Verified Commit fa8abc50 authored by Fushan Wen's avatar Fushan Wen 💬
Browse files

wallpapers/image: show light&&dark images side by side in previews

CCBUG: 207976
parent 909a7ad9
Pipeline #186803 passed with stage
in 6 minutes and 10 seconds
......@@ -6,6 +6,7 @@
#include "abstractimagelistmodel.h"
#include <QPainter>
#include <QThreadPool>
#include <KFileItem>
......@@ -72,48 +73,95 @@ void AbstractImageListModel::slotHandleImageSizeFound(const QString &path, const
void AbstractImageListModel::slotHandlePreview(const KFileItem &item, const QPixmap &preview)
{
auto job = qobject_cast<KIO::PreviewJob *>(sender());
if (!job) {
return;
}
const QString urlString = item.url().toLocalFile();
const QPersistentModelIndex pidx = m_previewJobsUrls.take(urlString);
QModelIndex idx;
const QPersistentModelIndex idx = job->property("index").toPersistentModelIndex();
if (!pidx.isValid()) {
if (int row = indexOf(urlString); row >= 0) {
idx = index(row, 0);
} else {
return;
}
auto it = m_previewJobsUrls.find(idx);
Q_ASSERT(it != m_previewJobsUrls.end());
it->removeOne(urlString);
const QStringList paths = job->property("paths").toStringList();
QPixmap *cachedPreview = m_imageCache.object(paths);
if (!cachedPreview) {
// Insert full preview
m_imageCache.insert(paths, new QPixmap(preview), 0);
} else {
idx = pidx;
// Show multiple images side by side
QPainter p(cachedPreview);
const int i = paths.indexOf(urlString);
const double start = i / static_cast<double>(paths.size());
const double end = (i + 1) / static_cast<double>(paths.size());
// Cropped area
const QPoint topLeft(start * preview.width(), 0);
const QPoint bottomRight(end * preview.width(), preview.height());
// Inserted area
const QPoint topLeft2(start * cachedPreview->width(), 0);
const QPoint bottomRight2(end * cachedPreview->width(), cachedPreview->height());
p.drawPixmap(QRect(topLeft2, bottomRight2), preview.copy(QRect(topLeft, bottomRight)));
}
const int cost = preview.width() * preview.height() * preview.depth() / 8;
if (it->empty()) {
// All images in the list have been loaded
m_previewJobsUrls.erase(it);
if (m_imageCache.insert(urlString, new QPixmap(preview), cost)) {
Q_EMIT dataChanged(idx, idx, {ScreenshotRole});
cachedPreview = m_imageCache.object(paths);
auto finalPreview = new QPixmap(*cachedPreview);
if (m_imageCache.insert(paths, finalPreview, 1)) {
Q_EMIT dataChanged(idx, idx, {ScreenshotRole});
} else {
delete finalPreview;
}
}
}
void AbstractImageListModel::slotHandlePreviewFailed(const KFileItem &item)
{
m_previewJobsUrls.remove(item.url().toLocalFile());
auto job = qobject_cast<KIO::PreviewJob *>(sender());
if (!job) {
return;
}
auto it = m_previewJobsUrls.find(job->property("index").toPersistentModelIndex());
Q_ASSERT(it != m_previewJobsUrls.end());
it->removeOne(item.url().toLocalFile());
if (it->empty()) {
m_previewJobsUrls.erase(it);
}
}
void AbstractImageListModel::asyncGetPreview(const QString &path, const QPersistentModelIndex &index) const
void AbstractImageListModel::asyncGetPreview(const QStringList &paths, const QPersistentModelIndex &index) const
{
if (m_previewJobsUrls.contains(path) || path.isEmpty()) {
if (m_previewJobsUrls.contains(index) || paths.isEmpty()) {
return;
}
const QUrl url = QUrl::fromLocalFile(path);
const QStringList availablePlugins = KIO::PreviewJob::availablePlugins();
KFileItemList list;
for (const QString &path : paths) {
list.append(KFileItem(QUrl::fromLocalFile(path), QString(), 0));
}
KIO::PreviewJob *const job = KIO::filePreview(KFileItemList{KFileItem(url, QString(), 0)}, m_screenshotSize, &availablePlugins);
KIO::PreviewJob *const job = KIO::filePreview(list, m_screenshotSize, &availablePlugins);
job->setIgnoreMaximumSize(true);
job->setProperty("paths", paths);
job->setProperty("index", index);
connect(job, &KIO::PreviewJob::gotPreview, this, &AbstractImageListModel::slotHandlePreview);
connect(job, &KIO::PreviewJob::failed, this, &AbstractImageListModel::slotHandlePreviewFailed);
m_previewJobsUrls.insert(path, index);
m_previewJobsUrls.insert(index, paths);
}
void AbstractImageListModel::asyncGetImageSize(const QString &path, const QPersistentModelIndex &index) const
......
......@@ -53,7 +53,13 @@ Q_SIGNALS:
void loaded(AbstractImageListModel *model);
protected:
void asyncGetPreview(const QString &path, const QPersistentModelIndex &index) const;
/**
* Asynchronously generates a preview.
* Multiple images are displayed side by side following the order in @c paths
*
* @note @c paths should have no duplicate urls.
*/
void asyncGetPreview(const QStringList &paths, const QPersistentModelIndex &index) const;
void asyncGetImageSize(const QString &path, const QPersistentModelIndex &index) const;
bool m_loading = false;
......@@ -61,10 +67,10 @@ protected:
QSize m_screenshotSize;
QSize m_targetSize;
QCache<QString, QPixmap> m_imageCache;
QCache<QStringList, QPixmap> m_imageCache;
QCache<QString, QSize> m_imageSizeCache;
mutable QHash<QString, QPersistentModelIndex> m_previewJobsUrls;
mutable QHash<QPersistentModelIndex, QStringList> m_previewJobsUrls;
mutable QHash<QString, QPersistentModelIndex> m_sizeJobsUrls;
QHash<QString, bool> m_pendingDeletion;
......
......@@ -41,13 +41,13 @@ QVariant ImageListModel::data(const QModelIndex &index, int role) const
return QFileInfo(m_data.at(row)).completeBaseName();
case ScreenshotRole: {
QPixmap *cachedPreview = m_imageCache.object(m_data.at(row));
QPixmap *cachedPreview = m_imageCache.object({m_data.at(row)});
if (cachedPreview) {
return *cachedPreview;
}
asyncGetPreview(m_data.at(row), QPersistentModelIndex(index));
asyncGetPreview({m_data.at(row)}, QPersistentModelIndex(index));
return QVariant();
}
......
......@@ -46,15 +46,20 @@ QVariant PackageListModel::data(const QModelIndex &index, int role) const
return PackageFinder::packageDisplayName(b);
case ScreenshotRole: {
const QString path = b.filePath("preferred");
QStringList paths{b.filePath(QByteArrayLiteral("preferred"))};
const QString darkPath = b.filePath(QByteArrayLiteral("preferredDark"));
if (!darkPath.isEmpty()) {
paths.append(darkPath);
}
QPixmap *cachedPreview = m_imageCache.object(path);
QPixmap *cachedPreview = m_imageCache.object(paths);
if (cachedPreview) {
return *cachedPreview;
}
asyncGetPreview(path, QPersistentModelIndex(index));
asyncGetPreview(paths, QPersistentModelIndex(index));
return QVariant();
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment