diff --git a/libs/resources/CMakeLists.txt b/libs/resources/CMakeLists.txt index 68fc51c820..6a21b73714 100644 --- a/libs/resources/CMakeLists.txt +++ b/libs/resources/CMakeLists.txt @@ -1,74 +1,75 @@ include_directories(${QUAZIP_INCLUDE_DIRS}) add_subdirectory(tests) set(kritaresources_LIB_SRCS KisResourceCacheDb.cpp KisResourceLoader.cpp KisResourceLoaderRegistry.cpp KisResourceLocator.cpp KisResourceStorage.cpp KisResourceModel.cpp KisTagFilterResourceProxyModel.cpp + KisResourcesActiveFilterModel.cpp KisResourceModelProvider.cpp KisResourceTypeModel.cpp KisStorageModel.cpp KisStorageFilterProxyModel.cpp KisResourceIterator.cpp KisResourceSearchBoxFilter.cpp KisStoragePlugin.cpp KisBundleStorage.cpp KisFolderStorage.cpp KisMemoryStorage.cpp KisTag.cpp KisTagModel.cpp KisTagModelProvider.cpp KisActiveFilterTagProxyModel.cpp KoResource.cpp KoResourceBundle.cpp KoResourceBundleManifest.cpp KoMD5Generator.cpp KoResourcePaths.cpp ResourceDebug.cpp kconfigini.cpp kconfigdata.cpp kconfigbackend.cpp KisRequiredResourcesOperators.cpp KisResourcesInterface.cpp KisLocalStrokeResources.cpp KisGlobalResourcesInterface.cpp ) qt5_add_resources(kritaresources_LIB_SRCS sql.qrc) add_library(kritaresources SHARED ${kritaresources_LIB_SRCS}) generate_export_header(kritaresources BASE_NAME kritaresources) target_link_libraries(kritaresources PUBLIC Qt5::Core Qt5::Widgets Qt5::Sql PRIVATE kritaversion kritaglobal kritaplugin kritastore KF5::ConfigCore KF5::CoreAddons KF5::I18n ${QUAZIP_LIBRARIES} ) set_target_properties(kritaresources PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritaresources ${INSTALL_TARGETS_DEFAULT_ARGS} ) diff --git a/libs/resources/KisResourceModel.cpp b/libs/resources/KisResourceModel.cpp index 439432c468..2d76159de1 100644 --- a/libs/resources/KisResourceModel.cpp +++ b/libs/resources/KisResourceModel.cpp @@ -1,571 +1,586 @@ /* * Copyright (C) 2018 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisResourceModel.h" #include #include #include #include #include #include #include #include struct KisResourceModel::Private { QSqlQuery resourcesQuery; QSqlQuery tagQuery; QString resourceType; - int columnCount {9}; + int columnCount {10}; int cachedRowCount {-1}; }; //static int s_i = 0; KisResourceModel::KisResourceModel(const QString &resourceType, QObject *parent) : QAbstractTableModel(parent) , d(new Private) { //qDebug() << "ResourceModel" << s_i << resourceType; s_i++; d->resourceType = resourceType; bool r = d->resourcesQuery.prepare("SELECT resources.id\n" ", resources.storage_id\n" ", resources.name\n" ", resources.filename\n" ", resources.tooltip\n" ", resources.thumbnail\n" ", resources.status\n" ", storages.location\n" ", resources.version\n" ", resource_types.name as resource_type\n" + ", resources.status as resource_active\n" + ", storages.active as storage_active\n" "FROM resources\n" ", resource_types\n" ", storages\n" "WHERE resources.resource_type_id = resource_types.id\n" "AND resources.storage_id = storages.id\n" "AND resource_types.name = :resource_type\n" - "AND resources.status = 1\n" - "AND storages.active = 1"); + "ORDER BY resources.id"); if (!r) { qWarning() << "Could not prepare KisResourceModel query" << d->resourcesQuery.lastError(); } d->resourcesQuery.bindValue(":resource_type", d->resourceType); resetQuery(); r = d->tagQuery.prepare("SELECT tags.id\n" ", tags.url\n" ", tags.name\n" ", tags.comment\n" "FROM tags\n" ", resource_tags\n" "WHERE tags.active > 0\n" // make sure the tag is active "AND tags.id = resource_tags.tag_id\n" // join tags + resource_tags by tag_id - "AND resource_tags.resource_id = :resource_id\n"); // make sure we're looking for tags for a specific resource + "AND resource_tags.resource_id = :resource_id\n" + "ORDER BY tags.id"); // make sure we're looking for tags for a specific resource if (!r) { qWarning() << "Could not prepare TagsForResource query" << d->tagQuery.lastError(); } } KisResourceModel::~KisResourceModel() { delete d; } int KisResourceModel::columnCount(const QModelIndex &/*parent*/) const { return d->columnCount; } QVariant KisResourceModel::data(const QModelIndex &index, int role) const { QVariant v; if (!index.isValid()) return v; if (index.row() > rowCount()) return v; if (index.column() > d->columnCount) return v; bool pos = const_cast(this)->d->resourcesQuery.seek(index.row()); if (pos) { switch(role) { case Qt::DisplayRole: { switch(index.column()) { case Id: return d->resourcesQuery.value("id"); case StorageId: return d->resourcesQuery.value("storage_id"); case Name: return d->resourcesQuery.value("name"); case Filename: return d->resourcesQuery.value("filename"); case Tooltip: return d->resourcesQuery.value("tooltip"); case Thumbnail: { QByteArray ba = d->resourcesQuery.value("thumbnail").toByteArray(); QBuffer buf(&ba); buf.open(QBuffer::ReadOnly); QImage img; img.load(&buf, "PNG"); return QVariant::fromValue(img); } case Status: return d->resourcesQuery.value("status"); case Location: return d->resourcesQuery.value("location"); case ResourceType: return d->resourcesQuery.value("resource_type"); + case ResourceActive: + return d->resourcesQuery.value("resource_active"); + case StorageActive: + return d->resourcesQuery.value("storage_active"); default: ; }; Q_FALLTHROUGH(); } case Qt::DecorationRole: { if (index.column() == Thumbnail) { QByteArray ba = d->resourcesQuery.value("thumbnail").toByteArray(); QBuffer buf(&ba); buf.open(QBuffer::ReadOnly); QImage img; img.load(&buf, "PNG"); return QVariant::fromValue(img); } return QVariant(); } case Qt::ToolTipRole: Q_FALLTHROUGH(); case Qt::StatusTipRole: Q_FALLTHROUGH(); case Qt::WhatsThisRole: return d->resourcesQuery.value("tooltip"); case Qt::UserRole + Id: return d->resourcesQuery.value("id"); case Qt::UserRole + StorageId: return d->resourcesQuery.value("storage_id"); case Qt::UserRole + Name: return d->resourcesQuery.value("name"); case Qt::UserRole + Filename: return d->resourcesQuery.value("filename"); case Qt::UserRole + Tooltip: return d->resourcesQuery.value("tooltip"); case Qt::UserRole + Thumbnail: { QByteArray ba = d->resourcesQuery.value("thumbnail").toByteArray(); QBuffer buf(&ba); buf.open(QBuffer::ReadOnly); QImage img; img.load(&buf, "PNG"); return QVariant::fromValue(img); } case Qt::UserRole + Status: return d->resourcesQuery.value("status"); case Qt::UserRole + Location: return d->resourcesQuery.value("location"); case Qt::UserRole + ResourceType: return d->resourcesQuery.value("resource_type"); case Qt::UserRole + Tags: { QVector tags = tagsForResource(d->resourcesQuery.value("id").toInt()); QStringList tagNames; Q_FOREACH(const KisTagSP tag, tags) { tagNames << tag->name(); } return tagNames; } case Qt::UserRole + Dirty: { QString storageLocation = d->resourcesQuery.value("location").toString(); QString filename = d->resourcesQuery.value("filename").toString(); // An uncached resource has not been loaded, so it cannot be dirty if (!KisResourceLocator::instance()->resourceCached(storageLocation, d->resourceType, filename)) { return false; } else { // Now we have to check the resource, but that's cheap since it's been loaded in any case KoResourceSP resource = resourceForIndex(index); return resource->isDirty(); } } case Qt::UserRole + MetaData: { QMap r = KisResourceLocator::instance()->metaDataForResource(d->resourcesQuery.value("id").toInt()); return r; } case Qt::UserRole + KoResourceRole: { KoResourceSP tag = resourceForIndex(index); QVariant response; response.setValue(tag); return response; } - + case Qt::UserRole + ResourceActive: + { + return d->resourcesQuery.value("resource_active"); + } + case Qt::UserRole + StorageActive: + { + return d->resourcesQuery.value("storage_active"); + } default: ; } } return v; } QVariant KisResourceModel::headerData(int section, Qt::Orientation orientation, int role) const { QVariant v = QVariant(); if (role != Qt::DisplayRole) { return v; } if (orientation == Qt::Horizontal) { switch(section) { case Id: v = i18n("Id"); break; case StorageId: v = i18n("Storage ID"); break; case Name: v = i18n("Name"); break; case Filename: v = i18n("File Name"); break; case Tooltip: v = i18n("Tooltip"); break; case Thumbnail: v = i18n("Image"); break; case Status: v = i18n("Status"); break; case Location: v = i18n("Location"); break; case ResourceType: v = i18n("Resource Type"); break; + case ResourceActive: + v = i18n("Active"); + case StorageActive: + v = i18n("Storage Active"); default: v = QString::number(section); } return v; } return QAbstractItemModel::headerData(section, orientation, role); } //static int s_i2 {0}; KoResourceSP KisResourceModel::resourceForIndex(QModelIndex index) const { KoResourceSP resource = 0; if (!index.isValid()) return resource; if (index.row() > rowCount()) return resource; if (index.column() > d->columnCount) return resource; //qDebug() << "KisResourceModel::resourceForIndex" << s_i2 << d->resourceType; s_i2++; bool pos = const_cast(this)->d->resourcesQuery.seek(index.row()); if (pos) { int id = d->resourcesQuery.value("id").toInt(); resource = resourceForId(id); } return resource; } KoResourceSP KisResourceModel::resourceForId(int id) const { return KisResourceLocator::instance()->resourceForId(id); } KoResourceSP KisResourceModel::resourceForFilename(QString filename) const { KoResourceSP resource = 0; QSqlQuery q; bool r = q.prepare("SELECT resources.id AS id\n" "FROM resources\n" ", resource_types\n" ", storages\n" "WHERE resources.resource_type_id = resource_types.id\n" "AND resources.storage_id = storages.id\n" "AND resources.filename = :resource_filename\n" "AND resource_types.name = :resource_type\n" "AND resources.status = 1\n" "AND storages.active = 1"); if (!r) { qWarning() << "Could not prepare KisResourceModel query for resource name" << q.lastError(); } q.bindValue(":resource_filename", filename); q.bindValue(":resource_type", d->resourceType); r = q.exec(); if (!r) { qWarning() << "Could not select" << d->resourceType << "resources by filename" << q.lastError() << q.boundValues(); } if (q.first()) { int id = q.value("id").toInt(); resource = KisResourceLocator::instance()->resourceForId(id); } return resource; } KoResourceSP KisResourceModel::resourceForName(QString name) const { KoResourceSP resource = 0; QSqlQuery q; bool r = q.prepare("SELECT resources.id AS id\n" "FROM resources\n" ", resource_types\n" ", storages\n" "WHERE resources.resource_type_id = resource_types.id\n" "AND resources.storage_id = storages.id\n" "AND resources.name = :resource_name\n" "AND resource_types.name = :resource_type\n" "AND resources.status = 1\n" "AND storages.active = 1"); if (!r) { qWarning() << "Could not prepare KisResourceModel query for resource name" << q.lastError(); } q.bindValue(":resource_type", d->resourceType); q.bindValue(":resource_name", name); r = q.exec(); if (!r) { qWarning() << "Could not select" << d->resourceType << "resources by name" << q.lastError() << q.boundValues(); } if (q.first()) { int id = q.value("id").toInt(); resource = KisResourceLocator::instance()->resourceForId(id); } return resource; } KoResourceSP KisResourceModel::resourceForMD5(const QByteArray md5sum) const { KoResourceSP resource = 0; QSqlQuery q; bool r = q.prepare("SELECT resource_id AS id\n" "FROM versioned_resources\n" "WHERE md5sum = :md5sum"); if (!r) { qWarning() << "Could not prepare KisResourceModel query for resource md5" << q.lastError(); } q.bindValue(":md5sum", md5sum.toHex()); r = q.exec(); if (!r) { qWarning() << "Could not select" << d->resourceType << "resources by md5" << q.lastError() << q.boundValues(); } if (q.first()) { int id = q.value("id").toInt(); resource = KisResourceLocator::instance()->resourceForId(id); } return resource; } //static int s_i3 {0}; QModelIndex KisResourceModel::indexFromResource(KoResourceSP resource) const { if (!resource || !resource->valid()) return QModelIndex(); //qDebug() << "KisResourceModel::indexFromResource" << s_i3 << d->resourceType; s_i3++; // For now a linear seek to find the first resource with the right id d->resourcesQuery.first(); do { if (d->resourcesQuery.value("id").toInt() == resource->resourceId()) { return createIndex(d->resourcesQuery.at(), 0); } } while (d->resourcesQuery.next()); return QModelIndex(); } //static int s_i4 {0}; bool KisResourceModel::removeResource(const QModelIndex &index) { if (index.row() > rowCount()) return false; if (index.column() > d->columnCount) return false; //qDebug() << "KisResourceModel::removeResource" << s_i4 << d->resourceType; s_i4++; bool pos = d->resourcesQuery.seek(index.row()); if (!pos) return false; int resourceId = d->resourcesQuery.value("id").toInt(); if (!KisResourceLocator::instance()->removeResource(resourceId)) { qWarning() << "Failed to remove resource" << resourceId; return false; } return resetQuery(); } //static int s_i5 {0}; bool KisResourceModel::removeResource(KoResourceSP resource) { if (!resource || !resource->valid()) return false; //qDebug() << "KisResourceModel::remvoeResource 2" << s_i5 << d->resourceType; s_i5++; if (!KisResourceLocator::instance()->removeResource(resource->resourceId())) { qWarning() << "Failed to remove resource" << resource->resourceId(); return false; } return resetQuery(); } //static int s_i6 {0}; bool KisResourceModel::importResourceFile(const QString &filename) { //qDebug() << "KisResourceModel::importResource" << s_i6 << d->resourceType; s_i6++; if (!KisResourceLocator::instance()->importResourceFromFile(d->resourceType, filename)) { qWarning() << "Failed to import resource" << filename; return false; } return resetQuery(); } //static int s_i7 {0}; bool KisResourceModel::addResource(KoResourceSP resource, const QString &storageId) { if (!resource || !resource->valid()) { qWarning() << "Cannot add resource. Resource is null or not valid"; return false; } //qDebug() << "KisResourceModel::addResource" << s_i7 << d->resourceType; s_i7++; if (!KisResourceLocator::instance()->addResource(d->resourceType, resource, storageId)) { qWarning() << "Failed to add resource" << resource->name(); return false; } return resetQuery(); } //static int s_i8 {0}; bool KisResourceModel::updateResource(KoResourceSP resource) { if (!resource || !resource->valid()) { qWarning() << "Cannot update resource. Resource is null or not valid"; return false; } //qDebug() << "KisResourceModel::updateResource" << s_i8 << d->resourceType; s_i8++; if (!KisResourceLocator::instance()->updateResource(d->resourceType, resource)) { qWarning() << "Failed to update resource" << resource; return false; } return resetQuery(); } bool KisResourceModel::renameResource(KoResourceSP resource, const QString &name) { if (!resource || !resource->valid() || name.isEmpty()) { qWarning() << "Cannot rename resources. Resource is NULL or not valid or name is empty"; return false; } resource->setName(name); if (!KisResourceLocator::instance()->updateResource(d->resourceType, resource)) { qWarning() << "Failed to rename resource" << resource << name; return false; } return resetQuery(); } //static int s_i9 {0}; bool KisResourceModel::setResourceMetaData(KoResourceSP resource, QMap metadata) { //qDebug() << "KisResourceModel::setResourceMetaData" << s_i9 << d->resourceType; s_i9++; Q_ASSERT(resource->resourceId() > -1); return KisResourceLocator::instance()->setMetaDataForResource(resource->resourceId(), metadata); } bool KisResourceModel::resetQuery() { QElapsedTimer t; t.start(); emit beforeResourcesLayoutReset(QModelIndex()); beginResetModel(); bool r = d->resourcesQuery.exec(); if (!r) { qWarning() << "Could not select" << d->resourceType << "resources" << d->resourcesQuery.lastError() << d->resourcesQuery.boundValues(); } d->cachedRowCount = -1; endResetModel(); emit afterResourcesLayoutReset(); qDebug() << "KisResourceModel::resetQuery for" << d->resourceType << "took" << t.elapsed() << "ms"; return r; } QVector KisResourceModel::tagsForResource(int resourceId) const { return KisTagModelProvider::tagModel(d->resourceType)->tagsForResource(resourceId); } int KisResourceModel::rowCount(const QModelIndex &) const { if (d->cachedRowCount < 0) { QSqlQuery q; q.prepare("SELECT count(*)\n" "FROM resources\n" ", resource_types\n" ", storages\n" "WHERE resources.resource_type_id = resource_types.id\n" "AND resource_types.name = :resource_type\n" - "AND resources.storage_id = storages.id\n" - "AND resources.status = 1\n" - "AND storages.active = 1"); + "AND resources.storage_id = storages.id\n"); q.bindValue(":resource_type", d->resourceType); q.exec(); q.first(); const_cast(this)->d->cachedRowCount = q.value(0).toInt(); } return d->cachedRowCount; } diff --git a/libs/resources/KisResourceModel.h b/libs/resources/KisResourceModel.h index 24f59e1a14..c099cc80e3 100644 --- a/libs/resources/KisResourceModel.h +++ b/libs/resources/KisResourceModel.h @@ -1,217 +1,222 @@ /* * Copyright (C) 2018 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KISRESOURCEMODEL_H #define KISRESOURCEMODEL_H #include #include #include #include /** * KisAbstractResourceModel defines the interface for accessing resources * that is used in KisResourceModel and the various filter/proxy models */ class KRITARESOURCES_EXPORT KisAbstractResourceModel { public: virtual ~KisAbstractResourceModel(){} /** * @brief resourceForIndex * @param index * @return */ virtual KoResourceSP resourceForIndex(QModelIndex index = QModelIndex()) const = 0; /** * @brief indexFromResource * @param resource * @return */ virtual QModelIndex indexFromResource(KoResourceSP resource) const = 0; /** * @brief removeResource * @param index * @return */ virtual bool removeResource(const QModelIndex &index) = 0; /** * @brief importResourceFile * @param filename * @return */ virtual bool importResourceFile(const QString &filename) = 0; /** * @brief addResource adds the given resource to the database and storage * @param resource the resource itself * @param storageId the id of the storage (could be "memory" for temporary * resources, the document's storage id for document storages or empty to save * to the default resources folder * @return true if adding the resoruce succeeded. */ virtual bool addResource(KoResourceSP resource, const QString &storageId = QString()) = 0; /** * @brief updateResource * @param resource * @return */ virtual bool updateResource(KoResourceSP resource) = 0; /** * @brief renameResource name the given resource. The resource will have its * name field reset, will be saved to the storage and there will be a new * version created in the database. * @param resource The resource to rename * @param name The new name * @return true if the operation succeeded. */ virtual bool renameResource(KoResourceSP resource, const QString &name) = 0; /** * @brief removeResource * @param resource * @return */ virtual bool removeResource(KoResourceSP resource) = 0; /** * @brief setResourceMetaData * @param metadata * @return */ virtual bool setResourceMetaData(KoResourceSP resource, QMap metadata) = 0; }; /** * @brief The KisResourceModel class provides access to the cache database * for a particular resource type. Instances should be retrieved using * KisResourceModelProvider. All resources are part of this model, active and - * inactive. + * inactive, from all storages, active and inactive. */ class KRITARESOURCES_EXPORT KisResourceModel : public QAbstractTableModel, public KisAbstractResourceModel { Q_OBJECT public: /** * @brief The Columns enum indexes the columns in the model. To get * the thumbnail for a particular resource, create the index with * QModelIndex(row, Thumbnail). */ enum Columns { Id = 0, StorageId, Name, Filename, Tooltip, Thumbnail, Status, Location, ResourceType, Tags, /// A larger thumbnail for displaying in a tooltip. 200x200 or so. LargeThumbnail, /// A dirty resource is one that has been modified locally but not saved Dirty, /// MetaData is a map of key, value pairs that is associated with this resource MetaData, - KoResourceRole + /// XXX: what is this used for, again? + KoResourceRole, + /// Whether the current resource is active + ResourceActive, + /// Whether the current resource's storage isa ctive + StorageActive }; private: friend class KisResourceModelProvider; friend class TestResourceModel; KisResourceModel(const QString &resourceType, QObject *parent = 0); public: ~KisResourceModel() override; // QAbstractItemModel API int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; // Resources API /** * @brief resourceForIndex returns a properly versioned and id's resource object */ KoResourceSP resourceForIndex(QModelIndex index = QModelIndex()) const override; KoResourceSP resourceForId(int id) const; /** * resourceForFilename returns the first resource with the given filename that * is active and is in an active store. Note that the filename does not include * a path to the storage, and if there are resources with the same filename * in several active storages, only one resource is returned. * * @return a resource if one is found, or 0 if none are found */ KoResourceSP resourceForFilename(QString fileName) const; /** * resourceForName returns the first resource with the given name that * is active and is in an active store. Note that if there are resources * with the same name in several active storages, only one resource * is returned. * * @return a resource if one is found, or 0 if none are found */ KoResourceSP resourceForName(QString name) const; KoResourceSP resourceForMD5(const QByteArray md5sum) const; QModelIndex indexFromResource(KoResourceSP resource) const override; bool removeResource(const QModelIndex &index) override; bool removeResource(KoResourceSP resource) override; bool importResourceFile(const QString &filename) override; bool addResource(KoResourceSP resource, const QString &storageId = QString()) override; bool updateResource(KoResourceSP resource) override; bool renameResource(KoResourceSP resource, const QString &name) override; bool setResourceMetaData(KoResourceSP resource, QMap metadata) override; QVector tagsForResource(int resourceId) const; Q_SIGNALS: // XXX: emit these signals void beforeResourcesLayoutReset(QModelIndex activateAfterReformat); void afterResourcesLayoutReset(); private: bool resetQuery(); struct Private; Private *const d; }; #endif // KISRESOURCEMODEL_H diff --git a/libs/resources/KisResourcesActiveFilterModel.cpp b/libs/resources/KisResourcesActiveFilterModel.cpp new file mode 100644 index 0000000000..014b5f6fca --- /dev/null +++ b/libs/resources/KisResourcesActiveFilterModel.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2020 Boudewijn Rempt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include "KisResourcesActiveFilterModel.h" + +struct KisResourcesActiveFilterModel::Private +{ + int column {-1}; + ResourceFilter resourceFilter {ShowActiveResources}; + StorageFilter storageFilter {ShowActiveStorages}; +}; + +KisResourcesActiveFilterModel::KisResourcesActiveFilterModel(int column, QObject *parent) + : QSortFilterProxyModel(parent) + , d(new Private) +{ + d->column = column; +} + +KisResourcesActiveFilterModel::~KisResourcesActiveFilterModel() +{ + delete d; +} + +void KisResourcesActiveFilterModel::setResourceFilter(ResourceFilter filter) +{ + d->resourceFilter = filter; +} + +void KisResourcesActiveFilterModel::setStorageFilter(StorageFilter filter) +{ + d->storageFilter = filter; +} + +KoResourceSP KisResourcesActiveFilterModel::resourceForIndex(QModelIndex index) const +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return source->resourceForIndex(mapToSource(index)); + } + return 0; +} + +QModelIndex KisResourcesActiveFilterModel::indexFromResource(KoResourceSP resource) const +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return mapFromSource(source->indexFromResource(resource)); + } + return QModelIndex(); +} + +bool KisResourcesActiveFilterModel::removeResource(const QModelIndex &index) +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return source->removeResource(mapToSource(index)); + } + return false; +} + +bool KisResourcesActiveFilterModel::importResourceFile(const QString &filename) +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return source->importResourceFile(filename); + } + return false; +} + +bool KisResourcesActiveFilterModel::addResource(KoResourceSP resource, const QString &storageId) +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return source->addResource(resource, storageId); + } + return false; +} + +bool KisResourcesActiveFilterModel::updateResource(KoResourceSP resource) +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return source->updateResource(resource); + } + return false; +} + +bool KisResourcesActiveFilterModel::renameResource(KoResourceSP resource, const QString &name) +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return source->renameResource(resource, name); + } + return false; +} + +bool KisResourcesActiveFilterModel::removeResource(KoResourceSP resource) +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return source->removeResource(resource); + } + return false; +} + +bool KisResourcesActiveFilterModel::setResourceMetaData(KoResourceSP resource, QMap metadata) +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return source->setResourceMetaData(resource, metadata); + } + return false; +} + + +bool KisResourcesActiveFilterModel::filterAcceptsColumn(int /*source_column*/, const QModelIndex &/*source_parent*/) const +{ + return true; +} + +bool KisResourcesActiveFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const +{ + if (d->resourceFilter == ShowAllResources && d->storageFilter == ShowAllStorages) { + return true; + } + + QModelIndex idx = sourceModel()->index(source_row, 0, source_parent); + ResourceFilter resourceActive = (ResourceFilter)sourceModel()->data(idx, Qt::UserRole + KisResourceModel::ResourceActive).toInt(); + StorageFilter storageActive = (StorageFilter)sourceModel()->data(idx, Qt::UserRole + KisResourceModel::StorageActive).toInt(); + + if (d->resourceFilter == ShowAllResources) { + return (storageActive == d->storageFilter); + } + + if (d->storageFilter == ShowAllStorages) { + return (resourceActive == d->resourceFilter); + } + + return ((storageActive == d->storageFilter) && (resourceActive == d->resourceFilter)); +} + +bool KisResourcesActiveFilterModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const +{ + QString nameLeft = sourceModel()->data(source_left, Qt::UserRole + KisResourceModel::Name).toString(); + QString nameRight = sourceModel()->data(source_right, Qt::UserRole + KisResourceModel::Name).toString(); + return nameLeft < nameRight; +} + + diff --git a/libs/resources/KisResourcesActiveFilterModel.h b/libs/resources/KisResourcesActiveFilterModel.h new file mode 100644 index 0000000000..10293ac8b6 --- /dev/null +++ b/libs/resources/KisResourcesActiveFilterModel.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 Boudewijn Rempt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef KISACTIVEFILTERMODEL_H +#define KISACTIVEFILTERMODEL_H + +#include +#include +#include + +#include "kritaresources_export.h" + +/** + * @brief The KisActiveResourcesModel class + */ +class KRITARESOURCES_EXPORT KisResourcesActiveFilterModel : public QSortFilterProxyModel, public KisAbstractResourceModel +{ + Q_OBJECT +public: + KisResourcesActiveFilterModel(int column, QObject *parent); + ~KisResourcesActiveFilterModel() override; + + enum ResourceFilter { + ShowInactiveResources = 0, + ShowActiveResources, + ShowAllResources + }; + + void setResourceFilter(ResourceFilter filter); + + enum StorageFilter { + ShowInactiveStorages = 0, + ShowActiveStorages, + ShowAllStorages + }; + + void setStorageFilter(StorageFilter filter); + +public: + + KoResourceSP resourceForIndex(QModelIndex index = QModelIndex()) const override; + QModelIndex indexFromResource(KoResourceSP resource) const override; + bool removeResource(const QModelIndex &index) override; + bool importResourceFile(const QString &filename) override; + bool addResource(KoResourceSP resource, const QString &storageId = QString()) override; + bool updateResource(KoResourceSP resource) override; + bool renameResource(KoResourceSP resource, const QString &name) override; + bool removeResource(KoResourceSP resource) override; + bool setResourceMetaData(KoResourceSP resource, QMap metadata) override; + +protected: + + bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const override; + bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; + bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override; + +private: + + struct Private; + Private *const d; + + Q_DISABLE_COPY(KisResourcesActiveFilterModel) + +}; + +#endif // KISACTIVEFILTERMODEL_H