1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1998 Mark Donohoe <donohoe@kde.org>
4 SPDX-FileCopyrightText: 1997 Nicolas Hadacek <hadacek@kde.org>
5 SPDX-FileCopyrightText: 1998 Matthias Ettrich <ettrich@kde.org>
6 SPDX-FileCopyrightText: 2001 Ellis Whitehead <ellis@kde.org>
7 SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
8 SPDX-FileCopyrightText: 2007 Roberto Raggi <roberto@kdevelop.org>
9 SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com>
10
11 SPDX-License-Identifier: LGPL-2.0-or-later
12*/
13
14#include "config-xmlgui.h"
15#include "kshortcutsdialog_p.h"
16
17#include <QAction>
18#include <QGridLayout>
19#include <QLabel>
20#include <QPainter>
21#include <QPen>
22#include <QRadioButton>
23
24#include <KLocalizedString>
25#if HAVE_GLOBALACCEL
26#include <KGlobalAccel>
27#endif
28
29#include "kkeysequencewidget.h"
30
31void TabConnectedWidget::paintEvent(QPaintEvent *e)
32{
33 QWidget::paintEvent(event: e);
34 QPainter p(this);
35 QPen pen(QPalette().highlight().color());
36 pen.setWidth(6);
37 p.setPen(pen);
38 p.drawLine(x1: 0, y1: 0, x2: width(), y2: 0);
39 if (qApp->isLeftToRight()) {
40 p.drawLine(x1: 0, y1: 0, x2: 0, y2: height());
41 } else {
42 p.drawLine(x1: width(), y1: 0, x2: width(), y2: height());
43 }
44}
45
46ShortcutEditWidget::ShortcutEditWidget(QWidget *viewport, const QKeySequence &defaultSeq, const QKeySequence &activeSeq, bool allowLetterShortcuts)
47 : TabConnectedWidget(viewport)
48 , m_defaultKeySequence(defaultSeq)
49 , m_isUpdating(false)
50 , m_action(nullptr)
51 , m_noneText(i18nc("No shortcut defined", "None"))
52{
53 QGridLayout *layout = new QGridLayout(this);
54
55 m_defaultRadio = new QRadioButton(i18nc("@option:radio", "Default:"), this);
56 m_defaultLabel = new QLabel(m_noneText, this);
57 const QString defaultText = defaultSeq.toString(format: QKeySequence::NativeText);
58 if (!defaultText.isEmpty()) {
59 m_defaultLabel->setText(defaultText);
60 }
61
62 m_customRadio = new QRadioButton(i18nc("@option:radio", "Custom:"), this);
63 m_customEditor = new KKeySequenceWidget(this);
64 m_customEditor->setModifierlessAllowed(allowLetterShortcuts);
65
66 layout->addWidget(m_defaultRadio, row: 0, column: 0);
67 layout->addWidget(m_defaultLabel, row: 0, column: 1);
68 layout->addWidget(m_customRadio, row: 1, column: 0);
69 layout->addWidget(m_customEditor, row: 1, column: 1);
70 layout->setColumnStretch(column: 2, stretch: 1);
71
72 setKeySequence(activeSeq);
73
74 connect(sender: m_defaultRadio, signal: &QRadioButton::toggled, context: this, slot: &ShortcutEditWidget::defaultToggled);
75 connect(sender: m_customEditor, signal: &KKeySequenceWidget::keySequenceChanged, context: this, slot: &ShortcutEditWidget::setCustom);
76 connect(sender: m_customEditor, signal: &KKeySequenceWidget::stealShortcut, context: this, slot: &ShortcutEditWidget::stealShortcut);
77#if HAVE_GLOBALACCEL
78 connect(sender: KGlobalAccel::self(), signal: &KGlobalAccel::globalShortcutChanged, context: this, slot: [this](QAction *action, const QKeySequence &seq) {
79 if (action != m_action) {
80 return;
81 }
82 setKeySequence(seq);
83 });
84#endif
85}
86
87KKeySequenceWidget::ShortcutTypes ShortcutEditWidget::checkForConflictsAgainst() const
88{
89 return m_customEditor->checkForConflictsAgainst();
90}
91
92// slot
93void ShortcutEditWidget::defaultToggled(bool checked)
94{
95 if (m_isUpdating) {
96 return;
97 }
98
99 m_isUpdating = true;
100 if (checked) {
101 // The default key sequence should be activated. We check first if this is
102 // possible.
103 if (m_customEditor->isKeySequenceAvailable(seq: m_defaultKeySequence)) {
104 // Clear the customs widget
105 m_customEditor->clearKeySequence();
106 Q_EMIT keySequenceChanged(m_defaultKeySequence);
107 } else {
108 // We tried to switch to the default key sequence and failed. Go
109 // back.
110 m_customRadio->setChecked(true);
111 }
112 } else {
113 // The empty key sequence is always valid
114 Q_EMIT keySequenceChanged(QKeySequence());
115 }
116 m_isUpdating = false;
117}
118
119void ShortcutEditWidget::setCheckActionCollections(const QList<KActionCollection *> &checkActionCollections)
120{
121 // We just forward them to out KKeySequenceWidget.
122 m_customEditor->setCheckActionCollections(checkActionCollections);
123}
124
125void ShortcutEditWidget::setCheckForConflictsAgainst(KKeySequenceWidget::ShortcutTypes types)
126{
127 m_customEditor->setCheckForConflictsAgainst(types);
128}
129
130void ShortcutEditWidget::setComponentName(const QString &componentName)
131{
132 m_customEditor->setComponentName(componentName);
133}
134
135void ShortcutEditWidget::setMultiKeyShortcutsAllowed(bool allowed)
136{
137 // We just forward them to out KKeySequenceWidget.
138 m_customEditor->setMultiKeyShortcutsAllowed(allowed);
139}
140
141bool ShortcutEditWidget::multiKeyShortcutsAllowed() const
142{
143 return m_customEditor->multiKeyShortcutsAllowed();
144}
145
146void ShortcutEditWidget::setAction(QObject *action)
147{
148 m_action = action;
149}
150
151// slot
152void ShortcutEditWidget::setCustom(const QKeySequence &seq)
153{
154 if (m_isUpdating) {
155 return;
156 }
157
158 // seq is a const reference to a private variable of KKeySequenceWidget.
159 // Somewhere below we possible change that one. But we want to emit seq
160 // whatever happens. So we make a copy.
161 QKeySequence original = seq;
162
163 m_isUpdating = true;
164
165 // Check if the user typed in the default sequence into the custom field.
166 // We do this by calling setKeySequence which will do the right thing.
167 setKeySequence(original);
168
169 Q_EMIT keySequenceChanged(original);
170 m_isUpdating = false;
171}
172
173void ShortcutEditWidget::setKeySequence(const QKeySequence &activeSeq)
174{
175 const QString seqString = activeSeq.isEmpty() ? m_noneText : activeSeq.toString(format: QKeySequence::NativeText);
176 if (seqString == m_defaultLabel->text()) {
177 m_defaultRadio->setChecked(true);
178 m_customEditor->clearKeySequence();
179 } else {
180 m_customRadio->setChecked(true);
181 // m_customEditor->setKeySequence does some stuff we only want to
182 // execute when the sequence really changes.
183 if (activeSeq != m_customEditor->keySequence()) {
184 m_customEditor->setKeySequence(seq: activeSeq);
185 }
186 }
187}
188

source code of kxmlgui/src/kshortcuteditwidget.cpp