• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kdeui

kxmlguifactory.cpp

Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, 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(1002) << "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(1002) << "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(1002) << "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  */

kdeui

Skip menu "kdeui"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal