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.

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
This commit is contained in:
Peter Penz 2009-07-17 19:26:46 +00:00
parent 93ce7f40e2
commit a447eb391c
2 changed files with 139 additions and 14 deletions

View file

@ -26,15 +26,75 @@
#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"

View file

@ -22,14 +22,18 @@
#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