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 }