Krita Source Code Documentation
Loading...
Searching...
No Matches
kxmlguiclient.cpp
Go to the documentation of this file.
1/* This file is part of the KDE libraries
2 SPDX-FileCopyrightText: 2000 Simon Hausmann <hausmann@kde.org>
3 SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-only
6*/
7
8#include "kxmlguiclient.h"
9
11#include "kxmlguifactory.h"
12#include "kxmlguibuilder.h"
13#include "kactioncollection.h"
14
15#include <QAction>
16#include <QDir>
17#include <QFile>
18#include <QDomDocument>
19#include <QPointer>
20#include <QCoreApplication>
21#include <QStandardPaths>
22#include <QDebug>
23
24#include <klocalizedstring.h>
25
26#include <assert.h>
27
28#if defined(KCONFIG_BEFORE_5_24)
29# define authorizeAction authorizeKAction
30#endif
31
33{
34public:
36 : m_componentName(QCoreApplication::applicationName()),
38 m_parent(0L),
39 m_builder(0L)
40 {
41 m_textTagNames.append(QLatin1String("text"));
42 m_textTagNames.append(QLatin1String("Text"));
43 m_textTagNames.append(QLatin1String("title"));
44 }
48
49 bool mergeXML(QDomElement &base, QDomElement &additive,
50 KisKActionCollection *actionCollection);
51 bool isEmptyContainer(const QDomElement &base,
52 KisKActionCollection *actionCollection) const;
53
54 QDomElement findMatchingElement(const QDomElement &base,
55 const QDomElement &additive);
56
58
59 QDomDocument m_doc;
61 QDomDocument m_buildDocument;
64 //QPtrList<KisKXMLGUIClient> m_supers;
67 QString m_xmlFile;
70
71 // Actions to enable/disable on a state change
72 QMap<QString, KisKXMLGUIClient::StateChange> m_actionsStateMap;
73};
74
79
82{
83 parent->insertChildClient(this);
84}
85
87{
88 if (d->m_parent) {
90 }
91
92 if (d->m_factory) {
93 qWarning() << this << "deleted without having been removed from the factory first. This will leak standalone popupmenus and could lead to crashes.";
94 d->m_factory->forgetClient(this);
95 }
96
97 Q_FOREACH (KisKXMLGUIClient *client, d->m_children) {
98 if (d->m_factory) {
99 d->m_factory->forgetClient(client);
100 }
101 assert(client->d->m_parent == this);
102 client->d->m_parent = 0;
103 }
104
105 delete d->m_actionCollection;
106 delete d;
107}
108
109QAction *KisKXMLGUIClient::action(const char *name) const
110{
111 QAction *act = actionCollection()->action(QLatin1String(name));
112 if (!act) {
113 Q_FOREACH (KisKXMLGUIClient *client, d->m_children) {
114 act = client->actionCollection()->action(QLatin1String(name));
115 if (act) {
116 break;
117 }
118 }
119 }
120 return act;
121}
122
124{
125 if (!d->m_actionCollection) {
127 d->m_actionCollection->setObjectName(QStringLiteral("KisKXMLGUIClient-KisKActionCollection"));
128 }
129 return d->m_actionCollection;
130}
131
132QAction *KisKXMLGUIClient::action(const QDomElement &element) const
133{
134 return actionCollection()->action(element.attribute(QStringLiteral("name")));
135}
136
138{
139 return d->m_componentName;
140}
141
143{
144 return d->m_doc;
145}
146
148{
149 return d->m_xmlFile;
150}
151
153{
154 if (!d->m_localXMLFile.isEmpty()) {
155 return d->m_localXMLFile;
156 }
157
158 if (!QDir::isRelativePath(d->m_xmlFile)) {
159 return QString(); // can't save anything here
160 }
161
162 if (d->m_xmlFile.isEmpty()) { // setXMLFile not called at all, can't save. Use case: ToolBarHandler
163 return QString();
164 }
165
166 return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/kxmlgui5/") +
167 componentName() + QLatin1Char('/') + d->m_xmlFile;
168}
169
171{
172 // TODO: this method can't be used for the KXmlGuiWindow, since it doesn't merge in ui_standards.xmlgui!
173 // -> KDE5: load ui_standards_rc in setXMLFile using a flag, and remember that flag?
174 // and then KisKEditToolBar can use reloadXML.
175 QString file(xmlFile());
176 if (!file.isEmpty()) {
177 setXMLFile(file);
178 }
179}
180
181void KisKXMLGUIClient::setComponentName(const QString &componentName, const QString &componentDisplayName)
182{
185 actionCollection()->setComponentDisplayName(componentDisplayName);
186 if (d->m_builder) {
188 }
189}
190
192{
193 QString file = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, QStringLiteral("ui/ui_standards.xmlgui"));
194 if (file.isEmpty()) {
195 // fallback to resource, to allow to use the rc file compiled into this framework, must exist!
196 file = QStringLiteral(":/kxmlgui5/ui_standards.xmlgui");
197 Q_ASSERT(QFile::exists(file));
198 }
199 return file;
200}
201
206
207void KisKXMLGUIClient::setXMLFile(const QString &_file, bool merge, bool setXMLDoc)
208{
209 // store our xml file name
210 if (!_file.isNull()) {
211 d->m_xmlFile = _file;
212 }
213
214 if (!setXMLDoc) {
215 return;
216 }
217
218 QString file = _file;
219 QStringList allFiles;
220 if (!QDir::isRelativePath(file)) {
221 allFiles.append(file);
222 } else {
223 const QString filter = componentName() + QLatin1Char('/') + _file;
224
225 // files on filesystem
226 allFiles << QStandardPaths::locateAll(QStandardPaths::AppDataLocation, QStringLiteral("kxmlgui5/") + filter); // KF >= 5.1
227
228 // KF >= 5.4 (resource file)
229 const QString qrcFile(QStringLiteral(":/kxmlgui5/") + filter);
230 if (QFile::exists(qrcFile)) {
231 allFiles << qrcFile;
232 }
233
234 // then compat locations
235 const QStringList compatFiles =
236 QStandardPaths::locateAll(QStandardPaths::AppDataLocation, filter) + // kdelibs4, KF 5.0
237 QStandardPaths::locateAll(QStandardPaths::AppDataLocation, _file); // kdelibs4, KF 5.0, caller passes component name
238
239 if (allFiles.isEmpty() && !compatFiles.isEmpty()) {
240 qWarning() << "kxmlguiclient: KisKXMLGUI file found at deprecated location" << compatFiles << "-- please use ${KisKXMLGUI_INSTALL_DIR} to install this file instead.";
241 }
242 allFiles += compatFiles;
243 }
244 if (allFiles.isEmpty() && !_file.isEmpty()) {
245 // if a non-empty file gets passed and we can't find it,
246 // inform the developer using some debug output
247 qWarning() << "cannot find .xmlgui file" << _file << "for component" << componentName();
248 }
249
250 // make sure to merge the settings from any file specified by setLocalXMLFile()
251 if (!d->m_localXMLFile.isEmpty() && !file.endsWith(QStringLiteral("ui_standards.xmlgui"))) {
252 const bool exists = QDir::isRelativePath(d->m_localXMLFile) || QFile::exists(d->m_localXMLFile);
253 if (exists && !allFiles.contains(d->m_localXMLFile)) {
254 allFiles.prepend(d->m_localXMLFile);
255 }
256 }
257
258 QString doc;
259 if (!allFiles.isEmpty()) {
260 file = findMostRecentXMLFile(allFiles, doc);
261 }
262
263 // Always call setXML, even on error, so that we don't keep all ui_standards.xmlgui menus.
264 setXML(doc, merge);
265}
266
267void KisKXMLGUIClient::setLocalXMLFile(const QString &file)
268{
269 d->m_localXMLFile = file;
270}
271
272void KisKXMLGUIClient::replaceXMLFile(const QString &xmlfile, const QString &localxmlfile, bool merge)
273{
274 if (!QDir::isAbsolutePath(xmlfile)) {
275 qWarning() << "xml file" << xmlfile << "is not an absolute path";
276 }
277
278 setLocalXMLFile(localxmlfile);
279 setXMLFile(xmlfile, merge);
280}
281
282// The top document element may have translation domain attribute set,
283// or the translation domain may be implicitly the application domain.
284// This domain must be used to fetch translations for all text elements
285// in the document that do not have their own domain attribute.
286// In order to preserve this semantics through document mergings,
287// the top or application domain must be propagated to all text elements
288// lacking their own domain attribute.
289static void propagateTranslationDomain(QDomDocument &doc, const QStringList tagNames)
290{
291 const QLatin1String attrDomain("translationDomain");
292 QDomElement base = doc.documentElement();
293 QString domain = base.attribute(attrDomain);
294 if (domain.isEmpty()) {
295 domain = QString::fromUtf8(KLocalizedString::applicationDomain());
296 if (domain.isEmpty()) {
297 return;
298 }
299 }
300 foreach (const QString &tagName, tagNames) {
301 QDomNodeList textNodes = base.elementsByTagName(tagName);
302 for (int i = 0; i < textNodes.length(); ++i) {
303 QDomElement e = textNodes.item(i).toElement();
304 QString localDomain = e.attribute(attrDomain);
305 if (localDomain.isEmpty()) {
306 e.setAttribute(attrDomain, domain);
307 }
308 }
309 }
310}
311
312void KisKXMLGUIClient::setXML(const QString &document, bool merge)
313{
314 QDomDocument doc;
315 // QDomDocument raises a parse error on empty document, but we accept no app-specific document,
316 // in which case you only get ui_standards.xmlgui layout.
317#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
318 QString errorMsg;
319 int errorLine, errorColumn;
320 bool result = document.isEmpty() || doc.setContent(document, &errorMsg, &errorLine, &errorColumn);
321 if (result) {
322#else
323 QDomDocument::ParseResult result = doc.setContent(document);
324 if (document.isEmpty() || result) {
325#endif
327 setDOMDocument(doc, merge);
328 } else {
329#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
330 qCritical() << "Error parsing XML document:" << errorMsg << "at line" << errorLine << "column" << errorColumn;
331#else
332 qCritical() << "Error parsing XML document:" << result.errorMessage << "at line" << result.errorLine << "column" << result.errorColumn;
333#endif
334#ifdef NDEBUG
335 setDOMDocument(QDomDocument(), merge); // otherwise empty menus from ui_standards.xmlgui stay around
336#else
337 abort();
338#endif
339 }
340}
341
342void KisKXMLGUIClient::setDOMDocument(const QDomDocument &document, bool merge)
343{
344 if (merge && !d->m_doc.isNull()) {
345 QDomElement base = d->m_doc.documentElement();
346
347 QDomElement e = document.documentElement();
348
349 // merge our original (global) xml with our new one
350 d->mergeXML(base, e, actionCollection());
351
352 // reassign our pointer as mergeXML might have done something
353 // strange to it
354 base = d->m_doc.documentElement();
355
356 //qDebug(260) << "Result of xmlgui merging:" << d->m_doc.toString();
357
358 // we want some sort of failsafe.. just in case
359 if (base.isNull()) {
360 d->m_doc = document;
361 }
362 } else {
363 d->m_doc = document;
364 }
365
366 setXMLGUIBuildDocument(QDomDocument());
367}
368
369// if (equals(a,b)) is more readable than if (a.compare(b, Qt::CaseInsensitive)==0)
370static inline bool equalstr(const QString &a, const QString &b)
371{
372 return a.compare(b, Qt::CaseInsensitive) == 0;
373}
374static inline bool equalstr(const QString &a, const QLatin1String &b)
375{
376 return a.compare(b, Qt::CaseInsensitive) == 0;
377}
378
379bool KisKXMLGUIClientPrivate::mergeXML(QDomElement &base, QDomElement &additive, KisKActionCollection *actionCollection)
380{
381 const QLatin1String tagAction("Action");
382 const QLatin1String tagMerge("Merge");
383 const QLatin1String tagSeparator("Separator");
384 const QLatin1String tagMergeLocal("MergeLocal");
385 const QLatin1String tagText("text");
386 const QLatin1String attrAppend("append");
387 const QString attrName(QStringLiteral("name"));
388 const QString attrWeakSeparator(QStringLiteral("weakSeparator"));
389 const QString attrAlreadyVisited(QStringLiteral("alreadyVisited"));
390 const QString attrNoMerge(QStringLiteral("noMerge"));
391 const QLatin1String attrOne("1");
392
393 // there is a possibility that we don't want to merge in the
394 // additive.. rather, we might want to *replace* the base with the
395 // additive. this can be for any container.. either at a file wide
396 // level or a simple container level. we look for the 'noMerge'
397 // tag, in any event and just replace the old with the new
398 if (additive.attribute(attrNoMerge) == attrOne) { // ### use toInt() instead? (Simon)
399 base.parentNode().replaceChild(additive, base);
400 return true;
401 } else {
402 // Merge attributes
403 {
404 const QDomNamedNodeMap attribs = additive.attributes();
405 const uint attribcount = attribs.count();
406
407 for (uint i = 0; i < attribcount; ++i) {
408 const QDomNode node = attribs.item(i);
409 base.setAttribute(node.nodeName(), node.nodeValue());
410 }
411 }
412
413 // iterate over all elements in the container (of the global DOM tree)
414 QDomNode n = base.firstChild();
415 while (!n.isNull()) {
416 QDomElement e = n.toElement();
417 n = n.nextSibling(); // Advance now so that we can safely delete e
418 if (e.isNull()) {
419 continue;
420 }
421
422 const QString tag = e.tagName();
423
424 // if there's an action tag in the global tree and the action is
425 // not implemented, then we remove the element
426 if (equalstr(tag, tagAction)) {
427 const QString name = e.attribute(attrName);
428 if (!actionCollection->action(name)) {
429 // remove this child as we aren't using it
430 base.removeChild(e);
431 continue;
432 }
433 }
434
435 // if there's a separator defined in the global tree, then add an
436 // attribute, specifying that this is a "weak" separator
437 else if (equalstr(tag, tagSeparator)) {
438 e.setAttribute(attrWeakSeparator, (uint)1);
439
440 // okay, hack time. if the last item was a weak separator OR
441 // this is the first item in a container, then we nuke the
442 // current one
443 QDomElement prev = e.previousSibling().toElement();
444 if (prev.isNull() ||
445 (equalstr(prev.tagName(), tagSeparator) && !prev.attribute(attrWeakSeparator).isNull()) ||
446 (equalstr(prev.tagName(), tagText))) {
447 // the previous element was a weak separator or didn't exist
448 base.removeChild(e);
449 continue;
450 }
451 }
452
453 // the MergeLocal tag lets us specify where non-standard elements
454 // of the local tree shall be merged in. After inserting the
455 // elements we delete this element
456 else if (equalstr(tag, tagMergeLocal)) {
457 QDomNode it = additive.firstChild();
458 while (!it.isNull()) {
459 QDomElement newChild = it.toElement();
460 it = it.nextSibling();
461 if (newChild.isNull()) {
462 continue;
463 }
464
465 if (equalstr(newChild.tagName(), tagText)) {
466 continue;
467 }
468
469 if (newChild.attribute(attrAlreadyVisited) == attrOne) {
470 continue;
471 }
472
473 QString itAppend(newChild.attribute(attrAppend));
474 QString elemName(e.attribute(attrName));
475
476 if ((itAppend.isNull() && elemName.isEmpty()) ||
477 (itAppend == elemName)) {
478 // first, see if this new element matches a standard one in
479 // the global file. if it does, then we skip it as it will
480 // be merged in, later
481 QDomElement matchingElement = findMatchingElement(newChild, base);
482 if (matchingElement.isNull() || equalstr(newChild.tagName(), tagSeparator)) {
483 base.insertBefore(newChild, e);
484 }
485 }
486 }
487
488 base.removeChild(e);
489 continue;
490 }
491
492 else if (equalstr(tag, tagText)) {
493 continue;
494 } else if (equalstr(tag, tagMerge)) {
495 continue;
496 }
497
498 // in this last case we check for a separator tag and, if not, we
499 // can be sure that it is a container --> proceed with child nodes
500 // recursively and delete the just proceeded container item in
501 // case it is empty (if the recursive call returns true)
502 else {
503 QDomElement matchingElement = findMatchingElement(e, additive);
504 if (!matchingElement.isNull()) {
505 matchingElement.setAttribute(attrAlreadyVisited, (uint)1);
506
507 if (mergeXML(e, matchingElement, actionCollection)) {
508 base.removeChild(e);
509 additive.removeChild(matchingElement); // make sure we don't append it below
510 continue;
511 }
512
513 continue;
514 } else {
515 // this is an important case here! We reach this point if the
516 // "local" tree does not contain a container definition for
517 // this container. However we have to call mergeXML recursively
518 // and make it check if there are actions implemented for this
519 // container. *If* none, then we can remove this container now
520 QDomElement dummy;
521 if (mergeXML(e, dummy, actionCollection)) {
522 base.removeChild(e);
523 }
524 continue;
525 }
526 }
527 }
528
529 //here we append all child elements which were not inserted
530 //previously via the LocalMerge tag
531 n = additive.firstChild();
532 while (!n.isNull()) {
533 QDomElement e = n.toElement();
534 n = n.nextSibling(); // Advance now so that we can safely delete e
535 if (e.isNull()) {
536 continue;
537 }
538
539 QDomElement matchingElement = findMatchingElement(e, base);
540
541 if (matchingElement.isNull()) {
542 base.appendChild(e);
543 }
544 }
545
546 // do one quick check to make sure that the last element was not
547 // a weak separator
548 QDomElement last = base.lastChild().toElement();
549 if (equalstr(last.tagName(), tagSeparator) &&
550 (!last.attribute(attrWeakSeparator).isNull())) {
551 base.removeChild(last);
552 }
553 }
554
555 return isEmptyContainer(base, actionCollection);
556}
557
559{
560 // now we check if we are empty (in which case we return "true", to
561 // indicate the caller that it can delete "us" (the base element
562 // argument of "this" call)
563 QDomNode n = base.firstChild();
564 while (!n.isNull()) {
565 const QDomElement e = n.toElement();
566 n = n.nextSibling(); // Advance now so that we can safely delete e
567 if (e.isNull()) {
568 continue;
569 }
570
571 const QString tag = e.tagName();
572
573 if (equalstr(tag, QLatin1String("Action"))) {
574 // if base contains an implemented action, then we must not get
575 // deleted (note that the actionCollection contains both,
576 // "global" and "local" actions)
577 if (actionCollection->action(e.attribute(QStringLiteral("name")))) {
578 return false;
579 }
580 } else if (equalstr(tag, QLatin1String("Separator"))) {
581 // if we have a separator which has *not* the weak attribute
582 // set, then it must be owned by the "local" tree in which case
583 // we must not get deleted either
584 const QString weakAttr = e.attribute(QStringLiteral("weakSeparator"));
585 if (weakAttr.isEmpty() || weakAttr.toInt() != 1) {
586 return false;
587 }
588 }
589
590 else if (equalstr(tag, QLatin1String("merge"))) {
591 continue;
592 }
593
594 // a text tag is NOT enough to spare this container
595 else if (equalstr(tag, QLatin1String("text"))) {
596 continue;
597 }
598
599 // what's left are non-empty containers! *don't* delete us in this
600 // case (at this position we can be *sure* that the container is
601 // *not* empty, as the recursive call for it was in the first loop
602 // which deleted the element in case the call returned "true"
603 else {
604 return false;
605 }
606 }
607
608 return true; // I'm empty, please delete me.
609}
610
611QDomElement KisKXMLGUIClientPrivate::findMatchingElement(const QDomElement &base, const QDomElement &additive)
612{
613 QDomNode n = additive.firstChild();
614 while (!n.isNull()) {
615 QDomElement e = n.toElement();
616 n = n.nextSibling(); // Advance now so that we can safely delete e -- TODO we don't, so simplify this
617 if (e.isNull()) {
618 continue;
619 }
620
621 const QString tag = e.tagName();
622 // skip all action and merge tags as we will never use them
623 if (equalstr(tag, QLatin1String("Action"))
624 || equalstr(tag, QLatin1String("MergeLocal"))) {
625 continue;
626 }
627
628 // now see if our tags are equivalent
629 if (equalstr(tag, base.tagName()) &&
630 e.attribute(QStringLiteral("name")) == base.attribute(QStringLiteral("name"))) {
631 return e;
632 }
633 }
634
635 // nope, return a (now) null element
636 return QDomElement();
637}
638
639void KisKXMLGUIClient::setXMLGUIBuildDocument(const QDomDocument &doc)
640{
641 d->m_buildDocument = doc;
642}
643
645{
646 return d->m_buildDocument;
647}
648
653
658
663
665{
666 if (child->d->m_parent) {
667 child->d->m_parent->removeChildClient(child);
668 }
669 d->m_children.append(child);
670 child->d->m_parent = this;
671}
672
674{
675 assert(d->m_children.contains(child));
676 d->m_children.removeAll(child);
677 child->d->m_parent = 0;
678}
679
680/*bool KisKXMLGUIClient::addSuperClient( KisKXMLGUIClient *super )
681{
682 if ( d->m_supers.contains( super ) )
683 return false;
684 d->m_supers.append( super );
685 return true;
686}*/
687
692
694{
695 d->m_builder = builder;
696}
697
702
703void KisKXMLGUIClient::plugActionList(const QString &name, const QList<QAction *> &actionList)
704{
705 if (!d->m_factory) {
706 return;
707 }
708
709 d->m_factory->plugActionList(this, name, actionList);
710}
711
712void KisKXMLGUIClient::unplugActionList(const QString &name)
713{
714 if (!d->m_factory) {
715 return;
716 }
717
718 d->m_factory->unplugActionList(this, name);
719}
720
721QString KisKXMLGUIClient::findMostRecentXMLFile(const QStringList &files, QString &doc)
722{
723 KXmlGuiVersionHandler versionHandler(files);
724 doc = versionHandler.finalDocument();
725 return versionHandler.finalFile();
726}
727
729 const QString &action)
730{
731 StateChange stateChange = getActionsToChangeForState(state);
732
733 stateChange.actionsToEnable.append(action);
734 //qDebug(260) << "KisKXMLGUIClient::addStateActionEnabled( " << state << ", " << action << ")";
735
736 d->m_actionsStateMap.insert(state, stateChange);
737}
738
740 const QString &action)
741{
742 StateChange stateChange = getActionsToChangeForState(state);
743
744 stateChange.actionsToDisable.append(action);
745 //qDebug(260) << "KisKXMLGUIClient::addStateActionDisabled( " << state << ", " << action << ")";
746
747 d->m_actionsStateMap.insert(state, stateChange);
748}
749
754
756{
757 StateChange stateChange = getActionsToChangeForState(newstate);
758
759 bool setTrue = (reverse == StateNoReverse);
760 bool setFalse = !setTrue;
761
762 // Enable actions which need to be enabled...
763 //
764 for (QStringList::const_iterator it = stateChange.actionsToEnable.constBegin();
765 it != stateChange.actionsToEnable.constEnd(); ++it) {
766
767 QAction *action = actionCollection()->action(*it);
768 if (action) {
769 action->setEnabled(setTrue);
770 }
771 }
772
773 // and disable actions which need to be disabled...
774 //
775 for (QStringList::const_iterator it = stateChange.actionsToDisable.constBegin();
776 it != stateChange.actionsToDisable.constEnd(); ++it) {
777
778 QAction *action = actionCollection()->action(*it);
779 if (action) {
780 action->setEnabled(setFalse);
781 }
782 }
783
784}
785
787{
789 foreach (KisKXMLGUIClient *client, d->m_children) {
790 client->beginXMLPlug(w);
791 }
792}
793
797
799{
801 foreach (KisKXMLGUIClient *client, d->m_children) {
802 client->prepareXMLUnplug(w);
803 }
804}
805
807{
808 /*BASE::virtual_hook( id, data );*/
809}
unsigned int uint
A container for a set of QAction objects.
void setComponentDisplayName(const QString &displayName)
void removeAssociatedWidget(QWidget *widget)
void setComponentName(const QString &componentName)
QAction * action(int index) const
void addAssociatedWidget(QWidget *widget)
void setBuilderClient(KisKXMLGUIClient *client)
QList< KisKXMLGUIClient * > m_children
QMap< QString, KisKXMLGUIClient::StateChange > m_actionsStateMap
bool isEmptyContainer(const QDomElement &base, KisKActionCollection *actionCollection) const
bool mergeXML(QDomElement &base, QDomElement &additive, KisKActionCollection *actionCollection)
QDomElement findMatchingElement(const QDomElement &base, const QDomElement &additive)
KisKXMLGUIBuilder * m_builder
QPointer< KisKXMLGUIFactory > m_factory
KisKActionCollection * m_actionCollection
KisKXMLGUIClient * m_parent
void setFactory(KisKXMLGUIFactory *factory)
static QString findMostRecentXMLFile(const QStringList &files, QString &doc)
virtual void setComponentName(const QString &componentName, const QString &componentDisplayName)
KisKXMLGUIClientPrivate *const d
void beginXMLPlug(QWidget *)
QDomDocument xmlguiBuildDocument() const
void setXMLGUIBuildDocument(const QDomDocument &doc)
void setDOMDocument(const QDomDocument &document, bool merge=false)
KisKXMLGUIBuilder * clientBuilder() const
void setClientBuilder(KisKXMLGUIBuilder *builder)
virtual QString xmlFile() const
KisKXMLGUIClient * parentClient() const
StateChange getActionsToChangeForState(const QString &state)
virtual QDomDocument domDocument() const
void setLocalXMLFile(const QString &file)
QAction * action(const char *name) const
void unplugActionList(const QString &name)
static QString standardsXmlFileLocation()
void prepareXMLUnplug(QWidget *)
void addStateActionEnabled(const QString &state, const QString &action)
virtual void stateChanged(const QString &newstate, ReverseStateChange reverse=StateNoReverse)
virtual QString localXMLFile() const
void replaceXMLFile(const QString &xmlfile, const QString &localxmlfile, bool merge=false)
void removeChildClient(KisKXMLGUIClient *child)
virtual void virtual_hook(int id, void *data)
KisKXMLGUIFactory * factory() const
void setXMLFile(const QString &file, bool merge=false, bool setXMLDoc=true)
QList< KisKXMLGUIClient * > childClients()
void insertChildClient(KisKXMLGUIClient *child)
void setXML(const QString &document, bool merge=false)
virtual QString componentName() const
void plugActionList(const QString &name, const QList< QAction * > &actionList)
virtual KisKActionCollection * actionCollection() const
void addStateActionDisabled(const QString &state, const QString &action)
virtual ~KisKXMLGUIClient()
static QString readConfigFile(const QString &filename, const QString &componentName=QString())
static bool equalstr(const QString &a, const QString &b)
static void propagateTranslationDomain(QDomDocument &doc, const QStringList tagNames)