diff options
Diffstat (limited to 'sfx2/source/control')
-rw-r--r-- | sfx2/source/control/bindings.cxx | 2426 | ||||
-rw-r--r-- | sfx2/source/control/ctrlitem.cxx | 466 | ||||
-rwxr-xr-x | sfx2/source/control/dispatch.cxx | 3113 | ||||
-rw-r--r-- | sfx2/source/control/macro.cxx | 708 | ||||
-rw-r--r-- | sfx2/source/control/minfitem.cxx | 104 | ||||
-rw-r--r-- | sfx2/source/control/msg.cxx | 75 | ||||
-rw-r--r-- | sfx2/source/control/msgpool.cxx | 421 | ||||
-rw-r--r-- | sfx2/source/control/objface.cxx | 685 | ||||
-rw-r--r-- | sfx2/source/control/querystatus.cxx | 241 | ||||
-rw-r--r-- | sfx2/source/control/request.cxx | 978 | ||||
-rw-r--r-- | sfx2/source/control/sfxstatuslistener.cxx | 290 | ||||
-rw-r--r-- | sfx2/source/control/shell.cxx | 1288 | ||||
-rw-r--r-- | sfx2/source/control/sorgitm.cxx | 136 | ||||
-rw-r--r-- | sfx2/source/control/statcach.cxx | 577 | ||||
-rw-r--r-- | sfx2/source/control/unoctitm.cxx | 1013 |
15 files changed, 12521 insertions, 0 deletions
diff --git a/sfx2/source/control/bindings.cxx b/sfx2/source/control/bindings.cxx new file mode 100644 index 000000000000..cf04de2cb3a4 --- /dev/null +++ b/sfx2/source/control/bindings.cxx @@ -0,0 +1,2426 @@ +/************************************************************************* + * + * 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/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 + 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 ( !(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; +} diff --git a/sfx2/source/control/ctrlitem.cxx b/sfx2/source/control/ctrlitem.cxx new file mode 100644 index 000000000000..9376b81fa0ff --- /dev/null +++ b/sfx2/source/control/ctrlitem.cxx @@ -0,0 +1,466 @@ +/************************************************************************* + * + * 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 <svl/itempool.hxx> +#ifndef GCC +#endif + +#include <sfx2/ctrlitem.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/msgpool.hxx> +#include "statcach.hxx" +#include <sfx2/viewfrm.hxx> + +//==================================================================== + +DBG_NAME(SfxControllerItem); + +//-------------------------------------------------------------------- +#ifdef DBG_UTIL + +void SfxControllerItem::CheckConfigure_Impl( ULONG nType ) +{ + // echter Slot? (also kein Separator etc.) + if ( !nId ) + return; + + // ist die Id "uberhaupt in 'nType' konfigurierbar? + const SfxSlot *pSlot = SFX_SLOTPOOL().GetSlot(nId); + DBG_ASSERTWARNING( pSlot, "SfxControllerItem: binding not existing slot" ); + if ( pSlot && !pSlot->IsMode(nType) ) + { + DBG_WARNING( "SfxControllerItem: slot without ...Config-flag" ); + DbgOutf( "SfxControllerItem: Config-flag missing at SID %5d", + pSlot->GetSlotId() ); + } +} + +#endif + +//-------------------------------------------------------------------- + +// returns the next registered SfxControllerItem with the same id + +SfxControllerItem* SfxControllerItem::GetItemLink() +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + return pNext == this ? 0 : pNext; +} + +//-------------------------------------------------------------------- + +// returns TRUE if this binding is really bound to a function + +BOOL SfxControllerItem::IsBound() const +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + return pNext != this; +} + +//-------------------------------------------------------------------- + +// returns the associated function-id or 0 if none + +// USHORT SfxControllerItem::GetId() const; + +//==================================================================== + +// registeres with the id at the bindings + +void SfxControllerItem::Bind( USHORT nNewId, SfxBindings *pBindinx ) +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + DBG_ASSERT(pBindings || pBindinx, "Keine Bindings"); + + if ( IsBound() ) { + DBG_ASSERT(pBindings, "Keine Bindings"); + pBindings->Release(*this); + } + + nId = nNewId; + pNext = 0; + + if (pBindinx) + pBindings = pBindinx; + pBindings->Register(*this); +} + +void SfxControllerItem::BindInternal_Impl( USHORT nNewId, SfxBindings *pBindinx ) +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + DBG_ASSERT(pBindings || pBindinx, "Keine Bindings"); + + if ( IsBound() ) { + DBG_ASSERT(pBindings, "Keine Bindings"); + pBindings->Release(*this); + } + + nId = nNewId; + pNext = 0; + + if (pBindinx) + pBindings = pBindinx; + pBindings->RegisterInternal_Impl(*this); +} + + +//==================================================================== + +void SfxControllerItem::UnBind() + +/* [Beschreibung] + + "ost die Verbindung dieses SfxControllerItems mit der SfxBindings-Instanz, + an der es zur Zeit gebunden ist. Ab diesem Zeitpunkt erh"alt es keine + Statusbenachrichtigungen (<SfxControllerItem::StateChented()>) mehr. + + + [Querverweise] + + <SfxControllerItem::ReBind()> + <SfxControllerItem::ClearCache()> +*/ +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + DBG_ASSERT(pBindings, "Keine Bindings"); + DBG_ASSERT( IsBound(), "unbindings unbound SfxControllerItem" ); + + pBindings->Release(*this); + pNext = this; +} + +//==================================================================== + +void SfxControllerItem::ReBind() + +/* [Beschreibung] + + Binded dieses SfxControllerItem wieder an die SfxBindings-Instanz, + an der es zuletzt gebunden war. Ab diesem Zeitpunkt erh"alt es wieder + Statusbenachrichtigungen (<SfxControllerItem::StateChented()>). + + + [Querverweise] + + <SfxControllerItem::UnBind()> + <SfxControllerItem::ClearCache()> +*/ + +{ + DBG_MEMTEST(); +DBG_CHKTHIS(SfxControllerItem, 0); + DBG_ASSERT(pBindings, "Keine Bindings"); + DBG_ASSERT( !IsBound(), "bindings rebound SfxControllerItem" ); + + pBindings->Register(*this); +} + +//==================================================================== + +void SfxControllerItem::UpdateSlot() + +/* [Beschreibung] + + Holt den Status 'hart' neu. + + [Querverweise] + + <SfxControllerItem::ClearCache()> +*/ + +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + DBG_ASSERT(pBindings, "Keine Bindings"); + + pBindings->Update( GetId() ); +} + +//-------------------------------------------------------------------- + +void SfxControllerItem::ClearCache() + +/* [Beschreibung] + + "oscht den Status-Cache f"ur dieses SfxControllerItem. D.h. beim + n"achsten Status-Update wird das <SfxPoolItem> auf jeden Fall geschickt, + auch wenn zuvor dasselbe geschickt wurde. Dies wird ben"otigt, wenn + ein Controller umgeschaltet werden kann und sich diesen Status + selbst merkt. + + + [Beispiel] + + Der Kombi-Controller f"ur das Einstellen des Fl"achentyps und der + konkreten Auspr"agung (Farbe blau oder Schraffur X) kann im Typ + umgestellt werden, wird jedoch dann bei der n"achsten Selektion + wieder benachrichtigt, auch wenn es dieselben Daten sind. + + + [Querverweise] + + <SfxControllerItem::UnBind()> + <SfxControllerItem::ReBind()> +*/ + + +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + DBG_ASSERT(pBindings, "Keine Bindings"); + + pBindings->ClearCache_Impl( GetId() ); +} + +//-------------------------------------------------------------------- + +// replaces the successor in the list of bindings of the same id + +SfxControllerItem* SfxControllerItem::ChangeItemLink( SfxControllerItem* pNewLink ) +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + SfxControllerItem* pOldLink = pNext; + pNext = pNewLink; + return pOldLink == this ? 0 : pOldLink; +} + +//-------------------------------------------------------------------- + +// changes the id of unbound functions (e.g. for sub-menu-ids) + +void SfxControllerItem::SetId( USHORT nItemId ) +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + DBG_ASSERT( !IsBound(), "changing id of bound binding" ); + nId = nItemId; +} + +//-------------------------------------------------------------------- + +// creates a atomic item for a controller without registration + +SfxControllerItem::SfxControllerItem(): + nId(0), + pNext(this), + pBindings(0) +{ + DBG_MEMTEST(); + DBG_CTOR(SfxControllerItem, 0); +} + +//-------------------------------------------------------------------- + +// creates a representation of the function nId and registeres it + +SfxControllerItem::SfxControllerItem( USHORT nID, SfxBindings &rBindings ): + nId(nID), + pNext(this), + pBindings(&rBindings) +{ + DBG_MEMTEST(); + DBG_CTOR(SfxControllerItem, 0); + Bind(nId, &rBindings); +} + +//-------------------------------------------------------------------- + +// unregisteres the item in the bindings + +SfxControllerItem::~SfxControllerItem() +{ + DBG_MEMTEST(); + if ( IsBound() ) + pBindings->Release(*this); + DBG_DTOR(SfxControllerItem, 0); +} + +//-------------------------------------------------------------------- + +void SfxControllerItem::StateChanged +( + USHORT , // <SID> des ausl"osenden Slot + SfxItemState , // <SfxItemState> von 'pState' + const SfxPoolItem* // Slot-Status, ggf. 0 oder IsInvalidItem() +) + +/* [Beschreibung] + + Diese virtuelle Methode wird vom SFx gerufen, um <SfxControllerItem>s + dar"uber zu benachrichtigen, da\s sich der Status des Slots 'nSID' + ge"andert hat. Der neue Wert sowie der von diesem Wert ermittelte + Status wird als 'pState' bzw. 'eState' mitgegeben. + + Der Status eines Slots kann sich "andern, wenn z.B. das MDI-Fenster + gewechselt wird oder der Slot explizit mit <SfxBindings::Invalidate()> + invalidiert wurde. + + Achtung! Die Methode wird nicht gerufen, wenn der Slot ung"ultig wurde, + danach jedoch wieder denselben Wert angenommen hat. + + Diese Basisklasse braucht nicht gerufen zu werden, weitere Zwischenstufen + jedoch (z.B. <SfxToolboxControl>) sollten gerufen werden. +*/ + +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); +} + +//-------------------------------------------------------------------- + +void SfxControllerItem::DeleteFloatingWindow() +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); +} + +//-------------------------------------------------------------------- + +void SfxStatusForwarder::StateChanged +( + USHORT nSID, // <SID> des ausl"osenden Slot + SfxItemState eState, // <SfxItemState> von 'pState' + const SfxPoolItem* pState // Slot-Status, ggf. 0 oder IsInvalidItem() +) + +{ + pMaster->StateChanged( nSID, eState, pState ); +} + +//-------------------------------------------------------------------- + +SfxStatusForwarder::SfxStatusForwarder( + USHORT nSlotId, + SfxControllerItem& rMaster ): + SfxControllerItem( nSlotId, rMaster.GetBindings() ), + pMaster( &rMaster ) +{ +} + +//-------------------------------------------------------------------- + +SfxItemState SfxControllerItem::GetItemState +( + const SfxPoolItem* pState /* Pointer auf das <SfxPoolItem>, dessen + Status erfragt werden soll. */ +) + +/* [Beschreibung] + + Statische Methode zum Ermitteln des Status des SfxPoolItem-Pointers, + in der Methode <SfxControllerItem::StateChanged(const SfxPoolItem*)> + zu verwenden. + + [R"uckgabewert] + + SfxItemState SFX_ITEM_UNKNOWN + Enabled, aber keine weitere Statusinformation + verf"ugbar. Typisch f"ur <Slot>s, die allenfalls + zeitweise disabled sind, aber ihre Darstellung sonst + nicht "andern. + + SFX_ITEM_DISABLED + Disabled und keine weiter Statusinformation + verf"ugbar. Alle anderen ggf. angezeigten Werte sollten + auf den Default zur"uckgesetzt werden. + + SFX_ITEM_DONTCARE + Enabled aber es waren nur uneindeutige Werte + verf"ugbar (also keine, die abgefragt werden k"onnen). + + SFX_ITEM_AVAILABLE + Enabled und mit verf"ugbarem Wert, der von 'pState' + erfragbar ist. Der Typ ist dabei im gesamten + Programm eindeutig und durch den Slot festgelegt. +*/ + +{ + return !pState + ? SFX_ITEM_DISABLED + : IsInvalidItem(pState) + ? SFX_ITEM_DONTCARE + : pState->ISA(SfxVoidItem) && !pState->Which() + ? SFX_ITEM_UNKNOWN + : SFX_ITEM_AVAILABLE; +} + +//-------------------------------------------------------------------- + +SfxMapUnit SfxControllerItem::GetCoreMetric() const + +/* [Beschreibung] + + Holt vom zust"andigen Pool die Ma\seinheit ab, in der das Status-Item + vorliegt. +*/ + +{ + SfxStateCache *pCache = pBindings->GetStateCache( nId ); + SfxDispatcher *pDispat = pBindings->GetDispatcher_Impl(); + + if ( !pDispat ) + { + SfxViewFrame* pViewFrame = SfxViewFrame::Current(); + if ( !pViewFrame ) + SfxViewFrame::GetFirst(); + if ( pViewFrame ) + pDispat = pViewFrame->GetDispatcher(); + } + + if ( pDispat && pCache ) + { + const SfxSlotServer *pServer = pCache->GetSlotServer( *pDispat ); + if ( pServer ) + { + SfxShell *pSh = pDispat->GetShell( pServer->GetShellLevel() ); + SfxItemPool &rPool = pSh->GetPool(); + USHORT nWhich = rPool.GetWhich( nId ); + return rPool.GetMetric( nWhich ); + } + } + + DBG_WARNING( "W1: Can not find ItemPool!" ); + return SFX_MAPUNIT_100TH_MM; +} + +//------------------------------------------------------------------------ + +#ifdef _MSC_VER +#pragma optimize("g",off) +#endif + + diff --git a/sfx2/source/control/dispatch.cxx b/sfx2/source/control/dispatch.cxx new file mode 100755 index 000000000000..ddf3422744cb --- /dev/null +++ b/sfx2/source/control/dispatch.cxx @@ -0,0 +1,3113 @@ +/************************************************************************* + * + * 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 <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> +#ifndef _SFXEITEM_HXX //autogen +#include <svl/eitem.hxx> +#endif +#include <svl/undo.hxx> +#ifndef _WRKWIN_HXX //autogen +#include <vcl/wrkwin.hxx> +#endif +#include <svtools/ttprops.hxx> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> // wg. bsearch + +#define _SVSTDARR_ULONGS +#include <svl/svstdarr.hxx> +#include <svtools/helpopt.hxx> +#include <com/sun/star/frame/XLayoutManager.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#ifndef GCC +#endif + +// wg. 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" + +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 - und ConfigId der Toolbox + sal_uInt16 nMode; // spezielle Sichtbarkeitsflags + String aName; + SfxInterface* pIFace; + + SfxObjectBars_Impl() : + nResId( 0 ) + {} +}; + +//------------------------------------------------------------------ + +struct SfxDispatcher_Impl +{ + SfxRequestPtrArray aReqArr; + const SfxSlotServer* pCachedServ1; // zuletzt gerufene Message + const SfxSlotServer* pCachedServ2; // vorletzt gerufene Message + SfxShellStack_Impl aStack; // aktive Funktionalitaet + Timer aTimer; // fuers flushen + SfxToDoStack_Impl aToDoStack; // nicht abgearb. Push/Pop + SfxViewFrame* pFrame; // 0 oder zugeh"or. Frame + SfxDispatcher* pParent; // z.B. AppDispatcher, ggf. 0 + SfxHintPosterRef xPoster; // asynchrones Execute + sal_Bool bFlushing; // sal_True waehrend Flush //? + sal_Bool bUpdated; // Update_Impl gelaufen + sal_Bool bLocked; // kein Execute + sal_Bool bInvalidateOnUnlock;// da fragte jemand + sal_Bool bActive; // nicht verwechseln mit gesetzt! + sal_Bool* pInCallAliveFlag; // dem Stack den Dtor anzeigen + SfxObjectBars_Impl aObjBars[SFX_OBJECTBAR_MAX]; + SfxObjectBars_Impl aFixedObjBars[SFX_OBJECTBAR_MAX]; + SvULongs aChildWins; + sal_uInt32 nEventId; // EventId UserEvent + sal_Bool bUILocked; // Update abgeklemmt (!zappeln) + sal_Bool bNoUI; // UI nur vom Parent Dispatcher + sal_Bool bReadOnly; // Dokument ist ReadOnly + sal_Bool bQuiet; // nur parent dispatcher verwenden + sal_Bool bModal; // nur Slots vom Parent-Dispatcher + + sal_Bool bFilterEnabling; // sal_True=filter enabled slots, 2==ReadOnlyDoc uebersteuert + sal_uInt16 nFilterCount; // Anzahl der SIDs in pFilterSIDs + const sal_uInt16* pFilterSIDs; // sortiertes Array von SIDs + sal_uInt16 nStandardMode; // ExecuteMode f. PlugInDispatcher + SvUShorts* 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 + +/* [Beschreibung] + + Mit dieser Methode kann festgestellt werden, ob der SfxDispatcher + gesperrt oder freigegeben ist. Ein gesperrter SfxDispatcher + f"uhrt keine <SfxRequest>s mehr aus und liefert keine + Status-Informationen mehr. Er verh"alt sich so als w"aren alle + Slots disabled. + + Der Dispatcher gilt auch als gesperrt, wenn alle Dispatcher + gelockt sind (<SfxApplication::LockDispatcher()>) oder der zugeh"orige + Top-Frame im modal-mode ist und der angegebene Slot Frame-spezifisch + (also nicht von der Application) bedient wird. +*/ + +{ + return pImp->bLocked; +} + +//-------------------------------------------------------------------- +sal_Bool SfxDispatcher::IsAppDispatcher() const + +/* [Beschreibung] + + Mit dieser Methode l"a\st sich festellen, ob der SfxDispacher der + Applikations-Dispatcher ist. + + + [R"uckgabewert] + + sal_Bool sal_True + Es ist der Applikations-Dispatcher. + + sal_False + Es ist ein Dispatcher eines SfxViewFrame. +*/ + +{ + return !pImp->pFrame; +} + +//-------------------------------------------------------------------- +int SfxDispatcher::Call_Impl( SfxShell& rShell, const SfxSlot &rSlot, SfxRequest &rReq, sal_Bool bRecord ) + +/* [Beschreibung] + + Hilfsfunktion zum pr"ufen, ob ein Slot executed werden darf und + der Execution selbst. +*/ + +{ + SFX_STACK(SfxDispatcher::Call_Impl); + + // darf der Slot gerufen werden (i.S.v. enabled) + if ( rSlot.IsMode(SFX_SLOT_FASTCALL) || rShell.CanExecuteSlot_Impl(rSlot) ) + { + if ( GetFrame() ) + { + // ggf. Recording anwerfen + 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::createFromAscii("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() ); + } + } + + // Alles holen, was gebraucht wird, da der Slot den Execute evtl. nicht + // "uberlebt, falls es ein 'Pseudoslot' f"ur Macros oder Verben ist + sal_Bool bAutoUpdate = rSlot.IsMode(SFX_SLOT_AUTOUPDATE); + + // API-Call-Klammerung und Document-Lock w"ahrend des Calls + { + // 'this' mu\s im Dtor bescheid sagen + 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 ); + + // falls 'this' noch lebt + if ( bThisDispatcherAlive ) + pImp->pInCallAliveFlag = pOldInCallAliveFlag; + else + { + if ( pOldInCallAliveFlag ) + { + // auch verschachtelte Stack-Frames sch"utzen + *pOldInCallAliveFlag = sal_False; + } + + // do nothing after this object is dead + return rReq.IsDone(); + } + } + + if ( rReq.IsDone() ) + { + SfxBindings *pBindings = GetBindings(); + + // bei AutoUpdate sofort updaten; "Pseudoslots" d"urfen nicht + // Autoupdate sein! + if ( bAutoUpdate && pBindings ) + { + const SfxSlot* pSlave = rSlot.GetLinkedSlot(); + if (pSlave) + { + // bei Enum-Slots irgendeinen gebundenen Slave-Slot nehmen + 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 ) + +/* [Beschreibung] + + Der Konstruktor der Klasse SfxDispatcher legt einen leeren Stack + von <SfxShell>-Pointern an. Er ist initial nicht gelockt und gilt als + geflusht. +*/ + +{ + 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() + +/* [Beschreibung] + + Der Destruktor der Klasse SfxDispatcher darf nicht gerufen werden, + wenn die SfxDispatcher-Instanz aktiv ist. Es d"urfen sich allerdings + noch <SfxShell>-Pointer auf dem Stack befinden. +*/ + +{ +#ifdef DBG_UTIL + ByteString sTemp( "Delete Dispatcher " ); + sTemp += ByteString::CreateFromInt64( (sal_uIntPtr)this ); + DBG_TRACE( sTemp.GetBuffer() ); + DBG_ASSERT( !pImp->bActive, "deleting active Dispatcher" ); +#endif + + // Damit in LeaveRegistrations kein Timer per Reschedule in PlugComm + // zuschlaegt + pImp->aTimer.Stop(); + pImp->xPoster->SetEventHdl( Link() ); + + // die Stack-Varialblem in Call_Impl benachrichtigen + if ( pImp->pInCallAliveFlag ) + *pImp->pInCallAliveFlag = sal_False; + + // Bindings und App besorgen + SfxApplication *pSfxApp = SFX_APP(); + SfxBindings* pBindings = GetBindings(); + +// if (pImp->nEventId) +// pSfxApp->RemoveEventHdl(pImp->nEventId); + + // wenn noch nicht flushed, die Bindings wiederbeleben + if ( pBindings && !pSfxApp->IsDowning() && !bFlushed ) + pBindings->DLEAVEREGISTRATIONS(); + + // ggf. bei den Bindings abmelden + while ( pBindings ) + { + if ( pBindings->GetDispatcher_Impl() == this) + pBindings->SetDispatcher(0); + pBindings = pBindings->GetSubBindings_Impl(); + } + + delete pImp; +} + +//==================================================================== +void SfxDispatcher::Pop +( + SfxShell& rShell, /* Die vom Stack zu nehmende SfxShell-Instanz. */ + + sal_uInt16 nMode /* SFX_SHELL_POP_UNTIL + Es werden auch alle "uber 'rShell' liegenenden + SfxShell's vom Stack genommen. + + SFX_SHELL_POP_DELETE + Alle tats"achlich vom Stack genommenen + SfxShells werden gel"oscht. + + SFX_SHELL_PUSH (InPlace use only) + Die Shell wird gepusht. */ +) +/* [Beschreibung] + + Mit dieser Methode wird eine oder mehrere <SfxShell> vom SfxDispatcher + gepoppt. Die SfxShell wird zun"achst zum poppen vermerkt und + es wird ein Timer aufgesetzt. Erst bei Ablauf des Timers wird + tats"achlich gepoppt (<SfxDispatcher::Flush()>) und die <SfxBindings> + werden invalidiert. W"ahrend der Timer l"auft gleichen sich + entgegengesetzte Push und Pop Befehle mit derselben SfxShell aus. +*/ + +{ + 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(); + +#ifdef DBG_UTIL + ByteString aMsg( "-SfxDispatcher(" ); + aMsg += ByteString::CreateFromInt64( (sal_uIntPtr) this ); + aMsg += bPush ? ")::Push(" : ")::Pop("; + if ( rShell.GetInterface() ) + aMsg += rShell.GetInterface()->GetClassName(); + else + aMsg += ByteString::CreateFromInt64( (sal_uIntPtr) &rShell ); + aMsg += bDelete ? ") with delete" : ")"; + if ( bUntil ) aMsg += " (up to)"; + DbgTrace( aMsg.GetBuffer() ); +#endif + + // gleiche Shell wie on-Top des ToDo-Stacks? + if ( pImp->aToDoStack.Count() && pImp->aToDoStack.Top().pCluster == &rShell ) + { + // inverse Actions heben sich auf + 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 + { + // ::com::sun::star::chaos::Action merken + pImp->aToDoStack.Push( SfxToDo_Impl(bPush, bDelete, bUntil, rShell) ); + if ( bFlushed ) + { + DBG_TRACE("Unflushed dispatcher!"); + bFlushed = sal_False; + pImp->bUpdated = sal_False; + + // Bindings schlafen legen + SfxBindings* pBindings = GetBindings(); + if ( pBindings ) + pBindings->DENTERREGISTRATIONS(); + } + } + + if ( !pSfxApp->IsDowning() && pImp->aToDoStack.Count() ) + { + //! if (SFX_APP()->AnyInput(INPUT_KEYBOARD | INPUT_MOUSE) ) + //! AnyInput haut nicht hin; hier muss noch ein Kriterium gefunden + //! werden. Solange wieder immer mit Timer. + + if (sal_True) + { + // Kein sofortiges Update gewuenscht + pImp->aTimer.SetTimeout(SFX_FLUSH_TIMEOUT); + pImp->aTimer.SetTimeoutHdl( LINK(this, SfxDispatcher, EventHdl_Impl ) ); + pImp->aTimer.Start(); + } + else + { + // Schnellstmoegliches Update (sollte Normalfall sein) + pImp->aTimer.Stop(); + GetpApp()->PostUserEvent(pImp->nEventId, (void*)0); + } + } + else + { + // doch nichts zu tun + pImp->aTimer.Stop(); + + // ggf. Bindings wieder aufwecken + if ( !pImp->aToDoStack.Count() ) + { + SfxBindings* pBindings = GetBindings(); + if ( pBindings ) + pBindings->DLEAVEREGISTRATIONS(); + } + } +} + +//-------------------------------------------------------------------- + +IMPL_LINK_INLINE_START( SfxDispatcher, EventHdl_Impl, void *, pvoid ) + +/* [Beschreibung] + + Dieser Handler wird nach <SfxDispatcher::Invalidate()> oder Bewegungen + auf dem Stack (<SfxDispatcher::Push()> und <SfxDispatcher::Pop()) gerufen. + + Er flusht den Stack, falls er dirty ist, f"uhrt also die ausstehenden + Push und Pop Befehle tats"achlich aus. +*/ + +{ + (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 ) + +/* [Beschreibung] + + Mit dieser Methode kann gepr"uft werden, ob sich die <SfxShell> rShell + auf dem Stack befindet, wenn er geflusht w"are. Dabei wird der + SfxDispatcher jedoch nicht tats"achlich geflusht. + + Diese Methode ist u.a. dazu gedacht, Assertions zu erm"oglichen, ohne + als Seiteneffekt den SfxDispathcer flushen zu m"ussen. +*/ + +{ + 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 ) + +/* [Beschreibung] + + Ermittelt die Position einer SfxShell im Stack des Dispatchers. + Dazu wird dieser ggf. zuvor geflusht. + + + [Rueckgabewert] + + sal_uInt16 == USRT_MAX + Die SfxShell befindet sich nicht auf + diesem SfxDispatcher. + + < USHRT_MAX + Position der SfxShell auf dem Dispatcher + von oben mit 0 beginnend gez"ahlt. +*/ + +{ + 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 + +/* [Beschreibung] + + Liefert einen Pointer auf die <SfxShell>, welche sich an der Position + nIdx (von oben, letzt-gepushte liegt bei 0) auf dem Stack befindet. + + Dabei wird der SfxDispatcher nicht geflusht. + + Ist der Stack nicht tief genug, wird ein 0-Pointer zur"uckgegeben. +*/ + +{ + 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 + +/* [Beschreibung] + + Diese Methode liefert einen Pointer auf die <SfxBindings> Instanz + zur"uck, an die der SfxDispatcher gerade gebunden ist. Ein SfxDispatcher + ist nur dann an SfxBindings gebunden, wenn er <UI-aktiv> ist. Ist + er nicht UI-aktiv, wird ein 0-Pointer zur"uckgegeben. + + Der zur"uckgegebene Pointer ist nur im <unmittelbaren Kontext> des + Methodenaufrufs g"ultig. +*/ + +{ + if ( pImp->pFrame ) + return &pImp->pFrame->GetBindings(); + else + return NULL; +} + +//-------------------------------------------------------------------- +SfxViewFrame* SfxDispatcher::GetFrame() const + +/* [Beschreibung] + + Liefert einen Pointer auf die <SfxViewFrame> Instanz, der dieser + SfxDispatcher geh"ort. Falls es sich um den Applikations-Dispatcher + handelt, wird ein 0-Pointer zur"uckgegeben. +*/ + +{ + DBG_MEMTEST(); + return pImp->pFrame; +} + +//-------------------------------------------------------------------- +void SfxDispatcher::DoActivate_Impl( sal_Bool bMDI, SfxViewFrame* /* pOld */ ) + +/* [Beschreibung] + + Diese Methode steuert das Aktivieren eines Dispatchers. + + Da der Applikations-Dispatcher immer aktiv ist, entweder als + Unterdispatcher des <SfxViewFrame>-Dispatchers oder selbst, wird + er nie als ganzes Aktiviert, sondern nur seine einzelnen <SfxShell>s + bei <SfxDispatcher::Push(SfxShell&)>. + + Beim Aktivieren eines SfxDispatchers wird an allen auf seinem + Stack befindlichen SfxShells, beginnend mit der untersten, der Handler + <SfxShell::Activate(sal_Bool)> gerufen. +*/ + +{ + DBG_MEMTEST(); + SFX_STACK(SfxDispatcher::DoActivate); + if ( bMDI ) + { + #ifdef DBG_UTIL + ByteString sTemp("Activate Dispatcher "); + sTemp += ByteString::CreateFromInt64( (sal_uIntPtr) this ); + DBG_TRACE(sTemp.GetBuffer()); + DBG_ASSERT( !pImp->bActive, "Activate-Fehler" ); + #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 + ByteString sTemp("Non-MDI-Activate Dispatcher"); + sTemp += ByteString::CreateFromInt64( (sal_uIntPtr) this ); + DBG_TRACE( sTemp.GetBuffer() ); + #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 ) + { + //SfxWorkWindow *pWorkWin = pImp->pFrame->GetFrame().GetWorkWindow_Impl(); + SfxBindings *pBind = GetBindings(); + while ( pBind ) + { + pBind->HidePopupCtrls_Impl( FALSE ); + pBind = pBind->GetSubBindings_Impl(); + } + + pImp->pFrame->GetFrame().GetWorkWindow_Impl()->HidePopups_Impl( FALSE, FALSE, 1 ); + } + + if ( pImp->aToDoStack.Count() ) + { + if (sal_True) + { + // Kein sofortiges Update gewuenscht + pImp->aTimer.SetTimeout(SFX_FLUSH_TIMEOUT); + pImp->aTimer.SetTimeoutHdl( LINK(this, SfxDispatcher, EventHdl_Impl ) ); + pImp->aTimer.Start(); + } + else + { + // Schnellstmoegliches Update (sollte Normalfall sein) + pImp->aTimer.Stop(); + GetpApp()->PostUserEvent(pImp->nEventId, (void*)0); + } + } +} + +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 ) + +/* [Beschreibung] + + Diese Methode steuert das Deaktivieren eines Dispatchers. + + Da der Applikations-Dispatcher immer aktiv ist, entweder als + Unterdispatcher des <SfxViewFrame>-Dispatchers oder selbst, wird + er nie als ganzes Deaktiviert, sondern nur seine einzelnen <SfxShell>s + bei <SfxDispatcher::Pop(SfxShell&)>. + + Beim Deaktivieren eines SfxDispatchers wird an allen auf seinem + Stack befindlichen SfxShells, beginnend mit der obersten, der Handler + <SfxShell::Deactivate(sal_Bool)> gerufen. +*/ + +{ + DBG_MEMTEST(); + SFX_STACK(SfxDispatcher::DoDeactivate); + + SfxApplication *pSfxApp = SFX_APP(); + + if ( bMDI ) + { + DBG_TRACE(ByteString("Deactivate Dispatcher ").Append(ByteString::CreateFromInt64( (sal_uIntPtr) this )).GetBuffer()); + DBG_ASSERT( pImp->bActive, "Deactivate-Fehler" ); + pImp->bActive = sal_False; + + if ( pImp->pFrame && !(pImp->pFrame->GetObjectShell()->IsInPlaceActive() ) ) + { + SfxWorkWindow *pWorkWin = pImp->pFrame->GetFrame().GetWorkWindow_Impl(); + if ( pWorkWin ) + { + for (sal_uInt16 n=0; n<pImp->aChildWins.Count();) + { + SfxChildWindow *pWin = pWorkWin->GetChildWindow_Impl( (sal_uInt16) ( pImp->aChildWins[n] & 0xFFFF ) ); + if (!pWin || (pWin && pWin->GetAlignment() == SFX_ALIGN_NOALIGNMENT)) + pImp->aChildWins.Remove(n); + else + n++; + } + } + } + } + else { + DBG_TRACE( ByteString ("Non-MDI-DeActivate Dispatcher").Append(ByteString::CreateFromInt64( (sal_uIntPtr) this )).GetBuffer() ); + } + + if ( IsAppDispatcher() && !pSfxApp->IsDowning() ) + return; + + for ( sal_uInt16 i = 0; i < pImp->aStack.Count(); ++i ) + pImp->aStack.Top(i)->DoDeactivate_Impl(pImp->pFrame, bMDI); + + 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 = FALSE; + } + + if ( bHidePopups ) + { + //SfxWorkWindow *pWorkWin = pImp->pFrame->GetFrame().GetWorkWindow_Impl(); + SfxBindings *pBind = GetBindings(); + while ( pBind ) + { + pBind->HidePopupCtrls_Impl( TRUE ); + pBind = pBind->GetSubBindings_Impl(); + } + + pImp->pFrame->GetFrame().GetWorkWindow_Impl()->HidePopups_Impl( TRUE, 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, // die zu suchende Slot-Id + SfxShell** ppShell, // die SfxShell, welche nSlot z.Zt. bedient + const SfxSlot** ppSlot, // der SfxSlot, welcher nSlot z.Zt. bedient + sal_Bool bOwnShellsOnly, + sal_Bool bModal, // trotz ModalMode + sal_Bool bRealSlot +) + +/* [Beschreibung] + + Diese Methode sucht im SfxDispatcher nach der <SfxShell>, von der + die Slot-Id nSlot zur Zeit bedient wird. Dazu wird der Dispatcher + zuvor geflusht. + + + [R"uckgabewert] + + int sal_True + Die SfxShell wurde gefunden, ppShell und ppSlot + sind g"ultig. + + sal_True + Die SfxShell wurde nicht gefunden, ppShell und ppSlot + sind ung"ultig. +*/ + +{ + 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; + +#ifdef DBG_UTILx + ByteString aMsg( nSlot ); + aMsg += " found in "; + aMsg += (*ppShell)->GetInterface()->GetClassName(); + DbgTrace( aMsg.GetBuffer() ); +#endif + + return sal_True; + } + +#ifdef DBG_UTILx + ByteString aMsg( nSlot ); + aMsg += " not found"; + DbgTrace( aMsg.GetBuffer() ); +#endif + + return sal_False; +} + +/* +struct Executer : public SfxHint +{ + SfxRequest *pRequest; + const SfxSlot* pSlot; + sal_uInt16 nLevel; + + Executer( SfxRequest* pReq, const SfxSlot* p, sal_uInt16 n ) + : pRequest( pReq ) + , pSlot(p) + , nLevel(n) + {} + ~Executer() + {delete pRequest;} +}; +*/ + +//-------------------------------------------------------------------- +void SfxDispatcher::_Execute +( + SfxShell& rShell, // zu rufende <SfxShell> + const SfxSlot& rSlot, // zu rufender <SfxSlot> + SfxRequest& rReq, // auszuf"uhrende Funktion (Id und optional Parameter) + SfxCallMode eCallMode // synchron, asynchron oder wie beim Slot angegeben +) + +/* [Beschreibung] + + Diese Methode f"uhrt einen Request "uber einen gecachten <Slot-Server> + aus. +*/ + +{ + 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( TRUE ); + pDispat->pImp->xPoster->Post(new SfxRequest(rReq)); +// pDispat->pImp->xPoster->Post(new Executer(new SfxRequest(rReq), &rSlot, n )); + 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 ) + +/* [Beschreibung] + + Hilfsfunktion zum putten von rItem unter der im Pool des Item-Sets + rSet geltenden Which-Id. +*/ + +{ + // mit ggf. gemappter Which-Id putten + const SfxItemPool *pPool = rSet.GetPool(); + sal_uInt16 nWhich = rItem.Which(); +#ifdef TF_POOLABLE + if ( pPool->IsSlot(nWhich) ) +#else + if ( pPool->HasMap() && pPool->IsSlot(nWhich) ) +#endif + 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; + + // via Bindings/Interceptor? (dann ist der Returnwert nicht exakt) + 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; + + // sonst via 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 ) ) + { + // Ausf"uhrbarkeit vorher testen + 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; + sal_Bool bDone = sal_False; + 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 ); + bDone = aReq.IsDone(); + } + else + { + SfxRequest aReq( nSlot, eCall, pShell->GetPool() ); + _Execute( *pShell, *pSlot, aReq, eCall ); + bDone = aReq.IsDone(); + } + } + + return nRet; +} + +sal_uInt16 SfxDispatcher::ExecuteFunction( sal_uInt16 nSlot, const SfxItemSet& rArgs, + sal_uInt16 nMode ) +{ + if ( !nMode ) + nMode = pImp->nStandardMode; + +/* + // at the moment not implemented + // via Bindings/Interceptor? (dann ist der Returnwert nicht exakt) + sal_Bool bViaBindings = SFX_USE_BINDINGS == ( nMode & SFX_USE_BINDINGS ); + nMode &= ~sal_uInt16(SFX_USE_BINDINGS); + if ( bViaBindings && GetBindings() ) + return GetBindings()->Execute( nSlot, rArgs, nMode ) + ? EXECUTE_POSSIBLE + : EXECUTE_NO; +*/ + // sonst via 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 ) ) + { + // Ausf"uhrbarkeit vorher testen + 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; + sal_Bool bDone = sal_False; + SfxRequest aReq( nSlot, eCall, rArgs ); + _Execute( *pShell, *pSlot, aReq, eCall ); + bDone = aReq.IsDone(); + } + + return nRet; +} + +sal_uInt16 SfxDispatcher::GetSlotId( const String& rCommand ) +{ + const SfxSlot *pSlot = GetSlot( rCommand ); + if ( pSlot ) + return pSlot->GetSlotId(); + return 0; +} + +const SfxSlot* SfxDispatcher::GetSlot( const String& rCommand ) +{ + // Anzahl der Shells auf den verkettenten Dispatchern z"ahlen + 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; +} + +//-------------------------------------------------------------------- +int SfxExecuteItem::operator==( const SfxPoolItem& rItem ) const +{ + SfxExecuteItem& rArg = (SfxExecuteItem& )rItem; + sal_uInt16 nCount = Count(); + if( nCount != rArg.Count() ) + return sal_False; + while( nCount -- ) + if( *GetObject( nCount ) != *rArg.GetObject( nCount ) ) + return sal_False; + return eCall == rArg.eCall; +} + +//-------------------------------------------------------------------- +SfxPoolItem* SfxExecuteItem::Clone( SfxItemPool* ) const +{ + return new SfxExecuteItem( *this ); +} + +//-------------------------------------------------------------------- +SfxExecuteItem::SfxExecuteItem( const SfxExecuteItem& rArg ) + : SfxItemPtrArray(), SfxPoolItem( rArg ), nModifier( 0 ) +{ + eCall = rArg.eCall; + nSlot = rArg.nSlot; + sal_uInt16 nCount = rArg.Count(); + for( sal_uInt16 nPos = 0; nPos < nCount; nPos++ ) + Insert( rArg[ nPos ]->Clone(), nPos ); +} + +//-------------------------------------------------------------------- +SfxExecuteItem::SfxExecuteItem( + sal_uInt16 nWhichId, sal_uInt16 nSlotP, SfxCallMode eModeP, + const SfxPoolItem* pArg1, ... ) : + SfxPoolItem( nWhichId ), nSlot( nSlotP ), eCall( eModeP ), nModifier( 0 ) +{ + va_list pVarArgs; + va_start( pVarArgs, pArg1 ); + for ( const SfxPoolItem *pArg = pArg1; pArg; + pArg = va_arg( pVarArgs, const SfxPoolItem* ) ) + Insert( pArg->Clone(), Count() ); + va_end(pVarArgs); +} + +//-------------------------------------------------------------------- +SfxExecuteItem::SfxExecuteItem( + sal_uInt16 nWhichId, sal_uInt16 nSlotP, SfxCallMode eModeP ) + : SfxPoolItem( nWhichId ), nSlot( nSlotP ), eCall( eModeP ), nModifier( 0 ) +{ +} + +//-------------------------------------------------------------------- +const SfxPoolItem* SfxDispatcher::Execute( const SfxExecuteItem& rItem ) +{ + const SfxPoolItem** pPtr = new const SfxPoolItem*[ rItem.Count() + 1 ]; + for( sal_uInt16 nPos = rItem.Count(); nPos--; ) + pPtr[ nPos ] = rItem.GetObject( nPos ); + pPtr[ rItem.Count() ] = 0; + const SfxPoolItem* pRet = Execute( + rItem.GetSlot(), rItem.GetCallMode(), pPtr, rItem.GetModifier() ); + + delete [] (SfxPoolItem**)pPtr; + + return pRet; +} + +//-------------------------------------------------------------------- +const SfxPoolItem* SfxDispatcher::Execute( + USHORT nSlot, + SfxCallMode nCall, + SfxItemSet* pArgs, + SfxItemSet* pInternalArgs, + USHORT 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, // die Id der auszufuehrenden Funktion + SfxCallMode eCall, // SFX_CALLMODE_SYNCRHON, ..._ASYNCHRON oder ..._SLOT + const SfxPoolItem **pArgs, // 0-terminiertes C-Array von Parametern + sal_uInt16 nModi, + const SfxPoolItem **pInternalArgs // 0-terminiertes C-Array von Parametern +) + +/* [Beschreibung] + + Methode zum Ausf"uhren eines <SfxSlot>s "uber die Slot-Id. + + + [R"uckgabewert] + + const SfxPoolItem* Pointer auf ein bis zum n"achsten Durchlauf + der Message-Loop g"ultiges SfxPoolItem, + welches den R"uckgabewert enth"alt. + + Oder ein 0-Pointer, wenn die Funktion nicht + ausgef"uhrt wurde (z.B. Abbruch durch den + Benutzer). +*/ + +{ + 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, // die Id der auszufuehrenden Funktion + SfxCallMode eCall, // SFX_CALLMODE_SYNCRHON, ..._ASYNCHRON oder ..._SLOT + const SfxItemSet &rArgs // <SfxItemSet> mit Parametern +) + +/* [Beschreibung] + + Methode zum Ausf"uhren eines <SfxSlot>s "uber die Slot-Id. + + + [R"uckgabewert] + + const SfxPoolItem* Pointer auf ein bis zum n"achsten Durchlauf + der Message-Loop g"ultiges SfxPoolItem, + welches den R"uckgabewert enth"alt. + + Oder ein 0-Pointer, wenn die Funktion nicht + ausgef"uhrt wurde (z.B. Abbruch durch den + Benutzer). +*/ + +{ + return Execute( nSlot, eCall, 0, rArgs ); +} + +//-------------------------------------------------------------------- +const SfxPoolItem* SfxDispatcher::Execute +( + USHORT nSlot, + SfxCallMode eCall, + USHORT 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, // die Id der auszufuehrenden Funktion + SfxCallMode eCall, // SFX_CALLMODE_SYNCRHON, ..._ASYNCHRON oder ..._SLOT + va_list pVarArgs, // Parameterliste ab 2. Parameter + const SfxPoolItem* pArg1 // erster Parameter +) + +/* [Beschreibung] + + Methode zum Ausf"uhren eines <SfxSlot>s "uber die Slot-Id. + + + [R"uckgabewert] + + const SfxPoolItem* Pointer auf ein bis zum n"achsten Durchlauf + der Message-Loop g"ultiges SfxPoolItem, + welches den R"uckgabewert enth"alt. + + Oder ein 0-Pointer, wenn die Funktion nicht + ausgef"uhrt wurde (z.B. Abbruch durch den + Benutzer). +*/ + +{ + 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() ); + + for ( const SfxPoolItem *pArg = pArg1; + pArg; + pArg = va_arg( pVarArgs, const SfxPoolItem* ) ) + MappedPut_Impl( aSet, *pArg ); + + SfxRequest aReq( nSlot, eCall, aSet ); + _Execute( *pShell, *pSlot, aReq, eCall ); + return aReq.GetReturnValue(); + } + return 0; +} + +//-------------------------------------------------------------------- +const SfxPoolItem* SfxDispatcher::Execute +( + sal_uInt16 nSlot, // die Id der auszufuehrenden Funktion + SfxCallMode eCall, // SFX_CALLMODE_SYNCRHON, ..._ASYNCHRON oder ..._SLOT + const SfxPoolItem* pArg1, // erster Parameter + ... // 0-terminiertes Liste Parametern +) + +/* [Beschreibung] + + Methode zum Ausf"uhren eines <SfxSlot>s "uber die Slot-Id. + + + [Anmerkung] + + Die Parameter werden kopiert, k"onnen daher als Adresse von + Stack-Objekten "ubergeben werden. + + + [R"uckgabewert] + + const SfxPoolItem* Pointer auf ein bis zum n"achsten Durchlauf + der Message-Loop g"ultiges SfxPoolItem, + welches den R"uckgabewert enth"alt. + + Oder ein 0-Pointer, wenn die Funktion nicht + ausgef"uhrt wurde (z.B. Abbruch durch den + Benutzer). + + + [Beispiel] + + 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 ) + +/* [Beschreibung] + + Hilfsmethode zum Empfangen der asynchron auszuf"uhrenden <SfxRequest>s. +*/ + +{ + DBG_MEMTEST(); + DBG_ASSERT( !pImp->bFlushing, "recursive call to dispatcher" ); + SFX_STACK(SfxDispatcher::PostMsgHandler); + + // ist auch der Pool noch nicht gestorben? +// SfxRequest* pReq = pExec->pRequest; + if ( !pReq->IsCancelled() ) + { + if ( !IsLocked(pReq->GetSlot()) ) + { + Flush(); + SfxSlotServer aSvr; + if ( _FindServer(pReq->GetSlot(), aSvr, HACK(x) sal_True ) ) +// SfxShell *pShell = GetShell(pExec->nLevel); +// if ( pShell && pShell->GetInterface()->GetSlot( pExec->pSlot->GetSlotId() ) ) + { + const SfxSlot *pSlot = aSvr.GetSlot(); + SfxShell *pSh = GetShell(aSvr.GetShellLevel()); + + DBG( SfxApplication *pSfxApp = SFX_APP() ); + DBG( pSfxApp->EnterAsynchronCall_Impl() ); + + // Wenn pSlot ein "Pseudoslot" f"ur Macros oder Verben ist, kann + // er im Call_Impl zerst"ort werden, also nicht mehr benutzen! + pReq->SetSynchronCall( sal_False ); + Call_Impl( *pSh, *pSlot, *pReq, pReq->AllowsRecording() ); //! woher bRecord? +// Call_Impl( *pShell, *pExec->pSlot, *pReq, sal_True ); //! woher bRecord? + DBG( pSfxApp->LeaveAsynchronCall_Impl() ); + } + +// delete pExec; + } + else + { +// pImp->xPoster->Post(pExec); + if ( pImp->bLocked ) + pImp->aReqArr.Insert( new SfxRequest(*pReq), pImp->aReqArr.Count() ); + else + pImp->xPoster->Post(new SfxRequest(*pReq)); + } + } +// else +// delete pExec; + + 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.Remove(0, pImp->aChildWins.Count()); + + // 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 wether 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) + { + 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 ); + 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.Insert( nId, pImp->aChildWins.Count()); + } + + 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() + +/* [Beschreibung] + + Hilfsmethode zum Ausf"uhren der ausstehenden Push- und Pop-Befehle. +*/ + +{ + DBG_PROFSTART(SfxDispatcherFlush); + DBG_MEMTEST(); + SFX_STACK(SfxDispatcher::FlushImpl); + + DBG_TRACE("Flushing dispatcher!"); + +#ifdef DBG_UTIL + ByteString aMsg( "SfxDispatcher(" ); + aMsg += ByteString::CreateFromInt64( (sal_uIntPtr) this ); + aMsg += ")::Flush()"; +#endif + + pImp->aTimer.Stop(); + + if ( pImp->pParent ) + pImp->pParent->Flush(); + +// if ( pImp->bQuiet ) +// return; + + pImp->bFlushing = !pImp->bFlushing; + if ( !pImp->bFlushing ) + { + pImp->bFlushing = sal_True; + DBG_PROFSTOP(SfxDispatcherFlush); +//! +#ifdef DBG_UTIL_MESSEHACK_AUSKOMMENT + DBG_ERROR( "reentering SfxDispatcher::Flush()" ); + aMsg += " reentering, aborted"; + DbgTrace( aMsg.GetBuffer() ); +#endif + return; + } + + SfxApplication *pSfxApp = SFX_APP(); + + // in der 1. Runde den echten Stack 'um'bauen + 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 ) + { + // tats"aechlich pushen + DBG_ASSERT( !pImp->aStack.Contains( aToDo.pCluster ), + "pushed SfxShell already on stack" ); + pImp->aStack.Push( aToDo.pCluster ); + aToDo.pCluster->SetDisableFlags( pImp->nDisableFlags ); + + // die bewegte Shell merken + aToDoCopy.Push( aToDo ); + } + else + { + // tats"aechlich poppen + SfxShell* pPopped = 0; + FASTBOOL bFound = sal_False; + do + { + DBG_ASSERT( pImp->aStack.Count(), "popping from empty stack" ); + pPopped = pImp->aStack.Pop(); + pPopped->SetDisableFlags( 0 ); + bFound = pPopped == aToDo.pCluster; + + // die bewegte Shell merken + 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(); + } + + // ggf. Bindings invalidieren + if ( !pSfxApp->IsDowning() ) + { + if ( bModify ) + { + pImp->pCachedServ1 = 0; + pImp->pCachedServ2 = 0; + } + + InvalidateBindings_Impl( bModify ); + } + + pImp->bFlushing = sal_False; + pImp->bUpdated = sal_False; // nicht nur bei bModify, falls Doc/Template-Config + bFlushed = sal_True; + DBG_TRACE("Successfully flushed dispatcher!"); + + // in der 2. Runde die Shells aktivieren und ggf. l"oschen + 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(); + + // Wenn bei Activate/Deactivate/Delete weitere Stackbewegungen erfolgt sind : + if (!bFlushed) + // falls jemand Push/Pop gerufen hat, wurde auch EnterReg gerufen! + FlushImpl(); + + if( bAwakeBindings && GetBindings() ) + GetBindings()->DLEAVEREGISTRATIONS(); + DBG_PROFSTOP(SfxDispatcherFlush); + + for (sal_uInt16 n=0; n<SFX_OBJECTBAR_MAX; n++) + pImp->aFixedObjBars[n].nResId = 0; + +#ifdef DBG_UTIL + aMsg += " done"; + DbgTrace( aMsg.GetBuffer() ); +#endif +} + +//-------------------------------------------------------------------- +void SfxDispatcher::SetSlotFilter +( + HACK(hier muss mal ein enum rein) + sal_Bool bEnable, /* sal_True: + nur angegebene Slots enablen, + alle anderen disablen + + sal_False: + die angegebenen Slots disablen, + alle anderen zun"achst enablen + */ + sal_uInt16 nCount, // Anzahl der SIDs im folgenden Array + const sal_uInt16* pSIDs // sortiertes Array von 'nCount' SIDs +) + +/* [Beschreibung] + + Mit dieser Methode wird ein Filter gesetzt, mit dem gezielt Slots + enabled bzw. disabled werden k"onnen. Das "ubergebene Array mu\s + bis zum Dtor bzw. n"achsten <SetSlotFilter()> erhalten bleiben, es + wird nicht vom Dispatcher gel"oscht, es kann daher static sein. + + In ReadOnly-Dokumenten kann man mit 'bEnable==2' quasi das ReadOnlyDoc + Flag von Slots "ubersteuern, dieser werden also wieder gefunden. Auf + andere Slots hat das dann keine Auswirkung. + + + [Beispiel] + + gezieltes disablen der Slots 1, 2 und 3: + + static sal_uInt16 __READONLY_DATA pSIDs[] = { 1, 2, 3 }; + pDisp->SetSlotFilter( sal_False, sizeof(pSIDs)/sizeof(sal_uInt16), pSIDs ); + + nur die Slots 5, 6 und 7 zulassen: + + static sal_uInt16 __READONLY_DATA pSIDs[] = { 5, 6, 7 }; + pDisp->SetSlotFilter( sal_True, sizeof(pSIDs)/sizeof(sal_uInt16), pSIDs ); + + Filter ausschalten: + + pDisp->SetSlotFilter(); +*/ + +{ +#ifdef DBG_UTIL + // Array "uberpr"ufen + for ( sal_uInt16 n = 1; n < nCount; ++n ) + DBG_ASSERT( pSIDs[n] > pSIDs[n-1], "SetSlotFilter: SIDs not sortet" ); +#endif + + if ( pImp->pFilterSIDs ) + pImp->pFilterSIDs = 0; + + pImp->bFilterEnabling = bEnable; + pImp->nFilterCount = nCount; + pImp->pFilterSIDs = pSIDs; + + GetBindings()->InvalidateAll(sal_True); +} + +//-------------------------------------------------------------------- +EXTERN_C +#if defined( PM2 ) && (!defined( CSET ) && !defined ( MTW ) && !defined( WTC )) +int _stdcall +#else +#ifdef WNT +int _cdecl +#else +int +#endif +#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 + +/* [Beschreibung] + + Sucht 'nSID' in dem mit <SetSlotFilter()> gesetzten Filter und + liefert sal_True, falls die SID erlaubt ist, bzw. sal_False, falls sie + durch den Filter disabled ist. + + [R"uckgabewert] + sal_Bool 0 => disabled + 1 => enabled + 2 => enabled even if ReadOnlyDoc +*/ + +{ + // kein Filter? + if ( 0 == pImp->nFilterCount ) + // => alle SIDs erlaubt + return sal_True; + + // suchen + 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; + // sonst je nach Negativ/Positiv Filter + return pImp->bFilterEnabling ? bFound : !bFound; +} + +//-------------------------------------------------------------------- +sal_Bool SfxDispatcher::_TryIntercept_Impl +( + sal_uInt16 nSlot, // zu suchende Slot-Id + SfxSlotServer& rServer, // zu f"uellende <SfxSlotServer>-Instanz + sal_Bool bSelf +) +{ + // Eventuell geh"ort der parent auch zu einer Komponente + SfxDispatcher *pParent = pImp->pParent; + sal_uInt16 nLevels = pImp->aStack.Count(); + while ( pParent && pParent->pImp->pFrame ) + { + if ( pParent->pImp->pFrame->GetFrame().HasComponent() ) + { + // Components d"urfen intercepten + if ( pParent->_TryIntercept_Impl( nSlot, rServer, sal_True ) ) + { + // Die eigenen Shells zum Shelllevel hinzuz"ahlen + rServer.SetShellLevel( rServer.GetShellLevel() + nLevels ); + return sal_True; + } + else + // Keine weitere Interception + break; + } + else + nLevels = nLevels + pParent->pImp->aStack.Count(); + + pParent = pParent->pImp->pParent; + } + + if ( bSelf ) + { + // Die ComponentViewShell befragen + Flush(); + SfxShell *pObjShell = GetShell(0); + SfxInterface *pIFace = pObjShell->GetInterface(); + const SfxSlot *pSlot = pIFace->GetSlot(nSlot); + + if ( pSlot ) + { + rServer.SetSlot(pSlot); + rServer.SetShellLevel(0); +#ifdef DBG_UTILx + String aMsg( nSlot ); + aMsg += " intercepted"; + DbgTrace( aMsg.GetBuffer() ); +#endif + return sal_True; + } + } + + return sal_False; +} + +sal_Bool SfxDispatcher::_FindServer +( + sal_uInt16 nSlot, // zu suchende Slot-Id + SfxSlotServer& rServer, // zu f"uellnde <SfxSlotServer>-Instanz + sal_Bool bModal // trotz ModalMode +) + +/* [Beschreibung] + + Diese Hilfsmethode sucht den <Slot-Server>, der nSlot zur Zeit bedient. + Als Ergebnis wird rServer entsprechend gef"ullt. + + Falls bekannt, kann das SfxInterface mitgegeben werden, von welchem + nSlot momentan bedient wird. + + Vor der Suche nach nSlot wird der SfxDispatcher geflusht. + + + [R"uckgabewert] + + sal_Bool sal_True + Der Slot wurde gefunden, rServer ist g"ultig. + + sal_False + Der Slot wird momentan nicht bedient, rServer + ist ung"ultig. +*/ + +{ + SFX_STACK(SfxDispatcher::_FindServer); + + // Dispatcher gelockt? (SID_HELP_PI trotzdem durchlassen) + if ( IsLocked(nSlot) ) + { + pImp->bInvalidateOnUnlock = sal_True; + return sal_False; + } + + // Anzahl der Shells auf den verkettenten Dispatchern z"ahlen + 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 gegen gesetzten Filter pr"ufen + sal_uInt16 nSlotEnableMode=0; + if ( pImp->pFrame ) + { + nSlotEnableMode = IsSlotEnabledByFilter_Impl( nSlot ); + if ( 0 == nSlotEnableMode ) + return sal_False; + } + + // im Quiet-Mode nur 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 ); +// ( pImp->pFrame && pImp->pFrame->GetObjectShell() ); +// pImp->pFrame->GetObjectShell()->IsLoading() ); + + // durch alle Shells der verketteten Dispatchern von oben nach unten suchen +#ifdef DBG_UTILx + String aStack( "Stack:" ); +#endif + 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 geh"ort zum Container? + FASTBOOL bIsContainerSlot = pSlot->IsMode(SFX_SLOT_CONTAINER); + FASTBOOL bIsInPlace = pImp->pFrame && pImp->pFrame->GetObjectShell()->IsInPlaceActive(); + + // Shell geh"ort zum Server? + // AppDispatcher oder IPFrame-Dispatcher + FASTBOOL bIsServerShell = !pImp->pFrame || bIsInPlace; + + // Nat"urlich sind ServerShell-Slots auch ausf"uhrbar, wenn sie auf + // einem Container-Dispatcher ohne IPClient ausgef"uhrt werden sollen. + if ( !bIsServerShell ) + { + SfxViewShell *pViewSh = pImp->pFrame->GetViewShell(); + bIsServerShell = !pViewSh || !pViewSh->GetUIActiveClient(); + } + + // Shell geh"ort zum Container? + // AppDispatcher oder kein IPFrameDispatcher + FASTBOOL bIsContainerShell = !pImp->pFrame || !bIsInPlace; + // Shell und Slot passen zusammen + if ( !( ( bIsContainerSlot && bIsContainerShell ) || + ( !bIsContainerSlot && bIsServerShell ) ) ) + pSlot = 0; + } + +#ifdef DBG_UTILx + if ( pSlot ) + { + String aMsg( nSlot ); + aMsg += " found in "; + aMsg += pObjShell->GetInterface()->GetClassName(); + DbgTrace( aMsg.GetBuffer() ); + } + else + { + aStack += " "; + aStack += pObjShell->GetInterface()->GetClassName(); + } +#endif + if ( pSlot && !IsAllowed( nSlot ) ) + { + pSlot = NULL; + } + + if ( pSlot ) + { + rServer.SetSlot(pSlot); + rServer.SetShellLevel(i); + return sal_True; + } + } + +#ifdef DBG_UTILx + String aMsg( nSlot ); + aMsg += " not found in "; + aMsg += aStack; + DbgTrace( aMsg.GetBuffer() ); +#endif + return sal_False; +} + +sal_Bool SfxDispatcher::HasSlot_Impl( sal_uInt16 nSlot ) +{ + Flush(); + sal_uInt16 nTotCount = pImp->aStack.Count(); + + if ( pImp->pParent && !pImp->pParent->pImp->pFrame ) + { + // the last frame also uses the AppDispatcher + nTotCount = nTotCount + pImp->aStack.Count(); + } + + if (nSlot >= SID_VERB_START && nSlot <= SID_VERB_END) + { + // Verb-Slot? + for ( sal_uInt16 nShell = 0;; ++nShell ) + { + SfxShell *pSh = GetShell(nShell); + if ( pSh == NULL ) + return false; + if ( pSh->ISA(SfxViewShell) ) + return true; + } + } + + // SID gegen gesetzten Filter pr"ufen + sal_uInt16 nSlotEnableMode=0; + if ( pImp->pFrame ) + { + nSlotEnableMode = IsSlotEnabledByFilter_Impl( nSlot ); + if ( 0 == nSlotEnableMode ) + return sal_False; + } + + // im Quiet-Mode nur Parent-Dispatcher + if ( pImp->bQuiet ) + return sal_False; + + sal_Bool bReadOnly = ( 2 != nSlotEnableMode && pImp->bReadOnly ); +// ( pImp->pFrame && pImp->pFrame->GetObjectShell()); +// pImp->pFrame->GetObjectShell()->IsLoading() ); + + for ( sal_uInt16 i=0 ; 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 geh"ort zum Container? + FASTBOOL bIsContainerSlot = pSlot->IsMode(SFX_SLOT_CONTAINER); + FASTBOOL bIsInPlace = pImp->pFrame && pImp->pFrame->GetObjectShell()->IsInPlaceActive(); + + // Shell geh"ort zum Server? + // AppDispatcher oder IPFrame-Dispatcher + FASTBOOL bIsServerShell = !pImp->pFrame || bIsInPlace; + + // Nat"urlich sind ServerShell-Slots auch ausf"uhrbar, wenn sie auf + // einem Container-Dispatcher ohne IPClient ausgef"uhrt werden sollen. + if ( !bIsServerShell ) + { + SfxViewShell *pViewSh = pImp->pFrame->GetViewShell(); + bIsServerShell = !pViewSh || !pViewSh->GetUIActiveClient(); + } + + // Shell geh"ort zum Container? + // AppDispatcher oder kein IPFrameDispatcher + FASTBOOL bIsContainerShell = !pImp->pFrame || !bIsInPlace; + + // Shell und Slot passen zusammen + if ( !( ( bIsContainerSlot && bIsContainerShell ) || + ( !bIsContainerSlot && bIsServerShell ) ) ) + pSlot = 0; + } + + if ( pSlot && !IsAllowed( nSlot ) ) + pSlot = NULL; + + if ( pSlot ) + return sal_True; + } + + return sal_False; +} + + + +//-------------------------------------------------------------------- +sal_Bool SfxDispatcher::_FillState +( + const SfxSlotServer& rSvr, // abzufragende <Slot-Server> + SfxItemSet& rState, // zu f"ullendes <SfxItemSet> + const SfxSlot* pRealSlot // ggf. der tats"achliche Slot +) + +/* [Beschreibung] + + Hilfsmethode zum Abfragen des Status des <Slot-Server>s rSvr. + In rState m"ussen die gew"unschten Slots-Ids (teilweise in Which-Ids + des betreffenden Pools umgewandelt) vorhanden sein. + + Der SfxDispatcher wird vor der Abfrage geflusht. +*/ + +{ + 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 FALSE; + // Flush(); + + // Objekt ermitteln und Message an diesem Objekt aufrufen + SfxShell *pSh = GetShell(rSvr.GetShellLevel()); + DBG_ASSERT(pSh, "ObjektShell nicht gefunden"); + + SfxStateFunc pFunc; + + if (pRealSlot) + pFunc = pRealSlot->GetStateFnc(); + else + pFunc = pSlot->GetStateFnc(); + + pSh->CallState( pFunc, rState ); +#ifdef DBG_UTIL + // pr"ufen, ob IDL (SlotMap) und aktuelle Items "ubereinstimmen + 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()) ) + { + ByteString aMsg( "item-type unequal to IDL (=> no BASIC)" ); + aMsg += "\nwith SID: "; + aMsg += ByteString::CreateFromInt32( nSlotId ); + aMsg += "\nin "; + aMsg += pIF->GetClassName(); + DbgOut( aMsg.GetBuffer(), DBG_OUT_ERROR, __FILE__, __LINE__); + } + } + } +#endif + + DBG_PROFSTOP(SfxDispatcherFillState); + return sal_True; + } + + DBG_PROFSTOP(SfxDispatcherFillState); + return sal_False; +} + +//-------------------------------------------------------------------- +const SfxPoolItem* SfxDispatcher::_Execute( const SfxSlotServer &rSvr ) + +/* [Beschreibung] + + Diese Methode f"uhrt einen Request "uber einen gecachten <Slot-Server> + aus. +*/ + +{ + const SfxSlot *pSlot = rSvr.GetSlot(); + if ( IsLocked( pSlot->GetSlotId() ) ) + return 0; + + if ( pSlot ) + { + Flush(); + + if ( pSlot->IsMode(SFX_SLOT_ASYNCHRON) ) + //! ignoriert rSvr + { + SfxShell *pShell = GetShell( rSvr.GetShellLevel() ); + SfxDispatcher *pDispat = this; + while ( pDispat ) + { + sal_uInt16 nShellCount = pDispat->pImp->aStack.Count(); + for ( sal_uInt16 n=0; n<nShellCount; n++ ) + if ( pShell == pDispat->pImp->aStack.Top(n) ) + { + pDispat->pImp->xPoster->Post( + new SfxRequest( pSlot->GetSlotId(), + SFX_CALLMODE_RECORD, pShell->GetPool() ) ); +// pDispat->pImp->xPoster->Post(new Executer( +// new SfxRequest( pSlot->GetSlotId(), +// SFX_CALLMODE_RECORD, pShell->GetPool() ), +// pSlot, n )); + return 0; + } + } + } + else + { + // Objekt ermitteln und Message an diesem Objekt aufrufen + SfxShell *pSh = GetShell(rSvr.GetShellLevel()); + SfxRequest aReq( pSlot->GetSlotId(), SFX_CALLMODE_RECORD, pSh->GetPool() ); + if ( Call_Impl( *pSh, *pSlot, aReq, sal_True ) ) // von Bindings immer recorden + return aReq.GetReturnValue(); + } + } + return 0; +} + +//---------------------------------------------------------------------- +void SfxDispatcher::ExecutePopup( sal_uInt16 nConfigId, + Window *pWin, const Point *pPos, + const SfxPoolItem *, ... ) +{ + ExecutePopup( nConfigId, pWin, pPos ); +} + +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; +/* + const SvVerbList *pVerbList = 0; + sal_uInt16 nMaxShellLevel = rDisp.pImp->aStack.Count(); + for ( pSh = rDisp.GetShell(nShLevel); + pSh && nShLevel < nMaxShellLevel ; + ++nShLevel, pSh = rDisp.GetShell(nShLevel) ) + { + if ( pSh->GetVerbs() ) + { + pVerbList = pSh->GetVerbs(); + break; + } + } +*/ + 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 aPop( rResId.GetId(), *rDisp.GetBindings() ); + //aPop.SetResMgr(rResId.GetResMgr()); + //aPop.AddClipboardFunctions(); + //aPop.Initialize(); + //if ( pVerbList && pVerbList->Count() ) + // aPop.InsertVerbs(pVerbList); + //aPop.RemoveDisabledEntries(); + //aPop.Execute( pPos ? *pPos : pWindow->GetPointerPosPixel(), pWindow ); + 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 aPop( rId, *GetBindings() ); + aPop.AddClipboardFunctions(); + aPop.Initialize(); + aPop.RemoveDisabledEntries(); + aPop.Execute( pPos ? *pPos : pWindow->GetPointerPosPixel(), pWindow ); +*/ + SfxPopupMenuManager::ExecutePopup( rId, GetFrame(), pPos ? *pPos : pWindow->GetPointerPosPixel(), pWindow ); +} + +//-------------------------------------------------------------------- +void SfxDispatcher::Lock( sal_Bool bLock ) + +/* [Beschreibung] + + Mit dieser Methode kann der SfxDispatcher gesperrt und freigegeben + werden. Ein gesperrter SfxDispatcher f"uhrt keine <SfxRequest>s mehr + aus und liefert keine Status-Informationen mehr. Er verh"alt sich + so als w"aren alle Slots 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 ) + { + USHORT nCount = pImp->aReqArr.Count(); + for ( USHORT 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::ResetObjectBars_Impl() + +/* [Beschreibung] + + Mit dieser Methode werden alle Objectbar-Anforderungen, die dieser + Dispatcher an das AppWindow hat, beseitigt. +*/ +{ + for (sal_uInt16 n=0; n<SFX_OBJECTBAR_MAX; n++) + pImp->aObjBars[n].nResId = 0; + pImp->aChildWins.Remove(0, pImp->aChildWins.Count()); +} + + +//-------------------------------------------------------------------- +void SfxDispatcher::DebugOutput_Impl() const +{ +#ifdef DBG_UTIL + + sal_uInt16 nOld = (sal_uInt16) DbgGetData()->nTraceOut; + DbgGetData()->nTraceOut = DBG_OUT_FILE; + + if (bFlushed) + DBG_TRACE("Flushed"); + if (pImp->bUpdated) + DBG_TRACE("Updated"); + + for ( sal_uInt16 nShell = pImp->aStack.Count(); nShell > 0; --nShell ) + { + SfxShell *pShell = GetShell(nShell-1); + const SfxInterface *pIFace = pShell->GetInterface(); + DBG_TRACE (pIFace->GetClassName()); + } + + DbgGetData()->nTraceOut = nOld; + +#endif +} + +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 ) +{ +// if ( !bHide && pImp->bReadOnly ) +// bHide = sal_True; + 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; +// pImp->bNoUI = bOn; +} + +sal_Bool SfxDispatcher::GetReadOnly_Impl() const +{ + return pImp->bReadOnly; +} + +//------------------------------------------------------------------------- +void SfxDispatcher::SetQuietMode_Impl( sal_Bool bOn ) + +/* [Beschreibung] + + Bei 'bOn' stellt sich dieser Dispatcher quasi tot und leitet alles + an den Parent-Dispatcher weiter. +*/ + +{ + pImp->bQuiet = bOn; + SfxBindings* pBindings = GetBindings(); + if ( pBindings ) + pBindings->InvalidateAll(sal_True); +} + +//------------------------------------------------------------------------- +void SfxDispatcher::SetModalMode_Impl( sal_Bool bOn ) + +/* [Beschreibung] + + Bei 'bOn' werden nur noch Slots des Parent-Dispatchers gefunden. +*/ + +{ + pImp->bModal = 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( USHORT 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) ) + { + USHORT nSubId( 0 ); + SfxItemPool& rPool = pShell->GetPool(); + USHORT nWhich = rPool.GetWhich( nSID ); + if ( rPool.GetMetric( nWhich ) == SFX_MAPUNIT_TWIP ) + nSubId |= CONVERT_TWIPS; + pItem->QueryValue( aState, (BYTE)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; +} + +// Ein dirty trick, um an die Methoden der private base class von +// SfxShellStack_Impl heranzukommen +class StackAccess_Impl : public SfxShellStack_Implarr_ +{}; + +void SfxDispatcher::InsertShell_Impl( SfxShell& rShell, sal_uInt16 nPos ) +{ + Flush(); + + // Der cast geht, weil SfxShellStack_Impl keine eigenen member hat + ((StackAccess_Impl*) (&pImp->aStack))->Insert( nPos, &rShell ); + rShell.SetDisableFlags( pImp->nDisableFlags ); + rShell.DoActivate_Impl(pImp->pFrame, sal_True); + + if ( !SFX_APP()->IsDowning() ) + { + pImp->bUpdated = sal_False; + pImp->pCachedServ1 = 0; + pImp->pCachedServ2 = 0; + InvalidateBindings_Impl(sal_True); + } +} + +void SfxDispatcher::RemoveShell_Impl( SfxShell& rShell ) +{ + Flush(); + + // Der cast geht, weil SfxShellStack_Impl keine eigenen member hat + 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 +/* + [Beschreibung] + Die Methode prueft, ob der Zugriff auf diese Schnittstelle erlaubt ist. + */ +{ + if ( !pImp->pDisableList ) + { + return sal_True; + } + + // BinSearch in der DisableListe + SvUShorts& rList = *pImp->pDisableList; + sal_uInt16 nCount = rList.Count(); + 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 ist 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 in der Liste gefunden ? + 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; + } +} diff --git a/sfx2/source/control/macro.cxx b/sfx2/source/control/macro.cxx new file mode 100644 index 000000000000..04a820d8e0ac --- /dev/null +++ b/sfx2/source/control/macro.cxx @@ -0,0 +1,708 @@ +/************************************************************************* + * + * 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" + +#if OSL_DEBUG_LEVEL > 1 +#include <tools/stream.hxx> +#endif + +#include "macro.hxx" +#include <sfx2/request.hxx> +#include <sfx2/msg.hxx> + +//==================================================================== + +SV_DECL_PTRARR_DEL( SfxStatements_Impl, SfxMacroStatement*, 16, 8 ) +SV_IMPL_PTRARR( SfxStatements_Impl, SfxMacroStatement* ); + +//-------------------------------------------------------------------- + +struct SfxMacro_Impl + +/* [Beschreibung] + + Implementations-Struktur der Klasse <SfxMacro>. +*/ + +{ + SfxMacroMode eMode; /* Zweck der <SfxMacro>-Instanz, + Bedeutung siehe enum <SfxMacroMode> */ + SfxStatements_Impl aList; /* Liste von aufgezeichneten Statements */ +}; + +//==================================================================== + +SfxMacroStatement::SfxMacroStatement +( + const SfxShell& /*rShell*/, // <SfxShell>, die den Request ausf"uhrte + const String& /*rTarget*/, // Name des Zielobjektes vor der Ausf"urhung + BOOL /*bAbsolute*/, // obsolet + const SfxSlot& rSlot, // der <SfxSlot>, der das Statement abspielen kann + BOOL bRequestDone, // wurde der Request tats"achlich ausgef"uhrt + ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue >& rArgs +) + +/* [Beschreibung] + + Dieser Konstruktor der Klasse SfxMacroStatement erzeugt ein Statement, + bei dem ein Objekt angesprochen wird, welches durch 'rShell' angegeben + ist. Dabei erfolgt die Addressierung je nach 'bAbsolute' absolut, + also z.B. als '[mydoc.sdc]' oder relativ, also z.B. 'ActiveDocument'. + + Je nach Art der Subklasse von 'rShell' ergeben sich folgende + Ausdr"ucke: + + | absolut relativ + ----------------------------------------------------------------------- + SfxApplication' | 'StarCalc' 'Application' + SfxViewFrame' | '[mydoc.sdc:1]' 'ActiveWindow' + SfxViewShell' | '[mydoc.sdc:1]' 'AvtiveWindow' + SfxObjectShell' | '[mydoc.sdc]' 'ActiveDocument' + sonstige (Sub-Shells) | '[mydoc.sdc:1]' 'ActiveWindow' + + Dabei sind 'StarCalc' stellvertretend fuer den Namen der Applikation + (Application::GetAppName()const). In der absoluten Fassung k"onnte + die Selektion auch deskriptiv z.B. als 'CellSelection("A5-D8")') + angesprochen werden, dazu mu\ jedoch vom Anwendungsprogrammierer der + Konstruktor <SfxMacroStatement::SfxMacroStatement(const String&, + const SfxSlot&,BOOL,SfxArguments*)> verwendet werden. + + F"ur das so bezeichnete Objekt wird dann je nach Typ des Slots + eine Zuweisung an eines seiner Properties oder der Aufruf einer seiner + Methoden ausgedr"uckt. + + + [Beispiele] + + absolut: + SCalc3.OpenDocument( "\docs\mydoc.sdd", "StarDraw Presentation", 0, 0 ) + [mydoc.sdd].Activate() + [mydoc.sdd:1].SwitchToView( 2 ) + [mydoc.sdc:1:1].CellSelection( "A5-D8" ).LineColor = 192357 + + relativ: + ActiveWindow.LineColor = 192357 + + + [Querverweise] + + <SfxMacroStatement::SfxMacroStatement(const String&,const SfxSlot&,BOOL,SfxArguments*)> + <SfxMacroStatement::SfxMacroStatement(const String&)> +*/ + +: nSlotId( rSlot.GetSlotId() ), + aArgs( rArgs ), + bDone( bRequestDone ), + pDummy( 0 ) +{ + // Workaround Recording nicht exportierter Slots (#25386#) + if ( !rSlot.pName ) + return; +/* + // Objekt-Typ bestimmen + FASTBOOL bIsApp = rShell.ISA(SfxApplication); + FASTBOOL bIsDoc = rShell.ISA(SfxObjectShell); + FASTBOOL bIsWin = !bIsApp && !bIsDoc && + ( rShell.ISA(SfxViewShell) || rShell.ISA(SfxViewFrame) ); + FASTBOOL bIsSel = !bIsApp && !bIsDoc && !bIsWin; + + // Objekt nicht schon im Slot-Namen enthalten? + if ( bIsSel || rSlot.pName[0] == '.' ) + { + // absolutes Aufzeichnen? + if ( rSlot.IsMode( SFX_SLOT_RECORDABSOLUTE ) ) + { + // an der Applikation oder am Modul + if ( rShell.ISA(SfxApplication) || rShell.ISA(SfxModule) ) + aStatement = rTarget; + + // am Dokument? + // '[' = 5Bh + // ']' = 5Dh + else if ( rShell.ISA(SfxObjectShell) ) + { + aStatement = 0x005B; + aStatement += rTarget; + aStatement += 0x005D; + } + + else if ( rShell.ISA(SfxViewFrame) ) + { + aStatement = 0x005B; + aStatement += String::CreateFromAscii("ViewFrame");//rShell.GetSbxObject()->GetName(); + aStatement += 0x005D; + } + + else + { + // an der View oder Sub-Shell + SfxViewShell *pViewShell = rShell.GetViewShell(); + aStatement = 0x005B; + aStatement += String::CreateFromAscii("ViewShell");//pViewShell->GetViewFrame()->GetSbxObject()->GetName(); + aStatement += 0x005D; + if ( !rShell.ISA(SfxViewFrame) ) + // an einer Sub-Shell zus"atlich ".Selection" anh"angen + aStatement += DEFINE_CONST_UNICODE(".Selection"); + } + } + else // relatives Aufzeichnen + { + // an der Application? + if ( rShell.ISA(SfxApplication) ) + aStatement = DEFINE_CONST_UNICODE("Application"); + + // am Modul? + else if ( rShell.ISA(SfxModule) ) + aStatement = DEFINE_CONST_UNICODE("ActiveModule"); + + // am Dokument + else if ( rShell.ISA(SfxObjectShell) ) + aStatement = DEFINE_CONST_UNICODE("ActiveDocument"); + + // am Window + else if ( rShell.ISA(SfxViewShell) || rShell.ISA(SfxViewFrame) ) + aStatement = DEFINE_CONST_UNICODE("ActiveWindow"); + + else + // an einer Sub-Shell + aStatement = DEFINE_CONST_UNICODE("Selection"); + } + } + + if ( bIsSel ) + { + // bei Selection ggf. noch den Namen der SubShell anh"angen + const SfxShellObject *pShObj = + (const SfxShellObject*) rShell.GetSbxObject(); + if ( pShObj ) + { + const SfxShellObject *pParentObj = + (const SfxShellObject*) pShObj->GetParent(); + SfxShell *pParentSh = pParentObj->GetShell(); + DBG_ASSERT( pParentSh->ISA(SfxViewFrame), + "parent of SubShell must be a Frame" ); + if ( rSlot.pName[0] == '.' ) + { + aStatement += '.'; + aStatement += rShell.GetSbxObject()->GetName(); + } + } + else + DBG_ASSERT( rSlot.pName[0] != '0', "recording unnamed object" ); + } +*/ + aStatement = DEFINE_CONST_UNICODE("Selection"); + + // an diesen Objekt-Ausdruck den Methoden-/Property-Namen und Parameter + GenerateNameAndArgs_Impl( SfxRequest::GetRecordingMacro(), rSlot, bRequestDone, aArgs); +} + +//-------------------------------------------------------------------- + +SfxMacroStatement::SfxMacroStatement +( + const String& rTarget, // Objekt, was beim Playing angesprochen wird + const SfxSlot& rSlot, // der <SfxSlot>, der das Statement abspielen kann + BOOL bRequestDone, // wurde der Request tats"achlich ausgef"uhrt + ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue >& rArgs +) + +/* [Beschreibung] + + + [Querverweise] + + <SfxMacroStatement::SfxMacroStatement(const String&)> + <SfxMacroStatement::SfxMacroStatement(const SfxShell&,BOOL,const SfxSlot&,BOOL,SfxArguments*)> +*/ + +: nSlotId( rSlot.GetSlotId() ), + aArgs( rArgs ), + bDone( bRequestDone ), + pDummy( 0 ) +{ + aStatement = rTarget; + aStatement += '.'; + GenerateNameAndArgs_Impl( SfxRequest::GetRecordingMacro(), rSlot, bRequestDone, aArgs); +} + +//-------------------------------------------------------------------- + +SfxMacroStatement::SfxMacroStatement +( + const String& rStatement // manuell erzeugte(s) Statement(s) +) + +/* [Beschreibung] + + Dieser Konstruktor erzeugt eine SfxMacroStatement-Instanz, deren + Aufbau vollst"andig vom Applikationsentwickler bestimmt wird. Da der + angegebene String auch mehrere mit CR/LF getrennte Statements + enthalten darf, ist damit ein weitgehender Eingriff in das Aufzeichnen + von BASIC-Makros m"oglich, um Spezialf"alle zu behandeln. + + + [Querverweise] + + <SfxMacroStatement::SfxMacroStatement(const String&,const SfxSlot&,BOOL,SfxArguments*)> + <SfxMacroStatement::SfxMacroStatement(const SfxShell&,BOOL,const SfxSlot&,BOOL,SfxArguments*)> +*/ + +: nSlotId( 0 ), + aStatement( rStatement ), + bDone( TRUE ), + pDummy( 0 ) +{ +} + +//-------------------------------------------------------------------- + +SfxMacroStatement::SfxMacroStatement +( + const SfxMacroStatement& rOrig // Original, von dem kopiert wird +) + +/* [Beschreibung] + + Copy-Konstruktor der SfxMacroStatement-Klasse. +*/ + +: nSlotId( rOrig.nSlotId ), + aStatement( rOrig.aStatement ), + bDone( rOrig.bDone ), + pDummy( 0 ) +{ + aArgs = rOrig.aArgs; +} + +//-------------------------------------------------------------------- + +SfxMacroStatement::~SfxMacroStatement() + +/* [Beschreibung] + + Destruktor der Klasse SfxMacroStatement. Gibt die Liste der + aktuellen Parameter frei. +*/ + +{ +} + +//-------------------------------------------------------------------- + +void SfxMacroStatement::GenerateNameAndArgs_Impl +( + SfxMacro* /*pMacro*/, // darin wird aufgezeichnet + const SfxSlot& rSlot, // der Slot, der das Statement abspielen kann + BOOL bRequestDone, // TRUE=wurde ausgef"uhrt, FALSE=abgebrochen + ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue >& /*rArgs*/ +) + +/* [Beschreibung] + + Interne Hilfsmethode zum generieren des Funktions-/Property-Names + sowie der Parameter. Diese Methode wird nur verwendet, wenn der + Anwendungsprogrammierer keinen eigenen Source an den <SfxRequest> + geh"angt hat. +*/ + +{ + if ( aStatement.Len() && aStatement.GetChar( aStatement.Len() - 1 ) != '.' + && rSlot.pName[0] != '.' ) + aStatement += '.'; + + // der Name des Slots ist der Name der Methode / des Properties + aStatement += String::CreateFromAscii(rSlot.pName); + if ( rSlot.IsMode(SFX_SLOT_METHOD) ) + aStatement += DEFINE_CONST_UNICODE("( "); + else + aStatement += DEFINE_CONST_UNICODE(" = "); + + // alle zusammengesuchten Parameter rausschreiben + if ( aArgs.getLength() ) + for ( USHORT nArg = 0; nArg < aArgs.getLength(); ++nArg ) + { + // den Parameter textuell darstellen + String aArg; + ::com::sun::star::uno::Any& rValue = aArgs[nArg].Value; + ::com::sun::star::uno::Type pType = rValue.getValueType(); + if ( pType == ::getBooleanCppuType() ) + { + sal_Bool bTemp = false; + rValue >>= bTemp; + aArg = bTemp ? DEFINE_CONST_UNICODE("TRUE") : DEFINE_CONST_UNICODE("FALSE"); + } + else if ( pType == ::getCppuType((const sal_Int16*)0) ) + { + sal_uInt16 nTemp = 0; + rValue >>= nTemp; + aArg = String::CreateFromInt32( (sal_Int32) nTemp ); + } + else if ( pType == ::getCppuType((const sal_Int32*)0) ) + { + sal_uInt32 nTemp = 0; + rValue >>= nTemp; + aArg = String::CreateFromInt32( nTemp ); + } + else if ( pType == ::getCppuType((const ::rtl::OUString*)0) ) + { + ::rtl::OUString sTemp; + rValue >>= sTemp; + + // Anf"uhrungszeichen werden verdoppelt + XubString aRecordable( sTemp ); + USHORT nPos = 0; + while ( TRUE ) + { + nPos = aRecordable.SearchAndReplace( DEFINE_CONST_UNICODE('"'), DEFINE_CONST_UNICODE("\"\""), nPos ); + if ( STRING_NOTFOUND == nPos ) + break; + nPos += 2; + } + + // nicht druckbare Zeichen werden als chr$(...) geschrieben + FASTBOOL bPrevReplaced = FALSE; + for ( USHORT n = 0; n < aRecordable.Len(); ++n ) + { + sal_Unicode cChar = aRecordable.GetChar(n); + if ( !( cChar>=32 && cChar!=127 ) ) // ALS ERSATZ FUER String::IsPrintable()! + { + XubString aReplacement( DEFINE_CONST_UNICODE("+chr$(") ); + aReplacement += cChar; + + if ( bPrevReplaced ) + { + aRecordable.Insert( aReplacement, n - 2 ); + n = n + aReplacement.Len(); + aRecordable.SetChar((unsigned short) (n-2), 0x0029);// ')' = 29h + aRecordable.Replace( n-1, 2, DEFINE_CONST_UNICODE("+\"") ); + // ++n; + } + else + { + aReplacement += DEFINE_CONST_UNICODE(")+\""); + aRecordable.SetChar(n, 0x0022 );// '"' = 22h + aRecordable.Insert( aReplacement, n + 1 ); + n = n + aReplacement.Len(); + } + bPrevReplaced = TRUE; + } + else + bPrevReplaced = FALSE; + + // Argument in Anf"uhrungszeichen + aArg = '"'; + aArg += aRecordable; + aArg += '"'; + } +/* + case SbxBYTE: + { + // als Zahl darstellen + aArg = (USHORT) rVar.GetByte(); + break; + } +*/ + } + else + { + OSL_ENSURE( + pType == ::getVoidCppuType(), "Unknown Type in recorder!" ); + } + + // den Parameter anh"angen + aStatement += aArg; + aStatement += DEFINE_CONST_UNICODE(", "); + } + + // Statement beeden + if ( aArgs.getLength() ) + aStatement.Erase( aStatement.Len() - 2, 1 ); + else + aStatement.Erase( aStatement.Len() - 1, 1 ); + if ( rSlot.IsMode(SFX_SLOT_METHOD) ) + aStatement += ')'; + + if ( !bRequestDone ) + // nicht als "Done()" gekennzeichnete Statements auskommentieren + aStatement.InsertAscii( "rem ", 0 ); +} + +//-------------------------------------------------------------------- + +SfxMacro::SfxMacro +( + SfxMacroMode eMode // Zweck der Instanz, siehe <SfxMacroMode> +) + +/* [Beschreibung] + + Konstruktor der Klasse SfxMacro. Instanzen dieser Klasse werden im + SFx zu zwei Zwecken ben"otigt: + + 1. zum Aufzeichnen von Makros + In diesem Fall wird der Konstruktor mit SFX_MACRO_RECORDINGABSOLUTE + oder SFX_MACRO_RECORDINGRELATIVE aufgerufen. Es sollte sich um eine + Instanz einer abgeleiteten Klasse handeln, um in der Ableitung + die Information dar"uber unterzubringen, wo das Makro gespeichert + werden soll. Ein solches Makro solle sich dann in seinem Destruktor + an der vom Benutzer gew"ahlten Stelle speichern. + + 2. zum Zuordnen von exisitierenden Makros + In diesem Fall wird der Konstruktor mit SFX_MACRO_EXISTING aufgerufen. + Eine solche Instanz wird z.B. ben"otigt, wenn Makros auf Events + oder <SfxControllerItem>s konfiguriert werden sollen. +*/ + +: pImp( new SfxMacro_Impl ) + +{ + pImp->eMode = eMode; +} + +//-------------------------------------------------------------------- + +SfxMacro::~SfxMacro() + +/* [Beschreibung] + + Virtueller Destruktor der Klasse SfxMacro. Dieser sollte in den + abgeleiteten Klassen "uberladen werden, um in den Modi + SFX_MACRO_RECORDINGABSOLUTE und SFX_MACRO_RECORDINGRELATIVE den + aufgezeichneten Source abzuspeichern. + + + [Querverweise] + + <SfxMacro::GenerateSource()const> +*/ + +{ +#if OSL_DEBUG_LEVEL > 1 + SvFileStream aStream( String::CreateFromAscii("file:///f:/testmacro.bas" ), STREAM_STD_READWRITE | STREAM_TRUNC ); + aStream << ByteString( GenerateSource(), RTL_TEXTENCODING_UTF8 ).GetBuffer(); +#endif + delete pImp; +} + +//-------------------------------------------------------------------- + +SfxMacroMode SfxMacro::GetMode() const + +/* [Beschreibung] + + Liefert den Modus, der besagt zu welchem Zweck das SfxMacro konstruiert + wurde. + + + [Querverweise] + + enum <SfxMacroMode> +*/ + +{ + return pImp->eMode; +} + +//-------------------------------------------------------------------- + +void SfxMacro::Record +( + SfxMacroStatement* pStatement // aufzuzeichnendes <SfxMacroStatement> +) + +/* [Beschreibung] + + Diese Methode zeichnet das als Parameter "ubergeben Statement auf. + Die Instanz auf die der "ubergebe Pointer zeigt, geht in das Eigentum + des SfxMacro "uber. + + Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt, + welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE + konstruiert wirde. + + + [Querverweise] + + <SfxMacro::Replace(SfxMacroStatement*)> + <SfxMacro::Remove()> + <SfxMacro::GetLastStatement()const> +*/ + +{ + DBG_ASSERT( pImp->eMode != SFX_MACRO_EXISTING, "invalid call to non-recording SfxMacro" ); + pImp->aList.C40_INSERT( SfxMacroStatement, pStatement, pImp->aList.Count() ); +} + +//-------------------------------------------------------------------- + +void SfxMacro::Replace +( + SfxMacroStatement* pStatement // aufzuzeichnendes <SfxMacroStatement> +) + +/* [Beschreibung] + + Diese Methode zeichnet das als Parameter "ubergeben Statement auf. + Dabei wird das jeweils zuletzt aufgezeichnete Statement "uberschrieben. + Die Instanz auf die der "ubergebe Pointer zeigt, geht in das Eigentum + des SfxMacro "uber. + + Mit dieser Methode ist es m"oglich, Statements zusammenzufassen. Z.B. + anstelle f"unfmal hintereinander 'CursorLeft()' aufzurufen, k"onnte + das zu 'CursorLeft(5)' zusammengefa\st werden. Oder anstelle ein Wort + Buchstabe f"ur Buchstabe aufzubauen, k"onnte dies durch ein einziges + Statement 'InsertString("Hallo")' ersetzt werden. + + Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt, + welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE + konstruiert wurde und bereits ein aufgezeichnetes Statement vorhanden + ist. + + + [Anmerkung] + + Diese Methode wird typischerweise aus den Execute-Methoden der + <SfxSlot>s von den Applikationsentwicklern gerufen. + + + [Querverweise] + + <SfxMacro::Record(SfxMacroStatement*)> + <SfxMacro::Remove()> + <SfxMacro::GetLastStatement()const> +*/ + +{ + DBG_ASSERT( pImp->eMode != SFX_MACRO_EXISTING, "invalid call to non-recording SfxMacro" ); + DBG_ASSERT( pImp->aList.Count(), "no replaceable statement available" ); + pImp->aList.Remove( pImp->aList.Count() - 1 ); + pImp->aList.C40_INSERT( SfxMacroStatement,pStatement, pImp->aList.Count() ); +} + +//-------------------------------------------------------------------- + +void SfxMacro::Remove() + +/* [Beschreibung] + + Diese Methode l"oscht das zuletzt aufgezeichnete <SfxMacroStatement> + und entfernt es aus dem Macro. + + Mit dieser Methode ist es m"oglich, Statements zusammenzufassen. Z.B. + anstelle f"unfmal hintereinander 'CursorLeft()' aufzurufen, k"onnte + das zu 'CursorLeft(5)' zusammengefa\st werden. Oder anstelle ein Wort + Buchstabe f"ur Buchstabe aufzubauen, k"onnte dies durch ein einziges + Statement 'InsertString("Hallo")' ersetzt werden. + + Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt, + welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE + konstruiert wurde und bereits ein aufgezeichnetes Statement vorhanden + ist. + + + [Anmerkung] + + Diese Methode wird typischerweise aus den Execute-Methoden der + <SfxSlot>s von den Applikationsentwicklern gerufen. + + + [Querverweise] + + <SfxMacro::Replace(SfxMacroStatement*)> + <SfxMacro::Record(SfxMacroStatement*)> + <SfxMacro::GetLastStatement()const> +*/ + +{ + DBG_ASSERT( pImp->eMode != SFX_MACRO_EXISTING, "invalid call to non-recording SfxMacro" ); + DBG_ASSERT( pImp->aList.Count(), "no replaceable statement available" ); + pImp->aList.Remove( pImp->aList.Count() - 1 ); +} + +//-------------------------------------------------------------------- + +const SfxMacroStatement* SfxMacro::GetLastStatement() const + +/* [Beschreibung] + + Mit dieser Methode kann auf das jeweils zuletzt aufgezeichnete Statement + lesend zugegriffen werden. Zusammen mit der Methode + <SfxMacro::Replace(SfxMacroStatement*)> ergibt sich dadurch die + M"oglichkeit, Statements zusammenzufassen. + + Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt, + welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE + konstruiert wurde. + + + [Querverweise] + + <SfxMacro::Record(SfxMacroStatement*)> + <SfxMacro::Replace(SfxMacroStatement*)> +*/ + +{ + DBG_ASSERT( pImp->eMode != SFX_MACRO_EXISTING, "invalid call to non-recording SfxMacro" ); + if ( pImp->aList.Count() ) + return pImp->aList.GetObject( pImp->aList.Count() - 1 ); + return 0; +} + +//-------------------------------------------------------------------- + +String SfxMacro::GenerateSource() const + +/* [Beschreibung] + + Diese Funktion generiert aus den, seit dem Konstruieren der Instanz + bis zum Zeitpunkt des Aufrufs dieser Methode aufgezeichneten + <SfxMacroStatement>s einen BASIC-Sourcecode, der die Statements, + jedoch nicht den Header ('Sub X') und den Footer ('End Sub') enth"alt. + + + [Querverweise] + + <SfxMacro::Record(SfxMacroStatement*)> + <SfxMacro::Repeat(SfxMacroStatement*)> +*/ + +{ + DBG_ASSERT( pImp->eMode != SFX_MACRO_EXISTING, "invalid call to non-recording SfxMacro" ); + String aSource; + for ( USHORT n = 0; n < pImp->aList.Count(); ++n ) + { + aSource += pImp->aList.GetObject(n)->GetStatement(); + if ( (n+1) < pImp->aList.Count() ) + aSource += DEFINE_CONST_UNICODE("\n"); + } + + return aSource; +} + diff --git a/sfx2/source/control/minfitem.cxx b/sfx2/source/control/minfitem.cxx new file mode 100644 index 000000000000..b0cdd58d2645 --- /dev/null +++ b/sfx2/source/control/minfitem.cxx @@ -0,0 +1,104 @@ +/************************************************************************* + * + * 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 --------------------------------------------------------------- + +#include "sfx2/minfitem.hxx" + +// STATIC DATA ----------------------------------------------------------- + +TYPEINIT1(SfxMacroInfoItem, SfxPoolItem); + +// ----------------------------------------------------------------------- + +SfxMacroInfoItem::SfxMacroInfoItem( + USHORT nWhichId, // Slot-ID + const BasicManager* pMgr, + const String &rLibName, + const String &rModuleName, + const String &rMethodName, + const String &rComment) : + SfxPoolItem(nWhichId), + pBasicManager(pMgr), + aLibName(rLibName), + aModuleName(rModuleName), + aMethodName(rMethodName), + aCommentText(rComment) +{ +} + +// ----------------------------------------------------------------------- + +// copy ctor + +SfxMacroInfoItem::SfxMacroInfoItem(const SfxMacroInfoItem& rCopy): + SfxPoolItem(rCopy), + pBasicManager(rCopy.pBasicManager), + aLibName(rCopy.aLibName), + aModuleName(rCopy.aModuleName), + aMethodName(rCopy.aMethodName), + aCommentText(rCopy.aCommentText) +{ +} + +// ----------------------------------------------------------------------- + +// op == + +int SfxMacroInfoItem::operator==( const SfxPoolItem& rCmp) const +{ + return SfxPoolItem::operator==(rCmp) && + pBasicManager == ((const SfxMacroInfoItem&)rCmp).pBasicManager && + aLibName == ((const SfxMacroInfoItem&)rCmp).aLibName && + aModuleName == ((const SfxMacroInfoItem&)rCmp).aModuleName && + aMethodName == ((const SfxMacroInfoItem&)rCmp).aMethodName && + aCommentText == ((const SfxMacroInfoItem&)rCmp).aCommentText; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem *SfxMacroInfoItem::Clone( SfxItemPool *) const +{ + return new SfxMacroInfoItem(*this); +} + +// ----------------------------------------------------------------------- + +String SfxMacroInfoItem::GetQualifiedName() const +{ + String aMacroName = aLibName; + aMacroName += '.'; + aMacroName += aModuleName; + aMacroName += '.'; + aMacroName += aMethodName; + return aMacroName; +} + + diff --git a/sfx2/source/control/msg.cxx b/sfx2/source/control/msg.cxx new file mode 100644 index 000000000000..6b05c03160ff --- /dev/null +++ b/sfx2/source/control/msg.cxx @@ -0,0 +1,75 @@ +/************************************************************************* + * + * 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 <svl/itempool.hxx> +#include <svl/eitem.hxx> +#include <sfx2/msg.hxx> + +//==================================================================== + +SfxSlotKind SfxSlot::GetKind() const +{ + if( !nMasterSlotId && !nValue) + return (SfxSlotKind) SFX_KIND_STANDARD; + if ( nMasterSlotId && fnExec==0 && fnState==0 ) + { + if ( pType->Type() == TYPE(SfxBoolItem) ) + return (SfxSlotKind) SFX_KIND_ENUM; + else + { + DBG_ERROR( "invalid slot kind detected" ); + return SFX_KIND_ENUM; + } + } + else + return (SfxSlotKind) SFX_KIND_ATTR; +} + +//-------------------------------------------------------------------- + +USHORT SfxSlot::GetWhich( const SfxItemPool &rPool ) const +{ + if ( !nMasterSlotId || nMasterSlotId == USHRT_MAX ) + ((SfxSlot*) this) -> nMasterSlotId = rPool.GetWhich(nSlotId); + return nMasterSlotId; +} + +::rtl::OString SfxSlot::GetCommand() const +{ + rtl::OString sRet(".uno:"); + sRet += pUnoName; + return sRet; +} + +::rtl::OUString SfxSlot::GetCommandString() const +{ + rtl::OString aCmd(GetCommand()); + return rtl::OUString( aCmd, aCmd.getLength(), RTL_TEXTENCODING_UTF8 ); +} + diff --git a/sfx2/source/control/msgpool.cxx b/sfx2/source/control/msgpool.cxx new file mode 100644 index 000000000000..9d3661ef1bc1 --- /dev/null +++ b/sfx2/source/control/msgpool.cxx @@ -0,0 +1,421 @@ +/************************************************************************* + * + * 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 <tools/stream.hxx> +#include <rsc/rscsfx.hxx> +#ifndef GCC +#endif + +// wg. pSlotPool +#include "appdata.hxx" +#include <sfx2/msgpool.hxx> +#include <sfx2/minarray.hxx> +#include <sfx2/msg.hxx> +#include <sfx2/app.hxx> +#include <sfx2/objface.hxx> +#include "sfxtypes.hxx" +#include "sfx2/sfxresid.hxx" +#include "arrdecl.hxx" +#include <sfx2/module.hxx> + +#include <sfx2/sfx.hrc> + +//==================================================================== + +struct SfxSIDRegistration_Impl +{ + String _aGroup; + String _aName; + USHORT _nSID; +}; + +struct SfxSlotType_Impl +{ + USHORT nId; + TypeId nType; + + SfxSlotType_Impl( USHORT nTheId, TypeId nTheType ): + nId(nTheId), nType(nTheType) + {} +}; + +DECL_2BYTEARRAY(SfxSlotGroupArr_Impl, USHORT, 6, 4) +DECL_PTRARRAY(SfxInterfaceArr_Impl, SfxInterface*, 6, 3) +DECL_PTRARRAY(SfxSlotTypeArr_Impl, SfxSlotType_Impl*, 8, 8) + + +//==================================================================== + +SfxSlotPool::SfxSlotPool( SfxSlotPool *pParent, ResMgr* pResManager ) + : _pGroups(0) + , _pTypes(0) + , _pParentPool( pParent ) + , _pResMgr( pResManager ) + , _pInterfaces(0) + , _nCurGroup(0) + , _nCurInterface(0) + , _nCurMsg(0) + , _pUnoSlots( 0 ) +{ + if ( !_pResMgr ) + _pResMgr = SfxApplication::GetOrCreate()->GetOffResManager_Impl(); +} + +//==================================================================== + +SfxSlotPool::~SfxSlotPool() +{ + _pParentPool = 0; + for ( SfxInterface *pIF = FirstInterface(); pIF; pIF = FirstInterface() ) + delete pIF; + delete _pInterfaces; + delete _pGroups; + if ( _pTypes ) + { + for ( USHORT n =_pTypes->Count(); n--; ) + delete _pTypes->GetObject(n); + delete _pTypes; + } +} + +//==================================================================== + +// registers the availability of the Interface of functions + +void SfxSlotPool::RegisterInterface( SfxInterface& rInterface ) +{ + DBG_MEMTEST(); + + // add to the list of SfxObjectInterface instances + if ( _pInterfaces == 0 ) + _pInterfaces = new SfxInterfaceArr_Impl; + _pInterfaces->Append(&rInterface); + + // bei einem (einzelnen) Null-Slot abbrechen (aus syntaktischen Gr"unden + // enthalten interfaces immer mindestens einen Slot) + if ( rInterface.Count() == 1 && !rInterface[0]->nSlotId ) + return; + + // possibly add Interface-id and group-ids of funcs to the list of groups + if ( !_pGroups ) + { + _pGroups = new SfxSlotGroupArr_Impl; + + if ( _pParentPool ) + { + // Die Groups im parent Slotpool sind auch hier bekannt + SfxSlotGroupArr_Impl& rGroups = *_pParentPool->_pGroups; + for ( USHORT n=0; n<rGroups.Count(); n++ ) + _pGroups->Append( rGroups[n] ); + } + } + + if ( !_pTypes ) + _pTypes = new SfxSlotTypeArr_Impl; + for ( USHORT nFunc = 0; nFunc < rInterface.Count(); ++nFunc ) + { + SfxSlot *pDef = rInterface[nFunc]; + if ( pDef->GetGroupId() && /* pDef->GetGroupId() != GID_INTERN && */ + !_pGroups->Contains(pDef->GetGroupId()) ) + { + if (pDef->GetGroupId() == GID_INTERN) + _pGroups->Insert(0, pDef->GetGroupId()); + else + _pGroups->Append(pDef->GetGroupId()); + } +#if 0 + const TypeId &rTypeId = pDef->GetType()->Type(); + if ( /*rTypeId != TYPE(SfxVoidItem) &&*/ rTypeId != 0 ) + { + USHORT nPos; + for ( nPos = 0; nPos < _pTypes->Count(); ++nPos ) + { + if ( _pTypes->GetObject(nPos)->nId == pDef->GetSlotId() ) + { + DBG_ASSERT( rTypeId == _pTypes->GetObject(nPos)->nType, + "same slot id with unequal item types" ); + } + else if ( _pTypes->GetObject(nPos)->nId > pDef->GetSlotId() ) + break; + } + if ( nPos >= _pTypes->Count() || + _pTypes->GetObject(nPos)->nId > pDef->GetSlotId() ) + _pTypes->Append( new SfxSlotType_Impl( pDef->GetSlotId(), rTypeId ) ); + } +#endif + } +} + +//==================================================================== + +TypeId SfxSlotPool::GetSlotType( USHORT nId ) const +{ + const SfxSlot* pSlot = (const_cast <SfxSlotPool*> (this))->GetSlot( nId ); + return pSlot ? pSlot->GetType()->Type() : 0; +/* + for ( USHORT nPos = 0; nPos < _pTypes->Count(); ++nPos ) + { + if ( _pTypes->GetObject(nPos)->nId == nId ) + return _pTypes->GetObject(nPos)->nType; + } + return _pParentPool ? _pParentPool->GetSlotType( nId ) : 0; + */ +} + +//==================================================================== + +// unregisters the availability of the Interface of functions + +void SfxSlotPool::ReleaseInterface( SfxInterface& rInterface ) +{ + DBG_MEMTEST(); + DBG_ASSERT( _pInterfaces, "releasing SfxInterface, but there are none" ); + // remove from the list of SfxInterface instances + _pInterfaces->Remove(&rInterface); +} + +//-------------------------------------------------------------------- + +// get the first SfxMessage for a special Id (e.g. for getting check-mode) + +const SfxSlot* SfxSlotPool::GetSlot( USHORT nId ) +{ + DBG_MEMTEST(); + DBG_ASSERT( _pInterfaces != 0, "no Interfaces registered" ); + + // Zun"achst die eigenen Interfaces absuchen + for ( USHORT nInterf = 0; nInterf < _pInterfaces->Count(); ++nInterf ) + { + const SfxSlot *pDef = _pInterfaces->GetObject(nInterf)->GetSlot(nId); + if ( pDef ) + return pDef; + } + + // Dann beim eventuell vorhandenen parent versuchen + return _pParentPool ? _pParentPool->GetSlot( nId ) : 0; +} + +//-------------------------------------------------------------------- + +// skips to the next group + +String SfxSlotPool::SeekGroup( USHORT nNo ) +{ + DBG_MEMTEST(); + DBG_ASSERT( _pInterfaces != 0, "no Interfaces registered" ); + + // if the group exists, use it + if ( _pGroups && nNo < _pGroups->Count() ) + { + _nCurGroup = nNo; + if ( _pParentPool ) + { + // Meistens stimmt die Reihenfolge der Ids "uberein + USHORT nParentCount = _pParentPool->_pGroups->Count(); + if ( nNo < nParentCount && (*_pGroups)[nNo] == (*_pParentPool->_pGroups)[nNo] ) + _pParentPool->_nCurGroup = nNo; + else + { + // Ansonsten mu\s gesucht werden + // Wenn die Gruppe im parent pool nicht gefunden wird, wird + // _nCurGroup au\serhalb des g"ultigen Bereiches gesetzt + USHORT i; + for ( i=1; i<nParentCount; i++ ) + if ( (*_pGroups)[nNo] == (*_pParentPool->_pGroups)[i] ) + break; + _pParentPool->_nCurGroup = i; + } + } + + SfxResId aResId( (*_pGroups)[_nCurGroup] ); + aResId.SetRT(RSC_STRING); + if ( !aResId.GetResMgr()->IsAvailable(aResId) ) + { + DBG_ERROR( "GroupId-Name nicht im SFX definiert!" ); + return String(); + } + + return String( aResId ); + } + + return String(); +} + + +//-------------------------------------------------------------------- + +USHORT SfxSlotPool::GetGroupCount() +{ + return _pGroups->Count(); +} + + +//-------------------------------------------------------------------- + +// internal search loop + +const SfxSlot* SfxSlotPool::SeekSlot( USHORT nStartInterface ) +{ + DBG_MEMTEST(); + DBG_ASSERT( _pInterfaces != 0, "no Interfaces registered" ); + + // Die Numerierung der interfaces startet beim parent pool + USHORT nFirstInterface = _pParentPool ? _pParentPool->_pInterfaces->Count() : 0; + + // sind wir am Ende des Parent-Pools angekommen? + if ( nStartInterface < nFirstInterface && + _pParentPool->_nCurGroup >= _pParentPool->_pGroups->Count() ) + nStartInterface = nFirstInterface; + + // liegt das Interface noch im Parent-Pool? + if ( nStartInterface < nFirstInterface ) + { + DBG_ASSERT( _pParentPool, "Kein parent pool!" ); + _nCurInterface = nStartInterface; + return _pParentPool->SeekSlot( nStartInterface ); + } + + // find the first func-def with the current group id + USHORT nCount = _pInterfaces->Count() + nFirstInterface; + for ( _nCurInterface = nStartInterface; + _nCurInterface < nCount; + ++_nCurInterface ) + { + SfxInterface* pInterface = (*_pInterfaces)[_nCurInterface-nFirstInterface]; + for ( _nCurMsg = 0; + _nCurMsg < pInterface->Count(); + ++_nCurMsg ) + { + const SfxSlot* pMsg = (*pInterface)[_nCurMsg]; + if ( pMsg->GetGroupId() == _pGroups->GetObject(_nCurGroup) ) + return pMsg; + } + } + + return 0; +} + +//-------------------------------------------------------------------- + +// skips to the next func in the current group + +const SfxSlot* SfxSlotPool::NextSlot() +{ + DBG_MEMTEST(); + DBG_ASSERT( _pInterfaces != 0, "no Interfaces registered" ); + + // Die Numerierung der interfaces startet beim parent pool + USHORT nFirstInterface = _pParentPool ? _pParentPool->_pInterfaces->Count() : 0; + + if ( _nCurInterface < nFirstInterface && _nCurGroup >= _pParentPool->_pGroups->Count() ) + _nCurInterface = nFirstInterface; + + if ( _nCurInterface < nFirstInterface ) + { + DBG_ASSERT( _pParentPool, "Kein parent pool!" ); + const SfxSlot *pSlot = _pParentPool->NextSlot(); + _nCurInterface = _pParentPool->_nCurInterface; + if ( pSlot ) + return pSlot; + if ( _nCurInterface == nFirstInterface ) + // parent pool ist fertig + return SeekSlot( nFirstInterface ); + } + + USHORT nInterface = _nCurInterface - nFirstInterface; + // possibly we are already at the end + if ( nInterface >= _pInterfaces->Count() ) + return 0; + + // look for further matching func-defs within the same Interface + SfxInterface* pInterface = (*_pInterfaces)[nInterface]; + while ( ++_nCurMsg < pInterface->Count() ) + { + SfxSlot* pMsg = (*pInterface)[_nCurMsg]; + if ( pMsg->GetGroupId() == _pGroups->GetObject(_nCurGroup) ) + return pMsg; + } + + return SeekSlot(++_nCurInterface ); +} + + +//-------------------------------------------------------------------- + +// SlotName erfragen, gfs. mit HilfeText + +//-------------------------------------------------------------------- + +SfxInterface* SfxSlotPool::FirstInterface() +{ + _nCurInterface = 0; + if ( !_pInterfaces || !_pInterfaces->Count() ) + return 0; + return _pParentPool ? _pParentPool->FirstInterface() : (*_pInterfaces)[0]; +} + + +//-------------------------------------------------------------------- + +SfxInterface* SfxSlotPool::NextInterface() +{ + _nCurInterface++; + USHORT nFirstInterface = _pParentPool ? _pParentPool->_pInterfaces->Count() : 0; + if ( _nCurInterface < nFirstInterface ) + return (*_pParentPool->_pInterfaces)[_nCurInterface]; + USHORT nInterface = _nCurInterface - nFirstInterface; + return nInterface < _pInterfaces->Count() ? (*_pInterfaces)[nInterface] : 0; +} + +const SfxSlot* SfxSlotPool::GetUnoSlot( const String& rName ) +{ + const SfxSlot *pSlot = NULL; + for ( USHORT nInterface=0; nInterface<_pInterfaces->Count(); nInterface++ ) + { + pSlot = (*_pInterfaces)[nInterface]->GetSlot( rName ); + if ( pSlot ) + break; + } + + if ( !pSlot && _pParentPool ) + pSlot = _pParentPool->GetUnoSlot( rName ); + + return pSlot; +} + +SfxSlotPool& SfxSlotPool::GetSlotPool( SfxViewFrame *pFrame ) +{ + SfxModule *pMod = SfxModule::GetActiveModule( pFrame ); + if ( pMod && pMod->GetSlotPool() ) + return *pMod->GetSlotPool(); + else + return *SFX_APP()->Get_Impl()->pSlotPool; +} + + diff --git a/sfx2/source/control/objface.cxx b/sfx2/source/control/objface.cxx new file mode 100644 index 000000000000..d0ce2abae773 --- /dev/null +++ b/sfx2/source/control/objface.cxx @@ -0,0 +1,685 @@ +/************************************************************************* + * + * 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 <stdlib.h> +#include <tools/rcid.h> +#ifndef GCC +#endif +#include <tools/stream.hxx> + +#include <sfx2/module.hxx> +#include <sfx2/objface.hxx> +#include <sfx2/msg.hxx> +#include <sfx2/app.hxx> +#include <sfx2/msgpool.hxx> +#include "sfx2/sfxresid.hxx" +#include <sfx2/minarray.hxx> +#include <sfx2/objsh.hxx> + +DBG_NAME(SfxInterface) + +//==================================================================== + +EXTERN_C +#if defined( PM2 ) && (!defined( CSET ) && !defined ( MTW ) && !defined( WTC )) +int _stdcall +#else +#ifdef WNT +int _cdecl +#else +int +#endif +#endif + +SfxCompareSlots_Impl( const void* pSmaller, const void* pBigger ) +{ + DBG_MEMTEST(); + return ( (int) ((SfxSlot*)pSmaller)->GetSlotId() ) - + ( (int) ((SfxSlot*)pBigger)->GetSlotId() ); +} + +//========================================================================= + +struct SfxObjectUI_Impl +{ + USHORT nPos; + ResId aResId; + BOOL bVisible; + BOOL bContext; + String* pName; + sal_uInt32 nFeature; + + SfxObjectUI_Impl(USHORT n, const ResId& rResId, BOOL bVis, sal_uInt32 nFeat) : + nPos(n), + aResId(rResId.GetId(), *rResId.GetResMgr()), + bVisible(bVis), + bContext(FALSE), + pName(0), + nFeature(nFeat) + { + aResId.SetRT(rResId.GetRT()); + } + + ~SfxObjectUI_Impl() + { + delete pName; + } +}; + +DECL_PTRARRAY(SfxObjectUIArr_Impl, SfxObjectUI_Impl*, 2, 2) + +struct SfxInterface_Impl +{ + SfxObjectUIArr_Impl* pObjectBars; // registered ObjectBars + SfxObjectUIArr_Impl* pChildWindows; // registered ChildWindows + ResId aPopupRes; // registered PopupMenu + ResId aStatBarRes; // registered StatusBar + SfxModule* pModule; + BOOL bRegistered; + + SfxInterface_Impl() : + aPopupRes(0,*SfxApplication::GetOrCreate()->GetSfxResManager()), + aStatBarRes(0,*SfxApplication::GetOrCreate()->GetSfxResManager()) + , bRegistered(FALSE) + { + pObjectBars = new SfxObjectUIArr_Impl; + pChildWindows = new SfxObjectUIArr_Impl; + } + + ~SfxInterface_Impl() + { + USHORT n; + for (n=0; n<pObjectBars->Count(); n++) + delete (*pObjectBars)[n]; + delete pObjectBars; + + for (n=0; n<pChildWindows->Count(); n++) + delete (*pChildWindows)[n]; + delete pChildWindows; + } +}; + +static SfxObjectUI_Impl* CreateObjectBarUI_Impl( USHORT nPos, const ResId& rResId, sal_uInt32 nFeature, const String *pStr ); + +//==================================================================== + +//==================================================================== +// ctor, registeres a new unit + +SfxInterface::SfxInterface( const char *pClassName, + const ResId& rNameResId, + SfxInterfaceId nId, + const SfxInterface* pParent, + SfxSlot &rSlotMap, USHORT nSlotCount ): + pName(pClassName), + pGenoType(pParent), + nClassId(nId), + aNameResId(rNameResId.GetId(),*rNameResId.GetResMgr()), + pImpData(0) +{ + pImpData = new SfxInterface_Impl; + SetSlotMap( rSlotMap, nSlotCount ); +} + +void SfxInterface::Register( SfxModule* pMod ) +{ + pImpData->bRegistered = TRUE; + pImpData->pModule = pMod; + if ( pMod ) + pMod->GetSlotPool()->RegisterInterface(*this); + else + SFX_APP()->GetAppSlotPool_Impl().RegisterInterface(*this); +} + +void SfxInterface::SetSlotMap( SfxSlot& rSlotMap, USHORT nSlotCount ) +{ + pSlots = &rSlotMap; + nCount = nSlotCount; + SfxSlot* pIter = pSlots; + if ( 1 == nCount && !pIter->pNextSlot ) + pIter->pNextSlot = pIter; + + if ( !pIter->pNextSlot ) + { + // sort the SfxSlots by id + qsort( pSlots, nCount, sizeof(SfxSlot), SfxCompareSlots_Impl ); + + // link masters and slaves + USHORT nIter = 1; + for ( pIter = pSlots; nIter <= nCount; ++pIter, ++nIter ) + { + //! hier bitte sinnvoll pruefen + //! DBG_ASSERT(!(pIter->IsMode(SFX_SLOT_CACHABLE) && + //! pIter->IsMode(SFX_SLOT_VOLATILE)), + //! "invalid Flags" ); + DBG_ASSERT( nIter == nCount || + pIter->GetSlotId() != (pIter+1)->GetSlotId(), + "doppelte SID" ); + + // jeder Master verweist auf seinen ersten Slave (ENUM), alle + // Slaves auf ihren Master. + // Slaves verweisen im Ring auf die anderen mit gleichem Master + if ( pIter->GetKind() == SFX_KIND_ENUM ) + { + pIter->pLinkedSlot = GetSlot( pIter->nMasterSlotId ); + DBG_ASSERT( pIter->pLinkedSlot, "slave without master" ); + if ( !pIter->pLinkedSlot->pLinkedSlot ) + ( (SfxSlot*) pIter->pLinkedSlot)->pLinkedSlot = pIter; + + if ( 0 == pIter->GetNextSlot() ) + { + SfxSlot *pLastSlot = pIter; + for ( USHORT n = nIter; n < Count(); ++n ) + { + SfxSlot *pCurSlot = (pSlots+n); + if ( pCurSlot->nMasterSlotId == pIter->nMasterSlotId ) + { + pLastSlot->pNextSlot = pCurSlot; + pLastSlot = pCurSlot; + } + } + pLastSlot->pNextSlot = pIter; + } + } + else if ( 0 == pIter->GetNextSlot() ) + { + // Slots verweisen im Ring auf den n"achten mit derselben Statusmethode + SfxSlot *pLastSlot = pIter; + for ( USHORT n = nIter; n < Count(); ++n ) + { + SfxSlot *pCurSlot = (pSlots+n); + if ( pCurSlot->GetStateFnc() == pIter->GetStateFnc() ) + { + pLastSlot->pNextSlot = pCurSlot; + pLastSlot = pCurSlot; + } + } + pLastSlot->pNextSlot = pIter; + } + } + } +#ifdef DBG_UTIL + else + { + USHORT nIter = 1; + for ( SfxSlot *pNext = pIter+1; nIter < nCount; ++pNext, ++nIter ) + { + + if ( pNext->GetSlotId() <= pIter->GetSlotId() ) + DBG_ERROR ("Falsche Reihenfolge!"); + + if ( pIter->GetKind() == SFX_KIND_ENUM ) + { + const SfxSlot *pMasterSlot = GetSlot(pIter->nMasterSlotId); + const SfxSlot *pFirstSlave = pMasterSlot->pLinkedSlot; + const SfxSlot *pSlave = pFirstSlave; + do + { + if ( pSlave->pLinkedSlot != pMasterSlot ) + { + ByteString aStr("Falsche Master/Slave-Verkettung : "); + aStr += ByteString::CreateFromInt32(pMasterSlot->GetSlotId()); + aStr += " , "; + aStr += ByteString::CreateFromInt32(pSlave->GetSlotId()); + DBG_ERROR(aStr.GetBuffer()); + } + + if ( pSlave->nMasterSlotId != pMasterSlot->GetSlotId() ) + { + ByteString aStr("Falsche Master/Slave-Ids : "); + aStr += ByteString::CreateFromInt32(pMasterSlot->GetSlotId()); + aStr += " , "; + aStr += ByteString::CreateFromInt32(pSlave->GetSlotId()); + DBG_ERROR(aStr.GetBuffer()); + } + + pSlave = pSlave->pNextSlot; + } + while ( pSlave != pFirstSlave ); + } + else + { + if ( pIter->pLinkedSlot ) + { + if ( pIter->pLinkedSlot->GetKind() != SFX_KIND_ENUM ) + { + ByteString aStr("Slave ist kein enum : "); + aStr += ByteString::CreateFromInt32(pIter->GetSlotId()); + aStr += " , "; + aStr += ByteString::CreateFromInt32(pIter->pLinkedSlot->GetSlotId()); + DBG_ERROR(aStr.GetBuffer()); + } + } + + const SfxSlot *pCurSlot = pIter; + do + { + pCurSlot = pCurSlot->pNextSlot; + if ( pCurSlot->GetStateFnc() != pIter->GetStateFnc() ) + { + ByteString aStr("Verkettete Slots mit verschiedenen StateMethods : "); + aStr += ByteString::CreateFromInt32(pCurSlot->GetSlotId()); + aStr += " , "; + aStr += ByteString::CreateFromInt32(pIter->GetSlotId()); + DBG_ERROR(aStr.GetBuffer()); + } + } + while ( pCurSlot != pIter ); + } + + pIter = pNext; + } + } +#endif +} + + +//-------------------------------------------------------------------- + + + +SfxInterface::~SfxInterface() +{ + SfxModule *pMod = pImpData->pModule; + BOOL bRegistered = pImpData->bRegistered; + delete pImpData; + DBG_ASSERT( bRegistered, "Interface not registered!" ); + if ( bRegistered ) + { + if ( pMod ) + pMod->GetSlotPool()->ReleaseInterface(*this); + else + SFX_APP()->GetAppSlotPool_Impl().ReleaseInterface(*this); + } +} + +//-------------------------------------------------------------------- + +// searches for the specified func + + +const SfxSlot* SfxInterface::GetSlot( USHORT nFuncId ) const +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxInterface, 0); + DBG_ASSERT( this && pSlots && nCount, "" ); + + // find the id using binary search + void* p = bsearch( &nFuncId, pSlots, nCount, sizeof(SfxSlot), + SfxCompareSlots_Impl ); + if ( !p && pGenoType ) + return pGenoType->GetSlot( nFuncId ); + + return p ? (const SfxSlot*)p : 0; +} + +const SfxSlot* SfxInterface::GetSlot( const String& rCommand ) const +{ + static const char UNO_COMMAND[] = ".uno:"; + + String aCommand( rCommand ); + if ( aCommand.SearchAscii( UNO_COMMAND ) == 0 ) + aCommand.Erase( 0, sizeof( UNO_COMMAND )-1 ); + + for ( USHORT n=0; n<nCount; n++ ) + { + if ( (pSlots+n)->pUnoName && + aCommand.CompareIgnoreCaseToAscii( (pSlots+n)->GetUnoName() ) == COMPARE_EQUAL ) + return pSlots+n; + } + + return pGenoType ? pGenoType->GetSlot( aCommand ) : NULL; +} + +//-------------------------------------------------------------------- + + +const SfxSlot* SfxInterface::GetRealSlot( const SfxSlot *pSlot ) const +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxInterface, 0); + DBG_ASSERT( this && pSlots && nCount, "" ); + + if ( !ContainsSlot_Impl(pSlot) ) + { + if(pGenoType) + return pGenoType->GetRealSlot(pSlot); + DBG_ERROR("fremder Slot"); + return 0; + } + + return pSlot->pLinkedSlot; +} + +//-------------------------------------------------------------------- + + +const SfxSlot* SfxInterface::GetRealSlot( USHORT nSlotId ) const +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxInterface, 0); + DBG_ASSERT( this && pSlots && nCount, "" ); + + const SfxSlot *pSlot = GetSlot(nSlotId); + if ( !pSlot ) + { + if(pGenoType) + return pGenoType->GetRealSlot(nSlotId); + DBG_ERROR("fremder Slot"); + return 0; + } + + return pSlot->pLinkedSlot; +} + +//-------------------------------------------------------------------- + + +void SfxInterface::RegisterPopupMenu( const ResId& rResId ) +{ + DBG_CHKTHIS(SfxInterface, 0); + pImpData->aPopupRes = rResId; +} + +//-------------------------------------------------------------------- + +void SfxInterface::RegisterObjectBar( USHORT nPos, const ResId& rResId, + const String *pStr ) +{ + RegisterObjectBar( nPos, rResId, 0UL, pStr ); +} + + +void SfxInterface::RegisterObjectBar( USHORT nPos, const ResId& rResId, sal_uInt32 nFeature, const String *pStr ) +{ + SfxObjectUI_Impl* pUI = CreateObjectBarUI_Impl( nPos, rResId, nFeature, pStr ); + if ( pUI ) + pImpData->pObjectBars->Append(pUI); +} + +SfxObjectUI_Impl* CreateObjectBarUI_Impl( USHORT nPos, const ResId& rResId, sal_uInt32 nFeature, const String *pStr ) +{ + if ((nPos & SFX_VISIBILITY_MASK) == 0) + nPos |= SFX_VISIBILITY_STANDARD; + + SfxObjectUI_Impl* pUI = new SfxObjectUI_Impl(nPos, rResId, TRUE, nFeature); + + if (pStr == 0) + { + ResId aResId(rResId); + aResId.SetRT(RSC_STRING); + aResId.SetResMgr(rResId.GetResMgr()); + if( ! aResId.GetResMgr() ) + aResId.SetResMgr( SfxApplication::GetOrCreate()->GetOffResManager_Impl() ); + if ( !aResId.GetResMgr()->IsAvailable(aResId) ) + pUI->pName = new String (DEFINE_CONST_UNICODE("NoName")); + else + pUI->pName = new String(aResId); + } + else + pUI->pName = new String(*pStr); + + return pUI; +} + +const ResId& SfxInterface::GetObjectBarResId( USHORT nNo ) const +{ + BOOL bGenoType = (pGenoType != 0 && !pGenoType->HasName()); + if ( bGenoType ) + { + // Gibt es Toolbars in der Superklasse ? + USHORT nBaseCount = pGenoType->GetObjectBarCount(); + if ( nNo < nBaseCount ) + // Die der Superklasse kommen zuerst + return pGenoType->GetObjectBarResId( nNo ); + else + nNo = nNo - nBaseCount; + } + +#ifdef DBG_UTIL + USHORT nObjBarCount = pImpData->pObjectBars->Count(); + DBG_ASSERT( nNo<nObjBarCount,"Objectbar ist unbekannt!" ); +#endif + return (*pImpData->pObjectBars)[nNo]->aResId; +} + +//-------------------------------------------------------------------- + + +USHORT SfxInterface::GetObjectBarPos( USHORT nNo ) const +{ + BOOL bGenoType = (pGenoType != 0 && !pGenoType->HasName()); + if ( bGenoType ) + { + // Gibt es Toolbars in der Superklasse ? + USHORT nBaseCount = pGenoType->GetObjectBarCount(); + if ( nNo < nBaseCount ) + // Die der Superklasse kommen zuerst + return pGenoType->GetObjectBarPos( nNo ); + else + nNo = nNo - nBaseCount; + } + +#ifdef DBG_UTIL + USHORT nObjBarCount = pImpData->pObjectBars->Count(); + DBG_ASSERT( nNo<nObjBarCount,"Objectbar ist unbekannt!" ); +#endif + return (*pImpData->pObjectBars)[nNo]->nPos; +} + +//-------------------------------------------------------------------- + + +USHORT SfxInterface::GetObjectBarCount() const +{ + if (pGenoType && ! pGenoType->HasName()) + return pImpData->pObjectBars->Count() + pGenoType->GetObjectBarCount(); + else + return pImpData->pObjectBars->Count(); +} + +//-------------------------------------------------------------------- +void SfxInterface::RegisterChildWindow(USHORT nId, BOOL bContext, const String* pChildWinName) +{ + RegisterChildWindow( nId, bContext, 0UL, pChildWinName ); +} + +void SfxInterface::RegisterChildWindow(USHORT nId, BOOL bContext, sal_uInt32 nFeature, const String*) +{ + SfxObjectUI_Impl* pUI = new SfxObjectUI_Impl(0, ResId(nId, *SfxApplication::GetOrCreate()->GetOffResManager_Impl()), TRUE, nFeature); + pUI->bContext = bContext; + pImpData->pChildWindows->Append(pUI); +} + +void SfxInterface::RegisterStatusBar(const ResId& rResId) +{ + pImpData->aStatBarRes = rResId; +} + + +sal_uInt32 SfxInterface::GetChildWindowId (USHORT nNo) const +{ + if ( pGenoType ) + { + // Gibt es ChildWindows in der Superklasse ? + USHORT nBaseCount = pGenoType->GetChildWindowCount(); + if ( nNo < nBaseCount ) + // Die der Superklasse kommen zuerst + return pGenoType->GetChildWindowId( nNo ); + else + nNo = nNo - nBaseCount; + } + +#ifdef DBG_UTIL + USHORT nCWCount = pImpData->pChildWindows->Count(); + DBG_ASSERT( nNo<nCWCount,"ChildWindow ist unbekannt!" ); +#endif + sal_uInt32 nRet = (*pImpData->pChildWindows)[nNo]->aResId.GetId(); + if ( (*pImpData->pChildWindows)[nNo]->bContext ) + nRet += sal_uInt32( nClassId ) << 16; + return nRet; +} + +sal_uInt32 SfxInterface::GetChildWindowFeature (USHORT nNo) const +{ + if ( pGenoType ) + { + // Gibt es ChildWindows in der Superklasse ? + USHORT nBaseCount = pGenoType->GetChildWindowCount(); + if ( nNo < nBaseCount ) + // Die der Superklasse kommen zuerst + return pGenoType->GetChildWindowFeature( nNo ); + else + nNo = nNo - nBaseCount; + } + +#ifdef DBG_UTIL + USHORT nCWCount = pImpData->pChildWindows->Count(); + DBG_ASSERT( nNo<nCWCount,"ChildWindow ist unbekannt!" ); +#endif + return (*pImpData->pChildWindows)[nNo]->nFeature; +} + +//-------------------------------------------------------------------- + + +USHORT SfxInterface::GetChildWindowCount() const +{ + if (pGenoType) + return pImpData->pChildWindows->Count() + pGenoType->GetChildWindowCount(); + else + return pImpData->pChildWindows->Count(); +} + + +const ResId& SfxInterface::GetPopupMenuResId() const +{ + return pImpData->aPopupRes; +} + + +const ResId& SfxInterface::GetStatusBarResId() const +{ + if (pImpData->aStatBarRes.GetId() == 0 && pGenoType) + return pGenoType->GetStatusBarResId(); + else + return pImpData->aStatBarRes; +} + + + +const String* SfxInterface::GetObjectBarName ( USHORT nNo ) const +{ + BOOL bGenoType = (pGenoType != 0 && !pGenoType->HasName()); + if ( bGenoType ) + { + // Gibt es Toolbars in der Superklasse ? + USHORT nBaseCount = pGenoType->GetObjectBarCount(); + if ( nNo < nBaseCount ) + // Die der Superklasse kommen zuerst + return pGenoType->GetObjectBarName( nNo ); + else + nNo = nNo - nBaseCount; + } + +#ifdef DBG_UTIL + USHORT nObjBarCount = pImpData->pObjectBars->Count(); + DBG_ASSERT( nNo<nObjBarCount,"Objectbar ist unbekannt!" ); +#endif + return (*pImpData->pObjectBars)[nNo]->pName; +} + +sal_uInt32 SfxInterface::GetObjectBarFeature ( USHORT nNo ) const +{ + BOOL bGenoType = (pGenoType != 0 && !pGenoType->HasName()); + if ( bGenoType ) + { + // Gibt es Toolbars in der Superklasse ? + USHORT nBaseCount = pGenoType->GetObjectBarCount(); + if ( nNo < nBaseCount ) + // Die der Superklasse kommen zuerst + return pGenoType->GetObjectBarFeature( nNo ); + else + nNo = nNo - nBaseCount; + } + +#ifdef DBG_UTIL + USHORT nObjBarCount = pImpData->pObjectBars->Count(); + DBG_ASSERT( nNo<nObjBarCount,"Objectbar ist unbekannt!" ); +#endif + return (*pImpData->pObjectBars)[nNo]->nFeature; +} + +BOOL SfxInterface::IsObjectBarVisible(USHORT nNo) const +{ + BOOL bGenoType = (pGenoType != 0 && !pGenoType->HasName()); + if ( bGenoType ) + { + // Gibt es Toolbars in der Superklasse ? + USHORT nBaseCount = pGenoType->GetObjectBarCount(); + if ( nNo < nBaseCount ) + // Die der Superklasse kommen zuerst + return pGenoType->IsObjectBarVisible( nNo ); + else + nNo = nNo - nBaseCount; + } + +#ifdef DBG_UTIL + USHORT nObjBarCount = pImpData->pObjectBars->Count(); + DBG_ASSERT( nNo<nObjBarCount,"Objectbar ist unbekannt!" ); +#endif + return (*pImpData->pObjectBars)[nNo]->bVisible; +} + +const SfxInterface* SfxInterface::GetRealInterfaceForSlot( const SfxSlot *pRealSlot ) const +{ + DBG_ASSERT( pImpData->bRegistered, "Interface not registered!" ); + const SfxInterface* pInterface = this; + + // Der Slot k"onnte auch aus dem Interface einer Shell-Basisklasse stammen + do + { + const SfxSlot *pLastSlot = (*pInterface)[pInterface->Count()-1]; + const SfxSlot *pFirstSlot = (*pInterface)[0]; + + // Ist pInterface der Owner von pRealSlot ? + if ( pFirstSlot <= pRealSlot && pRealSlot <= pLastSlot ) + break; + + // Sonst Interface der Superklasse probieren + pInterface = pInterface->pGenoType; + } + while ( pInterface ); + + return pInterface; +} + + + diff --git a/sfx2/source/control/querystatus.cxx b/sfx2/source/control/querystatus.cxx new file mode 100644 index 000000000000..bee4a5c87675 --- /dev/null +++ b/sfx2/source/control/querystatus.cxx @@ -0,0 +1,241 @@ +/************************************************************************* + * + * 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 <sfx2/querystatus.hxx> +#include <svl/poolitem.hxx> +#include <svl/eitem.hxx> +#include <svl/stritem.hxx> +#include <svl/intitem.hxx> +#include <svl/itemset.hxx> +#include <svtools/itemdel.hxx> +#include <svl/visitem.hxx> +#include <cppuhelper/weak.hxx> +#include <comphelper/processfactory.hxx> +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/frame/status/ItemStatus.hpp> +#include <com/sun/star/frame/status/ItemState.hpp> +#include <com/sun/star/frame/status/Visibility.hpp> + +using ::rtl::OUString; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::frame::status; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; + +class SfxQueryStatus_Impl : public ::com::sun::star::frame::XStatusListener , + public ::com::sun::star::lang::XTypeProvider , + public ::cppu::OWeakObject +{ + public: + SFX_DECL_XINTERFACE_XTYPEPROVIDER + + SfxQueryStatus_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider >& rDispatchProvider, USHORT nSlotId, const rtl::OUString& aCommand ); + virtual ~SfxQueryStatus_Impl(); + + // Query method + SfxItemState QueryState( SfxPoolItem*& pPoolItem ); + + // XEventListener + virtual void SAL_CALL disposing(const ::com::sun::star::lang::EventObject& Source) throw( ::com::sun::star::uno::RuntimeException ); + + // XStatusListener + virtual void SAL_CALL statusChanged(const ::com::sun::star::frame::FeatureStateEvent& Event) throw( ::com::sun::star::uno::RuntimeException ); + + private: + SfxQueryStatus_Impl( const SfxQueryStatus& ); + SfxQueryStatus_Impl(); + SfxQueryStatus_Impl& operator=( const SfxQueryStatus& ); + + sal_Bool m_bQueryInProgress; + SfxItemState m_eState; + SfxPoolItem* m_pItem; + USHORT m_nSlotID; + osl::Condition m_aCondition; + ::com::sun::star::util::URL m_aCommand; + com::sun::star::uno::Reference< com::sun::star::frame::XDispatch > m_xDispatch; +}; + +SFX_IMPL_XINTERFACE_2( SfxQueryStatus_Impl, OWeakObject, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener ) +SFX_IMPL_XTYPEPROVIDER_2( SfxQueryStatus_Impl, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener ) + +SfxQueryStatus_Impl::SfxQueryStatus_Impl( const Reference< XDispatchProvider >& rDispatchProvider, USHORT nSlotId, const OUString& rCommand ) : + cppu::OWeakObject(), + m_bQueryInProgress( sal_False ), + m_eState( SFX_ITEM_DISABLED ), + m_pItem( 0 ), + m_nSlotID( nSlotId ) +{ + m_aCommand.Complete = rCommand; + Reference < XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance( + rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY ); + xTrans->parseStrict( m_aCommand ); + if ( rDispatchProvider.is() ) + m_xDispatch = rDispatchProvider->queryDispatch( m_aCommand, rtl::OUString(), 0 ); + m_aCondition.reset(); +} + +SfxQueryStatus_Impl::~SfxQueryStatus_Impl() +{ +} + +void SAL_CALL SfxQueryStatus_Impl::disposing( const EventObject& ) +throw( RuntimeException ) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + m_xDispatch.clear(); +} + +void SAL_CALL SfxQueryStatus_Impl::statusChanged( const FeatureStateEvent& rEvent) +throw( RuntimeException ) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + m_pItem = NULL; + m_eState = SFX_ITEM_DISABLED; + + if ( rEvent.IsEnabled ) + { + m_eState = SFX_ITEM_AVAILABLE; + ::com::sun::star::uno::Type pType = rEvent.State.getValueType(); + + if ( pType == ::getBooleanCppuType() ) + { + sal_Bool bTemp = false; + rEvent.State >>= bTemp ; + m_pItem = new SfxBoolItem( m_nSlotID, bTemp ); + } + else if ( pType == ::getCppuType((const sal_uInt16*)0) ) + { + sal_uInt16 nTemp = 0; + rEvent.State >>= nTemp ; + m_pItem = new SfxUInt16Item( m_nSlotID, nTemp ); + } + else if ( pType == ::getCppuType((const sal_uInt32*)0) ) + { + sal_uInt32 nTemp = 0; + rEvent.State >>= nTemp ; + m_pItem = new SfxUInt32Item( m_nSlotID, nTemp ); + } + else if ( pType == ::getCppuType((const ::rtl::OUString*)0) ) + { + ::rtl::OUString sTemp ; + rEvent.State >>= sTemp ; + m_pItem = new SfxStringItem( m_nSlotID, sTemp ); + } + else if ( pType == ::getCppuType((const ::com::sun::star::frame::status::ItemStatus*)0) ) + { + ItemStatus aItemStatus; + rEvent.State >>= aItemStatus; + m_eState = aItemStatus.State; + m_pItem = new SfxVoidItem( m_nSlotID ); + } + else if ( pType == ::getCppuType((const ::com::sun::star::frame::status::Visibility*)0) ) + { + Visibility aVisibilityStatus; + rEvent.State >>= aVisibilityStatus; + m_pItem = new SfxVisibilityItem( m_nSlotID, aVisibilityStatus.bVisible ); + } + else + { + m_eState = SFX_ITEM_UNKNOWN; + m_pItem = new SfxVoidItem( m_nSlotID ); + } + } + + if ( m_pItem ) + DeleteItemOnIdle( m_pItem ); + + try + { + m_aCondition.set(); + m_xDispatch->removeStatusListener( Reference< XStatusListener >( static_cast< cppu::OWeakObject* >( this ), UNO_QUERY ), + m_aCommand ); + } + catch ( Exception& ) + { + } +} + +// Query method +SfxItemState SfxQueryStatus_Impl::QueryState( SfxPoolItem*& rpPoolItem ) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( !m_bQueryInProgress ) + { + m_pItem = NULL; + m_eState = SFX_ITEM_DISABLED; + + if ( m_xDispatch.is() ) + { + try + { + m_aCondition.reset(); + m_bQueryInProgress = sal_True; + m_xDispatch->addStatusListener( Reference< XStatusListener >( static_cast< cppu::OWeakObject* >( this ), UNO_QUERY ), + m_aCommand ); + } + catch ( Exception& ) + { + m_aCondition.set(); + } + } + else + m_aCondition.set(); + } + + m_aCondition.wait(); + + m_bQueryInProgress = sal_False; + rpPoolItem = m_pItem; + return m_eState; +} + +//************************************************************************* + +SfxQueryStatus::SfxQueryStatus( const Reference< XDispatchProvider >& rDispatchProvider, USHORT nSlotId, const OUString& rCommand ) +{ + m_pSfxQueryStatusImpl = new SfxQueryStatus_Impl( rDispatchProvider, nSlotId, rCommand ); + m_xStatusListener = Reference< XStatusListener >( + static_cast< cppu::OWeakObject* >( m_pSfxQueryStatusImpl ), + UNO_QUERY ); +} + +SfxQueryStatus::~SfxQueryStatus() +{ +} + +SfxItemState SfxQueryStatus::QueryState( SfxPoolItem*& rpPoolItem ) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + return m_pSfxQueryStatusImpl->QueryState( rpPoolItem ); +} diff --git a/sfx2/source/control/request.cxx b/sfx2/source/control/request.cxx new file mode 100644 index 000000000000..88a52d0ad0bf --- /dev/null +++ b/sfx2/source/control/request.cxx @@ -0,0 +1,978 @@ +/************************************************************************* + * + * 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 <com/sun/star/frame/DispatchStatement.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/frame/XDispatchRecorderSupplier.hpp> +#include <svl/itemiter.hxx> + +#ifndef _ARGS_HXX //autogen +#include <svl/itempool.hxx> +#endif +#include <svtools/itemdel.hxx> + +#include <comphelper/processfactory.hxx> + +#ifndef GCC +#endif + +#include <svl/smplhint.hxx> + +#include <sfx2/request.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/msg.hxx> +#include <sfx2/viewfrm.hxx> +#include "macro.hxx" +#include <sfx2/objface.hxx> +#include <sfx2/appuno.hxx> + +//=================================================================== + +using namespace ::com::sun::star; + +struct SfxRequest_Impl: public SfxListener + +/* [Beschreibung] + + Implementations-Struktur der Klasse <SfxRequest>. +*/ + +{ + SfxRequest* pAnti; // Owner wegen sterbendem Pool + String aTarget; // ggf. von App gesetztes Zielobjekt + SfxItemPool* pPool; // ItemSet mit diesem Pool bauen + SfxPoolItem* pRetVal; // R"uckgabewert geh"ort sich selbst + SfxShell* pShell; // ausgef"uhrt an dieser Shell + const SfxSlot* pSlot; // ausgef"uhrter Slot + USHORT nModifier; // welche Modifier waren gedrueckt? + BOOL bDone; // "uberhaupt ausgef"uhrt + BOOL bIgnored; // vom User abgebrochen + BOOL bCancelled; // nicht mehr zustellen + BOOL bUseTarget; // aTarget wurde von Applikation gesetzt + USHORT nCallMode; // Synch/Asynch/API/Record + BOOL bAllowRecording; + SfxAllItemSet* pInternalArgs; + SfxViewFrame* pViewFrame; + + com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder > xRecorder; + + SfxRequest_Impl( SfxRequest *pOwner ) + : pAnti( pOwner) + , pPool(0) + , nModifier(0) + , bCancelled(FALSE) + , nCallMode( SFX_CALLMODE_SYNCHRON ) + , bAllowRecording( FALSE ) + , pInternalArgs( 0 ) + , pViewFrame(0) + {} + ~SfxRequest_Impl() { delete pInternalArgs; } + + + void SetPool( SfxItemPool *pNewPool ); + virtual void Notify( SfxBroadcaster &rBC, const SfxHint &rHint ); + void Record( const uno::Sequence < beans::PropertyValue >& rArgs ); +}; + + +//==================================================================== + +void SfxRequest_Impl::Notify( SfxBroadcaster&, const SfxHint &rHint ) +{ + SfxSimpleHint *pSimpleHint = PTR_CAST(SfxSimpleHint, &rHint); + if ( pSimpleHint && pSimpleHint->GetId() == SFX_HINT_DYING ) + pAnti->Cancel(); +} + +//==================================================================== + +void SfxRequest_Impl::SetPool( SfxItemPool *pNewPool ) +{ + if ( pNewPool != pPool ) + { + if ( pPool ) + EndListening( pPool->BC() ); + pPool = pNewPool; + if ( pNewPool ) + StartListening( pNewPool->BC() ); + } +} + +//==================================================================== + + +SfxRequest::~SfxRequest() +{ + DBG_MEMTEST(); + + // nicht mit Done() marktierte Requests mit 'rem' rausschreiben + if ( pImp->xRecorder.is() && !pImp->bDone && !pImp->bIgnored ) + pImp->Record( uno::Sequence < beans::PropertyValue >() ); + + // Objekt abr"aumen + delete pArgs; + if ( pImp->pRetVal ) + DeleteItemOnIdle(pImp->pRetVal); + delete pImp; +} +//-------------------------------------------------------------------- + + +SfxRequest::SfxRequest +( + const SfxRequest& rOrig +) +: SfxHint( rOrig ), + nSlot(rOrig.nSlot), + pArgs(rOrig.pArgs? new SfxAllItemSet(*rOrig.pArgs): 0), + pImp( new SfxRequest_Impl(this) ) +{ + DBG_MEMTEST(); + + pImp->bAllowRecording = rOrig.pImp->bAllowRecording; + pImp->bDone = FALSE; + pImp->bIgnored = FALSE; + pImp->pRetVal = 0; + pImp->pShell = 0; + pImp->pSlot = 0; + pImp->nCallMode = rOrig.pImp->nCallMode; + pImp->bUseTarget = rOrig.pImp->bUseTarget; + pImp->aTarget = rOrig.pImp->aTarget; + pImp->nModifier = rOrig.pImp->nModifier; + + // deep copy needed ! + pImp->pInternalArgs = (rOrig.pImp->pInternalArgs ? new SfxAllItemSet(*rOrig.pImp->pInternalArgs) : 0); + + if ( pArgs ) + pImp->SetPool( pArgs->GetPool() ); + else + pImp->SetPool( rOrig.pImp->pPool ); +} +//-------------------------------------------------------------------- + + +SfxRequest::SfxRequest +( + SfxViewFrame* pViewFrame, + USHORT nSlotId + +) + +/* [Beschreibung] + + Mit diesem Konstruktor k"onnen Events, die nicht "uber den SfxDispatcher + gelaufen sind (z.B aus KeyInput() oder Mouse-Events) nachtr"aglich + recorded werden. Dazu wird eine SfxRequest-Instanz mit diesem Konstruktor + erzeugt und dann genauso verfahren, wie mit einem SfxRequest, der in + eine <Slot-Execute-Methode> als Parameter gegeben wird. +*/ + +: nSlot(nSlotId), + pArgs(0), + pImp( new SfxRequest_Impl(this) ) +{ + DBG_MEMTEST(); + + pImp->bDone = FALSE; + pImp->bIgnored = FALSE; + pImp->SetPool( &pViewFrame->GetPool() ); + pImp->pRetVal = 0; + pImp->pShell = 0; + pImp->pSlot = 0; + pImp->nCallMode = SFX_CALLMODE_SYNCHRON; + pImp->bUseTarget = FALSE; + pImp->pViewFrame = pViewFrame; + if( pImp->pViewFrame->GetDispatcher()->GetShellAndSlot_Impl( nSlotId, &pImp->pShell, &pImp->pSlot, TRUE, TRUE ) ) + { + pImp->SetPool( &pImp->pShell->GetPool() ); + pImp->xRecorder = SfxRequest::GetMacroRecorder( pViewFrame ); + pImp->aTarget = pImp->pShell->GetName(); + } +#ifdef DBG_UTIL + else + { + ByteString aStr( "Recording unsupported slot: "); + aStr += ByteString::CreateFromInt32( pImp->pPool->GetSlotId(nSlotId) ); + DBG_ERROR( aStr.GetBuffer() ); + } +#endif +} + +//-------------------------------------------------------------------- + + +SfxRequest::SfxRequest +( + USHORT nSlotId, // auszuf"uhrende <Slot-Id> + SfxCallMode nMode, // Synch/API/... + SfxItemPool& rPool // ggf. f"ur das SfxItemSet f"ur Parameter +) + +// creates a SfxRequest without arguments + +: nSlot(nSlotId), + pArgs(0), + pImp( new SfxRequest_Impl(this) ) +{ + DBG_MEMTEST(); + + pImp->bDone = FALSE; + pImp->bIgnored = FALSE; + pImp->SetPool( &rPool ); + pImp->pRetVal = 0; + pImp->pShell = 0; + pImp->pSlot = 0; + pImp->nCallMode = nMode; + pImp->bUseTarget = FALSE; +} + +SfxRequest::SfxRequest +( + const SfxSlot* pSlot, // auszuf"uhrende <Slot-Id> + const com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue >& rArgs, + SfxCallMode nMode, // Synch/API/... + SfxItemPool& rPool // ggf. f"ur das SfxItemSet f"ur Parameter +) +: nSlot(pSlot->GetSlotId()), + pArgs(new SfxAllItemSet(rPool)), + pImp( new SfxRequest_Impl(this) ) +{ + DBG_MEMTEST(); + + pImp->bDone = FALSE; + pImp->bIgnored = FALSE; + pImp->SetPool( &rPool ); + pImp->pRetVal = 0; + pImp->pShell = 0; + pImp->pSlot = 0; + pImp->nCallMode = nMode; + pImp->bUseTarget = FALSE; + TransformParameters( nSlot, rArgs, *pArgs, pSlot ); +} + +//----------------------------------------------------------------------- + +SfxRequest::SfxRequest +( + USHORT nSlotId, + USHORT nMode, + const SfxAllItemSet& rSfxArgs +) + +// creates a SfxRequest with arguments + +: nSlot(nSlotId), + pArgs(new SfxAllItemSet(rSfxArgs)), + pImp( new SfxRequest_Impl(this) ) +{ + DBG_MEMTEST(); + + pImp->bDone = FALSE; + pImp->bIgnored = FALSE; + pImp->SetPool( rSfxArgs.GetPool() ); + pImp->pRetVal = 0; + pImp->pShell = 0; + pImp->pSlot = 0; + pImp->nCallMode = nMode; + pImp->bUseTarget = FALSE; +} +//-------------------------------------------------------------------- + +USHORT SfxRequest::GetCallMode() const +{ + return pImp->nCallMode; +} + +//-------------------------------------------------------------------- + +BOOL SfxRequest::IsSynchronCall() const +{ + return SFX_CALLMODE_SYNCHRON == ( SFX_CALLMODE_SYNCHRON & pImp->nCallMode ); +} + +//-------------------------------------------------------------------- + +void SfxRequest::SetSynchronCall( BOOL bSynchron ) +{ + if ( bSynchron ) + pImp->nCallMode |= SFX_CALLMODE_SYNCHRON; + else + pImp->nCallMode &= ~(USHORT) SFX_CALLMODE_SYNCHRON; +} + +void SfxRequest::SetInternalArgs_Impl( const SfxAllItemSet& rArgs ) +{ + delete pImp->pInternalArgs; + pImp->pInternalArgs = new SfxAllItemSet( rArgs ); +} + +const SfxItemSet* SfxRequest::GetInternalArgs_Impl() const +{ + return pImp->pInternalArgs; +} + +//-------------------------------------------------------------------- + + +void SfxRequest_Impl::Record +( + const uno::Sequence < beans::PropertyValue >& rArgs // aktuelle Parameter +) + +/* [Beschreibung] + + Interne Hilfsmethode zum erzeugen einer <SfxMacroStatement>-Instanz, + welche den bereits ausgef"uhrten SfxRequest wiederholbar beschreibt. + + Die erzeugte Instanz, auf die ein Pointer zur"uckgeliefert wird + geht in das Eigentum des Aufrufers "uber. +*/ + +{ + String aCommand = String::CreateFromAscii(".uno:"); + aCommand.AppendAscii( pSlot->GetUnoName() ); + ::rtl::OUString aCmd( aCommand ); + if(xRecorder.is()) + { + uno::Reference< container::XIndexReplace > xReplace( xRecorder, uno::UNO_QUERY ); + if ( xReplace.is() && aCmd.compareToAscii(".uno:InsertText") == COMPARE_EQUAL ) + { + sal_Int32 nCount = xReplace->getCount(); + if ( nCount ) + { + frame::DispatchStatement aStatement; + uno::Any aElement = xReplace->getByIndex(nCount-1); + if ( (aElement >>= aStatement) && aStatement.aCommand == aCmd ) + { + ::rtl::OUString aStr; + ::rtl::OUString aNew; + aStatement.aArgs[0].Value >>= aStr; + rArgs[0].Value >>= aNew; + aStr += aNew; + aStatement.aArgs[0].Value <<= aStr; + aElement <<= aStatement; + xReplace->replaceByIndex( nCount-1, aElement ); + return; + } + } + } + + com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > xFactory( + ::comphelper::getProcessServiceFactory(), + com::sun::star::uno::UNO_QUERY); + + com::sun::star::uno::Reference< com::sun::star::util::XURLTransformer > xTransform( + xFactory->createInstance(rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer")), + com::sun::star::uno::UNO_QUERY); + + com::sun::star::util::URL aURL; + aURL.Complete = aCmd; + xTransform->parseStrict(aURL); + + if (bDone) + xRecorder->recordDispatch(aURL,rArgs); + else + xRecorder->recordDispatchAsComment(aURL,rArgs); + } +} + +//-------------------------------------------------------------------- + +void SfxRequest::Record_Impl +( + SfxShell& rSh, // die <SfxShell>, die den Request ausgef"uhrt hat + const SfxSlot& rSlot, // der <SfxSlot>, der den Request ausgef"uhrt hat + com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder > xRecorder, // der Recorder, mit dem aufgezeichnet wird + SfxViewFrame* pViewFrame +) + +/* [Beschreibung] + + Diese interne Methode markiert den SfxRequest als in dem angegebenen + SfxMakro aufzuzeichnen. + + Pointer auf die Parameter werden in Done() wieder verwendet, m"usseb + dann also noch leben. +*/ + +{ + DBG_MEMTEST(); + pImp->pShell = &rSh; + pImp->pSlot = &rSlot; + pImp->xRecorder = xRecorder; + pImp->aTarget = rSh.GetName(); + pImp->pViewFrame = pViewFrame; +} + +//-------------------------------------------------------------------- + +void SfxRequest::SetArgs( const SfxAllItemSet& rArgs ) +{ + delete pArgs; + pArgs = new SfxAllItemSet(rArgs); + pImp->SetPool( pArgs->GetPool() ); +} + +//-------------------------------------------------------------------- + +void SfxRequest::AppendItem(const SfxPoolItem &rItem) +{ + if(!pArgs) + pArgs = new SfxAllItemSet(*pImp->pPool); + pArgs->Put(rItem, rItem.Which()); +} + +//-------------------------------------------------------------------- + +void SfxRequest::RemoveItem( USHORT nID ) +{ + if (pArgs) + { + pArgs->ClearItem(nID); + if ( !pArgs->Count() ) + DELETEZ(pArgs); + } +} + +//-------------------------------------------------------------------- + +const SfxPoolItem* SfxRequest::GetArg +( + USHORT nSlotId, // Slot-Id oder Which-Id des Parameters + FASTBOOL bDeep, // FALSE: nicht in Parent-ItemSets suchen + TypeId aType // != 0: RTTI Pruefung mit Assertion +) const +{ + return GetItem( pArgs, nSlotId, bDeep, aType ); +} + + +//-------------------------------------------------------------------- +const SfxPoolItem* SfxRequest::GetItem +( + const SfxItemSet* pArgs, + USHORT nSlotId, // Slot-Id oder Which-Id des Parameters + bool bDeep, // false: nicht in Parent-ItemSets suchen + TypeId aType // != 0: RTTI Pruefung mit Assertion +) + +/* [Beschreibung] + + Mit dieser Methode wird der Zugriff auf einzelne Parameter im + SfxRequest wesentlich vereinfacht. Insbesondere wird die Typpr"ufung + (per Assertion) durchgef"uhrt, wodurch die Applikations-Sourcen + wesentlich "ubersichtlicher werden. In der PRODUCT-Version wird + eine 0 zur"uckgegeben, wenn das gefundene Item nicht von der + angegebenen Klasse ist. + + + [Beispiel] + + void MyShell::Execute( SfxRequest &rReq ) + { + switch ( rReq.GetSlot() ) + { + case SID_MY: + { + ... + // ein Beispiel ohne Verwendung des Makros + const SfxInt32Item *pPosItem = (const SfxUInt32Item*) + rReq.GetArg( SID_POS, FALSE, TYPE(SfxInt32Item) ); + USHORT nPos = pPosItem ? pPosItem->GetValue() : 0; + + // ein Beispiel mit Verwendung des Makros + SFX_REQUEST_ARG(rReq, pSizeItem, SfxInt32Item, SID_SIZE, FALSE); + USHORT nSize = pSizeItem ? pPosItem->GetValue() : 0; + + ... + } + + ... + } + } +*/ + +{ + if ( pArgs ) + { + // ggf. in Which-Id umrechnen + USHORT nWhich = pArgs->GetPool()->GetWhich(nSlotId); + + // ist das Item gesetzt oder bei bDeep==TRUE verf"ugbar? + const SfxPoolItem *pItem = 0; + if ( ( bDeep ? SFX_ITEM_AVAILABLE : SFX_ITEM_SET ) + <= pArgs->GetItemState( nWhich, bDeep, &pItem ) ) + { + // stimmt der Typ "uberein? + if ( !pItem || pItem->IsA(aType) ) + return pItem; + + // Item da aber falsch => Programmierfehler + DBG_ERROR( "invalid argument type" ); + } + } + + // keine Parameter, nicht gefunden oder falschen Typ gefunden + return 0; +} + +//-------------------------------------------------------------------- + +void SfxRequest::SetReturnValue(const SfxPoolItem &rItem) +{ + DBG_ASSERT(!pImp->pRetVal, "Returnwert mehrfach setzen?"); + if(pImp->pRetVal) + delete pImp->pRetVal; + pImp->pRetVal = rItem.Clone(); +} + +//-------------------------------------------------------------------- + +const SfxPoolItem* SfxRequest::GetReturnValue() const +{ + return pImp->pRetVal; +} + +//-------------------------------------------------------------------- + +void SfxRequest::Done +( + const SfxItemSet& rSet, /* von der Applikation mitgeteilte Parameter, + die z.B. in einem Dialog vom Benuter + erfragt wurden, ggf. 0 falls keine + Parameter gesetzt wurden */ + + FASTBOOL bKeep /* TRUE (default) + 'rSet' wird gepeichert und ist "uber + GetArgs() abfragbar + + FALSE + 'rSet' wird nicht kopiert (schneller) */ +) + +/* [Beschreibung] + + Diese Methode mu\s in der <Execute-Methode> des <SfxSlot>s gerufen + werden, der den SfxRequest ausgef"uhrt hat, wenn die Ausf"uhrung + tats"achlich stattgefunden hat. Wird 'Done()' nicht gerufen, gilt + der SfxRequest als abgebrochen. + + Etwaige Returnwerte werden nur durchgereicht, wenn 'Done()' gerufen + wurde. Ebenso werden beim Aufzeichnen von Makros nur echte + Statements erzeugt, wenn 'Done()' gerufen wurde; f"ur SfxRequests, + die nicht derart gekennzeichnet wurden, wird anstelle dessen eine + auf die abgebrochene Funktion hinweisende Bemerkung ('rem') eingf"ugt. + + + [Anmerkung] + + 'Done()' wird z.B. nicht gerufen, wenn ein durch die Funktion gestarteter + Dialog vom Benutzer abgebrochen wurde oder das Ausf"uhren aufgrund + eines falschen Kontextes (ohne Verwendung separater <SfxShell>s) + nicht durchgef"uhrt werden konnte. 'Done()' mu\s sehr wohl gerufen + werden, wenn das Ausf"uhren der Funktion zu einem regul"aren Fehler + f"uhrte (z.B. Datei konnte nicht ge"offnet werden). +*/ + +{ + Done_Impl( &rSet ); + + // ggf. Items merken, damit StarDraw sie abfragen kann + if ( bKeep ) + { + if ( !pArgs ) + { + pArgs = new SfxAllItemSet( rSet ); + pImp->SetPool( pArgs->GetPool() ); + } + else + { + SfxItemIter aIter(rSet); + const SfxPoolItem* pItem = aIter.FirstItem(); + while(pItem) + { + if(!IsInvalidItem(pItem)) + pArgs->Put(*pItem,pItem->Which()); + pItem = aIter.NextItem(); + } + } + } +} + +//-------------------------------------------------------------------- + + +void SfxRequest::Done( BOOL bRelease ) +// [<SfxRequest::Done(SfxItemSet&)>] +{ + Done_Impl( pArgs ); + if( bRelease ) + DELETEZ( pArgs ); +} + +//-------------------------------------------------------------------- + +void SfxRequest::ForgetAllArgs() +{ + DELETEZ( pArgs ); + DELETEZ( pImp->pInternalArgs ); +} + +//-------------------------------------------------------------------- + +BOOL SfxRequest::IsCancelled() const +{ + return pImp->bCancelled; +} + +//-------------------------------------------------------------------- + +void SfxRequest::Cancel() + +/* [Beschreibung] + + Markiert diesen Request als nicht mehr auszufuehren. Wird z.B. gerufen, + wenn das Ziel (genauer dessen Pool) stirbt. +*/ + +{ + pImp->bCancelled = TRUE; + pImp->SetPool( 0 ); + DELETEZ( pArgs ); +} + +//-------------------------------------------------------------------- + + +void SfxRequest::Ignore() + +/* [Beschreibung] + + Wird diese Methode anstelle von <SfxRequest::Done()> gerufen, dann + wird dieser Request nicht recorded. + + + [Bespiel] + + Das Selektieren von Tools im StarDraw soll nicht aufgezeichnet werden, + dieselben Slots sollen aber zum erzeugen der von den Tools zu + erzeugenden Objekte verwendet werde. Also kann nicht NoRecord + angegeben werden, dennoch soll u.U. nicht aufgezeichnet werden. +*/ + +{ + // als tats"achlich ausgef"uhrt markieren + pImp->bIgnored = TRUE; +} + +//-------------------------------------------------------------------- + +void SfxRequest::Done_Impl +( + const SfxItemSet* pSet /* von der Applikation mitgeteilte Parameter, + die z.B. in einem Dialog vom Benuter + erfragt wurden, ggf. 0 falls keine + Parameter gesetzt wurden */ +) + +/* [Beschreibung] + + Interne Methode zum als 'done' markieren des SfxRequest und zum Auswerten + der Parameter in 'pSet' falls aufgezeichnet wird. +*/ + +{ + // als tats"achlich ausgef"uhrt markieren + pImp->bDone = TRUE; + + // nicht Recorden + if ( !pImp->xRecorder.is() ) + return; + + // wurde ein anderer Slot ausgef"uhrt als angefordert (Delegation) + if ( nSlot != pImp->pSlot->GetSlotId() ) + { + // Slot neu suchen + pImp->pSlot = pImp->pShell->GetInterface()->GetSlot(nSlot); + DBG_ASSERT( pImp->pSlot, "delegated SlotId not found" ); + if ( !pImp->pSlot ) // Hosentr"ger und G"urtel + return; + } + + // record-f"ahig? + // neues Recorden verwendet UnoName! + if ( !pImp->pSlot->pUnoName ) + { + ByteString aStr( "Recording not exported slot: "); + aStr += ByteString::CreateFromInt32( pImp->pSlot->GetSlotId() ); + DBG_ERROR( aStr.GetBuffer() ); + } + + if ( !pImp->pSlot->pUnoName ) // Hosentr"ger und G"urtel + return; + + // "ofters ben"otigte Werte + SfxItemPool &rPool = pImp->pShell->GetPool(); + + // Property-Slot? + if ( !pImp->pSlot->IsMode(SFX_SLOT_METHOD) ) + { + // des Property als SfxPoolItem besorgen + const SfxPoolItem *pItem; + USHORT nWhich = rPool.GetWhich(pImp->pSlot->GetSlotId()); + SfxItemState eState = pSet ? pSet->GetItemState( nWhich, FALSE, &pItem ) : SFX_ITEM_UNKNOWN; +#ifdef DBG_UTIL + if ( SFX_ITEM_SET != eState ) + { + ByteString aStr( "Recording property not available: "); + aStr += ByteString::CreateFromInt32( pImp->pSlot->GetSlotId() ); + DBG_ERROR( aStr.GetBuffer() ); + } +#endif + uno::Sequence < beans::PropertyValue > aSeq; + if ( eState == SFX_ITEM_SET ) + TransformItems( pImp->pSlot->GetSlotId(), *pSet, aSeq, pImp->pSlot ); + pImp->Record( aSeq ); + } + + // alles in ein einziges Statement aufzeichnen? + else if ( pImp->pSlot->IsMode(SFX_SLOT_RECORDPERSET) ) + { + uno::Sequence < beans::PropertyValue > aSeq; + if ( pSet ) + TransformItems( pImp->pSlot->GetSlotId(), *pSet, aSeq, pImp->pSlot ); + pImp->Record( aSeq ); + } + + // jedes Item als einzelnes Statement recorden + else if ( pImp->pSlot->IsMode(SFX_SLOT_RECORDPERITEM) ) + { + if ( pSet ) + { + // "uber die Items iterieren + SfxItemIter aIter(*pSet); + for ( const SfxPoolItem* pItem = aIter.FirstItem(); pItem; pItem = aIter.NextItem() ) + { + // die Slot-Id f"ur das einzelne Item ermitteln + USHORT nSlotId = rPool.GetSlotId( pItem->Which() ); + if ( nSlotId == nSlot ) + { + // mit Hosentr"ager und G"urtel reparieren des falschen Flags + DBG_ERROR( "recursion RecordPerItem - use RecordPerSet!" ); + SfxSlot *pSlot = (SfxSlot*) pImp->pSlot; + pSlot->nFlags &= ~((ULONG)SFX_SLOT_RECORDPERITEM); + pSlot->nFlags &= SFX_SLOT_RECORDPERSET; + } + + // einen Sub-Request recorden + SfxRequest aReq( pImp->pViewFrame, nSlotId ); + if ( aReq.pImp->pSlot ) + aReq.AppendItem( *pItem ); + aReq.Done(); + } + } + else + { + HACK(hierueber nochmal nachdenken) + pImp->Record( uno::Sequence < beans::PropertyValue >() ); + } + } +} + +//-------------------------------------------------------------------- + +BOOL SfxRequest::IsDone() const + +/* [Beschreibung] + + Mit dieser Methode kann abgefragt werden, ob der SfxRequest tats"achlich + ausgef"uhrt wurde oder nicht. Wurde ein SfxRequest nicht ausgef"uhrt, + liegt dies z.B. daran, da\s der Benutzer abgebrochen hat oder + der Kontext f"ur diesen Request falsch war, dieses aber nicht "uber + eine separate <SfxShell> realisiert wurde. + + SfxRequest-Instanzen, die hier FALSE liefern, werden nicht recorded. + + + [Querverweise] + + <SfxRequest::Done(const SfxItemSet&)> + <SfxRequest::Done()> +*/ + +{ + return pImp->bDone; +} + +//-------------------------------------------------------------------- + +SfxMacro* SfxRequest::GetRecordingMacro() + +/* [Beschreibung] + + Mit dieser Methode kann abgefragt werden, ob und in welchem <SfxMacro> + die SfxRequests gerade aufgezeichnet werden. +*/ + +{ + return NULL; +} + +//-------------------------------------------------------------------- + +com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder > SfxRequest::GetMacroRecorder( SfxViewFrame* pView ) + +/* [Beschreibung] + + Hier wird versucht einen Recorder fuer dispatch() Aufrufe vom Frame zu bekommen. + Dieser ist dort per Property an einem Supplier verfuegbar - aber nur dann, wenn + recording angeschaltet wurde. + (Siehe auch SfxViewFrame::MiscExec_Impl() und SID_RECORDING) +*/ + +{ + com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder > xRecorder; + + com::sun::star::uno::Reference< com::sun::star::beans::XPropertySet > xSet( + (pView ? pView : SfxViewFrame::Current())->GetFrame().GetFrameInterface(), + com::sun::star::uno::UNO_QUERY); + + if(xSet.is()) + { + com::sun::star::uno::Any aProp = xSet->getPropertyValue(rtl::OUString::createFromAscii("DispatchRecorderSupplier")); + com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorderSupplier > xSupplier; + aProp >>= xSupplier; + if(xSupplier.is()) + xRecorder = xSupplier->getDispatchRecorder(); + } + + return xRecorder; +} + +BOOL SfxRequest::HasMacroRecorder( SfxViewFrame* pView ) +{ + return GetMacroRecorder( pView ).is(); +} + + +//-------------------------------------------------------------------- + +BOOL SfxRequest::IsAPI() const + +/* [Beschreibung] + + Liefert TRUE, wenn dieser SfxRequest von einer API (z.B. BASIC) + erzeugt wurde, sonst FALSE. +*/ + +{ + return SFX_CALLMODE_API == ( SFX_CALLMODE_API & pImp->nCallMode ); +} + +//-------------------------------------------------------------------- + + +FASTBOOL SfxRequest::IsRecording() const + +/* [Beschreibung] + + Liefert TRUE, wenn dieser SfxRequest recorded werden soll, d.h. + 1. zu Zeit ein Makro aufgezeichnet wird + 2. dieser Request "uberhaupt aufgezeichnet wird + 3. der Request nicht von reiner API (z.B. BASIC) ausgeht, + sonst FALSE. +*/ + +{ + return ( AllowsRecording() && GetMacroRecorder().is() ); +} + +//-------------------------------------------------------------------- +void SfxRequest::SetModifier( USHORT nModi ) +{ + pImp->nModifier = nModi; +} + +//-------------------------------------------------------------------- +USHORT SfxRequest::GetModifier() const +{ + return pImp->nModifier; +} + +//-------------------------------------------------------------------- + +void SfxRequest::SetTarget( const String &rTarget ) + +/* [Beschreibung] + + Mit dieser Methode kann das zu recordende Zielobjekt umgesetzt werden. + + + [Beispiel] + + Die BASIC-Methode 'Open' wird zwar von der Shell 'Application' ausgef"uhrt, + aber am Objekt 'Documents' (global) recorded: + + rReq.SetTarget( "Documents" ); + + Dies f"uhrt dann zu: + + Documents.Open( ... ) +*/ + +{ + pImp->aTarget = rTarget; + pImp->bUseTarget = TRUE; +} + +void SfxRequest::AllowRecording( BOOL bSet ) +{ + pImp->bAllowRecording = bSet; +} + +BOOL SfxRequest::AllowsRecording() const +{ + BOOL bAllow = pImp->bAllowRecording; + if( !bAllow ) + bAllow = ( SFX_CALLMODE_API != ( SFX_CALLMODE_API & pImp->nCallMode ) ) && + ( SFX_CALLMODE_RECORD == ( SFX_CALLMODE_RECORD & pImp->nCallMode ) ); + return bAllow; +} + +void SfxRequest::ReleaseArgs() +{ + DELETEZ( pArgs ); + DELETEZ( pImp->pInternalArgs ); +} diff --git a/sfx2/source/control/sfxstatuslistener.cxx b/sfx2/source/control/sfxstatuslistener.cxx new file mode 100644 index 000000000000..c2cf5f164e7c --- /dev/null +++ b/sfx2/source/control/sfxstatuslistener.cxx @@ -0,0 +1,290 @@ +/************************************************************************* + * + * 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 <sfx2/sfxstatuslistener.hxx> +#include <svl/poolitem.hxx> +#include <svl/eitem.hxx> +#include <svl/stritem.hxx> +#include <svl/intitem.hxx> +#include <svl/itemset.hxx> +#include <svtools/itemdel.hxx> +#include <svl/visitem.hxx> +#include <cppuhelper/weak.hxx> +#include <comphelper/processfactory.hxx> +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/frame/status/ItemStatus.hpp> +#include <com/sun/star/frame/status/ItemState.hpp> +#include <com/sun/star/frame/status/Visibility.hpp> + +#include <sfx2/viewfrm.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/unoctitm.hxx> +#include <sfx2/msgpool.hxx> + +using ::rtl::OUString; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::frame::status; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; + +SFX_IMPL_XINTERFACE_3( SfxStatusListener, OWeakObject, ::com::sun::star::lang::XComponent, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener ) +SFX_IMPL_XTYPEPROVIDER_3( SfxStatusListener, ::com::sun::star::lang::XComponent, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener ) + +SfxStatusListener::SfxStatusListener( const Reference< XDispatchProvider >& rDispatchProvider, USHORT nSlotId, const OUString& rCommand ) : + cppu::OWeakObject(), + m_nSlotID( nSlotId ), + m_xDispatchProvider( rDispatchProvider ) +{ + m_aCommand.Complete = rCommand; + Reference < XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance( + rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY ); + xTrans->parseStrict( m_aCommand ); + if ( rDispatchProvider.is() ) + m_xDispatch = rDispatchProvider->queryDispatch( m_aCommand, rtl::OUString(), 0 ); +} + +SfxStatusListener::~SfxStatusListener() +{ +} + +// old sfx controller item C++ API +void SfxStatusListener::StateChanged( USHORT, SfxItemState, const SfxPoolItem* ) +{ + // must be implemented by sub class +} + +void SfxStatusListener::Bind() +{ + if ( !m_xDispatch.is() && m_xDispatchProvider.is() ) + { + m_xDispatch = m_xDispatchProvider->queryDispatch( m_aCommand, rtl::OUString(), 0 ); + try + { + Reference< XStatusListener > aStatusListener( static_cast< OWeakObject* >( this ), UNO_QUERY ); + m_xDispatch->addStatusListener( aStatusListener, m_aCommand ); + } + catch( Exception& ) + { + } + } +} + +void SfxStatusListener::Bind( USHORT nSlotId, const rtl::OUString& rNewCommand ) +{ + // first remove old listener, if we have a dispatch object + Reference< XStatusListener > aStatusListener( static_cast< OWeakObject* >( this ), UNO_QUERY ); + if ( m_xDispatch.is() ) + m_xDispatch->removeStatusListener( aStatusListener, m_aCommand ); + if ( m_xDispatchProvider.is() ) + { + // Store new command data and query for new dispatch + m_nSlotID = nSlotId; + m_aCommand.Complete = rNewCommand; + Reference < XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance( + rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY ); + xTrans->parseStrict( m_aCommand ); + + m_xDispatch = m_xDispatchProvider->queryDispatch( m_aCommand, rtl::OUString(), 0 ); + + try + { + m_xDispatch->addStatusListener( aStatusListener, m_aCommand ); + } + catch( Exception& ) + { + } + } +} + +void SfxStatusListener::UnBind() +{ + if ( m_xDispatch.is() ) + { + Reference< XStatusListener > aStatusListener( static_cast< OWeakObject* >( this ), UNO_QUERY ); + m_xDispatch->removeStatusListener( aStatusListener, m_aCommand ); + m_xDispatch.clear(); + } +} + +void SfxStatusListener::ReBind() +{ + Reference< XStatusListener > aStatusListener( static_cast< OWeakObject* >( this ), UNO_QUERY ); + if ( m_xDispatch.is() ) + m_xDispatch->removeStatusListener( aStatusListener, m_aCommand ); + if ( m_xDispatchProvider.is() ) + { + try + { + m_xDispatch = m_xDispatchProvider->queryDispatch( m_aCommand, rtl::OUString(), 0 ); + if ( m_xDispatch.is() ) + m_xDispatch->addStatusListener( aStatusListener, m_aCommand ); + } + catch( Exception& ) + { + } + } +} + +// new UNO API +void SAL_CALL SfxStatusListener::dispose() throw( ::com::sun::star::uno::RuntimeException ) +{ + if ( m_xDispatch.is() && m_aCommand.Complete.getLength() > 0 ) + { + try + { + Reference< XStatusListener > aStatusListener( static_cast< OWeakObject* >( this ), UNO_QUERY ); + m_xDispatch->removeStatusListener( aStatusListener, m_aCommand ); + } + catch ( Exception& ) + { + } + } + + m_xDispatch.clear(); + m_xDispatchProvider.clear(); +} + +void SAL_CALL SfxStatusListener::addEventListener( const Reference< XEventListener >& ) +throw ( RuntimeException ) +{ + // do nothing - this is a wrapper class which does not support listeners +} + +void SAL_CALL SfxStatusListener::removeEventListener( const Reference< XEventListener >& ) +throw ( RuntimeException ) +{ + // do nothing - this is a wrapper class which does not support listeners +} + +void SAL_CALL SfxStatusListener::disposing( const EventObject& Source ) +throw( RuntimeException ) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + if ( Source.Source == Reference< XInterface >( m_xDispatch, UNO_QUERY )) + m_xDispatch.clear(); + else if ( Source.Source == Reference< XInterface >( m_xDispatchProvider, UNO_QUERY )) + m_xDispatchProvider.clear(); +} + +void SAL_CALL SfxStatusListener::statusChanged( const FeatureStateEvent& rEvent) +throw( RuntimeException ) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + SfxViewFrame* pViewFrame = NULL; + if ( m_xDispatch.is() ) + { + Reference< XUnoTunnel > xTunnel( m_xDispatch, 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 ) + pViewFrame = pDisp->GetDispatcher_Impl()->GetFrame(); + } + + SfxSlotPool& rPool = SfxSlotPool::GetSlotPool( pViewFrame ); + const SfxSlot* pSlot = rPool.GetSlot( m_nSlotID ); + + SfxItemState eState = SFX_ITEM_DISABLED; + SfxPoolItem* pItem = NULL; + if ( rEvent.IsEnabled ) + { + eState = SFX_ITEM_AVAILABLE; + ::com::sun::star::uno::Type pType = rEvent.State.getValueType(); + + if ( pType == ::getVoidCppuType() ) + { + pItem = new SfxVoidItem( m_nSlotID ); + eState = SFX_ITEM_UNKNOWN; + } + else if ( pType == ::getBooleanCppuType() ) + { + sal_Bool bTemp = false; + rEvent.State >>= bTemp ; + pItem = new SfxBoolItem( m_nSlotID, bTemp ); + } + else if ( pType == ::getCppuType((const sal_uInt16*)0) ) + { + sal_uInt16 nTemp = 0; + rEvent.State >>= nTemp ; + pItem = new SfxUInt16Item( m_nSlotID, nTemp ); + } + else if ( pType == ::getCppuType((const sal_uInt32*)0) ) + { + sal_uInt32 nTemp = 0; + rEvent.State >>= nTemp ; + pItem = new SfxUInt32Item( m_nSlotID, nTemp ); + } + else if ( pType == ::getCppuType((const ::rtl::OUString*)0) ) + { + ::rtl::OUString sTemp ; + rEvent.State >>= sTemp ; + pItem = new SfxStringItem( m_nSlotID, sTemp ); + } + else if ( pType == ::getCppuType((const ::com::sun::star::frame::status::ItemStatus*)0) ) + { + ItemStatus aItemStatus; + rEvent.State >>= aItemStatus; + eState = aItemStatus.State; + pItem = new SfxVoidItem( m_nSlotID ); + } + else if ( pType == ::getCppuType((const ::com::sun::star::frame::status::Visibility*)0) ) + { + Visibility aVisibilityStatus; + rEvent.State >>= aVisibilityStatus; + pItem = new SfxVisibilityItem( m_nSlotID, aVisibilityStatus.bVisible ); + } + else + { + if ( pSlot ) + pItem = pSlot->GetType()->CreateItem(); + if ( pItem ) + { + pItem->SetWhich( m_nSlotID ); + pItem->PutValue( rEvent.State ); + } + else + pItem = new SfxVoidItem( m_nSlotID ); + } + } + + StateChanged( m_nSlotID, eState, pItem ); + delete pItem; +} + diff --git a/sfx2/source/control/shell.cxx b/sfx2/source/control/shell.cxx new file mode 100644 index 000000000000..d1605754680a --- /dev/null +++ b/sfx2/source/control/shell.cxx @@ -0,0 +1,1288 @@ +/************************************************************************* + * + * 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 <com/sun/star/embed/VerbDescriptor.hpp> +#include <com/sun/star/embed/VerbAttributes.hpp> +#include <basic/sbstar.hxx> +#include <svl/itempool.hxx> +#include <svl/undo.hxx> +#include <svtools/itemdel.hxx> +#include <svtools/asynclink.hxx> +#include <basic/sbx.hxx> + +#include <unotools/undoopt.hxx> + +#ifndef GCC +#endif + +#include <sfx2/app.hxx> +#include <sfx2/shell.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/objface.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/dispatch.hxx> +#include "sfxtypes.hxx" +#include <sfx2/request.hxx> +#include <sfx2/mnumgr.hxx> +#include "statcach.hxx" +#include <sfx2/msgpool.hxx> + +//==================================================================== + +DBG_NAME(SfxShell) + +//==================================================================== + +TYPEINIT0(SfxShell); + +//==================================================================== +typedef SfxSlot* SfxSlotPtr; +SV_DECL_PTRARR_DEL( SfxVerbSlotArr_Impl, SfxSlotPtr, 4, 4) +SV_IMPL_PTRARR( SfxVerbSlotArr_Impl, SfxSlotPtr); + +using namespace com::sun::star; + +//========================================================================= +// SfxShell_Impl +//========================================================================= +struct SfxShell_Impl: public SfxBroadcaster +{ + String aObjectName;// Name des Sbx-Objects + SfxItemArray_Impl aItems; // Datenaustausch auf Item-Basis + SfxViewShell* pViewSh; // SfxViewShell falls Shell ViewFrame/ViewShell/SubShell ist + SfxViewFrame* pFrame; // Frame, falls <UI-aktiv> + SfxRepeatTarget* pRepeatTarget; +// SbxObjectRef xParent; + BOOL bInAppBASIC; + BOOL bActive; + ULONG nDisableFlags; + ULONG nHelpId; + svtools::AsynchronLink* pExecuter; + svtools::AsynchronLink* pUpdater; + SfxVerbSlotArr_Impl aSlotArr; + com::sun::star::uno::Sequence < com::sun::star::embed::VerbDescriptor > aVerbList; + SfxShell_Impl() : pExecuter( 0 ), pUpdater( 0 ) {} + ~SfxShell_Impl() { delete pExecuter; delete pUpdater;} +}; + +//==================================================================== +#ifdef DBG_UTIL + +String SfxShellIdent_Impl( const SfxShell *pSh ) + +/* [Beschreibung] + + Interne Hilfesfunktion. Liefert einen die SfxShell 'pSh' beschreibenden + String zur"uck. Z.B.: SfxApplication[StarWriter] +*/ + +{ + String aIdent( pSh->ISA(SfxApplication) ? DEFINE_CONST_UNICODE("SfxApplication") : + pSh->ISA(SfxViewFrame) ? DEFINE_CONST_UNICODE("SfxViewFrame") : + pSh->ISA(SfxViewShell) ? DEFINE_CONST_UNICODE("SfxViewShell") : + pSh->ISA(SfxObjectShell) ? DEFINE_CONST_UNICODE("SfxObjectShell") : DEFINE_CONST_UNICODE("SfxShell") ); + aIdent += '['; + aIdent += pSh->GetName(); + aIdent += ']'; + return aIdent; +} + +#endif +//==================================================================== + +//========================================================================= +// SfxShell +//========================================================================= + +void __EXPORT SfxShell::EmptyExecStub(SfxShell *, SfxRequest &) +{ +} + +void __EXPORT SfxShell::EmptyStateStub(SfxShell *, SfxItemSet &) +{ +} + +SfxShell::SfxShell() + +/* [Beschreibung] + + Der Konstruktor der Klasse SfxShell initialisierung nur einfache + Typen, das dazugeh"orige SbxObject wird erst on-demand erzeugt. + Daher ist das Anlegen einer SfxShell Instanz sehr billig. +*/ + +: pImp(0), + pPool(0), + pUndoMgr(0) +{ + DBG_CTOR(SfxShell, 0); + pImp = new SfxShell_Impl; + pImp->pViewSh = 0; + pImp->pFrame = 0; + pImp->pRepeatTarget = 0; + pImp->bInAppBASIC = FALSE; + pImp->nHelpId = 0L; + pImp->bActive = FALSE; + pImp->nDisableFlags = 0; +} + +//------------------------------------------------------------------------- + +SfxShell::SfxShell( SfxViewShell *pViewSh ) + +/* [Beschreibung] + + Der Konstruktor der Klasse SfxShell initialisierung nur einfache + Typen, das dazugeh"orige SbxObject wird erst on-demand erzeugt. + Daher ist das Anlegen einer SfxShell Instanz sehr billig. +*/ + +: pImp(0), + pPool(0), + pUndoMgr(0) +{ + DBG_CTOR(SfxShell, 0); + pImp = new SfxShell_Impl; + pImp->pViewSh = pViewSh; + pImp->pFrame = 0; + pImp->pRepeatTarget = 0; + pImp->bInAppBASIC = FALSE; + pImp->nHelpId = 0L; + pImp->bActive = FALSE; +} + +//-------------------------------------------------------------------- + +SfxShell::~SfxShell() + +/* [Beschreibung] + + Die Verbindungs zu einem ggf. zugeh"origen SbxObject wird gel"ost. + Das SbxObject existiert ggf. weiter, kann aber keine Funktionen + mehr ausf"uhren und keine Properties mehr bereitstellen. +*/ + +{ + DBG_DTOR(SfxShell, 0); + delete pImp; +} + +//-------------------------------------------------------------------- + +void SfxShell::SetName( const String &rName ) + +/* [Beschreibung] + + Setzt den Namen des Shell-Objekts. Mit diesem Namen kann die + SfxShell-Instanz vom BASIC aus angesprochen werden. +*/ + +{ + pImp->aObjectName = rName; +} + +//-------------------------------------------------------------------- + +const String& SfxShell::GetName() const + +/* [Beschreibung] + + Liefert den Namen des Shell-Objekts. Mit diesem Namen kann die + SfxShell-Instanz vom BASIC aus angesprochen werden. +*/ + +{ + return pImp->aObjectName; +} + +//-------------------------------------------------------------------- + +SvGlobalName SfxShell::GetGlobalName() const + +/* [Beschreibung] + + Liefert den Global Unique Identifier des Shell-Objekts. Mit diesem + Namen kann die SfxShell-Instanz z.B. via OLE Automation angesprochen + werden, bzw. in der Registration-Database gefunden werden. +*/ + +{ + return SvGlobalName(); +} + +//-------------------------------------------------------------------- + +SfxDispatcher* SfxShell::GetDispatcher() const + +/* [Beschreibung] + + Diese Methode liefert einen Pointer auf den <SfxDispatcher>, in + dem die SfxShell gerade <UI-aktiv> ist bzw. einen 0-Pointer, wenn + sie gerade nicht UI-aktiv ist. + + Der zur"uckgegebene Pointer ist nur im unmittelbaren Kontext des + Methodenaufrufs g"ultig. +*/ + +{ + return pImp->pFrame ? pImp->pFrame->GetDispatcher() : 0; +} + +//-------------------------------------------------------------------- + +SfxViewShell* SfxShell::GetViewShell() const + +/* [Beschreibung] + + Liefert bei SubShells die SfxViewShell, in der sie liegen. Sonst und + falls nicht vom App-Entwickler angegeben liefert diese Methode 0. +*/ + +{ + return pImp->pViewSh; +} + +//-------------------------------------------------------------------- + +SfxViewFrame* SfxShell::GetFrame() const + +/* [Beschreibung] + + Diese Methode liefert einen Pointer auf den <SfxViewFrame>, dem diese + SfxShell-Instanz zugeordnet ist oder in dem sie zur Zeit <UI-aktiv> ist. + Ein 0-Pointer wird geliefert, wenn diese SfxShell-OInstanz gerade nicht + UI-aktiv ist und auch keinem SfxViewFrame fest zugeordnet ist. + + Der zur"uckgegebene Pointer ist nur im unmittelbaren Kontext des + Methodenaufrufs g"ultig. + + + [Anmerkung] + + Nur Instanzen von Subklasse von SfxApplication und SfxObjectShell sollten + hier einen 0-Pointer liefern. Ansonsten liegt ein Fehler im Anwendungs- + programm vor (falscher Ctor von SfxShell gerufen). + + + [Querverweise] + + <SfxViewShell::GetViewFrame()const> +*/ + +{ + if ( pImp->pFrame ) + return pImp->pFrame; + if ( pImp->pViewSh ) + return pImp->pViewSh->GetViewFrame(); + return 0; +} + +//-------------------------------------------------------------------- + +const SfxPoolItem* SfxShell::GetItem +( + USHORT nSlotId // Slot-Id des zu erfragenden <SfxPoolItem>s +) const + +/* [Beschreibung] + + Mit dieser Methode kann auf beliebige Objekte von Subklassen von + <SfxPoolItem> zugegriffen werden. Diese Austauschtechnik wird ben"otigt, + wenn z.B. spezielle <SfxToolBoxControl> Subklassen Zugriff auf + bestimmte Daten z.B. der <SfxObjectShell> ben"otigen. + + Die zur"uckgelieferte Instanz geh"ort der jeweilige SfxShell und + darf nur im unmittelbaren Kontext des Methodenaufrufs verwendet werden. + + + [Querverweise] + + <SfxShell::PutItem(const SfxPoolItem&)> + <SfxShell::RemoveItem(USHORT)> +*/ + +{ + for ( USHORT nPos = 0; nPos < pImp->aItems.Count(); ++nPos ) + if ( pImp->aItems.GetObject(nPos)->Which() == nSlotId ) + return pImp->aItems.GetObject(nPos); + return 0; +} + +//-------------------------------------------------------------------- + +void SfxShell::RemoveItem +( + USHORT nSlotId // Slot-Id des zu l"oschenden <SfxPoolItem>s +) + +/* [Beschreibung] + + Mit dieser Methode k"onnen die allgemein zur Verf"ugung gestellten + Instanzen von Subklassen von <SfxPoolItem> aus der SfxShell entfernt + werden. + + Die gespeicherte Instanz wird gel"oscht. + + + [Querverweise] + + <SfxShell::PutItem(const SfxPoolItem&)> + <SfxShell::GetItem(USHORT)> +*/ + +{ + for ( USHORT nPos = 0; nPos < pImp->aItems.Count(); ++nPos ) + if ( pImp->aItems.GetObject(nPos)->Which() == nSlotId ) + { + // Item entfernen und l"oschen + SfxPoolItem *pItem = pImp->aItems.GetObject(nPos); + delete pItem; + pImp->aItems.Remove(nPos); + + // falls aktiv Bindings benachrichtigen + SfxDispatcher *pDispat = GetDispatcher(); + if ( pDispat ) + { + SfxVoidItem aVoid( nSlotId ); + pDispat->GetBindings()->Broadcast( SfxPoolItemHint( &aVoid ) ); + } + } +} + +//-------------------------------------------------------------------- + +void SfxShell::PutItem +( + const SfxPoolItem& rItem /* Instanz, von der eine Kopie erstellt wird, + die in der SfxShell in einer Liste + gespeichert wird. */ +) + +/* [Beschreibung] + + Mit dieser Methode k"onnen beliebige Objekte von Subklassen von + <SfxPoolItem> zur Verf"ugung gestellt werden. Diese Austauschtechnik + wird ben"otigt, wenn z.B. spezielle <SfxToolBoxControl> Subklassen + Zugriff auf bestimmte Daten z.B. der <SfxObjectShell> ben"otigen. + + Falls ein SfxPoolItem mit derselben Slot-Id exisitert, wird dieses + automatisch gel"oscht. + + + [Querverweise] + + <SfxShell::RemoveItem(USHORT)> + <SfxShell::GetItem(USHORT)> +*/ + +{ + DBG_ASSERT( !rItem.ISA(SfxSetItem), "SetItems aren't allowed here" ); + DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ), + "items with Which-Ids aren't allowed here" ); + + // MSC auf WNT/W95 machte hier Mist, Vorsicht bei Umstellungen + const SfxPoolItem *pItem = rItem.Clone(); + SfxPoolItemHint aItemHint( (SfxPoolItem*) pItem ); + const USHORT nWhich = rItem.Which(); + SfxPoolItem **ppLoopItem = (SfxPoolItem**) pImp->aItems.GetData(); + USHORT nPos; + for ( nPos = 0; nPos < pImp->aItems.Count(); ++nPos, ++ppLoopItem ) + { + if ( (*ppLoopItem)->Which() == nWhich ) + { + // Item austauschen + delete *ppLoopItem; + pImp->aItems.Remove(nPos); + pImp->aItems.Insert( (SfxPoolItemPtr) pItem, nPos ); + + // falls aktiv Bindings benachrichtigen + SfxDispatcher *pDispat = GetDispatcher(); + if ( pDispat ) + { + SfxBindings* pBindings = pDispat->GetBindings(); + pBindings->Broadcast( aItemHint ); + USHORT nSlotId = nWhich; //pItem->GetSlotId(); + SfxStateCache* pCache = pBindings->GetStateCache( nSlotId ); + if ( pCache ) + { + pCache->SetState( SFX_ITEM_AVAILABLE, pItem->Clone(), TRUE ); + pCache->SetCachedState( TRUE ); + } + } + return; + } + } + + Broadcast( aItemHint ); + pImp->aItems.Insert((SfxPoolItemPtr)pItem, nPos ); +} + +//-------------------------------------------------------------------- + +SfxInterface* SfxShell::GetInterface() const + +/* [Beschreibung] + + Mit dieser virtuellen Methode, die durch das Makro <SFX_DECL_INTERFACE> + von jeder Subclass mit eigenen Slots automatisch "uberladen wird, kann + auf die zu der Subklasse geh"orende <SfxInterface>-Instanz zugegriffen + werden. + + Die Klasse SfxShell selbst hat noch kein eigenes SfxInterface + (keine Slots), daher wird ein 0-Pointer zur"uckgeliefert. +*/ + +{ + return GetStaticInterface(); +} + +//-------------------------------------------------------------------- + +SfxBroadcaster* SfxShell::GetBroadcaster() + +/* [Beschreibung] + + Liefert einen SfxBroadcaster f"ur diese SfxShell-Instanz bis die + Klasse SfxShell von SfxBroadcaster abgeleitet ist. +*/ + +{ + return pImp; +} + +//-------------------------------------------------------------------- + +::svl::IUndoManager* SfxShell::GetUndoManager() + +/* [Beschreibung] + + Jede Subclass von SfxShell kann "uber einen <SfxUndoManager> verf"ugen. + Dieser kann in den abgeleiteten Klasse mit <SfxShell:SetUndoManager()> + gesetzt werden. + + Die Klasse SfxShell selbst hat noch keinen SfxUndoManager, es wird + daher ein 0-Pointer zur"uckgeliefert. +*/ + +{ + return pUndoMgr; +} + +//-------------------------------------------------------------------- + +void SfxShell::SetUndoManager( ::svl::IUndoManager *pNewUndoMgr ) + +/* [Beschreibung] + + Setzt einen <SfxUndoManager> f"ur diese <SfxShell> Instanz. F"ur das + Undo wird immer nur der Undo-Manager an der jeweils oben auf dem + Stack des <SfxDispatcher> liegenden SfxShell verwendet. + + Am "ubergebenen <SfxUndoManager> wird automatisch die aktuelle + Max-Undo-Action-Count Einstellung aus den Optionen gesetzt. + + 'pNewUndoMgr' mu\s bis zum Dtor dieser SfxShell-Instanz oder bis + zum n"achsten 'SetUndoManager()' existieren. +*/ + +{ + OSL_ENSURE( ( pUndoMgr == NULL ) || ( pNewUndoMgr == NULL ) || ( pUndoMgr == pNewUndoMgr ), + "SfxShell::SetUndoManager: exchanging one non-NULL manager with another non-NULL manager? Suspicious!" ); + // there's at least one client of our UndoManager - the DocumentUndoManager at the SfxBaseModel - which + // caches the UndoManager, and registers itself as listener. If exchanging non-NULL UndoManagers is really + // a supported scenario (/me thinks it is not), then we would need to notify all such clients instances. + + pUndoMgr = pNewUndoMgr; + if ( pUndoMgr ) + pUndoMgr->SetMaxUndoActionCount( (USHORT) SvtUndoOptions().GetUndoCount() ); +} + +//-------------------------------------------------------------------- + +SfxRepeatTarget* SfxShell::GetRepeatTarget() const + +/* [Beschreibung] + + Liefert einen Pointer auf die <SfxRepeatTarget>-Instanz, die + als RepeatTarget bei SID_REPEAT verwendet wird, wenn der + von dieser SfxShell gelieferte <SfxUndoManager> angesprochen wird. + Der R"uckgabewert kann 0 sein. + + + [Anmerkung] + + Eine Ableitung von <SfxShell> oder einer ihrer Subklassen von + <SfxRepeatTarget> ist nicht zu empfehlen, da Compiler-Fehler + provoziert werden (wegen Call-to-Pointer-to-Member-Function to + subclass). +*/ + +{ + return pImp->pRepeatTarget; +} + +//-------------------------------------------------------------------- + +void SfxShell::SetRepeatTarget( SfxRepeatTarget *pTarget ) + +/* [Beschreibung] + + Setzt den die <SfxRepeatTarget>-Instanz, die bei SID_REPEAT als + RepeatTarget verwendet wird, wenn der von dieser SfxShell gelieferte + <SfxUndoManager> angesprochen wird. Durch 'pTarget==0' wird SID_REPEAT + f"ur diese SfxShell disabled. Die Instanz '*pTarget' mu\s so lange + leben, wie sie angemeldet ist. + + + [Anmerkung] + + Eine Ableitung von <SfxShell> oder einer ihrer Subklassen von + <SfxRepeatTarget> ist nicht zu empfehlen, da Compiler-Fehler + provoziert werden (wegen Call-to-Pointer-to-Member-Function to + subclass). +*/ + +{ + pImp->pRepeatTarget = pTarget; +} + +//-------------------------------------------------------------------- + +void SfxShell::Invalidate +( + USHORT nId /* Zu invalidierende Slot-Id oder Which-Id. + Falls diese 0 ist (default), werden + alle z.Zt. von dieser Shell bedienten + Slot-Ids invalidiert. */ +) + +/* [Beschreibung] + + Mit dieser Methode k"onnen Slots der Subclasses "uber die Slot-Id + oder alternativ "uber die Which-Id invalidiert werden. Slot-Ids, + die von der Subclass ererbt sind, werden ebenfalls invalidert. + + [Querverweise] + <SfxBindings::Invalidate(USHORT)> + <SfxBindings::InvalidateAll(BOOL)> +*/ + +{ + if ( !GetViewShell() ) + { + DBG_ERROR( "wrong Invalidate method called!" ); + return; + } + + Invalidate_Impl( GetViewShell()->GetViewFrame()->GetBindings(), nId ); +} + +void SfxShell::Invalidate_Impl( SfxBindings& rBindings, USHORT nId ) +{ + if ( nId == 0 ) + { + rBindings.InvalidateShell( *this, FALSE ); + } + else + { + const SfxInterface *pIF = GetInterface(); + do + { + const SfxSlot *pSlot = pIF->GetSlot(nId); + if ( pSlot ) + { + // bei Enum-Slots ist der Master-Slot zu invalidieren + if ( SFX_KIND_ENUM == pSlot->GetKind() ) + pSlot = pSlot->GetLinkedSlot(); + + // den Slot selbst und ggf. auch alle Slave-Slots invalidieren + rBindings.Invalidate( pSlot->GetSlotId() ); + for ( const SfxSlot *pSlave = pSlot->GetLinkedSlot(); + pSlave && pIF->ContainsSlot_Impl( pSlave ) && + pSlave->GetLinkedSlot() == pSlot; + ++pSlave ) + rBindings.Invalidate( pSlave->GetSlotId() ); + + return; + } + + pIF = pIF->GetGenoType(); + } + + while ( pIF ); + + DBG_WARNING( "W3: invalidating slot-id unknown in shell" ); + } +} + +//-------------------------------------------------------------------- + +void SfxShell::DoActivate_Impl( SfxViewFrame *pFrame, BOOL bMDI ) + +/* [Beschreibung] + + Diese Methode steuert die Aktivierung der SfxShell-Instanz. Zun"achst + wird durch Aufruf der virtuellen Methode <SfxShell::Activate(BOOL)> + der Subclass die M"oglichkeit gegeben, auf das Event zu reagieren. + + Bei bMDI == TRUE wird das zugeh"orige SbxObject 'scharfgeschaltet', + so da\s Methoden des Objekts unqualifiziert (ohne den Namen des Objekts) + vom BASIC gefunden werden. +*/ + +{ +#ifdef DBG_UTIL + const SfxInterface *p_IF = GetInterface(); + if ( !p_IF ) + return; +#endif +#ifdef DBG_UTIL_VB + String aMsg("SfxShell::DoActivate() "); + aMsg += (long)this; + aMsg += " "; + aMsg += GetInterface()->GetName(); + aMsg += " bMDI "; + if ( bMDI ) aMsg += "MDI"; + DbgTrace( aMsg.GetBuffer() ); +#endif + + if ( bMDI ) + { + // Frame merken, in dem aktiviert wird + pImp->pFrame = pFrame; + pImp->bActive = TRUE; + } + + // Subklasse benachrichtigen + Activate(bMDI); +} + +//-------------------------------------------------------------------- + +void SfxShell::DoDeactivate_Impl( SfxViewFrame *pFrame, BOOL bMDI ) + +/* [Beschreibung] + + Diese Methode steuert die Deaktivierung der SfxShell-Instanz. Bei + bMDI == TRUE wird zun"achst das SbxObject in einen Status versetzt, + so da\s Methoden vom BASIC aus nur noch qualifiziert gerufen werden + k"onnen. + + Dann erh"alt in jedem Fall die Subclass durch Aufruf der virtuellen + Methode <SfxShell::Deactivate(BOOL)> die M"oglichkeit auf das Event + zu reagieren. +*/ + +{ +#ifdef DBG_UTIL + const SfxInterface *p_IF = GetInterface(); + if ( !p_IF ) + return; +#endif +#ifdef DBG_UTIL_VB + String aMsg("SfxShell::DoDeactivate()"); + aMsg += (long)this; + aMsg += " "; + aMsg += GetInterface()->GetName(); + aMsg += " bMDI "; + if ( bMDI ) aMsg += "MDI"; + DbgTrace( aMsg.GetBuffer() ); +#endif + + // nur wenn er vom Frame kommt (nicht z.B. pop der BASIC-IDE vom AppDisp) + if ( bMDI && pImp->pFrame == pFrame ) + { + // austragen + pImp->pFrame = 0; + pImp->bActive = FALSE; + } + + // Subklasse benachrichtigen + Deactivate(bMDI); +} + +//-------------------------------------------------------------------- + +BOOL SfxShell::IsActive() const +{ + return pImp->bActive; +} + +//-------------------------------------------------------------------- + +void SfxShell::Activate +( + BOOL /*bMDI*/ /* TRUE + der <SfxDispatcher>, auf dem die SfxShell sich + befindet, ist aktiv geworden oder die SfxShell + Instanz wurde auf einen aktiven SfxDispatcher + gepusht. (vergl. SystemWindow::IsMDIActivate()) + + FALSE + das zum <SfxViewFrame>, auf dessen SfxDispatcher + sich die SfxShell Instanz befindet, wurde + aktiviert. + (z.B. durch einen geschlossenen Dialog) */ +) + +/* [Beschreibung] + + Virtuelle Methode, die beim Aktivieren der SfxShell Instanz gerufen + wird, um den Subclasses die Gelegenheit zu geben, auf das Aktivieren + zu reagieren. + + Die Basisimplementation ist leer und braucht nicht gerufen zu werden. + + + [Querverweise] + StarView SystemWindow::Activate(BOOL) +*/ + +{ +} + +//-------------------------------------------------------------------- + +void SfxShell::Deactivate +( + BOOL /*bMDI*/ /* TRUE + der <SfxDispatcher>, auf dem die SfxShell sich + befindet, ist inaktiv geworden oder die SfxShell + Instanz wurde auf einen aktiven SfxDispatcher + gepoppt. (vergl. SystemWindow::IsMDIActivate()) + + FALSE + das zum <SfxViewFrame>, auf dessen SfxDispatcher + sich die SfxShell Instanz befindet, wurde + deaktiviert. (z.B. durch einen Dialog) */ + +) + +/* [Beschreibung] + + Virtuelle Methode, die beim Deaktivieren der SfxShell Instanz gerufen + wird, um den Subclasses die Gelegenheit zu geben, auf das Deaktivieren + zu reagieren. + + Die Basisimplementation ist leer und braucht nicht gerufen zu werden. + + + [Querverweise] + StarView SystemWindow::Dectivate(BOOL) +*/ + +{ +} + +void SfxShell::ParentActivate +( +) + +/* [Beschreibung] + + Ein Parent des <SfxDispatcher>, auf dem die SfxShell sich befindet, + ist aktiv geworden, oder die SfxShell Instanz wurde auf einen + <SfxDispatcher> gepusht, dessen parent aktiv ist. + + Die Basisimplementation ist leer und braucht nicht gerufen zu werden. + + [Querverweise] + SfxShell::Activate() +*/ +{ +} + +//-------------------------------------------------------------------- + +void SfxShell::ParentDeactivate +( +) + +/* [Beschreibung] + + Der aktive Parent des <SfxDispatcher>, auf dem die SfxShell sich befindet, + ist deaktiviert worden. + + Die Basisimplementation ist leer und braucht nicht gerufen zu werden. + + [Querverweise] + SfxShell::Deactivate() +*/ +{ +} + +//-------------------------------------------------------------------- + +ResMgr* SfxShell::GetResMgr() const + +/* [Beschreibung] + + Diese Methode liefert den ResMgr der <Resource-DLL>, die von der + SfxShell-Instanz verwendet wird. Ist dies ein 0-Pointer, so + ist der aktuelle Resource-Manager zu verwenden. +*/ + +{ + return GetInterface()->GetResMgr(); +} + +//-------------------------------------------------------------------- + +FASTBOOL SfxShell::CanExecuteSlot_Impl( const SfxSlot &rSlot ) + +/* [Beschreibung] + + Diese Methode stellt durch Aufruf der Statusfunktion fest, + ob 'rSlot' aktuell ausgef"uhrt werden kann. +*/ +{ + // Slot-Status holen + SfxItemPool &rPool = GetPool(); + const USHORT nId = rSlot.GetWhich( rPool ); + SfxItemSet aSet(rPool, nId, nId); + SfxStateFunc pFunc = rSlot.GetStateFnc(); + CallState( pFunc, aSet ); + return aSet.GetItemState(nId) != SFX_ITEM_DISABLED; +} + +//-------------------------------------------------------------------- + +long ShellCall_Impl( void* pObj, void* pArg ) +{ + ((SfxShell* )pObj)->ExecuteSlot( *(SfxRequest*)pArg, (SfxInterface*)0L ); + return 0; +} + +/* [Beschreibung] + Asynchrones ExecuteSlot fuer das RELOAD + */ + +//-------------------------------------------------------------------- +const SfxPoolItem* SfxShell::ExecuteSlot( SfxRequest& rReq, BOOL bAsync ) +{ + if( !bAsync ) + return ExecuteSlot( rReq, (SfxInterface*)0L ); + else + { + if( !pImp->pExecuter ) + pImp->pExecuter = new svtools::AsynchronLink( + Link( this, ShellCall_Impl ) ); + pImp->pExecuter->Call( new SfxRequest( rReq ) ); + return 0; + } +} + +const SfxPoolItem* SfxShell::ExecuteSlot +( + SfxRequest &rReq, // der weiterzuleitende <SfxRequest> + const SfxInterface* pIF // default = 0 bedeutet virtuell besorgen +) + +/* [Beschreibung] + + Diese Methode erm"oglicht das Weiterleiten eines <SfxRequest> an + die angegebene Basis-<SfxShell>. + + + [Beispiel] + + In einer von SfxViewShell abgeleiteten Klasse soll SID_PRINTDOCDIRECT + abgefangen werden. Unter bestimmten Umst"anden soll vor dem Drucken + eine Abfrage erscheinen, und der Request soll ggf. abgebrochen werden. + + Dazu ist in der IDL dieser Subklasse der o.g. Slot einzutragen. Die + Execute-Methode enth"alt dann skizziert: + + void SubViewShell::Exec( SfxRequest &rReq ) + { + if ( rReq.GetSlot() == SID_PRINTDOCDIRECT ) + { + 'dialog' + if ( 'condition' ) + ExecuteSlot( rReq, SfxViewShell::GetInterface() ); + } + } + + Es braucht i.d.R. kein rReq.Done() gerufen zu werden, da das bereits + die Implementierung der SfxViewShell erledigt bzw. abgebrochen wurde. + + + [Querverweise] + + <SfxShell::GetSlotState(USHORT,const SfxInterface*,SfxItemSet*)> +*/ + +{ + if ( !pIF ) + pIF = GetInterface(); + + USHORT nSlot = rReq.GetSlot(); + const SfxSlot* pSlot = NULL; + if ( nSlot >= SID_VERB_START && nSlot <= SID_VERB_END ) + pSlot = GetVerbSlot_Impl(nSlot); + if ( !pSlot ) + pSlot = pIF->GetSlot(nSlot); + DBG_ASSERT( pSlot, "slot not supported" ); + + SfxExecFunc pFunc = pSlot->GetExecFnc(); + if ( pFunc ) + CallExec( pFunc, rReq ); + + return rReq.GetReturnValue(); +} + +//-------------------------------------------------------------------- + +const SfxPoolItem* SfxShell::GetSlotState +( + USHORT nSlotId, // Slot-Id des zu befragenden Slots + const SfxInterface* pIF, // default = 0 bedeutet virtuell besorgen + SfxItemSet* pStateSet // SfxItemSet der Slot-State-Methode +) + +/* [Beschreibung] + + Diese Methode liefert den Status des Slots mit der angegebenen Slot-Id + "uber das angegebene Interface. + + Ist der Slot disabled oder in dieser SfxShell (und deren Parent-Shells) + nicht bekannt, wird ein 0-Pointer zur"uckgeliefert. + + Hat der Slot keinen Status, wird ein SfxVoidItem zur"uckgeliefert. + + Der Status wird bei pStateSet != 0 gleich in diesem Set gesetzt, so + da\s <SfxShell>-Subklassen Slots-"uberladen und auch bei der + Status-Methode die Basis-Implementierung rufen k"onnen. + + + [Beispiel] + + In einer von SfxViewShell abgeleiteten Klasse soll SID_PRINTDOCDIRECT + abgefangen werden. Unter bestimmten Umst"anden soll vor dem Drucken + eine Abfrage erscheinen, und der Request soll ggf. abgebrochen werden. + + Dazu ist in der IDL dieser Subklasse der o.g. Slot einzutragen. Die + Status-Methode enth"alt dann skizziert: + + void SubViewShell::PrintState( SfxItemSet &rState ) + { + if ( rState.GetItemState( SID_PRINTDOCDIRECT ) != SFX_ITEM_UNKNOWN ) + GetSlotState( SID_PRINTDOCDIRECT, SfxViewShell::GetInterface(), + &rState ); + ... + } + + + [Querverweise] + + <SfxShell::ExecuteSlot(SfxRequest&)> +*/ + +{ + // Slot am angegebenen Interface besorgen + if ( !pIF ) + pIF = GetInterface(); + SfxItemState eState; + SfxItemPool &rPool = GetPool(); + + const SfxSlot* pSlot = NULL; + if ( nSlotId >= SID_VERB_START && nSlotId <= SID_VERB_END ) + pSlot = GetVerbSlot_Impl(nSlotId); + if ( !pSlot ) + pSlot = pIF->GetSlot(nSlotId); + if ( pSlot ) + // ggf. auf Which-Id mappen + nSlotId = pSlot->GetWhich( rPool ); + + // Item und Item-Status besorgen + const SfxPoolItem *pItem = NULL; + SfxItemSet aSet( rPool, nSlotId, nSlotId ); // pItem stirbt sonst zu fr"uh + if ( pSlot ) + { + // Status-Methode rufen + SfxStateFunc pFunc = pSlot->GetStateFnc(); + if ( pFunc ) + CallState( pFunc, aSet ); + eState = aSet.GetItemState( nSlotId, TRUE, &pItem ); + + // ggf. Default-Item besorgen + if ( eState == SFX_ITEM_DEFAULT ) + { + if ( SfxItemPool::IsWhich(nSlotId) ) + pItem = &rPool.GetDefaultItem(nSlotId); + else + eState = SFX_ITEM_DONTCARE; + } + } + else + eState = SFX_ITEM_UNKNOWN; + + // Item und Item-Status auswerten und ggf. in pStateSet mitpflegen + SfxPoolItem *pRetItem = 0; + if ( eState <= SFX_ITEM_DISABLED ) + { + if ( pStateSet ) + pStateSet->DisableItem(nSlotId); + return 0; + } + else if ( eState == SFX_ITEM_DONTCARE ) + { + if ( pStateSet ) + pStateSet->ClearItem(nSlotId); + pRetItem = new SfxVoidItem(0); + } + else + { + if ( pStateSet && pStateSet->Put( *pItem ) ) + return &pStateSet->Get( pItem->Which() ); + pRetItem = pItem->Clone(); + } + DeleteItemOnIdle(pRetItem); + + return pRetItem; +} + +//-------------------------------------------------------------------- + +SFX_EXEC_STUB(SfxShell, VerbExec) +SFX_STATE_STUB(SfxShell, VerbState) + +void SfxShell::SetVerbs(const com::sun::star::uno::Sequence < com::sun::star::embed::VerbDescriptor >& aVerbs) +{ + SfxViewShell *pViewSh = PTR_CAST ( SfxViewShell, this); + + DBG_ASSERT(pViewSh, "SetVerbs nur an der ViewShell aufrufen!"); + if ( !pViewSh ) + return; + + // Zun"achst alle Statecaches dirty machen, damit keiner mehr versucht, + // die Slots zu benutzen + { + SfxBindings *pBindings = + pViewSh->GetViewFrame()->GetDispatcher()->GetBindings(); + USHORT nCount = pImp->aSlotArr.Count(); + for (USHORT n1=0; n1<nCount ; n1++) + { + USHORT nId = SID_VERB_START + n1; + pBindings->Invalidate(nId, FALSE, TRUE); + } + } + + USHORT nr=0; + for (sal_Int32 n=0; n<aVerbs.getLength(); n++) + { + USHORT nSlotId = SID_VERB_START + nr++; + DBG_ASSERT(nSlotId <= SID_VERB_END, "Zuviele Verben!"); + if (nSlotId > SID_VERB_END) + break; + + SfxSlot *pNewSlot = new SfxSlot; + pNewSlot->nSlotId = nSlotId; + pNewSlot->nGroupId = 0; + + // Verb-Slots m"ussen asynchron ausgef"uhrt werden, da sie w"ahrend + // des Ausf"uhrens zerst"ort werden k"onnten + pNewSlot->nFlags = SFX_SLOT_ASYNCHRON | SFX_SLOT_CONTAINER; + pNewSlot->nMasterSlotId = 0; + pNewSlot->nValue = 0; + pNewSlot->fnExec = SFX_STUB_PTR(SfxShell,VerbExec); + pNewSlot->fnState = SFX_STUB_PTR(SfxShell,VerbState); + pNewSlot->pType = 0; HACK(SFX_TYPE(SfxVoidItem)) + pNewSlot->pName = U2S(aVerbs[n].VerbName); + pNewSlot->pLinkedSlot = 0; + pNewSlot->nArgDefCount = 0; + pNewSlot->pFirstArgDef = 0; + pNewSlot->pUnoName = 0; + + if (pImp->aSlotArr.Count()) + { + SfxSlot *pSlot = (pImp->aSlotArr)[0]; + pNewSlot->pNextSlot = pSlot->pNextSlot; + pSlot->pNextSlot = pNewSlot; + } + else + pNewSlot->pNextSlot = pNewSlot; + + pImp->aSlotArr.Insert(pNewSlot, (USHORT) n); + } + + pImp->aVerbList = aVerbs; + + if (pViewSh) + { + // Der Status von SID_OBJECT wird im Controller direkt an der Shell + // abgeholt, es reicht also, ein neues StatusUpdate anzuregen + SfxBindings *pBindings = pViewSh->GetViewFrame()->GetDispatcher()-> + GetBindings(); + pBindings->Invalidate( SID_OBJECT, TRUE, TRUE ); + } +} + +//-------------------------------------------------------------------- + +const com::sun::star::uno::Sequence < com::sun::star::embed::VerbDescriptor >& SfxShell::GetVerbs() const +{ + return pImp->aVerbList; +} + +//-------------------------------------------------------------------- + +void SfxShell::VerbExec(SfxRequest& rReq) +{ + USHORT nId = rReq.GetSlot(); + SfxViewShell *pViewShell = GetViewShell(); + if ( pViewShell ) + { + BOOL bReadOnly = pViewShell->GetObjectShell()->IsReadOnly(); + com::sun::star::uno::Sequence < com::sun::star::embed::VerbDescriptor > aList = pViewShell->GetVerbs(); + for (sal_Int32 n=0, nVerb=0; n<aList.getLength(); n++) + { + // check for ReadOnly verbs + if ( bReadOnly && !(aList[n].VerbAttributes & embed::VerbAttributes::MS_VERBATTR_NEVERDIRTIES) ) + continue; + + // check for verbs that shouldn't appear in the menu + if ( !(aList[n].VerbAttributes & embed::VerbAttributes::MS_VERBATTR_ONCONTAINERMENU) ) + continue; + + if (nId == SID_VERB_START + nVerb++) + { + pViewShell->DoVerb(aList[n].VerbID); + rReq.Done(); + return; + } + } + } +} + +//-------------------------------------------------------------------- + +void SfxShell::VerbState(SfxItemSet& ) +{ +} + +//-------------------------------------------------------------------- + +const SfxSlot* SfxShell::GetVerbSlot_Impl(USHORT nId) const +{ + com::sun::star::uno::Sequence < com::sun::star::embed::VerbDescriptor > rList = pImp->aVerbList; + + DBG_ASSERT(nId >= SID_VERB_START && nId <= SID_VERB_END,"Falsche VerbId!"); + USHORT nIndex = nId - SID_VERB_START; + DBG_ASSERT(nIndex < rList.getLength(),"Falsche VerbId!"); + + if (nIndex < rList.getLength()) + return pImp->aSlotArr[nIndex]; + else + return 0; +} + +//-------------------------------------------------------------------- + +void SfxShell::SetHelpId(ULONG nId) +{ + pImp->nHelpId = nId; +} + +//-------------------------------------------------------------------- + +ULONG SfxShell::GetHelpId() const +{ + return pImp->nHelpId; +} + +//-------------------------------------------------------------------- + +SfxObjectShell* SfxShell::GetObjectShell() +{ + if ( GetViewShell() ) + return GetViewShell()->GetViewFrame()->GetObjectShell(); + else + return NULL; +} + +//-------------------------------------------------------------------- + +sal_Bool SfxShell::HasUIFeature( sal_uInt32 ) +{ + return sal_False; +} + +long DispatcherUpdate_Impl( void*, void* pArg ) +{ + ((SfxDispatcher*) pArg)->Update_Impl( TRUE ); + ((SfxDispatcher*) pArg)->GetBindings()->InvalidateAll(FALSE); + return 0; +} + +void SfxShell::UIFeatureChanged() +{ + SfxViewFrame *pFrame = GetFrame(); + if ( pFrame && pFrame->IsVisible() ) + { + // Auch dann Update erzwingen, wenn Dispatcher schon geupdated ist, + // sonst bleibt evtl. irgendwas in den gebunkerten Tools stecken. + // Asynchron aufrufen, um Rekursionen zu vermeiden + if ( !pImp->pUpdater ) + pImp->pUpdater = new svtools::AsynchronLink( Link( this, DispatcherUpdate_Impl ) ); + + // Mehrfachaufrufe gestattet + pImp->pUpdater->Call( pFrame->GetDispatcher(), TRUE ); + } +} + +void SfxShell::SetDisableFlags( ULONG nFlags ) +{ + pImp->nDisableFlags = nFlags; +} + +ULONG SfxShell::GetDisableFlags() const +{ + return pImp->nDisableFlags; +} + +SfxItemSet* SfxShell::CreateItemSet( USHORT ) +{ + return NULL; +} + +void SfxShell::ApplyItemSet( USHORT, const SfxItemSet& ) +{ +} + +void SfxShell::SetViewShell_Impl( SfxViewShell* pView ) +{ + pImp->pViewSh = pView; +} + + + diff --git a/sfx2/source/control/sorgitm.cxx b/sfx2/source/control/sorgitm.cxx new file mode 100644 index 000000000000..cb24fe34e9b6 --- /dev/null +++ b/sfx2/source/control/sorgitm.cxx @@ -0,0 +1,136 @@ +/************************************************************************* + * + * 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 <sfx2/sfxsids.hrc> +#include "sorgitm.hxx" +// STATIC DATA ----------------------------------------------------------- + +TYPEINIT1_AUTOFACTORY(SfxScriptOrganizerItem, SfxStringItem); + +//------------------------------------------------------------------------ + +SfxScriptOrganizerItem::SfxScriptOrganizerItem() : + + SfxStringItem() + +{ +} + +//------------------------------------------------------------------------ + +SfxScriptOrganizerItem::SfxScriptOrganizerItem( const String& rLanguage ) : + + SfxStringItem( SID_SCRIPTORGANIZER, rLanguage ), + + aLanguage( rLanguage ) + +{ +} + +//------------------------------------------------------------------------ + +SfxScriptOrganizerItem::SfxScriptOrganizerItem( const SfxScriptOrganizerItem& rItem ) : + + SfxStringItem( rItem ), + + aLanguage( rItem.aLanguage ) + +{ +} + +//------------------------------------------------------------------------ + +SfxScriptOrganizerItem::~SfxScriptOrganizerItem() +{ +} + +//------------------------------------------------------------------------ + +SfxPoolItem* SfxScriptOrganizerItem::Clone( SfxItemPool * ) const +{ + return new SfxScriptOrganizerItem( *this ); +} + +//------------------------------------------------------------------------ + +int SfxScriptOrganizerItem::operator==( const SfxPoolItem& rItem) const +{ + return rItem.Type() == Type() && + SfxStringItem::operator==(rItem) && + aLanguage == ((const SfxScriptOrganizerItem &)rItem).aLanguage; +} + + +sal_Bool SfxScriptOrganizerItem::QueryValue( com::sun::star::uno::Any& rVal, BYTE nMemberId ) const +{ + String aValue; + BOOL bIsString = FALSE; + sal_Bool bValue = sal_False; + nMemberId &= ~CONVERT_TWIPS; + switch ( nMemberId ) + { + case 0: + case MID_SCRIPT_ORGANIZER_LANGUAGE: + bIsString = TRUE; + aValue = aLanguage; + break; + default: + DBG_ERROR("Wrong MemberId!"); + return sal_False; + } + + if ( bIsString ) + rVal <<= ::rtl::OUString( aValue ); + else + rVal <<= bValue; + return sal_True; +} + +sal_Bool SfxScriptOrganizerItem::PutValue( const com::sun::star::uno::Any& rVal, BYTE nMemberId ) +{ + ::rtl::OUString aValue; + sal_Bool bRet = sal_False; + nMemberId &= ~CONVERT_TWIPS; + switch ( nMemberId ) + { + case 0: + case MID_SCRIPT_ORGANIZER_LANGUAGE: + bRet = (rVal >>= aValue); + if ( bRet ) + aLanguage = aValue; + break; + default: + DBG_ERROR("Wrong MemberId!"); + return sal_False; + } + + return bRet; +} + diff --git a/sfx2/source/control/statcach.cxx b/sfx2/source/control/statcach.cxx new file mode 100644 index 000000000000..3fdd14369856 --- /dev/null +++ b/sfx2/source/control/statcach.cxx @@ -0,0 +1,577 @@ +/************************************************************************* + * + * 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" + +#ifdef SOLARIS +// HACK: prevent conflict between STLPORT and Workshop headers on Solaris 8 +#include <ctime> +#endif + +#include <string> // HACK: prevent conflict between STLPORT and Workshop headers +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/frame/XFrameActionListener.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/frame/FrameActionEvent.hpp> +#include <com/sun/star/frame/FrameAction.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <cppuhelper/weak.hxx> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <svl/stritem.hxx> +#include <svl/visitem.hxx> +#include <comphelper/processfactory.hxx> + +#ifndef GCC +#endif + +#include <sfx2/app.hxx> +#include <sfx2/appuno.hxx> +#include "statcach.hxx" +#include <sfx2/msg.hxx> +#include <sfx2/ctrlitem.hxx> +#include <sfx2/dispatch.hxx> +#include "sfxtypes.hxx" +#include <sfx2/sfxuno.hxx> +#include <sfx2/unoctitm.hxx> +#include <sfx2/msgpool.hxx> +#include <sfx2/viewfrm.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; + +//==================================================================== + +DBG_NAME(SfxStateCache) +DBG_NAME(SfxStateCacheSetState) + +SFX_IMPL_XINTERFACE_2( BindDispatch_Impl, OWeakObject, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener ) +SFX_IMPL_XTYPEPROVIDER_2( BindDispatch_Impl, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener ) + +//----------------------------------------------------------------------------- +BindDispatch_Impl::BindDispatch_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > & rDisp, const ::com::sun::star::util::URL& rURL, SfxStateCache *pStateCache, const SfxSlot* pS ) + : xDisp( rDisp ) + , aURL( rURL ) + , pCache( pStateCache ) + , pSlot( pS ) +{ + DBG_ASSERT( pCache && pSlot, "Invalid BindDispatch!"); + aStatus.IsEnabled = sal_True; +} + +void SAL_CALL BindDispatch_Impl::disposing( const ::com::sun::star::lang::EventObject& ) throw( ::com::sun::star::uno::RuntimeException ) +{ + if ( xDisp.is() ) + { + xDisp->removeStatusListener( (::com::sun::star::frame::XStatusListener*) this, aURL ); + xDisp = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > (); + } +} + +void SAL_CALL BindDispatch_Impl::statusChanged( const ::com::sun::star::frame::FeatureStateEvent& rEvent ) throw( ::com::sun::star::uno::RuntimeException ) +{ + aStatus = rEvent; + if ( !pCache ) + return; + + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > xRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY ); + if ( aStatus.Requery ) + pCache->Invalidate( sal_True ); + else + { + SfxPoolItem *pItem=NULL; + sal_uInt16 nId = pCache->GetId(); + SfxItemState eState = SFX_ITEM_DISABLED; + // pCache->Invalidate( sal_False ); + if ( !aStatus.IsEnabled ) + { + // default + } + else if (aStatus.State.hasValue()) + { + eState = SFX_ITEM_AVAILABLE; + ::com::sun::star::uno::Any aAny = aStatus.State; + + ::com::sun::star::uno::Type pType = aAny.getValueType(); + if ( pType == ::getBooleanCppuType() ) + { + sal_Bool bTemp = false; + aAny >>= bTemp ; + pItem = new SfxBoolItem( nId, bTemp ); + } + else if ( pType == ::getCppuType((const sal_uInt16*)0) ) + { + sal_uInt16 nTemp = 0; + aAny >>= nTemp ; + pItem = new SfxUInt16Item( nId, nTemp ); + } + else if ( pType == ::getCppuType((const sal_uInt32*)0) ) + { + sal_uInt32 nTemp = 0; + aAny >>= nTemp ; + pItem = new SfxUInt32Item( nId, nTemp ); + } + else if ( pType == ::getCppuType((const ::rtl::OUString*)0) ) + { + ::rtl::OUString sTemp ; + aAny >>= sTemp ; + pItem = new SfxStringItem( nId, sTemp ); + } + else + { + if ( pSlot ) + pItem = pSlot->GetType()->CreateItem(); + if ( pItem ) + { + pItem->SetWhich( nId ); + pItem->PutValue( aAny ); + } + else + pItem = new SfxVoidItem( nId ); + } + } + else + { + // DONTCARE status + pItem = new SfxVoidItem(0); + eState = SFX_ITEM_UNKNOWN; + } + + for ( SfxControllerItem *pCtrl = pCache->GetItemLink(); + pCtrl; + pCtrl = pCtrl->GetItemLink() ) + pCtrl->StateChanged( nId, eState, pItem ); + + delete pItem; + } +} + +void BindDispatch_Impl::Release() +{ + if ( xDisp.is() ) + { + xDisp->removeStatusListener( (::com::sun::star::frame::XStatusListener*) this, aURL ); + xDisp = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > (); + } + + pCache = NULL; + release(); +} + +const ::com::sun::star::frame::FeatureStateEvent& BindDispatch_Impl::GetStatus() const +{ + return aStatus; +} + +void BindDispatch_Impl::Dispatch( uno::Sequence < beans::PropertyValue > aProps, sal_Bool bForceSynchron ) +{ + if ( xDisp.is() && aStatus.IsEnabled ) + { + sal_Int32 nLength = aProps.getLength(); + aProps.realloc(nLength+1); + aProps[nLength].Name = DEFINE_CONST_UNICODE("SynchronMode"); + aProps[nLength].Value <<= bForceSynchron ; + xDisp->dispatch( aURL, aProps ); + } +} + +//-------------------------------------------------------------------- + +/* Dieser Konstruktor fuer einen ungueltigen Cache, der sich also + bei der ersten Anfrage zun"achst updated. + */ + +SfxStateCache::SfxStateCache( sal_uInt16 nFuncId ): + pDispatch( 0 ), + nId(nFuncId), + pInternalController(0), + pController(0), + pLastItem( 0 ), + eLastState( 0 ), + bItemVisible( sal_True ) +{ + DBG_MEMTEST(); + DBG_CTOR(SfxStateCache, 0); + bCtrlDirty = sal_True; + bSlotDirty = sal_True; + bItemDirty = sal_True; +} + +//-------------------------------------------------------------------- + +/* Der Destruktor pr"uft per Assertion, ob noch Controller angemeldet + sind. + */ + +SfxStateCache::~SfxStateCache() +{ + DBG_MEMTEST(); + DBG_DTOR(SfxStateCache, 0); + DBG_ASSERT( pController == 0 && pInternalController == 0, "es sind noch Controller angemeldet" ); + if ( !IsInvalidItem(pLastItem) ) + delete pLastItem; + if ( pDispatch ) + { + pDispatch->Release(); + pDispatch = NULL; + } +} + +//-------------------------------------------------------------------- +// invalidates the cache (next request will force update) +void SfxStateCache::Invalidate( sal_Bool bWithMsg ) +{ + bCtrlDirty = sal_True; + if ( bWithMsg ) + { + bSlotDirty = sal_True; + aSlotServ.SetSlot( 0 ); + if ( pDispatch ) + { + pDispatch->Release(); + pDispatch = NULL; + } + } +} + +//-------------------------------------------------------------------- + +// gets the corresponding function from the dispatcher or the cache + +const SfxSlotServer* SfxStateCache::GetSlotServer( SfxDispatcher &rDispat , const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & xProv ) +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxStateCache, 0); + + if ( bSlotDirty ) + { + // get the SlotServer; we need it for internal controllers anyway, but also in most cases + rDispat._FindServer( nId, aSlotServ, sal_False ); + + DBG_ASSERT( !pDispatch, "Old Dispatch not removed!" ); + + // we don't need to check the dispatch provider if we only have an internal controller + if ( xProv.is() ) + { + const SfxSlot* pSlot = aSlotServ.GetSlot(); + if ( !pSlot ) + // get the slot - even if it is disabled on the dispatcher + pSlot = SfxSlotPool::GetSlotPool( rDispat.GetFrame() ).GetSlot( nId ); + + if ( !pSlot || !pSlot->pUnoName ) + { + bSlotDirty = sal_False; + bCtrlDirty = sal_True; + return aSlotServ.GetSlot()? &aSlotServ: 0; + } + + // create the dispatch URL from the slot data + ::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; + + // try to get a dispatch object for this command + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp = xProv->queryDispatch( aURL, ::rtl::OUString(), 0 ); + if ( xDisp.is() ) + { + // test the dispatch object if it is just a wrapper for a SfxDispatcher + ::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 ) + { + // The intercepting object is an SFX component + // If this dispatch object does not use the wanted dispatcher or the AppDispatcher, it's treated like any other UNO component + // (intercepting by internal dispatches) + SfxDispatcher *pDispatcher = pDisp->GetDispatcher_Impl(); + if ( pDispatcher == &rDispat || pDispatcher == SFX_APP()->GetAppDispatcher_Impl() ) + { + // so we can use it directly + bSlotDirty = sal_False; + bCtrlDirty = sal_True; + return aSlotServ.GetSlot()? &aSlotServ: 0; + } + } + + // so the dispatch object isn't a SfxDispatcher wrapper or it is one, but it uses another dispatcher, but not rDispat + pDispatch = new BindDispatch_Impl( xDisp, aURL, this, pSlot ); + pDispatch->acquire(); + + // flags must be set before adding StatusListener because the dispatch object will set the state + bSlotDirty = sal_False; + bCtrlDirty = sal_True; + xDisp->addStatusListener( pDispatch, aURL ); + } + else if ( rDispat.GetFrame() ) + { + ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider > xFrameProv( + rDispat.GetFrame()->GetFrame().GetFrameInterface(), ::com::sun::star::uno::UNO_QUERY ); + if ( xFrameProv != xProv ) + return GetSlotServer( rDispat, xFrameProv ); + } + } + + bSlotDirty = sal_False; + bCtrlDirty = sal_True; + } + + // we *always* return a SlotServer (if there is one); but in case of an external dispatch we might not use it + // for the "real" (non internal) controllers + return aSlotServ.GetSlot()? &aSlotServ: 0; +} + + +//-------------------------------------------------------------------- + +// Status setzen in allen Controllern + +void SfxStateCache::SetState +( + SfxItemState eState, // <SfxItemState> von 'pState' + const SfxPoolItem* pState, // Status des Slots, ggf. 0 oder -1 + BOOL bMaybeDirty +) + +/* [Beschreibung] + + Diese Methode verteilt die Status auf alle an dieser SID gebundenen + <SfxControllerItem>s. Ist der Wert derselbe wie zuvor und wurde in- + zwischen weder ein Controller angemeldet, noch ein Controller invalidiert, + dann wird kein Wert weitergeleitet. Dadurch wird z.B. Flackern in + ListBoxen vermieden. +*/ + +{ +// if ( pDispatch ) +// return; + SetState_Impl( eState, pState, bMaybeDirty ); +} + +//-------------------------------------------------------------------- + +void SfxStateCache::SetVisibleState( BOOL bShow ) +{ + SfxItemState eState( SFX_ITEM_AVAILABLE ); + const SfxPoolItem* pState( NULL ); + sal_Bool bNotify( sal_False ); + sal_Bool bDeleteItem( sal_False ); + + if ( bShow != bItemVisible ) + { + bItemVisible = bShow; + if ( bShow ) + { + if ( IsInvalidItem(pLastItem) || ( pLastItem == NULL )) + { + pState = new SfxVoidItem( nId ); + bDeleteItem = sal_True; + } + else + pState = pLastItem; + + eState = eLastState; + bNotify = ( pState != 0 ); + } + else + { + pState = new SfxVisibilityItem( nId, FALSE ); + bDeleteItem = sal_True; + } + + // Controller updaten + if ( !pDispatch && pController ) + { + for ( SfxControllerItem *pCtrl = pController; + pCtrl; + pCtrl = pCtrl->GetItemLink() ) + pCtrl->StateChanged( nId, eState, pState ); + } + + if ( pInternalController ) + pInternalController->StateChanged( nId, eState, pState ); + + if ( !bDeleteItem ) + delete pState; + } +} + +//-------------------------------------------------------------------- + +void SfxStateCache::SetState_Impl +( + SfxItemState eState, // <SfxItemState> von 'pState' + const SfxPoolItem* pState, // Status des Slots, ggf. 0 oder -1 + BOOL bMaybeDirty +) +{ + (void)bMaybeDirty; //unused + DBG_MEMTEST(); + DBG_CHKTHIS(SfxStateCache, 0); + + // wenn zwischen Enter- und LeaveRegistrations ein hartes Update kommt + // k"onnen zwischenzeitlich auch Cached ohne Controller exisitieren + if ( !pController && !pInternalController ) + return; + + DBG_ASSERT( bMaybeDirty || !bSlotDirty, "setting state of dirty message" ); +// DBG_ASSERT( bCtrlDirty || ( aSlotServ.GetSlot() && aSlotServ.GetSlot()->IsMode(SFX_SLOT_VOLATILE) ), ! Discussed with MBA +// "setting state of non dirty controller" ); + DBG_ASSERT( SfxControllerItem::GetItemState(pState) == eState, "invalid SfxItemState" ); + DBG_PROFSTART(SfxStateCacheSetState); + + // m"ussen die Controller "uberhaupt benachrichtigt werden? + FASTBOOL bNotify = bItemDirty; + if ( !bItemDirty ) + { + FASTBOOL bBothAvailable = pLastItem && pState && + !IsInvalidItem(pState) && !IsInvalidItem(pLastItem); + DBG_ASSERT( !bBothAvailable || pState != pLastItem, "setting state with own item" ); + if ( bBothAvailable ) + bNotify = pState->Type() != pLastItem->Type() || + *pState != *pLastItem; + else + bNotify = ( pState != pLastItem ) || ( eState != eLastState ); + } + + if ( bNotify ) + { + // Controller updaten + if ( !pDispatch && pController ) + { + for ( SfxControllerItem *pCtrl = pController; + pCtrl; + pCtrl = pCtrl->GetItemLink() ) + pCtrl->StateChanged( nId, eState, pState ); + } + + if ( pInternalController ) + ((SfxDispatchController_Impl *)pInternalController)->StateChanged( nId, eState, pState, &aSlotServ ); + + // neuen Wert merken + if ( !IsInvalidItem(pLastItem) ) + DELETEZ(pLastItem); + if ( pState && !IsInvalidItem(pState) ) + pLastItem = pState->Clone(); + else + pLastItem = 0; + eLastState = eState; + bItemDirty = sal_False; + } + + bCtrlDirty = sal_False; + DBG_PROFSTOP(SfxStateCacheSetState); +} + + +//-------------------------------------------------------------------- + +// alten Status in allen Controllern nochmal setzen + +void SfxStateCache::SetCachedState( BOOL bAlways ) +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxStateCache, 0); + DBG_ASSERT(pController==NULL||pController->GetId()==nId, "Cache mit falschem ControllerItem" ); + DBG_PROFSTART(SfxStateCacheSetState); + + // nur updaten wenn cached item vorhanden und auch verarbeitbar + // (Wenn der State gesendet wird, mu\s sichergestellt sein, da\s ein + // Slotserver vorhanden ist, s. SfxControllerItem::GetCoreMetric() ) + if ( bAlways || ( !bItemDirty && !bSlotDirty ) ) + { + // Controller updaten + if ( !pDispatch && pController ) + { + for ( SfxControllerItem *pCtrl = pController; + pCtrl; + pCtrl = pCtrl->GetItemLink() ) + pCtrl->StateChanged( nId, eLastState, pLastItem ); + } + + if ( pInternalController ) + ((SfxDispatchController_Impl *)pInternalController)->StateChanged( nId, eLastState, pLastItem, &aSlotServ ); + + // Controller sind jetzt ok + bCtrlDirty = sal_True; + } + + DBG_PROFSTOP(SfxStateCacheSetState); +} + + +//-------------------------------------------------------------------- + +// FloatingWindows in allen Controls mit dieser Id zerstoeren + +void SfxStateCache::DeleteFloatingWindows() +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxStateCache, 0); + + SfxControllerItem *pNextCtrl=0; + for ( SfxControllerItem *pCtrl=pController; pCtrl; pCtrl=pNextCtrl ) + { + DBG_TRACE((ByteString("pCtrl: ").Append(ByteString::CreateFromInt64((sal_uIntPtr)pCtrl))).GetBuffer()); + pNextCtrl = pCtrl->GetItemLink(); + pCtrl->DeleteFloatingWindow(); + } +} + +::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > SfxStateCache::GetDispatch() const +{ + if ( pDispatch ) + return pDispatch->xDisp; + return ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > (); +} + +void SfxStateCache::Dispatch( const SfxItemSet* pSet, sal_Bool bForceSynchron ) +{ + // protect pDispatch against destruction in the call + ::com::sun::star::uno::Reference < ::com::sun::star::frame::XStatusListener > xKeepAlive( pDispatch ); + if ( pDispatch ) + { + uno::Sequence < beans::PropertyValue > aArgs; + if (pSet) + TransformItems( nId, *pSet, aArgs ); + pDispatch->Dispatch( aArgs, bForceSynchron ); + } +} + + diff --git a/sfx2/source/control/unoctitm.cxx b/sfx2/source/control/unoctitm.cxx new file mode 100644 index 000000000000..f85d0d8e9e49 --- /dev/null +++ b/sfx2/source/control/unoctitm.cxx @@ -0,0 +1,1013 @@ +/************************************************************************* + * + * 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 <tools/debug.hxx> +#include <svl/eitem.hxx> +#include <svl/stritem.hxx> +#include <svl/intitem.hxx> +#include <svl/itemset.hxx> +#include <svl/visitem.hxx> +#include <svtools/javacontext.hxx> +#include <svl/itempool.hxx> +#include <tools/urlobj.hxx> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/frame/XFrameActionListener.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/frame/FrameActionEvent.hpp> +#include <com/sun/star/frame/FrameAction.hpp> +#include <com/sun/star/frame/status/ItemStatus.hpp> +#include <com/sun/star/frame/status/ItemState.hpp> +#include <com/sun/star/frame/DispatchResultState.hpp> +#include <com/sun/star/frame/status/Visibility.hpp> +#include <comphelper/processfactory.hxx> +#include <comphelper/sequence.hxx> +#include <vos/mutex.hxx> +#include <uno/current_context.hxx> +#include <vcl/svapp.hxx> + +#include <sfx2/app.hxx> +#include <sfx2/unoctitm.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/frame.hxx> +#include <sfx2/ctrlitem.hxx> +#include <sfx2/sfxuno.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/sfxsids.hrc> +#include <sfx2/request.hxx> +#include "statcach.hxx" +#include <sfx2/msgpool.hxx> +#include <sfx2/objsh.hxx> + +namespace css = ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; +//long nOfficeDispatchCount = 0; + +enum URLTypeId +{ + URLType_BOOL, + URLType_BYTE, + URLType_SHORT, + URLType_LONG, + URLType_HYPER, + URLType_STRING, + URLType_FLOAT, + URLType_DOUBLE, + URLType_COUNT +}; + +const char* URLTypeNames[URLType_COUNT] = +{ + "bool", + "byte", + "short", + "long", + "hyper", + "string", + "float", + "double" +}; + +SFX_IMPL_XINTERFACE_2( SfxUnoControllerItem, OWeakObject, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener ) +SFX_IMPL_XTYPEPROVIDER_2( SfxUnoControllerItem, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener ) + +SfxUnoControllerItem::SfxUnoControllerItem( SfxControllerItem *pItem, SfxBindings& rBind, const String& rCmd ) + : pCtrlItem( pItem ) + , pBindings( &rBind ) +{ + DBG_ASSERT( !pCtrlItem || !pCtrlItem->IsBound(), "ControllerItem fehlerhaft!" ); + + aCommand.Complete = rCmd; + Reference < XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance( rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY ); + xTrans->parseStrict( aCommand ); + pBindings->RegisterUnoController_Impl( this ); +} + +SfxUnoControllerItem::~SfxUnoControllerItem() +{ + // tell bindings to forget this controller ( if still connected ) + if ( pBindings ) + pBindings->ReleaseUnoController_Impl( this ); +} + +void SfxUnoControllerItem::UnBind() +{ + // connection to SfxControllerItem is lost + pCtrlItem = NULL; + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY ); + ReleaseDispatch(); +} + +void SAL_CALL SfxUnoControllerItem::statusChanged(const ::com::sun::star::frame::FeatureStateEvent& rEvent) throw ( ::com::sun::star::uno::RuntimeException ) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + DBG_ASSERT( pCtrlItem, "Dispatch hat den StatusListener nicht entfern!" ); + + if ( rEvent.Requery ) + { + // Fehler kann nur passieren, wenn das alte Dispatch fehlerhaft implementiert + // ist, also removeStatusListener nicht gefunzt hat. Aber sowas soll + // ja vorkommen ... + // Also besser vor ReleaseDispatch gegen Abflug sch"utzen! + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY ); + ReleaseDispatch(); + if ( pCtrlItem ) + GetNewDispatch(); // asynchron ?? + } + else if ( pCtrlItem ) + { + SfxItemState eState = SFX_ITEM_DISABLED; + SfxPoolItem* pItem = NULL; + if ( rEvent.IsEnabled ) + { + eState = SFX_ITEM_AVAILABLE; + ::com::sun::star::uno::Type pType = rEvent.State.getValueType(); + + if ( pType == ::getBooleanCppuType() ) + { + sal_Bool bTemp = false; + rEvent.State >>= bTemp ; + pItem = new SfxBoolItem( pCtrlItem->GetId(), bTemp ); + } + else if ( pType == ::getCppuType((const sal_uInt16*)0) ) + { + sal_uInt16 nTemp = 0; + rEvent.State >>= nTemp ; + pItem = new SfxUInt16Item( pCtrlItem->GetId(), nTemp ); + } + else if ( pType == ::getCppuType((const sal_uInt32*)0) ) + { + sal_uInt32 nTemp = 0; + rEvent.State >>= nTemp ; + pItem = new SfxUInt32Item( pCtrlItem->GetId(), nTemp ); + } + else if ( pType == ::getCppuType((const ::rtl::OUString*)0) ) + { + ::rtl::OUString sTemp ; + rEvent.State >>= sTemp ; + pItem = new SfxStringItem( pCtrlItem->GetId(), sTemp ); + } + else + pItem = new SfxVoidItem( pCtrlItem->GetId() ); + } + + pCtrlItem->StateChanged( pCtrlItem->GetId(), eState, pItem ); + delete pItem; + } +} + +void SAL_CALL SfxUnoControllerItem::disposing( const ::com::sun::star::lang::EventObject& ) throw ( ::com::sun::star::uno::RuntimeException ) +{ + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY ); + ReleaseDispatch(); +} + +void SfxUnoControllerItem::ReleaseDispatch() +{ + if ( xDispatch.is() ) + { + xDispatch->removeStatusListener( (::com::sun::star::frame::XStatusListener*) this, aCommand ); + xDispatch = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > (); + } +} + +void SfxUnoControllerItem::GetNewDispatch() +{ + if ( !pBindings ) + { + // Bindings released + DBG_ERROR( "Tried to get dispatch, but no Bindings!" ); + return; + } + + // forget old dispatch + xDispatch = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > (); + + // no arms, no cookies ! + if ( !pBindings->GetDispatcher_Impl() || !pBindings->GetDispatcher_Impl()->GetFrame() ) + return; + + SfxFrame& rFrame = pBindings->GetDispatcher_Impl()->GetFrame()->GetFrame(); + SfxFrame *pParent = rFrame.GetParentFrame(); + if ( pParent ) + // parent may intercept + xDispatch = TryGetDispatch( pParent ); + + if ( !xDispatch.is() ) + { + // no interception + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame = rFrame.GetFrameInterface(); + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv( xFrame, ::com::sun::star::uno::UNO_QUERY ); + if ( xProv.is() ) + xDispatch = xProv->queryDispatch( aCommand, ::rtl::OUString(), 0 ); + } + + if ( xDispatch.is() ) + xDispatch->addStatusListener( (::com::sun::star::frame::XStatusListener*) this, aCommand ); + else if ( pCtrlItem ) + pCtrlItem->StateChanged( pCtrlItem->GetId(), SFX_ITEM_DISABLED, NULL ); +} + +::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > SfxUnoControllerItem::TryGetDispatch( SfxFrame *pFrame ) +{ + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp; + SfxFrame *pParent = pFrame->GetParentFrame(); + if ( pParent ) + // parent may intercept + xDisp = TryGetDispatch( pParent ); + + // only components may intercept + if ( !xDisp.is() && pFrame->HasComponent() ) + { + // no interception + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame = pFrame->GetFrameInterface(); + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv( xFrame, ::com::sun::star::uno::UNO_QUERY ); + if ( xProv.is() ) + xDisp = xProv->queryDispatch( aCommand, ::rtl::OUString(), 0 ); + } + + return xDisp; +} + +void SfxUnoControllerItem::Execute() +{ + // dispatch the resource + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > aSeq(1); + aSeq[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Referer") ); + aSeq[0].Value <<= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("private:select") ); + if ( xDispatch.is() ) + xDispatch->dispatch( aCommand, aSeq ); +} + +void SfxUnoControllerItem::ReleaseBindings() +{ + // connection to binding is lost; so forget the binding and the dispatch + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY ); + ReleaseDispatch(); + if ( pBindings ) + pBindings->ReleaseUnoController_Impl( this ); + pBindings = NULL; +} + +void SfxStatusDispatcher::ReleaseAll() +{ + ::com::sun::star::lang::EventObject aObject; + aObject.Source = (::cppu::OWeakObject*) this; + aListeners.disposeAndClear( aObject ); +} + +void SAL_CALL SfxStatusDispatcher::dispatch( const ::com::sun::star::util::URL&, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& ) throw ( ::com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL SfxStatusDispatcher::dispatchWithNotification( + const ::com::sun::star::util::URL&, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >&, + const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchResultListener >& ) throw( ::com::sun::star::uno::RuntimeException ) +{ +} + +SFX_IMPL_XINTERFACE_2( SfxStatusDispatcher, OWeakObject, ::com::sun::star::frame::XNotifyingDispatch, ::com::sun::star::frame::XDispatch ) +SFX_IMPL_XTYPEPROVIDER_2( SfxStatusDispatcher, ::com::sun::star::frame::XNotifyingDispatch, ::com::sun::star::frame::XDispatch ) +//IMPLNAME "com.sun.star.comp.sfx2.StatusDispatcher", + +SfxStatusDispatcher::SfxStatusDispatcher() + : aListeners( aMutex ) +{ +} + +void SAL_CALL SfxStatusDispatcher::addStatusListener(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > & aListener, const ::com::sun::star::util::URL& aURL) throw ( ::com::sun::star::uno::RuntimeException ) +{ + aListeners.addInterface( aURL.Complete, aListener ); + if ( aURL.Complete.compareToAscii(".uno:LifeTime")==0 ) + { + ::com::sun::star::frame::FeatureStateEvent aEvent; + aEvent.FeatureURL = aURL; + aEvent.Source = (::com::sun::star::frame::XDispatch*) this; + aEvent.IsEnabled = sal_True; + aEvent.Requery = sal_False; + aListener->statusChanged( aEvent ); + } +} + +void SAL_CALL SfxStatusDispatcher::removeStatusListener( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > & aListener, const ::com::sun::star::util::URL& aURL ) throw ( ::com::sun::star::uno::RuntimeException ) +{ + aListeners.removeInterface( aURL.Complete, aListener ); +} + +SFX_IMPL_XINTERFACE_1( SfxOfficeDispatch, SfxStatusDispatcher, ::com::sun::star::lang::XUnoTunnel ) +SFX_IMPL_XTYPEPROVIDER_2( SfxOfficeDispatch, ::com::sun::star::frame::XNotifyingDispatch, ::com::sun::star::lang::XUnoTunnel ) + + +//------------------------------------------------------------------------- +// XUnoTunnel +sal_Int64 SAL_CALL SfxOfficeDispatch::getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) throw(::com::sun::star::uno::RuntimeException) +{ + if ( aIdentifier == impl_getStaticIdentifier() ) + return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >( this )); + else + return 0; +} + +/* ASDBG +void* SfxOfficeDispatch::getImplementation(Reflection *p) +{ + if( p == ::getCppuType((const SfxOfficeDispatch*)0) ) + return this; + else + return ::cppu::OWeakObject::getImplementation(p); + +} + +Reflection* ::getCppuType((const SfxOfficeDispatch*)0) +{ + static StandardClassReflection aRefl( + 0, + createStandardClass( + "SfxOfficeDispatch", ::cppu::OWeakObject::get::cppu::OWeakObjectIdlClass(), + 1, + ::getCppuType((const ::com::sun::star::frame::XDispatch*)0) ) ); + return &aRefl; +} +*/ + +SfxOfficeDispatch::SfxOfficeDispatch( SfxBindings& rBindings, SfxDispatcher* pDispat, const SfxSlot* pSlot, const ::com::sun::star::util::URL& rURL ) +{ +// nOfficeDispatchCount++; + + // this object is an adapter that shows a ::com::sun::star::frame::XDispatch-Interface to the outside and uses a SfxControllerItem to monitor a state + pControllerItem = new SfxDispatchController_Impl( this, &rBindings, pDispat, pSlot, rURL ); +} + +SfxOfficeDispatch::SfxOfficeDispatch( SfxDispatcher* pDispat, const SfxSlot* pSlot, const ::com::sun::star::util::URL& rURL ) +{ +// nOfficeDispatchCount++; + + // this object is an adapter that shows a ::com::sun::star::frame::XDispatch-Interface to the outside and uses a SfxControllerItem to monitor a state + pControllerItem = new SfxDispatchController_Impl( this, NULL, pDispat, pSlot, rURL ); +} + +SfxOfficeDispatch::~SfxOfficeDispatch() +{ +// --nOfficeDispatchCount; + + if ( pControllerItem ) + { + // when dispatch object is released, destroy its connection to this object and destroy it + pControllerItem->UnBindController(); + delete pControllerItem; + } +} + +const ::com::sun::star::uno::Sequence< sal_Int8 >& SfxOfficeDispatch::impl_getStaticIdentifier() +{ + // {38 57 CA 80 09 36 11 d4 83 FE 00 50 04 52 6B 21} + static sal_uInt8 pGUID[16] = { 0x38, 0x57, 0xCA, 0x80, 0x09, 0x36, 0x11, 0xd4, 0x83, 0xFE, 0x00, 0x50, 0x04, 0x52, 0x6B, 0x21 }; + static ::com::sun::star::uno::Sequence< sal_Int8 > seqID((sal_Int8*)pGUID,16) ; + return seqID ; +} + + +void SAL_CALL SfxOfficeDispatch::dispatch( const ::com::sun::star::util::URL& aURL, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs ) throw ( ::com::sun::star::uno::RuntimeException ) +{ + // ControllerItem is the Impl class + if ( pControllerItem ) + { + // The JavaContext contains an interaction handler which is used when + // the creation of a Java Virtual Machine fails. The second parameter + // indicates, that there shall only be one user notification (message box) + // even if the same error (interaction) reoccurs. The effect is, that if a + // user selects a menu entry than they may get only one notification that + // a JRE is not selected. + com::sun::star::uno::ContextLayer layer( + new svt::JavaContext( com::sun::star::uno::getCurrentContext(), + true) ); + + pControllerItem->dispatch( aURL, aArgs, ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchResultListener >() ); + } +} + +void SAL_CALL SfxOfficeDispatch::dispatchWithNotification( const ::com::sun::star::util::URL& aURL, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs, + const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchResultListener >& rListener ) throw( ::com::sun::star::uno::RuntimeException ) +{ + // ControllerItem is the Impl class + if ( pControllerItem ) + { + // see comment for SfxOfficeDispatch::dispatch + com::sun::star::uno::ContextLayer layer( + new svt::JavaContext( com::sun::star::uno::getCurrentContext(), + true) ); + + pControllerItem->dispatch( aURL, aArgs, rListener ); + } +} + +void SAL_CALL SfxOfficeDispatch::addStatusListener(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > & aListener, const ::com::sun::star::util::URL& aURL) throw ( ::com::sun::star::uno::RuntimeException ) +{ + GetListeners().addInterface( aURL.Complete, aListener ); + if ( pControllerItem ) + { + // ControllerItem is the Impl class + pControllerItem->addStatusListener( aListener, aURL ); + } +} + +SfxDispatcher* SfxOfficeDispatch::GetDispatcher_Impl() +{ + return pControllerItem->GetDispatcher(); +} + +void SfxOfficeDispatch::SetFrame(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame) +{ + if ( pControllerItem ) + pControllerItem->SetFrame( xFrame ); +} + +void SfxOfficeDispatch::SetMasterUnoCommand( sal_Bool bSet ) +{ + if ( pControllerItem ) + pControllerItem->setMasterSlaveCommand( bSet ); +} + +sal_Bool SfxOfficeDispatch::IsMasterUnoCommand() const +{ + if ( pControllerItem ) + return pControllerItem->isMasterSlaveCommand(); + return sal_False; +} + +// Determine if URL contains a master/slave command which must be handled a little bit different +sal_Bool SfxOfficeDispatch::IsMasterUnoCommand( const ::com::sun::star::util::URL& aURL ) +{ + if ( aURL.Protocol.equalsAscii( ".uno:" ) && + ( aURL.Path.indexOf( '.' ) > 0 )) + return sal_True; + + return sal_False; +} + +rtl::OUString SfxOfficeDispatch::GetMasterUnoCommand( const ::com::sun::star::util::URL& aURL ) +{ + rtl::OUString aMasterCommand; + if ( IsMasterUnoCommand( aURL )) + { + sal_Int32 nIndex = aURL.Path.indexOf( '.' ); + if ( nIndex > 0 ) + aMasterCommand = aURL.Path.copy( 0, nIndex ); + } + + return aMasterCommand; +} + +SfxDispatchController_Impl::SfxDispatchController_Impl( + SfxOfficeDispatch* pDisp, + SfxBindings* pBind, + SfxDispatcher* pDispat, + const SfxSlot* pSlot, + const ::com::sun::star::util::URL& rURL ) + : aDispatchURL( rURL ) + , pDispatcher( pDispat ) + , pBindings( pBind ) + , pLastState( 0 ) + , nSlot( pSlot->GetSlotId() ) + , pDispatch( pDisp ) + , bMasterSlave( sal_False ) + , bVisible( sal_True ) + , pUnoName( pSlot->pUnoName ) +{ + if ( aDispatchURL.Protocol.equalsAscii("slot:") && pUnoName ) + { + ByteString aTmp(".uno:"); + aTmp += pUnoName; + aDispatchURL.Complete = ::rtl::OUString::createFromAscii( aTmp.GetBuffer() ); + Reference < ::com::sun::star::util::XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance( rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY ); + xTrans->parseStrict( aDispatchURL ); + } + + SetId( nSlot ); + if ( pBindings ) + { + // Bind immediately to enable the cache to recycle dispatches when asked for the same command + // a command in "slot" or in ".uno" notation must be treated as identical commands! + pBindings->ENTERREGISTRATIONS(); + BindInternal_Impl( nSlot, pBindings ); + pBindings->LEAVEREGISTRATIONS(); + } +} + +SfxDispatchController_Impl::~SfxDispatchController_Impl() +{ + if ( pLastState && !IsInvalidItem( pLastState ) ) + delete pLastState; + + if ( pDispatch ) + { + // disconnect + pDispatch->pControllerItem = NULL; + + // force all listeners to release the dispatch object + ::com::sun::star::lang::EventObject aObject; + aObject.Source = (::cppu::OWeakObject*) pDispatch; + pDispatch->GetListeners().disposeAndClear( aObject ); + } +} + +void SfxDispatchController_Impl::SetFrame(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& _xFrame) +{ + xFrame = _xFrame; +} + +void SfxDispatchController_Impl::setMasterSlaveCommand( sal_Bool bSet ) +{ + bMasterSlave = bSet; +} + +sal_Bool SfxDispatchController_Impl::isMasterSlaveCommand() const +{ + return bMasterSlave; +} + +void SfxDispatchController_Impl::UnBindController() +{ + pDispatch = NULL; + if ( IsBound() ) + { + GetBindings().ENTERREGISTRATIONS(); + SfxControllerItem::UnBind(); + GetBindings().LEAVEREGISTRATIONS(); + } +} + +void SfxDispatchController_Impl::addParametersToArgs( const com::sun::star::util::URL& aURL, ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rArgs ) const +{ + // Extract the parameter from the URL and put them into the property value sequence + sal_Int32 nQueryIndex = aURL.Complete.indexOf( '?' ); + if ( nQueryIndex > 0 ) + { + rtl::OUString aParamString( aURL.Complete.copy( nQueryIndex+1 )); + sal_Int32 nIndex = 0; + do + { + rtl::OUString aToken = aParamString.getToken( 0, '&', nIndex ); + + sal_Int32 nParmIndex = 0; + rtl::OUString aParamType; + rtl::OUString aParamName = aToken.getToken( 0, '=', nParmIndex ); + rtl::OUString aValue = (nParmIndex!=-1) ? aToken.getToken( 0, '=', nParmIndex ) : ::rtl::OUString(); + + if ( aParamName.getLength() > 0 ) + { + nParmIndex = 0; + aToken = aParamName; + aParamName = (nParmIndex!=-1) ? aToken.getToken( 0, ':', nParmIndex ) : ::rtl::OUString(); + aParamType = (nParmIndex!=-1) ? aToken.getToken( 0, ':', nParmIndex ) : ::rtl::OUString(); + } + + sal_Int32 nLen = rArgs.getLength(); + rArgs.realloc( nLen+1 ); + rArgs[nLen].Name = aParamName; + + if ( aParamType.getLength() == 0 ) + { + // Default: LONG + rArgs[nLen].Value <<= aValue.toInt32(); + } + else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_BOOL], 4 )) + { + // BOOL support + rArgs[nLen].Value <<= aValue.toBoolean(); + } + else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_BYTE], 4 )) + { + // BYTE support + rArgs[nLen].Value <<= sal_Int8( aValue.toInt32() ); + } + else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_LONG], 4 )) + { + // LONG support + rArgs[nLen].Value <<= aValue.toInt32(); + } + else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_SHORT], 5 )) + { + // SHORT support + rArgs[nLen].Value <<= sal_Int8( aValue.toInt32() ); + } + else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_HYPER], 5 )) + { + // HYPER support + rArgs[nLen].Value <<= aValue.toInt64(); + } + else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_FLOAT], 5 )) + { + // FLOAT support + rArgs[nLen].Value <<= aValue.toFloat(); + } + else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_STRING], 6 )) + { + // STRING support + rArgs[nLen].Value <<= rtl::OUString( INetURLObject::decode( aValue, '%', INetURLObject::DECODE_WITH_CHARSET )); + } + else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_DOUBLE], 6)) + { + // DOUBLE support + rArgs[nLen].Value <<= aValue.toDouble(); + } + } + while ( nIndex >= 0 ); + } +} + +SfxMapUnit SfxDispatchController_Impl::GetCoreMetric( SfxItemPool& rPool, sal_uInt16 nSlotId ) +{ + USHORT nWhich = rPool.GetWhich( nSlotId ); + return rPool.GetMetric( nWhich ); +} + +rtl::OUString SfxDispatchController_Impl::getSlaveCommand( const ::com::sun::star::util::URL& rURL ) +{ + rtl::OUString aSlaveCommand; + sal_Int32 nIndex = rURL.Path.indexOf( '.' ); + if (( nIndex > 0 ) && ( nIndex < rURL.Path.getLength() )) + aSlaveCommand = rURL.Path.copy( nIndex+1 ); + return aSlaveCommand; +} + +void SAL_CALL SfxDispatchController_Impl::dispatch( const ::com::sun::star::util::URL& aURL, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs, + const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchResultListener >& rListener ) throw( ::com::sun::star::uno::RuntimeException ) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( + pDispatch && + ( + (aURL.Protocol.equalsAsciiL( ".uno:", 5 ) && aURL.Path == aDispatchURL.Path) || + (aURL.Protocol.equalsAsciiL( "slot:", 5 ) && aURL.Path.toInt32() == GetId()) + ) + ) + { + /* + if ( !IsBound() && pBindings ) + { + pBindings->ENTERREGISTRATIONS(); + BindInternal_Impl( nSlot, pBindings ); + pBindings->LEAVEREGISTRATIONS(); + } */ + + if ( !pDispatcher && pBindings ) + pDispatcher = GetBindings().GetDispatcher_Impl(); + + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > lNewArgs; + sal_Int32 nCount = aArgs.getLength(); + + // Support for URL based arguments + INetURLObject aURLObj( aURL.Complete ); + if ( aURLObj.HasParam() ) + addParametersToArgs( aURL, lNewArgs ); + + // Try to find call mode and frame name inside given arguments... + SfxCallMode nCall = SFX_CALLMODE_STANDARD; + sal_Int32 nMarkArg = -1; + + // Filter arguments which shouldn't be part of the sequence property value + sal_Bool bTemp = sal_Bool(); + sal_uInt16 nModifier(0); + std::vector< ::com::sun::star::beans::PropertyValue > aAddArgs; + for( sal_Int32 n=0; n<nCount; n++ ) + { + const ::com::sun::star::beans::PropertyValue& rProp = aArgs[n]; + if( rProp.Name.equalsAsciiL("SynchronMode",12)) + { + if( rProp.Value >>=bTemp ) + nCall = bTemp ? SFX_CALLMODE_SYNCHRON : SFX_CALLMODE_ASYNCHRON; + } + else if( rProp.Name.equalsAsciiL("Bookmark",8)) + { + nMarkArg = n; + aAddArgs.push_back( aArgs[n] ); + } + else if( rProp.Name.equalsAsciiL("KeyModifier",11)) + rProp.Value >>= nModifier; + else + aAddArgs.push_back( aArgs[n] ); + } + + // Add needed arguments to sequence property value + sal_uInt32 nAddArgs = aAddArgs.size(); + if ( nAddArgs > 0 ) + { + sal_uInt32 nIndex( lNewArgs.getLength() ); + + lNewArgs.realloc( lNewArgs.getLength()+aAddArgs.size() ); + for ( sal_uInt32 i = 0; i < nAddArgs; i++ ) + lNewArgs[nIndex++] = aAddArgs[i]; + } + + // Overwrite possible detected sychron argument, if real listener exists (currently no other way) + if ( rListener.is() ) + nCall = SFX_CALLMODE_SYNCHRON; + + if( GetId() == SID_JUMPTOMARK && nMarkArg == - 1 ) + { + // we offer dispatches for SID_JUMPTOMARK if the URL points to a bookmark inside the document + // so we must retrieve this as an argument from the parsed URL + lNewArgs.realloc( lNewArgs.getLength()+1 ); + nMarkArg = lNewArgs.getLength()-1; + lNewArgs[nMarkArg].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Bookmark")); + lNewArgs[nMarkArg].Value <<= aURL.Mark; + } + + css::uno::Reference< css::frame::XFrame > xFrameRef(xFrame.get(), css::uno::UNO_QUERY); + if (! xFrameRef.is() && pDispatcher) + { + SfxViewFrame* pViewFrame = pDispatcher->GetFrame(); + if (pViewFrame) + xFrameRef = pViewFrame->GetFrame().GetFrameInterface(); + } + SfxAllItemSet aInternalSet( SFX_APP()->GetPool() ); + if (xFrameRef.is()) // an empty set is no problem ... but an empty frame reference can be a problem ! + aInternalSet.Put( SfxUnoFrameItem( SID_FILLFRAME, xFrameRef ) ); + + sal_Bool bSuccess = sal_False; + sal_Bool bFailure = sal_False; + const SfxPoolItem* pItem = NULL; + SfxShell* pShell( 0 ); + // #i102619# Retrieve metric from shell before execution - the shell could be destroyed after execution + SfxMapUnit eMapUnit( SFX_MAPUNIT_100TH_MM ); + if ( pDispatcher->GetBindings() ) + { + if ( !pDispatcher->IsLocked( GetId() ) ) + { + const SfxSlot *pSlot = 0; + if ( pDispatcher->GetShellAndSlot_Impl( GetId(), &pShell, &pSlot, sal_False, + SFX_CALLMODE_MODAL==(nCall&SFX_CALLMODE_MODAL), FALSE ) ) + { + if ( bMasterSlave ) + { + // Extract slave command and add argument to the args list. Master slot MUST + // have a argument that has the same name as the master slot and type is SfxStringItem. + sal_Int32 nIndex = lNewArgs.getLength(); + lNewArgs.realloc( nIndex+1 ); + lNewArgs[nIndex].Name = rtl::OUString::createFromAscii( pSlot->pUnoName ); + lNewArgs[nIndex].Value = makeAny( SfxDispatchController_Impl::getSlaveCommand( aDispatchURL )); + } + + eMapUnit = GetCoreMetric( pShell->GetPool(), GetId() ); + SfxAllItemSet aSet( pShell->GetPool() ); + TransformParameters( GetId(), lNewArgs, aSet, pSlot ); + if ( aSet.Count() ) + { + // execute with arguments - call directly + pItem = pDispatcher->Execute( GetId(), nCall, &aSet, &aInternalSet, nModifier ); + bSuccess = (pItem != NULL); + } + else + { + // execute using bindings, enables support for toggle/enum etc. + SfxRequest aReq( GetId(), nCall, pShell->GetPool() ); + aReq.SetModifier( nModifier ); + aReq.SetInternalArgs_Impl(aInternalSet); + pDispatcher->GetBindings()->Execute_Impl( aReq, pSlot, pShell ); + pItem = aReq.GetReturnValue(); + bSuccess = aReq.IsDone() || pItem != NULL; + bFailure = aReq.IsCancelled(); + } + } +#ifdef DBG_UTIL + else + DBG_WARNING("MacroPlayer: Unknown slot dispatched!"); +#endif + } + } + else + { + eMapUnit = GetCoreMetric( SFX_APP()->GetPool(), GetId() ); + // AppDispatcher + SfxAllItemSet aSet( SFX_APP()->GetPool() ); + TransformParameters( GetId(), lNewArgs, aSet ); + + if ( aSet.Count() ) + pItem = pDispatcher->Execute( GetId(), nCall, &aSet, &aInternalSet, nModifier ); + else + // SfxRequests take empty sets as argument sets, GetArgs() returning non-zero! + pItem = pDispatcher->Execute( GetId(), nCall, 0, &aInternalSet, nModifier ); + + // no bindings, no invalidate ( usually done in SfxDispatcher::Call_Impl()! ) + if ( SfxApplication::Get() ) + { + SfxDispatcher* pAppDispat = SFX_APP()->GetAppDispatcher_Impl(); + if ( pAppDispat ) + { + const SfxPoolItem* pState=0; + SfxItemState eState = pDispatcher->QueryState( GetId(), pState ); + StateChanged( GetId(), eState, pState ); + } + } + + bSuccess = (pItem != NULL); + } + + if ( rListener.is() ) + { + ::com::sun::star::frame::DispatchResultEvent aEvent; + if ( bSuccess ) + aEvent.State = com::sun::star::frame::DispatchResultState::SUCCESS; +// else if ( bFailure ) + else + aEvent.State = com::sun::star::frame::DispatchResultState::FAILURE; +// else +// aEvent.State = com::sun::star::frame::DispatchResultState::DONTKNOW; + + aEvent.Source = (::com::sun::star::frame::XDispatch*) pDispatch; + if ( bSuccess && pItem && !pItem->ISA(SfxVoidItem) ) + { + USHORT nSubId( 0 ); + if ( eMapUnit == SFX_MAPUNIT_TWIP ) + nSubId |= CONVERT_TWIPS; + pItem->QueryValue( aEvent.Result, (BYTE)nSubId ); + } + + rListener->dispatchFinished( aEvent ); + } + } +} + +SfxDispatcher* SfxDispatchController_Impl::GetDispatcher() +{ + if ( !pDispatcher && pBindings ) + pDispatcher = GetBindings().GetDispatcher_Impl(); + return pDispatcher; +} + +void SAL_CALL SfxDispatchController_Impl::addStatusListener(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > & aListener, const ::com::sun::star::util::URL& aURL) throw ( ::com::sun::star::uno::RuntimeException ) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( !pDispatch ) + return; + + /*if ( !IsBound() && pBindings ) + { + pBindings->ENTERREGISTRATIONS(); + BindInternal_Impl( nSlot, pBindings ); + pBindings->LEAVEREGISTRATIONS(); + } */ + + // Use alternative QueryState call to have a valid UNO representation of the state. + ::com::sun::star::uno::Any aState; + if ( !pDispatcher && pBindings ) + pDispatcher = GetBindings().GetDispatcher_Impl(); + SfxItemState eState = pDispatcher->QueryState( GetId(), aState ); + + if ( eState == SFX_ITEM_DONTCARE ) + { + // Use special uno struct to transport don't care state + ::com::sun::star::frame::status::ItemStatus aItemStatus; + aItemStatus.State = ::com::sun::star::frame::status::ItemState::dont_care; + aState = makeAny( aItemStatus ); + } + + ::com::sun::star::frame::FeatureStateEvent aEvent; + aEvent.FeatureURL = aURL; + aEvent.Source = (::com::sun::star::frame::XDispatch*) pDispatch; + aEvent.Requery = sal_False; + if ( bVisible ) + { + aEvent.IsEnabled = eState != SFX_ITEM_DISABLED; + aEvent.State = aState; + } + else + { + ::com::sun::star::frame::status::Visibility aVisibilityStatus; + aVisibilityStatus.bVisible = sal_False; + + // MBA: we might decide to *not* disable "invisible" slots, but this would be + // a change that needs to adjust at least the testtool + aEvent.IsEnabled = sal_False; + aEvent.State = makeAny( aVisibilityStatus ); + } + + aListener->statusChanged( aEvent ); +} + +void SfxDispatchController_Impl::StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState, SfxSlotServer* pSlotServ ) +{ + if ( !pDispatch ) + return; + + // Bindings instance notifies controller about a state change, listeners must be notified also + // Don't cache visibility state changes as they are volatile. We need our real state to send it + // to our controllers after visibility is set to true. + sal_Bool bNotify = sal_True; + if ( pState && !IsInvalidItem( pState ) ) + { + if ( !pState->ISA( SfxVisibilityItem ) ) + { + sal_Bool bBothAvailable = pLastState && !IsInvalidItem(pLastState); + if ( bBothAvailable ) + bNotify = pState->Type() != pLastState->Type() || *pState != *pLastState; + if ( pLastState && !IsInvalidItem( pLastState ) ) + delete pLastState; + pLastState = !IsInvalidItem(pState) ? pState->Clone() : pState; + bVisible = sal_True; + } + else + bVisible = ((SfxVisibilityItem *)pState)->GetValue(); + } + else + { + if ( pLastState && !IsInvalidItem( pLastState ) ) + delete pLastState; + pLastState = pState; + } + + ::cppu::OInterfaceContainerHelper* pContnr = pDispatch->GetListeners().getContainer ( aDispatchURL.Complete ); + if ( bNotify && pContnr ) + { + ::com::sun::star::uno::Any aState; + if ( ( eState >= SFX_ITEM_AVAILABLE ) && pState && !IsInvalidItem( pState ) && !pState->ISA(SfxVoidItem) ) + { + // Retrieve metric from pool to have correct sub ID when calling QueryValue + USHORT nSubId( 0 ); + SfxMapUnit eMapUnit( SFX_MAPUNIT_100TH_MM ); + + // retrieve the core metric + // it's enough to check the objectshell, the only shell that does not use the pool of the document + // is SfxViewFrame, but it hasn't any metric parameters + // TODO/LATER: what about the FormShell? Does it use any metric data?! Perhaps it should use the Pool of the document! + if ( pSlotServ && pDispatcher ) + { + SfxShell* pShell = pDispatcher->GetShell( pSlotServ->GetShellLevel() ); + DBG_ASSERT( pShell, "Can't get core metric without shell!" ); + if ( pShell ) + eMapUnit = GetCoreMetric( pShell->GetPool(), nSID ); + } + + if ( eMapUnit == SFX_MAPUNIT_TWIP ) + nSubId |= CONVERT_TWIPS; + + pState->QueryValue( aState, (BYTE)nSubId ); + } + else if ( eState == SFX_ITEM_DONTCARE ) + { + // Use special uno struct to transport don't care state + ::com::sun::star::frame::status::ItemStatus aItemStatus; + aItemStatus.State = ::com::sun::star::frame::status::ItemState::dont_care; + aState = makeAny( aItemStatus ); + } + + ::com::sun::star::frame::FeatureStateEvent aEvent; + aEvent.FeatureURL = aDispatchURL; + aEvent.Source = (::com::sun::star::frame::XDispatch*) pDispatch; + aEvent.IsEnabled = eState != SFX_ITEM_DISABLED; + aEvent.Requery = sal_False; + aEvent.State = aState; + + ::cppu::OInterfaceIteratorHelper aIt( *pContnr ); + while( aIt.hasMoreElements() ) + { + try + { + ((::com::sun::star::frame::XStatusListener *)aIt.next())->statusChanged( aEvent ); + } + catch( ::com::sun::star::uno::RuntimeException& ) + { + aIt.remove(); + } + } + } +} + +void SfxDispatchController_Impl::StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState ) +{ + StateChanged( nSID, eState, pState, 0 ); +} |