File indexing completed on 2024-05-12 15:59:52
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 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_meta_generator; 0243 static const QString s_meta_author; 0244 static const QString s_meta_title; 0245 static const QString s_meta_description; 0246 static const QString s_meta_initial_creator; 0247 static const QString s_meta_creator; 0248 static const QString s_meta_creation_date; 0249 static const QString s_meta_dc_date; 0250 static const QString s_meta_user_defined; 0251 static const QString s_meta_name; 0252 static const QString s_meta_value; 0253 static const QString s_meta_version; 0254 static const QString s_meta_license; 0255 static const QString s_meta_email; 0256 static const QString s_meta_website; 0257 0258 void setMetaData(const QString &key, const QVariant &value); 0259 QStringList metaDataKeys() const; 0260 QVariant metaData(const QString &key) const; 0261 0262 private: 0263 0264 friend class KisStorageModel; 0265 friend class KisResourceLocator; 0266 friend class KisResourceCacheDb; 0267 0268 void setStorageId(int storageId); 0269 int storageId(); 0270 0271 class Private; 0272 QScopedPointer<Private> d; 0273 }; 0274 0275 0276 0277 inline QDebug operator<<(QDebug dbg, const KisResourceStorageSP storage) 0278 { 0279 if (storage.isNull()) { 0280 dbg.nospace() << "[RESOURCESTORAGE] NULL"; 0281 } 0282 else { 0283 dbg.nospace() << "[RESOURCESTORAGE] Name: " << storage->name() 0284 << " Version: " << storage->location() 0285 << " Valid: " << storage->valid() 0286 << " Storage: " << KisResourceStorage::storageTypeToString(storage->type()) 0287 << " Timestamp: " << storage->timestamp() 0288 << " Pointer: " << storage.data(); 0289 } 0290 return dbg.space(); 0291 } 0292 0293 class KRITARESOURCES_EXPORT KisStoragePluginRegistry { 0294 public: 0295 KisStoragePluginRegistry(); 0296 virtual ~KisStoragePluginRegistry(); 0297 0298 void addStoragePluginFactory(KisResourceStorage::StorageType storageType, KisStoragePluginFactoryBase *factory); 0299 static KisStoragePluginRegistry *instance(); 0300 private: 0301 friend class KisResourceStorage; 0302 QMap<KisResourceStorage::StorageType, KisStoragePluginFactoryBase*> m_storageFactoryMap; 0303 0304 }; 0305 0306 struct VersionedResourceEntry 0307 { 0308 QString resourceType; 0309 QString filename; 0310 QList<QString> tagList; 0311 QDateTime lastModified; 0312 int guessedVersion = -1; 0313 QString guessedKey; 0314 0315 struct KeyVersionLess { 0316 bool operator()(const VersionedResourceEntry &lhs, const VersionedResourceEntry &rhs) const { 0317 return lhs.guessedKey < rhs.guessedKey || 0318 (lhs.guessedKey == rhs.guessedKey && lhs.guessedVersion < rhs.guessedVersion); 0319 } 0320 }; 0321 0322 struct KeyLess { 0323 bool operator()(const VersionedResourceEntry &lhs, const VersionedResourceEntry &rhs) const { 0324 return lhs.guessedKey < rhs.guessedKey; 0325 } 0326 }; 0327 }; 0328 0329 class KRITARESOURCES_EXPORT KisStorageVersioningHelper { 0330 public: 0331 0332 static bool addVersionedResource(const QString &saveLocation, KoResourceSP resource, int minVersion); 0333 static QString chooseUniqueName(KoResourceSP resource, 0334 int minVersion, 0335 std::function<bool(QString)> checkExists); 0336 0337 static void detectFileVersions(QVector<VersionedResourceEntry> &allFiles); 0338 0339 0340 }; 0341 0342 class KisVersionedStorageIterator : public KisResourceStorage::ResourceIterator 0343 { 0344 public: 0345 KisVersionedStorageIterator(const QVector<VersionedResourceEntry> &entries, 0346 KisStoragePlugin *_q); 0347 0348 bool hasNext() const override; 0349 void next() override; 0350 QString url() const override; 0351 QString type() const override; 0352 QDateTime lastModified() const override; 0353 KoResourceSP resourceImpl() const override; 0354 0355 int guessedVersion() const override; 0356 0357 QSharedPointer<KisResourceStorage::ResourceIterator> versions() const override; 0358 0359 protected: 0360 KisVersionedStorageIterator(const QVector<VersionedResourceEntry> &entries, 0361 QVector<VersionedResourceEntry>::const_iterator begin, 0362 QVector<VersionedResourceEntry>::const_iterator end, 0363 KisStoragePlugin *_q); 0364 protected: 0365 KisStoragePlugin *q = 0; 0366 const QVector<VersionedResourceEntry> m_entries; 0367 QVector<VersionedResourceEntry>::const_iterator m_it; 0368 QVector<VersionedResourceEntry>::const_iterator m_chunkStart; 0369 QVector<VersionedResourceEntry>::const_iterator m_begin; 0370 QVector<VersionedResourceEntry>::const_iterator m_end; 0371 bool m_isStarted = false; 0372 }; 0373 0374 0375 #endif // KISRESOURCESTORAGE_H