From e5cd0147621499df067ed71b11bec03d02fb5032 Mon Sep 17 00:00:00 2001 From: Le Tan Date: Tue, 26 Sep 2017 19:27:11 +0800 Subject: [PATCH] support recycle bin folder for extern files 1. Add external_recycle_bin_folder config; 2. By default, each external file will use _v_recycle_bin in the same directory as its recycle bin folder to hold deleted images; --- src/resources/vnote.ini | 3 ++ src/utils/vutils.cpp | 87 ++++++++++++++++++----------------------- src/utils/vutils.h | 11 +++++- src/vconfigmanager.cpp | 3 ++ src/vconfigmanager.h | 10 +++++ src/veditwindow.cpp | 35 +++++++++++++++++ src/veditwindow.h | 3 ++ src/vmdedit.cpp | 6 ++- src/vorphanfile.cpp | 15 +++++++ src/vorphanfile.h | 9 +++++ 10 files changed, 129 insertions(+), 53 deletions(-) diff --git a/src/resources/vnote.ini b/src/resources/vnote.ini index 6d39595a..70c080b8 100644 --- a/src/resources/vnote.ini +++ b/src/resources/vnote.ini @@ -113,6 +113,9 @@ markdownit_opt_linkify=true ; Default name of the recycle bin of notebook recycle_bin_folder=_v_recycle_bin +; Default name of the recycle bin of external files +external_recycle_bin_folder=_v_recycle_bin + ; Confirm before deleting unused images confirm_images_clean_up=true diff --git a/src/utils/vutils.cpp b/src/utils/vutils.cpp index d140035f..73c186c2 100644 --- a/src/utils/vutils.cpp +++ b/src/utils/vutils.cpp @@ -22,7 +22,7 @@ #include #include -#include "vfile.h" +#include "vorphanfile.h" #include "vnote.h" #include "vnotebook.h" #include "hgmarkdownhighlighter.h" @@ -740,13 +740,6 @@ QString VUtils::getShortcutText(const QString &p_keySeq) return QKeySequence(p_keySeq).toString(QKeySequence::NativeText); } -static QString getRecycleBinSubFolderToUse(const VNotebook *p_notebook) -{ - QString folderPath = p_notebook->getRecycleBinFolderPath(); - QDir dir(folderPath); - return QDir::cleanPath(dir.absoluteFilePath(QDateTime::currentDateTime().toString("yyyyMMdd"))); -} - bool VUtils::deleteDirectory(const VNotebook *p_notebook, const QString &p_path, bool p_skipRecycleBin) @@ -756,25 +749,7 @@ bool VUtils::deleteDirectory(const VNotebook *p_notebook, return dir.removeRecursively(); } else { // Move it to the recycle bin folder. - QString binPath = getRecycleBinSubFolderToUse(p_notebook); - QDir binDir(binPath); - if (!binDir.exists()) { - binDir.mkpath(binPath); - if (!binDir.exists()) { - return false; - } - } - - QString destName = getFileNameWithSequence(binPath, - directoryNameFromPath(p_path)); - - qDebug() << "try to move" << p_path << "to" << binPath << "as" << destName; - if (!binDir.rename(p_path, binDir.filePath(destName))) { - qWarning() << "fail to move directory" << p_path << "to" << binDir.filePath(destName); - return false; - } - - return true; + return deleteFile(p_notebook->getRecycleBinFolderPath(), p_path); } } @@ -815,41 +790,53 @@ bool VUtils::deleteFile(const VNotebook *p_notebook, return file.remove(); } else { // Move it to the recycle bin folder. - QString binPath = getRecycleBinSubFolderToUse(p_notebook); - QDir binDir(binPath); - if (!binDir.exists()) { - binDir.mkpath(binPath); - if (!binDir.exists()) { - return false; - } - } - - QString destName = getFileNameWithSequence(binPath, - fileNameFromPath(p_path)); - - qDebug() << "try to move" << p_path << "to" << binPath << "as" << destName; - if (!binDir.rename(p_path, binDir.filePath(destName))) { - qWarning() << "fail to move file" << p_path << "to" << binDir.filePath(destName); - return false; - } - - return true; + return deleteFile(p_notebook->getRecycleBinFolderPath(), p_path); } } -bool VUtils::deleteFile(const QString &p_path, +bool VUtils::deleteFile(const VOrphanFile *p_file, + const QString &p_path, bool p_skipRecycleBin) { if (p_skipRecycleBin) { QFile file(p_path); return file.remove(); } else { - // TODO: Move it to the recycle bin folder. - QFile file(p_path); - return file.remove(); + // Move it to the recycle bin folder. + return deleteFile(p_file->fetchRecycleBinFolderPath(), p_path); } } +static QString getRecycleBinSubFolderToUse(const QString &p_folderPath) +{ + QDir dir(p_folderPath); + return QDir::cleanPath(dir.absoluteFilePath(QDateTime::currentDateTime().toString("yyyyMMdd"))); +} + +bool VUtils::deleteFile(const QString &p_recycleBinFolderPath, + const QString &p_path) +{ + QString binPath = getRecycleBinSubFolderToUse(p_recycleBinFolderPath); + QDir binDir(binPath); + if (!binDir.exists()) { + binDir.mkpath(binPath); + if (!binDir.exists()) { + return false; + } + } + + QString destName = getFileNameWithSequence(binPath, + fileNameFromPath(p_path)); + + qDebug() << "try to move" << p_path << "to" << binPath << "as" << destName; + if (!binDir.rename(p_path, binDir.filePath(destName))) { + qWarning() << "fail to move" << p_path << "to" << binDir.filePath(destName); + return false; + } + + return true; +} + QVector VUtils::fetchImageRegionsUsingParser(const QString &p_content) { Q_ASSERT(!p_content.isEmpty()); diff --git a/src/utils/vutils.h b/src/utils/vutils.h index 2c228de7..ec02e841 100644 --- a/src/utils/vutils.h +++ b/src/utils/vutils.h @@ -13,6 +13,7 @@ class QKeyEvent; class VFile; +class VOrphanFile; class VNotebook; #if !defined(V_ASSERT) @@ -151,9 +152,10 @@ public: bool p_skipRecycleBin = false); // Delete file specified by @p_path. - // Will just move the file to the recycle bin of VNote if + // Will just move the file to the recycle bin of VOrphanFile if // @p_skipRecycleBin is false. - static bool deleteFile(const QString &p_path, + static bool deleteFile(const VOrphanFile *p_file, + const QString &p_path, bool p_skipRecycleBin = false); static QString displayDateTime(const QDateTime &p_dateTime); @@ -203,6 +205,11 @@ private: // Use HGMarkdownParser to parse @p_content to get all image link regions. static QVector fetchImageRegionsUsingParser(const QString &p_content); + // Delete file/directory specified by @p_path by moving it to the recycle bin + // folder @p_recycleBinFolderPath. + static bool deleteFile(const QString &p_recycleBinFolderPath, + const QString &p_path); + // static QVector> s_availableLanguages; }; diff --git a/src/vconfigmanager.cpp b/src/vconfigmanager.cpp index 4439b3f7..eab1199e 100644 --- a/src/vconfigmanager.cpp +++ b/src/vconfigmanager.cpp @@ -208,6 +208,9 @@ void VConfigManager::initialize() m_recycleBinFolder = getConfigFromSettings("global", "recycle_bin_folder").toString(); + m_recycleBinFolderExt = getConfigFromSettings("global", + "external_recycle_bin_folder").toString(); + m_confirmImagesCleanUp = getConfigFromSettings("global", "confirm_images_clean_up").toBool(); diff --git a/src/vconfigmanager.h b/src/vconfigmanager.h index 48e15c59..88a943d6 100644 --- a/src/vconfigmanager.h +++ b/src/vconfigmanager.h @@ -271,6 +271,8 @@ public: const QString &getRecycleBinFolder() const; + const QString &getRecycleBinFolderExt() const; + bool getConfirmImagesCleanUp() const; void setConfirmImagesCleanUp(bool p_enabled); @@ -553,6 +555,9 @@ private: // Default name of the recycle bin folder of notebook. QString m_recycleBinFolder; + // Default name of the recycle bin folder of external files. + QString m_recycleBinFolderExt; + // Confirm before deleting unused images. bool m_confirmImagesCleanUp; @@ -1439,6 +1444,11 @@ inline const QString &VConfigManager::getRecycleBinFolder() const return m_recycleBinFolder; } +inline const QString &VConfigManager::getRecycleBinFolderExt() const +{ + return m_recycleBinFolderExt; +} + inline bool VConfigManager::getConfirmImagesCleanUp() const { return m_confirmImagesCleanUp; diff --git a/src/veditwindow.cpp b/src/veditwindow.cpp index aad29f53..0648c13c 100644 --- a/src/veditwindow.cpp +++ b/src/veditwindow.cpp @@ -146,6 +146,33 @@ void VEditWindow::initTabActions() QUrl url = QUrl::fromLocalFile(file->fetchBasePath()); QDesktopServices::openUrl(url); }); + + m_recycleBinAct = new QAction(QIcon(":/resources/icons/recycle_bin.svg"), + tr("&Recycle Bin"), this); + m_recycleBinAct->setToolTip(tr("Open the recycle bin of this note")); + connect(m_recycleBinAct, &QAction::triggered, + this, [this]() { + int tab = this->m_closeTabAct->data().toInt(); + Q_ASSERT(tab != -1); + + VEditTab *editor = getTab(tab); + VFile *file = editor->getFile(); + Q_ASSERT(file); + + QString folderPath; + if (file->getType() == FileType::Note) { + const VNoteFile *tmpFile = dynamic_cast((VFile *)file); + folderPath = tmpFile->getNotebook()->getRecycleBinFolderPath(); + } else if (file->getType() == FileType::Orphan) { + const VOrphanFile *tmpFile = dynamic_cast((VFile *)file); + folderPath = tmpFile->fetchRecycleBinFolderPath(); + } else { + Q_ASSERT(false); + } + + QUrl url = QUrl::fromLocalFile(folderPath); + QDesktopServices::openUrl(url); + }); } void VEditWindow::setupCornerWidget() @@ -560,6 +587,11 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos) m_locateAct->setData(tab); menu.addAction(m_locateAct); + menu.addSeparator(); + + m_recycleBinAct->setData(tab); + menu.addAction(m_recycleBinAct); + m_openLocationAct->setData(tab); menu.addAction(m_openLocationAct); @@ -567,6 +599,9 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos) menu.addAction(m_noteInfoAct); } else if (file->getType() == FileType::Orphan && !(dynamic_cast(file)->isSystemFile())) { + m_recycleBinAct->setData(tab); + menu.addAction(m_recycleBinAct); + m_openLocationAct->setData(tab); menu.addAction(m_openLocationAct); diff --git a/src/veditwindow.h b/src/veditwindow.h index 83a56ee6..40e6b176 100644 --- a/src/veditwindow.h +++ b/src/veditwindow.h @@ -177,6 +177,9 @@ private: // Open the location (the folder containing this file) of this note. QAction *m_openLocationAct; + + // Open the recycle bin folder of this note. + QAction *m_recycleBinAct; }; inline QString VEditWindow::generateTooltip(const VFile *p_file) const diff --git a/src/vmdedit.cpp b/src/vmdedit.cpp index 02a81e97..bac4f358 100644 --- a/src/vmdedit.cpp +++ b/src/vmdedit.cpp @@ -13,6 +13,7 @@ #include "dialog/vconfirmdeletiondialog.h" #include "vimagepreviewer.h" #include "vtextblockdata.h" +#include "vorphanfile.h" extern VConfigManager *g_config; extern VNote *g_vnote; @@ -308,8 +309,11 @@ void VMdEdit::clearUnusedImages() if (m_file->getType() == FileType::Note) { const VNoteFile *tmpFile = dynamic_cast((VFile *)m_file); ret = VUtils::deleteFile(tmpFile->getNotebook(), unusedImages[i], false); + } else if (m_file->getType() == FileType::Orphan) { + const VOrphanFile *tmpFile = dynamic_cast((VFile *)m_file); + ret = VUtils::deleteFile(tmpFile, unusedImages[i], false); } else { - ret = VUtils::deleteFile(unusedImages[i], false); + Q_ASSERT(false); } if (!ret) { diff --git a/src/vorphanfile.cpp b/src/vorphanfile.cpp index 599e8aec..a0cf9543 100644 --- a/src/vorphanfile.cpp +++ b/src/vorphanfile.cpp @@ -67,3 +67,18 @@ QString VOrphanFile::getImageFolderInLink() const return folder; } + +QString VOrphanFile::fetchRecycleBinFolderPath() const +{ + QString folder = m_recycleBinFolder; + if (m_recycleBinFolder.isEmpty()) { + folder = g_config->getRecycleBinFolderExt(); + } + + QFileInfo fi(folder); + if (fi.isAbsolute()) { + return folder; + } else { + return QDir(fetchBasePath()).filePath(folder); + } +} diff --git a/src/vorphanfile.h b/src/vorphanfile.h index 54e6b8ca..6d4b851a 100644 --- a/src/vorphanfile.h +++ b/src/vorphanfile.h @@ -35,6 +35,9 @@ public: bool isSystemFile() const; + // Get the recycle bin folder for this file. + QString fetchRecycleBinFolderPath() const; + private: // Full path of this file. QString m_path; @@ -45,6 +48,12 @@ private: // Valid only within a session. QString m_imageFolder; + // Recycle bin forlder. + // May be absolute or relative path. + // Empty to use the global default config. + // Valid only within a session. + QString m_recycleBinFolder; + // Whether it is a system internal file. bool m_systemFile; };