mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 22:09:52 +08:00
support opening external files from context menu in system browser
This commit is contained in:
parent
e33ff1fede
commit
0b9d259de6
46
src/main.cpp
46
src/main.cpp
@ -6,6 +6,8 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QDir>
|
||||||
#include "utils/vutils.h"
|
#include "utils/vutils.h"
|
||||||
#include "vsingleinstanceguard.h"
|
#include "vsingleinstanceguard.h"
|
||||||
#include "vconfigmanager.h"
|
#include "vconfigmanager.h"
|
||||||
@ -91,16 +93,18 @@ void VLogger(QtMsgType type, const QMessageLogContext &context, const QString &m
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
VSingleInstanceGuard guard;
|
||||||
|
bool canRun = guard.tryRun();
|
||||||
|
|
||||||
#if defined(QT_NO_DEBUG)
|
#if defined(QT_NO_DEBUG)
|
||||||
|
if (canRun) {
|
||||||
g_logFile.setFileName(VConfigManager::getLogFilePath());
|
g_logFile.setFileName(VConfigManager::getLogFilePath());
|
||||||
g_logFile.open(QIODevice::WriteOnly);
|
g_logFile.open(QIODevice::WriteOnly);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (canRun) {
|
||||||
qInstallMessageHandler(VLogger);
|
qInstallMessageHandler(VLogger);
|
||||||
|
|
||||||
VSingleInstanceGuard guard;
|
|
||||||
if (!guard.tryRun()) {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QTextCodec *codec = QTextCodec::codecForName("UTF8");
|
QTextCodec *codec = QTextCodec::codecForName("UTF8");
|
||||||
@ -109,6 +113,35 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
// The file path passed via command line arguments.
|
||||||
|
QStringList filePaths;
|
||||||
|
QStringList args = app.arguments();
|
||||||
|
for (int i = 1; i < args.size(); ++i) {
|
||||||
|
if (QFileInfo::exists(args[i])) {
|
||||||
|
QString filePath = args[i];
|
||||||
|
QFileInfo fi(filePath);
|
||||||
|
if (fi.isFile()) {
|
||||||
|
// Need to use absolute path here since VNote may be launched
|
||||||
|
// in different working directory.
|
||||||
|
filePath = QDir::cleanPath(fi.absoluteFilePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
filePaths.append(filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "command line arguments" << args;
|
||||||
|
|
||||||
|
if (!canRun) {
|
||||||
|
// Ask another instance to open files passed in.
|
||||||
|
if (!filePaths.isEmpty()) {
|
||||||
|
guard.openExternalFiles(filePaths);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
vconfig.initialize();
|
vconfig.initialize();
|
||||||
|
|
||||||
QString locale = VUtils::getLocale();
|
QString locale = VUtils::getLocale();
|
||||||
@ -119,6 +152,7 @@ int main(int argc, char *argv[])
|
|||||||
if (!qtTranslator.load("qt_" + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
|
if (!qtTranslator.load("qt_" + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
|
||||||
qtTranslator.load("qt_" + locale, "translations");
|
qtTranslator.load("qt_" + locale, "translations");
|
||||||
}
|
}
|
||||||
|
|
||||||
app.installTranslator(&qtTranslator);
|
app.installTranslator(&qtTranslator);
|
||||||
|
|
||||||
// load translation for vnote
|
// load translation for vnote
|
||||||
@ -128,7 +162,7 @@ int main(int argc, char *argv[])
|
|||||||
app.installTranslator(&translator);
|
app.installTranslator(&translator);
|
||||||
}
|
}
|
||||||
|
|
||||||
VMainWindow w;
|
VMainWindow w(&guard);
|
||||||
QString style = VUtils::readFileFromDisk(":/resources/vnote.qss");
|
QString style = VUtils::readFileFromDisk(":/resources/vnote.qss");
|
||||||
if (!style.isEmpty()) {
|
if (!style.isEmpty()) {
|
||||||
VUtils::processStyle(style, w.getPalette());
|
VUtils::processStyle(style, w.getPalette());
|
||||||
@ -137,5 +171,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
w.show();
|
w.show();
|
||||||
|
|
||||||
|
w.openExternalFiles(filePaths);
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
- `Ctrl+E E`
|
- `Ctrl+E E`
|
||||||
Toggle expanding the edit area.
|
Toggle expanding the edit area.
|
||||||
- `Ctrl+Alt+N`
|
- `Ctrl+Alt+N`
|
||||||
Create a note in current directory.
|
Create a note in current folder.
|
||||||
- `Ctrl+F`
|
- `Ctrl+F`
|
||||||
Find/Replace in current note.
|
Find/Replace in current note.
|
||||||
- `Ctrl+Q`
|
- `Ctrl+Q`
|
||||||
@ -135,7 +135,7 @@ Number key 1 to 9 will jump to the tabs with corresponding sequence number.
|
|||||||
- `0`
|
- `0`
|
||||||
Jump to previous tab. Alternate between current and previous tab.
|
Jump to previous tab. Alternate between current and previous tab.
|
||||||
- `D`
|
- `D`
|
||||||
Locate to the directory of current note.
|
Locate to the folder of current note.
|
||||||
- `Q`
|
- `Q`
|
||||||
Discard current changes and exit edit mode.
|
Discard current changes and exit edit mode.
|
||||||
- `V`
|
- `V`
|
||||||
|
@ -136,7 +136,7 @@ size=8
|
|||||||
- `0`
|
- `0`
|
||||||
跳转到前一个标签页(即前一个当前标签页)。实现当前标签页和前一个标签页之间的轮换。
|
跳转到前一个标签页(即前一个当前标签页)。实现当前标签页和前一个标签页之间的轮换。
|
||||||
- `D`
|
- `D`
|
||||||
定位当前笔记所在目录。
|
定位当前笔记所在文件夹。
|
||||||
- `Q`
|
- `Q`
|
||||||
放弃当前更改并退出编辑模式。
|
放弃当前更改并退出编辑模式。
|
||||||
- `V`
|
- `V`
|
||||||
|
@ -34,7 +34,7 @@ background: 005fff
|
|||||||
editor-current-line
|
editor-current-line
|
||||||
background: c5cae9
|
background: c5cae9
|
||||||
# [VNote] Vim insert mode cursor line background
|
# [VNote] Vim insert mode cursor line background
|
||||||
vim-insert-background: cdc0b0
|
vim-insert-background: bcbcbc
|
||||||
# [VNote] Vim normal mode cursor line background
|
# [VNote] Vim normal mode cursor line background
|
||||||
vim-normal-background: b0bec5
|
vim-normal-background: b0bec5
|
||||||
# [VNote] Vim visual mode cursor line background
|
# [VNote] Vim visual mode cursor line background
|
||||||
|
@ -131,6 +131,20 @@ void VEditWindow::initTabActions()
|
|||||||
g_vnote->getMainWindow()->editOrphanFileInfo(file);
|
g_vnote->getMainWindow()->editOrphanFileInfo(file);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_openLocationAct = new QAction(tr("Open Note Location"), this);
|
||||||
|
m_openLocationAct->setToolTip(tr("Open the folder containing this note in operating system"));
|
||||||
|
connect(m_openLocationAct, &QAction::triggered,
|
||||||
|
this, [this](){
|
||||||
|
int tab = this->m_closeTabAct->data().toInt();
|
||||||
|
Q_ASSERT(tab != -1);
|
||||||
|
|
||||||
|
VEditTab *editor = getTab(tab);
|
||||||
|
QPointer<VFile> file = editor->getFile();
|
||||||
|
Q_ASSERT(file);
|
||||||
|
QUrl url = QUrl::fromLocalFile(file->retriveBasePath());
|
||||||
|
QDesktopServices::openUrl(url);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEditWindow::setupCornerWidget()
|
void VEditWindow::setupCornerWidget()
|
||||||
@ -527,10 +541,17 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos)
|
|||||||
// Locate to folder.
|
// Locate to folder.
|
||||||
m_locateAct->setData(tab);
|
m_locateAct->setData(tab);
|
||||||
menu.addAction(m_locateAct);
|
menu.addAction(m_locateAct);
|
||||||
|
|
||||||
|
m_openLocationAct->setData(tab);
|
||||||
|
menu.addAction(m_openLocationAct);
|
||||||
|
|
||||||
m_noteInfoAct->setData(tab);
|
m_noteInfoAct->setData(tab);
|
||||||
menu.addAction(m_noteInfoAct);
|
menu.addAction(m_noteInfoAct);
|
||||||
} else if (file->getType() == FileType::Orphan
|
} else if (file->getType() == FileType::Orphan
|
||||||
&& !dynamic_cast<VOrphanFile *>(file)->isSystemFile()) {
|
&& !dynamic_cast<VOrphanFile *>(file)->isSystemFile()) {
|
||||||
|
m_openLocationAct->setData(tab);
|
||||||
|
menu.addAction(m_openLocationAct);
|
||||||
|
|
||||||
m_noteInfoAct->setData(tab);
|
m_noteInfoAct->setData(tab);
|
||||||
menu.addAction(m_noteInfoAct);
|
menu.addAction(m_noteInfoAct);
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,9 @@ private:
|
|||||||
|
|
||||||
// View and edit info about this note.
|
// View and edit info about this note.
|
||||||
QAction *m_noteInfoAct;
|
QAction *m_noteInfoAct;
|
||||||
|
|
||||||
|
// Open the location (the folder containing this file) of this note.
|
||||||
|
QAction *m_openLocationAct;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline QString VEditWindow::generateTooltip(const VFile *p_file) const
|
inline QString VEditWindow::generateTooltip(const VFile *p_file) const
|
||||||
|
@ -25,17 +25,20 @@
|
|||||||
#include "dialog/vupdater.h"
|
#include "dialog/vupdater.h"
|
||||||
#include "vorphanfile.h"
|
#include "vorphanfile.h"
|
||||||
#include "dialog/vorphanfileinfodialog.h"
|
#include "dialog/vorphanfileinfodialog.h"
|
||||||
|
#include "vsingleinstanceguard.h"
|
||||||
|
|
||||||
extern VConfigManager vconfig;
|
extern VConfigManager vconfig;
|
||||||
|
|
||||||
VNote *g_vnote;
|
VNote *g_vnote;
|
||||||
|
|
||||||
|
const int VMainWindow::c_sharedMemTimerInterval = 1000;
|
||||||
|
|
||||||
#if defined(QT_NO_DEBUG)
|
#if defined(QT_NO_DEBUG)
|
||||||
extern QFile g_logFile;
|
extern QFile g_logFile;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VMainWindow::VMainWindow(QWidget *parent)
|
VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent)
|
||||||
: QMainWindow(parent), m_onePanel(false)
|
: QMainWindow(p_parent), m_onePanel(false), m_guard(p_guard)
|
||||||
{
|
{
|
||||||
setWindowIcon(QIcon(":/resources/icons/vnote.ico"));
|
setWindowIcon(QIcon(":/resources/icons/vnote.ico"));
|
||||||
vnote = new VNote(this);
|
vnote = new VNote(this);
|
||||||
@ -56,6 +59,19 @@ VMainWindow::VMainWindow(QWidget *parent)
|
|||||||
notebookSelector->update();
|
notebookSelector->update();
|
||||||
|
|
||||||
initCaptain();
|
initCaptain();
|
||||||
|
|
||||||
|
initSharedMemoryWatcher();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VMainWindow::initSharedMemoryWatcher()
|
||||||
|
{
|
||||||
|
m_sharedMemTimer = new QTimer(this);
|
||||||
|
m_sharedMemTimer->setSingleShot(false);
|
||||||
|
m_sharedMemTimer->setInterval(c_sharedMemTimerInterval);
|
||||||
|
connect(m_sharedMemTimer, &QTimer::timeout,
|
||||||
|
this, &VMainWindow::checkSharedMemory);
|
||||||
|
|
||||||
|
m_sharedMemTimer->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMainWindow::initCaptain()
|
void VMainWindow::initCaptain()
|
||||||
@ -1349,6 +1365,10 @@ void VMainWindow::setEditorStyle(QAction *p_action)
|
|||||||
void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file,
|
void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file,
|
||||||
bool p_editMode)
|
bool p_editMode)
|
||||||
{
|
{
|
||||||
|
bool systemFile = p_file
|
||||||
|
&& p_file->getType() == FileType::Orphan
|
||||||
|
&& dynamic_cast<const VOrphanFile *>(p_file)->isSystemFile();
|
||||||
|
|
||||||
m_printAct->setEnabled(p_file && p_file->getDocType() == DocType::Markdown);
|
m_printAct->setEnabled(p_file && p_file->getDocType() == DocType::Markdown);
|
||||||
m_exportAsPDFAct->setEnabled(p_file && p_file->getDocType() == DocType::Markdown);
|
m_exportAsPDFAct->setEnabled(p_file && p_file->getDocType() == DocType::Markdown);
|
||||||
|
|
||||||
@ -1356,8 +1376,8 @@ void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file,
|
|||||||
discardExitAct->setVisible(p_file && p_editMode);
|
discardExitAct->setVisible(p_file && p_editMode);
|
||||||
saveExitAct->setVisible(p_file && p_editMode);
|
saveExitAct->setVisible(p_file && p_editMode);
|
||||||
saveNoteAct->setVisible(p_file && p_editMode);
|
saveNoteAct->setVisible(p_file && p_editMode);
|
||||||
deleteNoteAct->setVisible(p_file && p_file->isModifiable());
|
deleteNoteAct->setVisible(p_file && p_file->getType() == FileType::Normal);
|
||||||
noteInfoAct->setVisible(p_file && p_file->getType() == FileType::Normal);
|
noteInfoAct->setVisible(p_file && !systemFile);
|
||||||
m_closeNoteAct->setVisible(p_file);
|
m_closeNoteAct->setVisible(p_file);
|
||||||
|
|
||||||
m_insertImageAct->setEnabled(p_file && p_editMode);
|
m_insertImageAct->setEnabled(p_file && p_editMode);
|
||||||
@ -1483,17 +1503,25 @@ void VMainWindow::updateWindowTitle(const QString &str)
|
|||||||
|
|
||||||
void VMainWindow::curEditFileInfo()
|
void VMainWindow::curEditFileInfo()
|
||||||
{
|
{
|
||||||
if (!m_curFile || m_curFile->getType() != FileType::Normal) {
|
Q_ASSERT(m_curFile);
|
||||||
return;
|
|
||||||
}
|
if (m_curFile->getType() == FileType::Normal) {
|
||||||
fileList->fileInfo(m_curFile);
|
fileList->fileInfo(m_curFile);
|
||||||
|
} else if (m_curFile->getType() == FileType::Orphan) {
|
||||||
|
VOrphanFile *file = dynamic_cast<VOrphanFile *>((VFile *)m_curFile);
|
||||||
|
Q_ASSERT(file);
|
||||||
|
if (!file->isSystemFile()) {
|
||||||
|
editOrphanFileInfo(m_curFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMainWindow::deleteCurNote()
|
void VMainWindow::deleteCurNote()
|
||||||
{
|
{
|
||||||
if (!m_curFile || !m_curFile->isModifiable()) {
|
if (!m_curFile || m_curFile->getType() != FileType::Normal) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fileList->deleteFile(m_curFile);
|
fileList->deleteFile(m_curFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1828,3 +1856,16 @@ void VMainWindow::editOrphanFileInfo(VFile *p_file)
|
|||||||
file->setImageFolder(imgFolder);
|
file->setImageFolder(imgFolder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VMainWindow::checkSharedMemory()
|
||||||
|
{
|
||||||
|
QStringList files = m_guard->fetchFilesToOpen();
|
||||||
|
if (!files.isEmpty()) {
|
||||||
|
qDebug() << "shared memory fetch files" << files;
|
||||||
|
openExternalFiles(files);
|
||||||
|
|
||||||
|
show();
|
||||||
|
activateWindow();
|
||||||
|
QApplication::alert(this, 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -31,6 +31,8 @@ class VFindReplaceDialog;
|
|||||||
class VCaptain;
|
class VCaptain;
|
||||||
class VVimIndicator;
|
class VVimIndicator;
|
||||||
class VTabIndicator;
|
class VTabIndicator;
|
||||||
|
class VSingleInstanceGuard;
|
||||||
|
class QTimer;
|
||||||
|
|
||||||
class VMainWindow : public QMainWindow
|
class VMainWindow : public QMainWindow
|
||||||
{
|
{
|
||||||
@ -39,7 +41,7 @@ class VMainWindow : public QMainWindow
|
|||||||
public:
|
public:
|
||||||
friend class VCaptain;
|
friend class VCaptain;
|
||||||
|
|
||||||
VMainWindow(QWidget *parent = 0);
|
VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent = 0);
|
||||||
const QVector<QPair<QString, QString> > &getPalette() const;
|
const QVector<QPair<QString, QString> > &getPalette() const;
|
||||||
void locateFile(VFile *p_file);
|
void locateFile(VFile *p_file);
|
||||||
void locateCurrentFile();
|
void locateCurrentFile();
|
||||||
@ -49,6 +51,9 @@ public:
|
|||||||
// View and edit the information of @p_file, which is an orphan file.
|
// View and edit the information of @p_file, which is an orphan file.
|
||||||
void editOrphanFileInfo(VFile *p_file);
|
void editOrphanFileInfo(VFile *p_file);
|
||||||
|
|
||||||
|
// Open external files @p_files as orphan files.
|
||||||
|
void openExternalFiles(const QStringList &p_files);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void importNoteFromFile();
|
void importNoteFromFile();
|
||||||
void viewSettings();
|
void viewSettings();
|
||||||
@ -100,6 +105,10 @@ private slots:
|
|||||||
// Handle the status update of the current tab of VEditArea.
|
// Handle the status update of the current tab of VEditArea.
|
||||||
void handleAreaTabStatusUpdated(const VEditTabInfo &p_info);
|
void handleAreaTabStatusUpdated(const VEditTabInfo &p_info);
|
||||||
|
|
||||||
|
// Check the shared memory between different instances to see if we have
|
||||||
|
// files to open.
|
||||||
|
void checkSharedMemory();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
|
void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
|
||||||
void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
|
void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
|
||||||
@ -154,8 +163,9 @@ private:
|
|||||||
const QString &p_text,
|
const QString &p_text,
|
||||||
QObject *p_parent = nullptr);
|
QObject *p_parent = nullptr);
|
||||||
|
|
||||||
// Open external files @p_files as orphan files.
|
// Init a timer to watch the change of the shared memory between instances of
|
||||||
void openExternalFiles(const QStringList &p_files);
|
// VNote.
|
||||||
|
void initSharedMemoryWatcher();
|
||||||
|
|
||||||
VNote *vnote;
|
VNote *vnote;
|
||||||
QPointer<VFile> m_curFile;
|
QPointer<VFile> m_curFile;
|
||||||
@ -216,6 +226,15 @@ private:
|
|||||||
QToolBar *m_editToolBar;
|
QToolBar *m_editToolBar;
|
||||||
|
|
||||||
QVector<QPixmap> predefinedColorPixmaps;
|
QVector<QPixmap> predefinedColorPixmaps;
|
||||||
|
|
||||||
|
// Single instance guard.
|
||||||
|
VSingleInstanceGuard *m_guard;
|
||||||
|
|
||||||
|
// Timer to check the shared memory between instances of VNote.
|
||||||
|
QTimer *m_sharedMemTimer;
|
||||||
|
|
||||||
|
// Interval of the shared memory timer in ms.
|
||||||
|
static const int c_sharedMemTimerInterval;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline VFileList *VMainWindow::getFileList() const
|
inline VFileList *VMainWindow::getFileList() const
|
||||||
|
@ -530,6 +530,7 @@ bool VMdEditOperations::handleKeyEsc(QKeyEvent *p_event)
|
|||||||
|
|
||||||
bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event)
|
bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event)
|
||||||
{
|
{
|
||||||
|
bool autolist = true;
|
||||||
if (p_event->modifiers() & Qt::ControlModifier) {
|
if (p_event->modifiers() & Qt::ControlModifier) {
|
||||||
m_autoIndentPos = -1;
|
m_autoIndentPos = -1;
|
||||||
return false;
|
return false;
|
||||||
@ -543,7 +544,9 @@ bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event)
|
|||||||
cursor.insertText(" ");
|
cursor.insertText(" ");
|
||||||
cursor.endEditBlock();
|
cursor.endEditBlock();
|
||||||
|
|
||||||
// Let remaining logics handle inserting the new block.
|
// Let remaining logics handle inserting the new block except that we
|
||||||
|
// do not need to insert auto list.
|
||||||
|
autolist = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if we need to cancel auto indent.
|
// See if we need to cancel auto indent.
|
||||||
@ -585,7 +588,7 @@ bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event)
|
|||||||
textInserted = VEditUtils::insertBlockWithIndent(cursor);
|
textInserted = VEditUtils::insertBlockWithIndent(cursor);
|
||||||
|
|
||||||
// Continue the list from previous line.
|
// Continue the list from previous line.
|
||||||
if (vconfig.getAutoList()) {
|
if (vconfig.getAutoList() && autolist) {
|
||||||
textInserted = VEditUtils::insertListMarkAsPreviousBlock(cursor) || textInserted;
|
textInserted = VEditUtils::insertListMarkAsPreviousBlock(cursor) || textInserted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,11 +282,12 @@ VFile *VNote::getOrphanFile(const QString &p_path, bool p_modifiable, bool p_sys
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString path = QDir::cleanPath(p_path);
|
||||||
// See if the file has already been opened before.
|
// See if the file has already been opened before.
|
||||||
for (auto const &file : m_externalFiles) {
|
for (auto const &file : m_externalFiles) {
|
||||||
Q_ASSERT(file->getType() == FileType::Orphan);
|
Q_ASSERT(file->getType() == FileType::Orphan);
|
||||||
VOrphanFile *oFile = dynamic_cast<VOrphanFile *>(file);
|
VOrphanFile *oFile = dynamic_cast<VOrphanFile *>(file);
|
||||||
if (oFile->retrivePath() == p_path) {
|
if (VUtils::equalPath(QDir::cleanPath(oFile->retrivePath()), path)) {
|
||||||
Q_ASSERT(oFile->isModifiable() == p_modifiable);
|
Q_ASSERT(oFile->isModifiable() == p_modifiable);
|
||||||
Q_ASSERT(oFile->isSystemFile() == p_systemFile);
|
Q_ASSERT(oFile->isSystemFile() == p_systemFile);
|
||||||
return file;
|
return file;
|
||||||
@ -303,8 +304,8 @@ VFile *VNote::getOrphanFile(const QString &p_path, bool p_modifiable, bool p_sys
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a VOrphanFile for p_path.
|
// Create a VOrphanFile for path.
|
||||||
VOrphanFile *file = new VOrphanFile(p_path, this, p_modifiable, p_systemFile);
|
VOrphanFile *file = new VOrphanFile(path, this, p_modifiable, p_systemFile);
|
||||||
m_externalFiles.append(file);
|
m_externalFiles.append(file);
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
@ -1,73 +1,132 @@
|
|||||||
#include "vsingleinstanceguard.h"
|
#include "vsingleinstanceguard.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
const QString VSingleInstanceGuard::m_memKey = "vnote_shared_memory";
|
#include "utils/vutils.h"
|
||||||
const QString VSingleInstanceGuard::m_semKey = "vnote_semaphore";
|
|
||||||
const int VSingleInstanceGuard::m_magic = 133191933;
|
const QString VSingleInstanceGuard::c_memKey = "vnote_shared_memory";
|
||||||
|
const int VSingleInstanceGuard::c_magic = 133191933;
|
||||||
|
|
||||||
VSingleInstanceGuard::VSingleInstanceGuard()
|
VSingleInstanceGuard::VSingleInstanceGuard()
|
||||||
: m_sharedMemory(m_memKey), m_sem(m_semKey, 1)
|
: m_sharedMemory(c_memKey)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
VSingleInstanceGuard::~VSingleInstanceGuard()
|
|
||||||
{
|
|
||||||
if (m_sharedMemory.isAttached()) {
|
|
||||||
detachMemory();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VSingleInstanceGuard::detachMemory()
|
|
||||||
{
|
|
||||||
m_sem.acquire();
|
|
||||||
m_sharedMemory.detach();
|
|
||||||
m_sem.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VSingleInstanceGuard::tryAttach()
|
|
||||||
{
|
|
||||||
m_sem.acquire();
|
|
||||||
bool ret = m_sharedMemory.attach();
|
|
||||||
m_sem.release();
|
|
||||||
if (ret) {
|
|
||||||
m_sharedMemory.lock();
|
|
||||||
SharedStruct *str = (SharedStruct *)m_sharedMemory.data();
|
|
||||||
str->m_activeRequest = 1;
|
|
||||||
m_sharedMemory.unlock();
|
|
||||||
detachMemory();
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VSingleInstanceGuard::tryRun()
|
bool VSingleInstanceGuard::tryRun()
|
||||||
{
|
{
|
||||||
// If we can attach to the sharedmemory, there is another instance running.
|
// If we can attach to the sharedmemory, there is another instance running.
|
||||||
if (tryAttach()) {
|
// In Linux, crashes may cause the shared memory segment remains. In this case,
|
||||||
|
// this will attach to the old segment, then exit, freeing the old segment.
|
||||||
|
if (m_sharedMemory.attach()) {
|
||||||
qDebug() << "another instance is running";
|
qDebug() << "another instance is running";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to create it
|
// Try to create it.
|
||||||
m_sem.acquire();
|
|
||||||
bool ret = m_sharedMemory.create(sizeof(SharedStruct));
|
bool ret = m_sharedMemory.create(sizeof(SharedStruct));
|
||||||
m_sem.release();
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
// We created it
|
// We created it.
|
||||||
m_sharedMemory.lock();
|
m_sharedMemory.lock();
|
||||||
SharedStruct *str = (SharedStruct *)m_sharedMemory.data();
|
SharedStruct *str = (SharedStruct *)m_sharedMemory.data();
|
||||||
str->m_magic = m_magic;
|
str->m_magic = c_magic;
|
||||||
str->m_activeRequest = 0;
|
str->m_filesBufIdx = 0;
|
||||||
m_sharedMemory.unlock();
|
m_sharedMemory.unlock();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// Maybe another thread create it
|
qDebug() << "fail to create shared memory segment";
|
||||||
if (tryAttach()) {
|
|
||||||
qDebug() << "another instance is running";
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSingleInstanceGuard::openExternalFiles(const QStringList &p_files)
|
||||||
|
{
|
||||||
|
if (p_files.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_sharedMemory.isAttached()) {
|
||||||
|
if (!m_sharedMemory.attach()) {
|
||||||
|
qDebug() << "fail to attach to the shared memory segment"
|
||||||
|
<< (m_sharedMemory.error() ? m_sharedMemory.errorString() : "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "try to request another instance to open files" << p_files;
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
int tryCount = 100;
|
||||||
|
while (tryCount--) {
|
||||||
|
qDebug() << "set shared memory one round" << idx << "of" << p_files.size();
|
||||||
|
m_sharedMemory.lock();
|
||||||
|
SharedStruct *str = (SharedStruct *)m_sharedMemory.data();
|
||||||
|
V_ASSERT(str->m_magic == c_magic);
|
||||||
|
for (; idx < p_files.size(); ++idx) {
|
||||||
|
if (p_files[idx].size() + 1 > FilesBufCount) {
|
||||||
|
qDebug() << "skip file since its long name" << p_files[idx];
|
||||||
|
// Skip this long long name file.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!appendFileToBuffer(str, p_files[idx])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_sharedMemory.unlock();
|
||||||
|
|
||||||
|
if (idx < p_files.size()) {
|
||||||
|
VUtils::sleepWait(500);
|
||||||
} else {
|
} else {
|
||||||
// Something wrong here
|
break;
|
||||||
qWarning() << "fail to create or attach shared memory segment";
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VSingleInstanceGuard::appendFileToBuffer(SharedStruct *p_str, const QString &p_file)
|
||||||
|
{
|
||||||
|
if (p_file.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int strSize = p_file.size();
|
||||||
|
if (strSize + 1 > FilesBufCount - p_str->m_filesBufIdx) {
|
||||||
|
qDebug() << "no enough space for" << p_file;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put the size first.
|
||||||
|
p_str->m_filesBuf[p_str->m_filesBufIdx++] = (ushort)strSize;
|
||||||
|
const QChar *data = p_file.constData();
|
||||||
|
for (int i = 0; i < strSize; ++i) {
|
||||||
|
p_str->m_filesBuf[p_str->m_filesBufIdx++] = data[i].unicode();
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "after appended one file" << p_str->m_filesBufIdx << p_file;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList VSingleInstanceGuard::fetchFilesToOpen()
|
||||||
|
{
|
||||||
|
QStringList files;
|
||||||
|
Q_ASSERT(m_sharedMemory.isAttached());
|
||||||
|
m_sharedMemory.lock();
|
||||||
|
SharedStruct *str = (SharedStruct *)m_sharedMemory.data();
|
||||||
|
Q_ASSERT(str->m_magic == c_magic);
|
||||||
|
Q_ASSERT(str->m_filesBufIdx <= FilesBufCount);
|
||||||
|
int idx = 0;
|
||||||
|
while (idx < str->m_filesBufIdx) {
|
||||||
|
int strSize = str->m_filesBuf[idx++];
|
||||||
|
Q_ASSERT(strSize <= str->m_filesBufIdx - idx);
|
||||||
|
QString file;
|
||||||
|
for (int i = 0; i < strSize; ++i) {
|
||||||
|
file.append(QChar(str->m_filesBuf[idx++]));
|
||||||
|
}
|
||||||
|
|
||||||
|
files.append(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
str->m_filesBufIdx = 0;
|
||||||
|
m_sharedMemory.unlock();
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
@ -3,31 +3,51 @@
|
|||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QSharedMemory>
|
#include <QSharedMemory>
|
||||||
#include <QSystemSemaphore>
|
#include <QStringList>
|
||||||
|
|
||||||
class VSingleInstanceGuard
|
class VSingleInstanceGuard
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VSingleInstanceGuard();
|
VSingleInstanceGuard();
|
||||||
~VSingleInstanceGuard();
|
|
||||||
|
// Return ture if this is the only instance of VNote.
|
||||||
bool tryRun();
|
bool tryRun();
|
||||||
|
|
||||||
|
// There is already another instance running.
|
||||||
|
// Call this to ask that instance to open external files passed in
|
||||||
|
// via command line arguments.
|
||||||
|
void openExternalFiles(const QStringList &p_files);
|
||||||
|
|
||||||
|
// Fetch files from shared memory to open.
|
||||||
|
// Will clear the shared memory.
|
||||||
|
QStringList fetchFilesToOpen();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void detachMemory();
|
// The count of the entries in the buffer to hold the path of the files to open.
|
||||||
bool tryAttach();
|
enum { FilesBufCount = 1024 };
|
||||||
|
|
||||||
struct SharedStruct {
|
struct SharedStruct {
|
||||||
// A magic number to identify if this struct is initialized
|
// A magic number to identify if this struct is initialized
|
||||||
int m_magic;
|
int m_magic;
|
||||||
// If it is 1, then another instance ask this instance to show itself
|
|
||||||
int m_activeRequest;
|
// Next empty entry in m_filesBuf.
|
||||||
|
int m_filesBufIdx;
|
||||||
|
|
||||||
|
// File paths to be opened.
|
||||||
|
// Encoded in this way with 2 bytes for each size part.
|
||||||
|
// [size of file1][file1][size of file2][file 2]
|
||||||
|
// Unicode representation of QString.
|
||||||
|
ushort m_filesBuf[FilesBufCount];
|
||||||
};
|
};
|
||||||
|
|
||||||
static const QString m_memKey;
|
// Append @p_file to the shared struct files buffer.
|
||||||
static const QString m_semKey;
|
// Returns true if succeeds or false if there is no enough space.
|
||||||
static const int m_magic;
|
bool appendFileToBuffer(SharedStruct *p_str, const QString &p_file);
|
||||||
|
|
||||||
QSharedMemory m_sharedMemory;
|
QSharedMemory m_sharedMemory;
|
||||||
QSystemSemaphore m_sem;
|
|
||||||
|
static const QString c_memKey;
|
||||||
|
static const int c_magic;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VSINGLEINSTANCEGUARD_H
|
#endif // VSINGLEINSTANCEGUARD_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user