/************************************************************************* * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: bindings.cxx,v $ * * $Revision: 1.49 $ * * last change: $Author: vg $ $Date: 2006-11-21 17:47:45 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. * * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2005 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sfx2.hxx" #include #ifndef _SFXITEMPOOL_HXX //autogen #include #endif #ifndef _SFXITEMITER_HXX //autogen #include #endif #ifndef _SFXENUMITEM_HXX //autogen #include #endif #ifndef _AEITEM_HXX //autogen #include #endif #include #include #include #ifndef _COM_SUN_STAR_UTIL_XURLTRANSFORMER_HPP_ #include #endif #ifndef _COM_SUN_STAR_FRAME_XDISPATCHPROVIDERINTERCEPTOR_HPP_ #include #endif #ifndef _COM_SUN_STAR_FRAME_XDISPATCH_HPP_ #include #endif #ifndef _COM_SUN_STAR_FRAME_XDISPATCHPROVIDER_HPP_ #include #endif #ifndef _COM_SUN_STAR_FRAME_XSTATUSLISTENER_HPP_ #include #endif #ifndef _COM_SUN_STAR_FRAME_FRAMESEARCHFLAG_HPP_ #include #endif #ifndef _COM_SUN_STAR_FRAME_XDISPATCHPROVIDERINTERCEPTION_HPP_ #include #endif #ifndef _COM_SUN_STAR_FRAME_FEATURESTATEEVENT_HPP_ #include #endif #ifndef _COM_SUN_STAR_FRAME_DISPATCHDESCRIPTOR_HPP_ #include #endif #ifndef _COM_SUN_STAR_FRAME_XCONTROLLER_HPP_ #include #endif #include #include #ifndef GCC #endif // wg. nInReschedule #include "appdata.hxx" #include "bindings.hxx" #include "msg.hxx" #include "statcach.hxx" #include "ctrlitem.hxx" #include "app.hxx" #include "dispatch.hxx" #include "request.hxx" #include "objface.hxx" #include "sfxtypes.hxx" #include "workwin.hxx" #include "macrconf.hxx" #include "unoctitm.hxx" #include "sfx.hrc" #include "sfxuno.hxx" #include "topfrm.hxx" #include "objsh.hxx" #include "msgpool.hxx" 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(); ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > aSeq; xDisp->dispatch( aCommand, aSeq ); delete this; return 0L; } class SfxBindings_Impl /* [Beschreibung] Diese Implementations-Struktur der Klasse SfxBindings dient der Entkopplung von "Anderungen vom exportierten Interface sowie der Verringerung von extern sichtbaren Symbolen. Eine Instanz exisitiert pro SfxBindings-Instanz f"ur deren Laufzeit. */ { 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 /* [Beschreibung] In Instanzen dieser Struktur werden in weitere Informationen zu den gemeinsam von einem zu erfragenden Status gesammelt, deren Ids dort in die Ranges eines s aufgenommen werden. Diese Informationen werden w"ahrend der Suche nach den zusammen upzudatenden Ids sowieso als Zwischenergebnis ermittelt und nachher wieder ben"otigt, daher macht es Sinn, sie f"ur diesen kurzen Zeitraum gleich aufzubewahren. */ { sal_uInt16 nSlotId; // die Slot-Id sal_uInt16 nWhichId; // falls verf"ugbar die Which-Id, sonst nSlotId const SfxSlot* pSlot; // Pointer auf den 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; } const int operator==( const SfxFoundCache_Impl &r ) { 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() /* [Beschreibung] Konstruktor der Klasse SfxBindings. Genau eine Instanz wird automatisch von der vor angelegt. Wird eine Instanz ben"otigt, z.B. zum Invalidieren von Slots, sollte diese "uber den zugeh"origen besorgt werden. Bestimmte SfxViewFrame Subklassen (z.B. ) legen ihre eigene Instanz der SfxBindings an. Instanzen k"onnen erst angelegt werden, wenn die zugeh"orige SfxBindings Instanz existiert. */ : 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 existierende Instanz wird von der nach Ausf"urhung von automatisch zerst"ort. Noch existierende 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() /* [Beschreibung] Interne Methode zum l"oschen noch existierender Instanzen, die bei dieser SfxBindings Instanz angemeldet sind. Dies sind i.d.R. s. Nich sich selbst geh"orende SfxControllerItems d"urfen bei Aufruf nur noch existieren, wenn sie einem der restlichen SfxPopupWindows geh"oren. [Anmerkung] Wird beim Beenden der Applikation gerufen, bevor das Applikations- Fenster gel"oscht wird. */ { // 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 ) /* [Beschreibung] Dieser Methode versteckt und zeigt die , die aus s dieser SfxBindings-Instanz abgerissen wurden bzw. floating -Instanzen dieser SfxBindings-Instanz. [Anmerkung] Es k"onnten noch weitere Floating-Windows exisitieren, die durch diese Methode nicht erfa\st werden. */ { // 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 ) /* [Beschreibung] Interne Methode zum Updaten eines Caches und den von derselben Status-Methode in derselben Shell bedienten und dirty Slots. */ { 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 ) /* [Beschreibung] Diese Methode sorgt f"ur synchrones Updaten der auf die Slot-Id nId gebundenen Instanzen, die an dieser SfxBindings Instanz angemeldet sind. Vergleichbar zu Window::Update() (StarView) erfolgt ein Update nur, wenn entweder ein auf diese Slot-Id gebundenes SfxContollerItem dirty ist, oder die Slot-Id selbst dirty ist. Dies kann durch einen vorhergehendes Aufruf von erzwungen werden. [Anmerkung] Es ist g"unstiger, zun"achst alle zu invalidierenden Slot-Ids per zu invalidieren und dann Update() aufzurufen, als einzelne abwechselnde Invalidate/Update, da von derselben Status-Methode bediente Status-Anfragen von den SfxBindings automatisch zusammengefa"st werden. [Querverweise] */ { 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() /* [Beschreibung] Diese Methode sorgt f"ur synchrones Updaten aller Instanzen, die an dieser SfxBindings Instanz angemeldet sind. Vergleichbar zu Window::Update() (StarView) erfolgt ein Update nur, wenn entweder ein SfxContollerItem dirty ist, in einem Status-Cache der Zeiger auf den dirty ist. Ersteres kann durch einen Aufruf von erzwungen werden, letzters durch . [Querverweise] */ { 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 ) /* [Beschreibung] Diese Methode erlaubt das direkte Setzen neuer Status-Werte, ohne den Umweg "uber und das dann im Update erfolgende Rufen der Status-Methoden an den s. [Querverweise] */ { // 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 ) /* [Beschreibung] Diese Methode erlaubt das direkte Setzen eines neuen Status-Wertes, ohne den Umweg "uber und das dann im Update erfolgende Rufen der Status-Methoden an den s. Mit dieser Methode k"onnen nur s mit Slot, nicht aber mit Which-Id gesetzt werden, da kein bekannt ist, "uber den gemappt werden k"onnte. [Querverweise] */ { 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. */ ) /* [Beschreibung] Diese Methode sucht die zu einer Slot-Id geh"orige Instanz. Falls die Slot-Id in keinem Controller gebunden ist, wird ein 0-Pointer zur"uckgegeben. Falls pPos != 0, wird erst ab der Position mit der Suche angefangen. Dieses ist eine Optimierung, f"ur den Fall, da"s die kleineren Ids bereits abgearbeitet wurden. In *pPos wird der ::com::sun::star::sdbcx::Index innerhalb der SfxBindings zur"uckgegeben, unter dem dieser Cache z.Zt. abgelegt ist. Dieser ::com::sun::star::sdbcx::Index ist bis zum n"achsten Aufruf von g"ultig. W"ahrend der Umkonfiguration ( == sal_True) kann ist der ::com::sun::star::sdbcx::Index und der R"uckgabewert nur sehr kurzfristig g"ultig. */ { 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 */ ) /* [Beschreibung] Invalidiert alle Instanzen, die an dieser SfxBindings Instanz angemeldet sind, und bei bWithMsg == sal_True ebenfalls die -Caches. Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden, bevor "uberhaupt etwas passiert. [Querverweise] */ { 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!) */ ) /* [Beschreibung] Invalidiert die Instanzen der Slot-Ids in 'pIds', die an dieser SfxBindings Instanz angemeldet sind. Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden, bevor "uberhaupt etwas passiert. [Querverweise] */ { 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 , 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 ) /* [Beschreibung] Invalidiert alle Instanzen, die zur Zeit von der angegebenen SfxShell Instanz bedient werden und an dieser SfxBindings Instanz angemeldet sind Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden, bevor "uberhaupt etwas passiert. [Querverweise] */ { 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 ) /* [Beschreibung] Invalidiert alle Instanzen, die auf die Slot-Id nId gebunden sind und an dieser SfxBindings Instanz angemeldet sind. Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden, bevor "uberhaupt etwas passiert. [Querverweise] */ { 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 ? ) /* [Beschreibung] Invalidiert alle Instanzen, die auf die Slot-Id nId gebunden sind und an dieser SfxBindings Instanz angemeldet sind, und bei bWithMsg == sal_True ebenfalls den -Cache. Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden, bevor "uberhaupt etwas passiert. [Querverweise] */ { 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(); } } } void SfxBindings::Invalidate ( sal_uInt16, // zu invalidierende Slot-Id sal_Bool // SlotServer neu holen ? ) /* [Beschreibung] Invalidiert alle Instanzen, die auf die Slot-Id nId gebunden sind und an dieser SfxBindings Instanz angemeldet sind, und bei bWithMsg == sal_True ebenfalls den -Cache. Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden, bevor "uberhaupt etwas passiert. [Querverweise] */ { DBG_ERROR( "Methode veraltet!" ); } //-------------------------------------------------------------------- sal_Bool SfxBindings::IsBound( sal_uInt16 nSlotId, sal_uInt16 nStartSearchAt ) /* [Beschreibung] Stellt fest, ob die angegebene Slot-Id in einem gebunden ist, der an dieser SfxBindings Instanz angemeldet ist. [R"uckgabewert] sal_Bool sal_True Die angegeben Slot-Id ist gebunden. sal_False Die angegeben Slot-Id ist nicht gebunden. */ { 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 ) /* [Beschreibung] Ermittelt den ::com::sun::star::sdbcx::Index der angegebenen Slot-Id in den SfxBindings. Falls die Slot-Id nicht gebunden ist, wird der ::com::sun::star::sdbcx::Index zur"uckgegeben, an dem sie eingef"ugt w"urde. */ { DBG_MEMTEST(); DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); DBG_PROFSTART(SfxBindingsMsgPos); // answer immediately if a function-seek comes repeated if ( pImp->nCachedFunc1 < pImp->pCaches->Count() && (*pImp->pCaches)[pImp->nCachedFunc1]->GetId() == nId ) { ++nCache1; DBG_PROFSTOP(SfxBindingsMsgPos); return pImp->nCachedFunc1; } if ( pImp->nCachedFunc2 < pImp->pCaches->Count() && (*pImp->pCaches)[pImp->nCachedFunc2]->GetId() == nId ) { ++nCache2; // swap the caches sal_uInt16 nTemp = pImp->nCachedFunc1; pImp->nCachedFunc1 = pImp->nCachedFunc2; pImp->nCachedFunc2 = nTemp; DBG_PROFSTOP(SfxBindingsMsgPos); return pImp->nCachedFunc1; } // binary search, if not found, seek to target-position if ( pImp->pCaches->Count() <= nStartSearchAt ) { DBG_PROFSTOP(SfxBindingsMsgPos); return 0; } if ( pImp->pCaches->Count() == (nStartSearchAt+1) ) { DBG_PROFSTOP(SfxBindingsMsgPos); return (*pImp->pCaches)[nStartSearchAt]->GetId() >= nId ? 0 : 1; } sal_uInt16 nLow = nStartSearchAt; sal_uInt16 nMid = 0; sal_uInt16 nHigh = 0; sal_Bool bFound = sal_False; nHigh = pImp->pCaches->Count() - 1; while ( !bFound && nLow <= nHigh ) { nMid = (nLow + nHigh) >> 1; DBG_ASSERT( nMid < pImp->pCaches->Count(), "bsearch ist buggy" ); int nDiff = (int) nId - (int) ( ((*pImp->pCaches)[nMid])->GetId() ); if ( nDiff < 0) { if ( nMid == 0 ) break; nHigh = nMid - 1; } else if ( nDiff > 0 ) { nLow = nMid + 1; if ( nLow == 0 ) break; } else bFound = sal_True; } sal_uInt16 nPos = bFound ? nMid : nLow; DBG_ASSERT( nPos <= pImp->pCaches->Count(), "" ); DBG_ASSERT( nPos == pImp->pCaches->Count() || nId <= (*pImp->pCaches)[nPos]->GetId(), "" ); DBG_ASSERT( nPos == nStartSearchAt || nId > (*pImp->pCaches)[nPos-1]->GetId(), "" ); DBG_ASSERT( ( (nPos+1) >= pImp->pCaches->Count() ) || nId < (*pImp->pCaches)[nPos+1]->GetId(), "" ); pImp->nCachedFunc2 = pImp->nCachedFunc1; pImp->nCachedFunc1 = nPos; DBG_PROFSTOP(SfxBindingsMsgPos); return nPos; } //-------------------------------------------------------------------- void SfxBindings::RegisterInternal_Impl( SfxControllerItem& rItem ) { Register_Impl( rItem, TRUE ); } void SfxBindings::Register( SfxControllerItem& rItem ) { Register_Impl( rItem, FALSE ); } void SfxBindings::Register_Impl( SfxControllerItem& rItem, BOOL bInternal ) { DBG_MEMTEST(); DBG_ASSERT( nRegLevel > 0, "registration without EnterRegistrations" ); DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Register while status-updating" ); // insert new cache if it does not already exist sal_uInt16 nId = rItem.GetId(); sal_uInt16 nPos = GetSlotPos(nId); if ( nPos >= pImp->pCaches->Count() || (*pImp->pCaches)[nPos]->GetId() != nId ) { SfxStateCache* pCache = new SfxStateCache(nId); pImp->pCaches->Insert( nPos, pCache ); DBG_ASSERT( nPos == 0 || (*pImp->pCaches)[nPos]->GetId() > (*pImp->pCaches)[nPos-1]->GetId(), "" ); DBG_ASSERT( (nPos == pImp->pCaches->Count()-1) || (*pImp->pCaches)[nPos]->GetId() < (*pImp->pCaches)[nPos+1]->GetId(), "" ); pImp->bMsgDirty = sal_True; } // enqueue the new binding if ( bInternal ) { (*pImp->pCaches)[nPos]->SetInternalController( &rItem ); } else { SfxControllerItem *pOldItem = (*pImp->pCaches)[nPos]->ChangeItemLink(&rItem); rItem.ChangeItemLink(pOldItem); } } //-------------------------------------------------------------------- void SfxBindings::Release( SfxControllerItem& rItem ) { DBG_MEMTEST(); DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); //! DBG_ASSERT( nRegLevel > 0, "release without EnterRegistrations" ); DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Release while status-updating" ); ENTERREGISTRATIONS(); // find the bound function sal_uInt16 nId = rItem.GetId(); sal_uInt16 nPos = GetSlotPos(nId); SfxStateCache* pCache = (*pImp->pCaches)[nPos]; if ( pCache->GetId() == nId ) { if ( pCache->GetInternalController() == &rItem ) { pCache->ReleaseInternalController(); } else { // is this the first binding in the list? SfxControllerItem* pItem = pCache->GetItemLink(); if ( pItem == &rItem ) pCache->ChangeItemLink( rItem.GetItemLink() ); else { // search the binding in the list while ( pItem && pItem->GetItemLink() != &rItem ) pItem = pItem->GetItemLink(); // unlink it if it was found if ( pItem ) pItem->ChangeItemLink( rItem.GetItemLink() ); } } // was this the last controller? if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() ) { #ifdef slow // remove the BoundFunc delete (*pImp->pCaches)[nPos]; pImp->pCaches->Remove(nPos, 1); #endif if ( SfxMacroConfig::IsMacroSlot( nId ) ) { delete (*pImp->pCaches)[nPos]; pImp->pCaches->Remove(nPos, 1); } else pImp->bCtrlReleased = sal_True; } } LEAVEREGISTRATIONS(); } //-------------------------------------------------------------------- const SfxPoolItem* SfxBindings::ExecuteSynchron( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, const SfxPoolItem **ppInternalArgs ) { DBG_MEMTEST(); DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); if( !nId || !pDispatcher ) return NULL; return Execute_Impl( nId, ppItems, nModi, SFX_CALLMODE_SYNCHRON, ppInternalArgs ); } sal_Bool SfxBindings::Execute( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode, const SfxPoolItem **ppInternalArgs ) /* [Beschreibung] F"uhrt den Slot mit der Slot-Id nId "uber den Cache aus. Dies ist nur bei in dieser SfxBindings INstanz gebundenen Slot-Ids m"oglich. [R"uckgabewert] sal_Bool sal_True Das Execute wurde ausgef"uhrt. sal_False Das Execute konnte nicht ausgef"uhrt werden, weil der Slot entweder nicht zur Verf"ugung steht (in keiner aktiven vorhanden oder disabled) ist oder der Anwender die Ausf"uhrung abgebrochen hat (Cancel in einem Dialog). [Querverweise] */ { 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() ) { // cache binds to an external dispatch provider pCache->Dispatch( 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() /* [Beschreibung] Interne Methode zum Updaten der Pointer auf die SlotServer nach . */ { 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 ) /* [Beschreibung] Diese interne Methode sucht zu pCache die Slot-Ids, die von derselben Status-Methode bedient werden und ebenfalls gebunden und dirty sind. Es wird ein SfxItemSet zusammengestellt, das die Slot-Ids (oder falls vorhanden die mit dem Pool der Shell gemappten Which-Ids) enth"alt. Die Caches dieser Slots werden in pFoundCaches zur"uckgeliefert. */ { DBG_MEMTEST(); DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); DBG_ASSERT( !pImp->bMsgDirty, "CreateSet_Impl mit dirty MessageServer" ); const SfxSlotServer* pMsgSvr = pCache->GetSlotServer(*pDispatcher, pImp->xProv); if(!pMsgSvr || !pDispatcher) return 0; DBG_PROFSTART(SfxBindingsCreateSet); pRealSlot = 0; *pMsgServer = pMsgSvr; sal_uInt16 nShellLevel = pMsgSvr->GetShellLevel(); SfxShell *pShell = pDispatcher->GetShell( nShellLevel ); if ( !pShell ) // seltener GPF beim Browsen durch Update aus Inet-Notify return 0; SfxItemPool &rPool = pShell->GetPool(); // hole die Status-Methode, von der pCache bedient wird SfxStateFunc pFnc = 0; const SfxInterface *pInterface = pShell->GetInterface(); if ( SFX_KIND_ENUM == pMsgSvr->GetSlot()->GetKind() ) { pRealSlot = pInterface->GetRealSlot(pMsgSvr->GetSlot()); pCache = GetStateCache( pRealSlot->GetSlotId() ); // DBG_ASSERT( pCache, "Kein Slotcache fuer den Masterslot gefunden!" ); } else pRealSlot = pMsgSvr->GetSlot(); // // Achtung: pCache darf auch NULL sein !!! // pFnc = pRealSlot->GetStateFnc(); // der RealSlot ist immer drin const SfxFoundCache_Impl *pFound = new SfxFoundCache_Impl( pRealSlot->GetSlotId(), pRealSlot->GetWhich(rPool), pRealSlot, pCache ); rFound.Insert( pFound ); USHORT nSlot = pRealSlot->GetSlotId(); if ( !SfxMacroConfig::IsMacroSlot( nSlot ) && !(nSlot >= SID_VERB_START && nSlot <= SID_VERB_END) ) { pInterface = pInterface->GetRealInterfaceForSlot( pRealSlot ); DBG_ASSERT (pInterface,"Slot in angegebener Shell nicht gefunden!"); } // Durchsuche die Bindings nach den von derselben Funktion bedienten Slots. // Daf"ur kommen nur Slots in Frage, die es im gefundenen Interface gibt. // Die Position des Statecaches im StateCache-Array sal_uInt16 nCachePos = pImp->nMsgPos; const SfxSlot *pSibling = pRealSlot->GetNextSlot(); // Die Slots eines Interfaces sind im Kreis verkettet while ( pSibling > pRealSlot ) { SfxStateFunc pSiblingFnc=0; SfxStateCache *pSiblingCache = GetStateCache( pSibling->GetSlotId(), &nCachePos ); // Ist der Slot "uberhaupt gecached ? if ( pSiblingCache ) { const SfxSlotServer *pServ = pSiblingCache->GetSlotServer(*pDispatcher, pImp->xProv); if ( pServ && pServ->GetShellLevel() == nShellLevel ) pSiblingFnc = pServ->GetSlot()->GetStateFnc(); } // Mu\s der Slot "uberhaupt upgedatet werden ? FASTBOOL bInsert = pSiblingCache && pSiblingCache->IsControllerDirty(); // Bugfix #26161#: Es reicht nicht, nach der selben Shell zu fragen !! FASTBOOL bSameMethod = pSiblingCache && pFnc == pSiblingFnc; // Wenn der Slot ein nicht-dirty MasterSlot ist, dann ist vielleicht // einer seiner Slaves dirty ? Dann wird der Masterslot doch eingef"ugt. if ( !bInsert && bSameMethod && pSibling->GetLinkedSlot() ) { // auch Slave-Slots auf Binding pru"fen const SfxSlot* pFirstSlave = pSibling->GetLinkedSlot(); for ( const SfxSlot *pSlaveSlot = pFirstSlave; !bInsert; pSlaveSlot = pSlaveSlot->GetNextSlot()) { // Die Slaves zeigen auf ihren Master DBG_ASSERT(pSlaveSlot->GetLinkedSlot() == pSibling, "Falsche Master/Slave-Beziehung!"); sal_uInt16 nCurMsgPos = pImp->nMsgPos; const SfxStateCache *pSlaveCache = GetStateCache( pSlaveSlot->GetSlotId(), &nCurMsgPos ); // Ist der Slave-Slot gecached und dirty ? bInsert = pSlaveCache && pSlaveCache->IsControllerDirty(); // Slaves sind untereinander im Kreis verkettet if (pSlaveSlot->GetNextSlot() == pFirstSlave) break; } } if ( bInsert && bSameMethod ) { const SfxFoundCache_Impl *pFoundCache = new SfxFoundCache_Impl( pSibling->GetSlotId(), pSibling->GetWhich(rPool), pSibling, pSiblingCache ); rFound.Insert( pFoundCache ); } pSibling = pSibling->GetNextSlot(); } // aus den Ranges ein Set erzeugen sal_uInt16 *pRanges = new sal_uInt16[rFound.Count() * 2 + 1]; int j = 0; USHORT i = 0; while ( i < rFound.Count() ) { pRanges[j++] = rFound[i]->nWhichId; // aufeinanderfolgende Zahlen for ( ; i < rFound.Count()-1; ++i ) if ( rFound[i]->nWhichId+1 != rFound[i+1]->nWhichId ) break; pRanges[j++] = rFound[i++]->nWhichId; } pRanges[j] = 0; // terminierende NULL SfxItemSet *pSet = new SfxItemSet(rPool, pRanges); delete [] pRanges; DBG_PROFSTOP(SfxBindingsCreateSet); return pSet; } //-------------------------------------------------------------------- void SfxBindings::UpdateControllers_Impl ( const SfxInterface* pIF, // das diese Id momentan bedienende Interface const SfxFoundCache_Impl* pFound, // Cache, Slot, Which etc. const SfxPoolItem* pItem, // item to send to controller SfxItemState eState // state of item ) /* [Beschreibung] Dieses ist eine Hilfsmethode f"ur NextJob_Impl mit der die SfxController, welche auf nSlotId gebunden sind, upgedated werden. Dabei wird der Wert aus dem SfxPoolItem unter dem Which-Wert nWhich aus dem Set rSet genommen. Falls zu rSlot Enum-Werte in der Slotmap eingetragen sind, und diese gebunden sind, werden sie ebenfalls upgedated. */ { 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 ) /* [Beschreibung] Die SfxController werden "uber einen Timer updated. Dieses ist der dazugeh"orige interne TimeOut-Handler. */ { #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(); if ( pFrame && pFrame->GetObjectShell()->IsInModalMode() || pSfxApp->IsDowning() || !pImp->pCaches->Count() ) { 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; } } } // volatiles wieder von vorne starten pImp->nMsgPos = 0; pImp->aTimer.SetTimeout(TIMEOUT_IDLE); 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); } // 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) /* [Beschreibung] Die An- oder Abmeldung von Instanzen mu"s in EnterRegistrations() und LeaveRegistrations() geklammert werden. W"ahrend dieser Zeit erfolgen keine Udates der Instanzen (weder der alten noch der neu angemeldeten). [Parameter] pFile, nLine Dateiname und Zeilennummer der rufenden Methode (nur Debug) [R"uckgabewert] sal_uInt16 Level der Registrierung. Dieser kann in als Parameter angegeben werden, um die Paarigkeit der EnterRegistrations() und LeaveRegistrations() zu pr"ufen. [Querverweise] */ { (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 ) /* [Beschreibung] Die An- oder Abmeldung von Instanzen mu"s in EnterRegistrations() und LeaveRegistrations() geklammert werden. W"ahrend dieser Zeit erfolgen keine Udates der Instanzen (weder der alten noch der neu angemeldeten). [Parameter] sal_uInt16 nLevel == USRT_MAX keine Paarigkeits-Pr"ufung f"ur diese Klammerung pFile, nLine Dateiname und Zeilennummer der rufenden Methode (nur Debug) < USHRT_MAX R"uckgabewert des zugeh"origen EnterRegistrations() zum pr"ufen der Paarigkeit. [Querverweise] */ { (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) /* [Beschreibung] Diese Methode liefert einen Pointer auf den zur Zeit gecacheten SfxSlot f"ur die angegebene Slot-Id. [R"uckgabewert] const * 0 Falls die Slot-Id nicht gebunden ist oder ein solcher Slot momentan in keiner aktiven vorhanden ist. != 0 Falls die Slot-Id gebunden ist und ein solcher Slot momentan in einer aktiven vorhanden ist. */ { 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 ) /* [Beschreibung] Setzt den zur Zeit von dieser SfxBindings Instanz zu verwendenden Dispatcher um. Falls sich der Dispatcher dadurch "andert, wird intern mit sal_True gerufen, also jegliche gecachete Information der Bindings weggeworfen. */ { 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 ) // interne Methode zum forwarden dieses Methodenaufrufs { GetStateCache(nSlotId)->ClearCache(); } //-------------------------------------------------------------------- // interne Methode zum Ansto\sen des Statusupdates 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 ) /* [Beschreibung] Wird gerufen, um den Status f"ur 'nSlot' zu erfragen. Wenn der return value SFX_ITEM_SET ist, wird ein SfxPoolItem zur"uckgegeben, indem der rpState entsprechend gesetzt wird. Es findet dabei ein Eigent"umer"ubergang statt, d.h. die aufrufende Methode mu\s das Item l"oschen. Anmerkung: diese Methode ist sehr teuer und sollte nur gerufen werden, wenn kein Controller f"ur das Erfragen des Status angelegt werden kann oder der Status unbedingt sofort geliefert werden mu\s. */ { ::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(); SfxTopViewFrame* pTop = PTR_CAST( SfxTopViewFrame, pFrame->GetTopViewFrame() ); return pTop->GetTopFrame_Impl()->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() ) { new SfxAsyncExec_Impl( aURL, xDisp ); return TRUE; } return FALSE; } //REMOVE SfxConfigManager* SfxBindings::GetConfigManager( USHORT nType ) const //{ //REMOVE SfxConfigManager *pMgr = pDispatcher->GetFrame()->GetObjectShell()->GetConfigManager(); //REMOVE if ( pMgr && pMgr->HasConfigItem( nType ) ) //REMOVE return pMgr; //REMOVE else // return SFX_APP()->GetConfigManager_Impl(); //} 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; }