1 /*
2 outline_tree_presenter.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_presenter.h"
20
21 namespace m8r {
22
23 using namespace std;
24
OutlineTreePresenter(OutlineTreeView * view,MainWindowPresenter * mwp,QObject * parent)25 OutlineTreePresenter::OutlineTreePresenter(OutlineTreeView* view, MainWindowPresenter* mwp, QObject* parent)
26 : QObject(parent)
27 {
28 this->view = view;
29 this->model = new OutlineTreeModel{view, mwp->getHtmlRepresentation()};
30 this->view->setModel(this->model);
31 this->mind = mwp->getMind();
32
33 // ensure HTML cells rendering
34 HtmlDelegate* delegate = new HtmlDelegate{};
35 this->view->setItemDelegate(delegate);
36
37 // signals
38 QObject::connect(view, SIGNAL(signalSelectNextRow()), this, SLOT(slotSelectNextRow()));
39 QObject::connect(view, SIGNAL(signalSelectPreviousRow()), this, SLOT(slotSelectPreviousRow()));
40
41 QObject::connect(view, SIGNAL(signalOutlineShow()), mwp, SLOT(doActionOutlineShow()));
42
43 QObject::connect(view, SIGNAL(signalChangePromote()), mwp, SLOT(doActionNotePromote()));
44 QObject::connect(view, SIGNAL(signalChangeDemote()), mwp, SLOT(doActionNoteDemote()));
45 QObject::connect(view, SIGNAL(signalChangeFirst()), mwp, SLOT(doActionNoteFirst()));
46 QObject::connect(view, SIGNAL(signalChangeUp()), mwp, SLOT(doActionNoteUp()));
47 QObject::connect(view, SIGNAL(signalChangeDown()), mwp, SLOT(doActionNoteDown()));
48 QObject::connect(view, SIGNAL(signalChangeLast()), mwp, SLOT(doActionNoteLast()));
49
50 QObject::connect(view, SIGNAL(signalOutlineOrNoteEdit()), mwp, SLOT(doActionOutlineOrNoteEdit()));
51 QObject::connect(view, SIGNAL(signalEdit()), mwp, SLOT(doActionNoteEdit()));
52 QObject::connect(view, SIGNAL(signalForget()), mwp, SLOT(doActionNoteForget()));
53 }
54
~OutlineTreePresenter()55 OutlineTreePresenter::~OutlineTreePresenter()
56 {
57 if(model) delete model;
58 }
59
refresh(Outline * outline,Outline::Patch * patch)60 void OutlineTreePresenter::refresh(Outline* outline, Outline::Patch* patch)
61 {
62 // If FORGET aspect is used, then only VIEW is filtered, but operations are performed
63 // on the non-filtered O's Ns. UI view serves just as a FILTER of what can be changed.
64 // Therefore anything special is needed on the backend.
65 // Unfortunately PATCH will NOT help if VIEW is filtered and everyhing must be
66 // refreshed.
67 if(outline) {
68 if(patch) {
69 const vector<Note*>& notes = outline->getNotes();
70 switch(patch->diff) {
71 case Outline::Patch::Diff::CHANGE:
72 for(unsigned int i=patch->start; i<=patch->start+patch->count; i++) {
73 model->refresh(notes[i], i, false);
74 }
75 break;
76 case Outline::Patch::Diff::MOVE:
77 for(unsigned int i=patch->start; i<=patch->start+patch->count; i++) {
78 model->refresh(notes[i], i, true);
79 }
80 break;
81 default:
82 break;
83 }
84 } else {
85 model->removeAllRows();
86 for(Note* note:outline->getNotes()) {
87 model->addNote(note);
88 }
89 }
90
91 // forget / time scope: hide view rows ~ there is full model, I just hide what's visible > patch should work
92 if(mind->getScopeAspect().isEnabled()) {
93 vector<int> parents;
94 for(size_t i=0; i<outline->getNotesCount(); i++) {
95 if(mind->getScopeAspect().isInScope(outline->getNotes()[i])) {
96 // N's parents
97 parents.clear();
98 outline->getNotePathToRoot(i, parents);
99 if(parents.size()) {
100 for(size_t p=0; p<parents.size(); p++) {
101 view->showRow(parents[p]);
102 }
103 }
104 // N
105 view->showRow(i);
106 } else {
107 view->hideRow(i);
108 }
109 }
110 }
111 }
112 }
113
refresh(Note * note)114 void OutlineTreePresenter::refresh(Note* note)
115 {
116 QItemSelectionModel *select = view->selectionModel();
117 if(select->hasSelection()) {
118 model->refresh(note, select->selectedRows());
119 } else {
120 model->refresh(note);
121 }
122 }
123
insertAndSelect(Note * note)124 void OutlineTreePresenter::insertAndSelect(Note* note)
125 {
126 int row = model->insertNote(note);
127 view->scrollTo(model->index(row, 0));
128 view->selectRow(row);
129 }
130
clearSelection()131 void OutlineTreePresenter::clearSelection()
132 {
133 view->clearSelection();
134 }
135
selectRowByNote(const Note * note)136 void OutlineTreePresenter::selectRowByNote(const Note* note)
137 {
138 if(note) {
139 int row = model->getRowByNote(note);
140 if(row >= 0) {
141 view->selectRow(row);
142 view->scrollTo(model->index(row, 0));
143 return;
144 }
145 }
146 view->clearSelection();
147 }
148
getCurrentRow() const149 int OutlineTreePresenter::getCurrentRow() const
150 {
151 QModelIndexList indexes = view->selectionModel()->selection().indexes();
152 for(int i=0; i<indexes.count(); i++) {
153 return indexes.at(i).row();
154 }
155 return NO_ROW;
156 }
157
getCurrentNote() const158 Note* OutlineTreePresenter::getCurrentNote() const
159 {
160 int row = getCurrentRow();
161 // IMPROVE constant w/ a name
162 if(row != -1) {
163 return model->item(row)->data().value<Note*>();
164 } else {
165 return nullptr;
166 }
167 }
168
slotSelectNextRow()169 void OutlineTreePresenter::slotSelectNextRow()
170 {
171 int row = getCurrentRow();
172 if(row < model->rowCount()-1) {
173 QModelIndex nextIndex = model->index(row+1, 0);
174 view->setCurrentIndex(nextIndex);
175 }
176 }
177
slotSelectPreviousRow()178 void OutlineTreePresenter::slotSelectPreviousRow()
179 {
180 int row = getCurrentRow();
181 if(row) {
182 QModelIndex previousIndex = model->index(row-1, 0);
183 view->setCurrentIndex(previousIndex);
184 }
185 }
186
187 } // m8r namespace
188