File indexing completed on 2024-05-19 04:27:39

0001 /*
0002  *  SPDX-FileCopyrightText: 2020 Boudewijn Rempt <boud@valdyas.org>
0003  *  SPDX-FileCopyrightText: 2021 Agata Cacko <cacko.azh@gmail.com>
0004  *  SPDX-FileCopyrightText: 2022 Dmitry Kazakov <dimula73@gmail.com>
0005  *  SPDX-FileCopyrightText: 2023 L. E. Segovia <amy@amyspark.me>
0006  *
0007  *  SPDX-License-Identifier: GPL-3.0-or-later
0008  */
0009 
0010 #include "KisResourceQueryMapper.h"
0011 
0012 #include <QBuffer>
0013 #include <QByteArray>
0014 #include <QDebug>
0015 #include <QFont>
0016 #include <QImage>
0017 #include <QSqlError>
0018 #include <QString>
0019 #include <QVariant>
0020 
0021 #include "KisResourceLocator.h"
0022 #include "KisResourceModel.h"
0023 #include "KisResourceModelProvider.h"
0024 #include "KisResourceThumbnailCache.h"
0025 #include "KisTag.h"
0026 #include "kis_assert.h"
0027 
0028 QImage KisResourceQueryMapper::getThumbnailFromQuery(const QSqlQuery &query, bool useResourcePrefix)
0029 {
0030     const QString storageLocation =
0031         KisResourceLocator::instance()->makeStorageLocationAbsolute(query.value("location").toString());
0032     const QString resourceType = query.value("resource_type").toString();
0033     const QString filename = query.value(useResourcePrefix ? "resource_filename" : "filename").toString();
0034 
0035     // NOTE: Only use the private methods of KisResourceThumbnailCache here to prevent any chances of
0036     // recursion.
0037     QImage img =
0038         KisResourceThumbnailCache::instance()->originalImage(storageLocation, resourceType, filename);
0039     if (!img.isNull()) {
0040         return img;
0041     } else {
0042         const int resourceId = query.value(useResourcePrefix ? "resource_id" : "id").toInt();
0043         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(resourceId >= 0, img);
0044 
0045         bool result = false;
0046         QSqlQuery thumbQuery;
0047         result = thumbQuery.prepare("SELECT thumbnail FROM resources WHERE resources.id = :resource_id");
0048         if (!result) {
0049             qWarning() << "Failed to prepare query for thumbnail of" << resourceId << thumbQuery.lastError();
0050             return img;
0051         }
0052 
0053         thumbQuery.bindValue(":resource_id", resourceId);
0054 
0055         result = thumbQuery.exec();
0056 
0057         if (!result) {
0058             qWarning() << "Failed to execute query for thumbnail of" << resourceId << thumbQuery.lastError();
0059             return img;
0060         }
0061 
0062         if (!thumbQuery.next()) {
0063             qWarning() << "Failed to find thumbnail of" << resourceId;
0064             return img;
0065         }
0066 
0067         QByteArray ba = thumbQuery.value("thumbnail").toByteArray();
0068         QBuffer buf(&ba);
0069         buf.open(QBuffer::ReadOnly);
0070         img.load(&buf, "PNG");
0071 
0072         KisResourceThumbnailCache::instance()->insert(storageLocation, resourceType, filename, img);
0073         return img;
0074     }
0075 }
0076 
0077 QVariant KisResourceQueryMapper::variantFromResourceQuery(const QSqlQuery &query, int column, int role, bool useResourcePrefix)
0078 {
0079     const QString resourceType = query.value("resource_type").toString();
0080 
0081     switch(role) {
0082     case Qt::FontRole:
0083         return QFont();
0084     case Qt::DisplayRole:
0085     {
0086         switch(column) {
0087         case KisAbstractResourceModel::Id:
0088             return query.value(useResourcePrefix ? "resource_id" : "id");
0089         case KisAbstractResourceModel::StorageId:
0090             return query.value("storage_id");
0091         case KisAbstractResourceModel::Name:
0092             return query.value(useResourcePrefix ? "resource_name" : "name");
0093         case KisAbstractResourceModel::Filename:
0094             return query.value(useResourcePrefix ? "resource_filename" : "filename");
0095         case KisAbstractResourceModel::Tooltip:
0096             return query.value(useResourcePrefix ? "resource_tooltip" : "tooltip");
0097         case KisAbstractResourceModel::Thumbnail:
0098         {
0099             return QVariant::fromValue<QImage>(getThumbnailFromQuery(query, useResourcePrefix));
0100         }
0101         case KisAbstractResourceModel::Status:
0102             return query.value(useResourcePrefix ? "resource_active" : "status");
0103         case KisAbstractResourceModel::Location:
0104             return query.value("location");
0105         case KisAbstractResourceModel::ResourceType:
0106             return query.value("resource_type");
0107         case KisAbstractResourceModel::Dirty:
0108         {
0109             QString storageLocation = query.value("location").toString();
0110             QString filename = query.value(useResourcePrefix ? "resource_filename" : "filename").toString();
0111 
0112             // An uncached resource has not been loaded, so it cannot be dirty
0113             if (!KisResourceLocator::instance()->resourceCached(storageLocation, resourceType, filename)) {
0114                 return false;
0115             }
0116             else {
0117                 // Now we have to check the resource, but that's cheap since it's been loaded in any case
0118                 KoResourceSP resource = KisResourceLocator::instance()->resourceForId(query.value(useResourcePrefix ? "resource_id" : "id").toInt());
0119                 return resource->isDirty();
0120             }
0121         }
0122         case KisAbstractResourceModel::ResourceActive:
0123             return query.value("resource_active");
0124         case KisAbstractResourceModel::StorageActive:
0125             return query.value(useResourcePrefix ? "resource_storage_active" : "storage_active");
0126         default:
0127             ;
0128         };
0129         Q_FALLTHROUGH();
0130     }
0131     case Qt::DecorationRole:
0132     {
0133         if (column == KisAbstractResourceModel::Thumbnail) {
0134             return QVariant::fromValue<QImage>(getThumbnailFromQuery(query, useResourcePrefix));
0135         }
0136         return QVariant();
0137     }
0138     case Qt::CheckStateRole: {
0139         switch (column) {
0140         case KisAbstractResourceModel::Status:
0141             if (query.value(useResourcePrefix ? "resource_active" : "status").toInt() == 0) {
0142                 return Qt::Unchecked;
0143             } else {
0144                 return Qt::Checked;
0145             }
0146         case KisAbstractResourceModel::Dirty: {
0147             const QString storageLocation = query.value("location").toString();
0148             const QString filename = query.value(useResourcePrefix ? "resource_filename" : "filename").toString();
0149 
0150             // An uncached resource has not been loaded, so it cannot be dirty
0151             if (!KisResourceLocator::instance()->resourceCached(storageLocation, resourceType, filename)) {
0152                 return Qt::Unchecked;
0153             } else {
0154                 // Now we have to check the resource, but that's cheap since it's been loaded in any case
0155                 KoResourceSP resource = KisResourceLocator::instance()->resourceForId(
0156                     query.value(useResourcePrefix ? "resource_id" : "id").toInt());
0157                 return resource->isDirty() ? Qt::Checked : Qt::Unchecked;
0158             }
0159         }
0160         case KisAbstractResourceModel::ResourceActive:
0161             if (query.value("resource_active").toInt() == 0) {
0162                 return Qt::Unchecked;
0163             } else {
0164                 return Qt::Checked;
0165             }
0166         case KisAbstractResourceModel::StorageActive:
0167             if (query.value(useResourcePrefix ? "resource_storage_active" : "storage_active").toInt() == 0) {
0168                 return Qt::Unchecked;
0169             } else {
0170                 return Qt::Checked;
0171             }
0172         default:
0173             return {};
0174         };
0175     }
0176     case Qt::StatusTipRole:
0177         return QVariant();
0178     case Qt::ToolTipRole:
0179         Q_FALLTHROUGH();
0180     case Qt::WhatsThisRole:
0181         return query.value("tooltip");
0182     case Qt::UserRole + KisAbstractResourceModel::Id:
0183         return query.value(useResourcePrefix ? "resource_id" : "id");
0184     case Qt::UserRole + KisAbstractResourceModel::StorageId:
0185         return query.value("storage_id");
0186     case Qt::UserRole + KisAbstractResourceModel::Name:
0187         return query.value(useResourcePrefix ? "resource_name" : "name");
0188     case Qt::UserRole + KisAbstractResourceModel::Filename:
0189         return query.value(useResourcePrefix ? "resource_filename" : "filename");
0190     case Qt::UserRole + KisAbstractResourceModel::Tooltip:
0191         return query.value(useResourcePrefix ? "resource_tooltip" : "tooltip");
0192     case Qt::UserRole + KisAbstractResourceModel::MD5:
0193         return query.value(useResourcePrefix ? "resource_md5sum" : "md5sum");
0194     case Qt::UserRole + KisAbstractResourceModel::Thumbnail:
0195     {
0196         return QVariant::fromValue<QImage>(getThumbnailFromQuery(query, useResourcePrefix));
0197     }
0198     case Qt::UserRole + KisAbstractResourceModel::Status:
0199         return query.value(useResourcePrefix ? "resource_active" : "status");
0200     case Qt::UserRole + KisAbstractResourceModel::Location:
0201         return query.value("location");
0202     case Qt::UserRole + KisAbstractResourceModel::ResourceType:
0203         return query.value("resource_type");
0204     case Qt::UserRole + KisAbstractResourceModel::Tags:
0205     {
0206         KisAllResourcesModel *resourceModel = KisResourceModelProvider::resourceModel(resourceType);
0207         QStringList tagNames;
0208         Q_FOREACH(const KisTagSP tag, resourceModel->tagsForResource(query.value(useResourcePrefix ? "resource_id" : "id").toInt())) {
0209             tagNames << tag->name();
0210         }
0211         return tagNames;
0212     }
0213     case Qt::UserRole + KisAbstractResourceModel::Dirty:
0214     {
0215         QString storageLocation = query.value("location").toString();
0216         QString filename = query.value(useResourcePrefix ? "resource_filename" : "filename").toString();
0217 
0218         // An uncached resource has not been loaded, so it cannot be dirty
0219         if (!KisResourceLocator::instance()->resourceCached(storageLocation, resourceType, filename)) {
0220             return false;
0221         }
0222         else {
0223             // Now we have to check the resource, but that's cheap since it's been loaded in any case
0224             KoResourceSP resource = KisResourceLocator::instance()->resourceForId(query.value(useResourcePrefix ? "resource_id" : "id").toInt());
0225             return resource->isDirty();
0226         }
0227     }
0228     case Qt::UserRole + KisAbstractResourceModel::MetaData:
0229     {
0230         QMap<QString, QVariant> r = KisResourceLocator::instance()->metaDataForResource(query.value(useResourcePrefix ? "resource_id" : "id").toInt());
0231         return r;
0232     }
0233     case Qt::UserRole + KisAbstractResourceModel::ResourceActive:
0234     {
0235         return query.value("resource_active");
0236     }
0237     case Qt::UserRole + KisAbstractResourceModel::StorageActive:
0238     {
0239         return query.value(useResourcePrefix ? "resource_storage_active" : "storage_active");
0240     }
0241     default:
0242         ;
0243     }
0244 
0245     return QVariant();
0246 }
0247