diff --git a/krita/data/paintoppresets/kis_paintoppresets_tags.xml b/krita/data/paintoppresets/kis_paintoppresets_tags.xml index 31b2fe0981..33619bb4ad 100644 --- a/krita/data/paintoppresets/kis_paintoppresets_tags.xml +++ b/krita/data/paintoppresets/kis_paintoppresets_tags.xml @@ -1,440 +1,440 @@ - Sketch + Sketch - FX - Textures - Ink + FX + Textures + Ink - Digital + Digital - Paint + Paint - Textures + Textures - Sketch - Digital + Sketch + Digital - Sketch - Digital - Ink + Sketch + Digital + Ink - Sketch - Digital - Ink + Sketch + Digital + Ink - FX - Digital + FX + Digital - Textures + Textures - Textures + Textures - Paint - Sketch - ★ My Favorites + Paint + Sketch + ★ My Favorites - Ink + Ink - Paint - Sketch + Paint + Sketch - Sketch + Sketch - Sketch - Digital - ★ My Favorites + Sketch + Digital + ★ My Favorites - Paint + Paint - Sketch - Erasers - Digital - ★ My Favorites - Ink + Sketch + Erasers + Digital + ★ My Favorites + Ink - Sketch + Sketch - Textures - Paint - Ink + Textures + Paint + Ink - Paint - Sketch - Digital + Paint + Sketch + Digital - FX - Textures - Ink + FX + Textures + Ink - Digital + Digital - Paint + Paint - Sketch + Sketch - Pixel Art - Digital + Pixel Art + Digital - Ink + Ink - Textures + Textures - Textures + Textures - Sketch - Digital + Sketch + Digital - Paint + Paint - Sketch - Digital + Sketch + Digital - Paint + Paint - Sketch + Sketch - FX - Textures + FX + Textures - Paint + Paint - Textures - Paint + Textures + Paint - Sketch - Digital - ★ My Favorites + Sketch + Digital + ★ My Favorites - Paint + Paint - Textures + Textures - Sketch - Digital - Ink + Sketch + Digital + Ink - Paint + Paint - FX - Textures + FX + Textures - FX - Digital + FX + Digital - Paint + Paint - Textures + Textures - Sketch + Sketch - Textures - Ink + Textures + Ink - FX - Digital + FX + Digital - Textures + Textures - Sketch + Sketch - Textures - Paint - Ink + Textures + Paint + Ink - Ink + Ink - Paint + Paint - Paint + Paint - Sketch - Digital + Sketch + Digital - Textures - Ink + Textures + Ink - Digital + Digital - Ink + Ink - Paint - Sketch - ★ My Favorites + Paint + Sketch + ★ My Favorites - Digital - Ink + Digital + Ink - Paint + Paint - Sketch - Digital + Sketch + Digital - FX - Digital - Paint + FX + Digital + Paint - Textures + Textures - Textures + Textures - Sketch + Sketch - Digital - Ink + Digital + Ink - Textures + Textures - Textures + Textures - Paint + Paint - Paint + Paint - Paint + Paint - Digital + Digital - Sketch + Sketch - Sketch - Paint + Sketch + Paint - Sketch + Sketch - FX - Digital + FX + Digital - Textures + Textures - Textures + Textures - Digital + Digital - ★ My Favorites + ★ My Favorites - FX - Textures - Ink + FX + Textures + Ink - Paint - Sketch - Digital - ★ My Favorites + Paint + Sketch + Digital + ★ My Favorites - Digital + Digital - Sketch - Digital + Sketch + Digital - Digital - Ink + Digital + Ink - Sketch + Sketch - Textures - Ink + Textures + Ink - Textures + Textures - FX + FX - Digital - ★ My Favorites + Digital + ★ My Favorites - Digital + Digital - Textures + Textures - ★ My Favorites + ★ My Favorites - FX + FX - Digital - ★ My Favorites + Digital + ★ My Favorites - Pixel Art - Digital + Pixel Art + Digital - Paint + Paint - Paint + Paint - Sketch - Erasers - Digital - ★ My Favorites + Sketch + Erasers + Digital + ★ My Favorites - Sketch - ★ My Favorites + Sketch + ★ My Favorites - FX - Digital + FX + Digital - Pixel Art - Digital + Pixel Art + Digital - Digital + Digital - Sketch - Digital - Ink + Sketch + Digital + Ink - Sketch - Erasers - Digital - Ink + Sketch + Erasers + Digital + Ink - Textures + Textures - Sketch + Sketch - Paint + Paint - Sketch - Digital + Sketch + Digital - FX - Digital + FX + Digital - Sketch + Sketch - Textures + Textures - Pixel Art + Pixel Art - Paint + Paint - ★ My Favorites + ★ My Favorites - Ink + Ink - Sketch + Sketch - Textures + Textures - Digital + Digital diff --git a/libs/image/brushengine/kis_paintop_registry.cc b/libs/image/brushengine/kis_paintop_registry.cc index 066ae594e5..9665494adf 100644 --- a/libs/image/brushengine/kis_paintop_registry.cc +++ b/libs/image/brushengine/kis_paintop_registry.cc @@ -1,175 +1,175 @@ /* * Copyright (c) 2004 Boudewijn Rempt * * 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 "kis_paintop_registry.h" #include #include #include #include #include #include #include #include #include "kis_paint_device.h" #include "kis_painter.h" #include "kis_debug.h" #include "kis_layer.h" #include "kis_image.h" #include "kis_paintop_config_widget.h" Q_GLOBAL_STATIC(KisPaintOpRegistry, s_registryInstance) KisPaintOpRegistry::KisPaintOpRegistry() { } KisPaintOpRegistry::~KisPaintOpRegistry() { Q_FOREACH (const QString & id, keys()) { delete get(id); } dbgRegistry << "Deleting KisPaintOpRegistry"; } void KisPaintOpRegistry::initRegistry() { KoPluginLoader::instance()->load("Krita/Paintop", "(Type == 'Service') and ([X-Krita-Version] == 28)"); QStringList toBeRemoved; Q_FOREACH (const QString & id, keys()) { KisPaintOpFactory *factory = get(id); if (!factory->settings()) { toBeRemoved << id; } else { factory->processAfterLoading(); } } Q_FOREACH (const QString & id, toBeRemoved) { remove(id); } } KisPaintOpRegistry* KisPaintOpRegistry::instance() { - if (!s_registryInstance.exists()) { + dbgRegistry << "initalizing KisPaintOpRegistry"; s_registryInstance->initRegistry(); } return s_registryInstance; } #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND void KisPaintOpRegistry::preinitializePaintOpIfNeeded(const KisPaintOpPresetSP preset) { if (!preset) return; KisPaintOpFactory *f = value(preset->paintOp().id()); f->preinitializePaintOpIfNeeded(preset->settings()); } #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ KisPaintOp * KisPaintOpRegistry::paintOp(const QString & id, const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image) const { if (painter == 0) { warnKrita << " KisPaintOpRegistry::paintOp painter is null"; return 0; } Q_ASSERT(settings); KisPaintOpFactory* f = value(id); if (f) { KisPaintOp * op = f->createOp(settings, painter, node, image); if (op) { return op; } } warnKrita << "Could not create paintop for factory" << id << "with settings" << settings; return 0; } KisPaintOp * KisPaintOpRegistry::paintOp(const KisPaintOpPresetSP preset, KisPainter * painter, KisNodeSP node, KisImageSP image) const { Q_ASSERT(preset); Q_ASSERT(painter); if (!preset) return 0; return paintOp(preset->paintOp().id(), preset->settings(), painter, node, image); } KisPaintOpSettingsSP KisPaintOpRegistry::settings(const KoID& id) const { KisPaintOpFactory *f = value(id.id()); Q_ASSERT(f); if (f) { KisPaintOpSettingsSP settings = f->settings(); settings->setProperty("paintop", id.id()); return settings; } return 0; } KisPaintOpPresetSP KisPaintOpRegistry::defaultPreset(const KoID& id) const { KisPaintOpSettingsSP s = settings(id); if (s.isNull()) { return KisPaintOpPresetSP(); } KisPaintOpPresetSP preset(new KisPaintOpPreset()); preset->setName(i18n("default")); preset->setSettings(s); preset->setPaintOp(id); Q_ASSERT(!preset->paintOp().id().isEmpty()); preset->setValid(true); return preset; } QIcon KisPaintOpRegistry::icon(const KoID &id) const { KisPaintOpFactory* f = value(id.id()); if (!f) { dbgRegistry << "No paintop" << id.id() << ""; QPixmap p = QPixmap(22, 22); p.fill(Qt::transparent); return QIcon(p); } return f->icon(); } QList KisPaintOpRegistry::listKeys() const { QList answer; Q_FOREACH (const QString & key, keys()) { answer.append(KoID(key, get(key)->name())); } return answer; } diff --git a/libs/image/filter/kis_filter_registry.cc b/libs/image/filter/kis_filter_registry.cc index 4e8143663b..01bbddb4cf 100644 --- a/libs/image/filter/kis_filter_registry.cc +++ b/libs/image/filter/kis_filter_registry.cc @@ -1,81 +1,82 @@ /* * Copyright (c) 2003 Patrick Julien * Copyright (c) 2004 Cyrille Berger * Copyright (c) 2004-2008 Boudewijn Rempt * * 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 "filter/kis_filter_registry.h" #include #include #include #include #include #include "kis_debug.h" #include "kis_types.h" #include "kis_paint_device.h" #include "filter/kis_filter.h" #include "kis_filter_configuration.h" KisFilterRegistry::KisFilterRegistry(QObject *parent) : QObject(parent) { } KisFilterRegistry::~KisFilterRegistry() { dbgRegistry << "deleting KisFilterRegistry"; Q_FOREACH (KisFilterSP filter, values()) { remove(filter->id()); filter.clear(); } } KisFilterRegistry* KisFilterRegistry::instance() { KisFilterRegistry *reg = qApp->findChild(QString()); if (!reg) { + dbgRegistry << "initializing KisFilterRegistry"; reg = new KisFilterRegistry(qApp); KoPluginLoader::instance()->load("Krita/Filter", "Type == 'Service' and ([X-Krita-Version] == 28)"); } return reg; } void KisFilterRegistry::add(KisFilterSP item) { add(item->id(), item); } void KisFilterRegistry::add(const QString &id, KisFilterSP item) { KoGenericRegistry::add(id, item); emit(filterAdded(id)); } KisFilterConfigurationSP KisFilterRegistry::cloneConfiguration(const KisFilterConfigurationSP kfc) { Q_ASSERT(kfc); KisFilterSP filter = value(kfc->name()); KisFilterConfigurationSP newkfc(filter->defaultConfiguration()); newkfc->fromXML(kfc->toXML()); return newkfc; } diff --git a/libs/image/generator/kis_generator_registry.cpp b/libs/image/generator/kis_generator_registry.cpp index 60c7e4f3ce..9a14e03798 100644 --- a/libs/image/generator/kis_generator_registry.cpp +++ b/libs/image/generator/kis_generator_registry.cpp @@ -1,80 +1,81 @@ /* * Copyright (c) 2008 Boudewijn Rempt * * 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 "generator/kis_generator_registry.h" #include #include #include #include #include #include "filter/kis_filter_configuration.h" #include "kis_debug.h" #include "kis_types.h" #include "kis_paint_device.h" #include "generator/kis_generator.h" KisGeneratorRegistry::KisGeneratorRegistry(QObject *parent) : QObject(parent) { } KisGeneratorRegistry::~KisGeneratorRegistry() { Q_FOREACH (KisGeneratorSP generator, values()) { remove(generator->id()); generator.clear(); } dbgRegistry << "deleting KisGeneratorRegistry"; } KisGeneratorRegistry* KisGeneratorRegistry::instance() { KisGeneratorRegistry *reg = qApp->findChild(QString()); if (!reg) { + dbgRegistry << "initializing KisGeneratorRegistry"; reg = new KisGeneratorRegistry(qApp); KoPluginLoader::instance()->load("Krita/Generator", "Type == 'Service' and ([X-Krita-Version] == 28)"); } return reg; } void KisGeneratorRegistry::add(KisGeneratorSP item) { dbgPlugins << "adding " << item->name(); add(item->id(), item); } void KisGeneratorRegistry::add(const QString &id, KisGeneratorSP item) { dbgPlugins << "adding " << item->name() << " with id " << id; KoGenericRegistry::add(id, item); emit(generatorAdded(id)); } KisFilterConfigurationSP KisGeneratorRegistry::cloneConfiguration(const KisFilterConfigurationSP kfc) { KisGeneratorSP filter = value(kfc->name()); KisFilterConfigurationSP newkfc(filter->defaultConfiguration()); newkfc->fromXML(kfc->toXML()); return newkfc; } diff --git a/libs/ui/KisApplication.cpp b/libs/ui/KisApplication.cpp index 99152f7335..99228f7013 100644 --- a/libs/ui/KisApplication.cpp +++ b/libs/ui/KisApplication.cpp @@ -1,799 +1,833 @@ /* * 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 "KoGlobal.h" #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 namespace { const QTime appStartTime(QTime::currentTime()); } class KisApplicationPrivate { public: KisApplicationPrivate() : splashScreen(0) {} QPointer splashScreen; }; 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 KisApplicationPrivate) , m_autosaveDialog(0) , m_mainWindow(0) , m_batchRun(false) { #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(); qDebug() << "krita has opengl" << KisOpenGL::hasOpenGL(); } #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("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() { +// qDebug() << "loadResources();"; + setSplashScreenLoadingText(i18n("Loading Resources...")); processEvents(); KoResourceServerProvider::instance(); - setSplashScreenLoadingText(i18n("Loading Brushes...")); - processEvents(); - KisBrushServer::instance()->brushServer(); - 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 print = args.print(); const bool exportAs = args.exportAs(); const bool exportAsPdf = args.exportAsPdf(); const QString exportFileName = args.exportFileName(); m_batchRun = (print || exportAs || exportAsPdf || !exportFileName.isEmpty()); // print & exportAsPdf do user interaction ATM const bool needsMainWindow = !exportAs; // only show the mainWindow when no command-line mode option is passed // TODO: fix print & exportAsPdf to work without mainwindow shown const bool showmainWindow = !exportAs; // would be !batchRun; const bool showSplashScreen = !m_batchRun && qEnvironmentVariableIsEmpty("NOSPLASH"); if (showSplashScreen && d->splashScreen) { d->splashScreen->show(); d->splashScreen->repaint(); processEvents(); } KoHashGeneratorProvider::instance()->setGenerator("MD5", new KisMD5Generator()); // Initialize all Krita directories etc. KoGlobal::initialize(); 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 all resources and tags before the plugins do that - loadResources(); - // Load the plugins loadPlugins(); + // Load all resources + loadResources(); + + // Load all the tags + loadResourceTags(); + + // Load the gui plugins + loadGuiPlugins(); + if (needsMainWindow) { // show a mainWindow asap, if we want that setSplashScreenLoadingText(i18n("Loading Main Window...")); processEvents(); m_mainWindow = KisPart::instance()->createMainWindow(); if (showmainWindow) { m_mainWindow->initializeGeometry(); if (!args.workspace().isEmpty()) { KoResourceServer * rserver = KisResourceServerProvider::instance()->workspaceServer(); KisWorkspaceResource* workspace = rserver->resourceByName(args.workspace()); if (workspace) { m_mainWindow->restoreWorkspace(workspace->dockerState()); } } if (args.canvasOnly()) { m_mainWindow->viewManager()->switchCanvasOnly(true); } if (args.fullScreen()) { m_mainWindow->showFullScreen(); } else { m_mainWindow->show(); } } } short int numberOfOpenDocuments = 0; // number of documents open // Check for autosave files that can be restored, if we're not running a batchrun (test, print, export to pdf) if (!m_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::instance()->addDocument(doc); m_mainWindow->addViewAndNotifyLoadingCompleted(doc); } } // Get the command line arguments which we have to parse int argsCount = args.filenames().count(); if (argsCount > 0) { // Loop through arguments short int nPrinted = 0; 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 (m_batchRun) { continue; } if (createNewDocFromTemplate(fileName, m_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::instance()->createDocument(); doc->setFileBatchMode(m_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(); } nPrinted++; QTimer::singleShot(0, this, SLOT(quit())); } else if (m_mainWindow) { KisMainWindow::OpenFlags flags = m_batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; if (m_mainWindow->openDocument(QUrl::fromLocalFile(fileName), flags)) { if (print) { m_mainWindow->slotFilePrint(); nPrinted++; // TODO: trigger closing of app once printing is done } else if (exportAsPdf) { KisPrintJob *job = m_mainWindow->exportToPdf(exportFileName); if (job) connect (job, SIGNAL(destroyed(QObject*)), m_mainWindow, SLOT(slotFileQuit()), Qt::QueuedConnection); nPrinted++; } else { // Normal case, success numberOfOpenDocuments++; } } else { // .... if failed // delete doc; done by openDocument } } } } if (m_batchRun) { return nPrinted > 0; } } // 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() { delete d; } 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 = m_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 = m_batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; mainWindow->openDocument(QUrl::fromLocalFile(url), flags); } } void KisApplication::checkAutosaveFiles() { if (m_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(); } m_autosaveDialog = new KisAutoSaveRecoveryDialog(autosaveFiles, activeWindow()); QDialog::DialogCode result = (QDialog::DialogCode) m_autosaveDialog->exec(); if (result == QDialog::Accepted) { QStringList filesToRecover = m_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 (m_mainWindow) { Q_FOREACH (const QUrl &url, autosaveUrls) { KisMainWindow::OpenFlags flags = m_batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; m_mainWindow->openDocument(url, flags | KisMainWindow::RecoveryFile); } } } // cleanup delete m_autosaveDialog; m_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 = m_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(); } } } diff --git a/libs/ui/KisApplication.h b/libs/ui/KisApplication.h index de7e937102..c1aa8310d4 100644 --- a/libs/ui/KisApplication.h +++ b/libs/ui/KisApplication.h @@ -1,124 +1,126 @@ /* * 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. */ #ifndef KIS_APPLICATION_H #define KIS_APPLICATION_H #include #include #include "kritaui_export.h" #include class KisMainWindow; class KisApplicationPrivate; class QWidget; class KisApplicationArguments; class KisAutoSaveRecoveryDialog; #include /** * @brief Base class for the %Krita app * * This class handles arguments given on the command line and * shows a generic about dialog for the Krita app. * * In addition it adds the standard directories where Krita * can find its images etc. * * If the last mainwindow becomes closed, KisApplication automatically * calls QApplication::quit. */ class KRITAUI_EXPORT KisApplication : public QtSingleApplication { Q_OBJECT public: /** * Creates an application object, adds some standard directories and * initializes kimgio. */ explicit KisApplication(const QString &key, int &argc, char **argv); /** * Destructor. */ ~KisApplication() override; /** * Call this to start the application. * * Parses command line arguments and creates the initial main windowss and docs * from them (or an empty doc if no cmd-line argument is specified ). * * You must call this method directly before calling QApplication::exec. * * It is valid behaviour not to call this method at all. In this case you * have to process your command line parameters by yourself. */ virtual bool start(const KisApplicationArguments &args); /** * Checks if user is holding ctrl+alt+shift keys and asks if the settings file should be cleared. * * Typically called during startup before reading the config. */ void askClearConfig(); /** * Tell KisApplication to show this splashscreen when you call start(); * when start returns, the splashscreen is hidden. Use KSplashScreen * to have the splash show correctly on Xinerama displays. */ void setSplashScreen(QWidget *splash); void setSplashScreenLoadingText(QString); void hideSplashScreen(); /// Overridden to handle exceptions from event handlers. bool notify(QObject *receiver, QEvent *event) override; void addResourceTypes(); void loadResources(); + void loadResourceTags(); void loadPlugins(); + void loadGuiPlugins(); void initializeGlobals(const KisApplicationArguments &args); public Q_SLOTS: void remoteArguments(QByteArray message, QObject*socket); void fileOpenRequested(const QString & url); private: /// @return the number of autosavefiles opened void checkAutosaveFiles(); bool createNewDocFromTemplate(const QString &fileName, KisMainWindow *m_mainWindow); void clearConfig(); private: KisApplicationPrivate * const d; class ResetStarting; friend class ResetStarting; KisAutoSaveRecoveryDialog *m_autosaveDialog; QPointer m_mainWindow; // The first mainwindow we create on startup bool m_batchRun; }; #endif diff --git a/libs/ui/KisResourceBundleServerProvider.cpp b/libs/ui/KisResourceBundleServerProvider.cpp index 6ee8ed07db..87e855225a 100644 --- a/libs/ui/KisResourceBundleServerProvider.cpp +++ b/libs/ui/KisResourceBundleServerProvider.cpp @@ -1,69 +1,70 @@ /* * kis_resourceserver.cc - part of KImageShop * * Copyright (c) 1999 Matthias Elter * Copyright (c) 2003 Patrick Julien * Copyright (c) 2005 Sven Langkamp * * 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 "KisResourceBundleServerProvider.h" #include "KisResourceServerProvider.h" #include #include #include #include #include #include #include #include #include #include Q_GLOBAL_STATIC(KisResourceBundleServerProvider, s_instance) KisResourceBundleServerProvider::KisResourceBundleServerProvider() { m_resourceBundleServer = new KoResourceServerSimpleConstruction("kis_resourcebundles", "*.bundle"); - m_resourceBundleServer->loadResources(KoResourceServerProvider::blacklistFileNames(m_resourceBundleServer->fileNames(), m_resourceBundleServer->blackListedFiles())); + QStringList files = KoResourceServerProvider::blacklistFileNames(m_resourceBundleServer->fileNames(), m_resourceBundleServer->blackListedFiles()); + qDebug() << "Bundle files to load" << files; + m_resourceBundleServer->loadResources(files); Q_FOREACH (KisResourceBundle *bundle, m_resourceBundleServer->resources()) { if (!bundle->install()) { warnKrita << "Could not install resources for bundle" << bundle->name(); } } - KisResourceServerProvider::instance()->paintOpPresetServer()->clearOldSystemTags(); } KisResourceBundleServerProvider::~KisResourceBundleServerProvider() { delete m_resourceBundleServer; } KisResourceBundleServerProvider* KisResourceBundleServerProvider::instance() { return s_instance; } KoResourceServer *KisResourceBundleServerProvider::resourceBundleServer() { return m_resourceBundleServer; } diff --git a/libs/widgets/KoResourceServer.h b/libs/widgets/KoResourceServer.h index b9d973666d..fcbe0914f0 100644 --- a/libs/widgets/KoResourceServer.h +++ b/libs/widgets/KoResourceServer.h @@ -1,756 +1,762 @@ /* This file is part of the KDE project Copyright (c) 1999 Matthias Elter Copyright (c) 2003 Patrick Julien Copyright (c) 2005 Sven Langkamp Copyright (c) 2007 Jan Hambrecht Copyright (C) 2011 Srikanth Tiyyagura Copyright (c) 2013 Sascha Suelzer 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 KORESOURCESERVER_H #define KORESOURCESERVER_H #include #include #include #include #include #include #include #include #include "resources/KoResource.h" #include "KoResourceServerPolicies.h" #include "KoResourceServerObserver.h" #include "KoResourceTagStore.h" #include "KoResourcePaths.h" #include #include #include "kritawidgets_export.h" #include "WidgetsDebug.h" class KoResource; /** * KoResourceServerBase is the base class of all resource servers */ class KRITAWIDGETS_EXPORT KoResourceServerBase { public: /** * Constructs a KoResourceServerBase * @param resource type, has to be the same as used by KoResourcePaths * @param extensions the file extensions separate by ':', e.g. "*.kgr:*.svg:*.ggr" */ KoResourceServerBase(const QString& type, const QString& extensions) : m_type(type) , m_extensions(extensions) { } virtual ~KoResourceServerBase() {} virtual int resourceCount() const = 0; virtual void loadResources(QStringList filenames) = 0; - virtual QStringList blackListedFiles() const = 0; + virtual QStringList blackListedFiles() = 0; virtual QStringList queryResources(const QString &query) const = 0; QString type() const { return m_type; } /** * File extensions for resources of the server * @returns the file extensions separated by ':', e.g. "*.kgr:*.svg:*.ggr" */ QString extensions() const { return m_extensions; } QStringList fileNames() { QStringList extensionList = m_extensions.split(':'); QStringList fileNames; foreach (const QString &extension, extensionList) { fileNames += KoResourcePaths::findAllResources(type().toLatin1(), extension, KoResourcePaths::Recursive); } - - if (type() == "kis_resourcebundles") { - KConfigGroup group = KSharedConfig::openConfig()->group("BundleHack"); - if (group.readEntry("HideKrita3Bundle", true)) { - Q_FOREACH(const QString &filename, fileNames) { - if (filename.endsWith("Krita_3_Default_Resources.bundle")) { - if (!m_blackListFileNames.contains(filename)) { - m_blackListFileNames.append(filename); - } - } - } - } - } return fileNames; } protected: QStringList m_blackListFileNames; friend class KoResourceTagStore; virtual KoResource *byMd5(const QByteArray &md5) const = 0; virtual KoResource *byFileName(const QString &fileName) const = 0; private: QString m_type; QString m_extensions; protected: QMutex m_loadLock; }; /** * KoResourceServer manages the resources of one type. It stores, * loads and saves the resources. To keep track of changes the server * can be observed with a KoResourceServerObserver * * The \p Policy template parameter defines the way how the lifetime * of a resource is handled. There are to predefined policies: * * o PointerStoragePolicy --- usual pointers with ownership over * the resource. * o SharedPointerStoragePolicy --- shared pointers. The server does no * extra handling for the lifetime of * the resource. * * Use the former for usual resources and the latter for shared pointer based * ones. */ template > class KoResourceServer : public KoResourceServerBase { public: typedef typename Policy::PointerType PointerType; typedef KoResourceServerObserver ObserverType; KoResourceServer(const QString& type, const QString& extensions) : KoResourceServerBase(type, extensions) { m_blackListFile = KoResourcePaths::locateLocal("data", type + ".blacklist"); m_blackListFileNames = readBlackListFile(); m_tagStore = new KoResourceTagStore(this); - m_tagStore->loadTags(); } ~KoResourceServer() override { if (m_tagStore) { delete m_tagStore; } Q_FOREACH (ObserverType* observer, m_observers) { observer->unsetResourceServer(); } Q_FOREACH (PointerType res, m_resources) { Policy::deleteResource(res); } m_resources.clear(); } int resourceCount() const override { return m_resources.size(); } /** * Loads a set of resources and adds them to the resource server. * If a filename appears twice the resource will only be added once. Resources that can't * be loaded or and invalid aren't added to the server. * @param filenames list of filenames to be loaded */ void loadResources(QStringList filenames) override { QStringList uniqueFiles; while (!filenames.empty()) { QString front = filenames.first(); filenames.pop_front(); // In the save location, people can use sub-folders... And then they probably want // to load both versions! See https://bugs.kde.org/show_bug.cgi?id=321361. QString fname; if (front.contains(saveLocation())) { fname = front.split(saveLocation())[1]; } else { fname = QFileInfo(front).fileName(); } // XXX: Don't load resources with the same filename. Actually, we should look inside // the resource to find out whether they are really the same, but for now this // will prevent the same brush etc. showing up twice. if (!uniqueFiles.contains(fname)) { m_loadLock.lock(); uniqueFiles.append(fname); QList resources = createResources(front); Q_FOREACH (PointerType resource, resources) { Q_CHECK_PTR(resource); if (resource->load() && resource->valid() && !resource->md5().isEmpty()) { addResourceToMd5Registry(resource); m_resourcesByFilename[resource->shortFilename()] = resource; if (resource->name().isEmpty()) { resource->setName(fname); } if (m_resourcesByName.contains(resource->name())) { resource->setName(resource->name() + "(" + resource->shortFilename() + ")"); } m_resourcesByName[resource->name()] = resource; notifyResourceAdded(resource); } else { warnWidgets << "Loading resource " << front << "failed"; Policy::deleteResource(resource); } } m_loadLock.unlock(); } } m_resources = sortedResources(); Q_FOREACH (ObserverType* observer, m_observers) { observer->syncTaggedResourceView(); } - debugWidgets << "done loading resources for type " << type(); +// qDebug() << "done loading resources for type " << type(); } + void loadTags() { + m_tagStore->loadTags(); + } void clearOldSystemTags() { m_tagStore->clearOldSystemTags(); } /// Adds an already loaded resource to the server bool addResource(PointerType resource, bool save = true, bool infront = false) { if (!resource->valid()) { warnWidgets << "Tried to add an invalid resource!"; return false; } if (save) { QFileInfo fileInfo(resource->filename()); QDir d(fileInfo.path()); if (!d.exists()) { d.mkdir(fileInfo.path()); } if (fileInfo.exists()) { QString filename = fileInfo.path() + "/" + fileInfo.baseName() + "XXXXXX" + "." + fileInfo.suffix(); debugWidgets << "fileName is " << filename; QTemporaryFile file(filename); if (file.open()) { debugWidgets << "now " << file.fileName(); resource->setFilename(file.fileName()); } } if (!resource->save()) { warnWidgets << "Could not save resource!"; return false; } } Q_ASSERT(!resource->filename().isEmpty() || !resource->name().isEmpty()); if (resource->filename().isEmpty()) { resource->setFilename(resource->name()); } else if (resource->name().isEmpty()) { resource->setName(resource->filename()); } m_resourcesByFilename[resource->shortFilename()] = resource; addResourceToMd5Registry(resource); m_resourcesByName[resource->name()] = resource; if (infront) { m_resources.insert(0, resource); } else { m_resources.append(resource); } notifyResourceAdded(resource); return true; } /** * Removes a given resource from the blacklist. */ bool removeFromBlacklist(PointerType resource) { if (m_blackListFileNames.contains(resource->filename())) { m_blackListFileNames.removeAll(resource->filename()); writeBlackListFile(); return true; } return false; } /// Remove a resource from Resource Server but not from a file bool removeResourceFromServer(PointerType resource){ if ( !m_resourcesByFilename.contains( resource->shortFilename() ) ) { return false; } removeResourceFromMd5Registry(resource); m_resourcesByName.remove(resource->name()); m_resourcesByFilename.remove(resource->shortFilename()); m_resources.removeAt(m_resources.indexOf(resource)); m_tagStore->removeResource(resource); notifyRemovingResource(resource); Policy::deleteResource(resource); return true; } /// Remove a resource from the resourceserver and blacklist it bool removeResourceAndBlacklist(PointerType resource) { if ( !m_resourcesByFilename.contains( resource->shortFilename() ) ) { return false; } removeResourceFromMd5Registry(resource); m_resourcesByName.remove(resource->name()); m_resourcesByFilename.remove(resource->shortFilename()); m_resources.removeAt(m_resources.indexOf(resource)); m_tagStore->removeResource(resource); notifyRemovingResource(resource); m_blackListFileNames.append(resource->filename()); writeBlackListFile(); Policy::deleteResource(resource); return true; } QList resources() { m_loadLock.lock(); QList resourceList = m_resources; Q_FOREACH (PointerType r, m_resourceBlackList) { resourceList.removeOne(r); } m_loadLock.unlock(); return resourceList; } /// Returns path where to save user defined and imported resources to virtual QString saveLocation() { return KoResourcePaths::saveLocation(type().toLatin1()); } /** * Creates a new resource from a given file and adds them to the resource server * The base implementation does only load one resource per file, override to implement collections * @param filename file name of the resource file to be imported * @param fileCreation decides whether to create the file in the saveLocation() directory */ virtual bool importResourceFile(const QString & filename , bool fileCreation=true) { QFileInfo fi(filename); if (!fi.exists()) return false; if ( fi.size() == 0) return false; PointerType resource = createResource( filename ); resource->load(); if (!resource->valid()) { warnWidgets << "Import failed! Resource is not valid"; Policy::deleteResource(resource); return false; } if (fileCreation) { Q_ASSERT(!resource->defaultFileExtension().isEmpty()); Q_ASSERT(!saveLocation().isEmpty()); QString newFilename = saveLocation() + fi.baseName() + resource->defaultFileExtension(); QFileInfo fileInfo(newFilename); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(saveLocation() + fi.baseName() + QString("%1").arg(i) + resource->defaultFileExtension()); i++; } resource->setFilename(fileInfo.filePath()); } if(!addResource(resource)) { Policy::deleteResource(resource); } return true; } /// Removes the resource file from the resource server virtual void removeResourceFile(const QString & filename) { QFileInfo fi(filename); PointerType resource = resourceByFilename(fi.fileName()); if (!resource) { warnWidgets << "Resource file do not exist "; return; } if (!removeResourceFromServer(resource)) return; } /** * Addes an observer to the server * @param observer the observer to be added * @param notifyLoadedResources determines if the observer should be notified about the already loaded resources */ void addObserver(ObserverType* observer, bool notifyLoadedResources = true) { m_loadLock.lock(); if(observer && !m_observers.contains(observer)) { m_observers.append(observer); if(notifyLoadedResources) { Q_FOREACH (PointerType resource, m_resourcesByFilename) { observer->resourceAdded(resource); } } } m_loadLock.unlock(); } /** * Removes an observer from the server * @param observer the observer to be removed */ void removeObserver(ObserverType* observer) { int index = m_observers.indexOf( observer ); if( index < 0 ) return; m_observers.removeAt( index ); } PointerType resourceByFilename(const QString& filename) const { if (m_resourcesByFilename.contains(filename)) { return m_resourcesByFilename[filename]; } return 0; } PointerType resourceByName( const QString& name ) const { if (m_resourcesByName.contains(name)) { return m_resourcesByName[name]; } return 0; } PointerType resourceByMD5(const QByteArray& md5) const { return m_resourcesByMd5.value(md5); } /** * Call after changing the content of a resource; * Notifies the connected views. */ void updateResource( PointerType resource ) { notifyResourceChanged(resource); } - QStringList blackListedFiles() const override + QStringList blackListedFiles() override { + if (type() == "kis_resourcebundles") { + KConfigGroup group = KSharedConfig::openConfig()->group("BundleHack"); + if (group.readEntry("HideKrita3Bundle", true)) { + Q_FOREACH(const QString &filename, fileNames()) { + if (filename.endsWith("Krita_3_Default_Resources.bundle")) { + if (!m_blackListFileNames.contains(filename)) { + m_blackListFileNames.append(filename); + } + } + } + } +// qDebug() << "blacklisted filenames" << m_blackListFileNames; + } return m_blackListFileNames; } void removeBlackListedFiles() { QStringList remainingFiles; // Files that can't be removed e.g. no rights will stay blacklisted Q_FOREACH (const QString &filename, m_blackListFileNames) { QFile file( filename ); if( ! file.remove() ) { remainingFiles.append(filename); } } m_blackListFileNames = remainingFiles; writeBlackListFile(); } QStringList tagNamesList() const { return m_tagStore->tagNamesList(); } // don't use these method directly since it doesn't update views! void addTag( KoResource* resource,const QString& tag) { m_tagStore->addTag(resource,tag); } // don't use these method directly since it doesn't update views! void delTag( KoResource* resource,const QString& tag) { m_tagStore->delTag(resource, tag); } QStringList searchTag(const QString& lineEditText) { return m_tagStore->searchTag(lineEditText); } void tagCategoryAdded(const QString& tag) { m_tagStore->serializeTags(); Q_FOREACH (ObserverType* observer, m_observers) { observer->syncTagAddition(tag); } } void tagCategoryRemoved(const QString& tag) { m_tagStore->delTag(tag); m_tagStore->serializeTags(); Q_FOREACH (ObserverType* observer, m_observers) { observer->syncTagRemoval(tag); } } void tagCategoryMembersChanged() { m_tagStore->serializeTags(); Q_FOREACH (ObserverType* observer, m_observers) { observer->syncTaggedResourceView(); } } QStringList queryResources(const QString &query) const override { return m_tagStore->searchTag(query); } QStringList assignedTagsList(KoResource* resource) const { return m_tagStore->assignedTagsList(resource); } /** * Create one or more resources from a single file. By default one resource is created. * Override to create more resources from the file. * @param filename the filename of the resource or resource collection */ virtual QList createResources( const QString & filename ) { QList createdResources; createdResources.append(createResource(filename)); return createdResources; } virtual PointerType createResource( const QString & filename ) = 0; /// Return the currently stored resources in alphabetical order, overwrite for customized sorting virtual QList sortedResources() { QMap sortedNames; Q_FOREACH (const QString &name, m_resourcesByName.keys()) { sortedNames.insert(name.toLower(), m_resourcesByName[name]); } return sortedNames.values(); } protected: void notifyResourceAdded(PointerType resource) { Q_FOREACH (ObserverType* observer, m_observers) { observer->resourceAdded(resource); } } void notifyRemovingResource(PointerType resource) { Q_FOREACH (ObserverType* observer, m_observers) { observer->removingResource(resource); } } void notifyResourceChanged(PointerType resource) { Q_FOREACH (ObserverType* observer, m_observers) { observer->resourceChanged(resource); } } /// Reads the xml file and returns the filenames as a list QStringList readBlackListFile() { QStringList filenameList; QFile f(m_blackListFile); if (!f.open(QIODevice::ReadOnly)) { return filenameList; } QDomDocument doc; if (!doc.setContent(&f)) { warnWidgets << "The file could not be parsed."; return filenameList; } QDomElement root = doc.documentElement(); if (root.tagName() != "resourceFilesList") { warnWidgets << "The file doesn't seem to be of interest."; return filenameList; } QDomElement file = root.firstChildElement("file"); while (!file.isNull()) { QDomNode n = file.firstChild(); QDomElement e = n.toElement(); if (e.tagName() == "name") { // If the krita bundle has landed in the blacklist, skip it. if (type() == "kis_resourcebundles") { +// qDebug() << "Checking for not reading bundle" << e.text(); if (e.text().endsWith("Krita_3_Default_Resources.bundle")) { file = file.nextSiblingElement("file"); } } filenameList.append(e.text().replace(QString("~"), QDir::homePath())); } file = file.nextSiblingElement("file"); } - +// if (type() == "kis_resourcebundles") { +// qDebug() << "Read bundle blacklist" << filenameList; +// } return filenameList; } /// write the blacklist file entries to an xml file void writeBlackListFile() { QFile f(m_blackListFile); if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { warnWidgets << "Cannot write meta information to '" << m_blackListFile << "'." << endl; return; } QDomDocument doc; QDomElement root; QDomDocument docTemp("m_blackListFile"); doc = docTemp; doc.appendChild(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"")); root = doc.createElement("resourceFilesList"); doc.appendChild(root); Q_FOREACH (QString filename, m_blackListFileNames) { // Don't write the krita3 bundle to the blacklist, since its location will change // when using the appimate. if (type() == "kis_resourcebundles") { +// qDebug() << "Checking for Not writing krita 3 bundle" << filename; if (filename.endsWith("Krita_3_Default_Resources.bundle")) continue; } QDomElement fileEl = doc.createElement("file"); QDomElement nameEl = doc.createElement("name"); QDomText nameText = doc.createTextNode(filename.replace(QDir::homePath(), QString("~"))); nameEl.appendChild(nameText); fileEl.appendChild(nameEl); root.appendChild(fileEl); } QTextStream metastream(&f); metastream << doc.toString(); f.close(); } protected: KoResource* byMd5(const QByteArray &md5) const override { return Policy::toResourcePointer(resourceByMD5(md5)); } KoResource* byFileName(const QString &fileName) const override { return Policy::toResourcePointer(resourceByFilename(fileName)); } private: void addResourceToMd5Registry(PointerType resource) { const QByteArray md5 = resource->md5(); if (!md5.isEmpty()) { m_resourcesByMd5.insert(md5, resource); } } void removeResourceFromMd5Registry(PointerType resource) { const QByteArray md5 = resource->md5(); if (!md5.isEmpty()) { m_resourcesByMd5.remove(md5); } } private: QHash m_resourcesByName; QHash m_resourcesByFilename; QHash m_resourcesByMd5; QList m_resourceBlackList; QList m_resources; ///< list of resources in order of addition QList m_observers; QString m_blackListFile; KoResourceTagStore* m_tagStore; }; template > class KoResourceServerSimpleConstruction : public KoResourceServer { public: KoResourceServerSimpleConstruction(const QString& type, const QString& extensions) : KoResourceServer(type, extensions) { } typename KoResourceServer::PointerType createResource( const QString & filename ) override { return new T(filename); } }; #endif // KORESOURCESERVER_H diff --git a/libs/widgets/KoResourceServerProvider.h b/libs/widgets/KoResourceServerProvider.h index 8d52fed603..9226e00488 100644 --- a/libs/widgets/KoResourceServerProvider.h +++ b/libs/widgets/KoResourceServerProvider.h @@ -1,66 +1,75 @@ /* This file is part of the KDE project Copyright (c) 1999 Matthias Elter Copyright (c) 2003 Patrick Julien Copyright (c) 2005 Sven Langkamp 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 KORESOURCESERVERPROVIDER_H #define KORESOURCESERVERPROVIDER_H #include #include #include #include "KoResourceServer.h" #include #include #include #include #include /** * Provides default resource servers for gradients, patterns and palettes */ class KRITAWIDGETS_EXPORT KoResourceServerProvider : public QObject { Q_OBJECT public: KoResourceServerProvider(); ~KoResourceServerProvider() override; static KoResourceServerProvider* instance(); + + /** + * @brief blacklistFileNames filters the filenames with the list of blacklisted file names + * @param fileNames all files + * @param blacklistedFileNames the files we don't want + * @return the result + */ static QStringList blacklistFileNames(QStringList fileNames, const QStringList &blacklistedFileNames); + + KoResourceServer* patternServer(); KoResourceServer* gradientServer(); KoResourceServer* paletteServer(); KoResourceServer* svgSymbolCollectionServer(); private: KoResourceServerProvider(const KoResourceServerProvider&); KoResourceServerProvider operator=(const KoResourceServerProvider&); private: struct Private; Private* const d; }; #endif // KORESOURCESERVERPROVIDER_H diff --git a/libs/widgets/KoResourceTagStore.cpp b/libs/widgets/KoResourceTagStore.cpp index b2fa159a98..072b83e18e 100644 --- a/libs/widgets/KoResourceTagStore.cpp +++ b/libs/widgets/KoResourceTagStore.cpp @@ -1,443 +1,417 @@ /* This file is part of the KDE project Copyright (c) 2011 Sven Langkamp Copyright (C) 2011 Srikanth Tiyyagura 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 */ #include "KoResourceTagStore.h" #include #include #include #include #include #include #include +#include + #define BLACKLISTED "blacklisted" ///< xml tag for blacklisted tags -static const QStringList krita3PresetSystemTags = {"ink", "Ink", "paint", "sketch", "demo", "Block", "Wet", "FX", "Erasers", "Circle", "Smudge", "Mix", "PixelArt"}; +static const QStringList krita3PresetSystemTags = {"Ink", "Block", "Wet", "FX", "Erasers", "Circle", "Smudge", "Mix", "PixelArt", "ink", "sketch", "demo", "paint"}; class Q_DECL_HIDDEN KoResourceTagStore::Private { public: QMultiHash md5ToTag; QMultiHash identifierToTag; QHash tagList; QStringList blacklistedTags; KoResourceServerBase *resourceServer; }; KoResourceTagStore::KoResourceTagStore(KoResourceServerBase *resourceServer) : d(new Private) { d->resourceServer = resourceServer; } KoResourceTagStore::~KoResourceTagStore() { serializeTags(); delete d; } QStringList KoResourceTagStore::assignedTagsList(const KoResource* resource) const { if (!resource) return QStringList(); QStringList tags = d->md5ToTag.values(resource->md5()); tags += d->identifierToTag.values(resource->filename()); tags.removeDuplicates(); return tags; } void KoResourceTagStore::removeResource(const KoResource *resource) { QStringList tags = assignedTagsList(resource); d->md5ToTag.remove(resource->md5()); d->identifierToTag.remove(resource->filename()); Q_FOREACH (const QString &tag, tags) { if (d->tagList.contains(tag)) { if (d->tagList[tag] > 0) { d->tagList[tag]--; } } } } QStringList KoResourceTagStore::tagNamesList() const { QStringList tagList = d->tagList.uniqueKeys(); Q_FOREACH(const QString &tag, d->blacklistedTags) { tagList.removeAll(tag); } return tagList; } void KoResourceTagStore::addTag(KoResource* resource, const QString& tag) { +// if (d->resourceServer->type() == "kis_paintoppresets" && resource) { +// qDebug() << "\t\t\taddTag" << tag << resource->filename() << d->tagList[tag] << d->md5ToTag.value(resource->md5()) << d->identifierToTag.values(resource->filename()); +// } + if (d->blacklistedTags.contains(tag)) { d->blacklistedTags.removeAll(tag); } - if (!resource) { + + if (!d->tagList.contains(tag)) { d->tagList.insert(tag, 0); } - else { + + if (resource) { bool added = false; if (!d->md5ToTag.contains(resource->md5(), tag)) { added = true; d->md5ToTag.insert(resource->md5(), tag); } if (!d->identifierToTag.contains(resource->filename())) { added = true; d->identifierToTag.insert(resource->filename(), tag); } if (added) { - if (d->tagList.contains(tag)) { - d->tagList[tag]++; - } - else { - d->tagList.insert(tag, 1); - } + d->tagList[tag]++; } } +// if (d->resourceServer->type() == "kis_paintoppresets" && resource) { +// qDebug() << "\t\t\t\tafter addTag" << tag << resource->filename() << d->tagList[tag] << d->md5ToTag.value(resource->md5()) << d->identifierToTag.values(resource->filename()); +// } + } void KoResourceTagStore::delTag(KoResource* resource, const QString& tag) { int res = d->md5ToTag.remove(resource->md5(), tag); res += d->identifierToTag.remove(resource->filename(), tag); if (res > 0) { // decrease the usecount for this tag if (d->tagList.contains(tag)) { if (d->tagList[tag] > 0) { d->tagList[tag]--; } } } } void KoResourceTagStore::delTag(const QString& tag) { Q_FOREACH (const QByteArray &res, d->md5ToTag.keys(tag)) { d->md5ToTag.remove(res, tag); } Q_FOREACH (const QString &identifier, d->identifierToTag.keys(tag)) { d->identifierToTag.remove(identifier, tag); } Q_ASSERT(!d->md5ToTag.values().contains(tag)); Q_ASSERT(!d->identifierToTag.values().contains(tag)); d->tagList.remove(tag); d->blacklistedTags << tag; serializeTags(); } QStringList KoResourceTagStore::searchTag(const QString& query) const { QStringList tagsList = query.split(QRegExp("[,]\\s*"), QString::SkipEmptyParts); if (tagsList.isEmpty()) { return QStringList(); } QSet resources; Q_FOREACH (QString tag, tagsList) { Q_FOREACH (const QByteArray &md5, d->md5ToTag.keys(tag)) { KoResource *res = d->resourceServer->byMd5(md5); if (res) resources << res; } Q_FOREACH (const QString &identifier, d->identifierToTag.keys(tag)) { KoResource *res = d->resourceServer->byFileName(identifier); if (res) resources << res; } } QStringList filenames; Q_FOREACH (const KoResource *res, resources) { if (res) { - filenames << adjustedFileName(res->shortFilename()); + filenames << res->shortFilename(); } } - - return removeAdjustedFileNames(filenames); + return filenames; } void KoResourceTagStore::loadTags() { QStringList tagFiles = KoResourcePaths::findDirs("tags"); Q_FOREACH (const QString &tagFile, tagFiles) { -// if (d->resourceServer->type() == "kis_paintoppresets") { -// qDebug() << "loading tags" << tagFile + d->resourceServer->type() + "_tags.xml"; -// } - readXMLFile(tagFile + d->resourceServer->type() + "_tags.xml"); + QString fileName = tagFile + d->resourceServer->type() + "_tags.xml"; + if (QFileInfo(fileName).exists()) { + readXMLFile(fileName); + } } } void KoResourceTagStore::clearOldSystemTags() { if (d->resourceServer->type() == "kis_paintoppresets") { // qDebug() << "clearOldSystemTags" << d->tagList; Q_FOREACH(const QString &systemTag, krita3PresetSystemTags) { // qDebug() << "\t" << systemTag << d->tagList[systemTag]; if (d->tagList[systemTag] == 0) { d->tagList.remove(systemTag); } } } } void KoResourceTagStore::writeXMLFile(const QString &tagstore) { QFile f(tagstore); if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { warnWidgets << "Cannot write meta information to '" << tagstore << "'."; return; } QDomDocument doc; QDomElement root; QDomDocument docTemp("tags"); doc = docTemp; doc.appendChild(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"")); root = doc.createElement("tags"); doc.appendChild(root); QSet taggedResources; Q_FOREACH (const QByteArray &md5, d->md5ToTag.keys()) { KoResource *res = d->resourceServer->byMd5(md5); if (res) { taggedResources << res; } } Q_FOREACH (const QString &identifier, d->identifierToTag.keys()) { KoResource *res = d->resourceServer->byFileName(identifier); if (res) { taggedResources << res; } } Q_FOREACH (const KoResource *res, taggedResources) { QDomElement resourceEl = doc.createElement("resource"); resourceEl.setAttribute("identifier", res->filename().replace(QDir::homePath(), QString("~"))); resourceEl.setAttribute("md5", QString(res->md5().toBase64())); Q_FOREACH (const QString &tag, assignedTagsList(res)) { QDomElement tagEl = doc.createElement("tag"); tagEl.setAttribute(BLACKLISTED, "false"); tagEl.appendChild(doc.createTextNode(tag)); resourceEl.appendChild(tagEl); } root.appendChild(resourceEl); } // Now write empty tags Q_FOREACH (const QString &tag, d->tagList.uniqueKeys()) { if (d->tagList[tag] == 0) { QDomElement resourceEl = doc.createElement("resource"); resourceEl.setAttribute("identifier", "dummy"); QDomElement tagEl = doc.createElement("tag"); tagEl.setAttribute(BLACKLISTED, d->blacklistedTags.contains(tag) ? "true" : "false"); tagEl.appendChild(doc.createTextNode(tag)); resourceEl.appendChild(tagEl); root.appendChild(resourceEl); } } // Now write blacklisted tags. Q_FOREACH (const QString &tag, d->blacklistedTags) { if (d->tagList[tag] == 0) { QDomElement resourceEl = doc.createElement("resource"); resourceEl.setAttribute("identifier", "dummy"); QDomElement tagEl = doc.createElement("tag"); tagEl.setAttribute(BLACKLISTED, "true"); tagEl.appendChild(doc.createTextNode(tag)); resourceEl.appendChild(tagEl); root.appendChild(resourceEl); } } QTextStream metastream(&f); metastream.setCodec("UTF-8"); metastream << doc.toString(); f.close(); } void KoResourceTagStore::readXMLFile(const QString &tagstore) { QString inputFile; if (QFile::exists(tagstore)) { inputFile = tagstore; - } else { + } + else { return; } +// qDebug() << "\treadXMLFile()." << tagstore << d->resourceServer->type() << "Server has" << d->resourceServer->resourceCount() << "resources"; + if (d->resourceServer->type() == "kis_paintoppresets") { + Q_FOREACH(const QString &line, kisBacktrace().split("\n")) { +// qDebug() << line; + } + } + QFile f(inputFile); if (!f.open(QIODevice::ReadOnly)) { + qWarning() << "Could not open tag file" << tagstore; return; } QDomDocument doc; if (!doc.setContent(&f)) { warnWidgets << "The file could not be parsed."; return; } QDomElement root = doc.documentElement(); if (root.tagName() != "tags") { warnWidgets << "The file doesn't seem to be of interest."; return; } QDomNodeList resourceNodesList = root.childNodes(); for (int i = 0; i < resourceNodesList.count(); i++) { QByteArray resourceMD5; QString identifier; QDomElement element = resourceNodesList.at(i).toElement(); if (element.tagName() == "resource") { KoResource *resByMd5 = 0; KoResource *resByFileName = 0; if (element.hasAttribute("md5")) { resourceMD5 = QByteArray::fromBase64(element.attribute("md5").toLatin1()); resByMd5 = d->resourceServer->byMd5(resourceMD5); } if (element.hasAttribute("identifier")) { identifier = element.attribute("identifier"); QFileInfo fi(identifier); resByFileName = d->resourceServer->byFileName(fi.fileName()); } - if (identifier == "dummy" || isServerResource(identifier)) { +// qDebug() << "\t\tmd5" << QString::fromLatin1(resourceMD5.toHex()) << "resByMd5" << resByMd5 << "identifier" << identifier << "resByFileName" << resByFileName; + if (identifier == "dummy") { QDomNodeList tagNodesList = resourceNodesList.at(i).childNodes(); - for (int j = 0; j < tagNodesList.count() ; j++) { - QDomElement tagEl = tagNodesList.at(j).toElement(); bool blacklisted = (tagEl.attribute(BLACKLISTED, "false") == "true"); if (blacklisted || d->blacklistedTags.contains(tagEl.text())) { if (!d->blacklistedTags.contains(tagEl.text())) { d->blacklistedTags << tagEl.text(); } } else { - if (identifier != "dummy") { - QFileInfo fi(identifier); - KoResource *res = d->resourceServer->byFileName(fi.fileName()); - addTag(res, tagEl.text()); - } - else { - addTag(0, tagEl.text()); - } - d->md5ToTag.insert(resourceMD5, tagEl.text()); - d->identifierToTag.insert(identifier, tagEl.text()); + addTag(0, tagEl.text()); } } } else { KoResource *res = 0; if (resByMd5 && resByFileName && (resByMd5 != resByFileName)) { warnWidgets << "MD5sum and filename point to different resources -- was the resource renamed? We go with md5"; res = resByMd5; } else if (!resByMd5 && resByFileName) { // We didn't find the resource by md5, but did find it by filename, so take that one res = resByFileName; } else { res = resByMd5; } QDomNodeList tagNodesList = resourceNodesList.at(i).childNodes(); for (int j = 0; j < tagNodesList.count() ; j++) { QDomElement tagEl = tagNodesList.at(j).toElement(); bool blacklisted = (tagEl.attribute(BLACKLISTED, "false") == "true"); if (blacklisted || d->blacklistedTags.contains(tagEl.text())) { if (!d->blacklistedTags.contains(tagEl.text())) { d->blacklistedTags << tagEl.text(); } } else { if (res) { addTag(res, tagEl.text()); } d->md5ToTag.insert(resourceMD5, tagEl.text()); d->identifierToTag.insert(identifier, tagEl.text()); } } } } } -} - -bool KoResourceTagStore::isServerResource(const QString &resourceName) const -{ - bool removeChild = false; - QStringList extensionsList = d->resourceServer->extensions().split(':'); - Q_FOREACH (QString extension, extensionsList) { - if (resourceName.contains(extension.remove('*'))) { - removeChild = true; - break; - } - } - return removeChild; -} - -QString KoResourceTagStore::adjustedFileName(const QString &fileName) const -{ - if (!isServerResource(fileName)) { - return fileName + "-krita" + d->resourceServer->extensions().split(':').takeFirst().remove('*'); - } - return fileName; -} - -QStringList KoResourceTagStore::removeAdjustedFileNames(QStringList fileNamesList) const -{ - Q_FOREACH (const QString & fileName, fileNamesList) { - if (fileName.contains("-krita")) { - fileNamesList.append(fileName.split("-krita").takeFirst()); - fileNamesList.removeAll(fileName); - } - } - return fileNamesList; +// qDebug() << "Done reading XML file from" << tagstore << d->tagList; } void KoResourceTagStore::serializeTags() { writeXMLFile(KoResourcePaths::saveLocation("tags") + d->resourceServer->type() + "_tags.xml"); } diff --git a/libs/widgets/KoResourceTagStore.h b/libs/widgets/KoResourceTagStore.h index 61a81f8e31..965c521a6f 100644 --- a/libs/widgets/KoResourceTagStore.h +++ b/libs/widgets/KoResourceTagStore.h @@ -1,93 +1,84 @@ /* This file is part of the KDE project Copyright (c) 2011 Sven Langkamp Copyright (c) 2011 Srikanth Tiyyagura 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 KORESOURCETAGSTORE_H #define KORESOURCETAGSTORE_H #include #include "kritawidgets_export.h" class KoResourceServerBase; class KoResource; class QStringList; class QString; /** * KoResourceTagging allows to add and delete tags to resources and also search reources using tags */ class KRITAWIDGETS_EXPORT KoResourceTagStore { public: /** * Constructs a KoResourceTagging object * */ explicit KoResourceTagStore(KoResourceServerBase *resourceServer); ~KoResourceTagStore(); QStringList assignedTagsList(const KoResource *resource) const; /// remote the given resource from the tagstore void removeResource(const KoResource *resource); /// Add the given tag to the tag store. The resource can be empty, in which case /// the tag is added but unused void addTag(KoResource* resource, const QString& tag); /// Remove the given tag for the given resource. It will be blacklisted if there are no users left. void delTag(KoResource* resource, const QString& tag); /// Remove the tag altogether. It will be blacklisted, too. void delTag(const QString& tag); /// @return a list of all the tags in this store QStringList tagNamesList() const; /// Return a list of filenames for the given tag QStringList searchTag(const QString& query) const; void loadTags(); void clearOldSystemTags(); void serializeTags(); private: friend class KoResourceTaggingTest; void readXMLFile(const QString &tagstore); void writeXMLFile(const QString &tagstore); - /// To check whether the resource belongs to the present server or not - bool isServerResource(const QString &resourceName) const; - - /// If resource filenames have no extensions, then we add "-krita.extension". - QString adjustedFileName(const QString &fileName) const; - - /// Removes the adjustements before going to the server - QStringList removeAdjustedFileNames(QStringList fileNamesList) const; - class Private; Private * const d; }; #endif // KORESOURCETAGSTORE_H diff --git a/libs/widgetutils/kis_action_registry.cpp b/libs/widgetutils/kis_action_registry.cpp index 8e9ec3a265..8f7dd8a05f 100644 --- a/libs/widgetutils/kis_action_registry.cpp +++ b/libs/widgetutils/kis_action_registry.cpp @@ -1,413 +1,416 @@ /* * Copyright (c) 2015 Michael Abrahams * * 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 3 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 #include #include #include #include #include #include #include #include #include "kis_debug.h" #include "KoResourcePaths.h" #include "kis_icon_utils.h" #include "kis_action_registry.h" #include "kshortcutschemeshelper_p.h" namespace { /** * We associate several pieces of information with each shortcut. The first * piece of information is a QDomElement, containing the raw data from the * .action XML file. The second and third are QKeySequences, the first of * which is the default shortcut, the last of which is any custom shortcut. * The last two are the KActionCollection and KActionCategory used to * organize the shortcut editor. */ struct ActionInfoItem { QDomElement xmlData; QString collectionName; QString categoryName; inline QList defaultShortcuts() const { return m_defaultShortcuts; } inline void setDefaultShortcuts(const QList &value) { m_defaultShortcuts = value; } inline QList customShortcuts() const { return m_customShortcuts; } inline void setCustomShortcuts(const QList &value, bool explicitlyReset) { m_customShortcuts = value; m_explicitlyReset = explicitlyReset; } inline QList effectiveShortcuts() const { return m_customShortcuts.isEmpty() && !m_explicitlyReset ? m_defaultShortcuts : m_customShortcuts; } private: QList m_defaultShortcuts; QList m_customShortcuts; bool m_explicitlyReset = false; }; // Convenience macros to extract text of a child node. QString getChildContent(QDomElement xml, QString node) { return xml.firstChildElement(node).text(); } // Use Krita debug logging categories instead of KDE's default qDebug() for // harmless empty strings and translations QString quietlyTranslate(const QString &s) { if (s.isEmpty()) { return s; } QString translatedString = i18nc("action", s.toUtf8()); if (translatedString == s) { translatedString = i18n(s.toUtf8()); } if (translatedString.isEmpty()) { dbgAction << "No translation found for" << s; return s; } return translatedString; } } class Q_DECL_HIDDEN KisActionRegistry::Private { public: Private(KisActionRegistry *_q) : q(_q) {} // This is the main place containing ActionInfoItems. QMap actionInfoList; void loadActionFiles(); void loadCustomShortcuts(QString filename = QStringLiteral("kritashortcutsrc")); // XXX: this adds a default item for the given name to the list of actioninfo objects! ActionInfoItem &actionInfo(const QString &name) { if (!actionInfoList.contains(name)) { dbgAction << "Tried to look up info for unknown action" << name; } return actionInfoList[name]; } KisActionRegistry *q; QSet sanityPropertizedShortcuts; }; Q_GLOBAL_STATIC(KisActionRegistry, s_instance) KisActionRegistry *KisActionRegistry::instance() { + if (!s_instance.exists()) { + dbgRegistry << "initializing KoActionRegistry"; + } return s_instance; } bool KisActionRegistry::hasAction(const QString &name) const { return d->actionInfoList.contains(name); } KisActionRegistry::KisActionRegistry() : d(new KisActionRegistry::Private(this)) { KConfigGroup cg = KSharedConfig::openConfig()->group("Shortcut Schemes"); QString schemeName = cg.readEntry("Current Scheme", "Default"); loadShortcutScheme(schemeName); loadCustomShortcuts(); } KisActionRegistry::ActionCategory KisActionRegistry::fetchActionCategory(const QString &name) const { if (!d->actionInfoList.contains(name)) return ActionCategory(); const ActionInfoItem info = d->actionInfoList.value(name); return ActionCategory(info.collectionName, info.categoryName); } void KisActionRegistry::notifySettingsUpdated() { d->loadCustomShortcuts(); } void KisActionRegistry::loadCustomShortcuts() { d->loadCustomShortcuts(); } void KisActionRegistry::loadShortcutScheme(const QString &schemeName) { // Load scheme file if (schemeName != QStringLiteral("Default")) { QString schemeFileName = KShortcutSchemesHelper::schemeFileLocations().value(schemeName); if (schemeFileName.isEmpty()) { return; } KConfig schemeConfig(schemeFileName, KConfig::SimpleConfig); applyShortcutScheme(&schemeConfig); } else { // Apply default scheme, updating KisActionRegistry data applyShortcutScheme(); } } QAction * KisActionRegistry::makeQAction(const QString &name, QObject *parent) { QAction * a = new QAction(parent); if (!d->actionInfoList.contains(name)) { dbgAction << "Warning: requested data for unknown action" << name; return a; } propertizeAction(name, a); return a; } void KisActionRegistry::settingsPageSaved() { // For now, custom shortcuts are dealt with by writing to file and reloading. loadCustomShortcuts(); // Announce UI should reload current shortcuts. emit shortcutsUpdated(); } void KisActionRegistry::applyShortcutScheme(const KConfigBase *config) { // First, update the things in KisActionRegistry d->actionInfoList.clear(); d->loadActionFiles(); if (config == 0) { // Use default shortcut scheme. Simplest just to reload everything. loadCustomShortcuts(); } else { const auto schemeEntries = config->group(QStringLiteral("Shortcuts")).entryMap(); // Load info item for each shortcut, reset custom shortcuts auto it = schemeEntries.constBegin(); while (it != schemeEntries.end()) { ActionInfoItem &info = d->actionInfo(it.key()); info.setDefaultShortcuts(QKeySequence::listFromString(it.value())); it++; } } } void KisActionRegistry::updateShortcut(const QString &name, QAction *action) { const ActionInfoItem &info = d->actionInfo(name); action->setShortcuts(info.effectiveShortcuts()); action->setProperty("defaultShortcuts", qVariantFromValue(info.defaultShortcuts())); d->sanityPropertizedShortcuts.insert(name); } bool KisActionRegistry::sanityCheckPropertized(const QString &name) { return d->sanityPropertizedShortcuts.contains(name); } QList KisActionRegistry::registeredShortcutIds() const { return d->actionInfoList.keys(); } bool KisActionRegistry::propertizeAction(const QString &name, QAction * a) { if (!d->actionInfoList.contains(name)) { warnAction << "No XML data found for action" << name; return false; } const ActionInfoItem info = d->actionInfo(name); QDomElement actionXml = info.xmlData; if (!actionXml.text().isEmpty()) { // i18n requires converting format from QString. auto getChildContent_i18n = [=](QString node){return quietlyTranslate(getChildContent(actionXml, node));}; // Note: the fields in the .action documents marked for translation are determined by extractrc. QString icon = getChildContent(actionXml, "icon"); QString text = getChildContent_i18n("text"); QString whatsthis = getChildContent_i18n("whatsThis"); QString toolTip = getChildContent_i18n("toolTip"); QString statusTip = getChildContent_i18n("statusTip"); QString iconText = getChildContent_i18n("iconText"); bool isCheckable = getChildContent(actionXml, "isCheckable") == QString("true"); a->setObjectName(name); // This is helpful, should be added more places in Krita a->setIcon(KisIconUtils::loadIcon(icon.toLatin1())); a->setText(text); a->setObjectName(name); a->setWhatsThis(whatsthis); a->setToolTip(toolTip); a->setStatusTip(statusTip); a->setIconText(iconText); a->setCheckable(isCheckable); } updateShortcut(name, a); return true; } QString KisActionRegistry::getActionProperty(const QString &name, const QString &property) { ActionInfoItem info = d->actionInfo(name); QDomElement actionXml = info.xmlData; if (actionXml.text().isEmpty()) { dbgAction << "No XML data found for action" << name; return QString(); } return getChildContent(actionXml, property); } void KisActionRegistry::Private::loadActionFiles() { QStringList actionDefinitions = KoResourcePaths::findAllResources("kis_actions", "*.action", KoResourcePaths::Recursive); // Extract actions all XML .action files. Q_FOREACH (const QString &actionDefinition, actionDefinitions) { QDomDocument doc; QFile f(actionDefinition); f.open(QFile::ReadOnly); doc.setContent(f.readAll()); QDomElement base = doc.documentElement(); // "ActionCollection" outer group QString collectionName = base.attribute("name"); QString version = base.attribute("version"); if (version != "2") { errAction << ".action XML file" << actionDefinition << "has incorrect version; skipping."; continue; } // Loop over nodes. Each of these corresponds to a // KActionCategory, producing a group of actions in the shortcut dialog. QDomElement actions = base.firstChild().toElement(); while (!actions.isNull()) { // field QDomElement categoryTextNode = actions.firstChild().toElement(); QString categoryName = quietlyTranslate(categoryTextNode.text()); // tags QDomElement actionXml = categoryTextNode.nextSiblingElement(); // Loop over individual actions while (!actionXml.isNull()) { if (actionXml.tagName() == "Action") { // Read name from format QString name = actionXml.attribute("name"); // Bad things if (name.isEmpty()) { errAction << "Unnamed action in definitions file " << actionDefinition; } else if (actionInfoList.contains(name)) { errAction << "NOT COOL: Duplicated action name from xml data: " << name; } else { ActionInfoItem info; info.xmlData = actionXml; // Use empty list to signify no shortcut QString shortcutText = getChildContent(actionXml, "shortcut"); if (!shortcutText.isEmpty()) { info.setDefaultShortcuts(QKeySequence::listFromString(shortcutText)); } info.categoryName = categoryName; info.collectionName = collectionName; actionInfoList.insert(name,info); } } actionXml = actionXml.nextSiblingElement(); } actions = actions.nextSiblingElement(); } } } void KisActionRegistry::Private::loadCustomShortcuts(QString filename) { const KConfigGroup localShortcuts(KSharedConfig::openConfig(filename), QStringLiteral("Shortcuts")); if (!localShortcuts.exists()) { return; } // Distinguish between two "null" states for custom shortcuts. for (auto i = actionInfoList.begin(); i != actionInfoList.end(); ++i) { if (localShortcuts.hasKey(i.key())) { QString entry = localShortcuts.readEntry(i.key(), QString()); if (entry == QStringLiteral("none")) { i.value().setCustomShortcuts(QList(), true); } else { i.value().setCustomShortcuts(QKeySequence::listFromString(entry), false); } } else { i.value().setCustomShortcuts(QList(), false); } } } KisActionRegistry::ActionCategory::ActionCategory() { } KisActionRegistry::ActionCategory::ActionCategory(const QString &_componentName, const QString &_categoryName) : componentName(_componentName), categoryName(_categoryName), m_isValid(true) { } bool KisActionRegistry::ActionCategory::isValid() const { return m_isValid && !categoryName.isEmpty() && !componentName.isEmpty(); } diff --git a/plugins/dockers/tasksetdocker/tasksetdocker_dock.cpp b/plugins/dockers/tasksetdocker/tasksetdocker_dock.cpp index abb85afdd4..a00eaff6be 100644 --- a/plugins/dockers/tasksetdocker/tasksetdocker_dock.cpp +++ b/plugins/dockers/tasksetdocker/tasksetdocker_dock.cpp @@ -1,240 +1,241 @@ /* * Copyright (c) 2011 Sven Langkamp * * 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "tasksetdocker_dock.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tasksetmodel.h" class KisTasksetDelegate : public QStyledItemDelegate { public: KisTasksetDelegate(QObject * parent = 0) : QStyledItemDelegate(parent) {} ~KisTasksetDelegate() override {} /// reimplemented QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const override { return QSize(QStyledItemDelegate::sizeHint(option, index).width(), qMin(QStyledItemDelegate::sizeHint(option, index).width(), 25)); } }; class KisTasksetResourceDelegate : public QStyledItemDelegate { public: KisTasksetResourceDelegate(QObject * parent = 0) : QStyledItemDelegate(parent) {} ~KisTasksetResourceDelegate() override {} /// reimplemented void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override; }; void KisTasksetResourceDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { if (! index.isValid()) return; TasksetResource* taskset = static_cast(index.internalPointer()); if (option.state & QStyle::State_Selected) { painter->setPen(QPen(option.palette.highlight(), 2.0)); painter->fillRect(option.rect, option.palette.highlight()); painter->setBrush(option.palette.highlightedText()); } else { painter->setBrush(option.palette.text()); } painter->drawText(option.rect.x() + 5, option.rect.y() + painter->fontMetrics().ascent() + 5, taskset->name()); } TasksetDockerDock::TasksetDockerDock( ) : QDockWidget(i18n("Task Sets")), m_canvas(0), m_blocked(false) { QWidget* widget = new QWidget(this); setupUi(widget); m_model = new TasksetModel(this); tasksetView->setModel(m_model); tasksetView->setItemDelegate(new KisTasksetDelegate(this)); recordButton->setIcon(KisIconUtils::loadIcon("media-record")); recordButton->setCheckable(true); clearButton->setIcon(KisIconUtils::loadIcon("edit-delete")); saveButton->setIcon(KisIconUtils::loadIcon("document-save")); saveButton->setEnabled(false); chooserButton->setIcon(KisIconUtils::loadIcon("edit-copy")); m_rserver = new KoResourceServerSimpleConstruction("kis_taskset", "*.kts"); if (!QFileInfo(m_rserver->saveLocation()).exists()) { QDir().mkpath(m_rserver->saveLocation()); } QSharedPointer adapter (new KoResourceServerAdapter(m_rserver)); m_rserver->loadResources(KoResourceServerProvider::blacklistFileNames(m_rserver->fileNames(), m_rserver->blackListedFiles())); + m_rserver->loadTags(); KoResourceItemChooser* itemChooser = new KoResourceItemChooser(adapter, this); itemChooser->setItemDelegate(new KisTasksetResourceDelegate(this)); itemChooser->setFixedSize(500, 250); itemChooser->setRowHeight(30); itemChooser->setColumnCount(1); itemChooser->showTaggingBar(true); chooserButton->setPopupWidget(itemChooser); connect(itemChooser, SIGNAL(resourceSelected(KoResource*)), this, SLOT(resourceSelected(KoResource*))); setWidget(widget); connect( tasksetView, SIGNAL(clicked( const QModelIndex & ) ), this, SLOT(activated ( const QModelIndex & ) ) ); connect( recordButton, SIGNAL(toggled(bool)), this, SLOT(recordClicked())); connect( clearButton, SIGNAL(clicked(bool)), this, SLOT(clearClicked())); connect( saveButton, SIGNAL(clicked(bool)), this, SLOT(saveClicked())); } TasksetDockerDock::~TasksetDockerDock() { delete m_rserver; } void TasksetDockerDock::setCanvas(KoCanvasBase * canvas) { if (m_canvas && m_canvas->viewManager()) { m_canvas->viewManager()->actionCollection()->disconnect(this); Q_FOREACH (KXMLGUIClient* client, m_canvas->viewManager()->mainWindow()->childClients()) { client->actionCollection()->disconnect(this); } } m_canvas = dynamic_cast(canvas); } void TasksetDockerDock::unsetCanvas() { m_canvas = 0; m_model->clear(); } void TasksetDockerDock::actionTriggered(QAction* action) { if(action && !action->objectName().isEmpty() && !m_blocked && recordButton->isChecked()) { m_model->addAction(action); saveButton->setEnabled(true); } } void TasksetDockerDock::activated(const QModelIndex& index) { QAction* action = m_model->actionFromIndex(index); m_blocked = true; action->trigger(); m_blocked = false; } void TasksetDockerDock::recordClicked() { if(m_canvas) { KisViewManager* view = m_canvas->viewManager(); connect(view->actionCollection(), SIGNAL(actionTriggered(QAction*)), this, SLOT(actionTriggered(QAction*)), Qt::UniqueConnection); Q_FOREACH (KXMLGUIClient* client, view->mainWindow()->childClients()) { connect(client->actionCollection(), SIGNAL(actionTriggered(QAction*)), this, SLOT(actionTriggered(QAction*)), Qt::UniqueConnection); } } } void TasksetDockerDock::saveClicked() { bool ok; QString name = QInputDialog::getText(this, i18n("Taskset Name"), i18n("Name:"), QLineEdit::Normal, QString(), &ok); if (!ok) { return; } TasksetResource* taskset = new TasksetResource(QString()); QStringList actionNames; Q_FOREACH (QAction* action, m_model->actions()) { actionNames.append(action->objectName()); } taskset->setActionList(actionNames); taskset->setValid(true); QString saveLocation = m_rserver->saveLocation(); bool newName = false; if(name.isEmpty()) { newName = true; name = i18n("Taskset"); } QFileInfo fileInfo(saveLocation + name + taskset->defaultFileExtension()); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(saveLocation + name + QString("%1").arg(i) + taskset->defaultFileExtension()); i++; } taskset->setFilename(fileInfo.filePath()); if(newName) { name = i18n("Taskset %1", i); } taskset->setName(name); m_rserver->addResource(taskset); } void TasksetDockerDock::clearClicked() { saveButton->setEnabled(false); m_model->clear(); } void TasksetDockerDock::resourceSelected(KoResource* resource) { if(!m_canvas) { return; } m_model->clear(); saveButton->setEnabled(true); Q_FOREACH (const QString& actionName, static_cast(resource)->actionList()) { QAction* action = m_canvas->viewManager()->actionCollection()->action(actionName); if(action) { m_model->addAction(action); } } } diff --git a/plugins/paintops/defaultpaintops/defaultpaintops_plugin.cc b/plugins/paintops/defaultpaintops/defaultpaintops_plugin.cc index 03d5bde99d..1e1df6a90d 100644 --- a/plugins/paintops/defaultpaintops/defaultpaintops_plugin.cc +++ b/plugins/paintops/defaultpaintops/defaultpaintops_plugin.cc @@ -1,57 +1,55 @@ /* * defaultpaintops_plugin.cc -- Part of Krita * * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) * * 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 "defaultpaintops_plugin.h" #include #include #include #include #include "kis_simple_paintop_factory.h" #include "kis_brushop.h" #include "kis_brushop_settings_widget.h" #include "kis_duplicateop.h" #include "kis_duplicateop_settings.h" #include "kis_global.h" #include #include "KisBrushOpSettings.h" #include "kis_brush_server.h" #include "kis_duplicateop_settings_widget.h" K_PLUGIN_FACTORY_WITH_JSON(DefaultPaintOpsPluginFactory, "kritadefaultpaintops.json", registerPlugin();) DefaultPaintOpsPlugin::DefaultPaintOpsPlugin(QObject *parent, const QVariantList &) : QObject(parent) { KisPaintOpRegistry *r = KisPaintOpRegistry::instance(); r->add(new KisSimplePaintOpFactory("paintbrush", i18nc("Pixel paintbrush", "Pixel"), KisPaintOpFactory::categoryStable(), "krita-paintbrush.png", QString(), QStringList(), 1)); r->add(new KisSimplePaintOpFactory("duplicate", i18nc("clone paintbrush (previously \"Duplicate\")", "Clone"), KisPaintOpFactory::categoryStable(), "krita-duplicate.png", QString(), QStringList(COMPOSITE_COPY), 15)); - - KisBrushServer::instance(); } DefaultPaintOpsPlugin::~DefaultPaintOpsPlugin() { } #include "defaultpaintops_plugin.moc" diff --git a/plugins/tools/karbonplugins/tools/filterEffectTool/FilterResourceServerProvider.cpp b/plugins/tools/karbonplugins/tools/filterEffectTool/FilterResourceServerProvider.cpp index 25344555e4..9c332fb299 100644 --- a/plugins/tools/karbonplugins/tools/filterEffectTool/FilterResourceServerProvider.cpp +++ b/plugins/tools/karbonplugins/tools/filterEffectTool/FilterResourceServerProvider.cpp @@ -1,60 +1,61 @@ /* This file is part of the KDE project Copyright (c) 1999 Matthias Elter Copyright (c) 2003 Patrick Julien Copyright (c) 2005 Sven Langkamp 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 */ #include "FilterResourceServerProvider.h" #include "FilterEffectResource.h" #include #include #include #include #include #include FilterResourceServerProvider *FilterResourceServerProvider::m_singleton = 0; FilterResourceServerProvider::FilterResourceServerProvider() { m_filterEffectServer = new KoResourceServerSimpleConstruction("ko_effects", "*.svg"); if (!QFileInfo(m_filterEffectServer->saveLocation()).exists()) { QDir().mkpath(m_filterEffectServer->saveLocation()); } m_filterEffectServer->loadResources(KoResourceServerProvider::blacklistFileNames(m_filterEffectServer->fileNames(), m_filterEffectServer->blackListedFiles())); + m_filterEffectServer->loadTags(); } FilterResourceServerProvider::~FilterResourceServerProvider() { delete m_filterEffectServer; } FilterResourceServerProvider *FilterResourceServerProvider::instance() { if (FilterResourceServerProvider::m_singleton == 0) { FilterResourceServerProvider::m_singleton = new FilterResourceServerProvider(); } return FilterResourceServerProvider::m_singleton; } KoResourceServer *FilterResourceServerProvider::filterEffectServer() { return m_filterEffectServer; }