mirror of
https://invent.kde.org/system/dolphin
synced 2024-08-21 17:30:15 +00:00
Optimize Directory size counting
Two changes: * Prioritise size counting for visible path * stop the worker when switching dirs
This commit is contained in:
parent
a15def4e64
commit
ba930ddb36
|
@ -422,6 +422,10 @@ void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList &itemRang
|
||||||
m_hoverSequenceLoadedItems.clear();
|
m_hoverSequenceLoadedItems.clear();
|
||||||
|
|
||||||
killPreviewJob();
|
killPreviewJob();
|
||||||
|
|
||||||
|
if (m_scanDirectories) {
|
||||||
|
m_directoryContentsCounter->stopWorker();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Only remove the items from m_finishedItems. They will be removed
|
// Only remove the items from m_finishedItems. They will be removed
|
||||||
// from the other sets later on.
|
// from the other sets later on.
|
||||||
|
@ -537,7 +541,7 @@ void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem &item, const QPi
|
||||||
|
|
||||||
QPixmap scaledPixmap = transformPreviewPixmap(pixmap);
|
QPixmap scaledPixmap = transformPreviewPixmap(pixmap);
|
||||||
|
|
||||||
QHash<QByteArray, QVariant> data = rolesData(item);
|
QHash<QByteArray, QVariant> data = rolesData(item, index);
|
||||||
|
|
||||||
const QStringList overlays = data["iconOverlays"].toStringList();
|
const QStringList overlays = data["iconOverlays"].toStringList();
|
||||||
// Strangely KFileItem::overlays() returns empty string-values, so
|
// Strangely KFileItem::overlays() returns empty string-values, so
|
||||||
|
@ -1210,13 +1214,10 @@ void KFileItemModelRolesUpdater::applySortRole(int index)
|
||||||
|
|
||||||
data.insert("type", item.mimeComment());
|
data.insert("type", item.mimeComment());
|
||||||
} else if (m_model->sortRole() == "size" && item.isLocalFile() && !item.isSlow() && item.isDir()) {
|
} else if (m_model->sortRole() == "size" && item.isLocalFile() && !item.isSlow() && item.isDir()) {
|
||||||
const QString path = item.localPath();
|
startDirectorySizeCounting(item, index);
|
||||||
if (m_scanDirectories) {
|
|
||||||
m_directoryContentsCounter->scanDirectory(path);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Probably the sort role is a baloo role - just determine all roles.
|
// 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);
|
disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged);
|
||||||
|
@ -1252,7 +1253,7 @@ bool KFileItemModelRolesUpdater::applyResolvedRoles(int index, ResolveHint hint)
|
||||||
|
|
||||||
QHash<QByteArray, QVariant> data;
|
QHash<QByteArray, QVariant> data;
|
||||||
if (resolveAll) {
|
if (resolveAll) {
|
||||||
data = rolesData(item);
|
data = rolesData(item, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!item.iconName().isEmpty()) {
|
if (!item.iconName().isEmpty()) {
|
||||||
|
@ -1273,7 +1274,19 @@ bool KFileItemModelRolesUpdater::applyResolvedRoles(int index, ResolveHint hint)
|
||||||
return false;
|
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;
|
QHash<QByteArray, QVariant> data;
|
||||||
|
|
||||||
|
@ -1281,16 +1294,7 @@ QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileIte
|
||||||
const bool getIsExpandableRole = m_roles.contains("isExpandable");
|
const bool getIsExpandableRole = m_roles.contains("isExpandable");
|
||||||
|
|
||||||
if ((getSizeRole || getIsExpandableRole) && !item.isSlow() && item.isDir()) {
|
if ((getSizeRole || getIsExpandableRole) && !item.isSlow() && item.isDir()) {
|
||||||
if (item.isLocalFile()) {
|
startDirectorySizeCounting(item, index);
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_roles.contains("extension")) {
|
if (m_roles.contains("extension")) {
|
||||||
|
|
|
@ -319,7 +319,7 @@ private:
|
||||||
|
|
||||||
enum ResolveHint { ResolveFast, ResolveAll };
|
enum ResolveHint { ResolveFast, ResolveAll };
|
||||||
bool applyResolvedRoles(int index, ResolveHint hint);
|
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
|
* Must be invoked if a property has been changed that affects
|
||||||
|
@ -334,6 +334,8 @@ private:
|
||||||
void trimHoverSequenceLoadedItems();
|
void trimHoverSequenceLoadedItems();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void startDirectorySizeCounting(const KFileItem &item, int index);
|
||||||
|
|
||||||
enum State { Idle, Paused, ResolvingSortRole, ResolvingAllRoles, PreviewJobRunning };
|
enum State { Idle, Paused, ResolvingSortRole, ResolvingAllRoles, PreviewJobRunning };
|
||||||
|
|
||||||
State m_state;
|
State m_state;
|
||||||
|
|
|
@ -44,6 +44,7 @@ KDirectoryContentsCounter::KDirectoryContentsCounter(KFileItemModel *model, QObj
|
||||||
m_worker->moveToThread(m_workerThread);
|
m_worker->moveToThread(m_workerThread);
|
||||||
|
|
||||||
connect(this, &KDirectoryContentsCounter::requestDirectoryContentsCount, m_worker, &KDirectoryContentsCounterWorker::countDirectoryContents);
|
connect(this, &KDirectoryContentsCounter::requestDirectoryContentsCount, m_worker, &KDirectoryContentsCounterWorker::countDirectoryContents);
|
||||||
|
connect(this, &KDirectoryContentsCounter::stop, m_worker, &KDirectoryContentsCounterWorker::stop);
|
||||||
connect(m_worker, &KDirectoryContentsCounterWorker::result, this, &KDirectoryContentsCounter::slotResult);
|
connect(m_worker, &KDirectoryContentsCounterWorker::result, this, &KDirectoryContentsCounter::slotResult);
|
||||||
|
|
||||||
m_dirWatcher = new KDirWatch(this);
|
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)
|
void KDirectoryContentsCounter::slotResult(const QString &path, int count, long size)
|
||||||
{
|
{
|
||||||
m_workerIsBusy = false;
|
m_workerIsBusy = false;
|
||||||
|
@ -91,11 +87,11 @@ void KDirectoryContentsCounter::slotResult(const QString &path, int count, long
|
||||||
if (!m_priorityQueue.empty()) {
|
if (!m_priorityQueue.empty()) {
|
||||||
const QString firstPath = m_priorityQueue.front();
|
const QString firstPath = m_priorityQueue.front();
|
||||||
m_priorityQueue.pop_front();
|
m_priorityQueue.pop_front();
|
||||||
startWorker(firstPath);
|
scanDirectory(firstPath, PathCountPriority::High);
|
||||||
} else if (!m_queue.empty()) {
|
} else if (!m_queue.empty()) {
|
||||||
const QString firstPath = m_queue.front();
|
const QString firstPath = m_queue.front();
|
||||||
m_queue.pop_front();
|
m_queue.pop_front();
|
||||||
startWorker(firstPath);
|
scanDirectory(firstPath, PathCountPriority::Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_cache->contains(resolvedPath)) {
|
if (s_cache->contains(resolvedPath)) {
|
||||||
|
@ -127,7 +123,7 @@ void KDirectoryContentsCounter::slotDirWatchDirty(const QString &path)
|
||||||
return;
|
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 QString resolvedPath = QFileInfo(path).canonicalFilePath();
|
||||||
const bool alreadyInCache = s_cache->contains(resolvedPath);
|
const bool alreadyInCache = s_cache->contains(resolvedPath);
|
||||||
|
@ -168,10 +164,16 @@ void KDirectoryContentsCounter::startWorker(const QString &path)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_workerIsBusy) {
|
if (m_workerIsBusy) {
|
||||||
|
// only enqueue path not yet in queue
|
||||||
if (std::find(m_queue.begin(), m_queue.end(), path) == m_queue.end()
|
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()) {
|
&& std::find(m_priorityQueue.begin(), m_priorityQueue.end(), path) == m_priorityQueue.end()) {
|
||||||
if (alreadyInCache) {
|
if (priority == PathCountPriority::Normal) {
|
||||||
m_queue.push_back(path);
|
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 {
|
} else {
|
||||||
// append to priority queue
|
// append to priority queue
|
||||||
m_priorityQueue.push_back(path);
|
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;
|
QThread *KDirectoryContentsCounter::m_workerThread = nullptr;
|
||||||
|
|
|
@ -21,6 +21,8 @@ class KDirectoryContentsCounter : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum PathCountPriority { Normal, High };
|
||||||
|
|
||||||
explicit KDirectoryContentsCounter(KFileItemModel *model, QObject *parent = nullptr);
|
explicit KDirectoryContentsCounter(KFileItemModel *model, QObject *parent = nullptr);
|
||||||
~KDirectoryContentsCounter() override;
|
~KDirectoryContentsCounter() override;
|
||||||
|
|
||||||
|
@ -35,7 +37,12 @@ public:
|
||||||
* Uses a cache internally to speed up first result,
|
* Uses a cache internally to speed up first result,
|
||||||
* but emit again result when the cache was updated
|
* 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:
|
Q_SIGNALS:
|
||||||
/**
|
/**
|
||||||
|
@ -46,14 +53,13 @@ Q_SIGNALS:
|
||||||
|
|
||||||
void requestDirectoryContentsCount(const QString &path, KDirectoryContentsCounterWorker::Options options);
|
void requestDirectoryContentsCount(const QString &path, KDirectoryContentsCounterWorker::Options options);
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void slotResult(const QString &path, int count, long size);
|
void slotResult(const QString &path, int count, long size);
|
||||||
void slotDirWatchDirty(const QString &path);
|
void slotDirWatchDirty(const QString &path);
|
||||||
void slotItemsRemoved();
|
void slotItemsRemoved();
|
||||||
|
|
||||||
private:
|
|
||||||
void startWorker(const QString &path);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KFileItemModel *m_model;
|
KFileItemModel *m_model;
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ KDirectoryContentsCounterWorker::KDirectoryContentsCounterWorker(QObject *parent
|
||||||
|
|
||||||
#ifndef Q_OS_WIN
|
#ifndef Q_OS_WIN
|
||||||
KDirectoryContentsCounterWorker::CountResult
|
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;
|
int count = -1;
|
||||||
long size = -1;
|
long size = -1;
|
||||||
|
@ -36,7 +36,7 @@ walkDir(const QString &dirPath, const bool countHiddenFiles, const bool countDir
|
||||||
QT_DIRENT *dirEntry;
|
QT_DIRENT *dirEntry;
|
||||||
QT_STATBUF buf;
|
QT_STATBUF buf;
|
||||||
|
|
||||||
while ((dirEntry = QT_READDIR(dir))) {
|
while (!m_stopping && (dirEntry = QT_READDIR(dir))) {
|
||||||
if (dirEntry->d_name[0] == '.') {
|
if (dirEntry->d_name[0] == '.') {
|
||||||
if (dirEntry->d_name[1] == '\0' || !countHiddenFiles) {
|
if (dirEntry->d_name[1] == '\0' || !countHiddenFiles) {
|
||||||
// Skip "." or hidden files
|
// Skip "." or hidden files
|
||||||
|
@ -64,7 +64,7 @@ walkDir(const QString &dirPath, const bool countHiddenFiles, const bool countDir
|
||||||
size += buf.st_size;
|
size += buf.st_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dirEntry->d_type == DT_DIR) {
|
if (!m_stopping && dirEntry->d_type == DT_DIR) {
|
||||||
// recursion for dirs
|
// recursion for dirs
|
||||||
auto subdirResult = walkDir(nameBuf, countHiddenFiles, countDirectoriesOnly, allowedRecursiveLevel - 1);
|
auto subdirResult = walkDir(nameBuf, countHiddenFiles, countDirectoriesOnly, allowedRecursiveLevel - 1);
|
||||||
if (subdirResult.size > 0) {
|
if (subdirResult.size > 0) {
|
||||||
|
@ -106,8 +106,18 @@ KDirectoryContentsCounterWorker::CountResult KDirectoryContentsCounterWorker::su
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KDirectoryContentsCounterWorker::stop()
|
||||||
|
{
|
||||||
|
m_stopping = true;
|
||||||
|
}
|
||||||
|
|
||||||
void KDirectoryContentsCounterWorker::countDirectoryContents(const QString &path, Options options)
|
void KDirectoryContentsCounterWorker::countDirectoryContents(const QString &path, Options options)
|
||||||
{
|
{
|
||||||
|
m_stopping = false;
|
||||||
|
|
||||||
auto res = subItemsCount(path, options);
|
auto res = subItemsCount(path, options);
|
||||||
Q_EMIT result(path, res.count, res.size);
|
|
||||||
|
if (!m_stopping) {
|
||||||
|
Q_EMIT result(path, res.count, res.size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ public:
|
||||||
*
|
*
|
||||||
* @return The number of items.
|
* @return The number of items.
|
||||||
*/
|
*/
|
||||||
static CountResult subItemsCount(const QString &path, Options options);
|
CountResult subItemsCount(const QString &path, Options options);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
/**
|
/**
|
||||||
|
@ -53,6 +53,15 @@ public Q_SLOTS:
|
||||||
// is needed here. Just using 'Options' is OK for the compiler, but
|
// is needed here. Just using 'Options' is OK for the compiler, but
|
||||||
// confuses moc.
|
// confuses moc.
|
||||||
void countDirectoryContents(const QString &path, KDirectoryContentsCounterWorker::Options options);
|
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)
|
Q_DECLARE_METATYPE(KDirectoryContentsCounterWorker::Options)
|
||||||
|
|
Loading…
Reference in a new issue