KXmlGui

kactioncollection.cpp
1 /*
2  This file is part of the KDE libraries
3  SPDX-FileCopyrightText: 1999 Reginald Stadlbauer <[email protected]>
4  SPDX-FileCopyrightText: 1999 Simon Hausmann <[email protected]>
5  SPDX-FileCopyrightText: 2000 Nicolas Hadacek <[email protected]>
6  SPDX-FileCopyrightText: 2000 Kurt Granroth <[email protected]>
7  SPDX-FileCopyrightText: 2000 Michael Koch <[email protected]>
8  SPDX-FileCopyrightText: 2001 Holger Freyther <[email protected]>
9  SPDX-FileCopyrightText: 2002 Ellis Whitehead <[email protected]>
10  SPDX-FileCopyrightText: 2002 Joseph Wenninger <[email protected]>
11  SPDX-FileCopyrightText: 2005-2007 Hamish Rodda <[email protected]>
12 
13  SPDX-License-Identifier: LGPL-2.0-only
14 */
15 
16 #include "config-xmlgui.h"
17 
18 #include "kactioncollection.h"
19 
20 #include "kactioncategory.h"
21 #include "kxmlguiclient.h"
22 #include "kxmlguifactory.h"
23 #include "debug.h"
24 
25 #include <kauthorized.h>
26 #include <kconfiggroup.h>
27 #if HAVE_GLOBALACCEL
28 # include <kglobalaccel.h>
29 #endif
30 #include <ksharedconfig.h>
31 
32 #include <QDomDocument>
33 #include <QSet>
34 #include <QGuiApplication>
35 #include <QMap>
36 #include <QList>
37 #include <QMetaMethod>
38 
39 #include <stdio.h>
40 
41 class KActionCollectionPrivate
42 {
43 public:
44  KActionCollectionPrivate()
45  : m_parentGUIClient(nullptr),
46  configGroup(QStringLiteral("Shortcuts")),
47  configIsGlobal(false),
48  connectTriggered(false),
49  connectHovered(false),
50  q(nullptr)
51 
52  {
53  }
54 
55  void setComponentForAction(QAction *action)
56  {
57 #if HAVE_GLOBALACCEL
58  bool hasGlobalShortcut = KGlobalAccel::self()->hasShortcut(action);
59 #else
60  bool hasGlobalShortcut = false;
61 #endif
62  if (!hasGlobalShortcut) {
63  action->setProperty("componentName", m_componentName);
64  action->setProperty("componentDisplayName", m_componentDisplayName);
65  }
66  }
67 
68  static QList<KActionCollection *> s_allCollections;
69 
70  void _k_associatedWidgetDestroyed(QObject *obj);
71  void _k_actionDestroyed(QObject *obj);
72 
73  bool writeKXMLGUIConfigFile();
74 
75  QString m_componentName;
76  QString m_componentDisplayName;
77 
80  QAction *unlistAction(QAction *);
81 
82  QMap<QString, QAction *> actionByName;
83  QList<QAction *> actions;
84 
85  const KXMLGUIClient *m_parentGUIClient;
86 
87  QString configGroup;
88  bool configIsGlobal : 1;
89 
90  bool connectTriggered : 1;
91  bool connectHovered : 1;
92 
94 
95  QList<QWidget *> associatedWidgets;
96 };
97 
98 QList<KActionCollection *> KActionCollectionPrivate::s_allCollections;
99 
101  : QObject(parent)
102  , d(new KActionCollectionPrivate)
103 {
104  d->q = this;
105  KActionCollectionPrivate::s_allCollections.append(this);
106 
107  setComponentName(cName);
108 }
109 
111  : QObject(nullptr)
112  , d(new KActionCollectionPrivate)
113 {
114  d->q = this;
115  KActionCollectionPrivate::s_allCollections.append(this);
116 
117  d->m_parentGUIClient = parent;
118  d->m_componentName = parent->componentName();
119 }
120 
122 {
123  KActionCollectionPrivate::s_allCollections.removeAll(this);
124 }
125 
127 {
128  d->actionByName.clear();
129  qDeleteAll(d->actions);
130  d->actions.clear();
131 }
132 
134 {
135  QAction *action = nullptr;
136 
137  if (!name.isEmpty()) {
138  action = d->actionByName.value(name);
139  }
140 
141  return action;
142 }
143 
145 {
146  // ### investigate if any apps use this at all
147  return actions().value(index);
148 }
149 
151 {
152  return d->actions.count();
153 }
154 
156 {
157  return count() == 0;
158 }
159 
161 {
162  if (count() > 0) {
163  // Its component name is part of an action's signature in the context of
164  // global shortcuts and the semantics of changing an existing action's
165  // signature are, as it seems, impossible to get right.
166  // As of now this only matters for global shortcuts. We could
167  // thus relax the requirement and only refuse to change the component data
168  // if we have actions with global shortcuts in this collection.
169  qCWarning(DEBUG_KXMLGUI) << "KActionCollection::setComponentName does not work on a KActionCollection containing actions!" << cName;
170  }
171 
172  if (!cName.isEmpty()) {
173  d->m_componentName = cName;
174  } else {
175  d->m_componentName = QCoreApplication::applicationName();
176  }
177 }
178 
180 {
181  return d->m_componentName;
182 }
183 
185 {
186  d->m_componentDisplayName = displayName;
187 }
188 
190 {
191  if (!d->m_componentDisplayName.isEmpty()) {
192  return d->m_componentDisplayName;
193  }
196  }
198 }
199 
201 {
202  return d->m_parentGUIClient;
203 }
204 
206 {
207  return d->actions;
208 }
209 
211 {
212  QList<QAction *> ret;
213  for (QAction *action : qAsConst(d->actions)) {
214  if (!action->actionGroup()) {
215  ret.append(action);
216  }
217  }
218  return ret;
219 }
220 
222 {
224  for (QAction *action : qAsConst(d->actions)) {
225  if (action->actionGroup()) {
226  set.insert(action->actionGroup());
227  }
228  }
229  return set.values();
230 }
231 
233 {
234  if (!action) {
235  return action;
236  }
237 
238  const QString objectName = action->objectName();
239  QString indexName = name;
240 
241  if (indexName.isEmpty()) {
242  // No name provided. Use the objectName.
243  indexName = objectName;
244 
245  } else {
246 
247  // A name was provided. Check against objectName.
248  if ((!objectName.isEmpty()) && (objectName != indexName)) {
249  // The user specified a new name and the action already has a
250  // different one. The objectName is used for saving shortcut
251  // settings to disk. Both for local and global shortcuts.
252  qCDebug(DEBUG_KXMLGUI) << "Registering action " << objectName << " under new name " << indexName;
253  // If there is a global shortcuts it's a very bad idea.
254 #if HAVE_GLOBALACCEL
255  if (KGlobalAccel::self()->hasShortcut(action)) {
256  // In debug mode assert
257  Q_ASSERT(!KGlobalAccel::self()->hasShortcut(action));
258  // In release mode keep the old name
259  qCCritical(DEBUG_KXMLGUI) << "Changing action name from " << objectName << " to " << indexName << "\nignored because of active global shortcut.";
260  indexName = objectName;
261  }
262 #endif
263  }
264 
265  // Set the new name
266  action->setObjectName(indexName);
267  }
268 
269  // No name provided and the action had no name. Make one up. This will not
270  // work when trying to save shortcuts. Both local and global shortcuts.
271  if (indexName.isEmpty()) {
272  indexName = QString::asprintf("unnamed-%p", (void *)action);
273  action->setObjectName(indexName);
274  }
275 
276  // From now on the objectName has to have a value. Else we cannot safely
277  // remove actions.
278  Q_ASSERT(!action->objectName().isEmpty());
279 
280  // look if we already have THIS action under THIS name ;)
281  if (d->actionByName.value(indexName, nullptr) == action) {
282  // This is not a multi map!
283  Q_ASSERT(d->actionByName.count(indexName) == 1);
284  return action;
285  }
286 
287  if (!KAuthorized::authorizeAction(indexName)) {
288  // Disable this action
289  action->setEnabled(false);
290  action->setVisible(false);
291  action->blockSignals(true);
292  }
293 
294  // Check if we have another action under this name
295  if (QAction *oldAction = d->actionByName.value(indexName)) {
296  takeAction(oldAction);
297  }
298 
299  // Check if we have this action under a different name.
300  // Not using takeAction because we don't want to remove it from categories,
301  // and because it has the new name already.
302  const int oldIndex = d->actions.indexOf(action);
303  if (oldIndex != -1) {
304  d->actionByName.remove(d->actionByName.key(action));
305  d->actions.removeAt(oldIndex);
306  }
307 
308  // Add action to our lists.
309  d->actionByName.insert(indexName, action);
310  d->actions.append(action);
311 
312  for (QWidget *widget : qAsConst(d->associatedWidgets)) {
313  widget->addAction(action);
314  }
315 
316  connect(action, SIGNAL(destroyed(QObject*)), SLOT(_k_actionDestroyed(QObject*)));
317 
318  d->setComponentForAction(action);
319 
320  if (d->connectHovered) {
321  connect(action, &QAction::hovered,
322  this, &KActionCollection::slotActionHovered);
323  }
324 
325  if (d->connectTriggered) {
326  connect(action, &QAction::triggered,
327  this, &KActionCollection::slotActionTriggered);
328  }
329 
330  Q_EMIT inserted(action);
331  Q_EMIT changed();
332  return action;
333 }
334 
336 {
337  for (QAction *action : actions) {
338  addAction(action->objectName(), action);
339  }
340 }
341 
343 {
344  delete takeAction(action);
345 }
346 
348 {
349  if (!d->unlistAction(action)) {
350  return nullptr;
351  }
352 
353  // Remove the action from all widgets
354  for (QWidget *widget : qAsConst(d->associatedWidgets)) {
355  widget->removeAction(action);
356  }
357 
358  action->disconnect(this);
359 
360 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
361  Q_EMIT removed(action); //deprecated
362 #endif
363  Q_EMIT changed();
364  return action;
365 }
366 
367 QAction *KActionCollection::addAction(KStandardAction::StandardAction actionType, const QObject *receiver, const char *member)
368 {
369  QAction *action = KStandardAction::create(actionType, receiver, member, this);
370  return action;
371 }
372 
374  const QObject *receiver, const char *member)
375 {
376  // pass 0 as parent, because if the parent is a KActionCollection KStandardAction::create automatically
377  // adds the action to it under the default name. We would trigger the
378  // warning about renaming the action then.
379  QAction *action = KStandardAction::create(actionType, receiver, member, nullptr);
380  // Give it a parent for gc.
381  action->setParent(this);
382  // Remove the name to get rid of the "rename action" warning above
383  action->setObjectName(name);
384  // And now add it with the desired name.
385  return addAction(name, action);
386 }
387 
388 QAction *KActionCollection::addAction(const QString &name, const QObject *receiver, const char *member)
389 {
390  QAction *a = new QAction(this);
391  if (receiver && member) {
392  connect(a, SIGNAL(triggered(bool)), receiver, member);
393  }
394  return addAction(name, a);
395 }
396 
398 {
399  const QList<QKeySequence> shortcuts = defaultShortcuts(action);
400  return shortcuts.isEmpty() ? QKeySequence() : shortcuts.first();
401 }
402 
404 {
405  return action->property("defaultShortcuts").value<QList<QKeySequence> >();
406 }
407 
409 {
410  setDefaultShortcuts(action, QList<QKeySequence>() << shortcut);
411 }
412 
414 {
415  action->setShortcuts(shortcuts);
416  action->setProperty("defaultShortcuts", QVariant::fromValue(shortcuts));
417 }
418 
420 {
421  // Considered as true by default
422  const QVariant value = action->property("isShortcutConfigurable");
423  return value.isValid() ? value.toBool() : true;
424 }
425 
426 void KActionCollection::setShortcutsConfigurable(QAction *action, bool configurable)
427 {
428  action->setProperty("isShortcutConfigurable", configurable);
429 }
430 
432 {
433  return d->configGroup;
434 }
435 
437 {
438  d->configGroup = group;
439 }
440 
442 {
443  return d->configIsGlobal;
444 }
445 
447 {
448  d->configIsGlobal = global;
449 }
450 
452 {
453 #if HAVE_GLOBALACCEL
454  Q_ASSERT(config);
455  if (!config || !config->exists()) {
456  return;
457  }
458 
459  for (QMap<QString, QAction *>::ConstIterator it = d->actionByName.constBegin();
460  it != d->actionByName.constEnd(); ++it) {
461  QAction *action = it.value();
462  if (!action) {
463  continue;
464  }
465 
466  const QString &actionName = it.key();
467 
468  if (isShortcutsConfigurable(action)) {
469  QString entry = config->readEntry(actionName, QString());
470  if (!entry.isEmpty()) {
472  } else {
474  KGlobalAccel::self()->setShortcut(action, defaultShortcut, KGlobalAccel::NoAutoloading);
475  }
476  }
477  }
478 #else
479  Q_UNUSED(config);
480 #endif
481 }
482 
484 {
486  if (!config) {
487  config = &cg;
488  }
489 
490  if (!config->exists()) {
491  return;
492  }
493 
494  for (QMap<QString, QAction *>::ConstIterator it = d->actionByName.constBegin();
495  it != d->actionByName.constEnd(); ++it) {
496  QAction *action = it.value();
497  if (!action) {
498  continue;
499  }
500 
501  if (isShortcutsConfigurable(action)) {
502  const QString &actionName = it.key();
503  QString entry = config->readEntry(actionName, QString());
504  if (!entry.isEmpty()) {
506  } else {
507  action->setShortcuts(defaultShortcuts(action));
508  }
509  }
510  }
511 
512  //qCDebug(DEBUG_KXMLGUI) << " done";
513 }
514 
515 void KActionCollection::exportGlobalShortcuts(KConfigGroup *config, bool writeAll) const
516 {
517 #if HAVE_GLOBALACCEL
518  Q_ASSERT(config);
519  if (!config) {
520  return;
521  }
522 
523  for (QMap<QString, QAction *>::ConstIterator it = d->actionByName.constBegin();
524  it != d->actionByName.constEnd(); ++it) {
525 
526  QAction *action = it.value();
527  if (!action) {
528  continue;
529  }
530  const QString &actionName = it.key();
531 
532  // If the action name starts with unnamed- spit out a warning. That name
533  // will change at will and will break loading writing
534  if (actionName.startsWith(QLatin1String("unnamed-"))) {
535  qCCritical(DEBUG_KXMLGUI) << "Skipped exporting Shortcut for action without name " << action->text() << "!";
536  continue;
537  }
538 
539  if (isShortcutsConfigurable(action) && KGlobalAccel::self()->hasShortcut(action)) {
540  bool bConfigHasAction = !config->readEntry(actionName, QString()).isEmpty();
541  bool bSameAsDefault = (KGlobalAccel::self()->shortcut(action) == KGlobalAccel::self()->defaultShortcut(action));
542  // If we're using a global config or this setting
543  // differs from the default, then we want to write.
545  if (configIsGlobal()) {
546  flags |= KConfigGroup::Global;
547  }
548  if (writeAll || !bSameAsDefault) {
549  QString s = QKeySequence::listToString(KGlobalAccel::self()->shortcut(action));
550  if (s.isEmpty()) {
551  s = QStringLiteral("none");
552  }
553  qCDebug(DEBUG_KXMLGUI) << "\twriting " << actionName << " = " << s;
554  config->writeEntry(actionName, s, flags);
555  }
556  // Otherwise, this key is the same as default
557  // but exists in config file. Remove it.
558  else if (bConfigHasAction) {
559  qCDebug(DEBUG_KXMLGUI) << "\tremoving " << actionName << " because == default";
560  config->deleteEntry(actionName, flags);
561  }
562  }
563  }
564 
565  config->sync();
566 #else
567  Q_UNUSED(config);
568  Q_UNUSED(writeAll);
569 #endif
570 }
571 
572 bool KActionCollectionPrivate::writeKXMLGUIConfigFile()
573 {
574  const KXMLGUIClient *kxmlguiClient = q->parentGUIClient();
575  // return false if there is no KXMLGUIClient
576  if (!kxmlguiClient || kxmlguiClient->xmlFile().isEmpty()) {
577  return false;
578  }
579 
580  qCDebug(DEBUG_KXMLGUI) << "xmlFile=" << kxmlguiClient->xmlFile();
581 
582  QString attrShortcut = QStringLiteral("shortcut");
583 
584  // Read XML file
585  QString sXml(KXMLGUIFactory::readConfigFile(kxmlguiClient->xmlFile(), q->componentName()));
586  QDomDocument doc;
587  doc.setContent(sXml);
588 
589  // Process XML data
590 
591  // Get hold of ActionProperties tag
593 
594  // now, iterate through our actions
595  for (QMap<QString, QAction *>::ConstIterator it = actionByName.constBegin();
596  it != actionByName.constEnd(); ++it) {
597  QAction *action = it.value();
598  if (!action) {
599  continue;
600  }
601 
602  const QString &actionName = it.key();
603 
604  // If the action name starts with unnamed- spit out a warning and ignore
605  // it. That name will change at will and will break loading writing
606  if (actionName.startsWith(QLatin1String("unnamed-"))) {
607  qCCritical(DEBUG_KXMLGUI) << "Skipped writing shortcut for action " << actionName << "(" << action->text() << ")!";
608  continue;
609  }
610 
611  bool bSameAsDefault = (action->shortcuts() == q->defaultShortcuts(action));
612  qCDebug(DEBUG_KXMLGUI) << "name = " << actionName
613  << " shortcut = " << QKeySequence::listToString(action->shortcuts())
614 #if HAVE_GLOBALACCEL
615  << " globalshortcut = " << QKeySequence::listToString(KGlobalAccel::self()->shortcut(action))
616 #endif
617  << " def = " << QKeySequence::listToString(q->defaultShortcuts(action));
618 
619  // now see if this element already exists
620  // and create it if necessary (unless bSameAsDefault)
621  QDomElement act_elem = KXMLGUIFactory::findActionByName(elem, actionName, !bSameAsDefault);
622  if (act_elem.isNull()) {
623  continue;
624  }
625 
626  if (bSameAsDefault) {
627  act_elem.removeAttribute(attrShortcut);
628  //qCDebug(DEBUG_KXMLGUI) << "act_elem.attributes().count() = " << act_elem.attributes().count();
629  if (act_elem.attributes().count() == 1) {
630  elem.removeChild(act_elem);
631  }
632  } else {
633  act_elem.setAttribute(attrShortcut, QKeySequence::listToString(action->shortcuts()));
634  }
635  }
636 
637  // Write back to XML file
638  KXMLGUIFactory::saveConfigFile(doc, kxmlguiClient->localXMLFile(), q->componentName());
639  // and since we just changed the xml file clear the dom we have in memory
640  // it'll be rebuilt if needed
641  const_cast<KXMLGUIClient*>(kxmlguiClient)->setXMLGUIBuildDocument({});
642  return true;
643 }
644 
645 void KActionCollection::writeSettings(KConfigGroup *config, bool writeAll, QAction *oneAction) const
646 {
647  // If the caller didn't provide a config group we try to save the KXMLGUI
648  // Configuration file. If that succeeds we are finished.
649  if (config == nullptr && d->writeKXMLGUIConfigFile()) {
650  return;
651  }
652 
654  if (!config) {
655  config = &cg;
656  }
657 
658  QList<QAction *> writeActions;
659  if (oneAction) {
660  writeActions.append(oneAction);
661  } else {
662  writeActions = actions();
663  }
664 
665  for (QMap<QString, QAction *>::ConstIterator it = d->actionByName.constBegin();
666  it != d->actionByName.constEnd(); ++it) {
667 
668  QAction *action = it.value();
669  if (!action) {
670  continue;
671  }
672 
673  const QString &actionName = it.key();
674 
675  // If the action name starts with unnamed- spit out a warning and ignore
676  // it. That name will change at will and will break loading writing
677  if (actionName.startsWith(QLatin1String("unnamed-"))) {
678  qCCritical(DEBUG_KXMLGUI) << "Skipped saving Shortcut for action without name " << action->text() << "!";
679  continue;
680  }
681 
682  // Write the shortcut
683  if (isShortcutsConfigurable(action)) {
684  bool bConfigHasAction = !config->readEntry(actionName, QString()).isEmpty();
685  bool bSameAsDefault = (action->shortcuts() == defaultShortcuts(action));
686  // If we're using a global config or this setting
687  // differs from the default, then we want to write.
689 
690  // Honor the configIsGlobal() setting
691  if (configIsGlobal()) {
692  flags |= KConfigGroup::Global;
693  }
694 
695  if (writeAll || !bSameAsDefault) {
696  // We are instructed to write all shortcuts or the shortcut is
697  // not set to its default value. Write it
699  if (s.isEmpty()) {
700  s = QStringLiteral("none");
701  }
702  qCDebug(DEBUG_KXMLGUI) << "\twriting " << actionName << " = " << s;
703  config->writeEntry(actionName, s, flags);
704 
705  } else if (bConfigHasAction) {
706  // Otherwise, this key is the same as default but exists in
707  // config file. Remove it.
708  qCDebug(DEBUG_KXMLGUI) << "\tremoving " << actionName << " because == default";
709  config->deleteEntry(actionName, flags);
710  }
711  }
712  }
713 
714  config->sync();
715 }
716 
717 void KActionCollection::slotActionTriggered()
718 {
719  QAction *action = qobject_cast<QAction *>(sender());
720  if (action) {
721  Q_EMIT actionTriggered(action);
722  }
723 }
724 
725 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
727 {
728  slotActionHovered();
729 }
730 #endif
731 
732 void KActionCollection::slotActionHovered()
733 {
734  QAction *action = qobject_cast<QAction *>(sender());
735  if (action) {
736 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
737  Q_EMIT actionHighlighted(action);
738 #endif
739  Q_EMIT actionHovered(action);
740  }
741 }
742 
743 void KActionCollectionPrivate::_k_actionDestroyed(QObject *obj)
744 {
745  // obj isn't really a QAction anymore. So make sure we don't do fancy stuff
746  // with it.
747  QAction *action = static_cast<QAction *>(obj);
748 
749  if (!unlistAction(action)) {
750  return;
751  }
752 
753  //HACK the object we emit is partly destroyed
754 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
755  Q_EMIT q->removed(action);
756 #endif
757  Q_EMIT q->changed();
758 }
759 
761 {
762  if (d->connectHovered && d->connectTriggered) {
763  return;
764  }
765 
766  if (
767 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
768  signal.methodSignature() == "actionHighlighted(QAction*)" ||
769 #endif
770  signal.methodSignature() == "actionHovered(QAction*)") {
771  if (!d->connectHovered) {
772  d->connectHovered = true;
773  for (QAction *action : qAsConst(d->actions)) {
774  connect(action, &QAction::hovered,
775  this, &KActionCollection::slotActionHovered);
776  }
777  }
778 
779  } else if (signal.methodSignature() == "actionTriggered(QAction*)") {
780  if (!d->connectTriggered) {
781  d->connectTriggered = true;
782  for (QAction *action: qAsConst(d->actions)) {
783  connect(action, &QAction::triggered,
784  this, &KActionCollection::slotActionTriggered);
785  }
786  }
787  }
788 
789  QObject::connectNotify(signal);
790 }
791 
793 {
794  return KActionCollectionPrivate::s_allCollections;
795 }
796 
798 {
799  for (QAction *action : qAsConst(d->actions)) {
800  if (!widget->actions().contains(action)) {
801  widget->addAction(action);
802  }
803  }
804 }
805 
807 {
808  if (!d->associatedWidgets.contains(widget)) {
809  widget->addActions(actions());
810 
811  d->associatedWidgets.append(widget);
812  connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(_k_associatedWidgetDestroyed(QObject*)));
813  }
814 }
815 
817 {
818  for (QAction *action : qAsConst(d->actions)) {
819  widget->removeAction(action);
820  }
821 
822  d->associatedWidgets.removeAll(widget);
823  disconnect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(_k_associatedWidgetDestroyed(QObject*)));
824 }
825 
826 QAction *KActionCollectionPrivate::unlistAction(QAction *action)
827 {
828  // ATTENTION:
829  // This method is called with an QObject formerly known as a QAction
830  // during _k_actionDestroyed(). So don't do fancy stuff here that needs a
831  // real QAction!
832 
833  // Get the index for the action
834  int index = actions.indexOf(action);
835 
836  // Action not found.
837  if (index == -1) {
838  return nullptr;
839  }
840 
841  // An action collection can't have the same action twice.
842  Q_ASSERT(actions.indexOf(action, index + 1) == -1);
843 
844  // Get the actions name
845  const QString name = action->objectName();
846 
847  // Remove the action
848  actionByName.remove(name);
849  actions.removeAt(index);
850 
851  // Remove the action from the categories. Should be only one
852  const QList<KActionCategory *> categories = q->findChildren<KActionCategory *>();
853  for (KActionCategory *category : categories) {
854  category->unlistAction(action);
855  }
856 
857  return action;
858 }
859 
861 {
862  return d->associatedWidgets;
863 }
864 
866 {
867  for (QWidget *widget : qAsConst(d->associatedWidgets)) {
868  for (QAction *action : qAsConst(d->actions)) {
869  widget->removeAction(action);
870  }
871  }
872 
873  d->associatedWidgets.clear();
874 }
875 
876 void KActionCollectionPrivate::_k_associatedWidgetDestroyed(QObject *obj)
877 {
878  associatedWidgets.removeAll(static_cast<QWidget *>(obj));
879 }
880 
881 #include "moc_kactioncollection.cpp"
Categorize actions for KShortcutsEditor.
static QString readConfigFile(const QString &filename, const QString &componentName=QString())
bool sync() override
void removeAssociatedWidget(QWidget *widget)
Remove an association between all actions in this collection and the given widget, i.e.
A container for a set of QAction objects.
void associateWidget(QWidget *widget) const
Associate all actions in this collection to the given widget.
void triggered(bool checked)
bool isShortcutsConfigurable(QAction *action) const
Returns true if the given action&#39;s shortcuts may be configured by the user.
~KActionCollection() override
Destructor.
QActionGroup * actionGroup() const const
QString asprintf(const char *cformat,...)
A KXMLGUIClient can be used with KXMLGUIFactory to create a GUI from actions and an XML document...
Definition: kxmlguiclient.h:39
const QList< QActionGroup * > actionGroups() const
Returns the list of all QActionGroups associated with actions in this action collection.
QList< QKeySequence > listFromString(const QString &str, QKeySequence::SequenceFormat format)
void addAction(QAction *action)
void setConfigGlobal(bool global)
Set whether this action collection&#39;s configuration should be global to KDE ( true )...
QList< QWidget * > associatedWidgets() const
Return a list of all associated widgets.
void addActions(QList< QAction * > actions)
QString listToString(const QList< QKeySequence > &list, QKeySequence::SequenceFormat format)
void setShortcutsConfigurable(QAction *action, bool configurable)
Indicate whether the user may configure the action&#39;s shortcuts.
QByteArray methodSignature() const const
QObject * sender() const const
QAction * create(StandardAction id, const QObject *recvr, Func slot, QObject *parent)
QT_MOC_COMPAT void removed(QAction *action)
Indicates that action was removed from this action collection.
void actionTriggered(QAction *action)
Indicates that action was triggered.
Q_INVOKABLE void setDefaultShortcuts(QAction *action, const QList< QKeySequence > &shortcuts)
Set the default shortcuts for the given action.
const QList< QAction * > actionsWithoutGroup() const
Returns the list of QActions without an QAction::actionGroup() which belong to this action collection...
static const QList< KActionCollection * > & allCollections()
Access the list of all action collections in existence for this app.
QMap::const_iterator constBegin() const const
void setVisible(bool)
void inserted(QAction *action)
Indicates that action was inserted into this action collection.
void removeAt(int i)
QList< QKeySequence > shortcuts() const const
KActionCollection(QObject *parent, const QString &cName=QString())
Constructor.
void setDefaultShortcut(QAction *action, const QKeySequence &shortcut)
Set the default shortcut for the given action.
T value() const const
Q_INVOKABLE QAction * addAction(const QString &name, QAction *action)
Add an action under the given name to the collection.
void writeEntry(const QString &key, const QVariant &value, WriteConfigFlags pFlags=Normal)
virtual QString componentName() const
virtual QString xmlFile() const
This will return the name of the XML file as set by setXMLFile().
bool configIsGlobal() const
Returns whether this action collection&#39;s configuration should be global to KDE ( true )...
QSet::iterator insert(const T &value)
QList< QKeySequence > defaultShortcuts(QAction *action) const
Get the default shortcuts for the given action.
void setComponentName(const QString &componentName)
Set the componentName associated with this action collection.
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
int count() const
Returns the number of actions in the collection.
T value(int i) const const
int indexOf(const T &value, int from) const const
void deleteEntry(const QString &pKey, WriteConfigFlags pFlags=Normal)
void append(const T &value)
void setShortcuts(const QList< QKeySequence > &shortcuts)
QVariant property(const char *name) const const
bool exists() const
bool isEmpty() const const
QString objectName() const const
bool isEmpty() const const
int removeAll(const T &value)
QList< QAction * > actions() const
Returns the list of QActions which belong to this action collection.
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
void changed()
Emitted when an action has been inserted into, or removed from, this action collection.
void connectNotify(const QMetaMethod &signal) override
Overridden to perform connections when someone wants to know whether an action was highlighted or tri...
QList< QKeySequence > shortcut(const QAction *action) const
T & first()
void removeAction(QAction *action)
Removes an action from the collection and deletes it.
QT_MOC_COMPAT void actionHighlighted(QAction *action)
Indicates that action was highlighted (hovered over).
QAction * takeAction(QAction *action)
Removes an action from the collection.
void addActions(const QList< QAction * > &actions)
Adds a list of actions to the collection.
virtual void connectNotify(const QMetaMethod &signal)
bool blockSignals(bool block)
QDomNode removeChild(const QDomNode &oldChild)
void setParent(QObject *parent)
void clear()
Clears the entire action collection, deleting all actions.
bool contains(const T &value) const const
QVariant fromValue(const T &value)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
static bool saveConfigFile(const QDomDocument &doc, const QString &filename, const QString &componentName=QString())
QString componentDisplayName() const
The display name for the associated component.
static KGlobalAccel * self()
void clearAssociatedWidgets()
Clear all associated widgets and remove the actions from those widgets.
void actionHovered(QAction *action)
Indicates that action was hovered.
QObject(QObject *parent)
void exportGlobalShortcuts(KConfigGroup *config, bool writeDefaults=false) const
Export the current configurable global key associations to config.
bool hasShortcut(const QAction *action) const
void hovered()
void writeSettings(KConfigGroup *config=nullptr, bool writeDefaults=false, QAction *oneAction=nullptr) const
Write the current configurable key associations to config.
bool isEmpty() const
Returns whether the action collection is empty or not.
void removeAction(QAction *action)
void addAssociatedWidget(QWidget *widget)
Associate all actions in this collection to the given widget, including any actions added after this ...
bool toBool() const const
bool isValid() const const
QAction * action(int index) const
Return the QAction* at position index in the action collection.
bool setProperty(const char *name, const QVariant &value)
void setComponentDisplayName(const QString &displayName)
Set the component display name associated with this action collection.
QList< QKeySequence > defaultShortcut(const QAction *action) const
const KXMLGUIClient * parentGUIClient() const
The parent KXMLGUIClient, or null if not available.
KCONFIGCORE_EXPORT bool authorizeAction(const QString &action)
QKeySequence defaultShortcut(QAction *action) const
Get the default primary shortcut for the given action.
void setConfigGroup(const QString &group)
Sets group as the KConfig group with which settings will be loaded and saved.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QList< QAction * > actions() const const
T qobject_cast(QObject *object)
QObject * parent() const const
void readSettings(KConfigGroup *config=nullptr)
Read all key associations from config.
T readEntry(const QString &key, const T &aDefault) const
bool setShortcut(QAction *action, const QList< QKeySequence > &shortcut, GlobalShortcutLoading loadFlag=Autoloading)
QString applicationDisplayName()
QString componentName() const
The component name with which this class is associated.
virtual QT_MOC_COMPAT void slotActionHighlighted()
static QDomElement actionPropertiesElement(QDomDocument &doc)
void destroyed(QObject *obj)
void setEnabled(bool)
QString configGroup() const
Returns the KConfig group with which settings will be loaded and saved.
Q_EMITQ_EMIT
static QDomElement findActionByName(QDomElement &elem, const QString &sName, bool create)
QString applicationName()
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)
void importGlobalShortcuts(KConfigGroup *config)
Import from config all configurable global key associations.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Jan 19 2021 22:52:56 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.