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;