1 /*
2 outline_view.h 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 "orloj_presenter.h"
20
21 #include "../../lib/src/gear/lang_utils.h"
22
23 using namespace std;
24
25 namespace m8r {
26
OrlojPresenter(MainWindowPresenter * mainPresenter,OrlojView * view,Mind * mind)27 OrlojPresenter::OrlojPresenter(MainWindowPresenter* mainPresenter,
28 OrlojView* view,
29 Mind* mind)
30 : activeFacet{OrlojPresenterFacets::FACET_NONE},
31 config{Configuration::getInstance()},
32 skipEditNoteCheck{false}
33 {
34 this->mainPresenter = mainPresenter;
35 this->view = view;
36 this->mind = mind;
37
38 this->dashboardPresenter = new DashboardPresenter(view->getDashboard(), this);
39 this->organizerPresenter = new OrganizerPresenter(view->getOrganizer(), this);
40 this->tagCloudPresenter = new TagsTablePresenter(view->getTagCloud(), mainPresenter->getHtmlRepresentation());
41 this->outlinesTablePresenter = new OutlinesTablePresenter(view->getOutlinesTable(), mainPresenter->getHtmlRepresentation());
42 this->recentNotesTablePresenter = new RecentNotesTablePresenter(view->getRecentNotesTable(), mainPresenter->getHtmlRepresentation());
43 this->outlineViewPresenter = new OutlineViewPresenter(view->getOutlineView(), this);
44 this->outlineHeaderViewPresenter = new OutlineHeaderViewPresenter(view->getOutlineHeaderView(), this);
45 this->outlineHeaderEditPresenter = new OutlineHeaderEditPresenter(view->getOutlineHeaderEdit(), mainPresenter, this);
46 this->noteViewPresenter = new NoteViewPresenter(view->getNoteView(), this);
47 this->noteEditPresenter = new NoteEditPresenter(view->getNoteEdit(), mainPresenter, this);
48 this->navigatorPresenter = new NavigatorPresenter(view->getNavigator(), this, mind->getKnowledgeGraph());
49
50 /* Orloj presenter WIRES signals and slots between VIEWS and PRESENTERS.
51 *
52 * It's done by Orloj presenter as it has access to all its child windows
53 * and widgets - it can show/hide what's needed and then pass control to children.
54 */
55
56 // hit enter in Os to view O detail
57 QObject::connect(
58 view->getOutlinesTable(),
59 SIGNAL(signalShowSelectedOutline()),
60 this,
61 SLOT(slotShowSelectedOutline()));
62 QObject::connect(
63 view->getDashboard()->getOutlinesDashboardlet(),
64 SIGNAL(signalShowSelectedOutline()),
65 this,
66 SLOT(slotShowSelectedOutline()));
67 QObject::connect(
68 view->getOutlinesTable(),
69 SIGNAL(signalFindOutlineByName()),
70 mainPresenter,
71 SLOT(doActionFindOutlineByName()));
72 // click O tree to view Note
73 QObject::connect(
74 view->getOutlineView()->getOutlineTree()->selectionModel(),
75 SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
76 this,
77 SLOT(slotShowNote(const QItemSelection&, const QItemSelection&)));
78 // hit ENTER in recent Os/Ns to view O/N detail
79 QObject::connect(
80 view->getRecentNotesTable(),
81 SIGNAL(signalShowSelectedRecentNote()),
82 this,
83 SLOT(slotShowSelectedRecentNote()));
84 QObject::connect(
85 view->getDashboard()->getRecentDashboardlet(),
86 SIGNAL(signalShowSelectedRecentNote()),
87 this,
88 SLOT(slotShowSelectedRecentNote()));
89 // hit ENTER in Tags to view Recall by Tag detail
90 QObject::connect(
91 view->getTagCloud(),
92 SIGNAL(signalShowDialogForTag()),
93 this,
94 SLOT(slotShowSelectedTagRecallDialog()));
95 QObject::connect(
96 view->getDashboard()->getTagsDashboardlet(),
97 SIGNAL(signalShowDialogForTag()),
98 this,
99 SLOT(slotShowSelectedTagRecallDialog()));
100 // navigator
101 QObject::connect(
102 navigatorPresenter, SIGNAL(signalOutlineSelected(Outline*)),
103 this, SLOT(slotShowOutlineNavigator(Outline*)));
104 QObject::connect(
105 navigatorPresenter, SIGNAL(signalNoteSelected(Note*)),
106 this, SLOT(slotShowNoteNavigator(Note*)));
107 QObject::connect(
108 navigatorPresenter, SIGNAL(signalThingSelected()),
109 this, SLOT(slotShowNavigator()));
110 // N editor
111 #ifdef __APPLE__
112 QObject::connect(
113 mainPresenter->getMainMenu()->getView()->actionEditComplete, SIGNAL(triggered()),
114 this, SLOT(slotEditStartLinkCompletion()));
115 #endif
116 // editor getting data from the backend
117 QObject::connect(
118 view->getNoteEdit()->getNoteEditor(), SIGNAL(signalGetLinksForPattern(const QString&)),
119 this, SLOT(slotGetLinksForPattern(const QString&)));
120 QObject::connect(
121 this, SIGNAL(signalLinksForPattern(const QString&, std::vector<std::string>*)),
122 view->getNoteEdit()->getNoteEditor(), SLOT(slotPerformLinkCompletion(const QString&, std::vector<std::string>*)));
123 QObject::connect(
124 view->getOutlineHeaderEdit()->getHeaderEditor(), SIGNAL(signalGetLinksForPattern(const QString&)),
125 this, SLOT(slotGetLinksForPattern(const QString&)));
126 QObject::connect(
127 this, SIGNAL(signalLinksForHeaderPattern(const QString&, std::vector<std::string>*)),
128 view->getOutlineHeaderEdit()->getHeaderEditor(), SLOT(slotPerformLinkCompletion(const QString&, std::vector<std::string>*)));
129 QObject::connect(
130 outlineHeaderEditPresenter->getView()->getButtonsPanel(), SIGNAL(signalShowLivePreview()),
131 mainPresenter, SLOT(doActionToggleLiveNotePreview()));
132 QObject::connect(
133 noteEditPresenter->getView()->getButtonsPanel(), SIGNAL(signalShowLivePreview()),
134 mainPresenter, SLOT(doActionToggleLiveNotePreview()));
135 // intercept Os table column sorting
136 QObject::connect(
137 view->getOutlinesTable()->horizontalHeader(), SIGNAL(sectionClicked(int)),
138 this, SLOT(slotOutlinesTableSorted(int)));
139 // toggle full O HTML preview
140 QObject::connect(
141 view->getOutlineHeaderView()->getEditPanel()->getFullOPreviewButton(), SIGNAL(clicked()),
142 this, SLOT(slotToggleFullOutlinePreview()));
143 }
144
dialogSaveOrCancel()145 int dialogSaveOrCancel()
146 {
147 // l10n by moving this dialog either to Qt class OR view class
148 QMessageBox msgBox{
149 QMessageBox::Question,
150 "Save Note",
151 "Do you want to save Note changes?"};
152 QPushButton* discard = msgBox.addButton("&Discard changes", QMessageBox::DestructiveRole);
153 QPushButton* autosave = msgBox.addButton("Do not ask && &autosave", QMessageBox::AcceptRole);
154 QPushButton* edit = msgBox.addButton("Continue &editing", QMessageBox::YesRole);
155 QPushButton* save = msgBox.addButton("&Save", QMessageBox::ActionRole);
156 msgBox.exec();
157
158 QAbstractButton* choosen = msgBox.clickedButton();
159 if(discard == choosen) {
160 return OrlojButtonRoles::DISCARD_ROLE;
161 } else if(autosave == choosen) {
162 return OrlojButtonRoles::AUTOSAVE_ROLE;
163 } else if(edit == choosen) {
164 return OrlojButtonRoles::EDIT_ROLE;
165 } else if(save == choosen) {
166 return OrlojButtonRoles::SAVE_ROLE;
167 }
168
169 return OrlojButtonRoles::INVALID_ROLE;
170 }
171
onFacetChange(const OrlojPresenterFacets targetFacet) const172 void OrlojPresenter::onFacetChange(const OrlojPresenterFacets targetFacet) const
173 {
174 MF_DEBUG("Facet CHANGE: " << activeFacet << " > " << targetFacet << endl);
175
176 if(activeFacet == OrlojPresenterFacets::FACET_NAVIGATOR) {
177 navigatorPresenter->cleanupBeforeHide();
178 } else if(targetFacet == OrlojPresenterFacets::FACET_VIEW_OUTLINE) {
179 outlineViewPresenter->getOutlineTree()->focus();
180 }
181 }
182
showFacetRecentNotes(const vector<Note * > & notes)183 void OrlojPresenter::showFacetRecentNotes(const vector<Note*>& notes)
184 {
185 setFacet(OrlojPresenterFacets::FACET_RECENT_NOTES);
186 recentNotesTablePresenter->refresh(notes);
187 view->showFacetRecentNotes();
188 mainPresenter->getStatusBar()->showMindStatistics();
189 }
190
showFacetDashboard()191 void OrlojPresenter::showFacetDashboard() {
192 setFacet(OrlojPresenterFacets::FACET_DASHBOARD);
193
194 vector<Note*> allNotes{};
195 mind->getAllNotes(allNotes, true, true);
196 map<const Tag*,int> allTags{};
197 mind->getTagsCardinality(allTags);
198
199 dashboardPresenter->refresh(
200 mind->getOutlines(),
201 allNotes,
202 allTags,
203 mind->remind().getOutlineMarkdownsSize(),
204 mind->getStatistics()
205 );
206 view->showFacetDashboard();
207 mainPresenter->getMainMenu()->showFacetDashboard();
208 mainPresenter->getStatusBar()->showMindStatistics();
209 }
210
showFacetOrganizer(const vector<Outline * > & outlines)211 void OrlojPresenter::showFacetOrganizer(const vector<Outline*>& outlines)
212 {
213 setFacet(OrlojPresenterFacets::FACET_ORGANIZER);
214 organizerPresenter->refresh(outlines);
215 view->showFacetOrganizer();
216 mainPresenter->getMainMenu()->showFacetOrganizer();
217 mainPresenter->getStatusBar()->showMindStatistics();
218 }
219
showFacetKnowledgeGraphNavigator()220 void OrlojPresenter::showFacetKnowledgeGraphNavigator()
221 {
222 switch(activeFacet) {
223 case OrlojPresenterFacets::FACET_VIEW_OUTLINE_HEADER:
224 case OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER:
225 case OrlojPresenterFacets::FACET_VIEW_OUTLINE:
226 setFacet(OrlojPresenterFacets::FACET_NAVIGATOR);
227 navigatorPresenter->showInitialView(outlineViewPresenter->getCurrentOutline());
228 slotShowOutlineNavigator(outlineViewPresenter->getCurrentOutline());
229 break;
230 case OrlojPresenterFacets::FACET_VIEW_NOTE:
231 setFacet(OrlojPresenterFacets::FACET_NAVIGATOR);
232 navigatorPresenter->showInitialView(noteViewPresenter->getCurrentNote());
233 slotShowNoteNavigator(noteViewPresenter->getCurrentNote());
234 break;
235 case OrlojPresenterFacets::FACET_EDIT_NOTE:
236 setFacet(OrlojPresenterFacets::FACET_NAVIGATOR);
237 navigatorPresenter->showInitialView(noteEditPresenter->getCurrentNote());
238 slotShowNoteNavigator(noteEditPresenter->getCurrentNote());
239 break;
240 case OrlojPresenterFacets::FACET_TAG_CLOUD:
241 setFacet(OrlojPresenterFacets::FACET_NAVIGATOR);
242 navigatorPresenter->showInitialViewTags();
243 view->showFacetNavigator();
244 break;
245 default:
246 setFacet(OrlojPresenterFacets::FACET_NAVIGATOR);
247 navigatorPresenter->showInitialView();
248 view->showFacetNavigator();
249 break;
250 }
251
252 mainPresenter->getMainMenu()->showFacetNavigator();
253 mainPresenter->getStatusBar()->showMindStatistics();
254 }
255
showFacetOutlineList(const vector<Outline * > & outlines)256 void OrlojPresenter::showFacetOutlineList(const vector<Outline*>& outlines)
257 {
258 setFacet(OrlojPresenterFacets::FACET_LIST_OUTLINES);
259 // IMPROVE reload ONLY if dirty, otherwise just show
260 outlinesTablePresenter->refresh(outlines);
261 view->showFacetOutlines();
262 mainPresenter->getMainMenu()->showFacetOutlineList();
263 mainPresenter->getStatusBar()->showMindStatistics();
264 }
265
slotShowOutlines()266 void OrlojPresenter::slotShowOutlines()
267 {
268 showFacetOutlineList(mind->getOutlines());
269 }
270
showFacetOutline(Outline * outline)271 void OrlojPresenter::showFacetOutline(Outline* outline)
272 {
273 if(activeFacet == OrlojPresenterFacets::FACET_NAVIGATOR) {
274 outlineHeaderViewPresenter->refresh(outline);
275 view->showFacetNavigatorOutline();
276 } else {
277 setFacet(OrlojPresenterFacets::FACET_VIEW_OUTLINE);
278
279 outlineViewPresenter->refresh(outline);
280 outlineHeaderViewPresenter->refresh(outline);
281 view->showFacetOutlineHeaderView();
282 }
283
284 outline->incReads();
285 outline->makeDirty();
286
287 mainPresenter->getMainMenu()->showFacetOutlineView();
288
289 mainPresenter->getStatusBar()->showInfo(QString("Notebook '%1' %2").arg(outline->getName().c_str()).arg(outline->getKey().c_str()));
290 }
291
slotShowSelectedOutline()292 void OrlojPresenter::slotShowSelectedOutline()
293 {
294 if(activeFacet!=OrlojPresenterFacets::FACET_ORGANIZER
295 &&
296 activeFacet!=OrlojPresenterFacets::FACET_TAG_CLOUD
297 &&
298 activeFacet!=OrlojPresenterFacets::FACET_NAVIGATOR
299 &&
300 activeFacet!=OrlojPresenterFacets::FACET_RECENT_NOTES
301 )
302 {
303 int row;
304 if(activeFacet==OrlojPresenterFacets::FACET_DASHBOARD) {
305 row = dashboardPresenter->getOutlinesPresenter()->getCurrentRow();
306 } else {
307 row = outlinesTablePresenter->getCurrentRow();
308 }
309 if(row != OutlinesTablePresenter::NO_ROW) {
310 QStandardItem* item;
311 if(activeFacet==OrlojPresenterFacets::FACET_DASHBOARD) {
312 item = dashboardPresenter->getOutlinesPresenter()->getModel()->item(row);
313 } else {
314 item = outlinesTablePresenter->getModel()->item(row);
315 }
316 // TODO introduce name my user role - replace constant with my enum name > do it for whole file e.g. MfDataRole
317 if(item) {
318 Outline* outline = item->data(Qt::UserRole + 1).value<Outline*>();
319 showFacetOutline(outline);
320 return;
321 } else {
322 mainPresenter->getStatusBar()->showInfo(QString(tr("Selected Notebook not found!")));
323 }
324 }
325 mainPresenter->getStatusBar()->showInfo(QString(tr("No Notebook selected!")));
326 }
327 }
328
slotShowOutline(const QItemSelection & selected,const QItemSelection & deselected)329 void OrlojPresenter::slotShowOutline(const QItemSelection& selected, const QItemSelection& deselected)
330 {
331 Q_UNUSED(deselected);
332
333 if(activeFacet!=OrlojPresenterFacets::FACET_ORGANIZER
334 &&
335 activeFacet!=OrlojPresenterFacets::FACET_TAG_CLOUD
336 &&
337 activeFacet!=OrlojPresenterFacets::FACET_NAVIGATOR
338 &&
339 activeFacet!=OrlojPresenterFacets::FACET_RECENT_NOTES
340 )
341 {
342 QModelIndexList indices = selected.indexes();
343 if(indices.size()) {
344 const QModelIndex& index = indices.at(0);
345 QStandardItem* item = outlinesTablePresenter->getModel()->itemFromIndex(index);
346 // TODO introduce name my user role - replace constant with my enum name > do it for whole file e.g. MfDataRole
347 Outline* outline = item->data(Qt::UserRole + 1).value<Outline*>();
348 showFacetOutline(outline);
349 } else {
350 mainPresenter->getStatusBar()->showInfo(QString(tr("No Notebook selected!")));
351 }
352 }
353 }
354
showFacetTagCloud()355 void OrlojPresenter::showFacetTagCloud()
356 {
357 setFacet(OrlojPresenterFacets::FACET_TAG_CLOUD);
358
359 map<const Tag*,int> tags{};
360 mind->getTagsCardinality(tags);
361 tagCloudPresenter->refresh(tags);
362
363 view->showFacetTagCloud();
364
365 mainPresenter->getStatusBar()->showInfo(QString("%2 Tags").arg(tags.size()));
366 }
367
slotShowSelectedTagRecallDialog()368 void OrlojPresenter::slotShowSelectedTagRecallDialog()
369 {
370 if(activeFacet == OrlojPresenterFacets::FACET_TAG_CLOUD
371 ||
372 activeFacet == OrlojPresenterFacets::FACET_DASHBOARD
373 )
374 {
375 int row;
376 if(activeFacet==OrlojPresenterFacets::FACET_DASHBOARD) {
377 row = dashboardPresenter->getTagsPresenter()->getCurrentRow();
378 } else {
379 row = tagCloudPresenter->getCurrentRow();
380 }
381 if(row != OutlinesTablePresenter::NO_ROW) {
382 QStandardItem* item;
383 switch(activeFacet) {
384 case OrlojPresenterFacets::FACET_TAG_CLOUD:
385 item = tagCloudPresenter->getModel()->item(row);
386 break;
387 case OrlojPresenterFacets::FACET_DASHBOARD:
388 item = dashboardPresenter->getTagsPresenter()->getModel()->item(row);
389 break;
390 default:
391 item = nullptr;
392 }
393 // TODO introduce name my user role - replace constant with my enum name > do it for whole file e.g. MfDataRole
394 if(item) {
395 const Tag* tag = item->data(Qt::UserRole + 1).value<const Tag*>();
396 mainPresenter->doTriggerFindNoteByTag(tag);
397 } else {
398 mainPresenter->getStatusBar()->showInfo(QString(tr("Selected Tag not found!")));
399 }
400 } else {
401 mainPresenter->getStatusBar()->showInfo(QString(tr("No Tag selected!")));
402 }
403 }
404 }
405
slotShowTagRecallDialog(const QItemSelection & selected,const QItemSelection & deselected)406 void OrlojPresenter::slotShowTagRecallDialog(const QItemSelection& selected, const QItemSelection& deselected)
407 {
408 Q_UNUSED(deselected);
409
410 if(activeFacet == OrlojPresenterFacets::FACET_TAG_CLOUD
411 ||
412 activeFacet == OrlojPresenterFacets::FACET_DASHBOARD
413 )
414 {
415 QModelIndexList indices = selected.indexes();
416 if(indices.size()) {
417 const QModelIndex& index = indices.at(0);
418 QStandardItem* item;
419 // TODO if 2 switch
420 if(activeFacet == OrlojPresenterFacets::FACET_TAG_CLOUD) {
421 item = tagCloudPresenter->getModel()->itemFromIndex(index);
422 } else {
423 item = dashboardPresenter->getTagsPresenter()->getModel()->itemFromIndex(index);
424 }
425 // TODO introduce name my user role - replace constant with my enum name > do it for whole file e.g. MfDataRole
426 const Tag* tag = item->data(Qt::UserRole + 1).value<const Tag*>();
427 mainPresenter->doTriggerFindNoteByTag(tag);
428 } else {
429 mainPresenter->getStatusBar()->showInfo(QString(tr("No Tag selected!")));
430 }
431 }
432 }
433
showFacetNoteView()434 void OrlojPresenter::showFacetNoteView()
435 {
436 view->showFacetNoteView();
437 mainPresenter->getMainMenu()->showFacetOutlineView();
438 setFacet(OrlojPresenterFacets::FACET_VIEW_NOTE);
439 }
440
showFacetNoteView(Note * note)441 void OrlojPresenter::showFacetNoteView(Note* note)
442 {
443 if(activeFacet == OrlojPresenterFacets::FACET_NAVIGATOR) {
444 noteViewPresenter->refresh(note);
445 view->showFacetNavigatorNote();
446 mainPresenter->getMainMenu()->showFacetOutlineView();
447 } else {
448 if(outlineViewPresenter->getCurrentOutline()!=note->getOutline()) {
449 showFacetOutline(note->getOutline());
450 }
451 noteViewPresenter->refresh(note);
452 view->showFacetNoteView();
453 outlineViewPresenter->selectRowByNote(note);
454 mainPresenter->getMainMenu()->showFacetOutlineView();
455
456 setFacet(OrlojPresenterFacets::FACET_VIEW_NOTE);
457 }
458
459 QString p{note->getOutline()->getKey().c_str()};
460 p += "#";
461 p += note->getMangledName().c_str();
462 mainPresenter->getStatusBar()->showInfo(QString(tr("Note '%1' %2")).arg(note->getName().c_str()).arg(p));
463 }
464
showFacetNoteEdit(Note * note)465 void OrlojPresenter::showFacetNoteEdit(Note* note)
466 {
467 if(activeFacet == OrlojPresenterFacets::FACET_NAVIGATOR) {
468 outlineViewPresenter->refresh(note->getOutline());
469 }
470
471 noteEditPresenter->setNote(note);
472 view->showFacetNoteEdit();
473 setFacet(OrlojPresenterFacets::FACET_EDIT_NOTE);
474 mainPresenter->getMainMenu()->showFacetNoteEdit();
475
476 // refresh live preview to ensure on/off autolinking, full O vs. header, ...
477 if(config.isUiLiveNotePreview()) {
478 noteViewPresenter->refreshLivePreview();
479 }
480 }
481
showFacetOutlineHeaderEdit(Outline * outline)482 void OrlojPresenter::showFacetOutlineHeaderEdit(Outline* outline)
483 {
484 if(activeFacet == OrlojPresenterFacets::FACET_NAVIGATOR) {
485 outlineViewPresenter->refresh(outline);
486 }
487
488 outlineHeaderEditPresenter->setOutline(outline);
489 view->showFacetOutlineHeaderEdit();
490 setFacet(OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER);
491 mainPresenter->getMainMenu()->showFacetNoteEdit();
492
493 // refresh live preview to ensure on/off autolinking, full O vs. header, ...
494 if(config.isUiLiveNotePreview()) {
495 outlineHeaderViewPresenter->refreshLivePreview();
496 }
497 }
498
applyFacetHoisting()499 bool OrlojPresenter::applyFacetHoisting()
500 {
501 if(Configuration::getInstance().isUiHoistedMode()) {
502 if(isFacetActive(OrlojPresenterFacets::FACET_VIEW_OUTLINE)
503 ||
504 isFacetActive(OrlojPresenterFacets::FACET_VIEW_OUTLINE_HEADER))
505 {
506 view->showFacetHoistedOutlineHeaderView();
507 } else if(isFacetActive(OrlojPresenterFacets::FACET_VIEW_NOTE)) {
508 view->showFacetHoistedNoteView();
509 } else if(isFacetActive(OrlojPresenterFacets::FACET_EDIT_NOTE)) {
510 view->showFacetHoistedNoteEdit();
511 } else if(isFacetActive(OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER)) {
512 view->showFacetHoistedOutlineHeaderEdit();
513 }
514
515 return false;
516 } else {
517 if(isFacetActive(OrlojPresenterFacets::FACET_VIEW_OUTLINE)
518 ||
519 isFacetActive(OrlojPresenterFacets::FACET_VIEW_OUTLINE_HEADER))
520 {
521 view->showFacetOutlineHeaderView();
522 } else if(isFacetActive(OrlojPresenterFacets::FACET_VIEW_NOTE)) {
523 view->showFacetNoteView();
524 } else if(isFacetActive(OrlojPresenterFacets::FACET_EDIT_NOTE)) {
525 view->showFacetNoteEdit();
526 } else if(isFacetActive(OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER)) {
527 view->showFacetOutlineHeaderEdit();
528 }
529
530 return true;
531 }
532 }
533
fromOutlineHeaderEditBackToView(Outline * outline)534 void OrlojPresenter::fromOutlineHeaderEditBackToView(Outline* outline)
535 {
536 // LEFT: update O name above Ns tree
537 outlineViewPresenter->refresh(outline->getName());
538 // RIGHT
539 outlineHeaderViewPresenter->refresh(outline);
540 view->showFacetOutlineHeaderView();
541 setFacet(OrlojPresenterFacets::FACET_VIEW_OUTLINE_HEADER);
542 mainPresenter->getMainMenu()->showFacetOutlineView();
543 }
544
fromNoteEditBackToView(Note * note)545 void OrlojPresenter::fromNoteEditBackToView(Note* note)
546 {
547 noteViewPresenter->clearSearchExpression();
548 noteViewPresenter->refresh(note);
549 // update N in the tree
550 outlineViewPresenter->refresh(note);
551
552 showFacetNoteView();
553 }
554
avoidDataLossOnNoteEdit()555 bool OrlojPresenter::avoidDataLossOnNoteEdit()
556 {
557 // avoid lost of N editor changes
558 if(skipEditNoteCheck) {
559 skipEditNoteCheck=false;
560 if(activeFacet == OrlojPresenterFacets::FACET_EDIT_NOTE) {
561 noteEditPresenter->getView()->getNoteEditor()->setFocus();
562 } else if(activeFacet == OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER) {
563 outlineHeaderEditPresenter->getView()->getHeaderEditor()->setFocus();
564 }
565 return true;
566 } else {
567 if(activeFacet == OrlojPresenterFacets::FACET_EDIT_NOTE) {
568 int decision{};
569 if(Configuration::getInstance().isUiEditorAutosave()) {
570 decision = OrlojButtonRoles::SAVE_ROLE;
571 } else {
572 decision = dialogSaveOrCancel();
573 }
574
575 switch(decision) {
576 case OrlojButtonRoles::DISCARD_ROLE:
577 // do nothing
578 break;
579 case OrlojButtonRoles::AUTOSAVE_ROLE:
580 Configuration::getInstance().setUiEditorAutosave(true);
581 mainPresenter->getConfigRepresentation()->save(Configuration::getInstance());
582 MF_FALL_THROUGH;
583 case OrlojButtonRoles::SAVE_ROLE:
584 noteEditPresenter->slotSaveNote();
585 break;
586 case OrlojButtonRoles::EDIT_ROLE:
587 MF_FALL_THROUGH;
588 default:
589 // rollback ~ select previous N and continue
590 // ugly & stupid hack to disable signal emitted on N selection in O tree
591 skipEditNoteCheck=true;
592 outlineViewPresenter->selectRowByNote(noteEditPresenter->getCurrentNote());
593 return true;
594 }
595 } else if(activeFacet == OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER) {
596 int decision = dialogSaveOrCancel();
597 switch(decision) {
598 case OrlojButtonRoles::DISCARD_ROLE:
599 // do nothing
600 break;
601 case OrlojButtonRoles::AUTOSAVE_ROLE:
602 Configuration::getInstance().setUiEditorAutosave(true);
603 mainPresenter->getConfigRepresentation()->save(Configuration::getInstance());
604 MF_FALL_THROUGH;
605 case OrlojButtonRoles::SAVE_ROLE:
606 outlineHeaderEditPresenter->slotSaveOutlineHeader();
607 break;
608 case OrlojButtonRoles::EDIT_ROLE:
609 MF_FALL_THROUGH;
610 default:
611 // rollback ~ select previous N and continue
612 // ugly & stupid hack to disable signal emitted on N selection in O tree
613 skipEditNoteCheck=true;
614 outlineViewPresenter->getOutlineTree()->clearSelection();
615 return true;
616 }
617 }
618 }
619
620 return false;
621 }
622
slotShowOutlineHeader()623 void OrlojPresenter::slotShowOutlineHeader()
624 {
625 if(avoidDataLossOnNoteEdit()) return;
626
627 // refresh header
628 outlineHeaderViewPresenter->refresh(outlineViewPresenter->getCurrentOutline());
629 setFacet(OrlojPresenterFacets::FACET_VIEW_OUTLINE_HEADER);
630 view->showFacetOutlineHeaderView();
631 }
632
slotShowNote(const QItemSelection & selected,const QItemSelection & deselected)633 void OrlojPresenter::slotShowNote(const QItemSelection& selected, const QItemSelection& deselected)
634 {
635 Q_UNUSED(deselected);
636
637 if(avoidDataLossOnNoteEdit()) return;
638
639 QModelIndexList indices = selected.indexes();
640 if(indices.size()) {
641 const QModelIndex& index = indices.at(0);
642 QStandardItem* item
643 = outlineViewPresenter->getOutlineTree()->getModel()->itemFromIndex(index);
644 // IMPROVE make my role constant
645 Note* note = item->data(Qt::UserRole + 1).value<Note*>();
646
647 note->incReads();
648 note->makeDirty();
649
650 showFacetNoteView(note);
651 } else {
652 Outline* outline = outlineViewPresenter->getCurrentOutline();
653 mainPresenter->getStatusBar()->showInfo(QString("Notebook '%1' %2").arg(outline->getName().c_str()).arg(outline->getKey().c_str()));
654 }
655 }
656
slotShowNavigator()657 void OrlojPresenter::slotShowNavigator()
658 {
659 view->showFacetNavigator();
660 }
661
slotShowNoteNavigator(Note * note)662 void OrlojPresenter::slotShowNoteNavigator(Note* note)
663 {
664 if(note) {
665 note->incReads();
666 note->makeDirty();
667
668 showFacetNoteView(note);
669 }
670 }
671
slotShowOutlineNavigator(Outline * outline)672 void OrlojPresenter::slotShowOutlineNavigator(Outline* outline)
673 {
674 if(outline) {
675 // timestamps are updated by O header view
676 showFacetOutline(outline);
677 }
678 }
679
680 /**
681 * @brief Return MD links for given O/N name prefix (pattern).
682 *
683 * For example 'Mi' > { '[MindForger](mf/projects.md#mind-forger)', '[Middle](mf/places.md#middle) }'
684 */
slotGetLinksForPattern(const QString & pattern)685 void OrlojPresenter::slotGetLinksForPattern(const QString& pattern)
686 {
687 vector<Thing*> allThings{};
688 vector<string> thingsNames = vector<string>{};
689 string prefix{pattern.toStdString()};
690
691 Outline* currentOutline;
692 if(activeFacet == OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER) {
693 currentOutline = outlineHeaderEditPresenter->getCurrentOutline();
694 } else {
695 currentOutline = noteEditPresenter->getCurrentNote()->getOutline();
696 }
697
698 mind->getAllThings(
699 allThings,
700 &thingsNames,
701 &prefix,
702 ThingNameSerialization::LINK,
703 currentOutline);
704
705 vector<string>* links = new vector<string>{};
706 *links = thingsNames;
707
708 if(activeFacet == OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER) {
709 emit signalLinksForHeaderPattern(pattern, links);
710 } else {
711 emit signalLinksForPattern(pattern, links);
712 }
713 }
714
slotShowSelectedRecentNote()715 void OrlojPresenter::slotShowSelectedRecentNote()
716 {
717 if(activeFacet == OrlojPresenterFacets::FACET_RECENT_NOTES
718 ||
719 activeFacet == OrlojPresenterFacets::FACET_DASHBOARD
720 )
721 {
722 int row;
723 if(activeFacet==OrlojPresenterFacets::FACET_DASHBOARD) {
724 row = dashboardPresenter->getRecentNotesPresenter()->getCurrentRow();
725 } else {
726 row = recentNotesTablePresenter->getCurrentRow();
727 }
728 if(row != RecentNotesTablePresenter::NO_ROW) {
729 QStandardItem* item;
730 switch(activeFacet) {
731 case OrlojPresenterFacets::FACET_RECENT_NOTES:
732 item = recentNotesTablePresenter->getModel()->item(row);
733 break;
734 case OrlojPresenterFacets::FACET_DASHBOARD:
735 item = dashboardPresenter->getRecentNotesPresenter()->getModel()->item(row);
736 break;
737 default:
738 item = nullptr;
739 }
740 // TODO make my role constant
741 if(item) {
742 const Note* note = item->data(Qt::UserRole + 1).value<const Note*>();
743
744 showFacetOutline(note->getOutline());
745 if(note->getType() != note->getOutline()->getOutlineDescriptorNoteType()) {
746 // IMPROVE make this more efficient
747 showFacetNoteView();
748 getOutlineView()->selectRowByNote(note);
749 }
750 mainPresenter->getStatusBar()->showInfo(QString(tr("Note "))+QString::fromStdString(note->getName()));
751 } else {
752 mainPresenter->getStatusBar()->showInfo(QString(tr("Selected Notebook/Note not found!")));
753 }
754 } else {
755 mainPresenter->getStatusBar()->showInfo(QString(tr("No Note selected!")));
756 }
757 }
758 }
759
slotShowRecentNote(const QItemSelection & selected,const QItemSelection & deselected)760 void OrlojPresenter::slotShowRecentNote(const QItemSelection& selected, const QItemSelection& deselected)
761 {
762 Q_UNUSED(deselected);
763
764 if(activeFacet == OrlojPresenterFacets::FACET_RECENT_NOTES
765 ||
766 activeFacet == OrlojPresenterFacets::FACET_DASHBOARD
767 )
768 {
769 QModelIndexList indices = selected.indexes();
770 if(indices.size()) {
771 const QModelIndex& index = indices.at(0);
772 QStandardItem* item;
773 if(activeFacet == OrlojPresenterFacets::FACET_RECENT_NOTES) {
774 item = recentNotesTablePresenter->getModel()->itemFromIndex(index);
775 } else {
776 item = dashboardPresenter->getRecentNotesPresenter()->getModel()->itemFromIndex(index);
777 }
778 // TODO make my role constant
779 const Note* note = item->data(Qt::UserRole + 1).value<const Note*>();
780
781 showFacetOutline(note->getOutline());
782 if(note->getType() != note->getOutline()->getOutlineDescriptorNoteType()) {
783 // IMPROVE make this more efficient
784 showFacetNoteView();
785 getOutlineView()->selectRowByNote(note);
786 }
787 mainPresenter->getStatusBar()->showInfo(QString(tr("Note "))+QString::fromStdString(note->getName()));
788 } else {
789 mainPresenter->getStatusBar()->showInfo(QString(tr("No Note selected!")));
790 }
791 }
792 }
793
refreshLiveNotePreview()794 void OrlojPresenter::refreshLiveNotePreview()
795 {
796 if(isFacetActive(OrlojPresenterFacets::FACET_EDIT_NOTE)) {
797 view->showFacetNoteEdit();
798 } else if(isFacetActive(OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER)) {
799 view->showFacetOutlineHeaderEdit();
800 }
801 }
802
slotEditStartLinkCompletion()803 void OrlojPresenter::slotEditStartLinkCompletion()
804 {
805 if(isFacetActive(OrlojPresenterFacets::FACET_EDIT_NOTE)) {
806 view->getNoteEdit()->getNoteEditor()->slotStartLinkCompletion();
807 } else if(isFacetActive(OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER)) {
808 view->getOutlineHeaderEdit()->getHeaderEditor()->slotStartLinkCompletion();
809 }
810 }
811
slotRefreshCurrentNotePreview()812 void OrlojPresenter::slotRefreshCurrentNotePreview()
813 {
814 MF_DEBUG("Slot to refresh live preview: " << getFacet() << " hoist: " << config.isUiHoistedMode() << endl);
815 if(!config.isUiHoistedMode()) {
816 if(isFacetActive(OrlojPresenterFacets::FACET_EDIT_NOTE)) {
817 noteViewPresenter->refreshLivePreview();
818 #if defined(__APPLE__) || defined(_WIN32)
819 getNoteEdit()->getView()->getNoteEditor()->setFocus();
820 #endif
821 } else if(isFacetActive(OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER)) {
822 outlineHeaderViewPresenter->refreshLivePreview();
823 #if defined(__APPLE__) || defined(_WIN32)
824 getOutlineHeaderEdit()->getView()->getHeaderEditor()->setFocus();
825 #endif
826 }
827 }
828 }
829
slotOutlinesTableSorted(int column)830 void OrlojPresenter::slotOutlinesTableSorted(int column)
831 {
832 Qt::SortOrder order
833 = view->getOutlinesTable()->horizontalHeader()->sortIndicatorOrder();
834 MF_DEBUG("Os table sorted: " << column << " descending: " << order << endl);
835
836 config.setUiOsTableSortColumn(column);
837 config.setUiOsTableSortOrder(order==Qt::SortOrder::AscendingOrder?true:false);
838 mainPresenter->getConfigRepresentation()->save(config);
839 }
840
slotToggleFullOutlinePreview()841 void OrlojPresenter::slotToggleFullOutlinePreview()
842 {
843 config.setUiFullOPreview(!config.isUiFullOPreview());
844 mainPresenter->getConfigRepresentation()->save(config);
845
846 // refresh O header view
847 getOutlineHeaderView()->refreshCurrent();
848 }
849
850 } // m8r namespace
851