File indexing completed on 2025-04-27 03:58:28

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2010-01-16
0007  * Description : Item view for listing items in a categorized fashion optionally
0008  *
0009  * SPDX-FileCopyrightText: 2007      by Rafael Fernández López <ereslibre at kde dot org>
0010  * SPDX-FileCopyrightText: 2009-2012 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0011  * SPDX-FileCopyrightText: 2011-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #ifndef DIGIKAM_DCATEGORIZED_VIEW_PRIVATE_H
0018 #define DIGIKAM_DCATEGORIZED_VIEW_PRIVATE_H
0019 
0020 #include "dcategorizedview.h"
0021 
0022 // C++ includes
0023 
0024 #include <cmath>
0025 
0026 // Qt includes
0027 
0028 #include <QVector>
0029 #include <QPainter>
0030 #include <QScrollBar>
0031 #include <QPaintEvent>
0032 
0033 // Local includes
0034 
0035 #include "dcategorizedsortfilterproxymodel.h"
0036 #include "dcategorydrawer.h"
0037 
0038 /**
0039  * NOTE: By defining DOLPHIN_DRAGANDDROP the custom drag and drop implementation of
0040  * DCategorizedView is bypassed to have a consistent drag and drop look for all
0041  * views. Hopefully transparent pixmaps for drag objects will be supported in
0042  * Qt 4.4, so that this workaround can be skipped.
0043  */
0044 #define DOLPHIN_DRAGANDDROP
0045 
0046 class DCategoryDrawer;
0047 
0048 namespace Digikam
0049 {
0050 
0051 class DCategorizedSortFilterProxyModel;
0052 
0053 class Q_DECL_HIDDEN SparseModelIndexVector : public QVector<QModelIndex>
0054 {
0055 public:
0056 
0057     explicit SparseModelIndexVector(int rowCount, QAbstractItemModel* const model_, int column_)
0058         : QVector<QModelIndex>(rowCount),
0059           model(model_),
0060           column(column_)
0061     {
0062     }
0063 
0064     inline QModelIndex& operator[](int i)
0065     {
0066         QModelIndex& index = QVector<QModelIndex>::operator[](i);
0067 
0068         if (!index.isValid())
0069         {
0070             index = model->index(i, column);
0071         }
0072 
0073         return index;
0074     }
0075 
0076 private:
0077 
0078     // not to be used
0079 
0080     const QModelIndex& operator[](int i) const
0081     {
0082         return QVector<QModelIndex>::operator[](i);
0083     }
0084 
0085 private:
0086 
0087     QAbstractItemModel* model;
0088     int                 column;
0089 };
0090 
0091 // ------------------------------------------------------------------------------------
0092 
0093 class Q_DECL_HIDDEN DCategorizedView::Private
0094 {
0095 public:
0096 
0097     explicit Private(DCategorizedView* const listView);
0098     ~Private();
0099 
0100     // Methods
0101 
0102     /**
0103      * Returns the list of items that intersects with @p rect
0104      */
0105     const QModelIndexList& intersectionSet(const QRect& rect);
0106 
0107     /**
0108      * Gets the item rect in the viewport for @p index
0109      */
0110     QRect visualRectInViewport(const QModelIndex& index) const;
0111 
0112     /**
0113      * Returns the category rect in the viewport for @p category
0114      */
0115     QRect visualCategoryRectInViewport(const QString& category) const;
0116 
0117     /**
0118      * Caches and returns the rect that corresponds to @p index
0119      */
0120     const QRect& cacheIndex(const QModelIndex& index);
0121 
0122     /**
0123      * Caches and returns the rect that corresponds to @p category
0124      */
0125     const QRect& cacheCategory(const QString& category);
0126 
0127     /**
0128      * Returns the rect that corresponds to @p index
0129      * @note If the rect is not cached, it becomes cached
0130      */
0131     const QRect& cachedRectIndex(const QModelIndex& index);
0132 
0133     /**
0134      * Returns the rect that corresponds to @p category
0135      * @note If the rect is not cached, it becomes cached
0136      */
0137     const QRect& cachedRectCategory(const QString& category);
0138 
0139     /**
0140      * Returns the visual rect (taking in count x and y offsets) for @p index
0141      * @note If the rect is not cached, it becomes cached
0142      */
0143     QRect visualRect(const QModelIndex& index);
0144 
0145     /**
0146      * Returns the visual rect (taking in count x and y offsets) for @p category
0147      * @note If the rect is not cached, it becomes cached
0148      */
0149     QRect categoryVisualRect(const QString& category);
0150 
0151     /**
0152      * Returns the contents size of this view (topmost category to bottommost index + spacing)
0153      */
0154     QSize contentsSize();
0155 
0156     /**
0157      * This method will draw a new category represented by index
0158      * @p index on the rect specified by @p option.rect, with
0159      * painter @p painter
0160      */
0161     void drawNewCategory(const QModelIndex& index,
0162                          int sortRole,
0163                          const QStyleOption& option,
0164                          QPainter* painter);
0165 
0166     /**
0167      * This method will update scrollbars ranges. Called when our model changes
0168      * or when the view is resized
0169      */
0170     void updateScrollbars();
0171 
0172     /**
0173      * This method will draw dragged items in the painting operation
0174      */
0175     void drawDraggedItems(QPainter* painter);
0176 
0177     /**
0178      * This method will determine which rect needs to be updated because of a
0179      * dragging operation
0180      */
0181     void drawDraggedItems();
0182 
0183     /**
0184      * This method will, starting from the index at begin in the given (sorted) modelIndex List,
0185      * find the last index having the same category as the index to begin with.
0186      */
0187     int categoryUpperBound(SparseModelIndexVector& modelIndexList, int begin, int averageSize = 0);
0188 
0189     /**
0190      * Returns a QItemSelection for all items intersection rect.
0191      */
0192     QItemSelection selectionForRect(const QRect& rect);
0193 
0194 public:
0195 
0196     /// Attributes
0197     class Q_DECL_HIDDEN ElementInfo
0198     {
0199     public:
0200 
0201         explicit ElementInfo()
0202             : relativeOffsetToCategory(0)
0203         {
0204         }
0205 
0206         QString category;
0207         int     relativeOffsetToCategory;
0208     };
0209 
0210 public:
0211 
0212     /// Basic data
0213     DCategorizedView*                 listView;
0214     DCategoryDrawer*                  categoryDrawer;
0215     QSize                             biggestItemSize;
0216 
0217     /// Behavior data
0218     bool                              mouseButtonPressed;
0219     bool                              rightMouseButtonPressed;
0220     bool                              dragLeftViewport;
0221     bool                              drawItemsWhileDragging;
0222     QModelIndex                       hovered;
0223     QString                           hoveredCategory;
0224     QPoint                            initialPressPosition;
0225     QPoint                            mousePosition;
0226     int                               forcedSelectionPosition;
0227 
0228     /**
0229      * Cache data
0230      * We cannot merge some of them into structs because it would affect
0231      * performance
0232      */
0233     QVector<ElementInfo>              elementsInfo;
0234     QHash<int, QRect>                 elementsPosition;
0235     QHash<QString, QVector<int> >     categoriesIndexes;
0236     QHash<QString, QRect>             categoriesPosition;
0237     QStringList                       categories;
0238     QModelIndexList                   intersectedIndexes;
0239     QRect                             lastDraggedItemsRect;
0240     QItemSelection                    lastSelection;
0241 
0242     /// Attributes for speed reasons
0243     DCategorizedSortFilterProxyModel* proxyModel;
0244 };
0245 
0246 } // namespace Digikam
0247 
0248 #endif // DIGIKAM_DCATEGORIZED_VIEW_PRIVATE_H