kxmlguiclient.cpp Source File (kdeui Library)

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

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:02 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001