From c3fb0dc15ba71da45ed854769a3d80410c8fc598 Mon Sep 17 00:00:00 2001 From: Heiko Becker Date: Tue, 9 May 2023 08:59:14 +0200 Subject: Fix build without KF5Activities --- src/global.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/global.cpp b/src/global.cpp index 8babbbddc..9246eeb33 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -16,7 +16,7 @@ #include #include #include -#ifdef HAVE_KACTIVITIES +#if HAVE_KACTIVITIES #include #endif @@ -143,7 +143,7 @@ bool Dolphin::attachToExistingInstance(const QList &inputUrls, QVector, QStringList>> Dolphin::dolphinGuiInstances(const QString &preferredService) { -#ifdef HAVE_KACTIVITIES +#if HAVE_KACTIVITIES static std::once_flag one_consumer; static KActivities::Consumer *consumer; std::call_once(one_consumer, []() { @@ -161,7 +161,7 @@ QVector, QStringList>> Do QSharedPointer interface( new OrgKdeDolphinMainWindowInterface(service, QStringLiteral("/dolphin/Dolphin_1"), QDBusConnection::sessionBus())); if (interface->isValid() && !interface->lastError().isValid()) { -#ifdef HAVE_KACTIVITIES +#if HAVE_KACTIVITIES const auto currentActivity = consumer->currentActivity(); if (currentActivity.isEmpty() || currentActivity == QStringLiteral("00000000-0000-0000-0000-000000000000") || interface->isOnActivity(consumer->currentActivity())) -- cgit v1.3 From 629a5d44ddd89defb86c7fe9025735d00d8f0738 Mon Sep 17 00:00:00 2001 From: Méven Car Date: Wed, 10 May 2023 16:41:30 +0200 Subject: Add a TODO KF6 to solve bug 464722 CCBUG: 464722 --- src/kitemviews/kfileitemmodel.cpp | 1 + src/kitemviews/kfileitemmodelrolesupdater.cpp | 1 + 2 files changed, 2 insertions(+) (limited to 'src') diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp index ebcd4b912..0d61775ad 100644 --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -1829,6 +1829,7 @@ QHash KFileItemModel::retrieveData(const KFileItem &item, } if (m_requestRole[ExtensionRole] && !isDir) { + // TODO KF6 use KFileItem::suffix 464722 data.insert(sharedValue("extension"), QFileInfo(item.name()).suffix()); } diff --git a/src/kitemviews/kfileitemmodelrolesupdater.cpp b/src/kitemviews/kfileitemmodelrolesupdater.cpp index e0e61cd49..c488fc0cf 100644 --- a/src/kitemviews/kfileitemmodelrolesupdater.cpp +++ b/src/kitemviews/kfileitemmodelrolesupdater.cpp @@ -1304,6 +1304,7 @@ QHash KFileItemModelRolesUpdater::rolesData(const KFileIte } if (m_roles.contains("extension")) { + // TODO KF6 use KFileItem::suffix 464722 data.insert("extension", QFileInfo(item.name()).suffix()); } -- cgit v1.3 From dec80fb0f940ff4e71032c2d3544f0d60a05c4ce Mon Sep 17 00:00:00 2001 From: Méven Car Date: Thu, 18 May 2023 10:07:50 +0200 Subject: global.cpp: Ensure qApp does not emit signal because of local QEventLoop BUG: 469656 --- src/global.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/global.cpp b/src/global.cpp index 9246eeb33..c68b2d2d0 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -148,6 +148,8 @@ QVector, QStringList>> Do static KActivities::Consumer *consumer; std::call_once(one_consumer, []() { consumer = new KActivities::Consumer(); + // to prevent QGuiApplication::saveStateRequest + const QSignalBlocker blocker(qApp); // ensures the consumer is ready for query QEventLoop loop; QObject::connect(consumer, &KActivities::Consumer::serviceStatusChanged, &loop, &QEventLoop::quit); -- cgit v1.3 From b01329bf360795b51809c0adfeefaa91b79f7950 Mon Sep 17 00:00:00 2001 From: Méven Car Date: Wed, 24 May 2023 10:50:11 +0200 Subject: Revert "global.cpp: Ensure qApp does not emit signal because of local QEventLoop" This reverts commit dec80fb0f940ff4e71032c2d3544f0d60a05c4ce. --- src/global.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/global.cpp b/src/global.cpp index c68b2d2d0..9246eeb33 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -148,8 +148,6 @@ QVector, QStringList>> Do static KActivities::Consumer *consumer; std::call_once(one_consumer, []() { consumer = new KActivities::Consumer(); - // to prevent QGuiApplication::saveStateRequest - const QSignalBlocker blocker(qApp); // ensures the consumer is ready for query QEventLoop loop; QObject::connect(consumer, &KActivities::Consumer::serviceStatusChanged, &loop, &QEventLoop::quit); -- cgit v1.3 From ee8b71e5568f5a56b886b877d63fb345c96b2cce Mon Sep 17 00:00:00 2001 From: Méven Car Date: Wed, 24 May 2023 10:52:59 +0200 Subject: Revert "Restrict attaching instances to those on the same activity or same virtual desktop" This reverts commit b99f6f50eef395a3ceb88fb3d4b7357cbbc13c85. BUG: 408919 Reintroduces: CCBUG: 408919 --- src/dolphinmainwindow.cpp | 25 ------------------------- src/dolphinmainwindow.h | 3 --- src/global.cpp | 44 +++++++++++--------------------------------- 3 files changed, 11 insertions(+), 61 deletions(-) (limited to 'src') diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index 0094bc2e7..00af38beb 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -277,31 +277,6 @@ void DolphinMainWindow::openFiles(const QStringList &files, bool splitView) openFiles(QUrl::fromStringList(files), splitView); } -bool DolphinMainWindow::isOnCurrentDesktop() const -{ -#if HAVE_X11 - if (KWindowSystem::isPlatformX11()) { - const NET::Properties properties = NET::WMDesktop; - KWindowInfo info(this->winId(), properties); - return info.isOnCurrentDesktop(); - } -#endif - return true; -} - -bool DolphinMainWindow::isOnActivity(const QString &activityId) const -{ -#if HAVE_X11 && HAVE_KACTIVITIES - if (KWindowSystem::isPlatformX11()) { - const NET::Properties properties = NET::Supported; - const NET::Properties2 properties2 = NET::WM2Activities; - KWindowInfo info(this->winId(), properties, properties2); - return info.activities().contains(activityId); - } -#endif - return true; -} - void DolphinMainWindow::activateWindow(const QString &activationToken) { window()->setAttribute(Qt::WA_NativeWindow, true); diff --git a/src/dolphinmainwindow.h b/src/dolphinmainwindow.h index 92ddb24c3..5bb17e79a 100644 --- a/src/dolphinmainwindow.h +++ b/src/dolphinmainwindow.h @@ -204,9 +204,6 @@ public Q_SLOTS: /** @see GeneralSettings::splitViewChanged() */ void slotSplitViewChanged(); - bool isOnActivity(const QString &activityId) const; - bool isOnCurrentDesktop() const; - Q_SIGNALS: /** * Is sent if the selection of the currently active view has diff --git a/src/global.cpp b/src/global.cpp index 9246eeb33..554eb41fa 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -16,9 +16,6 @@ #include #include #include -#if HAVE_KACTIVITIES -#include -#endif #include @@ -143,37 +140,13 @@ bool Dolphin::attachToExistingInstance(const QList &inputUrls, QVector, QStringList>> Dolphin::dolphinGuiInstances(const QString &preferredService) { -#if HAVE_KACTIVITIES - static std::once_flag one_consumer; - static KActivities::Consumer *consumer; - std::call_once(one_consumer, []() { - consumer = new KActivities::Consumer(); - // ensures the consumer is ready for query - QEventLoop loop; - QObject::connect(consumer, &KActivities::Consumer::serviceStatusChanged, &loop, &QEventLoop::quit); - loop.exec(); - }); -#endif - QVector, QStringList>> dolphinInterfaces; - const auto tryAppendInterface = [&dolphinInterfaces](const QString &service) { - // Check if instance can handle our URLs - QSharedPointer interface( - new OrgKdeDolphinMainWindowInterface(service, QStringLiteral("/dolphin/Dolphin_1"), QDBusConnection::sessionBus())); - if (interface->isValid() && !interface->lastError().isValid()) { -#if HAVE_KACTIVITIES - const auto currentActivity = consumer->currentActivity(); - if (currentActivity.isEmpty() || currentActivity == QStringLiteral("00000000-0000-0000-0000-000000000000") - || interface->isOnActivity(consumer->currentActivity())) -#endif - if (interface->isOnCurrentDesktop()) { - dolphinInterfaces.append(qMakePair(interface, QStringList())); - } - } - }; - if (!preferredService.isEmpty()) { - tryAppendInterface(preferredService); + QSharedPointer preferredInterface( + new OrgKdeDolphinMainWindowInterface(preferredService, QStringLiteral("/dolphin/Dolphin_1"), QDBusConnection::sessionBus())); + if (preferredInterface->isValid() && !preferredInterface->lastError().isValid()) { + dolphinInterfaces.append(qMakePair(preferredInterface, QStringList())); + } } // Look for dolphin instances among all available dbus services. @@ -185,7 +158,12 @@ QVector, QStringList>> Do const QString myPid = QLatin1Char('-') + QString::number(QCoreApplication::applicationPid()); for (const QString &service : dbusServices) { if (service.startsWith(pattern) && !service.endsWith(myPid)) { - tryAppendInterface(service); + // Check if instance can handle our URLs + QSharedPointer interface( + new OrgKdeDolphinMainWindowInterface(service, QStringLiteral("/dolphin/Dolphin_1"), QDBusConnection::sessionBus())); + if (interface->isValid() && !interface->lastError().isValid()) { + dolphinInterfaces.append(qMakePair(interface, QStringList())); + } } } -- cgit v1.3 From a1c5c5cf81b5d1f6b7a0aa10b8a981cb70c5b26c Mon Sep 17 00:00:00 2001 From: Méven Car Date: Fri, 26 May 2023 15:10:09 +0000 Subject: KDirectoryContentsCounter: show intermediate dir size counting results, improve stopping, improve data caching Two user visible changes: * we can see the dir size changing as it is updated. * This makes the file counting a lot more reactive, when changing directories for instance. `KDirectoryContentsCounterWorker::walkDir` is not recursive anymore. The cache is now shared and only a single thread is used to count size recursively. --- src/kitemviews/kfileitemlistview.cpp | 15 -- src/kitemviews/kfileitemlistview.h | 8 - src/kitemviews/kfileitemlistwidget.cpp | 2 +- src/kitemviews/kfileitemmodel.cpp | 2 + src/kitemviews/kfileitemmodel.h | 5 + src/kitemviews/kfileitemmodelrolesupdater.cpp | 88 +++++-- src/kitemviews/kfileitemmodelrolesupdater.h | 6 +- .../private/kdirectorycontentscounter.cpp | 283 ++++++++++++++------- src/kitemviews/private/kdirectorycontentscounter.h | 16 +- .../private/kdirectorycontentscounterworker.cpp | 187 ++++++++------ .../private/kdirectorycontentscounterworker.h | 33 +-- src/panels/folders/folderspanel.cpp | 1 - 12 files changed, 394 insertions(+), 252 deletions(-) (limited to 'src') diff --git a/src/kitemviews/kfileitemlistview.cpp b/src/kitemviews/kfileitemlistview.cpp index e2a27a5ea..668ebdfb2 100644 --- a/src/kitemviews/kfileitemlistview.cpp +++ b/src/kitemviews/kfileitemlistview.cpp @@ -41,7 +41,6 @@ KFileItemListView::KFileItemListView(QGraphicsWidget *parent) , m_modelRolesUpdater(nullptr) , m_updateVisibleIndexRangeTimer(nullptr) , m_updateIconSizeTimer(nullptr) - , m_scanDirectories(true) { setAcceptDrops(true); @@ -119,19 +118,6 @@ qlonglong KFileItemListView::localFileSizePreviewLimit() const return m_modelRolesUpdater ? m_modelRolesUpdater->localFileSizePreviewLimit() : 0; } -void KFileItemListView::setScanDirectories(bool enabled) -{ - m_scanDirectories = enabled; - if (m_modelRolesUpdater) { - m_modelRolesUpdater->setScanDirectories(m_scanDirectories); - } -} - -bool KFileItemListView::scanDirectories() -{ - return m_scanDirectories; -} - QPixmap KFileItemListView::createDragPixmap(const KItemSet &indexes) const { if (!model()) { @@ -269,7 +255,6 @@ void KFileItemListView::onModelChanged(KItemModelBase *current, KItemModelBase * if (current) { m_modelRolesUpdater = new KFileItemModelRolesUpdater(static_cast(current), this); m_modelRolesUpdater->setIconSize(availableIconSize()); - m_modelRolesUpdater->setScanDirectories(scanDirectories()); applyRolesToModel(); } diff --git a/src/kitemviews/kfileitemlistview.h b/src/kitemviews/kfileitemlistview.h index 63bcf9e75..b4be0093e 100644 --- a/src/kitemviews/kfileitemlistview.h +++ b/src/kitemviews/kfileitemlistview.h @@ -71,13 +71,6 @@ public: void setLocalFileSizePreviewLimit(qlonglong size); qlonglong localFileSizePreviewLimit() const; - /** - * If set to true, directories contents are scanned to determine their size - * Default true - */ - void setScanDirectories(bool enabled); - bool scanDirectories(); - QPixmap createDragPixmap(const KItemSet &indexes) const override; /** @@ -137,7 +130,6 @@ private: KFileItemModelRolesUpdater *m_modelRolesUpdater; QTimer *m_updateVisibleIndexRangeTimer; QTimer *m_updateIconSizeTimer; - bool m_scanDirectories; friend class KFileItemListViewTest; // For unit testing }; diff --git a/src/kitemviews/kfileitemlistwidget.cpp b/src/kitemviews/kfileitemlistwidget.cpp index d9644bef5..ec8683345 100644 --- a/src/kitemviews/kfileitemlistwidget.cpp +++ b/src/kitemviews/kfileitemlistwidget.cpp @@ -67,7 +67,7 @@ QString KFileItemListWidgetInformant::roleText(const QByteArray &role, const QHa if (values.value("isDir").toBool()) { if (!roleValue.isNull() && roleValue != -1) { // The item represents a directory. - if (DetailsModeSettings::directorySizeCount()) { + if (DetailsModeSettings::directorySizeCount() || roleValue == -2 /* size is invalid */) { // Show the number of sub directories instead of the file size of the directory. const int count = values.value("count").toInt(); text = i18ncp("@item:intable", "%1 item", "%1 items", count); diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp index 0d61775ad..6617fbec6 100644 --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -129,6 +129,8 @@ void KFileItemModel::refreshDirectory(const QUrl &url) } m_dirLister->openUrl(url, KDirLister::Reload); + + Q_EMIT directoryRefreshing(); } QUrl KFileItemModel::directory() const diff --git a/src/kitemviews/kfileitemmodel.h b/src/kitemviews/kfileitemmodel.h index afcd633b0..721569a0c 100644 --- a/src/kitemviews/kfileitemmodel.h +++ b/src/kitemviews/kfileitemmodel.h @@ -217,6 +217,11 @@ Q_SIGNALS: */ void directoryLoadingCompleted(); + /** + * Is emitted when the model is being refreshed (F5 key press) + */ + void directoryRefreshing(); + /** * Is emitted after the loading of a directory has been canceled. */ diff --git a/src/kitemviews/kfileitemmodelrolesupdater.cpp b/src/kitemviews/kfileitemmodelrolesupdater.cpp index c488fc0cf..6838d0861 100644 --- a/src/kitemviews/kfileitemmodelrolesupdater.cpp +++ b/src/kitemviews/kfileitemmodelrolesupdater.cpp @@ -10,6 +10,7 @@ #include "kfileitemmodel.h" #include "private/kdirectorycontentscounter.h" #include "private/kpixmapmodifier.h" +#include "qdir.h" #include #include @@ -20,6 +21,8 @@ #include #include +#include "dolphin_detailsmodesettings.h" + #if HAVE_BALOO #include "private/kbaloorolesprovider.h" #include @@ -72,7 +75,6 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel *model, QO , m_resolvableRoles() , m_enabledPlugins() , m_localFileSizePreviewLimit(0) - , m_scanDirectories(true) , m_pendingSortRoleItems() , m_pendingIndexes() , m_pendingPreviewItems() @@ -321,16 +323,6 @@ qlonglong KFileItemModelRolesUpdater::localFileSizePreviewLimit() const return m_localFileSizePreviewLimit; } -void KFileItemModelRolesUpdater::setScanDirectories(bool enabled) -{ - m_scanDirectories = enabled; -} - -bool KFileItemModelRolesUpdater::scanDirectories() const -{ - return m_scanDirectories; -} - void KFileItemModelRolesUpdater::setHoverSequenceState(const QUrl &itemUrl, int seqIdx) { const KFileItem item = m_model->fileItem(itemUrl); @@ -423,8 +415,7 @@ void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList &itemRang m_hoverSequenceLoadedItems.clear(); killPreviewJob(); - - if (m_scanDirectories) { + if (!m_model->showDirectoriesOnly()) { m_directoryContentsCounter->stopWorker(); } } else { @@ -856,10 +847,10 @@ void KFileItemModelRolesUpdater::applyChangedBalooRolesForItem(const KFileItem & #endif } -void KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived(const QString &path, int count, long size) +void KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived(const QString &path, int count, long long size) { - const bool getSizeRole = m_roles.contains("size"); const bool getIsExpandableRole = m_roles.contains("isExpandable"); + const bool getSizeRole = m_roles.contains("size"); if (getSizeRole || getIsExpandableRole) { const int index = m_model->index(QUrl::fromLocalFile(path)); @@ -1278,18 +1269,71 @@ bool KFileItemModelRolesUpdater::applyResolvedRoles(int index, ResolveHint hint) void KFileItemModelRolesUpdater::startDirectorySizeCounting(const KFileItem &item, int index) { - if (item.isSlow()) { + if (DetailsModeSettings::directorySizeCount() || item.isSlow() || !item.isLocalFile()) { + // fastpath no recursion necessary + + auto data = m_model->data(index); + if (data.value("size") == -2) { + // means job already started + return; + } + + auto url = item.url(); + if (!item.localPath().isEmpty()) { + // optimization for desktop:/, trash:/ + url = QUrl::fromLocalFile(item.localPath()); + } + + data.insert("isExpandable", false); + data.insert("count", 0); + data.insert("size", -2); // invalid size, -1 means size unknown + + disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); + m_model->setData(index, data); + connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); + + auto listJob = KIO::listDir(url); + QObject::connect(listJob, &KIO::ListJob::entries, this, [this, index](const KJob * /*job*/, const KIO::UDSEntryList &list) { + auto data = m_model->data(index); + int origCount = data.value("count").toInt(); + int entryCount = origCount; + + for (const KIO::UDSEntry &entry : list) { + const auto name = entry.stringValue(KIO::UDSEntry::UDS_NAME); + + if (name == QStringLiteral("..") || name == QStringLiteral(".")) { + continue; + } + if (!m_model->showHiddenFiles() && name.startsWith(QLatin1Char('.'))) { + continue; + } + if (m_model->showDirectoriesOnly() && !entry.isDir()) { + continue; + } + ++entryCount; + } + + // count has changed + if (origCount < entryCount) { + QHash data; + data.insert("isExpandable", entryCount > 0); + data.insert("count", entryCount); + + disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); + m_model->setData(index, data); + connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); + } + }); return; } // 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); - } + 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 KFileItemModelRolesUpdater::rolesData(const KFileItem &item, int index) diff --git a/src/kitemviews/kfileitemmodelrolesupdater.h b/src/kitemviews/kfileitemmodelrolesupdater.h index be6f23193..78fa757f8 100644 --- a/src/kitemviews/kfileitemmodelrolesupdater.h +++ b/src/kitemviews/kfileitemmodelrolesupdater.h @@ -260,7 +260,7 @@ private Q_SLOTS: void applyChangedBalooRoles(const QString &file); void applyChangedBalooRolesForItem(const KFileItem &file); - void slotDirectoryContentsCountReceived(const QString &path, int count, long size); + void slotDirectoryContentsCountReceived(const QString &path, int count, long long size); private: /** @@ -334,6 +334,9 @@ private: void trimHoverSequenceLoadedItems(); private: + /** + * enqueue directory size counting for KFileItem item at index + */ void startDirectorySizeCounting(const KFileItem &item, int index); enum State { Idle, Paused, ResolvingSortRole, ResolvingAllRoles, PreviewJobRunning }; @@ -370,7 +373,6 @@ private: QSet m_resolvableRoles; QStringList m_enabledPlugins; qulonglong m_localFileSizePreviewLimit; - bool m_scanDirectories; // Items for which the sort role still has to be determined. QSet m_pendingSortRoleItems; diff --git a/src/kitemviews/private/kdirectorycontentscounter.cpp b/src/kitemviews/private/kdirectorycontentscounter.cpp index 37e852ab9..e1a47419d 100644 --- a/src/kitemviews/private/kdirectorycontentscounter.cpp +++ b/src/kitemviews/private/kdirectorycontentscounter.cpp @@ -6,6 +6,7 @@ */ #include "kdirectorycontentscounter.h" +#include "dolphin_detailsmodesettings.h" #include "kitemviews/kfileitemmodel.h" #include @@ -16,36 +17,102 @@ namespace { + +class LocalCache +{ +public: + struct cacheData { + int count = 0; + long long size = 0; + ushort refCount = 0; + qint64 timestamp = 0; + + inline operator bool() const + { + return timestamp != 0 && count != -1; + } + }; + + LocalCache() + : m_cache() + { + } + + cacheData insert(const QString &key, cacheData data, bool inserted) + { + data.timestamp = QDateTime::currentMSecsSinceEpoch(); + if (inserted) { + data.refCount += 1; + } + m_cache.insert(key, data); + return data; + } + + cacheData value(const QString &key) const + { + return m_cache.value(key); + } + + void unRefAll(const QSet &keys) + { + for (const auto &key : keys) { + auto entry = m_cache[key]; + entry.refCount -= 1; + if (entry.refCount == 0) { + m_cache.remove(key); + } + } + } + + void removeAll(const QSet &keys) + { + for (const auto &key : keys) { + m_cache.remove(key); + } + } + +private: + QHash m_cache; +}; + /// cache of directory counting result -static QHash> *s_cache; +static LocalCache *s_cache; +static QThread *s_workerThread; +static KDirectoryContentsCounterWorker *s_worker; } KDirectoryContentsCounter::KDirectoryContentsCounter(KFileItemModel *model, QObject *parent) : QObject(parent) , m_model(model) + , m_priorityQueue() , m_queue() - , m_worker(nullptr) , m_workerIsBusy(false) , m_dirWatcher(nullptr) , m_watchedDirs() { - connect(m_model, &KFileItemModel::itemsRemoved, this, &KDirectoryContentsCounter::slotItemsRemoved); + if (s_cache == nullptr) { + s_cache = new LocalCache(); + } - if (!m_workerThread) { - m_workerThread = new QThread(); - m_workerThread->start(); + if (!s_workerThread) { + s_workerThread = new QThread(); + s_workerThread->setObjectName(QStringLiteral("KDirectoryContentsCounterThread")); + s_workerThread->start(); } - if (s_cache == nullptr) { - s_cache = new QHash>(); + if (!s_worker) { + s_worker = new KDirectoryContentsCounterWorker(); + s_worker->moveToThread(s_workerThread); } - m_worker = new KDirectoryContentsCounterWorker(); - m_worker->moveToThread(m_workerThread); + connect(m_model, &KFileItemModel::itemsRemoved, this, &KDirectoryContentsCounter::slotItemsRemoved); + connect(m_model, &KFileItemModel::directoryRefreshing, this, &KDirectoryContentsCounter::slotDirectoryRefreshing); + + connect(this, &KDirectoryContentsCounter::requestDirectoryContentsCount, s_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(s_worker, &KDirectoryContentsCounterWorker::result, this, &KDirectoryContentsCounter::slotResult); + connect(s_worker, &KDirectoryContentsCounterWorker::intermediateResult, this, &KDirectoryContentsCounter::result); + connect(s_worker, &KDirectoryContentsCounterWorker::finished, this, &KDirectoryContentsCounter::scheduleNext); m_dirWatcher = new KDirWatch(this); connect(m_dirWatcher, &KDirWatch::dirty, this, &KDirectoryContentsCounter::slotDirWatchDirty); @@ -53,60 +120,20 @@ KDirectoryContentsCounter::KDirectoryContentsCounter(KFileItemModel *model, QObj KDirectoryContentsCounter::~KDirectoryContentsCounter() { - 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; - } + s_cache->unRefAll(m_watchedDirs); } -void KDirectoryContentsCounter::slotResult(const QString &path, int count, long size) +void KDirectoryContentsCounter::slotResult(const QString &path, int count, long long size) { - m_workerIsBusy = false; - - const QFileInfo info = QFileInfo(path); - const QString resolvedPath = info.canonicalFilePath(); - - if (!m_dirWatcher->contains(resolvedPath)) { + const auto fileInfo = QFileInfo(path); + const QString resolvedPath = fileInfo.canonicalFilePath(); + if (fileInfo.isReadable() && !m_watchedDirs.contains(resolvedPath)) { m_dirWatcher->addDir(resolvedPath); - m_watchedDirs.insert(resolvedPath); - } - - if (!m_priorityQueue.empty()) { - const QString firstPath = m_priorityQueue.front(); - m_priorityQueue.pop_front(); - scanDirectory(firstPath, PathCountPriority::High); - } else if (!m_queue.empty()) { - const QString firstPath = m_queue.front(); - m_queue.pop_front(); - scanDirectory(firstPath, PathCountPriority::Normal); } + bool inserted = m_watchedDirs.insert(resolvedPath) == m_watchedDirs.end(); - 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(count, size)); - } + // update cache or overwrite value + s_cache->insert(resolvedPath, {count, size, true}, inserted); // sends the results Q_EMIT result(path, count, size); @@ -131,6 +158,11 @@ void KDirectoryContentsCounter::slotItemsRemoved() { const bool allItemsRemoved = (m_model->count() == 0); + if (allItemsRemoved) { + s_cache->removeAll(m_watchedDirs); + stopWorker(); + } + if (!m_watchedDirs.isEmpty()) { // Don't let KDirWatch watch for removed items if (allItemsRemoved) { @@ -138,7 +170,6 @@ void KDirectoryContentsCounter::slotItemsRemoved() m_dirWatcher->removeDir(path); } m_watchedDirs.clear(); - m_queue.clear(); } else { QMutableSetIterator it(m_watchedDirs); while (it.hasNext()) { @@ -152,46 +183,102 @@ void KDirectoryContentsCounter::slotItemsRemoved() } } -void KDirectoryContentsCounter::scanDirectory(const QString &path, PathCountPriority priority) +void KDirectoryContentsCounter::slotDirectoryRefreshing() +{ + s_cache->removeAll(m_watchedDirs); +} + +void KDirectoryContentsCounter::scheduleNext() { - const QString resolvedPath = QFileInfo(path).canonicalFilePath(); - const bool alreadyInCache = s_cache->contains(resolvedPath); - if (alreadyInCache) { + if (!m_priorityQueue.empty()) { + m_currentPath = m_priorityQueue.front(); + m_priorityQueue.pop_front(); + } else if (!m_queue.empty()) { + m_currentPath = m_queue.front(); + m_queue.pop_front(); + } else { + m_currentPath.clear(); + m_workerIsBusy = false; + return; + } + + const auto fileInfo = QFileInfo(m_currentPath); + const QString resolvedPath = fileInfo.canonicalFilePath(); + const auto pair = s_cache->value(resolvedPath); + if (pair) { // fast path when in cache // will be updated later if result has changed - const auto pair = s_cache->value(resolvedPath); - Q_EMIT result(path, pair.first, pair.second); - } - - 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 (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); - } - } - } else { - KDirectoryContentsCounterWorker::Options options; + Q_EMIT result(m_currentPath, pair.count, pair.size); + } + + // if scanned fully recently, skip rescan + if (pair && pair.timestamp >= fileInfo.fileTime(QFile::FileModificationTime).toMSecsSinceEpoch()) { + scheduleNext(); + return; + } + + KDirectoryContentsCounterWorker::Options options; + + if (m_model->showHiddenFiles()) { + options |= KDirectoryContentsCounterWorker::CountHiddenFiles; + } + + m_workerIsBusy = true; + Q_EMIT requestDirectoryContentsCount(m_currentPath, options, DetailsModeSettings::recursiveDirectorySizeLimit()); +} - if (m_model->showHiddenFiles()) { - options |= KDirectoryContentsCounterWorker::CountHiddenFiles; +void KDirectoryContentsCounter::enqueuePathScanning(const QString &path, bool alreadyInCache, PathCountPriority priority) +{ + // ensure to update the entry in the queue + auto it = std::find(m_queue.begin(), m_queue.end(), path); + if (it != m_queue.end()) { + m_queue.erase(it); + } else { + it = std::find(m_priorityQueue.begin(), m_priorityQueue.end(), path); + if (it != m_priorityQueue.end()) { + m_priorityQueue.erase(it); } + } - if (m_model->showDirectoriesOnly()) { - options |= KDirectoryContentsCounterWorker::CountDirectoriesOnly; + if (priority == PathCountPriority::Normal) { + if (alreadyInCache) { + // we already knew the dir size + // otherwise it gets lower priority + m_queue.push_back(path); + } else { + m_queue.push_front(path); } + } else { + // append to priority queue + m_priorityQueue.push_front(path); + } +} + +void KDirectoryContentsCounter::scanDirectory(const QString &path, PathCountPriority priority) +{ + if (m_workerIsBusy && m_currentPath == path) { + // already listing + return; + } + + const auto fileInfo = QFileInfo(path); + const QString resolvedPath = fileInfo.canonicalFilePath(); + const auto pair = s_cache->value(resolvedPath); + if (pair) { + // fast path when in cache + // will be updated later if result has changed + Q_EMIT result(path, pair.count, pair.size); + } - Q_EMIT requestDirectoryContentsCount(path, options); - m_workerIsBusy = true; + // if scanned fully recently, skip rescan + if (pair && pair.timestamp >= fileInfo.fileTime(QFile::FileModificationTime).toMSecsSinceEpoch()) { + return; + } + + enqueuePathScanning(path, pair, priority); + + if (!m_workerIsBusy && !s_worker->stopping()) { + scheduleNext(); } } @@ -199,7 +286,9 @@ void KDirectoryContentsCounter::stopWorker() { m_queue.clear(); m_priorityQueue.clear(); - Q_EMIT stop(); -} -QThread *KDirectoryContentsCounter::m_workerThread = nullptr; + if (m_workerIsBusy && m_currentPath == s_worker->scannedPath()) { + s_worker->stop(); + } + m_currentPath.clear(); +} diff --git a/src/kitemviews/private/kdirectorycontentscounter.h b/src/kitemviews/private/kdirectorycontentscounter.h index 9a5e4a86b..552b5560e 100644 --- a/src/kitemviews/private/kdirectorycontentscounter.h +++ b/src/kitemviews/private/kdirectorycontentscounter.h @@ -49,32 +49,32 @@ Q_SIGNALS: * 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, long size); + void result(const QString &path, int count, long long size); - void requestDirectoryContentsCount(const QString &path, KDirectoryContentsCounterWorker::Options options); - - void stop(); + void requestDirectoryContentsCount(const QString &path, KDirectoryContentsCounterWorker::Options options, int maxRecursiveLevel); private Q_SLOTS: - void slotResult(const QString &path, int count, long size); + void slotResult(const QString &path, int count, long long size); void slotDirWatchDirty(const QString &path); void slotItemsRemoved(); + void slotDirectoryRefreshing(); + void scheduleNext(); private: + void enqueuePathScanning(const QString &path, bool alreadyInCache, PathCountPriority priority); + KFileItemModel *m_model; // Used as FIFO queues. std::list m_priorityQueue; std::list m_queue; - static QThread *m_workerThread; - - KDirectoryContentsCounterWorker *m_worker; bool m_workerIsBusy; KDirWatch *m_dirWatcher; QSet m_watchedDirs; // Required as sadly KDirWatch does not offer a getter method // to get all watched directories. + QString m_currentPath; }; #endif diff --git a/src/kitemviews/private/kdirectorycontentscounterworker.cpp b/src/kitemviews/private/kdirectorycontentscounterworker.cpp index 2227ebbc2..eb456da25 100644 --- a/src/kitemviews/private/kdirectorycontentscounterworker.cpp +++ b/src/kitemviews/private/kdirectorycontentscounterworker.cpp @@ -7,16 +7,16 @@ #include "kdirectorycontentscounterworker.h" -// Required includes for subItemsCount(): +// Required includes for countDirectoryContents(): #ifdef Q_OS_WIN #include #else -#include -#include +#include +#include +#include +#include #endif -#include "dolphin_detailsmodesettings.h" - KDirectoryContentsCounterWorker::KDirectoryContentsCounterWorker(QObject *parent) : QObject(parent) { @@ -24,100 +24,135 @@ KDirectoryContentsCounterWorker::KDirectoryContentsCounterWorker(QObject *parent } #ifndef Q_OS_WIN -KDirectoryContentsCounterWorker::CountResult -KDirectoryContentsCounterWorker::walkDir(const QString &dirPath, const bool countHiddenFiles, const bool countDirectoriesOnly, const uint allowedRecursiveLevel) +void KDirectoryContentsCounterWorker::walkDir(const QString &dirPath, bool countHiddenFiles, uint allowedRecursiveLevel) { - int count = -1; - long size = -1; - auto dir = QT_OPENDIR(QFile::encodeName(dirPath)); - if (dir) { - count = 0; - size = 0; - QT_DIRENT *dirEntry; - QT_STATBUF buf; - - while (!m_stopping && (dirEntry = QT_READDIR(dir))) { - if (dirEntry->d_name[0] == '.') { - if (dirEntry->d_name[1] == '\0' || !countHiddenFiles) { - // Skip "." or hidden files - continue; - } - if (dirEntry->d_name[1] == '.' && dirEntry->d_name[2] == '\0') { - // Skip ".." - continue; - } + QByteArray text = dirPath.toLocal8Bit(); + char *rootPath = new char[text.size() + 1]; + ::strncpy(rootPath, text.constData(), text.size() + 1); + char *path[2]{rootPath, nullptr}; + + // follow symlink only for root dir + auto tree = ::fts_open(path, FTS_COMFOLLOW | FTS_PHYSICAL | FTS_XDEV, nullptr); + if (!tree) { + delete[] rootPath; + return; + } + + FTSENT *node; + long long totalSize = -1; + int totalCount = -1; + QElapsedTimer timer; + timer.start(); + + while ((node = fts_read(tree)) && !m_stopping) { + auto info = node->fts_info; + + if (info == FTS_DC) { + // ignore directories clausing cycles + continue; + } + if (info == FTS_DNR) { + // ignore directories that can’t be read + continue; + } + if (info == FTS_ERR) { + // ignore directories causing errors + fts_set(tree, node, FTS_SKIP); + continue; + } + if (info == FTS_DP) { + // ignore end traversal of dir + continue; + } + + if (!countHiddenFiles && node->fts_name[0] == '.' && strncmp(".git", node->fts_name, 4) != 0) { + // skip hidden files, except .git dirs + if (info == FTS_D) { + fts_set(tree, node, FTS_SKIP); + } + continue; + } + + if (info == FTS_F) { + // only count files that are physical (aka skip /proc/kcore...) + // naive size counting not taking into account effective disk space used (aka size/block_size * block_size) + // skip directory size (usually a 4KB block) + if (node->fts_statp->st_blocks > 0) { + totalSize += node->fts_statp->st_size; } + } - // If only directories are counted, consider an unknown file type and links also - // 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; - if (countEntry) { - ++count; + if (info == FTS_D) { + if (node->fts_level == 0) { + // first read was sucessful, we can init counters + totalSize = 0; + totalCount = 0; } - if (allowedRecursiveLevel > 0) { - QString nameBuf = QStringLiteral("%1/%2").arg(dirPath, dirEntry->d_name); - - if (dirEntry->d_type == DT_REG) { - if (QT_STAT(nameBuf.toLocal8Bit(), &buf) == 0) { - size += buf.st_size; - } - } - if (!m_stopping && dirEntry->d_type == DT_DIR) { - // recursion for dirs - auto subdirResult = walkDir(nameBuf, countHiddenFiles, countDirectoriesOnly, allowedRecursiveLevel - 1); - if (subdirResult.size > 0) { - size += subdirResult.size; - } - } + if (node->fts_level > (int)allowedRecursiveLevel) { + // skip too deep nodes + fts_set(tree, node, FTS_SKIP); + continue; } } - QT_CLOSEDIR(dir); + // count first level elements + if (node->fts_level == 1) { + ++totalCount; + } + + // delay intermediate results + if (timer.hasExpired(200) || node->fts_level == 0) { + Q_EMIT intermediateResult(dirPath, totalCount, totalSize); + timer.restart(); + } + } + + delete[] rootPath; + fts_close(tree); + if (errno != 0) { + return; + } + + if (!m_stopping) { + Q_EMIT result(dirPath, totalCount, totalSize); } - return KDirectoryContentsCounterWorker::CountResult{count, size}; } #endif -KDirectoryContentsCounterWorker::CountResult KDirectoryContentsCounterWorker::subItemsCount(const QString &path, Options options) +void KDirectoryContentsCounterWorker::stop() +{ + m_stopping = true; +} + +bool KDirectoryContentsCounterWorker::stopping() const +{ + return m_stopping; +} + +QString KDirectoryContentsCounterWorker::scannedPath() const +{ + return m_scannedPath; +} + +void KDirectoryContentsCounterWorker::countDirectoryContents(const QString &path, Options options, int maxRecursiveLevel) { const bool countHiddenFiles = options & CountHiddenFiles; - const bool countDirectoriesOnly = options & CountDirectoriesOnly; #ifdef Q_OS_WIN QDir dir(path); - QDir::Filters filters = QDir::NoDotAndDotDot | QDir::System; + QDir::Filters filters = QDir::NoDotAndDotDot | QDir::System | QDir::AllEntries; if (countHiddenFiles) { filters |= QDir::Hidden; } - if (countDirectoriesOnly) { - filters |= QDir::Dirs; - } else { - filters |= QDir::AllEntries; - } - return {static_cast(dir.entryList(filters).count()), 0}; -#else - const uint maxRecursiveLevel = DetailsModeSettings::directorySizeCount() ? 1 : DetailsModeSettings::recursiveDirectorySizeLimit(); + Q_EMIT result(path, static_cast(dir.entryList(filters).count()), 0); +#else - auto res = walkDir(path, countHiddenFiles, countDirectoriesOnly, maxRecursiveLevel); + m_scannedPath = path; + walkDir(path, countHiddenFiles, maxRecursiveLevel); - return res; #endif -} - -void KDirectoryContentsCounterWorker::stop() -{ - m_stopping = true; -} -void KDirectoryContentsCounterWorker::countDirectoryContents(const QString &path, Options options) -{ m_stopping = false; - - auto res = subItemsCount(path, options); - - if (!m_stopping) { - Q_EMIT result(path, res.count, res.size); - } + Q_EMIT finished(); } diff --git a/src/kitemviews/private/kdirectorycontentscounterworker.h b/src/kitemviews/private/kdirectorycontentscounterworker.h index 5266960cd..077df9f69 100644 --- a/src/kitemviews/private/kdirectorycontentscounterworker.h +++ b/src/kitemviews/private/kdirectorycontentscounterworker.h @@ -17,32 +17,20 @@ class KDirectoryContentsCounterWorker : public QObject Q_OBJECT public: - enum Option { NoOptions = 0x0, CountHiddenFiles = 0x1, CountDirectoriesOnly = 0x2 }; + enum Option { NoOptions = 0x0, CountHiddenFiles = 0x1 }; 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); - /** - * Counts the items inside the directory \a path using the options - * \a options. - * - * @return The number of items. - */ - CountResult subItemsCount(const QString &path, Options options); - + bool stopping() const; + QString scannedPath() const; Q_SIGNALS: /** * Signals that the directory \a path contains \a count items and optionally the size of its content. */ - void result(const QString &path, int count, long size); + void result(const QString &path, int count, long long size); + void intermediateResult(const QString &path, int count, long long size); + void finished(); public Q_SLOTS: /** @@ -52,16 +40,17 @@ public Q_SLOTS: // Note that the full type name KDirectoryContentsCounterWorker::Options // is needed here. Just using 'Options' is OK for the compiler, but // confuses moc. - void countDirectoryContents(const QString &path, KDirectoryContentsCounterWorker::Options options); + void countDirectoryContents(const QString &path, KDirectoryContentsCounterWorker::Options options, int maxRecursiveLevel); void stop(); private: #ifndef Q_OS_WIN - KDirectoryContentsCounterWorker::CountResult - walkDir(const QString &dirPath, const bool countHiddenFiles, const bool countDirectoriesOnly, const uint allowedRecursiveLevel); + void walkDir(const QString &dirPath, bool countHiddenFiles, uint allowedRecursiveLevel); #endif - bool m_stopping = false; + QString m_scannedPath; + + std::atomic m_stopping = false; }; Q_DECLARE_METATYPE(KDirectoryContentsCounterWorker::Options) diff --git a/src/panels/folders/folderspanel.cpp b/src/panels/folders/folderspanel.cpp index 914692000..f304654cb 100644 --- a/src/panels/folders/folderspanel.cpp +++ b/src/panels/folders/folderspanel.cpp @@ -131,7 +131,6 @@ void FoldersPanel::showEvent(QShowEvent *event) // This assures that no performance and memory overhead is given when the folders panel is not // used at all and stays invisible. KFileItemListView *view = new KFileItemListView(); - view->setScanDirectories(false); view->setWidgetCreator(new KItemListWidgetCreator()); view->setSupportsItemExpanding(true); // Set the opacity to 0 initially. The opacity will be increased after the loading of the initial tree -- cgit v1.3 From c17e6c8d2b33d6d62df46025b69cb7b401f09f62 Mon Sep 17 00:00:00 2001 From: Méven Car Date: Fri, 26 May 2023 16:10:38 +0000 Subject: Expand or collapse all selected folders on Key Right/Left CCBUG: 196772 --- src/kitemviews/kitemlistcontroller.cpp | 35 ++++- src/kitemviews/kitemset.h | 93 ++++++++++- src/tests/CMakeLists.txt | 5 + src/tests/kitemlistcontrollerexpandtest.cpp | 235 ++++++++++++++++++++++++++++ 4 files changed, 352 insertions(+), 16 deletions(-) create mode 100644 src/tests/kitemlistcontrollerexpandtest.cpp (limited to 'src') diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index 2e7d2f057..74a631d8d 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -237,21 +237,34 @@ bool KItemListController::keyPressEvent(QKeyEvent *event) { int index = m_selectionManager->currentItem(); int key = event->key(); + const bool shiftPressed = event->modifiers() & Qt::ShiftModifier; // Handle the expanding/collapsing of items - if (m_view->supportsItemExpanding() && m_model->isExpandable(index)) { - if (key == Qt::Key_Right) { - if (m_model->setExpanded(index, true)) { - return true; + // expand / collapse all selected directories + if (m_view->supportsItemExpanding() && m_model->isExpandable(index) && (key == Qt::Key_Right || key == Qt::Key_Left)) { + const bool expandOrCollapse = key == Qt::Key_Right ? true : false; + bool shouldReturn = m_model->setExpanded(index, expandOrCollapse); + + // edit in reverse to preserve index of the first handled items + const auto selectedItems = m_selectionManager->selectedItems(); + for (auto it = selectedItems.rbegin(); it != selectedItems.rend(); ++it) { + shouldReturn |= m_model->setExpanded(*it, expandOrCollapse); + if (!shiftPressed) { + m_selectionManager->setSelected(*it); } - } else if (key == Qt::Key_Left) { - if (m_model->setExpanded(index, false)) { - return true; + } + if (shouldReturn) { + // update keyboard anchors + if (shiftPressed) { + m_keyboardAnchorIndex = selectedItems.count() > 0 ? qMin(index, selectedItems.last()) : index; + m_keyboardAnchorPos = keyboardAnchorPos(m_keyboardAnchorIndex); } + + event->ignore(); + return true; } } - const bool shiftPressed = event->modifiers() & Qt::ShiftModifier; const bool controlPressed = event->modifiers() & Qt::ControlModifier; const bool shiftOrControlPressed = shiftPressed || controlPressed; const bool navigationPressed = key == Qt::Key_Home || key == Qt::Key_End || key == Qt::Key_PageUp || key == Qt::Key_PageDown || key == Qt::Key_Up @@ -327,11 +340,17 @@ bool KItemListController::keyPressEvent(QKeyEvent *event) case Qt::Key_Up: updateKeyboardAnchor(); + if (shiftPressed && !m_selectionManager->isAnchoredSelectionActive() && m_selectionManager->isSelected(index)) { + m_selectionManager->beginAnchoredSelection(index); + } index = previousRowIndex(index); break; case Qt::Key_Down: updateKeyboardAnchor(); + if (shiftPressed && !m_selectionManager->isAnchoredSelectionActive() && m_selectionManager->isSelected(index)) { + m_selectionManager->beginAnchoredSelection(index); + } index = nextRowIndex(index); break; diff --git a/src/kitemviews/kitemset.h b/src/kitemviews/kitemset.h index fd73c0e02..b8ab6864d 100644 --- a/src/kitemviews/kitemset.h +++ b/src/kitemviews/kitemset.h @@ -50,7 +50,7 @@ public: class iterator { - iterator(const KItemRangeList::iterator &rangeIt, int offset) + iterator(const KItemRangeList::iterator &rangeIt, int offset = 0) : m_rangeIt(rangeIt) , m_offset(offset) { @@ -135,7 +135,7 @@ public: class const_iterator { - const_iterator(KItemRangeList::const_iterator rangeIt, int offset) + const_iterator(KItemRangeList::const_iterator rangeIt, int offset = 0) : m_rangeIt(rangeIt) , m_offset(offset) { @@ -223,6 +223,70 @@ public: friend class KItemSet; }; + class const_reverse_iterator + { + public: + const_reverse_iterator(KItemSet::const_iterator rangeIt) + : m_current(rangeIt) + { + } + + const_reverse_iterator(const KItemSet::const_reverse_iterator &other) + : m_current(other.base()) + { + } + + int operator*() const + { + // analog to std::prev + auto t = const_iterator(m_current); + --t; + return *t; + } + + inline bool operator==(const const_reverse_iterator &other) const + { + return m_current == other.m_current; + } + + bool operator!=(const const_reverse_iterator &other) const + { + return !(*this == other); + } + + const_reverse_iterator &operator++() + { + --m_current; + return *this; + } + const_reverse_iterator operator++(int) + { + auto tmp = *this; + ++(*this); + return tmp; + } + + const_reverse_iterator &operator--() + { + ++m_current; + return *this; + } + const_reverse_iterator operator--(int) + { + auto tmp = *this; + --(*this); + return tmp; + } + + KItemSet::const_iterator base() const + { + return m_current; + } + + private: + KItemSet::const_iterator m_current; + }; + iterator begin(); const_iterator begin() const; const_iterator constBegin() const; @@ -230,6 +294,9 @@ public: const_iterator end() const; const_iterator constEnd() const; + const_reverse_iterator rend() const; + const_reverse_iterator rbegin() const; + int first() const; int last() const; @@ -366,32 +433,32 @@ inline bool KItemSet::remove(int i) inline KItemSet::iterator KItemSet::begin() { - return iterator(m_itemRanges.begin(), 0); + return iterator(m_itemRanges.begin()); } inline KItemSet::const_iterator KItemSet::begin() const { - return const_iterator(m_itemRanges.begin(), 0); + return const_iterator(m_itemRanges.begin()); } inline KItemSet::const_iterator KItemSet::constBegin() const { - return const_iterator(m_itemRanges.constBegin(), 0); + return const_iterator(m_itemRanges.constBegin()); } inline KItemSet::iterator KItemSet::end() { - return iterator(m_itemRanges.end(), 0); + return iterator(m_itemRanges.end()); } inline KItemSet::const_iterator KItemSet::end() const { - return const_iterator(m_itemRanges.end(), 0); + return const_iterator(m_itemRanges.end()); } inline KItemSet::const_iterator KItemSet::constEnd() const { - return const_iterator(m_itemRanges.constEnd(), 0); + return const_iterator(m_itemRanges.constEnd()); } inline int KItemSet::first() const @@ -405,6 +472,16 @@ inline int KItemSet::last() const return lastRange.index + lastRange.count - 1; } +inline KItemSet::const_reverse_iterator KItemSet::rend() const +{ + return KItemSet::const_reverse_iterator(constBegin()); +} + +inline KItemSet::const_reverse_iterator KItemSet::rbegin() const +{ + return KItemSet::const_reverse_iterator(constEnd()); +} + inline KItemSet &KItemSet::operator<<(int i) { insert(i); diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index d4a7457cb..8e0c6f119 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -20,6 +20,11 @@ ecm_add_test(kitemlistcontrollertest.cpp testdir.cpp TEST_NAME kitemlistcontrollertest LINK_LIBRARIES dolphinprivate Qt${QT_MAJOR_VERSION}::Test) +# KItemListControllerExpandTest +ecm_add_test(kitemlistcontrollerexpandtest.cpp testdir.cpp +TEST_NAME kitemlistcontrollerexpandtest +LINK_LIBRARIES dolphinprivate Qt${QT_MAJOR_VERSION}::Test) + # KFileItemListViewTest ecm_add_test(kfileitemlistviewtest.cpp testdir.cpp TEST_NAME kfileitemlistviewtest diff --git a/src/tests/kitemlistcontrollerexpandtest.cpp b/src/tests/kitemlistcontrollerexpandtest.cpp new file mode 100644 index 000000000..20bc0cc0c --- /dev/null +++ b/src/tests/kitemlistcontrollerexpandtest.cpp @@ -0,0 +1,235 @@ +/* + * SPDX-FileCopyrightText: 2023 Méven Car + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "kitemviews/kfileitemlistview.h" +#include "kitemviews/kfileitemmodel.h" +#include "kitemviews/kitemlistcontainer.h" +#include "kitemviews/kitemlistcontroller.h" +#include "kitemviews/kitemlistselectionmanager.h" +#include "testdir.h" + +#include +#include +#include + +class KItemListControllerExpandTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + + void init(); + void cleanup(); + + void testDirExpand(); + +private: + KFileItemListView *m_view; + KItemListController *m_controller; + KItemListSelectionManager *m_selectionManager; + KFileItemModel *m_model; + TestDir *m_testDir; + KItemListContainer *m_container; + QSignalSpy *m_spyDirectoryLoadingCompleted; +}; + +void KItemListControllerExpandTest::initTestCase() +{ + QStandardPaths::setTestModeEnabled(true); + qRegisterMetaType("KItemSet"); + + m_testDir = new TestDir(); + m_model = new KFileItemModel(); + m_view = new KFileItemListView(); + m_controller = new KItemListController(m_model, m_view, this); + m_container = new KItemListContainer(m_controller); + m_controller = m_container->controller(); + m_controller->setSelectionBehavior(KItemListController::MultiSelection); + m_selectionManager = m_controller->selectionManager(); + + QStringList files; + files << "dir1/file1"; + files << "dir1/file2"; + files << "dir1/file3"; + files << "dir1/file4"; + files << "dir1/file5"; + + files << "dir2/file1"; + files << "dir2/file2"; + files << "dir2/file3"; + files << "dir2/file4"; + files << "dir2/file5"; + + files << "dir3/file1"; + files << "dir3/file2"; + files << "dir3/file3"; + files << "dir3/file4"; + files << "dir3/file5"; + + m_testDir->createFiles(files); + m_model->loadDirectory(m_testDir->url()); + m_spyDirectoryLoadingCompleted = new QSignalSpy(m_model, &KFileItemModel::directoryLoadingCompleted); + QVERIFY(m_spyDirectoryLoadingCompleted->wait()); + + m_container->show(); + QVERIFY(QTest::qWaitForWindowExposed(m_container)); +} +void KItemListControllerExpandTest::cleanupTestCase() +{ + delete m_container; + m_container = nullptr; + + delete m_testDir; + m_testDir = nullptr; +} + +void KItemListControllerExpandTest::init() +{ + m_selectionManager->setCurrentItem(0); + QCOMPARE(m_selectionManager->currentItem(), 0); + + m_selectionManager->clearSelection(); + QVERIFY(!m_selectionManager->hasSelection()); +} + +void KItemListControllerExpandTest::cleanup() +{ +} + +void KItemListControllerExpandTest::testDirExpand() +{ + m_view->setItemLayout(KFileItemListView::DetailsLayout); + QCOMPARE(m_view->itemLayout(), KFileItemListView::DetailsLayout); + m_view->setSupportsItemExpanding(true); + + // intial state + QCOMPARE(m_spyDirectoryLoadingCompleted->count(), 1); + QCOMPARE(m_model->count(), 3); + QCOMPARE(m_selectionManager->currentItem(), 0); + QCOMPARE(m_selectionManager->selectedItems().count(), 0); + + // extend first folder + QTest::keyClick(m_container, Qt::Key_Right); + QVERIFY(m_spyDirectoryLoadingCompleted->wait()); + QCOMPARE(m_model->count(), 8); + QCOMPARE(m_selectionManager->currentItem(), 0); + QCOMPARE(m_selectionManager->selectedItems().count(), 0); + + // collapse folder + QTest::keyClick(m_container, Qt::Key_Left); + + QCOMPARE(m_model->count(), 3); + QCOMPARE(m_selectionManager->currentItem(), 0); + QCOMPARE(m_selectionManager->selectedItems().count(), 0); + + // make the first folder selected + QTest::keyClick(m_container, Qt::Key_Down); + QCOMPARE(m_model->count(), 3); + QCOMPARE(m_selectionManager->currentItem(), 1); + QCOMPARE(m_selectionManager->selectedItems().count(), 1); + + QTest::keyClick(m_container, Qt::Key_Up); + QCOMPARE(m_model->count(), 3); + QCOMPARE(m_selectionManager->currentItem(), 0); + QCOMPARE(m_selectionManager->selectedItems().count(), 1); + + // expand the two first folders + QTest::keyClick(m_container, Qt::Key_Down, Qt::ShiftModifier); + QCOMPARE(m_model->count(), 3); + QCOMPARE(m_selectionManager->currentItem(), 1); + QCOMPARE(m_selectionManager->selectedItems().count(), 2); + + // precondition + QCOMPARE(m_spyDirectoryLoadingCompleted->count(), 2); + + // expand selected folders + QTest::keyClick(m_container, Qt::Key_Right); + QVERIFY(QTest::qWaitFor( + [this]() { + return m_spyDirectoryLoadingCompleted->count() == 3; + }, + 100)); + QCOMPARE(m_model->count(), 8); + QCOMPARE(m_selectionManager->currentItem(), 6); + QCOMPARE(m_selectionManager->selectedItems().count(), 2); + + // collapse the folders + QTest::keyClick(m_container, Qt::Key_Left); + QCOMPARE(m_model->count(), 3); + QCOMPARE(m_selectionManager->currentItem(), 1); + QCOMPARE(m_selectionManager->selectedItems().count(), 2); + + // select third folder + QTest::keyClick(m_container, Qt::Key_Down, Qt::ShiftModifier); + QCOMPARE(m_model->count(), 3); + QCOMPARE(m_selectionManager->currentItem(), 2); + QCOMPARE(m_selectionManager->selectedItems().count(), 3); + + // precondition + QCOMPARE(m_spyDirectoryLoadingCompleted->count(), 3); + + // expand the three folders + QTest::keyClick(m_container, Qt::Key_Right); + + QVERIFY(QTest::qWaitFor( + [this]() { + return m_spyDirectoryLoadingCompleted->count() == 6; + }, + 100)); + + QCOMPARE(m_model->count(), 18); + QCOMPARE(m_selectionManager->currentItem(), 12); + QCOMPARE(m_selectionManager->selectedItems().count(), 3); + + // collapse the folders + QTest::keyClick(m_container, Qt::Key_Left); + QCOMPARE(m_model->count(), 3); + QCOMPARE(m_selectionManager->currentItem(), 2); + QCOMPARE(m_selectionManager->selectedItems().count(), 3); + + // shift select the directories + QTest::keyClick(m_container, Qt::Key_Up); + QCOMPARE(m_model->count(), 3); + QCOMPARE(m_selectionManager->currentItem(), 1); + QCOMPARE(m_selectionManager->selectedItems().count(), 1); + + QTest::keyClick(m_container, Qt::Key_Up); + QCOMPARE(m_model->count(), 3); + QCOMPARE(m_selectionManager->currentItem(), 0); + QCOMPARE(m_selectionManager->selectedItems().count(), 1); + + QTest::keyClick(m_container, Qt::Key_Down, Qt::ShiftModifier); + QTest::keyClick(m_container, Qt::Key_Down, Qt::ShiftModifier); + + QCOMPARE(m_model->count(), 3); + QCOMPARE(m_selectionManager->currentItem(), 2); + QCOMPARE(m_selectionManager->selectedItems().count(), 3); + + // expand the three folders with shift modifier + QTest::keyClick(m_container, Qt::Key_Right, Qt::ShiftModifier); + + QVERIFY(QTest::qWaitFor( + [this]() { + return m_spyDirectoryLoadingCompleted->count() == 9; + }, + 100)); + + QCOMPARE(m_model->count(), 18); + QCOMPARE(m_selectionManager->currentItem(), 12); + QCOMPARE(m_selectionManager->selectedItems().count(), 13); + + // collapse the folders + QTest::keyClick(m_container, Qt::Key_Left); + QCOMPARE(m_model->count(), 3); + QCOMPARE(m_selectionManager->currentItem(), 2); + QCOMPARE(m_selectionManager->selectedItems().count(), 3); +} + +QTEST_MAIN(KItemListControllerExpandTest) + +#include "kitemlistcontrollerexpandtest.moc" -- cgit v1.3 From 05e99b3dd11aadb355b2b15cb7a5ed493b9823df Mon Sep 17 00:00:00 2001 From: Heiko Becker Date: Fri, 2 Jun 2023 20:44:05 +0200 Subject: GIT_SILENT Update Appstream for new release (cherry picked from commit db3c01a34ab927f0ef2401c03d175cd253656950) --- src/org.kde.dolphin.appdata.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/org.kde.dolphin.appdata.xml b/src/org.kde.dolphin.appdata.xml index 010f81c4c..319e1e46a 100644 --- a/src/org.kde.dolphin.appdata.xml +++ b/src/org.kde.dolphin.appdata.xml @@ -493,10 +493,10 @@ dolphin + - -- cgit v1.3 From e5abe2c67bed7f1ca448cc94eb3abcfbe7d0da92 Mon Sep 17 00:00:00 2001 From: Felix Ernst Date: Sun, 4 Jun 2023 18:09:42 +0200 Subject: Update my eMail to the KDE-provided one GIT_SILENT NO_CHANGELOG --- src/dolphinnavigatorswidgetaction.cpp | 2 +- src/dolphinnavigatorswidgetaction.h | 2 +- src/dolphintabpage.cpp | 2 +- src/dolphintabpage.h | 2 +- src/dolphinurlnavigator.cpp | 2 +- src/dolphinurlnavigator.h | 2 +- src/dolphinurlnavigatorscontroller.cpp | 2 +- src/dolphinurlnavigatorscontroller.h | 2 +- src/kitemviews/kfileitemlisttostring.cpp | 2 +- src/kitemviews/kfileitemlisttostring.h | 2 +- src/selectionmode/actiontexthelper.cpp | 2 +- src/selectionmode/actiontexthelper.h | 2 +- src/selectionmode/actionwithwidget.cpp | 2 +- src/selectionmode/actionwithwidget.h | 2 +- src/selectionmode/backgroundcolorhelper.cpp | 2 +- src/selectionmode/backgroundcolorhelper.h | 2 +- src/selectionmode/bottombar.cpp | 2 +- src/selectionmode/bottombar.h | 2 +- src/selectionmode/bottombarcontentscontainer.cpp | 2 +- src/selectionmode/bottombarcontentscontainer.h | 2 +- src/selectionmode/singleclickselectionproxystyle.h | 2 +- src/selectionmode/topbar.cpp | 2 +- src/selectionmode/topbar.h | 2 +- src/settings/viewmodes/viewmodesettings.cpp | 2 +- 24 files changed, 24 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/dolphinnavigatorswidgetaction.cpp b/src/dolphinnavigatorswidgetaction.cpp index 47a2a2303..a36836a37 100644 --- a/src/dolphinnavigatorswidgetaction.cpp +++ b/src/dolphinnavigatorswidgetaction.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2020 Felix Ernst + SPDX-FileCopyrightText: 2020 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/dolphinnavigatorswidgetaction.h b/src/dolphinnavigatorswidgetaction.h index 67c93d22d..6f068e27d 100644 --- a/src/dolphinnavigatorswidgetaction.h +++ b/src/dolphinnavigatorswidgetaction.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2020 Felix Ernst + SPDX-FileCopyrightText: 2020 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/dolphintabpage.cpp b/src/dolphintabpage.cpp index 2979cb568..413e77e81 100644 --- a/src/dolphintabpage.cpp +++ b/src/dolphintabpage.cpp @@ -1,6 +1,6 @@ /* * SPDX-FileCopyrightText: 2014 Emmanuel Pescosta - * SPDX-FileCopyrightText: 2020 Felix Ernst + * SPDX-FileCopyrightText: 2020 Felix Ernst * * SPDX-License-Identifier: GPL-2.0-or-later */ diff --git a/src/dolphintabpage.h b/src/dolphintabpage.h index 4e89d22ee..0c691830e 100644 --- a/src/dolphintabpage.h +++ b/src/dolphintabpage.h @@ -1,6 +1,6 @@ /* * SPDX-FileCopyrightText: 2014 Emmanuel Pescosta - * SPDX-FileCopyrightText: 2020 Felix Ernst + * SPDX-FileCopyrightText: 2020 Felix Ernst * * SPDX-License-Identifier: GPL-2.0-or-later */ diff --git a/src/dolphinurlnavigator.cpp b/src/dolphinurlnavigator.cpp index ad0a86b77..280b8b2e1 100644 --- a/src/dolphinurlnavigator.cpp +++ b/src/dolphinurlnavigator.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2020 Felix Ernst + SPDX-FileCopyrightText: 2020 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/dolphinurlnavigator.h b/src/dolphinurlnavigator.h index 572c29f63..93a573105 100644 --- a/src/dolphinurlnavigator.h +++ b/src/dolphinurlnavigator.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2020 Felix Ernst + SPDX-FileCopyrightText: 2020 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/dolphinurlnavigatorscontroller.cpp b/src/dolphinurlnavigatorscontroller.cpp index bdf6513f1..32845710d 100644 --- a/src/dolphinurlnavigatorscontroller.cpp +++ b/src/dolphinurlnavigatorscontroller.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2020 Felix Ernst + SPDX-FileCopyrightText: 2020 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/dolphinurlnavigatorscontroller.h b/src/dolphinurlnavigatorscontroller.h index fec15f481..8e9cf562d 100644 --- a/src/dolphinurlnavigatorscontroller.h +++ b/src/dolphinurlnavigatorscontroller.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2020 Felix Ernst + SPDX-FileCopyrightText: 2020 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/kitemviews/kfileitemlisttostring.cpp b/src/kitemviews/kfileitemlisttostring.cpp index d10680adc..9f281c813 100644 --- a/src/kitemviews/kfileitemlisttostring.cpp +++ b/src/kitemviews/kfileitemlisttostring.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/kitemviews/kfileitemlisttostring.h b/src/kitemviews/kfileitemlisttostring.h index f1c2902b8..1cba1a43c 100644 --- a/src/kitemviews/kfileitemlisttostring.h +++ b/src/kitemviews/kfileitemlisttostring.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/actiontexthelper.cpp b/src/selectionmode/actiontexthelper.cpp index 28a247185..b54e9b004 100644 --- a/src/selectionmode/actiontexthelper.cpp +++ b/src/selectionmode/actiontexthelper.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/actiontexthelper.h b/src/selectionmode/actiontexthelper.h index 6ca99990f..aa6569411 100644 --- a/src/selectionmode/actiontexthelper.h +++ b/src/selectionmode/actiontexthelper.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/actionwithwidget.cpp b/src/selectionmode/actionwithwidget.cpp index 1284912b6..cc407d334 100644 --- a/src/selectionmode/actionwithwidget.cpp +++ b/src/selectionmode/actionwithwidget.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/actionwithwidget.h b/src/selectionmode/actionwithwidget.h index 9b83022de..e56729a6f 100644 --- a/src/selectionmode/actionwithwidget.h +++ b/src/selectionmode/actionwithwidget.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/backgroundcolorhelper.cpp b/src/selectionmode/backgroundcolorhelper.cpp index 1615c36bb..74f5bda1a 100644 --- a/src/selectionmode/backgroundcolorhelper.cpp +++ b/src/selectionmode/backgroundcolorhelper.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/backgroundcolorhelper.h b/src/selectionmode/backgroundcolorhelper.h index 251c5eddf..3450c8e19 100644 --- a/src/selectionmode/backgroundcolorhelper.h +++ b/src/selectionmode/backgroundcolorhelper.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/bottombar.cpp b/src/selectionmode/bottombar.cpp index f39431076..c85286cbb 100644 --- a/src/selectionmode/bottombar.cpp +++ b/src/selectionmode/bottombar.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/bottombar.h b/src/selectionmode/bottombar.h index 3ad361ef6..fd6eaebd9 100644 --- a/src/selectionmode/bottombar.h +++ b/src/selectionmode/bottombar.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/bottombarcontentscontainer.cpp b/src/selectionmode/bottombarcontentscontainer.cpp index 4619bcae0..730471ab0 100644 --- a/src/selectionmode/bottombarcontentscontainer.cpp +++ b/src/selectionmode/bottombarcontentscontainer.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/bottombarcontentscontainer.h b/src/selectionmode/bottombarcontentscontainer.h index 560220258..10e7ba5fd 100644 --- a/src/selectionmode/bottombarcontentscontainer.h +++ b/src/selectionmode/bottombarcontentscontainer.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/singleclickselectionproxystyle.h b/src/selectionmode/singleclickselectionproxystyle.h index a0c1585d5..e0bdc9df2 100644 --- a/src/selectionmode/singleclickselectionproxystyle.h +++ b/src/selectionmode/singleclickselectionproxystyle.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/topbar.cpp b/src/selectionmode/topbar.cpp index 1981be411..d58d10fb4 100644 --- a/src/selectionmode/topbar.cpp +++ b/src/selectionmode/topbar.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/topbar.h b/src/selectionmode/topbar.h index 820af23c6..028fc4985 100644 --- a/src/selectionmode/topbar.h +++ b/src/selectionmode/topbar.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/settings/viewmodes/viewmodesettings.cpp b/src/settings/viewmodes/viewmodesettings.cpp index 0cfc0634d..504ec12e7 100644 --- a/src/settings/viewmodes/viewmodesettings.cpp +++ b/src/settings/viewmodes/viewmodesettings.cpp @@ -1,6 +1,6 @@ /* * SPDX-FileCopyrightText: 2011 Peter Penz - * SPDX-FileCopyrightText: 2021 Felix Ernst + * SPDX-FileCopyrightText: 2021 Felix Ernst * * SPDX-License-Identifier: GPL-2.0-or-later */ -- cgit v1.3 From 3338c2834af81e00c3f2b73ad7061fefce89f226 Mon Sep 17 00:00:00 2001 From: Méven Car Date: Tue, 13 Jun 2023 09:40:27 +0000 Subject: Settings Add ViewModes > Content display This does not move the settings location in files though. baby step for https://invent.kde.org/system/dolphin/-/issues/36 --- src/CMakeLists.txt | 6 + src/dolphinviewcontainer.cpp | 11 +- src/kitemviews/kfileitemlistwidget.cpp | 14 +- src/kitemviews/kfileitemmodel.cpp | 8 +- src/kitemviews/kfileitemmodelrolesupdater.cpp | 5 +- src/kitemviews/kitemlistwidget.cpp | 2 +- .../private/kdirectorycontentscounter.cpp | 4 +- src/kitemviews/private/kdirectorycontentscounter.h | 2 +- src/settings/dolphin_contentdisplaysettings.kcfg | 31 +++++ src/settings/dolphin_contentdisplaysettings.kcfgc | 4 + src/settings/dolphin_detailsmodesettings.kcfg | 21 --- src/settings/dolphin_detailsmodesettings.upd | 11 +- src/settings/viewmodes/contentdisplaytab.cpp | 148 +++++++++++++++++++++ src/settings/viewmodes/contentdisplaytab.h | 39 ++++++ src/settings/viewmodes/viewsettingspage.cpp | 23 +++- src/settings/viewmodes/viewsettingspage.h | 4 + src/settings/viewmodes/viewsettingstab.cpp | 129 ++---------------- src/settings/viewmodes/viewsettingstab.h | 8 -- src/views/dolphinitemlistview.cpp | 3 + src/views/dolphinview.h | 5 +- 20 files changed, 305 insertions(+), 173 deletions(-) create mode 100644 src/settings/dolphin_contentdisplaysettings.kcfg create mode 100644 src/settings/dolphin_contentdisplaysettings.kcfgc create mode 100644 src/settings/viewmodes/contentdisplaytab.cpp create mode 100644 src/settings/viewmodes/contentdisplaytab.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 97bc770d7..62c70ba79 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -183,6 +183,7 @@ kconfig_add_kcfg_files(dolphinprivate settings/dolphin_directoryviewpropertysettings.kcfgc settings/dolphin_detailsmodesettings.kcfgc settings/dolphin_iconsmodesettings.kcfgc + settings/dolphin_contentdisplaysettings.kcfgc settings/dolphin_generalsettings.kcfgc settings/dolphin_contextmenusettings.kcfgc settings/dolphin_versioncontrolsettings.kcfgc @@ -305,6 +306,7 @@ target_sources(dolphinstatic PRIVATE settings/viewmodes/viewsettingspage.cpp settings/viewmodes/viewmodesettings.cpp settings/viewmodes/viewsettingstab.cpp + settings/viewmodes/contentdisplaytab.cpp statusbar/dolphinstatusbar.cpp statusbar/mountpointobserver.cpp statusbar/mountpointobservercache.cpp @@ -364,6 +366,7 @@ target_sources(dolphinstatic PRIVATE settings/viewmodes/viewsettingspage.h settings/viewmodes/viewmodesettings.h settings/viewmodes/viewsettingstab.h + settings/viewmodes/contentdisplaytab.h statusbar/dolphinstatusbar.h statusbar/mountpointobserver.h statusbar/mountpointobservercache.h @@ -408,6 +411,7 @@ kconfig_add_kcfg_files(dolphinstatic settings/dolphin_detailsmodesettings.kcfgc settings/dolphin_contextmenusettings.kcfgc settings/dolphin_iconsmodesettings.kcfgc + settings/dolphin_contentdisplaysettings.kcfgc search/dolphin_searchsettings.kcfgc settings/dolphin_versioncontrolsettings.kcfgc ) @@ -544,6 +548,7 @@ if(NOT WIN32) settings/dolphin_directoryviewpropertysettings.kcfgc settings/dolphin_detailsmodesettings.kcfgc settings/dolphin_iconsmodesettings.kcfgc + settings/dolphin_contentdisplaysettings.kcfgc settings/dolphin_generalsettings.kcfgc settings/dolphin_versioncontrolsettings.kcfgc ) @@ -586,6 +591,7 @@ install( FILES settings/dolphin_directoryviewpropertysettings.kcfg settings/dolphin_compactmodesettings.kcfg settings/dolphin_iconsmodesettings.kcfg settings/dolphin_detailsmodesettings.kcfg + settings/dolphin_contentdisplaysettings.kcfg settings/dolphin_versioncontrolsettings.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR} ) diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp index 2dc366129..8627891c0 100644 --- a/src/dolphinviewcontainer.cpp +++ b/src/dolphinviewcontainer.cpp @@ -6,8 +6,11 @@ #include "dolphinviewcontainer.h" +#include "dolphin_compactmodesettings.h" +#include "dolphin_contentdisplaysettings.h" #include "dolphin_detailsmodesettings.h" #include "dolphin_generalsettings.h" +#include "dolphin_iconsmodesettings.h" #include "dolphindebug.h" #include "dolphinplacesmodelsingleton.h" #include "filterbar/filterbar.h" @@ -176,11 +179,9 @@ DolphinViewContainer::DolphinViewContainer(const QUrl &url, QWidget *parent) setSearchModeEnabled(isSearchUrl(url)); - connect(DetailsModeSettings::self(), &KCoreConfigSkeleton::configChanged, this, [=]() { - if (view()->viewMode() == DolphinView::Mode::DetailsView) { - view()->reload(); - } - }); + // Update view as the ContentDisplaySettings change + // this happens here and not in DolphinView as DolphinviewContainer and DolphinView are not in the same build target ATM + connect(ContentDisplaySettings::self(), &KCoreConfigSkeleton::configChanged, m_view, &DolphinView::reload); KFilePlacesModel *placesModel = DolphinPlacesModelSingleton::instance().placesModel(); connect(placesModel, &KFilePlacesModel::dataChanged, this, &DolphinViewContainer::slotPlacesModelChanged); diff --git a/src/kitemviews/kfileitemlistwidget.cpp b/src/kitemviews/kfileitemlistwidget.cpp index ec8683345..385067af0 100644 --- a/src/kitemviews/kfileitemlistwidget.cpp +++ b/src/kitemviews/kfileitemlistwidget.cpp @@ -9,7 +9,7 @@ #include "kfileitemmodel.h" #include "kitemlistview.h" -#include "dolphin_detailsmodesettings.h" +#include "dolphin_contentdisplaysettings.h" #include #include @@ -56,7 +56,7 @@ QString KFileItemListWidgetInformant::roleText(const QByteArray &role, const QHa // use a hash + switch for a linear runtime. auto formatDate = [formatter, local](const QDateTime &time) { - if (DetailsModeSettings::useShortRelativeDates()) { + if (ContentDisplaySettings::useShortRelativeDates()) { return formatter.formatRelativeDateTime(time, QLocale::ShortFormat); } else { return local.toString(time, QLocale::ShortFormat); @@ -67,7 +67,7 @@ QString KFileItemListWidgetInformant::roleText(const QByteArray &role, const QHa if (values.value("isDir").toBool()) { if (!roleValue.isNull() && roleValue != -1) { // The item represents a directory. - if (DetailsModeSettings::directorySizeCount() || roleValue == -2 /* size is invalid */) { + if (ContentDisplaySettings::directorySizeCount() || roleValue == -2 /* size is invalid */) { // Show the number of sub directories instead of the file size of the directory. const int count = values.value("count").toInt(); text = i18ncp("@item:intable", "%1 item", "%1 items", count); @@ -101,14 +101,14 @@ QString KFileItemListWidgetInformant::roleText(const QByteArray &role, const QHa } else if (role == "permissions") { const auto permissions = roleValue.value(); - switch (DetailsModeSettings::usePermissionsFormat()) { - case DetailsModeSettings::EnumUsePermissionsFormat::SymbolicFormat: + switch (ContentDisplaySettings::usePermissionsFormat()) { + case ContentDisplaySettings::EnumUsePermissionsFormat::SymbolicFormat: text = permissions.at(0).toString(); break; - case DetailsModeSettings::EnumUsePermissionsFormat::NumericFormat: + case ContentDisplaySettings::EnumUsePermissionsFormat::NumericFormat: text = QString::number(permissions.at(1).toInt(), 8); break; - case DetailsModeSettings::EnumUsePermissionsFormat::CombinedFormat: + case ContentDisplaySettings::EnumUsePermissionsFormat::CombinedFormat: text = QString("%1 (%2)").arg(permissions.at(0).toString()).arg(permissions.at(1).toInt(), 0, 8); break; } diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp index 6617fbec6..5ac6f9be1 100644 --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -8,7 +8,7 @@ #include "kfileitemmodel.h" -#include "dolphin_detailsmodesettings.h" +#include "dolphin_contentdisplaysettings.h" #include "dolphin_generalsettings.h" #include "dolphindebug.h" #include "private/kfileitemmodelsortalgorithm.h" @@ -1991,7 +1991,7 @@ bool KFileItemModel::lessThan(const ItemData *a, const ItemData *b, const QColla } } - if (m_sortDirsFirst || (DetailsModeSettings::directorySizeCount() && m_sortRole == SizeRole)) { + if (m_sortDirsFirst || (ContentDisplaySettings::directorySizeCount() && m_sortRole == SizeRole)) { const bool isDirA = a->item.isDir(); const bool isDirB = b->item.isDir(); if (isDirA && !isDirB) { @@ -2043,7 +2043,7 @@ int KFileItemModel::sortRoleCompare(const ItemData *a, const ItemData *b, const break; case SizeRole: { - if (DetailsModeSettings::directorySizeCount() && itemA.isDir()) { + if (ContentDisplaySettings::directorySizeCount() && itemA.isDir()) { // folders first then // items A and B are folders thanks to lessThan checks auto valueA = a->values.value("count"); @@ -2303,7 +2303,7 @@ QList> KFileItemModel::sizeRoleGroups() const KIO::filesize_t fileSize = !item.isNull() ? item.size() : ~0U; QString newGroupValue; if (!item.isNull() && item.isDir()) { - if (DetailsModeSettings::directorySizeCount() || m_sortDirsFirst) { + if (ContentDisplaySettings::directorySizeCount() || m_sortDirsFirst) { newGroupValue = i18nc("@title:group Size", "Folders"); } else { fileSize = m_itemData.at(i)->values.value("size").toULongLong(); diff --git a/src/kitemviews/kfileitemmodelrolesupdater.cpp b/src/kitemviews/kfileitemmodelrolesupdater.cpp index 6838d0861..9d8ae55da 100644 --- a/src/kitemviews/kfileitemmodelrolesupdater.cpp +++ b/src/kitemviews/kfileitemmodelrolesupdater.cpp @@ -10,7 +10,6 @@ #include "kfileitemmodel.h" #include "private/kdirectorycontentscounter.h" #include "private/kpixmapmodifier.h" -#include "qdir.h" #include #include @@ -21,7 +20,7 @@ #include #include -#include "dolphin_detailsmodesettings.h" +#include "dolphin_contentdisplaysettings.h" #if HAVE_BALOO #include "private/kbaloorolesprovider.h" @@ -1269,7 +1268,7 @@ bool KFileItemModelRolesUpdater::applyResolvedRoles(int index, ResolveHint hint) void KFileItemModelRolesUpdater::startDirectorySizeCounting(const KFileItem &item, int index) { - if (DetailsModeSettings::directorySizeCount() || item.isSlow() || !item.isLocalFile()) { + if (ContentDisplaySettings::directorySizeCount() || item.isSlow() || !item.isLocalFile()) { // fastpath no recursion necessary auto data = m_model->data(index); diff --git a/src/kitemviews/kitemlistwidget.cpp b/src/kitemviews/kitemlistwidget.cpp index 1d6b9641a..2c8ef70a5 100644 --- a/src/kitemviews/kitemlistwidget.cpp +++ b/src/kitemviews/kitemlistwidget.cpp @@ -40,6 +40,7 @@ KItemListWidget::KItemListWidget(KItemListWidgetInformant *informant, QGraphicsI , m_data() , m_visibleRoles() , m_columnWidths() + , m_sidePadding(0) , m_styleOption() , m_siblingsInfo() , m_hoverOpacity(0) @@ -49,7 +50,6 @@ KItemListWidget::KItemListWidget(KItemListWidgetInformant *informant, QGraphicsI , m_selectionToggle(nullptr) , m_editedRole() , m_iconSize(-1) - , m_sidePadding(0) { connect(&m_hoverSequenceTimer, &QTimer::timeout, this, &KItemListWidget::slotHoverSequenceTimerTimeout); } diff --git a/src/kitemviews/private/kdirectorycontentscounter.cpp b/src/kitemviews/private/kdirectorycontentscounter.cpp index e1a47419d..648b20b6f 100644 --- a/src/kitemviews/private/kdirectorycontentscounter.cpp +++ b/src/kitemviews/private/kdirectorycontentscounter.cpp @@ -6,7 +6,7 @@ */ #include "kdirectorycontentscounter.h" -#include "dolphin_detailsmodesettings.h" +#include "dolphin_contentdisplaysettings.h" #include "kitemviews/kfileitemmodel.h" #include @@ -224,7 +224,7 @@ void KDirectoryContentsCounter::scheduleNext() } m_workerIsBusy = true; - Q_EMIT requestDirectoryContentsCount(m_currentPath, options, DetailsModeSettings::recursiveDirectorySizeLimit()); + Q_EMIT requestDirectoryContentsCount(m_currentPath, options, ContentDisplaySettings::recursiveDirectorySizeLimit()); } void KDirectoryContentsCounter::enqueuePathScanning(const QString &path, bool alreadyInCache, PathCountPriority priority) diff --git a/src/kitemviews/private/kdirectorycontentscounter.h b/src/kitemviews/private/kdirectorycontentscounter.h index 552b5560e..0da3ccd7d 100644 --- a/src/kitemviews/private/kdirectorycontentscounter.h +++ b/src/kitemviews/private/kdirectorycontentscounter.h @@ -47,7 +47,7 @@ public: Q_SIGNALS: /** * Signals that the directory \a path contains \a count items of size \a - * Size calculation depends on parameter DetailsModeSettings::recursiveDirectorySizeLimit + * Size calculation depends on parameter ContentDisplaySettings::recursiveDirectorySizeLimit */ void result(const QString &path, int count, long long size); diff --git a/src/settings/dolphin_contentdisplaysettings.kcfg b/src/settings/dolphin_contentdisplaysettings.kcfg new file mode 100644 index 000000000..36895b869 --- /dev/null +++ b/src/settings/dolphin_contentdisplaysettings.kcfg @@ -0,0 +1,31 @@ + + + + + + + + true + + + + 10 + + + + true + + + + + + + + + 0 + + + diff --git a/src/settings/dolphin_contentdisplaysettings.kcfgc b/src/settings/dolphin_contentdisplaysettings.kcfgc new file mode 100644 index 000000000..c986578b2 --- /dev/null +++ b/src/settings/dolphin_contentdisplaysettings.kcfgc @@ -0,0 +1,4 @@ +File=dolphin_contentdisplaysettings.kcfg +ClassName=ContentDisplaySettings +Singleton=yes +Mutators=true diff --git a/src/settings/dolphin_detailsmodesettings.kcfg b/src/settings/dolphin_detailsmodesettings.kcfg index 9efdebe71..98fe0efff 100644 --- a/src/settings/dolphin_detailsmodesettings.kcfg +++ b/src/settings/dolphin_detailsmodesettings.kcfg @@ -39,26 +39,5 @@ true - - - true - - - - 10 - - - - true - - - - - - - - - 0 - diff --git a/src/settings/dolphin_detailsmodesettings.upd b/src/settings/dolphin_detailsmodesettings.upd index 091fee52c..da8f4b9cd 100644 --- a/src/settings/dolphin_detailsmodesettings.upd +++ b/src/settings/dolphin_detailsmodesettings.upd @@ -5,4 +5,13 @@ Version=5 Id=rename-leading-padding File=dolphinrc Group=DetailsMode -Key=LeadingPadding,SidePadding \ No newline at end of file +Key=LeadingPadding,SidePadding + +#Rename Move content-display from detailsMode +Id=move-content-display +File=dolphinrc +Group=DetailsMode,ContentDisplay +Key=DirectorySizeCount +Key=RecursiveDirectorySizeLimit +Key=UseShortRelativeDates +Key=UsePermissionsFormat diff --git a/src/settings/viewmodes/contentdisplaytab.cpp b/src/settings/viewmodes/contentdisplaytab.cpp new file mode 100644 index 000000000..442bd3b49 --- /dev/null +++ b/src/settings/viewmodes/contentdisplaytab.cpp @@ -0,0 +1,148 @@ +/* + * SPDX-FileCopyrightText: 2023 Méven Car + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "contentdisplaytab.h" +#include "dolphin_contentdisplaysettings.h" + +#include +#include + +#include +#include +#include +#include +#include + +ContentDisplayTab::ContentDisplayTab(QWidget *parent) + : SettingsPageBase(parent) + , m_numberOfItems(nullptr) + , m_sizeOfContents(nullptr) + , m_recursiveDirectorySizeLimit(nullptr) + , m_useRelatetiveDates(nullptr) + , m_useShortDates(nullptr) + , m_useSymbolicPermissions(nullptr) + , m_useNumericPermissions(nullptr) + , m_useCombinedPermissions(nullptr) +{ + QFormLayout *topLayout = new QFormLayout(this); + +#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, &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 + + QDateTime thirtyMinutesAgo = QDateTime::currentDateTime().addSecs(-30 * 60); + QLocale local; + KFormat formatter(local); + + m_useRelatetiveDates = new QRadioButton( + i18nc("option:radio as in relative date", "Relative (e.g. '%1')", formatter.formatRelativeDateTime(thirtyMinutesAgo, QLocale::ShortFormat))); + m_useShortDates = + new QRadioButton(i18nc("option:radio as in absolute date", "Absolute (e.g. '%1')", local.toString(thirtyMinutesAgo, QLocale::ShortFormat))); + + QButtonGroup *dateFormatGroup = new QButtonGroup(this); + dateFormatGroup->addButton(m_useRelatetiveDates); + dateFormatGroup->addButton(m_useShortDates); + + topLayout->addRow(i18nc("@title:group", "Date style:"), m_useRelatetiveDates); + topLayout->addRow(QString(), m_useShortDates); + + m_useSymbolicPermissions = new QRadioButton(i18nc("option:radio as symbolic style ", "Symbolic (e.g. 'drwxr-xr-x')")); + m_useNumericPermissions = new QRadioButton(i18nc("option:radio as numeric style", "Numeric (Octal) (e.g. '755')")); + m_useCombinedPermissions = new QRadioButton(i18nc("option:radio as combined style", "Combined (e.g. 'drwxr-xr-x (755)')")); + + topLayout->addRow(i18nc("@title:group", "Permissions style:"), m_useSymbolicPermissions); + topLayout->addRow(QString(), m_useNumericPermissions); + topLayout->addRow(QString(), m_useCombinedPermissions); + + QButtonGroup *permissionsFormatGroup = new QButtonGroup(this); + permissionsFormatGroup->addButton(m_useSymbolicPermissions); + permissionsFormatGroup->addButton(m_useNumericPermissions); + permissionsFormatGroup->addButton(m_useCombinedPermissions); + +#ifndef Q_OS_WIN + connect(m_recursiveDirectorySizeLimit, &QSpinBox::valueChanged, this, &SettingsPageBase::changed); + connect(m_numberOfItems, &QRadioButton::toggled, this, &SettingsPageBase::changed); + connect(m_sizeOfContents, &QRadioButton::toggled, this, [=]() { + m_recursiveDirectorySizeLimit->setEnabled(m_sizeOfContents->isChecked()); + }); +#endif + + connect(m_useRelatetiveDates, &QRadioButton::toggled, this, &SettingsPageBase::changed); + connect(m_useShortDates, &QRadioButton::toggled, this, &SettingsPageBase::changed); + connect(m_useSymbolicPermissions, &QRadioButton::toggled, this, &SettingsPageBase::changed); + connect(m_useNumericPermissions, &QRadioButton::toggled, this, &SettingsPageBase::changed); + connect(m_useCombinedPermissions, &QRadioButton::toggled, this, &SettingsPageBase::changed); + + loadSettings(); +} + +void ContentDisplayTab::applySettings() +{ + auto settings = ContentDisplaySettings::self(); +#ifndef Q_OS_WIN + settings->setDirectorySizeCount(m_numberOfItems->isChecked()); + settings->setRecursiveDirectorySizeLimit(m_recursiveDirectorySizeLimit->value()); +#endif + + settings->setUseShortRelativeDates(m_useRelatetiveDates->isChecked()); + + if (m_useSymbolicPermissions->isChecked()) { + settings->setUsePermissionsFormat(ContentDisplaySettings::EnumUsePermissionsFormat::SymbolicFormat); + } else if (m_useNumericPermissions->isChecked()) { + settings->setUsePermissionsFormat(ContentDisplaySettings::EnumUsePermissionsFormat::NumericFormat); + } else if (m_useCombinedPermissions->isChecked()) { + settings->setUsePermissionsFormat(ContentDisplaySettings::EnumUsePermissionsFormat::CombinedFormat); + } + settings->save(); +} + +void ContentDisplayTab::loadSettings() +{ + auto settings = ContentDisplaySettings::self(); +#ifndef Q_OS_WIN + if (settings->directorySizeCount()) { + m_numberOfItems->setChecked(true); + m_recursiveDirectorySizeLimit->setEnabled(false); + } else { + m_sizeOfContents->setChecked(true); + m_recursiveDirectorySizeLimit->setEnabled(true); + } + m_recursiveDirectorySizeLimit->setValue(settings->recursiveDirectorySizeLimit()); +#endif + m_useRelatetiveDates->setChecked(settings->useShortRelativeDates()); + m_useShortDates->setChecked(!settings->useShortRelativeDates()); + m_useSymbolicPermissions->setChecked(settings->usePermissionsFormat() == ContentDisplaySettings::EnumUsePermissionsFormat::SymbolicFormat); + m_useNumericPermissions->setChecked(settings->usePermissionsFormat() == ContentDisplaySettings::EnumUsePermissionsFormat::NumericFormat); + m_useCombinedPermissions->setChecked(settings->usePermissionsFormat() == ContentDisplaySettings::EnumUsePermissionsFormat::CombinedFormat); +} + +void ContentDisplayTab::restoreDefaults() +{ + auto settings = ContentDisplaySettings::self(); + settings->useDefaults(true); + loadSettings(); + settings->useDefaults(false); +} diff --git a/src/settings/viewmodes/contentdisplaytab.h b/src/settings/viewmodes/contentdisplaytab.h new file mode 100644 index 000000000..5484bf413 --- /dev/null +++ b/src/settings/viewmodes/contentdisplaytab.h @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: 2023 Méven Car + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef GENERALTAB_H +#define GENERALTAB_H + +#include "settings/settingspagebase.h" + +class QRadioButton; +class QSpinBox; + +class ContentDisplayTab : public SettingsPageBase +{ + Q_OBJECT + +public: + ContentDisplayTab(QWidget *parent); + +public: + // SettingsPageBase interface + void applySettings() override; + void restoreDefaults() override; + +private: + void loadSettings(); + + QRadioButton *m_numberOfItems; + QRadioButton *m_sizeOfContents; + QSpinBox *m_recursiveDirectorySizeLimit; + QRadioButton *m_useRelatetiveDates; + QRadioButton *m_useShortDates; + QRadioButton *m_useSymbolicPermissions; + QRadioButton *m_useNumericPermissions; + QRadioButton *m_useCombinedPermissions; +}; + +#endif // GENERALTAB_H diff --git a/src/settings/viewmodes/viewsettingspage.cpp b/src/settings/viewmodes/viewsettingspage.cpp index cb0b5ecee..33409ec25 100644 --- a/src/settings/viewmodes/viewsettingspage.cpp +++ b/src/settings/viewmodes/viewsettingspage.cpp @@ -6,7 +6,7 @@ #include "viewsettingspage.h" -#include "views/dolphinview.h" +#include "contentdisplaytab.h" #include "viewsettingstab.h" #include @@ -21,7 +21,14 @@ ViewSettingsPage::ViewSettingsPage(QWidget *parent) QVBoxLayout *topLayout = new QVBoxLayout(this); topLayout->setContentsMargins(0, 0, 0, 0); - QTabWidget *tabWidget = new QTabWidget(this); + tabWidget = new QTabWidget(this); + + // Content Display Tab + contentDisplayTab = new ContentDisplayTab(tabWidget); + tabWidget->addTab(contentDisplayTab, + QIcon::fromTheme(QStringLiteral("view-choose")), + i18nc("@title:tab how file items columns are displayed", "Content Display")); + connect(contentDisplayTab, &SettingsPageBase::changed, this, &ViewSettingsPage::changed); // Initialize 'Icons' tab ViewSettingsTab *iconsTab = new ViewSettingsTab(ViewSettingsTab::IconsMode, tabWidget); @@ -51,6 +58,8 @@ ViewSettingsPage::~ViewSettingsPage() void ViewSettingsPage::applySettings() { + contentDisplayTab->applySettings(); + for (ViewSettingsTab *tab : qAsConst(m_tabs)) { tab->applySettings(); } @@ -58,7 +67,15 @@ void ViewSettingsPage::applySettings() void ViewSettingsPage::restoreDefaults() { + if (tabWidget->currentWidget() == contentDisplayTab) { + contentDisplayTab->restoreDefaults(); + return; + } + for (ViewSettingsTab *tab : qAsConst(m_tabs)) { - tab->restoreDefaultSettings(); + if (tabWidget->currentWidget() == tab) { + tab->restoreDefaultSettings(); + return; + } } } diff --git a/src/settings/viewmodes/viewsettingspage.h b/src/settings/viewmodes/viewsettingspage.h index 797c0b712..e52f6b2c0 100644 --- a/src/settings/viewmodes/viewsettingspage.h +++ b/src/settings/viewmodes/viewsettingspage.h @@ -10,6 +10,8 @@ class ViewSettingsTab; class QWidget; +class ContentDisplayTab; +class QTabWidget; /** * @brief Page for the 'View' settings of the Dolphin settings dialog. @@ -32,6 +34,8 @@ public: void restoreDefaults() override; private: + ContentDisplayTab *contentDisplayTab; + QTabWidget *tabWidget; QList m_tabs; }; diff --git a/src/settings/viewmodes/viewsettingstab.cpp b/src/settings/viewmodes/viewsettingstab.cpp index 1d4c5f5d5..df850e530 100644 --- a/src/settings/viewmodes/viewsettingstab.cpp +++ b/src/settings/viewmodes/viewsettingstab.cpp @@ -14,7 +14,6 @@ #include "settings/viewmodes/viewmodesettings.h" #include "views/zoomlevelinfo.h" -#include #include #include @@ -35,12 +34,6 @@ ViewSettingsTab::ViewSettingsTab(Mode mode, QWidget *parent) , m_widthBox(nullptr) , m_maxLinesBox(nullptr) , m_expandableFolders(nullptr) - , m_recursiveDirectorySizeLimit(nullptr) - , m_useRelatetiveDates(nullptr) - , m_useShortDates(nullptr) - , m_useSymbolicPermissions(nullptr) - , m_useNumericPermissions(nullptr) - , m_useCombinedPermissions(nullptr) { QFormLayout *topLayout = new QFormLayout(this); @@ -113,61 +106,6 @@ ViewSettingsTab::ViewSettingsTab(Mode mode, QWidget *parent) topLayout->addRow(i18nc("@title:group", "Open files and folders:"), m_entireRow); // clang-format on topLayout->addRow(QString(), m_iconAndNameOnly); - -#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, &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 - - QDateTime thirtyMinutesAgo = QDateTime::currentDateTime().addSecs(-30 * 60); - QLocale local; - KFormat formatter(local); - - m_useRelatetiveDates = new QRadioButton( - i18nc("option:radio as in relative date", "Relative (e.g. '%1')", formatter.formatRelativeDateTime(thirtyMinutesAgo, QLocale::ShortFormat))); - m_useShortDates = - new QRadioButton(i18nc("option:radio as in absolute date", "Absolute (e.g. '%1')", local.toString(thirtyMinutesAgo, QLocale::ShortFormat))); - - QButtonGroup *dateFormatGroup = new QButtonGroup(this); - dateFormatGroup->addButton(m_useRelatetiveDates); - dateFormatGroup->addButton(m_useShortDates); - - topLayout->addRow(i18nc("@title:group", "Date style:"), m_useRelatetiveDates); - topLayout->addRow(QString(), m_useShortDates); - - m_useSymbolicPermissions = new QRadioButton(i18nc("option:radio as symbolic style ", "Symbolic (e.g. 'drwxr-xr-x')")); - - m_useNumericPermissions = new QRadioButton(i18nc("option:radio as numeric style", "Numeric (Octal) (e.g. '755')")); - - m_useCombinedPermissions = new QRadioButton(i18nc("option:radio as combined style", "Combined (e.g. 'drwxr-xr-x (755)')")); - - topLayout->addRow(i18nc("@title:group", "Permissions style:"), m_useSymbolicPermissions); - topLayout->addRow(QString(), m_useNumericPermissions); - topLayout->addRow(QString(), m_useCombinedPermissions); - - QButtonGroup *permissionsFormatGroup = new QButtonGroup(this); - permissionsFormatGroup->addButton(m_useSymbolicPermissions); - permissionsFormatGroup->addButton(m_useNumericPermissions); - permissionsFormatGroup->addButton(m_useCombinedPermissions); break; } @@ -188,18 +126,6 @@ ViewSettingsTab::ViewSettingsTab(Mode mode, QWidget *parent) case DetailsMode: connect(m_entireRow, &QCheckBox::toggled, this, &ViewSettingsTab::changed); connect(m_expandableFolders, &QCheckBox::toggled, this, &ViewSettingsTab::changed); -#ifndef Q_OS_WIN - connect(m_recursiveDirectorySizeLimit, &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()); - }); -#endif - connect(m_useRelatetiveDates, &QRadioButton::toggled, this, &ViewSettingsTab::changed); - connect(m_useShortDates, &QRadioButton::toggled, this, &ViewSettingsTab::changed); - connect(m_useSymbolicPermissions, &QRadioButton::toggled, this, &ViewSettingsTab::changed); - connect(m_useNumericPermissions, &QRadioButton::toggled, this, &ViewSettingsTab::changed); - connect(m_useCombinedPermissions, &QRadioButton::toggled, this, &ViewSettingsTab::changed); break; default: break; @@ -212,50 +138,35 @@ ViewSettingsTab::~ViewSettingsTab() void ViewSettingsTab::applySettings() { - const QFont font = m_fontRequester->currentFont(); - const bool useSystemFont = (m_fontRequester->mode() == DolphinFontRequester::SystemFont); - switch (m_mode) { case IconsMode: IconsModeSettings::setTextWidthIndex(m_widthBox->currentIndex()); IconsModeSettings::setMaximumTextLines(m_maxLinesBox->currentIndex()); + IconsModeSettings::self()->save(); break; case CompactMode: CompactModeSettings::setMaximumTextWidthIndex(m_widthBox->currentIndex()); + CompactModeSettings::self()->save(); break; case DetailsMode: + auto detailsModeSettings = DetailsModeSettings::self(); // We need side-padding when the full row is a click target to still be able to not click items. // So here the default padding is enabled when the full row highlight is enabled. - if (m_entireRow->isChecked() && !DetailsModeSettings::highlightEntireRow()) { - auto detailsModeSettings = DetailsModeSettings::self(); + if (m_entireRow->isChecked() && !detailsModeSettings->highlightEntireRow()) { const bool usedDefaults = detailsModeSettings->useDefaults(true); const uint defaultSidePadding = detailsModeSettings->sidePadding(); detailsModeSettings->useDefaults(usedDefaults); - if (DetailsModeSettings::sidePadding() < defaultSidePadding) { - DetailsModeSettings::setSidePadding(defaultSidePadding); + if (detailsModeSettings->sidePadding() < defaultSidePadding) { + detailsModeSettings->setSidePadding(defaultSidePadding); } - } else if (!m_entireRow->isChecked() && DetailsModeSettings::highlightEntireRow()) { + } else if (!m_entireRow->isChecked() && detailsModeSettings->highlightEntireRow()) { // The full row click target is disabled so now most of the view area can be used to interact // with the view background. Having an extra side padding has no usability benefit in this case. - DetailsModeSettings::setSidePadding(0); - } - DetailsModeSettings::setHighlightEntireRow(m_entireRow->isChecked()); - DetailsModeSettings::setExpandableFolders(m_expandableFolders->isChecked()); -#ifndef Q_OS_WIN - DetailsModeSettings::setDirectorySizeCount(m_numberOfItems->isChecked()); - DetailsModeSettings::setRecursiveDirectorySizeLimit(m_recursiveDirectorySizeLimit->value()); -#endif - DetailsModeSettings::setUseShortRelativeDates(m_useRelatetiveDates->isChecked()); - - if (m_useSymbolicPermissions->isChecked()) { - DetailsModeSettings::setUsePermissionsFormat(DetailsModeSettings::EnumUsePermissionsFormat::SymbolicFormat); - } else if (m_useNumericPermissions->isChecked()) { - DetailsModeSettings::setUsePermissionsFormat(DetailsModeSettings::EnumUsePermissionsFormat::NumericFormat); - } else if (m_useCombinedPermissions->isChecked()) { - DetailsModeSettings::setUsePermissionsFormat(DetailsModeSettings::EnumUsePermissionsFormat::CombinedFormat); + detailsModeSettings->setSidePadding(0); } - break; - default: + detailsModeSettings->setHighlightEntireRow(m_entireRow->isChecked()); + detailsModeSettings->setExpandableFolders(m_expandableFolders->isChecked()); + detailsModeSettings->save(); break; } @@ -266,6 +177,9 @@ void ViewSettingsTab::applySettings() settings.setIconSize(iconSize); settings.setPreviewSize(previewSize); + const QFont font = m_fontRequester->currentFont(); + const bool useSystemFont = (m_fontRequester->mode() == DolphinFontRequester::SystemFont); + settings.setUseSystemFont(useSystemFont); settings.setViewFont(font); @@ -294,21 +208,6 @@ void ViewSettingsTab::loadSettings() m_entireRow->setChecked(DetailsModeSettings::highlightEntireRow()); m_iconAndNameOnly->setChecked(!m_entireRow->isChecked()); m_expandableFolders->setChecked(DetailsModeSettings::expandableFolders()); -#ifndef Q_OS_WIN - 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()); -#endif - m_useRelatetiveDates->setChecked(DetailsModeSettings::useShortRelativeDates()); - m_useShortDates->setChecked(!DetailsModeSettings::useShortRelativeDates()); - m_useSymbolicPermissions->setChecked(DetailsModeSettings::usePermissionsFormat() == DetailsModeSettings::EnumUsePermissionsFormat::SymbolicFormat); - m_useNumericPermissions->setChecked(DetailsModeSettings::usePermissionsFormat() == DetailsModeSettings::EnumUsePermissionsFormat::NumericFormat); - m_useCombinedPermissions->setChecked(DetailsModeSettings::usePermissionsFormat() == DetailsModeSettings::EnumUsePermissionsFormat::CombinedFormat); break; default: break; diff --git a/src/settings/viewmodes/viewsettingstab.h b/src/settings/viewmodes/viewsettingstab.h index b59fb399e..6be8fc3b5 100644 --- a/src/settings/viewmodes/viewsettingstab.h +++ b/src/settings/viewmodes/viewsettingstab.h @@ -55,14 +55,6 @@ private: QRadioButton *m_entireRow; QRadioButton *m_iconAndNameOnly; QCheckBox *m_expandableFolders; - QRadioButton *m_numberOfItems; - QRadioButton *m_sizeOfContents; - QSpinBox *m_recursiveDirectorySizeLimit; - QRadioButton *m_useRelatetiveDates; - QRadioButton *m_useShortDates; - QRadioButton *m_useSymbolicPermissions; - QRadioButton *m_useNumericPermissions; - QRadioButton *m_useCombinedPermissions; }; #endif diff --git a/src/views/dolphinitemlistview.cpp b/src/views/dolphinitemlistview.cpp index a24e31347..9902f651b 100644 --- a/src/views/dolphinitemlistview.cpp +++ b/src/views/dolphinitemlistview.cpp @@ -7,6 +7,7 @@ #include "dolphinitemlistview.h" #include "dolphin_compactmodesettings.h" +#include "dolphin_contentdisplaysettings.h" #include "dolphin_detailsmodesettings.h" #include "dolphin_generalsettings.h" #include "dolphin_iconsmodesettings.h" @@ -81,6 +82,8 @@ void DolphinItemListView::readSettings() CompactModeSettings::self()->load(); DetailsModeSettings::self()->load(); + ContentDisplaySettings::self()->load(); + beginTransaction(); setEnabledSelectionToggles(m_selectionTogglesEnabled); diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h index 705272308..21ca49c24 100644 --- a/src/views/dolphinview.h +++ b/src/views/dolphinview.h @@ -225,8 +225,6 @@ public: /** Returns the additional information which should be shown for the items. */ QList visibleRoles() const; - void reload(); - /** * Refreshes the view to get synchronized with the settings (e.g. icons size, * font, ...). @@ -347,6 +345,9 @@ public: bool eventFilter(QObject *watched, QEvent *event) override; public Q_SLOTS: + + void reload(); + /** * Changes the directory to \a url. If the current directory is equal to * \a url, nothing will be done (use DolphinView::reload() instead). -- cgit v1.3 From cf14a888ceb97e20506164f33f5bd1b5d2212da1 Mon Sep 17 00:00:00 2001 From: Méven Car Date: Mon, 29 May 2023 09:56:50 +0200 Subject: Tabbar: duplicate tab when double clicking on it BUG: 470388 --- src/dolphintabbar.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/dolphintabbar.cpp b/src/dolphintabbar.cpp index 82695ac21..c04b34954 100644 --- a/src/dolphintabbar.cpp +++ b/src/dolphintabbar.cpp @@ -103,14 +103,15 @@ void DolphinTabBar::mouseReleaseEvent(QMouseEvent *event) void DolphinTabBar::mouseDoubleClickEvent(QMouseEvent *event) { - const int index = tabAt(event->pos()); + int index = tabAt(event->pos()); if (index < 0) { - // Double click on the empty tabbar area opens a new activated tab - // with the url from the current tab. - Q_EMIT openNewActivatedTab(currentIndex()); - return; + // empty tabbar area case + index = currentIndex(); } + // Double click on the tabbar opens a new activated tab + // with the url from the doubleclicked tab or currentTab otherwise. + Q_EMIT openNewActivatedTab(index); QTabBar::mouseDoubleClickEvent(event); } -- cgit v1.3 From 51fcd600a8adb235bd510724fb3b8f8df9e0c6b6 Mon Sep 17 00:00:00 2001 From: l10n daemon script Date: Fri, 16 Jun 2023 01:40:55 +0000 Subject: SVN_SILENT made messages (.desktop file) - always resolve ours In case of conflict in i18n, keep the version of the branch "ours" To resolve a particular conflict, "git checkout --ours path/to/file.desktop" --- src/dolphinpartactions.desktop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/dolphinpartactions.desktop b/src/dolphinpartactions.desktop index 9a547f0ca..24ee78f7e 100644 --- a/src/dolphinpartactions.desktop +++ b/src/dolphinpartactions.desktop @@ -97,7 +97,7 @@ Name[ie]=Compact Name[is]=Þétt Name[it]=Compatta Name[ja]=コンパクト -Name[ka]=დაპატარავება +Name[ka]=კომპაქტური Name[ko]=축소됨 Name[lt]=Kompaktiškas Name[lv]=Kompakts -- cgit v1.3 From 7f3967cf38f8ab707681981dd0bc6b220c3dbf83 Mon Sep 17 00:00:00 2001 From: Méven Car Date: Thu, 15 Jun 2023 12:32:00 +0200 Subject: Hide application/x-trash files following showHidenFiles BUG: 3212 --- src/kitemviews/kfileitemmodel.cpp | 40 ++++++++++++++++++++++++- src/kitemviews/kfileitemmodel.h | 6 ++++ src/kitemviews/private/kfileitemmodelfilter.cpp | 32 ++++++++++++++++---- src/kitemviews/private/kfileitemmodelfilter.h | 8 +++++ 4 files changed, 79 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp index 5ac6f9be1..629332703 100644 --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -105,6 +105,8 @@ KFileItemModel::KFileItemModel(QObject *parent) connect(m_resortAllItemsTimer, &QTimer::timeout, this, &KFileItemModel::resortAllItems); connect(GeneralSettings::self(), &GeneralSettings::sortingChoiceChanged, this, &KFileItemModel::slotSortingChoiceChanged); + + setShowTrashMime(m_dirLister->showHiddenFiles()); } KFileItemModel::~KFileItemModel() @@ -238,6 +240,27 @@ bool KFileItemModel::sortHiddenLast() const return m_sortHiddenLast; } +void KFileItemModel::setShowTrashMime(bool show) +{ + const auto trashMime = QStringLiteral("application/x-trash"); + QStringList excludeFilter = m_filter.excludeMimeTypes(); + bool wasShown = !excludeFilter.contains(trashMime); + + if (show) { + if (!wasShown) { + excludeFilter.removeAll(trashMime); + } + } else { + if (wasShown) { + excludeFilter.append(trashMime); + } + } + + if (wasShown != show) { + setExcludeMimeTypeFilter(excludeFilter); + } +} + void KFileItemModel::setShowHiddenFiles(bool show) { #if KIO_VERSION < QT_VERSION_CHECK(5, 100, 0) @@ -245,6 +268,7 @@ void KFileItemModel::setShowHiddenFiles(bool show) #else m_dirLister->setShowHiddenFiles(show); #endif + setShowTrashMime(show); m_dirLister->emitChanges(); if (show) { dispatchPendingItemsToInsert(); @@ -740,6 +764,20 @@ QStringList KFileItemModel::mimeTypeFilters() const return m_filter.mimeTypes(); } +void KFileItemModel::setExcludeMimeTypeFilter(const QStringList &filters) +{ + if (m_filter.excludeMimeTypes() != filters) { + dispatchPendingItemsToInsert(); + m_filter.setExcludeMimeTypes(filters); + applyFilters(); + } +} + +QStringList KFileItemModel::excludeMimeTypeFilter() const +{ + return m_filter.excludeMimeTypes(); +} + void KFileItemModel::applyFilters() { // ===STEP 1=== @@ -1823,7 +1861,7 @@ QHash KFileItemModel::retrieveData(const KFileItem &item, } if (m_requestRole[IsHiddenRole]) { - data.insert(sharedValue("isHidden"), item.isHidden()); + data.insert(sharedValue("isHidden"), item.isHidden() || item.mimetype() == QStringLiteral("application/x-trash")); } if (m_requestRole[NameRole]) { diff --git a/src/kitemviews/kfileitemmodel.h b/src/kitemviews/kfileitemmodel.h index 721569a0c..3c2721d8f 100644 --- a/src/kitemviews/kfileitemmodel.h +++ b/src/kitemviews/kfileitemmodel.h @@ -182,6 +182,9 @@ public: void setMimeTypeFilters(const QStringList &filters); QStringList mimeTypeFilters() const; + void setExcludeMimeTypeFilter(const QStringList &filters); + QStringList excludeMimeTypeFilter() const; + struct RoleInfo { QByteArray role; QString translation; @@ -199,6 +202,9 @@ public: */ static QList rolesInformation(); + /** set to true to hide application/x-trash files */ + void setShowTrashMime(bool show); + Q_SIGNALS: /** * Is emitted if the loading of a directory has been started. It is diff --git a/src/kitemviews/private/kfileitemmodelfilter.cpp b/src/kitemviews/private/kfileitemmodelfilter.cpp index f199c314f..0f9530801 100644 --- a/src/kitemviews/private/kfileitemmodelfilter.cpp +++ b/src/kitemviews/private/kfileitemmodelfilter.cpp @@ -8,6 +8,8 @@ #include +#include + #include KFileItemModelFilter::KFileItemModelFilter() @@ -56,15 +58,25 @@ QStringList KFileItemModelFilter::mimeTypes() const return m_mimeTypes; } +void KFileItemModelFilter::setExcludeMimeTypes(const QStringList &types) +{ + m_excludeMimeTypes = types; +} + +QStringList KFileItemModelFilter::excludeMimeTypes() const +{ + return m_excludeMimeTypes; +} + bool KFileItemModelFilter::hasSetFilters() const { - return (!m_pattern.isEmpty() || !m_mimeTypes.isEmpty()); + return (!m_pattern.isEmpty() || !m_mimeTypes.isEmpty() || !m_excludeMimeTypes.isEmpty()); } bool KFileItemModelFilter::matches(const KFileItem &item) const { const bool hasPatternFilter = !m_pattern.isEmpty(); - const bool hasMimeTypesFilter = !m_mimeTypes.isEmpty(); + const bool hasMimeTypesFilter = !m_mimeTypes.isEmpty() || !m_excludeMimeTypes.isEmpty(); // If no filter is set, return true. if (!hasPatternFilter && !hasMimeTypesFilter) { @@ -95,10 +107,18 @@ bool KFileItemModelFilter::matchesPattern(const KFileItem &item) const bool KFileItemModelFilter::matchesType(const KFileItem &item) const { - for (const QString &mimeType : qAsConst(m_mimeTypes)) { - if (item.mimetype() == mimeType) { - return true; - } + bool excluded = std::any_of(m_excludeMimeTypes.constBegin(), m_excludeMimeTypes.constEnd(), [item](const QString &excludeMimetype) { + return item.mimetype() == excludeMimetype; + }); + if (excluded) { + return false; + } + + bool included = std::any_of(m_mimeTypes.constBegin(), m_mimeTypes.constEnd(), [item](const QString &mimeType) { + return item.mimetype() == mimeType; + }); + if (included) { + return true; } return m_mimeTypes.isEmpty(); diff --git a/src/kitemviews/private/kfileitemmodelfilter.h b/src/kitemviews/private/kfileitemmodelfilter.h index 959590da8..ce6cbeebb 100644 --- a/src/kitemviews/private/kfileitemmodelfilter.h +++ b/src/kitemviews/private/kfileitemmodelfilter.h @@ -44,6 +44,13 @@ public: void setMimeTypes(const QStringList &types); QStringList mimeTypes() const; + /** + * Set the list of mimetypes that are used for comparison and excluded with the + * item in KFileItemModelFilter::matchesMimeType. + */ + void setExcludeMimeTypes(const QStringList &types); + QStringList excludeMimeTypes() const; + /** * @return True if either the pattern or mimetype filters has been set. */ @@ -73,5 +80,6 @@ private: // faster comparison in matches(). QString m_pattern; // Property set by setPattern(). QStringList m_mimeTypes; // Property set by setMimeTypes() + QStringList m_excludeMimeTypes; // Property set by setExcludeMimeTypes() }; #endif -- cgit v1.3 From 2fb1fc1d5c4bd9076d95ef34c414fdd2ce1a0d59 Mon Sep 17 00:00:00 2001 From: l10n daemon script Date: Tue, 20 Jun 2023 00:56:01 +0000 Subject: GIT_SILENT made messages (after extraction) --- src/org.kde.dolphin.appdata.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/org.kde.dolphin.appdata.xml b/src/org.kde.dolphin.appdata.xml index 319e1e46a..e582fde8a 100644 --- a/src/org.kde.dolphin.appdata.xml +++ b/src/org.kde.dolphin.appdata.xml @@ -261,7 +261,7 @@

Dolphin-ek Interneteko hodei-zerbitzu askotako eta urruneko beste makina batzuetako fitxategi eta karpetak zure mahaigainean egongo balira bezala erakuts ditzake.

Dolphin osaa näyttää tiedostot ja kansiot monista internetin pilvipalveluista sekä etäkoneilta kuin ne olisivat välittömästi työpöydälläsi.

Dolphin peut afficher des fichiers et des dossiers à partir de nombreux services de stockage sur Internet (Cloud) et d'ordinateurs distants, comme s'ils étaient directement sur votre ordinateur.

-

Dolphin pode mostrar ficheiros e cartafoles de moitos servizos de nube de internet e outras máquinas remotas como se estivesen no seu escritorio.

+

Dolphin pode amosar ficheiros e cartafoles de moitos servizos de nube de internet e outras máquinas remotas como se estivesen no seu escritorio.

डॉल्फ़िन कई इंटरनेट क्लाउड सेवाओं और अन्य दूरस्थ मशीनों से फ़ाइलें और फ़ोल्डर प्रदर्शित इस प्रकार कर सकता है जैसे कि वे आपके डेस्कटॉप पर ही हैं।

A Dolphin úgy képes fájlokat megjeleníteni számos felhőszolgáltatásból vagy távoli gépekről, mintha azok a saját számítógépén lennének.

Dolphin pote monstrar files e dossieres ab multe servicios cloud de internet e altere machinas remote como si illos esseva exactemente sur tu scriptorio.

-- cgit v1.3 From 7458d21bb73721eb05b2932ca02faaf395fae268 Mon Sep 17 00:00:00 2001 From: l10n daemon script Date: Sun, 25 Jun 2023 00:55:37 +0000 Subject: GIT_SILENT made messages (after extraction) --- src/org.kde.dolphin.appdata.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/org.kde.dolphin.appdata.xml b/src/org.kde.dolphin.appdata.xml index e582fde8a..8c546c4ad 100644 --- a/src/org.kde.dolphin.appdata.xml +++ b/src/org.kde.dolphin.appdata.xml @@ -80,7 +80,7 @@ Fitxategi-kudeatzailea Tiedostonhallinta Gestionnaire de fichiers - Xestor de ficheiros + Xestor de ficheiros. מנהל קבצים फ़ाइल प्रबंधक Fájlkezelő @@ -177,7 +177,7 @@

Dolphin-ek denbora aurreztuko dizuten produktibitate-ezaugarri ugari ditu. Fitxa anitzen eta ikuspegi zatituen ezaugarriek aldi berean karpeta anitz nabigatzen uzten dute, eta fitxategiak ikuspegien artean arrastatu eta jaregin ditzakezu haiek erraz mugitu edo kopiatzeko. Dolphin-en eskuin-klik laster-menuak, besteak beste, fitxategiak konprimatzeko, partekatzeko, eta bikoizteko ekintza azkarrak eskaintzen ditu. Zuk nahi dituzun ekintzak ere erants ditzakezu.

Dolphinin monet tuottavuusominaisuudet säästävät aikaasi. Välilehdet ja jaetut näkyvät mahdollistavat useamman kansion tarkastelun yhtä aikaa, jolloin tiedostoja voi helposti kopioida tai siirtää näkymästä toiseen vetämällä ja pudottamalla. Dolphinin kontekstivalikon tarjoamin pikatoiminnoin tiedostoja voi muun muassa pakata, jakaa ja monistaa. Myös omia mukautettuja toimintoja voi luoda.

Dolphin contient de nombreuses fonctionnalités pour la productivité vous permettant de gagner du temps. Les fonctionnalités d'onglets multiples et d'affichage scindé vous permettent de naviguer dans plusieurs dossiers en même temps. Vous pouvez aussi réaliser facilement des glisser et déposer entre les affichages pour les déplacer ou les copier. Le menu de Dolphin accessible par un clic droit fournit plusieurs actions rapides vous permettant de compresser, partager et dupliquer des fichiers, entre autres actions. Vous pouvez aussi ajouter votre propres actions personnalisées.

-

Dolphin contén una morea de funcionalidades de produtividade para aforrarlle tempo. As funcionalidades de lapelas e vista dividida permiten navegar varios cartafoles ao mesmo tempo, e pode arrastrar e soltar ficheiros entre as súas vistas facilmente para movelos ou copialos. O menú de clic dereito de Dolphin fornece moitas accións rápidas que lle permiten comprimir, compartir, e duplicar ficheiros, entre outras cousas. Tamén pode engadir as súas propias accións personalizadas.

+

Dolphin contén una morea de funcionalidades de produtividade para aforrarlle tempo. As funcionalidades de separadores e vista dividida permiten navegar varios cartafoles ao mesmo tempo, e pode arrastrar e soltar ficheiros entre as súas vistas facilmente para movelos ou copialos. O menú de clic dereito de Dolphin fornece moitas accións rápidas que lle permiten comprimir, compartir, e duplicar ficheiros, entre outras cousas. Tamén pode engadir as súas propias accións personalizadas.

डॉल्फिन में बहुत सारी उत्पादकता विशेषताएं होती हैं जो आपका समय बचाएगी। एकाधिक टैब और विभाजित दृश्य सुविधाएं एक ही समय में एकाधिक फ़ोल्डरों को संचालित करने में काम आतीं हैं, और आप फ़ाइलों को स्थानांतरित करने या नकल करने के लिए आसानी से फ़ाइलों को खींच कर छोड़ सकते हैं। डॉल्फ़िन का दाहिना-क्लिक मेनू कई द्रुत क्रियाएं प्रदान करता है जो आपको कई अन्य चीजों के साथ-साथ फ़ाइलों को संपीड़ित, साझा और प्रतिलिपि बनाने देता है। आप अपनी खुद की तदनुकूल कार्रवाइयां भी जोड़ सकते हैं।

A Dolphin számos olyan funkcióval bír, amelyek időt spórolnak Önnek. A lapokkal és osztott nézetekkel egyszerre navigálhat több mappában egyszerre, és könnyen húzhat át fájlokat az egyik nézetből a másikba, átmásolva vagy áthelyezve azokat. A Dolphin jobb gombos menüje rengeteg gyors műveletet biztosít, például tömörítést, megosztást vagy fájlduplikálást. Akár saját műveletekkel is bővítheti azt.

Dolphin contine abundantia de characteristicas de productivitate que te salveguardera tempore. Le characteristicas de multiple schedas e vista dividite permitte navigar dossieres multiple al mesme tempore, e tu pote facilemente traher e deponer files inter vistas per mover o copiar los. Le menu de pulsar a dextere de Dolphines fornite con multe actiones rapide que te permitte comprimer, compartir, e duplicar files, inter multe altere cosas. Tu anqu pote adder tu actiones personalisate.

@@ -356,7 +356,7 @@ Fitxategi-kudeaketa Dolphin-ekin Tiedostonhallinta Dolphinissa Gestion de fichiers dans Dolphin - Xestión de ficheiros en Dolphin + Xestión de ficheiros en Dolphin. ניהול קבצים ב־Dolphin डॉल्फिन में फ़ाइल प्रबंधन Fájlkezelés a Dolphinban @@ -408,7 +408,7 @@ Dolphinen txertatutako terminala Upotettu pääte Dolphinissa Terminal intégré dans Dolphin - Terminal incrustado en Dolphin + Terminal incrustado en Dolphin. डॉल्फिन में सन्निहित टर्मिनल Beágyazott terminál a Dolphinban Terminal incorporate in Dolphin @@ -456,7 +456,7 @@ Dolphinek zure fitxategi-kudeatzailea nahi duzun eran konfiguratzen uzten dizu Dolphinilla voit tehdä tiedostonhallintaa juuri kuten haluat Dolphin vous permet de configurer votre gestionnaire de fichiers, exactement comme vous le souhaitez. - Dolphin permítelle configurar o seu xestor de ficheiros como queira + Dolphin permítelle configurar o seu xestor de ficheiros como queira. डॉल्फ़िन आपको अपने फ़ाइल प्रबंधक को ठीक वैसे ही विन्यस्त करने देता है जैसे आप चाहते हैं A Dolphin lehetővé teszi, hogy úgy állítsa be a fájlkezelőkét, ahogyan szeretné Dolphin te permitte configurar tu gerente de file exactemente como tu lo vole -- cgit v1.3 From b92bb43e9da038c68ff8cf3f95e043a2e42b6c75 Mon Sep 17 00:00:00 2001 From: Tem PQD Date: Sun, 25 Jun 2023 00:31:07 +0000 Subject: Fix Refresh tooltip text and add Refresh whatsThis text BUG: 469263 --- src/dolphinmainwindow.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index 00af38beb..219c9eb56 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -1766,7 +1766,14 @@ void DolphinMainWindow::setupActions() stashSplit->setVisible(sessionInterface && sessionInterface->isServiceRegistered(QStringLiteral("org.kde.kio.StashNotifier"))); connect(stashSplit, &QAction::triggered, this, &DolphinMainWindow::toggleSplitStash); - KStandardAction::redisplay(this, &DolphinMainWindow::reloadView, actionCollection()); + QAction *redisplay = KStandardAction::redisplay(this, &DolphinMainWindow::reloadView, actionCollection()); + redisplay->setToolTip(i18nc("@info:tooltip", "Refresh view")); + redisplay->setWhatsThis(xi18nc("@info:whatsthis refresh", + "This refreshes " + "the folder view." + "If the contents of this folder have changed, refreshing will re-scan this folder " + "and show you a newly-updated view of the files and folders contained here." + "If the view is split, this refreshes the one that is currently in focus.")); QAction *stop = actionCollection()->addAction(QStringLiteral("stop")); stop->setText(i18nc("@action:inmenu View", "Stop")); -- cgit v1.3