From: Peter Penz Date: Wed, 1 Feb 2012 19:40:57 +0000 (+0100) Subject: KFileItemModelRolesUpdater: Optimize updates X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/commitdiff_plain/43373b3a1650a5834f3d030b61d80b0a4e858588?ds=sidebyside KFileItemModelRolesUpdater: Optimize updates The asynchronous resolving to bypass performance bottlenecks is not necessary anymore as multiple ranges can be inserted in one step now. This solves the issue that e.g. opening a tree resulted in temporary unknown icons for a short period of time. --- diff --git a/src/kitemviews/kfileitemlistview.cpp b/src/kitemviews/kfileitemlistview.cpp index 86db28d3d..4762e8089 100644 --- a/src/kitemviews/kfileitemlistview.cpp +++ b/src/kitemviews/kfileitemlistview.cpp @@ -376,8 +376,6 @@ void KFileItemListView::onScrollOffsetChanged(qreal current, qreal previous) void KFileItemListView::onVisibleRolesChanged(const QList& current, const QList& previous) { - Q_UNUSED(current); - Q_UNUSED(previous); applyRolesToModel(); if (m_itemLayout == DetailsLayout) { diff --git a/src/kitemviews/kfileitemmodelrolesupdater.cpp b/src/kitemviews/kfileitemmodelrolesupdater.cpp index a974094d5..0c204e474 100644 --- a/src/kitemviews/kfileitemmodelrolesupdater.cpp +++ b/src/kitemviews/kfileitemmodelrolesupdater.cpp @@ -72,7 +72,6 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO m_pendingVisibleItems(), m_pendingInvisibleItems(), m_previewJobs(), - m_resolvePendingRolesTimer(0), m_changedItemsTimer(0), m_changedItems() { @@ -91,13 +90,6 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), this, SLOT(slotItemsChanged(KItemRangeList,QSet))); - // A timer with a minimal timeout is used to merge several triggerPendingRolesResolving() calls - // to only one call of resolvePendingRoles(). - m_resolvePendingRolesTimer = new QTimer(this); - m_resolvePendingRolesTimer->setInterval(1); - m_resolvePendingRolesTimer->setSingleShot(true); - connect(m_resolvePendingRolesTimer, SIGNAL(timeout()), this, SLOT(resolvePendingRoles())); - // Use a timer to prevent that each call of slotItemsChanged() results in a synchronous // resolving of the roles. Postpone the resolving until no update has been done for 2 seconds. m_changedItemsTimer = new QTimer(this); @@ -379,84 +371,6 @@ void KFileItemModelRolesUpdater::slotPreviewJobFinished(KJob* job) startPreviewJob(visibleItems + m_pendingInvisibleItems.toList()); } -void KFileItemModelRolesUpdater::resolvePendingRoles() -{ - int resolvedCount = 0; - - const bool hasSlowRoles = m_previewShown - || m_roles.contains("size") - || m_roles.contains("type") - || m_roles.contains("isExpandable"); - const ResolveHint resolveHint = hasSlowRoles ? ResolveFast : ResolveAll; - - // Resolving the MIME type can be expensive. Assure that not more than MaxBlockTimeout ms are - // spend for resolving them synchronously. Usually this is more than enough to determine - // all visible items, but there are corner cases where this limit gets easily exceeded. - QElapsedTimer timer; - timer.start(); - - // Resolve the MIME type of all visible items - QSetIterator visibleIt(m_pendingVisibleItems); - while (visibleIt.hasNext()) { - const KFileItem item = visibleIt.next(); - applyResolvedRoles(item, resolveHint); - if (!hasSlowRoles) { - Q_ASSERT(!m_pendingInvisibleItems.contains(item)); - // All roles have been resolved already by applyResolvedRoles() - m_pendingVisibleItems.remove(item); - } - ++resolvedCount; - - if (timer.elapsed() > MaxBlockTimeout) { - break; - } - } - - // Resolve the MIME type of the invisible items at least until the timeout - // has been exceeded or the maximum number of items has been reached - KFileItemList invisibleItems; - if (m_lastVisibleIndex >= 0) { - // The visible range is valid, don't care about the order how the MIME - // type of invisible items get resolved - invisibleItems = m_pendingInvisibleItems.toList(); - } else { - // The visible range is temporary invalid (e.g. happens when loading - // a directory) so take care to sort the currently invisible items where - // a part will get visible later - invisibleItems = sortedItems(m_pendingInvisibleItems); - } - - int index = 0; - while (resolvedCount < MaxResolveItemsCount && index < invisibleItems.count() && timer.elapsed() <= MaxBlockTimeout) { - const KFileItem item = invisibleItems.at(index); - applyResolvedRoles(item, resolveHint); - - if (!hasSlowRoles) { - // All roles have been resolved already by applyResolvedRoles() - m_pendingInvisibleItems.remove(item); - } - ++index; - ++resolvedCount; - } - - if (m_previewShown) { - KFileItemList items = sortedItems(m_pendingVisibleItems); - items += invisibleItems; - startPreviewJob(items); - } else { - QTimer::singleShot(0, this, SLOT(resolveNextPendingRoles())); - } - -#ifdef KFILEITEMMODELROLESUPDATER_DEBUG - if (timer.elapsed() > MaxBlockTimeout) { - kDebug() << "Maximum time of" << MaxBlockTimeout - << "ms exceeded, skipping items... Remaining visible:" << m_pendingVisibleItems.count() - << "invisible:" << m_pendingInvisibleItems.count(); - } - kDebug() << "[TIME] Resolved pending roles:" << timer.elapsed(); -#endif -} - void KFileItemModelRolesUpdater::resolveNextPendingRoles() { if (m_paused) { @@ -556,7 +470,7 @@ void KFileItemModelRolesUpdater::startUpdating(const KItemRangeList& itemRanges) } } - triggerPendingRolesResolving(rangesCount); + resolvePendingRoles(); } void KFileItemModelRolesUpdater::startPreviewJob(const KFileItemList& items) @@ -612,6 +526,84 @@ bool KFileItemModelRolesUpdater::hasPendingRoles() const return !m_pendingVisibleItems.isEmpty() || !m_pendingInvisibleItems.isEmpty(); } +void KFileItemModelRolesUpdater::resolvePendingRoles() +{ + int resolvedCount = 0; + + const bool hasSlowRoles = m_previewShown + || m_roles.contains("size") + || m_roles.contains("type") + || m_roles.contains("isExpandable"); + const ResolveHint resolveHint = hasSlowRoles ? ResolveFast : ResolveAll; + + // Resolving the MIME type can be expensive. Assure that not more than MaxBlockTimeout ms are + // spend for resolving them synchronously. Usually this is more than enough to determine + // all visible items, but there are corner cases where this limit gets easily exceeded. + QElapsedTimer timer; + timer.start(); + + // Resolve the MIME type of all visible items + QSetIterator visibleIt(m_pendingVisibleItems); + while (visibleIt.hasNext()) { + const KFileItem item = visibleIt.next(); + applyResolvedRoles(item, resolveHint); + if (!hasSlowRoles) { + Q_ASSERT(!m_pendingInvisibleItems.contains(item)); + // All roles have been resolved already by applyResolvedRoles() + m_pendingVisibleItems.remove(item); + } + ++resolvedCount; + + if (timer.elapsed() > MaxBlockTimeout) { + break; + } + } + + // Resolve the MIME type of the invisible items at least until the timeout + // has been exceeded or the maximum number of items has been reached + KFileItemList invisibleItems; + if (m_lastVisibleIndex >= 0) { + // The visible range is valid, don't care about the order how the MIME + // type of invisible items get resolved + invisibleItems = m_pendingInvisibleItems.toList(); + } else { + // The visible range is temporary invalid (e.g. happens when loading + // a directory) so take care to sort the currently invisible items where + // a part will get visible later + invisibleItems = sortedItems(m_pendingInvisibleItems); + } + + int index = 0; + while (resolvedCount < MaxResolveItemsCount && index < invisibleItems.count() && timer.elapsed() <= MaxBlockTimeout) { + const KFileItem item = invisibleItems.at(index); + applyResolvedRoles(item, resolveHint); + + if (!hasSlowRoles) { + // All roles have been resolved already by applyResolvedRoles() + m_pendingInvisibleItems.remove(item); + } + ++index; + ++resolvedCount; + } + + if (m_previewShown) { + KFileItemList items = sortedItems(m_pendingVisibleItems); + items += invisibleItems; + startPreviewJob(items); + } else { + QTimer::singleShot(0, this, SLOT(resolveNextPendingRoles())); + } + +#ifdef KFILEITEMMODELROLESUPDATER_DEBUG + if (timer.elapsed() > MaxBlockTimeout) { + kDebug() << "Maximum time of" << MaxBlockTimeout + << "ms exceeded, skipping items... Remaining visible:" << m_pendingVisibleItems.count() + << "invisible:" << m_pendingInvisibleItems.count(); + } + kDebug() << "[TIME] Resolved pending roles:" << timer.elapsed(); +#endif +} + void KFileItemModelRolesUpdater::resetPendingRoles() { m_pendingVisibleItems.clear(); @@ -623,21 +615,6 @@ void KFileItemModelRolesUpdater::resetPendingRoles() Q_ASSERT(m_previewJobs.isEmpty()); } -void KFileItemModelRolesUpdater::triggerPendingRolesResolving(int count) -{ - if (count == m_model->count()) { - // When initially loading a directory a synchronous resolving prevents a minor - // flickering when opening directories. This is also fine from a performance point - // of view as it is assured in resolvePendingRoles() to never block the event-loop - // for more than 200 ms. - resolvePendingRoles(); - } else { - // Items have been added. This can be done in several small steps within one loop - // because of the sorting and hence may not trigger any expensive operation. - m_resolvePendingRolesTimer->start(); - } -} - void KFileItemModelRolesUpdater::sortAndResolveAllRoles() { if (m_paused) { @@ -675,8 +652,7 @@ void KFileItemModelRolesUpdater::sortAndResolveAllRoles() } } - triggerPendingRolesResolving(m_pendingVisibleItems.count() + - m_pendingInvisibleItems.count()); + resolvePendingRoles(); } void KFileItemModelRolesUpdater::sortAndResolvePendingRoles() @@ -715,8 +691,7 @@ void KFileItemModelRolesUpdater::sortAndResolvePendingRoles() } } - triggerPendingRolesResolving(m_pendingVisibleItems.count() + - m_pendingInvisibleItems.count()); + resolvePendingRoles(); } bool KFileItemModelRolesUpdater::applyResolvedRoles(const KFileItem& item, ResolveHint hint) diff --git a/src/kitemviews/kfileitemmodelrolesupdater.h b/src/kitemviews/kfileitemmodelrolesupdater.h index b3945d14d..4db2dde97 100644 --- a/src/kitemviews/kfileitemmodelrolesupdater.h +++ b/src/kitemviews/kfileitemmodelrolesupdater.h @@ -123,7 +123,6 @@ private slots: */ void slotPreviewJobFinished(KJob* job); - void resolvePendingRoles(); void resolveNextPendingRoles(); /** @@ -150,8 +149,8 @@ private: void startPreviewJob(const KFileItemList& items); bool hasPendingRoles() const; + void resolvePendingRoles(); void resetPendingRoles(); - void triggerPendingRolesResolving(int count); void sortAndResolveAllRoles(); void sortAndResolvePendingRoles(); @@ -198,8 +197,6 @@ private: QSet m_pendingInvisibleItems; QList m_previewJobs; - QTimer* m_resolvePendingRolesTimer; - // When downloading or copying large files, the slot slotItemsChanged() // will be called periodically within a quite short delay. To prevent // a high CPU-load by generating e.g. previews for each notification, the update