File indexing completed on 2024-05-19 05:48:09
0001 /* 0002 * SPDX-FileCopyrightText: 2011 Peter Penz <peter.penz19@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kitemlistsizehintresolver.h" 0008 #include "kitemviews/kitemlistview.h" 0009 0010 KItemListSizeHintResolver::KItemListSizeHintResolver(const KItemListView *itemListView) 0011 : m_itemListView(itemListView) 0012 , m_logicalHeightHintCache() 0013 , m_logicalWidthHint(0.0) 0014 , m_minHeightHint(0.0) 0015 , m_needsResolving(false) 0016 { 0017 } 0018 0019 KItemListSizeHintResolver::~KItemListSizeHintResolver() 0020 { 0021 } 0022 0023 QSizeF KItemListSizeHintResolver::minSizeHint() 0024 { 0025 updateCache(); 0026 return QSizeF(m_logicalWidthHint, m_minHeightHint); 0027 } 0028 0029 QSizeF KItemListSizeHintResolver::sizeHint(int index) 0030 { 0031 updateCache(); 0032 return QSizeF(m_logicalWidthHint, m_logicalHeightHintCache.at(index).first); 0033 } 0034 0035 bool KItemListSizeHintResolver::isElided(int index) 0036 { 0037 return m_logicalHeightHintCache.at(index).second; 0038 } 0039 0040 void KItemListSizeHintResolver::itemsInserted(const KItemRangeList &itemRanges) 0041 { 0042 int insertedCount = 0; 0043 for (const KItemRange &range : itemRanges) { 0044 insertedCount += range.count; 0045 } 0046 0047 const int currentCount = m_logicalHeightHintCache.count(); 0048 m_logicalHeightHintCache.reserve(currentCount + insertedCount); 0049 0050 // We build the new list from the end to the beginning to mimize the 0051 // number of moves. 0052 m_logicalHeightHintCache.insert(m_logicalHeightHintCache.end(), insertedCount, std::make_pair(0.0, false)); 0053 0054 int sourceIndex = currentCount - 1; 0055 int targetIndex = m_logicalHeightHintCache.count() - 1; 0056 int itemsToInsertBeforeCurrentRange = insertedCount; 0057 0058 for (int rangeIndex = itemRanges.count() - 1; rangeIndex >= 0; --rangeIndex) { 0059 const KItemRange &range = itemRanges.at(rangeIndex); 0060 itemsToInsertBeforeCurrentRange -= range.count; 0061 0062 // First: move all existing items that must be put behind 'range'. 0063 while (targetIndex >= itemsToInsertBeforeCurrentRange + range.index + range.count) { 0064 m_logicalHeightHintCache[targetIndex] = m_logicalHeightHintCache[sourceIndex]; 0065 --sourceIndex; 0066 --targetIndex; 0067 } 0068 0069 // Then: insert QSizeF() for the items which are inserted into 'range'. 0070 while (targetIndex >= itemsToInsertBeforeCurrentRange + range.index) { 0071 m_logicalHeightHintCache[targetIndex] = std::make_pair(0.0, false); 0072 --targetIndex; 0073 } 0074 } 0075 0076 m_needsResolving = true; 0077 0078 Q_ASSERT(m_logicalHeightHintCache.count() == m_itemListView->model()->count()); 0079 } 0080 0081 void KItemListSizeHintResolver::itemsRemoved(const KItemRangeList &itemRanges) 0082 { 0083 const QVector<std::pair<qreal, bool>>::iterator begin = m_logicalHeightHintCache.begin(); 0084 const QVector<std::pair<qreal, bool>>::iterator end = m_logicalHeightHintCache.end(); 0085 0086 KItemRangeList::const_iterator rangeIt = itemRanges.constBegin(); 0087 const KItemRangeList::const_iterator rangeEnd = itemRanges.constEnd(); 0088 0089 QVector<std::pair<qreal, bool>>::iterator destIt = begin + rangeIt->index; 0090 QVector<std::pair<qreal, bool>>::iterator srcIt = destIt + rangeIt->count; 0091 0092 ++rangeIt; 0093 0094 while (srcIt != end) { 0095 *destIt = *srcIt; 0096 ++destIt; 0097 ++srcIt; 0098 0099 if (rangeIt != rangeEnd && srcIt == begin + rangeIt->index) { 0100 // Skip the items in the next removed range. 0101 srcIt += rangeIt->count; 0102 ++rangeIt; 0103 } 0104 } 0105 0106 m_logicalHeightHintCache.erase(destIt, end); 0107 0108 // Note that the cache size might temporarily not match the model size if 0109 // this function is called from KItemListView::setModel() to empty the cache. 0110 if (!m_logicalHeightHintCache.isEmpty() && m_itemListView->model()) { 0111 Q_ASSERT(m_logicalHeightHintCache.count() == m_itemListView->model()->count()); 0112 } 0113 } 0114 0115 void KItemListSizeHintResolver::itemsMoved(const KItemRange &range, const QList<int> &movedToIndexes) 0116 { 0117 QVector<std::pair<qreal, bool>> newLogicalHeightHintCache(m_logicalHeightHintCache); 0118 0119 const int movedRangeEnd = range.index + range.count; 0120 for (int i = range.index; i < movedRangeEnd; ++i) { 0121 const int newIndex = movedToIndexes.at(i - range.index); 0122 newLogicalHeightHintCache[newIndex] = m_logicalHeightHintCache.at(i); 0123 } 0124 0125 m_logicalHeightHintCache = newLogicalHeightHintCache; 0126 } 0127 0128 void KItemListSizeHintResolver::itemsChanged(int index, int count, const QSet<QByteArray> &roles) 0129 { 0130 Q_UNUSED(roles) 0131 while (count) { 0132 m_logicalHeightHintCache[index] = std::make_pair(0.0, false); 0133 ++index; 0134 --count; 0135 } 0136 0137 m_needsResolving = true; 0138 } 0139 0140 void KItemListSizeHintResolver::clearCache() 0141 { 0142 m_logicalHeightHintCache.fill(std::make_pair(0.0, false)); 0143 m_needsResolving = true; 0144 } 0145 0146 void KItemListSizeHintResolver::updateCache() 0147 { 0148 if (m_needsResolving) { 0149 m_itemListView->calculateItemSizeHints(m_logicalHeightHintCache, m_logicalWidthHint); 0150 m_needsResolving = false; 0151 } 0152 }