增加同步上传与更新git功能 (#1482)

* 增加git同步功能

* windows下增加图标

* Git操作改为异步

* 优化同步功能

* 更新完成后重新加载当前笔记本

* 上传前关闭所有已打开笔记

* Revert "更新完成后重新加载当前笔记本"

This reverts commit 67bf9836b83203093dd71f8df99b903bcaa0adb1.

* optimize code

* revert  VDirectoryTree.h

* format code

Co-authored-by: musmus9405 <542719479@qq.com>
This commit is contained in:
刘涛 2020-08-29 11:53:04 +08:00 committed by GitHub
parent fafd78af94
commit 1fb6e777a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 569 additions and 0 deletions

View File

@ -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

1
src/resources/icon.rc Normal file
View File

@ -0,0 +1 @@
IDI_ICON1 ICON DISCARDABLE "resources/icons/vnote.ico"

Binary file not shown.

View File

@ -5519,6 +5519,41 @@ Please check the network or image size</source>
<source>Use system&apos;s background color configuration for editor</source>
<translation>使</translation>
</message>
<message>
<location filename="../vmainwindow.cpp" line="1004"/>
<source>&amp;Sync</source>
<translation></translation>
</message>
<message>
<location filename="../vmainwindow.cpp" line="1006"/>
<source>&amp;Upload</source>
<translation></translation>
</message>
<message>
<location filename="../vmainwindow.cpp" line="1011"/>
<source>&amp;Download</source>
<translation></translation>
</message>
<message>
<location filename="../vmainwindow.cpp" line="1007"/>
<source>upload note</source>
<translation></translation>
</message>
<message>
<location filename="../vmainwindow.cpp" line="1012"/>
<source>download note</source>
<translation></translation>
</message>
<message>
<location filename="../vmainwindow.cpp" line="1028"/>
<source>Are you sure to close opened notes</source>
<translation></translation>
</message>
<message>
<location filename="../vmainwindow.cpp" line="1029"/>
<source>VNote will close all the opened notes before upload.</source>
<translation>VNote会在上传前关闭所有已打开笔记</translation>
</message>
</context>
<context>
<name>VMarkdownTab</name>
@ -8861,4 +8896,37 @@ Please check the network or image size</source>
<translation></translation>
</message>
</context>
<context>
<name>VSync</name>
<message>
<location filename="../utils/vSync.cpp" line="22"/>
<source>Sync</source>
<translation></translation>
</message>
<message>
<location filename="../utils/vSync.cpp" line="22"/>
<source>Sure</source>
<translation></translation>
</message>
<message>
<location filename="../utils/vSync.cpp" line="34"/>
<source>Downloading</source>
<translation>...</translation>
</message>
<message>
<location filename="../utils/vSync.cpp" line="41"/>
<source>Uploading</source>
<translation>...</translation>
</message>
<message>
<location filename="../utils/vSync.cpp" line="177"/>
<source>Download Success</source>
<translation></translation>
</message>
<message>
<location filename="../utils/vSync.cpp" line="202"/>
<source>Upload Success</source>
<translation></translation>
</message>
</context>
</TS>

217
src/utils/vSync.cpp Normal file
View File

@ -0,0 +1,217 @@
#include "vSync.h"
#include <qglobal.h>
#include <qdatetime.h>
#include <qdebug.h>
#include <qstring.h>
#include <qmessagebox.h>
#include <qpushbutton.h>
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();
}

84
src/utils/vSync.h Normal file
View File

@ -0,0 +1,84 @@
#ifndef _V_SYNC_H_
#define _V_SYNC_H_
#include <qstring.h>
#include <QObject>
#include <qprocess.h>
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

View File

@ -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 <span style=\"%1\">%2</span>?")
.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 <span style=\"%1\">%2</span>.")
.arg(g_config->c_dataTextStyle)
.arg(m_notebook->getName()),
tr("Please check if path <span style=\"%1\">%2</span> 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) {

View File

@ -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);

View File

@ -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<VNotebook*>& noteBooks = vnote->getNotebooks();
for (QVector<VNotebook*>::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<VNotebook *> &noteBooks = vnote->getNotebooks();
for (QVector<VNotebook *>::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()
{
}

View File

@ -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<QToolBar *> m_toolBars;
@ -512,6 +522,8 @@ private:
VTagExplorer *m_tagExplorer;
VSync *m_git;
// Whether sync note list to current tab.
bool m_syncNoteListToCurrentTab;