diff --git a/src/platformtheme/khintssettings.cpp b/src/platformtheme/khintssettings.cpp index b3fab56..9215ce4 100644 --- a/src/platformtheme/khintssettings.cpp +++ b/src/platformtheme/khintssettings.cpp @@ -1,433 +1,439 @@ /* 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 #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"))); } 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 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; 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: 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 8f8ce67..c4486a2 100644 --- a/src/platformtheme/khintssettingsmac.mm +++ b/src/platformtheme/khintssettingsmac.mm @@ -1,304 +1,304 @@ /* 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); 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()) { 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); #ifdef DBUS_SUPPORT_ENABLED QMetaObject::invokeMethod(this, "delayedDBusConnects", Qt::QueuedConnection); #endif loadPalettes(); } KHintsSettingsMac::~KHintsSettingsMac() { } // adapted from QGenericUnixTheme::xdgIconThemePaths() QStringList KHintsSettingsMac::xdgIconThemePaths() const { QStringList paths; // 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) { // 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/plintegration-cumpatch1.diff b/src/platformtheme/plintegration-cumpatch1.diff index 0ea86f9..f7b2e4e 100644 --- a/src/platformtheme/plintegration-cumpatch1.diff +++ b/src/platformtheme/plintegration-cumpatch1.diff @@ -1,332 +1,333 @@ 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 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