File indexing completed on 2024-04-21 04:41:46

0001 /***************************************************************************
0002  *   Copyright (C) 2017 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 "viewbase.h"
0019 
0020 // Qt
0021 #include <QtCore/QTimer>
0022 #include <QQmlContext>
0023 
0024 // LibStdC++
0025 #include <functional>
0026 
0027 // KQuickItemViews
0028 #include "private/statetracker/viewitem_p.h"
0029 #include "adapters/abstractitemadapter.h"
0030 #include "adapters/selectionadapter.h"
0031 #include "private/statetracker/content_p.h"
0032 #include "viewport.h"
0033 #include "contextadapterfactory.h"
0034 #include "adapters/contextadapter.h"
0035 #include "adapters/modeladapter.h"
0036 #include "private/selectionadapter_p.h"
0037 #include "extensions/contextextension.h"
0038 
0039 class ViewBasePrivate final : public QObject
0040 {
0041     Q_OBJECT
0042 public:
0043 
0044     enum class State {
0045         UNFILLED, /*!< There is less items that the space available          */
0046         ANCHORED, /*!< Some items are out of view, but it's at the beginning */
0047         SCROLLED, /*!< It's scrolled to a random point                       */
0048         AT_END  , /*!< It's at the end of the items                          */
0049         ERROR   , /*!< Something went wrong                                  */
0050     };
0051 
0052     enum class Action {
0053         INSERTION    = 0,
0054         REMOVAL      = 1,
0055         MOVE         = 2,
0056         RESET_SCROLL = 3,
0057         SCROLL       = 4,
0058     };
0059 
0060     typedef bool(ViewBasePrivate::*StateF)();
0061 
0062     static const State  m_fStateMap    [5][5];
0063     static const StateF m_fStateMachine[5][5];
0064 
0065     QQmlEngine *m_pEngine {      nullptr    };
0066     Qt::Corner  m_Corner  {Qt::TopLeftCorner};
0067 
0068     QVector<ModelAdapter*> m_lAdapters;
0069 
0070     State m_State {State::UNFILLED};
0071 
0072     ViewBase* q_ptr;
0073 
0074 private:
0075     bool nothing     ();
0076     bool resetScoll  ();
0077     bool refresh     ();
0078     bool refreshFront();
0079     bool refreshBack ();
0080     bool error       ();
0081 
0082 public Q_SLOTS:
0083     void slotContentChanged();
0084 };
0085 
0086 /// Add the same property as the QtQuick.ListView
0087 class ModelIndexGroup final : public ContextExtension
0088 {
0089 public:
0090     virtual ~ModelIndexGroup() {}
0091     virtual QVector<QByteArray>& propertyNames() const override;
0092     virtual QVariant getProperty(AbstractItemAdapter* item, uint id, const QModelIndex& index) const override;
0093 };
0094 
0095 #define S ViewBasePrivate::State::
0096 const ViewBasePrivate::State ViewBasePrivate::m_fStateMap[5][5] = {
0097 /*              INSERTION    REMOVAL       MOVE     RESET_SCROLL    SCROLL  */
0098 /*UNFILLED */ { S ANCHORED, S UNFILLED , S UNFILLED , S UNFILLED, S UNFILLED },
0099 /*ANCHORED */ { S ANCHORED, S ANCHORED , S ANCHORED , S ANCHORED, S SCROLLED },
0100 /*SCROLLED */ { S SCROLLED, S SCROLLED , S SCROLLED , S ANCHORED, S SCROLLED },
0101 /*AT_END   */ { S AT_END  , S AT_END   , S AT_END   , S ANCHORED, S SCROLLED },
0102 /*ERROR    */ { S ERROR   , S ERROR    , S ERROR    , S ERROR   , S ERROR    },
0103 };
0104 #undef S
0105 
0106 #define A &ViewBasePrivate::
0107 const ViewBasePrivate::StateF ViewBasePrivate::m_fStateMachine[5][5] = {
0108 /*              INSERTION           REMOVAL          MOVE        RESET_SCROLL     SCROLL  */
0109 /*UNFILLED*/ { A refreshFront, A refreshFront , A refreshFront , A nothing   , A nothing  },
0110 /*ANCHORED*/ { A refreshFront, A refreshFront , A refreshFront , A nothing   , A refresh  },
0111 /*SCROLLED*/ { A refresh     , A refresh      , A refresh      , A resetScoll, A refresh  },
0112 /*AT_END  */ { A refreshBack , A refreshBack  , A refreshBack  , A resetScoll, A refresh  },
0113 /*ERROR   */ { A error       , A error        , A error        , A error     , A error    },
0114 };
0115 #undef A
0116 
0117 ViewBase::ViewBase(QQuickItem* parent) : Flickable(parent), d_ptr(new ViewBasePrivate())
0118 {
0119     d_ptr->q_ptr = this;
0120 }
0121 
0122 ViewBase::~ViewBase()
0123 {
0124     delete d_ptr;
0125 }
0126 
0127 void ViewBase::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
0128 {
0129     Q_UNUSED(oldGeometry)
0130     contentItem()->setWidth(newGeometry.width());
0131 
0132     // Resize the viewport(s)
0133     for (auto ma : qAsConst(d_ptr->m_lAdapters)) {
0134         const auto vps = ma->viewports();
0135         for (auto vp : qAsConst(vps))
0136             vp->resize(
0137                 QRectF {0.0, 0.0, newGeometry.width(), newGeometry.height()}
0138             );
0139     }
0140 }
0141 
0142 void ViewBase::reload()
0143 {
0144     Q_ASSERT(false);
0145 }
0146 
0147 void ViewBasePrivate::slotContentChanged()
0148 {
0149     emit q_ptr->contentChanged();
0150 }
0151 
0152 bool ViewBasePrivate::nothing()
0153 { return true; }
0154 
0155 bool ViewBasePrivate::resetScoll()
0156 {
0157     return true;
0158 }
0159 
0160 bool ViewBasePrivate::refresh()
0161 {
0162     return true;
0163 }
0164 
0165 bool ViewBasePrivate::refreshFront()
0166 {
0167     return true;
0168 }
0169 
0170 bool ViewBasePrivate::refreshBack()
0171 {
0172     return true;
0173 }
0174 
0175 bool ViewBasePrivate::error()
0176 {
0177     Q_ASSERT(false);
0178     return true;
0179 }
0180 
0181 void ViewBase::refresh()
0182 {
0183     //TODO
0184 }
0185 
0186 QVector<QByteArray>& ModelIndexGroup::propertyNames() const
0187 {
0188     static QVector<QByteArray> ret {
0189         "index"     ,
0190         "rootIndex" ,
0191         "rowCount"  ,
0192     };
0193 
0194     return ret;
0195 }
0196 
0197 QVariant ModelIndexGroup::getProperty(AbstractItemAdapter* item, uint id, const QModelIndex& index) const
0198 {
0199     switch(id) {
0200         case 0 /*index*/:
0201             return index.row();
0202         case 1 /*rootIndex*/:
0203             return item->index(); // That's a QPersistentModelIndex and is a better fit
0204         case 2 /*rowCount*/:
0205             return index.model()->rowCount(index);
0206         //FIXME add parent index
0207         //FIXME add parent item?
0208         //FIXME depth
0209     }
0210 
0211     Q_ASSERT(false);
0212     return {};
0213 }
0214 
0215 void ViewBase::addModelAdapter(ModelAdapter* a)
0216 {
0217     connect(a, &ModelAdapter::contentChanged,
0218         d_ptr, &ViewBasePrivate::slotContentChanged);
0219 
0220     a->contextAdapterFactory()->addContextExtension(new ModelIndexGroup());
0221 
0222     d_ptr->m_lAdapters << a;
0223 }
0224 
0225 void ViewBase::removeModelAdapter(ModelAdapter* a)
0226 {
0227     Q_ASSERT(false); //TODO
0228     d_ptr->m_lAdapters.removeAll(a);
0229 }
0230 
0231 QVector<ModelAdapter*> ViewBase::modelAdapters() const
0232 {
0233     return d_ptr->m_lAdapters;
0234 }
0235 
0236 bool ViewBase::isEmpty() const
0237 {
0238     for (auto a : qAsConst(d_ptr->m_lAdapters)) {
0239         if (!a->isEmpty())
0240             return false;
0241     }
0242 
0243     return true;
0244 }
0245 
0246 Qt::Corner ViewBase::gravity() const
0247 {
0248     return d_ptr->m_Corner;
0249 }
0250 
0251 void ViewBase::setGravity(Qt::Corner g)
0252 {
0253     d_ptr->m_Corner = g;
0254     refresh();
0255 }
0256 
0257 #include <viewbase.moc>