/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/frame/XDispatchRecorderSupplier.hpp>
#include <com/sun/star/frame/XLayoutManager.hpp>
#include <svl/itempool.hxx>
#include <svl/itemiter.hxx>
#include <svl/whiter.hxx>
#include <svl/intitem.hxx>
#include <svl/eitem.hxx>
#include <svl/undo.hxx>
#include <vcl/wrkwin.hxx>
#include <svtools/ttprops.hxx>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>  // due to bsearch

#include <svtools/helpopt.hxx>
#include <com/sun/star/frame/XLayoutManager.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>

// due to nAutoPageID
#include "appdata.hxx"
#include "sfx2/sfxhelp.hxx"
#include <sfx2/dispatch.hxx>
#include <sfx2/minstack.hxx>
#include <sfx2/msg.hxx>
#include <sfx2/objface.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/request.hxx>
#include <sfx2/app.hxx>
#include <sfx2/hintpost.hxx>
#include "slotserv.hxx"
#include <sfx2/ipclient.hxx>
#include "sfxtypes.hxx"
#include <sfx2/viewfrm.hxx>
#include <sfx2/viewsh.hxx>
#include <sfx2/childwin.hxx>
#include <sfx2/docfac.hxx>
#include <sfx2/msgpool.hxx>
#include <sfx2/module.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/sfxuno.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/mnumgr.hxx>
#include "workwin.hxx"
#include <rtl/strbuf.hxx>

namespace css = ::com::sun::star;

//==================================================================
DBG_NAME(SfxDispatcherFlush)
DBG_NAME(SfxDispatcherFillState)

//==================================================================
typedef SfxRequest* SfxRequestPtr;
SV_IMPL_PTRARR( SfxItemPtrArray, SfxPoolItemPtr );
SV_DECL_PTRARR_DEL( SfxRequestPtrArray, SfxRequestPtr, 4, 4 )
SV_IMPL_PTRARR( SfxRequestPtrArray, SfxRequestPtr );

DECL_PTRSTACK(SfxShellStack_Impl, SfxShell*, 8, 4 );
//==================================================================

struct SfxToDo_Impl
{
    SfxShell*  pCluster;
    bool       bPush;
    bool       bDelete;
    bool       bUntil;

    SfxToDo_Impl()
        : pCluster(0)
        , bPush(false)
        , bDelete(false)
        , bUntil(false)
                {}
    SfxToDo_Impl( bool bOpPush, bool bOpDelete, bool bOpUntil, SfxShell& rCluster )
        : pCluster(&rCluster)
        , bPush(bOpPush)
        , bDelete(bOpDelete)
        , bUntil(bOpUntil)
                {}
    ~SfxToDo_Impl(){}

    bool operator==( const SfxToDo_Impl& rWith ) const
    { return pCluster==rWith.pCluster && bPush==rWith.bPush; }
};

DECL_OBJSTACK(SfxToDoStack_Impl, SfxToDo_Impl, 8, 4);
IMPL_OBJSTACK(SfxToDoStack_Impl, SfxToDo_Impl);

struct SfxObjectBars_Impl
{
    sal_uInt32     nResId;  // Resource - and ConfigId of the Toolbox
    sal_uInt16     nMode;   // special visibility flags
    String         aName;
    SfxInterface*  pIFace;

    SfxObjectBars_Impl() :
        nResId( 0 )
    {}
};

//------------------------------------------------------------------

struct SfxDispatcher_Impl
{
    SfxRequestPtrArray   aReqArr;
    const SfxSlotServer* pCachedServ1;  // last called message
    const SfxSlotServer* pCachedServ2;  // penultimate called Message
    SfxShellStack_Impl   aStack;        // active functionality
    Timer                aTimer;        // for Flush
    SfxToDoStack_Impl    aToDoStack;    // not processed Push/Pop
    SfxViewFrame*        pFrame;        // NULL or associated Frame
    SfxDispatcher*       pParent;       // AppDispatcher, NULL if possible
    SfxHintPosterRef     xPoster;       // Execute asynchronous
    sal_Bool             bFlushing;     // sal_True during Flush //?
    sal_Bool             bUpdated;      // Update_Impl has run
    sal_Bool             bLocked;       // No Execute
    sal_Bool     bInvalidateOnUnlock;   // because someone asked
    sal_Bool             bActive;       // not to be confused with set!
    sal_Bool*       pInCallAliveFlag;   // view the Destructor Stack
    SfxObjectBars_Impl   aObjBars[SFX_OBJECTBAR_MAX];
    SfxObjectBars_Impl   aFixedObjBars[SFX_OBJECTBAR_MAX];
    std::vector<sal_uInt32> aChildWins;
    sal_uInt16           nActionLevel;  // in EnterAction
    sal_uInt32           nEventId;      // EventId UserEvent
    sal_Bool             bUILocked;     // Update disconnected (no flicker)
    sal_Bool             bNoUI;         // UI only from Parent Dispatcher
    sal_Bool             bReadOnly;     // Document is ReadOnly
    sal_Bool             bQuiet;        // Only use parent dispatcher
    sal_Bool             bModal;        // Only slots from parent dispatcher

    sal_Bool           bFilterEnabling; // sal_True=filter enabled slots,
                                        // 2==ReadOnlyDoc overturned
    sal_uInt16           nFilterCount;  // Number of SIDs in pFilterSIDs
    const sal_uInt16*    pFilterSIDs;   // sorted Array of SIDs
    sal_uInt16           nStandardMode; // ExecuteMode from PlugInDispatcher
    std::vector<sal_uInt16>* pDisableList;
    sal_uInt32           nDisableFlags;
};

#define NO_OBJECTBAR    0
#define OWN_OBJECTBAR   1
#define OTHER_OBJECTBAR 2

//------------------------------------------------------------------

#define SFX_FLUSH_TIMEOUT    50

//====================================================================
sal_Bool SfxDispatcher::IsLocked( sal_uInt16 ) const

/*  [Description]

    With this method it can be determined whether the SfxDispatcher is
    locked or unlocked. A locked SfxDispatcher does not perform <SfxRequest>s
    and no longer provides any status information. It behaves as if all the
    slots are disabled.

    The dispatcher is also marked as blocked, if all Dispatcher are locked
    (<SfxApplication::LockDispatcher()>) or the associated top frame is in the
    modal-mode and if the specified slot are handled as frame-specific
    (ie, not served by the application).
*/

{
    return pImp->bLocked;
}

//--------------------------------------------------------------------
sal_Bool SfxDispatcher::IsAppDispatcher() const

/*  [Description]

    With this method it can be determined if the SfxDispacher is the
    applications dispatcher.

    [Return value]

    sal_Bool   sal_True       it is the application dispatcher.
               sal_Fals       it is a SfxViewFrame dispatcher.
*/

{
    return !pImp->pFrame;
}

//--------------------------------------------------------------------
int SfxDispatcher::Call_Impl( SfxShell& rShell, const SfxSlot &rSlot, SfxRequest &rReq, sal_Bool bRecord )

/*  [Description]

    Helper function to check whether a slot can be executed and
    check the execution itself
*/

{
    SFX_STACK(SfxDispatcher::Call_Impl);

    // The slot may be called (meaning enabled)
    if ( rSlot.IsMode(SFX_SLOT_FASTCALL) || rShell.CanExecuteSlot_Impl(rSlot) )
    {
        if ( GetFrame() )
        {
            // Recording may start
            com::sun::star::uno::Reference< com::sun::star::frame::XFrame > xFrame(
                    GetFrame()->GetFrame().GetFrameInterface(),
                    com::sun::star::uno::UNO_QUERY);

            com::sun::star::uno::Reference< com::sun::star::beans::XPropertySet > xSet(
                    xFrame,
                    com::sun::star::uno::UNO_QUERY);

            if ( xSet.is() )
            {
                com::sun::star::uno::Any aProp = xSet->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DispatchRecorderSupplier")));
                com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorderSupplier > xSupplier;
                com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder > xRecorder;
                aProp >>= xSupplier;
                if(xSupplier.is())
                    xRecorder = xSupplier->getDispatchRecorder();

                if ( bRecord && xRecorder.is() && !rSlot.IsMode(SFX_SLOT_NORECORD) )
                    rReq.Record_Impl( rShell, rSlot, xRecorder, GetFrame() );
            }
        }
        // Get all that is needed, because the slot may not have survived the
        // Execute if it is a 'pseudo slot' for macros or verbs.
        sal_Bool bAutoUpdate = rSlot.IsMode(SFX_SLOT_AUTOUPDATE);

        // API-call parentheses and document-lock during the calls
        {
            // 'this' must respond in the Destructor
            sal_Bool bThisDispatcherAlive = sal_True;
            sal_Bool *pOldInCallAliveFlag = pImp->pInCallAliveFlag;
            pImp->pInCallAliveFlag = &bThisDispatcherAlive;

            SfxViewFrame* pView = GetFrame();
            if ( !pView )
                pView = SfxViewFrame::Current();
            if ( pView )
            {
                rtl::OString aCmd(".uno:");
                aCmd += rSlot.GetUnoName();
                SfxHelp::OpenHelpAgent( &pView->GetFrame(), aCmd );
            }

            SfxExecFunc pFunc = rSlot.GetExecFnc();
            rShell.CallExec( pFunc, rReq );

            // If 'this' is still alive
            if ( bThisDispatcherAlive )
                pImp->pInCallAliveFlag = pOldInCallAliveFlag;
            else
            {
                if ( pOldInCallAliveFlag )
                {
                    // also protect nested stack frames
                    *pOldInCallAliveFlag = sal_False;
                }

                // do nothing after this object is dead
                return rReq.IsDone();
            }
        }

        if ( rReq.IsDone() )
        {
            SfxBindings *pBindings = GetBindings();

            // When AutoUpdate update immediately; "Pseudoslots" must not be
            // Autoupdate!
            if ( bAutoUpdate && pBindings )
            {
                const SfxSlot* pSlave = rSlot.GetLinkedSlot();
                if (pSlave)
                {
                    // When enum slots take any bound slave slot
                    while (!pBindings->IsBound(pSlave->GetSlotId()) && pSlave != &rSlot )
                        pSlave = pSlave->GetLinkedSlot();
                    pBindings->Invalidate(pSlave->GetSlotId());
                    pBindings->Update(pSlave->GetSlotId());
                }
                else
                {
                    pBindings->Invalidate(rSlot.GetSlotId());
                    pBindings->Update(rSlot.GetSlotId());
                }
            }

            return sal_True;
        }
    }

    return sal_False;
}

//====================================================================
void SfxDispatcher::Construct_Impl( SfxDispatcher* pParent )
{
    pImp = new SfxDispatcher_Impl;
    bFlushed = sal_True;
    SfxApplication *pSfxApp = SFX_APP();

    pImp->pCachedServ1 = 0;
    pImp->pCachedServ2 = 0;
    pImp->bFlushing = sal_False;
    pImp->bUpdated = sal_False;
    pImp->bLocked = sal_False;
    pImp->bActive = sal_False;
    pImp->pParent = NULL;
    pImp->bUILocked = sal_False;
    pImp->bNoUI = sal_False;
    pImp->bReadOnly = sal_False;
    pImp->bQuiet = sal_False;
    pImp->bModal = sal_False;
    pImp->pInCallAliveFlag = 0;
    pImp->bFilterEnabling = sal_False;
    pImp->nFilterCount = 0;
    pImp->pFilterSIDs = 0;
    pImp->nStandardMode = 0;
    pImp->pDisableList = pSfxApp->GetDisabledSlotList_Impl();
    pImp->nDisableFlags = 0;

    pImp->pParent = pParent;

    pImp->bInvalidateOnUnlock = sal_False;

    for (sal_uInt16 n=0; n<SFX_OBJECTBAR_MAX; n++)
        pImp->aObjBars[n].nResId = 0;

    GenLink aGenLink( LINK(this, SfxDispatcher, PostMsgHandler) );

    pImp->xPoster = new SfxHintPoster(aGenLink);

    pImp->aTimer.SetTimeout(SFX_FLUSH_TIMEOUT);
    pImp->aTimer.SetTimeoutHdl( LINK(this, SfxDispatcher, EventHdl_Impl ) );
}

SfxDispatcher::SfxDispatcher( SfxDispatcher* pParent )
{
    Construct_Impl( pParent );
    pImp->pFrame = 0;
}

SfxDispatcher::SfxDispatcher( SfxViewFrame *pViewFrame )

/*  [Description]

    The constructor of the SfxDispatcher class places a stack of empty
    <SfxShell> pointers. It is not initially locked and is considered flushed.
*/

{
    if ( pViewFrame )
    {
        SfxViewFrame *pFrame = pViewFrame->GetParentViewFrame();
        if ( pFrame )
            Construct_Impl(  pFrame->GetDispatcher() );
        else
            Construct_Impl( 0 );
    }
    else
        Construct_Impl( 0 );
    pImp->pFrame = pViewFrame;
}

//====================================================================
SfxDispatcher::~SfxDispatcher()

/*  [Description]

    The destructor of the SfxDispatcher class should not be called when the
    SfxDispatcher instance is active. It may, however, still be a <SfxShell>
    pointer on the stack.
*/

{
#ifdef DBG_UTIL
    rtl::OStringBuffer sTemp(RTL_CONSTASCII_STRINGPARAM("Delete Dispatcher "));
    sTemp.append(reinterpret_cast<sal_Int64>(this));
    OSL_TRACE("%s", sTemp.getStr());
    DBG_ASSERT( !pImp->bActive, "deleting active Dispatcher" );
#endif

    // So that no timer by Reschedule in PlugComm strikes the LeaveRegistrations
    pImp->aTimer.Stop();
    pImp->xPoster->SetEventHdl( Link() );

    // Notify the stack varialbles in Call_Impl
    if ( pImp->pInCallAliveFlag )
        *pImp->pInCallAliveFlag = sal_False;

    // Get bindings and application
    SfxApplication *pSfxApp = SFX_APP();
    SfxBindings* pBindings = GetBindings();

    // When not flushed, revive the bindings
    if ( pBindings && !pSfxApp->IsDowning() && !bFlushed )
        pBindings->DLEAVEREGISTRATIONS();

    // may unregister the bindings
    while ( pBindings )
    {
        if ( pBindings->GetDispatcher_Impl() == this)
            pBindings->SetDispatcher(0);
        pBindings = pBindings->GetSubBindings_Impl();
    }

    delete pImp;
}

//====================================================================
void SfxDispatcher::Pop
(
    SfxShell&   rShell,  /* the stack to take the SfxShell instance. */

    sal_uInt16   nMode   /* SFX_SHELL_POP_UNTIL
                            Also all 'rShell' of SfxShells are taken from the
                            stack.

                            SFX_SHELL_POP_DELETE
                            All SfxShells actually taken from the stack
                            will be deleted.

                            SFX_SHELL_PUSH (InPlace use only)
                            The Shell is pushed. */
)
/*  [Description]

    With this method, one or more <SfxShell> are poped from the SfxDispatcher.
    The SfxShell is marked for popping and a timer is set up. Only when the
    timer has reached the end, the pop is actually performed
    ( <SfxDispatcher::Flush()> ) and the <SfxBindings> is invalidated.
    While the timer is running the opposing push and pop commands on one
    SfxShell cancel each other out.
*/

{
    DBG_MEMTEST();
    DBG_ASSERT( rShell.GetInterface(),
                "pushing SfxShell without previous RegisterInterface()" );

    bool bDelete = (nMode & SFX_SHELL_POP_DELETE) == SFX_SHELL_POP_DELETE;
    bool bUntil = (nMode & SFX_SHELL_POP_UNTIL) == SFX_SHELL_POP_UNTIL;
    bool bPush = (nMode & SFX_SHELL_PUSH) == SFX_SHELL_PUSH;

    SfxApplication *pSfxApp = SFX_APP();

    SAL_INFO(
        "sfx2",
        "-SfxDispatcher(" << this << (bPush ? ")::Push(" : ")::Pop(")
            << (rShell.GetInterface()
                ? rShell.GetInterface()->GetClassName() : SAL_STREAM(&rShell))
            << (bDelete ? ") with delete" : ")")
            << (bUntil ? " (up to)" : ""));

    // same shell as on top of the to-do stack?
    if ( pImp->aToDoStack.Count() && pImp->aToDoStack.Top().pCluster == &rShell )
    {
        // cancel inverse actions
        if ( pImp->aToDoStack.Top().bPush != bPush )
            pImp->aToDoStack.Pop();
        else
        {
            DBG_ASSERT( bPush, "SfxInterface pushed more than once" );
            DBG_ASSERT( !bPush, "SfxInterface popped more than once" );
        }
    }
    else
    {
        // Remember ::com::sun::star::chaos::Action
        pImp->aToDoStack.Push( SfxToDo_Impl(bPush, bDelete, bUntil, rShell) );
        if ( bFlushed )
        {
            OSL_TRACE("Unflushed dispatcher!");
            bFlushed = sal_False;
            pImp->bUpdated = sal_False;

            // Put bindings to sleep
            SfxBindings* pBindings = GetBindings();
            if ( pBindings )
                pBindings->DENTERREGISTRATIONS();
        }
    }

    if ( !pSfxApp->IsDowning() && pImp->aToDoStack.Count() )
    {
        // No immediate update is requested
        pImp->aTimer.SetTimeout(SFX_FLUSH_TIMEOUT);
        pImp->aTimer.SetTimeoutHdl( LINK(this, SfxDispatcher, EventHdl_Impl ) );
        pImp->aTimer.Start();
    }
    else
    {
        // but to do nothing
        pImp->aTimer.Stop();

        // Bindings may wake up again
        if ( !pImp->aToDoStack.Count() )
        {
            SfxBindings* pBindings = GetBindings();
            if ( pBindings )
                pBindings->DLEAVEREGISTRATIONS();
        }
    }
}

//--------------------------------------------------------------------

IMPL_LINK_INLINE_START( SfxDispatcher, EventHdl_Impl, void *, pvoid )

/*  [Description]

    This handler is called after <SfxDispatcher::Invalidate()> or after
    changes on the stack (<SfxDispatcher::Push()> and <SfxDispatcher::Pop())

    It flushes the Stack, if it is dirty, thus it actually excecutes the
    pending Push and Pop commands.
*/

{
    (void)pvoid; // unused
    DBG_MEMTEST();

    Flush();
    Update_Impl();
    SfxBindings* pBindings = GetBindings();
    if ( pBindings )
        pBindings->StartUpdate_Impl(sal_False);
    return 0;
}
IMPL_LINK_INLINE_END( SfxDispatcher, EventHdl_Impl, void *, pvoid )

//--------------------------------------------------------------------
sal_Bool SfxDispatcher::CheckVirtualStack( const SfxShell& rShell, sal_Bool bDeep )

/*  [Description]

    With this method it can be tested whether the <SfxShell> rShell is on the
    stack, when it was flushed. This way the SfxDispatcher is not actually
    flushed.

    This method is intended among other things to make assertions possible
    without the side effect of having to flush the SfxDispathcer.
*/

{
    DBG_MEMTEST();
    SFX_STACK(SfxDispatcher::CheckVirtualStack);

    SfxShellStack_Impl aStack( pImp->aStack );
    for ( short nToDo = pImp->aToDoStack.Count()-1; nToDo >= 0; --nToDo )
    {
        SfxToDo_Impl aToDo( pImp->aToDoStack.Top(nToDo) );
        if ( aToDo.bPush )
            aStack.Push( (SfxShell*) aToDo.pCluster );
        else
        {
            SfxShell* pPopped = 0;
            do
            {
                DBG_ASSERT( aStack.Count(), "popping from empty stack" );
                pPopped = aStack.Pop();
            }
            while ( aToDo.bUntil && pPopped != aToDo.pCluster );
            DBG_ASSERT( pPopped == aToDo.pCluster, "popping unpushed SfxInterface" );
        }
    }

    sal_Bool bReturn;
    if ( bDeep )
        bReturn = aStack.Contains(&rShell);
    else
        bReturn = aStack.Top() == &rShell;
    return bReturn;
}

//--------------------------------------------------------------------
sal_uInt16 SfxDispatcher::GetShellLevel( const SfxShell& rShell )

/*  [Description]

    Determines the position of a given SfxShell in the stack of the dispatcher.
    If possible this is flushed before.

    [Return value]

    sal_uInt16                  == USRT_MAX
                                The SfxShell is not on this SfxDispatcher.

                                < USHRT_MAX
                                Position of the SfxShell on the Dispatcher
                                from the top count stating with 0.
*/

{
    DBG_MEMTEST();
    SFX_STACK(SfxDispatcher::GetShellLevel);
    Flush();

    for ( sal_uInt16 n = 0; n < pImp->aStack.Count(); ++n )
        if ( pImp->aStack.Top( n ) == &rShell )
            return n;
    if ( pImp->pParent )
    {
        sal_uInt16 nRet = pImp->pParent->GetShellLevel(rShell);
        if ( nRet == USHRT_MAX )
            return nRet;
        return  nRet + pImp->aStack.Count();
    }

    return USHRT_MAX;
}

//--------------------------------------------------------------------
SfxShell *SfxDispatcher::GetShell(sal_uInt16 nIdx) const

/*  [Description]

    Returns a pointer to the <SfxShell> which is at the position nIdx
    (from the top, last pushed is 0) on the stack.

    Thus the SfxDispatcher is not flushed.

    Is the stack not deep enough a NULL-Pointer is returned.
*/

{
    DBG_MEMTEST();

    sal_uInt16 nShellCount = pImp->aStack.Count();
    if ( nIdx < nShellCount )
        return pImp->aStack.Top(nIdx);
    else if ( pImp->pParent )
        return pImp->pParent->GetShell( nIdx - nShellCount );
    return 0;
}

//--------------------------------------------------------------------
SfxBindings* SfxDispatcher::GetBindings() const

/*  [Description]

    This method returns a pointer to the <SfxBinding> Instance on which the
    SfxDispatcher is curretly bound. A SfxDispatcher is only bound to
    the SfxBindings when it is <UI-aktiv>. If it is not UI-active,
    a NULL-pointer is returned.

    The returned pointer is only valid in the immediate context of the method
    call.
*/

{
    if ( pImp->pFrame )
        return &pImp->pFrame->GetBindings();
    else
        return NULL;
}

//--------------------------------------------------------------------
SfxViewFrame* SfxDispatcher::GetFrame() const

/*  [Description]

    Returns a pointer to the <SfxViewFrame> instance, which belongs to
    this SfxDispatcher. If it is about the application dispatcher,
    a NULL-pointer is returned.
*/

{
    DBG_MEMTEST();
    return pImp->pFrame;
}

//--------------------------------------------------------------------
void SfxDispatcher::DoActivate_Impl( sal_Bool bMDI, SfxViewFrame* /* pOld */ )

/*  [Description]

    This method controls the activation of a dispatcher.

    Since the application dispatcher is always active, either as a sub
    dispatcher of the <SfxViewFrame> dispatcher or as itself, it is never
    activated as a whole, instead only its individual <SfxShell>s at
    <SfxDispatcher::Push(SfxShell&)>.

    When activating a SfxDispatcher all of the SfxShells located on its stack
    are called with the handler <SfxShell::Activate(sal_Bool)>, starting with
    the lowest.
*/

{
    DBG_MEMTEST();
    SFX_STACK(SfxDispatcher::DoActivate);
    if ( bMDI )
    {
#ifdef DBG_UTIL
        rtl::OStringBuffer sTemp(
            RTL_CONSTASCII_STRINGPARAM("Activate Dispatcher "));
        sTemp.append(reinterpret_cast<sal_Int64>(this));
        OSL_TRACE("%s", sTemp.getStr());
        DBG_ASSERT( !pImp->bActive, "Activation error" );
#endif
        pImp->bActive = sal_True;
        pImp->bUpdated = sal_False;
        SfxBindings* pBindings = GetBindings();
        if ( pBindings )
        {
            pBindings->SetDispatcher(this);
            pBindings->SetActiveFrame( pImp->pFrame->GetFrame().GetFrameInterface() );
        }
    }
    else
    {
#ifdef DBG_UTIL
        rtl::OStringBuffer sTemp(
            RTL_CONSTASCII_STRINGPARAM("Non-MDI-Activate Dispatcher"));
        sTemp.append(reinterpret_cast<sal_Int64>(this));
        OSL_TRACE("%s", sTemp.getStr());
#endif
    }

    if ( IsAppDispatcher() )
        return;

    for ( int i = int(pImp->aStack.Count()) - 1; i >= 0; --i )
        pImp->aStack.Top( (sal_uInt16) i )->DoActivate_Impl(pImp->pFrame, bMDI);

    if ( bMDI && pImp->pFrame )
    {
        SfxBindings *pBind = GetBindings();
        while ( pBind )
        {
            pBind->HidePopupCtrls_Impl( sal_False );
            pBind = pBind->GetSubBindings_Impl();
        }

        pImp->pFrame->GetFrame().GetWorkWindow_Impl()->HidePopups_Impl( sal_False, sal_False, 1 );
    }

    if ( pImp->aToDoStack.Count() )
    {
        // No immediate update is requested
        pImp->aTimer.SetTimeout(SFX_FLUSH_TIMEOUT);
        pImp->aTimer.SetTimeoutHdl( LINK(this, SfxDispatcher, EventHdl_Impl ) );
        pImp->aTimer.Start();
    }
}

void SfxDispatcher::DoParentActivate_Impl()
{
    for ( int i = int(pImp->aStack.Count()) - 1; i >= 0; --i )
        pImp->aStack.Top( (sal_uInt16) i )->ParentActivate();
}

//--------------------------------------------------------------------
void SfxDispatcher::DoDeactivate_Impl( sal_Bool bMDI, SfxViewFrame* pNew )

/*  [Description]

    This method controls the deactivation of a dispatcher.

    Since the application dispatcher is always active, either as a sub
    dispatcher of the <SfxViewFrame> dispatcher or as itself, it is never
    deactivated as a whole, instead only its individual <SfxShell>s at
    <SfxDispatcher::Pop(SfxShell&)>.

    When deactivating a SfxDispatcher all of the SfxShells located on its stack
    are called with the handler <SfxShell::Deactivate(sal_Bool)>, starting with
    the lowest.
*/

{
    DBG_MEMTEST();
    SFX_STACK(SfxDispatcher::DoDeactivate);

    SfxApplication *pSfxApp = SFX_APP();

    if ( bMDI )
    {
        OSL_TRACE(rtl::OStringBuffer(RTL_CONSTASCII_STRINGPARAM("Deactivate Dispatcher")).append(reinterpret_cast<sal_Int64>(this)).getStr());
        DBG_ASSERT( pImp->bActive, "Deactivate error" );
        pImp->bActive = sal_False;

        if ( pImp->pFrame && !(pImp->pFrame->GetObjectShell()->IsInPlaceActive() ) )
        {
            SfxWorkWindow *pWorkWin = pImp->pFrame->GetFrame().GetWorkWindow_Impl();
            if ( pWorkWin )
            {
                for (size_t n=0; n<pImp->aChildWins.size();)
                {
                    SfxChildWindow *pWin = pWorkWin->GetChildWindow_Impl( (sal_uInt16) ( pImp->aChildWins[n] & 0xFFFF ) );
                    if (!pWin || (pWin && pWin->GetAlignment() == SFX_ALIGN_NOALIGNMENT))
                        pImp->aChildWins.erase(pImp->aChildWins.begin()+n);
                    else
                        n++;
                }
            }
        }
    }
    else {
        OSL_TRACE(rtl::OStringBuffer(RTL_CONSTASCII_STRINGPARAM("Non-MDI-DeActivate Dispatcher")).append(reinterpret_cast<sal_Int64>(this)).getStr());
    }

    if ( IsAppDispatcher() && !pSfxApp->IsDowning() )
        return;

    for ( sal_uInt16 i = 0; i < pImp->aStack.Count(); ++i )
        pImp->aStack.Top(i)->DoDeactivate_Impl(pImp->pFrame, bMDI);

    sal_Bool bHidePopups = bMDI && pImp->pFrame;
    if ( pNew && pImp->pFrame )
    {
        com::sun::star::uno::Reference< com::sun::star::frame::XFrame > xOldFrame(
            pNew->GetFrame().GetFrameInterface()->getCreator(), com::sun::star::uno::UNO_QUERY );

        com::sun::star::uno::Reference< com::sun::star::frame::XFrame > xMyFrame(
            GetFrame()->GetFrame().GetFrameInterface(), com::sun::star::uno::UNO_QUERY );

        if ( xOldFrame == xMyFrame )
            bHidePopups = sal_False;
    }

    if ( bHidePopups )
    {
        SfxBindings *pBind = GetBindings();
        while ( pBind )
        {
            pBind->HidePopupCtrls_Impl( sal_True );
            pBind = pBind->GetSubBindings_Impl();
        }

        pImp->pFrame->GetFrame().GetWorkWindow_Impl()->HidePopups_Impl( sal_True, sal_False, 1 );
    }

    Flush();
}

void SfxDispatcher::DoParentDeactivate_Impl()
{
    for ( int i = int(pImp->aStack.Count()) - 1; i >= 0; --i )
        pImp->aStack.Top( (sal_uInt16) i )->ParentDeactivate();
}

//--------------------------------------------------------------------
int SfxDispatcher::GetShellAndSlot_Impl
(
    sal_uInt16      nSlot,    // the searchable Slot-Id
    SfxShell**      ppShell,  // the SfxShell, which are currently handled
                              // the nSlot
    const SfxSlot** ppSlot,   // the SfxSlot, which are currently handled
                              // the nSlot
    sal_Bool        bOwnShellsOnly,
    sal_Bool        bModal,   // ModalMode
    sal_Bool        bRealSlot
)

/*  [Description]

    This method searches in SfxDispatcher after <SfxShell> , from the Slot Id
    nSlot currently being handled. For this, the dispatcher is first flushed.

    [Return value]

    int              sal_True
                     The SfxShell was found, ppShell and ppSlot are valid.

                     sal_False
                     The SfxShell was not found, ppShell and ppSlot are invalid.
*/

{
    SFX_STACK(SfxDispatcher::GetShellAndSlot_Impl);

    Flush();
    SfxSlotServer aSvr;
    if ( _FindServer(nSlot, aSvr, bModal) )
    {
        if ( bOwnShellsOnly && aSvr.GetShellLevel() >= pImp->aStack.Count() )
            return sal_False;

        *ppShell = GetShell(aSvr.GetShellLevel());
        *ppSlot = aSvr.GetSlot();
        if ( 0 == (*ppSlot)->GetExecFnc() && bRealSlot )
            *ppSlot = (*ppShell)->GetInterface()->GetRealSlot(*ppSlot);
        // Check only real slots as enum slots don't have an execute function!
        if ( bRealSlot && ((0 == *ppSlot) || (0 == (*ppSlot)->GetExecFnc()) ))
            return sal_False;

        return sal_True;
    }

    return sal_False;
}

//--------------------------------------------------------------------
void SfxDispatcher::_Execute
(
    SfxShell&       rShell,    // to the calling <SfxShell>
    const SfxSlot&  rSlot,     // to the calling <SfxSlot>
    SfxRequest&     rReq,      // function to be performed
                               // (Id and optional parameters)
    SfxCallMode     eCallMode  // Synchronously, asynchronously or as shown in
                               // the slot
)

/*  [Description]

    This method performs a request for a cached <Slot-Server>.
*/

{
    DBG_MEMTEST();
    DBG_ASSERT( !pImp->bFlushing, "recursive call to dispatcher" );
    DBG_ASSERT( !pImp->aToDoStack.Count(), "unprepared InPlace _Execute" );

    if ( IsLocked( rSlot.GetSlotId() ) )
        return;

    if ( (eCallMode & SFX_CALLMODE_ASYNCHRON) ||
         ( !(eCallMode & SFX_CALLMODE_SYNCHRON) &&
           rSlot.IsMode(SFX_SLOT_ASYNCHRON) ) )
    {
        SfxDispatcher *pDispat = this;
        while ( pDispat )
        {
            sal_uInt16 nShellCount = pDispat->pImp->aStack.Count();
            for ( sal_uInt16 n=0; n<nShellCount; n++ )
            {
                if ( &rShell == pDispat->pImp->aStack.Top(n) )
                {
                    if ( eCallMode & SFX_CALLMODE_RECORD )
                        rReq.AllowRecording( sal_True );
                    pDispat->pImp->xPoster->Post(new SfxRequest(rReq));
                    return;
                }
            }

            pDispat = pDispat->pImp->pParent;
        }
    }
    else
        Call_Impl( rShell, rSlot, rReq, SFX_CALLMODE_RECORD==(eCallMode&SFX_CALLMODE_RECORD) );
}

//--------------------------------------------------------------------
void MappedPut_Impl( SfxAllItemSet &rSet, const SfxPoolItem &rItem )

/*  [Description]

    Helper function to put from rItem below the Which-ID in the pool of the
    Item Sets rSet.
*/

{
    // Put with mapped Which-Id if possible
    const SfxItemPool *pPool = rSet.GetPool();
    sal_uInt16 nWhich = rItem.Which();
    if ( pPool->IsSlot(nWhich) )
        nWhich = pPool->GetWhich(nWhich);
    rSet.Put( rItem, nWhich );
}

//--------------------------------------------------------------------

#ifndef SFX_USE_BINDINGS
#define SFX_USE_BINDINGS 0x8000
#endif

sal_uInt16 SfxDispatcher::ExecuteFunction( sal_uInt16 nSlot, SfxPoolItem **pArgs,
                                       sal_uInt16 nMode )
{
    if ( !nMode )
        nMode = pImp->nStandardMode;

    // through Bindings/Interceptor? (then the return value is not exact)
    sal_Bool bViaBindings = SFX_USE_BINDINGS == ( nMode & SFX_USE_BINDINGS );
    nMode &= ~sal_uInt16(SFX_USE_BINDINGS);
    if ( bViaBindings && GetBindings() )
        return GetBindings()->Execute( nSlot, (const SfxPoolItem **) pArgs, nMode )
                ? EXECUTE_POSSIBLE
                : EXECUTE_NO;

    // otherwise through the Dispatcher
    if ( IsLocked(nSlot) )
        return 0;
    SfxShell *pShell = 0;
    SfxCallMode eCall = SFX_CALLMODE_SYNCHRON;
    sal_uInt16 nRet = EXECUTE_NO;
    const SfxSlot *pSlot = 0;
    if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, sal_False, sal_False ) )
    {
        // Feasibility test before
        if ( pSlot->IsMode( SFX_SLOT_FASTCALL ) ||
            pShell->CanExecuteSlot_Impl( *pSlot ) )
                nRet = EXECUTE_POSSIBLE;

        if ( nMode == EXECUTEMODE_ASYNCHRON )
            eCall = SFX_CALLMODE_ASYNCHRON;
        else if ( nMode == EXECUTEMODE_DIALOGASYNCHRON && pSlot->IsMode( SFX_SLOT_HASDIALOG ) )
            eCall = SFX_CALLMODE_ASYNCHRON;
        else if ( pSlot->GetMode() & SFX_SLOT_ASYNCHRON )
            eCall = SFX_CALLMODE_ASYNCHRON;
        if ( pArgs && *pArgs )
        {
            SfxAllItemSet aSet( pShell->GetPool() );
            for ( SfxPoolItem **pArg = pArgs; *pArg; ++pArg )
                MappedPut_Impl( aSet, **pArg );
            SfxRequest aReq( nSlot, eCall, aSet );
            _Execute( *pShell, *pSlot, aReq, eCall );
        }
        else
        {
            SfxRequest aReq( nSlot, eCall, pShell->GetPool() );
            _Execute( *pShell, *pSlot, aReq, eCall );
        }
    }

    return nRet;
}

sal_uInt16 SfxDispatcher::ExecuteFunction( sal_uInt16 nSlot, const SfxItemSet& rArgs,
                                       sal_uInt16 nMode )
{
    if ( !nMode )
        nMode = pImp->nStandardMode;

    // otherwise through the Dispatcher
    if ( IsLocked(nSlot) )
        return 0;
    SfxShell *pShell = 0;
    SfxCallMode eCall = SFX_CALLMODE_SYNCHRON;
    sal_uInt16 nRet = EXECUTE_NO;
    const SfxSlot *pSlot = 0;
    if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, sal_False, sal_False ) )
    {
        // Feasibility test before
        if ( pSlot->IsMode( SFX_SLOT_FASTCALL ) ||
            pShell->CanExecuteSlot_Impl( *pSlot ) )
                nRet = EXECUTE_POSSIBLE;

        if ( nMode == EXECUTEMODE_ASYNCHRON )
            eCall = SFX_CALLMODE_ASYNCHRON;
        else if ( nMode == EXECUTEMODE_DIALOGASYNCHRON && pSlot->IsMode( SFX_SLOT_HASDIALOG ) )
            eCall = SFX_CALLMODE_ASYNCHRON;
        else if ( pSlot->GetMode() & SFX_SLOT_ASYNCHRON )
            eCall = SFX_CALLMODE_ASYNCHRON;
        SfxRequest aReq( nSlot, eCall, rArgs );
        _Execute( *pShell, *pSlot, aReq, eCall );
    }

    return nRet;
}

const SfxSlot* SfxDispatcher::GetSlot( const String& rCommand )
{
    // Count the number of Shells on the linked Dispatcher
    Flush();
    sal_uInt16 nTotCount = pImp->aStack.Count();
    if ( pImp->pParent )
    {
        SfxDispatcher *pParent = pImp->pParent;
        while ( pParent )
        {
            nTotCount = nTotCount + pParent->pImp->aStack.Count();
            pParent = pParent->pImp->pParent;
        }
    }

    const SfxSlot *pSlot=NULL;
    sal_uInt16 nFirstShell = 0;
    for ( sal_uInt16 i = nFirstShell; i < nTotCount; ++i )
    {
        SfxShell *pObjShell = GetShell(i);
        SfxInterface *pIFace = pObjShell->GetInterface();
        pSlot = pIFace->GetSlot( rCommand );
        if ( pSlot )
            return pSlot;
    }

    return 0;
}

//--------------------------------------------------------------------
const SfxPoolItem*  SfxDispatcher::Execute(
    sal_uInt16 nSlot,
    SfxCallMode nCall,
    SfxItemSet* pArgs,
    SfxItemSet* pInternalArgs,
    sal_uInt16 nModi)
{
    if ( IsLocked(nSlot) )
        return 0;

    SfxShell *pShell = 0;
    const SfxSlot *pSlot = 0;
    if ( GetShellAndSlot_Impl( nSlot,  &pShell, &pSlot, sal_False,
                               SFX_CALLMODE_MODAL==(nCall&SFX_CALLMODE_MODAL) ) )
    {
        SfxAllItemSet aSet( pShell->GetPool() );
        if ( pArgs )
        {
            SfxItemIter aIter(*pArgs);
            for ( const SfxPoolItem *pArg = aIter.FirstItem();
                pArg;
                pArg = aIter.NextItem() )
                MappedPut_Impl( aSet, *pArg );
        }
        SfxRequest aReq( nSlot, nCall, aSet );
        if (pInternalArgs)
            aReq.SetInternalArgs_Impl( *pInternalArgs );
        aReq.SetModifier( nModi );

        _Execute( *pShell, *pSlot, aReq, nCall );
        return aReq.GetReturnValue();
    }
    return 0;
}

//--------------------------------------------------------------------
const SfxPoolItem* SfxDispatcher::Execute
(
    sal_uInt16 nSlot,                 // the Id of the executing function
    SfxCallMode eCall,                // SFX_CALLMODE_SYNCRHON, ..._ASYNCHRON
                                      // or ..._SLOT
    const SfxPoolItem **pArgs,        // Zero teminated C-Array of Parameters
    sal_uInt16 nModi,
    const SfxPoolItem **pInternalArgs // Zero terminated C-Array of Parameters
)

/*  [Description]

    Method to excecute a <SfxSlot>s over the Slot-Id.

    [Return value]

    const SfxPoolItem*      Pointer to the SfxPoolItem valid to the next run
                            though the Message-Loop, which contains the return
                            value.

                            Or a NULL-Pointer, when the function was not
                            executed (for example canceled by the user).
*/

{
    if ( IsLocked(nSlot) )
        return 0;

    SfxShell *pShell = 0;
    const SfxSlot *pSlot = 0;
    if ( GetShellAndSlot_Impl( nSlot,  &pShell, &pSlot, sal_False,
                               SFX_CALLMODE_MODAL==(eCall&SFX_CALLMODE_MODAL) ) )
    {
        SfxRequest* pReq;
        if ( pArgs && *pArgs )
        {
            SfxAllItemSet aSet( pShell->GetPool() );
            for ( const SfxPoolItem **pArg = pArgs; *pArg; ++pArg )
                MappedPut_Impl( aSet, **pArg );
            pReq = new SfxRequest( nSlot, eCall, aSet );
        }
        else
            pReq =  new SfxRequest( nSlot, eCall, pShell->GetPool() );
        pReq->SetModifier( nModi );
        if( pInternalArgs && *pInternalArgs)
        {
            SfxAllItemSet aSet( SFX_APP()->GetPool() );
            for ( const SfxPoolItem **pArg = pInternalArgs; *pArg; ++pArg )
                aSet.Put( **pArg );
            pReq->SetInternalArgs_Impl( aSet );
        }
        _Execute( *pShell, *pSlot, *pReq, eCall );
        const SfxPoolItem* pRet = pReq->GetReturnValue();
        delete pReq; return pRet;
    }
    return 0;
}

//--------------------------------------------------------------------
const SfxPoolItem* SfxDispatcher::Execute
(
    sal_uInt16 nSlot,        // the Id of the executing function
    SfxCallMode eCall,       // SFX_CALLMODE_SYNCRHON, ..._ASYNCHRON or ..._SLOT
    const SfxItemSet &rArgs  // <SfxItemSet> with the parameters
)

/*  [Description]

    Method to excecute a <SfxSlot>s over the Slot-Id.

    [Return value]

    const SfxPoolItem*      Pointer to the SfxPoolItem valid to the next run
                            though the Message-Loop, which contains the return
                            value.

                            Or a NULL-Pointer, when the function was not
                            executed (for example canceled by the user).
*/

{
    return Execute( nSlot, eCall, 0, rArgs );
}

//--------------------------------------------------------------------
const SfxPoolItem*  SfxDispatcher::Execute
(
    sal_uInt16 nSlot,
    SfxCallMode eCall,
    sal_uInt16 nModi,
    const SfxItemSet &rArgs
)
{
    if ( IsLocked(nSlot) )
        return 0;

    SfxShell *pShell = 0;
    const SfxSlot *pSlot = 0;
    if ( GetShellAndSlot_Impl( nSlot,  &pShell, &pSlot, sal_False,
                               SFX_CALLMODE_MODAL==(eCall&SFX_CALLMODE_MODAL) ) )
    {
        SfxAllItemSet aSet( pShell->GetPool() );
        SfxItemIter aIter(rArgs);
        for ( const SfxPoolItem *pArg = aIter.FirstItem();
              pArg;
              pArg = aIter.NextItem() )
            MappedPut_Impl( aSet, *pArg );
        SfxRequest aReq( nSlot, eCall, aSet );
        aReq.SetModifier( nModi );
        _Execute( *pShell, *pSlot, aReq, eCall );
        return aReq.GetReturnValue();
    }
    return 0;
}

//--------------------------------------------------------------------
const SfxPoolItem* SfxDispatcher::Execute
(
    sal_uInt16          nSlot,  // the Id of the executing function
    SfxCallMode         eCall,  // SFX_CALLMODE_SYNCRHON, ..._ASYNCHRON or
                                // ..._SLOT
    const SfxPoolItem*  pArg1,  // First parameter
    ...                         // Zero terminated list of parameters
)

/*  [Description]

    Method to excecute a <SfxSlot>s over the Slot-Id.

    [Note]

    The parameters are copied, can therefore be passed on as the address
    of stack objects.

    [Return value]

    const SfxPoolItem*      Pointer to the SfxPoolItem valid to the next run
                            though the Message-Loop, which contains the return
                            value.

                            Or a NULL-Pointer, when the function was not
                            executed (for example canceled by the user).

    [Example]

    pDispatcher->Execute( SID_OPENDOCUMENT, SFX_CALLMODE_SYNCHRON,
        &SfxStringItem( SID_FILE_NAME, "\\tmp\\temp.sdd" ),
        &SfxStringItem( SID_FILTER_NAME, "StarDraw Presentation" ),
        &SfxBoolItem( SID_DOC_READONLY, sal_False ),
        0L );
*/

{
    if ( IsLocked(nSlot) )
        return 0;

    SfxShell *pShell = 0;
    const SfxSlot *pSlot = 0;
    if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, sal_False,
                               SFX_CALLMODE_MODAL==(eCall&SFX_CALLMODE_MODAL) ) )
    {
       SfxAllItemSet aSet( pShell->GetPool() );

       va_list pVarArgs;
       va_start( pVarArgs, pArg1 );
       for ( const SfxPoolItem *pArg = pArg1;
             pArg;
             pArg = va_arg( pVarArgs, const SfxPoolItem* ) )
           MappedPut_Impl( aSet, *pArg );
       va_end(pVarArgs);

       SfxRequest aReq( nSlot, eCall, aSet );
       _Execute( *pShell, *pSlot, aReq, eCall );
       return aReq.GetReturnValue();
    }
    return 0;
}

//--------------------------------------------------------------------

IMPL_LINK( SfxDispatcher, PostMsgHandler, SfxRequest*, pReq )

/*  [Description]

    Helper method to receive the asynchronously executed <SfxRequest>s.
*/

{
    DBG_MEMTEST();
    DBG_ASSERT( !pImp->bFlushing, "recursive call to dispatcher" );
    SFX_STACK(SfxDispatcher::PostMsgHandler);

    // Has also the Pool not yet died?
    if ( !pReq->IsCancelled() )
    {
        if ( !IsLocked(pReq->GetSlot()) )
        {
            Flush();
            SfxSlotServer aSvr;
            if ( _FindServer(pReq->GetSlot(), aSvr, HACK(x) sal_True ) )
            {
                const SfxSlot *pSlot = aSvr.GetSlot();
                SfxShell *pSh = GetShell(aSvr.GetShellLevel());

                DBG( SfxApplication *pSfxApp = SFX_APP() );
                DBG( pSfxApp->EnterAsynchronCall_Impl() );

                // When the pSlot is a "Pseudoslot" for macros or Verbs, it can
                // be destroyed in the Call_Impl, thus do not use it anymore!
                pReq->SetSynchronCall( sal_False );
                Call_Impl( *pSh, *pSlot, *pReq, pReq->AllowsRecording() ); //! why bRecord?
                DBG( pSfxApp->LeaveAsynchronCall_Impl() );
            }
        }
        else
        {
            if ( pImp->bLocked )
                pImp->aReqArr.Insert( new SfxRequest(*pReq), pImp->aReqArr.Count() );
            else
                pImp->xPoster->Post(new SfxRequest(*pReq));
        }
    }

    delete pReq;
    return 0;
}
//--------------------------------------------------------------------
void SfxDispatcher::SetMenu_Impl()
{
    if ( pImp->pFrame )
    {
        SfxViewFrame* pTop = pImp->pFrame->GetTopViewFrame();
        if ( pTop && pTop->GetBindings().GetDispatcher() == this )
        {
            SfxFrame& rFrame = pTop->GetFrame();
            if ( rFrame.IsMenuBarOn_Impl() )
            {
                com::sun::star::uno::Reference < com::sun::star::beans::XPropertySet > xPropSet( rFrame.GetFrameInterface(), com::sun::star::uno::UNO_QUERY );
                if ( xPropSet.is() )
                {
                    com::sun::star::uno::Reference< ::com::sun::star::frame::XLayoutManager > xLayoutManager;
                    com::sun::star::uno::Any aValue = xPropSet->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LayoutManager" )));
                    aValue >>= xLayoutManager;
                    if ( xLayoutManager.is() )
                    {
                        rtl::OUString aMenuBarURL( RTL_CONSTASCII_USTRINGPARAM( "private:resource/menubar/menubar" ));
                        if ( !xLayoutManager->isElementVisible( aMenuBarURL ) )
                            xLayoutManager->createElement( aMenuBarURL );
                    }
                }
            }
        }
    }
}

//--------------------------------------------------------------------
void SfxDispatcher::Update_Impl( sal_Bool bForce )
{
    SFX_STACK(SfxDispatcher::Update_Impl);

    Flush();

    if ( !pImp->pFrame || pImp->bUILocked )
        return;

    SFX_APP();  // -Wall is this required???
    SfxDispatcher *pDisp = this;
    sal_Bool bUpdate = bForce;
    while ( pDisp && pDisp->pImp->pFrame )
    {
        SfxWorkWindow *pWork = pDisp->pImp->pFrame->GetFrame().GetWorkWindow_Impl();
        SfxDispatcher *pAct = pWork->GetBindings().GetDispatcher_Impl();
        if ( pAct == pDisp || pAct == this )
        {
            if ( !bUpdate )
                bUpdate = !pDisp->pImp->bUpdated;
            pDisp->pImp->bUpdated = sal_True;
        }
        else
            break;

        pDisp = pDisp->pImp->pParent;
    }

    if ( !bUpdate || pImp->pFrame->GetFrame().IsClosing_Impl() )
        return;

    SfxViewFrame* pTop = pImp->pFrame ? pImp->pFrame->GetTopViewFrame() : NULL;
    sal_Bool bUIActive = pTop && pTop->GetBindings().GetDispatcher() == this;

    if ( !bUIActive && pTop && GetBindings() == &pTop->GetBindings() )
        // keep own tools internally for collecting
        GetBindings()->GetDispatcher()->pImp->bUpdated = sal_False;

    SfxBindings* pBindings = GetBindings();
    if ( pBindings )
        pBindings->DENTERREGISTRATIONS();

    com::sun::star::uno::Reference< com::sun::star::frame::XFrame > xFrame = pBindings->GetActiveFrame();
    com::sun::star::uno::Reference< com::sun::star::beans::XPropertySet > xPropSet( xFrame, com::sun::star::uno::UNO_QUERY );
    com::sun::star::uno::Reference< ::com::sun::star::frame::XLayoutManager > xLayoutManager;
    if ( xPropSet.is() )
    {
        try
        {
            com::sun::star::uno::Any aValue = xPropSet->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LayoutManager" )) );
            aValue >>= xLayoutManager;
        }
        catch ( com::sun::star::uno::Exception& )
        {
        }
    }

    if ( xLayoutManager.is() )
        xLayoutManager->lock();

    sal_Bool bIsIPActive = pImp->pFrame && pImp->pFrame->GetObjectShell()->IsInPlaceActive();
    SfxInPlaceClient *pClient = pImp->pFrame ? pImp->pFrame->GetViewShell()->GetUIActiveClient() : NULL;
    if ( bUIActive && /* !bIsIPActive && */ ( !pClient || !pClient->IsObjectUIActive() ) )
        SetMenu_Impl();

    SfxWorkWindow *pWorkWin = pImp->pFrame->GetFrame().GetWorkWindow_Impl();
    SfxWorkWindow *pTaskWin = pImp->pFrame->GetTopFrame().GetWorkWindow_Impl();
    pTaskWin->ResetStatusBar_Impl();

    SfxDispatcher *pDispat = this;
    while ( pDispat )
    {
        SfxWorkWindow *pWork = pDispat->pImp->pFrame->GetFrame().GetWorkWindow_Impl();
        SfxDispatcher *pAct = pWork->GetBindings().GetDispatcher_Impl();
        if ( pAct == pDispat || pAct == this )
        {
            pWork->ResetObjectBars_Impl();
            pWork->ResetChildWindows_Impl();
        }

        pDispat = pDispat->pImp->pParent;
    }

    sal_Bool bIsActive = sal_False;
    SfxDispatcher *pActDispat = pWorkWin->GetBindings().GetDispatcher_Impl();
    pDispat = this;
    while ( pActDispat && !bIsActive )
    {
        if ( pDispat == pActDispat )
            bIsActive = sal_True;
        pActDispat = pActDispat->pImp->pParent;
    }

    _Update_Impl( bUIActive, !bIsIPActive, bIsIPActive, pTaskWin );
    if ( bUIActive || bIsActive )
        pWorkWin->UpdateObjectBars_Impl();

    if ( pBindings )
        pBindings->DLEAVEREGISTRATIONS();

    if ( xLayoutManager.is() )
        xLayoutManager->unlock();

    return;
}

void SfxDispatcher::_Update_Impl( sal_Bool bUIActive, sal_Bool bIsMDIApp, sal_Bool bIsIPOwner, SfxWorkWindow *pTaskWin )
{
    SFX_APP();
    SfxWorkWindow *pWorkWin = pImp->pFrame->GetFrame().GetWorkWindow_Impl();
    sal_Bool bIsActive = sal_False;
    sal_Bool bIsTaskActive = sal_False;
    SfxDispatcher *pActDispat = pWorkWin->GetBindings().GetDispatcher_Impl();
    SfxDispatcher *pDispat = this;
    while ( pActDispat && !bIsActive )
    {
        if ( pDispat == pActDispat )
            bIsActive = sal_True;
        pActDispat = pActDispat->pImp->pParent;
    }

    if ( pImp->pParent && !pImp->bQuiet /* && bUIActive */ )
        pImp->pParent->_Update_Impl( bUIActive, bIsMDIApp, bIsIPOwner, pTaskWin );

    for (sal_uInt16 n=0; n<SFX_OBJECTBAR_MAX; n++)
        pImp->aObjBars[n].nResId = 0;
    pImp->aChildWins.clear();

    // bQuiet : own shells aren't considered for UI and SlotServer
    // bNoUI: own Shells aren't considered fors UI
    if ( pImp->bQuiet || pImp->bNoUI || (pImp->pFrame && pImp->pFrame->GetObjectShell()->IsPreview()) )
        return;

    sal_uInt32 nStatBarId=0;
    SfxShell *pStatusBarShell = NULL;

    SfxSlotPool* pSlotPool = &SfxSlotPool::GetSlotPool( GetFrame() );
    sal_uInt16 nTotCount = pImp->aStack.Count();
    for ( sal_uInt16 nShell = nTotCount; nShell > 0; --nShell )
    {
        SfxShell *pShell = GetShell( nShell-1 );
        SfxInterface *pIFace = pShell->GetInterface();

        // don't consider shells if "Hidden" oder "Quiet"
        sal_Bool bReadOnlyShell = IsReadOnlyShell_Impl( nShell-1 );
        sal_uInt16 nNo;
        for ( nNo = 0; pIFace && nNo<pIFace->GetObjectBarCount(); ++nNo )
        {
            sal_uInt16 nPos = pIFace->GetObjectBarPos(nNo);
            if ( bReadOnlyShell && !( nPos & SFX_VISIBILITY_READONLYDOC ) )
                continue;

            // check whether toolbar needs activation of a special feature
            sal_uInt32 nFeature = pIFace->GetObjectBarFeature(nNo);
            if ( nFeature && !pShell->HasUIFeature( nFeature ) )
                continue;

            // check for toolboxes that are exclusively for a viewer
            if ( pImp->pFrame)
            {
                sal_Bool bViewerTbx = SFX_VISIBILITY_VIEWER == ( nPos & SFX_VISIBILITY_VIEWER );
                SfxObjectShell* pSh = pImp->pFrame->GetObjectShell();
                SFX_ITEMSET_ARG( pSh->GetMedium()->GetItemSet(), pItem, SfxBoolItem, SID_VIEWONLY, sal_False );
                sal_Bool bIsViewer = pItem && pItem->GetValue();
                if ( bIsViewer != bViewerTbx )
                    continue;
            }

            // always register toolbars, allows to switch them on
            sal_Bool bVisible = pIFace->IsObjectBarVisible(nNo);
            if ( !bVisible )
                nPos &= SFX_POSITION_MASK;

            SfxObjectBars_Impl& rBar = pImp->aObjBars[nPos & SFX_POSITION_MASK];
            rBar.nMode = nPos;
            rBar.nResId = pIFace->GetObjectBarResId(nNo).GetId();
            const String *pName = pIFace->GetObjectBarName(nNo);
            if ( pName )
                rBar.aName = *pName;
            else
                rBar.aName.Erase();
            rBar.pIFace = pIFace;

            if ( bUIActive || bIsActive )
            {
                pWorkWin->SetObjectBar_Impl(
                    nPos, rBar.nResId, rBar.pIFace, &rBar.aName );
            }

            if ( !bVisible )
                rBar.nResId = 0;
        }

        for ( nNo=0; pIFace && nNo<pIFace->GetChildWindowCount(); nNo++ )
        {
            sal_uInt32 nId = pIFace->GetChildWindowId(nNo);
            const SfxSlot *pSlot = pSlotPool->GetSlot( (sal_uInt16) nId );
            DBG_ASSERT( pSlot, "Childwindow slot missing!");
            if ( bReadOnlyShell )
            {
                // only show ChildWindows if their slot is allowed for readonly documents
                if ( pSlot && !pSlot->IsMode( SFX_SLOT_READONLYDOC ) )
                    continue;
            }

            sal_uInt32 nFeature = pIFace->GetChildWindowFeature(nNo);
            if ( nFeature && !pShell->HasUIFeature( nFeature ) )
                continue;

            // slot decides wether a ChildWindow is shown when document is OLE server or OLE client
            sal_uInt16 nMode = SFX_VISIBILITY_STANDARD;
            if( pSlot )
            {
                if ( pSlot->IsMode(SFX_SLOT_CONTAINER) )
                {
                    if ( pWorkWin->IsVisible_Impl( SFX_VISIBILITY_CLIENT ) )
                        nMode |= SFX_VISIBILITY_CLIENT;
                }
                else
                {
                    if ( pWorkWin->IsVisible_Impl( SFX_VISIBILITY_SERVER ) )
                        nMode |= SFX_VISIBILITY_SERVER;
                }
            }

            if ( bUIActive || bIsActive )
                pWorkWin->SetChildWindowVisible_Impl( nId, sal_True, nMode );
            if ( bUIActive || bIsActive || !pWorkWin->IsFloating( (sal_uInt16) ( nId & 0xFFFF ) ) )
                pImp->aChildWins.push_back( nId );
        }

        if ( bIsMDIApp || bIsIPOwner )
        {
            sal_uInt32 nId = pIFace->GetStatusBarResId().GetId();
            if ( nId )
            {
                nStatBarId = nId;
                pStatusBarShell =  pShell;
            }
        }
    }

    for ( sal_uInt16 nPos=0; nPos<SFX_OBJECTBAR_MAX; nPos++ )
    {
        SfxObjectBars_Impl& rFixed = pImp->aFixedObjBars[nPos];
        if ( rFixed.nResId )
        {
            SfxObjectBars_Impl& rBar = pImp->aObjBars[nPos];
            rBar = rFixed;
            pWorkWin->SetObjectBar_Impl( rFixed.nMode,
                rFixed.nResId, rFixed.pIFace, &rFixed.aName );
        }
    }

    if ( pTaskWin && ( bIsMDIApp || bIsIPOwner ) )
    {
        SfxDispatcher *pActDispatcher = pTaskWin->GetBindings().GetDispatcher_Impl();
        SfxDispatcher *pDispatcher = this;
        while ( pActDispatcher && !bIsTaskActive )
        {
            if ( pDispatcher == pActDispatcher )
                bIsTaskActive = sal_True;
            pActDispatcher = pActDispatcher->pImp->pParent;
        }

        if ( bIsTaskActive && nStatBarId && pImp->pFrame )
        {
            // internal frames also may control statusbar
            SfxBindings& rBindings = pImp->pFrame->GetBindings();
            pImp->pFrame->GetFrame().GetWorkWindow_Impl()->SetStatusBar_Impl( nStatBarId, pStatusBarShell, rBindings );
        }
    }
}

//--------------------------------------------------------------------
void SfxDispatcher::FlushImpl()

/*  [Description]

    Helper method to execute the outstanding push and pop commands.
*/

{
    DBG_PROFSTART(SfxDispatcherFlush);
    DBG_MEMTEST();
    SFX_STACK(SfxDispatcher::FlushImpl);

    OSL_TRACE("Flushing dispatcher!");

    pImp->aTimer.Stop();

    if ( pImp->pParent )
        pImp->pParent->Flush();

    pImp->bFlushing = !pImp->bFlushing;
    if ( !pImp->bFlushing )
    {
        pImp->bFlushing = sal_True;
        DBG_PROFSTOP(SfxDispatcherFlush);
        return;
    }

    SfxApplication *pSfxApp = SFX_APP();

    // Re-build the true stack in the first round
    SfxToDoStack_Impl aToDoCopy;
    sal_Bool bModify = sal_False;
    short nToDo;
    for ( nToDo = pImp->aToDoStack.Count()-1; nToDo >= 0; --nToDo )
    {
        bModify = sal_True;

        SfxToDo_Impl aToDo( pImp->aToDoStack.Top(nToDo) );
        if ( aToDo.bPush )
        {
            // Actually push
            DBG_ASSERT( !pImp->aStack.Contains( aToDo.pCluster ),
                        "pushed SfxShell already on stack" );
            pImp->aStack.Push( aToDo.pCluster );
            aToDo.pCluster->SetDisableFlags( pImp->nDisableFlags );

            // Mark the moved shell
            aToDoCopy.Push( aToDo );
        }
        else
        {
            // Actually pop
            SfxShell* pPopped = 0;
            bool bFound = false;
            do
            {
                DBG_ASSERT( pImp->aStack.Count(), "popping from empty stack" );
                pPopped = pImp->aStack.Pop();
                pPopped->SetDisableFlags( 0 );
                bFound = pPopped == aToDo.pCluster;

                // Mark the moved Shell
                aToDoCopy.Push( SfxToDo_Impl( sal_False, aToDo.bDelete, sal_False, *pPopped) );
            }
            while ( aToDo.bUntil && !bFound );
            DBG_ASSERT( bFound, "wrong SfxShell popped" );
        }

        if ( nToDo == 0 )
            pImp->aToDoStack.Clear();
    }

    // Invalidate bindings, if possible
    if ( !pSfxApp->IsDowning() )
    {
        if ( bModify )
        {
            pImp->pCachedServ1 = 0;
            pImp->pCachedServ2 = 0;
        }

        InvalidateBindings_Impl( bModify );
    }

    pImp->bFlushing = sal_False;
    pImp->bUpdated = sal_False; // not only when bModify, if Doc/Template-Config
    bFlushed = sal_True;
    OSL_TRACE("Successfully flushed dispatcher!");

    // Activate the Shells and possible delete them in the 2nd round
    for ( nToDo = aToDoCopy.Count()-1; nToDo >= 0; --nToDo )
    {
        SfxToDo_Impl aToDo( aToDoCopy.Top(nToDo) );
        if ( aToDo.bPush )
        {
            if ( pImp->bActive )
                aToDo.pCluster->DoActivate_Impl(pImp->pFrame, sal_True);
        }
        else
            if ( pImp->bActive )
                aToDo.pCluster->DoDeactivate_Impl(pImp->pFrame, sal_True);
    }
    for ( nToDo = aToDoCopy.Count()-1; nToDo >= 0; --nToDo )
    {
        SfxToDo_Impl aToDo( aToDoCopy.Top(nToDo) );
        if ( aToDo.bDelete ) delete aToDo.pCluster;
    }
    sal_Bool bAwakeBindings = aToDoCopy.Count() != 0;
    if( bAwakeBindings )
        aToDoCopy.Clear();

    // If more changes have occured on the stach when
    // Activate/Deactivate/Delete:
    if (!bFlushed)
        // If Push/Pop hs been called by someone, theb also EnterReg was called!
        FlushImpl();

    if( bAwakeBindings && GetBindings() )
        GetBindings()->DLEAVEREGISTRATIONS();
    DBG_PROFSTOP(SfxDispatcherFlush);

    for (sal_uInt16 n=0; n<SFX_OBJECTBAR_MAX; n++)
        pImp->aFixedObjBars[n].nResId = 0;

    SAL_INFO("sfx2", "SfxDispatcher(" << this << ")::Flush() done");
}

//--------------------------------------------------------------------
void SfxDispatcher::SetSlotFilter
(
    HACK(hier muss mal ein enum rein)
    sal_Bool           bEnable,  /* sal_True:
                                    only enable specified slots,
                                    disable all other

                                    sal_False:
                                    disable specified slots,
                                    first enable all other
                                 */
    sal_uInt16         nCount,   // Number of SIDs in the following Array
    const sal_uInt16*  pSIDs     // sorted Array of 'nCount' SIDs
)

/*  [Description]

    With this method a filter set, the target slots can be enabled or disabled.
    The passed array must be retained until the destructor or the next
    <SetSlotFilter()>, it is not deleted from the dispatcher, so it can thus be
    static.

    In read-only documents the quasi ReadOnlyDoc Flag of slots can be
    overturned by the use of 'bEnable == 2', so this will be displayed again.
    On the other slots it has no effect.

    [Example]

    Targeted disabling of Slots 1, 2 and 3:

        static sal_uInt16 const pSIDs[] = { 1, 2, 3 };
        pDisp->SetSlotFilter( sal_False, sizeof(pSIDs)/sizeof(sal_uInt16), pSIDs );

    only permit Slots 5, 6 and 7:

        static sal_uInt16 const pSIDs[] = { 5, 6, 7 };
        pDisp->SetSlotFilter( sal_True, sizeof(pSIDs)/sizeof(sal_uInt16), pSIDs );

    Turn-off Filter:

        pDisp->SetSlotFilter();
*/

{
#ifdef DBG_UTIL
    // Check Array
    for ( sal_uInt16 n = 1; n < nCount; ++n )
        DBG_ASSERT( pSIDs[n] > pSIDs[n-1], "SetSlotFilter: SIDs not sorted" );
#endif

    if ( pImp->pFilterSIDs )
        pImp->pFilterSIDs = 0;

    pImp->bFilterEnabling = bEnable;
    pImp->nFilterCount = nCount;
    pImp->pFilterSIDs = pSIDs;

    GetBindings()->InvalidateAll(sal_True);
}

//--------------------------------------------------------------------
EXTERN_C
#ifdef WNT
int _cdecl
#else
int
#endif

SfxCompareSIDs_Impl( const void* pSmaller, const void* pBigger )
{
    DBG_MEMTEST();
    return ( (long) *((sal_uInt16*)pSmaller) ) - ( (long) *((sal_uInt16*)pBigger) );
}

//--------------------------------------------------------------------
sal_Bool SfxDispatcher::IsSlotEnabledByFilter_Impl( sal_uInt16 nSID ) const

/*  [Description]

    Searches for 'nSID' in the Filter set by <SetSlotFilter()> and
    returns sal_True, if the SIDis allowed, or sal_False, if it is
    disabled by the Filter.

    [Return value]
    sal_Bool            0       =>      disabled
                        1       =>      enabled
                        2       =>      enabled even if ReadOnlyDoc
*/

{
    // no filter?
    if ( 0 == pImp->nFilterCount )
        // => all SIDs allowed
        return sal_True;

    // search
    sal_Bool bFound = 0 != bsearch( &nSID, pImp->pFilterSIDs, pImp->nFilterCount,
                                sizeof(sal_uInt16), SfxCompareSIDs_Impl );

    // even if ReadOnlyDoc
    if ( 2 == pImp->bFilterEnabling )
        return bFound ? 2 : 1;
    // Otherwise after Negative/Positive Filter
    return pImp->bFilterEnabling ? bFound : !bFound;
}

//--------------------------------------------------------------------
sal_Bool SfxDispatcher::_TryIntercept_Impl
(
    sal_uInt16      nSlot,    // Slot-Id to search for
    SfxSlotServer&  rServer,  // <SfxSlotServer>-Instance to fill
    sal_Bool        bSelf
)
{
    // Maybe the parent is also belongs to a component
    SfxDispatcher *pParent = pImp->pParent;
    sal_uInt16 nLevels = pImp->aStack.Count();
    while ( pParent && pParent->pImp->pFrame )
    {
        if ( pParent->pImp->pFrame->GetFrame().HasComponent() )
        {
            // Components may be intercepted
            if ( pParent->_TryIntercept_Impl( nSlot, rServer, sal_True ) )
            {
                // The own shells are added to the Shell Level
                rServer.SetShellLevel( rServer.GetShellLevel() + nLevels );
                return sal_True;
            }
            else
                // No further Interception
                break;
        }
        else
            nLevels = nLevels + pParent->pImp->aStack.Count();

        pParent = pParent->pImp->pParent;
    }

    if ( bSelf )
    {
        // Query the ComponentViewShell
        Flush();
        SfxShell *pObjShell = GetShell(0);
        SfxInterface *pIFace = pObjShell->GetInterface();
        const SfxSlot *pSlot = pIFace->GetSlot(nSlot);

        if ( pSlot )
        {
            rServer.SetSlot(pSlot);
            rServer.SetShellLevel(0);
            return sal_True;
        }
    }

    return sal_False;
}

sal_Bool SfxDispatcher::_FindServer
(
    sal_uInt16      nSlot,     // Slot-Id to search for
    SfxSlotServer&  rServer,   // <SfxSlotServer>-Instance to fill
    sal_Bool        bModal     // Dispite ModalMode
)

/*  [Description]

    This helper method searches for the <Slot-Server> which currently serves
    the nSlot. As the result, rServe is filled accordingly.

    If known the SfxInterface which is currently served by nSlot can be
    passed along.

    The SfxDispatcher is flushed while searching for nSlot.

    [Return value]


    sal_Bool            sal_True
                        The Slot was found, rServer is valid.

                        sal_False
                        The Slot is currently not served, rServer is invalid.
*/

{
    SFX_STACK(SfxDispatcher::_FindServer);

    // Dispatcher locked? (nevertheless let SID_HELP_PI through)
    if ( IsLocked(nSlot) )
    {
        pImp->bInvalidateOnUnlock = sal_True;
        return sal_False;
    }

    // Count the number of Shells in the linked dispatchers.
    Flush();
    sal_uInt16 nTotCount = pImp->aStack.Count();
    if ( pImp->pParent )
    {
        SfxDispatcher *pParent = pImp->pParent;
        while ( pParent )
        {
            nTotCount = nTotCount + pParent->pImp->aStack.Count();
            pParent = pParent->pImp->pParent;
        }
    }

    // Verb-Slot?
    if (nSlot >= SID_VERB_START && nSlot <= SID_VERB_END)
    {
        for ( sal_uInt16 nShell = 0;; ++nShell )
        {
            SfxShell *pSh = GetShell(nShell);
            if ( pSh == NULL )
                return false;
            if ( pSh->ISA(SfxViewShell) )
            {
                const SfxSlot* pSlot = pSh->GetVerbSlot_Impl(nSlot);
                if ( pSlot )
                {
                    rServer.SetShellLevel(nShell);
                    rServer.SetSlot( pSlot );
                    return true;
                }
            }
        }
    }

    // SID check against set filter
    sal_uInt16 nSlotEnableMode=0;
    if ( pImp->pFrame )
    {
        nSlotEnableMode = IsSlotEnabledByFilter_Impl( nSlot );
        if ( 0 == nSlotEnableMode )
            return sal_False;
    }

    // In Quiet-Mode only Parent-Dispatcher
    if ( pImp->bQuiet )
    {
        if ( pImp->pParent )
        {
            sal_Bool bRet = pImp->pParent->_FindServer( nSlot, rServer, bModal );
            rServer.SetShellLevel
                ( rServer.GetShellLevel() + pImp->aStack.Count() );
            return bRet;
        }
        else
            return sal_False;
    }

    sal_Bool bReadOnly = ( 2 != nSlotEnableMode && pImp->bReadOnly );

    // search through all the shells of the chained dispatchers
    // from top to bottom
    sal_uInt16 nFirstShell = pImp->bModal && !bModal ? pImp->aStack.Count() : 0;
    for ( sal_uInt16 i = nFirstShell; i < nTotCount; ++i )
    {
        SfxShell *pObjShell = GetShell(i);
        SfxInterface *pIFace = pObjShell->GetInterface();
        const SfxSlot *pSlot = pIFace->GetSlot(nSlot);

        if ( pSlot && pSlot->nDisableFlags && ( pSlot->nDisableFlags & pObjShell->GetDisableFlags() ) != 0 )
            return sal_False;

        if ( pSlot && !( pSlot->nFlags & SFX_SLOT_READONLYDOC ) && bReadOnly )
            return sal_False;

        if ( pSlot )
        {
            // Slot belongs to Container?
            bool bIsContainerSlot = pSlot->IsMode(SFX_SLOT_CONTAINER);
            bool bIsInPlace = pImp->pFrame && pImp->pFrame->GetObjectShell()->IsInPlaceActive();

            // Shell belongs to Server?
            // AppDispatcher or IPFrame-Dispatcher
            bool bIsServerShell = !pImp->pFrame || bIsInPlace;

            // Of course ShellServer-Slots are also executable even when it is
            // excecuted on a container dispatcher without a IPClient.
            if ( !bIsServerShell )
            {
                SfxViewShell *pViewSh = pImp->pFrame->GetViewShell();
                bIsServerShell = !pViewSh || !pViewSh->GetUIActiveClient();
            }

            // Shell belongs to Container?
            // AppDispatcher or no IPFrameDispatcher
            bool bIsContainerShell = !pImp->pFrame || !bIsInPlace;
            // Shell and Slot match
            if ( !( ( bIsContainerSlot && bIsContainerShell ) ||
                    ( !bIsContainerSlot && bIsServerShell ) ) )
                pSlot = 0;
        }

        if ( pSlot && !IsAllowed( nSlot ) )
        {
            pSlot = NULL;
        }

        if ( pSlot )
        {
            rServer.SetSlot(pSlot);
            rServer.SetShellLevel(i);
            return sal_True;
        }
    }

    return sal_False;
}

//--------------------------------------------------------------------
sal_Bool SfxDispatcher::_FillState
(
    const SfxSlotServer&  rSvr,      // <Slot-Server> to query
    SfxItemSet&           rState,    // <SfxItemSet> to be filled
    const SfxSlot*        pRealSlot  // The actual Slot if possible
)

/*  [Description]

    Helper method to obtain the status of the <Slot-Server>s rSvr.
    The required slots IDs (partly converted to Which-IDs of the pool)
    must be present in rstate.

    The SfxDispatcher is flushed before the query.
*/

{
    SFX_STACK(SfxDispatcher::_FillState);

    DBG_PROFSTART(SfxDispatcherFillState);

    const SfxSlot *pSlot = rSvr.GetSlot();
    if ( pSlot && IsLocked( pSlot->GetSlotId() ) )
    {
        pImp->bInvalidateOnUnlock = sal_True;
        DBG_PROFSTOP(SfxDispatcherFillState);
        return sal_False;
    }

    if ( pSlot )
    {
        DBG_ASSERT(bFlushed, "Dispatcher not flushed after retrieving slot servers!");
        if ( !bFlushed )
            return sal_False;

        // Determine the object and call the Message of this object
        SfxShell *pSh = GetShell(rSvr.GetShellLevel());
        DBG_ASSERT(pSh, "ObjektShell not found");

        SfxStateFunc pFunc;

        if (pRealSlot)
            pFunc = pRealSlot->GetStateFnc();
        else
            pFunc = pSlot->GetStateFnc();

        pSh->CallState( pFunc, rState );
#ifdef DBG_UTIL
        // To examine the conformity of IDL (SlotMap) and current Items
        if ( DbgIsAssertWarning() && rState.Count() )
        {
            SfxInterface *pIF = pSh->GetInterface();
            SfxItemIter aIter( rState );
            for ( const SfxPoolItem *pItem = aIter.FirstItem();
                  pItem;
                  pItem = aIter.NextItem() )
            {
                if ( !IsInvalidItem(pItem) && !pItem->ISA(SfxVoidItem) )
                {
                    sal_uInt16 nSlotId = rState.GetPool()->GetSlotId(pItem->Which());
                    if ( !pItem->IsA(pIF->GetSlot(nSlotId)->GetType()->Type()) )
                    {
                        rtl::OStringBuffer aMsg(RTL_CONSTASCII_STRINGPARAM(
                            "item-type unequal to IDL (=> no BASIC)"));
                        aMsg.append(RTL_CONSTASCII_STRINGPARAM("\nwith SID: "));
                        aMsg.append(static_cast<sal_Int32>(nSlotId));
                        aMsg.append(RTL_CONSTASCII_STRINGPARAM("\nin "));
                        aMsg.append(pIF->GetClassName());
                        DbgOut(aMsg.getStr(), DBG_OUT_ERROR, __FILE__, __LINE__);
                    }
                }
            }
        }
#endif

        DBG_PROFSTOP(SfxDispatcherFillState);
        return sal_True;
    }

    DBG_PROFSTOP(SfxDispatcherFillState);
    return sal_False;
}

SfxPopupMenuManager* SfxDispatcher::Popup( sal_uInt16 nConfigId,Window *pWin, const Point *pPos )
{
    SfxDispatcher &rDisp = *SFX_APP()->GetDispatcher_Impl();
    sal_uInt16 nShLevel = 0;
    SfxShell *pSh;
    nShLevel=0;

    if ( rDisp.pImp->bQuiet )
    {
        nConfigId = 0;
        nShLevel = rDisp.pImp->aStack.Count();
    }

    Window *pWindow = pWin ? pWin : rDisp.pImp->pFrame->GetFrame().GetWorkWindow_Impl()->GetWindow();
    for ( pSh = rDisp.GetShell(nShLevel); pSh; ++nShLevel, pSh = rDisp.GetShell(nShLevel) )
    {
        const ResId& rResId = pSh->GetInterface()->GetPopupMenuResId();
        if ( ( nConfigId == 0 && rResId.GetId() ) || ( nConfigId != 0 && rResId.GetId() == nConfigId ) )
        {
                return SfxPopupMenuManager::Popup( rResId, rDisp.GetFrame(), pPos ? *pPos : pWindow->GetPointerPosPixel(), pWindow );
        }
    }
    return 0;
}


//----------------------------------------------------------------------
void SfxDispatcher::ExecutePopup( sal_uInt16 nConfigId, Window *pWin, const Point *pPos )
{
    SfxDispatcher &rDisp = *SFX_APP()->GetDispatcher_Impl();
    sal_uInt16 nShLevel = 0;
    SfxShell *pSh;

    nShLevel=0;
    if ( rDisp.pImp->bQuiet )
    {
        nConfigId = 0;
        nShLevel = rDisp.pImp->aStack.Count();
    }

    Window *pWindow = pWin ? pWin : rDisp.pImp->pFrame->GetFrame().GetWorkWindow_Impl()->GetWindow();
    for ( pSh = rDisp.GetShell(nShLevel); pSh; ++nShLevel, pSh = rDisp.GetShell(nShLevel) )
    {
        const ResId& rResId = pSh->GetInterface()->GetPopupMenuResId();
        if ( ( nConfigId == 0 && rResId.GetId() ) || ( nConfigId != 0 && rResId.GetId() == nConfigId ) )
        {
            SfxPopupMenuManager::ExecutePopup( rResId, rDisp.GetFrame(), pPos ? *pPos : pWindow->GetPointerPosPixel(), pWindow );
            return;
        }
    }
}

//----------------------------------------------------------------------
void SfxDispatcher::ExecutePopup( const ResId &rId, Window *pWin, const Point *pPos )
{
    Window *pWindow = pWin ? pWin : pImp->pFrame->GetFrame().GetWorkWindow_Impl()->GetWindow();
    SfxPopupMenuManager::ExecutePopup( rId, GetFrame(), pPos ? *pPos : pWindow->GetPointerPosPixel(), pWindow );
}

//--------------------------------------------------------------------
void SfxDispatcher::Lock( sal_Bool bLock )

/*  [Description]

    With this method the SfxDispatcher can be locked and released. A locked
    SfxDispatcher does not perform <SfxRequest>s and does no longer provide
    status information. It behaves as if all the slots were disabled.
*/

{
    SfxBindings* pBindings = GetBindings();
    if ( !bLock && pImp->bLocked && pImp->bInvalidateOnUnlock )
    {
        if ( pBindings )
            pBindings->InvalidateAll(sal_True);
        pImp->bInvalidateOnUnlock = sal_False;
    }
    else if ( pBindings )
        pBindings->InvalidateAll(sal_False);
    pImp->bLocked = bLock;
    if ( !bLock )
    {
        sal_uInt16 nCount = pImp->aReqArr.Count();
        for ( sal_uInt16 i=0; i<nCount; i++ )
            pImp->xPoster->Post( pImp->aReqArr[i] );
        pImp->aReqArr.Remove( 0, nCount );
    }
}

sal_uInt32 SfxDispatcher::GetObjectBarId( sal_uInt16 nPos ) const
{
    return pImp->aObjBars[nPos].nResId;
}

void SfxDispatcher::LockUI_Impl( sal_Bool bLock )
{
    sal_Bool bWasLocked = pImp->bUILocked;
    pImp->bUILocked = bLock;
    if ( !bLock && bWasLocked )
        Update_Impl( sal_True );
}

//-------------------------------------------------------------------------
void SfxDispatcher::HideUI( sal_Bool bHide )
{
    sal_Bool bWasHidden = pImp->bNoUI;
    pImp->bNoUI = bHide;
    if ( pImp->pFrame )
    {
        SfxViewFrame* pTop = pImp->pFrame->GetTopViewFrame();
        if ( pTop && pTop->GetBindings().GetDispatcher() == this )
        {
            SfxFrame& rFrame = pTop->GetFrame();
            if ( rFrame.IsMenuBarOn_Impl() )
            {
                com::sun::star::uno::Reference < com::sun::star::beans::XPropertySet > xPropSet( rFrame.GetFrameInterface(), com::sun::star::uno::UNO_QUERY );
                if ( xPropSet.is() )
                {
                    com::sun::star::uno::Reference< ::com::sun::star::frame::XLayoutManager > xLayoutManager;
                    com::sun::star::uno::Any aValue = xPropSet->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LayoutManager" )));
                    aValue >>= xLayoutManager;
                    if ( xLayoutManager.is() )
                        xLayoutManager->setVisible( !bHide );
                }
            }
        }
    }

    if ( bHide != bWasHidden )
        Update_Impl( sal_True );
}

void SfxDispatcher::SetReadOnly_Impl( sal_Bool bOn )
{
    pImp->bReadOnly = bOn;
}

sal_Bool SfxDispatcher::GetReadOnly_Impl() const
{
    return pImp->bReadOnly;
}

//-------------------------------------------------------------------------
void SfxDispatcher::SetQuietMode_Impl( sal_Bool bOn )

/*  [Description]

    With 'bOn' the Dispatcher is quasi dead and transfers everything to the
    Parent-Dispatcher.
*/

{
    pImp->bQuiet = bOn;
    SfxBindings* pBindings = GetBindings();
    if ( pBindings )
        pBindings->InvalidateAll(sal_True);
}

void SfxDispatcher::SetExecuteMode( sal_uInt16 nMode )
{
    pImp->nStandardMode = nMode;
}

SfxItemState SfxDispatcher::QueryState( sal_uInt16 nSlot, const SfxPoolItem* &rpState )
{
    SfxShell *pShell = 0;
    const SfxSlot *pSlot = 0;
    if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, sal_False, sal_False ) )
    {
        rpState = pShell->GetSlotState(nSlot);
        if ( !rpState )
            return SFX_ITEM_DISABLED;
        else
            return SFX_ITEM_AVAILABLE;
    }

    return SFX_ITEM_DISABLED;
}

SfxItemState SfxDispatcher::QueryState( sal_uInt16 nSID, ::com::sun::star::uno::Any& rAny )
{
    SfxShell *pShell = 0;
    const SfxSlot *pSlot = 0;
    if ( GetShellAndSlot_Impl( nSID, &pShell, &pSlot, sal_False, sal_False ) )
    {
        const SfxPoolItem* pItem( 0 );

        pItem = pShell->GetSlotState( nSID );
        if ( !pItem )
            return SFX_ITEM_DISABLED;
        else
        {
            ::com::sun::star::uno::Any aState;
            if ( !pItem->ISA(SfxVoidItem) )
            {
                sal_uInt16 nSubId( 0 );
                SfxItemPool& rPool = pShell->GetPool();
                sal_uInt16 nWhich = rPool.GetWhich( nSID );
                if ( rPool.GetMetric( nWhich ) == SFX_MAPUNIT_TWIP )
                    nSubId |= CONVERT_TWIPS;
                pItem->QueryValue( aState, (sal_uInt8)nSubId );
            }
            rAny = aState;

            return SFX_ITEM_AVAILABLE;
        }
    }

    return SFX_ITEM_DISABLED;
}

sal_Bool SfxDispatcher::IsReadOnlyShell_Impl( sal_uInt16 nShell ) const
{
    sal_uInt16 nShellCount = pImp->aStack.Count();
    if ( nShell < nShellCount )
    {
        SfxShell* pShell = pImp->aStack.Top( nShell );
        if( pShell->ISA( SfxModule ) || pShell->ISA( SfxApplication ) || pShell->ISA( SfxViewFrame ) )
            return sal_False;
        else
            return pImp->bReadOnly;
    }
    else if ( pImp->pParent )
        return pImp->pParent->IsReadOnlyShell_Impl( nShell - nShellCount );
    return sal_True;
}

// A dirty trick, to get hold of the methods of the private base class
// SfxShellStack_Impl
class StackAccess_Impl : public SfxShellStack_Implarr_
{};

void SfxDispatcher::RemoveShell_Impl( SfxShell& rShell )
{
    Flush();

    // The cast is because SfxShellStack_Impl member has non of its own
    StackAccess_Impl& rStack = *((StackAccess_Impl*) (&pImp->aStack));
    sal_uInt16 nCount = rStack.Count();
    for ( sal_uInt16 n=0; n<nCount; ++n )
    {
        if ( rStack[n] == &rShell )
        {
            rStack.Remove( n );
            rShell.SetDisableFlags( 0 );
            rShell.DoDeactivate_Impl(pImp->pFrame, sal_True);
            break;
        }
    }

    if ( !SFX_APP()->IsDowning() )
    {
        pImp->bUpdated = sal_False;
        pImp->pCachedServ1 = 0;
        pImp->pCachedServ2 = 0;
        InvalidateBindings_Impl(sal_True);
    }
}

sal_Bool SfxDispatcher::IsAllowed
(
    sal_uInt16 nSlot
) const
/*
    [Description]

    The method checks whether the access is allowed on this interface.
 */
{
    if ( !pImp->pDisableList )
    {
        return sal_True;
    }

    // BinSearch in the disable list
    std::vector<sal_uInt16>& rList = *pImp->pDisableList;
    sal_uInt16 nCount = rList.size();
    sal_uInt16 nLow = 0, nMid = 0, nHigh;
    sal_Bool bFound = sal_False;
    nHigh = nCount - 1;

    while ( !bFound && nLow <= nHigh )
    {
        nMid = (nLow + nHigh) >> 1;
        DBG_ASSERT( nMid < nCount, "bsearch is buggy" );

        int nDiff = (int) nSlot - (int) rList[nMid];
        if ( nDiff < 0)
        {
            if ( nMid == 0 )
                break;
            nHigh = nMid - 1;
        }
        else if ( nDiff > 0 )
        {
            nLow = nMid + 1;
            if ( nLow == 0 )
                break;
        }
        else
            bFound = sal_True;
    }

#ifdef _DEBUG
    // Slot found in the List?
    sal_uInt16 nPos = bFound ? nMid : nLow;

    DBG_ASSERT( nPos <= nCount, "" );
    DBG_ASSERT( nPos == nCount || nSlot <= rList[nPos], "" );
    DBG_ASSERT( nPos == 0 || nSlot > rList[nPos-1], "" );
    DBG_ASSERT( ( (nPos+1) >= nCount ) || nSlot < rList[nPos+1], "" );
#endif

    return !bFound;
}

void SfxDispatcher::InvalidateBindings_Impl( sal_Bool bModify )
{
    // App-Dispatcher?
    if ( IsAppDispatcher() )
    {
        for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst();
                pFrame;
                pFrame = SfxViewFrame::GetNext( *pFrame ) )
            pFrame->GetBindings().InvalidateAll(bModify);
    }
    else
    {
        SfxDispatcher *pDisp = GetBindings()->GetDispatcher_Impl();
        while ( pDisp )
        {
            if ( pDisp == this )
            {
                GetBindings()->InvalidateAll( bModify );
                break;
            }

            pDisp = pDisp->pImp->pParent;
        }
    }
}

sal_Bool SfxDispatcher::IsUpdated_Impl() const
{
    return pImp->bUpdated;
}

void SfxDispatcher::SetDisableFlags( sal_uInt32 nFlags )
{
    pImp->nDisableFlags = nFlags;
    for ( int i = int(pImp->aStack.Count()) - 1; i >= 0; --i )
        pImp->aStack.Top( (sal_uInt16) i )->SetDisableFlags( nFlags );
}

sal_uInt32 SfxDispatcher::GetDisableFlags() const
{
    return pImp->nDisableFlags;
}

SfxModule* SfxDispatcher::GetModule() const
{
    for ( sal_uInt16 nShell = 0;; ++nShell )
    {
        SfxShell *pSh = GetShell(nShell);
        if ( pSh == NULL )
            return 0;
        if ( pSh->ISA(SfxModule) )
            return (SfxModule*) pSh;
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
