Browse Source

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;
Le Tan 8 years ago
parent
commit
a64d01ea86

+ 12 - 11
src/dialog/vfileinfodialog.cpp

@@ -1,30 +1,31 @@
 #include <QtWidgets>
 #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;

+ 9 - 8
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

+ 4 - 2
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 \

+ 13 - 0
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<VElementRegion> VUtils::fetchImageRegionsUsingParser(const QString &p_content)
 {
     Q_ASSERT(!p_content.isEmpty());

+ 6 - 0
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):

+ 2 - 2
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};

+ 31 - 31
src/vdirectory.cpp

@@ -4,7 +4,7 @@
 #include <QJsonArray>
 #include <QDebug>
 #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;

+ 16 - 15
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<VFile *> &getFiles() const;
+    const QVector<VNoteFile *> &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<VDirectory *> m_subDirs;
 
     // Owner of the files
-    QVector<VFile *> m_files;
+    QVector<VNoteFile *> 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<VFile *> &VDirectory::getFiles() const
+inline const QVector<VNoteFile *> &VDirectory::getFiles() const
 {
     return m_files;
 }

+ 1 - 1
src/vedit.h

@@ -11,7 +11,7 @@
 #include <QFontMetrics>
 #include "vconstants.h"
 #include "vtoc.h"
-#include "vfile.h"
+#include "vnotefile.h"
 
 class VEditOperations;
 class QLabel;

+ 6 - 5
src/veditwindow.cpp

@@ -125,8 +125,9 @@ void VEditWindow::initTabActions()
                 VEditTab *editor = getTab(tab);
                 QPointer<VFile> 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<VNoteFile *>((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<VOrphanFile *>(file)->isSystemFile()) {
+               && !(dynamic_cast<VOrphanFile *>(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<VFile> file = editor->getFile();
-    if (file->getType() == FileType::Normal) {
+    if (file->getType() == FileType::Note) {
         vnote->getMainWindow()->locateFile(file);
     }
 }

+ 8 - 2
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<const VNoteFile *>(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,

+ 15 - 210
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<ImageLink> 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)
-{
-    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;
-}
-
-bool VFile::isRelativeImageFolder() const
-{
-    return true;
-}
-
-QString VFile::getImageFolderInLink() const
+bool VFile::isInternalImageFolder(const QString &p_path) const
 {
-    return getNotebook()->getImageFolder();
+    return VUtils::equalPath(VUtils::basePathFromPath(p_path),
+                             fetchBasePath())
+           || VUtils::equalPath(p_path, fetchImageFolderPath());
 }
 
-VFile *VFile::fromJson(const QJsonObject &p_json,
-                       QObject *p_parent,
-                       FileType p_type,
-                       bool p_modifiable)
+void VFile::setModified(bool p_modified)
 {
-    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));
+    m_modified = p_modified;
 }
 
-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;
-}

+ 76 - 44
src/vfile.h

@@ -5,11 +5,9 @@
 #include <QString>
 #include <QUrl>
 #include <QDateTime>
-#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;
-
-    // Rename the file.
-    virtual bool rename(const QString &p_name);
+    // directory of this file or equals to fetchImageFolderPath().
+    bool isInternalImageFolder(const QString &p_path) const;
 
-    // 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;

+ 24 - 20
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<VFile *> &files = m_directory->getFiles();
+
+    const QVector<VNoteFile *> &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 <span style=\"%1\">%2</span>.")
@@ -355,14 +356,14 @@ void VFileList::newFile()
 QVector<QListWidgetItem *> VFileList::updateFileListAdded()
 {
     QVector<QListWidgetItem *> ret;
-    const QVector<VFile *> &files = m_directory->getFiles();
+    const QVector<VNoteFile *> &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<VFile> srcFile = m_copiedFiles[i];
+        QPointer<VNoteFile> 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<VFile *> files = m_directory->getFiles();
+    const QVector<VNoteFile *> files = m_directory->getFiles();
     int nrItems = fileList->count();
     if (nrItems != files.size()) {
         return false;

+ 20 - 16
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<QListWidgetItem *> updateFileListAdded();
-    inline QPointer<VFile> getVFile(QListWidgetItem *p_item) const;
+
+    inline QPointer<VNoteFile> getVFile(QListWidgetItem *p_item) const;
+
     // Check if the list items match exactly the contents of the directory.
     bool identicalListWithDirectory() const;
     QList<QListWidgetItem *> 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<VDirectory> m_directory;
-    QVector<QPointer<VFile> > m_copiedFiles;
+    QVector<QPointer<VNoteFile> > m_copiedFiles;
 
     // Actions
     QAction *m_openInReadAct;
@@ -126,10 +130,10 @@ inline void VFileList::setEditArea(VEditArea *editArea)
     this->editArea = editArea;
 }
 
-inline QPointer<VFile> VFileList::getVFile(QListWidgetItem *p_item) const
+inline QPointer<VNoteFile> 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

+ 21 - 12
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<VOrphanFile *>(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<const VNoteFile *>((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<VNoteFile *>((VFile *)m_curFile);
+        Q_ASSERT(file);
+        fileList->fileInfo(file);
     } else if (m_curFile->getType() == FileType::Orphan) {
         VOrphanFile *file = dynamic_cast<VOrphanFile *>((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<VNoteFile *>((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<VNoteFile *>(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<VOrphanFile *>(file))->setNotebookName(tr("[Help]"));
     editArea->openFile(file, OpenFileMode::Read);
 }
 

+ 10 - 2
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<const VNoteFile *>((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];

+ 4 - 4
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);
     }

+ 9 - 10
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<VOrphanFile *>(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) {

+ 9 - 7
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<VFile *> m_externalFiles;
+    QList<VOrphanFile *> m_externalFiles;
 };
 
 inline const QVector<QPair<QString, QString> >& VNote::getPalette() const

+ 3 - 3
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();

+ 3 - 2
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;

+ 187 - 0
src/vnotefile.cpp

@@ -0,0 +1,187 @@
+#include "vnotefile.h"
+
+#include <QDir>
+#include <QDebug>
+#include <QTextEdit>
+#include <QFileInfo>
+#include <QDebug>
+
+#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<ImageLink> 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();
+}
+

+ 66 - 0
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

+ 33 - 7
src/vopenedlistmenu.cpp

@@ -8,7 +8,7 @@
 #include <QStyleFactory>
 
 #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<const VNoteFile *>(a.file)->getNotebookName().toLower();
+    } else {
+        notebooka = "EXTERNAL_FILES";
+    }
+
+    if (b.file->getType() == FileType::Note) {
+        notebookb = dynamic_cast<const VNoteFile *>(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<const VNoteFile *>((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<const VNoteFile *>(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)

+ 8 - 96
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()) {

+ 27 - 40
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 fetchBasePath() const Q_DECL_OVERRIDE;
 
-    VNotebook *getNotebook() Q_DECL_OVERRIDE;
+    QString fetchImageFolderPath() const Q_DECL_OVERRIDE;
 
-    // Rename file.
-    bool rename(const QString &p_name) Q_DECL_OVERRIDE;
+    // Whether use a relative image folder.
+    bool useRelativeImageFolder() const Q_DECL_OVERRIDE;
 
-    void setImageFolder(const QString &p_path);
+    // Return the image folder part in an image link.
+    QString getImageFolderInLink() const Q_DECL_OVERRIDE;
 
+    // Return image folder config.
     const QString getImageFolder() const;
 
-    // Whether the image folder is a relative path.
-    bool isRelativeImageFolder() const Q_DECL_OVERRIDE;
-
-    // Return the image folder part in an image link.
-    QString getImageFolderInLink() const Q_DECL_OVERRIDE;
+    // 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
+inline const QString VOrphanFile::getImageFolder() const
 {
-    return m_systemFile;
+    return m_imageFolder;
 }
 
-inline const QString VOrphanFile::getImageFolder() const
+inline void VOrphanFile::setImageFolder(const QString &p_path)
 {
-    return m_imageFolder;
+    m_imageFolder = p_path;
+}
+
+inline bool VOrphanFile::isSystemFile() const
+{
+    return m_systemFile;
 }
 
 #endif // VORPHANFILE_H