KXmlGui

kxmlguifactory.cpp
1 /*
2  This file is part of the KDE libraries
3  SPDX-FileCopyrightText: 1999, 2000 Simon Hausmann <[email protected]>
4  SPDX-FileCopyrightText: 2000 Kurt Granroth <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "config-xmlgui.h"
10 
11 #include "kxmlguifactory.h"
12 
13 #include "kxmlguifactory_p.h"
14 #include "kshortcutschemeshelper_p.h"
15 #include "kxmlguiclient.h"
16 #include "kxmlguibuilder.h"
17 #include "kshortcutsdialog.h"
18 #include "kactioncollection.h"
19 #include "debug.h"
20 
21 #include <QAction>
22 #include <QDir>
23 #include <QDomDocument>
24 #include <QFile>
25 #include <QCoreApplication>
26 #include <QTextStream>
27 #include <QWidget>
28 #include <QVariant>
29 #include <QTextCodec>
30 #include <QStandardPaths>
31 
32 #include <ksharedconfig.h>
33 #include <kconfiggroup.h>
34 #if HAVE_GLOBALACCEL
35 # include <kglobalaccel.h>
36 #endif
37 
38 Q_DECLARE_METATYPE(QList<QKeySequence>)
39 
40 using namespace KXMLGUI;
41 
42 class KXMLGUIFactoryPrivate : public BuildState
43 {
44 public:
45  enum ShortcutOption { SetActiveShortcut = 1, SetDefaultShortcut = 2};
46 
47  KXMLGUIFactoryPrivate()
48  {
49  m_rootNode = new ContainerNode(nullptr, QString(), QString());
50  attrName = QStringLiteral("name");
51  }
52  ~KXMLGUIFactoryPrivate()
53  {
54  delete m_rootNode;
55  }
56 
57  void pushState()
58  {
59  m_stateStack.push(*this);
60  }
61 
62  void popState()
63  {
64  BuildState::operator=(m_stateStack.pop());
65  }
66 
67  bool emptyState() const
68  {
69  return m_stateStack.isEmpty();
70  }
71 
72  QWidget *findRecursive(KXMLGUI::ContainerNode *node, bool tag);
73  QList<QWidget *> findRecursive(KXMLGUI::ContainerNode *node, const QString &tagName);
74  void applyActionProperties(const QDomElement &element,
75  ShortcutOption shortcutOption = KXMLGUIFactoryPrivate::SetActiveShortcut);
76  void configureAction(QAction *action, const QDomNamedNodeMap &attributes,
77  ShortcutOption shortcutOption = KXMLGUIFactoryPrivate::SetActiveShortcut);
78  void configureAction(QAction *action, const QDomAttr &attribute,
79  ShortcutOption shortcutOption = KXMLGUIFactoryPrivate::SetActiveShortcut);
80 
81  void applyShortcutScheme(const QString &schemeName, KXMLGUIClient *client, const QList<QAction *> &actions);
82  void refreshActionProperties(KXMLGUIClient *client, const QList<QAction *> &actions, const QDomDocument &doc);
83  void saveDefaultActionProperties(const QList<QAction *> &actions);
84 
85  ContainerNode *m_rootNode;
86 
87  /*
88  * Contains the container which is searched for in ::container .
89  */
90  QString m_containerName;
91 
92  /*
93  * List of all clients
94  */
95  QList<KXMLGUIClient *> m_clients;
96 
97  QString attrName;
98 
99  BuildStateStack m_stateStack;
100 };
101 
102 QString KXMLGUIFactory::readConfigFile(const QString &filename, const QString &_componentName)
103 {
104  QString componentName = _componentName.isEmpty() ? QCoreApplication::applicationName() : _componentName;
105  QString xml_file;
106 
107  if (!QDir::isRelativePath(filename)) {
108  xml_file = filename;
109  } else {
110  // KF >= 5.1 (KXMLGUI_INSTALL_DIR)
111  xml_file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("kxmlgui5/") + componentName + QLatin1Char('/') + filename);
112  if (!QFile::exists(xml_file)) {
113  // KF >= 5.4 (resource file)
114  xml_file = QLatin1String(":/kxmlgui5/") + componentName + QLatin1Char('/') + filename;
115  }
116 
117  bool warn = false;
118  if (!QFile::exists(xml_file)) {
119  // kdelibs4 / KF 5.0 solution
120  xml_file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, componentName + QLatin1Char('/') + filename);
121  warn = true;
122  }
123 
124  if (!QFile::exists(xml_file)) {
125  // kdelibs4 / KF 5.0 solution, and the caller includes the component name
126  // This was broken (lead to component/component/ in kdehome) and unnecessary
127  // (they can specify it with setComponentName instead)
129  warn = true;
130  }
131 
132  if (warn && !xml_file.isEmpty()) {
133  qCWarning(DEBUG_KXMLGUI) << "KXMLGUI file found at deprecated location" << xml_file << "-- please use ${KXMLGUI_INSTALL_DIR} to install these files instead.";
134  }
135  }
136 
137  QFile file(xml_file);
138  if (xml_file.isEmpty() || !file.open(QIODevice::ReadOnly)) {
139  qCCritical(DEBUG_KXMLGUI) << "No such XML file" << filename;
140  return QString();
141  }
142 
143  QByteArray buffer(file.readAll());
144  return QString::fromUtf8(buffer.constData(), buffer.size());
145 }
146 
148  const QString &filename, const QString &_componentName)
149 {
150  QString componentName = _componentName.isEmpty() ? QCoreApplication::applicationName() : _componentName;
151  QString xml_file(filename);
152 
153  if (QDir::isRelativePath(xml_file))
155  QLatin1String("/kxmlgui5/") + componentName + QLatin1Char('/') + filename;
156 
157  QFileInfo fileInfo(xml_file);
158  QDir().mkpath(fileInfo.absolutePath());
159  QFile file(xml_file);
160  if (xml_file.isEmpty() || !file.open(QIODevice::WriteOnly)) {
161  qCCritical(DEBUG_KXMLGUI) << "Could not write to" << filename;
162  return false;
163  }
164 
165  // write out our document
166  QTextStream ts(&file);
167  ts.setCodec(QTextCodec::codecForName("UTF-8"));
168  ts << doc;
169 
170  file.close();
171  return true;
172 }
173 
175  : QObject(parent), d(new KXMLGUIFactoryPrivate)
176 {
177  d->builder = builder;
178  d->guiClient = nullptr;
179  if (d->builder) {
180  d->builderContainerTags = d->builder->containerTags();
181  d->builderCustomTags = d->builder->customTags();
182  }
183 }
184 
186 {
187  for (KXMLGUIClient *client : qAsConst(d->m_clients)) {
188  client->setFactory(nullptr);
189  }
190  delete d;
191 }
192 
194 {
195  //qCDebug(DEBUG_KXMLGUI) << client;
196  if (client->factory()) {
197  if (client->factory() == this) {
198  return;
199  } else {
200  client->factory()->removeClient(client); //just in case someone does stupid things ;-)
201  }
202  }
203 
204  if (d->emptyState()) {
205  emit makingChanges(true);
206  }
207  d->pushState();
208 
209 // QTime dt; dt.start();
210 
211  d->guiClient = client;
212 
213  // add this client to our client list
214  if (!d->m_clients.contains(client)) {
215  d->m_clients.append(client);
216  }
217  //else
218  //qCDebug(DEBUG_KXMLGUI) << "XMLGUI client already added " << client;
219 
220  // Tell the client that plugging in is process and
221  // let it know what builder widget its mainwindow shortcuts
222  // should be attached to.
223  client->beginXMLPlug(d->builder->widget());
224 
225  // try to use the build document for building the client's GUI, as the build document
226  // contains the correct container state information (like toolbar positions, sizes, etc.) .
227  // if there is non available, then use the "real" document.
228  QDomDocument doc = client->xmlguiBuildDocument();
229  if (doc.documentElement().isNull()) {
230  doc = client->domDocument();
231  }
232 
233  QDomElement docElement = doc.documentElement();
234 
235  d->m_rootNode->index = -1;
236 
237  // cache some variables
238 
239  d->clientName = docElement.attribute(d->attrName);
240  d->clientBuilder = client->clientBuilder();
241 
242  if (d->clientBuilder) {
243  d->clientBuilderContainerTags = d->clientBuilder->containerTags();
244  d->clientBuilderCustomTags = d->clientBuilder->customTags();
245  } else {
246  d->clientBuilderContainerTags.clear();
247  d->clientBuilderCustomTags.clear();
248  }
249 
250  // load shortcut schemes, user-defined shortcuts and other action properties
251  d->saveDefaultActionProperties(client->actionCollection()->actions());
252  if (!doc.isNull()) {
253  d->refreshActionProperties(client, client->actionCollection()->actions(), doc);
254  }
255 
256  BuildHelper(*d, d->m_rootNode).build(docElement);
257 
258  // let the client know that we built its GUI.
259  client->setFactory(this);
260 
261  // call the finalizeGUI method, to fix up the positions of toolbars for example.
262  // Note: the client argument is ignored
263  d->builder->finalizeGUI(d->guiClient);
264 
265  // reset some variables, for safety
266  d->BuildState::reset();
267 
268  client->endXMLPlug();
269 
270  d->popState();
271 
272  emit clientAdded(client);
273 
274  // build child clients
275  const auto children = client->childClients();
276  for (KXMLGUIClient *child : children) {
277  addClient(child);
278  }
279 
280  if (d->emptyState()) {
281  emit makingChanges(false);
282  }
283  /*
284  QString unaddedActions;
285  Q_FOREACH (KActionCollection* ac, KActionCollection::allCollections())
286  Q_FOREACH (QAction* action, ac->actions())
287  if (action->associatedWidgets().isEmpty())
288  unaddedActions += action->objectName() + ' ';
289 
290  if (!unaddedActions.isEmpty())
291  qCWarning(DEBUG_KXMLGUI) << "The following actions are not plugged into the gui (shortcuts will not work): " << unaddedActions;
292  */
293 
294 // qCDebug(DEBUG_KXMLGUI) << "addClient took " << dt.elapsed();
295 }
296 
298 {
299  for (KXMLGUIClient *client : qAsConst(d->m_clients)) {
300  d->guiClient = client;
301  QDomDocument doc = client->xmlguiBuildDocument();
302  if (doc.documentElement().isNull()) {
303  client->reloadXML();
304  doc = client->domDocument();
305  }
306  d->refreshActionProperties(client, client->actionCollection()->actions(), doc);
307  }
308  d->guiClient = nullptr;
309 }
310 
311 static QString currentShortcutScheme()
312 {
313  const KConfigGroup cg = KSharedConfig::openConfig()->group("Shortcut Schemes");
314  return cg.readEntry("Current Scheme", "Default");
315 }
316 
317 // Find the right ActionProperties element, otherwise return null element
318 static QDomElement findActionPropertiesElement(const QDomDocument &doc)
319 {
320  const QLatin1String tagActionProp("ActionProperties");
321  const QString schemeName = currentShortcutScheme();
323  for (; !e.isNull(); e = e.nextSiblingElement()) {
324  if (QString::compare(e.tagName(), tagActionProp, Qt::CaseInsensitive) == 0
325  && (e.attribute(QStringLiteral("scheme"), QStringLiteral("Default")) == schemeName)) {
326  return e;
327  }
328  }
329  return QDomElement();
330 }
331 
332 void KXMLGUIFactoryPrivate::refreshActionProperties(KXMLGUIClient *client, const QList<QAction *> &actions, const QDomDocument &doc)
333 {
334  // try to find and apply shortcuts schemes
335  const QString schemeName = KShortcutSchemesHelper::currentShortcutSchemeName();
336  //qCDebug(DEBUG_KXMLGUI) << client->componentName() << ": applying shortcut scheme" << schemeName;
337 
338  if (schemeName != QLatin1String("Default")) {
339  applyShortcutScheme(schemeName, client, actions);
340  } else {
341  // apply saved default shortcuts
342  for (QAction *action : actions) {
343  QVariant savedDefaultShortcut = action->property("_k_DefaultShortcut");
344  if (savedDefaultShortcut.isValid()) {
345  QList<QKeySequence> shortcut = savedDefaultShortcut.value<QList<QKeySequence> >();
346  action->setShortcuts(shortcut);
347  action->setProperty("defaultShortcuts", QVariant::fromValue(shortcut));
348  //qCDebug(DEBUG_KXMLGUI) << "scheme said" << action->shortcut().toString() << "for action" << action->objectName();
349  } else {
350  action->setShortcuts(QList<QKeySequence>());
351  }
352  }
353  }
354 
355  // try to find and apply user-defined shortcuts
356  const QDomElement actionPropElement = findActionPropertiesElement(doc);
357  if (!actionPropElement.isNull()) {
358  applyActionProperties(actionPropElement);
359  }
360 }
361 
362 void KXMLGUIFactoryPrivate::saveDefaultActionProperties(const QList<QAction *> &actions)
363 {
364  // This method is called every time the user activated a new
365  // kxmlguiclient. We only want to execute the following code only once in
366  // the lifetime of an action.
367  for (QAction *action : actions) {
368  // Skip nullptr actions or those we have seen already.
369  if (!action || action->property("_k_DefaultShortcut").isValid()) {
370  continue;
371  }
372 
373  // Check if the default shortcut is set
374  QList<QKeySequence> defaultShortcut = action->property("defaultShortcuts").value<QList<QKeySequence> >();
375  QList<QKeySequence> activeShortcut = action->shortcuts();
376  //qCDebug(DEBUG_KXMLGUI) << action->objectName() << "default=" << defaultShortcut.toString() << "active=" << activeShortcut.toString();
377 
378  // Check if we have an empty default shortcut and an non empty
379  // custom shortcut. Print out a warning and correct the mistake.
380  if ((!activeShortcut.isEmpty()) && defaultShortcut.isEmpty()) {
381  qCCritical(DEBUG_KXMLGUI) << "Shortcut for action " << action->objectName() << action->text() << "set with QAction::setShortcut()! Use KActionCollection::setDefaultShortcut(s) instead.";
382  action->setProperty("_k_DefaultShortcut", QVariant::fromValue(activeShortcut));
383  } else {
384  action->setProperty("_k_DefaultShortcut", QVariant::fromValue(defaultShortcut));
385  }
386  }
387 }
388 
389 void KXMLGUIFactory::changeShortcutScheme(const QString &scheme)
390 {
391  qCDebug(DEBUG_KXMLGUI) << "Changing shortcut scheme to" << scheme;
392  KConfigGroup cg = KSharedConfig::openConfig()->group("Shortcut Schemes");
393  cg.writeEntry("Current Scheme", scheme);
394 
396 }
397 
398 void KXMLGUIFactory::forgetClient(KXMLGUIClient *client)
399 {
400  d->m_clients.removeAll(client);
401 }
402 
404 {
405  //qCDebug(DEBUG_KXMLGUI) << client;
406 
407  // don't try to remove the client's GUI if we didn't build it
408  if (!client || client->factory() != this) {
409  return;
410  }
411 
412  if (d->emptyState()) {
413  emit makingChanges(true);
414  }
415 
416  // remove this client from our client list
417  d->m_clients.removeAll(client);
418 
419  // remove child clients first (create a copy of the list just in case the
420  // original list is modified directly or indirectly in removeClient())
421  const QList<KXMLGUIClient *> childClients(client->childClients());
422  for (KXMLGUIClient *child : childClients) {
423  removeClient(child);
424  }
425 
426  //qCDebug(DEBUG_KXMLGUI) << "calling removeRecursive";
427 
428  d->pushState();
429 
430  // cache some variables
431 
432  d->guiClient = client;
433  d->clientName = client->domDocument().documentElement().attribute(d->attrName);
434  d->clientBuilder = client->clientBuilder();
435 
436  client->setFactory(nullptr);
437 
438  // if we don't have a build document for that client, yet, then create one by
439  // cloning the original document, so that saving container information in the
440  // DOM tree does not touch the original document.
441  QDomDocument doc = client->xmlguiBuildDocument();
442  if (doc.documentElement().isNull()) {
443  doc = client->domDocument().cloneNode(true).toDocument();
444  client->setXMLGUIBuildDocument(doc);
445  }
446 
447  d->m_rootNode->destruct(doc.documentElement(), *d);
448 
449  // reset some variables
450  d->BuildState::reset();
451 
452  // This will destruct the KAccel object built around the given widget.
453  client->prepareXMLUnplug(d->builder->widget());
454 
455  d->popState();
456 
457  if (d->emptyState()) {
458  emit makingChanges(false);
459  }
460 
461  emit clientRemoved(client);
462 }
463 
465 {
466  return d->m_clients;
467 }
468 
470  bool useTagName)
471 {
472  d->pushState();
473  d->m_containerName = containerName;
474  d->guiClient = client;
475 
476  QWidget *result = d->findRecursive(d->m_rootNode, useTagName);
477 
478  d->guiClient = nullptr;
479  d->m_containerName.clear();
480 
481  d->popState();
482 
483  return result;
484 }
485 
486 QList<QWidget *> KXMLGUIFactory::containers(const QString &tagName)
487 {
488  return d->findRecursive(d->m_rootNode, tagName);
489 }
490 
492 {
493  d->m_rootNode->reset();
494 
495  d->m_rootNode->clearChildren();
496 }
497 
498 void KXMLGUIFactory::resetContainer(const QString &containerName, bool useTagName)
499 {
500  if (containerName.isEmpty()) {
501  return;
502  }
503 
504  ContainerNode *container = d->m_rootNode->findContainer(containerName, useTagName);
505  if (container && container->parent) {
506  container->parent->removeChild(container);
507  }
508 }
509 
510 QWidget *KXMLGUIFactoryPrivate::findRecursive(KXMLGUI::ContainerNode *node, bool tag)
511 {
512  if (((!tag && node->name == m_containerName) ||
513  (tag && node->tagName == m_containerName)) &&
514  (!guiClient || node->client == guiClient)) {
515  return node->container;
516  }
517 
518  for (ContainerNode *child : qAsConst(node->children)) {
519  QWidget *cont = findRecursive(child, tag);
520  if (cont) {
521  return cont;
522  }
523  }
524 
525  return nullptr;
526 }
527 
528 // Case insensitive equality without calling toLower which allocates a new string
529 static inline bool equals(const QString &str1, const char *str2)
530 {
531  return str1.compare(QLatin1String(str2), Qt::CaseInsensitive) == 0;
532 }
533 static inline bool equals(const QString &str1, const QString &str2)
534 {
535  return str1.compare(str2, Qt::CaseInsensitive) == 0;
536 }
537 
538 QList<QWidget *> KXMLGUIFactoryPrivate::findRecursive(KXMLGUI::ContainerNode *node,
539  const QString &tagName)
540 {
541  QList<QWidget *> res;
542 
543  if (equals(node->tagName, tagName)) {
544  res.append(node->container);
545  }
546 
547  for (KXMLGUI::ContainerNode *child : qAsConst(node->children)) {
548  res << findRecursive(child, tagName);
549  }
550 
551  return res;
552 }
553 
554 void KXMLGUIFactory::plugActionList(KXMLGUIClient *client, const QString &name,
555  const QList<QAction *> &actionList)
556 {
557  d->pushState();
558  d->guiClient = client;
559  d->actionListName = name;
560  d->actionList = actionList;
561  d->clientName = client->domDocument().documentElement().attribute(d->attrName);
562 
563  d->m_rootNode->plugActionList(*d);
564 
565  // Load shortcuts for these new actions
566  d->saveDefaultActionProperties(actionList);
567  d->refreshActionProperties(client, actionList, client->domDocument());
568 
569  d->BuildState::reset();
570  d->popState();
571 }
572 
573 void KXMLGUIFactory::unplugActionList(KXMLGUIClient *client, const QString &name)
574 {
575  d->pushState();
576  d->guiClient = client;
577  d->actionListName = name;
578  d->clientName = client->domDocument().documentElement().attribute(d->attrName);
579 
580  d->m_rootNode->unplugActionList(*d);
581 
582  d->BuildState::reset();
583  d->popState();
584 }
585 
586 void KXMLGUIFactoryPrivate::applyActionProperties(const QDomElement &actionPropElement,
587  ShortcutOption shortcutOption)
588 {
589  for (QDomElement e = actionPropElement.firstChildElement();
590  !e.isNull(); e = e.nextSiblingElement()) {
591  if (!equals(e.tagName(), "action")) {
592  continue;
593  }
594 
595  QAction *action = guiClient->action(e);
596  if (!action) {
597  continue;
598  }
599 
600  configureAction(action, e.attributes(), shortcutOption);
601  }
602 }
603 
604 void KXMLGUIFactoryPrivate::configureAction(QAction *action, const QDomNamedNodeMap &attributes,
605  ShortcutOption shortcutOption)
606 {
607  for (int i = 0; i < attributes.length(); i++) {
608  QDomAttr attr = attributes.item(i).toAttr();
609  if (attr.isNull()) {
610  continue;
611  }
612 
613  configureAction(action, attr, shortcutOption);
614  }
615 }
616 
617 void KXMLGUIFactoryPrivate::configureAction(QAction *action, const QDomAttr &attribute,
618  ShortcutOption shortcutOption)
619 {
620  QString attrName = attribute.name();
621  // If the attribute is a deprecated "accel", change to "shortcut".
622  if (equals(attrName, "accel")) {
623  attrName = QStringLiteral("shortcut");
624  }
625 
626  // No need to re-set name, particularly since it's "objectName" in Qt4
627  if (equals(attrName, "name")) {
628  return;
629  }
630 
631  if (equals(attrName, "icon")) {
632  action->setIcon(QIcon::fromTheme(attribute.value()));
633  return;
634  }
635 
636  QVariant propertyValue;
637 
638  QVariant::Type propertyType = action->property(attrName.toLatin1().constData()).type();
639  bool isShortcut = (propertyType == QVariant::KeySequence);
640 
641  if (propertyType == QVariant::Int) {
642  propertyValue = QVariant(attribute.value().toInt());
643  } else if (propertyType == QVariant::UInt) {
644  propertyValue = QVariant(attribute.value().toUInt());
645  } else if (isShortcut) {
646  // Setting the shortcut by property also sets the default shortcut (which is incorrect), so we have to do it directly
647  if (attrName == QLatin1String("globalShortcut")) {
648 #if HAVE_GLOBALACCEL
650 #endif
651  } else {
652  action->setShortcuts(QKeySequence::listFromString(attribute.value()));
653  }
654  if (shortcutOption & KXMLGUIFactoryPrivate::SetDefaultShortcut) {
655  action->setProperty("defaultShortcuts", QVariant::fromValue(QKeySequence::listFromString(attribute.value())));
656  }
657  } else {
658  propertyValue = QVariant(attribute.value());
659  }
660  if (!isShortcut && !action->setProperty(attrName.toLatin1().constData(), propertyValue)) {
661  qCWarning(DEBUG_KXMLGUI) << "Error: Unknown action property " << attrName << " will be ignored!";
662  }
663 }
664 
665 void KXMLGUIFactoryPrivate::applyShortcutScheme(const QString &schemeName, KXMLGUIClient *client, const QList<QAction *> &actions)
666 {
667  //First clear all existing shortcuts
668  for (QAction *action : actions) {
670  // We clear the default shortcut as well because the shortcut scheme will set its own defaults
671  action->setProperty("defaultShortcuts", QVariant::fromValue(QList<QKeySequence>()));
672  }
673 
674  // Find the document for the shortcut scheme using the current application path.
675  // This allows to install a single XML file for a shortcut scheme for kdevelop
676  // rather than 10.
677  // Also look for the current xmlguiclient path.
678  // Per component xml files make sense for making kmail shortcuts available in kontact.
679  QString schemeFileName = KShortcutSchemesHelper::shortcutSchemeFileName(client->componentName(), schemeName);
680  if (schemeFileName.isEmpty()) {
681  schemeFileName = KShortcutSchemesHelper::applicationShortcutSchemeFileName(schemeName);
682  }
683  if (schemeFileName.isEmpty()) {
684  qCWarning(DEBUG_KXMLGUI) << client->componentName() << ": shortcut scheme file not found:" << schemeName << "after trying" << QCoreApplication::applicationName() << "and" << client->componentName();
685  return;
686  }
687 
688  QDomDocument scheme;
689  QFile schemeFile(schemeFileName);
690  if (schemeFile.open(QIODevice::ReadOnly)) {
691  qCDebug(DEBUG_KXMLGUI) << client->componentName() << ": found shortcut scheme XML" << schemeFileName;
692  scheme.setContent(&schemeFile);
693  }
694 
695  if (scheme.isNull()) {
696  return;
697  }
698 
699  QDomElement docElement = scheme.documentElement();
700  QDomElement actionPropElement = docElement.namedItem(QStringLiteral("ActionProperties")).toElement();
701 
702  //Check if we really have the shortcut configuration here
703  if (!actionPropElement.isNull()) {
704  //qCDebug(DEBUG_KXMLGUI) << "Applying shortcut scheme for XMLGUI client" << client->componentName();
705 
706  //Apply all shortcuts we have
707  applyActionProperties(actionPropElement, KXMLGUIFactoryPrivate::SetDefaultShortcut);
708  //} else {
709  //qCDebug(DEBUG_KXMLGUI) << "Invalid shortcut scheme file";
710  }
711 }
712 
713 int KXMLGUIFactory::configureShortcuts(bool letterCutsOk, bool bSaveSettings)
714 {
717  qobject_cast<QWidget *>(parent()));
718  for (KXMLGUIClient *client : qAsConst(d->m_clients)) {
719  if (client) {
720  qCDebug(DEBUG_KXMLGUI) << "Adding collection from client" << client->componentName() << "with" << client->actionCollection()->count() << "actions";
721  dlg.addCollection(client->actionCollection());
722  }
723  }
724  return dlg.configure(bSaveSettings);
725 }
726 
727 // Find or create
729 {
730  // first, lets see if we have existing properties
731  QDomElement elem = findActionPropertiesElement(doc);
732 
733  // if there was none, create one
734  if (elem.isNull()) {
735  elem = doc.createElement(QStringLiteral("ActionProperties"));
736  elem.setAttribute(QStringLiteral("scheme"), currentShortcutScheme());
737  doc.documentElement().appendChild(elem);
738  }
739  return elem;
740 }
741 
743 {
744  const QLatin1String attrName("name");
745  for (QDomNode it = elem.firstChild(); !it.isNull(); it = it.nextSibling()) {
746  QDomElement e = it.toElement();
747  if (e.attribute(attrName) == sName) {
748  return e;
749  }
750  }
751 
752  if (create) {
753  QDomElement act_elem = elem.ownerDocument().createElement(QStringLiteral("Action"));
754  act_elem.setAttribute(attrName, sName);
755  elem.appendChild(act_elem);
756  return act_elem;
757  }
758  return QDomElement();
759 }
760 
void setCodec(QTextCodec *codec)
static QString readConfigFile(const QString &filename, const QString &componentName=QString())
QString writableLocation(QStandardPaths::StandardLocation type)
virtual KActionCollection * actionCollection() const
Retrieves the entire action collection for the GUI client.
A KXMLGUIClient can be used with KXMLGUIFactory to create a GUI from actions and an XML document...
Definition: kxmlguiclient.h:38
QString name() const const
QDomNode appendChild(const QDomNode &newChild)
QList< QKeySequence > listFromString(const QString &str, QKeySequence::SequenceFormat format)
QString attribute(const QString &name, const QString &defValue) const const
void removeClient(KXMLGUIClient *client)
Removes the GUI described by the client, by unplugging all provided actions and removing all owned co...
void addClient(KXMLGUIClient *client)
Creates the GUI described by the QDomDocument of the client, using the client&#39;s actions, and merges it with the previously created GUI.
void setIcon(const QIcon &icon)
const QObjectList & children() const const
QDomElement nextSiblingElement(const QString &tagName) const const
T value() const const
void writeEntry(const QString &key, const QVariant &value, WriteConfigFlags pFlags=Normal)
KXMLGUIFactory * factory() const
Retrieves a pointer to the KXMLGUIFactory this client is associated with (will return nullptr if the ...
QDomElement documentElement() const const
virtual QString componentName() const
bool exists() const const
void reset()
Use this method to free all memory allocated by the KXMLGUIFactory.
int count() const
Returns the number of actions in the collection.
T value(int i) const const
void setFactory(KXMLGUIFactory *factory)
This method is called by the KXMLGUIFactory as soon as the client is added to the KXMLGUIFactory&#39;s GU...
QDomElement toElement() const const
QList< KXMLGUIClient * > childClients()
Retrieves a list of all child clients.
void append(const T &value)
void setShortcuts(const QList< QKeySequence > &shortcuts)
QString fromUtf8(const char *str, int size)
QVariant property(const char *name) const const
QDomDocument ownerDocument() const const
QDomDocument xmlguiBuildDocument() const
Implements the creation of the GUI (menubar, menus and toolbars) as requested by the GUI factory...
void setAttribute(const QString &name, const QString &value)
CaseInsensitive
int toInt(bool *ok, int base) const const
bool isEmpty() const const
bool isEmpty() const const
QList< QAction * > actions() const
Returns the list of QActions which belong to this action collection.
const char * constData() const const
QByteArray readAll()
void makingChanges(bool)
Emitted when the factory is currently making changes to the GUI, i.e.
void resetContainer(const QString &containerName, bool useTagName=false)
Use this method to free all memory allocated by the KXMLGUIFactory for a specific container...
virtual bool open(QIODevice::OpenMode mode) override
void addCollection(KActionCollection *, const QString &title=QString())
Add all actions of the collection to the ones displayed and configured by the dialog.
QDomNode namedItem(const QString &name) const const
bool isRelativePath(const QString &path)
QVariant fromValue(const T &value)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
QString value() const const
bool isNull() const const
Letter shortcuts are allowed.
static bool saveConfigFile(const QDomDocument &doc, const QString &filename, const QString &componentName=QString())
static KGlobalAccel * self()
QDomNode firstChild() const const
QByteArray toLatin1() const const
QDomNode cloneNode(bool deep) const const
int length() const const
virtual void close() override
QDomElement firstChildElement(const QString &tagName) const const
QTextCodec * codecForName(const QByteArray &name)
void refreshActionProperties()
Use this method to reset and reread action properties (shortcuts, etc.) for all actions.
QDomAttr toAttr() const const
bool isValid() const const
virtual QDomDocument domDocument() const
QWidget * container(const QString &containerName, KXMLGUIClient *client, bool useTagName=false)
Use this method to get access to a container widget with the name specified with containerName and wh...
QIcon fromTheme(const QString &name)
bool setProperty(const char *name, const QVariant &value)
QString tagName() const const
QDomElement createElement(const QString &tagName)
QList< KXMLGUIClient * > clients() const
Returns a list of all clients currently added to this factory.
int configureShortcuts(bool bAllowLetterShortcuts=true, bool bSaveSettings=true)
Show a standard configure shortcut for every action in this factory.
QDomNode item(int index) const const
QString absolutePath() const const
Shortcuts without a modifier are not allowed, so &#39;A&#39; would not be valid, whereas &#39;Ctrl+A&#39; would be...
QObject * parent() const const
int compare(const QString &other, Qt::CaseSensitivity cs) const const
KXMLGUIBuilder * clientBuilder() const
Retrieves the client&#39;s GUI builder or nullptr if no client specific builder has been assigned via set...
T readEntry(const QString &key, const T &aDefault) const
bool setShortcut(QAction *action, const QList< QKeySequence > &shortcut, GlobalShortcutLoading loadFlag=Autoloading)
~KXMLGUIFactory()
Destructor.
KXMLGUIFactory(KXMLGUIBuilder *builder, QObject *parent=nullptr)
Constructs a KXMLGUIFactory.
static QDomElement actionPropertiesElement(QDomDocument &doc)
QDomDocument toDocument() const const
Dialog for configuration of KActionCollection and KGlobalAccel.
static QDomElement findActionByName(QDomElement &elem, const QString &sName, bool create)
bool mkpath(const QString &dirPath) const const
QString applicationName()
QString locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)
void setXMLGUIBuildDocument(const QDomDocument &doc)
uint toUInt(bool *ok, int base) const const
bool configure(bool saveSettings=true)
Run the dialog and call writeSettings() on the action collections that were added if saveSettings is ...
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Thu Dec 3 2020 22:51:28 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.