1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2007, 2009 Rafael Fernández López <ereslibre@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#ifndef KCATEGORIZEDVIEW_H
9#define KCATEGORIZEDVIEW_H
10
11#include <QListView>
12#include <memory>
13
14#include <kitemviews_export.h>
15
16class KCategoryDrawer;
17
18/*!
19 * \class KCategorizedView
20 * \inmodule KItemViews
21 *
22 * \brief Item view for listing items in a categorized fashion optionally.
23 *
24 * KCategorizedView basically has the same functionality as QListView, only that it also lets you
25 * layout items in a way that they are categorized visually.
26 *
27 * For it to work you will need to set a KCategorizedSortFilterProxyModel and a KCategoryDrawer
28 * with methods setModel() and setCategoryDrawer() respectively. Also, the model will need to be
29 * flagged as categorized with KCategorizedSortFilterProxyModel::setCategorizedModel(true).
30 *
31 * The way it works (if categorization enabled):
32 * \list
33 * \li When sorting, it does more things than QListView does. It will ask the model for the
34 * special role CategorySortRole (see KCategorizedSortFilterProxyModel). This can return
35 * a QString or an int in order to tell the view the order of categories. In this sense, for
36 * instance, if we are sorting by name ascending, "A" would be before than "B". If we are
37 * sorting by size ascending, 512 bytes would be before 1024 bytes. This way categories are
38 * also sorted.
39 *
40 * \li When the view has to paint, it will ask the model with the role CategoryDisplayRole
41 * (see KCategorizedSortFilterProxyModel). It will for instance return "F" for "foo.pdf" if
42 * we are sorting by name ascending, or "Small" if a certain item has 100 bytes, for example.
43 * \endlist
44 *
45 * For drawing categories, KCategoryDrawer will be used. You can inherit this class to do your own
46 * drawing.
47 *
48 * \note All examples cited before talk about filesystems and such, but have present that this
49 * is a completely generic class, and it can be used for whatever your purpose is. For
50 * instance when talking about animals, you can separate them by "Mammal" and "Oviparous". In
51 * this very case, for example, the CategorySortRole and the CategoryDisplayRole could be the
52 * same ("Mammal" and "Oviparous").
53 *
54 * \note There is a really performance boost if CategorySortRole returns an int instead of a QString.
55 * Have present that this role is asked (n * log n) times when sorting and compared. Comparing
56 * ints is always faster than comparing strings, without mattering how fast the string
57 * comparison is. Consider thinking of a way of returning ints instead of QStrings if your
58 * model can contain a high number of items.
59 *
60 * \warning Note that for really drawing items in blocks you will need some things to be done:
61 * \list
62 * \li The model set to this view has to be (or inherit if you want to do special stuff
63 * in it) KCategorizedSortFilterProxyModel.
64 * \li This model needs to be set setCategorizedModel to true.
65 * \li Set a category drawer by calling setCategoryDrawer.
66 * \endlist
67 *
68 * \sa KCategorizedSortFilterProxyModel, KCategoryDrawer
69 */
70class KITEMVIEWS_EXPORT KCategorizedView : public QListView
71{
72 Q_OBJECT
73
74 /*!
75 * \property KCategorizedView::categorySpacing
76 */
77 Q_PROPERTY(int categorySpacing READ categorySpacing WRITE setCategorySpacing NOTIFY categorySpacingChanged)
78
79 /*!
80 * \property KCategorizedView::alternatingBlockColors
81 */
82 Q_PROPERTY(bool alternatingBlockColors READ alternatingBlockColors WRITE setAlternatingBlockColors NOTIFY alternatingBlockColorsChanged)
83
84 /*!
85 * \property KCategorizedView::collapsibleBlocks
86 */
87 Q_PROPERTY(bool collapsibleBlocks READ collapsibleBlocks WRITE setCollapsibleBlocks NOTIFY collapsibleBlocksChanged)
88
89public:
90 /*!
91 *
92 */
93 KCategorizedView(QWidget *parent = nullptr);
94
95 ~KCategorizedView() override;
96
97 void setModel(QAbstractItemModel *model) override;
98
99 /*!
100 * Calls to setGridSizeOwn().
101 */
102 void setGridSize(const QSize &size);
103
104 /*!
105 * \warning note that setGridSize is not virtual in the base class (QListView), so if you are
106 * calling to this method, make sure you have a KCategorizedView pointer around. This
107 * means that something like:
108 * \code
109 * QListView *lv = new KCategorizedView();
110 * lv->setGridSize(mySize);
111 * \endcode
112 *
113 * will not call to the expected setGridSize method. Instead do something like this:
114 *
115 * \code
116 * QListView *lv;
117 * ...
118 * KCategorizedView *cv = qobject_cast<KCategorizedView*>(lv);
119 * if (cv) {
120 * cv->setGridSizeOwn(mySize);
121 * } else {
122 * lv->setGridSize(mySize);
123 * }
124 * \endcode
125 *
126 * \note this method will call to QListView::setGridSize among other operations.
127 *
128 * \since 4.4
129 */
130 void setGridSizeOwn(const QSize &size);
131
132 QRect visualRect(const QModelIndex &index) const override;
133
134 /*!
135 * Returns the current category drawer.
136 */
137 KCategoryDrawer *categoryDrawer() const;
138
139 /*!
140 * The category drawer that will be used for drawing categories.
141 */
142 void setCategoryDrawer(KCategoryDrawer *categoryDrawer);
143
144 /*!
145 * Returns the spacing between categories.
146 *
147 * \since 4.4
148 */
149 int categorySpacing() const;
150
151 /*!
152 * Sets the spacing between categories.
153 *
154 * \since 4.4
155 */
156 void setCategorySpacing(int categorySpacing);
157
158 /*!
159 * Returns whether blocks should be drawn with alternating colors.
160 *
161 * \since 4.4
162 */
163 bool alternatingBlockColors() const;
164
165 /*!
166 * Sets whether blocks should be drawn with alternating colors.
167 *
168 * \since 4.4
169 */
170 void setAlternatingBlockColors(bool enable);
171
172 /*!
173 * Returns whether blocks can be collapsed or not.
174 *
175 * \since 4.4
176 */
177 bool collapsibleBlocks() const;
178
179 /*!
180 * Sets whether blocks can be collapsed or not.
181 *
182 * \since 4.4
183 */
184 void setCollapsibleBlocks(bool enable);
185
186 /*!
187 * Returns the block of indexes that are in \a category.
188 *
189 * \since 4.5
190 */
191 QModelIndexList block(const QString &category);
192
193 /*!
194 * Returns the block of indexes that are represented by \a representative.
195 *
196 * \since 4.5
197 */
198 QModelIndexList block(const QModelIndex &representative);
199
200 QModelIndex indexAt(const QPoint &point) const override;
201
202 void reset() override;
203
204Q_SIGNALS:
205
206 /*!
207 *
208 */
209 void categorySpacingChanged(int spacing);
210
211 /*!
212 *
213 */
214 void alternatingBlockColorsChanged(bool enable);
215
216 /*!
217 *
218 */
219 void collapsibleBlocksChanged(bool enable);
220
221protected:
222 void paintEvent(QPaintEvent *event) override;
223
224 void resizeEvent(QResizeEvent *event) override;
225
226 void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) override;
227
228 void mouseMoveEvent(QMouseEvent *event) override;
229
230 void mousePressEvent(QMouseEvent *event) override;
231
232 void mouseReleaseEvent(QMouseEvent *event) override;
233
234 void leaveEvent(QEvent *event) override;
235
236 void startDrag(Qt::DropActions supportedActions) override;
237
238 void dragMoveEvent(QDragMoveEvent *event) override;
239
240 void dragEnterEvent(QDragEnterEvent *event) override;
241
242 void dragLeaveEvent(QDragLeaveEvent *event) override;
243
244 void dropEvent(QDropEvent *event) override;
245
246 QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override;
247
248 void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override;
249
250 void updateGeometries() override;
251
252 void currentChanged(const QModelIndex &current, const QModelIndex &previous) override;
253
254 void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles = QList<int>()) override;
255
256 void rowsInserted(const QModelIndex &parent, int start, int end) override;
257
258protected Q_SLOTS:
259 /*!
260 * \internal
261 * Reposition items as needed.
262 */
263 virtual void slotLayoutChanged();
264
265private:
266 friend class KCategorizedViewPrivate;
267 std::unique_ptr<class KCategorizedViewPrivate> const d;
268
269 Q_PRIVATE_SLOT(d, void _k_slotCollapseOrExpandClicked(QModelIndex))
270};
271
272#endif // KCATEGORIZEDVIEW_H
273

source code of kitemviews/src/kcategorizedview.h