22 #include "kxmlguifactory_p.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>
47 using namespace KXMLGUI;
49 class KXMLGUIFactoryPrivate :
public BuildState
52 enum ShortcutOption { SetActiveShortcut = 1, SetDefaultShortcut = 2};
54 KXMLGUIFactoryPrivate()
60 m_rootNode =
new ContainerNode( 0L,
QString(), 0L );
61 m_defaultMergingName = defaultMergingName;
62 tagActionList = actionList;
65 ~KXMLGUIFactoryPrivate()
72 m_stateStack.push( *
this );
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 );
92 void applyShortcutScheme(
KXMLGUIClient *client,
const QList<QAction*>& actions,
const QDomDocument& scheme);
93 void refreshActionProperties(
KXMLGUIClient *client,
const QList<QAction*>& actions,
const QDomDocument& doc);
94 void saveDefaultActionProperties(
const QList<QAction*>& actions);
96 ContainerNode *m_rootNode;
108 QList<KXMLGUIClient*> m_clients;
114 BuildStateStack m_stateStack;
121 if (!QDir::isRelativePath(filename))
127 if ( !QFile::exists( xml_file ) )
131 QFile file( xml_file );
132 if ( xml_file.isEmpty() || !file.open( QIODevice::ReadOnly ) )
134 kError(240) <<
"No such XML file" << filename;
138 QByteArray buffer(file.readAll());
139 return QString::fromUtf8(buffer.constData(), buffer.size());
148 if (QDir::isRelativePath(xml_file))
151 QFile file( xml_file );
152 if ( xml_file.isEmpty() || !file.open( QIODevice::WriteOnly ) )
154 kError(240) <<
"Could not write to" << filename;
159 QTextStream ts(&file);
160 ts.setCodec( QTextCodec::codecForName(
"UTF-8" ) );
172 QDomNode n = node.firstChild();
173 while ( !n.isNull() )
175 if ( n.nodeType() == QDomNode::CommentNode )
179 node.removeChild( tmp );
191 :
QObject( parent ),d(new KXMLGUIFactoryPrivate)
193 d->builder = builder;
197 d->builderContainerTags = d->builder->containerTags();
198 d->builderCustomTags = d->builder->customTags();
214 if ( client->
factory() == this )
226 d->guiClient = client;
229 if ( !d->m_clients.contains( client ) )
230 d->m_clients.append( client );
232 kDebug(260) <<
"XMLGUI client already added " << client;
243 if ( doc.documentElement().isNull() )
246 QDomElement docElement = doc.documentElement();
248 d->m_rootNode->index = -1;
252 d->clientName = docElement.attribute( d->attrName );
255 if ( d->clientBuilder )
257 d->clientBuilderContainerTags = d->clientBuilder->containerTags();
258 d->clientBuilderCustomTags = d->clientBuilder->customTags();
262 d->clientBuilderContainerTags.clear();
263 d->clientBuilderCustomTags.clear();
271 BuildHelper( *d, d->m_rootNode ).build( docElement );
280 d->builder->finalizeGUI( d->guiClient );
283 d->BuildState::reset();
315 d->guiClient = client;
317 if ( doc.documentElement().isNull() )
330 return cg.
readEntry(
"Current Scheme",
"Default");
336 const QLatin1String tagActionProp(
"ActionProperties");
338 QDomElement e = doc.documentElement().firstChildElement();
339 for( ; !e.isNull(); e = e.nextSiblingElement() ) {
340 if (QString::compare(e.tagName(), tagActionProp, Qt::CaseInsensitive) == 0
341 && (e.attribute(
"scheme",
"Default") == schemeName) ) {
345 return QDomElement();
348 void KXMLGUIFactoryPrivate::refreshActionProperties(
KXMLGUIClient *client,
const QList<QAction*>& actions,
const QDomDocument& doc)
351 QDomDocument scheme = shortcutSchemeDoc(client);
352 applyShortcutScheme(client, actions, scheme);
356 if ( !actionPropElement.isNull() )
357 applyActionProperties( actionPropElement );
360 void KXMLGUIFactoryPrivate::saveDefaultActionProperties(
const QList<QAction *>& actions)
365 foreach (
QAction *action, actions) {
367 if (!action || action->property(
"_k_DefaultShortcut").isValid())
continue;
369 if (
KAction* kaction = qobject_cast<KAction*>(action)) {
380 kError(240) <<
"Shortcut for KAction " << kaction->objectName() << kaction->text() <<
"set with QShortcut::setShortcut()! See KAction documentation.";
381 kaction->setProperty(
"_k_DefaultShortcut", activeShortcut);
383 kaction->setProperty(
"_k_DefaultShortcut", defaultShortcut);
389 if ( !action->isSeparator() )
390 kError(240) <<
"Attempt to use QAction" << action->objectName() <<
"with KXMLGUIFactory!";
391 action->setProperty(
"_k_DefaultShortcut",
KShortcut());
399 kDebug(260) <<
"Changing shortcut scheme to" << scheme;
408 d->m_clients.removeAll( client );
416 if ( !client || client->
factory() != this )
423 d->m_clients.removeAll( client );
427 const QList<KXMLGUIClient*> childClients(client->
childClients());
437 d->guiClient = client;
438 d->clientName = client->
domDocument().documentElement().attribute( d->attrName );
447 if ( doc.documentElement().isNull() )
449 doc = client->
domDocument().cloneNode(
true ).toDocument();
453 d->m_rootNode->destruct( doc.documentElement(), *d );
456 d->BuildState::reset();
478 d->m_containerName = containerName;
479 d->guiClient = client;
481 QWidget *result = d->findRecursive( d->m_rootNode, useTagName );
484 d->m_containerName.clear();
493 return d->findRecursive( d->m_rootNode, tagName );
498 d->m_rootNode->reset();
500 d->m_rootNode->clearChildren();
505 if ( containerName.isEmpty() )
508 ContainerNode *
container = d->m_rootNode->findContainer( containerName, useTagName );
513 ContainerNode *parent = container->parent;
519 parent->removeChild( container );
522 QWidget *KXMLGUIFactoryPrivate::findRecursive( KXMLGUI::ContainerNode *node,
bool tag )
524 if ( ( ( !tag && node->name == m_containerName ) ||
525 ( tag && node->tagName == m_containerName ) ) &&
526 ( !guiClient || node->client == guiClient ) )
527 return node->container;
529 foreach (ContainerNode* child, node->children)
542 return str1.compare(QLatin1String(str2), Qt::CaseInsensitive) == 0;
546 return str1.compare(str2, Qt::CaseInsensitive) == 0;
550 QList<QWidget*> KXMLGUIFactoryPrivate::findRecursive( KXMLGUI::ContainerNode *node,
555 if (
equals(node->tagName, tagName) )
556 res.append( node->container );
558 foreach (KXMLGUI::ContainerNode* child, node->children)
559 res << findRecursive( child, tagName );
565 const QList<QAction*> &actionList )
568 d->guiClient = client;
569 d->actionListName =
name;
570 d->actionList = actionList;
571 d->clientName = client->
domDocument().documentElement().attribute( d->attrName );
573 d->m_rootNode->plugActionList( *d );
576 d->saveDefaultActionProperties(actionList);
577 d->refreshActionProperties(client, actionList, client->
domDocument());
579 d->BuildState::reset();
586 d->guiClient = client;
587 d->actionListName =
name;
588 d->clientName = client->
domDocument().documentElement().attribute( d->attrName );
590 d->m_rootNode->unplugActionList( *d );
592 d->BuildState::reset();
596 void KXMLGUIFactoryPrivate::applyActionProperties(
const QDomElement &actionPropElement,
597 ShortcutOption shortcutOption )
599 for (QDomElement e = actionPropElement.firstChildElement();
600 !e.isNull(); e = e.nextSiblingElement()) {
601 if ( !
equals(e.tagName(),
"action") )
604 QAction *action = guiClient->action( e );
608 configureAction( action, e.attributes(), shortcutOption );
612 void KXMLGUIFactoryPrivate::configureAction(
QAction *action,
const QDomNamedNodeMap &attributes,
613 ShortcutOption shortcutOption )
615 for ( uint i = 0; i < attributes.length(); i++ )
617 QDomAttr attr = attributes.item( i ).toAttr();
621 configureAction( action, attr, shortcutOption );
625 void KXMLGUIFactoryPrivate::configureAction(
QAction *action,
const QDomAttr &attribute,
626 ShortcutOption shortcutOption )
630 QString attrName = attribute.name();
632 if (
equals(attrName,
"accel") )
633 attrName = attrShortcut;
636 if (
equals(attrName,
"name") )
639 if (
equals(attrName,
"icon") ) {
640 action->setIcon(
KIcon( attribute.value() ) );
646 QVariant::Type propertyType = action->property( attrName.toLatin1() ).type();
648 if ( propertyType == QVariant::Int ) {
649 propertyValue =
QVariant( attribute.value().toInt() );
650 }
else if ( propertyType == QVariant::UInt ) {
651 propertyValue =
QVariant( attribute.value().toUInt() );
652 }
else if ( propertyType == QVariant::UserType && action->property( attrName.toLatin1() ).userType() == qMetaTypeId<KShortcut>() ) {
654 if (
KAction* ka = qobject_cast<KAction*>(action)) {
655 if (attrName==
"globalShortcut") {
660 if (shortcutOption & KXMLGUIFactoryPrivate::SetDefaultShortcut)
664 propertyValue =
KShortcut( attribute.value() );
666 propertyValue =
QVariant( attribute.value() );
668 if (!action->setProperty( attrName.toLatin1(), propertyValue )) {
669 kWarning() <<
"Error: Unknown action property " << attrName <<
" will be ignored!";
673 QDomDocument KXMLGUIFactoryPrivate::shortcutSchemeDoc(
KXMLGUIClient *client)
680 if (schemeName !=
"Default")
688 QFile schemeFile(schemeFileName);
689 if (schemeFile.open(QIODevice::ReadOnly))
692 doc.setContent(&schemeFile);
699 void KXMLGUIFactoryPrivate::applyShortcutScheme(
KXMLGUIClient *client,
const QList<QAction*> &actions,
const QDomDocument& scheme)
707 if (schemeName !=
"Default") {
708 foreach (
QAction *action, actions) {
709 if (
KAction *kaction = qobject_cast<KAction*>(action)) {
716 action->setProperty(
"shortcut",
KShortcut());
721 foreach (
QAction *action, actions) {
722 if (
KAction *kaction = qobject_cast<KAction*>(action)) {
723 QVariant savedDefaultShortcut = kaction->property(
"_k_DefaultShortcut");
724 if (savedDefaultShortcut.isValid()) {
733 action->setProperty(
"shortcut",
KShortcut());
741 QDomElement docElement = scheme.documentElement();
742 QDomElement actionPropElement = docElement.namedItem( actionPropElementName ).toElement();
745 if (!actionPropElement.isNull()) {
749 applyActionProperties(actionPropElement, KXMLGUIFactoryPrivate::SetDefaultShortcut);
751 kDebug(260) <<
"Invalid shortcut scheme file";
759 qobject_cast<QWidget*>(parent()));
776 elem = doc.createElement(QLatin1String(
"ActionProperties"));
778 doc.documentElement().appendChild( elem );
787 for( QDomNode it = elem.firstChild(); !it.isNull(); it = it.nextSibling() ) {
788 QDomElement e = it.toElement();
789 if( e.attribute( attrName ) == sName )
794 QDomElement act_elem = elem.ownerDocument().createElement( tagAction );
795 act_elem.setAttribute( attrName, sName );
796 elem.appendChild( act_elem );
799 return QDomElement();
802 #include "kxmlguifactory.moc"