File indexing completed on 2024-05-19 04:27:38

0001 /*
0002  * SPDX-FileCopyrightText: 2018 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #ifndef KISRESOURCEMODEL_H
0008 #define KISRESOURCEMODEL_H
0009 
0010 #include <QAbstractTableModel>
0011 #include <QSortFilterProxyModel>
0012 
0013 #include <kritaresources_export.h>
0014 
0015 #include <KoResource.h>
0016 #include <KisTag.h>
0017 
0018 
0019 /**
0020  * KisAbstractResourceModel defines the interface for accessing resources
0021  * that is used in KisResourceModel and the various filter/proxy models
0022  */
0023 class KRITARESOURCES_EXPORT KisAbstractResourceModel {
0024 
0025 public:
0026 
0027     /**
0028      * @brief The Columns enum indexes the columns in the model. To get
0029      * the thumbnail for a particular resource, create the index with
0030      * QModelIndex(row, Thumbnail).
0031      */
0032     enum Columns {
0033         Id = 0,
0034         StorageId,
0035         Name,
0036         Filename,
0037         Tooltip,
0038         Thumbnail,
0039         /// Whether the resource is active. Duplicate of ResourceActive.
0040         Status,
0041         Location,
0042         ResourceType,
0043         Tags,
0044         MD5,
0045         /// A larger thumbnail for displaying in a tooltip. 200x200 or so.
0046         LargeThumbnail,
0047         /// A dirty resource is one that has been modified locally but not saved
0048         Dirty,
0049         /// MetaData is a map of key, value pairs that is associated with this resource
0050         MetaData,
0051         /// Whether the current resource is active
0052         ResourceActive,
0053         /// Whether the current resource's storage is active
0054         StorageActive,
0055     };
0056 
0057     virtual ~KisAbstractResourceModel(){}
0058 
0059     /**
0060      * @brief resourceForIndex returns a properly versioned and id'ed resource object
0061      */
0062     virtual KoResourceSP resourceForIndex(QModelIndex index = QModelIndex()) const = 0;
0063 
0064     /**
0065      * @brief indexFromResource
0066      * @param resource
0067      * @return
0068      */
0069     virtual QModelIndex indexForResource(KoResourceSP resource) const = 0;
0070 
0071     /**
0072      * @brief indexFromResource
0073      * @param resourceId resource id for which we want to get an index
0074      * @return
0075      */
0076     virtual QModelIndex indexForResourceId(int resourceId) const = 0;
0077 
0078     /**
0079      * @brief setResourceActive changes 'active' state of the resource
0080      * @param index the index of the resource
0081      * @param value new 'active' state of the resource
0082      * @return true if the new state has been assigned successfully
0083      */
0084     virtual bool setResourceActive(const QModelIndex &index, bool value) = 0;
0085 
0086     /**
0087      * A convenience function to put a resource into inactive state
0088      */
0089     inline bool setResourceInactive(const QModelIndex &index) {
0090         return setResourceActive(index, false);
0091     }
0092 
0093     /**
0094      * @brief importResourceFile
0095      * @param filename
0096      * @return
0097      */
0098     virtual KoResourceSP importResourceFile(const QString &filename, const bool allowOverwrite, const QString &storageId = QString("")) = 0;
0099 
0100     /**
0101      * @brief importResource imports a resource from a QIODevice
0102      *
0103      * Importing a resource from a binary blob is the only way to guarantee that its
0104      * MD5 checksum is kept persistent. The underlying storage will just copy bytes
0105      * into its location.
0106      *
0107      * @param filename file name of the resource if preset. File name may be used
0108      *                 for addressing the resource, so it is usually preferred to
0109      *                 preserve it.
0110      *
0111      * @param device device where the resource should be read from
0112      *
0113      * @return the loaded resource object
0114      */
0115     virtual KoResourceSP importResource(const QString &filename, QIODevice *device, const bool allowOverwrite, const QString &storageId = QString("")) = 0;
0116 
0117     /**
0118      * @brief importWillOverwriteResource checks is importing a resource with this filename will overwrite anything
0119      *
0120      * If this function returns true, then importResource() is guaranteed to
0121      * fail with 'allowOverwrite' set to false.
0122      *
0123      * @param filename file name of the resource if preset. File name may be used
0124      *                 for addressing the resource, so it is usually preferred to
0125      *                 preserve it.
0126      *
0127      * @return true if the some existing will be overwritten while importing
0128      */
0129     virtual bool importWillOverwriteResource(const QString &fileName, const QString &storageLocation = QString()) const = 0;
0130 
0131     /**
0132      * @brief exportResource exports a resource into a QIODevice
0133      *
0134      * Exporting a resource as a binary blob is the only way to guarantee that its
0135      * MD5 checksum is kept persistent. The underlying storage will just copy bytes
0136      * into the device without doing any conversions
0137      *
0138      * @param resource the resource to be exported
0139      *
0140      * @param device device where the resource should be written to
0141      *
0142      * @return true if export operation has been successful
0143      */
0144     virtual bool exportResource(KoResourceSP resource, QIODevice *device) = 0;
0145 
0146     /**
0147      * @brief addResource adds the given resource to the database and storage. If the resource
0148      * already exists in the given storage with md5, filename or name, the existing resource
0149      * will be updated instead. If the existing resource was inactive, it will be active
0150      * (undeleted).
0151      *
0152      * @param resource the resource itself
0153      * @param storageId the id of the storage (could be "memory" for temporary
0154      * resources, the document's storage id for document storages or empty to save
0155      * to the default resources folder
0156      * @return true if adding the resource succeeded.
0157      */
0158     virtual bool addResource(KoResourceSP resource, const QString &storageId = QString("")) = 0;
0159 
0160     /**
0161      * @brief updateResource creates a new version of the resource in the storage and
0162      * in the database. This will also set the resource to active if it was inactive.
0163      *
0164      * Note: if the storage does not support versioning, updating the resource will fail.
0165      *
0166      * @param resource
0167      * @return true if the resource was successful updated,
0168      */
0169     virtual bool updateResource(KoResourceSP resource) = 0;
0170 
0171     /**
0172      * @brief reloadResource
0173      * @param resource
0174      * @return
0175      */
0176     virtual bool reloadResource(KoResourceSP resource) = 0;
0177 
0178     /**
0179      * @brief renameResource name the given resource. The resource will have its
0180      * name field reset, will be saved to the storage and there will be a new
0181      * version created in the database.
0182      * @param resource The resource to rename
0183      * @param name The new name
0184      * @return true if the operation succeeded.
0185      */
0186     virtual bool renameResource(KoResourceSP resource, const QString &name) = 0;
0187 
0188     /**
0189      * @brief setResourceMetaData
0190      * @param metadata
0191      * @return
0192      */
0193     virtual bool setResourceMetaData(KoResourceSP resource, QMap<QString, QVariant> metadata) = 0;
0194 };
0195 
0196 class KRITARESOURCES_EXPORT KisAbstractResourceFilterInterface
0197 {
0198 public:
0199     virtual ~KisAbstractResourceFilterInterface() {}
0200 
0201     enum ResourceFilter {
0202         ShowInactiveResources = 0,
0203         ShowActiveResources,
0204         ShowAllResources
0205     };
0206 
0207     enum StorageFilter {
0208         ShowInactiveStorages = 0,
0209         ShowActiveStorages,
0210         ShowAllStorages
0211     };
0212 public:
0213 
0214     /**
0215      * Select status of the resources that should be shown
0216      */
0217     virtual void setResourceFilter(ResourceFilter filter) = 0;
0218 
0219     /**
0220      * Select status of the storages that should be shown
0221      */
0222     virtual void setStorageFilter(StorageFilter filter) = 0;
0223 };
0224 
0225 /**
0226  * @brief The KisAllresourcesModel class provides access to the cache database
0227  * for a particular resource type. Instances should be retrieved using
0228  * KisResourceModelProvider. All resources are part of this model, active and
0229  * inactive, from all storages, active and inactive.
0230  */
0231 class KRITARESOURCES_EXPORT KisAllResourcesModel : public QAbstractTableModel, public KisAbstractResourceModel
0232 {
0233     Q_OBJECT
0234 
0235 private:
0236     friend class KisResourceModelProvider;
0237     friend class KisResourceModel;
0238     friend class KisResourceQueryMapper;
0239     KisAllResourcesModel(const QString &resourceType, QObject *parent = 0);
0240 
0241 public:
0242 
0243     ~KisAllResourcesModel() override;
0244 
0245 // QAbstractItemModel API
0246 
0247     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
0248     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
0249     QVariant data(const QModelIndex &index, int role) const override;
0250     QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
0251     bool setData(const QModelIndex &index, const QVariant &value, int role) override;
0252     Qt::ItemFlags flags(const QModelIndex &index) const override;
0253 
0254 // Resources API
0255 
0256     KoResourceSP resourceForIndex(QModelIndex index = QModelIndex()) const override;
0257     QModelIndex indexForResource(KoResourceSP resource) const override;
0258     QModelIndex indexForResourceId(int resourceId) const override;
0259     bool setResourceActive(const QModelIndex &index, bool value) override;
0260     KoResourceSP importResourceFile(const QString &filename, const bool allowOverwrite, const QString &storageId = QString("")) override;
0261     KoResourceSP importResource(const QString &filename, QIODevice *device, const bool allowOverwrite, const QString &storageId = QString("")) override;
0262     bool importWillOverwriteResource(const QString &fileName, const QString &storageLocation = QString()) const override;
0263     bool exportResource(KoResourceSP resource, QIODevice *device) override;
0264     bool addResource(KoResourceSP resource, const QString &storageId = QString("")) override;
0265     bool updateResource(KoResourceSP resource) override;
0266     bool reloadResource(KoResourceSP resource) override;
0267     bool renameResource(KoResourceSP resource, const QString &name) override;
0268     bool setResourceMetaData(KoResourceSP resource, QMap<QString, QVariant> metadata) override;
0269 
0270 private Q_SLOTS:
0271 
0272     void storageActiveStateChanged(const QString &location);
0273 
0274     /**
0275      * A special connection for KisResourceLocator, which can import
0276      * a resource on its own (all other places are supposed to do that
0277      * via KisResourceModel). This call is needed to make sure the
0278      * internal query in the model is reset.
0279      *
0280      * WARNING: the resource is expected to be added to the **end**
0281      * of the model, that is, its resourceId is expected to be greater
0282      * than any existing resource.
0283      */
0284     void beginExternalResourceImport(const QString &resourceType, int numResources);
0285 
0286     /**
0287      * \see beginExternalResourceImport
0288      */
0289     void endExternalResourceImport(const QString &resourceType);
0290 
0291     /**
0292      * A special connection for KisResourceLocator, which can remove the resource
0293      * while importing something with overwrite. In such a case the locator will
0294      * emit both, remove and insert signals for both the resources.
0295      */
0296     void beginExternalResourceRemove(const QString &resourceType, const QVector<int> &resourceId);
0297 
0298     /**
0299      * \see beginExternalResourceRemove
0300      */
0301     void endExternalResourceRemove(const QString &resourceType);
0302 
0303     /**
0304      * A special connection for KisResourceLocator, which is triggered when the
0305      * resource changes its 'active' state
0306      */
0307     void slotResourceActiveStateChanged(const QString &resourceType, int resourceId);
0308 
0309 public:
0310 
0311     KoResourceSP resourceForId(int id) const;
0312 
0313     /**
0314      * @brief resourceExists checks whether there is a resource with, in order,
0315      * the given md5, the filename or the resource name.
0316      */
0317     bool resourceExists(const QString &md5, const QString &filename, const QString &name);
0318 
0319     /**
0320      * resourceForFilename returns the first resource with the given filename that
0321      * is active and is in an active store. Note that the filename does not include
0322      * a path to the storage, and if there are resources with the same filename
0323      * in several active storages, only one resource is returned.
0324      *
0325      * @param filename the filename we're looking for
0326      * @param checkDependentResources: check whether we should try to find a resource embedded
0327      * in a resource that's not been loaded yet in the metadata table.
0328      * @return a resource if one is found, or 0 if none are found
0329      */
0330     QVector<KoResourceSP> resourcesForFilename(QString filename) const;
0331 
0332     /**
0333      * resourceForName returns the first resource with the given name that
0334      * is active and is in an active store. Note that if there are resources
0335      * with the same name in several active storages, only one resource
0336      * is returned.
0337      *
0338      * @return a resource if one is found, or 0 if none are found
0339      */
0340     QVector<KoResourceSP> resourcesForName(const QString &name) const;
0341     QVector<KoResourceSP> resourcesForMD5(const QString &md5sum) const;
0342     QVector<KisTagSP> tagsForResource(int resourceId) const;
0343 
0344 private:
0345 
0346     bool resetQuery();
0347 
0348     struct Private;
0349     Private *const d;
0350 
0351 };
0352 
0353 /**
0354  * @brief The KisResourceModel class provides the main access to resources. It is possible
0355  * to filter the resources returned by the active status flag of the resources and the
0356  * storages
0357  */
0358 class KRITARESOURCES_EXPORT KisResourceModel : public QSortFilterProxyModel, public KisAbstractResourceModel, public KisAbstractResourceFilterInterface
0359 {
0360     Q_OBJECT
0361 
0362 public:
0363 
0364     KisResourceModel(const QString &type, QObject *parent = 0);
0365     ~KisResourceModel() override;
0366 
0367 
0368     void setResourceFilter(ResourceFilter filter) override;
0369     void setStorageFilter(StorageFilter filter) override;
0370 
0371     void showOnlyUntaggedResources(bool showOnlyUntagged);
0372 
0373 public:
0374 
0375     KoResourceSP resourceForIndex(QModelIndex index = QModelIndex()) const override;
0376     QModelIndex indexForResource(KoResourceSP resource) const override;
0377     QModelIndex indexForResourceId(int resourceId) const override;
0378     bool setResourceActive(const QModelIndex &index, bool value) override;
0379     KoResourceSP importResourceFile(const QString &filename, const bool allowOverwrite, const QString &storageId = QString("")) override;
0380     KoResourceSP importResource(const QString &filename, QIODevice *device, const bool allowOverwrite, const QString &storageId = QString("")) override;
0381     bool importWillOverwriteResource(const QString &fileName, const QString &storageLocation = QString()) const override;
0382     bool exportResource(KoResourceSP resource, QIODevice *device) override;
0383     bool addResource(KoResourceSP resource, const QString &storageId = QString("")) override;
0384     bool updateResource(KoResourceSP resource) override;
0385     bool reloadResource(KoResourceSP resource) override;
0386     bool renameResource(KoResourceSP resource, const QString &name) override;
0387     bool setResourceMetaData(KoResourceSP resource, QMap<QString, QVariant> metadata) override;
0388 
0389 public:
0390 
0391     KoResourceSP resourceForId(int id) const;
0392 
0393     /**
0394      * resourceForFilename returns the resources with the given filename that
0395      * fit the current filters. Note that the filename does not include
0396      * a path to the storage.
0397      *
0398      * @return a resource if one is found, or 0 if none are found
0399      */
0400     QVector<KoResourceSP> resourcesForFilename(QString fileName) const;
0401 
0402     /**
0403      * resourceForName returns the resources with the given name that
0404      * fit the current filters.
0405      *
0406      * @return a resource if one is found, or 0 if none are found
0407      */
0408     QVector<KoResourceSP> resourcesForName(QString name) const;
0409     QVector<KoResourceSP> resourcesForMD5(const QString md5sum) const;
0410     QVector<KisTagSP> tagsForResource(int resourceId) const;
0411 
0412 protected:
0413 
0414     bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const override;
0415     bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
0416     bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
0417 
0418 private:
0419     QVector<KoResourceSP> filterByColumn(const QString filter, KisAllResourcesModel::Columns column) const;
0420     bool filterResource(const QModelIndex &idx) const;
0421 
0422     struct Private;
0423     Private *const d;
0424 
0425     Q_DISABLE_COPY(KisResourceModel)
0426 
0427 };
0428 
0429 
0430 
0431 #endif // KISRESOURCEMODEL_H