1 /*
2  outline_tree_model.cpp     MindForger thinking notebook
3 
4  Copyright (C) 2016-2020 Martin Dvorak <martin.dvorak@mindforger.com>
5 
6  This program is free software; you can redistribute it and/or
7  modify it under the terms of the GNU General Public License
8  as published by the Free Software Foundation; either version 2
9  of the License, or (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "outline_tree_model.h"
20 
21 #include <iostream>
22 
23 #define NO_INDEX -1
24 
25 using namespace std;
26 
27 namespace m8r {
28 
OutlineTreeModel(QObject * parent,HtmlOutlineRepresentation * htmlRepresentation)29 OutlineTreeModel::OutlineTreeModel(QObject *parent, HtmlOutlineRepresentation* htmlRepresentation)
30     : QStandardItemModel(parent), htmlRepresentation(htmlRepresentation)
31 {
32     setColumnCount(5);
33     setRowCount(0);
34 }
35 
removeAllRows()36 void OutlineTreeModel::removeAllRows()
37 {
38     QStandardItemModel::clear();
39 
40     QStringList tableHeader;
41     tableHeader
42             << tr("Outline") // tree of Notes is in fact Notebook's outline
43             << tr("Done")
44             << tr("Rs")
45             << tr("Ws")
46             << tr("Modified");
47     setHorizontalHeaderLabels(tableHeader);
48 }
49 
createNameText(string & html,Note * note)50 void OutlineTreeModel::createNameText(string& html, Note* note)
51 {
52     for(auto depth=0; depth<note->getDepth(); depth++) {
53         html += "&nbsp;&nbsp;&nbsp;&nbsp;";
54     }
55     html += note->getName();
56 
57     htmlRepresentation->tagsToHtml(note->getTags(), html);
58     // IMPROVE make showing of type configurable
59     htmlRepresentation->noteTypeToHtml(note->getType(), html);
60 }
61 
createRowFor(Note * note,QList<QStandardItem * > & rowItems)62 void OutlineTreeModel::createRowFor(Note* note, QList<QStandardItem*>& rowItems)
63 {
64     // name
65     string name{};
66     name.reserve(200);
67     createNameText(name, note);
68     QStandardItem* noteItem = new QStandardItem{QString::fromStdString(name)};
69     // TODO declare custom role
70     noteItem->setData(QVariant::fromValue(note), Qt::UserRole + 1);
71     rowItems += noteItem;
72     // %
73     QString s{};
74     if(note->getProgress()) {
75         s.clear();
76         s += QString::number(note->getProgress());
77         s += "%";
78         rowItems += new QStandardItem{s};
79     } else {
80         rowItems += new QStandardItem{""};
81     }
82     // rd/wr
83     rowItems += new QStandardItem{QString::number(note->getReads())};
84     rowItems += new QStandardItem{QString::number(note->getRevision())};
85     // pretty
86     s = note->getModifiedPretty().c_str();
87     rowItems += new QStandardItem{s};
88 }
89 
90 
addNote(Note * note)91 void OutlineTreeModel::addNote(Note* note)
92 {
93     QList<QStandardItem*> items;
94     createRowFor(note, items);
95     appendRow(items);
96 }
97 
insertNote(Note * note)98 int OutlineTreeModel::insertNote(Note* note)
99 {
100     if(note) {
101         QList<QStandardItem*> items;
102         createRowFor(note, items);
103         int offset = note->getOutline()->getNoteOffset(note);
104         insertRow(offset, items);
105         return offset;
106     } else {
107         return 0;
108     }
109 }
110 
getRowByNote(const Note * note)111 int OutlineTreeModel::getRowByNote(const Note* note)
112 {
113     for(int row = 0; row<rowCount(); row++) {
114         if(item(row)->data().value<Note*>() == note) {
115             return row;
116         }
117     }
118     return NO_INDEX;
119 }
120 
refresh(Note * note,int row,bool set)121 void OutlineTreeModel::refresh(Note* note, int row, bool set)
122 {
123     if(row > NO_INDEX) {
124         if(set) {
125             // TODO declare custom role
126             item(row,0)->setData(QVariant::fromValue(note), Qt::UserRole + 1);
127         }
128 
129         string s{};
130         s.reserve(100);
131         createNameText(s, note);
132         // refresh content
133         item(row,0)->setText(QString::fromStdString(s));
134 
135         if(note->getProgress()) {
136             s.clear();
137             s += std::to_string(note->getProgress());
138             s += "%";
139             item(row,1)->setText(QString::fromStdString(s));
140         } else {
141             item(row,1)->setText("");
142         }
143 
144         item(row,2)->setText(QString::number(note->getReads()));
145         item(row,3)->setText(QString::number(note->getRevision()));
146         item(row,4)->setText(QString::fromStdString(note->getModifiedPretty()));
147 
148         QModelIndex from = createIndex(row, 0, item(row,0));
149         QModelIndex to = createIndex(row, 3, item(row,3));
150 
151         // notify widget about changes
152         emit dataChanged(from,to);
153     }
154 }
155 
refresh(Note * note,QModelIndexList selection)156 void OutlineTreeModel::refresh(Note* note, QModelIndexList selection)
157 {
158     int row = NO_INDEX;
159 
160     // determine row number by note attached to the row - selection or iteration
161     if(selection.size()) {
162         // TODO declare custom role
163         if(item(selection[0].row())->data(Qt::UserRole + 1).value<Note*>() == note) {
164             row = selection[0].row();
165         }
166     }
167     if(row <= NO_INDEX) {
168         // IMPROVE UI note that has both Note and QStandardItem refs
169         row = getRowByNote(note);
170     }
171 
172     refresh(note, row);
173 }
174 
175 } // m8r namespace
176