]> git.sven.stormbind.net Git - sven/vym.git/blob - src/treeitem.cpp
Replace Pierre as the maintainer
[sven/vym.git] / src / treeitem.cpp
1 #include <QStringList>
2 #include <iostream>
3
4 #include "attributeitem.h"
5 #include "branchitem.h"
6 #include "branchobj.h"
7 #include "misc.h"
8 #include "treeitem.h"
9 #include "vymmodel.h"
10 #include "xlinkitem.h"
11 #include "xlinkobj.h"
12
13 using namespace std;
14
15 extern ulong itemLastID;
16 extern FlagRowMaster *standardFlagsMaster;
17 extern FlagRowMaster *systemFlagsMaster;
18 extern FlagRowMaster *userFlagsMaster;
19
20 extern QTextStream vout;
21
22 TreeItem::TreeItem(TreeItem *parent)
23 {
24     // qDebug() << "Constructor TreeItem this=" << this << "  parent=" << parent;
25     init();
26     parentItem = parent;
27
28     rootItem = this;
29     if (parentItem)
30         rootItem = parentItem->rootItem;
31 }
32
33 TreeItem::~TreeItem()
34 {
35     // qDebug()<<"Destr TreeItem this="<<this<<"
36     // childcount="<<childItems.count();
37     TreeItem *ti;
38     while (!childItems.isEmpty()) {
39         ti = childItems.takeFirst();
40         delete ti;
41     }
42 }
43
44 void TreeItem::init()
45 {
46     model = NULL;
47
48     // Assign ID
49     itemLastID++;
50     itemID = itemLastID;
51     uuid = QUuid::createUuid();
52
53     branchOffset = 0;
54     branchCounter = 0;
55
56     imageOffset = 0;
57     imageCounter = 0;
58
59     attributeCounter = 0;
60     attributeOffset = 0;
61
62     xlinkCounter = 0;
63     xlinkOffset = 0;
64
65     target = false;
66
67     heading.clear();
68     heading.setText(" ");
69     note.setText("");
70
71     hidden = false;
72     hideExport = false;
73
74     itemData.clear();
75     itemData << "";
76
77     backgroundColor = Qt::transparent;
78
79     standardFlags.setMasterRow(standardFlagsMaster);
80     userFlags.setMasterRow(userFlagsMaster);
81     systemFlags.setMasterRow(systemFlagsMaster);
82 }
83
84 void TreeItem::setModel(VymModel *m) { model = m; }
85
86 VymModel *TreeItem::getModel() { return model; }
87
88 int TreeItem::getRowNumAppend(TreeItem *item)
89 {
90     switch (item->type) {
91     case Attribute:
92         return attributeOffset + attributeCounter;
93     case XLink:
94         return xlinkOffset + xlinkCounter;
95     case Image:
96         return imageOffset + imageCounter;
97     case MapCenter:
98         return branchOffset + branchCounter;
99     case Branch:
100         return branchOffset + branchCounter;
101     default:
102         return -1;
103     }
104 }
105
106 void TreeItem::appendChild(TreeItem *item)
107 {
108     item->parentItem = this;
109     item->rootItem = rootItem;
110     item->setModel(model);
111
112     if (item->type == Attribute) {
113         // attribute are on top of list
114         childItems.insert(attributeCounter, item);
115         attributeCounter++;
116         xlinkOffset++;
117         imageOffset++;
118         branchOffset++;
119     }
120
121     if (item->type == XLink) {
122         childItems.insert(xlinkCounter + xlinkOffset, item);
123         xlinkCounter++;
124         imageOffset++;
125         branchOffset++;
126     }
127
128     if (item->type == Image) {
129         childItems.insert(imageCounter + imageOffset, item);
130         imageCounter++;
131         branchOffset++;
132     }
133
134     if (item->isBranchLikeType()) {
135         // branches are on bottom of list
136         childItems.append(item);
137         branchCounter++;
138
139         // Set correct type
140         if (this == rootItem)
141             item->setType(MapCenter);
142         else
143             item->setType(Branch);
144     }
145 }
146
147 void TreeItem::removeChild(int row)
148 {
149     if (row < 0 || row > childItems.size() - 1)
150         qWarning("TreeItem::removeChild tried to remove non existing item?!");
151     else {
152         if (childItems.at(row)->type == Attribute) {
153             attributeCounter--;
154             xlinkOffset--;
155             imageOffset--;
156             branchOffset--;
157         }
158         if (childItems.at(row)->type == XLink) {
159             xlinkCounter--;
160             imageOffset--;
161             branchOffset--;
162         }
163         if (childItems.at(row)->type == Image) {
164             imageCounter--;
165             branchOffset--;
166         }
167         if (childItems.at(row)->isBranchLikeType())
168             branchCounter--;
169
170         childItems.removeAt(row);
171     }
172 }
173
174 TreeItem *TreeItem::child(int row) { return childItems.value(row); }
175
176 int TreeItem::childCount() const { return childItems.count(); }
177
178 int TreeItem::childNumber() const
179 {
180     if (parentItem)
181         return parentItem->childItems.indexOf(const_cast<TreeItem *>(this));
182
183     return 0;
184 }
185
186 int TreeItem::columnCount() const { return 1; }
187
188 int TreeItem::branchCount() const { return branchCounter; }
189
190 int TreeItem::imageCount() const { return imageCounter; }
191
192 int TreeItem::xlinkCount() const { return xlinkCounter; }
193
194 int TreeItem::attributeCount() const { return attributeCounter; }
195
196 int TreeItem::row() const
197 {
198     if (parentItem)
199         return parentItem->childItems.indexOf(const_cast<TreeItem *>(this));
200
201     qDebug() << "TI::row() pI=NULL this=" << this << "  ***************";
202     return 0;
203 }
204
205 int TreeItem::depth()
206 {
207     // Rootitem d=-1
208     // MapCenter d=0
209     int d = -2;
210     TreeItem *ti = this;
211     while (ti != NULL) {
212         ti = ti->parent();
213         d++;
214     }
215     return d;
216 }
217
218 TreeItem *TreeItem::parent()
219 {
220     // qDebug() << "TI::parent of "<<getHeadingStd()<<"  is "<<parentItem;
221     return parentItem;
222 }
223
224 bool TreeItem::isChildOf(TreeItem *ti)
225 {
226     if (this == rootItem)
227         return false;
228     if (parentItem == ti)
229         return true;
230     if (parentItem == rootItem)
231         return false;
232     return parentItem->isChildOf(ti);
233 }
234
235 int TreeItem::childNum() { return parentItem->childItems.indexOf(this); }
236
237 int TreeItem::num()
238 {
239     if (!parentItem)
240         return -1;
241     return parentItem->num(this);
242 }
243
244 int TreeItem::num(TreeItem *item)
245 {
246     if (!item)
247         return -1;
248     if (!childItems.contains(item))
249         return -1;
250     switch (item->getType()) {
251     case MapCenter:
252         return childItems.indexOf(item) - branchOffset;
253     case Branch:
254         return childItems.indexOf(item) - branchOffset;
255     case Image:
256         return childItems.indexOf(item) - imageOffset;
257     case Attribute:
258         return childItems.indexOf(item) - attributeOffset;
259     case XLink:
260         return childItems.indexOf(item) - xlinkOffset;
261     default:
262         return -1;
263     }
264 }
265 void TreeItem::setType(const Type t)
266 {
267     type = t;
268 }
269
270 TreeItem::Type TreeItem::getType()
271 {
272     if (type == Branch && depth() == 0)
273         return MapCenter; // should not be necesssary
274     return type;
275 }
276
277 bool TreeItem::isBranchLikeType() const
278 {
279     if (type == Branch || type == MapCenter)
280         return true;
281     else
282         return false;
283 }
284
285 QString TreeItem::getTypeName()
286 {
287     switch (type) {
288         case Undefined:
289             return QString("Undefined");
290         case MapCenter:
291             return QString("MapCenter");
292         case Branch:
293             return QString("Branch");
294         case Image:
295             return QString("Image");
296         case Attribute:
297             return QString("Attribute");
298         case XLink:
299             return QString("XLink");
300         default:
301             return QString("TreeItem::getTypeName no typename defined?!");
302     }
303 }
304
305 QVariant TreeItem::data(int column) const { return itemData.value(column); }
306
307 void TreeItem::setHeading(const VymText &vt)
308 {
309     heading = vt;
310     itemData[0] = getHeadingPlain().replace("\n"," "); // used in TreeEditor
311 }
312
313 void TreeItem::setHeadingPlainText(const QString &s)
314 {
315     VymText vt;
316
317     vt.setPlainText(s);
318
319     if (!heading.isRichText())
320         // Keep current color
321         vt.setColor(heading.getColor());
322     setHeading(vt);
323 }
324
325 Heading TreeItem::getHeading() const { return heading; }
326
327 QString TreeItem::getHeadingText() { return heading.getText(); }
328
329 std::string TreeItem::getHeadingStd() const
330 {
331     return getHeadingPlain().toStdString();
332 }
333
334 QString TreeItem::getHeadingPlain() const
335 {
336     // strip beginning and tailing WS
337     return heading.getTextASCII().trimmed();
338 }
339
340 QString TreeItem::getHeadingPlainWithParents(uint numberOfParents = 0)
341 {
342     QString s = getHeadingPlain();
343     if (numberOfParents > 0) {
344         TreeItem *ti = this;
345         int l = numberOfParents;
346         while (l > 0 && ti->depth() > 0) {
347             ti = ti->parent();
348             if (ti)
349                 s = ti->getHeadingPlain() + " -> " + s;
350             else
351                 l = 0;
352             l--;
353         }
354     }
355     return s;
356 }
357
358 QString TreeItem::getHeadingDepth() // Indent by depth for debugging
359 {
360     QString ds;
361     for (int i = 0; i < depth(); i++)
362         ds += "  ";
363     return ds + getHeadingPlain();
364 }
365
366 void TreeItem::setHeadingColor(QColor color) { heading.setColor(color); }
367
368 QColor TreeItem::getHeadingColor() { return heading.getColor(); }
369
370 void TreeItem::setBackgroundColor(QColor color) { backgroundColor = color; }
371
372 void TreeItem::setURL(const QString &u)
373 {
374     url = u;
375     if (!url.isEmpty())
376         systemFlags.activate(QString("system-url"));
377     else
378         systemFlags.deactivate(QString("system-url"));
379 }
380
381 QString TreeItem::getURL() { return url; }
382
383 void TreeItem::setVymLink(const QString &vl)
384 {
385     if (!vl.isEmpty()) {
386         // We need the relative (from loading)
387         // or absolute path (from User event)
388         // and build the absolute path.
389
390         QDir d(vl);
391         if (d.isAbsolute())
392             vymLink = vl;
393         else {
394             // If we have relative, use path of
395             // current map to build absolute path
396             // based on path of current map and relative
397             // path to linked map
398             QString p = dirname(model->getDestPath());
399             vymLink = convertToAbs(p, vl);
400         }
401         systemFlags.activate(QString("system-vymLink"));
402     }
403     else {
404         vymLink.clear();
405         systemFlags.deactivate(QString("system-vymLink"));
406     }
407 }
408
409 QString TreeItem::getVymLink() { return vymLink; }
410
411 void TreeItem::toggleTarget()
412 {
413     systemFlags.toggle(QString("system-target"));
414     target = systemFlags.isActive(QString("system-target"));
415     model->emitDataChanged(this); // FIXME-4 better call from VM?
416 }
417
418 bool TreeItem::isTarget() { return target; }
419
420 bool TreeItem::isNoteEmpty() { return note.isEmpty(); }
421
422 bool TreeItem::clearNote()
423 {
424     note.clear();
425     return systemFlags.deactivate(QString("system-note"));
426 }
427
428 bool TreeItem::setNote(const VymText &vt)
429 {
430     note = vt;
431
432     if (note.isEmpty()) {
433         if (systemFlags.isActive(QString("system-note")))
434             return systemFlags.deactivate(QString("system-note"));
435     }
436     else {
437         if (!systemFlags.isActive(QString("system-note")))
438             return systemFlags.activate(QString("system-note"));
439     }
440     return false; // No need to update flag and reposition later
441 }
442
443 bool TreeItem::setNote(const VymNote &vn) { return setNote((VymText)vn); }
444
445 bool TreeItem::hasEmptyNote() { return note.isEmpty(); }
446
447 VymNote TreeItem::getNote() { return note; }
448
449 QString TreeItem::getNoteASCII(const QString &indent, const int &width)
450 {
451     return note.getTextASCII(indent, width);
452 }
453
454 QString TreeItem::getNoteASCII() { return note.getTextASCII(); }
455
456 void TreeItem::activateStandardFlagByName(const QString &name)
457 {
458     standardFlags.activate(name);
459     //    model->emitDataChanged(this);
460 }
461
462 void TreeItem::deactivateStandardFlagByName(const QString &name)
463 {
464     standardFlags.deactivate(name);
465     //    model->emitDataChanged(this);
466 }
467
468 void TreeItem::deactivateAllStandardFlags()
469 {
470     standardFlags.deactivateAll();
471     userFlags.deactivateAll();
472     //    model->emitDataChanged(this);
473 }
474
475 Flag *TreeItem::findFlagByUid(const QUuid &uid)
476 {
477     Flag *f = standardFlagsMaster->findFlagByUid(uid);
478     if (!f)
479         f = userFlagsMaster->findFlagByUid(uid);
480     return f;
481 }
482
483 Flag *TreeItem::toggleFlagByUid(const QUuid &uid, bool useGroups)
484 {
485     Flag *f = standardFlagsMaster->findFlagByUid(uid);
486     if (f) {
487         standardFlags.toggle(uid, useGroups);
488     }
489     else {
490         f = userFlagsMaster->findFlagByUid(uid);
491         if (f) {
492             userFlags.toggle(uid, useGroups);
493         }
494         else {
495             qWarning() << "TI::toggleFlag failed for flag " << uid;
496             return nullptr;
497         }
498     }
499
500     return f;
501 }
502
503 void TreeItem::toggleSystemFlag(const QString &name, FlagRow *master)
504 {
505     systemFlags.toggle(name, master);
506     model->emitDataChanged(this);
507 }
508
509 bool TreeItem::hasActiveFlag(const QString &name)
510 {
511     return standardFlags.isActive(name);
512 }
513
514 bool TreeItem::hasActiveSystemFlag(const QString &name)
515 {
516     return systemFlags.isActive(name);
517 }
518
519 QList<QUuid> TreeItem::activeFlagUids()
520 {
521     return standardFlags.activeFlagUids() + userFlags.activeFlagUids();
522 }
523
524 QList<QUuid> TreeItem::activeSystemFlagUids()
525 {
526     return systemFlags.activeFlagUids();
527 }
528
529 bool TreeItem::canMoveDown()
530 {
531     switch (type) {
532     case Undefined:
533         return false;
534     case MapCenter:
535     case Branch:
536         if (!parentItem)
537             return false;
538         if (parentItem->num(this) < parentItem->branchCount() - 1)
539             return true;
540         else
541             return false;
542         break;
543     case Image:
544         return false;
545     default:
546         return false;
547     }
548 }
549
550 bool TreeItem::canMoveUp()
551 {
552     switch (type) {
553     case MapCenter:
554     case Branch:
555         if (!parentItem)
556             return false;
557         if (parentItem->num(this) > 0)
558             return true;
559         else
560             return false;
561         break;
562     default:
563         return false;
564     }
565 }
566
567 ulong TreeItem::getID() { return itemID; }
568
569 void TreeItem::setUuid(const QString &id) { uuid = QUuid(id); }
570
571 QUuid TreeItem::getUuid() { return uuid; }
572
573 TreeItem *TreeItem::getChildNum(const int &n)
574 {
575     if (n >= 0 && n < childItems.count())
576         return childItems.at(n);
577     else
578         return NULL;
579 }
580
581 BranchItem *TreeItem::getFirstBranch()
582 {
583     if (branchCounter > 0)
584         return getBranchNum(0);
585     else
586         return NULL;
587 }
588
589 BranchItem *TreeItem::getLastBranch()
590 {
591     if (branchCounter > 0)
592         return getBranchNum(branchCounter - 1);
593     else
594         return NULL;
595 }
596
597 ImageItem *TreeItem::getFirstImage()
598 {
599     if (imageCounter > 0)
600         return getImageNum(imageCounter - 1);
601     else
602         return NULL;
603 }
604
605 ImageItem *TreeItem::getLastImage()
606 {
607     if (imageCounter > 0)
608         return getImageNum(imageCounter - 1);
609     else
610         return NULL;
611 }
612
613 BranchItem *TreeItem::getNextBranch(BranchItem *currentBranch)
614 {
615     if (!currentBranch)
616         return NULL;
617     int n = num(currentBranch) + 1;
618     if (n < branchCounter)
619         return getBranchNum(branchOffset + n);
620     else
621         return NULL;
622 }
623
624 BranchItem *TreeItem::getBranchNum(const int &n)
625 {
626     if (n >= 0 && n < branchCounter)
627         return (BranchItem *)getChildNum(branchOffset + n);
628     else
629         return NULL;
630 }
631
632 BranchObj *TreeItem::getBranchObjNum(const int &n)
633 {
634     if (n >= 0 && n < branchCounter) {
635         BranchItem *bi = getBranchNum(n);
636         if (bi) {
637             BranchObj *bo = (BranchObj *)(bi->getLMO());
638             if (bo)
639                 return bo;
640             else
641                 qDebug() << "TI::getBONum bo=NULL";
642         }
643     }
644     return NULL;
645 }
646
647 ImageItem *TreeItem::getImageNum(const int &n)
648 {
649     if (n >= 0 && n < imageCounter)
650         return (ImageItem *)getChildNum(imageOffset + n);
651     else
652         return NULL;
653 }
654
655 FloatImageObj *TreeItem::getImageObjNum(const int &n)
656 {
657     if (imageCounter > 0)
658         return (FloatImageObj *)(getImageNum(n)->getLMO());
659     else
660         return NULL;
661 }
662
663 AttributeItem *TreeItem::getAttributeNum(const int &n)
664 {
665     if (n >= 0 && n < attributeCounter)
666         return (AttributeItem *)getChildNum(attributeOffset + n);
667     else
668         return NULL;
669 }
670
671 AttributeItem *TreeItem::getAttributeByKey(const QString &k)
672 {
673     AttributeItem *ai;
674     for (int i = 0; i < attributeCount(); i++) {
675         ai = getAttributeNum(i);
676         if (ai->getKey() == k) return ai;
677     }
678     return nullptr;
679 }
680
681 XLinkItem *TreeItem::getXLinkItemNum(const int &n)
682 {
683     if (n >= 0 && n < xlinkCounter)
684         return (XLinkItem *)getChildNum(xlinkOffset + n);
685     else
686         return NULL;
687 }
688
689 XLinkObj *TreeItem::getXLinkObjNum(const int &n)
690 {
691     if (xlinkCounter > 0) {
692         XLinkItem *xli = getXLinkItemNum(n);
693         if (xli) {
694             Link *l = xli->getLink();
695             if (l)
696                 return l->getXLinkObj();
697         }
698     }
699     return NULL;
700 }
701
702 void TreeItem::setHideTmp(HideTmpMode mode)
703 {
704     if (type == Image || type == Branch || type == MapCenter)
705     //  ((ImageItem*)this)->updateVisibility();
706     {
707         // LinkableMapObj* lmo=((MapItem*)this)->getLMO();
708
709         if (mode == HideExport &&
710             (hideExport ||
711              hasHiddenExportParent())) // FIXME-4  try to avoid calling
712                                        // hasScrolledParent repeatedly
713
714             // Hide stuff according to hideExport flag and parents
715             hidden = true;
716         else
717             // Do not hide, but still take care of scrolled status
718             hidden = false;
719         updateVisibility();
720         // And take care of my children
721         for (int i = 0; i < branchCount(); ++i)
722             getBranchNum(i)->setHideTmp(mode);
723     }
724 }
725
726 bool TreeItem::hasHiddenExportParent()
727 {
728     // Calls parents recursivly to
729     // find out, if we or parents are temp. hidden
730
731     if (hidden || hideExport)
732         return true;
733
734     if (parentItem)
735         return parentItem->hasHiddenExportParent();
736     else
737         return false;
738 }
739
740 void TreeItem::setHideInExport(bool b)
741 {
742     if (type == MapCenter || type == Branch || type == Image) {
743         hideExport = b;
744         if (b)
745             systemFlags.activate(QString("system-hideInExport"));
746         else
747             systemFlags.deactivate(QString("system-hideInExport"));
748     }
749 }
750
751 bool TreeItem::hideInExport() { return hideExport; }
752
753 void TreeItem::updateVisibility()
754 {
755     // overloaded in derived objects
756 }
757
758 bool TreeItem::isHidden() { return hidden; }
759
760 QString TreeItem::getGeneralAttr()
761 {
762     QString s;
763     if (hideExport)
764         s += attribut("hideInExport", "true");
765     if (!url.isEmpty())
766         s += attribut("url", url);
767     if (!vymLink.isEmpty())
768         s += attribut("vymLink", convertToRel(model->getDestPath(), vymLink));
769
770     if (target)
771         s += attribut("localTarget", "true");
772     return s;
773 }