X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/980846ab36eef12c152aa913267145b8bab2f326..e6ea3ab4c41dcc115143a237aafd3a1152849433:/src/kitemviews/private/kdirectorycontentscounter.cpp diff --git a/src/kitemviews/private/kdirectorycontentscounter.cpp b/src/kitemviews/private/kdirectorycontentscounter.cpp index fd8479feb..a19bce8b3 100644 --- a/src/kitemviews/private/kdirectorycontentscounter.cpp +++ b/src/kitemviews/private/kdirectorycontentscounter.cpp @@ -19,93 +19,115 @@ ***************************************************************************/ #include "kdirectorycontentscounter.h" - -#include "kdirectorycontentscounterworker.h" -#include +#include "kitemviews/kfileitemmodel.h" #include + +#include +#include #include +namespace { + /// cache of directory counting result + static QHash> *s_cache; +} + KDirectoryContentsCounter::KDirectoryContentsCounter(KFileItemModel* model, QObject* parent) : QObject(parent), m_model(model), m_queue(), - m_workerThread(0), - m_worker(0), + m_worker(nullptr), m_workerIsBusy(false), - m_dirWatcher(0), + m_dirWatcher(nullptr), m_watchedDirs() { - connect(m_model, SIGNAL(itemsRemoved(KItemRangeList)), - this, SLOT(slotItemsRemoved())); + connect(m_model, &KFileItemModel::itemsRemoved, + this, &KDirectoryContentsCounter::slotItemsRemoved); + + if (!m_workerThread) { + m_workerThread = new QThread(); + m_workerThread->start(); + } + + if (s_cache == nullptr) { + s_cache = new QHash>(); + } - m_workerThread = new QThread(this); m_worker = new KDirectoryContentsCounterWorker(); m_worker->moveToThread(m_workerThread); - connect(this, SIGNAL(requestDirectoryContentsCount(QString,KDirectoryContentsCounterWorker::Options)), - m_worker, SLOT(countDirectoryContents(QString,KDirectoryContentsCounterWorker::Options))); - connect(m_worker, SIGNAL(result(QString,int)), - this, SLOT(slotResult(QString,int))); - - m_workerThread->start(); + connect(this, &KDirectoryContentsCounter::requestDirectoryContentsCount, + m_worker, &KDirectoryContentsCounterWorker::countDirectoryContents); + connect(m_worker, &KDirectoryContentsCounterWorker::result, + this, &KDirectoryContentsCounter::slotResult); m_dirWatcher = new KDirWatch(this); - connect(m_dirWatcher, SIGNAL(dirty(QString)), this, SLOT(slotDirWatchDirty(QString))); + connect(m_dirWatcher, &KDirWatch::dirty, this, &KDirectoryContentsCounter::slotDirWatchDirty); } KDirectoryContentsCounter::~KDirectoryContentsCounter() { - m_workerThread->quit(); - m_workerThread->wait(); - - delete m_worker; + if (m_workerThread->isRunning()) { + // The worker thread will continue running. It could even be running + // a method of m_worker at the moment, so we delete it using + // deleteLater() to prevent a crash. + m_worker->deleteLater(); + } else { + // There are no remaining workers -> stop the worker thread. + m_workerThread->quit(); + m_workerThread->wait(); + delete m_workerThread; + m_workerThread = nullptr; + + // The worker thread has finished running now, so it's safe to delete + // m_worker. deleteLater() would not work at all because the event loop + // which would deliver the event to m_worker is not running any more. + delete m_worker; + } } -void KDirectoryContentsCounter::addDirectory(const QString& path) +void KDirectoryContentsCounter::scanDirectory(const QString& path) { startWorker(path); } -int KDirectoryContentsCounter::countDirectoryContentsSynchronously(const QString& path) +void KDirectoryContentsCounter::slotResult(const QString& path, int count, long size) { - if (!m_dirWatcher->contains(path)) { - m_dirWatcher->addDir(path); - m_watchedDirs.insert(path); - } + m_workerIsBusy = false; - KDirectoryContentsCounterWorker::Options options; + const QFileInfo info = QFileInfo(path); + const QString resolvedPath = info.canonicalFilePath(); - if (m_model->showHiddenFiles()) { - options |= KDirectoryContentsCounterWorker::CountHiddenFiles; + if (!m_dirWatcher->contains(resolvedPath)) { + m_dirWatcher->addDir(resolvedPath); + m_watchedDirs.insert(resolvedPath); } - if (m_model->showDirectoriesOnly()) { - options |= KDirectoryContentsCounterWorker::CountDirectoriesOnly; + if (!m_queue.isEmpty()) { + startWorker(m_queue.dequeue()); } - return KDirectoryContentsCounterWorker::subItemsCount(path, options); -} - -void KDirectoryContentsCounter::slotResult(const QString& path, int count) -{ - m_workerIsBusy = false; - - if (!m_dirWatcher->contains(path)) { - m_dirWatcher->addDir(path); - m_watchedDirs.insert(path); + if (s_cache->contains(resolvedPath)) { + const auto pair = s_cache->value(resolvedPath); + if (pair.first == count && pair.second == size) { + // no change no need to send another result event + return; + } } - if (!m_queue.isEmpty()) { - startWorker(m_queue.dequeue()); + if (info.dir().path() == m_model->rootItem().url().path()) { + // update cache or overwrite value + // when path is a direct children of the current model root + s_cache->insert(resolvedPath, QPair(count, size)); } - emit result(path, count); + // sends the results + emit result(resolvedPath, count, size); } void KDirectoryContentsCounter::slotDirWatchDirty(const QString& path) { - const int index = m_model->index(KUrl(path)); + const int index = m_model->index(QUrl::fromLocalFile(path)); if (index >= 0) { if (!m_model->fileItem(index).isDir()) { // If INotify is used, KDirWatch issues the dirty() signal @@ -125,7 +147,7 @@ void KDirectoryContentsCounter::slotItemsRemoved() if (!m_watchedDirs.isEmpty()) { // Don't let KDirWatch watch for removed items if (allItemsRemoved) { - foreach (const QString& path, m_watchedDirs) { + for (const QString& path : qAsConst(m_watchedDirs)) { m_dirWatcher->removeDir(path); } m_watchedDirs.clear(); @@ -134,7 +156,7 @@ void KDirectoryContentsCounter::slotItemsRemoved() QMutableSetIterator it(m_watchedDirs); while (it.hasNext()) { const QString& path = it.next(); - if (m_model->index(KUrl(path)) < 0) { + if (m_model->index(QUrl::fromLocalFile(path)) < 0) { m_dirWatcher->removeDir(path); it.remove(); } @@ -145,6 +167,13 @@ void KDirectoryContentsCounter::slotItemsRemoved() void KDirectoryContentsCounter::startWorker(const QString& path) { + if (s_cache->contains(path)) { + // fast path when in cache + // will be updated later if result has changed + const auto pair = s_cache->value(path); + emit result(path, pair.first, pair.second); + } + if (m_workerIsBusy) { m_queue.enqueue(path); } else { @@ -162,3 +191,5 @@ void KDirectoryContentsCounter::startWorker(const QString& path) m_workerIsBusy = true; } } + +QThread* KDirectoryContentsCounter::m_workerThread = nullptr;