diff --git a/CMakeLists.txt b/CMakeLists.txt index 04f291bed4..fa9abbcda7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,924 +1,939 @@ project(krita) message(STATUS "Using CMake version: ${CMAKE_VERSION}") cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) set(MIN_QT_VERSION 5.9.0) set(MIN_FRAMEWORKS_VERSION 5.44.0) set( CMAKE_CXX_STANDARD 11 ) set( CMAKE_CXX_STANDARD_REQUIRED ON ) if (POLICY CMP0002) cmake_policy(SET CMP0002 OLD) endif() if (POLICY CMP0017) cmake_policy(SET CMP0017 NEW) endif () if (POLICY CMP0022) cmake_policy(SET CMP0022 OLD) endif () if (POLICY CMP0026) cmake_policy(SET CMP0026 OLD) endif() if (POLICY CMP0042) cmake_policy(SET CMP0042 NEW) endif() if (POLICY CMP0046) cmake_policy(SET CMP0046 OLD) endif () if (POLICY CMP0059) cmake_policy(SET CMP0059 OLD) endif() if (POLICY CMP0063) cmake_policy(SET CMP0063 OLD) endif() if (POLICY CMP0054) cmake_policy(SET CMP0054 OLD) endif() if (POLICY CMP0064) cmake_policy(SET CMP0064 OLD) endif() if (POLICY CMP0071) cmake_policy(SET CMP0071 OLD) endif() if (APPLE) set(APPLE_SUPPRESS_X11_WARNING TRUE) set(KDE_SKIP_RPATH_SETTINGS TRUE) set(CMAKE_MACOSX_RPATH 1) set(BUILD_WITH_INSTALL_RPATH 1) add_definitions(-mmacosx-version-min=10.12 -Wno-macro-redefined -Wno-deprecated-register) endif() if (CMAKE_COMPILER_IS_GNUCXX AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9 AND NOT WIN32) add_compile_options($<$:-Wno-suggest-override> -Wextra -Wno-class-memaccess) endif() ###################### ####################### ## Constants defines ## ####################### ###################### # define common versions of Krita applications, used to generate kritaversion.h # update these version for every release: set(KRITA_VERSION_STRING "5.0.0-prealpha") # Major version: 3 for 3.x, 4 for 4.x, etc. set(KRITA_STABLE_VERSION_MAJOR 5) # Minor version: 0 for 4.0, 1 for 4.1, etc. set(KRITA_STABLE_VERSION_MINOR 0) # Bugfix release version, or 0 for before the first stable release set(KRITA_VERSION_RELEASE 0) # the 4th digit, really only used for the Windows installer: # - [Pre-]Alpha: Starts from 0, increment 1 per release # - Beta: Starts from 50, increment 1 per release # - Stable: Set to 100, bump to 101 if emergency update is needed set(KRITA_VERSION_REVISION 0) set(KRITA_ALPHA 1) # uncomment only for Alpha #set(KRITA_BETA 1) # uncomment only for Beta #set(KRITA_RC 1) # uncomment only for RC if(NOT DEFINED KRITA_ALPHA AND NOT DEFINED KRITA_BETA AND NOT DEFINED KRITA_RC) set(KRITA_STABLE 1) # do not edit endif() message(STATUS "Krita version: ${KRITA_VERSION_STRING}") # Define the generic version of the Krita libraries here # This makes it easy to advance it when the next Krita release comes. # 14 was the last GENERIC_KRITA_LIB_VERSION_MAJOR of the previous Krita series # (2.x) so we're starting with 15 in 3.x series, 16 in 4.x series if(KRITA_STABLE_VERSION_MAJOR EQUAL 5) math(EXPR GENERIC_KRITA_LIB_VERSION_MAJOR "${KRITA_STABLE_VERSION_MINOR} + 17") else() # let's make sure we won't forget to update the "16" message(FATAL_ERROR "Reminder: please update offset == 16 used to compute GENERIC_KRITA_LIB_VERSION_MAJOR to something bigger") endif() set(GENERIC_KRITA_LIB_VERSION "${GENERIC_KRITA_LIB_VERSION_MAJOR}.0.0") set(GENERIC_KRITA_LIB_SOVERSION "${GENERIC_KRITA_LIB_VERSION_MAJOR}") LIST (APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules") LIST (APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/kde_macro") # fetch git revision for the current build set(KRITA_GIT_SHA1_STRING "") set(KRITA_GIT_BRANCH_STRING "") include(GetGitRevisionDescription) get_git_head_hash(GIT_SHA1) get_git_branch(GIT_BRANCH) if(GIT_SHA1) string(SUBSTRING ${GIT_SHA1} 0 7 GIT_SHA1) set(KRITA_GIT_SHA1_STRING ${GIT_SHA1}) if(GIT_BRANCH) set(KRITA_GIT_BRANCH_STRING ${GIT_BRANCH}) else() set(KRITA_GIT_BRANCH_STRING "(detached HEAD)") endif() endif() # create test make targets enable_testing() # collect list of broken tests, empty here to start fresh with each cmake run set(KRITA_BROKEN_TESTS "" CACHE INTERNAL "KRITA_BROKEN_TESTS") ############ ############# ## Options ## ############# ############ include(FeatureSummary) if (WIN32) option(USE_DRMINGW "Support the Dr. Mingw crash handler (only on windows)" ON) add_feature_info("Dr. Mingw" USE_DRMINGW "Enable the Dr. Mingw crash handler") if (MINGW) option(USE_MINGW_HARDENING_LINKER "Enable DEP (NX), ASLR and high-entropy ASLR linker flags (mingw-w64)" ON) add_feature_info("Linker Security Flags" USE_MINGW_HARDENING_LINKER "Enable DEP (NX), ASLR and high-entropy ASLR linker flags") if (USE_MINGW_HARDENING_LINKER) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--dynamicbase -Wl,--nxcompat -Wl,--disable-auto-image-base") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--dynamicbase -Wl,--nxcompat -Wl,--disable-auto-image-base") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--dynamicbase -Wl,--nxcompat -Wl,--disable-auto-image-base") if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") # Enable high-entropy ASLR for 64-bit # The image base has to be >4GB for HEASLR to be enabled. # The values used here are kind of arbitrary. set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--high-entropy-va -Wl,--image-base,0x140000000") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--high-entropy-va -Wl,--image-base,0x180000000") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--high-entropy-va -Wl,--image-base,0x180000000") endif ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") else (USE_MINGW_HARDENING_LINKER) message(WARNING "Linker Security Flags not enabled!") endif (USE_MINGW_HARDENING_LINKER) endif (MINGW) endif () option(HIDE_SAFE_ASSERTS "Don't show message box for \"safe\" asserts, just ignore them automatically and dump a message to the terminal." ON) configure_file(config-hide-safe-asserts.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-hide-safe-asserts.h) add_feature_info("Hide Safe Asserts" HIDE_SAFE_ASSERTS "Don't show message box for \"safe\" asserts, just ignore them automatically and dump a message to the terminal.") option(USE_LOCK_FREE_HASH_TABLE "Use lock free hash table instead of blocking." ON) configure_file(config-hash-table-implementaion.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-hash-table-implementaion.h) add_feature_info("Lock free hash table" USE_LOCK_FREE_HASH_TABLE "Use lock free hash table instead of blocking.") option(FOUNDATION_BUILD "A Foundation build is a binary release build that can package some extra things like color themes. Linux distributions that build and install Krita into a default system location should not define this option to true." OFF) add_feature_info("Foundation Build" FOUNDATION_BUILD "A Foundation build is a binary release build that can package some extra things like color themes. Linux distributions that build and install Krita into a default system location should not define this option to true.") option(KRITA_ENABLE_BROKEN_TESTS "Enable tests that are marked as broken" OFF) add_feature_info("Enable Broken Tests" KRITA_ENABLE_BROKEN_TESTS "Runs broken test when \"make test\" is invoked (use -DKRITA_ENABLE_BROKEN_TESTS=ON to enable).") option(LIMIT_LONG_TESTS "Run long running unittests in a limited quick mode" ON) configure_file(config-limit-long-tests.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-limit-long-tests.h) add_feature_info("Limit long tests" LIMIT_LONG_TESTS "Run long running unittests in a limited quick mode") option(ENABLE_PYTHON_2 "Enables the compiler to look for Python 2.7 instead of Python 3. Some packaged scripts are not compatible with Python 2 and this should only be used if you really have to use 2.7." OFF) option(BUILD_KRITA_QT_DESIGNER_PLUGINS "Build Qt Designer plugins for Krita widgets" OFF) add_feature_info("Build Qt Designer plugins" BUILD_KRITA_QT_DESIGNER_PLUGINS "Builds Qt Designer plugins for Krita widgets (use -DBUILD_KRITA_QT_DESIGNER_PLUGINS=ON to enable).") +option(ENABLE_UPDATERS "Enable updaters/update notifications" ON) +configure_file(config-updaters.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-updaters.h) +add_feature_info("Enable updaters" ENABLE_UPDATERS "Enable updaters/update notifications.") + +# Branding. Available options: default, Beta, Plus, Next. Can be set from command line +if (NOT DEFINED BRANDING) + set(BRANDING "default") +endif() +message(STATUS "Branding selected: ${BRANDING}") + include(MacroJPEG) ######################################################### ## Look for Python3 It is also searched by KF5, ## ## so we should request the correct version in advance ## ######################################################### function(TestCompileLinkPythonLibs OUTPUT_VARNAME) include(CheckCXXSourceCompiles) set(CMAKE_REQUIRED_INCLUDES ${PYTHON_INCLUDE_PATH}) set(CMAKE_REQUIRED_LIBRARIES ${PYTHON_LIBRARIES}) if (MINGW) set(CMAKE_REQUIRED_DEFINITIONS -D_hypot=hypot) endif (MINGW) unset(${OUTPUT_VARNAME} CACHE) CHECK_CXX_SOURCE_COMPILES(" #include int main(int argc, char *argv[]) { Py_InitializeEx(0); }" ${OUTPUT_VARNAME}) endfunction() if(MINGW) if(ENABLE_PYTHON_2) message(FATAL_ERROR "Python 2.7 is not supported on Windows at the moment.") else(ENABLE_PYTHON_2) find_package(PythonInterp 3.8 EXACT) find_package(PythonLibs 3.8 EXACT) endif(ENABLE_PYTHON_2) if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) if(ENABLE_PYTHON_2) find_package(PythonLibrary 2.7) else(ENABLE_PYTHON_2) find_package(PythonLibrary 3.8) endif(ENABLE_PYTHON_2) TestCompileLinkPythonLibs(CAN_USE_PYTHON_LIBS) if (NOT CAN_USE_PYTHON_LIBS) message(FATAL_ERROR "Compiling with Python library failed, please check whether the architecture is correct. Python will be disabled.") endif (NOT CAN_USE_PYTHON_LIBS) endif (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) else(MINGW) if(ENABLE_PYTHON_2) find_package(PythonInterp 2.7) find_package(PythonLibrary 2.7) else(ENABLE_PYTHON_2) find_package(PythonInterp 3.0) find_package(PythonLibrary 3.0) endif(ENABLE_PYTHON_2) endif(MINGW) ######################## ######################### ## Look for KDE and Qt ## ######################### ######################## find_package(ECM 5.22 REQUIRED NOMODULE) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) include(ECMOptionalAddSubdirectory) include(ECMAddAppIcon) include(ECMSetupVersion) include(ECMMarkNonGuiExecutable) include(ECMGenerateHeaders) include(GenerateExportHeader) include(ECMMarkAsTest) include(ECMInstallIcons) include(CMakePackageConfigHelpers) include(WriteBasicConfigVersionFile) include(CheckFunctionExists) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings) # do not reorder to be alphabetical: this is the order in which the frameworks # depend on each other. find_package(KF5 ${MIN_FRAMEWORKS_VERSION} REQUIRED COMPONENTS Config WidgetsAddons Completion CoreAddons GuiAddons I18n ItemModels ItemViews WindowSystem ) find_package(Qt5 ${MIN_QT_VERSION} REQUIRED COMPONENTS Core Gui Widgets Xml Network PrintSupport Svg Test Concurrent Sql ) if (ANDROID) find_package(Qt5 ${MIN_QT_VERSION} REQUIRED COMPONENTS AndroidExtras ) endif() if (WIN32) set(CMAKE_REQUIRED_INCLUDES ${Qt5Core_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${Qt5Core_LIBRARIES}) CHECK_CXX_SOURCE_COMPILES(" #include int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_MSWindowsUseWinTabAPI); } " QT_HAS_WINTAB_SWITCH ) unset(CMAKE_REQUIRED_INCLUDES) unset(CMAKE_REQUIRED_LIBRARIES) option(USE_QT_TABLET_WINDOWS "Do not use Krita's forked Wintab and Windows Ink support on Windows, but leave everything to Qt." ON) add_feature_info("Use Qt's Windows Tablet Support" USE_QT_TABLET_WINDOWS "Do not use Krita's forked Wintab and Windows Ink support on Windows, but leave everything to Qt.") configure_file(config_use_qt_tablet_windows.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_use_qt_tablet_windows.h) endif () set(CMAKE_REQUIRED_INCLUDES ${Qt5Core_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES}) CHECK_CXX_SOURCE_COMPILES(" #include int main(int argc, char *argv[]) { QSurfaceFormat fmt; fmt.setColorSpace(QSurfaceFormat::scRGBColorSpace); fmt.setColorSpace(QSurfaceFormat::bt2020PQColorSpace); } " HAVE_HDR ) configure_file(config-hdr.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-hdr.h) CHECK_CXX_SOURCE_COMPILES(" #include int main(int argc, char *argv[]) { QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Round); QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor); QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); } " HAVE_HIGH_DPI_SCALE_FACTOR_ROUNDING_POLICY ) configure_file(config-high-dpi-scale-factor-rounding-policy.h.in ${CMAKE_CURRENT_BINARY_DIR}/config-high-dpi-scale-factor-rounding-policy.h) if (WIN32) CHECK_CXX_SOURCE_COMPILES(" #include int main(int argc, char *argv[]) { QWindowsWindowFunctions::setHasBorderInFullScreenDefault(true); } " HAVE_SET_HAS_BORDER_IN_FULL_SCREEN_DEFAULT ) configure_file(config-set-has-border-in-full-screen-default.h.in ${CMAKE_CURRENT_BINARY_DIR}/config-set-has-border-in-full-screen-default.h) endif (WIN32) unset(CMAKE_REQUIRED_INCLUDES) unset(CMAKE_REQUIRED_LIBRARIES) include (MacroAddFileDependencies) include (MacroBoolTo01) include (MacroEnsureOutOfSourceBuild) macro_ensure_out_of_source_build("Compiling Krita inside the source directory is not possible. Please refer to the build instruction https://community.kde.org/Krita#Build_Instructions") # Note: OPTIONAL_COMPONENTS does not seem to be reliable # (as of ECM 5.15.0, CMake 3.2) find_package(Qt5Multimedia ${MIN_QT_VERSION}) set_package_properties(Qt5Multimedia PROPERTIES DESCRIPTION "Qt multimedia integration" URL "https://www.qt.io/" TYPE OPTIONAL PURPOSE "Optionally used to provide sound support for animations") macro_bool_to_01(Qt5Multimedia_FOUND HAVE_QT_MULTIMEDIA) configure_file(config-qtmultimedia.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-qtmultimedia.h ) if (NOT APPLE) find_package(Qt5Quick ${MIN_QT_VERSION}) set_package_properties(Qt5Quick PROPERTIES DESCRIPTION "QtQuick" URL "https://www.qt.io/" TYPE OPTIONAL PURPOSE "Optionally used for the touch gui for Krita") macro_bool_to_01(Qt5Quick_FOUND HAVE_QT_QUICK) find_package(Qt5QuickWidgets ${MIN_QT_VERSION}) set_package_properties(Qt5QuickWidgets PROPERTIES DESCRIPTION "QtQuickWidgets" URL "https://www.qt.io/" TYPE OPTIONAL PURPOSE "Optionally used for the touch gui for Krita") endif() if (NOT WIN32 AND NOT APPLE AND NOT ANDROID) find_package(Qt5 ${MIN_QT_VERSION} REQUIRED X11Extras) find_package(Qt5DBus ${MIN_QT_VERSION}) set(HAVE_DBUS ${Qt5DBus_FOUND}) set_package_properties(Qt5DBus PROPERTIES DESCRIPTION "Qt DBUS integration" URL "https://www.qt.io/" TYPE OPTIONAL PURPOSE "Optionally used to provide a dbus api on Linux") find_package(KF5Crash ${MIN_FRAMEWORKS_VERSION}) macro_bool_to_01(KF5Crash_FOUND HAVE_KCRASH) set_package_properties(KF5Crash PROPERTIES DESCRIPTION "KDE's Crash Handler" URL "https://api.kde.org/frameworks-api/frameworks5-apidocs/kcrash/html/index.html" TYPE OPTIONAL PURPOSE "Optionally used to provide crash reporting on Linux") find_package(X11 REQUIRED COMPONENTS Xinput) set(HAVE_X11 TRUE) add_definitions(-DHAVE_X11) else() set(HAVE_DBUS FALSE) set(HAVE_X11 FALSE) endif() add_definitions( -DQT_USE_QSTRINGBUILDER -DQT_STRICT_ITERATORS -DQT_NO_SIGNALS_SLOTS_KEYWORDS -DQT_NO_URL_CAST_FROM_STRING -DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS ) #if (${Qt5_VERSION} VERSION_GREATER "5.14.0" ) # add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50F00) #elseif (${Qt5_VERSION} VERSION_GREATER "5.13.0" ) # add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50E00) #elseif (${Qt5_VERSION} VERSION_GREATER "5.12.0" ) # add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50D00) #elseif (${Qt5_VERSION} VERSION_GREATER "5.11.0" ) # add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50C00) #if(${Qt5_VERSION} VERSION_GREATER "5.10.0" ) # add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50B00) #if(${Qt5_VERSION} VERSION_GREATER "5.9.0" ) # add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50A00) #else() add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50900) #endif() add_definitions(-DQT_DEPRECATED_WARNINGS) add_definitions(-DTRANSLATION_DOMAIN=\"krita\") # # The reason for this mode is that the Debug mode disable inlining # if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fext-numeric-literals") endif() option(KRITA_DEVS "For Krita developers. This modifies the DEBUG build type to use -O3 -g, while still enabling Q_ASSERT. This is necessary because the Qt5 cmake modules normally append QT_NO_DEBUG to any build type that is not labeled Debug") if (KRITA_DEVS) set(CMAKE_CXX_FLAGS_DEBUG "-O3 -g" CACHE STRING "" FORCE) endif() if(UNIX) set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES};m") endif() if(WIN32) if(MSVC) # C4522: 'class' : multiple assignment operators specified set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -wd4522") endif() endif() # KDECompilerSettings adds the `--export-all-symbols` linker flag. # We don't really need it. if(MINGW) string(REPLACE "-Wl,--export-all-symbols" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") string(REPLACE "-Wl,--export-all-symbols" "" CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}") endif(MINGW) if(MINGW) # Hack CMake's variables to tell AR to create thin archives to reduce unnecessary writes. # Source of definition: https://github.com/Kitware/CMake/blob/v3.14.1/Modules/Platform/Windows-GNU.cmake#L128 # Thin archives: https://sourceware.org/binutils/docs/binutils/ar.html#index-thin-archives macro(mingw_use_thin_archive lang) foreach(rule CREATE_SHARED_MODULE CREATE_SHARED_LIBRARY LINK_EXECUTABLE) string(REGEX REPLACE "( [^ T]+) " "\\1T " CMAKE_${lang}_${rule} "${CMAKE_${lang}_${rule}}") endforeach() endmacro() mingw_use_thin_archive(CXX) endif(MINGW) # enable exceptions globally kde_enable_exceptions() set(KRITA_DEFAULT_TEST_DATA_DIR ${CMAKE_SOURCE_DIR}/sdk/tests/data/) macro(macro_add_unittest_definitions) add_definitions(-DFILES_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data/") add_definitions(-DFILES_OUTPUT_DIR="${CMAKE_CURRENT_BINARY_DIR}") add_definitions(-DFILES_DEFAULT_DATA_DIR="${KRITA_DEFAULT_TEST_DATA_DIR}") add_definitions(-DSYSTEM_RESOURCES_DATA_DIR="${CMAKE_SOURCE_DIR}/krita/data/") endmacro() # overcome some platform incompatibilities if(WIN32) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/winquirks) add_definitions(-D_USE_MATH_DEFINES) add_definitions(-DNOMINMAX) set(WIN32_PLATFORM_NET_LIBS ws2_32.lib netapi32.lib) endif() # set custom krita plugin installdir if (ANDROID) # use default ABI if (NOT ANDROID_ABI) set (ANDROID_ABI armeabi-v7a) endif() set (ANDROID_SDK_ROOT $ENV{ANDROID_SDK_ROOT}) set (KRITA_PLUGIN_INSTALL_DIR ${LIB_INSTALL_DIR}) # set (DATA_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/assets) else() set (KRITA_PLUGIN_INSTALL_DIR ${LIB_INSTALL_DIR}/kritaplugins) endif() ########################### ############################ ## Required dependencies ## ############################ ########################### # FIXME: Still hardcoded if (ANDROID) set (Boost_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/i/${ANDROID_ABI}/include/boost-1_69) set (Boost_LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/i/${ANDROID_ABI}/lib) set (KF5_LIBRARIES ${CMAKE_CURRENT_BINARY_DIR}/kf5/kde/install/lib) endif() +# HACK for detecting boost from binary factory deps, remove +if(MINGW) + set (Boost_COMPILER "-mgw73") +endif() + find_package(PNG REQUIRED) list (APPEND ANDROID_EXTRA_LIBS ${PNG_LIBRARY}) if (APPLE) # this is not added correctly on OSX -- see https://forum.kde.org/viewtopic.php?f=139&t=101867&p=221242#p221242 include_directories(SYSTEM ${PNG_INCLUDE_DIR}) endif() add_definitions(-DBOOST_ALL_NO_LIB) find_package(Boost 1.55 REQUIRED COMPONENTS system) include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) ## ## Test for GNU Scientific Library ## find_package(GSL) set_package_properties(GSL PROPERTIES URL "https://www.gnu.org/software/gsl" TYPE RECOMMENDED PURPOSE "Required by Krita's Transform tool.") macro_bool_to_01(GSL_FOUND HAVE_GSL) configure_file(config-gsl.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-gsl.h ) if (GSL_FOUND) list (APPEND ANDROID_EXTRA_LIBS ${GSL_LIBRARIES} ${GSL_CBLAS_LIBRARIES}) endif() ########################### ############################ ## Optional dependencies ## ############################ ########################### find_package(ZLIB) set_package_properties(ZLIB PROPERTIES DESCRIPTION "Compression library" URL "https://www.zlib.net/" TYPE OPTIONAL PURPOSE "Optionally used by the G'Mic and the PSD plugins") macro_bool_to_01(ZLIB_FOUND HAVE_ZLIB) find_package(OpenEXR) set_package_properties(OpenEXR PROPERTIES DESCRIPTION "High dynamic-range (HDR) image file format" URL "https://www.openexr.com" TYPE OPTIONAL PURPOSE "Required by the Krita OpenEXR filter") macro_bool_to_01(OPENEXR_FOUND HAVE_OPENEXR) set(LINK_OPENEXR_LIB) if(OPENEXR_FOUND) include_directories(SYSTEM ${OPENEXR_INCLUDE_DIRS}) set(LINK_OPENEXR_LIB ${OPENEXR_LIBRARIES}) add_definitions(${OPENEXR_DEFINITIONS}) endif() find_package(TIFF) set_package_properties(TIFF PROPERTIES DESCRIPTION "TIFF Library and Utilities" URL "http://www.libtiff.org" TYPE OPTIONAL PURPOSE "Required by the Krita TIFF filter") if (TIFF_FOUND) list (APPEND ANDROID_EXTRA_LIBS ${TIFF_LIBRARY}) endif() find_package(JPEG) set_package_properties(JPEG PROPERTIES DESCRIPTION "Free library for JPEG image compression. Note: libjpeg8 is NOT supported." URL "https://www.libjpeg-turbo.org" TYPE OPTIONAL PURPOSE "Required by the Krita JPEG filter") if (JPEG_FOUND) list (APPEND ANDROID_EXTRA_LIBS ${JPEG_LIBRARY}) endif() find_package(GIF) set_package_properties(GIF PROPERTIES DESCRIPTION "Library for loading and saving gif files." URL "http://giflib.sourceforge.net/" TYPE OPTIONAL PURPOSE "Required by the Krita GIF filter") if (GIF_FOUND) list (APPEND ANDROID_EXTRA_LIBS ${GIF_LIBRARY}) endif() find_package(HEIF "1.3.0") set_package_properties(HEIF PROPERTIES DESCRIPTION "Library for loading and saving heif files." URL "https://github.com/strukturag/libheif" TYPE OPTIONAL PURPOSE "Required by the Krita HEIF filter") find_package(OpenJPEG "2.3.0") set_package_properties(OpenJPEG PROPERTIES DESCRIPTION "Library for loading and saving jp2000 files." URL "https://www.openjpeg.org/" TYPE OPTIONAL PURPOSE "Required by the Krita JP2000 filter") set(LIBRAW_MIN_VERSION "0.16") find_package(LibRaw ${LIBRAW_MIN_VERSION}) set_package_properties(LibRaw PROPERTIES DESCRIPTION "Library to decode RAW images" URL "https://www.libraw.org/" TYPE OPTIONAL PURPOSE "Required to build the raw import plugin") find_package(FFTW3) set_package_properties(FFTW3 PROPERTIES DESCRIPTION "A fast, free C FFT library" URL "http://www.fftw.org/" TYPE OPTIONAL PURPOSE "Required by the Krita for fast convolution operators and some G'Mic features") macro_bool_to_01(FFTW3_FOUND HAVE_FFTW3) if (FFTW3_FOUND) list (APPEND ANDROID_EXTRA_LIBS ${FFTW3_LIBRARY}) endif() find_package(OCIO) set_package_properties(OCIO PROPERTIES DESCRIPTION "The OpenColorIO Library" URL "https://www.opencolorio.org" TYPE OPTIONAL PURPOSE "Required by the Krita LUT docker") macro_bool_to_01(OCIO_FOUND HAVE_OCIO) set_package_properties(PythonLibrary PROPERTIES DESCRIPTION "Python Library" URL "https://www.python.org" TYPE OPTIONAL PURPOSE "Required by the Krita PyQt plugin") macro_bool_to_01(PYTHONLIBS_FOUND HAVE_PYTHONLIBS) find_package(SIP "4.19.13") set_package_properties(SIP PROPERTIES DESCRIPTION "Support for generating SIP Python bindings" URL "https://www.riverbankcomputing.com/software/sip/download" TYPE OPTIONAL PURPOSE "Required by the Krita PyQt plugin") macro_bool_to_01(SIP_FOUND HAVE_SIP) find_package(PyQt5 "5.6.0") set_package_properties(PyQt5 PROPERTIES DESCRIPTION "Python bindings for Qt5." URL "https://www.riverbankcomputing.com/software/pyqt/download5" TYPE OPTIONAL PURPOSE "Required by the Krita PyQt plugin") macro_bool_to_01(PYQT5_FOUND HAVE_PYQT5) ## ## Look for OpenGL ## # TODO: see if there is a better check for QtGui being built with opengl support (and thus the QOpenGL* classes) if(Qt5Gui_OPENGL_IMPLEMENTATION) message(STATUS "Found QtGui OpenGL support") else() message(FATAL_ERROR "Did NOT find QtGui OpenGL support. Check your Qt configuration. You cannot build Krita without Qt OpenGL support.") endif() ## ## Test for eigen3 ## find_package(Eigen3 3.0 REQUIRED) set_package_properties(Eigen3 PROPERTIES DESCRIPTION "C++ template library for linear algebra" URL "http://eigen.tuxfamily.org" TYPE REQUIRED) ## ## Test for exiv2 ## find_package(LibExiv2 0.16 REQUIRED) if (ANDROID) list (APPEND ANDROID_EXTRA_LIBS ${LibExiv2_LIBRARIES}) # because libexiv2 depends on libexpat and it is installed in the same folder get_filename_component (_base_dir ${LibExiv2_LIBRARIES} DIRECTORY) list (APPEND ANDROID_EXTRA_LIBS ${_base_dir}/libexpat.so) endif() ## ## Test for lcms ## find_package(LCMS2 2.4 REQUIRED) set_package_properties(LCMS2 PROPERTIES DESCRIPTION "LittleCMS Color management engine" URL "http://www.littlecms.com" TYPE REQUIRED PURPOSE "Will be used for color management and is necessary for Krita") if(LCMS2_FOUND) if(NOT ${LCMS2_VERSION} VERSION_LESS 2040 ) set(HAVE_LCMS24 TRUE) endif() set(HAVE_REQUIRED_LCMS_VERSION TRUE) set(HAVE_LCMS2 TRUE) endif() list (APPEND ANDROID_EXTRA_LIBS ${LCMS2_LIBRARIES}) ## ## Test for Vc ## set(OLD_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules ) set(HAVE_VC FALSE) if (NOT ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") if(NOT MSVC) find_package(Vc 1.1.0) set_package_properties(Vc PROPERTIES DESCRIPTION "Portable, zero-overhead SIMD library for C++" URL "https://github.com/VcDevel/Vc" TYPE OPTIONAL PURPOSE "Required by the Krita for vectorization") macro_bool_to_01(Vc_FOUND HAVE_VC) endif() endif() configure_file(config-vc.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-vc.h ) if(HAVE_VC) message(STATUS "Vc found!") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/vc") include (VcMacros) if(Vc_COMPILER_IS_CLANG) set(ADDITIONAL_VC_FLAGS "-ffp-contract=fast") if(NOT WIN32) set(ADDITIONAL_VC_FLAGS "${ADDITIONAL_VC_FLAGS} -fPIC") endif() elseif (NOT MSVC) set(ADDITIONAL_VC_FLAGS "-fabi-version=0 -ffp-contract=fast") if(NOT WIN32) set(ADDITIONAL_VC_FLAGS "${ADDITIONAL_VC_FLAGS} -fPIC") endif() endif() macro(ko_compile_for_all_implementations_no_scalar _objs _src) vc_compile_for_all_implementations(${_objs} ${_src} FLAGS ${ADDITIONAL_VC_FLAGS} ONLY SSE2 SSSE3 SSE4_1 AVX AVX2+FMA+BMI2) endmacro() macro(ko_compile_for_all_implementations _objs _src) vc_compile_for_all_implementations(${_objs} ${_src} FLAGS ${ADDITIONAL_VC_FLAGS} ONLY Scalar SSE2 SSSE3 SSE4_1 AVX AVX2+FMA+BMI2) endmacro() endif() set(CMAKE_MODULE_PATH ${OLD_CMAKE_MODULE_PATH} ) add_definitions(${QT_DEFINITIONS} ${QT_QTDBUS_DEFINITIONS}) ## ## Test endianness ## include (TestBigEndian) test_big_endian(CMAKE_WORDS_BIGENDIAN) ## ## Test for qt-poppler ## find_package(Poppler COMPONENTS Qt5) set_package_properties(Poppler PROPERTIES DESCRIPTION "A PDF rendering library" URL "https://poppler.freedesktop.org/" TYPE OPTIONAL PURPOSE "Required by the Krita PDF filter.") ## ## Test for quazip ## find_package(QuaZip 0.6) set_package_properties(QuaZip PROPERTIES DESCRIPTION "A library for reading and writing zip files" URL "https://stachenov.github.io/quazip/" TYPE REQUIRED PURPOSE "Needed for reading and writing KRA and ORA files" ) # FIXME: better way to do this? list (APPEND ANDROID_EXTRA_LIBS ${QUAZIP_LIBRARIES} ${EXPAT_LIBRARY} ${KF5_LIBRARIES}/libKF5Completion.so ${KF5_LIBRARIES}/libKF5WindowSystem.so ${KF5_LIBRARIES}/libKF5WidgetsAddons.so ${KF5_LIBRARIES}/libKF5ItemViews.so ${KF5_LIBRARIES}/libKF5ItemModels.so ${KF5_LIBRARIES}/libKF5GuiAddons.so ${KF5_LIBRARIES}/libKF5I18n.so ${KF5_LIBRARIES}/libKF5CoreAddons.so ${KF5_LIBRARIES}/libKF5ConfigGui.so ${KF5_LIBRARIES}/libKF5ConfigCore.so) ## ## Test for Atomics ## include(CheckAtomic) ############################ ############################# ## Add Krita helper macros ## ############################# ############################ include(MacroKritaAddBenchmark) #################### ##################### ## Define includes ## ##################### #################### # for config.h and includes (if any?) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/interfaces ) add_subdirectory(libs) add_subdirectory(plugins) if (BUILD_TESTING) add_subdirectory(benchmarks) endif() add_subdirectory(krita) configure_file(KoConfig.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/KoConfig.h ) configure_file(config_convolution.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_convolution.h) configure_file(config-ocio.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-ocio.h ) check_function_exists(powf HAVE_POWF) configure_file(config-powf.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-powf.h) if(WIN32) include(${CMAKE_CURRENT_LIST_DIR}/packaging/windows/installer/ConfigureInstallerNsis.cmake) endif() message("\nBroken tests:") foreach(tst ${KRITA_BROKEN_TESTS}) message(" * ${tst}") endforeach() feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/po OR EXISTS ${CMAKE_CURRENT_BINARY_DIR}/po ) find_package(KF5I18n CONFIG REQUIRED) ki18n_install(po) endif() if(DEFINED QTANDROID_EXPORTED_TARGET AND NOT TARGET "create-apk") set (_CMAKE_ANDROID_DIR "${ECM_DIR}/../toolchain") list(LENGTH QTANDROID_EXPORTED_TARGET targetsCount) include(${_CMAKE_ANDROID_DIR}/ECMAndroidDeployQt.cmake) math(EXPR last "${targetsCount}-1") foreach(idx RANGE 0 ${last}) list(GET QTANDROID_EXPORTED_TARGET ${idx} exportedTarget) list(GET ANDROID_APK_DIR ${idx} APK_DIR) if(APK_DIR AND NOT EXISTS "${ANDROID_APK_DIR}/AndroidManifest.xml" AND IS_ABSOLUTE ANDROID_APK_DIR) message(FATAL_ERROR "Cannot find ${APK_DIR}/AndroidManifest.xml according to ANDROID_APK_DIR. ${ANDROID_APK_DIR} ${exportedTarget}") elseif(NOT APK_DIR) get_filename_component(_qt5Core_install_prefix "${Qt5Core_DIR}/../../../" ABSOLUTE) set(APK_DIR "${_qt5Core_install_prefix}/src/android/templates/") endif() ecm_androiddeployqt("${exportedTarget}" "${ECM_ADDITIONAL_FIND_ROOT_PATH}") set_target_properties(create-apk-${exportedTarget} PROPERTIES ANDROID_APK_DIR "${APK_DIR}") endforeach() elseif(ANDROID) message(STATUS "You can export a target by specifying -DQTANDROID_EXPORTED_TARGET= and -DANDROID_APK_DIR=") endif() diff --git a/config-updaters.h.cmake b/config-updaters.h.cmake new file mode 100644 index 0000000000..342169abb4 --- /dev/null +++ b/config-updaters.h.cmake @@ -0,0 +1,6 @@ +/* config-updaters.h. Generated by cmake from config-updaters.h.cmake */ + +#cmakedefine ENABLE_UPDATERS 1 + + + diff --git a/krita/CMakeLists.txt b/krita/CMakeLists.txt index 82a00458ea..b0e823ace6 100644 --- a/krita/CMakeLists.txt +++ b/krita/CMakeLists.txt @@ -1,113 +1,113 @@ project(krita) include_directories(SYSTEM ${EIGEN3_INCLUDE_DIR} ${Vc_INCLUDE_DIR} ) add_subdirectory( dtd ) add_subdirectory( data ) add_subdirectory( integration ) # Install the application icons following the freedesktop icon theme spec -add_subdirectory( pics/app ) +add_subdirectory( "pics/branding/${BRANDING}" ) if (ANDROID) include_directories (${Qt5AndroidExtras_INCLUDE_DIRS}) endif() set(krita_SRCS main.cc) # Set the application icon on the application if (NOT APPLE) - file(GLOB ICON_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/pics/app/*-apps-krita.png") + file(GLOB ICON_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/pics/branding/${BRANDING}/*-apps-krita.png") else() - set(ICON_SRCS - "${CMAKE_CURRENT_SOURCE_DIR}/pics/app/16-apps-krita.png" - "${CMAKE_CURRENT_SOURCE_DIR}/pics/app/32-apps-krita.png" - "${CMAKE_CURRENT_SOURCE_DIR}/pics/app/48-apps-krita.png" - "${CMAKE_CURRENT_SOURCE_DIR}/pics/app/128-apps-krita.png" - "${CMAKE_CURRENT_SOURCE_DIR}/pics/app/256-apps-krita.png" - "${CMAKE_CURRENT_SOURCE_DIR}/pics/app/512-apps-krita.png" - "${CMAKE_CURRENT_SOURCE_DIR}/pics/app/1024-apps-krita.png" - ) -endif() + set(ICON_SRCS + "${CMAKE_CURRENT_SOURCE_DIR}/pics/branding/${BRANDING}/16-apps-krita.png" + "${CMAKE_CURRENT_SOURCE_DIR}/pics/branding/${BRANDING}/32-apps-krita.png" + "${CMAKE_CURRENT_SOURCE_DIR}/pics/branding/${BRANDING}/48-apps-krita.png" + "${CMAKE_CURRENT_SOURCE_DIR}/pics/branding/${BRANDING}/128-apps-krita.png" + "${CMAKE_CURRENT_SOURCE_DIR}/pics/branding/${BRANDING}/256-apps-krita.png" + "${CMAKE_CURRENT_SOURCE_DIR}/pics/branding/${BRANDING}/512-apps-krita.png" + "${CMAKE_CURRENT_SOURCE_DIR}/pics/branding/${BRANDING}/1024-apps-krita.png" + ) +endif() ecm_add_app_icon(krita_SRCS ICONS ${ICON_SRCS}) # Install the mimetype icons ecm_install_icons(ICONS "${CMAKE_CURRENT_SOURCE_DIR}/pics/mimetypes/16-mimetypes-application-x-krita.png" "${CMAKE_CURRENT_SOURCE_DIR}/pics/mimetypes/22-mimetypes-application-x-krita.png" "${CMAKE_CURRENT_SOURCE_DIR}/pics/mimetypes/32-mimetypes-application-x-krita.png" "${CMAKE_CURRENT_SOURCE_DIR}/pics/mimetypes/48-mimetypes-application-x-krita.png" "${CMAKE_CURRENT_SOURCE_DIR}/pics/mimetypes/64-mimetypes-application-x-krita.png" "${CMAKE_CURRENT_SOURCE_DIR}/pics/mimetypes/128-mimetypes-application-x-krita.png" "${CMAKE_CURRENT_SOURCE_DIR}/pics/mimetypes/256-mimetypes-application-x-krita.png" "${CMAKE_CURRENT_SOURCE_DIR}/pics/mimetypes/512-mimetypes-application-x-krita.png" "${CMAKE_CURRENT_SOURCE_DIR}/pics/mimetypes/1024-mimetypes-application-x-krita.png" DESTINATION ${KDE_INSTALL_ICONDIR} THEME hicolor) # separate listing, both used by Krita and KritaSketch set(krita_QRCS ${CMAKE_SOURCE_DIR}/krita/krita.qrc ${CMAKE_SOURCE_DIR}/krita/pics/Breeze-dark/breeze-dark-icons.qrc ${CMAKE_SOURCE_DIR}/krita/pics/Breeze-light/breeze-light-icons.qrc ${CMAKE_SOURCE_DIR}/krita/pics/layerbox/layerbox-icons.qrc ${CMAKE_SOURCE_DIR}/krita/pics/layerbox/svg/layerbox-svg-icons.qrc ${CMAKE_SOURCE_DIR}/krita/pics/layers/layers-icons.qrc ${CMAKE_SOURCE_DIR}/krita/pics/misc-light/misc-light-icons.qrc ${CMAKE_SOURCE_DIR}/krita/pics/misc-dark/misc-dark-icons.qrc ${CMAKE_SOURCE_DIR}/krita/pics/paintops/paintops-icons.qrc ${CMAKE_SOURCE_DIR}/krita/pics/tools/SVG/16/tools-svg-16-icons.qrc ${CMAKE_SOURCE_DIR}/krita/pics/tool_transform/tool-transform-icons.qrc ${CMAKE_SOURCE_DIR}/krita/pics/svg/svg-icons.qrc ${CMAKE_SOURCE_DIR}/libs/flake/flake.qrc ${CMAKE_SOURCE_DIR}/libs/widgets/kritawidgets.qrc ${CMAKE_SOURCE_DIR}/pics/icons.qrc ${CMAKE_SOURCE_DIR}/krita/data/aboutdata/aboutdata.qrc ${CMAKE_SOURCE_DIR}/krita/data/shaders/shaders.qrc ${CMAKE_SOURCE_DIR}/krita/data/cursors/cursors.qrc CACHE INTERNAL "krita_QRCS" ) qt5_add_resources(krita_SRCS ${krita_QRCS}) if (ANDROID) add_library(krita SHARED ${krita_SRCS}) target_link_libraries(krita PRIVATE Qt5::AndroidExtras) else() add_executable(krita ${krita_SRCS}) endif() -target_link_libraries(krita +target_link_libraries(krita PRIVATE - kritaui + kritaui Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Xml Qt5::Network Qt5::PrintSupport Qt5::Svg Qt5::Concurrent) if(HAVE_KCRASH) target_link_libraries(krita PRIVATE KF5::Crash) endif() if (APPLE) set_target_properties(krita PROPERTIES INSTALL_RPATH "@loader_path/../../../../lib;@loader_path/../lib;@loader_path/../Frameworks;@executable_path/../lib;@executable_path/../Frameworks") set_target_properties(krita PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.template) set_target_properties(krita PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "org.krita") set_target_properties(krita PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Krita") set_target_properties(krita PROPERTIES MACOSX_BUNDLE_ICON_FILE "krita_SRCS.icns") set_target_properties(krita PROPERTIES MACOSX_BUNDLE_LONG_VERSION_STRING ${KRITA_VERSION_STRING}) set_target_properties(krita PROPERTIES MACOSX_BUNDLE_SHORT_VERSION_STRING ${KRITA_VERSION_STRING}) set_target_properties(krita PROPERTIES MACOSX_BUNDLE_VERSION ${KRITA_VERSION_STRING}) set_target_properties(krita PROPERTIES MACOSX_BUNDLE_COPYRIGHT "GNU Public License, V2 or, at your option, any later version.") endif () install(TARGETS krita ${INSTALL_TARGETS_DEFAULT_ARGS}) install(PROGRAMS org.kde.krita.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) install(FILES krita.action kritamenu.action DESTINATION ${DATA_INSTALL_DIR}/krita/actions) install(FILES org.kde.krita.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR} ) install(DIRECTORY DESTINATION ${DATA_INSTALL_DIR}/krita/shortcuts) diff --git a/krita/pics/Breeze-dark/breeze-dark-icons.qrc b/krita/pics/Breeze-dark/breeze-dark-icons.qrc index 22a8f234aa..092a750743 100644 --- a/krita/pics/Breeze-dark/breeze-dark-icons.qrc +++ b/krita/pics/Breeze-dark/breeze-dark-icons.qrc @@ -1,90 +1,89 @@ - - - + + dark_application-exit.svg dark_application-pdf.svg dark_applications-system.svg dark_arrow-down.svg dark_arrow-downright.svg dark_arrow-downleft.svg dark_arrow-topright.svg dark_arrow-topleft.svg dark_arrow-left.svg dark_arrow-right.svg dark_arrow-up.svg dark_bookmarks.svg dark_applications-system.svg dark_configure.svg dark_configure.svg dark_dialog-cancel.svg dark_window-close.svg dark_dialog-ok.svg dark_dialog-warning.svg dark_document-edit.svg dark_document-export.svg dark_document-import.svg dark_document-new.svg dark_document-open-recent.svg dark_document-open.svg dark_document-print-preview.svg - dark_configure.svg + dark_configure.svg dark_document-save-as.svg dark_document-save.svg dark_download.svg dark_drive-harddisk.svg dark_edit-clear.svg dark_edit-copy.svg dark_edit-cut.svg dark_edit-delete.svg dark_edit-paste.svg dark_edit-redo.svg dark_edit-undo.svg dark_folder-documents.svg dark_folder-pictures.svg dark_folder.svg dark_format-list-unordered.svg dark_go-home.svg dark_arrow-right.svg dark_arrow-left.svg dark_arrow-up.svg dark_system-help.svg dark_im-user.svg dark_kde.svg dark_layer-visible-off.svg dark_link.svg dark_list-add.svg dark_locked.svg dark_media-playback-start.svg dark_media-playback-stop.svg dark_media-record.svg dark_locked.svg dark_object-rotate-left.svg dark_object-rotate-right.svg dark_unlocked.svg dark_preferences-desktop-color.svg dark_preferences-desktop-display.svg dark_preferences-desktop-locale.svg dark_process-stop.svg dark_select-all.svg dark_select-clear.svg dark_system-help.svg dark_tag.svg dark_tools-report-bug.svg dark_tools-wizard.svg dark_unlocked.svg dark_view-choose.svg dark_view-filter.svg dark_view-fullscreen.svg dark_view-grid.svg dark_view-list-details.svg dark_view-list-text.svg dark_view-preview.svg dark_view-refresh.svg dark_window-close.svg dark_window-new.svg dark_zoom-in.svg dark_zoom-original.svg dark_zoom-out.svg + dark_update-medium.svg - diff --git a/krita/pics/Breeze-dark/dark_update-medium.svg b/krita/pics/Breeze-dark/dark_update-medium.svg new file mode 100644 index 0000000000..79abf5579f --- /dev/null +++ b/krita/pics/Breeze-dark/dark_update-medium.svg @@ -0,0 +1,12 @@ + + + + + + + diff --git a/krita/pics/Breeze-light/breeze-light-icons.qrc b/krita/pics/Breeze-light/breeze-light-icons.qrc index a7688a6699..70aabf9864 100644 --- a/krita/pics/Breeze-light/breeze-light-icons.qrc +++ b/krita/pics/Breeze-light/breeze-light-icons.qrc @@ -1,91 +1,91 @@ - - - + + light_application-exit.svg light_application-pdf.svg light_applications-system.svg light_arrow-down.svg light_arrow-downright.svg light_arrow-downleft.svg light_arrow-topright.svg light_arrow-topleft.svg light_arrow-left.svg light_arrow-right.svg light_arrow-up.svg light_bookmarks.svg light_applications-system.svg light_configure.svg light_configure.svg light_dialog-cancel.svg light_window-close.svg light_dialog-ok.svg light_dialog-warning.svg light_document-edit.svg light_document-export.svg light_document-import.svg light_document-new.svg light_document-open-recent.svg light_document-open.svg light_document-print-preview.svg light_document-print.svg - light_configure.svg + light_configure.svg light_document-save-as.svg light_document-save.svg light_download.svg light_drive-harddisk.svg light_edit-clear.svg light_edit-copy.svg light_edit-cut.svg light_edit-delete.svg light_edit-paste.svg light_edit-redo.svg light_edit-undo.svg light_folder-documents.svg light_folder-pictures.svg light_folder.svg light_format-list-unordered.svg light_go-home.svg light_arrow-right.svg light_arrow-left.svg light_arrow-up.svg light_system-help.svg light_im-user.svg light_kde.svg light_layer-visible-off.svg light_link.svg light_list-add.svg light_locked.svg light_media-playback-start.svg light_media-playback-stop.svg light_media-record.svg light_locked.svg light_object-rotate-left.svg light_object-rotate-right.svg light_unlocked.svg light_preferences-desktop-color.svg light_preferences-desktop-display.svg light_preferences-desktop-locale.svg light_process-stop.svg light_select-all.svg light_select-clear.svg light_system-help.svg light_tag.svg light_tools-report-bug.svg light_tools-wizard.svg light_unlocked.svg light_view-choose.svg light_view-filter.svg light_view-fullscreen.svg light_view-grid.svg light_view-list-details.svg light_view-list-text.svg light_view-preview.svg light_view-refresh.svg light_window-close.svg light_window-new.svg light_zoom-in.svg light_zoom-original.svg light_zoom-out.svg - + breeze-light-icons.qrc + light_update-medium.svg + - diff --git a/krita/pics/Breeze-light/light_update-medium.svg b/krita/pics/Breeze-light/light_update-medium.svg new file mode 100644 index 0000000000..fdbe4ed80d --- /dev/null +++ b/krita/pics/Breeze-light/light_update-medium.svg @@ -0,0 +1,12 @@ + + + + + + + diff --git a/krita/pics/app/1024-apps-krita.png b/krita/pics/app/1024-apps-krita.png deleted file mode 100644 index 71dfb0fdb4..0000000000 Binary files a/krita/pics/app/1024-apps-krita.png and /dev/null differ diff --git a/krita/pics/app/128-apps-krita.png b/krita/pics/app/128-apps-krita.png deleted file mode 100644 index cc8ffdc04e..0000000000 Binary files a/krita/pics/app/128-apps-krita.png and /dev/null differ diff --git a/krita/pics/app/16-apps-krita.png b/krita/pics/app/16-apps-krita.png deleted file mode 100644 index 509edbddf3..0000000000 Binary files a/krita/pics/app/16-apps-krita.png and /dev/null differ diff --git a/krita/pics/app/22-apps-krita.png b/krita/pics/app/22-apps-krita.png deleted file mode 100644 index 598b25ac80..0000000000 Binary files a/krita/pics/app/22-apps-krita.png and /dev/null differ diff --git a/krita/pics/app/256-apps-krita.png b/krita/pics/app/256-apps-krita.png deleted file mode 100644 index 8903ce340d..0000000000 Binary files a/krita/pics/app/256-apps-krita.png and /dev/null differ diff --git a/krita/pics/app/32-apps-krita.png b/krita/pics/app/32-apps-krita.png deleted file mode 100644 index 6f0d408bfc..0000000000 Binary files a/krita/pics/app/32-apps-krita.png and /dev/null differ diff --git a/krita/pics/app/48-apps-krita.png b/krita/pics/app/48-apps-krita.png deleted file mode 100644 index 6ca751b520..0000000000 Binary files a/krita/pics/app/48-apps-krita.png and /dev/null differ diff --git a/krita/pics/app/512-apps-krita.png b/krita/pics/app/512-apps-krita.png deleted file mode 100644 index ea31d4c9ad..0000000000 Binary files a/krita/pics/app/512-apps-krita.png and /dev/null differ diff --git a/krita/pics/app/64-apps-krita.png b/krita/pics/app/64-apps-krita.png deleted file mode 100644 index 9b7620f5a0..0000000000 Binary files a/krita/pics/app/64-apps-krita.png and /dev/null differ diff --git a/krita/pics/app/CMakeLists.txt b/krita/pics/app/CMakeLists.txt deleted file mode 100644 index 10d95ebb78..0000000000 --- a/krita/pics/app/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -ecm_install_icons( -ICONS -1024-apps-krita.png -128-apps-krita.png -16-apps-krita.png -22-apps-krita.png -256-apps-krita.png -32-apps-krita.png -48-apps-krita.png -512-apps-krita.png -64-apps-krita.png -sc-apps-krita.svgz -DESTINATION - ${ICON_INSTALL_DIR} ) diff --git a/krita/pics/branding/Beta/1024-apps-krita.png b/krita/pics/branding/Beta/1024-apps-krita.png new file mode 100644 index 0000000000..f48f281997 Binary files /dev/null and b/krita/pics/branding/Beta/1024-apps-krita.png differ diff --git a/krita/pics/branding/Beta/128-apps-krita.png b/krita/pics/branding/Beta/128-apps-krita.png new file mode 100644 index 0000000000..a6c1382331 Binary files /dev/null and b/krita/pics/branding/Beta/128-apps-krita.png differ diff --git a/krita/pics/branding/Beta/16-apps-krita.png b/krita/pics/branding/Beta/16-apps-krita.png new file mode 100644 index 0000000000..56943452d7 Binary files /dev/null and b/krita/pics/branding/Beta/16-apps-krita.png differ diff --git a/krita/pics/branding/Beta/22-apps-krita.png b/krita/pics/branding/Beta/22-apps-krita.png new file mode 100644 index 0000000000..1129da053c Binary files /dev/null and b/krita/pics/branding/Beta/22-apps-krita.png differ diff --git a/krita/pics/branding/Beta/256-apps-krita.png b/krita/pics/branding/Beta/256-apps-krita.png new file mode 100644 index 0000000000..bf7e911e83 Binary files /dev/null and b/krita/pics/branding/Beta/256-apps-krita.png differ diff --git a/krita/pics/branding/Beta/32-apps-krita.png b/krita/pics/branding/Beta/32-apps-krita.png new file mode 100644 index 0000000000..8c6c816c55 Binary files /dev/null and b/krita/pics/branding/Beta/32-apps-krita.png differ diff --git a/krita/pics/branding/Beta/48-apps-krita.png b/krita/pics/branding/Beta/48-apps-krita.png new file mode 100644 index 0000000000..01be689876 Binary files /dev/null and b/krita/pics/branding/Beta/48-apps-krita.png differ diff --git a/krita/pics/branding/Beta/512-apps-krita.png b/krita/pics/branding/Beta/512-apps-krita.png new file mode 100644 index 0000000000..77be7288c3 Binary files /dev/null and b/krita/pics/branding/Beta/512-apps-krita.png differ diff --git a/krita/pics/branding/Beta/64-apps-krita.png b/krita/pics/branding/Beta/64-apps-krita.png new file mode 100644 index 0000000000..7021a56431 Binary files /dev/null and b/krita/pics/branding/Beta/64-apps-krita.png differ diff --git a/krita/pics/branding/Beta/CMakeLists.txt b/krita/pics/branding/Beta/CMakeLists.txt new file mode 100644 index 0000000000..a03ad1a37f --- /dev/null +++ b/krita/pics/branding/Beta/CMakeLists.txt @@ -0,0 +1,14 @@ +ecm_install_icons( +ICONS +1024-apps-krita.png +128-apps-krita.png +16-apps-krita.png +22-apps-krita.png +256-apps-krita.png +32-apps-krita.png +48-apps-krita.png +512-apps-krita.png +64-apps-krita.png +sc-apps-krita.svgz +DESTINATION + ${ICON_INSTALL_DIR} ) diff --git a/krita/pics/branding/Beta/krita.ico b/krita/pics/branding/Beta/krita.ico new file mode 100644 index 0000000000..0c130868ee Binary files /dev/null and b/krita/pics/branding/Beta/krita.ico differ diff --git a/krita/pics/branding/Beta/sc-apps-krita.svgz b/krita/pics/branding/Beta/sc-apps-krita.svgz new file mode 100644 index 0000000000..f27081d728 Binary files /dev/null and b/krita/pics/branding/Beta/sc-apps-krita.svgz differ diff --git a/krita/pics/branding/Next/1024-apps-krita.png b/krita/pics/branding/Next/1024-apps-krita.png new file mode 100644 index 0000000000..d44a922920 Binary files /dev/null and b/krita/pics/branding/Next/1024-apps-krita.png differ diff --git a/krita/pics/branding/Next/128-apps-krita.png b/krita/pics/branding/Next/128-apps-krita.png new file mode 100644 index 0000000000..1d840ba322 Binary files /dev/null and b/krita/pics/branding/Next/128-apps-krita.png differ diff --git a/krita/pics/branding/Next/16-apps-krita.png b/krita/pics/branding/Next/16-apps-krita.png new file mode 100644 index 0000000000..145e86e315 Binary files /dev/null and b/krita/pics/branding/Next/16-apps-krita.png differ diff --git a/krita/pics/branding/Next/22-apps-krita.png b/krita/pics/branding/Next/22-apps-krita.png new file mode 100644 index 0000000000..9a9c02127c Binary files /dev/null and b/krita/pics/branding/Next/22-apps-krita.png differ diff --git a/krita/pics/branding/Next/256-apps-krita.png b/krita/pics/branding/Next/256-apps-krita.png new file mode 100644 index 0000000000..c59d9e3421 Binary files /dev/null and b/krita/pics/branding/Next/256-apps-krita.png differ diff --git a/krita/pics/branding/Next/32-apps-krita.png b/krita/pics/branding/Next/32-apps-krita.png new file mode 100644 index 0000000000..db37bf57be Binary files /dev/null and b/krita/pics/branding/Next/32-apps-krita.png differ diff --git a/krita/pics/branding/Next/48-apps-krita.png b/krita/pics/branding/Next/48-apps-krita.png new file mode 100644 index 0000000000..b169026e6f Binary files /dev/null and b/krita/pics/branding/Next/48-apps-krita.png differ diff --git a/krita/pics/branding/Next/512-apps-krita.png b/krita/pics/branding/Next/512-apps-krita.png new file mode 100644 index 0000000000..99fe06a42f Binary files /dev/null and b/krita/pics/branding/Next/512-apps-krita.png differ diff --git a/krita/pics/branding/Next/64-apps-krita.png b/krita/pics/branding/Next/64-apps-krita.png new file mode 100644 index 0000000000..38405a4088 Binary files /dev/null and b/krita/pics/branding/Next/64-apps-krita.png differ diff --git a/krita/pics/branding/Next/CMakeLists.txt b/krita/pics/branding/Next/CMakeLists.txt new file mode 100644 index 0000000000..a03ad1a37f --- /dev/null +++ b/krita/pics/branding/Next/CMakeLists.txt @@ -0,0 +1,14 @@ +ecm_install_icons( +ICONS +1024-apps-krita.png +128-apps-krita.png +16-apps-krita.png +22-apps-krita.png +256-apps-krita.png +32-apps-krita.png +48-apps-krita.png +512-apps-krita.png +64-apps-krita.png +sc-apps-krita.svgz +DESTINATION + ${ICON_INSTALL_DIR} ) diff --git a/krita/pics/branding/Next/krita.ico b/krita/pics/branding/Next/krita.ico new file mode 100644 index 0000000000..947a195002 Binary files /dev/null and b/krita/pics/branding/Next/krita.ico differ diff --git a/krita/pics/branding/Next/sc-apps-krita.svgz b/krita/pics/branding/Next/sc-apps-krita.svgz new file mode 100644 index 0000000000..6eafca870e Binary files /dev/null and b/krita/pics/branding/Next/sc-apps-krita.svgz differ diff --git a/krita/pics/branding/Plus/1024-apps-krita.png b/krita/pics/branding/Plus/1024-apps-krita.png new file mode 100644 index 0000000000..922656ed65 Binary files /dev/null and b/krita/pics/branding/Plus/1024-apps-krita.png differ diff --git a/krita/pics/branding/Plus/128-apps-krita.png b/krita/pics/branding/Plus/128-apps-krita.png new file mode 100644 index 0000000000..c43f9da3de Binary files /dev/null and b/krita/pics/branding/Plus/128-apps-krita.png differ diff --git a/krita/pics/branding/Plus/16-apps-krita.png b/krita/pics/branding/Plus/16-apps-krita.png new file mode 100644 index 0000000000..800b2cd934 Binary files /dev/null and b/krita/pics/branding/Plus/16-apps-krita.png differ diff --git a/krita/pics/branding/Plus/22-apps-krita.png b/krita/pics/branding/Plus/22-apps-krita.png new file mode 100644 index 0000000000..85014c75ca Binary files /dev/null and b/krita/pics/branding/Plus/22-apps-krita.png differ diff --git a/krita/pics/branding/Plus/256-apps-krita.png b/krita/pics/branding/Plus/256-apps-krita.png new file mode 100644 index 0000000000..766d1bd923 Binary files /dev/null and b/krita/pics/branding/Plus/256-apps-krita.png differ diff --git a/krita/pics/branding/Plus/32-apps-krita.png b/krita/pics/branding/Plus/32-apps-krita.png new file mode 100644 index 0000000000..321da34278 Binary files /dev/null and b/krita/pics/branding/Plus/32-apps-krita.png differ diff --git a/krita/pics/branding/Plus/48-apps-krita.png b/krita/pics/branding/Plus/48-apps-krita.png new file mode 100644 index 0000000000..62db690d85 Binary files /dev/null and b/krita/pics/branding/Plus/48-apps-krita.png differ diff --git a/krita/pics/branding/Plus/512-apps-krita.png b/krita/pics/branding/Plus/512-apps-krita.png new file mode 100644 index 0000000000..08686a4349 Binary files /dev/null and b/krita/pics/branding/Plus/512-apps-krita.png differ diff --git a/krita/pics/branding/Plus/64-apps-krita.png b/krita/pics/branding/Plus/64-apps-krita.png new file mode 100644 index 0000000000..8c67da1afc Binary files /dev/null and b/krita/pics/branding/Plus/64-apps-krita.png differ diff --git a/krita/pics/branding/Plus/CMakeLists.txt b/krita/pics/branding/Plus/CMakeLists.txt new file mode 100644 index 0000000000..a03ad1a37f --- /dev/null +++ b/krita/pics/branding/Plus/CMakeLists.txt @@ -0,0 +1,14 @@ +ecm_install_icons( +ICONS +1024-apps-krita.png +128-apps-krita.png +16-apps-krita.png +22-apps-krita.png +256-apps-krita.png +32-apps-krita.png +48-apps-krita.png +512-apps-krita.png +64-apps-krita.png +sc-apps-krita.svgz +DESTINATION + ${ICON_INSTALL_DIR} ) diff --git a/krita/pics/branding/Plus/krita.ico b/krita/pics/branding/Plus/krita.ico new file mode 100644 index 0000000000..59461dadd1 Binary files /dev/null and b/krita/pics/branding/Plus/krita.ico differ diff --git a/krita/pics/branding/Plus/sc-apps-krita.svgz b/krita/pics/branding/Plus/sc-apps-krita.svgz new file mode 100644 index 0000000000..389e485628 Binary files /dev/null and b/krita/pics/branding/Plus/sc-apps-krita.svgz differ diff --git a/krita/pics/branding/default/1024-apps-krita.png b/krita/pics/branding/default/1024-apps-krita.png new file mode 100644 index 0000000000..16350a5ba8 Binary files /dev/null and b/krita/pics/branding/default/1024-apps-krita.png differ diff --git a/krita/pics/branding/default/128-apps-krita.png b/krita/pics/branding/default/128-apps-krita.png new file mode 100644 index 0000000000..10323c29ba Binary files /dev/null and b/krita/pics/branding/default/128-apps-krita.png differ diff --git a/krita/pics/branding/default/16-apps-krita.png b/krita/pics/branding/default/16-apps-krita.png new file mode 100644 index 0000000000..41d8bff242 Binary files /dev/null and b/krita/pics/branding/default/16-apps-krita.png differ diff --git a/krita/pics/branding/default/22-apps-krita.png b/krita/pics/branding/default/22-apps-krita.png new file mode 100644 index 0000000000..bcdb8c9259 Binary files /dev/null and b/krita/pics/branding/default/22-apps-krita.png differ diff --git a/krita/pics/branding/default/256-apps-krita.png b/krita/pics/branding/default/256-apps-krita.png new file mode 100644 index 0000000000..65b22b034b Binary files /dev/null and b/krita/pics/branding/default/256-apps-krita.png differ diff --git a/krita/pics/branding/default/32-apps-krita.png b/krita/pics/branding/default/32-apps-krita.png new file mode 100644 index 0000000000..de9950ac1d Binary files /dev/null and b/krita/pics/branding/default/32-apps-krita.png differ diff --git a/krita/pics/branding/default/48-apps-krita.png b/krita/pics/branding/default/48-apps-krita.png new file mode 100644 index 0000000000..7b1ca28703 Binary files /dev/null and b/krita/pics/branding/default/48-apps-krita.png differ diff --git a/krita/pics/branding/default/512-apps-krita.png b/krita/pics/branding/default/512-apps-krita.png new file mode 100644 index 0000000000..59b428fd56 Binary files /dev/null and b/krita/pics/branding/default/512-apps-krita.png differ diff --git a/krita/pics/branding/default/64-apps-krita.png b/krita/pics/branding/default/64-apps-krita.png new file mode 100644 index 0000000000..de2724683a Binary files /dev/null and b/krita/pics/branding/default/64-apps-krita.png differ diff --git a/krita/pics/branding/default/CMakeLists.txt b/krita/pics/branding/default/CMakeLists.txt new file mode 100644 index 0000000000..a03ad1a37f --- /dev/null +++ b/krita/pics/branding/default/CMakeLists.txt @@ -0,0 +1,14 @@ +ecm_install_icons( +ICONS +1024-apps-krita.png +128-apps-krita.png +16-apps-krita.png +22-apps-krita.png +256-apps-krita.png +32-apps-krita.png +48-apps-krita.png +512-apps-krita.png +64-apps-krita.png +sc-apps-krita.svgz +DESTINATION + ${ICON_INSTALL_DIR} ) diff --git a/krita/pics/branding/default/krita.ico b/krita/pics/branding/default/krita.ico new file mode 100644 index 0000000000..b4af2104be Binary files /dev/null and b/krita/pics/branding/default/krita.ico differ diff --git a/krita/pics/app/sc-apps-krita.svgz b/krita/pics/branding/default/sc-apps-krita.svgz similarity index 100% rename from krita/pics/app/sc-apps-krita.svgz rename to krita/pics/branding/default/sc-apps-krita.svgz diff --git a/krita/pics/branding/generate_icons.sh b/krita/pics/branding/generate_icons.sh new file mode 100755 index 0000000000..a1a07bd38e --- /dev/null +++ b/krita/pics/branding/generate_icons.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -x + +for dir in $(find ./ -maxdepth 1 -mindepth 1 -type d); do + rm ${dir}/*.png ${dir}/*.ico + + for i in $(echo "16 22 32 48 64 128 256 512 1024"); do + inkscape -z -e ${dir}/${i}-apps-krita.png -w ${i} -h ${i} ${dir}/sc-apps-krita.svgz + #convert ${dir}/sc-apps-krita.svgz -resize "${i}x" ${dir}/${i}-apps-krita.png + done + + convert ${dir}/sc-apps-krita.svgz -alpha off -resize 256x256 \ + -define icon:auto-resize="256,128,96,64,48,32,16" \ + ${dir}/krita.ico +done diff --git a/krita/pics/app/krita.ico b/krita/pics/branding/krita.ico similarity index 100% rename from krita/pics/app/krita.ico rename to krita/pics/branding/krita.ico diff --git a/libs/ui/CMakeLists.txt b/libs/ui/CMakeLists.txt index 4c30c763c1..f0920dedc7 100644 --- a/libs/ui/CMakeLists.txt +++ b/libs/ui/CMakeLists.txt @@ -1,622 +1,645 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/qtlockedfile ) include_directories(SYSTEM ${EIGEN3_INCLUDE_DIR} ${OCIO_INCLUDE_DIR} ) if (ANDROID) add_definitions(-DQT_OPENGL_ES_3) add_definitions(-DHAS_ONLY_OPENGL_ES) include_directories (${Qt5AndroidExtras_INCLUDE_DIRS}) endif() add_subdirectory( tests ) if (APPLE) find_library(FOUNDATION_LIBRARY Foundation) find_library(APPKIT_LIBRARY AppKit) 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_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_config.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 canvas/kis_change_guides_command.cpp canvas/kis_guides_decoration.cpp canvas/kis_guides_manager.cpp canvas/kis_guides_config.cpp canvas/kis_snap_config.cpp canvas/kis_snap_line_strategy.cpp canvas/KisSnapPointStrategy.cpp canvas/KisSnapPixelStrategy.cpp canvas/KisMirrorAxisConfig.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_filter.cpp dialogs/kis_dlg_stroke_selection_properties.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_layer_style.cpp dialogs/kis_dlg_png_import.cpp dialogs/kis_dlg_import_image_sequence.cpp dialogs/kis_delayed_save_dialog.cpp dialogs/KisSessionManagerDialog.cpp dialogs/KisNewWindowLayoutDialog.cpp dialogs/KisDlgChangeCloneSource.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 brushhud/kis_uniform_paintop_property_widget.cpp brushhud/kis_brush_hud.cpp brushhud/kis_round_hud_button.cpp brushhud/kis_dlg_brush_hud_config.cpp brushhud/kis_brush_hud_properties_list.cpp brushhud/kis_brush_hud_properties_config.cpp kis_aspect_ratio_locker.cpp kis_autogradient.cc kis_bookmarked_configurations_editor.cc kis_bookmarked_configurations_model.cc kis_bookmarked_filter_configurations_model.cc KisPaintopPropertiesBase.cpp kis_canvas_resource_provider.cpp kis_derived_resources.cpp kis_categories_mapper.cpp kis_categorized_list_model.cpp kis_categorized_item_delegate.cpp kis_clipboard.cc kis_config.cc KisOcioConfiguration.cpp kis_control_frame.cpp kis_composite_ops_model.cc kis_paint_ops_model.cpp kis_custom_pattern.cc kis_file_layer.cpp kis_change_file_layer_command.h kis_safe_document_loader.cpp kis_splash_screen.cpp kis_filter_manager.cc kis_filters_model.cc KisImageBarrierLockerWithFeedback.cpp 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 KisNodeDisplayModeAdapter.cpp kis_node_model.cpp kis_node_filter_proxy_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 KisDecorationsManager.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 KisResourceServerProvider.cpp KisSelectedShapesProxy.cpp kis_selection_decoration.cc kis_selection_manager.cc KisSelectionActionsAdapter.cpp kis_statusbar.cc kis_zoom_manager.cc kis_favorite_resource_manager.cpp kis_workspace_resource.cpp kis_action.cpp kis_action_manager.cpp KisActionPlugin.cpp kis_canvas_controls_manager.cpp kis_tooltip_manager.cpp kis_multinode_property.cpp kis_stopgradient_editor.cpp KisWelcomePageWidget.cpp KisChangeCloneLayersCommand.cpp kisexiv2/kis_exif_io.cpp kisexiv2/kis_exiv2.cpp kisexiv2/kis_iptc_io.cpp kisexiv2/kis_xmp_io.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_opengl_shader_loader.cpp opengl/kis_texture_tile_info_pool.cpp opengl/KisOpenGLUpdateInfoBuilder.cpp opengl/KisOpenGLModeProber.cpp opengl/KisScreenInformationAdapter.cpp kis_fps_decoration.cpp tool/KisToolChangesTracker.cpp tool/KisToolChangesTrackerData.cpp 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_stabilized_events_sampler.cpp tool/kis_tool_freehand_helper.cpp tool/kis_tool_multihand_helper.cpp tool/kis_figure_painting_tool_helper.cpp tool/KisAsyncronousStrokeUpdateHelper.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/KisStabilizerDelayedPaintHelper.cpp tool/KisStrokeSpeedMonitor.cpp tool/strokes/freehand_stroke.cpp tool/strokes/KisStrokeEfficiencyMeasurer.cpp tool/strokes/kis_painter_based_stroke_strategy.cpp tool/strokes/kis_filter_stroke_strategy.cpp tool/strokes/kis_color_picker_stroke_strategy.cpp tool/strokes/KisFreehandStrokeInfo.cpp tool/strokes/KisMaskedFreehandStrokePainter.cpp tool/strokes/KisMaskingBrushRenderer.cpp tool/strokes/KisMaskingBrushCompositeOpFactory.cpp tool/strokes/move_stroke_strategy.cpp tool/KisSelectionToolFactoryBase.cpp tool/KisToolPaintFactoryBase.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_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_paintop_presets_save.cpp widgets/kis_paintop_preset_icon_library.cpp widgets/kis_pattern_chooser.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/KisSelectionPropertySlider.cpp widgets/kis_size_group.cpp widgets/kis_size_group_p.cpp widgets/kis_wdg_generator.cpp widgets/kis_workspace_chooser.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 widgets/kis_color_label_selector_widget.cpp widgets/kis_color_filter_combo.cpp widgets/kis_elided_label.cpp widgets/kis_stopgradient_slider_widget.cpp widgets/kis_preset_live_preview_view.cpp widgets/KisScreenColorPicker.cpp widgets/KoDualColorButton.cpp widgets/KoStrokeConfigWidget.cpp widgets/KoFillConfigWidget.cpp widgets/KisLayerStyleAngleSelector.cpp widgets/KisMemoryReportButton.cpp widgets/KisDitherWidget.cpp KisPaletteEditor.cpp dialogs/KisDlgPaletteEditor.cpp widgets/KisNewsWidget.cpp widgets/KisGamutMaskToolbar.cpp utils/kis_document_aware_spin_box_unit_manager.cpp utils/KisSpinBoxSplineUnitConverter.cpp utils/KisClipboardUtil.cpp utils/KisDitherUtil.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_native_gesture_shortcut.cpp input/kis_single_action_shortcut.cpp input/kis_stroke_shortcut.cpp input/kis_shortcut_matcher.cpp input/kis_select_layer_action.cpp input/KisQtWidgetsTweaker.cpp input/KisInputActionGroup.cpp input/kis_zoom_and_rotate_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 actions/KisPasteActionFactories.cpp actions/KisTransformToolActivationCommand.cpp input/kis_touch_shortcut.cpp kis_document_undo_store.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 canvas/kis_mirror_axis.cpp kis_abstract_perspective_grid.cpp KisApplication.cpp KisAutoSaveRecoveryDialog.cpp KisDetailsPane.cpp KisDocument.cpp KisCloneDocumentStroke.cpp kis_node_view_color_scheme.cpp KisImportExportFilter.cpp KisImportExportManager.cpp KisImportExportUtils.cpp kis_async_action_feedback.cpp KisMainWindow.cpp KisOpenPane.cpp KisPart.cpp KisPrintJob.cpp KisTemplate.cpp KisTemplateCreateDia.cpp KisTemplateGroup.cpp KisTemplates.cpp KisTemplatesPane.cpp KisTemplateTree.cpp KisUndoActionsUpdateManager.cpp KisView.cpp KisCanvasWindow.cpp KisImportExportErrorCode.cpp KisImportExportAdditionalChecks.cpp thememanager.cpp kis_mainwindow_observer.cpp KisViewManager.cpp kis_mirror_manager.cpp qtlockedfile/qtlockedfile.cpp qtsingleapplication/qtlocalpeer.cpp qtsingleapplication/qtsingleapplication.cpp KisApplicationArguments.cpp KisNetworkAccessManager.cpp + KisRssReader.cpp KisMultiFeedRSSModel.cpp KisRemoteFileFetcher.cpp KisSaveGroupVisitor.cpp KisWindowLayoutResource.cpp KisWindowLayoutManager.cpp KisSessionResource.cpp KisReferenceImagesDecoration.cpp KisReferenceImage.cpp flake/KisReferenceImagesLayer.cpp flake/KisReferenceImagesLayer.h KisMouseClickEater.cpp KisDecorationsWrapperLayer.cpp ) if(WIN32) # Private headers are needed for: # * KisDlgCustomTabletResolution # * KisScreenInformationAdapter include_directories(SYSTEM ${Qt5Gui_PRIVATE_INCLUDE_DIRS}) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} qtlockedfile/qtlockedfile_win.cpp ) if (NOT USE_QT_TABLET_WINDOWS) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} input/wintab/kis_tablet_support_win.cpp input/wintab/kis_screen_size_choice_dialog.cpp input/wintab/kis_tablet_support_win8.cpp ) else() set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} dialogs/KisDlgCustomTabletResolution.cpp ) endif() endif() set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} kis_animation_frame_cache.cpp kis_animation_cache_populator.cpp KisAsyncAnimationRendererBase.cpp KisAsyncAnimationCacheRenderer.cpp KisAsyncAnimationFramesSavingRenderer.cpp dialogs/KisAsyncAnimationRenderDialogBase.cpp dialogs/KisAsyncAnimationCacheRenderDialog.cpp dialogs/KisAsyncAnimationFramesSaveDialog.cpp canvas/kis_animation_player.cpp kis_animation_importer.cpp KisSyncedAudioPlayback.cpp KisFrameDataSerializer.cpp KisFrameCacheStore.cpp KisFrameCacheSwapper.cpp KisAbstractFrameCacheSwapper.cpp KisInMemoryFrameCacheSwapper.cpp input/wintab/drawpile_tablettester/tablettester.cpp input/wintab/drawpile_tablettester/tablettest.cpp ) if (UNIX) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} qtlockedfile/qtlockedfile_unix.cpp ) endif() +if (ENABLE_UPDATERS) + if (UNIX) + set(kritaui_LIB_SRCS + ${kritaui_LIB_SRCS} + utils/KisAppimageUpdater.cpp + ) + endif() + + set(kritaui_LIB_SRCS + ${kritaui_LIB_SRCS} + utils/KisUpdaterBase.cpp + utils/KisManualUpdater.cpp + utils/KisUpdaterStatus.cpp + ) +endif() + + if(APPLE) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} osx.mm ) endif() if (ANDROID) set (kritaui_LIB_SRCS ${kritaui_LIB_SRCS} KisAndroidFileManager.cpp) endif() ki18n_wrap_ui(kritaui_LIB_SRCS widgets/KoFillConfigWidget.ui widgets/KoStrokeConfigWidget.ui widgets/KisDitherWidget.ui forms/wdgdlgpngimport.ui forms/wdgfullscreensettings.ui forms/wdgautogradient.ui forms/wdggeneralsettings.ui forms/wdgperformancesettings.ui forms/wdggenerators.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/wdgmultipliersdoublesliderspinbox.ui forms/wdgnodequerypatheditor.ui forms/wdgpresetselectorstrip.ui forms/wdgsavebrushpreset.ui forms/wdgpreseticonlibrary.ui forms/wdgrectangleconstraints.ui forms/wdgimportimagesequence.ui forms/wdgstrokeselectionproperties.ui forms/KisDetailsPaneBase.ui forms/KisOpenPaneBase.ui forms/wdgstopgradienteditor.ui forms/wdgsessionmanager.ui forms/wdgnewwindowlayout.ui forms/KisWelcomePage.ui forms/WdgDlgPaletteEditor.ui forms/KisNewsPage.ui forms/wdgGamutMaskToolbar.ui forms/wdgchangeclonesource.ui brushhud/kis_dlg_brush_hud_config.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 layerstyles/wdgKisLayerStyleAngleSelector.ui wdgsplash.ui input/wintab/kis_screen_size_choice_dialog.ui input/wintab/drawpile_tablettester/tablettest.ui ) if(WIN32) if(USE_QT_TABLET_WINDOWS) ki18n_wrap_ui(kritaui_LIB_SRCS dialogs/KisDlgCustomTabletResolution.ui ) else() ki18n_wrap_ui(kritaui_LIB_SRCS input/wintab/kis_screen_size_choice_dialog.ui ) endif() endif() 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 - kritaimpex kritacolor kritaimage kritalibbrush kritawidgets kritawidgetutils kritaresources ${PNG_LIBRARIES} LibExiv2::LibExiv2 + kritaversion kritaimpex kritacolor kritaimage kritalibbrush kritawidgets kritawidgetutils kritaresources ${PNG_LIBRARIES} LibExiv2::LibExiv2 ) if (ANDROID) target_link_libraries(kritaui GLESv3) target_link_libraries(kritaui Qt5::Gui) target_link_libraries(kritaui Qt5::AndroidExtras) endif() if (HAVE_QT_MULTIMEDIA) target_link_libraries(kritaui Qt5::Multimedia) endif() if (NOT WIN32 AND NOT APPLE AND NOT ANDROID) target_link_libraries(kritaui ${X11_X11_LIB} ${X11_Xinput_LIB}) endif() if(APPLE) target_link_libraries(kritaui ${FOUNDATION_LIBRARY}) target_link_libraries(kritaui ${APPKIT_LIBRARY}) endif () target_link_libraries(kritaui ${OPENEXR_LIBRARIES}) # Add VSync disable workaround if(NOT WIN32 AND NOT APPLE AND NOT ANDROID) target_link_libraries(kritaui ${CMAKE_DL_LIBS} Qt5::X11Extras) endif() if(X11_FOUND) target_link_libraries(kritaui Qt5::X11Extras ${X11_LIBRARIES}) endif() target_include_directories(kritaui PUBLIC $ $ $ $ $ $ $ ) set_target_properties(kritaui PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritaui ${INSTALL_TARGETS_DEFAULT_ARGS}) if (APPLE) install(FILES osx.stylesheet DESTINATION ${DATA_INSTALL_DIR}/krita) endif () + +if (UNIX AND BUILD_TESTING AND ENABLE_UPDATERS) + install(FILES tests/data/AppImageUpdateDummy + PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE + DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) +endif () diff --git a/libs/ui/KisMultiFeedRSSModel.cpp b/libs/ui/KisMultiFeedRSSModel.cpp index 5bebd6d6e8..5777d1a033 100644 --- a/libs/ui/KisMultiFeedRSSModel.cpp +++ b/libs/ui/KisMultiFeedRSSModel.cpp @@ -1,226 +1,170 @@ /************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** ** GNU Lesser General Public License Usage ** ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this file. ** Please review the following information to ensure the GNU Lesser General ** Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** Other Usage ** ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** **************************************************************************/ #include "KisMultiFeedRSSModel.h" #include #include #include #include #include +#include #include #include #include -QString shortenHtml(QString html) -{ - html.replace(QLatin1String("")); - uint firstParaEndHtml = (uint) html.indexOf(QLatin1String("

"), html.indexOf(QLatin1String("

"))+1); - uint firstParaEndBr = (uint) html.indexOf(QLatin1String("request().url(); - requestUrl = source.toString(); - streamReader.setDevice(reply); - RssItemList list; - while (!streamReader.atEnd()) { - switch (streamReader.readNext()) { - case QXmlStreamReader::StartElement: - if (streamReader.name() == QLatin1String("item")) - list.append(parseItem()); - else if (streamReader.name() == QLatin1String("title")) - blogName = streamReader.readElementText(); - else if (streamReader.name() == QLatin1String("link")) { - if (!streamReader.namespaceUri().isEmpty()) - break; - QString favIconString(streamReader.readElementText()); - QUrl favIconUrl(favIconString); - favIconUrl.setPath(QLatin1String("favicon.ico")); - blogIcon = favIconUrl.toString(); - blogIcon = QString(); // XXX: fix the favicon on krita.org! - } - break; - default: - break; - } - } - return list; - } - -private: - QXmlStreamReader streamReader; - QString requestUrl; - QString blogIcon; - QString blogName; -}; +#include MultiFeedRssModel::MultiFeedRssModel(QObject *parent) : QAbstractListModel(parent), m_networkAccessManager(new KisNetworkAccessManager), m_articleCount(0) { - connect(m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), - SLOT(appendFeedData(QNetworkReply*)), Qt::QueuedConnection); - + initialize(); } +MultiFeedRssModel::MultiFeedRssModel(KisNetworkAccessManager* nam, QObject* parent) + : QAbstractListModel(parent), + m_networkAccessManager(nam), + m_articleCount(0) +{ + initialize(); +} MultiFeedRssModel::~MultiFeedRssModel() { } QHash MultiFeedRssModel::roleNames() const { QHash roleNames; - roleNames[TitleRole] = "title"; - roleNames[DescriptionRole] = "description"; - roleNames[PubDateRole] = "pubDate"; - roleNames[LinkRole] = "link"; - roleNames[CategoryRole] = "category"; - roleNames[BlogNameRole] = "blogName"; - roleNames[BlogIconRole] = "blogIcon"; + roleNames[KisRssReader::RssRoles::TitleRole] = "title"; + roleNames[KisRssReader::RssRoles::DescriptionRole] = "description"; + roleNames[KisRssReader::RssRoles::PubDateRole] = "pubDate"; + roleNames[KisRssReader::RssRoles::LinkRole] = "link"; + roleNames[KisRssReader::RssRoles::CategoryRole] = "category"; + roleNames[KisRssReader::RssRoles::BlogNameRole] = "blogName"; + roleNames[KisRssReader::RssRoles::BlogIconRole] = "blogIcon"; return roleNames; } void MultiFeedRssModel::addFeed(const QString& feed) { + if (m_sites.contains(feed)) { + // do not add the feed twice + return; + } + + m_sites << feed; const QUrl feedUrl(feed); QMetaObject::invokeMethod(m_networkAccessManager, "getUrl", Qt::QueuedConnection, Q_ARG(QUrl, feedUrl)); } bool sortForPubDate(const RssItem& item1, const RssItem& item2) { return item1.pubDate > item2.pubDate; } void MultiFeedRssModel::appendFeedData(QNetworkReply *reply) { - RssReader reader; + KisRssReader reader; m_aggregatedFeed.append(reader.parse(reply)); - std::sort(m_aggregatedFeed.begin(), m_aggregatedFeed.end(), sortForPubDate); + sortAggregatedFeed(); setArticleCount(m_aggregatedFeed.size()); beginResetModel(); endResetModel(); emit feedDataChanged(); } +void MultiFeedRssModel::sortAggregatedFeed() +{ + std::sort(m_aggregatedFeed.begin(), m_aggregatedFeed.end(), sortForPubDate); +} + +void MultiFeedRssModel::initialize() +{ + connect(m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), + SLOT(appendFeedData(QNetworkReply*)), Qt::QueuedConnection); +} + void MultiFeedRssModel::removeFeed(const QString &feed) { QMutableListIterator it(m_aggregatedFeed); while (it.hasNext()) { RssItem item = it.next(); if (item.source == feed) it.remove(); } setArticleCount(m_aggregatedFeed.size()); + + m_sites.removeOne(feed); } int MultiFeedRssModel::rowCount(const QModelIndex &) const { return m_aggregatedFeed.size(); } QVariant MultiFeedRssModel::data(const QModelIndex &index, int role) const { RssItem item = m_aggregatedFeed.at(index.row()); switch (role) { case Qt::DisplayRole: { return QString("" + item.title + "" "
(" + item.pubDate.toLocalTime().toString(Qt::DefaultLocaleShortDate) + ") " + item.description.left(90).append("...") + "


"); } - case TitleRole: + case KisRssReader::RssRoles::TitleRole: return item.title; - case DescriptionRole: + case KisRssReader::RssRoles::DescriptionRole: return item.description; - case PubDateRole: + case KisRssReader::RssRoles::PubDateRole: return item.pubDate.toString("dd-MM-yyyy hh:mm"); - case LinkRole: + case KisRssReader::RssRoles::LinkRole: return item.link; - case CategoryRole: + case KisRssReader::RssRoles::CategoryRole: return item.category; - case BlogNameRole: + case KisRssReader::RssRoles::BlogNameRole: return item.blogName; - case BlogIconRole: + case KisRssReader::RssRoles::BlogIconRole: return item.blogIcon; } return QVariant(); } diff --git a/libs/ui/KisMultiFeedRSSModel.h b/libs/ui/KisMultiFeedRSSModel.h index 7575013244..ff0ca9c18e 100644 --- a/libs/ui/KisMultiFeedRSSModel.h +++ b/libs/ui/KisMultiFeedRSSModel.h @@ -1,108 +1,98 @@ /************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** ** GNU Lesser General Public License Usage ** ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this file. ** Please review the following information to ensure the GNU Lesser General ** Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** Other Usage ** ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** **************************************************************************/ #ifndef MULTIFEEDRSSMODEL_H #define MULTIFEEDRSSMODEL_H #include #include #include +#include + #include -class QThread; + class QNetworkReply; class QNetworkAccessManager; - -struct RssItem { - QString source; - QString title; - QString link; - QString description; - QString category; - QString blogName; - QString blogIcon; - QDateTime pubDate; - -}; -typedef QList RssItemList; - class KisNetworkAccessManager; -enum RssRoles { TitleRole = Qt::UserRole + 1, DescriptionRole, LinkRole, - PubDateRole, CategoryRole, BlogNameRole, BlogIconRole - }; - class KRITAUI_EXPORT MultiFeedRssModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(int articleCount READ articleCount WRITE setArticleCount NOTIFY articleCountChanged) public: explicit MultiFeedRssModel(QObject *parent = 0); + explicit MultiFeedRssModel(KisNetworkAccessManager* nam, QObject *parent = 0); ~MultiFeedRssModel() override; + QHash roleNames() const override; void addFeed(const QString& feed); void removeFeed(const QString& feed); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; int articleCount() const { return m_articleCount; } public Q_SLOTS: void setArticleCount(int arg) { if (m_articleCount != arg) { m_articleCount = arg; emit articleCountChanged(arg); } } Q_SIGNALS: void articleCountChanged(int arg); void feedDataChanged(); private Q_SLOTS: void appendFeedData(QNetworkReply *reply); private: QStringList m_sites; RssItemList m_aggregatedFeed; QNetworkAccessManager *m_networkAccessManager; - QThread *m_namThread; int m_articleCount; + + void sortAggregatedFeed(); + void initialize(); + + friend class MockMultiFeedRssModel; }; #endif // MULTIFEEDRSSMODEL_H diff --git a/libs/ui/KisNetworkAccessManager.cpp b/libs/ui/KisNetworkAccessManager.cpp index e0a6e5f1f2..b85beff69a 100644 --- a/libs/ui/KisNetworkAccessManager.cpp +++ b/libs/ui/KisNetworkAccessManager.cpp @@ -1,51 +1,50 @@ /* * 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 "KisNetworkAccessManager.h" #include #include #include #include -#include KisNetworkAccessManager::KisNetworkAccessManager(QObject *parent) : QNetworkAccessManager(parent) { setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy); } void KisNetworkAccessManager::getUrl(const QUrl &url) { QNetworkRequest req; req.setUrl(url); get(req); } QNetworkReply* KisNetworkAccessManager::createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData) { QString agentStr = QString::fromLatin1("%1/%2 (QNetworkAccessManager %3; %4; %5 bit)") .arg(qApp->applicationName()) .arg(qApp->applicationVersion()) .arg(QSysInfo::prettyProductName()) .arg(QLocale::system().name()) .arg(QSysInfo::WordSize); QNetworkRequest req(request); req.setRawHeader("User-Agent", agentStr.toLatin1()); return QNetworkAccessManager::createRequest(op, req, outgoingData); } diff --git a/libs/ui/KisRssReader.cpp b/libs/ui/KisRssReader.cpp new file mode 100644 index 0000000000..5df0f70f0b --- /dev/null +++ b/libs/ui/KisRssReader.cpp @@ -0,0 +1,134 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "KisRssReader.h" + +#include +#include +#include +#include + +QString shortenHtml(QString html) +{ + html.replace(QLatin1String("")); + uint firstParaEndHtml = (uint) html.indexOf(QLatin1String("

"), html.indexOf(QLatin1String("

"))+1); + uint firstParaEndBr = (uint) html.indexOf(QLatin1String("request().url(); + requestUrl = source.toString(); + m_streamReader.setDevice(reply); + + return parseStream(m_streamReader); +} + +RssItemList KisRssReader::parse(QFile &file) { + requestUrl = file.fileName(); + file.open(QIODevice::ReadOnly); + m_streamReader.setDevice(&file); + + RssItemList itemList(parseStream(m_streamReader)); + + file.close(); + return itemList; +} diff --git a/libs/ui/KisMultiFeedRSSModel.h b/libs/ui/KisRssReader.h similarity index 51% copy from libs/ui/KisMultiFeedRSSModel.h copy to libs/ui/KisRssReader.h index 7575013244..17c1868297 100644 --- a/libs/ui/KisMultiFeedRSSModel.h +++ b/libs/ui/KisRssReader.h @@ -1,108 +1,87 @@ /************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** ** GNU Lesser General Public License Usage ** ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this file. ** Please review the following information to ensure the GNU Lesser General ** Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** Other Usage ** ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** **************************************************************************/ -#ifndef MULTIFEEDRSSMODEL_H -#define MULTIFEEDRSSMODEL_H +#ifndef KISRSSREADER_H +#define KISRSSREADER_H -#include -#include +#include #include +#include +#include +#include #include -class QThread; -class QNetworkReply; -class QNetworkAccessManager; - struct RssItem { QString source; QString title; QString link; QString description; QString category; QString blogName; QString blogIcon; QDateTime pubDate; }; typedef QList RssItemList; -class KisNetworkAccessManager; +Q_DECLARE_METATYPE(RssItem); -enum RssRoles { TitleRole = Qt::UserRole + 1, DescriptionRole, LinkRole, - PubDateRole, CategoryRole, BlogNameRole, BlogIconRole - }; -class KRITAUI_EXPORT MultiFeedRssModel : public QAbstractListModel +class KRITAUI_EXPORT KisRssReader { - Q_OBJECT - Q_PROPERTY(int articleCount READ articleCount WRITE setArticleCount NOTIFY articleCountChanged) public: - explicit MultiFeedRssModel(QObject *parent = 0); - ~MultiFeedRssModel() override; - QHash roleNames() const override; - void addFeed(const QString& feed); - void removeFeed(const QString& feed); - - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - - int articleCount() const { - return m_articleCount; - } - -public Q_SLOTS: - void setArticleCount(int arg) { - if (m_articleCount != arg) { - m_articleCount = arg; - emit articleCountChanged(arg); - } - } - -Q_SIGNALS: - void articleCountChanged(int arg); - void feedDataChanged(); - -private Q_SLOTS: - void appendFeedData(QNetworkReply *reply); + KisRssReader(); + + enum RssRoles { + TitleRole = Qt::UserRole + 1, + DescriptionRole, + LinkRole, + PubDateRole, + CategoryRole, + BlogNameRole, + BlogIconRole + }; + + RssItem parseItem(); + RssItemList parseStream(QXmlStreamReader& streamReader); + RssItemList parse(QNetworkReply *reply); + RssItemList parse(QFile& file); private: - QStringList m_sites; - RssItemList m_aggregatedFeed; - QNetworkAccessManager *m_networkAccessManager; - QThread *m_namThread; - int m_articleCount; + QXmlStreamReader m_streamReader; + QString requestUrl; + QString blogIcon; + QString blogName; }; -#endif // MULTIFEEDRSSMODEL_H - - +#endif // KISRSSREADER_H diff --git a/libs/ui/KisWelcomePageWidget.cpp b/libs/ui/KisWelcomePageWidget.cpp index 652bdb46bf..bb80b6c96f 100644 --- a/libs/ui/KisWelcomePageWidget.cpp +++ b/libs/ui/KisWelcomePageWidget.cpp @@ -1,460 +1,634 @@ /* This file is part of the KDE project * Copyright (C) 2018 Scott Petrovic * * 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 "KisWelcomePageWidget.h" -#include #include #include #include #include #include +#include #include #include "kis_action_manager.h" #include "kactioncollection.h" #include "kis_action.h" #include "KConfigGroup" #include "KSharedConfig" #include #include #include "kis_icon_utils.h" #include "krita_utils.h" #include "KoStore.h" #include "kis_config.h" #include "KisDocument.h" #include #include #include +#include + +#include +#include +#include + +#include "config-updaters.h" + +#ifdef ENABLE_UPDATERS +#ifdef Q_OS_LINUX +#include +#endif + +#include +#endif + +#include +#include + +#include KisWelcomePageWidget::KisWelcomePageWidget(QWidget *parent) : QWidget(parent) { setupUi(this); recentDocumentsListView->setDragEnabled(false); recentDocumentsListView->viewport()->setAutoFillBackground(false); recentDocumentsListView->setSpacing(2); // set up URLs that go to web browser manualLink->setTextFormat(Qt::RichText); manualLink->setTextInteractionFlags(Qt::TextBrowserInteraction); manualLink->setOpenExternalLinks(true); gettingStartedLink->setTextFormat(Qt::RichText); gettingStartedLink->setTextInteractionFlags(Qt::TextBrowserInteraction); gettingStartedLink->setOpenExternalLinks(true); supportKritaLink->setTextFormat(Qt::RichText); supportKritaLink->setTextInteractionFlags(Qt::TextBrowserInteraction); supportKritaLink->setOpenExternalLinks(true); userCommunityLink->setTextFormat(Qt::RichText); userCommunityLink->setTextInteractionFlags(Qt::TextBrowserInteraction); userCommunityLink->setOpenExternalLinks(true); kritaWebsiteLink->setTextFormat(Qt::RichText); kritaWebsiteLink->setTextInteractionFlags(Qt::TextBrowserInteraction); kritaWebsiteLink->setOpenExternalLinks(true); sourceCodeLink->setTextFormat(Qt::RichText); sourceCodeLink->setTextInteractionFlags(Qt::TextBrowserInteraction); sourceCodeLink->setOpenExternalLinks(true); poweredByKDELink->setTextFormat(Qt::RichText); poweredByKDELink->setTextInteractionFlags(Qt::TextBrowserInteraction); poweredByKDELink->setOpenExternalLinks(true); kdeIcon->setIconSize(QSize(20, 20)); kdeIcon->setIcon(KisIconUtils::loadIcon(QStringLiteral("kde")).pixmap(20)); versionNotificationLabel->setTextFormat(Qt::RichText); versionNotificationLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); versionNotificationLabel->setOpenExternalLinks(true); + devBuildIcon->setIcon(KisIconUtils::loadIcon("warning")); + + devBuildLabel->setTextFormat(Qt::RichText); + devBuildLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + devBuildLabel->setOpenExternalLinks(true); + devBuildLabel->setVisible(false); + + updaterFrame->setVisible(false); + versionNotificationLabel->setVisible(false); + bnVersionUpdate->setVisible(false); + bnErrorDetails->setVisible(false); + connect(chkShowNews, SIGNAL(toggled(bool)), newsWidget, SLOT(toggleNews(bool))); - connect(newsWidget, SIGNAL(newsDataChanged()), this, SLOT(slotUpdateVersionMessage())); +#ifdef ENABLE_UPDATERS + connect(chkShowNews, SIGNAL(toggled(bool)), this, SLOT(slotToggleUpdateChecks(bool))); +#endif #ifdef Q_OS_ANDROID // checking this widgets crashes the app, so it is better for it to be hidden for now newsWidget->hide(); helpTitleLabel_2->hide(); chkShowNews->hide(); #endif - // configure the News area KisConfig cfg(true); - bool m_getNews = cfg.readEntry("FetchNews", false); - chkShowNews->setChecked(m_getNews); + m_checkUpdates = cfg.readEntry("FetchNews", false); + + +#ifdef ENABLE_UPDATERS +#ifndef Q_OS_ANDROID + // Setup version updater, but do not check for them, unless the user explicitely + // wants to check for updates. + // * No updater is created for Linux/Steam, Windows/Steam and Windows/Store distributions, + // as those stores have their own updating mechanism. + // * STEAMAPPID(Windows)/SteamAppId(Linux) environment variable is set when Krita is run from Steam. + // The environment variables are not public API. + // * AppxManifest.xml file in the installation directory indicates MS Store version +#if defined Q_OS_LINUX + if (!qEnvironmentVariableIsSet("SteamAppId")) { // do not create updater for linux/steam + if (qEnvironmentVariableIsSet("APPIMAGE")) { + m_versionUpdater.reset(new KisAppimageUpdater()); + } else { + m_versionUpdater.reset(new KisManualUpdater()); + } + } +#elif defined Q_OS_WIN + QString appxManifestFilePath = QString("%1/../AppxManifest.xml").arg(QCoreApplication::applicationDirPath()); + QFileInfo appxManifestFileInfo(appxManifestFilePath); - setAcceptDrops(true); + if (!appxManifestFileInfo.exists() && !qEnvironmentVariableIsSet("STEAMAPPID")) { + m_versionUpdater.reset(new KisManualUpdater()); + KisUsageLogger::log("Non-store package - creating updater"); + } else { + KisUsageLogger::log("detected appx or steam package - not creating the updater"); + } + +#else + // always create updater for MacOS + m_versionUpdater.reset(new KisManualUpdater()); +#endif // Q_OS_* + + if (!m_versionUpdater.isNull()) { + connect(bnVersionUpdate, SIGNAL(clicked()), this, SLOT(slotRunVersionUpdate())); + connect(bnErrorDetails, SIGNAL(clicked()), this, SLOT(slotShowUpdaterErrorDetails())); + connect(m_versionUpdater.data(), SIGNAL(sigUpdateCheckStateChange(KisUpdaterStatus)), + this, SLOT(slotSetUpdateStatus(const KisUpdaterStatus&))); + if (m_checkUpdates) { // only if the user wants them + m_versionUpdater->checkForUpdate(); + } + } +#endif // ifndef Q_OS_ANDROID +#endif // ENABLE_UPDATERS + + chkShowNews->setChecked(m_checkUpdates); + + setAcceptDrops(true); } KisWelcomePageWidget::~KisWelcomePageWidget() { } void KisWelcomePageWidget::setMainWindow(KisMainWindow* mainWin) { if (mainWin) { m_mainWindow = mainWin; // set the shortcut links from actions (only if a shortcut exists) if ( mainWin->viewManager()->actionManager()->actionByName("file_new")->shortcut().toString() != "") { newFileLinkShortcut->setText(QString("(") + mainWin->viewManager()->actionManager()->actionByName("file_new")->shortcut().toString() + QString(")")); } if (mainWin->viewManager()->actionManager()->actionByName("file_open")->shortcut().toString() != "") { openFileShortcut->setText(QString("(") + mainWin->viewManager()->actionManager()->actionByName("file_open")->shortcut().toString() + QString(")")); } connect(recentDocumentsListView, SIGNAL(clicked(QModelIndex)), this, SLOT(recentDocumentClicked(QModelIndex))); // we need the view manager to actually call actions, so don't create the connections // until after the view manager is set connect(newFileLink, SIGNAL(clicked(bool)), this, SLOT(slotNewFileClicked())); connect(openFileLink, SIGNAL(clicked(bool)), this, SLOT(slotOpenFileClicked())); connect(clearRecentFilesLink, SIGNAL(clicked(bool)), mainWin, SLOT(clearRecentFiles())); slotUpdateThemeColors(); // allows RSS news items to apply analytics tracking. newsWidget->setAnalyticsTracking("?" + analyticsString); } } void KisWelcomePageWidget::showDropAreaIndicator(bool show) { if (!show) { QString dropFrameStyle = "QFrame#dropAreaIndicator { border: 0px }"; dropFrameBorder->setStyleSheet(dropFrameStyle); } else { QColor textColor = qApp->palette().color(QPalette::Text); QColor backgroundColor = qApp->palette().color(QPalette::Background); QColor blendedColor = KritaUtils::blendColors(textColor, backgroundColor, 0.8); // QColor.name() turns it into a hex/web format QString dropFrameStyle = QString("QFrame#dropAreaIndicator { border: 2px dotted ").append(blendedColor.name()).append(" }") ; dropFrameBorder->setStyleSheet(dropFrameStyle); } } void KisWelcomePageWidget::slotUpdateThemeColors() { textColor = qApp->palette().color(QPalette::Text); backgroundColor = qApp->palette().color(QPalette::Background); // make the welcome screen labels a subtle color so it doesn't clash with the main UI elements blendedColor = KritaUtils::blendColors(textColor, backgroundColor, 0.8); blendedStyle = QString("color: ").append(blendedColor.name()); // what labels to change the color... startTitleLabel->setStyleSheet(blendedStyle); recentDocumentsLabel->setStyleSheet(blendedStyle); helpTitleLabel->setStyleSheet(blendedStyle); newFileLinkShortcut->setStyleSheet(blendedStyle); openFileShortcut->setStyleSheet(blendedStyle); clearRecentFilesLink->setStyleSheet(blendedStyle); recentDocumentsListView->setStyleSheet(blendedStyle); newFileLink->setStyleSheet(blendedStyle); openFileLink->setStyleSheet(blendedStyle); // giving the drag area messaging a dotted border QString dottedBorderStyle = QString("border: 2px dotted ").append(blendedColor.name()).append("; color:").append(blendedColor.name()).append( ";"); dragImageHereLabel->setStyleSheet(dottedBorderStyle); // make drop area QFrame have a dotted line dropFrameBorder->setObjectName("dropAreaIndicator"); QString dropFrameStyle = QString("QFrame#dropAreaIndicator { border: 4px dotted ").append(blendedColor.name()).append("}"); dropFrameBorder->setStyleSheet(dropFrameStyle); // only show drop area when we have a document over the empty area showDropAreaIndicator(false); // add icons for new and open settings to make them stand out a bit more openFileLink->setIconSize(QSize(30, 30)); newFileLink->setIconSize(QSize(30, 30)); openFileLink->setIcon(KisIconUtils::loadIcon("document-open")); newFileLink->setIcon(KisIconUtils::loadIcon("document-new")); kdeIcon->setIcon(KisIconUtils::loadIcon(QStringLiteral("kde")).pixmap(20)); // HTML links seem to be a bit more stubborn with theme changes... setting inline styles to help with color change userCommunityLink->setText(QString("") .append(i18n("User Community")).append("")); gettingStartedLink->setText(QString("") .append(i18n("Getting Started")).append("")); manualLink->setText(QString("") .append(i18n("User Manual")).append("")); supportKritaLink->setText(QString("") .append(i18n("Support Krita")).append("")); kritaWebsiteLink->setText(QString("") .append(i18n("Krita Website")).append("")); sourceCodeLink->setText(QString("") .append(i18n("Source Code")).append("")); poweredByKDELink->setText(QString("") .append(i18n("Powered by KDE")).append("")); - slotUpdateVersionMessage(); // text set from RSS feed + // show the dev version labels, if dev version is detected + showDevVersionHighlight(); + +#ifdef ENABLE_UPDATERS + updateVersionUpdaterFrame(); // updater frame +#endif // re-populate recent files since they might have themed icons populateRecentDocuments(); } void KisWelcomePageWidget::populateRecentDocuments() { m_recentFilesModel.clear(); // clear existing data before it gets re-populated // grab recent files data int numRecentFiles = m_mainWindow->recentFilesUrls().length() > 5 ? 5 : m_mainWindow->recentFilesUrls().length(); // grab at most 5 for (int i = 0; i < numRecentFiles; i++ ) { QStandardItem *recentItem = new QStandardItem(1,2); // 1 row, 1 column recentItem->setIcon(KisIconUtils::loadIcon("document-export")); QString recentFileUrlPath = m_mainWindow->recentFilesUrls().at(i).toLocalFile(); QString fileName = QFileInfo(recentFileUrlPath).fileName(); QList brokenUrls; if (m_thumbnailMap.contains(recentFileUrlPath)) { recentItem->setIcon(m_thumbnailMap[recentFileUrlPath]); } else { QFileInfo fi(recentFileUrlPath); if (fi.exists()) { QString mimeType = KisMimeDatabase::mimeTypeForFile(recentFileUrlPath); if (mimeType == KisDocument::nativeFormatMimeType() || mimeType == "image/openraster") { QScopedPointer store(KoStore::createStore(recentFileUrlPath, KoStore::Read)); if (store) { QString thumbnailpath; if (store->hasFile(QString("Thumbnails/thumbnail.png"))){ thumbnailpath = QString("Thumbnails/thumbnail.png"); } else if (store->hasFile(QString("preview.png"))) { thumbnailpath = QString("preview.png"); } if (!thumbnailpath.isEmpty()) { if (store->open(thumbnailpath)) { QByteArray bytes = store->read(store->size()); store->close(); QImage img; img.loadFromData(bytes); img.setDevicePixelRatio(devicePixelRatioF()); recentItem->setIcon(QIcon(QPixmap::fromImage(img))); } } } else { brokenUrls << m_mainWindow->recentFilesUrls().at(i); } } else if (mimeType == "image/tiff" || mimeType == "image/x-tiff") { // Workaround for a bug in Qt tiff QImageIO plugin QScopedPointer doc; doc.reset(KisPart::instance()->createTemporaryDocument()); doc->setFileBatchMode(true); bool r = doc->openUrl(QUrl::fromLocalFile(recentFileUrlPath), KisDocument::DontAddToRecent); if (r) { KisPaintDeviceSP projection = doc->image()->projection(); recentItem->setIcon(QIcon(QPixmap::fromImage(projection->createThumbnail(48, 48, projection->exactBounds())))); } else { brokenUrls << m_mainWindow->recentFilesUrls().at(i); } } else { QImage img; img.setDevicePixelRatio(devicePixelRatioF()); img.load(recentFileUrlPath); if (!img.isNull()) { recentItem->setIcon(QIcon(QPixmap::fromImage(img.scaledToWidth(48)))); } else { brokenUrls << m_mainWindow->recentFilesUrls().at(i); } } if (brokenUrls.size() == 0 || brokenUrls.last().toLocalFile() != recentFileUrlPath) { m_thumbnailMap[recentFileUrlPath] = recentItem->icon(); } } } Q_FOREACH(const QUrl &url, brokenUrls) { m_mainWindow->removeRecentUrl(url); } // set the recent object with the data if (brokenUrls.isEmpty() || brokenUrls.last().toLocalFile() != recentFileUrlPath) { recentItem->setText(fileName); // what to display for the item recentItem->setToolTip(recentFileUrlPath); m_recentFilesModel.appendRow(recentItem); } } // hide clear and Recent files title if there are none bool hasRecentFiles = m_mainWindow->recentFilesUrls().length() > 0; recentDocumentsLabel->setVisible(hasRecentFiles); clearRecentFilesLink->setVisible(hasRecentFiles); recentDocumentsListView->setIconSize(QSize(48, 48)); recentDocumentsListView->setModel(&m_recentFilesModel); } -void KisWelcomePageWidget::slotUpdateVersionMessage() -{ - alertIcon->setIcon(KisIconUtils::loadIcon("warning")); - alertIcon->setVisible(false); - - // find out if we need an update...or if this is a development version: - // dev builds contain GIT hash in it and the word git - // stable versions do not contain this. - if (qApp->applicationVersion().contains("git")) { - // Development build - QString versionLabelText = QString("") - .append(i18n("DEV BUILD")).append(""); - - versionNotificationLabel->setText(versionLabelText); - alertIcon->setVisible(true); - versionNotificationLabel->setVisible(true); - - } else if (newsWidget->hasUpdateAvailable()) { - - // build URL for label - QString versionLabelText = QString("versionLink() + "?" + - analyticsString + "version-update" + "\">") - .append(i18n("New Version Available!")).append(""); - - versionNotificationLabel->setVisible(true); - versionNotificationLabel->setText(versionLabelText); - alertIcon->setVisible(true); - - } else { - // no message needed... exit - versionNotificationLabel->setVisible(false); - return; - } - - if (!blendedStyle.isNull()) { - versionNotificationLabel->setStyleSheet(blendedStyle); - } - -} void KisWelcomePageWidget::dragEnterEvent(QDragEnterEvent *event) { //qDebug() << "dragEnterEvent formats" << event->mimeData()->formats() << "urls" << event->mimeData()->urls() << "has images" << event->mimeData()->hasImage(); showDropAreaIndicator(true); if (event->mimeData()->hasUrls() || event->mimeData()->hasFormat("application/x-krita-node") || event->mimeData()->hasFormat("application/x-qt-image")) { event->accept(); } } void KisWelcomePageWidget::dropEvent(QDropEvent *event) { //qDebug() << "KisWelcomePageWidget::dropEvent() formats" << event->mimeData()->formats() << "urls" << event->mimeData()->urls() << "has images" << event->mimeData()->hasImage(); showDropAreaIndicator(false); if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() > 0) { Q_FOREACH (const QUrl &url, event->mimeData()->urls()) { if (url.toLocalFile().endsWith(".bundle")) { bool r = m_mainWindow->installBundle(url.toLocalFile()); if (!r) { qWarning() << "Could not install bundle" << url.toLocalFile(); } } else { m_mainWindow->openDocument(url, KisMainWindow::None); } } } } void KisWelcomePageWidget::dragMoveEvent(QDragMoveEvent *event) { //qDebug() << "dragMoveEvent"; m_mainWindow->dragMoveEvent(event); if (event->mimeData()->hasUrls() || event->mimeData()->hasFormat("application/x-krita-node") || event->mimeData()->hasFormat("application/x-qt-image")) { event->accept(); } } void KisWelcomePageWidget::dragLeaveEvent(QDragLeaveEvent */*event*/) { //qDebug() << "dragLeaveEvent"; showDropAreaIndicator(false); m_mainWindow->dragLeave(); } +void KisWelcomePageWidget::showDevVersionHighlight() +{ + // always flag developement version + if (isDevelopmentBuild()) { + QString devBuildLabelText = QString("") + .append(i18n("DEV BUILD")).append(""); + + devBuildLabel->setText(devBuildLabelText); + devBuildIcon->setVisible(true); + devBuildLabel->setVisible(true); + } else { + devBuildIcon->setVisible(false); + devBuildLabel->setVisible(false); + } +} + void KisWelcomePageWidget::recentDocumentClicked(QModelIndex index) { QString fileUrl = index.data(Qt::ToolTipRole).toString(); m_mainWindow->openDocument(QUrl::fromLocalFile(fileUrl), KisMainWindow::None ); } +bool KisWelcomePageWidget::isDevelopmentBuild() +{ + QString versionString = KritaVersionWrapper::versionString(true); + + if (versionString.contains("git")) { + return true; + } else { + return false; + } +} + void KisWelcomePageWidget::slotNewFileClicked() { m_mainWindow->slotFileNew(); } void KisWelcomePageWidget::slotOpenFileClicked() { m_mainWindow->slotFileOpen(); } +#ifdef ENABLE_UPDATERS +void KisWelcomePageWidget::slotToggleUpdateChecks(bool state) +{ + if (m_versionUpdater.isNull()) { + return; + } + + m_checkUpdates = state; + + if (m_checkUpdates) { + m_versionUpdater->checkForUpdate(); + } + + updateVersionUpdaterFrame(); +} + +void KisWelcomePageWidget::slotRunVersionUpdate() +{ + if (m_versionUpdater.isNull()) { + return; + } + + if (m_checkUpdates) { + m_versionUpdater->doUpdate(); + } +} + +void KisWelcomePageWidget::slotSetUpdateStatus(KisUpdaterStatus updateStatus) +{ + m_updaterStatus = updateStatus; + updateVersionUpdaterFrame(); +} + +void KisWelcomePageWidget::slotShowUpdaterErrorDetails() +{ + QMessageBox::warning(0, i18nc("@title:window", "Krita"), m_updaterStatus.updaterOutput()); +} + +void KisWelcomePageWidget::updateVersionUpdaterFrame() +{ + updaterFrame->setVisible(false); + versionNotificationLabel->setVisible(false); + bnVersionUpdate->setVisible(false); + bnErrorDetails->setVisible(false); + + if (!m_checkUpdates || m_versionUpdater.isNull()) { + return; + } + + QString versionLabelText; + + if (m_updaterStatus.status() == UpdaterStatus::StatusID::UPDATE_AVAILABLE) { + updaterFrame->setVisible(true); + updaterFrame->setEnabled(true); + versionLabelText = i18n("New version of Krita is available."); + versionNotificationLabel->setVisible(true); + updateIcon->setIcon(KisIconUtils::loadIcon("update-medium")); + + if (m_versionUpdater->hasUpdateCapability()) { + bnVersionUpdate->setVisible(true); +// bnVersionUpdate->setEnabled(true); + } else { + // build URL for label + QString downloadLink = QString(" Download Krita %4") + .arg(blendedColor.name()) + .arg(m_updaterStatus.downloadLink()) + .arg(analyticsString + "version-update") + .arg(m_updaterStatus.availableVersion()); + + versionLabelText.append(downloadLink); + } + + } else if ( + (m_updaterStatus.status() == UpdaterStatus::StatusID::UPTODATE) + || (m_updaterStatus.status() == UpdaterStatus::StatusID::CHECK_ERROR) + || (m_updaterStatus.status() == UpdaterStatus::StatusID::IN_PROGRESS) + ){ + // no notifications, if uptodate + // also, stay silent on check error - we do not want to generate lots of user support issues + // because of failing wifis and proxies over the world + updaterFrame->setVisible(false); + + } else if (m_updaterStatus.status() == UpdaterStatus::StatusID::UPDATE_ERROR) { + updaterFrame->setVisible(true); + versionLabelText = i18n("An error occurred during the update"); + versionNotificationLabel->setVisible(true); + bnErrorDetails->setVisible(true); + updateIcon->setIcon(KisIconUtils::loadIcon("warning")); + +// bnErrorDetails->setEnabled(true); + + } else if (m_updaterStatus.status() == UpdaterStatus::StatusID::RESTART_REQUIRED) { + updaterFrame->setVisible(true); + versionLabelText = QString("%1 %2").arg(i18n("Restart is required.")).arg(m_updaterStatus.details()); + versionNotificationLabel->setVisible(true); + updateIcon->setIcon(KisIconUtils::loadIcon("view-refresh")); + } + + versionNotificationLabel->setText(versionLabelText); + if (!blendedStyle.isNull()) { + versionNotificationLabel->setStyleSheet(blendedStyle); + } +} +#endif diff --git a/libs/ui/KisWelcomePageWidget.h b/libs/ui/KisWelcomePageWidget.h index 51a4fafa62..1e29394dfc 100644 --- a/libs/ui/KisWelcomePageWidget.h +++ b/libs/ui/KisWelcomePageWidget.h @@ -1,93 +1,117 @@ /* This file is part of the KDE project * Copyright (C) 2018 Scott Petrovic * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KISWELCOMEPAGEWIDGET_H #define KISWELCOMEPAGEWIDGET_H #include "kritaui_export.h" #include "KisViewManager.h" #include "KisMainWindow.h" +#include #include #include "ui_KisWelcomePage.h" #include +#include + +#include "config-updaters.h" /// A widget for displaying if no documents are open. This will display in the MDI area class KRITAUI_EXPORT KisWelcomePageWidget : public QWidget, public Ui::KisWelcomePage { Q_OBJECT public: explicit KisWelcomePageWidget(QWidget *parent); ~KisWelcomePageWidget() override; void setMainWindow(KisMainWindow* m_mainWindow); public Q_SLOTS: /// if a document is placed over this area, a dotted line will appear as an indicator /// that it is a droppable area. KisMainwindow is what triggers this void showDropAreaIndicator(bool show); void slotUpdateThemeColors(); /// this could be called multiple times. If a recent document doesn't /// have a preview, an icon is used that needs to be updated void populateRecentDocuments(); - void slotUpdateVersionMessage(); +#ifdef ENABLE_UPDATERS + void slotSetUpdateStatus(KisUpdaterStatus updateStatus); + void slotShowUpdaterErrorDetails(); +#endif protected: // QWidget overrides void dragEnterEvent(QDragEnterEvent * event) override; void dropEvent(QDropEvent * event) override; void dragMoveEvent(QDragMoveEvent * event) override; void dragLeaveEvent(QDragLeaveEvent * event) override; private: + void showDevVersionHighlight(); + +#ifdef ENABLE_UPDATERS + void updateVersionUpdaterFrame(); +#endif + KisMainWindow *m_mainWindow; QStandardItemModel m_recentFilesModel; QMap m_thumbnailMap; /// help us see how many people are clicking startup screen links /// you can see the results in Matomo (stats.kde.org) /// this will be listed in the "Acquisition" section of Matomo /// just append some text to this to associate it with an event/page const QString analyticsString = "pk_campaign=startup-sceen&pk_kwd="; // keeping track of link colors with theme change QColor textColor; QColor backgroundColor; QColor blendedColor; QString blendedStyle; - +#ifdef ENABLE_UPDATERS + QScopedPointer m_versionUpdater; + KisUpdaterStatus m_updaterStatus; +#endif + bool m_checkUpdates {false}; private Q_SLOTS: void slotNewFileClicked(); void slotOpenFileClicked(); void recentDocumentClicked(QModelIndex index); + +#ifdef ENABLE_UPDATERS + void slotRunVersionUpdate(); + void slotToggleUpdateChecks(bool state); +#endif + + bool isDevelopmentBuild(); }; #endif // KISWELCOMEPAGEWIDGET_H diff --git a/libs/ui/forms/KisWelcomePage.ui b/libs/ui/forms/KisWelcomePage.ui index 16ea785892..3cadb26c80 100644 --- a/libs/ui/forms/KisWelcomePage.ui +++ b/libs/ui/forms/KisWelcomePage.ui @@ -1,851 +1,992 @@ KisWelcomePage 0 0 - 788 - 476 + 1118 + 593 0 0 false QFrame::Box QFrame::Plain 4 0 - + + + + Qt::Vertical + + + + 5 + 5 + + + + + 5 0 0 30 0 18 Community 0 0 true User Manual Qt::Horizontal QSizePolicy::Expanding 40 5 0 true Getting Started Qt::Horizontal 40 5 true Support Krita Qt::Horizontal 40 20 true User Community Qt::Horizontal 40 20 true Krita Website Qt::Horizontal 40 20 0 0 true Source Code Qt::Horizontal 40 20 20 20 20 20 20 true true Powered by KDE Qt::Horizontal 40 20 0 0 QFrame::Box 2 Drag Image in window to open Qt::AlignCenter true 30 Qt::Horizontal 40 20 Qt::Vertical 20 20 - - - - Qt::Horizontal - - - - 5 - 5 - - - - - + Qt::Vertical 5 5 - - - - Qt::Vertical - - - - 5 - 5 - - - - - - - - Qt::Horizontal - - - - 5 - 5 - - - - - + 5 0 20 0 0 70 0 18 Start - + 0 0 16 16 16 16 true - - - - 0 - 0 - - - - - true - - + - Krita X.X.X Update Available - - - 2 - - - false + DEV BUILD Qt::Horizontal 40 20 0 true Qt::NoFocus New File false true 20 0 false Qt::Horizontal 40 20 0 30 true Qt::NoFocus Open File false true 20 0 false Qt::Horizontal 40 20 18 Recent Documents 0 0 true Qt::NoFocus Clear false true Qt::Horizontal 5 20 0 0 300 250 true false Qt::NoFocus false QFrame::NoFrame QFrame::Plain 0 false false QAbstractItemView::SelectItems QListView::Snap QListView::Fixed 0 QListView::ListMode true false Qt::Vertical 5 5 - + + + + Qt::Horizontal + + + + 5 + 5 + + + + + + + + Qt::Horizontal + + + + 5 + 5 + + + + + 0 0 18 News 0 true 0 0 Show news about Krita: this needs internet to retrieve information from the krita.org website Check for updates - + + + false + + + + 0 + 0 + + + + + 16777215 + 200 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + true + + + + 0 + 0 + + + + + 32 + 32 + + + + + 50 + 50 + + + + + + + + 32 + 32 + + + + true + + + + + + + false + + + + 0 + 0 + + + + + false + + + + Krita Version X.X.X Available + + + false + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + 2 + + + false + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 50 + 20 + + + + + + + + Update now! + + + + + + + Show details + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + 0 + 0 + + + KisNewsWidget QWidget

widgets/KisNewsWidget.h
1 diff --git a/libs/ui/tests/CMakeLists.txt b/libs/ui/tests/CMakeLists.txt index 215bfaeea9..c5cd5d132e 100644 --- a/libs/ui/tests/CMakeLists.txt +++ b/libs/ui/tests/CMakeLists.txt @@ -1,169 +1,191 @@ set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) include_directories(${CMAKE_SOURCE_DIR}/libs/image/metadata ${CMAKE_SOURCE_DIR}/sdk/tests ) include(ECMAddTests) macro_add_unittest_definitions() ecm_add_tests( kis_image_view_converter_test.cpp kis_shape_selection_test.cpp kis_doc2_test.cpp kis_coordinates_converter_test.cpp kis_grid_config_test.cpp kis_stabilized_events_sampler_test.cpp kis_brush_hud_properties_config_test.cpp kis_shape_commands_test.cpp kis_stop_gradient_editor_test.cpp kis_file_layer_test.cpp kis_multinode_property_test.cpp KisFrameSerializerTest.cpp KisFrameCacheStoreTest.cpp kis_animation_exporter_test.cpp kis_prescaled_projection_test.cpp kis_animation_importer_test.cpp KisSpinBoxSplineUnitConverterTest.cpp KisDocumentReplaceTest.cpp + KisRssReaderTest.cpp LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-" ) +if (ENABLE_UPDATERS) +if (UNIX) + ecm_add_test( KisAppimageUpdaterTest.cpp + TEST_NAME KisAppimageUpdaterTest + LINK_LIBRARIES kritaui Qt5::Test + NAME_PREFIX "libs-ui-") +endif() + +ecm_add_test( KisManualUpdaterTest.cpp ../../../sdk/tests/testutil.cpp MockMultiFeedRssModel.cpp + TEST_NAME KisManualUpdaterTest + LINK_LIBRARIES kritaui Qt5::Test + NAME_PREFIX "libs-ui-") +endif() + + +ecm_add_test( KisMultiFeedRssModelTest.cpp ../../../sdk/tests/testutil.cpp MockNetworkAccessManager.cpp + TEST_NAME KisMultiFeedRssModelTest + LINK_LIBRARIES kritaui Qt5::Test + NAME_PREFIX "libs-ui-") + + ecm_add_test( kis_selection_decoration_test.cpp ../../../sdk/tests/stroke_testing_utils.cpp TEST_NAME KisSelectionDecorationTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") ecm_add_test( kis_node_dummies_graph_test.cpp ../../../sdk/tests/testutil.cpp TEST_NAME KisNodeDummiesGraphTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") ecm_add_test( kis_node_shapes_graph_test.cpp ../../../sdk/tests/testutil.cpp TEST_NAME KisNodeShapesGraphTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") ecm_add_test( kis_model_index_converter_test.cpp ../../../sdk/tests/testutil.cpp TEST_NAME KisModelIndexConverterTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") ecm_add_test( kis_categorized_list_model_test.cpp modeltest.cpp TEST_NAME KisCategorizedListModelTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") ecm_add_test( kis_node_juggler_compressed_test.cpp ../../../sdk/tests/testutil.cpp TEST_NAME KisNodeJugglerCompressedTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") ecm_add_test( kis_input_manager_test.cpp ../../../sdk/tests/testutil.cpp TEST_NAME KisInputManagerTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") ecm_add_test( kis_node_model_test.cpp modeltest.cpp TEST_NAME kis_node_model_test LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") ##### Tests that currently fail and should be fixed ##### include(KritaAddBrokenUnitTest) krita_add_broken_unit_test( kis_shape_controller_test.cpp kis_dummies_facade_base_test.cpp TEST_NAME kis_shape_controller_test LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") krita_add_broken_unit_test( kis_exiv2_test.cpp TEST_NAME KisExiv2Test LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") krita_add_broken_unit_test( kis_clipboard_test.cpp TEST_NAME KisClipboardTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") krita_add_broken_unit_test( freehand_stroke_test.cpp ${CMAKE_SOURCE_DIR}/sdk/tests/stroke_testing_utils.cpp TEST_NAME FreehandStrokeTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") krita_add_broken_unit_test( FreehandStrokeBenchmark.cpp ${CMAKE_SOURCE_DIR}/sdk/tests/stroke_testing_utils.cpp TEST_NAME FreehandStrokeBenchmark LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") krita_add_broken_unit_test( KisPaintOnTransparencyMaskTest.cpp ${CMAKE_SOURCE_DIR}/sdk/tests/stroke_testing_utils.cpp TEST_NAME KisPaintOnTransparencyMaskTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") krita_add_broken_unit_test( fill_processing_visitor_test.cpp ${CMAKE_SOURCE_DIR}/sdk/tests/stroke_testing_utils.cpp TEST_NAME FillProcessingVisitorTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") krita_add_broken_unit_test( filter_stroke_test.cpp ../../../sdk/tests/stroke_testing_utils.cpp TEST_NAME FilterStrokeTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") krita_add_broken_unit_test( kis_selection_manager_test.cpp TEST_NAME KisSelectionManagerTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") #set_tests_properties(libs-ui-KisSelectionManagerTest PROPERTIES TIMEOUT 300) krita_add_broken_unit_test( kis_node_manager_test.cpp TEST_NAME KisNodeManagerTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") krita_add_broken_unit_test( kis_dummies_facade_test.cpp kis_dummies_facade_base_test.cpp ../../../sdk/tests/testutil.cpp TEST_NAME KisDummiesFacadeTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") krita_add_broken_unit_test( kis_zoom_and_pan_test.cpp ../../../sdk/tests/testutil.cpp TEST_NAME KisZoomAndPanTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") #set_tests_properties(libs-ui-KisZoomAndPanTest PROPERTIES TIMEOUT 300) krita_add_broken_unit_test( kis_action_manager_test.cpp TEST_NAME KisActionManagerTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") krita_add_broken_unit_test( kis_categories_mapper_test.cpp testing_categories_mapper.cpp TEST_NAME KisCategoriesMapperTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") krita_add_broken_unit_test( kis_animation_frame_cache_test.cpp TEST_NAME kis_animation_frame_cache_test LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") krita_add_broken_unit_test( kis_derived_resources_test.cpp TEST_NAME kis_derived_resources_test LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") krita_add_broken_unit_test( kis_shape_layer_test.cpp TEST_NAME KisShapeLayerTest LINK_LIBRARIES kritaui Qt5::Test NAME_PREFIX "libs-ui-") diff --git a/libs/ui/tests/KisAppimageUpdaterTest.cpp b/libs/ui/tests/KisAppimageUpdaterTest.cpp new file mode 100644 index 0000000000..1bdb3197bb --- /dev/null +++ b/libs/ui/tests/KisAppimageUpdaterTest.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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 "KisAppimageUpdaterTest.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +KisAppimageUpdaterTest::KisAppimageUpdaterTest(QObject *parent) : QObject(parent) +{ + +} + +void KisAppimageUpdaterTest::testCheckForUpdate() +{ + QFETCH(QString, controlValue); + QFETCH(UpdaterStatus::StatusID, resultStatus); + + QString updaterDummyPath = QString("%1%2/AppImageUpdateDummy") + .arg(QString(FILES_DATA_DIR)) + .arg(QDir::separator()); + + + qputenv("APPIMAGEUPDATE_DUMMY_STATE", controlValue.toLocal8Bit()); + + QScopedPointer updater(new KisAppimageUpdater(updaterDummyPath)); + + QSignalSpy spy(updater.data(), SIGNAL(sigUpdateCheckStateChange(KisUpdaterStatus))); + + QVERIFY(spy.isValid()); + + updater->checkForUpdate(); + + QTest::qWait(1000); + + QList arguments = spy.takeFirst(); + KisUpdaterStatus firstStatus = arguments.at(0).value(); + + QCOMPARE(firstStatus.status(), UpdaterStatus::StatusID::IN_PROGRESS); + + arguments = spy.takeFirst(); + KisUpdaterStatus secondStatus = arguments.at(0).value(); + + QCOMPARE(secondStatus.status(), resultStatus); +} + +void KisAppimageUpdaterTest::testCheckForUpdate_data() +{ + QTest::addColumn("controlValue"); + QTest::addColumn("resultStatus"); + + QTest::addRow("uptodate") + << QString("check_uptodate") + << UpdaterStatus::StatusID::UPTODATE; + + QTest::addRow("update available") + << QString("check_update_avail") + << UpdaterStatus::StatusID::UPDATE_AVAILABLE; + + QTest::addRow("error") + << QString("check_error") + << UpdaterStatus::StatusID::CHECK_ERROR; + + QTest::addRow("empty update info") + << QString("check_updinfo_empty") + << UpdaterStatus::StatusID::CHECK_ERROR; +} + +void KisAppimageUpdaterTest::testDoUpdate() +{ + QFETCH(QString, controlValue); + QFETCH(UpdaterStatus::StatusID, resultStatus); + + QString updaterDummyPath = QString("%1%2/AppImageUpdateDummy") + .arg(QString(FILES_DATA_DIR)) + .arg(QDir::separator()); + + + qputenv("APPIMAGEUPDATE_DUMMY_STATE", controlValue.toLocal8Bit()); + + QScopedPointer updater(new KisAppimageUpdater(updaterDummyPath)); + + QSignalSpy spy(updater.data(), SIGNAL(sigUpdateCheckStateChange(KisUpdaterStatus))); + + QVERIFY(spy.isValid()); + + updater->doUpdate(); + + QTest::qWait(1000); + + QList arguments = spy.takeFirst(); + KisUpdaterStatus secondStatus = arguments.at(0).value(); + + QCOMPARE(secondStatus.status(), resultStatus); + + // for error also check for output + if (secondStatus.status() == UpdaterStatus::StatusID::UPDATE_ERROR) { + QCOMPARE(secondStatus.updaterOutput(), QString("DUMMY: an error occured\n")); + } +} + +void KisAppimageUpdaterTest::testDoUpdate_data() +{ + QTest::addColumn("controlValue"); + QTest::addColumn("resultStatus"); + + QTest::addRow("update ok") + << QString("update_ok") + << UpdaterStatus::StatusID::RESTART_REQUIRED; + + QTest::addRow("error") + << QString("update_error") + << UpdaterStatus::StatusID::UPDATE_ERROR; + + QTest::addRow("runtime error") + << QString("runtime_error") + << UpdaterStatus::StatusID::UPDATE_ERROR; +} + +QTEST_MAIN(KisAppimageUpdaterTest); diff --git a/libs/ui/tests/KisAppimageUpdaterTest.h b/libs/ui/tests/KisAppimageUpdaterTest.h new file mode 100644 index 0000000000..e850d2f099 --- /dev/null +++ b/libs/ui/tests/KisAppimageUpdaterTest.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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. + */ + +#ifndef KISAPPIMAGEUPDATERTEST_H +#define KISAPPIMAGEUPDATERTEST_H + +#include + +class KisAppimageUpdaterTest : public QObject +{ + Q_OBJECT +public: + explicit KisAppimageUpdaterTest(QObject *parent = nullptr); + +private Q_SLOTS: + void testCheckForUpdate(); + void testCheckForUpdate_data(); + void testDoUpdate(); + void testDoUpdate_data(); +}; + +#endif // KISAPPIMAGEUPDATERTEST_H diff --git a/libs/ui/tests/KisManualUpdaterTest.cpp b/libs/ui/tests/KisManualUpdaterTest.cpp new file mode 100644 index 0000000000..aca329a258 --- /dev/null +++ b/libs/ui/tests/KisManualUpdaterTest.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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 "KisManualUpdaterTest.h" + +#include +#include +#include +#include +#include + +KisManualUpdaterTest::KisManualUpdaterTest(QObject *parent) : QObject(parent) +{ + +} + +void KisManualUpdaterTest::testAvailableVersionIsHigher() +{ + QFETCH(QString, currentVersion); + QFETCH(QString, availableVersion); + QFETCH(bool, expectedReturnValue); + + QScopedPointer updater(new KisManualUpdater()); + bool actualReturnValue = updater->availableVersionIsHigher(currentVersion, availableVersion); + QCOMPARE(actualReturnValue, expectedReturnValue); +} + +void KisManualUpdaterTest::testAvailableVersionIsHigher_data() +{ + QTest::addColumn("currentVersion"); + QTest::addColumn("availableVersion"); + QTest::addColumn("expectedReturnValue"); + + QTest::addRow("equal") << "4.2.5" << "4.2.5" << false; + + QTest::addRow("higher major") << "3.0.0" << "4.2.5" << true; + QTest::addRow("higher minor") << "4.2.4" << "4.3.4" << true; + QTest::addRow("higher rev") << "4.2.4" << "4.2.5" << true; + + QTest::addRow("lower major") << "4.2.5" << "3.2.5" << false; + QTest::addRow("lower minor") << "4.2.5" << "4.1.5" << false; + QTest::addRow("lower rev") << "4.2.5" << "4.2.4" << false; + + QTest::addRow("current is git, available lower stable") << "4.3.0-d8ea4b" << "4.2.5" << false; + QTest::addRow("current is beta, available lower stable") << "4.2.6-beta1" << "4.2.5" << false; + + QTest::addRow("current is git, available higher stable") << "4.3.0-d8ea4b" << "4.4.2" << true; + QTest::addRow("current is beta, available lower stable") << "4.2.6-beta1" << "4.3.1" << true; + + QTest::addRow("current is git, available equal version release") << "4.3.0-d8ea4b" << "4.3.0" << true; + QTest::addRow("current is beta, available equal version release") << "4.2.6-beta1" << "4.2.6" << true; + + QTest::addRow("available is git, current equal version release") << "4.3.0" << "4.3.0-d8ea4b" << false; + QTest::addRow("available is beta, current equal version release") << "4.2.6" << "4.2.6-beta1" << false; + +// this is not solved in the function, as it is unlikely to have such versions in the RSS feed +// QTest::addRow("current is git, available equal version beta") << "4.3.0-d8ea4b" << "4.3.0-beta1" << true; + // QTest::addRow("available is beta, current equal version git") << "4.2.6-beta1" << "4.2.6-d8ea4b" << false; + + QTest::addRow("current is empty") << QString() << "4.2.5" << false; + QTest::addRow("available is empty") << "4.2.6" << QString() << false; +} + +void KisManualUpdaterTest::testCheckForUpdate() +{ + QFETCH(RssItemList, feed); + QFETCH(QString, currentVersion); + QFETCH(QString, availableVersion); + QFETCH(QString, downloadLink); + QFETCH(UpdaterStatus::StatusID, resultStatus); + + MockMultiFeedRssModel* mockRssModel(new MockMultiFeedRssModel()); + mockRssModel->loadFeedData(feed); + + QScopedPointer updater(new KisManualUpdater(mockRssModel, currentVersion)); + + QSignalSpy spy(updater.data(), SIGNAL(sigUpdateCheckStateChange(KisUpdaterStatus))); + + QVERIFY(spy.isValid()); + + updater->checkForUpdate(); + + QTest::qWait(1000); + + QList arguments = spy.takeFirst(); + KisUpdaterStatus updaterStatus = arguments.at(0).value(); + + QCOMPARE(updaterStatus.status(), resultStatus); + QCOMPARE(updaterStatus.availableVersion(), availableVersion); + QCOMPARE(updaterStatus.downloadLink(), downloadLink); +} + +void KisManualUpdaterTest::testCheckForUpdate_data() +{ + QTest::addColumn("feed"); + QTest::addColumn("currentVersion"); + QTest::addColumn("availableVersion"); + QTest::addColumn("downloadLink"); + QTest::addColumn("resultStatus"); + + RssItem item1 = RssItem(); + item1.title = "Krita 4.3.0 Released"; + item1.link = "https://krita.org/en/item/krita-4-3-0/"; + item1.category = "Official Release"; + item1.pubDate = QDateTime::fromString(QString("Wed, 10 Sep 2019 09:42:15 +0000"), Qt::RFC2822Date); + + RssItem item2 = RssItem(); + item2.title = "Krita 4.2.4 Released"; + item2.link = "https://krita.org/en/item/krita-4-2-4/"; + item2.category = "Official Release"; + item2.pubDate = QDateTime::fromString(QString("Wed, 10 Sep 2018 09:42:15 +0000"), Qt::RFC2822Date); + + RssItem item3 = RssItem(); + item3.title = "Interview with The Artist"; + item3.link = "https://krita.org/en/item/interview-with-the-artist/"; + item3.category = "Artist Interview"; + item3.pubDate = QDateTime::fromString(QString("Wed, 15 Sep 2019 09:42:15 +0000"), Qt::RFC2822Date); + + + RssItemList feed = RssItemList() << item1 << item2 << item3; + + QTest::addRow("uptodate") + << feed + << QString("4.3.0") + << QString("4.3.0") + << QString("https://krita.org/en/item/krita-4-3-0/") + << UpdaterStatus::StatusID::UPTODATE; + + QTest::addRow("update available") + << feed + << QString("4.2.4") + << QString("4.3.0") + << QString("https://krita.org/en/item/krita-4-3-0/") + << UpdaterStatus::StatusID::UPDATE_AVAILABLE; +} + +QTEST_MAIN(KisManualUpdaterTest); diff --git a/libs/ui/tests/KisManualUpdaterTest.h b/libs/ui/tests/KisManualUpdaterTest.h new file mode 100644 index 0000000000..e3febaeea4 --- /dev/null +++ b/libs/ui/tests/KisManualUpdaterTest.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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. + */ + + +#ifndef KISMANUALUPDATERTEST_H +#define KISMANUALUPDATERTEST_H + +#include + +class KisManualUpdaterTest : public QObject +{ + Q_OBJECT +public: + explicit KisManualUpdaterTest(QObject *parent = nullptr); + +private Q_SLOTS: + void testAvailableVersionIsHigher(); + void testAvailableVersionIsHigher_data(); + + void testCheckForUpdate(); + void testCheckForUpdate_data(); +}; + +#endif // KISMANUALUPDATERTEST_H diff --git a/libs/ui/tests/KisMultiFeedRssModelTest.cpp b/libs/ui/tests/KisMultiFeedRssModelTest.cpp new file mode 100644 index 0000000000..5aa7b4cec0 --- /dev/null +++ b/libs/ui/tests/KisMultiFeedRssModelTest.cpp @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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 "KisMultiFeedRssModelTest.h" + +#include +#include + +#include +#include +#include + + +KisMultiFeedRssModelTest::KisMultiFeedRssModelTest(QObject *parent) : QObject(parent) +{ + +} + +void KisMultiFeedRssModelTest::testAddFeed() +{ + QFETCH(QList, replyDataList); + QFETCH(int, resultArticleCount); + + + MockNetworkAccessManager* nam(new MockNetworkAccessManager()); + + QStringList feedList; + for(FakeReplyData& replyData: replyDataList) { + feedList << replyData.url.toString(); + nam->setReplyData(replyData); + } + + MultiFeedRssModel* rssModel(new MultiFeedRssModel(nam)); + QSignalSpy spy(rssModel, SIGNAL(feedDataChanged())); + QVERIFY(spy.isValid()); + + for(QString& feedUrl: feedList) { + rssModel->addFeed(feedUrl); + } + + // wait for signal + QVERIFY(spy.wait()); + + QCOMPARE(rssModel->articleCount(), resultArticleCount); +} + +void KisMultiFeedRssModelTest::testAddFeed_data() +{ + QTest::addColumn>("replyDataList"); + QTest::addColumn("resultArticleCount"); + + // setup feed1 + QFile rssFile1(TestUtil::fetchDataFileLazy("rss_feeds/feed.xml")); + bool fileOpened = rssFile1.open(QIODevice::ReadOnly | QIODevice::Text); + QVERIFY(fileOpened); + + QString urlFeed1("https://krita.org/en/feed/"); + + // create reply data + FakeReplyData replyFeed1; + replyFeed1.url = QUrl(urlFeed1); + replyFeed1.statusCode = 200; + replyFeed1.requestMethod = QNetworkAccessManager::GetOperation; + replyFeed1.contentType = "application/atom+xml"; + replyFeed1.responseBody = rssFile1.readAll(); + + + // setup feed2 + QFile rssFile2(TestUtil::fetchDataFileLazy("rss_feeds/feed.xml")); + fileOpened = rssFile2.open(QIODevice::ReadOnly | QIODevice::Text); + QVERIFY(fileOpened); + + QString urlFeed2("https://krita.org/en/another_feed/"); + + FakeReplyData replyFeed2; + replyFeed2.url = QUrl(urlFeed2); + replyFeed2.statusCode = 200; + replyFeed2.requestMethod = QNetworkAccessManager::GetOperation; + replyFeed2.contentType = "application/atom+xml"; + replyFeed2.responseBody = rssFile2.readAll(); + + + // test with 1 feed + QList listTest1 = { replyFeed1 }; + QTest::addRow("1 feed") + << listTest1 + << 10; + + // test with 2 feeds + QList listTest2 = { replyFeed1, replyFeed2 }; + QTest::addRow("2 feeds") + << listTest2 + << 20; +} + +void KisMultiFeedRssModelTest::testRemoveFeed() +{ + QFETCH(QList, replyDataList); + QFETCH(QString, removeFeedUrl); + QFETCH(int, resultArticleCount); + + + MockNetworkAccessManager* nam(new MockNetworkAccessManager()); + + QStringList feedList; + for(FakeReplyData& replyData: replyDataList) { + feedList << replyData.url.toString(); + nam->setReplyData(replyData); + } + + MultiFeedRssModel* rssModel(new MultiFeedRssModel(nam)); + QSignalSpy spyAdd(rssModel, SIGNAL(feedDataChanged())); + QVERIFY(spyAdd.isValid()); + + for(QString& feedUrl: feedList) { + rssModel->addFeed(feedUrl); + } + + // wait for signal + QVERIFY(spyAdd.wait()); + + // the remove test itself + rssModel->removeFeed(removeFeedUrl); + + QCOMPARE(rssModel->articleCount(), resultArticleCount); +} + +void KisMultiFeedRssModelTest::testRemoveFeed_data() +{ + QTest::addColumn>("replyDataList"); + QTest::addColumn("removeFeedUrl"); + QTest::addColumn("resultArticleCount"); + + // setup feed1 + QFile rssFile1(TestUtil::fetchDataFileLazy("rss_feeds/feed.xml")); + bool fileOpened = rssFile1.open(QIODevice::ReadOnly | QIODevice::Text); + QVERIFY(fileOpened); + + QString urlFeed1("https://krita.org/en/feed/"); + + // create reply data + FakeReplyData replyFeed1; + replyFeed1.url = QUrl(urlFeed1); + replyFeed1.statusCode = 200; + replyFeed1.requestMethod = QNetworkAccessManager::GetOperation; + replyFeed1.contentType = "application/atom+xml"; + replyFeed1.responseBody = rssFile1.readAll(); + + // setup feed2 + QFile rssFile2(TestUtil::fetchDataFileLazy("rss_feeds/feed.xml")); + fileOpened = rssFile2.open(QIODevice::ReadOnly | QIODevice::Text); + QVERIFY(fileOpened); + + QString urlFeed2("https://krita.org/en/another_feed/"); + + FakeReplyData replyFeed2; + replyFeed2.url = QUrl(urlFeed2); + replyFeed2.statusCode = 200; + replyFeed2.requestMethod = QNetworkAccessManager::GetOperation; + replyFeed2.contentType = "application/atom+xml"; + replyFeed2.responseBody = rssFile2.readAll(); + + + // test with 1 feed + QList listTest1 = { replyFeed1 }; + QTest::addRow("1 feed") + << listTest1 + << urlFeed1 + << 0; + + // test with 2 feeds + QList listTest2 = { replyFeed1, replyFeed2 }; + QTest::addRow("2 feeds") + << listTest2 + << urlFeed1 + << 10; +} + +QTEST_MAIN(KisMultiFeedRssModelTest); + diff --git a/libs/ui/tests/KisMultiFeedRssModelTest.h b/libs/ui/tests/KisMultiFeedRssModelTest.h new file mode 100644 index 0000000000..d0e024a5d3 --- /dev/null +++ b/libs/ui/tests/KisMultiFeedRssModelTest.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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. + */ + + +#ifndef KISMULTIFEEDRSSMODELTEST_H +#define KISMULTIFEEDRSSMODELTEST_H + +#include + +class KisMultiFeedRssModelTest : public QObject +{ + Q_OBJECT +public: + explicit KisMultiFeedRssModelTest(QObject *parent = nullptr); + +private Q_SLOTS: + void testAddFeed(); + void testAddFeed_data(); + + void testRemoveFeed(); + void testRemoveFeed_data(); +}; + +#endif // KISMULTIFEEDRSSMODELTEST_H diff --git a/libs/ui/tests/KisRssReaderTest.cpp b/libs/ui/tests/KisRssReaderTest.cpp new file mode 100644 index 0000000000..6afb845752 --- /dev/null +++ b/libs/ui/tests/KisRssReaderTest.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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 "KisRssReaderTest.h" +#include +#include +#include +#include + +KisRssReaderTest::KisRssReaderTest(QObject *parent) : QObject(parent) +{ + +} + +void KisRssReaderTest::testParseData() +{ + KisRssReader reader; + QFile rssFile(TestUtil::fetchDataFileLazy("rss_feeds/feed.xml")); + + RssItemList itemList = reader.parse(rssFile); + + QCOMPARE(itemList.count(), 10); + +} + +QTEST_MAIN(KisRssReaderTest); diff --git a/libs/ui/tests/KisRssReaderTest.h b/libs/ui/tests/KisRssReaderTest.h new file mode 100644 index 0000000000..7c43412271 --- /dev/null +++ b/libs/ui/tests/KisRssReaderTest.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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. + */ + +#ifndef KISRSSREADERTEST_H +#define KISRSSREADERTEST_H + +#include +#include + +class KisRssReaderTest : public QObject +{ + Q_OBJECT +public: + explicit KisRssReaderTest(QObject *parent = nullptr); + +private Q_SLOTS: + void testParseData(); +}; + +#endif // KISRSSREADERTEST_H diff --git a/libs/ui/tests/MockMultiFeedRssModel.cpp b/libs/ui/tests/MockMultiFeedRssModel.cpp new file mode 100644 index 0000000000..8b3761e3cd --- /dev/null +++ b/libs/ui/tests/MockMultiFeedRssModel.cpp @@ -0,0 +1,28 @@ +#include "MockMultiFeedRssModel.h" + +#include +#include +#include +#include + +MockMultiFeedRssModel::MockMultiFeedRssModel(QObject *parent) + : MultiFeedRssModel(parent) +{ + +} + +void MockMultiFeedRssModel::addFeed(const QString &feed) +{ + Q_UNUSED(feed); + + emit feedDataChanged(); +} + +void MockMultiFeedRssModel::loadFeedData(const RssItemList& feed) +{ + m_aggregatedFeed = feed; + sortAggregatedFeed(); + setArticleCount(m_aggregatedFeed.size()); + beginResetModel(); + endResetModel(); +} diff --git a/libs/ui/tests/MockMultiFeedRssModel.h b/libs/ui/tests/MockMultiFeedRssModel.h new file mode 100644 index 0000000000..c3416fde8c --- /dev/null +++ b/libs/ui/tests/MockMultiFeedRssModel.h @@ -0,0 +1,25 @@ +#ifndef MOCKMULTIFEEDRSSMODEL_H +#define MOCKMULTIFEEDRSSMODEL_H + +#include + +#include +#include "kritaui_export.h" + +class KRITAUI_EXPORT MockMultiFeedRssModel : public MultiFeedRssModel +{ + Q_OBJECT + +public: + explicit MockMultiFeedRssModel(QObject *parent = 0); + + void addFeed(const QString& feed); + + /** + * @brief to be called in the setup phase of the unittest, before call to addFeed + * @param rssFile + */ + void loadFeedData(const RssItemList& feed); +}; + +#endif // MOCKMULTIFEEDRSSMODEL_H diff --git a/libs/ui/tests/MockNetworkAccessManager.cpp b/libs/ui/tests/MockNetworkAccessManager.cpp new file mode 100644 index 0000000000..ead092efea --- /dev/null +++ b/libs/ui/tests/MockNetworkAccessManager.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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 "MockNetworkAccessManager.h" + +#include +#include +#include + + +FakeNetworkReply::FakeNetworkReply(const QNetworkRequest& originalRequest, FakeReplyData &replyData) + : QNetworkReply() +{ + setRequest(originalRequest); + + setUrl(replyData.url); + setOperation(replyData.requestMethod); + setAttribute(QNetworkRequest::HttpStatusCodeAttribute, replyData.statusCode); + setHeader(QNetworkRequest::ContentTypeHeader, replyData.contentType); + setHeader(QNetworkRequest::ContentLengthHeader, replyData.responseBody.size()); + + m_data.setData(replyData.responseBody); + + m_data.open(QIODevice::ReadOnly); + + open(QIODevice::ReadOnly); + setFinished(true); + QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection); + QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); +} + +void FakeNetworkReply::abort() +{ + return; +} + +bool FakeNetworkReply::atEnd() const +{ + return m_data.atEnd(); +} + +qint64 FakeNetworkReply::bytesAvailable() const +{ + return m_data.bytesAvailable(); +} + +bool FakeNetworkReply::canReadLine() const +{ + return m_data.canReadLine(); +} + +void FakeNetworkReply::close() +{ + return m_data.close(); +} + +qint64 FakeNetworkReply::size() const +{ + return m_data.size(); +} + +qint64 FakeNetworkReply::pos() const +{ + return m_data.pos(); +} + +qint64 FakeNetworkReply::readData(char *data, qint64 maxLen) +{ + return m_data.read(data, maxLen); +} + +qint64 FakeNetworkReply::writeData(const char *data, qint64 maxLen) +{ + return m_data.write(data, maxLen); +} + +MockNetworkAccessManager::MockNetworkAccessManager(QObject *parent) + : KisNetworkAccessManager(parent) +{ +} + +void MockNetworkAccessManager::setReplyData(FakeReplyData &replyData) +{ + m_replyData = replyData; +} + +QNetworkReply *MockNetworkAccessManager::createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData) +{ + Q_UNUSED(op); + Q_UNUSED(outgoingData); + + return new FakeNetworkReply(request, m_replyData); +} diff --git a/libs/ui/tests/MockNetworkAccessManager.h b/libs/ui/tests/MockNetworkAccessManager.h new file mode 100644 index 0000000000..5a0b94e14c --- /dev/null +++ b/libs/ui/tests/MockNetworkAccessManager.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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. + */ + +#ifndef MOCKNETWORKACCESSMANAGER_H +#define MOCKNETWORKACCESSMANAGER_H + +#include +#include +#include +#include + +#include + +#include "kritaui_export.h" + + +struct FakeReplyData { + QUrl url; + QNetworkAccessManager::Operation requestMethod; + int statusCode; + QString contentType; + QByteArray responseBody; +}; +Q_DECLARE_METATYPE(FakeReplyData); + +class FakeNetworkReply : public QNetworkReply +{ + Q_OBJECT + +public: + explicit FakeNetworkReply(const QNetworkRequest &originalRequest, FakeReplyData& replyData); + + void abort() override; + bool atEnd() const override; + qint64 bytesAvailable() const override; + bool canReadLine() const override; + void close() override; + qint64 size() const override; + qint64 pos() const override; + +protected: + qint64 readData(char *data, qint64 maxLen) override; + qint64 writeData(const char *data, qint64 maxLen) override; + +private: + QBuffer m_data; +}; + +class KRITAUI_EXPORT MockNetworkAccessManager : public KisNetworkAccessManager +{ + Q_OBJECT + +public: + explicit MockNetworkAccessManager(QObject *parent = 0); + + void setReplyData(FakeReplyData& replyData); + + QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData); + +private: + FakeReplyData m_replyData; +}; + +#endif // MOCKNETWORKACCESSMANAGER_H diff --git a/libs/ui/tests/data/AppImageUpdateDummy b/libs/ui/tests/data/AppImageUpdateDummy new file mode 100755 index 0000000000..215a0289d7 --- /dev/null +++ b/libs/ui/tests/data/AppImageUpdateDummy @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 + +import sys +import os +import argparse +import os.path + +EXIT_RUNTIME_ERROR = 255 +EXIT_OK = 0 +EXIT_ERROR = 1 + +EXIT_CHECK_UPTODATE = 0 +EXIT_CHECK_ERROR = 2 +EXIT_CHECK_UPDATE_AVAIL = 1 + +EXIT_INVALID_USAGE = 100 + +# files that govern the output of this dummy +states = { + "check_uptodate": EXIT_CHECK_UPTODATE, + "check_update_avail": EXIT_CHECK_UPDATE_AVAIL, + "check_error": EXIT_CHECK_ERROR, + "check_updinfo_empty": EXIT_RUNTIME_ERROR, + "update_ok": EXIT_OK, + "update_error": EXIT_ERROR, + "runtime_error": EXIT_RUNTIME_ERROR +} + +parser = argparse.ArgumentParser() +parser.add_argument('--check-for-update', dest='check_for_update', action='store_true', + help='only check if updates are available') +parser.add_argument('appimage_path', metavar='APPIMAGE_PATH', type=str, help='path to the appimage') + +args = parser.parse_args() + + +if "APPIMAGEUPDATE_DUMMY_STATE" not in os.environ.keys(): + sys.exit(EXIT_INVALID_USAGE) + +state_string = str(os.environ["APPIMAGEUPDATE_DUMMY_STATE"]) + +# if we want to test the update, return update available for --check-for-update +if (args.check_for_update): + if state_string in [ 'update_ok', 'update_error', 'runtime_error' ]: + sys.exit(EXIT_CHECK_UPDATE_AVAIL) + +# else lookup the state in the dict +if (state_string in states.keys()): + state = states[state_string] + + if state_string in ['update_error', 'runtime_error']: + print("DUMMY: an error occured") + + sys.exit(states[state_string]) + +else: + sys.exit(EXIT_INVALID_USAGE) diff --git a/libs/ui/tests/data/rss_feeds/feed.xml b/libs/ui/tests/data/rss_feeds/feed.xml new file mode 100644 index 0000000000..10d1e8f269 --- /dev/null +++ b/libs/ui/tests/data/rss_feeds/feed.xml @@ -0,0 +1,661 @@ + + + + Krita + + https://krita.org + Digital Painting. Creative Freedom. + Fri, 04 Oct 2019 13:43:35 +0000 + en-US + + hourly + + 1 + https://wordpress.org/?v=5.2.3 + + Krita 4.2.7 Released + https://krita.org/en/item/krita-4-2-7-released/ + Thu, 03 Oct 2019 08:42:40 +0000 + + + + https://krita.org/?p=9790 + + Today, we’re releasing the sixth bug fix release of Krita 4.2. As discussed in our development update, we intend to release a few more monthly 4.2 bug fix releases before releasing Krita 4.3. There are a lot of bug fixes!

+

And to celebrate the release, we have a new video by Ramon Miranda which comes with a very nice present: a free new bundle of six sketching brush presets!

+

+

Bugs Fixed in 4.2.7

+
    +
  • Improve the layout and functionality of the color selector dialog and make it perform much better. (BUG:381529). Patches by Mathias Wein.
  • +
  • Do not crash when trying to merge an invisible group layer (BUG:411124)
  • +
  • Make it possible to save group layers to file layers even if they are empty (BUG:411101)
  • +
  • Make the initial location of the OCIO profile selector sensible
  • +
  • Fix possible crashes when a broken file ends up in the Recent Documents List (BUG:411416)
  • +
  • Use locale-based formatting of numbers in the measure tool and other places. Patch by Karl Ove Lufthammer.
  • +
  • Make HTML markup in the Search Field tooltips work. Patch by Karl Ove Lufthammer.
  • +
  • Fix a crash when moving multiple vector shapes (BUG:409872)
  • +
  • Fix the sort order of images imported as frames if they are not numbered with prefix 0’s (BUG:375885)
  • +
  • Make it possible again to run the Python Scripting Debugger on Linux (BUG:410807) Patch by Rebecca Breu.
  • +
  • Cache ICC profiles when loading layers: this speeds up loading images with thousands of layers (BUG:411532)
  • +
  • Fix file layer and comics manager page updating on Windows (BUG:410409, BUG:389544)
  • +
  • Use LittleCMS’ copy alpha channel flag to speed up color transformations
  • +
  • Fix outline move mode (BUG:411057)
  • +
  • Fix a hang in the text shape if an UTF-8 Line Break character is used (BUG:410402)
  • +
  • Fix a random crash if there is not enough space in the swapfile location for AMD Ryzen 3500 CPU’s (BUG:411081)
  • +
  • Fix checking whether the swapfile location is actually writable on Windows (BUG:411129, BUG:411081)
  • +
  • Fix another random crash when painting (BUG:411280)
  • +
  • Fix artifacts when moving control points of a path shape (BUG:411334)
  • +
  • Fix a crash when cropping a particular image (BUG:411536)
  • +
  • Fix move action in the bezier selection tool (BUG:398294)
  • +
  • Fix artifacts in Gaussian Blur on transparent layers (BUG:411719)
  • +
  • Fix a crash when the Liquify Transform is started too quickly (BUG:411703)
  • +
  • Fix a bad memory leak in the jpeg converter (BUG:410864)
  • +
  • Fix a crash when loading a JPEG image with a broken color profile (BUG:410864)
  • +
  • Fix problems when zooming with a touchpad (BUG:410940)
  • +
  • Fix issues when using the calculation capabilities of the specific color selector’s spin boxes (BUG:409818). Patch by Jasper Hartog
  • +
  • Make sure all layers are shown in the animation timeline by default
  • +
  • Fix a crash when the colorize tool is active on closing Krita
  • +
  • Fix a crash when converting a colorspace with OCIO enabled (BUG:411045)
  • +
  • Fix the Strength parameter not being used in Rotation – Fuzzy Dab (BUG:376179)
  • +
  • Fix a crash when using the mouse wheel while an image is opening
  • +
  • Re-add error messages lost when refactoring the error messages for loading images
  • +
  • Do not crash if libjpeg encounters any kind of error (BUG:364350)
  • +
  • Fix presets with random offset of texture being marked dirty all the time (BUG:406427)
  • +
  • Fix curves changing randomly with sensors with Use Same Curve enabled (BUG:383909)
  • +
  • Add a simple progress bar when saving .kra files
  • +
  • Ensure that the temporary folder isn’t suggested as a save-location as this can result in lost work.
  • +
  • Make sure toolbars don’t get enabled after editing the toolbar buttons (BUG:402679)
  • +
  • Do not crash when loading a tiled TIFF file with planar color data. (BUG:407171)
  • +
  • Fix freezes when changing some brush properties or curves (BUG:410158)
  • +
  • Fix wrong borders in the Edge Detection and Height To Normal Map Filters (BUG:411922)
  • +
  • Fix outline of Group Layers in Move Tool and Transform Tool (BUG:392717)
  • +
  • Fix preview of shape layers in Transform Tool and Move Tool (BUG:392717)
  • +
  • Raise the maximum FPS limit to 300 fps from 100 fps
  • +
  • Do not allow clone layers from pass-through group layers (BUG:409949)
  • +
  • Fix the color of a selected shape being synchronized with the color selectors (BUG:381784)
  • +
  • Fix updating the current shape color when doing undo/redo (BUG:404975)
  • +
  • Fix the broken TestKisSwatchGroup test (BUG:410387) Patch by Krysztof Kurek.
  • +
  • Make the splash render pixel-perfect on fractionally scaled displays. Patch by Guo Yunhe.
  • +
  • Fix a crash in Feather Selection, Wavelets, Blur and Edge Detection (BUG:412057)
  • +
  • Include reference images in the screen color picker (BUG:411816) Patch by Matthias Wein.
  • +
  • Clean up the SVG files used for icons and license the SVG files properly. Patch by Raghavendra Kamath.
  • +
  • Fix updating the assistants when moving the handles. Patch by Matthias Wein.
  • +
  • Fix a bad memory corruption error color handling. Patch by Matthias Wein.
  • +
+

Download

+

Windows

+ + +

Linux

+ +

(If, for some reason, Firefox thinks it needs to load this as text: to download, right-click on the link.)

+

OSX

+ +

Note: the gmic-qt is not available on OSX.

+

Source code

+

Note: Linux distributions building Krita against Qt 5.13 have to be aware that a regression in Qt crashes Krita on exit. There’s a workaround for that, but that was not ready for this release.

+ +

md5sum

+

For all downloads:

+ +

Support Krita

+

Krita is a free and open source project. Please consider supporting the project with donations or by buying training videos or the artbook! With your support, we can keep the core team working on Krita full-time.

+

 

+]]>
+
+ + September Development Update + https://krita.org/en/item/september-development-update/ + Mon, 30 Sep 2019 13:50:22 +0000 + + + + https://krita.org/?p=9779 + + We’re about to do another bug-fix release of Krita: that’ll be 4.2.7. We’re seeing that the number of new bug reports is dropping a bit, week over week: even though most bug reports can be closed instantly as duplicates or not bugs at all, that’s probably a sign that our stable releases are getting more and more stable. (See here to learn how to make good bug reports.) Though the total number of open bugs remains high, we worked really hard all September to make Krita better:

+

+

We also managed make 538 changes to the code in September with 23 developers — and that excludes translations, since those aren’t in our code repository.

+

We also went back to the Coverity Static Code analyzer and started analyzing Krita again. That was good for at least a hundred potential bug fixes, and it’s something that’s ongoing. We hadn’t done that for quite some time! There is still plenty to do, but the average defect density for projects the size of Krita is 0.7, so we’re not that bad.

+

+

Of course, focus on fixing bugs means that there’s less time for cool new features, or extending existing features. We did merge Sharaf Zaman’s Android port, though, which means that pretty soon we should have signed nightly Android APK’s!

+

Today during our weekly contributors meeting (notes are here), we decided we wanted to continue and do another couple of montly bug fix releases in the 4.2 series. In what’s currently our master branch, there are quite a few nice new features we’d like to share, though, and we’ll start making alpha builds of master in October, and invite everyone to help test what will become Krita 4.3.0.

+

We had originally wanted to release 4.3.0 in October, and have a fundraiser to celebrate the release. Part of the reason we’re postponing 4.3.0 is that we’d like to continue for a while with the stable 4.2 releases. Another reason is that we want 4.3.0 to have a completely reworked system for loading, handling and saving things like brush presets. We’ve been working on that for a long time now, and things are coming together, but there’s still a lot that needs to be done.

+]]>
+
+ + Interview with Samantha Skoros + https://krita.org/en/item/interview-with-samantha-skoros/ + Mon, 30 Sep 2019 07:22:39 +0000 + + + + https://krita.org/?p=9758 + + +

Could you tell us something about yourself?

+

Oh I’m terrible at talking about myself. I guess the easiest thing would be that I’m 26 years old and a mother. I identify as genderfluid and pansexual, I freaking love Dungeons and Dragons, and I also am a super avid knitter/fiber artist. I mainly just love doing things with my hands and gravitate to any hobby or craft that lets me do that.

+

Do you paint professionally, as a hobby artist, or both?

+

A complete hobbyist. I actually only started drawing maybe a year ago, so I’m still learning a lot and growing. I’d love to do this professionally some day, but right now I just really enjoy drawing for my own self.

+

What genre(s) do you work in?

+

I’m so new to this I don’t even know if I know how to answer this. I mean I guess I mostly work in portraits? I’m trying to get better at drawing buildings and scenes. I’d love to get into comics at some point but my skill level just isn’t quite there yet.

+

+

Whose work inspires you most — who are your role models as an artist?

+

I love seeing all sorts of art on twitter, I follow a lot of digital and traditional artists and a lot of them draw Dungeons and Dragons characters and I just love seeing people’s imaginations come to life in that way. I also love Jen Bartel and This Is Angle (This Is Angle writes a comic that I absolutely love the art style of, The Devil Is A Handsome Man) But both of them are just amazing artists and if I could draw half as well as them I would feel accomplished.

+

How and when did you get to try digital painting for the first time?

+

About a year ago I decided I really wanted to get into drawing. It was always something I wanted to do but just never took that leap. But the time I got there, I realized doing traditional art would be hard simply because we don’t have a lot of space in our home. The house is filled with yarn, fabric, leather, pets, and kid toys. There just wasn’t space for another hobby so I realized digital art would be the only way for me to do this thing. So my partner found me a refurbished Wacom pen tablet and I just fell in love with it.

+

+

What makes you choose digital over traditional painting?

+

The biggest thing for me is the space it saves. But also, boy, do I absolutely love the undo function. I make a LOT of mistakes and so having the ability to just ctrl+z a bad stroke is phenomenal. I also love the freedom it gives, you can do so much with it that I feel like you just can’t accomplish with traditional. I guess another thing too would be how easy it is to share, I can just upload the finished work to wherever and don’t have to worry about trying to scan traditional art into the computer in order to show people.

+

+

How did you find out about Krita?

+

So when I first got my pen tablet, I was looking at a few programs. I knew I wasn’t going to mess with anything expensive like PS, but I still wanted a good program. Krita was actually the first thing that I found and it just worked perfectly for everything I needed and it was super user friendly. I had people recommend other programs but honestly I just fell in love with Krita and didn’t even bother looking at anything else.

+

+

What was your first impression?

+

Sheer joy. It was the first thing I found and it was just perfect, everything I wanted in a drawing program.

+

What do you love about Krita?

+

I love the quality of it, It’s just as good as the pricier programs and it’s free. It’s also got an amazing community of people around it.

+

What do you think needs improvement in Krita? Is there anything that really annoys you?

+

I think the biggest issue I run into is just wanting to undo more than the allotted undo’s. Sometimes I just zone out and do a bunch of strokes and then realize I’m on the wrong layer and I can’t undo all of my mistakes. But I suppose that’s more of a user error.

+

What sets Krita apart from the other tools that you use?

+

It’s layout is very user friendly and intuitive. I never have to look long for something, it’s always right where I expected it would be. So I didn’t have to waste a bunch of time learning some complicated program, it’s just so well designed and supported that even if I couldn’t figure something out, there’s a great community that is prepared to help.

+

If you had to pick one favourite of all your work done in Krita so far, what would it be, and why?

+

+

Oh that’s a hard one. I don’t know that I have a favorite one, per say, but I do love all of the demons I draw. I think I just like drawing horns on people and blacking out their eyes. My body of work though is small so it’s hard to pick a favorite when my style keeps changing and evolving.

+

What techniques and brushes did you use in it?

+

I like using the sketch tools and then going over the sketch with the basic paint brush. I also have some of David Revoy’s brushes and I love using them for fun backgrounds and effects. But honestly I mainly use the basic brushes, they can accomplish so much.

+

Where can people see more of your work?

+

I’m on twitter: @moderbjorn_
+and I am also on Instagram: @moderbjorn
+I also occasionally draw on Twitch: ModerBjorn

+

Anything else you’d like to share?

+

I think I’d like to just say that it’s never too late for you to do the art thing. You don’t have to be one of those people that drew constantly in high school to be someone who’s good at art later in life. Even if it isn’t drawing, maybe it’s writing or wood carving, maybe you really want to try sewing. I’m telling you to do it, it’s so rewarding and you get to watch yourself get better with everything that you do. Don’t let anyone stop you from doing the thing that you want to do, especially yourself. I’m a stay at home mom with no time and sometimes no energy to do it. But just take a breath and understand that it’s okay to go at your own pace, you don’t owe anyone anything and you’re doing this for you. Yeah, I think that’s it. Just do the thing and you’ll be so proud of yourself, I believe in you.

+]]>
+
+ + Let’s Test Krita 4.2.7 Beta! + https://krita.org/en/item/lets-test-krita-4-2-7-beta/ + Wed, 25 Sep 2019 10:52:21 +0000 + + + + https://krita.org/?p=9751 + + We’re almost ready for a new release of Krita, with lots of bug fixes! So, please help with testing. As with 4.2.6, there’s a link on the welcome screen to a survey. Filling out the survey helps us figure out regressions and other problems. You can safely use any beta build on any operating system next to your production version of Krita. Settings and resources will be shared, but you won’t overwrite you existing installation by using one of the portable beta downloads.

+

In addition to reported bugs, this release fixes a lot of issues found by the Coverity Static Code checker.

+

We also have a bunch of great patches by new Krita hackers: Karl Ove Lufthammer, Rebecca Breu, Matthias Wein, Jasper Hartog, Krysztof Kurek and Guo Yunhe. Yay!

+

If all is well, we will release 4.2.7 in a week.

+

Bugs Fixed in 4.2.7

+
    +
  • Improve the layout and functionality of the color selector dialog and make it perform much better. (BUG:381529). Patches by Mathias Wein.
  • +
  • Do not crash when trying to merge an invisible group layer (BUG:411124)
  • +
  • Make it possible to save group layers to file layers even if they are empty (BUG:411101)
  • +
  • Make the initial location of the OCIO profile selector sensible
  • +
  • Fix possible crashes when a broken file ends up in the Recent Documents List (BUG:411416)
  • +
  • Use locale-based formatting of numbers in the measure tool and other places. Patch by Karl Ove Lufthammer.
  • +
  • Make HTML markup in the Search Field tooltips work. Patch by Karl Ove Lufthammer.
  • +
  • Fix a crash when moving multiple vector shapes (BUG:409872)
  • +
  • Fix the sort order of images imported as frames if they are not numbered with prefix 0’s (BUG:375885)
  • +
  • Make it possible again to run the Python Scripting Debugger on Linux (BUG:410807) Patch by Rebecca Breu.
  • +
  • Cache ICC profiles when loading layers: this speeds up loading images with thousands of layers (BUG:411532)
  • +
  • Fix file layer and comics manager page updating on Windows (BUG:410409, BUG:389544)
  • +
  • Use LittleCMS’ copy alpha channel flag to speed up color transformations
  • +
  • Fix outline move mode (BUG:411057)
  • +
  • Fix a hang in the text shape if an UTF-8 Line Break character is used (BUG:410402)
  • +
  • Fix a random crash if there is not enough space in the swapfile location for AMD Ryzen 3500 CPU’s (BUG:411081)
  • +
  • Fix checking whether the swapfile location is actually writable on Windows (BUG:411129, BUG:411081)
  • +
  • Fix another random crash when painting (BUG:411280)
  • +
  • Fix artifacts when moving control points of a path shape (BUG:411334)
  • +
  • Fix a crash when cropping a particular image (BUG:411536)
  • +
  • Fix move action in the bezier selection tool (BUG:398294)
  • +
  • Fix artifacts in Gaussian Blur on transparent layers (BUG:411719)
  • +
  • Fix a crash when the Liquify Transform is started too quickly (BUG:411703)
  • +
  • Fix a bad memory leak in the jpeg converter (BUG:410864)
  • +
  • Fix a crash when loading a JPEG image with a broken color profile (BUG:410864)
  • +
  • Fix problems when zooming with a touchpad (BUG:410940)
  • +
  • Fix issues when using the calculation capabilities of the specific color selector’s spin boxes (BUG:409818). Patch by Jasper Hartog
  • +
  • Make sure all layers are shown in the animation timeline by default
  • +
  • Fix a crash when the colorize tool is active on closing Krita
  • +
  • Fix a crash when converting a colorspace with OCIO enabled (BUG:411045)
  • +
  • Fix the Strength parameter not being used in Rotation – Fuzzy Dab (BUG:376179)
  • +
  • Fix a crash when using the mouse wheel while an image is opening
  • +
  • Re-add error messages lost when refactoring the error messages for loading images
  • +
  • Do not crash if libjpeg encounters any kind of error (BUG:364350)
  • +
  • Fix presets with random offset of texture being marked dirty all the time (BUG:406427)
  • +
  • Fix curves changing randomly with sensors with Use Same Curve enabled (BUG:383909)
  • +
  • Add a simple progress bar when saving .kra files
  • +
  • Ensure that the temporary folder isn’t suggested as a save-location as this can result in lost work.
  • +
  • Make sure toolbars don’t get enabled after editing the toolbar buttons (BUG:402679)
  • +
  • Do not crash when loading a tiled TIFF file with planar color data. (BUG:407171)
  • +
  • Fix freezes when changing some brush properties or curves (BUG:410158)
  • +
  • Fix wrong borders in the Edge Detection and Height To Normal Map Filters (BUG:411922)
  • +
  • Fix outline of Group Layers in Move Tool and Transform Tool (BUG:392717)
  • +
  • Fix preview of shape layers in Transform Tool and Move Tool (BUG:392717)
  • +
  • Raise the maximum FPS limit to 300 fps from 100 fps
  • +
  • Do not allow clone layers from pass-through group layers (BUG:409949)
  • +
  • Fix the color of a selected shape being synchronized with the color selectors (BUG:381784)
  • +
  • Fix updating the current shape color when doing undo/redo (BUG:404975)
  • +
  • Fix the broken TestKisSwatchGroup test (BUG:410387) Patch by Krysztof Kurek.
  • +
  • Make the splash render pixel-perfect on fractionally scaled displays. Patch by Guo Yunhe.
  • +
  • Fix a crash in Feather Selection, Wavelets, Blur and Edge Detection (BUG:412057)
  • +
  • Include reference images in the screen color picker (BUG:411816) Patch by Matthias Wein.
  • +
  • Clean up the SVG files used for icons and license the SVG files properly. Patch by Raghavendra Kamath.
  • +
  • Fix updating the assistants when moving the handles. Patch by Matthias Wein.
  • +
  • Fix a bad memory corruption error color handling. Patch by Matthias Wein.
  • +
+

Download

+

Windows

+

For the beta, you should only only use the portable zip files. Just open the zip file in Explorer and drag the folder somewhere convenient, then double-click on the krita icon in the folder. This will not impact an installed version of Krita, though it will share your settings and custom resources with your regular installed version of Krita. For reporting crashes, also get the debug symbols folder.

+ + +

Linux

+ +

(If, for some reason, Firefox thinks it needs to load this as text: to download, right-click on the link.)

+

OSX

+ +

Note: the gmic-qt is not available on OSX.

+

Source code

+ +

md5sum

+

For all downloads:

+ +

Support Krita

+

Krita is a free and open source project. Please consider supporting the project with donations or by buying training videos or the artbook! With your support, we can keep the core team working on Krita full-time.

+

 

+]]>
+
+ + Interview with Julius Grels + https://krita.org/en/item/interview-with-julius-grels/ + Mon, 16 Sep 2019 08:00:25 +0000 + + + + https://krita.org/?p=9727 + + +

Could you tell us something about yourself?

+

Sure. I’m Julius Grels, and “I like to call myself an artist whenever I’m wasted enough”. In all seriousness though, I think I’d describe myself more as a self-taught caricaturist or illustrator. I usually like to take some existing premise from real life or history, e.g. painting a picture of a (famous) person, depicting wildlife, et cetera. I’m also very fond of making comics, music and video games whenever I have the time (if only?).

+

Do you paint professionally, as a hobby artist, or both?

+

I’m most definitely a hobbyist, since I haven’t done any professional commissions (apart from some miniscule design work in the past), and what I do for living right now isn’t even remotely connected to art! That said, I’d most certainly would love to work as an illustrator, comic artist, or anything alike! My biggest wish would be to illustrate (and/or write) a children’s book someday.

+

+

What genre(s) do you work in?

+

I’m most comfortable when doing caricatures and comics; in the latter I can also infuse my story-telling abilities, the little there are. I prefer to illustrate living things; people, animals and nature itself. I’m not exactly keen on drawing in-animate objects, though I’m learning to force myself out of this comfort zone. I like to keep things simple and clean, or at least I try my best not to get lost in time-consuming detailing. Guess that’s one argument I can use as to why I prefer using simple black background on most of my works…

+

Whose work inspires you most — who are your role models as an artist?

+

I mostly draw (clever, eh?) influence and inspiration from animation, comics and video game art. I’m hesitant to drop any names because I don’t really have role models per se, and I tend to find pretty much any artist’s work interesting and inspiring. I guess as a Finn I could mention Tove Jansson and Mauri Kunnas. Jansson is of course famous for creating the Moomins, but she was also an accomplished artist and writer in her own right. Kunnas is a well-loved artist best known for his children’s books – pretty much every child in Finland has read at least one of his stories. In my opinion he’s also one of the greatest illustrators this country has to offer.

+

In addition to the aforementioned, I basically inhaled Franco-Belgian comics as a child; I loved reading Astérix, Lucky Luke, Iznogoud and the rest, so artists like Uderzo, Tabary and Tardi have also had a huge influence on me. Whenever possible, I browse through concept art of different video games. Video games are an interesting subject anyway because they not only combine art, design and technology but have to make all three work together even-handedly to create an enjoyable interactive experience.

+

 

+

How and when did you get to try digital painting for the first time?

+

If we don’t count MS Paint doodles, I think my first real try at digital painting was at elementary school somewhere around the late 90’s where we were introduced to Paint Shop Pro as a part of some “build your own website” -course. We were only able to use mouse for drawing, which was extremely clunky and made me think the whole idea of drawing and painting with a computer was just insane; I’d rather stick to my pencils and brushes, thank you very much. It wasn’t until later when I realised there are equipment specifically made for digital artwork, and once I got my hands on a Wacom tablet, I was sold.

+

What makes you choose digital over traditional painting?

+

Nothing? I mean, they are completely different working methods, and I still paint traditionally. Nevertheless, I’ve started to slowly leer towards digital painting, since it’s much easier to control your work and you can experiment more without the fear of ruining something irreversibly (especially when it comes to inking comics and other drawings). While it’s arguable whether digital painting is more cost-efficient than traditional methods in the long run, I think it’s at least less painful to start working with; you only need to set up your computer and programs ready, while with traditional painting you need to take out easel, canvas, gesso, colours, brushes, pencils? you get the idea. Furthermore, in my case where I don’t have a separate studio I have to find and clear a space in my apartment to set all that stuff up. Hassle, hassle!

+

+

How did you find out about Krita?

+

At one point I started to search for open source alternatives for the myriad number of programs I was using, and Krita was a recommendation somewhere to replace Photoshop, with high ratings from users.

+

What was your first impression?

+

I guess I’m still languishing in my first impression, because I haven’t been able to use Krita as much as I have wanted. In any case, my very first impression upon opening the program was a relieved “this looks familiar” sigh, and it was incredibly easy to start using Krita from there on.

+

What do you love about Krita?

+

Like I mentioned above, I find the interface very easy to use. I also love the fact the community is so alive, and you can find answers to just about any dilemma. All in all, Krita is a magnificent tool for making 2d artwork.

+

+

What do you think needs improvement in Krita? Is there anything that really annoys you?

+

Majority of my problems with Krita are due to the fact I’ve yet to learn most of its nuances, so I can’t really say about improvements that much. Krita seems to be quite a memory-hog, which can cause lot of lag and freezing especially when working with bigger canvases. That, and I’m not too happy with the text tool/editor either and prefer not to use it at all. It’s the one thing in Krita that’s needlessly complicated in my opinion.

+

What sets Krita apart from the other tools that you use?

+

Krita is the only digital painting software I use. Being open source is probably what makes it stand out the most. I use other open source programs as well, e.g. Blender, OpenToonz and Aseprite, but they obviously aren’t that much similar to Krita?

+

If you had to pick one favourite of all your work done in Krita so far, what would it be, and why?

+

+

Not much to choose from, but nevertheless, I’d say Megantereon, which was my first serious Krita artwork that I actually managed to finish. The main reason why I like it so much is simply because I had no initial planning; I took my Wacom, opened Krita and started doodling “something tiger-like”. After an hour or so, I began to realise there might be more to it, and continued working. The first version had plain fur, simplistic ear and lifeless green eye. I published it on deviantart.com, but wasn’t happy with the result, and later on decided to tweak the cat a bit. The fur got more detailed with stripes and spots, and I completely overhauled both the ear and the eye. The final result is what you see here, and I quickly replaced my previous attempt with this better version. I also like Megantereon as it neatly represents my interests (wildlife, history) and my preferred style (stylized, semi-realistic).

+

What techniques and brushes did you use in it?

+

Every brush I used is a Krita default. I used Basic and Fill Circle for outlining and some detail, Bristle Texture and Square for texturing and Inkpens for smaller detailing. There might be some Smudge tool I used too, but I honestly can’t remember.
+I made a rough outlining on one layer against a black background and constructed the beast from bones to muscles to fur et cetera from there on. In the end I had laid out 23 layers with such genius descriptions as “skull”, “Layer 17”, “BLOOD SALIVA”, “hideTheBeard” and “washing”. In retrospect, I highly recommend people to use layers more scarcely if possible – they slow down the program, and the whole working process ends up confusing. At least name your layers better than I did!
+I have two versions of the final work; with and without Noise Effect, which I used to achieve a more horror-esque vibe. I send the noiseless version here so the details aren’t obstructed too much.

+

Where can people see more of your work?

+

At the moment, my most recent work will be published at https://www.deviantart.com/jgrels . Don’t hold your breath, though; I publish work at a snail’s pace. You can also follow me on Twitter @JuliusGrels if you so desire, where I’m giving more information about my possible future projects, like a couple of webcomics I’ve planned to do.

+

Anything else you’d like to share?

+

Maybe just some general advice to any aspiring artist: never stop honing your skills, get out of your comfort zone, don’t fear experimenting, and most importantly; have confidence. Believe in yourself. Even if you don’t think you’re that great of an artist but love doing art, just keep working and publishing your work for everyone to see. You can doubt your talent, but never doubt your passion.

+

Finally, I want to send my thanks to the Krita Foundation and give my highest appreciation for the great work you’ve done. Thank you!

+]]>
+
+ + Krita 4.2.6 released + https://krita.org/en/item/krita-4-2-6-released/ + Tue, 10 Sep 2019 10:55:39 +0000 + + + + + https://krita.org/?p=9735 + + A bit later than expected, because of a regression found during beta testing, we’re releasing Krita 4.2.6. Over 120 people have participated in the beta test survey, so this is something we’ll repeat for the next release.

+

This release also contains an important workaround for users with an AMD Ryzen 5 3500 CPU. This CPU has a bug in its hardware random generator that caused crashes.

+

New features:

+
    +
  • Add new layer from visible to layer right-click context menu.
  • +
  • When running Krita for the first time on Windows, Angle is now the default renderer. Note that if you have an NVidia GPU and Krita’s window is transparent, you need to select Angle manually in Krita’s settings; if you have another GPU and you have problems with the canvas not updating, you might need to manually select OpenGL in the same window.
  • +
+

We want to especially thank Karl Ove Hufthammer for his extensive work on polishing the translatable string.

+

Bugs fixed

+
    +
  • Allow selection overlay to be reset to default. (BUG:410470)
  • +
  • Set date for bundle creation to use ISO-Date. (BUG:410490)
  • +
  • Fix freeze with 32bit float tiff by using our own tiff reader for the thumbnails. (BUG:408731)
  • +
  • Ensure filter mask button is disabled appropriately depending on whether the filter supports it. (BUG:410374)
  • +
  • Enable the small color selector if opengles is available as well (BUG:410602)
  • +
  • Fix mixed Zoom, Pan, Rotate on macOS (BUG:410698)
  • +
  • Ensure that checkboxes are shown in menus even when using the fusion theme
  • +
  • Isolate Layer Crash (BUG:408785)
  • +
  • Properly fix font resetting when all the text in the editor removed (BUG:409243)
  • +
  • Fix lags in Move Tool when using tablet device (BUG:410838)
  • +
  • Fix Shift and Alt modifiers in Outline Selection Tool (BUG:410532)
  • +
  • Ensure Convert group to Animated Layer shows text in the toolbar. (BUG:410500)
  • +
  • Allow ‘Add Clone Layer’ to Work on Multiple Layers (BUG:373338)
  • +
  • Fix saving animated transparency masks created through conversion (BUG:409895)
  • +
  • Partially fix the curve change despite ‘Share curve across all settings’ checked (BUG:383909)
  • +
  • Try harder to make sure that the swap location is writable
  • +
  • Properly handle timezones in bundles
  • +
  • Make sure all the settings dialogs pages are always shown in the same order
  • +
  • Make the settings dialog fit in low-res screens (BUG:410793)
  • +
  • Remove misleading ‘px’ suffix for ‘move amount’ shortcut setting
  • +
  • Make string for reasons for image export problems translatable (BUG:406973)
  • +
  • Fix crash when creating a bezier curve (BUG:410572)
  • +
  • Fix deadlocks in KoShapeManager (BUG:410909, BUG:410572)
  • +
  • Fix a deadlock when using broken Wacom drivers on Linux (BUG:410797)
  • +
  • Fix absolute brush rotation on rotated canvas (BUG:292726)
  • +
  • Fix deadlock when removing reference image (BUG:411212)
  • +
  • Fix a deadlock in handling of vector objects (BUG:411365)
  • +
  • Fix autosave saving only once (BUG:411631)
  • +
+

Download

+

Windows

+

Note for Windows users: if you encounter crashes, please follow these instructions to use the debug symbols so we can figure out where Krita crashes.

+ + +

Linux

+ +

(If, for some reason, Firefox thinks it needs to load this as text: to download, right-click on the link.)

+

OSX

+ +

Note: the gmic-qt is not available on OSX.

+

Source code

+ +

md5sum

+

For all downloads:

+ +

Key

+

The Linux appimage and the source .tar.gz and .tar.xz tarballs are signed. You can retrieve the public key over https here: 0x58b9596c722ea3bd.asc. The signatures are here (filenames ending in .sig).

+

Support Krita

+

Krita is a free and open source project. Please consider supporting the project with donations or by buying training videos or the artbook! With your support, we can keep the core team working on Krita full-time.

+]]>
+
+ + Interview with Wojtek Trybus + https://krita.org/en/item/interview-with-wojtek-trybus/ + Mon, 02 Sep 2019 08:00:37 +0000 + + + + https://krita.org/?p=9692 + +

+

Could you tell us something about yourself?

+

My name is Wojtek Trybus and I publish artworks as wojtryb. I’m in the last year of Computer Science studies in Poland. I’m also a pianist since 6, and happen to be a hobbyist and self-taught illustrator for something like 8 years now.

+

Do you paint professionally, as a hobby artist, or both?

+

Drawing was always something that, despite being quite hard to learn, was making me happy and fulfilled. I guess this counts as a hobby then. I don’t make any money from it right now and I still haven’t decided if I will be more of a programmer or a graphic designer in the nearest future.

+

+

What genre(s) do you work in?

+

My artistic journey started with some simple and minimalistic illustrations – by keeping them so simple, I never got discouraged, as most beginners do, jumping straight into complex artworks. As my knowledge and experience grew, it all became more and more complicated, though the need to keep this feeling of simplicity in my artworks still remains.

+

Whose work inspires you most — who are your role models as an artist?

+

Vlad Gerasimov, founder of Vladstudio, was my first great inspiration – my minimalistic illustrations originated from his way of seeing the world. I think it is still a bit visible in my artworks, even though our ways parted long time ago, as I switched to a much different approach. Currently, I guess I’m more into David Revoy – his open source ideology – and Nathan Fowkes http://www.nathanfowkesart.com/, whose work, especially for the “How to train your dragon” movie, is for me the absolute level cap that an artist can achieve. Julia Blattman is also worth mentioning, as her artworks full of imagination remind me of what I felt looking at those Vladstudio illustrations long time ago.

+

How and when did you get to try digital painting for the first time?

+

As a kid, as many other kids, I used to love computer games – when I grew up a bit, I noticed that it was not the games I liked that much, but the worlds they took me to. When in 2011 I found out how you can use GIMP and a digital tablet to create something similar, it all began.

+

+

What makes you choose digital over traditional painting?

+

Making a lot of mess was always something that bothered me. I still remember how I hated art classes in primary school with kids covering every single thing in the room with paint. In digital painting you can always elegantly save and quit with your hands clean. While I still really enjoy sketching with pencil and pen, I’m afraid I will have a tough job to convince myself to use real paint again (as I know traditional media can give you a lot).

+

How did you find out about Krita?

+

It was 2015, I guess, when I read about it on David Revoy’s blog for the first time – I suppose many artists switched from GIMP to Krita somewhere in that time because of his support to the program.

+

What was your first impression?

+

Insanely laggy 😀 It took me one year to accidentally switch something in settings, that suddenly made it work normally. Luckily, with each update, it’s less likely for someone to have such a problem again. After I made my first artwork in 2016, Krita happened to exceed GIMP in any way possible. I fell in love instantly.

+

+

What do you love about Krita?

+

I love how Krita makes it possible for everyone to learn how to draw, while not wanting anything in exchange. It kind of restores my faith in humanity every time I think about it. It’s even harder to believe that developers manage to constantly update and improve it, while their budget and human resources are hard to compare with those that other art programs have.

+

What do you think needs improvement in Krita? Is there anything that really annoys you?

+

I don’t think there are too many flaws right now in the program itself. All the bugs I noticed in 2016 have been fixed by now. It also seems really stable on Kubuntu – the crashes are happening less often than in the past. Developers did a gorgeous job again and I guess, and with this whole “squash the bugs” campaign they really meant it.

+

The thing that bothers me though, is how Krita is sometimes perceived across the internet – some people think it is still laggy or full of bugs – maybe it used to be that way, but in my opinion changed a lot in recent years. Some others may underappreciate it, as Photoshop is still the standard required in the industry.

+

I’m really grateful for each and every artist who already helps to promote the program on social media and art-related websites, but I believe it still deserves more – more recognition, professional users, more mind-blowing, “Made in Krita” artworks that would inspire beginners, finally maybe even more donations for further development.

+

I try to promote it the best I can and it even encourages me to practice and improve as an artist, but I still think we lack some PR – come on guys. Let’s show what we can do with Krita 🙂

+

What sets Krita apart from the other tools that you use?

+

Actually I don’t use any other drawing application as I simply don’t need one. I think that says a lot about it. Krita still allows me to constantly develop, and I’m sure that the only thing now that limits me is my current lack of skills. But I’m constantly working on that.

+

If you had to pick one favourite of all your work done in Krita so far, what would it be, and why?

+

+

One of my most recent illustrations is “festival preparation” – it indicates the direction I want to go with my art – to improve in art foundations, while keeping it fun and full of imagination. A lot of things I studied recently were used here, and it seems it all went particularly well.

+

What techniques and brushes did you use in it?

+

By coincidence, this artwork was actually a final test of brushes I use, that recently had some serious modifications to them. As I like things simple, they don’t mess that much with brush tips and textures as most of presets available on the internet do, but are quite tricky in terms of dynamics – they can randomize rotation and colors to differentiate the strokes. You can actually check them out, as I made them available to use freely some time ago: [Link to brushes]

+

Where can people see more of your work?

+

I use artstation as my more refined portfolio and facebook for loose updates. Some of my older artworks can still be found on deviantArt.

+

https://www.facebook.com/trybus.wojciech
+https://www.artstation.com/wojtryb
+https://www.deviantart.com/wojtryb

+

Anything else you’d like to share?

+

Soon I’ll be graduating from college and there are lots of changes and decisions ahead of me for sure – keep your fingers crossed in case I need them to still make progress at the current pace and create the art I love 🙂

+]]>
+
+ + Help Beta Test Krita 4.2.6! + https://krita.org/en/item/help-beta-test-krita-4-2-6/ + Sat, 31 Aug 2019 10:00:56 +0000 + + + + https://krita.org/?p=9667 + + This will be the first Krita release since the big sprint. We’re aiming to do monthly bugfix releases again from now on! But we also want to cut down on the regressions that come with rapid development so we’re making beta releases again. Please help the team out and check these beta releases for bugs and regressions. Right there in the welcome screen is a link to a survey where you can give your feedback:

+

The survey idea is new — we want to get your impressions of what we’re about to release. If it works, we’ll be refining the surveys.

+

What’s new in 4.2.6?

+

New features:

+
    +
  • Add new layer from visible to layer right-click context menu.
  • +
  • When running Krita for the first time on Windows, Angle is now the default renderer. Note that if you have an NVidia GPU and Krita’s window is transparent, you need to select Angle manually in Krita’s settings; if you have another GPU and you have problems with the canvas not updating, you might need to manually select OpenGL in the same window.
  • +
+

We want to especially thank Karl Ove Hufthammer for his extensive work on polishing the translatable string.

+

Bugs fixed

+
    +
  • Allow selection overlay to be reset to default. (BUG:410470)
  • +
  • Set date for bundle creation to use ISO-Date. (BUG:410490)
  • +
  • Fix freeze with 32bit float tiff by using our own tiff reader for the thumbnails. (BUG:408731)
  • +
  • Ensure filter mask button is disabled appropriately depending on whether the filter supports it. (BUG:410374)
  • +
  • Enable the small color selector if opengles is available as well (BUG:410602)
  • +
  • Fix mixed Zoom, Pan, Rotate on macOS (BUG:410698)
  • +
  • Ensure that checkboxes are shown in menus even when using the fusion theme
  • +
  • Isolate Layer Crash (BUG:408785)
  • +
  • Properly fix font resetting when all the text in the editor removed (BUG:409243)
  • +
  • Fix lags in Move Tool when using tablet device (BUG:410838)
  • +
  • Fix Shift and Alt modifiers in Outline Selection Tool (BUG:410532)
  • +
  • Ensure Convert group to Animated Layer shows text in the toolbar. (BUG:410500)
  • +
  • Allow ‘Add Clone Layer’ to Work on Multiple Layers (BUG:373338)
  • +
  • Fix saving animated transparency masks created through conversion (BUG:409895)
  • +
  • Fix curve change despite ‘Use same curve’ checked (BUG:383909)
  • +
  • Try harder to make sure that the swap location is writable
  • +
  • Properly handle timezones in bundles
  • +
  • Allow ‘Add Clone Layer’ to Work on Multiple Layers (BUG:373338)
  • +
  • Fix saving animated transparency masks created through conversion (BUG:409895)
  • +
  • Make sure all the settings dialogs pages are always shown in the same order
  • +
  • Make the settings dialog fit in low-res screens (BUG:410793)
  • +
  • Remove misleading ‘px’ suffix for ‘move amount’ shortcut setting
  • +
  • Make string for reasons for image export problems translatable (BUG:406973)
  • +
  • Fix crash when creating a bezier curve (BUG:410572)
  • +
  • Fix deadlocks in KoShapeManager (BUG:410909, BUG:410572)
  • +
  • Fix a deadlock when using broken Wacom drivers on Linux (BUG:410797)
  • +
  • Fix absolute brush rotation on rotated canvas (BUG:292726)
  • +
  • Fix deadlock when removing reference image (BUG:411212)
  • +
  • Fix a deadlock in handling of vector objects (BUG:411365)
  • +
+

Download

+

Windows

+

For the beta, only portable zip files are available. Just open the zip file in Explorer and drag the folder somewhere convenient, then double-click on the krita icon in the folder. This will not impact an installed version of Krita, though it will share your settings and custom resources with your regular installed version of Krita. For reporting crashes, also get the debug symbols folder.

+ + +

Linux

+ +

(If, for some reason, Firefox thinks it needs to load this as text: to download, right-click on the link.)

+

OSX

+ +

Note: the gmic-qt is not available on OSX.

+

Source code

+ +

md5sum

+

For all downloads:

+ +

Support Krita

+

Krita is a free and open source project. Please consider supporting the project with donations or by buying training videos or the artbook! With your support, we can keep the core team working on Krita full-time.

+

 

+]]>
+
+ + Mounamnamat Médias Teaches Animation using Krita + https://krita.org/en/item/mounamnamat-medias-teaches-animation-using-krita/ + Thu, 29 Aug 2019 09:20:27 +0000 + + + + https://krita.org/?p=9689 + + Amine Sossi Alaoui and Sonia Didier write to tell us about their experience teaching children 2D animation using Krita, with some very cool results:

+

We’re a Moroccan animation studio, created 6 months ago and based in Rabat, Morocco. Before that we worked in animation studios in France during 10 years. Our goal now is to develop animation industry in Morocco and Africa. It’s a long way to go, and for the moment, we’re just beginning with 2d animation. Krita is a great tool for that, and we’re very happy to use it, and to share the knowledge we have about it.

+

So, this summer, we wanted children to learn about 2D animation, so we created an one-week animation course for children from 8 to 14 years old. It was 2 hours per day during 5 days, for a group of 8 to 12 children. The goal was to create an one-minute animated shortfilm in 2D, from the writing of the story, storyboard, background, animation, colorisation and compositing.

+

For that we chose to use Krita (and Shotcut for the final compositing and sound). It’s great software, very complete and fun to work with. And as it’s free, we’re sure that the children could use it at home if they like, to make their own projects.

+

Finally, four groups of children have worked on Krita this summer, and the result is on Youtube for anyone to watch on our youtube channel. Here are the first three films; the fourth film is not yet on youtube. Should be shortly, when it’s finalized.

+

We hope you’ll all like it !

+

+

+

+

Now we hope that we’ll have others projects with Krita, and we’ll be happy
+to share them with you.

+]]>
+
+ + Interview with Chayse Goodall + https://krita.org/en/item/interview-with-chayse-goodall/ + Mon, 19 Aug 2019 08:00:17 +0000 + + + + https://krita.org/?p=9642 + + +

Could you tell us something about yourself?

+

Hi, my name is Chayse Goodall. I am 14 years old. I just draw for fun!

+

Do you paint professionally, as a hobby artist, or both?

+

I do animate and draw for a hobby. My artwork improves little by little, but I don’t think it’ll be good enough for a profession!

+

What genre(s) do you work in?

+

I don’t know what my style is, but people tell me that I have an anime style.

+

Whose work inspires you most — who are your role models as an artist?

+

I have many inspirers, two of which was my art teachers, and one of which was my math tutor. They both motivate me to keep going with my progress.

+

How and when did you get to try digital painting for the first time?

+

I tried digital art in 2015. I only had a phone at the time, so it was hard at first. It’s a million times better now, and I have a touch screen computer, so I’ve been trying different art programs!

+

What makes you choose digital over traditional painting?

+

There are more tools, and there is an undo button!

+

How did you find out about Krita?

+

I was looking up free art programs, and stumbled across this program.

+

What was your first impression?

+

My experience was great! It was easy to follow once you get the hang of it!

+

What do you love about Krita?

+

All the brushes and how easy it is to save.

+

What do you think needs improvement in Krita? Is there anything that really annoys you?

+

It is a bit confusing and it looks complex to newcomers.

+

What sets Krita apart from the other tools that you use?

+

It has amazing features and it doesn’t require me to “sign up” or pay for anything!

+

If you had to pick one favourite of all your work done in Krita so far, what would it be, and why?

+

I only made one picture. She doesn’t have a name, she was just a test character to see how good the program was. (It came out great!)

+

What techniques and brushes did you use in it?

+

I normally draw the sketch first in a dark red color. Then I draw the plain body in a light green. I sketch the clothes, hair, and accessories on in a neon color.

+

I just use the pen for coloring and shading.

+

Where can people see more of your work?

+

My instagram- panstables
+My youtube- Nubbins

+]]>
+
+
+
+ + \ No newline at end of file diff --git a/libs/ui/utils/KisAppimageUpdater.cpp b/libs/ui/utils/KisAppimageUpdater.cpp new file mode 100644 index 0000000000..845c923f93 --- /dev/null +++ b/libs/ui/utils/KisAppimageUpdater.cpp @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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 "KisAppimageUpdater.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +KisAppimageUpdater::KisAppimageUpdater() + : m_checkProcess(new QProcess(this)) + , m_updateProcess(new QProcess(this)) +{ + QString updaterPath; + +#if defined(KRITA_GIT_SHA1_STRING) + if (qEnvironmentVariableIsSet("KRITA_APPIMAGEUPDATER_USE_DUMMY")) { + updaterPath = QString("%1%2AppImageUpdateDummy") + .arg(QCoreApplication::applicationDirPath()) + .arg(QDir::separator()); + } else { + updaterPath = QString("%1%2AppImageUpdate") + .arg(QCoreApplication::applicationDirPath()) + .arg(QDir::separator()); + } +#else + updaterPath = QString("%1%2AppImageUpdate") + .arg(QCoreApplication::applicationDirPath()) + .arg(QDir::separator()); +#endif + + initialize(updaterPath); +} + +#if defined(KRITA_GIT_SHA1_STRING) +KisAppimageUpdater::KisAppimageUpdater(QString dummyUpdaterPath) + : m_checkProcess(new QProcess(this)) + , m_updateProcess(new QProcess(this)) +{ + initialize(dummyUpdaterPath); +} +#endif + +void KisAppimageUpdater::checkForUpdate() +{ + if (m_updaterInProgress) { + return; + } + + if (!m_updateCapability) { + return; + } + + // reset output for subsequent checks, is this needed? + m_checkOutput = QString(); + m_updateOutput = QString(); + m_updaterStatus.setUpdaterOutput(QString()); + + QStringList args = QStringList() << "--check-for-update" << m_appimagePath; + + m_checkProcess->start(m_updaterBinary, args); + m_updaterInProgress = true; +} + +bool KisAppimageUpdater::hasUpdateCapability() +{ + return m_updateCapability; +} + +void KisAppimageUpdater::doUpdate() +{ + QStringList args = QStringList() << m_appimagePath; + m_updateProcess->start(m_updaterBinary, args); +} + +void KisAppimageUpdater::slotUpdateCheckFinished(int result, QProcess::ExitStatus exitStatus) +{ + KisUsageLogger::log( + QString("KisAppimageUpdater: update check finished. Result: %1 Exit status: %2\npath: %3\noutput: %4") + .arg(result) + .arg(exitStatus) + .arg(m_appimagePath) + .arg(m_updateOutput) + ); + + UpdaterStatus::StatusID updateStatus; + + if (exitStatus == QProcess::CrashExit) { + updateStatus = UpdaterStatus::StatusID::CHECK_ERROR; + + } else { + switch (result) { + case 0: + updateStatus = UpdaterStatus::StatusID::UPTODATE; + break; + case 1: + updateStatus = UpdaterStatus::StatusID::UPDATE_AVAILABLE; + break; + case 2: + updateStatus = UpdaterStatus::StatusID::CHECK_ERROR; + break; + default: + // some errors have exit code of 255 (modified by system, when AppImageUpdate returns -1) + // one source of 255 is when the AppImage does not contain update information + updateStatus = UpdaterStatus::StatusID::CHECK_ERROR; + break; + } + } + + m_updaterInProgress = false; + + m_updaterStatus.setStatus(updateStatus); + m_updaterStatus.setUpdaterOutput(m_updateOutput); + + emit sigUpdateCheckStateChange(m_updaterStatus); +} + +void KisAppimageUpdater::slotUpdateCheckStarted() +{ + m_updaterStatus.setStatus(UpdaterStatus::StatusID::IN_PROGRESS); + emit sigUpdateCheckStateChange(m_updaterStatus); +} + +void KisAppimageUpdater::slotUpdateCheckErrorOccurred(QProcess::ProcessError error) +{ + KisUsageLogger::log( + QString("KisAppimageUpdater: error occurred during update check: %1\npath: %2\noutput: %3") + .arg(error) + .arg(m_appimagePath) + .arg(m_checkOutput) + ); + + m_updaterInProgress = false; + + m_updaterStatus.setStatus(UpdaterStatus::StatusID::CHECK_ERROR); + + emit sigUpdateCheckStateChange(m_updaterStatus); +} + +void KisAppimageUpdater::slotUpdateFinished(int result, QProcess::ExitStatus exitStatus) +{ + KisUsageLogger::log( + QString("KisAppimageUpdater: update finished. Result: %1\nExit status: %2\npath: %3\noutput: %4") + .arg(result) + .arg(exitStatus) + .arg(m_appimagePath) + .arg(m_updateOutput) + ); + + UpdaterStatus::StatusID updateStatus; + QFileInfo finfoAppImagePath(m_appimagePath); + QString statusDetails; + + if (exitStatus == QProcess::CrashExit) { + updateStatus = UpdaterStatus::StatusID::UPDATE_ERROR; + + } else { + switch (result) { + case 0: + updateStatus = UpdaterStatus::StatusID::RESTART_REQUIRED; + statusDetails = i18n("New AppImage was downloaded to %1. To complete the update, close Krita and run the new AppImage.", finfoAppImagePath.path()); + break; + default: + // some errors have exit code of 255 (modified by system, when AppImageUpdate returns -1) + updateStatus = UpdaterStatus::StatusID::UPDATE_ERROR; + break; + } + } + + m_updaterInProgress = false; + + m_updaterStatus.setStatus(updateStatus); + m_updaterStatus.setUpdaterOutput(m_updateOutput); + m_updaterStatus.setDetails(statusDetails); + + emit sigUpdateCheckStateChange(m_updaterStatus); +} + +void KisAppimageUpdater::slotUpdateErrorOccurred(QProcess::ProcessError error) +{ + KisUsageLogger::log( + QString("KisAppimageUpdater: error occurred during update: %1\npath: %2\noutput: %3") + .arg(error) + .arg(m_appimagePath) + .arg(m_updateOutput) + ); + + m_updaterInProgress = false; + + m_updaterStatus.setStatus(UpdaterStatus::StatusID::UPDATE_ERROR); + m_updaterStatus.setUpdaterOutput(m_updateOutput); + + emit sigUpdateCheckStateChange(m_updaterStatus); +} + +void KisAppimageUpdater::slotAppendCheckOutput() +{ + m_checkOutput.append(m_checkProcess->readAllStandardOutput()); +} + +void KisAppimageUpdater::slotAppendUpdateOutput() +{ + m_updateOutput.append(m_updateProcess->readAllStandardOutput()); +} + +void KisAppimageUpdater::initialize(QString& updaterPath) +{ + m_appimagePath = qEnvironmentVariable("APPIMAGE"); + m_updaterBinary = updaterPath; + + m_updateCapability = findUpdaterBinary(); + + m_checkProcess->setProcessChannelMode(QProcess::MergedChannels); + m_updateProcess->setProcessChannelMode(QProcess::MergedChannels); + + connect(m_checkProcess.data(), SIGNAL(started()), this, SLOT(slotUpdateCheckStarted())); + connect(m_checkProcess.data(), SIGNAL(errorOccurred(QProcess::ProcessError)), + this, SLOT(slotUpdateCheckErrorOccurred(QProcess::ProcessError))); + connect(m_checkProcess.data(), SIGNAL(finished(int, QProcess::ExitStatus)), + this, SLOT(slotUpdateCheckFinished(int, QProcess::ExitStatus))); + connect(m_checkProcess.data(), SIGNAL(readyReadStandardOutput()), + this, SLOT(slotAppendCheckOutput())); + + + connect(m_updateProcess.data(), SIGNAL(errorOccurred(QProcess::ProcessError)), + this, SLOT(slotUpdateErrorOccurred(QProcess::ProcessError))); + connect(m_updateProcess.data(), SIGNAL(finished(int, QProcess::ExitStatus)), + this, SLOT(slotUpdateFinished(int, QProcess::ExitStatus))); + connect(m_updateProcess.data(), SIGNAL(readyReadStandardOutput()), + this, SLOT(slotAppendUpdateOutput())); +} + +bool KisAppimageUpdater::findUpdaterBinary() +{ + QFileInfo finfo(m_updaterBinary); + if (finfo.isExecutable()) { + return true; + } else { + KisUsageLogger::log( + QString("KisAppimageUpdater: AppImageUpdate (%1) was not found within the Krita appimage, or is not executable") + .arg(m_updaterBinary) + ); + return false; + } +} diff --git a/libs/ui/utils/KisAppimageUpdater.h b/libs/ui/utils/KisAppimageUpdater.h new file mode 100644 index 0000000000..1c8947ca34 --- /dev/null +++ b/libs/ui/utils/KisAppimageUpdater.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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. + */ + + +#ifndef KISAPPIMAGEUPDATER_H +#define KISAPPIMAGEUPDATER_H + +#include +#include +#include + +#include + +#include "kritaui_export.h" + + +class QString; + +class KRITAUI_EXPORT KisAppimageUpdater : public KisUpdaterBase +{ + Q_OBJECT + +public: + KisAppimageUpdater(); +#ifdef KRITA_GIT_SHA1_STRING + explicit KisAppimageUpdater(QString dummyUpdaterPath); +#endif + + void checkForUpdate() override; + bool hasUpdateCapability() override; + void doUpdate() override; + +private Q_SLOTS: + void slotUpdateCheckFinished(int result, QProcess::ExitStatus exitStatus); + void slotUpdateCheckStarted(); + void slotUpdateCheckErrorOccurred(QProcess::ProcessError error); + + void slotUpdateFinished(int result, QProcess::ExitStatus exitStatus); + void slotUpdateErrorOccurred(QProcess::ProcessError error); + + void slotAppendCheckOutput(); + void slotAppendUpdateOutput(); + +private: + void initialize(QString& updaterPath); + + bool findUpdaterBinary(); + QString m_updaterBinary; + QString m_appimagePath; + bool m_updateCapability; + bool m_updaterInProgress {false}; + QString m_checkOutput; + QString m_updateOutput; + + QScopedPointer m_checkProcess; + QScopedPointer m_updateProcess; +}; + +#endif // KISAPPIMAGEUPDATER_H diff --git a/libs/ui/utils/KisManualUpdater.cpp b/libs/ui/utils/KisManualUpdater.cpp new file mode 100644 index 0000000000..982bc6e7af --- /dev/null +++ b/libs/ui/utils/KisManualUpdater.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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 "KisManualUpdater.h" +#include +#include + +#include +#include +#include +#include + +#include + + +KisManualUpdater::KisManualUpdater() + : m_currentVersion(KritaVersionWrapper::versionString()) +{ + m_rssModel.reset(new MultiFeedRssModel()); +} + +KisManualUpdater::KisManualUpdater(MultiFeedRssModel* rssModel, QString ¤tVersion) + : m_currentVersion(currentVersion) +{ + m_rssModel.reset(rssModel); +} + +void KisManualUpdater::checkForUpdate() +{ +// m_rssModel->addFeed(QLatin1String("https://krita.org/en/feed/")); + m_rssModel->addFeed(QLatin1String("http://localhost/feed.xml")); + connect(m_rssModel.data(), SIGNAL(feedDataChanged()), this, SLOT(rssDataChanged())); +} + +void KisManualUpdater::rssDataChanged() +{ + // grab the latest release post and URL for reference later + // if we need to update + QString availableVersion; + QString downloadLink; + + for (int i = 0; i < m_rssModel->rowCount(); i++) { + const QModelIndex &idx = m_rssModel->index(i); + + if (idx.isValid()) { + // only use official release announcements to get version number + if ( idx.data(KisRssReader::RssRoles::CategoryRole).toString() != "Official Release") { + continue; + } + + QString linkTitle = idx.data(KisRssReader::RssRoles::TitleRole).toString(); + + // regex to capture version number + QRegularExpression versionRegex("\\d\\.\\d\\.?\\d?\\.?\\d"); + QRegularExpressionMatch matched = versionRegex.match(linkTitle); + + // only take the top match for release version since that is the newest + if (matched.hasMatch()) { + availableVersion = matched.captured(0); + downloadLink = idx.data(KisRssReader::RssRoles::LinkRole).toString(); + break; + } + } + } + + UpdaterStatus::StatusID status; + + if (availableVersionIsHigher(m_currentVersion, availableVersion)) { + status = UpdaterStatus::StatusID::UPDATE_AVAILABLE; + } else { + status = UpdaterStatus::StatusID::UPTODATE; + } + + m_updaterStatus.setStatus(status); + m_updaterStatus.setAvailableVersion(availableVersion); + m_updaterStatus.setDownloadLink(downloadLink); + + emit sigUpdateCheckStateChange(m_updaterStatus); +} + +bool KisManualUpdater::availableVersionIsHigher(QString currentVersion, QString availableVersion) +{ + if (currentVersion.isEmpty() || availableVersion.isEmpty()) { + return false; + } + + int currentSuffixIndex {5}; + int availableSuffixIndex {5}; + + QVersionNumber currentVersionNumber = QVersionNumber::fromString(currentVersion, ¤tSuffixIndex); + QVersionNumber availableVersionNumber = QVersionNumber::fromString(availableVersion, &availableSuffixIndex); + + QString currentSuffix = currentVersion.mid(currentSuffixIndex); + QString availableSuffix = availableVersion.mid(availableSuffixIndex); + + if (currentVersionNumber.normalized() == availableVersionNumber.normalized()) { + if (!currentSuffix.isEmpty() && availableSuffix.isEmpty()) { + return true; + } else { + return false; + } + } else { + return (currentVersionNumber.normalized() < availableVersionNumber.normalized()); + } +} diff --git a/libs/ui/utils/KisManualUpdater.h b/libs/ui/utils/KisManualUpdater.h new file mode 100644 index 0000000000..c29847aaeb --- /dev/null +++ b/libs/ui/utils/KisManualUpdater.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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. + */ + + +#ifndef KISMANUALUPDATER_H +#define KISMANUALUPDATER_H + +#include + +#include +#include +#include "kritaui_export.h" + + +class KRITAUI_EXPORT KisManualUpdater : public KisUpdaterBase +{ + Q_OBJECT + +public: + KisManualUpdater(); + /** + * @brief KisManualUpdater - constructor for testing + * @param rssModel + * @param currentVersion + */ + explicit KisManualUpdater(MultiFeedRssModel* rssModel, QString& currentVersion); + + void checkForUpdate() override; + + // this updater can only check for updates + /** + * @brief the manual updater can only check for available versions + * @return false + */ + inline bool hasUpdateCapability() override { return false; } + inline void doUpdate() override { return; } + +public Q_SLOTS: + void rssDataChanged(); + +private: + bool availableVersionIsHigher(QString currentVersion, QString availableVersion); + + QScopedPointer m_rssModel; + QString m_currentVersion; + + friend class KisManualUpdaterTest; +}; + +#endif // KISMANUALUPDATER_H diff --git a/libs/ui/utils/KisUpdaterBase.cpp b/libs/ui/utils/KisUpdaterBase.cpp new file mode 100644 index 0000000000..cd4daf4e04 --- /dev/null +++ b/libs/ui/utils/KisUpdaterBase.cpp @@ -0,0 +1,6 @@ +#include "KisUpdaterBase.h" + +KisUpdaterBase::KisUpdaterBase() +{ + +} diff --git a/libs/ui/utils/KisUpdaterBase.h b/libs/ui/utils/KisUpdaterBase.h new file mode 100644 index 0000000000..c79c85fda0 --- /dev/null +++ b/libs/ui/utils/KisUpdaterBase.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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. + */ + + +#ifndef KISUPDATERBASE_H +#define KISUPDATERBASE_H + +#include +#include + +class QString; + +class KisUpdaterBase : public QObject +{ + Q_OBJECT + +public: + KisUpdaterBase(); + + /** + * @brief start the process checking whether there is an update available or not + * When the check is done, the updater emits sigUpdateCheckStateChange with the check result + */ + virtual void checkForUpdate() = 0; + + /** + * @brief Returns true if this updater can actually perform an update. + * If it can only check for new versions, return false. + * @return bool + */ + virtual bool hasUpdateCapability() = 0; + + /** + * @brief if the updater has update capability, start the update process + * When the update is done, the updater emits sigUpdateCheckStateChange with the check result + */ + virtual void doUpdate() = 0; + +Q_SIGNALS: + void sigUpdateCheckStateChange(KisUpdaterStatus); + +protected: + KisUpdaterStatus m_updaterStatus; +}; + +#endif // KISUPDATERBASE_H diff --git a/libs/ui/utils/KisUpdaterStatus.cpp b/libs/ui/utils/KisUpdaterStatus.cpp new file mode 100644 index 0000000000..93ead4e51e --- /dev/null +++ b/libs/ui/utils/KisUpdaterStatus.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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 "KisUpdaterStatus.h" +#include + +KisUpdaterStatus::KisUpdaterStatus() +{ + +} + +KisUpdaterStatus::KisUpdaterStatus(const KisUpdaterStatus& rhs) + : QObject(0) + , m_status(rhs.m_status) + , m_availableVersion(rhs.m_availableVersion) + , m_downloadLink(rhs.m_downloadLink) + , m_updaterOutput(rhs.m_updaterOutput) + , m_details(rhs.m_details) +{ + +} + +KisUpdaterStatus::~KisUpdaterStatus() +{ + +} + +UpdaterStatus::StatusID KisUpdaterStatus::status() { + return m_status; +} + +QString KisUpdaterStatus::availableVersion() { + return m_availableVersion; +} + +QString KisUpdaterStatus::downloadLink() { + return m_downloadLink; +} + +QString KisUpdaterStatus::updaterOutput() { + return m_updaterOutput; +} + +QString KisUpdaterStatus::details() +{ + return m_details; +} + +void KisUpdaterStatus::setStatus(const UpdaterStatus::StatusID& status) +{ + m_status = status; +} + +void KisUpdaterStatus::setAvailableVersion(const QString& availableVersion) +{ + m_availableVersion = availableVersion; +} + +void KisUpdaterStatus::setDownloadLink(const QString& downloadLink) +{ + m_downloadLink = downloadLink; +} + +void KisUpdaterStatus::setUpdaterOutput(const QString& updaterOutput) +{ + m_updaterOutput = updaterOutput; +} + +void KisUpdaterStatus::setDetails(const QString& details) +{ + m_details = details; +} + +KisUpdaterStatus& KisUpdaterStatus::operator=(KisUpdaterStatus& secondArg) +{ + m_status = secondArg.status(); + m_availableVersion = secondArg.availableVersion(); + m_downloadLink = secondArg.downloadLink(); + m_updaterOutput = secondArg.updaterOutput(); + m_details = secondArg.details(); + + return *this; +} + +bool KisUpdaterStatus::operator==(KisUpdaterStatus& secondArg) +{ + if (m_status == secondArg.status()) { + return true; + } else { + return false; + } +} diff --git a/libs/ui/utils/KisUpdaterStatus.h b/libs/ui/utils/KisUpdaterStatus.h new file mode 100644 index 0000000000..3492675f52 --- /dev/null +++ b/libs/ui/utils/KisUpdaterStatus.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * 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. + */ + + +#ifndef KISUPDATERSTATUS_H +#define KISUPDATERSTATUS_H + +#include +#include +#include + +#include "kritaui_export.h" + + +namespace UpdaterStatus { + + enum class KRITAUI_EXPORT StatusID { + UPTODATE, + UPDATE_AVAILABLE, + CHECK_ERROR, + UPDATE_ERROR, + IN_PROGRESS, + RESTART_REQUIRED, + INITIALIZED + }; + +} + +Q_DECLARE_METATYPE(UpdaterStatus::StatusID); + + +class KRITAUI_EXPORT KisUpdaterStatus : public QObject +{ + Q_OBJECT + +public: + KisUpdaterStatus(); + KisUpdaterStatus(const KisUpdaterStatus& rhs); + ~KisUpdaterStatus(); + + UpdaterStatus::StatusID status(); + QString availableVersion(); + QString downloadLink(); + QString updaterOutput(); + QString details(); + + void setStatus(const UpdaterStatus::StatusID& status); + void setAvailableVersion(const QString& availableVersion); + void setDownloadLink(const QString& downloadLink); + void setUpdaterOutput(const QString& updaterOutput); + void setDetails(const QString& details); + + KisUpdaterStatus& operator=(KisUpdaterStatus& secondArg); + bool operator==(KisUpdaterStatus& secondArg); + +private: + UpdaterStatus::StatusID m_status { UpdaterStatus::StatusID::INITIALIZED }; + QString m_availableVersion; + QString m_downloadLink; + QString m_updaterOutput; + QString m_details; +}; + +Q_DECLARE_METATYPE(KisUpdaterStatus); + +#endif // KISUPDATERSTATUS_H diff --git a/libs/ui/widgets/KisNewsWidget.cpp b/libs/ui/widgets/KisNewsWidget.cpp index bf9207aa84..f35c7f680e 100644 --- a/libs/ui/widgets/KisNewsWidget.cpp +++ b/libs/ui/widgets/KisNewsWidget.cpp @@ -1,229 +1,144 @@ /* * Copyright (c) 2018 boud * * 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 "KisNewsWidget.h" #include #include #include #include #include #include #include #include "kis_config.h" #include "KisMultiFeedRSSModel.h" #include "QRegularExpression" KisNewsDelegate::KisNewsDelegate(QObject *parent) : QStyledItemDelegate(parent) { } void KisNewsDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { painter->save(); QStyleOptionViewItem optionCopy = option; initStyleOption(&optionCopy, index); QStyle *style = optionCopy.widget? optionCopy.widget->style() : QApplication::style(); QTextDocument doc; doc.setHtml(optionCopy.text); doc.setDocumentMargin(10); /// Painting item without text optionCopy.text = QString(); style->drawControl(QStyle::CE_ItemViewItem, &optionCopy, painter); QAbstractTextDocumentLayout::PaintContext ctx; // Highlighting text if item is selected if (optionCopy.state & QStyle::State_Selected) { ctx.palette.setColor(QPalette::Text, optionCopy.palette.color(QPalette::Active, QPalette::HighlightedText)); } painter->translate(optionCopy.rect.left(), optionCopy.rect.top()); QRect clip(0, 0, optionCopy.rect.width(), optionCopy.rect.height()); doc.setPageSize(clip.size()); doc.drawContents(painter, clip); painter->restore(); } QSize KisNewsDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem optionCopy = option; initStyleOption(&optionCopy, index); QTextDocument doc; doc.setHtml(optionCopy.text); doc.setTextWidth(optionCopy.rect.width()); return QSize(doc.idealWidth(), doc.size().height()); } KisNewsWidget::KisNewsWidget(QWidget *parent) : QWidget(parent) , m_getNews(false) , m_rssModel(0) - , m_needsVersionUpdate(false) { setupUi(this); m_rssModel = new MultiFeedRssModel(this); connect(m_rssModel, SIGNAL(feedDataChanged()), this, SLOT(rssDataChanged())); setCursor(Qt::PointingHandCursor); listNews->setModel(m_rssModel); listNews->setItemDelegate(new KisNewsDelegate(listNews)); connect(listNews, SIGNAL(clicked(QModelIndex)), this, SLOT(itemSelected(QModelIndex))); } void KisNewsWidget::setAnalyticsTracking(QString text) { m_analyticsTrackingParameters = text; } -bool KisNewsWidget::hasUpdateAvailable() -{ - return m_needsVersionUpdate; -} - -QString KisNewsWidget::versionNumber() -{ - return m_newVersionNumber; -} - -QString KisNewsWidget::versionLink() -{ - return m_newVersionLink; -} - void KisNewsWidget::toggleNews(bool toggle) { KisConfig cfg(false); cfg.writeEntry("FetchNews", toggle); if (toggle) { - m_rssModel->addFeed(QLatin1String("https://krita.org/en/feed/")); +// m_rssModel->addFeed(QLatin1String("https://krita.org/en/feed/")); + m_rssModel->addFeed(QLatin1String("http://localhost/feed.xml")); } else { - m_rssModel->removeFeed(QLatin1String("https://krita.org/en/feed/")); +// m_rssModel->removeFeed(QLatin1String("https://krita.org/en/feed/")); + m_rssModel->removeFeed(QLatin1String("http://localhost/feed.xml")); } } void KisNewsWidget::itemSelected(const QModelIndex &idx) { if (idx.isValid()) { - QString link = idx.data(RssRoles::LinkRole).toString(); + QString link = idx.data(KisRssReader::RssRoles::LinkRole).toString(); // append query string for analytics tracking if we set it if (m_analyticsTrackingParameters != "") { // use title in analytics query string - QString linkTitle = idx.data(RssRoles::TitleRole).toString(); + QString linkTitle = idx.data(KisRssReader::RssRoles::TitleRole).toString(); linkTitle = linkTitle.simplified(); // trims and makes 1 white space linkTitle = linkTitle.replace(" ", ""); m_analyticsTrackingParameters = m_analyticsTrackingParameters.append(linkTitle); QDesktopServices::openUrl(QUrl(link.append(m_analyticsTrackingParameters))); } else { QDesktopServices::openUrl(QUrl(link)); } } } void KisNewsWidget::rssDataChanged() { - - // grab the latest release post and URL for reference later - // if we need to update - for (int i = 0; i < m_rssModel->rowCount(); i++) - { - const QModelIndex &idx = m_rssModel->index(i); - - if (idx.isValid()) { - - // only use official release announcements to get version number - if ( idx.data(RssRoles::CategoryRole).toString() != "Official Release") { - continue; - } - - QString linkTitle = idx.data(RssRoles::TitleRole).toString(); - - // regex to capture version number - QRegularExpression versionRegex("\\d\\.\\d\\.?\\d?\\.?\\d"); - QRegularExpressionMatch matched = versionRegex.match(linkTitle); - - // only take the top match for release version since that is the newest - if (matched.hasMatch()) { - m_newVersionNumber = matched.captured(0); - m_newVersionLink = idx.data(RssRoles::LinkRole).toString(); - break; - } - } - } - - // see if we need to update our version, or we are on a dev version - calculateVersionUpdateStatus(); - emit newsDataChanged(); } - -void KisNewsWidget::calculateVersionUpdateStatus() -{ - // do nothing if we are in dev version. - QString currentVersionString = qApp->applicationVersion(); - if (currentVersionString.contains("git")) { - return; - } - - QList currentVersionParts; - Q_FOREACH (QString number, currentVersionString.split(".")) { - currentVersionParts.append(number.toInt()); - } - - QList onlineReleaseAnnouncement; - Q_FOREACH (QString number, m_newVersionNumber.split(".")) { - onlineReleaseAnnouncement.append(number.toInt()); - } - - while (onlineReleaseAnnouncement.size() < 4) { - onlineReleaseAnnouncement.append(0); - } - - while (currentVersionParts.size() < 4) { - currentVersionParts.append(0); - } - - // Check versions from mayor to minor - // We don't assume onlineRelease version is always equal or higher. - bool makeUpdate = true; - for (int i = 0; i <= 3; i++) { - if (onlineReleaseAnnouncement.at(i) > currentVersionParts.at(i)) { - m_needsVersionUpdate = (true & makeUpdate); - return; - } else if (onlineReleaseAnnouncement.at(i) < currentVersionParts.at(i)) { - makeUpdate &= false; - } - } -} diff --git a/libs/ui/widgets/KisNewsWidget.h b/libs/ui/widgets/KisNewsWidget.h index 71dba10506..46aa55e8c4 100644 --- a/libs/ui/widgets/KisNewsWidget.h +++ b/libs/ui/widgets/KisNewsWidget.h @@ -1,79 +1,63 @@ /* * Copyright (c) 2018 boud * * 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. */ #ifndef KISNEWSWIDGET_H #define KISNEWSWIDGET_H #include #include #include #include class MultiFeedRssModel; class KisNewsDelegate : public QStyledItemDelegate { Q_OBJECT public: KisNewsDelegate(QObject *parent = 0); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; /** * @brief The KisNewsWidget class shows the latest news from Krita.org */ class KisNewsWidget : public QWidget, public Ui::KisNewsPage { Q_OBJECT public: explicit KisNewsWidget(QWidget *parent = nullptr); void setAnalyticsTracking(QString text); - bool hasUpdateAvailable(); - QString versionNumber(); - QString versionLink(); - Q_SIGNALS: void newsDataChanged(); private Q_SLOTS: void toggleNews(bool toggle); void itemSelected(const QModelIndex &idx); void rssDataChanged(); private: - // do version compare to see if there is a new version available - void calculateVersionUpdateStatus(); - -private: - bool m_getNews; - MultiFeedRssModel *m_rssModel; + bool m_getNews {false}; + MultiFeedRssModel *m_rssModel {0}; QString m_analyticsTrackingParameters; - - /// for new Krita version notification - QString m_newVersionNumber; - QString m_newVersionLink; - - // version checking logic tells us we need to update our Krita - bool m_needsVersionUpdate; - }; #endif // KISNEWSWIDGET_H diff --git a/packaging/linux/appimage/build-image.sh b/packaging/linux/appimage/build-image.sh index 345dc4ace9..d70cc23564 100755 --- a/packaging/linux/appimage/build-image.sh +++ b/packaging/linux/appimage/build-image.sh @@ -1,110 +1,155 @@ #!/bin/bash # Halt on errors and be verbose about what we are doing -set -e +#set -e set -x # Read in our parameters export BUILD_PREFIX=$1 export KRITA_SOURCES=$2 # Save some frequently referenced locations in variables for ease of use / updating export APPDIR=$BUILD_PREFIX/krita.appdir export PLUGINS=$APPDIR/usr/lib/kritaplugins/ -# qjsonparser, used to add metadata to the plugins needs to work in a en_US.UTF-8 environment. +# qjsonparser, used to add metadata to the plugins needs to work in a en_US.UTF-8 environment. # That's not always the case, so make sure it is export LC_ALL=en_US.UTF-8 export LANG=en_us.UTF-8 # We want to use $prefix/deps/usr/ for all our dependencies export DEPS_INSTALL_PREFIX=$BUILD_PREFIX/deps/usr/ export DOWNLOADS_DIR=$BUILD_PREFIX/downloads/ # Setup variables needed to help everything find what we built export LD_LIBRARY_PATH=$DEPS_INSTALL_PREFIX/lib/:$DEPS_INSTALL_PREFIX/lib/x86_64-linux-gnu/:$APPDIR/usr/lib/:$LD_LIBRARY_PATH export PATH=$DEPS_INSTALL_PREFIX/bin/:$PATH export PKG_CONFIG_PATH=$DEPS_INSTALL_PREFIX/share/pkgconfig/:$DEPS_INSTALL_PREFIX/lib/pkgconfig/:/usr/lib/pkgconfig/:$PKG_CONFIG_PATH export CMAKE_PREFIX_PATH=$DEPS_INSTALL_PREFIX:$CMAKE_PREFIX_PATH export PYTHONPATH=$DEPS_INSTALL_PREFIX/sip/:$DEPS_INSTALL_PREFIX/lib/python3.8/site-packages/:$DEPS_INSTALL_PREFIX/lib/python3.8/ export PYTHONHOME=$DEPS_INSTALL_PREFIX +# download +mkdir -p $DOWNLOADS_DIR +cd $DOWNLOADS_DIR +wget "https://files.kde.org/krita/build/AppImageUpdate-x86_64.AppImage" -O AppImageUpdate +echo -n "ebc4763e8eac6aa7b9dfcbea77ec07d2e01fa1b9f10a38d4af0fc040bc965c1f AppImageUpdate" | sha256sum -c - + # Switch over to our build prefix cd $BUILD_PREFIX # # Now we can get the process started! # # Step 0: place the translations where ki18n and Qt look for them if [ -d $APPDIR/usr/share/locale ] ; then mv $APPDIR/usr/share/locale $APPDIR/usr/share/krita fi -# Step 1: Copy over all the resources provided by dependencies that we need +# Step 1: Copy over all the resources provided by dependencies that we need cp -r $DEPS_INSTALL_PREFIX/share/locale $APPDIR/usr/share/krita cp -r $DEPS_INSTALL_PREFIX/share/kf5 $APPDIR/usr/share cp -r $DEPS_INSTALL_PREFIX/share/mime $APPDIR/usr/share cp -r $DEPS_INSTALL_PREFIX/lib/python3.8 $APPDIR/usr/lib cp -r $DEPS_INSTALL_PREFIX/share/sip $APPDIR/usr/share cp -r $DEPS_INSTALL_PREFIX/translations $APPDIR/usr/ # Step 2: Relocate x64 binaries from the architecture specific directory as required for Appimages mv $APPDIR/usr/lib/x86_64-linux-gnu/* $APPDIR/usr/lib rm -rf $APPDIR/usr/lib/x86_64-linux-gnu/ # Step 3: Update the rpath in the various plugins we have to make sure they'll be loadable in an Appimage context for lib in $PLUGINS/*.so*; do - patchelf --set-rpath '$ORIGIN/..' $lib; + patchelf --set-rpath '$ORIGIN/..' $lib; done for lib in $APPDIR/usr/lib/python3.8/site-packages/PyQt5/*.so*; do patchelf --set-rpath '$ORIGIN/../..' $lib; done for lib in $APPDIR/usr/lib/python3.8/lib-dynload/*.so*; do patchelf --set-rpath '$ORIGIN/../..' $lib; done patchelf --set-rpath '$ORIGIN/../../../..' $APPDIR/usr/lib/qml/org/krita/draganddrop/libdraganddropplugin.so patchelf --set-rpath '$ORIGIN/../../../..' $APPDIR/usr/lib/qml/org/krita/sketch/libkritasketchplugin.so patchelf --set-rpath '$ORIGIN/../..' $APPDIR/usr/lib/krita-python-libs/PyKrita/krita.so patchelf --set-rpath '$ORIGIN/../..' $APPDIR/usr/lib/python3.8/site-packages/PyQt5/sip.so +# Step 4: Install AppImageUpdate +if [ -f $DOWNLOADS_DIR/AppImageUpdate ]; then + cp $DOWNLOADS_DIR/AppImageUpdate $APPDIR/usr/bin/ + chmod +x $APPDIR/usr/bin/AppImageUpdate +fi + # Step 5: Find out what version of Krita we built and give the Appimage a proper name cd $BUILD_PREFIX/krita-build KRITA_VERSION=$(grep "#define KRITA_VERSION_STRING" libs/version/kritaversion.h | cut -d '"' -f 2) - # Also find out the revision of Git we built # Then use that to generate a combined name we'll distribute cd $KRITA_SOURCES if [[ -d .git ]]; then GIT_REVISION=$(git rev-parse --short HEAD) - VERSION=$KRITA_VERSION-$GIT_REVISION + export VERSION=$KRITA_VERSION-$GIT_REVISION + VERSION_TYPE="developement" + BRANCH="$(git rev-parse --abbrev-ref HEAD)" + if [ "$BRANCH" = "master" ]; then + CHANNEL="Next" + else + CHANNEL="Plus" + fi else - VERSION=$KRITA_VERSION + export VERSION=$KRITA_VERSION + + #if KRITA_BETA is set, set channel to Beta, otherwise set it to stable + grep "define KRITA_BETA 1" libs/version/kritaversion.h; + is_beta=$? + if [ is_beta -eq 0 ]; then + VERSION_TYPE="developement" + CHANNEL="Beta" + else + VERSION_TYPE="stable" + CHANNEL="Stable" + fi fi +DATE=$(git log -1 --format="%ct" | xargs -I{} date -d @{} +%Y-%m-%d) +if [ "$DATE" = "" ] ; then + DATE=$(date +%Y-%m-%d) +fi + +sed -e "s|||" -i $APPDIR/usr/share/metainfo/org.kde.krita.appdata.xml + +# set zsync url for linuxdeployqt +if [ "$CHANNEL" = "Next" ]; then + ZSYNC_URL="zsync|https://binary-factory.kde.org/job/Krita_Nightly_Appimage_Build/lastSuccessfulBuild/artifact/Krita-${CHANNEL}-x86_64.AppImage.zsync" +elif [ "$CHANNEL" = "Plus" ]; then + ZSYNC_URL="zsync|https://binary-factory.kde.org/job/Krita_Stable_Appimage_Build/lastSuccessfulBuild/artifact/Krita-${CHANNEL}-x86_64.AppImage.zsync" +elif [ "$CHANNEL" = "Stable" ]; then + ZSYNC_URL="zsync|https://download.kde.org/stable/krita/updates/Krita-${CHANNEL}-x86_64.AppImage.zsync" +elif [ "$CHANNEL" = "Beta" ]; then + ZSYNC_URL="zsync|https://download.kde.org/unstable/krita/updates/Krita-${CHANNEL}-x86_64.AppImage.zsync" +fi # Return to our build root cd $BUILD_PREFIX # place the icon where linuxdeployqt seems to expect it find $APPDIR -name krita.png cp $APPDIR/usr/share/icons/hicolor/256x256/apps/krita.png $APPDIR ls $APPDIR # Step 4: Build the image!!! linuxdeployqt $APPDIR/usr/share/applications/org.kde.krita.desktop \ -executable=$APPDIR/usr/bin/krita \ -qmldir=$DEPS_INSTALL_PREFIX/qml \ -verbose=2 \ -bundle-non-qt-libs \ -extra-plugins=$PLUGINS,$APPDIR/usr/lib/krita-python-libs/PyKrita/krita.so,$APPDIR/usr/lib//qml/org/krita/sketch/libkritasketchplugin.so,$APPDIR/usr/lib/qml/org/krita/draganddrop/libdraganddropplugin.so \ - -appimage - -# Generate a new name for the Appimage file and rename it accordingly -APPIMAGE=krita-"$VERSION"-x86_64.appimage + -updateinformation="${ZSYNC_URL}" \ + -appimage -mv Krita*x86_64.AppImage $APPIMAGE +# the zsync will be regenerated after signing +rm Krita-${VERSION}-x86_64.AppImage.zsync diff --git a/packaging/linux/appimage/build-krita.sh b/packaging/linux/appimage/build-krita.sh index f69b53b3ac..146f8279c2 100755 --- a/packaging/linux/appimage/build-krita.sh +++ b/packaging/linux/appimage/build-krita.sh @@ -1,52 +1,76 @@ #!/bin/bash # Halt on errors and be verbose about what we are doing set -e set -x # Read in our parameters export BUILD_PREFIX=$1 export KRITA_SOURCES=$2 -# qjsonparser, used to add metadata to the plugins needs to work in a en_US.UTF-8 environment. +# qjsonparser, used to add metadata to the plugins needs to work in a en_US.UTF-8 environment. # That's not always the case, so make sure it is export LC_ALL=en_US.UTF-8 export LANG=en_us.UTF-8 # We want to use $prefix/deps/usr/ for all our dependencies export DEPS_INSTALL_PREFIX=$BUILD_PREFIX/deps/usr/ export DOWNLOADS_DIR=$BUILD_PREFIX/downloads/ # Setup variables needed to help everything find what we build export LD_LIBRARY_PATH=$DEPS_INSTALL_PREFIX/lib:$LD_LIBRARY_PATH export PATH=$DEPS_INSTALL_PREFIX/bin:$PATH export PKG_CONFIG_PATH=$DEPS_INSTALL_PREFIX/share/pkgconfig:$DEPS_INSTALL_PREFIX/lib/pkgconfig:/usr/lib/pkgconfig:$PKG_CONFIG_PATH export CMAKE_PREFIX_PATH=$DEPS_INSTALL_PREFIX:$CMAKE_PREFIX_PATH export PYTHONPATH=$DEPS_INSTALL_PREFIX/sip:$DEPS_INSTALL_PREFIX/lib/python3.8/site-packages:$DEPS_INSTALL_PREFIX/lib/python3.8 export PYTHONHOME=$DEPS_INSTALL_PREFIX +cd $KRITA_SOURCES + +# determine the channel for branding +if [[ -d .git ]]; then + BRANCH="$(git rev-parse --abbrev-ref HEAD)" + if [ "$BRANCH" = "master" ]; then + BRANDING="Next" + else + BRANDING="Plus" + fi +else + #if KRITA_BETA is set, set channel to Beta, otherwise set it to stable + grep "define KRITA_BETA 1" libs/version/kritaversion.h; + is_beta=$? + if [ is_beta -eq 0 ]; then + BRANDING="Beta" + else + BRANDING="default" + fi +fi + +BUILD_TYPE="Release" + # Make sure our build directory exists if [ ! -d $BUILD_PREFIX/krita-build/ ] ; then mkdir -p $BUILD_PREFIX/krita-build/ fi # Now switch to it cd $BUILD_PREFIX/krita-build/ # Determine how many CPUs we have CPU_COUNT=`grep processor /proc/cpuinfo | wc -l` + # Configure Krita cmake $KRITA_SOURCES \ -DCMAKE_INSTALL_PREFIX:PATH=$BUILD_PREFIX/krita.appdir/usr \ -DDEFINE_NO_DEPRECATED=1 \ - -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \ -DFOUNDATION_BUILD=1 \ -DHIDE_SAFE_ASSERTS=ON \ - -DBUILD_TESTING=FALSE \ + -DBUILD_TESTING=TRUE \ -DPYQT_SIP_DIR_OVERRIDE=$DEPS_INSTALL_PREFIX/share/sip/ \ - -DHAVE_MEMORY_LEAK_TRACKER=FALSE - + -DHAVE_MEMORY_LEAK_TRACKER=FALSE \ + -DBRANDING="${BRANDING}" + # Build and Install Krita (ready for the next phase) make -j$CPU_COUNT install - diff --git a/packaging/linux/appimage/generate_zsync.sh b/packaging/linux/appimage/generate_zsync.sh new file mode 100644 index 0000000000..a826110b99 --- /dev/null +++ b/packaging/linux/appimage/generate_zsync.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +set -x +set -e + +APPIMAGE_PATH="${1}" +CHANNEL="${2}" +VERSION="${3}" + +if [ -z $APPIMAGE_PATH ]; then + echo "path to appimage (arg1) is not set" + exit 1 +fi + +if [ -z $CHANNEL ]; then + echo "channel (arg2) is not set" + exit 1 +fi + +if [ -z $VERSION ]; then + echo "version (arg3) is not set" + exit 1 +fi + +# regenerate zsync file +if [ "$CHANNEL" = "Next" ]; then + URL="${BUILD_URL}/artifact/" +elif [ "$CHANNEL" = "Plus" ]; then + URL="${BUILD_URL}/artifact/" +elif [ "$CHANNEL" = "Stable" ]; then + URL="https://download.kde.org/stable/krita/${VERSION}" +elif [ "$CHANNEL" = "Beta" ]; then + URL="https://download.kde.org/unstable/krita/${VERSION}" +fi + +zsyncmake -u "${URL}/$(basename ${APPIMAGE_PATH})" -o $APPIMAGE_PATH.zsync.new $APPIMAGE_PATH +ret=$? +if [ $ret -eq 0 ]; then + mv $APPIMAGE_PATH.zsync.new Krita-${CHANNEL}-x86_64.AppImage.zsync +fi + diff --git a/packaging/linux/appimage/rewrite_appimage_updinfo.sh b/packaging/linux/appimage/rewrite_appimage_updinfo.sh new file mode 100755 index 0000000000..78452e5a87 --- /dev/null +++ b/packaging/linux/appimage/rewrite_appimage_updinfo.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +set -x +set -e + +APPIMAGE_PATH="${1}" +UPDURL="${2}" + +if [ -z $APPIMAGE_PATH ]; then + echo "path to appimage (arg1) is not set" + exit 1 +fi + +if [ -z $UPDURL ]; then + echo "update url (arg2) is not set" + exit 1 +fi + + +tempdir="$(mktemp rewrite_appimage_updinfo.XXXXXX -d -p /tmp)" + +destination=$(basename $APPIMAGE_PATH) +updinfo_file="${tempdir}/upd_info" + +echo -n "zsync|${UPDURL}" > $updinfo_file + +# get offsets and lengths of .upd_info section of the AppImage +OFFSET=$(objdump -h "${APPIMAGE_PATH}" | grep .upd_info | awk '{print $6}') +LENGTH=$(objdump -h "${APPIMAGE_PATH}" | grep .upd_info | awk '{print $3}') + +# Null the section +dd if=/dev/zero bs=1 seek=$(($(echo 0x$OFFSET))) count=$(($(echo 0x$LENGTH))) of="${APPIMAGE_PATH}" conv=notrunc + +# Embed the updinfo +dd if=${updinfo_file} bs=1 seek=$(($(echo 0x$OFFSET))) count=$(($(echo 0x$LENGTH))) of="${APPIMAGE_PATH}" conv=notrunc + +# cleanup +rm -rf $tempdir diff --git a/packaging/linux/appimage/sign_appimage.sh b/packaging/linux/appimage/sign_appimage.sh new file mode 100755 index 0000000000..e3c0c72bb8 --- /dev/null +++ b/packaging/linux/appimage/sign_appimage.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +set -x +set -e + +APPIMAGE_PATH="${1}" +GPG_KEY="${2}" + +if [ -z $APPIMAGE_PATH ]; then + echo "path to appimage (arg1) is not set" + exit 1 +fi + +if [ -z $GPG_KEY ]; then + echo "gpg key id (arg3) is not set" + exit 1 +fi + +tempdir="$(mktemp sign_appimage.XXXXXX -d -p /tmp)" + +destination=$(basename $APPIMAGE_PATH) + +ascfile="${tempdir}/${destination}.digest.asc" +digestfile="${tempdir}/${destination}.digest" +sigkeyfile="${tempdir}/sig_pubkey" + +if [ -f $digestfile ]; then rm $digestfile; fi +if [ -f $ascfile ]; then rm $ascfile; fi +if [ -f $sigkeyfile ]; then rm $sigkeyfile; fi + +# get offsets and lengths of .sha256_sig and .sig_key sections of the AppImage +SIG_OFFSET=$(objdump -h "${APPIMAGE_PATH}" | grep .sha256_sig | awk '{print $6}') +SIG_LENGTH=$(objdump -h "${APPIMAGE_PATH}" | grep .sha256_sig | awk '{print $3}') + +KEY_OFFSET=$(objdump -h "${APPIMAGE_PATH}" | grep .sig_key | awk '{print $6}') +KEY_LENGTH=$(objdump -h "${APPIMAGE_PATH}" | grep .sig_key | awk '{print $3}') + +# Null the sections +dd if=/dev/zero bs=1 seek=$(($(echo 0x$SIG_OFFSET))) count=$(($(echo 0x$SIG_LENGTH))) of="${APPIMAGE_PATH}" conv=notrunc +dd if=/dev/zero bs=1 seek=$(($(echo 0x$KEY_OFFSET))) count=$(($(echo 0x$KEY_LENGTH))) of="${APPIMAGE_PATH}" conv=notrunc + +# generate sha256sum +# BEWARE THE NEWLINE! if it is not stripped, AppImageUpdate validaton will fail +sha256sum $APPIMAGE_PATH | cut -d " " -f 1 | tr -d '\n' > $digestfile + +#sign the sha256sum +gpg2 --detach-sign --armor -u $GPG_KEY -o $ascfile $digestfile +gpg2 --export --armor $GPG_KEY > $sigkeyfile + +# Embed the signature +dd if=${ascfile} bs=1 seek=$(($(echo 0x$SIG_OFFSET))) count=$(($(echo 0x$SIG_LENGTH))) of="${APPIMAGE_PATH}" conv=notrunc +# Embed the public part of the signing key +dd if=${sigkeyfile} bs=1 seek=$(($(echo 0x$KEY_OFFSET))) count=$(($(echo 0x$KEY_LENGTH))) of="${APPIMAGE_PATH}" conv=notrunc + +# cleanup +rm -rf $tempdir diff --git a/packaging/linux/appimage/strip_appimage_signature.sh b/packaging/linux/appimage/strip_appimage_signature.sh new file mode 100755 index 0000000000..518bc8dbf2 --- /dev/null +++ b/packaging/linux/appimage/strip_appimage_signature.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +set -x +set -e + +APPIMAGE_PATH="${1}" +CHANNEL="${2}" +GPG_KEY="${3}" + +if [ -z $APPIMAGE_PATH ]; then + echo "path to appimage (arg1) is not set" + exit 1 +fi + +if [ -z $CHANNEL ]; then + echo "channel (arg2) is not set" + exit 1 +fi + +if [ -z $GPG_KEY ]; then + echo "gpg key id (arg3) is not set" + exit 1 +fi + +tempdir="$(mktemp strip_appimage_signature.XXXXXX -d -p /tmp)" + +destination=$(basename $APPIMAGE_PATH) + +ascfile="${tempdir}/${destination}.digest.asc" +digestfile="${tempdir}/${destination}.digest" +sigkeyfile="${tempdir}/sig_pubkey" + +if [ -f $digestfile ]; then rm $digestfile; fi +if [ -f $ascfile ]; then rm $ascfile; fi +if [ -f $sigkeyfile ]; then rm $sigkeyfile; fi + +# get offsets and lengths of .sha256_sig and .sig_key sections of the AppImage +SIG_OFFSET=$(objdump -h "${APPIMAGE_PATH}" | grep .sha256_sig | awk '{print $6}') +SIG_LENGTH=$(objdump -h "${APPIMAGE_PATH}" | grep .sha256_sig | awk '{print $3}') + +KEY_OFFSET=$(objdump -h "${APPIMAGE_PATH}" | grep .sig_key | awk '{print $6}') +KEY_LENGTH=$(objdump -h "${APPIMAGE_PATH}" | grep .sig_key | awk '{print $3}') + +# Null the sections +dd if=/dev/zero bs=1 seek=$(($(echo 0x$SIG_OFFSET))) count=$(($(echo 0x$SIG_LENGTH))) of="${APPIMAGE_PATH}" conv=notrunc +dd if=/dev/zero bs=1 seek=$(($(echo 0x$KEY_OFFSET))) count=$(($(echo 0x$KEY_LENGTH))) of="${APPIMAGE_PATH}" conv=notrunc + +# regenerate zsync file +# TODO: replace with real urls +if [ "$CHANNEL" = "Next" ]; then + URL="http://localhost:8000/nightly" +elif [ "$CHANNEL" = "Plus" ]; then + URL="http://localhost:8000/nightly" +elif [ "$CHANNEL" = "Stable" ]; then + URL="http://localhost:8000/stable" +elif [ "$CHANNEL" = "Beta" ]; then + URL="http://localhost:8000/unstable" +fi + +zsyncmake -u "${URL}/$(basename ${APPIMAGE_PATH})" -o $APPIMAGE_PATH.zsync.new $APPIMAGE_PATH +ret=$? +if [ $ret -eq 0 ]; then + mv $APPIMAGE_PATH.zsync.new Krita-${CHANNEL}-x86_64.AppImage.zsync +fi + +# cleanup +rm -rf $tempdir diff --git a/packaging/linux/appimage/validate_appimage_signature.sh b/packaging/linux/appimage/validate_appimage_signature.sh new file mode 100755 index 0000000000..5511723f7d --- /dev/null +++ b/packaging/linux/appimage/validate_appimage_signature.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +set -x +set -e + +APPIMAGE_PATH="${1}" + +if [ -z $APPIMAGE_PATH ]; then + echo "path to appimage (arg1) is not set" + exit 1 +fi + +tempdir="$(mktemp validate_appimage_signature.XXXXXX -d -p /tmp)" + +destination=$(basename $APPIMAGE_PATH) + +ascfile="${tempdir}/${destination}.digest.asc" +digestfile="${tempdir}/${destination}.digest" +sigkeyfile="${tempdir}/sig_pubkey" +tempkeyringpath="${tempdir}/keyring" +tmpappimage="$tempdir/tmp.AppImage" + +# get offsets and lengths of .sha256_sig and .sig_key sections of the AppImage +SIG_OFFSET=$(objdump -h "${APPIMAGE_PATH}" | grep .sha256_sig | awk '{print $6}') +SIG_LENGTH=$(objdump -h "${APPIMAGE_PATH}" | grep .sha256_sig | awk '{print $3}') + +KEY_OFFSET=$(objdump -h "${APPIMAGE_PATH}" | grep .sig_key | awk '{print $6}') +KEY_LENGTH=$(objdump -h "${APPIMAGE_PATH}" | grep .sig_key | awk '{print $3}') + +cp $APPIMAGE_PATH $tmpappimage + +# restore the original, for generating checksum +dd if=/dev/zero bs=1 seek=$(($(echo 0x$SIG_OFFSET))) count=$(($(echo 0x$SIG_LENGTH))) of="${tmpappimage}" conv=notrunc +dd if=/dev/zero bs=1 seek=$(($(echo 0x$KEY_OFFSET))) count=$(($(echo 0x$KEY_LENGTH))) of="${tmpappimage}" conv=notrunc + +sha256sum $tmpappimage | cut -d " " -f 1 | tr -d '\n' > $digestfile + +# extract signature +dd if="${APPIMAGE_PATH}" bs=1 skip=$(($(echo 0x$SIG_OFFSET))) count=$(($(echo 0x$SIG_LENGTH))) of="${ascfile}" +# extract the public part of the signing key +dd if=${APPIMAGE_PATH} bs=1 skip=$(($(echo 0x$KEY_OFFSET))) count=$(($(echo 0x$KEY_LENGTH))) of="${sigkeyfile}" + +cat $sigkeyfile | gpg2 --no-default-keyring --keyring $tempkeyringpath --import +gpg2 --no-default-keyring --keyring $tempkeyringpath --verify $ascfile $digestfile + +# cleanup +rm -rf $tempdir