kdeui Library API Documentation

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., 59 Temple Place - Suite 330,
00017    Boston, MA 02111-1307, 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( -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     QDomElement e;
00371     // ### slow
00372     for ( e = baseElement.firstChild().toElement(); !e.isNull();
00373           e = e.nextSibling().toElement() )
00374         if ( e.tagName() == childNode->tagName &&
00375              e.attribute( attrName ) == childNode->name )
00376             return e;
00377 
00378     return QDomElement();
00379 }
00380 
00381 void ContainerNode::unplugActions( BuildState &state )
00382 {
00383     if ( !container )
00384         return;
00385 
00386     ContainerClientListIt clientIt( clients );
00387 
00388     if ( clients.count() == 1 && clientIt.current()->client == client &&
00389          client == state.guiClient )
00390         container->hide(); // this container is going to die, that's for sure.
00391                            // in this case let's just hide it, which makes the
00392                            // destruction faster
00393 
00394     while ( clientIt.current() )
00395         //only unplug the actions of the client we want to remove, as the container might be owned
00396         //by a different client
00397         if ( clientIt.current()->client == state.guiClient )
00398         {
00399             unplugClient( clientIt.current() );
00400             clients.removeRef( clientIt.current() );
00401         }
00402         else
00403             ++clientIt;
00404 }
00405 
00406 void ContainerNode::unplugClient( ContainerClient *client )
00407 {
00408     static const QString &tagActionList = KGlobal::staticQString( "actionlist" );
00409 
00410     assert( builder );
00411 
00412     // now quickly remove all custom elements (i.e. separators) and unplug all actions
00413 
00414     QValueList<int>::ConstIterator custIt = client->customElements.begin();
00415     QValueList<int>::ConstIterator custEnd = client->customElements.end();
00416     for (; custIt != custEnd; ++custIt )
00417         builder->removeCustomElement( container, *custIt );
00418 
00419     client->actions.unplug( container );
00420 
00421     // now adjust all merging indices
00422 
00423     MergingIndexList::Iterator mergingIt = findIndex( client->mergingName );
00424 
00425     adjustMergingIndices( - ( client->actions.count()
00426                           + client->customElements.count() ),
00427                           mergingIt );
00428 
00429     // unplug all actionslists
00430 
00431     ActionListMap::ConstIterator alIt = client->actionLists.begin();
00432     ActionListMap::ConstIterator alEnd = client->actionLists.end();
00433     for (; alIt != alEnd; ++alIt )
00434     {
00435         alIt.data().unplug( container );
00436 
00437         // construct the merging index key (i.e. like named merging) , find the
00438         // corresponding merging index and adjust all indices
00439         QString mergingKey = alIt.key();
00440         mergingKey.prepend( tagActionList );
00441 
00442         MergingIndexList::Iterator mIt = findIndex( mergingKey );
00443         if ( mIt == mergingIndices.end() )
00444             continue;
00445 
00446         adjustMergingIndices( - alIt.data().count(), mIt );
00447 
00448         // remove the actionlists' merging index
00449         // ### still needed? we clean up below anyway?
00450         mergingIndices.remove( mIt );
00451     }
00452 }
00453 
00454 void ContainerNode::reset()
00455 {
00456     QPtrListIterator<ContainerNode> childIt( children );
00457     for (; childIt.current(); ++childIt )
00458         childIt.current()->reset();
00459 
00460     if ( client )
00461         client->setFactory( 0L );
00462 }
00463 
00464 int ContainerNode::calcMergingIndex( const QString &mergingName, 
00465                                      MergingIndexList::Iterator &it,
00466                                      BuildState &state,
00467                                      bool ignoreDefaultMergingIndex )
00468 {
00469     MergingIndexList::Iterator mergingIt;
00470 
00471     if ( mergingName.isEmpty() )
00472         mergingIt = findIndex( state.clientName );
00473     else
00474         mergingIt = findIndex( mergingName );
00475 
00476     MergingIndexList::Iterator mergingEnd = mergingIndices.end();
00477     it = mergingEnd;
00478 
00479     if ( ( mergingIt == mergingEnd && state.currentDefaultMergingIt == mergingEnd ) ||
00480          ignoreDefaultMergingIndex )
00481         return index;
00482 
00483     if ( mergingIt != mergingEnd )
00484         it = mergingIt;
00485     else
00486         it = state.currentDefaultMergingIt;
00487 
00488     return (*it).value;
00489 }
00490 
00491 BuildHelper::BuildHelper( BuildState &state, ContainerNode *node )
00492     : containerClient( 0 ), ignoreDefaultMergingIndex( false ), m_state( state ), 
00493       parentNode( node )
00494 {
00495     static const QString &defaultMergingName = KGlobal::staticQString( "<default>" );
00496 
00497     // create a list of supported container and custom tags
00498     customTags = m_state.builderCustomTags;
00499     containerTags = m_state.builderContainerTags;
00500 
00501     if ( parentNode->builder != m_state.builder )
00502     {
00503         customTags += parentNode->builderCustomTags;
00504         containerTags += parentNode->builderContainerTags;
00505     }
00506 
00507     if ( m_state.clientBuilder ) {
00508         customTags = m_state.clientBuilderCustomTags + customTags;
00509         containerTags = m_state.clientBuilderContainerTags + containerTags;
00510     }
00511 
00512     m_state.currentDefaultMergingIt = parentNode->findIndex( defaultMergingName );
00513     parentNode->calcMergingIndex( QString::null, m_state.currentClientMergingIt, 
00514                                   m_state, /*ignoreDefaultMergingIndex*/ false );
00515 }
00516 
00517 void BuildHelper::build( const QDomElement &element )
00518 {
00519     QDomElement e = element.firstChild().toElement();
00520     for (; !e.isNull(); e = e.nextSibling().toElement() )
00521         processElement( e );
00522 }
00523 
00524 void BuildHelper::processElement( const QDomElement &e )
00525 {
00526     // some often used QStrings
00527     static const QString &tagAction = KGlobal::staticQString( "action" );
00528     static const QString &tagMerge = KGlobal::staticQString( "merge" );
00529     static const QString &tagState = KGlobal::staticQString( "state" );
00530     static const QString &tagDefineGroup = KGlobal::staticQString( "definegroup" );
00531     static const QString &tagActionList = KGlobal::staticQString( "actionlist" );
00532     static const QString &attrName = KGlobal::staticQString( "name" );
00533 
00534     QString tag( e.tagName().lower() );
00535     QString currName( e.attribute( attrName ) );
00536 
00537     bool isActionTag = ( tag == tagAction );
00538 
00539     if ( isActionTag || customTags.findIndex( tag ) != -1 )
00540         processActionOrCustomElement( e, isActionTag );
00541     else if ( containerTags.findIndex( tag ) != -1 )
00542         processContainerElement( e, tag, currName );
00543     else if ( tag == tagMerge || tag == tagDefineGroup || tag == tagActionList )
00544         processMergeElement( tag, currName, e );
00545     else if ( tag == tagState )
00546         processStateElement( e );
00547 }
00548 
00549 void BuildHelper::processActionOrCustomElement( const QDomElement &e, bool isActionTag )
00550 {
00551     static const QString &attrGroup = KGlobal::staticQString( "group" );
00552 
00553     if ( !parentNode->container )
00554         return;
00555 
00556     MergingIndexList::Iterator it( m_state.currentClientMergingIt );
00557 
00558     bool haveGroup = false;
00559     QString group( e.attribute( attrGroup ) );
00560     if ( !group.isEmpty() )
00561     {
00562         group.prepend( attrGroup );
00563         haveGroup = true;
00564     }
00565 
00566     int idx;
00567     if ( haveGroup ) // if we have a group attribute, then we cannot use our nicely
00568                      // cached running merging index values.
00569         idx = parentNode->calcMergingIndex( group, it, m_state, ignoreDefaultMergingIndex );
00570     else if ( m_state.currentClientMergingIt == parentNode->mergingIndices.end() )
00571         // if we don't have a current merging index, then we want to append our action
00572         idx = parentNode->index;
00573     else
00574         idx = (*m_state.currentClientMergingIt).value;
00575 
00576     containerClient = parentNode->findChildContainerClient( m_state.guiClient, group, it );
00577 
00578     bool guiElementCreated = false;
00579     if ( isActionTag )
00580         guiElementCreated = processActionElement( e, idx );
00581     else
00582         guiElementCreated = processCustomElement( e, idx );
00583 
00584     if ( guiElementCreated )
00585         // adjust any following merging indices and the current running index for the container
00586         parentNode->adjustMergingIndices( 1, it );
00587 }
00588 
00589 bool BuildHelper::processActionElement( const QDomElement &e, int idx )
00590 {
00591     assert( m_state.guiClient );
00592 
00593     // look up the action and plug it in
00594     KAction *action = m_state.guiClient->action( e );
00595 
00596     if ( !action )
00597         return false;
00598 
00599     action->plug( parentNode->container, idx );
00600 
00601     // save a reference to the plugged action, in order to properly unplug it afterwards.
00602     containerClient->actions.append( action );
00603 
00604     return true;
00605 }
00606 
00607 bool BuildHelper::processCustomElement( const QDomElement &e, int idx )
00608 {
00609     assert( parentNode->builder );
00610 
00611     int id = parentNode->builder->createCustomElement( parentNode->container, idx, e );
00612     if ( id == 0 )
00613         return false;
00614 
00615     containerClient->customElements.append( id );
00616     return true;
00617 }
00618 
00619 void BuildHelper::processStateElement( const QDomElement &element )
00620 {
00621     QString stateName = element.attribute( "name" );
00622 
00623     if ( !stateName || !stateName.length() ) return;
00624 
00625     QDomElement e = element.firstChild().toElement();
00626 
00627     for (; !e.isNull(); e = e.nextSibling().toElement() ) {
00628         QString tagName = e.tagName().lower();
00629 
00630         if ( tagName != "enable" && tagName != "disable" )
00631             continue;
00632     
00633         bool processingActionsToEnable = (tagName == "enable");
00634 
00635         // process action names
00636         QDomElement actionEl = e.firstChild().toElement();
00637 
00638         for (; !actionEl.isNull(); actionEl = actionEl.nextSibling().toElement() ) {
00639             if ( actionEl.tagName().lower() != "action" ) continue;
00640 
00641             QString actionName = actionEl.attribute( "name" );
00642             if ( !actionName || !actionName.length() ) return;
00643 
00644             if ( processingActionsToEnable )
00645                 m_state.guiClient->addStateActionEnabled( stateName, actionName );
00646             else
00647                 m_state.guiClient->addStateActionDisabled( stateName, actionName );
00648 
00649         }
00650     }
00651 }
00652 
00653 void BuildHelper::processMergeElement( const QString &tag, const QString &name, const QDomElement &e )
00654 {
00655     static const QString &tagDefineGroup = KGlobal::staticQString( "definegroup" );
00656     static const QString &tagActionList = KGlobal::staticQString( "actionlist" );
00657     static const QString &defaultMergingName = KGlobal::staticQString( "<default>" );
00658     static const QString &attrGroup = KGlobal::staticQString( "group" );
00659 
00660     QString mergingName( name );
00661     if ( mergingName.isEmpty() )
00662     {
00663         if ( tag == tagDefineGroup )
00664         {
00665             kdError(1000) << "cannot define group without name!" << endl;
00666             return;
00667         }
00668         if ( tag == tagActionList )
00669         {
00670             kdError(1000) << "cannot define actionlist without name!" << endl;
00671             return;
00672         }
00673         mergingName = defaultMergingName;
00674     }
00675 
00676     if ( tag == tagDefineGroup )
00677         mergingName.prepend( attrGroup ); //avoid possible name clashes by prepending
00678                                               // "group" to group definitions
00679     else if ( tag == tagActionList )
00680         mergingName.prepend( tagActionList );
00681 
00682     if ( parentNode->findIndex( mergingName ) != parentNode->mergingIndices.end() )
00683         return; //do not allow the redefinition of merging indices!
00684 
00685     MergingIndexList::Iterator mIt( parentNode->mergingIndices.end() );
00686 
00687     QString group( e.attribute( attrGroup ) );
00688     if ( !group.isEmpty() ) 
00689         group.prepend( attrGroup );
00690 
00691     // calculate the index of the new merging index. Usually this does not need any calculation,
00692     // we just want the last available index (i.e. append) . But in case the <Merge> tag appears
00693     // "inside" another <Merge> tag from a previously build client, then we have to use the
00694     // "parent's" index. That's why we call calcMergingIndex here.
00695     MergingIndex newIdx;
00696     newIdx.value = parentNode->calcMergingIndex( group, mIt, m_state, ignoreDefaultMergingIndex );
00697     newIdx.mergingName = mergingName;
00698     newIdx.clientName = m_state.clientName;
00699 
00700     // if that merging index is "inside" another one, then append it right after the "parent" .
00701     if ( mIt != parentNode->mergingIndices.end() )
00702         parentNode->mergingIndices.insert( ++mIt, newIdx );
00703     else
00704         parentNode->mergingIndices.append( newIdx );
00705 
00706     if ( mergingName == defaultMergingName )
00707 
00708         ignoreDefaultMergingIndex = true;
00709 
00710     // re-calculate the running default and client merging indices.
00711     m_state.currentDefaultMergingIt = parentNode->findIndex( defaultMergingName );
00712     parentNode->calcMergingIndex( QString::null, m_state.currentClientMergingIt,
00713                                   m_state, ignoreDefaultMergingIndex );
00714 }
00715 
00716 void BuildHelper::processContainerElement( const QDomElement &e, const QString &tag,
00717                                            const QString &name )
00718 {
00719     static const QString &attrGroup = KGlobal::staticQString( "group" );
00720     static const QString &defaultMergingName = KGlobal::staticQString( "<default>" );
00721 
00722     ContainerNode *containerNode = parentNode->findContainer( name, tag,
00723                                                               &containerList,
00724                                                               m_state.guiClient );
00725 
00726     if ( !containerNode )
00727     {
00728         MergingIndexList::Iterator it( m_state.currentClientMergingIt );
00729 
00730         bool haveGroup = false;
00731         QString group( e.attribute( attrGroup ) );
00732         if ( !group.isEmpty() )
00733         {
00734             group.prepend( attrGroup );
00735             haveGroup = true;
00736         }
00737 
00738         int idx;
00739         if ( haveGroup )
00740             idx = parentNode->calcMergingIndex( group, it, m_state, ignoreDefaultMergingIndex );
00741         else if ( m_state.currentClientMergingIt == parentNode->mergingIndices.end() )
00742             idx = parentNode->index;
00743         else
00744             idx = (*m_state.currentClientMergingIt).value;
00745 
00746         int id;
00747 
00748         KXMLGUIBuilder *builder;
00749 
00750         QWidget *container = createContainer( parentNode->container, idx, e, id, &builder );
00751 
00752         // no container? (probably some <text> tag or so ;-)
00753         if ( !container )
00754             return;
00755 
00756         parentNode->adjustMergingIndices( 1, it );
00757 
00758         assert( parentNode->findContainerNode( container ) == 0 );
00759         
00760         containerList.append( container );
00761 
00762         QString mergingName;
00763         if ( it != parentNode->mergingIndices.end() )
00764             mergingName = (*it).mergingName;
00765 
00766         QStringList cusTags = m_state.builderCustomTags;
00767         QStringList conTags = m_state.builderContainerTags;
00768         if ( builder != m_state.builder )
00769         {
00770             cusTags = m_state.clientBuilderCustomTags;
00771             conTags = m_state.clientBuilderContainerTags;
00772         }
00773 
00774         containerNode = new ContainerNode( container, tag, name, parentNode,
00775                                            m_state.guiClient, builder, id, 
00776                                            mergingName, group, cusTags, conTags );
00777     }
00778 
00779     BuildHelper( m_state, containerNode ).build( e );
00780 
00781     // and re-calculate running values, for better performance
00782     m_state.currentDefaultMergingIt = parentNode->findIndex( defaultMergingName );
00783     parentNode->calcMergingIndex( QString::null, m_state.currentClientMergingIt,
00784                                   m_state, ignoreDefaultMergingIndex );
00785 }
00786 
00787 QWidget *BuildHelper::createContainer( QWidget *parent, int index, 
00788                                        const QDomElement &element, int &id, 
00789                                        KXMLGUIBuilder **builder )
00790 {
00791     QWidget *res = 0L;
00792 
00793     if ( m_state.clientBuilder )
00794     {
00795         res = m_state.clientBuilder->createContainer( parent, index, element, id );
00796 
00797         if ( res )
00798         {
00799             *builder = m_state.clientBuilder;
00800             return res;
00801         }
00802     }
00803 
00804     KInstance *oldInstance = m_state.builder->builderInstance();
00805     KXMLGUIClient *oldClient = m_state.builder->builderClient();
00806 
00807     m_state.builder->setBuilderClient( m_state.guiClient );
00808 
00809     res = m_state.builder->createContainer( parent, index, element, id );
00810 
00811     m_state.builder->setBuilderInstance( oldInstance );
00812     m_state.builder->setBuilderClient( oldClient );
00813 
00814     if ( res )
00815         *builder = m_state.builder;
00816 
00817     return res;
00818 }
00819 
00820 void BuildState::reset()
00821 {
00822     clientName = QString::null;
00823     actionListName = QString::null;
00824     actionList.clear();
00825     guiClient = 0;
00826     clientBuilder = 0;
00827 
00828     currentDefaultMergingIt = currentClientMergingIt = MergingIndexList::Iterator();
00829 }
00830 
00831 /* vim: et sw=4
00832  */
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:15:06 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001