Verified Commit 6407a2a8 authored by Fushan Wen's avatar Fushan Wen
Browse files

kcms/runners: Move KRunner settings to individual KCM

Port them to QML.

CCBUG: 318538
parent 08d2c7b3
# KI18N Translation Domain for this library
add_definitions(-DTRANSLATION_DOMAIN=\"kcm_search\")
# Search Config Module
set(kcm_search_SRCS
kcm.cpp
krunnerdata.cpp
)
kconfig_add_kcfg_files(kcm_search_SRCS krunnersettings.kcfgc)
kconfig_add_kcfg_files(kcm_search_SRCS krunnersettingsbase.kcfgc)
add_library(kcm_plasmasearch MODULE ${kcm_search_SRCS})
add_executable(plugininstaller
......@@ -30,7 +31,6 @@ target_link_libraries(kcm_plasmasearch
KF5::Runner
KF5::I18n
KF5::NewStuffWidgets
KF5::Activities
Qt::DBus
Qt::Widgets
......@@ -52,3 +52,34 @@ install(FILES kcm_plasmasearch.desktop DESTINATION ${KDE_INSTALL_APPDIR})
install(TARGETS kcm_plasmasearch DESTINATION ${KDE_INSTALL_PLUGINDIR}/plasma/kcms/systemsettings_qwidgets)
install(FILES krunner.knsrc DESTINATION ${KDE_INSTALL_KNSRCDIR})
install(TARGETS plugininstaller DESTINATION ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
# KRunner Settings Module
set(kcm_krunnersettings_SRCS
krunnersettings.cpp
krunnersettingsdata.cpp
)
kcmutils_generate_module_data(
kcm_krunnersettings_SRCS
MODULE_DATA_HEADER krunnersettingsdata.h
MODULE_DATA_CLASS_NAME KRunnerSettingsData
SETTINGS_HEADERS krunnersettingsbase.h
SETTINGS_CLASSES KRunnerSettingsBase
)
kconfig_add_kcfg_files(kcm_krunnersettings_SRCS krunnersettingsbase.kcfgc GENERATE_MOC)
kcoreaddons_add_plugin(kcm_krunnersettings SOURCES ${kcm_krunnersettings_SRCS} INSTALL_NAMESPACE "plasma/kcms/desktop")
target_link_libraries(kcm_krunnersettings
KF5::Activities
KF5::ConfigCore
KF5::I18n
KF5::KCMUtils
KF5::QuickAddons
Qt::DBus
)
install(FILES krunnersettingsbase.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR})
kpackage_install_package(package kcm_krunnersettings kcms)
......@@ -10,38 +10,28 @@
#include "kcm.h"
#include <KAboutData>
#include <KActivities/Consumer>
#include <KActivities/Info>
#include <KCMultiDialog>
#include <KLocalizedString>
#include <KNSWidgets/Button>
#include <KPluginFactory>
#include <KPluginWidget>
#include <KRunner/RunnerManager>
#include <QDebug>
#include <QStandardPaths>
#include "krunnerdata.h"
#include "krunnersettings.h"
#include <QAction>
#include <QApplication>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusMetaType>
#include <QDialog>
#include <QFileInfo>
#include <QFormLayout>
#include <QLabel>
#include <QMenu>
#include <QPainter>
#include <QToolButton>
#include <QVBoxLayout>
#include "krunnerdata.h"
K_PLUGIN_FACTORY_WITH_JSON(SearchConfigModuleFactory, "kcm_plasmasearch.json", registerPlugin<SearchConfigModule>(); registerPlugin<KRunnerData>();)
SearchConfigModule::SearchConfigModule(QWidget *parent, const QVariantList &args)
: KCModule(parent, args)
, m_config(KSharedConfig::openConfig("krunnerrc"))
, m_settings(new KRunnerSettings(this))
{
KAboutData *about = new KAboutData(QStringLiteral("kcm_search"),
i18nc("kcm name for About dialog", "Configure search settings"),
......@@ -57,58 +47,12 @@ SearchConfigModule::SearchConfigModule(QWidget *parent, const QVariantList &args
}
QVBoxLayout *layout = new QVBoxLayout(this);
m_consumer = new KActivities::Consumer(this);
m_historyConfigGroup = KSharedConfig::openConfig(QStringLiteral("krunnerstaterc"), KConfig::NoGlobals, QStandardPaths::GenericDataLocation)
->group("PlasmaRunnerManager")
.group("History");
QHBoxLayout *headerLayout = new QHBoxLayout;
layout->addLayout(headerLayout);
QLabel *label = new QLabel(i18n("Enable or disable plugins (used in KRunner, Application Launcher, and the Overview effect)"));
m_clearHistoryButton = new QToolButton(this);
m_clearHistoryButton->setIcon(
QIcon::fromTheme(isRightToLeft() ? QStringLiteral("edit-clear-locationbar-ltr") : QStringLiteral("edit-clear-locationbar-rtl")));
m_clearHistoryButton->setPopupMode(QToolButton::InstantPopup);
m_clearHistoryButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
connect(m_clearHistoryButton, &QPushButton::clicked, this, &SearchConfigModule::deleteAllHistory);
QHBoxLayout *configHeaderLayout = new QHBoxLayout;
QVBoxLayout *configHeaderLeft = new QVBoxLayout;
QVBoxLayout *configHeaderRight = new QVBoxLayout;
// Options where KRunner should pop up
m_topPositioning = new QRadioButton(i18n("Top"), this);
connect(m_topPositioning, &QRadioButton::toggled, this, &SearchConfigModule::updateUnmanagedState);
m_freeFloating = new QRadioButton(i18n("Center"), this);
connect(m_freeFloating, &QRadioButton::toggled, this, &SearchConfigModule::updateUnmanagedState);
QFormLayout *positionLayout = new QFormLayout;
positionLayout->addRow(i18n("KRunner position:"), m_topPositioning);
positionLayout->addRow(QString(), m_freeFloating);
m_enableHistory = new QCheckBox(i18n("Enable"), this);
m_enableHistory->setObjectName("kcfg_historyEnabled");
positionLayout->addItem(new QSpacerItem(0, 0));
positionLayout->addRow(i18n("KRunner history:"), m_enableHistory);
connect(m_enableHistory, &QCheckBox::toggled, m_clearHistoryButton, &QPushButton::setEnabled);
m_retainPriorSearch = new QCheckBox(i18n("Retain previous search"), this);
m_retainPriorSearch->setObjectName("kcfg_retainPriorSearch");
positionLayout->addRow(QString(), m_retainPriorSearch);
m_activityAware = new QCheckBox(i18n("Activity aware (previous search and history)"), this);
m_activityAware->setObjectName("kcfg_activityAware");
connect(m_activityAware, &QCheckBox::clicked, this, &SearchConfigModule::configureClearHistoryButton);
positionLayout->addRow(QString(), m_activityAware);
configHeaderLeft->addLayout(positionLayout);
configHeaderRight->setSizeConstraint(QLayout::SetNoConstraint);
configHeaderRight->setAlignment(Qt::AlignBottom);
configHeaderRight->addWidget(m_clearHistoryButton);
configHeaderLayout->addLayout(configHeaderLeft);
configHeaderLayout->addStretch();
configHeaderLayout->addLayout(configHeaderRight);
headerLayout->addWidget(label);
headerLayout->addStretch();
......@@ -128,11 +72,27 @@ SearchConfigModule::SearchConfigModule(QWidget *parent, const QVariantList &args
QDBusConnection::sessionBus().send(message);
});
layout->addLayout(configHeaderLayout);
layout->addSpacing(12);
layout->addWidget(m_pluginSelector);
QHBoxLayout *downloadLayout = new QHBoxLayout;
// Open KRunner settings
m_krunnerSettingsButton = new QPushButton(QIcon::fromTheme(QStringLiteral("krunner")), QStringLiteral("Configure KRunner…"), this);
connect(m_krunnerSettingsButton, &QPushButton::clicked, this, [this] {
if (!m_krunnerSettingsDialog) {
const KPluginMetaData krunnerModule(QPluginLoader("plasma/kcms/desktop/kcm_krunnersettings"));
if (krunnerModule.isValid()) {
m_krunnerSettingsDialog = new KCMultiDialog(this);
m_krunnerSettingsDialog->addModule(krunnerModule, {QLatin1String("openedFromPluginSettings")});
} else {
return;
}
}
m_krunnerSettingsDialog->show();
});
KNSWidgets::Button *downloadButton = new KNSWidgets::Button(i18n("Get New Plugins…"), QStringLiteral("krunner.knsrc"), this);
connect(downloadButton, &KNSWidgets::Button::dialogFinished, this, [this](const QList<KNSCore::Entry> &changedEntries) {
if (!changedEntries.isEmpty()) {
......@@ -141,12 +101,12 @@ SearchConfigModule::SearchConfigModule(QWidget *parent, const QVariantList &args
}
});
downloadLayout->addStretch();
downloadLayout->addWidget(m_krunnerSettingsButton);
downloadLayout->addWidget(downloadButton);
layout->addLayout(downloadLayout);
connect(this, &SearchConfigModule::defaultsIndicatorsVisibleChanged, this, &SearchConfigModule::updateUnmanagedState);
connect(this, &SearchConfigModule::defaultsIndicatorsVisibleChanged, m_pluginSelector, &KPluginWidget::setDefaultsIndicatorsVisible);
addConfig(m_settings, this);
}
void SearchConfigModule::load()
......@@ -154,11 +114,6 @@ void SearchConfigModule::load()
m_pluginSelector->clear();
KCModule::load();
m_topPositioning->setChecked(!m_settings->freeFloating());
m_freeFloating->setChecked(m_settings->freeFloating());
m_clearHistoryButton->setEnabled(m_enableHistory->isChecked());
// Set focus on the pluginselector to pass focus to search bar.
m_pluginSelector->setFocus(Qt::OtherFocusReason);
......@@ -168,31 +123,12 @@ void SearchConfigModule::load()
if (!m_pluginID.isEmpty()) {
m_pluginSelector->showConfiguration(m_pluginID);
}
configureClearHistoryButton();
}
void SearchConfigModule::save()
{
m_settings->setFreeFloating(m_freeFloating->isChecked());
m_settings->save();
KCModule::save();
// Combine & write history
if (!m_activityAware->isChecked()) {
if (!m_historyConfigGroup.hasKey(nullUuid)) {
QStringList activities = m_consumer->activities();
activities.removeOne(m_consumer->currentActivity());
QStringList newHistory = m_historyConfigGroup.readEntry(m_consumer->currentActivity(), QStringList());
for (const QString &activity : qAsConst(activities)) {
newHistory.append(m_historyConfigGroup.readEntry(activity, QStringList()));
}
newHistory.removeDuplicates();
m_historyConfigGroup.writeEntry(nullUuid, newHistory, KConfig::Notify);
m_historyConfigGroup.sync();
}
}
m_pluginSelector->save();
QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/krunnerrc"), QStringLiteral("org.kde.kconfig.notify"), QStringLiteral("ConfigChanged"));
......@@ -205,80 +141,13 @@ void SearchConfigModule::defaults()
{
KCModule::defaults();
m_topPositioning->setChecked(!m_settings->defaultFreeFloatingValue());
m_freeFloating->setChecked(m_settings->defaultFreeFloatingValue());
m_pluginSelector->defaults();
}
void SearchConfigModule::configureClearHistoryButton()
{
const QStringList activities = m_consumer->activities();
const QStringList historyKeys = m_historyConfigGroup.keyList();
if (m_activityAware->isChecked() && activities.length() > 1) {
auto *installMenu = new QMenu(m_clearHistoryButton);
QAction *all = installMenu->addAction(m_clearHistoryButton->icon(), i18nc("delete history for all activities", "For all activities"));
installMenu->setEnabled(!historyKeys.isEmpty());
connect(all, &QAction::triggered, this, &SearchConfigModule::deleteAllHistory);
for (const auto &key : activities) {
KActivities::Info info(key);
QIcon icon;
const QString iconStr = info.icon();
if (iconStr.isEmpty()) {
icon = m_clearHistoryButton->icon();
} else if (QFileInfo::exists(iconStr)) {
icon = QIcon(iconStr);
} else {
icon = QIcon::fromTheme(iconStr);
}
QAction *singleActivity = installMenu->addAction(icon, i18nc("delete history for this activity", "For activity \"%1\"", info.name()));
singleActivity->setEnabled(historyKeys.contains(key)); // Otherwise there would be nothing to delete
connect(singleActivity, &QAction::triggered, this, [this, key]() {
deleteHistoryGroup(key);
});
installMenu->addAction(singleActivity);
m_clearHistoryButton->setText(i18n("Clear History…"));
}
m_clearHistoryButton->setMenu(installMenu);
} else {
m_clearHistoryButton->setText(i18n("Clear History"));
m_clearHistoryButton->setMenu(nullptr);
m_clearHistoryButton->setEnabled(m_settings->historyEnabled() && !historyKeys.isEmpty());
}
}
void SearchConfigModule::deleteHistoryGroup(const QString &key)
{
m_historyConfigGroup.deleteEntry(key, KConfig::Notify);
m_historyConfigGroup.sync();
configureClearHistoryButton();
}
void SearchConfigModule::deleteAllHistory()
{
m_historyConfigGroup.deleteGroup(KConfig::Notify);
m_historyConfigGroup.sync();
configureClearHistoryButton();
}
void SearchConfigModule::updateUnmanagedState()
{
bool isNeedSave = false;
isNeedSave |= m_pluginSelector->isSaveNeeded();
isNeedSave |= m_topPositioning->isChecked() == m_settings->freeFloating();
isNeedSave |= m_freeFloating->isChecked() != m_settings->freeFloating();
unmanagedWidgetChangeState(isNeedSave);
bool isDefault = true;
isDefault &= m_pluginSelector->isDefault();
isDefault &= m_topPositioning->isChecked() != m_settings->defaultFreeFloatingValue();
isDefault &= m_freeFloating->isChecked() == m_settings->defaultFreeFloatingValue();
setDefaultIndicatorVisible(m_topPositioning, defaultsIndicatorsVisible() && m_topPositioning->isChecked() == m_settings->defaultFreeFloatingValue());
setDefaultIndicatorVisible(m_freeFloating, defaultsIndicatorsVisible() && m_freeFloating->isChecked() != m_settings->defaultFreeFloatingValue());
unmanagedWidgetDefaultState(isDefault);
unmanagedWidgetChangeState(m_pluginSelector->isSaveNeeded());
unmanagedWidgetDefaultState(m_pluginSelector->isDefault());
}
void SearchConfigModule::setDefaultIndicatorVisible(QWidget *widget, bool visible)
......
......@@ -9,17 +9,12 @@
#ifndef _KCM_SEARCH_H
#define _KCM_SEARCH_H
#include <KActivities/Consumer>
#include <KCModule>
#include <KConfigGroup>
#include <KSharedConfig>
#include <QCheckBox>
#include <QPushButton>
#include <QRadioButton>
#include <QToolButton>
class KPluginWidget;
class KRunnerSettings;
class KCMultiDialog;
class SearchConfigModule : public KCModule
{
......@@ -38,9 +33,6 @@ public Q_SLOTS:
void save() override;
void defaults() override;
void updateUnmanagedState();
void configureClearHistoryButton();
void deleteHistoryGroup(const QString &key);
void deleteAllHistory();
private:
void setDefaultIndicatorVisible(QWidget *widget, bool visible);
......@@ -48,16 +40,8 @@ private:
KPluginWidget *m_pluginSelector;
KSharedConfigPtr m_config;
QString m_pluginID;
QRadioButton *m_topPositioning;
QRadioButton *m_freeFloating;
QCheckBox *m_retainPriorSearch;
QCheckBox *m_activityAware;
QToolButton *m_clearHistoryButton;
QCheckBox *m_enableHistory;
KRunnerSettings *m_settings;
KActivities::Consumer *m_consumer;
KConfigGroup m_historyConfigGroup;
const QString nullUuid = QStringLiteral("00000000-0000-0000-0000-000000000000");
QPushButton *m_krunnerSettingsButton = nullptr;
KCMultiDialog *m_krunnerSettingsDialog = nullptr;
};
#endif
{
"KPlugin": {
"Authors": [
{
"Email": "qydwhotmail@gmail.com",
"Name": "Fushan Wen"
}
],
"Description": "Configure KRunner behavior",
"FormFactors": [
"desktop",
"handset",
"tablet"
],
"Icon": "krunner",
"Id": "kcm_krunnersettings",
"License": "GPL",
"Name": "KRunner Settings",
"Version": "0.1"
}
}
......@@ -13,12 +13,12 @@
#include <KPluginInfo>
#include <KRunner/RunnerManager>
#include "krunnersettings.h"
#include "krunnersettingsbase.h"
KRunnerData::KRunnerData(QObject *parent, const QVariantList &args)
: KCModuleData(parent, args)
, m_krunnerConfig(KSharedConfig::openConfig("krunnerrc"))
, m_settings(new KRunnerSettings(this))
, m_settings(new KRunnerSettingsBase(this))
{
m_settings->load();
}
......
......@@ -12,7 +12,7 @@
#include <KCModuleData>
#include <KSharedConfig>
class KRunnerSettings;
class KRunnerSettingsBase;
class KRunnerData : public KCModuleData
{
......@@ -24,7 +24,7 @@ public:
private:
KSharedConfigPtr m_krunnerConfig;
KRunnerSettings *m_settings;
KRunnerSettingsBase *m_settings;
};
#endif // KRUNNERDATA_H
/*
SPDX-FileCopyrightText: 2022 Fushan Wen <qydwhotmail@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "krunnersettings.h"
#include <KActivities/Info>
#include <KConfig>
#include <KLocalizedString>
#include <KPluginFactory>
#include <QDBusConnection>
#include <QDBusMessage>
#include "krunnersettingsbase.h"
#include "krunnersettingsdata.h"
K_PLUGIN_CLASS_WITH_JSON(KRunnerSettings, "kcm_krunnersettings.json")
KRunnerSettings::KRunnerSettings(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args)
: KQuickAddons::ManagedConfigModule(parent, metaData, args)
, m_data(new KRunnerSettingsData(this))
, m_consumer(new KActivities::Consumer(this))
, m_historyConfigGroup(KSharedConfig::openConfig(QStringLiteral("krunnerstaterc"), KConfig::NoGlobals, QStandardPaths::GenericDataLocation)
->group("PlasmaRunnerManager")
.group("History"))
, m_historyKeys(m_historyConfigGroup.keyList())
, m_doesShowPluginButton(args.size() == 0 || args.constFirst() != QLatin1String("openedFromPluginSettings"))
{
qmlRegisterType<KRunnerSettingsBase>();
setButtons(Apply | Default);
connect(krunnerSettings(), &KRunnerSettingsBase::activityAwareChanged, this, &KRunnerSettings::hasSingleHistoryChanged);
connect(m_consumer, &KActivities::Consumer::activitiesChanged, this, &KRunnerSettings::activityCountChanged);
connect(m_consumer, &KActivities::Consumer::activitiesChanged, this, &KRunnerSettings::hasSingleHistoryChanged);
}
KRunnerSettings::~KRunnerSettings()
{
}
KRunnerSettingsBase *KRunnerSettings::krunnerSettings() const
{
return m_data->settings();
}
int KRunnerSettings::activityCount() const
{
return m_consumer->activities().size();
}
bool KRunnerSettings::hasSingleHistory() const
{
return !krunnerSettings()->activityAware() || m_historyKeys.size() == 1 || activityCount() == 1;
}
QStringList KRunnerSettings::historyKeys() const
{
return m_historyKeys;
}
QString KRunnerSettings::iconNameForActivity(const QString &id) const
{
return KActivities::Info(id).icon();
}
QString KRunnerSettings::singleActivityName() const
{
if (m_historyKeys.size() == 0) {
return QString();
}
// Sometimes there are history items in deleted activities but only
// one activity is available.
if (const QStringList activities = m_consumer->activities(); activities.size() == 1) {
return KActivities::Info(activities.constFirst()).name();
}
return KActivities::Info(m_historyKeys.constFirst()).name();
}
void KRunnerSettings::configureClearHistoryButton()
{
const QStringList historyKeys = m_historyConfigGroup.keyList();
if (historyKeys == m_historyKeys) {
return;
}
m_historyKeys = historyKeys;
Q_EMIT hasSingleHistoryChanged();
Q_EMIT singleActivityNameChanged();
Q_EMIT historyKeysChanged();
}
void KRunnerSettings::deleteAllHistory()
{
m_historyConfigGroup.deleteGroup(KConfig::Notify);
m_historyConfigGroup.sync();
configureClearHistoryButton();
}
void KRunnerSettings::deleteHistoryGroup(const QString &key)
{
if (key.isEmpty()) {
return;
}
m_historyConfigGroup.deleteEntry(key, KConfig::Notify);
m_historyConfigGroup.sync();
configureClearHistoryButton();
}
void KRunnerSettings::save()
{
ManagedConfigModule::save();
// Combine & write history
if (!krunnerSettings()->activityAware()) {
if (!m_historyConfigGroup.hasKey(nullUuid)) {
QStringList activities = m_consumer->activities();
activities.removeOne(m_consumer->currentActivity());
QStringList newHistory = m_historyConfigGroup.readEntry(m_consumer->currentActivity(), QStringList());
for (const QString &activity : std::as_const(activities)) {
newHistory.append(m_historyConfigGroup.readEntry(activity, QStringList()));
}
newHistory.removeDuplicates();
m_historyConfigGroup.writeEntry(nullUuid, newHistory, KConfig::Notify);
m_historyConfigGroup.sync();
}
}
QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/krunnerrc"), QStringLiteral("org.kde.kconfig.notify"), QStringLiteral("ConfigChanged"));
const QHash<QString, QByteArrayList> changes = {{QStringLiteral("Plugins"), {}}};
message.setArguments({QVariant::fromValue(changes)});
QDBusConnection::sessionBus().send(message);
}
#include "krunnersettings.moc"
/*
SPDX-FileCopyrightText: 2022 Fushan Wen <qydwhotmail@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef KRUNNERSETTINGS_H
#define KRUNNERSETTINGS_H
#include <KActivities/Consumer>
#include <KConfigGroup>
#include <KQuickAddons/ManagedConfigModule>
class KRunnerSettingsBase;
class KRunnerSettingsData;
class KRunnerSettings : public KQuickAddons::ManagedConfigModule
{
Q_OBJECT
Q_PROPERTY(KRunnerSettingsBase *krunnerSettings READ krunnerSettings CONSTANT)
/**
* @return @c true if the KCM is not launched from the plugin settings, @c false
* otherwise.
*/
Q_PROPERTY(bool doesShowPluginButton MEMBER m_doesShowPluginButton CONSTANT)
Q_PROPERTY(QString activityCount READ activityCount NOTIFY activityCountChanged)
/**
* @return @c true if activity aware is not enabled or only one activity has
* history, @c false otherwise.
*/
Q_PROPERTY(bool hasSingleHistory READ hasSingleHistory NOTIFY hasSingleHistoryChanged)
Q_PROPERTY(QString singleActivityName READ singleActivityName NOTIFY singleActivityNameChanged)
Q_PROPERTY(QStringList historyKeys READ historyKeys NOTIFY historyKeysChanged)
public:
KRunnerSettings(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args);
~KRunnerSettings() override;
KRunnerSettingsBase *krunnerSettings() const;