From c2fe857e3adf305484d63d219eefe110e9491c2e Mon Sep 17 00:00:00 2001 From: Le Tan Date: Mon, 7 Aug 2017 20:04:18 +0800 Subject: [PATCH] open an external file as internal note if it is a note within VNote --- src/utils/vutils.cpp | 34 ++++++++++++++++++++++++++++++++++ src/utils/vutils.h | 9 +++++++++ src/vdirectory.cpp | 33 +++++++++++++++++++++++++++++++++ src/vdirectory.h | 29 ++++++++++++++++------------- src/vmainwindow.cpp | 12 ++++++++++-- src/vmainwindow.h | 4 +++- src/vnote.cpp | 14 ++++++++++++++ src/vnote.h | 5 +++++ src/vnotebook.cpp | 36 ++++++++++++++++++++++++++++++++++++ src/vnotebook.h | 16 ++++++++++++++-- 10 files changed, 174 insertions(+), 18 deletions(-) diff --git a/src/utils/vutils.cpp b/src/utils/vutils.cpp index 6791c7fa..a3f27f30 100644 --- a/src/utils/vutils.cpp +++ b/src/utils/vutils.cpp @@ -650,3 +650,37 @@ bool VUtils::equalPath(const QString &p_patha, const QString &p_pathb) return a == b; } + +bool VUtils::splitPathInBasePath(const QString &p_base, + const QString &p_path, + QStringList &p_parts) +{ + p_parts.clear(); + QString a = QDir::cleanPath(p_base); + QString b = QDir::cleanPath(p_path); + +#if defined(Q_OS_WIN) + if (!b.toLower().startsWith(a.toLower())) { + return false; + } +#else + if (!b.startsWith(a)) { + return false; + } +#endif + + if (a.size() == b.size()) { + return true; + } + + Q_ASSERT(a.size() < b.size()); + + if (b.at(a.size()) != '/') { + return false; + } + + p_parts = b.right(b.size() - a.size() - 1).split("/", QString::SkipEmptyParts); + + qDebug() << QString("split path %1 based on %2 to %3 parts").arg(p_path).arg(p_base).arg(p_parts.size()); + return true; +} diff --git a/src/utils/vutils.h b/src/utils/vutils.h index bf6b3ef0..d1d9d6c8 100644 --- a/src/utils/vutils.h +++ b/src/utils/vutils.h @@ -109,6 +109,15 @@ public: // Returns true if @p_patha and @p_pathb points to the same file/directory. static bool equalPath(const QString &p_patha, const QString &p_pathb); + // Try to split @p_path into multiple parts based on @p_base. + // Returns false if @p_path is not under @p_base directory. + // @p_parts will be empty if @p_path is right @p_base. + // Example: "/home/tamlok/study", "/home/tamlok/study/a/b/c/vnote.md" + // returns true and @p_parts is {a, b, c, vnote.md}. + static bool splitPathInBasePath(const QString &p_base, + const QString &p_path, + QStringList &p_parts); + // 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/vdirectory.cpp b/src/vdirectory.cpp index 8d5660f5..25f22fe7 100644 --- a/src/vdirectory.cpp +++ b/src/vdirectory.cpp @@ -678,3 +678,36 @@ void VDirectory::reorderFiles(int p_first, int p_last, int p_destStart) m_files = oriFiles; } } + +VFile *VDirectory::tryLoadFile(QStringList &p_filePath) +{ + qDebug() << "directory" << m_name << "tryLoadFile()" << p_filePath.join("/"); + if (p_filePath.isEmpty()) { + return NULL; + } + + bool opened = isOpened(); + if (!open()) { + return NULL; + } + + VFile *file = NULL; + + if (p_filePath.size() == 1) { + // File. + file = findFile(p_filePath.at(0)); + } else { + // Directory. + VDirectory *dir = findSubDirectory(p_filePath.at(0)); + if (dir) { + p_filePath.removeFirst(); + file = dir->tryLoadFile(p_filePath); + } + } + + if (!file && !opened) { + close(); + } + + return file; +} diff --git a/src/vdirectory.h b/src/vdirectory.h index 26f417a8..7e1100d1 100644 --- a/src/vdirectory.h +++ b/src/vdirectory.h @@ -60,20 +60,20 @@ public: static VDirectory *copyDirectory(VDirectory *p_destDir, const QString &p_destName, VDirectory *p_srcDir, bool p_cut); - inline const QVector &getSubDirs() const; - inline const QString &getName() const; - inline void setName(const QString &p_name); - inline bool isOpened() const; - inline VDirectory *getParentDirectory(); - inline const VDirectory *getParentDirectory() const; - inline VNotebook *getNotebook(); - inline const VNotebook *getNotebook() const; - inline const QVector &getFiles() const; - inline QString retrivePath() const; + const QVector &getSubDirs() const; + const QString &getName() const; + void setName(const QString &p_name); + bool isOpened() const; + VDirectory *getParentDirectory(); + const VDirectory *getParentDirectory() const; + VNotebook *getNotebook(); + const VNotebook *getNotebook() const; + const QVector &getFiles() const; + QString retrivePath() const; QString retriveBasePath() const; - inline QString retriveRelativePath() const; - inline QString getNotebookName() const; - inline bool isExpanded() const; + QString retriveRelativePath() const; + QString getNotebookName() const; + bool isExpanded() const; void setExpanded(bool p_expanded); void reorderFiles(int p_first, int p_last, int p_destStart); @@ -90,6 +90,9 @@ public: // notebook. bool writeToConfig() const; + // Try to load file given relative path @p_filePath. + VFile *tryLoadFile(QStringList &p_filePath); + private: // Get the path of @p_dir recursively QString retrivePath(const VDirectory *p_dir) const; diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index 4d57905f..bc8f125b 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -1890,11 +1890,19 @@ void VMainWindow::handleVimStatusUpdated(const VVim *p_vim) } } -void VMainWindow::openExternalFiles(const QStringList &p_files) +void VMainWindow::openExternalFiles(const QStringList &p_files, bool p_forceOrphan) { qDebug() << "open external files" << p_files; for (int i = 0; i < p_files.size(); ++i) { - VFile *file = vnote->getOrphanFile(p_files[i], true); + VFile *file = NULL; + if (!p_forceOrphan) { + file = vnote->getInternalFile(p_files[i]); + } + + if (!file) { + file = vnote->getOrphanFile(p_files[i], true); + } + editArea->openFile(file, OpenFileMode::Read); } } diff --git a/src/vmainwindow.h b/src/vmainwindow.h index 23ba1934..e6ea49cc 100644 --- a/src/vmainwindow.h +++ b/src/vmainwindow.h @@ -53,7 +53,9 @@ public: void editOrphanFileInfo(VFile *p_file); // Open external files @p_files as orphan files. - void openExternalFiles(const QStringList &p_files); + // If @p_forceOrphan is false, for each file, VNote will try to find out if + // it is a note inside VNote. If yes, VNote will open it as internal file. + void openExternalFiles(const QStringList &p_files, bool p_forceOrphan = false); private slots: void importNoteFromFile(); diff --git a/src/vnote.cpp b/src/vnote.cpp index 737884ac..59fe8534 100644 --- a/src/vnote.cpp +++ b/src/vnote.cpp @@ -309,3 +309,17 @@ VFile *VNote::getOrphanFile(const QString &p_path, bool p_modifiable, bool p_sys m_externalFiles.append(file); return file; } + +VFile *VNote::getInternalFile(const QString &p_path) +{ + VFile *file = NULL; + for (auto & nb : m_notebooks) { + file = nb->tryLoadFile(p_path); + if (file) { + break; + } + } + + return file; +} + diff --git a/src/vnote.h b/src/vnote.h index 158a06d6..ee862eca 100644 --- a/src/vnote.h +++ b/src/vnote.h @@ -78,6 +78,11 @@ public: VFile *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. + // Otherwise, returns NULL. + VFile *getInternalFile(const QString &p_path); + public slots: void updateTemplate(); diff --git a/src/vnotebook.cpp b/src/vnotebook.cpp index c2fb2001..36aee9a5 100644 --- a/src/vnotebook.cpp +++ b/src/vnotebook.cpp @@ -187,6 +187,37 @@ bool VNotebook::containsFile(const VFile *p_file) const return m_rootDir->containsFile(p_file); } +VFile *VNotebook::tryLoadFile(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; + } + + VFile *file = m_rootDir->tryLoadFile(filePath); + + if (!file && !opened) { + close(); + } + + return file; + } + + return NULL; +} + const QString &VNotebook::getImageFolder() const { if (m_imageFolder.isEmpty()) { @@ -205,3 +236,8 @@ const QString &VNotebook::getImageFolderConfig() const { return m_imageFolder; } + +bool VNotebook::isOpened() const +{ + return m_rootDir->isOpened(); +} diff --git a/src/vnotebook.h b/src/vnotebook.h index ac7e233d..3c2f82eb 100644 --- a/src/vnotebook.h +++ b/src/vnotebook.h @@ -17,15 +17,27 @@ public: // Open the root directory to load contents bool open(); + // Whether this notebook is opened. + bool isOpened() const; + // Close all the directory and files of this notebook. // Please make sure all files belonging to this notebook have been closed in the tab. void close(); 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. + // 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); + QString getName() const; QString getPath() const; - inline VDirectory *getRootDir(); + + VDirectory *getRootDir() const; + void rename(const QString &p_name); static VNotebook *createNotebook(const QString &p_name, const QString &p_path, @@ -76,7 +88,7 @@ private: VDirectory *m_rootDir; }; -inline VDirectory *VNotebook::getRootDir() +inline VDirectory *VNotebook::getRootDir() const { return m_rootDir; }