X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/fa4680cb38028aceb68d41e1937d27c71d1f121b..c92c5cada0bb687d29f4af1eb1230f28cc2bdf6c:/src/revisioncontrolobserver.cpp diff --git a/src/revisioncontrolobserver.cpp b/src/revisioncontrolobserver.cpp index 99fd61b67..246450fe7 100644 --- a/src/revisioncontrolobserver.cpp +++ b/src/revisioncontrolobserver.cpp @@ -28,13 +28,72 @@ #include #include +/** + * 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 UpdateItemStatesThread : public QThread +{ +public: + UpdateItemStatesThread(QObject* parent); + void setData(RevisionControlPlugin* plugin, + const QList& itemStates); + QList itemStates() const; + +protected: + virtual void run(); + +private: + RevisionControlPlugin* m_plugin; + QList m_itemStates; +}; + +UpdateItemStatesThread::UpdateItemStatesThread(QObject* parent) : + QThread(parent) +{ +} + +void UpdateItemStatesThread::setData(RevisionControlPlugin* plugin, + const QList& 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 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 +160,65 @@ void RevisionControlObserver::verifyDirectory() } } +void RevisionControlObserver::applyUpdatedItemStates() +{ + // QAbstractItemModel::setData() triggers a bottleneck in combination with QListView + // (a detailed description of the root cause is given in the class KFilePreviewGenerator + // from kdelibs). To bypass this bottleneck, the signals of the model are temporary blocked. + // This works as the update of the data does not require a relayout of the views used in Dolphin. + const bool signalsBlocked = m_dolphinModel->signalsBlocked(); + m_dolphinModel->blockSignals(true); + + const QList itemStates = m_updateItemStatesThread->itemStates(); + foreach (const ItemState& itemState, itemStates) { + m_dolphinModel->setData(itemState.index, + QVariant(static_cast(itemState.revision)), + Qt::DecorationRole); + } + + m_dolphinModel->blockSignals(signalsBlocked); + m_view->viewport()->repaint(); + + 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.name()); - m_dolphinModel->setData(index, QVariant(static_cast(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 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"