From a64d01ea864b9bce28249a0231ab8fe725b7d177 Mon Sep 17 00:00:00 2001 From: Le Tan Date: Thu, 21 Sep 2017 19:33:37 +0800 Subject: [PATCH] refactor VFile and VOrphanFile 1. Make VFile a real abstract class; 2. Use VNoteFile for internal note file; 3. Use VOrphanFile for external orphan file; --- src/dialog/vfileinfodialog.cpp | 23 ++-- src/dialog/vfileinfodialog.h | 17 +-- src/src.pro | 6 +- src/utils/vutils.cpp | 13 ++ src/utils/vutils.h | 6 + src/vconstants.h | 4 +- src/vdirectory.cpp | 62 ++++----- src/vdirectory.h | 31 ++--- src/vedit.h | 2 +- src/veditwindow.cpp | 11 +- src/veditwindow.h | 10 +- src/vfile.cpp | 225 +++------------------------------ src/vfile.h | 120 +++++++++++------- src/vfilelist.cpp | 44 ++++--- src/vfilelist.h | 36 +++--- src/vmainwindow.cpp | 33 +++-- src/vmdedit.cpp | 12 +- src/vmdeditoperations.cpp | 8 +- src/vnote.cpp | 19 ++- src/vnote.h | 16 ++- src/vnotebook.cpp | 6 +- src/vnotebook.h | 5 +- src/vnotefile.cpp | 187 +++++++++++++++++++++++++++ src/vnotefile.h | 66 ++++++++++ src/vopenedlistmenu.cpp | 40 +++++- src/vorphanfile.cpp | 104 ++------------- src/vorphanfile.h | 71 +++++------ 27 files changed, 625 insertions(+), 552 deletions(-) create mode 100644 src/vnotefile.cpp create mode 100644 src/vnotefile.h diff --git a/src/dialog/vfileinfodialog.cpp b/src/dialog/vfileinfodialog.cpp index 1413a12f..88435242 100644 --- a/src/dialog/vfileinfodialog.cpp +++ b/src/dialog/vfileinfodialog.cpp @@ -1,30 +1,31 @@ #include #include "vfileinfodialog.h" #include "vdirectory.h" -#include "vfile.h" +#include "vnotefile.h" #include "vconfigmanager.h" #include "utils/vutils.h" extern VConfigManager *g_config; -VFileInfoDialog::VFileInfoDialog(const QString &title, const QString &info, - VDirectory *directory, const VFile *file, +VFileInfoDialog::VFileInfoDialog(const QString &title, + const QString &info, + VDirectory *directory, + const VNoteFile *file, QWidget *parent) - : QDialog(parent), title(title), info(info), - m_directory(directory), m_file(file) + : QDialog(parent), m_directory(directory), m_file(file) { - setupUI(); + setupUI(title, info); connect(nameEdit, &QLineEdit::textChanged, this, &VFileInfoDialog::handleInputChanged); handleInputChanged(); } -void VFileInfoDialog::setupUI() +void VFileInfoDialog::setupUI(const QString &p_title, const QString &p_info) { QLabel *infoLabel = NULL; - if (!info.isEmpty()) { - infoLabel = new QLabel(info); + if (!p_info.isEmpty()) { + infoLabel = new QLabel(p_info); } // File name. @@ -78,7 +79,7 @@ void VFileInfoDialog::setupUI() mainLayout->setSizeConstraint(QLayout::SetFixedSize); setLayout(mainLayout); - setWindowTitle(title); + setWindowTitle(p_title); } void VFileInfoDialog::handleInputChanged() @@ -89,7 +90,7 @@ void VFileInfoDialog::handleInputChanged() if (nameOk && name != m_file->getName()) { // Check if the name conflicts with existing note name. // Case-insensitive when creating note. - const VFile *file = m_directory->findFile(name, false); + const VNoteFile *file = m_directory->findFile(name, false); if (file && file != m_file) { nameOk = false; showWarnLabel = true; diff --git a/src/dialog/vfileinfodialog.h b/src/dialog/vfileinfodialog.h index d8ee89be..939cfcdf 100644 --- a/src/dialog/vfileinfodialog.h +++ b/src/dialog/vfileinfodialog.h @@ -8,32 +8,33 @@ class QLineEdit; class QDialogButtonBox; class QString; class VDirectory; -class VFile; +class VNoteFile; +// File information dialog for internal note file. class VFileInfoDialog : public QDialog { Q_OBJECT public: - VFileInfoDialog(const QString &title, const QString &info, - VDirectory *directory, const VFile *file, + VFileInfoDialog(const QString &title, + const QString &info, + VDirectory *directory, + const VNoteFile *file, QWidget *parent = 0); + QString getNameInput() const; private slots: void handleInputChanged(); private: - void setupUI(); + void setupUI(const QString &p_title, const QString &p_info); QLineEdit *nameEdit; QLabel *m_warnLabel; QDialogButtonBox *m_btnBox; - QString title; - QString info; - VDirectory *m_directory; - const VFile *m_file; + const VNoteFile *m_file; }; #endif // VFILEINFODIALOG_H diff --git a/src/src.pro b/src/src.pro index 16578117..6e8279c5 100644 --- a/src/src.pro +++ b/src/src.pro @@ -74,7 +74,8 @@ SOURCES += main.cpp\ dialog/vorphanfileinfodialog.cpp \ vtextblockdata.cpp \ utils/vpreviewutils.cpp \ - dialog/vconfirmdeletiondialog.cpp + dialog/vconfirmdeletiondialog.cpp \ + vnotefile.cpp HEADERS += vmainwindow.h \ vdirectorytree.h \ @@ -136,7 +137,8 @@ HEADERS += vmainwindow.h \ dialog/vorphanfileinfodialog.h \ vtextblockdata.h \ utils/vpreviewutils.h \ - dialog/vconfirmdeletiondialog.h + dialog/vconfirmdeletiondialog.h \ + vnotefile.h RESOURCES += \ vnote.qrc \ diff --git a/src/utils/vutils.cpp b/src/utils/vutils.cpp index 20275ade..5277e76b 100644 --- a/src/utils/vutils.cpp +++ b/src/utils/vutils.cpp @@ -820,6 +820,19 @@ bool VUtils::deleteFile(const VNotebook *p_notebook, } } +bool VUtils::deleteFile(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(); + } +} + 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 d59b2876..a5999d3f 100644 --- a/src/utils/vutils.h +++ b/src/utils/vutils.h @@ -146,6 +146,12 @@ public: const QString &p_path, bool p_skipRecycleBin = false); + // Delete file specified by @p_path. + // Will just move the file to the recycle bin of VNote if + // @p_skipRecycleBin is false. + static bool deleteFile(const QString &p_path, + bool p_skipRecycleBin = false); + // Regular expression for image link. // ![image title]( http://github.com/tamlok/vnote.jpg "alt \" text" ) // Captured texts (need to be trimmed): diff --git a/src/vconstants.h b/src/vconstants.h index 44da5975..c0d60908 100644 --- a/src/vconstants.h +++ b/src/vconstants.h @@ -7,9 +7,9 @@ // Container: a composite file containing multiple files; enum class DocType { Html = 0, Markdown, List, Container, Invalid }; -// Normal: note file managed by VNote; +// Note: note file managed by VNote; // Orphan: external file; -enum class FileType { Normal, Orphan }; +enum class FileType { Note, Orphan }; enum class ClipboardOpType { Invalid, CopyFile, CopyDir }; enum class OpenFileMode {Read = 0, Edit}; diff --git a/src/vdirectory.cpp b/src/vdirectory.cpp index 0f6628ff..f3c64f0a 100644 --- a/src/vdirectory.cpp +++ b/src/vdirectory.cpp @@ -4,7 +4,7 @@ #include #include #include "vconfigmanager.h" -#include "vfile.h" +#include "vnotefile.h" #include "utils/vutils.h" extern VConfigManager *g_config; @@ -53,10 +53,10 @@ bool VDirectory::open() QJsonArray fileJson = configJson[DirConfig::c_files].toArray(); for (int i = 0; i < fileJson.size(); ++i) { QJsonObject fileItem = fileJson[i].toObject(); - VFile *file = VFile::fromJson(fileItem, - this, - FileType::Normal, - true); + VNoteFile *file = VNoteFile::fromJson(this, + fileItem, + FileType::Note, + true); m_files.append(file); } @@ -78,7 +78,7 @@ void VDirectory::close() m_subDirs.clear(); for (int i = 0; i < m_files.size(); ++i) { - VFile *file = m_files[i]; + VNoteFile *file = m_files[i]; file->close(); delete file; } @@ -237,7 +237,7 @@ VDirectory *VDirectory::findSubDirectory(const QString &p_name, bool p_caseSensi return NULL; } -VFile *VDirectory::findFile(const QString &p_name, bool p_caseSensitive) +VNoteFile *VDirectory::findFile(const QString &p_name, bool p_caseSensitive) { if (!open()) { return NULL; @@ -271,7 +271,7 @@ bool VDirectory::containsFile(const VFile *p_file) const return false; } -VFile *VDirectory::createFile(const QString &p_name) +VNoteFile *VDirectory::createFile(const QString &p_name) { Q_ASSERT(!p_name.isEmpty()); if (!open()) { @@ -288,12 +288,12 @@ VFile *VDirectory::createFile(const QString &p_name) file.close(); QDateTime dateTime = QDateTime::currentDateTimeUtc(); - VFile *ret = new VFile(this, - p_name, - FileType::Normal, - true, - dateTime, - dateTime); + VNoteFile *ret = new VNoteFile(this, + p_name, + FileType::Note, + true, + dateTime, + dateTime); m_files.append(ret); if (!writeToConfig()) { file.remove(); @@ -307,7 +307,7 @@ VFile *VDirectory::createFile(const QString &p_name) return ret; } -bool VDirectory::addFile(VFile *p_file, int p_index) +bool VDirectory::addFile(VNoteFile *p_file, int p_index) { if (!open()) { return false; @@ -336,19 +336,19 @@ bool VDirectory::addFile(VFile *p_file, int p_index) return true; } -VFile *VDirectory::addFile(const QString &p_name, int p_index) +VNoteFile *VDirectory::addFile(const QString &p_name, int p_index) { if (!open() || p_name.isEmpty()) { return NULL; } QDateTime dateTime = QDateTime::currentDateTimeUtc(); - VFile *file = new VFile(this, - p_name, - FileType::Normal, - true, - dateTime, - dateTime); + VNoteFile *file = new VNoteFile(this, + p_name, + FileType::Note, + true, + dateTime, + dateTime); if (!file) { return NULL; } @@ -450,7 +450,7 @@ bool VDirectory::removeSubDirectory(VDirectory *p_dir) return true; } -bool VDirectory::removeFile(VFile *p_file) +bool VDirectory::removeFile(VNoteFile *p_file) { V_ASSERT(m_opened); V_ASSERT(p_file); @@ -468,7 +468,7 @@ bool VDirectory::removeFile(VFile *p_file) return true; } -void VDirectory::deleteFile(VFile *p_file) +void VDirectory::deleteFile(VNoteFile *p_file) { removeFile(p_file); @@ -476,7 +476,7 @@ void VDirectory::deleteFile(VFile *p_file) V_ASSERT(!p_file->isOpened()); V_ASSERT(p_file->parent()); - p_file->deleteDiskFile(); + p_file->deleteFile(); delete p_file; } @@ -512,8 +512,8 @@ bool VDirectory::rename(const QString &p_name) return true; } -VFile *VDirectory::copyFile(VDirectory *p_destDir, const QString &p_destName, - VFile *p_srcFile, bool p_cut) +VNoteFile *VDirectory::copyFile(VDirectory *p_destDir, const QString &p_destName, + VNoteFile *p_srcFile, bool p_cut) { QString srcPath = QDir::cleanPath(p_srcFile->fetchPath()); QString destPath = QDir::cleanPath(QDir(p_destDir->fetchPath()).filePath(p_destName)); @@ -536,9 +536,9 @@ VFile *VDirectory::copyFile(VDirectory *p_destDir, const QString &p_destName, return NULL; } - // Handle VDirectory and VFile + // Handle VDirectory and VNoteFile int index = -1; - VFile *destFile = NULL; + VNoteFile *destFile = NULL; if (p_cut) { // Remove the file from config srcDir->removeFile(p_srcFile); @@ -710,7 +710,7 @@ void VDirectory::reorderFiles(int p_first, int p_last, int p_destStart) } } -VFile *VDirectory::tryLoadFile(QStringList &p_filePath) +VNoteFile *VDirectory::tryLoadFile(QStringList &p_filePath) { qDebug() << "directory" << m_name << "tryLoadFile()" << p_filePath.join("/"); if (p_filePath.isEmpty()) { @@ -722,7 +722,7 @@ VFile *VDirectory::tryLoadFile(QStringList &p_filePath) return NULL; } - VFile *file = NULL; + VNoteFile *file = NULL; #if defined(Q_OS_WIN) bool caseSensitive = false; diff --git a/src/vdirectory.h b/src/vdirectory.h index a10fab58..061d379f 100644 --- a/src/vdirectory.h +++ b/src/vdirectory.h @@ -10,6 +10,7 @@ #include "vnotebook.h" class VFile; +class VNoteFile; class VDirectory : public QObject { @@ -27,20 +28,20 @@ public: // Returns the VDirectory with the name @p_name directly in this directory. VDirectory *findSubDirectory(const QString &p_name, bool p_caseSensitive); - // Returns the VFile with the name @p_name directly in this directory. - VFile *findFile(const QString &p_name, bool p_caseSensitive); + // Returns the VNoteFile with the name @p_name directly in this directory. + VNoteFile *findFile(const QString &p_name, bool p_caseSensitive); // If current dir or its sub-dir contains @p_file. bool containsFile(const VFile *p_file) const; - VFile *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. // It won't change the parent of @p_file to enable it find its path. - bool removeFile(VFile *p_file); + bool removeFile(VNoteFile *p_file); // Remove the directory in the config and m_subDirs without deleting it in the disk. // It won't change the parent of @p_dir to enable it find its path. @@ -48,20 +49,20 @@ public: // Add the file in the config and m_files. If @p_index is -1, add it at the end. // @p_name: the file name of the file to add. - // Return the VFile if succeed. - VFile *addFile(const QString &p_name, int p_index); + // Return the VNoteFile if succeed. + VNoteFile *addFile(const QString &p_name, int p_index); // Delete @p_file both from disk and config, as well as its local images. - void deleteFile(VFile *p_file); + void deleteFile(VNoteFile *p_file); // Rename current directory to @p_name. bool rename(const QString &p_name); // Copy @p_srcFile to @p_destDir, setting new name to @p_destName. // @p_cut: copy or cut. - // Returns the dest VFile. - static VFile *copyFile(VDirectory *p_destDir, const QString &p_destName, - VFile *p_srcFile, bool p_cut); + // Returns the dest VNoteFile. + static VNoteFile *copyFile(VDirectory *p_destDir, const QString &p_destName, + VNoteFile *p_srcFile, bool p_cut); static VDirectory *copyDirectory(VDirectory *p_destDir, const QString &p_destName, VDirectory *p_srcDir, bool p_cut); @@ -74,7 +75,7 @@ public: const VDirectory *getParentDirectory() const; VNotebook *getNotebook(); const VNotebook *getNotebook() const; - const QVector &getFiles() const; + const QVector &getFiles() const; QString fetchPath() const; QString fetchBasePath() const; QString fetchRelativePath() const; @@ -97,7 +98,7 @@ public: bool writeToConfig() const; // Try to load file given relative path @p_filePath. - VFile *tryLoadFile(QStringList &p_filePath); + VNoteFile *tryLoadFile(QStringList &p_filePath); QDateTime getCreatedTimeUtc() const; @@ -115,7 +116,7 @@ private: void addNotebookConfig(QJsonObject &p_json) const; // Add the file in the config and m_files. If @p_index is -1, add it at the end. - bool addFile(VFile *p_file, int p_index); + bool addFile(VNoteFile *p_file, int p_index); // Add the directory in the config and m_subDirs. If @p_index is -1, add it at the end. // Return the VDirectory if succeed. @@ -134,7 +135,7 @@ private: QVector m_subDirs; // Owner of the files - QVector m_files; + QVector m_files; // Whether the directory has been opened. bool m_opened; @@ -177,7 +178,7 @@ inline const VDirectory *VDirectory::getParentDirectory() const return (const VDirectory *)this->parent(); } -inline const QVector &VDirectory::getFiles() const +inline const QVector &VDirectory::getFiles() const { return m_files; } diff --git a/src/vedit.h b/src/vedit.h index 64174e51..7c8b4cce 100644 --- a/src/vedit.h +++ b/src/vedit.h @@ -11,7 +11,7 @@ #include #include "vconstants.h" #include "vtoc.h" -#include "vfile.h" +#include "vnotefile.h" class VEditOperations; class QLabel; diff --git a/src/veditwindow.cpp b/src/veditwindow.cpp index 6f500d89..aad29f53 100644 --- a/src/veditwindow.cpp +++ b/src/veditwindow.cpp @@ -125,8 +125,9 @@ void VEditWindow::initTabActions() VEditTab *editor = getTab(tab); QPointer file = editor->getFile(); Q_ASSERT(file); - if (file->getType() == FileType::Normal) { - g_vnote->getMainWindow()->getFileList()->fileInfo(file); + if (file->getType() == FileType::Note) { + VNoteFile *tmpFile = dynamic_cast((VFile *)file); + g_vnote->getMainWindow()->getFileList()->fileInfo(tmpFile); } else if (file->getType() == FileType::Orphan) { g_vnote->getMainWindow()->editOrphanFileInfo(file); } @@ -554,7 +555,7 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos) VEditTab *editor = getTab(tab); VFile *file = editor->getFile(); - if (file->getType() == FileType::Normal) { + if (file->getType() == FileType::Note) { // Locate to folder. m_locateAct->setData(tab); menu.addAction(m_locateAct); @@ -565,7 +566,7 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos) m_noteInfoAct->setData(tab); menu.addAction(m_noteInfoAct); } else if (file->getType() == FileType::Orphan - && !dynamic_cast(file)->isSystemFile()) { + && !(dynamic_cast(file)->isSystemFile())) { m_openLocationAct->setData(tab); menu.addAction(m_openLocationAct); @@ -761,7 +762,7 @@ void VEditWindow::handleLocateAct() int tab = m_locateAct->data().toInt(); VEditTab *editor = getTab(tab); QPointer file = editor->getFile(); - if (file->getType() == FileType::Normal) { + if (file->getType() == FileType::Note) { vnote->getMainWindow()->locateFile(file); } } diff --git a/src/veditwindow.h b/src/veditwindow.h index 99f39a2a..83a56ee6 100644 --- a/src/veditwindow.h +++ b/src/veditwindow.h @@ -10,11 +10,11 @@ #include "vedittab.h" #include "vtoc.h" #include "vconstants.h" +#include "vnotefile.h" class VNote; class QPushButton; class QActionGroup; -class VFile; class VEditArea; class VEditWindow : public QTabWidget @@ -184,8 +184,14 @@ inline QString VEditWindow::generateTooltip(const VFile *p_file) const if (!p_file) { return ""; } + // [Notebook]path - return QString("[%1] %2").arg(p_file->getNotebookName()).arg(p_file->fetchPath()); + if (p_file->getType() == FileType::Note) { + const VNoteFile *tmpFile = dynamic_cast(p_file); + return QString("[%1] %2").arg(tmpFile->getNotebookName()).arg(tmpFile->fetchPath()); + } else { + return QString("%1").arg(p_file->fetchPath()); + } } inline QString VEditWindow::generateTabText(int p_index, const QString &p_name, diff --git a/src/vfile.cpp b/src/vfile.cpp index e3aacb80..81e68629 100644 --- a/src/vfile.cpp +++ b/src/vfile.cpp @@ -30,17 +30,18 @@ VFile::~VFile() bool VFile::open() { - Q_ASSERT(!m_name.isEmpty()); if (m_opened) { return true; } + + Q_ASSERT(!m_name.isEmpty()); Q_ASSERT(m_content.isEmpty()); - QString path = fetchPath(); - qDebug() << "path" << path; - m_content = VUtils::readFileFromDisk(path); + + QString filePath = fetchPath(); + Q_ASSERT(QFileInfo::exists(filePath)); + m_content = VUtils::readFileFromDisk(filePath); m_modified = false; m_opened = true; - qDebug() << "file" << m_name << "opened"; return true; } @@ -49,164 +50,24 @@ void VFile::close() if (!m_opened) { return; } + m_content.clear(); + m_modified = false; m_opened = false; } -void VFile::deleteDiskFile() -{ - V_ASSERT(parent()); - - // Delete local images if it is Markdown. - if (m_docType == DocType::Markdown) { - deleteLocalImages(); - } - - // Delete the file - QString filePath = fetchPath(); - if (VUtils::deleteFile(getNotebook(), filePath, false)) { - qDebug() << "deleted" << filePath; - } else { - qWarning() << "fail to delete" << filePath; - } -} - bool VFile::save() { Q_ASSERT(m_opened); bool ret = VUtils::writeFileToDisk(fetchPath(), m_content); if (ret) { m_modifiedTimeUtc = QDateTime::currentDateTimeUtc(); + m_modified = false; } return ret; } -void VFile::setModified(bool p_modified) -{ - m_modified = p_modified; -} - -void VFile::deleteLocalImages() -{ - V_ASSERT(m_docType == DocType::Markdown); - - QVector images = VUtils::fetchImagesFromMarkdownFile(this, - ImageLink::LocalRelativeInternal); - int deleted = 0; - for (int i = 0; i < images.size(); ++i) { - if (VUtils::deleteFile(getNotebook(), images[i].m_path, false)) { - ++deleted; - } - } - - qDebug() << "delete" << deleted << "images for" << fetchPath(); -} - -void VFile::setName(const QString &p_name) -{ - m_name = p_name; - DocType newType = VUtils::docTypeFromName(p_name); - if (newType != m_docType) { - qWarning() << "setName() change the DocType. A convertion should be followed"; - } -} - -const QString &VFile::getName() const -{ - return m_name; -} - -VDirectory *VFile::getDirectory() -{ - Q_ASSERT(parent()); - return (VDirectory *)parent(); -} - -const VDirectory *VFile::getDirectory() const -{ - Q_ASSERT(parent()); - return (const VDirectory *)parent(); -} - -DocType VFile::getDocType() const -{ - return m_docType; -} - -const QString &VFile::getContent() const -{ - return m_content; -} - -QString VFile::getNotebookName() const -{ - return getDirectory()->getNotebookName(); -} - -const VNotebook *VFile::getNotebook() const -{ - return getDirectory()->getNotebook(); -} - -VNotebook *VFile::getNotebook() -{ - return getDirectory()->getNotebook(); -} - -QString VFile::fetchPath() const -{ - QString dirPath = getDirectory()->fetchPath(); - return QDir(dirPath).filePath(m_name); -} - -QString VFile::fetchRelativePath() const -{ - QString dirRelativePath = getDirectory()->fetchRelativePath(); - return QDir(dirRelativePath).filePath(m_name); -} - -QString VFile::fetchBasePath() const -{ - return getDirectory()->fetchPath(); -} - -QString VFile::fetchImagePath() const -{ - return QDir(fetchBasePath()).filePath(getNotebook()->getImageFolder()); -} - -void VFile::setContent(const QString &p_content) -{ - m_content = p_content; -} - -bool VFile::isModified() const -{ - return m_modified; -} - -bool VFile::isModifiable() const -{ - return m_modifiable; -} - -bool VFile::isOpened() const -{ - return m_opened; -} - -FileType VFile::getType() const -{ - return m_type; -} - -bool VFile::isInternalImageFolder(const QString &p_path) const -{ - return VUtils::equalPath(VUtils::basePathFromPath(p_path), - getDirectory()->fetchPath()); -} - QUrl VFile::getBaseUrl() const { // Need to judge the path: Url, local file, resource file. @@ -229,71 +90,15 @@ QUrl VFile::getBaseUrl() const return baseUrl; } -bool VFile::rename(const QString &p_name) +bool VFile::isInternalImageFolder(const QString &p_path) const { - if (m_name == p_name) { - return true; - } - - QString oldName = m_name; - - VDirectory *dir = getDirectory(); - V_ASSERT(dir); - // Rename it in disk. - QDir diskDir(dir->fetchPath()); - if (!diskDir.rename(m_name, p_name)) { - qWarning() << "fail to rename note" << m_name << "to" << p_name << "in disk"; - return false; - } - - m_name = p_name; - - // Update parent directory's config file. - if (!dir->writeToConfig()) { - m_name = oldName; - diskDir.rename(p_name, m_name); - return false; - } - - // Can't not change doc type. - Q_ASSERT(m_docType == VUtils::docTypeFromName(m_name)); - - qDebug() << "note renamed from" << oldName << "to" << m_name; - - return true; + return VUtils::equalPath(VUtils::basePathFromPath(p_path), + fetchBasePath()) + || VUtils::equalPath(p_path, fetchImageFolderPath()); } -bool VFile::isRelativeImageFolder() const +void VFile::setModified(bool p_modified) { - return true; + m_modified = p_modified; } -QString VFile::getImageFolderInLink() const -{ - return getNotebook()->getImageFolder(); -} - -VFile *VFile::fromJson(const QJsonObject &p_json, - QObject *p_parent, - FileType p_type, - bool p_modifiable) -{ - return new VFile(p_parent, - p_json[DirConfig::c_name].toString(), - p_type, - p_modifiable, - QDateTime::fromString(p_json[DirConfig::c_createdTime].toString(), - Qt::ISODate), - QDateTime::fromString(p_json[DirConfig::c_modifiedTime].toString(), - Qt::ISODate)); -} - -QJsonObject VFile::toConfigJson() const -{ - QJsonObject item; - item[DirConfig::c_name] = m_name; - item[DirConfig::c_createdTime] = m_createdTimeUtc.toString(Qt::ISODate); - item[DirConfig::c_modifiedTime] = m_modifiedTimeUtc.toString(Qt::ISODate); - - return item; -} diff --git a/src/vfile.h b/src/vfile.h index bbef1bde..6c3ca101 100644 --- a/src/vfile.h +++ b/src/vfile.h @@ -5,11 +5,9 @@ #include #include #include -#include "vdirectory.h" #include "vconstants.h" -class VNotebook; - +// VFile is an abstract class representing a file in VNote. class VFile : public QObject { Q_OBJECT @@ -22,57 +20,56 @@ public: QDateTime p_modifiedTimeUtc); virtual ~VFile(); + + // Open the file to load content into m_content. + // Init m_opened, m_modified, and m_content. virtual bool open(); + + // Close the file. + // Clear m_modified, m_content, m_opened. virtual void close(); + + // Save m_content to the file. virtual bool save(); const QString &getName() const; - virtual void setName(const QString &p_name); - virtual VDirectory *getDirectory(); - virtual const VDirectory *getDirectory() const; - DocType getDocType() const; - const QString &getContent() const; - virtual void setContent(const QString &p_content); - virtual const VNotebook *getNotebook() const; - virtual VNotebook *getNotebook(); - virtual QString getNotebookName() const; - virtual QString fetchPath() const; - virtual QString fetchRelativePath() const; - virtual QString fetchBasePath() const; - // The path of the image folder. - virtual QString fetchImagePath() const; + DocType getDocType() const; bool isModified() const; + bool isModifiable() const; + bool isOpened() const; + FileType getType() const; + const QString &getContent() const; + + void setContent(const QString &p_content); + + // Get the absolute full path of the file. + virtual QString fetchPath() const = 0; + + // Get the absolute full path of the directory containing the file. + virtual QString fetchBasePath() const = 0; + + // The path of the image folder to store images of this file. + virtual QString fetchImageFolderPath() const = 0; + // Return the base URL for this file when loaded in VWebView. QUrl getBaseUrl() const; // Whether the directory @p_path is an internal image folder of this file. // It is true only when the folder is in the same directory as the parent - // directory of this file. - virtual bool isInternalImageFolder(const QString &p_path) const; + // directory of this file or equals to fetchImageFolderPath(). + bool isInternalImageFolder(const QString &p_path) const; - // Rename the file. - virtual bool rename(const QString &p_name); - - // Whether the image folder is a relative path. - virtual bool isRelativeImageFolder() const; + // Whether use a relative image folder. + virtual bool useRelativeImageFolder() const = 0; // Return the image folder part in an image link. - virtual QString getImageFolderInLink() const; - - // Create a VFile from @p_json Json object. - static VFile *fromJson(const QJsonObject &p_json, - QObject *p_parent, - FileType p_type, - bool p_modifiable); - - // Create a Json object from current instance. - QJsonObject toConfigJson() const; + virtual QString getImageFolderInLink() const = 0; QDateTime getCreatedTimeUtc() const; @@ -82,19 +79,13 @@ public slots: void setModified(bool p_modified); protected: - // Delete the file and corresponding images - void deleteDiskFile(); - - // Delete local images of DocType::Markdown. - void deleteLocalImages(); - // Name of this file. QString m_name; - // Whether this file has been opened. + // Whether this file has been opened (content loaded). bool m_opened; - // File has been modified in editor + // m_content is different from that in the disk. bool m_modified; // DocType of this file: Html, Markdown. @@ -103,6 +94,7 @@ protected: // Content of this file. QString m_content; + // FileType of this file: Note, Orphan. FileType m_type; // Whether this file is modifiable. @@ -113,10 +105,50 @@ protected: // UTC time of last modification to this file in VNote. QDateTime m_modifiedTimeUtc; - - friend class VDirectory; }; +inline const QString &VFile::getName() const +{ + return m_name; +} + +inline DocType VFile::getDocType() const +{ + return m_docType; +} + +inline bool VFile::isModified() const +{ + return m_modified; +} + +inline bool VFile::isModifiable() const +{ + return m_modifiable; +} + +inline bool VFile::isOpened() const +{ + return m_opened; +} + +inline FileType VFile::getType() const +{ + return m_type; +} + +inline const QString &VFile::getContent() const +{ + Q_ASSERT(m_opened); + return m_content; +} + +inline void VFile::setContent(const QString &p_content) +{ + m_content = p_content; + m_modified = true; +} + inline QDateTime VFile::getCreatedTimeUtc() const { return m_createdTimeUtc; diff --git a/src/vfilelist.cpp b/src/vfilelist.cpp index 03806f8c..9fe95ded 100644 --- a/src/vfilelist.cpp +++ b/src/vfilelist.cpp @@ -8,7 +8,7 @@ #include "vnote.h" #include "veditarea.h" #include "utils/vutils.h" -#include "vfile.h" +#include "vnotefile.h" #include "vconfigmanager.h" #include "vmdedit.h" #include "vmdtab.h" @@ -182,9 +182,10 @@ void VFileList::updateFileList() if (!m_directory->open()) { return; } - const QVector &files = m_directory->getFiles(); + + const QVector &files = m_directory->getFiles(); for (int i = 0; i < files.size(); ++i) { - VFile *file = files[i]; + VNoteFile *file = files[i]; insertFileListItem(file); } } @@ -205,7 +206,7 @@ void VFileList::openFileLocation() const QDesktopServices::openUrl(url); } -void VFileList::fileInfo(VFile *p_file) +void VFileList::fileInfo(VNoteFile *p_file) { if (!p_file) { return; @@ -239,7 +240,7 @@ void VFileList::fileInfo(VFile *p_file) } } -void VFileList::fillItem(QListWidgetItem *p_item, const VFile *p_file) +void VFileList::fillItem(QListWidgetItem *p_item, const VNoteFile *p_file) { unsigned long long ptr = (long long)p_file; p_item->setData(Qt::UserRole, ptr); @@ -249,7 +250,7 @@ void VFileList::fillItem(QListWidgetItem *p_item, const VFile *p_file) V_ASSERT(sizeof(p_file) <= sizeof(ptr)); } -QListWidgetItem* VFileList::insertFileListItem(VFile *file, bool atFront) +QListWidgetItem* VFileList::insertFileListItem(VNoteFile *file, bool atFront) { V_ASSERT(file); QListWidgetItem *item = new QListWidgetItem(); @@ -300,7 +301,7 @@ void VFileList::newFile() defaultName = VUtils::getFileNameWithSequence(m_directory->fetchPath(), defaultName); VNewFileDialog dialog(tr("Create Note"), info, defaultName, m_directory, this); if (dialog.exec() == QDialog::Accepted) { - VFile *file = m_directory->createFile(dialog.getNameInput()); + VNoteFile *file = m_directory->createFile(dialog.getNameInput()); if (!file) { VUtils::showMessage(QMessageBox::Warning, tr("Warning"), tr("Fail to create note %2.") @@ -355,14 +356,14 @@ void VFileList::newFile() QVector VFileList::updateFileListAdded() { QVector ret; - const QVector &files = m_directory->getFiles(); + const QVector &files = m_directory->getFiles(); for (int i = 0; i < files.size(); ++i) { - VFile *file = files[i]; + VNoteFile *file = files[i]; if (i >= fileList->count()) { QListWidgetItem *item = insertFileListItem(file, false); ret.append(item); } else { - VFile *itemFile = getVFile(fileList->item(i)); + VNoteFile *itemFile = getVFile(fileList->item(i)); if (itemFile != file) { QListWidgetItem *item = insertFileListItem(file, false); ret.append(item); @@ -384,11 +385,12 @@ void VFileList::deleteFile() } // @p_file may or may not be listed in VFileList -void VFileList::deleteFile(VFile *p_file) +void VFileList::deleteFile(VNoteFile *p_file) { if (!p_file) { return; } + VDirectory *dir = p_file->getDirectory(); QString fileName = p_file->getName(); int ret = VUtils::showMessage(QMessageBox::Warning, tr("Warning"), @@ -427,7 +429,7 @@ void VFileList::contextMenuRequested(QPoint pos) } if (item && fileList->selectedItems().size() == 1) { - VFile *file = getVFile(item); + VNoteFile *file = getVFile(item); if (file && file->getDocType() == DocType::Markdown) { menu.addAction(m_openInReadAct); menu.addAction(m_openInEditAct); @@ -464,7 +466,7 @@ void VFileList::contextMenuRequested(QPoint pos) menu.exec(fileList->mapToGlobal(pos)); } -QListWidgetItem* VFileList::findItem(const VFile *p_file) +QListWidgetItem* VFileList::findItem(const VNoteFile *p_file) { if (!p_file || p_file->getDirectory() != m_directory) { return NULL; @@ -477,6 +479,7 @@ QListWidgetItem* VFileList::findItem(const VFile *p_file) return item; } } + return NULL; } @@ -515,7 +518,7 @@ bool VFileList::importFile(const QString &p_srcFilePath) return false; } - VFile *destFile = m_directory->addFile(srcName, -1); + VNoteFile *destFile = m_directory->addFile(srcName, -1); if (destFile) { return insertFileListItem(destFile, false); } @@ -531,7 +534,7 @@ void VFileList::copySelectedFiles(bool p_isCut) QJsonArray files; m_copiedFiles.clear(); for (int i = 0; i < items.size(); ++i) { - VFile *file = getVFile(items[i]); + VNoteFile *file = getVFile(items[i]); QJsonObject fileJson; fileJson["notebook"] = file->getNotebookName(); fileJson["path"] = file->fetchPath(); @@ -579,10 +582,11 @@ void VFileList::pasteFiles(VDirectory *p_destDir) int nrPasted = 0; for (int i = 0; i < m_copiedFiles.size(); ++i) { - QPointer srcFile = m_copiedFiles[i]; + QPointer srcFile = m_copiedFiles[i]; if (!srcFile) { continue; } + QString fileName = srcFile->getName(); VDirectory *srcDir = srcFile->getDirectory(); if (srcDir == p_destDir && !isCut) { @@ -606,7 +610,7 @@ void VFileList::pasteFiles(VDirectory *p_destDir) m_copiedFiles.clear(); } -bool VFileList::copyFile(VDirectory *p_destDir, const QString &p_destName, VFile *p_file, bool p_cut) +bool VFileList::copyFile(VDirectory *p_destDir, const QString &p_destName, VNoteFile *p_file, bool p_cut) { QString srcPath = QDir::cleanPath(p_file->fetchPath()); QString destPath = QDir::cleanPath(QDir(p_destDir->fetchPath()).filePath(p_destName)); @@ -617,7 +621,7 @@ bool VFileList::copyFile(VDirectory *p_destDir, const QString &p_destName, VFile // DocType is not allowed to change. Q_ASSERT(p_file->getDocType() == VUtils::docTypeFromName(destPath)); - VFile *destFile = VDirectory::copyFile(p_destDir, p_destName, p_file, p_cut); + VNoteFile *destFile = VDirectory::copyFile(p_destDir, p_destName, p_file, p_cut); updateFileList(); if (destFile) { emit fileUpdated(destFile); @@ -676,7 +680,7 @@ void VFileList::focusInEvent(QFocusEvent * /* p_event */) fileList->setFocus(); } -bool VFileList::locateFile(const VFile *p_file) +bool VFileList::locateFile(const VNoteFile *p_file) { if (p_file) { if (p_file->getDirectory() != m_directory) { @@ -704,7 +708,7 @@ void VFileList::handleRowsMoved(const QModelIndex &p_parent, int p_start, int p_ bool VFileList::identicalListWithDirectory() const { - const QVector files = m_directory->getFiles(); + const QVector files = m_directory->getFiles(); int nrItems = fileList->count(); if (nrItems != files.size()) { return false; diff --git a/src/vfilelist.h b/src/vfilelist.h index 0736951b..d73202db 100644 --- a/src/vfilelist.h +++ b/src/vfilelist.h @@ -11,7 +11,7 @@ #include "vnotebook.h" #include "vconstants.h" #include "vdirectory.h" -#include "vfile.h" +#include "vnotefile.h" #include "vnavigationmode.h" class QAction; @@ -29,9 +29,9 @@ public: explicit VFileList(QWidget *parent = 0); bool importFile(const QString &p_srcFilePath); inline void setEditArea(VEditArea *editArea); - void fileInfo(VFile *p_file); - void deleteFile(VFile *p_file); - bool locateFile(const VFile *p_file); + void fileInfo(VNoteFile *p_file); + void deleteFile(VNoteFile *p_file); + bool locateFile(const VNoteFile *p_file); inline const VDirectory *currentDirectory() const; // Implementations for VNavigationMode. @@ -41,16 +41,16 @@ public: bool handleKeyNavigation(int p_key, bool &p_succeed) Q_DECL_OVERRIDE; signals: - void fileClicked(VFile *p_file, OpenFileMode mode = OpenFileMode::Read); - void fileCreated(VFile *p_file, OpenFileMode mode = OpenFileMode::Read); - void fileUpdated(const VFile *p_file); + void fileClicked(VNoteFile *p_file, OpenFileMode mode = OpenFileMode::Read); + void fileCreated(VNoteFile *p_file, OpenFileMode mode = OpenFileMode::Read); + void fileUpdated(const VNoteFile *p_file); private slots: void contextMenuRequested(QPoint pos); void handleItemClicked(QListWidgetItem *currentItem); void fileInfo(); void openFileLocation() const; - // m_copiedFiles will keep the files's VFile. + // m_copiedFiles will keep the files's VNoteFile. void copySelectedFiles(bool p_isCut = false); void cutSelectedFiles(); void pasteFilesInCurDir(); @@ -72,32 +72,36 @@ private: void initShortcuts(); void updateFileList(); - QListWidgetItem *insertFileListItem(VFile *file, bool atFront = false); + + QListWidgetItem *insertFileListItem(VNoteFile *file, bool atFront = false); + void removeFileListItem(QListWidgetItem *item); // Init actions. void initActions(); // Return the corresponding QListWidgetItem of @p_file. - QListWidgetItem *findItem(const VFile *p_file); + QListWidgetItem *findItem(const VNoteFile *p_file); void copyFileInfoToClipboard(const QJsonArray &p_files, bool p_isCut); void pasteFiles(VDirectory *p_destDir); - bool copyFile(VDirectory *p_destDir, const QString &p_destName, VFile *p_file, bool p_cut); + bool copyFile(VDirectory *p_destDir, const QString &p_destName, VNoteFile *p_file, bool p_cut); // New items have been added to direcotry. Update file list accordingly. QVector updateFileListAdded(); - inline QPointer getVFile(QListWidgetItem *p_item) const; + + inline QPointer getVFile(QListWidgetItem *p_item) const; + // Check if the list items match exactly the contents of the directory. bool identicalListWithDirectory() const; QList getVisibleItems() const; // Fill the info of @p_item according to @p_file. - void fillItem(QListWidgetItem *p_item, const VFile *p_file); + void fillItem(QListWidgetItem *p_item, const VNoteFile *p_file); VEditArea *editArea; QListWidget *fileList; QPointer m_directory; - QVector > m_copiedFiles; + QVector > m_copiedFiles; // Actions QAction *m_openInReadAct; @@ -126,10 +130,10 @@ inline void VFileList::setEditArea(VEditArea *editArea) this->editArea = editArea; } -inline QPointer VFileList::getVFile(QListWidgetItem *p_item) const +inline QPointer VFileList::getVFile(QListWidgetItem *p_item) const { Q_ASSERT(p_item); - return (VFile *)p_item->data(Qt::UserRole).toULongLong(); + return (VNoteFile *)p_item->data(Qt::UserRole).toULongLong(); } inline const VDirectory *VFileList::currentDirectory() const diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index 319d63d6..b527768a 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -26,6 +26,7 @@ #include "vorphanfile.h" #include "dialog/vorphanfileinfodialog.h" #include "vsingleinstanceguard.h" +#include "vnotefile.h" extern VConfigManager *g_config; @@ -464,7 +465,6 @@ void VMainWindow::initHelpMenu() } VFile *file = vnote->getOrphanFile(docName, false, true); - (dynamic_cast(file))->setNotebookName(tr("[Help]")); editArea->openFile(file, OpenFileMode::Read); }); @@ -1508,7 +1508,7 @@ void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file, editNoteAct->setEnabled(p_file && p_file->isModifiable() && !p_editMode); editNoteAct->setVisible(!saveExitAct->isVisible()); saveNoteAct->setEnabled(p_file && p_editMode); - deleteNoteAct->setEnabled(p_file && p_file->getType() == FileType::Normal); + deleteNoteAct->setEnabled(p_file && p_file->getType() == FileType::Note); noteInfoAct->setEnabled(p_file && !systemFile); m_insertImageAct->setEnabled(p_file && p_editMode); @@ -1545,7 +1545,13 @@ void VMainWindow::handleAreaTabStatusUpdated(const VEditTabInfo &p_info) if (m_curFile) { m_findReplaceDialog->updateState(m_curFile->getDocType(), editMode); - title = QString("[%1] %2").arg(m_curFile->getNotebookName()).arg(m_curFile->fetchPath()); + if (m_curFile->getType() == FileType::Note) { + const VNoteFile *tmpFile = dynamic_cast((VFile *)m_curFile); + title = QString("[%1] %2").arg(tmpFile->getNotebookName()).arg(tmpFile->fetchPath()); + } else { + title = QString("%1").arg(m_curFile->fetchPath()); + } + if (m_curFile->isModifiable()) { if (m_curFile->isModified()) { title.append('*'); @@ -1636,8 +1642,10 @@ void VMainWindow::curEditFileInfo() { Q_ASSERT(m_curFile); - if (m_curFile->getType() == FileType::Normal) { - fileList->fileInfo(m_curFile); + if (m_curFile->getType() == FileType::Note) { + VNoteFile *file = dynamic_cast((VFile *)m_curFile); + Q_ASSERT(file); + fileList->fileInfo(file); } else if (m_curFile->getType() == FileType::Orphan) { VOrphanFile *file = dynamic_cast((VFile *)m_curFile); Q_ASSERT(file); @@ -1649,11 +1657,12 @@ void VMainWindow::curEditFileInfo() void VMainWindow::deleteCurNote() { - if (!m_curFile || m_curFile->getType() != FileType::Normal) { + if (!m_curFile || m_curFile->getType() != FileType::Note) { return; } - fileList->deleteFile(m_curFile); + VNoteFile *file = dynamic_cast((VFile *)m_curFile); + fileList->deleteFile(file); } void VMainWindow::closeEvent(QCloseEvent *event) @@ -1793,23 +1802,24 @@ void VMainWindow::insertImage() bool VMainWindow::locateFile(VFile *p_file) { bool ret = false; - if (!p_file || p_file->getType() != FileType::Normal) { + if (!p_file || p_file->getType() != FileType::Note) { return ret; } - VNotebook *notebook = p_file->getNotebook(); + VNoteFile *file = dynamic_cast(p_file); + VNotebook *notebook = file->getNotebook(); if (notebookSelector->locateNotebook(notebook)) { while (directoryTree->currentNotebook() != notebook) { QCoreApplication::sendPostedEvents(); } - VDirectory *dir = p_file->getDirectory(); + VDirectory *dir = file->getDirectory(); if (directoryTree->locateDirectory(dir)) { while (fileList->currentDirectory() != dir) { QCoreApplication::sendPostedEvents(); } - if (fileList->locateFile(p_file)) { + if (fileList->locateFile(file)) { ret = true; fileList->setFocus(); } @@ -1933,7 +1943,6 @@ void VMainWindow::shortcutHelp() } VFile *file = vnote->getOrphanFile(docName, false, true); - (dynamic_cast(file))->setNotebookName(tr("[Help]")); editArea->openFile(file, OpenFileMode::Read); } diff --git a/src/vmdedit.cpp b/src/vmdedit.cpp index 1f358008..4f0c8ed2 100644 --- a/src/vmdedit.cpp +++ b/src/vmdedit.cpp @@ -219,7 +219,7 @@ void VMdEdit::imageInserted(const QString &p_path) { ImageLink link; link.m_path = p_path; - if (m_file->isRelativeImageFolder()) { + if (m_file->useRelativeImageFolder()) { link.m_type = ImageLink::LocalRelativeInternal; } else { link.m_type = ImageLink::LocalAbsolute; @@ -300,7 +300,15 @@ void VMdEdit::clearUnusedImages() } for (int i = 0; i < unusedImages.size(); ++i) { - if (!VUtils::deleteFile(m_file->getNotebook(), unusedImages[i], false)) { + bool ret = false; + if (m_file->getType() == FileType::Note) { + const VNoteFile *tmpFile = dynamic_cast((VFile *)m_file); + ret = VUtils::deleteFile(tmpFile->getNotebook(), unusedImages[i], false); + } else { + ret = VUtils::deleteFile(unusedImages[i], false); + } + + if (!ret) { qWarning() << "fail to delete unused original image" << unusedImages[i]; } else { qDebug() << "delete unused image" << unusedImages[i]; diff --git a/src/vmdeditoperations.cpp b/src/vmdeditoperations.cpp index d2c641b3..f03dfa59 100644 --- a/src/vmdeditoperations.cpp +++ b/src/vmdeditoperations.cpp @@ -45,7 +45,7 @@ bool VMdEditOperations::insertImageFromMimeData(const QMimeData *source) dialog.setImage(image); if (dialog.exec() == QDialog::Accepted) { insertImageFromQImage(dialog.getImageTitleInput(), - m_file->fetchImagePath(), + m_file->fetchImageFolderPath(), m_file->getImageFolderInLink(), image); } @@ -170,12 +170,12 @@ bool VMdEditOperations::insertImageFromURL(const QUrl &imageUrl) if (dialog.exec() == QDialog::Accepted) { if (isLocal) { insertImageFromPath(dialog.getImageTitleInput(), - m_file->fetchImagePath(), + m_file->fetchImageFolderPath(), m_file->getImageFolderInLink(), imagePath); } else { insertImageFromQImage(dialog.getImageTitleInput(), - m_file->fetchImagePath(), + m_file->fetchImageFolderPath(), m_file->getImageFolderInLink(), dialog.getImage()); } @@ -192,7 +192,7 @@ bool VMdEditOperations::insertImage() QString imagePath = dialog.getPathInput(); qDebug() << "insert image from" << imagePath << "as" << title; insertImageFromPath(title, - m_file->fetchImagePath(), + m_file->fetchImageFolderPath(), m_file->getImageFolderInLink(), imagePath); } diff --git a/src/vnote.cpp b/src/vnote.cpp index 6806aa0b..b74880eb 100644 --- a/src/vnote.cpp +++ b/src/vnote.cpp @@ -12,6 +12,7 @@ #include "vconfigmanager.h" #include "vmainwindow.h" #include "vorphanfile.h" +#include "vnotefile.h" extern VConfigManager *g_config; @@ -281,7 +282,7 @@ const QString &VNote::getMonospacedFont() const return font; } -VFile *VNote::getOrphanFile(const QString &p_path, bool p_modifiable, bool p_systemFile) +VOrphanFile *VNote::getOrphanFile(const QString &p_path, bool p_modifiable, bool p_systemFile) { if (p_path.isEmpty()) { return NULL; @@ -290,17 +291,15 @@ VFile *VNote::getOrphanFile(const QString &p_path, bool p_modifiable, bool p_sys QString path = QDir::cleanPath(p_path); // See if the file has already been opened before. for (auto const &file : m_externalFiles) { - Q_ASSERT(file->getType() == FileType::Orphan); - VOrphanFile *oFile = dynamic_cast(file); - if (VUtils::equalPath(QDir::cleanPath(oFile->fetchPath()), path)) { - Q_ASSERT(oFile->isModifiable() == p_modifiable); - Q_ASSERT(oFile->isSystemFile() == p_systemFile); + if (VUtils::equalPath(QDir::cleanPath(file->fetchPath()), path)) { + Q_ASSERT(file->isModifiable() == p_modifiable); + Q_ASSERT(file->isSystemFile() == p_systemFile); return file; } } for (int i = 0; i < m_externalFiles.size(); ++i) { - VFile *file = m_externalFiles[i]; + VOrphanFile *file = m_externalFiles[i]; if (!file->isOpened()) { qDebug() << "release orphan file" << file; m_externalFiles.removeAt(i); @@ -310,14 +309,14 @@ VFile *VNote::getOrphanFile(const QString &p_path, bool p_modifiable, bool p_sys } // Create a VOrphanFile for path. - VOrphanFile *file = new VOrphanFile(path, this, p_modifiable, p_systemFile); + VOrphanFile *file = new VOrphanFile(this, path, p_modifiable, p_systemFile); m_externalFiles.append(file); return file; } -VFile *VNote::getInternalFile(const QString &p_path) +VNoteFile *VNote::getInternalFile(const QString &p_path) { - VFile *file = NULL; + VNoteFile *file = NULL; for (auto & nb : m_notebooks) { file = nb->tryLoadFile(p_path); if (file) { diff --git a/src/vnote.h b/src/vnote.h index 5ef0f36b..1ef882d9 100644 --- a/src/vnote.h +++ b/src/vnote.h @@ -14,7 +14,8 @@ #include "vconstants.h" class VMainWindow; -class VFile; +class VOrphanFile; +class VNoteFile; class VNote : public QObject { @@ -80,14 +81,15 @@ public: QString getNavigationLabelStyle(const QString &p_str) const; - // Given the path of an external file, create a VFile struct. - VFile *getOrphanFile(const QString &p_path, bool p_modifiable, - bool p_systemFile = false); + // Given the path of an external file, create a VOrphanFile struct. + VOrphanFile *getOrphanFile(const QString &p_path, + bool p_modifiable, + bool p_systemFile = false); // Given the path of a file, try to find it in all notebooks. - // Returns a VFile struct if it is a note in one notebook. + // Returns a VNoteFile struct if it is a note in one notebook. // Otherwise, returns NULL. - VFile *getInternalFile(const QString &p_path); + VNoteFile *getInternalFile(const QString &p_path); public slots: void updateTemplate(); @@ -102,7 +104,7 @@ private: // Hold all external file: Orphan File. // Need to clean up periodly. - QList m_externalFiles; + QList m_externalFiles; }; inline const QVector >& VNote::getPalette() const diff --git a/src/vnotebook.cpp b/src/vnotebook.cpp index 3d5d4a0e..b5b39329 100644 --- a/src/vnotebook.cpp +++ b/src/vnotebook.cpp @@ -4,7 +4,7 @@ #include "vdirectory.h" #include "utils/vutils.h" #include "vconfigmanager.h" -#include "vfile.h" +#include "vnotefile.h" extern VConfigManager *g_config; @@ -221,7 +221,7 @@ bool VNotebook::containsFile(const VFile *p_file) const return m_rootDir->containsFile(p_file); } -VFile *VNotebook::tryLoadFile(const QString &p_path) +VNoteFile *VNotebook::tryLoadFile(const QString &p_path) { QFileInfo fi(p_path); Q_ASSERT(fi.isAbsolute()); @@ -240,7 +240,7 @@ VFile *VNotebook::tryLoadFile(const QString &p_path) return NULL; } - VFile *file = m_rootDir->tryLoadFile(filePath); + VNoteFile *file = m_rootDir->tryLoadFile(filePath); if (!file && !opened) { close(); diff --git a/src/vnotebook.h b/src/vnotebook.h index 1348cea6..ccff4e66 100644 --- a/src/vnotebook.h +++ b/src/vnotebook.h @@ -7,6 +7,7 @@ class VDirectory; class VFile; +class VNoteFile; class VNotebook : public QObject { @@ -29,11 +30,11 @@ public: bool containsFile(const VFile *p_file) const; // Try to load the file @p_path. - // Returns the corresponding VFile struct if @p_path is a note inside this notebook. + // Returns the corresponding VNoteFile struct if @p_path is a note 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. - VFile *tryLoadFile(const QString &p_path); + VNoteFile *tryLoadFile(const QString &p_path); const QString &getName() const; const QString &getPath() const; diff --git a/src/vnotefile.cpp b/src/vnotefile.cpp new file mode 100644 index 00000000..0307cd20 --- /dev/null +++ b/src/vnotefile.cpp @@ -0,0 +1,187 @@ +#include "vnotefile.h" + +#include +#include +#include +#include +#include + +#include "utils/vutils.h" +#include "vdirectory.h" + +VNoteFile::VNoteFile(VDirectory *p_directory, + const QString &p_name, + FileType p_type, + bool p_modifiable, + QDateTime p_createdTimeUtc, + QDateTime p_modifiedTimeUtc) + : VFile(p_directory, p_name, p_type, p_modifiable, p_createdTimeUtc, p_modifiedTimeUtc) +{ +} + +QString VNoteFile::fetchPath() const +{ + return QDir(getDirectory()->fetchPath()).filePath(m_name); +} + +QString VNoteFile::fetchBasePath() const +{ + return getDirectory()->fetchPath(); +} + +QString VNoteFile::fetchImageFolderPath() const +{ + return QDir(fetchBasePath()).filePath(getNotebook()->getImageFolder()); +} + +bool VNoteFile::useRelativeImageFolder() const +{ + // Always use relative image folder. + return true; +} + +QString VNoteFile::getImageFolderInLink() const +{ + return getNotebook()->getImageFolder(); +} + +void VNoteFile::setName(const QString &p_name) +{ + Q_ASSERT(m_name.isEmpty() + || (m_docType == VUtils::docTypeFromName(p_name))); + + m_name = p_name; +} + +bool VNoteFile::rename(const QString &p_name) +{ + if (m_name == p_name) { + return true; + } + + QString oldName = m_name; + + VDirectory *dir = getDirectory(); + Q_ASSERT(dir); + + // Rename it in disk. + QDir diskDir(dir->fetchPath()); + if (!diskDir.rename(m_name, p_name)) { + qWarning() << "fail to rename file" << m_name << "to" << p_name << "in disk"; + return false; + } + + m_name = p_name; + + // Update parent directory's config file. + if (!dir->writeToConfig()) { + m_name = oldName; + diskDir.rename(p_name, m_name); + return false; + } + + // Can't not change doc type. + Q_ASSERT(m_docType == VUtils::docTypeFromName(m_name)); + + qDebug() << "file renamed from" << oldName << "to" << m_name; + return true; +} + +VDirectory *VNoteFile::getDirectory() +{ + Q_ASSERT(parent()); + return (VDirectory *)parent(); +} + +const VDirectory *VNoteFile::getDirectory() const +{ + Q_ASSERT(parent()); + return (const VDirectory *)parent(); +} + +VNotebook *VNoteFile::getNotebook() +{ + return getDirectory()->getNotebook(); +} + +const VNotebook *VNoteFile::getNotebook() const +{ + return getDirectory()->getNotebook(); +} + +QString VNoteFile::getNotebookName() const +{ + return getDirectory()->getNotebookName(); +} + +QString VNoteFile::fetchRelativePath() const +{ + return QDir(getDirectory()->fetchRelativePath()).filePath(m_name); +} + +VNoteFile *VNoteFile::fromJson(VDirectory *p_directory, + const QJsonObject &p_json, + FileType p_type, + bool p_modifiable) +{ + return new VNoteFile(p_directory, + p_json[DirConfig::c_name].toString(), + p_type, + p_modifiable, + QDateTime::fromString(p_json[DirConfig::c_createdTime].toString(), + Qt::ISODate), + QDateTime::fromString(p_json[DirConfig::c_modifiedTime].toString(), + Qt::ISODate)); +} + +QJsonObject VNoteFile::toConfigJson() const +{ + QJsonObject item; + item[DirConfig::c_name] = m_name; + item[DirConfig::c_createdTime] = m_createdTimeUtc.toString(Qt::ISODate); + item[DirConfig::c_modifiedTime] = m_modifiedTimeUtc.toString(Qt::ISODate); + + return item; +} + +bool VNoteFile::deleteFile() +{ + Q_ASSERT(parent()); + + bool ret = false; + + // Delete local images if it is Markdown. + if (m_docType == DocType::Markdown) { + deleteInternalImages(); + } + + // TODO: Delete attachments. + + // Delete the file. + QString filePath = fetchPath(); + if (VUtils::deleteFile(getNotebook(), filePath, false)) { + ret = true; + qDebug() << "deleted" << m_name << filePath; + } else { + qWarning() << "fail to delete" << m_name << filePath; + } + + return ret; +} + +void VNoteFile::deleteInternalImages() +{ + Q_ASSERT(parent() && m_docType == DocType::Markdown); + + QVector images = VUtils::fetchImagesFromMarkdownFile(this, + ImageLink::LocalRelativeInternal); + int deleted = 0; + for (int i = 0; i < images.size(); ++i) { + if (VUtils::deleteFile(getNotebook(), images[i].m_path, false)) { + ++deleted; + } + } + + qDebug() << "delete" << deleted << "images for" << m_name << fetchPath(); +} + diff --git a/src/vnotefile.h b/src/vnotefile.h new file mode 100644 index 00000000..f49001b6 --- /dev/null +++ b/src/vnotefile.h @@ -0,0 +1,66 @@ +#ifndef VNOTEFILE_H +#define VNOTEFILE_H + +#include "vfile.h" + +class VDirectory; +class VNotebook; + +class VNoteFile : public VFile +{ + Q_OBJECT +public: + VNoteFile(VDirectory *p_directory, + const QString &p_name, + FileType p_type, + bool p_modifiable, + QDateTime p_createdTimeUtc, + QDateTime p_modifiedTimeUtc); + + QString fetchPath() const Q_DECL_OVERRIDE; + + QString fetchBasePath() const Q_DECL_OVERRIDE; + + QString fetchImageFolderPath() const Q_DECL_OVERRIDE; + + bool useRelativeImageFolder() const Q_DECL_OVERRIDE; + + QString getImageFolderInLink() const Q_DECL_OVERRIDE; + + // Set the name of this file. + void setName(const QString &p_name); + + // Rename the name of this file in disk and config. + bool rename(const QString &p_name); + + VDirectory *getDirectory(); + + const VDirectory *getDirectory() const; + + VNotebook *getNotebook(); + + const VNotebook *getNotebook() const; + + QString getNotebookName() const; + + // Get the relative path related to the notebook. + QString fetchRelativePath() const; + + // Create a VNoteFile from @p_json Json object. + static VNoteFile *fromJson(VDirectory *p_directory, + const QJsonObject &p_json, + FileType p_type, + bool p_modifiable); + + // Create a Json object from current instance. + QJsonObject toConfigJson() const; + + // Delete this file in disk as well as all its images/attachments. + bool deleteFile(); + +private: + // Delete internal images of this file. + void deleteInternalImages(); +}; + +#endif // VNOTEFILE_H diff --git a/src/vopenedlistmenu.cpp b/src/vopenedlistmenu.cpp index 91c78f11..4daf55eb 100644 --- a/src/vopenedlistmenu.cpp +++ b/src/vopenedlistmenu.cpp @@ -8,7 +8,7 @@ #include #include "veditwindow.h" -#include "vfile.h" +#include "vnotefile.h" #include "vedittab.h" #include "vdirectory.h" #include "utils/vutils.h" @@ -18,8 +18,19 @@ static const int c_cmdTime = 1 * 1000; static bool fileComp(const VOpenedListMenu::ItemInfo &a, const VOpenedListMenu::ItemInfo &b) { - QString notebooka = a.file->getNotebookName().toLower(); - QString notebookb = b.file->getNotebookName().toLower(); + QString notebooka, notebookb; + if (a.file->getType() == FileType::Note) { + notebooka = dynamic_cast(a.file)->getNotebookName().toLower(); + } else { + notebooka = "EXTERNAL_FILES"; + } + + if (b.file->getType() == FileType::Note) { + notebookb = dynamic_cast(b.file)->getNotebookName().toLower(); + } else { + notebookb = "EXTERNAL_FILES"; + } + if (notebooka < notebookb) { return true; } else if (notebooka > notebookb) { @@ -87,11 +98,20 @@ void VOpenedListMenu::updateOpenedList() int index = files[i].index; // Whether add separator. - QString curNotebook = file->getNotebookName(); + QString curNotebook; + const VDirectory *curDirectory = NULL; + if (file->getType() == FileType::Note) { + const VNoteFile *tmpFile = dynamic_cast((VFile *)file); + curNotebook = tmpFile->getNotebookName(); + curDirectory = tmpFile->getDirectory(); + } else { + curNotebook = "EXTERNAL_FILES"; + } + if (curNotebook != notebook - || file->getDirectory() != directory) { + || curDirectory != directory) { notebook = curNotebook; - directory = file->getDirectory(); + directory = curDirectory; QString dirName; if (directory) { dirName = directory->getName(); @@ -127,8 +147,14 @@ QString VOpenedListMenu::generateDescription(const VFile *p_file) const if (!p_file) { return ""; } + // [Notebook]path - return QString("[%1] %2").arg(p_file->getNotebookName()).arg(p_file->fetchPath()); + if (p_file->getType() == FileType::Note) { + const VNoteFile *tmpFile = dynamic_cast(p_file); + return QString("[%1] %2").arg(tmpFile->getNotebookName()).arg(tmpFile->fetchPath()); + } else { + return QString("%1").arg(p_file->fetchPath()); + } } void VOpenedListMenu::handleItemTriggered(QAction *p_action) diff --git a/src/vorphanfile.cpp b/src/vorphanfile.cpp index e05d2d4c..599e8aec 100644 --- a/src/vorphanfile.cpp +++ b/src/vorphanfile.cpp @@ -8,33 +8,19 @@ extern VConfigManager *g_config; -VOrphanFile::VOrphanFile(const QString &p_path, QObject *p_parent, - bool p_modifiable, bool p_systemFile) +VOrphanFile::VOrphanFile(QObject *p_parent, + const QString &p_path, + bool p_modifiable, + bool p_systemFile) : VFile(p_parent, VUtils::fileNameFromPath(p_path), FileType::Orphan, p_modifiable, QDateTime(), QDateTime()), - m_path(p_path), m_notebookName(tr("[EXTERNAL]")), m_systemFile(p_systemFile) + m_path(p_path), + m_systemFile(p_systemFile) { - qDebug() << "VOrphanFile" << p_path << m_name << p_modifiable; -} - -bool VOrphanFile::open() -{ - Q_ASSERT(!m_name.isEmpty()); - if (m_opened) { - return true; - } - - Q_ASSERT(m_content.isEmpty()); - Q_ASSERT(QFileInfo::exists(m_path)); - - m_content = VUtils::readFileFromDisk(m_path); - m_modified = false; - m_opened = true; - return true; } QString VOrphanFile::fetchPath() const @@ -42,17 +28,12 @@ QString VOrphanFile::fetchPath() const return m_path; } -QString VOrphanFile::fetchRelativePath() const -{ - return m_path; -} - QString VOrphanFile::fetchBasePath() const { return VUtils::basePathFromPath(m_path); } -QString VOrphanFile::fetchImagePath() const +QString VOrphanFile::fetchImageFolderPath() const { QString folder = m_imageFolder; if (m_imageFolder.isEmpty()) { @@ -67,76 +48,7 @@ QString VOrphanFile::fetchImagePath() const } } -bool VOrphanFile::save() -{ - Q_ASSERT(m_opened); - Q_ASSERT(m_modifiable); - return VUtils::writeFileToDisk(fetchPath(), m_content); -} - -void VOrphanFile::setName(const QString & /* p_name */) -{ - V_ASSERT(false); -} - -VDirectory *VOrphanFile::getDirectory() -{ - return NULL; -} - -const VDirectory *VOrphanFile::getDirectory() const -{ - return NULL; -} - -QString VOrphanFile::getNotebookName() const -{ - return m_notebookName; -} - -void VOrphanFile::setNotebookName(const QString &p_notebook) -{ - m_notebookName = p_notebook; -} - -VNotebook *VOrphanFile::getNotebook() -{ - return NULL; -} - -void VOrphanFile::setContent(const QString & p_content) -{ - m_content = p_content; -} - -bool VOrphanFile::isInternalImageFolder(const QString &p_path) const -{ - return VUtils::equalPath(VUtils::basePathFromPath(p_path), - fetchBasePath()) - || VUtils::equalPath(p_path, fetchImagePath()); -} - -bool VOrphanFile::rename(const QString &p_name) -{ - QDir dir(fetchBasePath()); - if (!dir.rename(m_name, p_name)) { - qWarning() << "fail to rename note" << m_name << "to" << p_name << "in disk"; - return false; - } - - m_name = p_name; - m_path = dir.filePath(m_name); - return true; -} - -void VOrphanFile::setImageFolder(const QString &p_path) -{ - qDebug() << "orphan file" << fetchPath() << "image folder" - << m_imageFolder << "->" << p_path; - m_imageFolder = p_path; -} - -bool VOrphanFile::isRelativeImageFolder() const +bool VOrphanFile::useRelativeImageFolder() const { QString folder = m_imageFolder; if (m_imageFolder.isEmpty()) { diff --git a/src/vorphanfile.h b/src/vorphanfile.h index bd67ab0e..54e6b8ca 100644 --- a/src/vorphanfile.h +++ b/src/vorphanfile.h @@ -3,78 +3,65 @@ #include "vfile.h" -// VOrphanFile is file not belong to any notebooks or directories. +// VOrphanFile is a file not belonging to any notebooks or directories. +// Such as external files, system files. +// It uses the file path to locate and identify a file. class VOrphanFile : public VFile { Q_OBJECT public: - VOrphanFile(const QString &p_path, QObject *p_parent, - bool p_modifiable, bool p_systemFile = false); + VOrphanFile(QObject *p_parent, + const QString &p_path, + bool p_modifiable, + bool p_systemFile = false); - bool open() Q_DECL_OVERRIDE; QString fetchPath() const Q_DECL_OVERRIDE; - QString fetchRelativePath() const Q_DECL_OVERRIDE; + QString fetchBasePath() const Q_DECL_OVERRIDE; - VDirectory *getDirectory() Q_DECL_OVERRIDE; - const VDirectory *getDirectory() const Q_DECL_OVERRIDE; - QString getNotebookName() const Q_DECL_OVERRIDE; - void setNotebookName(const QString &p_notebook); + QString fetchImageFolderPath() const Q_DECL_OVERRIDE; - VNotebook *getNotebook() Q_DECL_OVERRIDE; - - // Rename file. - bool rename(const QString &p_name) Q_DECL_OVERRIDE; - - void setImageFolder(const QString &p_path); - - const QString getImageFolder() const; - - // Whether the image folder is a relative path. - bool isRelativeImageFolder() const Q_DECL_OVERRIDE; + // Whether use a relative image folder. + bool useRelativeImageFolder() const Q_DECL_OVERRIDE; // Return the image folder part in an image link. QString getImageFolderInLink() const Q_DECL_OVERRIDE; + // Return image folder config. + const QString getImageFolder() const; + + // Set the image folder config. + void setImageFolder(const QString &p_path); + bool isSystemFile() const; private: - bool save() Q_DECL_OVERRIDE; - void setName(const QString &p_name) Q_DECL_OVERRIDE; - QString fetchImagePath() const Q_DECL_OVERRIDE; - void setContent(const QString &p_content) Q_DECL_OVERRIDE; - bool isInternalImageFolder(const QString &p_path) const Q_DECL_OVERRIDE; - - static VFile *fromJson(const QJsonObject &p_json, - QObject *p_parent, - FileType p_type, - bool p_modifiable); - - QJsonObject toConfigJson() const; - + // Full path of this file. QString m_path; - QString m_notebookName; - // Image folder path of this file. // It could be an absolute or relative path. // Empty to use the global default config. + // Valid only within a session. QString m_imageFolder; // Whether it is a system internal file. bool m_systemFile; - - friend class VDirectory; }; -inline bool VOrphanFile::isSystemFile() const -{ - return m_systemFile; -} - inline const QString VOrphanFile::getImageFolder() const { return m_imageFolder; } +inline void VOrphanFile::setImageFolder(const QString &p_path) +{ + m_imageFolder = p_path; +} + +inline bool VOrphanFile::isSystemFile() const +{ + return m_systemFile; +} + #endif // VORPHANFILE_H