File indexing completed on 2024-05-12 04:43:04
0001 /*************************************************************************** 0002 * Copyright (C) 2017-2018 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 #ifndef KQUICKITEMVIEWS_INDEX_P_H 0019 #define KQUICKITEMVIEWS_INDEX_P_H 0020 0021 #include <QtCore/QModelIndex> 0022 #include <QtCore/QList> 0023 0024 #include <private/geoutils_p.h> 0025 #include <private/indexmetadata_p.h> 0026 0027 class Viewport; 0028 0029 namespace StateTracker { 0030 0031 class Continuity; 0032 0033 /** 0034 * Internal navigation structure designed to support partial tree loading. 0035 * 0036 * This isn't intended to be used directly. It exists as its own class because 0037 * previous iterations were embedded within the model event slots and it made 0038 * it generally unmaintainable. The idea is to provide atomic and batch 0039 * operations that can be unit tested individually (eventually). 0040 * 0041 * * Support continuous but incomplete sets of indices 0042 * * Support indices currently being moved or removed 0043 * * Support moving and reparenting 0044 * * Provide both a geometric/cartesian and tree navigation API. 0045 */ 0046 class Index 0047 { 0048 friend class Continuity; //Manage the m_pContinuity 0049 public: 0050 enum class LifeCycleState { 0051 NEW , /*!< Not part of a tree yet */ 0052 NORMAL , /*!< There is a valid index and a parent node */ 0053 TRANSITION , /*!< Between rowsAbouttoMove and rowsMoved (and removed) */ 0054 ROOT , /*!< This is the root element */ 0055 }; 0056 0057 explicit Index(Viewport *p) : m_Geometry(this, p) {} 0058 virtual ~Index(); 0059 0060 static void insertChildBefore(Index* self, StateTracker::Index* other, StateTracker::Index* parent); 0061 static void insertChildAfter(Index* self, StateTracker::Index* other, StateTracker::Index* parent); 0062 0063 Index *firstChild() const; 0064 Index *lastChild () const; 0065 0066 Index *nextSibling () const; 0067 Index *previousSibling() const; 0068 0069 Index *parent() const; 0070 0071 // Geometric navigation 0072 Index* up () const; //TODO remove 0073 Index* down () const; //TODO remove 0074 Index* left () const; //TODO remove 0075 Index* right() const; //TODO remove 0076 0077 Index* next(Qt::Edge e) const; 0078 0079 int depth() const; 0080 0081 int effectiveRow() const; 0082 int effectiveColumn() const; 0083 QPersistentModelIndex effectiveParentIndex() const; 0084 0085 virtual void remove(bool reparent = false); 0086 static void bridgeGap(Index* first, StateTracker::Index* second); 0087 0088 Index *childrenLookup(const QPersistentModelIndex &index) const; 0089 bool hasChildren(Index *child) const; 0090 int loadedChildrenCount() const; 0091 QList<Index*> allLoadedChildren() const; 0092 bool withinRange(QAbstractItemModel* m, int last, int first) const; 0093 0094 void resetTemporaryIndex(); 0095 bool hasTemporaryIndex(); 0096 void setTemporaryIndex(const QModelIndex& newParent, int row, int column); 0097 0098 /** Return true when both elements have the same parent and are continuous. 0099 * If other is `nullptr` and `i` is first (or last), then that's also true 0100 */ 0101 bool isNeighbor(Index *other) const; 0102 0103 QPersistentModelIndex index() const; 0104 void setModelIndex(const QPersistentModelIndex& idx); 0105 0106 LifeCycleState lifeCycleState() const {return m_LifeCycleState;} 0107 0108 IndexMetadata *metadata() const; 0109 0110 //TODO have one for vertical and horizontal axis 0111 Continuity *continuityTracker() const; 0112 0113 // Runtime tests 0114 #ifdef ENABLE_EXTRA_VALIDATION 0115 void _test_validate_chain() const; 0116 static void _test_bridgeGap(Index *first, Index *second); 0117 #endif 0118 0119 private: 0120 // Because slotRowsMoved is called before the change take effect, cache 0121 // the "new real row and column" since the current index()->row() is now 0122 // garbage. 0123 int m_MoveToRow {-1}; 0124 int m_MoveToColumn {-1}; 0125 QPersistentModelIndex m_MoveToParent; 0126 0127 uint m_Depth {0}; 0128 0129 LifeCycleState m_LifeCycleState {LifeCycleState::NEW}; 0130 0131 Index* m_tSiblings[2] = {nullptr, nullptr}; 0132 Index* m_tChildren[2] = {nullptr, nullptr}; 0133 // Keep the parent to be able to get back to the root 0134 Index* m_pParent {nullptr}; 0135 QPersistentModelIndex m_Index; 0136 0137 //TODO use a btree, not an hash 0138 QHash<QPersistentModelIndex, Index*> m_hLookup; 0139 mutable IndexMetadata m_Geometry; 0140 Continuity *m_pContinuity {nullptr}; 0141 }; 0142 0143 } 0144 0145 /** 0146 * TODO get rid of this and implement paging 0147 * 0148 * Keep track of state "edges". 0149 * 0150 * This allows to manipulate rectangles of QModelIndex similar to QtCore 0151 * dataChanged and other signals. 0152 */ 0153 class ModelRect final 0154 { 0155 public: 0156 StateTracker::Index* getEdge(Qt::Edge e) const; 0157 void setEdge(StateTracker::Index* tti, Qt::Edge e); 0158 0159 Qt::Edges m_Edges {Qt::TopEdge|Qt::LeftEdge|Qt::RightEdge|Qt::BottomEdge}; 0160 private: 0161 GeoRect<StateTracker::Index*> m_lpEdges; //TODO port to ModelRect 0162 }; 0163 0164 // Inject some extra validation when executed in debug mode. 0165 #ifdef ENABLE_EXTRA_VALIDATION 0166 #define _DO_TEST_IDX(f, self, ...) self->f(__VA_ARGS__); 0167 #define _DO_TEST_IDX_STATIC(f, ...) f(__VA_ARGS__); 0168 #else 0169 #define _DO_TEST_IDX(f, self, ...) /*NOP*/; 0170 #define _DO_TEST_IDX_STATIC(f, ...) /*NOP*/; 0171 #endif 0172 0173 #endif