File indexing completed on 2024-04-21 15:01:33

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)
0072     Q_PROPERTY(bool alternatingBlockColors READ alternatingBlockColors WRITE setAlternatingBlockColors)
0073     Q_PROPERTY(bool collapsibleBlocks READ collapsibleBlocks WRITE setCollapsibleBlocks)
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 protected:
0200     /**
0201      * Reimplemented from QWidget.
0202      */
0203     void paintEvent(QPaintEvent *event) override;
0204 
0205     /**
0206      * Reimplemented from QWidget.
0207      */
0208     void resizeEvent(QResizeEvent *event) override;
0209 
0210     /**
0211      * Reimplemented from QAbstractItemView.
0212      */
0213     virtual void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) override;
0214 
0215     /**
0216      * Reimplemented from QWidget.
0217      */
0218     void mouseMoveEvent(QMouseEvent *event) override;
0219 
0220     /**
0221      * Reimplemented from QWidget.
0222      */
0223     void mousePressEvent(QMouseEvent *event) override;
0224 
0225     /**
0226      * Reimplemented from QWidget.
0227      */
0228     void mouseReleaseEvent(QMouseEvent *event) override;
0229 
0230     /**
0231      * Reimplemented from QWidget.
0232      */
0233     void leaveEvent(QEvent *event) override;
0234 
0235     /**
0236      * Reimplemented from QAbstractItemView.
0237      */
0238     void startDrag(Qt::DropActions supportedActions) override;
0239 
0240     /**
0241      * Reimplemented from QAbstractItemView.
0242      */
0243     void dragMoveEvent(QDragMoveEvent *event) override;
0244 
0245     /**
0246      * Reimplemented from QAbstractItemView.
0247      */
0248     void dragEnterEvent(QDragEnterEvent *event) override;
0249 
0250     /**
0251      * Reimplemented from QAbstractItemView.
0252      */
0253     void dragLeaveEvent(QDragLeaveEvent *event) override;
0254 
0255     /**
0256      * Reimplemented from QAbstractItemView.
0257      */
0258     void dropEvent(QDropEvent *event) override;
0259 
0260     /**
0261      * Reimplemented from QAbstractItemView.
0262      */
0263     virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override;
0264 
0265     /**
0266      * Reimplemented from QAbstractItemView.
0267      */
0268     virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override;
0269 
0270     /**
0271      * Reimplemented from QAbstractItemView.
0272      */
0273     void updateGeometries() override;
0274 
0275     /**
0276      * Reimplemented from QAbstractItemView.
0277      */
0278     virtual void currentChanged(const QModelIndex &current, const QModelIndex &previous) override;
0279 
0280     /**
0281      * Reimplemented from QAbstractItemView.
0282      */
0283     virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>()) override;
0284 
0285     /**
0286      * Reimplemented from QAbstractItemView.
0287      */
0288     virtual void rowsInserted(const QModelIndex &parent, int start, int end) override;
0289 
0290 protected Q_SLOTS:
0291 #if KITEMVIEWS_BUILD_DEPRECATED_SINCE(4, 4)
0292     /**
0293      * @internal
0294      * @deprecated Since 4.4.
0295      */
0296     KITEMVIEWS_DEPRECATED_VERSION(4, 4, "No longer use")
0297     virtual void rowsInsertedArtifficial(const QModelIndex &parent, int start, int end);
0298 #endif
0299 
0300 #if KITEMVIEWS_BUILD_DEPRECATED_SINCE(4, 4)
0301     /**
0302      * @internal
0303      * @deprecated Since 4.4.
0304      */
0305     KITEMVIEWS_DEPRECATED_VERSION(4, 4, "No longer use")
0306     virtual void rowsRemoved(const QModelIndex &parent, int start, int end);
0307 #endif
0308 
0309     /**
0310      * @internal
0311      * Reposition items as needed.
0312      */
0313     virtual void slotLayoutChanged();
0314 
0315 private:
0316     friend class KCategorizedViewPrivate;
0317     std::unique_ptr<class KCategorizedViewPrivate> const d;
0318 
0319     Q_PRIVATE_SLOT(d, void _k_slotCollapseOrExpandClicked(QModelIndex))
0320 };
0321 
0322 #endif // KCATEGORIZEDVIEW_H