refactor VDirectoryTree

- Refine folder deletion logics;
- Refine folder copy/paste logics;
- Add folder sort logics;
This commit is contained in:
Le Tan 2017-09-29 20:31:13 +08:00
parent f9080db71c
commit 3724eb35dd
13 changed files with 796 additions and 280 deletions

View File

@ -132,6 +132,11 @@ void VSortDialog::treeUpdated()
m_treeWidget->resizeColumnToContents(i); m_treeWidget->resizeColumnToContents(i);
} }
QHeaderView *header = m_treeWidget->header();
if (header) {
header->setStretchLastSection(true);
}
// We just need single level. // We just need single level.
int cnt = m_treeWidget->topLevelItemCount(); int cnt = m_treeWidget->topLevelItemCount();
for (int i = 0; i < cnt; ++i) { for (int i = 0; i < cnt; ++i) {

View File

@ -374,7 +374,6 @@ void VAttachmentList::sortItems()
QTreeWidget *tree = dialog.getTreeWidget(); QTreeWidget *tree = dialog.getTreeWidget();
tree->clear(); tree->clear();
tree->setColumnCount(1); tree->setColumnCount(1);
tree->header()->setStretchLastSection(true);
QStringList headers; QStringList headers;
headers << tr("Name"); headers << tr("Name");
tree->setHeaderLabels(headers); tree->setHeaderLabels(headers);

View File

@ -19,6 +19,7 @@ namespace ClipboardConfig
static const QString c_magic = "magic"; static const QString c_magic = "magic";
static const QString c_isCut = "is_cut"; static const QString c_isCut = "is_cut";
static const QString c_files = "files"; static const QString c_files = "files";
static const QString c_dirs = "dirs";
} }
enum class OpenFileMode {Read = 0, Edit}; enum class OpenFileMode {Read = 0, Edit};

View File

@ -10,8 +10,8 @@
extern VConfigManager *g_config; extern VConfigManager *g_config;
VDirectory::VDirectory(VNotebook *p_notebook, VDirectory::VDirectory(VNotebook *p_notebook,
VDirectory *p_parent,
const QString &p_name, const QString &p_name,
QObject *p_parent,
QDateTime p_createdTimeUtc) QDateTime p_createdTimeUtc)
: QObject(p_parent), : QObject(p_parent),
m_notebook(p_notebook), m_notebook(p_notebook),
@ -45,7 +45,7 @@ bool VDirectory::open()
QJsonArray dirJson = configJson[DirConfig::c_subDirectories].toArray(); QJsonArray dirJson = configJson[DirConfig::c_subDirectories].toArray();
for (int i = 0; i < dirJson.size(); ++i) { for (int i = 0; i < dirJson.size(); ++i) {
QJsonObject dirItem = dirJson[i].toObject(); QJsonObject dirItem = dirJson[i].toObject();
VDirectory *dir = new VDirectory(m_notebook, dirItem[DirConfig::c_name].toString(), this); VDirectory *dir = new VDirectory(m_notebook, this, dirItem[DirConfig::c_name].toString());
m_subDirs.append(dir); m_subDirs.append(dir);
} }
@ -188,28 +188,37 @@ void VDirectory::addNotebookConfig(QJsonObject &p_json) const
} }
} }
VDirectory *VDirectory::createSubDirectory(const QString &p_name) VDirectory *VDirectory::createSubDirectory(const QString &p_name,
QString *p_errMsg)
{ {
Q_ASSERT(!p_name.isEmpty()); Q_ASSERT(!p_name.isEmpty());
// First open current directory
if (!open()) { if (!open()) {
VUtils::addErrMsg(p_errMsg, tr("Fail to open folder %1.").arg(m_name));
return NULL; return NULL;
} }
qDebug() << "create subfolder" << p_name << "in" << m_name; QDir dir(fetchPath());
if (dir.exists(p_name)) {
VUtils::addErrMsg(p_errMsg, tr("%1 already exists in directory %2.")
.arg(p_name)
.arg(fetchPath()));
return NULL;
}
QString path = fetchPath();
QDir dir(path);
if (!dir.mkdir(p_name)) { if (!dir.mkdir(p_name)) {
qWarning() << "fail to create directory" << p_name << "under" << path; VUtils::addErrMsg(p_errMsg, tr("Fail to create folder in %1.")
.arg(m_name));
return NULL; return NULL;
} }
VDirectory *ret = new VDirectory(m_notebook, VDirectory *ret = new VDirectory(m_notebook,
p_name,
this, this,
p_name,
QDateTime::currentDateTimeUtc()); QDateTime::currentDateTimeUtc());
if (!ret->writeToConfig()) { if (!ret->writeToConfig()) {
VUtils::addErrMsg(p_errMsg, tr("Fail to write configuration of folder %1.")
.arg(p_name));
dir.rmdir(p_name); dir.rmdir(p_name);
delete ret; delete ret;
return NULL; return NULL;
@ -217,11 +226,13 @@ VDirectory *VDirectory::createSubDirectory(const QString &p_name)
m_subDirs.append(ret); m_subDirs.append(ret);
if (!writeToConfig()) { if (!writeToConfig()) {
VConfigManager::deleteDirectoryConfig(QDir(path).filePath(p_name)); VUtils::addErrMsg(p_errMsg, tr("Fail to write configuration of folder %1.")
dir.rmdir(p_name); .arg(p_name));
QDir subdir(dir.filePath(p_name));
subdir.removeRecursively();
delete ret; delete ret;
m_subDirs.removeLast(); m_subDirs.removeLast();
return NULL; return NULL;
} }
@ -399,13 +410,13 @@ bool VDirectory::addSubDirectory(VDirectory *p_dir, int p_index)
VDirectory *VDirectory::addSubDirectory(const QString &p_name, int p_index) VDirectory *VDirectory::addSubDirectory(const QString &p_name, int p_index)
{ {
if (!open()) { if (!open() || p_name.isEmpty()) {
return NULL; return NULL;
} }
VDirectory *dir = new VDirectory(m_notebook, VDirectory *dir = new VDirectory(m_notebook,
p_name,
this, this,
p_name,
QDateTime::currentDateTimeUtc()); QDateTime::currentDateTimeUtc());
if (!dir) { if (!dir) {
return NULL; return NULL;
@ -419,24 +430,45 @@ VDirectory *VDirectory::addSubDirectory(const QString &p_name, int p_index)
return dir; return dir;
} }
void VDirectory::deleteSubDirectory(VDirectory *p_subDir, bool p_skipRecycleBin) bool VDirectory::deleteDirectory(bool p_skipRecycleBin, QString *p_errMsg)
{ {
Q_ASSERT(p_subDir->getNotebook() == m_notebook); Q_ASSERT(!m_opened);
Q_ASSERT(parent());
QString dirPath = p_subDir->fetchPath();
p_subDir->close();
removeSubDirectory(p_subDir);
// Delete the entire directory. // Delete the entire directory.
bool ret = true;
QString dirPath = fetchPath();
if (!VUtils::deleteDirectory(m_notebook, dirPath, p_skipRecycleBin)) { if (!VUtils::deleteDirectory(m_notebook, dirPath, p_skipRecycleBin)) {
qWarning() << "fail to remove directory" << dirPath << "recursively"; VUtils::addErrMsg(p_errMsg, tr("Fail to delete the directory %1.").arg(dirPath));
} else { ret = false;
qDebug() << "deleted" << dirPath << (p_skipRecycleBin ? "from disk" : "to recycle bin");
} }
delete p_subDir; return ret;
}
bool VDirectory::deleteDirectory(VDirectory *p_dir, bool p_skipRecycleBin, QString *p_errMsg)
{
p_dir->close();
bool ret = true;
QString name = p_dir->getName();
QString path = p_dir->fetchPath();
if (!p_dir->deleteDirectory(p_skipRecycleBin, p_errMsg)) {
ret = false;
}
VDirectory *paDir = p_dir->getParentDirectory();
Q_ASSERT(paDir);
if (!paDir->removeSubDirectory(p_dir)) {
VUtils::addErrMsg(p_errMsg, tr("Fail to remove the folder from the folder configuration."));
ret = false;
}
delete p_dir;
return ret;
} }
bool VDirectory::removeSubDirectory(VDirectory *p_dir) bool VDirectory::removeSubDirectory(VDirectory *p_dir)
@ -452,8 +484,6 @@ bool VDirectory::removeSubDirectory(VDirectory *p_dir)
return false; return false;
} }
qDebug() << "folder" << p_dir->getName() << "removed from folder" << m_name;
return true; return true;
} }
@ -504,35 +534,48 @@ bool VDirectory::rename(const QString &p_name)
return true; return true;
} }
// Copy @p_srcDir to be a sub-directory of @p_destDir with name @p_destName. bool VDirectory::copyDirectory(VDirectory *p_destDir,
VDirectory *VDirectory::copyDirectory(VDirectory *p_destDir, const QString &p_destName, const QString &p_destName,
VDirectory *p_srcDir, bool p_cut) VDirectory *p_dir,
bool p_isCut,
VDirectory **p_targetDir,
QString *p_errMsg)
{ {
QString srcPath = QDir::cleanPath(p_srcDir->fetchPath()); bool ret = true;
*p_targetDir = NULL;
QString srcPath = QDir::cleanPath(p_dir->fetchPath());
QString destPath = QDir::cleanPath(QDir(p_destDir->fetchPath()).filePath(p_destName)); QString destPath = QDir::cleanPath(QDir(p_destDir->fetchPath()).filePath(p_destName));
if (VUtils::equalPath(srcPath, destPath)) { if (VUtils::equalPath(srcPath, destPath)) {
return p_srcDir; *p_targetDir = p_dir;
return false;
} }
VDirectory *srcParentDir = p_srcDir->getParentDirectory(); if (!p_destDir->isOpened()) {
VUtils::addErrMsg(p_errMsg, tr("Fail to open target folder."));
// Copy the directory return false;
if (!VUtils::copyDirectory(srcPath, destPath, p_cut)) {
return NULL;
} }
// Handle VDirectory QString opStr = p_isCut ? tr("cut") : tr("copy");
int index = -1; VDirectory *paDir = p_dir->getParentDirectory();
Q_ASSERT(paDir->isOpened());
// Copy the directory.
if (!VUtils::copyDirectory(srcPath, destPath, p_isCut)) {
VUtils::addErrMsg(p_errMsg, tr("Fail to %1 the folder.").arg(opStr));
qWarning() << "fail to" << opStr << "the folder directory" << srcPath << "to" << destPath;
return false;
}
// Add directory to VDirectory.
VDirectory *destDir = NULL; VDirectory *destDir = NULL;
if (p_cut) { if (p_isCut) {
// Remove the directory from config paDir->removeSubDirectory(p_dir);
srcParentDir->removeSubDirectory(p_srcDir); p_dir->setName(p_destName);
p_srcDir->setName(p_destName);
// Add the directory to new dir's config // Add the directory to new dir's config
if (p_destDir->addSubDirectory(p_srcDir, index)) { if (p_destDir->addSubDirectory(p_dir, -1)) {
destDir = p_srcDir; destDir = p_dir;
} else { } else {
destDir = NULL; destDir = NULL;
} }
@ -540,7 +583,15 @@ VDirectory *VDirectory::copyDirectory(VDirectory *p_destDir, const QString &p_de
destDir = p_destDir->addSubDirectory(p_destName, -1); destDir = p_destDir->addSubDirectory(p_destName, -1);
} }
return destDir; if (!destDir) {
VUtils::addErrMsg(p_errMsg, tr("Fail to add the folder to target folder's configuration."));
return false;
}
qDebug() << "copyDirectory:" << p_dir << "to" << destDir;
*p_targetDir = destDir;
return ret;
} }
void VDirectory::setExpanded(bool p_expanded) void VDirectory::setExpanded(bool p_expanded)
@ -591,6 +642,39 @@ VNoteFile *VDirectory::tryLoadFile(QStringList &p_filePath)
return file; return file;
} }
VDirectory *VDirectory::tryLoadDirectory(QStringList &p_filePath)
{
qDebug() << "directory" << m_name << "tryLoadDirectory()" << p_filePath.join("/");
if (p_filePath.isEmpty()) {
return NULL;
}
bool opened = isOpened();
if (!open()) {
return NULL;
}
#if defined(Q_OS_WIN)
bool caseSensitive = false;
#else
bool caseSensitive = true;
#endif
VDirectory *dir = findSubDirectory(p_filePath.at(0), caseSensitive);
if (dir) {
if (p_filePath.size() > 1) {
p_filePath.removeFirst();
dir = dir->tryLoadDirectory(p_filePath);
}
}
if (!dir && !opened) {
close();
}
return dir;
}
bool VDirectory::sortFiles(const QVector<int> &p_sortedIdx) bool VDirectory::sortFiles(const QVector<int> &p_sortedIdx)
{ {
V_ASSERT(m_opened); V_ASSERT(m_opened);
@ -611,3 +695,24 @@ bool VDirectory::sortFiles(const QVector<int> &p_sortedIdx)
return ret; return ret;
} }
bool VDirectory::sortSubDirectories(const QVector<int> &p_sortedIdx)
{
V_ASSERT(m_opened);
V_ASSERT(p_sortedIdx.size() == m_subDirs.size());
auto ori = m_subDirs;
for (int i = 0; i < p_sortedIdx.size(); ++i) {
m_subDirs[i] = ori[p_sortedIdx[i]];
}
bool ret = true;
if (!writeToConfig()) {
qWarning() << "fail to reorder sub-directories in config" << p_sortedIdx;
m_subDirs = ori;
ret = false;
}
return ret;
}

View File

@ -17,13 +17,16 @@ class VDirectory : public QObject
Q_OBJECT Q_OBJECT
public: public:
VDirectory(VNotebook *p_notebook, VDirectory(VNotebook *p_notebook,
VDirectory *p_parent,
const QString &p_name, const QString &p_name,
QObject *p_parent = 0,
QDateTime p_createdTimeUtc = QDateTime()); QDateTime p_createdTimeUtc = QDateTime());
bool open(); bool open();
void close(); void close();
VDirectory *createSubDirectory(const QString &p_name);
// Create a sub-directory with name @p_name.
VDirectory *createSubDirectory(const QString &p_name,
QString *p_errMsg = NULL);
// Returns the VDirectory with the name @p_name directly in this directory. // Returns the VDirectory with the name @p_name directly in this directory.
VDirectory *findSubDirectory(const QString &p_name, bool p_caseSensitive); VDirectory *findSubDirectory(const QString &p_name, bool p_caseSensitive);
@ -36,9 +39,6 @@ public:
VNoteFile *createFile(const QString &p_name); VNoteFile *createFile(const QString &p_name);
// Remove and delete subdirectory @p_subDir.
void deleteSubDirectory(VDirectory *p_subDir, bool p_skipRecycleBin = false);
// Remove the file in the config and m_files without deleting it in the disk. // Remove the file in the config and m_files without deleting it in the disk.
// It won't change the parent of @p_file to enable it find its path. // It won't change the parent of @p_file to enable it find its path.
bool removeFile(VNoteFile *p_file); bool removeFile(VNoteFile *p_file);
@ -58,10 +58,17 @@ public:
// Rename current directory to @p_name. // Rename current directory to @p_name.
bool rename(const QString &p_name); bool rename(const QString &p_name);
static VDirectory *copyDirectory(VDirectory *p_destDir, const QString &p_destName, // Copy @p_dir as a sub-directory of @p_destDir with the new name @p_destName.
VDirectory *p_srcDir, bool p_cut); // Return a directory representing the destination directory after copy/cut.
static bool copyDirectory(VDirectory *p_destDir,
const QString &p_destName,
VDirectory *p_dir,
bool p_isCut,
VDirectory **p_targetDir,
QString *p_errMsg = NULL);
const QVector<VDirectory *> &getSubDirs() const; const QVector<VDirectory *> &getSubDirs() const;
const QString &getName() const; const QString &getName() const;
void setName(const QString &p_name); void setName(const QString &p_name);
bool isOpened() const; bool isOpened() const;
@ -96,11 +103,22 @@ public:
// Try to load file given relative path @p_filePath. // Try to load file given relative path @p_filePath.
VNoteFile *tryLoadFile(QStringList &p_filePath); VNoteFile *tryLoadFile(QStringList &p_filePath);
// Try to load directory given relative path @p_filePath.
VDirectory *tryLoadDirectory(QStringList &p_filePath);
QDateTime getCreatedTimeUtc() const; QDateTime getCreatedTimeUtc() const;
// Reorder files in m_files by index. // Reorder files in m_files by index.
bool sortFiles(const QVector<int> &p_sortedIdx); bool sortFiles(const QVector<int> &p_sortedIdx);
// Reorder sub-directories in m_subDirs by index.
bool sortSubDirectories(const QVector<int> &p_sortedIdx);
// Delete directory @p_dir.
static bool deleteDirectory(VDirectory *p_dir,
bool p_skipRecycleBin = false,
QString *p_errMsg = NULL);
private: private:
// Get the path of @p_dir recursively // Get the path of @p_dir recursively
QString fetchPath(const VDirectory *p_dir) const; QString fetchPath(const VDirectory *p_dir) const;
@ -121,6 +139,9 @@ private:
// Add the directory in the config and m_subDirs. If @p_index is -1, add it at the end. // Add the directory in the config and m_subDirs. If @p_index is -1, add it at the end.
bool addSubDirectory(VDirectory *p_dir, int p_index); bool addSubDirectory(VDirectory *p_dir, int p_index);
// Delete this directory in disk.
bool deleteDirectory(bool p_skipRecycleBin = false, QString *p_errMsg = NULL);
// Notebook containing this folder. // Notebook containing this folder.
QPointer<VNotebook> m_notebook; QPointer<VNotebook> m_notebook;

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,6 @@
#include "vnotebook.h" #include "vnotebook.h"
#include "vnavigationmode.h" #include "vnavigationmode.h"
class VNote;
class VEditArea; class VEditArea;
class QLabel; class QLabel;
@ -20,10 +19,14 @@ class VDirectoryTree : public QTreeWidget, public VNavigationMode
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit VDirectoryTree(VNote *vnote, QWidget *parent = 0); explicit VDirectoryTree(QWidget *parent = 0);
inline void setEditArea(VEditArea *p_editArea);
void setEditArea(VEditArea *p_editArea);
// Locate to the item representing @p_directory.
bool locateDirectory(const VDirectory *p_directory); bool locateDirectory(const VDirectory *p_directory);
inline const VNotebook *currentNotebook() const;
const VNotebook *currentNotebook() const;
// Implementations for VNavigationMode. // Implementations for VNavigationMode.
void registerNavigation(QChar p_majorKey) Q_DECL_OVERRIDE; void registerNavigation(QChar p_majorKey) Q_DECL_OVERRIDE;
@ -33,12 +36,17 @@ public:
signals: signals:
void currentDirectoryChanged(VDirectory *p_directory); void currentDirectoryChanged(VDirectory *p_directory);
void directoryUpdated(const VDirectory *p_directory); void directoryUpdated(const VDirectory *p_directory);
public slots: public slots:
// Set directory tree to display a given notebook @p_notebook.
void setNotebook(VNotebook *p_notebook); void setNotebook(VNotebook *p_notebook);
// Create a root folder.
void newRootDirectory(); void newRootDirectory();
void deleteDirectory();
// View and edit info about directory.
void editDirectoryInfo(); void editDirectoryInfo();
// Clear and re-build the whole directory tree. // Clear and re-build the whole directory tree.
@ -46,75 +54,117 @@ public slots:
void updateDirectoryTree(); void updateDirectoryTree();
private slots: private slots:
// Set the state of expansion of the directory.
void handleItemExpanded(QTreeWidgetItem *p_item); void handleItemExpanded(QTreeWidgetItem *p_item);
// Set the state of expansion of the directory.
void handleItemCollapsed(QTreeWidgetItem *p_item); void handleItemCollapsed(QTreeWidgetItem *p_item);
void contextMenuRequested(QPoint pos); void contextMenuRequested(QPoint pos);
// Directory selected folder.
// Currently only support single selected item.
void deleteSelectedDirectory();
// Create sub-directory of current item's directory.
void newSubDirectory(); void newSubDirectory();
// Current tree item changed.
void currentDirectoryItemChanged(QTreeWidgetItem *currentItem); void currentDirectoryItemChanged(QTreeWidgetItem *currentItem);
void copySelectedDirectories(bool p_cut = false);
// Copy selected directories.
// Will put a Json string into the clipboard which contains the information
// about copied directories.
void copySelectedDirectories(bool p_isCut = false);
void cutSelectedDirectories(); void cutSelectedDirectories();
void pasteDirectoriesInCurDir();
// Paste directories from clipboard as sub-directories of current item.
void pasteDirectoriesFromClipboard();
// Open the folder's parent directory in system's file browser.
void openDirectoryLocation() const; void openDirectoryLocation() const;
// Reload the content of current directory. // Reload the content of current directory.
void reloadFromDisk(); void reloadFromDisk();
// Sort sub-folders of current item's folder.
void sortItems();
protected: protected:
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
private: private:
// Build the subtree of @p_parent recursively to the depth @p_depth.
// Item @p_parent must not be built before.
// Will expand the item if the corresponding directory was expanded before.
// @p_depth: valid only when greater than 0.
void updateDirectoryTreeOne(QTreeWidgetItem *p_parent, int p_depth);
// Build the subtree of @p_parent recursively to the depth @p_depth. // Build the subtree of @p_parent recursively to the depth @p_depth.
// @p_depth: negative - infinite levels. // @p_depth: negative - infinite levels.
// Will expand the item if the corresponding directory was expanded before. // Will expand the item if the corresponding directory was expanded before.
// Will treat items with children as items having been built before.
void buildSubTree(QTreeWidgetItem *p_parent, int p_depth); void buildSubTree(QTreeWidgetItem *p_parent, int p_depth);
// Fill the content of a tree item. // Fill the content of a tree item according to @p_directory.
void fillTreeItem(QTreeWidgetItem &p_item, const QString &p_name, void fillTreeItem(QTreeWidgetItem *p_item, VDirectory *p_directory);
VDirectory *p_directory, const QIcon &p_icon);
void initShortcuts(); void initShortcuts();
void initActions(); void initActions();
// Update @p_item's direct children only: deleted, added, renamed. // Update @p_item's direct children only: deleted, added, renamed.
void updateItemChildren(QTreeWidgetItem *p_item); void updateItemDirectChildren(QTreeWidgetItem *p_item);
// Find the corresponding item of @p_dir; // Find the corresponding item of @p_dir;
// Return's NULL if no item is found and it is the root directory if @p_widget is true. // Return's NULL if no item is found and it is the root directory if @p_widget is true.
QTreeWidgetItem *findVDirectory(const VDirectory *p_dir, bool &p_widget); QTreeWidgetItem *findVDirectory(const VDirectory *p_dir, bool *p_widget = NULL);
inline QPointer<VDirectory> getVDirectory(QTreeWidgetItem *p_item) const;
void copyDirectoryInfoToClipboard(const QJsonArray &p_dirs, bool p_cut); QPointer<VDirectory> getVDirectory(QTreeWidgetItem *p_item) const;
void pasteDirectories(VDirectory *p_destDir);
bool copyDirectory(VDirectory *p_destDir, const QString &p_destName, // Paste @p_dirs as sub-directory of @p_destDir.
VDirectory *p_srcDir, bool p_cut); void pasteDirectories(VDirectory *p_destDir,
const QVector<QString> &p_dirs,
bool p_isCut);
// Build the subtree of @p_item's children if it has not been built yet. // Build the subtree of @p_item's children if it has not been built yet.
void updateChildren(QTreeWidgetItem *p_item); // We need to fill the children before showing a item to get a correct render.
void buildChildren(QTreeWidgetItem *p_item);
// Expand/create the directory tree nodes to @p_directory. // Expand/create the directory tree nodes to @p_directory.
QTreeWidgetItem *expandToVDirectory(const VDirectory *p_directory); QTreeWidgetItem *expandToVDirectory(const VDirectory *p_directory);
// Expand the currently-built subtree of @p_item according to VDirectory.isExpanded(). // Expand the currently-built subtree of @p_item according to VDirectory.isExpanded().
void expandItemTree(QTreeWidgetItem *p_item); void expandSubTree(QTreeWidgetItem *p_item);
QList<QTreeWidgetItem *> getVisibleItems() const; QList<QTreeWidgetItem *> getVisibleItems() const;
QList<QTreeWidgetItem *> getVisibleChildItems(const QTreeWidgetItem *p_item) const; QList<QTreeWidgetItem *> getVisibleChildItems(const QTreeWidgetItem *p_item) const;
// We use a map to save and restore current directory of each notebook.
// Try to restore current directory after changing notebook.
// Return false if no cache item found for current notebook.
bool restoreCurrentItem(); bool restoreCurrentItem();
VNote *vnote; // Generate new magic to m_magicForClipboard.
int getNewMagic();
// Check if @p_magic equals to m_magicForClipboard.
bool checkMagic(int p_magic) const;
// Check if clipboard contains valid info to paste as directories.
bool pasteAvailable() const;
// Sort sub-directories of @p_dir.
void sortItems(VDirectory *p_dir);
QPointer<VNotebook> m_notebook; QPointer<VNotebook> m_notebook;
QVector<QPointer<VDirectory> > m_copiedDirs;
VEditArea *m_editArea; VEditArea *m_editArea;
// Each notebook's current item's VDirectory. // Each notebook's current item's VDirectory.
QHash<VNotebook *, VDirectory *> m_notebookCurrentDirMap; QHash<VNotebook *, VDirectory *> m_notebookCurrentDirMap;
// Magic number for clipboard operations.
int m_magicForClipboard;
// Actions // Actions
QAction *newRootDirAct; QAction *newRootDirAct;
QAction *newSiblingDirAct; QAction *newSiblingDirAct;
@ -125,6 +175,7 @@ private:
QAction *cutAct; QAction *cutAct;
QAction *pasteAct; QAction *pasteAct;
QAction *m_openLocationAct; QAction *m_openLocationAct;
QAction *m_sortAct;
// Reload content from disk. // Reload content from disk.
QAction *m_reloadAct; QAction *m_reloadAct;

View File

@ -702,15 +702,16 @@ void VFileList::pasteFilesFromClipboard()
} }
pasteFiles(m_directory, filesToPaste, isCut); pasteFiles(m_directory, filesToPaste, isCut);
QClipboard *clipboard = QApplication::clipboard();
clipboard->clear();
} }
void VFileList::pasteFiles(VDirectory *p_destDir, void VFileList::pasteFiles(VDirectory *p_destDir,
const QVector<QString> &p_files, const QVector<QString> &p_files,
bool p_isCut) bool p_isCut)
{ {
QClipboard *clipboard = QApplication::clipboard();
if (!p_destDir || p_files.isEmpty()) { if (!p_destDir || p_files.isEmpty()) {
clipboard->clear();
return; return;
} }
@ -721,7 +722,7 @@ void VFileList::pasteFiles(VDirectory *p_destDir,
qWarning() << "Copied file is not an internal note" << p_files[i]; qWarning() << "Copied file is not an internal note" << p_files[i];
VUtils::showMessage(QMessageBox::Warning, VUtils::showMessage(QMessageBox::Warning,
tr("Warning"), tr("Warning"),
tr("Fail to copy note <span style=\"%1\">%2</span>.") tr("Fail to paste note <span style=\"%1\">%2</span>.")
.arg(g_config->c_dataTextStyle) .arg(g_config->c_dataTextStyle)
.arg(p_files[i]), .arg(p_files[i]),
tr("VNote could not find this note in any notebook."), tr("VNote could not find this note in any notebook."),
@ -794,7 +795,7 @@ void VFileList::pasteFiles(VDirectory *p_destDir,
} }
} }
qDebug() << "copy" << nrPasted << "files"; qDebug() << "pasted" << nrPasted << "files";
if (nrPasted > 0) { if (nrPasted > 0) {
g_mainWin->showStatusMessage(tr("%1 %2 pasted") g_mainWin->showStatusMessage(tr("%1 %2 pasted")
.arg(nrPasted) .arg(nrPasted)
@ -802,7 +803,6 @@ void VFileList::pasteFiles(VDirectory *p_destDir,
} }
updateFileList(); updateFileList();
clipboard->clear();
getNewMagic(); getNewMagic();
} }
@ -1021,7 +1021,6 @@ void VFileList::sortItems()
QTreeWidget *tree = dialog.getTreeWidget(); QTreeWidget *tree = dialog.getTreeWidget();
tree->clear(); tree->clear();
tree->setColumnCount(3); tree->setColumnCount(3);
tree->header()->setStretchLastSection(true);
QStringList headers; QStringList headers;
headers << tr("Name") << tr("Created Time") << tr("Modified Time"); headers << tr("Name") << tr("Created Time") << tr("Modified Time");
tree->setHeaderLabels(headers); tree->setHeaderLabels(headers);

View File

@ -177,7 +177,7 @@ QWidget *VMainWindow::setupDirectoryPanel()
notebookSelector->setProperty("NotebookPanel", true); notebookSelector->setProperty("NotebookPanel", true);
notebookSelector->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); notebookSelector->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
directoryTree = new VDirectoryTree(vnote); directoryTree = new VDirectoryTree;
directoryTree->setProperty("NotebookPanel", true); directoryTree->setProperty("NotebookPanel", true);
QVBoxLayout *nbLayout = new QVBoxLayout; QVBoxLayout *nbLayout = new QVBoxLayout;
@ -193,7 +193,11 @@ QWidget *VMainWindow::setupDirectoryPanel()
nbContainer->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); nbContainer->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
connect(notebookSelector, &VNotebookSelector::curNotebookChanged, connect(notebookSelector, &VNotebookSelector::curNotebookChanged,
directoryTree, &VDirectoryTree::setNotebook); this, [this](VNotebook *p_notebook) {
directoryTree->setNotebook(p_notebook);
directoryTree->setFocus();
});
connect(notebookSelector, &VNotebookSelector::curNotebookChanged, connect(notebookSelector, &VNotebookSelector::curNotebookChanged,
this, &VMainWindow::handleCurrentNotebookChanged); this, &VMainWindow::handleCurrentNotebookChanged);
@ -501,6 +505,14 @@ void VMainWindow::initHelpMenu()
editArea->openFile(file, OpenFileMode::Read); editArea->openFile(file, OpenFileMode::Read);
}); });
QAction *wikiAct = new QAction(tr("&Wiki"), this);
wikiAct->setToolTip(tr("View VNote's wiki on Github"));
connect(wikiAct, &QAction::triggered,
this, [this]() {
QString url("https://github.com/tamlok/vnote/wiki");
QDesktopServices::openUrl(url);
});
QAction *updateAct = new QAction(tr("Check For &Updates"), this); QAction *updateAct = new QAction(tr("Check For &Updates"), this);
updateAct->setToolTip(tr("Check for updates of VNote")); updateAct->setToolTip(tr("Check for updates of VNote"));
connect(updateAct, &QAction::triggered, connect(updateAct, &QAction::triggered,
@ -539,6 +551,7 @@ void VMainWindow::initHelpMenu()
helpMenu->addAction(shortcutAct); helpMenu->addAction(shortcutAct);
helpMenu->addAction(mdGuideAct); helpMenu->addAction(mdGuideAct);
helpMenu->addAction(wikiAct);
helpMenu->addAction(updateAct); helpMenu->addAction(updateAct);
helpMenu->addAction(starAct); helpMenu->addAction(starAct);
helpMenu->addAction(feedbackAct); helpMenu->addAction(feedbackAct);

View File

@ -325,3 +325,16 @@ VNoteFile *VNote::getInternalFile(const QString &p_path)
return file; return file;
} }
VDirectory *VNote::getInternalDirectory(const QString &p_path)
{
VDirectory *dir = NULL;
for (auto & nb : m_notebooks) {
dir = nb->tryLoadDirectory(p_path);
if (dir) {
break;
}
}
return dir;
}

View File

@ -88,6 +88,11 @@ public:
// Otherwise, returns NULL. // Otherwise, returns NULL.
VNoteFile *getInternalFile(const QString &p_path); VNoteFile *getInternalFile(const QString &p_path);
// Given the path of a folder, try to find it in all notebooks.
// Returns a VDirectory struct if it is a folder in one notebook.
// Otherwise, returns NULL.
VDirectory *getInternalDirectory(const QString &p_path);
public slots: public slots:
void updateTemplate(); void updateTemplate();

View File

@ -14,8 +14,8 @@ VNotebook::VNotebook(const QString &name, const QString &path, QObject *parent)
m_path = QDir::cleanPath(path); m_path = QDir::cleanPath(path);
m_recycleBinFolder = g_config->getRecycleBinFolder(); m_recycleBinFolder = g_config->getRecycleBinFolder();
m_rootDir = new VDirectory(this, m_rootDir = new VDirectory(this,
VUtils::directoryNameFromPath(path),
NULL, NULL,
VUtils::directoryNameFromPath(path),
QDateTime::currentDateTimeUtc()); QDateTime::currentDateTimeUtc());
} }
@ -202,7 +202,7 @@ bool VNotebook::deleteNotebook(VNotebook *p_notebook, bool p_deleteFiles)
QVector<VDirectory *> subdirs = rootDir->getSubDirs(); QVector<VDirectory *> subdirs = rootDir->getSubDirs();
for (auto dir : subdirs) { for (auto dir : subdirs) {
// Skip recycle bin. // Skip recycle bin.
rootDir->deleteSubDirectory(dir, true); VDirectory::deleteDirectory(dir, true);
} }
// Delete the recycle bin. // Delete the recycle bin.
@ -280,6 +280,37 @@ VNoteFile *VNotebook::tryLoadFile(const QString &p_path)
return NULL; return NULL;
} }
VDirectory *VNotebook::tryLoadDirectory(const QString &p_path)
{
QFileInfo fi(p_path);
Q_ASSERT(fi.isAbsolute());
if (!fi.exists()) {
return NULL;
}
QStringList filePath;
if (VUtils::splitPathInBasePath(m_path, p_path, filePath)) {
if (filePath.isEmpty()) {
return NULL;
}
bool opened = isOpened();
if (!open()) {
return NULL;
}
VDirectory *dir = m_rootDir->tryLoadDirectory(filePath);
if (!dir && !opened) {
close();
}
return dir;
}
return NULL;
}
const QString &VNotebook::getImageFolder() const const QString &VNotebook::getImageFolder() const
{ {
if (m_imageFolder.isEmpty()) { if (m_imageFolder.isEmpty()) {

View File

@ -36,6 +36,13 @@ public:
// if @p_path is not inside this notebook. // if @p_path is not inside this notebook.
VNoteFile *tryLoadFile(const QString &p_path); VNoteFile *tryLoadFile(const QString &p_path);
// Try to load the directory @p_path.
// Returns the corresponding VDirectory struct if @p_path is a folder inside this notebook.
// Otherwise, returns NULL.
// If notebook is not opened currently, it will open itself and close itself
// if @p_path is not inside this notebook.
VDirectory *tryLoadDirectory(const QString &p_path);
const QString &getName() const; const QString &getName() const;
const QString &getPath() const; const QString &getPath() const;
@ -86,9 +93,6 @@ public:
// Need to check if this notebook has been opened. // Need to check if this notebook has been opened.
QDateTime getCreatedTimeUtc(); QDateTime getCreatedTimeUtc();
signals:
void contentChanged();
private: private:
// Serialize current instance to json. // Serialize current instance to json.
QJsonObject toConfigJson() const; QJsonObject toConfigJson() const;