File indexing completed on 2025-01-26 05:06:22

0001 /*
0002     SPDX-FileCopyrightText: 2014 Eike Hein <hein@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include <QAbstractItemModel>
0010 
0011 #include "folderplugin_private_export.h"
0012 
0013 class FolderModel;
0014 
0015 class QTimer;
0016 
0017 class FOLDERPLUGIN_TESTS_EXPORT Positioner : public QAbstractItemModel
0018 {
0019     Q_OBJECT
0020 
0021     Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
0022     Q_PROPERTY(FolderModel *folderModel READ folderModel WRITE setFolderModel NOTIFY folderModelChanged)
0023     Q_PROPERTY(int perStripe READ perStripe WRITE setPerStripe NOTIFY perStripeChanged)
0024     Q_PROPERTY(QStringList positions READ positions WRITE setPositions NOTIFY positionsChanged)
0025 
0026 public:
0027     explicit Positioner(QObject *parent = nullptr);
0028     ~Positioner() override;
0029 
0030     bool enabled() const;
0031     void setEnabled(bool enabled);
0032 
0033     FolderModel *folderModel() const;
0034     void setFolderModel(QObject *folderModel);
0035 
0036     int perStripe() const;
0037     void setPerStripe(int perStripe);
0038 
0039     QStringList positions() const;
0040     void setPositions(const QStringList &positions);
0041 
0042     Q_INVOKABLE int map(int row) const;
0043 
0044     Q_INVOKABLE int nearestItem(int currentIndex, Qt::ArrowType direction);
0045 
0046     Q_INVOKABLE bool isBlank(int row) const;
0047     Q_INVOKABLE int indexForUrl(const QUrl &url) const;
0048 
0049     Q_INVOKABLE void setRangeSelected(int anchor, int to);
0050 
0051     Q_INVOKABLE void reset();
0052 
0053     /**
0054      * Performs the move operation in the underlying model.
0055      *
0056      * @param moves List of indexes that were moved. Two
0057      *              consecutive entries correspond to the
0058      *              from and to position.
0059      *
0060      * @return The lowest index that was moved. Used to
0061      *         determine the first selected item.
0062      */
0063     Q_INVOKABLE int move(const QVariantList &moves);
0064 
0065     QHash<int, QByteArray> roleNames() const override;
0066 
0067     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
0068     QModelIndex parent(const QModelIndex &index) const override;
0069 
0070     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
0071 
0072     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
0073     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
0074 
0075 #ifdef BUILD_TESTING
0076     QHash<int, int> proxyToSourceMapping() const
0077     {
0078         return m_proxyToSource;
0079     }
0080     QHash<int, int> sourceToProxyMapping() const
0081     {
0082         return m_sourceToProxy;
0083     }
0084 #endif
0085 
0086 Q_SIGNALS:
0087     void enabledChanged() const;
0088     void folderModelChanged() const;
0089     void perStripeChanged() const;
0090     void positionsChanged() const;
0091 
0092 private Q_SLOTS:
0093     void updatePositions();
0094     void sourceStatusChanged();
0095     void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles);
0096     void sourceModelAboutToBeReset();
0097     void sourceModelReset();
0098     void sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
0099     void sourceRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow);
0100     void sourceRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
0101     void sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
0102     void sourceRowsInserted(const QModelIndex &parent, int first, int last);
0103     void sourceRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow);
0104     void sourceRowsRemoved(const QModelIndex &parent, int first, int last);
0105     void sourceLayoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
0106 
0107 private:
0108     void initMaps(int size = -1);
0109     void updateMaps(int proxyIndex, int sourceIndex);
0110     int firstRow() const;
0111     int lastRow() const;
0112     int firstFreeRow() const;
0113     void applyPositions();
0114     void flushPendingChanges();
0115     void connectSignals(FolderModel *model);
0116     void disconnectSignals(FolderModel *model);
0117 
0118     bool m_enabled;
0119     FolderModel *m_folderModel;
0120 
0121     int m_perStripe;
0122 
0123     QModelIndexList m_pendingChanges;
0124     bool m_ignoreNextTransaction;
0125 
0126     QStringList m_positions;
0127     bool m_deferApplyPositions;
0128     QVariantList m_deferMovePositions;
0129     QTimer *const m_updatePositionsTimer;
0130 
0131     QHash<int, int> m_proxyToSource;
0132     QHash<int, int> m_sourceToProxy;
0133     bool m_beginInsertRowsCalled = false; // used to sync the amount of begin/endInsertRows calls
0134 };