File indexing completed on 2024-04-28 04:41:52

0001 /***************************************************************************
0002  *   Copyright (C) 2017 by Emmanuel Lepage Vallee                          *
0003  *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@kde.org>             *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 3 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0017  **************************************************************************/
0018 #include "hierarchyview.h"
0019 
0020 // KQuickItemViews
0021 #include "adapters/abstractitemadapter.h"
0022 
0023 // Qt
0024 #include <QQmlContext>
0025 
0026 /**
0027  * Polymorphic tree item for the SingleModelViewBase.
0028  *
0029  * Classes implementing SingleModelViewBase need to provide an implementation of the pure
0030  * virtual functions. It is useful, for example, to manage both a raster and
0031  * QQuickItem based version of a view.
0032  *
0033  * The state is managed by the SingleModelViewBase and it's own protected virtual methods.
0034  */
0035 class HierarchyViewItem final : public AbstractItemAdapter
0036 {
0037 public:
0038     explicit HierarchyViewItem(Viewport* r);
0039     virtual ~HierarchyViewItem();
0040 
0041     // Actions
0042     virtual bool move   () override;
0043     virtual bool remove () override;
0044 
0045 private:
0046     bool m_IsHead { false };
0047 };
0048 
0049 class HierarchyViewPrivate
0050 {
0051 public:
0052 
0053     // When all elements are assumed to have the same height, life is easy
0054     QVector<qreal> m_DepthChart {0};
0055 
0056     HierarchyView* q_ptr;
0057 };
0058 
0059 HierarchyView::HierarchyView(QQuickItem* parent) : SingleModelViewBase(new ItemFactory<HierarchyViewItem>(), parent),
0060     d_ptr(new HierarchyViewPrivate)
0061 {
0062     d_ptr->q_ptr = this;
0063 }
0064 
0065 HierarchyView::~HierarchyView()
0066 {
0067     delete d_ptr;
0068 }
0069 
0070 HierarchyViewItem::HierarchyViewItem(Viewport* r) : AbstractItemAdapter(r)
0071 {
0072 }
0073 
0074 HierarchyViewItem::~HierarchyViewItem()
0075 {
0076     delete container();
0077 }
0078 
0079 bool HierarchyViewItem::move()
0080 {
0081     // Will happen when trying to move a FAILED, but buffered item
0082     if (!container()) {
0083         qDebug() << "NO ITEM" << index().data();
0084         return false;
0085     }
0086 
0087     container()->setWidth(view()->contentItem()->width());
0088 
0089     auto nextElem = static_cast<HierarchyViewItem*>(next(Qt::BottomEdge));
0090     auto prevElem = static_cast<HierarchyViewItem*>(next(Qt::TopEdge));
0091 
0092     // The root has been moved in the middle of the tree, find the new root
0093     //TODO maybe add a deterministic API instead of O(N) lookup
0094     if (prevElem && m_IsHead) {
0095         m_IsHead = false;
0096 
0097         auto root = prevElem;
0098         while (auto prev = root->next(Qt::TopEdge))
0099             root = static_cast<HierarchyViewItem*>(prev);
0100 
0101         root->move();
0102         Q_ASSERT(root->m_IsHead);
0103     }
0104 
0105     // So other items can be GCed without always resetting to 0x0, note that it
0106     // might be a good idea to extend Flickable to support a virtual
0107     // origin point.
0108     if ((!prevElem) || (nextElem && nextElem->m_IsHead)) {
0109         auto anchors = qvariant_cast<QObject*>(container()->property("anchors"));
0110         anchors->setProperty("top", {});
0111         container()->setY(0);
0112         m_IsHead = true;
0113     }
0114     else if (prevElem) {
0115         Q_ASSERT(!m_IsHead);
0116         container()->setProperty("y", {});
0117         auto anchors = qvariant_cast<QObject*>(container()->property("anchors"));
0118         anchors->setProperty("top", prevElem->container()->property("bottom"));
0119     }
0120 
0121     // Now, update the next anchors
0122     if (nextElem) {
0123         nextElem->m_IsHead = false;
0124         nextElem->container()->setProperty("y", {});
0125 
0126         auto anchors = qvariant_cast<QObject*>(nextElem->container()->property("anchors"));
0127         anchors->setProperty("top", container()->property("bottom"));
0128     }
0129 
0130     updateGeometry();
0131 
0132     return true;
0133 }
0134 
0135 bool HierarchyViewItem::remove()
0136 {
0137     if (container()) {
0138         container()->setParent(nullptr);
0139         container()->setParentItem(nullptr);
0140         container()->setVisible(false);
0141     }
0142 
0143     auto nextElem = static_cast<HierarchyViewItem*>(next(Qt::BottomEdge));
0144     auto prevElem = static_cast<HierarchyViewItem*>(next(Qt::TopEdge));
0145 
0146     if (nextElem) {
0147         if (m_IsHead) {
0148             auto anchors = qvariant_cast<QObject*>(nextElem->container()->property("anchors"));
0149             anchors->setProperty("top", {});
0150             container()->setY(0);
0151             nextElem->m_IsHead = true;
0152         }
0153         else { //TODO maybe eventually use a state machine for this
0154             auto anchors = qvariant_cast<QObject*>(nextElem->container()->property("anchors"));
0155             anchors->setProperty("top", prevElem->container()->property("bottom"));
0156         }
0157     }
0158 
0159     return true;
0160 }