diff options
Diffstat (limited to 'sfx2/source/control/bindings.cxx')
-rw-r--r-- | sfx2/source/control/bindings.cxx | 2433 |
1 files changed, 2433 insertions, 0 deletions
diff --git a/sfx2/source/control/bindings.cxx b/sfx2/source/control/bindings.cxx new file mode 100644 index 000000000000..40f6346de8ee --- /dev/null +++ b/sfx2/source/control/bindings.cxx @@ -0,0 +1,2433 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include <hash_map> +#include <svl/itempool.hxx> +#include <svl/itemiter.hxx> +#include <svl/eitem.hxx> +#include <svl/aeitem.hxx> +#include <svl/intitem.hxx> +#include <svl/stritem.hxx> +#include <svl/visitem.hxx> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/frame/XDispatchProviderInterceptor.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XStatusListener.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/frame/XDispatchProviderInterception.hpp> +#include <com/sun/star/frame/FeatureStateEvent.hpp> +#include <com/sun/star/frame/DispatchDescriptor.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <comphelper/processfactory.hxx> +#include <svtools/itemdel.hxx> + +#ifndef GCC +#endif + +// wg. nInReschedule +#include "appdata.hxx" +#include <sfx2/bindings.hxx> +#include <sfx2/msg.hxx> +#include "statcach.hxx" +#include <sfx2/ctrlitem.hxx> +#include <sfx2/app.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/request.hxx> +#include <sfx2/objface.hxx> +#include "sfxtypes.hxx" +#include "workwin.hxx" +#include <sfx2/macrconf.hxx> +#include <sfx2/unoctitm.hxx> +#include <sfx2/sfx.hrc> +#include <sfx2/sfxuno.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/msgpool.hxx> + +#include <comphelper/uieventslogger.hxx> +#include <com/sun/star/frame/XModuleManager.hpp> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; + +DBG_NAME(SfxBindingsMsgPos) +DBG_NAME(SfxBindingsUpdateServers) +DBG_NAME(SfxBindingsCreateSet) +DBG_NAME(SfxBindingsUpdateCtrl1) +DBG_NAME(SfxBindingsUpdateCtrl2) +DBG_NAME(SfxBindingsNextJob_Impl0) +DBG_NAME(SfxBindingsNextJob_Impl) +DBG_NAME(SfxBindingsUpdate_Impl) +DBG_NAME(SfxBindingsInvalidateAll) + +//==================================================================== + +static USHORT nTimeOut = 300; + +#define TIMEOUT_FIRST nTimeOut +#define TIMEOUT_UPDATING 20 +#define TIMEOUT_IDLE 2500 + +static sal_uInt32 nCache1 = 0; +static sal_uInt32 nCache2 = 0; + +typedef std::hash_map< USHORT, bool > InvalidateSlotMap; + +//==================================================================== + +DECL_PTRARRAY(SfxStateCacheArr_Impl, SfxStateCache*, 32, 16) + +//==================================================================== + +class SfxAsyncExec_Impl +{ + ::com::sun::star::util::URL aCommand; + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp; + Timer aTimer; + +public: + + SfxAsyncExec_Impl( const ::com::sun::star::util::URL& rCmd, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch >& rDisp ) + : aCommand( rCmd ) + , xDisp( rDisp ) + { + aTimer.SetTimeoutHdl( LINK(this, SfxAsyncExec_Impl, TimerHdl) ); + aTimer.SetTimeout( 0 ); + aTimer.Start(); + } + + DECL_LINK( TimerHdl, Timer*); +}; + +IMPL_LINK(SfxAsyncExec_Impl, TimerHdl, Timer*, pTimer) +{ + (void)pTimer; // unused + aTimer.Stop(); + + Sequence<beans::PropertyValue> aSeq; + xDisp->dispatch( aCommand, aSeq ); + + delete this; + return 0L; +} + +class SfxBindings_Impl +{ +public: + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchRecorder > xRecorder; + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv; + SfxUnoControllerArr_Impl* + pUnoCtrlArr; + SfxWorkWindow* pWorkWin; + SfxBindings* pSubBindings; + SfxBindings* pSuperBindings; + SfxStateCacheArr_Impl* pCaches; // je ein cache fuer jede gebundene + sal_uInt16 nCachedFunc1; // index der zuletzt gerufenen + sal_uInt16 nCachedFunc2; // index der vorletzt gerufenen + sal_uInt16 nMsgPos; // Message-Position, ab der zu aktualisieren ist + SfxPopupAction ePopupAction; // in DeleteFloatinWindow() abgefragt + sal_Bool bContextChanged; + sal_Bool bMsgDirty; // wurde ein MessageServer invalidiert? + sal_Bool bAllMsgDirty; // wurden die MessageServer invalidiert? + sal_Bool bAllDirty; // nach InvalidateAll + sal_Bool bCtrlReleased; // waehrend EnterRegistrations + AutoTimer aTimer; // fuer volatile Slots + sal_Bool bInUpdate; // fuer Assertions + sal_Bool bInNextJob; // fuer Assertions + sal_Bool bFirstRound; // Erste Runde im Update + sal_uInt16 nFirstShell; // Shell, die in erster Runde bevorzugt wird + sal_uInt16 nOwnRegLevel; // z"ahlt die echten Locks, ohne die der SuperBindings + InvalidateSlotMap m_aInvalidateSlots; // store slots which are invalidated while in update +}; + +//-------------------------------------------------------------------- + +struct SfxFoundCache_Impl +{ + sal_uInt16 nSlotId; // die Slot-Id + sal_uInt16 nWhichId; // falls verf"ugbar die Which-Id, sonst nSlotId + const SfxSlot* pSlot; // Pointer auf den <Master-Slot> + SfxStateCache* pCache; // Pointer auf den StatusCache, ggf. 0 + + SfxFoundCache_Impl(): + nSlotId(0), + nWhichId(0), + pSlot(0), + pCache(0) + {} + + SfxFoundCache_Impl(SfxFoundCache_Impl&r): + nSlotId(r.nSlotId), + nWhichId(r.nWhichId), + pSlot(r.pSlot), + pCache(r.pCache) + {} + + SfxFoundCache_Impl(sal_uInt16 nS, sal_uInt16 nW, const SfxSlot *pS, SfxStateCache *pC ): + nSlotId(nS), + nWhichId(nW), + pSlot(pS), + pCache(pC) + {} + + int operator<( const SfxFoundCache_Impl &r ) const + { return nWhichId < r.nWhichId; } + + int operator==( const SfxFoundCache_Impl &r ) const + { return nWhichId== r.nWhichId; } +}; + +//-------------------------------------------------------------------------- + +SV_DECL_PTRARR_SORT_DEL(SfxFoundCacheArr_Impl, SfxFoundCache_Impl*, 16, 16 ) +SV_IMPL_OP_PTRARR_SORT(SfxFoundCacheArr_Impl, SfxFoundCache_Impl*); + +//========================================================================== + +SfxBindings::SfxBindings() +: pImp(new SfxBindings_Impl), + pDispatcher(0), + nRegLevel(1) // geht erst auf 0, wenn Dispatcher gesetzt +{ + pImp->nMsgPos = 0; + pImp->bAllMsgDirty = sal_True; + pImp->bContextChanged = sal_False; + pImp->bMsgDirty = sal_True; + pImp->bAllDirty = sal_True; + pImp->ePopupAction = SFX_POPUP_DELETE; + pImp->nCachedFunc1 = 0; + pImp->nCachedFunc2 = 0; + pImp->bCtrlReleased = sal_False; + pImp->bFirstRound = sal_False; + pImp->bInNextJob = sal_False; + pImp->bInUpdate = sal_False; + pImp->pSubBindings = NULL; + pImp->pSuperBindings = NULL; + pImp->pWorkWin = NULL; + pImp->pUnoCtrlArr = NULL; + pImp->nOwnRegLevel = nRegLevel; + + // all caches are valid (no pending invalidate-job) + // create the list of caches + pImp->pCaches = new SfxStateCacheArr_Impl; + pImp->aTimer.SetTimeoutHdl( LINK(this, SfxBindings, NextJob_Impl) ); +} + +//==================================================================== + +SfxBindings::~SfxBindings() + +/* [Beschreibung] + + Destruktor der Klasse SfxBindings. Die eine, f"ur jede <SfxApplication> + existierende Instanz wird von der <SfxApplication> nach Ausf"urhung + von <SfxApplication::Exit()> automatisch zerst"ort. + + Noch existierende <SfxControllerItem> Instanzen, die bei dieser + SfxBindings Instanz angemeldet sind, werden im Destruktor + automatisch zerst"ort. Dies sind i.d.R. Floating-Toolboxen, Value-Sets + etc. Arrays von SfxControllerItems d"urfen zu diesem Zeitpunkt nicht + mehr exisitieren. +*/ + +{ + // Die SubBindings sollen ja nicht gelocked werden ! + pImp->pSubBindings = NULL; + + ENTERREGISTRATIONS(); + + pImp->aTimer.Stop(); + DeleteControllers_Impl(); + + // Caches selbst l"oschen + sal_uInt16 nCount = pImp->pCaches->Count(); + for ( sal_uInt16 nCache = 0; nCache < nCount; ++nCache ) + delete pImp->pCaches->GetObject(nCache); + + DELETEZ( pImp->pWorkWin ); + + delete pImp->pCaches; + delete pImp; +} + +//-------------------------------------------------------------------- + +void SfxBindings::DeleteControllers_Impl() +{ + // in der ersten Runde den SfxPopupWindows l"oschen + sal_uInt16 nCount = pImp->pCaches->Count(); + sal_uInt16 nCache; + for ( nCache = 0; nCache < nCount; ++nCache ) + { + // merken wo man ist + SfxStateCache *pCache = pImp->pCaches->GetObject(nCache); + sal_uInt16 nSlotId = pCache->GetId(); + + // SfxPopupWindow l"oschen lassen + pCache->DeleteFloatingWindows(); + + // da der Cache verkleinert worden sein kann, wiederaufsetzen + sal_uInt16 nNewCount = pImp->pCaches->Count(); + if ( nNewCount < nCount ) + { + nCache = GetSlotPos(nSlotId); + if ( nCache >= nNewCount || + nSlotId != pImp->pCaches->GetObject(nCache)->GetId() ) + --nCache; + nCount = nNewCount; + } + } + + // alle Caches l"oschen + for ( nCache = pImp->pCaches->Count(); nCache > 0; --nCache ) + { + // Cache via ::com::sun::star::sdbcx::Index besorgen + SfxStateCache *pCache = pImp->pCaches->GetObject(nCache-1); + + // alle Controller in dem Cache unbinden + SfxControllerItem *pNext; + for ( SfxControllerItem *pCtrl = pCache->GetItemLink(); + pCtrl; pCtrl = pNext ) + { + pNext = pCtrl->GetItemLink(); + pCtrl->UnBind(); + } + + if ( pCache->GetInternalController() ) + pCache->GetInternalController()->UnBind(); + + // Cache l"oschen + if( nCache-1 < pImp->pCaches->Count() ) + delete (*pImp->pCaches)[nCache-1]; + pImp->pCaches->Remove(nCache-1, 1); + } + + if( pImp->pUnoCtrlArr ) + { + sal_uInt16 nCtrlCount = pImp->pUnoCtrlArr->Count(); + for ( sal_uInt16 n=nCtrlCount; n>0; n-- ) + { + SfxUnoControllerItem *pCtrl = (*pImp->pUnoCtrlArr)[n-1]; + pCtrl->ReleaseBindings(); + } + + DBG_ASSERT( !pImp->pUnoCtrlArr->Count(), "UnoControllerItems nicht entfernt!" ); + DELETEZ( pImp->pUnoCtrlArr ); + } +} + +//-------------------------------------------------------------------- + +SfxPopupAction SfxBindings::GetPopupAction_Impl() const +{ + return pImp->ePopupAction; +} + + +//-------------------------------------------------------------------- + +void SfxBindings::HidePopups( bool bHide ) +{ + // SfxPopupWindows hiden + HidePopupCtrls_Impl( bHide ); + SfxBindings *pSub = pImp->pSubBindings; + while ( pSub ) + { + pImp->pSubBindings->HidePopupCtrls_Impl( bHide ); + pSub = pSub->pImp->pSubBindings; + } + + // SfxChildWindows hiden + DBG_ASSERT( pDispatcher, "HidePopups not allowed without dispatcher" ); + if ( pImp->pWorkWin ) + pImp->pWorkWin->HidePopups_Impl( bHide, sal_True ); +} + +void SfxBindings::HidePopupCtrls_Impl( FASTBOOL bHide ) +{ + if ( bHide ) + { + // SfxPopupWindows hiden + pImp->ePopupAction = SFX_POPUP_HIDE; + } + else + { + // SfxPopupWindows showen + pImp->ePopupAction = SFX_POPUP_SHOW; + } + + for ( sal_uInt16 nCache = 0; nCache < pImp->pCaches->Count(); ++nCache ) + pImp->pCaches->GetObject(nCache)->DeleteFloatingWindows(); + pImp->ePopupAction = SFX_POPUP_DELETE; +} + +//-------------------------------------------------------------------- + +void SfxBindings::Update_Impl +( + SfxStateCache* pCache // der upzudatende SfxStatusCache +) +{ + if( pCache->GetDispatch().is() && pCache->GetItemLink() ) + { + pCache->SetCachedState(TRUE); + if ( !pCache->GetInternalController() ) + return; + } + + if ( !pDispatcher ) + return; + DBG_PROFSTART(SfxBindingsUpdate_Impl); + + // alle mit derselben Statusmethode zusammensammeln, die dirty sind + SfxDispatcher &rDispat = *pDispatcher; + const SfxSlot *pRealSlot = 0; + const SfxSlotServer* pMsgServer = 0; + SfxFoundCacheArr_Impl aFound; + SfxItemSet *pSet = CreateSet_Impl( pCache, pRealSlot, &pMsgServer, aFound ); + sal_Bool bUpdated = sal_False; + if ( pSet ) + { + // Status erfragen + if ( rDispat._FillState( *pMsgServer, *pSet, pRealSlot ) ) + { + // Status posten + const SfxInterface *pInterface = + rDispat.GetShell(pMsgServer->GetShellLevel())->GetInterface(); + for ( sal_uInt16 nPos = 0; nPos < aFound.Count(); ++nPos ) + { + const SfxFoundCache_Impl *pFound = aFound[nPos]; + sal_uInt16 nWhich = pFound->nWhichId; + const SfxPoolItem *pItem = 0; + SfxItemState eState = pSet->GetItemState(nWhich, sal_True, &pItem); + if ( eState == SFX_ITEM_DEFAULT && SfxItemPool::IsWhich(nWhich) ) + pItem = &pSet->Get(nWhich); + UpdateControllers_Impl( pInterface, aFound[nPos], pItem, eState ); + } + bUpdated = sal_True; + } + + delete pSet; + } + + if ( !bUpdated && pCache ) + { + // Wenn pCache == NULL und kein SlotServer ( z.B. weil Dispatcher gelockt! ), + // darf nat"urlich kein Update versucht werden + SfxFoundCache_Impl aFoundCache( + pCache->GetId(), 0, + pRealSlot, pCache ); + UpdateControllers_Impl( 0, &aFoundCache, 0, SFX_ITEM_DISABLED); + } + + DBG_PROFSTOP(SfxBindingsUpdate_Impl); +} + +//-------------------------------------------------------------------- + +void SfxBindings::InvalidateSlotsInMap_Impl() +{ + InvalidateSlotMap::const_iterator pIter = pImp->m_aInvalidateSlots.begin(); + while ( pIter != pImp->m_aInvalidateSlots.end() ) + { + Invalidate( pIter->first ); + ++pIter; + } + pImp->m_aInvalidateSlots.clear(); +} + +//-------------------------------------------------------------------- + +void SfxBindings::AddSlotToInvalidateSlotsMap_Impl( USHORT nId ) +{ + pImp->m_aInvalidateSlots[nId] = sal_True; +} + +//-------------------------------------------------------------------- + +void SfxBindings::Update +( + sal_uInt16 nId // die gebundene und upzudatende Slot-Id +) +{ + DBG_MEMTEST(); + DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); + +//!!TLX: Fuehrte zu Vorlagenkatalogstillstand +// if ( nRegLevel ) +// return; + + if ( pDispatcher ) + pDispatcher->Flush(); + + if ( pImp->pSubBindings ) + pImp->pSubBindings->Update( nId ); + + SfxStateCache* pCache = GetStateCache( nId ); + if ( pCache ) + { + pImp->bInUpdate = sal_True; + if ( pImp->bMsgDirty ) + { + UpdateSlotServer_Impl(); + pCache = GetStateCache( nId ); + } + + if (pCache) + { + BOOL bInternalUpdate = TRUE; + if( pCache->GetDispatch().is() && pCache->GetItemLink() ) + { + pCache->SetCachedState(TRUE); + bInternalUpdate = ( pCache->GetInternalController() != 0 ); + } + + if ( bInternalUpdate ) + { + // Status erfragen + const SfxSlotServer* pMsgServer = pCache->GetSlotServer(*pDispatcher, pImp->xProv); + if ( !pCache->IsControllerDirty() && + ( !pMsgServer || + !pMsgServer->GetSlot()->IsMode(SFX_SLOT_VOLATILE) ) ) + { + pImp->bInUpdate = sal_False; + InvalidateSlotsInMap_Impl(); + return; + } + if (!pMsgServer) + { + pCache->SetState(SFX_ITEM_DISABLED, 0); + pImp->bInUpdate = sal_False; + InvalidateSlotsInMap_Impl(); + return; + } + + Update_Impl(pCache); + } + + pImp->bAllDirty = sal_False; + } + + pImp->bInUpdate = sal_False; + InvalidateSlotsInMap_Impl(); + } +} + +//-------------------------------------------------------------------- + +void SfxBindings::Update() +{ + DBG_MEMTEST(); + DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); + + if ( pImp->pSubBindings ) + pImp->pSubBindings->Update(); + + if ( pDispatcher ) + { + if ( nRegLevel ) + return; + + pImp->bInUpdate = sal_True; + pDispatcher->Flush(); + pDispatcher->Update_Impl(); + while ( !NextJob_Impl(0) ) + ; // loop + pImp->bInUpdate = sal_False; + InvalidateSlotsInMap_Impl(); + } +} + +//-------------------------------------------------------------------- + +void SfxBindings::SetState +( + const SfxItemSet& rSet // zu setzende Status-Werte +) +{ + // wenn gelockt, dann nur invalidieren + if ( nRegLevel ) + { + SfxItemIter aIter(rSet); + for ( const SfxPoolItem *pItem = aIter.FirstItem(); + pItem; + pItem = aIter.NextItem() ) + Invalidate( pItem->Which() ); + } + else + { + // Status d"urfen nur angenommen werden, wenn alle Slot-Pointer gesetzt sind + if ( pImp->bMsgDirty ) + UpdateSlotServer_Impl(); + + // "uber das ItemSet iterieren, falls Slot gebunden, updaten + //! Bug: WhichIter verwenden und ggf. VoidItems hochschicken + SfxItemIter aIter(rSet); + for ( const SfxPoolItem *pItem = aIter.FirstItem(); + pItem; + pItem = aIter.NextItem() ) + { + SfxStateCache* pCache = + GetStateCache( rSet.GetPool()->GetSlotId(pItem->Which()) ); + if ( pCache ) + { + // Status updaten + if ( !pCache->IsControllerDirty() ) + pCache->Invalidate(sal_False); + pCache->SetState( SFX_ITEM_AVAILABLE, pItem ); + + //! nicht implementiert: Updates von EnumSlots via MasterSlots + } + } + } +} + +//-------------------------------------------------------------------- + +void SfxBindings::SetState +( + const SfxPoolItem& rItem // zu setzender Status-Wert +) +{ + if ( nRegLevel ) + { + Invalidate( rItem.Which() ); + } + else + { + // Status d"urfen nur angenommen werden, wenn alle Slot-Pointer gesetzt sind + if ( pImp->bMsgDirty ) + UpdateSlotServer_Impl(); + + // falls der Slot gebunden ist, updaten + DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ), + "cannot set items with which-id" ); + SfxStateCache* pCache = GetStateCache( rItem.Which() ); + if ( pCache ) + { + // Status updaten + if ( !pCache->IsControllerDirty() ) + pCache->Invalidate(sal_False); + pCache->SetState( SFX_ITEM_AVAILABLE, &rItem ); + + //! nicht implementiert: Updates von EnumSlots via MasterSlots + } + } +} + + +//-------------------------------------------------------------------- + +SfxStateCache* SfxBindings::GetAnyStateCache_Impl( sal_uInt16 nId ) +{ + SfxStateCache* pCache = GetStateCache( nId ); + if ( !pCache && pImp->pSubBindings ) + return pImp->pSubBindings->GetAnyStateCache_Impl( nId ); + return pCache; +} + +SfxStateCache* SfxBindings::GetStateCache +( + sal_uInt16 nId /* Slot-Id, deren SfxStatusCache gefunden + werden soll */, + sal_uInt16* pPos /* 0 bzw. Position, ab der die Bindings + bin"ar durchsucht werden sollen. Liefert + die Position zur"uck, an der nId gefunden + wurde, bzw. an der es einfef"ugt werden + w"urde. */ +) +{ + DBG_MEMTEST(); + DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); + // is the specified function bound? + const sal_uInt16 nStart = ( pPos ? *pPos : 0 ); + const sal_uInt16 nPos = GetSlotPos( nId, nStart ); + + if ( nPos < pImp->pCaches->Count() && + (*pImp->pCaches)[nPos]->GetId() == nId ) + { + if ( pPos ) + *pPos = nPos; + return (*pImp->pCaches)[nPos]; + } + return 0; +} + +//-------------------------------------------------------------------- + +void SfxBindings::InvalidateAll +( + sal_Bool bWithMsg /* sal_True + Slot-Server als ung"ultig markieren + + sal_False + Slot-Server bleiben g"ultig */ +) +{ + DBG_PROFSTART(SfxBindingsInvalidateAll); + DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" ); + + DBG_MEMTEST(); + + if ( pImp->pSubBindings ) + pImp->pSubBindings->InvalidateAll( bWithMsg ); + + // ist schon alles dirty gesetzt oder downing => nicht zu tun + if ( !pDispatcher || + ( pImp->bAllDirty && ( !bWithMsg || pImp->bAllMsgDirty ) ) || + SFX_APP()->IsDowning() ) + { + DBG_PROFSTOP(SfxBindingsInvalidateAll); + return; + } + + pImp->bAllMsgDirty = pImp->bAllMsgDirty || bWithMsg; + pImp->bMsgDirty = pImp->bMsgDirty || pImp->bAllMsgDirty || bWithMsg; + pImp->bAllDirty = sal_True; + + for ( sal_uInt16 n = 0; n < pImp->pCaches->Count(); ++n ) + pImp->pCaches->GetObject(n)->Invalidate(bWithMsg); +/* + ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame + ( pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY ); + + if ( bWithMsg && xFrame.is() ) + xFrame->contextChanged(); +*/ + pImp->nMsgPos = 0; + if ( !nRegLevel ) + { + pImp->aTimer.Stop(); + pImp->aTimer.SetTimeout(TIMEOUT_FIRST); + pImp->aTimer.Start(); +// pImp->bFirstRound = sal_True; +// pImp->nFirstShell = 0; + } + + DBG_PROFSTOP(SfxBindingsInvalidateAll); +} + +//-------------------------------------------------------------------- + +void SfxBindings::Invalidate +( + const sal_uInt16* pIds /* numerisch sortiertes 0-terminiertes Array + von Slot-Ids (einzel, nicht als Paare!) */ +) +{ + DBG_PROFSTART(SfxBindingsInvalidateAll); +// DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" ); + + DBG_MEMTEST(); + + if ( pImp->bInUpdate ) + { + sal_Int32 i = 0; + while ( pIds[i] != 0 ) + AddSlotToInvalidateSlotsMap_Impl( pIds[i++] ); + + if ( pImp->pSubBindings ) + pImp->pSubBindings->Invalidate( pIds ); + return; + } + + if ( pImp->pSubBindings ) + pImp->pSubBindings->Invalidate( pIds ); + + // ist schon alles dirty gesetzt oder downing => nicht zu tun + if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() ) + return; + + // in immer kleiner werdenden Berichen bin"ar suchen + for ( sal_uInt16 n = GetSlotPos(*pIds); + *pIds && n < pImp->pCaches->Count(); + n = GetSlotPos(*pIds, n) ) + { + // falls SID "uberhaupt gebunden ist, den Cache invalidieren + SfxStateCache *pCache = pImp->pCaches->GetObject(n); + if ( pCache->GetId() == *pIds ) + pCache->Invalidate(sal_False); + + // n"achste SID + if ( !*++pIds ) + break; + DBG_ASSERT( *pIds > *(pIds-1), "pIds unsorted" ); + } + + // falls nicht gelockt, Update-Timer starten + pImp->nMsgPos = 0; + if ( !nRegLevel ) + { + pImp->aTimer.Stop(); + pImp->aTimer.SetTimeout(TIMEOUT_FIRST); + pImp->aTimer.Start(); +// pImp->bFirstRound = sal_True; +// pImp->nFirstShell = 0; + } + + DBG_PROFSTOP(SfxBindingsInvalidateAll); +} + +//-------------------------------------------------------------------- + +void SfxBindings::InvalidateShell +( + const SfxShell& rSh /* Die <SfxShell>, deren Slot-Ids + invalidiert werden sollen. */, + + sal_Bool bDeep /* sal_True + auch die, von der SfxShell + ererbten Slot-Ids werden invalidert + + sal_False + die ererbten und nicht "uberladenen + Slot-Ids werden invalidiert */ + //! MI: z. Zt. immer bDeep +) +{ + DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" ); + + if ( pImp->pSubBindings ) + pImp->pSubBindings->InvalidateShell( rSh, bDeep ); + + if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() ) + return; + + DBG_PROFSTART(SfxBindingsInvalidateAll); + DBG_MEMTEST(); + + // Jetzt schon flushen, wird in GetShellLevel(rSh) sowieso gemacht; wichtig, + // damit pImp->bAll(Msg)Dirty korrekt gesetzt ist + pDispatcher->Flush(); + + if ( !pDispatcher || + ( pImp->bAllDirty && pImp->bAllMsgDirty ) || + SFX_APP()->IsDowning() ) + { + // Wenn sowieso demn"achst alle Server geholt werden + return; + } + + // Level finden + sal_uInt16 nLevel = pDispatcher->GetShellLevel(rSh); + if ( nLevel != USHRT_MAX ) + { + for ( sal_uInt16 n = 0; n < pImp->pCaches->Count(); ++n ) + { + SfxStateCache *pCache = pImp->pCaches->GetObject(n); + const SfxSlotServer *pMsgServer = + pCache->GetSlotServer(*pDispatcher, pImp->xProv); + if ( pMsgServer && pMsgServer->GetShellLevel() == nLevel ) + pCache->Invalidate(sal_False); + } + pImp->nMsgPos = 0; + if ( !nRegLevel ) + { + pImp->aTimer.Stop(); + pImp->aTimer.SetTimeout(TIMEOUT_FIRST); + pImp->aTimer.Start(); + pImp->bFirstRound = sal_True; + pImp->nFirstShell = nLevel; + } + } + + DBG_PROFSTOP(SfxBindingsInvalidateAll); +} + +//-------------------------------------------------------------------- + +void SfxBindings::Invalidate +( + sal_uInt16 nId // zu invalidierende Slot-Id +) +{ + DBG_MEMTEST(); +// DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" ); + + if ( pImp->bInUpdate ) + { + AddSlotToInvalidateSlotsMap_Impl( nId ); + if ( pImp->pSubBindings ) + pImp->pSubBindings->Invalidate( nId ); + return; + } + + if ( pImp->pSubBindings ) + pImp->pSubBindings->Invalidate( nId ); + + if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() ) + return; + + SfxStateCache* pCache = GetStateCache(nId); + if ( pCache ) + { + pCache->Invalidate(sal_False); + pImp->nMsgPos = Min(GetSlotPos(nId), pImp->nMsgPos); + if ( !nRegLevel ) + { + pImp->aTimer.Stop(); + pImp->aTimer.SetTimeout(TIMEOUT_FIRST); + pImp->aTimer.Start(); + } + } +} + +//-------------------------------------------------------------------- + +void SfxBindings::Invalidate +( + sal_uInt16 nId, // zu invalidierende Slot-Id + sal_Bool bWithItem, // StateCache clearen ? + sal_Bool bWithMsg // SlotServer neu holen ? +) +{ + DBG_MEMTEST(); + DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" ); + + if ( pImp->pSubBindings ) + pImp->pSubBindings->Invalidate( nId, bWithItem, bWithMsg ); + + if ( SFX_APP()->IsDowning() ) + return; + + SfxStateCache* pCache = GetStateCache(nId); + if ( pCache ) + { + if ( bWithItem ) + pCache->ClearCache(); + pCache->Invalidate(bWithMsg); + + if ( !pDispatcher || pImp->bAllDirty ) + return; + + pImp->nMsgPos = Min(GetSlotPos(nId), pImp->nMsgPos); + if ( !nRegLevel ) + { + pImp->aTimer.Stop(); + pImp->aTimer.SetTimeout(TIMEOUT_FIRST); + pImp->aTimer.Start(); + } + } +} + +//-------------------------------------------------------------------- + +sal_Bool SfxBindings::IsBound( sal_uInt16 nSlotId, sal_uInt16 nStartSearchAt ) +{ + DBG_MEMTEST(); + DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); + return GetStateCache(nSlotId, &nStartSearchAt ) != 0; +} + +//-------------------------------------------------------------------- + +sal_uInt16 SfxBindings::GetSlotPos( sal_uInt16 nId, sal_uInt16 nStartSearchAt ) +{ + DBG_MEMTEST(); + DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); + DBG_PROFSTART(SfxBindingsMsgPos); + + // answer immediately if a function-seek comes repeated + if ( pImp->nCachedFunc1 < pImp->pCaches->Count() && + (*pImp->pCaches)[pImp->nCachedFunc1]->GetId() == nId ) + { + ++nCache1; + DBG_PROFSTOP(SfxBindingsMsgPos); + return pImp->nCachedFunc1; + } + if ( pImp->nCachedFunc2 < pImp->pCaches->Count() && + (*pImp->pCaches)[pImp->nCachedFunc2]->GetId() == nId ) + { + ++nCache2; + + // swap the caches + sal_uInt16 nTemp = pImp->nCachedFunc1; + pImp->nCachedFunc1 = pImp->nCachedFunc2; + pImp->nCachedFunc2 = nTemp; + DBG_PROFSTOP(SfxBindingsMsgPos); + return pImp->nCachedFunc1; + } + + // binary search, if not found, seek to target-position + if ( pImp->pCaches->Count() <= nStartSearchAt ) + { + DBG_PROFSTOP(SfxBindingsMsgPos); + return 0; + } + if ( pImp->pCaches->Count() == (nStartSearchAt+1) ) + { + DBG_PROFSTOP(SfxBindingsMsgPos); + return (*pImp->pCaches)[nStartSearchAt]->GetId() >= nId ? 0 : 1; + } + sal_uInt16 nLow = nStartSearchAt; + sal_uInt16 nMid = 0; + sal_uInt16 nHigh = 0; + sal_Bool bFound = sal_False; + nHigh = pImp->pCaches->Count() - 1; + while ( !bFound && nLow <= nHigh ) + { + nMid = (nLow + nHigh) >> 1; + DBG_ASSERT( nMid < pImp->pCaches->Count(), "bsearch ist buggy" ); + int nDiff = (int) nId - (int) ( ((*pImp->pCaches)[nMid])->GetId() ); + 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; + } + sal_uInt16 nPos = bFound ? nMid : nLow; + DBG_ASSERT( nPos <= pImp->pCaches->Count(), "" ); + DBG_ASSERT( nPos == pImp->pCaches->Count() || + nId <= (*pImp->pCaches)[nPos]->GetId(), "" ); + DBG_ASSERT( nPos == nStartSearchAt || + nId > (*pImp->pCaches)[nPos-1]->GetId(), "" ); + DBG_ASSERT( ( (nPos+1) >= pImp->pCaches->Count() ) || + nId < (*pImp->pCaches)[nPos+1]->GetId(), "" ); + pImp->nCachedFunc2 = pImp->nCachedFunc1; + pImp->nCachedFunc1 = nPos; + DBG_PROFSTOP(SfxBindingsMsgPos); + return nPos; +} +//-------------------------------------------------------------------- +void SfxBindings::RegisterInternal_Impl( SfxControllerItem& rItem ) +{ + Register_Impl( rItem, TRUE ); + +} + +void SfxBindings::Register( SfxControllerItem& rItem ) +{ + Register_Impl( rItem, FALSE ); +} + +void SfxBindings::Register_Impl( SfxControllerItem& rItem, BOOL bInternal ) +{ + DBG_MEMTEST(); + DBG_ASSERT( nRegLevel > 0, "registration without EnterRegistrations" ); + DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Register while status-updating" ); + + // insert new cache if it does not already exist + sal_uInt16 nId = rItem.GetId(); + sal_uInt16 nPos = GetSlotPos(nId); + if ( nPos >= pImp->pCaches->Count() || + (*pImp->pCaches)[nPos]->GetId() != nId ) + { + SfxStateCache* pCache = new SfxStateCache(nId); + pImp->pCaches->Insert( nPos, pCache ); + DBG_ASSERT( nPos == 0 || + (*pImp->pCaches)[nPos]->GetId() > + (*pImp->pCaches)[nPos-1]->GetId(), "" ); + DBG_ASSERT( (nPos == pImp->pCaches->Count()-1) || + (*pImp->pCaches)[nPos]->GetId() < + (*pImp->pCaches)[nPos+1]->GetId(), "" ); + pImp->bMsgDirty = sal_True; + } + + // enqueue the new binding + if ( bInternal ) + { + (*pImp->pCaches)[nPos]->SetInternalController( &rItem ); + } + else + { + SfxControllerItem *pOldItem = (*pImp->pCaches)[nPos]->ChangeItemLink(&rItem); + rItem.ChangeItemLink(pOldItem); + } +} + +//-------------------------------------------------------------------- + +void SfxBindings::Release( SfxControllerItem& rItem ) +{ + DBG_MEMTEST(); + DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); + //! DBG_ASSERT( nRegLevel > 0, "release without EnterRegistrations" ); + DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Release while status-updating" ); + ENTERREGISTRATIONS(); + + // find the bound function + sal_uInt16 nId = rItem.GetId(); + sal_uInt16 nPos = GetSlotPos(nId); + SfxStateCache* pCache = (*pImp->pCaches)[nPos]; + if ( pCache->GetId() == nId ) + { + if ( pCache->GetInternalController() == &rItem ) + { + pCache->ReleaseInternalController(); + } + else + { + // is this the first binding in the list? + SfxControllerItem* pItem = pCache->GetItemLink(); + if ( pItem == &rItem ) + pCache->ChangeItemLink( rItem.GetItemLink() ); + else + { + // search the binding in the list + while ( pItem && pItem->GetItemLink() != &rItem ) + pItem = pItem->GetItemLink(); + + // unlink it if it was found + if ( pItem ) + pItem->ChangeItemLink( rItem.GetItemLink() ); + } + } + + // was this the last controller? + if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() ) + { +#ifdef slow + // remove the BoundFunc + delete (*pImp->pCaches)[nPos]; + pImp->pCaches->Remove(nPos, 1); +#endif + if ( SfxMacroConfig::IsMacroSlot( nId ) ) + { + delete (*pImp->pCaches)[nPos]; + pImp->pCaches->Remove(nPos, 1); + } + else + pImp->bCtrlReleased = sal_True; + } + } + + LEAVEREGISTRATIONS(); +} + +//-------------------------------------------------------------------- +const SfxPoolItem* SfxBindings::ExecuteSynchron( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, + const SfxPoolItem **ppInternalArgs ) +{ + DBG_MEMTEST(); + DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); + + if( !nId || !pDispatcher ) + return NULL; + + return Execute_Impl( nId, ppItems, nModi, SFX_CALLMODE_SYNCHRON, ppInternalArgs ); +} + +sal_Bool SfxBindings::Execute( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode, + const SfxPoolItem **ppInternalArgs ) +{ + DBG_MEMTEST(); + DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); + + if( !nId || !pDispatcher ) + return sal_False; + + const SfxPoolItem* pRet = Execute_Impl( nId, ppItems, nModi, nCallMode, ppInternalArgs ); + return ( pRet != 0 ); +} + +void SfxBindings::ExecuteGlobal_Impl( USHORT nId ) +{ + if( nId && pDispatcher ) + Execute_Impl( nId, NULL, 0, SFX_CALLMODE_ASYNCHRON, NULL, TRUE ); +} + +const SfxPoolItem* SfxBindings::Execute_Impl( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode, + const SfxPoolItem **ppInternalArgs, BOOL bGlobalOnly ) +{ + SfxStateCache *pCache = GetStateCache( nId ); + if ( !pCache ) + { + SfxBindings *pBind = pImp->pSubBindings; + while ( pBind ) + { + if ( pBind->GetStateCache( nId ) ) + return pBind->Execute_Impl( nId, ppItems, nModi, nCallMode, ppInternalArgs, bGlobalOnly ); + pBind = pBind->pImp->pSubBindings; + }; + } + + SfxDispatcher &rDispatcher = *pDispatcher; + rDispatcher.Flush(); + rDispatcher.GetFrame(); // -Wall is this required??? + + // get SlotServer (Slot+ShellLevel) and Shell from cache + sal_Bool bDeleteCache = sal_False; + if ( !pCache ) + { + // Execution of non cached slots (Accelerators don't use Controllers) + // slot is uncached, use SlotCache to handle external dispatch providers + pCache = new SfxStateCache( nId ); + pCache->GetSlotServer( rDispatcher, pImp->xProv ); + bDeleteCache = sal_True; + } + + if ( pCache && pCache->GetDispatch().is() ) + { + DBG_ASSERT( !ppInternalArgs, "Internal args get lost when dispatched!" ); + + SfxItemPool &rPool = GetDispatcher()->GetFrame()->GetObjectShell()->GetPool(); + SfxRequest aReq( nId, nCallMode, rPool ); + aReq.SetModifier( nModi ); + if( ppItems ) + while( *ppItems ) + aReq.AppendItem( **ppItems++ ); + + // cache binds to an external dispatch provider + pCache->Dispatch( aReq.GetArgs(), nCallMode == SFX_CALLMODE_SYNCHRON ); + if ( bDeleteCache ) + DELETEZ( pCache ); + SfxPoolItem *pVoid = new SfxVoidItem( nId ); + DeleteItemOnIdle( pVoid ); + return pVoid; + } + + // slot is handled internally by SfxDispatcher + if ( pImp->bMsgDirty ) + UpdateSlotServer_Impl(); + + SfxShell *pShell=0; + const SfxSlot *pSlot=0; + + // if slot was uncached, we should have created a cache in this method! + DBG_ASSERT( pCache, "This code needs a cache!"); + const SfxSlotServer* pServer = pCache ? pCache->GetSlotServer( rDispatcher, pImp->xProv ) : 0; + if ( !pServer ) + { + return NULL; + } + else + { + pShell = rDispatcher.GetShell( pServer->GetShellLevel() ); + pSlot = pServer->GetSlot(); + } + + if ( bGlobalOnly ) + if ( !pShell->ISA(SfxModule) && !pShell->ISA(SfxApplication) && !pShell->ISA(SfxViewFrame) ) + return NULL; + + SfxItemPool &rPool = pShell->GetPool(); + SfxRequest aReq( nId, nCallMode, rPool ); + aReq.SetModifier( nModi ); + if( ppItems ) + while( *ppItems ) + aReq.AppendItem( **ppItems++ ); + if ( ppInternalArgs ) + { + SfxAllItemSet aSet( rPool ); + for ( const SfxPoolItem **pArg = ppInternalArgs; *pArg; ++pArg ) + aSet.Put( **pArg ); + aReq.SetInternalArgs_Impl( aSet ); + } + + Execute_Impl( aReq, pSlot, pShell ); + + const SfxPoolItem* pRet = aReq.GetReturnValue(); + if ( !pRet ) + { + SfxPoolItem *pVoid = new SfxVoidItem( nId ); + DeleteItemOnIdle( pVoid ); + pRet = pVoid; + } + + if ( bDeleteCache ) + delete pCache; + + return pRet; +} + +void SfxBindings::Execute_Impl( SfxRequest& aReq, const SfxSlot* pSlot, SfxShell* pShell ) +{ + SfxItemPool &rPool = pShell->GetPool(); + + if ( SFX_KIND_ENUM == pSlot->GetKind() ) + { + // bei Enum-Slots muss der Master mit dem Wert des Enums executet werden + const SfxSlot *pRealSlot = pShell->GetInterface()->GetRealSlot(pSlot); + const sal_uInt16 nSlotId = pRealSlot->GetSlotId(); + aReq.SetSlot( nSlotId ); + aReq.AppendItem( SfxAllEnumItem( rPool.GetWhich(nSlotId), pSlot->GetValue() ) ); + pDispatcher->_Execute( *pShell, *pRealSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD ); + } + else if ( SFX_KIND_ATTR == pSlot->GetKind() ) + { + // bei Attr-Slots muss der Which-Wert gemapped werden + const sal_uInt16 nSlotId = pSlot->GetSlotId(); + aReq.SetSlot( nSlotId ); + if ( pSlot->IsMode(SFX_SLOT_TOGGLE) ) + { + // an togglebare-Attribs (Bools) wird der Wert angeheangt + sal_uInt16 nWhich = pSlot->GetWhich(rPool); + SfxItemSet aSet(rPool, nWhich, nWhich, 0); + SfxStateFunc aFunc = pSlot->GetStateFnc(); + pShell->CallState( aFunc, aSet ); + const SfxPoolItem *pOldItem; + SfxItemState eState = aSet.GetItemState(nWhich, sal_True, &pOldItem); + if ( eState == SFX_ITEM_DISABLED ) + return; + + if ( SFX_ITEM_AVAILABLE == eState && SfxItemPool::IsWhich(nWhich) ) + pOldItem = &aSet.Get(nWhich); + + if ( SFX_ITEM_SET == eState || + ( SFX_ITEM_AVAILABLE == eState && + SfxItemPool::IsWhich(nWhich) && + pOldItem ) ) + { + if ( pOldItem->ISA(SfxBoolItem) ) + { + // wir koennen Bools toggeln + sal_Bool bOldValue = ((const SfxBoolItem *)pOldItem)->GetValue(); + SfxBoolItem *pNewItem = (SfxBoolItem*) (pOldItem->Clone()); + pNewItem->SetValue( !bOldValue ); + aReq.AppendItem( *pNewItem ); + delete pNewItem; + } + else if ( pOldItem->ISA(SfxEnumItemInterface) && + ((SfxEnumItemInterface *)pOldItem)->HasBoolValue()) + { + // und Enums mit Bool-Interface + SfxEnumItemInterface *pNewItem = + (SfxEnumItemInterface*) (pOldItem->Clone()); + pNewItem->SetBoolValue(!((SfxEnumItemInterface *)pOldItem)->GetBoolValue()); + aReq.AppendItem( *pNewItem ); + delete pNewItem; + } + else { + DBG_ERROR( "Toggle only for Enums and Bools allowed" ); + } + } + else if ( SFX_ITEM_DONTCARE == eState ) + { + // ein Status-Item per Factory erzeugen + SfxPoolItem *pNewItem = pSlot->GetType()->CreateItem(); + DBG_ASSERT( pNewItem, "Toggle an Slot ohne ItemFactory" ); + pNewItem->SetWhich( nWhich ); + + if ( pNewItem->ISA(SfxBoolItem) ) + { + // wir koennen Bools toggeln + ((SfxBoolItem*)pNewItem)->SetValue( sal_True ); + aReq.AppendItem( *pNewItem ); + } + else if ( pNewItem->ISA(SfxEnumItemInterface) && + ((SfxEnumItemInterface *)pNewItem)->HasBoolValue()) + { + // und Enums mit Bool-Interface + ((SfxEnumItemInterface*)pNewItem)->SetBoolValue(sal_True); + aReq.AppendItem( *pNewItem ); + } + else { + DBG_ERROR( "Toggle only for Enums and Bools allowed" ); + } + delete pNewItem; + } + else { + DBG_ERROR( "suspicious Toggle-Slot" ); + } + } + + pDispatcher->_Execute( *pShell, *pSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD ); + } + else + pDispatcher->_Execute( *pShell, *pSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD ); +} + +//-------------------------------------------------------------------- + +void SfxBindings::UpdateSlotServer_Impl() +{ + DBG_PROFSTART(SfxBindingsUpdateServers); + DBG_MEMTEST(); + DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); + + // synchronisieren + pDispatcher->Flush(); +// pDispatcher->Update_Impl(); + + if ( pImp->bAllMsgDirty ) + { + if ( !nRegLevel ) + { + ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame + ( pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY ); + //if ( xFrame.is() ) + // xFrame->contextChanged(); + pImp->bContextChanged = FALSE; + } + else + pImp->bContextChanged = TRUE; + } + + const sal_uInt16 nCount = pImp->pCaches->Count(); + for(sal_uInt16 i = 0; i < nCount; ++i) + { + SfxStateCache *pCache = pImp->pCaches->GetObject(i); + pCache->GetSlotServer(*pDispatcher, pImp->xProv); + } + pImp->bMsgDirty = pImp->bAllMsgDirty = sal_False; + + Broadcast( SfxSimpleHint(SFX_HINT_DOCCHANGED) ); + + DBG_PROFSTOP(SfxBindingsUpdateServers); +} + +//-------------------------------------------------------------------- + +#ifdef WNT +int __cdecl CmpUS_Impl(const void *p1, const void *p2) +#else +int CmpUS_Impl(const void *p1, const void *p2) +#endif + +/* [Beschreibung] + + Interne Vergleichsfunktion fuer qsort. +*/ + +{ + return *(sal_uInt16 *)p1 - *(sal_uInt16 *)p2; +} + +//-------------------------------------------------------------------- + +SfxItemSet* SfxBindings::CreateSet_Impl +( + SfxStateCache*& pCache, // in: Status-Cache von nId + const SfxSlot*& pRealSlot, // out: RealSlot zu nId + const SfxSlotServer** pMsgServer, // out: Slot-Server zu nId + SfxFoundCacheArr_Impl& rFound // out: Liste der Caches der Siblings +) +{ + DBG_MEMTEST(); + DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); + + DBG_ASSERT( !pImp->bMsgDirty, "CreateSet_Impl mit dirty MessageServer" ); + + const SfxSlotServer* pMsgSvr = pCache->GetSlotServer(*pDispatcher, pImp->xProv); + if(!pMsgSvr || !pDispatcher) + return 0; + + DBG_PROFSTART(SfxBindingsCreateSet); + pRealSlot = 0; + *pMsgServer = pMsgSvr; + + sal_uInt16 nShellLevel = pMsgSvr->GetShellLevel(); + SfxShell *pShell = pDispatcher->GetShell( nShellLevel ); + if ( !pShell ) // seltener GPF beim Browsen durch Update aus Inet-Notify + return 0; + + SfxItemPool &rPool = pShell->GetPool(); + + // hole die Status-Methode, von der pCache bedient wird + SfxStateFunc pFnc = 0; + const SfxInterface *pInterface = pShell->GetInterface(); + if ( SFX_KIND_ENUM == pMsgSvr->GetSlot()->GetKind() ) + { + pRealSlot = pInterface->GetRealSlot(pMsgSvr->GetSlot()); + pCache = GetStateCache( pRealSlot->GetSlotId() ); +// DBG_ASSERT( pCache, "Kein Slotcache fuer den Masterslot gefunden!" ); + } + else + pRealSlot = pMsgSvr->GetSlot(); + + // + // Achtung: pCache darf auch NULL sein !!! + // + + pFnc = pRealSlot->GetStateFnc(); + + // der RealSlot ist immer drin + const SfxFoundCache_Impl *pFound = new SfxFoundCache_Impl( + pRealSlot->GetSlotId(), pRealSlot->GetWhich(rPool), pRealSlot, pCache ); + rFound.Insert( pFound ); + + USHORT nSlot = pRealSlot->GetSlotId(); + if ( !SfxMacroConfig::IsMacroSlot( nSlot ) && !(nSlot >= SID_VERB_START && nSlot <= SID_VERB_END) ) + { + pInterface = pInterface->GetRealInterfaceForSlot( pRealSlot ); + DBG_ASSERT (pInterface,"Slot in angegebener Shell nicht gefunden!"); + } + + // Durchsuche die Bindings nach den von derselben Funktion bedienten Slots. + // Daf"ur kommen nur Slots in Frage, die es im gefundenen Interface gibt. + + // Die Position des Statecaches im StateCache-Array + sal_uInt16 nCachePos = pImp->nMsgPos; + const SfxSlot *pSibling = pRealSlot->GetNextSlot(); + + // Die Slots eines Interfaces sind im Kreis verkettet + while ( pSibling > pRealSlot ) + { + SfxStateFunc pSiblingFnc=0; + SfxStateCache *pSiblingCache = + GetStateCache( pSibling->GetSlotId(), &nCachePos ); + + // Ist der Slot "uberhaupt gecached ? + if ( pSiblingCache ) + { + const SfxSlotServer *pServ = pSiblingCache->GetSlotServer(*pDispatcher, pImp->xProv); + if ( pServ && pServ->GetShellLevel() == nShellLevel ) + pSiblingFnc = pServ->GetSlot()->GetStateFnc(); + } + + // Mu\s der Slot "uberhaupt upgedatet werden ? + FASTBOOL bInsert = pSiblingCache && pSiblingCache->IsControllerDirty(); + + // Bugfix #26161#: Es reicht nicht, nach der selben Shell zu fragen !! + FASTBOOL bSameMethod = pSiblingCache && pFnc == pSiblingFnc; + + // Wenn der Slot ein nicht-dirty MasterSlot ist, dann ist vielleicht + // einer seiner Slaves dirty ? Dann wird der Masterslot doch eingef"ugt. + if ( !bInsert && bSameMethod && pSibling->GetLinkedSlot() ) + { + // auch Slave-Slots auf Binding pru"fen + const SfxSlot* pFirstSlave = pSibling->GetLinkedSlot(); + for ( const SfxSlot *pSlaveSlot = pFirstSlave; + !bInsert; + pSlaveSlot = pSlaveSlot->GetNextSlot()) + { + // Die Slaves zeigen auf ihren Master + DBG_ASSERT(pSlaveSlot->GetLinkedSlot() == pSibling, + "Falsche Master/Slave-Beziehung!"); + + sal_uInt16 nCurMsgPos = pImp->nMsgPos; + const SfxStateCache *pSlaveCache = + GetStateCache( pSlaveSlot->GetSlotId(), &nCurMsgPos ); + + // Ist der Slave-Slot gecached und dirty ? + bInsert = pSlaveCache && pSlaveCache->IsControllerDirty(); + + // Slaves sind untereinander im Kreis verkettet + if (pSlaveSlot->GetNextSlot() == pFirstSlave) + break; + } + } + + if ( bInsert && bSameMethod ) + { + const SfxFoundCache_Impl *pFoundCache = new SfxFoundCache_Impl( + pSibling->GetSlotId(), pSibling->GetWhich(rPool), + pSibling, pSiblingCache ); + + rFound.Insert( pFoundCache ); + } + + pSibling = pSibling->GetNextSlot(); + } + + // aus den Ranges ein Set erzeugen + sal_uInt16 *pRanges = new sal_uInt16[rFound.Count() * 2 + 1]; + int j = 0; + USHORT i = 0; + while ( i < rFound.Count() ) + { + pRanges[j++] = rFound[i]->nWhichId; + // aufeinanderfolgende Zahlen + for ( ; i < rFound.Count()-1; ++i ) + if ( rFound[i]->nWhichId+1 != rFound[i+1]->nWhichId ) + break; + pRanges[j++] = rFound[i++]->nWhichId; + } + pRanges[j] = 0; // terminierende NULL + SfxItemSet *pSet = new SfxItemSet(rPool, pRanges); + delete [] pRanges; + DBG_PROFSTOP(SfxBindingsCreateSet); + return pSet; +} + +//-------------------------------------------------------------------- + +void SfxBindings::UpdateControllers_Impl +( + const SfxInterface* pIF, // das diese Id momentan bedienende Interface + const SfxFoundCache_Impl* pFound, // Cache, Slot, Which etc. + const SfxPoolItem* pItem, // item to send to controller + SfxItemState eState // state of item +) +{ + DBG_ASSERT( !pFound->pSlot || SFX_KIND_ENUM != pFound->pSlot->GetKind(), + "direct update of enum slot isn't allowed" ); + DBG_PROFSTART(SfxBindingsUpdateCtrl1); + + SfxStateCache* pCache = pFound->pCache; + const SfxSlot* pSlot = pFound->pSlot; + DBG_ASSERT( !pCache || !pSlot || pCache->GetId() == pSlot->GetSlotId(), "SID mismatch" ); + + // insofern gebunden, die Controller f"uer den Slot selbst updaten + if ( pCache && pCache->IsControllerDirty() ) + { + if ( SFX_ITEM_DONTCARE == eState ) + { + // uneindeuting + pCache->SetState( SFX_ITEM_DONTCARE, (SfxPoolItem *)-1 ); + } + else if ( SFX_ITEM_DEFAULT == eState && + pFound->nWhichId > SFX_WHICH_MAX ) + { + // kein Status oder Default aber ohne Pool + SfxVoidItem aVoid(0); + pCache->SetState( SFX_ITEM_UNKNOWN, &aVoid ); + } + else if ( SFX_ITEM_DISABLED == eState ) + pCache->SetState(SFX_ITEM_DISABLED, 0); + else + pCache->SetState(SFX_ITEM_AVAILABLE, pItem); + } + + DBG_PROFSTOP(SfxBindingsUpdateCtrl1); + + // insofern vorhanden und gebunden, die Controller f"uer Slave-Slots + // (Enum-Werte) des Slots updaten + DBG_PROFSTART(SfxBindingsUpdateCtrl2); + DBG_ASSERT( !pSlot || 0 == pSlot->GetLinkedSlot() || !pItem || + pItem->ISA(SfxEnumItemInterface), + "master slot with non-enum-type found" ); + const SfxSlot *pFirstSlave = pSlot ? pSlot->GetLinkedSlot() : 0; + if ( pIF && pFirstSlave) + { + // Items auf EnumItem casten + const SfxEnumItemInterface *pEnumItem = + PTR_CAST(SfxEnumItemInterface,pItem); + if ( eState == SFX_ITEM_AVAILABLE && !pEnumItem ) + eState = SFX_ITEM_DONTCARE; + else + eState = SfxControllerItem::GetItemState( pEnumItem ); + + // "uber alle Slaves-Slots iterieren + for ( const SfxSlot *pSlave = pFirstSlave; pSlave; pSlave = pSlave->GetNextSlot() ) + { + DBG_ASSERT(pSlave, "Falsche SlaveSlot-Verkettung!"); + DBG_ASSERT(SFX_KIND_ENUM == pSlave->GetKind(),"non enum slaves aren't allowed"); + DBG_ASSERT(pSlave->GetMasterSlotId() == pSlot->GetSlotId(),"falscher MasterSlot!"); + + // ist die Funktion gebunden? + SfxStateCache *pEnumCache = GetStateCache( pSlave->GetSlotId() ); + if ( pEnumCache ) + { + pEnumCache->Invalidate(sal_False); + + HACK(CONTROL/SELECT Kram) + if ( eState == SFX_ITEM_DONTCARE && pFound->nWhichId == 10144 ) + { + SfxVoidItem aVoid(0); + pEnumCache->SetState( SFX_ITEM_UNKNOWN, &aVoid ); + + if (pSlave->GetNextSlot() == pFirstSlave) + break; + + continue; + } + + if ( SFX_ITEM_DISABLED == eState || !pEnumItem->IsEnabled( pSlave->GetSlotId()) ) + { + // disabled + pEnumCache->SetState(SFX_ITEM_DISABLED, 0); + } + else if ( SFX_ITEM_AVAILABLE == eState ) + { + // enum-Wert ermitteln + sal_uInt16 nValue = pEnumItem->GetEnumValue(); + SfxBoolItem aBool( pFound->nWhichId, pSlave->GetValue() == nValue ); + pEnumCache->SetState(SFX_ITEM_AVAILABLE, &aBool); + } + else + { + // uneindeuting + pEnumCache->SetState( SFX_ITEM_DONTCARE, (SfxPoolItem *)-1 ); + } + } + + if (pSlave->GetNextSlot() == pFirstSlave) + break; + } + } + + DBG_PROFSTOP(SfxBindingsUpdateCtrl2); +} + + +//-------------------------------------------------------------------- + +IMPL_LINK( SfxBindings, NextJob_Impl, Timer *, pTimer ) +{ +#ifdef DBG_UTIL + // on Windows very often C++ Exceptions (GPF etc.) are caught by MSVCRT or another MS library + // try to get them here + try + { +#endif + const unsigned MAX_INPUT_DELAY = 200; + + DBG_MEMTEST(); + DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); + + DBG_PROFSTART(SfxBindingsNextJob_Impl0); + + if ( Application::GetLastInputInterval() < MAX_INPUT_DELAY && pTimer ) + { + pImp->aTimer.SetTimeout(TIMEOUT_UPDATING); + return sal_True; + } + + SfxApplication *pSfxApp = SFX_APP(); + + if( pDispatcher ) + pDispatcher->Update_Impl(); + + // modifying the SfxObjectInterface-stack without SfxBindings => nothing to do + SfxViewFrame* pFrame = pDispatcher->GetFrame(); + //<!--Modified by PengYunQuan for Validity Cell Range Picker + //if ( (pFrame && pFrame->GetObjectShell()->IsInModalMode()) || pSfxApp->IsDowning() || !pImp->pCaches->Count() ) + if ( (pFrame && !pFrame->GetObjectShell()->AcceptStateUpdate()) || pSfxApp->IsDowning() || !pImp->pCaches->Count() ) + //-->Modified by PengYunQuan for Validity Cell Range Picker + { + DBG_PROFSTOP(SfxBindingsNextJob_Impl0); + return sal_True; + } + if ( !pDispatcher || !pDispatcher->IsFlushed() ) + { + DBG_PROFSTOP(SfxBindingsNextJob_Impl0); + return sal_True; + } + + // gfs. alle Server aktualisieren / geschieht in eigener Zeitscheibe + if ( pImp->bMsgDirty ) + { + UpdateSlotServer_Impl(); + DBG_PROFSTOP(SfxBindingsNextJob_Impl0); + return sal_False; + } + + DBG_PROFSTOP(SfxBindingsNextJob_Impl0); + DBG_PROFSTART(SfxBindingsNextJob_Impl); + pImp->bAllDirty = sal_False; + pImp->aTimer.SetTimeout(TIMEOUT_UPDATING); + + // at least 10 loops and further if more jobs are available but no input + FASTBOOL bPreEmptive = pTimer && !pSfxApp->Get_Impl()->nInReschedule; + sal_uInt16 nLoops = 10; + pImp->bInNextJob = sal_True; + const sal_uInt16 nCount = pImp->pCaches->Count(); + while ( pImp->nMsgPos < nCount ) + { + // iterate through the bound functions + sal_Bool bJobDone = sal_False; + while ( !bJobDone ) + { + SfxStateCache* pCache = (*pImp->pCaches)[pImp->nMsgPos]; + DBG_ASSERT( pCache, "invalid SfxStateCache-position in job queue" ); + sal_Bool bWasDirty = pCache->IsControllerDirty(); + if ( bWasDirty ) + { +/* + sal_Bool bSkip = sal_False; + if ( pImp->bFirstRound ) + { + // Falls beim Update eine Shell vorgezogen werden soll, + // kommt in einer ersten Update-Runde nur diese dran + const SfxSlotServer *pMsgServer = + pCache->GetSlotServer(*pDispatcher, pImp->xProv); + if ( pMsgServer && + pMsgServer->GetShellLevel() != pImp->nFirstShell ) + bSkip = sal_True; + } + + if ( !bSkip ) + { +*/ + Update_Impl( pCache ); + DBG_ASSERT( nCount == pImp->pCaches->Count(), + "Reschedule in StateChanged => buff" ); +// } + } + + // skip to next function binding + ++pImp->nMsgPos; + + // keep job if it is not completed, but any input is available + bJobDone = pImp->nMsgPos >= nCount; + if ( bJobDone && pImp->bFirstRound ) + { + // Update der bevorzugten Shell ist gelaufen, nun d"urfen + // auch die anderen + bJobDone = sal_False; + pImp->bFirstRound = sal_False; + pImp->nMsgPos = 0; + } + + if ( bWasDirty && !bJobDone && bPreEmptive && (--nLoops == 0) ) + { + DBG_PROFSTOP(SfxBindingsNextJob_Impl); + pImp->bInNextJob = sal_False; + return sal_False; + } + } + } + + pImp->nMsgPos = 0; + + // check for volatile slots + bool bVolatileSlotsPresent = false; + for ( sal_uInt16 n = 0; n < nCount; ++n ) + { + SfxStateCache* pCache = (*pImp->pCaches)[n]; + const SfxSlotServer *pSlotServer = pCache->GetSlotServer(*pDispatcher, pImp->xProv); + if ( pSlotServer && pSlotServer->GetSlot()->IsMode(SFX_SLOT_VOLATILE) ) + { + pCache->Invalidate(sal_False); + bVolatileSlotsPresent = true; + } + } + + if (bVolatileSlotsPresent) + pImp->aTimer.SetTimeout(TIMEOUT_IDLE); + else + pImp->aTimer.Stop(); + + // Update-Runde ist beendet + pImp->bInNextJob = sal_False; + Broadcast(SfxSimpleHint(SFX_HINT_UPDATEDONE)); + DBG_PROFSTOP(SfxBindingsNextJob_Impl); + return sal_True; +#ifdef DBG_UTIL + } + catch (...) + { + DBG_ERROR("C++ exception caught!"); + pImp->bInNextJob = sal_False; + } + + return sal_False; +#endif +} + +//-------------------------------------------------------------------- + +sal_uInt16 SfxBindings::EnterRegistrations(const char *pFile, int nLine) +{ + (void)pFile; + (void)nLine; + DBG_MEMTEST(); +#ifdef DBG_UTIL + ByteString aMsg; + aMsg.Fill( Min(nRegLevel, sal_uInt16(8) ) ); + aMsg += "this = "; + aMsg += ByteString::CreateFromInt32((long)this); + aMsg += " Level = "; + aMsg += ByteString::CreateFromInt32(nRegLevel); + aMsg += " SfxBindings::EnterRegistrations "; + if(pFile) { + aMsg += "File: "; + aMsg += pFile; + aMsg += " Line: "; + aMsg += ByteString::CreateFromInt32(nLine); + } +// FILE* pLog = fopen( "c:\\bindings.log", "a+w" ); +// fwrite( aMsg.GetBuffer(), 1, aMsg.Len(), pLog ); +// fclose( pLog ); + DbgTrace( aMsg.GetBuffer() ); +#endif + + // Wenn Bindings gelockt werden, auch SubBindings locken + if ( pImp->pSubBindings ) + { + pImp->pSubBindings->ENTERREGISTRATIONS(); + + // Dieses EnterRegistrations ist f"ur die SubBindings kein "echtes" + pImp->pSubBindings->pImp->nOwnRegLevel--; + + // Bindings synchronisieren + pImp->pSubBindings->nRegLevel = nRegLevel + pImp->pSubBindings->pImp->nOwnRegLevel + 1; + } + + pImp->nOwnRegLevel++; + + // check if this is the outer most level + if ( ++nRegLevel == 1 ) + { + // stop background-processing + pImp->aTimer.Stop(); + + // flush the cache + pImp->nCachedFunc1 = 0; + pImp->nCachedFunc2 = 0; + + // merken, ob ganze Caches verschwunden sind + pImp->bCtrlReleased = sal_False; + } + + return nRegLevel; +} +//-------------------------------------------------------------------- + +void SfxBindings::LeaveRegistrations( sal_uInt16 nLevel, const char *pFile, int nLine ) +{ + (void)nLevel; // unused variable + (void)pFile; + (void)nLine; + DBG_MEMTEST(); + DBG_ASSERT( nRegLevel, "Leave without Enter" ); + DBG_ASSERT( nLevel == USHRT_MAX || nLevel == nRegLevel, "wrong Leave" ); + + // Nur wenn die SubBindings noch von den SuperBindings gelockt sind, diesen Lock entfernen + // ( d.h. wenn es mehr Locks als "echte" Locks dort gibt ) + if ( pImp->pSubBindings && pImp->pSubBindings->nRegLevel > pImp->pSubBindings->pImp->nOwnRegLevel ) + { + // Bindings synchronisieren + pImp->pSubBindings->nRegLevel = nRegLevel + pImp->pSubBindings->pImp->nOwnRegLevel; + + // Dieses LeaveRegistrations ist f"ur die SubBindings kein "echtes" + pImp->pSubBindings->pImp->nOwnRegLevel++; + pImp->pSubBindings->LEAVEREGISTRATIONS(); + } + + pImp->nOwnRegLevel--; + + // check if this is the outer most level + if ( --nRegLevel == 0 && !SFX_APP()->IsDowning() ) + { + if ( pImp->bContextChanged ) + { + pImp->bContextChanged = FALSE; + /* + ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame + ( pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY ); + if ( xFrame.is() ) + xFrame->contextChanged();*/ + } + +#ifndef slow + SfxViewFrame* pFrame = pDispatcher->GetFrame(); + + // ggf unbenutzte Caches entfernen bzw. PlugInInfo aufbereiten + if ( pImp->bCtrlReleased ) + { + for ( sal_uInt16 nCache = pImp->pCaches->Count(); nCache > 0; --nCache ) + { + // Cache via ::com::sun::star::sdbcx::Index besorgen + SfxStateCache *pCache = pImp->pCaches->GetObject(nCache-1); + + // kein Controller mehr interessiert + if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() ) + { + // Cache entfernen. Safety: first remove and then delete + SfxStateCache* pSfxStateCache = (*pImp->pCaches)[nCache-1]; + pImp->pCaches->Remove(nCache-1, 1); + delete pSfxStateCache; + } + else + { + // neue Controller mit den alten Items benachrichtigen + //!pCache->SetCachedState(); + } + } + } +#endif + // restart background-processing + pImp->nMsgPos = 0; + if ( !pFrame || !pFrame->GetObjectShell() ) + return; + if ( pImp->pCaches && pImp->pCaches->Count() ) + { + pImp->aTimer.Stop(); + pImp->aTimer.SetTimeout(TIMEOUT_FIRST); + pImp->aTimer.Start(); +// pImp->bFirstRound = sal_True; + } + } + +#ifdef DBG_UTIL + ByteString aMsg; + aMsg.Fill( Min(nRegLevel, sal_uInt16(8)) ); + aMsg += "this = "; + aMsg += ByteString::CreateFromInt32((long)this); + aMsg += " Level = "; + aMsg += ByteString::CreateFromInt32(nRegLevel); + aMsg += " SfxBindings::LeaveRegistrations "; + if(pFile) { + aMsg += "File: "; + aMsg += pFile; + aMsg += " Line: "; + aMsg += ByteString::CreateFromInt32(nLine); + } +// FILE* pLog = fopen( "c:\\bindings.log", "a+w" ); +// fwrite( aMsg.GetBuffer(), 1, aMsg.Len(), pLog ); +// fclose( pLog ); + DbgTrace( aMsg.GetBuffer() ); +#endif +} + +//-------------------------------------------------------------------- + +const SfxSlot* SfxBindings::GetSlot(sal_uInt16 nSlotId) +{ + DBG_MEMTEST(); + DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); + + // syncronisieren + pDispatcher->Flush(); + if ( pImp->bMsgDirty ) + UpdateSlotServer_Impl(); + + // get the cache for the specified function; return if not bound + SfxStateCache* pCache = GetStateCache(nSlotId); + return pCache && pCache->GetSlotServer(*pDispatcher, pImp->xProv)? + pCache->GetSlotServer(*pDispatcher, pImp->xProv)->GetSlot(): 0; +} + +//-------------------------------------------------------------------- + +void SfxBindings::SetDispatcher( SfxDispatcher *pDisp ) +{ + SfxDispatcher *pOldDispat = pDispatcher; + if ( pDisp != pDispatcher ) + { + if ( pOldDispat ) + { + SfxBindings* pBind = pOldDispat->GetBindings(); + while ( pBind ) + { + if ( pBind->pImp->pSubBindings == this && pBind->pDispatcher != pDisp ) + pBind->SetSubBindings_Impl( NULL ); + pBind = pBind->pImp->pSubBindings; + } + } + + pDispatcher = pDisp; + + ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider > xProv; + if ( pDisp ) + xProv = ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider > + ( pDisp->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY ); + + SetDispatchProvider_Impl( xProv ); + InvalidateAll( sal_True ); + InvalidateUnoControllers_Impl(); + + if ( pDispatcher && !pOldDispat ) + { + if ( pImp->pSubBindings && pImp->pSubBindings->pDispatcher != pOldDispat ) + { + DBG_ERROR( "SubBindings vor Aktivieren schon gesetzt!" ); + pImp->pSubBindings->ENTERREGISTRATIONS(); + } + LEAVEREGISTRATIONS(); + } + else if( !pDispatcher ) + { + ENTERREGISTRATIONS(); + if ( pImp->pSubBindings && pImp->pSubBindings->pDispatcher != pOldDispat ) + { + DBG_ERROR( "SubBindings im Deaktivieren immer noch gesetzt!" ); + pImp->pSubBindings->LEAVEREGISTRATIONS(); + } + } + + Broadcast( SfxSimpleHint( SFX_HINT_DATACHANGED ) ); + + if ( pDisp ) + { + SfxBindings* pBind = pDisp->GetBindings(); + while ( pBind && pBind != this ) + { + if ( !pBind->pImp->pSubBindings ) + { + pBind->SetSubBindings_Impl( this ); + break; + } + + pBind = pBind->pImp->pSubBindings; + } + } + } +} + +//-------------------------------------------------------------------- + +void SfxBindings::ClearCache_Impl( sal_uInt16 nSlotId ) +{ + GetStateCache(nSlotId)->ClearCache(); +} + +//-------------------------------------------------------------------- +void SfxBindings::StartUpdate_Impl( sal_Bool bComplete ) +{ + if ( pImp->pSubBindings ) + pImp->pSubBindings->StartUpdate_Impl( bComplete ); + + if ( !bComplete ) + // Update darf unterbrochen werden + NextJob_Impl(&pImp->aTimer); + else + // alle Slots am St"uck updaten + NextJob_Impl(0); +} + +//------------------------------------------------------------------------- + +SfxItemState SfxBindings::QueryState( sal_uInt16 nSlot, SfxPoolItem* &rpState ) +{ + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp; + SfxStateCache *pCache = GetStateCache( nSlot ); + if ( pCache ) + xDisp = pCache->GetDispatch(); + if ( xDisp.is() || !pCache ) + { + const SfxSlot* pSlot = SfxSlotPool::GetSlotPool( pDispatcher->GetFrame() ).GetSlot( nSlot ); + if ( !pSlot || !pSlot->pUnoName ) + return SFX_ITEM_DISABLED; + + ::com::sun::star::util::URL aURL; + ::rtl::OUString aCmd( DEFINE_CONST_UNICODE(".uno:")); + aURL.Protocol = aCmd; + aURL.Path = ::rtl::OUString::createFromAscii(pSlot->GetUnoName()); + aCmd += aURL.Path; + aURL.Complete = aCmd; + aURL.Main = aCmd; + + if ( !xDisp.is() ) + xDisp = pImp->xProv->queryDispatch( aURL, ::rtl::OUString(), 0 ); + + if ( xDisp.is() ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XUnoTunnel > xTunnel( xDisp, ::com::sun::star::uno::UNO_QUERY ); + SfxOfficeDispatch* pDisp = NULL; + if ( xTunnel.is() ) + { + sal_Int64 nImplementation = xTunnel->getSomething(SfxOfficeDispatch::impl_getStaticIdentifier()); + pDisp = reinterpret_cast< SfxOfficeDispatch* >( sal::static_int_cast< sal_IntPtr >( nImplementation )); + } + + if ( !pDisp ) + { + BOOL bDeleteCache = FALSE; + if ( !pCache ) + { + pCache = new SfxStateCache( nSlot ); + pCache->GetSlotServer( *GetDispatcher_Impl(), pImp->xProv ); + bDeleteCache = TRUE; + } + + SfxItemState eState = SFX_ITEM_SET; + SfxPoolItem *pItem=NULL; + BindDispatch_Impl *pBind = new BindDispatch_Impl( xDisp, aURL, pCache, pSlot ); + pBind->acquire(); + xDisp->addStatusListener( pBind, aURL ); + if ( !pBind->GetStatus().IsEnabled ) + { + eState = SFX_ITEM_DISABLED; + } + else + { + ::com::sun::star::uno::Any aAny = pBind->GetStatus().State; + ::com::sun::star::uno::Type pType = aAny.getValueType(); + + if ( pType == ::getBooleanCppuType() ) + { + sal_Bool bTemp = false; + aAny >>= bTemp ; + pItem = new SfxBoolItem( nSlot, bTemp ); + } + else if ( pType == ::getCppuType((const sal_uInt16*)0) ) + { + sal_uInt16 nTemp = 0; + aAny >>= nTemp ; + pItem = new SfxUInt16Item( nSlot, nTemp ); + } + else if ( pType == ::getCppuType((const sal_uInt32*)0) ) + { + sal_uInt32 nTemp = 0; + aAny >>= nTemp ; + pItem = new SfxUInt32Item( nSlot, nTemp ); + } + else if ( pType == ::getCppuType((const ::rtl::OUString*)0) ) + { + ::rtl::OUString sTemp ; + aAny >>= sTemp ; + pItem = new SfxStringItem( nSlot, sTemp ); + } + else + pItem = new SfxVoidItem( nSlot ); + } + + xDisp->removeStatusListener( pBind, aURL ); + pBind->Release(); + rpState = pItem; + if ( bDeleteCache ) + DELETEZ( pCache ); + return eState; + } + } + } + + // Dann am Dispatcher testen; da die von dort zur"uckgegebenen Items immer + // DELETE_ON_IDLE sind, mu\s eine Kopie davon gezogen werden, um einen + // Eigent"umer"ubergang zu erm"oglichen + const SfxPoolItem *pItem = NULL; + SfxItemState eState = pDispatcher->QueryState( nSlot, pItem ); + if ( eState == SFX_ITEM_SET ) + { + DBG_ASSERT( pItem, "SFX_ITEM_SET aber kein Item!" ); + if ( pItem ) + rpState = pItem->Clone(); + } + else if ( eState == SFX_ITEM_AVAILABLE && pItem ) + { + rpState = pItem->Clone(); + } + + return eState; +} + +void SfxBindings::SetSubBindings_Impl( SfxBindings *pSub ) +{ + if ( pImp->pSubBindings ) + { + pImp->pSubBindings->SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > () ); + pImp->pSubBindings->pImp->pSuperBindings = NULL; + } + + pImp->pSubBindings = pSub; + + if ( pSub ) + { + pImp->pSubBindings->SetDispatchProvider_Impl( pImp->xProv ); + pSub->pImp->pSuperBindings = this; + } +} + +SfxBindings* SfxBindings::GetSubBindings_Impl( sal_Bool bTop ) const +{ + SfxBindings *pRet = pImp->pSubBindings; + if ( bTop ) + { + while ( pRet->pImp->pSubBindings ) + pRet = pRet->pImp->pSubBindings; + } + + return pRet; +} + +void SfxBindings::SetWorkWindow_Impl( SfxWorkWindow* pWork ) +{ + pImp->pWorkWin = pWork; +} + +SfxWorkWindow* SfxBindings::GetWorkWindow_Impl() const +{ + return pImp->pWorkWin; +} + +void SfxBindings::RegisterUnoController_Impl( SfxUnoControllerItem* pControl ) +{ + if ( !pImp->pUnoCtrlArr ) + pImp->pUnoCtrlArr = new SfxUnoControllerArr_Impl; + pImp->pUnoCtrlArr->Insert( pControl, pImp->pUnoCtrlArr->Count() ); +} + +void SfxBindings::ReleaseUnoController_Impl( SfxUnoControllerItem* pControl ) +{ + if ( pImp->pUnoCtrlArr ) + { + sal_uInt16 nPos = pImp->pUnoCtrlArr->GetPos( pControl ); + if ( nPos != 0xFFFF ) + { + pImp->pUnoCtrlArr->Remove( nPos ); + return; + } + } + + if ( pImp->pSubBindings ) + pImp->pSubBindings->ReleaseUnoController_Impl( pControl ); +} + +void SfxBindings::InvalidateUnoControllers_Impl() +{ + if ( pImp->pUnoCtrlArr ) + { + sal_uInt16 nCount = pImp->pUnoCtrlArr->Count(); + for ( sal_uInt16 n=nCount; n>0; n-- ) + { + SfxUnoControllerItem *pCtrl = (*pImp->pUnoCtrlArr)[n-1]; + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > xRef( (::cppu::OWeakObject*)pCtrl, ::com::sun::star::uno::UNO_QUERY ); + pCtrl->ReleaseDispatch(); + pCtrl->GetNewDispatch(); + } + } + + if ( pImp->pSubBindings ) + pImp->pSubBindings->InvalidateUnoControllers_Impl(); +} + +sal_Bool SfxBindings::IsInUpdate() const +{ + sal_Bool bInUpdate = pImp->bInUpdate; + if ( !bInUpdate && pImp->pSubBindings ) + bInUpdate = pImp->pSubBindings->IsInUpdate(); + return bInUpdate; +} + +void SfxBindings::SetVisibleState( sal_uInt16 nId, sal_Bool bShow ) +{ + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp; + SfxStateCache *pCache = GetStateCache( nId ); + if ( pCache ) + pCache->SetVisibleState( bShow ); +} + +void SfxBindings::SetActiveFrame( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > & rFrame ) +{ + if ( rFrame.is() || !pDispatcher ) + SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > ( rFrame, ::com::sun::star::uno::UNO_QUERY ) ); + else + SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > ( + pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), ::com::sun::star::uno::UNO_QUERY ) ); +} + +const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > SfxBindings::GetActiveFrame() const +{ + const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame( pImp->xProv, ::com::sun::star::uno::UNO_QUERY ); + if ( xFrame.is() || !pDispatcher ) + return xFrame; + else + return pDispatcher->GetFrame()->GetFrame().GetFrameInterface(); +} + +void SfxBindings::SetDispatchProvider_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & rProv ) +{ + sal_Bool bInvalidate = ( rProv != pImp->xProv ); + if ( bInvalidate ) + { + pImp->xProv = rProv; + InvalidateAll( sal_True ); + InvalidateUnoControllers_Impl(); + } + + if ( pImp->pSubBindings ) + pImp->pSubBindings->SetDispatchProvider_Impl( pImp->xProv ); +} + +const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & SfxBindings::GetDispatchProvider_Impl() const +{ + return pImp->xProv; +} + +SystemWindow* SfxBindings::GetSystemWindow() const +{ + SfxViewFrame *pFrame = pDispatcher->GetFrame(); + while ( pFrame->GetParentViewFrame_Impl() ) + pFrame = pFrame->GetParentViewFrame_Impl(); + SfxViewFrame* pTop = pFrame->GetTopViewFrame(); + return pTop->GetFrame().GetTopWindow_Impl(); +} + +BOOL SfxBindings::ExecuteCommand_Impl( const String& rCommand ) +{ + ::com::sun::star::util::URL aURL; + aURL.Complete = rCommand; + Reference < XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance( rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY ); + xTrans->parseStrict( aURL ); + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp = pImp->xProv->queryDispatch( aURL, ::rtl::OUString(), 0 ); + if ( xDisp.is() ) + { + if(::comphelper::UiEventsLogger::isEnabled()) //#i88653# + { + ::rtl::OUString sAppName; + try + { + static ::rtl::OUString our_aModuleManagerName = ::rtl::OUString::createFromAscii("com.sun.star.frame.ModuleManager"); + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceManager = + ::comphelper::getProcessServiceFactory(); + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModuleManager > xModuleManager( + xServiceManager->createInstance(our_aModuleManagerName) + , ::com::sun::star::uno::UNO_QUERY_THROW); + ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame( + pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY_THROW); + sAppName = xModuleManager->identify(xFrame); + } catch(::com::sun::star::uno::Exception&) {} + Sequence<beans::PropertyValue> source; + ::comphelper::UiEventsLogger::appendDispatchOrigin(source, sAppName, ::rtl::OUString::createFromAscii("SfxAsyncExec")); + ::comphelper::UiEventsLogger::logDispatch(aURL, source); + } + new SfxAsyncExec_Impl( aURL, xDisp ); + return TRUE; + } + + return FALSE; +} + +com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder > SfxBindings::GetRecorder() const +{ + return pImp->xRecorder; +} + +void SfxBindings::SetRecorder_Impl( com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder >& rRecorder ) +{ + pImp->xRecorder = rRecorder; +} + +void SfxBindings::ContextChanged_Impl() +{ + if ( !pImp->bInUpdate && ( !pImp->bContextChanged || !pImp->bAllMsgDirty ) ) + { + InvalidateAll( TRUE ); + } +} + +uno::Reference < frame::XDispatch > SfxBindings::GetDispatch( const SfxSlot* pSlot, const util::URL& aURL, sal_Bool bMasterCommand ) +{ + uno::Reference < frame::XDispatch > xRet; + SfxStateCache* pCache = GetStateCache( pSlot->nSlotId ); + if ( pCache && !bMasterCommand ) + xRet = pCache->GetInternalDispatch(); + if ( !xRet.is() ) + { + // dispatches for slaves are unbound, they don't have a state + SfxOfficeDispatch* pDispatch = bMasterCommand ? + new SfxOfficeDispatch( pDispatcher, pSlot, aURL ) : + new SfxOfficeDispatch( *this, pDispatcher, pSlot, aURL ); + + pDispatch->SetMasterUnoCommand( bMasterCommand ); + xRet = uno::Reference < frame::XDispatch >( pDispatch ); + if ( !pCache ) + pCache = GetStateCache( pSlot->nSlotId ); + + DBG_ASSERT( pCache, "No cache for OfficeDispatch!" ); + if ( pCache && !bMasterCommand ) + pCache->SetInternalDispatch( xRet ); + } + + return xRet; +} |