File indexing completed on 2024-05-12 04:43:05
0001 /*************************************************************************** 0002 * Copyright (C) 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 "proximity_p.h" 0019 0020 #include "index_p.h" 0021 0022 using State = StateTracker::Proximity::State; 0023 0024 class ProximityPrivate 0025 { 0026 public: 0027 void nothing() {} 0028 0029 QModelIndexList up () const; 0030 QModelIndexList down() const; 0031 0032 typedef void(ProximityPrivate::*StateF)(); 0033 0034 static const State m_fStateMap [6][3]; 0035 static const StateF m_fStateMachine[6][3]; 0036 0037 State m_State[4] { 0038 State::UNKNOWN, State::UNKNOWN, 0039 State::UNKNOWN, State::UNKNOWN, 0040 }; 0041 0042 StateTracker::Index *m_pSelf; 0043 0044 IndexMetadata *q_ptr; 0045 }; 0046 0047 #define S StateTracker::Proximity::State:: 0048 const StateTracker::Proximity::State ProximityPrivate::m_fStateMap[6][3] = { 0049 /* QUERY DISCARD MOVE */ 0050 /* UNKNOWN */ { S UNKNOWN, S UNKNOWN, S UNKNOWN }, 0051 /* LOADED */ { S UNKNOWN, S UNKNOWN, S UNKNOWN }, 0052 /* MOVED */ { S UNKNOWN, S UNKNOWN, S UNKNOWN }, 0053 /* UNLOADED_TOP */ { S UNKNOWN, S UNKNOWN, S UNKNOWN }, 0054 /* UNLOADED_BOTTOM */ { S UNKNOWN, S UNKNOWN, S UNKNOWN }, 0055 /* UNLOADED_BOTH */ { S UNKNOWN, S UNKNOWN, S UNKNOWN }, 0056 }; 0057 #undef S 0058 0059 #define A &ProximityPrivate:: 0060 const ProximityPrivate::StateF ProximityPrivate::m_fStateMachine[6][3] = { 0061 /* QUERY DISCARD MOVE */ 0062 /* UNKNOWN */ { A nothing, A nothing, A nothing }, 0063 /* LOADED */ { A nothing, A nothing, A nothing }, 0064 /* MOVED */ { A nothing, A nothing, A nothing }, 0065 /* UNLOADED_TOP */ { A nothing, A nothing, A nothing }, 0066 /* UNLOADED_BOTTOM */ { A nothing, A nothing, A nothing }, 0067 /* UNLOADED_BOTH */ { A nothing, A nothing, A nothing }, 0068 }; 0069 #undef A 0070 0071 StateTracker::Proximity::Proximity(IndexMetadata *q, StateTracker::Index *self) : 0072 d_ptr(new ProximityPrivate()) 0073 { 0074 d_ptr->q_ptr = q; 0075 d_ptr->m_pSelf = self; 0076 } 0077 0078 void StateTracker::Proximity::performAction(IndexMetadata::ProximityAction a, Qt::Edge e) 0079 { 0080 Q_UNUSED(e) 0081 Q_UNUSED(a) 0082 Q_ASSERT(false); 0083 } 0084 0085 bool StateTracker::Proximity::canLoadMore(Qt::Edge e) 0086 { 0087 Q_UNUSED(e) 0088 Q_ASSERT(false); 0089 return false; 0090 } 0091 0092 QModelIndexList StateTracker::Proximity::getNext(Qt::Edge e) 0093 { 0094 //TODO right now this will return garbage, this will need some more code to handle 0095 Q_ASSERT(d_ptr->m_pSelf->lifeCycleState() != StateTracker::Index::LifeCycleState::TRANSITION); //TODO 0096 0097 switch (e) { 0098 case Qt::TopEdge: 0099 return d_ptr->up(); 0100 case Qt::BottomEdge: 0101 return d_ptr->down(); 0102 case Qt::LeftEdge: 0103 case Qt::RightEdge: 0104 Q_ASSERT(false); //TODO 0105 } 0106 0107 return {}; 0108 } 0109 0110 QModelIndexList ProximityPrivate::up() const 0111 { 0112 QModelIndexList ret; 0113 0114 const int r = m_pSelf->effectiveRow(); 0115 0116 if (r) { 0117 // When there is a previous sibling, return its last (grant) children 0118 // or return that sibling. 0119 auto idx = m_pSelf->index().model()->index( 0120 r - 1, m_pSelf->index().column(), m_pSelf->effectiveParentIndex() 0121 ); 0122 0123 if (!idx.isValid()) 0124 return ret; 0125 0126 ret << idx; 0127 Q_ASSERT(idx.isValid()); 0128 0129 // Find the deepest (grang)children 0130 while (auto rc = m_pSelf->index().model()->rowCount(idx)) { 0131 ret << (idx = m_pSelf->index().model()->index( 0132 rc - 1, 0, m_pSelf->effectiveParentIndex() 0133 )); 0134 Q_ASSERT(idx.isValid()); 0135 } 0136 0137 return ret; 0138 } 0139 else { 0140 // Up is either the parent or a (grand) children of the parent 0141 auto idx = m_pSelf->effectiveParentIndex(); 0142 0143 if (!idx.isValid()) 0144 return ret; 0145 0146 ret << idx; 0147 0148 // Find the deepest (grang)children 0149 while (auto rc = m_pSelf->index().model()->rowCount(idx)) { 0150 if (!idx.isValid()) 0151 break; 0152 0153 ret << (idx = m_pSelf->index().model()->index( 0154 rc - 1, 0, m_pSelf->effectiveParentIndex() 0155 )); 0156 } 0157 0158 return ret; 0159 } 0160 0161 //TODO recurse parent->rowCount..->last 0162 Q_ASSERT(m_pSelf->parent() && 0163 m_pSelf->parent()->lifeCycleState() == StateTracker::Index::LifeCycleState::ROOT 0164 ); 0165 0166 return ret; 0167 } 0168 0169 QModelIndexList ProximityPrivate::down() const 0170 { 0171 int effRow = m_pSelf->effectiveRow(); 0172 QModelIndex par = m_pSelf->effectiveParentIndex(); 0173 0174 // In *theory*, all relevant parents should be loaded, so it's always 0175 // returning a single item 0176 0177 // Return the first child 0178 if (m_pSelf->index().model()->rowCount(m_pSelf->index())) { 0179 const QModelIndex idx = m_pSelf->index().model()->index(0, 0, m_pSelf->index()); 0180 Q_ASSERT_X(idx.isValid(), "proximity", "rowCount() reported multiple children," 0181 "but index() return an invalid index for {0,0}. Make sure rowCount checks" 0182 " the parent method parameter."); 0183 return idx.isValid() ? QModelIndexList{idx} : QModelIndexList(); 0184 } 0185 0186 // Return the next sibling 0187 if (m_pSelf->index().model()->rowCount(par)-1 > effRow) { 0188 const QModelIndex idx = m_pSelf->index().model()->index(effRow+1, 0, par); 0189 Q_ASSERT_X(idx.isValid(), "proximity", "rowCount() reported multiple children," 0190 "but index() return an invalid index. Make sure rowCount checks the parent."); 0191 return idx.isValid() ? QModelIndexList{idx} : QModelIndexList(); 0192 } 0193 0194 while (par.isValid()) { 0195 auto sib = par.sibling(par.row()+1, par.column()); 0196 if (sib.isValid()) 0197 return {sib}; 0198 0199 par = par.parent(); 0200 } 0201 0202 return {}; 0203 } 0204 0205 /* 0206 if (auto rc = m_pModel->rowCount(idx)) 0207 return m_pModel->index(0,0, idx); 0208 0209 auto sib = idx.siblingAtRow(idx.row()+1); 0210 0211 if (sib.isValid()) 0212 return sib; 0213 0214 if (!idx.parent().isValid()) 0215 return {}; 0216 0217 auto p = idx.parent(); 0218 0219 while (p.isValid()) { 0220 sib = p.siblingAtRow(p.row()+1); 0221 if (sib.isValid()) 0222 return sib; 0223 0224 p = p.parent(); 0225 } 0226 0227 return {}; 0228 */