From ec38f1cdb641f0b277100edd92b268ec856e2ece Mon Sep 17 00:00:00 2001 From: Peter Penz Date: Tue, 27 Sep 2011 20:42:58 +0200 Subject: [PATCH] Details view: Improve performance When inserting items or when updating the item-roles there is no need to recalculate the column-widths for all items to get an optimized column-width. --- src/kitemviews/kfileitemlistview.cpp | 49 ++++++++++++++++---------- src/kitemviews/kfileitemlistview.h | 2 +- src/kitemviews/kitemlistview.cpp | 51 +++++++++++++++++++++++++--- src/kitemviews/kitemlistview.h | 8 ++++- 4 files changed, 86 insertions(+), 24 deletions(-) diff --git a/src/kitemviews/kfileitemlistview.cpp b/src/kitemviews/kfileitemlistview.cpp index 50f28fe5b..f1594b10b 100644 --- a/src/kitemviews/kfileitemlistview.cpp +++ b/src/kitemviews/kfileitemlistview.cpp @@ -167,31 +167,42 @@ QSizeF KFileItemListView::itemSizeHint(int index) const return QSize(); } -QHash KFileItemListView::visibleRolesSizes() const +QHash KFileItemListView::visibleRolesSizes(const KItemRangeList& itemRanges) const { QElapsedTimer timer; timer.start(); QHash sizes; - const int itemCount = model()->count(); - for (int i = 0; i < itemCount; ++i) { - foreach (const QByteArray& visibleRole, visibleRoles()) { - QSizeF maxSize = sizes.value(visibleRole, QSizeF(0, 0)); - const QSizeF itemSize = visibleRoleSizeHint(i, visibleRole); - maxSize = maxSize.expandedTo(itemSize); - sizes.insert(visibleRole, maxSize); - } + int calculatedItemCount = 0; + bool maxTimeExceeded = false; + foreach (const KItemRange& itemRange, itemRanges) { + const int startIndex = itemRange.index; + const int endIndex = startIndex + itemRange.count - 1; + + for (int i = startIndex; i <= endIndex; ++i) { + foreach (const QByteArray& visibleRole, visibleRoles()) { + QSizeF maxSize = sizes.value(visibleRole, QSizeF(0, 0)); + const QSizeF itemSize = visibleRoleSizeHint(i, visibleRole); + maxSize = maxSize.expandedTo(itemSize); + sizes.insert(visibleRole, maxSize); + } - if (i > 100 && timer.elapsed() > 200) { - // When having several thousands of items calculating the sizes can get - // very expensive. We accept a possibly too small role-size in favour - // of having no blocking user interface. - #ifdef KFILEITEMLISTVIEW_DEBUG - kDebug() << "Timer exceeded, stopped after" << i << "items"; - #endif + if (calculatedItemCount > 100 && timer.elapsed() > 200) { + // When having several thousands of items calculating the sizes can get + // very expensive. We accept a possibly too small role-size in favour + // of having no blocking user interface. + #ifdef KFILEITEMLISTVIEW_DEBUG + kDebug() << "Timer exceeded, stopped after" << calculatedItemCount << "items"; + #endif + maxTimeExceeded = true; + break; + } + } + if (maxTimeExceeded) { break; } + ++calculatedItemCount; } // Stretch the width of the first role so that the full visible view-width @@ -213,7 +224,11 @@ QHash KFileItemListView::visibleRolesSizes() const } #ifdef KFILEITEMLISTVIEW_DEBUG - kDebug() << "[TIME] Calculated dynamic item size for " << itemCount << "items:" << timer.elapsed(); + int rangesItemCount = 0; + foreach (const KItemRange& itemRange, itemRanges) { + rangesItemCount += itemRange.count; + } + kDebug() << "[TIME] Calculated dynamic item size for " << rangesItemCount << "items:" << timer.elapsed(); #endif return sizes; } diff --git a/src/kitemviews/kfileitemlistview.h b/src/kitemviews/kfileitemlistview.h index 696322f8f..125c86142 100644 --- a/src/kitemviews/kfileitemlistview.h +++ b/src/kitemviews/kfileitemlistview.h @@ -61,7 +61,7 @@ public: virtual QSizeF itemSizeHint(int index) const; /** @reimp */ - virtual QHash visibleRolesSizes() const; + virtual QHash visibleRolesSizes(const KItemRangeList& itemRanges) const; /** @reimp */ virtual QPixmap createDragPixmap(const QSet& indexes) const; diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index 6d96c0999..1224ff6bd 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -404,8 +404,9 @@ QSizeF KItemListView::itemSizeHint(int index) const return itemSize(); } -QHash KItemListView::visibleRolesSizes() const +QHash KItemListView::visibleRolesSizes(const KItemRangeList& itemRanges) const { + Q_UNUSED(itemRanges); return QHash(); } @@ -604,7 +605,7 @@ void KItemListView::resizeEvent(QGraphicsSceneResizeEvent* event) void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges) { - updateVisibleRoleSizes(); + updateVisibleRoleSizes(itemRanges); const bool hasMultipleRanges = (itemRanges.count() > 1); if (hasMultipleRanges) { @@ -761,7 +762,7 @@ void KItemListView::slotItemsChanged(const KItemRangeList& itemRanges, { const bool updateSizeHints = itemSizeHintUpdateRequired(roles); if (updateSizeHints) { - updateVisibleRoleSizes(); + updateVisibleRoleSizes(itemRanges); } foreach (const KItemRange& itemRange, itemRanges) { @@ -1381,13 +1382,48 @@ QHash KItemListView::headerRolesWidths() const return rolesWidths; } -void KItemListView::updateVisibleRoleSizes() +void KItemListView::updateVisibleRoleSizes(const KItemRangeList& itemRanges) { if (!m_itemSize.isEmpty() || m_useHeaderWidths) { return; } - m_visibleRolesSizes = visibleRolesSizes(); + const int itemCount = m_model->count(); + int rangesItemCount = 0; + foreach (const KItemRange& range, itemRanges) { + rangesItemCount += range.count; + } + + if (itemCount == rangesItemCount) { + // The sizes of all roles need to be determined + m_visibleRolesSizes = visibleRolesSizes(itemRanges); + } else { + // Only a sub range of the roles need to be determined. + // The chances are good that the sizes of the sub ranges + // already fit into the available sizes and hence no + // expensive update might be required. + bool updateRequired = false; + + const QHash updatedSizes = visibleRolesSizes(itemRanges); + QHashIterator it(updatedSizes); + while (it.hasNext()) { + it.next(); + const QByteArray& role = it.key(); + const QSizeF& updatedSize = it.value(); + const QSizeF currentSize = m_visibleRolesSizes.value(role); + if (updatedSize.width() > currentSize.width() || updatedSize.height() > currentSize.height()) { + m_visibleRolesSizes.insert(role, updatedSize); + updateRequired = true; + } + } + + if (!updateRequired) { + // All the updated sizes are smaller than the current sizes and no change + // of the roles-widths is required + return; + } + } + if (m_header) { m_header->setVisibleRolesWidths(headerRolesWidths()); } @@ -1421,6 +1457,11 @@ void KItemListView::updateVisibleRoleSizes() } } +void KItemListView::updateVisibleRoleSizes() +{ + updateVisibleRoleSizes(KItemRangeList() << KItemRange(0, m_model->count())); +} + int KItemListView::calculateAutoScrollingIncrement(int pos, int range, int oldInc) { int inc = 0; diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index d6b0d5a77..091d2c36b 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -160,11 +160,12 @@ public: virtual QSizeF itemSizeHint(int index) const; /** + * @param itemRanges Items that must be checked for getting the visible roles sizes. * @return The size of each visible role in case if KItemListView::itemSize() * is empty. This allows to have dynamic but equal role sizes between * all items. Per default an empty hash is returned. */ - virtual QHash visibleRolesSizes() const; + virtual QHash visibleRolesSizes(const KItemRangeList& itemRanges) const; /** * @return The bounding rectangle of the item relative to the top/left of @@ -340,6 +341,11 @@ private: * if the m_itemRect is empty and no custom header-widths are used * (see m_useHeaderWidths). */ + void updateVisibleRoleSizes(const KItemRangeList& itemRanges); + + /** + * Convenience method for updateVisibleRoleSizes(KItemRangeList() << KItemRange(0, m_model->count()). + */ void updateVisibleRoleSizes(); /** -- 2.47.3