]> cloud.milkyroute.net Git - dolphin.git/commitdiff
The performance of updating the revision state of items depends on the used plugin...
authorPeter Penz <peter.penz19@gmail.com>
Fri, 17 Jul 2009 19:26:46 +0000 (19:26 +0000)
committerPeter Penz <peter.penz19@gmail.com>
Fri, 17 Jul 2009 19:26:46 +0000 (19:26 +0000)
Still open issue: Applying the revision control property to the model is a bottleneck in QListView (a detailed description of the reason is in kdelibs/kfile/kfilepreviewgenerator.cpp, class LayoutBlocker). But the approach used in KFilePreviewGenerator destroys the textlayout in this case and is temporary disabled until I could track down the reason.

svn path=/trunk/KDE/kdebase/apps/; revision=998492

src/revisioncontrolobserver.cpp
src/revisioncontrolobserver.h

index 9b8cb25838061755b0f05a00d091020a8458e9bc..9d11154e022026cbd4b9a42a14a7a50fb9f57686 100644 (file)
 
 #include <QAbstractProxyModel>
 #include <QAbstractItemView>
+#include <QListView>
 #include <QTimer>
 
+/**
+ * The performance of updating the revision state of items depends
+ * on the used plugin. To prevent that Dolphin gets blocked by a
+ * slow plugin, the updating is delegated to a thread.
+ */
+class LIBDOLPHINPRIVATE_EXPORT UpdateItemStatesThread : public QThread
+{
+public:
+    UpdateItemStatesThread(QObject* parent);
+    void setData(RevisionControlPlugin* plugin,
+                 const QList<RevisionControlObserver::ItemState>& itemStates);
+    QList<RevisionControlObserver::ItemState> itemStates() const;
+    
+protected:
+    virtual void run();
+    
+private:
+    RevisionControlPlugin* m_plugin;
+    QList<RevisionControlObserver::ItemState> m_itemStates;
+};
+
+UpdateItemStatesThread::UpdateItemStatesThread(QObject* parent) :
+    QThread(parent)
+{
+}
+
+void UpdateItemStatesThread::setData(RevisionControlPlugin* plugin,
+                                     const QList<RevisionControlObserver::ItemState>& itemStates)
+{
+    m_plugin = plugin;
+    m_itemStates = itemStates;
+}
+
+void UpdateItemStatesThread::run()
+{
+    Q_ASSERT(m_itemStates.count() > 0);
+    Q_ASSERT(m_plugin != 0);
+    
+    // it is assumed that all items have the same parent directory
+    const QString directory = m_itemStates.first().item.url().directory(KUrl::AppendTrailingSlash);
+    
+    if (m_plugin->beginRetrieval(directory)) {
+        const int count = m_itemStates.count();
+        for (int i = 0; i < count; ++i) {
+            m_itemStates[i].revision = m_plugin->revisionState(m_itemStates[i].item);
+        }
+        m_plugin->endRetrieval();
+    }
+}
+
+QList<RevisionControlObserver::ItemState> UpdateItemStatesThread::itemStates() const
+{
+    return m_itemStates;
+}
+
+// ---
+
 RevisionControlObserver::RevisionControlObserver(QAbstractItemView* view) :
     QObject(view),
+    m_pendingItemStatesUpdate(false),
     m_view(view),
     m_dirLister(0),
     m_dolphinModel(0),
     m_dirVerificationTimer(0),
-    m_plugin(0)
+    m_plugin(0),
+    m_updateItemStatesThread(0)
 {
     Q_ASSERT(view != 0);
 
@@ -101,24 +161,70 @@ void RevisionControlObserver::verifyDirectory()
     }
 }
 
+void RevisionControlObserver::applyUpdatedItemStates()
+{
+    // Updating items with non-uniform item sizes is a serious bottleneck
+    // in QListView. Temporary disable the non-uniform item sizes.
+    QListView* listView = qobject_cast<QListView*>(m_view);
+    bool uniformSizes = true;
+    if (listView != 0) {
+        uniformSizes = listView->uniformItemSizes();
+        //listView->setUniformItemSizes(true); TODO: does not work as well as in KFilePreviewGenerator
+    }
+
+    const QList<ItemState> itemStates = m_updateItemStatesThread->itemStates();
+    foreach (const ItemState& itemState, itemStates) {
+        m_dolphinModel->setData(itemState.index,
+                                QVariant(static_cast<int>(itemState.revision)),
+                                Qt::DecorationRole);
+    }
+
+    if (listView != 0) {
+        listView->setUniformItemSizes(uniformSizes);
+    }
+
+    m_view->viewport()->repaint(); // TODO: this should not be necessary, as DolphinModel::setData() calls dataChanged()
+    
+    if (m_pendingItemStatesUpdate) {
+        m_pendingItemStatesUpdate = false;
+        updateItemStates();
+    }
+}
+
 void RevisionControlObserver::updateItemStates()
 {
     Q_ASSERT(m_plugin != 0);
-    const KUrl directory = m_dirLister->url();
-    if (!m_plugin->beginRetrieval(directory.toLocalFile(KUrl::AddTrailingSlash))) {
+    if (m_updateItemStatesThread == 0) {
+        m_updateItemStatesThread = new UpdateItemStatesThread(this);
+        connect(m_updateItemStatesThread, SIGNAL(finished()),
+                this, SLOT(applyUpdatedItemStates()));
+    }
+    if (m_updateItemStatesThread->isRunning()) {
+        // An update is currently ongoing. Wait until the thread has finished
+        // the update (see applyUpdatedItemStates()).
+        m_pendingItemStatesUpdate = true;
         return;
     }
-
+    
     const int rowCount = m_dolphinModel->rowCount();
-    for (int row = 0; row < rowCount; ++row) {
-        const QModelIndex index = m_dolphinModel->index(row, DolphinModel::Revision);
-        const KFileItem item = m_dolphinModel->itemForIndex(index);
-        const RevisionControlPlugin::RevisionState revision = m_plugin->revisionState(item);
-        m_dolphinModel->setData(index, QVariant(static_cast<int>(revision)), Qt::DecorationRole);
+    if (rowCount > 0) {
+        // Build a list of all items in the current directory and delegate
+        // this list to the thread, which adjusts the revision states.
+        QList<ItemState> itemStates;
+        for (int row = 0; row < rowCount; ++row) {
+            const QModelIndex index = m_dolphinModel->index(row, DolphinModel::Revision);
+            
+            ItemState itemState;
+            itemState.index = index;
+            itemState.item = m_dolphinModel->itemForIndex(index);
+            itemState.revision = RevisionControlPlugin::LocalRevision;
+            
+            itemStates.append(itemState);
+        }
+        
+        m_updateItemStatesThread->setData(m_plugin, itemStates);
+        m_updateItemStatesThread->start(); // applyUpdatedItemStates() is called when finished
     }
-    m_view->viewport()->repaint(); // TODO: this should not be necessary, as DolphinModel::setData() calls dataChanged()
-
-    m_plugin->endRetrieval();
 }
 
 #include "revisioncontrolobserver.moc"
index 14ea0528eacd1fe9e4e7381ca41c1686894e2d34..c5cf9bb0dce1272336e3d6fbb0d868d9ff80ce55 100644 (file)
 
 #include <libdolphin_export.h>
 
+#include <kfileitem.h>
+#include <revisioncontrolplugin.h>
 #include <QObject>
+#include <QPersistentModelIndex>
 #include <QString>
 
 class DolphinModel;
 class KDirLister;
 class QAbstractItemView;
+class QThread;
 class QTimer;
-class RevisionControlPlugin;
+class UpdateItemStatesThread;
 
 /**
  * @brief Observes all revision control plugins.
@@ -50,16 +54,31 @@ public:
 private slots:
     void delayedDirectoryVerification();
     void verifyDirectory();
-
+    void applyUpdatedItemStates();
+    
 private:
     void updateItemStates();
 
 private:
+    struct ItemState
+    {
+        QPersistentModelIndex index;
+        KFileItem item;
+        RevisionControlPlugin::RevisionState revision;
+    };
+    
+    bool m_pendingItemStatesUpdate;
+    
     QAbstractItemView* m_view;
     KDirLister* m_dirLister;
     DolphinModel* m_dolphinModel;
+    
     QTimer* m_dirVerificationTimer;
+    
     RevisionControlPlugin* m_plugin;
+    UpdateItemStatesThread* m_updateItemStatesThread;
+
+    friend class UpdateItemStatesThread;
 };
 
 #endif // REVISIONCONTROLOBSERVER_H