diff --git a/libs/resources/CMakeLists.txt b/libs/resources/CMakeLists.txt index 6a21b73714..68fc51c820 100644 --- a/libs/resources/CMakeLists.txt +++ b/libs/resources/CMakeLists.txt @@ -1,75 +1,74 @@ 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/KisResourceIterator.cpp b/libs/resources/KisResourceIterator.cpp index e8aa99734f..15bb032fee 100644 --- a/libs/resources/KisResourceIterator.cpp +++ b/libs/resources/KisResourceIterator.cpp @@ -1,164 +1,164 @@ /* * 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 "KisResourceIterator.h" #include #include KisResourceItem::KisResourceItem(KisResourceModel *resourceModel, const QModelIndex &index) : m_resourceModel(resourceModel) , m_index(index) { } int KisResourceItem::id() { if (m_index.isValid()) { - return m_index.data(Qt::UserRole + KisResourceModel::Id).toInt(); + return m_index.data(Qt::UserRole + KisAbstractResourceModel::Id).toInt(); } return -1; } QString KisResourceItem::resourceType() { if (m_index.isValid()) { - return m_index.data(Qt::UserRole + KisResourceModel::ResourceType).toString(); + return m_index.data(Qt::UserRole + KisAbstractResourceModel::ResourceType).toString(); } return QString(); } QString KisResourceItem::name() { if (m_index.isValid()) { - return m_index.data(Qt::UserRole + KisResourceModel::Name).toString(); + return m_index.data(Qt::UserRole + KisAbstractResourceModel::Name).toString(); } return QString(); } QString KisResourceItem::filename() { if (m_index.isValid()) { - return m_index.data(Qt::UserRole + KisResourceModel::Filename).toString(); + return m_index.data(Qt::UserRole + KisAbstractResourceModel::Filename).toString(); } return QString(); } QString KisResourceItem::tooltip() { if (m_index.isValid()) { - return m_index.data(Qt::UserRole + KisResourceModel::Tooltip).toString(); + return m_index.data(Qt::UserRole + KisAbstractResourceModel::Tooltip).toString(); } return QString(); } QImage KisResourceItem::thumbnail() { if (m_index.isValid()) { - return m_index.data(Qt::UserRole + KisResourceModel::Thumbnail).value(); + return m_index.data(Qt::UserRole + KisAbstractResourceModel::Thumbnail).value(); } return QImage(); } KoResourceSP KisResourceItem::resource() { if (m_index.isValid() && m_resourceModel) { return m_resourceModel->resourceForIndex(m_index); } return 0; } struct KisResourceIterator::Private { Private(KisResourceModel *_resourceModel) : resourceModel(_resourceModel) {} KisResourceModel *resourceModel {0}; int currentRow {0}; }; KisResourceIterator::KisResourceIterator(KisResourceModel *resourceModel) : d(new Private(resourceModel)) { } KisResourceIterator::~KisResourceIterator() { } bool KisResourceIterator::hasNext() const { return d->currentRow < d->resourceModel->rowCount() - 1; } bool KisResourceIterator::hasPrevious() const { return d->currentRow > 0 && d->resourceModel->rowCount() > 1 && d->currentRow < d->resourceModel->rowCount(); } const KisResourceItemSP KisResourceIterator::next() { if (d->currentRow < d->resourceModel->rowCount() - 1) { d->currentRow++; QModelIndex idx = d->resourceModel->index(d->currentRow, 0); return KisResourceItemSP(new KisResourceItem(d->resourceModel, idx)); } return KisResourceItemSP(new KisResourceItem(0, QModelIndex())); } const KisResourceItemSP KisResourceIterator::peekNext() const { if (d->currentRow < d->resourceModel->rowCount() - 2) { QModelIndex idx = d->resourceModel->index(d->currentRow + 1, 0); return KisResourceItemSP(new KisResourceItem(d->resourceModel, idx)); } return KisResourceItemSP(new KisResourceItem(0, QModelIndex())); } const KisResourceItemSP KisResourceIterator::peekPrevious() const { if (d->currentRow > 1 && d->resourceModel->rowCount() > 2) { QModelIndex idx = d->resourceModel->index(d->currentRow -1, 0); return KisResourceItemSP(new KisResourceItem(d->resourceModel, idx)); } return KisResourceItemSP(new KisResourceItem(0, QModelIndex())); } const KisResourceItemSP KisResourceIterator::previous() { if (d->currentRow > 1 && d->resourceModel->rowCount() > 2) { d->currentRow--; QModelIndex idx = d->resourceModel->index(d->currentRow, 0); return KisResourceItemSP(new KisResourceItem(d->resourceModel, idx)); } return KisResourceItemSP(new KisResourceItem(0, QModelIndex())); } void KisResourceIterator::toBack() { d->currentRow = 0; } void KisResourceIterator::toEnd() { d->currentRow = d->resourceModel->rowCount() -1; } diff --git a/libs/resources/KisResourceLocator.h b/libs/resources/KisResourceLocator.h index b3ec0f0162..546b762250 100644 --- a/libs/resources/KisResourceLocator.h +++ b/libs/resources/KisResourceLocator.h @@ -1,276 +1,276 @@ /* * 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 KISRESOURCELOCATOR_H #define KISRESOURCELOCATOR_H #include #include #include #include #include "kritaresources_export.h" #include /** * The KisResourceLocator class locates all resource storages (folders, * bundles, various adobe resource libraries) in the resource location. * * The resource location is always a writable folder. * * There is one resource locator which is owned by the QApplication * object. * * The resource location is configurable, but there is only one location * where Krita will look for resources. */ class KRITARESOURCES_EXPORT KisResourceLocator : public QObject { Q_OBJECT public: // The configuration key that holds the resource location // for this installation of Krita. The location is // QStandardPaths::AppDataLocation by default, but that // can be changed. static const QString resourceLocationKey; static KisResourceLocator *instance(); ~KisResourceLocator(); enum class LocatorError { Ok, LocationReadOnly, CannotCreateLocation, CannotInitializeDb, CannotSynchronizeDb }; /** * @brief initialize Setup the resource locator for use. * * @param installationResourcesLocation the place where the resources * that come packaged with Krita reside. */ LocatorError initialize(const QString &installationResourcesLocation); /** * @brief errorMessages * @return */ QStringList errorMessages() const; /** * @brief resourceLocationBase is the place where all resource storages (folder, * bundles etc. are located. This is a writable place. * @return the base location for all storages. */ QString resourceLocationBase() const; /** * @brief purge purges the local resource cache */ void purge(); /** * @brief addStorage Adds a new resource storage to the database. The storage is * will be marked as not pre-installed. * @param storageLocation a unique name for the given storage * @param storage a storage object * @return true if the storage has been added successfully */ bool addStorage(const QString &storageLocation, KisResourceStorageSP storage); /** * @brief removeStorage removes the temporary storage from the database * @param document the unique name of the document * @return true is successful. */ bool removeStorage(const QString &storageLocation); /** * @brief hasStorage can be used to check whether the given storage already exists * @param storageLocation the name of the storage * @return true if the storage is known */ bool hasStorage(const QString &storageLocation); Q_SIGNALS: void progressMessage(const QString&); /// Emitted whenever a storage is added void storageAdded(const QString &location); /// Emitted whenever a storage is removed void storageRemoved(const QString &location); private: - friend class KisResourceModel; + friend class KisAllResourcesModel; friend class KisTagModel; friend class KisStorageModel; friend class TestResourceLocator; friend class TestResourceModel; friend class Resource; friend class KisResourceCacheDb; friend class KisStorageFilterProxyModel; /// @return true if the resource is present in the cache, false if it hasn't been loaded bool resourceCached(QString storageLocation, const QString &resourceType, const QString &filename) const; /** * @brief resource finds a physical resource in one of the storages * @param storageLocation the storage containing the resource. If empty, * this is the folder storage. * * Note that the resource does not have the version or id field set, so this cannot be used directly, * but only through KisResourceModel. * * @param resourceType the type of the resource * @param filename the filename of the resource including extension, but withou * any paths * @return A resource if found, or 0 */ KoResourceSP resource(QString storageLocation, const QString &resourceType, const QString &filename); /** * @brief resourceForId returns the resource with the given id, or 0 if no such resource exists. * The resource object will have its id set but not its version. * @param resourceId the id */ KoResourceSP resourceForId(int resourceId); /** * @brief removeResource * @param resourceId * @param optional: the storage that contains the given resource * @return */ bool removeResource(int resourceId, const QString &storageLocation = QString()); /** * @brief importResourceFromFile * @param resourceType * @param fileName * @param storageLocation: optional, the storage where the resource will be stored. Empty means in the default Folder storage. * @return */ bool importResourceFromFile(const QString &resourceType, const QString &fileName, const QString &storageLocation = QString()); /** * @brief addResource adds the given resource to the database and potentially a storage * @param resourceType the type of the resource * @param resource the actual resource object * @param storageLocation the storage where the resource will be saved. By default this is the the default folder storage. * @return true if successful */ bool addResource(const QString &resourceType, const KoResourceSP resource, const QString &storageLocation = QString()); /** * @brief updateResource * @param resourceType * @param resource * @return */ bool updateResource(const QString &resourceType, const KoResourceSP resource); /** * @brief metaDataForResource * @param id * @return */ QMap metaDataForResource(int id) const; /** * @brief setMetaDataForResource * @param id * @param map * @return */ bool setMetaDataForResource(int id, QMap map) const; /** * @brief metaDataForStorage * @param storage * @return */ QMap metaDataForStorage(const QString &storageLocation) const; /** * @brief setMetaDataForStorage * @param storage * @param map */ void setMetaDataForStorage(const QString &storageLocation, QMap map) const; /** * Loads all the resources required by \p resource into the cache * * loadRequiredResources() also loads embedded resources and adds them * into the database. */ void loadRequiredResources(KoResourceSP resource); KisResourceLocator(QObject *parent); KisResourceLocator(const KisResourceLocator&); KisResourceLocator operator=(const KisResourceLocator&); enum class InitializationStatus { Unknown, // We don't know whether Krita has run on this system for this resource location yet Initialized, // Everything is ready to start synchronizing the database FirstRun, // Krita hasn't run for this resource location yet FirstUpdate, // Krita was installed, but it's a version from before the resource locator existed, only user-defined resources are present Updating // Krita is updating from an older version with resource locator }; LocatorError firstTimeInstallation(InitializationStatus initializationStatus, const QString &installationResourcesLocation); // First time installation bool initializeDb(); // Synchronize on restarting Krita to see whether the user has added any storages or resources to the resources location bool synchronizeDb(); void findStorages(); QList storages() const; KisResourceStorageSP storageByLocation(const QString &location) const; KisResourceStorageSP folderStorage() const; KisResourceStorageSP memoryStorage() const; struct ResourceStorage { QString storageLocation; QString resourceType; QString resourceFileName; }; ResourceStorage getResourceStorage(int resourceId) const; QString makeStorageLocationAbsolute(QString storageLocation) const; QString makeStorageLocationRelative(QString location) const; class Private; QScopedPointer d; }; #endif // KISRESOURCELOCATOR_H diff --git a/libs/resources/KisResourceModel.cpp b/libs/resources/KisResourceModel.cpp index 75f829859e..9d5ec676e6 100644 --- a/libs/resources/KisResourceModel.cpp +++ b/libs/resources/KisResourceModel.cpp @@ -1,601 +1,780 @@ /* * 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 { +struct KisAllResourcesModel::Private { QSqlQuery resourcesQuery; QSqlQuery tagQuery; QString resourceType; int columnCount {10}; int cachedRowCount {-1}; }; //static int s_i = 0; -KisResourceModel::KisResourceModel(const QString &resourceType, QObject *parent) +KisAllResourcesModel::KisAllResourcesModel(const QString &resourceType, QObject *parent) : QAbstractTableModel(parent) , d(new Private) { //qDebug() << "ResourceModel" << s_i << resourceType; s_i++; connect(KisResourceLocator::instance(), SIGNAL(storageAdded(const QString&)), this, SLOT(addStorage(const QString&))); connect(KisResourceLocator::instance(), SIGNAL(storageRemoved(const QString&)), this, SLOT(removeStorage(const QString&))); 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" "ORDER BY resources.id"); if (!r) { - qWarning() << "Could not prepare KisResourceModel query" << d->resourcesQuery.lastError(); + qWarning() << "Could not prepare KisAllResourcesModel 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" "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() +KisAllResourcesModel::~KisAllResourcesModel() { delete d; } -int KisResourceModel::columnCount(const QModelIndex &/*parent*/) const +int KisAllResourcesModel::columnCount(const QModelIndex &/*parent*/) const { return d->columnCount; } -QVariant KisResourceModel::data(const QModelIndex &index, int role) const +QVariant KisAllResourcesModel::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()); + 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 KisAllResourcesModel::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 KisAllResourcesModel::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++; + //qDebug() << "KisAllResourcesModel::resourceForIndex" << s_i2 << d->resourceType; s_i2++; - bool pos = const_cast(this)->d->resourcesQuery.seek(index.row()); + 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 +KoResourceSP KisAllResourcesModel::resourceForId(int id) const { return KisResourceLocator::instance()->resourceForId(id); } -KoResourceSP KisResourceModel::resourceForFilename(QString filename) const +KoResourceSP KisAllResourcesModel::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(); + qWarning() << "Could not prepare KisAllResourcesModel 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 KisAllResourcesModel::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(); + qWarning() << "Could not prepare KisAllResourcesModel 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 KisAllResourcesModel::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(); + qWarning() << "Could not prepare KisAllResourcesModel 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 +QModelIndex KisAllResourcesModel::indexFromResource(KoResourceSP resource) const { if (!resource || !resource->valid()) return QModelIndex(); - //qDebug() << "KisResourceModel::indexFromResource" << s_i3 << d->resourceType; s_i3++; + //qDebug() << "KisAllResourcesModel::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) +bool KisAllResourcesModel::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++; + //qDebug() << "KisAllResourcesModel::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) +bool KisAllResourcesModel::removeResource(KoResourceSP resource) { if (!resource || !resource->valid()) return false; - //qDebug() << "KisResourceModel::remvoeResource 2" << s_i5 << d->resourceType; s_i5++; + //qDebug() << "KisAllResourcesModel::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) +bool KisAllResourcesModel::importResourceFile(const QString &filename) { - //qDebug() << "KisResourceModel::importResource" << s_i6 << d->resourceType; s_i6++; + //qDebug() << "KisAllResourcesModel::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) +bool KisAllResourcesModel::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++; + //qDebug() << "KisAllResourcesModel::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) +bool KisAllResourcesModel::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++; + //qDebug() << "KisAllResourcesModel::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) +bool KisAllResourcesModel::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) +bool KisAllResourcesModel::setResourceMetaData(KoResourceSP resource, QMap metadata) { - //qDebug() << "KisResourceModel::setResourceMetaData" << s_i9 << d->resourceType; s_i9++; + //qDebug() << "KisAllResourcesModel::setResourceMetaData" << s_i9 << d->resourceType; s_i9++; Q_ASSERT(resource->resourceId() > -1); return KisResourceLocator::instance()->setMetaDataForResource(resource->resourceId(), metadata); } -bool KisResourceModel::resetQuery() +bool KisAllResourcesModel::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"; + qDebug() << "KisAllResourcesModel::resetQuery for" << d->resourceType << "took" << t.elapsed() << "ms"; return r; } -QVector KisResourceModel::tagsForResource(int resourceId) const +QVector KisAllResourcesModel::tagsForResource(int resourceId) const { return KisTagModelProvider::tagModel(d->resourceType)->tagsForResource(resourceId); } -int KisResourceModel::rowCount(const QModelIndex &) const +int KisAllResourcesModel::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"); q.bindValue(":resource_type", d->resourceType); q.exec(); q.first(); - const_cast(this)->d->cachedRowCount = q.value(0).toInt(); + const_cast(this)->d->cachedRowCount = q.value(0).toInt(); } return d->cachedRowCount; } -void KisResourceModel::addStorage(const QString &location) +void KisAllResourcesModel::addStorage(const QString &location) +{ + +} + + +void KisAllResourcesModel::removeStorage(const QString &location) { } +struct KisResourceModel::Private +{ + ResourceFilter resourceFilter {ShowActiveResources}; + StorageFilter storageFilter {ShowActiveStorages}; +}; + +KisResourceModel::KisResourceModel(const QString &type, QObject *parent) + : QSortFilterProxyModel(parent) + , d(new Private) +{ + setSourceModel(new KisAllResourcesModel(type)); +} -void KisResourceModel::removeStorage(const QString &location) +KisResourceModel::~KisResourceModel() { + delete d; +} +void KisResourceModel::setResourceFilter(ResourceFilter filter) +{ + d->resourceFilter = filter; } + +void KisResourceModel::setStorageFilter(StorageFilter filter) +{ + d->storageFilter = filter; +} + +KoResourceSP KisResourceModel::resourceForIndex(QModelIndex index) const +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return source->resourceForIndex(mapToSource(index)); + } + return 0; +} + +QModelIndex KisResourceModel::indexFromResource(KoResourceSP resource) const +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return mapFromSource(source->indexFromResource(resource)); + } + return QModelIndex(); +} + +bool KisResourceModel::removeResource(const QModelIndex &index) +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return source->removeResource(mapToSource(index)); + } + return false; +} + +bool KisResourceModel::importResourceFile(const QString &filename) +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return source->importResourceFile(filename); + } + return false; +} + +bool KisResourceModel::addResource(KoResourceSP resource, const QString &storageId) +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return source->addResource(resource, storageId); + } + return false; +} + +bool KisResourceModel::updateResource(KoResourceSP resource) +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return source->updateResource(resource); + } + return false; +} + +bool KisResourceModel::renameResource(KoResourceSP resource, const QString &name) +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return source->renameResource(resource, name); + } + return false; +} + +bool KisResourceModel::removeResource(KoResourceSP resource) +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return source->removeResource(resource); + } + return false; +} + +bool KisResourceModel::setResourceMetaData(KoResourceSP resource, QMap metadata) +{ + KisAbstractResourceModel *source = dynamic_cast(sourceModel()); + if (source) { + return source->setResourceMetaData(resource, metadata); + } + return false; +} + + + + +bool KisResourceModel::filterAcceptsColumn(int /*source_column*/, const QModelIndex &/*source_parent*/) const +{ + return true; +} + +bool KisResourceModel::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 + KisAbstractResourceModel::ResourceActive).toInt(); + StorageFilter storageActive = (StorageFilter)sourceModel()->data(idx, Qt::UserRole + KisAbstractResourceModel::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 KisResourceModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const +{ + QString nameLeft = sourceModel()->data(source_left, Qt::UserRole + KisAbstractResourceModel::Name).toString(); + QString nameRight = sourceModel()->data(source_right, Qt::UserRole + KisAbstractResourceModel::Name).toString(); + return nameLeft < nameRight; +} + + +KoResourceSP KisResourceModel::resourceForId(int id) const +{ + return static_cast(sourceModel())->resourceForId(id); +} + +KoResourceSP KisResourceModel::resourceForFilename(QString fileName) const +{ + return static_cast(sourceModel())->resourceForFilename(fileName); +} + +KoResourceSP KisResourceModel::resourceForName(QString name) const +{ + return static_cast(sourceModel())->resourceForName(name); +} + +KoResourceSP KisResourceModel::resourceForMD5(const QByteArray md5sum) const +{ + return static_cast(sourceModel())->resourceForMD5(md5sum); +} + +QVector KisResourceModel::tagsForResource(int resourceId) const +{ + return static_cast(sourceModel())->tagsForResource(resourceId); +} + + + +bool KisResourceModel::resetQuery() +{ + return static_cast(sourceModel())->resetQuery(); +} + diff --git a/libs/resources/KisResourceModel.h b/libs/resources/KisResourceModel.h index 370562d674..91ffae0573 100644 --- a/libs/resources/KisResourceModel.h +++ b/libs/resources/KisResourceModel.h @@ -1,227 +1,318 @@ /* * 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 #include /** * KisAbstractResourceModel defines the interface for accessing resources * that is used in KisResourceModel and the various filter/proxy models */ class KRITARESOURCES_EXPORT KisAbstractResourceModel { 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, + /// XXX: what is this used for, again? + KoResourceRole, + /// Whether the current resource is active + ResourceActive, + /// Whether the current resource's storage isa ctive + StorageActive + }; + 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 + * @brief The KisAllresourcesModel 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, from all storages, active and inactive. */ -class KRITARESOURCES_EXPORT KisResourceModel : public QAbstractTableModel, public KisAbstractResourceModel +class KRITARESOURCES_EXPORT KisAllResourcesModel : 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, - /// 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); + friend class KisResourceModel; + KisAllResourcesModel(const QString &resourceType, QObject *parent = 0); public: - ~KisResourceModel() override; + ~KisAllResourcesModel() 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; + 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; + +Q_SIGNALS: + + // XXX: emit these signals + void beforeResourcesLayoutReset(QModelIndex activateAfterReformat); + void afterResourcesLayoutReset(); + +private Q_SLOTS: + + void addStorage(const QString &location); + void removeStorage(const QString &location); + +private: + 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; + QVector tagsForResource(int resourceId) const; + + bool resetQuery(); + + struct Private; + Private *const d; + +}; +/** + * @brief The KisResourceModel class provides the main access to resources. It is possible + * to filter the resources returned by the active status flag of the resources and the + * storages + */ +class KRITARESOURCES_EXPORT KisResourceModel : public QSortFilterProxyModel, public KisAbstractResourceModel +{ + Q_OBJECT +private: + friend class TestResourceModel; + friend class KisResourceModelProvider; + KisResourceModel(const QString &type, QObject *parent = 0); +public: + ~KisResourceModel() 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 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 removeResource(KoResourceSP resource) override; bool setResourceMetaData(KoResourceSP resource, QMap metadata) override; + + +public: + + 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; QVector tagsForResource(int resourceId) const; -Q_SIGNALS: - // XXX: emit these signals - void beforeResourcesLayoutReset(QModelIndex activateAfterReformat); - void afterResourcesLayoutReset(); -private Q_SLOTS: +protected: - void addStorage(const QString &location); - void removeStorage(const QString &location); + 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: bool resetQuery(); struct Private; Private *const d; + Q_DISABLE_COPY(KisResourceModel) + }; + + #endif // KISRESOURCEMODEL_H diff --git a/libs/resources/KisResourcesActiveFilterModel.cpp b/libs/resources/KisResourcesActiveFilterModel.cpp index 014b5f6fca..bf7d489632 100644 --- a/libs/resources/KisResourcesActiveFilterModel.cpp +++ b/libs/resources/KisResourcesActiveFilterModel.cpp @@ -1,165 +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 +struct KisResourceModel::Private { int column {-1}; ResourceFilter resourceFilter {ShowActiveResources}; StorageFilter storageFilter {ShowActiveStorages}; }; -KisResourcesActiveFilterModel::KisResourcesActiveFilterModel(int column, QObject *parent) +KisResourceModel::KisResourceModel(int column, QObject *parent) : QSortFilterProxyModel(parent) , d(new Private) { d->column = column; } -KisResourcesActiveFilterModel::~KisResourcesActiveFilterModel() +KisResourceModel::~KisResourceModel() { delete d; } -void KisResourcesActiveFilterModel::setResourceFilter(ResourceFilter filter) +void KisResourceModel::setResourceFilter(ResourceFilter filter) { d->resourceFilter = filter; } -void KisResourcesActiveFilterModel::setStorageFilter(StorageFilter filter) +void KisResourceModel::setStorageFilter(StorageFilter filter) { d->storageFilter = filter; } -KoResourceSP KisResourcesActiveFilterModel::resourceForIndex(QModelIndex index) const +KoResourceSP KisResourceModel::resourceForIndex(QModelIndex index) const { KisAbstractResourceModel *source = dynamic_cast(sourceModel()); if (source) { return source->resourceForIndex(mapToSource(index)); } return 0; } -QModelIndex KisResourcesActiveFilterModel::indexFromResource(KoResourceSP resource) const +QModelIndex KisResourceModel::indexFromResource(KoResourceSP resource) const { KisAbstractResourceModel *source = dynamic_cast(sourceModel()); if (source) { return mapFromSource(source->indexFromResource(resource)); } return QModelIndex(); } -bool KisResourcesActiveFilterModel::removeResource(const QModelIndex &index) +bool KisResourceModel::removeResource(const QModelIndex &index) { KisAbstractResourceModel *source = dynamic_cast(sourceModel()); if (source) { return source->removeResource(mapToSource(index)); } return false; } -bool KisResourcesActiveFilterModel::importResourceFile(const QString &filename) +bool KisResourceModel::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) +bool KisResourceModel::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) +bool KisResourceModel::updateResource(KoResourceSP resource) { KisAbstractResourceModel *source = dynamic_cast(sourceModel()); if (source) { return source->updateResource(resource); } return false; } -bool KisResourcesActiveFilterModel::renameResource(KoResourceSP resource, const QString &name) +bool KisResourceModel::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) +bool KisResourceModel::removeResource(KoResourceSP resource) { KisAbstractResourceModel *source = dynamic_cast(sourceModel()); if (source) { return source->removeResource(resource); } return false; } -bool KisResourcesActiveFilterModel::setResourceMetaData(KoResourceSP resource, QMap metadata) +bool KisResourceModel::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 +bool KisResourceModel::filterAcceptsColumn(int /*source_column*/, const QModelIndex &/*source_parent*/) const { return true; } -bool KisResourcesActiveFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const +bool KisResourceModel::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 +bool KisResourceModel::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 index 10293ac8b6..4e205debfc 100644 --- a/libs/resources/KisResourcesActiveFilterModel.h +++ b/libs/resources/KisResourcesActiveFilterModel.h @@ -1,81 +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 +class KRITARESOURCES_EXPORT KisResourceModel : public QSortFilterProxyModel, public KisAbstractResourceModel { Q_OBJECT public: - KisResourcesActiveFilterModel(int column, QObject *parent); - ~KisResourcesActiveFilterModel() override; + KisResourceModel(int column, QObject *parent); + ~KisResourceModel() 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 diff --git a/libs/resources/KisStorageFilterProxyModel.cpp b/libs/resources/KisStorageFilterProxyModel.cpp index 10c3d86307..f4ccba4037 100644 --- a/libs/resources/KisStorageFilterProxyModel.cpp +++ b/libs/resources/KisStorageFilterProxyModel.cpp @@ -1,106 +1,106 @@ /* * 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 "KisStorageFilterProxyModel.h" #include #include #include #include #include struct KisStorageFilterProxyModel::Private { FilterType filterType {KisStorageFilterProxyModel::ByStorageType}; QVariant filter; }; KisStorageFilterProxyModel::KisStorageFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent) , d(new Private) { } KisStorageFilterProxyModel::~KisStorageFilterProxyModel() { delete d; } KisResourceStorageSP KisStorageFilterProxyModel::storageForIndex(QModelIndex index) const { KisStorageModel *source = dynamic_cast(sourceModel()); if (source) { return source->storageForIndex(mapToSource(index)); } return 0; } void KisStorageFilterProxyModel::setFilter(KisStorageFilterProxyModel::FilterType filterType, QVariant filter) { d->filter = filter; d->filterType = filterType; } bool KisStorageFilterProxyModel::filterAcceptsColumn(int /*source_column*/, const QModelIndex &/*source_parent*/) const { return true; } bool KisStorageFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { if (d->filter.isNull()) return true; - QModelIndex idx = sourceModel()->index(source_row, KisResourceModel::Name, source_parent); + QModelIndex idx = sourceModel()->index(source_row, KisAbstractResourceModel::Name, source_parent); switch (d->filterType) { case ByFileName: { QString filename = d->filter.toString(); return (sourceModel()->data(idx, Qt::UserRole + KisStorageModel::Location).toString().contains(filename)); } case ByStorageType: { QString storageType = sourceModel()->data(idx, Qt::UserRole + KisStorageModel::StorageType).toString(); return (d->filter.toStringList().contains(storageType)); } case ByActive: { bool active = d->filter.toBool(); bool isActive = sourceModel()->data(idx, Qt::UserRole + KisStorageModel::Active).toBool(); return (active == isActive); } default: ; } return false; } bool KisStorageFilterProxyModel::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(); + QString nameLeft = sourceModel()->data(source_left, Qt::UserRole + KisAbstractResourceModel::Name).toString(); + QString nameRight = sourceModel()->data(source_right, Qt::UserRole + KisAbstractResourceModel::Name).toString(); return nameLeft < nameRight; } void KisStorageFilterProxyModel::slotModelReset() { invalidateFilter(); } diff --git a/libs/resources/KisTagFilterResourceProxyModel.cpp b/libs/resources/KisTagFilterResourceProxyModel.cpp index e97e2a9d64..ec6746e0d9 100644 --- a/libs/resources/KisTagFilterResourceProxyModel.cpp +++ b/libs/resources/KisTagFilterResourceProxyModel.cpp @@ -1,224 +1,224 @@ /* * 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 "KisTagFilterResourceProxyModel.h" #include #include #include #include struct KisTagFilterResourceProxyModel::Private { Private() : filter(new KisResourceSearchBoxFilter()) { } QList tags; KisTagModel* tagModel; QScopedPointer filter; bool filterInCurrentTag {false}; }; KisTagFilterResourceProxyModel::KisTagFilterResourceProxyModel(KisTagModel* model, QObject *parent) : QSortFilterProxyModel(parent) , d(new Private) { d->tagModel = model; //connect(model, SIGNAL(modelReset()), this, SLOT(slotModelReset())); } KisTagFilterResourceProxyModel::~KisTagFilterResourceProxyModel() { delete d; } KoResourceSP KisTagFilterResourceProxyModel::resourceForIndex(QModelIndex index) const { KisAbstractResourceModel *source = dynamic_cast(sourceModel()); if (source) { return source->resourceForIndex(mapToSource(index)); } return 0; } QModelIndex KisTagFilterResourceProxyModel::indexFromResource(KoResourceSP resource) const { KisAbstractResourceModel *source = dynamic_cast(sourceModel()); if (source) { return mapFromSource(source->indexFromResource(resource)); } return QModelIndex(); } bool KisTagFilterResourceProxyModel::removeResource(const QModelIndex &index) { KisAbstractResourceModel *source = dynamic_cast(sourceModel()); if (source) { return source->removeResource(mapToSource(index)); } return false; } bool KisTagFilterResourceProxyModel::importResourceFile(const QString &filename) { KisAbstractResourceModel *source = dynamic_cast(sourceModel()); if (source) { return source->importResourceFile(filename); } return false; } bool KisTagFilterResourceProxyModel::addResource(KoResourceSP resource, const QString &storageId) { KisAbstractResourceModel *source = dynamic_cast(sourceModel()); if (source) { return source->addResource(resource, storageId); } return false; } bool KisTagFilterResourceProxyModel::updateResource(KoResourceSP resource) { KisAbstractResourceModel *source = dynamic_cast(sourceModel()); if (source) { return source->updateResource(resource); } return false; } bool KisTagFilterResourceProxyModel::renameResource(KoResourceSP resource, const QString &name) { KisAbstractResourceModel *source = dynamic_cast(sourceModel()); if (source) { return source->renameResource(resource, name); } return false; } bool KisTagFilterResourceProxyModel::removeResource(KoResourceSP resource) { KisAbstractResourceModel *source = dynamic_cast(sourceModel()); if (source) { return source->removeResource(resource); } return false; } bool KisTagFilterResourceProxyModel::setResourceMetaData(KoResourceSP resource, QMap metadata) { KisAbstractResourceModel *source = dynamic_cast(sourceModel()); if (source) { return source->setResourceMetaData(resource, metadata); } return false; } void KisTagFilterResourceProxyModel::setTag(const KisTagSP tag) { d->tags.clear(); if (!tag.isNull()) { d->tags << tag; } invalidateFilter(); } void KisTagFilterResourceProxyModel::setSearchBoxText(const QString& seatchBoxText) { d->filter->setFilter(seatchBoxText); invalidateFilter(); } void KisTagFilterResourceProxyModel::setFilterByCurrentTag(const bool filterInCurrentTag) { d->filterInCurrentTag = filterInCurrentTag; invalidateFilter(); } bool KisTagFilterResourceProxyModel::filterAcceptsColumn(int /*source_column*/, const QModelIndex &/*source_parent*/) const { return true; } bool KisTagFilterResourceProxyModel::resourceHasCurrentTag(KisTagSP currentTag, QVector tagsForResource) const { if (!d->filterInCurrentTag && !d->filter->isEmpty()) { // we don't need to check anything else because the user wants to search in all resources // but if the filter text is empty, we do need to filter by the current tag return true; } if (currentTag.isNull()) { // no tag set; all resources are allowed return true; } else { if (currentTag->id() == KisTagModel::All) { // current tag is "All", all resources are allowed return true; } else if (currentTag->id() == KisTagModel::AllUntagged) { // current tag is "All untagged", all resources without any tags are allowed return tagsForResource.size() == 0; } else { // checking whether the current tag is on the list of tags assigned to the resource Q_FOREACH(KisTagSP temp, tagsForResource) { if (temp->id() == currentTag->id()) { return true; } } } } return false; } bool KisTagFilterResourceProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { if (d->tagModel == 0) { return true; } - QModelIndex idx = sourceModel()->index(source_row, KisResourceModel::Name, source_parent); - int resourceId = sourceModel()->data(idx, Qt::UserRole + KisResourceModel::Id).toInt(); - QString resourceName = sourceModel()->data(idx, Qt::UserRole + KisResourceModel::Name).toString(); + QModelIndex idx = sourceModel()->index(source_row, KisAbstractResourceModel::Name, source_parent); + int resourceId = sourceModel()->data(idx, Qt::UserRole + KisAbstractResourceModel::Id).toInt(); + QString resourceName = sourceModel()->data(idx, Qt::UserRole + KisAbstractResourceModel::Name).toString(); QVector tagsForResource = d->tagModel->tagsForResource(resourceId); KisTagSP tag = d->tags.isEmpty() ? KisTagSP() : d->tags.first(); bool hasCurrentTag = resourceHasCurrentTag(tag, tagsForResource); if (!hasCurrentTag) { return false; } bool currentFilterMatches = d->filter->matchesResource(resourceName); return currentFilterMatches; } bool KisTagFilterResourceProxyModel::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(); + QString nameLeft = sourceModel()->data(source_left, Qt::UserRole + KisAbstractResourceModel::Name).toString(); + QString nameRight = sourceModel()->data(source_right, Qt::UserRole + KisAbstractResourceModel::Name).toString(); return nameLeft < nameRight; } void KisTagFilterResourceProxyModel::slotModelReset() { invalidateFilter(); } diff --git a/libs/resources/tests/TestResourceModel.cpp b/libs/resources/tests/TestResourceModel.cpp index 8bad9113cc..1805bc2611 100644 --- a/libs/resources/tests/TestResourceModel.cpp +++ b/libs/resources/tests/TestResourceModel.cpp @@ -1,307 +1,307 @@ /* * Copyright (c) 2018 boud * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "TestResourceModel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef FILES_DATA_DIR #error "FILES_DATA_DIR not set. A directory with the data used for testing installing resources" #endif #ifndef FILES_DEST_DIR #error "FILES_DEST_DIR not set. A directory where data will be written to for testing installing resources" #endif void TestResourceModel::initTestCase() { ResourceTestHelper::initTestDb(); ResourceTestHelper::createDummyLoaderRegistry(); m_srcLocation = QString(FILES_DATA_DIR); QVERIFY2(QDir(m_srcLocation).exists(), m_srcLocation.toUtf8()); m_dstLocation = QString(FILES_DEST_DIR); ResourceTestHelper::cleanDstLocation(m_dstLocation); KConfigGroup cfg(KSharedConfig::openConfig(), ""); cfg.writeEntry(KisResourceLocator::resourceLocationKey, m_dstLocation); m_locator = KisResourceLocator::instance(); if (!KisResourceCacheDb::initialize(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))) { qWarning() << "Could not initialize KisResourceCacheDb on" << QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); } QVERIFY(KisResourceCacheDb::isValid()); KisResourceLocator::LocatorError r = m_locator->initialize(m_srcLocation); if (!m_locator->errorMessages().isEmpty()) { qDebug() << m_locator->errorMessages(); } QVERIFY(r == KisResourceLocator::LocatorError::Ok); QVERIFY(QDir(m_dstLocation).exists()); } void TestResourceModel::testRowCount() { QSqlQuery q; QVERIFY(q.prepare("SELECT count(*)\n" "FROM resources\n" ", resource_types\n" "WHERE resources.resource_type_id = resource_types.id\n" "AND resource_types.name = :resource_type")); q.bindValue(":resource_type", m_resourceType); QVERIFY(q.exec()); q.first(); int rowCount = q.value(0).toInt(); QVERIFY(rowCount == 3); KisResourceModel resourceModel(m_resourceType); QCOMPARE(resourceModel.rowCount(), rowCount); } void TestResourceModel::testData() { KisResourceModel resourceModel(m_resourceType); QStringList resourceNames; for (int i = 0; i < resourceModel.rowCount(); ++i) { - QVariant v = resourceModel.data(resourceModel.index(i, KisResourceModel::Name), Qt::DisplayRole); + QVariant v = resourceModel.data(resourceModel.index(i, KisAbstractResourceModel::Name), Qt::DisplayRole); resourceNames << v.toString(); } QVERIFY(resourceNames.contains("test0.kpp")); QVERIFY(resourceNames.contains("test1.kpp")); QVERIFY(resourceNames.contains("test2.kpp")); } void TestResourceModel::testResourceForIndex() { KisResourceModel resourceModel(m_resourceType); KoResourceSP resource = resourceModel.resourceForIndex(resourceModel.index(0, 0)); QVERIFY(resource); QVERIFY(resource->resourceId() > -1); } void TestResourceModel::testIndexFromResource() { KisResourceModel resourceModel(m_resourceType); KoResourceSP resource = resourceModel.resourceForIndex(resourceModel.index(1, 0)); QModelIndex idx = resourceModel.indexFromResource(resource); QVERIFY(idx.row() == 1); QVERIFY(idx.column() == 0); } void TestResourceModel::testRemoveResourceByIndex() { KisResourceModel resourceModel(m_resourceType); int resourceCount = resourceModel.rowCount(); KoResourceSP resource = resourceModel.resourceForIndex(resourceModel.index(1, 0)); bool r = resourceModel.removeResource(resourceModel.index(1, 0)); QVERIFY(r); QCOMPARE(resourceCount - 1, resourceModel.rowCount()); QVERIFY(!resourceModel.indexFromResource(resource).isValid()); } void TestResourceModel::testRemoveResource() { KisResourceModel resourceModel(m_resourceType); int resourceCount = resourceModel.rowCount(); KoResourceSP resource = resourceModel.resourceForIndex(resourceModel.index(1, 0)); QVERIFY(resource); bool r = resourceModel.removeResource(resource); QVERIFY(r); QCOMPARE(resourceCount - 1, resourceModel.rowCount()); QVERIFY(!resourceModel.indexFromResource(resource).isValid()); } void TestResourceModel::testImportResourceFile() { KisResourceModel resourceModel(m_resourceType); QTemporaryFile f(QDir::tempPath() + "/testresourcemodel-testimportresourcefile-XXXXXX.kpp"); f.open(); f.write("0"); f.close(); int resourceCount = resourceModel.rowCount(); bool r = resourceModel.importResourceFile(f.fileName()); QVERIFY(r); QCOMPARE(resourceCount + 1, resourceModel.rowCount()); } void TestResourceModel::testAddResource() { KisResourceModel resourceModel(m_resourceType); int resourceCount = resourceModel.rowCount(); KoResourceSP resource(new DummyResource("dummy.kpp")); resource->setValid(true); bool r = resourceModel.addResource(resource); QVERIFY(r); QCOMPARE(resourceCount + 1, resourceModel.rowCount()); } void TestResourceModel::testAddTemporaryResource() { KisResourceModel resourceModel(m_resourceType); int resourceCount = resourceModel.rowCount(); KoResourceSP resource(new DummyResource("dummy.kpp")); resource->setValid(true); bool r = resourceModel.addResource(resource, "memory"); QVERIFY(r); QCOMPARE(resourceCount + 1, resourceModel.rowCount()); } void TestResourceModel::testUpdateResource() { int resourceId; { KisResourceModel resourceModel(m_resourceType); KoResourceSP resource = resourceModel.resourceForIndex(resourceModel.index(0, 0)); QVERIFY(resource); QVERIFY(resource.dynamicCast()->something().isEmpty()); resource.dynamicCast()->setSomething("It's changed"); resourceId = resource->resourceId(); bool r = resourceModel.updateResource(resource); QVERIFY(r); } { // Check the resource itself KisResourceLocator::instance()->purge(); KoResourceSP resource = KisResourceLocator::instance()->resourceForId(resourceId); QVERIFY(resource); QVERIFY(!resource.dynamicCast()->something().isEmpty()); QVERIFY(resource->resourceId() == resourceId); // Check the versions in the database QSqlQuery q; QVERIFY(q.prepare("SELECT count(*)\n" "FROM versioned_resources\n" "WHERE resource_id = :resource_id\n")); q.bindValue(":resource_id", resourceId); QVERIFY(q.exec()); q.first(); int rowCount = q.value(0).toInt(); QCOMPARE(rowCount, 2); } } void TestResourceModel::testResourceForId() { KisResourceModel resourceModel(m_resourceType); KoResourceSP resource = resourceModel.resourceForIndex(resourceModel.index(0, 0)); QVERIFY(!resource.isNull()); KoResourceSP resource2 = resourceModel.resourceForId(resource->resourceId()); QVERIFY(!resource2.isNull()); QCOMPARE(resource, resource2); } void TestResourceModel::testResourceForName() { KisResourceModel resourceModel(m_resourceType); KoResourceSP resource = resourceModel.resourceForIndex(resourceModel.index(0, 0)); QVERIFY(!resource.isNull()); KoResourceSP resource2 = resourceModel.resourceForName(resource->name()); QVERIFY(!resource2.isNull()); QCOMPARE(resource, resource2); } void TestResourceModel::testResourceForFileName() { KisResourceModel resourceModel(m_resourceType); KoResourceSP resource = resourceModel.resourceForIndex(resourceModel.index(0, 0)); QVERIFY(!resource.isNull()); KoResourceSP resource2 = resourceModel.resourceForFilename(resource->filename()); QVERIFY(!resource2.isNull()); QCOMPARE(resource, resource2); } void TestResourceModel::testResourceForMD5() { KisResourceModel resourceModel(m_resourceType); KoResourceSP resource = resourceModel.resourceForIndex(resourceModel.index(0, 0)); QVERIFY(!resource.isNull()); KoResourceSP resource2 = resourceModel.resourceForMD5(resource->md5()); QVERIFY(!resource2.isNull()); QCOMPARE(resource->md5(), resource2->md5()); } void TestResourceModel::testRenameResource() { KisResourceModel resourceModel(m_resourceType); KoResourceSP resource = resourceModel.resourceForIndex(resourceModel.index(1, 0)); QVERIFY(!resource.isNull()); const QString name = resource->name(); bool r = resourceModel.renameResource(resource, "A New Name"); QVERIFY(r); QSqlQuery q; if (!q.prepare("SELECT name\n" "FROM resources\n" "WHERE id = :resource_id\n")) { qWarning() << "Could not prepare testRenameResource Query" << q.lastError(); } q.bindValue(":resource_id", resource->resourceId()); if (!q.exec()) { qWarning() << "Could not execute testRenameResource Query" << q.lastError(); } q.first(); QString newName = q.value(0).toString(); QVERIFY(name != newName); QCOMPARE("A New Name", newName); } void TestResourceModel::cleanupTestCase() { ResourceTestHelper::rmTestDb(); ResourceTestHelper::cleanDstLocation(m_dstLocation); } QTEST_MAIN(TestResourceModel) diff --git a/libs/resources/tests/TestTagFilterResourceProxyModel.cpp b/libs/resources/tests/TestTagFilterResourceProxyModel.cpp index 8cbb7bebcd..906a92db9f 100644 --- a/libs/resources/tests/TestTagFilterResourceProxyModel.cpp +++ b/libs/resources/tests/TestTagFilterResourceProxyModel.cpp @@ -1,136 +1,136 @@ /* * Copyright (c) 2019 boud * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "TestTagFilterResourceProxyModel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef FILES_DATA_DIR #error "FILES_DATA_DIR not set. A directory with the data used for testing installing resources" #endif #ifndef FILES_DEST_DIR #error "FILES_DEST_DIR not set. A directory where data will be written to for testing installing resources" #endif void TestTagFilterResourceProxyModel::initTestCase() { ResourceTestHelper::initTestDb(); ResourceTestHelper::createDummyLoaderRegistry(); m_srcLocation = QString(FILES_DATA_DIR); QVERIFY2(QDir(m_srcLocation).exists(), m_srcLocation.toUtf8()); m_dstLocation = QString(FILES_DEST_DIR); ResourceTestHelper::cleanDstLocation(m_dstLocation); KConfigGroup cfg(KSharedConfig::openConfig(), ""); cfg.writeEntry(KisResourceLocator::resourceLocationKey, m_dstLocation); m_locator = KisResourceLocator::instance(); if (!KisResourceCacheDb::initialize(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))) { qDebug() << "Could not initialize KisResourceCacheDb on" << QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); } QVERIFY(KisResourceCacheDb::isValid()); KisResourceLocator::LocatorError r = m_locator->initialize(m_srcLocation); if (!m_locator->errorMessages().isEmpty()) qDebug() << m_locator->errorMessages(); QVERIFY(r == KisResourceLocator::LocatorError::Ok); QVERIFY(QDir(m_dstLocation).exists()); } void TestTagFilterResourceProxyModel::testRowCount() { QSqlQuery q; QVERIFY(q.prepare("SELECT count(*)\n" "FROM resources\n" ", resource_types\n" "WHERE resources.resource_type_id = resource_types.id\n" "AND resource_types.name = :resource_type")); q.bindValue(":resource_type", resourceType); QVERIFY(q.exec()); q.first(); int rowCount = q.value(0).toInt(); QVERIFY(rowCount == 3); KisResourceModel *resourceModel = KisResourceModelProvider::resourceModel(resourceType); KisTagFilterResourceProxyModel proxyModel; proxyModel.setSourceModel(resourceModel); QCOMPARE(proxyModel.rowCount(), rowCount); } void TestTagFilterResourceProxyModel::testData() { KisResourceModel *resourceModel = KisResourceModelProvider::resourceModel(resourceType); KisTagFilterResourceProxyModel proxyModel; proxyModel.setSourceModel(resourceModel); QStringList names = QStringList() << "test0.kpp" << "test1.kpp" << "test2.kpp"; for (int i = 0; i < proxyModel.rowCount(); ++i) { - QVariant v = resourceModel->data(proxyModel.mapToSource(proxyModel.index(i, 0)), Qt::UserRole + KisResourceModel::Name); + QVariant v = resourceModel->data(proxyModel.mapToSource(proxyModel.index(i, 0)), Qt::UserRole + KisAbstractResourceModel::Name); QVERIFY(names.contains(v.toString())); } } void TestTagFilterResourceProxyModel::testResource() { KisResourceModel *resourceModel = KisResourceModelProvider::resourceModel(resourceType); KisTagFilterResourceProxyModel proxyModel; proxyModel.setSourceModel(resourceModel); KoResourceSP resource = resourceModel->resourceForIndex(proxyModel.mapToSource(proxyModel.index(0, 0))); QVERIFY(resource); } void TestTagFilterResourceProxyModel::cleanupTestCase() { ResourceTestHelper::rmTestDb(); ResourceTestHelper::cleanDstLocation(m_dstLocation); } QTEST_MAIN(TestTagFilterResourceProxyModel)