diff --git a/3rdparty/README.md b/3rdparty/README.md index 3ab4d05fc7..35493707af 100644 --- a/3rdparty/README.md +++ b/3rdparty/README.md @@ -1,283 +1,273 @@ = CMake external projects to build krita's dependencies on Linux, Windows or OSX = If you need to build Krita's dependencies for the following reasons: * you develop on Windows and aren't using Emerge * you develop on OSX and aren't using Homebrew * you want to build a generic, distro-agnostic version of Krita for Linux * you develop on Linux, but some dependencies aren't available for your distribution and you know what you're doing, you can use the following guide to build the dependencies that Krita needs. If you develop on Linux and your distribution has the dependencies available, YOU DO NOT NEED THIS GUIDE AND YOU SHOULD STOP READING NOW Otherwise you risk major confusion. == Prerequisites == Note: on all operating systems the entire procedure is done in a terminal window. 1. git: https://git-scm.com/downloads. Make sure git is in your path 2. cmake 3.3.2: https://cmake.org/download/. Make sure cmake is in your path. 3. Make sure you have a compiler: * Linux: gcc, minimum version 4.8 * OSX: clang, you need to install xcode for this * Windows: MSVC 2015 Community Edition: https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx +4. If you compile Qt on Windows, you will also need Python 2.7: https://www.python.org/download/releases/2.7/. Make sure to have python.exe in you path. == Setup your environment == Windows Only: When launching the commands from the console, run first "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat" in it, this way all the environment variables for the compiler will be ready. == Prepare your directory layout == 1. Make a toplevel build directory, say $HOME/dev or c:\dev. We'll refer to this directory as BUILDROOT. You can use a variable for this, on WINDOWS %BUILDROOT%, on OSX and Linux $BUILDROOT. 2. Checkout krita in BUILDROOT cd BUILDROOT git clone git://anongit.kde.org/krita.git 3. Create the build directory mkdir BUILDROOT/b 4. Create the downloads directory mkdir BUILDROOT/d 5. Create the install directory mkdir BUILDROOT/i == Qt == Install Qt. Either build from source or with the qt.io installer. Make sure qmake is in your path. You need qtbase, qtsvg, qttools, qtscript, qtdeclarative, qtgraphicaleffects, qttranslations. On Windows, you also need qtwinextras, on Linux qtx11extras. When installing from source, you can use these example configure commands: * Linux: ./configure \ -skip qt3d \ -skip qtactiveqt \ -skip qtcanvas3d \ -skip qtconnectivity \ -skip qtdoc \ -skip qtenginio \ -skip qtgraphicaleffects \ -skip qtlocation \ -skip qtmultimedia \ -skip qtsensors \ -skip qtserialport \ -skip qtwayland \ -skip qtwebchannel \ -skip qtwebengine \ -skip qtwebkit \ -skip qtwebkit-examples \ -skip qtwebsockets \ -skip qtxmlpatterns \ -opensource -confirm-license -release \ -no-qml-debug -no-mtdev -no-journald \ -no-openssl -no-libproxy \ -no-pulseaudio -no-alsa -no-nis \ -no-cups -no-tslib -no-pch \ -no-dbus -no-gstreamer -no-system-proxies \ -no-openssl -no-libproxy -no-pulseaudio \ -qt-xcb -xcb -qt-freetype -qt-harfbuzz \ -qt-pcre -qt-xkbcommon-x11 -xcb-xlib \ -prefix BUILDROOT/i make -j8 * OSX ./configure \ -skip qt3d \ -skip qtactiveqt \ -skip qtcanvas3d \ -skip qtconnectivity \ -skip qtdeclarative \ -skip qtdoc \ -skip qtenginio \ -skip qtgraphicaleffects \ -skip qtlocation \ -skip qtmultimedia \ -skip qtsensors \ -skip qtserialport \ -skip qtwayland \ -skip qtwebchannel \ -skip qtwebengine \ -skip qtwebsockets \ -skip qtxmlpatterns \ -opensource -confirm-license -release \ -no-qml-debug -no-mtdev -no-journald \ -no-openssl -no-libproxy \ -no-pulseaudio -no-alsa -no-nis \ -no-cups -no-tslib -no-pch \ -no-dbus -no-gstreamer -no-system-proxies \ -no-openssl -no-libproxy -no-pulseaudio \ -nomake examples -nomake demos \ -prefix $BUILDROOT/i * Windows - configure -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity -skip qtdoc -skip qtenginio -skip qtgraphicaleffects -skip qtlocation -skip qtmultimedia -skip qtsensors -skip qtserialport -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtxmlpatterns -opensource -confirm-license -release -no-qml-debug -no-mtdev -no-openssl -no-libproxy -no-nis -no-dbus -no-system-proxies -no-libproxy -opengl desktop -prefix %BUILDROOT%\i + To do a normal release build use: + + configure -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity -skip qtdoc -skip qtenginio -skip qtgraphicaleffects -skip qtlocation -skip qtmultimedia -skip qtsensors -skip qtserialport -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtxmlpatterns -no-sql-sqlite -nomake examples -nomake tools -no-compile-examples -no-dbus -no-iconv -no-angle -no-ssl -no-openssl -no-wmf-backend -no-qml-debug -no-libproxy -no-system-proxies -no-nis -no-icu -no-mtdev -opensource -confirm-license -release -opengl desktop -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -prefix %BUILDROOT%\i + + If a release with debug info for developing purposes is needed, add the -force-debug-info to the configure options above, so that the pdb files will be generated. + + N.B.: if you don't have the Qt 5.6 pre-built binaries already installed, you will need to copy Qt5Core.dll, coming from those binaries inside the Qt build directory, under the path qtbase\bin, otherwise you'll get an error + about it missing when using jom and a more cryptic error with nmake. The same has to be done with Qt5Xml.dll, to be copied under qttools\bin. + Don't use the dlls coming from the QtCreator folder, they won't work. == Prepare the externals build == 1. enter the BUILDROOT/b directory 2. run cmake: * Linux: cmake ../krita/3rdparty -DINSTALL_ROOT=BUILDROOT/i -DEXTERNALS_DOWNLOAD_DIR=BUILDROOT/d -DCMAKE_INSTALL_PREFIX=BUILDROOT/i : * OSX: * Windows 32 bits: * Windows 64 bits: Note that the cmake command needs to point to your buildroot like /dev/d, not c:\dev\d. set PATH=BUILDROOT\i\bin\;BUILDROOT\i\lib;%PATH% cmake ..\krita\3rdparty -DEXTERNALS_DOWNLOAD_DIR=/dev/d -DINSTALL_ROOT=/dev/i -G "Visual Studio 14 Win64" 3. build the packages: With a judicious application of DEPENDS statements, it's possible to build it all in one go, but in my experience that fails anyway, so it's better to build the dependencies indepdendently. On Windows: cmake --build . --config RelWithDebInfo --target ext_patch cmake --build . --config RelWithDebInfo --target ext_png2ico cmake --build . --config RelWithDebInfo --target ext_pthreads On all operating systems: cmake --build . --config RelWithDebInfo --target ext_boost cmake --build . --config RelWithDebInfo --target ext_eigen3 cmake --build . --config RelWithDebInfo --target ext_exiv2 cmake --build . --config RelWithDebInfo --target ext_fftw3 - -Note for Windows: - -fftw3 is still broken, don't know why. Copy the bin, lib and include folders from - - \b\ext_fftw3\ext_fftw3-prefix\src\ext_fftw3 - -manuall to BUILDROOT\i - cmake --build . --config RelWithDebInfo --target ext_ilmbase cmake --build . --config RelWithDebInfo --target ext_jpeg cmake --build . --config RelWithDebInfo --target ext_lcms2 cmake --build . --config RelWithDebInfo --target ext_ocio cmake --build . --config RelWithDebInfo --target ext_openexr Note for OSX: On OSX, you need to first build openexr; that will fail; then you need to set the rpath for the two utilities correctly, then try to build openexr again. install_name_tool -add_rpath $BUILD_ROOT/i/lib $BUILD_ROOT/b/ext_openexr/ext_openexr-prefix/src/ext_openexr-build/IlmImf/./b44ExpLogTable install_name_tool -add_rpath $BUILD_ROOT/i/lib $BUILD_ROOT/b/ext_openexr/ext_openexr-prefix/src/ext_openexr-build/IlmImf/./dwaLookups -Note for Windows: - -With MSVC 2015, the boost library has a name that later on makes the libraries unfindable, so you need to copy them. - - cd BUILDROOT\i\lib - copy boost_system-vc-mt-1_55.dll boost_system-vc140-mt-1_55.dll - copy boost_system-vc-mt-1_55.lib boost_system-vc140-mt-1_55.lib - - On All operating systems: cmake --build . --config RelWithDebInfo --target ext_png cmake --build . --config RelWithDebInfo --target ext_tiff cmake --build . --config RelWithDebInfo --target ext_gsl cmake --build . --config RelWithDebInfo --target ext_vc cmake --build . --config RelWithDebInfo --target ext_libraw cmake --build . --config RelWithDebInfo --target ext_openjpeg On Windows and OSX cmake --build . --config RelWithDebInfo --target ext_kwindowsystem On Windows (Note: skip this for now if you're using msvc 2015, poppler isn't compatible with that compiler yet) cmake --build . --config RelWithDebInfo --target ext_freetype cmake --build . --config RelWithDebInfo --target ext_poppler On Linux cmake --build . --config RelWithDebInfo --target ext_kcrash Note: poppler should be buildable on Linux as well with a home-built freetype and fontconfig, but I don't know how to make fontconfig find freetype, and on Linux, fontconfig is needed for poppler. Poppler is needed for PDF import. Note 2: libcurl still isn't available. == Build Krita == 1. Make a krita build directory: mkdir BUILDROOT/build 2. Enter the BUILDROOT/build 3. Run On Windows Depending on what you want to use, run this command for MSBuild (slower compiling, since it doesn't properly use all the CPU cores, but ships with Visual Studio) cmake ..\krita -G "Visual Studio 14 Win64" -DBoost_DEBUG=OFF -DBOOST_INCLUDEDIR=c:\dev\i\include -DBOOST_DEBUG=ON -DBOOST_ROOT=c:\dev\i -DBOOST_LIBRARYDIR=c:\dev\i\lib -DCMAKE_INSTALL_PREFIX=c:\dev\i -DCMAKE_PREFIX_PATH=c:\dev\i -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTING=OFF -DKDE4_BUILD_TESTS=OFF -DHAVE_MEMORY_LEAK_TRACKER=OFF -DPACKAGERS_BUILD=ON -Wno-dev -DDEFINE_NO_DEPRECATED=1 Or this to later use jom (faster compiling, uses all cores, ships with QtCreator/pre-built Qt binaries): cmake ..\krita -G "NMake Makefiles" -DBoost_DEBUG=OFF -DBOOST_INCLUDEDIR=c:\dev\i\include -DBOOST_DEBUG=ON -DBOOST_ROOT=c:\dev\i -DBOOST_LIBRARYDIR=c:\dev\i\lib -DCMAKE_INSTALL_PREFIX=c:\dev\i -DCMAKE_PREFIX_PATH=c:\dev\i -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTING=OFF -DKDE4_BUILD_TESTS=OFF -DHAVE_MEMORY_LEAK_TRACKER=OFF -DPACKAGERS_BUILD=ON -Wno-dev -DDEFINE_NO_DEPRECATED=1 On Linux cmake ../krita -DCMAKE_INSTALL_PREFIX=BUILDROOT/i -DDEFINE_NO_DEPRECATED=1 -DPACKAGERS_BUILD=ON -DBUILD_TESTING=OFF -DKDE4_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo On OSX cmake ../krita -DCMAKE_INSTALL_PREFIX=/Users/boud/dev/i -DDEFINE_NO_DEPRECATED=1 -DBUILD_TESTING=OFF -DKDE4_BUILD_TESTS=OFF -DPACKAGERS_BUILD=ON -DBUNDLE_INSTALL_DIR=$HOME/dev/i/bin -DCMAKE_BUILD_TYPE=RelWithDebInfo 4. Run On Linux and OSX make make install On Windows Either use MSBuild to build: cmake --build . --config RelWithDebInfo --target INSTALL Or use jom which should be in a path similar to C:\Qt\Qt5.6.0\Tools\QtCreator\bin\jom.exe. So, from the same folder, instead of running cmake run: "C:\Qt\Qt5.6.0\Tools\QtCreator\bin\jom.exe" install 6. Run krita: On Linux BUILDROOT/i/bin/krita On Windows BUILDROOT\i\bin\krita.exe On OSX BUILDROOT/i/bin/krita.app/Contents/MacOS/krita == Common Issues == -On Windows, if you get a 'mspdb140.dll' missing alert window, it means you did not run the bat file. Make sure to include the quotes in the command. +- On Windows, if you get a 'mspdb140.dll' missing alert window, it means you did not run the bat file. Make sure to include the quotes in the command: + "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat" -"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat" - - - +- On Windows, if you get an error about Qt5Core.dll missing/not found or nmake exit with an error that mention QT_PLUGIN_PATH, you have to copy a couple of dlls in the Qt build directory, look + for the N.B. in the Qt instructions at the start of the Readme. diff --git a/3rdparty/ext_boost/CMakeLists.txt b/3rdparty/ext_boost/CMakeLists.txt index f0dd7d2614..958fac24bc 100755 --- a/3rdparty/ext_boost/CMakeLists.txt +++ b/3rdparty/ext_boost/CMakeLists.txt @@ -1,52 +1,53 @@ SET(PREFIX_ext_boost "${EXTPREFIX}" ) if (MSVC) if (${CMAKE_GENERATOR} STREQUAL "Visual Studio 14 2015 Win64") ExternalProject_Add( ext_boost DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} URL http://files.kde.org/krita/build/dependencies/boost_1_55_0.zip URL_MD5 8aca361a4713a1f491b0a5e33fee0f1f CONFIGURE_COMMAND /bootstrap.bat --prefix=${PREFIX_ext_boost} BUILD_COMMAND /b2.exe --with-system --build-dir=build-dir --prefix=${PREFIX_ext_boost} toolset=msvc variant=release link=shared threading=multi architecture=x86 address-model=64 variant=release install INSTALL_COMMAND "" INSTALL_DIR ${EXTPREFIX_boost} - UPDATE_COMMAND "" + UPDATE_COMMAND ${CMAKE_COMMAND} -E copy ${PREFIX_ext_boost}/lib/boost_system-vc-mt-1_55.dll ${PREFIX_ext_boost}/lib/boost_system-vc140-mt-1_55.dll + COMMAND ${CMAKE_COMMAND} -E copy ${PREFIX_ext_boost}/lib/boost_system-vc-mt-1_55.lib ${PREFIX_ext_boost}/lib/boost_system-vc140-mt-1_55.lib ALWAYS 0 BUILD_IN_SOURCE 1 ) else() ExternalProject_Add( ext_boost DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} URL http://files.kde.org/krita/build/dependencies/boost_1_55_0.zip URL_MD5 8aca361a4713a1f491b0a5e33fee0f1f CONFIGURE_COMMAND /bootstrap.bat --prefix=${PREFIX_ext_boost} BUILD_COMMAND /b2.exe --with-system --build-dir=build-dir --prefix=${PREFIX_ext_boost} toolset=msvc variant=release link=shared threading=multi architecture=x86 variant=release install INSTALL_COMMAND "" INSTALL_DIR ${EXTPREFIX_boost} UPDATE_COMMAND "" ALWAYS 0 BUILD_IN_SOURCE 1 ) endif() else() ExternalProject_Add( ext_boost DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} URL http://files.kde.org/krita/build/dependencies/boost_1_55_0.tar.bz2 URL_MD5 d6eef4b4cacb2183f2bf265a5a03a354 CONFIGURE_COMMAND /bootstrap.sh --prefix=${PREFIX_ext_boost} --with-libraries=system BUILD_COMMAND /b2 install INSTALL_COMMAND "" INSTALL_DIR ${PREFIX_ext_boost} UPDATE_COMMAND "" ALWAYS 0 BUILD_IN_SOURCE 1 ) endif() diff --git a/3rdparty/ext_fftw3/CMakeLists.txt b/3rdparty/ext_fftw3/CMakeLists.txt index d936c8d57c..474363952a 100755 --- a/3rdparty/ext_fftw3/CMakeLists.txt +++ b/3rdparty/ext_fftw3/CMakeLists.txt @@ -1,50 +1,50 @@ SET(PREFIX_ext_fftw3 "${EXTPREFIX}" ) if (MSVC) if (${CMAKE_GENERATOR} STREQUAL "Visual Studio 14 2015 Win64") ExternalProject_Add( ext_fftw3 DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} URL http://files.kde.org/krita/build/dependencies/fftw-3.3.4-dll64.zip URL_MD5 c4ec1e6d84e7a8b1cd61121d11d44ee4 INSTALL_DIR ${PREFIX_ext_fftw3} CONFIGURE_COMMAND "" BUILD_COMMAND ${CMAKE_COMMAND} -E echo deploying fftw3 64 binary - INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory bin ${PREFIX_ext_fftw3} - COMMAND ${CMAKE_COMMAND} -E copy_directory lib ${PREFIX_ext_fftw3} - COMMAND ${CMAKE_COMMAND} -E copy_directory include ${PREFIX_ext_fftw3} + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory /bin ${PREFIX_ext_fftw3}/bin + COMMAND ${CMAKE_COMMAND} -E copy_directory /lib ${PREFIX_ext_fftw3}/lib + COMMAND ${CMAKE_COMMAND} -E copy_directory /include ${PREFIX_ext_fftw3}/include UPDATE_COMMAND "" ALWAYS 0 ) else() ExternalProject_Add( ext_fftw3 DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} URL http://files.kde.org/krita/build/dependencies/fftw-3.3.4-dll32.zip URL_MD5 03754fe2a7fbaf983b0cc9a728e0a5b3 INSTALL_DIR ${PREFIX_ext_fftw3} CONFIGURE_COMMAND "" BUILD_COMMAND ${CMAKE_COMMAND} -E echo deploying fftw3 32 binary - INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory bin ${PREFIX_ext_fftw3} - COMMAND ${CMAKE_COMMAND} -E copy_directory lib ${PREFIX_ext_fftw3} - COMMAND ${CMAKE_COMMAND} -E copy_directory include ${PREFIX_ext_fftw3} + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory /bin ${PREFIX_ext_fftw3}/bin + COMMAND ${CMAKE_COMMAND} -E copy_directory /lib ${PREFIX_ext_fftw3}/lib + COMMAND ${CMAKE_COMMAND} -E copy_directory /include ${PREFIX_ext_fftw3}/include UPDATE_COMMAND "" ALWAYS 0 ) endif() else (MSVC) ExternalProject_Add( ext_fftw3 DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} URL http://files.kde.org/krita/build/dependencies/fftw-3.3.4.tar.gz URL_MD5 2edab8c06b24feeb3b82bbb3ebf3e7b3 INSTALL_DIR ${PREFIX_ext_fftw3} CONFIGURE_COMMAND /configure --prefix=${PREFIX_ext_fftw3} ${GLOBAL_AUTOMAKE_PROFILE} --enable-static=false --enable-shared=yes BUILD_COMMAND make INSTALL_COMMAND make install UPDATE_COMMAND "" ALWAYS 0 ) endif (MSVC) diff --git a/3rdparty/ext_qt/CMakeLists.txt b/3rdparty/ext_qt/CMakeLists.txt index 2fb103b6dd..12442b0c19 100644 --- a/3rdparty/ext_qt/CMakeLists.txt +++ b/3rdparty/ext_qt/CMakeLists.txt @@ -1,69 +1,69 @@ SET(EXTPREFIX_qt "${EXTPREFIX}") if (WIN32) ExternalProject_Add( ext_qt DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} URL http://download.qt.io/development_releases/qt/5.6/5.6.0-beta/single/qt-everywhere-opensource-src-5.6.0-beta.zip - URL_MD5 d0c366ddf9796256e168ccce6b087175 + URL_MD5 5b44d298dd14aa861d34d623c162ec22 PATCH_COMMAND myptch -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/disable-wintab.diff + COMMAND myptch -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/qtgui-private-headers.diff INSTALL_DIR ${EXTPREFIX_qt} - CONFIGURE_COMMAND /configure.bat -no-sql-sqlite -opensource -nomake examples -confirm-license -no-dbus -prefix ${EXTPREFIX_qt} -I ${EXTPREFIX_qt}/include -L ${EXTPREFIX_qt}/lib -nomake tools -no-compile-examples -opengl desktop -no-iconv -no-angle -no-ssl -no-openssl -no-wmf-backend -no-qml-debug -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity -skip qtdoc -skip qtenginio -skip qtgraphicaleffects -skip qtlocation -skip qtmultimedia-skip qtsensors -skip qtserialport -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtxmlpatterns -qt-zlib -qt-pcre -no-icu -qt-libpng -qt-libjpeg -no-pch + CONFIGURE_COMMAND /configure.bat -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity -skip qtdoc -skip qtenginio -skip qtgraphicaleffects -skip qtlocation -skip qtmultimedia -skip qtsensors -skip qtserialport -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtxmlpatterns -no-sql-sqlite -nomake examples -nomake tools -no-compile-examples -no-dbus -no-iconv -no-angle -no-ssl -no-openssl -no-wmf-backend -no-qml-debug -no-libproxy -no-system-proxies -no-nis -no-icu -no-mtdev -opensource -confirm-license -release -opengl desktop -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -prefix ${EXTPREFIX_qt} BUILD_COMMAND nmake INSTALL_COMMAND nmake install UPDATE_COMMAND "" BUILD_IN_SOURCE 1 ALWAYS 0 - #DEPENDS ext_perl ) else() if (APPLE) ExternalProject_Add( ext_qt DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} URL http://download.qt.io/development_releases/qt/5.6/5.6.0-beta/single/qt-everywhere-opensource-src-5.6.0-beta.tar.gz URL_MD5 d0c366ddf9796256e168ccce6b087175 INSTALL_DIR ${EXTPREFIX_qt} CONFIGURE_COMMAND "/configure -confirm-license -opensource -nomake examples \ -no-pch -no-dbus -no-icu -no-iconv -no-openssl -no-nis \ -no-compile-examples -qt-freetype -qt-harfbuzz -opengl desktop \ -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity \ -skip qtenginio -skip qtgraphicaleffects -skip qtlocation -skip qtmultimedia \ -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets \ -skip qtwebview -skip qtxmlpatterns \ -prefix ${EXTPREFIX_qt} " BUILD_COMMAND make INSTALL_COMMAND make install UPDATE_COMMAND "" BUILD_IN_SOURCE 1 ALWAYS 0 ) else() ExternalProject_Add( ext_qt DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} URL http://download.qt.io/development_releases/qt/5.6/5.6.0-beta/single/qt-everywhere-opensource-src-5.6.0-beta.tar.gz URL_MD5 d0c366ddf9796256e168ccce6b087175 INSTALL_DIR ${EXTPREFIX_qt} CONFIGURE_COMMAND "/configure -prefix ${EXTPREFIX_qt} -I ${EXTPREFIX_qt}/include -L ${EXTPREFIX_qt}/lib \ -opensource -confirm-license -nomake examples \ -no-sql-sqlite -no-openssl -no-qml-debug -no-mtdev -no-journald -no-syslog -no-glib -no-pulseaudio -no-alsa -no-gtkstyle \ -no-nis -no-cups -no-iconv -no-tslib -no-icu -no-directfb -no-linuxfb -no-gstreamer -no-pch \ -qt-zlib -qt-pcre -no-icu -qt-libpng -qt-libjpeg -qt-harfbuzz -no-libproxy -qt-freetype -qt-xcb -qt-xkbcommon-x11 \ -optimized-qmake \ -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity \ -skip qtenginio -skip qtgraphicaleffects -skip qtlocation \ -skip qtmultimedia -skip qtwayland -skip qtwebchannel \ -skip qtwebengine -skip qtwebsockets -skip qtwebview \ -skip qtxmlpatterns" BUILD_COMMAND gmake INSTALL_COMMAND gmake install UPDATE_COMMAND "" BUILD_IN_SOURCE 1 ALWAYS 0 ) endif() -endif() +endif() \ No newline at end of file diff --git a/3rdparty/ext_qt/disable-wintab.diff b/3rdparty/ext_qt/disable-wintab.diff index f127c1a63e..797e2aedeb 100644 --- a/3rdparty/ext_qt/disable-wintab.diff +++ b/3rdparty/ext_qt/disable-wintab.diff @@ -1,63 +1,68 @@ -diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp -index f2f6402..09abbbf 100644 ---- a/src/plugins/platforms/windows/qwindowscontext.cpp -+++ b/src/plugins/platforms/windows/qwindowscontext.cpp -@@ -300,7 +300,6 @@ struct QWindowsContextPrivate { +diff --git a/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp b/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp +index f2f6402..9a5bc03 100644 +--- a/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp ++++ b/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp +@@ -299,9 +299,6 @@ struct QWindowsContextPrivate { + QWindowsMimeConverter m_mimeConverter; QWindowsScreenManager m_screenManager; QSharedPointer m_creationContext; - #if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) +-#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) - QScopedPointer m_tabletSupport; - #endif +-#endif const HRESULT m_oleInitializeResult; const QByteArray m_eventType; -@@ -347,15 +346,12 @@ QWindowsContext::QWindowsContext() : + QWindow *m_lastActiveWindow; +@@ -346,17 +343,10 @@ QWindowsContext::QWindowsContext() : + const QByteArray bv = qgetenv("QT_QPA_VERBOSE"); if (!bv.isEmpty()) QLoggingCategory::setFilterRules(QString::fromLocal8Bit(bv)); - #if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) +-#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) - d->m_tabletSupport.reset(QWindowsTabletSupport::create()); - qCDebug(lcQpaTablet) << "Tablet support: " << (d->m_tabletSupport.isNull() ? QStringLiteral("None") : d->m_tabletSupport->description()); - #endif +-#endif } QWindowsContext::~QWindowsContext() { - #if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) +-#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) - d->m_tabletSupport.reset(); // Destroy internal window before unregistering classes. - #endif +-#endif unregisterWindowClasses(); if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE) -@@ -397,12 +393,7 @@ bool QWindowsContext::initTouch(unsigned integrationOptions) + OleUninitialize(); +@@ -397,12 +387,7 @@ bool QWindowsContext::initTouch(unsigned integrationOptions) void QWindowsContext::setTabletAbsoluteRange(int a) { -#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) - if (!d->m_tabletSupport.isNull()) - d->m_tabletSupport->setAbsoluteRange(a); -#else Q_UNUSED(a) -#endif } void QWindowsContext::setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness) -@@ -777,11 +768,7 @@ QWindowsScreenManager &QWindowsContext::screenManager() +@@ -777,11 +762,7 @@ QWindowsScreenManager &QWindowsContext::screenManager() QWindowsTabletSupport *QWindowsContext::tabletSupport() const { -#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) - return d->m_tabletSupport.data(); -#else return 0; -#endif } /*! -@@ -1152,8 +1139,6 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, +@@ -1151,10 +1132,6 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, + *result = LRESULT(MA_NOACTIVATE); return true; } - #ifndef QT_NO_TABLETEVENT +-#ifndef QT_NO_TABLETEVENT - if (!d->m_tabletSupport.isNull()) - d->m_tabletSupport->notifyActivate(); - #endif // !QT_NO_TABLETEVENT +-#endif // !QT_NO_TABLETEVENT if (platformWindow->testFlag(QWindowsWindow::BlockedByModal)) if (const QWindow *modalWindow = QGuiApplication::modalWindow()) - + QWindowsWindow::baseWindowOf(modalWindow)->alertWindow(); diff --git a/3rdparty/ext_qt/qtgui-private-headers.diff b/3rdparty/ext_qt/qtgui-private-headers.diff new file mode 100644 index 0000000000..3e719feab6 --- /dev/null +++ b/3rdparty/ext_qt/qtgui-private-headers.diff @@ -0,0 +1,12 @@ +diff --git a/qtbase/mkspecs/features/create_cmake.prf b/qtbase/mkspecs/features/create_cmake.prf +index 11fb52a..aec9ea9 100644 +--- a/qtbase/mkspecs/features/create_cmake.prf ++++ b/qtbase/mkspecs/features/create_cmake.prf +@@ -30,7 +30,6 @@ CMAKE_MODULE_NAME = $$cmakeModuleName($${MODULE}) + + split_incpath { + CMAKE_ADD_SOURCE_INCLUDE_DIRS = true +- CMAKE_NO_PRIVATE_INCLUDES = true # Don't add private includes in the build dir which don't exist + CMAKE_SOURCE_INCLUDES = \ + $$cmakeTargetPaths($$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/Qt$${CMAKE_MODULE_NAME}) + CMAKE_SOURCE_PRIVATE_INCLUDES = \ diff --git a/libs/ui/CMakeLists.txt b/libs/ui/CMakeLists.txt index 1a32c18d90..199726b431 100644 --- a/libs/ui/CMakeLists.txt +++ b/libs/ui/CMakeLists.txt @@ -1,545 +1,548 @@ # Disable -Wswitch because of the extra definitions we here: # kis_input_manager.cpp: In member function ‘virtual bool KisInputManager::eventFilter(QObject*, QEvent*)’: # warning: case value ‘1001’ not in enumerated type ‘QEvent::Type’ [-Wswitch] # warning: case value ‘1002’ not in enumerated type ‘QEvent::Type’ [-Wswitch] if (CMAKE_COMPILER_IS_GNUCXX) add_definitions(${KDE4_ENABLE_EXCEPTIONS} -Wno-switch) endif () include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/flake ${CMAKE_CURRENT_SOURCE_DIR}/ora ${CMAKE_CURRENT_SOURCE_DIR}/qtsingleapplication ${CMAKE_CURRENT_SOURCE_DIR}/qtlockedfile ${CMAKE_CURRENT_SOURCE_DIR}/actions ${CMAKE_CURRENT_SOURCE_DIR}/canvas ${CMAKE_CURRENT_SOURCE_DIR}/dialogs ${CMAKE_CURRENT_SOURCE_DIR}/forms ${CMAKE_CURRENT_SOURCE_DIR}/input ${CMAKE_CURRENT_SOURCE_DIR}/input/config ${CMAKE_CURRENT_SOURCE_DIR}/input/wintab ${CMAKE_CURRENT_SOURCE_DIR}/kisexiv2 ${CMAKE_CURRENT_SOURCE_DIR}/kra ${CMAKE_CURRENT_SOURCE_DIR}/layerstyles ${CMAKE_CURRENT_SOURCE_DIR}/opengl ${CMAKE_CURRENT_SOURCE_DIR}/operations ${CMAKE_CURRENT_SOURCE_DIR}/processing ${CMAKE_CURRENT_SOURCE_DIR}/recorder ${CMAKE_CURRENT_SOURCE_DIR}/resourcemanager ${CMAKE_CURRENT_SOURCE_DIR}/tool ${CMAKE_CURRENT_SOURCE_DIR}/tool/strokes ${CMAKE_CURRENT_SOURCE_DIR}/widgets ${EXIV2_INCLUDE_DIR} ${EIGEN3_INCLUDE_DIR} ${OCIO_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ) add_subdirectory( tests ) if (APPLE) find_library(FOUNDATION_LIBRARY Foundation) endif () set(kritaui_LIB_SRCS canvas/kis_canvas_widget_base.cpp canvas/kis_canvas2.cpp canvas/kis_canvas_updates_compressor.cpp canvas/kis_canvas_controller.cpp canvas/kis_paintop_transformation_connector.cpp canvas/kis_display_color_converter.cpp canvas/kis_display_filter.cpp canvas/kis_exposure_gamma_correction_interface.cpp canvas/kis_tool_proxy.cpp canvas/kis_canvas_decoration.cc canvas/kis_coordinates_converter.cpp canvas/kis_grid_manager.cpp canvas/kis_grid_decoration.cpp canvas/kis_grid_painter_configuration.cpp canvas/kis_perspective_grid_manager.cpp canvas/kis_perspective_grid_decoration.cpp canvas/kis_prescaled_projection.cpp canvas/kis_qpainter_canvas.cpp canvas/kis_projection_backend.cpp canvas/kis_update_info.cpp canvas/kis_image_patch.cpp canvas/kis_image_pyramid.cpp canvas/kis_infinity_manager.cpp dialogs/kis_about_application.cpp dialogs/kis_dlg_adj_layer_props.cc dialogs/kis_dlg_adjustment_layer.cc dialogs/kis_dlg_filter.cpp dialogs/kis_dlg_generator_layer.cpp dialogs/kis_dlg_file_layer.cpp dialogs/kis_dlg_image_properties.cc dialogs/kis_dlg_layer_properties.cc dialogs/kis_dlg_preferences.cc dialogs/slider_and_spin_box_sync.cpp dialogs/kis_dlg_blacklist_cleanup.cpp dialogs/kis_dlg_layer_style.cpp dialogs/kis_dlg_png_import.cpp dialogs/kis_dlg_import_image_sequence.cpp dialogs/kis_delayed_save_dialog.cpp flake/kis_node_dummies_graph.cpp flake/kis_dummies_facade_base.cpp flake/kis_dummies_facade.cpp flake/kis_node_shapes_graph.cpp flake/kis_node_shape.cpp flake/kis_shape_controller.cpp flake/kis_shape_layer.cc flake/kis_shape_layer_canvas.cpp flake/kis_shape_selection.cpp flake/kis_shape_selection_canvas.cpp flake/kis_shape_selection_model.cpp flake/kis_take_all_shapes_command.cpp kis_autogradient.cc kis_bookmarked_configurations_editor.cc kis_bookmarked_configurations_model.cc kis_bookmarked_filter_configurations_model.cc kis_canvas_resource_provider.cpp kis_categories_mapper.cpp kis_categorized_list_model.cpp kis_categorized_item_delegate.cpp kis_clipboard.cc kis_config.cc kis_config_notifier.cpp kis_control_frame.cpp kis_composite_ops_model.cc kis_paint_ops_model.cpp kis_cursor.cc kis_custom_pattern.cc kis_file_layer.cpp kis_safe_document_loader.cpp kis_splash_screen.cpp kis_filter_manager.cc kis_filters_model.cc kis_histogram_view.cc kis_image_manager.cc kis_image_view_converter.cpp kis_import_catcher.cc kis_layer_manager.cc kis_mask_manager.cc kis_mimedata.cpp kis_node_commands_adapter.cpp kis_node_manager.cpp kis_node_juggler_compressed.cpp kis_node_selection_adapter.cpp kis_node_insertion_adapter.cpp kis_node_model.cpp kis_model_index_converter_base.cpp kis_model_index_converter.cpp kis_model_index_converter_show_all.cpp kis_painting_assistant.cc kis_painting_assistants_decoration.cpp kis_painting_assistants_manager.cpp kis_paintop_box.cc kis_paintop_option.cpp kis_paintop_options_model.cpp kis_paintop_settings_widget.cpp kis_popup_palette.cpp kis_png_converter.cpp kis_preference_set_registry.cpp kis_resource_server_provider.cpp kis_selection_decoration.cc kis_selection_manager.cc kis_statusbar.cc kis_zoom_manager.cc kis_favorite_resource_manager.cpp kis_workspace_resource.cpp kis_action.cpp kis_action_manager.cpp kis_view_plugin.cpp kis_canvas_controls_manager.cpp kis_tooltip_manager.cpp kis_multinode_property.cpp kis_async_action_feedback.cpp kisexiv2/kis_exif_io.cpp kisexiv2/kis_exiv2.cpp kisexiv2/kis_iptc_io.cpp kisexiv2/kis_xmp_io.cpp kra/kis_kra_utils.cpp kra/kis_kra_load_visitor.cpp kra/kis_kra_loader.cpp kra/kis_kra_save_visitor.cpp kra/kis_kra_saver.cpp kra/kis_kra_savexml_visitor.cpp opengl/kis_opengl.cpp opengl/kis_opengl_canvas2.cpp opengl/kis_opengl_canvas_debugger.cpp opengl/kis_opengl_image_textures.cpp opengl/kis_texture_tile.cpp opengl/kis_texture_tile_update_info.cpp kis_fps_decoration.cpp ora/kis_open_raster_stack_load_visitor.cpp ora/kis_open_raster_stack_save_visitor.cpp ora/ora_load_context.cc ora/ora_save_context.cc recorder/kis_node_query_path_editor.cc recorder/kis_recorded_action_creator.cc recorder/kis_recorded_action_creator_factory.cc recorder/kis_recorded_action_creator_factory_registry.cc recorder/kis_recorded_action_editor_factory.cc recorder/kis_recorded_action_editor_factory_registry.cc recorder/kis_recorded_filter_action_editor.cc recorder/kis_recorded_filter_action_creator.cpp recorder/kis_recorded_paint_action_editor.cc tool/kis_selection_tool_helper.cpp tool/kis_selection_tool_config_widget_helper.cpp tool/kis_rectangle_constraint_widget.cpp tool/kis_shape_tool_helper.cpp tool/kis_tool.cc tool/kis_delegated_tool_policies.cpp tool/kis_tool_freehand.cc tool/kis_speed_smoother.cpp tool/kis_painting_information_builder.cpp tool/kis_tool_freehand_helper.cpp tool/kis_tool_multihand_helper.cpp tool/kis_figure_painting_tool_helper.cpp tool/kis_recording_adapter.cpp tool/kis_tool_paint.cc tool/kis_tool_shape.cc tool/kis_tool_ellipse_base.cpp tool/kis_tool_rectangle_base.cpp tool/kis_tool_polyline_base.cpp tool/kis_tool_utils.cpp tool/kis_resources_snapshot.cpp tool/kis_smoothing_options.cpp tool/strokes/freehand_stroke.cpp tool/strokes/kis_painter_based_stroke_strategy.cpp tool/strokes/kis_filter_stroke_strategy.cpp widgets/kis_cmb_composite.cc widgets/kis_cmb_contour.cpp widgets/kis_cmb_gradient.cpp widgets/kis_paintop_list_widget.cpp widgets/kis_cmb_idlist.cc widgets/kis_color_space_selector.cc widgets/kis_advanced_color_space_selector.cc widgets/kis_cie_tongue_widget.cpp widgets/kis_tone_curve_widget.cpp widgets/kis_curve_widget.cpp widgets/kis_custom_image_widget.cc widgets/kis_image_from_clipboard_widget.cpp widgets/kis_double_widget.cc widgets/kis_filter_selector_widget.cc widgets/kis_gradient_chooser.cc widgets/kis_gradient_slider_widget.cc widgets/kis_gradient_slider.cpp widgets/kis_iconwidget.cc widgets/kis_mask_widgets.cpp widgets/kis_meta_data_merge_strategy_chooser_widget.cc widgets/kis_multi_bool_filter_widget.cc widgets/kis_multi_double_filter_widget.cc widgets/kis_multi_integer_filter_widget.cc widgets/kis_multipliers_double_slider_spinbox.cpp widgets/kis_paintop_presets_popup.cpp widgets/kis_tool_options_popup.cpp widgets/kis_paintop_presets_chooser_popup.cpp widgets/kis_pattern_chooser.cc widgets/kis_popup_button.cc widgets/kis_preset_chooser.cpp widgets/kis_progress_widget.cpp widgets/kis_selection_options.cc widgets/kis_scratch_pad.cpp widgets/kis_scratch_pad_event_filter.cpp widgets/kis_preset_selector_strip.cpp widgets/kis_tree_view_popup.cc widgets/kis_slider_spin_box.cpp widgets/kis_size_group.cpp widgets/kis_size_group_p.cpp widgets/kis_wdg_generator.cpp widgets/kis_workspace_chooser.cpp widgets/squeezedcombobox.cpp widgets/kis_categorized_list_view.cpp widgets/kis_widget_chooser.cpp widgets/kis_tool_button.cpp widgets/kis_floating_message.cpp widgets/kis_lod_availability_widget.cpp input/kis_input_manager.cpp input/kis_input_manager_p.cpp input/kis_extended_modifiers_mapper.cpp input/kis_abstract_input_action.cpp input/kis_tool_invocation_action.cpp input/kis_pan_action.cpp input/kis_alternate_invocation_action.cpp input/kis_rotate_canvas_action.cpp input/kis_zoom_action.cpp input/kis_change_frame_action.cpp input/kis_gamma_exposure_action.cpp input/kis_show_palette_action.cpp input/kis_change_primary_setting_action.cpp input/kis_abstract_shortcut.cpp input/kis_single_action_shortcut.cpp input/kis_stroke_shortcut.cpp input/kis_shortcut_matcher.cpp input/kis_select_layer_action.cpp operations/kis_operation.cpp operations/kis_operation_configuration.cpp operations/kis_operation_registry.cpp operations/kis_operation_ui_factory.cpp operations/kis_operation_ui_widget.cpp operations/kis_filter_selection_operation.cpp actions/kis_selection_action_factories.cpp input/kis_touch_shortcut.cpp kis_document_undo_store.cpp kis_transaction_based_command.cpp kis_gui_context_command.cpp kis_gui_context_command_p.cpp input/kis_tablet_debugger.cpp input/kis_input_profile_manager.cpp input/kis_input_profile.cpp input/kis_shortcut_configuration.cpp input/config/kis_input_configuration_page.cpp input/config/kis_edit_profiles_dialog.cpp input/config/kis_input_profile_model.cpp input/config/kis_input_configuration_page_item.cpp input/config/kis_action_shortcuts_model.cpp input/config/kis_input_type_delegate.cpp input/config/kis_input_mode_delegate.cpp input/config/kis_input_button.cpp input/config/kis_input_editor_delegate.cpp input/config/kis_mouse_input_editor.cpp input/config/kis_wheel_input_editor.cpp input/config/kis_key_input_editor.cpp processing/fill_processing_visitor.cpp kis_asl_layer_style_serializer.cpp kis_psd_layer_style_resource.cpp canvas/kis_mirror_axis.cpp kis_abstract_perspective_grid.cpp KisApplication.cpp KisAutoSaveRecoveryDialog.cpp KisDetailsPane.cpp KisDocument.cpp KisDocumentEntry.cpp KisNodeDelegate.cpp KisNodeToolTip.cpp KisNodeView.cpp KisFilterChain.cpp KisFilterChainLink.cpp KisFilterChainLinkList.cpp KisImportExportFilter.cpp KisFilterEdge.cpp KisFilterEntry.cpp KisFilterGraph.cpp KisImportExportManager.cpp KisImportExportManager_p.cpp KisFilterVertex.cpp KisMainWindow.cpp KisOpenPane.cpp KisPart.cpp KisPrintJob.cpp KisTemplate.cpp KisTemplateCreateDia.cpp KisTemplateGroup.cpp KisTemplates.cpp KisTemplatesPane.cpp KisTemplateTree.cpp KisUndoStackAction.cpp KisView.cpp thememanager.cpp kis_mainwindow_observer.cpp KisViewManager.cpp kis_mirror_manager.cpp qtlockedfile/qtlockedfile.cpp qtsingleapplication/qtlocalpeer.cpp qtsingleapplication/qtsingleapplication.cpp KisResourceBundle.cpp KisResourceBundleManifest.cpp kis_md5_generator.cpp KisApplicationArguments.cpp KisNetworkAccessManager.cpp KisWelcomeScreen.cpp KisMultiFeedRSSModel.cpp KisPaletteModel.cpp KisColorsetChooser.cpp ) if(WIN32) + if (NOT Qt5Gui_PRIVATE_INCLUDE_DIRS) + message(FATAL_ERROR "Qt5Gui Private header are missing!") + endif() set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} input/kis_tablet_event.cpp input/wintab/kis_tablet_support_win.cpp input/wintab/kis_screen_size_choice_dialog.cpp qtlockedfile/qtlockedfile_win.cpp ) include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS}) endif() if (HAVE_OPENGL) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} kis_animation_frame_cache.cpp kis_animation_cache_populator.cpp canvas/kis_animation_player.cpp kis_animation_exporter.cpp kis_animation_importer.cpp ) endif() if(UNIX) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} input/kis_tablet_event.cpp input/wintab/kis_tablet_support.cpp qtlockedfile/qtlockedfile_unix.cpp ) if(NOT APPLE) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} input/wintab/kis_tablet_support_x11.cpp input/wintab/qxcbconnection_xi2.cpp input/wintab/qxcbconnection.cpp input/wintab/kis_xi2_event_filter.cpp ) endif() endif() kde_enable_exceptions() if(WIN32) #ki18n_wrap_ui( # input/wintab/kis_screen_size_choice_dialog.ui #) endif() ki18n_wrap_ui(kritaui_LIB_SRCS forms/wdgdlgpngimport.ui forms/wdgfullscreensettings.ui forms/wdgautogradient.ui forms/wdggeneralsettings.ui forms/wdgperformancesettings.ui forms/wdggridsettings.ui forms/wdggenerators.ui forms/wdgcustompalette.ui forms/wdgbookmarkedconfigurationseditor.ui forms/wdgapplyprofile.ui forms/wdgcustompattern.ui forms/wdglayerproperties.ui forms/wdgcolorsettings.ui forms/wdgtabletsettings.ui forms/wdgcolorspaceselector.ui forms/wdgcolorspaceselectoradvanced.ui forms/wdgdisplaysettings.ui forms/kis_previewwidgetbase.ui forms/kis_matrix_widget.ui forms/wdgselectionoptions.ui forms/wdggeometryoptions.ui forms/wdgnewimage.ui forms/wdgimageproperties.ui forms/wdgmaskfromselection.ui forms/wdgmasksource.ui forms/wdgfilterdialog.ui forms/wdgmetadatamergestrategychooser.ui forms/wdgpaintoppresets.ui forms/wdgpaintopsettings.ui forms/wdgdlggeneratorlayer.ui forms/wdgdlgfilelayer.ui forms/wdgfilterselector.ui forms/wdgfilternodecreation.ui forms/wdgpaintactioneditor.ui forms/wdgmultipliersdoublesliderspinbox.ui forms/wdgnodequerypatheditor.ui forms/wdgpresetselectorstrip.ui forms/wdgdlgblacklistcleanup.ui forms/wdgrectangleconstraints.ui forms/wdgimportimagesequence.ui forms/KisDetailsPaneBase.ui forms/KisOpenPaneBase.ui dialogs/kis_delayed_save_dialog.ui input/config/kis_input_configuration_page.ui input/config/kis_edit_profiles_dialog.ui input/config/kis_input_configuration_page_item.ui input/config/kis_mouse_input_editor.ui input/config/kis_wheel_input_editor.ui input/config/kis_key_input_editor.ui layerstyles/wdgBevelAndEmboss.ui layerstyles/wdgblendingoptions.ui layerstyles/WdgColorOverlay.ui layerstyles/wdgContour.ui layerstyles/wdgdropshadow.ui layerstyles/WdgGradientOverlay.ui layerstyles/wdgInnerGlow.ui layerstyles/wdglayerstyles.ui layerstyles/WdgPatternOverlay.ui layerstyles/WdgSatin.ui layerstyles/WdgStroke.ui layerstyles/wdgstylesselector.ui layerstyles/wdgTexture.ui wdgsplash.ui input/wintab/kis_screen_size_choice_dialog.ui ) QT5_WRAP_CPP(kritaui_HEADERS_MOC KisNodePropertyAction_p.h) add_library(kritaui SHARED ${kritaui_HEADERS_MOC} ${kritaui_LIB_SRCS} ) generate_export_header(kritaui BASE_NAME kritaui) target_link_libraries(kritaui KF5::CoreAddons KF5::Completion KF5::I18n KF5::ItemViews Qt5::Network kritacolor kritaimage kritalibbrush kritawidgets kritawidgetutils ${PNG_LIBRARIES} ${EXIV2_LIBRARIES} ) if (HAVE_KIO) target_link_libraries(kritaui KF5::KIOCore) endif() if (NOT WIN32 AND NOT APPLE) target_link_libraries(kritaui ${X11_X11_LIB} ${X11_Xinput_LIB} ${XCB_LIBRARIES}) endif() if(APPLE) target_link_libraries(kritaui ${FOUNDATION_LIBRARY}) endif () if(HAVE_OPENEXR) target_link_libraries(kritaui ${OPENEXR_LIBRARIES}) endif() if(HAVE_OPENGL) # Add VSync disable workaround if(NOT WIN32 AND NOT APPLE) target_link_libraries(kritaui ${CMAKE_DL_LIBS} Qt5::X11Extras) endif() endif() if(X11_FOUND) target_link_libraries(kritaui Qt5::X11Extras ${X11_LIBRARIES}) endif() target_link_libraries(kritaui LINK_INTERFACE_LIBRARIES kritaimage kritalibbrush kritapigment KF5::Completion KF5::I18n ${GL_INTERFACE_LIBRARIES}) target_include_directories(kritaui PUBLIC $ $ $ $ $ $ ) set_target_properties(kritaui PROPERTIES VERSION ${GENERIC_CALLIGRA_LIB_VERSION} SOVERSION ${GENERIC_CALLIGRA_LIB_SOVERSION} ) install(TARGETS kritaui ${INSTALL_TARGETS_DEFAULT_ARGS}) if (APPLE) install(FILES osx.stylesheet DESTINATION ${DATA_INSTALL_DIR}/krita) endif () diff --git a/libs/ui/KisApplication.cpp b/libs/ui/KisApplication.cpp index 060a25b9b7..838174ab28 100644 --- a/libs/ui/KisApplication.cpp +++ b/libs/ui/KisApplication.cpp @@ -1,727 +1,728 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright (C) 2009 Thomas Zander 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KoGlobal.h" #include "KoConfig.h" #include #include #include "thememanager.h" #include "KisPrintJob.h" #include "KisDocumentEntry.h" #include "KisDocument.h" #include "KisMainWindow.h" #include "KisAutoSaveRecoveryDialog.h" #include "KisPart.h" #include #include "kis_md5_generator.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 #ifdef HAVE_OPENGL #include "opengl/kis_opengl.h" #endif #include namespace { const QTime appStartTime(QTime::currentTime()); } class KisApplicationPrivate { public: KisApplicationPrivate() : splashScreen(0) {} QWidget *splashScreen; }; class KisApplication::ResetStarting { public: ResetStarting(QWidget *splash = 0) : m_splash(splash) { } ~ResetStarting() { if (m_splash) { KConfigGroup cfg( KSharedConfig::openConfig(), "SplashScreen"); bool hideSplash = cfg.readEntry("HideSplashAfterStartup", false); if (hideSplash) { m_splash->hide(); } else { m_splash->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); QRect r(QPoint(), m_splash->size()); m_splash->move(QApplication::desktop()->availableGeometry().center() - r.center()); m_splash->setWindowTitle(qAppName()); Q_FOREACH (QObject *o, m_splash->children()) { QWidget *w = qobject_cast(o); if (w && w->isHidden()) { w->setVisible(true); } } m_splash->show(); } } } QWidget *m_splash; }; KisApplication::KisApplication(const QString &key, int &argc, char **argv) : QtSingleApplication(key, argc, argv) , d(new KisApplicationPrivate) { 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 = CalligraVersionWrapper::versionString(true); setApplicationVersion(version); setWindowIcon(KisIconUtils::loadIcon("calligrakrita")); QStringList styles = QStringList() << "Fusion" << "Plastique"; if (!styles.contains(style()->objectName())) { Q_FOREACH (const QString & style, styles) { if (!setStyle(style)) { qDebug() << "No" << style << "available."; } else { qDebug() << "Set style" << style; break; } } } #ifdef HAVE_OPENGL KisOpenGL::initialize(); /** * Warn about Intel's broken video drivers */ #if defined HAVE_OPENGL && defined Q_OS_WIN KisConfig cfg; QString renderer = KisOpenGL::renderer(); if (cfg.useOpenGL() && renderer.startsWith("Intel") && !cfg.readEntry("WarnedAboutIntel", false)) { QMessageBox::information(0, i18nc("@title:window", "Krita: Warning"), i18n("You have an Intel(R) HD Graphics video adapter.\n" "If you experience problems like a black or blank screen," "please update your display driver to the latest version.\n\n" "You can also disable OpenGL rendering in Krita's Settings.\n")); cfg.writeEntry("WarnedAboutIntel", true); } #endif #endif } #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(NULL != fnIsWow64Process) { if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) { //handle error } } return bIsWow64; } #endif void initializeGlobals(const KisApplicationArguments &args) { int dpiX = args.dpiX(); int dpiY = args.dpiY(); if (dpiX > 0 && dpiY > 0) { KoDpi::setDPI(dpiX, dpiY); } } void addResourceTypes() { // All Krita's resource types KoResourcePaths::addResourceType("kis_pics", "data", "/pics/"); KoResourcePaths::addResourceType("kis_images", "data", "/images/"); KoResourcePaths::addResourceType("icc_profiles", "data", "/profiles/"); KoResourcePaths::addResourceType("metadata_schema", "data", "/metadata/schemas/"); KoResourcePaths::addResourceType("kis_brushes", "data", "/brushes/"); KoResourcePaths::addResourceType("kis_taskset", "data", "/taskset/"); KoResourcePaths::addResourceType("kis_taskset", "data", "/taskset/"); KoResourcePaths::addResourceType("gmic_definitions", "data", "/gmic/"); KoResourcePaths::addResourceType("kis_resourcebundles", "data", "/bundles/"); KoResourcePaths::addResourceType("kis_defaultpresets", "data", "/defaultpresets/"); KoResourcePaths::addResourceType("kis_paintoppresets", "data", "/paintoppresets/"); KoResourcePaths::addResourceType("kis_workspaces", "data", "/workspaces/"); KoResourcePaths::addResourceType("psd_layer_style_collections", "data", "/asl"); KoResourcePaths::addResourceType("ko_patterns", "data", "/patterns/", true); KoResourcePaths::addResourceType("ko_gradients", "data", "/gradients/"); KoResourcePaths::addResourceType("ko_gradients", "data", "/gradients/", true); KoResourcePaths::addResourceType("ko_palettes", "data", "/palettes/", true); KoResourcePaths::addResourceType("kis_shortcuts", "data", "/shortcuts/"); KoResourcePaths::addResourceType("kis_actions", "data", "/actions"); KoResourcePaths::addResourceType("icc_profiles", "data", "/color/icc"); KoResourcePaths::addResourceType("ko_effects", "data", "/effects/"); KoResourcePaths::addResourceType("tags", "data", "/tags/"); // // Extra directories to look for create resources. (Does anyone actually use that anymore?) // KoResourcePaths::addResourceDir("ko_gradients", "/usr/share/create/gradients/gimp"); // KoResourcePaths::addResourceDir("ko_gradients", QDir::homePath() + QString("/.create/gradients/gimp")); // KoResourcePaths::addResourceDir("ko_patterns", "/usr/share/create/patterns/gimp"); // KoResourcePaths::addResourceDir("ko_patterns", QDir::homePath() + QString("/.create/patterns/gimp")); // KoResourcePaths::addResourceDir("kis_brushes", "/usr/share/create/brushes/gimp"); // KoResourcePaths::addResourceDir("kis_brushes", QDir::homePath() + QString("/.create/brushes/gimp")); // KoResourcePaths::addResourceDir("ko_palettes", "/usr/share/create/swatches"); // KoResourcePaths::addResourceDir("ko_palettes", QDir::homePath() + QString("/.create/swatches")); // Make directories for all resources we can save, and tags QDir d; d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tags/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/asl/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/bundles/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/gradients/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/paintoppresets/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/palettes/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/patterns/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/taskset/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/workspaces/"); } void loadResources() { // Load base resources KoResourceServerProvider::instance()->gradientServer(true); KoResourceServerProvider::instance()->patternServer(true); KoResourceServerProvider::instance()->paletteServer(false); KisBrushServer::instance()->brushServer(true); // load paintop presets KisResourceServerProvider::instance()->paintOpPresetServer(true); KisResourceServerProvider::instance()->resourceBundleServer(); } void loadPlugins() { KoShapeRegistry* r = KoShapeRegistry::instance(); r->add(new KisShapeSelectionFactory()); KisActionRegistry::instance(); KisFilterRegistry::instance(); KisGeneratorRegistry::instance(); KisPaintOpRegistry::instance(); KoColorSpaceRegistry::instance(); // Load the krita-specific tools KoPluginLoader::instance()->load(QString::fromLatin1("Krita/Tool"), QString::fromLatin1("[X-Krita-Version] == 28")); // Load dockers KoPluginLoader::instance()->load(QString::fromLatin1("Krita/Dock"), QString::fromLatin1("[X-Krita-Version] == 28")); // XXX_EXIV: make the exiv io backends real plugins KisExiv2::initialize(); } bool KisApplication::start(const KisApplicationArguments &args) { #if defined(Q_OS_WIN) || defined (Q_OS_MAC) #ifdef ENV32BIT KisConfig cfg; 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 QDir appdir(applicationDirPath()); appdir.cdUp(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); // If there's no kdehome, set it and restart the process. if (!env.contains("XDG_DATA_DIRS")) { qDebug() << "Setting XDG_DATA_DIRS" << KoResourcePaths::getApplicationRoot() + "/share"; qputenv("XDG_DATA_DIRS", QFile::encodeName(KoResourcePaths::getApplicationRoot() + "/share")); } qputenv("PATH", QFile::encodeName(appdir.absolutePath() + "/bin" + ";" + appdir.absolutePath() + "/lib" + ";" + appdir.absolutePath() + "/lib/kde4" + ";" + appdir.absolutePath() + "/Frameworks" + ";" + appdir.absolutePath())); #endif initializeGlobals(args); const bool doTemplate = args.doTemplate(); const bool print = args.print(); const bool exportAs = args.exportAs(); const bool exportAsPdf = args.exportAsPdf(); const QString exportFileName = args.exportFileName(); const QString profileFileName = args.profileFileName(); const bool batchRun = (print || exportAs || exportAsPdf); // print & exportAsPdf do user interaction ATM const bool needsMainWindow = !exportAs; // only show the mainWindow when no command-line mode option is passed // TODO: fix print & exportAsPdf to work without mainwindow shown const bool showmainWindow = !exportAs; // would be !batchRun; const bool showSplashScreen = !batchRun && !qgetenv("NOSPLASH").isEmpty(); if (showSplashScreen) { d->splashScreen->show(); d->splashScreen->repaint(); processEvents(); } KoHashGeneratorProvider::instance()->setGenerator("MD5", new KisMD5Generator()); // Initialize all Calligra directories etc. KoGlobal::initialize(); KConfigGroup group(KSharedConfig::openConfig(), "theme"); Digikam::ThemeManager themeManager; themeManager.setCurrentTheme(group.readEntry("Theme", "Krita dark")); ResetStarting resetStarting(d->splashScreen); // remove the splash when done Q_UNUSED(resetStarting); // Make sure we can save resources and tags addResourceTypes(); // Load all resources and tags before the plugins do that loadResources(); // Load the plugins loadPlugins(); KisMainWindow *mainWindow = 0; if (needsMainWindow) { // show a mainWindow asap, if we want that mainWindow = KisPart::instance()->createMainWindow(); if (showmainWindow) { QTimer::singleShot(1, mainWindow, SLOT(show())); } } short int numberOfOpenDocuments = 0; // number of documents open // Check for autosave files that can be restored, if we're not running a batchrun (test, print, export to pdf) QList urls = checkAutosaveFiles(); if (!batchRun && mainWindow) { Q_FOREACH (const QUrl &url, urls) { KisDocument *doc = KisPart::instance()->createDocument(); mainWindow->openDocumentInternal(url, doc); } } // Get the command line arguments which we have to parse int argsCount = args.filenames().count(); if (argsCount > 0) { QTextStream profileoutput; profileoutput.setCodec("UTF-8"); QFile profileFile(profileFileName); if (!profileFileName.isEmpty() && profileFile.open(QFile::WriteOnly | QFile::Truncate)) { profileoutput.setDevice(&profileFile); } // Loop through arguments short int nPrinted = 0; for (int argNumber = 0; argNumber < argsCount; argNumber++) { QString fileName = args.filenames().at(argNumber); // are we just trying to open a template? if (doTemplate) { // called in mix with batch options? ignore and silently skip if (batchRun) { continue; } if (createNewDocFromTemplate(fileName, mainWindow)) { ++numberOfOpenDocuments; } // now try to load } else { if (exportAs) { QMimeType outputMimetype; QMimeDatabase db; outputMimetype = db.mimeTypeForFile(exportFileName); if (outputMimetype.isDefault()) { dbgKrita << i18n("Mimetype not found, try using the -mimetype option") << endl; return 1; } QApplication::setOverrideCursor(Qt::WaitCursor); QString outputFormat = outputMimetype.name(); KisImportExportFilter::ConversionStatus status = KisImportExportFilter::OK; KisImportExportManager manager(fileName); manager.setBatchMode(true); QByteArray mime(outputFormat.toLatin1()); status = manager.exportDocument(exportFileName, mime); if (status != KisImportExportFilter::OK) { dbgKrita << "Could not export " << fileName << "to" << exportFileName << ":" << (int)status; } nPrinted++; QTimer::singleShot(0, this, SLOT(quit())); } else if (mainWindow) { KisDocument *doc = KisPart::instance()->createDocument(); if (mainWindow->openDocumentInternal(QUrl::fromLocalFile(fileName), doc)) { if (print) { mainWindow->slotFilePrint(); nPrinted++; // TODO: trigger closing of app once printing is done } else if (exportAsPdf) { KisPrintJob *job = mainWindow->exportToPdf(exportFileName); if (job) connect (job, SIGNAL(destroyed(QObject*)), mainWindow, SLOT(slotFileQuit()), Qt::QueuedConnection); nPrinted++; } else { // Normal case, success numberOfOpenDocuments++; } } else { // .... if failed // delete doc; done by openDocument } } } } if (batchRun) { return nPrinted > 0; } } // not calling this before since the program will quit there. return true; } KisApplication::~KisApplication() { delete d; } void KisApplication::setSplashScreen(QWidget *splashScreen) { d->splashScreen = splashScreen; } bool KisApplication::notify(QObject *receiver, QEvent *event) { try { return QApplication::notify(receiver, event); } catch (std::exception &e) { qWarning("Error %s sending event %i to object %s", e.what(), event->type(), qPrintable(receiver->objectName())); } catch (...) { qWarning("Error sending event %i to object %s", event->type(), qPrintable(receiver->objectName())); } return false; } void KisApplication::remoteArguments(QByteArray message, QObject *socket) { Q_UNUSED(socket); // check if we have any mainwindow KisMainWindow *mw = qobject_cast(qApp->activeWindow()); if (!mw) { mw = KisPart::instance()->mainWindows().first(); } if (!mw) { return; } KisApplicationArguments args = KisApplicationArguments::deserialize(message); const bool doTemplate = args.doTemplate(); const int argsCount = args.filenames().count(); if (argsCount > 0) { // Loop through arguments for (int argNumber = 0; argNumber < argsCount; ++argNumber) { QString filename = args.filenames().at(argNumber); // are we just trying to open a template? if (doTemplate) { createNewDocFromTemplate(filename, mw); } else if (QFile(filename).exists()) { KisDocument *doc = KisPart::instance()->createDocument(); mw->openDocumentInternal(QUrl::fromLocalFile(filename), doc); } } } } void KisApplication::fileOpenRequested(const QString &url) { KisMainWindow *mainWindow = KisPart::instance()->mainWindows().first(); if (mainWindow) { KisDocument *doc = KisPart::instance()->createDocument(); mainWindow->openDocumentInternal(QUrl::fromLocalFile(url), doc); } } QList KisApplication::checkAutosaveFiles() { // Check for autosave files from a previous run. There can be several, and // we want to offer a restore for every one. Including a nice thumbnail! QStringList autoSaveFiles; QStringList filters; filters << QString(".krita-*-*-autosave.kra"); #ifdef Q_OS_WIN QDir dir = QDir::temp(); #else QDir dir = QDir::home(); #endif // all autosave files for our application autoSaveFiles = dir.entryList(filters, QDir::Files | QDir::Hidden); // Allow the user to make their selection if (autoSaveFiles.size() > 0) { KisAutoSaveRecoveryDialog *dlg = new KisAutoSaveRecoveryDialog(autoSaveFiles, activeWindow()); if (dlg->exec() == QDialog::Accepted) { QStringList filesToRecover = dlg->recoverableFiles(); Q_FOREACH (const QString &autosaveFile, autoSaveFiles) { if (!filesToRecover.contains(autosaveFile)) { QFile::remove(dir.absolutePath() + "/" + autosaveFile); } } autoSaveFiles = filesToRecover; } else { // don't recover any of the files, but don't delete them either autoSaveFiles.clear(); } + delete dlg; } QList autosaveUrls; if (autoSaveFiles.size() > 0) { Q_FOREACH (const QString &autoSaveFile, autoSaveFiles) { const QUrl url = QUrl::fromLocalFile(dir.absolutePath() + QLatin1Char('/') + autoSaveFile); autosaveUrls << url; } } return autosaveUrls; } 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 = KisPart::instance()->templatesResourcePath(); 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); KisDocument *doc = KisPart::instance()->createDocument(); if (mainWindow->openDocumentInternal(templateURL, doc)) { doc->resetURL(); doc->setEmpty(); doc->setTitleModified(); dbgUI << "Template loaded..."; return true; } else { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Template %1 failed to load.", templateURL.toDisplayString())); } } return false; } void KisApplication::clearConfig() { KIS_ASSERT_RECOVER_RETURN(qApp->thread() == QThread::currentThread()); KSharedConfigPtr config = KSharedConfig::openConfig(); // find user settings file bool createDir = false; QString kritarcPath = KoResourcePaths::locateLocal("config", "kritarc", createDir); QFile configFile(kritarcPath); if (configFile.exists()) { // clear file if (configFile.open(QFile::WriteOnly)) { configFile.close(); } else { QMessageBox::warning(0, i18nc("@title:window", "Krita"), i18n("Failed to clear %1\n\n" "Please make sure no other program is using the file and try again.", kritarcPath), QMessageBox::Ok, QMessageBox::Ok); } } // reload from disk; with the user file settings cleared, // this should load any default configuration files shipping with the program config->reparseConfiguration(); config->sync(); } void KisApplication::askClearConfig() { Qt::KeyboardModifiers mods = QApplication::queryKeyboardModifiers(); bool askClearConfig = (mods & Qt::ControlModifier) && (mods & Qt::ShiftModifier) && (mods & Qt::AltModifier); if (askClearConfig) { bool ok = QMessageBox::question(0, i18nc("@title:window", "Krita"), i18n("Do you want to clear the settings file?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes; if (ok) { clearConfig(); } } } diff --git a/libs/ui/KisAutoSaveRecoveryDialog.cpp b/libs/ui/KisAutoSaveRecoveryDialog.cpp index bf7d62fa0e..9b95edd7b2 100644 --- a/libs/ui/KisAutoSaveRecoveryDialog.cpp +++ b/libs/ui/KisAutoSaveRecoveryDialog.cpp @@ -1,271 +1,271 @@ /* This file is part of the KDE project 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 "KisAutoSaveRecoveryDialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct FileItem { FileItem() : checked(true) {} QImage thumbnail; QString name; QString date; bool checked; }; class FileItemDelegate : public KWidgetItemDelegate { public: FileItemDelegate(QAbstractItemView *itemView, KisAutoSaveRecoveryDialog *dlg) : KWidgetItemDelegate(itemView, dlg) , m_parent(dlg) { } QList createItemWidgets(const QModelIndex& /*index*/) const { // a lump of coal and a piece of elastic will get you through the world QModelIndex idx = property("goya:creatingWidgetForIndex").value(); QWidget *page = new QWidget; QHBoxLayout *layout = new QHBoxLayout(page); QCheckBox *checkBox = new QCheckBox; checkBox->setProperty("fileitem", idx.data()); connect(checkBox, SIGNAL(toggled(bool)), m_parent, SLOT(toggleFileItem(bool))); QLabel *thumbnail = new QLabel; QLabel *filename = new QLabel; QLabel *dateModified = new QLabel; layout->addWidget(checkBox); layout->addWidget(thumbnail); layout->addWidget(filename); layout->addWidget(dateModified); page->setFixedSize(600, 200); return QList() << page; } void updateItemWidgets(const QList widgets, const QStyleOptionViewItem &option, const QPersistentModelIndex &index) const { FileItem *fileItem = (FileItem*)index.data().value(); QWidget* page= widgets[0]; QHBoxLayout* layout = qobject_cast(page->layout()); QCheckBox *checkBox = qobject_cast(layout->itemAt(0)->widget()); QLabel *thumbnail = qobject_cast(layout->itemAt(1)->widget()); QLabel *filename = qobject_cast(layout->itemAt(2)->widget()); QLabel *modified = qobject_cast(layout->itemAt(3)->widget()); checkBox->setChecked(fileItem->checked); thumbnail->setPixmap(QPixmap::fromImage(fileItem->thumbnail)); filename->setText(fileItem->name); modified->setText(fileItem->date); // move the page _up_ otherwise it will draw relative to the actual postion page->setGeometry(option.rect.translated(0, -option.rect.y())); } void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &/*index*/) const { //paint background for selected or hovered item QStyleOptionViewItemV4 opt = option; itemView()->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, 0); } QSize sizeHint(const QStyleOptionViewItem&, const QModelIndex&) const { return QSize(600, 200); } KisAutoSaveRecoveryDialog *m_parent; }; class KisAutoSaveRecoveryDialog::FileItemModel : public QAbstractListModel { public: FileItemModel(QList fileItems, QObject *parent) : QAbstractListModel(parent) , m_fileItems(fileItems){} virtual ~FileItemModel() { qDeleteAll(m_fileItems); m_fileItems.clear(); } int rowCount(const QModelIndex &/*parent*/) const { return m_fileItems.size(); } Qt::ItemFlags flags(const QModelIndex& /*index*/) const { Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; return flags; } QVariant data(const QModelIndex& index, int role) const { if (index.isValid() && index.row() < m_fileItems.size()) { FileItem *item = m_fileItems.at(index.row()); switch (role) { case Qt::DisplayRole: { return QVariant::fromValue((void*)item); } case Qt::SizeHintRole: return QSize(600, 200); } } return QVariant(); } bool setData(const QModelIndex& index, const QVariant& /*value*/, int role) { if (index.isValid() && index.row() < m_fileItems.size()) { if (role == Qt::CheckStateRole) { m_fileItems.at(index.row())->checked = !m_fileItems.at(index.row())->checked; return true; } } return false; } QList m_fileItems; }; KisAutoSaveRecoveryDialog::KisAutoSaveRecoveryDialog(const QStringList &filenames, QWidget *parent) : KoDialog(parent) { setCaption(i18nc("@title:window", "Recover Files")); setButtons( KoDialog::Ok | KoDialog::Cancel | KoDialog::User1 ); setButtonText(KoDialog::User1, i18n("Discard All")); setMinimumSize(650, 500); QWidget *page = new QWidget(this); QVBoxLayout *layout = new QVBoxLayout(page); if (filenames.size() == 1) { layout->addWidget(new QLabel(i18n("The following autosave file can be recovered:"))); } else { layout->addWidget(new QLabel(i18n("The following autosave files can be recovered:"))); } m_listView = new QListView(); m_listView->setAcceptDrops(false); KWidgetItemDelegate *delegate = new FileItemDelegate(m_listView, this); m_listView->setItemDelegate(delegate); QList fileItems; Q_FOREACH (const QString &filename, filenames) { FileItem *file = new FileItem(); file->name = filename; #ifdef Q_OS_WIN QString path = QDir::tempPath() + "/" + filename; #else QString path = QDir::homePath() + "/" + filename; #endif // get thumbnail -- all calligra apps save a thumbnail KoStore* store = KoStore::createStore(path, KoStore::Read); if (store && (store->open(QString("Thumbnails/thumbnail.png")) || store->open(QString("preview.png")))) { // Hooray! No long delay for the user... QByteArray bytes = store->read(store->size()); store->close(); delete store; QImage img; img.loadFromData(bytes); file->thumbnail = img.scaled(QSize(200,200), Qt::KeepAspectRatio, Qt::SmoothTransformation); } // get the date QDateTime date = QFileInfo(path).lastModified(); file->date = "(" + date.toString(Qt::LocalDate) + ")"; fileItems.append(file); } m_model = new FileItemModel(fileItems, m_listView); m_listView->setModel(m_model); layout->addWidget(m_listView); layout->addWidget(new QLabel(i18n("If you select Cancel, all recoverable files will be kept.\nIf you press OK, selected files will be recovered, the unselected files discarded."))); setMainWidget(page); - setAttribute(Qt::WA_DeleteOnClose, true); + setAttribute(Qt::WA_DeleteOnClose, false); connect( this, SIGNAL( user1Clicked() ), this, SLOT( slotDeleteAll() ) ); } void KisAutoSaveRecoveryDialog::slotDeleteAll() { foreach(FileItem* fileItem, m_model->m_fileItems) { fileItem->checked = false; } accept(); } QStringList KisAutoSaveRecoveryDialog::recoverableFiles() { QStringList files; Q_FOREACH (FileItem* fileItem, m_model->m_fileItems) { if (fileItem->checked) { files << fileItem->name; } } return files; } void KisAutoSaveRecoveryDialog::toggleFileItem(bool toggle) { // I've made better man from a piece of putty and matchstick! QVariant v = sender()->property("fileitem") ; if (v.isValid()) { FileItem *fileItem = (FileItem*)v.value(); fileItem->checked = toggle; } } diff --git a/libs/ui/KisMainWindow.cpp b/libs/ui/KisMainWindow.cpp index 624c55518b..26d12d5251 100644 --- a/libs/ui/KisMainWindow.cpp +++ b/libs/ui/KisMainWindow.cpp @@ -1,2353 +1,2353 @@ /* 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 #ifdef HAVE_KIO #include #endif #include #include #include #include #include #include #include #include #include #include #include "KoDockFactoryBase.h" #include "KoDockWidgetTitleBar.h" #include "KoDocumentInfoDlg.h" #include "KoDocumentInfo.h" #include "KoFileDialog.h" #include #include #include #include #include #include "KoToolDocker.h" #include #include #include #include #include "KisView.h" #include "KisDocument.h" #include "KisImportExportManager.h" #include "KisPrintJob.h" #include "KisPart.h" #include "KisApplication.h" #include "kis_action.h" #include "kis_canvas_controller.h" #include "kis_canvas2.h" #include "KisViewManager.h" #include "KisDocument.h" #include "dialogs/kis_dlg_preferences.h" #include "kis_config_notifier.h" #include "kis_canvas_resource_provider.h" #include "kis_node.h" #include "kis_image.h" #include "kis_group_layer.h" #include #include "kis_paintop_box.h" #include "kis_config.h" #include "kis_config_notifier.h" #include "dialogs/kis_about_application.h" #include "kis_mainwindow_observer.h" #include "kis_action_manager.h" #include "thememanager.h" #include "kis_resource_server_provider.h" #ifdef HAVE_OPENGL #include "kis_animation_importer.h" #include "dialogs/kis_dlg_import_image_sequence.h" #include "kis_animation_exporter.h" #endif #include "kis_icon_utils.h" #include #include #include "kis_signal_compressor_with_param.h" #include "dialogs/kis_delayed_save_dialog.h" class ToolDockerFactory : public KoDockFactoryBase { public: ToolDockerFactory() : KoDockFactoryBase() { } QString id() const { return "sharedtooldocker"; } QDockWidget* createDockWidget() { KoToolDocker* dockWidget = new KoToolDocker(); dockWidget->setTabEnabled(false); return dockWidget; } DockPosition defaultDockPosition() const { return DockRight; } }; class Q_DECL_HIDDEN KisMainWindow::Private { public: Private(KisMainWindow *parent) : q(parent) , viewManager(0) , firstTime(true) , windowSizeDirty(false) , readOnly(false) , isImporting(false) , isExporting(false) , noCleanup(false) , showDocumentInfo(0) , saveAction(0) , saveActionAs(0) , printAction(0) , printActionPreview(0) , exportPdf(0) , closeAll(0) // , reloadFile(0) , importFile(0) , exportFile(0) , undo(0) , redo(0) , newWindow(0) , close(0) , mdiCascade(0) , mdiTile(0) , mdiNextWindow(0) , mdiPreviousWindow(0) , toggleDockers(0) , toggleDockerTitleBars(0) , 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)) , helpMenu(0) , brushesAndStuff(0) , recentFiles(0) , toolOptionsDocker(0) , deferredClosingEvent(0) , themeManager(0) , mdiArea(new QMdiArea(parent)) , activeSubWindow(0) , windowMapper(new QSignalMapper(parent)) , documentMapper(new QSignalMapper(parent)) , lastExportSpecialOutputFlag(0) { } ~Private() { qDeleteAll(toolbarList); } KisMainWindow *q; KisViewManager *viewManager; QPointer activeView; QPointer progress; QMutex progressMutex; QList toolbarList; bool firstTime; bool windowSizeDirty; bool readOnly; bool isImporting; bool isExporting; bool noCleanup; KisAction *showDocumentInfo; KisAction *saveAction; KisAction *saveActionAs; KisAction *printAction; KisAction *printActionPreview; KisAction *exportPdf; #ifdef HAVE_OPENGL KisAction *importAnimation; KisAction *exportAnimation; #endif KisAction *closeAll; // KisAction *reloadFile; KisAction *importFile; KisAction *exportFile; KisAction *undo; KisAction *redo; KisAction *newWindow; KisAction *close; KisAction *mdiCascade; KisAction *mdiTile; KisAction *mdiNextWindow; KisAction *mdiPreviousWindow; KisAction *toggleDockers; KisAction *toggleDockerTitleBars; KisAction *expandingSpacers[2]; KActionMenu *dockWidgetMenu; KActionMenu *windowMenu; KActionMenu *documentMenu; KHelpMenu *helpMenu; KToolBar *brushesAndStuff; KRecentFilesAction *recentFiles; QUrl lastExportUrl; QMap dockWidgetsMap; QMap dockWidgetVisibilityMap; QByteArray dockerStateBeforeHiding; KoToolDocker *toolOptionsDocker; QCloseEvent *deferredClosingEvent; Digikam::ThemeManager *themeManager; QMdiArea *mdiArea; QMdiSubWindow *activeSubWindow; QSignalMapper *windowMapper; QSignalMapper *documentMapper; QByteArray lastExportedFormat; int lastExportSpecialOutputFlag; QScopedPointer > tabSwitchCompressor; 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() : KXmlGuiWindow() , d(new Private(this)) { KisConfig cfg; d->viewManager = new KisViewManager(this, actionCollection()); KConfigGroup group( KSharedConfig::openConfig(), "theme"); d->themeManager = new Digikam::ThemeManager(group.readEntry("Theme", "Krita dark"), this); setAcceptDrops(true); 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_MAC setUnifiedTitleAndToolBarOnMac(true); #endif connect(this, SIGNAL(restoringDone()), this, SLOT(forceDockTabFonts())); connect(this, SIGNAL(documentSaved()), d->viewManager, SLOT(slotDocumentSaved())); 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); QMetaObject::invokeMethod(this, "initializeGeometry", Qt::QueuedConnection); KoToolBoxFactory toolBoxFactory; QDockWidget *toolbox = createDockWidget(&toolBoxFactory); toolbox->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable); if (cfg.toolOptionsInDocker()) { ToolDockerFactory toolDockerFactory; d->toolOptionsDocker = qobject_cast(createDockWidget(&toolDockerFactory)); } 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(); } 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->setMainWindow(d->viewManager); } } d->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); d->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); d->mdiArea->setTabPosition(QTabWidget::North); d->mdiArea->setTabsClosable(true); setCentralWidget(d->mdiArea); 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*))); createActions(); setAutoSaveSettings("krita", false); KoPluginLoader::instance()->load("Krita/ViewPlugin", "Type == 'Service' and ([X-Krita-Version] == 28)", KoPluginLoader::PluginsConfig(), viewManager()); subWindowActivated(); updateWindowMenu(); if (isHelpMenuEnabled() && !d->helpMenu) { d->helpMenu = new KHelpMenu(this, "Dummy Text That Is Not Used In Frameworks 5", 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(); // If we have customized the toolbars, load that first setLocalXMLFile(KoResourcePaths::locateLocal("data", "krita/krita.rc")); QString doc; QStringList allFiles = KoResourcePaths::findAllResources("data", "krita/krita.rc"); KIS_ASSERT(allFiles.size() > 0); // We need at least one krita.rc file! setXMLFile(findMostRecentXMLFile(allFiles, doc)); guiFactory()->addClient(this); // Create and plug toolbar list for Settings menu QList toolbarList; Q_FOREACH (QWidget* it, guiFactory()->containers("ToolBar")) { KToolBar * toolBar = ::qobject_cast(it); 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!"; } plugActionList("toolbarlist", toolbarList); setToolbarList(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)); } } void KisMainWindow::setNoCleanup(bool noCleanup) { d->noCleanup = noCleanup; } KisMainWindow::~KisMainWindow() { // Q_FOREACH (QAction *ac, actionCollection()->actions()) { // QAction *action = qobject_cast(ac); // if (action) { // dbgKrita << "", "").replace("", "") // << "iconText=" << action->iconText().replace("&", "&") // << "shortcut=" << action->shortcut(QAction::ActiveShortcut).toString() // << "defaultShortcut=" << action->shortcut(QAction::DefaultShortcut).toString() // << "isCheckable=" << QString((action->isChecked() ? "true" : "false")) // << "statusTip=" << action->statusTip() // << "/>" ; // } // else { // dbgKrita << "Got a QAction:" << ac->objectName(); // } // } // The doc and view might still exist (this is the case when closing the window) KisPart::instance()->removeMainWindow(this); if (d->noCleanup) return; delete d->viewManager; delete d; } void KisMainWindow::addView(KisView *view) { if (d->activeView == view) return; if (d->activeView) { d->activeView->disconnect(this); } showView(view); updateCaption(); emit restoringDone(); if (d->activeView) { connect(d->activeView, SIGNAL(titleModified(QString,bool)), SLOT(slotDocumentTitleModified(QString,bool))); } } void KisMainWindow::showView(KisView *imageView) { 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(); QMdiSubWindow *subwin = d->mdiArea->addSubWindow(imageView); subwin->setAttribute(Qt::WA_DeleteOnClose, true); connect(subwin, SIGNAL(destroyed()), SLOT(updateWindowMenu())); KisConfig cfg; subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setWindowIcon(qApp->windowIcon()); if (d->mdiArea->subWindowList().size() == 1) { imageView->showMaximized(); } else { imageView->show(); } setActiveView(imageView); updateWindowMenu(); updateCaption(); } } void KisMainWindow::slotPreferences() { if (KisDlgPreferences::editPreferences()) { KisConfigNotifier::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(koview); if (view) { // Update the settings for all nodes -- they don't query // KisConfig directly because they need the settings during // compositing, and they don't connect to the config notifier // because nodes are not QObjects (because only one base class // can be a QObject). KisNode* node = dynamic_cast(view->image()->rootLayer().data()); node->updateSettings(); } } d->viewManager->showHideScrollbars(); } } void KisMainWindow::slotThemeChanged() { // save theme changes instantly KConfigGroup group( KSharedConfig::openConfig(), "theme"); group.writeEntry("Theme", d->themeManager->currentThemeName()); // reload action icons! Q_FOREACH (QAction *action, actionCollection()->actions()) { KisIconUtils::updateIcon(action); } emit themeChanged(); } void KisMainWindow::updateReloadFileAction(KisDocument *doc) { Q_UNUSED(doc); // d->reloadFile->setEnabled(doc && !doc->url().isEmpty()); } void KisMainWindow::setReadWrite(bool readwrite) { d->saveAction->setEnabled(readwrite); d->importFile->setEnabled(readwrite); d->readOnly = !readwrite; updateCaption(); } void KisMainWindow::addRecentURL(const QUrl &url) { dbgUI << "KisMainWindow::addRecentURL url=" << url.toDisplayString(); // Add entry to recent documents list // (call coming from KisDocument because it must work with cmd line, template dlg, file/open, etc.) if (!url.isEmpty()) { bool ok = true; if (url.isLocalFile()) { QString path = url.adjusted(QUrl::StripTrailingSlash).toLocalFile(); const QStringList tmpDirs = KoResourcePaths::resourceDirs("tmp"); for (QStringList::ConstIterator it = tmpDirs.begin() ; ok && it != tmpDirs.end() ; ++it) if (path.contains(*it)) ok = false; // it's in the tmp resource #ifdef HAVE_KIO if (ok) { KRecentDocument::add(path); } #endif } #ifdef HAVE_KIO else { KRecentDocument::add(url.url(QUrl::StripTrailingSlash), true); } #endif if (ok) { d->recentFiles->addUrl(url); } saveRecentFiles(); } } void KisMainWindow::saveRecentFiles() { // Save list of recent files KSharedConfigPtr config = KSharedConfig::openConfig(); d->recentFiles->saveEntries(config->group("RecentFiles")); config->sync(); // Tell all windows to reload their list, after saving // Doesn't work multi-process, but it's a start Q_FOREACH (KMainWindow* window, KMainWindow::memberList()) static_cast(window)->reloadRecentFileList(); } void KisMainWindow::reloadRecentFileList() { d->recentFiles->loadEntries( KSharedConfig::openConfig()->group("RecentFiles")); } void KisMainWindow::updateCaption() { if (!d->mdiArea->activeSubWindow()) { updateCaption(QString(), false); } else { QString caption( d->activeView->document()->caption() ); if (d->readOnly) { caption += ' ' + i18n("(write protected)"); } d->activeView->setWindowTitle(caption); updateCaption(caption, d->activeView->document()->isModified()); if (!d->activeView->document()->url().fileName().isEmpty()) d->saveAction->setToolTip(i18n("Save as %1", d->activeView->document()->url().fileName())); else d->saveAction->setToolTip(i18n("Save")); } } void KisMainWindow::updateCaption(const QString & caption, bool mod) { dbgUI << "KisMainWindow::updateCaption(" << caption << "," << mod << ")"; #ifdef CALLIGRA_ALPHA setCaption(QString("ALPHA %1: %2").arg(CALLIGRA_ALPHA).arg(caption), mod); return; #endif #ifdef CALLIGRA_BETA setCaption(QString("BETA %1: %2").arg(CALLIGRA_BETA).arg(caption), mod); return; #endif #ifdef CALLIGRA_RC setCaption(QString("RELEASE CANDIDATE %1: %2").arg(CALLIGRA_RC).arg(caption), mod); return; #endif setCaption(caption, mod); } KisView *KisMainWindow::activeView() const { if (d->activeView) { return d->activeView; } return 0; } bool KisMainWindow::openDocument(const QUrl &url) { if (!QFile(url.toLocalFile()).exists()) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("The file %1 does not exist.", url.url())); d->recentFiles->removeUrl(url); //remove the file from the recent-opened-file-list saveRecentFiles(); return false; } return openDocumentInternal(url); } bool KisMainWindow::openDocumentInternal(const QUrl &url, KisDocument *newdoc) { if (!url.isLocalFile()) { qDebug() << "KisMainWindow::openDocumentInternal. Not a local file:" << url; return false; } if (!newdoc) { newdoc = KisPart::instance()->createDocument(); } d->firstTime = true; connect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); connect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); connect(newdoc, SIGNAL(canceled(const QString &)), this, SLOT(slotLoadCanceled(const QString &))); bool openRet = (!isImporting()) ? newdoc->openUrl(url) : newdoc->importDocument(url); if (!openRet) { delete newdoc; return false; } KisPart::instance()->addDocument(newdoc); updateReloadFileAction(newdoc); if (!QFileInfo(url.toLocalFile()).isWritable()) { setReadWrite(false); } return true; } void KisMainWindow::addViewAndNotifyLoadingCompleted(KisDocument *document) { KisView *view = KisPart::instance()->createView(document, resourceManager(), actionCollection(), this); addView(view); emit guiLoadingFinished(); } QStringList KisMainWindow::showOpenFileDialog() { KoFileDialog dialog(this, KoFileDialog::ImportFiles, "OpenDocument"); dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); dialog.setMimeTypeFilters(KisImportExportManager::mimeFilter(KIS_MIME_TYPE, KisImportExportManager::Import, KisDocumentEntry::extraNativeMimeTypes())); QStringList filters = dialog.nameFilters(); filters << i18n("All files (*.*)"); dialog.setNameFilters(filters); dialog.setHideNameFilterDetailsOption(); dialog.setCaption(isImporting() ? i18n("Import Images") : i18n("Open Images")); return dialog.filenames(); } // Separate from openDocument to handle async loading (remote URLs) void KisMainWindow::slotLoadCompleted() { KisDocument *newdoc = qobject_cast(sender()); addViewAndNotifyLoadingCompleted(newdoc); disconnect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); disconnect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); disconnect(newdoc, SIGNAL(canceled(const QString &)), this, SLOT(slotLoadCanceled(const QString &))); emit loadCompleted(); } void KisMainWindow::slotLoadCanceled(const QString & errMsg) { dbgUI << "KisMainWindow::slotLoadCanceled"; if (!errMsg.isEmpty()) // empty when canceled by user QMessageBox::critical(this, i18nc("@title:window", "Krita"), errMsg); // ... can't delete the document, it's the one who emitted the signal... KisDocument* doc = qobject_cast(sender()); Q_ASSERT(doc); disconnect(doc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); disconnect(doc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); disconnect(doc, SIGNAL(canceled(const QString &)), this, SLOT(slotLoadCanceled(const QString &))); } void KisMainWindow::slotSaveCanceled(const QString &errMsg) { dbgUI << "KisMainWindow::slotSaveCanceled"; if (!errMsg.isEmpty()) // empty when canceled by user QMessageBox::critical(this, i18nc("@title:window", "Krita"), errMsg); slotSaveCompleted(); } void KisMainWindow::slotSaveCompleted() { dbgUI << "KisMainWindow::slotSaveCompleted"; KisDocument* doc = qobject_cast(sender()); Q_ASSERT(doc); disconnect(doc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); disconnect(doc, SIGNAL(completed()), this, SLOT(slotSaveCompleted())); disconnect(doc, SIGNAL(canceled(const QString &)), this, SLOT(slotSaveCanceled(const QString &))); if (d->deferredClosingEvent) { KXmlGuiWindow::closeEvent(d->deferredClosingEvent); } } bool KisMainWindow::saveDocument(KisDocument *document, bool saveas, bool silent, int specialOutputFlag) { if (!document) { return true; } KisDelayedSaveDialog dlg(document->image(), this); dlg.blockIfImageIsBusy(); bool reset_url; if (document->url().isEmpty()) { reset_url = true; saveas = true; } else { reset_url = false; } connect(document, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); connect(document, SIGNAL(completed()), this, SLOT(slotSaveCompleted())); connect(document, SIGNAL(canceled(const QString &)), this, SLOT(slotSaveCanceled(const QString &))); QUrl oldURL = document->url(); QString oldFile = document->localFilePath(); QByteArray _native_format = document->nativeFormatMimeType(); QByteArray oldOutputFormat = document->outputMimeType(); int oldSpecialOutputFlag = document->specialOutputFlag(); QUrl suggestedURL = document->url(); QStringList mimeFilter; QMimeDatabase db; QMimeType mime = db.mimeTypeForName(_native_format); if (specialOutputFlag) { mimeFilter = mime.globPatterns(); } else { mimeFilter = KisImportExportManager::mimeFilter(_native_format, KisImportExportManager::Export, document->extraNativeMimeTypes()); } if (!mimeFilter.contains(oldOutputFormat) && !isExporting()) { dbgUI << "KisMainWindow::saveDocument no export filter for" << oldOutputFormat; // --- don't setOutputMimeType in case the user cancels the Save As // dialog and then tries to just plain Save --- // suggest a different filename extension (yes, we fortunately don't all live in a world of magic :)) QString suggestedFilename = suggestedURL.fileName(); if (!suggestedFilename.isEmpty()) { // ".kra" looks strange for a name int c = suggestedFilename.lastIndexOf('.'); const QString ext = mime.preferredSuffix(); if (!ext.isEmpty()) { if (c < 0) suggestedFilename += ext; else suggestedFilename = suggestedFilename.left(c) + ext; } else { // current filename extension wrong anyway if (c > 0) { // this assumes that a . signifies an extension, not just a . suggestedFilename = suggestedFilename.left(c); } } suggestedURL = suggestedURL.adjusted(QUrl::RemoveFilename); suggestedURL.setPath(suggestedURL.path() + suggestedFilename); } // force the user to choose outputMimeType saveas = true; } bool ret = false; if (document->url().isEmpty() || saveas) { // if you're just File/Save As'ing to change filter options you // don't want to be reminded about overwriting files etc. bool justChangingFilterOptions = false; KoFileDialog dialog(this, KoFileDialog::SaveFile, "SaveDocument"); dialog.setCaption(i18n("untitled")); if (isExporting() && !d->lastExportUrl.isEmpty()) { dialog.setDefaultDir(d->lastExportUrl.toLocalFile(), true); } else { dialog.setDefaultDir(suggestedURL.toLocalFile(), true); } dialog.setMimeTypeFilters(mimeFilter, KIS_MIME_TYPE); QUrl newURL = QUrl::fromUserInput(dialog.filename()); if (newURL.isLocalFile()) { QString fn = newURL.toLocalFile(); if (QFileInfo(fn).completeSuffix().isEmpty()) { QMimeDatabase db; QMimeType mime = db.mimeTypeForName(_native_format); fn.append(mime.preferredSuffix()); newURL = QUrl::fromLocalFile(fn); } } if (document->documentInfo()->aboutInfo("title") == i18n("Unnamed")) { QString fn = newURL.toLocalFile(); QFileInfo info(fn); document->documentInfo()->setAboutInfo("title", info.baseName()); } QByteArray outputFormat = _native_format; if (!specialOutputFlag) { QMimeType mime = db.mimeTypeForUrl(newURL); QString outputFormatString = mime.name(); outputFormat = outputFormatString.toLatin1(); } if (!isExporting()) justChangingFilterOptions = (newURL == document->url()) && (outputFormat == document->mimeType()) && (specialOutputFlag == oldSpecialOutputFlag); else justChangingFilterOptions = (newURL == d->lastExportUrl) && (outputFormat == d->lastExportedFormat) && (specialOutputFlag == d->lastExportSpecialOutputFlag); bool bOk = true; if (newURL.isEmpty()) { bOk = false; } // adjust URL before doing checks on whether the file exists. if (specialOutputFlag) { QString fileName = newURL.fileName(); if ( specialOutputFlag== KisDocument::SaveAsDirectoryStore) { //dbgKrita << "save to directory: " << newURL.url(); } else if (specialOutputFlag == KisDocument::SaveEncrypted) { int dot = fileName.lastIndexOf('.'); dbgKrita << dot; QString ext = mime.preferredSuffix(); if (!ext.isEmpty()) { if (dot < 0) fileName += ext; else fileName = fileName.left(dot) + ext; } else { // current filename extension wrong anyway if (dot > 0) fileName = fileName.left(dot); } newURL = newURL.adjusted(QUrl::RemoveFilename); newURL.setPath(newURL.path() + fileName); } } if (bOk) { bool wantToSave = true; // don't change this line unless you know what you're doing :) if (!justChangingFilterOptions || document->confirmNonNativeSave(isExporting())) { if (!document->isNativeFormat(outputFormat)) wantToSave = true; } if (wantToSave) { // // Note: // If the user is stupid enough to Export to the current URL, // we do _not_ change this operation into a Save As. Reasons // follow: // // 1. A check like "isExporting() && oldURL == newURL" // doesn't _always_ work on case-insensitive filesystems // and inconsistent behaviour is bad. // 2. It is probably not a good idea to change document->mimeType // and friends because the next time the user File/Save's, // (not Save As) they won't be expecting that they are // using their File/Export settings // // As a bad side-effect of this, the modified flag will not // be updated and it is possible that what is currently on // their screen is not what is stored on disk (through loss // of formatting). But if you are dumb enough to change // mimetype but not the filename, then arguably, _you_ are // the "bug" :) // // - Clarence // document->setOutputMimeType(outputFormat, specialOutputFlag); if (!isExporting()) { // Save As ret = document->saveAs(newURL); if (ret) { dbgUI << "Successful Save As!"; addRecentURL(newURL); setReadWrite(true); } else { dbgUI << "Failed Save As!"; document->setUrl(oldURL); document->setLocalFilePath(oldFile); document->setOutputMimeType(oldOutputFormat, oldSpecialOutputFlag); } } else { // Export ret = document->exportDocument(newURL); if (ret) { // a few file dialog convenience things d->lastExportUrl = newURL; d->lastExportedFormat = outputFormat; d->lastExportSpecialOutputFlag = specialOutputFlag; } // always restore output format document->setOutputMimeType(oldOutputFormat, oldSpecialOutputFlag); } if (silent) // don't let the document change the window caption document->setTitleModified(); } // if (wantToSave) { else ret = false; } // if (bOk) { else ret = false; } else { // saving bool needConfirm = document->confirmNonNativeSave(false) && !document->isNativeFormat(oldOutputFormat); if (!needConfirm || (needConfirm && exportConfirmation(oldOutputFormat /* not so old :) */)) ) { // be sure document has the correct outputMimeType! if (isExporting() || document->isModified()) { ret = document->save(); } if (!ret) { dbgUI << "Failed Save!"; document->setUrl(oldURL); document->setLocalFilePath(oldFile); } } else ret = false; } if (!ret && reset_url) document->resetURL(); //clean the suggested filename as the save dialog was rejected updateReloadFileAction(document); updateCaption(); return ret; } bool KisMainWindow::exportConfirmation(const QByteArray &/*outputFormat*/) { return true; } void KisMainWindow::undo() { if (activeView()) { activeView()->undoAction()->trigger(); d->undo->setText(activeView()->undoAction()->text()); } } void KisMainWindow::redo() { if (activeView()) { activeView()->redoAction()->trigger(); d->redo->setText(activeView()->redoAction()->text()); } } void KisMainWindow::closeEvent(QCloseEvent *e) { d->mdiArea->closeAllSubWindows(); KConfigGroup cfg( KSharedConfig::openConfig(), "MainWindow"); cfg.writeEntry("ko_geometry", saveGeometry().toBase64()); cfg.writeEntry("ko_windowstate", saveState().toBase64()); { KConfigGroup group( KSharedConfig::openConfig(), "theme"); group.writeEntry("Theme", d->themeManager->currentThemeName()); } if(d->activeView && d->activeView->document() && d->activeView->document()->isLoading()) { e->setAccepted(false); return; } QList childrenList = d->mdiArea->subWindowList(); if (childrenList.isEmpty()) { d->deferredClosingEvent = e; if (!d->dockerStateBeforeHiding.isEmpty()) { restoreState(d->dockerStateBeforeHiding); } statusBar()->setVisible(true); menuBar()->setVisible(true); saveWindowSettings(); if (d->noCleanup) return; Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) { KisView *view = dynamic_cast(subwin); if (view) { KisPart::instance()->removeView(view); } } if (!d->dockWidgetVisibilityMap.isEmpty()) { // re-enable dockers for persistency Q_FOREACH (QDockWidget* dockWidget, d->dockWidgetsMap) dockWidget->setVisible(d->dockWidgetVisibilityMap.value(dockWidget)); } } else { e->setAccepted(false); } } void KisMainWindow::saveWindowSettings() { KSharedConfigPtr config = KSharedConfig::openConfig(); if (d->windowSizeDirty ) { dbgUI << "KisMainWindow::saveWindowSettings"; KConfigGroup group = config->group("MainWindow"); KWindowConfig::saveWindowSize(windowHandle(), group); config->sync(); d->windowSizeDirty = false; } if (!d->activeView || d->activeView->document()) { // Save toolbar position into the config file of the app, under the doc's component name KConfigGroup group = KSharedConfig::openConfig()->group("krita"); saveMainWindowSettings(group); // Save collapsable state of dock widgets for (QMap::const_iterator i = d->dockWidgetsMap.constBegin(); i != d->dockWidgetsMap.constEnd(); ++i) { if (i.value()->widget()) { KConfigGroup dockGroup = group.group(QString("DockWidget ") + i.key()); dockGroup.writeEntry("Collapsed", i.value()->widget()->isHidden()); dockGroup.writeEntry("Locked", i.value()->property("Locked").toBool()); dockGroup.writeEntry("DockArea", (int) dockWidgetArea(i.value())); } } } KSharedConfig::openConfig()->sync(); resetAutoSaveSettings(); // Don't let KMainWindow override the good stuff we wrote down } void KisMainWindow::resizeEvent(QResizeEvent * e) { d->windowSizeDirty = true; KXmlGuiWindow::resizeEvent(e); } void KisMainWindow::setActiveView(KisView* view) { d->activeView = view; updateCaption(); actionCollection()->action("edit_undo")->setText(activeView()->undoAction()->text()); actionCollection()->action("edit_redo")->setText(activeView()->redoAction()->text()); d->viewManager->setCurrentView(view); } void KisMainWindow::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasUrls() || event->mimeData()->hasFormat("application/x-krita-node") || event->mimeData()->hasFormat("application/x-qt-image")) { event->accept(); } } void KisMainWindow::dropEvent(QDropEvent *event) { if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() > 0) { Q_FOREACH (const QUrl &url, event->mimeData()->urls()) { openDocument(url); } } } void KisMainWindow::dragMoveEvent(QDragMoveEvent * event) { QTabBar *tabBar = d->findTabBarHACK(); if (!tabBar && d->mdiArea->viewMode() == QMdiArea::TabbedView) { qWarning() << "WARNING!!! Cannot find QTabBar in the main window! Looks like Qt has changed behavior. Drag & Drop between multiple tabs might not work properly (tabs will not switch automatically)!"; } if (tabBar && tabBar->isVisible()) { QPoint pos = tabBar->mapFromGlobal(mapToGlobal(event->pos())); if (tabBar->rect().contains(pos)) { const int tabIndex = tabBar->tabAt(pos); if (tabIndex >= 0 && tabBar->currentIndex() != tabIndex) { d->tabSwitchCompressor->start(tabIndex); } } else if (d->tabSwitchCompressor->isActive()) { d->tabSwitchCompressor->stop(); } } } void KisMainWindow::dragLeaveEvent(QDragLeaveEvent * /*event*/) { if (d->tabSwitchCompressor->isActive()) { d->tabSwitchCompressor->stop(); } } void KisMainWindow::switchTab(int index) { QTabBar *tabBar = d->findTabBarHACK(); if (!tabBar) return; tabBar->setCurrentIndex(index); } void KisMainWindow::slotFileNew() { KisPart::instance()->showStartUpWidget(this, true /*Always show widget*/); } void KisMainWindow::slotFileOpen() { QStringList urls = showOpenFileDialog(); if (urls.isEmpty()) return; Q_FOREACH (const QString& url, urls) { if (!url.isEmpty()) { bool res = openDocument(QUrl::fromLocalFile(url)); if (!res) { warnKrita << "Loading" << url << "failed"; } } } } void KisMainWindow::slotFileOpenRecent(const QUrl &url) { (void) openDocument(QUrl(url)); } void KisMainWindow::slotFileSave() { if (saveDocument(d->activeView->document())) emit documentSaved(); } void KisMainWindow::slotFileSaveAs() { if (saveDocument(d->activeView->document(), true)) emit documentSaved(); } KoCanvasResourceManager *KisMainWindow::resourceManager() const { return d->viewManager->resourceProvider()->resourceManager(); } int KisMainWindow::viewCount() const { return d->mdiArea->subWindowList().size(); } bool KisMainWindow::restoreWorkspace(const QByteArray &state) { QByteArray oldState = saveState(); const bool showTitlebars = KisConfig().showDockerTitleBars(); // needed because otherwise the layout isn't correctly restored in some situations Q_FOREACH (QDockWidget *dock, dockWidgets()) { dock->hide(); dock->titleBarWidget()->setVisible(showTitlebars); } bool success = KXmlGuiWindow::restoreState(state); if (!success) { KXmlGuiWindow::restoreState(oldState); Q_FOREACH (QDockWidget *dock, dockWidgets()) { if (dock->titleBarWidget()) { dock->titleBarWidget()->setVisible(showTitlebars || dock->isFloating()); } } return false; } Q_FOREACH (QDockWidget *dock, dockWidgets()) { if (dock->titleBarWidget()) { const bool isCollapsed = (dock->widget() && dock->widget()->isHidden()) || !dock->widget(); dock->titleBarWidget()->setVisible(showTitlebars || (dock->isFloating() && isCollapsed)); } } return success; } KisViewManager *KisMainWindow::viewManager() const { return d->viewManager; } void KisMainWindow::slotDocumentInfo() { if (!d->activeView->document()) return; KoDocumentInfo *docInfo = d->activeView->document()->documentInfo(); if (!docInfo) return; KoDocumentInfoDlg *dlg = d->activeView->document()->createDocumentInfoDialog(this, docInfo); if (dlg->exec()) { if (dlg->isDocumentSaved()) { d->activeView->document()->setModified(false); } else { d->activeView->document()->setModified(true); } d->activeView->document()->setTitleModified(); } delete dlg; } bool KisMainWindow::slotFileCloseAll() { Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) { if (subwin) { if(!subwin->close()) return false; } } updateCaption(); return true; } void KisMainWindow::slotFileQuit() { if(!slotFileCloseAll()) return; close(); Q_FOREACH (QPointer mainWin, KisPart::instance()->mainWindows()) { if (mainWin != this) { if(!mainWin->slotFileCloseAll()) return; mainWin->close(); } } } void KisMainWindow::slotFilePrint() { if (!activeView()) return; KisPrintJob *printJob = activeView()->createPrintJob(); if (printJob == 0) return; applyDefaultSettings(printJob->printer()); QPrintDialog *printDialog = activeView()->createPrintDialog( printJob, this ); if (printDialog && printDialog->exec() == QDialog::Accepted) { printJob->printer().setPageMargins(0.0, 0.0, 0.0, 0.0, QPrinter::Point); printJob->printer().setPaperSize(QSizeF(activeView()->image()->width() / (72.0 * activeView()->image()->xRes()), activeView()->image()->height()/ (72.0 * activeView()->image()->yRes())), QPrinter::Inch); printJob->startPrinting(KisPrintJob::DeleteWhenDone); } else { delete printJob; } delete printDialog; } void KisMainWindow::slotFilePrintPreview() { if (!activeView()) return; KisPrintJob *printJob = activeView()->createPrintJob(); if (printJob == 0) return; /* Sets the startPrinting() slot to be blocking. The Qt print-preview dialog requires the printing to be completely blocking and only return when the full document has been printed. By default the KisPrintingDialog is non-blocking and multithreading, setting blocking to true will allow it to be used in the preview dialog */ printJob->setProperty("blocking", true); QPrintPreviewDialog *preview = new QPrintPreviewDialog(&printJob->printer(), this); printJob->setParent(preview); // will take care of deleting the job connect(preview, SIGNAL(paintRequested(QPrinter*)), printJob, SLOT(startPrinting())); preview->exec(); delete preview; } KisPrintJob* KisMainWindow::exportToPdf(const QString &pdfFileName) { if (!activeView()) return 0; KoPageLayout pageLayout; pageLayout = activeView()->pageLayout(); return exportToPdf(pageLayout, pdfFileName); } KisPrintJob* KisMainWindow::exportToPdf(KoPageLayout pageLayout, QString pdfFileName) { if (!activeView()) return 0; if (!activeView()->document()) return 0; if (pdfFileName.isEmpty()) { KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); QString defaultDir = group.readEntry("SavePdfDialog"); if (defaultDir.isEmpty()) defaultDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); QUrl startUrl = QUrl::fromLocalFile(defaultDir); KisDocument* pDoc = d->activeView->document(); /** if document has a file name, take file name and replace extension with .pdf */ if (pDoc && pDoc->url().isValid()) { startUrl = pDoc->url(); QString fileName = startUrl.fileName(); fileName = fileName.replace( QRegExp( "\\.\\w{2,5}$", Qt::CaseInsensitive ), ".pdf" ); startUrl = startUrl.adjusted(QUrl::RemoveFilename); startUrl.setPath(startUrl.path() + fileName ); } QPointer layoutDlg(new KoPageLayoutDialog(this, pageLayout)); layoutDlg->setWindowModality(Qt::WindowModal); if (layoutDlg->exec() != QDialog::Accepted || !layoutDlg) { delete layoutDlg; return 0; } pageLayout = layoutDlg->pageLayout(); delete layoutDlg; KoFileDialog dialog(this, KoFileDialog::SaveFile, "SaveDocument"); dialog.setCaption(i18n("Export as PDF")); dialog.setDefaultDir(startUrl.toLocalFile()); dialog.setMimeTypeFilters(QStringList() << "application/pdf"); QUrl url = QUrl::fromUserInput(dialog.filename()); pdfFileName = url.toLocalFile(); if (pdfFileName.isEmpty()) return 0; } KisPrintJob *printJob = activeView()->createPrintJob(); if (printJob == 0) return 0; if (isHidden()) { printJob->setProperty("noprogressdialog", true); } applyDefaultSettings(printJob->printer()); // TODO for remote files we have to first save locally and then upload. printJob->printer().setOutputFileName(pdfFileName); printJob->printer().setDocName(pdfFileName); printJob->printer().setColorMode(QPrinter::Color); if (pageLayout.format == KoPageFormat::CustomSize) { printJob->printer().setPaperSize(QSizeF(pageLayout.width, pageLayout.height), QPrinter::Millimeter); } else { printJob->printer().setPaperSize(KoPageFormat::printerPageSize(pageLayout.format)); } printJob->printer().setPageMargins(pageLayout.leftMargin, pageLayout.topMargin, pageLayout.rightMargin, pageLayout.bottomMargin, QPrinter::Millimeter); switch (pageLayout.orientation) { case KoPageFormat::Portrait: printJob->printer().setOrientation(QPrinter::Portrait); break; case KoPageFormat::Landscape: printJob->printer().setOrientation(QPrinter::Landscape); break; } //before printing check if the printer can handle printing if (!printJob->canPrint()) { QMessageBox::critical(this, i18nc("@title:window", "Krita"), i18n("Cannot export to the specified file")); } printJob->startPrinting(KisPrintJob::DeleteWhenDone); return printJob; } void KisMainWindow::importAnimation() { #ifdef HAVE_OPENGL if (!activeView()) return; KisDocument *document = activeView()->document(); if (!document) return; KisDlgImportImageSequence dlg(this, document); if (dlg.exec() == QDialog::Accepted) { QStringList files = dlg.files(); int firstFrame = dlg.firstFrame(); int step = dlg.step(); KisAnimationImporter importer(document->image()); importer.import(files, firstFrame, step); activeView()->canvasBase()->refetchDataFromImage(); } #endif } void KisMainWindow::exportAnimation() { #ifdef HAVE_OPENGL if (!activeView()) return; KisDocument *document = activeView()->document(); if (!document) return; KisAnimationExporterUI exporter(this); exporter.exportSequence(document); activeView()->canvasBase()->refetchDataFromImage(); #endif } void KisMainWindow::slotConfigureKeys() { KisPart::instance()->configureShortcuts(); emit keyBindingsChanged(); } void KisMainWindow::slotConfigureToolbars() { KConfigGroup group = KSharedConfig::openConfig()->group("krita"); saveMainWindowSettings(group); KEditToolBar edit(factory(), this); connect(&edit, SIGNAL(newToolBarConfig()), this, SLOT(slotNewToolbarConfig())); (void) edit.exec(); applyToolBarLayout(); } void KisMainWindow::slotNewToolbarConfig() { applyMainWindowSettings(KSharedConfig::openConfig()->group("krita")); KXMLGUIFactory *factory = guiFactory(); Q_UNUSED(factory); // Check if there's an active view if (!d->activeView) return; plugActionList("toolbarlist", d->toolbarList); applyToolBarLayout(); } void KisMainWindow::slotToolbarToggled(bool toggle) { //dbgUI <<"KisMainWindow::slotToolbarToggled" << sender()->name() <<" toggle=" << true; // The action (sender) and the toolbar have the same name KToolBar * bar = toolBar(sender()->objectName()); if (bar) { if (toggle) { bar->show(); } else { bar->hide(); } if (d->activeView && d->activeView->document()) { KConfigGroup group = KSharedConfig::openConfig()->group("krita"); saveMainWindowSettings(group); } } else warnUI << "slotToolbarToggled : Toolbar " << sender()->objectName() << " not found!"; } void KisMainWindow::viewFullscreen(bool fullScreen) { KisConfig cfg; cfg.setFullscreenMode(fullScreen); if (fullScreen) { setWindowState(windowState() | Qt::WindowFullScreen); // set } else { setWindowState(windowState() & ~Qt::WindowFullScreen); // reset } } void KisMainWindow::slotProgress(int value) { qApp->processEvents(); if (!d->progressMutex.tryLock()) return; dbgUI << "KisMainWindow::slotProgress" << value; if (value <= -1 || value >= 100) { if (d->progress) { statusBar()->removeWidget(d->progress); delete d->progress; d->progress = 0; } d->firstTime = true; d->progressMutex.unlock(); return; } if (d->firstTime || !d->progress) { // The statusbar might not even be created yet. // So check for that first, and create it if necessary QStatusBar *bar = findChild(); if (!bar) { statusBar()->show(); QApplication::sendPostedEvents(this, QEvent::ChildAdded); } if (d->progress) { statusBar()->removeWidget(d->progress); delete d->progress; d->progress = 0; } d->progress = new QProgressBar(statusBar()); d->progress->setMaximumHeight(statusBar()->fontMetrics().height()); d->progress->setRange(0, 100); statusBar()->addPermanentWidget(d->progress); d->progress->show(); d->firstTime = false; } if (!d->progress.isNull()) { d->progress->setValue(value); } qApp->processEvents(); d->progressMutex.unlock(); } void KisMainWindow::setMaxRecentItems(uint _number) { d->recentFiles->setMaxItems(_number); } void KisMainWindow::slotReloadFile() { KisDocument* document = d->activeView->document(); if (!document || document->url().isEmpty()) return; if (document->isModified()) { bool ok = QMessageBox::question(this, i18nc("@title:window", "Krita"), i18n("You will lose all changes made since your last save\n" "Do you want to continue?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes; if (!ok) return; } QUrl url = document->url(); saveWindowSettings(); if (!document->reload()) { QMessageBox::critical(this, i18nc("@title:window", "Krita"), i18n("Error: Could not reload this document")); } return; } void KisMainWindow::slotImportFile() { dbgUI << "slotImportFile()"; d->isImporting = true; slotFileOpen(); d->isImporting = false; } void KisMainWindow::slotExportFile() { dbgUI << "slotExportFile()"; d->isExporting = true; slotFileSaveAs(); d->isExporting = false; } bool KisMainWindow::isImporting() const { return d->isImporting; } bool KisMainWindow::isExporting() const { return d->isExporting; } QDockWidget* KisMainWindow::createDockWidget(KoDockFactoryBase* factory) { QDockWidget* dockWidget = 0; if (!d->dockWidgetsMap.contains(factory->id())) { dockWidget = factory->createDockWidget(); // It is quite possible that a dock factory cannot create the dock; don't // do anything in that case. if (!dockWidget) { warnKrita << "Could not create docker for" << factory->id(); return 0; } KoDockWidgetTitleBar *titleBar = dynamic_cast(dockWidget->titleBarWidget()); // Check if the dock widget is supposed to be collapsable if (!dockWidget->titleBarWidget()) { titleBar = new KoDockWidgetTitleBar(dockWidget); dockWidget->setTitleBarWidget(titleBar); titleBar->setCollapsable(factory->isCollapsable()); } titleBar->setFont(KoDockRegistry::dockFont()); dockWidget->setObjectName(factory->id()); dockWidget->setParent(this); if (dockWidget->widget() && dockWidget->widget()->layout()) dockWidget->widget()->layout()->setContentsMargins(1, 1, 1, 1); Qt::DockWidgetArea side = Qt::RightDockWidgetArea; bool visible = true; switch (factory->defaultDockPosition()) { case KoDockFactoryBase::DockTornOff: dockWidget->setFloating(true); // position nicely? break; case KoDockFactoryBase::DockTop: side = Qt::TopDockWidgetArea; break; case KoDockFactoryBase::DockLeft: side = Qt::LeftDockWidgetArea; break; case KoDockFactoryBase::DockBottom: side = Qt::BottomDockWidgetArea; break; case KoDockFactoryBase::DockRight: side = Qt::RightDockWidgetArea; break; case KoDockFactoryBase::DockMinimized: default: side = Qt::RightDockWidgetArea; visible = false; } KConfigGroup group = KSharedConfig::openConfig()->group("krita").group("DockWidget " + factory->id()); side = static_cast(group.readEntry("DockArea", static_cast(side))); if (side == Qt::NoDockWidgetArea) side = Qt::RightDockWidgetArea; addDockWidget(side, dockWidget); if (!visible) { dockWidget->hide(); } bool collapsed = factory->defaultCollapsed(); bool locked = false; group = KSharedConfig::openConfig()->group("krita").group("DockWidget " + factory->id()); collapsed = group.readEntry("Collapsed", collapsed); locked = group.readEntry("Locked", locked); //dbgKrita << "docker" << factory->id() << dockWidget << "collapsed" << collapsed << "locked" << locked << "titlebar" << titleBar; if (titleBar && collapsed) titleBar->setCollapsed(true); if (titleBar && locked) titleBar->setLocked(true); d->dockWidgetsMap.insert(factory->id(), dockWidget); } else { dockWidget = d->dockWidgetsMap[factory->id()]; } #ifdef Q_OS_MAC dockWidget->setAttribute(Qt::WA_MacSmallSize, true); #endif dockWidget->setFont(KoDockRegistry::dockFont()); connect(dockWidget, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(forceDockTabFonts())); return dockWidget; } void KisMainWindow::forceDockTabFonts() { Q_FOREACH (QObject *child, children()) { if (child->inherits("QTabBar")) { ((QTabBar *)child)->setFont(KoDockRegistry::dockFont()); } } } QList KisMainWindow::dockWidgets() const { return d->dockWidgetsMap.values(); } QDockWidget* KisMainWindow::dockWidget(const QString &id) { if (!d->dockWidgetsMap.contains(id)) return 0; return d->dockWidgetsMap[id]; } QList KisMainWindow::canvasObservers() const { QList observers; Q_FOREACH (QDockWidget *docker, dockWidgets()) { KoCanvasObserverBase *observer = dynamic_cast(docker); if (observer) { observers << observer; } else { warnKrita << docker << "is not a canvas observer"; } } return observers; } void KisMainWindow::toggleDockersVisibility(bool visible) { if (!visible) { d->dockerStateBeforeHiding = saveState(); Q_FOREACH (QObject* widget, children()) { if (widget->inherits("QDockWidget")) { QDockWidget* dw = static_cast(widget); if (dw->isVisible()) { dw->hide(); } } } } else { restoreState(d->dockerStateBeforeHiding); } } void KisMainWindow::setToolbarList(QList toolbarList) { qDeleteAll(d->toolbarList); d->toolbarList = toolbarList; } void KisMainWindow::slotDocumentTitleModified(const QString &caption, bool mod) { updateCaption(caption, mod); updateReloadFileAction(d->activeView ? d->activeView->document() : 0); } void KisMainWindow::subWindowActivated() { bool enabled = (activeKisView() != 0); d->mdiCascade->setEnabled(enabled); d->mdiNextWindow->setEnabled(enabled); d->mdiPreviousWindow->setEnabled(enabled); d->mdiTile->setEnabled(enabled); d->close->setEnabled(enabled); d->closeAll->setEnabled(enabled); setActiveSubWindow(d->mdiArea->activeSubWindow()); Q_FOREACH (QToolBar *tb, toolBars()) { if (tb->objectName() == "BrushesAndStuff") { tb->setEnabled(enabled); } } updateCaption(); d->actionManager()->updateGUI(); } void KisMainWindow::updateWindowMenu() { QMenu *menu = d->windowMenu->menu(); menu->clear(); menu->addAction(d->newWindow); menu->addAction(d->documentMenu); QMenu *docMenu = d->documentMenu->menu(); docMenu->clear(); Q_FOREACH (QPointer doc, KisPart::instance()->documents()) { if (doc) { QString title = doc->url().toDisplayString(); if (title.isEmpty()) title = doc->image()->objectName(); QAction *action = docMenu->addAction(title); action->setIcon(qApp->windowIcon()); connect(action, SIGNAL(triggered()), d->documentMapper, SLOT(map())); d->documentMapper->setMapping(action, doc); } } menu->addSeparator(); menu->addAction(d->close); menu->addAction(d->closeAll); if (d->mdiArea->viewMode() == QMdiArea::SubWindowView) { menu->addSeparator(); menu->addAction(d->mdiTile); menu->addAction(d->mdiCascade); } menu->addSeparator(); menu->addAction(d->mdiNextWindow); menu->addAction(d->mdiPreviousWindow); menu->addSeparator(); QList windows = d->mdiArea->subWindowList(); for (int i = 0; i < windows.size(); ++i) { QPointerchild = qobject_cast(windows.at(i)->widget()); if (child) { QString text; if (i < 9) { text = i18n("&%1 %2", i + 1, child->document()->url().toDisplayString()); } else { text = i18n("%1 %2", i + 1, child->document()->url().toDisplayString()); } QAction *action = menu->addAction(text); action->setIcon(qApp->windowIcon()); action->setCheckable(true); action->setChecked(child == activeKisView()); connect(action, SIGNAL(triggered()), d->windowMapper, SLOT(map())); d->windowMapper->setMapping(action, windows.at(i)); } } updateCaption(); } void KisMainWindow::setActiveSubWindow(QWidget *window) { if (!window) return; QMdiSubWindow *subwin = qobject_cast(window); //dbgKrita << "setActiveSubWindow();" << subwin << d->activeSubWindow; if (subwin && subwin != d->activeSubWindow) { KisView *view = qobject_cast(subwin->widget()); //dbgKrita << "\t" << view << activeView(); if (view && view != activeView()) { setActiveView(view); } d->activeSubWindow = subwin; } updateWindowMenu(); d->actionManager()->updateGUI(); } void KisMainWindow::configChanged() { KisConfig cfg; QMdiArea::ViewMode viewMode = (QMdiArea::ViewMode)cfg.readEntry("mdi_viewmode", (int)QMdiArea::TabbedView); d->mdiArea->setViewMode(viewMode); Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) { subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); } KConfigGroup group( KSharedConfig::openConfig(), "theme"); d->themeManager->setCurrentTheme(group.readEntry("Theme", "Krita dark")); d->actionManager()->updateGUI(); QBrush brush(cfg.getMDIBackgroundColor()); d->mdiArea->setBackground(brush); QString backgroundImage = cfg.getMDIBackgroundImage(); if (backgroundImage != "") { QImage image(backgroundImage); QBrush brush(image); d->mdiArea->setBackground(brush); } d->mdiArea->update(); } void KisMainWindow::newView(QObject *document) { KisDocument *doc = qobject_cast(document); KisView *view = KisPart::instance()->createView(doc, resourceManager(), actionCollection(), this); addView(view); d->actionManager()->updateGUI(); } void KisMainWindow::newWindow() { KisPart::instance()->createMainWindow()->show(); } void KisMainWindow::closeCurrentWindow() { d->mdiArea->currentSubWindow()->close(); d->actionManager()->updateGUI(); } void KisMainWindow::checkSanity() { // print error if the lcms engine is not available if (!KoColorSpaceEngineRegistry::instance()->contains("icc")) { // need to wait 1 event since exiting here would not work. m_errorMessage = i18n("The Calligra LittleCMS color management plugin is not installed. Krita will quit now."); m_dieOnError = true; QTimer::singleShot(0, this, SLOT(showErrorAndDie())); return; } KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); if (rserver->resources().isEmpty()) { m_errorMessage = i18n("Krita cannot find any brush presets! Krita will quit now."); m_dieOnError = true; QTimer::singleShot(0, this, SLOT(showErrorAndDie())); return; } } void KisMainWindow::showErrorAndDie() { QMessageBox::critical(0, i18nc("@title:window", "Installation error"), m_errorMessage); if (m_dieOnError) { exit(10); } } void KisMainWindow::showAboutApplication() { KisAboutApplication dlg(this); dlg.exec(); } QPointerKisMainWindow::activeKisView() { if (!d->mdiArea) return 0; QMdiSubWindow *activeSubWindow = d->mdiArea->activeSubWindow(); //dbgKrita << "activeKisView" << activeSubWindow; if (!activeSubWindow) return 0; return qobject_cast(activeSubWindow->widget()); } void KisMainWindow::newOptionWidgets(const QList > &optionWidgetList) { Q_FOREACH (QWidget *w, optionWidgetList) { #ifdef Q_OS_MAC w->setAttribute(Qt::WA_MacSmallSize, true); #endif w->setFont(KoDockRegistry::dockFont()); } if (d->toolOptionsDocker) { d->toolOptionsDocker->setOptionWidgets(optionWidgetList); } else { d->viewManager->paintOpBox()->newOptionWidgets(optionWidgetList); } } void KisMainWindow::applyDefaultSettings(QPrinter &printer) { if (!d->activeView) return; QString title = d->activeView->document()->documentInfo()->aboutInfo("title"); if (title.isEmpty()) { title = d->activeView->document()->url().fileName(); // strip off the native extension (I don't want foobar.kwd.ps when printing into a file) QMimeDatabase db; QMimeType mime = db.mimeTypeForName(d->activeView->document()->outputMimeType()); if (mime.isValid()) { QString extension = mime.preferredSuffix(); if (title.endsWith(extension)) title.chop(extension.length()); } } if (title.isEmpty()) { // #139905 title = i18n("%1 unsaved document (%2)", qApp->applicationDisplayName(), QLocale().toString(QDate::currentDate(), QLocale::ShortFormat)); } printer.setDocName(title); } void KisMainWindow::createActions() { KisActionManager *actionManager = d->actionManager(); actionManager->createStandardAction(KStandardAction::New, this, SLOT(slotFileNew())); actionManager->createStandardAction(KStandardAction::Open, this, SLOT(slotFileOpen())); actionManager->createStandardAction(KStandardAction::Quit, this, SLOT(slotFileQuit())); actionManager->createStandardAction(KStandardAction::KeyBindings, this, SLOT(slotConfigureKeys())); actionManager->createStandardAction(KStandardAction::ConfigureToolbars, this, SLOT(slotConfigureToolbars())); actionManager->createStandardAction(KStandardAction::FullScreen, this, SLOT(viewFullscreen(bool))); d->recentFiles = KStandardAction::openRecent(this, SLOT(slotFileOpenRecent(QUrl)), actionCollection()); connect(d->recentFiles, SIGNAL(recentListCleared()), this, SLOT(saveRecentFiles())); KSharedConfigPtr configPtr = KSharedConfig::openConfig(); d->recentFiles->loadEntries(configPtr->group("RecentFiles")); d->saveAction = actionManager->createStandardAction(KStandardAction::Save, this, SLOT(slotFileSave())); d->saveAction->setActivationFlags(KisAction::ACTIVE_IMAGE); d->saveActionAs = actionManager->createStandardAction(KStandardAction::SaveAs, this, SLOT(slotFileSaveAs())); d->saveActionAs->setActivationFlags(KisAction::ACTIVE_IMAGE); d->printAction = actionManager->createStandardAction(KStandardAction::Print, this, SLOT(slotFilePrint())); d->printAction->setActivationFlags(KisAction::ACTIVE_IMAGE); d->printActionPreview = actionManager->createStandardAction(KStandardAction::PrintPreview, this, SLOT(slotFilePrintPreview())); d->printActionPreview->setActivationFlags(KisAction::ACTIVE_IMAGE); d->undo = actionManager->createStandardAction(KStandardAction::Undo, this, SLOT(undo())); d->undo ->setActivationFlags(KisAction::ACTIVE_IMAGE); d->redo = actionManager->createStandardAction(KStandardAction::Redo, this, SLOT(redo())); d->redo->setActivationFlags(KisAction::ACTIVE_IMAGE); d->exportPdf = actionManager->createAction("file_export_pdf"); connect(d->exportPdf, SIGNAL(triggered()), this, SLOT(exportToPdf())); #ifdef HAVE_OPENGL d->importAnimation = actionManager->createAction("file_import_animation"); connect(d->importAnimation, SIGNAL(triggered()), this, SLOT(importAnimation())); d->exportAnimation = actionManager->createAction("file_export_animation"); connect(d->exportAnimation, SIGNAL(triggered()), this, SLOT(exportAnimation())); #endif d->closeAll = actionManager->createAction("file_close_all"); connect(d->closeAll, SIGNAL(triggered()), this, SLOT(slotFileCloseAll())); // d->reloadFile = actionManager->createAction("file_reload_file"); // d->reloadFile->setActivationFlags(KisAction::CURRENT_IMAGE_MODIFIED); // connect(d->reloadFile, SIGNAL(triggered(bool)), this, SLOT(slotReloadFile())); d->importFile = actionManager->createAction("file_import_file"); connect(d->importFile, SIGNAL(triggered(bool)), this, SLOT(slotImportFile())); d->exportFile = actionManager->createAction("file_export_file"); connect(d->exportFile, SIGNAL(triggered(bool)), this, SLOT(slotExportFile())); /* The following entry opens the document information dialog. Since the action is named so it intends to show data this entry should not have a trailing ellipses (...). */ d->showDocumentInfo = actionManager->createAction("file_documentinfo"); connect(d->showDocumentInfo, SIGNAL(triggered(bool)), this, SLOT(slotDocumentInfo())); d->themeManager->setThemeMenuAction(new KActionMenu(i18nc("@action:inmenu", "&Themes"), this)); d->themeManager->registerThemeActions(actionCollection()); connect(d->themeManager, SIGNAL(signalThemeChanged()), this, SLOT(slotThemeChanged())); d->toggleDockers = actionManager->createAction("view_toggledockers"); d->toggleDockers->setChecked(true); connect(d->toggleDockers, SIGNAL(toggled(bool)), SLOT(toggleDockersVisibility(bool))); d->toggleDockerTitleBars = actionManager->createAction("view_toggledockertitlebars"); { KisConfig cfg; d->toggleDockerTitleBars->setChecked(cfg.showDockerTitleBars()); } connect(d->toggleDockerTitleBars, SIGNAL(toggled(bool)), SLOT(showDockerTitleBars(bool))); actionCollection()->addAction("settings_dockers_menu", d->dockWidgetMenu); actionCollection()->addAction("window", d->windowMenu); d->mdiCascade = actionManager->createAction("windows_cascade"); connect(d->mdiCascade, SIGNAL(triggered()), d->mdiArea, SLOT(cascadeSubWindows())); d->mdiTile = actionManager->createAction("windows_tile"); connect(d->mdiTile, SIGNAL(triggered()), d->mdiArea, SLOT(tileSubWindows())); d->mdiNextWindow = actionManager->createAction("windows_next"); connect(d->mdiNextWindow, SIGNAL(triggered()), d->mdiArea, SLOT(activateNextSubWindow())); d->mdiPreviousWindow = actionManager->createAction("windows_previous"); connect(d->mdiPreviousWindow, SIGNAL(triggered()), d->mdiArea, SLOT(activatePreviousSubWindow())); d->newWindow = actionManager->createAction("view_newwindow"); connect(d->newWindow, SIGNAL(triggered(bool)), this, SLOT(newWindow())); d->close = actionManager->createAction("file_close"); connect(d->close, SIGNAL(triggered()), SLOT(closeCurrentWindow())); actionManager->createStandardAction(KStandardAction::Preferences, this, SLOT(slotPreferences())); for (int i = 0; i < 2; i++) { d->expandingSpacers[i] = new KisAction(i18n("Expanding Spacer")); d->expandingSpacers[i]->setDefaultWidget(new QWidget(this)); d->expandingSpacers[i]->defaultWidget()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); actionManager->addAction(QString("expanding_spacer_%1").arg(i), d->expandingSpacers[i]); } } void KisMainWindow::applyToolBarLayout() { const bool isPlastiqueStyle = style()->objectName() == "plastique"; Q_FOREACH (KToolBar *toolBar, toolBars()) { toolBar->layout()->setSpacing(4); if (isPlastiqueStyle) { toolBar->setContentsMargins(0, 0, 0, 2); } } } void KisMainWindow::initializeGeometry() { // if the user didn's specify the geometry on the command line (does anyone do that still?), // we first figure out some good default size and restore the x,y position. See bug 285804Z. KConfigGroup cfg( KSharedConfig::openConfig(), "MainWindow"); QByteArray geom = QByteArray::fromBase64(cfg.readEntry("ko_geometry", QByteArray())); if (!restoreGeometry(geom)) { const int scnum = QApplication::desktop()->screenNumber(parentWidget()); QRect desk = QApplication::desktop()->availableGeometry(scnum); // if the desktop is virtual then use virtual screen size if (QApplication::desktop()->isVirtualDesktop()) { desk = QApplication::desktop()->availableGeometry(QApplication::desktop()->screen(scnum)); } quint32 x = desk.x(); quint32 y = desk.y(); quint32 w = 0; quint32 h = 0; // Default size -- maximize on small screens, something useful on big screens const int deskWidth = desk.width(); if (deskWidth > 1024) { // a nice width, and slightly less than total available // height to componensate for the window decs w = (deskWidth / 3) * 2; h = (desk.height() / 3) * 2; } else { w = desk.width(); h = desk.height(); } x += (desk.width() - w) / 2; y += (desk.height() - h) / 2; move(x,y); setGeometry(geometry().x(), geometry().y(), w, h); } restoreWorkspace(QByteArray::fromBase64(cfg.readEntry("ko_windowstate", QByteArray()))); } void KisMainWindow::showManual() { - QDesktopServices::openUrl(QUrl("https://userbase.kde.org/Special:MyLanguage/Krita/Manual")); + QDesktopServices::openUrl(QUrl("https://docs.krita.org")); } void KisMainWindow::showDockerTitleBars(bool show) { Q_FOREACH (QDockWidget *dock, dockWidgets()) { if (dock->titleBarWidget()) { const bool isCollapsed = (dock->widget() && dock->widget()->isHidden()) || !dock->widget(); dock->titleBarWidget()->setVisible(show || (dock->isFloating() && isCollapsed)); } } KisConfig cfg; cfg.setShowDockerTitleBars(show); } void KisMainWindow::moveEvent(QMoveEvent *e) { if (qApp->desktop()->screenNumber(this) != qApp->desktop()->screenNumber(e->oldPos())) { KisConfigNotifier::instance()->notifyConfigChanged(); } } #include #include #include diff --git a/libs/ui/KisTemplate.cpp b/libs/ui/KisTemplate.cpp index 476a18bfd2..7cb09c5459 100644 --- a/libs/ui/KisTemplate.cpp +++ b/libs/ui/KisTemplate.cpp @@ -1,63 +1,76 @@ /* This file is part of the KDE project Copyright (C) 2000 Werner Trobin 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 "KisTemplate.h" #include #include #include #include #include #include #include KisTemplate::KisTemplate(const QString &name, const QString &description, const QString &file, const QString &picture, const QString &fileName, const QString &_measureSystem, - bool hidden, bool touched) : - m_name(name), m_descr(description), m_file(file), m_picture(picture), m_fileName(fileName), - m_hidden(hidden), m_touched(touched), m_cached(false), m_measureSystem(_measureSystem) + bool hidden, bool touched) + : m_name(name) + , m_descr(description) + , m_file(file) + , m_picture(picture) + , m_fileName(fileName) + , m_hidden(hidden) + , m_touched(touched) + , m_cached(false) + , m_measureSystem(_measureSystem) { } const QPixmap &KisTemplate::loadPicture() { if (m_cached) return m_pixmap; + m_cached = true; + if (m_picture[ 0 ] == '/') { QImage img(m_picture); if (img.isNull()) { dbgKrita << "Couldn't find icon " << m_picture; m_pixmap = QPixmap(); return m_pixmap; } const int maxHeightWidth = 128; // ### TODO: some people would surely like to have 128x128 if (img.width() > maxHeightWidth || img.height() > maxHeightWidth) { img = img.scaled(maxHeightWidth, maxHeightWidth, Qt::KeepAspectRatio, Qt::SmoothTransformation); } m_pixmap = QPixmap::fromImage(img); return m_pixmap; - } else { // relative path + } + else { // relative path QString filename = KoResourcePaths::findResource("kis_pics", m_picture + ".png"); + if (filename.isEmpty()) { + + } m_pixmap = QPixmap(filename); return m_pixmap; } } diff --git a/libs/ui/KisTemplateGroup.cpp b/libs/ui/KisTemplateGroup.cpp index 2d82bcc4eb..9cd126945c 100644 --- a/libs/ui/KisTemplateGroup.cpp +++ b/libs/ui/KisTemplateGroup.cpp @@ -1,96 +1,99 @@ /* This file is part of the KDE project Copyright (C) 2000 Werner Trobin 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 "KisTemplateGroup.h" #include #include KisTemplateGroup::KisTemplateGroup(const QString &name, const QString &dir, - int _sortingWeight, bool touched) : - m_name(name), m_touched(touched), m_sortingWeight(_sortingWeight) + int _sortingWeight, bool touched) + : m_name(name) + , m_touched(touched) + , m_sortingWeight(_sortingWeight) { m_dirs.append(dir); } KisTemplateGroup::~KisTemplateGroup() { qDeleteAll(m_templates); } bool KisTemplateGroup::isHidden() const { QList::const_iterator it = m_templates.begin(); bool hidden = true; while (it != m_templates.end() && hidden) { hidden = (*it)->isHidden(); ++it; } return hidden; } void KisTemplateGroup::setHidden(bool hidden) const { Q_FOREACH (KisTemplate* t, m_templates) t->setHidden(hidden); m_touched = true; } bool KisTemplateGroup::add(KisTemplate *t, bool force, bool touch) { KisTemplate *myTemplate = find(t->name()); if (myTemplate == 0) { m_templates.append(t); m_touched = touch; return true; - } else if (myTemplate && force) { + } + else if (myTemplate && force) { //dbgUI <<"removing :" << myTemplate->fileName(); QFile::remove(myTemplate->fileName()); QFile::remove(myTemplate->picture()); QFile::remove(myTemplate->file()); m_templates.removeAll(myTemplate); delete myTemplate; m_templates.append(t); m_touched = touch; return true; } return false; } KisTemplate *KisTemplateGroup::find(const QString &name) const { QList::const_iterator it = m_templates.begin(); KisTemplate* ret = NULL; while (it != m_templates.end()) { if ((*it)->name() == name) { ret = *it; break; } ++it; } return ret; } diff --git a/libs/ui/kis_paintop_box.cc b/libs/ui/kis_paintop_box.cc index a2f9657bdc..fc864ae6af 100644 --- a/libs/ui/kis_paintop_box.cc +++ b/libs/ui/kis_paintop_box.cc @@ -1,1168 +1,1169 @@ /* * kis_paintop_box.cc - part of KImageShop/Krayon/Krita * * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) * Copyright (c) 2009-2011 Sven Langkamp (sven.langkamp@gmail.com) * Copyright (c) 2010 Lukáš Tvrdý * Copyright (C) 2011 Silvio Heinrich * Copyright (C) 2011 Srikanth Tiyyagura * Copyright (c) 2014 Mohit Goyal * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_paintop_box.h" #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_canvas2.h" #include "kis_node_manager.h" #include "KisViewManager.h" #include "kis_canvas_resource_provider.h" #include "kis_resource_server_provider.h" #include "kis_favorite_resource_manager.h" #include "kis_config.h" #include "widgets/kis_popup_button.h" #include "widgets/kis_tool_options_popup.h" #include "widgets/kis_paintop_presets_popup.h" #include "widgets/kis_tool_options_popup.h" #include "widgets/kis_paintop_presets_chooser_popup.h" #include "widgets/kis_workspace_chooser.h" #include "widgets/kis_paintop_list_widget.h" #include "widgets/kis_slider_spin_box.h" #include "widgets/kis_cmb_composite.h" #include "widgets/kis_widget_chooser.h" #include "tool/kis_tool.h" #include "kis_signals_blocker.h" #include "kis_action_manager.h" typedef KoResourceServerSimpleConstruction > KisPaintOpPresetResourceServer; typedef KoResourceServerAdapter > KisPaintOpPresetResourceServerAdapter; KisPaintopBox::KisPaintopBox(KisViewManager *view, QWidget *parent, const char *name) : QWidget(parent) , m_resourceProvider(view->resourceProvider()) , m_optionWidget(0) , m_toolOptionsPopupButton(0) , m_brushEditorPopupButton(0) , m_presetSelectorPopupButton(0) , m_toolOptionsPopup(0) , m_viewManager(view) , m_previousNode(0) , m_currTabletToolID(KoInputDevice::invalid()) , m_presetsEnabled(true) , m_blockUpdate(false) , m_dirtyPresetsEnabled(false) , m_eraserBrushSizeEnabled(false) { Q_ASSERT(view != 0); setObjectName(name); KisConfig cfg; m_dirtyPresetsEnabled = cfg.useDirtyPresets(); m_eraserBrushSizeEnabled = cfg.useEraserBrushSize(); KAcceleratorManager::setNoAccel(this); setWindowTitle(i18n("Painter's Toolchest")); KConfigGroup grp = KSharedConfig::openConfig()->group("krita").group("Toolbar BrushesAndStuff"); int iconsize = grp.readEntry("IconSize", 32); if (!cfg.toolOptionsInDocker()) { m_toolOptionsPopupButton = new KisPopupButton(this); m_toolOptionsPopupButton->setIcon(KisIconUtils::loadIcon("configure")); m_toolOptionsPopupButton->setToolTip(i18n("Tool Settings")); m_toolOptionsPopupButton->setFixedSize(iconsize, iconsize); } m_brushEditorPopupButton = new KisPopupButton(this); m_brushEditorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_02")); m_brushEditorPopupButton->setToolTip(i18n("Edit brush settings")); m_brushEditorPopupButton->setFixedSize(iconsize, iconsize); m_presetSelectorPopupButton = new KisPopupButton(this); m_presetSelectorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_01")); m_presetSelectorPopupButton->setToolTip(i18n("Choose brush preset")); m_presetSelectorPopupButton->setFixedSize(iconsize, iconsize); m_eraseModeButton = new QToolButton(this); m_eraseModeButton->setFixedSize(iconsize, iconsize); m_eraseModeButton->setCheckable(true); m_eraseAction = m_viewManager->actionManager()->createAction("erase_action"); m_eraseModeButton->setDefaultAction(m_eraseAction); eraserBrushSize = 0; // brush size changed when using erase mode m_reloadButton = new QToolButton(this); m_reloadButton->setFixedSize(iconsize, iconsize); m_reloadButton->setCheckable(true); m_reloadAction = m_viewManager->actionManager()->createAction("reload_preset_action"); m_reloadButton->setDefaultAction(m_reloadAction); m_alphaLockButton = new QToolButton(this); m_alphaLockButton->setFixedSize(iconsize, iconsize); m_alphaLockButton->setCheckable(true); KisAction* alphaLockAction = m_viewManager->actionManager()->createAction("preserve_alpha"); m_alphaLockButton->setDefaultAction(alphaLockAction); m_hMirrorButton = new QToolButton(this); m_hMirrorButton->setFixedSize(iconsize, iconsize); m_hMirrorButton->setCheckable(true); m_hMirrorAction = m_viewManager->actionManager()->createAction("hmirror_action"); m_hMirrorButton->setDefaultAction(m_hMirrorAction); m_vMirrorButton = new QToolButton(this); m_vMirrorButton->setFixedSize(iconsize, iconsize); m_vMirrorButton->setCheckable(true); m_vMirrorAction = m_viewManager->actionManager()->createAction("vmirror_action"); m_vMirrorButton->setDefaultAction(m_vMirrorAction); const bool sliderLabels = cfg.sliderLabels(); int sliderWidth; if (sliderLabels) { sliderWidth = 150 * logicalDpiX() / 96; } else { sliderWidth = 120 * logicalDpiX() / 96; } for (int i = 0; i < 3; ++i) { m_sliderChooser[i] = new KisWidgetChooser(i + 1); KisDoubleSliderSpinBox* slOpacity; KisDoubleSliderSpinBox* slFlow; KisDoubleSliderSpinBox* slSize; if (sliderLabels) { slOpacity = m_sliderChooser[i]->addWidget("opacity"); slFlow = m_sliderChooser[i]->addWidget("flow"); slSize = m_sliderChooser[i]->addWidget("size"); slOpacity->setPrefix(QString("%1 ").arg(i18n("Opacity:"))); slFlow->setPrefix(QString("%1 ").arg(i18n("Flow:"))); slSize->setPrefix(QString("%1 ").arg(i18n("Size:"))); } else { slOpacity = m_sliderChooser[i]->addWidget("opacity", i18n("Opacity:")); slFlow = m_sliderChooser[i]->addWidget("flow", i18n("Flow:")); slSize = m_sliderChooser[i]->addWidget("size", i18n("Size:")); } slOpacity->setRange(0.0, 1.0, 2); slOpacity->setValue(1.0); slOpacity->setSingleStep(0.05); slOpacity->setMinimumWidth(qMax(sliderWidth, slOpacity->sizeHint().width())); slOpacity->setFixedHeight(iconsize); slOpacity->setBlockUpdateSignalOnDrag(true); slFlow->setRange(0.0, 1.0, 2); slFlow->setValue(1.0); slFlow->setSingleStep(0.05); slFlow->setMinimumWidth(qMax(sliderWidth, slFlow->sizeHint().width())); slFlow->setFixedHeight(iconsize); slFlow->setBlockUpdateSignalOnDrag(true); slSize->setRange(0, 1000, 2); slSize->setValue(100); slSize->setSingleStep(1); slSize->setExponentRatio(3.0); slSize->setSuffix(i18n(" px")); slSize->setMinimumWidth(qMax(sliderWidth, slSize->sizeHint().width())); slSize->setFixedHeight(iconsize); slSize->setBlockUpdateSignalOnDrag(true); m_sliderChooser[i]->chooseWidget(cfg.toolbarSlider(i + 1)); } m_cmbCompositeOp = new KisCompositeOpComboBox(); m_cmbCompositeOp->setFixedHeight(iconsize); Q_FOREACH (KisAction * a, m_cmbCompositeOp->blendmodeActions()) { m_viewManager->actionManager()->addAction(a->text(), a); } m_workspaceWidget = new KisPopupButton(this); m_workspaceWidget->setIcon(KisIconUtils::loadIcon("view-choose")); m_workspaceWidget->setToolTip(i18n("Choose workspace")); m_workspaceWidget->setFixedSize(iconsize, iconsize); m_workspaceWidget->setPopupWidget(new KisWorkspaceChooser(view)); QHBoxLayout* baseLayout = new QHBoxLayout(this); m_paintopWidget = new QWidget(this); baseLayout->addWidget(m_paintopWidget); baseLayout->setSpacing(4); baseLayout->setContentsMargins(0, 0, 0, 0); m_layout = new QHBoxLayout(m_paintopWidget); if (!cfg.toolOptionsInDocker()) { m_layout->addWidget(m_toolOptionsPopupButton); } m_layout->addWidget(m_brushEditorPopupButton); m_layout->addWidget(m_presetSelectorPopupButton); m_layout->setSpacing(4); m_layout->setContentsMargins(0, 0, 0, 0); QWidget* compositeActions = new QWidget(this); QHBoxLayout* compositeLayout = new QHBoxLayout(compositeActions); compositeLayout->addWidget(m_cmbCompositeOp); compositeLayout->addWidget(m_eraseModeButton); compositeLayout->addWidget(m_alphaLockButton); compositeLayout->setSpacing(4); compositeLayout->setContentsMargins(0, 0, 0, 0); compositeLayout->addWidget(m_reloadButton); QWidgetAction * action; action = new QWidgetAction(this); view->actionCollection()->addAction("composite_actions", action); action->setDefaultWidget(compositeActions); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("brushslider1", action); view->actionCollection()->addAction("brushslider1", action); action->setDefaultWidget(m_sliderChooser[0]); connect(action, SIGNAL(triggered()), m_sliderChooser[0], SLOT(showPopupWidget())); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[0], SLOT(updateThemedIcons())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("brushslider2", action); view->actionCollection()->addAction("brushslider2", action); action->setDefaultWidget(m_sliderChooser[1]); connect(action, SIGNAL(triggered()), m_sliderChooser[1], SLOT(showPopupWidget())); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[1], SLOT(updateThemedIcons())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("brushslider3", action); view->actionCollection()->addAction("brushslider3", action); action->setDefaultWidget(m_sliderChooser[2]); connect(action, SIGNAL(triggered()), m_sliderChooser[2], SLOT(showPopupWidget())); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[2], SLOT(updateThemedIcons())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("next_favorite_preset", action); view->actionCollection()->addAction("next_favorite_preset", action); connect(action, SIGNAL(triggered()), this, SLOT(slotNextFavoritePreset())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("previous_favorite_preset", action); view->actionCollection()->addAction("previous_favorite_preset", action); connect(action, SIGNAL(triggered()), this, SLOT(slotPreviousFavoritePreset())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("previous_preset", action); view->actionCollection()->addAction("previous_preset", action); connect(action, SIGNAL(triggered()), this, SLOT(slotSwitchToPreviousPreset())); if (!cfg.toolOptionsInDocker()) { action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("show_tool_options", action); // TODO: check how this is serialized, add it to krita.action view->actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_Backslash)); view->actionCollection()->addAction("show_tool_options", action); connect(action, SIGNAL(triggered()), m_toolOptionsPopupButton, SLOT(showPopupWidget())); } action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("show_brush_editor", action); connect(action, SIGNAL(triggered()), m_brushEditorPopupButton, SLOT(showPopupWidget())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("show_brush_presets", action); view->actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_F6)); // TODO: check this view->actionCollection()->addAction("show_brush_presets", action); connect(action, SIGNAL(triggered()), m_presetSelectorPopupButton, SLOT(showPopupWidget())); QWidget* mirrorActions = new QWidget(this); QHBoxLayout* mirrorLayout = new QHBoxLayout(mirrorActions); mirrorLayout->addWidget(m_hMirrorButton); mirrorLayout->addWidget(m_vMirrorButton); mirrorLayout->setSpacing(4); mirrorLayout->setContentsMargins(0, 0, 0, 0); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("mirror_actions", action); action->setDefaultWidget(mirrorActions); view->actionCollection()->addAction("mirror_actions", action); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("workspaces", action); view->actionCollection()->addAction("workspaces", action); action->setDefaultWidget(m_workspaceWidget); if (!cfg.toolOptionsInDocker()) { m_toolOptionsPopup = new KisToolOptionsPopup(); m_toolOptionsPopupButton->setPopupWidget(m_toolOptionsPopup); m_toolOptionsPopup->switchDetached(false); } m_presetsPopup = new KisPaintOpPresetsPopup(m_resourceProvider); m_brushEditorPopupButton->setPopupWidget(m_presetsPopup); m_presetsPopup->switchDetached(false); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_presetsPopup, SLOT(updateThemedIcons())); m_presetsChooserPopup = new KisPaintOpPresetsChooserPopup(); m_presetsChooserPopup->setFixedSize(500, 600); m_presetSelectorPopupButton->setPopupWidget(m_presetsChooserPopup); m_prevCompositeOpID = KoCompositeOpRegistry::instance().getDefaultCompositeOp().id(); m_currCompositeOpID = KoCompositeOpRegistry::instance().getDefaultCompositeOp().id(); slotNodeChanged(view->activeNode()); // Get all the paintops QList keys = KisPaintOpRegistry::instance()->keys(); QList factoryList; Q_FOREACH (const QString & paintopId, keys) { factoryList.append(KisPaintOpRegistry::instance()->get(paintopId)); } m_presetsPopup->setPaintOpList(factoryList); connect(m_presetsPopup , SIGNAL(paintopActivated(QString)) , SLOT(slotSetPaintop(QString))); connect(m_presetsPopup , SIGNAL(savePresetClicked()) , SLOT(slotSaveActivePreset())); connect(m_presetsPopup , SIGNAL(defaultPresetClicked()) , SLOT(slotSetupDefaultPreset())); connect(m_presetsPopup , SIGNAL(signalResourceSelected(KoResource*)), SLOT(resourceSelected(KoResource*))); connect(m_presetsPopup , SIGNAL(reloadPresetClicked()) , SLOT(slotReloadPreset())); connect(m_presetsPopup , SIGNAL(dirtyPresetToggled(bool)) , SLOT(slotDirtyPresetToggled(bool))); connect(m_presetsPopup , SIGNAL(eraserBrushSizeToggled(bool)) , SLOT(slotEraserBrushSizeToggled(bool))); connect(m_presetsChooserPopup, SIGNAL(resourceSelected(KoResource*)) , SLOT(resourceSelected(KoResource*))); connect(m_resourceProvider , SIGNAL(sigNodeChanged(const KisNodeSP)) , SLOT(slotNodeChanged(const KisNodeSP))); connect(m_cmbCompositeOp , SIGNAL(currentIndexChanged(int)) , SLOT(slotSetCompositeMode(int))); connect(m_eraseAction , SIGNAL(triggered(bool)) , SLOT(slotToggleEraseMode(bool))); connect(alphaLockAction , SIGNAL(triggered(bool)) , SLOT(slotToggleAlphaLockMode(bool))); connect(m_hMirrorAction , SIGNAL(triggered(bool)) , SLOT(slotHorizontalMirrorChanged(bool))); connect(m_vMirrorAction , SIGNAL(triggered(bool)) , SLOT(slotVerticalMirrorChanged(bool))); connect(m_reloadAction , SIGNAL(triggered()) , SLOT(slotReloadPreset())); connect(m_sliderChooser[0]->getWidget("opacity"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed())); connect(m_sliderChooser[0]->getWidget("flow") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed())); connect(m_sliderChooser[0]->getWidget("size") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed())); connect(m_sliderChooser[1]->getWidget("opacity"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed())); connect(m_sliderChooser[1]->getWidget("flow") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed())); connect(m_sliderChooser[1]->getWidget("size") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed())); connect(m_sliderChooser[2]->getWidget("opacity"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed())); connect(m_sliderChooser[2]->getWidget("flow") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed())); connect(m_sliderChooser[2]->getWidget("size") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed())); //Needed to connect canvas to favorite resource manager connect(m_viewManager->resourceProvider(), SIGNAL(sigOpacityChanged(qreal)), SLOT(slotOpacityChanged(qreal))); connect(m_viewManager->resourceProvider(), SIGNAL(sigFGColorChanged(KoColor)), SLOT(slotUnsetEraseMode())); m_favoriteResourceManager = new KisFavoriteResourceManager(this); connect(m_resourceProvider, SIGNAL(sigFGColorUsed(KoColor)), m_favoriteResourceManager, SLOT(slotAddRecentColor(KoColor))); connect(m_resourceProvider, SIGNAL(sigFGColorChanged(KoColor)), m_favoriteResourceManager, SLOT(slotChangeFGColorSelector(KoColor))); connect(m_resourceProvider, SIGNAL(sigBGColorChanged(KoColor)), m_favoriteResourceManager, SLOT(slotSetBGColor(KoColor))); // cold initialization m_favoriteResourceManager->slotChangeFGColorSelector(m_resourceProvider->fgColor()); m_favoriteResourceManager->slotSetBGColor(m_resourceProvider->bgColor()); connect(m_favoriteResourceManager, SIGNAL(sigSetFGColor(KoColor)), m_resourceProvider, SLOT(slotSetFGColor(KoColor))); connect(m_favoriteResourceManager, SIGNAL(sigSetBGColor(KoColor)), m_resourceProvider, SLOT(slotSetBGColor(KoColor))); connect(m_favoriteResourceManager, SIGNAL(sigEnableChangeColor(bool)), m_resourceProvider, SLOT(slotResetEnableFGChange(bool))); connect(view->mainWindow(), SIGNAL(themeChanged()), this, SLOT(slotUpdateSelectionIcon())); slotInputDeviceChanged(KoToolManager::instance()->currentInputDevice()); } KisPaintopBox::~KisPaintopBox() { KisConfig cfg; QMapIterator iter(m_tabletToolMap); while (iter.hasNext()) { iter.next(); if ((iter.key().pointer) == QTabletEvent::Eraser) { cfg.writeEntry(QString("LastEraser_%1").arg(iter.key().uniqueID) , iter.value().preset->name()); } else { cfg.writeEntry(QString("LastPreset_%1").arg(iter.key().uniqueID) , iter.value().preset->name()); } } // Do not delete the widget, since it it is global to the application, not owned by the view m_presetsPopup->setPaintOpSettingsWidget(0); qDeleteAll(m_paintopOptionWidgets); delete m_favoriteResourceManager; } void KisPaintopBox::restoreResource(KoResource* resource) { KisPaintOpPreset* preset = dynamic_cast(resource); if (preset) { setCurrentPaintop(preset->paintOp(), preset); m_presetsPopup->setPresetImage(preset->image()); m_presetsPopup->resourceSelected(resource); } } void KisPaintopBox::newOptionWidgets(const QList > &optionWidgetList) { if (m_toolOptionsPopup) { m_toolOptionsPopup->newOptionWidgets(optionWidgetList); } } void KisPaintopBox::resourceSelected(KoResource* resource) { KisPaintOpPreset* preset = dynamic_cast(resource); if (preset) { if (!preset->settings()->isLoadable()) return; setCurrentPaintopAndReload(preset->paintOp(), preset); m_presetsPopup->setPresetImage(preset->image()); m_presetsPopup->resourceSelected(resource); } } QPixmap KisPaintopBox::paintopPixmap(const KoID& paintop) { QString pixmapName = KisPaintOpRegistry::instance()->pixmap(paintop); if (pixmapName.isEmpty()) return QPixmap(); return QPixmap(KoResourcePaths::findResource("kis_images", pixmapName)); } KoID KisPaintopBox::currentPaintop() { return m_resourceProvider->currentPreset()->paintOp(); } void KisPaintopBox::setCurrentPaintopAndReload(const KoID& paintop, KisPaintOpPresetSP preset) { if (!m_dirtyPresetsEnabled) { KisSignalsBlocker blocker(m_optionWidget); if (!preset->load()) { warnKrita << "failed to load the preset."; } } setCurrentPaintop(paintop, preset); } void KisPaintopBox::setCurrentPaintop(const KoID& paintop, KisPaintOpPresetSP preset) { if (m_resourceProvider->currentPreset()) { m_resourceProvider->setPreviousPaintOpPreset(m_resourceProvider->currentPreset()); if (m_optionWidget) { m_optionWidget->disconnect(this); m_optionWidget->hide(); } m_paintOpPresetMap[m_resourceProvider->currentPreset()->paintOp()] = m_resourceProvider->currentPreset(); m_tabletToolMap[m_currTabletToolID].preset = m_resourceProvider->currentPreset(); m_tabletToolMap[m_currTabletToolID].paintOpID = m_resourceProvider->currentPreset()->paintOp(); } preset = (!preset) ? activePreset(paintop) : preset; Q_ASSERT(preset && preset->settings()); if (!m_paintopOptionWidgets.contains(paintop)) m_paintopOptionWidgets[paintop] = KisPaintOpRegistry::instance()->get(paintop.id())->createConfigWidget(this); m_optionWidget = m_paintopOptionWidgets[paintop]; preset->settings()->setOptionsWidget(m_optionWidget); m_optionWidget->setImage(m_viewManager->image()); m_optionWidget->setNode(m_viewManager->activeNode()); m_optionWidget->setConfiguration(preset->settings()); m_presetsPopup->setPaintOpSettingsWidget(m_optionWidget); Q_ASSERT(m_optionWidget && m_presetSelectorPopupButton); connect(m_optionWidget, SIGNAL(sigConfigurationUpdated()), this, SLOT(slotUpdatePreset())); connect(m_optionWidget, SIGNAL(sigSaveLockedConfig(KisPropertiesConfiguration*)), this, SLOT(slotSaveLockedOptionToPreset(KisPropertiesConfiguration*))); connect(m_optionWidget, SIGNAL(sigDropLockedConfig(KisPropertiesConfiguration*)), this, SLOT(slotDropLockedOption(KisPropertiesConfiguration*))); connect(m_optionWidget, SIGNAL(sigConfigurationItemChanged()), this, SLOT(slotConfigurationItemChanged())); + // load the current brush engine icon for the brush editor toolbar button KisPaintOpFactory* paintOp = KisPaintOpRegistry::instance()->get(paintop.id()); QString pixFilename = KoResourcePaths::findResource("kis_images", paintOp->pixmap()); m_brushEditorPopupButton->setIcon(QIcon(pixFilename)); m_resourceProvider->setPaintOpPreset(preset); m_presetsPopup->setCurrentPaintOp(paintop.id()); if (m_presetsPopup->currentPaintOp() != paintop.id()) { // Must change the paintop as the current one is not supported // by the new colorspace. dbgKrita << "current paintop " << paintop.name() << " was not set, not supported by colorspace"; } /** * We will get more update signals from the configuration widgets * but they might be delayed by some internal deferring timers, * so just call the slot directly */ slotUpdatePreset(); } KoID KisPaintopBox::defaultPaintOp() { return KoID("paintbrush"); } KisPaintOpPresetSP KisPaintopBox::defaultPreset(const KoID& paintOp) { QString defaultName = paintOp.id() + ".kpp"; QString path = KoResourcePaths::findResource("kis_defaultpresets", defaultName); KisPaintOpPresetSP preset = new KisPaintOpPreset(path); if (!preset->load()) { preset = KisPaintOpRegistry::instance()->defaultPreset(paintOp); } Q_ASSERT(preset); Q_ASSERT(preset->valid()); return preset; } KisPaintOpPresetSP KisPaintopBox::activePreset(const KoID& paintOp) { if (m_paintOpPresetMap[paintOp] == 0) { m_paintOpPresetMap[paintOp] = defaultPreset(paintOp); } return m_paintOpPresetMap[paintOp]; } void KisPaintopBox::updateCompositeOp(QString compositeOpID, bool localUpdate) { if (!m_optionWidget) return; KisSignalsBlocker blocker(m_optionWidget); KisNodeSP node = m_resourceProvider->currentNode(); if (node && node->paintDevice()) { if (!node->paintDevice()->colorSpace()->hasCompositeOp(compositeOpID)) compositeOpID = KoCompositeOpRegistry::instance().getDefaultCompositeOp().id(); m_cmbCompositeOp->blockSignals(true); m_cmbCompositeOp->selectCompositeOp(KoID(compositeOpID)); m_cmbCompositeOp->blockSignals(false); m_eraseModeButton->defaultAction()->blockSignals(true); m_eraseModeButton->blockSignals(true); m_eraseModeButton->setChecked(compositeOpID == COMPOSITE_ERASE); m_eraseModeButton->defaultAction()->setChecked(compositeOpID == COMPOSITE_ERASE); m_eraseModeButton->blockSignals(false); m_eraseModeButton->defaultAction()->blockSignals(false); if (compositeOpID != m_currCompositeOpID) { m_resourceProvider->currentPreset()->settings()->setPaintOpCompositeOp(compositeOpID); m_optionWidget->setConfiguration(m_resourceProvider->currentPreset()->settings().data()); if (!localUpdate) m_resourceProvider->setCurrentCompositeOp(compositeOpID); m_prevCompositeOpID = m_currCompositeOpID; m_currCompositeOpID = compositeOpID; } } } void KisPaintopBox::setWidgetState(int flags) { if (flags & (ENABLE_COMPOSITEOP | DISABLE_COMPOSITEOP)) { m_cmbCompositeOp->setEnabled(flags & ENABLE_COMPOSITEOP); m_eraseModeButton->setEnabled(flags & ENABLE_COMPOSITEOP); } if (flags & (ENABLE_PRESETS | DISABLE_PRESETS)) { m_presetSelectorPopupButton->setEnabled(flags & ENABLE_PRESETS); m_brushEditorPopupButton->setEnabled(flags & ENABLE_PRESETS); } for (int i = 0; i < 3; ++i) { if (flags & (ENABLE_OPACITY | DISABLE_OPACITY)) m_sliderChooser[i]->getWidget("opacity")->setEnabled(flags & ENABLE_OPACITY); if (flags & (ENABLE_FLOW | DISABLE_FLOW)) m_sliderChooser[i]->getWidget("flow")->setEnabled(flags & ENABLE_FLOW); if (flags & (ENABLE_SIZE | DISABLE_SIZE)) m_sliderChooser[i]->getWidget("size")->setEnabled(flags & ENABLE_SIZE); } } void KisPaintopBox::setSliderValue(const QString& sliderID, qreal value) { for (int i = 0; i < 3; ++i) { KisDoubleSliderSpinBox* slider = m_sliderChooser[i]->getWidget(sliderID); slider->blockSignals(true); slider->setValue(value); slider->blockSignals(false); } } void KisPaintopBox::slotSetPaintop(const QString& paintOpId) { if (KisPaintOpRegistry::instance()->get(paintOpId) != 0) { KoID id(paintOpId, KisPaintOpRegistry::instance()->get(paintOpId)->name()); setCurrentPaintop(id); } } void KisPaintopBox::slotInputDeviceChanged(const KoInputDevice& inputDevice) { TabletToolMap::iterator toolData = m_tabletToolMap.find(inputDevice); if (toolData == m_tabletToolMap.end()) { KisConfig cfg; KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer(false); KisPaintOpPresetSP preset; if (inputDevice.pointer() == QTabletEvent::Eraser) { preset = rserver->resourceByName(cfg.readEntry(QString("LastEraser_%1").arg(inputDevice.uniqueTabletId()), "Eraser_circle")); } else { preset = rserver->resourceByName(cfg.readEntry(QString("LastPreset_%1").arg(inputDevice.uniqueTabletId()), "Basic_tip_default")); } if (!preset) { preset = rserver->resourceByName("Basic_tip_default"); } if (preset) { setCurrentPaintop(preset->paintOp(), preset); } } else { setCurrentPaintop(toolData->paintOpID, toolData->preset); } m_currTabletToolID = TabletToolID(inputDevice); } void KisPaintopBox::slotCanvasResourceChanged(int /*key*/, const QVariant& /*v*/) { if (m_viewManager) { sender()->blockSignals(true); KisPaintOpPresetSP preset = m_viewManager->resourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); if (preset && m_resourceProvider->currentPreset()->name() != preset->name()) { QString compositeOp = preset->settings()->getString("CompositeOp"); updateCompositeOp(compositeOp); resourceSelected(preset.data()); } m_presetsChooserPopup->canvasResourceChanged(preset.data(), preset); if (m_resourceProvider->currentCompositeOp() != m_currCompositeOpID) { QString compositeOp = m_resourceProvider->currentCompositeOp(); m_cmbCompositeOp->blockSignals(true); m_cmbCompositeOp->selectCompositeOp(KoID(compositeOp)); m_cmbCompositeOp->blockSignals(false); m_eraseModeButton->defaultAction()->blockSignals(true); m_eraseModeButton->blockSignals(true); m_eraseModeButton->setChecked(compositeOp == COMPOSITE_ERASE); m_eraseModeButton->defaultAction()->setChecked(compositeOp == COMPOSITE_ERASE); m_eraseModeButton->blockSignals(false); m_eraseModeButton->defaultAction()->blockSignals(false); } sender()->blockSignals(false); } } void KisPaintopBox::slotSaveActivePreset() { KisPaintOpPresetSP curPreset = m_resourceProvider->currentPreset(); if (!curPreset) return; m_favoriteResourceManager->setBlockUpdates(true); KisPaintOpPresetSP newPreset = curPreset->clone(); KisPaintOpPresetResourceServer * rServer = KisResourceServerProvider::instance()->paintOpPresetServer(); QString saveLocation = rServer->saveLocation(); QString presetName = m_presetsPopup->getPresetName(); QString presetFilename = saveLocation + presetName + newPreset->defaultFileExtension(); QStringList tags; KisPaintOpPresetSP resource = rServer->resourceByName(presetName); if (resource) { tags = rServer->assignedTagsList(resource.data()); rServer->removeResourceAndBlacklist(resource); } newPreset->setImage(m_presetsPopup->cutOutOverlay()); newPreset->setFilename(presetFilename); newPreset->setName(presetName); newPreset->setPresetDirty(false); rServer->addResource(newPreset); Q_FOREACH (const QString & tag, tags) { rServer->addTag(newPreset.data(), tag); } // HACK ALERT! the server does not notify the observers // automatically, so we need to call theupdate manually! rServer->tagCategoryMembersChanged(); restoreResource(newPreset.data()); m_favoriteResourceManager->setBlockUpdates(false); } void KisPaintopBox::slotUpdatePreset() { if (!m_resourceProvider->currentPreset()) return; // block updates of avoid some over updating of the option widget m_blockUpdate = true; setSliderValue("size", m_resourceProvider->currentPreset()->settings()->paintOpSize().width()); { qreal opacity = m_resourceProvider->currentPreset()->settings()->paintOpOpacity(); m_resourceProvider->setOpacity(opacity); setSliderValue("opacity", opacity); setWidgetState(ENABLE_OPACITY); } { setSliderValue("flow", m_resourceProvider->currentPreset()->settings()->paintOpFlow()); setWidgetState(ENABLE_FLOW); } { updateCompositeOp(m_resourceProvider->currentPreset()->settings()->paintOpCompositeOp()); setWidgetState(ENABLE_COMPOSITEOP); } m_blockUpdate = false; } void KisPaintopBox::slotSetupDefaultPreset() { KisPaintOpPresetSP preset = defaultPreset(m_resourceProvider->currentPreset()->paintOp()); preset->settings()->setOptionsWidget(m_optionWidget); m_optionWidget->setConfiguration(preset->settings()); m_optionWidget->writeConfiguration(const_cast(preset->settings().data())); } void KisPaintopBox::slotNodeChanged(const KisNodeSP node) { if (m_previousNode.isValid() && m_previousNode->paintDevice()) disconnect(m_previousNode->paintDevice().data(), SIGNAL(colorSpaceChanged(const KoColorSpace*)), this, SLOT(slotColorSpaceChanged(const KoColorSpace*))); // Reconnect colorspace change of node if (node && node->paintDevice()) { connect(node->paintDevice().data(), SIGNAL(colorSpaceChanged(const KoColorSpace*)), this, SLOT(slotColorSpaceChanged(const KoColorSpace*))); m_resourceProvider->setCurrentCompositeOp(m_currCompositeOpID); m_previousNode = node; slotColorSpaceChanged(node->colorSpace()); } if (m_optionWidget) { m_optionWidget->setNode(node); } } void KisPaintopBox::slotColorSpaceChanged(const KoColorSpace* colorSpace) { m_cmbCompositeOp->validate(colorSpace); } void KisPaintopBox::slotToggleEraseMode(bool checked) { if (checked) { updateCompositeOp(COMPOSITE_ERASE); //add an option to enable eraser brush size if (m_eraserBrushSizeEnabled==true) { // remember brush size. set the eraser size to the normal brush size if not set normalBrushSize = m_sliderChooser[0]->getWidget("size")->value(); if (qFuzzyIsNull(eraserBrushSize)) eraserBrushSize = normalBrushSize; } else { normalBrushSize = eraserBrushSize; eraserBrushSize = m_sliderChooser[0]->getWidget("size")->value(); } } else { updateCompositeOp(m_prevCompositeOpID); if (m_eraserBrushSizeEnabled==true) { // save eraser brush size as eraserBrushSize (they are all the same, so just grab the first one) eraserBrushSize = m_sliderChooser[0]->getWidget("size")->value(); } else { normalBrushSize = m_sliderChooser[0]->getWidget("size")->value(); } } //update value in UI (this is the main place the value is 'stored' in memory) qreal updateSize = checked ? eraserBrushSize : normalBrushSize; m_sliderChooser[0]->getWidget("size")->setValue(updateSize); m_sliderChooser[1]->getWidget("size")->setValue(updateSize); m_sliderChooser[2]->getWidget("size")->setValue(updateSize); toggleHighlightedButton(m_eraseModeButton); } void KisPaintopBox::slotSetCompositeMode(int index) { Q_UNUSED(index); if (m_resourceProvider->currentPreset()->settings()->hasProperty("CompositeOp")) { QString compositeOp = m_cmbCompositeOp->selectedCompositeOp().id(); updateCompositeOp(compositeOp); } } void KisPaintopBox::slotHorizontalMirrorChanged(bool value) { m_resourceProvider->setMirrorHorizontal(value); toggleHighlightedButton(m_hMirrorButton); } void KisPaintopBox::slotVerticalMirrorChanged(bool value) { m_resourceProvider->setMirrorVertical(value); toggleHighlightedButton(m_vMirrorButton); } void KisPaintopBox::sliderChanged(int n) { if (!m_optionWidget) // widget will not exist if the are no documents open return; KisSignalsBlocker blocker(m_optionWidget); m_optionWidget->writeConfiguration(const_cast(m_resourceProvider->currentPreset()->settings().data())); qreal opacity = m_sliderChooser[n]->getWidget("opacity")->value(); qreal flow = m_sliderChooser[n]->getWidget("flow")->value(); qreal size = m_sliderChooser[n]->getWidget("size")->value(); setSliderValue("opacity", opacity); setSliderValue("flow" , flow); setSliderValue("size" , size); if (m_presetsEnabled) { // IMPORTANT: set the PaintOp size before setting the other properties // it wont work the other way qreal sizeDiff = size - m_resourceProvider->currentPreset()->settings()->paintOpSize().width(); m_resourceProvider->currentPreset()->settings()->changePaintOpSize(sizeDiff, 0); m_resourceProvider->currentPreset()->settings()->setPaintOpOpacity(opacity); m_resourceProvider->currentPreset()->settings()->setPaintOpFlow(flow); KisLockedPropertiesProxy *propertiesProxy = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(m_resourceProvider->currentPreset()->settings()); propertiesProxy->setProperty("OpacityValue", opacity); propertiesProxy->setProperty("FlowValue", flow); delete propertiesProxy; m_optionWidget->setConfiguration(m_resourceProvider->currentPreset()->settings().data()); } m_resourceProvider->setOpacity(opacity); m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset().data()); } void KisPaintopBox::slotSlider1Changed() { sliderChanged(0); } void KisPaintopBox::slotSlider2Changed() { sliderChanged(1); } void KisPaintopBox::slotSlider3Changed() { sliderChanged(2); } void KisPaintopBox::slotToolChanged(KoCanvasController* canvas, int toolId) { Q_UNUSED(canvas); Q_UNUSED(toolId); if (!m_viewManager->canvasBase()) return; QString id = KoToolManager::instance()->activeToolId(); KisTool* tool = dynamic_cast(KoToolManager::instance()->toolById(m_viewManager->canvasBase(), id)); if (tool) { int flags = tool->flags(); if (flags & KisTool::FLAG_USES_CUSTOM_COMPOSITEOP) { setWidgetState(ENABLE_COMPOSITEOP | ENABLE_OPACITY); } else { setWidgetState(DISABLE_COMPOSITEOP | DISABLE_OPACITY); } if (flags & KisTool::FLAG_USES_CUSTOM_PRESET) { setWidgetState(ENABLE_PRESETS | ENABLE_SIZE | ENABLE_FLOW); slotUpdatePreset(); m_presetsEnabled = true; } else { setWidgetState(DISABLE_PRESETS | DISABLE_SIZE | DISABLE_FLOW); m_presetsEnabled = false; } } else setWidgetState(DISABLE_ALL); } void KisPaintopBox::slotOpacityChanged(qreal opacity) { if (m_blockUpdate) { return; } m_blockUpdate = true; for (int i = 0; i < 3; ++i) { KisDoubleSliderSpinBox *opacitySlider = m_sliderChooser[i]->getWidget("opacity"); opacitySlider->blockSignals(true); opacitySlider->setValue(opacity); opacitySlider->blockSignals(false); } if (m_presetsEnabled) { m_resourceProvider->currentPreset()->settings()->setPaintOpOpacity(opacity); m_optionWidget->setConfiguration(m_resourceProvider->currentPreset()->settings().data()); } m_blockUpdate = false; } void KisPaintopBox::slotPreviousFavoritePreset() { if (!m_favoriteResourceManager) return; int i = 0; Q_FOREACH (KisPaintOpPresetSP preset, m_favoriteResourceManager->favoritePresetList()) { if (m_resourceProvider->currentPreset() && m_resourceProvider->currentPreset()->name() == preset->name()) { if (i > 0) { m_favoriteResourceManager->slotChangeActivePaintop(i - 1); } else { m_favoriteResourceManager->slotChangeActivePaintop(m_favoriteResourceManager->numFavoritePresets() - 1); } return; } i++; } } void KisPaintopBox::slotNextFavoritePreset() { if (!m_favoriteResourceManager) return; int i = 0; Q_FOREACH (KisPaintOpPresetSP preset, m_favoriteResourceManager->favoritePresetList()) { if (m_resourceProvider->currentPreset()->name() == preset->name()) { if (i < m_favoriteResourceManager->numFavoritePresets() - 1) { m_favoriteResourceManager->slotChangeActivePaintop(i + 1); } else { m_favoriteResourceManager->slotChangeActivePaintop(0); } return; } i++; } } void KisPaintopBox::slotSwitchToPreviousPreset() { if (m_resourceProvider->previousPreset()) { setCurrentPaintop(m_resourceProvider->previousPreset()->paintOp(), m_resourceProvider->previousPreset()); } } void KisPaintopBox::slotUnsetEraseMode() { if (m_currCompositeOpID == COMPOSITE_ERASE) { updateCompositeOp(m_prevCompositeOpID); } } void KisPaintopBox::slotToggleAlphaLockMode(bool checked) { if (checked) { m_alphaLockButton->actions()[0]->setIcon(KisIconUtils::loadIcon("transparency-locked")); } else { m_alphaLockButton->actions()[0]->setIcon(KisIconUtils::loadIcon("transparency-unlocked")); } toggleHighlightedButton(m_alphaLockButton); m_resourceProvider->setGlobalAlphaLock(checked); } void KisPaintopBox::toggleHighlightedButton(QToolButton* m_tool) { QPalette p = palette(); if (m_tool->isChecked()) { QPalette palette_highlight(p); palette_highlight.setColor(QPalette::Button, p.color(QPalette::Highlight)); m_tool->setPalette(palette_highlight); } else { m_tool->setPalette(p); } } void KisPaintopBox::slotReloadPreset() { KisSignalsBlocker blocker(m_optionWidget); //Here using the name and fetching the preset from the server was the only way the load was working. Otherwise it was not loading. KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); KisPaintOpPresetSP preset = rserver->resourceByName(m_resourceProvider->currentPreset()->name()); if (preset) { preset->load(); preset->settings()->setOptionsWidget(m_optionWidget); m_optionWidget->setConfiguration(preset->settings()); m_presetsPopup->resourceSelected(preset.data()); } slotUpdatePreset(); } void KisPaintopBox::slotConfigurationItemChanged() // Called only when UI is changed and not when preset is changed { m_optionWidget->writeConfiguration(const_cast(m_resourceProvider->currentPreset()->settings().data())); m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset().data()); m_presetsPopup->updateViewSettings(); } void KisPaintopBox::slotSaveLockedOptionToPreset(KisPropertiesConfiguration* p) { QMapIterator i(p->getProperties()); while (i.hasNext()) { i.next(); m_resourceProvider->currentPreset()->settings()->setProperty(i.key(), QVariant(i.value())); if (m_resourceProvider->currentPreset()->settings()->hasProperty(i.key() + "_previous")) { m_resourceProvider->currentPreset()->settings()->removeProperty(i.key() + "_previous"); } } slotConfigurationItemChanged(); } void KisPaintopBox::slotDropLockedOption(KisPropertiesConfiguration* p) { KisSignalsBlocker blocker(m_optionWidget); KisPaintOpPresetSP preset = m_resourceProvider->currentPreset(); { KisPaintOpPreset::DirtyStateSaver dirtySaver(preset.data()); QMapIterator i(p->getProperties()); while (i.hasNext()) { i.next(); if (preset->settings()->hasProperty(i.key() + "_previous")) { preset->settings()->setProperty(i.key(), preset->settings()->getProperty(i.key() + "_previous")); preset->settings()->removeProperty(i.key() + "_previous"); } } m_optionWidget->setConfiguration(preset->settings()); } slotUpdatePreset(); } void KisPaintopBox::slotDirtyPresetToggled(bool value) { if (!value) { slotReloadPreset(); m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset().data()); m_presetsPopup->updateViewSettings(); } m_dirtyPresetsEnabled = value; KisConfig cfg; cfg.setUseDirtyPresets(m_dirtyPresetsEnabled); } void KisPaintopBox::slotEraserBrushSizeToggled(bool value) { m_eraserBrushSizeEnabled = value; KisConfig cfg; cfg.setUseEraserBrushSize(m_eraserBrushSizeEnabled); } void KisPaintopBox::slotUpdateSelectionIcon() { m_hMirrorAction->setIcon(KisIconUtils::loadIcon("symmetry-horizontal")); m_vMirrorAction->setIcon(KisIconUtils::loadIcon("symmetry-vertical")); KisConfig cfg; if (!cfg.toolOptionsInDocker()) { m_toolOptionsPopupButton->setIcon(KisIconUtils::loadIcon("configure")); } m_presetSelectorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_01")); m_brushEditorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_02")); m_workspaceWidget->setIcon(KisIconUtils::loadIcon("view-choose")); m_eraseAction->setIcon(KisIconUtils::loadIcon("draw-eraser")); m_reloadAction->setIcon(KisIconUtils::loadIcon("view-refresh")); } diff --git a/libs/ui/kis_splash_screen.cpp b/libs/ui/kis_splash_screen.cpp index e693da7fc3..4816cba393 100644 --- a/libs/ui/kis_splash_screen.cpp +++ b/libs/ui/kis_splash_screen.cpp @@ -1,145 +1,145 @@ /* * Copyright (c) 2014 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_splash_screen.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include KisSplashScreen::KisSplashScreen(const QString &version, const QPixmap &pixmap, bool themed, QWidget *parent, Qt::WindowFlags f) : QWidget(parent, Qt::SplashScreen | Qt::FramelessWindowHint | f) { setupUi(this); setWindowIcon(KisIconUtils::loadIcon("calligrakrita")); QString color = "#FFFFFF"; if (themed && qApp->palette().background().color().value() >100) { color = "#000000"; } lblSplash->setPixmap(pixmap); bnClose->hide(); connect(bnClose, SIGNAL(clicked()), this, SLOT(close())); chkShowAtStartup->hide(); connect(chkShowAtStartup, SIGNAL(toggled(bool)), this, SLOT(toggleShowAtStartup(bool))); KConfigGroup cfg( KSharedConfig::openConfig(), "SplashScreen"); bool hideSplash = cfg.readEntry("HideSplashAfterStartup", false); chkShowAtStartup->setChecked(hideSplash); lblLinks->setTextFormat(Qt::RichText); lblLinks->setText(i18n("" "" "" "

Links

" "

Support Krita

" "

Getting Started

" - "

Manual

" + "

Manual

" "

Krita Website

" "

User Community

" "

Source Code

" "

Krita on Steam

" "" "", color)); lblVersion->setText(i18n("Version: %1", version)); lblVersion->setStyleSheet("color:" + color); KConfigGroup cfg2( KSharedConfig::openConfig(), "RecentFiles"); int i = 1; QString recent = i18n("" "" "" "

Recent Files

", color); QString path; QStringList recentfiles; do { path = cfg2.readPathEntry(QString("File%1").arg(i), QString()); if (!path.isEmpty()) { QString name = cfg2.readPathEntry(QString("Name%1").arg(i), QString()); QUrl url(path); if (name.isEmpty()) name = url.fileName(); if (!url.isLocalFile() || QFile::exists(url.toLocalFile())) { recentfiles.insert(0, QString("

%2

").arg(path).arg(name).arg(color)); } } i++; } while (!path.isEmpty() || i <= 8); recent += recentfiles.join("\n"); recent += "" ""; lblRecent->setText(recent); connect(lblRecent, SIGNAL(linkActivated(QString)), SLOT(linkClicked(QString))); } void KisSplashScreen::repaint() { QWidget::repaint(); QApplication::flush(); } void KisSplashScreen::show() { QRect r(QPoint(), sizeHint()); resize(r.size()); move(QApplication::desktop()->availableGeometry().center() - r.center()); if (isVisible()) { repaint(); } } void KisSplashScreen::toggleShowAtStartup(bool toggle) { KConfigGroup cfg( KSharedConfig::openConfig(), "SplashScreen"); cfg.writeEntry("HideSplashAfterStartup", toggle); } void KisSplashScreen::linkClicked(const QString &link) { KisPart::instance()->openExistingFile(QUrl::fromLocalFile(link)); if (isTopLevel()) { close(); } } diff --git a/libs/widgetutils/KoResourcePaths.cpp b/libs/widgetutils/KoResourcePaths.cpp index 27f5ad8ed8..871adab2bf 100644 --- a/libs/widgetutils/KoResourcePaths.cpp +++ b/libs/widgetutils/KoResourcePaths.cpp @@ -1,469 +1,492 @@ /* * Copyright (c) 2015 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "KoResourcePaths.h" #include #include #include #include #include #include #include #include #include #include #include Q_GLOBAL_STATIC(KoResourcePaths, s_instance); static QString cleanup(const QString &path) { return QDir::cleanPath(path); } static QStringList cleanup(const QStringList &pathList) { QStringList cleanedPathList; Q_FOREACH(const QString &path, pathList) { cleanedPathList << cleanup(path); } return cleanedPathList; } static QString cleanupDirs(const QString &path) { return QDir::cleanPath(path) + QDir::separator(); } static QStringList cleanupDirs(const QStringList &pathList) { QStringList cleanedPathList; Q_FOREACH(const QString &path, pathList) { cleanedPathList << cleanupDirs(path); } return cleanedPathList; } #ifdef Q_OS_WIN static const Qt::CaseSensitivity cs = Qt::CaseInsensitive; #else static const Qt::CaseSensitivity cs = Qt::CaseSensitive; #endif #ifdef Q_OS_MAC #include #include #include #endif QString getInstallationPrefix() { #ifdef Q_OS_MAC CFURLRef appUrlRef = CFBundleCopyBundleURL(CFBundleGetMainBundle()); CFStringRef macPath = CFURLCopyFileSystemPath(appUrlRef, kCFURLPOSIXPathStyle); const char *pathPtr = CFStringGetCStringPtr(macPath, CFStringGetSystemEncoding()); QString bundlePath = QString::fromLatin1(pathPtr); // //qDebug() << "1" << bundlePath << (bundlePath + QString::fromLatin1("/Contents/MacOS/share")); if (QFile(bundlePath + QString::fromLatin1("/Contents/MacOS/share")).exists()) { // //qDebug() << "running from a deployed bundle"; bundlePath += QString::fromLatin1("/Contents/MacOS/"); } else { // //qDebug() << "running from make install"; bundlePath += "/../"; } CFRelease(appUrlRef); CFRelease(macPath); return bundlePath; #else - return qApp->applicationDirPath() + QDir::separator(); + return qApp->applicationDirPath() + "/../"; #endif } class Q_DECL_HIDDEN KoResourcePaths::Private { public: QMap absolutes; // For each resource type, the list of absolute paths, from most local (most priority) to most global QMap relatives; // Same with relative paths QMutex relativesMutex; QMutex absolutesMutex; QStringList aliases(const QString &type) { QStringList r; QStringList a; relativesMutex.lock(); if (relatives.contains(type)) { r += relatives[type]; } relativesMutex.unlock(); - ////qDebug() << "\trelatives" << r; + //qDebug() << "\trelatives" << r; absolutesMutex.lock(); if (absolutes.contains(type)) { a += absolutes[type]; } - ////qDebug() << "\tabsolutes" << a; + //qDebug() << "\tabsolutes" << a; absolutesMutex.unlock(); return r + a; } QStandardPaths::StandardLocation mapTypeToQStandardPaths(const QString &type) { if (type == "tmp") { return QStandardPaths::TempLocation; } else if (type == "appdata") { return QStandardPaths::AppDataLocation; } else if (type == "data") { return QStandardPaths::AppDataLocation; } else if (type == "cache") { return QStandardPaths::CacheLocation; } else if (type == "locale") { return QStandardPaths::AppDataLocation; } else { return QStandardPaths::AppDataLocation; } } }; KoResourcePaths::KoResourcePaths() : d(new Private) { } KoResourcePaths::~KoResourcePaths() { } QString KoResourcePaths::getApplicationRoot() { return getInstallationPrefix(); } void KoResourcePaths::addResourceType(const char *type, const char *basetype, const QString &relativeName, bool priority) { s_instance->addResourceTypeInternal(QString::fromLatin1(type), QString::fromLatin1(basetype), relativeName, priority); } void KoResourcePaths::addResourceDir(const char *type, const QString &dir, bool priority) { s_instance->addResourceDirInternal(QString::fromLatin1(type), dir, priority); } QString KoResourcePaths::findResource(const char *type, const QString &fileName) { return cleanup(s_instance->findResourceInternal(QString::fromLatin1(type), fileName)); } QStringList KoResourcePaths::findDirs(const char *type, const QString &reldir) { return cleanupDirs(s_instance->findDirsInternal(QString::fromLatin1(type), reldir)); } QStringList KoResourcePaths::findAllResources(const char *type, const QString &filter, SearchOptions options) { return cleanup(s_instance->findAllResourcesInternal(QString::fromLatin1(type), filter, options)); } QStringList KoResourcePaths::resourceDirs(const char *type) { return cleanupDirs(s_instance->resourceDirsInternal(QString::fromLatin1(type))); } QString KoResourcePaths::saveLocation(const char *type, const QString &suffix, bool create) { return cleanupDirs(s_instance->saveLocationInternal(QString::fromLatin1(type), suffix, create)); } QString KoResourcePaths::locate(const char *type, const QString &filename) { return cleanup(s_instance->locateInternal(QString::fromLatin1(type), filename)); } QString KoResourcePaths::locateLocal(const char *type, const QString &filename, bool createDir) { return cleanup(s_instance->locateLocalInternal(QString::fromLatin1(type), filename, createDir)); } void KoResourcePaths::addResourceTypeInternal(const QString &type, const QString &basetype, const QString &relativename, bool priority) { Q_UNUSED(basetype); if (relativename.isEmpty()) return; QString copy = relativename; Q_ASSERT(basetype == "data"); if (!copy.endsWith(QLatin1Char('/'))) { copy += QLatin1Char('/'); } d->relativesMutex.lock(); QStringList &rels = d->relatives[type]; // find or insert if (!rels.contains(copy, cs)) { if (priority) { rels.prepend(copy); } else { rels.append(copy); } } d->relativesMutex.unlock(); - ////qDebug() << "addResourceType: type" << type << "basetype" << basetype << "relativename" << relativename << "priority" << priority << d->relatives[type]; + //qDebug() << "addResourceType: type" << type << "basetype" << basetype << "relativename" << relativename << "priority" << priority << d->relatives[type]; } void KoResourcePaths::addResourceDirInternal(const QString &type, const QString &absdir, bool priority) { if (absdir.isEmpty() || type.isEmpty()) return; // find or insert entry in the map QString copy = absdir; if (copy.at(copy.length() - 1) != QLatin1Char('/')) { copy += QLatin1Char('/'); } d->absolutesMutex.lock(); QStringList &paths = d->absolutes[type]; if (!paths.contains(copy, cs)) { if (priority) { paths.prepend(copy); } else { paths.append(copy); } } d->absolutesMutex.unlock(); //qDebug() << "addResourceDir: type" << type << "absdir" << absdir << "priority" << priority << d->absolutes[type]; } QString KoResourcePaths::findResourceInternal(const QString &type, const QString &fileName) { QStringList aliases = d->aliases(type); - + //qDebug() << "aliases" << aliases; QString resource = QStandardPaths::locate(QStandardPaths::AppDataLocation, fileName, QStandardPaths::LocateFile); + if (resource.isEmpty()) { Q_FOREACH (const QString &alias, aliases) { resource = QStandardPaths::locate(d->mapTypeToQStandardPaths(type), alias + '/' + fileName, QStandardPaths::LocateFile); - if (!resource.isEmpty()) { + if (QFile::exists(resource)) { + continue; + } + } + } + if (resource.isEmpty() || !QFile::exists(resource)) { + QString approot = getApplicationRoot(); + Q_FOREACH (const QString &alias, aliases) { + resource = approot + "/share/" + alias + '/' + fileName; + if (QFile::exists(resource)) { continue; } } } - //Q_ASSERT(!resource.isEmpty()); + if (resource.isEmpty() || !QFile::exists(resource)) { + QString approot = getApplicationRoot(); + Q_FOREACH (const QString &alias, aliases) { + resource = approot + "/share/krita/" + alias + '/' + fileName; + if (QFile::exists(resource)) { + continue; + } + } + } + //qDebug() << "findResource: type" << type << "filename" << fileName << "resource" << resource; + Q_ASSERT(!resource.isEmpty()); return resource; } QStringList KoResourcePaths::findDirsInternal(const QString &type, const QString &relDir) { QStringList aliases = d->aliases(type); - //qDebug() << type << aliases << d->mapTypeToQStandardPaths(type); + //qDebug() << type << relDir << aliases << d->mapTypeToQStandardPaths(type); QStringList dirs; #ifdef Q_OS_MAC QString bundlePath = getApplicationRoot() + "/share/" + relDir; dirs << bundlePath; bundlePath = getApplicationRoot() + "/../share/" + relDir; dirs << bundlePath; #endif dirs << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), relDir, QStandardPaths::LocateDirectory); Q_FOREACH (const QString &alias, aliases) { dirs << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias + '/' + relDir, QStandardPaths::LocateDirectory); } - //Q_ASSERT(!dirs.isEmpty()); + if (dirs.isEmpty()) { + dirs.append(getApplicationRoot() + "/share/" + relDir); + dirs.append(getApplicationRoot() + "/share/krita/" + relDir); + } //qDebug() << "findDirs: type" << type << "relDir" << relDir<< "resource" << dirs; return dirs; } QStringList filesInDir(const QString &startdir, const QString & filter, bool noduplicates, bool recursive) { //qDebug() << "filesInDir: startdir" << startdir << "filter" << filter << "noduplicates" << noduplicates << "recursive" << recursive; QStringList result; // First the entries in this path QStringList nameFilters; nameFilters << filter; const QStringList fileNames = QDir(startdir).entryList(nameFilters, QDir::Files | QDir::CaseSensitive, QDir::Name); //qDebug() << "\tFound:" << fileNames.size() << ":" << fileNames; Q_FOREACH (const QString &fileName, fileNames) { QString file = startdir + '/' + fileName; result << file; } // And then everything underneath, if recursive is specified if (recursive) { const QStringList entries = QDir(startdir).entryList(QDir::Dirs | QDir::NoDotAndDotDot); Q_FOREACH (const QString &subdir, entries) { - ////qDebug() << "\tGoing to look in subdir" << subdir << "of" << startdir; + //qDebug() << "\tGoing to look in subdir" << subdir << "of" << startdir; result << filesInDir(startdir + '/' + subdir, filter, noduplicates, recursive); } } return result; } QStringList KoResourcePaths::findAllResourcesInternal(const QString &type, const QString &_filter, SearchOptions options) const { //qDebug() << "====================================================="; //qDebug() << type << _filter << QStandardPaths::standardLocations(d->mapTypeToQStandardPaths(type)); bool noDuplicates = options & KoResourcePaths::NoDuplicates; bool recursive = options & KoResourcePaths::Recursive; //qDebug() << "findAllResources: type" << type << "filter" << _filter << "no dups" << noDuplicates << "recursive" << recursive; QStringList aliases = d->aliases(type); QString filter = _filter; // In cases where the filter is like "color-schemes/*.colors" instead of "*.kpp", used with unregistered resource types if (filter.indexOf('*') > 0) { aliases << filter.split('*').first(); filter = '*' + filter.split('*')[1]; //qDebug() << "Split up alias" << aliases << "filter" << filter; } QStringList resources; if (aliases.isEmpty()) { resources << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), filter, QStandardPaths::LocateFile); } //qDebug() << "\tresources from qstandardpaths:" << resources.size(); Q_FOREACH (const QString &alias, aliases) { //qDebug() << "\t\talias:" << alias; - const QStringList dirs = QStringList() << getInstallationPrefix() + "../share/" + alias + "/" - << getInstallationPrefix() + "../share/krita/" + alias + "/" + const QStringList dirs = QStringList() << getInstallationPrefix() + "share/" + alias + "/" + << getInstallationPrefix() + "share/krita/" + alias + "/" << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory); QSet s = QSet::fromList(dirs); //qDebug() << "\t\tdirs:" << dirs; Q_FOREACH (const QString &dir, s) { resources << filesInDir(dir, filter, noDuplicates, recursive); } } //qDebug() << "\tresources also from aliases:" << resources.size(); if (resources.isEmpty()) { QFileInfo fi(filter); - resources << filesInDir(getInstallationPrefix() + "../share/" + fi.path(), fi.fileName(), noDuplicates, false); - resources << filesInDir(getInstallationPrefix() + "../share/krita" + fi.path(), fi.fileName(), noDuplicates, false); + resources << filesInDir(getInstallationPrefix() + "share/" + fi.path(), fi.fileName(), noDuplicates, false); + resources << filesInDir(getInstallationPrefix() + "share/krita" + fi.path(), fi.fileName(), noDuplicates, false); } //qDebug() << "\tresources from installation:" << resources.size(); if (noDuplicates) { QSet s = QSet::fromList(resources); resources = s.toList(); } //qDebug() << "====================================================="; return resources; } QStringList KoResourcePaths::resourceDirsInternal(const QString &type) { QStringList resourceDirs; QStringList aliases = d->aliases(type); Q_FOREACH (const QString &alias, aliases) { - resourceDirs << getInstallationPrefix() + "../share/" + alias + "/" + resourceDirs << getInstallationPrefix() + "share/" + alias + "/" << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory); - resourceDirs << getInstallationPrefix() + "../share/krita" + alias + "/" + resourceDirs << getInstallationPrefix() + "share/krita" + alias + "/" << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory); resourceDirs << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory); } //qDebug() << "resourceDirs: type" << type << resourceDirs; return resourceDirs; } QString KoResourcePaths::saveLocationInternal(const QString &type, const QString &suffix, bool create) { QStringList aliases = d->aliases(type); QString path; if (aliases.size() > 0) { path = QStandardPaths::writableLocation(d->mapTypeToQStandardPaths(type)) + '/' + aliases.first(); } else { path = QStandardPaths::writableLocation(d->mapTypeToQStandardPaths(type)) + '/' + (suffix.isEmpty() ? "krita" : suffix); } QDir d(path); if (!d.exists() && create) { d.mkpath(path); } //qDebug() << "saveLocation: type" << type << "suffix" << suffix << "create" << create << "path" << path; return path; } QString KoResourcePaths::locateInternal(const QString &type, const QString &filename) { QStringList aliases = d->aliases(type); QStringList locations; if (aliases.isEmpty()) { locations << QStandardPaths::locate(d->mapTypeToQStandardPaths(type), filename, QStandardPaths::LocateFile); } Q_FOREACH (const QString &alias, aliases) { locations << QStandardPaths::locate(d->mapTypeToQStandardPaths(type), (alias.endsWith('/') ? alias : alias + '/') + filename, QStandardPaths::LocateFile); } //qDebug() << "locate: type" << type << "filename" << filename << "locations" << locations; if (locations.size() > 0) { return locations.first(); } else { return ""; } } QString KoResourcePaths::locateLocalInternal(const QString &type, const QString &filename, bool createDir) { QString path = saveLocationInternal(type, "", createDir); //qDebug() << "locateLocal: type" << type << "filename" << filename << "CreateDir" << createDir << "path" << path; return path + '/' + filename; } diff --git a/plugins/tools/basictools/kis_tool_path.cc b/plugins/tools/basictools/kis_tool_path.cc index 679edb064b..1bc272404f 100644 --- a/plugins/tools/basictools/kis_tool_path.cc +++ b/plugins/tools/basictools/kis_tool_path.cc @@ -1,112 +1,119 @@ /* * Copyright (c) 2007 Sven Langkamp * Copyright (c) 2010 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_path.h" #include #include #include KisToolPath::KisToolPath(KoCanvasBase * canvas) : DelegatedPathTool(canvas, Qt::ArrowCursor, new __KisToolPathLocalTool(canvas, this)) { } void KisToolPath::resetCursorStyle() { DelegatedPathTool::resetCursorStyle(); overrideCursorIfNotEditable(); } void KisToolPath::requestStrokeEnd() { localTool()->endPathWithoutLastPoint(); } void KisToolPath::requestStrokeCancellation() { localTool()->cancelPath(); } void KisToolPath::mousePressEvent(KoPointerEvent *event) { if (!nodeEditable()) return; DelegatedPathTool::mousePressEvent(event); } // Install an event filter to catch right-click events. -// This is the simplest way to accommodate the popup palette binding. +// The simplest way to accommodate the popup palette binding. +// This code is duplicated in kis_tool_select_path.cc bool KisToolPath::eventFilter(QObject *obj, QEvent *event) { Q_UNUSED(obj); if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick) { QMouseEvent *mouseEvent = static_cast(event); if (mouseEvent->button() == Qt::RightButton) { localTool()->removeLastPoint(); return true; } + } else if (event->type() == QEvent::TabletPress) { + QTabletEvent *tabletEvent = static_cast(event); + if (tabletEvent->button() == Qt::RightButton) { + localTool()->removeLastPoint(); + return true; + } } return false; } void KisToolPath::beginAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(action) mousePressEvent(event); } void KisToolPath::continueAlternateAction(KoPointerEvent *event, AlternateAction action){ Q_UNUSED(action) mouseMoveEvent(event); } void KisToolPath::endAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(action) mouseReleaseEvent(event); } QList > KisToolPath::createOptionWidgets() { QList > widgets = DelegatedPathTool::createOptionWidgets(); QList > filteredWidgets; Q_FOREACH (QWidget* widget, widgets) { if (widget->objectName() != "Stroke widget") { filteredWidgets.push_back(widget); } } return filteredWidgets; } __KisToolPathLocalTool::__KisToolPathLocalTool(KoCanvasBase * canvas, KisToolPath* parentTool) : KoCreatePathTool(canvas), m_parentTool(parentTool) {} void __KisToolPathLocalTool::paintPath(KoPathShape &pathShape, QPainter &painter, const KoViewConverter &converter) { Q_UNUSED(converter); QTransform matrix; matrix.scale(m_parentTool->image()->xRes(), m_parentTool->image()->yRes()); matrix.translate(pathShape.position().x(), pathShape.position().y()); m_parentTool->paintToolOutline(&painter, m_parentTool->pixelToView(matrix.map(pathShape.outline()))); } void __KisToolPathLocalTool::addPathShape(KoPathShape* pathShape) { m_parentTool->addPathShape(pathShape, kundo2_i18n("Draw Bezier Curve")); } diff --git a/plugins/tools/selectiontools/kis_tool_select_path.cc b/plugins/tools/selectiontools/kis_tool_select_path.cc index e643ceb5fc..d838550298 100644 --- a/plugins/tools/selectiontools/kis_tool_select_path.cc +++ b/plugins/tools/selectiontools/kis_tool_select_path.cc @@ -1,160 +1,167 @@ /* * Copyright (c) 2007 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_select_path.h" #include #include "kis_cursor.h" #include "kis_image.h" #include "kis_painter.h" #include "kis_selection_options.h" #include "kis_canvas_resource_provider.h" #include "kis_canvas2.h" #include "kis_pixel_selection.h" #include "kis_selection_tool_helper.h" #include KisToolSelectPath::KisToolSelectPath(KoCanvasBase * canvas) : SelectionActionHandler(canvas, KisCursor::load("tool_polygonal_selection_cursor.png", 6, 6), i18n("Select path"), (KisTool*) (new __KisToolSelectPathLocalTool(canvas, this))) { } void KisToolSelectPath::requestStrokeEnd() { localTool()->endPathWithoutLastPoint(); } void KisToolSelectPath::requestStrokeCancellation() { localTool()->cancelPath(); } void KisToolSelectPath::mousePressEvent(KoPointerEvent* event) { if (!selectionEditable()) return; DelegatedSelectPathTool::mousePressEvent(event); } // Install an event filter to catch right-click events. +// This code is duplicated in kis_tool_path.cc bool KisToolSelectPath::eventFilter(QObject *obj, QEvent *event) { - Q_UNUSED(obj) + Q_UNUSED(obj); if (event->type() == QEvent::MouseButtonPress || - event->type() == QEvent::MouseButtonDblClick) { + event->type() == QEvent::MouseButtonDblClick) { QMouseEvent *mouseEvent = static_cast(event); if (mouseEvent->button() == Qt::RightButton) { localTool()->removeLastPoint(); return true; } + } else if (event->type() == QEvent::TabletPress) { + QTabletEvent *tabletEvent = static_cast(event); + if (tabletEvent->button() == Qt::RightButton) { + localTool()->removeLastPoint(); + return true; + } } return false; } QList > KisToolSelectPath::createOptionWidgets() { QList > widgetsList = DelegatedSelectPathTool::createOptionWidgets(); return widgetsList; } void KisToolSelectPath::setAlternateSelectionAction(SelectionAction action) { // We will turn off the ability to change the selection in the middle of drawing a path. if (!m_localTool->listeningToModifiers()) { SelectionActionHandler::setAlternateSelectionAction(action); } } bool KisDelegatedSelectPathWrapper::listeningToModifiers() { return m_localTool->listeningToModifiers(); } void KisDelegatedSelectPathWrapper::beginPrimaryAction(KoPointerEvent *event) { mousePressEvent(event); } void KisDelegatedSelectPathWrapper::continuePrimaryAction(KoPointerEvent *event){ mouseMoveEvent(event); } void KisDelegatedSelectPathWrapper::endPrimaryAction(KoPointerEvent *event) { mouseReleaseEvent(event); } __KisToolSelectPathLocalTool::__KisToolSelectPathLocalTool(KoCanvasBase * canvas, KisToolSelectPath* parentTool) : KoCreatePathTool(canvas), m_selectionTool(parentTool) { } void __KisToolSelectPathLocalTool::paintPath(KoPathShape &pathShape, QPainter &painter, const KoViewConverter &converter) { Q_UNUSED(converter); KisCanvas2 * kisCanvas = dynamic_cast(canvas()); if (!kisCanvas) return; QTransform matrix; matrix.scale(kisCanvas->image()->xRes(), kisCanvas->image()->yRes()); matrix.translate(pathShape.position().x(), pathShape.position().y()); m_selectionTool->paintToolOutline(&painter, m_selectionTool->pixelToView(matrix.map(pathShape.outline()))); } void __KisToolSelectPathLocalTool::addPathShape(KoPathShape* pathShape) { pathShape->normalize(); pathShape->close(); KisCanvas2 * kisCanvas = dynamic_cast(canvas()); if (!kisCanvas) return; KisImageWSP image = kisCanvas->image(); KisSelectionToolHelper helper(kisCanvas, kundo2_i18n("Select by Bezier Curve")); if (m_selectionTool->selectionMode() == PIXEL_SELECTION) { KisPixelSelectionSP tmpSel = KisPixelSelectionSP(new KisPixelSelection()); KisPainter painter(tmpSel); painter.setPaintColor(KoColor(Qt::black, tmpSel->colorSpace())); painter.setFillStyle(KisPainter::FillStyleForegroundColor); painter.setAntiAliasPolygonFill(m_selectionTool->antiAliasSelection()); painter.setStrokeStyle(KisPainter::StrokeStyleNone); QTransform matrix; matrix.scale(image->xRes(), image->yRes()); matrix.translate(pathShape->position().x(), pathShape->position().y()); QPainterPath path = matrix.map(pathShape->outline()); painter.fillPainterPath(path); tmpSel->setOutlineCache(path); helper.selectPixelSelection(tmpSel, m_selectionTool->selectionAction()); delete pathShape; } else { helper.addSelectionShape(pathShape); } } diff --git a/windows/build.bat b/windows/build.bat index 8b0b979b71..35163c8eac 100644 --- a/windows/build.bat +++ b/windows/build.bat @@ -1,41 +1,35 @@ rem rem Follow the instructions in 3rdparty/README.md to setup Qt and the rem build dirs and checkout krita rem set PATH=c:\dev\i\bin\;c:\dev\i\lib;%PATH% cd c:\dev\b cmake ..\krita\3rdparty -DEXTERNALS_DOWNLOAD_DIR=/dev/d -DINSTALL_ROOT=/dev/i -G "Visual Studio 14 Win64" cmake --build . --config RelWithDebInfo --target ext_patch cmake --build . --config RelWithDebInfo --target ext_png2ico cmake --build . --config RelWithDebInfo --target ext_pthreads cmake --build . --config RelWithDebInfo --target ext_boost -copy c:\dev\i\lib\boost_system-vc-mt-1_55.dll c:\dev\i\lib\boost_system-vc140-mt-1_55.dll -copy c:\dev\i\lib\boost_system-vc-mt-1_55.dll c:\dev\i\bin\boost_system-vc140-mt-1_55.dll -copy c:\dev\i\lib\boost_system-vc-mt-1_55.lib c:\dev\i\lib\boost_system-vc140-mt-1_55.lib cmake --build . --config RelWithDebInfo --target ext_eigen3 cmake --build . --config RelWithDebInfo --target ext_fftw3 -xcopy ext_fftw3\ext_fftw3-prefix\src\ext_fftw3\bin\*.* c:\dev\i\bin -xcopy ext_fftw3\ext_fftw3-prefix\src\ext_fftw3\lib\*.* c:\dev\i\lib -xcopy ext_fftw3\ext_fftw3-prefix\src\ext_fftw3\include\*.* c:\dev\i\include cmake --build . --config RelWithDebInfo --target ext_ilmbase cmake --build . --config RelWithDebInfo --target ext_jpeg cmake --build . --config RelWithDebInfo --target ext_lcms2 cmake --build . --config RelWithDebInfo --target ext_png cmake --build . --config RelWithDebInfo --target ext_tiff cmake --build . --config RelWithDebInfo --target ext_gsl cmake --build . --config RelWithDebInfo --target ext_vc cmake --build . --config RelWithDebInfo --target ext_libraw rem cmake --build . --config RelWithDebInfo --target ext_openjpeg rem cmake --build . --config RelWithDebInfo --target ext_freetype cmake --build . --config RelWithDebInfo --target ext_ocio cmake --build . --config RelWithDebInfo --target ext_openexr cmake --build . --config RelWithDebInfo --target ext_exiv2 cmake --build . --config RelWithDebInfo --target ext_kwindowsystem REM cmake --build . --config RelWithDebInfo --target ext_poppler cd c:\dev\build cmake ..\krita -G"Visual Studio 14 Win64" -DBoost_DEBUG=OFF -DBOOST_INCLUDEDIR=c:\dev\i\include -DBOOST_DEBUG=ON -DBOOST_ROOT=c:\dev\i -DBOOST_LIBRARYDIR=c:\dev\i\lib -DCMAKE_INSTALL_PREFIX=c:\dev\i -DCMAKE_PREFIX_PATH=c:\dev\i -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTING=OFF -DKDE4_BUILD_TESTS=OFF -DHAVE_MEMORY_LEAK_TRACKER=OFF -DPACKAGERS_BUILD=ON -Wno-dev -DDEFINE_NO_DEPRECATED=1 copy c:\dev\i\lib\*.dll c:\dev\i\bin copy "C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x64\*.dll" c:\dev\i\bin