File indexing completed on 2024-05-19 04:29:09
0001 /* 0002 * SPDX-FileCopyrightText: 1998, 1999 Torben Weis <weis@kde.org> 0003 * SPDX-FileCopyrightText: 2012 Boudewijn Rempt <boud@valdyas.org> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "KisApplication.h" 0009 0010 #include <stdlib.h> 0011 #ifdef Q_OS_WIN 0012 #include <windows.h> 0013 #include <tchar.h> 0014 #include "KisWindowsPackageUtils.h" 0015 #endif 0016 0017 #ifdef Q_OS_MACOS 0018 #include "osx.h" 0019 #include "KisMacosEntitlements.h" 0020 #endif 0021 0022 #include <QStandardPaths> 0023 #include <QDesktopWidget> 0024 #include <QDir> 0025 #include <QFile> 0026 #include <QLocale> 0027 #include <QMessageBox> 0028 #include <QProcessEnvironment> 0029 #include <QStringList> 0030 #include <QStyle> 0031 #include <QStyleFactory> 0032 #include <QSysInfo> 0033 #include <QTimer> 0034 #include <QWidget> 0035 #include <QImageReader> 0036 #include <QImageWriter> 0037 #include <QThread> 0038 0039 #include <klocalizedstring.h> 0040 #include <kdesktopfile.h> 0041 #include <kconfig.h> 0042 #include <kconfiggroup.h> 0043 0044 #include <KoDockRegistry.h> 0045 #include <KoToolRegistry.h> 0046 #include <KoColorSpaceRegistry.h> 0047 #include <KoPluginLoader.h> 0048 #include <KoShapeRegistry.h> 0049 #include "KoConfig.h" 0050 #include <KoResourcePaths.h> 0051 #include <KisMimeDatabase.h> 0052 #include "thememanager.h" 0053 #include "KisDocument.h" 0054 #include "KisMainWindow.h" 0055 #include "KisAutoSaveRecoveryDialog.h" 0056 #include "KisPart.h" 0057 #include <kis_icon.h> 0058 #include "kis_splash_screen.h" 0059 #include "kis_config.h" 0060 #include "flake/kis_shape_selection.h" 0061 #include <filter/kis_filter.h> 0062 #include <filter/kis_filter_registry.h> 0063 #include <filter/kis_filter_configuration.h> 0064 #include <generator/kis_generator_registry.h> 0065 #include <generator/kis_generator.h> 0066 #include <brushengine/kis_paintop_registry.h> 0067 #include <kis_meta_data_io_backend.h> 0068 #include <kis_meta_data_backend_registry.h> 0069 #include "KisApplicationArguments.h" 0070 #include <kis_debug.h> 0071 #include "kis_action_registry.h" 0072 #include <KoResourceServer.h> 0073 #include <KisResourceServerProvider.h> 0074 #include <KoResourceServerProvider.h> 0075 #include "opengl/kis_opengl.h" 0076 #include "kis_spin_box_unit_manager.h" 0077 #include "kis_document_aware_spin_box_unit_manager.h" 0078 #include "KisViewManager.h" 0079 #include <KisUsageLogger.h> 0080 0081 #include <KritaVersionWrapper.h> 0082 #include <dialogs/KisSessionManagerDialog.h> 0083 0084 #include <KisResourceCacheDb.h> 0085 #include <KisResourceLocator.h> 0086 #include <KisResourceLoader.h> 0087 #include <KisResourceLoaderRegistry.h> 0088 0089 #include <KisBrushTypeMetaDataFixup.h> 0090 #include <kis_gbr_brush.h> 0091 #include <kis_png_brush.h> 0092 #include <kis_svg_brush.h> 0093 #include <kis_imagepipe_brush.h> 0094 #include <KoColorSet.h> 0095 #include <KoSegmentGradient.h> 0096 #include <KoStopGradient.h> 0097 #include <KoPattern.h> 0098 #include <kis_workspace_resource.h> 0099 #include <KisSessionResource.h> 0100 #include <resources/KoSvgSymbolCollectionResource.h> 0101 0102 #include "widgets/KisScreenColorSampler.h" 0103 #include "KisDlgInternalColorSelector.h" 0104 0105 #include <dialogs/KisAsyncAnimationFramesSaveDialog.h> 0106 #include <kis_image_animation_interface.h> 0107 #include "kis_file_layer.h" 0108 #include "kis_group_layer.h" 0109 #include "kis_node_commands_adapter.h" 0110 #include "KisSynchronizedConnection.h" 0111 #include <QThreadStorage> 0112 #include <KisWindowsPackageUtils.h> 0113 0114 #include <kis_psd_layer_style.h> 0115 0116 #include <config-seexpr.h> 0117 #include <config-safe-asserts.h> 0118 0119 namespace { 0120 const QTime appStartTime(QTime::currentTime()); 0121 } 0122 0123 namespace { 0124 struct AppRecursionInfo { 0125 ~AppRecursionInfo() { 0126 KIS_SAFE_ASSERT_RECOVER_NOOP(!eventRecursionCount); 0127 KIS_SAFE_ASSERT_RECOVER_NOOP(postponedSynchronizationEvents.empty()); 0128 } 0129 0130 int eventRecursionCount {0}; 0131 std::queue<KisSynchronizedConnectionEvent> postponedSynchronizationEvents; 0132 }; 0133 0134 struct AppRecursionGuard { 0135 AppRecursionGuard(AppRecursionInfo *info) 0136 : m_info(info) 0137 { 0138 m_info->eventRecursionCount++; 0139 } 0140 0141 ~AppRecursionGuard() 0142 { 0143 m_info->eventRecursionCount--; 0144 } 0145 private: 0146 AppRecursionInfo *m_info {0}; 0147 }; 0148 0149 } 0150 0151 /** 0152 * We cannot make the recursion info be a part of KisApplication, 0153 * because KisApplication also owns QQmlThread, which is destroyed 0154 * after KisApplication::Private, which makes QThreadStorage spit 0155 * a warning about being destroyed too early 0156 */ 0157 Q_GLOBAL_STATIC(QThreadStorage<AppRecursionInfo>, s_recursionInfo) 0158 0159 class KisApplication::Private 0160 { 0161 public: 0162 Private() {} 0163 QPointer<KisSplashScreen> splashScreen; 0164 KisAutoSaveRecoveryDialog *autosaveDialog {0}; 0165 QPointer<KisMainWindow> mainWindow; // The first mainwindow we create on startup 0166 bool batchRun {false}; 0167 QVector<QByteArray> earlyRemoteArguments; 0168 QVector<QString> earlyFileOpenEvents; 0169 }; 0170 0171 class KisApplication::ResetStarting 0172 { 0173 public: 0174 ResetStarting(KisSplashScreen *splash, int fileCount) 0175 : m_splash(splash) 0176 , m_fileCount(fileCount) 0177 { 0178 } 0179 0180 ~ResetStarting() { 0181 0182 if (m_splash) { 0183 m_splash->hide(); 0184 } 0185 } 0186 0187 QPointer<KisSplashScreen> m_splash; 0188 int m_fileCount; 0189 }; 0190 0191 0192 KisApplication::KisApplication(const QString &key, int &argc, char **argv) 0193 : QtSingleApplication(key, argc, argv) 0194 , d(new Private) 0195 { 0196 #ifdef Q_OS_MACOS 0197 setMouseCoalescingEnabled(false); 0198 #endif 0199 0200 QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath()); 0201 0202 setApplicationDisplayName("Krita"); 0203 setApplicationName("krita"); 0204 // Note: Qt docs suggest we set this, but if we do, we get resource paths of the form of krita/krita, which is weird. 0205 // setOrganizationName("krita"); 0206 setOrganizationDomain("krita.org"); 0207 0208 QString version = KritaVersionWrapper::versionString(true); 0209 setApplicationVersion(version); 0210 setWindowIcon(KisIconUtils::loadIcon("krita-branding")); 0211 0212 if (qgetenv("KRITA_NO_STYLE_OVERRIDE").isEmpty()) { 0213 QStringList styles = QStringList() << "macintosh" << "breeze" << "fusion"; 0214 if (!styles.contains(style()->objectName().toLower())) { 0215 Q_FOREACH (const QString & style, styles) { 0216 if (!setStyle(style)) { 0217 qDebug() << "No" << style << "available."; 0218 } 0219 else { 0220 qDebug() << "Set style" << style; 0221 break; 0222 } 0223 } 0224 } 0225 0226 // if style is set from config, try to load that 0227 KisConfig cfg(true); 0228 QString widgetStyleFromConfig = cfg.widgetStyle(); 0229 if(widgetStyleFromConfig != "") { 0230 qApp->setStyle(widgetStyleFromConfig); 0231 } 0232 0233 } 0234 else { 0235 qDebug() << "Style override disabled, using" << style()->objectName(); 0236 } 0237 0238 // store the style name 0239 qApp->setProperty(currentUnderlyingStyleNameProperty, style()->objectName()); 0240 KisSynchronizedConnectionBase::registerSynchronizedEventBarrier(std::bind(&KisApplication::processPostponedSynchronizationEvents, this)); 0241 } 0242 0243 #if defined(Q_OS_WIN) && defined(ENV32BIT) 0244 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); 0245 0246 LPFN_ISWOW64PROCESS fnIsWow64Process; 0247 0248 BOOL isWow64() 0249 { 0250 BOOL bIsWow64 = FALSE; 0251 0252 //IsWow64Process is not available on all supported versions of Windows. 0253 //Use GetModuleHandle to get a handle to the DLL that contains the function 0254 //and GetProcAddress to get a pointer to the function if available. 0255 0256 fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( 0257 GetModuleHandle(TEXT("kernel32")),"IsWow64Process"); 0258 0259 if(0 != fnIsWow64Process) 0260 { 0261 if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) 0262 { 0263 //handle error 0264 } 0265 } 0266 return bIsWow64; 0267 } 0268 #endif 0269 0270 void KisApplication::initializeGlobals(const KisApplicationArguments &args) 0271 { 0272 Q_UNUSED(args) 0273 // There are no globals to initialize from the arguments now. There used 0274 // to be the `dpi` argument, but it doesn't do anything anymore. 0275 } 0276 0277 void KisApplication::addResourceTypes() 0278 { 0279 // All Krita's resource types 0280 KoResourcePaths::addAssetType("markers", "data", "/styles/"); 0281 KoResourcePaths::addAssetType("kis_pics", "data", "/pics/"); 0282 KoResourcePaths::addAssetType("kis_images", "data", "/images/"); 0283 KoResourcePaths::addAssetType("metadata_schema", "data", "/metadata/schemas/"); 0284 KoResourcePaths::addAssetType("gmic_definitions", "data", "/gmic/"); 0285 KoResourcePaths::addAssetType("kis_shortcuts", "data", "/shortcuts/"); 0286 KoResourcePaths::addAssetType("kis_actions", "data", "/actions"); 0287 KoResourcePaths::addAssetType("kis_actions", "data", "/pykrita"); 0288 KoResourcePaths::addAssetType("icc_profiles", "data", "/color/icc"); 0289 KoResourcePaths::addAssetType("icc_profiles", "data", "/profiles/"); 0290 KoResourcePaths::addAssetType(ResourceType::FilterEffects, "data", "/effects/"); 0291 KoResourcePaths::addAssetType("tags", "data", "/tags/"); 0292 KoResourcePaths::addAssetType("templates", "data", "/templates"); 0293 KoResourcePaths::addAssetType("pythonscripts", "data", "/pykrita"); 0294 KoResourcePaths::addAssetType("preset_icons", "data", "/preset_icons"); 0295 #if defined HAVE_SEEXPR 0296 KoResourcePaths::addAssetType(ResourceType::SeExprScripts, "data", "/seexpr_scripts/", true); 0297 #endif 0298 0299 // Make directories for all resources we can save, and tags 0300 KoResourcePaths::saveLocation("data", "/asl/", true); 0301 KoResourcePaths::saveLocation("data", "/input/", true); 0302 KoResourcePaths::saveLocation("data", "/pykrita/", true); 0303 KoResourcePaths::saveLocation("data", "/color-schemes/", true); 0304 KoResourcePaths::saveLocation("data", "/preset_icons/", true); 0305 KoResourcePaths::saveLocation("data", "/preset_icons/tool_icons/", true); 0306 KoResourcePaths::saveLocation("data", "/preset_icons/emblem_icons/", true); 0307 } 0308 0309 0310 bool KisApplication::event(QEvent *event) 0311 { 0312 0313 #ifdef Q_OS_MACOS 0314 if (event->type() == QEvent::FileOpen) { 0315 QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(event); 0316 emit fileOpenRequest(openEvent->file()); 0317 return true; 0318 } 0319 #endif 0320 return QApplication::event(event); 0321 } 0322 0323 0324 bool KisApplication::registerResources() 0325 { 0326 KisResourceLoaderRegistry *reg = KisResourceLoaderRegistry::instance(); 0327 0328 reg->add(new KisResourceLoader<KisPaintOpPreset>(ResourceSubType::KritaPaintOpPresets, ResourceType::PaintOpPresets, i18n("Brush presets"), 0329 QStringList() << "application/x-krita-paintoppreset")); 0330 0331 reg->add(new KisResourceLoader<KisGbrBrush>(ResourceSubType::GbrBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/x-gimp-brush")); 0332 reg->add(new KisResourceLoader<KisImagePipeBrush>(ResourceSubType::GihBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/x-gimp-brush-animated")); 0333 reg->add(new KisResourceLoader<KisSvgBrush>(ResourceSubType::SvgBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/svg+xml")); 0334 reg->add(new KisResourceLoader<KisPngBrush>(ResourceSubType::PngBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/png")); 0335 0336 reg->add(new KisResourceLoader<KoSegmentGradient>(ResourceSubType::SegmentedGradients, ResourceType::Gradients, i18n("Gradients"), QStringList() << "application/x-gimp-gradient")); 0337 reg->add(new KisResourceLoader<KoStopGradient>(ResourceSubType::StopGradients, ResourceType::Gradients, i18n("Gradients"), QStringList() << "image/svg+xml")); 0338 0339 reg->add(new KisResourceLoader<KoColorSet>(ResourceType::Palettes, ResourceType::Palettes, i18n("Palettes"), 0340 QStringList() << KisMimeDatabase::mimeTypeForSuffix("kpl") 0341 << KisMimeDatabase::mimeTypeForSuffix("gpl") 0342 << KisMimeDatabase::mimeTypeForSuffix("pal") 0343 << KisMimeDatabase::mimeTypeForSuffix("act") 0344 << KisMimeDatabase::mimeTypeForSuffix("aco") 0345 << KisMimeDatabase::mimeTypeForSuffix("css") 0346 << KisMimeDatabase::mimeTypeForSuffix("colors") 0347 << KisMimeDatabase::mimeTypeForSuffix("xml") 0348 << KisMimeDatabase::mimeTypeForSuffix("sbz"))); 0349 0350 0351 reg->add(new KisResourceLoader<KoPattern>(ResourceType::Patterns, ResourceType::Patterns, i18n("Patterns"), {"application/x-gimp-pattern", "image/x-gimp-pat", "application/x-gimp-pattern", "image/bmp", "image/jpeg", "image/png", "image/tiff"})); 0352 reg->add(new KisResourceLoader<KisWorkspaceResource>(ResourceType::Workspaces, ResourceType::Workspaces, i18n("Workspaces"), QStringList() << "application/x-krita-workspace")); 0353 reg->add(new KisResourceLoader<KoSvgSymbolCollectionResource>(ResourceType::Symbols, ResourceType::Symbols, i18n("SVG symbol libraries"), QStringList() << "image/svg+xml")); 0354 reg->add(new KisResourceLoader<KisWindowLayoutResource>(ResourceType::WindowLayouts, ResourceType::WindowLayouts, i18n("Window layouts"), QStringList() << "application/x-krita-windowlayout")); 0355 reg->add(new KisResourceLoader<KisSessionResource>(ResourceType::Sessions, ResourceType::Sessions, i18n("Sessions"), QStringList() << "application/x-krita-session")); 0356 reg->add(new KisResourceLoader<KoGamutMask>(ResourceType::GamutMasks, ResourceType::GamutMasks, i18n("Gamut masks"), QStringList() << "application/x-krita-gamutmasks")); 0357 #if defined HAVE_SEEXPR 0358 reg->add(new KisResourceLoader<KisSeExprScript>(ResourceType::SeExprScripts, ResourceType::SeExprScripts, i18n("SeExpr Scripts"), QStringList() << "application/x-krita-seexpr-script")); 0359 #endif 0360 // XXX: this covers only individual styles, not the library itself! 0361 reg->add(new KisResourceLoader<KisPSDLayerStyle>(ResourceType::LayerStyles, 0362 ResourceType::LayerStyles, 0363 i18nc("Resource type name", "Layer styles"), 0364 QStringList() << "application/x-photoshop-style")); 0365 0366 reg->registerFixup(10, new KisBrushTypeMetaDataFixup()); 0367 0368 #ifndef Q_OS_ANDROID 0369 QString databaseLocation = KoResourcePaths::getAppDataLocation(); 0370 #else 0371 // Sqlite doesn't support content URIs (obviously). So, we make database location unconfigurable on android. 0372 QString databaseLocation = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); 0373 #endif 0374 0375 if (!KisResourceCacheDb::initialize(databaseLocation)) { 0376 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita: Fatal error"), i18n("%1\n\nKrita will quit now.", KisResourceCacheDb::lastError())); 0377 } 0378 0379 KisResourceLocator::LocatorError r = KisResourceLocator::instance()->initialize(KoResourcePaths::getApplicationRoot() + "/share/krita"); 0380 connect(KisResourceLocator::instance(), SIGNAL(progressMessage(const QString&)), this, SLOT(setSplashScreenLoadingText(const QString&))); 0381 if (r != KisResourceLocator::LocatorError::Ok && qApp->inherits("KisApplication")) { 0382 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita: Fatal error"), KisResourceLocator::instance()->errorMessages().join('\n') + i18n("\n\nKrita will quit now.")); 0383 return false; 0384 } 0385 return true; 0386 } 0387 0388 void KisApplication::loadPlugins() 0389 { 0390 // qDebug() << "loadPlugins();"; 0391 0392 KoShapeRegistry* r = KoShapeRegistry::instance(); 0393 r->add(new KisShapeSelectionFactory()); 0394 KoColorSpaceRegistry::instance(); 0395 KisActionRegistry::instance(); 0396 KisFilterRegistry::instance(); 0397 KisGeneratorRegistry::instance(); 0398 KisPaintOpRegistry::instance(); 0399 KoToolRegistry::instance(); 0400 KoDockRegistry::instance(); 0401 KisMetadataBackendRegistry::instance(); 0402 } 0403 0404 bool KisApplication::start(const KisApplicationArguments &args) 0405 { 0406 KisConfig cfg(false); 0407 0408 #if defined(Q_OS_WIN) 0409 #ifdef ENV32BIT 0410 0411 if (isWow64() && !cfg.readEntry("WarnedAbout32Bits", false)) { 0412 QMessageBox::information(qApp->activeWindow(), 0413 i18nc("@title:window", "Krita: Warning"), 0414 i18n("You are running a 32 bits build on a 64 bits Windows.\n" 0415 "This is not recommended.\n" 0416 "Please download and install the x64 build instead.")); 0417 cfg.writeEntry("WarnedAbout32Bits", true); 0418 0419 } 0420 #endif 0421 #endif 0422 0423 QString opengl = cfg.canvasState(); 0424 if (opengl == "OPENGL_NOT_TRIED" ) { 0425 cfg.setCanvasState("TRY_OPENGL"); 0426 } 0427 else if (opengl != "OPENGL_SUCCESS" && opengl != "TRY_OPENGL") { 0428 cfg.setCanvasState("OPENGL_FAILED"); 0429 } 0430 0431 setSplashScreenLoadingText(i18n("Initializing Globals...")); 0432 processEvents(); 0433 initializeGlobals(args); 0434 0435 const bool doNewImage = args.doNewImage(); 0436 const bool doTemplate = args.doTemplate(); 0437 const bool exportAs = args.exportAs(); 0438 const bool exportSequence = args.exportSequence(); 0439 const QString exportFileName = args.exportFileName(); 0440 0441 d->batchRun = (exportAs || exportSequence || !exportFileName.isEmpty()); 0442 const bool needsMainWindow = (!exportAs && !exportSequence); 0443 // only show the mainWindow when no command-line mode option is passed 0444 bool showmainWindow = (!exportAs && !exportSequence); // would be !batchRun; 0445 0446 const bool showSplashScreen = !d->batchRun && qEnvironmentVariableIsEmpty("NOSPLASH"); 0447 if (showSplashScreen && d->splashScreen) { 0448 d->splashScreen->show(); 0449 d->splashScreen->repaint(); 0450 processEvents(); 0451 } 0452 0453 KConfigGroup group(KSharedConfig::openConfig(), "theme"); 0454 Digikam::ThemeManager themeManager; 0455 themeManager.setCurrentTheme(group.readEntry("Theme", "Krita dark")); 0456 0457 0458 ResetStarting resetStarting(d->splashScreen, args.filenames().count()); // remove the splash when done 0459 Q_UNUSED(resetStarting); 0460 0461 // Make sure we can save resources and tags 0462 setSplashScreenLoadingText(i18n("Adding resource types...")); 0463 processEvents(); 0464 addResourceTypes(); 0465 0466 setSplashScreenLoadingText(i18n("Loading plugins...")); 0467 processEvents(); 0468 // Load the plugins 0469 loadPlugins(); 0470 0471 // Load all resources 0472 setSplashScreenLoadingText(i18n("Loading resources...")); 0473 processEvents(); 0474 if (!registerResources()) { 0475 return false; 0476 } 0477 0478 KisPart *kisPart = KisPart::instance(); 0479 if (needsMainWindow) { 0480 // show a mainWindow asap, if we want that 0481 setSplashScreenLoadingText(i18n("Loading Main Window...")); 0482 processEvents(); 0483 0484 0485 bool sessionNeeded = true; 0486 auto sessionMode = cfg.sessionOnStartup(); 0487 0488 if (!args.session().isEmpty()) { 0489 sessionNeeded = !kisPart->restoreSession(args.session()); 0490 } else if (sessionMode == KisConfig::SOS_ShowSessionManager) { 0491 showmainWindow = false; 0492 sessionNeeded = false; 0493 kisPart->showSessionManager(); 0494 } else if (sessionMode == KisConfig::SOS_PreviousSession) { 0495 KConfigGroup sessionCfg = KSharedConfig::openConfig()->group("session"); 0496 const QString &sessionName = sessionCfg.readEntry("previousSession"); 0497 0498 sessionNeeded = !kisPart->restoreSession(sessionName); 0499 } 0500 0501 if (sessionNeeded) { 0502 kisPart->startBlankSession(); 0503 } 0504 0505 if (!args.windowLayout().isEmpty()) { 0506 KoResourceServer<KisWindowLayoutResource> * rserver = KisResourceServerProvider::instance()->windowLayoutServer(); 0507 KisWindowLayoutResourceSP windowLayout = rserver->resource("", "", args.windowLayout()); 0508 if (windowLayout) { 0509 windowLayout->applyLayout(); 0510 } 0511 } 0512 0513 setSplashScreenLoadingText(i18n("Launching...")); 0514 0515 if (showmainWindow) { 0516 d->mainWindow = kisPart->currentMainwindow(); 0517 0518 if (!args.workspace().isEmpty()) { 0519 KoResourceServer<KisWorkspaceResource> * rserver = KisResourceServerProvider::instance()->workspaceServer(); 0520 KisWorkspaceResourceSP workspace = rserver->resource("", "", args.workspace()); 0521 if (workspace) { 0522 d->mainWindow->restoreWorkspace(workspace); 0523 } 0524 } 0525 0526 if (args.canvasOnly()) { 0527 d->mainWindow->viewManager()->switchCanvasOnly(true); 0528 } 0529 0530 if (args.fullScreen()) { 0531 d->mainWindow->showFullScreen(); 0532 } 0533 } else { 0534 d->mainWindow = kisPart->createMainWindow(); 0535 } 0536 } 0537 short int numberOfOpenDocuments = 0; // number of documents open 0538 0539 // Check for autosave files that can be restored, if we're not running a batch run (test) 0540 if (!d->batchRun) { 0541 checkAutosaveFiles(); 0542 } 0543 0544 setSplashScreenLoadingText(QString()); // done loading, so clear out label 0545 processEvents(); 0546 0547 //configure the unit manager 0548 KisSpinBoxUnitManagerFactory::setDefaultUnitManagerBuilder(new KisDocumentAwareSpinBoxUnitManagerBuilder()); 0549 connect(this, &KisApplication::aboutToQuit, &KisSpinBoxUnitManagerFactory::clearUnitManagerBuilder); //ensure the builder is destroyed when the application leave. 0550 //the new syntax slot syntax allow to connect to a non q_object static method. 0551 0552 // Create a new image, if needed 0553 if (doNewImage) { 0554 KisDocument *doc = args.createDocumentFromArguments(); 0555 if (doc) { 0556 kisPart->addDocument(doc); 0557 d->mainWindow->addViewAndNotifyLoadingCompleted(doc); 0558 } 0559 } 0560 0561 // Get the command line arguments which we have to parse 0562 int argsCount = args.filenames().count(); 0563 if (argsCount > 0) { 0564 // Loop through arguments 0565 for (int argNumber = 0; argNumber < argsCount; argNumber++) { 0566 QString fileName = args.filenames().at(argNumber); 0567 // are we just trying to open a template? 0568 if (doTemplate) { 0569 // called in mix with batch options? ignore and silently skip 0570 if (d->batchRun) { 0571 continue; 0572 } 0573 if (createNewDocFromTemplate(fileName, d->mainWindow)) { 0574 ++numberOfOpenDocuments; 0575 } 0576 // now try to load 0577 } 0578 else { 0579 if (exportAs) { 0580 QString outputMimetype = KisMimeDatabase::mimeTypeForFile(exportFileName, false); 0581 if (outputMimetype == "application/octetstream") { 0582 dbgKrita << i18n("Mimetype not found, try using the -mimetype option") << endl; 0583 return false; 0584 } 0585 0586 KisDocument *doc = kisPart->createDocument(); 0587 doc->setFileBatchMode(d->batchRun); 0588 bool result = doc->openPath(fileName); 0589 0590 if (!result) { 0591 errKrita << "Could not load " << fileName << ":" << doc->errorMessage(); 0592 QTimer::singleShot(0, this, SLOT(quit())); 0593 return false; 0594 } 0595 0596 if (exportFileName.isEmpty()) { 0597 errKrita << "Export destination is not specified for" << fileName << "Please specify export destination with --export-filename option"; 0598 QTimer::singleShot(0, this, SLOT(quit())); 0599 return false; 0600 } 0601 0602 qApp->processEvents(); // For vector layers to be updated 0603 0604 doc->setFileBatchMode(true); 0605 doc->image()->waitForDone(); 0606 0607 if (!doc->exportDocumentSync(exportFileName, outputMimetype.toLatin1())) { 0608 errKrita << "Could not export " << fileName << "to" << exportFileName << ":" << doc->errorMessage(); 0609 } 0610 QTimer::singleShot(0, this, SLOT(quit())); 0611 return true; 0612 } 0613 else if (exportSequence) { 0614 KisDocument *doc = kisPart->createDocument(); 0615 doc->setFileBatchMode(d->batchRun); 0616 doc->openPath(fileName); 0617 qApp->processEvents(); // For vector layers to be updated 0618 0619 if (!doc->image()->animationInterface()->hasAnimation()) { 0620 errKrita << "This file has no animation." << endl; 0621 QTimer::singleShot(0, this, SLOT(quit())); 0622 return false; 0623 } 0624 0625 doc->setFileBatchMode(true); 0626 int sequenceStart = 0; 0627 0628 KisAsyncAnimationFramesSaveDialog exporter(doc->image(), 0629 doc->image()->animationInterface()->documentPlaybackRange(), 0630 exportFileName, 0631 sequenceStart, 0632 false, 0633 0); 0634 exporter.setBatchMode(d->batchRun); 0635 KisAsyncAnimationFramesSaveDialog::Result result = 0636 exporter.regenerateRange(0); 0637 if (result != KisAsyncAnimationFramesSaveDialog::RenderComplete) { 0638 errKrita << i18n("Failed to render animation frames!") << endl; 0639 } 0640 QTimer::singleShot(0, this, SLOT(quit())); 0641 return true; 0642 } 0643 else if (d->mainWindow) { 0644 if (QFileInfo(fileName).fileName().endsWith(".bundle", Qt::CaseInsensitive)) { 0645 d->mainWindow->installBundle(fileName); 0646 } 0647 else { 0648 KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; 0649 0650 if (d->mainWindow->openDocument(fileName, flags)) { 0651 // Normal case, success 0652 numberOfOpenDocuments++; 0653 } 0654 } 0655 } 0656 } 0657 } 0658 } 0659 0660 //add an image as file-layer 0661 if (!args.fileLayer().isEmpty()){ 0662 if (d->mainWindow->viewManager()->image()){ 0663 KisFileLayer *fileLayer = new KisFileLayer(d->mainWindow->viewManager()->image(), "", 0664 args.fileLayer(), KisFileLayer::None, "Bicubic", 0665 d->mainWindow->viewManager()->image()->nextLayerName(i18n("File layer")), OPACITY_OPAQUE_U8); 0666 QFileInfo fi(fileLayer->path()); 0667 if (fi.exists()){ 0668 KisNodeCommandsAdapter adapter(d->mainWindow->viewManager()); 0669 adapter.addNode(fileLayer, d->mainWindow->viewManager()->activeNode()->parent(), 0670 d->mainWindow->viewManager()->activeNode()); 0671 } 0672 else{ 0673 QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "Krita:Warning"), 0674 i18n("Cannot add %1 as a file layer: the file does not exist.", fileLayer->path())); 0675 } 0676 } 0677 else if (this->isRunning()){ 0678 QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "Krita:Warning"), 0679 i18n("Cannot add the file layer: no document is open.\n\n" 0680 "You can create a new document using the --new-image option, or you can open an existing file.\n\n" 0681 "If you instead want to add the file layer to a document in an already running instance of Krita, check the \"Allow only one instance of Krita\" checkbox in the settings (Settings -> General -> Window).")); 0682 } 0683 else { 0684 QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "Krita: Warning"), 0685 i18n("Cannot add the file layer: no document is open.\n" 0686 "You can either create a new file using the --new-image option, or you can open an existing file.")); 0687 } 0688 } 0689 0690 // fixes BUG:369308 - Krita crashing on splash screen when loading. 0691 // trying to open a file before Krita has loaded can cause it to hang and crash 0692 if (d->splashScreen) { 0693 d->splashScreen->displayLinks(true); 0694 d->splashScreen->displayRecentFiles(true); 0695 } 0696 0697 Q_FOREACH(const QByteArray &message, d->earlyRemoteArguments) { 0698 executeRemoteArguments(message, d->mainWindow); 0699 } 0700 0701 KisUsageLogger::writeSysInfo(KisUsageLogger::screenInformation()); 0702 0703 // process File open event files 0704 if (!d->earlyFileOpenEvents.isEmpty()) { 0705 hideSplashScreen(); 0706 Q_FOREACH(QString fileName, d->earlyFileOpenEvents) { 0707 d->mainWindow->openDocument(fileName, QFlags<KisMainWindow::OpenFlag>()); 0708 } 0709 } 0710 0711 verifyMetatypeRegistration(); 0712 0713 // not calling this before since the program will quit there. 0714 return true; 0715 } 0716 0717 KisApplication::~KisApplication() 0718 { 0719 if (!isRunning()) { 0720 KisResourceCacheDb::deleteTemporaryResources(); 0721 } 0722 } 0723 0724 void KisApplication::setSplashScreen(QWidget *splashScreen) 0725 { 0726 d->splashScreen = qobject_cast<KisSplashScreen*>(splashScreen); 0727 } 0728 0729 void KisApplication::setSplashScreenLoadingText(const QString &textToLoad) 0730 { 0731 if (d->splashScreen) { 0732 d->splashScreen->setLoadingText(textToLoad); 0733 d->splashScreen->repaint(); 0734 } 0735 } 0736 0737 void KisApplication::hideSplashScreen() 0738 { 0739 if (d->splashScreen) { 0740 // hide the splashscreen to see the dialog 0741 d->splashScreen->hide(); 0742 } 0743 } 0744 0745 0746 bool KisApplication::notify(QObject *receiver, QEvent *event) 0747 { 0748 try { 0749 bool result = true; 0750 0751 /** 0752 * KisApplication::notify() is called for every event loop processed in 0753 * any thread, so we need to make sure our counters and postponed events 0754 * queues are stored in a per-thread way. 0755 */ 0756 AppRecursionInfo &info = s_recursionInfo->localData(); 0757 0758 { 0759 // QApplication::notify() can throw, so use RAII for counters 0760 AppRecursionGuard guard(&info); 0761 0762 if (event->type() == KisSynchronizedConnectionBase::eventType()) { 0763 0764 if (info.eventRecursionCount > 1) { 0765 KisSynchronizedConnectionEvent *typedEvent = static_cast<KisSynchronizedConnectionEvent*>(event); 0766 KIS_SAFE_ASSERT_RECOVER_NOOP(typedEvent->destination == receiver); 0767 0768 info.postponedSynchronizationEvents.emplace(KisSynchronizedConnectionEvent(*typedEvent)); 0769 } else { 0770 result = QApplication::notify(receiver, event); 0771 } 0772 } else { 0773 result = QApplication::notify(receiver, event); 0774 } 0775 } 0776 0777 if (!info.eventRecursionCount) { 0778 processPostponedSynchronizationEvents(); 0779 0780 } 0781 0782 return result; 0783 0784 } catch (std::exception &e) { 0785 qWarning("Error %s sending event %i to object %s", 0786 e.what(), event->type(), qPrintable(receiver->objectName())); 0787 } catch (...) { 0788 qWarning("Error <unknown> sending event %i to object %s", 0789 event->type(), qPrintable(receiver->objectName())); 0790 } 0791 return false; 0792 } 0793 0794 void KisApplication::processPostponedSynchronizationEvents() 0795 { 0796 AppRecursionInfo &info = s_recursionInfo->localData(); 0797 0798 while (!info.postponedSynchronizationEvents.empty()) { 0799 // QApplication::notify() can throw, so use RAII for counters 0800 AppRecursionGuard guard(&info); 0801 0802 /// We must pop event from the queue **before** we call 0803 /// QApplication::notify(), because it can throw! 0804 KisSynchronizedConnectionEvent typedEvent = info.postponedSynchronizationEvents.front(); 0805 info.postponedSynchronizationEvents.pop(); 0806 0807 if (!typedEvent.destination) { 0808 qWarning() << "WARNING: the destination object of KisSynchronizedConnection has been destroyed during postponed delivery"; 0809 continue; 0810 } 0811 0812 QApplication::notify(typedEvent.destination, &typedEvent); 0813 } 0814 } 0815 0816 bool KisApplication::isStoreApplication() 0817 { 0818 if (qEnvironmentVariableIsSet("STEAMAPPID") || qEnvironmentVariableIsSet("SteamAppId")) { 0819 return true; 0820 } 0821 0822 if (applicationDirPath().toLower().contains("steam")) { 0823 return true; 0824 } 0825 0826 #ifdef Q_OS_WIN 0827 // This is also true for user-installed MSIX, but that's 0828 // likely only true in institutional situations, where 0829 // we don't want to show the beggin banner either. 0830 if (KisWindowsPackageUtils::isRunningInPackage()) { 0831 return true; 0832 } 0833 #endif 0834 0835 #ifdef Q_OS_MACOS 0836 KisMacosEntitlements entitlements; 0837 if (entitlements.sandbox()) { 0838 return true; 0839 } 0840 #endif 0841 0842 return false; 0843 } 0844 0845 void KisApplication::verifyMetatypeRegistration() 0846 { 0847 /** 0848 * Veryfy that all our statically registered types are actually registered. 0849 * This check is skipped in release builds, when HIDE_SAFE_ASSERTS is defined 0850 */ 0851 #if !defined(HIDE_SAFE_ASSERTS) || defined(CRASH_ON_SAFE_ASSERTS) 0852 0853 auto verifyTypeRegistered = [] (const char *type) { 0854 const int typeId = QMetaType::type(type); 0855 0856 if (typeId <= 0) { 0857 qFatal("ERROR: type-id for metatype %s is not found", type); 0858 } 0859 0860 if (!QMetaType::isRegistered(typeId)) { 0861 qFatal("ERROR: metatype %s is not registered", type); 0862 } 0863 }; 0864 0865 verifyTypeRegistered("KisBrushSP"); 0866 verifyTypeRegistered("KoSvgText::AutoValue"); 0867 verifyTypeRegistered("KoSvgText::BackgroundProperty"); 0868 verifyTypeRegistered("KoSvgText::StrokeProperty"); 0869 verifyTypeRegistered("KoSvgText::TextTransformInfo"); 0870 verifyTypeRegistered("KoSvgText::TextIndentInfo"); 0871 verifyTypeRegistered("KoSvgText::TabSizeInfo"); 0872 verifyTypeRegistered("KoSvgText::LineHeightInfo"); 0873 verifyTypeRegistered("KisPaintopLodLimitations"); 0874 verifyTypeRegistered("KisImageSP"); 0875 verifyTypeRegistered("KisImageSignalType"); 0876 verifyTypeRegistered("KisNodeSP"); 0877 verifyTypeRegistered("KisNodeList"); 0878 verifyTypeRegistered("KisPaintDeviceSP"); 0879 verifyTypeRegistered("KisTimeSpan"); 0880 verifyTypeRegistered("KoColor"); 0881 verifyTypeRegistered("KoResourceSP"); 0882 verifyTypeRegistered("KoResourceCacheInterfaceSP"); 0883 verifyTypeRegistered("KisAsyncAnimationRendererBase::CancelReason"); 0884 verifyTypeRegistered("KisGridConfig"); 0885 verifyTypeRegistered("KisGuidesConfig"); 0886 verifyTypeRegistered("KisUpdateInfoSP"); 0887 verifyTypeRegistered("KisToolChangesTrackerDataSP"); 0888 verifyTypeRegistered("QVector<QImage>"); 0889 verifyTypeRegistered("SnapshotDirInfoList"); 0890 verifyTypeRegistered("TransformTransactionProperties"); 0891 verifyTypeRegistered("ToolTransformArgs"); 0892 verifyTypeRegistered("QPainterPath"); 0893 #endif 0894 } 0895 0896 void KisApplication::executeRemoteArguments(QByteArray message, KisMainWindow *mainWindow) 0897 { 0898 KisApplicationArguments args = KisApplicationArguments::deserialize(message); 0899 const bool doTemplate = args.doTemplate(); 0900 const bool doNewImage = args.doNewImage(); 0901 const int argsCount = args.filenames().count(); 0902 bool documentCreated = false; 0903 0904 // Create a new image, if needed 0905 if (doNewImage) { 0906 KisDocument *doc = args.createDocumentFromArguments(); 0907 if (doc) { 0908 KisPart::instance()->addDocument(doc); 0909 d->mainWindow->addViewAndNotifyLoadingCompleted(doc); 0910 } 0911 } 0912 if (argsCount > 0) { 0913 // Loop through arguments 0914 for (int argNumber = 0; argNumber < argsCount; ++argNumber) { 0915 QString filename = args.filenames().at(argNumber); 0916 // are we just trying to open a template? 0917 if (doTemplate) { 0918 documentCreated |= createNewDocFromTemplate(filename, mainWindow); 0919 } 0920 else if (QFile(filename).exists()) { 0921 KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; 0922 documentCreated |= mainWindow->openDocument(filename, flags); 0923 } 0924 } 0925 } 0926 0927 //add an image as file-layer if called in another process and singleApplication is enabled 0928 if (!args.fileLayer().isEmpty()){ 0929 if (argsCount > 0 && !documentCreated){ 0930 //arg was passed but document was not created so don't add the file layer. 0931 QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"), 0932 i18n("Couldn't open file %1",args.filenames().at(argsCount - 1))); 0933 } 0934 else if (mainWindow->viewManager()->image()){ 0935 KisFileLayer *fileLayer = new KisFileLayer(mainWindow->viewManager()->image(), "", 0936 args.fileLayer(), KisFileLayer::None, "Bicubic", 0937 mainWindow->viewManager()->image()->nextLayerName(i18n("File layer")), OPACITY_OPAQUE_U8); 0938 QFileInfo fi(fileLayer->path()); 0939 if (fi.exists()){ 0940 KisNodeCommandsAdapter adapter(d->mainWindow->viewManager()); 0941 adapter.addNode(fileLayer, d->mainWindow->viewManager()->activeNode()->parent(), 0942 d->mainWindow->viewManager()->activeNode()); 0943 } 0944 else{ 0945 QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"), 0946 i18n("Cannot add %1 as a file layer: the file does not exist.", fileLayer->path())); 0947 } 0948 } 0949 else { 0950 QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"), 0951 i18n("Cannot add the file layer: no document is open.")); 0952 } 0953 } 0954 } 0955 0956 0957 void KisApplication::remoteArguments(QByteArray message, QObject *socket) 0958 { 0959 Q_UNUSED(socket); 0960 0961 // check if we have any mainwindow 0962 KisMainWindow *mw = qobject_cast<KisMainWindow*>(qApp->activeWindow()); 0963 0964 if (!mw && KisPart::instance()->mainWindows().size() > 0) { 0965 mw = KisPart::instance()->mainWindows().first(); 0966 } 0967 0968 if (!mw) { 0969 d->earlyRemoteArguments << message; 0970 return; 0971 } 0972 executeRemoteArguments(message, mw); 0973 } 0974 0975 void KisApplication::fileOpenRequested(const QString &url) 0976 { 0977 if (!d->mainWindow) { 0978 d->earlyFileOpenEvents.append(url); 0979 return; 0980 } 0981 0982 KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; 0983 d->mainWindow->openDocument(url, flags); 0984 } 0985 0986 0987 void KisApplication::checkAutosaveFiles() 0988 { 0989 if (d->batchRun) return; 0990 0991 QDir dir = KisAutoSaveRecoveryDialog::autoSaveLocation(); 0992 0993 // Check for autosave files from a previous run. There can be several, and 0994 // we want to offer a restore for every one. Including a nice thumbnail! 0995 0996 // Hidden autosave files 0997 QStringList filters = QStringList() << QString(".krita-*-*-autosave.kra"); 0998 0999 // all autosave files for our application 1000 QStringList autosaveFiles = dir.entryList(filters, QDir::Files | QDir::Hidden); 1001 1002 // Visible autosave files 1003 filters = QStringList() << QString("krita-*-*-autosave.kra"); 1004 autosaveFiles += dir.entryList(filters, QDir::Files); 1005 1006 // Allow the user to make their selection 1007 if (autosaveFiles.size() > 0) { 1008 if (d->splashScreen) { 1009 // hide the splashscreen to see the dialog 1010 d->splashScreen->hide(); 1011 } 1012 d->autosaveDialog = new KisAutoSaveRecoveryDialog(autosaveFiles, activeWindow()); 1013 QDialog::DialogCode result = (QDialog::DialogCode) d->autosaveDialog->exec(); 1014 1015 if (result == QDialog::Accepted) { 1016 QStringList filesToRecover = d->autosaveDialog->recoverableFiles(); 1017 Q_FOREACH (const QString &autosaveFile, autosaveFiles) { 1018 if (!filesToRecover.contains(autosaveFile)) { 1019 KisUsageLogger::log(QString("Removing autosave file %1").arg(dir.absolutePath() + "/" + autosaveFile)); 1020 QFile::remove(dir.absolutePath() + "/" + autosaveFile); 1021 } 1022 } 1023 autosaveFiles = filesToRecover; 1024 } else { 1025 autosaveFiles.clear(); 1026 } 1027 1028 if (autosaveFiles.size() > 0) { 1029 QList<QString> autosavePaths; 1030 Q_FOREACH (const QString &autoSaveFile, autosaveFiles) { 1031 const QString path = dir.absolutePath() + QLatin1Char('/') + autoSaveFile; 1032 autosavePaths << path; 1033 } 1034 if (d->mainWindow) { 1035 Q_FOREACH (const QString &path, autosavePaths) { 1036 KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; 1037 d->mainWindow->openDocument(path, flags | KisMainWindow::RecoveryFile); 1038 } 1039 } 1040 } 1041 // cleanup 1042 delete d->autosaveDialog; 1043 d->autosaveDialog = nullptr; 1044 } 1045 } 1046 1047 bool KisApplication::createNewDocFromTemplate(const QString &fileName, KisMainWindow *mainWindow) 1048 { 1049 QString templatePath; 1050 1051 if (QFile::exists(fileName)) { 1052 templatePath = fileName; 1053 dbgUI << "using full path..."; 1054 } 1055 else { 1056 QString desktopName(fileName); 1057 const QString templatesResourcePath = QStringLiteral("templates/"); 1058 1059 QStringList paths = KoResourcePaths::findAllAssets("data", templatesResourcePath + "*/" + desktopName); 1060 if (paths.isEmpty()) { 1061 paths = KoResourcePaths::findAllAssets("data", templatesResourcePath + desktopName); 1062 } 1063 1064 if (paths.isEmpty()) { 1065 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita"), 1066 i18n("No template found for: %1", desktopName)); 1067 } else if (paths.count() > 1) { 1068 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita"), 1069 i18n("Too many templates found for: %1", desktopName)); 1070 } else { 1071 templatePath = paths.at(0); 1072 } 1073 } 1074 1075 if (!templatePath.isEmpty()) { 1076 KDesktopFile templateInfo(templatePath); 1077 1078 KisMainWindow::OpenFlags batchFlags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; 1079 if (mainWindow->openDocument(templatePath, KisMainWindow::Import | batchFlags)) { 1080 dbgUI << "Template loaded..."; 1081 return true; 1082 } 1083 else { 1084 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita"), 1085 i18n("Template %1 failed to load.", fileName)); 1086 } 1087 } 1088 1089 return false; 1090 } 1091 1092 void KisApplication::resetConfig() 1093 { 1094 KIS_ASSERT_RECOVER_RETURN(qApp->thread() == QThread::currentThread()); 1095 1096 KSharedConfigPtr config = KSharedConfig::openConfig(); 1097 config->markAsClean(); 1098 1099 // find user settings file 1100 const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); 1101 QString kritarcPath = configPath + QStringLiteral("/kritarc"); 1102 1103 QFile kritarcFile(kritarcPath); 1104 1105 if (kritarcFile.exists()) { 1106 if (kritarcFile.open(QFile::ReadWrite)) { 1107 QString backupKritarcPath = kritarcPath + QStringLiteral(".backup"); 1108 1109 QFile backupKritarcFile(backupKritarcPath); 1110 1111 if (backupKritarcFile.exists()) { 1112 backupKritarcFile.remove(); 1113 } 1114 1115 QMessageBox::information(qApp->activeWindow(), 1116 i18nc("@title:window", "Krita"), 1117 i18n("Krita configurations reset!\n\n" 1118 "Backup file was created at: %1\n\n" 1119 "Restart Krita for changes to take effect.", 1120 backupKritarcPath), 1121 QMessageBox::Ok, QMessageBox::Ok); 1122 1123 // clear file 1124 kritarcFile.rename(backupKritarcPath); 1125 1126 kritarcFile.close(); 1127 } 1128 else { 1129 QMessageBox::warning(qApp->activeWindow(), 1130 i18nc("@title:window", "Krita"), 1131 i18n("Failed to clear %1\n\n" 1132 "Please make sure no other program is using the file and try again.", 1133 kritarcPath), 1134 QMessageBox::Ok, QMessageBox::Ok); 1135 } 1136 } 1137 1138 // reload from disk; with the user file settings cleared, 1139 // this should load any default configuration files shipping with the program 1140 config->reparseConfiguration(); 1141 config->sync(); 1142 1143 // Restore to default workspace 1144 KConfigGroup cfg = KSharedConfig::openConfig()->group("MainWindow"); 1145 1146 QString currentWorkspace = cfg.readEntry<QString>("CurrentWorkspace", "Default"); 1147 KoResourceServer<KisWorkspaceResource> * rserver = KisResourceServerProvider::instance()->workspaceServer(); 1148 KisWorkspaceResourceSP workspace = rserver->resource("", "", currentWorkspace); 1149 1150 if (workspace) { 1151 d->mainWindow->restoreWorkspace(workspace); 1152 } 1153 } 1154 1155 void KisApplication::askResetConfig() 1156 { 1157 bool ok = QMessageBox::question(qApp->activeWindow(), 1158 i18nc("@title:window", "Krita"), 1159 i18n("Do you want to clear the settings file?"), 1160 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes; 1161 if (ok) { 1162 resetConfig(); 1163 } 1164 }