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 #include "index_p.h"
0019 
0020 #include "continuity_p.h"
0021 
0022 // Use some constant for readability
0023 #define PREVIOUS 0
0024 #define NEXT 1
0025 #define FIRST 0
0026 #define LAST 1
0027 
0028 StateTracker::Index::~Index()
0029 {
0030     remove();
0031 }
0032 
0033 StateTracker::Index* StateTracker::Index::firstChild() const
0034 {
0035     return m_tChildren[FIRST];
0036 }
0037 
0038 StateTracker::Index* StateTracker::Index::lastChild() const
0039 {
0040     return m_tChildren[LAST];
0041 }
0042 
0043 StateTracker::Index* StateTracker::Index::nextSibling() const
0044 {
0045     return m_tSiblings[NEXT];
0046 }
0047 
0048 StateTracker::Index* StateTracker::Index::previousSibling() const
0049 {
0050     return m_tSiblings[PREVIOUS];
0051 }
0052 
0053 StateTracker::Index *StateTracker::Index::parent() const
0054 {
0055     return m_pParent;
0056 }
0057 
0058 void StateTracker::Index::insertChildAfter(StateTracker::Index* self, StateTracker::Index* other, StateTracker::Index* parent)
0059 {
0060     Q_ASSERT(!self->m_pParent);
0061     Q_ASSERT(parent);
0062     Q_ASSERT(self->m_LifeCycleState == LifeCycleState::NEW);
0063     Q_ASSERT(parent->firstChild() || !other);
0064 
0065     //Always detach first
0066     Q_ASSERT(!self->m_tSiblings[PREVIOUS]);
0067     Q_ASSERT(!self->m_tSiblings[NEXT]);
0068 
0069 
0070     if (!parent->m_tChildren[FIRST]) {
0071         Q_ASSERT(!parent->m_tChildren[LAST]);
0072         Q_ASSERT(!parent->loadedChildrenCount());
0073         parent->m_hLookup[self->m_Index] = self;
0074         parent->m_tChildren[FIRST] = parent->m_tChildren[LAST] = self;
0075         self->m_pParent = parent;
0076         self->m_LifeCycleState = self->m_MoveToRow != -1 ?
0077             LifeCycleState::TRANSITION : LifeCycleState::NORMAL;
0078 
0079         StateTracker::Continuity::select(self);
0080 
0081         _DO_TEST_IDX(_test_validate_chain, parent)
0082         return;
0083     }
0084 
0085     Q_ASSERT(other);
0086     Q_ASSERT(other->m_pParent == parent);
0087     Q_ASSERT(!parent->m_hLookup.contains(self->m_Index));
0088 
0089     Q_ASSERT(!parent->m_hLookup.values().contains(self));
0090     parent->m_hLookup[self->m_Index] = self;
0091     self->m_pParent = parent;
0092 
0093     self->m_LifeCycleState = self->m_MoveToRow != -1 ?
0094         LifeCycleState::TRANSITION : LifeCycleState::NORMAL;
0095 
0096     self->m_tSiblings[NEXT] = other->m_tSiblings[NEXT];
0097 
0098     if (other->m_tSiblings[NEXT]) {
0099         Q_ASSERT(other->m_tSiblings[NEXT]->m_tSiblings[PREVIOUS] == other);
0100         other->m_tSiblings[NEXT]->m_tSiblings[PREVIOUS] = self;
0101     }
0102 
0103     other->m_tSiblings[NEXT] = self;
0104     self->m_tSiblings[PREVIOUS] = other;
0105 
0106     if (parent->m_tChildren[LAST] ==  other)
0107         parent->m_tChildren[LAST] = self;
0108 
0109     StateTracker::Continuity::select(self);
0110 
0111     _DO_TEST_IDX(_test_validate_chain, parent)
0112 }
0113 
0114 void StateTracker::Index::insertChildBefore(StateTracker::Index* self, StateTracker::Index* other, StateTracker::Index* parent)
0115 {
0116     Q_ASSERT(!self->m_pParent);
0117     Q_ASSERT(parent);
0118     Q_ASSERT(self->m_LifeCycleState == LifeCycleState::NEW);
0119     Q_ASSERT(!parent->m_hLookup.contains(self->m_Index));
0120 
0121     _DO_TEST_IDX(_test_validate_chain, parent)
0122 
0123     Q_ASSERT(!parent->m_hLookup.values().contains(self));
0124     parent->m_hLookup[self->m_Index] = self;
0125     self->m_pParent = parent;
0126     self->m_LifeCycleState = self->m_MoveToRow != -1 ?
0127         LifeCycleState::TRANSITION : LifeCycleState::NORMAL;
0128 
0129     if (!parent->firstChild()) {
0130         Q_ASSERT(!parent->lastChild());
0131         parent->m_tChildren[FIRST] = parent->m_tChildren[LAST] = self;
0132         self->m_tSiblings[PREVIOUS] = self->m_tSiblings[NEXT] = nullptr;
0133         Q_ASSERT(!self->nextSibling());
0134         Q_ASSERT(!self->previousSibling());
0135 
0136         StateTracker::Continuity::select(self);
0137 
0138         _DO_TEST_IDX(_test_validate_chain, parent)
0139         return;
0140     }
0141 
0142 //     Q_ASSERT(!self->nextSibling());
0143     Q_ASSERT(parent == self->m_pParent);
0144 
0145     if (!other) {
0146         if (auto f = parent->firstChild())
0147             f->m_tSiblings[PREVIOUS] = self;
0148 
0149         self->m_tSiblings[NEXT] = parent->firstChild();
0150         parent->m_tChildren[FIRST] = self;
0151         Q_ASSERT(!self->previousSibling());
0152         Q_ASSERT(parent->lastChild());
0153 
0154         StateTracker::Continuity::select(self);
0155 
0156         _DO_TEST_IDX(_test_validate_chain, parent)
0157         return;
0158     }
0159 
0160     Q_ASSERT(other);
0161     Q_ASSERT(other->m_pParent == parent);
0162     Q_ASSERT(other->m_pParent == parent);
0163 
0164     if (other == parent->firstChild()) {
0165         Q_ASSERT(!other->previousSibling());
0166         Q_ASSERT(other->nextSibling() || other == parent->lastChild());
0167         parent->m_tChildren[FIRST] = self;
0168         self->m_tSiblings[NEXT] = other;
0169         self->m_tSiblings[PREVIOUS] = nullptr;
0170         other->m_tSiblings[PREVIOUS] = self;
0171         Q_ASSERT(!self->previousSibling());
0172         Q_ASSERT(parent->lastChild());
0173         Q_ASSERT(parent->firstChild());
0174     }
0175     else {
0176         Q_ASSERT(other->previousSibling());
0177         other->previousSibling()->m_tSiblings[NEXT] = self;
0178         self->m_tSiblings[PREVIOUS] = other->previousSibling();
0179         self->m_tSiblings[NEXT] = other;
0180         other->m_tSiblings[PREVIOUS] = self;
0181     }
0182 
0183     StateTracker::Continuity::select(self);
0184 
0185     _DO_TEST_IDX(_test_validate_chain, parent)
0186 }
0187 
0188 /// Fix the issues introduced by createGap (does not update m_pParent and m_hLookup)
0189 void StateTracker::Index::bridgeGap(StateTracker::Index* first, StateTracker::Index* second)
0190 {
0191     // 3 possible case: siblings, first child or last child
0192 
0193     if (first && second && first->m_pParent == second->m_pParent) {
0194         // first and second are siblings
0195 
0196         if (first == first->m_pParent->lastChild())
0197             Q_ASSERT(false);//TODO
0198 
0199         if (first->m_pParent->lastChild() == first) {
0200             Q_ASSERT(!second->nextSibling());
0201             first->m_pParent->m_tChildren[LAST] = second;
0202         }
0203 
0204         first->m_tSiblings [  NEXT  ] = second;
0205         second->m_tSiblings[PREVIOUS] = first;
0206 
0207 //         Q_ASSERT(!second->m_pParent->lastChild() ==second);
0208 
0209     }
0210     else if (second && ((!first) || first == second->m_pParent)) {
0211         auto par = second->m_pParent;
0212         second->remove(true);
0213         Q_ASSERT(second->m_LifeCycleState == LifeCycleState::NEW);
0214         insertChildBefore(second, nullptr, par);
0215     }
0216     else if (first && second && first->m_pParent->lastChild() == first) {
0217         // There is nothing to do
0218         Q_ASSERT(second->parent() == first->parent()->parent());
0219         Q_ASSERT(second->previousSibling() == first->parent());
0220 
0221     }
0222     else if (first) {
0223 
0224         // `first` may be the last child of a last child (of a...)
0225         Q_ASSERT((!second) || second->parent()->lastChild() == second);
0226 
0227         // It's the last element or the second is a last leaf and first is unrelated
0228         first->m_tSiblings[NEXT] = nullptr;
0229 
0230         if (!first->m_pParent->firstChild())
0231             first->m_pParent->m_tChildren[FIRST] = first;
0232 
0233         if (first->m_pParent->lastChild() && first->m_pParent->lastChild() != first) {
0234             first->m_pParent->lastChild()->m_tSiblings[NEXT] = first;
0235             first->m_tSiblings[PREVIOUS] = first->m_pParent->lastChild();
0236         }
0237 
0238         first->m_pParent->m_tChildren[LAST] = first;
0239         Q_ASSERT((!first) || first->m_pParent->lastChild());
0240 //
0241 //         //BEGIN test
0242 //         int count =0;
0243 //         for (auto c = first->m_pParent->lastChild(); c; c = c->previousSibling())
0244 //             count++;
0245 //
0246 //         Q_ASSERT(first->m_pParent->firstChild());
0247 //
0248 //         Q_ASSERT(count == first->m_pParent->m_hLookup.size());
0249 //         //END test
0250     }
0251     else {
0252         Q_ASSERT(false); //Something went really wrong elsewhere
0253     }
0254 
0255     _DO_TEST_IDX_STATIC(_test_bridgeGap, first, second)
0256 }
0257 
0258 void StateTracker::Index::remove(bool reparent)
0259 {
0260     if (m_LifeCycleState == LifeCycleState::NEW)
0261         return;
0262 
0263     // Make sure the StateTracker::Continuity doesn't lose its state too early
0264     // and end up in a crash or memory corruption
0265     StateTracker::Continuity::remove(this);
0266 
0267     // You can't remove ROOT, so this should always be true
0268     Q_ASSERT(m_pParent);
0269 
0270     Q_ASSERT(m_pParent->m_hLookup.values().contains(this));
0271     const int size = m_pParent->m_hLookup.size();
0272     m_pParent->m_hLookup.remove(m_Index);
0273     Q_ASSERT(size == m_pParent->m_hLookup.size()+1);
0274     Q_ASSERT(!m_pParent->m_hLookup.values().contains(this));
0275 
0276     if (!reparent) {
0277         Q_ASSERT(!firstChild());
0278         Q_ASSERT(m_hLookup.isEmpty());
0279     }
0280 
0281     const auto oldNext(nextSibling()), oldPrev(previousSibling());
0282 
0283     // Do not use bridgeGap to prevent rist of recursion on invalid trees
0284     if (oldPrev && oldNext) {
0285         Q_ASSERT(oldPrev != oldNext);
0286         oldPrev->m_tSiblings[NEXT] = oldNext;
0287         oldNext->m_tSiblings[PREVIOUS] = oldPrev;
0288     }
0289     Q_ASSERT((!oldPrev) || oldPrev->previousSibling() != oldPrev);
0290     Q_ASSERT((!oldNext) || oldNext->nextSibling() != oldNext);
0291 
0292 
0293     if (m_pParent->firstChild() == this) {
0294         Q_ASSERT(!oldPrev);
0295         Q_ASSERT((!oldNext) || oldNext->previousSibling() == this);
0296 
0297         if (auto next = oldNext)
0298             next->m_tSiblings[PREVIOUS] = nullptr;
0299 
0300         m_pParent->m_tChildren[FIRST] = oldNext;
0301 
0302         Q_ASSERT((!oldNext) || !oldNext->previousSibling());
0303 
0304         if (m_pParent->firstChild())
0305             m_pParent->firstChild()->m_tSiblings[PREVIOUS] = nullptr;
0306     }
0307 
0308     if (m_pParent->lastChild() == this) {
0309         Q_ASSERT((!oldNext));
0310         Q_ASSERT((!oldPrev) || oldPrev->nextSibling() ==this);
0311 
0312         m_pParent->m_tChildren[LAST] = oldPrev;
0313 
0314         if (m_pParent->lastChild())
0315             m_pParent->lastChild()->m_tSiblings[NEXT] = nullptr;
0316     }
0317 
0318     Q_ASSERT((!m_pParent->firstChild()) || m_pParent->lastChild());
0319 
0320 
0321 //     else if (previousSibling()) {
0322 //         Q_ASSERT(false); //TODO
0323 //     }
0324 //     else if (oldNext) {
0325 //         Q_ASSERT(false); //TODO
0326 //     }
0327 //     else { //FIXME very wrong
0328 //         Q_ASSERT(m_pParent->m_hLookup.isEmpty());
0329 //         m_pParent->m_tChildren[FIRST] = nullptr;
0330 //         m_pParent->m_tChildren[LAST] = nullptr;
0331 //     }
0332 
0333     m_LifeCycleState = LifeCycleState::NEW;
0334     m_pParent = nullptr;
0335 }
0336 
0337 StateTracker::Index* StateTracker::Index::up() const
0338 {
0339     StateTracker::Index* ret = nullptr;
0340 
0341     // Another simple case, there is no parent
0342     if (!m_pParent) {
0343         Q_ASSERT(!m_Index.parent().isValid()); //TODO remove, no longer true when partial loading is implemented
0344 
0345         return nullptr;
0346     }
0347 
0348     // Keep in mind that the "root" means no parent
0349     if (m_pParent && m_pParent->m_pParent && !previousSibling())
0350         return m_pParent;
0351 
0352     ret = previousSibling();
0353 
0354     while (ret && ret->lastChild())
0355         ret = ret->lastChild();
0356 
0357     return ret;
0358 }
0359 
0360 StateTracker::Index* StateTracker::Index::next(Qt::Edge e) const
0361 {
0362     switch (e) {
0363         case Qt::TopEdge:
0364             return up();
0365         case Qt::BottomEdge:
0366             return down();
0367         case Qt::LeftEdge:
0368             return left();
0369         case Qt::RightEdge:
0370             return right();
0371     }
0372 
0373     Q_ASSERT(false);
0374 
0375     return nullptr;
0376 }
0377 
0378 StateTracker::Index* StateTracker::Index::down() const
0379 {
0380     StateTracker::Index* ret = nullptr;
0381     auto i = this;
0382 
0383     if (firstChild()) {
0384         //Q_ASSERT(m_pParent->firstChild()->m_Index.row() == 0); //racy
0385         ret = firstChild();
0386         return ret;
0387     }
0388 
0389     // Recursively unwrap the tree until an element is found
0390     while(i) {
0391         if (i->nextSibling() && (ret = i->nextSibling()))
0392             return ret;
0393 
0394         i = i->parent();
0395     }
0396 
0397     // Can't happen, exists to detect corrupted code
0398     if (m_Index.parent().isValid()) {
0399         Q_ASSERT(m_pParent);
0400 //         Q_ASSERT(m_pParent->parent()->parent()->m_hLookup.size()
0401 //             == m_pParent->m_Index.parent().row()+1);
0402     }
0403 
0404     return ret;
0405 }
0406 
0407 StateTracker::Index* StateTracker::Index::left() const
0408 {
0409     return nullptr; //TODO
0410 }
0411 
0412 StateTracker::Index* StateTracker::Index::right() const
0413 {
0414     return nullptr; //TODO
0415 }
0416 
0417 void ModelRect::setEdge(StateTracker::Index* tti, Qt::Edge e)
0418 {
0419     m_lpEdges.set(tti, e);
0420 }
0421 
0422 StateTracker::Index* ModelRect::getEdge(Qt::Edge e) const
0423 {
0424     return m_lpEdges.get(e);
0425 }
0426 
0427 StateTracker::Index *StateTracker::Index::childrenLookup(const QPersistentModelIndex &index) const
0428 {
0429     return m_hLookup.value(index);
0430 }
0431 
0432 bool StateTracker::Index::hasChildren(StateTracker::Index *child) const
0433 {
0434     return !m_hLookup.keys(child).isEmpty();
0435 }
0436 
0437 int StateTracker::Index::loadedChildrenCount() const
0438 {
0439     return m_hLookup.size();
0440 }
0441 
0442 QList<StateTracker::Index*> StateTracker::Index::allLoadedChildren() const
0443 {
0444     return m_hLookup.values();
0445 }
0446 
0447 bool StateTracker::Index::withinRange(QAbstractItemModel* m, int last, int first) const
0448 {
0449     // Return true if the previous element or next element are loaded
0450     const QModelIndex prev = first ? m->index(first - 1, 0, m_Index) : QModelIndex();
0451     const QModelIndex next = first ? m->index(last  + 1, 0, m_Index) : QModelIndex();
0452 
0453     return (prev.isValid() && m_hLookup.contains(prev))
0454         || (next.isValid() && m_hLookup.contains(next));
0455 }
0456 
0457 int StateTracker::Index::effectiveRow() const
0458 {
0459     return m_MoveToRow == -1 ?
0460         m_Index.row() : m_MoveToRow;
0461 }
0462 
0463 int StateTracker::Index::effectiveColumn() const
0464 {
0465     return m_MoveToColumn == -1 ?
0466         m_Index.column() : m_MoveToColumn;
0467 }
0468 
0469 QPersistentModelIndex StateTracker::Index::effectiveParentIndex() const
0470 {
0471     return m_LifeCycleState == LifeCycleState::TRANSITION ?
0472         m_MoveToParent : m_pParent->index();
0473 }
0474 
0475 void StateTracker::Index::resetTemporaryIndex()
0476 {
0477     Q_ASSERT(m_pParent);
0478     Q_ASSERT(m_LifeCycleState == LifeCycleState::TRANSITION);
0479     m_LifeCycleState = LifeCycleState::NORMAL;
0480     m_MoveToRow    = -1;
0481     m_MoveToColumn = -1;
0482     m_MoveToParent = QModelIndex();
0483 }
0484 
0485 bool StateTracker::Index::hasTemporaryIndex()
0486 {
0487     return m_MoveToRow != -1 || m_MoveToColumn != -1;
0488 }
0489 
0490 void StateTracker::Index::setTemporaryIndex(const QModelIndex& newParent, int row, int column)
0491 {
0492     //TODO handle parent
0493     Q_ASSERT(m_LifeCycleState == LifeCycleState::NORMAL);
0494     m_MoveToParent   = newParent;
0495     m_MoveToRow      = row;
0496     m_MoveToColumn   = column;
0497     m_LifeCycleState = LifeCycleState::TRANSITION;
0498 }
0499 
0500 QPersistentModelIndex StateTracker::Index::index() const
0501 {
0502     return m_Index;
0503 }
0504 
0505 void StateTracker::Index::setModelIndex(const QPersistentModelIndex& idx)
0506 {
0507     Q_ASSERT(m_LifeCycleState == LifeCycleState::NEW);
0508     m_Index = idx;
0509 }
0510 
0511 int StateTracker::Index::depth() const
0512 {
0513     int d = 0;
0514 
0515     auto s = this;
0516 
0517     while((s = s->parent()) && ++d);
0518 
0519     return d;//FIXME m_pTTI->m_Depth;
0520 }
0521 
0522 bool StateTracker::Index::isNeighbor(Index *other) const
0523 {
0524     if (!other)
0525         return parent()->lastChild() == this || parent()->firstChild() == this;
0526 
0527     return previousSibling() == other || nextSibling() == other;
0528 }
0529 
0530 IndexMetadata *StateTracker::Index::metadata() const
0531 {
0532     return &m_Geometry;
0533 }
0534 
0535 StateTracker::Continuity *StateTracker::Index::continuityTracker() const
0536 {
0537     Q_ASSERT(m_pContinuity);
0538 
0539     // This should not happen and means the StateTracker::Continuity::size()
0540     // is currently returning the wrong value, but it can be recovered from and
0541     // is not worth crashing over this in release mode.
0542     if (!m_pContinuity)
0543         StateTracker::Continuity::select(const_cast<Index*>(this));
0544 
0545     return m_pContinuity;
0546 }
0547 
0548 #undef PREVIOUS
0549 #undef NEXT
0550 #undef FIRST
0551 #undef LAST
0552 #undef TTI