diff --git a/3rdparty/ext_frameworks/karchive.diff b/3rdparty/ext_frameworks/karchive.diff new file mode 100644 index 0000000000..e5ce615438 --- /dev/null +++ b/3rdparty/ext_frameworks/karchive.diff @@ -0,0 +1,21 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 45b3bf0..6afd3cb 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -33,7 +33,7 @@ find_package(BZip2) + set_package_properties(BZip2 PROPERTIES + URL "https://sourceware.org/bzip2/" + DESCRIPTION "Support for BZip2 compressed files and data streams" +- TYPE RECOMMENDED ++ TYPE OPTIONAL + PURPOSE "Support for BZip2 compressed files and data streams" + ) + +@@ -41,6 +41,7 @@ find_package(LibLZMA) + set_package_properties(LibLZMA PROPERTIES + URL "http://tukaani.org/xz/" + DESCRIPTION "Support for xz compressed files and data streams" ++ TYPE OPTIONAL + PURPOSE "Support for xz compressed files and data streams" + ) + include_directories( diff --git a/libs/widgetutils/kis_action_registry.cpp b/libs/widgetutils/kis_action_registry.cpp index 7b57ee1c37..6e2d998d54 100644 --- a/libs/widgetutils/kis_action_registry.cpp +++ b/libs/widgetutils/kis_action_registry.cpp @@ -1,429 +1,156 @@ /* * Copyright (c) 2015 Michael Abrahams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include "kis_debug.h" #include "KoResourcePaths.h" #include "kis_icon_utils.h" #include "kis_action_registry.h" #include "kshortcutschemeshelper_p.h" namespace { /** * We associate several pieces of information with each shortcut. The first * piece of information is a QDomElement, containing the raw data from the * .action XML file. The second and third are QKeySequences, the first of * which is the default shortcut, the last of which is any custom shortcut. * The last two are the KActionCollection and KActionCategory used to * organize the shortcut editor. */ struct ActionInfoItem { QDomElement xmlData; QString collectionName; QString categoryName; inline QList defaultShortcuts() const { return m_defaultShortcuts; } inline void setDefaultShortcuts(const QList &value) { m_defaultShortcuts = value; } inline QList customShortcuts() const { return m_customShortcuts; } inline void setCustomShortcuts(const QList &value, bool explicitlyReset) { m_customShortcuts = value; m_explicitlyReset = explicitlyReset; } inline QList effectiveShortcuts() const { return m_customShortcuts.isEmpty() && !m_explicitlyReset ? m_defaultShortcuts : m_customShortcuts; } private: QList m_defaultShortcuts; QList m_customShortcuts; bool m_explicitlyReset = false; }; // Convenience macros to extract text of a child node. QString getChildContent(QDomElement xml, QString node) { return xml.firstChildElement(node).text(); } - // Use Krita debug logging categories instead of KDE's default qDebug() for - // harmless empty strings and translations - QString quietlyTranslate(const QString &s) { - if (s.isEmpty()) { - return s; - } - QString translatedString = i18nc("action", s.toUtf8()); - if (translatedString == s) { - translatedString = i18n(s.toUtf8()); - } - if (translatedString.isEmpty()) { - dbgAction << "No translation found for" << s; - return s; - } - - return translatedString; - } -} - - - -class Q_DECL_HIDDEN KisActionRegistry::Private -{ -public: - - Private(KisActionRegistry *_q) : q(_q) {} - - // This is the main place containing ActionInfoItems. - QMap actionInfoList; - void loadActionFiles(); - void loadCustomShortcuts(QString filename = QStringLiteral("kritashortcutsrc")); - - // XXX: this adds a default item for the given name to the list of actioninfo objects! - ActionInfoItem &actionInfo(const QString &name) { - if (!actionInfoList.contains(name)) { - dbgAction << "Tried to look up info for unknown action" << name; - } - return actionInfoList[name]; - } - - KisActionRegistry *q; - QSet sanityPropertizedShortcuts; -}; - - -Q_GLOBAL_STATIC(KisActionRegistry, s_instance) - -KisActionRegistry *KisActionRegistry::instance() -{ - if (!s_instance.exists()) { - dbgRegistry << "initializing KoActionRegistry"; - } - return s_instance; -} - -bool KisActionRegistry::hasAction(const QString &name) const -{ - return d->actionInfoList.contains(name); -} - - -KisActionRegistry::KisActionRegistry() - : d(new KisActionRegistry::Private(this)) -{ - KConfigGroup cg = KSharedConfig::openConfig()->group("Shortcut Schemes"); - QString schemeName = cg.readEntry("Current Scheme", "Default"); - loadShortcutScheme(schemeName); - loadCustomShortcuts(); -} - -KisActionRegistry::~KisActionRegistry() -{ -} - -KisActionRegistry::ActionCategory KisActionRegistry::fetchActionCategory(const QString &name) const -{ - if (!d->actionInfoList.contains(name)) return ActionCategory(); - - const ActionInfoItem info = d->actionInfoList.value(name); - return ActionCategory(info.collectionName, info.categoryName); -} - -void KisActionRegistry::notifySettingsUpdated() -{ - d->loadCustomShortcuts(); -} - -void KisActionRegistry::loadCustomShortcuts() -{ - d->loadCustomShortcuts(); -} - -void KisActionRegistry::loadShortcutScheme(const QString &schemeName) -{ - // Load scheme file - if (schemeName != QStringLiteral("Default")) { - QString schemeFileName = KShortcutSchemesHelper::schemeFileLocations().value(schemeName); - if (schemeFileName.isEmpty()) { - return; - } - KConfig schemeConfig(schemeFileName, KConfig::SimpleConfig); - applyShortcutScheme(&schemeConfig); - } else { - // Apply default scheme, updating KisActionRegistry data - applyShortcutScheme(); - } -} - -QAction * KisActionRegistry::makeQAction(const QString &name, QObject *parent) -{ - QAction * a = new QAction(parent); - if (!d->actionInfoList.contains(name)) { - qWarning() << "Warning: requested data for unknown action" << name; - a->setObjectName(name); - return a; - } - - propertizeAction(name, a); - return a; -} - -void KisActionRegistry::settingsPageSaved() -{ - // For now, custom shortcuts are dealt with by writing to file and reloading. - loadCustomShortcuts(); - - // Announce UI should reload current shortcuts. - emit shortcutsUpdated(); -} - - -void KisActionRegistry::applyShortcutScheme(const KConfigBase *config) -{ - // First, update the things in KisActionRegistry - d->actionInfoList.clear(); - d->loadActionFiles(); - - if (config == 0) { - // Use default shortcut scheme. Simplest just to reload everything. - loadCustomShortcuts(); - } else { - const auto schemeEntries = config->group(QStringLiteral("Shortcuts")).entryMap(); - // Load info item for each shortcut, reset custom shortcuts - auto it = schemeEntries.constBegin(); - while (it != schemeEntries.end()) { - ActionInfoItem &info = d->actionInfo(it.key()); - info.setDefaultShortcuts(QKeySequence::listFromString(it.value())); - it++; - } - } -} - -void KisActionRegistry::updateShortcut(const QString &name, QAction *action) -{ - const ActionInfoItem &info = d->actionInfo(name); - action->setShortcuts(info.effectiveShortcuts()); - action->setProperty("defaultShortcuts", QVariant::fromValue(info.defaultShortcuts())); - - d->sanityPropertizedShortcuts.insert(name); -} - -bool KisActionRegistry::sanityCheckPropertized(const QString &name) -{ - return d->sanityPropertizedShortcuts.contains(name); -} - -QList KisActionRegistry::registeredShortcutIds() const -{ - return d->actionInfoList.keys(); -} - -bool KisActionRegistry::propertizeAction(const QString &name, QAction * a) -{ - if (!d->actionInfoList.contains(name)) { - warnAction << "propertizeAction: No XML data found for action" << name; - return false; - } - - const ActionInfoItem info = d->actionInfo(name); - - QDomElement actionXml = info.xmlData; - if (!actionXml.text().isEmpty()) { - // i18n requires converting format from QString. - auto getChildContent_i18n = [=](QString node){return quietlyTranslate(getChildContent(actionXml, node));}; - - // Note: the fields in the .action documents marked for translation are determined by extractrc. - QString icon = getChildContent(actionXml, "icon"); - QString text = getChildContent_i18n("text"); - QString whatsthis = getChildContent_i18n("whatsThis"); - QString toolTip = getChildContent_i18n("toolTip"); - QString statusTip = getChildContent_i18n("statusTip"); - QString iconText = getChildContent_i18n("iconText"); - bool isCheckable = getChildContent(actionXml, "isCheckable") == QString("true"); - - a->setObjectName(name); // This is helpful, should be added more places in Krita - if (!icon.isEmpty()) { - a->setIcon(KisIconUtils::loadIcon(icon.toLatin1())); - } - a->setText(text); - a->setObjectName(name); - a->setWhatsThis(whatsthis); - a->setToolTip(toolTip); - a->setStatusTip(statusTip); - a->setIconText(iconText); - a->setCheckable(isCheckable); - } - - updateShortcut(name, a); - return true; -} - - - -QString KisActionRegistry::getActionProperty(const QString &name, const QString &property) -{ - ActionInfoItem info = d->actionInfo(name); - QDomElement actionXml = info.xmlData; - if (actionXml.text().isEmpty()) { - dbgAction << "getActionProperty: No XML data found for action" << name; - return QString(); - } - - return getChildContent(actionXml, property); - -} - - -void KisActionRegistry::Private::loadActionFiles() -{ - QStringList actionDefinitions = - KoResourcePaths::findAllResources("kis_actions", "*.action", KoResourcePaths::Recursive); - dbgAction << "Action Definitions" << actionDefinitions; - - // Extract actions all XML .action files. - Q_FOREACH (const QString &actionDefinition, actionDefinitions) { - qDebug() << "\tLoading Action File" << actionDefinition; - QDomDocument doc; - QFile f(actionDefinition); - f.open(QFile::ReadOnly); - doc.setContent(f.readAll()); - - QDomElement base = doc.documentElement(); // "ActionCollection" outer group - QString collectionName = base.attribute("name"); - QString version = base.attribute("version"); - if (version != "2") { - qDebug() << ".action XML file" << actionDefinition << "has incorrect version; skipping."; - continue; - } - - // Loop over nodes. Each of these corresponds to a - // KActionCategory, producing a group of actions in the shortcut dialog. - QDomElement actions = base.firstChild().toElement(); - while (!actions.isNull()) { - - // field - QDomElement categoryTextNode = actions.firstChild().toElement(); - QString categoryName = quietlyTranslate(categoryTextNode.text()); - - // tags - QDomElement actionXml = categoryTextNode.nextSiblingElement(); - - if (actionXml.isNull()) { - qWarning() << actionDefinition << "does not contain any valid actios! (Or the text element was left empty...)"; - } - - // Loop over individual actions - while (!actionXml.isNull()) { - if (actionXml.tagName() == "Action") { - // Read name from format - QString name = actionXml.attribute("name"); - - // Bad things - if (name.isEmpty()) { - qDebug() << "Unnamed action in definitions file " << actionDefinition; + // Use Krita debug logging categories instead of KDE's default qDebug() << "Unnamed action in definitions file " << actionDefinition; } else if (actionInfoList.contains(name)) { qWarning() << "NOT COOL: Duplicated action name from xml data: " << name; } else { ActionInfoItem info; info.xmlData = actionXml; // Use empty list to signify no shortcut QString shortcutText = getChildContent(actionXml, "shortcut"); if (!shortcutText.isEmpty()) { info.setDefaultShortcuts(QKeySequence::listFromString(shortcutText)); } info.categoryName = categoryName; info.collectionName = collectionName; actionInfoList.insert(name,info); } } actionXml = actionXml.nextSiblingElement(); } actions = actions.nextSiblingElement(); } } } void KisActionRegistry::Private::loadCustomShortcuts(QString filename) { const KConfigGroup localShortcuts(KSharedConfig::openConfig(filename), QStringLiteral("Shortcuts")); if (!localShortcuts.exists()) { return; } // Distinguish between two "null" states for custom shortcuts. for (auto i = actionInfoList.begin(); i != actionInfoList.end(); ++i) { if (localShortcuts.hasKey(i.key())) { QString entry = localShortcuts.readEntry(i.key(), QString()); if (entry == QStringLiteral("none")) { i.value().setCustomShortcuts(QList(), true); } else { i.value().setCustomShortcuts(QKeySequence::listFromString(entry), false); } } else { i.value().setCustomShortcuts(QList(), false); } } } KisActionRegistry::ActionCategory::ActionCategory() { } KisActionRegistry::ActionCategory::ActionCategory(const QString &_componentName, const QString &_categoryName) : componentName(_componentName), categoryName(_categoryName), m_isValid(true) { } bool KisActionRegistry::ActionCategory::isValid() const { return m_isValid && !categoryName.isEmpty() && !componentName.isEmpty(); } diff --git a/packaging/windows/installer/MakeInstallerNsis.cmake.in b/packaging/windows/installer/MakeInstallerNsis.cmake.in index bee7ddc325..ba05c09878 100644 --- a/packaging/windows/installer/MakeInstallerNsis.cmake.in +++ b/packaging/windows/installer/MakeInstallerNsis.cmake.in @@ -1,167 +1,167 @@ cmake_minimum_required(VERSION 3.0 FATAL_ERROR) set(ARCH_IS_32_BIT @INSTALLER_NSIS_IS_32_BIT@) if(ARCH_IS_32_BIT) set(ARG_ARCH "/DKRITA_INSTALLER_32") set(FILENAME_ARCH "-x86") else() set(ARG_ARCH "/DKRITA_INSTALLER_64") set(FILENAME_ARCH "-x64") endif() if(NOT IS_DIRECTORY "${KRITA_PACKAGE_ROOT}") message(FATAL_ERROR "KRITA_PACKAGE_ROOT not set") endif() if(NOT DEFINED OUTPUT_FILEPATH) set(OUTPUT_FILEPATH "${CMAKE_CURRENT_BINARY_DIR}/krita-setup${FILENAME_ARCH}.exe") endif() if(NOT DEFINED DOWNLOAD_DIR) set(DOWNLOAD_DIR "${CMAKE_CURRENT_BINARY_DIR}") endif() # Download and find NSIS if(NOT DEFINED NO_DOWNLOAD_NSIS) set(DOWNLOAD_NSIS_VERSION "3.05") message(STATUS "Downloading NSIS...") if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/nsis-${DOWNLOAD_NSIS_VERSION}") file(REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/nsis-${DOWNLOAD_NSIS_VERSION}") endif() file(DOWNLOAD "https://files.kde.org/krita/build/dependencies/nsis-${DOWNLOAD_NSIS_VERSION}.zip" "${DOWNLOAD_DIR}/nsis-${DOWNLOAD_NSIS_VERSION}.zip" - EXPECTED_HASH SHA1=68f9c7025110b95c20431bbce28f3bf2d0ddb1ff + EXPECTED_HASH SHA1=d0cf5c1397d3ffb5cf6643fbff46457e05a48312 ) execute_process(COMMAND ${CMAKE_COMMAND} -E tar xfz "${DOWNLOAD_DIR}/nsis-${DOWNLOAD_NSIS_VERSION}.zip" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" RESULT_VARIABLE result_extract ) if(NOT result_extract EQUAL 0) message(FATAL_ERROR "Failed to extract NSIS") endif() if(NOT IS_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/nsis-${DOWNLOAD_NSIS_VERSION}") message(FATAL_ERROR "Failed to find NSIS after extracting") endif() find_program(TOOL_MAKENSIS NAMES makensis.exe PATHS "${CMAKE_CURRENT_BINARY_DIR}/nsis-${DOWNLOAD_NSIS_VERSION}" NO_DEFAULT_PATH ) else() find_program(TOOL_MAKENSIS NAMES makensis.exe HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS]" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS]" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS\\Unicode]" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS\\Unicode]" ) endif() if(NOT TOOL_MAKENSIS) message(FATAL_ERROR "Failed to find makensis.exe") endif() execute_process(COMMAND "${TOOL_MAKENSIS}" "/version" OUTPUT_VARIABLE MAKENSIS_VERSION ) # Check version is v3.* if(NOT MAKENSIS_VERSION MATCHES "^v3\\.") message(FATAL_ERROR "Expected NSIS version v3.*, got ${MAKENSIS_VERSION}") endif() message(STATUS "NSIS version ${MAKENSIS_VERSION}") # Check if package contains debug symbols file(TO_CMAKE_PATH "${KRITA_PACKAGE_ROOT}" KRITA_PACKAGE_ROOT_PATCHED) file(GLOB_RECURSE globForDebugFiles "${KRITA_PACKAGE_ROOT_PATCHED}/*.debug" ) if(globForDebugFiles) if(REMOVE_DEBUG) message(STATUS "Removing debug symbols") foreach(debugFileItem ${globForDebugFiles}) get_filename_component(debugFileDir "${debugFileItem}" DIRECTORY) get_filename_component(debugDirName "${debugFileDir}" NAME) if(debugDirName STREQUAL ".debug") if(EXISTS "${debugFileDir}") message(STATUS "Deleting ${debugFileDir}") file(REMOVE_RECURSE "${debugFileDir}") endif() else() message(STATUS "Deleting ${debugFileItem}") file(REMOVE "${debugFileItem}") endif() endforeach() else() message(FATAL_ERROR "${KRITA_PACKAGE_ROOT} seems to contain debug symbols. Set REMOVE_DEBUG to true if you want to remove them.") endif() endif() # Download installer script package message(STATUS "Downloading NSIS script package...") if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/krita-nsis") file(REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/krita-nsis") endif() file(DOWNLOAD "https://github.com/alvinhochun/KritaShellExtension/releases/download/v1.2.4b/krita-nsis-v1.2.4b.zip" "${DOWNLOAD_DIR}/krita-nsis.zip" EXPECTED_HASH SHA1=43c5bade13fb885e8546dac4486b8e2df62dc692 ) execute_process(COMMAND ${CMAKE_COMMAND} -E tar xfz "${DOWNLOAD_DIR}/krita-nsis.zip" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" RESULT_VARIABLE result_extract ) if(NOT result_extract EQUAL 0) message(FATAL_ERROR "Failed to extract krita-nsis package") endif() if(NOT IS_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/krita-nsis") message(FATAL_ERROR "Failed to find krita-nsis after extracting") endif() # Place Krita installer files in the right place file(COPY "${CMAKE_CURRENT_LIST_DIR}/installer/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/krita-nsis/" FILES_MATCHING PATTERN "*" ) # Detect FFmpeg (currently optional) if(EXISTS "${KRITA_PACKAGE_ROOT}/bin/ffmpeg.exe" AND EXISTS "${KRITA_PACKAGE_ROOT}/bin/ffmpeg_LICENSE.txt" AND EXISTS "${KRITA_PACKAGE_ROOT}/bin/ffmpeg_README.txt" ) set(ARG_HAS_FFMPEG "/DHAS_FFMPEG") else() set(ARG_HAS_FFMPEG "/DNO_HAS_FFMPEG") endif() # Build installer message(STATUS "Building installer...") set(KRITA_VERSION_NUMBER "@KRITA_STABLE_VERSION_MAJOR@.@KRITA_STABLE_VERSION_MINOR@.@KRITA_VERSION_RELEASE@.@KRITA_VERSION_REVISION@") set(KRITA_VERSION_STRING "@KRITA_VERSION_STRING@") set(KRITA_GIT_SHA1_STRING "@KRITA_GIT_SHA1_STRING@") if(KRITA_GIT_SHA1_STRING) set(KRITA_VERSION_STRING "${KRITA_VERSION_STRING} (git ${KRITA_GIT_SHA1_STRING})") endif() execute_process(COMMAND "${TOOL_MAKENSIS}" "${ARG_ARCH}" "/DKRITA_VERSION=${KRITA_VERSION_NUMBER}" "/DKRITA_VERSION_DISPLAY=${KRITA_VERSION_STRING}" "/DKRITA_INSTALLER_OUTPUT_DIR=" "/DKRITA_INSTALLER_OUTPUT_NAME=${OUTPUT_FILEPATH}" "/DKRITA_PACKAGE_ROOT=${KRITA_PACKAGE_ROOT}" "${ARG_HAS_FFMPEG}" "/XSetCompressor /SOLID lzma" "/V3" "/INPUTCHARSET" "UTF8" "${CMAKE_CURRENT_BINARY_DIR}/krita-nsis/installer_krita.nsi" RESULT_VARIABLE result_makensis ) if(NOT result_makensis EQUAL 0) message(FATAL_ERROR "Failed to build installer") endif() message(STATUS "Built installer")