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;
This commit is contained in:
Le Tan 2017-09-26 19:27:11 +08:00
parent 6f1cab39ba
commit e5cd014762
10 changed files with 129 additions and 53 deletions

View File

@ -113,6 +113,9 @@ markdownit_opt_linkify=true
; Default name of the recycle bin of notebook ; Default name of the recycle bin of notebook
recycle_bin_folder=_v_recycle_bin 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 before deleting unused images
confirm_images_clean_up=true confirm_images_clean_up=true

View File

@ -22,7 +22,7 @@
#include <QRegExp> #include <QRegExp>
#include <QKeySequence> #include <QKeySequence>
#include "vfile.h" #include "vorphanfile.h"
#include "vnote.h" #include "vnote.h"
#include "vnotebook.h" #include "vnotebook.h"
#include "hgmarkdownhighlighter.h" #include "hgmarkdownhighlighter.h"
@ -740,13 +740,6 @@ QString VUtils::getShortcutText(const QString &p_keySeq)
return QKeySequence(p_keySeq).toString(QKeySequence::NativeText); 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, bool VUtils::deleteDirectory(const VNotebook *p_notebook,
const QString &p_path, const QString &p_path,
bool p_skipRecycleBin) bool p_skipRecycleBin)
@ -756,25 +749,7 @@ bool VUtils::deleteDirectory(const VNotebook *p_notebook,
return dir.removeRecursively(); return dir.removeRecursively();
} else { } else {
// Move it to the recycle bin folder. // Move it to the recycle bin folder.
QString binPath = getRecycleBinSubFolderToUse(p_notebook); return deleteFile(p_notebook->getRecycleBinFolderPath(), p_path);
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;
} }
} }
@ -815,41 +790,53 @@ bool VUtils::deleteFile(const VNotebook *p_notebook,
return file.remove(); return file.remove();
} else { } else {
// Move it to the recycle bin folder. // Move it to the recycle bin folder.
QString binPath = getRecycleBinSubFolderToUse(p_notebook); return deleteFile(p_notebook->getRecycleBinFolderPath(), p_path);
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;
} }
} }
bool VUtils::deleteFile(const QString &p_path, bool VUtils::deleteFile(const VOrphanFile *p_file,
const QString &p_path,
bool p_skipRecycleBin) bool p_skipRecycleBin)
{ {
if (p_skipRecycleBin) { if (p_skipRecycleBin) {
QFile file(p_path); QFile file(p_path);
return file.remove(); return file.remove();
} else { } else {
// TODO: Move it to the recycle bin folder. // Move it to the recycle bin folder.
QFile file(p_path); return deleteFile(p_file->fetchRecycleBinFolderPath(), p_path);
return file.remove();
} }
} }
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<VElementRegion> VUtils::fetchImageRegionsUsingParser(const QString &p_content) QVector<VElementRegion> VUtils::fetchImageRegionsUsingParser(const QString &p_content)
{ {
Q_ASSERT(!p_content.isEmpty()); Q_ASSERT(!p_content.isEmpty());

View File

@ -13,6 +13,7 @@
class QKeyEvent; class QKeyEvent;
class VFile; class VFile;
class VOrphanFile;
class VNotebook; class VNotebook;
#if !defined(V_ASSERT) #if !defined(V_ASSERT)
@ -151,9 +152,10 @@ public:
bool p_skipRecycleBin = false); bool p_skipRecycleBin = false);
// Delete file specified by @p_path. // 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. // @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); bool p_skipRecycleBin = false);
static QString displayDateTime(const QDateTime &p_dateTime); static QString displayDateTime(const QDateTime &p_dateTime);
@ -203,6 +205,11 @@ private:
// Use HGMarkdownParser to parse @p_content to get all image link regions. // Use HGMarkdownParser to parse @p_content to get all image link regions.
static QVector<VElementRegion> fetchImageRegionsUsingParser(const QString &p_content); static QVector<VElementRegion> 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);
// <value, name> // <value, name>
static QVector<QPair<QString, QString>> s_availableLanguages; static QVector<QPair<QString, QString>> s_availableLanguages;
}; };

View File

@ -208,6 +208,9 @@ void VConfigManager::initialize()
m_recycleBinFolder = getConfigFromSettings("global", m_recycleBinFolder = getConfigFromSettings("global",
"recycle_bin_folder").toString(); "recycle_bin_folder").toString();
m_recycleBinFolderExt = getConfigFromSettings("global",
"external_recycle_bin_folder").toString();
m_confirmImagesCleanUp = getConfigFromSettings("global", m_confirmImagesCleanUp = getConfigFromSettings("global",
"confirm_images_clean_up").toBool(); "confirm_images_clean_up").toBool();

View File

@ -271,6 +271,8 @@ public:
const QString &getRecycleBinFolder() const; const QString &getRecycleBinFolder() const;
const QString &getRecycleBinFolderExt() const;
bool getConfirmImagesCleanUp() const; bool getConfirmImagesCleanUp() const;
void setConfirmImagesCleanUp(bool p_enabled); void setConfirmImagesCleanUp(bool p_enabled);
@ -553,6 +555,9 @@ private:
// Default name of the recycle bin folder of notebook. // Default name of the recycle bin folder of notebook.
QString m_recycleBinFolder; QString m_recycleBinFolder;
// Default name of the recycle bin folder of external files.
QString m_recycleBinFolderExt;
// Confirm before deleting unused images. // Confirm before deleting unused images.
bool m_confirmImagesCleanUp; bool m_confirmImagesCleanUp;
@ -1439,6 +1444,11 @@ inline const QString &VConfigManager::getRecycleBinFolder() const
return m_recycleBinFolder; return m_recycleBinFolder;
} }
inline const QString &VConfigManager::getRecycleBinFolderExt() const
{
return m_recycleBinFolderExt;
}
inline bool VConfigManager::getConfirmImagesCleanUp() const inline bool VConfigManager::getConfirmImagesCleanUp() const
{ {
return m_confirmImagesCleanUp; return m_confirmImagesCleanUp;

View File

@ -146,6 +146,33 @@ void VEditWindow::initTabActions()
QUrl url = QUrl::fromLocalFile(file->fetchBasePath()); QUrl url = QUrl::fromLocalFile(file->fetchBasePath());
QDesktopServices::openUrl(url); 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<const VNoteFile *>((VFile *)file);
folderPath = tmpFile->getNotebook()->getRecycleBinFolderPath();
} else if (file->getType() == FileType::Orphan) {
const VOrphanFile *tmpFile = dynamic_cast<const VOrphanFile *>((VFile *)file);
folderPath = tmpFile->fetchRecycleBinFolderPath();
} else {
Q_ASSERT(false);
}
QUrl url = QUrl::fromLocalFile(folderPath);
QDesktopServices::openUrl(url);
});
} }
void VEditWindow::setupCornerWidget() void VEditWindow::setupCornerWidget()
@ -560,6 +587,11 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos)
m_locateAct->setData(tab); m_locateAct->setData(tab);
menu.addAction(m_locateAct); menu.addAction(m_locateAct);
menu.addSeparator();
m_recycleBinAct->setData(tab);
menu.addAction(m_recycleBinAct);
m_openLocationAct->setData(tab); m_openLocationAct->setData(tab);
menu.addAction(m_openLocationAct); menu.addAction(m_openLocationAct);
@ -567,6 +599,9 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos)
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_recycleBinAct->setData(tab);
menu.addAction(m_recycleBinAct);
m_openLocationAct->setData(tab); m_openLocationAct->setData(tab);
menu.addAction(m_openLocationAct); menu.addAction(m_openLocationAct);

View File

@ -177,6 +177,9 @@ private:
// Open the location (the folder containing this file) of this note. // Open the location (the folder containing this file) of this note.
QAction *m_openLocationAct; QAction *m_openLocationAct;
// Open the recycle bin folder of this note.
QAction *m_recycleBinAct;
}; };
inline QString VEditWindow::generateTooltip(const VFile *p_file) const inline QString VEditWindow::generateTooltip(const VFile *p_file) const

View File

@ -13,6 +13,7 @@
#include "dialog/vconfirmdeletiondialog.h" #include "dialog/vconfirmdeletiondialog.h"
#include "vimagepreviewer.h" #include "vimagepreviewer.h"
#include "vtextblockdata.h" #include "vtextblockdata.h"
#include "vorphanfile.h"
extern VConfigManager *g_config; extern VConfigManager *g_config;
extern VNote *g_vnote; extern VNote *g_vnote;
@ -308,8 +309,11 @@ void VMdEdit::clearUnusedImages()
if (m_file->getType() == FileType::Note) { if (m_file->getType() == FileType::Note) {
const VNoteFile *tmpFile = dynamic_cast<const VNoteFile *>((VFile *)m_file); const VNoteFile *tmpFile = dynamic_cast<const VNoteFile *>((VFile *)m_file);
ret = VUtils::deleteFile(tmpFile->getNotebook(), unusedImages[i], false); ret = VUtils::deleteFile(tmpFile->getNotebook(), unusedImages[i], false);
} else if (m_file->getType() == FileType::Orphan) {
const VOrphanFile *tmpFile = dynamic_cast<const VOrphanFile *>((VFile *)m_file);
ret = VUtils::deleteFile(tmpFile, unusedImages[i], false);
} else { } else {
ret = VUtils::deleteFile(unusedImages[i], false); Q_ASSERT(false);
} }
if (!ret) { if (!ret) {

View File

@ -67,3 +67,18 @@ QString VOrphanFile::getImageFolderInLink() const
return folder; 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);
}
}

View File

@ -35,6 +35,9 @@ public:
bool isSystemFile() const; bool isSystemFile() const;
// Get the recycle bin folder for this file.
QString fetchRecycleBinFolderPath() const;
private: private:
// Full path of this file. // Full path of this file.
QString m_path; QString m_path;
@ -45,6 +48,12 @@ private:
// Valid only within a session. // Valid only within a session.
QString m_imageFolder; 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. // Whether it is a system internal file.
bool m_systemFile; bool m_systemFile;
}; };