diff --git a/krita/krita4.xmlgui b/krita/krita4.xmlgui
index 49c16a698c..41673bc53b 100644
--- a/krita/krita4.xmlgui
+++ b/krita/krita4.xmlgui
@@ -1,410 +1,412 @@
&View&Canvas&Snap To&Image&Rotate&LayerNew&Import/ExportImport&Convert&Select&Group&Transform&RotateTransform &All Layers&RotateS&plitS&plit Alpha&SelectSelect &OpaqueFilte&r&ToolsScriptsSetti&ngs
+
+ &HelpFileBrushes and Stuff
diff --git a/krita/kritamenu.action b/krita/kritamenu.action
index 28584f0e39..9985e3ab16 100644
--- a/krita/kritamenu.action
+++ b/krita/kritamenu.action
@@ -1,1841 +1,1851 @@
Filedocument-new&NewCreate new documentNew00Ctrl+Nfalsedocument-open&Open...Open an existing documentOpen00Ctrl+Ofalsedocument-open-recentOpen &RecentOpen a document which was recently openedOpen Recent10falsedocument-save&SaveSaveSave10Ctrl+Sfalsedocument-save-asSave &As...Save document under a new nameSave As10Ctrl+Shift+SfalseSessions...Open session managerSessions00falsedocument-importOpen ex&isting Document as Untitled Document...Open existing Document as Untitled DocumentOpen existing Document as Untitled Document00falsedocument-exportE&xport...ExportExport10falseImport animation frames...Import animation framesImport animation frames10false&Render Animation...Render Animation to GIF, Image Sequence or VideoRender Animation10000false&Render Animation AgainRender Animation AgainRender Animation10000falseSave Incremental &VersionSave Incremental VersionSave Incremental Version10Ctrl+Alt+SfalseSave Incremental &BackupSave Incremental BackupSave Incremental Backup10F4false&Create Template From Image...Create Template From ImageCreate Template From Image10falseCreate Copy &From Current ImageCreate Copy From Current ImageCreate Copy From Current Image10falsedocument-print&Print...Print documentPrint10Ctrl+Pfalsedocument-print-previewPrint Previe&wShow a print preview of documentPrint Preview10falseconfigure&Document InformationDocument InformationDocument Information10false&Close AllClose AllClose All10Ctrl+Shift+WfalseC&loseCloseClose10Ctrl+Wfalse&QuitQuit applicationQuit00Ctrl+QfalseEditedit-undoUndoUndo last actionUndo10Ctrl+Zfalseedit-redoRedoRedo last undone actionRedo10Ctrl+Shift+Zfalseedit-cutCu&tCut selection to clipboardCut00Ctrl+Xfalseedit-copy&CopyCopy selection to clipboardCopy00Ctrl+CfalseC&opy (sharp)Copy (sharp)Copy (sharp)1000000000falseCut (&sharp)Cut (sharp)Cut (sharp)1000000000falseCopy &mergedCopy mergedCopy merged1000000000Ctrl+Shift+Cfalseedit-paste&PastePaste clipboard contentPaste00Ctrl+VfalsePaste at CursorPaste at cursorPaste at cursor00Ctrl+Alt+VfalsePaste into &New ImagePaste into New ImagePaste into New Image00Ctrl+Shift+NfalsePaste as R&eference ImagePaste as Reference ImagePaste as Reference Image10Ctrl+Shift+Rfalseedit-clearC&learClearClear10Delfalse&Fill with Foreground ColorFill with Foreground ColorFill with Foreground Color100001Shift+BackspacefalseFill &with Background ColorFill with Background ColorFill with Background Color100001BackspacefalseF&ill with PatternFill with PatternFill with Pattern100001falseFill SpecialFill with Foreground Color (Opacity)Fill with Foreground Color (Opacity)Fill with Foreground Color (Opacity)100001Ctrl+Shift+BackspacefalseFill with Background Color (Opacity)Fill with Background Color (Opacity)Fill with Background Color (Opacity)100001Ctrl+BackspacefalseFill with Pattern (Opacity)Fill with Pattern (Opacity)Fill with Pattern (Opacity)100001falseStro&ke selected shapesStroke selected shapesStroke selected shapes10000000000falseStroke Selec&tion...Stroke selectionStroke selection100000000000falseDelete keyframeDelete keyframeDelete keyframe1000000falseWindowwindow-new&New WindowNew WindowNew Window00falseN&extNextNext100falsePreviousPreviousPreviousfalseViewdocument-new&Show Canvas OnlyShow just the canvas or the whole windowShow Canvas Only00Tabtrueview-fullscreenF&ull Screen ModeDisplay the window in full screenFull Screen Mode00Ctrl+Shift+FtrueDetach canvasShow the canvas on a separate windowDetach canvas00true&Wrap Around ModeWrap Around ModeWrap Around Mode10true&Instant Preview ModeInstant Preview ModeInstant Preview Mode10Shift+LtrueSoft ProofingTurns on Soft ProofingTurns on Soft ProofingCtrl+YtrueOut of Gamut WarningsTurns on warnings for colors out of proofed gamut, needs soft proofing to be turned on.Turns on warnings for colors out of proofed gamut, needs soft proofing to be turned on.Ctrl+Shift+Ytruemirror-viewMirror ViewMirror ViewMirror ViewMfalsezoom-original&Reset zoomReset zoomReset zoom10Ctrl+0falsezoom-inZoom &InZoom In00Ctrl++falsezoom-outZoom &OutZoom Out00Ctrl+-falserotate-canvas-rightRotate &Canvas RightRotate Canvas RightRotate Canvas Right10Ctrl+]falserotate-canvas-leftRotate Canvas &LeftRotate Canvas LeftRotate Canvas Left10Ctrl+[falserotation-resetReset Canvas RotationReset Canvas RotationReset Canvas Rotation10falseShow &RulersThe rulers show the horizontal and vertical positions of the mouse on the image and can be used to position your mouse at the right place on the canvas. <p>Uncheck this to hide the rulers.</p>Show RulersShow Rulers10trueRulers Track PointerThe rulers will track current mouse position and show it on screen. It can cause suptle performance slowdownRulers Track PointerRulers Track Pointer10trueShow GuidesShow or hide guidesShow Guides10trueLock GuidesLock or unlock guidesLock Guides10trueSnap to GuidesSnap cursor to guides positionSnap to Guides10trueShow Status &BarShow or hide the status barShow Status Bar00trueShow Pixel GridShow Pixel GridShow Pixel Grid10001000trueview-gridShow &GridShow GridShow Grid10000Ctrl+Shift+'trueSnap To GridSnap To GridSnap To Grid1000Ctrl+Shift+;trueShow Snap Options PopupShow Snap Options PopupShow Snap Options Popup1000Shift+sfalseSnap OrthogonalSnap OrthogonalSnap Orthogonal1000trueSnap NodeSnap NodeSnap Node1000trueSnap ExtensionSnap ExtensionSnap Extension1000trueSnap PixelSnap PixelSnap Pixel1000trueSnap IntersectionSnap IntersectionSnap Intersection1000trueSnap Bounding BoxSnap Bounding BoxSnap Bounding Box1000trueSnap Image BoundsSnap Image BoundsSnap Image Bounds1000trueSnap Image CenterSnap Image CenterSnap Image Center1000trueS&how Painting AssistantsShow Painting AssistantsShow Painting Assistants10000trueShow &Assistant PreviewsShow Assistant PreviewsShow Assistant Previews10000trueS&how Reference ImagesShow Reference ImagesShow Reference Images10000trueImagedocument-properties&Properties...PropertiesProperties10000falseformat-stroke-color&Image Background Color and Transparency...Change the background color of the imageImage Background Color and Transparency10000false&Convert Image Color Space...Convert Image Color SpaceConvert Image Color Space10000falsetrim-to-image&Trim to Image SizeTrim to Image SizeTrim to Image Size10falseTrim to Current &LayerTrim to Current LayerTrim to Current Layer1000000falseTrim to S&electionTrim to SelectionTrim to Selection1000000000false&Rotate Image...Rotate ImageRotate Image10000falseobject-rotate-rightRotate &Image 90° to the RightRotate Image 90° to the RightRotate Image 90° to the Right10000falseobject-rotate-leftRotate Image &90° to the LeftRotate Image 90° to the LeftRotate Image 90° to the Left10000falseRotate Image &180°Rotate Image 180°Rotate Image 180°10000false&Shear Image...Shear ImageShear Image10000falsesymmetry-horizontal&Mirror Image HorizontallyMirror Image HorizontallyMirror Image Horizontally10000falsesymmetry-verticalMirror Image &VerticallyMirror Image VerticallyMirror Image Vertically10000falseScale Image To &New Size...Scale Image To New SizeScale Image To New Size10000Ctrl+Alt+Ifalse&Offset Image...Offset ImageOffset Image10000falseR&esize Canvas...Resize CanvasResize Canvas10000Ctrl+Alt+CfalseIm&age Split Image SplitImage Split10000falseSeparate Ima&ge...Separate ImageSeparate Image10000falseSelectedit-select-allSelect &AllSelect AllSelect All00Ctrl+Afalseedit-select-none&DeselectDeselectDeselect11000000000Ctrl+Shift+Afalse&ReselectReselectReselect00Ctrl+Shift+Dfalse&Convert to Vector SelectionConvert to Vector SelectionConvert to Vector Selection1000000000000000000false&Convert to Raster SelectionConvert to Raster SelectionConvert to Raster Selection100000000000000000falseEdit SelectionEdit SelectionEdit Selection10000000000100falseConvert Shapes to &Vector SelectionConvert Shapes to Vector SelectionConvert Shapes to Vector Selection10000000000false&Feather Selection...Feather SelectionFeather Selection10000000000100Shift+F6falseDis&play SelectionDisplay SelectionDisplay Selection10000Ctrl+HtrueSca&le...ScaleScale100000000100falseS&elect from Color Range...Select from Color RangeSelect from Color Range10000100falseSelect &Opaque (Replace)Select OpaqueSelect Opaque1100falseSelect Opaque (&Add)Select Opaque (Add)Select Opaque (Add)1100falseSelect Opaque (&Subtract)Select Opaque (Subtract)Select Opaque (Subtract)1100falseSelect Opaque (&Intersect)Select Opaque (Intersect)Select Opaque (Intersect)1100false&Grow Selection...Grow SelectionGrow Selection10000000000100falseS&hrink Selection...Shrink SelectionShrink Selection10000000000100false&Border Selection...Border SelectionBorder Selection10000000000100falseS&moothSmoothSmooth10000000000100falseFilter&Apply Filter AgainApply Filter AgainApply Filter Again00Ctrl+FfalseAdjustAdjustAdjustfalseArtisticArtisticArtisticfalseBlurBlurBlurfalseColorsColorsColorsfalseEdge DetectionEdge DetectionEdge DetectionfalseEnhanceEnhanceEnhancefalseEmbossEmbossEmbossfalseMapMapMapfalseOtherOtherOtherfalsegmicStart G'MIC-QtStart G'Mic-QtStart G'Mic-QtfalsegmicRe-apply the last G'MIC filterApply the last G'Mic-Qt action againApply the last G'Mic-Qt action againfalseSettingsconfigure&Configure Krita...Configure KritaConfigure Krita00false&Manage Resources...Manage ResourcesManage Resources00falsepreferences-desktop-localeSwitch Application &Language...Switch Application LanguageSwitch Application Languagefalse&Show DockersShow DockersShow Dockers00trueconfigureConfigure Tool&bars...Configure ToolbarsConfigure Toolbars00falseDockersDockersDockersfalse&ThemesThemesThemesfalseim-userActive Author ProfileActive Author ProfileActive Author Profile
+
+
+ Reset Krita Configurations
+
+ Reset Krita Configurations
+ Reset Krita Configurations
+
+ false
+
+ configure-shortcutsConfigure S&hortcuts...Configure ShortcutsConfigure Shortcuts00false&WindowWindowWindowfalseHelphelp-contentsKrita &HandbookKrita HandbookKrita HandbookF1falsetools-report-bug&Report Bug...Report BugReport Bugfalsekrita&About KritaAbout KritaAbout KritafalsekdeAbout &KDEAbout KDEAbout KDEfalseBrushes and Stuff&GradientsGradientsGradientsfalse&PatternsPatternsPatternsfalse&ColorColorColorfalse&Painter's ToolsPainter's ToolsPainter's ToolsfalseBrush compositeBrush compositeBrush compositefalseBrush option slider 1Brush option slider 1Brush option slider 1falseBrush option slider 2Brush option slider 2Brush option slider 2falseBrush option slider 3Brush option slider 3Brush option slider 3falseMirrorMirrorMirrorfalseLayoutsSelect layoutfalseWorkspacesWorkspacesWorkspacesfalse
diff --git a/krita/main.cc b/krita/main.cc
index 908f7abe03..1d04a71b14 100644
--- a/krita/main.cc
+++ b/krita/main.cc
@@ -1,610 +1,605 @@
/*
* Copyright (c) 1999 Matthias Elter
* Copyright (c) 2002 Patrick Julien
* Copyright (c) 2015 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "data/splash/splash_screen.xpm"
#include "data/splash/splash_holidays.xpm"
#include "data/splash/splash_screen_x2.xpm"
#include "data/splash/splash_holidays_x2.xpm"
#include "KisDocument.h"
#include "kis_splash_screen.h"
#include "KisPart.h"
#include "KisApplicationArguments.h"
#include
#include "input/KisQtWidgetsTweaker.h"
#include
#include
#ifdef Q_OS_ANDROID
#include
#endif
#if defined Q_OS_WIN
#include "config_use_qt_tablet_windows.h"
#include
#ifndef USE_QT_TABLET_WINDOWS
#include
#include
#else
#include
#endif
#include "config-high-dpi-scale-factor-rounding-policy.h"
#include "config-set-has-border-in-full-screen-default.h"
#ifdef HAVE_SET_HAS_BORDER_IN_FULL_SCREEN_DEFAULT
#include
#endif
#include
#endif
#if defined HAVE_KCRASH
#include
#elif defined USE_DRMINGW
namespace
{
void tryInitDrMingw()
{
wchar_t path[MAX_PATH];
QString pathStr = QCoreApplication::applicationDirPath().replace(L'/', L'\\') + QStringLiteral("\\exchndl.dll");
if (pathStr.size() > MAX_PATH - 1) {
return;
}
int pathLen = pathStr.toWCharArray(path);
path[pathLen] = L'\0'; // toWCharArray doesn't add NULL terminator
HMODULE hMod = LoadLibraryW(path);
if (!hMod) {
return;
}
// No need to call ExcHndlInit since the crash handler is installed on DllMain
auto myExcHndlSetLogFileNameA = reinterpret_cast(GetProcAddress(hMod, "ExcHndlSetLogFileNameA"));
if (!myExcHndlSetLogFileNameA) {
return;
}
// Set the log file path to %LocalAppData%\kritacrash.log
QString logFile = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation).replace(L'/', L'\\') + QStringLiteral("\\kritacrash.log");
myExcHndlSetLogFileNameA(logFile.toLocal8Bit());
}
} // namespace
#endif
#ifdef Q_OS_WIN
namespace
{
typedef enum ORIENTATION_PREFERENCE {
ORIENTATION_PREFERENCE_NONE = 0x0,
ORIENTATION_PREFERENCE_LANDSCAPE = 0x1,
ORIENTATION_PREFERENCE_PORTRAIT = 0x2,
ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED = 0x4,
ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED = 0x8
} ORIENTATION_PREFERENCE;
typedef BOOL WINAPI (*pSetDisplayAutoRotationPreferences_t)(
ORIENTATION_PREFERENCE orientation
);
void resetRotation()
{
QLibrary user32Lib("user32");
if (!user32Lib.load()) {
qWarning() << "Failed to load user32.dll! This really should not happen.";
return;
}
pSetDisplayAutoRotationPreferences_t pSetDisplayAutoRotationPreferences
= reinterpret_cast(user32Lib.resolve("SetDisplayAutoRotationPreferences"));
if (!pSetDisplayAutoRotationPreferences) {
dbgKrita << "Failed to load function SetDisplayAutoRotationPreferences";
return;
}
bool result = pSetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE_NONE);
dbgKrita << "SetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE_NONE) returned" << result;
}
} // namespace
#endif
#ifdef Q_OS_ANDROID
extern "C" JNIEXPORT void JNICALL
Java_org_krita_android_JNIWrappers_saveState(JNIEnv* /*env*/,
jobject /*obj*/,
jint /*n*/)
{
if (!KisPart::exists()) return;
KisPart *kisPart = KisPart::instance();
QList> list = kisPart->documents();
for (QPointer &doc: list)
{
doc->autoSaveOnPause();
}
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
kritarc.setValue("canvasState", "OPENGL_SUCCESS");
}
extern "C" JNIEXPORT void JNICALL
Java_org_krita_android_JNIWrappers_exitFullScreen(JNIEnv* /*env*/,
jobject /*obj*/,
jint /*n*/)
{
if (!KisPart::exists()) return;
KisMainWindow *mainWindow = KisPart::instance()->currentMainwindow();
mainWindow->viewFullscreen(false);
}
__attribute__ ((visibility ("default")))
#endif
extern "C" int main(int argc, char **argv)
{
// The global initialization of the random generator
qsrand(time(0));
bool runningInKDE = !qgetenv("KDE_FULL_SESSION").isEmpty();
#if defined HAVE_X11
qputenv("QT_QPA_PLATFORM", "xcb");
#endif
// Workaround a bug in QNetworkManager
qputenv("QT_BEARER_POLL_TIMEOUT", QByteArray::number(-1));
// A per-user unique string, without /, because QLocalServer cannot use names with a / in it
QString key = "Krita4" + QStandardPaths::writableLocation(QStandardPaths::HomeLocation).replace("/", "_");
key = key.replace(":", "_").replace("\\","_");
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true);
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
QCoreApplication::setAttribute(Qt::AA_DisableShaderDiskCache, true);
#ifdef HAVE_HIGH_DPI_SCALE_FACTOR_ROUNDING_POLICY
// This rounding policy depends on a series of patches to Qt related to
// https://bugreports.qt.io/browse/QTBUG-53022. These patches are applied
// in ext_qt for WIndows (patches 0031-0036).
//
// The rounding policy can be set externally by setting the environment
// variable `QT_SCALE_FACTOR_ROUNDING_POLICY` to one of the following:
// Round: Round up for .5 and above.
// Ceil: Always round up.
// Floor: Always round down.
// RoundPreferFloor: Round up for .75 and above.
// PassThrough: Don't round.
//
// The default is set to RoundPreferFloor for better behaviour than before,
// but can be overridden by the above environment variable.
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor);
#endif
#ifdef Q_OS_ANDROID
const QString write_permission = "android.permission.WRITE_EXTERNAL_STORAGE";
const QStringList permissions = { write_permission };
const QtAndroid::PermissionResultMap resultHash =
QtAndroid::requestPermissionsSync(QStringList(permissions));
if (resultHash[write_permission] == QtAndroid::PermissionResult::Denied) {
// TODO: show a dialog and graciously exit
dbgKrita << "Permission denied by the user";
}
else {
dbgKrita << "Permission granted";
}
#endif
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
bool singleApplication = true;
bool enableOpenGLDebug = false;
bool openGLDebugSynchronous = false;
bool logUsage = true;
{
singleApplication = kritarc.value("EnableSingleApplication", true).toBool();
if (kritarc.value("EnableHiDPI", true).toBool()) {
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
}
if (!qgetenv("KRITA_HIDPI").isEmpty()) {
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
}
#ifdef HAVE_HIGH_DPI_SCALE_FACTOR_ROUNDING_POLICY
if (kritarc.value("EnableHiDPIFractionalScaling", true).toBool()) {
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
}
#endif
if (!qgetenv("KRITA_OPENGL_DEBUG").isEmpty()) {
enableOpenGLDebug = true;
} else {
enableOpenGLDebug = kritarc.value("EnableOpenGLDebug", false).toBool();
}
if (enableOpenGLDebug && (qgetenv("KRITA_OPENGL_DEBUG") == "sync" || kritarc.value("OpenGLDebugSynchronous", false).toBool())) {
openGLDebugSynchronous = true;
}
KisConfig::RootSurfaceFormat rootSurfaceFormat = KisConfig::rootSurfaceFormat(&kritarc);
KisOpenGL::OpenGLRenderer preferredRenderer = KisOpenGL::RendererAuto;
logUsage = kritarc.value("LogUsage", true).toBool();
#ifdef Q_OS_WIN
const QString preferredRendererString = kritarc.value("OpenGLRenderer", "angle").toString();
#else
const QString preferredRendererString = kritarc.value("OpenGLRenderer", "auto").toString();
#endif
preferredRenderer = KisOpenGL::convertConfigToOpenGLRenderer(preferredRendererString);
const KisOpenGL::RendererConfig config =
KisOpenGL::selectSurfaceConfig(preferredRenderer, rootSurfaceFormat, enableOpenGLDebug);
KisOpenGL::setDefaultSurfaceConfig(config);
KisOpenGL::setDebugSynchronous(openGLDebugSynchronous);
#ifdef Q_OS_WIN
// HACK: https://bugs.kde.org/show_bug.cgi?id=390651
resetRotation();
#endif
}
if (logUsage) {
KisUsageLogger::initialize();
}
QString root;
QString language;
{
// Create a temporary application to get the root
QCoreApplication app(argc, argv);
Q_UNUSED(app);
root = KoResourcePaths::getApplicationRoot();
QSettings languageoverride(configPath + QStringLiteral("/klanguageoverridesrc"), QSettings::IniFormat);
languageoverride.beginGroup(QStringLiteral("Language"));
language = languageoverride.value(qAppName(), "").toString();
}
#ifdef Q_OS_LINUX
{
QByteArray originalXdgDataDirs = qgetenv("XDG_DATA_DIRS");
if (originalXdgDataDirs.isEmpty()) {
// We don't want to completely override the default
originalXdgDataDirs = "/usr/local/share/:/usr/share/";
}
qputenv("XDG_DATA_DIRS", QFile::encodeName(root + "share") + ":" + originalXdgDataDirs);
}
#else
qputenv("XDG_DATA_DIRS", QFile::encodeName(root + "share"));
#endif
dbgKrita << "Setting XDG_DATA_DIRS" << qgetenv("XDG_DATA_DIRS");
// Now that the paths are set, set the language. First check the override from the language
// selection dialog.
dbgKrita << "Override language:" << language;
bool rightToLeft = false;
if (!language.isEmpty()) {
KLocalizedString::setLanguages(language.split(":"));
// And override Qt's locale, too
QLocale locale(language.split(":").first());
QLocale::setDefault(locale);
#ifdef Q_OS_MAC
// prevents python >=3.7 nl_langinfo(CODESET) fail bug 417312.
qputenv("LANG", (locale.name() + ".UTF-8").toLocal8Bit());
#else
qputenv("LANG", locale.name().toLocal8Bit());
#endif
const QStringList rtlLanguages = QStringList()
<< "ar" << "dv" << "he" << "ha" << "ku" << "fa" << "ps" << "ur" << "yi";
if (rtlLanguages.contains(language.split(':').first())) {
rightToLeft = true;
}
}
else {
dbgKrita << "Qt UI languages:" << QLocale::system().uiLanguages() << qgetenv("LANG");
// And if there isn't one, check the one set by the system.
QLocale locale = QLocale::system();
if (locale.name() != QStringLiteral("en")) {
QStringList uiLanguages = locale.uiLanguages();
for (QString &uiLanguage : uiLanguages) {
// This list of language codes that can have a specifier should
// be extended whenever we have translations that need it; right
// now, only en, pt, zh are in this situation.
if (uiLanguage.startsWith("en") || uiLanguage.startsWith("pt")) {
uiLanguage.replace(QChar('-'), QChar('_'));
}
else if (uiLanguage.startsWith("zh-Hant") || uiLanguage.startsWith("zh-TW")) {
uiLanguage = "zh_TW";
}
else if (uiLanguage.startsWith("zh-Hans") || uiLanguage.startsWith("zh-CN")) {
uiLanguage = "zh_CN";
}
}
if (uiLanguages.size() > 0 ) {
QString envLanguage = uiLanguages.first();
envLanguage.replace(QChar('-'), QChar('_'));
for (int i = 0; i < uiLanguages.size(); i++) {
QString uiLanguage = uiLanguages[i];
// Strip the country code
int idx = uiLanguage.indexOf(QChar('-'));
if (idx != -1) {
uiLanguage = uiLanguage.left(idx);
uiLanguages.replace(i, uiLanguage);
}
}
dbgKrita << "Converted ui languages:" << uiLanguages;
#ifdef Q_OS_MAC
// See https://bugs.kde.org/show_bug.cgi?id=396370
KLocalizedString::setLanguages(QStringList() << uiLanguages.first());
qputenv("LANG", (envLanguage + ".UTF-8").toLocal8Bit());
#else
KLocalizedString::setLanguages(QStringList() << uiLanguages);
qputenv("LANG", envLanguage.toLocal8Bit());
#endif
}
}
}
#if defined Q_OS_WIN && defined USE_QT_TABLET_WINDOWS && defined QT_HAS_WINTAB_SWITCH
const bool forceWinTab = !KisConfig::useWin8PointerInputNoApp(&kritarc);
QCoreApplication::setAttribute(Qt::AA_MSWindowsUseWinTabAPI, forceWinTab);
if (qEnvironmentVariableIsEmpty("QT_WINTAB_DESKTOP_RECT") &&
qEnvironmentVariableIsEmpty("QT_IGNORE_WINTAB_MAPPING")) {
QRect customTabletRect;
KisDlgCustomTabletResolution::Mode tabletMode =
KisDlgCustomTabletResolution::getTabletMode(&customTabletRect);
KisDlgCustomTabletResolution::applyConfiguration(tabletMode, customTabletRect);
}
#endif
// first create the application so we can create a pixmap
KisApplication app(key, argc, argv);
KisUsageLogger::writeHeader();
KisOpenGL::initialize();
#ifdef HAVE_SET_HAS_BORDER_IN_FULL_SCREEN_DEFAULT
if (QCoreApplication::testAttribute(Qt::AA_UseDesktopOpenGL)) {
QWindowsWindowFunctions::setHasBorderInFullScreenDefault(true);
}
#endif
if (!language.isEmpty()) {
if (rightToLeft) {
app.setLayoutDirection(Qt::RightToLeft);
}
else {
app.setLayoutDirection(Qt::LeftToRight);
}
}
KLocalizedString::setApplicationDomain("krita");
dbgKrita << "Available translations" << KLocalizedString::availableApplicationTranslations();
dbgKrita << "Available domain translations" << KLocalizedString::availableDomainTranslations("krita");
#ifdef Q_OS_WIN
QDir appdir(KoResourcePaths::getApplicationRoot());
QString path = qgetenv("PATH");
qputenv("PATH", QFile::encodeName(appdir.absolutePath() + "/bin" + ";"
+ appdir.absolutePath() + "/lib" + ";"
+ appdir.absolutePath() + "/Frameworks" + ";"
+ appdir.absolutePath() + ";"
+ path));
dbgKrita << "PATH" << qgetenv("PATH");
#endif
if (qApp->applicationDirPath().contains(KRITA_BUILD_DIR)) {
qFatal("FATAL: You're trying to run krita from the build location. You can only run Krita from the installation location.");
}
#if defined HAVE_KCRASH
KCrash::initialize();
#elif defined USE_DRMINGW
tryInitDrMingw();
#endif
- // If we should clear the config, it has to be done as soon as possible after
- // KisApplication has been created. Otherwise the config file may have been read
- // and stored in a KConfig object we have no control over.
- app.askClearConfig();
-
KisApplicationArguments args(app);
if (singleApplication && app.isRunning()) {
// only pass arguments to main instance if they are not for batch processing
// any batch processing would be done in this separate instance
const bool batchRun = args.exportAs() || args.exportSequence();
if (!batchRun) {
QByteArray ba = args.serialize();
if (app.sendMessage(ba)) {
return 0;
}
}
}
if (!runningInKDE) {
// Icons in menus are ugly and distracting
app.setAttribute(Qt::AA_DontShowIconsInMenus);
}
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
app.setAttribute(Qt::AA_DisableWindowContextHelpButton);
#endif
app.installEventFilter(KisQtWidgetsTweaker::instance());
if (!args.noSplash()) {
// then create the pixmap from an xpm: we cannot get the
// location of our datadir before we've started our components,
// so use an xpm.
QDate currentDate = QDate::currentDate();
QWidget *splash = 0;
if (currentDate > QDate(currentDate.year(), 12, 4) ||
currentDate < QDate(currentDate.year(), 1, 9)) {
splash = new KisSplashScreen(app.applicationVersion(), QPixmap(splash_holidays_xpm), QPixmap(splash_holidays_x2_xpm));
}
else {
splash = new KisSplashScreen(app.applicationVersion(), QPixmap(splash_screen_xpm), QPixmap(splash_screen_x2_xpm));
}
app.setSplashScreen(splash);
}
#if defined Q_OS_WIN
KisConfig cfg(false);
bool supportedWindowsVersion = true;
QOperatingSystemVersion osVersion = QOperatingSystemVersion::current();
if (osVersion.type() == QOperatingSystemVersion::Windows) {
if (osVersion.majorVersion() >= QOperatingSystemVersion::Windows7.majorVersion()) {
supportedWindowsVersion = true;
}
else {
supportedWindowsVersion = false;
if (cfg.readEntry("WarnedAboutUnsupportedWindows", false)) {
QMessageBox::information(0,
i18nc("@title:window", "Krita: Warning"),
i18n("You are running an unsupported version of Windows: %1.\n"
"This is not recommended. Do not report any bugs.\n"
"Please update to a supported version of Windows: Windows 7, 8, 8.1 or 10.", osVersion.name()));
cfg.writeEntry("WarnedAboutUnsupportedWindows", true);
}
}
}
#ifndef USE_QT_TABLET_WINDOWS
{
if (cfg.useWin8PointerInput() && !KisTabletSupportWin8::isAvailable()) {
cfg.setUseWin8PointerInput(false);
}
if (!cfg.useWin8PointerInput()) {
bool hasWinTab = KisTabletSupportWin::init();
if (!hasWinTab && supportedWindowsVersion) {
if (KisTabletSupportWin8::isPenDeviceAvailable()) {
// Use WinInk automatically
cfg.setUseWin8PointerInput(true);
} else if (!cfg.readEntry("WarnedAboutMissingWinTab", false)) {
if (KisTabletSupportWin8::isAvailable()) {
QMessageBox::information(nullptr,
i18n("Krita Tablet Support"),
i18n("Cannot load WinTab driver and no Windows Ink pen devices are found. If you have a drawing tablet, please make sure the tablet driver is properly installed."),
QMessageBox::Ok, QMessageBox::Ok);
} else {
QMessageBox::information(nullptr,
i18n("Krita Tablet Support"),
i18n("Cannot load WinTab driver. If you have a drawing tablet, please make sure the tablet driver is properly installed."),
QMessageBox::Ok, QMessageBox::Ok);
}
cfg.writeEntry("WarnedAboutMissingWinTab", true);
}
}
}
if (cfg.useWin8PointerInput()) {
KisTabletSupportWin8 *penFilter = new KisTabletSupportWin8();
if (penFilter->init()) {
// penFilter.registerPointerDeviceNotifications();
app.installNativeEventFilter(penFilter);
dbgKrita << "Using Win8 Pointer Input for tablet support";
} else {
dbgKrita << "No Win8 Pointer Input available";
delete penFilter;
}
}
}
#elif defined QT_HAS_WINTAB_SWITCH
// Check if WinTab/WinInk has actually activated
const bool useWinTabAPI = app.testAttribute(Qt::AA_MSWindowsUseWinTabAPI);
if (useWinTabAPI != !cfg.useWin8PointerInput()) {
cfg.setUseWin8PointerInput(useWinTabAPI);
}
#endif
#endif
app.setAttribute(Qt::AA_CompressHighFrequencyEvents, false);
// Set up remote arguments.
QObject::connect(&app, SIGNAL(messageReceived(QByteArray,QObject*)),
&app, SLOT(remoteArguments(QByteArray,QObject*)));
QObject::connect(&app, SIGNAL(fileOpenRequest(QString)),
&app, SLOT(fileOpenRequested(QString)));
// Hardware information
KisUsageLogger::writeSysInfo("\nHardware Information\n");
KisUsageLogger::writeSysInfo(QString(" GPU Acceleration: %1").arg(kritarc.value("OpenGLRenderer", "auto").toString()));
KisUsageLogger::writeSysInfo(QString(" Memory: %1 Mb").arg(KisImageConfig(true).totalRAM()));
KisUsageLogger::writeSysInfo(QString(" Number of Cores: %1").arg(QThread::idealThreadCount()));
KisUsageLogger::writeSysInfo(QString(" Swap Location: %1\n").arg(KisImageConfig(true).swapDir()));
KisConfig(true).logImportantSettings();
if (!app.start(args)) {
KisUsageLogger::log("Could not start Krita Application");
return 1;
}
int state = app.exec();
{
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
kritarc.setValue("canvasState", "OPENGL_SUCCESS");
}
if (logUsage) {
KisUsageLogger::close();
}
return state;
}
diff --git a/libs/ui/KisApplication.cpp b/libs/ui/KisApplication.cpp
index daba3f8856..26e91a7238 100644
--- a/libs/ui/KisApplication.cpp
+++ b/libs/ui/KisApplication.cpp
@@ -1,991 +1,1017 @@
/*
* 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_MACOS
#include "osx.h"
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "KoConfig.h"
#include
#include
#include "thememanager.h"
#include "KisPrintJob.h"
#include "KisDocument.h"
#include "KisMainWindow.h"
#include "KisAutoSaveRecoveryDialog.h"
#include "KisPart.h"
#include
#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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "widgets/KisScreenColorPicker.h"
#include "KisDlgInternalColorSelector.h"
#include
#include
#include "kis_file_layer.h"
#include "kis_group_layer.h"
#include "kis_node_commands_adapter.h"
#include
namespace {
const QTime appStartTime(QTime::currentTime());
}
class KisApplication::Private
{
public:
Private() {}
QPointer splashScreen;
KisAutoSaveRecoveryDialog *autosaveDialog {0};
QPointer mainWindow; // The first mainwindow we create on startup
bool batchRun {false};
QVector earlyRemoteArguments;
};
class KisApplication::ResetStarting
{
public:
ResetStarting(KisSplashScreen *splash, int fileCount)
: m_splash(splash)
, m_fileCount(fileCount)
{
}
~ResetStarting() {
if (m_splash) {
m_splash->hide();
}
}
QPointer m_splash;
int m_fileCount;
};
KisApplication::KisApplication(const QString &key, int &argc, char **argv)
: QtSingleApplication(key, argc, argv)
, d(new Private)
{
#ifdef Q_OS_MACOS
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("krita"));
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();
}
}
#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("markers", "data", "/styles/");
KoResourcePaths::addResourceType("kis_pics", "data", "/pics/");
KoResourcePaths::addResourceType("kis_images", "data", "/images/");
KoResourcePaths::addResourceType("metadata_schema", "data", "/metadata/schemas/");
KoResourcePaths::addResourceType(ResourceType::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(ResourceType::PaintOpPresets, "data", "/paintoppresets/");
KoResourcePaths::addResourceType(ResourceType::Workspaces, "data", "/workspaces/");
KoResourcePaths::addResourceType(ResourceType::WindowLayouts, "data", "/windowlayouts/");
KoResourcePaths::addResourceType(ResourceType::Sessions, "data", "/sessions/");
KoResourcePaths::addResourceType("psd_layer_style_collections", "data", "/asl");
KoResourcePaths::addResourceType(ResourceType::Patterns, "data", "/patterns/", true);
KoResourcePaths::addResourceType(ResourceType::Gradients, "data", "/gradients/");
KoResourcePaths::addResourceType(ResourceType::Gradients, "data", "/gradients/", true);
KoResourcePaths::addResourceType(ResourceType::Palettes, "data", "/palettes/", true);
KoResourcePaths::addResourceType("kis_shortcuts", "data", "/shortcuts/");
KoResourcePaths::addResourceType("kis_actions", "data", "/actions");
KoResourcePaths::addResourceType("kis_actions", "data", "/pykrita");
KoResourcePaths::addResourceType("icc_profiles", "data", "/color/icc");
KoResourcePaths::addResourceType("icc_profiles", "data", "/profiles/");
KoResourcePaths::addResourceType(ResourceType::FilterEffects, "data", "/effects/");
KoResourcePaths::addResourceType("tags", "data", "/tags/");
KoResourcePaths::addResourceType("templates", "data", "/templates");
KoResourcePaths::addResourceType("pythonscripts", "data", "/pykrita");
KoResourcePaths::addResourceType(ResourceType::Symbols, "data", "/symbols");
KoResourcePaths::addResourceType("preset_icons", "data", "/preset_icons");
KoResourcePaths::addResourceType(ResourceType::GamutMasks, "data", "/gamutmasks/", true);
// // Extra directories to look for create resources. (Does anyone actually use that anymore?)
// KoResourcePaths::addResourceDir(ResourceType::Gradients, "/usr/share/create/gradients/gimp");
// KoResourcePaths::addResourceDir(ResourceType::Gradients, QDir::homePath() + QString("/.create/gradients/gimp"));
// KoResourcePaths::addResourceDir(ResourceType::Patterns, "/usr/share/create/patterns/gimp");
// KoResourcePaths::addResourceDir(ResourceType::Patterns, QDir::homePath() + QString("/.create/patterns/gimp"));
// KoResourcePaths::addResourceDir(ResourceType::Brushes, "/usr/share/create/brushes/gimp");
// KoResourcePaths::addResourceDir(ResourceType::Brushes, QDir::homePath() + QString("/.create/brushes/gimp"));
// KoResourcePaths::addResourceDir(ResourceType::Palettes, "/usr/share/create/swatches");
// KoResourcePaths::addResourceDir(ResourceType::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/");
// between 4.2.x and 4.3.0 there was a change from 'taskset' to 'tasksets'
// so to make older resource folders compatible with the new version, let's rename the folder
// so no tasksets are lost.
if (d.exists(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/taskset/")) {
d.rename(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/taskset/",
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tasksets/");
}
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tasksets/");
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/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/gamutmasks/");
}
bool KisApplication::registerResources()
{
KisResourceLoaderRegistry *reg = KisResourceLoaderRegistry::instance();
reg->add(new KisResourceLoader(ResourceType::PaintOpPresets, ResourceType::PaintOpPresets, i18n("Brush presets"), QStringList() << "application/x-krita-paintoppreset"));
reg->add(new KisResourceLoader(ResourceSubType::GbrBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/x-gimp-brush"));
reg->add(new KisResourceLoader(ResourceSubType::GihBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/x-gimp-brush-animated"));
reg->add(new KisResourceLoader(ResourceSubType::SvgBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/svg+xml"));
reg->add(new KisResourceLoader(ResourceSubType::PngBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/png"));
reg->add(new KisResourceLoader(ResourceSubType::SegmentedGradients, ResourceType::Gradients, i18n("Gradients"), QStringList() << "application/x-gimp-gradient"));
reg->add(new KisResourceLoader(ResourceSubType::StopGradients, ResourceType::Gradients, i18n("Gradients"), QStringList() << "application/x-karbon-gradient" << "image/svg+xml"));
reg->add(new KisResourceLoader(ResourceType::Palettes, ResourceType::Palettes, i18n("Palettes"),
QStringList() << KisMimeDatabase::mimeTypeForSuffix("kpl")
<< KisMimeDatabase::mimeTypeForSuffix("gpl")
<< KisMimeDatabase::mimeTypeForSuffix("pal")
<< KisMimeDatabase::mimeTypeForSuffix("act")
<< KisMimeDatabase::mimeTypeForSuffix("aco")
<< KisMimeDatabase::mimeTypeForSuffix("css")
<< KisMimeDatabase::mimeTypeForSuffix("colors")
<< KisMimeDatabase::mimeTypeForSuffix("xml")
<< KisMimeDatabase::mimeTypeForSuffix("sbz")));
QList src = QImageReader::supportedMimeTypes();
QStringList allImageMimes;
Q_FOREACH(const QByteArray ba, src) {
if (QImageWriter::supportedMimeTypes().contains(ba)) {
allImageMimes << QString::fromUtf8(ba);
}
}
allImageMimes << KisMimeDatabase::mimeTypeForSuffix("pat");
reg->add(new KisResourceLoader(ResourceType::Patterns, ResourceType::Patterns, i18n("Patterns"), allImageMimes));
reg->add(new KisResourceLoader(ResourceType::Workspaces, ResourceType::Workspaces, i18n("Workspaces"), QStringList() << "application/x-krita-workspace"));
reg->add(new KisResourceLoader(ResourceType::Symbols, ResourceType::Symbols, i18n("SVG symbol libraries"), QStringList() << "image/svg+xml"));
reg->add(new KisResourceLoader(ResourceType::WindowLayouts, ResourceType::WindowLayouts, i18n("Window layouts"), QStringList() << "application/x-krita-windowlayout"));
reg->add(new KisResourceLoader(ResourceType::Sessions, ResourceType::Sessions, i18n("Sessions"), QStringList() << "application/x-krita-session"));
reg->add(new KisResourceLoader(ResourceType::GamutMasks, ResourceType::GamutMasks, i18n("Gamut masks"), QStringList() << "application/x-krita-gamutmasks"));
reg->add(new KisResourceLoader(ResourceType::LayerStyles,
ResourceType::LayerStyles,
ResourceType::LayerStyles,
QStringList() << "application/x-photoshop-style"));
if (!KisResourceCacheDb::initialize(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))) {
QMessageBox::critical(0, i18nc("@title:window", "Krita: Fatal error"), i18n("%1\n\nKrita will quit now.", KisResourceCacheDb::lastError()));
//return false;
}
KisResourceLocator::LocatorError r = KisResourceLocator::instance()->initialize(KoResourcePaths::getApplicationRoot() + "/share/krita");
connect(KisResourceLocator::instance(), SIGNAL(progressMessage(const QString&)), this, SLOT(setSplashScreenLoadingText(const QString&)));
if (r != KisResourceLocator::LocatorError::Ok ) {
QMessageBox::critical(0, i18nc("@title:window", "Krita: Fatal error"), KisResourceLocator::instance()->errorMessages().join('\n') + i18n("\n\nKrita will quit now."));
//return false;
}
return true;
}
void KisApplication::loadPlugins()
{
// qDebug() << "loadPlugins();";
KoShapeRegistry* r = KoShapeRegistry::instance();
r->add(new KisShapeSelectionFactory());
KoColorSpaceRegistry::instance();
KisActionRegistry::instance();
KisFilterRegistry::instance();
KisGeneratorRegistry::instance();
KisPaintOpRegistry::instance();
KoToolRegistry::instance();
KoDockRegistry::instance();
}
void KisApplication::loadGuiPlugins()
{
// 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(false);
#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" && opengl != "TRY_OPENGL") {
cfg.setCanvasState("OPENGL_FAILED");
}
setSplashScreenLoadingText(i18n("Initializing Globals"));
processEvents();
initializeGlobals(args);
const bool doNewImage = args.doNewImage();
const bool doTemplate = args.doTemplate();
const bool exportAs = args.exportAs();
const bool exportSequence = args.exportSequence();
const QString exportFileName = args.exportFileName();
d->batchRun = (exportAs || exportSequence || !exportFileName.isEmpty());
const bool needsMainWindow = (!exportAs && !exportSequence);
// only show the mainWindow when no command-line mode option is passed
bool showmainWindow = (!exportAs && !exportSequence); // would be !batchRun;
const bool showSplashScreen = !d->batchRun && qEnvironmentVariableIsEmpty("NOSPLASH");
if (showSplashScreen && d->splashScreen) {
d->splashScreen->show();
d->splashScreen->repaint();
processEvents();
}
KConfigGroup group(KSharedConfig::openConfig(), "theme");
Digikam::ThemeManager themeManager;
themeManager.setCurrentTheme(group.readEntry("Theme", "Krita dark"));
ResetStarting resetStarting(d->splashScreen, args.filenames().count()); // remove the splash when done
Q_UNUSED(resetStarting);
// Make sure we can save resources and tags
setSplashScreenLoadingText(i18n("Adding resource types"));
processEvents();
addResourceTypes();
// Load the plugins
loadPlugins();
// Load all resources
if (!registerResources()) {
return false;
}
// Load the gui plugins
loadGuiPlugins();
KisPart *kisPart = KisPart::instance();
if (needsMainWindow) {
// show a mainWindow asap, if we want that
setSplashScreenLoadingText(i18n("Loading Main Window..."));
processEvents();
bool sessionNeeded = true;
auto sessionMode = cfg.sessionOnStartup();
if (!args.session().isEmpty()) {
sessionNeeded = !kisPart->restoreSession(args.session());
} else if (sessionMode == KisConfig::SOS_ShowSessionManager) {
showmainWindow = false;
sessionNeeded = false;
kisPart->showSessionManager();
} else if (sessionMode == KisConfig::SOS_PreviousSession) {
KConfigGroup sessionCfg = KSharedConfig::openConfig()->group("session");
const QString &sessionName = sessionCfg.readEntry("previousSession");
sessionNeeded = !kisPart->restoreSession(sessionName);
}
if (sessionNeeded) {
kisPart->startBlankSession();
}
if (!args.windowLayout().isEmpty()) {
KoResourceServer * rserver = KisResourceServerProvider::instance()->windowLayoutServer();
KisWindowLayoutResourceSP windowLayout = rserver->resourceByName(args.windowLayout());
if (windowLayout) {
windowLayout->applyLayout();
}
}
if (showmainWindow) {
d->mainWindow = kisPart->currentMainwindow();
if (!args.workspace().isEmpty()) {
KoResourceServer * rserver = KisResourceServerProvider::instance()->workspaceServer();
KisWorkspaceResourceSP workspace = rserver->resourceByName(args.workspace());
if (workspace) {
d->mainWindow->restoreWorkspace(workspace->resourceId());
}
}
if (args.canvasOnly()) {
d->mainWindow->viewManager()->switchCanvasOnly(true);
}
if (args.fullScreen()) {
d->mainWindow->showFullScreen();
}
} else {
d->mainWindow = kisPart->createMainWindow();
}
}
short int numberOfOpenDocuments = 0; // number of documents open
// Check for autosave files that can be restored, if we're not running a batchrun (test)
if (!d->batchRun) {
checkAutosaveFiles();
}
setSplashScreenLoadingText(QString()); // done loading, so clear out label
processEvents();
//configure the unit manager
KisSpinBoxUnitManagerFactory::setDefaultUnitManagerBuilder(new KisDocumentAwareSpinBoxUnitManagerBuilder());
connect(this, &KisApplication::aboutToQuit, &KisSpinBoxUnitManagerFactory::clearUnitManagerBuilder); //ensure the builder is destroyed when the application leave.
//the new syntax slot syntax allow to connect to a non q_object static method.
// Create a new image, if needed
if (doNewImage) {
KisDocument *doc = args.createDocumentFromArguments();
if (doc) {
kisPart->addDocument(doc);
d->mainWindow->addViewAndNotifyLoadingCompleted(doc);
}
}
// Get the command line arguments which we have to parse
int argsCount = args.filenames().count();
if (argsCount > 0) {
// Loop through arguments
for (int argNumber = 0; argNumber < argsCount; argNumber++) {
QString fileName = args.filenames().at(argNumber);
// are we just trying to open a template?
if (doTemplate) {
// called in mix with batch options? ignore and silently skip
if (d->batchRun) {
continue;
}
if (createNewDocFromTemplate(fileName, d->mainWindow)) {
++numberOfOpenDocuments;
}
// now try to load
}
else {
if (exportAs) {
QString outputMimetype = KisMimeDatabase::mimeTypeForFile(exportFileName, false);
if (outputMimetype == "application/octetstream") {
dbgKrita << i18n("Mimetype not found, try using the -mimetype option") << endl;
return false;
}
KisDocument *doc = kisPart->createDocument();
doc->setFileBatchMode(d->batchRun);
bool result = doc->openUrl(QUrl::fromLocalFile(fileName));
if (!result) {
errKrita << "Could not load " << fileName << ":" << doc->errorMessage();
QTimer::singleShot(0, this, SLOT(quit()));
return false;
}
if (exportFileName.isEmpty()) {
errKrita << "Export destination is not specified for" << fileName << "Please specify export destination with --export-filename option";
QTimer::singleShot(0, this, SLOT(quit()));
return false;
}
qApp->processEvents(); // For vector layers to be updated
doc->setFileBatchMode(true);
if (!doc->exportDocumentSync(QUrl::fromLocalFile(exportFileName), outputMimetype.toLatin1())) {
errKrita << "Could not export " << fileName << "to" << exportFileName << ":" << doc->errorMessage();
}
QTimer::singleShot(0, this, SLOT(quit()));
return true;
}
else if (exportSequence) {
KisDocument *doc = kisPart->createDocument();
doc->setFileBatchMode(d->batchRun);
doc->openUrl(QUrl::fromLocalFile(fileName));
qApp->processEvents(); // For vector layers to be updated
if (!doc->image()->animationInterface()->hasAnimation()) {
errKrita << "This file has no animation." << endl;
QTimer::singleShot(0, this, SLOT(quit()));
return false;
}
doc->setFileBatchMode(true);
int sequenceStart = 0;
KisAsyncAnimationFramesSaveDialog exporter(doc->image(),
doc->image()->animationInterface()->fullClipRange(),
exportFileName,
sequenceStart,
false,
0);
exporter.setBatchMode(d->batchRun);
KisAsyncAnimationFramesSaveDialog::Result result =
exporter.regenerateRange(0);
if (result == KisAsyncAnimationFramesSaveDialog::RenderFailed) {
errKrita << i18n("Failed to render animation frames!") << endl;
}
QTimer::singleShot(0, this, SLOT(quit()));
return true;
}
else if (d->mainWindow) {
if (fileName.endsWith(".bundle")) {
d->mainWindow->installBundle(fileName);
}
else {
KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
if (d->mainWindow->openDocument(QUrl::fromLocalFile(fileName), flags)) {
// Normal case, success
numberOfOpenDocuments++;
}
}
}
}
}
}
//add an image as file-layer
if (!args.fileLayer().isEmpty()){
if (d->mainWindow->viewManager()->image()){
KisFileLayer *fileLayer = new KisFileLayer(d->mainWindow->viewManager()->image(), "",
args.fileLayer(), KisFileLayer::None,
d->mainWindow->viewManager()->image()->nextLayerName(), OPACITY_OPAQUE_U8);
QFileInfo fi(fileLayer->path());
if (fi.exists()){
KisNodeCommandsAdapter adapter(d->mainWindow->viewManager());
adapter.addNode(fileLayer, d->mainWindow->viewManager()->activeNode()->parent(),
d->mainWindow->viewManager()->activeNode());
}
else{
QMessageBox::warning(nullptr, i18nc("@title:window", "Krita:Warning"),
i18n("Cannot add %1 as a file layer: the file does not exist.", fileLayer->path()));
}
}
else if (this->isRunning()){
QMessageBox::warning(nullptr, i18nc("@title:window", "Krita:Warning"),
i18n("Cannot add the file layer: no document is open.\n\n"
"You can create a new document using the --new-image option, or you can open an existing file.\n\n"
"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)."));
}
else {
QMessageBox::warning(nullptr, i18nc("@title:window", "Krita: Warning"),
i18n("Cannot add the file layer: no document is open.\n"
"You can either create a new file using the --new-image option, or you can open an existing file."));
}
}
// 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);
}
Q_FOREACH(const QByteArray &message, d->earlyRemoteArguments) {
executeRemoteArguments(message, d->mainWindow);
}
KisUsageLogger::writeSysInfo(KisUsageLogger::screenInformation());
// not calling this before since the program will quit there.
return true;
}
KisApplication::~KisApplication()
{
KisResourceCacheDb::deleteTemporaryResources();
}
void KisApplication::setSplashScreen(QWidget *splashScreen)
{
d->splashScreen = qobject_cast(splashScreen);
}
void KisApplication::setSplashScreenLoadingText(const QString &textToLoad)
{
if (d->splashScreen) {
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::executeRemoteArguments(QByteArray message, KisMainWindow *mainWindow)
{
KisApplicationArguments args = KisApplicationArguments::deserialize(message);
const bool doTemplate = args.doTemplate();
const bool doNewImage = args.doNewImage();
const int argsCount = args.filenames().count();
bool documentCreated = false;
// Create a new image, if needed
if (doNewImage) {
KisDocument *doc = args.createDocumentFromArguments();
if (doc) {
KisPart::instance()->addDocument(doc);
d->mainWindow->addViewAndNotifyLoadingCompleted(doc);
}
}
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) {
documentCreated |= createNewDocFromTemplate(filename, mainWindow);
}
else if (QFile(filename).exists()) {
KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
documentCreated |= mainWindow->openDocument(QUrl::fromLocalFile(filename), flags);
}
}
}
//add an image as file-layer if called in another process and singleApplication is enabled
if (!args.fileLayer().isEmpty()){
if (argsCount > 0 && !documentCreated){
//arg was passed but document was not created so don't add the file layer.
QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"),
i18n("Couldn't open file %1",args.filenames().at(argsCount - 1)));
}
else if (mainWindow->viewManager()->image()){
KisFileLayer *fileLayer = new KisFileLayer(mainWindow->viewManager()->image(), "",
args.fileLayer(), KisFileLayer::None,
mainWindow->viewManager()->image()->nextLayerName(), OPACITY_OPAQUE_U8);
QFileInfo fi(fileLayer->path());
if (fi.exists()){
KisNodeCommandsAdapter adapter(d->mainWindow->viewManager());
adapter.addNode(fileLayer, d->mainWindow->viewManager()->activeNode()->parent(),
d->mainWindow->viewManager()->activeNode());
}
else{
QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"),
i18n("Cannot add %1 as a file layer: the file does not exist.", fileLayer->path()));
}
}
else {
QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"),
i18n("Cannot add the file layer: no document is open."));
}
}
}
void KisApplication::remoteArguments(QByteArray message, QObject *socket)
{
Q_UNUSED(socket);
// check if we have any mainwindow
KisMainWindow *mw = qobject_cast(qApp->activeWindow());
if (!mw && KisPart::instance()->mainWindows().size() > 0) {
mw = KisPart::instance()->mainWindows().first();
}
if (!mw) {
d->earlyRemoteArguments << message;
return;
}
executeRemoteArguments(message, mw);
}
void KisApplication::fileOpenRequested(const QString &url)
{
KisMainWindow *mainWindow = KisPart::instance()->mainWindows().first();
if (mainWindow) {
KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
mainWindow->openDocument(QUrl::fromLocalFile(url), flags);
}
}
void KisApplication::checkAutosaveFiles()
{
if (d->batchRun) return;
#ifdef Q_OS_WIN
QDir dir = QDir::temp();
#else
QDir dir = QDir::home();
#endif
// 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!
// Hidden autosave files
QStringList filters = QStringList() << QString(".krita-*-*-autosave.kra");
// all autosave files for our application
QStringList autosaveFiles = dir.entryList(filters, QDir::Files | QDir::Hidden);
// Visible autosave files
filters = QStringList() << QString("krita-*-*-autosave.kra");
autosaveFiles += dir.entryList(filters, QDir::Files);
// Allow the user to make their selection
if (autosaveFiles.size() > 0) {
if (d->splashScreen) {
// hide the splashscreen to see the dialog
d->splashScreen->hide();
}
d->autosaveDialog = new KisAutoSaveRecoveryDialog(autosaveFiles, activeWindow());
QDialog::DialogCode result = (QDialog::DialogCode) d->autosaveDialog->exec();
if (result == QDialog::Accepted) {
QStringList filesToRecover = d->autosaveDialog->recoverableFiles();
Q_FOREACH (const QString &autosaveFile, autosaveFiles) {
if (!filesToRecover.contains(autosaveFile)) {
KisUsageLogger::log(QString("Removing autosave file %1").arg(dir.absolutePath() + "/" + autosaveFile));
QFile::remove(dir.absolutePath() + "/" + autosaveFile);
}
}
autosaveFiles = filesToRecover;
} else {
autosaveFiles.clear();
}
if (autosaveFiles.size() > 0) {
QList autosaveUrls;
Q_FOREACH (const QString &autoSaveFile, autosaveFiles) {
const QUrl url = QUrl::fromLocalFile(dir.absolutePath() + QLatin1Char('/') + autoSaveFile);
autosaveUrls << url;
}
if (d->mainWindow) {
Q_FOREACH (const QUrl &url, autosaveUrls) {
KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
d->mainWindow->openDocument(url, flags | KisMainWindow::RecoveryFile);
}
}
}
// cleanup
delete d->autosaveDialog;
d->autosaveDialog = nullptr;
}
}
bool KisApplication::createNewDocFromTemplate(const QString &fileName, KisMainWindow *mainWindow)
{
QString templatePath;
const QUrl templateUrl = QUrl::fromLocalFile(fileName);
if (QFile::exists(fileName)) {
templatePath = templateUrl.toLocalFile();
dbgUI << "using full path...";
}
else {
QString desktopName(fileName);
const QString templatesResourcePath = QStringLiteral("templates/");
QStringList paths = KoResourcePaths::findAllResources("data", templatesResourcePath + "*/" + desktopName);
if (paths.isEmpty()) {
paths = KoResourcePaths::findAllResources("data", templatesResourcePath + desktopName);
}
if (paths.isEmpty()) {
QMessageBox::critical(0, i18nc("@title:window", "Krita"),
i18n("No template found for: %1", desktopName));
} else if (paths.count() > 1) {
QMessageBox::critical(0, i18nc("@title:window", "Krita"),
i18n("Too many templates found for: %1", desktopName));
} else {
templatePath = paths.at(0);
}
}
if (!templatePath.isEmpty()) {
QUrl templateBase;
templateBase.setPath(templatePath);
KDesktopFile templateInfo(templatePath);
QString templateName = templateInfo.readUrl();
QUrl templateURL;
templateURL.setPath(templateBase.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path() + '/' + templateName);
if (templateURL.scheme().isEmpty()) {
templateURL.setScheme("file");
}
KisMainWindow::OpenFlags batchFlags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
if (mainWindow->openDocument(templateURL, KisMainWindow::Import | batchFlags)) {
dbgUI << "Template loaded...";
return true;
}
else {
QMessageBox::critical(0, i18nc("@title:window", "Krita"),
i18n("Template %1 failed to load.", templateURL.toDisplayString()));
}
}
return false;
}
-void KisApplication::clearConfig()
+void KisApplication::resetConfig()
{
KIS_ASSERT_RECOVER_RETURN(qApp->thread() == QThread::currentThread());
KSharedConfigPtr config = KSharedConfig::openConfig();
-
+ config->markAsClean();
+
// 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();
+ const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
+ QString kritarcPath = configPath + QStringLiteral("/kritarc");
+
+ QFile kritarcFile(kritarcPath);
+
+ if (kritarcFile.exists()) {
+ if (kritarcFile.open(QFile::ReadWrite)) {
+ QString backupKritarcPath = kritarcPath + QStringLiteral(".backup");
+
+ QFile backupKritarcFile(backupKritarcPath);
+
+ if (backupKritarcFile.exists()) {
+ backupKritarcFile.remove();
+ }
+
+ QMessageBox::information(0,
+ i18nc("@title:window", "Krita"),
+ i18n("Krita configurations reset!\n\n"
+ "Backup file was created at: %1\n\n"
+ "Restart Krita for changes to take effect.",
+ backupKritarcPath),
+ QMessageBox::Ok, QMessageBox::Ok);
+
+ // clear file
+ kritarcFile.rename(backupKritarcPath);
+
+ kritarcFile.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();
+
+ // Restore to default workspace
+ KConfigGroup cfg = KSharedConfig::openConfig()->group("MainWindow");
+
+ QString currentWorkspace = cfg.readEntry("CurrentWorkspace", "Default");
+ KoResourceServer * rserver = KisResourceServerProvider::instance()->workspaceServer();
+ KisWorkspaceResourceSP workspace = rserver->resourceByName(currentWorkspace);
+
+ if (workspace) {
+ d->mainWindow->restoreWorkspace(workspace->resourceId());
+ }
}
-void KisApplication::askClearConfig()
+void KisApplication::askresetConfig()
{
- 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();
- }
+ 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) {
+ resetConfig();
}
}
diff --git a/libs/ui/KisApplication.h b/libs/ui/KisApplication.h
index f07c6817fa..a87ba8df5e 100644
--- a/libs/ui/KisApplication.h
+++ b/libs/ui/KisApplication.h
@@ -1,122 +1,122 @@
/*
* 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
#include "kritaui_export.h"
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();
+ void askresetConfig();
/**
* 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 hideSplashScreen();
/// Overridden to handle exceptions from event handlers.
bool notify(QObject *receiver, QEvent *event) override;
void addResourceTypes();
bool registerResources();
void loadPlugins();
void loadGuiPlugins();
void initializeGlobals(const KisApplicationArguments &args);
public Q_SLOTS:
void executeRemoteArguments(QByteArray message, KisMainWindow *mainWindow);
void remoteArguments(QByteArray message, QObject*socket);
void fileOpenRequested(const QString & url);
void setSplashScreenLoadingText(const QString&);
private:
/// @return the number of autosavefiles opened
void checkAutosaveFiles();
bool createNewDocFromTemplate(const QString &fileName, KisMainWindow *m_mainWindow);
- void clearConfig();
+ void resetConfig();
private:
class Private;
QScopedPointer d;
class ResetStarting;
friend class ResetStarting;
};
#endif
diff --git a/libs/ui/KisMainWindow.cpp b/libs/ui/KisMainWindow.cpp
index e2d5337284..791e161f77 100644
--- a/libs/ui/KisMainWindow.cpp
+++ b/libs/ui/KisMainWindow.cpp
@@ -1,2863 +1,2873 @@
/* This file is part of the KDE project
Copyright (C) 1998, 1999 Torben Weis
Copyright (C) 2000-2006 David Faure
Copyright (C) 2007, 2009 Thomas zander
Copyright (C) 2010 Benjamin Port
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 "KisMainWindow.h"
#include
// qt includes
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kis_selection_manager.h"
#include "kis_icon_utils.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "KoDockFactoryBase.h"
#include "KoDocumentInfoDlg.h"
#include "KoDocumentInfo.h"
#include "KoFileDialog.h"
#include
#include
#include
#include
#include
#include "KoToolDocker.h"
#include "KoToolBoxDocker_p.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef Q_OS_ANDROID
#include
#endif
#include
#include
#include "dialogs/kis_about_application.h"
#include "dialogs/kis_delayed_save_dialog.h"
#include "dialogs/kis_dlg_preferences.h"
#include "kis_action_manager.h"
#include "KisApplication.h"
#include "kis_canvas2.h"
#include "kis_canvas_controller.h"
#include "kis_canvas_resource_provider.h"
#include "kis_clipboard.h"
#include "kis_config.h"
#include "kis_config_notifier.h"
#include "kis_custom_image_widget.h"
#include
#include "kis_group_layer.h"
#include "kis_image_from_clipboard_widget.h"
#include "kis_image.h"
#include
#include "KisImportExportManager.h"
#include "kis_mainwindow_observer.h"
#include "kis_memory_statistics_server.h"
#include "kis_node.h"
#include "KisOpenPane.h"
#include "kis_paintop_box.h"
#include "KisPart.h"
#include "KisPrintJob.h"
#include "KisResourceServerProvider.h"
#include "kis_signal_compressor_with_param.h"
#include "kis_statusbar.h"
#include "KisView.h"
#include "KisViewManager.h"
#include "thememanager.h"
#include "kis_animation_importer.h"
#include "dialogs/kis_dlg_import_image_sequence.h"
#include
#include "KisWindowLayoutManager.h"
#include
#include "KisWelcomePageWidget.h"
#include
#include
#include "KisCanvasWindow.h"
#include "kis_action.h"
#include
class ToolDockerFactory : public KoDockFactoryBase
{
public:
ToolDockerFactory() : KoDockFactoryBase() { }
QString id() const override {
return "sharedtooldocker";
}
QDockWidget* createDockWidget() override {
KoToolDocker* dockWidget = new KoToolDocker();
return dockWidget;
}
DockPosition defaultDockPosition() const override {
return DockRight;
}
};
class Q_DECL_HIDDEN KisMainWindow::Private
{
public:
Private(KisMainWindow *parent, QUuid id)
: q(parent)
, id(id)
, dockWidgetMenu(new KActionMenu(i18nc("@action:inmenu", "&Dockers"), parent))
, windowMenu(new KActionMenu(i18nc("@action:inmenu", "&Window"), parent))
, documentMenu(new KActionMenu(i18nc("@action:inmenu", "New &View"), parent))
, workspaceMenu(new KActionMenu(i18nc("@action:inmenu", "Wor&kspace"), parent))
, welcomePage(new KisWelcomePageWidget(parent))
, widgetStack(new QStackedWidget(parent))
, mdiArea(new QMdiArea(parent))
, windowMapper(new KisSignalMapper(parent))
, documentMapper(new KisSignalMapper(parent))
#ifdef Q_OS_ANDROID
, fileManager(new KisAndroidFileManager(parent))
#endif
{
if (id.isNull()) this->id = QUuid::createUuid();
welcomeScroller = new QScrollArea();
welcomeScroller->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
welcomeScroller->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
welcomeScroller->setWidget(welcomePage);
welcomeScroller->setWidgetResizable(true);
widgetStack->addWidget(welcomeScroller);
widgetStack->addWidget(mdiArea);
mdiArea->setTabsMovable(true);
mdiArea->setActivationOrder(QMdiArea::ActivationHistoryOrder);
}
~Private() {
qDeleteAll(toolbarList);
}
KisMainWindow *q {0};
QUuid id;
KisViewManager *viewManager {0};
QPointer activeView;
QList toolbarList;
bool firstTime {true};
bool windowSizeDirty {false};
bool readOnly {false};
KisAction *showDocumentInfo {0};
KisAction *saveAction {0};
KisAction *saveActionAs {0};
// KisAction *printAction;
// KisAction *printActionPreview;
// KisAction *exportPdf {0};
KisAction *importAnimation {0};
KisAction *closeAll {0};
// KisAction *reloadFile;
KisAction *importFile {0};
KisAction *exportFile {0};
KisAction *undo {0};
KisAction *redo {0};
KisAction *newWindow {0};
KisAction *close {0};
KisAction *mdiCascade {0};
KisAction *mdiTile {0};
KisAction *mdiNextWindow {0};
KisAction *mdiPreviousWindow {0};
KisAction *toggleDockers {0};
+ KisAction *resetConfigurations {0};
KisAction *toggleDockerTitleBars {0};
KisAction *toggleDetachCanvas {0};
KisAction *fullScreenMode {0};
KisAction *showSessionManager {0};
KisAction *expandingSpacers[2];
KActionMenu *dockWidgetMenu;
KActionMenu *windowMenu;
KActionMenu *documentMenu;
KActionMenu *workspaceMenu;
KHelpMenu *helpMenu {0};
KRecentFilesAction *recentFiles {0};
KisResourceModel *workspacemodel {0};
QScopedPointer undoActionsUpdateManager;
QString lastExportLocation;
QMap dockWidgetsMap;
QByteArray dockerStateBeforeHiding;
KoToolDocker *toolOptionsDocker {0};
QCloseEvent *deferredClosingEvent {0};
Digikam::ThemeManager *themeManager {0};
QScrollArea *welcomeScroller {0};
KisWelcomePageWidget *welcomePage {0};
QStackedWidget *widgetStack {0};
QMdiArea *mdiArea;
QMdiSubWindow *activeSubWindow {0};
KisSignalMapper *windowMapper;
KisSignalMapper *documentMapper;
KisCanvasWindow *canvasWindow {0};
QByteArray lastExportedFormat;
QScopedPointer > tabSwitchCompressor;
QMutex savingEntryMutex;
KConfigGroup windowStateConfig;
QUuid workspaceBorrowedBy;
KisSignalAutoConnectionsStore screenConnectionsStore;
#ifdef Q_OS_ANDROID
KisAndroidFileManager *fileManager;
#endif
KisActionManager * actionManager() {
return viewManager->actionManager();
}
QTabBar* findTabBarHACK() {
QObjectList objects = mdiArea->children();
Q_FOREACH (QObject *object, objects) {
QTabBar *bar = qobject_cast(object);
if (bar) {
return bar;
}
}
return 0;
}
};
KisMainWindow::KisMainWindow(QUuid uuid)
: KXmlGuiWindow()
, d(new Private(this, uuid))
{
d->workspacemodel = KisResourceModelProvider::resourceModel(ResourceType::Workspaces);
connect(d->workspacemodel, SIGNAL(afterResourcesLayoutReset()), this, SLOT(updateWindowMenu()));
d->viewManager = new KisViewManager(this, actionCollection());
KConfigGroup group( KSharedConfig::openConfig(), "theme");
d->themeManager = new Digikam::ThemeManager(group.readEntry("Theme", "Krita dark"), this);
d->windowStateConfig = KSharedConfig::openConfig()->group("MainWindow");
setStandardToolBarMenuEnabled(true);
setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
setDockNestingEnabled(true);
qApp->setStartDragDistance(25); // 25 px is a distance that works well for Tablet and Mouse events
#ifdef Q_OS_MACOS
setUnifiedTitleAndToolBarOnMac(true);
#endif
connect(this, SIGNAL(restoringDone()), this, SLOT(forceDockTabFonts()));
connect(this, SIGNAL(themeChanged()), d->viewManager, SLOT(updateIcons()));
connect(KisPart::instance(), SIGNAL(documentClosed(QString)), SLOT(updateWindowMenu()));
connect(KisPart::instance(), SIGNAL(documentOpened(QString)), SLOT(updateWindowMenu()));
connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), this, SLOT(configChanged()));
actionCollection()->addAssociatedWidget(this);
KoPluginLoader::instance()->load("Krita/ViewPlugin", "Type == 'Service' and ([X-Krita-Version] == 28)", KoPluginLoader::PluginsConfig(), d->viewManager, false);
// Load the per-application plugins (Right now, only Python) We do this only once, when the first mainwindow is being created.
KoPluginLoader::instance()->load("Krita/ApplicationPlugin", "Type == 'Service' and ([X-Krita-Version] == 28)", KoPluginLoader::PluginsConfig(), qApp, true);
KoToolBoxFactory toolBoxFactory;
QDockWidget *toolbox = createDockWidget(&toolBoxFactory);
toolbox->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable);
KisConfig cfg(true);
if (cfg.toolOptionsInDocker()) {
ToolDockerFactory toolDockerFactory;
d->toolOptionsDocker = qobject_cast(createDockWidget(&toolDockerFactory));
d->toolOptionsDocker->toggleViewAction()->setEnabled(true);
}
QMap dockwidgetActions;
dockwidgetActions[toolbox->toggleViewAction()->text()] = toolbox->toggleViewAction();
Q_FOREACH (const QString & docker, KoDockRegistry::instance()->keys()) {
KoDockFactoryBase *factory = KoDockRegistry::instance()->value(docker);
QDockWidget *dw = createDockWidget(factory);
dockwidgetActions[dw->toggleViewAction()->text()] = dw->toggleViewAction();
}
if (d->toolOptionsDocker) {
dockwidgetActions[d->toolOptionsDocker->toggleViewAction()->text()] = d->toolOptionsDocker->toggleViewAction();
}
connect(KoToolManager::instance(), SIGNAL(toolOptionWidgetsChanged(KoCanvasController*,QList >)), this, SLOT(newOptionWidgets(KoCanvasController*,QList >)));
Q_FOREACH (QString title, dockwidgetActions.keys()) {
d->dockWidgetMenu->addAction(dockwidgetActions[title]);
}
Q_FOREACH (QDockWidget *wdg, dockWidgets()) {
if ((wdg->features() & QDockWidget::DockWidgetClosable) == 0) {
wdg->setVisible(true);
}
}
Q_FOREACH (KoCanvasObserverBase* observer, canvasObservers()) {
observer->setObservedCanvas(0);
KisMainwindowObserver* mainwindowObserver = dynamic_cast(observer);
if (mainwindowObserver) {
mainwindowObserver->setViewManager(d->viewManager);
}
}
// Load all the actions from the tool plugins
Q_FOREACH(KoToolFactoryBase *toolFactory, KoToolRegistry::instance()->values()) {
toolFactory->createActions(actionCollection());
}
d->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
d->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
d->mdiArea->setTabPosition(QTabWidget::North);
d->mdiArea->setTabsClosable(true);
// Tab close button override
// Windows just has a black X, and Ubuntu has a dark x that is hard to read
// just switch this icon out for all OSs so it is easier to see
d->mdiArea->setStyleSheet("QTabBar::close-button { image: url(:/pics/broken-preset.png) }");
setCentralWidget(d->widgetStack);
d->widgetStack->setCurrentIndex(0);
connect(d->mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(subWindowActivated()));
connect(d->windowMapper, SIGNAL(mapped(QWidget*)), this, SLOT(setActiveSubWindow(QWidget*)));
connect(d->documentMapper, SIGNAL(mapped(QObject*)), this, SLOT(newView(QObject*)));
d->canvasWindow = new KisCanvasWindow(this);
actionCollection()->addAssociatedWidget(d->canvasWindow);
createActions();
// the welcome screen needs to grab actions...so make sure this line goes after the createAction() so they exist
d->welcomePage->setMainWindow(this);
setAutoSaveSettings(d->windowStateConfig, false);
subWindowActivated();
updateWindowMenu();
if (isHelpMenuEnabled() && !d->helpMenu) {
// workaround for KHelpMenu (or rather KAboutData::applicationData()) internally
// not using the Q*Application metadata ATM, which results e.g. in the bugreport wizard
// not having the app version preset
// fixed hopefully in KF5 5.22.0, patch pending
QGuiApplication *app = qApp;
KAboutData aboutData(app->applicationName(), app->applicationDisplayName(), app->applicationVersion());
aboutData.setOrganizationDomain(app->organizationDomain().toUtf8());
d->helpMenu = new KHelpMenu(this, aboutData, false);
// workaround-less version:
// d->helpMenu = new KHelpMenu(this, QString()/*unused*/, false);
// The difference between using KActionCollection->addAction() is that
// these actions do not get tied to the MainWindow. What does this all do?
KActionCollection *actions = d->viewManager->actionCollection();
QAction *helpContentsAction = d->helpMenu->action(KHelpMenu::menuHelpContents);
QAction *whatsThisAction = d->helpMenu->action(KHelpMenu::menuWhatsThis);
QAction *reportBugAction = d->helpMenu->action(KHelpMenu::menuReportBug);
QAction *switchLanguageAction = d->helpMenu->action(KHelpMenu::menuSwitchLanguage);
QAction *aboutAppAction = d->helpMenu->action(KHelpMenu::menuAboutApp);
QAction *aboutKdeAction = d->helpMenu->action(KHelpMenu::menuAboutKDE);
if (helpContentsAction) {
actions->addAction(helpContentsAction->objectName(), helpContentsAction);
}
if (whatsThisAction) {
actions->addAction(whatsThisAction->objectName(), whatsThisAction);
}
if (reportBugAction) {
actions->addAction(reportBugAction->objectName(), reportBugAction);
}
if (switchLanguageAction) {
actions->addAction(switchLanguageAction->objectName(), switchLanguageAction);
}
if (aboutAppAction) {
actions->addAction(aboutAppAction->objectName(), aboutAppAction);
}
if (aboutKdeAction) {
actions->addAction(aboutKdeAction->objectName(), aboutKdeAction);
}
connect(d->helpMenu, SIGNAL(showAboutApplication()), SLOT(showAboutApplication()));
}
// KDE' libs 4''s help contents action is broken outside kde, for some reason... We can handle it just as easily ourselves
QAction *helpAction = actionCollection()->action("help_contents");
helpAction->disconnect();
connect(helpAction, SIGNAL(triggered()), this, SLOT(showManual()));
#if 0
//check for colliding shortcuts
QSet existingShortcuts;
Q_FOREACH (QAction* action, actionCollection()->actions()) {
if(action->shortcut() == QKeySequence(0)) {
continue;
}
dbgKrita << "shortcut " << action->text() << " " << action->shortcut();
Q_ASSERT(!existingShortcuts.contains(action->shortcut()));
existingShortcuts.insert(action->shortcut());
}
#endif
configChanged();
// Make sure the python plugins create their actions in time
KisPart::instance()->notifyMainWindowIsBeingCreated(this);
// If we have customized the toolbars, load that first
setLocalXMLFile(KoResourcePaths::locateLocal("data", "krita4.xmlgui"));
setXMLFile(":/kxmlgui5/krita4.xmlgui");
guiFactory()->addClient(this);
connect(guiFactory(), SIGNAL(makingChanges(bool)), SLOT(slotXmlGuiMakingChanges(bool)));
// Create and plug toolbar list for Settings menu
QList toolbarList;
Q_FOREACH (QWidget* it, guiFactory()->containers("ToolBar")) {
KToolBar * toolBar = ::qobject_cast(it);
toolBar->setMovable(KisConfig(true).readEntry("LockAllDockerPanels", false));
if (toolBar) {
if (toolBar->objectName() == "BrushesAndStuff") {
toolBar->setEnabled(false);
}
KToggleAction* act = new KToggleAction(i18n("Show %1 Toolbar", toolBar->windowTitle()), this);
actionCollection()->addAction(toolBar->objectName().toUtf8(), act);
act->setCheckedState(KGuiItem(i18n("Hide %1 Toolbar", toolBar->windowTitle())));
connect(act, SIGNAL(toggled(bool)), this, SLOT(slotToolbarToggled(bool)));
act->setChecked(!toolBar->isHidden());
toolbarList.append(act);
} else {
warnUI << "Toolbar list contains a " << it->metaObject()->className() << " which is not a toolbar!";
}
}
KToolBar::setToolBarsLocked(KisConfig(true).readEntry("LockAllDockerPanels", false));
plugActionList("toolbarlist", toolbarList);
d->toolbarList = toolbarList;
applyToolBarLayout();
d->viewManager->updateGUI();
d->viewManager->updateIcons();
QTimer::singleShot(1000, this, SLOT(checkSanity()));
{
using namespace std::placeholders; // For _1 placeholder
std::function callback(
std::bind(&KisMainWindow::switchTab, this, _1));
d->tabSwitchCompressor.reset(
new KisSignalCompressorWithParam(500, callback, KisSignalCompressor::FIRST_INACTIVE));
}
if (cfg.readEntry("CanvasOnlyActive", false)) {
QString currentWorkspace = cfg.readEntry("CurrentWorkspace", "Default");
KoResourceServer * rserver = KisResourceServerProvider::instance()->workspaceServer();
KisWorkspaceResourceSP workspace = rserver->resourceByName(currentWorkspace);
if (workspace) {
restoreWorkspace(workspace->resourceId());
}
cfg.writeEntry("CanvasOnlyActive", false);
menuBar()->setVisible(true);
}
this->winId(); // Ensures the native window has been created.
QWindow *window = this->windowHandle();
connect(window, SIGNAL(screenChanged(QScreen *)), this, SLOT(windowScreenChanged(QScreen *)));
}
KisMainWindow::~KisMainWindow()
{
// Q_FOREACH (QAction *ac, actionCollection()->actions()) {
// QAction *action = qobject_cast(ac);
// if (action) {
// qDebug() << "objectName()
// << "\n\ticon=" << action->icon().name()
// << "\n\ttext=" << action->text().replace("&", "&")
// << "\n\twhatsThis=" << action->whatsThis()
// << "\n\ttoolTip=" << action->toolTip().replace("", "").replace("", "")
// << "\n\ticonText=" << action->iconText().replace("&", "&")
// << "\n\tshortcut=" << action->shortcut().toString()
// << "\n\tisCheckable=" << QString((action->isChecked() ? "true" : "false"))
// << "\n\tstatusTip=" << action->statusTip()
// << "\n/>\n" ;
// }
// else {
// dbgKrita << "Got a non-qaction:" << ac->objectName();
// }
// }
// The doc and view might still exist (this is the case when closing the window)
KisPart::instance()->removeMainWindow(this);
delete d->viewManager;
delete d;
}
QUuid KisMainWindow::id() const {
return d->id;
}
void KisMainWindow::addView(KisView *view, QMdiSubWindow *subWindow)
{
if (d->activeView == view && !subWindow) return;
if (d->activeView) {
d->activeView->disconnect(this);
}
// register the newly created view in the input manager
viewManager()->inputManager()->addTrackedCanvas(view->canvasBase());
showView(view, subWindow);
updateCaption();
emit restoringDone();
if (d->activeView) {
connect(d->activeView, SIGNAL(titleModified(QString,bool)), SLOT(slotDocumentTitleModified()));
connect(d->viewManager->statusBar(), SIGNAL(memoryStatusUpdated()), this, SLOT(updateCaption()));
}
}
void KisMainWindow::notifyChildViewDestroyed(KisView *view)
{
/**
* If we are the last view of the window, Qt will not activate another tab
* before destroying tab/window. In this case we should clear all the dangling
* pointers manually by setting the current view to null
*/
viewManager()->inputManager()->removeTrackedCanvas(view->canvasBase());
if (view->canvasBase() == viewManager()->canvasBase()) {
viewManager()->setCurrentView(0);
}
}
void KisMainWindow::showView(KisView *imageView, QMdiSubWindow *subwin)
{
if (imageView && activeView() != imageView) {
// XXX: find a better way to initialize this!
imageView->setViewManager(d->viewManager);
imageView->canvasBase()->setFavoriteResourceManager(d->viewManager->paintOpBox()->favoriteResourcesManager());
imageView->slotLoadingFinished();
if (!subwin) {
subwin = d->mdiArea->addSubWindow(imageView);
} else {
subwin->setWidget(imageView);
}
imageView->setSubWindow(subwin);
subwin->setAttribute(Qt::WA_DeleteOnClose, true);
connect(subwin, SIGNAL(destroyed()), SLOT(updateWindowMenu()));
KisConfig cfg(true);
subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.readEntry("mdi_rubberband", cfg.useOpenGL()));
subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.readEntry("mdi_rubberband", cfg.useOpenGL()));
subwin->setWindowIcon(qApp->windowIcon());
#ifdef Q_OS_MACOS
connect(subwin, SIGNAL(destroyed()), SLOT(updateSubwindowFlags()));
updateSubwindowFlags();
#endif
if (d->mdiArea->subWindowList().size() == 1) {
imageView->showMaximized();
}
else {
imageView->show();
}
/**
* Hack alert!
*
* Here we explicitly request KoToolManager to emit all the tool
* activation signals, to reinitialize the tool options docker.
*
* That is needed due to a design flaw we have in the
* initialization procedure. The tool in the KoToolManager is
* initialized in KisView::setViewManager() calls, which
* happens early enough. During this call the tool manager
* requests KoCanvasControllerWidget to emit the signal to
* update the widgets in the tool docker. *But* at that moment
* of time the view is not yet connected to the main window,
* because it happens in KisViewManager::setCurrentView a bit
* later. This fact makes the widgets updating signals be lost
* and never reach the tool docker.
*
* So here we just explicitly call the tool activation stub.
*/
KoToolManager::instance()->initializeCurrentToolForCanvas();
// No, no, no: do not try to call this _before_ the show() has
// been called on the view; only when that has happened is the
// opengl context active, and very bad things happen if we tell
// the dockers to update themselves with a view if the opengl
// context is not active.
setActiveView(imageView);
updateWindowMenu();
updateCaption();
}
}
void KisMainWindow::slotPreferences()
{
QScopedPointer dlgPreferences(new KisDlgPreferences(this));
if (dlgPreferences->editPreferences()) {
KisConfigNotifier::instance()->notifyConfigChanged();
KisConfigNotifier::instance()->notifyPixelGridModeChanged();
KisImageConfigNotifier::instance()->notifyConfigChanged();
// XXX: should this be changed for the views in other windows as well?
Q_FOREACH (QPointer koview, KisPart::instance()->views()) {
KisViewManager *view = qobject_cast