21 #include "kxmlguiversionhandler_p.h"
25 #include <QtCore/QDir>
26 #include <QtCore/QFile>
27 #include <QtXml/QDomDocument>
28 #include <QtCore/QTextIStream>
29 #include <QtCore/QRegExp>
30 #include <QtCore/QPointer>
42 class KXMLGUIClientPrivate
45 KXMLGUIClientPrivate()
47 m_actionCollection(0),
52 ~KXMLGUIClientPrivate()
56 bool mergeXML( QDomElement &base, QDomElement &additive,
58 bool isEmptyContainer(
const QDomElement& base,
61 QDomElement findMatchingElement(
const QDomElement &base,
62 const QDomElement &additive );
68 QDomDocument m_buildDocument;
69 QPointer<KXMLGUIFactory> m_factory;
83 : d( new KXMLGUIClientPrivate )
88 : d( new KXMLGUIClientPrivate )
96 d->m_parent->removeChildClient(
this );
100 kWarning(240) <<
this <<
"deleted without having been removed from the factory first. This will leak standalone popupmenus and could lead to crashes.";
101 d->m_factory->forgetClient(
this);
106 d->m_factory->forgetClient(client);
107 assert( client->d->m_parent ==
this );
108 client->d->m_parent = 0;
111 delete d->m_actionCollection;
130 if ( !d->m_actionCollection )
133 d->m_actionCollection->setObjectName(
"KXMLGUIClient-KActionCollection" );
135 return d->m_actionCollection;
140 static const QString &attrName = KGlobal::staticQString(
"name" );
146 return d->m_componentData;
161 if ( !d->m_localXMLFile.isEmpty() )
162 return d->m_localXMLFile;
164 if ( !QDir::isRelativePath(d->m_xmlFile) )
167 if (d->m_xmlFile.isEmpty())
180 if ( !file.isEmpty() )
189 d->m_builder->setBuilderClient(
this );
195 if (file.isEmpty()) {
206 if ( !_file.isNull() )
207 d->m_xmlFile = _file;
214 if ( !QDir::isRelativePath( file ) ) {
215 allFiles.append( file );
221 if ( allFiles.isEmpty() && !_file.isEmpty() ) {
228 if ( !d->m_localXMLFile.isEmpty() && !file.endsWith(
"ui_standards.rc") ) {
229 const bool exists = QDir::isRelativePath(d->m_localXMLFile) || QFile::exists(d->m_localXMLFile);
230 if (exists && !allFiles.contains(d->m_localXMLFile))
231 allFiles.prepend( d->m_localXMLFile );
235 if ( !allFiles.isEmpty() )
244 d->m_localXMLFile = file;
249 if ( !QDir::isAbsolutePath ( xmlfile ) ) {
250 kWarning() <<
"xml file" << xmlfile <<
"is not an absolute path";
261 int errorLine, errorColumn;
264 bool result = document.isEmpty() || doc.setContent(document, &errorMsg, &errorLine, &errorColumn);
269 kError(240) <<
"Error parsing XML document:" << errorMsg <<
"at line" << errorLine <<
"column" << errorColumn;
272 kFatal() <<
"Error parsing XML document:" << errorMsg <<
"at line" << errorLine <<
"column" << errorColumn;
279 if ( merge && !d->m_doc.isNull() )
281 QDomElement base = d->m_doc.documentElement();
283 QDomElement e = document.documentElement();
290 base = d->m_doc.documentElement();
308 return a.compare(b, Qt::CaseInsensitive) == 0;
311 bool KXMLGUIClientPrivate::mergeXML( QDomElement &base, QDomElement &additive,
KActionCollection *actionCollection )
313 static const QString &tagAction = KGlobal::staticQString(
"Action" );
314 static const QString &tagMerge = KGlobal::staticQString(
"Merge" );
315 static const QString &tagSeparator = KGlobal::staticQString(
"Separator" );
316 static const QString &attrName = KGlobal::staticQString(
"name" );
317 static const QString &attrAppend = KGlobal::staticQString(
"append" );
318 static const QString &attrWeakSeparator = KGlobal::staticQString(
"weakSeparator" );
319 static const QString &tagMergeLocal = KGlobal::staticQString(
"MergeLocal" );
320 static const QString &tagText = KGlobal::staticQString(
"text" );
321 static const QString &attrAlreadyVisited = KGlobal::staticQString(
"alreadyVisited" );
322 static const QString &attrNoMerge = KGlobal::staticQString(
"noMerge" );
323 static const QString &attrOne = KGlobal::staticQString(
"1" );
330 if ( additive.attribute(attrNoMerge) == attrOne )
332 base.parentNode().replaceChild(additive, base);
337 const QDomNamedNodeMap attribs = additive.attributes();
338 const uint attribcount = attribs.count();
340 for(uint i = 0; i < attribcount; ++i) {
341 const QDomNode node = attribs.item(i);
342 base.setAttribute(node.nodeName(), node.nodeValue());
347 QDomNode n = base.firstChild();
348 while ( !n.isNull() )
350 QDomElement e = n.toElement();
355 const QString tag = e.tagName();
361 if (!actionCollection->
action(name) ||
362 !KAuthorized::authorizeKAction(name))
365 base.removeChild( e );
372 else if (
equalstr(tag, tagSeparator)) {
373 e.setAttribute( attrWeakSeparator, (uint)1 );
378 QDomElement prev = e.previousSibling().toElement();
380 (
equalstr(prev.tagName(), tagSeparator) && !prev.attribute(attrWeakSeparator).isNull() ) ||
381 (
equalstr(prev.tagName(), tagText))) {
383 base.removeChild( e );
391 else if (
equalstr(tag, tagMergeLocal)) {
392 QDomNode it = additive.firstChild();
393 while ( !it.isNull() )
395 QDomElement newChild = it.toElement();
396 it = it.nextSibling();
397 if (newChild.isNull() )
400 if (
equalstr(newChild.tagName(), tagText))
403 if ( newChild.attribute( attrAlreadyVisited ) == attrOne )
406 QString itAppend( newChild.attribute( attrAppend ) );
407 QString elemName( e.attribute( attrName ) );
409 if ( ( itAppend.isNull() && elemName.isEmpty() ) ||
410 ( itAppend == elemName ) )
415 QDomElement matchingElement = findMatchingElement( newChild, base );
416 if (matchingElement.isNull() ||
equalstr(newChild.tagName(), tagSeparator))
417 base.insertBefore( newChild, e );
421 base.removeChild( e );
437 QDomElement matchingElement = findMatchingElement( e, additive );
438 if ( !matchingElement.isNull() )
440 matchingElement.setAttribute( attrAlreadyVisited, (uint)1 );
442 if ( mergeXML( e, matchingElement, actionCollection ) )
444 base.removeChild( e );
445 additive.removeChild(matchingElement);
459 if ( mergeXML( e, dummy, actionCollection ) )
460 base.removeChild( e );
468 n = additive.firstChild();
469 while ( !n.isNull() )
471 QDomElement e = n.toElement();
476 QDomElement matchingElement = findMatchingElement( e, base );
478 if ( matchingElement.isNull() )
480 base.appendChild( e );
486 QDomElement last = base.lastChild().toElement();
487 if (
equalstr(last.tagName(), tagSeparator) &&
488 (!last.attribute(attrWeakSeparator).isNull())) {
489 base.removeChild( last );
493 return isEmptyContainer(base, actionCollection);
496 bool KXMLGUIClientPrivate::isEmptyContainer(
const QDomElement& base,
KActionCollection *actionCollection)
const
501 QDomNode n = base.firstChild();
502 while (!n.isNull()) {
503 const QDomElement e = n.toElement();
508 const QString tag = e.tagName();
510 static const QString &tagAction = KGlobal::staticQString(
"Action");
511 static const QString &tagSeparator = KGlobal::staticQString(
"Separator");
512 static const QString &tagText = KGlobal::staticQString(
"text");
513 static const QString &tagMerge = KGlobal::staticQString(
"Merge");
518 static const QString &attrName = KGlobal::staticQString(
"name");
519 if (actionCollection->
action(e.attribute(attrName))) {
523 else if (
equalstr(tag, tagSeparator)) {
527 static const QString &attrWeakSeparator = KGlobal::staticQString(
"weakSeparator");
528 const QString weakAttr = e.attribute(attrWeakSeparator);
529 if (weakAttr.isEmpty() || weakAttr.toInt() != 1) {
555 QDomElement KXMLGUIClientPrivate::findMatchingElement(
const QDomElement &base,
const QDomElement &additive )
557 static const QString &tagAction = KGlobal::staticQString(
"Action" );
558 static const QString &tagMergeLocal = KGlobal::staticQString(
"MergeLocal" );
559 static const QString &attrName = KGlobal::staticQString(
"name" );
561 QDomNode n = additive.firstChild();
562 while ( !n.isNull() )
564 QDomElement e = n.toElement();
569 const QString tag = e.tagName();
577 if (
equalstr(tag, base.tagName()) &&
578 e.attribute(attrName) == base.attribute(attrName)) {
584 return QDomElement();
589 d->m_buildDocument = doc;
594 return d->m_buildDocument;
614 if ( child->d->m_parent )
615 child->d->m_parent->removeChildClient( child );
616 d->m_children.append( child );
617 child->d->m_parent =
this;
622 assert( d->m_children.contains( child ) );
623 d->m_children.removeAll( child );
624 child->d->m_parent = 0;
637 return d->m_children;
642 d->m_builder = builder;
657 d->m_factory->plugActionList(
this, name, actionList );
665 d->m_factory->unplugActionList(
this, name );
670 KXmlGuiVersionHandler versionHandler(files);
671 doc = versionHandler.finalDocument();
672 return versionHandler.finalFile();
683 d->m_actionsStateMap.insert( state, stateChange );
695 d->m_actionsStateMap.insert( state, stateChange );
701 return d->m_actionsStateMap[state];
710 bool setFalse = !setTrue;
714 for ( QStringList::const_iterator it = stateChange.
actionsToEnable.constBegin();
718 if (action) action->setEnabled(setTrue);
723 for ( QStringList::const_iterator it = stateChange.
actionsToDisable.constBegin();
727 if (action) action->setEnabled(setFalse);