KXmlGui

kactioncollection.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 1999 Reginald Stadlbauer <[email protected]>
3  (C) 1999 Simon Hausmann <[email protected]>
4  (C) 2000 Nicolas Hadacek <[email protected]>
5  (C) 2000 Kurt Granroth <[email protected]>
6  (C) 2000 Michael Koch <[email protected]>
7  (C) 2001 Holger Freyther <[email protected]>
8  (C) 2002 Ellis Whitehead <[email protected]>
9  (C) 2002 Joseph Wenninger <[email protected]>
10  (C) 2005-2007 Hamish Rodda <[email protected]>
11 
12  This library is free software; you can redistribute it and/or
13  modify it under the terms of the GNU Library General Public
14  License version 2 as published by the Free Software Foundation.
15 
16  This library is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  Library General Public License for more details.
20 
21  You should have received a copy of the GNU Library General Public License
22  along with this library; see the file COPYING.LIB. If not, write to
23  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  Boston, MA 02110-1301, USA.
25 */
26 
27 #include "config-xmlgui.h"
28 
29 #include "kactioncollection.h"
30 
31 #include "kactioncategory.h"
32 #include "kxmlguiclient.h"
33 #include "kxmlguifactory.h"
34 #include "debug.h"
35 
36 #include <kauthorized.h>
37 #include <kconfiggroup.h>
38 #if HAVE_GLOBALACCEL
39 # include <kglobalaccel.h>
40 #endif
41 #include <ksharedconfig.h>
42 
43 #include <QDomDocument>
44 #include <QSet>
45 #include <QGuiApplication>
46 #include <QMap>
47 #include <QList>
48 #include <QAction>
49 #include <QMetaMethod>
50 
51 #include <stdio.h>
52 
53 class KActionCollectionPrivate
54 {
55 public:
56  KActionCollectionPrivate()
57  : m_parentGUIClient(nullptr),
58  configGroup(QStringLiteral("Shortcuts")),
59  configIsGlobal(false),
60  connectTriggered(false),
61  connectHovered(false),
62  q(nullptr)
63 
64  {
65  }
66 
67  void setComponentForAction(QAction *action)
68  {
69 #if HAVE_GLOBALACCEL
70  bool hasGlobalShortcut = KGlobalAccel::self()->hasShortcut(action);
71 #else
72  bool hasGlobalShortcut = false;
73 #endif
74  if (!hasGlobalShortcut) {
75  action->setProperty("componentName", m_componentName);
76  action->setProperty("componentDisplayName", m_componentDisplayName);
77  }
78  }
79 
80  static QList<KActionCollection *> s_allCollections;
81 
82  void _k_associatedWidgetDestroyed(QObject *obj);
83  void _k_actionDestroyed(QObject *obj);
84 
85  bool writeKXMLGUIConfigFile();
86 
87  QString m_componentName;
88  QString m_componentDisplayName;
89 
92  QAction *unlistAction(QAction *);
93 
94  QMap<QString, QAction *> actionByName;
95  QList<QAction *> actions;
96 
97  const KXMLGUIClient *m_parentGUIClient;
98 
99  QString configGroup;
100  bool configIsGlobal : 1;
101 
102  bool connectTriggered : 1;
103  bool connectHovered : 1;
104 
106 
107  QList<QWidget *> associatedWidgets;
108 };
109 
110 QList<KActionCollection *> KActionCollectionPrivate::s_allCollections;
111 
113  : QObject(parent)
114  , d(new KActionCollectionPrivate)
115 {
116  d->q = this;
117  KActionCollectionPrivate::s_allCollections.append(this);
118 
119  setComponentName(cName);
120 }
121 
123  : QObject(nullptr)
124  , d(new KActionCollectionPrivate)
125 {
126  d->q = this;
127  KActionCollectionPrivate::s_allCollections.append(this);
128 
129  d->m_parentGUIClient = parent;
130  d->m_componentName = parent->componentName();
131 }
132 
134 {
135  KActionCollectionPrivate::s_allCollections.removeAll(this);
136 
137  delete d;
138 }
139 
141 {
142  d->actionByName.clear();
143  qDeleteAll(d->actions);
144  d->actions.clear();
145 }
146 
148 {
149  QAction *action = nullptr;
150 
151  if (!name.isEmpty()) {
152  action = d->actionByName.value(name);
153  }
154 
155  return action;
156 }
157 
159 {
160  // ### investigate if any apps use this at all
161  return actions().value(index);
162 }
163 
165 {
166  return d->actions.count();
167 }
168 
170 {
171  return count() == 0;
172 }
173 
175 {
176  if (count() > 0) {
177  // Its component name is part of an action's signature in the context of
178  // global shortcuts and the semantics of changing an existing action's
179  // signature are, as it seems, impossible to get right.
180  // As of now this only matters for global shortcuts. We could
181  // thus relax the requirement and only refuse to change the component data
182  // if we have actions with global shortcuts in this collection.
183  qCWarning(DEBUG_KXMLGUI) << "KActionCollection::setComponentName does not work on a KActionCollection containing actions!" << cName;
184  }
185 
186  if (!cName.isEmpty()) {
187  d->m_componentName = cName;
188  } else {
189  d->m_componentName = QCoreApplication::applicationName();
190  }
191 }
192 
194 {
195  return d->m_componentName;
196 }
197 
199 {
200  d->m_componentDisplayName = displayName;
201 }
202 
204 {
205  if (!d->m_componentDisplayName.isEmpty()) {
206  return d->m_componentDisplayName;
207  }
210  }
212 }
213 
215 {
216  return d->m_parentGUIClient;
217 }
218 
220 {
221  return d->actions;
222 }
223 
225 {
226  QList<QAction *> ret;
227  for (QAction *action : qAsConst(d->actions)) {
228  if (!action->actionGroup()) {
229  ret.append(action);
230  }
231  }
232  return ret;
233 }
234 
236 {
238  for (QAction *action : qAsConst(d->actions)) {
239  if (action->actionGroup()) {
240  set.insert(action->actionGroup());
241  }
242  }
243  return set.values();
244 }
245 
247 {
248  if (!action) {
249  return action;
250  }
251 
252  const QString objectName = action->objectName();
253  QString indexName = name;
254 
255  if (indexName.isEmpty()) {
256  // No name provided. Use the objectName.
257  indexName = objectName;
258 
259  } else {
260 
261  // A name was provided. Check against objectName.
262  if ((!objectName.isEmpty()) && (objectName != indexName)) {
263  // The user specified a new name and the action already has a
264  // different one. The objectName is used for saving shortcut
265  // settings to disk. Both for local and global shortcuts.
266  qCDebug(DEBUG_KXMLGUI) << "Registering action " << objectName << " under new name " << indexName;
267  // If there is a global shortcuts it's a very bad idea.
268 #if HAVE_GLOBALACCEL
269  if (KGlobalAccel::self()->hasShortcut(action)) {
270  // In debug mode assert
271  Q_ASSERT(!KGlobalAccel::self()->hasShortcut(action));
272  // In release mode keep the old name
273  qCCritical(DEBUG_KXMLGUI) << "Changing action name from " << objectName << " to " << indexName << "\nignored because of active global shortcut.";
274  indexName = objectName;
275  }
276 #endif
277  }
278 
279  // Set the new name
280  action->setObjectName(indexName);
281  }
282 
283  // No name provided and the action had no name. Make one up. This will not
284  // work when trying to save shortcuts. Both local and global shortcuts.
285  if (indexName.isEmpty()) {
286  indexName = QString::asprintf("unnamed-%p", (void *)action);
287  action->setObjectName(indexName);
288  }
289 
290  // From now on the objectName has to have a value. Else we cannot safely
291  // remove actions.
292  Q_ASSERT(!action->objectName().isEmpty());
293 
294  // look if we already have THIS action under THIS name ;)
295  if (d->actionByName.value(indexName, nullptr) == action) {
296  // This is not a multi map!
297  Q_ASSERT(d->actionByName.count(indexName) == 1);
298  return action;
299  }
300 
301  if (!KAuthorized::authorizeAction(indexName)) {
302  // Disable this action
303  action->setEnabled(false);
304  action->setVisible(false);
305  action->blockSignals(true);
306  }
307 
308  // Check if we have another action under this name
309  if (QAction *oldAction = d->actionByName.value(indexName)) {
310  takeAction(oldAction);
311  }
312 
313  // Check if we have this action under a different name.
314  // Not using takeAction because we don't want to remove it from categories,
315  // and because it has the new name already.
316  const int oldIndex = d->actions.indexOf(action);
317  if (oldIndex != -1) {
318  d->actionByName.remove(d->actionByName.key(action));
319  d->actions.removeAt(oldIndex);
320  }
321 
322  // Add action to our lists.
323  d->actionByName.insert(indexName, action);
324  d->actions.append(action);
325 
326  for (QWidget *widget : qAsConst(d->associatedWidgets)) {
327  widget->addAction(action);
328  }
329 
330  connect(action, SIGNAL(destroyed(QObject*)), SLOT(_k_actionDestroyed(QObject*)));
331 
332  d->setComponentForAction(action);
333 
334  if (d->connectHovered) {
335  connect(action, &QAction::hovered,
336  this, &KActionCollection::slotActionHovered);
337  }
338 
339  if (d->connectTriggered) {
340  connect(action, &QAction::triggered,
341  this, &KActionCollection::slotActionTriggered);
342  }
343 
344  emit inserted(action);
345  emit changed();
346  return action;
347 }
348 
350 {
351  for (QAction *action : actions) {
352  addAction(action->objectName(), action);
353  }
354 }
355 
357 {
358  delete takeAction(action);
359 }
360 
362 {
363  if (!d->unlistAction(action)) {
364  return nullptr;
365  }
366 
367  // Remove the action from all widgets
368  for (QWidget *widget : qAsConst(d->associatedWidgets)) {
369  widget->removeAction(action);
370  }
371 
372  action->disconnect(this);
373 
374 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
375  emit removed(action); //deprecated
376 #endif
377  emit changed();
378  return action;
379 }
380 
381 QAction *KActionCollection::addAction(KStandardAction::StandardAction actionType, const QObject *receiver, const char *member)
382 {
383  QAction *action = KStandardAction::create(actionType, receiver, member, this);
384  return action;
385 }
386 
388  const QObject *receiver, const char *member)
389 {
390  // pass 0 as parent, because if the parent is a KActionCollection KStandardAction::create automatically
391  // adds the action to it under the default name. We would trigger the
392  // warning about renaming the action then.
393  QAction *action = KStandardAction::create(actionType, receiver, member, nullptr);
394  // Give it a parent for gc.
395  action->setParent(this);
396  // Remove the name to get rid of the "rename action" warning above
397  action->setObjectName(name);
398  // And now add it with the desired name.
399  return addAction(name, action);
400 }
401 
402 QAction *KActionCollection::addAction(const QString &name, const QObject *receiver, const char *member)
403 {
404  QAction *a = new QAction(this);
405  if (receiver && member) {
406  connect(a, SIGNAL(triggered(bool)), receiver, member);
407  }
408  return addAction(name, a);
409 }
410 
412 {
413  const QList<QKeySequence> shortcuts = defaultShortcuts(action);
414  return shortcuts.isEmpty() ? QKeySequence() : shortcuts.first();
415 }
416 
418 {
419  return action->property("defaultShortcuts").value<QList<QKeySequence> >();
420 }
421 
423 {
424  setDefaultShortcuts(action, QList<QKeySequence>() << shortcut);
425 }
426 
428 {
429  action->setShortcuts(shortcuts);
430  action->setProperty("defaultShortcuts", QVariant::fromValue(shortcuts));
431 }
432 
434 {
435  // Considered as true by default
436  const QVariant value = action->property("isShortcutConfigurable");
437  return value.isValid() ? value.toBool() : true;
438 }
439 
440 void KActionCollection::setShortcutsConfigurable(QAction *action, bool configurable)
441 {
442  action->setProperty("isShortcutConfigurable", configurable);
443 }
444 
446 {
447  return d->configGroup;
448 }
449 
451 {
452  d->configGroup = group;
453 }
454 
456 {
457  return d->configIsGlobal;
458 }
459 
461 {
462  d->configIsGlobal = global;
463 }
464 
466 {
467 #if HAVE_GLOBALACCEL
468  Q_ASSERT(config);
469  if (!config || !config->exists()) {
470  return;
471  }
472 
473  for (QMap<QString, QAction *>::ConstIterator it = d->actionByName.constBegin();
474  it != d->actionByName.constEnd(); ++it) {
475  QAction *action = it.value();
476  if (!action) {
477  continue;
478  }
479 
480  QString actionName = it.key();
481 
482  if (isShortcutsConfigurable(action)) {
483  QString entry = config->readEntry(actionName, QString());
484  if (!entry.isEmpty()) {
486  } else {
488  KGlobalAccel::self()->setShortcut(action, defaultShortcut, KGlobalAccel::NoAutoloading);
489  }
490  }
491  }
492 #else
493  Q_UNUSED(config);
494 #endif
495 }
496 
498 {
500  if (!config) {
501  config = &cg;
502  }
503 
504  if (!config->exists()) {
505  return;
506  }
507 
508  for (QMap<QString, QAction *>::ConstIterator it = d->actionByName.constBegin();
509  it != d->actionByName.constEnd(); ++it) {
510  QAction *action = it.value();
511  if (!action) {
512  continue;
513  }
514 
515  if (isShortcutsConfigurable(action)) {
516  QString actionName = it.key();
517  QString entry = config->readEntry(actionName, QString());
518  if (!entry.isEmpty()) {
520  } else {
521  action->setShortcuts(defaultShortcuts(action));
522  }
523  }
524  }
525 
526  //qCDebug(DEBUG_KXMLGUI) << " done";
527 }
528 
529 void KActionCollection::exportGlobalShortcuts(KConfigGroup *config, bool writeAll) const
530 {
531 #if HAVE_GLOBALACCEL
532  Q_ASSERT(config);
533  if (!config) {
534  return;
535  }
536 
537  for (QMap<QString, QAction *>::ConstIterator it = d->actionByName.constBegin();
538  it != d->actionByName.constEnd(); ++it) {
539 
540  QAction *action = it.value();
541  if (!action) {
542  continue;
543  }
544  QString actionName = it.key();
545 
546  // If the action name starts with unnamed- spit out a warning. That name
547  // will change at will and will break loading writing
548  if (actionName.startsWith(QLatin1String("unnamed-"))) {
549  qCCritical(DEBUG_KXMLGUI) << "Skipped exporting Shortcut for action without name " << action->text() << "!";
550  continue;
551  }
552 
553  if (isShortcutsConfigurable(action) && KGlobalAccel::self()->hasShortcut(action)) {
554  bool bConfigHasAction = !config->readEntry(actionName, QString()).isEmpty();
555  bool bSameAsDefault = (KGlobalAccel::self()->shortcut(action) == KGlobalAccel::self()->defaultShortcut(action));
556  // If we're using a global config or this setting
557  // differs from the default, then we want to write.
559  if (configIsGlobal()) {
560  flags |= KConfigGroup::Global;
561  }
562  if (writeAll || !bSameAsDefault) {
563  QString s = QKeySequence::listToString(KGlobalAccel::self()->shortcut(action));
564  if (s.isEmpty()) {
565  s = QStringLiteral("none");
566  }
567  qCDebug(DEBUG_KXMLGUI) << "\twriting " << actionName << " = " << s;
568  config->writeEntry(actionName, s, flags);
569  }
570  // Otherwise, this key is the same as default
571  // but exists in config file. Remove it.
572  else if (bConfigHasAction) {
573  qCDebug(DEBUG_KXMLGUI) << "\tremoving " << actionName << " because == default";
574  config->deleteEntry(actionName, flags);
575  }
576  }
577  }
578 
579  config->sync();
580 #else
581  Q_UNUSED(config);
582  Q_UNUSED(writeAll);
583 #endif
584 }
585 
586 bool KActionCollectionPrivate::writeKXMLGUIConfigFile()
587 {
588  const KXMLGUIClient *kxmlguiClient = q->parentGUIClient();
589  // return false if there is no KXMLGUIClient
590  if (!kxmlguiClient || kxmlguiClient->xmlFile().isEmpty()) {
591  return false;
592  }
593 
594  qCDebug(DEBUG_KXMLGUI) << "xmlFile=" << kxmlguiClient->xmlFile();
595 
596  QString attrShortcut = QStringLiteral("shortcut");
597 
598  // Read XML file
599  QString sXml(KXMLGUIFactory::readConfigFile(kxmlguiClient->xmlFile(), q->componentName()));
600  QDomDocument doc;
601  doc.setContent(sXml);
602 
603  // Process XML data
604 
605  // Get hold of ActionProperties tag
607 
608  // now, iterate through our actions
609  for (QMap<QString, QAction *>::ConstIterator it = actionByName.constBegin();
610  it != actionByName.constEnd(); ++it) {
611  QAction *action = it.value();
612  if (!action) {
613  continue;
614  }
615 
616  QString actionName = it.key();
617 
618  // If the action name starts with unnamed- spit out a warning and ignore
619  // it. That name will change at will and will break loading writing
620  if (actionName.startsWith(QLatin1String("unnamed-"))) {
621  qCCritical(DEBUG_KXMLGUI) << "Skipped writing shortcut for action " << actionName << "(" << action->text() << ")!";
622  continue;
623  }
624 
625  bool bSameAsDefault = (action->shortcuts() == q->defaultShortcuts(action));
626  qCDebug(DEBUG_KXMLGUI) << "name = " << actionName
627  << " shortcut = " << QKeySequence::listToString(action->shortcuts())
628 #if HAVE_GLOBALACCEL
629  << " globalshortcut = " << QKeySequence::listToString(KGlobalAccel::self()->shortcut(action))
630 #endif
631  << " def = " << QKeySequence::listToString(q->defaultShortcuts(action));
632 
633  // now see if this element already exists
634  // and create it if necessary (unless bSameAsDefault)
635  QDomElement act_elem = KXMLGUIFactory::findActionByName(elem, actionName, !bSameAsDefault);
636  if (act_elem.isNull()) {
637  continue;
638  }
639 
640  if (bSameAsDefault) {
641  act_elem.removeAttribute(attrShortcut);
642  //qCDebug(DEBUG_KXMLGUI) << "act_elem.attributes().count() = " << act_elem.attributes().count();
643  if (act_elem.attributes().count() == 1) {
644  elem.removeChild(act_elem);
645  }
646  } else {
647  act_elem.setAttribute(attrShortcut, QKeySequence::listToString(action->shortcuts()));
648  }
649  }
650 
651  // Write back to XML file
652  KXMLGUIFactory::saveConfigFile(doc, kxmlguiClient->localXMLFile(), q->componentName());
653  return true;
654 }
655 
656 void KActionCollection::writeSettings(KConfigGroup *config, bool writeAll, QAction *oneAction) const
657 {
658  // If the caller didn't provide a config group we try to save the KXMLGUI
659  // Configuration file. If that succeeds we are finished.
660  if (config == nullptr && d->writeKXMLGUIConfigFile()) {
661  return;
662  }
663 
665  if (!config) {
666  config = &cg;
667  }
668 
669  QList<QAction *> writeActions;
670  if (oneAction) {
671  writeActions.append(oneAction);
672  } else {
673  writeActions = actions();
674  }
675 
676  for (QMap<QString, QAction *>::ConstIterator it = d->actionByName.constBegin();
677  it != d->actionByName.constEnd(); ++it) {
678 
679  QAction *action = it.value();
680  if (!action) {
681  continue;
682  }
683 
684  QString actionName = it.key();
685 
686  // If the action name starts with unnamed- spit out a warning and ignore
687  // it. That name will change at will and will break loading writing
688  if (actionName.startsWith(QLatin1String("unnamed-"))) {
689  qCCritical(DEBUG_KXMLGUI) << "Skipped saving Shortcut for action without name " << action->text() << "!";
690  continue;
691  }
692 
693  // Write the shortcut
694  if (isShortcutsConfigurable(action)) {
695  bool bConfigHasAction = !config->readEntry(actionName, QString()).isEmpty();
696  bool bSameAsDefault = (action->shortcuts() == defaultShortcuts(action));
697  // If we're using a global config or this setting
698  // differs from the default, then we want to write.
700 
701  // Honor the configIsGlobal() setting
702  if (configIsGlobal()) {
703  flags |= KConfigGroup::Global;
704  }
705 
706  if (writeAll || !bSameAsDefault) {
707  // We are instructed to write all shortcuts or the shortcut is
708  // not set to its default value. Write it
710  if (s.isEmpty()) {
711  s = QStringLiteral("none");
712  }
713  qCDebug(DEBUG_KXMLGUI) << "\twriting " << actionName << " = " << s;
714  config->writeEntry(actionName, s, flags);
715 
716  } else if (bConfigHasAction) {
717  // Otherwise, this key is the same as default but exists in
718  // config file. Remove it.
719  qCDebug(DEBUG_KXMLGUI) << "\tremoving " << actionName << " because == default";
720  config->deleteEntry(actionName, flags);
721  }
722  }
723  }
724 
725  config->sync();
726 }
727 
728 void KActionCollection::slotActionTriggered()
729 {
730  QAction *action = qobject_cast<QAction *>(sender());
731  if (action) {
732  emit actionTriggered(action);
733  }
734 }
735 
736 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
738 {
739  slotActionHovered();
740 }
741 #endif
742 
743 void KActionCollection::slotActionHovered()
744 {
745  QAction *action = qobject_cast<QAction *>(sender());
746  if (action) {
747 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
748  emit actionHighlighted(action);
749 #endif
750  emit actionHovered(action);
751  }
752 }
753 
754 void KActionCollectionPrivate::_k_actionDestroyed(QObject *obj)
755 {
756  // obj isn't really a QAction anymore. So make sure we don't do fancy stuff
757  // with it.
758  QAction *action = static_cast<QAction *>(obj);
759 
760  if (!unlistAction(action)) {
761  return;
762  }
763 
764  //HACK the object we emit is partly destroyed
765 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
766  emit q->removed(action); //deprecated. remove in KDE5
767 #endif
768  emit q->changed();
769 }
770 
772 {
773  if (d->connectHovered && d->connectTriggered) {
774  return;
775  }
776 
777  if (
778 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
779  signal.methodSignature() == "actionHighlighted(QAction*)" ||
780 #endif
781  signal.methodSignature() == "actionHovered(QAction*)") {
782  if (!d->connectHovered) {
783  d->connectHovered = true;
784  for (QAction *action : qAsConst(d->actions)) {
785  connect(action, &QAction::hovered,
786  this, &KActionCollection::slotActionHovered);
787  }
788  }
789 
790  } else if (signal.methodSignature() == "actionTriggered(QAction*)") {
791  if (!d->connectTriggered) {
792  d->connectTriggered = true;
793  for (QAction *action: qAsConst(d->actions)) {
794  connect(action, &QAction::triggered,
795  this, &KActionCollection::slotActionTriggered);
796  }
797  }
798  }
799 
800  QObject::connectNotify(signal);
801 }
802 
804 {
805  return KActionCollectionPrivate::s_allCollections;
806 }
807 
809 {
810  for (QAction *action : qAsConst(d->actions)) {
811  if (!widget->actions().contains(action)) {
812  widget->addAction(action);
813  }
814  }
815 }
816 
818 {
819  if (!d->associatedWidgets.contains(widget)) {
820  widget->addActions(actions());
821 
822  d->associatedWidgets.append(widget);
823  connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(_k_associatedWidgetDestroyed(QObject*)));
824  }
825 }
826 
828 {
829  for (QAction *action : qAsConst(d->actions)) {
830  widget->removeAction(action);
831  }
832 
833  d->associatedWidgets.removeAll(widget);
834  disconnect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(_k_associatedWidgetDestroyed(QObject*)));
835 }
836 
837 QAction *KActionCollectionPrivate::unlistAction(QAction *action)
838 {
839  // ATTENTION:
840  // This method is called with an QObject formerly known as a QAction
841  // during _k_actionDestroyed(). So don't do fancy stuff here that needs a
842  // real QAction!
843 
844  // Get the index for the action
845  int index = actions.indexOf(action);
846 
847  // Action not found.
848  if (index == -1) {
849  return nullptr;
850  }
851 
852  // An action collection can't have the same action twice.
853  Q_ASSERT(actions.indexOf(action, index + 1) == -1);
854 
855  // Get the actions name
856  const QString name = action->objectName();
857 
858  // Remove the action
859  actionByName.remove(name);
860  actions.removeAt(index);
861 
862  // Remove the action from the categories. Should be only one
863  const QList<KActionCategory *> categories = q->findChildren<KActionCategory *>();
864  for (KActionCategory *category : categories) {
865  category->unlistAction(action);
866  }
867 
868  return action;
869 }
870 
872 {
873  return d->associatedWidgets;
874 }
875 
877 {
878  for (QWidget *widget : qAsConst(d->associatedWidgets)) {
879  for (QAction *action : qAsConst(d->actions)) {
880  widget->removeAction(action);
881  }
882  }
883 
884  d->associatedWidgets.clear();
885 }
886 
887 void KActionCollectionPrivate::_k_associatedWidgetDestroyed(QObject *obj)
888 {
889  associatedWidgets.removeAll(static_cast<QWidget *>(obj));
890 }
891 
892 #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:48
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)
void changed()
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.
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-2020 The KDE developers.
Generated on Tue Aug 4 2020 22:49:43 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.