From beecb5b5f7dd650fa5036c850b2f16b25313db6b Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Fri, 18 Feb 2022 23:26:24 +0100
Subject: [PATCH] Add tree view for project notes (#41)
* Convert the story tree into a stack of item trees
* Rename StoryTree to ItemTree
* Extend item tre and model to add folders and notes
* Restrict which items can hold documents
* Let doc editor keep item instead of handle
* Rename item type Folder to Group
* Implement close project and cleanup functionality
---
CMakeLists.txt | 4 +-
i18n/collett_en_US.ts | 201 ++++++++++--------
i18n/collett_nb_NO.ts | 201 ++++++++++--------
.../81def5a0-62c6-48b8-9bf3-cb031a09e2bb.json | 19 ++
...c2290a95-ca41-4181-89f2-18cb610ab716.json} | 0
sample/project/characters.json | 17 ++
sample/project/project.json | 6 +-
src/core/data.cpp | 8 -
src/core/data.h | 1 -
src/editor/doceditor.cpp | 27 ++-
src/editor/doceditor.h | 15 +-
src/gui/{storytree.cpp => itemtree.cpp} | 104 +++++----
src/gui/{storytree.h => itemtree.h} | 18 +-
...ytreedelegate.cpp => itemtreedelegate.cpp} | 12 +-
...storytreedelegate.h => itemtreedelegate.h} | 16 +-
src/gui/maintoolbar.cpp | 8 +-
src/gui/maintoolbar.h | 1 +
src/gui/treetoolbar.cpp | 69 +++++-
src/gui/treetoolbar.h | 29 ++-
src/guimain.cpp | 115 +++++++---
src/guimain.h | 24 ++-
src/project/item.cpp | 40 +++-
src/project/item.h | 8 +-
src/project/itemmodel.cpp | 79 +++++--
src/project/itemmodel.h | 8 +-
src/project/project.cpp | 8 +-
src/project/project.h | 3 +
27 files changed, 701 insertions(+), 340 deletions(-)
create mode 100644 sample/content/81def5a0-62c6-48b8-9bf3-cb031a09e2bb.json
rename sample/content/{e709ba3f-3141-4b4b-95df-4a8d3e91a8ba.json => c2290a95-ca41-4181-89f2-18cb610ab716.json} (100%)
rename src/gui/{storytree.cpp => itemtree.cpp} (58%)
rename src/gui/{storytree.h => itemtree.h} (81%)
rename src/gui/{storytreedelegate.cpp => itemtreedelegate.cpp} (85%)
rename src/gui/{storytreedelegate.h => itemtreedelegate.h} (79%)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 688c584..b421b83 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -89,10 +89,10 @@ list(APPEND SRC_FILES
src/editor/doceditor
src/editor/edittoolbar
src/editor/textedit
+ src/gui/itemtree
+ src/gui/itemtreedelegate
src/gui/maintoolbar
src/gui/statusbar
- src/gui/storytree
- src/gui/storytreedelegate
src/gui/treetoolbar
src/project/document
src/project/item
diff --git a/i18n/collett_en_US.ts b/i18n/collett_en_US.ts
index 82c38db..f85ab41 100644
--- a/i18n/collett_en_US.ts
+++ b/i18n/collett_en_US.ts
@@ -110,150 +110,183 @@
- Collett::GuiMain
+ Collett::GuiItemTree
-
-
+
+
-
-
- Collett::GuiMainToolBar
-
-
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
- Collett::GuiStoryTree
+ Collett::GuiMain
-
-
+
+
-
-
-
-
-
-
+
+
-
-
-
-
-
-
+
+
+
+
+ Collett::GuiMainToolBar
-
-
-
-
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Collett::GuiTreeToolBar
-
-
+
+
-
+
@@ -266,37 +299,37 @@
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
@@ -304,32 +337,32 @@
Collett::ItemModel
-
+
-
+
-
+
-
+
-
+
-
+
@@ -337,7 +370,7 @@
Collett::Project
-
+
diff --git a/i18n/collett_nb_NO.ts b/i18n/collett_nb_NO.ts
index b840889..654c3e3 100644
--- a/i18n/collett_nb_NO.ts
+++ b/i18n/collett_nb_NO.ts
@@ -110,150 +110,183 @@
- Collett::GuiMain
+ Collett::GuiItemTree
-
-
+
+
-
-
- Collett::GuiMainToolBar
-
-
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
- Collett::GuiStoryTree
+ Collett::GuiMain
-
-
+
+
-
-
-
-
-
-
+
+
-
-
-
-
-
-
+
+
+
+
+ Collett::GuiMainToolBar
-
-
-
-
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Collett::GuiTreeToolBar
-
-
+
+
-
+
@@ -266,37 +299,37 @@
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
@@ -304,32 +337,32 @@
Collett::ItemModel
-
+
-
+
-
+
-
+
-
+
-
+
@@ -337,7 +370,7 @@
Collett::Project
-
+
diff --git a/sample/content/81def5a0-62c6-48b8-9bf3-cb031a09e2bb.json b/sample/content/81def5a0-62c6-48b8-9bf3-cb031a09e2bb.json
new file mode 100644
index 0000000..8432d70
--- /dev/null
+++ b/sample/content/81def5a0-62c6-48b8-9bf3-cb031a09e2bb.json
@@ -0,0 +1,19 @@
+{
+ "c:format": "document",
+ "m:created": "2022-02-18T21:03:13",
+ "m:updated": "2022-02-18T22:20:47",
+ "x:content": [
+ {
+ "u:fmt": "h1:al",
+ "u:txt": "t:b|Jane Doe"
+ },
+ {
+ "u:fmt": "p:al",
+ "u:txt": "t|Jane Doe is not just anybody, she's Jane Doe, the mysterious woman who no one knows the real name of."
+ },
+ {
+ "u:fmt": "p:al:ti",
+ "u:txt": "t|She's not gonna tell you her real name, so there is no point asking. No point being a super hero if everyone knows your name and where you live so they can call you each time the cat goes looking for a treat at the neighbours'!"
+ }
+ ]
+}
diff --git a/sample/content/e709ba3f-3141-4b4b-95df-4a8d3e91a8ba.json b/sample/content/c2290a95-ca41-4181-89f2-18cb610ab716.json
similarity index 100%
rename from sample/content/e709ba3f-3141-4b4b-95df-4a8d3e91a8ba.json
rename to sample/content/c2290a95-ca41-4181-89f2-18cb610ab716.json
diff --git a/sample/project/characters.json b/sample/project/characters.json
index b959eff..bd8d0ef 100644
--- a/sample/project/characters.json
+++ b/sample/project/characters.json
@@ -4,5 +4,22 @@
"u:name": "Characters",
"u:type": "ROOT",
"x:items": [
+ {
+ "m:expanded": true,
+ "m:handle": "e0428917-b42f-49ac-a481-3c11bc0dc506",
+ "m:order": 0,
+ "m:words": 0,
+ "u:name": "Main Characters",
+ "u:type": "GROUP",
+ "x:items": [
+ {
+ "m:handle": "81def5a0-62c6-48b8-9bf3-cb031a09e2bb",
+ "m:order": 0,
+ "m:words": 0,
+ "u:name": "Jane Doe",
+ "u:type": "NOTE"
+ }
+ ]
+ }
]
}
diff --git a/sample/project/project.json b/sample/project/project.json
index 1a0a559..9fec81b 100644
--- a/sample/project/project.json
+++ b/sample/project/project.json
@@ -2,13 +2,13 @@
"c:format": "Collett Project",
"c:meta": {
"m:created": "2021-12-14T22:24:25",
- "m:updated": "2022-02-14T20:07:35"
+ "m:updated": "2022-02-18T22:20:53"
},
"c:project": {
"s:last-doc-main": "7e5a1a98-d1a3-44a1-ab4e-2b5d21d92201",
"u:models": [
- "characters",
- "story"
+ "story",
+ "characters"
],
"u:project-name": "Sample Project"
},
diff --git a/src/core/data.cpp b/src/core/data.cpp
index 642b15a..df81df9 100644
--- a/src/core/data.cpp
+++ b/src/core/data.cpp
@@ -101,12 +101,4 @@ Project *CollettData::project() {
}
}
-ItemModel *CollettData::storyModel() {
- if (hasProject()) {
- return m_project.data()->model("story");
- } else {
- return nullptr;
- }
-}
-
} // namespace Collett
diff --git a/src/core/data.h b/src/core/data.h
index 71824d4..3580cc3 100644
--- a/src/core/data.h
+++ b/src/core/data.h
@@ -53,7 +53,6 @@ class CollettData : public QObject
bool hasProject() const;
Project *project();
- ItemModel *storyModel();
private:
static CollettData *staticInstance;
diff --git a/src/editor/doceditor.cpp b/src/editor/doceditor.cpp
index 01341b9..f757cca 100644
--- a/src/editor/doceditor.cpp
+++ b/src/editor/doceditor.cpp
@@ -19,11 +19,12 @@
** along with this program. If not, see .
*/
+#include "item.h"
#include "collett.h"
+#include "document.h"
#include "settings.h"
-#include "doceditor.h"
#include "textedit.h"
-#include "document.h"
+#include "doceditor.h"
#include "edittoolbar.h"
#include
@@ -43,7 +44,7 @@ GuiDocEditor::GuiDocEditor(QWidget *parent)
: QWidget(parent)
{
m_data = CollettData::instance();
- m_docUuid = QUuid();
+ m_item = nullptr;
m_document = nullptr;
m_textArea = new GuiTextEdit(this);
@@ -124,15 +125,15 @@ GuiDocEditor::GuiDocEditor(QWidget *parent)
* ============
*/
-bool GuiDocEditor::openDocument(const QUuid &uuid) {
+bool GuiDocEditor::openDocument(Item *item) {
- if (!m_data->hasProject()) {
- qWarning() << "No project loaded";
+ if (!m_data->hasProject() || !item) {
+ qWarning() << "Nothing to load";
return false;
}
- m_docUuid = uuid;
- m_document = m_data->project()->document(uuid);
+ m_item = item;
+ m_document = m_data->project()->document(m_item->handle());
m_textArea->setJsonContent(m_document->content());
m_autoSave->start();
@@ -167,8 +168,8 @@ void GuiDocEditor::closeDocument() {
m_autoSave->stop();
m_textArea->setReadOnly(true);
m_textArea->clear();
- m_docUuid = QUuid();
m_document = nullptr;
+ m_item = nullptr;
}
/**
@@ -177,11 +178,15 @@ void GuiDocEditor::closeDocument() {
*/
QUuid GuiDocEditor::currentDocument() const {
- return m_docUuid;
+ if (m_item) {
+ return m_item->handle();
+ } else {
+ return QUuid();
+ }
}
bool GuiDocEditor::hasDocument() const {
- return m_document != nullptr && !m_docUuid.isNull();
+ return m_document != nullptr && m_item != nullptr;
}
/**!
diff --git a/src/editor/doceditor.h b/src/editor/doceditor.h
index c3daea7..cd250fe 100644
--- a/src/editor/doceditor.h
+++ b/src/editor/doceditor.h
@@ -22,10 +22,11 @@
#ifndef GUI_DOCEDITOR_H
#define GUI_DOCEDITOR_H
-#include "collett.h"
#include "data.h"
-#include "textedit.h"
+#include "item.h"
+#include "collett.h"
#include "document.h"
+#include "textedit.h"
#include "edittoolbar.h"
#include
@@ -47,7 +48,7 @@ class GuiDocEditor : public QWidget
// Data Methods
- bool openDocument(const QUuid &uuid);
+ bool openDocument(Item *item);
bool saveDocument();
void closeDocument();
@@ -61,13 +62,13 @@ class GuiDocEditor : public QWidget
void popMessage(const Collett::Severity type, const QString &message);
private:
- GuiTextEdit *m_textArea;
+ GuiTextEdit *m_textArea;
GuiEditToolBar *m_editToolBar;
- QTimer *m_autoSave;
+ QTimer *m_autoSave;
CollettData *m_data;
- Document *m_document;
- QUuid m_docUuid;
+ Item *m_item;
+ Document *m_document;
private slots:
void editorCharFormatChanged(const QTextCharFormat &fmt);
diff --git a/src/gui/storytree.cpp b/src/gui/itemtree.cpp
similarity index 58%
rename from src/gui/storytree.cpp
rename to src/gui/itemtree.cpp
index 6760380..1b019a7 100644
--- a/src/gui/storytree.cpp
+++ b/src/gui/itemtree.cpp
@@ -1,6 +1,6 @@
/*
-** Collett – GUI Story Tree Class
-** ==============================
+** Collett – GUI Item Tree Class
+** =============================
**
** This file is a part of Collett
** Copyright 2020–2022, Veronica Berglyd Olsen
@@ -21,9 +21,9 @@
#include "collett.h"
#include "item.h"
-#include "storytree.h"
+#include "itemtree.h"
#include "itemmodel.h"
-#include "storytreedelegate.h"
+#include "itemtreedelegate.h"
#include
#include
@@ -47,10 +47,10 @@ namespace Collett {
*
* @param parent the parent widget.
*/
-GuiStoryTree::GuiStoryTree(QWidget *parent)
+GuiItemTree::GuiItemTree(QWidget *parent)
: QTreeView(parent)
{
- this->setItemDelegate(new GuiStoryTreeDelegate(this));
+ this->setItemDelegate(new GuiItemTreeDelegate(this));
this->setHeaderHidden(true);
this->setAlternatingRowColors(true);
this->setExpandsOnDoubleClick(false);
@@ -70,7 +70,7 @@ GuiStoryTree::GuiStoryTree(QWidget *parent)
* =============
*/
-void GuiStoryTree::setTreeModel(ItemModel *model) {
+void GuiItemTree::setTreeModel(ItemModel *model) {
m_model = model;
this->setModel(m_model);
@@ -90,7 +90,7 @@ void GuiStoryTree::setTreeModel(ItemModel *model) {
* =============
*/
-QModelIndex GuiStoryTree::firstSelectedIndex() {
+QModelIndex GuiItemTree::firstSelectedIndex() {
QModelIndexList selections = this->selectedIndexes();
if (!selections.isEmpty()) {
return selections.at(0);
@@ -99,7 +99,7 @@ QModelIndex GuiStoryTree::firstSelectedIndex() {
}
}
-void GuiStoryTree::getAllChildren(const QModelIndex &index, QModelIndexList &children) {
+void GuiItemTree::getAllChildren(const QModelIndex &index, QModelIndexList &children) {
children.append(index);
for (int i = 0; i < model()->rowCount(index); ++i) {
getAllChildren(model()->index(i, 0, index), children);
@@ -119,14 +119,16 @@ void GuiStoryTree::getAllChildren(const QModelIndex &index, QModelIndexList &chi
*
* @param pos the position of the cursor.
*/
-void GuiStoryTree::doOpenContextMenu(const QPoint &pos) {
+void GuiItemTree::doOpenContextMenu(const QPoint &pos) {
QModelIndex index = this->indexAt(pos);
Item *item;
+ bool root = false;
if (index.isValid()) {
item = static_cast- (index.internalPointer());
} else {
item = m_model->rootItem();
+ root = true;
}
if (!item) {
return;
@@ -139,8 +141,8 @@ void GuiStoryTree::doOpenContextMenu(const QPoint &pos) {
// Item Options
// ------------
- contextMenu.addAction(m_editItem);
- contextMenu.addSeparator();
+ // contextMenu.addAction(m_editItem);
+ // contextMenu.addSeparator();
// New Items
// ---------
@@ -148,13 +150,13 @@ void GuiStoryTree::doOpenContextMenu(const QPoint &pos) {
QMenu *scMenu = new QMenu(tr("Add Scene"));
if (item->allowedChild(Item::Scene)) {
QAction *inAction = scMenu->addAction(tr("Inside"));
- connect(inAction, &QAction::triggered, [this, item]{doAddChild(item, Item::Scene, ItemModel::Inside);});
+ connect(inAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Scene, ItemModel::Inside);});
}
if (item->allowedSibling(Item::Scene)) {
QAction *bfAction = scMenu->addAction(tr("Before"));
- connect(bfAction, &QAction::triggered, [this, item]{doAddChild(item, Item::Scene, ItemModel::Before);});
+ connect(bfAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Scene, ItemModel::Before);});
QAction *afAction = scMenu->addAction(tr("After"));
- connect(afAction, &QAction::triggered, [this, item]{doAddChild(item, Item::Scene, ItemModel::After);});
+ connect(afAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Scene, ItemModel::After);});
}
if (!scMenu->isEmpty()) {
contextMenu.addMenu(scMenu);
@@ -163,13 +165,13 @@ void GuiStoryTree::doOpenContextMenu(const QPoint &pos) {
QMenu *chMenu = new QMenu(tr("Add Chapter"));
if (item->allowedChild(Item::Chapter)) {
QAction *inAction = chMenu->addAction(tr("Inside"));
- connect(inAction, &QAction::triggered, [this, item]{doAddChild(item, Item::Chapter, ItemModel::Inside);});
+ connect(inAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Chapter, ItemModel::Inside);});
}
if (item->allowedSibling(Item::Chapter)) {
QAction *bfAction = chMenu->addAction(tr("Before"));
- connect(bfAction, &QAction::triggered, [this, item]{doAddChild(item, Item::Chapter, ItemModel::Before);});
+ connect(bfAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Chapter, ItemModel::Before);});
QAction *afAction = chMenu->addAction(tr("After"));
- connect(afAction, &QAction::triggered, [this, item]{doAddChild(item, Item::Chapter, ItemModel::After);});
+ connect(afAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Chapter, ItemModel::After);});
}
if (!chMenu->isEmpty()) {
contextMenu.addMenu(chMenu);
@@ -178,13 +180,13 @@ void GuiStoryTree::doOpenContextMenu(const QPoint &pos) {
QMenu *ptMenu = new QMenu(tr("Add Partition"));
if (item->allowedChild(Item::Partition)) {
QAction *inAction = ptMenu->addAction(tr("Inside"));
- connect(inAction, &QAction::triggered, [this, item]{doAddChild(item, Item::Partition, ItemModel::Inside);});
+ connect(inAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Partition, ItemModel::Inside);});
}
if (item->allowedSibling(Item::Partition)) {
QAction *bfAction = ptMenu->addAction(tr("Before"));
- connect(bfAction, &QAction::triggered, [this, item]{doAddChild(item, Item::Partition, ItemModel::Before);});
+ connect(bfAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Partition, ItemModel::Before);});
QAction *afAction = ptMenu->addAction(tr("After"));
- connect(afAction, &QAction::triggered, [this, item]{doAddChild(item, Item::Partition, ItemModel::After);});
+ connect(afAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Partition, ItemModel::After);});
}
if (!ptMenu->isEmpty()) {
contextMenu.addMenu(ptMenu);
@@ -192,14 +194,14 @@ void GuiStoryTree::doOpenContextMenu(const QPoint &pos) {
QMenu *bkMenu = new QMenu(tr("Add Book"));
if (item->allowedChild(Item::Book)) {
- QAction *inAction = bkMenu->addAction(index.isValid() ? tr("Inside") : tr("Here"));
- connect(inAction, &QAction::triggered, [this, item]{doAddChild(item, Item::Book, ItemModel::Inside);});
+ QAction *inAction = bkMenu->addAction(root ? tr("Here") : tr("Inside"));
+ connect(inAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Book, ItemModel::Inside);});
}
if (item->allowedSibling(Item::Book)) {
QAction *bfAction = bkMenu->addAction(tr("Before"));
- connect(bfAction, &QAction::triggered, [this, item]{doAddChild(item, Item::Book, ItemModel::Before);});
+ connect(bfAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Book, ItemModel::Before);});
QAction *afAction = bkMenu->addAction(tr("After"));
- connect(afAction, &QAction::triggered, [this, item]{doAddChild(item, Item::Book, ItemModel::After);});
+ connect(afAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Book, ItemModel::After);});
}
if (!bkMenu->isEmpty()) {
contextMenu.addMenu(bkMenu);
@@ -208,18 +210,48 @@ void GuiStoryTree::doOpenContextMenu(const QPoint &pos) {
QMenu *pgMenu = new QMenu(tr("Add Page"));
if (item->allowedChild(Item::Page)) {
QAction *inAction = pgMenu->addAction(tr("Inside"));
- connect(inAction, &QAction::triggered, [this, item]{doAddChild(item, Item::Page, ItemModel::Inside);});
+ connect(inAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Page, ItemModel::Inside);});
}
if (item->allowedSibling(Item::Page)) {
QAction *bfAction = pgMenu->addAction(tr("Before"));
- connect(bfAction, &QAction::triggered, [this, item]{doAddChild(item, Item::Page, ItemModel::Before);});
+ connect(bfAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Page, ItemModel::Before);});
QAction *afAction = pgMenu->addAction(tr("After"));
- connect(afAction, &QAction::triggered, [this, item]{doAddChild(item, Item::Page, ItemModel::After);});
+ connect(afAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Page, ItemModel::After);});
}
if (!pgMenu->isEmpty()) {
contextMenu.addMenu(pgMenu);
}
+ QMenu *fdMenu = new QMenu(tr("Add Group"));
+ if (item->allowedChild(Item::Group)) {
+ QAction *inAction = fdMenu->addAction(root ? tr("Here") : tr("Inside"));
+ connect(inAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Group, ItemModel::Inside);});
+ }
+ if (item->allowedSibling(Item::Group)) {
+ QAction *bfAction = fdMenu->addAction(tr("Before"));
+ connect(bfAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Group, ItemModel::Before);});
+ QAction *afAction = fdMenu->addAction(tr("After"));
+ connect(afAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Group, ItemModel::After);});
+ }
+ if (!fdMenu->isEmpty()) {
+ contextMenu.addMenu(fdMenu);
+ }
+
+ QMenu *ntMenu = new QMenu(tr("Add Note"));
+ if (item->allowedChild(Item::Note)) {
+ QAction *inAction = ntMenu->addAction(root ? tr("Here") : tr("Inside"));
+ connect(inAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Note, ItemModel::Inside);});
+ }
+ if (item->allowedSibling(Item::Note)) {
+ QAction *bfAction = ntMenu->addAction(tr("Before"));
+ connect(bfAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Note, ItemModel::Before);});
+ QAction *afAction = ntMenu->addAction(tr("After"));
+ connect(afAction, &QAction::triggered, [this, index]{doAddChild(index, Item::Note, ItemModel::After);});
+ }
+ if (!ntMenu->isEmpty()) {
+ contextMenu.addMenu(ntMenu);
+ }
+
contextMenu.exec(QWidget::mapToGlobal(pos));
}
@@ -228,7 +260,7 @@ void GuiStoryTree::doOpenContextMenu(const QPoint &pos) {
*
* @param bool unused.
*/
-void GuiStoryTree::doEditName(bool checked) {
+void GuiItemTree::doEditName(bool checked) {
Q_UNUSED(checked);
QModelIndex index = this->firstSelectedIndex();
@@ -254,13 +286,13 @@ void GuiStoryTree::doEditName(bool checked) {
*
* The slot will forward the call to create a new story item to the model.
*
- * @param item the item to add a child relative to.
- * @param type the type of item to add.
- * @param loc the relative location of where to add the new item.
+ * @param index the item index to add a child relative to.
+ * @param type the type of item to add.
+ * @param loc the relative location of where to add the new item.
*/
-void GuiStoryTree::doAddChild(Item *item, Item::ItemType type, ItemModel::AddLocation loc) {
+void GuiItemTree::doAddChild(const QModelIndex &index, Item::ItemType type, ItemModel::AddLocation loc) {
if (m_model) {
- if (m_model->addItem(item, type, loc)) {
+ if (m_model->addItem(index, type, loc)) {
qDebug() << "Added" << Item::typeToLabel(type);
} else {
qWarning() << "Failed to add" << Item::typeToLabel(type);
@@ -268,11 +300,11 @@ void GuiStoryTree::doAddChild(Item *item, Item::ItemType type, ItemModel::AddLoc
}
}
-void GuiStoryTree::saveExpanded(const QModelIndex &index) {
+void GuiItemTree::saveExpanded(const QModelIndex &index) {
if (m_model) m_model->setExpanded(index, true);
}
-void GuiStoryTree::saveCollapsed(const QModelIndex &index) {
+void GuiItemTree::saveCollapsed(const QModelIndex &index) {
if (m_model) m_model->setExpanded(index, false);
}
diff --git a/src/gui/storytree.h b/src/gui/itemtree.h
similarity index 81%
rename from src/gui/storytree.h
rename to src/gui/itemtree.h
index bc911e0..7b9be93 100644
--- a/src/gui/storytree.h
+++ b/src/gui/itemtree.h
@@ -1,6 +1,6 @@
/*
-** Collett – GUI Story Tree Class
-** ==============================
+** Collett – GUI Item Tree Class
+** =============================
**
** This file is a part of Collett
** Copyright 2020–2022, Veronica Berglyd Olsen
@@ -19,8 +19,8 @@
** along with this program. If not, see .
*/
-#ifndef GUI_STORYTREE_H
-#define GUI_STORYTREE_H
+#ifndef GUI_ITEMTREE_H
+#define GUI_ITEMTREE_H
#include "item.h"
#include "itemmodel.h"
@@ -34,15 +34,15 @@
namespace Collett {
-class GuiStoryTree : public QTreeView
+class GuiItemTree : public QTreeView
{
Q_OBJECT
public:
enum AddLocation{Before, After, Inside};
- GuiStoryTree(QWidget *parent=nullptr);
- ~GuiStoryTree() {};
+ GuiItemTree(QWidget *parent=nullptr);
+ ~GuiItemTree() {};
// Class Setters
@@ -58,7 +58,7 @@ public slots:
private slots:
void doOpenContextMenu(const QPoint &pos);
- void doAddChild(Item *item, Item::ItemType type, ItemModel::AddLocation loc);
+ void doAddChild(const QModelIndex &index, Item::ItemType type, ItemModel::AddLocation loc);
void saveExpanded(const QModelIndex &index);
void saveCollapsed(const QModelIndex &index);
@@ -70,4 +70,4 @@ private slots:
};
} // namespace Collett
-#endif // GUI_STORYTREE_H
+#endif // GUI_ITEMTREE_H
diff --git a/src/gui/storytreedelegate.cpp b/src/gui/itemtreedelegate.cpp
similarity index 85%
rename from src/gui/storytreedelegate.cpp
rename to src/gui/itemtreedelegate.cpp
index 45fb73f..460180c 100644
--- a/src/gui/storytreedelegate.cpp
+++ b/src/gui/itemtreedelegate.cpp
@@ -1,6 +1,6 @@
/*
-** Collett – GUI Story Tree Delegate Class
-** =======================================
+** Collett – GUI Item Tree Delegate Class
+** ======================================
**
** This file is a part of Collett
** Copyright 2020–2022, Veronica Berglyd Olsen
@@ -19,7 +19,7 @@
** along with this program. If not, see .
*/
-#include "storytreedelegate.h"
+#include "itemtreedelegate.h"
#include
#include
@@ -36,7 +36,7 @@
namespace Collett {
-GuiStoryTreeDelegate::GuiStoryTreeDelegate(QWidget *parent)
+GuiItemTreeDelegate::GuiItemTreeDelegate(QWidget *parent)
: QAbstractItemDelegate(parent)
{
m_headFont = qApp->font();
@@ -46,7 +46,7 @@ GuiStoryTreeDelegate::GuiStoryTreeDelegate(QWidget *parent)
m_mainHeight = QFontMetrics(m_mainFont).height();
}
-void GuiStoryTreeDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
+void GuiItemTreeDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
QVariantList data = index.data(Qt::DisplayRole).toList();
Q_ASSERT(data.size() == 3);
@@ -82,7 +82,7 @@ void GuiStoryTreeDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
painter->restore();
}
-QSize GuiStoryTreeDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
+QSize GuiItemTreeDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
return QSize(option.rect.width(), m_headHeight + m_mainHeight + 4);
}
diff --git a/src/gui/storytreedelegate.h b/src/gui/itemtreedelegate.h
similarity index 79%
rename from src/gui/storytreedelegate.h
rename to src/gui/itemtreedelegate.h
index a28fb8e..ae0ca00 100644
--- a/src/gui/storytreedelegate.h
+++ b/src/gui/itemtreedelegate.h
@@ -1,6 +1,6 @@
/*
-** Collett – GUI Story Tree Delegate Class
-** =======================================
+** Collett – GUI Item Tree Delegate Class
+** ======================================
**
** This file is a part of Collett
** Copyright 2020–2022, Veronica Berglyd Olsen
@@ -19,8 +19,8 @@
** along with this program. If not, see .
*/
-#ifndef GUI_STORYTREEDELEGATE_H
-#define GUI_STORYTREEDELEGATE_H
+#ifndef GUI_ITEMTREEDELEGATE_H
+#define GUI_ITEMTREEDELEGATE_H
#include
#include
@@ -32,13 +32,13 @@
namespace Collett {
-class GuiStoryTreeDelegate : public QAbstractItemDelegate
+class GuiItemTreeDelegate : public QAbstractItemDelegate
{
Q_OBJECT
public:
- GuiStoryTreeDelegate(QWidget *parent=nullptr);
- ~GuiStoryTreeDelegate() {};
+ GuiItemTreeDelegate(QWidget *parent=nullptr);
+ ~GuiItemTreeDelegate() {};
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
@@ -52,4 +52,4 @@ class GuiStoryTreeDelegate : public QAbstractItemDelegate
};
} // namespace Collett
-#endif // GUI_STORYTREEDELEGATE_H
+#endif // GUI_ITEMTREEDELEGATE_H
diff --git a/src/gui/maintoolbar.cpp b/src/gui/maintoolbar.cpp
index d089a73..243846f 100644
--- a/src/gui/maintoolbar.cpp
+++ b/src/gui/maintoolbar.cpp
@@ -32,9 +32,8 @@
namespace Collett {
-GuiMainToolBar::GuiMainToolBar(QWidget *parent)
- : QToolBar(parent)
-{
+GuiMainToolBar::GuiMainToolBar(QWidget *parent) : QToolBar(parent) {
+
QWidget *stretch1 = new QWidget();
QWidget *stretch2 = new QWidget();
stretch1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@@ -75,6 +74,9 @@ void GuiMainToolBar::buildMainMenu() {
m_saveProject = m_projectMenu->addAction(tr("Save Project"));
m_saveProject->setShortcut(QKeySequence("Ctrl+Shift+S"));
+ m_closeProject = m_projectMenu->addAction(tr("Close Project"));
+ m_closeProject->setShortcut(QKeySequence("Ctrl+Shift+W"));
+
m_projectButton = new QToolButton(this);
m_projectButton->setText(tr("Project"));
m_projectButton->setIcon(icons->icon("projectMenu"));
diff --git a/src/gui/maintoolbar.h b/src/gui/maintoolbar.h
index 44a3d97..e80df9a 100644
--- a/src/gui/maintoolbar.h
+++ b/src/gui/maintoolbar.h
@@ -52,6 +52,7 @@ class GuiMainToolBar : public QToolBar
QAction *m_newProject;
QAction *m_openProject;
QAction *m_saveProject;
+ QAction *m_closeProject;
// Documents Menu
QToolButton *m_docsButton;
diff --git a/src/gui/treetoolbar.cpp b/src/gui/treetoolbar.cpp
index fb0a7bf..f1217fa 100644
--- a/src/gui/treetoolbar.cpp
+++ b/src/gui/treetoolbar.cpp
@@ -1,6 +1,6 @@
/*
-** Collett – GUI Tree Tool Bar Class
-** =================================
+** Collett – GUI Tree ToolBar Class
+** ================================
**
** This file is a part of Collett
** Copyright 2020–2022, Veronica Berglyd Olsen
@@ -20,27 +20,84 @@
*/
#include "treetoolbar.h"
+#include "itemtree.h"
+#include "itemmodel.h"
#include "icons.h"
+#include
+#include
#include
+#include
#include
#include
#include
+#include
namespace Collett {
-GuiTreeToolBar::GuiTreeToolBar(QWidget *parent)
- : QToolBar(parent)
-{
+GuiTreeToolBar::GuiTreeToolBar(QWidget *parent) : QToolBar(parent) {
+ this->initToolBar();
+}
+
+/**
+ * Class Methods
+ * =============
+ */
+
+void GuiTreeToolBar::clearModels() {
+ m_modelButtons.clear();
+ m_modelTree.clear();
+ this->clear();
+ this->initToolBar();
+}
+
+void GuiTreeToolBar::addModelEntry(const QString &name, ItemModel *model, GuiItemTree *tree) {
+
+ CollettIcons *icons = CollettIcons::instance();
+
+ QToolButton *button = new QToolButton(this);
+ button->setIcon(icons->icon(model->modelIcon()));
+ button->setToolTip(model->modelName());
+ this->insertWidget(m_addAction, button);
+
+ m_modelButtons.insert(name, button);
+ m_modelTree.insert(name, tree);
+
+ connect(button, &QToolButton::clicked, [this, name]{treeButtonTriggered(name);});
+}
+
+/**
+ * Internal Functions
+ * ==================
+ */
+
+void GuiTreeToolBar::initToolBar() {
QWidget *stretch = new QWidget(this);
stretch->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
CollettIcons *icons = CollettIcons::instance();
+ m_addAction = new QAction(this);
+ m_addAction->setText(tr("Add Action"));
+ m_addAction->setIcon(icons->icon("add"));
+
this->setOrientation(Qt::Vertical);
- this->addAction(icons->icon("storyModel"), tr("Story"));
+ this->addAction(m_addAction);
this->addWidget(stretch);
this->addAction(icons->icon("settings"), tr("Settings"));
}
+/**
+ * Private Slots
+ * =============
+ */
+
+void GuiTreeToolBar::treeButtonTriggered(const QString &name) {
+ qDebug() << "Clicked tree button:" << name;
+ if (m_modelTree.contains(name)) {
+ emit treeButtonClicked(m_modelTree.value(name));
+ } else {
+ }
+}
+
} // namespace Collett
diff --git a/src/gui/treetoolbar.h b/src/gui/treetoolbar.h
index 4310c2e..4980d8a 100644
--- a/src/gui/treetoolbar.h
+++ b/src/gui/treetoolbar.h
@@ -1,6 +1,6 @@
/*
-** Collett – GUI Tree Tool Bar Class
-** =================================
+** Collett – GUI Tree ToolBar Class
+** ================================
**
** This file is a part of Collett
** Copyright 2020–2022, Veronica Berglyd Olsen
@@ -22,8 +22,15 @@
#ifndef GUI_TREETOOLBAR_H
#define GUI_TREETOOLBAR_H
+#include "itemtree.h"
+#include "itemmodel.h"
+
+#include
+#include
#include
+#include
#include
+#include
namespace Collett {
@@ -35,6 +42,24 @@ class GuiTreeToolBar : public QToolBar
GuiTreeToolBar(QWidget *parent=nullptr);
~GuiTreeToolBar() {};
+ // Class Methods
+
+ void clearModels();
+ void addModelEntry(const QString &name, ItemModel *model, GuiItemTree *tree);
+
+signals:
+ void treeButtonClicked(GuiItemTree *tree);
+
+private:
+ QAction *m_addAction;
+ QHash m_modelButtons;
+ QHash m_modelTree;
+
+ void initToolBar();
+
+private slots:
+ void treeButtonTriggered(const QString &name);
+
};
} // namespace Collett
diff --git a/src/guimain.cpp b/src/guimain.cpp
index 03b3e66..a312639 100644
--- a/src/guimain.cpp
+++ b/src/guimain.cpp
@@ -20,13 +20,14 @@
*/
#include "data.h"
-#include "doceditor.h"
-#include "guimain.h"
+#include "item.h"
#include "icons.h"
-#include "maintoolbar.h"
+#include "guimain.h"
+#include "itemtree.h"
#include "settings.h"
+#include "doceditor.h"
#include "statusbar.h"
-#include "storytree.h"
+#include "maintoolbar.h"
#include "treetoolbar.h"
#include
@@ -34,8 +35,10 @@
#include
#include
#include
+#include
#include
#include
+#include
#include
namespace Collett {
@@ -48,7 +51,7 @@ GuiMain::GuiMain(QWidget *parent) : QMainWindow(parent) {
// Collett Widgets
m_mainToolBar = new GuiMainToolBar(this);
m_treeToolBar = new GuiTreeToolBar(this);
- m_storyTree = new GuiStoryTree(this);
+ m_treeStack = new QStackedWidget(this);
m_mainStatus = new GuiMainStatus(this);
m_docEditor = new GuiDocEditor(this);
@@ -56,7 +59,7 @@ GuiMain::GuiMain(QWidget *parent) : QMainWindow(parent) {
m_splitMain = new QSplitter(Qt::Horizontal, this);
m_splitMain->setContentsMargins(0, 0, 0, 0);
m_splitMain->setOpaqueResize(false);
- m_splitMain->addWidget(m_storyTree);
+ m_splitMain->addWidget(m_treeStack);
m_splitMain->addWidget(m_docEditor);
this->addToolBar(Qt::TopToolBarArea, m_mainToolBar);
@@ -70,15 +73,16 @@ GuiMain::GuiMain(QWidget *parent) : QMainWindow(parent) {
m_splitMain->setSizes(mainConf->mainSplitSizes());
// Connect Signals and Slots
- connect(m_storyTree, SIGNAL(doubleClicked(const QModelIndex&)),
- this, SLOT(storyTreeDoubleClick(const QModelIndex&)));
-
+ connect(m_mainToolBar->m_closeProject, SIGNAL(triggered()),
+ this, SLOT(closeProjectRequest()));
connect(m_mainToolBar->m_openDocument, SIGNAL(triggered()),
this, SLOT(openSelectedDocument()));
connect(m_mainToolBar->m_saveDocument, SIGNAL(triggered()),
- this, SLOT(saveOpenDocument()));
+ this, SLOT(saveCurrentDocument()));
connect(m_mainToolBar->m_renameDocument, SIGNAL(triggered()),
this, SLOT(renameDocument()));
+ connect(m_treeToolBar, SIGNAL(treeButtonClicked(GuiItemTree*)),
+ this, SLOT(changeModelTree(GuiItemTree*)));
// Connect Actions to Capture Key Sequence
this->addAction(m_mainToolBar->m_newProject);
@@ -99,6 +103,7 @@ GuiMain::GuiMain(QWidget *parent) : QMainWindow(parent) {
GuiMain::~GuiMain() {
qDebug() << "Destructor: GuiMain";
+ qDeleteAll(m_itemTrees.begin(), m_itemTrees.end());
delete m_data;
}
@@ -114,13 +119,22 @@ void GuiMain::openProject(const QString &path) {
return;
}
- QItemSelectionModel *m = m_storyTree->selectionModel();
- m_storyTree->setTreeModel(m_data->storyModel());
- delete m;
+ for (const QString &name : m_data->project()->modelList()) {
+ qDebug() << "Adding tree:" << name;
+ this->addItemTree(name);
+ }
+ if (m_itemTrees.contains("story")) {
+ this->m_treeStack->setCurrentWidget(m_itemTrees.value("story"));
+ }
QUuid lastDocMain = m_data->project()->lastDocumentMain();
if (!lastDocMain.isNull()) {
- this->openDocument(lastDocMain);
+ Item *itemMain = nullptr;
+ for (const GuiItemTree *tree : m_itemTrees) {
+ itemMain = static_cast(tree->model())->itemFromHandle(lastDocMain);
+ if (itemMain) break;
+ }
+ this->openDocument(itemMain);
}
m_mainToolBar->setProjectName(m_data->project()->projectName());
@@ -132,6 +146,9 @@ bool GuiMain::saveProject() {
}
bool GuiMain::closeProject() {
+ this->closeDocument();
+ m_treeToolBar->clearModels();
+ m_data->closeProject();
return true;
};
@@ -140,9 +157,12 @@ bool GuiMain::closeProject() {
* ================
*/
-void GuiMain::openDocument(const QUuid &uuid) {
+void GuiMain::openDocument(Item *item) {
- if (!m_data->hasProject()) {
+ if (!m_data->hasProject() || !item) {
+ return;
+ }
+ if (!item->canHoldDocument()) {
return;
}
@@ -150,7 +170,7 @@ void GuiMain::openDocument(const QUuid &uuid) {
m_docEditor->saveDocument();
m_docEditor->closeDocument();
}
- m_docEditor->openDocument(uuid);
+ m_docEditor->openDocument(item);
m_data->project()->setLastDocumentMain(m_docEditor->currentDocument());
}
@@ -173,6 +193,33 @@ void GuiMain::closeDocument() {
* ===========
*/
+void GuiMain::addItemTree(const QString &name) {
+
+ if (!m_data->hasProject()) {
+ return;
+ }
+ if (m_itemTrees.contains(name)) {
+ qWarning() << "ItemTree already exists:" << name;
+ return;
+ }
+
+ ItemModel *model = m_data->project()->model(name);
+ if (!model) {
+ qWarning() << "Model does not exist:" << name;
+ return;
+ }
+
+ GuiItemTree *tree = new GuiItemTree(this);
+ m_itemTrees.insert(name, tree);
+
+ tree->setTreeModel(model);
+ m_treeStack->addWidget(tree);
+ m_treeToolBar->addModelEntry(name, model, tree);
+
+ connect(tree, SIGNAL(doubleClicked(const QModelIndex&)),
+ this, SLOT(itemTreeDoubleClick(const QModelIndex&)));
+}
+
bool GuiMain::closeMain() {
m_docEditor->saveDocument();
@@ -211,18 +258,29 @@ void GuiMain::closeEvent(QCloseEvent *event) {
* =============
*/
+void GuiMain::closeProjectRequest() {
+ auto response = QMessageBox::question(
+ this, tr("Question"), tr("Do you want to close the project?")
+ );
+ if (response == QMessageBox::Yes) {
+ this->closeProject();
+ }
+}
+
void GuiMain::openSelectedDocument() {
if (!m_data->hasProject())
return;
- QModelIndex index = m_storyTree->firstSelectedIndex();
+ GuiItemTree *tree = static_cast(m_treeStack->currentWidget());
+ QModelIndex index = tree->firstSelectedIndex();
if (!index.isValid())
return;
- this->openDocument(m_data->storyModel()->itemHandle(index));
+ ItemModel *model = static_cast(tree->model());
+ this->openDocument(model->itemFromIndex(index));
}
-void GuiMain::saveOpenDocument() {
+void GuiMain::saveCurrentDocument() {
if (!m_data->hasProject())
return;
if (m_docEditor->anyFocus())
@@ -232,14 +290,21 @@ void GuiMain::saveOpenDocument() {
void GuiMain::renameDocument() {
if (!m_data->hasProject())
return;
- m_storyTree->doEditName(false);
+
+ GuiItemTree *tree = static_cast(m_treeStack->currentWidget());
+ tree->doEditName(false);
}
-void GuiMain::storyTreeDoubleClick(const QModelIndex &index) {
- if (!m_data->hasProject() || !index.isValid()) {
+void GuiMain::itemTreeDoubleClick(const QModelIndex &index) {
+ Q_UNUSED(index);
+ this->openSelectedDocument();
+}
+
+void GuiMain::changeModelTree(GuiItemTree *tree) {
+ if (!m_data->hasProject())
return;
- }
- this->openDocument(m_data->storyModel()->itemHandle(index));
+
+ m_treeStack->setCurrentWidget(static_cast(tree));
}
} // namespace Collett
diff --git a/src/guimain.h b/src/guimain.h
index 2274d42..0175fa9 100644
--- a/src/guimain.h
+++ b/src/guimain.h
@@ -22,14 +22,16 @@
#ifndef GUI_MAIN_H
#define GUI_MAIN_H
-#include "collett.h"
#include "data.h"
+#include "item.h"
+#include "collett.h"
+#include "itemtree.h"
+#include "doceditor.h"
+#include "statusbar.h"
#include "maintoolbar.h"
#include "treetoolbar.h"
-#include "statusbar.h"
-#include "storytree.h"
-#include "doceditor.h"
+#include
#include
#include
#include
@@ -37,6 +39,7 @@
#include
#include
#include
+#include
namespace Collett {
@@ -56,12 +59,13 @@ class GuiMain : public QMainWindow
// Document Methods
- void openDocument(const QUuid &uuid);
+ void openDocument(Item *item);
void saveDocument();
void closeDocument();
// GUI Methods
+ void addItemTree(const QString &name);
bool closeMain();
private:
@@ -70,10 +74,12 @@ class GuiMain : public QMainWindow
// Collett Widgets
GuiMainToolBar *m_mainToolBar;
GuiTreeToolBar *m_treeToolBar;
- GuiStoryTree *m_storyTree;
+ QStackedWidget *m_treeStack;
GuiDocEditor *m_docEditor;
GuiMainStatus *m_mainStatus;
+ QHash m_itemTrees;
+
// GUI Widgets
QSplitter *m_splitMain;
@@ -82,10 +88,12 @@ class GuiMain : public QMainWindow
private slots:
+ void closeProjectRequest();
void openSelectedDocument();
- void saveOpenDocument();
+ void saveCurrentDocument();
void renameDocument();
- void storyTreeDoubleClick(const QModelIndex &index);
+ void itemTreeDoubleClick(const QModelIndex &index);
+ void changeModelTree(GuiItemTree *tree);
};
} // namespace Collett
diff --git a/src/project/item.cpp b/src/project/item.cpp
index 76aa4ca..cff200d 100644
--- a/src/project/item.cpp
+++ b/src/project/item.cpp
@@ -193,10 +193,6 @@ QJsonObject Item::toJsonObject() {
type = QLatin1String("ROOT");
expandable = false;
break;
- case Item::Folder:
- type = QLatin1String("FOLDER");
- expandable = true;
- break;
case Item::Book:
type = QLatin1String("BOOK");
expandable = true;
@@ -217,6 +213,10 @@ QJsonObject Item::toJsonObject() {
type = QLatin1String("PAGE");
expandable = false;
break;
+ case Item::Group:
+ type = QLatin1String("GROUP");
+ expandable = true;
+ break;
case Item::Note:
type = QLatin1String("NOTE");
expandable = false;
@@ -278,9 +278,9 @@ bool Item::allowedChild(Item::ItemType type) const {
} else {
switch (m_type) {
case Item::Root:
- return type == Item::Folder || type == Item::Note;
+ return type == Item::Group || type == Item::Note;
break;
- case Item::Folder:
+ case Item::Group:
return type == Item::Note;
break;
default:
@@ -306,6 +306,16 @@ bool Item::allowedSibling(Item::ItemType type) const {
}
}
+bool Item::canHoldDocument() const {
+ switch (m_type) {
+ case ItemType::Chapter: return true;
+ case ItemType::Scene: return true;
+ case ItemType::Page: return true;
+ case ItemType::Note: return true;
+ default: return false;
+ }
+}
+
/**
* Class Setters
* =============
@@ -357,6 +367,18 @@ bool Item::isExpanded() const {
return m_expanded;
}
+Item *Item::findItemFromHandle(const QUuid &uuid) const {
+ if (m_handle == uuid) {
+ return const_cast
- (this);
+ } else {
+ for (Item* child : m_childItems) {
+ Item *item = child->findItemFromHandle(uuid);
+ if (item) return item;
+ }
+ }
+ return nullptr;
+}
+
/**
* Static Methods
* ==============
@@ -375,12 +397,12 @@ QString Item::typeToLabel(ItemType type) {
QString name = "";
switch (type) {
case Item::Root: name = ""; break;
- case Item::Folder: name = tr("Folder"); break;
case Item::Book: name = tr("Book"); break;
case Item::Partition: name = tr("Partition"); break;
case Item::Chapter: name = tr("Chapter"); break;
case Item::Scene: name = tr("Scene"); break;
case Item::Page: name = tr("Page"); break;
+ case Item::Group: name = tr("Group"); break;
case Item::Note: name = tr("Note"); break;
case Item::Invalid: name = ""; break;
}
@@ -391,8 +413,6 @@ Item::ItemType Item::typeFromString(const QString &value) {
QString upper = value.toUpper();
if (upper == "ROOT") {
return Item::Root;
- } else if (upper == "FOLDER") {
- return Item::Folder;
} else if (upper == "BOOK") {
return Item::Book;
} else if (upper == "PARTITION") {
@@ -403,6 +423,8 @@ Item::ItemType Item::typeFromString(const QString &value) {
return Item::Scene;
} else if (upper == "PAGE") {
return Item::Page;
+ } else if (upper == "GROUP") {
+ return Item::Group;
} else if (upper == "NOTE") {
return Item::Note;
} else {
diff --git a/src/project/item.h b/src/project/item.h
index 539e5fb..cbe0ed4 100644
--- a/src/project/item.h
+++ b/src/project/item.h
@@ -34,7 +34,11 @@ class Item : public QObject
Q_OBJECT
public:
- enum ItemType{Invalid, Root, Folder, Book, Partition, Chapter, Scene, Page, Note};
+ enum ItemType{
+ Invalid,
+ Root, Book, Partition, Chapter, Scene, Page,
+ Group, Note
+ };
explicit Item(const QUuid &uuid, const QString &name, bool story, ItemType type, Item *parentItem=nullptr);
~Item();
@@ -46,6 +50,7 @@ class Item : public QObject
QJsonObject toJsonObject();
bool allowedChild(ItemType type) const;
bool allowedSibling(ItemType type) const;
+ bool canHoldDocument() const;
// Class Setters
@@ -61,6 +66,7 @@ class Item : public QObject
int wordCount() const;
int childWordCounts() const;
bool isExpanded() const;
+ Item *findItemFromHandle(const QUuid &uuid) const;
// Static Methods
diff --git a/src/project/itemmodel.cpp b/src/project/itemmodel.cpp
index 3aba8eb..d64cd6d 100644
--- a/src/project/itemmodel.cpp
+++ b/src/project/itemmodel.cpp
@@ -167,24 +167,46 @@ bool ItemModel::fromJsonObject(const QJsonObject &json) {
* @param loc the relative location of where to add the new item.
* @return true if the item was successfully added, otherwise false.
*/
-bool ItemModel::addItem(Item *relativeTo, Item::ItemType type, AddLocation loc) {
- if (!relativeTo) {
- return false;
- }
- Item *target = relativeTo;
- int pos = relativeTo->childCount();
- if (loc == AddLocation::Before || loc == AddLocation::After) {
- target = relativeTo->parentItem();
- pos = relativeTo->row() + (loc == AddLocation::After ? 1 : 0);
- }
- if (!target) {
- return false;
+bool ItemModel::addItem(const QModelIndex &relative, Item::ItemType type, AddLocation loc) {
+
+ QString name = tr("New %1").arg(Item::typeToLabel(type));
+
+ if (!relative.isValid()) {
+
+ int pos = m_rootItem->childCount();
+ emit beginInsertRows(this->index(0, 0), pos, pos);
+ Item *item = m_rootItem->addChild(name, type, pos);
+ emit endInsertRows();
+ qDebug() << "Added root item with name:" << name;
+ return item != nullptr;
+
+ } else {
+
+ QModelIndex index = relative;
+
+ Item *target = itemFromIndex(relative);
+ if (!target) {
+ return false;
+ }
+
+ int pos = target->childCount();
+ if (loc == AddLocation::Before || loc == AddLocation::After) {
+ target = target->parentItem();
+ index = this->parent(relative);
+ pos = target->row() + (loc == AddLocation::After ? 1 : 0);
+ }
+ if (!target) {
+ return false;
+ }
+
+ emit beginInsertRows(index, pos, pos);
+ Item *item = target->addChild(name, type, pos);
+ emit endInsertRows();
+
+ qDebug() << "Added item with name:" << name;
+ return item != nullptr;
+
}
- qDebug() << target->row() << pos;
- emit beginInsertRows(createIndex(target->row(), 0, target), pos, pos);
- Item *item = target->addChild(tr("New %1").arg(Item::typeToLabel(type)), type, pos);
- emit endInsertRows();
- return item != nullptr;
}
/**!
@@ -210,11 +232,23 @@ bool ItemModel::isValid() const {
* =============
*/
+QString ItemModel::modelName() const {
+ return m_name;
+}
+
+QString ItemModel::modelIcon() const {
+ return m_icon;
+}
+
+ItemModel::ModelType ItemModel::modelType() const {
+ return m_type;
+}
+
Item *ItemModel::rootItem() const {
return m_rootItem;
}
-Item *ItemModel::storyItem(const QModelIndex &index) {
+Item *ItemModel::itemFromIndex(const QModelIndex &index) {
if (index.isValid()) {
return static_cast
- (index.internalPointer());
} else {
@@ -222,12 +256,11 @@ Item *ItemModel::storyItem(const QModelIndex &index) {
}
}
-QUuid ItemModel::itemHandle(const QModelIndex &index) {
- if (index.isValid()) {
- Item *item = static_cast
- (index.internalPointer());
- return item->handle();
+Item *ItemModel::itemFromHandle(const QUuid &uuid) {
+ if (!uuid.isNull()) {
+ return m_rootItem->findItemFromHandle(uuid);
} else {
- return QUuid();
+ return nullptr;
}
}
diff --git a/src/project/itemmodel.h b/src/project/itemmodel.h
index e07befe..e17aca2 100644
--- a/src/project/itemmodel.h
+++ b/src/project/itemmodel.h
@@ -24,6 +24,7 @@
#include "item.h"
+#include
#include
#include
#include
@@ -49,7 +50,7 @@ class ItemModel : public QAbstractItemModel
QJsonObject toJsonObject();
bool fromJsonObject(const QJsonObject &json);
- bool addItem(Item *relativeTo, Item::ItemType type, AddLocation loc);
+ bool addItem(const QModelIndex &relative, Item::ItemType type, AddLocation loc);
bool isEmpty() const;
bool isValid() const;
@@ -57,10 +58,11 @@ class ItemModel : public QAbstractItemModel
QString modelName() const;
QString modelIcon() const;
+ ModelType modelType() const;
Item *rootItem() const;
- Item *storyItem(const QModelIndex &index);
- QUuid itemHandle(const QModelIndex &index);
+ Item *itemFromIndex(const QModelIndex &index);
+ Item *itemFromHandle(const QUuid &uuid);
QString itemName(const QModelIndex &index);
bool isExpanded(const QModelIndex &index);
diff --git a/src/project/project.cpp b/src/project/project.cpp
index e4b88ca..ddb8fa5 100644
--- a/src/project/project.cpp
+++ b/src/project/project.cpp
@@ -32,6 +32,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -174,6 +175,10 @@ Storage *Project::store() {
return m_store;
}
+QStringList Project::modelList() const {
+ return m_modelOrder;
+}
+
ItemModel *Project::model(const QString &name) {
if (m_models.contains(name)) {
return m_models.value(name);
@@ -228,6 +233,7 @@ bool Project::loadProjectStructure() {
for (const QJsonValue &value : jProject.value(QLatin1String("u:models")).toArray()) {
QString key = value.toString().simplified();
if (!key.isEmpty()) {
+ m_modelOrder << key;
m_models.insert(key, new ItemModel(this));
QJsonObject mData;
if (m_store->loadFile(key, mData)) {
@@ -256,7 +262,7 @@ bool Project::saveProjectStructure() {
jProject[QLatin1String("s:last-doc-main")] = m_lastDocMain.toString(QUuid::WithoutBraces);
// Data Models
- for (const QString &key : m_models.keys()) {
+ for (const QString &key : m_modelOrder) {
jModels.append(key);
qDebug() << "Saving model:" << key;
if (!m_store->saveFile(key, m_models[key]->toJsonObject())) {
diff --git a/src/project/project.h b/src/project/project.h
index 335bdbe..446008f 100644
--- a/src/project/project.h
+++ b/src/project/project.h
@@ -32,6 +32,7 @@
#include
#include
#include
+#include
namespace Collett {
@@ -62,6 +63,7 @@ class Project : public QObject
QString projectName() const;
Storage *store();
+ QStringList modelList() const;
ItemModel *model(const QString &name);
Document *document(const QUuid &uuid);
@@ -91,6 +93,7 @@ class Project : public QObject
// Content
+ QStringList m_modelOrder;
QHash m_models;
QHash m_documents;