/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sfx2.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef GCC #endif // wg. nInReschedule #include "appdata.hxx" #include #include #include "statcach.hxx" #include #include #include #include #include #include "sfxtypes.hxx" #include "workwin.hxx" #include #include #include #include #include #include #include #include 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 sal_uInt16 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< sal_uInt16, 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 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 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 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() { // 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(sal_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( sal_uInt16 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) { sal_Bool bInternalUpdate = sal_True; if( pCache->GetDispatch().is() && pCache->GetItemLink() ) { pCache->SetCachedState(sal_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 , 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, sal_True ); } void SfxBindings::Register( SfxControllerItem& rItem ) { Register_Impl( rItem, sal_False ); } void SfxBindings::Register_Impl( SfxControllerItem& rItem, sal_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( sal_uInt16 nId ) { if( nId && pDispatcher ) Execute_Impl( nId, NULL, 0, SFX_CALLMODE_ASYNCHRON, NULL, sal_True ); } const SfxPoolItem* SfxBindings::Execute_Impl( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode, const SfxPoolItem **ppInternalArgs, sal_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 = sal_False; } else pImp->bContextChanged = sal_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 ); sal_uInt16 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 ? bool bInsert = pSiblingCache && pSiblingCache->IsControllerDirty(); // Bugfix #26161#: Es reicht nicht, nach der selben Shell zu fragen !! bool 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; sal_uInt16 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 { 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 bool 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 = sal_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 ) { sal_Bool bDeleteCache = sal_False; if ( !pCache ) { pCache = new SfxStateCache( nSlot ); pCache->GetSlotServer( *GetDispatcher_Impl(), pImp->xProv ); bDeleteCache = sal_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(); } sal_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 source; ::comphelper::UiEventsLogger::appendDispatchOrigin(source, sAppName, ::rtl::OUString::createFromAscii("SfxAsyncExec")); ::comphelper::UiEventsLogger::logDispatch(aURL, source); } new SfxAsyncExec_Impl( aURL, xDisp ); return sal_True; } return sal_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( sal_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; }