Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit 1ee6660c authored by David Redondo's avatar David Redondo 🏎

Rewrite of the global shortcuts kcm

Summary:
This is a total rewrite of the global shortcuts kcm from scratch. It uses an
abstract item model backend with a qml frontend. This resolves some issues the
old kcm inherently had because it just stacked KShortcutEditors. First it enables
a global serach/filter which either matches the component name, actions, default
or set key combinations across components. Secondly KGlobalAccel can have multiple
default/active key combinations for each action - the old kcm only exposed two each.
The new kcm displays all default or set key combinations.
The main visual structure is similiar to the old kcm. On the left there is a list
with all components but rather than divided into "Application Launchers" and
"Other Shortcuts" the sections are now called "Applications" and "System Services"
(cf. notifications kcm) and the components are now assigned whether the service
we find for a component is an application or not rather if the component was
added via .desktop file. In the main view the shortcuts are displayed. Each item
corresponds to one action. Initially each item is collapsed and shows the action
name and a list of the currently set key combinations for that action. In the
expanded form all default shortcuts are shown which can be activated or
deactivated and all other active shortcuts ("Custom Shortcuts"). It is possible
to change, remove or add new custom shortcuts.
The kcm and model communicate directly with the daemon over DBus. This removes
the need to awkwardly construct actions to pass to the KGlobalAccel API.

BUG: 157468
BUG: 213101
BUG: 230583
BUG: 250121
BUG: 251437
BUG: 272554
BUG: 318964
BUG: 341817
BUG: 348264
BUG: 366257
BUG: 369020
BUG: 388574
BUG: 393403
BUG: 408942
BUG: 416149
BUG: 416737
BUG: 417915
BUG: 419215
BUG: 419515
BUG: 419624
BUG: 419692
BUG: 419825
BUG: 419909
BUG: 420093
FIXED-IN: 5.19.0

Closes T7267

Test Plan:
kcmshell5 kcm_keys
{F8243559}

{F8243560}

{F8243561}

{F8243562}

{F8243563}

{F8243564}

Reviewers: #vdg, #plasma, ngraham

Reviewed By: #vdg, ngraham

Subscribers: GB_2, broulik, davidedmundson, nicolasfella, ngraham, iasensio, plasma-devel

Tags: #plasma

Maniphest Tasks: T7267

Differential Revision: https://phabricator.kde.org/D28744
parent fdfb4878
# KI18N Translation Domain for this library
add_definitions(-DTRANSLATION_DOMAIN=\"kcmkeys\")
add_definitions(-DTRANSLATION_DOMAIN=\"kcm_keys\")
########### next target ###############
set(kcm_keys_PART_SRCS
kglobalshortcutseditor.cpp
globalshortcuts.cpp
select_scheme_dialog.cpp
kglobalaccel_interface.cpp
kglobalaccel_component_interface.cpp
export_scheme_dialog.cpp
)
ki18n_wrap_ui( kcm_keys_PART_SRCS
export_scheme_dialog.ui
kglobalshortcutseditor.ui
select_application.ui
select_scheme_dialog.ui )
set(kcm_keys_SRCS
kcm_keys.cpp
filteredmodel.cpp
shortcutsmodel.cpp
)
set(kglobalaccel_xml ${KGLOBALACCEL_DBUS_INTERFACES_DIR}/kf5_org.kde.KGlobalAccel.xml)
set_source_files_properties(${kglobalaccel_xml} PROPERTIES INCLUDE "kglobalshortcutinfo.h")
qt5_add_dbus_interface(kdeui_LIB_SRCS ${kglobalaccel_xml} kglobalaccel_interface )
set_source_files_properties(${kglobalaccel_xml} PROPERTIES
INCLUDE "kglobalshortcutinfo.h"
NO_NAMESPACE TRUE
CLASSNAME "KGlobalAccelInterface"
)
qt5_add_dbus_interface(kcm_keys_SRCS ${kglobalaccel_xml} kglobalaccel_interface)
set(kglobalaccel_component_xml ${KGLOBALACCEL_DBUS_INTERFACES_DIR}/kf5_org.kde.kglobalaccel.Component.xml)
set_source_files_properties(${kglobalaccel_component_xml} PROPERTIES INCLUDE "kglobalshortcutinfo.h")
qt5_add_dbus_interface(kdeui_LIB_SRCS ${kglobalaccel_component_xml} kglobalaccel_component_interface )
set_source_files_properties(${kglobalaccel_component_xml} PROPERTIES
INCLUDE "kglobalshortcutinfo.h"
NO_NAMESPACE TRUE
CLASSNAME "KGlobalAccelComponentInterface"
)
qt5_add_dbus_interface(kcm_keys_SRCS ${kglobalaccel_component_xml} kglobalaccel_component_interface)
ecm_qt_declare_logging_category(kcm_keys_SRCS
HEADER kcmkeys_debug.h
IDENTIFIER KCMKEYS
CATEGORY_NAME org.kde.kcm_keys
EXPORT KCMKEYS
DESCRIPTION "System Settings - Global Shortcuts"
)
ecm_qt_install_logging_categories(
EXPORT KCMKEYS
DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}
)
add_library(kcm_keys MODULE ${kcm_keys_SRCS})
add_library(kcm_keys MODULE ${kcm_keys_PART_SRCS})
target_link_libraries(kcm_keys
Qt5::DBus
KF5::KCMUtils
KF5::GlobalAccel
KF5::I18n
KF5::KIOWidgets
KF5::XmlGui
KF5::ItemModels
KF5::ItemViews
KF5::QuickAddons
)
install(TARGETS kcm_keys DESTINATION ${KDE_INSTALL_PLUGINDIR} )
kcoreaddons_desktop_to_json(kcm_keys "kcm_keys.desktop")
install(FILES kcm_keys.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR})
install(TARGETS kcm_keys DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms)
########### install files ###############
kpackage_install_package(package kcm_keys kcms)
install( FILES keys.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} )
install( FILES
install(FILES
schemes/kde3.kksrc
schemes/kde4.kksrc
schemes/mac4.kksrc
......@@ -52,6 +63,5 @@ install( FILES
schemes/win3.kksrc
schemes/win4.kksrc
schemes/wm3.kksrc
DESTINATION ${KDE_INSTALL_DATADIR}/kcmkeys )
DESTINATION ${KDE_INSTALL_DATADIR}/kcmkeys
)
2005-09-30 Benjamin Meyer
* Removed Command Shortcuts, it is already in kmenuedit
1999-08-19 Duncan Haldane <duncan@kde.org>
* removed left-over commented out code from change
decribed below, and adjusted help doc names to
index-1.html
1999-02-28 Duncan Haldane <duncan@kde.org>
* commented out those unnecessary debug calls.
in keyconfig.cpp
1998-12-19 Duncan Haldane <f.d.m.haldane@cwix.com>
* Converted global.cpp, global.h to keyconfig.cpp,
keyconfig.h, that can now be used to configure both
the standard keys and the global keys
in the same sophisticated manner as
global.cpp did for just the global keys.
* converted main.cpp to use keyconfig.cpp rather than
global.cpp and standard.cpp for standard and globall
key configuration. KGlobalConfig and KStdConfig disappear.
(KGlobalConfig is renamed to KKeyConfig)
* appropriate changes to Makefile.am.
* standard key binding are now #include'd from
stdbindings.cpp
* standard.cpp, standard.h are left here for now.
The entries that used to use them in main.cpp and
Makefile.am are just commented out for now.
#! /usr/bin/env bash
# customkeys=`grep "^.include .\.\." keyconfig.cpp | sed -e "s#.*\"\(.*\)\"#\1#"`
# $XGETTEXT *.cpp $customkeys -o $podir/kcmkeys.pot
$EXTRACTRC *.ui >> rc.cpp
$XGETTEXT *.cpp -o $podir/kcmkeys.pot
rm -f rc.cpp
$XGETTEXT `find . -name "*.cpp" -o -name "*.qml"` -o $podir/kcm_keys.pot
CHANGES V0.2
- Global keys stored by default in ~/.kde/share/config/kdeglobals
[Global Keys] group
- KKeyDialog checks new key choices against exising bindings for the widget
and against entries in .kderc [Global Keys]
- kcmkeys now has two standard kcontrol pages - one for standard desktop
accelerators and one for global keybindings.
/**
* Copyright (C) 2009 Michael Jansen <kde@michael-jansen.biz>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "export_scheme_dialog.h"
#include <QCheckBox>
#include <KLocalizedString>
#include <KConfigGroup>
#include <QDialogButtonBox>
#include <QPushButton>
ExportSchemeDialog::ExportSchemeDialog(QStringList components, QWidget *parent)
: QDialog(parent),
ui(),
mComponents(components)
{
QWidget *w = new QWidget(this);
ui.setupUi(w);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(w);
// We allow to check more than one button
mButtons.setExclusive(false);
// A grid layout for the buttons
QGridLayout *vb = new QGridLayout(this);
int item=0;
for (const QString &component : qAsConst(mComponents)) {
QCheckBox *cb = new QCheckBox(component);
vb->addWidget(cb, item / 2, item % 2);
mButtons.addButton(cb, item);
++item;
}
ui.components->setLayout(vb);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
okButton->setDefault(true);
okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
mainLayout->addWidget(buttonBox);
}
ExportSchemeDialog::~ExportSchemeDialog()
{}
QStringList ExportSchemeDialog::selectedComponents() const
{
QStringList rc;
const auto buttons = mButtons.buttons();
for (const QAbstractButton *button : buttons) {
if (button->isChecked())
{
// Remove the '&' added by KAcceleratorManager magically
rc.append(KLocalizedString::removeAcceleratorMarker(button->text()));
}
}
return rc;
}
#include "moc_export_scheme_dialog.cpp"
#ifndef EXPORT_SCHEME_DIALOG_H
#define EXPORT_SCHEME_DIALOG_H
/**
* Copyright (C) 2009 Michael Jansen <kde@michael-jansen.biz>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "ui_export_scheme_dialog.h"
#include <QButtonGroup>
#include <QDialog>
/**
* @author Michael Jansen <kde@michael-jansen.biz>
*/
class ExportSchemeDialog : public QDialog
{
Q_OBJECT
public:
ExportSchemeDialog (QStringList components, QWidget *parent=nullptr);
~ExportSchemeDialog() override;
// Get the list of currently selected components
QStringList selectedComponents() const;
private:
Ui::ExportSchemeDialog ui;
// list of components to choose from
QStringList mComponents;
// list of buttons for the components
QButtonGroup mButtons;
}; // ExportSchemeDialog
#endif /* EXPORT_SCHEME_DIALOG_H */
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ExportSchemeDialog</class>
<widget class="QWidget" name="ExportSchemeDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="components_label">
<property name="text">
<string>Select the Components to Export</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="components">
<property name="title">
<string>Components</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
/*
* Copyright 2020 David Redondo <kde@david-redondo.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "filteredmodel.h"
#include <QKeySequence>
#include "shortcutsmodel.h"
FilteredShortcutsModel::FilteredShortcutsModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
setRecursiveFilteringEnabled(true);
}
bool FilteredShortcutsModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if (m_filter.isEmpty()) {
return true;
}
const QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
const bool displayMatches = index.data(Qt::DisplayRole).toString().contains(m_filter, Qt::CaseInsensitive);
if (!source_parent.isValid() || displayMatches) {
return displayMatches;
}
if (index.parent().data(Qt::DisplayRole).toString().contains(m_filter, Qt::CaseInsensitive)) {
return true;
}
const auto &defaultShortcuts = index.data(ShortcutsModel::DefaultShortcutsRole).value<QSet<QKeySequence>>();
for (const auto& shortcut : defaultShortcuts) {
if (shortcut.toString(QKeySequence::NativeText).contains(m_filter, Qt::CaseInsensitive)) {
return true;
}
}
const auto &shortcuts = index.data(ShortcutsModel::CustomShortcutsRole).value<QSet<QKeySequence>>();
for (const auto& shortcut : shortcuts) {
if (shortcut.toString(QKeySequence::NativeText).contains(m_filter, Qt::CaseInsensitive)) {
return true;
}
}
return false;
}
QString FilteredShortcutsModel::filter() const
{
return m_filter;
}
void FilteredShortcutsModel::setFilter(const QString &filter)
{
if (filter == m_filter) {
return;
}
m_filter = filter;
invalidateFilter();
emit filterChanged();
}
/*
* Copyright 2020 David Redondo <kde@david-redondo.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FILTEREDMODEL_H
#define FILTEREDMODEL_H
#include <QSortFilterProxyModel>
class FilteredShortcutsModel : public QSortFilterProxyModel
{
Q_OBJECT
Q_PROPERTY(QString filter READ filter WRITE setFilter NOTIFY filterChanged)
public:
explicit FilteredShortcutsModel(QObject *parent);
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
QString filter() const;
void setFilter(const QString &filter);
Q_SIGNALS:
void filterChanged();
private:
QString m_filter;
};
#endif
/*
* Copyright 2007 Andreas Pakulat <apaku@gmx.de>
* Copyright 2008 Michael Jansen <kde@michael-jansen.biz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "globalshortcuts.h"
#include "kglobalshortcutseditor.h"
#include <KLocalizedString>
#include <KMessageBox>
#include <KPluginFactory>
#include <QLayout>
K_PLUGIN_FACTORY(GlobalShortcutsModuleFactory, registerPlugin<GlobalShortcutsModule>();)
GlobalShortcutsModule::GlobalShortcutsModule(QWidget *parent, const QVariantList &args)
: KCModule(parent, args),
editor(nullptr)
{
KCModule::setButtons(KCModule::Buttons(KCModule::Default | KCModule::Apply | KCModule::Help));
// Create the kglobaleditor
editor = new KGlobalShortcutsEditor(this, KShortcutsEditor::GlobalAction);
connect(editor, &KGlobalShortcutsEditor::changed, this, &GlobalShortcutsModule::markAsChanged);
// Layout the hole bunch
QVBoxLayout *global = new QVBoxLayout;
global->addWidget(editor);
setLayout(global);
}
GlobalShortcutsModule::~GlobalShortcutsModule()
{}
void GlobalShortcutsModule::load()
{
editor->load();
}
void GlobalShortcutsModule::defaults()
{
switch (KMessageBox::questionYesNoCancel(
this,
i18n("You are about to reset all shortcuts to their default values."),
i18n("Reset to defaults"),
KGuiItem(i18n("Current Component")),
KGuiItem(i18n("All Components"))))
{
case KMessageBox::Yes:
editor->defaults(KGlobalShortcutsEditor::CurrentComponent);
break;
case KMessageBox::No:
editor->defaults(KGlobalShortcutsEditor::AllComponents);
break;
default:
return;
}
}
void GlobalShortcutsModule::save()
{
editor->save();
}
#include "globalshortcuts.moc"
/*
* Copyright 2007 Andreas Pakulat <apaku@gmx.de>
* Copyright 2008 Michael Jansen <kde@michael-jansen.biz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef GLOBAL_SHORTCUTS_H
#define GLOBAL_SHORTCUTS_H
#include <kcmodule.h>
#include <QHash>
class KGlobalShortcutsEditor;
class GlobalShortcutsModule : public KCModule
{
Q_OBJECT
public:
GlobalShortcutsModule(QWidget *parent, const QVariantList &args);
~GlobalShortcutsModule() override;
void save() override;
void load() override;
void defaults() override;
private:
KGlobalShortcutsEditor *editor = nullptr;
};
#endif
/*
* Copyright 2020 David Redondo <kde@david-redondo.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "kcm_keys.h"
#include <QDBusMetaType>
#include <QFile>
#include <QQuickItem>
#include <QQuickRenderControl>
#include <QWindow>
#include <KAboutData>
#include <KConfig>
#include <KConfigGroup>
#include <kglobalaccel_interface.h>
#include <KGlobalShortcutInfo>
#include <KLocalizedString>
#include <KMessageBox>
#include <KOpenWithDialog>
#include <KPluginFactory>
#include "filteredmodel.h"
#include "kcmkeys_debug.h"
#include "shortcutsmodel.h"
K_PLUGIN_CLASS_WITH_JSON(KCMKeys, "kcm_keys.json")
KCMKeys::KCMKeys(QObject *parent, const QVariantList &args)
: KQuickAddons::ConfigModule(parent, args)
{
constexpr char uri[] = "org.kde.private.kcms.keys";
qmlRegisterUncreatableType<ShortcutsModel>(uri, 2, 0, "ShortcutsModel", "Can't create ShortcutsModel");
qmlRegisterAnonymousType<FilteredShortcutsModel>(uri, 2);
qmlRegisterAnonymousType<KGlobalAccelInterface>(uri, 2);
qmlProtectModule(uri, 2);
qDBusRegisterMetaType<KGlobalShortcutInfo>();
qDBusRegisterMetaType<QList<KGlobalShortcutInfo>>();
qDBusRegisterMetaType<QList<QStringList>>();
KAboutData *about = new KAboutData(QStringLiteral("kcm_keys"), i18n("Global Shortcuts"),
QStringLiteral("2.0"), QString(), KAboutLicense::GPL);
about->addAuthor(i18n("David Redondo"), QString(), QStringLiteral("kde@david-redondo.de"));
setAboutData(about);
m_globalAccelInterface = new KGlobalAccelInterface(QStringLiteral("org.kde.kglobalaccel")
, QStringLiteral("/kglobalaccel"), QDBusConnection::sessionBus(), this);
if (!m_globalAccelInterface->isValid()) {
setError(i18n("Failed to communicate with global shortcuts daemon"));
qCCritical(KCMKEYS) << "Interface is not valid";
if (m_globalAccelInterface->lastError().isValid()) {
qCCritical(KCMKEYS) << m_globalAccelInterface->lastError().name() << m_globalAccelInterface->lastError().message();
}
}
m_shortcutsModel = new ShortcutsModel(m_globalAccelInterface, this);
m_fileredModel = new FilteredShortcutsModel(this);
m_fileredModel->setSourceModel(m_shortcutsModel);
connect(m_shortcutsModel, &QAbstractItemModel::dataChanged, this, [this] {
setNeedsSave(m_shortcutsModel->needsSave());
setRepresentsDefaults(m_shortcutsModel->isDefault());
});
connect(m_shortcutsModel, &QAbstractItemModel::modelReset, this, [this] {
setNeedsSave(false);
setRepresentsDefaults(m_shortcutsModel->isDefault());
});
connect(m_shortcutsModel, &ShortcutsModel::errorOccured, this, &KCMKeys::setError);
}
void KCMKeys::load()
{
m_shortcutsModel->load();
}
void KCMKeys::save()
{
m_shortcutsModel->save();
}
void