Make sure that all visible items have an icon

We try to determine "final" icons, i.e., icons with known mime type,
for 200 ms. If this does not succeed, we at least load "fast" icons,
i.e., load the icons without determining the mime type.

REVIEW: 111009
This commit is contained in:
Frank Reininghaus 2013-06-20 19:13:35 +02:00
parent 4b8c4124cb
commit 015957c5a2
2 changed files with 76 additions and 87 deletions

View file

@ -88,7 +88,6 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO
m_resolvableRoles(),
m_enabledPlugins(),
m_pendingSortRoleItems(),
m_pendingSortRoleIndexes(),
m_pendingIndexes(),
m_pendingPreviewItems(),
m_previewJob(),
@ -261,8 +260,9 @@ void KFileItemModelRolesUpdater::setPaused(bool paused)
resolveNextSortRole();
} else {
m_state = Idle;
startUpdating();
}
startUpdating();
}
}
@ -345,17 +345,14 @@ void KFileItemModelRolesUpdater::slotItemsInserted(const KItemRangeList& itemRan
applySortProgressToModel();
// If there are still items whose sort role is unknown, return
// and handle them asynchronously.
if (!m_pendingSortRoleItems.isEmpty()) {
if (m_state != ResolvingSortRole) {
// Trigger the asynchronous determination of the sort role.
// If there are still items whose sort role is unknown, check if the
// asynchronous determination of the sort role is already in progress,
// and start it if that is not the case.
if (!m_pendingSortRoleItems.isEmpty() && m_state != ResolvingSortRole) {
killPreviewJob();
m_state = ResolvingSortRole;
resolveNextSortRole();
}
return;
}
}
startUpdating();
@ -419,7 +416,6 @@ void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRang
m_finishedItems.clear();
m_pendingSortRoleItems.clear();
m_pendingSortRoleIndexes.clear();
m_pendingIndexes.clear();
m_pendingPreviewItems.clear();
m_recentlyChangedItems.clear();
@ -449,9 +445,6 @@ void KFileItemModelRolesUpdater::slotItemsMoved(const KItemRange& itemRange, QLi
Q_UNUSED(itemRange);
Q_UNUSED(movedToIndexes);
// The indexes of the items with missing sort role are not valid any more.
m_pendingSortRoleIndexes.clear();
// The visible items might have changed.
startUpdating();
}
@ -492,7 +485,6 @@ void KFileItemModelRolesUpdater::slotSortRoleChanged(const QByteArray& current,
if (m_resolvableRoles.contains(current)) {
m_pendingSortRoleItems.clear();
m_pendingSortRoleIndexes.clear();
m_finishedItems.clear();
const int count = m_model->count();
@ -519,7 +511,6 @@ void KFileItemModelRolesUpdater::slotSortRoleChanged(const QByteArray& current,
} else {
m_state = Idle;
m_pendingSortRoleItems.clear();
m_pendingSortRoleIndexes.clear();
applySortProgressToModel();
}
}
@ -636,55 +627,20 @@ void KFileItemModelRolesUpdater::resolveNextSortRole()
return;
}
if (m_pendingSortRoleItems.count() != m_pendingSortRoleIndexes.count()) {
// The indexes with missing sort role have to be updated.
m_pendingSortRoleIndexes.clear();
foreach (const KFileItem& item, m_pendingSortRoleItems) {
QSet<KFileItem>::iterator it = m_pendingSortRoleItems.begin();
while (it != m_pendingSortRoleItems.end()) {
const KFileItem item = *it;
const int index = m_model->index(item);
if (index < 0) {
m_pendingSortRoleItems.remove(item);
} else {
m_pendingSortRoleIndexes.append(index);
}
}
std::sort(m_pendingSortRoleIndexes.begin(), m_pendingSortRoleIndexes.end());
}
// Try to update an item in the visible range.
QList<int>::iterator it = std::lower_bound(m_pendingSortRoleIndexes.begin(),
m_pendingSortRoleIndexes.end(),
m_firstVisibleIndex);
// It seems that there is no such item. Start with the first item in the list.
if (it == m_pendingSortRoleIndexes.end()) {
it = m_pendingSortRoleIndexes.begin();
}
while (it != m_pendingSortRoleIndexes.end()) {
// TODO: Note that removing an index from the list m_pendingSortRoleIndexes
// at a random position is O(N). We might need a better solution
// to make sure that this does not harm the performance if
// many items have to be sorted.
const int index = *it;
const KFileItem item = m_model->fileItem(index);
// Continue if the sort role has already been determined for the
// item, and the item has not been changed recently.
if (!m_changedItems.contains(item) && m_model->data(index).contains(m_model->sortRole())) {
m_pendingSortRoleItems.remove(item);
m_pendingSortRoleIndexes.erase(it);
// Check if we are at the end of the list (note that the list's end has changed).
if (it != m_pendingSortRoleIndexes.end()) {
++it;
}
it = m_pendingSortRoleItems.erase(it);
continue;
}
applySortRole(index);
m_pendingSortRoleItems.remove(item);
m_pendingSortRoleIndexes.erase(it);
m_pendingSortRoleItems.erase(it);
break;
}
@ -836,9 +792,7 @@ void KFileItemModelRolesUpdater::slotDirWatchDirty(const QString& path)
void KFileItemModelRolesUpdater::startUpdating()
{
// Updating the items in and near the visible area makes sense only
// if sorting is finished.
if (m_state == ResolvingSortRole || m_state == Paused) {
if (m_state == Paused) {
return;
}
@ -848,16 +802,6 @@ void KFileItemModelRolesUpdater::startUpdating()
return;
}
int lastVisibleIndex = m_lastVisibleIndex;
if (lastVisibleIndex <= 0) {
// Guess a reasonable value for the last visible index if the view
// has not told us about the real value yet.
lastVisibleIndex = qMin(m_firstVisibleIndex + m_maximumVisibleItems, m_model->count() - 1);
if (lastVisibleIndex <= 0) {
lastVisibleIndex = qMin(200, m_model->count() - 1);
}
}
// Terminate all updates that are currently active.
killPreviewJob();
m_pendingIndexes.clear();
@ -866,12 +810,13 @@ void KFileItemModelRolesUpdater::startUpdating()
timer.start();
// Determine the icons for the visible items synchronously.
int index;
for (index = m_firstVisibleIndex; index <= lastVisibleIndex && timer.elapsed() < MaxBlockTimeout; ++index) {
const KFileItem item = m_model->fileItem(index);
applyResolvedRoles(item, ResolveFast);
updateVisibleIcons();
// A detailed update of the items in and near the visible area
// only makes sense if sorting is finished.
if (m_state == ResolvingSortRole) {
return;
}
const int firstIndexWithoutIcon = index;
// Start the preview job or the asynchronous resolving of all roles.
QList<int> indexes = indexesToResolve();
@ -896,6 +841,51 @@ void KFileItemModelRolesUpdater::startUpdating()
}
}
void KFileItemModelRolesUpdater::updateVisibleIcons()
{
int lastVisibleIndex = m_lastVisibleIndex;
if (lastVisibleIndex <= 0) {
// Guess a reasonable value for the last visible index if the view
// has not told us about the real value yet.
lastVisibleIndex = qMin(m_firstVisibleIndex + m_maximumVisibleItems, m_model->count() - 1);
if (lastVisibleIndex <= 0) {
lastVisibleIndex = qMin(200, m_model->count() - 1);
}
}
QElapsedTimer timer;
timer.start();
// Try to determine the final icons for all visible items.
int index;
for (index = m_firstVisibleIndex; index <= lastVisibleIndex && timer.elapsed() < MaxBlockTimeout; ++index) {
const KFileItem item = m_model->fileItem(index);
applyResolvedRoles(item, ResolveFast);
}
if (index > lastVisibleIndex) {
return;
}
// If this didn't work before MaxBlockTimeout was reached, at least
// prevent that the user sees 'unknown' icons.
disconnect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
this, SLOT(slotItemsChanged(KItemRangeList,QSet<QByteArray>)));
while (index <= lastVisibleIndex) {
if (!m_model->data(index).contains("iconName")) {
const KFileItem item = m_model->fileItem(index);
QHash<QByteArray, QVariant> data;
data.insert("iconName", item.iconName());
m_model->setData(index, data);
}
++index;
}
connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
this, SLOT(slotItemsChanged(KItemRangeList,QSet<QByteArray>)));
}
void KFileItemModelRolesUpdater::startPreviewJob()
{
m_state = PreviewJobRunning;
@ -1032,11 +1022,6 @@ void KFileItemModelRolesUpdater::applySortRole(int index)
QHash<QByteArray, QVariant> data;
const KFileItem item = m_model->fileItem(index);
if (index >= m_firstVisibleIndex && index <= m_lastVisibleIndex) {
// Determine the icon.
applyResolvedRoles(item, ResolveFast);
}
if (m_model->sortRole() == "type") {
if (!item.isMimeTypeKnown()) {
item.determineMimeType();

View file

@ -223,6 +223,15 @@ private:
*/
void startUpdating();
/**
* Loads the icons for the visible items. After 200 ms, the function
* stops determining mime types and only loads preliminary icons.
* This is a compromise that prevents that
* (a) the GUI is blocked for more than 200 ms, and
* (b) "unknown" icons could be shown in the view.
*/
void updateVisibleIcons();
/**
* Creates previews for the items starting from the first item in
* m_pendingPreviewItems.
@ -311,11 +320,6 @@ private:
// Items for which the sort role still has to be determined.
QSet<KFileItem> m_pendingSortRoleItems;
// While the sort role is being resolved, we also keep the indexes
// in a sorted list. The reason is that this enables us to determine
// both the sort role and the icon for the visible items first.
QList<int> m_pendingSortRoleIndexes;
// Indexes of items which still have to be handled by
// resolveNextPendingRoles().
QList<int> m_pendingIndexes;