1 /* 2 * SPDX-FileCopyrightText: 2011 Peter Penz <peter.penz19@gmail.com> 3 * 4 * SPDX-License-Identifier: GPL-2.0-or-later 5 */ 6 7 #ifndef KITEMLISTVIEWLAYOUTER_H 8 #define KITEMLISTVIEWLAYOUTER_H 9 10 #include "dolphin_export.h" 11 12 #include <QObject> 13 #include <QRectF> 14 #include <QSet> 15 #include <QSizeF> 16 #include <QVector> 17 18 class KItemModelBase; 19 class KItemListSizeHintResolver; 20 21 /** 22 * @brief Internal helper class for KItemListView to layout the items. 23 * 24 * The layouter is capable to align the items within a grid. If the 25 * scroll-direction is horizontal the column-width of the grid can be 26 * variable. If the scroll-direction is vertical the row-height of 27 * the grid can be variable. 28 * 29 * The layouter is implemented in a way that it postpones the expensive 30 * layout operation until a property is read the first time after 31 * marking the layouter as dirty (see markAsDirty()). This means that 32 * changing properties of the layouter is not expensive, only the 33 * first read of a property can get expensive. 34 */ 35 class DOLPHIN_EXPORT KItemListViewLayouter : public QObject 36 { 37 Q_OBJECT 38 39 public: 40 explicit KItemListViewLayouter(KItemListSizeHintResolver* sizeHintResolver, QObject* parent = nullptr); 41 ~KItemListViewLayouter() override; 42 43 void setScrollOrientation(Qt::Orientation orientation); 44 Qt::Orientation scrollOrientation() const; 45 46 void setSize(const QSizeF& size); 47 QSizeF size() const; 48 49 void setItemSize(const QSizeF& size); 50 QSizeF itemSize() const; 51 52 /** 53 * Margin between the rows and columns of items. 54 */ 55 void setItemMargin(const QSizeF& margin); 56 QSizeF itemMargin() const; 57 58 /** 59 * Sets the height of the header that is always aligned 60 * at the top. A height of <= 0.0 means that no header is 61 * used. 62 */ 63 void setHeaderHeight(qreal height); 64 qreal headerHeight() const; 65 66 /** 67 * Sets the height of the group header that is used 68 * to indicate a new item group. 69 */ 70 void setGroupHeaderHeight(qreal height); 71 qreal groupHeaderHeight() const; 72 73 /** 74 * Sets the margin between the last items of the group n and 75 * the group header for the group n + 1. 76 */ 77 void setGroupHeaderMargin(qreal margin); 78 qreal groupHeaderMargin() const; 79 80 void setScrollOffset(qreal scrollOffset); 81 qreal scrollOffset() const; 82 83 qreal maximumScrollOffset() const; 84 85 void setItemOffset(qreal scrollOffset); 86 qreal itemOffset() const; 87 88 qreal maximumItemOffset() const; 89 90 void setModel(const KItemModelBase* model); 91 const KItemModelBase* model() const; 92 93 /** 94 * @return The first (at least partly) visible index. -1 is returned 95 * if the item count is 0. 96 */ 97 int firstVisibleIndex() const; 98 99 /** 100 * @return The last (at least partly) visible index. -1 is returned 101 * if the item count is 0. 102 */ 103 int lastVisibleIndex() const; 104 105 /** 106 * @return Rectangle of the item with the index \a index. 107 * The top/left of the bounding rectangle is related to 108 * the top/left of the KItemListView. An empty rectangle 109 * is returned if an invalid index is given. 110 */ 111 QRectF itemRect(int index) const; 112 113 /** 114 * @return Rectangle of the group header for the item with the 115 * index \a index. Note that the layouter does not check 116 * whether the item really has a header: Usually only 117 * the first item of a group gets a header (see 118 * isFirstGroupItem()). 119 */ 120 QRectF groupHeaderRect(int index) const; 121 122 /** 123 * @return Column of the item with the index \a index. 124 * -1 is returned if an invalid index is given. 125 */ 126 int itemColumn(int index) const; 127 128 /** 129 * @return Row of the item with the index \a index. 130 * -1 is returned if an invalid index is given. 131 */ 132 int itemRow(int index) const; 133 134 /** 135 * @return Maximum number of (at least partly) visible items for 136 * the given size. 137 */ 138 int maximumVisibleItems() const; 139 140 /** 141 * @return True if the item with the index \p itemIndex 142 * is the first item within a group. 143 */ 144 bool isFirstGroupItem(int itemIndex) const; 145 146 /** 147 * Marks the layouter as dirty. This means as soon as a property of 148 * the layouter gets read, an expensive relayout will be done. 149 */ 150 void markAsDirty(); 151 columnCount()152 inline int columnCount() const 153 { 154 return m_columnCount; 155 } 156 157 #ifndef QT_NO_DEBUG 158 /** 159 * @return True if the layouter has been marked as dirty and hence has 160 * not called yet doLayout(). Is enabled only in the debugging 161 * mode, as it is not useful to check the dirty state otherwise. 162 */ 163 bool isDirty(); 164 #endif 165 166 private: 167 void doLayout(); 168 void updateVisibleIndexes(); 169 bool createGroupHeaders(); 170 171 /** 172 * @return Minimum width of group headers when grouping is enabled in the horizontal 173 * alignment mode. The header alignment is done like this: 174 * Header-1 Header-2 Header-3 175 * Item 1 Item 4 Item 7 176 * Item 2 Item 5 Item 8 177 * Item 3 Item 6 Item 9 178 */ 179 qreal minimumGroupHeaderWidth() const; 180 181 private: 182 bool m_dirty; 183 bool m_visibleIndexesDirty; 184 185 Qt::Orientation m_scrollOrientation; 186 QSizeF m_size; 187 188 QSizeF m_itemSize; 189 QSizeF m_itemMargin; 190 qreal m_headerHeight; 191 const KItemModelBase* m_model; 192 KItemListSizeHintResolver* m_sizeHintResolver; 193 194 qreal m_scrollOffset; 195 qreal m_maximumScrollOffset; 196 197 qreal m_itemOffset; 198 qreal m_maximumItemOffset; 199 200 int m_firstVisibleIndex; 201 int m_lastVisibleIndex; 202 203 qreal m_columnWidth; 204 qreal m_xPosInc; 205 int m_columnCount; 206 207 QVector<qreal> m_rowOffsets; 208 QVector<qreal> m_columnOffsets; 209 210 // Stores all item indexes that are the first item of a group. 211 // Assures fast access for KItemListViewLayouter::isFirstGroupItem(). 212 QSet<int> m_groupItemIndexes; 213 qreal m_groupHeaderHeight; 214 qreal m_groupHeaderMargin; 215 216 struct ItemInfo { 217 int column; 218 int row; 219 }; 220 QVector<ItemInfo> m_itemInfos; 221 222 friend class KItemListControllerTest; 223 }; 224 225 #endif 226 227 228