File indexing completed on 2024-04-21 03:56:14

0001 /*
0002     SPDX-FileCopyrightText: 2009 Stephen Kelly <steveire@gmail.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #ifndef KREPARENTINGPROXYMODEL_H
0008 #define KREPARENTINGPROXYMODEL_H
0009 
0010 #include <QAbstractProxyModel>
0011 
0012 class KReparentingProxyModelPrivate;
0013 
0014 /**
0015   @brief Restructures a source model, changing the parents of items.
0016 
0017   Subclasses can change the structure of a source model by reimplementing
0018   the isDescendantOf method.
0019 
0020   For example, if the source model is a list,
0021 
0022   @verbatim
0023   0
0024   - A
0025   - B
0026   - C
0027   - D
0028   - E
0029   @endverbatim
0030 
0031   It could be converted to a tree by an implementation something like:
0032 
0033   @code
0034   bool MyReparentingModel::isDescedantOf(const QModelIndex& ancestor, const QModelIndex& descendant ) const
0035   {
0036      return (
0037              (ancestor.data().toString() == "A" && descendant.data().toString() == "B")
0038           || (ancestor.data().toString() == "A" && descendant.data().toString() == "C")
0039           || (ancestor.data().toString() == "B" && descendant.data().toString() == "C")
0040           || (ancestor.data().toString() == "A" && descendant.data().toString() == "D")
0041           )
0042     ? true : KReparentingProxyModel::isDescendantOf(ancestor, descendant);
0043   }
0044   @endcode
0045 
0046   to get this result:
0047 
0048   @verbatim
0049   0
0050   - A
0051   - - B
0052   - - - C
0053   - - D
0054   - E
0055   @endverbatim
0056 
0057   Note that the implementation returns true for a query if "C" is a descendant of "A".
0058   The implementation must return the correct value for all of its descendants, not only its direct parent.
0059   The actual location to insert the descendant in the tree is determined internally by a binary find algorithm.
0060 
0061   The KReparentingProxyModel performs movement of items in the left-right directions, but not the up-down directions.
0062 
0063   \image html reparenting1.png "KReparentingProxyModel moving rows left to right"
0064 
0065   \image html reparenting2.png "KReparentingProxyModel can not move items both left-right and up-down"
0066 
0067   Reordering the rows in a model is the domain of QSortFilterProxyModel. An intermediate QSortFilterProxyModel
0068   can be used to achieve the desired result.
0069 
0070   \image html reparenting3.png "KReparentingProxyModel and QSortFilterProxyModel working in concert to move items both left-right and up-down"
0071 
0072   @code
0073     QAbstractItemModel *model = getModel();
0074 
0075     QSortFilterProxyModel *sorter = getSorter();
0076     sorter->setSourceModel(model);
0077 
0078     KReparentingProxyModel *reparenter = getReparenter();
0079     reparenter->setSourceModel(sorter);
0080 
0081     QTreeView *view = getView();
0082     view->setModel(reparenter);
0083   @endcode
0084 
0085 */
0086 class KReparentingProxyModel : public QAbstractProxyModel
0087 {
0088     Q_OBJECT
0089 public:
0090     KReparentingProxyModel(QObject *parent = nullptr);
0091 
0092     ~KReparentingProxyModel() override;
0093 
0094     QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override;
0095 
0096     QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
0097 
0098     void setSourceModel(QAbstractItemModel *sourceModel) override;
0099 
0100     /**
0101       Reimplement this to return whether @p descendant is a descendant of @p ancestor.
0102     */
0103     virtual bool isDescendantOf(const QModelIndex &ancestor, const QModelIndex &descendant) const;
0104 
0105     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
0106 
0107     QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const override;
0108 
0109     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
0110 
0111     QModelIndex parent(const QModelIndex &child) const override;
0112 
0113     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
0114 
0115     bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
0116 
0117     Qt::DropActions supportedDropActions() const override;
0118 
0119 protected:
0120     void beginChangeRule();
0121     void endChangeRule();
0122 
0123 private:
0124     Q_DECLARE_PRIVATE(KReparentingProxyModel)
0125     //@cond PRIVATE
0126     KReparentingProxyModelPrivate *d_ptr;
0127 
0128     Q_PRIVATE_SLOT(d_func(), void sourceRowsAboutToBeInserted(const QModelIndex &, int, int))
0129     Q_PRIVATE_SLOT(d_func(), void sourceRowsInserted(const QModelIndex &, int, int))
0130     Q_PRIVATE_SLOT(d_func(), void sourceRowsAboutToBeRemoved(const QModelIndex &, int, int))
0131     Q_PRIVATE_SLOT(d_func(), void sourceRowsRemoved(const QModelIndex &, int, int))
0132     Q_PRIVATE_SLOT(d_func(), void sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))
0133     Q_PRIVATE_SLOT(d_func(), void sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int))
0134     Q_PRIVATE_SLOT(d_func(), void sourceModelAboutToBeReset())
0135     Q_PRIVATE_SLOT(d_func(), void sourceModelReset())
0136     Q_PRIVATE_SLOT(d_func(), void sourceLayoutAboutToBeChanged())
0137     Q_PRIVATE_SLOT(d_func(), void sourceLayoutChanged())
0138     Q_PRIVATE_SLOT(d_func(), void sourceDataChanged(const QModelIndex &, const QModelIndex &))
0139 
0140     //@endcond
0141 };
0142 
0143 #endif