1 /*
2     SPDX-FileCopyrightText: 2009 Stephen Kelly <steveire@gmail.com>
3 
4     SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #ifndef KDESCENDANTSPROXYMODEL_P_H
8 #define KDESCENDANTSPROXYMODEL_P_H
9 
10 #include <QAbstractProxyModel>
11 
12 #include "kitemmodels_export.h"
13 
14 #include <memory>
15 
16 class KDescendantsProxyModelPrivate;
17 
18 /**
19 @class KDescendantsProxyModel kdescendantsproxymodel.h KDescendantsProxyModel
20 
21 @brief Proxy Model for restructuring a Tree into a list.
22 
23 A KDescendantsProxyModel may be used to alter how the items in the tree are presented.
24 
25 Given a model which is represented as a tree:
26 
27 \image html entitytreemodel.png "A plain EntityTreeModel in a view"
28 
29 The KDescendantsProxyModel restructures the sourceModel to represent it as a flat list.
30 
31 @code
32 // ... Create an entityTreeModel
33 KDescendantsProxyModel *descProxy = new KDescendantsProxyModel(this);
34 descProxy->setSourceModel(entityTree);
35 view->setModel(descProxy);
36 @endcode
37 
38 \image html descendantentitiesproxymodel.png "A KDescendantsProxyModel."
39 
40 KDescendantEntitiesProxyModel can also display the ancestors of the index in the source model as part of its display.
41 
42 @code
43 // ... Create an entityTreeModel
44 KDescendantsProxyModel *descProxy = new KDescendantsProxyModel(this);
45 descProxy->setSourceModel(entityTree);
46 
47 // #### This is new
48 descProxy->setDisplayAncestorData(true);
49 descProxy->setAncestorSeparator(QString(" / "));
50 
51 view->setModel(descProxy);
52 
53 @endcode
54 
55 \image html descendantentitiesproxymodel-withansecnames.png "A KDescendantsProxyModel with ancestor names."
56 
57 @since 4.6
58 @author Stephen Kelly <steveire@gmail.com>
59 */
60 class KITEMMODELS_EXPORT KDescendantsProxyModel : public QAbstractProxyModel
61 {
62     Q_OBJECT
63 
64     /**
65      * @since 5.62
66      */
67     Q_PROPERTY(QAbstractItemModel *model READ sourceModel WRITE setSourceModel NOTIFY sourceModelChanged)
68     /**
69      * @since 5.62
70      */
71     Q_PROPERTY(bool displayAncestorData READ displayAncestorData WRITE setDisplayAncestorData NOTIFY displayAncestorDataChanged)
72     /**
73      * @since 5.62
74      */
75     Q_PROPERTY(QString ancestorSeparator READ ancestorSeparator WRITE setAncestorSeparator NOTIFY ancestorSeparatorChanged)
76 
77     /**
78      * If true, all the nodes in the whole tree will be expanded upon loading and all items
79      * of the source model will be shown in the proxy.
80      * The default value is true.
81      * @since 5.74
82      */
83     Q_PROPERTY(bool expandsByDefault READ expandsByDefault WRITE setExpandsByDefault NOTIFY expandsByDefaultChanged)
84 
85 public:
86     enum AdditionalRoles {
87         // Note: use printf "0x%08X\n" $(($RANDOM*$RANDOM))
88         // to define additional roles.
89         LevelRole = 0x14823F9A,
90         ExpandableRole = 0x1CA894AD,
91         ExpandedRole = 0x1E413DA4,
92         HasSiblingsRole = 0x1633CE0C,
93     };
94 
95     /**
96      * Creates a new descendant entities proxy model.
97      *
98      * @param parent The parent object.
99      */
100     explicit KDescendantsProxyModel(QObject *parent = nullptr);
101 
102     /**
103      * Destroys the descendant entities proxy model.
104      */
105     ~KDescendantsProxyModel() override;
106 
107     /**
108      * Sets the source @p model of the proxy.
109      */
110     void setSourceModel(QAbstractItemModel *model) override;
111 
112 #if KITEMMODELS_ENABLE_DEPRECATED_SINCE(4, 8)
113     /**
114      * @deprecated Since 4.8
115      *
116      * This method does nothing.
117      */
118     KITEMMODELS_DEPRECATED_VERSION(4, 8, "Method is a no-op.")
119     void setRootIndex(const QModelIndex &index);
120 #endif
121 
122     /**
123      * Set whether to show ancestor data in the model. If @p display is true, then
124      * a source model which is displayed as
125      *
126      * @code
127      *  -> "Item 0-0" (this is row-depth)
128      *  -> -> "Item 0-1"
129      *  -> -> "Item 1-1"
130      *  -> -> -> "Item 0-2"
131      *  -> -> -> "Item 1-2"
132      *  -> "Item 1-0"
133      * @endcode
134      *
135      * will be displayed as
136      *
137      * @code
138      *  -> *Item 0-0"
139      *  -> "Item 0-0 / Item 0-1"
140      *  -> "Item 0-0 / Item 1-1"
141      *  -> "Item 0-0 / Item 1-1 / Item 0-2"
142      *  -> "Item 0-0 / Item 1-1 / Item 1-2"
143      *  -> "Item 1-0"
144      * @endcode
145      *
146      * If @p display is false, the proxy will show
147      *
148      * @code
149      *  -> *Item 0-0"
150      *  -> "Item 0-1"
151      *  -> "Item 1-1"
152      *  -> "Item 0-2"
153      *  -> "Item 1-2"
154      *  -> "Item 1-0"
155      * @endcode
156      *
157      * Default is false.
158      */
159     void setDisplayAncestorData(bool display);
160 
161     /**
162      * Whether ancestor data will be displayed.
163      */
164     bool displayAncestorData() const;
165 
166     /**
167      * Sets the ancestor @p separator used between data of ancestors.
168      */
169     void setAncestorSeparator(const QString &separator);
170 
171     /**
172      * Separator used between data of ancestors.
173      */
174     QString ancestorSeparator() const;
175 
176     QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override;
177     QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
178 
179     Qt::ItemFlags flags(const QModelIndex &index) const override;
180     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
181     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
182     QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
183 
184     QMimeData *mimeData(const QModelIndexList &indexes) const override;
185     QStringList mimeTypes() const override;
186 
187     bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
188     QModelIndex index(int, int, const QModelIndex &parent = QModelIndex()) const override;
189     QModelIndex parent(const QModelIndex &) const override;
190     int columnCount(const QModelIndex &index = QModelIndex()) const override;
191     QHash<int, QByteArray> roleNames() const override;
192 
193     /**
194      * If true, all the nodes in the whole tree will be expanded upon loading (default)
195      * @param expand whether we want everything expanded upon load
196      * @since 5.74
197      */
198     void setExpandsByDefault(bool expand);
199 
200     /**
201      * @returns true if all the tree nodes are expanded by default upon loading
202      * @since 5.74
203      */
204     bool expandsByDefault() const;
205 
206     /**
207      * @returns true if the source index is mapped in the proxy as expanded, therefore it will show its children
208      * @since 5.74
209      */
210     bool isSourceIndexExpanded(const QModelIndex &sourceIndex) const;
211 
212     /**
213      * @returns true if the source index is visible in the proxy, meaning all its parent hierarchy is expanded.
214      * @since 5.74
215      */
216     bool isSourceIndexVisible(const QModelIndex &sourceIndex) const;
217 
218     /**
219      * Maps a source index as expanded in the proxy, all its children will become visible.
220      * @param sourceIndex an idex of the source model.
221      * @since 5.74
222      */
223     void expandSourceIndex(const QModelIndex &sourceIndex);
224 
225     /**
226      * Maps a source index as collapsed in the proxy, all its children will be hidden.
227      * @param sourceIndex an idex of the source model.
228      * @since 5.74
229      */
230     void collapseSourceIndex(const QModelIndex &sourceIndex);
231 
232     Qt::DropActions supportedDropActions() const override;
233 
234     /**
235     Reimplemented to match all descendants.
236     */
237     virtual QModelIndexList match(const QModelIndex &start,
238                                   int role,
239                                   const QVariant &value,
240                                   int hits = 1,
241                                   Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const override;
242 
243 Q_SIGNALS:
244     void sourceModelChanged();
245     void displayAncestorDataChanged();
246     void ancestorSeparatorChanged();
247     void expandsByDefaultChanged(bool expands);
248     void sourceIndexExpanded(const QModelIndex &sourceIndex);
249     void sourceIndexCollapsed(const QModelIndex &sourceIndex);
250 
251 private:
252     Q_DECLARE_PRIVATE(KDescendantsProxyModel)
253     //@cond PRIVATE
254     std::unique_ptr<KDescendantsProxyModelPrivate> const d_ptr;
255 
256     Q_PRIVATE_SLOT(d_func(), void sourceRowsAboutToBeInserted(const QModelIndex &, int, int))
257     Q_PRIVATE_SLOT(d_func(), void sourceRowsInserted(const QModelIndex &, int, int))
258     Q_PRIVATE_SLOT(d_func(), void sourceRowsAboutToBeRemoved(const QModelIndex &, int, int))
259     Q_PRIVATE_SLOT(d_func(), void sourceRowsRemoved(const QModelIndex &, int, int))
260     Q_PRIVATE_SLOT(d_func(), void sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))
261     Q_PRIVATE_SLOT(d_func(), void sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int))
262     Q_PRIVATE_SLOT(d_func(), void sourceModelAboutToBeReset())
263     Q_PRIVATE_SLOT(d_func(), void sourceModelReset())
264     Q_PRIVATE_SLOT(d_func(), void sourceLayoutAboutToBeChanged())
265     Q_PRIVATE_SLOT(d_func(), void sourceLayoutChanged())
266     Q_PRIVATE_SLOT(d_func(), void sourceDataChanged(const QModelIndex &, const QModelIndex &))
267     Q_PRIVATE_SLOT(d_func(), void sourceModelDestroyed())
268 
269     Q_PRIVATE_SLOT(d_func(), void processPendingParents())
270 
271     // Make these private, they shouldn't be called by applications
272     //   virtual bool insertRows(int , int, const QModelIndex & = QModelIndex());
273     //   virtual bool insertColumns(int, int, const QModelIndex & = QModelIndex());
274     //   virtual bool removeRows(int, int, const QModelIndex & = QModelIndex());
275     //   virtual bool removeColumns(int, int, const QModelIndex & = QModelIndex());
276 
277     //@endcond
278 };
279 
280 #endif
281