diff --git a/libs/resources/CMakeLists.txt b/libs/resources/CMakeLists.txt index e29b62e0bc..9c9cfe8446 100644 --- a/libs/resources/CMakeLists.txt +++ b/libs/resources/CMakeLists.txt @@ -1,40 +1,40 @@ add_subdirectory(tests) set(kritaresources_LIB_SRCS KisResourceCacheDb.cpp KisResourceLoader.cpp KisResourceLoaderRegistry.cpp KisResourceLocator.cpp KisResourceStorage.cpp KoResource.cpp KoMD5Generator.cpp KoHashGeneratorProvider.cpp KoResourcePaths.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 PRIVATE + Qt5::Sql kritaversion kritaglobal - Qt5::Sql KF5::ConfigCore KF5::CoreAddons KF5::I18n KF5::Archive ) 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/KisResourceCacheDb.cpp b/libs/resources/KisResourceCacheDb.cpp index d5b2cd88e7..8f07d25822 100644 --- a/libs/resources/KisResourceCacheDb.cpp +++ b/libs/resources/KisResourceCacheDb.cpp @@ -1,253 +1,236 @@ /* * 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 "KisResourceCacheDb.h" #include #include #include #include #include #include #include "KisResourceLocator.h" const QString dbDriver = "QSQLITE"; const QStringList KisResourceCacheDb::resourceTypes = QStringList() << "BRUSH_TIP" << "GRADIENT" << "PAINTOP_PRESET" << "COLORSET" << "PATTERN" << "SYMBOL_LIBRARY" << "TEMPLATE" << "WORKSPACE" << "SESSION" << "UNKNOWN"; const QStringList KisResourceCacheDb::storageTypes = QStringList() << "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"}; const QString KisResourceCacheDb::databaseVersion {"0.0.1"}; +bool KisResourceCacheDb::s_valid {false}; - -class KisResourceCacheDb::Private -{ -public: - - bool valid {false}; - - QSqlError initDb(const QString &location); -}; - -KisResourceCacheDb::KisResourceCacheDb() - : d(new Private()) -{ -} - -KisResourceCacheDb::~KisResourceCacheDb() -{ -} - -bool KisResourceCacheDb::isValid() const +bool KisResourceCacheDb::isValid() { - return d->valid; + return s_valid; } -bool KisResourceCacheDb::initialize(const QString &location) const -{ - QSqlError err = d->initDb(location); - if (err.isValid()) { - qWarning() << "Could not initialize the database:" << err; - } - d->valid = !err.isValid(); - - return d->valid; -} -QSqlError KisResourceCacheDb::Private::initDb(const QString &location) +QSqlError initDb(const QString &location) { if (!QSqlDatabase::connectionNames().isEmpty()) { infoResources << "Already connected to resource cache database"; return QSqlError(); } QDir dbLocation(location); if (!dbLocation.exists()) { dbLocation.mkpath(dbLocation.path()); } QSqlDatabase db = QSqlDatabase::addDatabase(dbDriver); - db.setDatabaseName(location + "/" + resourceCacheDbFilename); + db.setDatabaseName(location + "/" + KisResourceCacheDb::resourceCacheDbFilename); if (!db.open()) { infoResources << "Could not connect to resource cache database"; return db.lastError(); } QStringList tables = QStringList() << "version_information" << "origin_types" << "resource_types" << "storages" << "tags" << "resources" << "translations" << "versioned_resources" << "resource_tags"; QStringList dbTables; // Verify whether we should recreate the database { bool allTablesPresent = true; dbTables = db.tables(); Q_FOREACH(const QString &table, tables) { if (!dbTables.contains(table)) { allTablesPresent = false; } } bool schemaIsOutDated = false; if (dbTables.contains("version_information")) { // Verify the version number QFile f(":/get_version_information.sql"); if (f.open(QFile::ReadOnly)) { QSqlQuery query(f.readAll()); if (query.size() > 0) { query.first(); QString schemaVersion = query.value(0).toString(); QString kritaVersion = query.value(1).toString(); QString creationDate = query.value(2).toString(); infoResources << "Database version" << schemaVersion << "Krita version that created the database" << kritaVersion << "At" << creationDate; - if (schemaVersion != databaseVersion) { + if (schemaVersion != KisResourceCacheDb::databaseVersion) { // XXX: Implement migration warnResources << "Database schema is outdated, migration is needed"; schemaIsOutDated = true; } } } else { return QSqlError("Error executing SQL", "Could not open get_version_information.sql", QSqlError::StatementError); } } if (allTablesPresent && !schemaIsOutDated) { infoResources << "All tables are present and up to date"; return QSqlError(); } } Q_FOREACH(const QString &table, tables) { QFile f(":/create_" + table + ".sql"); if (f.open(QFile::ReadOnly)) { QSqlQuery query; if (!query.exec(f.readAll())) { qWarning() << "Could not create table" << table; return db.lastError(); } infoResources << "Created table" << table; } else { return QSqlError("Error executing SQL", QString("Could not find SQL file %1").arg(table), QSqlError::StatementError); } } { if (dbTables.contains("origin_types")) { QSqlQuery query; if (!query.exec("DELETE * FROM origin_types;")) { qWarning() << "Could not clear table origin_types" << db.lastError(); } } QFile f(":/fill_origin_types.sql"); if (f.open(QFile::ReadOnly)) { QString sql = f.readAll(); - Q_FOREACH(const QString &originType, storageTypes) { + Q_FOREACH(const QString &originType, KisResourceCacheDb::storageTypes) { QSqlQuery query(sql); query.addBindValue(originType); if (!query.exec()) { qWarning() << "Could not insert" << originType << db.lastError() << query.executedQuery(); return db.lastError(); } } infoResources << "Filled lookup table origin_types"; } else { return QSqlError("Error executing SQL", QString("Could not find SQL fill_origin_types.sql."), QSqlError::StatementError); } } { if (dbTables.contains("resource_types")) { QSqlQuery query; if (!query.exec("DELETE * FROM resource_types;")) { qWarning() << "Could not cleare table resource_types" << db.lastError(); } } QFile f(":/fill_resource_types.sql"); if (f.open(QFile::ReadOnly)) { QString sql = f.readAll(); - Q_FOREACH(const QString &resourceType, resourceTypes) { + Q_FOREACH(const QString &resourceType, KisResourceCacheDb::resourceTypes) { QSqlQuery query(sql); query.addBindValue(resourceType); if (!query.exec()) { qWarning() << "Could not insert" << resourceType << db.lastError() << query.executedQuery(); return db.lastError(); } } infoResources << "Filled lookup table resource_types"; } else { return QSqlError("Error executing SQL", QString("Could not find SQL fill_resource_types.sql."), QSqlError::StatementError); } } { QFile f(":/fill_version_information.sql"); if (f.open(QFile::ReadOnly)) { QString sql = f.readAll(); QSqlQuery query; query.prepare(sql); - query.addBindValue(databaseVersion); + query.addBindValue(KisResourceCacheDb::databaseVersion); query.addBindValue(KritaVersionWrapper::versionString()); query.addBindValue(QDateTime::currentDateTimeUtc().toString()); if (!query.exec()) { qWarning() << "Could not insert the current version" << db.lastError() << query.executedQuery() << query.boundValues(); return db.lastError(); } infoResources << "Filled version table"; } else { return QSqlError("Error executing SQL", QString("Could not find SQL fill_version_information.sql."), QSqlError::StatementError); } } return QSqlError(); } + +bool KisResourceCacheDb::initialize(const QString &location) +{ + QSqlError err = initDb(location); + if (err.isValid()) { + qWarning() << "Could not initialize the database:" << err; + } + s_valid = !err.isValid(); + + return s_valid; +} diff --git a/libs/resources/KisResourceCacheDb.h b/libs/resources/KisResourceCacheDb.h index 0b2930974b..8900392cc1 100644 --- a/libs/resources/KisResourceCacheDb.h +++ b/libs/resources/KisResourceCacheDb.h @@ -1,72 +1,65 @@ /* * 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 KISRESOURCECACHEDB_H #define KISRESOURCECACHEDB_H #include -#include #include /** * @brief The KisResourceCacheDb class encapsulates the database that * caches information about the resources available to the user. * * KisApplication creates and initializes the database. All other methods * are static and can be used from anywhere. */ class KRITARESOURCES_EXPORT KisResourceCacheDb { public: static const QString dbLocationKey; ///< configuration key for the location of the database static const QString resourceCacheDbFilename; ///< filename of the database static const QString databaseVersion; ///< current schema version static const QStringList resourceTypes; ///< all types of resources static const QStringList storageTypes; ///< kinds of places where resources can be stored - /** - * @brief KisResourceCacheDb create a resource cache database. - */ - explicit KisResourceCacheDb(); - ~KisResourceCacheDb(); - /** * @brief isValid * @return true if the database has been correctly created, false if the database cannot be used */ - bool isValid() const; + static bool isValid(); /** * @brief initialize * @param location the location of the database * @return true if the database has been initialized correctly */ - bool initialize(const QString &location) const; + static bool initialize(const QString &location); private: + explicit KisResourceCacheDb(); + ~KisResourceCacheDb(); - class Private; - QScopedPointer d; - + static bool s_valid; }; #endif // KISRESOURCECACHEDB_H diff --git a/libs/resources/KisResourceLocator.cpp b/libs/resources/KisResourceLocator.cpp index 50e69f01b7..d2e5944bf7 100644 --- a/libs/resources/KisResourceLocator.cpp +++ b/libs/resources/KisResourceLocator.cpp @@ -1,192 +1,199 @@ /* * 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 "KoResourcePaths.h" #include "KisResourceStorage.h" #include "KisResourceCacheDb.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; QList storages; QStringList errorMessages; }; 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; } - // Add the folder - d->storages.append(QSharedPointer::create(d->resourceLocation)); - - // 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(); - d->storages.append(QSharedPointer::create(iter.filePath())); - } + findStorages(); return LocatorError::Ok; } QStringList KisResourceLocator::errorMessages() const { return d->errorMessages; } KisResourceLocator::LocatorError KisResourceLocator::firstTimeInstallation(InitalizationStatus initalizationStatus, const QString &installationResourcesLocation) { Q_UNUSED(initalizationStatus); Q_FOREACH(const QString &folder, resourceTypeFolders) { 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, resourceTypeFolders) { 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"; } } } } QFile f(d->resourceLocation + '/' + "KRITA_RESOURCE_VERSION"); f.open(QFile::WriteOnly); f.write(KritaVersionWrapper::versionString().toUtf8()); f.close(); return LocatorError::Ok; } +void KisResourceLocator::findStorages() +{ + // Add the folder + d->storages.append(QSharedPointer::create(d->resourceLocation)); + + // 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(); + d->storages.append(QSharedPointer::create(iter.filePath())); + } + + +} + bool KisResourceLocator::synchronizeDb() { Q_FOREACH(const KisResourceStorageSP storage, d->storages) { - qDebug() << "Storage" << storage->location() << storage->valid(); + } return true; } diff --git a/libs/resources/KisResourceLocator.h b/libs/resources/KisResourceLocator.h index c5bc24920b..1ffa87e452 100644 --- a/libs/resources/KisResourceLocator.h +++ b/libs/resources/KisResourceLocator.h @@ -1,87 +1,87 @@ /* * 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 /** * The KisResourceLocator class is used to find resources of * a certain type. */ class KRITARESOURCES_EXPORT KisResourceLocator : public QObject { Q_OBJECT public: static const QString resourceLocationKey; static const QStringList resourceTypeFolders; static KisResourceLocator *instance(); ~KisResourceLocator(); enum class LocatorError { Ok, LocationReadOnly, CannotCreateLocation }; /** * @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); QStringList errorMessages() const; bool synchronizeDb(); private: 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); - + void findStorages(); class Private; QScopedPointer d; }; #endif // KISRESOURCELOCATOR_H diff --git a/libs/resources/tests/TestResourceCacheDb.cpp b/libs/resources/tests/TestResourceCacheDb.cpp index 9539c66f2d..804c6b215c 100644 --- a/libs/resources/tests/TestResourceCacheDb.cpp +++ b/libs/resources/tests/TestResourceCacheDb.cpp @@ -1,92 +1,91 @@ /* * 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 "TestResourceCacheDb.h" #include #include #include #include #include void TestResourceCacheDb::initTestCase() { QDir dbLocation(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); if (dbLocation.exists()) { QFile(dbLocation.path() + "/" + KisResourceCacheDb::resourceCacheDbFilename).remove(); dbLocation.rmpath(dbLocation.path()); } } void TestResourceCacheDb::testCreateDatabase() { - KisResourceCacheDb cacheDb; - bool res = cacheDb.initialize(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); + bool res = KisResourceCacheDb::initialize(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); QVERIFY(res); - QVERIFY(cacheDb.isValid()); + QVERIFY(KisResourceCacheDb::isValid()); QSqlDatabase sqlDb = QSqlDatabase::database(); QStringList tables = QStringList() << "version_information" << "origin_types" << "resource_types" << "storages" << "tags" << "resources" << "translations" << "versioned_resources" << "resource_tags"; QStringList dbTables = sqlDb.tables(); Q_FOREACH(const QString &table, tables) { QVERIFY2(dbTables.contains(table), table.toLatin1()); } - res = cacheDb.initialize(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); + res = KisResourceCacheDb::initialize(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); QVERIFY(res); - QVERIFY(cacheDb.isValid()); + QVERIFY(KisResourceCacheDb::isValid()); } void TestResourceCacheDb::testLookupTables() { QSqlQuery query; bool r = query.exec("SELECT COUNT(*) FROM origin_types"); QVERIFY(r); QVERIFY(query.lastError() == QSqlError()); query.first(); QVERIFY(query.value(0).toInt() == KisResourceCacheDb::storageTypes.count()); r = query.exec("SELECT COUNT(*) FROM resource_types"); QVERIFY(r); QVERIFY(query.lastError() == QSqlError()); query.first(); QVERIFY(query.value(0).toInt() == KisResourceCacheDb::resourceTypes.count()); } void TestResourceCacheDb::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); } QTEST_MAIN(TestResourceCacheDb) diff --git a/libs/ui/KisApplication.cpp b/libs/ui/KisApplication.cpp index 6cabd29afd..23a3a42a14 100644 --- a/libs/ui/KisApplication.cpp +++ b/libs/ui/KisApplication.cpp @@ -1,893 +1,906 @@ /* * Copyright (C) 1998, 1999 Torben Weis * Copyright (C) 2012 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 "KisApplication.h" #include #ifdef Q_OS_WIN #include #include #endif #ifdef Q_OS_OSX #include "osx.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KoConfig.h" #include #include #include #include "thememanager.h" #include "KisPrintJob.h" #include "KisDocument.h" #include "KisMainWindow.h" #include "KisAutoSaveRecoveryDialog.h" #include "KisPart.h" #include #include "kis_md5_generator.h" #include "kis_splash_screen.h" #include "kis_config.h" #include "flake/kis_shape_selection.h" #include #include #include #include #include #include #include #include "kisexiv2/kis_exiv2.h" #include "KisApplicationArguments.h" #include #include "kis_action_registry.h" #include #include #include #include "kis_image_barrier_locker.h" #include "opengl/kis_opengl.h" #include "kis_spin_box_unit_manager.h" #include "kis_document_aware_spin_box_unit_manager.h" #include "KisViewManager.h" #include "kis_workspace_resource.h" #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { const QTime appStartTime(QTime::currentTime()); } class KisApplication::Private { public: Private() {} QPointer splashScreen; KisAutoSaveRecoveryDialog *autosaveDialog {0}; QPointer mainWindow; // The first mainwindow we create on startup bool batchRun {false}; }; class KisApplication::ResetStarting { public: ResetStarting(KisSplashScreen *splash, int fileCount) : m_splash(splash) , m_fileCount(fileCount) { } ~ResetStarting() { if (m_splash) { KConfigGroup cfg( KSharedConfig::openConfig(), "SplashScreen"); bool hideSplash = cfg.readEntry("HideSplashAfterStartup", false); if (m_fileCount > 0 || hideSplash) { m_splash->hide(); } else { m_splash->setWindowFlags(Qt::Dialog); QRect r(QPoint(), m_splash->size()); m_splash->move(QApplication::desktop()->availableGeometry().center() - r.center()); m_splash->setWindowTitle(qAppName()); m_splash->setParent(0); Q_FOREACH (QObject *o, m_splash->children()) { QWidget *w = qobject_cast(o); if (w && w->isHidden()) { w->setVisible(true); } } m_splash->show(); m_splash->activateWindow(); } } } QPointer m_splash; int m_fileCount; }; KisApplication::KisApplication(const QString &key, int &argc, char **argv) : QtSingleApplication(key, argc, argv) , d(new Private) { #ifdef Q_OS_OSX setMouseCoalescingEnabled(false); #endif QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath()); setApplicationDisplayName("Krita"); setApplicationName("krita"); // Note: Qt docs suggest we set this, but if we do, we get resource paths of the form of krita/krita, which is weird. // setOrganizationName("krita"); setOrganizationDomain("krita.org"); QString version = KritaVersionWrapper::versionString(true); setApplicationVersion(version); setWindowIcon(KisIconUtils::loadIcon("calligrakrita")); if (qgetenv("KRITA_NO_STYLE_OVERRIDE").isEmpty()) { QStringList styles = QStringList() << "breeze" << "fusion" << "plastique"; if (!styles.contains(style()->objectName().toLower())) { Q_FOREACH (const QString & style, styles) { if (!setStyle(style)) { qDebug() << "No" << style << "available."; } else { qDebug() << "Set style" << style; break; } } } } else { qDebug() << "Style override disabled, using" << style()->objectName(); } KisOpenGL::initialize(); } #if defined(Q_OS_WIN) && defined(ENV32BIT) typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); LPFN_ISWOW64PROCESS fnIsWow64Process; BOOL isWow64() { BOOL bIsWow64 = FALSE; //IsWow64Process is not available on all supported versions of Windows. //Use GetModuleHandle to get a handle to the DLL that contains the function //and GetProcAddress to get a pointer to the function if available. fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( GetModuleHandle(TEXT("kernel32")),"IsWow64Process"); if(0 != fnIsWow64Process) { if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) { //handle error } } return bIsWow64; } #endif void KisApplication::initializeGlobals(const KisApplicationArguments &args) { int dpiX = args.dpiX(); int dpiY = args.dpiY(); if (dpiX > 0 && dpiY > 0) { KoDpi::setDPI(dpiX, dpiY); } } void KisApplication::addResourceTypes() { // qDebug() << "addResourceTypes();"; // All Krita's resource types KoResourcePaths::addResourceType("kis_pics", "data", "/pics/"); KoResourcePaths::addResourceType("kis_images", "data", "/images/"); KoResourcePaths::addResourceType("icc_profiles", "data", "/profiles/"); KoResourcePaths::addResourceType("metadata_schema", "data", "/metadata/schemas/"); KoResourcePaths::addResourceType("kis_brushes", "data", "/brushes/"); KoResourcePaths::addResourceType("kis_taskset", "data", "/taskset/"); KoResourcePaths::addResourceType("kis_taskset", "data", "/taskset/"); KoResourcePaths::addResourceType("gmic_definitions", "data", "/gmic/"); KoResourcePaths::addResourceType("kis_resourcebundles", "data", "/bundles/"); KoResourcePaths::addResourceType("kis_defaultpresets", "data", "/defaultpresets/"); KoResourcePaths::addResourceType("kis_paintoppresets", "data", "/paintoppresets/"); KoResourcePaths::addResourceType("kis_workspaces", "data", "/workspaces/"); KoResourcePaths::addResourceType("kis_windowlayouts", "data", "/windowlayouts/"); KoResourcePaths::addResourceType("kis_sessions", "data", "/sessions/"); KoResourcePaths::addResourceType("psd_layer_style_collections", "data", "/asl"); KoResourcePaths::addResourceType("ko_patterns", "data", "/patterns/", true); KoResourcePaths::addResourceType("ko_gradients", "data", "/gradients/"); KoResourcePaths::addResourceType("ko_gradients", "data", "/gradients/", true); KoResourcePaths::addResourceType("ko_palettes", "data", "/palettes/", true); KoResourcePaths::addResourceType("kis_shortcuts", "data", "/shortcuts/"); KoResourcePaths::addResourceType("kis_actions", "data", "/actions"); KoResourcePaths::addResourceType("icc_profiles", "data", "/color/icc"); KoResourcePaths::addResourceType("ko_effects", "data", "/effects/"); KoResourcePaths::addResourceType("tags", "data", "/tags/"); KoResourcePaths::addResourceType("templates", "data", "/templates"); KoResourcePaths::addResourceType("pythonscripts", "data", "/pykrita"); KoResourcePaths::addResourceType("symbols", "data", "/symbols"); KoResourcePaths::addResourceType("preset_icons", "data", "/preset_icons"); // // Extra directories to look for create resources. (Does anyone actually use that anymore?) // KoResourcePaths::addResourceDir("ko_gradients", "/usr/share/create/gradients/gimp"); // KoResourcePaths::addResourceDir("ko_gradients", QDir::homePath() + QString("/.create/gradients/gimp")); // KoResourcePaths::addResourceDir("ko_patterns", "/usr/share/create/patterns/gimp"); // KoResourcePaths::addResourceDir("ko_patterns", QDir::homePath() + QString("/.create/patterns/gimp")); // KoResourcePaths::addResourceDir("kis_brushes", "/usr/share/create/brushes/gimp"); // KoResourcePaths::addResourceDir("kis_brushes", QDir::homePath() + QString("/.create/brushes/gimp")); // KoResourcePaths::addResourceDir("ko_palettes", "/usr/share/create/swatches"); // KoResourcePaths::addResourceDir("ko_palettes", QDir::homePath() + QString("/.create/swatches")); // Make directories for all resources we can save, and tags QDir d; d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tags/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/asl/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/bundles/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/brushes/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/gradients/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/paintoppresets/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/palettes/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/patterns/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/taskset/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/workspaces/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/input/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/pykrita/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/symbols/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/color-schemes/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/preset_icons/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/preset_icons/tool_icons/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/preset_icons/emblem_icons/"); // Indicate that it is now safe for users of KoResourcePaths to load resources KoResourcePaths::setReady(); } void KisApplication::loadResources() { KisResourceLoaderRegistry *reg = KisResourceLoaderRegistry::instance(); reg->add(new KisResourceLoader("paintoppresets", "paintoppresets", QStringList() << "application/x-krita-paintoppreset")); reg->add(new KisResourceLoader("resourcebundles", "bundles", QStringList() << "application/x-krita-bundle")); reg->add(new KisResourceLoader("gbr_brushes", "brushes", QStringList() << "image/x-gimp-brush")); reg->add(new KisResourceLoader("gih_brushes", "brushes", QStringList() << "image/x-gimp-brush-animated")); reg->add(new KisResourceLoader("svg_brushes", "brushes", QStringList() << "image/svg+xml")); reg->add(new KisResourceLoader("png_brushes", "brushes", QStringList() << "image/png")); reg->add(new KisResourceLoader("segmented_gradients", "gradients", QStringList() << "application/x-gimp-gradient")); reg->add(new KisResourceLoader("stop_gradients", "gradients", QStringList() << "application/x-karbon-gradient" << "image/svg+xml")); reg->add(new KisResourceLoader("palettes", "palettes", QStringList() << KisMimeDatabase::mimeTypeForSuffix("kpl") << KisMimeDatabase::mimeTypeForSuffix("gpl") << KisMimeDatabase::mimeTypeForSuffix("pal") << KisMimeDatabase::mimeTypeForSuffix("act") << KisMimeDatabase::mimeTypeForSuffix("aco") << KisMimeDatabase::mimeTypeForSuffix("css") << KisMimeDatabase::mimeTypeForSuffix("colors") << KisMimeDatabase::mimeTypeForSuffix("xml") << KisMimeDatabase::mimeTypeForSuffix("sbz"))); QList src = QImageReader::supportedMimeTypes(); QStringList allImageMimes; Q_FOREACH(const QByteArray ba, src) { allImageMimes << QString::fromUtf8(ba); } reg->add(new KisResourceLoader("patterns", "patterns", allImageMimes)); reg->add(new KisResourceLoader("workspaces", "workspaces", QStringList() << "application/x-krita-workspace")); reg->add(new KisResourceLoader("symbols", "symbols", QStringList() << "image/svg+xml")); reg->add(new KisResourceLoader("windowlayouts", "sessions", QStringList() << "application/x-krita-windowlayout")); reg->add(new KisResourceLoader("sessions", "sessions", QStringList() << "application/x-krita-session")); - qDebug() << "loadResources()" << reg->keys(); + KisResourceLocator::LocatorError r = KisResourceLocator::instance()->initialize(KoResourcePaths::getApplicationRoot() + "/share/krita"); + if (r != KisResourceLocator::LocatorError::Ok ) { + QMessageBox::critical(0, i18nc("@title:window", "Krita: Fatal error"), KisResourceLocator::instance()->errorMessages().join('\n')); + qApp->quit(); + } + + KisResourceCacheDb::initialize(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); + + if (!KisResourceLocator::instance()->synchronizeDb()) { + QMessageBox::critical(0, i18nc("@title:window", "Krita: Fatal error"), KisResourceLocator::instance()->errorMessages().join('\n')); + qApp->quit(); + } + setSplashScreenLoadingText(i18n("Loading Resources...")); processEvents(); KoResourceServerProvider::instance(); setSplashScreenLoadingText(i18n("Loading Brush Presets...")); processEvents(); KisResourceServerProvider::instance(); setSplashScreenLoadingText(i18n("Loading Brushes...")); processEvents(); KisBrushServer::instance()->brushServer(); setSplashScreenLoadingText(i18n("Loading Bundles...")); processEvents(); KisResourceBundleServerProvider::instance(); } void KisApplication::loadResourceTags() { // qDebug() << "loadResourceTags()"; KoResourceServerProvider::instance()->patternServer()->loadTags(); KoResourceServerProvider::instance()->gradientServer()->loadTags(); KoResourceServerProvider::instance()->paletteServer()->loadTags(); KoResourceServerProvider::instance()->svgSymbolCollectionServer()->loadTags(); KisBrushServer::instance()->brushServer()->loadTags(); KisResourceServerProvider::instance()->workspaceServer()->loadTags(); KisResourceServerProvider::instance()->layerStyleCollectionServer()->loadTags(); KisResourceBundleServerProvider::instance()->resourceBundleServer()->loadTags(); KisResourceServerProvider::instance()->paintOpPresetServer()->loadTags(); KisResourceServerProvider::instance()->paintOpPresetServer()->clearOldSystemTags(); } void KisApplication::loadPlugins() { // qDebug() << "loadPlugins();"; KoShapeRegistry* r = KoShapeRegistry::instance(); r->add(new KisShapeSelectionFactory()); KisActionRegistry::instance(); KisFilterRegistry::instance(); KisGeneratorRegistry::instance(); KisPaintOpRegistry::instance(); KoColorSpaceRegistry::instance(); } void KisApplication::loadGuiPlugins() { // qDebug() << "loadGuiPlugins();"; // Load the krita-specific tools setSplashScreenLoadingText(i18n("Loading Plugins for Krita/Tool...")); processEvents(); // qDebug() << "loading tools"; KoPluginLoader::instance()->load(QString::fromLatin1("Krita/Tool"), QString::fromLatin1("[X-Krita-Version] == 28")); // Load dockers setSplashScreenLoadingText(i18n("Loading Plugins for Krita/Dock...")); processEvents(); // qDebug() << "loading dockers"; KoPluginLoader::instance()->load(QString::fromLatin1("Krita/Dock"), QString::fromLatin1("[X-Krita-Version] == 28")); // XXX_EXIV: make the exiv io backends real plugins setSplashScreenLoadingText(i18n("Loading Plugins Exiv/IO...")); processEvents(); // qDebug() << "loading exiv2"; KisExiv2::initialize(); } bool KisApplication::start(const KisApplicationArguments &args) { KisConfig cfg; #if defined(Q_OS_WIN) #ifdef ENV32BIT if (isWow64() && !cfg.readEntry("WarnedAbout32Bits", false)) { QMessageBox::information(0, i18nc("@title:window", "Krita: Warning"), i18n("You are running a 32 bits build on a 64 bits Windows.\n" "This is not recommended.\n" "Please download and install the x64 build instead.")); cfg.writeEntry("WarnedAbout32Bits", true); } #endif #endif QString opengl = cfg.canvasState(); if (opengl == "OPENGL_NOT_TRIED" ) { cfg.setCanvasState("TRY_OPENGL"); } else if (opengl != "OPENGL_SUCCESS") { cfg.setCanvasState("OPENGL_FAILED"); } setSplashScreenLoadingText(i18n("Initializing Globals")); processEvents(); initializeGlobals(args); const bool doNewImage = args.doNewImage(); const bool doTemplate = args.doTemplate(); const bool exportAs = args.exportAs(); const QString exportFileName = args.exportFileName(); d->batchRun = (exportAs || !exportFileName.isEmpty()); const bool needsMainWindow = !exportAs; // only show the mainWindow when no command-line mode option is passed bool showmainWindow = !exportAs; // would be !batchRun; const bool showSplashScreen = !d->batchRun && qEnvironmentVariableIsEmpty("NOSPLASH"); if (showSplashScreen && d->splashScreen) { d->splashScreen->show(); d->splashScreen->repaint(); processEvents(); } KoHashGeneratorProvider::instance()->setGenerator("MD5", new KisMD5Generator()); KConfigGroup group(KSharedConfig::openConfig(), "theme"); Digikam::ThemeManager themeManager; themeManager.setCurrentTheme(group.readEntry("Theme", "Krita dark")); ResetStarting resetStarting(d->splashScreen, args.filenames().count()); // remove the splash when done Q_UNUSED(resetStarting); // Make sure we can save resources and tags setSplashScreenLoadingText(i18n("Adding resource types")); processEvents(); addResourceTypes(); // Load the plugins loadPlugins(); // Load all resources loadResources(); // Load all the tags loadResourceTags(); // Load the gui plugins loadGuiPlugins(); KisPart *kisPart = KisPart::instance(); if (needsMainWindow) { // show a mainWindow asap, if we want that setSplashScreenLoadingText(i18n("Loading Main Window...")); processEvents(); bool sessionNeeded = true; auto sessionMode = cfg.sessionOnStartup(); if (!args.session().isEmpty()) { sessionNeeded = !kisPart->restoreSession(args.session()); } else if (sessionMode == KisConfig::SOS_ShowSessionManager) { showmainWindow = false; sessionNeeded = false; kisPart->showSessionManager(); } else if (sessionMode == KisConfig::SOS_PreviousSession) { KConfigGroup sessionCfg = KSharedConfig::openConfig()->group("session"); const QString &sessionName = sessionCfg.readEntry("previousSession"); sessionNeeded = !kisPart->restoreSession(sessionName); } if (sessionNeeded) { kisPart->startBlankSession(); } if (!args.windowLayout().isEmpty()) { KoResourceServer * rserver = KisResourceServerProvider::instance()->windowLayoutServer(); KisWindowLayoutResource* windowLayout = rserver->resourceByName(args.windowLayout()); if (windowLayout) { windowLayout->applyLayout(); } } if (showmainWindow) { d->mainWindow = kisPart->currentMainwindow(); if (!args.workspace().isEmpty()) { KoResourceServer * rserver = KisResourceServerProvider::instance()->workspaceServer(); KisWorkspaceResource* workspace = rserver->resourceByName(args.workspace()); if (workspace) { d->mainWindow->restoreWorkspace(workspace); } } if (args.canvasOnly()) { d->mainWindow->viewManager()->switchCanvasOnly(true); } if (args.fullScreen()) { d->mainWindow->showFullScreen(); } } else { d->mainWindow = kisPart->createMainWindow(); } } short int numberOfOpenDocuments = 0; // number of documents open // Check for autosave files that can be restored, if we're not running a batchrun (test) if (!d->batchRun) { checkAutosaveFiles(); } setSplashScreenLoadingText(QString()); // done loading, so clear out label processEvents(); //configure the unit manager KisSpinBoxUnitManagerFactory::setDefaultUnitManagerBuilder(new KisDocumentAwareSpinBoxUnitManagerBuilder()); connect(this, &KisApplication::aboutToQuit, &KisSpinBoxUnitManagerFactory::clearUnitManagerBuilder); //ensure the builder is destroyed when the application leave. //the new syntax slot syntax allow to connect to a non q_object static method. // Create a new image, if needed if (doNewImage) { KisDocument *doc = args.image(); if (doc) { kisPart->addDocument(doc); d->mainWindow->addViewAndNotifyLoadingCompleted(doc); } } // Get the command line arguments which we have to parse int argsCount = args.filenames().count(); if (argsCount > 0) { // Loop through arguments for (int argNumber = 0; argNumber < argsCount; argNumber++) { QString fileName = args.filenames().at(argNumber); // are we just trying to open a template? if (doTemplate) { // called in mix with batch options? ignore and silently skip if (d->batchRun) { continue; } if (createNewDocFromTemplate(fileName, d->mainWindow)) { ++numberOfOpenDocuments; } // now try to load } else { if (exportAs) { QString outputMimetype = KisMimeDatabase::mimeTypeForFile(exportFileName, false); if (outputMimetype == "application/octetstream") { dbgKrita << i18n("Mimetype not found, try using the -mimetype option") << endl; return 1; } KisDocument *doc = kisPart->createDocument(); doc->setFileBatchMode(d->batchRun); doc->openUrl(QUrl::fromLocalFile(fileName)); qApp->processEvents(); // For vector layers to be updated doc->setFileBatchMode(true); if (!doc->exportDocumentSync(QUrl::fromLocalFile(exportFileName), outputMimetype.toLatin1())) { dbgKrita << "Could not export " << fileName << "to" << exportFileName << ":" << doc->errorMessage(); } QTimer::singleShot(0, this, SLOT(quit())); } else if (d->mainWindow) { if (fileName.endsWith(".bundle")) { d->mainWindow->installBundle(fileName); } else { KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; if (d->mainWindow->openDocument(QUrl::fromLocalFile(fileName), flags)) { // Normal case, success numberOfOpenDocuments++; } } } } } } // fixes BUG:369308 - Krita crashing on splash screen when loading. // trying to open a file before Krita has loaded can cause it to hang and crash if (d->splashScreen) { d->splashScreen->displayLinks(true); d->splashScreen->displayRecentFiles(true); } // not calling this before since the program will quit there. return true; } KisApplication::~KisApplication() { } void KisApplication::setSplashScreen(QWidget *splashScreen) { d->splashScreen = qobject_cast(splashScreen); } void KisApplication::setSplashScreenLoadingText(QString textToLoad) { if (d->splashScreen) { //d->splashScreen->loadingLabel->setText(textToLoad); d->splashScreen->setLoadingText(textToLoad); d->splashScreen->repaint(); } } void KisApplication::hideSplashScreen() { if (d->splashScreen) { // hide the splashscreen to see the dialog d->splashScreen->hide(); } } bool KisApplication::notify(QObject *receiver, QEvent *event) { try { return QApplication::notify(receiver, event); } catch (std::exception &e) { qWarning("Error %s sending event %i to object %s", e.what(), event->type(), qPrintable(receiver->objectName())); } catch (...) { qWarning("Error sending event %i to object %s", event->type(), qPrintable(receiver->objectName())); } return false; } void KisApplication::remoteArguments(QByteArray message, QObject *socket) { Q_UNUSED(socket); // check if we have any mainwindow KisMainWindow *mw = qobject_cast(qApp->activeWindow()); if (!mw) { mw = KisPart::instance()->mainWindows().first(); } if (!mw) { return; } KisApplicationArguments args = KisApplicationArguments::deserialize(message); const bool doTemplate = args.doTemplate(); const int argsCount = args.filenames().count(); if (argsCount > 0) { // Loop through arguments for (int argNumber = 0; argNumber < argsCount; ++argNumber) { QString filename = args.filenames().at(argNumber); // are we just trying to open a template? if (doTemplate) { createNewDocFromTemplate(filename, mw); } else if (QFile(filename).exists()) { KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; mw->openDocument(QUrl::fromLocalFile(filename), flags); } } } } void KisApplication::fileOpenRequested(const QString &url) { KisMainWindow *mainWindow = KisPart::instance()->mainWindows().first(); if (mainWindow) { KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; mainWindow->openDocument(QUrl::fromLocalFile(url), flags); } } void KisApplication::checkAutosaveFiles() { if (d->batchRun) return; // Check for autosave files from a previous run. There can be several, and // we want to offer a restore for every one. Including a nice thumbnail! QStringList filters; filters << QString(".krita-*-*-autosave.kra"); #ifdef Q_OS_WIN QDir dir = QDir::temp(); #else QDir dir = QDir::home(); #endif // all autosave files for our application QStringList autosaveFiles = dir.entryList(filters, QDir::Files | QDir::Hidden); // Allow the user to make their selection if (autosaveFiles.size() > 0) { if (d->splashScreen) { // hide the splashscreen to see the dialog d->splashScreen->hide(); } d->autosaveDialog = new KisAutoSaveRecoveryDialog(autosaveFiles, activeWindow()); QDialog::DialogCode result = (QDialog::DialogCode) d->autosaveDialog->exec(); if (result == QDialog::Accepted) { QStringList filesToRecover = d->autosaveDialog->recoverableFiles(); Q_FOREACH (const QString &autosaveFile, autosaveFiles) { if (!filesToRecover.contains(autosaveFile)) { QFile::remove(dir.absolutePath() + "/" + autosaveFile); } } autosaveFiles = filesToRecover; } else { autosaveFiles.clear(); } if (autosaveFiles.size() > 0) { QList autosaveUrls; Q_FOREACH (const QString &autoSaveFile, autosaveFiles) { const QUrl url = QUrl::fromLocalFile(dir.absolutePath() + QLatin1Char('/') + autoSaveFile); autosaveUrls << url; } if (d->mainWindow) { Q_FOREACH (const QUrl &url, autosaveUrls) { KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; d->mainWindow->openDocument(url, flags | KisMainWindow::RecoveryFile); } } } // cleanup delete d->autosaveDialog; d->autosaveDialog = nullptr; } } bool KisApplication::createNewDocFromTemplate(const QString &fileName, KisMainWindow *mainWindow) { QString templatePath; const QUrl templateUrl = QUrl::fromLocalFile(fileName); if (QFile::exists(fileName)) { templatePath = templateUrl.toLocalFile(); dbgUI << "using full path..."; } else { QString desktopName(fileName); const QString templatesResourcePath = QStringLiteral("templates/"); QStringList paths = KoResourcePaths::findAllResources("data", templatesResourcePath + "*/" + desktopName); if (paths.isEmpty()) { paths = KoResourcePaths::findAllResources("data", templatesResourcePath + desktopName); } if (paths.isEmpty()) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("No template found for: %1", desktopName)); } else if (paths.count() > 1) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Too many templates found for: %1", desktopName)); } else { templatePath = paths.at(0); } } if (!templatePath.isEmpty()) { QUrl templateBase; templateBase.setPath(templatePath); KDesktopFile templateInfo(templatePath); QString templateName = templateInfo.readUrl(); QUrl templateURL; templateURL.setPath(templateBase.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path() + '/' + templateName); KisMainWindow::OpenFlags batchFlags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; if (mainWindow->openDocument(templateURL, KisMainWindow::Import | batchFlags)) { dbgUI << "Template loaded..."; return true; } else { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Template %1 failed to load.", templateURL.toDisplayString())); } } return false; } void KisApplication::clearConfig() { KIS_ASSERT_RECOVER_RETURN(qApp->thread() == QThread::currentThread()); KSharedConfigPtr config = KSharedConfig::openConfig(); // find user settings file bool createDir = false; QString kritarcPath = KoResourcePaths::locateLocal("config", "kritarc", createDir); QFile configFile(kritarcPath); if (configFile.exists()) { // clear file if (configFile.open(QFile::WriteOnly)) { configFile.close(); } else { QMessageBox::warning(0, i18nc("@title:window", "Krita"), i18n("Failed to clear %1\n\n" "Please make sure no other program is using the file and try again.", kritarcPath), QMessageBox::Ok, QMessageBox::Ok); } } // reload from disk; with the user file settings cleared, // this should load any default configuration files shipping with the program config->reparseConfiguration(); config->sync(); } void KisApplication::askClearConfig() { Qt::KeyboardModifiers mods = QApplication::queryKeyboardModifiers(); bool askClearConfig = (mods & Qt::ControlModifier) && (mods & Qt::ShiftModifier) && (mods & Qt::AltModifier); if (askClearConfig) { bool ok = QMessageBox::question(0, i18nc("@title:window", "Krita"), i18n("Do you want to clear the settings file?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes; if (ok) { clearConfig(); } } }