]> git.sven.stormbind.net Git - sven/vym.git/blob - src/branchitem.cpp
Replace Pierre as the maintainer
[sven/vym.git] / src / branchitem.cpp
1 #include "branchitem.h"
2
3 #include "attributeitem.h"
4 #include "branchobj.h"
5 #include "task.h"
6 #include "taskmodel.h"
7 #include "vymmodel.h"
8 #include "xlink.h"
9 #include "xlinkitem.h"
10
11 extern TaskModel *taskModel;
12
13 //#include <QDir>
14
15 BranchItem::BranchItem(TreeItem *parent)
16     : MapItem(parent)
17 {
18     //qDebug()<< "Constr. BranchItem this=" << this << "parent:" << parent;
19
20     // Set type if parent is known yet
21     // if not, type is set in insertBranch or TreeItem::appendChild
22     if (parent == rootItem)
23         setType(MapCenter);
24     else
25         setType(Branch);
26
27     scrolled = false;
28     tmpUnscrolled = false;
29
30     includeImagesVer = false;
31     includeImagesHor = false;
32     includeChildren = false;
33     childrenLayout = BranchItem::AutoPositioning;
34
35     lastSelectedBranchNum = 0;
36     lastSelectedBranchNumAlt = 0;
37
38     task = NULL;
39 }
40
41 BranchItem::~BranchItem()
42 {
43     // qDebug()<< "Destr. BranchItem  this="<<this<<"  "<<getHeading();
44     if (mo) {
45         delete mo;
46         mo = NULL;
47     }
48     clear();
49 }
50
51 void BranchItem::clear()
52 {
53     if (task)
54         taskModel->deleteTask(task);
55 }
56
57 void BranchItem::copy(BranchItem *other) // TODO lacks most of data...
58 {
59     scrolled = other->scrolled;
60     tmpUnscrolled = other->tmpUnscrolled;
61 }
62
63 BranchItem *BranchItem::parentBranch() { return (BranchItem *)parentItem; }
64
65 void BranchItem::insertBranch(int pos, BranchItem *branch)
66 {
67     if (pos < 0)
68         pos = 0;
69     if (pos > branchCounter)
70         pos = branchCounter;
71     childItems.insert(pos + branchOffset, branch);
72     branch->parentItem = this;
73     branch->rootItem = rootItem;
74     branch->setModel(model);
75     if (parentItem == rootItem)
76         setType(MapCenter);
77     else
78         setType(Branch);
79
80     if (branchCounter == 0)
81         branchOffset = childItems.count() - 1;
82     branchCounter++;
83 }
84
85 QString BranchItem::saveToDir(const QString &tmpdir, const QString &prefix,
86                               const QPointF &offset, QList<Link *> &tmpLinks)
87 {
88     // Cloudy stuff can be hidden during exports
89     if (hidden)
90         return QString();
91
92     // Save uuid
93     QString idAttr = attribut("uuid", uuid.toString());
94
95     QString s, a;
96
97     // Update of note is usually done while unselecting a branch
98
99     QString scrolledAttr;
100     if (scrolled)
101         scrolledAttr = attribut("scrolled", "yes");
102     else
103         scrolledAttr = "";
104
105     // save area, if not scrolled   // not needed if HTML is rewritten...
106     // also we could check if _any_ of parents is scrolled
107     QString areaAttr;
108     if (mo && parentItem->isBranchLikeType() &&
109         !((BranchItem *)parentItem)->isScrolled()) {
110         qreal x = mo->getAbsPos().x();
111         qreal y = mo->getAbsPos().y();
112         areaAttr =
113             attribut("x1", QString().setNum(x - offset.x())) +
114             attribut("y1", QString().setNum(y - offset.y())) +
115             attribut("x2", QString().setNum(x + mo->width() - offset.x())) +
116             attribut("y2", QString().setNum(y + mo->height() - offset.y()));
117     }
118     else
119         areaAttr = "";
120
121     QString elementName;
122     if (parentItem == rootItem)
123         elementName = "mapcenter";
124     else
125         elementName = "branch";
126
127     // Free positioning of children
128     QString layoutAttr;
129     if (childrenLayout == BranchItem::FreePositioning)
130         layoutAttr += attribut("childrenFreePos", "true");
131
132     // Save rotation
133     QString rotAttr;
134     if (mo && mo->getRotation() != 0)
135         rotAttr = attribut("rotation", QString().setNum(mo->getRotation()));
136
137     s = beginElement(elementName + getMapAttr() + getGeneralAttr() +
138                      scrolledAttr + getIncludeImageAttr() + rotAttr +
139                      layoutAttr + idAttr);
140     incIndent();
141
142     // save heading
143     s += heading.saveToDir();
144
145     // save note
146     if (!note.isEmpty())
147         s += note.saveToDir();
148
149     // Save frame  // not saved if there is no MO
150     if (mo) {
151         // Avoid saving NoFrame for objects other than MapCenter
152         if (depth() == 0 || ((OrnamentedObj *)mo)->getFrame()->getFrameType() !=
153                                 FrameObj::NoFrame)
154             s += ((OrnamentedObj *)mo)->getFrame()->saveToDir();
155     }
156
157     // save names of flags set
158     s += standardFlags.saveState();
159     s += userFlags.saveState();
160
161     // Save Images
162     for (int i = 0; i < imageCount(); ++i)
163         s += getImageNum(i)->saveToDir(tmpdir, prefix);
164
165     // save attributes
166     for (int i = 0; i < attributeCount(); ++i)
167         s += getAttributeNum(i)->getDataXML();
168
169     // save task
170     if (task)
171         s += task->saveToDir();
172
173     // Save branches
174     int i = 0;
175     TreeItem *ti = getBranchNum(i);
176     while (ti) {
177         s += getBranchNum(i)->saveToDir(tmpdir, prefix, offset, tmpLinks);
178         i++;
179         ti = getBranchNum(i);
180     }
181
182     // Mark Links for save
183     for (int i = 0; i < xlinkCount(); ++i) {
184         Link *l = getXLinkItemNum(i)->getLink();
185         if (l && !tmpLinks.contains(l))
186             tmpLinks.append(l);
187     }
188     decIndent();
189     s += endElement(elementName);
190     return s;
191 }
192
193 void BranchItem::updateVisibility()
194 {
195     // Needed to hide relinked branch, if parent is scrolled
196     if (mo) {
197         if (hasScrolledParent(this) || hidden)
198             mo->setVisibility(false);
199         else
200             mo->setVisibility(true);
201     }
202 }
203
204 void BranchItem::setHeadingColor(QColor color)
205 {
206     TreeItem::setHeadingColor(color);
207     if (mo)
208         ((BranchObj *)mo)->setColor(color);
209 }
210
211 void BranchItem::updateTaskFlag()
212 {
213     systemFlags.deactivateGroup("system-tasks");
214     if (task) {
215         QString s = "system-" + task->getIconString();
216         systemFlags.activate(s);
217         model->emitDataChanged(this);
218     }
219     // else: During initialization the task is not yet attached to branch,
220     // so ignore it for now
221 }
222
223 void BranchItem::setTask(Task *t)
224 {
225     task = t;
226     updateTaskFlag();
227 }
228
229 Task *BranchItem::getTask() { return task; }
230
231 void BranchItem::scroll()
232 {
233     if (tmpUnscrolled)
234         resetTmpUnscroll();
235     if (!scrolled)
236         toggleScroll();
237 }
238 void BranchItem::unScroll()
239 {
240     if (tmpUnscrolled)
241         resetTmpUnscroll();
242     if (scrolled)
243         toggleScroll();
244 }
245
246 bool BranchItem::toggleScroll()
247 {
248     // MapCenters are not scrollable
249     if (depth() == 0)
250         return false;
251
252     BranchObj *bo;
253     if (scrolled) {
254         scrolled = false;
255         systemFlags.deactivate(QString("system-scrolledright"));
256         if (branchCounter > 0)
257             for (int i = 0; i < branchCounter; ++i) {
258                 bo = (BranchObj *)(getBranchNum(i)->getMO());
259                 if (bo)
260                     bo->setVisibility(true); // Recursively!
261             }
262     }
263     else {
264         scrolled = true;
265         systemFlags.activate(QString("system-scrolledright"));
266         if (branchCounter > 0)
267             for (int i = 0; i < branchCounter; ++i) {
268                 bo = (BranchObj *)(getBranchNum(i)->getMO());
269                 if (bo)
270                     bo->setVisibility(false); // Recursively!
271             }
272     }
273     return true;
274 }
275
276 bool BranchItem::isScrolled() { return scrolled; }
277
278 bool BranchItem::hasScrolledParent(BranchItem *start)
279 {
280     // Calls parents recursivly to
281     // find out, if we are scrolled at all.
282     // But ignore myself, just look at parents.
283
284     if (!start)
285         start = this;
286
287     if (this != start && scrolled)
288         return true;
289
290     BranchItem *bi = (BranchItem *)parentItem;
291     if (bi && bi != rootItem)
292         return bi->hasScrolledParent(start);
293     else
294         return false;
295 }
296
297 bool BranchItem::tmpUnscroll(BranchItem *start)
298 {
299     bool result = false;
300
301     if (!start)
302         start = this;
303
304     // Unscroll parent (recursivly)
305     BranchItem *pi = (BranchItem *)parentItem;
306     if (pi && pi->isBranchLikeType())
307         result = pi->tmpUnscroll(start);
308
309     // Unscroll myself
310     if (start != this && scrolled) {
311         tmpUnscrolled = true;
312         systemFlags.activate(QString("system-tmpUnscrolledRight"));
313         toggleScroll();
314         model->emitDataChanged(this);
315         result = true;
316     }
317     return result;
318 }
319
320 bool BranchItem::resetTmpUnscroll()
321 {
322     bool result = false;
323
324     // Unscroll parent (recursivly)
325     BranchItem *pi = (BranchItem *)parentItem;
326     if (pi && pi->isBranchLikeType())
327         result = pi->resetTmpUnscroll();
328
329     // Unscroll myself
330     if (tmpUnscrolled) {
331         tmpUnscrolled = false;
332         systemFlags.deactivate(QString("system-tmpUnscrolledRight"));
333         toggleScroll();
334         model->emitDataChanged(this);
335         result = true;
336     }
337     return result;
338 }
339
340 void BranchItem::sortChildren(
341     bool inverse) // FIXME-4 optimize by not using moveUp/Down
342 {
343     int childCount = branchCounter;
344     int curChildIndex;
345     bool madeChanges = false;
346     do {
347         madeChanges = false;
348         for (curChildIndex = 1; curChildIndex < childCount; curChildIndex++) {
349             BranchItem *curChild = getBranchNum(curChildIndex);
350             BranchItem *prevChild = getBranchNum(curChildIndex - 1);
351             if (inverse) {
352                 if (prevChild->getHeadingPlain().compare(
353                         curChild->getHeadingPlain(), Qt::CaseInsensitive) < 0) {
354                     model->moveUp(curChild);
355                     madeChanges = true;
356                 }
357             }
358             else if (prevChild->getHeadingPlain().compare(
359                          curChild->getHeadingPlain(), Qt::CaseInsensitive) >
360                      0) {
361                 model->moveUp(curChild);
362                 madeChanges = true;
363             }
364         }
365     } while (madeChanges);
366 }
367
368 void BranchItem::setChildrenLayout(BranchItem::LayoutHint layoutHint)
369 {
370     childrenLayout = layoutHint;
371 }
372
373 BranchItem::LayoutHint BranchItem::getChildrenLayout()
374 {
375     return childrenLayout;
376 }
377
378 void BranchItem::setIncludeImagesVer(bool b) { includeImagesVer = b; }
379
380 bool BranchItem::getIncludeImagesVer() { return includeImagesVer; }
381
382 void BranchItem::setIncludeImagesHor(bool b) { includeImagesHor = b; }
383
384 bool BranchItem::getIncludeImagesHor() { return includeImagesHor; }
385
386 QString BranchItem::getIncludeImageAttr()
387 {
388     QString a;
389     if (includeImagesVer)
390         a = attribut("incImgV", "true");
391     if (includeImagesHor)
392         a += attribut("incImgH", "true");
393     return a;
394 }
395
396 BranchItem *BranchItem::getFramedParentBranch(BranchItem *start)
397 {
398     BranchObj *bo = getBranchObj();
399     if (bo && bo->getFrameType() != FrameObj::NoFrame) {
400         if (bo->getFrame()->getFrameIncludeChildren())
401             return this;
402         if (this == start)
403             return this;
404     }
405     BranchItem *bi = (BranchItem *)parentItem;
406     if (bi && bi != rootItem)
407         return bi->getFramedParentBranch(start);
408     else
409         return NULL;
410 }
411
412 void BranchItem::setFrameIncludeChildren(bool b)
413 {
414     includeChildren = b; // FIXME-4 ugly: same information stored in FrameObj
415     BranchObj *bo = getBranchObj();
416     if (bo)
417         bo->getFrame()->setFrameIncludeChildren(b);
418 }
419
420 bool BranchItem::getFrameIncludeChildren()
421 {
422     BranchObj *bo = getBranchObj();
423     if (bo)
424         return bo->getFrame()->getFrameIncludeChildren();
425     else
426         return includeChildren;
427 }
428
429 QColor BranchItem::getBackgroundColor(BranchItem *start, bool checkInnerFrame)
430 {
431     /*
432     // Determine background color in taskEditor, first try inner frame
433     if (checkInnerFrame && branchContainer->frameType(true) != FrameContainer::NoFrame)
434             return branchContainer->frameBrushColor(true);
435
436     // Outer frame
437     if (branchContainer->frameType(false) != FrameContainer::NoFrame)
438             return branchContainer->frameBrushColor(false);
439
440     BranchItem *pb = parentBranch();
441     if (pb && pb != rootItem)
442         // Recursively try parents and check for frames there
443         return pb->getBackgroundColor(start, false);
444     else
445     */
446     BranchItem *bi = getFramedParentBranch(start);
447     if (bi)
448         return bi->getBranchObj()->getFrameBrushColor();
449
450         // No frame found
451         return model->getMapBackgroundColor();
452 }
453
454 void BranchItem::setLastSelectedBranch()
455 {
456     int d = depth();
457     if (d >= 0) {
458         if (d == 1)
459             // Hack to save an additional lastSelected for mapcenters in
460             // MapEditor depending on orientation this allows to go both left
461             // and right from there
462             if (mo && ((BranchObj *)mo)->getOrientation() ==
463                           LinkableMapObj::LeftOfCenter) {
464                 ((BranchItem *)parentItem)->lastSelectedBranchNumAlt =
465                     parentItem->num(this);
466                 return;
467             }
468         ((BranchItem *)parentItem)->lastSelectedBranchNum =
469             parentItem->num(this);
470     }
471 }
472
473 void BranchItem::setLastSelectedBranch(int i) { lastSelectedBranchNum = i; }
474
475 BranchItem *BranchItem::getLastSelectedBranch()
476 {
477     if (lastSelectedBranchNum >= branchCounter)
478         return getBranchNum(branchCounter - 1);
479     else
480         return getBranchNum(lastSelectedBranchNum);
481 }
482
483 BranchItem *BranchItem::getLastSelectedBranchAlt()
484 {
485     return getBranchNum(lastSelectedBranchNumAlt);
486 }
487
488 TreeItem *BranchItem::findMapItem(QPointF p, TreeItem *excludeTI)
489 {
490     // Search branches
491     TreeItem *ti;
492     for (int i = 0; i < branchCount(); ++i) {
493         ti = getBranchNum(i)->findMapItem(p, excludeTI);
494         if (ti != NULL)
495             return ti;
496     }
497
498     // Search images
499     ImageItem *ii;
500     for (int i = 0; i < imageCount(); ++i) {
501         ii = getImageNum(i);
502         MapObj *mo = ii->getMO();
503         if (mo && mo->isInClickBox(p) && (ii != excludeTI) &&
504             this != excludeTI && mo->isVisibleObj())
505             return ii;
506     }
507
508     // Search myself
509     if (getBranchObj()->isInClickBox(p) && (this != excludeTI) &&
510         getBranchObj()->isVisibleObj())
511         return this;
512
513     // Search attributes
514     AttributeItem *ai;
515     for (int i = 0; i < attributeCount(); ++i) {
516         ai = getAttributeNum(i);
517         MapObj *mo = ai->getMO();
518         if (mo && mo->isInClickBox(p) && (ai != excludeTI) &&
519             this != excludeTI && mo->isVisibleObj())
520             return ai;
521     }
522     return NULL;
523 }
524
525 void BranchItem::updateStyles(const bool &keepFrame)
526 {
527     // Update styles when relinking branches
528     if (mo) {
529         BranchObj *bo = getBranchObj();
530         if (parentItem != rootItem)
531             bo->setParObj((LinkableMapObj *)(((MapItem *)parentItem)->getMO()));
532         else
533             bo->setParObj(NULL);
534         bo->setDefAttr(BranchObj::MovedBranch, keepFrame);
535     }
536 }
537
538 BranchObj *BranchItem::getBranchObj() { return (BranchObj *)mo; }
539
540 BranchObj *BranchItem::createMapObj(QGraphicsScene *scene)
541 {
542     BranchObj *newbo;
543
544     if (parentItem == rootItem) {
545         newbo = new BranchObj(NULL, this);
546         mo = newbo;
547         scene->addItem(newbo);
548     }
549     else {
550         newbo = new BranchObj(((MapItem *)parentItem)->getMO(), this);
551         mo = newbo;
552         // Set visibility depending on parents
553         if (parentItem != rootItem &&
554             (((BranchItem *)parentItem)->scrolled ||
555              !((MapItem *)parentItem)->getLMO()->isVisibleObj()))
556             newbo->setVisibility(false);
557         if (depth() == 1) {
558             qreal r = 190;
559             qreal a =
560                 -M_PI_4 + M_PI_2 * (num()) + (M_PI_4 / 2) * (num() / 4 % 4);
561             QPointF p(r * cos(a), r * sin(a));
562             newbo->setRelPos(p);
563         }
564     }
565     newbo->setDefAttr(BranchObj::NewBranch);
566     initLMO();
567
568     if (!getHeading().isEmpty()) {
569         newbo->updateVisuals();
570         newbo->setColor(heading.getColor());
571     }
572
573     return newbo;
574 }