From: Peter Penz Date: Sun, 23 Mar 2008 01:56:18 +0000 (+0000) Subject: Performance boost for previews that are already available in the cache: apply the... X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/commitdiff_plain/8c6e717eadc966196f72b7552012c12f46c720ce?ds=inline Performance boost for previews that are already available in the cache: apply the previews in larger blocks instead of applying them immediately after getting the signal 'gotPreview' from the PreviewJob. Now the previews in Konqueror and Dolphin are as fast as in the good old KDE 3 days :-) svn path=/trunk/KDE/kdebase/apps/; revision=789009 --- diff --git a/src/iconmanager.cpp b/src/iconmanager.cpp index dcfa9befe..cde15b00b 100644 --- a/src/iconmanager.cpp +++ b/src/iconmanager.cpp @@ -38,10 +38,12 @@ IconManager::IconManager(QAbstractItemView* parent, DolphinSortFilterProxyModel* QObject(parent), m_showPreview(false), m_view(parent), + m_previewTimer(0), m_previewJobs(), m_dolphinModel(0), m_proxyModel(model), - m_cutItemsCache() + m_cutItemsCache(), + m_previews() { Q_ASSERT(m_view->iconSize().isValid()); // each view must provide its current icon size @@ -52,6 +54,9 @@ IconManager::IconManager(QAbstractItemView* parent, DolphinSortFilterProxyModel* QClipboard* clipboard = QApplication::clipboard(); connect(clipboard, SIGNAL(dataChanged()), this, SLOT(updateCutItems())); + + m_previewTimer = new QTimer(this); + connect(m_previewTimer, SIGNAL(timeout()), this, SLOT(dispatchPreviewQueue())); } IconManager::~IconManager() @@ -98,49 +103,12 @@ void IconManager::updateIcons(const KFileItemList& items) } } -void IconManager::replaceIcon(const KFileItem& item, const QPixmap& pixmap) +void IconManager::addToPreviewQueue(const KFileItem& item, const QPixmap& pixmap) { - Q_ASSERT(!item.isNull()); - if (!m_showPreview) { - // the preview has been canceled in the meantime - return; - } - - // check whether the item is part of the directory lister (it is possible - // that a preview from an old directory lister is received) - KDirLister* dirLister = m_dolphinModel->dirLister(); - bool isOldPreview = true; - const KUrl::List dirs = dirLister->directories(); - const QString itemDir = item.url().directory(); - foreach (KUrl url, dirs) { - if (url.path() == itemDir) { - isOldPreview = false; - break; - } - } - if (isOldPreview) { - return; - } - - const QModelIndex idx = m_dolphinModel->indexForItem(item); - if (idx.isValid() && (idx.column() == 0)) { - QPixmap icon = pixmap; - - const QString mimeType = item.mimetype(); - const QString mimeTypeGroup = mimeType.left(mimeType.indexOf('/')); - if ((mimeTypeGroup != "image") || !applyImageFrame(icon)) { - limitToSize(icon, m_view->iconSize()); - } - - const QMimeData* mimeData = QApplication::clipboard()->mimeData(); - if (KonqMimeData::decodeIsCutSelection(mimeData) && isCutItem(item)) { - KIconEffect iconEffect; - icon = iconEffect.apply(icon, KIconLoader::Desktop, KIconLoader::DisabledState); - m_dolphinModel->setData(idx, QIcon(icon), Qt::DecorationRole); - } else { - m_dolphinModel->setData(idx, QIcon(icon), Qt::DecorationRole); - } - } + Preview preview; + preview.item = item; + preview.pixmap = pixmap; + m_previews.append(preview); } void IconManager::slotPreviewJobFinished(KJob* job) @@ -165,6 +133,37 @@ void IconManager::updateCutItems() applyCutItemEffect(); } +void IconManager::dispatchPreviewQueue() +{ + const int previewsCount = m_previews.count(); + if (previewsCount == 0) { + return; + } + + // Applying the previews to the model must be done step by step + // in larger blocks: Applying a preview immediately when getting the signal + // 'gotPreview()' from the PreviewJob is too expensive, as a relayout + // of the view would be triggered for each single preview. + + int dispatchCount = 30; + if (dispatchCount > previewsCount) { + dispatchCount = previewsCount; + } + + for (int i = 0; i < dispatchCount; ++i) { + const Preview& preview = m_previews.first(); + replaceIcon(preview.item, preview.pixmap); + m_previews.pop_front(); + } + + if (m_previews.count() > 0) { + // there are still pending previews; if no preview job is + // working, poll more aggressively: + const int timeout = (m_previewJobs.count() > 0) ? 200 : 10; + m_previewTimer->start(timeout); + } +} + void IconManager::generatePreviews(const KFileItemList &items) { Q_ASSERT(m_showPreview); @@ -187,11 +186,57 @@ void IconManager::generatePreviews(const KFileItemList &items) const QSize size = m_view->iconSize(); KIO::PreviewJob* job = KIO::filePreview(orderedItems, 128, 128); connect(job, SIGNAL(gotPreview(const KFileItem&, const QPixmap&)), - this, SLOT(replaceIcon(const KFileItem&, const QPixmap&))); + this, SLOT(addToPreviewQueue(const KFileItem&, const QPixmap&))); connect(job, SIGNAL(finished(KJob*)), this, SLOT(slotPreviewJobFinished(KJob*))); m_previewJobs.append(job); + m_previewTimer->start(200); +} + +void IconManager::replaceIcon(const KFileItem& item, const QPixmap& pixmap) +{ + Q_ASSERT(!item.isNull()); + if (!m_showPreview) { + // the preview has been canceled in the meantime + return; + } + + // check whether the item is part of the directory lister (it is possible + // that a preview from an old directory lister is received) + KDirLister* dirLister = m_dolphinModel->dirLister(); + bool isOldPreview = true; + const KUrl::List dirs = dirLister->directories(); + const QString itemDir = item.url().directory(); + foreach (KUrl url, dirs) { + if (url.path() == itemDir) { + isOldPreview = false; + break; + } + } + if (isOldPreview) { + return; + } + + const QModelIndex idx = m_dolphinModel->indexForItem(item); + if (idx.isValid() && (idx.column() == 0)) { + QPixmap icon = pixmap; + + const QString mimeType = item.mimetype(); + const QString mimeTypeGroup = mimeType.left(mimeType.indexOf('/')); + if ((mimeTypeGroup != "image") || !applyImageFrame(icon)) { + limitToSize(icon, m_view->iconSize()); + } + + const QMimeData* mimeData = QApplication::clipboard()->mimeData(); + if (KonqMimeData::decodeIsCutSelection(mimeData) && isCutItem(item)) { + KIconEffect iconEffect; + icon = iconEffect.apply(icon, KIconLoader::Desktop, KIconLoader::DisabledState); + m_dolphinModel->setData(idx, QIcon(icon), Qt::DecorationRole); + } else { + m_dolphinModel->setData(idx, QIcon(icon), Qt::DecorationRole); + } + } } bool IconManager::isCutItem(const KFileItem& item) const diff --git a/src/iconmanager.h b/src/iconmanager.h index 888fb42ee..ed74946e6 100644 --- a/src/iconmanager.h +++ b/src/iconmanager.h @@ -59,10 +59,11 @@ private slots: void updateIcons(const KFileItemList& items); /** - * Replaces the icon of the item \a item by the preview pixmap - * \a pixmap. + * Adds the preview \a pixmap for the item \a item to the preview + * queue and starts a timer which will dispatch the preview queue + * later. */ - void replaceIcon(const KFileItem& item, const QPixmap& pixmap); + void addToPreviewQueue(const KFileItem& item, const QPixmap& pixmap); /** * Is invoked when the preview job has been finished and @@ -73,9 +74,21 @@ private slots: /** Synchronizes the item icon with the clipboard of cut items. */ void updateCutItems(); + /** + * Dispatches the preview queue m_previews block by block within + * time slices. + */ + void dispatchPreviewQueue(); + private: void generatePreviews(const KFileItemList &items); + /** + * Replaces the icon of the item \a item by the preview pixmap + * \a pixmap. + */ + void replaceIcon(const KFileItem& item, const QPixmap& pixmap); + /** * Returns true, if the item \a item has been cut into * the clipboard. @@ -112,14 +125,25 @@ private: QPixmap pixmap; }; + /** + * Remembers the received preview pixmap for an item. + */ + struct Preview + { + KFileItem item; + QPixmap pixmap; + }; + bool m_showPreview; QAbstractItemView* m_view; + QTimer* m_previewTimer; QList m_previewJobs; DolphinModel* m_dolphinModel; DolphinSortFilterProxyModel* m_proxyModel; QList m_cutItemsCache; + QList m_previews; }; inline bool IconManager::showPreview() const