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 "treeview.h" 0019 0020 // KQuickItemViews 0021 #include "adapters/abstractitemadapter.h" 0022 #include "extensions/contextextension.h" 0023 #include "adapters/modeladapter.h" 0024 #include "contextadapterfactory.h" 0025 #include "adapters/contextadapter.h" 0026 0027 // Qt 0028 #include <QQmlContext> 0029 0030 /** 0031 * Polymorphic tree item for the SingleModelViewBase. 0032 * 0033 * Classes implementing SingleModelViewBase need to provide an implementation of the pure 0034 * virtual functions. It is useful, for example, to manage both a raster and 0035 * QQuickItem based version of a view. 0036 * 0037 * The state is managed by the SingleModelViewBase and it's own protected virtual methods. 0038 */ 0039 class TreeViewItem final : public AbstractItemAdapter 0040 { 0041 public: 0042 explicit TreeViewItem(Viewport* r); 0043 virtual ~TreeViewItem(); 0044 0045 // Actions 0046 virtual bool move () override; 0047 virtual bool remove () override; 0048 0049 private: 0050 bool m_IsHead { false }; 0051 }; 0052 0053 /// Add the same property as the QtQuick.ListView 0054 class TreeContextProperties final : public ContextExtension 0055 { 0056 public: 0057 virtual ~TreeContextProperties() {} 0058 virtual QVector<QByteArray>& propertyNames() const override; 0059 virtual QVariant getProperty(AbstractItemAdapter* item, uint id, const QModelIndex& index) const override; 0060 virtual bool setProperty(AbstractItemAdapter* item, uint id, const QVariant& value, const QModelIndex& index) const override; 0061 }; 0062 0063 class TreeViewPrivate 0064 { 0065 public: 0066 }; 0067 0068 TreeView::TreeView(QQuickItem* parent) : SingleModelViewBase(new ItemFactory<TreeViewItem>(), parent), 0069 d_ptr(new TreeViewPrivate) 0070 { 0071 modelAdapters().first()->contextAdapterFactory()->addContextExtension( 0072 new TreeContextProperties() 0073 ); 0074 } 0075 0076 TreeView::~TreeView() 0077 { 0078 delete d_ptr; 0079 } 0080 0081 TreeViewItem::TreeViewItem(Viewport* r) : AbstractItemAdapter(r) 0082 { 0083 } 0084 0085 TreeViewItem::~TreeViewItem() 0086 { 0087 delete container(); 0088 } 0089 0090 bool TreeViewItem::move() 0091 { 0092 // Will happen when trying to move a FAILED, but buffered item 0093 if (!container()) { 0094 qDebug() << "NO ITEM" << index().data(); 0095 return false; 0096 } 0097 0098 container()->setWidth(view()->contentItem()->width()); 0099 0100 auto nextElem = static_cast<TreeViewItem*>(next(Qt::BottomEdge)); 0101 auto prevElem = static_cast<TreeViewItem*>(next(Qt::TopEdge)); 0102 0103 // The root has been moved in the middle of the tree, find the new root 0104 //TODO maybe add a deterministic API instead of O(N) lookup 0105 if (prevElem && m_IsHead) { 0106 m_IsHead = false; 0107 0108 auto root = prevElem; 0109 while (auto prev = root->next(Qt::TopEdge)) 0110 root = static_cast<TreeViewItem*>(prev); 0111 0112 root->move(); 0113 Q_ASSERT(root->m_IsHead); 0114 } 0115 0116 // So other items can be GCed without always resetting to 0x0, note that it 0117 // might be a good idea to extend Flickable to support a virtual 0118 // origin point. 0119 if ((!prevElem) || (nextElem && nextElem->m_IsHead)) { 0120 auto anchors = qvariant_cast<QObject*>(container()->property("anchors")); 0121 anchors->setProperty("top", {}); 0122 container()->setY(0); 0123 m_IsHead = true; 0124 } 0125 else if (prevElem) { 0126 Q_ASSERT(!m_IsHead); 0127 container()->setProperty("y", {}); 0128 auto anchors = qvariant_cast<QObject*>(container()->property("anchors")); 0129 anchors->setProperty("top", prevElem->container()->property("bottom")); 0130 } 0131 0132 // Now, update the next anchors 0133 if (nextElem) { 0134 nextElem->m_IsHead = false; 0135 nextElem->container()->setProperty("y", {}); 0136 0137 auto anchors = qvariant_cast<QObject*>(nextElem->container()->property("anchors")); 0138 anchors->setProperty("top", container()->property("bottom")); 0139 } 0140 0141 updateGeometry(); 0142 0143 return true; 0144 } 0145 0146 bool TreeViewItem::remove() 0147 { 0148 if (container()) { 0149 container()->setParent(nullptr); 0150 container()->setParentItem(nullptr); 0151 container()->setVisible(false); 0152 } 0153 0154 auto nextElem = static_cast<TreeViewItem*>(next(Qt::BottomEdge)); 0155 auto prevElem = static_cast<TreeViewItem*>(next(Qt::TopEdge)); 0156 0157 if (nextElem) { 0158 if (m_IsHead) { 0159 auto anchors = qvariant_cast<QObject*>(nextElem->container()->property("anchors")); 0160 anchors->setProperty("top", {}); 0161 container()->setY(0); 0162 nextElem->m_IsHead = true; 0163 } 0164 else { //TODO maybe eventually use a state machine for this 0165 auto anchors = qvariant_cast<QObject*>(nextElem->container()->property("anchors")); 0166 anchors->setProperty("top", prevElem->container()->property("bottom")); 0167 } 0168 } 0169 0170 return true; 0171 } 0172 0173 QVector<QByteArray>& TreeContextProperties::propertyNames() const 0174 { 0175 static QVector<QByteArray> ret { "expanded" }; 0176 return ret; 0177 } 0178 0179 QVariant TreeContextProperties::getProperty(AbstractItemAdapter* item, uint id, const QModelIndex& index) const 0180 { 0181 Q_UNUSED(index); 0182 Q_ASSERT(id == 0 && item); 0183 return !item->isCollapsed(); 0184 } 0185 0186 bool TreeContextProperties::setProperty(AbstractItemAdapter* item, uint id, const QVariant& value, const QModelIndex& index) const 0187 { 0188 Q_ASSERT(id == 0 && item && value.canConvert<bool>()); 0189 item->setCollapsed(!value.toBool()); 0190 return true; 0191 }