]> cloud.milkyroute.net Git - dolphin.git/commitdiff
[Details mode] Allow to fill the column size of directories with actual size
authorMéven Car <meven29@gmail.com>
Mon, 4 May 2020 05:26:26 +0000 (07:26 +0200)
committerMéven Car <meven29@gmail.com>
Mon, 4 May 2020 05:26:59 +0000 (07:26 +0200)
Summary:
Allow to compute the recursive size of directories to fill the details view size column.
A setting allow to set a limit to the recursive level, allowing the user to have some power over the setting.

When sorting by size and the feature is on, we get progressive ordering as the directory size are gathered.

KDirectoryContentsCounter uses a cache internally to keep results so that it can display directory size faster, but counts the dir size of directories each time it is asked to count the size a directory nevertheless and when the size has changed, it is updated.
KDirectoryContentsCounter uses one worker per instance only, meaning one process per view makes the disk spin.

FIXED-IN: 20.08
BUG: 190580
BUG: 158090

Test Plan:
With some recursion allowed:
{F8267580}

Without any recursion allowed (default):
{F8267581}

Reviewers: elvisangelaccio, ngraham, #dolphin

Reviewed By: elvisangelaccio, ngraham, #dolphin

Subscribers: feverfew, anthonyfieroni, iasensio, kfm-devel

Tags: #dolphin

Differential Revision: https://phabricator.kde.org/D25335

12 files changed:
src/dolphinviewcontainer.cpp
src/kitemviews/kfileitemlistwidget.cpp
src/kitemviews/kfileitemmodel.cpp
src/kitemviews/kfileitemmodelrolesupdater.cpp
src/kitemviews/kfileitemmodelrolesupdater.h
src/kitemviews/private/kdirectorycontentscounter.cpp
src/kitemviews/private/kdirectorycontentscounter.h
src/kitemviews/private/kdirectorycontentscounterworker.cpp
src/kitemviews/private/kdirectorycontentscounterworker.h
src/settings/dolphin_detailsmodesettings.kcfg
src/settings/viewmodes/viewsettingstab.cpp
src/settings/viewmodes/viewsettingstab.h

index 60d3374ad46cce67469ab5844aba3bb642cdd402..4ab34a06a85ef1632c6bdd8ed499489a1e03023b 100644 (file)
@@ -29,6 +29,8 @@
 #include "trash/dolphintrash.h"
 #include "views/viewmodecontroller.h"
 #include "views/viewproperties.h"
+#include "dolphin_detailsmodesettings.h"
+#include "views/dolphinview.h"
 
 #ifdef HAVE_KACTIVITIES
 #include <KActivities/ResourceInstance>
@@ -249,6 +251,12 @@ DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) :
 
     setSearchModeEnabled(isSearchUrl(url));
 
+    connect(DetailsModeSettings::self(), &KCoreConfigSkeleton::configChanged, this, [=]() {
+        if (view()->mode() == DolphinView::Mode::DetailsView) {
+            view()->reload();
+        }
+    });
+
     // Initialize kactivities resource instance
 
 #ifdef HAVE_KACTIVITIES
index 40b8ccf3717a4a10965cf8c361c8be7e743fb57a..a495a4c2ff63095511f421b740cc68c23f1e1388 100644 (file)
@@ -21,6 +21,8 @@
 #include "kfileitemmodel.h"
 #include "kitemlistview.h"
 
+#include "dolphin_detailsmodesettings.h"
+
 #include <KFormat>
 #include <KLocalizedString>
 
@@ -64,14 +66,24 @@ QString KFileItemListWidgetInformant::roleText(const QByteArray& role,
 
     if (role == "size") {
         if (values.value("isDir").toBool()) {
-            // The item represents a directory. Show the number of sub directories
-            // instead of the file size of the directory.
+            // The item represents a directory.
             if (!roleValue.isNull()) {
-                const int count = roleValue.toInt();
+                const int count = values.value("count").toInt();
                 if (count < 0) {
                     text = i18nc("@item:intable", "Unknown");
                 } else {
-                    text = i18ncp("@item:intable", "%1 item", "%1 items", count);
+                    if (DetailsModeSettings::directorySizeCount()) {
+                        //  Show the number of sub directories instead of the file size of the directory.
+                        text = i18ncp("@item:intable", "%1 item", "%1 items", count);
+                    } else {
+                        // if we have directory size available
+                        if (roleValue == -1) {
+                            text = i18nc("@item:intable", "Unknown");
+                        } else {
+                            const KIO::filesize_t size = roleValue.value<KIO::filesize_t>();
+                            text = KFormat().formatByteSize(size);
+                        }
+                    }
                 }
             }
         } else {
index e4dca2734871d3b0c9e0dc0da1375fab76d202e5..5e9603ba1876a539b6f6837e3a283f266aa9b8ea 100644 (file)
@@ -22,6 +22,7 @@
 #include "kfileitemmodel.h"
 
 #include "dolphin_generalsettings.h"
+#include "dolphin_detailsmodesettings.h"
 #include "dolphindebug.h"
 #include "private/kfileitemmodeldirlister.h"
 #include "private/kfileitemmodelsortalgorithm.h"
@@ -1767,8 +1768,15 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b, const
             // See "if (m_sortFoldersFirst || m_sortRole == SizeRole)" in KFileItemModel::lessThan():
             Q_ASSERT(itemB.isDir());
 
-            const QVariant valueA = a->values.value("size");
-            const QVariant valueB = b->values.value("size");
+            QVariant valueA, valueB;
+            if (DetailsModeSettings::directorySizeCount()) {
+                // use dir size then
+                valueA = a->values.value("size");
+                valueB = b->values.value("size");
+            } else {
+                valueA = a->values.value("count");
+                valueB = b->values.value("count");
+            }
             if (valueA.isNull() && valueB.isNull()) {
                 result = 0;
             } else if (valueA.isNull()) {
@@ -1776,7 +1784,11 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b, const
             } else if (valueB.isNull()) {
                 result = +1;
             } else {
-                result = valueA.toInt() - valueB.toInt();
+                if (valueA < valueB) {
+                    return -1;
+                } else {
+                    return +1;
+                }
             }
         } else {
             // See "if (m_sortFoldersFirst || m_sortRole == SizeRole)" in KFileItemModel::lessThan():
index bf2c84c4031ffa6346dc2e5813d6c7a0ea7b1007..c28e240a5f97ba6b54dc1bd6e5c5453a769da363 100644 (file)
@@ -44,7 +44,6 @@
 #include <QElapsedTimer>
 #include <QTimer>
 
-
 // #define KFILEITEMMODELROLESUPDATER_DEBUG
 
 namespace {
@@ -108,9 +107,9 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO
             this,    &KFileItemModelRolesUpdater::slotSortRoleChanged);
 
     // Use a timer to prevent that each call of slotItemsChanged() results in a synchronous
-    // resolving of the roles. Postpone the resolving until no update has been done for 1 second.
+    // resolving of the roles. Postpone the resolving until no update has been done for 100 ms.
     m_recentlyChangedItemsTimer = new QTimer(this);
-    m_recentlyChangedItemsTimer->setInterval(1000);
+    m_recentlyChangedItemsTimer->setInterval(100);
     m_recentlyChangedItemsTimer->setSingleShot(true);
     connect(m_recentlyChangedItemsTimer, &QTimer::timeout, this, &KFileItemModelRolesUpdater::resolveRecentlyChangedItems);
 
@@ -750,7 +749,7 @@ void KFileItemModelRolesUpdater::applyChangedBalooRolesForItem(const KFileItem &
 #endif
 }
 
-void KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived(const QString& path, int count)
+void KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived(const QString& path, int count, long size)
 {
     const bool getSizeRole = m_roles.contains("size");
     const bool getIsExpandableRole = m_roles.contains("isExpandable");
@@ -761,17 +760,16 @@ void KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived(const QStrin
             QHash<QByteArray, QVariant> data;
 
             if (getSizeRole) {
-                data.insert("size", count);
+                data.insert("count", count);
+                if (size != -1) {
+                    data.insert("size", QVariant::fromValue(size));
+                }
             }
             if (getIsExpandableRole) {
                 data.insert("isExpandable", count > 0);
             }
 
-            disconnect(m_model, &KFileItemModel::itemsChanged,
-                       this,    &KFileItemModelRolesUpdater::slotItemsChanged);
             m_model->setData(index, data);
-            connect(m_model, &KFileItemModel::itemsChanged,
-                    this,    &KFileItemModelRolesUpdater::slotItemsChanged);
         }
     }
 }
@@ -997,7 +995,7 @@ void KFileItemModelRolesUpdater::applySortRole(int index)
         data.insert("type", item.mimeComment());
     } else if (m_model->sortRole() == "size" && item.isLocalFile() && item.isDir()) {
         const QString path = item.localPath();
-        data.insert("size", m_directoryContentsCounter->countDirectoryContentsSynchronously(path));
+        m_directoryContentsCounter->scanDirectory(path);
     } else {
         // Probably the sort role is a baloo role - just determine all roles.
         data = rolesData(item);
@@ -1070,7 +1068,7 @@ QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileIte
             // Tell m_directoryContentsCounter that we want to count the items
             // inside the directory. The result will be received in slotDirectoryContentsCountReceived.
             const QString path = item.localPath();
-            m_directoryContentsCounter->addDirectory(path);
+            m_directoryContentsCounter->scanDirectory(path);
         } else if (getSizeRole) {
             data.insert("size", -1); // -1 indicates an unknown number of items
         }
index 9078c8e0d64cdc89607b27b656c46967a919865d..e21cd30dfe0672b358fd012467c9d73fc4b0399e 100644 (file)
@@ -212,7 +212,7 @@ private slots:
     void applyChangedBalooRoles(const QString& file);
     void applyChangedBalooRolesForItem(const KFileItem& file);
 
-    void slotDirectoryContentsCountReceived(const QString& path, int count);
+    void slotDirectoryContentsCountReceived(const QString& path, int count, long size);
 
 private:
     /**
index bd204fe8e24a353a16a0dccdc6ff821b668c8474..a19bce8b3b061cd6b0ba3685b2a4603257056510 100644 (file)
 #include <KDirWatch>
 
 #include <QFileInfo>
+#include <QDir>
 #include <QThread>
 
+namespace  {
+    /// cache of directory counting result
+    static QHash<QString, QPair<int, long>> *s_cache;
+}
+
 KDirectoryContentsCounter::KDirectoryContentsCounter(KFileItemModel* model, QObject* parent) :
     QObject(parent),
     m_model(model),
@@ -43,9 +49,12 @@ KDirectoryContentsCounter::KDirectoryContentsCounter(KFileItemModel* model, QObj
         m_workerThread->start();
     }
 
+    if (s_cache == nullptr) {
+        s_cache = new QHash<QString, QPair<int, long>>();
+    }
+
     m_worker = new KDirectoryContentsCounterWorker();
     m_worker->moveToThread(m_workerThread);
-    ++m_workersCount;
 
     connect(this,     &KDirectoryContentsCounter::requestDirectoryContentsCount,
             m_worker, &KDirectoryContentsCounterWorker::countDirectoryContents);
@@ -58,9 +67,7 @@ KDirectoryContentsCounter::KDirectoryContentsCounter(KFileItemModel* model, QObj
 
 KDirectoryContentsCounter::~KDirectoryContentsCounter()
 {
-    --m_workersCount;
-
-    if (m_workersCount > 0) {
+    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.
@@ -79,38 +86,17 @@ KDirectoryContentsCounter::~KDirectoryContentsCounter()
     }
 }
 
-void KDirectoryContentsCounter::addDirectory(const QString& path)
+void KDirectoryContentsCounter::scanDirectory(const QString& path)
 {
     startWorker(path);
 }
 
-int KDirectoryContentsCounter::countDirectoryContentsSynchronously(const QString& path)
-{
-    const QString resolvedPath = QFileInfo(path).canonicalFilePath();
-
-    if (!m_dirWatcher->contains(resolvedPath)) {
-        m_dirWatcher->addDir(resolvedPath);
-        m_watchedDirs.insert(resolvedPath);
-    }
-
-    KDirectoryContentsCounterWorker::Options options;
-
-    if (m_model->showHiddenFiles()) {
-        options |= KDirectoryContentsCounterWorker::CountHiddenFiles;
-    }
-
-    if (m_model->showDirectoriesOnly()) {
-        options |= KDirectoryContentsCounterWorker::CountDirectoriesOnly;
-    }
-
-    return KDirectoryContentsCounterWorker::subItemsCount(path, options);
-}
-
-void KDirectoryContentsCounter::slotResult(const QString& path, int count)
+void KDirectoryContentsCounter::slotResult(const QString& path, int count, long size)
 {
     m_workerIsBusy = false;
 
-    const QString resolvedPath = QFileInfo(path).canonicalFilePath();
+    const QFileInfo info = QFileInfo(path);
+    const QString resolvedPath = info.canonicalFilePath();
 
     if (!m_dirWatcher->contains(resolvedPath)) {
         m_dirWatcher->addDir(resolvedPath);
@@ -121,7 +107,22 @@ void KDirectoryContentsCounter::slotResult(const QString& path, int count)
         startWorker(m_queue.dequeue());
     }
 
-    emit result(path, count);
+    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 (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<int, long>(count, size));
+    }
+
+    // sends the results
+    emit result(resolvedPath, count, size);
 }
 
 void KDirectoryContentsCounter::slotDirWatchDirty(const QString& path)
@@ -146,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();
@@ -166,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 {
@@ -185,4 +193,3 @@ void KDirectoryContentsCounter::startWorker(const QString& path)
 }
 
 QThread* KDirectoryContentsCounter::m_workerThread = nullptr;
-int KDirectoryContentsCounter::m_workersCount = 0;
index 349860757ac52bc6f5cfb8dbabe5d9fa3b61699d..0c900ec644334ff12fc78f84da2cdda8a9275332 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <QQueue>
 #include <QSet>
+#include <QHash>
 
 class KDirWatch;
 class KFileItemModel;
@@ -45,28 +46,23 @@ public:
      *
      * The directory \a path is watched for changes, and the signal is emitted
      * again if a change occurs.
-     */
-    void addDirectory(const QString& path);
-
-    /**
-     * In contrast to \a addDirectory, this function counts the items inside
-     * the directory \a path synchronously and returns the result.
      *
-     * The directory is watched for changes, and the signal \a result is
-     * emitted if a change occurs.
+     * Uses a cache internally to speed up first result,
+     * but emit again result when the cache was updated
      */
-    int countDirectoryContentsSynchronously(const QString& path);
+    void scanDirectory(const QString& path);
 
 signals:
     /**
-     * Signals that the directory \a path contains \a count items.
+     * Signals that the directory \a path contains \a count items of size \a
+     * Size calculation depends on parameter DetailsModeSettings::recursiveDirectorySizeLimit
      */
-    void result(const QString& path, int count);
+    void result(const QString& path, int count, long size);
 
     void requestDirectoryContentsCount(const QString& path, KDirectoryContentsCounterWorker::Options options);
 
 private slots:
-    void slotResult(const QString& path, int count);
+    void slotResult(const QString& path, int count, long size);
     void slotDirWatchDirty(const QString& path);
     void slotItemsRemoved();
 
@@ -79,7 +75,6 @@ private:
     QQueue<QString> m_queue;
 
     static QThread* m_workerThread;
-    static int m_workersCount;
 
     KDirectoryContentsCounterWorker* m_worker;
     bool m_workerIsBusy;
index e9c954ed9ce32183716bf3f978f36a1ff4780a1b..3117d07aa4ea4e6175002bbeec4a812f61661ab5 100644 (file)
 
 // Required includes for subItemsCount():
 #ifdef Q_OS_WIN
-    #include <QDir>
+#include <QDir>
 #else
-    #include <QFile>
-    #include <qplatformdefs.h>
+#include <QFile>
+#include <qplatformdefs.h>
 #endif
 
+#include "dolphin_detailsmodesettings.h"
+
 KDirectoryContentsCounterWorker::KDirectoryContentsCounterWorker(QObject* parent) :
     QObject(parent)
 {
     qRegisterMetaType<KDirectoryContentsCounterWorker::Options>();
 }
 
-int KDirectoryContentsCounterWorker::subItemsCount(const QString& path, Options options)
+KDirectoryContentsCounterWorker::CountResult walkDir(const QString &dirPath,
+                                                     const bool countHiddenFiles,
+                                                     const bool countDirectoriesOnly,
+                                                     QT_DIRENT *dirEntry,
+                                                     const uint allowedRecursiveLevel)
 {
-    const bool countHiddenFiles = options & CountHiddenFiles;
-    const bool countDirectoriesOnly = options & CountDirectoriesOnly;
-
-#ifdef Q_OS_WIN
-    QDir dir(path);
-    QDir::Filters filters = QDir::NoDotAndDotDot | QDir::System;
-    if (countHiddenFiles) {
-        filters |= QDir::Hidden;
-    }
-    if (countDirectoriesOnly) {
-        filters |= QDir::Dirs;
-    } else {
-        filters |= QDir::AllEntries;
-    }
-    return dir.entryList(filters).count();
-#else
-    // Taken from kio/src/widgets/kdirmodel.cpp
-    // Copyright (C) 2006 David Faure <faure@kde.org>
-
     int count = -1;
-    auto dir = QT_OPENDIR(QFile::encodeName(path));
+    long size = -1;
+    auto dir = QT_OPENDIR(QFile::encodeName(dirPath));
     if (dir) {
         count = 0;
-        QT_DIRENT *dirEntry = nullptr;
+        QT_STATBUF buf;
+
         while ((dirEntry = QT_READDIR(dir))) {
             if (dirEntry->d_name[0] == '.') {
                 if (dirEntry->d_name[1] == '\0' || !countHiddenFiles) {
@@ -76,20 +65,69 @@ int KDirectoryContentsCounterWorker::subItemsCount(const QString& path, Options
             // as directory instead of trying to do an expensive stat()
             // (see bugs 292642 and 299997).
             const bool countEntry = !countDirectoriesOnly ||
-                                    dirEntry->d_type == DT_DIR ||
-                                    dirEntry->d_type == DT_LNK ||
-                                    dirEntry->d_type == DT_UNKNOWN;
+                    dirEntry->d_type == DT_DIR ||
+                    dirEntry->d_type == DT_LNK ||
+                    dirEntry->d_type == DT_UNKNOWN;
             if (countEntry) {
                 ++count;
             }
+
+            if (allowedRecursiveLevel > 0) {
+
+                bool linkFound = false;
+                QString nameBuf = QStringLiteral("%1/%2").arg(dirPath, dirEntry->d_name);
+
+                if (dirEntry->d_type == DT_REG || dirEntry->d_type == DT_LNK) {
+                    if (QT_STAT(nameBuf.toLocal8Bit(), &buf) == 0) {
+                        if (S_ISDIR(buf.st_mode)) {
+                            // was a dir link, recurse
+                            linkFound = true;
+                        }
+                        size += buf.st_size;
+                    }
+                }
+                if (dirEntry->d_type == DT_DIR || linkFound) {
+                    // recursion for dirs and dir links
+                    size += walkDir(nameBuf, countHiddenFiles, countDirectoriesOnly, dirEntry, allowedRecursiveLevel - 1).size;
+                }
+            }
         }
         QT_CLOSEDIR(dir);
     }
-    return count;
+    return KDirectoryContentsCounterWorker::CountResult{count, size};
+}
+
+KDirectoryContentsCounterWorker::CountResult KDirectoryContentsCounterWorker::subItemsCount(const QString& path, Options options)
+{
+    const bool countHiddenFiles = options & CountHiddenFiles;
+    const bool countDirectoriesOnly = options & CountDirectoriesOnly;
+
+#ifdef Q_OS_WIN
+    QDir dir(path);
+    QDir::Filters filters = QDir::NoDotAndDotDot | QDir::System;
+    if (countHiddenFiles) {
+        filters |= QDir::Hidden;
+    }
+    if (countDirectoriesOnly) {
+        filters |= QDir::Dirs;
+    } else {
+        filters |= QDir::AllEntries;
+    }
+    return {dir.entryList(filters).count(), 0};
+#else
+
+    const uint maxRecursiveLevel = DetailsModeSettings::directorySizeCount() ? 1 : DetailsModeSettings::recursiveDirectorySizeLimit();
+
+    QT_DIRENT *dirEntry = nullptr;
+
+    auto res = walkDir(QFile::encodeName(path), countHiddenFiles, countDirectoriesOnly, dirEntry, maxRecursiveLevel);
+
+    return res;
 #endif
 }
 
 void KDirectoryContentsCounterWorker::countDirectoryContents(const QString& path, Options options)
 {
-    emit result(path, subItemsCount(path, options));
+    auto res = subItemsCount(path, options);
+    emit result(path, res.count, res.size);
 }
index b40da6e87b57f5f99eb48c57b302a012bdc8b2d5..fac9978d5fe357d08af1f68fd3ccb5367d12a94b 100644 (file)
@@ -37,6 +37,14 @@ public:
     };
     Q_DECLARE_FLAGS(Options, Option)
 
+    struct CountResult {
+        /// number of elements in the directory
+        int count;
+        /// Recursive sum of the size of the directory content files and folders
+        /// Calculation depends on DetailsModeSettings::recursiveDirectorySizeLimit
+        long size;
+    };
+
     explicit KDirectoryContentsCounterWorker(QObject* parent = nullptr);
 
     /**
@@ -45,13 +53,13 @@ public:
      *
      * @return The number of items.
      */
-    static int subItemsCount(const QString& path, Options options);
+    static CountResult subItemsCount(const QString& path, Options options);
 
 signals:
     /**
-     * Signals that the directory \a path contains \a count items.
+     * Signals that the directory \a path contains \a count items and optionally the size of its content.
      */
-    void result(const QString& path, int count);
+    void result(const QString& path, int count, long size);
 
 public slots:
     /**
index e9a8fb28d26de61a0a3ba4e87a76491a902f3e50..6ef344ac4f27a74d47dc667e028351a1d772d6b3 100644 (file)
             <label>Expandable folders</label>
             <default>true</default>
         </entry>
+        <entry name="DirectorySizeCount" type="Bool">
+            <label>Whether or not content count is use as directory size</label>
+            <default>true</default>
+        </entry>
+        <entry name="RecursiveDirectorySizeLimit" type="UInt">
+            <label>Recursive directory size limit</label>
+            <default>10</default>
+        </entry>
     </group>
 </kcfg>
index 06b0b8cf5ca191d80b5e2faef4560eb1374de559..fa891133b38cfbb58d3eccfa72091fa33513cd4b 100644 (file)
 #include <QComboBox>
 #include <QHelpEvent>
 #include <QFormLayout>
+#include <QSpinBox>
+#include <QRadioButton>
+#include <QButtonGroup>
+#include <QLabel>
 
 ViewSettingsTab::ViewSettingsTab(Mode mode, QWidget* parent) :
     QWidget(parent),
@@ -42,11 +46,11 @@ ViewSettingsTab::ViewSettingsTab(Mode mode, QWidget* parent) :
     m_fontRequester(nullptr),
     m_widthBox(nullptr),
     m_maxLinesBox(nullptr),
-    m_expandableFolders(nullptr)
+    m_expandableFolders(nullptr),
+    m_recursiveDirectorySizeLimit(nullptr)
 {
     QFormLayout* topLayout = new QFormLayout(this);
 
-
     // Create "Icon Size" section
     const int minRange = ZoomLevelInfo::minimumLevel();
     const int maxRange = ZoomLevelInfo::maximumLevel();
@@ -75,7 +79,6 @@ ViewSettingsTab::ViewSettingsTab(Mode mode, QWidget* parent) :
     m_fontRequester = new DolphinFontRequester(this);
     topLayout->addRow(i18nc("@label:listbox", "Label font:"), m_fontRequester);
 
-
     switch (m_mode) {
     case IconsMode: {
         m_widthBox = new QComboBox();
@@ -107,8 +110,30 @@ ViewSettingsTab::ViewSettingsTab(Mode mode, QWidget* parent) :
     case DetailsMode:
         m_expandableFolders = new QCheckBox(i18nc("@option:check", "Expandable"));
         topLayout->addRow(i18nc("@label:checkbox", "Folders:"), m_expandableFolders);
-        break;
-    default:
+
+#ifndef Q_OS_WIN
+        // Sorting properties
+        m_numberOfItems = new QRadioButton(i18nc("option:radio", "Number of items"));
+        m_sizeOfContents = new QRadioButton(i18nc("option:radio", "Size of contents, up to "));
+
+        QButtonGroup* sortingModeGroup = new QButtonGroup(this);
+        sortingModeGroup->addButton(m_numberOfItems);
+        sortingModeGroup->addButton(m_sizeOfContents);
+
+        m_recursiveDirectorySizeLimit = new QSpinBox();
+        connect(m_recursiveDirectorySizeLimit, QOverload<int>::of(&QSpinBox::valueChanged), this, [this](int value) {
+            m_recursiveDirectorySizeLimit->setSuffix(i18np(" level deep", " levels deep", value));
+        });
+        m_recursiveDirectorySizeLimit->setRange(1, 20);
+        m_recursiveDirectorySizeLimit->setSingleStep(1);
+
+        QHBoxLayout *contentsSizeLayout = new QHBoxLayout();
+        contentsSizeLayout->addWidget(m_sizeOfContents);
+        contentsSizeLayout->addWidget(m_recursiveDirectorySizeLimit);
+
+        topLayout->addRow(i18nc("@title:group", "Folder size displays:"), m_numberOfItems);
+        topLayout->addRow(QString(), contentsSizeLayout);
+#endif
         break;
     }
 
@@ -128,6 +153,11 @@ ViewSettingsTab::ViewSettingsTab(Mode mode, QWidget* parent) :
         break;
     case DetailsMode:
         connect(m_expandableFolders, &QCheckBox::toggled, this, &ViewSettingsTab::changed);
+        connect(m_recursiveDirectorySizeLimit, QOverload<int>::of(&QSpinBox::valueChanged), this, &ViewSettingsTab::changed);
+        connect(m_numberOfItems, &QRadioButton::toggled, this, &ViewSettingsTab::changed);
+        connect(m_sizeOfContents, &QRadioButton::toggled, this, [=]() {
+            m_recursiveDirectorySizeLimit->setEnabled(m_sizeOfContents->isChecked());
+        });
         break;
     default:
         break;
@@ -153,6 +183,8 @@ void ViewSettingsTab::applySettings()
         break;
     case DetailsMode:
         DetailsModeSettings::setExpandableFolders(m_expandableFolders->isChecked());
+        DetailsModeSettings::setDirectorySizeCount(m_numberOfItems->isChecked());
+        DetailsModeSettings::setRecursiveDirectorySizeLimit(m_recursiveDirectorySizeLimit->value());
         break;
     default:
         break;
@@ -201,6 +233,14 @@ void ViewSettingsTab::loadSettings()
         break;
     case DetailsMode:
         m_expandableFolders->setChecked(DetailsModeSettings::expandableFolders());
+        if (DetailsModeSettings::directorySizeCount()) {
+            m_numberOfItems->setChecked(true);
+            m_recursiveDirectorySizeLimit->setEnabled(false);
+        } else {
+            m_sizeOfContents->setChecked(true);
+            m_recursiveDirectorySizeLimit->setEnabled(true);
+        }
+        m_recursiveDirectorySizeLimit->setValue(DetailsModeSettings::recursiveDirectorySizeLimit());
         break;
     default:
         break;
index fff882e5e2794806f349ad16ff081d169c3b50f5..4d459fca2e27c3c9324fd8eea5355b04f45ffc91 100644 (file)
@@ -28,6 +28,8 @@ class DolphinFontRequester;
 class QComboBox;
 class QCheckBox;
 class QSlider;
+class QSpinBox;
+class QRadioButton;
 
 /**
  * @brief Represents one tab of the view-settings page.
@@ -72,6 +74,9 @@ private:
     QComboBox* m_widthBox;
     QComboBox* m_maxLinesBox;
     QCheckBox* m_expandableFolders;
+    QRadioButton* m_numberOfItems;
+    QRadioButton* m_sizeOfContents;
+    QSpinBox* m_recursiveDirectorySizeLimit;
 };
 
 #endif