fix tricky regression noticed by Vyacheslav Tokarev on Google Reader.
[kdelibs.git] / kdeui / xmlgui / kxmlguifactory.cpp
blob4ddba00678c258eec1c1f0260b9a6ccf0b9149d0
1 /* This file is part of the KDE libraries
2 Copyright (C) 1999,2000 Simon Hausmann <hausmann@kde.org>
3 Copyright (C) 2000 Kurt Granroth <granroth@kde.org>
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.
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.
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.
21 #include "kxmlguifactory.h"
22 #include "kxmlguifactory_p.h"
23 #include "kxmlguiclient.h"
24 #include "kxmlguibuilder.h"
26 #include <assert.h>
28 #include <QtCore/QDir>
29 #include <QtXml/QDomDocument>
30 #include <QtCore/QFile>
31 #include <QtCore/QTextIStream>
32 #include <QtGui/QWidget>
33 #include <QtCore/QDate>
34 #include <QtCore/QVariant>
35 #include <QTextCodec>
37 #include <kdebug.h>
38 #include <kcomponentdata.h>
39 #include <kglobal.h>
40 #include <kshortcut.h>
41 #include <kstandarddirs.h>
43 #include "kaction.h"
44 #include "kshortcutsdialog.h"
45 #include "kactioncollection.h"
47 using namespace KXMLGUI;
49 class KXMLGUIFactoryPrivate : public BuildState
51 public:
52 enum ShortcutOption { SetActiveShortcut = 1, SetDefaultShortcut = 2};
54 KXMLGUIFactoryPrivate()
56 static const QString &defaultMergingName = KGlobal::staticQString( "<default>" );
57 static const QString &actionList = KGlobal::staticQString( "actionlist" );
58 static const QString &name = KGlobal::staticQString( "name" );
60 m_rootNode = new ContainerNode( 0L, QString(), 0L );
61 m_defaultMergingName = defaultMergingName;
62 tagActionList = actionList;
63 attrName = name;
65 ~KXMLGUIFactoryPrivate()
67 delete m_rootNode;
70 void pushState()
72 m_stateStack.push( *this );
75 void popState()
77 BuildState::operator=( m_stateStack.pop() );
80 bool emptyState() const { return m_stateStack.isEmpty(); }
82 QWidget *findRecursive( KXMLGUI::ContainerNode *node, bool tag );
83 QList<QWidget*> findRecursive( KXMLGUI::ContainerNode *node, const QString &tagName );
84 void applyActionProperties( const QDomElement &element,
85 ShortcutOption shortcutOption = KXMLGUIFactoryPrivate::SetActiveShortcut );
86 void configureAction( QAction *action, const QDomNamedNodeMap &attributes,
87 ShortcutOption shortcutOption = KXMLGUIFactoryPrivate::SetActiveShortcut );
88 void configureAction( QAction *action, const QDomAttr &attribute,
89 ShortcutOption shortcutOption = KXMLGUIFactoryPrivate::SetActiveShortcut );
91 QDomDocument shortcutSchemeDoc(KXMLGUIClient *client);
92 void applyShortcutScheme(KXMLGUIClient *client, QDomDocument scheme);
93 void refreshActionProperties(KXMLGUIClient *client, QDomDocument doc);
94 void saveDefaultActionProperties(KXMLGUIClient *client);
96 ContainerNode *m_rootNode;
98 QString m_defaultMergingName;
101 * Contains the container which is searched for in ::container .
103 QString m_containerName;
106 * List of all clients
108 QList<KXMLGUIClient*> m_clients;
110 QString tagActionList;
112 QString attrName;
114 BuildStateStack m_stateStack;
117 QString KXMLGUIFactory::readConfigFile( const QString &filename, const KComponentData &_componentData )
119 KComponentData componentData = _componentData.isValid() ? _componentData : KGlobal::mainComponent();
120 QString xml_file;
122 if (!QDir::isRelativePath(filename))
123 xml_file = filename;
124 else
126 xml_file = KStandardDirs::locate("data", componentData.componentName() + '/' + filename);
127 if ( !QFile::exists( xml_file ) )
128 xml_file = KStandardDirs::locate( "data", filename );
131 QFile file( xml_file );
132 if ( xml_file.isEmpty() || !file.open( QIODevice::ReadOnly ) )
134 kError(240) << "No such XML file" << filename;
135 return QString();
138 QByteArray buffer(file.readAll());
139 return QString::fromUtf8(buffer.constData(), buffer.size());
142 bool KXMLGUIFactory::saveConfigFile( const QDomDocument& doc,
143 const QString& filename, const KComponentData &_componentData )
145 KComponentData componentData = _componentData.isValid() ? _componentData : KGlobal::mainComponent();
146 QString xml_file(filename);
148 if (QDir::isRelativePath(xml_file))
149 xml_file = KStandardDirs::locateLocal("data", componentData.componentName() + '/' + filename);
151 QFile file( xml_file );
152 if ( xml_file.isEmpty() || !file.open( QIODevice::WriteOnly ) )
154 kError(240) << "Could not write to" << filename;
155 return false;
158 // write out our document
159 QTextStream ts(&file);
160 ts.setCodec( QTextCodec::codecForName( "UTF-8" ) );
161 ts << doc;
163 file.close();
164 return true;
168 * Removes all QDomComment objects from the specified node and all its children.
170 static void removeDOMComments( QDomNode &node )
172 QDomNode n = node.firstChild();
173 while ( !n.isNull() )
175 if ( n.nodeType() == QDomNode::CommentNode )
177 QDomNode tmp = n;
178 n = n.nextSibling();
179 node.removeChild( tmp );
181 else
183 QDomNode tmp = n;
184 n = n.nextSibling();
185 removeDOMComments( tmp );
190 KXMLGUIFactory::KXMLGUIFactory( KXMLGUIBuilder *builder, QObject *parent )
191 : QObject( parent ),d(new KXMLGUIFactoryPrivate)
193 d->builder = builder;
194 d->guiClient = 0;
195 if ( d->builder )
197 d->builderContainerTags = d->builder->containerTags();
198 d->builderCustomTags = d->builder->customTags();
202 KXMLGUIFactory::~KXMLGUIFactory()
204 delete d;
207 void KXMLGUIFactory::addClient( KXMLGUIClient *client )
209 //kDebug(260) << client;
210 if ( client->factory() ) {
211 if ( client->factory() == this )
212 return;
213 else
214 client->factory()->removeClient( client ); //just in case someone does stupid things ;-)
217 if (d->emptyState())
218 emit makingChanges(true);
219 d->pushState();
221 // QTime dt; dt.start();
223 d->guiClient = client;
225 // add this client to our client list
226 if ( !d->m_clients.contains( client ) )
227 d->m_clients.append( client );
228 else
229 kDebug(260) << "XMLGUI client already added " << client;
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() );
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();
243 QDomElement docElement = doc.documentElement();
245 d->m_rootNode->index = -1;
247 // cache some variables
249 d->clientName = docElement.attribute( d->attrName );
250 d->clientBuilder = client->clientBuilder();
252 if ( d->clientBuilder )
254 d->clientBuilderContainerTags = d->clientBuilder->containerTags();
255 d->clientBuilderCustomTags = d->clientBuilder->customTags();
257 else
259 d->clientBuilderContainerTags.clear();
260 d->clientBuilderCustomTags.clear();
263 // load shortcut schemes, user-defined shortcuts and other action properties
264 d->saveDefaultActionProperties(client);
265 d->refreshActionProperties(client, doc);
267 BuildHelper( *d, d->m_rootNode ).build( docElement );
269 // let the client know that we built its GUI.
270 client->setFactory( this );
272 // call the finalizeGUI method, to fix up the positions of toolbars for example.
273 // ### FIXME : obey client builder
274 // --- Well, toolbars have a bool "positioned", so it doesn't really matter,
275 // if we call positionYourself on all of them each time. (David)
276 d->builder->finalizeGUI( d->guiClient );
278 // reset some variables, for safety
279 d->BuildState::reset();
281 client->endXMLPlug();
283 d->popState();
285 emit clientAdded( client );
287 // build child clients
288 foreach (KXMLGUIClient *child, client->childClients())
289 addClient( child );
291 if (d->emptyState())
292 emit makingChanges(false);
294 QString unaddedActions;
295 foreach (KActionCollection* ac, KActionCollection::allCollections())
296 foreach (QAction* action, ac->actions())
297 if (action->associatedWidgets().isEmpty())
298 unaddedActions += action->objectName() + ' ';
300 if (!unaddedActions.isEmpty())
301 kWarning() << "The following actions are not plugged into the gui (shortcuts will not work): " << unaddedActions;
304 // kDebug() << "addClient took " << dt.elapsed();
307 void KXMLGUIFactory::refreshActionProperties()
309 foreach (KXMLGUIClient *client, d->m_clients)
311 d->guiClient = client;
312 QDomDocument doc = client->xmlguiBuildDocument();
313 if ( doc.documentElement().isNull() )
315 client->reloadXML();
316 doc = client->domDocument();
318 d->refreshActionProperties(client, doc);
320 d->guiClient = 0;
323 void KXMLGUIFactoryPrivate::refreshActionProperties(KXMLGUIClient *client, QDomDocument doc)
325 // try to find and apply shortcuts schemes
326 QDomDocument scheme = shortcutSchemeDoc(client);
327 applyShortcutScheme(client, scheme);
329 // try to find and apply user-defined shortcuts
330 QDomElement actionPropElement = KXMLGUIFactory::actionPropertiesElement(doc);
331 if (actionPropElement.childNodes().isEmpty())
332 doc.documentElement().removeChild(actionPropElement);
334 if ( !actionPropElement.isNull() )
335 applyActionProperties( actionPropElement );
338 void KXMLGUIFactoryPrivate::saveDefaultActionProperties(KXMLGUIClient *client)
340 // This method is called every time the user activated a new
341 // kxmlguiclient. We only want to execute the following code only once in
342 // the lifetime of an action.
343 foreach (QAction *action, client->actionCollection()->actions())
345 // Skip actions we have seen already.
346 if (action->property("_k_DefaultShortcut").isValid()) continue;
348 if (KAction* kaction = qobject_cast<KAction*>(action))
350 // Check if the default shortcut is set
351 KShortcut defaultShortcut = kaction->shortcut(KAction::DefaultShortcut);
352 KShortcut activeShortcut = kaction->shortcut(KAction::ActiveShortcut);
354 // Check if we have an empty default shortcut and an non empty
355 // custom shortcut. This should only happen if a developer called
356 // QAction::setShortcut on an KAction. Print out a warning and
357 // correct the mistake
358 if ((!activeShortcut.isEmpty()) && defaultShortcut.isEmpty())
360 kError() << "Shortcut for KAction " << kaction->objectName() << kaction->text() << "set with QShortcut::setShortcut()! See KAction documentation.";
361 kaction->setProperty("_k_DefaultShortcut", activeShortcut);
363 else
365 kaction->setProperty("_k_DefaultShortcut", defaultShortcut);
368 else
370 // A QAction used with KXMLGUI? Set our property and ignore it.
371 kError() << "Attempt to use QAction" << action->objectName() << "with KXMLGUIFactory!";
372 action->setProperty("_k_DefaultShortcut", KShortcut());
378 void KXMLGUIFactory::changeShortcutScheme(const QString &scheme)
380 kDebug(260) << "Changing shortcut scheme to" << scheme;
381 KConfigGroup cg = KGlobal::config()->group( "Shortcut Schemes" );
382 cg.writeEntry("Current Scheme", scheme);
384 refreshActionProperties();
387 void KXMLGUIFactory::removeClient( KXMLGUIClient *client )
389 //kDebug(260) << client;
391 // don't try to remove the client's GUI if we didn't build it
392 if ( !client || client->factory() != this )
393 return;
395 if (d->emptyState())
396 emit makingChanges(true);
398 // remove this client from our client list
399 d->m_clients.removeAll( client );
401 // remove child clients first (create a copy of the list just in case the
402 // original list is modified directly or indirectly in removeClient())
403 const QList<KXMLGUIClient*> childClients(client->childClients());
404 foreach (KXMLGUIClient *child, childClients)
405 removeClient(child);
407 //kDebug(260) << "calling removeRecursive";
409 d->pushState();
411 // cache some variables
413 d->guiClient = client;
414 d->clientName = client->domDocument().documentElement().attribute( d->attrName );
415 d->clientBuilder = client->clientBuilder();
417 client->setFactory( 0L );
419 // if we don't have a build document for that client, yet, then create one by
420 // cloning the original document, so that saving container information in the
421 // DOM tree does not touch the original document.
422 QDomDocument doc = client->xmlguiBuildDocument();
423 if ( doc.documentElement().isNull() )
425 doc = client->domDocument().cloneNode( true ).toDocument();
426 client->setXMLGUIBuildDocument( doc );
429 d->m_rootNode->destruct( doc.documentElement(), *d );
431 // reset some variables
432 d->BuildState::reset();
434 // This will destruct the KAccel object built around the given widget.
435 client->prepareXMLUnplug( d->builder->widget() );
437 d->popState();
439 if (d->emptyState())
440 emit makingChanges(false);
442 emit clientRemoved( client );
445 QList<KXMLGUIClient*> KXMLGUIFactory::clients() const
447 return d->m_clients;
450 QWidget *KXMLGUIFactory::container( const QString &containerName, KXMLGUIClient *client,
451 bool useTagName )
453 d->pushState();
454 d->m_containerName = containerName;
455 d->guiClient = client;
457 QWidget *result = d->findRecursive( d->m_rootNode, useTagName );
459 d->guiClient = 0L;
460 d->m_containerName.clear();
462 d->popState();
464 return result;
467 QList<QWidget*> KXMLGUIFactory::containers( const QString &tagName )
469 return d->findRecursive( d->m_rootNode, tagName );
472 void KXMLGUIFactory::reset()
474 d->m_rootNode->reset();
476 d->m_rootNode->clearChildren();
479 void KXMLGUIFactory::resetContainer( const QString &containerName, bool useTagName )
481 if ( containerName.isEmpty() )
482 return;
484 ContainerNode *container = d->m_rootNode->findContainer( containerName, useTagName );
486 if ( !container )
487 return;
489 ContainerNode *parent = container->parent;
490 if ( !parent )
491 return;
493 // resetInternal( container );
495 parent->removeChild( container );
498 QWidget *KXMLGUIFactoryPrivate::findRecursive( KXMLGUI::ContainerNode *node, bool tag )
500 if ( ( ( !tag && node->name == m_containerName ) ||
501 ( tag && node->tagName == m_containerName ) ) &&
502 ( !guiClient || node->client == guiClient ) )
503 return node->container;
505 foreach (ContainerNode* child, node->children)
507 QWidget *cont = findRecursive( child, tag );
508 if ( cont )
509 return cont;
512 return 0L;
515 // Case insensitive equality without calling toLower which allocates a new string
516 static inline bool equals(const QString& str1, const char* str2)
518 return str1.compare(QLatin1String(str2), Qt::CaseInsensitive) == 0;
520 static inline bool equals(const QString& str1, const QString& str2)
522 return str1.compare(str2, Qt::CaseInsensitive) == 0;
526 QList<QWidget*> KXMLGUIFactoryPrivate::findRecursive( KXMLGUI::ContainerNode *node,
527 const QString &tagName )
529 QList<QWidget*> res;
531 if ( equals(node->tagName, tagName) )
532 res.append( node->container );
534 foreach (KXMLGUI::ContainerNode* child, node->children)
535 res << findRecursive( child, tagName );
537 return res;
540 void KXMLGUIFactory::plugActionList( KXMLGUIClient *client, const QString &name,
541 const QList<QAction*> &actionList )
543 d->pushState();
544 d->guiClient = client;
545 d->actionListName = name;
546 d->actionList = actionList;
547 d->clientName = client->domDocument().documentElement().attribute( d->attrName );
549 d->m_rootNode->plugActionList( *d );
551 d->BuildState::reset();
552 d->popState();
555 void KXMLGUIFactory::unplugActionList( KXMLGUIClient *client, const QString &name )
557 d->pushState();
558 d->guiClient = client;
559 d->actionListName = name;
560 d->clientName = client->domDocument().documentElement().attribute( d->attrName );
562 d->m_rootNode->unplugActionList( *d );
564 d->BuildState::reset();
565 d->popState();
568 void KXMLGUIFactoryPrivate::applyActionProperties( const QDomElement &actionPropElement,
569 ShortcutOption shortcutOption )
571 for (QDomNode n = actionPropElement.firstChild();
572 !n.isNull(); n = n.nextSibling() )
574 QDomElement e = n.toElement();
575 if ( !equals(e.tagName(), "action") )
576 continue;
578 QAction *action = guiClient->action( e );
579 if ( !action )
580 continue;
582 configureAction( action, e.attributes(), shortcutOption );
586 void KXMLGUIFactoryPrivate::configureAction( QAction *action, const QDomNamedNodeMap &attributes,
587 ShortcutOption shortcutOption )
589 for ( uint i = 0; i < attributes.length(); i++ )
591 QDomAttr attr = attributes.item( i ).toAttr();
592 if ( attr.isNull() )
593 continue;
595 configureAction( action, attr, shortcutOption );
599 void KXMLGUIFactoryPrivate::configureAction( QAction *action, const QDomAttr &attribute,
600 ShortcutOption shortcutOption )
602 static const QString &attrShortcut = KGlobal::staticQString( "shortcut" );
604 QString attrName = attribute.name();
605 // If the attribute is a deprecated "accel", change to "shortcut".
606 if ( equals(attrName, "accel") )
607 attrName = attrShortcut;
609 // No need to re-set name, particularly since it's "objectName" in Qt4
610 if ( equals(attrName, "name") )
611 return;
613 if ( equals(attrName, "icon") ) {
614 action->setIcon( KIcon( attribute.value() ) );
615 return;
618 QVariant propertyValue;
620 QVariant::Type propertyType = action->property( attrName.toLatin1() ).type();
622 if ( propertyType == QVariant::Int ) {
623 propertyValue = QVariant( attribute.value().toInt() );
624 } else if ( propertyType == QVariant::UInt ) {
625 propertyValue = QVariant( attribute.value().toUInt() );
626 } else if ( propertyType == QVariant::UserType && action->property( attrName.toLatin1() ).userType() == qMetaTypeId<KShortcut>() ) {
627 // Setting the shortcut by property also sets the default shortcut (which is incorrect), so we have to do it directly
628 if (KAction* ka = qobject_cast<KAction*>(action)) {
629 if (attrName=="globalShortcut") {
630 ka->setGlobalShortcut(KShortcut(attribute.value()), KAction::ActiveShortcut);
631 } else {
632 ka->setShortcut(KShortcut(attribute.value()), KAction::ActiveShortcut);
634 if (shortcutOption & KXMLGUIFactoryPrivate::SetDefaultShortcut)
635 ka->setShortcut(KShortcut(attribute.value()), KAction::DefaultShortcut);
636 return;
638 propertyValue = KShortcut( attribute.value() );
639 } else {
640 propertyValue = QVariant( attribute.value() );
642 if (!action->setProperty( attrName.toLatin1(), propertyValue )) {
643 kWarning() << "Error: Unknown action property " << attrName << " will be ignored!";
647 QDomDocument KXMLGUIFactoryPrivate::shortcutSchemeDoc(KXMLGUIClient *client)
649 // Get the name of the current shorcut scheme
650 KConfigGroup cg = KGlobal::config()->group( "Shortcut Schemes" );
651 QString schemeName = cg.readEntry("Current Scheme", "Default");
653 QDomDocument doc;
654 if (schemeName != "Default")
656 // Find the document for the shortcut scheme using both current application path
657 // and current xmlguiclient path but making a preference to app path
658 QString schemeFileName = KStandardDirs::locateLocal("data",
659 client->componentData().componentName() + '/' +
660 client->componentData().componentName() + schemeName.toLower() + "shortcuts.rc" );
662 QFile schemeFile(schemeFileName);
663 if (schemeFile.open(QIODevice::ReadOnly))
665 // kDebug(260) << "Found shortcut scheme" << schemeFileName;
666 doc.setContent(&schemeFile);
667 schemeFile.close();
670 return doc;
673 void KXMLGUIFactoryPrivate::applyShortcutScheme(KXMLGUIClient *client, QDomDocument scheme)
675 static const QString &actionPropElementName = KGlobal::staticQString( "ActionProperties" );
677 KConfigGroup cg = KGlobal::config()->group( "Shortcut Schemes" );
678 QString schemeName = cg.readEntry("Current Scheme", "Default");
680 //First clear all existing shortcuts
681 if (schemeName != "Default") {
682 foreach (QAction *action, client->actionCollection()->actions())
684 if (KAction *kaction = qobject_cast<KAction*>(action))
686 kaction->setShortcut(KShortcut(), KAction::ActiveShortcut);
687 // We clear the default shortcut as well because the shortcut scheme will set its own defaults
688 kaction->setShortcut(KShortcut(), KAction::DefaultShortcut);
690 else
691 action->setProperty("shortcut", KShortcut());
693 } else {
694 // apply saved default shortcuts
695 foreach (QAction *action, client->actionCollection()->actions())
697 if (KAction *kaction = qobject_cast<KAction*>(action))
699 QVariant savedDefaultShortcut = kaction->property("_k_DefaultShortcut");
700 if (savedDefaultShortcut.isValid())
702 KShortcut shortcut = savedDefaultShortcut.value<KShortcut>();
703 kaction->setShortcut(shortcut, KAction::ActiveShortcut);
704 kaction->setShortcut(shortcut, KAction::DefaultShortcut);
705 continue;
708 action->setProperty("shortcut", KShortcut());
712 if (scheme.isNull())
713 return;
715 QDomElement docElement = scheme.documentElement();
716 QDomElement actionPropElement = docElement.namedItem( actionPropElementName ).toElement();
718 //Check if we really have the shortcut configuration here
719 if (!actionPropElement.isNull())
721 kDebug(260) << "Applying shortcut scheme for XMLGUI client" << client->componentData().componentName();
723 //Apply all shortcuts we have
724 applyActionProperties(actionPropElement, KXMLGUIFactoryPrivate::SetDefaultShortcut);
726 else
727 kDebug(260) << "Invalid shortcut scheme file";
730 int KXMLGUIFactory::configureShortcuts(bool letterCutsOk , bool bSaveSettings )
732 KShortcutsDialog dlg(KShortcutsEditor::AllActions,
733 letterCutsOk ? KShortcutsEditor::LetterShortcutsAllowed : KShortcutsEditor::LetterShortcutsDisallowed,
734 qobject_cast<QWidget*>(parent()));
735 foreach (KXMLGUIClient *client, d->m_clients)
737 if(client && !client->xmlFile().isEmpty())
738 dlg.addCollection( client->actionCollection() );
740 return dlg.configure(bSaveSettings);
743 QDomElement KXMLGUIFactory::actionPropertiesElement( QDomDocument& doc )
745 KConfigGroup cg = KGlobal::config()->group( "Shortcut Schemes" );
746 QString schemeName = cg.readEntry("Current Scheme", "Default");
748 const QString tagActionProp = QLatin1String("ActionProperties");
749 // first, lets see if we have existing properties
750 QDomElement elem;
751 QDomNode it = doc.documentElement().firstChild();
752 for( ; !it.isNull(); it = it.nextSibling() ) {
753 QDomElement e = it.toElement();
754 if( ((e.tagName() == tagActionProp) || (e.tagName() == tagActionProp.toLower()))
755 && (e.attribute("scheme", "Default") == schemeName) ) {
756 elem = e;
757 break;
761 // if there was none, create one
762 if( elem.isNull() ) {
763 elem = doc.createElement( tagActionProp );
764 elem.setAttribute( "scheme", schemeName );
765 doc.documentElement().appendChild( elem );
767 return elem;
770 QDomElement KXMLGUIFactory::findActionByName( QDomElement& elem, const QString& sName, bool create )
772 static const QString& attrName = KGlobal::staticQString( "name" );
773 static const QString& tagAction = KGlobal::staticQString( "Action" );
774 for( QDomNode it = elem.firstChild(); !it.isNull(); it = it.nextSibling() ) {
775 QDomElement e = it.toElement();
776 if( e.attribute( attrName ) == sName )
777 return e;
780 if( create ) {
781 QDomElement act_elem = elem.ownerDocument().createElement( tagAction );
782 act_elem.setAttribute( attrName, sName );
783 elem.appendChild( act_elem );
784 return act_elem;
786 return QDomElement();
789 #include "kxmlguifactory.moc"
791 /* vim: et sw=4