1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1997 Matthias Kalle Dalheimer <kalle@kde.org>
4 SPDX-FileCopyrightText: 1998, 1999, 2000 KDE Team
5 SPDX-FileCopyrightText: 2008 Nick Shaforostoff <shaforostoff@kde.ru>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9
10#include "kcheckaccelerators.h"
11
12#include <QAction>
13#include <QApplication>
14#include <QChar>
15#include <QCheckBox>
16#include <QClipboard>
17#include <QComboBox>
18#include <QDebug>
19#include <QDialog>
20#include <QDialogButtonBox>
21#include <QFile>
22#include <QGroupBox>
23#include <QLabel>
24#include <QMenu>
25#include <QMouseEvent>
26#include <QPushButton>
27#include <QShortcutEvent>
28#include <QTabBar>
29#include <QTextBrowser>
30#include <QVBoxLayout>
31
32#include <KAcceleratorManager>
33#include <KConfig>
34#include <KConfigGroup>
35#include <KLocalizedString>
36#include <KSharedConfig>
37
38KCheckAccelerators::KCheckAccelerators(QObject *parent, int key_, bool autoCheck_)
39 : QObject(parent)
40 , key(key_)
41 , block(false)
42 , autoCheck(autoCheck_)
43 , drklash(nullptr)
44{
45 setObjectName(QStringLiteral("kapp_accel_filter"));
46
47 KConfigGroup cg(KSharedConfig::openConfig(), QStringLiteral("Development"));
48 alwaysShow = cg.readEntry(key: "AlwaysShowCheckAccelerators", defaultValue: false);
49
50 parent->installEventFilter(filterObj: this);
51 connect(sender: &autoCheckTimer, signal: &QTimer::timeout, context: this, slot: &KCheckAccelerators::autoCheckSlot);
52}
53
54bool KCheckAccelerators::eventFilter(QObject * /*obj*/, QEvent *e)
55{
56 if (block) {
57 return false;
58 }
59
60 switch (e->type()) { // just simplify debuggin
61 case QEvent::ShortcutOverride:
62 if (key && (static_cast<QKeyEvent *>(e)->key() == key)) {
63 block = true;
64 checkAccelerators(automatic: false);
65 block = false;
66 e->accept();
67 return true;
68 }
69 break;
70 case QEvent::ChildAdded:
71 case QEvent::ChildRemoved:
72 // Only care about widgets; this also avoids starting the timer in other
73 // threads
74 if (!static_cast<QChildEvent *>(e)->child()->isWidgetType()) {
75 break;
76 }
77 Q_FALLTHROUGH();
78 // fall-through
79 case QEvent::Resize:
80 case QEvent::LayoutRequest:
81 case QEvent::WindowActivate:
82 case QEvent::WindowDeactivate:
83 if (autoCheck) {
84 autoCheckTimer.setSingleShot(true);
85 autoCheckTimer.start(msec: 20); // 20 ms
86 }
87 return false;
88 case QEvent::Timer:
89 case QEvent::MouseMove:
90 case QEvent::Paint:
91 return false;
92 default:
93 // qCDebug(DEBUG_KXMLGUI) << "KCheckAccelerators::eventFilter " << e->type()
94 // << " " << autoCheck;
95 break;
96 }
97 return false;
98}
99
100void KCheckAccelerators::autoCheckSlot()
101{
102 if (block) {
103 autoCheckTimer.setSingleShot(true);
104 autoCheckTimer.start(msec: 20);
105 return;
106 }
107 block = true;
108 checkAccelerators(automatic: !alwaysShow);
109 block = false;
110}
111
112void KCheckAccelerators::createDialog(QWidget *actWin, bool automatic)
113{
114 if (drklash) {
115 return;
116 }
117
118 drklash = new QDialog(actWin);
119 drklash->setAttribute(Qt::WA_DeleteOnClose);
120 drklash->setObjectName(QStringLiteral("kapp_accel_check_dlg"));
121 drklash->setWindowTitle(i18nc("@title:window", "Dr. Klash' Accelerator Diagnosis"));
122 drklash->resize(w: 500, h: 460);
123 QVBoxLayout *layout = new QVBoxLayout(drklash);
124 drklash_view = new QTextBrowser(drklash);
125 layout->addWidget(drklash_view);
126 QCheckBox *disableAutoCheck = nullptr;
127 if (automatic) {
128 disableAutoCheck = new QCheckBox(i18nc("@option:check", "Disable automatic checking"), drklash);
129 connect(sender: disableAutoCheck, signal: &QCheckBox::toggled, context: this, slot: &KCheckAccelerators::slotDisableCheck);
130 layout->addWidget(disableAutoCheck);
131 }
132 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close, drklash);
133 layout->addWidget(buttonBox);
134 connect(sender: buttonBox, signal: &QDialogButtonBox::rejected, context: drklash, slot: &QDialog::close);
135 if (disableAutoCheck) {
136 disableAutoCheck->setFocus();
137 } else {
138 drklash_view->setFocus();
139 }
140}
141
142void KCheckAccelerators::slotDisableCheck(bool on)
143{
144 autoCheck = !on;
145 if (!on) {
146 autoCheckSlot();
147 }
148}
149
150void KCheckAccelerators::checkAccelerators(bool automatic)
151{
152 QWidget *actWin = qApp->activeWindow();
153 if (!actWin) {
154 return;
155 }
156
157 KAcceleratorManager::manage(widget: actWin);
158 QString a;
159 QString c;
160 QString r;
161 KAcceleratorManager::last_manage(added&: a, changed&: c, removed&: r);
162
163 if (automatic) { // for now we only show dialogs on F12 checks
164 return;
165 }
166
167 if (c.isEmpty() && r.isEmpty() && (automatic || a.isEmpty())) {
168 return;
169 }
170
171 QString s;
172
173 if (!c.isEmpty()) {
174 s += i18n("<h2>Accelerators changed</h2>")
175 + QLatin1String(
176 "<table "
177 "border><tr><th><b>%1</b></th><th><b>%2</b></th></tr>%3</table>")
178 .arg(i18n("Old Text"), i18n("New Text"), args&: c);
179 }
180
181 if (!r.isEmpty()) {
182 s += i18n("<h2>Accelerators removed</h2>") + QLatin1String("<table border><tr><th><b>%1</b></th></tr>%2</table>").arg(i18n("Old Text"), args&: r);
183 }
184
185 if (!a.isEmpty()) {
186 s += i18n("<h2>Accelerators added (just for your info)</h2>")
187 + QLatin1String("<table border><tr><th><b>%1</b></th></tr>%2</table>").arg(i18n("New Text"), args&: a);
188 }
189
190 createDialog(actWin, automatic);
191 drklash_view->setHtml(s);
192 drklash->show();
193 drklash->raise();
194
195 // dlg will be destroyed before returning
196}
197
198void KCheckAccelerators::initiateIfNeeded()
199{
200 static QPointer<KCheckAccelerators> checker;
201 if (checker) {
202 return;
203 }
204
205 KConfigGroup cg(KSharedConfig::openConfig(), QStringLiteral("Development"));
206 QString sKey = cg.readEntry(key: "CheckAccelerators").trimmed();
207 int key = 0;
208 if (!sKey.isEmpty()) {
209 QList<QKeySequence> cuts = QKeySequence::listFromString(str: sKey);
210 if (!cuts.isEmpty()) {
211 key = cuts.first()[0].toCombined();
212 }
213 }
214 const bool autoCheck = cg.readEntry(key: "AutoCheckAccelerators", defaultValue: true);
215 if (key == 0 && !autoCheck) {
216 return;
217 }
218
219 checker = new KCheckAccelerators(qApp, key, autoCheck);
220}
221
222#include "moc_kcheckaccelerators.cpp"
223

source code of kxmlgui/src/kcheckaccelerators.cpp