summaryrefslogtreecommitdiffstats
path: root/kdeui/kxmlguifactory.cpp
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch)
tree5ac38a06f3dde268dc7927dc155896926aaf7012 /kdeui/kxmlguifactory.cpp
downloadtdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz
tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kdeui/kxmlguifactory.cpp')
-rw-r--r--kdeui/kxmlguifactory.cpp614
1 files changed, 614 insertions, 0 deletions
diff --git a/kdeui/kxmlguifactory.cpp b/kdeui/kxmlguifactory.cpp
new file mode 100644
index 000000000..1dbab4ddf
--- /dev/null
+++ b/kdeui/kxmlguifactory.cpp
@@ -0,0 +1,614 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999,2000 Simon Hausmann <hausmann@kde.org>
+ Copyright (C) 2000 Kurt Granroth <granroth@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kxmlguifactory.h"
+#include "kxmlguifactory_p.h"
+#include "kxmlguiclient.h"
+#include "kxmlguibuilder.h"
+
+#include <assert.h>
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qwidget.h>
+#include <qdatetime.h>
+#include <qvariant.h>
+
+#include <kaction.h>
+#include <kdebug.h>
+#include <kinstance.h>
+#include <kglobal.h>
+#include <kshortcut.h>
+#include <kstandarddirs.h>
+#include <kkeydialog.h>
+
+using namespace KXMLGUI;
+
+/*
+ * TODO: - make more use of QValueList instead of QPtrList
+ */
+
+class KXMLGUIFactoryPrivate : public BuildState
+{
+public:
+ KXMLGUIFactoryPrivate()
+ {
+ static const QString &defaultMergingName = KGlobal::staticQString( "<default>" );
+ static const QString &actionList = KGlobal::staticQString( "actionlist" );
+ static const QString &name = KGlobal::staticQString( "name" );
+
+ m_rootNode = new ContainerNode( 0L, QString::null, 0L );
+ m_defaultMergingName = defaultMergingName;
+ tagActionList = actionList;
+ attrName = name;
+ }
+ ~KXMLGUIFactoryPrivate()
+ {
+ delete m_rootNode;
+ }
+
+ void pushState()
+ {
+ m_stateStack.push( *this );
+ }
+
+ void popState()
+ {
+ BuildState::operator=( m_stateStack.pop() );
+ }
+
+ ContainerNode *m_rootNode;
+
+ QString m_defaultMergingName;
+
+ /*
+ * Contains the container which is searched for in ::container .
+ */
+ QString m_containerName;
+
+ /*
+ * List of all clients
+ */
+ QPtrList<KXMLGUIClient> m_clients;
+
+ QString tagActionList;
+
+ QString attrName;
+
+ BuildStateStack m_stateStack;
+};
+
+QString KXMLGUIFactory::readConfigFile( const QString &filename, const KInstance *instance )
+{
+ return readConfigFile( filename, false, instance );
+}
+
+QString KXMLGUIFactory::readConfigFile( const QString &filename, bool never_null, const KInstance *_instance )
+{
+ const KInstance *instance = _instance ? _instance : KGlobal::instance();
+ QString xml_file;
+
+ if (!QDir::isRelativePath(filename))
+ xml_file = filename;
+ else
+ {
+ xml_file = locate("data", QString::fromLatin1(instance->instanceName() + '/' ) + filename);
+ if ( !QFile::exists( xml_file ) )
+ xml_file = locate( "data", filename );
+ }
+
+ QFile file( xml_file );
+ if ( !file.open( IO_ReadOnly ) )
+ {
+ kdError(240) << "No such XML file " << filename << endl;
+ if ( never_null )
+ return QString::fromLatin1( "<!DOCTYPE kpartgui>\n<kpartgui name=\"empty\">\n</kpartgui>" );
+ else
+ return QString::null;
+ }
+
+#if QT_VERSION <= 0x030302
+ // Work around bug in QString::fromUtf8 (which calls strlen).
+ QByteArray buffer(file.size() + 1);
+ buffer = file.readAll();
+ if(!buffer.isEmpty())
+ buffer[ buffer.size() - 1 ] = '\0';
+ else
+ return QString::null;
+#else
+ QByteArray buffer(file.readAll());
+#endif
+ return QString::fromUtf8(buffer.data(), buffer.size());
+}
+
+bool KXMLGUIFactory::saveConfigFile( const QDomDocument& doc,
+ const QString& filename, const KInstance *_instance )
+{
+ const KInstance *instance = _instance ? _instance : KGlobal::instance();
+ QString xml_file(filename);
+
+ if (QDir::isRelativePath(xml_file))
+ xml_file = locateLocal("data", QString::fromLatin1( instance->instanceName() + '/' )
+ + filename);
+
+ QFile file( xml_file );
+ if ( !file.open( IO_WriteOnly ) )
+ {
+ kdError(240) << "Could not write to " << filename << endl;
+ return false;
+ }
+
+ // write out our document
+ QTextStream ts(&file);
+ ts.setEncoding( QTextStream::UnicodeUTF8 );
+ ts << doc;
+
+ file.close();
+ return true;
+}
+
+QString KXMLGUIFactory::documentToXML( const QDomDocument& doc )
+{
+ QString str;
+ QTextStream ts(&str, IO_WriteOnly);
+ ts.setEncoding( QTextStream::UnicodeUTF8 );
+ ts << doc;
+ return str;
+}
+
+QString KXMLGUIFactory::elementToXML( const QDomElement& elem )
+{
+ QString str;
+ QTextStream ts(&str, IO_WriteOnly);
+ ts.setEncoding( QTextStream::UnicodeUTF8 );
+ ts << elem;
+ return str;
+}
+
+void KXMLGUIFactory::removeDOMComments( QDomNode &node )
+{
+ QDomNode n = node.firstChild();
+ while ( !n.isNull() )
+ {
+ if ( n.nodeType() == QDomNode::CommentNode )
+ {
+ QDomNode tmp = n;
+ n = n.nextSibling();
+ node.removeChild( tmp );
+ }
+ else
+ {
+ QDomNode tmp = n;
+ n = n.nextSibling();
+ removeDOMComments( tmp );
+ }
+ }
+}
+
+KXMLGUIFactory::KXMLGUIFactory( KXMLGUIBuilder *builder, QObject *parent, const char *name )
+ : QObject( parent, name )
+{
+ d = new KXMLGUIFactoryPrivate;
+ d->builder = builder;
+ d->guiClient = 0;
+ if ( d->builder )
+ {
+ d->builderContainerTags = d->builder->containerTags();
+ d->builderCustomTags = d->builder->customTags();
+ }
+}
+
+KXMLGUIFactory::~KXMLGUIFactory()
+{
+ delete d;
+}
+
+void KXMLGUIFactory::addClient( KXMLGUIClient *client )
+{
+ kdDebug(1002) << "KXMLGUIFactory::addClient( " << client << " )" << endl; // ellis
+ static const QString &actionPropElementName = KGlobal::staticQString( "ActionProperties" );
+
+ if ( client->factory() ) {
+ if ( client->factory() == this )
+ return;
+ else
+ client->factory()->removeClient( client ); //just in case someone does stupid things ;-)
+ }
+
+ d->pushState();
+
+// QTime dt; dt.start();
+
+ d->guiClient = client;
+
+ // add this client to our client list
+ if ( !d->m_clients.containsRef( client ) )
+ d->m_clients.append( client );
+ else
+ kdDebug(1002) << "XMLGUI client already added " << client << endl;
+
+ // Tell the client that plugging in is process and
+ // let it know what builder widget its mainwindow shortcuts
+ // should be attached to.
+ client->beginXMLPlug( d->builder->widget() );
+
+ // try to use the build document for building the client's GUI, as the build document
+ // contains the correct container state information (like toolbar positions, sizes, etc.) .
+ // if there is non available, then use the "real" document.
+ QDomDocument doc = client->xmlguiBuildDocument();
+ if ( doc.documentElement().isNull() )
+ doc = client->domDocument();
+
+ QDomElement docElement = doc.documentElement();
+
+ d->m_rootNode->index = -1;
+
+ // cache some variables
+
+ d->clientName = docElement.attribute( d->attrName );
+ d->clientBuilder = client->clientBuilder();
+
+ if ( d->clientBuilder )
+ {
+ d->clientBuilderContainerTags = d->clientBuilder->containerTags();
+ d->clientBuilderCustomTags = d->clientBuilder->customTags();
+ }
+ else
+ {
+ d->clientBuilderContainerTags.clear();
+ d->clientBuilderCustomTags.clear();
+ }
+
+ // process a possibly existing actionproperties section
+
+ QDomElement actionPropElement = docElement.namedItem( actionPropElementName ).toElement();
+ if ( actionPropElement.isNull() )
+ actionPropElement = docElement.namedItem( actionPropElementName.lower() ).toElement();
+
+ if ( !actionPropElement.isNull() )
+ applyActionProperties( actionPropElement );
+
+ BuildHelper( *d, d->m_rootNode ).build( docElement );
+
+ // let the client know that we built its GUI.
+ client->setFactory( this );
+
+ // call the finalizeGUI method, to fix up the positions of toolbars for example.
+ // ### FIXME : obey client builder
+ // --- Well, toolbars have a bool "positioned", so it doesn't really matter,
+ // if we call positionYourself on all of them each time. (David)
+ d->builder->finalizeGUI( d->guiClient );
+
+ // reset some variables, for safety
+ d->BuildState::reset();
+
+ client->endXMLPlug();
+
+ d->popState();
+
+ emit clientAdded( client );
+
+ // build child clients
+ if ( client->childClients()->count() > 0 )
+ {
+ const QPtrList<KXMLGUIClient> *children = client->childClients();
+ QPtrListIterator<KXMLGUIClient> childIt( *children );
+ for (; childIt.current(); ++childIt )
+ addClient( childIt.current() );
+ }
+
+// kdDebug() << "addClient took " << dt.elapsed() << endl;
+}
+
+void KXMLGUIFactory::removeClient( KXMLGUIClient *client )
+{
+ kdDebug(1002) << "KXMLGUIFactory::removeClient( " << client << " )" << endl; // ellis
+
+ // don't try to remove the client's GUI if we didn't build it
+ if ( !client || client->factory() != this )
+ return;
+
+ // remove this client from our client list
+ d->m_clients.removeRef( client );
+
+ // remove child clients first
+ if ( client->childClients()->count() > 0 )
+ {
+ const QPtrList<KXMLGUIClient> *children = client->childClients();
+ QPtrListIterator<KXMLGUIClient> childIt( *children );
+ childIt.toLast();
+ for (; childIt.current(); --childIt )
+ removeClient( childIt.current() );
+ }
+
+ kdDebug(1002) << "KXMLGUIFactory::removeServant, calling removeRecursive" << endl;
+
+ d->pushState();
+
+ // cache some variables
+
+ d->guiClient = client;
+ d->clientName = client->domDocument().documentElement().attribute( d->attrName );
+ d->clientBuilder = client->clientBuilder();
+
+ client->setFactory( 0L );
+
+ // if we don't have a build document for that client, yet, then create one by
+ // cloning the original document, so that saving container information in the
+ // DOM tree does not touch the original document.
+ QDomDocument doc = client->xmlguiBuildDocument();
+ if ( doc.documentElement().isNull() )
+ {
+ doc = client->domDocument().cloneNode( true ).toDocument();
+ client->setXMLGUIBuildDocument( doc );
+ }
+
+ d->m_rootNode->destruct( doc.documentElement(), *d );
+
+ d->builder->finalizeGUI( d->guiClient ); //JoWenn
+
+ // reset some variables
+ d->BuildState::reset();
+
+ // This will destruct the KAccel object built around the given widget.
+ client->prepareXMLUnplug( d->builder->widget() );
+
+ d->popState();
+
+ emit clientRemoved( client );
+}
+
+QPtrList<KXMLGUIClient> KXMLGUIFactory::clients() const
+{
+ return d->m_clients;
+}
+
+QWidget *KXMLGUIFactory::container( const QString &containerName, KXMLGUIClient *client,
+ bool useTagName )
+{
+ d->pushState();
+ d->m_containerName = containerName;
+ d->guiClient = client;
+
+ QWidget *result = findRecursive( d->m_rootNode, useTagName );
+
+ d->guiClient = 0L;
+ d->m_containerName = QString::null;
+
+ d->popState();
+
+ return result;
+}
+
+QPtrList<QWidget> KXMLGUIFactory::containers( const QString &tagName )
+{
+ return findRecursive( d->m_rootNode, tagName );
+}
+
+void KXMLGUIFactory::reset()
+{
+ d->m_rootNode->reset();
+
+ d->m_rootNode->clearChildren();
+}
+
+void KXMLGUIFactory::resetContainer( const QString &containerName, bool useTagName )
+{
+ if ( containerName.isEmpty() )
+ return;
+
+ ContainerNode *container = d->m_rootNode->findContainer( containerName, useTagName );
+
+ if ( !container )
+ return;
+
+ ContainerNode *parent = container->parent;
+ if ( !parent )
+ return;
+
+ // resetInternal( container );
+
+ parent->removeChild( container );
+}
+
+QWidget *KXMLGUIFactory::findRecursive( KXMLGUI::ContainerNode *node, bool tag )
+{
+ if ( ( ( !tag && node->name == d->m_containerName ) ||
+ ( tag && node->tagName == d->m_containerName ) ) &&
+ ( !d->guiClient || node->client == d->guiClient ) )
+ return node->container;
+
+ QPtrListIterator<ContainerNode> it( node->children );
+ for (; it.current(); ++it )
+ {
+ QWidget *cont = findRecursive( it.current(), tag );
+ if ( cont )
+ return cont;
+ }
+
+ return 0L;
+}
+
+QPtrList<QWidget> KXMLGUIFactory::findRecursive( KXMLGUI::ContainerNode *node,
+ const QString &tagName )
+{
+ QPtrList<QWidget> res;
+
+ if ( node->tagName == tagName.lower() )
+ res.append( node->container );
+
+ QPtrListIterator<KXMLGUI::ContainerNode> it( node->children );
+ for (; it.current(); ++it )
+ {
+ QPtrList<QWidget> lst = findRecursive( it.current(), tagName );
+ QPtrListIterator<QWidget> wit( lst );
+ for (; wit.current(); ++wit )
+ res.append( wit.current() );
+ }
+
+ return res;
+}
+
+void KXMLGUIFactory::plugActionList( KXMLGUIClient *client, const QString &name,
+ const QPtrList<KAction> &actionList )
+{
+ d->pushState();
+ d->guiClient = client;
+ d->actionListName = name;
+ d->actionList = actionList;
+ d->clientName = client->domDocument().documentElement().attribute( d->attrName );
+
+ d->m_rootNode->plugActionList( *d );
+
+ d->BuildState::reset();
+ d->popState();
+}
+
+void KXMLGUIFactory::unplugActionList( KXMLGUIClient *client, const QString &name )
+{
+ d->pushState();
+ d->guiClient = client;
+ d->actionListName = name;
+ d->clientName = client->domDocument().documentElement().attribute( d->attrName );
+
+ d->m_rootNode->unplugActionList( *d );
+
+ d->BuildState::reset();
+ d->popState();
+}
+
+void KXMLGUIFactory::applyActionProperties( const QDomElement &actionPropElement )
+{
+ static const QString &tagAction = KGlobal::staticQString( "action" );
+
+ for (QDomNode n = actionPropElement.firstChild();
+ !n.isNull(); n = n.nextSibling() )
+ {
+ QDomElement e = n.toElement();
+ if ( e.tagName().lower() != tagAction )
+ continue;
+
+ KAction *action = d->guiClient->action( e );
+ if ( !action )
+ continue;
+
+ configureAction( action, e.attributes() );
+ }
+}
+
+void KXMLGUIFactory::configureAction( KAction *action, const QDomNamedNodeMap &attributes )
+{
+ for ( uint i = 0; i < attributes.length(); i++ )
+ {
+ QDomAttr attr = attributes.item( i ).toAttr();
+ if ( attr.isNull() )
+ continue;
+
+ configureAction( action, attr );
+ }
+}
+
+void KXMLGUIFactory::configureAction( KAction *action, const QDomAttr &attribute )
+{
+ static const QString &attrShortcut = KGlobal::staticQString( "shortcut" );
+
+ QString attrName = attribute.name();
+ // If the attribute is a deprecated "accel", change to "shortcut".
+ if ( attrName.lower() == "accel" )
+ attrName = attrShortcut;
+
+ QVariant propertyValue;
+
+ QVariant::Type propertyType = action->property( attrName.latin1() ).type();
+
+ if ( propertyType == QVariant::Int )
+ propertyValue = QVariant( attribute.value().toInt() );
+ else if ( propertyType == QVariant::UInt )
+ propertyValue = QVariant( attribute.value().toUInt() );
+ else
+ propertyValue = QVariant( attribute.value() );
+
+ action->setProperty( attrName.latin1(), propertyValue );
+}
+
+
+int KXMLGUIFactory::configureShortcuts(bool bAllowLetterShortcuts , bool bSaveSettings )
+{
+ KKeyDialog dlg( bAllowLetterShortcuts, dynamic_cast<QWidget*>(parent()) );
+ QPtrListIterator<KXMLGUIClient> it( d->m_clients );
+ KXMLGUIClient *client;
+ while( (client=it.current()) !=0 )
+ {
+ ++it;
+ if(!client->xmlFile().isEmpty())
+ dlg.insert( client->actionCollection() );
+ }
+ return dlg.configure(bSaveSettings);
+}
+
+QDomElement KXMLGUIFactory::actionPropertiesElement( QDomDocument& doc )
+{
+ const QString tagActionProp = QString::fromLatin1("ActionProperties");
+ // first, lets see if we have existing properties
+ QDomElement elem;
+ QDomNode it = doc.documentElement().firstChild();
+ for( ; !it.isNull(); it = it.nextSibling() ) {
+ QDomElement e = it.toElement();
+ if( e.tagName() == tagActionProp ) {
+ elem = e;
+ break;
+ }
+ }
+
+ // if there was none, create one
+ if( elem.isNull() ) {
+ elem = doc.createElement( tagActionProp );
+ doc.documentElement().appendChild( elem );
+ }
+ return elem;
+}
+
+QDomElement KXMLGUIFactory::findActionByName( QDomElement& elem, const QString& sName, bool create )
+{
+ static const QString& attrName = KGlobal::staticQString( "name" );
+ static const QString& tagAction = KGlobal::staticQString( "Action" );
+ for( QDomNode it = elem.firstChild(); !it.isNull(); it = it.nextSibling() ) {
+ QDomElement e = it.toElement();
+ if( e.attribute( attrName ) == sName )
+ return e;
+ }
+
+ if( create ) {
+ QDomElement act_elem = elem.ownerDocument().createElement( tagAction );
+ act_elem.setAttribute( attrName, sName );
+ elem.appendChild( act_elem );
+ return act_elem;
+ }
+ return QDomElement();
+}
+
+void KXMLGUIFactory::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "kxmlguifactory.moc"
+
+/* vim: et sw=4
+ */