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 }