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

wallpapers/image: Add AbstractImageListModel class

This serves as the base class for image list models.
parent 9a473c82
/*
SPDX-FileCopyrightText: 2022 Fushan Wen <qydwhotmail@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "abstractimagelistmodel.h"
#include <QPixmap>
#include <QThreadPool>
#include <KFileItem>
#include <KIO/PreviewJob>
#include "../finder/imagesizefinder.h"
AbstractImageListModel::AbstractImageListModel(const QSize &targetSize, QObject *parent)
: QAbstractListModel(parent)
, m_screenshotSize(targetSize / 8)
, m_targetSize(targetSize)
{
m_imageCache.setMaxCost(m_screenshotSize.width() * m_screenshotSize.height() * 20);
m_imageSizeCache.setMaxCost(20);
connect(this, &QAbstractListModel::rowsInserted, this, &AbstractImageListModel::countChanged);
connect(this, &QAbstractListModel::rowsRemoved, this, &AbstractImageListModel::countChanged);
connect(this, &QAbstractListModel::modelReset, this, &AbstractImageListModel::countChanged);
}
QHash<int, QByteArray> AbstractImageListModel::roleNames() const
{
return {
{Qt::DisplayRole, "display"},
{Qt::DecorationRole, "decoration"},
{AuthorRole, "author"},
{ScreenshotRole, "screenshot"},
{PathRole, "path"},
{PackageNameRole, "packageName"},
{RemovableRole, "removable"},
{PendingDeletionRole, "pendingDeletion"},
{ToggleRole, "checked"},
};
}
int AbstractImageListModel::count() const
{
return rowCount();
}
void AbstractImageListModel::reload()
{
if (m_loading || m_customPaths.empty()) {
return;
}
load(m_customPaths);
}
void AbstractImageListModel::slotTargetSizeChanged(const QSize &size)
{
m_targetSize = size;
reload();
}
void AbstractImageListModel::slotHandleImageSizeFound(const QString &path, const QSize &size)
{
const QPersistentModelIndex index = m_sizeJobsUrls.take(path);
if (m_imageSizeCache.insert(path, new QSize(size), 1)) {
Q_EMIT dataChanged(index, index, {ResolutionRole});
}
}
void AbstractImageListModel::slotHandlePreview(const KFileItem &item, const QPixmap &preview)
{
const QString urlString = item.url().toLocalFile();
const QPersistentModelIndex pidx = m_previewJobsUrls.take(urlString);
QModelIndex idx;
if (!pidx.isValid()) {
if (int row = indexOf(urlString); row >= 0) {
idx = index(row, 0);
} else {
return;
}
} else {
idx = pidx;
}
const int cost = preview.width() * preview.height() * preview.depth() / 8;
if (m_imageCache.insert(urlString, new QPixmap(preview), cost)) {
Q_EMIT dataChanged(idx, idx, {ScreenshotRole});
}
}
void AbstractImageListModel::slotHandlePreviewFailed(const KFileItem &item)
{
m_previewJobsUrls.remove(item.url().toLocalFile());
}
void AbstractImageListModel::asyncGetPreview(const QString &path, const QPersistentModelIndex &index) const
{
if (m_previewJobsUrls.contains(path) || path.isEmpty()) {
return;
}
const QUrl url = QUrl::fromLocalFile(path);
const QStringList availablePlugins = KIO::PreviewJob::availablePlugins();
KIO::PreviewJob *const job = KIO::filePreview(KFileItemList{KFileItem(url, QString(), 0)}, m_screenshotSize, &availablePlugins);
job->setIgnoreMaximumSize(true);
connect(job, &KIO::PreviewJob::gotPreview, this, &AbstractImageListModel::slotHandlePreview);
connect(job, &KIO::PreviewJob::failed, this, &AbstractImageListModel::slotHandlePreviewFailed);
m_previewJobsUrls.insert(path, index);
}
void AbstractImageListModel::asyncGetImageSize(const QString &path, const QPersistentModelIndex &index) const
{
if (m_sizeJobsUrls.contains(path) || path.isEmpty()) {
return;
}
ImageSizeFinder *finder = new ImageSizeFinder(path);
connect(finder, &ImageSizeFinder::sizeFound, this, &AbstractImageListModel::slotHandleImageSizeFound);
QThreadPool::globalInstance()->start(finder);
m_sizeJobsUrls.insert(path, index);
}
/*
SPDX-FileCopyrightText: 2022 Fushan Wen <qydwhotmail@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef ABSTRACTIMAGELISTMODEL_H
#define ABSTRACTIMAGELISTMODEL_H
#include <QAbstractListModel>
#include <QCache>
#include <QSize>
#include "imageroles.h"
class QPixmap;
class KFileItem;
/**
* Base class for image list model.
*/
class AbstractImageListModel : public QAbstractListModel, public ImageRoles
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
public:
explicit AbstractImageListModel(const QSize &targetSize, QObject *parent = nullptr);
QHash<int, QByteArray> roleNames() const override;
int count() const;
virtual int indexOf(const QString &path) const = 0;
virtual void load(const QStringList &customPaths = {}) = 0;
/**
* Reload when target size changes or a new package is installed
*/
void reload();
public Q_SLOTS:
virtual QStringList addBackground(const QString &path) = 0;
/**
* @return removed files that should be removed from \KDirWatch
*/
virtual QStringList removeBackground(const QString &path) = 0;
void slotTargetSizeChanged(const QSize &size);
Q_SIGNALS:
void countChanged();
void loaded(AbstractImageListModel *model);
protected:
void asyncGetPreview(const QString &path, const QPersistentModelIndex &index) const;
void asyncGetImageSize(const QString &path, const QPersistentModelIndex &index) const;
bool m_loading = false;
QSize m_screenshotSize;
QSize m_targetSize;
QCache<QString, QPixmap> m_imageCache;
QCache<QString, QSize> m_imageSizeCache;
mutable QHash<QString, QPersistentModelIndex> m_previewJobsUrls;
mutable QHash<QString, QPersistentModelIndex> m_sizeJobsUrls;
QHash<QString, bool> m_pendingDeletion;
QStringList m_removableWallpapers;
QStringList m_customPaths;
private Q_SLOTS:
void slotHandleImageSizeFound(const QString &path, const QSize &size);
void slotHandlePreview(const KFileItem &item, const QPixmap &preview);
void slotHandlePreviewFailed(const KFileItem &item);
};
#endif // ABSTRACTIMAGELISTMODEL_H
/*
SPDX-FileCopyrightText: 2022 Fushan Wen <qydwhotmail@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef IMAGEROLES_H
#define IMAGEROLES_H
class ImageRoles
{
Q_GADGET
public:
enum RoleType {
AuthorRole = Qt::UserRole,
ScreenshotRole,
ResolutionRole,
PathRole,
PackageNameRole,
RemovableRole,
PendingDeletionRole,
ToggleRole, /**< Used in slideshow model */
};
Q_ENUM(RoleType)
};
#endif
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