# kdeui Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# kxmlguiclient.cpp

    00001 /* This file is part of the KDE libraries
    00002    Copyright (C) 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 version 2 as published by the Free Software Foundation.
    00008
    00009    This library is distributed in the hope that it will be useful,
    00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00012    Library General Public License for more details.
    00013
    00014    You should have received a copy of the GNU Library General Public License
    00015    along with this library; see the file COPYING.LIB.  If not, write to
    00016    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00017    Boston, MA 02111-1307, USA.
    00018 */
    00019
    00020 #include "kxmlguiclient.h"
    00021 #include "kxmlguifactory.h"
    00022 #include "kxmlguibuilder.h"
    00023
    00024 #include <qdir.h>
    00025 #include <qfile.h>
    00026 #include <qdom.h>
    00027 #include <qtextstream.h>
    00028 #include <qregexp.h>
    00029 #include <qguardedptr.h>
    00030
    00031 #include <kinstance.h>
    00032 #include <kstandarddirs.h>
    00033 #include <kdebug.h>
    00034 #include <kaction.h>
    00035 #include <kapplication.h>
    00036
    00037 #include <assert.h>
    00038
    00039 class KXMLGUIClientPrivate
    00040 {
    00041 public:
    00042   KXMLGUIClientPrivate()
    00043   {
    00044     m_instance = KGlobal::instance();
    00045     m_parent = 0L;
    00046     m_builder = 0L;
    00047     m_actionCollection = 0;
    00048   }
    00049   ~KXMLGUIClientPrivate()
    00050   {
    00051   }
    00052
    00053   KInstance *m_instance;
    00054
    00055   QDomDocument m_doc;
    00056   KActionCollection *m_actionCollection;
    00057   QDomDocument m_buildDocument;
    00058   QGuardedPtr<KXMLGUIFactory> m_factory;
    00059   KXMLGUIClient *m_parent;
    00060   //QPtrList<KXMLGUIClient> m_supers;
    00061   QPtrList<KXMLGUIClient> m_children;
    00062   KXMLGUIBuilder *m_builder;
    00063   QString m_xmlFile;
    00064   QString m_localXMLFile;
    00065 };
    00066
    00067 KXMLGUIClient::KXMLGUIClient()
    00068 {
    00069   d = new KXMLGUIClientPrivate;
    00070 }
    00071
    00072 KXMLGUIClient::KXMLGUIClient( KXMLGUIClient *parent )
    00073 {
    00074   d = new KXMLGUIClientPrivate;
    00075   parent->insertChildClient( this );
    00076 }
    00077
    00078 KXMLGUIClient::~KXMLGUIClient()
    00079 {
    00080   if ( d->m_parent )
    00081     d->m_parent->removeChildClient( this );
    00082
    00083   QPtrListIterator<KXMLGUIClient> it( d->m_children );
    00084   for ( ; it.current(); ++it ) {
    00085       assert( it.current()->d->m_parent == this );
    00086       it.current()->d->m_parent = 0;
    00087   }
    00088
    00089   delete d->m_actionCollection;
    00090   delete d;
    00091 }
    00092
    00093 KAction *KXMLGUIClient::action( const char *name ) const
    00094 {
    00095   KAction* act = actionCollection()->action( name );
    00096   if ( !act ) {
    00097     QPtrListIterator<KXMLGUIClient> childIt( d->m_children );
    00098     for (; childIt.current(); ++childIt ) {
    00099       act = childIt.current()->actionCollection()->action( name );
    00100       if ( act )
    00101         break;
    00102     }
    00103   }
    00104   return act;
    00105 }
    00106
    00107 KActionCollection *KXMLGUIClient::actionCollection() const
    00108 {
    00109   if ( !d->m_actionCollection )
    00110   {
    00111     d->m_actionCollection = new KActionCollection(
    00112       "KXMLGUIClient-KActionCollection", this );
    00113   }
    00114   return d->m_actionCollection;
    00115 }
    00116
    00117 KAction *KXMLGUIClient::action( const QDomElement &element ) const
    00118 {
    00119   static const QString &attrName = KGlobal::staticQString( "name" );
    00120   return actionCollection()->action( element.attribute( attrName ).latin1() );
    00121 }
    00122
    00123 KInstance *KXMLGUIClient::instance() const
    00124 {
    00125   return d->m_instance;
    00126 }
    00127
    00128 QDomDocument KXMLGUIClient::domDocument() const
    00129 {
    00130   return d->m_doc;
    00131 }
    00132
    00133 QString KXMLGUIClient::xmlFile() const
    00134 {
    00135   return d->m_xmlFile;
    00136 }
    00137
    00138 QString KXMLGUIClient::localXMLFile() const
    00139 {
    00140   if ( !d->m_localXMLFile.isEmpty() )
    00141     return d->m_localXMLFile;
    00142
    00143   if ( !QDir::isRelativePath(d->m_xmlFile) )
    00144       return QString::null; // can't save anything here
    00145
    00146   return locateLocal( "data", QString::fromLatin1( instance()->instanceName() + '/' ) + d->m_xmlFile );
    00147 }
    00148
    00149
    00150 void KXMLGUIClient::reloadXML()
    00151 {
    00152     QString file( xmlFile() );
    00153     if ( !file.isEmpty() )
    00154         setXMLFile( file );
    00155 }
    00156
    00157 void KXMLGUIClient::setInstance( KInstance *instance )
    00158 {
    00159   d->m_instance = instance;
    00160   actionCollection()->setInstance( instance );
    00161   if ( d->m_builder )
    00162     d->m_builder->setBuilderClient( this );
    00163 }
    00164
    00165 void KXMLGUIClient::setXMLFile( const QString& _file, bool merge, bool setXMLDoc )
    00166 {
    00167   // store our xml file name
    00168   if ( !_file.isNull() ) {
    00169     d->m_xmlFile = _file;
    00170     actionCollection()->setXMLFile( _file );
    00171   }
    00172
    00173   if ( !setXMLDoc )
    00174     return;
    00175
    00176   QString file = _file;
    00177   if ( QDir::isRelativePath(file) )
    00178   {
    00179     QString doc;
    00180
    00181     QString filter = QString::fromLatin1( instance()->instanceName() + '/' ) + _file;
    00182
    00183     QStringList allFiles = instance()->dirs()->findAllResources( "data", filter ) + instance()->dirs()->findAllResources( "data", _file );
    00184
    00185     file = findMostRecentXMLFile( allFiles, doc );
    00186
    00187     if ( file.isEmpty() )
    00188     {
    00189       // this might or might not be an error.  for the time being,
    00190       // let's treat this as if it isn't a problem and the user just
    00191       // wants the global standards file
    00192
    00193       // however if a non-empty file gets passed and we can't find it we might
    00194       // inform the developer using some debug output
    00195       if ( !_file.isEmpty() )
    00196           kdWarning() << "KXMLGUIClient::setXMLFile: cannot find .rc file " << _file << endl;
    00197
    00198       setXML( QString::null, true );
    00199       return;
    00200     }
    00201     else if ( !doc.isEmpty() )
    00202     {
    00203       setXML( doc, merge );
    00204       return;
    00205     }
    00206   }
    00207
    00208   QString xml = KXMLGUIFactory::readConfigFile( file );
    00209   setXML( xml, merge );
    00210 }
    00211
    00212 void KXMLGUIClient::setLocalXMLFile( const QString &file )
    00213 {
    00214     d->m_localXMLFile = file;
    00215 }
    00216
    00217 void KXMLGUIClient::setXML( const QString &document, bool merge )
    00218 {
    00219   QDomDocument doc;
    00220   doc.setContent( document );
    00221   setDOMDocument( doc, merge );
    00222 }
    00223
    00224 void KXMLGUIClient::setDOMDocument( const QDomDocument &document, bool merge )
    00225 {
    00226   if ( merge )
    00227   {
    00228     QDomElement base = d->m_doc.documentElement();
    00229
    00230     QDomElement e = document.documentElement();
    00231
    00232     // merge our original (global) xml with our new one
    00233     mergeXML(base, e, actionCollection());
    00234
    00235     // reassign our pointer as mergeXML might have done something
    00236     // strange to it
    00237     base = d->m_doc.documentElement();
    00238
    00239     // we want some sort of failsafe.. just in case
    00240     if ( base.isNull() )
    00241       d->m_doc = document;
    00242   }
    00243   else
    00244   {
    00245     d->m_doc = document;
    00246   }
    00247
    00248   setXMLGUIBuildDocument( QDomDocument() );
    00249 }
    00250
    00251 bool KXMLGUIClient::mergeXML( QDomElement &base, const QDomElement &additive, KActionCollection *actionCollection )
    00252 {
    00253   static const QString &tagAction = KGlobal::staticQString( "Action" );
    00254   static const QString &tagMerge = KGlobal::staticQString( "Merge" );
    00255   static const QString &tagSeparator = KGlobal::staticQString( "Separator" );
    00256   static const QString &attrName = KGlobal::staticQString( "name" );
    00257   static const QString &attrAppend = KGlobal::staticQString( "append" );
    00258   static const QString &attrWeakSeparator = KGlobal::staticQString( "weakSeparator" );
    00259   static const QString &tagMergeLocal = KGlobal::staticQString( "MergeLocal" );
    00260   static const QString &tagText = KGlobal::staticQString( "text" );
    00261   static const QString &attrAlreadyVisited = KGlobal::staticQString( "alreadyVisited" );
    00262   static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" );
    00263   static const QString &attrOne = KGlobal::staticQString( "1" );
    00264
    00265   // there is a possibility that we don't want to merge in the
    00266   // additive.. rather, we might want to *replace* the base with the
    00267   // additive.  this can be for any container.. either at a file wide
    00268   // level or a simple container level.  we look for the 'noMerge'
    00269   // tag, in any event and just replace the old with the new
    00270   if ( additive.attribute(attrNoMerge) == attrOne ) // ### use toInt() instead? (Simon)
    00271   {
    00272     base.parentNode().replaceChild(additive, base);
    00273     return true;
    00274   }
    00275
    00276   QString tag;
    00277
    00278   // iterate over all elements in the container (of the global DOM tree)
    00279   QDomNode n = base.firstChild();
    00280   while ( !n.isNull() )
    00281   {
    00282     QDomElement e = n.toElement();
    00283     n = n.nextSibling(); // Advance now so that we can safely delete e
    00284     if (e.isNull())
    00285        continue;
    00286
    00287     tag = e.tagName();
    00288
    00289     // if there's an action tag in the global tree and the action is
    00290     // not implemented, then we remove the element
    00291     if ( tag == tagAction )
    00292     {
    00293       QCString name =  e.attribute( attrName ).utf8(); // WABA
    00294       if ( !actionCollection->action( name ) ||
    00295            (kapp && !kapp->authorizeKAction(name)))
    00296       {
    00297         // remove this child as we aren't using it
    00298         base.removeChild( e );
    00299         continue;
    00300       }
    00301     }
    00302
    00303     // if there's a separator defined in the global tree, then add an
    00304     // attribute, specifying that this is a "weak" separator
    00305     else if ( tag == tagSeparator )
    00306     {
    00307       e.setAttribute( attrWeakSeparator, (uint)1 );
    00308
    00309       // okay, hack time. if the last item was a weak separator OR
    00310       // this is the first item in a container, then we nuke the
    00311       // current one
    00312       QDomElement prev = e.previousSibling().toElement();
    00313       if ( prev.isNull() ||
    00314      ( prev.tagName() == tagSeparator && !prev.attribute( attrWeakSeparator ).isNull() ) ||
    00315      ( prev.tagName() == tagText ) )
    00316       {
    00317         // the previous element was a weak separator or didn't exist
    00318         base.removeChild( e );
    00319         continue;
    00320       }
    00321     }
    00322
    00323     // the MergeLocal tag lets us specify where non-standard elements
    00324     // of the local tree shall be merged in.  After inserting the
    00325     // elements we delete this element
    00326     else if ( tag == tagMergeLocal )
    00327     {
    00328       QDomNode it = additive.firstChild();
    00329       while ( !it.isNull() )
    00330       {
    00331         QDomElement newChild = it.toElement();
    00332         it = it.nextSibling();
    00333         if (newChild.isNull() )
    00334           continue;
    00335
    00336         if ( newChild.tagName() == tagText )
    00337           continue;
    00338
    00339         if ( newChild.attribute( attrAlreadyVisited ) == attrOne )
    00340           continue;
    00341
    00342         QString itAppend( newChild.attribute( attrAppend ) );
    00343         QString elemName( e.attribute( attrName ) );
    00344
    00345         if ( ( itAppend.isNull() && elemName.isEmpty() ) ||
    00346              ( itAppend == elemName ) )
    00347         {
    00348           // first, see if this new element matches a standard one in
    00349           // the global file.  if it does, then we skip it as it will
    00350           // be merged in, later
    00351           QDomElement matchingElement = findMatchingElement( newChild, base );
    00352           if ( matchingElement.isNull() || newChild.tagName() == tagSeparator )
    00353             base.insertBefore( newChild, e );
    00354         }
    00355       }
    00356
    00357       base.removeChild( e );
    00358       continue;
    00359     }
    00360
    00361     // in this last case we check for a separator tag and, if not, we
    00362     // can be sure that its a container --> proceed with child nodes
    00363     // recursively and delete the just proceeded container item in
    00364     // case its empty (if the recursive call returns true)
    00365     else if ( tag != tagMerge )
    00366     {
    00367       // handle the text tag
    00368       if ( tag == tagText )
    00369         continue;
    00370
    00371       QDomElement matchingElement = findMatchingElement( e, additive );
    00372
    00373       if ( !matchingElement.isNull() )
    00374       {
    00375         matchingElement.setAttribute( attrAlreadyVisited, (uint)1 );
    00376
    00377         if ( mergeXML( e, matchingElement, actionCollection ) )
    00378         {
    00379           base.removeChild( e );
    00380           continue;
    00381         }
    00382
    00383         // Merge attributes
    00384         const QDomNamedNodeMap attribs = matchingElement.attributes();
    00385         const uint attribcount = attribs.count();
    00386
    00387         for(uint i = 0; i < attribcount; ++i)
    00388         {
    00389           const QDomNode node = attribs.item(i);
    00390           e.setAttribute(node.nodeName(), node.nodeValue());
    00391         }
    00392
    00393         continue;
    00394       }
    00395       else
    00396       {
    00397         // this is an important case here! We reach this point if the
    00398         // "local" tree does not contain a container definition for
    00399         // this container. However we have to call mergeXML recursively
    00400         // and make it check if there are actions implemented for this
    00401         // container. *If* none, then we can remove this container now
    00402         if ( mergeXML( e, QDomElement(), actionCollection ) )
    00403           base.removeChild( e );
    00404         continue;
    00405       }
    00406     }
    00407   }
    00408
    00409   //here we append all child elements which were not inserted
    00410   //previously via the LocalMerge tag
    00411   n = additive.firstChild();
    00412   while ( !n.isNull() )
    00413   {
    00414     QDomElement e = n.toElement();
    00415     n = n.nextSibling(); // Advance now so that we can safely delete e
    00416     if (e.isNull())
    00417        continue;
    00418
    00419     QDomElement matchingElement = findMatchingElement( e, base );
    00420
    00421     if ( matchingElement.isNull() )
    00422     {
    00423       base.appendChild( e );
    00424     }
    00425   }
    00426
    00427   // do one quick check to make sure that the last element was not
    00428   // a weak separator
    00429   QDomElement last = base.lastChild().toElement();
    00430   if ( (last.tagName() == tagSeparator) && (!last.attribute( attrWeakSeparator ).isNull()) )
    00431   {
    00432     base.removeChild( last );
    00433   }
    00434
    00435   // now we check if we are empty (in which case we return "true", to
    00436   // indicate the caller that it can delete "us" (the base element
    00437   // argument of "this" call)
    00438   bool deleteMe = true;
    00439
    00440   n = base.firstChild();
    00441   while ( !n.isNull() )
    00442   {
    00443     QDomElement e = n.toElement();
    00444     n = n.nextSibling(); // Advance now so that we can safely delete e
    00445     if (e.isNull())
    00446        continue;
    00447
    00448     tag = e.tagName();
    00449
    00450     if ( tag == tagAction )
    00451     {
    00452       // if base contains an implemented action, then we must not get
    00453       // deleted (note that the actionCollection contains both,
    00454       // "global" and "local" actions
    00455       if ( actionCollection->action( e.attribute( attrName ).utf8() ) )
    00456       {
    00457         deleteMe = false;
    00458         break;
    00459       }
    00460     }
    00461     else if ( tag == tagSeparator )
    00462     {
    00463       // if we have a separator which has *not* the weak attribute
    00464       // set, then it must be owned by the "local" tree in which case
    00465       // we must not get deleted either
    00466       QString weakAttr = e.attribute( attrWeakSeparator );
    00467       if ( weakAttr.isEmpty() || weakAttr.toInt() != 1 )
    00468       {
    00469         deleteMe = false;
    00470         break;
    00471       }
    00472     }
    00473
    00474     // in case of a merge tag we have unlimited lives, too ;-)
    00475     else if ( tag == tagMerge )
    00476     {
    00477 //      deleteMe = false;
    00478 //      break;
    00479         continue;
    00480     }
    00481
    00482     // a text tag is NOT enough to spare this container
    00483     else if ( tag == tagText )
    00484     {
    00485       continue;
    00486     }
    00487
    00488     // what's left are non-empty containers! *don't* delete us in this
    00489     // case (at this position we can be *sure* that the container is
    00490     // *not* empty, as the recursive call for it was in the first loop
    00491     // which deleted the element in case the call returned "true"
    00492     else
    00493     {
    00494       deleteMe = false;
    00495       break;
    00496     }
    00497   }
    00498
    00499   return deleteMe;
    00500 }
    00501
    00502 QDomElement KXMLGUIClient::findMatchingElement( const QDomElement &base, const QDomElement &additive )
    00503 {
    00504   static const QString &tagAction = KGlobal::staticQString( "Action" );
    00505   static const QString &tagMergeLocal = KGlobal::staticQString( "MergeLocal" );
    00506   static const QString &attrName = KGlobal::staticQString( "name" );
    00507
    00508   QDomNode n = additive.firstChild();
    00509   while ( !n.isNull() )
    00510   {
    00511     QDomElement e = n.toElement();
    00512     n = n.nextSibling(); // Advance now so that we can safely delete e
    00513     if (e.isNull())
    00514        continue;
    00515
    00516     // skip all action and merge tags as we will never use them
    00517     if ( ( e.tagName() == tagAction ) || ( e.tagName() == tagMergeLocal ) )
    00518     {
    00519       continue;
    00520     }
    00521
    00522     // now see if our tags are equivalent
    00523     if ( ( e.tagName() == base.tagName() ) &&
    00524          ( e.attribute( attrName ) == base.attribute( attrName ) ) )
    00525     {
    00526         return e;
    00527     }
    00528   }
    00529
    00530   // nope, return a (now) null element
    00531   return QDomElement();
    00532 }
    00533
    00534 void KXMLGUIClient::conserveMemory()
    00535 {
    00536   d->m_doc = QDomDocument();
    00537   d->m_buildDocument = QDomDocument();
    00538 }
    00539
    00540 void KXMLGUIClient::setXMLGUIBuildDocument( const QDomDocument &doc )
    00541 {
    00542   d->m_buildDocument = doc;
    00543 }
    00544
    00545 QDomDocument KXMLGUIClient::xmlguiBuildDocument() const
    00546 {
    00547   return d->m_buildDocument;
    00548 }
    00549
    00550 void KXMLGUIClient::setFactory( KXMLGUIFactory *factory )
    00551 {
    00552   d->m_factory = factory;
    00553 }
    00554
    00555 KXMLGUIFactory *KXMLGUIClient::factory() const
    00556 {
    00557   return d->m_factory;
    00558 }
    00559
    00560 KXMLGUIClient *KXMLGUIClient::parentClient() const
    00561 {
    00562   return d->m_parent;
    00563 }
    00564
    00565 void KXMLGUIClient::insertChildClient( KXMLGUIClient *child )
    00566 {
    00567   if (  child->d->m_parent )
    00568     child->d->m_parent->removeChildClient( child );
    00569    d->m_children.append( child );
    00570    child->d->m_parent = this;
    00571 }
    00572
    00573 void KXMLGUIClient::removeChildClient( KXMLGUIClient *child )
    00574 {
    00575   assert( d->m_children.containsRef( child ) );
    00576   d->m_children.removeRef( child );
    00577   child->d->m_parent = 0;
    00578 }
    00579
    00580 /*bool KXMLGUIClient::addSuperClient( KXMLGUIClient *super )
    00581 {
    00582   if ( d->m_supers.contains( super ) )
    00583     return false;
    00584   d->m_supers.append( super );
    00585   return true;
    00586 }*/
    00587
    00588 const QPtrList<KXMLGUIClient> *KXMLGUIClient::childClients()
    00589 {
    00590   return &d->m_children;
    00591 }
    00592
    00593 void KXMLGUIClient::setClientBuilder( KXMLGUIBuilder *builder )
    00594 {
    00595   d->m_builder = builder;
    00596   if ( builder )
    00597     builder->setBuilderInstance( instance() );
    00598 }
    00599
    00600 KXMLGUIBuilder *KXMLGUIClient::clientBuilder() const
    00601 {
    00602   return d->m_builder;
    00603 }
    00604
    00605 void KXMLGUIClient::plugActionList( const QString &name, const QPtrList<KAction> &actionList )
    00606 {
    00607   if ( !d->m_factory )
    00608     return;
    00609
    00610   d->m_factory->plugActionList( this, name, actionList );
    00611 }
    00612
    00613 void KXMLGUIClient::unplugActionList( const QString &name )
    00614 {
    00615   if ( !d->m_factory )
    00616     return;
    00617
    00618   d->m_factory->unplugActionList( this, name );
    00619 }
    00620
    00621 QString KXMLGUIClient::findMostRecentXMLFile( const QStringList &files, QString &doc )
    00622 {
    00623
    00624   QValueList<DocStruct> allDocuments;
    00625
    00626   QStringList::ConstIterator it = files.begin();
    00627   QStringList::ConstIterator end = files.end();
    00628   for (; it != end; ++it )
    00629   {
    00630     //kdDebug() << "KXMLGUIClient::findMostRecentXMLFile " << *it << endl;
    00631     QString data = KXMLGUIFactory::readConfigFile( *it );
    00632     DocStruct d;
    00633     d.file = *it;
    00634     d.data = data;
    00635     allDocuments.append( d );
    00636   }
    00637
    00638   QValueList<DocStruct>::Iterator best = allDocuments.end();
    00639   uint bestVersion = 0;
    00640
    00641   QValueList<DocStruct>::Iterator docIt = allDocuments.begin();
    00642   QValueList<DocStruct>::Iterator docEnd = allDocuments.end();
    00643   for (; docIt != docEnd; ++docIt )
    00644   {
    00645     QString versionStr = findVersionNumber( (*docIt).data );
    00646     if ( versionStr.isEmpty() )
    00647       continue;
    00648
    00649     bool ok = false;
    00650     uint version = versionStr.toUInt( &ok );
    00651     if ( !ok )
    00652       continue;
    00653     //kdDebug() << "FOUND VERSION " << version << endl;
    00654
    00655     if ( version > bestVersion )
    00656     {
    00657       best = docIt;
    00658       //kdDebug() << "best version is now " << version << endl;
    00659       bestVersion = version;
    00660     }
    00661   }
    00662
    00663   if ( best != docEnd )
    00664   {
    00665     if ( best != allDocuments.begin() )
    00666     {
    00667       QValueList<DocStruct>::Iterator local = allDocuments.begin();
    00668
    00669       // load the local document and extract the action properties
    00670       QDomDocument document;
    00671       document.setContent( (*local).data );
    00672
    00673       ActionPropertiesMap properties = extractActionProperties( document );
    00674
    00675       // in case the document has a ActionProperties section
    00676       // we must not delete it but copy over the global doc
    00677       // to the local and insert the ActionProperties section
    00678       if ( !properties.isEmpty() )
    00679       {
    00680           // now load the global one with the higher version number
    00681           // into memory
    00682           document.setContent( (*best).data );
    00683           // and store the properties in there
    00684           storeActionProperties( document, properties );
    00685
    00686           (*local).data = document.toString();
    00687           // make sure we pick up the new local doc, when we return later
    00688           best = local;
    00689
    00690           // write out the new version of the local document
    00691           QFile f( (*local).file );
    00692           if ( f.open( IO_WriteOnly ) )
    00693           {
    00694             QCString utf8data = (*local).data.utf8();
    00695             f.writeBlock( utf8data.data(), utf8data.length() );
    00696             f.close();
    00697           }
    00698       }
    00699       else
    00700       {
    00701         QString f = (*local).file;
    00702         QString backup = f + QString::fromLatin1( ".backup" );
    00703         QDir dir;
    00704         dir.rename( f, backup );
    00705       }
    00706     }
    00707     doc = (*best).data;
    00708     return (*best).file;
    00709   }
    00710   else if ( files.count() > 0 )
    00711   {
    00712     //kdDebug() << "returning first one..." << endl;
    00713     doc = (*allDocuments.begin()).data;
    00714     return (*allDocuments.begin()).file;
    00715   }
    00716
    00717   return QString::null;
    00718 }
    00719
    00720
    00721
    00722 QString KXMLGUIClient::findVersionNumber( const QString &xml )
    00723 {
    00724   enum { ST_START, ST_AFTER_OPEN, ST_AFTER_GUI,
    00725                ST_EXPECT_VERSION, ST_VERSION_NUM} state = ST_START;
    00726   for (unsigned int pos = 0; pos < xml.length(); pos++)
    00727   {
    00728     switch (state)
    00729     {
    00730       case ST_START:
    00731         if (xml[pos] == '<')
    00732           state = ST_AFTER_OPEN;
    00733         break;
    00734       case ST_AFTER_OPEN:
    00735       {
    00736         //Jump to gui..
    00737         int guipos = xml.find("gui", pos, false /*case-insensitive*/);
    00738         if (guipos == -1)
    00739           return QString::null; //Reject
    00740
    00741         pos = guipos + 2; //Position at i, so we're moved ahead to the next character by the ++;
    00742         state = ST_AFTER_GUI;
    00743         break;
    00744       }
    00745       case ST_AFTER_GUI:
    00746         state = ST_EXPECT_VERSION;
    00747         break;
    00748       case ST_EXPECT_VERSION:
    00749       {
    00750         int verpos =  xml.find("version=\"", pos, false /*case-insensitive*/);
    00751         if (verpos == -1)
    00752           return QString::null; //Reject
    00753
    00754         pos = verpos +  8; //v = 0, e = +1, r = +2, s = +3 , i = +4, o = +5, n = +6, = = +7, " = + 8
    00755         state = ST_VERSION_NUM;
    00756         break;
    00757       }
    00758       case ST_VERSION_NUM:
    00759       {
    00760         unsigned int endpos;
    00761         for (endpos = pos; endpos <  xml.length(); endpos++)
    00762         {
    00763           if (xml[endpos].unicode() >= '0' && xml[endpos].unicode() <= '9')
    00764             continue; //Number..
    00765           if (xml[endpos].unicode() == '"') //End of parameter
    00766             break;
    00767           else //This shouldn't be here..
    00768           {
    00769             endpos = xml.length();
    00770           }
    00771         }
    00772
    00773         if (endpos != pos && endpos < xml.length() )
    00774         {
    00775           QString matchCandidate = xml.mid(pos, endpos - pos); //Don't include " ".
    00776           return matchCandidate;
    00777         }
    00778
    00779         state = ST_EXPECT_VERSION; //Try to match a well-formed version..
    00780         break;
    00781       } //case..
    00782     } //switch
    00783   } //for
    00784
    00785   return QString::null;
    00786 }
    00787
    00788 KXMLGUIClient::ActionPropertiesMap KXMLGUIClient::extractActionProperties( const QDomDocument &doc )
    00789 {
    00790   ActionPropertiesMap properties;
    00791
    00792   QDomElement actionPropElement = doc.documentElement().namedItem( "ActionProperties" ).toElement();
    00793
    00794   if ( actionPropElement.isNull() )
    00795     return properties;
    00796
    00797   QDomNode n = actionPropElement.firstChild();
    00798   while(!n.isNull())
    00799   {
    00800     QDomElement e = n.toElement();
    00801     n = n.nextSibling(); // Advance now so that we can safely delete e
    00802     if ( e.isNull() )
    00803       continue;
    00804
    00805     if ( e.tagName().lower() != "action" )
    00806       continue;
    00807
    00808     QString actionName = e.attribute( "name" );
    00809
    00810     if ( actionName.isEmpty() )
    00811       continue;
    00812
    00813     QMap<QString, QMap<QString, QString> >::Iterator propIt = properties.find( actionName );
    00814     if ( propIt == properties.end() )
    00815       propIt = properties.insert( actionName, QMap<QString, QString>() );
    00816
    00817     const QDomNamedNodeMap attributes = e.attributes();
    00818     const uint attributeslength = attributes.length();
    00819
    00820     for ( uint i = 0; i < attributeslength; ++i )
    00821     {
    00822       const QDomAttr attr = attributes.item( i ).toAttr();
    00823
    00824       if ( attr.isNull() )
    00825         continue;
    00826
    00827       const QString name = attr.name();
    00828
    00829       if ( name == "name" || name.isEmpty() )
    00830         continue;
    00831
    00832       (*propIt)[ name ] = attr.value();
    00833     }
    00834
    00835   }
    00836
    00837   return properties;
    00838 }
    00839
    00840 void KXMLGUIClient::storeActionProperties( QDomDocument &doc, const ActionPropertiesMap &properties )
    00841 {
    00842   QDomElement actionPropElement = doc.documentElement().namedItem( "ActionProperties" ).toElement();
    00843
    00844   if ( actionPropElement.isNull() )
    00845   {
    00846     actionPropElement = doc.createElement( "ActionProperties" );
    00847     doc.documentElement().appendChild( actionPropElement );
    00848   }
    00849
    00850   while ( !actionPropElement.firstChild().isNull() )
    00851     actionPropElement.removeChild( actionPropElement.firstChild() );
    00852
    00853   ActionPropertiesMap::ConstIterator it = properties.begin();
    00854   ActionPropertiesMap::ConstIterator end = properties.end();
    00855   for (; it != end; ++it )
    00856   {
    00857     QDomElement action = doc.createElement( "Action" );
    00858     action.setAttribute( "name", it.key() );
    00859     actionPropElement.appendChild( action );
    00860
    00861     QMap<QString, QString> attributes = (*it);
    00862     QMap<QString, QString>::ConstIterator attrIt = attributes.begin();
    00863     QMap<QString, QString>::ConstIterator attrEnd = attributes.end();
    00864     for (; attrIt != attrEnd; ++attrIt )
    00865       action.setAttribute( attrIt.key(), attrIt.data() );
    00866   }
    00867 }
    00868
    00869 void KXMLGUIClient::addStateActionEnabled(const QString& state,
    00870                                           const QString& action)
    00871 {
    00872   StateChange stateChange = getActionsToChangeForState(state);
    00873
    00874   stateChange.actionsToEnable.append( action );
    00875   //kdDebug() << "KXMLGUIClient::addStateActionEnabled( " << state << ", " << action << ")" << endl;
    00876
    00877   m_actionsStateMap.replace( state, stateChange );
    00878 }
    00879
    00880
    00881 void KXMLGUIClient::addStateActionDisabled(const QString& state,
    00882                                            const QString& action)
    00883 {
    00884   StateChange stateChange = getActionsToChangeForState(state);
    00885
    00886   stateChange.actionsToDisable.append( action );
    00887   //kdDebug() << "KXMLGUIClient::addStateActionDisabled( " << state << ", " << action << ")" << endl;
    00888
    00889   m_actionsStateMap.replace( state, stateChange );
    00890 }
    00891
    00892
    00893 KXMLGUIClient::StateChange KXMLGUIClient::getActionsToChangeForState(const QString& state)
    00894 {
    00895   return m_actionsStateMap[state];
    00896 }
    00897
    00898
    00899 void KXMLGUIClient::stateChanged(const QString &newstate, KXMLGUIClient::ReverseStateChange reverse)
    00900 {
    00901   StateChange stateChange = getActionsToChangeForState(newstate);
    00902
    00903   bool setTrue = (reverse == StateNoReverse);
    00904   bool setFalse = !setTrue;
    00905
    00906   // Enable actions which need to be enabled...
    00907   //
    00908   for ( QStringList::Iterator it = stateChange.actionsToEnable.begin();
    00909         it != stateChange.actionsToEnable.end(); ++it ) {
    00910
    00911     KAction *action = actionCollection()->action((*it).latin1());
    00912     if (action) action->setEnabled(setTrue);
    00913   }
    00914
    00915   // and disable actions which need to be disabled...
    00916   //
    00917   for ( QStringList::Iterator it = stateChange.actionsToDisable.begin();
    00918         it != stateChange.actionsToDisable.end(); ++it ) {
    00919
    00920     KAction *action = actionCollection()->action((*it).latin1());
    00921     if (action) action->setEnabled(setFalse);
    00922   }
    00923
    00924 }
    00925
    00926 void KXMLGUIClient::beginXMLPlug( QWidget *w )
    00927 {
    00928   actionCollection()->beginXMLPlug( w );
    00929   QPtrListIterator<KXMLGUIClient> childIt( d->m_children );
    00930   for (; childIt.current(); ++childIt )
    00931     childIt.current()->actionCollection()->beginXMLPlug( w );
    00932 }
    00933
    00934 void KXMLGUIClient::endXMLPlug()
    00935 {
    00936   actionCollection()->endXMLPlug();
    00937   QPtrListIterator<KXMLGUIClient> childIt( d->m_children );
    00938   for (; childIt.current(); ++childIt )
    00939     childIt.current()->actionCollection()->endXMLPlug();
    00940 }
    00941
    00942 void KXMLGUIClient::prepareXMLUnplug( QWidget * )
    00943 {
    00944   actionCollection()->prepareXMLUnplug();
    00945   QPtrListIterator<KXMLGUIClient> childIt( d->m_children );
    00946   for (; childIt.current(); ++childIt )
    00947     childIt.current()->actionCollection()->prepareXMLUnplug();
    00948 }
    00949
    00950 void KXMLGUIClient::virtual_hook( int, void* )
    00951 { /*BASE::virtual_hook( id, data );*/ }

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