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 | SPDX-FileCopyrightText: 2008 Michael Jansen <kde@michael-jansen.biz> |
11 | SPDX-FileCopyrightText: 2008 Alexander Dymo <adymo@kdevelop.org> |
12 | SPDX-FileCopyrightText: 2009 Chani Armitage <chani@kde.org> |
13 | |
14 | SPDX-License-Identifier: LGPL-2.0-or-later |
15 | */ |
16 | |
17 | #include "kshortcutsdialog.h" |
18 | #include "kshortcutschemeshelper_p.h" |
19 | #include "kshortcutsdialog_p.h" |
20 | |
21 | #include <QApplication> |
22 | #include <QDialogButtonBox> |
23 | #include <QDomDocument> |
24 | |
25 | #include <KConfigGroup> |
26 | #include <KLocalizedString> |
27 | #include <KMessageBox> |
28 | #include <KSharedConfig> |
29 | |
30 | #include "kactioncollection.h" |
31 | #include "kxmlguiclient.h" |
32 | #include "kxmlguifactory.h" |
33 | |
34 | /************************************************************************/ |
35 | /* KShortcutsDialog */ |
36 | /* */ |
37 | /* Originally by Nicolas Hadacek <hadacek@via.ecp.fr> */ |
38 | /* */ |
39 | /* Substantially revised by Mark Donohoe <donohoe@kde.org> */ |
40 | /* */ |
41 | /* And by Espen Sand <espen@kde.org> 1999-10-19 */ |
42 | /* (by using KDialog there is almost no code left ;) */ |
43 | /* */ |
44 | /************************************************************************/ |
45 | |
46 | QKeySequence primarySequence(const QList<QKeySequence> &sequences) |
47 | { |
48 | return sequences.isEmpty() ? QKeySequence() : sequences.at(i: 0); |
49 | } |
50 | |
51 | QKeySequence alternateSequence(const QList<QKeySequence> &sequences) |
52 | { |
53 | return sequences.size() <= 1 ? QKeySequence() : sequences.at(i: 1); |
54 | } |
55 | |
56 | class KShortcutsDialogPrivate |
57 | { |
58 | public: |
59 | KShortcutsDialogPrivate(KShortcutsDialog *qq) |
60 | : q(qq) |
61 | { |
62 | } |
63 | |
64 | QList<KActionCollection *> m_collections; |
65 | |
66 | void changeShortcutScheme(const QString &scheme) |
67 | { |
68 | if (m_keyChooser->isModified() |
69 | && KMessageBox::questionTwoActions(parent: q, |
70 | i18n("The current shortcut scheme is modified. Save before switching to the new one?" ), |
71 | title: QString(), |
72 | primaryAction: KStandardGuiItem::save(), |
73 | secondaryAction: KStandardGuiItem::discard()) |
74 | == KMessageBox::PrimaryAction) { |
75 | m_keyChooser->save(); |
76 | } else { |
77 | m_keyChooser->undo(); |
78 | } |
79 | |
80 | QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); |
81 | m_keyChooser->clearCollections(); |
82 | |
83 | for (KActionCollection *collection : std::as_const(t&: m_collections)) { |
84 | // passing an empty stream forces the clients to reread the XML |
85 | KXMLGUIClient *client = const_cast<KXMLGUIClient *>(collection->parentGUIClient()); |
86 | if (client) { |
87 | client->setXMLGUIBuildDocument(QDomDocument()); |
88 | } |
89 | } |
90 | |
91 | // get xmlguifactory |
92 | if (!m_collections.isEmpty()) { |
93 | const KXMLGUIClient *client = m_collections.first()->parentGUIClient(); |
94 | if (client) { |
95 | KXMLGUIFactory *factory = client->factory(); |
96 | if (factory) { |
97 | factory->changeShortcutScheme(scheme); |
98 | } |
99 | } |
100 | } |
101 | |
102 | for (KActionCollection *collection : std::as_const(t&: m_collections)) { |
103 | m_keyChooser->addCollection(collection); |
104 | } |
105 | |
106 | QApplication::restoreOverrideCursor(); |
107 | } |
108 | |
109 | void undo() |
110 | { |
111 | m_keyChooser->undo(); |
112 | } |
113 | |
114 | void toggleDetails() |
115 | { |
116 | const bool isVisible = m_schemeEditor->isVisible(); |
117 | |
118 | m_schemeEditor->setVisible(!isVisible); |
119 | m_detailsButton->setText(detailsButtonText() + (isVisible ? QStringLiteral(" >>" ) : QStringLiteral(" <<" ))); |
120 | } |
121 | |
122 | static QString detailsButtonText() |
123 | { |
124 | return i18n("Manage &Schemes" ); |
125 | } |
126 | |
127 | void save() |
128 | { |
129 | m_keyChooser->save(); |
130 | Q_EMIT q->saved(); |
131 | } |
132 | |
133 | KShortcutsDialog *const q; |
134 | KShortcutsEditor *m_keyChooser = nullptr; // ### move |
135 | KShortcutSchemesEditor *m_schemeEditor = nullptr; |
136 | QPushButton *m_detailsButton = nullptr; |
137 | bool m_saveSettings = false; |
138 | }; |
139 | |
140 | KShortcutsDialog::KShortcutsDialog(QWidget *parent) |
141 | : KShortcutsDialog(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, parent) |
142 | { |
143 | } |
144 | |
145 | KShortcutsDialog::KShortcutsDialog(KShortcutsEditor::ActionTypes types, KShortcutsEditor::LetterShortcuts allowLetterShortcuts, QWidget *parent) |
146 | : QDialog(parent) |
147 | , d(new KShortcutsDialogPrivate(this)) |
148 | { |
149 | setWindowTitle(i18nc("@title:window" , "Configure Keyboard Shortcuts" )); |
150 | setModal(true); |
151 | |
152 | QVBoxLayout *layout = new QVBoxLayout(this); |
153 | |
154 | d->m_keyChooser = new KShortcutsEditor(this, types, allowLetterShortcuts); |
155 | layout->addWidget(d->m_keyChooser); |
156 | |
157 | d->m_schemeEditor = new KShortcutSchemesEditor(this); |
158 | connect(sender: d->m_schemeEditor, signal: &KShortcutSchemesEditor::shortcutsSchemeChanged, context: this, slot: [this](const QString &scheme) { |
159 | d->changeShortcutScheme(scheme); |
160 | }); |
161 | d->m_schemeEditor->hide(); |
162 | layout->addWidget(d->m_schemeEditor); |
163 | |
164 | d->m_detailsButton = new QPushButton; |
165 | d->m_detailsButton->setText(KShortcutsDialogPrivate::detailsButtonText() + QLatin1String(" >>" )); |
166 | |
167 | QPushButton *printButton = new QPushButton; |
168 | KGuiItem::assign(button: printButton, item: KStandardGuiItem::print()); |
169 | |
170 | QDialogButtonBox *buttonBox = new QDialogButtonBox(this); |
171 | buttonBox->addButton(button: d->m_detailsButton, role: QDialogButtonBox::ActionRole); |
172 | buttonBox->addButton(button: printButton, role: QDialogButtonBox::ActionRole); |
173 | buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults); |
174 | KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Ok), item: KStandardGuiItem::ok()); |
175 | KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Cancel), item: KStandardGuiItem::cancel()); |
176 | KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::RestoreDefaults), item: KStandardGuiItem::defaults()); |
177 | layout->addWidget(buttonBox); |
178 | |
179 | connect(sender: buttonBox->button(which: QDialogButtonBox::RestoreDefaults), signal: &QAbstractButton::clicked, context: d->m_keyChooser, slot: &KShortcutsEditor::allDefault); |
180 | connect(sender: d->m_detailsButton, signal: &QPushButton::clicked, context: this, slot: [this]() { |
181 | d->toggleDetails(); |
182 | }); |
183 | connect(sender: printButton, signal: &QPushButton::clicked, context: d->m_keyChooser, slot: &KShortcutsEditor::printShortcuts); |
184 | connect(sender: buttonBox, signal: &QDialogButtonBox::rejected, context: this, slot: [this]() { |
185 | d->undo(); |
186 | }); |
187 | |
188 | connect(sender: buttonBox, signal: &QDialogButtonBox::accepted, context: this, slot: &QDialog::accept); |
189 | connect(sender: buttonBox, signal: &QDialogButtonBox::rejected, context: this, slot: &QDialog::reject); |
190 | |
191 | KConfigGroup group(KSharedConfig::openConfig(), QStringLiteral("KShortcutsDialog Settings" )); |
192 | resize(group.readEntry(key: "Dialog Size" , defaultValue: sizeHint())); |
193 | } |
194 | |
195 | KShortcutsDialog::~KShortcutsDialog() |
196 | { |
197 | KConfigGroup group(KSharedConfig::openConfig(), QStringLiteral("KShortcutsDialog Settings" )); |
198 | group.writeEntry(key: "Dialog Size" , value: size(), pFlags: KConfigGroup::Persistent | KConfigGroup::Global); |
199 | } |
200 | |
201 | void KShortcutsDialog::addCollection(KActionCollection *collection, const QString &title) |
202 | { |
203 | d->m_keyChooser->addCollection(collection, title); |
204 | d->m_collections << collection; |
205 | } |
206 | |
207 | QList<KActionCollection *> KShortcutsDialog::actionCollections() const |
208 | { |
209 | return d->m_collections; |
210 | } |
211 | |
212 | // TODO KF6: remove this method, always save settings, and open the |
213 | // dialog with show() not exec() |
214 | bool KShortcutsDialog::configure(bool saveSettings) |
215 | { |
216 | d->m_saveSettings = saveSettings; |
217 | if (isModal()) { |
218 | int retcode = exec(); |
219 | return retcode; |
220 | } else { |
221 | show(); |
222 | return false; |
223 | } |
224 | } |
225 | |
226 | void KShortcutsDialog::accept() |
227 | { |
228 | if (d->m_saveSettings) { |
229 | d->save(); |
230 | } |
231 | QDialog::accept(); |
232 | } |
233 | |
234 | QSize KShortcutsDialog::sizeHint() const |
235 | { |
236 | return QSize(600, 480); |
237 | } |
238 | |
239 | // static |
240 | void KShortcutsDialog::showDialog(KActionCollection *collection, KShortcutsEditor::LetterShortcuts allowLetterShortcuts, QWidget *parent) |
241 | { |
242 | auto *dlg = new KShortcutsDialog(KShortcutsEditor::AllActions, allowLetterShortcuts, parent); |
243 | dlg->setAttribute(Qt::WA_DeleteOnClose); |
244 | |
245 | dlg->d->m_saveSettings = true; // Always save settings if the dialog is accepted |
246 | |
247 | dlg->addCollection(collection); |
248 | dlg->show(); |
249 | } |
250 | |
251 | void KShortcutsDialog::importConfiguration(const QString &path) |
252 | { |
253 | KConfig config(path); |
254 | d->m_keyChooser->importConfiguration(config: static_cast<KConfigBase *>(&config)); |
255 | } |
256 | |
257 | void KShortcutsDialog::exportConfiguration(const QString &path) const |
258 | { |
259 | KConfig config(path); |
260 | d->m_keyChooser->exportConfiguration(config: static_cast<KConfigBase *>(&config)); |
261 | } |
262 | |
263 | void KShortcutsDialog::refreshSchemes() |
264 | { |
265 | d->m_schemeEditor->refreshSchemes(); |
266 | } |
267 | |
268 | void KShortcutsDialog::addActionToSchemesMoreButton(QAction *action) |
269 | { |
270 | d->m_schemeEditor->addMoreMenuAction(action); |
271 | } |
272 | |
273 | #include "moc_kshortcutsdialog.cpp" |
274 | #include "moc_kshortcutsdialog_p.cpp" |
275 | |