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