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 */