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

KDE's Doxygen guidelines are available online.