┌   ┐
54
└   ┘

summaryrefslogtreecommitdiff
path: root/src/kitemviews
diff options
context:
space:
mode:
authorMéven Car <[email protected]>2023-02-12 11:21:53 +0000
committerMéven Car <[email protected]>2023-02-12 11:21:53 +0000
commitba930ddb3635fe2d94d727e72aaf261513b28060 (patch)
tree9199f7944d1b02830eb05f15a58fe1b1be1edbce /src/kitemviews
parenta15def4e64dc08d508e7a511a20ad06e7e8a2e0c (diff)
Optimize Directory size counting
Two changes: * Prioritise size counting for visible path * stop the worker when switching dirs
Diffstat (limited to 'src/kitemviews')
-rw-r--r--src/kitemviews/kfileitemmodelrolesupdater.cpp40
-rw-r--r--src/kitemviews/kfileitemmodelrolesupdater.h4
-rw-r--r--src/kitemviews/private/kdirectorycontentscounter.cpp31
-rw-r--r--src/kitemviews/private/kdirectorycontentscounter.h14
-rw-r--r--src/kitemviews/private/kdirectorycontentscounterworker.cpp18
-rw-r--r--src/kitemviews/private/kdirectorycontentscounterworker.h11
6 files changed, 79 insertions, 39 deletions
diff --git a/src/kitemviews/kfileitemmodelrolesupdater.cpp b/src/kitemviews/kfileitemmodelrolesupdater.cpp
index 4af4f3024..4fd126619 100644
--- a/src/kitemviews/kfileitemmodelrolesupdater.cpp
+++ b/src/kitemviews/kfileitemmodelrolesupdater.cpp
@@ -422,6 +422,10 @@ void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList &itemRang
m_hoverSequenceLoadedItems.clear();
killPreviewJob();
+
+ if (m_scanDirectories) {
+ m_directoryContentsCounter->stopWorker();
+ }
} else {
// Only remove the items from m_finishedItems. They will be removed
// from the other sets later on.
@@ -537,7 +541,7 @@ void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem &item, const QPi
QPixmap scaledPixmap = transformPreviewPixmap(pixmap);
- QHash<QByteArray, QVariant> data = rolesData(item);
+ QHash<QByteArray, QVariant> data = rolesData(item, index);
const QStringList overlays = data["iconOverlays"].toStringList();
// Strangely KFileItem::overlays() returns empty string-values, so
@@ -1210,13 +1214,10 @@ void KFileItemModelRolesUpdater::applySortRole(int index)
data.insert("type", item.mimeComment());
} else if (m_model->sortRole() == "size" && item.isLocalFile() && !item.isSlow() && item.isDir()) {
- const QString path = item.localPath();
- if (m_scanDirectories) {
- m_directoryContentsCounter->scanDirectory(path);
- }
+ startDirectorySizeCounting(item, index);
} else {
// Probably the sort role is a baloo role - just determine all roles.
- data = rolesData(item);
+ data = rolesData(item, index);
}
disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged);
@@ -1252,7 +1253,7 @@ bool KFileItemModelRolesUpdater::applyResolvedRoles(int index, ResolveHint hint)
QHash<QByteArray, QVariant> data;
if (resolveAll) {
- data = rolesData(item);
+ data = rolesData(item, index);
}
if (!item.iconName().isEmpty()) {
@@ -1273,7 +1274,19 @@ bool KFileItemModelRolesUpdater::applyResolvedRoles(int index, ResolveHint hint)
return false;
}
-QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileItem &item)
+void KFileItemModelRolesUpdater::startDirectorySizeCounting(const KFileItem &item, int index)
+{
+ // Tell m_directoryContentsCounter that we want to count the items
+ // inside the directory. The result will be received in slotDirectoryContentsCountReceived.
+ if (m_scanDirectories && item.isLocalFile()) {
+ const QString path = item.localPath();
+ const auto priority = index >= m_firstVisibleIndex && index <= m_lastVisibleIndex ? KDirectoryContentsCounter::PathCountPriority::High
+ : KDirectoryContentsCounter::PathCountPriority::Normal;
+ m_directoryContentsCounter->scanDirectory(path, priority);
+ }
+}
+
+QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileItem &item, int index)
{
QHash<QByteArray, QVariant> data;
@@ -1281,16 +1294,7 @@ QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileIte
const bool getIsExpandableRole = m_roles.contains("isExpandable");
if ((getSizeRole || getIsExpandableRole) && !item.isSlow() && item.isDir()) {
- if (item.isLocalFile()) {
- // Tell m_directoryContentsCounter that we want to count the items
- // inside the directory. The result will be received in slotDirectoryContentsCountReceived.
- if (m_scanDirectories) {
- const QString path = item.localPath();
- m_directoryContentsCounter->scanDirectory(path);
- }
- } else if (getSizeRole) {
- data.insert("size", -1); // -1 indicates an unknown number of items
- }
+ startDirectorySizeCounting(item, index);
}
if (m_roles.contains("extension")) {
diff --git a/src/kitemviews/kfileitemmodelrolesupdater.h b/src/kitemviews/kfileitemmodelrolesupdater.h
index 90f29c5c0..be6f23193 100644
--- a/src/kitemviews/kfileitemmodelrolesupdater.h
+++ b/src/kitemviews/kfileitemmodelrolesupdater.h
@@ -319,7 +319,7 @@ private:
enum ResolveHint { ResolveFast, ResolveAll };
bool applyResolvedRoles(int index, ResolveHint hint);
- QHash<QByteArray, QVariant> rolesData(const KFileItem &item);
+ QHash<QByteArray, QVariant> rolesData(const KFileItem &item, int index);
/**
* Must be invoked if a property has been changed that affects
@@ -334,6 +334,8 @@ private:
void trimHoverSequenceLoadedItems();
private:
+ void startDirectorySizeCounting(const KFileItem &item, int index);
+
enum State { Idle, Paused, ResolvingSortRole, ResolvingAllRoles, PreviewJobRunning };
State m_state;
diff --git a/src/kitemviews/private/kdirectorycontentscounter.cpp b/src/kitemviews/private/kdirectorycontentscounter.cpp
index 039b79b6e..37e852ab9 100644
--- a/src/kitemviews/private/kdirectorycontentscounter.cpp
+++ b/src/kitemviews/private/kdirectorycontentscounter.cpp
@@ -44,6 +44,7 @@ KDirectoryContentsCounter::KDirectoryContentsCounter(KFileItemModel *model, QObj
m_worker->moveToThread(m_workerThread);
connect(this, &KDirectoryContentsCounter::requestDirectoryContentsCount, m_worker, &KDirectoryContentsCounterWorker::countDirectoryContents);
+ connect(this, &KDirectoryContentsCounter::stop, m_worker, &KDirectoryContentsCounterWorker::stop);
connect(m_worker, &KDirectoryContentsCounterWorker::result, this, &KDirectoryContentsCounter::slotResult);
m_dirWatcher = new KDirWatch(this);
@@ -71,11 +72,6 @@ KDirectoryContentsCounter::~KDirectoryContentsCounter()
}
}
-void KDirectoryContentsCounter::scanDirectory(const QString &path)
-{
- startWorker(path);
-}
-
void KDirectoryContentsCounter::slotResult(const QString &path, int count, long size)
{
m_workerIsBusy = false;
@@ -91,11 +87,11 @@ void KDirectoryContentsCounter::slotResult(const QString &path, int count, long
if (!m_priorityQueue.empty()) {
const QString firstPath = m_priorityQueue.front();
m_priorityQueue.pop_front();
- startWorker(firstPath);
+ scanDirectory(firstPath, PathCountPriority::High);
} else if (!m_queue.empty()) {
const QString firstPath = m_queue.front();
m_queue.pop_front();
- startWorker(firstPath);
+ scanDirectory(firstPath, PathCountPriority::Normal);
}
if (s_cache->contains(resolvedPath)) {
@@ -127,7 +123,7 @@ void KDirectoryContentsCounter::slotDirWatchDirty(const QString &path)
return;
}
- startWorker(path);
+ scanDirectory(path, PathCountPriority::High);
}
}
@@ -156,7 +152,7 @@ void KDirectoryContentsCounter::slotItemsRemoved()
}
}
-void KDirectoryContentsCounter::startWorker(const QString &path)
+void KDirectoryContentsCounter::scanDirectory(const QString &path, PathCountPriority priority)
{
const QString resolvedPath = QFileInfo(path).canonicalFilePath();
const bool alreadyInCache = s_cache->contains(resolvedPath);
@@ -168,10 +164,16 @@ void KDirectoryContentsCounter::startWorker(const QString &path)
}
if (m_workerIsBusy) {
+ // only enqueue path not yet in queue
if (std::find(m_queue.begin(), m_queue.end(), path) == m_queue.end()
&& std::find(m_priorityQueue.begin(), m_priorityQueue.end(), path) == m_priorityQueue.end()) {
- if (alreadyInCache) {
- m_queue.push_back(path);
+ if (priority == PathCountPriority::Normal) {
+ if (alreadyInCache) {
+ // if we already knew the dir size, it gets lower priority
+ m_queue.push_back(path);
+ } else {
+ m_queue.push_front(path);
+ }
} else {
// append to priority queue
m_priorityQueue.push_back(path);
@@ -193,4 +195,11 @@ void KDirectoryContentsCounter::startWorker(const QString &path)
}
}
+void KDirectoryContentsCounter::stopWorker()
+{
+ m_queue.clear();
+ m_priorityQueue.clear();
+ Q_EMIT stop();
+}
+
QThread *KDirectoryContentsCounter::m_workerThread = nullptr;
diff --git a/src/kitemviews/private/kdirectorycontentscounter.h b/src/kitemviews/private/kdirectorycontentscounter.h
index f74565b73..9a5e4a86b 100644
--- a/src/kitemviews/private/kdirectorycontentscounter.h
+++ b/src/kitemviews/private/kdirectorycontentscounter.h
@@ -21,6 +21,8 @@ class KDirectoryContentsCounter : public QObject
Q_OBJECT
public:
+ enum PathCountPriority { Normal, High };
+
explicit KDirectoryContentsCounter(KFileItemModel *model, QObject *parent = nullptr);
~KDirectoryContentsCounter() override;
@@ -35,7 +37,12 @@ public:
* Uses a cache internally to speed up first result,
* but emit again result when the cache was updated
*/
- void scanDirectory(const QString &path);
+ void scanDirectory(const QString &path, PathCountPriority priority);
+
+ /**
+ * Stops the work until new input is passed
+ */
+ void stopWorker();
Q_SIGNALS:
/**
@@ -46,15 +53,14 @@ Q_SIGNALS:
void requestDirectoryContentsCount(const QString &path, KDirectoryContentsCounterWorker::Options options);
+ void stop();
+
private Q_SLOTS:
void slotResult(const QString &path, int count, long size);
void slotDirWatchDirty(const QString &path);
void slotItemsRemoved();
private:
- void startWorker(const QString &path);
-
-private:
KFileItemModel *m_model;
// Used as FIFO queues.
diff --git a/src/kitemviews/private/kdirectorycontentscounterworker.cpp b/src/kitemviews/private/kdirectorycontentscounterworker.cpp
index e227c1bc6..2227ebbc2 100644
--- a/src/kitemviews/private/kdirectorycontentscounterworker.cpp
+++ b/src/kitemviews/private/kdirectorycontentscounterworker.cpp
@@ -25,7 +25,7 @@ KDirectoryContentsCounterWorker::KDirectoryContentsCounterWorker(QObject *parent
#ifndef Q_OS_WIN
KDirectoryContentsCounterWorker::CountResult
-walkDir(const QString &dirPath, const bool countHiddenFiles, const bool countDirectoriesOnly, const uint allowedRecursiveLevel)
+KDirectoryContentsCounterWorker::walkDir(const QString &dirPath, const bool countHiddenFiles, const bool countDirectoriesOnly, const uint allowedRecursiveLevel)
{
int count = -1;
long size = -1;
@@ -36,7 +36,7 @@ walkDir(const QString &dirPath, const bool countHiddenFiles, const bool countDir
QT_DIRENT *dirEntry;
QT_STATBUF buf;
- while ((dirEntry = QT_READDIR(dir))) {
+ while (!m_stopping && (dirEntry = QT_READDIR(dir))) {
if (dirEntry->d_name[0] == '.') {
if (dirEntry->d_name[1] == '\0' || !countHiddenFiles) {
// Skip "." or hidden files
@@ -64,7 +64,7 @@ walkDir(const QString &dirPath, const bool countHiddenFiles, const bool countDir
size += buf.st_size;
}
}
- if (dirEntry->d_type == DT_DIR) {
+ if (!m_stopping && dirEntry->d_type == DT_DIR) {
// recursion for dirs
auto subdirResult = walkDir(nameBuf, countHiddenFiles, countDirectoriesOnly, allowedRecursiveLevel - 1);
if (subdirResult.size > 0) {
@@ -106,8 +106,18 @@ KDirectoryContentsCounterWorker::CountResult KDirectoryContentsCounterWorker::su
#endif
}
+void KDirectoryContentsCounterWorker::stop()
+{
+ m_stopping = true;
+}
+
void KDirectoryContentsCounterWorker::countDirectoryContents(const QString &path, Options options)
{
+ m_stopping = false;
+
auto res = subItemsCount(path, options);
- Q_EMIT result(path, res.count, res.size);
+
+ if (!m_stopping) {
+ Q_EMIT result(path, res.count, res.size);
+ }
}
diff --git a/src/kitemviews/private/kdirectorycontentscounterworker.h b/src/kitemviews/private/kdirectorycontentscounterworker.h
index 6bbe099a5..5266960cd 100644
--- a/src/kitemviews/private/kdirectorycontentscounterworker.h
+++ b/src/kitemviews/private/kdirectorycontentscounterworker.h
@@ -36,7 +36,7 @@ public:
*
* @return The number of items.
*/
- static CountResult subItemsCount(const QString &path, Options options);
+ CountResult subItemsCount(const QString &path, Options options);
Q_SIGNALS:
/**
@@ -53,6 +53,15 @@ public Q_SLOTS:
// is needed here. Just using 'Options' is OK for the compiler, but
// confuses moc.
void countDirectoryContents(const QString &path, KDirectoryContentsCounterWorker::Options options);
+ void stop();
+
+private:
+#ifndef Q_OS_WIN
+ KDirectoryContentsCounterWorker::CountResult
+ walkDir(const QString &dirPath, const bool countHiddenFiles, const bool countDirectoriesOnly, const uint allowedRecursiveLevel);
+#endif
+
+ bool m_stopping = false;
};
Q_DECLARE_METATYPE(KDirectoryContentsCounterWorker::Options)