-/***************************************************************************
- * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
- ***************************************************************************/
+/*
+ * SPDX-FileCopyrightText: 2011 Peter Penz <peter.penz19@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
#include "kfileitemmodelrolesupdater.h"
#include "kfileitemmodel.h"
+#include "private/kdirectorycontentscounter.h"
+#include "private/kpixmapmodifier.h"
#include <KConfig>
#include <KConfigGroup>
-#include <KSharedConfig>
-#include <KFileItem>
-#include <KIconLoader>
-#include <KJobWidgets>
#include <KIO/JobUiDelegate>
#include <KIO/PreviewJob>
-#include <KPluginLoader>
+#include <KIconLoader>
+#include <KJobWidgets>
#include <KOverlayIconPlugin>
+#include <KPluginLoader>
+#include <KSharedConfig>
-#include "private/kpixmapmodifier.h"
-#include "private/kdirectorycontentscounter.h"
+#ifdef HAVE_BALOO
+#include "private/kbaloorolesprovider.h"
+#include <Baloo/File>
+#include <Baloo/FileMonitor>
+#endif
#include <QApplication>
+#include <QIcon>
#include <QPainter>
-#include <QPixmap>
#include <QElapsedTimer>
#include <QTimer>
-#include <algorithm>
-
-#ifdef HAVE_BALOO
- #include "private/kbaloorolesprovider.h"
- #include <Baloo/File>
- #include <Baloo/FileMonitor>
-#endif
-
-
// #define KFILEITEMMODELROLESUPDATER_DEBUG
namespace {
m_roles(),
m_resolvableRoles(),
m_enabledPlugins(),
+ m_localFileSizePreviewLimit(0),
+ m_scanDirectories(true),
m_pendingSortRoleItems(),
m_pendingIndexes(),
m_pendingPreviewItems(),
m_previewJob(),
- m_recentlyChangedItemsTimer(0),
+ m_recentlyChangedItemsTimer(nullptr),
m_recentlyChangedItems(),
m_changedItems(),
- m_directoryContentsCounter(0)
+ m_directoryContentsCounter(nullptr)
#ifdef HAVE_BALOO
- , m_balooFileMonitor(0)
+ , m_balooFileMonitor(nullptr)
#endif
{
Q_ASSERT(model);
const KConfigGroup globalConfig(KSharedConfig::openConfig(), "PreviewSettings");
- m_enabledPlugins = globalConfig.readEntry("Plugins", QStringList()
- << QStringLiteral("directorythumbnail")
- << QStringLiteral("imagethumbnail")
- << QStringLiteral("jpegthumbnail"));
+ m_enabledPlugins = globalConfig.readEntry("Plugins", KIO::PreviewJob::defaultPlugins());
+ m_localFileSizePreviewLimit = static_cast<qulonglong>(globalConfig.readEntry("MaximumSize", 0));
connect(m_model, &KFileItemModel::itemsInserted,
this, &KFileItemModelRolesUpdater::slotItemsInserted);
this, &KFileItemModelRolesUpdater::slotSortRoleChanged);
// Use a timer to prevent that each call of slotItemsChanged() results in a synchronous
- // resolving of the roles. Postpone the resolving until no update has been done for 1 second.
+ // resolving of the roles. Postpone the resolving until no update has been done for 100 ms.
m_recentlyChangedItemsTimer = new QTimer(this);
- m_recentlyChangedItemsTimer->setInterval(1000);
+ m_recentlyChangedItemsTimer->setInterval(100);
m_recentlyChangedItemsTimer->setSingleShot(true);
connect(m_recentlyChangedItemsTimer, &QTimer::timeout, this, &KFileItemModelRolesUpdater::resolveRecentlyChangedItems);
connect(m_directoryContentsCounter, &KDirectoryContentsCounter::result,
this, &KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived);
- auto plugins = KPluginLoader::instantiatePlugins(QStringLiteral("kf5/overlayicon"), nullptr, qApp);
- foreach (QObject *it, plugins) {
+ const auto plugins = KPluginLoader::instantiatePlugins(QStringLiteral("kf5/overlayicon"), nullptr, qApp);
+ for (QObject *it : plugins) {
auto plugin = qobject_cast<KOverlayIconPlugin*>(it);
if (plugin) {
m_overlayIconsPlugin.append(plugin);
this, &KFileItemModelRolesUpdater::applyChangedBalooRoles);
} else if (!hasBalooRole && m_balooFileMonitor) {
delete m_balooFileMonitor;
- m_balooFileMonitor = 0;
+ m_balooFileMonitor = nullptr;
}
#endif
return m_enabledPlugins;
}
+void KFileItemModelRolesUpdater::setLocalFileSizePreviewLimit(const qlonglong size)
+{
+ m_localFileSizePreviewLimit = size;
+}
+
+qlonglong KFileItemModelRolesUpdater::localFileSizePreviewLimit() const
+{
+ return m_localFileSizePreviewLimit;
+}
+
+void KFileItemModelRolesUpdater::setScanDirectories(bool enabled)
+{
+ m_scanDirectories = enabled;
+}
+
+bool KFileItemModelRolesUpdater::scanDirectories() const
+{
+ return m_scanDirectories;
+}
+
void KFileItemModelRolesUpdater::slotItemsInserted(const KItemRangeList& itemRanges)
{
QElapsedTimer timer;
// Determine the sort role synchronously for as many items as possible.
if (m_resolvableRoles.contains(m_model->sortRole())) {
int insertedCount = 0;
- foreach (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) {
void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRanges)
{
- Q_UNUSED(itemRanges);
+ Q_UNUSED(itemRanges)
const bool allItemsRemoved = (m_model->count() == 0);
m_balooFileMonitor->clear();
} else {
QStringList newFileList;
- foreach (const QString& file, m_balooFileMonitor->files()) {
+ const QStringList oldFileList = m_balooFileMonitor->files();
+ for (const QString& file : oldFileList) {
if (m_model->index(QUrl::fromLocalFile(file)) >= 0) {
newFileList.append(file);
}
}
}
-void KFileItemModelRolesUpdater::slotItemsMoved(const KItemRange& itemRange, QList<int> movedToIndexes)
+void KFileItemModelRolesUpdater::slotItemsMoved(const KItemRange& itemRange, const QList<int> &movedToIndexes)
{
- Q_UNUSED(itemRange);
- Q_UNUSED(movedToIndexes);
+ Q_UNUSED(itemRange)
+ Q_UNUSED(movedToIndexes)
// The visible items might have changed.
startUpdating();
void KFileItemModelRolesUpdater::slotItemsChanged(const KItemRangeList& itemRanges,
const QSet<QByteArray>& roles)
{
- Q_UNUSED(roles);
+ Q_UNUSED(roles)
// Find out if slotItemsChanged() has been done recently. If that is the
// case, resolving the roles is postponed until a timer has exceeded
QSet<KFileItem>& targetSet = itemsChangedRecently ? m_recentlyChangedItems : m_changedItems;
- foreach (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);
void KFileItemModelRolesUpdater::slotSortRoleChanged(const QByteArray& current,
const QByteArray& previous)
{
- Q_UNUSED(current);
- Q_UNUSED(previous);
+ Q_UNUSED(current)
+ Q_UNUSED(previous)
if (m_resolvableRoles.contains(current)) {
m_pendingSortRoleItems.clear();
QPixmap scaledPixmap = pixmap;
- const QString mimeType = item.mimetype();
- const int slashIndex = mimeType.indexOf(QLatin1Char('/'));
- const QString mimeTypeGroup = mimeType.left(slashIndex);
- if (mimeTypeGroup == QLatin1String("image")) {
+ if (!pixmap.hasAlpha() && !pixmap.isNull()
+ && m_iconSize.width() > KIconLoader::SizeSmallMedium
+ && m_iconSize.height() > KIconLoader::SizeSmallMedium) {
if (m_enlargeSmallPreviews) {
KPixmapModifier::applyFrame(scaledPixmap, m_iconSize);
} else {
scaledPixmap);
scaledPixmap = largeFrame;
} else {
- // The image must be shrinked as it is too large to fit into
+ // The image must be shrunk as it is too large to fit into
// the available icon size
KPixmapModifier::applyFrame(scaledPixmap, m_iconSize);
}
}
- } else {
- KPixmapModifier::scale(scaledPixmap, m_iconSize);
+ } else if (!pixmap.isNull()) {
+ KPixmapModifier::scale(scaledPixmap, m_iconSize * qApp->devicePixelRatio());
+ scaledPixmap.setDevicePixelRatio(qApp->devicePixelRatio());
}
QHash<QByteArray, QVariant> data = rolesData(item);
// It is more efficient to do it here, as KIconLoader::drawOverlays()
// assumes that an overlay will be drawn and has some additional
// setup time.
- foreach (const QString& overlay, overlays) {
- if (!overlay.isEmpty()) {
- // There is at least one overlay, draw all overlays above m_pixmap
- // and cancel the check
- KIconLoader::global()->drawOverlays(overlays, scaledPixmap, KIconLoader::Desktop);
- break;
+ if (!scaledPixmap.isNull()) {
+ for (const QString& overlay : overlays) {
+ if (!overlay.isEmpty()) {
+ // There is at least one overlay, draw all overlays above m_pixmap
+ // and cancel the check
+ KIconLoader::global()->drawOverlays(overlays, scaledPixmap, KIconLoader::Desktop);
+ break;
+ }
}
}
void KFileItemModelRolesUpdater::slotPreviewJobFinished()
{
- m_previewJob = 0;
+ m_previewJob = nullptr;
if (m_state != PreviewJobRunning) {
return;
return;
}
applyChangedBalooRolesForItem(item);
+#else
+ Q_UNUSED(file)
#endif
}
const KBalooRolesProvider& rolesProvider = KBalooRolesProvider::instance();
QHash<QByteArray, QVariant> data;
- foreach (const QByteArray& role, rolesProvider.roles()) {
+ const auto roles = rolesProvider.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
this, &KFileItemModelRolesUpdater::slotItemsChanged);
#else
#ifndef Q_CC_MSVC
- Q_UNUSED(item);
+ Q_UNUSED(item)
#endif
#endif
}
-void KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived(const QString& path, int count)
+void KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived(const QString& path, int count, long size)
{
const bool getSizeRole = m_roles.contains("size");
const bool getIsExpandableRole = m_roles.contains("isExpandable");
QHash<QByteArray, QVariant> data;
if (getSizeRole) {
- data.insert("size", count);
+ data.insert("count", count);
+ data.insert("size", QVariant::fromValue(size));
}
if (getIsExpandableRole) {
data.insert("isExpandable", count > 0);
this, &KFileItemModelRolesUpdater::slotItemsChanged);
m_model->setData(index, data);
connect(m_model, &KFileItemModel::itemsChanged,
- this, &KFileItemModelRolesUpdater::slotItemsChanged);
+ this, &KFileItemModelRolesUpdater::slotItemsChanged);
}
}
}
m_pendingPreviewItems.clear();
m_pendingPreviewItems.reserve(indexes.count());
- foreach (int index, indexes) {
+ for (int index : qAsConst(indexes)) {
const KFileItem item = m_model->fileItem(index);
if (!m_finishedItems.contains(item)) {
m_pendingPreviewItems.append(item);
KIO::PreviewJob* job = new KIO::PreviewJob(itemSubSet, cacheSize, &m_enabledPlugins);
- job->setIgnoreMaximumSize(itemSubSet.first().isLocalFile());
- if (job->ui()) {
+ job->setIgnoreMaximumSize(itemSubSet.first().isLocalFile() && m_localFileSizePreviewLimit <= 0);
+ if (job->uiDelegate()) {
KJobWidgets::setWindow(job, qApp->activeWindow());
}
QList<int> visibleChangedIndexes;
QList<int> invisibleChangedIndexes;
+ visibleChangedIndexes.reserve(m_changedItems.size());
+ invisibleChangedIndexes.reserve(m_changedItems.size());
- foreach (const KFileItem& item, m_changedItems) {
+ auto changedItemsIt = m_changedItems.begin();
+ while (changedItemsIt != m_changedItems.end()) {
+ const auto& item = *changedItemsIt;
const int index = m_model->index(item);
if (index < 0) {
- m_changedItems.remove(item);
+ changedItemsIt = m_changedItems.erase(changedItemsIt);
continue;
}
+ ++changedItemsIt;
if (index >= m_firstVisibleIndex && index <= m_lastVisibleIndex) {
visibleChangedIndexes.append(index);
std::sort(visibleChangedIndexes.begin(), visibleChangedIndexes.end());
if (m_previewShown) {
- foreach (int index, visibleChangedIndexes) {
+ for (int index : qAsConst(visibleChangedIndexes)) {
m_pendingPreviewItems.append(m_model->fileItem(index));
}
- foreach (int index, invisibleChangedIndexes) {
+ for (int index : qAsConst(invisibleChangedIndexes)) {
m_pendingPreviewItems.append(m_model->fileItem(index));
}
data.insert("type", item.mimeComment());
} else if (m_model->sortRole() == "size" && item.isLocalFile() && item.isDir()) {
const QString path = item.localPath();
- data.insert("size", m_directoryContentsCounter->countDirectoryContentsSynchronously(path));
+ if (m_scanDirectories) {
+ m_directoryContentsCounter->scanDirectory(path);
+ }
} else {
// Probably the sort role is a baloo role - just determine all roles.
data = rolesData(item);
data = rolesData(item);
}
- data.insert("iconName", item.iconName());
+ if (!item.iconName().isEmpty()) {
+ data.insert("iconName", item.iconName());
+ }
if (m_clearPreviews) {
data.insert("iconPixmap", QPixmap());
if (item.isLocalFile()) {
// Tell m_directoryContentsCounter that we want to count the items
// inside the directory. The result will be received in slotDirectoryContentsCountReceived.
- const QString path = item.localPath();
- m_directoryContentsCounter->addDirectory(path);
+ 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
}
}
QStringList overlays = item.overlays();
- foreach(KOverlayIconPlugin *it, m_overlayIconsPlugin) {
+ for (KOverlayIconPlugin *it : qAsConst(m_overlayIconsPlugin)) {
overlays.append(it->getOverlays(item.url()));
}
data.insert("iconOverlays", overlays);
const int index = m_model->index(item);
QHash<QByteArray, QVariant> data = m_model->data(index);
QStringList overlays = item.overlays();
- foreach (KOverlayIconPlugin *it, m_overlayIconsPlugin) {
+ for (KOverlayIconPlugin *it : qAsConst(m_overlayIconsPlugin)) {
overlays.append(it->getOverlays(url));
}
data.insert("iconOverlays", overlays);
disconnect(m_previewJob, &KIO::PreviewJob::finished,
this, &KFileItemModelRolesUpdater::slotPreviewJobFinished);
m_previewJob->kill();
- m_previewJob = 0;
+ m_previewJob = nullptr;
m_pendingPreviewItems.clear();
}
}
const int count = m_model->count();
QList<int> result;
- result.reserve(ResolveAllItemsLimit);
+ result.reserve(qMin(count, (m_lastVisibleIndex - m_firstVisibleIndex + 1) +
+ ResolveAllItemsLimit +
+ (2 * m_maximumVisibleItems)));
// Add visible items.
for (int i = m_firstVisibleIndex; i <= m_lastVisibleIndex; ++i) {
// We need a reasonable upper limit for number of items to resolve after
// and before the visible range. m_maximumVisibleItems can be quite large
- // when using Compace View.
+ // when using Compact View.
const int readAheadItems = qMin(ReadAheadPages * m_maximumVisibleItems, ResolveAllItemsLimit / 2);
// Add items after the visible range.
}
// Add items on the last page.
- const int beginLastPage = qMax(qMin(endExtendedVisibleRange + 1, count - 1), count - m_maximumVisibleItems);
+ const int beginLastPage = qMax(endExtendedVisibleRange + 1, count - m_maximumVisibleItems);
for (int i = beginLastPage; i < count; ++i) {
result.append(i);
}
// Add items on the first page.
- const int endFirstPage = qMin(qMax(beginExtendedVisibleRange - 1, 0), m_maximumVisibleItems);
- for (int i = 0; i <= endFirstPage; ++i) {
+ const int endFirstPage = qMin(beginExtendedVisibleRange, m_maximumVisibleItems);
+ for (int i = 0; i < endFirstPage; ++i) {
result.append(i);
}
--remainingItems;
}
- for (int i = beginExtendedVisibleRange - 1; i > endFirstPage && remainingItems > 0; --i) {
+ for (int i = beginExtendedVisibleRange - 1; i >= endFirstPage && remainingItems > 0; --i) {
result.append(i);
--remainingItems;
}