]> git.sven.stormbind.net Git - sven/vym.git/blobdiff - src/treeitem.cpp
New upstream version 2.9.22
[sven/vym.git] / src / treeitem.cpp
diff --git a/src/treeitem.cpp b/src/treeitem.cpp
new file mode 100644 (file)
index 0000000..1beb13c
--- /dev/null
@@ -0,0 +1,773 @@
+#include <QStringList>
+#include <iostream>
+
+#include "attributeitem.h"
+#include "branchitem.h"
+#include "branchobj.h"
+#include "misc.h"
+#include "treeitem.h"
+#include "vymmodel.h"
+#include "xlinkitem.h"
+#include "xlinkobj.h"
+
+using namespace std;
+
+extern ulong itemLastID;
+extern FlagRowMaster *standardFlagsMaster;
+extern FlagRowMaster *systemFlagsMaster;
+extern FlagRowMaster *userFlagsMaster;
+
+extern QTextStream vout;
+
+TreeItem::TreeItem(TreeItem *parent)
+{
+    // qDebug() << "Constructor TreeItem this=" << this << "  parent=" << parent;
+    init();
+    parentItem = parent;
+
+    rootItem = this;
+    if (parentItem)
+        rootItem = parentItem->rootItem;
+}
+
+TreeItem::~TreeItem()
+{
+    // qDebug()<<"Destr TreeItem this="<<this<<"
+    // childcount="<<childItems.count();
+    TreeItem *ti;
+    while (!childItems.isEmpty()) {
+        ti = childItems.takeFirst();
+        delete ti;
+    }
+}
+
+void TreeItem::init()
+{
+    model = NULL;
+
+    // Assign ID
+    itemLastID++;
+    itemID = itemLastID;
+    uuid = QUuid::createUuid();
+
+    branchOffset = 0;
+    branchCounter = 0;
+
+    imageOffset = 0;
+    imageCounter = 0;
+
+    attributeCounter = 0;
+    attributeOffset = 0;
+
+    xlinkCounter = 0;
+    xlinkOffset = 0;
+
+    target = false;
+
+    heading.clear();
+    heading.setText(" ");
+    note.setText("");
+
+    hidden = false;
+    hideExport = false;
+
+    itemData.clear();
+    itemData << "";
+
+    backgroundColor = Qt::transparent;
+
+    standardFlags.setMasterRow(standardFlagsMaster);
+    userFlags.setMasterRow(userFlagsMaster);
+    systemFlags.setMasterRow(systemFlagsMaster);
+}
+
+void TreeItem::setModel(VymModel *m) { model = m; }
+
+VymModel *TreeItem::getModel() { return model; }
+
+int TreeItem::getRowNumAppend(TreeItem *item)
+{
+    switch (item->type) {
+    case Attribute:
+        return attributeOffset + attributeCounter;
+    case XLink:
+        return xlinkOffset + xlinkCounter;
+    case Image:
+        return imageOffset + imageCounter;
+    case MapCenter:
+        return branchOffset + branchCounter;
+    case Branch:
+        return branchOffset + branchCounter;
+    default:
+        return -1;
+    }
+}
+
+void TreeItem::appendChild(TreeItem *item)
+{
+    item->parentItem = this;
+    item->rootItem = rootItem;
+    item->setModel(model);
+
+    if (item->type == Attribute) {
+        // attribute are on top of list
+        childItems.insert(attributeCounter, item);
+        attributeCounter++;
+        xlinkOffset++;
+        imageOffset++;
+        branchOffset++;
+    }
+
+    if (item->type == XLink) {
+        childItems.insert(xlinkCounter + xlinkOffset, item);
+        xlinkCounter++;
+        imageOffset++;
+        branchOffset++;
+    }
+
+    if (item->type == Image) {
+        childItems.insert(imageCounter + imageOffset, item);
+        imageCounter++;
+        branchOffset++;
+    }
+
+    if (item->isBranchLikeType()) {
+        // branches are on bottom of list
+        childItems.append(item);
+        branchCounter++;
+
+        // Set correct type
+        if (this == rootItem)
+            item->setType(MapCenter);
+        else
+            item->setType(Branch);
+    }
+}
+
+void TreeItem::removeChild(int row)
+{
+    if (row < 0 || row > childItems.size() - 1)
+        qWarning("TreeItem::removeChild tried to remove non existing item?!");
+    else {
+        if (childItems.at(row)->type == Attribute) {
+            attributeCounter--;
+            xlinkOffset--;
+            imageOffset--;
+            branchOffset--;
+        }
+        if (childItems.at(row)->type == XLink) {
+            xlinkCounter--;
+            imageOffset--;
+            branchOffset--;
+        }
+        if (childItems.at(row)->type == Image) {
+            imageCounter--;
+            branchOffset--;
+        }
+        if (childItems.at(row)->isBranchLikeType())
+            branchCounter--;
+
+        childItems.removeAt(row);
+    }
+}
+
+TreeItem *TreeItem::child(int row) { return childItems.value(row); }
+
+int TreeItem::childCount() const { return childItems.count(); }
+
+int TreeItem::childNumber() const
+{
+    if (parentItem)
+        return parentItem->childItems.indexOf(const_cast<TreeItem *>(this));
+
+    return 0;
+}
+
+int TreeItem::columnCount() const { return 1; }
+
+int TreeItem::branchCount() const { return branchCounter; }
+
+int TreeItem::imageCount() const { return imageCounter; }
+
+int TreeItem::xlinkCount() const { return xlinkCounter; }
+
+int TreeItem::attributeCount() const { return attributeCounter; }
+
+int TreeItem::row() const
+{
+    if (parentItem)
+        return parentItem->childItems.indexOf(const_cast<TreeItem *>(this));
+
+    qDebug() << "TI::row() pI=NULL this=" << this << "  ***************";
+    return 0;
+}
+
+int TreeItem::depth()
+{
+    // Rootitem d=-1
+    // MapCenter d=0
+    int d = -2;
+    TreeItem *ti = this;
+    while (ti != NULL) {
+        ti = ti->parent();
+        d++;
+    }
+    return d;
+}
+
+TreeItem *TreeItem::parent()
+{
+    // qDebug() << "TI::parent of "<<getHeadingStd()<<"  is "<<parentItem;
+    return parentItem;
+}
+
+bool TreeItem::isChildOf(TreeItem *ti)
+{
+    if (this == rootItem)
+        return false;
+    if (parentItem == ti)
+        return true;
+    if (parentItem == rootItem)
+        return false;
+    return parentItem->isChildOf(ti);
+}
+
+int TreeItem::childNum() { return parentItem->childItems.indexOf(this); }
+
+int TreeItem::num()
+{
+    if (!parentItem)
+        return -1;
+    return parentItem->num(this);
+}
+
+int TreeItem::num(TreeItem *item)
+{
+    if (!item)
+        return -1;
+    if (!childItems.contains(item))
+        return -1;
+    switch (item->getType()) {
+    case MapCenter:
+        return childItems.indexOf(item) - branchOffset;
+    case Branch:
+        return childItems.indexOf(item) - branchOffset;
+    case Image:
+        return childItems.indexOf(item) - imageOffset;
+    case Attribute:
+        return childItems.indexOf(item) - attributeOffset;
+    case XLink:
+        return childItems.indexOf(item) - xlinkOffset;
+    default:
+        return -1;
+    }
+}
+void TreeItem::setType(const Type t)
+{
+    type = t;
+}
+
+TreeItem::Type TreeItem::getType()
+{
+    if (type == Branch && depth() == 0)
+        return MapCenter; // should not be necesssary
+    return type;
+}
+
+bool TreeItem::isBranchLikeType() const
+{
+    if (type == Branch || type == MapCenter)
+        return true;
+    else
+        return false;
+}
+
+QString TreeItem::getTypeName()
+{
+    switch (type) {
+        case Undefined:
+            return QString("Undefined");
+        case MapCenter:
+            return QString("MapCenter");
+        case Branch:
+            return QString("Branch");
+        case Image:
+            return QString("Image");
+        case Attribute:
+            return QString("Attribute");
+        case XLink:
+            return QString("XLink");
+        default:
+            return QString("TreeItem::getTypeName no typename defined?!");
+    }
+}
+
+QVariant TreeItem::data(int column) const { return itemData.value(column); }
+
+void TreeItem::setHeading(const VymText &vt)
+{
+    heading = vt;
+    itemData[0] = getHeadingPlain().replace("\n"," "); // used in TreeEditor
+}
+
+void TreeItem::setHeadingPlainText(const QString &s)
+{
+    VymText vt;
+
+    vt.setPlainText(s);
+
+    if (!heading.isRichText())
+        // Keep current color
+        vt.setColor(heading.getColor());
+    setHeading(vt);
+}
+
+Heading TreeItem::getHeading() const { return heading; }
+
+QString TreeItem::getHeadingText() { return heading.getText(); }
+
+std::string TreeItem::getHeadingStd() const
+{
+    return getHeadingPlain().toStdString();
+}
+
+QString TreeItem::getHeadingPlain() const
+{
+    // strip beginning and tailing WS
+    return heading.getTextASCII().trimmed();
+}
+
+QString TreeItem::getHeadingPlainWithParents(uint numberOfParents = 0)
+{
+    QString s = getHeadingPlain();
+    if (numberOfParents > 0) {
+        TreeItem *ti = this;
+        int l = numberOfParents;
+        while (l > 0 && ti->depth() > 0) {
+            ti = ti->parent();
+            if (ti)
+                s = ti->getHeadingPlain() + " -> " + s;
+            else
+                l = 0;
+            l--;
+        }
+    }
+    return s;
+}
+
+QString TreeItem::getHeadingDepth() // Indent by depth for debugging
+{
+    QString ds;
+    for (int i = 0; i < depth(); i++)
+        ds += "  ";
+    return ds + getHeadingPlain();
+}
+
+void TreeItem::setHeadingColor(QColor color) { heading.setColor(color); }
+
+QColor TreeItem::getHeadingColor() { return heading.getColor(); }
+
+void TreeItem::setBackgroundColor(QColor color) { backgroundColor = color; }
+
+void TreeItem::setURL(const QString &u)
+{
+    url = u;
+    if (!url.isEmpty())
+        systemFlags.activate(QString("system-url"));
+    else
+        systemFlags.deactivate(QString("system-url"));
+}
+
+QString TreeItem::getURL() { return url; }
+
+void TreeItem::setVymLink(const QString &vl)
+{
+    if (!vl.isEmpty()) {
+        // We need the relative (from loading)
+        // or absolute path (from User event)
+        // and build the absolute path.
+
+        QDir d(vl);
+        if (d.isAbsolute())
+            vymLink = vl;
+        else {
+            // If we have relative, use path of
+            // current map to build absolute path
+            // based on path of current map and relative
+            // path to linked map
+            QString p = dirname(model->getDestPath());
+            vymLink = convertToAbs(p, vl);
+        }
+        systemFlags.activate(QString("system-vymLink"));
+    }
+    else {
+        vymLink.clear();
+        systemFlags.deactivate(QString("system-vymLink"));
+    }
+}
+
+QString TreeItem::getVymLink() { return vymLink; }
+
+void TreeItem::toggleTarget()
+{
+    systemFlags.toggle(QString("system-target"));
+    target = systemFlags.isActive(QString("system-target"));
+    model->emitDataChanged(this); // FIXME-4 better call from VM?
+}
+
+bool TreeItem::isTarget() { return target; }
+
+bool TreeItem::isNoteEmpty() { return note.isEmpty(); }
+
+bool TreeItem::clearNote()
+{
+    note.clear();
+    return systemFlags.deactivate(QString("system-note"));
+}
+
+bool TreeItem::setNote(const VymText &vt)
+{
+    note = vt;
+
+    if (note.isEmpty()) {
+        if (systemFlags.isActive(QString("system-note")))
+            return systemFlags.deactivate(QString("system-note"));
+    }
+    else {
+        if (!systemFlags.isActive(QString("system-note")))
+            return systemFlags.activate(QString("system-note"));
+    }
+    return false; // No need to update flag and reposition later
+}
+
+bool TreeItem::setNote(const VymNote &vn) { return setNote((VymText)vn); }
+
+bool TreeItem::hasEmptyNote() { return note.isEmpty(); }
+
+VymNote TreeItem::getNote() { return note; }
+
+QString TreeItem::getNoteASCII(const QString &indent, const int &width)
+{
+    return note.getTextASCII(indent, width);
+}
+
+QString TreeItem::getNoteASCII() { return note.getTextASCII(); }
+
+void TreeItem::activateStandardFlagByName(const QString &name)
+{
+    standardFlags.activate(name);
+    //    model->emitDataChanged(this);
+}
+
+void TreeItem::deactivateStandardFlagByName(const QString &name)
+{
+    standardFlags.deactivate(name);
+    //    model->emitDataChanged(this);
+}
+
+void TreeItem::deactivateAllStandardFlags()
+{
+    standardFlags.deactivateAll();
+    userFlags.deactivateAll();
+    //    model->emitDataChanged(this);
+}
+
+Flag *TreeItem::findFlagByUid(const QUuid &uid)
+{
+    Flag *f = standardFlagsMaster->findFlagByUid(uid);
+    if (!f)
+        f = userFlagsMaster->findFlagByUid(uid);
+    return f;
+}
+
+Flag *TreeItem::toggleFlagByUid(const QUuid &uid, bool useGroups)
+{
+    Flag *f = standardFlagsMaster->findFlagByUid(uid);
+    if (f) {
+        standardFlags.toggle(uid, useGroups);
+    }
+    else {
+        f = userFlagsMaster->findFlagByUid(uid);
+        if (f) {
+            userFlags.toggle(uid, useGroups);
+        }
+        else {
+            qWarning() << "TI::toggleFlag failed for flag " << uid;
+            return nullptr;
+        }
+    }
+
+    return f;
+}
+
+void TreeItem::toggleSystemFlag(const QString &name, FlagRow *master)
+{
+    systemFlags.toggle(name, master);
+    model->emitDataChanged(this);
+}
+
+bool TreeItem::hasActiveFlag(const QString &name)
+{
+    return standardFlags.isActive(name);
+}
+
+bool TreeItem::hasActiveSystemFlag(const QString &name)
+{
+    return systemFlags.isActive(name);
+}
+
+QList<QUuid> TreeItem::activeFlagUids()
+{
+    return standardFlags.activeFlagUids() + userFlags.activeFlagUids();
+}
+
+QList<QUuid> TreeItem::activeSystemFlagUids()
+{
+    return systemFlags.activeFlagUids();
+}
+
+bool TreeItem::canMoveDown()
+{
+    switch (type) {
+    case Undefined:
+        return false;
+    case MapCenter:
+    case Branch:
+        if (!parentItem)
+            return false;
+        if (parentItem->num(this) < parentItem->branchCount() - 1)
+            return true;
+        else
+            return false;
+        break;
+    case Image:
+        return false;
+    default:
+        return false;
+    }
+}
+
+bool TreeItem::canMoveUp()
+{
+    switch (type) {
+    case MapCenter:
+    case Branch:
+        if (!parentItem)
+            return false;
+        if (parentItem->num(this) > 0)
+            return true;
+        else
+            return false;
+        break;
+    default:
+        return false;
+    }
+}
+
+ulong TreeItem::getID() { return itemID; }
+
+void TreeItem::setUuid(const QString &id) { uuid = QUuid(id); }
+
+QUuid TreeItem::getUuid() { return uuid; }
+
+TreeItem *TreeItem::getChildNum(const int &n)
+{
+    if (n >= 0 && n < childItems.count())
+        return childItems.at(n);
+    else
+        return NULL;
+}
+
+BranchItem *TreeItem::getFirstBranch()
+{
+    if (branchCounter > 0)
+        return getBranchNum(0);
+    else
+        return NULL;
+}
+
+BranchItem *TreeItem::getLastBranch()
+{
+    if (branchCounter > 0)
+        return getBranchNum(branchCounter - 1);
+    else
+        return NULL;
+}
+
+ImageItem *TreeItem::getFirstImage()
+{
+    if (imageCounter > 0)
+        return getImageNum(imageCounter - 1);
+    else
+        return NULL;
+}
+
+ImageItem *TreeItem::getLastImage()
+{
+    if (imageCounter > 0)
+        return getImageNum(imageCounter - 1);
+    else
+        return NULL;
+}
+
+BranchItem *TreeItem::getNextBranch(BranchItem *currentBranch)
+{
+    if (!currentBranch)
+        return NULL;
+    int n = num(currentBranch) + 1;
+    if (n < branchCounter)
+        return getBranchNum(branchOffset + n);
+    else
+        return NULL;
+}
+
+BranchItem *TreeItem::getBranchNum(const int &n)
+{
+    if (n >= 0 && n < branchCounter)
+        return (BranchItem *)getChildNum(branchOffset + n);
+    else
+        return NULL;
+}
+
+BranchObj *TreeItem::getBranchObjNum(const int &n)
+{
+    if (n >= 0 && n < branchCounter) {
+        BranchItem *bi = getBranchNum(n);
+        if (bi) {
+            BranchObj *bo = (BranchObj *)(bi->getLMO());
+            if (bo)
+                return bo;
+            else
+                qDebug() << "TI::getBONum bo=NULL";
+        }
+    }
+    return NULL;
+}
+
+ImageItem *TreeItem::getImageNum(const int &n)
+{
+    if (n >= 0 && n < imageCounter)
+        return (ImageItem *)getChildNum(imageOffset + n);
+    else
+        return NULL;
+}
+
+FloatImageObj *TreeItem::getImageObjNum(const int &n)
+{
+    if (imageCounter > 0)
+        return (FloatImageObj *)(getImageNum(n)->getLMO());
+    else
+        return NULL;
+}
+
+AttributeItem *TreeItem::getAttributeNum(const int &n)
+{
+    if (n >= 0 && n < attributeCounter)
+        return (AttributeItem *)getChildNum(attributeOffset + n);
+    else
+        return NULL;
+}
+
+AttributeItem *TreeItem::getAttributeByKey(const QString &k)
+{
+    AttributeItem *ai;
+    for (int i = 0; i < attributeCount(); i++) {
+        ai = getAttributeNum(i);
+        if (ai->getKey() == k) return ai;
+    }
+    return nullptr;
+}
+
+XLinkItem *TreeItem::getXLinkItemNum(const int &n)
+{
+    if (n >= 0 && n < xlinkCounter)
+        return (XLinkItem *)getChildNum(xlinkOffset + n);
+    else
+        return NULL;
+}
+
+XLinkObj *TreeItem::getXLinkObjNum(const int &n)
+{
+    if (xlinkCounter > 0) {
+        XLinkItem *xli = getXLinkItemNum(n);
+        if (xli) {
+            Link *l = xli->getLink();
+            if (l)
+                return l->getXLinkObj();
+        }
+    }
+    return NULL;
+}
+
+void TreeItem::setHideTmp(HideTmpMode mode)
+{
+    if (type == Image || type == Branch || type == MapCenter)
+    // ((ImageItem*)this)->updateVisibility();
+    {
+        // LinkableMapObj* lmo=((MapItem*)this)->getLMO();
+
+        if (mode == HideExport &&
+            (hideExport ||
+             hasHiddenExportParent())) // FIXME-4  try to avoid calling
+                                       // hasScrolledParent repeatedly
+
+            // Hide stuff according to hideExport flag and parents
+            hidden = true;
+        else
+            // Do not hide, but still take care of scrolled status
+            hidden = false;
+        updateVisibility();
+        // And take care of my children
+        for (int i = 0; i < branchCount(); ++i)
+            getBranchNum(i)->setHideTmp(mode);
+    }
+}
+
+bool TreeItem::hasHiddenExportParent()
+{
+    // Calls parents recursivly to
+    // find out, if we or parents are temp. hidden
+
+    if (hidden || hideExport)
+        return true;
+
+    if (parentItem)
+        return parentItem->hasHiddenExportParent();
+    else
+        return false;
+}
+
+void TreeItem::setHideInExport(bool b)
+{
+    if (type == MapCenter || type == Branch || type == Image) {
+        hideExport = b;
+        if (b)
+            systemFlags.activate(QString("system-hideInExport"));
+        else
+            systemFlags.deactivate(QString("system-hideInExport"));
+    }
+}
+
+bool TreeItem::hideInExport() { return hideExport; }
+
+void TreeItem::updateVisibility()
+{
+    // overloaded in derived objects
+}
+
+bool TreeItem::isHidden() { return hidden; }
+
+QString TreeItem::getGeneralAttr()
+{
+    QString s;
+    if (hideExport)
+        s += attribut("hideInExport", "true");
+    if (!url.isEmpty())
+        s += attribut("url", url);
+    if (!vymLink.isEmpty())
+        s += attribut("vymLink", convertToRel(model->getDestPath(), vymLink));
+
+    if (target)
+        s += attribut("localTarget", "true");
+    return s;
+}