File indexing completed on 2023-09-24 04:09:50
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