File indexing completed on 2024-05-19 04:27:39
0001 /* 0002 * SPDX-FileCopyrightText: 2018 Boudewijn Rempt <boud@valdyas.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef KISRESOURCESTORAGE_H 0008 #define KISRESOURCESTORAGE_H 0009 0010 #include <QSharedPointer> 0011 #include <QScopedPointer> 0012 #include <QString> 0013 #include <QDateTime> 0014 #include <QMap> 0015 0016 #include <KoResource.h> 0017 #include <KisTag.h> 0018 0019 #include <klocalizedstring.h> 0020 0021 #include <kritaresources_export.h> 0022 0023 class KisStoragePlugin; 0024 0025 class KisStoragePluginFactoryBase 0026 { 0027 public: 0028 virtual ~KisStoragePluginFactoryBase(){} 0029 virtual KisStoragePlugin *create(const QString &/*location*/) { return 0; } 0030 }; 0031 0032 template<typename T> 0033 class KisStoragePluginFactory : public KisStoragePluginFactoryBase 0034 { 0035 public: 0036 KisStoragePlugin *create(const QString &location) override { 0037 return new T(location); 0038 } 0039 }; 0040 0041 class KisResourceStorage; 0042 typedef QSharedPointer<KisResourceStorage> KisResourceStorageSP; 0043 0044 0045 /** 0046 * The KisResourceStorage class is the base class for 0047 * places where resources can be stored. Examples are 0048 * folders, bundles or Adobe resource libraries like 0049 * ABR files. 0050 */ 0051 class KRITARESOURCES_EXPORT KisResourceStorage 0052 { 0053 public: 0054 0055 /// A resource item is simply an entry in the storage, 0056 struct ResourceItem { 0057 0058 virtual ~ResourceItem() {} 0059 QString url; 0060 QString folder; 0061 QString resourceType; 0062 QDateTime lastModified; 0063 }; 0064 0065 class KRITARESOURCES_EXPORT TagIterator 0066 { 0067 public: 0068 virtual ~TagIterator() {} 0069 virtual bool hasNext() const = 0; 0070 /// The iterator is only valid if next() has been called at least once. 0071 virtual void next() = 0; 0072 0073 /// A tag object on which we can set properties and which we can save 0074 virtual KisTagSP tag() const = 0; 0075 }; 0076 0077 class KRITARESOURCES_EXPORT ResourceIterator 0078 { 0079 public: 0080 0081 virtual ~ResourceIterator() {} 0082 0083 virtual bool hasNext() const = 0; 0084 /// The iterator is only valid if next() has been called at least once. 0085 virtual void next() = 0; 0086 0087 virtual QString url() const = 0; 0088 virtual QString type() const = 0; 0089 virtual QDateTime lastModified() const = 0; 0090 virtual int guessedVersion() const { return 0; } 0091 virtual QSharedPointer<KisResourceStorage::ResourceIterator> versions() const; 0092 0093 KoResourceSP resource() const; 0094 0095 protected: 0096 /// This only loads the resource when called 0097 virtual KoResourceSP resourceImpl() const = 0; 0098 0099 private: 0100 mutable KoResourceSP m_cachedResource; 0101 mutable QString m_cachedResourceUrl; 0102 }; 0103 0104 enum class StorageType : int { 0105 Unknown = 1, 0106 Folder = 2, 0107 Bundle = 3, 0108 AdobeBrushLibrary = 4, 0109 AdobeStyleLibrary = 5, 0110 Memory = 6 0111 }; 0112 0113 static QString storageTypeToString(StorageType storageType) { 0114 switch (storageType) { 0115 case StorageType::Unknown: 0116 return i18n("Unknown"); 0117 case StorageType::Folder: 0118 return i18n("Folder"); 0119 case StorageType::Bundle: 0120 return i18n("Bundle"); 0121 case StorageType::AdobeBrushLibrary: 0122 return i18n("Adobe Brush Library"); 0123 case StorageType::AdobeStyleLibrary: 0124 return i18n("Adobe Style Library"); 0125 case StorageType::Memory: 0126 return i18n("Memory"); 0127 default: 0128 return i18n("Invalid"); 0129 } 0130 } 0131 0132 0133 static QString storageTypeToUntranslatedString(StorageType storageType) { 0134 switch (storageType) { 0135 case StorageType::Unknown: 0136 return ("Unknown"); 0137 case StorageType::Folder: 0138 return ("Folder"); 0139 case StorageType::Bundle: 0140 return ("Bundle"); 0141 case StorageType::AdobeBrushLibrary: 0142 return ("Adobe Brush Library"); 0143 case StorageType::AdobeStyleLibrary: 0144 return ("Adobe Style Library"); 0145 case StorageType::Memory: 0146 return ("Memory"); 0147 default: 0148 return ("Invalid"); 0149 } 0150 } 0151 0152 0153 KisResourceStorage(const QString &location); 0154 ~KisResourceStorage(); 0155 KisResourceStorage(const KisResourceStorage &rhs); 0156 KisResourceStorage &operator=(const KisResourceStorage &rhs); 0157 KisResourceStorageSP clone() const; 0158 0159 /// The filename of the storage if it's a bundle or Adobe Library. This can 0160 /// also be empty (for the folder storage) or "memory" for the storage for 0161 /// temporary resources, a UUID for storages associated with documents. 0162 QString name() const; 0163 0164 /// The absolute location of the storage 0165 QString location() const; 0166 0167 /// true if the storage exists and can be used 0168 bool valid() const; 0169 0170 /// The type of the storage 0171 StorageType type() const; 0172 0173 /// The icond for the storage 0174 QImage thumbnail() const; 0175 0176 /// The time and date when the storage was last modified, or created 0177 /// for memory storages. 0178 QDateTime timestamp() const; 0179 0180 /// The time and date when the resource was last modified 0181 /// For filestorage 0182 QDateTime timeStampForResource(const QString &resourceType, const QString &filename) const; 0183 0184 /// And entry in the storage; this is not the loaded resource 0185 ResourceItem resourceItem(const QString &url); 0186 0187 /// The loaded resource for an entry in the storage 0188 KoResourceSP resource(const QString &url); 0189 0190 /// The MD5 checksum of the resource in the storage 0191 QString resourceMd5(const QString &url); 0192 0193 /// If the resource is present on the filesystem as a distinct fine, 0194 /// returns the full file path of it, otherwise returns an empty string. 0195 /// 0196 /// Never manipulate the file in any way directly! It will destroy the 0197 /// resources database. Use this file path only for informational purposes. 0198 QString resourceFilePath(const QString &url); 0199 0200 /// An iterator over all the resources in the storage 0201 QSharedPointer<ResourceIterator> resources(const QString &resourceType) const; 0202 0203 /// An iterator over all the tags in the resource 0204 QSharedPointer<TagIterator> tags(const QString &resourceType) const; 0205 0206 /// Adds a tag to the storage, however, it does not store the links between 0207 /// tags and resources. 0208 bool addTag(const QString &resourceType, KisTagSP tag); 0209 0210 /// Creates a new version of the given resource. 0211 bool saveAsNewVersion(KoResourceSP resource); 0212 0213 /// Adds the given resource to the storage. If there is already a resource 0214 /// with the given filename of the given type, this should return false and 0215 /// saveAsNewVersion should be used. 0216 bool addResource(KoResourceSP resource); 0217 0218 /** 0219 * Copies the given file into this storage. Implementations should not overwrite 0220 * an existing resource with the same filename, but return false. 0221 * 0222 * @param url is the URL of the resource inside the storage, which is usually 0223 * resource_type/resource_filename.ext 0224 */ 0225 bool importResource(const QString &url, QIODevice *device); 0226 0227 /** 0228 * Copies the given resource from the storage into \p device 0229 * 0230 * @param url is the URL of the resource inside the storage, which is usually 0231 * resource_type/resource_filename.ext 0232 */ 0233 bool exportResource(const QString &url, QIODevice *device); 0234 0235 /// Returns true if the storage supports versioning of the resources. 0236 /// It enables loadVersionedResource() call. 0237 bool supportsVersioning() const; 0238 0239 /// Reloads the given resource from the persistent storage 0240 bool loadVersionedResource(KoResourceSP resource); 0241 0242 static const QString s_xmlns_meta; 0243 static const QString s_xmlns_dc; 0244 0245 static const QString s_meta_generator; 0246 static const QString s_meta_author; 0247 static const QString s_meta_title; 0248 static const QString s_meta_description; 0249 static const QString s_meta_initial_creator; 0250 static const QString s_meta_creator; 0251 static const QString s_meta_creation_date; 0252 static const QString s_meta_dc_date; 0253 static const QString s_meta_user_defined; 0254 static const QString s_meta_name; 0255 static const QString s_meta_value; 0256 static const QString s_meta_version; 0257 static const QString s_meta_license; 0258 static const QString s_meta_email; 0259 static const QString s_meta_website; 0260 0261 void setMetaData(const QString &key, const QVariant &value); 0262 QStringList metaDataKeys() const; 0263 QVariant metaData(const QString &key) const; 0264 0265 private: 0266 0267 friend class KisStorageModel; 0268 friend class KisResourceLocator; 0269 friend class KisResourceCacheDb; 0270 0271 void setStorageId(int storageId); 0272 int storageId(); 0273 0274 class Private; 0275 QScopedPointer<Private> d; 0276 }; 0277 0278 0279 0280 inline QDebug operator<<(QDebug dbg, const KisResourceStorageSP storage) 0281 { 0282 if (storage.isNull()) { 0283 dbg.nospace() << "[RESOURCESTORAGE] NULL"; 0284 } 0285 else { 0286 dbg.nospace() << "[RESOURCESTORAGE] Name: " << storage->name() 0287 << " Version: " << storage->location() 0288 << " Valid: " << storage->valid() 0289 << " Storage: " << KisResourceStorage::storageTypeToString(storage->type()) 0290 << " Timestamp: " << storage->timestamp() 0291 << " Pointer: " << storage.data(); 0292 } 0293 return dbg.space(); 0294 } 0295 0296 class KRITARESOURCES_EXPORT KisStoragePluginRegistry { 0297 public: 0298 KisStoragePluginRegistry(); 0299 virtual ~KisStoragePluginRegistry(); 0300 0301 void addStoragePluginFactory(KisResourceStorage::StorageType storageType, KisStoragePluginFactoryBase *factory); 0302 static KisStoragePluginRegistry *instance(); 0303 private: 0304 friend class KisResourceStorage; 0305 QMap<KisResourceStorage::StorageType, KisStoragePluginFactoryBase*> m_storageFactoryMap; 0306 0307 }; 0308 0309 struct VersionedResourceEntry 0310 { 0311 QString resourceType; 0312 QString filename; 0313 QList<QString> tagList; 0314 QDateTime lastModified; 0315 int guessedVersion = -1; 0316 QString guessedKey; 0317 0318 struct KeyVersionLess { 0319 bool operator()(const VersionedResourceEntry &lhs, const VersionedResourceEntry &rhs) const { 0320 return lhs.guessedKey < rhs.guessedKey || 0321 (lhs.guessedKey == rhs.guessedKey && lhs.guessedVersion < rhs.guessedVersion); 0322 } 0323 }; 0324 0325 struct KeyLess { 0326 bool operator()(const VersionedResourceEntry &lhs, const VersionedResourceEntry &rhs) const { 0327 return lhs.guessedKey < rhs.guessedKey; 0328 } 0329 }; 0330 }; 0331 0332 class KRITARESOURCES_EXPORT KisStorageVersioningHelper { 0333 public: 0334 0335 static bool addVersionedResource(const QString &saveLocation, KoResourceSP resource, int minVersion); 0336 static QString chooseUniqueName(KoResourceSP resource, 0337 int minVersion, 0338 std::function<bool(QString)> checkExists); 0339 0340 static void detectFileVersions(QVector<VersionedResourceEntry> &allFiles); 0341 0342 0343 }; 0344 0345 class KisVersionedStorageIterator : public KisResourceStorage::ResourceIterator 0346 { 0347 public: 0348 KisVersionedStorageIterator(const QVector<VersionedResourceEntry> &entries, 0349 KisStoragePlugin *_q); 0350 0351 bool hasNext() const override; 0352 void next() override; 0353 QString url() const override; 0354 QString type() const override; 0355 QDateTime lastModified() const override; 0356 KoResourceSP resourceImpl() const override; 0357 0358 int guessedVersion() const override; 0359 0360 QSharedPointer<KisResourceStorage::ResourceIterator> versions() const override; 0361 0362 protected: 0363 KisVersionedStorageIterator(const QVector<VersionedResourceEntry> &entries, 0364 QVector<VersionedResourceEntry>::const_iterator begin, 0365 QVector<VersionedResourceEntry>::const_iterator end, 0366 KisStoragePlugin *_q); 0367 protected: 0368 KisStoragePlugin *q = 0; 0369 const QVector<VersionedResourceEntry> m_entries; 0370 QVector<VersionedResourceEntry>::const_iterator m_it; 0371 QVector<VersionedResourceEntry>::const_iterator m_chunkStart; 0372 QVector<VersionedResourceEntry>::const_iterator m_begin; 0373 QVector<VersionedResourceEntry>::const_iterator m_end; 0374 bool m_isStarted = false; 0375 }; 0376 0377 0378 #endif // KISRESOURCESTORAGE_H