Simplify handling of preview jobs

This patch changes two things about the way we handle the preview jobs:

(a) Rather than passing a KFileItemList to startPreviewJob(),
    remembering the leftovers in the member variable
    m_pendingPreviewItems and then starting a new preview job for
    these, we append items that need a preview to this member, and let
    startPreviewJob() take its input from there. This simplifies the
    code greatly.

(b) To prevent that we start preview jobs with just one item and also
    that the GUI is frozen too long by startPreviewJob(), we take the
    following approach:

    * If the mime type of the first pending item is known, the function
      has probably been called by startUpdating(), which has determined
      mime types for the visible items already. startUpdating() has
      also blocked the GUI, so we just take all items at the beginning
      of the list with known mime type, and do not do any expensive
      mime type determination in startPreviewJob().

    * If the mime type of the first pending item is unknown, the
      function has probably been called by slotPreviewJobFinished(). In
      that case, we can afford to block the GUI for a short while, so
      we determine mime types for 200 ms.

REVIEW: 111008
This commit is contained in:
Frank Reininghaus 2013-06-20 18:10:07 +02:00
parent fda88516e9
commit 4b8c4124cb
2 changed files with 36 additions and 63 deletions

View file

@ -622,7 +622,7 @@ void KFileItemModelRolesUpdater::slotPreviewJobFinished()
m_state = Idle; m_state = Idle;
if (!m_pendingPreviewItems.isEmpty()) { if (!m_pendingPreviewItems.isEmpty()) {
startPreviewJob(m_pendingPreviewItems); startPreviewJob();
} else { } else {
if (!m_changedItems.isEmpty()) { if (!m_changedItems.isEmpty()) {
updateChangedItems(); updateChangedItems();
@ -877,26 +877,17 @@ void KFileItemModelRolesUpdater::startUpdating()
QList<int> indexes = indexesToResolve(); QList<int> indexes = indexesToResolve();
if (m_previewShown) { if (m_previewShown) {
KFileItemList itemsToResolve; m_pendingPreviewItems.clear();
m_pendingPreviewItems.reserve(indexes.count());
foreach (int index, indexes) { foreach (int index, indexes) {
const KFileItem item = m_model->fileItem(index); const KFileItem item = m_model->fileItem(index);
if (!m_finishedItems.contains(item)) { if (!m_finishedItems.contains(item)) {
itemsToResolve.append(m_model->fileItem(index)); m_pendingPreviewItems.append(item);
// Remember the items which have no icon yet. A fast
// asynchronous resolving will be done to make sure
// that icons are loaded as quickly as possible, i.e.,
// before the previews arrive.
if (index < m_firstVisibleIndex || index >= firstIndexWithoutIcon) {
m_pendingIndexes.append(index);
}
} }
} }
startPreviewJob(itemsToResolve); startPreviewJob();
// Determine the icons asynchronously as fast as possible.
QTimer::singleShot(0, this, SLOT(resolveNextPendingRoles()));
} else { } else {
m_pendingIndexes = indexes; m_pendingIndexes = indexes;
// Trigger the asynchronous resolving of all roles. // Trigger the asynchronous resolving of all roles.
@ -905,11 +896,11 @@ void KFileItemModelRolesUpdater::startUpdating()
} }
} }
void KFileItemModelRolesUpdater::startPreviewJob(const KFileItemList items) void KFileItemModelRolesUpdater::startPreviewJob()
{ {
m_state = PreviewJobRunning; m_state = PreviewJobRunning;
if (items.isEmpty()) { if (m_pendingPreviewItems.isEmpty()) {
QTimer::singleShot(0, this, SLOT(slotPreviewJobFinished())); QTimer::singleShot(0, this, SLOT(slotPreviewJobFinished()));
return; return;
} }
@ -924,43 +915,30 @@ void KFileItemModelRolesUpdater::startPreviewJob(const KFileItemList items)
// KIO::filePreview() will request the MIME-type of all passed items, which (in the // KIO::filePreview() will request the MIME-type of all passed items, which (in the
// worst case) might block the application for several seconds. To prevent such // worst case) might block the application for several seconds. To prevent such
// a blocking, we only pass items with known mime type to the preview job // a blocking, we only pass items with known mime type to the preview job.
// (if the icon has already been determined for an item in startUpdating() const int count = m_pendingPreviewItems.count();
// or resolveNextPendingRoles(), the type is known).
// This also prevents that repeated expensive mime type determinations are
// triggered here if a huge folder is loaded, and startUpdating() is called
// repeatedly.
//
// Note that we always pass at least one item to the preview job to prevent
// that we get an endless startPreviewJob()/slotPreviewJobFinished() loop
// if there are no items with known mime types yet for some reason.
const int count = items.count();
int previewJobItemCount = 1;
// TODO: This will start a job with one item only if this function is
// called from slotPreviewJobFinished(), and resolveNextPendingRoles()
// has not reached the items yet. This can happen if the previous preview
// job has finished very fast because generating previews failed for all
// items.
//
// Idea to improve this: if the mime type of the first item is unknown,
// determine mime types synchronously for a while.
while (previewJobItemCount < qMin(count, m_maximumVisibleItems) &&
items.at(previewJobItemCount).isMimeTypeKnown()) {
++previewJobItemCount;
}
KFileItemList itemSubSet; KFileItemList itemSubSet;
itemSubSet.reserve(previewJobItemCount); itemSubSet.reserve(count);
m_pendingPreviewItems.clear();
m_pendingPreviewItems.reserve(count - previewJobItemCount);
for (int i = 0; i < previewJobItemCount; ++i) { if (m_pendingPreviewItems.first().isMimeTypeKnown()) {
itemSubSet.append(items.at(i)); // Some mime types are known already, probably because they were
} // determined when loading the icons for the visible items. Start
// a preview job for all items at the beginning of the list which
// have a known mime type.
do {
itemSubSet.append(m_pendingPreviewItems.takeFirst());
} while (!m_pendingPreviewItems.isEmpty() && m_pendingPreviewItems.first().isMimeTypeKnown());
} else {
// Determine mime types for MaxBlockTimeout ms, and start a preview
// job for the corresponding items.
QElapsedTimer timer;
timer.start();
for (int i = previewJobItemCount; i < count; ++i) { do {
m_pendingPreviewItems.append(items.at(i)); const KFileItem item = m_pendingPreviewItems.takeFirst();
item.determineMimeType();
itemSubSet.append(item);
} while (!m_pendingPreviewItems.isEmpty() && timer.elapsed() < MaxBlockTimeout);
} }
KIO::PreviewJob* job = new KIO::PreviewJob(itemSubSet, cacheSize, &m_enabledPlugins); KIO::PreviewJob* job = new KIO::PreviewJob(itemSubSet, cacheSize, &m_enabledPlugins);
@ -1027,21 +1005,16 @@ void KFileItemModelRolesUpdater::updateChangedItems()
std::sort(visibleChangedIndexes.begin(), visibleChangedIndexes.end()); std::sort(visibleChangedIndexes.begin(), visibleChangedIndexes.end());
if (m_previewShown) { if (m_previewShown) {
KFileItemList visibleChangedItems;
KFileItemList invisibleChangedItems;
foreach (int index, visibleChangedIndexes) { foreach (int index, visibleChangedIndexes) {
visibleChangedItems.append(m_model->fileItem(index)); m_pendingPreviewItems.append(m_model->fileItem(index));
} }
foreach (int index, invisibleChangedIndexes) { foreach (int index, invisibleChangedIndexes) {
invisibleChangedItems.append(m_model->fileItem(index)); m_pendingPreviewItems.append(m_model->fileItem(index));
} }
if (m_previewJob) { if (!m_previewJob) {
m_pendingPreviewItems += visibleChangedItems + invisibleChangedItems; startPreviewJob();
} else {
startPreviewJob(visibleChangedItems + invisibleChangedItems);
} }
} else { } else {
const bool resolvingInProgress = !m_pendingIndexes.isEmpty(); const bool resolvingInProgress = !m_pendingIndexes.isEmpty();

View file

@ -224,13 +224,13 @@ private:
void startUpdating(); void startUpdating();
/** /**
* Creates previews for the items starting from the first item of the * Creates previews for the items starting from the first item in
* given list. * m_pendingPreviewItems.
* @see slotGotPreview() * @see slotGotPreview()
* @see slotPreviewFailed() * @see slotPreviewFailed()
* @see slotPreviewJobFinished() * @see slotPreviewJobFinished()
*/ */
void startPreviewJob(const KFileItemList items); void startPreviewJob();
/** /**
* Ensures that icons, previews, and other roles are determined for any * Ensures that icons, previews, and other roles are determined for any