X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/82202a24e20a36d8bfd814dce6702012d74a1620..cd2e64154fd5446a7e19aff4cb147efe2f2ba31e:/src/kitemviews/kfileitemmodelrolesupdater.cpp diff --git a/src/kitemviews/kfileitemmodelrolesupdater.cpp b/src/kitemviews/kfileitemmodelrolesupdater.cpp index 49657a9b1..09dd2eba1 100644 --- a/src/kitemviews/kfileitemmodelrolesupdater.cpp +++ b/src/kitemviews/kfileitemmodelrolesupdater.cpp @@ -13,7 +13,6 @@ #include #include -#include #include #include #include @@ -21,70 +20,75 @@ #include #include -#ifdef HAVE_BALOO +#include "dolphin_contentdisplaysettings.h" + +#if HAVE_BALOO #include "private/kbaloorolesprovider.h" #include #include #endif #include -#include +#include +#include #include #include -#include #include +#include + +using namespace std::chrono_literals; // #define KFILEITEMMODELROLESUPDATER_DEBUG -namespace { - // Maximum time in ms that the KFileItemModelRolesUpdater - // may perform a blocking operation - const int MaxBlockTimeout = 200; +namespace +{ +// Maximum time in ms that the KFileItemModelRolesUpdater +// may perform a blocking operation +const int MaxBlockTimeout = 200; - // If the number of items is smaller than ResolveAllItemsLimit, - // the roles of all items will be resolved. - const int ResolveAllItemsLimit = 500; +// If the number of items is smaller than ResolveAllItemsLimit, +// the roles of all items will be resolved. +const int ResolveAllItemsLimit = 500; - // Not only the visible area, but up to ReadAheadPages before and after - // this area will be resolved. - const int ReadAheadPages = 5; +// Not only the visible area, but up to ReadAheadPages before and after +// this area will be resolved. +const int ReadAheadPages = 5; } -KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QObject* parent) : - QObject(parent), - m_state(Idle), - m_previewChangedDuringPausing(false), - m_iconSizeChangedDuringPausing(false), - m_rolesChangedDuringPausing(false), - m_previewShown(false), - m_enlargeSmallPreviews(true), - m_clearPreviews(false), - m_finishedItems(), - m_model(model), - m_iconSize(), - m_firstVisibleIndex(0), - m_lastVisibleIndex(-1), - m_maximumVisibleItems(50), - m_roles(), - m_resolvableRoles(), - m_enabledPlugins(), - m_localFileSizePreviewLimit(0), - m_scanDirectories(true), - m_pendingSortRoleItems(), - m_pendingIndexes(), - m_pendingPreviewItems(), - m_previewJob(), - m_hoverSequenceItem(), - m_hoverSequenceIndex(0), - m_hoverSequencePreviewJob(nullptr), - m_hoverSequenceNumSuccessiveFailures(0), - m_recentlyChangedItemsTimer(nullptr), - m_recentlyChangedItems(), - m_changedItems(), - m_directoryContentsCounter(nullptr) - #ifdef HAVE_BALOO - , m_balooFileMonitor(nullptr) - #endif +KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel *model, QObject *parent) + : QObject(parent) + , m_state(Idle) + , m_previewChangedDuringPausing(false) + , m_iconSizeChangedDuringPausing(false) + , m_rolesChangedDuringPausing(false) + , m_previewShown(false) + , m_enlargeSmallPreviews(true) + , m_clearPreviews(false) + , m_finishedItems() + , m_model(model) + , m_iconSize() + , m_firstVisibleIndex(0) + , m_lastVisibleIndex(-1) + , m_maximumVisibleItems(50) + , m_roles() + , m_resolvableRoles() + , m_enabledPlugins() + , m_localFileSizePreviewLimit(0) + , m_pendingSortRoleItems() + , m_pendingIndexes() + , m_pendingPreviewItems() + , m_previewJob() + , m_hoverSequenceItem() + , m_hoverSequenceIndex(0) + , m_hoverSequencePreviewJob(nullptr) + , m_hoverSequenceNumSuccessiveFailures(0) + , m_recentlyChangedItemsTimer(nullptr) + , m_recentlyChangedItems() + , m_changedItems() + , m_directoryContentsCounter(nullptr) +#if HAVE_BALOO + , m_balooFileMonitor(nullptr) +#endif { Q_ASSERT(model); @@ -92,36 +96,31 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO m_enabledPlugins = globalConfig.readEntry("Plugins", KIO::PreviewJob::defaultPlugins()); m_localFileSizePreviewLimit = static_cast(globalConfig.readEntry("MaximumSize", 0)); - connect(m_model, &KFileItemModel::itemsInserted, - this, &KFileItemModelRolesUpdater::slotItemsInserted); - connect(m_model, &KFileItemModel::itemsRemoved, - this, &KFileItemModelRolesUpdater::slotItemsRemoved); - connect(m_model, &KFileItemModel::itemsChanged, - this, &KFileItemModelRolesUpdater::slotItemsChanged); - connect(m_model, &KFileItemModel::itemsMoved, - this, &KFileItemModelRolesUpdater::slotItemsMoved); - connect(m_model, &KFileItemModel::sortRoleChanged, - this, &KFileItemModelRolesUpdater::slotSortRoleChanged); + connect(m_model, &KFileItemModel::itemsInserted, this, &KFileItemModelRolesUpdater::slotItemsInserted); + connect(m_model, &KFileItemModel::itemsRemoved, this, &KFileItemModelRolesUpdater::slotItemsRemoved); + connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); + connect(m_model, &KFileItemModel::itemsMoved, this, &KFileItemModelRolesUpdater::slotItemsMoved); + connect(m_model, &KFileItemModel::sortRoleChanged, this, &KFileItemModelRolesUpdater::slotSortRoleChanged); // Use a timer to prevent that each call of slotItemsChanged() results in a synchronous // resolving of the roles. Postpone the resolving until no update has been done for 100 ms. m_recentlyChangedItemsTimer = new QTimer(this); - m_recentlyChangedItemsTimer->setInterval(100); + m_recentlyChangedItemsTimer->setInterval(100ms); m_recentlyChangedItemsTimer->setSingleShot(true); connect(m_recentlyChangedItemsTimer, &QTimer::timeout, this, &KFileItemModelRolesUpdater::resolveRecentlyChangedItems); m_resolvableRoles.insert("size"); m_resolvableRoles.insert("type"); m_resolvableRoles.insert("isExpandable"); -#ifdef HAVE_BALOO +#if HAVE_BALOO m_resolvableRoles += KBalooRolesProvider::instance().roles(); #endif m_directoryContentsCounter = new KDirectoryContentsCounter(m_model, this); - connect(m_directoryContentsCounter, &KDirectoryContentsCounter::result, - this, &KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived); + connect(m_directoryContentsCounter, &KDirectoryContentsCounter::result, this, &KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived); - const auto plugins = KPluginMetaData::findPlugins(QStringLiteral("kf5/overlayicon")); + const QString pluginNamespace = QStringLiteral("kf" QT_STRINGIFY(QT_MAJOR_VERSION)) + QStringLiteral("/overlayicon"); + const auto plugins = KPluginMetaData::findPlugins(pluginNamespace, {}, KPluginMetaData::AllowEmptyMetaData); for (const KPluginMetaData &data : plugins) { auto instance = QPluginLoader(data.fileName()).instance(); auto plugin = qobject_cast(instance); @@ -140,7 +139,7 @@ KFileItemModelRolesUpdater::~KFileItemModelRolesUpdater() killPreviewJob(); } -void KFileItemModelRolesUpdater::setIconSize(const QSize& size) +void KFileItemModelRolesUpdater::setIconSize(const QSize &size) { if (size != m_iconSize) { m_iconSize = size; @@ -219,7 +218,7 @@ bool KFileItemModelRolesUpdater::enlargeSmallPreviews() const return m_enlargeSmallPreviews; } -void KFileItemModelRolesUpdater::setEnabledPlugins(const QStringList& list) +void KFileItemModelRolesUpdater::setEnabledPlugins(const QStringList &list) { if (m_enabledPlugins != list) { m_enabledPlugins = list; @@ -239,8 +238,7 @@ void KFileItemModelRolesUpdater::setPaused(bool paused) m_state = Paused; killPreviewJob(); } else { - const bool updatePreviews = (m_iconSizeChangedDuringPausing && m_previewShown) || - m_previewChangedDuringPausing; + const bool updatePreviews = (m_iconSizeChangedDuringPausing && m_previewShown) || m_previewChangedDuringPausing; const bool resolveAll = updatePreviews || m_rolesChangedDuringPausing; if (resolveAll) { m_finishedItems.clear(); @@ -261,21 +259,21 @@ void KFileItemModelRolesUpdater::setPaused(bool paused) } } -void KFileItemModelRolesUpdater::setRoles(const QSet& roles) +void KFileItemModelRolesUpdater::setRoles(const QSet &roles) { if (m_roles != roles) { m_roles = roles; -#ifdef HAVE_BALOO +#if HAVE_BALOO // Check whether there is at least one role that must be resolved // with the help of Baloo. If this is the case, a (quite expensive) // resolving will be done in KFileItemModelRolesUpdater::rolesData() and // the role gets watched for changes. - const KBalooRolesProvider& rolesProvider = KBalooRolesProvider::instance(); + const KBalooRolesProvider &rolesProvider = KBalooRolesProvider::instance(); bool hasBalooRole = false; QSetIterator it(roles); while (it.hasNext()) { - const QByteArray& role = it.next(); + const QByteArray &role = it.next(); if (rolesProvider.roles().contains(role)) { hasBalooRole = true; break; @@ -284,8 +282,7 @@ void KFileItemModelRolesUpdater::setRoles(const QSet& roles) if (hasBalooRole && m_balooConfig.fileIndexingEnabled() && !m_balooFileMonitor) { m_balooFileMonitor = new Baloo::FileMonitor(this); - connect(m_balooFileMonitor, &Baloo::FileMonitor::fileMetaDataChanged, - this, &KFileItemModelRolesUpdater::applyChangedBalooRoles); + connect(m_balooFileMonitor, &Baloo::FileMonitor::fileMetaDataChanged, this, &KFileItemModelRolesUpdater::applyChangedBalooRoles); } else if (!hasBalooRole && m_balooFileMonitor) { delete m_balooFileMonitor; m_balooFileMonitor = nullptr; @@ -325,17 +322,7 @@ 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) +void KFileItemModelRolesUpdater::setHoverSequenceState(const QUrl &itemUrl, int seqIdx) { const KFileItem item = m_model->fileItem(itemUrl); @@ -355,7 +342,7 @@ void KFileItemModelRolesUpdater::setHoverSequenceState(const QUrl& itemUrl, int loadNextHoverSequencePreview(); } -void KFileItemModelRolesUpdater::slotItemsInserted(const KItemRangeList& itemRanges) +void KFileItemModelRolesUpdater::slotItemsInserted(const KItemRangeList &itemRanges) { QElapsedTimer timer; timer.start(); @@ -363,7 +350,7 @@ void KFileItemModelRolesUpdater::slotItemsInserted(const KItemRangeList& itemRan // Determine the sort role synchronously for as many items as possible. if (m_resolvableRoles.contains(m_model->sortRole())) { int insertedCount = 0; - for (const KItemRange& range : itemRanges) { + for (const KItemRange &range : itemRanges) { const int lastIndex = insertedCount + range.index + range.count - 1; for (int i = insertedCount + range.index; i <= lastIndex; ++i) { if (timer.elapsed() < MaxBlockTimeout) { @@ -390,13 +377,13 @@ void KFileItemModelRolesUpdater::slotItemsInserted(const KItemRangeList& itemRan startUpdating(); } -void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRanges) +void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList &itemRanges) { Q_UNUSED(itemRanges) const bool allItemsRemoved = (m_model->count() == 0); -#ifdef HAVE_BALOO +#if HAVE_BALOO if (m_balooFileMonitor) { // Don't let the FileWatcher watch for removed items if (allItemsRemoved) { @@ -404,7 +391,7 @@ void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRang } else { QStringList newFileList; const QStringList oldFileList = m_balooFileMonitor->files(); - for (const QString& file : oldFileList) { + for (const QString &file : oldFileList) { if (m_model->index(QUrl::fromLocalFile(file)) >= 0) { newFileList.append(file); } @@ -427,6 +414,9 @@ void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRang m_hoverSequenceLoadedItems.clear(); killPreviewJob(); + if (!m_model->showDirectoriesOnly()) { + m_directoryContentsCounter->stopWorker(); + } } else { // Only remove the items from m_finishedItems. They will be removed // from the other sets later on. @@ -440,7 +430,7 @@ void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRang } // Removed items won't have hover previews loaded anymore. - for (const KItemRange& itemRange : itemRanges) { + for (const KItemRange &itemRange : itemRanges) { int index = itemRange.index; for (int count = itemRange.count; count > 0; --count) { const KFileItem item = m_model->fileItem(index); @@ -454,7 +444,7 @@ void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRang } } -void KFileItemModelRolesUpdater::slotItemsMoved(const KItemRange& itemRange, const QList &movedToIndexes) +void KFileItemModelRolesUpdater::slotItemsMoved(KItemRange itemRange, const QList &movedToIndexes) { Q_UNUSED(itemRange) Q_UNUSED(movedToIndexes) @@ -463,8 +453,7 @@ void KFileItemModelRolesUpdater::slotItemsMoved(const KItemRange& itemRange, con startUpdating(); } -void KFileItemModelRolesUpdater::slotItemsChanged(const KItemRangeList& itemRanges, - const QSet& roles) +void KFileItemModelRolesUpdater::slotItemsChanged(const KItemRangeList &itemRanges, const QSet &roles) { Q_UNUSED(roles) @@ -473,9 +462,9 @@ void KFileItemModelRolesUpdater::slotItemsChanged(const KItemRangeList& itemRang // to prevent expensive repeated updates if files are updated frequently. const bool itemsChangedRecently = m_recentlyChangedItemsTimer->isActive(); - QSet& targetSet = itemsChangedRecently ? m_recentlyChangedItems : m_changedItems; + QSet &targetSet = itemsChangedRecently ? m_recentlyChangedItems : m_changedItems; - for (const KItemRange& itemRange : itemRanges) { + for (const KItemRange &itemRange : itemRanges) { int index = itemRange.index; for (int count = itemRange.count; count > 0; --count) { const KFileItem item = m_model->fileItem(index); @@ -491,8 +480,7 @@ void KFileItemModelRolesUpdater::slotItemsChanged(const KItemRangeList& itemRang } } -void KFileItemModelRolesUpdater::slotSortRoleChanged(const QByteArray& current, - const QByteArray& previous) +void KFileItemModelRolesUpdater::slotSortRoleChanged(const QByteArray ¤t, const QByteArray &previous) { Q_UNUSED(current) Q_UNUSED(previous) @@ -529,7 +517,7 @@ void KFileItemModelRolesUpdater::slotSortRoleChanged(const QByteArray& current, } } -void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem& item, const QPixmap& pixmap) +void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem &item, const QPixmap &pixmap) { if (m_state != PreviewJobRunning) { return; @@ -544,7 +532,7 @@ void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem& item, const QPi QPixmap scaledPixmap = transformPreviewPixmap(pixmap); - QHash data = rolesData(item); + QHash data = rolesData(item, index); const QStringList overlays = data["iconOverlays"].toStringList(); // Strangely KFileItem::overlays() returns empty string-values, so @@ -553,7 +541,7 @@ void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem& item, const QPi // assumes that an overlay will be drawn and has some additional // setup time. if (!scaledPixmap.isNull()) { - for (const QString& overlay : overlays) { + for (const QString &overlay : overlays) { if (!overlay.isEmpty()) { // There is at least one overlay, draw all overlays above m_pixmap // and cancel the check @@ -565,16 +553,14 @@ void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem& item, const QPi data.insert("iconPixmap", scaledPixmap); - disconnect(m_model, &KFileItemModel::itemsChanged, - this, &KFileItemModelRolesUpdater::slotItemsChanged); + disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); m_model->setData(index, data); - connect(m_model, &KFileItemModel::itemsChanged, - this, &KFileItemModelRolesUpdater::slotItemsChanged); + connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); m_finishedItems.insert(item); } -void KFileItemModelRolesUpdater::slotPreviewFailed(const KFileItem& item) +void KFileItemModelRolesUpdater::slotPreviewFailed(const KFileItem &item) { if (m_state != PreviewJobRunning) { return; @@ -587,11 +573,9 @@ void KFileItemModelRolesUpdater::slotPreviewFailed(const KFileItem& item) QHash data; data.insert("iconPixmap", QPixmap()); - disconnect(m_model, &KFileItemModel::itemsChanged, - this, &KFileItemModelRolesUpdater::slotItemsChanged); + disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); m_model->setData(index, data); - connect(m_model, &KFileItemModel::itemsChanged, - this, &KFileItemModelRolesUpdater::slotItemsChanged); + connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); applyResolvedRoles(index, ResolveAll); m_finishedItems.insert(item); @@ -617,7 +601,7 @@ void KFileItemModelRolesUpdater::slotPreviewJobFinished() } } -void KFileItemModelRolesUpdater::slotHoverSequenceGotPreview(const KFileItem& item, const QPixmap& pixmap) +void KFileItemModelRolesUpdater::slotHoverSequenceGotPreview(const KFileItem &item, const QPixmap &pixmap) { const int index = m_model->index(item); if (index < 0) { @@ -651,8 +635,7 @@ void KFileItemModelRolesUpdater::slotHoverSequenceGotPreview(const KFileItem& it m_model->setData(index, data); - const auto loadedIt = std::find(m_hoverSequenceLoadedItems.begin(), - m_hoverSequenceLoadedItems.end(), item); + const auto loadedIt = std::find(m_hoverSequenceLoadedItems.begin(), m_hoverSequenceLoadedItems.end(), item); if (loadedIt == m_hoverSequenceLoadedItems.end()) { m_hoverSequenceLoadedItems.push_back(item); trimHoverSequenceLoadedItems(); @@ -662,7 +645,7 @@ void KFileItemModelRolesUpdater::slotHoverSequenceGotPreview(const KFileItem& it m_hoverSequenceNumSuccessiveFailures = 0; } -void KFileItemModelRolesUpdater::slotHoverSequencePreviewFailed(const KFileItem& item) +void KFileItemModelRolesUpdater::slotHoverSequencePreviewFailed(const KFileItem &item) { const int index = m_model->index(item); if (index < 0) { @@ -674,11 +657,8 @@ void KFileItemModelRolesUpdater::slotHoverSequencePreviewFailed(const KFileItem& QHash data = m_model->data(index); QVector pixmaps = data["hoverSequencePixmaps"].value>(); - qCDebug(DolphinDebug).nospace() - << "Failed to generate hover sequence preview #" << pixmaps.size() - << " for file " << item.url().toString() - << " (attempt " << (m_hoverSequenceNumSuccessiveFailures+1) - << "/" << (numRetries+1) << ")"; + qCDebug(DolphinDebug).nospace() << "Failed to generate hover sequence preview #" << pixmaps.size() << " for file " << item.url().toString() << " (attempt " + << (m_hoverSequenceNumSuccessiveFailures + 1) << "/" << (numRetries + 1) << ")"; if (m_hoverSequenceNumSuccessiveFailures >= numRetries) { // Give up and simply duplicate the previous sequence image (if any) @@ -753,11 +733,9 @@ void KFileItemModelRolesUpdater::resolveNextSortRole() m_state = Idle; // Prevent that we try to update the items twice. - disconnect(m_model, &KFileItemModel::itemsMoved, - this, &KFileItemModelRolesUpdater::slotItemsMoved); + disconnect(m_model, &KFileItemModel::itemsMoved, this, &KFileItemModelRolesUpdater::slotItemsMoved); applySortProgressToModel(); - connect(m_model, &KFileItemModel::itemsMoved, - this, &KFileItemModelRolesUpdater::slotItemsMoved); + connect(m_model, &KFileItemModel::itemsMoved, this, &KFileItemModelRolesUpdater::slotItemsMoved); startUpdating(); } } @@ -794,18 +772,13 @@ void KFileItemModelRolesUpdater::resolveNextPendingRoles() data.insert("iconPixmap", QPixmap()); data.insert("hoverSequencePixmaps", QVariant::fromValue(QVector())); - disconnect(m_model, &KFileItemModel::itemsChanged, - this, &KFileItemModelRolesUpdater::slotItemsChanged); + disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); for (int index = 0; index <= m_model->count(); ++index) { - if (m_model->data(index).contains("iconPixmap") || - m_model->data(index).contains("hoverSequencePixmaps")) - { + if (m_model->data(index).contains("iconPixmap") || m_model->data(index).contains("hoverSequencePixmaps")) { m_model->setData(index, data); } } - connect(m_model, &KFileItemModel::itemsChanged, - this, &KFileItemModelRolesUpdater::slotItemsChanged); - + connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); } m_clearPreviews = false; } @@ -823,9 +796,9 @@ void KFileItemModelRolesUpdater::resolveRecentlyChangedItems() updateChangedItems(); } -void KFileItemModelRolesUpdater::applyChangedBalooRoles(const QString& file) +void KFileItemModelRolesUpdater::applyChangedBalooRoles(const QString &file) { -#ifdef HAVE_BALOO +#if HAVE_BALOO const KFileItem item = m_model->fileItem(QUrl::fromLocalFile(file)); if (item.isNull()) { @@ -841,15 +814,15 @@ void KFileItemModelRolesUpdater::applyChangedBalooRoles(const QString& file) void KFileItemModelRolesUpdater::applyChangedBalooRolesForItem(const KFileItem &item) { -#ifdef HAVE_BALOO +#if HAVE_BALOO Baloo::File file(item.localPath()); file.load(); - const KBalooRolesProvider& rolesProvider = KBalooRolesProvider::instance(); + const KBalooRolesProvider &rolesProvider = KBalooRolesProvider::instance(); QHash data; const auto roles = rolesProvider.roles(); - for (const QByteArray& role : roles) { + for (const QByteArray &role : roles) { // Overwrite all the role values with an empty QVariant, because the roles // provider doesn't overwrite it when the property value list is empty. // See bug 322348 @@ -862,12 +835,10 @@ void KFileItemModelRolesUpdater::applyChangedBalooRolesForItem(const KFileItem & data.insert(it.key(), it.value()); } - disconnect(m_model, &KFileItemModel::itemsChanged, - this, &KFileItemModelRolesUpdater::slotItemsChanged); + disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); const int index = m_model->index(item); m_model->setData(index, data); - connect(m_model, &KFileItemModel::itemsChanged, - this, &KFileItemModelRolesUpdater::slotItemsChanged); + connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); #else #ifndef Q_CC_MSVC Q_UNUSED(item) @@ -875,10 +846,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)); @@ -893,11 +864,9 @@ void KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived(const QStrin data.insert("isExpandable", count > 0); } - disconnect(m_model, &KFileItemModel::itemsChanged, - this, &KFileItemModelRolesUpdater::slotItemsChanged); + disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); m_model->setData(index, data); - connect(m_model, &KFileItemModel::itemsChanged, - this, &KFileItemModelRolesUpdater::slotItemsChanged); + connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); } } } @@ -993,8 +962,7 @@ void KFileItemModelRolesUpdater::startPreviewJob() // by PreviewJob if a smaller size is requested. For images KFileItemModelRolesUpdater must // do a downscaling anyhow because of the frame, so in this case only the provided // cache sizes are requested. - const QSize cacheSize = (m_iconSize.width() > 128) || (m_iconSize.height() > 128) - ? QSize(256, 256) : QSize(128, 128); + const QSize cacheSize = (m_iconSize.width() > 128) || (m_iconSize.height() > 128) ? QSize(256, 256) : QSize(128, 128); // KIO::filePreview() will request the MIME-type of all passed items, which (in the // worst case) might block the application for several seconds. To prevent such @@ -1024,38 +992,32 @@ void KFileItemModelRolesUpdater::startPreviewJob() } while (!m_pendingPreviewItems.isEmpty() && timer.elapsed() < MaxBlockTimeout); } - KIO::PreviewJob* job = new KIO::PreviewJob(itemSubSet, cacheSize, &m_enabledPlugins); + KIO::PreviewJob *job = new KIO::PreviewJob(itemSubSet, cacheSize, &m_enabledPlugins); - job->setIgnoreMaximumSize(itemSubSet.first().isLocalFile() && m_localFileSizePreviewLimit <= 0); + job->setIgnoreMaximumSize(itemSubSet.first().isLocalFile() && !itemSubSet.first().isSlow() && m_localFileSizePreviewLimit <= 0); if (job->uiDelegate()) { KJobWidgets::setWindow(job, qApp->activeWindow()); } - connect(job, &KIO::PreviewJob::gotPreview, - this, &KFileItemModelRolesUpdater::slotGotPreview); - connect(job, &KIO::PreviewJob::failed, - this, &KFileItemModelRolesUpdater::slotPreviewFailed); - connect(job, &KIO::PreviewJob::finished, - this, &KFileItemModelRolesUpdater::slotPreviewJobFinished); + connect(job, &KIO::PreviewJob::gotPreview, this, &KFileItemModelRolesUpdater::slotGotPreview); + connect(job, &KIO::PreviewJob::failed, this, &KFileItemModelRolesUpdater::slotPreviewFailed); + connect(job, &KIO::PreviewJob::finished, this, &KFileItemModelRolesUpdater::slotPreviewJobFinished); m_previewJob = job; } -QPixmap KFileItemModelRolesUpdater::transformPreviewPixmap(const QPixmap& pixmap) +QPixmap KFileItemModelRolesUpdater::transformPreviewPixmap(const QPixmap &pixmap) { QPixmap scaledPixmap = pixmap; - if (!pixmap.hasAlpha() && !pixmap.isNull() - && m_iconSize.width() > KIconLoader::SizeSmallMedium - && m_iconSize.height() > KIconLoader::SizeSmallMedium) { + if (!pixmap.hasAlpha() && !pixmap.isNull() && m_iconSize.width() > KIconLoader::SizeSmallMedium && m_iconSize.height() > KIconLoader::SizeSmallMedium) { if (m_enlargeSmallPreviews) { KPixmapModifier::applyFrame(scaledPixmap, m_iconSize); } else { // Assure that small previews don't get enlarged. Instead they // should be shown centered within the frame. const QSize contentSize = KPixmapModifier::sizeInsideFrame(m_iconSize); - const bool enlargingRequired = scaledPixmap.width() < contentSize.width() && - scaledPixmap.height() < contentSize.height(); + const bool enlargingRequired = scaledPixmap.width() < contentSize.width() && scaledPixmap.height() < contentSize.height(); if (enlargingRequired) { QSize frameSize = scaledPixmap.size() / scaledPixmap.devicePixelRatio(); frameSize.scale(m_iconSize, Qt::KeepAspectRatio); @@ -1066,7 +1028,7 @@ QPixmap KFileItemModelRolesUpdater::transformPreviewPixmap(const QPixmap& pixmap KPixmapModifier::applyFrame(largeFrame, frameSize); QPainter painter(&largeFrame); - painter.drawPixmap((largeFrame.width() - scaledPixmap.width() / scaledPixmap.devicePixelRatio()) / 2, + painter.drawPixmap((largeFrame.width() - scaledPixmap.width() / scaledPixmap.devicePixelRatio()) / 2, (largeFrame.height() - scaledPixmap.height() / scaledPixmap.devicePixelRatio()) / 2, scaledPixmap); scaledPixmap = largeFrame; @@ -1096,7 +1058,7 @@ void KFileItemModelRolesUpdater::loadNextHoverSequencePreview() } // We generate the next few sequence indices in advance (buffering) - const int maxSeqIdx = m_hoverSequenceIndex+5; + const int maxSeqIdx = m_hoverSequenceIndex + 5; QHash data = m_model->data(index); @@ -1129,23 +1091,19 @@ void KFileItemModelRolesUpdater::loadNextHoverSequencePreview() // by PreviewJob if a smaller size is requested. For images KFileItemModelRolesUpdater must // do a downscaling anyhow because of the frame, so in this case only the provided // cache sizes are requested. - const QSize cacheSize = (m_iconSize.width() > 128) || (m_iconSize.height() > 128) - ? QSize(256, 256) : QSize(128, 128); + const QSize cacheSize = (m_iconSize.width() > 128) || (m_iconSize.height() > 128) ? QSize(256, 256) : QSize(128, 128); - KIO::PreviewJob* job = new KIO::PreviewJob({m_hoverSequenceItem}, cacheSize, &m_enabledPlugins); + KIO::PreviewJob *job = new KIO::PreviewJob({m_hoverSequenceItem}, cacheSize, &m_enabledPlugins); job->setSequenceIndex(loadSeqIdx); - job->setIgnoreMaximumSize(m_hoverSequenceItem.isLocalFile() && m_localFileSizePreviewLimit <= 0); + job->setIgnoreMaximumSize(m_hoverSequenceItem.isLocalFile() && !m_hoverSequenceItem.isSlow() && m_localFileSizePreviewLimit <= 0); if (job->uiDelegate()) { KJobWidgets::setWindow(job, qApp->activeWindow()); } - connect(job, &KIO::PreviewJob::gotPreview, - this, &KFileItemModelRolesUpdater::slotHoverSequenceGotPreview); - connect(job, &KIO::PreviewJob::failed, - this, &KFileItemModelRolesUpdater::slotHoverSequencePreviewFailed); - connect(job, &KIO::PreviewJob::finished, - this, &KFileItemModelRolesUpdater::slotHoverSequencePreviewJobFinished); + connect(job, &KIO::PreviewJob::gotPreview, this, &KFileItemModelRolesUpdater::slotHoverSequenceGotPreview); + connect(job, &KIO::PreviewJob::failed, this, &KFileItemModelRolesUpdater::slotHoverSequencePreviewFailed); + connect(job, &KIO::PreviewJob::finished, this, &KFileItemModelRolesUpdater::slotHoverSequencePreviewJobFinished); m_hoverSequencePreviewJob = job; } @@ -1153,12 +1111,9 @@ void KFileItemModelRolesUpdater::loadNextHoverSequencePreview() void KFileItemModelRolesUpdater::killHoverSequencePreviewJob() { if (m_hoverSequencePreviewJob) { - disconnect(m_hoverSequencePreviewJob, &KIO::PreviewJob::gotPreview, - this, &KFileItemModelRolesUpdater::slotHoverSequenceGotPreview); - disconnect(m_hoverSequencePreviewJob, &KIO::PreviewJob::failed, - this, &KFileItemModelRolesUpdater::slotHoverSequencePreviewFailed); - disconnect(m_hoverSequencePreviewJob, &KIO::PreviewJob::finished, - this, &KFileItemModelRolesUpdater::slotHoverSequencePreviewJobFinished); + disconnect(m_hoverSequencePreviewJob, &KIO::PreviewJob::gotPreview, this, &KFileItemModelRolesUpdater::slotHoverSequenceGotPreview); + disconnect(m_hoverSequencePreviewJob, &KIO::PreviewJob::failed, this, &KFileItemModelRolesUpdater::slotHoverSequencePreviewFailed); + disconnect(m_hoverSequencePreviewJob, &KIO::PreviewJob::finished, this, &KFileItemModelRolesUpdater::slotHoverSequencePreviewJobFinished); m_hoverSequencePreviewJob->kill(); m_hoverSequencePreviewJob = nullptr; } @@ -1197,7 +1152,7 @@ void KFileItemModelRolesUpdater::updateChangedItems() auto changedItemsIt = m_changedItems.begin(); while (changedItemsIt != m_changedItems.end()) { - const auto& item = *changedItemsIt; + const auto &item = *changedItemsIt; const int index = m_model->index(item); if (index < 0) { @@ -1250,20 +1205,16 @@ void KFileItemModelRolesUpdater::applySortRole(int index) data.insert("type", item.mimeComment()); } else if (m_model->sortRole() == "size" && item.isLocalFile() && item.isDir()) { - const QString path = item.localPath(); - if (m_scanDirectories) { - m_directoryContentsCounter->scanDirectory(path); - } + startDirectorySizeCounting(item, index); + return; } else { // Probably the sort role is a baloo role - just determine all roles. - data = rolesData(item); + data = rolesData(item, index); } - disconnect(m_model, &KFileItemModel::itemsChanged, - this, &KFileItemModelRolesUpdater::slotItemsChanged); + disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); m_model->setData(index, data); - connect(m_model, &KFileItemModel::itemsChanged, - this, &KFileItemModelRolesUpdater::slotItemsChanged); + connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); } void KFileItemModelRolesUpdater::applySortProgressToModel() @@ -1294,7 +1245,7 @@ bool KFileItemModelRolesUpdater::applyResolvedRoles(int index, ResolveHint hint) QHash data; if (resolveAll) { - data = rolesData(item); + data = rolesData(item, index); } if (!item.iconName().isEmpty()) { @@ -1306,18 +1257,85 @@ bool KFileItemModelRolesUpdater::applyResolvedRoles(int index, ResolveHint hint) data.insert("hoverSequencePixmaps", QVariant::fromValue(QVector())); } - disconnect(m_model, &KFileItemModel::itemsChanged, - this, &KFileItemModelRolesUpdater::slotItemsChanged); + disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); m_model->setData(index, data); - connect(m_model, &KFileItemModel::itemsChanged, - this, &KFileItemModelRolesUpdater::slotItemsChanged); + connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); return true; } return false; } -QHash KFileItemModelRolesUpdater::rolesData(const KFileItem& item) +void KFileItemModelRolesUpdater::startDirectorySizeCounting(const KFileItem &item, int index) +{ + if (ContentDisplaySettings::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. + 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) { QHash data; @@ -1325,16 +1343,12 @@ QHash KFileItemModelRolesUpdater::rolesData(const KFileIte const bool getIsExpandableRole = m_roles.contains("isExpandable"); if ((getSizeRole || getIsExpandableRole) && item.isDir()) { - if (item.isLocalFile()) { - // Tell m_directoryContentsCounter that we want to count the items - // inside the directory. The result will be received in slotDirectoryContentsCountReceived. - if (m_scanDirectories) { - const QString path = item.localPath(); - m_directoryContentsCounter->scanDirectory(path); - } - } else if (getSizeRole) { - data.insert("size", -1); // -1 indicates an unknown number of items - } + startDirectorySizeCounting(item, index); + } + + if (m_roles.contains("extension")) { + // TODO KF6 use KFileItem::suffix 464722 + data.insert("extension", QFileInfo(item.name()).suffix()); } if (m_roles.contains("type")) { @@ -1345,9 +1359,11 @@ QHash KFileItemModelRolesUpdater::rolesData(const KFileIte for (KOverlayIconPlugin *it : qAsConst(m_overlayIconsPlugin)) { overlays.append(it->getOverlays(item.url())); } - data.insert("iconOverlays", overlays); + if (!overlays.isEmpty()) { + data.insert("iconOverlays", overlays); + } -#ifdef HAVE_BALOO +#if HAVE_BALOO if (m_balooFileMonitor) { m_balooFileMonitor->addFile(item.localPath()); applyChangedBalooRolesForItem(item); @@ -1356,14 +1372,14 @@ QHash KFileItemModelRolesUpdater::rolesData(const KFileIte return data; } -void KFileItemModelRolesUpdater::slotOverlaysChanged(const QUrl& url, const QStringList &) +void KFileItemModelRolesUpdater::slotOverlaysChanged(const QUrl &url, const QStringList &) { const KFileItem item = m_model->fileItem(url); if (item.isNull()) { return; } const int index = m_model->index(item); - QHash data = m_model->data(index); + QHash data = m_model->data(index); QStringList overlays = item.overlays(); for (KOverlayIconPlugin *it : qAsConst(m_overlayIconsPlugin)) { overlays.append(it->getOverlays(url)); @@ -1385,12 +1401,9 @@ void KFileItemModelRolesUpdater::updateAllPreviews() void KFileItemModelRolesUpdater::killPreviewJob() { if (m_previewJob) { - disconnect(m_previewJob, &KIO::PreviewJob::gotPreview, - this, &KFileItemModelRolesUpdater::slotGotPreview); - disconnect(m_previewJob, &KIO::PreviewJob::failed, - this, &KFileItemModelRolesUpdater::slotPreviewFailed); - disconnect(m_previewJob, &KIO::PreviewJob::finished, - this, &KFileItemModelRolesUpdater::slotPreviewJobFinished); + disconnect(m_previewJob, &KIO::PreviewJob::gotPreview, this, &KFileItemModelRolesUpdater::slotGotPreview); + disconnect(m_previewJob, &KIO::PreviewJob::failed, this, &KFileItemModelRolesUpdater::slotPreviewFailed); + disconnect(m_previewJob, &KIO::PreviewJob::finished, this, &KFileItemModelRolesUpdater::slotPreviewJobFinished); m_previewJob->kill(); m_previewJob = nullptr; m_pendingPreviewItems.clear(); @@ -1402,9 +1415,7 @@ QList KFileItemModelRolesUpdater::indexesToResolve() const const int count = m_model->count(); QList result; - result.reserve(qMin(count, (m_lastVisibleIndex - m_firstVisibleIndex + 1) + - ResolveAllItemsLimit + - (2 * m_maximumVisibleItems))); + result.reserve(qMin(count, (m_lastVisibleIndex - m_firstVisibleIndex + 1) + ResolveAllItemsLimit + (2 * m_maximumVisibleItems))); // Add visible items. // Resolve files first, their previews are quicker. @@ -1484,4 +1495,3 @@ void KFileItemModelRolesUpdater::trimHoverSequenceLoadedItems() } } } -