mirror of
https://invent.kde.org/system/dolphin
synced 2024-11-05 18:47:12 +00:00
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.
This commit is contained in:
parent
3326757370
commit
43373b3a16
3 changed files with 82 additions and 112 deletions
|
@ -376,8 +376,6 @@ void KFileItemListView::onScrollOffsetChanged(qreal current, qreal previous)
|
|||
|
||||
void KFileItemListView::onVisibleRolesChanged(const QList<QByteArray>& current, const QList<QByteArray>& previous)
|
||||
{
|
||||
Q_UNUSED(current);
|
||||
Q_UNUSED(previous);
|
||||
applyRolesToModel();
|
||||
|
||||
if (m_itemLayout == DetailsLayout) {
|
||||
|
|
|
@ -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<QByteArray>)),
|
||||
this, SLOT(slotItemsChanged(KItemRangeList,QSet<QByteArray>)));
|
||||
|
||||
// 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<KFileItem> 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<KFileItem> 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)
|
||||
|
|
|
@ -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<KFileItem> m_pendingInvisibleItems;
|
||||
QList<KJob*> 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
|
||||
|
|
Loading…
Reference in a new issue