File indexing completed on 2024-05-12 15:59:48
0001 /* 0002 * SPDX-FileCopyrightText: 2018 Boudewijn Rempt <boud@valdyas.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "KisFolderStorage.h" 0008 0009 #include <QDirIterator> 0010 #include <KisMimeDatabase.h> 0011 #include <kis_debug.h> 0012 #include <KisTag.h> 0013 #include <KisResourceLoaderRegistry.h> 0014 #include <KisGlobalResourcesInterface.h> 0015 #include <kis_pointer_utils.h> 0016 #include <KoMD5Generator.h> 0017 0018 0019 class FolderTagIterator : public KisResourceStorage::TagIterator 0020 { 0021 public: 0022 0023 FolderTagIterator(const QString &location, const QString &resourceType) 0024 : m_location(location) 0025 , m_resourceType(resourceType) 0026 { 0027 m_dirIterator.reset(new QDirIterator(location + '/' + resourceType, 0028 QStringList() << "*.tag", 0029 QDir::Files | QDir::Readable, 0030 QDirIterator::Subdirectories)); 0031 } 0032 0033 bool hasNext() const override 0034 { 0035 return m_dirIterator->hasNext(); 0036 } 0037 0038 void next() override 0039 { 0040 m_dirIterator->next(); 0041 const_cast<FolderTagIterator*>(this)->m_tag.reset(new KisTag); 0042 if (!load(m_tag)) { 0043 qWarning() << "Could not load tag" << m_dirIterator->filePath(); 0044 } 0045 } 0046 0047 KisTagSP tag() const override 0048 { 0049 return m_tag; 0050 } 0051 0052 private: 0053 0054 bool load(KisTagSP tag) const 0055 { 0056 QFile f(m_dirIterator->filePath()); 0057 tag->setFilename(m_dirIterator->fileName()); 0058 if (f.exists()) { 0059 f.open(QFile::ReadOnly); 0060 if (!tag->load(f)) { 0061 qWarning() << m_dirIterator->filePath() << "is not a valid tag desktop file"; 0062 return false; 0063 } 0064 0065 } 0066 return true; 0067 } 0068 0069 QScopedPointer<QDirIterator> m_dirIterator; 0070 QString m_location; 0071 QString m_resourceType; 0072 KisTagSP m_tag; 0073 }; 0074 0075 0076 class FolderItem : public KisResourceStorage::ResourceItem 0077 { 0078 public: 0079 ~FolderItem() override {} 0080 }; 0081 0082 0083 KisFolderStorage::KisFolderStorage(const QString &location) 0084 : KisStoragePlugin(location) 0085 { 0086 } 0087 0088 KisFolderStorage::~KisFolderStorage() 0089 { 0090 } 0091 0092 bool KisFolderStorage::saveAsNewVersion(const QString &resourceType, KoResourceSP _resource) 0093 { 0094 return KisStorageVersioningHelper::addVersionedResource(location() + "/" + resourceType, _resource, 0); 0095 } 0096 0097 KisResourceStorage::ResourceItem KisFolderStorage::resourceItem(const QString &url) 0098 { 0099 QFileInfo fi(url); 0100 FolderItem item; 0101 item.url = url; 0102 item.folder = fi.path().split("/").last(); 0103 item.lastModified = fi.lastModified(); 0104 return item; 0105 } 0106 0107 bool KisFolderStorage::loadVersionedResource(KoResourceSP resource) 0108 { 0109 QFileInfo fi(location() + '/' + resource->resourceType().first + '/' + resource->filename()); 0110 0111 QFile f(fi.absoluteFilePath()); 0112 if (!f.open(QFile::ReadOnly)) { 0113 qWarning() << "Could not open" << fi.absoluteFilePath() << "for reading"; 0114 return false; 0115 } 0116 0117 bool r = resource->loadFromDevice(&f, KisGlobalResourcesInterface::instance()); 0118 0119 // Check for the thumbnail 0120 if (r) { 0121 sanitizeResourceFileNameCase(resource, fi.dir()); 0122 0123 if ((resource->image().isNull() || resource->thumbnail().isNull()) && !resource->thumbnailPath().isNull()) { 0124 QImage img(location() + '/' + resource->resourceType().first + '/' + resource->thumbnailPath()); 0125 resource->setImage(img); 0126 resource->updateThumbnail(); 0127 } 0128 } 0129 0130 return r; 0131 } 0132 0133 QString KisFolderStorage::resourceMd5(const QString &url) 0134 { 0135 QString result; 0136 0137 QFile file(location() + "/" + url); 0138 if (file.exists() && file.open(QIODevice::ReadOnly)) { 0139 result = KoMD5Generator::generateHash(file.readAll()); 0140 } 0141 0142 return result; 0143 } 0144 0145 QString KisFolderStorage::resourceFilePath(const QString &url) 0146 { 0147 QFileInfo file(location() + "/" + url); 0148 return file.exists() ? file.absoluteFilePath() : QString(); 0149 } 0150 0151 QSharedPointer<KisResourceStorage::ResourceIterator> KisFolderStorage::resources(const QString &resourceType) 0152 { 0153 QVector<VersionedResourceEntry> entries; 0154 0155 const QString resourcesSaveLocation = location() + "/" + resourceType; 0156 0157 QDirIterator it(resourcesSaveLocation, 0158 KisResourceLoaderRegistry::instance()->filters(resourceType), 0159 QDir::Files | QDir::Readable, 0160 QDirIterator::Subdirectories);; 0161 0162 while (it.hasNext()) { 0163 it.next(); 0164 QFileInfo info(it.fileInfo()); 0165 0166 VersionedResourceEntry entry; 0167 entry.filename = it.filePath().mid(resourcesSaveLocation.size() + 1); 0168 0169 // Don't load 4.x backup resources 0170 if (entry.filename.contains("backup")) { 0171 continue; 0172 } 0173 0174 entry.lastModified = info.lastModified(); 0175 entry.tagList = {}; // TODO 0176 entry.resourceType = resourceType; 0177 entries.append(entry); 0178 } 0179 0180 KisStorageVersioningHelper::detectFileVersions(entries); 0181 0182 return toQShared(new KisVersionedStorageIterator(entries, this)); 0183 } 0184 0185 QSharedPointer<KisResourceStorage::TagIterator> KisFolderStorage::tags(const QString &resourceType) 0186 { 0187 return QSharedPointer<KisResourceStorage::TagIterator>(new FolderTagIterator(location(), resourceType)); 0188 } 0189 0190 bool KisFolderStorage::importResource(const QString &url, QIODevice *device) 0191 { 0192 bool result = false; 0193 0194 const QString resourcesLocation = location() + "/" + url; 0195 0196 QFile f(resourcesLocation); 0197 0198 if (f.exists()) return result; 0199 0200 if (f.open(QFile::WriteOnly)) { 0201 qint64 writtenBytes = f.write(device->readAll()); 0202 f.close(); 0203 result = (writtenBytes == device->size()); 0204 } else { 0205 qWarning() << "Cannot open" << resourcesLocation << "for writing"; 0206 } 0207 0208 KoResourceSP resourceAfterLoading = resource(url); 0209 0210 if (resourceAfterLoading.isNull()) { 0211 f.remove(); 0212 return false; 0213 } 0214 0215 return result; 0216 } 0217 0218 bool KisFolderStorage::exportResource(const QString &url, QIODevice *device) 0219 { 0220 bool result = false; 0221 0222 const QString resourcesLocation = location() + "/" + url; 0223 0224 QFile f(resourcesLocation); 0225 0226 if (!f.exists()) return result; 0227 0228 if (f.open(QFile::ReadOnly)) { 0229 device->write(f.readAll()); 0230 f.close(); 0231 result = true; 0232 } else { 0233 qWarning() << "Cannot open" << resourcesLocation << "for reading"; 0234 } 0235 0236 return result; 0237 } 0238 0239 bool KisFolderStorage::addResource(const QString &resourceType, KoResourceSP resource) 0240 { 0241 if (!resource || !resource->valid()) return false; 0242 0243 const QString resourcesSaveLocation = location() + "/" + resourceType; 0244 0245 QFileInfo fi(resourcesSaveLocation + "/" + resource->filename()); 0246 if (fi.exists()) { 0247 qWarning() << "Resource" << resourceType << resource->filename() << "already exists in" << resourcesSaveLocation; 0248 return false; 0249 } 0250 0251 QFile resourceFile(fi.absoluteFilePath()); 0252 if (!resourceFile.open(QFile::WriteOnly)) { 0253 qWarning() << "Could not open" << fi.absoluteFilePath() << "for writing."; 0254 return false; 0255 } 0256 0257 if (!resource->saveToDevice(&resourceFile)) { 0258 qWarning() << "Could not save resource to" << fi.absoluteFilePath(); 0259 resourceFile.close(); 0260 return false; 0261 } 0262 resourceFile.close(); 0263 0264 0265 0266 0267 return true; 0268 } 0269 0270 QStringList KisFolderStorage::metaDataKeys() const 0271 { 0272 return QStringList() << KisResourceStorage::s_meta_name; 0273 } 0274 0275 QVariant KisFolderStorage::metaData(const QString &key) const 0276 { 0277 if (key == KisResourceStorage::s_meta_name) { 0278 return i18n("Local Resources"); 0279 } 0280 return QVariant(); 0281 0282 }