KXmlGui

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

KDE's Doxygen guidelines are available online.