// Determine the sort role synchronously for as many items as possible.
if (m_resolvableRoles.contains(m_model->sortRole()) || m_resolvableRoles.contains(m_model->groupRole())) {
+ QList<QUrl> dirsWithAddedItems;
int insertedCount = 0;
for (const KItemRange &range : itemRanges) {
const int lastIndex = insertedCount + range.index + range.count - 1;
for (int i = insertedCount + range.index; i <= lastIndex; ++i) {
+ const auto fileItem = m_model->fileItem(i);
+ const auto fileItemParentFolderUrl = fileItem.url().adjusted(QUrl::RemoveFilename);
+ if (!dirsWithAddedItems.contains(fileItemParentFolderUrl)) {
+ dirsWithAddedItems.append(fileItemParentFolderUrl);
+ }
if (timer.elapsed() < MaxBlockTimeout) {
applySortRole(i);
} else {
- m_pendingSortRoleItems.insert(m_model->fileItem(i));
+ m_pendingSortRoleItems.insert(fileItem);
}
}
insertedCount += range.count;
}
+ recountDirectoryItems(dirsWithAddedItems);
+
applySortProgressToModel();
// If there are still items whose sort role is unknown, check if the
m_directoryContentsCounter->stopWorker();
}
} else {
+ QList<QUrl> dirsWithDeletedItems;
// Only remove the items from m_finishedItems. They will be removed
// from the other sets later on.
QSet<KFileItem>::iterator it = m_finishedItems.begin();
while (it != m_finishedItems.end()) {
if (m_model->index(*it) < 0) {
+ // Get the folder path of the file.
+ const auto folderUrl = it->url().adjusted(QUrl::RemoveFilename);
+ if (!dirsWithDeletedItems.contains(folderUrl)) {
+ dirsWithDeletedItems.append(folderUrl);
+ }
it = m_finishedItems.erase(it);
} else {
++it;
}
}
+ recountDirectoryItems(dirsWithDeletedItems);
+
// Removed items won't have hover previews loaded anymore.
for (const KItemRange &itemRange : itemRanges) {
int index = itemRange.index;
return;
}
- QPixmap scaledPixmap = transformPreviewPixmap(pixmap);
-
QHash<QByteArray, QVariant> data = rolesData(item, index);
-
- const QStringList overlays = data["iconOverlays"].toStringList();
- // Strangely KFileItem::overlays() returns empty string-values, so
- // we need to check first whether an overlay must be drawn at all.
- 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
- const QSize size = scaledPixmap.size();
- scaledPixmap = KIconUtils::addOverlays(scaledPixmap, overlays).pixmap(size);
- break;
- }
- }
- }
-
- data.insert("iconPixmap", scaledPixmap);
+ data.insert("iconPixmap", transformPreviewPixmap(pixmap));
+ data.insert("supportsSequencing", m_previewJob->handlesSequences());
disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged);
m_model->setData(index, data);
connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged);
+ Q_EMIT previewJobFinished(); // For unit testing
m_finishedItems.insert(item);
}
return;
}
- // PreviewJob internally caches items always with the size of
- // 128 x 128 pixels or 256 x 256 pixels. A (slow) downscaling is done
- // 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);
-
// 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
// a blocking, we only pass items with known mime type to the preview job.
} 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->setDevicePixelRatio(m_devicePixelRatio);
job->setIgnoreMaximumSize(itemSubSet.first().isLocalFile() && !itemSubSet.first().isSlow() && m_localFileSizePreviewLimit <= 0);
if (job->uiDelegate()) {
{
QPixmap scaledPixmap = pixmap;
- if (!pixmap.hasAlpha() && !pixmap.isNull() && m_iconSize.width() > KIconLoader::SizeSmallMedium && m_iconSize.height() > KIconLoader::SizeSmallMedium) {
+ if (pixmap.isNull()) {
+ return scaledPixmap;
+ }
+
+ if (!pixmap.hasAlpha() && m_iconSize.width() > KIconLoader::SizeSmallMedium && m_iconSize.height() > KIconLoader::SizeSmallMedium) {
if (m_enlargeSmallPreviews) {
KPixmapModifier::applyFrame(scaledPixmap, m_iconSize);
} else {
KPixmapModifier::applyFrame(scaledPixmap, m_iconSize);
}
}
- } else if (!pixmap.isNull()) {
+ } else {
KPixmapModifier::scale(scaledPixmap, m_iconSize * m_devicePixelRatio);
scaledPixmap.setDevicePixelRatio(m_devicePixelRatio);
}
return scaledPixmap;
}
+QSize KFileItemModelRolesUpdater::cacheSize()
+{
+ // PreviewJob internally caches items always with the size of
+ // 128 x 128 pixels or 256 x 256 pixels. A (slow) downscaling is done
+ // 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.
+ return (m_iconSize.width() > 128) || (m_iconSize.height() > 128) ? QSize(256, 256) : QSize(128, 128);
+}
+
void KFileItemModelRolesUpdater::loadNextHoverSequencePreview()
{
if (m_hoverSequenceItem.isNull() || m_hoverSequencePreviewJob) {
return;
}
- // PreviewJob internally caches items always with the size of
- // 128 x 128 pixels or 256 x 256 pixels. A (slow) downscaling is done
- // 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);
-
- 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_hoverSequenceItem.isSlow() && m_localFileSizePreviewLimit <= 0);
void KFileItemModelRolesUpdater::startDirectorySizeCounting(const KFileItem &item, int index)
{
- if (ContentDisplaySettings::directorySizeMode() == ContentDisplaySettings::EnumDirectorySizeMode::None || !item.isLocalFile()) {
+ if (ContentDisplaySettings::directorySizeMode() == ContentDisplaySettings::EnumDirectorySizeMode::None) {
+ return;
+ }
+
+ // Set any remote files to unknown size (-1).
+ if (!item.isLocalFile()) {
+ resetSizeData(index, -1);
return;
+ } else {
+ resetSizeData(index);
}
if (ContentDisplaySettings::directorySizeMode() == ContentDisplaySettings::EnumDirectorySizeMode::ContentCount || item.isSlow()) {
// fastpath no recursion necessary
-
auto data = m_model->data(index);
if (data.value("size") == -2) {
// means job already started
connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged);
auto listJob = KIO::listDir(url, KIO::HideProgressInfo);
- QObject::connect(listJob, &KIO::ListJob::entries, this, [this, item](const KJob * /*job*/, const KIO::UDSEntryList &list) {
+
+ QObject::connect(listJob, &KIO::ListJob::entries, this, [this, item](const KJob *job, const KIO::UDSEntryList &list) {
int index = m_model->index(item);
if (index < 0) {
return;
}
auto data = m_model->data(index);
int origCount = data.value("count").toInt();
- int entryCount = origCount;
+ // Get the amount of processed items...
+ int entryCount = job->processedAmount(KJob::Bytes);
+ // ...and then remove the unwanted items from the amount.
for (const KIO::UDSEntry &entry : list) {
const auto name = entry.stringValue(KIO::UDSEntry::UDS_NAME);
if (name == QStringLiteral("..") || name == QStringLiteral(".")) {
+ --entryCount;
continue;
}
if (!m_model->showHiddenFiles() && name.startsWith(QLatin1Char('.'))) {
+ --entryCount;
continue;
}
if (m_model->showDirectoriesOnly() && !entry.isDir()) {
+ --entryCount;
continue;
}
- ++entryCount;
}
QHash<QByteArray, QVariant> newData;
}
if (origCount != entryCount) {
- // count has changed
newData.insert("count", entryCount);
}
}
}
+void KFileItemModelRolesUpdater::resetSizeData(const int index, const int size)
+{
+ disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged);
+ auto data = m_model->data(index);
+ data.insert("size", size);
+ m_model->setData(index, data);
+ connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged);
+}
+
+void KFileItemModelRolesUpdater::recountDirectoryItems(const QList<QUrl> directories)
+{
+ for (const auto &dir : directories) {
+ auto index = m_model->index(dir);
+ if (index < 0) {
+ continue;
+ }
+ auto item = m_model->fileItem(index);
+ if (item.isDir()) {
+ startDirectorySizeCounting(item, index);
+ }
+ }
+}
+
#include "moc_kfileitemmodelrolesupdater.cpp"