kxmlguifactory_p.cpp

00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2001 Simon Hausmann <hausmann@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
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 "kxmlguifactory_p.h"
00021 #include "kxmlguiclient.h"
00022 #include "kxmlguibuilder.h"
00023 
00024 #include <qwidget.h>
00025 
00026 #include <kglobal.h>
00027 #include <kdebug.h>
00028 
00029 #include <assert.h>
00030 
00031 using namespace KXMLGUI;
00032 
00033 void ActionList::plug( QWidget *container, int index ) const
00034 {
00035     ActionListIt it( *this );
00036     for (; it.current(); ++it )
00037         it.current()->plug( container, index++ );
00038 }
00039 
00040 void ActionList::unplug( QWidget *container ) const
00041 {
00042     ActionListIt it( *this );
00043     for (; it.current(); ++it )
00044         it.current()->unplug( container );
00045 }
00046 
00047 ContainerNode::ContainerNode( QWidget *_container, const QString &_tagName,
00048                               const QString &_name, ContainerNode *_parent,
00049                               KXMLGUIClient *_client, KXMLGUIBuilder *_builder,
00050                               int id, const QString &_mergingName,
00051                               const QString &_groupName, const QStringList &customTags,
00052                               const QStringList &containerTags )
00053     : parent( _parent ), client( _client ), builder( _builder ),
00054       builderCustomTags( customTags ), builderContainerTags( containerTags ),
00055       container( _container ), containerId( id ), tagName( _tagName ), name( _name ),
00056       groupName( _groupName ), index( 0 ), mergingName( _mergingName )
00057 {
00058     children.setAutoDelete( true );
00059     clients.setAutoDelete( true );
00060 
00061     if ( parent )
00062         parent->children.append( this );
00063 }
00064 
00065 void ContainerNode::removeChild( ContainerNode *child )
00066 {
00067     MergingIndexList::Iterator mergingIt = findIndex( child->mergingName );
00068     adjustMergingIndices( -1, mergingIt );
00069     children.removeRef( child );
00070 }
00071 
00072 /*
00073  * Find a merging index with the given name. Used to find an index defined by <Merge name="blah"/>
00074  * or by a <DefineGroup name="foo" /> tag.
00075  */
00076 MergingIndexList::Iterator ContainerNode::findIndex( const QString &name )
00077 {
00078     MergingIndexList::Iterator it( mergingIndices.begin() );
00079     MergingIndexList::Iterator end( mergingIndices.end() );
00080     for (; it != end; ++it )
00081         if ( (*it).mergingName == name )
00082             return it;
00083     return it;
00084 }
00085 
00086 /*
00087  * Check if the given container widget is a child of this node and return the node structure
00088  * if fonud.
00089  */
00090 ContainerNode *ContainerNode::findContainerNode( QWidget *container )
00091 {
00092     ContainerNodeListIt it( children );
00093 
00094     for (; it.current(); ++it )
00095         if ( it.current()->container == container )
00096             return it.current();
00097 
00098     return 0L;
00099 }
00100 
00101 /*
00102  * Find a container recursively with the given name. Either compares _name with the
00103  * container's tag name or the value of the container's name attribute. Specified by
00104  * the tag bool .
00105  */
00106 ContainerNode *ContainerNode::findContainer( const QString &_name, bool tag )
00107 {
00108     if ( ( tag && tagName == _name ) ||
00109          ( !tag && name == _name ) )
00110         return this;
00111 
00112     ContainerNodeListIt it( children );
00113     for (; it.current(); ++it )
00114     {
00115         ContainerNode *res = it.current()->findContainer( _name, tag );
00116         if ( res )
00117             return res;
00118     }
00119 
00120     return 0;
00121 }
00122 
00123 /*
00124  * Finds a child container node (not recursively) with the given name and tagname. Explicitly
00125  * leaves out container widgets specified in the exludeList . Also ensures that the containers
00126  * belongs to currClient.
00127  */
00128 ContainerNode *ContainerNode::findContainer( const QString &name, const QString &tagName,
00129                                              const QPtrList<QWidget> *excludeList,
00130                                              KXMLGUIClient * /*currClient*/ )
00131 {
00132     ContainerNode *res = 0L;
00133     ContainerNodeListIt nIt( children );
00134 
00135     if ( !name.isEmpty() )
00136     {
00137         for (; nIt.current(); ++nIt )
00138             if ( nIt.current()->name == name &&
00139                  !excludeList->containsRef( nIt.current()->container ) )
00140             {
00141                 res = nIt.current();
00142                 break;
00143             }
00144 
00145         return res;
00146     }
00147 
00148     if ( !tagName.isEmpty() )
00149         for (; nIt.current(); ++nIt )
00150         {
00151             if ( nIt.current()->tagName == tagName &&
00152                  !excludeList->containsRef( nIt.current()->container )
00153                  /*
00154                   * It is a bad idea to also compare the client, because
00155                   * we don't want to do so in situations like these:
00156                   *
00157                   * <MenuBar>
00158                   *   <Menu>
00159                   *     ...
00160                   *
00161                   * other client:
00162                   * <MenuBar>
00163                   *   <Menu>
00164                   *    ...
00165                   *
00166                  && nIt.current()->client == currClient )
00167                  */
00168                 )
00169             {
00170                 res = nIt.current();
00171                 break;
00172             }
00173         }
00174 
00175     return res;
00176 }
00177 
00178 ContainerClient *ContainerNode::findChildContainerClient( KXMLGUIClient *currentGUIClient,
00179                                                           const QString &groupName,
00180                                                           const MergingIndexList::Iterator &mergingIdx )
00181 {
00182     if ( !clients.isEmpty() )
00183     {
00184         ContainerClientListIt clientIt( clients );
00185 
00186         for (; clientIt.current(); ++clientIt )
00187             if ( clientIt.current()->client == currentGUIClient )
00188             {
00189                 if ( groupName.isEmpty() )
00190                     return clientIt.current();
00191 
00192                 if ( groupName == clientIt.current()->groupName )
00193                     return clientIt.current();
00194             }
00195     }
00196 
00197     ContainerClient *client = new ContainerClient;
00198     client->client = currentGUIClient;
00199     client->groupName = groupName;
00200 
00201     if ( mergingIdx != mergingIndices.end() )
00202         client->mergingName = (*mergingIdx).mergingName;
00203 
00204     clients.append( client );
00205 
00206     return client;
00207 }
00208 
00209 void ContainerNode::plugActionList( BuildState &state )
00210 {
00211     MergingIndexList::Iterator mIt( mergingIndices.begin() );
00212     MergingIndexList::Iterator mEnd( mergingIndices.end() );
00213     for (; mIt != mEnd; ++mIt )
00214         plugActionList( state, mIt );
00215 
00216     QPtrListIterator<ContainerNode> childIt( children );
00217     for (; childIt.current(); ++childIt )
00218         childIt.current()->plugActionList( state );
00219 }
00220 
00221 void ContainerNode::plugActionList( BuildState &state, const MergingIndexList::Iterator &mergingIdxIt )
00222 {
00223     static const QString &tagActionList = KGlobal::staticQString( "actionlist" );
00224 
00225     MergingIndex mergingIdx = *mergingIdxIt;
00226 
00227     QString k( mergingIdx.mergingName );
00228 
00229     if ( k.find( tagActionList ) == -1 )
00230         return;
00231 
00232     k = k.mid( tagActionList.length() );
00233 
00234     if ( mergingIdx.clientName != state.clientName )
00235         return;
00236 
00237     if ( k != state.actionListName )
00238         return;
00239 
00240     ContainerClient *client = findChildContainerClient( state.guiClient,
00241                                                         QString::null,
00242                                                         mergingIndices.end() );
00243 
00244     client->actionLists.insert( k, state.actionList );
00245 
00246     state.actionList.plug( container, mergingIdx.value );
00247 
00248     adjustMergingIndices( state.actionList.count(), mergingIdxIt );
00249 }
00250 
00251 void ContainerNode::unplugActionList( BuildState &state )
00252 {
00253     MergingIndexList::Iterator mIt( mergingIndices.begin() );
00254     MergingIndexList::Iterator mEnd( mergingIndices.end() );
00255     for (; mIt != mEnd; ++mIt )
00256         unplugActionList( state, mIt );
00257 
00258     QPtrListIterator<ContainerNode> childIt( children );
00259     for (; childIt.current(); ++childIt )
00260         childIt.current()->unplugActionList( state );
00261 }
00262 
00263 void ContainerNode::unplugActionList( BuildState &state, const MergingIndexList::Iterator &mergingIdxIt )
00264 {
00265     static const QString &tagActionList = KGlobal::staticQString( "actionlist" );
00266 
00267     MergingIndex mergingIdx = *mergingIdxIt;
00268 
00269     QString k = mergingIdx.mergingName;
00270 
00271     if ( k.find( tagActionList ) == -1 )
00272         return;
00273 
00274     k = k.mid( tagActionList.length() );
00275 
00276     if ( mergingIdx.clientName != state.clientName )
00277         return;
00278 
00279     if ( k != state.actionListName )
00280         return;
00281 
00282     ContainerClient *client = findChildContainerClient( state.guiClient,
00283                                                         QString::null,
00284                                                         mergingIndices.end() );
00285 
00286     ActionListMap::Iterator lIt( client->actionLists.find( k ) );
00287     if ( lIt == client->actionLists.end() )
00288         return;
00289 
00290     lIt.data().unplug( container );
00291 
00292     adjustMergingIndices( -int(lIt.data().count()), mergingIdxIt );
00293 
00294     client->actionLists.remove( lIt );
00295 }
00296 
00297 void ContainerNode::adjustMergingIndices( int offset,
00298                                           const MergingIndexList::Iterator &it )
00299 {
00300     MergingIndexList::Iterator mergingIt = it;
00301     MergingIndexList::Iterator mergingEnd = mergingIndices.end();
00302 
00303     for (; mergingIt != mergingEnd; ++mergingIt )
00304         (*mergingIt).value += offset;
00305 
00306     index += offset;
00307 }
00308 
00309 bool ContainerNode::destruct( QDomElement element, BuildState &state )
00310 {
00311     destructChildren( element, state );
00312 
00313     unplugActions( state );
00314 
00315     // remove all merging indices the client defined
00316     MergingIndexList::Iterator cmIt = mergingIndices.begin();
00317     while ( cmIt != mergingIndices.end() )
00318         if ( (*cmIt).clientName == state.clientName )
00319             cmIt = mergingIndices.remove( cmIt );
00320         else
00321             ++cmIt;
00322 
00323     // ### check for merging index count, too?
00324     if ( clients.count() == 0 && children.count() == 0 && container &&
00325          client == state.guiClient )
00326     {
00327         QWidget *parentContainer = 0L;
00328 
00329         if ( parent && parent->container )
00330             parentContainer = parent->container;
00331 
00332         assert( builder );
00333 
00334         builder->removeContainer( container, parentContainer, element, containerId );
00335 
00336         client = 0L;
00337 
00338         return true;
00339     }
00340 
00341     if ( client == state.guiClient )
00342         client = 0L;
00343 
00344     return false;
00345 
00346 }
00347 
00348 void ContainerNode::destructChildren( const QDomElement &element, BuildState &state )
00349 {
00350     QPtrListIterator<ContainerNode> childIt( children );
00351     while ( childIt.current() )
00352     {
00353         ContainerNode *childNode = childIt.current();
00354 
00355         QDomElement childElement = findElementForChild( element, childNode );
00356 
00357         // destruct returns true in case the container really got deleted
00358         if ( childNode->destruct( childElement, state ) )
00359             removeChild( childNode );
00360         else
00361             ++childIt;
00362     }
00363 }
00364 
00365 QDomElement ContainerNode::findElementForChild( const QDomElement &baseElement,
00366                                                 ContainerNode *childNode )
00367 {
00368     static const QString &attrName = KGlobal::staticQString( "name" );
00369 
00370     // ### slow
00371     for ( QDomNode n = baseElement.firstChild(); !n.isNull();
00372           n = n.nextSibling() )
00373     {
00374         QDomElement e = n.toElement();
00375         if ( e.tagName().lower() == childNode->tagName &&
00376              e.attribute( attrName ) == childNode->name )
00377             return e;
00378     }
00379 
00380     return QDomElement();
00381 }
00382 
00383 void ContainerNode::unplugActions( BuildState &state )
00384 {
00385     if ( !container )
00386         return;
00387 
00388     ContainerClientListIt clientIt( clients );
00389 
00390     /*
00391         Disabled because it means in KToolBar::saveState isHidden is always true then,
00392         which is clearly wrong.
00393 
00394     if ( clients.count() == 1 && clientIt.current()->client == client &&
00395          client == state.guiClient )
00396         container->hide(); // this container is going to die, that's for sure.
00397                            // in this case let's just hide it, which makes the
00398                            // destruction faster
00399      */
00400 
00401     while ( clientIt.current() )
00402         //only unplug the actions of the client we want to remove, as the container might be owned
00403         //by a different client
00404         if ( clientIt.current()->client == state.guiClient )
00405         {
00406             unplugClient( clientIt.current() );
00407             clients.removeRef( clientIt.current() );
00408         }
00409         else
00410             ++clientIt;
00411 }
00412 
00413 void ContainerNode::unplugClient( ContainerClient *client )
00414 {
00415     static const QString &tagActionList = KGlobal::staticQString( "actionlist" );
00416 
00417     assert( builder );
00418 
00419     // now quickly remove all custom elements (i.e. separators) and unplug all actions
00420 
00421     QValueList<int>::ConstIterator custIt = client->customElements.begin();
00422     QValueList<int>::ConstIterator custEnd = client->customElements.end();
00423     for (; custIt != custEnd; ++custIt )
00424         builder->removeCustomElement( container, *custIt );
00425 
00426     client->actions.unplug( container );
00427 
00428     // now adjust all merging indices
00429 
00430     MergingIndexList::Iterator mergingIt = findIndex( client->mergingName );
00431 
00432     adjustMergingIndices( - int( client->actions.count()
00433                           + client->customElements.count() ),
00434                           mergingIt );
00435 
00436     // unplug all actionslists
00437 
00438     ActionListMap::ConstIterator alIt = client->actionLists.begin();
00439     ActionListMap::ConstIterator alEnd = client->actionLists.end();
00440     for (; alIt != alEnd; ++alIt )
00441     {
00442         alIt.data().unplug( container );
00443 
00444         // construct the merging index key (i.e. like named merging) , find the
00445         // corresponding merging index and adjust all indices
00446         QString mergingKey = alIt.key();
00447         mergingKey.prepend( tagActionList );
00448 
00449         MergingIndexList::Iterator mIt = findIndex( mergingKey );
00450         if ( mIt == mergingIndices.end() )
00451             continue;
00452 
00453         adjustMergingIndices( -int(alIt.data().count()), mIt );
00454 
00455         // remove the actionlists' merging index
00456         // ### still needed? we clean up below anyway?
00457         mergingIndices.remove( mIt );
00458     }
00459 }
00460 
00461 void ContainerNode::reset()
00462 {
00463     QPtrListIterator<ContainerNode> childIt( children );
00464     for (; childIt.current(); ++childIt )
00465         childIt.current()->reset();
00466 
00467     if ( client )
00468         client->setFactory( 0L );
00469 }
00470 
00471 int ContainerNode::calcMergingIndex( const QString &mergingName,
00472                                      MergingIndexList::Iterator &it,
00473                                      BuildState &state,
00474                                      bool ignoreDefaultMergingIndex )
00475 {
00476     MergingIndexList::Iterator mergingIt;
00477 
00478     if ( mergingName.isEmpty() )
00479         mergingIt = findIndex( state.clientName );
00480     else
00481         mergingIt = findIndex( mergingName );
00482 
00483     MergingIndexList::Iterator mergingEnd = mergingIndices.end();
00484     it = mergingEnd;
00485 
00486     if ( ( mergingIt == mergingEnd && state.currentDefaultMergingIt == mergingEnd ) ||
00487          ignoreDefaultMergingIndex )
00488         return index;
00489 
00490     if ( mergingIt != mergingEnd )
00491         it = mergingIt;
00492     else
00493         it = state.currentDefaultMergingIt;
00494 
00495     return (*it).value;
00496 }
00497 
00498 int BuildHelper::calcMergingIndex( const QDomElement &element, MergingIndexList::Iterator &it, QString &group )
00499 {
00500     static const QString &attrGroup = KGlobal::staticQString( "group" );
00501 
00502     bool haveGroup = false;
00503     group = element.attribute( attrGroup );
00504     if ( !group.isEmpty() ) {
00505         group.prepend( attrGroup );
00506         haveGroup = true;
00507     }
00508 
00509     int idx;
00510     if ( haveGroup )
00511         idx = parentNode->calcMergingIndex( group, it, m_state, ignoreDefaultMergingIndex );
00512     else if ( m_state.currentClientMergingIt == parentNode->mergingIndices.end() )
00513         idx = parentNode->index;
00514     else
00515         idx = (*m_state.currentClientMergingIt).value;
00516 
00517     return idx;
00518 }
00519 
00520 BuildHelper::BuildHelper( BuildState &state, ContainerNode *node )
00521     : containerClient( 0 ), ignoreDefaultMergingIndex( false ), m_state( state ),
00522       parentNode( node )
00523 {
00524     static const QString &defaultMergingName = KGlobal::staticQString( "<default>" );
00525 
00526     // create a list of supported container and custom tags
00527     customTags = m_state.builderCustomTags;
00528     containerTags = m_state.builderContainerTags;
00529 
00530     if ( parentNode->builder != m_state.builder )
00531     {
00532         customTags += parentNode->builderCustomTags;
00533         containerTags += parentNode->builderContainerTags;
00534     }
00535 
00536     if ( m_state.clientBuilder ) {
00537         customTags = m_state.clientBuilderCustomTags + customTags;
00538         containerTags = m_state.clientBuilderContainerTags + containerTags;
00539     }
00540 
00541     m_state.currentDefaultMergingIt = parentNode->findIndex( defaultMergingName );
00542     parentNode->calcMergingIndex( QString::null, m_state.currentClientMergingIt,
00543                                   m_state, /*ignoreDefaultMergingIndex*/ false );
00544 }
00545 
00546 void BuildHelper::build( const QDomElement &element )
00547 {
00548     for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() )
00549     {
00550         QDomElement e = n.toElement();
00551         if (e.isNull()) continue;
00552         processElement( e );
00553     }
00554 }
00555 
00556 void BuildHelper::processElement( const QDomElement &e )
00557 {
00558     // some often used QStrings
00559     static const QString &tagAction = KGlobal::staticQString( "action" );
00560     static const QString &tagMerge = KGlobal::staticQString( "merge" );
00561     static const QString &tagState = KGlobal::staticQString( "state" );
00562     static const QString &tagDefineGroup = KGlobal::staticQString( "definegroup" );
00563     static const QString &tagActionList = KGlobal::staticQString( "actionlist" );
00564     static const QString &attrName = KGlobal::staticQString( "name" );
00565 
00566     QString tag( e.tagName().lower() );
00567     QString currName( e.attribute( attrName ) );
00568 
00569     bool isActionTag = ( tag == tagAction );
00570 
00571     if ( isActionTag || customTags.findIndex( tag ) != -1 )
00572         processActionOrCustomElement( e, isActionTag );
00573     else if ( containerTags.findIndex( tag ) != -1 )
00574         processContainerElement( e, tag, currName );
00575     else if ( tag == tagMerge || tag == tagDefineGroup || tag == tagActionList )
00576         processMergeElement( tag, currName, e );
00577     else if ( tag == tagState )
00578         processStateElement( e );
00579 }
00580 
00581 void BuildHelper::processActionOrCustomElement( const QDomElement &e, bool isActionTag )
00582 {
00583     if ( !parentNode->container )
00584         return;
00585 
00586     MergingIndexList::Iterator it( m_state.currentClientMergingIt );
00587 
00588     QString group;
00589     int idx = calcMergingIndex( e, it, group );
00590 
00591     containerClient = parentNode->findChildContainerClient( m_state.guiClient, group, it );
00592 
00593     bool guiElementCreated = false;
00594     if ( isActionTag )
00595         guiElementCreated = processActionElement( e, idx );
00596     else
00597         guiElementCreated = processCustomElement( e, idx );
00598 
00599     if ( guiElementCreated )
00600         // adjust any following merging indices and the current running index for the container
00601         parentNode->adjustMergingIndices( 1, it );
00602 }
00603 
00604 bool BuildHelper::processActionElement( const QDomElement &e, int idx )
00605 {
00606     assert( m_state.guiClient );
00607 
00608     // look up the action and plug it in
00609     KAction *action = m_state.guiClient->action( e );
00610 
00611     //kdDebug() << "BuildHelper::processActionElement " << e.attribute( "name" ) << " -> " << action << " (in " << m_state.guiClient->actionCollection() << ")" << endl;
00612     if ( !action )
00613         return false;
00614 
00615     action->plug( parentNode->container, idx );
00616 
00617     // save a reference to the plugged action, in order to properly unplug it afterwards.
00618     containerClient->actions.append( action );
00619 
00620     return true;
00621 }
00622 
00623 bool BuildHelper::processCustomElement( const QDomElement &e, int idx )
00624 {
00625     assert( parentNode->builder );
00626 
00627     int id = parentNode->builder->createCustomElement( parentNode->container, idx, e );
00628     if ( id == 0 )
00629         return false;
00630 
00631     containerClient->customElements.append( id );
00632     return true;
00633 }
00634 
00635 void BuildHelper::processStateElement( const QDomElement &element )
00636 {
00637     QString stateName = element.attribute( "name" );
00638 
00639     if ( !stateName || !stateName.length() ) return;
00640 
00641     for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() )
00642     {
00643         QDomElement e = n.toElement();
00644         if (e.isNull()) continue;
00645 
00646         QString tagName = e.tagName().lower();
00647 
00648         if ( tagName != "enable" && tagName != "disable" )
00649             continue;
00650 
00651         bool processingActionsToEnable = (tagName == "enable");
00652 
00653         // process action names
00654         for (QDomNode n2 = n.firstChild(); !n2.isNull(); n2 = n2.nextSibling() )
00655         {
00656             QDomElement actionEl = n2.toElement();
00657             if ( actionEl.tagName().lower() != "action" ) continue;
00658 
00659             QString actionName = actionEl.attribute( "name" );
00660             if ( !actionName || !actionName.length() ) return;
00661 
00662             if ( processingActionsToEnable )
00663                 m_state.guiClient->addStateActionEnabled( stateName, actionName );
00664             else
00665                 m_state.guiClient->addStateActionDisabled( stateName, actionName );
00666 
00667         }
00668     }
00669 }
00670 
00671 void BuildHelper::processMergeElement( const QString &tag, const QString &name, const QDomElement &e )
00672 {
00673     static const QString &tagDefineGroup = KGlobal::staticQString( "definegroup" );
00674     static const QString &tagActionList = KGlobal::staticQString( "actionlist" );
00675     static const QString &defaultMergingName = KGlobal::staticQString( "<default>" );
00676     static const QString &attrGroup = KGlobal::staticQString( "group" );
00677 
00678     QString mergingName( name );
00679     if ( mergingName.isEmpty() )
00680     {
00681         if ( tag == tagDefineGroup )
00682         {
00683             kdError(1000) << "cannot define group without name!" << endl;
00684             return;
00685         }
00686         if ( tag == tagActionList )
00687         {
00688             kdError(1000) << "cannot define actionlist without name!" << endl;
00689             return;
00690         }
00691         mergingName = defaultMergingName;
00692     }
00693 
00694     if ( tag == tagDefineGroup )
00695         mergingName.prepend( attrGroup ); //avoid possible name clashes by prepending
00696                                               // "group" to group definitions
00697     else if ( tag == tagActionList )
00698         mergingName.prepend( tagActionList );
00699 
00700     if ( parentNode->findIndex( mergingName ) != parentNode->mergingIndices.end() )
00701         return; //do not allow the redefinition of merging indices!
00702 
00703     MergingIndexList::Iterator mIt( parentNode->mergingIndices.end() );
00704 
00705     QString group( e.attribute( attrGroup ) );
00706     if ( !group.isEmpty() )
00707         group.prepend( attrGroup );
00708 
00709     // calculate the index of the new merging index. Usually this does not need any calculation,
00710     // we just want the last available index (i.e. append) . But in case the <Merge> tag appears
00711     // "inside" another <Merge> tag from a previously build client, then we have to use the
00712     // "parent's" index. That's why we call calcMergingIndex here.
00713     MergingIndex newIdx;
00714     newIdx.value = parentNode->calcMergingIndex( group, mIt, m_state, ignoreDefaultMergingIndex );
00715     newIdx.mergingName = mergingName;
00716     newIdx.clientName = m_state.clientName;
00717 
00718     // if that merging index is "inside" another one, then append it right after the "parent" .
00719     if ( mIt != parentNode->mergingIndices.end() )
00720         parentNode->mergingIndices.insert( ++mIt, newIdx );
00721     else
00722         parentNode->mergingIndices.append( newIdx );
00723 
00724     if ( mergingName == defaultMergingName )
00725 
00726         ignoreDefaultMergingIndex = true;
00727 
00728     // re-calculate the running default and client merging indices.
00729     m_state.currentDefaultMergingIt = parentNode->findIndex( defaultMergingName );
00730     parentNode->calcMergingIndex( QString::null, m_state.currentClientMergingIt,
00731                                   m_state, ignoreDefaultMergingIndex );
00732 }
00733 
00734 void BuildHelper::processContainerElement( const QDomElement &e, const QString &tag,
00735                                            const QString &name )
00736 {
00737     static const QString &defaultMergingName = KGlobal::staticQString( "<default>" );
00738 
00739     ContainerNode *containerNode = parentNode->findContainer( name, tag,
00740                                                               &containerList,
00741                                                               m_state.guiClient );
00742 
00743     if ( !containerNode )
00744     {
00745         MergingIndexList::Iterator it( m_state.currentClientMergingIt );
00746         QString group;
00747 
00748         int idx = calcMergingIndex( e, it, group );
00749 
00750         int id;
00751 
00752         KXMLGUIBuilder *builder;
00753 
00754         QWidget *container = createContainer( parentNode->container, idx, e, id, &builder );
00755 
00756         // no container? (probably some <text> tag or so ;-)
00757         if ( !container )
00758             return;
00759 
00760         parentNode->adjustMergingIndices( 1, it );
00761 
00762         assert( !parentNode->findContainerNode( container ) );
00763 
00764         containerList.append( container );
00765 
00766         QString mergingName;
00767         if ( it != parentNode->mergingIndices.end() )
00768             mergingName = (*it).mergingName;
00769 
00770         QStringList cusTags = m_state.builderCustomTags;
00771         QStringList conTags = m_state.builderContainerTags;
00772         if ( builder != m_state.builder )
00773         {
00774             cusTags = m_state.clientBuilderCustomTags;
00775             conTags = m_state.clientBuilderContainerTags;
00776         }
00777 
00778         containerNode = new ContainerNode( container, tag, name, parentNode,
00779                                            m_state.guiClient, builder, id,
00780                                            mergingName, group, cusTags, conTags );
00781     }
00782 
00783     BuildHelper( m_state, containerNode ).build( e );
00784 
00785     // and re-calculate running values, for better performance
00786     m_state.currentDefaultMergingIt = parentNode->findIndex( defaultMergingName );
00787     parentNode->calcMergingIndex( QString::null, m_state.currentClientMergingIt,
00788                                   m_state, ignoreDefaultMergingIndex );
00789 }
00790 
00791 QWidget *BuildHelper::createContainer( QWidget *parent, int index,
00792                                        const QDomElement &element, int &id,
00793                                        KXMLGUIBuilder **builder )
00794 {
00795     QWidget *res = 0L;
00796 
00797     if ( m_state.clientBuilder )
00798     {
00799         res = m_state.clientBuilder->createContainer( parent, index, element, id );
00800 
00801         if ( res )
00802         {
00803             *builder = m_state.clientBuilder;
00804             return res;
00805         }
00806     }
00807 
00808     KInstance *oldInstance = m_state.builder->builderInstance();
00809     KXMLGUIClient *oldClient = m_state.builder->builderClient();
00810 
00811     m_state.builder->setBuilderClient( m_state.guiClient );
00812 
00813     res = m_state.builder->createContainer( parent, index, element, id );
00814 
00815     m_state.builder->setBuilderInstance( oldInstance );
00816     m_state.builder->setBuilderClient( oldClient );
00817 
00818     if ( res )
00819         *builder = m_state.builder;
00820 
00821     return res;
00822 }
00823 
00824 void BuildState::reset()
00825 {
00826     clientName = QString::null;
00827     actionListName = QString::null;
00828     actionList.clear();
00829     guiClient = 0;
00830     clientBuilder = 0;
00831 
00832     currentDefaultMergingIt = currentClientMergingIt = MergingIndexList::Iterator();
00833 }
00834 
00835 /* vim: et sw=4
00836  */
KDE Home | KDE Accessibility Home | Description of Access Keys