diff --git a/CMakeLists.txt b/CMakeLists.txt index 0870dee..8c6113e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,8 +86,10 @@ list(APPEND SRC_FILES src/gui/statusbar src/gui/storytree src/gui/treetoolbar + src/project/project src/project/storyitem src/project/storymodel + src/data src/guimain src/main src/settings diff --git a/i18n/collett_en_US.ts b/i18n/collett_en_US.ts index 6335660..11c506d 100644 --- a/i18n/collett_en_US.ts +++ b/i18n/collett_en_US.ts @@ -1,23 +1,10 @@ - - Collett::CollettStoryModel - - - Title - - - - - Words - - - Collett::GuiMain - + %1 %2 Version %3 @@ -25,17 +12,32 @@ Collett::GuiMainToolBar - + No Project - + + New Project + + + + + Open Project + + + + + Save Project + + + + Project - + Menu @@ -53,6 +55,34 @@ + + Collett::Project + + + + Project not found at: %1 + + + + + + Could not create folder: %1 + + + + + Collett::StoryModel + + + Label + + + + + Words + + + main diff --git a/i18n/collett_nb_NO.ts b/i18n/collett_nb_NO.ts index 08fde80..4727c28 100644 --- a/i18n/collett_nb_NO.ts +++ b/i18n/collett_nb_NO.ts @@ -1,23 +1,10 @@ - - Collett::CollettStoryModel - - - Title - - - - - Words - - - Collett::GuiMain - + %1 %2 Version %3 @@ -25,17 +12,32 @@ Collett::GuiMainToolBar - + No Project - + + New Project + + + + + Open Project + + + + + Save Project + + + + Project - + Menu @@ -53,6 +55,34 @@ + + Collett::Project + + + + Project not found at: %1 + + + + + + Could not create folder: %1 + + + + + Collett::StoryModel + + + Label + + + + + Words + + + main diff --git a/sample/data/project.json b/sample/data/project.json new file mode 100644 index 0000000..3bce656 --- /dev/null +++ b/sample/data/project.json @@ -0,0 +1,12 @@ +{ + "meta": { + "created": "2021-12-04T16:18:21", + "updated": "2021-12-04T16:18:23" + }, + "project": { + "bookTitle": "New Project", + "projectName": "New Project" + }, + "settings": { + } +} diff --git a/sample/data/story.json b/sample/data/story.json new file mode 100644 index 0000000..6bdeec9 --- /dev/null +++ b/sample/data/story.json @@ -0,0 +1,17 @@ +{ + "handle": "ROOT", + "xItems": [ + { + "handle": "b32008d7-5b44-43a6-ace3-a7343b2ad496", + "label": "Title Page", + "order": 0, + "wCount": 0 + }, + { + "handle": "ff608d47-2fac-4d48-9a9c-13d787bc76c2", + "label": "Chapter 1", + "order": 1, + "wCount": 0 + } + ] +} diff --git a/sample/project.collett b/sample/project.collett new file mode 100644 index 0000000..566a247 --- /dev/null +++ b/sample/project.collett @@ -0,0 +1,2 @@ +Collett 0.0.1-alpha0 +Project 0.1 diff --git a/src/collett.h b/src/collett.h index d0ec981..f3816d0 100644 --- a/src/collett.h +++ b/src/collett.h @@ -26,4 +26,11 @@ along with this program. If not, see . #define COL_VERSION_NUM 0x000001a0 #define COL_VERSION_DATE "2021-11-14" +#define COL_PROJECT_FILE_NAME "project.collett" +#define COL_SETTINGS_FILE_NAME "project.json" +#define COL_STORY_FILE_NAME "story.json" +#define COL_NOTES_FILE_NAME "notes.json" + +#define COL_STORY_TREE_COL_COUNT 2 + #endif // COLLETT_H diff --git a/src/data.cpp b/src/data.cpp new file mode 100644 index 0000000..8365baa --- /dev/null +++ b/src/data.cpp @@ -0,0 +1,118 @@ +/* +Collett – Core Data Class +========================= + +This file is a part of Collett +Copyright 2020–2021, Veronica Berglyd Olsen + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "data.h" +#include "project.h" +#include "storymodel.h" + +#include +#include + +namespace Collett { + +/* + Private Class Declaration + ========================= +*/ + +class CollettDataPrivate +{ +public: + static CollettData *instance; + + CollettDataPrivate() {}; + ~CollettDataPrivate() { + qDebug() << "Deconstructing: CollettDataPrivate"; + delete m_project; + }; + + Project *m_project; + + bool m_hasProject = false; +}; + +/* + Public Class Contruction/Deconstruction + ======================================= +*/ + +CollettData *CollettDataPrivate::instance = nullptr; + +CollettData *CollettData::instance() { + if (CollettDataPrivate::instance == nullptr) { + CollettDataPrivate::instance = new CollettData(); + qDebug() << "CollettData instance created"; + } + return CollettDataPrivate::instance; +} + +CollettData::CollettData() : d_ptr(new CollettDataPrivate()) { + Q_D(CollettData); +} + +CollettData::~CollettData() {} + +/* + Public Class Methods + ==================== +*/ + +bool CollettData::openProject(const QString &path) { + Q_D(CollettData); + + d->m_project = new Project(path); + bool status = d->m_project->openProject(); + d->m_hasProject = d->m_project->hasProject(); + + return status; +} + +bool CollettData::saveProject() { + Q_D(CollettData); + + if (d->m_hasProject) { + return d->m_project->saveProject(); + } else { + return false; + } +} + +Project *CollettData::project() { + Q_D(CollettData); + + if (d->m_hasProject) { + return d->m_project; + } else { + return nullptr; + } +} + +StoryModel *CollettData::storyModel() { + Q_D(CollettData); + + if (d->m_hasProject) { + return d->m_project->storyModel(); + } else { + return nullptr; + } +} + +} // namespace Collett diff --git a/src/data.h b/src/data.h new file mode 100644 index 0000000..94d6de2 --- /dev/null +++ b/src/data.h @@ -0,0 +1,60 @@ +/* +Collett – Core Data Class +========================= + +This file is a part of Collett +Copyright 2020–2021, Veronica Berglyd Olsen + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef COLLETT_DATA_H +#define COLLETT_DATA_H + +#include "collett.h" +#include "project.h" +#include "storymodel.h" + +#include +#include +#include +#include + +namespace Collett { + +class CollettDataPrivate; +class CollettData : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(CollettData) + +public: + static CollettData *instance(); + ~CollettData(); + +private: + QScopedPointer d_ptr; + CollettData(); + +public: + bool openProject(const QString &path); + bool saveProject(); + + Project *project(); + StoryModel *storyModel(); + +}; +} // namespace Collett + +#endif // COLLETT_DATA_H diff --git a/src/gui/maintoolbar.cpp b/src/gui/maintoolbar.cpp index 5348675..db61651 100644 --- a/src/gui/maintoolbar.cpp +++ b/src/gui/maintoolbar.cpp @@ -25,6 +25,8 @@ along with this program. If not, see . #include #include #include +#include +#include namespace Collett { @@ -39,7 +41,7 @@ GuiMainToolBar::GuiMainToolBar(QWidget *parent) m_projectName = new QLabel(tr("No Project")); this->setOrientation(Qt::Horizontal); - this->addAction(tr("Project")); + this->buildProjectMenu(); this->addWidget(stretch1); this->addWidget(m_projectName); this->addWidget(stretch2); @@ -50,4 +52,32 @@ void GuiMainToolBar::setProjectName(const QString &name) { m_projectName->setText(name); } +/* + Build Functions + =============== +*/ + +void GuiMainToolBar::buildProjectMenu() { + + // Menu + m_projectMenu = new QMenu(this); + + // New Project + m_newProject = m_projectMenu->addAction(tr("New Project")); + + // Open Project + m_openProject = m_projectMenu->addAction(tr("Open Project")); + + // Save Project + m_saveProject = m_projectMenu->addAction(tr("Save Project")); + + // Assemble + m_projectButton = new QToolButton(this); + m_projectButton->setText(tr("Project")); + m_projectButton->setMenu(m_projectMenu); + m_projectButton->setPopupMode(QToolButton::InstantPopup); + this->addWidget(m_projectButton); + +} + } // namespace Collett diff --git a/src/gui/maintoolbar.h b/src/gui/maintoolbar.h index ab5856e..a41de8e 100644 --- a/src/gui/maintoolbar.h +++ b/src/gui/maintoolbar.h @@ -26,6 +26,9 @@ along with this program. If not, see . #include #include #include +#include +#include +#include namespace Collett { @@ -42,6 +45,15 @@ class GuiMainToolBar : public QToolBar private: QLabel *m_projectName; + // Main Actions + QToolButton *m_projectButton; + QMenu *m_projectMenu; + QAction *m_newProject; + QAction *m_openProject; + QAction *m_saveProject; + + void buildProjectMenu(); + }; } // namespace Collett diff --git a/src/gui/storytree.cpp b/src/gui/storytree.cpp index 755a307..ced05c0 100644 --- a/src/gui/storytree.cpp +++ b/src/gui/storytree.cpp @@ -30,7 +30,6 @@ namespace Collett { GuiStoryTree::GuiStoryTree(QWidget *parent) : QTreeView(parent) { - this->setModel(new CollettStoryModel("", this)); } } // namespace Collett diff --git a/src/gui/storytree.h b/src/gui/storytree.h index ece84d7..712110d 100644 --- a/src/gui/storytree.h +++ b/src/gui/storytree.h @@ -19,8 +19,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef GUISTORYTREE_H -#define GUISTORYTREE_H +#ifndef GUI_STORYTREE_H +#define GUI_STORYTREE_H #include #include @@ -38,4 +38,4 @@ class GuiStoryTree : public QTreeView }; } // namespace Collett -#endif // GUISTORYTREE_H +#endif // GUI_STORYTREE_H diff --git a/src/guimain.cpp b/src/guimain.cpp index 508efb9..3edbc32 100644 --- a/src/guimain.cpp +++ b/src/guimain.cpp @@ -20,6 +20,7 @@ along with this program. If not, see . */ #include "guimain.h" +#include "data.h" #include "settings.h" #include "maintoolbar.h" #include "treetoolbar.h" @@ -34,6 +35,9 @@ namespace Collett { GuiMain::GuiMain(QWidget *parent) : QMainWindow(parent) { + // Create Main Data Object + m_data = CollettData::instance(); + // Collett Widgets m_mainToolBar = new GuiMainToolBar(this); m_treeToolBar = new GuiTreeToolBar(this); @@ -66,6 +70,25 @@ GuiMain::GuiMain(QWidget *parent) : QMainWindow(parent) { return; } +/* + Project Functions + ================= +*/ + +void GuiMain::openProject(const QString &path) { + m_data->openProject(path); + m_storyTree->setModel(m_data->storyModel()); + m_mainToolBar->setProjectName(m_data->project()->projectName()); +}; + +bool GuiMain::saveProject() { + return m_data->saveProject(); +} + +bool GuiMain::closeProject() { + return true; +}; + /* GUI Functions ============= @@ -73,6 +96,8 @@ GuiMain::GuiMain(QWidget *parent) : QMainWindow(parent) { bool GuiMain::closeMain() { + m_data->saveProject(); + // Save Settings CollettSettings *mainConf = CollettSettings::instance(); if (!this->isFullScreen()) { diff --git a/src/guimain.h b/src/guimain.h index 4d77cff..4f8b4ee 100644 --- a/src/guimain.h +++ b/src/guimain.h @@ -23,6 +23,7 @@ along with this program. If not, see . #define GUIMAIN_H #include "collett.h" +#include "data.h" #include "maintoolbar.h" #include "treetoolbar.h" #include "statusbar.h" @@ -33,6 +34,7 @@ along with this program. If not, see . #include #include #include +#include namespace Collett { @@ -44,9 +46,14 @@ class GuiMain : public QMainWindow GuiMain(QWidget *parent=nullptr); ~GuiMain() {}; + void openProject(const QString &path); + bool saveProject(); + bool closeProject(); + bool closeMain(); private: + CollettData *m_data; // Collett Widgets GuiMainToolBar *m_mainToolBar; diff --git a/src/main.cpp b/src/main.cpp index a91e110..10a14e5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -82,9 +82,9 @@ int main(int argc, char *argv[]) { Collett::GuiMain mainGUI; mainGUI.show(); - // if (parser.isSet(openFlag)) { - // mainGUI.openProject(parser.value(openFlag)); - // } + if (parser.isSet(openFlag)) { + mainGUI.openProject(parser.value(openFlag)); + } return app.exec(); } diff --git a/src/project/project.cpp b/src/project/project.cpp new file mode 100644 index 0000000..90383c9 --- /dev/null +++ b/src/project/project.cpp @@ -0,0 +1,344 @@ +/* +Collett – Project Class +======================= + +This file is a part of Collett +Copyright 2020–2021, Veronica Berglyd Olsen + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "collett.h" +#include "project.h" +#include "storymodel.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Collett { + +/** + * Project Private Class + * ===================== + */ + +class ProjectPrivate +{ +public: + ProjectPrivate() {}; + ~ProjectPrivate() {}; + + // Project + QString m_projectName = "New Project"; + QString m_bookTitle = "New Project"; + + // Meta + QDateTime m_createdTime = QDateTime::currentDateTime(); +}; + +/** + * Project Class Constructor/Destructor + * ==================================== + */ + +Project::Project(const QString &path) + : d_ptr(new ProjectPrivate()) +{ + Q_D(Project); + + this->clearError(); + m_hasProject = false; + m_pathValid = false; + + m_storyModel = new StoryModel(this); + + QFileInfo fObj(path); + if (!fObj.exists()) { + setError(tr("Project not found at: %1").arg(path)); + return; + } + + // If the path is a file, go one level up + QDir projDir = QDir(path).absolutePath(); + if (fObj.isFile()) { + projDir = fObj.dir().absolutePath(); + } + + QDir projFile = projDir.filePath(COL_PROJECT_FILE_NAME); + if (!QFileInfo::exists(projFile.path())) { + setError(tr("Project not found at: %1").arg(projFile.path())); + return; + } + + // Set the path variables + m_projectPath = projDir; + m_projectFile = projFile; + m_contentPath = QDir(m_projectPath.path() + "/content"); + m_dataPath = QDir(m_projectPath.path() + "/data"); + + // Verify that the needed project folders exist + if (!m_contentPath.exists()) { + if (m_projectPath.mkdir("content")) { + qDebug() << "Created folder:" << m_contentPath.path(); + } else { + setError(tr("Could not create folder: %1").arg(m_contentPath.path())); + return; + } + } + if (!m_dataPath.exists()) { + if (m_projectPath.mkdir("data")) { + qDebug() << "Created folder:" << m_dataPath.path(); + } else { + setError(tr("Could not create folder: %1").arg(m_dataPath.path())); + return; + } + } + + m_pathValid = true; + + qDebug() << "Project Path:" << m_projectPath.path(); + qDebug() << "Project File:" << m_projectFile.path(); +} + +Project::~Project() { + delete m_storyModel; +} + +/** + * Class Methods + * ============= + */ + +bool Project::openProject() { + + qInfo() << "Loading Project:" << m_projectPath.path(); + if (!m_pathValid) { + qWarning() << "Cannot load project from this path"; + return false; + } + + bool mainFile = loadProjectFile(); + + m_hasProject = mainFile; + + return m_hasProject; +} + +bool Project::saveProject() { + + qInfo() << "Saving Project:" << m_projectPath.path(); + if (!m_hasProject) { + qWarning() << "No project open, nothing to save"; + return false; + } + + bool mainFile = saveProjectFile(); + bool settFile = saveSettingsFile(); + bool storyFile = saveStoryFile(); + + return mainFile & settFile & storyFile; +} + +/** + * Project Getters + * =============== + */ + +QString Project::projectName() const { + Q_D(const Project); + return d->m_projectName; +} + +QString Project::bookTitle() const { + Q_D(const Project); + return d->m_bookTitle; +} + +bool Project::hasProject() const { + return m_hasProject; +} + +StoryModel *Project::storyModel() { + return m_storyModel; +} + +/** + * Project Setters + * =============== + */ + +void Project::setProjectName(const QString &name) { + Q_D(Project); + d->m_projectName = name.simplified(); +} + +void Project::setBookTitle(const QString &title) { + Q_D(Project); + d->m_bookTitle = title.simplified(); +} + +/** + * Project File + * ============ + * Load and save functions for the project.collett file. + */ + +bool Project::loadProjectFile() { + + bool hasCol = false; + bool hasPro = false; + + QFile prjFile(m_projectFile.path()); + if (prjFile.open(QIODevice::ReadOnly)) { + QString line; + QTextStream inStream(&prjFile); + while (!inStream.atEnd()) { + line = inStream.readLine(); + if (line.startsWith("Collett ")) { + m_collettVersion = line.remove(0, 8); + hasCol = true; + } else if (line.startsWith("Project ")) { + m_projectVersion = line.remove(0, 8); + hasPro = true; + } + } + prjFile.close(); + qInfo() << "File Collett Version:" << m_collettVersion; + qInfo() << "File Project Version:" << m_projectVersion; + return hasCol & hasPro; + } else { + return false; + } +} + +bool Project::saveProjectFile() { + + QByteArray colLine = "Collett " + QByteArray(COL_VERSION_STR); + QByteArray proLine = "Project 0.1"; + + QFile prjFile(m_projectFile.path()); + if (prjFile.open(QIODevice::WriteOnly)) { + QTextStream outData(&prjFile); + outData << "Collett " << QString(COL_VERSION_STR) << Qt::endl; + outData << "Project 0.1" << Qt::endl; + prjFile.close(); + return true; + } else { + return false; + } +} + +/** + * Settings FIle + * ============= + * Load and save functions for the data/project.json file. + * + * This file contains all the meta data and options for the Collett project, + * except for the project content itself (the documents). + */ + +bool Project::loadSettingsFile() { + return true; +} + +bool Project::saveSettingsFile() { + Q_D(Project); + + QJsonObject jData, jMeta, jProject, jSettings; + + jMeta["created"] = d->m_createdTime.toString(Qt::ISODate); + jMeta["updated"] = QDateTime::currentDateTime().toString(Qt::ISODate); + + jProject["bookTitle"] = d->m_bookTitle; + jProject["projectName"] = d->m_projectName; + + jData["meta"] = jMeta; + jData["project"] = jProject; + jData["settings"] = jSettings; + + QFile file(m_dataPath.filePath(COL_SETTINGS_FILE_NAME)); + if (!file.open(QIODevice::WriteOnly)) { + qWarning() << "Could not open settings file"; + return false; + } + + QJsonDocument doc(jData); + file.write(doc.toJson()); + file.close(); + + return true; +} + +/** + * Story File + * ========== + * Load and save functions for the data/story.json file. + * + * This file contains the structure of StoryItems contained in the StoryModel. + * The structure is contained as child items under a single root item, and is + * saved to a QJsonDocument by recursively calling the StoryItem->toJsonObject + * function. +`*/ + +bool Project::loadStoryFile() { + return true; +} + +bool Project::saveStoryFile() { + + QFile file(m_dataPath.filePath(COL_STORY_FILE_NAME)); + if (!file.open(QIODevice::WriteOnly)) { + qWarning() << "Could not open story file"; + return false; + } + + QJsonDocument doc(m_storyModel->toJsonObject()); + file.write(doc.toJson()); + file.close(); + + return true; +} + +/** + * Error Handling + * ============== + */ + +bool Project::hasError() const { + return m_hasError; +} + +QString Project::lastError() const { + return m_lastError; +} + +void Project::clearError() { + m_hasError = false; + m_lastError = ""; +} + +void Project::setError(const QString &error) { + m_hasError = true; + m_lastError = error; + qCritical() << error; +} + +} // namespace Collett diff --git a/src/project/project.h b/src/project/project.h new file mode 100644 index 0000000..48120d6 --- /dev/null +++ b/src/project/project.h @@ -0,0 +1,100 @@ +/* +Collett – Project Class +======================= + +This file is a part of Collett +Copyright 2020–2021, Veronica Berglyd Olsen + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef COLLETT_PROJECT_H +#define COLLETT_PROJECT_H + +#include "collett.h" +#include "storymodel.h" + +#include +#include +#include + +namespace Collett { + +class ProjectPrivate; +class Project : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(Project) + +public: + Project(const QString &path); + ~Project(); + +private: + QScopedPointer d_ptr; + +public: + // Class Methods + bool openProject(); + bool saveProject(); + + // Getters + QString projectName() const; + QString bookTitle() const; + bool hasProject() const; + bool hasError() const; + StoryModel *storyModel(); + + // Setters + void setProjectName(const QString &name); + void setBookTitle(const QString &title); + + // Error Handling + void clearError(); + QString lastError() const; + +private: + bool m_hasProject; + bool m_hasError; + QString m_lastError; + + // Project Paths + QDir m_projectPath; + QDir m_projectFile; + QDir m_contentPath; + QDir m_dataPath; + bool m_pathValid; + + // Project Meta + QString m_collettVersion = ""; + QString m_projectVersion = ""; + + // Content + StoryModel *m_storyModel; + + // File Load & Save + bool loadProjectFile(); + bool saveProjectFile(); + bool loadSettingsFile(); + bool saveSettingsFile(); + bool loadStoryFile(); + bool saveStoryFile(); + + // Error Handling + void setError(const QString &error); + +}; +} // namespace Collett + +#endif // COLLETT_PROJECT_H diff --git a/src/project/storyitem.cpp b/src/project/storyitem.cpp index 1ae1ec6..38bd3d2 100644 --- a/src/project/storyitem.cpp +++ b/src/project/storyitem.cpp @@ -19,57 +19,141 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "collett.h" #include "storyitem.h" +#include #include #include +#include +#include +#include namespace Collett { -CollettStoryItem::CollettStoryItem(const QVector &data, CollettStoryItem *parent) - : m_itemData(data), m_parentItem(parent) -{} +StoryItem::StoryItem(const QString &label, StoryItem *parent) + : m_parentItem(parent) +{ + m_handle = QUuid::createUuid(); + m_label = label; + m_wCount = 0; +} -CollettStoryItem::~CollettStoryItem() { +StoryItem::~StoryItem() { qDeleteAll(m_childItems); } -void CollettStoryItem::appendChild(CollettStoryItem *item) { +/* + Item Structure + ============== +*/ + +void StoryItem::appendChild(StoryItem *item) { m_childItems.append(item); } -CollettStoryItem *CollettStoryItem::child(int row) { +QJsonObject StoryItem::toJsonObject() { + + QJsonObject item; + QJsonArray children; + + for (qsizetype i=0; itoJsonObject()); + } + + if (!m_parentItem) { + item["handle"] = "ROOT"; + item["xItems"] = children; + } else { + item["handle"] = m_handle.toString(QUuid::WithoutBraces); + item["label"] = m_label; + item["order"] = row(); + item["wCount"] = m_wCount; + if (children.size() > 0) { + item["xItems"] = children; + } + } + + return item; +} + +/* + Setters + ======= +*/ + +void StoryItem::setLabel(const QString &label) { + m_label = label; +} + + +void StoryItem::setWordCount(int count) { + m_wCount = count > 0 ? count : 0; +} + +/* + Getters + ======= +*/ + +int StoryItem::wordCount() { + return m_wCount; +} + +int StoryItem::childWordCounts() { + int tCount = 0; + for (StoryItem* child : m_childItems) { + tCount += child->childWordCounts(); + } + return tCount; +} + +/* + Model Access + ============ +*/ + +StoryItem *StoryItem::child(int row) { if (row < 0 || row >= m_childItems.size()) { return nullptr; + } else { + return m_childItems.at(row); } - return m_childItems.at(row); } -int CollettStoryItem::childCount() const { +int StoryItem::childCount() const { return m_childItems.count(); } -int CollettStoryItem::row() const { +int StoryItem::row() const { if (m_parentItem) { - return m_parentItem->m_childItems.indexOf(const_cast(this)); + return m_parentItem->m_childItems.indexOf(const_cast(this)); } else { return 0; } } -int CollettStoryItem::columnCount() const { - return m_itemData.count(); +int StoryItem::columnCount() const { + return COL_STORY_TREE_COL_COUNT; } -QVariant CollettStoryItem::data(int column) const { - if (column < 0 || column >= m_itemData.size()) { +QVariant StoryItem::data(int column) const { + switch (column) { + case 0: + return QVariant(m_label); + break; + + case 1: + return QVariant(m_wCount); + break; + + default: return QVariant(); - } else { - return m_itemData.at(column); + break; } } -CollettStoryItem *CollettStoryItem::parentItem() { +StoryItem *StoryItem::parentItem() { return m_parentItem; } diff --git a/src/project/storyitem.h b/src/project/storyitem.h index 9879366..9dca57d 100644 --- a/src/project/storyitem.h +++ b/src/project/storyitem.h @@ -19,35 +19,52 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef COLLETTSTORYITEM_H -#define COLLETTSTORYITEM_H +#ifndef COLLETT_STORYITEM_H +#define COLLETT_STORYITEM_H +#include #include #include +#include namespace Collett { -class CollettStoryItem +class StoryItem { public: - explicit CollettStoryItem(const QVector &data, CollettStoryItem *parentItem=nullptr); - ~CollettStoryItem(); + explicit StoryItem(const QString &label, StoryItem *parentItem=nullptr); + ~StoryItem(); - void appendChild(CollettStoryItem *child); + // Structure + void appendChild(StoryItem *child); + QJsonObject toJsonObject(); - CollettStoryItem *child(int row); + // Setters + void setLabel(const QString &label); + void setWordCount(int count); + + // Getters + int wordCount(); + int childWordCounts(); + + // Model Access + int row() const; int childCount() const; int columnCount() const; QVariant data(int column) const; - int row() const; - CollettStoryItem *parentItem(); + StoryItem *child(int row); + StoryItem *parentItem(); private: - QVector m_childItems; - QVector m_itemData; - CollettStoryItem *m_parentItem; + QVector m_childItems; + StoryItem *m_parentItem; + + // Values + QUuid m_handle; + QString m_label; + int m_wCount; }; } // namespace Collett -#endif // COLLETTSTORYITEM_H +#endif // COLLETT_STORYITEM_H diff --git a/src/project/storymodel.cpp b/src/project/storymodel.cpp index 1210235..da408af 100644 --- a/src/project/storymodel.cpp +++ b/src/project/storymodel.cpp @@ -23,43 +23,60 @@ along with this program. If not, see . #include "storyitem.h" #include +#include +#include +#include #include namespace Collett { /* - CollettStoryModel - ----------------- + StoryModel + ---------- The data model of the project's stroy content. Example: https://doc.qt.io/qt-5/qtwidgets-itemviews-simpletreemodel-example.html */ -CollettStoryModel::CollettStoryModel(const QString &data, QObject *parent) +StoryModel::StoryModel(QObject *parent) : QAbstractItemModel(parent) { - rootItem = new CollettStoryItem({tr("Title"), tr("Words")}); - rootItem->appendChild(new CollettStoryItem({"Title Page", 100}, rootItem)); - rootItem->appendChild(new CollettStoryItem({"Chapter 1", 150}, rootItem)); + m_rootItem = new StoryItem(""); + m_rootItem->appendChild(new StoryItem("Title Page", m_rootItem)); + m_rootItem->appendChild(new StoryItem("Chapter 1", m_rootItem)); } -CollettStoryModel::~CollettStoryModel() { - delete rootItem; +StoryModel::~StoryModel() { + delete m_rootItem; } -QModelIndex CollettStoryModel::index(int row, int column, const QModelIndex &parent) const { +/* + Class Methods + ============= +*/ + +QJsonObject StoryModel::toJsonObject() { + return m_rootItem->toJsonObject(); +} + +/* + Model Access + ============ +*/ + +QModelIndex StoryModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) { return QModelIndex(); } - CollettStoryItem *parentItem; + StoryItem *parentItem; if (!parent.isValid()) { - parentItem = rootItem; + parentItem = m_rootItem; } else { - parentItem = static_cast(parent.internalPointer()); + parentItem = static_cast(parent.internalPointer()); } - CollettStoryItem *childItem = parentItem->child(row); + StoryItem *childItem = parentItem->child(row); if (childItem) { return createIndex(row, column, childItem); } else { @@ -67,47 +84,47 @@ QModelIndex CollettStoryModel::index(int row, int column, const QModelIndex &par } } -QModelIndex CollettStoryModel::parent(const QModelIndex &index) const { +QModelIndex StoryModel::parent(const QModelIndex &index) const { if (!index.isValid()) { return QModelIndex(); } - CollettStoryItem *childItem = static_cast(index.internalPointer()); - CollettStoryItem *parentItem = childItem->parentItem(); + StoryItem *childItem = static_cast(index.internalPointer()); + StoryItem *parentItem = childItem->parentItem(); - if (parentItem == rootItem) { + if (parentItem == m_rootItem) { return QModelIndex(); } else { return createIndex(parentItem->row(), 0, parentItem); } } -int CollettStoryModel::rowCount(const QModelIndex &parent) const { +int StoryModel::rowCount(const QModelIndex &parent) const { - CollettStoryItem *parentItem; + StoryItem *parentItem; if (parent.column() > 0) { return 0; } if (!parent.isValid()) { - parentItem = rootItem; + parentItem = m_rootItem; } else { - parentItem = static_cast(parent.internalPointer()); + parentItem = static_cast(parent.internalPointer()); } return parentItem->childCount(); } -int CollettStoryModel::columnCount(const QModelIndex &parent) const { +int StoryModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) { - return static_cast(parent.internalPointer())->columnCount(); + return static_cast(parent.internalPointer())->columnCount(); } else { - return rootItem->columnCount(); + return m_rootItem->columnCount(); } } -QVariant CollettStoryModel::data(const QModelIndex &index, int role) const { +QVariant StoryModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); @@ -116,12 +133,12 @@ QVariant CollettStoryModel::data(const QModelIndex &index, int role) const { return QVariant(); } - CollettStoryItem *item = static_cast(index.internalPointer()); + StoryItem *item = static_cast(index.internalPointer()); return item->data(index.column()); } -Qt::ItemFlags CollettStoryModel::flags(const QModelIndex &index) const { +Qt::ItemFlags StoryModel::flags(const QModelIndex &index) const { if (!index.isValid()) { return Qt::NoItemFlags; } else { @@ -129,10 +146,22 @@ Qt::ItemFlags CollettStoryModel::flags(const QModelIndex &index) const { } } -QVariant CollettStoryModel::headerData(int section, Qt::Orientation orientation, int role) const { +QVariant StoryModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { - return rootItem->data(section); + switch (section) { + case 0: + return QVariant(tr("Label")); + break; + + case 1: + return QVariant(tr("Words")); + break; + + default: + return QVariant(); + break; + } } else { return QVariant(); } diff --git a/src/project/storymodel.h b/src/project/storymodel.h index 81f6f03..57f8b51 100644 --- a/src/project/storymodel.h +++ b/src/project/storymodel.h @@ -19,26 +19,31 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef COLLETTSTORYMODEL_H -#define COLLETTSTORYMODEL_H +#ifndef COLLETT_STORYMODEL_H +#define COLLETT_STORYMODEL_H #include "storyitem.h" #include #include -#include +#include #include +#include namespace Collett { -class CollettStoryModel : public QAbstractItemModel +class StoryModel : public QAbstractItemModel { Q_OBJECT public: - explicit CollettStoryModel(const QString &data, QObject *parent=nullptr); - ~CollettStoryModel(); + explicit StoryModel(QObject *parent=nullptr); + ~StoryModel(); + + // Class Methods + QJsonObject toJsonObject(); + // Model Access QVariant data(const QModelIndex &index, int role) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; @@ -48,9 +53,9 @@ class CollettStoryModel : public QAbstractItemModel int columnCount(const QModelIndex &parent = QModelIndex()) const override; private: - CollettStoryItem *rootItem; + StoryItem *m_rootItem; }; } // namespace Collett -#endif // COLLETTSTORYMODEL_H +#endif // COLLETT_STORYMODEL_H