# kdeui Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | 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 <qdir.h>
    00029 #include <qfile.h>
    00030 #include <qtextstream.h>
    00031 #include <qwidget.h>
    00032 #include <qdatetime.h>
    00033 #include <qvariant.h>
    00034
    00035 #include <kaction.h>
    00036 #include <kdebug.h>
    00037 #include <kinstance.h>
    00038 #include <kglobal.h>
    00039 #include <kshortcut.h>
    00040 #include <kstandarddirs.h>
    00041 #include <kkeydialog.h>
    00042
    00043 using namespace KXMLGUI;
    00044
    00045 /*
    00046  * TODO:     - make more use of QValueList instead of QPtrList
    00047  */
    00048
    00049 class KXMLGUIFactoryPrivate : public BuildState
    00050 {
    00051 public:
    00052     KXMLGUIFactoryPrivate()
    00053     {
    00054         static const QString &defaultMergingName = KGlobal::staticQString( "<default>" );
    00055         static const QString &actionList = KGlobal::staticQString( "actionlist" );
    00056         static const QString &name = KGlobal::staticQString( "name" );
    00057
    00058         m_rootNode = new ContainerNode( 0L, QString::null, 0L );
    00059         m_defaultMergingName = defaultMergingName;
    00060         tagActionList = actionList;
    00061         attrName = name;
    00062     }
    00063     ~KXMLGUIFactoryPrivate()
    00064     {
    00065         delete m_rootNode;
    00066     }
    00067
    00068     void pushState()
    00069     {
    00070         m_stateStack.push( *this );
    00071     }
    00072
    00073     void popState()
    00074     {
    00075         BuildState::operator=( m_stateStack.pop() );
    00076     }
    00077
    00078     ContainerNode *m_rootNode;
    00079
    00080     QString m_defaultMergingName;
    00081
    00082     /*
    00083      * Contains the container which is searched for in ::container .
    00084      */
    00085     QString m_containerName;
    00086
    00087     /*
    00088      * List of all clients
    00089      */
    00090     QPtrList<KXMLGUIClient> m_clients;
    00091
    00092     QString tagActionList;
    00093
    00094     QString attrName;
    00095
    00096     BuildStateStack m_stateStack;
    00097 };
    00098
    00099 QString KXMLGUIFactory::readConfigFile( const QString &filename, const KInstance *instance )
    00100 {
    00101     return readConfigFile( filename, false, instance );
    00102 }
    00103
    00104 QString KXMLGUIFactory::readConfigFile( const QString &filename, bool never_null, const KInstance *_instance )
    00105 {
    00106     const KInstance *instance = _instance ? _instance : KGlobal::instance();
    00107     QString xml_file;
    00108
    00109     if (!QDir::isRelativePath(filename))
    00110         xml_file = filename;
    00111     else
    00112     {
    00113         xml_file = locate("data", QString::fromLatin1(instance->instanceName() + '/' ) + filename);
    00114         if ( !QFile::exists( xml_file ) )
    00115           xml_file = locate( "data", filename );
    00116     }
    00117
    00118     QFile file( xml_file );
    00119     if ( !file.open( IO_ReadOnly ) )
    00120     {
    00121         kdError(240) << "No such XML file " << filename << endl;
    00122         if ( never_null )
    00123             return QString::fromLatin1( "<!DOCTYPE kpartgui>\n<kpartgui name=\"empty\">\n</kpartgui>" );
    00124         else
    00125             return QString::null;
    00126     }
    00127
    00128 #if QT_VERSION <= 0x030302
    00129     // Work around bug in QString::fromUtf8 (which calls strlen).
    00130     QByteArray buffer(file.size() + 1);
    00131     buffer = file.readAll();
    00132     if(!buffer.isEmpty())
    00133         buffer[ buffer.size() - 1 ] = '\0';
    00134     else
    00135         return QString::null;
    00136 #else
    00137     QByteArray buffer(file.readAll());
    00138 #endif
    00139     return QString::fromUtf8(buffer.data(), buffer.size());
    00140 }
    00141
    00142 bool KXMLGUIFactory::saveConfigFile( const QDomDocument& doc,
    00143                                      const QString& filename, const KInstance *_instance )
    00144 {
    00145     const KInstance *instance = _instance ? _instance : KGlobal::instance();
    00146     QString xml_file(filename);
    00147
    00148     if (QDir::isRelativePath(xml_file))
    00149         xml_file = locateLocal("data", QString::fromLatin1( instance->instanceName() + '/' )
    00150                                + filename);
    00151
    00152     QFile file( xml_file );
    00153     if ( !file.open( IO_WriteOnly ) )
    00154     {
    00155         kdError(240) << "Could not write to " << filename << endl;
    00156         return false;
    00157     }
    00158
    00159     // write out our document
    00160     QTextStream ts(&file);
    00161     ts.setEncoding( QTextStream::UnicodeUTF8 );
    00162     ts << doc;
    00163
    00164     file.close();
    00165     return true;
    00166 }
    00167
    00168 QString KXMLGUIFactory::documentToXML( const QDomDocument& doc )
    00169 {
    00170     QString str;
    00171     QTextStream ts(&str, IO_WriteOnly);
    00172     ts.setEncoding( QTextStream::UnicodeUTF8 );
    00173     ts << doc;
    00174     return str;
    00175 }
    00176
    00177 QString KXMLGUIFactory::elementToXML( const QDomElement& elem )
    00178 {
    00179     QString str;
    00180     QTextStream ts(&str, IO_WriteOnly);
    00181     ts.setEncoding( QTextStream::UnicodeUTF8 );
    00182     ts << elem;
    00183     return str;
    00184 }
    00185
    00186 void KXMLGUIFactory::removeDOMComments( QDomNode &node )
    00187 {
    00188     QDomNode n = node.firstChild();
    00189     while ( !n.isNull() )
    00190     {
    00191         if ( n.nodeType() == QDomNode::CommentNode )
    00192         {
    00193             QDomNode tmp = n;
    00194             n = n.nextSibling();
    00195             node.removeChild( tmp );
    00196         }
    00197         else
    00198         {
    00199             QDomNode tmp = n;
    00200             n = n.nextSibling();
    00201             removeDOMComments( tmp );
    00202         }
    00203     }
    00204 }
    00205
    00206 KXMLGUIFactory::KXMLGUIFactory( KXMLGUIBuilder *builder, QObject *parent, const char *name )
    00207     : QObject( parent, name )
    00208 {
    00209     d = new KXMLGUIFactoryPrivate;
    00210     d->builder = builder;
    00211     d->guiClient = 0;
    00212     if ( d->builder )
    00213     {
    00214         d->builderContainerTags = d->builder->containerTags();
    00215         d->builderCustomTags = d->builder->customTags();
    00216     }
    00217 }
    00218
    00219 KXMLGUIFactory::~KXMLGUIFactory()
    00220 {
    00221     delete d;
    00222 }
    00223
    00224 void KXMLGUIFactory::addClient( KXMLGUIClient *client )
    00225 {
    00226     kdDebug(129) << "KXMLGUIFactory::addClient( " << client << " )" << endl; // ellis
    00227     static const QString &actionPropElementName = KGlobal::staticQString( "ActionProperties" );
    00228
    00229     if ( client->factory() ) {
    00230         if ( client->factory() == this )
    00231             return;
    00232         else
    00233             client->factory()->removeClient( client ); //just in case someone does stupid things ;-)
    00234     }
    00235
    00236     d->pushState();
    00237
    00238 //    QTime dt; dt.start();
    00239
    00240     d->guiClient = client;
    00241
    00242     // add this client to our client list
    00243     if ( !d->m_clients.containsRef( client ) )
    00244         d->m_clients.append( client );
    00245     else
    00246         kdDebug(129) << "XMLGUI client already added " << client << endl;
    00247
    00248     // Tell the client that plugging in is process and
    00249     //  let it know what builder widget its mainwindow shortcuts
    00250     //  should be attached to.
    00251     client->beginXMLPlug( d->builder->widget() );
    00252
    00253     // try to use the build document for building the client's GUI, as the build document
    00254     // contains the correct container state information (like toolbar positions, sizes, etc.) .
    00255     // if there is non available, then use the "real" document.
    00256     QDomDocument doc = client->xmlguiBuildDocument();
    00257     if ( doc.documentElement().isNull() )
    00258         doc = client->domDocument();
    00259
    00260     QDomElement docElement = doc.documentElement();
    00261
    00262     d->m_rootNode->index = -1;
    00263
    00264     // cache some variables
    00265
    00266     d->clientName = docElement.attribute( d->attrName );
    00267     d->clientBuilder = client->clientBuilder();
    00268
    00269     if ( d->clientBuilder )
    00270     {
    00271         d->clientBuilderContainerTags = d->clientBuilder->containerTags();
    00272         d->clientBuilderCustomTags = d->clientBuilder->customTags();
    00273     }
    00274     else
    00275     {
    00276         d->clientBuilderContainerTags.clear();
    00277         d->clientBuilderCustomTags.clear();
    00278     }
    00279
    00280     // process a possibly existing actionproperties section
    00281
    00282     QDomElement actionPropElement = docElement.namedItem( actionPropElementName ).toElement();
    00283     if ( actionPropElement.isNull() )
    00284         actionPropElement = docElement.namedItem( actionPropElementName.lower() ).toElement();
    00285
    00286     if ( !actionPropElement.isNull() )
    00287         applyActionProperties( actionPropElement );
    00288
    00289     BuildHelper( *d, d->m_rootNode ).build( docElement );
    00290
    00291     // let the client know that we built its GUI.
    00292     client->setFactory( this );
    00293
    00294     // call the finalizeGUI method, to fix up the positions of toolbars for example.
    00295     // ### FIXME : obey client builder
    00296     // --- Well, toolbars have a bool "positioned", so it doesn't really matter,
    00297     // if we call positionYourself on all of them each time. (David)
    00298     d->builder->finalizeGUI( d->guiClient );
    00299
    00300     // reset some variables, for safety
    00301     d->BuildState::reset();
    00302
    00303     client->endXMLPlug();
    00304
    00305     d->popState();
    00306
    00307     emit clientAdded( client );
    00308
    00309     // build child clients
    00310     if ( client->childClients()->count() > 0 )
    00311     {
    00312         const QPtrList<KXMLGUIClient> *children = client->childClients();
    00313         QPtrListIterator<KXMLGUIClient> childIt( *children );
    00314         for (; childIt.current(); ++childIt )
    00315             addClient( childIt.current() );
    00316     }
    00317
    00318 //    kdDebug() << "addClient took " << dt.elapsed() << endl;
    00319 }
    00320
    00321 void KXMLGUIFactory::removeClient( KXMLGUIClient *client )
    00322 {
    00323     kdDebug(129) << "KXMLGUIFactory::removeClient( " << client << " )" << endl; // ellis
    00324
    00325     // don't try to remove the client's GUI if we didn't build it
    00326     if ( !client || client->factory() != this )
    00327         return;
    00328
    00329     // remove this client from our client list
    00330     d->m_clients.removeRef( client );
    00331
    00332     // remove child clients first
    00333     if ( client->childClients()->count() > 0 )
    00334     {
    00335         const QPtrList<KXMLGUIClient> *children = client->childClients();
    00336         QPtrListIterator<KXMLGUIClient> childIt( *children );
    00337         childIt.toLast();
    00338         for (; childIt.current(); --childIt )
    00339             removeClient( childIt.current() );
    00340     }
    00341
    00342     kdDebug(1002) << "KXMLGUIFactory::removeServant, calling removeRecursive" << endl;
    00343
    00344     d->pushState();
    00345
    00346     // cache some variables
    00347
    00348     d->guiClient = client;
    00349     d->clientName = client->domDocument().documentElement().attribute( d->attrName );
    00350     d->clientBuilder = client->clientBuilder();
    00351
    00352     client->setFactory( 0L );
    00353
    00354     // if we don't have a build document for that client, yet, then create one by
    00355     // cloning the original document, so that saving container information in the
    00356     // DOM tree does not touch the original document.
    00357     QDomDocument doc = client->xmlguiBuildDocument();
    00358     if ( doc.documentElement().isNull() )
    00359     {
    00360         doc = client->domDocument().cloneNode( true ).toDocument();
    00361         client->setXMLGUIBuildDocument( doc );
    00362     }
    00363
    00364     d->m_rootNode->destruct( doc.documentElement(), *d );
    00365
    00366     d->builder->finalizeGUI( d->guiClient ); //JoWenn
    00367
    00368     // reset some variables
    00369     d->BuildState::reset();
    00370
    00371     // This will destruct the KAccel object built around the given widget.
    00372     client->prepareXMLUnplug( d->builder->widget() );
    00373
    00374     d->popState();
    00375
    00376     emit clientRemoved( client );
    00377 }
    00378
    00379 QPtrList<KXMLGUIClient> KXMLGUIFactory::clients() const
    00380 {
    00381     return d->m_clients;
    00382 }
    00383
    00384 QWidget *KXMLGUIFactory::container( const QString &containerName, KXMLGUIClient *client,
    00385                                     bool useTagName )
    00386 {
    00387     d->pushState();
    00388     d->m_containerName = containerName;
    00389     d->guiClient = client;
    00390
    00391     QWidget *result = findRecursive( d->m_rootNode, useTagName );
    00392
    00393     d->guiClient = 0L;
    00394     d->m_containerName = QString::null;
    00395
    00396     d->popState();
    00397
    00398     return result;
    00399 }
    00400
    00401 QPtrList<QWidget> KXMLGUIFactory::containers( const QString &tagName )
    00402 {
    00403     return findRecursive( d->m_rootNode, tagName );
    00404 }
    00405
    00406 void KXMLGUIFactory::reset()
    00407 {
    00408     d->m_rootNode->reset();
    00409
    00410     d->m_rootNode->clearChildren();
    00411 }
    00412
    00413 void KXMLGUIFactory::resetContainer( const QString &containerName, bool useTagName )
    00414 {
    00415     if ( containerName.isEmpty() )
    00416         return;
    00417
    00418     ContainerNode *container = d->m_rootNode->findContainer( containerName, useTagName );
    00419
    00420     if ( !container )
    00421         return;
    00422
    00423     ContainerNode *parent = container->parent;
    00424     if ( !parent )
    00425         return;
    00426
    00427     //  resetInternal( container );
    00428
    00429     parent->removeChild( container );
    00430 }
    00431
    00432 QWidget *KXMLGUIFactory::findRecursive( KXMLGUI::ContainerNode *node, bool tag )
    00433 {
    00434     if ( ( ( !tag && node->name == d->m_containerName ) ||
    00435            ( tag && node->tagName == d->m_containerName ) ) &&
    00436          ( !d->guiClient || node->client == d->guiClient ) )
    00437         return node->container;
    00438
    00439     QPtrListIterator<ContainerNode> it( node->children );
    00440     for (; it.current(); ++it )
    00441     {
    00442         QWidget *cont = findRecursive( it.current(), tag );
    00443         if ( cont )
    00444             return cont;
    00445     }
    00446
    00447     return 0L;
    00448 }
    00449
    00450 QPtrList<QWidget> KXMLGUIFactory::findRecursive( KXMLGUI::ContainerNode *node,
    00451                                                  const QString &tagName )
    00452 {
    00453     QPtrList<QWidget> res;
    00454
    00455     if ( node->tagName == tagName.lower() )
    00456         res.append( node->container );
    00457
    00458     QPtrListIterator<KXMLGUI::ContainerNode> it( node->children );
    00459     for (; it.current(); ++it )
    00460     {
    00461         QPtrList<QWidget> lst = findRecursive( it.current(), tagName );
    00462         QPtrListIterator<QWidget> wit( lst );
    00463         for (; wit.current(); ++wit )
    00464             res.append( wit.current() );
    00465     }
    00466
    00467     return res;
    00468 }
    00469
    00470 void KXMLGUIFactory::plugActionList( KXMLGUIClient *client, const QString &name,
    00471                                      const QPtrList<KAction> &actionList )
    00472 {
    00473     d->pushState();
    00474     d->guiClient = client;
    00475     d->actionListName = name;
    00476     d->actionList = actionList;
    00477     d->clientName = client->domDocument().documentElement().attribute( d->attrName );
    00478
    00479     d->m_rootNode->plugActionList( *d );
    00480
    00481     d->BuildState::reset();
    00482     d->popState();
    00483 }
    00484
    00485 void KXMLGUIFactory::unplugActionList( KXMLGUIClient *client, const QString &name )
    00486 {
    00487     d->pushState();
    00488     d->guiClient = client;
    00489     d->actionListName = name;
    00490     d->clientName = client->domDocument().documentElement().attribute( d->attrName );
    00491
    00492     d->m_rootNode->unplugActionList( *d );
    00493
    00494     d->BuildState::reset();
    00495     d->popState();
    00496 }
    00497
    00498 void KXMLGUIFactory::applyActionProperties( const QDomElement &actionPropElement )
    00499 {
    00500     static const QString &tagAction = KGlobal::staticQString( "action" );
    00501
    00502     for (QDomNode n = actionPropElement.firstChild();
    00503          !n.isNull(); n = n.nextSibling() )
    00504     {
    00505         QDomElement e = n.toElement();
    00506         if ( e.tagName().lower() != tagAction )
    00507             continue;
    00508
    00509         KAction *action = d->guiClient->action( e );
    00510         if ( !action )
    00511             continue;
    00512
    00513         configureAction( action, e.attributes() );
    00514     }
    00515 }
    00516
    00517 void KXMLGUIFactory::configureAction( KAction *action, const QDomNamedNodeMap &attributes )
    00518 {
    00519     for ( uint i = 0; i < attributes.length(); i++ )
    00520     {
    00521         QDomAttr attr = attributes.item( i ).toAttr();
    00522         if ( attr.isNull() )
    00523             continue;
    00524
    00525         configureAction( action, attr );
    00526     }
    00527 }
    00528
    00529 void KXMLGUIFactory::configureAction( KAction *action, const QDomAttr &attribute )
    00530 {
    00531     static const QString &attrShortcut = KGlobal::staticQString( "shortcut" );
    00532
    00533     QString attrName = attribute.name();
    00534     // If the attribute is a deprecated "accel", change to "shortcut".
    00535     if ( attrName.lower() == "accel" )
    00536         attrName = attrShortcut;
    00537
    00538     QVariant propertyValue;
    00539
    00540     QVariant::Type propertyType = action->property( attrName.latin1() ).type();
    00541
    00542     if ( propertyType == QVariant::Int )
    00543         propertyValue = QVariant( attribute.value().toInt() );
    00544     else if ( propertyType == QVariant::UInt )
    00545         propertyValue = QVariant( attribute.value().toUInt() );
    00546     else
    00547         propertyValue = QVariant( attribute.value() );
    00548
    00549     action->setProperty( attrName.latin1(), propertyValue );
    00550 }
    00551
    00552
    00553 int KXMLGUIFactory::configureShortcuts(bool bAllowLetterShortcuts , bool bSaveSettings )
    00554 {
    00555     KKeyDialog dlg( bAllowLetterShortcuts, dynamic_cast<QWidget*>(parent()) );
    00556     QPtrListIterator<KXMLGUIClient> it( d->m_clients );
    00557     KXMLGUIClient *client;
    00558     while( (client=it.current()) !=0 )
    00559     {
    00560         ++it;
    00561         if(!client->xmlFile().isEmpty())
    00562             dlg.insert( client->actionCollection() );
    00563     }
    00564     return dlg.configure(bSaveSettings);
    00565 }
    00566
    00567 QDomElement KXMLGUIFactory::actionPropertiesElement( QDomDocument& doc )
    00568 {
    00569     const QString tagActionProp = QString::fromLatin1("ActionProperties");
    00570     // first, lets see if we have existing properties
    00571     QDomElement elem;
    00572     QDomNode it = doc.documentElement().firstChild();
    00573     for( ; !it.isNull(); it = it.nextSibling() ) {
    00574         QDomElement e = it.toElement();
    00575         if( e.tagName() == tagActionProp ) {
    00576             elem = e;
    00577             break;
    00578         }
    00579     }
    00580
    00581     // if there was none, create one
    00582     if( elem.isNull() ) {
    00583         elem = doc.createElement( tagActionProp );
    00584         doc.documentElement().appendChild( elem );
    00585     }
    00586     return elem;
    00587 }
    00588
    00589 QDomElement KXMLGUIFactory::findActionByName( QDomElement& elem, const QString& sName, bool create )
    00590 {
    00591         static const QString& attrName = KGlobal::staticQString( "name" );
    00592     static const QString& tagAction = KGlobal::staticQString( "Action" );
    00593     for( QDomNode it = elem.firstChild(); !it.isNull(); it = it.nextSibling() ) {
    00594         QDomElement e = it.toElement();
    00595         if( e.attribute( attrName ) == sName )
    00596             return e;
    00597     }
    00598
    00599     if( create ) {
    00600         QDomElement act_elem = elem.ownerDocument().createElement( tagAction );
    00601         act_elem.setAttribute( attrName, sName );
    00602                 elem.appendChild( act_elem );
    00603                 return act_elem;
    00604     }
    00605         return QDomElement();
    00606 }
    00607
    00608 void KXMLGUIFactory::virtual_hook( int, void* )
    00609 { /*BASE::virtual_hook( id, data );*/ }
    00610
    00611 #include "kxmlguifactory.moc"
    00612
    00613 /* vim: et sw=4
    00614  */

This file is part of the documentation for kdeui Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:20:25 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003