File indexing completed on 2024-05-12 05:47:31

0001 /*
0002  * SPDX-FileCopyrightText: 2011 Peter Penz <peter.penz19@gmail.com>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef KITEMLISTVIEWLAYOUTER_H
0008 #define KITEMLISTVIEWLAYOUTER_H
0009 
0010 #include "dolphin_export.h"
0011 
0012 #include <QObject>
0013 #include <QRectF>
0014 #include <QSet>
0015 #include <QSizeF>
0016 #include <QVector>
0017 
0018 class KItemModelBase;
0019 class KItemListSizeHintResolver;
0020 
0021 /**
0022  * @brief Internal helper class for KItemListView to layout the items.
0023  *
0024  * The layouter is capable to align the items within a grid. If the
0025  * scroll-direction is horizontal the column-width of the grid can be
0026  * variable. If the scroll-direction is vertical the row-height of
0027  * the grid can be variable.
0028  *
0029  * The layouter is implemented in a way that it postpones the expensive
0030  * layout operation until a property is read the first time after
0031  * marking the layouter as dirty (see markAsDirty()). This means that
0032  * changing properties of the layouter is not expensive, only the
0033  * first read of a property can get expensive.
0034  */
0035 class DOLPHIN_EXPORT KItemListViewLayouter : public QObject
0036 {
0037     Q_OBJECT
0038 
0039 public:
0040     explicit KItemListViewLayouter(KItemListSizeHintResolver *sizeHintResolver, QObject *parent = nullptr);
0041     ~KItemListViewLayouter() override;
0042 
0043     void setScrollOrientation(Qt::Orientation orientation);
0044     Qt::Orientation scrollOrientation() const;
0045 
0046     void setSize(const QSizeF &size);
0047     QSizeF size() const;
0048 
0049     void setItemSize(const QSizeF &size);
0050     QSizeF itemSize() const;
0051 
0052     /**
0053      * Margin between the rows and columns of items.
0054      */
0055     void setItemMargin(const QSizeF &margin);
0056     QSizeF itemMargin() const;
0057 
0058     /**
0059      * Sets the height of the header that is always aligned
0060      * at the top. A height of <= 0.0 means that no header is
0061      * used.
0062      */
0063     void setHeaderHeight(qreal height);
0064     qreal headerHeight() const;
0065 
0066     /**
0067      * Sets the height of the group header that is used
0068      * to indicate a new item group.
0069      */
0070     void setGroupHeaderHeight(qreal height);
0071     qreal groupHeaderHeight() const;
0072 
0073     /**
0074      * Sets the margin between the last items of the group n and
0075      * the group header for the group n + 1.
0076      */
0077     void setGroupHeaderMargin(qreal margin);
0078     qreal groupHeaderMargin() const;
0079 
0080     void setScrollOffset(qreal scrollOffset);
0081     qreal scrollOffset() const;
0082 
0083     qreal maximumScrollOffset() const;
0084 
0085     void setItemOffset(qreal scrollOffset);
0086     qreal itemOffset() const;
0087 
0088     qreal maximumItemOffset() const;
0089 
0090     void setModel(const KItemModelBase *model);
0091     const KItemModelBase *model() const;
0092 
0093     /**
0094      * @return The first (at least partly) visible index. -1 is returned
0095      *         if the item count is 0.
0096      */
0097     int firstVisibleIndex() const;
0098 
0099     /**
0100      * @return The last (at least partly) visible index. -1 is returned
0101      *         if the item count is 0.
0102      */
0103     int lastVisibleIndex() const;
0104 
0105     /**
0106      * @return Rectangle of the item with the index \a index.
0107      *         The top/left of the bounding rectangle is related to
0108      *         the top/left of the KItemListView. An empty rectangle
0109      *         is returned if an invalid index is given.
0110      */
0111     QRectF itemRect(int index) const;
0112 
0113     /**
0114      * @return Rectangle of the group header for the item with the
0115      *         index \a index. Note that the layouter does not check
0116      *         whether the item really has a header: Usually only
0117      *         the first item of a group gets a header (see
0118      *         isFirstGroupItem()).
0119      */
0120     QRectF groupHeaderRect(int index) const;
0121 
0122     /**
0123      * @return Column of the item with the index \a index.
0124      *         -1 is returned if an invalid index is given.
0125      */
0126     int itemColumn(int index) const;
0127 
0128     /**
0129      * @return Row of the item with the index \a index.
0130      *         -1 is returned if an invalid index is given.
0131      */
0132     int itemRow(int index) const;
0133 
0134     /**
0135      * @return Maximum number of (at least partly) visible items for
0136      *         the given size.
0137      */
0138     int maximumVisibleItems() const;
0139 
0140     /**
0141      * @return True if the item with the index \p itemIndex
0142      *         is the first item within a group.
0143      */
0144     bool isFirstGroupItem(int itemIndex) const;
0145 
0146     /**
0147      * Marks the layouter as dirty. This means as soon as a property of
0148      * the layouter gets read, an expensive relayout will be done.
0149      */
0150     void markAsDirty();
0151 
0152     inline int columnCount() const
0153     {
0154         return m_columnCount;
0155     }
0156 
0157 #ifndef QT_NO_DEBUG
0158     /**
0159      * @return True if the layouter has been marked as dirty and hence has
0160      *         not called yet doLayout(). Is enabled only in the debugging
0161      *         mode, as it is not useful to check the dirty state otherwise.
0162      */
0163     bool isDirty();
0164 #endif
0165 
0166 private:
0167     void doLayout();
0168     void updateVisibleIndexes();
0169     bool createGroupHeaders();
0170 
0171     /**
0172      * @return Minimum width of group headers when grouping is enabled in the horizontal
0173      *         alignment mode. The header alignment is done like this:
0174      *         Header-1 Header-2 Header-3
0175      *         Item 1   Item 4   Item 7
0176      *         Item 2   Item 5   Item 8
0177      *         Item 3   Item 6   Item 9
0178      */
0179     qreal minimumGroupHeaderWidth() const;
0180 
0181 private:
0182     bool m_dirty;
0183     bool m_visibleIndexesDirty;
0184 
0185     Qt::Orientation m_scrollOrientation;
0186     QSizeF m_size;
0187 
0188     QSizeF m_itemSize;
0189     QSizeF m_itemMargin;
0190     qreal m_headerHeight;
0191     const KItemModelBase *m_model;
0192     KItemListSizeHintResolver *m_sizeHintResolver;
0193 
0194     qreal m_scrollOffset;
0195     qreal m_maximumScrollOffset;
0196 
0197     qreal m_itemOffset;
0198     qreal m_maximumItemOffset;
0199 
0200     int m_firstVisibleIndex;
0201     int m_lastVisibleIndex;
0202 
0203     qreal m_columnWidth;
0204     qreal m_xPosInc;
0205     int m_columnCount;
0206 
0207     QVector<qreal> m_rowOffsets;
0208     QVector<qreal> m_columnOffsets;
0209 
0210     // Stores all item indexes that are the first item of a group.
0211     // Assures fast access for KItemListViewLayouter::isFirstGroupItem().
0212     QSet<int> m_groupItemIndexes;
0213     qreal m_groupHeaderHeight;
0214     qreal m_groupHeaderMargin;
0215 
0216     struct ItemInfo {
0217         int column;
0218         int row;
0219     };
0220     QVector<ItemInfo> m_itemInfos;
0221 
0222     friend class KItemListControllerTest;
0223 };
0224 
0225 #endif