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