Commit 309cce59 authored by Boudewijn Rempt's avatar Boudewijn Rempt

Use a dynamic list of resource folders as resource types

(Though there is still a nasty synchronization issue with the
database definition)
parent 13738334
......@@ -42,10 +42,11 @@ const QStringList KisResourceCacheDb::resourceTypes = QStringList() << "BRUSH_TI
<< "SESSION"
<< "UNKNOWN";
const QStringList KisResourceCacheDb::storageTypes = QStringList() << "FOLDER"
<< "BUNDLE"
<< "ADOBE_BRUSH_LIBRARY"
<< "ADOBE_STYLE_LIBRARY"; // Installed or created by the user
const QStringList KisResourceCacheDb::storageTypes = QStringList() << "UNKNOWN"
<< "FOLDER"
<< "BUNDLE"
<< "ADOBE_BRUSH_LIBRARY"
<< "ADOBE_STYLE_LIBRARY"; // Installed or created by the user
const QString KisResourceCacheDb::dbLocationKey {"ResourceCacheDbDirectory"};
const QString KisResourceCacheDb::resourceCacheDbFilename {"resourcecache.sqlite"};
......@@ -58,7 +59,6 @@ bool KisResourceCacheDb::isValid()
return s_valid;
}
QSqlError initDb(const QString &location)
{
if (!QSqlDatabase::connectionNames().isEmpty()) {
......@@ -135,6 +135,7 @@ QSqlError initDb(const QString &location)
}
}
// Create tables
Q_FOREACH(const QString &table, tables) {
QFile f(":/create_" + table + ".sql");
if (f.open(QFile::ReadOnly)) {
......@@ -150,6 +151,25 @@ QSqlError initDb(const QString &location)
}
}
// Create indexes
QStringList indexes = QStringList() << "storages";
Q_FOREACH(const QString &index, indexes) {
QFile f(":/create_index_" + index + ".sql");
if (f.open(QFile::ReadOnly)) {
QSqlQuery query;
if (!query.exec(f.readAll())) {
qWarning() << "Could not create index" << index;
return db.lastError();
}
infoResources << "Created table" << index;
}
else {
return QSqlError("Error executing SQL", QString("Could not find SQL file %1").arg(index), QSqlError::StatementError);
}
}
// Fill lookup tables
{
if (dbTables.contains("origin_types")) {
QSqlQuery query;
......@@ -234,3 +254,64 @@ bool KisResourceCacheDb::initialize(const QString &location)
return s_valid;
}
bool KisResourceCacheDb::addResources(KisResourceStorageSP storage, QString folder)
{
qDebug() << folder << storage->resources(folder).count();
return true;
}
bool KisResourceCacheDb::addStorage(KisResourceStorageSP storage, bool preinstalled)
{
bool r = true;
if (!s_valid) return false;
{
QSqlQuery q;
r = q.prepare("SELECT * FROM storages WHERE location = :location");
q.bindValue(":location", storage->location());
r = q.exec();
if (!r) {
qWarning() << "Could not select from storages";
return r;
}
if (q.first()) {
//qDebug() << "This storage already exists";
return true;
}
}
{
QSqlQuery q;
r = q.prepare("INSERT INTO storages "
"(origin_type_id, location, datestamp, pre_installed, active)"
"VALUES"
"(:origin_type_id, :location, :datestamp, :pre_installed, :active);");
if (!r) {
qWarning() << "Could not prepare query" << q.lastError();
return r;
}
q.bindValue(":origin_type_id", static_cast<int>(storage->type()));
q.bindValue(":location", storage->location());
q.bindValue(":datestamp", storage->timestamp().toMSecsSinceEpoch());
q.bindValue(":pre_installed", preinstalled);
q.bindValue(":active", preinstalled ? 1 : 0);
r = q.exec();
if (!r) qWarning() << "Could not execute query" << q.lastError();
}
return r;
}
bool KisResourceCacheDb::synchronize(KisResourceStorageSP storage)
{
// Find the storage in the database
qDebug() << storage->location() << storage->timestamp();
return true;
}
......@@ -24,6 +24,8 @@
#include <kritaresources_export.h>
#include <KisResourceStorage.h>
/**
* @brief The KisResourceCacheDb class encapsulates the database that
* caches information about the resources available to the user.
......@@ -56,8 +58,18 @@ public:
private:
friend class KisResourceLocator;
friend class TestResourceLocator;
friend class TestResourceCacheDb;
explicit KisResourceCacheDb();
~KisResourceCacheDb();
KisResourceCacheDb operator=(const KisResourceCacheDb&);
static bool addResources(KisResourceStorageSP storage, QString folder);
static bool addStorage(KisResourceStorageSP storage, bool preinstalled);
static bool synchronize(KisResourceStorageSP storage);
static bool s_valid;
};
......
......@@ -39,3 +39,12 @@ KisResourceLoaderRegistry* KisResourceLoaderRegistry::instance()
}
return reg;
}
QStringList KisResourceLoaderRegistry::resourceFolders() const
{
QStringList r;
Q_FOREACH(KisResourceLoaderBase *loader, values()) {
r << loader->folder();
}
return r;
}
......@@ -34,6 +34,8 @@ public:
static KisResourceLoaderRegistry *instance();
QStringList resourceFolders() const;
private:
KisResourceLoaderRegistry(QObject *parent);
......
......@@ -37,23 +37,11 @@
#include "KoResourcePaths.h"
#include "KisResourceStorage.h"
#include "KisResourceCacheDb.h"
#include "KisResourceLoaderRegistry.h"
const QString KisResourceLocator::resourceLocationKey {"ResourceDirectory"};
const QStringList KisResourceLocator::resourceTypeFolders = QStringList()
<< "tags"
<< "asl"
<< "bundles"
<< "brushes"
<< "gradients"
<< "paintoppresets"
<< "palettes"
<< "patterns"
<< "taskset"
<< "workspaces"
<< "symbols";
class KisResourceLocator::Private {
public:
QString resourceLocation;
......@@ -143,7 +131,7 @@ KisResourceLocator::LocatorError KisResourceLocator::firstTimeInstallation(Inita
{
Q_UNUSED(initalizationStatus);
Q_FOREACH(const QString &folder, resourceTypeFolders) {
Q_FOREACH(const QString &folder, KisResourceLoaderRegistry::instance()->resourceFolders()) {
QDir dir(d->resourceLocation + '/' + folder + '/');
if (!dir.exists()) {
if (!QDir().mkpath(d->resourceLocation + '/' + folder + '/')) {
......@@ -153,14 +141,14 @@ KisResourceLocator::LocatorError KisResourceLocator::firstTimeInstallation(Inita
}
}
Q_FOREACH(const QString &folder, resourceTypeFolders) {
Q_FOREACH(const QString &folder, KisResourceLoaderRegistry::instance()->resourceFolders()) {
QDir dir(installationResourcesLocation + '/' + folder + '/');
if (dir.exists()) {
Q_FOREACH(const QString &entry, dir.entryList(QDir::Files | QDir::Readable)) {
QFile f(dir.canonicalPath() + '/'+ entry);
bool r = f.copy(d->resourceLocation + '/' + folder + '/' + entry);
if (!r) {
d->errorMessages << "Could not copy resource" << f.fileName() << "to the resource folder";
d->errorMessages << i18n("Could not copy resource %1 to the resource folder").arg(f.fileName());
}
}
}
......@@ -171,11 +159,40 @@ KisResourceLocator::LocatorError KisResourceLocator::firstTimeInstallation(Inita
f.write(KritaVersionWrapper::versionString().toUtf8());
f.close();
if (!initializeDb()) {
return LocatorError::CannotInitializeDb;
}
return LocatorError::Ok;
}
bool KisResourceLocator::initializeDb()
{
QStringList filters = QStringList() << "*.bundle" << "*.abr" << "*.asl";
QDirIterator iter(d->resourceLocation, filters, QDir::Files, QDirIterator::Subdirectories);
while (iter.hasNext()) {
iter.next();
KisResourceStorageSP storage = QSharedPointer<KisResourceStorage>::create(iter.filePath());
if (!KisResourceCacheDb::addStorage(storage, true)) {
d->errorMessages.append(i18n("Could not add storage %1 to the cache database").arg(iter.filePath()));
return false;
}
Q_FOREACH(const QString &folder, KisResourceLoaderRegistry::instance()->resourceFolders()) {
if (!KisResourceCacheDb::addResources(storage, folder)) {
d->errorMessages.append(i18n("Could not add resource type %1 to the cache database").arg(folder));
return false;
}
}
}
KisResourceCacheDb::addStorage(QSharedPointer<KisResourceStorage>::create(d->resourceLocation), false);
return true;
}
void KisResourceLocator::findStorages()
{
d->storages.clear();
// Add the folder
d->storages.append(QSharedPointer<KisResourceStorage>::create(d->resourceLocation));
......@@ -186,14 +203,20 @@ void KisResourceLocator::findStorages()
iter.next();
d->storages.append(QSharedPointer<KisResourceStorage>::create(iter.filePath()));
}
}
QList<KisResourceStorageSP> KisResourceLocator::storages() const
{
return d->storages;
}
bool KisResourceLocator::synchronizeDb()
{
d->errorMessages.clear();
Q_FOREACH(const KisResourceStorageSP storage, d->storages) {
if (!KisResourceCacheDb::synchronize(storage)) {
d->errorMessages.append(i18n("Could not synchronize %1 with the database").arg(storage->location()));
}
}
return true;
return d->errorMessages.isEmpty();
}
......@@ -27,6 +27,7 @@
#include <kritaresources_export.h>
#include <KisResourceStorage.h>
/**
* The KisResourceLocator class is used to find resources of
......@@ -38,7 +39,6 @@ class KRITARESOURCES_EXPORT KisResourceLocator : public QObject
public:
static const QString resourceLocationKey;
static const QStringList resourceTypeFolders;
static KisResourceLocator *instance();
......@@ -47,7 +47,8 @@ public:
enum class LocatorError {
Ok,
LocationReadOnly,
CannotCreateLocation
CannotCreateLocation,
CannotInitializeDb
};
/**
......@@ -64,6 +65,8 @@ public:
private:
friend class TestResourceLocator;
KisResourceLocator(QObject *parent);
KisResourceLocator(const KisResourceLocator&);
KisResourceLocator operator=(const KisResourceLocator&);
......@@ -77,8 +80,10 @@ private:
};
LocatorError firstTimeInstallation(InitalizationStatus initalizationStatus, const QString &installationResourcesLocation);
void findStorages();
bool initializeDb();
void findStorages();
QList<KisResourceStorageSP> storages() const;
class Private;
QScopedPointer<Private> d;
......
......@@ -25,6 +25,7 @@
class KisResourceStorage::Private {
public:
QString name;
QString location;
bool valid {false};
KisResourceStorage::StorageType storageType {KisResourceStorage::StorageType::Unknown};
......@@ -37,6 +38,7 @@ KisResourceStorage::KisResourceStorage(const QString &location)
d->location = location;
QFileInfo fi(d->location);
if (fi.isDir()) {
d->name = location;
d->storageType = StorageType::Folder;
d->valid = fi.isWritable();
}
......@@ -61,6 +63,11 @@ KisResourceStorage::~KisResourceStorage()
{
}
QString KisResourceStorage::name() const
{
return d->name;
}
QString KisResourceStorage::location() const
{
return d->location;
......@@ -71,6 +78,11 @@ KisResourceStorage::StorageType KisResourceStorage::type() const
return d->storageType;
}
QDateTime KisResourceStorage::timestamp() const
{
return QFileInfo(d->location).lastModified();
}
KoResourceSP KisResourceStorage::resource(const QString &url)
{
return 0;
......
......@@ -45,20 +45,22 @@ public:
QDateTime lastModified;
};
enum class StorageType {
Unknown,
Folder,
Bundle,
AdobeBrushLibrary,
AdobeStyleLibrary
enum class StorageType : int {
Unknown = 0,
Folder = 1,
Bundle = 2,
AdobeBrushLibrary = 3,
AdobeStyleLibrary = 4
};
KisResourceStorage(const QString &location);
~KisResourceStorage();
QString name() const;
QString location() const;
bool valid() const;
StorageType type() const;
QDateTime timestamp() const;
KoResourceSP resource(const QString &url);
QVector<KoResourceSP> resources(const QString &resourceType);
......
......@@ -55,7 +55,7 @@ KoResource::~KoResource()
KoResource::KoResource(const KoResource &rhs)
: d(new Private(*rhs.d))
{
qDebug() << ">>>>>>>>>>>>>>>>>>" << filename() << name() << valid();
qDebug() << "Copying a resource!" << filename() << name() << valid();
}
bool KoResource::saveToDevice(QIODevice *dev) const
......
......@@ -14,5 +14,6 @@
<file alias="create_versioned_resources.sql">sql/create_versioned_resources.sql</file>
<file alias="create_resource_tags.sql">sql/create_resource_tags.sql</file>
<file alias="get_version_information.sql">sql/get_version_information.sql</file>
<file alias="create_index_storages.sql">sql/create_index_storages.sql</file>
</qresource>
</RCC>
CREATE UNIQUE INDEX location ON storages(location);
CREATE TABLE IF NOT EXISTS storages (
id INTEGER PRIMARY KEY
, origin_type_id INTEGER
, name TEXT
, location TEXT
, datestamp TEXT
, checksum TEXT
, datestamp INTEGER
, pre_installed INTEGER
, active INTEGER
, FOREIGN KEY(origin_type_id) REFERENCES origin_types(id)
......
......@@ -22,14 +22,18 @@
#include <QTest>
#include <QVersionNumber>
#include <QDirIterator>
#include <QSqlError>
#include <QSqlQuery>
#include <kconfig.h>
#include <kconfiggroup.h>
#include <ksharedconfig.h>
#include <KritaVersionWrapper.h>
#include <KisResourceCacheDb.h>
#include <KisResourceLocator.h>
#include <KisResourceLoaderRegistry.h>
#ifndef FILES_DATA_DIR
#error "FILES_DATA_DIR not set. A directory with the data used for testing installing resources"
......@@ -39,8 +43,22 @@
#error "FILES_DEST_DIR not set. A directory where data will be written to for testing installing resources"
#endif
class Dummy : public KoResource {
public:
Dummy(const QString &f) : KoResource(f) {}
bool load() override { return true; }
bool loadFromDevice(QIODevice *) override { return true; }
bool save() override { return true; }
};
void TestResourceLocator::initTestCase()
{
QDir dbLocation(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
if (dbLocation.exists()) {
QFile(dbLocation.path() + "/" + KisResourceCacheDb::resourceCacheDbFilename).remove();
dbLocation.rmpath(dbLocation.path());
}
m_locator = KisResourceLocator::instance();
m_srcLocation = QString(FILES_DATA_DIR);
QVERIFY2(QDir(m_srcLocation).exists(), m_srcLocation.toUtf8());
......@@ -48,15 +66,33 @@ void TestResourceLocator::initTestCase()
cleanDstLocation();
KConfigGroup cfg(KSharedConfig::openConfig(), "");
cfg.writeEntry(KisResourceLocator::resourceLocationKey, m_dstLocation);
const QStringList resourceTypeFolders = QStringList()
<< "tags"
<< "asl"
<< "bundles"
<< "brushes"
<< "gradients"
<< "paintoppresets"
<< "palettes"
<< "patterns"
<< "taskset"
<< "workspaces"
<< "symbols";
Q_FOREACH(const QString &folder, resourceTypeFolders) {
KisResourceLoaderRegistry::instance()->add(folder, new KisResourceLoader<Dummy>("dummy" + folder, folder, QStringList() << "x-dummy"));
}
}
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, KisResourceLocator::resourceTypeFolders) {
Q_FOREACH(const QString &folder, KisResourceLoaderRegistry::instance()->resourceFolders()) {
QDir dstDir(m_dstLocation + '/' + folder + '/');
QDir srcDir(m_srcLocation + '/' + folder + '/');
......@@ -69,6 +105,20 @@ void TestResourceLocator::testLocatorInitalization()
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()
......@@ -78,6 +128,12 @@ void TestResourceLocator::testLocatorSynchronization()
void TestResourceLocator::cleanupTestCase()
{
QDir dbLocation(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
bool res = QFile(dbLocation.path() + "/" + KisResourceCacheDb::resourceCacheDbFilename).remove();
Q_ASSERT(res);
res = dbLocation.rmpath(dbLocation.path());
Q_ASSERT(res);
cleanDstLocation();
}
......
......@@ -31,6 +31,7 @@ class TestResourceLocator : public QObject
private Q_SLOTS:
void initTestCase();
void testLocatorInitalization();
void testStorageInitialization();
void testLocatorSynchronization();
void cleanupTestCase();
private:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment