Spectral/src/matriximageprovider.cpp

116 lines
3.3 KiB
C++
Raw Normal View History

#include "matriximageprovider.h"
2018-03-02 08:56:36 +00:00
#include <QDir>
#include <QFileInfo>
#include <QStandardPaths>
2019-01-04 12:17:26 +00:00
#include <QtCore/QDebug>
#include <QtCore/QThread>
2018-03-02 08:56:36 +00:00
2019-01-04 12:17:26 +00:00
using QMatrixClient::BaseJob;
2018-03-02 08:56:36 +00:00
ThumbnailResponse::ThumbnailResponse(QMatrixClient::Connection* c,
QString id,
const QSize& size)
: c(c),
mediaId(std::move(id)),
requestedSize(size),
localFile(QStringLiteral("%1/image_provider/%2-%3x%4.png")
.arg(QStandardPaths::writableLocation(
QStandardPaths::CacheLocation),
mediaId,
QString::number(requestedSize.width()),
QString::number(requestedSize.height()))),
errorStr("Image request hasn't started") {
2019-01-04 12:17:26 +00:00
if (requestedSize.isEmpty()) {
errorStr.clear();
emit finished();
return;
2018-07-09 02:45:26 +00:00
}
2019-01-04 12:17:26 +00:00
if (mediaId.count('/') != 1) {
errorStr =
tr("Media id '%1' doesn't follow server/mediaId pattern").arg(mediaId);
2019-01-04 12:17:26 +00:00
emit finished();
return;
}
QImage cachedImage;
if (cachedImage.load(localFile)) {
image = cachedImage;
errorStr.clear();
emit finished();
return;
}
// Execute a request on the main thread asynchronously
moveToThread(c->thread());
QMetaObject::invokeMethod(this, &ThumbnailResponse::startRequest,
Qt::QueuedConnection);
}
2019-01-04 12:17:26 +00:00
void ThumbnailResponse::startRequest() {
// Runs in the main thread, not QML thread
Q_ASSERT(QThread::currentThread() == c->thread());
2019-01-04 12:17:26 +00:00
job = c->getThumbnail(mediaId, requestedSize);
// Connect to any possible outcome including abandonment
// to make sure the QML thread is not left stuck forever.
connect(job, &BaseJob::finished, this, &ThumbnailResponse::prepareResult);
}
2019-01-04 12:17:26 +00:00
void ThumbnailResponse::prepareResult() {
Q_ASSERT(QThread::currentThread() == job->thread());
Q_ASSERT(job->error() != BaseJob::Pending);
2019-01-04 12:17:26 +00:00
{
QWriteLocker _(&lock);
if (job->error() == BaseJob::Success) {
image = job->thumbnail();
QString localPath = QFileInfo(localFile).absolutePath();
QDir dir;
if (!dir.exists(localPath))
dir.mkpath(localPath);
image.save(localFile);
2019-01-04 12:17:26 +00:00
errorStr.clear();
} else if (job->error() == BaseJob::Abandoned) {
errorStr = tr("Image request has been cancelled");
qDebug() << "ThumbnailResponse: cancelled for" << mediaId;
2019-01-04 12:17:26 +00:00
} else {
errorStr = job->errorString();
qWarning() << "ThumbnailResponse: no valid image for" << mediaId << "-"
<< errorStr;
}
job = nullptr;
2018-08-28 03:12:49 +00:00
}
2019-01-04 12:17:26 +00:00
emit finished();
}
void ThumbnailResponse::doCancel() {
// Runs in the main thread, not QML thread
if (job) {
Q_ASSERT(QThread::currentThread() == job->thread());
job->abandon();
}
}
2019-01-04 12:17:26 +00:00
QQuickTextureFactory* ThumbnailResponse::textureFactory() const {
QReadLocker _(&lock);
return QQuickTextureFactory::textureFactoryForImage(image);
}
2019-01-04 12:17:26 +00:00
QString ThumbnailResponse::errorString() const {
QReadLocker _(&lock);
return errorStr;
}
2019-01-04 12:17:26 +00:00
void ThumbnailResponse::cancel() {
QMetaObject::invokeMethod(this, &ThumbnailResponse::doCancel,
Qt::QueuedConnection);
2019-01-04 12:17:26 +00:00
}
QQuickImageResponse* MatrixImageProvider::requestImageResponse(
const QString& id,
const QSize& requestedSize) {
2019-01-04 12:17:26 +00:00
return new ThumbnailResponse(m_connection.load(), id, requestedSize);
2018-03-02 08:56:36 +00:00
}