File indexing completed on 2024-11-03 03:41:52
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 2007, 2009 Rafael Fernández López <ereslibre@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #ifndef KCATEGORIZEDVIEW_H 0009 #define KCATEGORIZEDVIEW_H 0010 0011 #include <QListView> 0012 #include <memory> 0013 0014 #include <kitemviews_export.h> 0015 0016 class KCategoryDrawer; 0017 0018 /** 0019 * @class KCategorizedView kcategorizedview.h KCategorizedView 0020 * 0021 * @short Item view for listing items in a categorized fashion optionally 0022 * 0023 * KCategorizedView basically has the same functionality as QListView, only that it also lets you 0024 * layout items in a way that they are categorized visually. 0025 * 0026 * For it to work you will need to set a KCategorizedSortFilterProxyModel and a KCategoryDrawer 0027 * with methods setModel() and setCategoryDrawer() respectively. Also, the model will need to be 0028 * flagged as categorized with KCategorizedSortFilterProxyModel::setCategorizedModel(true). 0029 * 0030 * The way it works (if categorization enabled): 0031 * 0032 * - When sorting, it does more things than QListView does. It will ask the model for the 0033 * special role CategorySortRole (@see KCategorizedSortFilterProxyModel). This can return 0034 * a QString or an int in order to tell the view the order of categories. In this sense, for 0035 * instance, if we are sorting by name ascending, "A" would be before than "B". If we are 0036 * sorting by size ascending, 512 bytes would be before 1024 bytes. This way categories are 0037 * also sorted. 0038 * 0039 * - When the view has to paint, it will ask the model with the role CategoryDisplayRole 0040 * (@see KCategorizedSortFilterProxyModel). It will for instance return "F" for "foo.pdf" if 0041 * we are sorting by name ascending, or "Small" if a certain item has 100 bytes, for example. 0042 * 0043 * For drawing categories, KCategoryDrawer will be used. You can inherit this class to do your own 0044 * drawing. 0045 * 0046 * @note All examples cited before talk about filesystems and such, but have present that this 0047 * is a completely generic class, and it can be used for whatever your purpose is. For 0048 * instance when talking about animals, you can separate them by "Mammal" and "Oviparous". In 0049 * this very case, for example, the CategorySortRole and the CategoryDisplayRole could be the 0050 * same ("Mammal" and "Oviparous"). 0051 * 0052 * @note There is a really performance boost if CategorySortRole returns an int instead of a QString. 0053 * Have present that this role is asked (n * log n) times when sorting and compared. Comparing 0054 * ints is always faster than comparing strings, without mattering how fast the string 0055 * comparison is. Consider thinking of a way of returning ints instead of QStrings if your 0056 * model can contain a high number of items. 0057 * 0058 * @warning Note that for really drawing items in blocks you will need some things to be done: 0059 * - The model set to this view has to be (or inherit if you want to do special stuff 0060 * in it) KCategorizedSortFilterProxyModel. 0061 * - This model needs to be set setCategorizedModel to true. 0062 * - Set a category drawer by calling setCategoryDrawer. 0063 * 0064 * @see KCategorizedSortFilterProxyModel, KCategoryDrawer 0065 * 0066 * @author Rafael Fernández López <ereslibre@kde.org> 0067 */ 0068 class KITEMVIEWS_EXPORT KCategorizedView : public QListView 0069 { 0070 Q_OBJECT 0071 Q_PROPERTY(int categorySpacing READ categorySpacing WRITE setCategorySpacing NOTIFY categorySpacingChanged) 0072 Q_PROPERTY(bool alternatingBlockColors READ alternatingBlockColors WRITE setAlternatingBlockColors NOTIFY alternatingBlockColorsChanged) 0073 Q_PROPERTY(bool collapsibleBlocks READ collapsibleBlocks WRITE setCollapsibleBlocks NOTIFY collapsibleBlocksChanged) 0074 0075 public: 0076 KCategorizedView(QWidget *parent = nullptr); 0077 0078 ~KCategorizedView() override; 0079 0080 /** 0081 * Reimplemented from QAbstractItemView. 0082 */ 0083 void setModel(QAbstractItemModel *model) override; 0084 0085 /** 0086 * Calls to setGridSizeOwn(). 0087 */ 0088 void setGridSize(const QSize &size); 0089 0090 /** 0091 * @warning note that setGridSize is not virtual in the base class (QListView), so if you are 0092 * calling to this method, make sure you have a KCategorizedView pointer around. This 0093 * means that something like: 0094 * @code 0095 * QListView *lv = new KCategorizedView(); 0096 * lv->setGridSize(mySize); 0097 * @endcode 0098 * 0099 * will not call to the expected setGridSize method. Instead do something like this: 0100 * 0101 * @code 0102 * QListView *lv; 0103 * ... 0104 * KCategorizedView *cv = qobject_cast<KCategorizedView*>(lv); 0105 * if (cv) { 0106 * cv->setGridSizeOwn(mySize); 0107 * } else { 0108 * lv->setGridSize(mySize); 0109 * } 0110 * @endcode 0111 * 0112 * @note this method will call to QListView::setGridSize among other operations. 0113 * 0114 * @since 4.4 0115 */ 0116 void setGridSizeOwn(const QSize &size); 0117 0118 /** 0119 * Reimplemented from QAbstractItemView. 0120 */ 0121 QRect visualRect(const QModelIndex &index) const override; 0122 0123 /** 0124 * Returns the current category drawer. 0125 */ 0126 KCategoryDrawer *categoryDrawer() const; 0127 0128 /** 0129 * The category drawer that will be used for drawing categories. 0130 */ 0131 void setCategoryDrawer(KCategoryDrawer *categoryDrawer); 0132 0133 /** 0134 * @return Category spacing. The spacing between categories. 0135 * 0136 * @since 4.4 0137 */ 0138 int categorySpacing() const; 0139 0140 /** 0141 * Stablishes the category spacing. This is the spacing between categories. 0142 * 0143 * @since 4.4 0144 */ 0145 void setCategorySpacing(int categorySpacing); 0146 0147 /** 0148 * @return Whether blocks should be drawn with alternating colors. 0149 * 0150 * @since 4.4 0151 */ 0152 bool alternatingBlockColors() const; 0153 0154 /** 0155 * Sets whether blocks should be drawn with alternating colors. 0156 * 0157 * @since 4.4 0158 */ 0159 void setAlternatingBlockColors(bool enable); 0160 0161 /** 0162 * @return Whether blocks can be collapsed or not. 0163 * 0164 * @since 4.4 0165 */ 0166 bool collapsibleBlocks() const; 0167 0168 /** 0169 * Sets whether blocks can be collapsed or not. 0170 * 0171 * @since 4.4 0172 */ 0173 void setCollapsibleBlocks(bool enable); 0174 0175 /** 0176 * @return Block of indexes that are into @p category. 0177 * 0178 * @since 4.5 0179 */ 0180 QModelIndexList block(const QString &category); 0181 0182 /** 0183 * @return Block of indexes that are represented by @p representative. 0184 * 0185 * @since 4.5 0186 */ 0187 QModelIndexList block(const QModelIndex &representative); 0188 0189 /** 0190 * Reimplemented from QAbstractItemView. 0191 */ 0192 QModelIndex indexAt(const QPoint &point) const override; 0193 0194 /** 0195 * Reimplemented from QAbstractItemView. 0196 */ 0197 void reset() override; 0198 0199 Q_SIGNALS: 0200 void categorySpacingChanged(int spacing); 0201 void alternatingBlockColorsChanged(bool enable); 0202 void collapsibleBlocksChanged(bool enable); 0203 0204 protected: 0205 /** 0206 * Reimplemented from QWidget. 0207 */ 0208 void paintEvent(QPaintEvent *event) override; 0209 0210 /** 0211 * Reimplemented from QWidget. 0212 */ 0213 void resizeEvent(QResizeEvent *event) override; 0214 0215 /** 0216 * Reimplemented from QAbstractItemView. 0217 */ 0218 virtual void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) override; 0219 0220 /** 0221 * Reimplemented from QWidget. 0222 */ 0223 void mouseMoveEvent(QMouseEvent *event) override; 0224 0225 /** 0226 * Reimplemented from QWidget. 0227 */ 0228 void mousePressEvent(QMouseEvent *event) override; 0229 0230 /** 0231 * Reimplemented from QWidget. 0232 */ 0233 void mouseReleaseEvent(QMouseEvent *event) override; 0234 0235 /** 0236 * Reimplemented from QWidget. 0237 */ 0238 void leaveEvent(QEvent *event) override; 0239 0240 /** 0241 * Reimplemented from QAbstractItemView. 0242 */ 0243 void startDrag(Qt::DropActions supportedActions) override; 0244 0245 /** 0246 * Reimplemented from QAbstractItemView. 0247 */ 0248 void dragMoveEvent(QDragMoveEvent *event) override; 0249 0250 /** 0251 * Reimplemented from QAbstractItemView. 0252 */ 0253 void dragEnterEvent(QDragEnterEvent *event) override; 0254 0255 /** 0256 * Reimplemented from QAbstractItemView. 0257 */ 0258 void dragLeaveEvent(QDragLeaveEvent *event) override; 0259 0260 /** 0261 * Reimplemented from QAbstractItemView. 0262 */ 0263 void dropEvent(QDropEvent *event) override; 0264 0265 /** 0266 * Reimplemented from QAbstractItemView. 0267 */ 0268 virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override; 0269 0270 /** 0271 * Reimplemented from QAbstractItemView. 0272 */ 0273 virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override; 0274 0275 /** 0276 * Reimplemented from QAbstractItemView. 0277 */ 0278 void updateGeometries() override; 0279 0280 /** 0281 * Reimplemented from QAbstractItemView. 0282 */ 0283 virtual void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) override; 0284 0285 /** 0286 * Reimplemented from QAbstractItemView. 0287 */ 0288 virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles = QList<int>()) override; 0289 0290 /** 0291 * Reimplemented from QAbstractItemView. 0292 */ 0293 virtual void rowsInserted(const QModelIndex &parent, int start, int end) override; 0294 0295 protected Q_SLOTS: 0296 /** 0297 * @internal 0298 * Reposition items as needed. 0299 */ 0300 virtual void slotLayoutChanged(); 0301 0302 private: 0303 friend class KCategorizedViewPrivate; 0304 std::unique_ptr<class KCategorizedViewPrivate> const d; 0305 0306 Q_PRIVATE_SLOT(d, void _k_slotCollapseOrExpandClicked(QModelIndex)) 0307 }; 0308 0309 #endif // KCATEGORIZEDVIEW_H