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

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