/* This file is part of the KDE libraries
   Copyright (C) 2001 Simon Hausmann <hausmann@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "kxmlguifactory_p.h"
#include "kxmlguiclient.h"
#include "kxmlguibuilder.h"

#include <QtGui/QWidget>

#include <kglobal.h>
#include <kdebug.h>

#include <assert.h>
#include <kcomponentdata.h>
#include <ktoolbar.h>

using namespace KXMLGUI;

void ActionList::plug( QWidget *container, int index ) const
{
    QAction* before = 0L; // Insert after end of widget's current actions (default).

    if ((index < 0) || (index > container->actions().count()))
        kWarning() << "Index " << index << " is not within range (0 - " << container->actions().count();
    else if (index != container->actions().count())
        before = container->actions().at(index); // Insert before indexed action.

    foreach (QAction* action, *this) {
        container->insertAction(before, action);
        // before = action; // BUG FIX: do not insert actions in reverse order.
    }
}

void ActionList::unplug( QWidget *container ) const
{
    foreach (QAction* action, *this) {
        if (container->actions().contains(action))
            container->removeAction( action );
    }
}

ContainerNode::ContainerNode( QWidget *_container, const QString &_tagName,
                              const QString &_name, ContainerNode *_parent,
                              KXMLGUIClient *_client, KXMLGUIBuilder *_builder,
                              QAction* _containerAction, const QString &_mergingName,
                              const QString &_groupName, const QStringList &customTags,
                              const QStringList &containerTags )
    : parent( _parent ), client( _client ), builder( _builder ),
      builderCustomTags( customTags ), builderContainerTags( containerTags ),
      container( _container ), containerAction( _containerAction ), tagName( _tagName ), name( _name ),
      groupName( _groupName ), index( 0 ), mergingName( _mergingName )
{
    if ( parent )
        parent->children.append( this );
}

ContainerNode::~ContainerNode()
{
    qDeleteAll(children);
    qDeleteAll(clients);
}

void ContainerNode::removeChild( ContainerNode* child )
{
    MergingIndexList::Iterator mergingIt = findIndex( child->mergingName );
    adjustMergingIndices( -1, mergingIt );
    children.removeAll(child);
    delete child;
}

void ContainerNode::removeChild( QMutableListIterator<ContainerNode*>& childIterator )
{
    MergingIndexList::Iterator mergingIt = findIndex( childIterator.peekNext()->mergingName );
    adjustMergingIndices( -1, mergingIt );
    delete childIterator.next();
    childIterator.remove();
}

/*
 * Find a merging index with the given name. Used to find an index defined by <Merge name="blah"/>
 * or by a <DefineGroup name="foo" /> tag.
 */
MergingIndexList::Iterator ContainerNode::findIndex( const QString &name )
{
    MergingIndexList::Iterator it( mergingIndices.begin() );
    MergingIndexList::Iterator end( mergingIndices.end() );
    for (; it != end; ++it )
        if ( (*it).mergingName == name )
            return it;
    return it;
}

/*
 * Check if the given container widget is a child of this node and return the node structure
 * if fonud.
 */
ContainerNode *ContainerNode::findContainerNode( QWidget *container )
{
    foreach (ContainerNode* child, children )
        if ( child->container == container )
            return child;

    return 0L;
}

/*
 * Find a container recursively with the given name. Either compares _name with the
 * container's tag name or the value of the container's name attribute. Specified by
 * the tag bool .
 */
ContainerNode *ContainerNode::findContainer( const QString &_name, bool tag )
{
    if ( ( tag && tagName == _name ) ||
         ( !tag && name == _name ) )
        return this;

    foreach (ContainerNode* child, children )
    {
        ContainerNode *res = child->findContainer( _name, tag );
        if ( res )
            return res;
    }

    return 0;
}

/*
 * Finds a child container node (not recursively) with the given name and tagname. Explicitly
 * leaves out container widgets specified in the exludeList . Also ensures that the containers
 * belongs to currClient.
 */
ContainerNode *ContainerNode::findContainer( const QString &name, const QString &tagName,
                                             const QList<QWidget*> *excludeList,
                                             KXMLGUIClient * /*currClient*/ )
{
    ContainerNode *res = 0L;
    ContainerNodeList::ConstIterator nIt = children.constBegin();

    if ( !name.isEmpty() )
    {
        for (; nIt != children.constEnd(); ++nIt )
            if ( (*nIt)->name == name &&
                 !excludeList->contains( (*nIt)->container ) )
            {
                res = *nIt;
                break;
            }

        return res;
    }

    if ( !tagName.isEmpty() )
        for (; nIt != children.constEnd(); ++nIt )
        {
            if ( (*nIt)->tagName == tagName &&
                 !excludeList->contains( (*nIt)->container )
                 /*
                  * It is a bad idea to also compare the client, because
                  * we don't want to do so in situations like these:
                  *
                  * <MenuBar>
                  *   <Menu>
                  *     ...
                  *
                  * other client:
                  * <MenuBar>
                  *   <Menu>
                  *    ...
                  *
                 && (*nIt)->client == currClient )
                 */
                )
            {
                res = *nIt;
                break;
            }
        }

    return res;
}

ContainerClient *ContainerNode::findChildContainerClient( KXMLGUIClient *currentGUIClient,
                                                          const QString &groupName,
                                                          const MergingIndexList::Iterator &mergingIdx )
{
    if ( !clients.isEmpty() )
    {
        foreach (ContainerClient* client, clients)
            if ( client->client == currentGUIClient )
            {
                if ( groupName.isEmpty() )
                    return client;

                if ( groupName == client->groupName )
                    return client;
            }
    }

    ContainerClient *client = new ContainerClient;
    client->client = currentGUIClient;
    client->groupName = groupName;

    if ( mergingIdx != mergingIndices.end() )
        client->mergingName = (*mergingIdx).mergingName;

    clients.append( client );

    return client;
}

void ContainerNode::plugActionList( BuildState &state )
{
    MergingIndexList::Iterator mIt( mergingIndices.begin() );
    MergingIndexList::Iterator mEnd( mergingIndices.end() );
    for (; mIt != mEnd; ++mIt )
        plugActionList( state, mIt );

    foreach (ContainerNode* child, children)
        child->plugActionList( state );
}

void ContainerNode::plugActionList( BuildState &state, const MergingIndexList::Iterator &mergingIdxIt )
{
    static const QString &tagActionList = KGlobal::staticQString( "actionlist" );

    MergingIndex mergingIdx = *mergingIdxIt;

    QString k( mergingIdx.mergingName );

    if ( k.indexOf( tagActionList ) == -1 )
        return;

    k = k.mid( tagActionList.length() );

    if ( mergingIdx.clientName != state.clientName )
        return;

    if ( k != state.actionListName )
        return;

    ContainerClient *client = findChildContainerClient( state.guiClient,
                                                        QString(),
                                                        mergingIndices.end() );

    client->actionLists.insert( k, state.actionList );

    state.actionList.plug( container, mergingIdx.value );

    adjustMergingIndices( state.actionList.count(), mergingIdxIt );
}

void ContainerNode::unplugActionList( BuildState &state )
{
    MergingIndexList::Iterator mIt( mergingIndices.begin() );
    MergingIndexList::Iterator mEnd( mergingIndices.end() );
    for (; mIt != mEnd; ++mIt )
        unplugActionList( state, mIt );

    foreach (ContainerNode* child, children)
        child->unplugActionList( state );
}

void ContainerNode::unplugActionList( BuildState &state, const MergingIndexList::Iterator &mergingIdxIt )
{
    static const QString &tagActionList = KGlobal::staticQString( "actionlist" );

    MergingIndex mergingIdx = *mergingIdxIt;

    QString k = mergingIdx.mergingName;

    if ( k.indexOf( tagActionList ) == -1 )
        return;

    k = k.mid( tagActionList.length() );

    if ( mergingIdx.clientName != state.clientName )
        return;

    if ( k != state.actionListName )
        return;

    ContainerClient *client = findChildContainerClient( state.guiClient,
                                                        QString(),
                                                        mergingIndices.end() );

    ActionListMap::Iterator lIt( client->actionLists.find( k ) );
    if ( lIt == client->actionLists.end() )
        return;

    lIt.value().unplug( container );

    adjustMergingIndices( -int(lIt.value().count()), mergingIdxIt );

    client->actionLists.erase( lIt );
}

void ContainerNode::adjustMergingIndices( int offset,
                                          const MergingIndexList::Iterator &it )
{
    MergingIndexList::Iterator mergingIt = it;
    MergingIndexList::Iterator mergingEnd = mergingIndices.end();

    for (; mergingIt != mergingEnd; ++mergingIt )
        (*mergingIt).value += offset;

    index += offset;
}

bool ContainerNode::destruct( QDomElement element, BuildState &state ) //krazy:exclude=passbyvalue (this is correct QDom usage, and a ref wouldn't allow passing doc.documentElement() as argument)
{
    destructChildren( element, state );

    unplugActions( state );

    // remove all merging indices the client defined
    QMutableListIterator<MergingIndex> cmIt = mergingIndices;
    while ( cmIt.hasNext() )
        if ( cmIt.next().clientName == state.clientName )
            cmIt.remove();

    // ### check for merging index count, too?
    if ( clients.count() == 0 && children.count() == 0 && container &&
         client == state.guiClient )
    {
        QWidget *parentContainer = 0L;

        if ( parent && parent->container )
            parentContainer = parent->container;

        assert( builder );

        builder->removeContainer( container, parentContainer, element, containerAction );

        client = 0L;

        return true;
    }

    if ( client == state.guiClient )
        client = 0L;

    return false;

}

void ContainerNode::destructChildren( const QDomElement &element, BuildState &state )
{
    QMutableListIterator<ContainerNode*> childIt = children;
    while ( childIt.hasNext() )
    {
        ContainerNode *childNode = childIt.peekNext();

        QDomElement childElement = findElementForChild( element, childNode );

        // destruct returns true in case the container really got deleted
        if ( childNode->destruct( childElement, state ) )
            removeChild( childIt );
        else
            childIt.next();
    }
}

QDomElement ContainerNode::findElementForChild( const QDomElement &baseElement,
                                                ContainerNode *childNode )
{
    static const QString &attrName = KGlobal::staticQString( "name" );

    // ### slow
    for ( QDomNode n = baseElement.firstChild(); !n.isNull();
          n = n.nextSibling() )
    {
        QDomElement e = n.toElement();
        if ( e.tagName().toLower() == childNode->tagName &&
             e.attribute( attrName ) == childNode->name )
            return e;
    }

    return QDomElement();
}

void ContainerNode::unplugActions( BuildState &state )
{
    if ( !container )
        return;

    QMutableListIterator<ContainerClient*> clientIt( clients );

    /*
        Disabled because it means in KToolBar::saveState isHidden is always true then,
        which is clearly wrong.

    if ( clients.count() == 1 && clientIt.current()->client == client &&
         client == state.guiClient )
        container->hide(); // this container is going to die, that's for sure.
                           // in this case let's just hide it, which makes the
                           // destruction faster
     */

    while ( clientIt.hasNext() )
        //only unplug the actions of the client we want to remove, as the container might be owned
        //by a different client
        if ( clientIt.peekNext()->client == state.guiClient )
        {
            unplugClient( clientIt.peekNext() );
            delete clientIt.next();
            clientIt.remove();
        }
        else
            clientIt.next();
}

void ContainerNode::unplugClient( ContainerClient *client )
{
    static const QString &tagActionList = KGlobal::staticQString( "actionlist" );

    assert( builder );

    // now quickly remove all custom elements (i.e. separators) and unplug all actions

    QList<QAction*>::ConstIterator custIt = client->customElements.constBegin();
    QList<QAction*>::ConstIterator custEnd = client->customElements.constEnd();
    for (; custIt != custEnd; ++custIt )
        builder->removeCustomElement( container, *custIt );

    KToolBar *bar = qobject_cast<KToolBar*>(container);
    if (bar) {
        bar->removeXMLGUIClient(client->client);
    }

    client->actions.unplug( container );

    // now adjust all merging indices

    MergingIndexList::Iterator mergingIt = findIndex( client->mergingName );

    adjustMergingIndices( - int( client->actions.count()
                          + client->customElements.count() ),
                          mergingIt );

    // unplug all actionslists

    ActionListMap::ConstIterator alIt = client->actionLists.constBegin();
    ActionListMap::ConstIterator alEnd = client->actionLists.constEnd();
    for (; alIt != alEnd; ++alIt )
    {
        alIt.value().unplug( container );

        // construct the merging index key (i.e. like named merging) , find the
        // corresponding merging index and adjust all indices
        QString mergingKey = alIt.key();
        mergingKey.prepend( tagActionList );

        MergingIndexList::Iterator mIt = findIndex( mergingKey );
        if ( mIt == mergingIndices.end() )
            continue;

        adjustMergingIndices( -int(alIt.value().count()), mIt );

        // remove the actionlists' merging index
        // ### still needed? we clean up below anyway?
        mergingIndices.erase( mIt );
    }
}

void ContainerNode::reset()
{
    foreach (ContainerNode* child, children)
        child->reset();

    if ( client )
        client->setFactory( 0L );
}

int ContainerNode::calcMergingIndex( const QString &mergingName,
                                     MergingIndexList::Iterator &it,
                                     BuildState &state,
                                     bool ignoreDefaultMergingIndex )
{
    MergingIndexList::Iterator mergingIt;

    if ( mergingName.isEmpty() )
        mergingIt = findIndex( state.clientName );
    else
        mergingIt = findIndex( mergingName );

    MergingIndexList::Iterator mergingEnd = mergingIndices.end();
    it = mergingEnd;

    if ( ( mergingIt == mergingEnd && state.currentDefaultMergingIt == mergingEnd ) ||
         ignoreDefaultMergingIndex )
        return index;

    if ( mergingIt != mergingEnd )
        it = mergingIt;
    else
        it = state.currentDefaultMergingIt;

    return (*it).value;
}

int BuildHelper::calcMergingIndex( const QDomElement &element, MergingIndexList::Iterator &it, QString &group )
{
    static const QString &attrGroup = KGlobal::staticQString( "group" );

    bool haveGroup = false;
    group = element.attribute( attrGroup );
    if ( !group.isEmpty() ) {
        group.prepend( attrGroup );
        haveGroup = true;
    }

    int idx;
    if ( haveGroup )
        idx = parentNode->calcMergingIndex( group, it, m_state, ignoreDefaultMergingIndex );
    else if ( m_state.currentClientMergingIt == parentNode->mergingIndices.end() )
        idx = parentNode->index;
    else
        idx = (*m_state.currentClientMergingIt).value;

    return idx;
}

BuildHelper::BuildHelper( BuildState &state, ContainerNode *node )
    : containerClient( 0 ), ignoreDefaultMergingIndex( false ), m_state( state ),
      parentNode( node )
{
    static const QString &defaultMergingName = KGlobal::staticQString( "<default>" );

    // create a list of supported container and custom tags
    customTags = m_state.builderCustomTags;
    containerTags = m_state.builderContainerTags;

    if ( parentNode->builder != m_state.builder )
    {
        customTags += parentNode->builderCustomTags;
        containerTags += parentNode->builderContainerTags;
    }

    if ( m_state.clientBuilder ) {
        customTags = m_state.clientBuilderCustomTags + customTags;
        containerTags = m_state.clientBuilderContainerTags + containerTags;
    }

    m_state.currentDefaultMergingIt = parentNode->findIndex( defaultMergingName );
    parentNode->calcMergingIndex( QString(), m_state.currentClientMergingIt,
                                  m_state, /*ignoreDefaultMergingIndex*/ false );
}

void BuildHelper::build( const QDomElement &element )
{
    for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() )
    {
        QDomElement e = n.toElement();
        if (e.isNull()) continue;
        processElement( e );
    }
}

void BuildHelper::processElement( const QDomElement &e )
{
    // some often used QStrings
    static const QString &tagAction = KGlobal::staticQString( "action" );
    static const QString &tagMerge = KGlobal::staticQString( "merge" );
    static const QString &tagState = KGlobal::staticQString( "state" );
    static const QString &tagDefineGroup = KGlobal::staticQString( "definegroup" );
    static const QString &tagActionList = KGlobal::staticQString( "actionlist" );
    static const QString &attrName = KGlobal::staticQString( "name" );

    QString tag( e.tagName().toLower() );
    QString currName( e.attribute( attrName ) );

    bool isActionTag = ( tag == tagAction );

    if ( isActionTag || customTags.indexOf( tag ) != -1 )
        processActionOrCustomElement( e, isActionTag );
    else if ( containerTags.indexOf( tag ) != -1 )
        processContainerElement( e, tag, currName );
    else if ( tag == tagMerge || tag == tagDefineGroup || tag == tagActionList )
        processMergeElement( tag, currName, e );
    else if ( tag == tagState )
        processStateElement( e );
}

void BuildHelper::processActionOrCustomElement( const QDomElement &e, bool isActionTag )
{
    if ( !parentNode->container )
        return;

    MergingIndexList::Iterator it( m_state.currentClientMergingIt );

    QString group;
    int idx = calcMergingIndex( e, it, group );

    containerClient = parentNode->findChildContainerClient( m_state.guiClient, group, it );

    bool guiElementCreated = false;
    if ( isActionTag )
        guiElementCreated = processActionElement( e, idx );
    else
        guiElementCreated = processCustomElement( e, idx );

    if ( guiElementCreated )
        // adjust any following merging indices and the current running index for the container
        parentNode->adjustMergingIndices( 1, it );
}

bool BuildHelper::processActionElement( const QDomElement &e, int idx )
{
    assert( m_state.guiClient );

    // look up the action and plug it in
    QAction *action = m_state.guiClient->action( e );

    //kDebug(260) << "BuildHelper::processActionElement " << e.attribute( "name" ) << " -> " << action << " (in " << m_state.guiClient->actionCollection() << ")";
    if ( !action )
        return false;

    QAction* before = 0L;
    if (idx >= 0 && idx < parentNode->container->actions().count())
      before = parentNode->container->actions()[idx];

    parentNode->container->insertAction(before, action);

    // save a reference to the plugged action, in order to properly unplug it afterwards.
    containerClient->actions.append( action );

    return true;
}

bool BuildHelper::processCustomElement( const QDomElement &e, int idx )
{
    assert( parentNode->builder );

    QAction* action = parentNode->builder->createCustomElement( parentNode->container, idx, e );
    if ( !action )
        return false;

    containerClient->customElements.append( action );
    return true;
}

void BuildHelper::processStateElement( const QDomElement &element )
{
    QString stateName = element.attribute( "name" );

    if ( stateName.isNull() || !stateName.length() ) return;

    for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() )
    {
        QDomElement e = n.toElement();
        if (e.isNull()) continue;

        QString tagName = e.tagName().toLower();

        if ( tagName != "enable" && tagName != "disable" )
            continue;

        bool processingActionsToEnable = (tagName == "enable");

        // process action names
        for (QDomNode n2 = n.firstChild(); !n2.isNull(); n2 = n2.nextSibling() )
        {
            QDomElement actionEl = n2.toElement();
            if ( actionEl.tagName().toLower() != "action" ) continue;

            QString actionName = actionEl.attribute( "name" );
            if ( actionName.isEmpty() ) return;

            if ( processingActionsToEnable )
                m_state.guiClient->addStateActionEnabled( stateName, actionName );
            else
                m_state.guiClient->addStateActionDisabled( stateName, actionName );

        }
    }
}

void BuildHelper::processMergeElement( const QString &tag, const QString &name, const QDomElement &e )
{
    static const QString &tagDefineGroup = KGlobal::staticQString( "definegroup" );
    static const QString &tagActionList = KGlobal::staticQString( "actionlist" );
    static const QString &defaultMergingName = KGlobal::staticQString( "<default>" );
    static const QString &attrGroup = KGlobal::staticQString( "group" );

    QString mergingName( name );
    if ( mergingName.isEmpty() )
    {
        if ( tag == tagDefineGroup )
        {
            kError(240) << "cannot define group without name!" << endl;
            return;
        }
        if ( tag == tagActionList )
        {
            kError(240) << "cannot define actionlist without name!" << endl;
            return;
        }
        mergingName = defaultMergingName;
    }

    if ( tag == tagDefineGroup )
        mergingName.prepend( attrGroup ); //avoid possible name clashes by prepending
                                              // "group" to group definitions
    else if ( tag == tagActionList )
        mergingName.prepend( tagActionList );

    if ( parentNode->findIndex( mergingName ) != parentNode->mergingIndices.end() )
        return; //do not allow the redefinition of merging indices!

    MergingIndexList::Iterator mIt( parentNode->mergingIndices.end() );

    QString group( e.attribute( attrGroup ) );
    if ( !group.isEmpty() )
        group.prepend( attrGroup );

    // calculate the index of the new merging index. Usually this does not need any calculation,
    // we just want the last available index (i.e. append) . But in case the <Merge> tag appears
    // "inside" another <Merge> tag from a previously build client, then we have to use the
    // "parent's" index. That's why we call calcMergingIndex here.
    MergingIndex newIdx;
    newIdx.value = parentNode->calcMergingIndex( group, mIt, m_state, ignoreDefaultMergingIndex );
    newIdx.mergingName = mergingName;
    newIdx.clientName = m_state.clientName;

    // if that merging index is "inside" another one, then append it right after the "parent" .
    if ( mIt != parentNode->mergingIndices.end() )
        parentNode->mergingIndices.insert( ++mIt, newIdx );
    else
        parentNode->mergingIndices.append( newIdx );

    if ( mergingName == defaultMergingName )

        ignoreDefaultMergingIndex = true;

    // re-calculate the running default and client merging indices.
    m_state.currentDefaultMergingIt = parentNode->findIndex( defaultMergingName );
    parentNode->calcMergingIndex( QString(), m_state.currentClientMergingIt,
                                  m_state, ignoreDefaultMergingIndex );
}

void BuildHelper::processContainerElement( const QDomElement &e, const QString &tag,
                                           const QString &name )
{
    static const QString &defaultMergingName = KGlobal::staticQString( "<default>" );

    ContainerNode *containerNode = parentNode->findContainer( name, tag,
                                                              &containerList,
                                                              m_state.guiClient );

    if ( !containerNode )
    {
        MergingIndexList::Iterator it( m_state.currentClientMergingIt );
        QString group;

        int idx = calcMergingIndex( e, it, group );

        QAction* containerAction;

        KXMLGUIBuilder *builder;

        QWidget *container = createContainer( parentNode->container, idx, e, containerAction, &builder );

        // no container? (probably some <text> tag or so ;-)
        if ( !container )
            return;

        parentNode->adjustMergingIndices( 1, it );

        assert( !parentNode->findContainerNode( container ) );

        containerList.append( container );

        QString mergingName;
        if ( it != parentNode->mergingIndices.end() )
            mergingName = (*it).mergingName;

        QStringList cusTags = m_state.builderCustomTags;
        QStringList conTags = m_state.builderContainerTags;
        if ( builder != m_state.builder )
        {
            cusTags = m_state.clientBuilderCustomTags;
            conTags = m_state.clientBuilderContainerTags;
        }

        containerNode = new ContainerNode( container, tag, name, parentNode,
                                           m_state.guiClient, builder, containerAction,
                                           mergingName, group, cusTags, conTags );
    } else {
        if ( tag == QLatin1String( "toolbar" ) ) {
            KToolBar *bar = qobject_cast<KToolBar*>(containerNode->container);
            if (bar) {
                if ( m_state.guiClient && !m_state.guiClient->xmlFile().isEmpty() )
                    bar->addXMLGUIClient(m_state.guiClient);
            } else {
                kWarning() << "toolbar container is not a KToolBar";
            }
        }
    }

    BuildHelper( m_state, containerNode ).build( e );

    // and re-calculate running values, for better performance
    m_state.currentDefaultMergingIt = parentNode->findIndex( defaultMergingName );
    parentNode->calcMergingIndex( QString(), m_state.currentClientMergingIt,
                                  m_state, ignoreDefaultMergingIndex );
}

QWidget *BuildHelper::createContainer( QWidget *parent, int index,
                                       const QDomElement &element, QAction*& containerAction,
                                       KXMLGUIBuilder **builder )
{
    QWidget *res = 0L;

    if ( m_state.clientBuilder )
    {
        res = m_state.clientBuilder->createContainer( parent, index, element, containerAction );

        if ( res )
        {
            *builder = m_state.clientBuilder;
            return res;
        }
    }

    KComponentData oldInstance = m_state.builder->builderComponentData();
    KXMLGUIClient *oldClient = m_state.builder->builderClient();

    m_state.builder->setBuilderClient( m_state.guiClient );

    res = m_state.builder->createContainer( parent, index, element, containerAction );

    m_state.builder->setBuilderComponentData(oldInstance);
    m_state.builder->setBuilderClient( oldClient );

    if ( res )
        *builder = m_state.builder;

    return res;
}

void BuildState::reset()
{
    clientName.clear();
    actionListName.clear();
    actionList.clear();
    guiClient = 0;
    clientBuilder = 0;

    currentDefaultMergingIt = currentClientMergingIt = MergingIndexList::Iterator();
}

/* vim: et sw=4
 */
