diff --git a/libs/resources/KisResourceLocator.cpp b/libs/resources/KisResourceLocator.cpp index 3e34608359..06be79ae26 100644 --- a/libs/resources/KisResourceLocator.cpp +++ b/libs/resources/KisResourceLocator.cpp @@ -1,401 +1,448 @@ /* * 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 "KisResourceLocator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KoResourcePaths.h" #include "KisResourceStorage.h" #include "KisResourceCacheDb.h" #include "KisResourceLoaderRegistry.h" #include "KisMemoryStorage.h" const QString KisResourceLocator::resourceLocationKey {"ResourceDirectory"}; class KisResourceLocator::Private { public: QString resourceLocation; QMap storages; QHash, KoResourceSP> resourceCache; QStringList errorMessages; - KisMemoryStorage memoryStorage; // For temporary resources }; KisResourceLocator::KisResourceLocator(QObject *parent) : QObject(parent) , d(new Private()) { } KisResourceLocator *KisResourceLocator::instance() { KisResourceLocator *locator = qApp->findChild(QString()); if (!locator) { locator = new KisResourceLocator(qApp); } return locator; } KisResourceLocator::~KisResourceLocator() { } KisResourceLocator::LocatorError KisResourceLocator::initialize(const QString &installationResourcesLocation) { InitalizationStatus initalizationStatus = InitalizationStatus::Unknown; KConfigGroup cfg(KSharedConfig::openConfig(), ""); d->resourceLocation = cfg.readEntry(resourceLocationKey, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); QFileInfo fi(d->resourceLocation); if (!fi.exists()) { if (!QDir().mkpath(d->resourceLocation)) { d->errorMessages << i18n("1. Could not create the resource location at %1.", d->resourceLocation); return LocatorError::CannotCreateLocation; } initalizationStatus = InitalizationStatus::FirstRun; } if (!fi.isWritable()) { d->errorMessages << i18n("2. The resource location at %1 is not writable.", d->resourceLocation); return LocatorError::LocationReadOnly; } // Check whether we're updating from an older version if (initalizationStatus != InitalizationStatus::FirstRun) { QFile fi(d->resourceLocation + '/' + "KRITA_RESOURCE_VERSION"); if (!fi.exists()) { initalizationStatus = InitalizationStatus::FirstUpdate; } else { fi.open(QFile::ReadOnly); QVersionNumber resource_version = QVersionNumber::fromString(QString::fromUtf8(fi.readAll())); QVersionNumber krita_version = QVersionNumber::fromString(KritaVersionWrapper::versionString()); if (krita_version > resource_version) { initalizationStatus = InitalizationStatus::Updating; } else { initalizationStatus = InitalizationStatus::Initialized; } } } if (initalizationStatus != InitalizationStatus::Initialized) { KisResourceLocator::LocatorError res = firstTimeInstallation(initalizationStatus, installationResourcesLocation); if (res != LocatorError::Ok) { return res; } initalizationStatus = InitalizationStatus::Initialized; } else { if (!synchronizeDb()) { return LocatorError::CannotSynchronizeDb; } } return LocatorError::Ok; } QStringList KisResourceLocator::errorMessages() const { return d->errorMessages; } QString KisResourceLocator::resourceLocationBase() const { return d->resourceLocation; } bool KisResourceLocator::resourceCached(QString storageLocation, const QString &resourceLocation) const { if (storageLocation.isEmpty()) { storageLocation = resourceLocationBase(); } else { storageLocation = resourceLocationBase() + '/' + storageLocation; } QPair key = QPair (storageLocation, resourceLocation); return d->resourceCache.contains(key); } KoResourceSP KisResourceLocator::resource(QString storageLocation, const QString &resourceLocation) { if (storageLocation.isEmpty()) { storageLocation = resourceLocationBase(); } - else { + else if (!QFileInfo(storageLocation).isAbsolute()) { storageLocation = resourceLocationBase() + '/' + storageLocation; } QPair key = QPair (storageLocation, resourceLocation); KoResourceSP resource; if (d->resourceCache.contains(key)) { resource = d->resourceCache[key]; } else { Q_ASSERT(d->storages.contains(storageLocation)); KisResourceStorageSP storage = d->storages[storageLocation]; Q_ASSERT(storage); resource = storage->resource(resourceLocation); if (resource) { d->resourceCache[key] = resource; } } return resource; } +KoResourceSP KisResourceLocator::resourceForId(int resourceId) +{ + ResourceStorage rs = getResourceStorage(resourceId); + return resource(rs.storageLocation, rs.resourceLocation); +} + bool KisResourceLocator::removeResource(int resourceId) { // First remove the resource from the cache + ResourceStorage rs = getResourceStorage(resourceId); + QPair key = QPair (rs.storageLocation, rs.resourceLocation); - // XXX: Should this query go into KisResourceCacheDb? - QSqlQuery q; - bool r = q.prepare("SELECT storages.location\n" - ", resources.filename\n" - "FROM resources\n" - ", storages\n" - "WHERE resources.id = :resource_id\n" - "AND resources.storage_id = storages.id"); - if (!r) { - qWarning() << "KisResourceLocator::removeResource: could not prepare query." << q.lastError(); - return false; - } - - q.bindValue(":resource_id", resourceId); - - r = q.exec(); - if (!r) { - qWarning() << "KisResourceLocator::removeResource: could not execute query." << q.lastError(); - } - - q.first(); - - QString storageLocation = q.value("location").toString(); - QString resourceLocation = q.value("filename").toString(); - - if (storageLocation.isEmpty()) { - storageLocation = resourceLocationBase(); - } - else { - storageLocation = resourceLocationBase() + '/' + storageLocation; - } - - QPair key = QPair (storageLocation, resourceLocation); - r = d->resourceCache.remove(key); + d->resourceCache.remove(key); return KisResourceCacheDb::removeResource(resourceId); } bool KisResourceLocator::importResourceFromFile(const QString &resourceType, const QString &fileName) { KisResourceLoaderBase *loader = KisResourceLoaderRegistry::instance()->loader(resourceType, KisMimeDatabase::mimeTypeForFile(fileName)); QFile f(fileName); if (!f.open(QFile::ReadOnly)) { qWarning() << "Could not open" << fileName << "for loading"; return false; } KoResourceSP resource = loader->load(fileName, f); if (!saveResourceToFolderStorage(resourceType, resource)) { return false; } return KisResourceCacheDb::addResource(folderStorage(), QFileInfo(resource->filename()).lastModified(), resource, resourceType); } bool KisResourceLocator::addResource(const QString &resourceType, const KoResourceSP resource, bool save) { if (!resource || !resource->valid()) return false; if (save) { if (!saveResourceToFolderStorage(resourceType, resource)) { return false; } } + else { + resource->setFilename("memory/" + resourceType + "/" + resource->name()); + memoryStorage()->addResource(resourceType, resource); + } - return KisResourceCacheDb::addResource(folderStorage(), QFileInfo(resource->filename()).lastModified(), resource, resourceType, !save); + return KisResourceCacheDb::addResource(save ? folderStorage() : memoryStorage(), + QFileInfo(resource->filename()).lastModified(), + resource, + resourceType, + !save); } +void KisResourceLocator::purge() +{ + d->resourceCache.clear(); +} + KisResourceLocator::LocatorError KisResourceLocator::firstTimeInstallation(InitalizationStatus initalizationStatus, const QString &installationResourcesLocation) { emit progressMessage(i18n("Krita is running for the first time. Intialization will take some time.")); Q_UNUSED(initalizationStatus); Q_FOREACH(const QString &folder, KisResourceLoaderRegistry::instance()->resourceTypes()) { QDir dir(d->resourceLocation + '/' + folder + '/'); if (!dir.exists()) { if (!QDir().mkpath(d->resourceLocation + '/' + folder + '/')) { d->errorMessages << i18n("3. Could not create the resource location at %1.", dir.path()); return LocatorError::CannotCreateLocation; } } } Q_FOREACH(const QString &folder, KisResourceLoaderRegistry::instance()->resourceTypes()) { QDir dir(installationResourcesLocation + '/' + folder + '/'); if (dir.exists()) { Q_FOREACH(const QString &entry, dir.entryList(QDir::Files | QDir::Readable)) { QFile f(dir.canonicalPath() + '/'+ entry); if (!QFileInfo(d->resourceLocation + '/' + folder + '/' + entry).exists()) { if (!f.copy(d->resourceLocation + '/' + folder + '/' + entry)) { d->errorMessages << i18n("Could not copy resource %1 to %2").arg(f.fileName()).arg(d->resourceLocation + '/' + folder + '/' + entry); } } } } } // And add bundles and adobe libraries QStringList filters = QStringList() << "*.bundle" << "*.abr" << "*.asl"; QDirIterator iter(installationResourcesLocation, filters, QDir::Files, QDirIterator::Subdirectories); while (iter.hasNext()) { iter.next(); emit progressMessage(i18n("Installing the resources from bundle %1.", iter.filePath())); QFile f(iter.filePath()); Q_ASSERT(f.exists()); if (!f.copy(d->resourceLocation + '/' + iter.fileName())) { d->errorMessages << i18n("Could not copy resource %1 to %2").arg(f.fileName()).arg(d->resourceLocation); } } QFile f(d->resourceLocation + '/' + "KRITA_RESOURCE_VERSION"); f.open(QFile::WriteOnly); f.write(KritaVersionWrapper::versionString().toUtf8()); f.close(); if (!initializeDb()) { return LocatorError::CannotInitializeDb; } return LocatorError::Ok; } bool KisResourceLocator::initializeDb() { emit progressMessage(i18n("Initalizing the resources.")); d->errorMessages.clear(); findStorages(); Q_FOREACH(KisResourceStorageSP storage, d->storages) { if (!KisResourceCacheDb::addStorage(storage, (storage->type() == KisResourceStorage::StorageType::Folder ? false : true))) { d->errorMessages.append(i18n("Could not add storage %1 to the cache database").arg(storage->location())); } Q_FOREACH(const QString &resourceType, KisResourceLoaderRegistry::instance()->resourceTypes()) { emit progressMessage(i18n("Adding %1 resources to folder %2", resourceType, storage->location())); if (!KisResourceCacheDb::addResources(storage, resourceType)) { d->errorMessages.append(i18n("Could not add resource type %1 to the cache database").arg(resourceType)); } if (!KisResourceCacheDb::addTags(storage, resourceType)) { d->errorMessages.append(i18n("Could not add tags for resource type %1 to the cache database").arg(resourceType)); } } } return (d->errorMessages.isEmpty()); } void KisResourceLocator::findStorages() { d->storages.clear(); // Add the folder KisResourceStorageSP storage = QSharedPointer::create(d->resourceLocation); d->storages[storage->location()] = storage; + // Add the memory storage + d->storages["memory"] = QSharedPointer::create("memory"); + // And add bundles and adobe libraries QStringList filters = QStringList() << "*.bundle" << "*.abr" << "*.asl"; QDirIterator iter(d->resourceLocation, filters, QDir::Files, QDirIterator::Subdirectories); while (iter.hasNext()) { iter.next(); KisResourceStorageSP storage = QSharedPointer::create(iter.filePath()); d->storages[storage->location()] = storage; } } QList KisResourceLocator::storages() const { return d->storages.values(); } bool KisResourceLocator::saveResourceToFolderStorage(const QString &resourceType, KoResourceSP resource) { - resource->setFilename(folderStorage()->location() + "/" + resourceType + "/" + resource->name()); if (QFileInfo(resource->filename()).exists()) { qWarning() << "Resource" << resource->filename() << "already exists"; return false; } if (!resource->save()) { qWarning() << "Could not save" << resource->filename(); return false; } return true; } +KisResourceStorageSP KisResourceLocator::storageByName(const QString &name) const +{ + if (!d->storages.contains(name)) { + qWarning() << "No" << name << "storage defined"; + return 0; + } + KisResourceStorageSP storage = d->storages[name]; + if (!storage || !storage->valid()) { + qWarning() << "Could not retrieve the" << name << "storage object or the object is not valid"; + return 0; + } + + return storage; +} + KisResourceStorageSP KisResourceLocator::folderStorage() const { - KisResourceStorageSP folderStorage = d->storages[d->resourceLocation]; - if (!folderStorage || !folderStorage->valid()) { - qWarning() << "Could not retrieve the folder storage object for the configured resource location" << d->resourceLocation; + return storageByName(d->resourceLocation); +} + +KisResourceStorageSP KisResourceLocator::memoryStorage() const +{ + return storageByName("memory"); +} + +KisResourceLocator::ResourceStorage KisResourceLocator::getResourceStorage(int resourceId) const +{ + ResourceStorage rs; + + QSqlQuery q; + bool r = q.prepare("SELECT storages.location\n" + ", resources.filename\n" + "FROM resources\n" + ", storages\n" + "WHERE resources.id = :resource_id\n" + "AND resources.storage_id = storages.id"); + if (!r) { + qWarning() << "KisResourceLocator::removeResource: could not prepare query." << q.lastError(); + return rs; } - return folderStorage; + + q.bindValue(":resource_id", resourceId); + + r = q.exec(); + if (!r) { + qWarning() << "KisResourceLocator::removeResource: could not execute query." << q.lastError(); + return rs; + } + + q.first(); + + QString storageLocation = q.value("location").toString(); + QString resourceLocation = q.value("filename").toString(); + + if (storageLocation.isEmpty()) { + storageLocation = resourceLocationBase(); + } + else { + storageLocation = resourceLocationBase() + '/' + storageLocation; + } + + rs.storageLocation = storageLocation; + rs.resourceLocation = resourceLocation; + + return rs; } bool KisResourceLocator::synchronizeDb() { d->errorMessages.clear(); findStorages(); Q_FOREACH(const KisResourceStorageSP storage, d->storages) { if (!KisResourceCacheDb::synchronizeStorage(storage)) { d->errorMessages.append(i18n("Could not synchronize %1 with the database").arg(storage->location())); } } return d->errorMessages.isEmpty(); } diff --git a/libs/resources/KisResourceLocator.h b/libs/resources/KisResourceLocator.h index fd142df1f9..04a7a3b22a 100644 --- a/libs/resources/KisResourceLocator.h +++ b/libs/resources/KisResourceLocator.h @@ -1,130 +1,184 @@ -/* +/* * 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 + * @return + */ QString resourceLocationBase() const; + /** + * @brief resource + * @param storageLocation + * @param resourceLocationBase + * @return + */ KoResourceSP resource(QString storageLocation, const QString &resourceLocationBase); + /** + * @brief resourceForId returns the resource with the given id, or 0 if no such resource exists + * @param resourceId the id + */ + KoResourceSP resourceForId(int resourceId); + + /** + * @brief removeResource + * @param resourceId + * @return + */ bool removeResource(int resourceId); + /** + * @brief importResourceFromFile + * @param resourceType + * @param fileName + * @return + */ bool importResourceFromFile(const QString &resourceType, const QString &fileName); + /** + * @brief addResource + * @param resourceType + * @param resource + * @param save + * @return + */ bool addResource(const QString &resourceType, const KoResourceSP resource, bool save = true); + /** + * @brief purge purges the local resource cache + */ + void purge(); + Q_SIGNALS: void progressMessage(const QString&); private: friend class KisResourceModel; /// @return true if the resource is present in the cache, false if it hasn't been loaded bool resourceCached(QString storageLocation, const QString &resourceLocationBase) const; friend class TestResourceLocator; KisResourceLocator(QObject *parent); KisResourceLocator(const KisResourceLocator&); KisResourceLocator operator=(const KisResourceLocator&); enum class InitalizationStatus { 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(InitalizationStatus initalizationStatus, 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; bool saveResourceToFolderStorage(const QString &resourceType, KoResourceSP resource); + + KisResourceStorageSP storageByName(const QString &name) const; KisResourceStorageSP folderStorage() const; + KisResourceStorageSP memoryStorage() const; + + struct ResourceStorage { + QString storageLocation; + QString resourceLocation; + }; + + ResourceStorage getResourceStorage(int resourceId) const; + class Private; QScopedPointer d; }; #endif // KISRESOURCELOCATOR_H diff --git a/libs/resources/KisResourceModel.h b/libs/resources/KisResourceModel.h index 9708ca78b7..bbdafacaf4 100644 --- a/libs/resources/KisResourceModel.h +++ b/libs/resources/KisResourceModel.h @@ -1,160 +1,161 @@ /* * 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 class 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. * @param resource the resource. * @param save if true, save the resource to the default storage, if false, the resource will not exist the next time Krita is started. * @return */ virtual bool addResource(KoResourceSP resource, bool save = true) = 0; /** * @brief updateResource * @param resource * @return */ virtual bool updateResource(KoResourceSP resource) = 0; /** * @brief removeResource * @param resource * @return */ virtual bool removeResource(KoResourceSP resource) = 0; }; /** * @brief The KisResourceModel class provides access to the cache database * for a particular resource type. Instances should be retrieved using * KisResourceModelProvider. */ 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, Image, 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 }; 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; // Resources API 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, bool save = true) override; bool updateResource(KoResourceSP resource) override; Q_SIGNALS: void beforeResourcesLayoutReset(QModelIndex); void afterResourcesLayoutReset(); private: bool resetQuery(); QStringList tagsForResource(int resourceId) const; struct Private; Private *const d; }; #endif // KISRESOURCEMODEL_H diff --git a/libs/resources/KisResourceStorage.cpp b/libs/resources/KisResourceStorage.cpp index f31a2a418d..efcae98617 100644 --- a/libs/resources/KisResourceStorage.cpp +++ b/libs/resources/KisResourceStorage.cpp @@ -1,122 +1,142 @@ /* * 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 "KisResourceStorage.h" #include #include #include #include "KisStoragePlugin.h" #include "KisFolderStorage.h" #include "KisBundleStorage.h" #include "KisAbrStorage.h" #include "KisAslStorage.h" +#include "KisMemoryStorage.h" class KisResourceStorage::Private { public: QString name; QString location; bool valid {false}; KisResourceStorage::StorageType storageType {KisResourceStorage::StorageType::Unknown}; - QScopedPointer storagePlugin; + QSharedPointer storagePlugin; }; KisResourceStorage::KisResourceStorage(const QString &location) : d(new Private()) { d->location = location; QFileInfo fi(d->location); if (fi.isDir()) { d->storagePlugin.reset(new KisFolderStorage(location)); d->name = location; d->storageType = StorageType::Folder; d->valid = fi.isWritable(); } + else if (location == "memory") { + d->storagePlugin.reset(new KisMemoryStorage); + d->name = "memory"; + d->storageType = StorageType::Memory; + d->valid = true; + } else { if (d->location.endsWith(".bundle")) { d->storagePlugin.reset(new KisBundleStorage(location)); d->storageType = StorageType::Bundle; // XXX: should we also check whether there's a valid metadata entry? Or is this enough? d->valid = (fi.isReadable() && QuaZip(d->location).open(QuaZip::mdUnzip)); } else if (d->location.endsWith(".abr")) { d->storagePlugin.reset(new KisAbrStorage(location)); d->storageType = StorageType::AdobeBrushLibrary; d->valid = fi.isReadable(); } else if (d->location.endsWith(".asl")) { d->storagePlugin.reset(new KisAslStorage(location)); d->storageType = StorageType::AdobeStyleLibrary; d->valid = fi.isReadable(); } } } KisResourceStorage::~KisResourceStorage() { } QString KisResourceStorage::name() const { return d->name; } QString KisResourceStorage::location() const { return d->location; } KisResourceStorage::StorageType KisResourceStorage::type() const { return d->storageType; } QDateTime KisResourceStorage::timestamp() const { return QFileInfo(d->location).lastModified(); } KisResourceStorage::ResourceItem KisResourceStorage::resourceItem(const QString &url) { return d->storagePlugin->resourceItem(url); } KoResourceSP KisResourceStorage::resource(const QString &url) { return d->storagePlugin->resource(url); } QSharedPointer KisResourceStorage::resources(const QString &resourceType) const { return d->storagePlugin->resources(resourceType); } QSharedPointer KisResourceStorage::tags(const QString &resourceType) const { return d->storagePlugin->tags(resourceType); } +void KisResourceStorage::addTag(const QString &resourceType, KisTagSP tag) +{ + if (d->storagePlugin.dynamicCast()) { + d->storagePlugin.dynamicCast()->addTag(resourceType, tag); + } +} + +void KisResourceStorage::addResource(const QString &resourceType, KoResourceSP resource) +{ + if (d->storagePlugin.dynamicCast()) { + d->storagePlugin.dynamicCast()->addResource(resourceType, resource); + } +} bool KisResourceStorage::valid() const { return d->valid; } diff --git a/libs/resources/KisResourceStorage.h b/libs/resources/KisResourceStorage.h index b5dd8a042c..e67f836b2f 100644 --- a/libs/resources/KisResourceStorage.h +++ b/libs/resources/KisResourceStorage.h @@ -1,119 +1,123 @@ /* * 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 KISRESOURCESTORAGE_H #define KISRESOURCESTORAGE_H #include #include #include #include #include #include #include /** * The KisResourceStorage class is the base class for * places where resources can be stored. Examples are * folders, bundles or Adobe resource libraries like * ABR files. */ class KRITARESOURCES_EXPORT KisResourceStorage { public: /// A resource item is simply an entry in the storage, struct ResourceItem { virtual ~ResourceItem() {} QString url; QString folder; QString resourceType; QDateTime lastModified; }; class TagIterator { public: virtual ~TagIterator() {} virtual bool hasNext() const = 0; virtual void next() const = 0; /// The untranslated name of the tag, to be used for making connections to resources virtual QString url() const = 0; /// The translated name of the tag, to be shown in the GUI virtual QString name() const = 0; /// An extra, optional comment for the tag virtual QString comment() const = 0; /// A tag object on which we can set properties and which we can save virtual KisTagSP tag() const = 0; }; class ResourceIterator { public: virtual ~ResourceIterator() {} virtual bool hasNext() const = 0; virtual void next() const = 0; virtual QString url() const = 0; virtual QString type() const = 0; virtual QDateTime lastModified() const = 0; /// This only loads the resource when called virtual KoResourceSP resource() const = 0; }; enum class StorageType : int { Unknown = 1, Folder = 2, Bundle = 3, AdobeBrushLibrary = 4, - AdobeStyleLibrary = 5 + AdobeStyleLibrary = 5, + Memory = 6 }; KisResourceStorage(const QString &location); ~KisResourceStorage(); QString name() const; QString location() const; bool valid() const; StorageType type() const; QDateTime timestamp() const; ResourceItem resourceItem(const QString &url); KoResourceSP resource(const QString &url); QSharedPointer resources(const QString &resourceType) const; QSharedPointer tags(const QString &resourceType) const; + void addTag(const QString &resourceType, KisTagSP tag); + void addResource(const QString &resourceType, KoResourceSP resource); + private: class Private; QScopedPointer d; }; typedef QSharedPointer KisResourceStorageSP; #endif // KISRESOURCESTORAGE_H diff --git a/libs/resources/KisResourceTypeModel.cpp b/libs/resources/KisResourceTypeModel.cpp index 06b1c66668..91c29349d5 100644 --- a/libs/resources/KisResourceTypeModel.cpp +++ b/libs/resources/KisResourceTypeModel.cpp @@ -1,123 +1,124 @@ /* * 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 "KisResourceTypeModel.h" #include #include "KisResourceLoader.h" #include "KisResourceLoaderRegistry.h" struct KisResourceTypeModel::Private { int cachedRowCount {-1}; QSqlQuery query; }; KisResourceTypeModel::KisResourceTypeModel(QObject *parent) : QAbstractTableModel(parent) , d(new Private) { prepareQuery(); } KisResourceTypeModel::~KisResourceTypeModel() { delete d; } int KisResourceTypeModel::rowCount(const QModelIndex &/*parent*/) const { if (d->cachedRowCount < 0) { QSqlQuery q; q.prepare("SELECT count(*)\n" "FROM resource_types\n"); q.exec(); q.first(); const_cast(this)->d->cachedRowCount = q.value(0).toInt(); qDebug() << "KisResourceTypeModel::rowCount()" << d->cachedRowCount; } return d->cachedRowCount; } int KisResourceTypeModel::columnCount(const QModelIndex &/*parent*/) const { return 3; } QVariant KisResourceTypeModel::data(const QModelIndex &index, int role) const { QVariant v; if (!index.isValid()) return v; if (index.row() > rowCount()) return v; if (index.column() > (int)Name) return v; bool pos = d->query.seek(index.row()); if (pos) { QString id = d->query.value("id").toString(); QString resourceType = d->query.value("name").toString(); QString name = resourceType; QVector loaders = KisResourceLoaderRegistry::instance()->resourceTypeLoaders(resourceType); Q_ASSERT(loaders.size() > 0); name = loaders.first()->name(); switch(role) { case Qt::DisplayRole: { switch(index.column()) { case Id: return id; case ResourceType: return resourceType; case Name: + default: return name; } } case Qt::UserRole + Id: return id; case Qt::UserRole + ResourceType: return resourceType; case Qt::UserRole + Name: return name; default: ; } } return v; } bool KisResourceTypeModel::prepareQuery() { beginResetModel(); bool r = d->query.prepare("SELECT id\n" ", name\n" "FROM resource_types\n"); if (!r) { qWarning() << "Could not prepare KisResourceTypeModel query" << d->query.lastError(); } r = d->query.exec(); if (!r) { qWarning() << "Could not execute KisResourceTypeModel query" << d->query.lastError(); } d->cachedRowCount = -1; endResetModel(); return r; } diff --git a/libs/resources/KisStoragePlugin.h b/libs/resources/KisStoragePlugin.h index 1683be20bd..2039513bd5 100644 --- a/libs/resources/KisStoragePlugin.h +++ b/libs/resources/KisStoragePlugin.h @@ -1,71 +1,71 @@ /* * 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 KISSTORAGEPLUGIN_H #define KISSTORAGEPLUGIN_H #include #include #include #include "kritaresources_export.h" /** - * The KisResourceStoragePlugin class is the base class + * The KisStoragePlugin class is the base class * for storage plugins. A storage plugin is used by * KisResourceStorage to locate resources and tags in * a kind of storage, like a folder, a bundle or an adobe * resource library. */ class KRITARESOURCES_EXPORT KisStoragePlugin { public: KisStoragePlugin(const QString &location); virtual ~KisStoragePlugin(); virtual KisResourceStorage::ResourceItem resourceItem(const QString &url) = 0; virtual KoResourceSP resource(const QString &url) = 0; virtual QSharedPointer resources(const QString &resourceType) = 0; virtual QSharedPointer tags(const QString &resourceType) = 0; virtual QImage thumbnail() const { return QImage(); } static const QString s_meta_generator; static const QString s_meta_author; static const QString s_meta_title; static const QString s_meta_description; static const QString s_meta_initial_creator; static const QString s_meta_creator; static const QString s_meta_creation_date; static const QString s_meta_dc_date; static const QString s_meta_user_defined; static const QString s_meta_name; static const QString s_meta_value; static const QString s_meta_version; virtual QString metaData(const QString &key) const { Q_UNUSED(key); return QString(); } protected: friend class TestBundleStorage; QString location() const; private: class Private; QScopedPointer d; }; #endif // KISSTORAGEPLUGIN_H diff --git a/libs/resources/KoResource.h b/libs/resources/KoResource.h index d391769226..6d4785371b 100644 --- a/libs/resources/KoResource.h +++ b/libs/resources/KoResource.h @@ -1,163 +1,165 @@ /* This file is part of the KDE project Copyright (c) 2003 Patrick Julien Copyright (c) 2005 Boudewijn Rempt This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef KORESOURCE_H #define KORESOURCE_H #include #include #include #include #include "KisResourceTypes.h" #include class QDomDocument; class QDomElement; /** * The KoResource class provides a representation of resources. This * includes, but not limited to, brushes and patterns. */ class KRITARESOURCES_EXPORT KoResource { public: /** * Creates a new KoResource object using @p filename. No file is opened * in the constructor, you have to call load. * * @param filename the file name to save and load from. */ explicit KoResource(const QString &filename); virtual ~KoResource(); bool operator ==(const KoResource &other) const { return other.md5() == md5(); } public: /** * Load this resource. * @return true if loading the resource succeeded. */ virtual bool load() = 0; virtual bool loadFromDevice(QIODevice *dev) = 0; /** * Save this resource. *@return true if saving the resource succeeded. */ virtual bool save() = 0; virtual bool saveToDevice(QIODevice* dev) const; /** * @returns a QImage thumbnail image representing this resource. * * This image could be null. The image can be in any valid format. */ QImage image() const; void setImage(const QImage &image); /// @return the md5sum calculated over the contents of the resource. QByteArray md5() const; /// @returns true if resource can be removed by the user bool removable() const; /// @return the full path to this resource QString filename() const; void setFilename(const QString& filename); /// @return the name of the file without the path QString shortFilename() const; /// @return the user-visible name of the resource QString name() const; void setName(const QString& name); /// @return true if the resource is ready for use bool valid() const; void setValid(bool valid); /// @return the default file extension which should be used when saving the resource virtual QString defaultFileExtension() const; /// @return true if the resource is permanent and can't be removed by the user bool permanent() const; void setPermanent(bool permanent); /// @return the name of the storage location of the resource QString storageLocation() const; /// Mark the preset as modified but not saved void setDirty(bool value); /// @return true if the preset has been modified, but not saved bool isDirty() const; /// store the given key, value pair in the resource void addMetaData(QString key, QVariant value); /// get a map with all the metadata QMap metadata() const; private: friend class KisResourceModel; friend class TestResourceModel; + friend class TestResourceLocator; + /// @return the unique id of the resource in the resource database int resourceId() const; void setResourceId(int id); void setStorageLocation(const QString &location); protected: /// override generateMD5 and in your resource subclass virtual QByteArray generateMD5() const; /// call this when the contents of the resource change so the md5 needs to be recalculated void setMD5(const QByteArray &md5); protected: KoResource(const KoResource &rhs); private: struct Private; Private* const d; }; static inline bool operator==(const KoResource &resource1, const KoResource &resource2) { return (resource1.md5() == resource2.md5()); } static inline uint qHash(const KoResource &resource) { return qHash(resource.md5()); } typedef QSharedPointer KoResourceSP; Q_DECLARE_METATYPE(QSharedPointer) #endif // KORESOURCE_H_ diff --git a/libs/resources/tests/DummyResource.h b/libs/resources/tests/DummyResource.h index d3427453b7..623e3712e8 100644 --- a/libs/resources/tests/DummyResource.h +++ b/libs/resources/tests/DummyResource.h @@ -1,32 +1,46 @@ /* * 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. */ #ifndef DUMMYRESOURCE_H #define DUMMYRESOURCE_H #include "KoResource.h" #include class DummyResource : public KoResource { public: DummyResource(const QString &f) : KoResource(f) {} bool load() override { setValid(true); return true; } bool loadFromDevice(QIODevice *) override { setValid(true); return true; } bool save() override { return true; } + + void setSomething(const QString &something) + { + m_something = something; + } + + QString something() const + { + return m_something; + } + +private: + + QString m_something; }; #endif // DUMMYRESOURCE_H diff --git a/libs/resources/tests/TestResourceLocator.cpp b/libs/resources/tests/TestResourceLocator.cpp index 2961cd823b..0fe97066f4 100644 --- a/libs/resources/tests/TestResourceLocator.cpp +++ b/libs/resources/tests/TestResourceLocator.cpp @@ -1,142 +1,156 @@ /* * Copyright (C) 2017 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 "TestResourceLocator.h" #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 TestResourceLocator::initTestCase() { ResourceTestHelper::initTestDb(); 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(); ResourceTestHelper::createDummyLoaderRegistry(); } void TestResourceLocator::testLocatorInitalization() { KisResourceCacheDb::initialize(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); 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()); Q_FOREACH(const QString &folder, KisResourceLoaderRegistry::instance()->resourceTypes()) { QDir dstDir(m_dstLocation + '/' + folder + '/'); QDir srcDir(m_srcLocation + '/' + folder + '/'); QVERIFY(dstDir.exists()); QVERIFY(dstDir.entryList(QDir::Files | QDir::NoDotAndDotDot) == srcDir.entryList(QDir::Files | QDir::NoDotAndDotDot)); } QFile f(m_dstLocation + '/' + "KRITA_RESOURCE_VERSION"); QVERIFY(f.exists()); f.open(QFile::ReadOnly); QVersionNumber version = QVersionNumber::fromString(QString::fromUtf8(f.readAll())); QVERIFY(version == QVersionNumber::fromString(KritaVersionWrapper::versionString())); } void TestResourceLocator::testStorageInitialization() { Q_FOREACH(KisResourceStorageSP storage, m_locator->storages()) { QVERIFY(KisResourceCacheDb::addStorage(storage, true)); } QSqlQuery query; bool r = query.exec("SELECT COUNT(*) FROM storages"); QVERIFY(r); QVERIFY(query.lastError() == QSqlError()); query.first(); QVERIFY(query.value(0).toInt() == m_locator->storages().count()); } void TestResourceLocator::testLocatorSynchronization() { QVERIFY(m_locator->synchronizeDb()); } void TestResourceLocator::testResources() { QSqlQuery query; bool r = query.exec("SELECT COUNT(*) FROM resources"); QVERIFY(r); QVERIFY(query.lastError() == QSqlError()); query.first(); QCOMPARE(query.value(0).toInt(), 7); } void TestResourceLocator::testTags() { QSqlQuery query; bool r = query.exec("SELECT COUNT(*) FROM tags"); QVERIFY(r); QVERIFY(query.lastError() == QSqlError()); query.first(); QCOMPARE(query.value(0).toInt(), 1); } -void TestResourceLocator::cleanupTestCase() + +void TestResourceLocator::testResourceLocationBase() { - ResourceTestHelper::rmTestDb(); - ResourceTestHelper::cleanDstLocation(m_dstLocation); + QCOMPARE(m_locator->resourceLocationBase(), QString(FILES_DEST_DIR)); } void TestResourceLocator::testResource() { KoResourceSP res = m_locator->resource("", "paintoppresets/test0.kpp"); QVERIFY(res); } +void TestResourceLocator::testResourceForId() +{ + KoResourceSP res = m_locator->resource("", "paintoppresets/test0.kpp"); + int resourceId = KisResourceCacheDb::resourceIdForResource("test0.kpp", "paintoppresets", ""); + QVERIFY(resourceId > -1); + KoResourceSP res2 = m_locator->resourceForId(resourceId); + QCOMPARE(res, res2); +} + +void TestResourceLocator::cleanupTestCase() +{ + ResourceTestHelper::rmTestDb(); + ResourceTestHelper::cleanDstLocation(m_dstLocation); +} QTEST_MAIN(TestResourceLocator) diff --git a/libs/resources/tests/TestResourceLocator.h b/libs/resources/tests/TestResourceLocator.h index b7f63755ed..151241a2fb 100644 --- a/libs/resources/tests/TestResourceLocator.h +++ b/libs/resources/tests/TestResourceLocator.h @@ -1,48 +1,52 @@ /* * Copyright (C) 2017 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 TESTRESOURCELOCATOR_H #define TESTRESOURCELOCATOR_H #include class KisResourceLocator; class TestResourceLocator : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testLocatorInitalization(); void testStorageInitialization(); void testLocatorSynchronization(); void testResources(); void testTags(); void cleanupTestCase(); + + void testResourceLocationBase(); void testResource(); + void testResourceForId(); + private: QString m_srcLocation; QString m_dstLocation; KisResourceLocator *m_locator; }; #endif diff --git a/libs/resources/tests/TestResourceModel.cpp b/libs/resources/tests/TestResourceModel.cpp index 49649b186a..cecf6143be 100644 --- a/libs/resources/tests/TestResourceModel.cpp +++ b/libs/resources/tests/TestResourceModel.cpp @@ -1,212 +1,225 @@ /* * 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))) { - qDebug() << "Could not initialize KisResourceCacheDb on" << 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); 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); } 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, false); QVERIFY(r); QCOMPARE(resourceCount + 1, resourceModel.rowCount()); } void TestResourceModel::testUpdateResource() { - KisResourceModel resourceModel(m_resourceType); - KoResourceSP resource = resourceModel.resourceForIndex(resourceModel.index(0, 0)); - QVERIFY(resource); - bool r = resourceModel.updateResource(resource); - QVERIFY(r); -} + 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); + } + { + KisResourceLocator::instance()->purge(); + KoResourceSP resource = KisResourceLocator::instance()->resourceForId(resourceId); + QVERIFY(resource); + QVERIFY(!resource.dynamicCast()->something().isEmpty()); + } +} + void TestResourceModel::cleanupTestCase() { - ResourceTestHelper::rmTestDb(); - ResourceTestHelper::cleanDstLocation(m_dstLocation); +// ResourceTestHelper::rmTestDb(); +// ResourceTestHelper::cleanDstLocation(m_dstLocation); } QTEST_MAIN(TestResourceModel) diff --git a/libs/resources/tests/TestResourceTypeModel.cpp b/libs/resources/tests/TestResourceTypeModel.cpp index 1306594435..28c6ba8b00 100644 --- a/libs/resources/tests/TestResourceTypeModel.cpp +++ b/libs/resources/tests/TestResourceTypeModel.cpp @@ -1,129 +1,128 @@ /* * 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 "TestResourceTypeModel.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 TestResourceTypeModel::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 TestResourceTypeModel::testRowCount() { QSqlQuery q; QVERIFY(q.prepare("SELECT count(*)\n" "FROM resource_types")); QVERIFY(q.exec()); q.first(); int rowCount = q.value(0).toInt(); QCOMPARE(rowCount, KisResourceLoaderRegistry::instance()->resourceTypes().count()); KisResourceTypeModel typeModel; QCOMPARE(typeModel.rowCount(), rowCount); } void TestResourceTypeModel::testData() { KisResourceTypeModel typeModel; for(int i = 0; i < typeModel.rowCount(); ++i) { QModelIndex idx = typeModel.index(0, KisResourceTypeModel::ResourceType); // qDebug() << "test" << idx.data(Qt::DisplayRole) // << idx.data(Qt::UserRole + KisResourceTypeModel::Id) // << idx.data(Qt::UserRole + KisResourceTypeModel::ResourceType) // << idx.data(Qt::UserRole + KisResourceTypeModel::Name); QVERIFY(KisResourceLoaderRegistry::instance()->resourceTypeLoaders(idx.data(Qt::DisplayRole).toString()).size() > 0); QVector loaders = KisResourceLoaderRegistry::instance()->resourceTypeLoaders(idx.data(Qt::UserRole + KisResourceTypeModel::ResourceType).toString()); QVERIFY(loaders.size() > 0); auto loader = loaders.first(); QCOMPARE(loader->name(), idx.data(Qt::UserRole + KisResourceTypeModel::Name).toString()); } } void TestResourceTypeModel::cleanupTestCase() { ResourceTestHelper::rmTestDb(); ResourceTestHelper::cleanDstLocation(m_dstLocation); - qDebug() << m_dstLocation; } QTEST_MAIN(TestResourceTypeModel)