Browse Source

refactor VDirectory and VNotebook

Le Tan 8 years ago
parent
commit
0631b1c30e
5 changed files with 255 additions and 234 deletions
  1. 1 0
      src/vconstants.h
  2. 194 221
      src/vdirectory.cpp
  3. 40 10
      src/vdirectory.h
  4. 17 3
      src/vnotebook.cpp
  5. 3 0
      src/vnotebook.h

+ 1 - 0
src/vconstants.h

@@ -26,5 +26,6 @@ namespace DirConfig
     static const QString c_subDirectories = "sub_directories";
     static const QString c_files = "files";
     static const QString c_imageFolder = "image_folder";
+    static const QString c_name = "name";
 }
 #endif

+ 194 - 221
src/vdirectory.cpp

@@ -21,7 +21,9 @@ bool VDirectory::open()
     if (m_opened) {
         return true;
     }
-    Q_ASSERT(m_subDirs.isEmpty() && m_files.isEmpty());
+
+    V_ASSERT(m_subDirs.isEmpty() && m_files.isEmpty());
+
     QString path = retrivePath();
     QJsonObject configJson = VConfigManager::readDirectoryConfig(path);
     if (configJson.isEmpty()) {
@@ -30,22 +32,22 @@ bool VDirectory::open()
     }
 
     // [sub_directories] section
-    QJsonArray dirJson = configJson["sub_directories"].toArray();
+    QJsonArray dirJson = configJson[DirConfig::c_subDirectories].toArray();
     for (int i = 0; i < dirJson.size(); ++i) {
         QJsonObject dirItem = dirJson[i].toObject();
-        VDirectory *dir = new VDirectory(m_notebook, dirItem["name"].toString(), this);
+        VDirectory *dir = new VDirectory(m_notebook, dirItem[DirConfig::c_name].toString(), this);
         m_subDirs.append(dir);
     }
 
     // [files] section
-    QJsonArray fileJson = configJson["files"].toArray();
+    QJsonArray fileJson = configJson[DirConfig::c_files].toArray();
     for (int i = 0; i < fileJson.size(); ++i) {
         QJsonObject fileItem = fileJson[i].toObject();
-        VFile *file = new VFile(fileItem["name"].toString(), this);
+        VFile *file = new VFile(fileItem[DirConfig::c_name].toString(), this);
         m_files.append(file);
     }
+
     m_opened = true;
-    qDebug() << "dir" << m_name << "open" << m_subDirs.size() << "sub directories" << m_files.size() << "files";
     return true;
 }
 
@@ -112,13 +114,19 @@ QJsonObject VDirectory::toConfigJson() const
 
     QJsonArray subDirs;
     for (int i = 0; i < m_subDirs.size(); ++i) {
-        subDirs.append(m_subDirs[i]->getName());
+        QJsonObject item;
+        item[DirConfig::c_name] = m_subDirs[i]->getName();
+
+        subDirs.append(item);
     }
     dirJson[DirConfig::c_subDirectories] = subDirs;
 
     QJsonArray files;
     for (int i = 0; i < m_files.size(); ++i) {
-        files.append(m_files[i]->getName());
+        QJsonObject item;
+        item[DirConfig::c_name] = m_files[i]->getName();
+
+        files.append(item);
     }
     dirJson[DirConfig::c_files] = files;
 
@@ -132,7 +140,33 @@ bool VDirectory::readConfig()
 
 bool VDirectory::writeToConfig() const
 {
-    return VConfigManager::writeDirectoryConfig(retrivePath(), toConfigJson());
+    QJsonObject json = toConfigJson();
+
+    if (!getParentDirectory()) {
+        // Root directory.
+        addNotebookConfig(json);
+    }
+
+    qDebug() << "folder" << m_name << "write to config" << json;
+    return writeToConfig(json);
+}
+
+bool VDirectory::writeToConfig(const QJsonObject &p_json) const
+{
+    return VConfigManager::writeDirectoryConfig(retrivePath(), p_json);
+}
+
+void VDirectory::addNotebookConfig(QJsonObject &p_json) const
+{
+    V_ASSERT(!getParentDirectory());
+
+    QJsonObject nbJson = m_notebook->toConfigJsonNotebook();
+
+    // Merge it to p_json.
+    for (auto it = nbJson.begin(); it != nbJson.end(); ++it) {
+        V_ASSERT(!p_json.contains(it.key()));
+        p_json[it.key()] = it.value();
+    }
 }
 
 VDirectory *VDirectory::createSubDirectory(const QString &p_name)
@@ -142,6 +176,9 @@ VDirectory *VDirectory::createSubDirectory(const QString &p_name)
     if (!open()) {
         return NULL;
     }
+
+    qDebug() << "create subfolder" << p_name << "in" << m_name;
+
     QString path = retrivePath();
     QDir dir(path);
     if (!dir.mkdir(p_name)) {
@@ -150,67 +187,52 @@ VDirectory *VDirectory::createSubDirectory(const QString &p_name)
     }
 
     VDirectory *ret = new VDirectory(m_notebook, p_name, this);
-    if (!VConfigManager::writeDirectoryConfig(QDir::cleanPath(QDir(path).filePath(p_name)),
-                                              ret->toConfigJson())) {
+    if (!ret->writeToConfig()) {
         dir.rmdir(p_name);
         delete ret;
         return NULL;
     }
 
-    if (!createSubDirectoryInConfig(p_name)) {
+    m_subDirs.append(ret);
+    if (!writeToConfig()) {
         VConfigManager::deleteDirectoryConfig(QDir(path).filePath(p_name));
         dir.rmdir(p_name);
         delete ret;
+        m_subDirs.removeLast();
+
         return NULL;
     }
 
-    m_subDirs.append(ret);
     return ret;
 }
 
-bool VDirectory::createSubDirectoryInConfig(const QString &p_name, int p_index)
-{
-    QString path = retrivePath();
-    QJsonObject dirJson = VConfigManager::readDirectoryConfig(path);
-    Q_ASSERT(!dirJson.isEmpty());
-    QJsonObject itemJson;
-    itemJson["name"] = p_name;
-    QJsonArray subDirArray = dirJson["sub_directories"].toArray();
-    if (p_index == -1) {
-        subDirArray.append(itemJson);
-    } else {
-        subDirArray.insert(p_index, itemJson);
-    }
-    dirJson["sub_directories"] = subDirArray;
-    if (!VConfigManager::writeDirectoryConfig(path, dirJson)) {
-        return false;
-    }
-    return true;
-}
-
 VDirectory *VDirectory::findSubDirectory(const QString &p_name)
 {
-    if (!m_opened && !open()) {
+    if (!open()) {
         return NULL;
     }
+
     for (int i = 0; i < m_subDirs.size(); ++i) {
         if (p_name == m_subDirs[i]->getName()) {
             return m_subDirs[i];
         }
     }
+
     return NULL;
 }
 
 VFile *VDirectory::findFile(const QString &p_name)
 {
-    if (!m_opened && !open()) {
+    if (!open()) {
         return NULL;
     }
+
     for (int i = 0; i < m_files.size(); ++i) {
         if (p_name == m_files[i]->getName()) {
             return m_files[i];
         }
     }
+
     return NULL;
 }
 
@@ -219,6 +241,7 @@ bool VDirectory::containsFile(const VFile *p_file) const
     if (!p_file) {
         return false;
     }
+
     QObject *paDir = p_file->parent();
     while (paDir) {
         if (paDir == this) {
@@ -227,6 +250,7 @@ bool VDirectory::containsFile(const VFile *p_file) const
             paDir = paDir->parent();
         }
     }
+
     return false;
 }
 
@@ -236,98 +260,105 @@ VFile *VDirectory::createFile(const QString &p_name)
     if (!open()) {
         return NULL;
     }
+
     QString path = retrivePath();
-    QString filePath = QDir(path).filePath(p_name);
-    QFile file(filePath);
+    QFile file(QDir(path).filePath(p_name));
     if (!file.open(QIODevice::WriteOnly)) {
         qWarning() << "fail to create file" << p_name;
         return NULL;
     }
+
     file.close();
-    qDebug() << "file created" << p_name;
 
-    if (!createFileInConfig(p_name)) {
+    VFile *ret = new VFile(p_name, this);
+    m_files.append(ret);
+    if (!writeToConfig()) {
         file.remove();
+        delete ret;
+        m_files.removeLast();
         return NULL;
     }
 
-    VFile *ret = new VFile(p_name, this);
-    m_files.append(ret);
+    qDebug() << "note" << p_name << "created in folder" << m_name;
+
     return ret;
 }
 
-bool VDirectory::createFileInConfig(const QString &p_name, int p_index)
+bool VDirectory::addFile(VFile *p_file, int p_index)
 {
-    QString path = retrivePath();
-    QJsonObject dirJson = VConfigManager::readDirectoryConfig(path);
-    Q_ASSERT(!dirJson.isEmpty());
-    QJsonObject itemJson;
-    itemJson["name"] = p_name;
-    QJsonArray fileArray = dirJson["files"].toArray();
-    if (p_index == -1) {
-        fileArray.append(itemJson);
-    } else {
-        fileArray.insert(p_index, itemJson);
-    }
-    dirJson["files"] = fileArray;
-    if (!VConfigManager::writeDirectoryConfig(path, dirJson)) {
+    if (!open()) {
         return false;
     }
-    return true;
-}
 
-VFile *VDirectory::addFile(VFile *p_file, int p_index)
-{
-    if (!open()) {
-        return NULL;
-    }
-    if (!createFileInConfig(p_file->getName(), p_index)) {
-        return NULL;
-    }
     if (p_index == -1) {
         m_files.append(p_file);
     } else {
         m_files.insert(p_index, p_file);
     }
+
+    if (!writeToConfig()) {
+        if (p_index == -1) {
+            m_files.removeLast();
+        } else {
+            m_files.remove(p_index);
+        }
+
+        return false;
+    }
+
     p_file->setParent(this);
-    return p_file;
+
+    qDebug() << "note" << p_file->getName() << "added to folder" << m_name;
+
+    return true;
 }
 
 VFile *VDirectory::addFile(const QString &p_name, int p_index)
 {
-    if (!open()) {
-        return NULL;
-    }
-    if (!createFileInConfig(p_name, p_index)) {
+    if (!open() || p_name.isEmpty()) {
         return NULL;
     }
+
     VFile *file = new VFile(p_name, this);
     if (!file) {
         return NULL;
     }
-    if (p_index == -1) {
-        m_files.append(file);
-    } else {
-        m_files.insert(p_index, file);
+
+    if (!addFile(file, p_index)) {
+        delete file;
+        return NULL;
     }
+
     return file;
 }
 
-VDirectory *VDirectory::addSubDirectory(VDirectory *p_dir, int p_index)
+bool VDirectory::addSubDirectory(VDirectory *p_dir, int p_index)
 {
     if (!open()) {
-        return NULL;
-    }
-    if (!createSubDirectoryInConfig(p_dir->getName(), p_index)) {
-        return NULL;
+        return false;
     }
+
     if (p_index == -1) {
         m_subDirs.append(p_dir);
     } else {
         m_subDirs.insert(p_index, p_dir);
     }
+
+    if (!writeToConfig()) {
+        if (p_index == -1) {
+            m_subDirs.removeLast();
+        } else {
+            m_subDirs.remove(p_index);
+        }
+
+        return false;
+    }
+
     p_dir->setParent(this);
-    return p_dir;
+
+    qDebug() << "folder" << p_dir->getName() << "added to folder" << m_name;
+
+    return true;
 }
 
 VDirectory *VDirectory::addSubDirectory(const QString &p_name, int p_index)
@@ -335,18 +366,17 @@ VDirectory *VDirectory::addSubDirectory(const QString &p_name, int p_index)
     if (!open()) {
         return NULL;
     }
-    if (!createSubDirectoryInConfig(p_name, p_index)) {
-        return NULL;
-    }
+
     VDirectory *dir = new VDirectory(m_notebook, p_name, this);
     if (!dir) {
         return NULL;
     }
-    if (p_index == -1) {
-        m_subDirs.append(dir);
-    } else {
-        m_subDirs.insert(p_index, dir);
+
+    if (!addSubDirectory(dir, p_index)) {
+        delete dir;
+        return NULL;
     }
+
     return dir;
 }
 
@@ -354,94 +384,55 @@ void VDirectory::deleteSubDirectory(VDirectory *p_subDir)
 {
     QString dirPath = p_subDir->retrivePath();
 
+    p_subDir->close();
+
     removeSubDirectory(p_subDir);
 
     // Delete the entire directory
-    p_subDir->close();
     QDir dir(dirPath);
     if (!dir.removeRecursively()) {
-        qWarning() << "fail to remove" << dirPath << "recursively";
+        qWarning() << "fail to remove directory" << dirPath << "recursively";
     } else {
-        qDebug() << "deleted" << dirPath;
+        qDebug() << "deleted" << dirPath << "from disk";
     }
+
     delete p_subDir;
 }
 
-int VDirectory::removeSubDirectory(VDirectory *p_dir)
+bool VDirectory::removeSubDirectory(VDirectory *p_dir)
 {
-    Q_ASSERT(m_opened);
-    Q_ASSERT(p_dir);
-
-    QString path = retrivePath();
+    V_ASSERT(m_opened);
+    V_ASSERT(p_dir);
 
-    int index;
-    for (index = 0; index < m_subDirs.size(); ++index) {
-        if (m_subDirs[index] == p_dir) {
-            break;
-        }
-    }
-    Q_ASSERT(index != m_subDirs.size());
+    int index = m_subDirs.indexOf(p_dir);
+    V_ASSERT(index != -1);
     m_subDirs.remove(index);
 
-    QString name = p_dir->getName();
-    // Update config to exclude this directory
-    QJsonObject dirJson = VConfigManager::readDirectoryConfig(path);
-    QJsonArray subDirArray = dirJson["sub_directories"].toArray();
-    bool deleted = false;
-    for (int i = 0; i < subDirArray.size(); ++i) {
-        QJsonObject ele = subDirArray[i].toObject();
-        if (ele["name"].toString() == name) {
-            subDirArray.removeAt(i);
-            deleted = true;
-            index = i;
-            break;
-        }
-    }
-    Q_ASSERT(deleted);
-    dirJson["sub_directories"] = subDirArray;
-    if (!VConfigManager::writeDirectoryConfig(path, dirJson)) {
-        qWarning() << "fail to update configuration in" << path;
+    if (!writeToConfig()) {
+        return false;
     }
-    return index;
+
+    qDebug() << "folder" << p_dir->getName() << "removed from folder" << m_name;
+
+    return true;
 }
 
-// After calling this, p_file->parent() remain the same.
-int VDirectory::removeFile(VFile *p_file)
+bool VDirectory::removeFile(VFile *p_file)
 {
-    Q_ASSERT(m_opened);
-    Q_ASSERT(p_file);
+    V_ASSERT(m_opened);
+    V_ASSERT(p_file);
 
-    QString path = retrivePath();
-
-    int index;
-    for (index = 0; index < m_files.size(); ++index) {
-        if (m_files[index] == p_file) {
-            break;
-        }
-    }
-    Q_ASSERT(index != m_files.size());
+    int index = m_files.indexOf(p_file);
+    V_ASSERT(index != -1);
     m_files.remove(index);
-    QString name = p_file->getName();
-
-    // Update config to exclude this file
-    QJsonObject dirJson = VConfigManager::readDirectoryConfig(path);
-    QJsonArray subFileArray = dirJson["files"].toArray();
-    bool deleted = false;
-    for (int i = 0; i < subFileArray.size(); ++i) {
-        QJsonObject ele = subFileArray[i].toObject();
-        if (ele["name"].toString() == name) {
-            subFileArray.removeAt(i);
-            deleted = true;
-            index = i;
-            break;
-        }
-    }
-    Q_ASSERT(deleted);
-    dirJson["files"] = subFileArray;
-    if (!VConfigManager::writeDirectoryConfig(path, dirJson)) {
-        qWarning() << "fail to update configuration in" << path;
+
+    if (!writeToConfig()) {
+        return false;
     }
-    return index;
+
+    qDebug() << "note" << p_file->getName() << "removed from folder" << m_name;
+
+    return true;
 }
 
 void VDirectory::deleteFile(VFile *p_file)
@@ -449,8 +440,11 @@ void VDirectory::deleteFile(VFile *p_file)
     removeFile(p_file);
 
     // Delete the file
-    Q_ASSERT(!p_file->isOpened());
+    V_ASSERT(!p_file->isOpened());
+    V_ASSERT(p_file->parent());
+
     p_file->deleteDiskFile();
+
     delete p_file;
 }
 
@@ -459,34 +453,29 @@ bool VDirectory::rename(const QString &p_name)
     if (m_name == p_name) {
         return true;
     }
+
+    QString oldName = m_name;
+
     VDirectory *parentDir = getParentDirectory();
-    Q_ASSERT(parentDir);
-    QString parentPath = parentDir->retrivePath();
-    QDir dir(parentPath);
-    QString name = m_name;
+    V_ASSERT(parentDir);
+    // Rename it in disk.
+    QDir dir(parentDir->retrivePath());
     if (!dir.rename(m_name, p_name)) {
-        qWarning() << "fail to rename directory" << m_name << "to" << p_name;
+        qWarning() << "fail to rename folder" << m_name << "to" << p_name << "in disk";
         return false;
     }
+
     m_name = p_name;
 
     // Update parent's config file
-    QJsonObject dirJson = VConfigManager::readDirectoryConfig(parentPath);
-    QJsonArray subDirArray = dirJson["sub_directories"].toArray();
-    int index = 0;
-    for (index = 0; index < subDirArray.size(); ++index) {
-        QJsonObject ele = subDirArray[index].toObject();
-        if (ele["name"].toString() == name) {
-            ele["name"] = p_name;
-            subDirArray[index] = ele;
-            break;
-        }
-    }
-    Q_ASSERT(index != subDirArray.size());
-    dirJson["sub_directories"] = subDirArray;
-    if (!VConfigManager::writeDirectoryConfig(parentPath, dirJson)) {
+    if (!parentDir->writeToConfig()) {
+        m_name = oldName;
+        dir.rename(p_name, m_name);
         return false;
     }
+
+    qDebug() << "folder renamed from" << oldName << "to" << m_name;
+
     return true;
 }
 
@@ -498,6 +487,7 @@ VFile *VDirectory::copyFile(VDirectory *p_destDir, const QString &p_destName,
     if (srcPath == destPath) {
         return p_srcFile;
     }
+
     VDirectory *srcDir = p_srcFile->getDirectory();
     DocType docType = p_srcFile->getDocType();
     DocType newDocType = VUtils::isMarkdown(destPath) ? DocType::Markdown : DocType::Html;
@@ -518,16 +508,20 @@ VFile *VDirectory::copyFile(VDirectory *p_destDir, const QString &p_destName,
     VFile *destFile = NULL;
     if (p_cut) {
         // Remove the file from config
-        index = srcDir->removeFile(p_srcFile);
+        srcDir->removeFile(p_srcFile);
+
         p_srcFile->setName(p_destName);
-        if (srcDir != p_destDir) {
-            index = -1;
-        }
+
         // Add the file to new dir's config
-        destFile = p_destDir->addFile(p_srcFile, index);
+        if (p_destDir->addFile(p_srcFile, index)) {
+            destFile = p_srcFile;
+        } else {
+            destFile = NULL;
+        }
     } else {
         destFile = p_destDir->addFile(p_destName, -1);
     }
+
     if (!destFile) {
         return NULL;
     }
@@ -616,6 +610,7 @@ VDirectory *VDirectory::copyDirectory(VDirectory *p_destDir, const QString &p_de
     if (srcPath == destPath) {
         return p_srcDir;
     }
+
     VDirectory *srcParentDir = p_srcDir->getParentDirectory();
 
     // Copy the directory
@@ -628,39 +623,41 @@ VDirectory *VDirectory::copyDirectory(VDirectory *p_destDir, const QString &p_de
     VDirectory *destDir = NULL;
     if (p_cut) {
         // Remove the directory from config
-        index = srcParentDir->removeSubDirectory(p_srcDir);
+        srcParentDir->removeSubDirectory(p_srcDir);
+
         p_srcDir->setName(p_destName);
-        if (srcParentDir != p_destDir) {
-            index = -1;
-        }
+
         // Add the directory to new dir's config
-        destDir = p_destDir->addSubDirectory(p_srcDir, index);
+        if (p_destDir->addSubDirectory(p_srcDir, index)) {
+            destDir = p_srcDir;
+        } else {
+            destDir = NULL;
+        }
     } else {
         destDir = p_destDir->addSubDirectory(p_destName, -1);
     }
+
     return destDir;
 }
 
 void VDirectory::setExpanded(bool p_expanded)
 {
     if (p_expanded) {
-        Q_ASSERT(m_opened);
+        V_ASSERT(m_opened);
     }
+
     m_expanded = p_expanded;
 }
 
 void VDirectory::reorderFiles(int p_first, int p_last, int p_destStart)
 {
-    Q_ASSERT(m_opened);
-    Q_ASSERT(p_first <= p_last);
-    Q_ASSERT(p_last < m_files.size());
-    Q_ASSERT(p_destStart < p_first || p_destStart > p_last);
-    Q_ASSERT(p_destStart >= 0 && p_destStart <= m_files.size());
+    V_ASSERT(m_opened);
+    V_ASSERT(p_first <= p_last);
+    V_ASSERT(p_last < m_files.size());
+    V_ASSERT(p_destStart < p_first || p_destStart > p_last);
+    V_ASSERT(p_destStart >= 0 && p_destStart <= m_files.size());
 
-    if (!reorderFilesInConfig(p_first, p_last, p_destStart)) {
-        qWarning() << "fail to reorder files in config" << p_first << p_last << p_destStart;
-        return;
-    }
+    auto oriFiles = m_files;
 
     // Reorder m_files.
     if (p_destStart > p_last) {
@@ -675,33 +672,9 @@ void VDirectory::reorderFiles(int p_first, int p_last, int p_destStart)
             m_files.move(i, to++);
         }
     }
-}
 
-bool VDirectory::reorderFilesInConfig(int p_first, int p_last, int p_destStart)
-{
-    QString path = retrivePath();
-    QJsonObject dirJson = VConfigManager::readDirectoryConfig(path);
-    Q_ASSERT(!dirJson.isEmpty());
-    QJsonArray fileArray = dirJson["files"].toArray();
-    Q_ASSERT(fileArray.size() == m_files.size());
-
-    if (p_destStart > p_last) {
-        int to = p_destStart - 1;
-        for (int i = p_first; i <= p_last; ++i) {
-            // Move p_first to p_destStart every time.
-            QJsonValue ele = fileArray.takeAt(p_first);
-            fileArray.insert(to, ele);
-        }
-    } else {
-        int to = p_destStart;
-        for (int i = p_first; i <= p_last; ++i) {
-            QJsonValue ele = fileArray.takeAt(i);
-            fileArray.insert(to++, ele);
-        }
-    }
-    dirJson["files"] = fileArray;
-    if (!VConfigManager::writeDirectoryConfig(path, dirJson)) {
-        return false;
+    if (!writeToConfig()) {
+        qWarning() << "fail to reorder files in config" << p_first << p_last << p_destStart;
+        m_files = oriFiles;
     }
-    return true;
 }

+ 40 - 10
src/vdirectory.h

@@ -19,28 +19,41 @@ public:
     bool open();
     void close();
     VDirectory *createSubDirectory(const QString &p_name);
+
+    // Returns the VDirectory with the name @p_name directly in this directory.
     VDirectory *findSubDirectory(const QString &p_name);
-    // Returns the VFile with the name @p_name.
+
+    // Returns the VFile with the name @p_name directly in this directory.
     VFile *findFile(const QString &p_name);
+
     // If current dir or its sub-dir contains @p_file.
     bool containsFile(const VFile *p_file) const;
+
     VFile *createFile(const QString &p_name);
+
     void deleteSubDirectory(VDirectory *p_subDir);
+
     // Remove the file in the config and m_files without deleting it in the disk.
-    int removeFile(VFile *p_file);
+    // It won't change the parent of @p_file to enable it find its path.
+    bool removeFile(VFile *p_file);
+
     // Remove the directory in the config and m_subDirs without deleting it in the disk.
-    int removeSubDirectory(VDirectory *p_dir);
+    // It won't change the parent of @p_dir to enable it find its path.
+    bool removeSubDirectory(VDirectory *p_dir);
+
     // Add the file in the config and m_files. If @p_index is -1, add it at the end.
     // Return the VFile if succeed.
-    VFile *addFile(VFile *p_file, int p_index);
     VFile *addFile(const QString &p_name, int p_index);
-    VDirectory *addSubDirectory(VDirectory *p_dir, int p_index);
-    VDirectory *addSubDirectory(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);
+
+    // 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.
+    // @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);
 
@@ -63,9 +76,9 @@ public:
     inline bool isExpanded() const;
     void setExpanded(bool p_expanded);
     void reorderFiles(int p_first, int p_last, int p_destStart);
-    bool reorderFilesInConfig(int p_first, int p_last, int p_destStart);
 
     // Serialize current instance to json.
+    // Not including sections belonging to notebook.
     QJsonObject toConfigJson() const;
 
     // Read configurations (excluding "sub_directories" and "files" section)
@@ -73,6 +86,8 @@ public:
     bool readConfig();
 
     // Write current instance to config file.
+    // If it is root directory, this will include sections belonging to
+    // notebook.
     bool writeToConfig() const;
 
 private:
@@ -80,8 +95,23 @@ private:
     QString retrivePath(const VDirectory *p_dir) const;
     // Get teh relative path of @p_dir recursively related to the notebook path
     QString retriveRelativePath(const VDirectory *p_dir) const;
-    bool createFileInConfig(const QString &p_name, int p_index = -1);
-    bool createSubDirectoryInConfig(const QString &p_name, int p_index = -1);
+
+    // Write @p_json to config.
+    bool writeToConfig(const QJsonObject &p_json) const;
+
+    // Add notebook part config to @p_json.
+    // Should only be called with root directory.
+    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);
+
+    // Add the directory in the config and m_subDirs. If @p_index is -1, add it at the end.
+    // Return the VDirectory if succeed.
+    VDirectory *addSubDirectory(const QString &p_name, int p_index);
+
+    // Add the directory in the config and m_subDirs. If @p_index is -1, add it at the end.
+    bool addSubDirectory(VDirectory *p_dir, int p_index);
 
     QPointer<VNotebook> m_notebook;
     QString m_name;

+ 17 - 3
src/vnotebook.cpp

@@ -37,9 +37,9 @@ bool VNotebook::readConfig()
     return true;
 }
 
-QJsonObject VNotebook::toConfigJson() const
+QJsonObject VNotebook::toConfigJsonNotebook() const
 {
-    QJsonObject json = m_rootDir->toConfigJson();
+    QJsonObject json;
 
     // [image_folder] section.
     json[DirConfig::c_imageFolder] = m_imageFolder;
@@ -47,6 +47,20 @@ QJsonObject VNotebook::toConfigJson() const
     return json;
 }
 
+QJsonObject VNotebook::toConfigJson() const
+{
+    QJsonObject json = m_rootDir->toConfigJson();
+    QJsonObject nbJson = toConfigJsonNotebook();
+
+    // Merge nbJson to json.
+    for (auto it = nbJson.begin(); it != nbJson.end(); ++it) {
+        V_ASSERT(!json.contains(it.key()));
+        json[it.key()] = it.value();
+    }
+
+    return json;
+}
+
 bool VNotebook::writeToConfig() const
 {
     return VConfigManager::writeDirectoryConfig(m_path, toConfigJson());
@@ -142,7 +156,7 @@ bool VNotebook::deleteNotebook(VNotebook *p_notebook, bool p_deleteFiles)
         QDir dir(p_notebook->getPath());
         dir.cdUp();
         if (!dir.rmdir(rootDir->getName())) {
-            qWarning() << "fail to delete notebook root directory" << rootDir->getName();
+            qWarning() << "fail to delete notebook root folder" << rootDir->getName();
             ret = false;
         }
     }

+ 3 - 0
src/vnotebook.h

@@ -51,6 +51,9 @@ public:
     // to root directory config file.
     bool writeConfig() const;
 
+    // Return only the info of notebook part in json.
+    QJsonObject toConfigJsonNotebook() const;
+
 signals:
     void contentChanged();