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

kdeui

kxmlguiclient.cpp

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

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