File indexing completed on 2024-05-12 15:59:50

0001 /*
0002  * SPDX-FileCopyrightText: 2018 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #ifndef KISRESOURCELOCATOR_H
0008 #define KISRESOURCELOCATOR_H
0009 
0010 #include <QObject>
0011 #include <QScopedPointer>
0012 #include <QStringList>
0013 #include <QString>
0014 
0015 #include "kritaresources_export.h"
0016 
0017 #include <KisResourceStorage.h>
0018 
0019 
0020 /**
0021  * The KisResourceLocator class locates all resource storages (folders,
0022  * bundles, various adobe resource libraries) in the resource location.
0023  *
0024  * The resource location is always a writable folder.
0025  *
0026  * There is one resource locator which is owned by the QApplication
0027  * object.
0028  *
0029  * The resource location is configurable, but there is only one location
0030  * where Krita will look for resources.
0031  */
0032 class KRITARESOURCES_EXPORT KisResourceLocator : public QObject
0033 {
0034     Q_OBJECT
0035 public:
0036 
0037     // The configuration key that holds the resource location
0038     // for this installation of Krita. The location is
0039     // QStandardPaths::AppDataLocation by default, but that
0040     // can be changed.
0041     static const QString resourceLocationKey;
0042 
0043     static KisResourceLocator *instance();
0044 
0045     ~KisResourceLocator();
0046 
0047     enum class LocatorError {
0048         Ok,
0049         LocationReadOnly,
0050         CannotCreateLocation,
0051         CannotInitializeDb,
0052         CannotSynchronizeDb
0053     };
0054 
0055     /**
0056      * @brief initialize Setup the resource locator for use.
0057      *
0058      * @param installationResourcesLocation the place where the resources
0059      * that come packaged with Krita reside.
0060      */
0061     LocatorError initialize(const QString &installationResourcesLocation);
0062 
0063     /**
0064      * @brief errorMessages
0065      * @return
0066      */
0067     QStringList errorMessages() const;
0068 
0069     /**
0070      * @brief resourceLocationBase is the place where all resource storages (folder,
0071      * bundles etc. are located. This is a writable place.
0072      * @return the base location for all storages.
0073      */
0074     QString resourceLocationBase() const;
0075 
0076     /**
0077      * @brief purge purges the local resource cache
0078      */
0079     void purge(const QString &storageLocation);
0080 
0081     /**
0082      * @brief addStorage Adds a new resource storage to the database. The storage is
0083      * will be marked as not pre-installed. If there is already a storage with the
0084      * given location, it will first be removed.
0085      * @param storageLocation a unique name for the given storage
0086      * @param storage a storage object
0087      * @return true if the storage has been added successfully
0088      */
0089     bool addStorage(const QString &storageLocation, KisResourceStorageSP storage);
0090 
0091     /**
0092      * @brief removeStorage removes the temporary storage from the database
0093      * @param storageLocation the unique name of the storage
0094      * @return true is successful.
0095      */
0096     bool removeStorage(const QString &storageLocation);
0097 
0098     /**
0099      * @brief hasStorage can be used to check whether the given storage already exists
0100      * @param storageLocation the name of the storage
0101      * @return true if the storage is known
0102      */
0103     bool hasStorage(const QString &storageLocation);
0104 
0105 
0106     /**
0107      * @brief saveTags saves all tags to .tag files in the resource folder
0108      */
0109     static void saveTags();
0110 
0111     /**
0112      * Remove the given tag from the cache
0113      */
0114     void purgeTag(const QString tagUrl, const QString resourceType);
0115 
0116     /**
0117      * Returns the full file path of the resource if it has any
0118      * separate physical representation on the disk
0119      */
0120     QString filePathForResource(KoResourceSP resource);
0121 
0122 Q_SIGNALS:
0123 
0124     void progressMessage(const QString&);
0125 
0126     /// Emitted whenever a storage is added
0127     void storageAdded(const QString &location);
0128 
0129     /// Emitted whenever a storage is removed
0130     void storageRemoved(const QString &location);
0131 
0132     /// Emitted when the locator needs to add an embedded resource
0133     void beginExternalResourceImport(const QString &resourceType, int numResources);
0134 
0135     /// Emitted when the locator finished importing the embedded resource
0136     void endExternalResourceImport(const QString &resourceType);
0137 
0138     /// Emitted when the locator needs to add an embedded resource
0139     void beginExternalResourceRemove(const QString &resourceType, const QVector<int> resourceIds);
0140 
0141     /// Emitted when the locator finished importing the embedded resource
0142     void endExternalResourceRemove(const QString &resourceType);
0143 
0144     /// Emitted when a resource changes its active state
0145     void resourceActiveStateChanged(const QString &resourceType, int resourceId);
0146 
0147 private:
0148 
0149     friend class KisAllTagsModel;
0150     friend class KisTagResourceModel;
0151     friend class KisAllResourcesModel;
0152     friend class KisAllTagResourceModel;
0153     friend class KisStorageModel;
0154     friend class TestResourceLocator;
0155     friend class TestResourceModel;
0156     friend class Resource;
0157     friend class KisResourceCacheDb;
0158     friend class KisStorageFilterProxyModel;
0159     friend class KisResourceQueryMapper;
0160     friend class KisResourceUserOperations;
0161     friend class KisBrushTypeMetaDataFixup;
0162 
0163     /// @return true if the resource is present in the cache, false if it hasn't been loaded
0164     bool resourceCached(QString storageLocation, const QString &resourceType, const QString &filename) const;
0165 
0166     /// add the thumbnail associated with resouceId to cache
0167     void cacheThumbnail(QString storageLocation, const QString &resourceType, const QString &filename, const QImage &img);
0168 
0169     /// @return a valid image if the thumbnail is present in the cache, an invalid image otherwise
0170     QImage thumbnailCached(QString storageLocation, const QString &resourceType, const QString &filename);
0171 
0172     /**
0173      * @brief resource finds a physical resource in one of the storages
0174      * @param storageLocation the storage containing the resource. If empty,
0175      * this is the folder storage.
0176      *
0177      * Note that the resource does not have the version or id field set, so this cannot be used directly,
0178      * but only through KisResourceModel.
0179      *
0180      * @param resourceType the type of the resource
0181      * @param filename the filename of the resource including extension, but without
0182      * any paths
0183      * @return A resource if found, or 0
0184      */
0185     KoResourceSP resource(QString storageLocation, const QString &resourceType, const QString &filename);
0186 
0187     /**
0188      * @brief resourceForId returns the resource with the given id, or 0 if no such resource exists.
0189      * The resource object will have its id set but not its version.
0190      * @param resourceId the id
0191      */
0192     KoResourceSP resourceForId(int resourceId);
0193 
0194     /**
0195      * @brief setResourceActive
0196      * @param resourceId
0197      * @param active shows if the resource should be set as active or not
0198      * @return
0199      */
0200     bool setResourceActive(int resourceId, bool active);
0201 
0202     /**
0203      * @brief importResourceFromFile
0204      * @param resourceType
0205      * @param fileName
0206      * @param storageLocation: optional, the storage where the resource will be stored. Empty means in the default Folder storage.
0207      * @return the imported resource, which has been added to the database and the cache
0208      */
0209     KoResourceSP importResourceFromFile(const QString &resourceType, const QString &fileName, const bool allowOverwrite, const QString &storageLocation = QString());
0210 
0211     /**
0212      * @brief importResource
0213      * @param resourceType
0214      * @param fileName: filename that should be assigned to the resource
0215      * @param device: QIODevice where the resource should be loaded from
0216      * @param storageLocation: optional, the storage where the resource will be stored. Empty means in the default Folder storage.
0217      * @return the imported resource, which has been added to the database and the cache
0218      */
0219     KoResourceSP importResource(const QString &resourceType, const QString &fileName, QIODevice *device, const bool allowOverwrite, const QString &storageLocation = QString());
0220 
0221     /**
0222      * @brief return whether importing will overwrite some existing resource
0223      * @param resourceType
0224      * @param fileName: filename that should be assigned to the resource
0225      * @param storageLocation: optional, the storage where the resource will be stored. Empty means in the default Folder storage.
0226      */
0227     bool importWillOverwriteResource(const QString &resourceType, const QString &fileName, const QString &storageLocation = QString()) const;
0228 
0229     /**
0230      * @brief exportResource
0231      * @param resource resource to be exported
0232      * @param device: QIODevice where the resource should be loaded to
0233      * @return true if the resource has been exported successfully
0234      */
0235     bool exportResource(KoResourceSP resource, QIODevice *device);
0236 
0237     /**
0238      * @brief addResource adds the given resource to the database and potentially a storage
0239      * @param resourceType the type of the resource
0240      * @param resource the actual resource object
0241      * @param storageLocation the storage where the resource will be saved. By default this is the the default folder storage.
0242      * @return true if successful
0243      */
0244     bool addResource(const QString &resourceType, const KoResourceSP resource, const QString &storageLocation = QString());
0245 
0246     /**
0247      * @brief updateResource
0248      * @param resourceType
0249      * @param resource
0250      * @return
0251      */
0252     bool updateResource(const QString &resourceType, const KoResourceSP resource);
0253 
0254     /**
0255      * @brief Reloads the resource from its persistent storage
0256      * @param resourceType the type of the resource
0257      * @param resource the actual resource object
0258      * @return true if reloading was successful. When returned false,
0259      *         \p resource is kept unchanged
0260      */
0261     bool reloadResource(const QString &resourceType, const KoResourceSP resource);
0262 
0263     /**
0264      * @brief metaDataForResource
0265      * @param id
0266      * @return
0267      */
0268     QMap<QString, QVariant> metaDataForResource(int id) const;
0269 
0270     /**
0271      * @brief setMetaDataForResource
0272      * @param id
0273      * @param map
0274      * @return
0275      */
0276     bool setMetaDataForResource(int id, QMap<QString, QVariant> map) const;
0277 
0278     /**
0279      * @brief metaDataForStorage
0280      * @param storage
0281      * @return
0282      */
0283     QMap<QString, QVariant> metaDataForStorage(const QString &storageLocation) const;
0284 
0285     /**
0286      * @brief setMetaDataForStorage
0287      * @param storage
0288      * @param map
0289      */
0290     void setMetaDataForStorage(const QString &storageLocation, QMap<QString, QVariant> map) const;
0291 
0292     /**
0293      * Loads all the resources required by \p resource into the cache
0294      *
0295      * loadRequiredResources() also loads embedded resources and adds them
0296      * into the database.
0297      */
0298     void loadRequiredResources(KoResourceSP resource);
0299 
0300     /**
0301      * @brief tagForUrl create a tag from the database
0302      * @param tagUrl the url
0303      * @return a complete tag with all translated names and comments.
0304      */
0305     KisTagSP tagForUrl(const QString &tagUrl, const QString resourceType);
0306 
0307     /**
0308      * @brief tagForUrlNoCache create a tag from the database, don't use cache
0309      * @param tagUrl url of the tag
0310      * @param resourceType resource type of the tag
0311      * @return
0312      */
0313     static KisTagSP tagForUrlNoCache(const QString &tagUrl, const QString resourceType);
0314 
0315     KisResourceLocator(QObject *parent);
0316     KisResourceLocator(const KisResourceLocator&);
0317     KisResourceLocator operator=(const KisResourceLocator&);
0318 
0319     enum class InitializationStatus {
0320         Unknown,      // We don't know whether Krita has run on this system for this resource location yet
0321         Initialized,  // Everything is ready to start synchronizing the database
0322         FirstRun,     // Krita hasn't run for this resource location yet
0323         FirstUpdate,  // Krita was installed, but it's a version from before the resource locator existed, only user-defined resources are present
0324         Updating      // Krita is updating from an older version with resource locator
0325     };
0326 
0327     LocatorError firstTimeInstallation(InitializationStatus initializationStatus, const QString &installationResourcesLocation);
0328 
0329     // First time installation
0330     bool initializeDb();
0331 
0332     // Synchronize on restarting Krita to see whether the user has added any storages or resources to the resources location
0333     bool synchronizeDb();
0334 
0335     void findStorages();
0336     QList<KisResourceStorageSP> storages() const;
0337 
0338     KisResourceStorageSP storageByLocation(const QString &location) const;
0339     KisResourceStorageSP folderStorage() const;
0340     KisResourceStorageSP memoryStorage() const;
0341 
0342     struct ResourceStorage {
0343         QString storageLocation;
0344         QString resourceType;
0345         QString resourceFileName;
0346      };
0347 
0348     friend class KisMyPaintPaintOpPreset;
0349 
0350     ResourceStorage getResourceStorage(int resourceId) const;
0351     QString makeStorageLocationAbsolute(QString storageLocation) const;
0352     QString makeStorageLocationRelative(QString location) const;
0353 
0354     class Private;
0355     QScopedPointer<Private> d;
0356 };
0357 
0358 #endif // KISRESOURCELOCATOR_H