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