diff --git a/CMakeLists.txt b/CMakeLists.txt index 44d8739..47708ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,121 +1,121 @@ cmake_minimum_required(VERSION 3.0) project(OSXIntegration) option(BUILD_KDE_THEME_PLUGIN "Should the KDE theme plugin be built?" ON) option(BUILD_QT_PLUGINS "Should the Qt QPA and style plugins be built (they don't depend on KDE but become optional when the KDE theme plugin is built)" ON) option(DEFINE_ICONTHEME_SETTINGS "Should the theme plugin define a standard theme and add the standard locations for icon themes to the search path?" OFF) option(PREFER_NATIVE_DIALOGS "Should native dialogs be preferred?" ON) option(NEVER_NATIVE_DIALOGS "Should native dialogs never be used (when not already preferred)?" OFF) option(OVERRIDE_NATIVE_THEME "Should the platform theme plugin replace the native theme? If OFF it installs as the \"kde\" theme." OFF) option(DISABLE_DBUS_SUPPORT "Don't build the D-Bus functionality. Experimental!" OFF) option(EMULATE_MENU_KEY "Emulate the presence of a Menu key as on PC keyboards when the right Command+Option keys are pressed. BUILD_QT_PLUGINS must be set for this to have any effect." OFF) +option(USE_PLCRASHREPORTER + "Use the Plausible CrashReporter (https://www.plcrashreporter.org)" + OFF) + include(FeatureSummary) find_package(ECM 5.20.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules") # feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_SOURCE_DIR}/cmake) include(GenerateExportHeader) -include(ECMPackageConfigHelpers) +include(CMakePackageConfigHelpers) include(ECMSetupVersion) include(ECMGenerateHeaders) +include(ECMQtDeclareLoggingCategory) include(KDEInstallDirs) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) # for the optional Qt QPA and style plugins # (note that they have not yet been tested against Qt 5.7) set(QT_MIN_VERSION 5.7.0) # minimum required version: if(BUILD_KDE_THEME_PLUGIN) # require the minimum version for the KF5 theme plugin and # only build the Qt plugins if the install is recent enough set(REQUIRED_QT_VERSION 5.5.0) else() # when we only build the Qt plugins we require their minimum version set(REQUIRED_QT_VERSION ${QT_MIN_VERSION}) endif() include(FindQt5Components) execute_process(COMMAND cmake/git_version.sh WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE KF5_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) message(STATUS "KF5_VERSION=${KF5_VERSION}") if(BUILD_KDE_THEME_PLUGIN) # 20170119: v5.30.0 is synced with plasma-integration 5.8.95 - set(KF5_DEP_VERSION "5.20.0") # handled by release scripts + set(KF5_DEP_VERSION "5.33.0") # handled by release scripts ecm_setup_version(${KF5_VERSION} VARIABLE_PREFIX OSXINTEGRATION VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/osxintegration_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5OSXIntegrationConfigVersion.cmake" SOVERSION 5) - find_package(KF5Config ${KF5_DEP_VERSION} REQUIRED) - find_package(KF5ConfigWidgets ${KF5_DEP_VERSION} REQUIRED) - find_package(KF5IconThemes ${KF5_DEP_VERSION} REQUIRED) - find_package(KF5Notifications ${KF5_DEP_VERSION} REQUIRED) - find_package(KF5WidgetsAddons ${KF5_DEP_VERSION} REQUIRED) + find_package(KF5 ${KF5_DEP_VERSION} REQUIRED COMPONENTS + Config ConfigWidgets I18n IconThemes KIO Notifications WidgetsAddons) if (NOT DISABLE_DBUS_SUPPORT) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED DBus) add_definitions(-DDBUS_SUPPORT_ENABLED) endif() - find_package(KF5I18n ${KF5_DEP_VERSION} REQUIRED) - find_package(KF5KIO ${KF5_DEP_VERSION} REQUIRED) add_definitions(-DTRANSLATION_DOMAIN=\"osxintegration5\") if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po") ki18n_install(po) endif() endif() add_subdirectory(src) if(BUILD_KDE_THEME_PLUGIN) add_subdirectory(autotests) # add_subdirectory(tests) # create a Config.cmake and a ConfigVersion.cmake file and install them set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5OSXIntegration") - ecm_configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KF5OSXIntegrationConfig.cmake.in" + configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KF5OSXIntegrationConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KF5OSXIntegrationConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5OSXIntegrationConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KF5OSXIntegrationConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/osxintegration_version.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5} COMPONENT Devel ) install(FILES macosx_workspace.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFY5RCDIR}) endif() feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/plintegration-cumpatch1.diff b/plintegration-cumpatch1.diff index 5139030..904b7d2 100644 --- a/plintegration-cumpatch1.diff +++ b/plintegration-cumpatch1.diff @@ -1,321 +1,338 @@ We were forked off frameworkintegration around the time that plasma-integration was also split off that framework. This file lists potentially relevant changes from plasma-integration's creation (c0ffbc2d87f7711b660d80a70b2c422a9152392e) until f33d00ef1321b96395ed4007df1d10b451d5ce5f (20170320) +20171129: merging plasma-integration commits (in reverse order): +0a6be721e4e35b54c2fba6a59243eea3c5d912d4 Implement support for selected mime type filters +7a7dfffba98d383821c39ac68de6e8aabe45b7ed Implement QPlatformTheme::fileIconPixmap() to make QFileIconProvider work. +4aef17e64f564331c79d5307dd6aeded828bf382 Replace Q_DECL_OVERRIDE with override +f25c5e10d0235c2d383e998bddc39fb35517ce9e Fix deprecation warnings. setSelection -> setSelectedUrl ui -> uiDelegate +0dafb9403266d6064074250d44b74dc0db946cfb Make sure we always set a default mime filter in save mode +4be9b478e5296914258b77eb02c2583ee0e84c7c Allow to disable blinking cursor completely +267e7c635733031d2990e78637cf6c10a56f9f05 Don't ignore initially selected mime type filter +b0059b1c8342b5ef95b054a0a5081b5db7e1c7bb Middle-click on QSystemTrayIcon сauses context menu +1b21b5977c2068c5bd30c9f9f641f60bdba9ea8e Also specify a default StyleName for fonts +2434bafcb168467f6763a20226918d27afa26744 [KHintsSettings] Update AA_DontShowIconsInMenus at runtime +86be8d49d8988fb6c35e847ed9e0aad3e8514208 Allow to change toolbar font separately again +f9e5b852faa78f6d67615ea3c435b10b393cdaa5 Add ~/.local/share/icons to icons search paths +1781d60b230c32977c078e2943d94c506d7ee645 Set QtQuickControls theme in QPT +059369d6b6a9a99538c175a3c53058cbb54e8abc partly merged, NOT the additional QtQuickControls2 dependency! +59d0ad3064bb3c45d7e9ab0604e65a31e5a24155 Show shortcuts in menus + 20170425: synced with the following plasma-integration commits (everything related to QDbusMenuBar is irrelevant on Mac): Fix warning when no initial directory is set. (7bca66673f9575083181ca1b0a9602ba077c9016) [KHintsSettings] Emit QGuiApplication::paletteChanged when run as QApplication (ab3298b3f5f728765d5afa8830aa7793140617c8) Do not treat filename in selection as URL (e70f8134a2bc4b3647e245c05f469aeed462a246) Use the native dialog if there's no QApplication (c6305f5edbbd15244d79cfc7569352cf6f6ea4d6) (in KdeMacTheme::usePlatformNativeDialog()) 20170119: synced, among others with the current version of these plasma-integration commits: 8fefab22498c15643e87ae104ef1d5fbfef8f539 Mon Sep 17 00:00:00 2001 7bbbd93cd3fc0abdffd3fa7f144cb50a33fafad9 Mon Sep 17 00:00:00 2001 ### Done: diff --git a/src/platformtheme/kdeplatformfiledialoghelper.cpp b/src/platformtheme/kdeplatformfiledialoghelper.cpp index 139c35d..15b5e90 100644 --- a/src/platformtheme/kdeplatformfiledialoghelper.cpp +++ b/src/platformtheme/kdeplatformfiledialoghelper.cpp @@ -288,6 +288,8 @@ void KDEPlatformFileDialogHelper::initializeDialog() // overwrite option if (options()->testOption(QFileDialogOptions::FileDialogOption::DontConfirmOverwrite)) { dialog->m_fileWidget->setConfirmOverwrite(false); + } else if (options()->acceptMode() == QFileDialogOptions::AcceptSave) { + dialog->m_fileWidget->setConfirmOverwrite(true); } } } @@ -328,11 +330,11 @@ void KDEPlatformFileDialogHelper::restoreSize() bool KDEPlatformFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) { - Q_UNUSED(parent) initializeDialog(); m_dialog->setWindowFlags(windowFlags); m_dialog->setWindowModality(windowModality); restoreSize(); + m_dialog->windowHandle()->setTransientParent(parent); // Use a delayed show here to delay show() after the internal Qt invisible QDialog. // The delayed call shouldn't matter, because for other "real" native QPlatformDialog // implementation like Mac and Windows, the native dialog is not necessarily diff --git a/src/platformtheme/khintssettings.cpp b/src/platformtheme/khintssettings.cpp index edbed5f..7768a1c 100644 --- a/src/platformtheme/khintssettings.cpp +++ b/src/platformtheme/khintssettings.cpp @@ -375,12 +375,6 @@ void KHintsSettings::loadPalettes() return; } - path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("plasma/look-and-feel/org.kde.loonandfeel/contents/colors")); - if (!path.isEmpty()) { - m_palettes[QPlatformTheme::SystemPalette] = new QPalette(KColorScheme::createApplicationPalette(KSharedConfig::openConfig(path))); - return; - } - const QString scheme = readConfigValue(QStringLiteral("General"), QStringLiteral("ColorScheme"), QStringLiteral("Breeze")).toString(); path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("color-schemes/") + scheme + QStringLiteral(".colors")); diff --git not done ### ### not done: There is little point changing the default fixed font in kfontsettingsdata.cpp (from Oxygen Mono to Hack); it's overridden in kfontsettingsdatamac.m (Monaco is close enough to Hack but still more elegant; has true Italic instead of an improved slanted (Oblique) mode. diff --git a/autotests/kfiledialog_unittest.cpp b/autotests/kfiledialog_unittest.cpp index 59915da..b32cd8e 100644 --- a/autotests/kfiledialog_unittest.cpp +++ b/autotests/kfiledialog_unittest.cpp @@ -19,6 +19,9 @@ */ #include +#include +#include +#include #include #include #include @@ -200,7 +203,61 @@ private Q_SLOTS: QCOMPARE(dialog.fileMode(), qtFileMode); } + + void testSaveOverwrite_data() + { + QTest::addColumn("qtOverwriteOption"); + QTest::addColumn("messageBoxExpected"); + QTest::newRow("checkoverwrite") << false << true; + QTest::newRow("allowoverwrite") << true << false; + } + + void testSaveOverwrite() + { + QFETCH(bool, qtOverwriteOption); + QFETCH(bool, messageBoxExpected); + + QTemporaryFile tempFile(QDir::tempPath()+"/kfiledialogtest_XXXXXX"); + tempFile.setAutoRemove(true); + tempFile.open(); + QString tempName = tempFile.fileName(); + tempFile.close(); + int idx = tempName.lastIndexOf('/'); + + QFileDialog dialog; + dialog.setAcceptMode(QFileDialog::AcceptSave); + if (qtOverwriteOption) dialog.setOption(QFileDialog::DontConfirmOverwrite); + dialog.setDirectory(tempName.left(idx+1)); + dialog.selectFile(tempName.mid(idx+1)); + dialog.open(); + + KFileWidget *fw = findFileWidget(); + QVERIFY(fw); + QTest::qWaitForWindowExposed(fw->window()); + QCOMPARE(fw->isVisible(), true); + + messageBoxSeen = false; + QTimer::singleShot(500, this, SLOT(checkMessageBox())); + fw->slotOk(); + + fw->slotCancel(); + QVERIFY(messageBoxSeen == messageBoxExpected); + } + +protected Q_SLOTS: + void checkMessageBox() + { + QDialog *msgbox = findMessageBox(); + if (!msgbox) return; + QTest::qWaitForWindowExposed(msgbox); + QCOMPARE(msgbox->isVisible(), true); + messageBoxSeen = true; + msgbox->close(); + } + private: + bool messageBoxSeen; + static QString fileViewToString(KFile::FileView fv) { switch (fv) { @@ -230,6 +287,18 @@ private: Q_ASSERT(widgets.count() == 1); return (widgets.count() == 1) ? widgets.first() : Q_NULLPTR; } + + static QDialog *findMessageBox() + { + QList widgets; + foreach (QWidget *widget, QApplication::topLevelWidgets()) { + QDialog *dlg = widget->findChild(); + if (dlg) { + widgets.append(dlg); + } + } + return (widgets.count() == 1) ? widgets.first() : Q_NULLPTR; + } }; QTEST_MAIN(KFileDialog_UnitTest) diff --git a/src/platformtheme/kfontsettingsdata.cpp b/src/platformtheme/kfontsettingsdata.cpp index a43e8be..d3f8fe3 100644 --- a/src/platformtheme/kfontsettingsdata.cpp +++ b/src/platformtheme/kfontsettingsdata.cpp @@ -54,7 +54,7 @@ static const char DefaultFont[] = "Noto Sans"; static const KFontData DefaultFontData[KFontSettingsData::FontTypesCount] = { { GeneralId, "font", DefaultFont, 10, -1, QFont::SansSerif }, - { GeneralId, "fixed", "Oxygen Mono", 9, -1, QFont::Monospace }, + { GeneralId, "fixed", "Hack", 9, -1, QFont::Monospace }, { GeneralId, "toolBarFont", DefaultFont, 9, -1, QFont::SansSerif }, { GeneralId, "menuFont", DefaultFont, 10, -1, QFont::SansSerif }, { "WM", "activeFont", DefaultFont, 10, -1, QFont::SansSerif }, diff --git a/tests/qfiledialogtest.cpp b/tests/qfiledialogtest.cpp index 1d69ea1..329eabf 100644 --- a/tests/qfiledialogtest.cpp +++ b/tests/qfiledialogtest.cpp @@ -31,6 +31,8 @@ int main(int argc, char **argv) parser.addHelpOption(); parser.addOption(QCommandLineOption(QStringList(QStringLiteral("staticFunction")), QStringLiteral("Test one of the static convenience function: 'getOpenFileUrl', 'getExistingDirectory'"), QStringLiteral("function name"))); parser.addOption(QCommandLineOption(QStringList(QStringLiteral("acceptMode")), QStringLiteral("File dialog acceptMode: 'open' or 'save'"), QStringLiteral("type"), QStringLiteral("open"))); + parser.addOption(QCommandLineOption(QStringList(QStringLiteral("confirmOverwrite")), QStringLiteral("Test overwrite option: 'on' or 'off'"), QStringLiteral("option"), QStringLiteral("on"))); + parser.addOption(QCommandLineOption(QStringList(QStringLiteral("nativeDialog")), QStringLiteral("Use the platform native dialog: 'on' or 'off'"), QStringLiteral("option"), QStringLiteral("on"))); parser.addOption(QCommandLineOption(QStringList(QStringLiteral("fileMode")), QStringLiteral("File dialog fileMode: 'AnyFile' or 'ExistingFile' or 'Directory' or 'ExistingFiles'"), QStringLiteral("type"))); parser.addOption(QCommandLineOption(QStringList(QStringLiteral("nameFilter")), QStringLiteral("Dialog nameFilter, e. g. 'cppfiles (*.cpp *.h *.hpp)', can be specified multiple times"), QStringLiteral("nameFilter"), QStringLiteral("Everything (*)"))); // add option mimeTypeFilter later @@ -83,6 +85,14 @@ int main(int argc, char **argv) dialog.selectNameFilter(selectNameFilter); } + if (parser.value(QStringLiteral("confirmOverwrite")) == QStringLiteral("off")) { + dialog.setOption(QFileDialog::DontConfirmOverwrite, true); + } + + if (parser.value(QStringLiteral("nativeDialog")) == QStringLiteral("off")) { + dialog.setOption(QFileDialog::DontUseNativeDialog, true); + } + dialog.setDirectory(parser.value(QStringLiteral("selectDirectory"))); dialog.selectFile(parser.value(QStringLiteral("selectFile"))); From 8fefab22498c15643e87ae104ef1d5fbfef8f539 Mon Sep 17 00:00:00 2001 From: David Faure Date: Fri, 23 Dec 2016 15:46:41 +0100 Subject: [PATCH] Fix compilation with Qt 5.8. --- src/platformtheme/kdeplatformfiledialoghelper.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/platformtheme/kdeplatformfiledialoghelper.cpp b/src/platformtheme/kdeplatformfiledialoghelper.cpp index 7e7e2e9..990b983 100644 --- a/src/platformtheme/kdeplatformfiledialoghelper.cpp +++ b/src/platformtheme/kdeplatformfiledialoghelper.cpp @@ -365,7 +365,13 @@ void KDEPlatformFileDialogHelper::selectFile(const QUrl &filename) // Qt 5 at least <= 5.8.0 does not derive the directory from the passed url // and set the initialDirectory option accordingly, also not for known schemes // like file://, so we have to do it ourselves + + // Syntax-wise we have to use a copy ctor until Qt 5.7.x and clone() since Qt 5.8. +#if QT_VERSION < QT_VERSION_CHECK(5, 8, 0) QSharedPointer opt(new QFileDialogOptions(*options())); +#else + auto opt = options()->clone(); +#endif opt->setInitialDirectory(m_dialog->directory()); setOptions(opt); } -- 2.11.0 From 7bbbd93cd3fc0abdffd3fa7f144cb50a33fafad9 Mon Sep 17 00:00:00 2001 From: "Friedrich W. H. Kossebau" Date: Thu, 22 Dec 2016 19:51:32 +0100 Subject: [PATCH] Fix Plasma-QPA filedialog to show wrong directory with QFileDialog::selectUrl() Summary: QFileDialog does not set the initialDirectory option in codepaths from QFileDialog::selectUrl(...) or QFileDialog::selectFile(...) when passing the task on to the native widget. So KDEPlatformFileDialogHelper has to make sure itself that info is kept. Because KDEPlatformFileDialogHelper::initializeDialog() calls setDirectory(options()->initialDirectory()); as intended, usually during the show event. And by that it resets any otherwise wanted state of the filewidget it had from previous setup calls via QFileDialog, and instead to whatever value the initialDirectory option had before, usually the working directory as set during initialization. Test Plan: New unit test kfiledialog_unittest testSelectUrl no longer fails with added code, also behaves now as expected with code e.g. from KUrlRequester. Reviewers: #plasma, #frameworks, dfaure Reviewed By: #plasma, graesslin, dfaure Subscribers: plasma-devel Tags: #plasma Differential Revision: https://phabricator.kde.org/D3796 --- autotests/kfiledialog_unittest.cpp | 18 ++++++++++++++++++ src/platformtheme/kdeplatformfiledialoghelper.cpp | 7 +++++++ 2 files changed, 25 insertions(+) diff --git a/autotests/kfiledialog_unittest.cpp b/autotests/kfiledialog_unittest.cpp index b32cd8e..47a5543 100644 --- a/autotests/kfiledialog_unittest.cpp +++ b/autotests/kfiledialog_unittest.cpp @@ -77,6 +77,24 @@ private Q_SLOTS: QCOMPARE(dialog.directory().absolutePath(), QDir::rootPath()); } + void testSelectUrl() + { + QTemporaryFile tempFile(QDir::tempPath()+"/kfiledialogtest_XXXXXX"); + tempFile.setAutoRemove(true); + tempFile.open(); + QString tempName = tempFile.fileName(); + QUrl url = QUrl::fromLocalFile(tempName); + int idx = tempName.lastIndexOf('/'); + QUrl directoryUrl = QUrl::fromLocalFile(tempName.left(idx+1)); + + QFileDialog dialog; + dialog.selectUrl(url); + dialog.show(); + + // check if dialog was set to base directory url of the passed file url + QCOMPARE(dialog.directoryUrl(), directoryUrl); + } + void testViewMode() { // Open a file dialog, and change view mode to tree diff --git a/src/platformtheme/kdeplatformfiledialoghelper.cpp b/src/platformtheme/kdeplatformfiledialoghelper.cpp index 15b5e90..7e7e2e9 100644 --- a/src/platformtheme/kdeplatformfiledialoghelper.cpp +++ b/src/platformtheme/kdeplatformfiledialoghelper.cpp @@ -361,6 +361,13 @@ QUrl KDEPlatformFileDialogHelper::directory() const void KDEPlatformFileDialogHelper::selectFile(const QUrl &filename) { m_dialog->selectFile(filename); + + // Qt 5 at least <= 5.8.0 does not derive the directory from the passed url + // and set the initialDirectory option accordingly, also not for known schemes + // like file://, so we have to do it ourselves + QSharedPointer opt(new QFileDialogOptions(*options())); + opt->setInitialDirectory(m_dialog->directory()); + setOptions(opt); } void KDEPlatformFileDialogHelper::setDirectory(const QUrl &directory) -- 2.11.0 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ed18a03..d92cdc1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,11 @@ +# this one (probably) best be avoided: +string(REPLACE "-fapplication-extension" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") +string(REPLACE "-fapplication-extension" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + if(BUILD_KDE_THEME_PLUGIN) add_subdirectory(platformtheme) endif() if(BUILD_QT_PLUGINS) add_subdirectory(qmacstyle) add_subdirectory(qcocoa-qpa) endif() diff --git a/src/platformtheme/CMakeLists.txt b/src/platformtheme/CMakeLists.txt index 48f5fe4..9fc9987 100644 --- a/src/platformtheme/CMakeLists.txt +++ b/src/platformtheme/CMakeLists.txt @@ -1,77 +1,96 @@ if(DEFINE_ICONTHEME_SETTINGS) message(STATUS "The icon theme search path will be set") add_definitions(-DKDEMACTHEME_ADD_ICONTHEMESETTINGS) endif() if(PREFER_NATIVE_DIALOGS) message(STATUS "Native dialogs will be preferred") add_definitions(-DKDEMACTHEME_PREFER_NATIVE_DIALOGS) else() if(NEVER_NATIVE_DIALOGS) message(STATUS "Native dialogs will be avoided") add_definitions(-DKDEMACTHEME_NEVER_NATIVE_DIALOGS) endif() endif() if(EMULATE_MENU_KEY) add_definitions(-DADD_MENU_KEY) endif() + +if(USE_PLCRASHREPORTER) + find_library(CRASHREP CrashReporter + DOC "The Plausible CrashReporter framework from https://www.plcrashreporter.org" + PATHS ${CMAKE_INSTALL_PREFIX}/Library/Frameworks) + if(NOT CRASHREP) + message(WARNING "CrashReporter framework not found, building without!") + else() + add_definitions(-DUSE_PLCRASHREPORTER) + endif() +endif() + add_subdirectory(presets) if(OVERRIDE_NATIVE_THEME) set(PLATFORM_PLUGIN_THEME_NAME "cocoa") set(PLUGIN_FILENAME "CocoaPlatformTheme") else() set(PLATFORM_PLUGIN_THEME_NAME "kde") set(PLUGIN_FILENAME "KDEPlatformTheme") endif() configure_file(config-platformtheme.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-platformtheme.h ) set(platformtheme_SRCS kdeplatformtheme.cpp kfontsettingsdata.cpp khintssettings.cpp kdeplatformfiledialoghelper.cpp kdeplatformfiledialogbase.cpp kdeplatformsystemtrayicon.cpp kfiletreeview.cpp kdirselectdialog.cpp kdemactheme.mm kfontsettingsdatamac.mm khintssettingsmac.mm ) if(OVERRIDE_NATIVE_THEME) set(platformtheme_SRCS ${platformtheme_SRCS} main_cocoa.cpp) else() set(platformtheme_SRCS ${platformtheme_SRCS} main_kde.cpp) endif() +ecm_qt_declare_logging_category(platformtheme_SRCS + HEADER platformtheme_logging.h + IDENTIFIER PLATFORMTHEME + CATEGORY_NAME ${PLUGIN_FILENAME} +) + include_directories( ${Qt5Gui_PRIVATE_INCLUDE_DIRS} ) # Use the same name for the platform theme module. This makes it impossible # to install both the plasma and the OS X integration modules, but that's # intentional. add_library(${PLUGIN_FILENAME} MODULE ${platformtheme_SRCS}) if (NOT DISABLE_DBUS_SUPPORT) target_link_libraries(${PLUGIN_FILENAME} PRIVATE Qt5::DBus ) endif() # add KF5:WindowSystem? target_link_libraries(${PLUGIN_FILENAME} PRIVATE KF5::ConfigWidgets KF5::ConfigCore KF5::IconThemes KF5::KIOFileWidgets # KFileFilterCombo, KDirSortFilterProxyModel, KRecentDirs KF5::KIOWidgets KF5::XmlGui KF5::I18n KF5::Notifications + "${CRASHREP}" ) target_link_libraries(${PLUGIN_FILENAME} PRIVATE "-framework AppKit") install(TARGETS ${PLUGIN_FILENAME} DESTINATION ${KDE_INSTALL_QTPLUGINDIR}/platformthemes) diff --git a/src/platformtheme/kdemactheme.h b/src/platformtheme/kdemactheme.h index 98660d4..08fafa4 100644 --- a/src/platformtheme/kdemactheme.h +++ b/src/platformtheme/kdemactheme.h @@ -1,73 +1,73 @@ /* This file is part of the KDE libraries * Copyright 2013 Kevin Ottens * Copyright 2015 René J.V. Bertin * * 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 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), 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 Lesser 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 KDEMACTHEME_H #define KDEMACTHEME_H #include "kdeplatformtheme.h" #include "kfontsettingsdatamac.h" #ifdef ADD_MENU_KEY #include #endif class KHintsSettingsMac; class QIconEngine; class KdeMacThemeEventFilter; class KdeMacTheme : public KdePlatformTheme { public: KdeMacTheme(); ~KdeMacTheme(); // KdeMacTheme must provide platform menu methods or else there will be no menus - QPlatformMenuItem* createPlatformMenuItem() const Q_DECL_OVERRIDE; - QPlatformMenu* createPlatformMenu() const Q_DECL_OVERRIDE; - QPlatformMenuBar* createPlatformMenuBar() const Q_DECL_OVERRIDE; + QPlatformMenuItem* createPlatformMenuItem() const override; + QPlatformMenu* createPlatformMenu() const override; + QPlatformMenuBar* createPlatformMenuBar() const override; - QVariant themeHint(ThemeHint hint) const Q_DECL_OVERRIDE; - const QPalette *palette(Palette type = SystemPalette) const Q_DECL_OVERRIDE; - const QFont *font(Font type) const Q_DECL_OVERRIDE; - QList keyBindings(QKeySequence::StandardKey key) const Q_DECL_OVERRIDE; + QVariant themeHint(ThemeHint hint) const override; + const QPalette *palette(Palette type = SystemPalette) const override; + const QFont *font(Font type) const override; + QList keyBindings(QKeySequence::StandardKey key) const override; - QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const Q_DECL_OVERRIDE; - bool usePlatformNativeDialog(DialogType type) const Q_DECL_OVERRIDE; + QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const override; + bool usePlatformNativeDialog(DialogType type) const override; - QString standardButtonText(int button) const Q_DECL_OVERRIDE; + QString standardButtonText(int button) const override; - QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const Q_DECL_OVERRIDE; + QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const override; protected: void loadSettings(); KFontSettingsDataMac::FontTypes fontType(Font type) const; private: KHintsSettingsMac *m_hints; KFontSettingsDataMac *m_fontsData; // this will hold the instance of the native theme that will be used as a fallback QPlatformTheme *nativeTheme; // this will hold an instance of a class with Qt and/or native event filters: KdeMacThemeEventFilter *m_eventFilter; }; #endif // KDEMACTHEME_H diff --git a/src/platformtheme/kdemactheme.mm b/src/platformtheme/kdemactheme.mm index 7e8f7a8..98d9195 100644 --- a/src/platformtheme/kdemactheme.mm +++ b/src/platformtheme/kdemactheme.mm @@ -1,680 +1,717 @@ /* This file is part of the KDE libraries * Copyright 2013 Kevin Ottens * Copyright 2013 Aleix Pol Gonzalez * Copyright 2014 Lukáš Tinkl * Copyright 2015 René J.V. Bertin * * 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 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), 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 Lesser 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. */ // #define ADD_MENU_KEY #include "config-platformtheme.h" #include "kdemactheme.h" #include "kfontsettingsdatamac.h" #include "khintssettingsmac.h" #include "kdeplatformfiledialoghelper.h" #include "kdeplatformsystemtrayicon.h" +#include "platformtheme_logging.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef QT_NO_GESTURES #include #include #include #include #include #include #include #include #include #include #include #include #endif // instantiating the native platform theme requires the use of private APIs #include #include #include #include #include #include #include #include #include +#ifdef USE_PLCRASHREPORTER +#include +#endif + // [NSEvent modifierFlags] keycodes: // LeftShift=131330 // RightShift=131332 // LeftAlt=524576 // RightAlt=524608 // LeftCommand=1048840 // RightCommand=1048848 // RightCommand+RightAlt=1573200 static QString platformName = QStringLiteral(""); // #define TAPANDHOLD_DEBUG class KdeMacThemeEventFilter : public QObject { Q_OBJECT public: KdeMacThemeEventFilter(QObject *parent=nullptr) : QObject(parent) { qtNativeFilter = new QNativeEventFilter; } virtual ~KdeMacThemeEventFilter() { delete qtNativeFilter; qtNativeFilter = nullptr; } class QNativeEventFilter : public QAbstractNativeEventFilter { public: virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override; }; QNativeEventFilter *qtNativeFilter; #ifdef ADD_MENU_KEY const static int keyboardMonitorMask = NSKeyDownMask | NSKeyUpMask | NSFlagsChangedMask; NSEvent *nativeEventHandler(void *message); id m_keyboardMonitor; bool enabled; NSTimeInterval disableTime; #endif #ifndef QT_NO_GESTURES inline bool handleGestureForObject(const QObject *obj) const { // this function is called with an that is or inherits a QWidget const QPushButton *btn = qobject_cast(obj); const QToolButton *tbtn = qobject_cast(obj); if (tbtn) { return !tbtn->menu(); } else if (btn) { return !btn->menu(); } else { return (qobject_cast(obj) || qobject_cast(obj) // || obj->inherits("QTabBar") || obj->inherits("QTabWidget") || qobject_cast(obj) || qobject_cast(obj) || qobject_cast(obj) // this catches items in directory lists and the like || obj->objectName() == QStringLiteral("qt_scrollarea_viewport") || obj->inherits("KateViewInternal")); // Konsole windows can be found as obj->inherits("Konsole::TerminalDisplay") but // for some reason Konsole doesn't respond to synthetic ContextMenu events } } #endif int pressedMouseButtons() { return [NSEvent pressedMouseButtons]; } bool eventFilter(QObject *obj, QEvent *event) override { #ifndef QT_NO_GESTURES static QVariant qTrue(true), qFalse(false); // #ifdef TAPANDHOLD_DEBUG // if (qEnvironmentVariableIsSet("TAPANDHOLD_CONTEXTMENU_DEBUG")) { // QVariant isGrabbed = obj->property("OurTaHGestureActive"); // if (isGrabbed.isValid() && isGrabbed.toBool()) { -// qWarning() << "event=" << event << "grabbed obj=" << obj; +// qCWarning(PLATFORMTHEME) << "event=" << event << "grabbed obj=" << obj; // } // } // #endif switch (event->type()) { case QEvent::MouseButtonPress: { QMouseEvent *me = dynamic_cast(event); if (me->button() == Qt::LeftButton && me->modifiers() == Qt::NoModifier) { QWidget *w = qobject_cast(obj); if (w && handleGestureForObject(obj)) { QVariant isGrabbed = obj->property("OurTaHGestureActive"); if (!(isGrabbed.isValid() && isGrabbed.toBool())) { // ideally we'd check first - if we could. // storing all grabbed QObjects is potentially dangerous since we won't // know when they go stale. w->grabGesture(Qt::TapAndHoldGesture); // accept this event but resend it so that the 1st mousepress // can also trigger a tap-and-hold! obj->setProperty("OurTaHGestureActive", qTrue); #ifdef TAPANDHOLD_DEBUG if (qEnvironmentVariableIsSet("TAPANDHOLD_CONTEXTMENU_DEBUG")) { - qWarning() << "event=" << event << "grabbing obj=" << obj << "parent=" << obj->parent(); + qCWarning(PLATFORMTHEME) << "event=" << event << "grabbing obj=" << obj << "parent=" << obj->parent(); } #endif if (!m_grabbing.contains(obj)) { QMouseEvent relay(*me); me->accept(); m_grabbing.insert(obj); int ret = QCoreApplication::sendEvent(obj, &relay); m_grabbing.remove(obj); return ret; } } } #ifdef TAPANDHOLD_DEBUG else if (w && qEnvironmentVariableIsSet("TAPANDHOLD_CONTEXTMENU_DEBUG")) { - qWarning() << "event=" << event << "obj=" << obj << "parent=" << obj->parent(); + qCWarning(PLATFORMTHEME) << "event=" << event << "obj=" << obj << "parent=" << obj->parent(); } #endif } // NB: don't "eat" the event if no action was taken! break; } // case QEvent::Paint: // if (pressedMouseButtons() == 1) { // // ignore QPaintEvents when the left mouse button (1<<0) is being held // break; // } else { // // not holding the left mouse button; fall through to check if // // maybe we should cancel a click-and-hold-opens-contextmenu process. // } case QEvent::MouseMove: case QEvent::MouseButtonRelease: { QVariant isGrabbed = obj->property("OurTaHGestureActive"); if (isGrabbed.isValid() && isGrabbed.toBool()) { #ifdef TAPANDHOLD_DEBUG - qWarning() << "event=" << event << "obj=" << obj << "parent=" << obj->parent() + qCWarning(PLATFORMTHEME) << "event=" << event << "obj=" << obj << "parent=" << obj->parent() << "grabbed=" << obj->property("OurTaHGestureActive"); #endif obj->setProperty("OurTaHGestureActive", qFalse); } break; } case QEvent::Gesture: { QGestureEvent *gEvent = static_cast(event); if (QTapAndHoldGesture *heldTap = static_cast(gEvent->gesture(Qt::TapAndHoldGesture))) { if (heldTap->state() == Qt::GestureFinished) { QVariant isGrabbed = obj->property("OurTaHGestureActive"); if (isGrabbed.isValid() && isGrabbed.toBool() && pressedMouseButtons() == 1) { QWidget *w = qobject_cast(obj); // user clicked and held a button, send it a simulated ContextMenuEvent // but send a simulated buttonrelease event first. QPoint localPos = w->mapFromGlobal(heldTap->position().toPoint()); QContextMenuEvent ce(QContextMenuEvent::Mouse, localPos, heldTap->hotSpot().toPoint()); // don't send a ButtonRelease event to Q*Buttons because we don't want to trigger them if (QPushButton *btn = qobject_cast(obj)) { btn->setDown(false); obj->setProperty("OurTaHGestureActive", qFalse); } else if (QToolButton *tbtn = qobject_cast(obj)) { tbtn->setDown(false); obj->setProperty("OurTaHGestureActive", qFalse); } else { QMouseEvent me(QEvent::MouseButtonRelease, localPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); #ifdef TAPANDHOLD_DEBUG - qWarning() << "Sending" << &me; + qCWarning(PLATFORMTHEME) << "Sending" << &me; #endif // we'll be unsetting OurTaHGestureActive in the MouseButtonRelease handler above QCoreApplication::sendEvent(obj, &me); } - qWarning() << "Sending" << &ce << "to" << obj << "because of" << gEvent << "isGrabbed=" << isGrabbed; + qCWarning(PLATFORMTHEME) << "Sending" << &ce << "to" << obj << "because of" << gEvent << "isGrabbed=" << isGrabbed; bool ret = QCoreApplication::sendEvent(obj, &ce); gEvent->accept(); - qWarning() << "\tsendEvent" << &ce << "returned" << ret; + qCWarning(PLATFORMTHEME) << "\tsendEvent" << &ce << "returned" << ret; return true; } } } break; } #ifdef TAPANDHOLD_DEBUG case QEvent::ContextMenu: if (qEnvironmentVariableIsSet("TAPANDHOLD_CONTEXTMENU_DEBUG")) { - qWarning() << "event=" << event << "obj=" << obj << "parent=" << obj->parent() + qCWarning(PLATFORMTHEME) << "event=" << event << "obj=" << obj << "parent=" << obj->parent() << "grabbed=" << obj->property("OurTaHGestureActive"); } break; #endif default: break; } #endif return false; } #ifndef QT_NO_GESTURES QSet m_grabbing; #endif }; -bool KdeMacThemeEventFilter::QNativeEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *) +bool KdeMacThemeEventFilter::QNativeEventFilter::nativeEventFilter(const QByteArray&, void *message, long *) { NSEvent *event = static_cast(message); switch ([event type]) { #if defined(MAC_OS_X_VERSION_10_12) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12) case NSEventTypeSystemDefined: #else case NSSystemDefined: #endif { // borrowed with thanks from QMPlay2 const int keyCode = ([event data1] & 0xFFFF0000) >> 16; const int keyFlags = ([event data1] & 0x0000FFFF); const int keyState = (((keyFlags & 0xFF00) >> 8) == 0xA); -// qWarning() << QStringLiteral("NSSystemDefined event keyCode=%1 keyFlags=%2 keyState=%3").arg(keyCode).arg(keyFlags).arg(keyState); +// qCWarning(PLATFORMTHEME) << QStringLiteral("NSSystemDefined event keyCode=%1 keyFlags=%2 keyState=%3").arg(keyCode).arg(keyFlags).arg(keyState); if (keyState == 1) { int qtKey = 0; switch (keyCode) { case NX_KEYTYPE_PLAY: qtKey = Qt::Key_MediaTogglePlayPause; break; case NX_KEYTYPE_NEXT: case NX_KEYTYPE_FAST: qtKey = Qt::Key_MediaNext; break; case NX_KEYTYPE_PREVIOUS: case NX_KEYTYPE_REWIND: qtKey = Qt::Key_MediaPrevious; break; } if (qtKey) { QKeyEvent mediaKeyEvent(QEvent::KeyPress, qtKey, Qt::NoModifier); - qWarning() << "Sending mediaKeyEvent" << &mediaKeyEvent; + qCWarning(PLATFORMTHEME) << "Sending mediaKeyEvent" << &mediaKeyEvent; QCoreApplication::sendEvent(qApp, &mediaKeyEvent); return false; } } break; } } return false; } #ifdef ADD_MENU_KEY NSEvent *KdeMacThemeEventFilter::nativeEventHandler(void *message) { NSEvent *event = static_cast(message); switch ([event type]) { case NSFlagsChanged: { switch ([event modifierFlags]) { case 524608: case 1048848: enabled = false; disableTime = [event timestamp]; break; case 1573200: // simultaneous press (i.e. within <= 0.1s) of just the right Command and Option keys: if (enabled || [event timestamp] - disableTime <= 0.1) { enabled = true; -// qWarning() << Q_FUNC_INFO << "event=" << QString::fromNSString([event description]) +// qCWarning(PLATFORMTHEME) << Q_FUNC_INFO << "event=" << QString::fromNSString([event description]) // << "modifierFlags=" << [event modifierFlags] << "keyCode=" << [event keyCode]; const unichar menuKeyCode = static_cast(NSMenuFunctionKey); NSString *menuKeyString = [NSString stringWithCharacters:&menuKeyCode length:1]; NSEvent *menuKeyEvent = [NSEvent keyEventWithType:NSKeyDown location:[event locationInWindow] modifierFlags:([event modifierFlags] & ~(NSCommandKeyMask|NSAlternateKeyMask)) timestamp:[event timestamp] windowNumber:[event windowNumber] context:nil characters:menuKeyString charactersIgnoringModifiers:menuKeyString isARepeat:NO // the keyCode must be an 8-bit value so not to be confounded with the Unicode value. // Judging from Carbon/Events.h 0x7f is unused. keyCode:0x7f]; -// qWarning() << "new event:" << QString::fromNSString([menuKeyEvent description]); +// qCWarning(PLATFORMTHEME) << "new event:" << QString::fromNSString([menuKeyEvent description]); return menuKeyEvent; } // fall through! default: // any other flag change reenables the menukey emulation. enabled = true; break; } break; } // case NSKeyDown: { -// qWarning() << Q_FUNC_INFO << "event=" << QString::fromNSString([event description]) +// qCWarning(PLATFORMTHEME) << Q_FUNC_INFO << "event=" << QString::fromNSString([event description]) // << "key=" << [event keyCode] // << "modifierFlags=" << [event modifierFlags] << "chars=" << QString::fromNSString([event characters]) // << "charsIgnMods=" << QString::fromNSString([event charactersIgnoringModifiers]); // break; // } } // standard event processing return event; } #endif //ADD_MENU_KEY static void warnNoNativeTheme() { - // Make sure the warning appears somewhere. qWarning() isn't guaranteed to be of use when we're + // Make sure the warning appears somewhere. qCWarning(PLATFORMTHEME) isn't guaranteed to be of use when we're // not called from a terminal session and it's probably too early to try an alert dialog. // NSLog() will log to system.log, but also to the terminal. if (platformName.contains(QLatin1String("cocoa"))) { NSLog(@"The %s platform theme plugin is being used and the native theme for the %@ platform failed to load.\n" "Applications will function but lack functionality available only through the native theme,\n" "including the menu bar at the top of the screen(s).", PLATFORM_PLUGIN_THEME_NAME, platformName.toNSString()); } else { NSLog(@"The %s platform theme plugin is being used and the native theme for the %@ platform failed to load.\n" "Applications will function but lack functionality available only through the native theme.", PLATFORM_PLUGIN_THEME_NAME, platformName.toNSString()); } } /* ============ How we get here: (lldb) bt * thread #1: tid = 0x2e3a6be, 0x000000010a481454 KDEPlatformTheme.so`KdeMacTheme::KdeMacTheme(this=0x0000000103a3d830) + 4 at kdemactheme.mm:72, queue = 'com.apple.main-thread', stop reason = breakpoint 1.2 * frame #0: 0x000000010a481454 KDEPlatformTheme.so`KdeMacTheme::KdeMacTheme(this=0x0000000103a3d830) + 4 at kdemactheme.mm:72 frame #1: 0x000000010a48686b KDEPlatformTheme.so`CocoaPlatformThemePlugin::create(this=, key=, paramList=) + 27 at main_mac.cpp:53 frame #2: 0x00000001008c85b8 QtGui`QPlatformThemeFactory::create(QString const&, QString const&) [inlined] QPlatformTheme* qLoadPlugin(loader=, key=0x0000000103a406b0, args=0x0000000103a3d710) + 60 at qfactoryloader_p.h:103 frame #3: 0x00000001008c857c QtGui`QPlatformThemeFactory::create(key=, platformPluginPath=) + 396 at qplatformthemefactory.cpp:73 frame #4: 0x00000001008d31bb QtGui`QGuiApplicationPrivate::createPlatformIntegration() [inlined] QLatin1String::QLatin1String(this=0x0000000103b17a00, pluginArgument=0x0000000103b17a00, this=0x0000000103b17a00, platformPluginPath=0x000000010134fa90, s=0x0000000103b19e50, platformThemeName=0x000000010134fa90, argc=, argv=) + 1357 at qguiapplication.cpp:1135 frame #5: 0x00000001008d2c6e QtGui`QGuiApplicationPrivate::createPlatformIntegration(this=0x0000000103c0a6a0) + 1950 at qguiapplication.cpp:1257 frame #6: 0x00000001008d3adb QtGui`QGuiApplicationPrivate::createEventDispatcher(this=) + 27 at qguiapplication.cpp:1274 frame #7: 0x00000001010e0098 QtCore`QCoreApplicationPrivate::init(this=0x0000000103c0a6a0) + 1832 at qcoreapplication.cpp:794 frame #8: 0x00000001008cfce1 QtGui`QGuiApplicationPrivate::init(this=0x0000000103c0a6a0) + 49 at qguiapplication.cpp:1297 frame #9: 0x000000010001e90e QtWidgets`QApplicationPrivate::init(this=0x0000000103c0a6a0) + 14 at qapplication.cpp:583 ============ */ KdeMacTheme::KdeMacTheme() { if (strcasecmp(QT_VERSION_STR, qVersion())) { NSLog(@"Warning: the %s platform theme plugin for Mac was built against Qt %s but is running with Qt %s!", PLATFORM_PLUGIN_THEME_NAME, QT_VERSION_STR, qVersion()); } // first things first: instruct Qt not to use the Mac-style toplevel menubar // if we are not using the Cocoa QPA plugin (but the XCB QPA instead). platformName = QGuiApplication::platformName(); if (!platformName.contains(QLatin1String("cocoa"))) { QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true); QCoreApplication::setAttribute(Qt::AA_MacDontSwapCtrlAndMeta, true); } QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration(); if (pi) { nativeTheme = pi->createPlatformTheme(platformName); } else { nativeTheme = Q_NULLPTR; } if (!nativeTheme) { warnNoNativeTheme(); } else if (qEnvironmentVariableIsSet("QT_QPA_PLATFORMTHEME_VERBOSE")) { - qWarning() << Q_FUNC_INFO + qCWarning(PLATFORMTHEME) << Q_FUNC_INFO << "loading platform theme plugin" << QLatin1String(PLATFORM_PLUGIN_THEME_NAME) << "for platform" << platformName; } m_fontsData = Q_NULLPTR; m_hints = Q_NULLPTR; loadSettings(); m_eventFilter = new KdeMacThemeEventFilter; #ifndef QT_NO_GESTURES qApp->installEventFilter(m_eventFilter); #endif #ifdef ADD_MENU_KEY m_eventFilter->m_keyboardMonitor = 0; @autoreleasepool { // set up a keyboard event monitor m_eventFilter->m_keyboardMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:KdeMacThemeEventFilter::keyboardMonitorMask handler:^(NSEvent* event) { return m_eventFilter->nativeEventHandler(event); }]; } if (m_eventFilter->m_keyboardMonitor) { m_eventFilter->enabled = true; } else { - qWarning() << Q_FUNC_INFO << "Could not create a global keyboard monitor"; + qCWarning(PLATFORMTHEME) << Q_FUNC_INFO << "Could not create a global keyboard monitor"; } #endif // for some reason our Qt native event filter is apparently never called. qApp->installNativeEventFilter(m_eventFilter->qtNativeFilter); + +#ifdef USE_PLCRASHREPORTER + static PLCrashReporter *crashReporter = nil; + if (!crashReporter) { + crashReporter = [[PLCrashReporter alloc] + initWithConfiguration:[PLCrashReporterConfig defaultConfiguration]]; + } + NSError *error; + if ([crashReporter hasPendingCrashReport]) @autoreleasepool { + NSData *crashData; + PLCrashReport *report = nil; + crashData = [crashReporter loadPendingCrashReportDataAndReturnError: &error]; + if (crashData) { + report = [[[PLCrashReport alloc] initWithData:crashData error:&error] autorelease]; + } + if (report) { + // report could be sent to KAboutData::applicationData().bugAddress() + // using QDesktopServices::openUrl("mailto:") + qCWarning(PLATFORMTHEME) << qApp->applicationName() << "crashed on" << QString::fromNSString([report.systemInfo.timestamp description]); + qCWarning(PLATFORMTHEME) << "\twith signal" << QString::fromNSString(report.signalInfo.name) + << "code" << QString::fromNSString(report.signalInfo.code) + << "at address" << report.signalInfo.address; + } + [crashReporter purgePendingCrashReport]; + } + if (![crashReporter enableCrashReporterAndReturnError: &error]) { + NSLog(@"Warning: Could not enable crash reporter: %@", error); + } +#endif } KdeMacTheme::~KdeMacTheme() { delete nativeTheme; if (m_eventFilter) { qApp->removeNativeEventFilter(m_eventFilter->qtNativeFilter); #ifdef ADD_MENU_KEY m_eventFilter->enabled = false; if (m_eventFilter->m_keyboardMonitor) { @autoreleasepool { [NSEvent removeMonitor:m_eventFilter->m_keyboardMonitor]; } } #endif } delete m_eventFilter; m_eventFilter = 0; } QPlatformMenuItem* KdeMacTheme::createPlatformMenuItem() const { if (nativeTheme) { return nativeTheme->createPlatformMenuItem(); } else { warnNoNativeTheme(); return QPlatformTheme::createPlatformMenuItem(); } } QPlatformMenu* KdeMacTheme::createPlatformMenu() const { if (nativeTheme) { return nativeTheme->createPlatformMenu(); } else { warnNoNativeTheme(); return QPlatformTheme::createPlatformMenu(); } } QPlatformMenuBar* KdeMacTheme::createPlatformMenuBar() const { if (nativeTheme) { return nativeTheme->createPlatformMenuBar(); } else { warnNoNativeTheme(); return QPlatformTheme::createPlatformMenuBar(); } } QVariant KdeMacTheme::themeHint(QPlatformTheme::ThemeHint hintType) const { QVariant hint = m_hints->hint(hintType); if (hint.isValid()) { return hint; } else { if (nativeTheme) { return nativeTheme->themeHint(hintType); } return QPlatformTheme::themeHint(hintType); } } const QPalette *KdeMacTheme::palette(Palette type) const { QPalette *palette = m_hints->palette(type); if (palette) { return palette; } else { if (nativeTheme) { return nativeTheme->palette(type); } return QPlatformTheme::palette(type); } } KFontSettingsDataMac::FontTypes KdeMacTheme::fontType(QPlatformTheme::Font type) const { KFontSettingsDataMac::FontTypes ftype; switch (type) { default: ftype = KFontSettingsDataMac::FontTypes(KdePlatformTheme::fontType(type)); break; case MessageBoxFont: ftype = KFontSettingsDataMac::MessageBoxFont; break; } return ftype; } const QFont *KdeMacTheme::font(Font type) const { // when using the platform-default fonts, try returning a bold version of the // standard system font; it's the only one where Qt/OS X really deviates. const QFont *qf = m_fontsData->font(fontType(type)); if (!qf && nativeTheme) { qf = nativeTheme->font(type); // if (qf) { -// qWarning() << "native font for type" << type << "=role" << fontType(type) << ":" << *qf; +// qCWarning(PLATFORMTHEME) << "native font for type" << type << "=role" << fontType(type) << ":" << *qf; // } else { -// qWarning() << "native font for type" << type << "=role" << fontType(type) << ": NULL"; +// qCWarning(PLATFORMTHEME) << "native font for type" << type << "=role" << fontType(type) << ": NULL"; // } } return qf; } void KdeMacTheme::loadSettings() { if (!m_fontsData) { m_fontsData = new KFontSettingsDataMac; } if (!m_hints) { m_hints = new KHintsSettingsMac; } } QList KdeMacTheme::keyBindings(QKeySequence::StandardKey key) const { // return a native keybinding if we can determine what that is if (nativeTheme) { return nativeTheme->keyBindings(key); } // or else we return whatever KDE applications expect elsewhere return KdePlatformTheme::keyBindings(key); } bool KdeMacTheme::usePlatformNativeDialog(QPlatformTheme::DialogType type) const { #ifdef KDEMACTHEME_PREFER_NATIVE_DIALOGS if (nativeTheme) { return nativeTheme->usePlatformNativeDialog(type); } #endif #ifndef KDEMACTHEME_NEVER_NATIVE_DIALOGS return type == QPlatformTheme::FileDialog && qobject_cast(QCoreApplication::instance()); #else return false; #endif } QString KdeMacTheme::standardButtonText(int button) const { // assume that button text is a domain where cross-platform application // coherence primes over native platform look and feel. IOW, function over form. // It's impossible to use the parent's method since we use // the nativeTheme in the default case switch (static_cast(button)) { case QPlatformDialogHelper::NoButton: - qWarning() << Q_FUNC_INFO << "Unsupported standard button:" << button; + qCWarning(PLATFORMTHEME) << Q_FUNC_INFO << "Unsupported standard button:" << button; return QString(); case QPlatformDialogHelper::Ok: return KStandardGuiItem::ok().text(); case QPlatformDialogHelper::Save: return KStandardGuiItem::save().text(); case QPlatformDialogHelper::SaveAll: return i18nc("@action:button", "Save All"); case QPlatformDialogHelper::Open: return KStandardGuiItem::open().text(); case QPlatformDialogHelper::Yes: return KStandardGuiItem::yes().text(); case QPlatformDialogHelper::YesToAll: return i18nc("@action:button", "Yes to All"); case QPlatformDialogHelper::No: return KStandardGuiItem::no().text(); case QPlatformDialogHelper::NoToAll: return i18nc("@action:button", "No to All"); case QPlatformDialogHelper::Abort: // FIXME KStandardGuiItem::stop() doesn't seem right here return i18nc("@action:button", "Abort"); case QPlatformDialogHelper::Retry: return i18nc("@action:button", "Retry"); case QPlatformDialogHelper::Ignore: return i18nc("@action:button", "Ignore"); case QPlatformDialogHelper::Close: return KStandardGuiItem::close().text(); case QPlatformDialogHelper::Cancel: return KStandardGuiItem::cancel().text(); case QPlatformDialogHelper::Discard: return KStandardGuiItem::discard().text(); case QPlatformDialogHelper::Help: return KStandardGuiItem::help().text(); case QPlatformDialogHelper::Apply: return KStandardGuiItem::apply().text(); case QPlatformDialogHelper::Reset: return KStandardGuiItem::reset().text(); case QPlatformDialogHelper::RestoreDefaults: return KStandardGuiItem::defaults().text(); default: if (nativeTheme) { // something not foreseen by Qt/KDE: now see if OS X // has an opinion about the text. return nativeTheme->standardButtonText(button); } return QPlatformTheme::defaultStandardButtonText(button); } } QPlatformDialogHelper *KdeMacTheme::createPlatformDialogHelper(QPlatformTheme::DialogType type) const { #ifdef KDEMACTHEME_PREFER_NATIVE_DIALOGS // always prefer native dialogs // NOTE: somehow, the "don't use native dialog" option that Qt's example "standarddialogs" // provides does not modify our usePlatformNativeDialog() return value, but *does* cause // a Qt dialog to be created instead of the native one. Weird. - if (nativeTheme) { + if (nativeTheme && !qEnvironmentVariableIsSet("PREFER_KDE_DIALOGS")) { return nativeTheme->createPlatformDialogHelper(type); } #endif QPlatformDialogHelper *helper = KdePlatformTheme::createPlatformDialogHelper(type); if (helper) { return helper; } else { - return QPlatformTheme::createPlatformDialogHelper(type); + if (nativeTheme) { + helper = nativeTheme->createPlatformDialogHelper(type); + } + return helper ? helper : QPlatformTheme::createPlatformDialogHelper(type); } } QPlatformSystemTrayIcon *KdeMacTheme::createPlatformSystemTrayIcon() const { if (nativeTheme) { return nativeTheme->createPlatformSystemTrayIcon(); } // TODO: figure out if it makes sense to return something other than // nativeTheme->createPlatformSystemTrayIcon() or even NULL return KdePlatformTheme::createPlatformSystemTrayIcon(); } #include "kdemactheme.moc" diff --git a/src/platformtheme/kdeplatformfiledialogbase_p.h b/src/platformtheme/kdeplatformfiledialogbase_p.h index 3191027..487bdbb 100644 --- a/src/platformtheme/kdeplatformfiledialogbase_p.h +++ b/src/platformtheme/kdeplatformfiledialogbase_p.h @@ -1,61 +1,63 @@ /* This file is part of the KDE libraries * Copyright 2013 Aleix Pol Gonzalez * * 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 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), 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 Lesser 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 KDEPLATFORMFILEDIALOGBASE_H #define KDEPLATFORMFILEDIALOGBASE_H #include #include #include class KFileWidget; class QDialogButtonBox; class KDEPlatformFileDialogBase : public QDialog { Q_OBJECT public: friend class KDEPlatformFileDialogHelper; explicit KDEPlatformFileDialogBase(); virtual QUrl directory() = 0; + virtual void selectMimeTypeFilter(const QString &filter) = 0; virtual void selectNameFilter(const QString &filter) = 0; virtual void setDirectory(const QUrl &directory) = 0; virtual void selectFile(const QUrl &filename) = 0; + virtual QString selectedMimeTypeFilter() = 0; virtual QString selectedNameFilter() = 0; virtual QList selectedFiles() = 0; void delayedShow(); void discardDelayedShow(); Q_SIGNALS: void closed(); void fileSelected(const QUrl &file); void filesSelected(const QList &files); void currentChanged(const QUrl &path); void directoryEntered(const QUrl &directory); void filterSelected(const QString &filter); protected: - void closeEvent(QCloseEvent *e) Q_DECL_OVERRIDE; + void closeEvent(QCloseEvent *e) override; QDialogButtonBox *m_buttons; QTimer m_timer; }; #endif diff --git a/src/platformtheme/kdeplatformfiledialoghelper.cpp b/src/platformtheme/kdeplatformfiledialoghelper.cpp index b3103a1..21fe7ff 100644 --- a/src/platformtheme/kdeplatformfiledialoghelper.cpp +++ b/src/platformtheme/kdeplatformfiledialoghelper.cpp @@ -1,386 +1,440 @@ /* This file is part of the KDE libraries * Copyright 2013 Aleix Pol Gonzalez * Copyright 2014 Martin Klapetek * * 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 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), 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 Lesser 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 "kdeplatformfiledialoghelper.h" #include "kdeplatformfiledialogbase_p.h" #include "kdirselectdialog_p.h" #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include namespace { /* * Map a Qt filter string into a KDE one. */ static QString qt2KdeFilter(const QStringList &f) { QString filter; QTextStream str(&filter, QIODevice::WriteOnly); QStringList list(f); list.replaceInStrings(QStringLiteral("/"), QStringLiteral("\\/")); QStringList::const_iterator it(list.constBegin()), end(list.constEnd()); bool first = true; for (; it != end; ++it) { int ob = it->lastIndexOf(QLatin1Char('(')), cb = it->lastIndexOf(QLatin1Char(')')); if (-1 != cb && ob < cb) { if (first) { first = false; } else { str << '\n'; } str << it->mid(ob + 1, (cb - ob) - 1) << '|' << it->mid(0, ob); } } return filter; } /* * Map a KDE filter string into a Qt one. */ static QString kde2QtFilter(const QStringList &list, const QString &kde) { QStringList::const_iterator it(list.constBegin()), end(list.constEnd()); int pos; for (; it != end; ++it) { if (-1 != (pos = it->indexOf(kde)) && pos > 0 && (QLatin1Char('(') == (*it)[pos - 1] || QLatin1Char(' ') == (*it)[pos - 1]) && it->length() >= kde.length() + pos && (QLatin1Char(')') == (*it)[pos + kde.length()] || QLatin1Char(' ') == (*it)[pos + kde.length()])) { return *it; } } return QString(); } } KDEPlatformFileDialog::KDEPlatformFileDialog() : KDEPlatformFileDialogBase() , m_fileWidget(new KFileWidget(QUrl(), this)) { setLayout(new QVBoxLayout); connect(m_fileWidget, SIGNAL(filterChanged(QString)), SIGNAL(filterSelected(QString))); layout()->addWidget(m_fileWidget); m_buttons = new QDialogButtonBox(this); m_buttons->addButton(m_fileWidget->okButton(), QDialogButtonBox::AcceptRole); m_buttons->addButton(m_fileWidget->cancelButton(), QDialogButtonBox::RejectRole); connect(m_buttons, SIGNAL(rejected()), m_fileWidget, SLOT(slotCancel())); connect(m_fileWidget->okButton(), SIGNAL(clicked(bool)), m_fileWidget, SLOT(slotOk())); connect(m_fileWidget, SIGNAL(accepted()), m_fileWidget, SLOT(accept())); connect(m_fileWidget, SIGNAL(accepted()), SLOT(accept())); connect(m_fileWidget->cancelButton(), SIGNAL(clicked(bool)), SLOT(reject())); layout()->addWidget(m_buttons); } QUrl KDEPlatformFileDialog::directory() { return m_fileWidget->baseUrl(); } QList KDEPlatformFileDialog::selectedFiles() { return m_fileWidget->selectedUrls(); } void KDEPlatformFileDialog::selectFile(const QUrl &filename) { QUrl dirUrl = filename.adjusted(QUrl::RemoveFilename); m_fileWidget->setUrl(dirUrl); - m_fileWidget->setSelection(filename.toString()); + m_fileWidget->setSelectedUrl(filename); } void KDEPlatformFileDialog::setViewMode(QFileDialogOptions::ViewMode view) { switch (view) { case QFileDialogOptions::ViewMode::Detail: m_fileWidget->setViewMode(KFile::FileView::Detail); break; case QFileDialogOptions::ViewMode::List: m_fileWidget->setViewMode(KFile::FileView::Simple); break; default: m_fileWidget->setViewMode(KFile::FileView::Default); break; } } void KDEPlatformFileDialog::setFileMode(QFileDialogOptions::FileMode mode) { switch (mode) { case QFileDialogOptions::FileMode::AnyFile: m_fileWidget->setMode(KFile::File); break; case QFileDialogOptions::FileMode::ExistingFile: m_fileWidget->setMode(KFile::Mode::File | KFile::Mode::ExistingOnly); break; case QFileDialogOptions::FileMode::Directory: m_fileWidget->setMode(KFile::Mode::Directory | KFile::Mode::ExistingOnly); break; case QFileDialogOptions::FileMode::ExistingFiles: m_fileWidget->setMode(KFile::Mode::Files | KFile::Mode::ExistingOnly); break; default: m_fileWidget->setMode(KFile::File); break; } } void KDEPlatformFileDialog::setCustomLabel(QFileDialogOptions::DialogLabel label, const QString &text) { if (label == QFileDialogOptions::Accept) { // OK button m_fileWidget->okButton()->setText(text); } else if (label == QFileDialogOptions::Reject) { // Cancel button m_fileWidget->cancelButton()->setText(text); } else if (label == QFileDialogOptions::LookIn) { // Location label m_fileWidget->setLocationLabel(text); } } +QString KDEPlatformFileDialog::selectedMimeTypeFilter() +{ + if (m_fileWidget->filterWidget()->isMimeFilter()) { + const auto mimeTypeFromFilter = QMimeDatabase().mimeTypeForName(m_fileWidget->filterWidget()->currentFilter()); + // If one does not call selectMimeTypeFilter(), KFileFilterCombo::currentFilter() returns invalid mimeTypes, + // such as "application/json application/zip". + if (mimeTypeFromFilter.isValid()) { + return mimeTypeFromFilter.name(); + } + } + + if (selectedFiles().isEmpty()) { + return QString(); + } + + // Works for both KFile::File and KFile::Files modes. + return QMimeDatabase().mimeTypeForUrl(selectedFiles().at(0)).name(); +} + QString KDEPlatformFileDialog::selectedNameFilter() { return m_fileWidget->filterWidget()->currentFilter(); } +void KDEPlatformFileDialog::selectMimeTypeFilter(const QString &filter) +{ + m_fileWidget->filterWidget()->setCurrentFilter(filter); +} + void KDEPlatformFileDialog::selectNameFilter(const QString &filter) { m_fileWidget->filterWidget()->setCurrentFilter(filter); } void KDEPlatformFileDialog::setDirectory(const QUrl &directory) { if (!directory.isLocalFile()) { // Qt can not determine if the remote URL points to a file or a // directory, that is why options()->initialDirectory() always returns // the full URL. KIO::StatJob *job = KIO::stat(directory); KJobWidgets::setWindow(job, this); if (job->exec()) { KIO::UDSEntry entry = job->statResult(); if (!entry.isDir()) { // this is probably a file remove the file part m_fileWidget->setUrl(directory.adjusted(QUrl::RemoveFilename)); - m_fileWidget->setSelection(directory.fileName()); + m_fileWidget->setSelectedUrl(directory); } else { m_fileWidget->setUrl(directory); } } } else { m_fileWidget->setUrl(directory); } } bool KDEPlatformFileDialogHelper::isSupportedUrl(const QUrl& url) const { return KProtocolInfo::protocols().contains(url.scheme()); } //////////////////////////////////////////////// KDEPlatformFileDialogHelper::KDEPlatformFileDialogHelper() : QPlatformFileDialogHelper() , m_dialog(new KDEPlatformFileDialog) { connect(m_dialog, SIGNAL(closed()), SLOT(saveSize())); connect(m_dialog, SIGNAL(finished(int)), SLOT(saveSize())); connect(m_dialog, SIGNAL(currentChanged(QUrl)), SIGNAL(currentChanged(QUrl))); connect(m_dialog, SIGNAL(directoryEntered(QUrl)), SIGNAL(directoryEntered(QUrl))); connect(m_dialog, SIGNAL(fileSelected(QUrl)), SIGNAL(fileSelected(QUrl))); connect(m_dialog, SIGNAL(filesSelected(QList)), SIGNAL(filesSelected(QList))); connect(m_dialog, SIGNAL(filterSelected(QString)), SIGNAL(filterSelected(QString))); connect(m_dialog, SIGNAL(accepted()), SIGNAL(accept())); connect(m_dialog, SIGNAL(rejected()), SIGNAL(reject())); } KDEPlatformFileDialogHelper::~KDEPlatformFileDialogHelper() { saveSize(); delete m_dialog; } void KDEPlatformFileDialogHelper::initializeDialog() { if (options()->testOption(QFileDialogOptions::ShowDirsOnly)) { m_dialog->deleteLater(); m_dialog = new KDirSelectDialog(options()->initialDirectory()); connect(m_dialog, SIGNAL(accepted()), SIGNAL(accept())); connect(m_dialog, SIGNAL(rejected()), SIGNAL(reject())); if (!options()->windowTitle().isEmpty()) m_dialog->setWindowTitle(options()->windowTitle()); } else { // needed for accessing m_fileWidget KDEPlatformFileDialog *dialog = qobject_cast(m_dialog); dialog->m_fileWidget->setOperationMode(options()->acceptMode() == QFileDialogOptions::AcceptOpen ? KFileWidget::Opening : KFileWidget::Saving); if (options()->windowTitle().isEmpty()) { dialog->setWindowTitle(options()->acceptMode() == QFileDialogOptions::AcceptOpen ? i18nc("@title:window", "Open File") : i18nc("@title:window", "Save File")); } else { dialog->setWindowTitle(options()->windowTitle()); } setDirectory(options()->initialDirectory()); //dialog->setViewMode(options()->viewMode()); // don't override our options, fixes remembering the chosen view mode and sizes! dialog->setFileMode(options()->fileMode()); // custom labels if (options()->isLabelExplicitlySet(QFileDialogOptions::Accept)) { // OK button dialog->setCustomLabel(QFileDialogOptions::Accept, options()->labelText(QFileDialogOptions::Accept)); } else if (options()->isLabelExplicitlySet(QFileDialogOptions::Reject)) { // Cancel button dialog->setCustomLabel(QFileDialogOptions::Reject, options()->labelText(QFileDialogOptions::Reject)); } else if (options()->isLabelExplicitlySet(QFileDialogOptions::LookIn)) { // Location label dialog->setCustomLabel(QFileDialogOptions::LookIn, options()->labelText(QFileDialogOptions::LookIn)); } const QStringList mimeFilters = options()->mimeTypeFilters(); const QStringList nameFilters = options()->nameFilters(); if (!mimeFilters.isEmpty()) { - dialog->m_fileWidget->setMimeFilter(mimeFilters); + QString defaultMimeFilter; + if (options()->acceptMode() == QFileDialogOptions::AcceptSave) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) + defaultMimeFilter = options()->initiallySelectedMimeTypeFilter(); +#endif + if (defaultMimeFilter.isEmpty()) { + defaultMimeFilter = mimeFilters.at(0); + } + } + dialog->m_fileWidget->setMimeFilter(mimeFilters, defaultMimeFilter); if ( mimeFilters.contains( QStringLiteral("inode/directory") ) ) dialog->m_fileWidget->setMode( dialog->m_fileWidget->mode() | KFile::Directory ); } else if (!nameFilters.isEmpty()) { dialog->m_fileWidget->setFilter(qt2KdeFilter(nameFilters)); } +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) + if (!options()->initiallySelectedMimeTypeFilter().isEmpty()) { + selectMimeTypeFilter(options()->initiallySelectedMimeTypeFilter()); + } else if (!options()->initiallySelectedNameFilter().isEmpty()) { + selectNameFilter(options()->initiallySelectedNameFilter()); + } +#else if (!options()->initiallySelectedNameFilter().isEmpty()) { selectNameFilter(options()->initiallySelectedNameFilter()); } +#endif // overwrite option // TODO: figure out how to avoid a native "OK to overwrite" request followed by one from KDE (mod in KIO??) if (options()->testOption(QFileDialogOptions::FileDialogOption::DontConfirmOverwrite)) { dialog->m_fileWidget->setConfirmOverwrite(false); } else if (options()->acceptMode() == QFileDialogOptions::AcceptSave) { dialog->m_fileWidget->setConfirmOverwrite(true); } } } void KDEPlatformFileDialogHelper::exec() { restoreSize(); // KDEPlatformFileDialog::show() will always be called during QFileDialog::exec() // discard the delayed show() it and use exec() and it will call show() for us. // We can't hide and show it here because of https://bugreports.qt.io/browse/QTBUG-48248 m_dialog->discardDelayedShow(); m_dialog->exec(); } void KDEPlatformFileDialogHelper::hide() { m_dialog->discardDelayedShow(); m_dialog->hide(); } void KDEPlatformFileDialogHelper::saveSize() { KSharedConfig::Ptr conf = KSharedConfig::openConfig(); KConfigGroup group = conf->group("FileDialogSize"); KWindowConfig::saveWindowSize(m_dialog->windowHandle(), group); } void KDEPlatformFileDialogHelper::restoreSize() { m_dialog->winId(); // ensure there's a window created KSharedConfig::Ptr conf = KSharedConfig::openConfig(); KWindowConfig::restoreWindowSize(m_dialog->windowHandle(), conf->group("FileDialogSize")); // NOTICE: QWindow::setGeometry() does NOT impact the backing QWidget geometry even if the platform // window was created -> QTBUG-40584. We therefore copy the size here. // TODO: remove once this was resolved in QWidget QPA m_dialog->resize(m_dialog->windowHandle()->size()); } bool KDEPlatformFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) { initializeDialog(); m_dialog->setWindowFlags(windowFlags); m_dialog->setWindowModality(windowModality); restoreSize(); m_dialog->windowHandle()->setTransientParent(parent); // Use a delayed show here to delay show() after the internal Qt invisible QDialog. // The delayed call shouldn't matter, because for other "real" native QPlatformDialog // implementation like Mac and Windows, the native dialog is not necessarily // show up immediately. m_dialog->delayedShow(); return true; } QList KDEPlatformFileDialogHelper::selectedFiles() const { return m_dialog->selectedFiles(); } +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) +QString KDEPlatformFileDialogHelper::selectedMimeTypeFilter() const +{ + return m_dialog->selectedMimeTypeFilter(); +} + +void KDEPlatformFileDialogHelper::selectMimeTypeFilter(const QString &filter) +{ + m_dialog->selectMimeTypeFilter(filter); +} +#endif + QString KDEPlatformFileDialogHelper::selectedNameFilter() const { return kde2QtFilter(options()->nameFilters(), m_dialog->selectedNameFilter()); } QUrl KDEPlatformFileDialogHelper::directory() const { return m_dialog->directory(); } void KDEPlatformFileDialogHelper::selectFile(const QUrl &filename) { m_dialog->selectFile(filename); } void KDEPlatformFileDialogHelper::setDirectory(const QUrl &directory) { if (!directory.isEmpty()) { m_dialog->setDirectory(directory); } } void KDEPlatformFileDialogHelper::selectNameFilter(const QString &filter) { m_dialog->selectNameFilter(qt2KdeFilter(QStringList(filter))); } void KDEPlatformFileDialogHelper::setFilter() { } bool KDEPlatformFileDialogHelper::defaultNameFilterDisables() const { return false; } diff --git a/src/platformtheme/kdeplatformfiledialoghelper.h b/src/platformtheme/kdeplatformfiledialoghelper.h index f80b8c7..24cf561 100644 --- a/src/platformtheme/kdeplatformfiledialoghelper.h +++ b/src/platformtheme/kdeplatformfiledialoghelper.h @@ -1,81 +1,87 @@ /* This file is part of the KDE libraries * Copyright 2013 Aleix Pol Gonzalez * * 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 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), 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 Lesser 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 KDEPLATFORMFILEDIALOGHELPER_H #define KDEPLATFORMFILEDIALOGHELPER_H #include #include "kdeplatformfiledialogbase_p.h" class KFileWidget; class QDialogButtonBox; class KDEPlatformFileDialog : public KDEPlatformFileDialogBase { Q_OBJECT public: friend class KDEPlatformFileDialogHelper; explicit KDEPlatformFileDialog(); - QUrl directory() Q_DECL_OVERRIDE; - void selectNameFilter(const QString &filter) Q_DECL_OVERRIDE; - void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; - void selectFile(const QUrl &filename) Q_DECL_OVERRIDE; + QUrl directory() override; + void selectMimeTypeFilter(const QString &filter) override; + void selectNameFilter(const QString &filter) override; + void setDirectory(const QUrl &directory) override; + void selectFile(const QUrl &filename) override; void setViewMode(QFileDialogOptions::ViewMode view); void setFileMode(QFileDialogOptions::FileMode mode); void setCustomLabel(QFileDialogOptions::DialogLabel label, const QString & text); - QString selectedNameFilter() Q_DECL_OVERRIDE; - QList selectedFiles() Q_DECL_OVERRIDE; + QString selectedMimeTypeFilter() override; + QString selectedNameFilter() override; + QList selectedFiles() override; protected: KFileWidget *m_fileWidget; }; class KDEPlatformFileDialogHelper : public QPlatformFileDialogHelper { Q_OBJECT public: KDEPlatformFileDialogHelper(); virtual ~KDEPlatformFileDialogHelper(); void initializeDialog(); - bool defaultNameFilterDisables() const Q_DECL_OVERRIDE; - QUrl directory() const Q_DECL_OVERRIDE; - QList selectedFiles() const Q_DECL_OVERRIDE; - QString selectedNameFilter() const Q_DECL_OVERRIDE; - void selectNameFilter(const QString &filter) Q_DECL_OVERRIDE; - void selectFile(const QUrl &filename) Q_DECL_OVERRIDE; - void setFilter() Q_DECL_OVERRIDE; - void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; - bool isSupportedUrl(const QUrl& url) const Q_DECL_OVERRIDE; + bool defaultNameFilterDisables() const override; + QUrl directory() const override; + QList selectedFiles() const override; +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) + QString selectedMimeTypeFilter() const override; + void selectMimeTypeFilter(const QString &filter) override; +#endif + QString selectedNameFilter() const override; + void selectNameFilter(const QString &filter) override; + void selectFile(const QUrl &filename) override; + void setFilter() override; + void setDirectory(const QUrl &directory) override; + bool isSupportedUrl(const QUrl& url) const override; - void exec() Q_DECL_OVERRIDE; - void hide() Q_DECL_OVERRIDE; - bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) Q_DECL_OVERRIDE; + void exec() override; + void hide() override; + bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) override; private Q_SLOTS: void saveSize(); private: void restoreSize(); KDEPlatformFileDialogBase *m_dialog; }; #endif // KDEPLATFORMFILEDIALOGHELPER_H diff --git a/src/platformtheme/kdeplatformsystemtrayicon.cpp b/src/platformtheme/kdeplatformsystemtrayicon.cpp index 11677e3..3c0b215 100644 --- a/src/platformtheme/kdeplatformsystemtrayicon.cpp +++ b/src/platformtheme/kdeplatformsystemtrayicon.cpp @@ -1,359 +1,359 @@ /* This file is part of the KDE libraries * Copyright 2014 Martin Gräßlin * * 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 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), 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 Lesser 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 "kdeplatformsystemtrayicon.h" #include #include #include #include #include #include #ifdef DBUS_SUPPORT_ENABLED #include #endif SystemTrayMenu::SystemTrayMenu() : QPlatformMenu() , m_tag(0) , m_menu(new QMenu()) { connect(m_menu.data(), &QMenu::aboutToShow, this, &QPlatformMenu::aboutToShow); connect(m_menu.data(), &QMenu::aboutToHide, this, &QPlatformMenu::aboutToHide); } SystemTrayMenu::~SystemTrayMenu() { if (m_menu) { m_menu->deleteLater(); } } QPlatformMenuItem *SystemTrayMenu::createMenuItem() const { return new SystemTrayMenuItem(); } void SystemTrayMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) { if (SystemTrayMenuItem *ours = qobject_cast(menuItem)) { bool inserted = false; if (SystemTrayMenuItem *oursBefore = qobject_cast(before)) { for (auto it = m_items.begin(); it != m_items.end(); ++it) { if (*it == oursBefore) { m_items.insert(it, ours); if (m_menu) { m_menu->insertAction(oursBefore->action(), ours->action()); } inserted = true; break; } } } if (!inserted) { m_items.append(ours); if (m_menu) { m_menu->addAction(ours->action()); } } } } QPlatformMenuItem *SystemTrayMenu::menuItemAt(int position) const { if (position < m_items.size()) { return m_items.at(position); } return Q_NULLPTR; } QPlatformMenuItem *SystemTrayMenu::menuItemForTag(quintptr tag) const { auto it = std::find_if(m_items.constBegin(), m_items.constEnd(), [tag](SystemTrayMenuItem *item) { return item->tag() == tag; }); if (it != m_items.constEnd()) { return *it; } return Q_NULLPTR; } void SystemTrayMenu::removeMenuItem(QPlatformMenuItem *menuItem) { if (SystemTrayMenuItem *ours = qobject_cast(menuItem)) { m_items.removeOne(ours); if (ours->action() && m_menu) { m_menu->removeAction(ours->action()); } } } void SystemTrayMenu::setEnabled(bool enabled) { if (!m_menu) { return; } m_menu->setEnabled(enabled); } void SystemTrayMenu::setIcon(const QIcon &icon) { if (!m_menu) { return; } m_menu->setIcon(icon); } void SystemTrayMenu::setTag(quintptr tag) { m_tag = tag; } void SystemTrayMenu::setText(const QString &text) { if (!m_menu) { return; } m_menu->setTitle(text); } void SystemTrayMenu::setVisible(bool visible) { if (!m_menu) { return; } m_menu->setVisible(visible); } void SystemTrayMenu::syncMenuItem(QPlatformMenuItem *menuItem) { Q_UNUSED(menuItem) // nothing to do } void SystemTrayMenu::syncSeparatorsCollapsible(bool enable) { if (!m_menu) { return; } m_menu->setSeparatorsCollapsible(enable); } quintptr SystemTrayMenu::tag() const { return m_tag; } QMenu *SystemTrayMenu::menu() const { return m_menu.data(); } SystemTrayMenuItem::SystemTrayMenuItem() : QPlatformMenuItem() , m_tag(0) , m_action(new QAction(this)) { connect(m_action, &QAction::triggered, this, &QPlatformMenuItem::activated); connect(m_action, &QAction::hovered, this, &QPlatformMenuItem::hovered); } SystemTrayMenuItem::~SystemTrayMenuItem() { } void SystemTrayMenuItem::setCheckable(bool checkable) { m_action->setCheckable(checkable); } void SystemTrayMenuItem::setChecked(bool isChecked) { m_action->setChecked(isChecked); } void SystemTrayMenuItem::setEnabled(bool enabled) { m_action->setEnabled(enabled); } void SystemTrayMenuItem::setFont(const QFont &font) { m_action->setFont(font); } void SystemTrayMenuItem::setIcon(const QIcon &icon) { m_action->setIcon(icon); } void SystemTrayMenuItem::setIsSeparator(bool isSeparator) { m_action->setSeparator(isSeparator); } void SystemTrayMenuItem::setMenu(QPlatformMenu *menu) { if (SystemTrayMenu *ourMenu = qobject_cast(menu)) { m_action->setMenu(ourMenu->menu()); } } void SystemTrayMenuItem::setRole(QPlatformMenuItem::MenuRole role) { Q_UNUSED(role) } void SystemTrayMenuItem::setShortcut(const QKeySequence &shortcut) { m_action->setShortcut(shortcut); } void SystemTrayMenuItem::setTag(quintptr tag) { m_tag = tag; } void SystemTrayMenuItem::setText(const QString &text) { m_action->setText(text); } void SystemTrayMenuItem::setVisible(bool isVisible) { m_action->setVisible(isVisible); } void SystemTrayMenuItem::setIconSize(int size) { Q_UNUSED(size); } quintptr SystemTrayMenuItem::tag() const { return m_tag; } QAction *SystemTrayMenuItem::action() const { return m_action; } KDEPlatformSystemTrayIcon::KDEPlatformSystemTrayIcon() : QPlatformSystemTrayIcon() , m_sni(Q_NULLPTR) { } KDEPlatformSystemTrayIcon::~KDEPlatformSystemTrayIcon() { } void KDEPlatformSystemTrayIcon::init() { if (!m_sni) { m_sni = new KStatusNotifierItem(); m_sni->setStandardActionsEnabled(false); m_sni->setTitle(QApplication::applicationDisplayName()); connect(m_sni, &KStatusNotifierItem::activateRequested, [this](bool active, const QPoint &pos) { Q_UNUSED(active) Q_UNUSED(pos) emit activated(QPlatformSystemTrayIcon::Trigger); }); connect(m_sni, &KStatusNotifierItem::secondaryActivateRequested, [this](const QPoint &pos) { Q_UNUSED(pos) - emit activated(QPlatformSystemTrayIcon::Context); + emit activated(QPlatformSystemTrayIcon::MiddleClick); }); } } void KDEPlatformSystemTrayIcon::cleanup() { delete m_sni; m_sni = Q_NULLPTR; } void KDEPlatformSystemTrayIcon::updateIcon(const QIcon &icon) { if (!m_sni) { return; } if (icon.name().isEmpty()) { m_sni->setIconByPixmap(icon); m_sni->setToolTipIconByPixmap(icon); } else { m_sni->setIconByName(icon.name()); m_sni->setToolTipIconByName(icon.name()); } } void KDEPlatformSystemTrayIcon::updateToolTip(const QString &tooltip) { if (!m_sni) { return; } m_sni->setToolTipTitle(tooltip); } void KDEPlatformSystemTrayIcon::updateMenu(QPlatformMenu *menu) { if (!m_sni) { return; } if (SystemTrayMenu *ourMenu = qobject_cast(menu)) { m_sni->setContextMenu(ourMenu->menu()); } } QPlatformMenu *KDEPlatformSystemTrayIcon::createMenu() const { return new SystemTrayMenu(); } QRect KDEPlatformSystemTrayIcon::geometry() const { // StatusNotifierItem doesn't provide the geometry return QRect(); } void KDEPlatformSystemTrayIcon::showMessage(const QString &title, const QString &msg, const QIcon &icon, MessageIcon iconType, int secs) { Q_UNUSED(iconType) if (!m_sni) { return; } m_sni->showMessage(title, msg, icon.name(), secs); } bool KDEPlatformSystemTrayIcon::isSystemTrayAvailable() const { #ifdef DBUS_SUPPORT_ENABLED QDBusInterface systrayHost(QStringLiteral("org.kde.StatusNotifierWatcher"), QStringLiteral("/StatusNotifierWatcher"), QStringLiteral("org.kde.StatusNotifierWatcher")); if (systrayHost.isValid()) { return systrayHost.property("IsStatusNotifierHostRegistered").toBool(); } #endif return false; } bool KDEPlatformSystemTrayIcon::supportsMessages() const { return true; } diff --git a/src/platformtheme/kdeplatformsystemtrayicon.h b/src/platformtheme/kdeplatformsystemtrayicon.h index 6825b4d..c8a7b96 100644 --- a/src/platformtheme/kdeplatformsystemtrayicon.h +++ b/src/platformtheme/kdeplatformsystemtrayicon.h @@ -1,111 +1,111 @@ /* This file is part of the KDE libraries * Copyright 2014 Martin Gräßlin * * 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 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), 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 Lesser 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 KDEPLATFORMSYSTEMTRAYICON_H #define KDEPLATFORMSYSTEMTRAYICON_H #include #include class KStatusNotifierItem; class SystemTrayMenuItem; class QAction; class QMenu; class SystemTrayMenu : public QPlatformMenu { Q_OBJECT public: SystemTrayMenu(); - ~SystemTrayMenu() Q_DECL_OVERRIDE; - void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) Q_DECL_OVERRIDE; - QPlatformMenuItem *menuItemAt(int position) const Q_DECL_OVERRIDE; - QPlatformMenuItem *menuItemForTag(quintptr tag) const Q_DECL_OVERRIDE; - void removeMenuItem(QPlatformMenuItem *menuItem) Q_DECL_OVERRIDE; - void setEnabled(bool enabled) Q_DECL_OVERRIDE; - void setIcon(const QIcon &icon) Q_DECL_OVERRIDE; - void setTag(quintptr tag) Q_DECL_OVERRIDE; - void setText(const QString &text) Q_DECL_OVERRIDE; - void setVisible(bool visible) Q_DECL_OVERRIDE; - void syncMenuItem(QPlatformMenuItem *menuItem) Q_DECL_OVERRIDE; - void syncSeparatorsCollapsible(bool enable) Q_DECL_OVERRIDE; - quintptr tag() const Q_DECL_OVERRIDE; - QPlatformMenuItem *createMenuItem() const Q_DECL_OVERRIDE; + ~SystemTrayMenu() override; + void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) override; + QPlatformMenuItem *menuItemAt(int position) const override; + QPlatformMenuItem *menuItemForTag(quintptr tag) const override; + void removeMenuItem(QPlatformMenuItem *menuItem) override; + void setEnabled(bool enabled) override; + void setIcon(const QIcon &icon) override; + void setTag(quintptr tag) override; + void setText(const QString &text) override; + void setVisible(bool visible) override; + void syncMenuItem(QPlatformMenuItem *menuItem) override; + void syncSeparatorsCollapsible(bool enable) override; + quintptr tag() const override; + QPlatformMenuItem *createMenuItem() const override; QMenu *menu() const; private: quintptr m_tag; QPointer m_menu; QList m_items; }; class SystemTrayMenuItem : public QPlatformMenuItem { Q_OBJECT public: SystemTrayMenuItem(); - ~SystemTrayMenuItem() Q_DECL_OVERRIDE; - void setCheckable(bool checkable) Q_DECL_OVERRIDE; - void setChecked(bool isChecked) Q_DECL_OVERRIDE; - void setEnabled(bool enabled) Q_DECL_OVERRIDE; - void setFont(const QFont &font) Q_DECL_OVERRIDE; - void setIcon(const QIcon &icon) Q_DECL_OVERRIDE; - void setIsSeparator(bool isSeparator) Q_DECL_OVERRIDE; - void setMenu(QPlatformMenu *menu) Q_DECL_OVERRIDE; - void setRole(MenuRole role) Q_DECL_OVERRIDE; - void setShortcut(const QKeySequence &shortcut) Q_DECL_OVERRIDE; - void setTag(quintptr tag) Q_DECL_OVERRIDE; - void setText(const QString &text) Q_DECL_OVERRIDE; - void setVisible(bool isVisible) Q_DECL_OVERRIDE; - quintptr tag() const Q_DECL_OVERRIDE; - void setIconSize(int size) Q_DECL_OVERRIDE; + ~SystemTrayMenuItem() override; + void setCheckable(bool checkable) override; + void setChecked(bool isChecked) override; + void setEnabled(bool enabled) override; + void setFont(const QFont &font) override; + void setIcon(const QIcon &icon) override; + void setIsSeparator(bool isSeparator) override; + void setMenu(QPlatformMenu *menu) override; + void setRole(MenuRole role) override; + void setShortcut(const QKeySequence &shortcut) override; + void setTag(quintptr tag) override; + void setText(const QString &text) override; + void setVisible(bool isVisible) override; + quintptr tag() const override; + void setIconSize(int size) override; QAction *action() const; private: quintptr m_tag; QAction *m_action; }; class KDEPlatformSystemTrayIcon : public QPlatformSystemTrayIcon { public: KDEPlatformSystemTrayIcon(); - ~KDEPlatformSystemTrayIcon() Q_DECL_OVERRIDE; + ~KDEPlatformSystemTrayIcon() override; - void init() Q_DECL_OVERRIDE; - void cleanup() Q_DECL_OVERRIDE; - void updateIcon(const QIcon &icon) Q_DECL_OVERRIDE; - void updateToolTip(const QString &tooltip) Q_DECL_OVERRIDE; - void updateMenu(QPlatformMenu *menu) Q_DECL_OVERRIDE; - QRect geometry() const Q_DECL_OVERRIDE; + void init() override; + void cleanup() override; + void updateIcon(const QIcon &icon) override; + void updateToolTip(const QString &tooltip) override; + void updateMenu(QPlatformMenu *menu) override; + QRect geometry() const override; void showMessage(const QString &title, const QString &msg, - const QIcon &icon, MessageIcon iconType, int secs) Q_DECL_OVERRIDE; + const QIcon &icon, MessageIcon iconType, int secs) override; - bool isSystemTrayAvailable() const Q_DECL_OVERRIDE; - bool supportsMessages() const Q_DECL_OVERRIDE; + bool isSystemTrayAvailable() const override; + bool supportsMessages() const override; - QPlatformMenu *createMenu() const Q_DECL_OVERRIDE; + QPlatformMenu *createMenu() const override; private: KStatusNotifierItem *m_sni; }; #endif diff --git a/src/platformtheme/kdeplatformtheme.cpp b/src/platformtheme/kdeplatformtheme.cpp index ff1157c..1377679 100644 --- a/src/platformtheme/kdeplatformtheme.cpp +++ b/src/platformtheme/kdeplatformtheme.cpp @@ -1,292 +1,337 @@ /* This file is part of the KDE libraries * Copyright 2013 Kevin Ottens * Copyright 2013 Aleix Pol Gonzalez * Copyright 2014 Lukáš Tinkl * * 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 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), 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 Lesser 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 #include "kdeplatformtheme.h" #include "kfontsettingsdata.h" #include "khintssettings.h" #include "kdeplatformfiledialoghelper.h" #include "kdeplatformsystemtrayicon.h" +#include "platformtheme_logging.h" #include #include #include #include #include #include #include #include #include #include #include #include +#include KdePlatformTheme::KdePlatformTheme() { m_fontsData = Q_NULLPTR; m_hints = Q_NULLPTR; loadSettings(); QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, false); + setQtQuickControlsTheme(); } KdePlatformTheme::~KdePlatformTheme() { delete m_fontsData; delete m_hints; } QVariant KdePlatformTheme::themeHint(QPlatformTheme::ThemeHint hintType) const { QVariant hint = m_hints->hint(hintType); if (hint.isValid()) { return hint; } else { return QPlatformTheme::themeHint(hintType); } } +QIcon KdePlatformTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions) const +{ + if (iconOptions.testFlag(DontUseCustomDirectoryIcons) && fileInfo.isDir()) { + qCWarning(PLATFORMTHEME) << Q_FUNC_INFO << "icon \"inode-directory\""; + return QIcon::fromTheme(QLatin1String("inode-directory")); + } + + qCWarning(PLATFORMTHEME) << Q_FUNC_INFO + << "file:" << fileInfo.absoluteFilePath() + << "icon:" << KIO::iconNameForUrl(QUrl::fromLocalFile(fileInfo.absoluteFilePath())); + return QIcon::fromTheme(KIO::iconNameForUrl(QUrl::fromLocalFile(fileInfo.absoluteFilePath()))); +} + +#if QT_VERSION < QT_VERSION_CHECK(5, 8, 0) +QPixmap KdePlatformTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, QPlatformTheme::IconOptions iconOptions) const +{ + return fileIcon(fileInfo, iconOptions).pixmap(size.toSize(), QIcon::Normal); +} +#endif + const QPalette *KdePlatformTheme::palette(Palette type) const { QPalette *palette = m_hints->palette(type); if (palette) { return palette; } else { return QPlatformTheme::palette(type); } } KFontSettingsData::FontTypes KdePlatformTheme::fontType(Font type) const { KFontSettingsData::FontTypes fdtype; switch (type) { case SystemFont: fdtype = KFontSettingsData::GeneralFont; break; case MenuFont: case MenuBarFont: case MenuItemFont: fdtype = KFontSettingsData::MenuFont; break; case MessageBoxFont: case LabelFont: case TipLabelFont: case StatusBarFont: case PushButtonFont: - case ToolButtonFont: case ItemViewFont: case ListViewFont: case HeaderViewFont: case ListBoxFont: case ComboMenuItemFont: case ComboLineEditFont: fdtype = KFontSettingsData::GeneralFont; break; case TitleBarFont: case MdiSubWindowTitleFont: case DockWidgetTitleFont: fdtype = KFontSettingsData::WindowTitleFont; break; case SmallFont: case MiniFont: fdtype = KFontSettingsData::SmallestReadableFont; break; case FixedFont: fdtype = KFontSettingsData::FixedFont; break; + case ToolButtonFont: + fdtype = KFontSettingsData::ToolbarFont; break; default: fdtype = KFontSettingsData::GeneralFont; break; } return fdtype; } const QFont *KdePlatformTheme::font(Font type) const { return m_fontsData->font(fontType(type)); } QIconEngine *KdePlatformTheme::createIconEngine(const QString &iconName) const { return new KIconEngine(iconName, KIconLoader::global()); } void KdePlatformTheme::loadSettings() { if (!m_fontsData) { m_fontsData = new KFontSettingsData; m_hints = new KHintsSettings; } } QList KdePlatformTheme::keyBindings(QKeySequence::StandardKey key) const { switch (key) { case QKeySequence::HelpContents: return KStandardShortcut::shortcut(KStandardShortcut::Help); case QKeySequence::WhatsThis: return KStandardShortcut::shortcut(KStandardShortcut::WhatsThis); case QKeySequence::Open: return KStandardShortcut::shortcut(KStandardShortcut::Open); case QKeySequence::Close: return KStandardShortcut::shortcut(KStandardShortcut::Close); case QKeySequence::Save: return KStandardShortcut::shortcut(KStandardShortcut::Save); case QKeySequence::New: return KStandardShortcut::shortcut(KStandardShortcut::New); case QKeySequence::Cut: return KStandardShortcut::shortcut(KStandardShortcut::Cut); case QKeySequence::Copy: return KStandardShortcut::shortcut(KStandardShortcut::Copy); case QKeySequence::Paste: return KStandardShortcut::shortcut(KStandardShortcut::Paste); case QKeySequence::Undo: return KStandardShortcut::shortcut(KStandardShortcut::Undo); case QKeySequence::Redo: return KStandardShortcut::shortcut(KStandardShortcut::Redo); case QKeySequence::Back: return KStandardShortcut::shortcut(KStandardShortcut::Back); case QKeySequence::Forward: return KStandardShortcut::shortcut(KStandardShortcut::Forward); case QKeySequence::Refresh: return KStandardShortcut::shortcut(KStandardShortcut::Reload); case QKeySequence::ZoomIn: return KStandardShortcut::shortcut(KStandardShortcut::ZoomIn); case QKeySequence::ZoomOut: return KStandardShortcut::shortcut(KStandardShortcut::ZoomOut); case QKeySequence::Print: return KStandardShortcut::shortcut(KStandardShortcut::Print); case QKeySequence::Find: return KStandardShortcut::shortcut(KStandardShortcut::Find); case QKeySequence::FindNext: return KStandardShortcut::shortcut(KStandardShortcut::FindNext); case QKeySequence::FindPrevious: return KStandardShortcut::shortcut(KStandardShortcut::FindPrev); case QKeySequence::Replace: return KStandardShortcut::shortcut(KStandardShortcut::Replace); case QKeySequence::SelectAll: return KStandardShortcut::shortcut(KStandardShortcut::SelectAll); case QKeySequence::MoveToNextWord: return KStandardShortcut::shortcut(KStandardShortcut::ForwardWord); case QKeySequence::MoveToPreviousWord: return KStandardShortcut::shortcut(KStandardShortcut::BackwardWord); case QKeySequence::MoveToNextPage: return KStandardShortcut::shortcut(KStandardShortcut::Next); case QKeySequence::MoveToPreviousPage: return KStandardShortcut::shortcut(KStandardShortcut::Prior); case QKeySequence::MoveToStartOfLine: return KStandardShortcut::shortcut(KStandardShortcut::BeginningOfLine); case QKeySequence::MoveToEndOfLine: return KStandardShortcut::shortcut(KStandardShortcut::EndOfLine); case QKeySequence::MoveToStartOfDocument: return KStandardShortcut::shortcut(KStandardShortcut::Begin); case QKeySequence::MoveToEndOfDocument: return KStandardShortcut::shortcut(KStandardShortcut::End); case QKeySequence::SaveAs: return KStandardShortcut::shortcut(KStandardShortcut::SaveAs); case QKeySequence::Preferences: return KStandardShortcut::shortcut(KStandardShortcut::Preferences); case QKeySequence::Quit: return KStandardShortcut::shortcut(KStandardShortcut::Quit); case QKeySequence::FullScreen: return KStandardShortcut::shortcut(KStandardShortcut::FullScreen); case QKeySequence::Deselect: return KStandardShortcut::shortcut(KStandardShortcut::Deselect); case QKeySequence::DeleteStartOfWord: return KStandardShortcut::shortcut(KStandardShortcut::DeleteWordBack); case QKeySequence::DeleteEndOfWord: return KStandardShortcut::shortcut(KStandardShortcut::DeleteWordForward); case QKeySequence::NextChild: return KStandardShortcut::shortcut(KStandardShortcut::TabNext); case QKeySequence::PreviousChild: return KStandardShortcut::shortcut(KStandardShortcut::TabPrev); default: return QPlatformTheme::keyBindings(key); } } bool KdePlatformTheme::usePlatformNativeDialog(QPlatformTheme::DialogType type) const { return type == QPlatformTheme::FileDialog; } QString KdePlatformTheme::standardButtonText(int button) const { switch (static_cast(button)) { case QPlatformDialogHelper::NoButton: - qWarning() << Q_FUNC_INFO << "Unsupported standard button:" << button; + qCWarning(PLATFORMTHEME) << Q_FUNC_INFO << "Unsupported standard button:" << button; return QString(); case QPlatformDialogHelper::Ok: return KStandardGuiItem::ok().text(); case QPlatformDialogHelper::Save: return KStandardGuiItem::save().text(); case QPlatformDialogHelper::SaveAll: return i18nc("@action:button", "Save All"); case QPlatformDialogHelper::Open: return KStandardGuiItem::open().text(); case QPlatformDialogHelper::Yes: return KStandardGuiItem::yes().text(); case QPlatformDialogHelper::YesToAll: return i18nc("@action:button", "Yes to All"); case QPlatformDialogHelper::No: return KStandardGuiItem::no().text(); case QPlatformDialogHelper::NoToAll: return i18nc("@action:button", "No to All"); case QPlatformDialogHelper::Abort: // FIXME KStandardGuiItem::stop() doesn't seem right here return i18nc("@action:button", "Abort"); case QPlatformDialogHelper::Retry: return i18nc("@action:button", "Retry"); case QPlatformDialogHelper::Ignore: return i18nc("@action:button", "Ignore"); case QPlatformDialogHelper::Close: return KStandardGuiItem::close().text(); case QPlatformDialogHelper::Cancel: return KStandardGuiItem::cancel().text(); case QPlatformDialogHelper::Discard: return KStandardGuiItem::discard().text(); case QPlatformDialogHelper::Help: return KStandardGuiItem::help().text(); case QPlatformDialogHelper::Apply: return KStandardGuiItem::apply().text(); case QPlatformDialogHelper::Reset: return KStandardGuiItem::reset().text(); case QPlatformDialogHelper::RestoreDefaults: return KStandardGuiItem::defaults().text(); default: return QPlatformTheme::defaultStandardButtonText(button); } } QPlatformDialogHelper *KdePlatformTheme::createPlatformDialogHelper(QPlatformTheme::DialogType type) const { switch (type) { case QPlatformTheme::FileDialog: return new KDEPlatformFileDialogHelper; case QPlatformTheme::FontDialog: case QPlatformTheme::ColorDialog: case QPlatformTheme::MessageDialog: default: return 0; } } QPlatformSystemTrayIcon *KdePlatformTheme::createPlatformSystemTrayIcon() const { return new KDEPlatformSystemTrayIcon; } + +//force QtQuickControls2 to use the desktop theme as default +void KdePlatformTheme::setQtQuickControlsTheme() +{ + //if the user is running only a QGuiApplication. Abort as this style is all about QWidgets and we know setting this will make it crash + if (!qobject_cast(qApp)) { + if (qgetenv("QT_QUICK_CONTROLS_1_STYLE").right(7) == "Desktop") { + qunsetenv("QT_QUICK_CONTROLS_1_STYLE"); + } + return; + } + //if the user has explicitly set something else, don't meddle + // Do this after potentially unsetting QT_QUICK_CONTROLS_1_STYLE! + if (qEnvironmentVariableIsSet("QT_QUICK_CONTROLS_STYLE")) { + return; + } + // newer plasma-integration versions use QtQuickControls2 for this + // I don't want that extra dependency. + qputenv("QT_QUICK_CONTROLS_STYLE", "org.kde.desktop"); +} + diff --git a/src/platformtheme/kdeplatformtheme.h b/src/platformtheme/kdeplatformtheme.h index 19fe815..923037b 100644 --- a/src/platformtheme/kdeplatformtheme.h +++ b/src/platformtheme/kdeplatformtheme.h @@ -1,62 +1,73 @@ /* This file is part of the KDE libraries * Copyright 2013 Kevin Ottens * * 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 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), 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 Lesser 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 KDEPLATFORMTHEME_H #define KDEPLATFORMTHEME_H #include #include "kfontsettingsdata.h" #include #include #include class KHintsSettings; class QIconEngine; class KdePlatformTheme : public QPlatformTheme { public: KdePlatformTheme(); ~KdePlatformTheme(); - QVariant themeHint(ThemeHint hint) const Q_DECL_OVERRIDE; - const QPalette *palette(Palette type = SystemPalette) const Q_DECL_OVERRIDE; - const QFont *font(Font type) const Q_DECL_OVERRIDE; - QIconEngine *createIconEngine(const QString &iconName) const Q_DECL_OVERRIDE; - QList keyBindings(QKeySequence::StandardKey key) const Q_DECL_OVERRIDE; + QVariant themeHint(ThemeHint hint) const override; +#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) + QIcon fileIcon(const QFileInfo &fileInfo, + QPlatformTheme::IconOptions iconOptions) const override; +#else + QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions) const override; + // this will be the implementation + QIcon fileIcon(const QFileInfo &fileInfo, + QPlatformTheme::IconOptions iconOptions) const; +#endif + const QPalette *palette(Palette type = SystemPalette) const override; + const QFont *font(Font type) const override; + QIconEngine *createIconEngine(const QString &iconName) const override; + QList keyBindings(QKeySequence::StandardKey key) const override; - QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const Q_DECL_OVERRIDE; - bool usePlatformNativeDialog(DialogType type) const Q_DECL_OVERRIDE; + QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const override; + bool usePlatformNativeDialog(DialogType type) const override; - QString standardButtonText(int button) const Q_DECL_OVERRIDE; + QString standardButtonText(int button) const override; - QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const Q_DECL_OVERRIDE; + QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const override; protected: void loadSettings(); + void setQtQuickControlsTheme(); KFontSettingsData::FontTypes fontType(Font type) const; private: KHintsSettings *m_hints; KFontSettingsData *m_fontsData; }; #endif // KDEPLATFORMTHEME_H diff --git a/src/platformtheme/kdirselectdialog.cpp b/src/platformtheme/kdirselectdialog.cpp index ffacd9e..9d13ec4 100644 --- a/src/platformtheme/kdirselectdialog.cpp +++ b/src/platformtheme/kdirselectdialog.cpp @@ -1,578 +1,588 @@ /* Copyright (C) 2001,2002 Carsten Pfeiffer Copyright (C) 2001 Michael Jarrett Copyright (C) 2009 Shaun Reich This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 "kdirselectdialog_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kfiletreeview_p.h" #include #include // ### add mutator for treeview! class KDirSelectDialog::Private { public: Private(bool localOnly, KDirSelectDialog *parent) : m_parent(parent), m_localOnly(localOnly), m_comboLocked(false), m_urlCombo(0) { } void readConfig(const KSharedConfigPtr &config, const QString &group); void saveConfig(KSharedConfigPtr config, const QString &group); void slotMkdir(); void slotCurrentChanged(); void slotExpand(const QModelIndex &); void slotUrlActivated(const QString &); void slotComboTextChanged(const QString &); void slotContextMenuRequested(const QPoint &); void slotNewFolder(); void slotMoveToTrash(); void slotDelete(); void slotProperties(); KDirSelectDialog *m_parent; bool m_localOnly : 1; bool m_comboLocked : 1; QUrl m_rootUrl; QUrl m_startDir; KFileTreeView *m_treeView; QMenu *m_contextMenu; KActionCollection *m_actions; KFilePlacesView *m_placesView; KHistoryComboBox *m_urlCombo; QString m_recentDirClass; QUrl m_startURL; QAction *moveToTrash; QAction *deleteAction; QAction *showHiddenFoldersAction; }; void KDirSelectDialog::Private::readConfig(const KSharedConfig::Ptr &config, const QString &group) { m_urlCombo->clear(); KConfigGroup conf(config, group); m_urlCombo->setHistoryItems(conf.readPathEntry("History Items", QStringList())); const QSize size = conf.readEntry("DirSelectDialog Size", QSize()); if (size.isValid()) { m_parent->resize(size); } } void KDirSelectDialog::Private::saveConfig(KSharedConfig::Ptr config, const QString &group) { KConfigGroup conf(config, group); KConfigGroup::WriteConfigFlags flags(KConfigGroup::Persistent | KConfigGroup::Global); conf.writePathEntry("History Items", m_urlCombo->historyItems(), flags); conf.writeEntry("DirSelectDialog Size", m_parent->size(), flags); config->sync(); } void KDirSelectDialog::Private::slotMkdir() { bool ok; QString where = m_parent->url().toDisplayString(QUrl::PreferLocalFile); QString name = i18nc("folder name", "New Folder"); if (m_parent->url().isLocalFile() && QFileInfo::exists(m_parent->url().toLocalFile() + QLatin1Char('/') + name)) { name = KIO::suggestName(m_parent->url(), name); } QString directory = KIO::encodeFileName(QInputDialog::getText(m_parent, i18nc("@title:window", "New Folder"), i18nc("@label:textbox", "Create new folder in:\n%1", where), QLineEdit::Normal, name, &ok)); if (!ok) { return; } bool selectDirectory = true; bool writeOk = false; bool exists = false; QUrl folderurl(m_parent->url()); const QStringList dirs = directory.split(QLatin1Char('/'), QString::SkipEmptyParts); QStringList::ConstIterator it = dirs.begin(); for (; it != dirs.end(); ++it) { folderurl.setPath(folderurl.path() + QLatin1Char('/') + *it); KIO::StatJob *job = KIO::stat(folderurl); KJobWidgets::setWindow(job, m_parent); job->setDetails(0); //We only want to know if it exists, 0 == that. job->setSide(KIO::StatJob::DestinationSide); exists = job->exec(); if (!exists) { KIO::MkdirJob *job = KIO::mkdir(folderurl); KJobWidgets::setWindow(job, m_parent); writeOk = job->exec(); } } if (exists) { // url was already existent QString which = folderurl.toDisplayString(QUrl::PreferLocalFile); KMessageBox::sorry(m_parent, i18n("A file or folder named %1 already exists.", which)); selectDirectory = false; } else if (!writeOk) { KMessageBox::sorry(m_parent, i18n("You do not have permission to create that folder.")); } else if (selectDirectory) { m_parent->setCurrentUrl(folderurl); } } void KDirSelectDialog::Private::slotCurrentChanged() { if (m_comboLocked) { return; } const QUrl u = m_treeView->currentUrl(); if (u.isValid()) { m_urlCombo->setEditText(u.toDisplayString(QUrl::PreferLocalFile)); } else { m_urlCombo->setEditText(QString()); } } void KDirSelectDialog::Private::slotUrlActivated(const QString &text) { if (text.isEmpty()) { return; } const QUrl url = QUrl::fromUserInput(text); m_urlCombo->addToHistory(url.toDisplayString()); if (m_parent->localOnly() && !url.isLocalFile()) { return; //FIXME: messagebox for the user } QUrl oldUrl = m_treeView->currentUrl(); if (oldUrl.isEmpty()) { oldUrl = m_startDir; } m_parent->setCurrentUrl(oldUrl); } void KDirSelectDialog::Private::slotComboTextChanged(const QString &text) { m_treeView->blockSignals(true); QUrl url = QUrl::fromUserInput(text); #ifdef Q_OS_WIN QUrl rootUrl(m_treeView->rootUrl()); if (url.isLocalFile() && !rootUrl.isParentOf(url) && !rootUrl.matches(url, QUrl::StripTrailingSlash)) { QUrl tmp = KIO::upUrl(url); while (tmp.path().length() > 1) { url = tmp; tmp = KIO::upUrl(url); } m_treeView->setRootUrl(url); } #endif m_treeView->setCurrentUrl(url); m_treeView->blockSignals(false); } void KDirSelectDialog::Private::slotContextMenuRequested(const QPoint &pos) { m_contextMenu->popup(m_treeView->viewport()->mapToGlobal(pos)); } void KDirSelectDialog::Private::slotExpand(const QModelIndex &index) { m_treeView->setExpanded(index, !m_treeView->isExpanded(index)); } void KDirSelectDialog::Private::slotNewFolder() { slotMkdir(); } void KDirSelectDialog::Private::slotMoveToTrash() { const QUrl url = m_treeView->selectedUrl(); KIO::JobUiDelegate job; if (job.askDeleteConfirmation(QList() << url, KIO::JobUiDelegate::Trash, KIO::JobUiDelegate::DefaultConfirmation)) { KIO::CopyJob *copyJob = KIO::trash(url); KJobWidgets::setWindow(copyJob, m_parent); - copyJob->ui()->setAutoErrorHandlingEnabled(true); + copyJob->uiDelegate()->setAutoErrorHandlingEnabled(true); } } void KDirSelectDialog::Private::slotDelete() { const QUrl url = m_treeView->selectedUrl(); KIO::JobUiDelegate job; if (job.askDeleteConfirmation(QList() << url, KIO::JobUiDelegate::Delete, KIO::JobUiDelegate::DefaultConfirmation)) { KIO::DeleteJob *deleteJob = KIO::del(url); KJobWidgets::setWindow(deleteJob, m_parent); - deleteJob->ui()->setAutoErrorHandlingEnabled(true); + deleteJob->uiDelegate()->setAutoErrorHandlingEnabled(true); } } void KDirSelectDialog::Private::slotProperties() { KPropertiesDialog *dialog = 0; dialog = new KPropertiesDialog(m_treeView->selectedUrl(), this->m_parent); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->show(); } KDirSelectDialog::KDirSelectDialog(const QUrl &startDir, bool localOnly, QWidget *parent) // #ifdef Q_OS_WIN // : QDialog(parent, Qt::WindowMinMaxButtonsHint), // #else // : QDialog(parent), // #endif : d(new Private(localOnly, this)) { setWindowTitle(i18nc("@title:window", "Select Folder")); QVBoxLayout *topLayout = new QVBoxLayout; setLayout(topLayout); QFrame *page = new QFrame(this); topLayout->addWidget(page); QPushButton *folderButton = new QPushButton; KGuiItem::assign(folderButton, KGuiItem(i18nc("@action:button", "New Folder..."), QStringLiteral("folder-new"))); connect(folderButton, SIGNAL(clicked()), this, SLOT(slotNewFolder())); m_buttons = new QDialogButtonBox(this); m_buttons->addButton(folderButton, QDialogButtonBox::ActionRole); m_buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(m_buttons, SIGNAL(accepted()), this, SLOT(accept())); connect(m_buttons, SIGNAL(rejected()), this, SLOT(reject())); topLayout->addWidget(m_buttons); QHBoxLayout *hlay = new QHBoxLayout(page); hlay->setMargin(0); QVBoxLayout *mainLayout = new QVBoxLayout(); d->m_actions = new KActionCollection(this); d->m_actions->addAssociatedWidget(this); d->m_placesView = new KFilePlacesView(page); d->m_placesView->setModel(new KFilePlacesModel(d->m_placesView)); d->m_placesView->setObjectName(QStringLiteral("speedbar")); d->m_placesView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); d->m_placesView->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); connect(d->m_placesView, SIGNAL(urlChanged(QUrl)), SLOT(setCurrentUrl(QUrl))); hlay->addWidget(d->m_placesView); hlay->addLayout(mainLayout); d->m_treeView = new KFileTreeView(page); d->m_treeView->setDirOnlyMode(true); d->m_treeView->setContextMenuPolicy(Qt::CustomContextMenu); for (int i = 1; i < d->m_treeView->model()->columnCount(); ++i) { d->m_treeView->hideColumn(i); } d->m_urlCombo = new KHistoryComboBox(page); d->m_urlCombo->setLayoutDirection(Qt::LeftToRight); d->m_urlCombo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength); d->m_urlCombo->setTrapReturnKey(true); d->m_urlCombo->setPixmapProvider(new KUrlPixmapProvider()); KUrlCompletion *comp = new KUrlCompletion(); comp->setMode(KUrlCompletion::DirCompletion); d->m_urlCombo->setCompletionObject(comp, true); d->m_urlCombo->setAutoDeleteCompletionObject(true); d->m_urlCombo->setDuplicatesEnabled(false); d->m_contextMenu = new QMenu(this); QAction *newFolder = new QAction(i18nc("@action:inmenu", "New Folder..."), this); d->m_actions->addAction(newFolder->objectName(), newFolder); newFolder->setIcon(QIcon::fromTheme(QStringLiteral("folder-new"))); newFolder->setShortcut(Qt::Key_F10); connect(newFolder, SIGNAL(triggered(bool)), this, SLOT(slotNewFolder())); d->m_contextMenu->addAction(newFolder); d->moveToTrash = new QAction(i18nc("@action:inmenu", "Move to Trash"), this); d->m_actions->addAction(d->moveToTrash->objectName(), d->moveToTrash); d->moveToTrash->setIcon(QIcon::fromTheme(QStringLiteral("user-trash"))); d->moveToTrash->setShortcut(Qt::Key_Delete); connect(d->moveToTrash, SIGNAL(triggered(bool)), this, SLOT(slotMoveToTrash())); d->m_contextMenu->addAction(d->moveToTrash); d->deleteAction = new QAction(i18nc("@action:inmenu", "Delete"), this); d->m_actions->addAction(d->deleteAction->objectName(), d->deleteAction); d->deleteAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); d->deleteAction->setShortcut(Qt::SHIFT + Qt::Key_Delete); connect(d->deleteAction, SIGNAL(triggered(bool)), this, SLOT(slotDelete())); d->m_contextMenu->addAction(d->deleteAction); d->m_contextMenu->addSeparator(); d->showHiddenFoldersAction = new KToggleAction(i18nc("@option:check", "Show Hidden Folders"), this); d->m_actions->addAction(d->showHiddenFoldersAction->objectName(), d->showHiddenFoldersAction); d->showHiddenFoldersAction->setShortcut(Qt::Key_F8); connect(d->showHiddenFoldersAction, SIGNAL(triggered(bool)), d->m_treeView, SLOT(setShowHiddenFiles(bool))); d->m_contextMenu->addAction(d->showHiddenFoldersAction); d->m_contextMenu->addSeparator(); QAction *propertiesAction = new QAction(i18nc("@action:inmenu", "Properties"), this); d->m_actions->addAction(propertiesAction->objectName(), propertiesAction); propertiesAction->setIcon(QIcon::fromTheme(QStringLiteral("document-properties"))); propertiesAction->setShortcut(Qt::ALT + Qt::Key_Return); connect(propertiesAction, SIGNAL(triggered(bool)), this, SLOT(slotProperties())); d->m_contextMenu->addAction(propertiesAction); d->m_startURL = KFileWidget::getStartUrl(startDir, d->m_recentDirClass); if (localOnly && !d->m_startURL.isLocalFile()) { QString docPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); if (QDir(docPath).exists()) { d->m_startURL = QUrl::fromLocalFile(docPath); } else { d->m_startURL = QUrl::fromLocalFile(QDir::homePath()); } } d->m_startDir = d->m_startURL; d->m_rootUrl = d->m_treeView->rootUrl(); d->readConfig(KSharedConfig::openConfig(), QStringLiteral("DirSelect Dialog")); mainLayout->addWidget(d->m_treeView, 1); mainLayout->addWidget(d->m_urlCombo, 0); connect(d->m_treeView, SIGNAL(currentChanged(QUrl)), SLOT(slotCurrentChanged())); connect(d->m_treeView, SIGNAL(activated(QModelIndex)), SLOT(slotExpand(QModelIndex))); connect(d->m_treeView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(slotContextMenuRequested(QPoint))); connect(d->m_urlCombo, SIGNAL(editTextChanged(QString)), SLOT(slotComboTextChanged(QString))); connect(d->m_urlCombo, SIGNAL(activated(QString)), SLOT(slotUrlActivated(QString))); connect(d->m_urlCombo, SIGNAL(returnPressed(QString)), SLOT(slotUrlActivated(QString))); setCurrentUrl(d->m_startURL); } KDirSelectDialog::~KDirSelectDialog() { delete d; } QUrl KDirSelectDialog::url() const { QUrl comboUrl = QUrl::fromUserInput(d->m_urlCombo->currentText()); if (comboUrl.isValid()) { KIO::StatJob *statJob = KIO::stat(comboUrl, KIO::HideProgressInfo); KJobWidgets::setWindow(statJob, d->m_parent); const bool ok = statJob->exec(); if (ok && statJob->statResult().isDir()) { return comboUrl; } } // qDebug() << comboUrl.path() << " is not an accessible directory"; return d->m_treeView->currentUrl(); } QUrl KDirSelectDialog::rootUrl() const { return d->m_rootUrl; } QAbstractItemView *KDirSelectDialog::view() const { return d->m_treeView; } bool KDirSelectDialog::localOnly() const { return d->m_localOnly; } QUrl KDirSelectDialog::startDir() const { return d->m_startDir; } void KDirSelectDialog::setCurrentUrl(const QUrl &url) { if (!url.isValid()) { return; } if (url.scheme() != d->m_rootUrl.scheme()) { QUrl u(url); //We need the url to end with / because some code ahead (kdirmodel) is expecting //to find the / separator. It can happen that a valid url like smb: does not have //one so we should add it. if (!u.toString().endsWith(QLatin1Char('/'))) { u.setPath(QStringLiteral("/")); } d->m_treeView->setRootUrl(u); d->m_rootUrl = u; } //Check if url represents a hidden folder and enable showing them QString fileName = url.fileName(); //TODO a better hidden file check? bool isHidden = fileName.length() > 1 && fileName[0] == QLatin1Char('.') && (fileName.length() > 2 ? fileName[1] != QLatin1Char('.') : true); bool showHiddenFiles = isHidden && !d->m_treeView->showHiddenFiles(); if (showHiddenFiles) { d->showHiddenFoldersAction->setChecked(true); d->m_treeView->setShowHiddenFiles(true); } d->m_treeView->setCurrentUrl(url); } void KDirSelectDialog::accept() { QUrl selectedUrl = url(); if (!selectedUrl.isValid()) { return; } if (!d->m_recentDirClass.isEmpty()) { KRecentDirs::add(d->m_recentDirClass, selectedUrl.toString()); } d->m_urlCombo->addToHistory(selectedUrl.toDisplayString()); KFileWidget::setStartDir(url()); QDialog::accept(); } void KDirSelectDialog::hideEvent(QHideEvent *event) { d->saveConfig(KSharedConfig::openConfig(), QStringLiteral("DirSelect Dialog")); QDialog::hideEvent(event); } // static QUrl KDirSelectDialog::selectDirectory(const QUrl &startDir, bool localOnly, QWidget *parent, const QString &caption) { KDirSelectDialog myDialog(startDir, localOnly, parent); if (!caption.isNull()) { myDialog.setWindowTitle(caption); } if (myDialog.exec() == QDialog::Accepted) { QUrl url = myDialog.url(); //Returning the most local url if (url.isLocalFile()) { return url; } KIO::StatJob *job = KIO::stat(url); KJobWidgets::setWindow(job, parent); if (!job->exec()) { return url; } KIO::UDSEntry entry = job->statResult(); const QString path = entry.stringValue(KIO::UDSEntry::UDS_LOCAL_PATH); return path.isEmpty() ? url : QUrl::fromLocalFile(path); } else { return QUrl(); } } QUrl KDirSelectDialog::directory() { return url(); } QList KDirSelectDialog::selectedFiles() { return QList() << url(); } void KDirSelectDialog::setDirectory(const QUrl &directory) { setCurrentUrl(directory); } +QString KDirSelectDialog::selectedMimeTypeFilter() +{ + return QString(); +} + QString KDirSelectDialog::selectedNameFilter() { return QString(); } void KDirSelectDialog::selectFile(const QUrl &filename) { Q_UNUSED(filename) } +void KDirSelectDialog::selectMimeTypeFilter(const QString &filter) +{ + Q_UNUSED(filter) +} + void KDirSelectDialog::selectNameFilter(const QString &filter) { Q_UNUSED(filter) } #include "moc_kdirselectdialog_p.cpp" diff --git a/src/platformtheme/kdirselectdialog_p.h b/src/platformtheme/kdirselectdialog_p.h index 06be37f..85bd86f 100644 --- a/src/platformtheme/kdirselectdialog_p.h +++ b/src/platformtheme/kdirselectdialog_p.h @@ -1,136 +1,138 @@ /* Copyright (C) 2001 Michael Jarrett Copyright (C) 2001 Carsten Pfeiffer Copyright (C) 2009 Shaun Reich This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 KDIRSELECTDIALOG_H #define KDIRSELECTDIALOG_H #include "kdeplatformfiledialogbase_p.h" #include class QAbstractItemView; /** * A pretty dialog for a KDirSelect control for selecting directories. * @author Michael Jarrett * @deprecated since 5.0, use QFileDialog::getExistingDirectoryUrl instead. */ class KDirSelectDialog : public KDEPlatformFileDialogBase { Q_OBJECT public: /** * Creates a new directory selection dialog. * @internal use the static selectDirectory function * @param startDir the directory, initially shown * @param localOnly unused. You can only select paths below the startDir * @param parent the parent for the dialog, usually 0L */ explicit KDirSelectDialog(const QUrl &startDir = QUrl(), bool localOnly = false, QWidget *parent = 0L); /** * Destroys the directory selection dialog. */ ~KDirSelectDialog(); /** * Returns the currently selected URL, or an empty one if no item is selected. * * If the URL entered in the combobox is valid and exists, it is returned. * Otherwise, the URL selected in the treeview is returned instead. */ QUrl url() const; /** * Returns the root url */ QUrl rootUrl() const; /** * Returns a pointer to the view which is used for displaying the directories. */ QAbstractItemView *view() const; /** * Returns whether only local directories can be selected. */ bool localOnly() const; /** * Creates a KDirSelectDialog, and returns the result. * @param startDir the directory, initially shown * The tree will display this directory and subdirectories of it. * @param localOnly unused. You can only select paths below the startDir * @param parent the parent widget to use for the dialog, or NULL to create a parent-less dialog * @param caption the caption to use for the dialog, or QString() for the default caption * @return The URL selected, or an empty URL if the user canceled * or no URL was selected. * * @deprecated since 5.0, use QFileDialog::getExistingDirectory (if localOnly was true) * or QFileDialog::getExistingDirectoryUrl (if localOnly was false) instead. */ static QUrl selectDirectory(const QUrl &startDir = QUrl(), bool localOnly = false, QWidget *parent = 0L, const QString &caption = QString()); /** * @return The path for the root node */ QUrl startDir() const; - QUrl directory() Q_DECL_OVERRIDE; - void selectNameFilter(const QString &filter) Q_DECL_OVERRIDE; - void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; - void selectFile(const QUrl &filename) Q_DECL_OVERRIDE; - QString selectedNameFilter() Q_DECL_OVERRIDE; - QList selectedFiles() Q_DECL_OVERRIDE; + QUrl directory() override; + void selectMimeTypeFilter(const QString &filter) override; + void selectNameFilter(const QString &filter) override; + void setDirectory(const QUrl &directory) override; + void selectFile(const QUrl &filename) override; + QString selectedMimeTypeFilter() override; + QString selectedNameFilter() override; + QList selectedFiles() override; public Q_SLOTS: /** * Sets the current @p url in the dialog. */ void setCurrentUrl(const QUrl &url); protected: - void accept() Q_DECL_OVERRIDE; + void accept() override; /** * Reimplemented for saving the dialog geometry. */ - void hideEvent(QHideEvent *event) Q_DECL_OVERRIDE; + void hideEvent(QHideEvent *event) override; private: class Private; Private *const d; Q_PRIVATE_SLOT(d, void slotCurrentChanged()) Q_PRIVATE_SLOT(d, void slotExpand(const QModelIndex &)) Q_PRIVATE_SLOT(d, void slotUrlActivated(const QString &)) Q_PRIVATE_SLOT(d, void slotComboTextChanged(const QString &)) Q_PRIVATE_SLOT(d, void slotContextMenuRequested(const QPoint &)) Q_PRIVATE_SLOT(d, void slotNewFolder()) Q_PRIVATE_SLOT(d, void slotMoveToTrash()) Q_PRIVATE_SLOT(d, void slotDelete()) Q_PRIVATE_SLOT(d, void slotProperties()) }; #endif diff --git a/src/platformtheme/kfiletreeview_p.h b/src/platformtheme/kfiletreeview_p.h index 8442018..3a27164 100644 --- a/src/platformtheme/kfiletreeview_p.h +++ b/src/platformtheme/kfiletreeview_p.h @@ -1,128 +1,128 @@ /* This file is part of the KDE project Copyright (C) 2007 Tobias Koenig 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 KFILETREEVIEW_H #define KFILETREEVIEW_H #include #include /** * The file treeview offers a treeview on the filesystem. */ class KFileTreeView : public QTreeView // exported only for kfiletreeviewtest { Q_OBJECT public: /** * Creates a new file tree view. */ KFileTreeView(QWidget *parent = 0); /** * Destroys the file tree view. */ ~KFileTreeView(); /** * Returns the current url. */ QUrl currentUrl() const; /** * Returns the selected url. */ QUrl selectedUrl() const; /** * Returns all selected urls. */ QList selectedUrls() const; /** * Returns the current root url of the view. */ QUrl rootUrl() const; /** * Returns true if the view is currently showing hidden files * @since 4.3 */ bool showHiddenFiles() const; /** * @reimplemented */ - QSize sizeHint() const Q_DECL_OVERRIDE; + QSize sizeHint() const override; public Q_SLOTS: /** * Sets whether the dir-only mode is @p enabled. * * In dir-only mode, only directories and subdirectories * are listed in the view. */ void setDirOnlyMode(bool enabled); /** * Sets whether hidden files shall be listed. */ void setShowHiddenFiles(bool enabled); /** * Sets the current @p url of the view. */ void setCurrentUrl(const QUrl &url); /** * Sets the root @p url of the view. * * The default is file:///. */ void setRootUrl(const QUrl &url); Q_SIGNALS: /** * This signal is emitted whenever an @p url has been activated. */ void activated(const QUrl &url); /** * This signal is emitted whenever the current @p url has been changed. */ void currentChanged(const QUrl &url); protected: using QTreeView::currentChanged; - void contextMenuEvent(QContextMenuEvent *) Q_DECL_OVERRIDE; + void contextMenuEvent(QContextMenuEvent *) override; private: class Private; Private *const d; Q_PRIVATE_SLOT(d, void _k_activated(const QModelIndex &)) Q_PRIVATE_SLOT(d, void _k_currentChanged(const QModelIndex &, const QModelIndex &)) Q_PRIVATE_SLOT(d, void _k_expanded(const QModelIndex &)) }; #endif diff --git a/src/platformtheme/kfontsettingsdata.cpp b/src/platformtheme/kfontsettingsdata.cpp index fc0c980..c2eec44 100644 --- a/src/platformtheme/kfontsettingsdata.cpp +++ b/src/platformtheme/kfontsettingsdata.cpp @@ -1,131 +1,133 @@ /* This file is part of the KDE libraries Copyright (C) 2000, 2006 David Faure Copyright 2008 Friedrich W. H. Kossebau Copyright 2013 Aleix Pol Gonzalez This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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. */ #undef QT_NO_CAST_FROM_ASCII #include "kfontsettingsdata.h" #include #include #include #include #ifdef DBUS_SUPPORT_ENABLED #include #include #endif #include #include #include KFontSettingsData::KFontSettingsData() : QObject(0) { #ifdef DBUS_SUPPORT_ENABLED QMetaObject::invokeMethod(this, "delayedDBusConnects", Qt::QueuedConnection); #endif for (int i = 0; i < FontTypesCount; ++i) { mFonts[i] = 0; } } KFontSettingsData::~KFontSettingsData() { for (int i = 0; i < FontTypesCount; ++i) { delete mFonts[i]; } } // NOTE: keep in sync with plasma-desktop/kcms/fonts/fonts.cpp static const char GeneralId[] = "General"; static const char DefaultFont[] = "Lucida Grande"; static const KFontData DefaultFontData[KFontSettingsData::FontTypesCount] = { - { GeneralId, "font", DefaultFont, 10, -1, QFont::SansSerif }, - { GeneralId, "fixed", "Monaco", 9, -1, QFont::Monospace }, - { GeneralId, "toolBarFont", DefaultFont, 9, -1, QFont::SansSerif }, - { GeneralId, "menuFont", DefaultFont, 10, -1, QFont::SansSerif }, - { "WM", "activeFont", DefaultFont, 10, -1, QFont::SansSerif }, - { GeneralId, "taskbarFont", DefaultFont, 10, -1, QFont::SansSerif }, - { GeneralId, "smallestReadableFont", DefaultFont, 8, -1, QFont::SansSerif } + { GeneralId, "font", DefaultFont, 10, -1, QFont::SansSerif, "Regular" }, + { GeneralId, "fixed", "Monaco", 9, -1, QFont::Monospace, "Regular" }, + { GeneralId, "toolBarFont", DefaultFont, 9, -1, QFont::SansSerif, "Regular" }, + { GeneralId, "menuFont", DefaultFont, 10, -1, QFont::SansSerif, "Regular" }, + { "WM", "activeFont", DefaultFont, 10, -1, QFont::SansSerif, "Regular" }, + { GeneralId, "taskbarFont", DefaultFont, 10, -1, QFont::SansSerif, "Regular" }, + { GeneralId, "smallestReadableFont", DefaultFont, 8, -1, QFont::SansSerif, "Regular" } }; KSharedConfigPtr &KFontSettingsData::kdeGlobals() { if (!mKdeGlobals) { if (qEnvironmentVariableIsSet("QT_QPA_PLATFORMTHEME_CONFIG_FILE")) { mKdeGlobals = KSharedConfig::openConfig(qgetenv("QT_QPA_PLATFORMTHEME_CONFIG_FILE"), KConfig::NoGlobals); } else { mKdeGlobals = KSharedConfig::openConfig(QStringLiteral("kdeglobals"), KConfig::NoGlobals); } } return mKdeGlobals; } QFont *KFontSettingsData::font(FontTypes fontType) { QFont *cachedFont = mFonts[fontType]; if (!cachedFont) { const KFontData &fontData = DefaultFontData[fontType]; cachedFont = new QFont(QLatin1String(fontData.FontName), fontData.Size, fontData.Weight); cachedFont->setStyleHint(fontData.StyleHint); const KConfigGroup configGroup(kdeGlobals(), fontData.ConfigGroupKey); QString fontInfo = configGroup.readEntry(fontData.ConfigKey, QString()); //If we have serialized information for this font, restore it //NOTE: We are not using KConfig directly because we can't call QFont::QFont from here if (!fontInfo.isEmpty()) { cachedFont->fromString(fontInfo); + } else { + cachedFont->setStyleName(QLatin1String(fontData.StyleName)); } mFonts[fontType] = cachedFont; } return cachedFont; } void KFontSettingsData::dropFontSettingsCache() { if (mKdeGlobals) { mKdeGlobals->reparseConfiguration(); } for (int i = 0; i < FontTypesCount; ++i) { delete mFonts[i]; mFonts[i] = 0; } QWindowSystemInterface::handleThemeChange(0); if (qobject_cast(QCoreApplication::instance())) { QApplication::setFont(*font(KFontSettingsData::GeneralFont)); } else { QGuiApplication::setFont(*font(KFontSettingsData::GeneralFont)); } } void KFontSettingsData::delayedDBusConnects() { #ifdef DBUS_SUPPORT_ENABLED QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KDEPlatformTheme"), QStringLiteral("org.kde.KDEPlatformTheme"), QStringLiteral("refreshFonts"), this, SLOT(dropFontSettingsCache())); #endif } diff --git a/src/platformtheme/kfontsettingsdata.h b/src/platformtheme/kfontsettingsdata.h index 4c14f54..cd04e9f 100644 --- a/src/platformtheme/kfontsettingsdata.h +++ b/src/platformtheme/kfontsettingsdata.h @@ -1,74 +1,75 @@ /* This file is part of the KDE libraries Copyright (C) 2000, 2006 David Faure Copyright 2008 Friedrich W. H. Kossebau Copyright 2013 Aleix Pol Gonzalez This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 KFONTSETTINGSDATA_H #define KFONTSETTINGSDATA_H #include #include #include struct KFontData { const char *ConfigGroupKey; const char *ConfigKey; const char *FontName; int Size; int Weight; QFont::StyleHint StyleHint; + const char *StyleName; }; class KFontSettingsData : public QObject { Q_OBJECT public: // if adding a new type here also add an entry to DefaultFontData enum FontTypes { GeneralFont = 0, FixedFont, ToolbarFont, MenuFont, WindowTitleFont, TaskbarFont, SmallestReadableFont, FontTypesCount }; public: KFontSettingsData(); ~KFontSettingsData(); public Q_SLOTS: void dropFontSettingsCache(); protected Q_SLOTS: void delayedDBusConnects(); public: // access, is not const due to caching QFont *font(FontTypes fontType); protected: KSharedConfigPtr &kdeGlobals(); private: QFont *mFonts[FontTypesCount]; KSharedConfigPtr mKdeGlobals; }; #endif // KFONTSETTINGSDATA_H diff --git a/src/platformtheme/kfontsettingsdatamac.mm b/src/platformtheme/kfontsettingsdatamac.mm index ff81c04..ebbd1c1 100644 --- a/src/platformtheme/kfontsettingsdatamac.mm +++ b/src/platformtheme/kfontsettingsdatamac.mm @@ -1,244 +1,253 @@ /* This file is part of the KDE libraries Copyright (C) 2000, 2006 David Faure Copyright 2008 Friedrich W. H. Kossebau Copyright 2013 Aleix Pol Gonzalez Copyright 2015 René J.V. Bertin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 "kfontsettingsdatamac.h" +#include "platformtheme_logging.h" #include #include #include #include #include #include #include #ifdef DBUS_SUPPORT_ENABLED #include #include #endif #include #include #include // NOTE: keep in sync with plasma-desktop/kcms/fonts/fonts.cpp static const char GeneralId[] = "General"; // NOTE: the default system font changed with OS X 10.11, from Lucida Grande to // San Francisco. With luck this will be caught by QFontDatabase::GeneralFont const char DefaultFont[] = "Lucida Grande"; static const char DefaultFixedFont[] = "Monaco"; static const char *LocalDefaultFont = NULL; // See README.fonts.txt for information and thoughts about native/default fonts KFontData DefaultFontData[KFontSettingsDataMac::FontTypesCount] = { - { GeneralId, "font", DefaultFont, 12, -1, QFont::SansSerif }, - { GeneralId, "fixed", DefaultFixedFont, 10, -1, QFont::Monospace }, - { GeneralId, "toolBarFont", DefaultFont, 10, -1, QFont::SansSerif }, - { GeneralId, "menuFont", DefaultFont, 14, -1, QFont::SansSerif }, + { GeneralId, "font", DefaultFont, 12, -1, QFont::SansSerif, "Medium" }, + { GeneralId, "fixed", DefaultFixedFont, 10, -1, QFont::Monospace, "Regular" }, + { GeneralId, "toolBarFont", DefaultFont, 10, -1, QFont::SansSerif, "Medium" }, + { GeneralId, "menuFont", DefaultFont, 14, -1, QFont::SansSerif, "Medium" }, // applications don't control the window titlebar fonts - { "WM", "activeFont", DefaultFont, 13, -1, QFont::SansSerif }, - { GeneralId, "taskbarFont", DefaultFont, 9, -1, QFont::SansSerif }, - { GeneralId, "smallestReadableFont", DefaultFont, 9, -1, QFont::SansSerif }, + { "WM", "activeFont", DefaultFont, 13, -1, QFont::SansSerif, "Medium" }, + { GeneralId, "taskbarFont", DefaultFont, 9, -1, QFont::SansSerif, "Medium" }, + { GeneralId, "smallestReadableFont", DefaultFont, 9, -1, QFont::SansSerif, "Medium" }, // this one is to accomodate for the MessageBoxFont which should be bold on OS X // when using the native theme fonts. - { GeneralId, "messageBoxFont", DefaultFont, 13, QFont::Bold, QFont::SansSerif } + { GeneralId, "messageBoxFont", DefaultFont, 13, QFont::Bold, QFont::SansSerif, "Bold" } }; static const char *fontNameFor(QFontDatabase::SystemFont role) { QFont qf = QFontDatabase::systemFont(role); if (!qf.defaultFamily().isEmpty()) { char *fn; if (role == QFontDatabase::FixedFont && !qf.fixedPitch()) { fn = strdup("Monaco"); } else if (qf.defaultFamily() == QStringLiteral(".Lucida Grande UI")) { fn = strdup("Lucida Grande"); } else { fn = strdup(qf.defaultFamily().toLocal8Bit().data()); } if (qEnvironmentVariableIsSet("QT_QPA_PLATFORMTHEME_VERBOSE")) { - qWarning() << "fontNameFor" << role << "font:" << qf << "name:" << fn; + qCWarning(PLATFORMTHEME) << "fontNameFor" << role << "font:" << qf << "name:" << fn; } return fn; } else { return NULL; } } void initDefaultFonts() { const char *fn; static bool active = false; // we must protect ourselves from being called recursively if (active) { return; } active = true; if (!LocalDefaultFont) { fn = fontNameFor(QFontDatabase::GeneralFont); LocalDefaultFont = fn; } for (int i = 0 ; i < KFontSettingsDataMac::FontTypesCount ; ++i) { switch(i) { case KFontSettingsDataMac::FixedFont: fn = fontNameFor(QFontDatabase::FixedFont); break; case KFontSettingsDataMac::WindowTitleFont: fn = fontNameFor(QFontDatabase::TitleFont); break; case KFontSettingsDataMac::SmallestReadableFont: fn = fontNameFor(QFontDatabase::SmallestReadableFont); break; default: fn = LocalDefaultFont; break; } if (qEnvironmentVariableIsSet("QT_QPA_PLATFORMTHEME_VERBOSE")) { - qWarning() << "Default font for type" << i << ":" << fn << "; currently:" << DefaultFontData[i].FontName; + qCWarning(PLATFORMTHEME) << "Default font for type" << i << ":" << fn << "; currently:" << DefaultFontData[i].FontName; } if (fn) { if (DefaultFontData[i].FontName != DefaultFont && DefaultFontData[i].FontName != DefaultFixedFont && DefaultFontData[i].FontName != LocalDefaultFont) { free((void*)DefaultFontData[i].FontName); } DefaultFontData[i].FontName = fn; } } active = false; } KFontSettingsDataMac::KFontSettingsDataMac() { #ifdef DBUS_SUPPORT_ENABLED QMetaObject::invokeMethod(this, "delayedDBusConnects", Qt::QueuedConnection); #endif for (int i = 0; i < FontTypesCount; ++i) { // remove any information that already have been cached by our parent // IFF we don't have our own mFonts copy // delete mFonts[i]; mFonts[i] = 0; } } KFontSettingsDataMac::~KFontSettingsDataMac() { for (int i = 0 ; i < KFontSettingsDataMac::FontTypesCount ; ++i) { if (DefaultFontData[i].FontName != DefaultFont && DefaultFontData[i].FontName != DefaultFixedFont) { if (DefaultFontData[i].FontName && DefaultFontData[i].FontName != LocalDefaultFont) { free((void*)(DefaultFontData[i].FontName)); } DefaultFontData[i].FontName = (i == FixedFont)? DefaultFixedFont : DefaultFont; } } if (LocalDefaultFont) { free((void*)(LocalDefaultFont)); } LocalDefaultFont = NULL; } QFont *KFontSettingsDataMac::font(FontTypes fontType) { QFont *cachedFont = mFonts[fontType]; if (!cachedFont) { // check if we have already initialised our local database mapping font types to fonts // if not, we do it here, at the latest possible moment. Doing it in the KFontSettingsDataMac // ctor is bound for failure as our instance is likely to be created before Qt's own // font database has been populated. That's expectable: the font database also represents // platform (theme) specific fonts for various roles, and our ctor is called as part of the // platform theme creation procedure. if (!LocalDefaultFont) { static bool active = false; // NB: initDefaultFonts() queries Qt's font database which in turn can call us // again. Protection against this is built into initDefaultFonts(), but in practice // we prefer to return NULL if called through recursively. if (!active) { active = true; initDefaultFonts(); active = false; } else { // our caller must handle NULL, preferably by relaying the font request // to the native platform theme (see KdeMacTheme::font()). return NULL; } } const KConfigGroup configGroup(kdeGlobals(), DefaultFontData[fontType].ConfigGroupKey); QString fontInfo; bool forceBold = false; if (fontType == MessageBoxFont) { // OS X special: the MessageBoxFont is by default a bold version of the GeneralFont // and that's what is cached in DefaultFontData[MessageBoxFont]. // NB: we can use a single configGroup for this hack as long as MessageBoxFont and // GeneralFont share the same ConfigGroupKey (or MessageBoxFont cannot be configured). fontInfo = configGroup.readEntry(DefaultFontData[GeneralFont].ConfigKey, QString()); if (!fontInfo.isEmpty()) { // However, if the user has configured a GeneralFont (MessageBoxFont cannot be configured), // we respect his/her choice but maintain the bold aspect dictated by the platform. fontType = GeneralFont; forceBold = true; } } const KFontData &fontData = DefaultFontData[fontType]; cachedFont = new QFont(QLatin1String(fontData.FontName), fontData.Size, forceBold? QFont::Bold : fontData.Weight); cachedFont->setStyleHint(fontData.StyleHint); + // ignore the default stylehint; works better converting medium -> bold +// cachedFont->setStyleName(QLatin1String(fontData.StyleName)); // if (qEnvironmentVariableIsSet("QT_QPA_PLATFORMTHEME_VERBOSE")) { -// qWarning() << "Requested font type" << fontType << "name=" << fontData.FontName << "forceBold=" << forceBold << "styleHint=" << fontData.StyleHint; -// qWarning() << "\t->" << *cachedFont; +// qCWarning(PLATFORMTHEME) << "Requested font type" << fontType << "name=" << fontData.FontName << "forceBold=" << forceBold << "styleHint=" << fontData.StyleHint; +// qCWarning(PLATFORMTHEME) << "\t->" << *cachedFont; // } fontInfo = configGroup.readEntry(fontData.ConfigKey, QString()); if (!fontInfo.isEmpty()) { cachedFont->fromString(fontInfo); // if (qEnvironmentVariableIsSet("QT_QPA_PLATFORMTHEME_VERBOSE")) { -// qWarning() << "\tfontInfo=" << fontInfo << "->" << *cachedFont; +// qCWarning(PLATFORMTHEME) << "\tfontInfo=" << fontInfo << "->" << *cachedFont; // } + } else { + QString fName = cachedFont->toString(); + cachedFont->setStyleName(QLatin1String(fontData.StyleName)); + if (qEnvironmentVariableIsSet("QT_QPA_PLATFORMTHEME_VERBOSE")) { + qCWarning(PLATFORMTHEME) << "\t" << fName << "+ styleName" << fontData.StyleName << "->" << *cachedFont; + } } mFonts[fontType] = cachedFont; } return cachedFont; } void KFontSettingsDataMac::dropFontSettingsCache() { if (qobject_cast(QCoreApplication::instance())) { QApplication::setFont(*font(KFontSettingsDataMac::GeneralFont)); } else { QGuiApplication::setFont(*font(KFontSettingsDataMac::GeneralFont)); } } void KFontSettingsDataMac::delayedDBusConnects() { #ifdef DBUS_SUPPORT_ENABLED QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KDEPlatformTheme"), QStringLiteral("org.kde.KDEPlatformTheme"), QStringLiteral("refreshFonts"), this, SLOT(dropFontSettingsCache())); #endif } diff --git a/src/platformtheme/khintssettings.cpp b/src/platformtheme/khintssettings.cpp index 3b52c8b..ae63e83 100644 --- a/src/platformtheme/khintssettings.cpp +++ b/src/platformtheme/khintssettings.cpp @@ -1,432 +1,434 @@ /* This file is part of the KDE libraries * Copyright 2013 Kevin Ottens * Copyright 2013 Aleix Pol Gonzalez * Copyright 2013 Alejandro Fiestas Olivares * * 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 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), 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 Lesser 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. */ #undef QT_NO_CAST_FROM_ASCII #include "khintssettings.h" +#include "platformtheme_logging.h" #include #include #include #include #include #include #include #include #include #include #include #include +#include #ifdef DBUS_SUPPORT_ENABLED #include #include #endif #include #include #include #include #include #ifdef UNIT_TEST #undef HAVE_X11 #define HAVE_X11 0 #endif #if HAVE_X11 #include #include #endif static const QString defaultLookAndFeelPackage = QStringLiteral("org.kde.breeze.desktop"); KSharedConfigPtr &KHintsSettings::kdeGlobals() { if (!mKdeGlobals) { if (qEnvironmentVariableIsSet("QT_QPA_PLATFORMTHEME_CONFIG_FILE")) { mKdeGlobals = KSharedConfig::openConfig(qgetenv("QT_QPA_PLATFORMTHEME_CONFIG_FILE"), KConfig::NoGlobals); } else { mKdeGlobals = KSharedConfig::openConfig(QStringLiteral("kdeglobals"), KConfig::NoGlobals); } } return mKdeGlobals; } KHintsSettings::KHintsSettings() : QObject(0) { kdeGlobals(); KConfigGroup cg(mKdeGlobals, "KDE"); // try to extract the proper defaults file from a lookandfeel package const QString looknfeel = cg.readEntry("LookAndFeelPackage", defaultLookAndFeelPackage); mDefaultLnfConfig = KSharedConfig::openConfig(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("plasma/look-and-feel/") + looknfeel + QStringLiteral("/contents/defaults"))); if (looknfeel != defaultLookAndFeelPackage) { mLnfConfig = KSharedConfig::openConfig(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("plasma/look-and-feel/") + defaultLookAndFeelPackage + QStringLiteral("/contents/defaults"))); } - - m_hints[QPlatformTheme::CursorFlashTime] = qBound(200, cg.readEntry("CursorBlinkRate", 1000), 2000); + const auto cursorBlinkRate = cg.readEntry("CursorBlinkRate", 1000); + m_hints[QPlatformTheme::CursorFlashTime] = cursorBlinkRate > 0 ? qBound(200, cursorBlinkRate, 2000) : 0; // 0 => no blinking m_hints[QPlatformTheme::MouseDoubleClickInterval] = cg.readEntry("DoubleClickInterval", 400); m_hints[QPlatformTheme::StartDragDistance] = cg.readEntry("StartDragDist", 10); m_hints[QPlatformTheme::StartDragTime] = cg.readEntry("StartDragTime", 500); KConfigGroup cgToolbar(mKdeGlobals, "Toolbar style"); m_hints[QPlatformTheme::ToolButtonStyle] = toolButtonStyle(cgToolbar); KConfigGroup cgToolbarIcon(mKdeGlobals, "MainToolbarIcons"); m_hints[QPlatformTheme::ToolBarIconSize] = cgToolbarIcon.readEntry("Size", 22); m_hints[QPlatformTheme::ItemViewActivateItemOnSingleClick] = cg.readEntry("SingleClick", true); m_hints[QPlatformTheme::SystemIconThemeName] = readConfigValue(QStringLiteral("Icons"), QStringLiteral("Theme"), QStringLiteral("oxygen")); m_hints[QPlatformTheme::SystemIconFallbackThemeName] = QStringLiteral("hicolor"); m_hints[QPlatformTheme::IconThemeSearchPaths] = xdgIconThemePaths(); QStringList styleNames; styleNames << QStringLiteral("oxygen") << QStringLiteral("fusion") << QStringLiteral("windows"); const QString configuredStyle = cg.readEntry("widgetStyle", QString()); if (!configuredStyle.isEmpty()) { styleNames.removeOne(configuredStyle); styleNames.prepend(configuredStyle); } const QString lnfStyle = readConfigValue(QStringLiteral("KDE"), QStringLiteral("widgetStyle"), QString()).toString(); if (!lnfStyle.isEmpty()) { styleNames.removeOne(lnfStyle); styleNames.prepend(lnfStyle); } m_hints[QPlatformTheme::StyleNames] = styleNames; m_hints[QPlatformTheme::DialogButtonBoxLayout] = QDialogButtonBox::KdeLayout; m_hints[QPlatformTheme::DialogButtonBoxButtonsHaveIcons] = cg.readEntry("ShowIconsOnPushButtons", true); m_hints[QPlatformTheme::UseFullScreenForPopupMenu] = true; m_hints[QPlatformTheme::KeyboardScheme] = QPlatformTheme::KdeKeyboardScheme; m_hints[QPlatformTheme::UiEffects] = cg.readEntry("GraphicEffectsLevel", 0) != 0 ? QPlatformTheme::GeneralUiEffect : 0; m_hints[QPlatformTheme::IconPixmapSizes] = QVariant::fromValue(QList() << 512 << 256 << 128 << 64 << 32 << 22 << 16 << 8); m_hints[QPlatformTheme::WheelScrollLines] = cg.readEntry("WheelScrollLines", 3); if (qobject_cast(QCoreApplication::instance())) { QApplication::setWheelScrollLines(cg.readEntry("WheelScrollLines", 3)); } - bool showIcons = cg.readEntry("ShowIconsInMenuItems", !QApplication::testAttribute(Qt::AA_DontShowIconsInMenus)); - QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus, !showIcons); + updateShowIconsInMenuItems(cg); -#ifdef DBUS_SUPPORT_ENABLED +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + m_hints[QPlatformTheme::ShowShortcutsInContextMenus] = true; +#endif + + #ifdef DBUS_SUPPORT_ENABLED QMetaObject::invokeMethod(this, "delayedDBusConnects", Qt::QueuedConnection); #endif QMetaObject::invokeMethod(this, "setupIconLoader", Qt::QueuedConnection); loadPalettes(); } KHintsSettings::~KHintsSettings() { qDeleteAll(m_palettes); } QVariant KHintsSettings::readConfigValue(const QString &group, const QString &key, const QVariant &defaultValue) { KConfigGroup userCg(mKdeGlobals, group); QVariant value = userCg.readEntry(key, QString()); if (!value.isNull()) { return value; } if (mLnfConfig) { KConfigGroup lnfCg(mLnfConfig, "kdeglobals"); lnfCg = KConfigGroup(&lnfCg, group); if (lnfCg.isValid()) { value = lnfCg.readEntry(key, defaultValue); if (!value.isNull()) { return value; } } } KConfigGroup lnfCg(mDefaultLnfConfig, group); if (lnfCg.isValid()) { return lnfCg.readEntry(key, defaultValue); } return defaultValue; } QStringList KHintsSettings::xdgIconThemePaths() const { QStringList paths; + // make sure we have ~/.local/share/icons in paths if it exists + paths << QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("icons"), QStandardPaths::LocateDirectory); + const QFileInfo homeIconDir(QDir::homePath() + QStringLiteral("/.icons")); if (homeIconDir.isDir()) { paths << homeIconDir.absoluteFilePath(); } - QString xdgDirString = QFile::decodeName(qgetenv("XDG_DATA_DIRS")); - - if (xdgDirString.isEmpty()) { - xdgDirString = QStringLiteral("/usr/local/share:/usr/share"); - } - - foreach (const QString &xdgDir, xdgDirString.split(QLatin1Char(':'))) { - const QFileInfo xdgIconsDir(xdgDir + QStringLiteral("/icons")); - if (xdgIconsDir.isDir()) { - paths << xdgIconsDir.absoluteFilePath(); - } - } - return paths; } void KHintsSettings::delayedDBusConnects() { #ifdef DBUS_SUPPORT_ENABLED QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KToolBar"), QStringLiteral("org.kde.KToolBar"), QStringLiteral("styleChanged"), this, SLOT(toolbarStyleChanged())); QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KGlobalSettings"), QStringLiteral("org.kde.KGlobalSettings"), QStringLiteral("notifyChange"), this, SLOT(slotNotifyChange(int,int))); #endif } void KHintsSettings::setupIconLoader() { connect(KIconLoader::global(), &KIconLoader::iconChanged, this, &KHintsSettings::iconChanged); } void KHintsSettings::toolbarStyleChanged() { mKdeGlobals->reparseConfiguration(); KConfigGroup cg(mKdeGlobals, "Toolbar style"); m_hints[QPlatformTheme::ToolButtonStyle] = toolButtonStyle(cg); //from gtksymbol.cpp QWidgetList widgets = QApplication::allWidgets(); for (int i = 0; i < widgets.size(); ++i) { QWidget *widget = widgets.at(i); if (qobject_cast(widget)) { QEvent event(QEvent::StyleChange); QApplication::sendEvent(widget, &event); } } } void KHintsSettings::slotNotifyChange(int type, int arg) { mKdeGlobals->reparseConfiguration(); KConfigGroup cg(mKdeGlobals, "KDE"); switch (type) { case PaletteChanged: { loadPalettes(); //QApplication::setPalette and QGuiApplication::setPalette are different functions //and non virtual. Call the correct one if (qobject_cast(QCoreApplication::instance())) { QPalette palette = *m_palettes[QPlatformTheme::SystemPalette]; QApplication::setPalette(palette); // QTBUG QGuiApplication::paletteChanged() signal is only emitted by QGuiApplication // so things like SystemPalette QtQuick item that use it won't notice a palette // change when a QApplication which causes e.g. QML System Settings modules to not update emit qApp->paletteChanged(palette); } else if (qobject_cast(QCoreApplication::instance())) { QGuiApplication::setPalette(*m_palettes[QPlatformTheme::SystemPalette]); } break; } case SettingsChanged: { SettingsCategory category = static_cast(arg); if (category == SETTINGS_QT || category == SETTINGS_MOUSE) { updateQtSettings(cg); } else if (category == SETTINGS_STYLE) { m_hints[QPlatformTheme::DialogButtonBoxButtonsHaveIcons] = cg.readEntry("ShowIconsOnPushButtons", true); m_hints[QPlatformTheme::UiEffects] = cg.readEntry("GraphicEffectsLevel", 0) != 0 ? QPlatformTheme::GeneralUiEffect : 0; + + updateShowIconsInMenuItems(cg); } break; } case ToolbarStyleChanged: { toolbarStyleChanged(); break; } case IconChanged: iconChanged(arg); //Once the KCM is ported to use IconChanged, this should not be needed break; case CursorChanged: updateCursorTheme(); break; case StyleChanged: { QApplication *app = qobject_cast(QCoreApplication::instance()); if (!app) { return; } const QString theme = cg.readEntry("widgetStyle", QString()); if (theme.isEmpty()) { return; } QStringList styleNames; styleNames << cg.readEntry("widgetStyle", QString()) << QStringLiteral("oxygen") << QStringLiteral("fusion") << QStringLiteral("windows"); const QString lnfStyle = readConfigValue(QStringLiteral("KDE"), QStringLiteral("widgetStyle"), QString()).toString(); if (!lnfStyle.isEmpty() && !styleNames.contains(lnfStyle)) { styleNames.prepend(lnfStyle); } m_hints[QPlatformTheme::StyleNames] = styleNames; app->setStyle(theme); loadPalettes(); break; } default: - qWarning() << "Unknown type of change in KGlobalSettings::slotNotifyChange: " << type; + qCWarning(PLATFORMTHEME) << "Unknown type of change in KGlobalSettings::slotNotifyChange: " << type; } } void KHintsSettings::iconChanged(int group) { KIconLoader::Group iconGroup = (KIconLoader::Group) group; if (iconGroup != KIconLoader::MainToolbar) { m_hints[QPlatformTheme::SystemIconThemeName] = readConfigValue(QStringLiteral("Icons"), QStringLiteral("Theme"), QStringLiteral("oxygen")); return; } const int currentSize = KIconLoader::global()->currentSize(KIconLoader::MainToolbar); if (m_hints[QPlatformTheme::ToolBarIconSize] == currentSize) { return; } m_hints[QPlatformTheme::ToolBarIconSize] = currentSize; //If we are not a QApplication, means that we are a QGuiApplication, then we do nothing. if (!qobject_cast(QCoreApplication::instance())) { return; } QWidgetList widgets = QApplication::allWidgets(); Q_FOREACH (QWidget *widget, widgets) { if (qobject_cast(widget) || qobject_cast(widget)) { QEvent event(QEvent::StyleChange); QApplication::sendEvent(widget, &event); } } } void KHintsSettings::updateQtSettings(KConfigGroup &cg) { int flash = qBound(200, cg.readEntry("CursorBlinkRate", 1000), 2000); m_hints[QPlatformTheme::CursorFlashTime] = flash; int doubleClickInterval = cg.readEntry("DoubleClickInterval", 400); m_hints[QPlatformTheme::MouseDoubleClickInterval] = doubleClickInterval; int startDragDistance = cg.readEntry("StartDragDist", 10); m_hints[QPlatformTheme::StartDragDistance] = startDragDistance; int startDragTime = cg.readEntry("StartDragTime", 10); m_hints[QPlatformTheme::StartDragTime] = startDragTime; m_hints[QPlatformTheme::ItemViewActivateItemOnSingleClick] = cg.readEntry("SingleClick", true); - bool showIcons = cg.readEntry("ShowIconsInMenuItems", !QApplication::testAttribute(Qt::AA_DontShowIconsInMenus)); - QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus, !showIcons); + updateShowIconsInMenuItems(cg); int wheelScrollLines = cg.readEntry("WheelScrollLines", 3); m_hints[QPlatformTheme::WheelScrollLines] = wheelScrollLines; QApplication *app = qobject_cast(QCoreApplication::instance()); if (app) { QApplication::setWheelScrollLines(cg.readEntry("WheelScrollLines", 3)); } } +void KHintsSettings::updateShowIconsInMenuItems(KConfigGroup &cg) +{ + bool showIcons = cg.readEntry("ShowIconsInMenuItems", !QApplication::testAttribute(Qt::AA_DontShowIconsInMenus)); + QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus, !showIcons); +} + Qt::ToolButtonStyle KHintsSettings::toolButtonStyle(const KConfigGroup &cg) const { const QString buttonStyle = cg.readEntry("ToolButtonStyle", "TextBesideIcon").toLower(); return buttonStyle == QLatin1String("textbesideicon") ? Qt::ToolButtonTextBesideIcon : buttonStyle == QLatin1String("icontextright") ? Qt::ToolButtonTextBesideIcon : buttonStyle == QLatin1String("textundericon") ? Qt::ToolButtonTextUnderIcon : buttonStyle == QLatin1String("icontextbottom") ? Qt::ToolButtonTextUnderIcon : buttonStyle == QLatin1String("textonly") ? Qt::ToolButtonTextOnly : Qt::ToolButtonIconOnly; } void KHintsSettings::loadPalettes() { qDeleteAll(m_palettes); m_palettes.clear(); if (mKdeGlobals->hasGroup("Colors:View")) { m_palettes[QPlatformTheme::SystemPalette] = new QPalette(KColorScheme::createApplicationPalette(mKdeGlobals)); } else { KConfigGroup cg(mKdeGlobals, "KDE"); const QString looknfeel = cg.readEntry("LookAndFeelPackage", defaultLookAndFeelPackage); QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("plasma/look-and-feel/") + looknfeel + QStringLiteral("/contents/colors")); if (!path.isEmpty()) { m_palettes[QPlatformTheme::SystemPalette] = new QPalette(KColorScheme::createApplicationPalette(KSharedConfig::openConfig(path))); return; } const QString scheme = readConfigValue(QStringLiteral("General"), QStringLiteral("ColorScheme"), QStringLiteral("Oxygen")).toString(); path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("color-schemes/") + scheme + QStringLiteral(".colors")); if (!path.isEmpty()) { m_palettes[QPlatformTheme::SystemPalette] = new QPalette(KColorScheme::createApplicationPalette(KSharedConfig::openConfig(path))); } } } void KHintsSettings::updateCursorTheme() { KConfig config(QStringLiteral("kcminputrc")); KConfigGroup g(&config, "Mouse"); int size = g.readEntry("cursorSize", -1); // Default cursor size is 16 points if (size == -1) { if (QScreen *s = QGuiApplication::primaryScreen()) { size = s->logicalDotsPerInchY() * 16 / 72; } else { size = 0; } } #if HAVE_X11 if (QX11Info::isPlatformX11()) { const QString theme = g.readEntry("cursorTheme", QString()); // Note that in X11R7.1 and earlier, calling XcursorSetTheme() // with a NULL theme would cause Xcursor to use "default", but // in 7.2 and later it will cause it to revert to the theme that // was configured when the application was started. XcursorSetTheme(QX11Info::display(), theme.isNull() ? "default" : QFile::encodeName(theme).constData()); XcursorSetDefaultSize(QX11Info::display(), size); } #endif } diff --git a/src/platformtheme/khintssettings.h b/src/platformtheme/khintssettings.h index 7127aa5..8cc58dd 100644 --- a/src/platformtheme/khintssettings.h +++ b/src/platformtheme/khintssettings.h @@ -1,101 +1,102 @@ /* This file is part of the KDE libraries * Copyright 2013 Alejandro Fiestas Olivares * * 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 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), 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 Lesser 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 KHINTS_SETTINGS_H #define KHINTS_SETTINGS_H #include #include #include #include class KConfigGroup; class QPalette; class KHintsSettings : public QObject { Q_OBJECT public: /** * An identifier for change signals. * @note Copied from KGlobalSettings */ enum ChangeType { PaletteChanged = 0, FontChanged, StyleChanged, SettingsChanged, IconChanged, CursorChanged, ToolbarStyleChanged, ClipboardConfigChanged, BlockShortcuts, NaturalSortingChanged }; /** * Valid values for the settingsChanged signal * @note Copied from KGlobalSettings */ enum SettingsCategory { SETTINGS_MOUSE, SETTINGS_COMPLETION, SETTINGS_PATHS, SETTINGS_POPUPMENU, SETTINGS_QT, SETTINGS_SHORTCUTS, SETTINGS_LOCALE, SETTINGS_STYLE }; explicit KHintsSettings(); virtual ~KHintsSettings(); inline QVariant hint(QPlatformTheme::ThemeHint hint) const { return m_hints[hint]; } inline QPalette *palette(QPlatformTheme::Palette type) const { return m_palettes[type]; } QStringList xdgIconThemePaths() const; protected Q_SLOTS: void delayedDBusConnects(); void setupIconLoader(); void toolbarStyleChanged(); void slotNotifyChange(int type, int arg); protected: KSharedConfigPtr &kdeGlobals(); QVariant readConfigValue(const QString &group, const QString &key, const QVariant &defaultValue); void loadPalettes(); void iconChanged(int group); void updateQtSettings(KConfigGroup &cg); + void updateShowIconsInMenuItems(KConfigGroup &cg); Qt::ToolButtonStyle toolButtonStyle(const KConfigGroup &cg) const; void updateCursorTheme(); inline QHash &palettes() { return m_palettes; } inline QHash &hints() { return m_hints; } private: QHash m_palettes; QHash m_hints; KSharedConfigPtr mKdeGlobals; KSharedConfigPtr mDefaultLnfConfig; KSharedConfigPtr mLnfConfig; }; #endif //KHINTS_SETTINGS_H diff --git a/src/platformtheme/khintssettingsmac.mm b/src/platformtheme/khintssettingsmac.mm index e30a479..0d98222 100644 --- a/src/platformtheme/khintssettingsmac.mm +++ b/src/platformtheme/khintssettingsmac.mm @@ -1,303 +1,312 @@ /* This file is part of the KDE libraries * Copyright 2013 Kevin Ottens * Copyright 2013 Aleix Pol Gonzalez * Copyright 2013 Alejandro Fiestas Olivares * Copyright 2015 René J.V. Bertin #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DBUS_SUPPORT_ENABLED #include #include #endif #include #include #include #include #include class KdeProxyStyle : public QProxyStyle { public: KdeProxyStyle(const QString &styleName) : QProxyStyle(styleName) { ; } int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, const QStyleOption *option = 0, const QWidget *widget = 0) const { int spacing = QProxyStyle::layoutSpacing(control1, control2, orientation, option, widget); - qWarning() << "layoutSpacing=" << spacing; + qCWarning(PLATFORMTHEME) << "layoutSpacing=" << spacing; if (spacing > 2) { spacing /= 2; } return spacing; } }; KHintsSettingsMac::KHintsSettingsMac() : styleProxy(0) { KSharedConfigPtr mKdeGlobals = kdeGlobals(); if (qEnvironmentVariableIsSet("QT_QPA_PLATFORMTHEME_VERBOSE")) { if (!mKdeGlobals->name().isEmpty()) { - qWarning() << Q_FUNC_INFO << "config file:" << mKdeGlobals->name() + qCWarning(PLATFORMTHEME) << Q_FUNC_INFO << "config file:" << mKdeGlobals->name() << "(" << QStandardPaths::locate(mKdeGlobals->locationType(), mKdeGlobals->name()) << ")"; } } KConfigGroup cg(mKdeGlobals, "KDE"); // we're overriding whatever the parent class configured hints().clear(); KConfigGroup cgToolbar(mKdeGlobals, "Toolbar style"); hints()[QPlatformTheme::ToolButtonStyle] = toolButtonStyle(cgToolbar); KConfigGroup cgToolbarIcon(mKdeGlobals, "MainToolbarIcons"); hints()[QPlatformTheme::ToolBarIconSize] = cgToolbarIcon.readEntry("Size", 22); hints()[QPlatformTheme::ItemViewActivateItemOnSingleClick] = cg.readEntry("SingleClick", true); #ifdef KDEMACTHEME_ADD_ICONTHEMESETTINGS // The new default Breeze icon theme is svg based and looks more out of place than the older Oxygen theme // which is PNG-based, and thus easier to use with/in the Finder. hints()[QPlatformTheme::SystemIconThemeName] = readConfigValue(QStringLiteral("Icons"), QStringLiteral("Theme"), QStringLiteral("oxygen")); hints()[QPlatformTheme::IconThemeSearchPaths] = xdgIconThemePaths(); #endif QStringList styleNames; styleNames << QStringLiteral("aqua") << QStringLiteral("macintosh") << QStringLiteral("fusion") << QStringLiteral("windows"); const QString configuredStyle = cg.readEntry("widgetStyle", QString()); if (!configuredStyle.isEmpty()) { styleNames.removeOne(configuredStyle); styleNames.prepend(configuredStyle); } const QString lnfStyle = readConfigValue(QStringLiteral("KDE"), QStringLiteral("widgetStyle"), QString()).toString(); if (!lnfStyle.isEmpty()) { styleNames.removeOne(lnfStyle); styleNames.prepend(lnfStyle); } hints()[QPlatformTheme::StyleNames] = styleNames; checkNativeTheme(configuredStyle); hints()[QPlatformTheme::DialogButtonBoxLayout] = QDialogButtonBox::MacLayout; hints()[QPlatformTheme::DialogButtonBoxButtonsHaveIcons] = cg.readEntry("ShowIconsOnPushButtons", false); hints()[QPlatformTheme::UseFullScreenForPopupMenu] = true; hints()[QPlatformTheme::KeyboardScheme] = QPlatformTheme::MacKeyboardScheme; hints()[QPlatformTheme::UiEffects] = cg.readEntry("GraphicEffectsLevel", 0) != 0 ? QPlatformTheme::GeneralUiEffect : 0; // this would be what we should return for IconPixmapSizes if we wanted to copy the system defaults: // qreal devicePixelRatio = qGuiApp->devicePixelRatio(); // QList sizes; // sizes << 16 * devicePixelRatio // << 32 * devicePixelRatio // << 64 * devicePixelRatio // << 128 * devicePixelRatio; // hints()[QPlatformTheme::IconPixmapSizes] = QVariant::fromValue(sizes); hints()[QPlatformTheme::WheelScrollLines] = cg.readEntry("WheelScrollLines", 3); if (qobject_cast(QCoreApplication::instance())) { QApplication::setWheelScrollLines(cg.readEntry("WheelScrollLines", 3)); } - bool showIcons = cg.readEntry("ShowIconsInMenuItems", !QApplication::testAttribute(Qt::AA_DontShowIconsInMenus)); - QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus, !showIcons); + updateShowIconsInMenuItems(cg); + +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + m_hints[QPlatformTheme::ShowShortcutsInContextMenus] = true; +#endif #ifdef DBUS_SUPPORT_ENABLED QMetaObject::invokeMethod(this, "delayedDBusConnects", Qt::QueuedConnection); #endif loadPalettes(); } KHintsSettingsMac::~KHintsSettingsMac() { } // adapted from QGenericUnixTheme::xdgIconThemePaths() QStringList KHintsSettingsMac::xdgIconThemePaths() const { QStringList paths; + + // make sure we have ~/.local/share/icons in paths if it exists + paths << QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("icons"), QStandardPaths::LocateDirectory); + // Add home directory first in search path const QFileInfo homeIconDir(QDir::homePath() + QStringLiteral("/.icons")); if (homeIconDir.isDir()) { paths.prepend(homeIconDir.absoluteFilePath()); } QStringList xdgDirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); if (xdgDirs.isEmpty()) { xdgDirs << QStringLiteral("/opt/local/share") << QStringLiteral("/usr/local/share") << QStringLiteral("/usr/share"); } foreach (const QString &xdgDir, xdgDirs) { const QFileInfo xdgIconsDir(xdgDir + QStringLiteral("/icons")); if (xdgIconsDir.isDir()) { paths.append(xdgIconsDir.absoluteFilePath()); } const QFileInfo pixmapsIconsDir(xdgDir + QStringLiteral("/pixmaps")); if (pixmapsIconsDir.isDir()) { paths.append(pixmapsIconsDir.absoluteFilePath()); } } return paths; } void KHintsSettingsMac::delayedDBusConnects() { #ifdef DBUS_SUPPORT_ENABLED QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KToolBar"), QStringLiteral("org.kde.KToolBar"), QStringLiteral("styleChanged"), this, SLOT(toolbarStyleChanged())); QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KGlobalSettings"), QStringLiteral("org.kde.KGlobalSettings"), QStringLiteral("notifyChange"), this, SLOT(slotNotifyChange(int,int))); #endif } void KHintsSettingsMac::checkNativeTheme(const QString &theme) { #if 0 // using a QStyleProxy messes up the colour palette for some reason, so this feature is deactivated for now if (theme.isEmpty() || theme.compare(QStringLiteral("macintosh"), Qt::CaseInsensitive) == 0) { if (qApp) { if (!styleProxy) { styleProxy = new KdeProxyStyle(QStringLiteral("macintosh")); } // styleProxy will be owned by QApplication after this, so no point deleting it qApp->setStyle(styleProxy); loadPalettes(); } } #endif // do this only when certain that there's a QApplication instance: // QApplication *app = qobject_cast(QCoreApplication::instance()); // if (app) { -// qWarning() << Q_FUNC_INFO << "platform theme:" << app->style()->objectName(); +// qCWarning(PLATFORMTHEME) << Q_FUNC_INFO << "platform theme:" << app->style()->objectName(); // } } void KHintsSettingsMac::slotNotifyChange(int type, int arg) { KHintsSettings::slotNotifyChange(type,arg); KSharedConfigPtr mKdeGlobals = kdeGlobals(); KConfigGroup cg(mKdeGlobals, "KDE"); switch (type) { case SettingsChanged: { SettingsCategory category = static_cast(arg); if (category == SETTINGS_STYLE) { hints()[QPlatformTheme::DialogButtonBoxButtonsHaveIcons] = cg.readEntry("ShowIconsOnPushButtons", false); + updateShowIconsInMenuItems(cg); } break; } case StyleChanged: { QApplication *app = qobject_cast(QCoreApplication::instance()); if (!app) { return; } const QString theme = cg.readEntry("widgetStyle", QString()); checkNativeTheme(theme); if (theme.isEmpty()) { return; } QStringList styleNames; styleNames << cg.readEntry("widgetStyle", QString()) << QStringLiteral("aqua") << QStringLiteral("macintosh") << QStringLiteral("fusion") << QStringLiteral("windows"); const QString lnfStyle = readConfigValue(QStringLiteral("KDE"), QStringLiteral("widgetStyle"), QString()).toString(); if (!lnfStyle.isEmpty() && !styleNames.contains(lnfStyle)) { styleNames.prepend(lnfStyle); } hints()[QPlatformTheme::StyleNames] = styleNames; break; } } } void KHintsSettingsMac::iconChanged(int group) { KIconLoader::Group iconGroup = (KIconLoader::Group) group; if (iconGroup != KIconLoader::MainToolbar) { hints()[QPlatformTheme::SystemIconThemeName] = readConfigValue(QStringLiteral("Icons"), QStringLiteral("Theme"), QStringLiteral("oxygen")); return; } return KHintsSettings::iconChanged(group); } Qt::ToolButtonStyle KHintsSettingsMac::toolButtonStyle(const KConfigGroup &cg) const { const QString buttonStyle = cg.readEntry("ToolButtonStyle", "TextUnderIcon").toLower(); return buttonStyle == QLatin1String("textbesideicon") ? Qt::ToolButtonTextBesideIcon : buttonStyle == QLatin1String("icontextright") ? Qt::ToolButtonTextBesideIcon : buttonStyle == QLatin1String("textundericon") ? Qt::ToolButtonTextUnderIcon : buttonStyle == QLatin1String("icontextbottom") ? Qt::ToolButtonTextUnderIcon : buttonStyle == QLatin1String("textonly") ? Qt::ToolButtonTextOnly : Qt::ToolButtonIconOnly; } void KHintsSettingsMac::loadPalettes() { qDeleteAll(palettes()); palettes().clear(); KSharedConfigPtr mKdeGlobals = kdeGlobals(); if (mKdeGlobals->hasGroup("Colors:View")) { palettes()[QPlatformTheme::SystemPalette] = new QPalette(KColorScheme::createApplicationPalette(mKdeGlobals)); } else { const QString scheme = readConfigValue(QStringLiteral("General"), QStringLiteral("ColorScheme"), QStringLiteral("Mac OSX Graphite")).toString(); const QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("color-schemes/") + scheme + QStringLiteral(".colors")); if (!path.isEmpty()) { palettes()[QPlatformTheme::SystemPalette] = new QPalette(KColorScheme::createApplicationPalette(KSharedConfig::openConfig(path))); } } } void KHintsSettingsMac::updateCursorTheme() { } diff --git a/src/platformtheme/main_cocoa.cpp b/src/platformtheme/main_cocoa.cpp index d40962b..41c4084 100644 --- a/src/platformtheme/main_cocoa.cpp +++ b/src/platformtheme/main_cocoa.cpp @@ -1,77 +1,77 @@ /* This file is part of the KDE libraries * Copyright 2013 Kevin Ottens * Copyright 2015 René J.V. Bertin * * 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 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), 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 Lesser 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 #include #include #include #include #include "kdemactheme.h" #include // We call ourselves the "cocoa" platform theme plugin. Doing that means we replace // the native platform theme. That is not a problem because the KdeMacTheme class proxies // the native theme. It just means that the native theme inherits a number of KDE // extensions, which are loaded automatically without user intervention like setting // an env. variable. // NB NB // This file should be kept in sync with main_kde.cpp !! // NB NB class CocoaPlatformThemePlugin : public QPlatformThemePlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformThemeFactoryInterface.5.1" FILE "cocoaplatformtheme.json") public: CocoaPlatformThemePlugin(QObject *parent = Q_NULLPTR) : QPlatformThemePlugin(parent) { if (qEnvironmentVariableIsSet("KDE_LAYOUT_USES_WIDGET_RECT")) { qApp->installEventFilter(this); } } - QPlatformTheme *create(const QString &key, const QStringList ¶mList) Q_DECL_OVERRIDE + QPlatformTheme *create(const QString &key, const QStringList ¶mList) override { Q_UNUSED(key) Q_UNUSED(paramList) return new KdeMacTheme; } protected: - bool eventFilter(QObject *object, QEvent *event) + bool eventFilter(QObject *object, QEvent *event) override { switch (event->type()) { case QEvent::ChildAdded: { QChildEvent *childEvent = static_cast(event); if (childEvent->child()->isWidgetType()) { QWidget* theChildWidget = qobject_cast(childEvent->child()); theChildWidget->setAttribute(Qt::WA_LayoutUsesWidgetRect, true); } } } return qApp->eventFilter(object, event); } }; #include "main_cocoa.moc" diff --git a/src/platformtheme/main_kde.cpp b/src/platformtheme/main_kde.cpp index d512f24..3de5d18 100644 --- a/src/platformtheme/main_kde.cpp +++ b/src/platformtheme/main_kde.cpp @@ -1,75 +1,75 @@ /* This file is part of the KDE libraries * Copyright 2013 Kevin Ottens * Copyright 2015 René J.V. Bertin * * 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 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), 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 Lesser 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 #include #include #include #include #include "kdemactheme.h" #include // We use a different internal class name for the Mac KDE platform theme plugin, but it will still // identify itself as "KDE" to Qt. This ensures that it will also be picked up when using // the XCB platform plugin (without patching it). // NB NB // This file should be kept in sync with main_kde.cpp !! // NB NB class KdePlatformThemePlugin : public QPlatformThemePlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformThemeFactoryInterface.5.1" FILE "kdeplatformtheme.json") public: KdePlatformThemePlugin(QObject *parent = Q_NULLPTR) : QPlatformThemePlugin(parent) { if (qEnvironmentVariableIsSet("KDE_LAYOUT_USES_WIDGET_RECT")) { qApp->installEventFilter(this); } } - QPlatformTheme *create(const QString &key, const QStringList ¶mList) Q_DECL_OVERRIDE + QPlatformTheme *create(const QString &key, const QStringList ¶mList) override { Q_UNUSED(key) Q_UNUSED(paramList) return new KdeMacTheme; } protected: bool eventFilter(QObject *object, QEvent *event) { switch (event->type()) { case QEvent::ChildAdded: { QChildEvent *childEvent = static_cast(event); if (childEvent->child()->isWidgetType()) { QWidget* theChildWidget = qobject_cast(childEvent->child()); theChildWidget->setAttribute(Qt::WA_LayoutUsesWidgetRect, true); } } } return qApp->eventFilter(object, event); } }; #include "main_kde.moc" diff --git a/src/qmacstyle/qmacstyle_mac_p.h b/src/qmacstyle/qmacstyle_mac_p.h index 459784c..e7ac381 100644 --- a/src/qmacstyle/qmacstyle_mac_p.h +++ b/src/qmacstyle/qmacstyle_mac_p.h @@ -1,141 +1,140 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWidgets module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QMACSTYLE_MAC_P_H #define QMACSTYLE_MAC_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // +#include "qtcore-config.h" #include #include QT_BEGIN_NAMESPACE -#if defined(Q_OS_MAC) && !defined(QT_NO_STYLE_MAC) +#if QT_CONFIG(style_mac) class QPalette; class QPushButton; class QStyleOptionButton; class QMacStylePrivate; class QMacStyle : public QCommonStyle { Q_OBJECT public: QMacStyle(); virtual ~QMacStyle(); void polish(QWidget *w); void unpolish(QWidget *w); void polish(QApplication*); void unpolish(QApplication*); void polish(QPalette &pal); void drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p, const QWidget *w = 0) const; void drawControl(ControlElement element, const QStyleOption *opt, QPainter *p, const QWidget *w = 0) const; QRect subElementRect(SubElement r, const QStyleOption *opt, const QWidget *widget = 0) const; void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p, const QWidget *w = 0) const; SubControl hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, const QPoint &pt, const QWidget *w = 0) const; QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, const QWidget *w = 0) const; QSize sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &contentsSize, const QWidget *w = 0) const; int pixelMetric(PixelMetric pm, const QStyleOption *opt = 0, const QWidget *widget = 0) const; QPalette standardPalette() const; virtual int styleHint(StyleHint sh, const QStyleOption *opt = 0, const QWidget *w = 0, QStyleHintReturn *shret = 0) const; - enum FocusRectPolicy { FocusEnabled, FocusDisabled, FocusDefault }; - static void setFocusRectPolicy(QWidget *w, FocusRectPolicy policy); - static FocusRectPolicy focusRectPolicy(const QWidget *w); - enum WidgetSizePolicy { SizeSmall, SizeLarge, SizeMini, SizeDefault }; static void setWidgetSizePolicy(const QWidget *w, WidgetSizePolicy policy); static WidgetSizePolicy widgetSizePolicy(const QWidget *w, const QStyleOption *opt = 0); QPixmap standardPixmap(StandardPixmap sp, const QStyleOption *opt, const QWidget *widget = 0) const; QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const; virtual void drawItemText(QPainter *p, const QRect &r, int flags, const QPalette &pal, bool enabled, const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) const; bool event(QEvent *e); QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *opt = 0, const QWidget *widget = 0) const; int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, const QStyleOption *option = 0, const QWidget *widget = 0) const; private: Q_DISABLE_COPY(QMacStyle) Q_DECLARE_PRIVATE(QMacStyle) +#if QT_CONFIG(pushbutton) friend bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOptionButton *option); +#endif }; #endif QT_END_NAMESPACE #endif // QMACSTYLE_MAC_P_H