kxmlguifactory.cpp Source File (kdeui Library)

| # kdeui Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# kxmlguifactory.cpp

    00001 /* This file is part of the KDE libraries
    00002    Copyright (C) 1999,2000 Simon Hausmann <hausmann@kde.org>
    00003    Copyright (C) 2000 Kurt Granroth <granroth@kde.org>
    00004
    00005    This library is free software; you can redistribute it and/or
    00006    modify it under the terms of the GNU Library General Public
    00007    License as published by the Free Software Foundation; either
    00008    version 2 of the License, or (at your option) any later version.
    00009
    00010    This library is distributed in the hope that it will be useful,
    00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00013    Library General Public License for more details.
    00014
    00015    You should have received a copy of the GNU Library General Public License
    00016    along with this library; see the file COPYING.LIB.  If not, write to
    00017    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00018    Boston, MA 02111-1307, USA.
    00019 */
    00020
    00021 #include "kxmlguifactory.h"
    00022 #include "kxmlguifactory_p.h"
    00023 #include "kxmlguiclient.h"
    00024 #include "kxmlguibuilder.h"
    00025
    00026 #include <assert.h>
    00027
    00028 #include <qfile.h>
    00029 #include <qtextstream.h>
    00030 #include <qwidget.h>
    00031 #include <qdatetime.h>
    00032 #include <qvariant.h>
    00033
    00034 #include <kaction.h>
    00035 #include <kdebug.h>
    00036 #include <kinstance.h>
    00037 #include <kglobal.h>
    00038 #include <kshortcut.h>
    00039 #include <kstandarddirs.h>
    00040
    00041 using namespace KXMLGUI;
    00042
    00043 /*
    00044  * TODO:     - make more use of QValueList instead of QPtrList
    00045  */
    00046
    00047 class KXMLGUIFactoryPrivate : public BuildState
    00048 {
    00049 public:
    00050     KXMLGUIFactoryPrivate()
    00051     {
    00052         static const QString &defaultMergingName = KGlobal::staticQString( "<default>" );
    00053         static const QString &actionList = KGlobal::staticQString( "actionlist" );
    00054         static const QString &name = KGlobal::staticQString( "name" );
    00055
    00056         m_rootNode = new ContainerNode( 0L, QString::null, 0L );
    00057         m_defaultMergingName = defaultMergingName;
    00058         tagActionList = actionList;
    00059         attrName = name;
    00060     }
    00061     ~KXMLGUIFactoryPrivate()
    00062     {
    00063         delete m_rootNode;
    00064     }
    00065
    00066     void pushState()
    00067     {
    00068         m_stateStack.push( *this );
    00069     }
    00070
    00071     void popState()
    00072     {
    00073         BuildState::operator=( m_stateStack.pop() );
    00074     }
    00075
    00076     ContainerNode *m_rootNode;
    00077
    00078     QString m_defaultMergingName;
    00079
    00080     /*
    00081      * Contains the container which is searched for in ::container .
    00082      */
    00083     QString m_containerName;
    00084
    00085     /*
    00086      * List of all clients
    00087      */
    00088     QPtrList<KXMLGUIClient> m_clients;
    00089
    00090     QString tagActionList;
    00091
    00092     QString attrName;
    00093
    00094     BuildStateStack m_stateStack;
    00095 };
    00096
    00097 QString KXMLGUIFactory::readConfigFile( const QString &filename, const KInstance *instance )
    00098 {
    00099     return readConfigFile( filename, false, instance );
    00100 }
    00101
    00102 QString KXMLGUIFactory::readConfigFile( const QString &filename, bool never_null, const KInstance *_instance )
    00103 {
    00104     const KInstance *instance = _instance ? _instance : KGlobal::instance();
    00105     QString xml_file;
    00106
    00107     if (filename[0] == '/')
    00108         xml_file = filename;
    00109     else
    00110     {
    00111         xml_file = locate("data", QString::fromLatin1(instance->instanceName() + '/' ) + filename);
    00112         if ( !QFile::exists( xml_file ) )
    00113           xml_file = locate( "data", filename );
    00114     }
    00115
    00116     QFile file( xml_file );
    00117     if ( !file.open( IO_ReadOnly ) )
    00118     {
    00119         kdError(1000) << "No such XML file " << filename << endl;
    00120         if ( never_null )
    00121             return QString::fromLatin1( "<!DOCTYPE kpartgui>\n<kpartgui name=\"empty\">\n</kpartgui>" );
    00122         else
    00123             return QString::null;
    00124     }
    00125
    00126     QByteArray buffer(file.readAll());
    00127     return QString::fromUtf8(buffer.data(), buffer.size());
    00128 }
    00129
    00130 bool KXMLGUIFactory::saveConfigFile( const QDomDocument& doc,
    00131                                      const QString& filename, const KInstance *_instance )
    00132 {
    00133     const KInstance *instance = _instance ? _instance : KGlobal::instance();
    00134     QString xml_file(filename);
    00135
    00136     if (xml_file[0] != '/')
    00137         xml_file = locateLocal("data", QString::fromLatin1( instance->instanceName() + '/' )
    00138                                + filename);
    00139
    00140     QFile file( xml_file );
    00141     if ( !file.open( IO_WriteOnly ) )
    00142     {
    00143         kdError(1000) << "Could not write to " << filename << endl;
    00144         return false;
    00145     }
    00146
    00147     // write out our document
    00148     QTextStream ts(&file);
    00149     ts.setEncoding( QTextStream::UnicodeUTF8 );
    00150     ts << doc;
    00151
    00152     file.close();
    00153     return true;
    00154 }
    00155
    00156 QString KXMLGUIFactory::documentToXML( const QDomDocument& doc )
    00157 {
    00158     QString str;
    00159     QTextStream ts(&str, IO_WriteOnly);
    00160     ts.setEncoding( QTextStream::UnicodeUTF8 );
    00161     ts << doc;
    00162     return str;
    00163 }
    00164
    00165 QString KXMLGUIFactory::elementToXML( const QDomElement& elem )
    00166 {
    00167     QString str;
    00168     QTextStream ts(&str, IO_WriteOnly);
    00169     ts.setEncoding( QTextStream::UnicodeUTF8 );
    00170     ts << elem;
    00171     return str;
    00172 }
    00173
    00174 void KXMLGUIFactory::removeDOMComments( QDomNode &node )
    00175 {
    00176     QDomNode n = node.firstChild();
    00177     while ( !n.isNull() )
    00178     {
    00179         if ( n.nodeType() == QDomNode::CommentNode )
    00180         {
    00181             QDomNode tmp = n;
    00182             n = n.nextSibling();
    00183             node.removeChild( tmp );
    00184         }
    00185         else
    00186         {
    00187             QDomNode tmp = n;
    00188             n = n.nextSibling();
    00189             removeDOMComments( tmp );
    00190         }
    00191     }
    00192 }
    00193
    00194 KXMLGUIFactory::KXMLGUIFactory( KXMLGUIBuilder *builder, QObject *parent, const char *name )
    00195     : QObject( parent, name )
    00196 {
    00197     d = new KXMLGUIFactoryPrivate;
    00198     d->builder = builder;
    00199     d->guiClient = 0;
    00200     if ( d->builder )
    00201     {
    00202         d->builderContainerTags = d->builder->containerTags();
    00203         d->builderCustomTags = d->builder->customTags();
    00204     }
    00205 }
    00206
    00207 KXMLGUIFactory::~KXMLGUIFactory()
    00208 {
    00209     delete d;
    00210 }
    00211
    00212 void KXMLGUIFactory::addClient( KXMLGUIClient *client )
    00213 {
    00214     kdDebug(129) << "KXMLGUIFactory::addClient( " << client << " )" << endl; // ellis
    00215     static const QString &actionPropElementName = KGlobal::staticQString( "ActionProperties" );
    00216
    00217     d->pushState();
    00218
    00219 //    QTime dt; dt.start();
    00220
    00221     d->guiClient = client;
    00222
    00223     if ( client->factory() && client->factory() != this )
    00224         client->factory()->removeClient( client ); //just in case someone does stupid things ;-)
    00225
    00226     // add this client to our client list
    00227     if ( d->m_clients.containsRef( client ) == 0 )
    00228         d->m_clients.append( client );
    00229     else
    00230         kdDebug(129) << "XMLGUI client already added " << client << endl;
    00231
    00232     // Tell the client that plugging in is process and
    00233     //  let it know what builder widget its mainwindow shortcuts
    00234     //  should be attached to.
    00235     client->beginXMLPlug( d->builder->widget() );
    00236
    00237     // try to use the build document for building the client's GUI, as the build document
    00238     // contains the correct container state information (like toolbar positions, sizes, etc.) .
    00239     // if there is non available, then use the "real" document.
    00240     QDomDocument doc = client->xmlguiBuildDocument();
    00241     if ( doc.documentElement().isNull() )
    00242         doc = client->domDocument();
    00243
    00244     QDomElement docElement = doc.documentElement();
    00245
    00246     d->m_rootNode->index = -1;
    00247
    00248     // cache some variables
    00249
    00250     d->clientName = docElement.attribute( d->attrName );
    00251     d->clientBuilder = client->clientBuilder();
    00252
    00253     if ( d->clientBuilder )
    00254     {
    00255         d->clientBuilderContainerTags = d->clientBuilder->containerTags();
    00256         d->clientBuilderCustomTags = d->clientBuilder->customTags();
    00257     }
    00258     else
    00259     {
    00260         d->clientBuilderContainerTags.clear();
    00261         d->clientBuilderCustomTags.clear();
    00262     }
    00263
    00264     // process a possibly existing actionproperties section
    00265
    00266     QDomElement actionPropElement = docElement.namedItem( actionPropElementName ).toElement();
    00267     if ( actionPropElement.isNull() )
    00268         actionPropElement = docElement.namedItem( actionPropElementName.lower() ).toElement();
    00269
    00270     if ( !actionPropElement.isNull() )
    00271         applyActionProperties( actionPropElement );
    00272
    00273     BuildHelper( *d, d->m_rootNode ).build( docElement );
    00274
    00275     // let the client know that we built its GUI.
    00276     client->setFactory( this );
    00277
    00278     // call the finalizeGUI method, to fix up the positions of toolbars for example.
    00279     // ### FIXME : obey client builder
    00280     // --- Well, toolbars have a bool "positioned", so it doesn't really matter,
    00281     // if we call positionYourself on all of them each time. (David)
    00282     d->builder->finalizeGUI( d->guiClient );
    00283
    00284     // reset some variables, for safety
    00285     d->BuildState::reset();
    00286
    00287     client->endXMLPlug();
    00288
    00289     d->popState();
    00290
    00291     emit clientAdded( client );
    00292
    00293     // build child clients
    00294     if ( client->childClients()->count() > 0 )
    00295     {
    00296         const QPtrList<KXMLGUIClient> *children = client->childClients();
    00297         QPtrListIterator<KXMLGUIClient> childIt( *children );
    00298         for (; childIt.current(); ++childIt )
    00299             addClient( childIt.current() );
    00300     }
    00301
    00302 //    kdDebug() << "addClient took " << dt.elapsed() << endl;
    00303 }
    00304
    00305 void KXMLGUIFactory::removeClient( KXMLGUIClient *client )
    00306 {
    00307     kdDebug(129) << "KXMLGUIFactory::removeClient( " << client << " )" << endl; // ellis
    00308
    00309     // don't try to remove the client's GUI if we didn't build it
    00310     if ( !client || client->factory() != this )
    00311         return;
    00312
    00313     // remove this client from our client list
    00314     d->m_clients.removeRef( client );
    00315
    00316     // remove child clients first
    00317     if ( client->childClients()->count() > 0 )
    00318     {
    00319         const QPtrList<KXMLGUIClient> *children = client->childClients();
    00320         QPtrListIterator<KXMLGUIClient> childIt( *children );
    00321         for (; childIt.current(); ++childIt )
    00322             removeClient( childIt.current() );
    00323     }
    00324
    00325     kdDebug(1002) << "KXMLGUIFactory::removeServant, calling removeRecursive" << endl;
    00326
    00327     d->pushState();
    00328
    00329     // cache some variables
    00330
    00331     d->guiClient = client;
    00332     d->clientName = client->domDocument().documentElement().attribute( d->attrName );
    00333     d->clientBuilder = client->clientBuilder();
    00334
    00335     client->setFactory( 0L );
    00336
    00337     // if we don't have a build document for that client, yet, then create one by
    00338     // cloning the original document, so that saving container information in the
    00339     // DOM tree does not touch the original document.
    00340     QDomDocument doc = client->xmlguiBuildDocument();
    00341     if ( doc.documentElement().isNull() )
    00342     {
    00343         doc = client->domDocument().cloneNode( true ).toDocument();
    00344         client->setXMLGUIBuildDocument( doc );
    00345     }
    00346
    00347     d->m_rootNode->destruct( doc.documentElement(), *d );
    00348
    00349     d->builder->finalizeGUI( d->guiClient ); //JoWenn
    00350
    00351     // reset some variables
    00352     d->BuildState::reset();
    00353
    00354     // This will destruct the KAccel object built around the given widget.
    00355     client->prepareXMLUnplug( d->builder->widget() );
    00356
    00357     d->popState();
    00358
    00359     emit clientRemoved( client );
    00360 }
    00361
    00362 QPtrList<KXMLGUIClient> KXMLGUIFactory::clients() const
    00363 {
    00364     return d->m_clients;
    00365 }
    00366
    00367 QWidget *KXMLGUIFactory::container( const QString &containerName, KXMLGUIClient *client,
    00368                                     bool useTagName )
    00369 {
    00370     d->pushState();
    00371     d->m_containerName = containerName;
    00372     d->guiClient = client;
    00373
    00374     QWidget *result = findRecursive( d->m_rootNode, useTagName );
    00375
    00376     d->guiClient = 0L;
    00377     d->m_containerName = QString::null;
    00378
    00379     d->popState();
    00380
    00381     return result;
    00382 }
    00383
    00384 QPtrList<QWidget> KXMLGUIFactory::containers( const QString &tagName )
    00385 {
    00386     return findRecursive( d->m_rootNode, tagName );
    00387 }
    00388
    00389 void KXMLGUIFactory::reset()
    00390 {
    00391     d->m_rootNode->reset();
    00392
    00393     d->m_rootNode->clearChildren();
    00394 }
    00395
    00396 void KXMLGUIFactory::resetContainer( const QString &containerName, bool useTagName )
    00397 {
    00398     if ( containerName.isEmpty() )
    00399         return;
    00400
    00401     ContainerNode *container = d->m_rootNode->findContainer( containerName, useTagName );
    00402
    00403     if ( !container )
    00404         return;
    00405
    00406     ContainerNode *parent = container->parent;
    00407     if ( !parent )
    00408         return;
    00409
    00410     //  resetInternal( container );
    00411
    00412     parent->removeChild( container );
    00413 }
    00414
    00415 QWidget *KXMLGUIFactory::findRecursive( KXMLGUI::ContainerNode *node, bool tag )
    00416 {
    00417     if ( ( ( !tag && node->name == d->m_containerName ) ||
    00418            ( tag && node->tagName == d->m_containerName ) ) &&
    00419          ( !d->guiClient || node->client == d->guiClient ) )
    00420         return node->container;
    00421
    00422     QPtrListIterator<ContainerNode> it( node->children );
    00423     for (; it.current(); ++it )
    00424     {
    00425         QWidget *cont = findRecursive( it.current(), tag );
    00426         if ( cont )
    00427             return cont;
    00428     }
    00429
    00430     return 0L;
    00431 }
    00432
    00433 QPtrList<QWidget> KXMLGUIFactory::findRecursive( KXMLGUI::ContainerNode *node,
    00434                                                  const QString &tagName )
    00435 {
    00436     QPtrList<QWidget> res;
    00437
    00438     if ( node->tagName == tagName.lower() )
    00439         res.append( node->container );
    00440
    00441     QPtrListIterator<KXMLGUI::ContainerNode> it( node->children );
    00442     for (; it.current(); ++it )
    00443     {
    00444         QPtrList<QWidget> lst = findRecursive( it.current(), tagName );
    00445         QPtrListIterator<QWidget> wit( lst );
    00446         for (; wit.current(); ++wit )
    00447             res.append( wit.current() );
    00448     }
    00449
    00450     return res;
    00451 }
    00452
    00453 void KXMLGUIFactory::plugActionList( KXMLGUIClient *client, const QString &name,
    00454                                      const QPtrList<KAction> &actionList )
    00455 {
    00456     d->pushState();
    00457     d->guiClient = client;
    00458     d->actionListName = name;
    00459     d->actionList = actionList;
    00460     d->clientName = client->domDocument().documentElement().attribute( d->attrName );
    00461
    00462     d->m_rootNode->plugActionList( *d );
    00463
    00464     d->BuildState::reset();
    00465     d->popState();
    00466 }
    00467
    00468 void KXMLGUIFactory::unplugActionList( KXMLGUIClient *client, const QString &name )
    00469 {
    00470     d->pushState();
    00471     d->guiClient = client;
    00472     d->actionListName = name;
    00473     d->clientName = client->domDocument().documentElement().attribute( d->attrName );
    00474
    00475     d->m_rootNode->unplugActionList( *d );
    00476
    00477     d->BuildState::reset();
    00478     d->popState();
    00479 }
    00480
    00481 void KXMLGUIFactory::applyActionProperties( const QDomElement &actionPropElement )
    00482 {
    00483     static const QString &tagAction = KGlobal::staticQString( "action" );
    00484
    00485     QDomElement e = actionPropElement.firstChild().toElement();
    00486     for (; !e.isNull(); e = e.nextSibling().toElement() )
    00487     {
    00488         if ( e.tagName().lower() != tagAction )
    00489             continue;
    00490
    00491         KAction *action = d->guiClient->action( e );
    00492         if ( !action )
    00493             continue;
    00494
    00495         configureAction( action, e.attributes() );
    00496     }
    00497 }
    00498
    00499 void KXMLGUIFactory::configureAction( KAction *action, const QDomNamedNodeMap &attributes )
    00500 {
    00501     for ( uint i = 0; i < attributes.length(); i++ )
    00502     {
    00503         QDomAttr attr = attributes.item( i ).toAttr();
    00504         if ( attr.isNull() )
    00505             continue;
    00506
    00507         configureAction( action, attr );
    00508     }
    00509 }
    00510
    00511 void KXMLGUIFactory::configureAction( KAction *action, const QDomAttr &attribute )
    00512 {
    00513     static const QString &attrShortcut = KGlobal::staticQString( "shortcut" );
    00514
    00515     QString attrName = attribute.name();
    00516
    00517     QVariant propertyValue;
    00518
    00519     QVariant::Type propertyType = action->property( attribute.name().latin1() ).type();
    00520
    00521     // If the attribute is a depricated "accel", change to "shortcut".
    00522     if ( attrName.lower() == "accel" )
    00523         attrName = attrShortcut;
    00524
    00525     if ( propertyType == QVariant::Int )
    00526         propertyValue = QVariant( attribute.value().toInt() );
    00527     else if ( propertyType == QVariant::UInt )
    00528         propertyValue = QVariant( attribute.value().toUInt() );
    00529     else
    00530         propertyValue = QVariant( attribute.value() );
    00531
    00532     action->setProperty( attrName.latin1() /* ???????? */, propertyValue );
    00533 }
    00534
    00535 void KXMLGUIFactory::virtual_hook( int, void* )
    00536 { /*BASE::virtual_hook( id, data );*/ }
    00537
    00538 #include "kxmlguifactory.moc"
    00539
    00540 /* vim: et sw=4
    00541  */

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:58:04 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001