diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3e1e8b4d..7d343030 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -12,9 +12,34 @@ target_sources(VNote PRIVATE ${DIALOG_SRCS})
target_sources(VNote PRIVATE ${UTILS_SRCS})
target_sources(VNote PRIVATE ${WIDGETS_SRCS})
target_sources(VNote PRIVATE ${QRC_FILES})
+if(WIN32)
+target_sources(VNote PRIVATE resources/icon.rc)
+endif(WIN32)
include_directories(dialog utils widgets)
+# Remove the console of gui program
+if(WIN32)
+ if(MSVC)
+ set_target_properties(VNote PROPERTIES
+ WIN32_EXECUTABLE YES
+ LINK_FLAGS "/ENTRY:mainCRTStartup"
+ )
+ elseif(CMAKE_COMPILER_IS_GNUCXX)
+ # SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mwindows") # Not tested
+ else()
+ message(SEND_ERROR "You are using an unsupported Windows compiler! (Not MSVC or GCC)")
+ endif(MSVC)
+elseif(APPLE)
+ set_target_properties(VNote PROPERTIES
+ MACOSX_BUNDLE YES
+ )
+elseif(UNIX)
+ # Nothing special required
+else()
+ message(SEND_ERROR "You are on an unsupported platform! (Not Win32, Mac OS X or Unix)")
+endif(WIN32)
+
# Qt5 libraries
target_link_libraries(VNote PRIVATE Qt5::Core Qt5::WebEngine Qt5::WebEngineWidgets
Qt5::Network Qt5::PrintSupport Qt5::WebChannel Qt5::Widgets
diff --git a/src/resources/icon.rc b/src/resources/icon.rc
new file mode 100644
index 00000000..0669e583
--- /dev/null
+++ b/src/resources/icon.rc
@@ -0,0 +1 @@
+IDI_ICON1 ICON DISCARDABLE "resources/icons/vnote.ico"
\ No newline at end of file
diff --git a/src/translations/vnote_zh_CN.qm b/src/translations/vnote_zh_CN.qm
index 4c5803a7..8d9e599e 100644
Binary files a/src/translations/vnote_zh_CN.qm and b/src/translations/vnote_zh_CN.qm differ
diff --git a/src/translations/vnote_zh_CN.ts b/src/translations/vnote_zh_CN.ts
index c18b0910..9f79fa84 100644
--- a/src/translations/vnote_zh_CN.ts
+++ b/src/translations/vnote_zh_CN.ts
@@ -5519,6 +5519,41 @@ Please check the network or image size
Use system's background color configuration for editor
为编辑器使用系统的背景色设置
+
+
+ &Sync
+ 同步
+
+
+
+ &Upload
+ 上传
+
+
+
+ &Download
+ 更新
+
+
+
+ upload note
+ 上传当前笔记本
+
+
+
+ download note
+ 更新当前笔记本
+
+
+
+ Are you sure to close opened notes
+ 确认关闭已打开笔记
+
+
+
+ VNote will close all the opened notes before upload.
+ VNote会在上传前关闭所有已打开笔记
+
VMarkdownTab
@@ -8861,4 +8896,37 @@ Please check the network or image size
字数
+
+ VSync
+
+
+ Sync
+ 同步
+
+
+
+ Sure
+ 确认
+
+
+
+ Downloading
+ 更新中...
+
+
+
+ Uploading
+ 上传中...
+
+
+
+ Download Success
+ 更新成功
+
+
+
+ Upload Success
+ 上传成功
+
+
diff --git a/src/utils/vSync.cpp b/src/utils/vSync.cpp
new file mode 100644
index 00000000..abb4d86f
--- /dev/null
+++ b/src/utils/vSync.cpp
@@ -0,0 +1,217 @@
+#include "vSync.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+VSync::VSync(QWidget *parent) : QObject(parent)
+{
+ m_process = new QProcess(this);
+ connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadOutput()));
+ connect(m_process, SIGNAL(readyReadStandardError()), this, SLOT(onReadError()));
+ connect(m_process, SIGNAL(finished(int)), this, SLOT(onProcessFinish(int)));
+
+ m_messageBox = new QMessageBox(parent);
+ m_messageBox->setModal(true);
+ m_messageBox->setWindowTitle(tr("Sync"));
+ m_messageBox->setStandardButtons(QMessageBox::NoButton);
+ m_messageButton = new QPushButton(m_messageBox);
+ m_messageButton->setText(tr("Sure"));
+ connect(m_messageButton, &QPushButton::clicked, this, &VSync::onMessageButtonClick);
+}
+
+VSync::~VSync()
+{
+ m_process->close();
+}
+
+void VSync::status()
+{
+ this->m_type = SyncType::Status;
+ this->start(getSyncHead("status"));
+}
+
+void VSync::add()
+{
+ this->m_type = SyncType::Add;
+ this->start(getSyncHead("add -A"));
+}
+
+void VSync::commit()
+{
+ this->m_type = SyncType::Commit;
+ QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd-hh:mm:ss");
+ this->start(getSyncHead(QString("commit -m %1").arg(time)));
+}
+
+void VSync::push()
+{
+ this->m_type = SyncType::Push;
+ this->start(getSyncHead("push"));
+}
+
+void VSync::pull()
+{
+ this->m_type = SyncType::Pull;
+ this->start(getSyncHead("pull"));
+}
+
+void VSync::authentication()
+{
+ this->m_type = SyncType::Authentication;
+ this->start("git config --global credential.helper store");
+}
+
+void VSync::download()
+{
+ showMessageBox(tr("Downloading"), false);
+ this->m_target = SyncTarget::Download;
+ this->status();
+}
+
+void VSync::upload()
+{
+ showMessageBox(tr("Uploading"), false);
+ this->m_target = SyncTarget::Upload;
+ this->status();
+}
+
+void VSync::onReadOutput()
+{
+ QString output = m_process->readAllStandardOutput();
+ qDebug() << "VSync.onReadOutput: " << output;
+ m_output.append(output);
+}
+
+void VSync::onReadError()
+{
+ QString error = m_process->readAllStandardError();
+ qDebug() << "VSync.onReadError: " << error;
+ m_error.append(error);
+}
+
+void VSync::onProcessFinish(int exitCode)
+{
+ qInfo() << "VSync.onProcessFinish: " << exitCode;
+ if (exitCode == 0)
+ {
+ switch (this->m_target)
+ {
+ case SyncTarget::Download:
+ this->processDownload();
+ break;
+ case SyncTarget::Upload:
+ this->processUpload();
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ /* code */
+ qCritical() << "sync failed, error: " << m_error << ", info: " << m_output;
+ QString message = QString("sync failed, exitCode: %1, error: %2, info: %3").arg(exitCode).arg(m_error).arg(m_output);
+ showMessageBox(message, true);
+ }
+
+ m_error.clear();
+ m_output.clear();
+}
+
+void VSync::start(const QString &cmd)
+{
+ m_process->start("cmd", QStringList() << "/c" << cmd);
+ m_process->waitForStarted();
+}
+
+void VSync::showMessageBox(const QString &message, bool showButton)
+{
+ m_messageBox->setText(message);
+ if (showButton)
+ {
+ m_messageBox->addButton(m_messageButton, QMessageBox::ButtonRole::YesRole);
+ }
+ else
+ {
+ m_messageBox->removeButton(m_messageButton);
+ }
+
+ if (!m_messageBox->isVisible())
+ {
+ m_messageBox->setVisible(true);
+ }
+}
+
+void VSync::hideMessageBox()
+{
+ m_messageBox->removeButton(m_messageButton);
+ m_messageBox->setVisible(false);
+}
+
+void VSync::onMessageButtonClick()
+{
+ m_messageBox->hide();
+}
+
+void VSync::processDownload()
+{
+ switch (this->m_type)
+ {
+ case SyncType::Status:
+ this->authentication();
+ break;
+ case SyncType::Authentication:
+ this->pull();
+ break;
+ case SyncType::Pull:
+ this->downloadFinish();
+ break;
+ default:
+ break;
+ }
+}
+
+void VSync::processUpload()
+{
+ switch (this->m_type)
+ {
+ case SyncType::Status:
+ this->add();
+ break;
+ case SyncType::Add:
+ this->commit();
+ break;
+ case SyncType::Commit:
+ this->authentication();
+ break;
+ case SyncType::Authentication:
+ this->push();
+ break;
+ case SyncType::Push:
+ this->uploadFinish();
+ break;
+ default:
+ break;
+ }
+}
+
+void VSync::downloadFinish()
+{
+ qInfo() << "download finish";
+ showMessageBox(tr("Download Success"), true);
+ m_type = VSync::SyncType::None;
+ m_target = VSync::SyncTarget::None;
+ emit this->downloadSuccess();
+}
+
+void VSync::uploadFinish()
+{
+ qInfo() << "upload finish";
+ showMessageBox(tr("Upload Success"), true);
+ m_type = VSync::SyncType::None;
+ m_target = VSync::SyncTarget::None;
+ emit this->uploadSuccess();
+}
\ No newline at end of file
diff --git a/src/utils/vSync.h b/src/utils/vSync.h
new file mode 100644
index 00000000..a5149c2f
--- /dev/null
+++ b/src/utils/vSync.h
@@ -0,0 +1,84 @@
+#ifndef _V_SYNC_H_
+#define _V_SYNC_H_
+#include
+#include
+#include
+
+class QMessageBox;
+class QPushButton;
+class VSync : public QObject
+{
+ Q_OBJECT
+private:
+ enum class SyncType
+ {
+ None,
+ Status,
+ Add,
+ Commit,
+ Push,
+ Pull,
+ Authentication
+ };
+
+ enum class SyncTarget
+ {
+ None,
+ Upload,
+ Download,
+ };
+signals:
+ void downloadSuccess();
+ void uploadSuccess();
+public:
+ VSync(QWidget *parent = NULL);
+ ~VSync();
+ void setDir(const QString &dir);
+ void upload();
+ void download();
+private slots:
+ void onReadOutput();
+ void onReadError();
+ void onProcessFinish(int exitCode);
+
+private:
+ void status();
+ void add();
+ void commit();
+ void push();
+ void pull();
+ void authentication();
+ void processDownload();
+ void processUpload();
+ void downloadFinish();
+ void uploadFinish();
+
+ void start(const QString &cmd);
+ void showMessageBox(const QString &message, bool showButton);
+ void hideMessageBox();
+ void onMessageButtonClick();
+ QString VSync::getSyncHead(const QString &args) const;
+
+private:
+ QString m_dir;
+
+ QMessageBox *m_messageBox;
+ QPushButton *m_messageButton;
+ QProcess *m_process;
+ SyncType m_type;
+ SyncTarget m_target;
+ QString m_output;
+ QString m_error;
+};
+
+inline void VSync::setDir(const QString &dir)
+{
+ this->m_dir = dir;
+};
+
+inline QString VSync::getSyncHead(const QString &args) const
+{
+ return QString("git -C %1 %2").arg(this->m_dir).arg(args);
+}
+
+#endif
diff --git a/src/vdirectorytree.cpp b/src/vdirectorytree.cpp
index 2a8efacc..4dda57ac 100644
--- a/src/vdirectorytree.cpp
+++ b/src/vdirectorytree.cpp
@@ -668,6 +668,74 @@ void VDirectoryTree::openDirectoryLocation() const
QDesktopServices::openUrl(url);
}
+void VDirectoryTree::reloadAllFromDisk()
+{
+ if (!m_notebook)
+ {
+ return;
+ }
+
+ QString info = tr("Are you sure to reload notebook %2?")
+ .arg(g_config->c_dataTextStyle)
+ .arg(m_notebook->getName());
+ QString msg = tr("Notebook %1 reloaded from disk").arg(m_notebook->getName());
+
+ if (g_config->getConfirmReloadFolder())
+ {
+ int ret = VUtils::showMessage(QMessageBox::Information, tr("Information"),
+ info,
+ tr("VNote will close all the related notes before reload."),
+ QMessageBox::Ok | QMessageBox::YesToAll | QMessageBox::Cancel,
+ QMessageBox::Ok,
+ this);
+ switch (ret)
+ {
+ case QMessageBox::YesToAll:
+ g_config->setConfirmReloadFolder(false);
+ // Fall through.
+
+ case QMessageBox::Ok:
+ break;
+
+ case QMessageBox::Cancel:
+ return;
+
+ default:
+ return;
+ }
+ }
+
+ m_notebookCurrentDirMap.remove(m_notebook);
+
+ if (!m_editArea->closeFile(m_notebook, false))
+ {
+ return;
+ }
+
+ m_notebook->close();
+
+ if (!m_notebook->open())
+ {
+ VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
+ tr("Fail to open notebook %2.")
+ .arg(g_config->c_dataTextStyle)
+ .arg(m_notebook->getName()),
+ tr("Please check if path %2 exists.")
+ .arg(g_config->c_dataTextStyle)
+ .arg(m_notebook->getPath()),
+ QMessageBox::Ok, QMessageBox::Ok, this);
+ clear();
+ return;
+ }
+
+ updateDirectoryTree();
+
+ if (!msg.isEmpty())
+ {
+ g_mainWin->showStatusMessage(msg);
+ }
+}
+
void VDirectoryTree::reloadFromDisk()
{
if (!m_notebook) {
diff --git a/src/vdirectorytree.h b/src/vdirectorytree.h
index 6f42e5ed..911cb492 100644
--- a/src/vdirectorytree.h
+++ b/src/vdirectorytree.h
@@ -35,6 +35,7 @@ public:
// Implementations for VNavigationMode.
void showNavigation() Q_DECL_OVERRIDE;
bool handleKeyNavigation(int p_key, bool &p_succeed) Q_DECL_OVERRIDE;
+ void reloadAllFromDisk();
signals:
void currentDirectoryChanged(VDirectory *p_directory);
diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp
index 3f93f6a1..e6036d6a 100644
--- a/src/vmainwindow.cpp
+++ b/src/vmainwindow.cpp
@@ -52,6 +52,7 @@
#include "vlistue.h"
#include "vtagexplorer.h"
#include "vmdeditor.h"
+#include "vSync.h"
extern VConfigManager *g_config;
@@ -113,6 +114,8 @@ VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent)
initDockWindows();
+ initSync();
+
int state = g_config->getPanelViewState();
if (state < 0 || state >= (int)PanelViewState::Invalid) {
state = (int)PanelViewState::VerticalMode;
@@ -813,6 +816,9 @@ void VMainWindow::initMenuBar()
initEditMenu();
initViewMenu();
initMarkdownMenu();
+#if defined(Q_OS_WIN)
+ initSyncMenu();
+#endif
initHelpMenu();
setMenuBarVisible(g_config->getMenuBarChecked());
@@ -990,6 +996,73 @@ void VMainWindow::initMarkdownMenu()
previewWidthAct->setChecked(g_config->getEnablePreviewImageConstraint());
}
+void VMainWindow::initSyncMenu()
+{
+ m_syncMenu = menuBar()->addMenu(tr("&Sync"));
+ m_syncMenu->setToolTipsVisible(true);
+ QAction* uploadAction = new QAction(tr("&Upload"), this);
+ uploadAction->setToolTip(tr("upload note"));
+ connect(uploadAction, &QAction::triggered, this, &VMainWindow::upload);
+ m_syncMenu->addAction(uploadAction);
+
+ QAction* downloadAction = new QAction(tr("&Download"), this);
+ downloadAction->setToolTip(tr("download note"));
+ connect(downloadAction, &QAction::triggered, this, &VMainWindow::download);
+ m_syncMenu->addAction(downloadAction);
+}
+
+void VMainWindow::upload()
+{
+ QVector& noteBooks = vnote->getNotebooks();
+ for (QVector::iterator i = noteBooks.begin(); i < noteBooks.end(); i++)
+ {
+ QString notebookDir = (*i)->getPath();
+ QString notebookName = (*i)->getName();
+ if ((*i)->isOpened())
+ {
+ qDebug() << "notebook name: " << notebookName << "notebook path: " << notebookDir;
+ int ret = VUtils::showMessage(QMessageBox::Information, tr("Information"),
+ tr("Are you sure to close opened notes"),
+ tr("VNote will close all the opened notes before upload."),
+ QMessageBox::Ok | QMessageBox::Cancel,
+ QMessageBox::Ok,
+ this);
+ switch (ret)
+ {
+ case QMessageBox::Ok:
+ this->m_editArea->closeAllFiles(true);
+ break;
+
+ case QMessageBox::Cancel:
+ return;
+
+ default:
+ return;
+ }
+ m_git->setDir(notebookDir);
+ m_git->upload();
+ break;
+ }
+ }
+}
+
+void VMainWindow::download()
+{
+ QVector ¬eBooks = vnote->getNotebooks();
+ for (QVector::iterator i = noteBooks.begin(); i < noteBooks.end(); i++)
+ {
+ QString notebookDir = (*i)->getPath();
+ QString notebookName = (*i)->getName();
+ if ((*i)->isOpened())
+ {
+ qDebug() << "notebook name: " << notebookName << "notebook path: " << notebookDir;
+ m_git->setDir(notebookDir);
+ m_git->download();
+ break;
+ }
+ }
+}
+
void VMainWindow::initViewMenu()
{
m_viewMenu = menuBar()->addMenu(tr("&View"));
@@ -3654,3 +3727,23 @@ void VMainWindow::checkIfNeedToShowWelcomePage()
m_editArea->openFile(file, OpenFileMode::Read);
}
}
+
+void VMainWindow::initSync()
+{
+ m_git = new VSync();
+ connect(m_git, &VSync::downloadSuccess, this, &VMainWindow::onDownloadSuccess);
+ connect(m_git, &VSync::uploadSuccess, this, &VMainWindow::onUploadSuccess);
+}
+
+void VMainWindow::onDownloadSuccess()
+{
+ if (m_dirTree)
+ {
+ m_dirTree->reloadAllFromDisk();
+ }
+}
+
+void VMainWindow::onUploadSuccess()
+{
+
+}
\ No newline at end of file
diff --git a/src/vmainwindow.h b/src/vmainwindow.h
index 2da51331..fa0192b0 100644
--- a/src/vmainwindow.h
+++ b/src/vmainwindow.h
@@ -45,6 +45,7 @@ class VUniversalEntry;
class VHistoryList;
class VExplorer;
class VTagExplorer;
+class VSync;
#define RESTART_EXIT_CODE 1000
@@ -246,6 +247,12 @@ private:
void initViewMenu();
void initMarkdownMenu();
void initHelpMenu();
+ void initSyncMenu();
+ void initSync();
+ void upload();
+ void download();
+ void onDownloadSuccess();
+ void onUploadSuccess();
void initDockWindows();
@@ -468,6 +475,9 @@ private:
QToolBar *m_noteToolBar;
+ // sync menu
+ QMenu *m_syncMenu;
+
// All the ToolBar.
QVector m_toolBars;
@@ -512,6 +522,8 @@ private:
VTagExplorer *m_tagExplorer;
+ VSync *m_git;
+
// Whether sync note list to current tab.
bool m_syncNoteListToCurrentTab;