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 <tqwidget.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( TQWidget *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( TQWidget *container ) const 00041 { 00042 ActionListIt it( *this ); 00043 for (; it.current(); ++it ) 00044 it.current()->unplug( container ); 00045 } 00046 00047 ContainerNode::ContainerNode( TQWidget *_container, const TQString &_tagName, 00048 const TQString &_name, ContainerNode *_parent, 00049 KXMLGUIClient *_client, KXMLGUIBuilder *_builder, 00050 int id, const TQString &_mergingName, 00051 const TQString &_groupName, const TQStringList &customTags, 00052 const TQStringList &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 TQString &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 found. 00089 */ 00090 ContainerNode *ContainerNode::findContainerNode( TQWidget *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 TQString &_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 TQString &name, const TQString &tagName, 00129 const TQPtrList<TQWidget> *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 TQString &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 TQPtrListIterator<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 TQString &tagActionList = KGlobal::staticQString( "actionlist" ); 00224 00225 MergingIndex mergingIdx = *mergingIdxIt; 00226 00227 TQString 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 TQString(), 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 TQPtrListIterator<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 TQString &tagActionList = KGlobal::staticQString( "actionlist" ); 00266 00267 MergingIndex mergingIdx = *mergingIdxIt; 00268 00269 TQString 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 TQString(), 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( TQDomElement 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 TQWidget *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 TQDomElement &element, BuildState &state ) 00349 { 00350 TQPtrListIterator<ContainerNode> childIt( children ); 00351 while ( childIt.current() ) 00352 { 00353 ContainerNode *childNode = childIt.current(); 00354 00355 TQDomElement 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 TQDomElement ContainerNode::findElementForChild( const TQDomElement &baseElement, 00366 ContainerNode *childNode ) 00367 { 00368 static const TQString &attrName = KGlobal::staticQString( "name" ); 00369 00370 // ### slow 00371 for ( TQDomNode n = baseElement.firstChild(); !n.isNull(); 00372 n = n.nextSibling() ) 00373 { 00374 TQDomElement e = n.toElement(); 00375 if ( e.tagName().lower() == childNode->tagName && 00376 e.attribute( attrName ) == childNode->name ) 00377 return e; 00378 } 00379 00380 return TQDomElement(); 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 TQString &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 TQValueList<int>::ConstIterator custIt = client->customElements.begin(); 00422 TQValueList<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 TQString 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 TQPtrListIterator<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 TQString &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 TQDomElement &element, MergingIndexList::Iterator &it, TQString &group ) 00499 { 00500 static const TQString &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 TQString &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( TQString(), m_state.currentClientMergingIt, 00543 m_state, /*ignoreDefaultMergingIndex*/ false ); 00544 } 00545 00546 void BuildHelper::build( const TQDomElement &element ) 00547 { 00548 for (TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) 00549 { 00550 TQDomElement e = n.toElement(); 00551 if (e.isNull()) continue; 00552 processElement( e ); 00553 } 00554 } 00555 00556 void BuildHelper::processElement( const TQDomElement &e ) 00557 { 00558 // some often used QStrings 00559 static const TQString &tagAction = KGlobal::staticQString( "action" ); 00560 static const TQString &tagMerge = KGlobal::staticQString( "merge" ); 00561 static const TQString &tagState = KGlobal::staticQString( "state" ); 00562 static const TQString &tagDefineGroup = KGlobal::staticQString( "definegroup" ); 00563 static const TQString &tagActionList = KGlobal::staticQString( "actionlist" ); 00564 static const TQString &attrName = KGlobal::staticQString( "name" ); 00565 00566 TQString tag( e.tagName().lower() ); 00567 TQString 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 TQDomElement &e, bool isActionTag ) 00582 { 00583 if ( !parentNode->container ) 00584 return; 00585 00586 MergingIndexList::Iterator it( m_state.currentClientMergingIt ); 00587 00588 TQString 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 TQDomElement &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 TQDomElement &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 TQDomElement &element ) 00636 { 00637 TQString stateName = element.attribute( "name" ); 00638 00639 if ( !stateName || !stateName.length() ) return; 00640 00641 for (TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) 00642 { 00643 TQDomElement e = n.toElement(); 00644 if (e.isNull()) continue; 00645 00646 TQString 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 (TQDomNode n2 = n.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) 00655 { 00656 TQDomElement actionEl = n2.toElement(); 00657 if ( actionEl.tagName().lower() != "action" ) continue; 00658 00659 TQString 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 TQString &tag, const TQString &name, const TQDomElement &e ) 00672 { 00673 static const TQString &tagDefineGroup = KGlobal::staticQString( "definegroup" ); 00674 static const TQString &tagActionList = KGlobal::staticQString( "actionlist" ); 00675 static const TQString &defaultMergingName = KGlobal::staticQString( "<default>" ); 00676 static const TQString &attrGroup = KGlobal::staticQString( "group" ); 00677 00678 TQString 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 TQString 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( TQString(), m_state.currentClientMergingIt, 00731 m_state, ignoreDefaultMergingIndex ); 00732 } 00733 00734 void BuildHelper::processContainerElement( const TQDomElement &e, const TQString &tag, 00735 const TQString &name ) 00736 { 00737 static const TQString &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 TQString group; 00747 00748 int idx = calcMergingIndex( e, it, group ); 00749 00750 int id; 00751 00752 KXMLGUIBuilder *builder; 00753 00754 TQWidget *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 TQString mergingName; 00767 if ( it != parentNode->mergingIndices.end() ) 00768 mergingName = (*it).mergingName; 00769 00770 TQStringList cusTags = m_state.builderCustomTags; 00771 TQStringList 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( TQString(), m_state.currentClientMergingIt, 00788 m_state, ignoreDefaultMergingIndex ); 00789 } 00790 00791 TQWidget *BuildHelper::createContainer( TQWidget *parent, int index, 00792 const TQDomElement &element, int &id, 00793 KXMLGUIBuilder **builder ) 00794 { 00795 TQWidget *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 = TQString(); 00827 actionListName = TQString(); 00828 actionList.clear(); 00829 guiClient = 0; 00830 clientBuilder = 0; 00831 00832 currentDefaultMergingIt = currentClientMergingIt = MergingIndexList::Iterator(); 00833 } 00834 00835 /* vim: et sw=4 00836 */