KGlobalAccel

kglobalaccel.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2001, 2002 Ellis Whitehead <ellis@kde.org>
4 SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
5 SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com>
6 SPDX-FileCopyrightText: 2008 Michael Jansen <kde@michael-jansen.biz>
7
8 SPDX-License-Identifier: LGPL-2.0-or-later
9*/
10
11#include "kglobalaccel.h"
12#include "kglobalaccel_debug.h"
13#include "kglobalaccel_p.h"
14
15#include <memory>
16
17#include <QAction>
18#include <QDBusMessage>
19#include <QDBusMetaType>
20#include <QGuiApplication>
21#include <QMessageBox>
22#include <QPushButton>
23#include <config-kglobalaccel.h>
24
25#if HAVE_X11
26#include <private/qtx11extras_p.h>
27#endif
28
29org::kde::kglobalaccel::Component *KGlobalAccelPrivate::getComponent(const QString &componentUnique, bool remember = false)
30{
31 // Check if we already have this component
32 {
33 auto component = components.value(componentUnique);
34 if (component) {
35 return component;
36 }
37 }
38
39 // Get the path for our component. We have to do that because
40 // componentUnique is probably not a valid dbus object path
41 QDBusReply<QDBusObjectPath> reply = iface()->getComponent(componentUnique);
42 if (!reply.isValid()) {
43 if (reply.error().name() == QLatin1String("org.kde.kglobalaccel.NoSuchComponent")) {
44 // No problem. The component doesn't exists. That's normal
45 return nullptr;
46 }
47
48 // An unknown error.
49 qCDebug(KGLOBALACCEL_LOG) << "Failed to get dbus path for component " << componentUnique << reply.error();
50 return nullptr;
51 }
52
53 // Now get the component
54 org::kde::kglobalaccel::Component *component =
55 new org::kde::kglobalaccel::Component(QStringLiteral("org.kde.kglobalaccel"), reply.value().path(), QDBusConnection::sessionBus(), q);
56
57 // No component no cleaning
58 if (!component->isValid()) {
59 qCDebug(KGLOBALACCEL_LOG) << "Failed to get component" << componentUnique << QDBusConnection::sessionBus().lastError();
60 return nullptr;
61 }
62
63 if (remember) {
64 // Connect to the signals we are interested in.
65 q->connect(component,
66 &org::kde::kglobalaccel::Component::globalShortcutPressed,
67 q,
68 [this](const QString &componentUnique, const QString &shortcutUnique, qlonglong timestamp) {
69 invokeAction(componentUnique, shortcutUnique, timestamp);
70 });
71
72 q->connect(component,
73 &org::kde::kglobalaccel::Component::globalShortcutReleased,
74 q,
75 [this](const QString &componentUnique, const QString &shortcutUnique, qlonglong) {
76 invokeDeactivate(componentUnique, shortcutUnique);
77 });
78
79 components[componentUnique] = component;
80 }
81
82 return component;
83}
84
85namespace
86{
87QString serviceName()
88{
89 return QStringLiteral("org.kde.kglobalaccel");
90}
91}
92
93void KGlobalAccelPrivate::cleanup()
94{
95 qDeleteAll(components);
96 delete m_iface;
97 m_iface = nullptr;
98 delete m_watcher;
99 m_watcher = nullptr;
100}
101
102KGlobalAccelPrivate::KGlobalAccelPrivate(KGlobalAccel *qq)
103 : q(qq)
104{
106 q->connect(m_watcher, &QDBusServiceWatcher::serviceOwnerChanged, q, [this](const QString &serviceName, const QString &oldOwner, const QString &newOwner) {
107 serviceOwnerChanged(serviceName, oldOwner, newOwner);
108 });
109}
110
111org::kde::KGlobalAccel *KGlobalAccelPrivate::iface()
112{
113 if (!m_iface) {
114 m_iface = new org::kde::KGlobalAccel(serviceName(), QStringLiteral("/kglobalaccel"), QDBusConnection::sessionBus());
115 // Make sure kglobalaccel is running. The iface declaration above somehow works anyway.
117 if (bus && !bus->isServiceRegistered(serviceName())) {
118 QDBusReply<void> reply = bus->startService(serviceName());
119 if (!reply.isValid()) {
120 qCritical() << "Couldn't start kglobalaccel from org.kde.kglobalaccel.service:" << reply.error();
121 }
122 }
123
124 q->connect(m_iface, &org::kde::KGlobalAccel::yourShortcutsChanged, q, [this](const QStringList &actionId, const QList<QKeySequence> &newKeys) {
125 shortcutsChanged(actionId, newKeys);
126 });
127 }
128 return m_iface;
129}
130
131KGlobalAccel::KGlobalAccel()
132 : d(new KGlobalAccelPrivate(this))
133{
134 qDBusRegisterMetaType<QList<int>>();
135 qDBusRegisterMetaType<QKeySequence>();
136 qDBusRegisterMetaType<QList<QKeySequence>>();
137 qDBusRegisterMetaType<QList<QStringList>>();
138 qDBusRegisterMetaType<KGlobalShortcutInfo>();
139 qDBusRegisterMetaType<QList<KGlobalShortcutInfo>>();
140 qDBusRegisterMetaType<KGlobalAccel::MatchType>();
141}
142
143KGlobalAccel::~KGlobalAccel()
144{
145 delete d;
146}
147
148// static
149bool KGlobalAccel::cleanComponent(const QString &componentUnique)
150{
151 org::kde::kglobalaccel::Component *component = self()->getComponent(componentUnique);
152 if (!component) {
153 return false;
154 }
155
156 return component->cleanUp();
157}
158
159// static
160bool KGlobalAccel::isComponentActive(const QString &componentUnique)
161{
162 org::kde::kglobalaccel::Component *component = self()->getComponent(componentUnique);
163 if (!component) {
164 return false;
165 }
166
167 return component->isActive();
168}
169
170org::kde::kglobalaccel::Component *KGlobalAccel::getComponent(const QString &componentUnique)
171{
172 return d->getComponent(componentUnique);
173}
174
175class KGlobalAccelSingleton
176{
177public:
178 KGlobalAccelSingleton();
179
180 KGlobalAccel instance;
181};
182
183Q_GLOBAL_STATIC(KGlobalAccelSingleton, s_instance)
184
185KGlobalAccelSingleton::KGlobalAccelSingleton()
186{
187 qAddPostRoutine([]() {
188 s_instance->instance.d->cleanup();
189 });
190}
191
193{
194 return &s_instance()->instance;
195}
196
197bool KGlobalAccelPrivate::doRegister(QAction *action)
198{
199 if (!action || action->objectName().isEmpty() || action->objectName().startsWith(QLatin1String("unnamed-"))) {
200 qWarning() << "Attempt to set global shortcut for action without objectName()."
201 " Read the setGlobalShortcut() documentation.";
202 return false;
203 }
204
205 const bool isRegistered = actions.contains(action);
206 if (isRegistered) {
207 return true;
208 }
209
210 QStringList actionId = makeActionId(action);
211
212 nameToAction.insert(actionId.at(KGlobalAccel::ActionUnique), action);
213 actions.insert(action);
214 iface()->doRegister(actionId);
215
216 QObject::connect(action, &QObject::destroyed, [this, action](QObject *) {
217 if (actions.contains(action) && (actionShortcuts.contains(action) || actionDefaultShortcuts.contains(action))) {
218 remove(action, KGlobalAccelPrivate::SetInactive);
219 }
220 });
221
222 return true;
223}
224
225void KGlobalAccelPrivate::remove(QAction *action, Removal removal)
226{
227 if (!action || action->objectName().isEmpty()) {
228 return;
229 }
230
231 const bool isRegistered = actions.contains(action);
232 if (!isRegistered) {
233 return;
234 }
235
236 QStringList actionId = makeActionId(action);
237
238 nameToAction.remove(actionId.at(KGlobalAccel::ActionUnique), action);
239 actions.remove(action);
240
241 if (removal == UnRegister) {
242 // Complete removal of the shortcut is requested
243 // (forgetGlobalShortcut)
244 unregister(actionId);
245 } else {
246 // If the action is a configurationAction wen only remove it from our
247 // internal registry. That happened above.
248
249 // If we are merely marking a callback as inactive there is nothing for kglobalaccel to do if kglobalaccel is not running
250 // this can happen on shutdown where all apps and kglobalaccel are all torn down at once
251 // For this reason we turn off the autostart flag in the DBus message call
252
253 if (!action->property("isConfigurationAction").toBool()) {
254 // If it's a session shortcut unregister it.
255 if (action->objectName().startsWith(QLatin1String("_k_session:"))) {
256 unregister(actionId);
257 } else {
258 setInactive(actionId);
259 }
260 }
261 }
262
263 actionDefaultShortcuts.remove(action);
264 actionShortcuts.remove(action);
265}
266
267void KGlobalAccelPrivate::unregister(const QStringList &actionId)
268{
269 const auto component = actionId.at(KGlobalAccel::ComponentUnique);
270 const auto action = actionId.at(KGlobalAccel::ActionUnique);
271
272 auto message = QDBusMessage::createMethodCall(iface()->service(), iface()->path(), iface()->interface(), QStringLiteral("unregister"));
273 message.setArguments({component, action});
274 message.setAutoStartService(false);
276}
277
278void KGlobalAccelPrivate::setInactive(const QStringList &actionId)
279{
280 auto message = QDBusMessage::createMethodCall(iface()->service(), iface()->path(), iface()->interface(), QStringLiteral("setInactive"));
281 message.setArguments({actionId});
282 message.setAutoStartService(false);
284}
285
286void KGlobalAccelPrivate::updateGlobalShortcut(/*const would be better*/ QAction *action,
287 ShortcutTypes actionFlags,
289{
290 // No action or no objectname -> Do nothing
291 if (!action || action->objectName().isEmpty()) {
292 return;
293 }
294
295 QStringList actionId = makeActionId(action);
296
297 uint setterFlags = 0;
298 if (globalFlags & NoAutoloading) {
299 setterFlags |= NoAutoloading;
300 }
301
302 if (actionFlags & ActiveShortcut) {
303 const QList<QKeySequence> activeShortcut = actionShortcuts.value(action);
304 bool isConfigurationAction = action->property("isConfigurationAction").toBool();
305 uint activeSetterFlags = setterFlags;
306
307 // setPresent tells kglobalaccel that the shortcut is active
308 if (!isConfigurationAction) {
309 activeSetterFlags |= SetPresent;
310 }
311
312 // Sets the shortcut, returns the active/real keys
313 const auto result = iface()->setShortcutKeys(actionId, activeShortcut, activeSetterFlags);
314
315 // Make sure we get informed about changes in the component by kglobalaccel
316 getComponent(componentUniqueForAction(action), true);
317
318 // Create a shortcut from the result
319 const QList<QKeySequence> scResult(result);
320
321 if (isConfigurationAction && (globalFlags & NoAutoloading)) {
322 // If this is a configuration action and we have set the shortcut,
323 // inform the real owner of the change.
324 // Note that setForeignShortcut will cause a signal to be sent to applications
325 // even if it did not "see" that the shortcut has changed. This is Good because
326 // at the time of comparison (now) the action *already has* the new shortcut.
327 // We called setShortcut(), remember?
328 // Also note that we will see our own signal so we may not need to call
329 // setActiveGlobalShortcutNoEnable - shortcutGotChanged() does it.
330 // In practice it's probably better to get the change propagated here without
331 // DBus delay as we do below.
332 iface()->setForeignShortcutKeys(actionId, result);
333 }
334 if (scResult != activeShortcut) {
335 // If kglobalaccel returned a shortcut that differs from the one we
336 // sent, use that one. There must have been clashes or some other problem.
337 actionShortcuts.insert(action, scResult);
338 Q_EMIT q->globalShortcutChanged(action, scResult.isEmpty() ? QKeySequence() : scResult.first());
339 }
340 }
341
342 if (actionFlags & DefaultShortcut) {
343 const QList<QKeySequence> defaultShortcut = actionDefaultShortcuts.value(action);
344 iface()->setShortcutKeys(actionId, defaultShortcut, setterFlags | IsDefault);
345 }
346}
347
348QStringList KGlobalAccelPrivate::makeActionId(const QAction *action)
349{
350 QStringList ret(componentUniqueForAction(action)); // Component Unique Id ( see actionIdFields )
351 Q_ASSERT(!ret.at(KGlobalAccel::ComponentUnique).isEmpty());
352 Q_ASSERT(!action->objectName().isEmpty());
353 ret.append(action->objectName()); // Action Unique Name
354 ret.append(componentFriendlyForAction(action)); // Component Friendly name
355 const QString actionText = action->text().replace(QLatin1Char('&'), QStringLiteral(""));
356 ret.append(actionText); // Action Friendly Name
357 return ret;
358}
359
360QList<int> KGlobalAccelPrivate::intListFromShortcut(const QList<QKeySequence> &cut)
361{
362 QList<int> ret;
363 for (const QKeySequence &sequence : cut) {
364 ret.append(sequence[0].toCombined());
365 }
366 while (!ret.isEmpty() && ret.last() == 0) {
367 ret.removeLast();
368 }
369 return ret;
370}
371
372QList<QKeySequence> KGlobalAccelPrivate::shortcutFromIntList(const QList<int> &list)
373{
375 ret.reserve(list.size());
376 std::transform(list.begin(), list.end(), std::back_inserter(ret), [](int i) {
377 return QKeySequence(i);
378 });
379 return ret;
380}
381
382QString KGlobalAccelPrivate::componentUniqueForAction(const QAction *action)
383{
384 if (!action->property("componentName").isValid()) {
386 } else {
387 return action->property("componentName").toString();
388 }
389}
390
391QString KGlobalAccelPrivate::componentFriendlyForAction(const QAction *action)
392{
393 QString property = action->property("componentDisplayName").toString();
394 if (!property.isEmpty()) {
395 return property;
396 }
399 }
401}
402
403#if HAVE_X11
404int timestampCompare(unsigned long time1_, unsigned long time2_) // like strcmp()
405{
406 quint32 time1 = time1_;
407 quint32 time2 = time2_;
408 if (time1 == time2) {
409 return 0;
410 }
411 return quint32(time1 - time2) < 0x7fffffffU ? 1 : -1; // time1 > time2 -> 1, handle wrapping
412}
413#endif
414
415QAction *KGlobalAccelPrivate::findAction(const QString &componentUnique, const QString &actionUnique)
416{
417 QAction *action = nullptr;
418 const QList<QAction *> candidates = nameToAction.values(actionUnique);
419 for (QAction *const a : candidates) {
420 if (componentUniqueForAction(a) == componentUnique) {
421 action = a;
422 }
423 }
424
425 // We do not trigger if
426 // - there is no action
427 // - the action is not enabled
428 // - the action is an configuration action
429 if (!action || !action->isEnabled() || action->property("isConfigurationAction").toBool()) {
430 return nullptr;
431 }
432 return action;
433}
434
435void KGlobalAccelPrivate::invokeAction(const QString &componentUnique, const QString &actionUnique, qlonglong timestamp)
436{
437 QAction *action = findAction(componentUnique, actionUnique);
438 if (!action) {
439 return;
440 }
441
442#if HAVE_X11
443 // Update this application's X timestamp if needed.
444 // TODO The 100%-correct solution should probably be handling this action
445 // in the proper place in relation to the X events queue in order to avoid
446 // the possibility of wrong ordering of user events.
447 if (QX11Info::isPlatformX11()) {
448 if (timestampCompare(timestamp, QX11Info::appTime()) > 0) {
449 QX11Info::setAppTime(timestamp);
450 }
451 if (timestampCompare(timestamp, QX11Info::appUserTime()) > 0) {
452 QX11Info::setAppUserTime(timestamp);
453 }
454 }
455#endif
456 action->setProperty("org.kde.kglobalaccel.activationTimestamp", timestamp);
457
458 if (m_lastActivatedAction != action) {
459 Q_EMIT q->globalShortcutActiveChanged(action, true);
460 m_lastActivatedAction = action;
461 }
462 action->trigger();
463}
464
465void KGlobalAccelPrivate::invokeDeactivate(const QString &componentUnique, const QString &actionUnique)
466{
467 QAction *action = findAction(componentUnique, actionUnique);
468 if (!action) {
469 return;
470 }
471
472 m_lastActivatedAction.clear();
473
474 Q_EMIT q->globalShortcutActiveChanged(action, false);
475}
476
477void KGlobalAccelPrivate::shortcutsChanged(const QStringList &actionId, const QList<QKeySequence> &keys)
478{
479 QAction *action = nameToAction.value(actionId.at(KGlobalAccel::ActionUnique));
480 if (!action) {
481 return;
482 }
483
484 actionShortcuts.insert(action, keys);
485 Q_EMIT q->globalShortcutChanged(action, keys.isEmpty() ? QKeySequence() : keys.first());
486}
487
488void KGlobalAccelPrivate::serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
489{
490 Q_UNUSED(oldOwner);
491 if (name == QLatin1String("org.kde.kglobalaccel") && !newOwner.isEmpty()) {
492 // kglobalaccel was restarted
493 qCDebug(KGLOBALACCEL_LOG) << "detected kglobalaccel restarting, re-registering all shortcut keys";
494 reRegisterAll();
495 }
496}
497
498void KGlobalAccelPrivate::reRegisterAll()
499{
500 // We clear all our data, assume that all data on the other side is clear too,
501 // and register each action as if it just was allowed to have global shortcuts.
502 // If the kded side still has the data it doesn't matter because of the
503 // autoloading mechanism. The worst case I can imagine is that an action's
504 // shortcut was changed but the kded side died before it got the message so
505 // autoloading will now assign an old shortcut to the action. Particularly
506 // picky apps might assert or misbehave.
507 const QSet<QAction *> allActions = actions;
508 nameToAction.clear();
509 actions.clear();
510 for (QAction *const action : allActions) {
511 if (doRegister(action)) {
512 updateGlobalShortcut(action, ActiveShortcut, KGlobalAccel::Autoloading);
513 }
514 }
515}
516
518{
519 return self()->d->iface()->globalShortcutsByKey(seq, type);
520}
521
523{
524 return self()->d->iface()->globalShortcutAvailable(seq, comp);
525}
526
527// static
529{
530 if (shortcuts.isEmpty()) {
531 // Usage error. Just say no
532 return false;
533 }
534
535 QString component = shortcuts[0].componentFriendlyName();
536
537 QString message;
538 if (shortcuts.size() == 1) {
539 message = tr("The '%1' key combination is registered by application %2 for action %3.").arg(seq.toString(), component, shortcuts[0].friendlyName());
540 } else {
541 QString actionList;
542 for (const KGlobalShortcutInfo &info : shortcuts) {
543 actionList += tr("In context '%1' for action '%2'\n").arg(info.contextFriendlyName(), info.friendlyName());
544 }
545 message = tr("The '%1' key combination is registered by application %2.\n%3").arg(seq.toString(), component, actionList);
546 }
547
548 QString title = tr("Conflict With Registered Global Shortcut");
549
550 QMessageBox box(parent);
551 box.setWindowTitle(title);
552 box.setText(message);
553 box.addButton(QMessageBox::Ok)->setText(tr("Reassign"));
555
556 return box.exec() == QMessageBox::Ok;
557}
558
559// static
561{
562 // get the shortcut, remove seq, and set the new shortcut
563 const QStringList actionId = self()->d->iface()->actionList(seq);
564 if (actionId.size() < 4) { // not a global shortcut
565 return;
566 }
567 QList<QKeySequence> sc = self()->d->iface()->shortcutKeys(actionId);
568
569 for (int i = 0; i < sc.count(); i++) {
570 if (sc[i] == seq) {
571 sc[i] = QKeySequence();
572 }
573 }
574
575 self()->d->iface()->setForeignShortcutKeys(actionId, sc);
576}
577
578bool checkGarbageKeycode(const QList<QKeySequence> &shortcut)
579{
580 // protect against garbage keycode -1 that Qt sometimes produces for exotic keys;
581 // at the moment (~mid 2008) Multimedia PlayPause is one of those keys.
582 for (const QKeySequence &sequence : shortcut) {
583 for (int i = 0; i < 4; i++) {
584 if (sequence[i].toCombined() == -1) {
585 qWarning() << "Encountered garbage keycode (keycode = -1) in input, not doing anything.";
586 return true;
587 }
588 }
589 }
590 return false;
591}
592
594{
595 if (checkGarbageKeycode(shortcut)) {
596 return false;
597 }
598
599 if (!d->doRegister(action)) {
600 return false;
601 }
602
603 d->actionDefaultShortcuts.insert(action, shortcut);
604 d->updateGlobalShortcut(action, KGlobalAccelPrivate::DefaultShortcut, loadFlag);
605 return true;
606}
607
609{
610 if (checkGarbageKeycode(shortcut)) {
611 return false;
612 }
613
614 if (!d->doRegister(action)) {
615 return false;
616 }
617
618 d->actionShortcuts.insert(action, shortcut);
619 d->updateGlobalShortcut(action, KGlobalAccelPrivate::ActiveShortcut, loadFlag);
620 return true;
621}
622
624{
625 return d->actionDefaultShortcuts.value(action);
626}
627
629{
630 return d->actionShortcuts.value(action);
631}
632
633QList<QKeySequence> KGlobalAccel::globalShortcut(const QString &componentName, const QString &actionId) const
634{
635 // see also d->updateGlobalShortcut(action, KGlobalAccelPrivate::ActiveShortcut, KGlobalAccel::Autoloading);
636
637 // how componentName and actionId map to QAction, e.g:
638 // action->setProperty("componentName", "kwin");
639 // action->setObjectName("Kill Window");
640
641 const QList<QKeySequence> scResult = self()->d->iface()->shortcutKeys({componentName, actionId, QString(), QString()});
642 return scResult;
643}
644
646{
647 d->remove(action, KGlobalAccelPrivate::UnRegister);
648}
649
650bool KGlobalAccel::hasShortcut(const QAction *action) const
651{
652 return d->actionShortcuts.contains(action) || d->actionDefaultShortcuts.contains(action);
653}
654
656{
658 return g->d->setShortcutWithDefault(action, shortcut, Autoloading);
659}
660
665
666bool KGlobalAccelPrivate::setShortcutWithDefault(QAction *action, const QList<QKeySequence> &shortcut, KGlobalAccel::GlobalShortcutLoading loadFlag)
667{
668 if (checkGarbageKeycode(shortcut)) {
669 return false;
670 }
671
672 if (!doRegister(action)) {
673 return false;
674 }
675
676 actionDefaultShortcuts.insert(action, shortcut);
677 actionShortcuts.insert(action, shortcut);
678 updateGlobalShortcut(action, KGlobalAccelPrivate::DefaultShortcut | KGlobalAccelPrivate::ActiveShortcut, loadFlag);
679 return true;
680}
681
683{
684 argument.beginStructure();
685 argument << static_cast<int>(type);
686 argument.endStructure();
687 return argument;
688}
689
691{
692 argument.beginStructure();
693 int arg;
694 argument >> arg;
695 type = static_cast<KGlobalAccel::MatchType>(arg);
696 argument.endStructure();
697 return argument;
698}
699
700#include "moc_kglobalaccel.cpp"
Configurable global shortcut support.
static QList< KGlobalShortcutInfo > globalShortcutsByKey(const QKeySequence &seq, MatchType type=Equal)
Returns a list of global shortcuts registered for the shortcut seq.
bool hasShortcut(const QAction *action) const
Returns true if a shortcut or a default shortcut has been registered for the given action.
static bool promptStealShortcutSystemwide(QWidget *parent, const QList< KGlobalShortcutInfo > &shortcuts, const QKeySequence &seq)
Show a messagebox to inform the user that a global shortcut is already occupied, and ask to take it a...
static void stealShortcutSystemwide(const QKeySequence &seq)
Take away the given shortcut from the named action it belongs to.
static bool isComponentActive(const QString &componentName)
Check if component is active.
MatchType
Keysequence match semantics.
static bool cleanComponent(const QString &componentUnique)
Clean the shortcuts for component componentUnique.
static KGlobalAccel * self()
Returns (and creates if necessary) the singleton instance.
bool setShortcut(QAction *action, const QList< QKeySequence > &shortcut, GlobalShortcutLoading loadFlag=Autoloading)
Assign a global shortcut for the given action.
GlobalShortcutLoading
An enum about global shortcut setter semantics.
@ Autoloading
Look up the action in global settings (using its main component's name and text()) and set the shortc...
void removeAllShortcuts(QAction *action)
Unregister and remove all defined global shortcuts for the given action.
bool setDefaultShortcut(QAction *action, const QList< QKeySequence > &shortcut, GlobalShortcutLoading loadFlag=Autoloading)
Assign a default global shortcut for a given QAction.
static bool isGlobalShortcutAvailable(const QKeySequence &seq, const QString &component=QString())
Check if the shortcut @seq is available for the component.
static bool setGlobalShortcut(QAction *action, const QList< QKeySequence > &shortcut)
Convenient method to set both active and default shortcut.
QList< QKeySequence > shortcut(const QAction *action) const
Get the global shortcut for this action, if one exists.
QList< QKeySequence > globalShortcut(const QString &componentName, const QString &actionId) const
Retrieves the shortcut as defined in global settings by componentName (e.g.
@ ComponentUnique
Components Unique Name (ID)
@ ActionUnique
Actions Unique Name(ID)
QList< QKeySequence > defaultShortcut(const QAction *action) const
Get the global default shortcut for this action, if one exists.
Type type(const QSqlDatabase &db)
KCALENDARCORE_EXPORT QDataStream & operator>>(QDataStream &in, const KCalendarCore::Alarm::Ptr &)
QString path(const QString &relativePath)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
const QList< QKeySequence > & cut()
QDebug operator<<(QDebug dbg, const PerceptualColor::LchaDouble &value)
bool isEnabled() const const
void trigger()
void beginStructure()
void endStructure()
QDBusMessage call(const QDBusMessage &message, QDBus::CallMode mode, int timeout) const const
QDBusConnectionInterface * interface() const const
QDBusError lastError() const const
QDBusConnection sessionBus()
QDBusReply< bool > isServiceRegistered(const QString &serviceName) const const
QDBusReply< void > startService(const QString &name)
QString name() const const
QDBusMessage createMethodCall(const QString &service, const QString &path, const QString &interface, const QString &method)
const QDBusError & error()
bool isValid() const const
QDBusReply::Type value() const const
void serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner)
QString toString(QKeySequence::SequenceFormat format) const const
void append(const T &value)
const T & at(int i) const const
QList::iterator begin()
int count(const T &value) const const
QList::iterator end()
bool isEmpty() const const
T & last()
void removeLast()
void reserve(int alloc)
int size() const const
T value(int i) const const
void addButton(QAbstractButton *button, QMessageBox::ButtonRole role)
virtual int exec() override
void setWindowTitle(const QString &title)
void setText(const QString &text)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void destroyed(QObject *obj)
QObject * parent() const const
QVariant property(const char *name) const const
bool setProperty(const char *name, const QVariant &value)
QString tr(const char *sourceText, const char *disambiguation, int n)
void clear()
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
bool isEmpty() const const
bool isValid() const const
bool toBool() const const
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sun Feb 25 2024 18:41:09 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.