Update ooo320-m1
[ooovba.git] / sfx2 / source / control / bindings.cxx
blob02efe0aebad6af90319c1cd52701ef78b8bcf697
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: bindings.cxx,v $
10 * $Revision: 1.53.46.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sfx2.hxx"
34 #include <hash_map>
35 #include <svtools/itempool.hxx>
36 #include <svtools/itemiter.hxx>
37 #include <svtools/eitem.hxx>
38 #include <svtools/aeitem.hxx>
39 #include <svtools/intitem.hxx>
40 #include <svtools/stritem.hxx>
41 #include <svtools/visitem.hxx>
42 #include <com/sun/star/util/XURLTransformer.hpp>
43 #include <com/sun/star/frame/XDispatchProviderInterceptor.hpp>
44 #include <com/sun/star/frame/XDispatch.hpp>
45 #include <com/sun/star/frame/XDispatchProvider.hpp>
46 #include <com/sun/star/frame/XStatusListener.hpp>
47 #include <com/sun/star/frame/FrameSearchFlag.hpp>
48 #include <com/sun/star/frame/XDispatchProviderInterception.hpp>
49 #include <com/sun/star/frame/FeatureStateEvent.hpp>
50 #include <com/sun/star/frame/DispatchDescriptor.hpp>
51 #include <com/sun/star/frame/XController.hpp>
52 #include <comphelper/processfactory.hxx>
53 #include <svtools/itemdel.hxx>
55 #ifndef GCC
56 #endif
58 // wg. nInReschedule
59 #include "appdata.hxx"
60 #include <sfx2/bindings.hxx>
61 #include <sfx2/msg.hxx>
62 #include "statcach.hxx"
63 #include <sfx2/ctrlitem.hxx>
64 #include <sfx2/app.hxx>
65 #include <sfx2/dispatch.hxx>
66 #include <sfx2/request.hxx>
67 #include <sfx2/objface.hxx>
68 #include "sfxtypes.hxx"
69 #include "workwin.hxx"
70 #include <sfx2/macrconf.hxx>
71 #include <sfx2/unoctitm.hxx>
72 #include <sfx2/sfx.hrc>
73 #include <sfx2/sfxuno.hxx>
74 #include <sfx2/topfrm.hxx>
75 #include <sfx2/objsh.hxx>
76 #include <sfx2/msgpool.hxx>
78 #include <comphelper/uieventslogger.hxx>
79 #include <com/sun/star/frame/XModuleManager.hpp>
82 using namespace ::com::sun::star;
83 using namespace ::com::sun::star::uno;
84 using namespace ::com::sun::star::util;
86 DBG_NAME(SfxBindingsMsgPos)
87 DBG_NAME(SfxBindingsUpdateServers)
88 DBG_NAME(SfxBindingsCreateSet)
89 DBG_NAME(SfxBindingsUpdateCtrl1)
90 DBG_NAME(SfxBindingsUpdateCtrl2)
91 DBG_NAME(SfxBindingsNextJob_Impl0)
92 DBG_NAME(SfxBindingsNextJob_Impl)
93 DBG_NAME(SfxBindingsUpdate_Impl)
94 DBG_NAME(SfxBindingsInvalidateAll)
96 //====================================================================
98 static USHORT nTimeOut = 300;
100 #define TIMEOUT_FIRST nTimeOut
101 #define TIMEOUT_UPDATING 20
102 #define TIMEOUT_IDLE 2500
104 static sal_uInt32 nCache1 = 0;
105 static sal_uInt32 nCache2 = 0;
107 typedef std::hash_map< USHORT, bool > InvalidateSlotMap;
109 //====================================================================
111 DECL_PTRARRAY(SfxStateCacheArr_Impl, SfxStateCache*, 32, 16)
113 //====================================================================
115 class SfxAsyncExec_Impl
117 ::com::sun::star::util::URL aCommand;
118 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
119 Timer aTimer;
121 public:
123 SfxAsyncExec_Impl( const ::com::sun::star::util::URL& rCmd, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch >& rDisp )
124 : aCommand( rCmd )
125 , xDisp( rDisp )
127 aTimer.SetTimeoutHdl( LINK(this, SfxAsyncExec_Impl, TimerHdl) );
128 aTimer.SetTimeout( 0 );
129 aTimer.Start();
132 DECL_LINK( TimerHdl, Timer*);
135 IMPL_LINK(SfxAsyncExec_Impl, TimerHdl, Timer*, pTimer)
137 (void)pTimer; // unused
138 aTimer.Stop();
140 Sequence<beans::PropertyValue> aSeq;
141 xDisp->dispatch( aCommand, aSeq );
143 delete this;
144 return 0L;
147 class SfxBindings_Impl
149 public:
150 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchRecorder > xRecorder;
151 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv;
152 SfxUnoControllerArr_Impl*
153 pUnoCtrlArr;
154 SfxWorkWindow* pWorkWin;
155 SfxBindings* pSubBindings;
156 SfxBindings* pSuperBindings;
157 SfxStateCacheArr_Impl* pCaches; // je ein cache fuer jede gebundene
158 sal_uInt16 nCachedFunc1; // index der zuletzt gerufenen
159 sal_uInt16 nCachedFunc2; // index der vorletzt gerufenen
160 sal_uInt16 nMsgPos; // Message-Position, ab der zu aktualisieren ist
161 SfxPopupAction ePopupAction; // in DeleteFloatinWindow() abgefragt
162 sal_Bool bContextChanged;
163 sal_Bool bMsgDirty; // wurde ein MessageServer invalidiert?
164 sal_Bool bAllMsgDirty; // wurden die MessageServer invalidiert?
165 sal_Bool bAllDirty; // nach InvalidateAll
166 sal_Bool bCtrlReleased; // waehrend EnterRegistrations
167 AutoTimer aTimer; // fuer volatile Slots
168 sal_Bool bInUpdate; // fuer Assertions
169 sal_Bool bInNextJob; // fuer Assertions
170 sal_Bool bFirstRound; // Erste Runde im Update
171 sal_uInt16 nFirstShell; // Shell, die in erster Runde bevorzugt wird
172 sal_uInt16 nOwnRegLevel; // z"ahlt die echten Locks, ohne die der SuperBindings
173 InvalidateSlotMap m_aInvalidateSlots; // store slots which are invalidated while in update
176 //--------------------------------------------------------------------
178 struct SfxFoundCache_Impl
180 sal_uInt16 nSlotId; // die Slot-Id
181 sal_uInt16 nWhichId; // falls verf"ugbar die Which-Id, sonst nSlotId
182 const SfxSlot* pSlot; // Pointer auf den <Master-Slot>
183 SfxStateCache* pCache; // Pointer auf den StatusCache, ggf. 0
185 SfxFoundCache_Impl():
186 nSlotId(0),
187 nWhichId(0),
188 pSlot(0),
189 pCache(0)
192 SfxFoundCache_Impl(SfxFoundCache_Impl&r):
193 nSlotId(r.nSlotId),
194 nWhichId(r.nWhichId),
195 pSlot(r.pSlot),
196 pCache(r.pCache)
199 SfxFoundCache_Impl(sal_uInt16 nS, sal_uInt16 nW, const SfxSlot *pS, SfxStateCache *pC ):
200 nSlotId(nS),
201 nWhichId(nW),
202 pSlot(pS),
203 pCache(pC)
206 int operator<( const SfxFoundCache_Impl &r ) const
207 { return nWhichId < r.nWhichId; }
209 int operator==( const SfxFoundCache_Impl &r ) const
210 { return nWhichId== r.nWhichId; }
213 //--------------------------------------------------------------------------
215 SV_DECL_PTRARR_SORT_DEL(SfxFoundCacheArr_Impl, SfxFoundCache_Impl*, 16, 16 )
216 SV_IMPL_OP_PTRARR_SORT(SfxFoundCacheArr_Impl, SfxFoundCache_Impl*);
218 //==========================================================================
220 SfxBindings::SfxBindings()
221 : pImp(new SfxBindings_Impl),
222 pDispatcher(0),
223 nRegLevel(1) // geht erst auf 0, wenn Dispatcher gesetzt
225 pImp->nMsgPos = 0;
226 pImp->bAllMsgDirty = sal_True;
227 pImp->bContextChanged = sal_False;
228 pImp->bMsgDirty = sal_True;
229 pImp->bAllDirty = sal_True;
230 pImp->ePopupAction = SFX_POPUP_DELETE;
231 pImp->nCachedFunc1 = 0;
232 pImp->nCachedFunc2 = 0;
233 pImp->bCtrlReleased = sal_False;
234 pImp->bFirstRound = sal_False;
235 pImp->bInNextJob = sal_False;
236 pImp->bInUpdate = sal_False;
237 pImp->pSubBindings = NULL;
238 pImp->pSuperBindings = NULL;
239 pImp->pWorkWin = NULL;
240 pImp->pUnoCtrlArr = NULL;
241 pImp->nOwnRegLevel = nRegLevel;
243 // all caches are valid (no pending invalidate-job)
244 // create the list of caches
245 pImp->pCaches = new SfxStateCacheArr_Impl;
246 pImp->aTimer.SetTimeoutHdl( LINK(this, SfxBindings, NextJob_Impl) );
249 //====================================================================
251 SfxBindings::~SfxBindings()
253 /* [Beschreibung]
255 Destruktor der Klasse SfxBindings. Die eine, f"ur jede <SfxApplication>
256 existierende Instanz wird von der <SfxApplication> nach Ausf"urhung
257 von <SfxApplication::Exit()> automatisch zerst"ort.
259 Noch existierende <SfxControllerItem> Instanzen, die bei dieser
260 SfxBindings Instanz angemeldet sind, werden im Destruktor
261 automatisch zerst"ort. Dies sind i.d.R. Floating-Toolboxen, Value-Sets
262 etc. Arrays von SfxControllerItems d"urfen zu diesem Zeitpunkt nicht
263 mehr exisitieren.
267 // Die SubBindings sollen ja nicht gelocked werden !
268 pImp->pSubBindings = NULL;
270 ENTERREGISTRATIONS();
272 pImp->aTimer.Stop();
273 DeleteControllers_Impl();
275 // Caches selbst l"oschen
276 sal_uInt16 nCount = pImp->pCaches->Count();
277 for ( sal_uInt16 nCache = 0; nCache < nCount; ++nCache )
278 delete pImp->pCaches->GetObject(nCache);
280 DELETEZ( pImp->pWorkWin );
282 delete pImp->pCaches;
283 delete pImp;
286 //--------------------------------------------------------------------
288 void SfxBindings::DeleteControllers_Impl()
290 // in der ersten Runde den SfxPopupWindows l"oschen
291 sal_uInt16 nCount = pImp->pCaches->Count();
292 sal_uInt16 nCache;
293 for ( nCache = 0; nCache < nCount; ++nCache )
295 // merken wo man ist
296 SfxStateCache *pCache = pImp->pCaches->GetObject(nCache);
297 sal_uInt16 nSlotId = pCache->GetId();
299 // SfxPopupWindow l"oschen lassen
300 pCache->DeleteFloatingWindows();
302 // da der Cache verkleinert worden sein kann, wiederaufsetzen
303 sal_uInt16 nNewCount = pImp->pCaches->Count();
304 if ( nNewCount < nCount )
306 nCache = GetSlotPos(nSlotId);
307 if ( nCache >= nNewCount ||
308 nSlotId != pImp->pCaches->GetObject(nCache)->GetId() )
309 --nCache;
310 nCount = nNewCount;
314 // alle Caches l"oschen
315 for ( nCache = pImp->pCaches->Count(); nCache > 0; --nCache )
317 // Cache via ::com::sun::star::sdbcx::Index besorgen
318 SfxStateCache *pCache = pImp->pCaches->GetObject(nCache-1);
320 // alle Controller in dem Cache unbinden
321 SfxControllerItem *pNext;
322 for ( SfxControllerItem *pCtrl = pCache->GetItemLink();
323 pCtrl; pCtrl = pNext )
325 pNext = pCtrl->GetItemLink();
326 pCtrl->UnBind();
329 if ( pCache->GetInternalController() )
330 pCache->GetInternalController()->UnBind();
332 // Cache l"oschen
333 if( nCache-1 < pImp->pCaches->Count() )
334 delete (*pImp->pCaches)[nCache-1];
335 pImp->pCaches->Remove(nCache-1, 1);
338 if( pImp->pUnoCtrlArr )
340 sal_uInt16 nCtrlCount = pImp->pUnoCtrlArr->Count();
341 for ( sal_uInt16 n=nCtrlCount; n>0; n-- )
343 SfxUnoControllerItem *pCtrl = (*pImp->pUnoCtrlArr)[n-1];
344 pCtrl->ReleaseBindings();
347 DBG_ASSERT( !pImp->pUnoCtrlArr->Count(), "UnoControllerItems nicht entfernt!" );
348 DELETEZ( pImp->pUnoCtrlArr );
352 //--------------------------------------------------------------------
354 SfxPopupAction SfxBindings::GetPopupAction_Impl() const
356 return pImp->ePopupAction;
360 //--------------------------------------------------------------------
362 void SfxBindings::HidePopups( bool bHide )
364 // SfxPopupWindows hiden
365 HidePopupCtrls_Impl( bHide );
366 SfxBindings *pSub = pImp->pSubBindings;
367 while ( pSub )
369 pImp->pSubBindings->HidePopupCtrls_Impl( bHide );
370 pSub = pSub->pImp->pSubBindings;
373 // SfxChildWindows hiden
374 DBG_ASSERT( pDispatcher, "HidePopups not allowed without dispatcher" );
375 if ( pImp->pWorkWin )
376 pImp->pWorkWin->HidePopups_Impl( bHide, sal_True );
379 void SfxBindings::HidePopupCtrls_Impl( FASTBOOL bHide )
381 if ( bHide )
383 // SfxPopupWindows hiden
384 pImp->ePopupAction = SFX_POPUP_HIDE;
386 else
388 // SfxPopupWindows showen
389 pImp->ePopupAction = SFX_POPUP_SHOW;
392 for ( sal_uInt16 nCache = 0; nCache < pImp->pCaches->Count(); ++nCache )
393 pImp->pCaches->GetObject(nCache)->DeleteFloatingWindows();
394 pImp->ePopupAction = SFX_POPUP_DELETE;
397 //--------------------------------------------------------------------
399 void SfxBindings::Update_Impl
401 SfxStateCache* pCache // der upzudatende SfxStatusCache
404 if( pCache->GetDispatch().is() && pCache->GetItemLink() )
406 pCache->SetCachedState(TRUE);
407 if ( !pCache->GetInternalController() )
408 return;
411 if ( !pDispatcher )
412 return;
413 DBG_PROFSTART(SfxBindingsUpdate_Impl);
415 // alle mit derselben Statusmethode zusammensammeln, die dirty sind
416 SfxDispatcher &rDispat = *pDispatcher;
417 const SfxSlot *pRealSlot = 0;
418 const SfxSlotServer* pMsgServer = 0;
419 SfxFoundCacheArr_Impl aFound;
420 SfxItemSet *pSet = CreateSet_Impl( pCache, pRealSlot, &pMsgServer, aFound );
421 sal_Bool bUpdated = sal_False;
422 if ( pSet )
424 // Status erfragen
425 if ( rDispat._FillState( *pMsgServer, *pSet, pRealSlot ) )
427 // Status posten
428 const SfxInterface *pInterface =
429 rDispat.GetShell(pMsgServer->GetShellLevel())->GetInterface();
430 for ( sal_uInt16 nPos = 0; nPos < aFound.Count(); ++nPos )
432 const SfxFoundCache_Impl *pFound = aFound[nPos];
433 sal_uInt16 nWhich = pFound->nWhichId;
434 const SfxPoolItem *pItem = 0;
435 SfxItemState eState = pSet->GetItemState(nWhich, sal_True, &pItem);
436 if ( eState == SFX_ITEM_DEFAULT && SfxItemPool::IsWhich(nWhich) )
437 pItem = &pSet->Get(nWhich);
438 UpdateControllers_Impl( pInterface, aFound[nPos], pItem, eState );
440 bUpdated = sal_True;
443 delete pSet;
446 if ( !bUpdated && pCache )
448 // Wenn pCache == NULL und kein SlotServer ( z.B. weil Dispatcher gelockt! ),
449 // darf nat"urlich kein Update versucht werden
450 SfxFoundCache_Impl aFoundCache(
451 pCache->GetId(), 0,
452 pRealSlot, pCache );
453 UpdateControllers_Impl( 0, &aFoundCache, 0, SFX_ITEM_DISABLED);
456 DBG_PROFSTOP(SfxBindingsUpdate_Impl);
459 //--------------------------------------------------------------------
461 void SfxBindings::InvalidateSlotsInMap_Impl()
463 InvalidateSlotMap::const_iterator pIter = pImp->m_aInvalidateSlots.begin();
464 while ( pIter != pImp->m_aInvalidateSlots.end() )
466 Invalidate( pIter->first );
467 ++pIter;
469 pImp->m_aInvalidateSlots.clear();
472 //--------------------------------------------------------------------
474 void SfxBindings::AddSlotToInvalidateSlotsMap_Impl( USHORT nId )
476 pImp->m_aInvalidateSlots[nId] = sal_True;
479 //--------------------------------------------------------------------
481 void SfxBindings::Update
483 sal_uInt16 nId // die gebundene und upzudatende Slot-Id
486 DBG_MEMTEST();
487 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
489 //!!TLX: Fuehrte zu Vorlagenkatalogstillstand
490 // if ( nRegLevel )
491 // return;
493 if ( pDispatcher )
494 pDispatcher->Flush();
496 if ( pImp->pSubBindings )
497 pImp->pSubBindings->Update( nId );
499 SfxStateCache* pCache = GetStateCache( nId );
500 if ( pCache )
502 pImp->bInUpdate = sal_True;
503 if ( pImp->bMsgDirty )
505 UpdateSlotServer_Impl();
506 pCache = GetStateCache( nId );
509 if (pCache)
511 BOOL bInternalUpdate = TRUE;
512 if( pCache->GetDispatch().is() && pCache->GetItemLink() )
514 pCache->SetCachedState(TRUE);
515 bInternalUpdate = ( pCache->GetInternalController() != 0 );
518 if ( bInternalUpdate )
520 // Status erfragen
521 const SfxSlotServer* pMsgServer = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
522 if ( !pCache->IsControllerDirty() &&
523 ( !pMsgServer ||
524 !pMsgServer->GetSlot()->IsMode(SFX_SLOT_VOLATILE) ) )
526 pImp->bInUpdate = sal_False;
527 InvalidateSlotsInMap_Impl();
528 return;
530 if (!pMsgServer)
532 pCache->SetState(SFX_ITEM_DISABLED, 0);
533 pImp->bInUpdate = sal_False;
534 InvalidateSlotsInMap_Impl();
535 return;
538 Update_Impl(pCache);
541 pImp->bAllDirty = sal_False;
544 pImp->bInUpdate = sal_False;
545 InvalidateSlotsInMap_Impl();
549 //--------------------------------------------------------------------
551 void SfxBindings::Update()
553 DBG_MEMTEST();
554 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
556 if ( pImp->pSubBindings )
557 pImp->pSubBindings->Update();
559 if ( pDispatcher )
561 if ( nRegLevel )
562 return;
564 pImp->bInUpdate = sal_True;
565 pDispatcher->Flush();
566 pDispatcher->Update_Impl();
567 while ( !NextJob_Impl(0) )
568 ; // loop
569 pImp->bInUpdate = sal_False;
570 InvalidateSlotsInMap_Impl();
574 //--------------------------------------------------------------------
576 void SfxBindings::SetState
578 const SfxItemSet& rSet // zu setzende Status-Werte
581 // wenn gelockt, dann nur invalidieren
582 if ( nRegLevel )
584 SfxItemIter aIter(rSet);
585 for ( const SfxPoolItem *pItem = aIter.FirstItem();
586 pItem;
587 pItem = aIter.NextItem() )
588 Invalidate( pItem->Which() );
590 else
592 // Status d"urfen nur angenommen werden, wenn alle Slot-Pointer gesetzt sind
593 if ( pImp->bMsgDirty )
594 UpdateSlotServer_Impl();
596 // "uber das ItemSet iterieren, falls Slot gebunden, updaten
597 //! Bug: WhichIter verwenden und ggf. VoidItems hochschicken
598 SfxItemIter aIter(rSet);
599 for ( const SfxPoolItem *pItem = aIter.FirstItem();
600 pItem;
601 pItem = aIter.NextItem() )
603 SfxStateCache* pCache =
604 GetStateCache( rSet.GetPool()->GetSlotId(pItem->Which()) );
605 if ( pCache )
607 // Status updaten
608 if ( !pCache->IsControllerDirty() )
609 pCache->Invalidate(sal_False);
610 pCache->SetState( SFX_ITEM_AVAILABLE, pItem );
612 //! nicht implementiert: Updates von EnumSlots via MasterSlots
618 //--------------------------------------------------------------------
620 void SfxBindings::SetState
622 const SfxPoolItem& rItem // zu setzender Status-Wert
625 if ( nRegLevel )
627 Invalidate( rItem.Which() );
629 else
631 // Status d"urfen nur angenommen werden, wenn alle Slot-Pointer gesetzt sind
632 if ( pImp->bMsgDirty )
633 UpdateSlotServer_Impl();
635 // falls der Slot gebunden ist, updaten
636 DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ),
637 "cannot set items with which-id" );
638 SfxStateCache* pCache = GetStateCache( rItem.Which() );
639 if ( pCache )
641 // Status updaten
642 if ( !pCache->IsControllerDirty() )
643 pCache->Invalidate(sal_False);
644 pCache->SetState( SFX_ITEM_AVAILABLE, &rItem );
646 //! nicht implementiert: Updates von EnumSlots via MasterSlots
652 //--------------------------------------------------------------------
654 SfxStateCache* SfxBindings::GetAnyStateCache_Impl( sal_uInt16 nId )
656 SfxStateCache* pCache = GetStateCache( nId );
657 if ( !pCache && pImp->pSubBindings )
658 return pImp->pSubBindings->GetAnyStateCache_Impl( nId );
659 return pCache;
662 SfxStateCache* SfxBindings::GetStateCache
664 sal_uInt16 nId /* Slot-Id, deren SfxStatusCache gefunden
665 werden soll */,
666 sal_uInt16* pPos /* 0 bzw. Position, ab der die Bindings
667 bin"ar durchsucht werden sollen. Liefert
668 die Position zur"uck, an der nId gefunden
669 wurde, bzw. an der es einfef"ugt werden
670 w"urde. */
673 DBG_MEMTEST();
674 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
675 // is the specified function bound?
676 const sal_uInt16 nStart = ( pPos ? *pPos : 0 );
677 const sal_uInt16 nPos = GetSlotPos( nId, nStart );
679 if ( nPos < pImp->pCaches->Count() &&
680 (*pImp->pCaches)[nPos]->GetId() == nId )
682 if ( pPos )
683 *pPos = nPos;
684 return (*pImp->pCaches)[nPos];
686 return 0;
689 //--------------------------------------------------------------------
691 void SfxBindings::InvalidateAll
693 sal_Bool bWithMsg /* sal_True
694 Slot-Server als ung"ultig markieren
696 sal_False
697 Slot-Server bleiben g"ultig */
700 DBG_PROFSTART(SfxBindingsInvalidateAll);
701 DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
703 DBG_MEMTEST();
705 if ( pImp->pSubBindings )
706 pImp->pSubBindings->InvalidateAll( bWithMsg );
708 // ist schon alles dirty gesetzt oder downing => nicht zu tun
709 if ( !pDispatcher ||
710 ( pImp->bAllDirty && ( !bWithMsg || pImp->bAllMsgDirty ) ) ||
711 SFX_APP()->IsDowning() )
713 DBG_PROFSTOP(SfxBindingsInvalidateAll);
714 return;
717 pImp->bAllMsgDirty = pImp->bAllMsgDirty || bWithMsg;
718 pImp->bMsgDirty = pImp->bMsgDirty || pImp->bAllMsgDirty || bWithMsg;
719 pImp->bAllDirty = sal_True;
721 for ( sal_uInt16 n = 0; n < pImp->pCaches->Count(); ++n )
722 pImp->pCaches->GetObject(n)->Invalidate(bWithMsg);
724 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame
725 ( pDispatcher->GetFrame()->GetFrame()->GetFrameInterface(), UNO_QUERY );
727 if ( bWithMsg && xFrame.is() )
728 xFrame->contextChanged();
730 pImp->nMsgPos = 0;
731 if ( !nRegLevel )
733 pImp->aTimer.Stop();
734 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
735 pImp->aTimer.Start();
736 // pImp->bFirstRound = sal_True;
737 // pImp->nFirstShell = 0;
740 DBG_PROFSTOP(SfxBindingsInvalidateAll);
743 //--------------------------------------------------------------------
745 void SfxBindings::Invalidate
747 const sal_uInt16* pIds /* numerisch sortiertes 0-terminiertes Array
748 von Slot-Ids (einzel, nicht als Paare!) */
751 DBG_PROFSTART(SfxBindingsInvalidateAll);
752 // DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
754 DBG_MEMTEST();
756 if ( pImp->bInUpdate )
758 sal_Int32 i = 0;
759 while ( pIds[i] != 0 )
760 AddSlotToInvalidateSlotsMap_Impl( pIds[i++] );
762 if ( pImp->pSubBindings )
763 pImp->pSubBindings->Invalidate( pIds );
764 return;
767 if ( pImp->pSubBindings )
768 pImp->pSubBindings->Invalidate( pIds );
770 // ist schon alles dirty gesetzt oder downing => nicht zu tun
771 if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
772 return;
774 // in immer kleiner werdenden Berichen bin"ar suchen
775 for ( sal_uInt16 n = GetSlotPos(*pIds);
776 *pIds && n < pImp->pCaches->Count();
777 n = GetSlotPos(*pIds, n) )
779 // falls SID "uberhaupt gebunden ist, den Cache invalidieren
780 SfxStateCache *pCache = pImp->pCaches->GetObject(n);
781 if ( pCache->GetId() == *pIds )
782 pCache->Invalidate(sal_False);
784 // n"achste SID
785 if ( !*++pIds )
786 break;
787 DBG_ASSERT( *pIds > *(pIds-1), "pIds unsorted" );
790 // falls nicht gelockt, Update-Timer starten
791 pImp->nMsgPos = 0;
792 if ( !nRegLevel )
794 pImp->aTimer.Stop();
795 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
796 pImp->aTimer.Start();
797 // pImp->bFirstRound = sal_True;
798 // pImp->nFirstShell = 0;
801 DBG_PROFSTOP(SfxBindingsInvalidateAll);
804 //--------------------------------------------------------------------
806 void SfxBindings::InvalidateShell
808 const SfxShell& rSh /* Die <SfxShell>, deren Slot-Ids
809 invalidiert werden sollen. */,
811 sal_Bool bDeep /* sal_True
812 auch die, von der SfxShell
813 ererbten Slot-Ids werden invalidert
815 sal_False
816 die ererbten und nicht "uberladenen
817 Slot-Ids werden invalidiert */
818 //! MI: z. Zt. immer bDeep
821 DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
823 if ( pImp->pSubBindings )
824 pImp->pSubBindings->InvalidateShell( rSh, bDeep );
826 if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
827 return;
829 DBG_PROFSTART(SfxBindingsInvalidateAll);
830 DBG_MEMTEST();
832 // Jetzt schon flushen, wird in GetShellLevel(rSh) sowieso gemacht; wichtig,
833 // damit pImp->bAll(Msg)Dirty korrekt gesetzt ist
834 pDispatcher->Flush();
836 if ( !pDispatcher ||
837 ( pImp->bAllDirty && pImp->bAllMsgDirty ) ||
838 SFX_APP()->IsDowning() )
840 // Wenn sowieso demn"achst alle Server geholt werden
841 return;
844 // Level finden
845 sal_uInt16 nLevel = pDispatcher->GetShellLevel(rSh);
846 if ( nLevel != USHRT_MAX )
848 for ( sal_uInt16 n = 0; n < pImp->pCaches->Count(); ++n )
850 SfxStateCache *pCache = pImp->pCaches->GetObject(n);
851 const SfxSlotServer *pMsgServer =
852 pCache->GetSlotServer(*pDispatcher, pImp->xProv);
853 if ( pMsgServer && pMsgServer->GetShellLevel() == nLevel )
854 pCache->Invalidate(sal_False);
856 pImp->nMsgPos = 0;
857 if ( !nRegLevel )
859 pImp->aTimer.Stop();
860 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
861 pImp->aTimer.Start();
862 pImp->bFirstRound = sal_True;
863 pImp->nFirstShell = nLevel;
867 DBG_PROFSTOP(SfxBindingsInvalidateAll);
870 //--------------------------------------------------------------------
872 void SfxBindings::Invalidate
874 sal_uInt16 nId // zu invalidierende Slot-Id
877 DBG_MEMTEST();
878 // DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
880 if ( pImp->bInUpdate )
882 AddSlotToInvalidateSlotsMap_Impl( nId );
883 if ( pImp->pSubBindings )
884 pImp->pSubBindings->Invalidate( nId );
885 return;
888 if ( pImp->pSubBindings )
889 pImp->pSubBindings->Invalidate( nId );
891 if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
892 return;
894 SfxStateCache* pCache = GetStateCache(nId);
895 if ( pCache )
897 pCache->Invalidate(sal_False);
898 pImp->nMsgPos = Min(GetSlotPos(nId), pImp->nMsgPos);
899 if ( !nRegLevel )
901 pImp->aTimer.Stop();
902 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
903 pImp->aTimer.Start();
908 //--------------------------------------------------------------------
910 void SfxBindings::Invalidate
912 sal_uInt16 nId, // zu invalidierende Slot-Id
913 sal_Bool bWithItem, // StateCache clearen ?
914 sal_Bool bWithMsg // SlotServer neu holen ?
917 DBG_MEMTEST();
918 DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
920 if ( pImp->pSubBindings )
921 pImp->pSubBindings->Invalidate( nId, bWithItem, bWithMsg );
923 if ( SFX_APP()->IsDowning() )
924 return;
926 SfxStateCache* pCache = GetStateCache(nId);
927 if ( pCache )
929 if ( bWithItem )
930 pCache->ClearCache();
931 pCache->Invalidate(bWithMsg);
933 if ( !pDispatcher || pImp->bAllDirty )
934 return;
936 pImp->nMsgPos = Min(GetSlotPos(nId), pImp->nMsgPos);
937 if ( !nRegLevel )
939 pImp->aTimer.Stop();
940 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
941 pImp->aTimer.Start();
946 //--------------------------------------------------------------------
948 sal_Bool SfxBindings::IsBound( sal_uInt16 nSlotId, sal_uInt16 nStartSearchAt )
950 DBG_MEMTEST();
951 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
952 return GetStateCache(nSlotId, &nStartSearchAt ) != 0;
955 //--------------------------------------------------------------------
957 sal_uInt16 SfxBindings::GetSlotPos( sal_uInt16 nId, sal_uInt16 nStartSearchAt )
959 DBG_MEMTEST();
960 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
961 DBG_PROFSTART(SfxBindingsMsgPos);
963 // answer immediately if a function-seek comes repeated
964 if ( pImp->nCachedFunc1 < pImp->pCaches->Count() &&
965 (*pImp->pCaches)[pImp->nCachedFunc1]->GetId() == nId )
967 ++nCache1;
968 DBG_PROFSTOP(SfxBindingsMsgPos);
969 return pImp->nCachedFunc1;
971 if ( pImp->nCachedFunc2 < pImp->pCaches->Count() &&
972 (*pImp->pCaches)[pImp->nCachedFunc2]->GetId() == nId )
974 ++nCache2;
976 // swap the caches
977 sal_uInt16 nTemp = pImp->nCachedFunc1;
978 pImp->nCachedFunc1 = pImp->nCachedFunc2;
979 pImp->nCachedFunc2 = nTemp;
980 DBG_PROFSTOP(SfxBindingsMsgPos);
981 return pImp->nCachedFunc1;
984 // binary search, if not found, seek to target-position
985 if ( pImp->pCaches->Count() <= nStartSearchAt )
987 DBG_PROFSTOP(SfxBindingsMsgPos);
988 return 0;
990 if ( pImp->pCaches->Count() == (nStartSearchAt+1) )
992 DBG_PROFSTOP(SfxBindingsMsgPos);
993 return (*pImp->pCaches)[nStartSearchAt]->GetId() >= nId ? 0 : 1;
995 sal_uInt16 nLow = nStartSearchAt;
996 sal_uInt16 nMid = 0;
997 sal_uInt16 nHigh = 0;
998 sal_Bool bFound = sal_False;
999 nHigh = pImp->pCaches->Count() - 1;
1000 while ( !bFound && nLow <= nHigh )
1002 nMid = (nLow + nHigh) >> 1;
1003 DBG_ASSERT( nMid < pImp->pCaches->Count(), "bsearch ist buggy" );
1004 int nDiff = (int) nId - (int) ( ((*pImp->pCaches)[nMid])->GetId() );
1005 if ( nDiff < 0)
1006 { if ( nMid == 0 )
1007 break;
1008 nHigh = nMid - 1;
1010 else if ( nDiff > 0 )
1011 { nLow = nMid + 1;
1012 if ( nLow == 0 )
1013 break;
1015 else
1016 bFound = sal_True;
1018 sal_uInt16 nPos = bFound ? nMid : nLow;
1019 DBG_ASSERT( nPos <= pImp->pCaches->Count(), "" );
1020 DBG_ASSERT( nPos == pImp->pCaches->Count() ||
1021 nId <= (*pImp->pCaches)[nPos]->GetId(), "" );
1022 DBG_ASSERT( nPos == nStartSearchAt ||
1023 nId > (*pImp->pCaches)[nPos-1]->GetId(), "" );
1024 DBG_ASSERT( ( (nPos+1) >= pImp->pCaches->Count() ) ||
1025 nId < (*pImp->pCaches)[nPos+1]->GetId(), "" );
1026 pImp->nCachedFunc2 = pImp->nCachedFunc1;
1027 pImp->nCachedFunc1 = nPos;
1028 DBG_PROFSTOP(SfxBindingsMsgPos);
1029 return nPos;
1031 //--------------------------------------------------------------------
1032 void SfxBindings::RegisterInternal_Impl( SfxControllerItem& rItem )
1034 Register_Impl( rItem, TRUE );
1038 void SfxBindings::Register( SfxControllerItem& rItem )
1040 Register_Impl( rItem, FALSE );
1043 void SfxBindings::Register_Impl( SfxControllerItem& rItem, BOOL bInternal )
1045 DBG_MEMTEST();
1046 DBG_ASSERT( nRegLevel > 0, "registration without EnterRegistrations" );
1047 DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Register while status-updating" );
1049 // insert new cache if it does not already exist
1050 sal_uInt16 nId = rItem.GetId();
1051 sal_uInt16 nPos = GetSlotPos(nId);
1052 if ( nPos >= pImp->pCaches->Count() ||
1053 (*pImp->pCaches)[nPos]->GetId() != nId )
1055 SfxStateCache* pCache = new SfxStateCache(nId);
1056 pImp->pCaches->Insert( nPos, pCache );
1057 DBG_ASSERT( nPos == 0 ||
1058 (*pImp->pCaches)[nPos]->GetId() >
1059 (*pImp->pCaches)[nPos-1]->GetId(), "" );
1060 DBG_ASSERT( (nPos == pImp->pCaches->Count()-1) ||
1061 (*pImp->pCaches)[nPos]->GetId() <
1062 (*pImp->pCaches)[nPos+1]->GetId(), "" );
1063 pImp->bMsgDirty = sal_True;
1066 // enqueue the new binding
1067 if ( bInternal )
1069 (*pImp->pCaches)[nPos]->SetInternalController( &rItem );
1071 else
1073 SfxControllerItem *pOldItem = (*pImp->pCaches)[nPos]->ChangeItemLink(&rItem);
1074 rItem.ChangeItemLink(pOldItem);
1078 //--------------------------------------------------------------------
1080 void SfxBindings::Release( SfxControllerItem& rItem )
1082 DBG_MEMTEST();
1083 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1084 //! DBG_ASSERT( nRegLevel > 0, "release without EnterRegistrations" );
1085 DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Release while status-updating" );
1086 ENTERREGISTRATIONS();
1088 // find the bound function
1089 sal_uInt16 nId = rItem.GetId();
1090 sal_uInt16 nPos = GetSlotPos(nId);
1091 SfxStateCache* pCache = (*pImp->pCaches)[nPos];
1092 if ( pCache->GetId() == nId )
1094 if ( pCache->GetInternalController() == &rItem )
1096 pCache->ReleaseInternalController();
1098 else
1100 // is this the first binding in the list?
1101 SfxControllerItem* pItem = pCache->GetItemLink();
1102 if ( pItem == &rItem )
1103 pCache->ChangeItemLink( rItem.GetItemLink() );
1104 else
1106 // search the binding in the list
1107 while ( pItem && pItem->GetItemLink() != &rItem )
1108 pItem = pItem->GetItemLink();
1110 // unlink it if it was found
1111 if ( pItem )
1112 pItem->ChangeItemLink( rItem.GetItemLink() );
1116 // was this the last controller?
1117 if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() )
1119 #ifdef slow
1120 // remove the BoundFunc
1121 delete (*pImp->pCaches)[nPos];
1122 pImp->pCaches->Remove(nPos, 1);
1123 #endif
1124 if ( SfxMacroConfig::IsMacroSlot( nId ) )
1126 delete (*pImp->pCaches)[nPos];
1127 pImp->pCaches->Remove(nPos, 1);
1129 else
1130 pImp->bCtrlReleased = sal_True;
1134 LEAVEREGISTRATIONS();
1137 //--------------------------------------------------------------------
1138 const SfxPoolItem* SfxBindings::ExecuteSynchron( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi,
1139 const SfxPoolItem **ppInternalArgs )
1141 DBG_MEMTEST();
1142 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1144 if( !nId || !pDispatcher )
1145 return NULL;
1147 return Execute_Impl( nId, ppItems, nModi, SFX_CALLMODE_SYNCHRON, ppInternalArgs );
1150 sal_Bool SfxBindings::Execute( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode,
1151 const SfxPoolItem **ppInternalArgs )
1153 DBG_MEMTEST();
1154 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1156 if( !nId || !pDispatcher )
1157 return sal_False;
1159 const SfxPoolItem* pRet = Execute_Impl( nId, ppItems, nModi, nCallMode, ppInternalArgs );
1160 return ( pRet != 0 );
1163 void SfxBindings::ExecuteGlobal_Impl( USHORT nId )
1165 if( nId && pDispatcher )
1166 Execute_Impl( nId, NULL, 0, SFX_CALLMODE_ASYNCHRON, NULL, TRUE );
1169 const SfxPoolItem* SfxBindings::Execute_Impl( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode,
1170 const SfxPoolItem **ppInternalArgs, BOOL bGlobalOnly )
1172 SfxStateCache *pCache = GetStateCache( nId );
1173 if ( !pCache )
1175 SfxBindings *pBind = pImp->pSubBindings;
1176 while ( pBind )
1178 if ( pBind->GetStateCache( nId ) )
1179 return pBind->Execute_Impl( nId, ppItems, nModi, nCallMode, ppInternalArgs, bGlobalOnly );
1180 pBind = pBind->pImp->pSubBindings;
1184 SfxDispatcher &rDispatcher = *pDispatcher;
1185 rDispatcher.Flush();
1186 rDispatcher.GetFrame(); // -Wall is this required???
1188 // get SlotServer (Slot+ShellLevel) and Shell from cache
1189 sal_Bool bDeleteCache = sal_False;
1190 if ( !pCache )
1192 // Execution of non cached slots (Accelerators don't use Controllers)
1193 // slot is uncached, use SlotCache to handle external dispatch providers
1194 pCache = new SfxStateCache( nId );
1195 pCache->GetSlotServer( rDispatcher, pImp->xProv );
1196 bDeleteCache = sal_True;
1199 if ( pCache && pCache->GetDispatch().is() )
1201 DBG_ASSERT( !ppInternalArgs, "Internal args get lost when dispatched!" );
1203 SfxItemPool &rPool = GetDispatcher()->GetFrame()->GetObjectShell()->GetPool();
1204 SfxRequest aReq( nId, nCallMode, rPool );
1205 aReq.SetModifier( nModi );
1206 if( ppItems )
1207 while( *ppItems )
1208 aReq.AppendItem( **ppItems++ );
1210 // cache binds to an external dispatch provider
1211 pCache->Dispatch( aReq.GetArgs(), nCallMode == SFX_CALLMODE_SYNCHRON );
1212 if ( bDeleteCache )
1213 DELETEZ( pCache );
1214 SfxPoolItem *pVoid = new SfxVoidItem( nId );
1215 DeleteItemOnIdle( pVoid );
1216 return pVoid;
1219 // slot is handled internally by SfxDispatcher
1220 if ( pImp->bMsgDirty )
1221 UpdateSlotServer_Impl();
1223 SfxShell *pShell=0;
1224 const SfxSlot *pSlot=0;
1226 // if slot was uncached, we should have created a cache in this method!
1227 DBG_ASSERT( pCache, "This code needs a cache!");
1228 const SfxSlotServer* pServer = pCache ? pCache->GetSlotServer( rDispatcher, pImp->xProv ) : 0;
1229 if ( !pServer )
1231 return NULL;
1233 else
1235 pShell = rDispatcher.GetShell( pServer->GetShellLevel() );
1236 pSlot = pServer->GetSlot();
1239 if ( bGlobalOnly )
1240 if ( !pShell->ISA(SfxModule) && !pShell->ISA(SfxApplication) && !pShell->ISA(SfxViewFrame) )
1241 return NULL;
1243 SfxItemPool &rPool = pShell->GetPool();
1244 SfxRequest aReq( nId, nCallMode, rPool );
1245 aReq.SetModifier( nModi );
1246 if( ppItems )
1247 while( *ppItems )
1248 aReq.AppendItem( **ppItems++ );
1249 if ( ppInternalArgs )
1251 SfxAllItemSet aSet( rPool );
1252 for ( const SfxPoolItem **pArg = ppInternalArgs; *pArg; ++pArg )
1253 aSet.Put( **pArg );
1254 aReq.SetInternalArgs_Impl( aSet );
1257 Execute_Impl( aReq, pSlot, pShell );
1259 const SfxPoolItem* pRet = aReq.GetReturnValue();
1260 if ( !pRet )
1262 SfxPoolItem *pVoid = new SfxVoidItem( nId );
1263 DeleteItemOnIdle( pVoid );
1264 pRet = pVoid;
1267 if ( bDeleteCache )
1268 delete pCache;
1270 return pRet;
1273 void SfxBindings::Execute_Impl( SfxRequest& aReq, const SfxSlot* pSlot, SfxShell* pShell )
1275 SfxItemPool &rPool = pShell->GetPool();
1277 if ( SFX_KIND_ENUM == pSlot->GetKind() )
1279 // bei Enum-Slots muss der Master mit dem Wert des Enums executet werden
1280 const SfxSlot *pRealSlot = pShell->GetInterface()->GetRealSlot(pSlot);
1281 const sal_uInt16 nSlotId = pRealSlot->GetSlotId();
1282 aReq.SetSlot( nSlotId );
1283 aReq.AppendItem( SfxAllEnumItem( rPool.GetWhich(nSlotId), pSlot->GetValue() ) );
1284 pDispatcher->_Execute( *pShell, *pRealSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD );
1286 else if ( SFX_KIND_ATTR == pSlot->GetKind() )
1288 // bei Attr-Slots muss der Which-Wert gemapped werden
1289 const sal_uInt16 nSlotId = pSlot->GetSlotId();
1290 aReq.SetSlot( nSlotId );
1291 if ( pSlot->IsMode(SFX_SLOT_TOGGLE) )
1293 // an togglebare-Attribs (Bools) wird der Wert angeheangt
1294 sal_uInt16 nWhich = pSlot->GetWhich(rPool);
1295 SfxItemSet aSet(rPool, nWhich, nWhich, 0);
1296 SfxStateFunc aFunc = pSlot->GetStateFnc();
1297 pShell->CallState( aFunc, aSet );
1298 const SfxPoolItem *pOldItem;
1299 SfxItemState eState = aSet.GetItemState(nWhich, sal_True, &pOldItem);
1300 if ( eState == SFX_ITEM_DISABLED )
1301 return;
1303 if ( SFX_ITEM_AVAILABLE == eState && SfxItemPool::IsWhich(nWhich) )
1304 pOldItem = &aSet.Get(nWhich);
1306 if ( SFX_ITEM_SET == eState ||
1307 ( SFX_ITEM_AVAILABLE == eState &&
1308 SfxItemPool::IsWhich(nWhich) &&
1309 pOldItem ) )
1311 if ( pOldItem->ISA(SfxBoolItem) )
1313 // wir koennen Bools toggeln
1314 sal_Bool bOldValue = ((const SfxBoolItem *)pOldItem)->GetValue();
1315 SfxBoolItem *pNewItem = (SfxBoolItem*) (pOldItem->Clone());
1316 pNewItem->SetValue( !bOldValue );
1317 aReq.AppendItem( *pNewItem );
1318 delete pNewItem;
1320 else if ( pOldItem->ISA(SfxEnumItemInterface) &&
1321 ((SfxEnumItemInterface *)pOldItem)->HasBoolValue())
1323 // und Enums mit Bool-Interface
1324 SfxEnumItemInterface *pNewItem =
1325 (SfxEnumItemInterface*) (pOldItem->Clone());
1326 pNewItem->SetBoolValue(!((SfxEnumItemInterface *)pOldItem)->GetBoolValue());
1327 aReq.AppendItem( *pNewItem );
1328 delete pNewItem;
1330 else {
1331 DBG_ERROR( "Toggle only for Enums and Bools allowed" );
1334 else if ( SFX_ITEM_DONTCARE == eState )
1336 // ein Status-Item per Factory erzeugen
1337 SfxPoolItem *pNewItem = pSlot->GetType()->CreateItem();
1338 DBG_ASSERT( pNewItem, "Toggle an Slot ohne ItemFactory" );
1339 pNewItem->SetWhich( nWhich );
1341 if ( pNewItem->ISA(SfxBoolItem) )
1343 // wir koennen Bools toggeln
1344 ((SfxBoolItem*)pNewItem)->SetValue( sal_True );
1345 aReq.AppendItem( *pNewItem );
1347 else if ( pNewItem->ISA(SfxEnumItemInterface) &&
1348 ((SfxEnumItemInterface *)pNewItem)->HasBoolValue())
1350 // und Enums mit Bool-Interface
1351 ((SfxEnumItemInterface*)pNewItem)->SetBoolValue(sal_True);
1352 aReq.AppendItem( *pNewItem );
1354 else {
1355 DBG_ERROR( "Toggle only for Enums and Bools allowed" );
1357 delete pNewItem;
1359 else {
1360 DBG_ERROR( "suspicious Toggle-Slot" );
1364 pDispatcher->_Execute( *pShell, *pSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD );
1366 else
1367 pDispatcher->_Execute( *pShell, *pSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD );
1370 //--------------------------------------------------------------------
1372 void SfxBindings::UpdateSlotServer_Impl()
1374 DBG_PROFSTART(SfxBindingsUpdateServers);
1375 DBG_MEMTEST();
1376 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1378 // synchronisieren
1379 pDispatcher->Flush();
1380 // pDispatcher->Update_Impl();
1382 if ( pImp->bAllMsgDirty )
1384 if ( !nRegLevel )
1386 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame
1387 ( pDispatcher->GetFrame()->GetFrame()->GetFrameInterface(), UNO_QUERY );
1388 //if ( xFrame.is() )
1389 // xFrame->contextChanged();
1390 pImp->bContextChanged = FALSE;
1392 else
1393 pImp->bContextChanged = TRUE;
1396 const sal_uInt16 nCount = pImp->pCaches->Count();
1397 for(sal_uInt16 i = 0; i < nCount; ++i)
1399 SfxStateCache *pCache = pImp->pCaches->GetObject(i);
1400 pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1402 pImp->bMsgDirty = pImp->bAllMsgDirty = sal_False;
1404 Broadcast( SfxSimpleHint(SFX_HINT_DOCCHANGED) );
1406 DBG_PROFSTOP(SfxBindingsUpdateServers);
1409 //--------------------------------------------------------------------
1411 #ifdef WNT
1412 int __cdecl CmpUS_Impl(const void *p1, const void *p2)
1413 #else
1414 int CmpUS_Impl(const void *p1, const void *p2)
1415 #endif
1417 /* [Beschreibung]
1419 Interne Vergleichsfunktion fuer qsort.
1423 return *(sal_uInt16 *)p1 - *(sal_uInt16 *)p2;
1426 //--------------------------------------------------------------------
1428 SfxItemSet* SfxBindings::CreateSet_Impl
1430 SfxStateCache*& pCache, // in: Status-Cache von nId
1431 const SfxSlot*& pRealSlot, // out: RealSlot zu nId
1432 const SfxSlotServer** pMsgServer, // out: Slot-Server zu nId
1433 SfxFoundCacheArr_Impl& rFound // out: Liste der Caches der Siblings
1436 DBG_MEMTEST();
1437 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1439 DBG_ASSERT( !pImp->bMsgDirty, "CreateSet_Impl mit dirty MessageServer" );
1441 const SfxSlotServer* pMsgSvr = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1442 if(!pMsgSvr || !pDispatcher)
1443 return 0;
1445 DBG_PROFSTART(SfxBindingsCreateSet);
1446 pRealSlot = 0;
1447 *pMsgServer = pMsgSvr;
1449 sal_uInt16 nShellLevel = pMsgSvr->GetShellLevel();
1450 SfxShell *pShell = pDispatcher->GetShell( nShellLevel );
1451 if ( !pShell ) // seltener GPF beim Browsen durch Update aus Inet-Notify
1452 return 0;
1454 SfxItemPool &rPool = pShell->GetPool();
1456 // hole die Status-Methode, von der pCache bedient wird
1457 SfxStateFunc pFnc = 0;
1458 const SfxInterface *pInterface = pShell->GetInterface();
1459 if ( SFX_KIND_ENUM == pMsgSvr->GetSlot()->GetKind() )
1461 pRealSlot = pInterface->GetRealSlot(pMsgSvr->GetSlot());
1462 pCache = GetStateCache( pRealSlot->GetSlotId() );
1463 // DBG_ASSERT( pCache, "Kein Slotcache fuer den Masterslot gefunden!" );
1465 else
1466 pRealSlot = pMsgSvr->GetSlot();
1469 // Achtung: pCache darf auch NULL sein !!!
1472 pFnc = pRealSlot->GetStateFnc();
1474 // der RealSlot ist immer drin
1475 const SfxFoundCache_Impl *pFound = new SfxFoundCache_Impl(
1476 pRealSlot->GetSlotId(), pRealSlot->GetWhich(rPool), pRealSlot, pCache );
1477 rFound.Insert( pFound );
1479 USHORT nSlot = pRealSlot->GetSlotId();
1480 if ( !SfxMacroConfig::IsMacroSlot( nSlot ) && !(nSlot >= SID_VERB_START && nSlot <= SID_VERB_END) )
1482 pInterface = pInterface->GetRealInterfaceForSlot( pRealSlot );
1483 DBG_ASSERT (pInterface,"Slot in angegebener Shell nicht gefunden!");
1486 // Durchsuche die Bindings nach den von derselben Funktion bedienten Slots.
1487 // Daf"ur kommen nur Slots in Frage, die es im gefundenen Interface gibt.
1489 // Die Position des Statecaches im StateCache-Array
1490 sal_uInt16 nCachePos = pImp->nMsgPos;
1491 const SfxSlot *pSibling = pRealSlot->GetNextSlot();
1493 // Die Slots eines Interfaces sind im Kreis verkettet
1494 while ( pSibling > pRealSlot )
1496 SfxStateFunc pSiblingFnc=0;
1497 SfxStateCache *pSiblingCache =
1498 GetStateCache( pSibling->GetSlotId(), &nCachePos );
1500 // Ist der Slot "uberhaupt gecached ?
1501 if ( pSiblingCache )
1503 const SfxSlotServer *pServ = pSiblingCache->GetSlotServer(*pDispatcher, pImp->xProv);
1504 if ( pServ && pServ->GetShellLevel() == nShellLevel )
1505 pSiblingFnc = pServ->GetSlot()->GetStateFnc();
1508 // Mu\s der Slot "uberhaupt upgedatet werden ?
1509 FASTBOOL bInsert = pSiblingCache && pSiblingCache->IsControllerDirty();
1511 // Bugfix #26161#: Es reicht nicht, nach der selben Shell zu fragen !!
1512 FASTBOOL bSameMethod = pSiblingCache && pFnc == pSiblingFnc;
1514 // Wenn der Slot ein nicht-dirty MasterSlot ist, dann ist vielleicht
1515 // einer seiner Slaves dirty ? Dann wird der Masterslot doch eingef"ugt.
1516 if ( !bInsert && bSameMethod && pSibling->GetLinkedSlot() )
1518 // auch Slave-Slots auf Binding pru"fen
1519 const SfxSlot* pFirstSlave = pSibling->GetLinkedSlot();
1520 for ( const SfxSlot *pSlaveSlot = pFirstSlave;
1521 !bInsert;
1522 pSlaveSlot = pSlaveSlot->GetNextSlot())
1524 // Die Slaves zeigen auf ihren Master
1525 DBG_ASSERT(pSlaveSlot->GetLinkedSlot() == pSibling,
1526 "Falsche Master/Slave-Beziehung!");
1528 sal_uInt16 nCurMsgPos = pImp->nMsgPos;
1529 const SfxStateCache *pSlaveCache =
1530 GetStateCache( pSlaveSlot->GetSlotId(), &nCurMsgPos );
1532 // Ist der Slave-Slot gecached und dirty ?
1533 bInsert = pSlaveCache && pSlaveCache->IsControllerDirty();
1535 // Slaves sind untereinander im Kreis verkettet
1536 if (pSlaveSlot->GetNextSlot() == pFirstSlave)
1537 break;
1541 if ( bInsert && bSameMethod )
1543 const SfxFoundCache_Impl *pFoundCache = new SfxFoundCache_Impl(
1544 pSibling->GetSlotId(), pSibling->GetWhich(rPool),
1545 pSibling, pSiblingCache );
1547 rFound.Insert( pFoundCache );
1550 pSibling = pSibling->GetNextSlot();
1553 // aus den Ranges ein Set erzeugen
1554 sal_uInt16 *pRanges = new sal_uInt16[rFound.Count() * 2 + 1];
1555 int j = 0;
1556 USHORT i = 0;
1557 while ( i < rFound.Count() )
1559 pRanges[j++] = rFound[i]->nWhichId;
1560 // aufeinanderfolgende Zahlen
1561 for ( ; i < rFound.Count()-1; ++i )
1562 if ( rFound[i]->nWhichId+1 != rFound[i+1]->nWhichId )
1563 break;
1564 pRanges[j++] = rFound[i++]->nWhichId;
1566 pRanges[j] = 0; // terminierende NULL
1567 SfxItemSet *pSet = new SfxItemSet(rPool, pRanges);
1568 delete [] pRanges;
1569 DBG_PROFSTOP(SfxBindingsCreateSet);
1570 return pSet;
1573 //--------------------------------------------------------------------
1575 void SfxBindings::UpdateControllers_Impl
1577 const SfxInterface* pIF, // das diese Id momentan bedienende Interface
1578 const SfxFoundCache_Impl* pFound, // Cache, Slot, Which etc.
1579 const SfxPoolItem* pItem, // item to send to controller
1580 SfxItemState eState // state of item
1583 DBG_ASSERT( !pFound->pSlot || SFX_KIND_ENUM != pFound->pSlot->GetKind(),
1584 "direct update of enum slot isn't allowed" );
1585 DBG_PROFSTART(SfxBindingsUpdateCtrl1);
1587 SfxStateCache* pCache = pFound->pCache;
1588 const SfxSlot* pSlot = pFound->pSlot;
1589 DBG_ASSERT( !pCache || !pSlot || pCache->GetId() == pSlot->GetSlotId(), "SID mismatch" );
1591 // insofern gebunden, die Controller f"uer den Slot selbst updaten
1592 if ( pCache && pCache->IsControllerDirty() )
1594 if ( SFX_ITEM_DONTCARE == eState )
1596 // uneindeuting
1597 pCache->SetState( SFX_ITEM_DONTCARE, (SfxPoolItem *)-1 );
1599 else if ( SFX_ITEM_DEFAULT == eState &&
1600 pFound->nWhichId > SFX_WHICH_MAX )
1602 // kein Status oder Default aber ohne Pool
1603 SfxVoidItem aVoid(0);
1604 pCache->SetState( SFX_ITEM_UNKNOWN, &aVoid );
1606 else if ( SFX_ITEM_DISABLED == eState )
1607 pCache->SetState(SFX_ITEM_DISABLED, 0);
1608 else
1609 pCache->SetState(SFX_ITEM_AVAILABLE, pItem);
1612 DBG_PROFSTOP(SfxBindingsUpdateCtrl1);
1614 // insofern vorhanden und gebunden, die Controller f"uer Slave-Slots
1615 // (Enum-Werte) des Slots updaten
1616 DBG_PROFSTART(SfxBindingsUpdateCtrl2);
1617 DBG_ASSERT( !pSlot || 0 == pSlot->GetLinkedSlot() || !pItem ||
1618 pItem->ISA(SfxEnumItemInterface),
1619 "master slot with non-enum-type found" );
1620 const SfxSlot *pFirstSlave = pSlot ? pSlot->GetLinkedSlot() : 0;
1621 if ( pIF && pFirstSlave)
1623 // Items auf EnumItem casten
1624 const SfxEnumItemInterface *pEnumItem =
1625 PTR_CAST(SfxEnumItemInterface,pItem);
1626 if ( eState == SFX_ITEM_AVAILABLE && !pEnumItem )
1627 eState = SFX_ITEM_DONTCARE;
1628 else
1629 eState = SfxControllerItem::GetItemState( pEnumItem );
1631 // "uber alle Slaves-Slots iterieren
1632 for ( const SfxSlot *pSlave = pFirstSlave; pSlave; pSlave = pSlave->GetNextSlot() )
1634 DBG_ASSERT(pSlave, "Falsche SlaveSlot-Verkettung!");
1635 DBG_ASSERT(SFX_KIND_ENUM == pSlave->GetKind(),"non enum slaves aren't allowed");
1636 DBG_ASSERT(pSlave->GetMasterSlotId() == pSlot->GetSlotId(),"falscher MasterSlot!");
1638 // ist die Funktion gebunden?
1639 SfxStateCache *pEnumCache = GetStateCache( pSlave->GetSlotId() );
1640 if ( pEnumCache )
1642 pEnumCache->Invalidate(sal_False);
1644 HACK(CONTROL/SELECT Kram)
1645 if ( eState == SFX_ITEM_DONTCARE && pFound->nWhichId == 10144 )
1647 SfxVoidItem aVoid(0);
1648 pEnumCache->SetState( SFX_ITEM_UNKNOWN, &aVoid );
1650 if (pSlave->GetNextSlot() == pFirstSlave)
1651 break;
1653 continue;
1656 if ( SFX_ITEM_DISABLED == eState || !pEnumItem->IsEnabled( pSlave->GetSlotId()) )
1658 // disabled
1659 pEnumCache->SetState(SFX_ITEM_DISABLED, 0);
1661 else if ( SFX_ITEM_AVAILABLE == eState )
1663 // enum-Wert ermitteln
1664 sal_uInt16 nValue = pEnumItem->GetEnumValue();
1665 SfxBoolItem aBool( pFound->nWhichId, pSlave->GetValue() == nValue );
1666 pEnumCache->SetState(SFX_ITEM_AVAILABLE, &aBool);
1668 else
1670 // uneindeuting
1671 pEnumCache->SetState( SFX_ITEM_DONTCARE, (SfxPoolItem *)-1 );
1675 if (pSlave->GetNextSlot() == pFirstSlave)
1676 break;
1680 DBG_PROFSTOP(SfxBindingsUpdateCtrl2);
1684 //--------------------------------------------------------------------
1686 IMPL_LINK( SfxBindings, NextJob_Impl, Timer *, pTimer )
1688 #ifdef DBG_UTIL
1689 // on Windows very often C++ Exceptions (GPF etc.) are caught by MSVCRT or another MS library
1690 // try to get them here
1693 #endif
1694 const unsigned MAX_INPUT_DELAY = 200;
1696 DBG_MEMTEST();
1697 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1699 DBG_PROFSTART(SfxBindingsNextJob_Impl0);
1701 if ( Application::GetLastInputInterval() < MAX_INPUT_DELAY && pTimer )
1703 pImp->aTimer.SetTimeout(TIMEOUT_UPDATING);
1704 return sal_True;
1707 SfxApplication *pSfxApp = SFX_APP();
1709 if( pDispatcher )
1710 pDispatcher->Update_Impl();
1712 // modifying the SfxObjectInterface-stack without SfxBindings => nothing to do
1713 SfxViewFrame* pFrame = pDispatcher->GetFrame();
1714 if ( (pFrame && pFrame->GetObjectShell()->IsInModalMode()) || pSfxApp->IsDowning() || !pImp->pCaches->Count() )
1716 DBG_PROFSTOP(SfxBindingsNextJob_Impl0);
1717 return sal_True;
1719 if ( !pDispatcher || !pDispatcher->IsFlushed() )
1721 DBG_PROFSTOP(SfxBindingsNextJob_Impl0);
1722 return sal_True;
1725 // gfs. alle Server aktualisieren / geschieht in eigener Zeitscheibe
1726 if ( pImp->bMsgDirty )
1728 UpdateSlotServer_Impl();
1729 DBG_PROFSTOP(SfxBindingsNextJob_Impl0);
1730 return sal_False;
1733 DBG_PROFSTOP(SfxBindingsNextJob_Impl0);
1734 DBG_PROFSTART(SfxBindingsNextJob_Impl);
1735 pImp->bAllDirty = sal_False;
1736 pImp->aTimer.SetTimeout(TIMEOUT_UPDATING);
1738 // at least 10 loops and further if more jobs are available but no input
1739 FASTBOOL bPreEmptive = pTimer && !pSfxApp->Get_Impl()->nInReschedule;
1740 sal_uInt16 nLoops = 10;
1741 pImp->bInNextJob = sal_True;
1742 const sal_uInt16 nCount = pImp->pCaches->Count();
1743 while ( pImp->nMsgPos < nCount )
1745 // iterate through the bound functions
1746 sal_Bool bJobDone = sal_False;
1747 while ( !bJobDone )
1749 SfxStateCache* pCache = (*pImp->pCaches)[pImp->nMsgPos];
1750 DBG_ASSERT( pCache, "invalid SfxStateCache-position in job queue" );
1751 sal_Bool bWasDirty = pCache->IsControllerDirty();
1752 if ( bWasDirty )
1755 sal_Bool bSkip = sal_False;
1756 if ( pImp->bFirstRound )
1758 // Falls beim Update eine Shell vorgezogen werden soll,
1759 // kommt in einer ersten Update-Runde nur diese dran
1760 const SfxSlotServer *pMsgServer =
1761 pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1762 if ( pMsgServer &&
1763 pMsgServer->GetShellLevel() != pImp->nFirstShell )
1764 bSkip = sal_True;
1767 if ( !bSkip )
1770 Update_Impl( pCache );
1771 DBG_ASSERT( nCount == pImp->pCaches->Count(),
1772 "Reschedule in StateChanged => buff" );
1773 // }
1776 // skip to next function binding
1777 ++pImp->nMsgPos;
1779 // keep job if it is not completed, but any input is available
1780 bJobDone = pImp->nMsgPos >= nCount;
1781 if ( bJobDone && pImp->bFirstRound )
1783 // Update der bevorzugten Shell ist gelaufen, nun d"urfen
1784 // auch die anderen
1785 bJobDone = sal_False;
1786 pImp->bFirstRound = sal_False;
1787 pImp->nMsgPos = 0;
1790 if ( bWasDirty && !bJobDone && bPreEmptive && (--nLoops == 0) )
1792 DBG_PROFSTOP(SfxBindingsNextJob_Impl);
1793 pImp->bInNextJob = sal_False;
1794 return sal_False;
1799 pImp->nMsgPos = 0;
1801 // check for volatile slots
1802 bool bVolatileSlotsPresent = false;
1803 for ( sal_uInt16 n = 0; n < nCount; ++n )
1805 SfxStateCache* pCache = (*pImp->pCaches)[n];
1806 const SfxSlotServer *pSlotServer = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1807 if ( pSlotServer && pSlotServer->GetSlot()->IsMode(SFX_SLOT_VOLATILE) )
1809 pCache->Invalidate(sal_False);
1810 bVolatileSlotsPresent = true;
1814 if (bVolatileSlotsPresent)
1815 pImp->aTimer.SetTimeout(TIMEOUT_IDLE);
1816 else
1817 pImp->aTimer.Stop();
1819 // Update-Runde ist beendet
1820 pImp->bInNextJob = sal_False;
1821 Broadcast(SfxSimpleHint(SFX_HINT_UPDATEDONE));
1822 DBG_PROFSTOP(SfxBindingsNextJob_Impl);
1823 return sal_True;
1824 #ifdef DBG_UTIL
1826 catch (...)
1828 DBG_ERROR("C++ exception caught!");
1829 pImp->bInNextJob = sal_False;
1832 return sal_False;
1833 #endif
1836 //--------------------------------------------------------------------
1838 sal_uInt16 SfxBindings::EnterRegistrations(const char *pFile, int nLine)
1840 (void)pFile;
1841 (void)nLine;
1842 DBG_MEMTEST();
1843 #ifdef DBG_UTIL
1844 ByteString aMsg;
1845 aMsg.Fill( Min(nRegLevel, sal_uInt16(8) ) );
1846 aMsg += "this = ";
1847 aMsg += ByteString::CreateFromInt32((long)this);
1848 aMsg += " Level = ";
1849 aMsg += ByteString::CreateFromInt32(nRegLevel);
1850 aMsg += " SfxBindings::EnterRegistrations ";
1851 if(pFile) {
1852 aMsg += "File: ";
1853 aMsg += pFile;
1854 aMsg += " Line: ";
1855 aMsg += ByteString::CreateFromInt32(nLine);
1857 // FILE* pLog = fopen( "c:\\bindings.log", "a+w" );
1858 // fwrite( aMsg.GetBuffer(), 1, aMsg.Len(), pLog );
1859 // fclose( pLog );
1860 DbgTrace( aMsg.GetBuffer() );
1861 #endif
1863 // Wenn Bindings gelockt werden, auch SubBindings locken
1864 if ( pImp->pSubBindings )
1866 pImp->pSubBindings->ENTERREGISTRATIONS();
1868 // Dieses EnterRegistrations ist f"ur die SubBindings kein "echtes"
1869 pImp->pSubBindings->pImp->nOwnRegLevel--;
1871 // Bindings synchronisieren
1872 pImp->pSubBindings->nRegLevel = nRegLevel + pImp->pSubBindings->pImp->nOwnRegLevel + 1;
1875 pImp->nOwnRegLevel++;
1877 // check if this is the outer most level
1878 if ( ++nRegLevel == 1 )
1880 // stop background-processing
1881 pImp->aTimer.Stop();
1883 // flush the cache
1884 pImp->nCachedFunc1 = 0;
1885 pImp->nCachedFunc2 = 0;
1887 // merken, ob ganze Caches verschwunden sind
1888 pImp->bCtrlReleased = sal_False;
1891 return nRegLevel;
1893 //--------------------------------------------------------------------
1895 void SfxBindings::LeaveRegistrations( sal_uInt16 nLevel, const char *pFile, int nLine )
1897 (void)nLevel; // unused variable
1898 (void)pFile;
1899 (void)nLine;
1900 DBG_MEMTEST();
1901 DBG_ASSERT( nRegLevel, "Leave without Enter" );
1902 DBG_ASSERT( nLevel == USHRT_MAX || nLevel == nRegLevel, "wrong Leave" );
1904 // Nur wenn die SubBindings noch von den SuperBindings gelockt sind, diesen Lock entfernen
1905 // ( d.h. wenn es mehr Locks als "echte" Locks dort gibt )
1906 if ( pImp->pSubBindings && pImp->pSubBindings->nRegLevel > pImp->pSubBindings->pImp->nOwnRegLevel )
1908 // Bindings synchronisieren
1909 pImp->pSubBindings->nRegLevel = nRegLevel + pImp->pSubBindings->pImp->nOwnRegLevel;
1911 // Dieses LeaveRegistrations ist f"ur die SubBindings kein "echtes"
1912 pImp->pSubBindings->pImp->nOwnRegLevel++;
1913 pImp->pSubBindings->LEAVEREGISTRATIONS();
1916 pImp->nOwnRegLevel--;
1918 // check if this is the outer most level
1919 if ( --nRegLevel == 0 && !SFX_APP()->IsDowning() )
1921 if ( pImp->bContextChanged )
1923 pImp->bContextChanged = FALSE;
1925 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame
1926 ( pDispatcher->GetFrame()->GetFrame()->GetFrameInterface(), UNO_QUERY );
1927 if ( xFrame.is() )
1928 xFrame->contextChanged();*/
1931 #ifndef slow
1932 SfxViewFrame* pFrame = pDispatcher->GetFrame();
1934 // ggf unbenutzte Caches entfernen bzw. PlugInInfo aufbereiten
1935 if ( pImp->bCtrlReleased )
1937 for ( sal_uInt16 nCache = pImp->pCaches->Count(); nCache > 0; --nCache )
1939 // Cache via ::com::sun::star::sdbcx::Index besorgen
1940 SfxStateCache *pCache = pImp->pCaches->GetObject(nCache-1);
1942 // kein Controller mehr interessiert
1943 if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() )
1945 // Cache entfernen. Safety: first remove and then delete
1946 SfxStateCache* pSfxStateCache = (*pImp->pCaches)[nCache-1];
1947 pImp->pCaches->Remove(nCache-1, 1);
1948 delete pSfxStateCache;
1950 else
1952 // neue Controller mit den alten Items benachrichtigen
1953 //!pCache->SetCachedState();
1957 #endif
1958 // restart background-processing
1959 pImp->nMsgPos = 0;
1960 if ( !pFrame || !pFrame->GetObjectShell() )
1961 return;
1962 if ( pImp->pCaches && pImp->pCaches->Count() )
1964 pImp->aTimer.Stop();
1965 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
1966 pImp->aTimer.Start();
1967 // pImp->bFirstRound = sal_True;
1971 #ifdef DBG_UTIL
1972 ByteString aMsg;
1973 aMsg.Fill( Min(nRegLevel, sal_uInt16(8)) );
1974 aMsg += "this = ";
1975 aMsg += ByteString::CreateFromInt32((long)this);
1976 aMsg += " Level = ";
1977 aMsg += ByteString::CreateFromInt32(nRegLevel);
1978 aMsg += " SfxBindings::LeaveRegistrations ";
1979 if(pFile) {
1980 aMsg += "File: ";
1981 aMsg += pFile;
1982 aMsg += " Line: ";
1983 aMsg += ByteString::CreateFromInt32(nLine);
1985 // FILE* pLog = fopen( "c:\\bindings.log", "a+w" );
1986 // fwrite( aMsg.GetBuffer(), 1, aMsg.Len(), pLog );
1987 // fclose( pLog );
1988 DbgTrace( aMsg.GetBuffer() );
1989 #endif
1992 //--------------------------------------------------------------------
1994 const SfxSlot* SfxBindings::GetSlot(sal_uInt16 nSlotId)
1996 DBG_MEMTEST();
1997 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1999 // syncronisieren
2000 pDispatcher->Flush();
2001 if ( pImp->bMsgDirty )
2002 UpdateSlotServer_Impl();
2004 // get the cache for the specified function; return if not bound
2005 SfxStateCache* pCache = GetStateCache(nSlotId);
2006 return pCache && pCache->GetSlotServer(*pDispatcher, pImp->xProv)?
2007 pCache->GetSlotServer(*pDispatcher, pImp->xProv)->GetSlot(): 0;
2010 //--------------------------------------------------------------------
2012 void SfxBindings::SetDispatcher( SfxDispatcher *pDisp )
2014 SfxDispatcher *pOldDispat = pDispatcher;
2015 if ( pDisp != pDispatcher )
2017 if ( pOldDispat )
2019 SfxBindings* pBind = pOldDispat->GetBindings();
2020 while ( pBind )
2022 if ( pBind->pImp->pSubBindings == this && pBind->pDispatcher != pDisp )
2023 pBind->SetSubBindings_Impl( NULL );
2024 pBind = pBind->pImp->pSubBindings;
2028 pDispatcher = pDisp;
2030 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider > xProv;
2031 if ( pDisp )
2032 xProv = ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider >
2033 ( pDisp->GetFrame()->GetFrame()->GetFrameInterface(), UNO_QUERY );
2035 SetDispatchProvider_Impl( xProv );
2036 InvalidateAll( sal_True );
2037 InvalidateUnoControllers_Impl();
2039 if ( pDispatcher && !pOldDispat )
2041 if ( pImp->pSubBindings && pImp->pSubBindings->pDispatcher != pOldDispat )
2043 DBG_ERROR( "SubBindings vor Aktivieren schon gesetzt!" );
2044 pImp->pSubBindings->ENTERREGISTRATIONS();
2046 LEAVEREGISTRATIONS();
2048 else if( !pDispatcher )
2050 ENTERREGISTRATIONS();
2051 if ( pImp->pSubBindings && pImp->pSubBindings->pDispatcher != pOldDispat )
2053 DBG_ERROR( "SubBindings im Deaktivieren immer noch gesetzt!" );
2054 pImp->pSubBindings->LEAVEREGISTRATIONS();
2058 Broadcast( SfxSimpleHint( SFX_HINT_DATACHANGED ) );
2060 if ( pDisp )
2062 SfxBindings* pBind = pDisp->GetBindings();
2063 while ( pBind && pBind != this )
2065 if ( !pBind->pImp->pSubBindings )
2067 pBind->SetSubBindings_Impl( this );
2068 break;
2071 pBind = pBind->pImp->pSubBindings;
2077 //--------------------------------------------------------------------
2079 void SfxBindings::ClearCache_Impl( sal_uInt16 nSlotId )
2081 GetStateCache(nSlotId)->ClearCache();
2084 //--------------------------------------------------------------------
2085 void SfxBindings::StartUpdate_Impl( sal_Bool bComplete )
2087 if ( pImp->pSubBindings )
2088 pImp->pSubBindings->StartUpdate_Impl( bComplete );
2090 if ( !bComplete )
2091 // Update darf unterbrochen werden
2092 NextJob_Impl(&pImp->aTimer);
2093 else
2094 // alle Slots am St"uck updaten
2095 NextJob_Impl(0);
2098 //-------------------------------------------------------------------------
2100 SfxItemState SfxBindings::QueryState( sal_uInt16 nSlot, SfxPoolItem* &rpState )
2102 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
2103 SfxStateCache *pCache = GetStateCache( nSlot );
2104 if ( pCache )
2105 xDisp = pCache->GetDispatch();
2106 if ( xDisp.is() || !pCache )
2108 const SfxSlot* pSlot = SfxSlotPool::GetSlotPool( pDispatcher->GetFrame() ).GetSlot( nSlot );
2109 if ( !pSlot || !pSlot->pUnoName )
2110 return SFX_ITEM_DISABLED;
2112 ::com::sun::star::util::URL aURL;
2113 ::rtl::OUString aCmd( DEFINE_CONST_UNICODE(".uno:"));
2114 aURL.Protocol = aCmd;
2115 aURL.Path = ::rtl::OUString::createFromAscii(pSlot->GetUnoName());
2116 aCmd += aURL.Path;
2117 aURL.Complete = aCmd;
2118 aURL.Main = aCmd;
2120 if ( !xDisp.is() )
2121 xDisp = pImp->xProv->queryDispatch( aURL, ::rtl::OUString(), 0 );
2123 if ( xDisp.is() )
2125 ::com::sun::star::uno::Reference< ::com::sun::star::lang::XUnoTunnel > xTunnel( xDisp, ::com::sun::star::uno::UNO_QUERY );
2126 SfxOfficeDispatch* pDisp = NULL;
2127 if ( xTunnel.is() )
2129 sal_Int64 nImplementation = xTunnel->getSomething(SfxOfficeDispatch::impl_getStaticIdentifier());
2130 pDisp = reinterpret_cast< SfxOfficeDispatch* >( sal::static_int_cast< sal_IntPtr >( nImplementation ));
2133 if ( !pDisp )
2135 BOOL bDeleteCache = FALSE;
2136 if ( !pCache )
2138 pCache = new SfxStateCache( nSlot );
2139 pCache->GetSlotServer( *GetDispatcher_Impl(), pImp->xProv );
2140 bDeleteCache = TRUE;
2143 SfxItemState eState = SFX_ITEM_SET;
2144 SfxPoolItem *pItem=NULL;
2145 BindDispatch_Impl *pBind = new BindDispatch_Impl( xDisp, aURL, pCache, pSlot );
2146 pBind->acquire();
2147 xDisp->addStatusListener( pBind, aURL );
2148 if ( !pBind->GetStatus().IsEnabled )
2150 eState = SFX_ITEM_DISABLED;
2152 else
2154 ::com::sun::star::uno::Any aAny = pBind->GetStatus().State;
2155 ::com::sun::star::uno::Type pType = aAny.getValueType();
2157 if ( pType == ::getBooleanCppuType() )
2159 sal_Bool bTemp = false;
2160 aAny >>= bTemp ;
2161 pItem = new SfxBoolItem( nSlot, bTemp );
2163 else if ( pType == ::getCppuType((const sal_uInt16*)0) )
2165 sal_uInt16 nTemp = 0;
2166 aAny >>= nTemp ;
2167 pItem = new SfxUInt16Item( nSlot, nTemp );
2169 else if ( pType == ::getCppuType((const sal_uInt32*)0) )
2171 sal_uInt32 nTemp = 0;
2172 aAny >>= nTemp ;
2173 pItem = new SfxUInt32Item( nSlot, nTemp );
2175 else if ( pType == ::getCppuType((const ::rtl::OUString*)0) )
2177 ::rtl::OUString sTemp ;
2178 aAny >>= sTemp ;
2179 pItem = new SfxStringItem( nSlot, sTemp );
2181 else
2182 pItem = new SfxVoidItem( nSlot );
2185 xDisp->removeStatusListener( pBind, aURL );
2186 pBind->Release();
2187 rpState = pItem;
2188 if ( bDeleteCache )
2189 DELETEZ( pCache );
2190 return eState;
2195 // Dann am Dispatcher testen; da die von dort zur"uckgegebenen Items immer
2196 // DELETE_ON_IDLE sind, mu\s eine Kopie davon gezogen werden, um einen
2197 // Eigent"umer"ubergang zu erm"oglichen
2198 const SfxPoolItem *pItem = NULL;
2199 SfxItemState eState = pDispatcher->QueryState( nSlot, pItem );
2200 if ( eState == SFX_ITEM_SET )
2202 DBG_ASSERT( pItem, "SFX_ITEM_SET aber kein Item!" );
2203 if ( pItem )
2204 rpState = pItem->Clone();
2206 else if ( eState == SFX_ITEM_AVAILABLE && pItem )
2208 rpState = pItem->Clone();
2211 return eState;
2214 void SfxBindings::SetSubBindings_Impl( SfxBindings *pSub )
2216 if ( pImp->pSubBindings )
2218 pImp->pSubBindings->SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > () );
2219 pImp->pSubBindings->pImp->pSuperBindings = NULL;
2222 pImp->pSubBindings = pSub;
2224 if ( pSub )
2226 pImp->pSubBindings->SetDispatchProvider_Impl( pImp->xProv );
2227 pSub->pImp->pSuperBindings = this;
2231 SfxBindings* SfxBindings::GetSubBindings_Impl( sal_Bool bTop ) const
2233 SfxBindings *pRet = pImp->pSubBindings;
2234 if ( bTop )
2236 while ( pRet->pImp->pSubBindings )
2237 pRet = pRet->pImp->pSubBindings;
2240 return pRet;
2243 void SfxBindings::SetWorkWindow_Impl( SfxWorkWindow* pWork )
2245 pImp->pWorkWin = pWork;
2248 SfxWorkWindow* SfxBindings::GetWorkWindow_Impl() const
2250 return pImp->pWorkWin;
2253 void SfxBindings::RegisterUnoController_Impl( SfxUnoControllerItem* pControl )
2255 if ( !pImp->pUnoCtrlArr )
2256 pImp->pUnoCtrlArr = new SfxUnoControllerArr_Impl;
2257 pImp->pUnoCtrlArr->Insert( pControl, pImp->pUnoCtrlArr->Count() );
2260 void SfxBindings::ReleaseUnoController_Impl( SfxUnoControllerItem* pControl )
2262 if ( pImp->pUnoCtrlArr )
2264 sal_uInt16 nPos = pImp->pUnoCtrlArr->GetPos( pControl );
2265 if ( nPos != 0xFFFF )
2267 pImp->pUnoCtrlArr->Remove( nPos );
2268 return;
2272 if ( pImp->pSubBindings )
2273 pImp->pSubBindings->ReleaseUnoController_Impl( pControl );
2276 void SfxBindings::InvalidateUnoControllers_Impl()
2278 if ( pImp->pUnoCtrlArr )
2280 sal_uInt16 nCount = pImp->pUnoCtrlArr->Count();
2281 for ( sal_uInt16 n=nCount; n>0; n-- )
2283 SfxUnoControllerItem *pCtrl = (*pImp->pUnoCtrlArr)[n-1];
2284 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > xRef( (::cppu::OWeakObject*)pCtrl, ::com::sun::star::uno::UNO_QUERY );
2285 pCtrl->ReleaseDispatch();
2286 pCtrl->GetNewDispatch();
2290 if ( pImp->pSubBindings )
2291 pImp->pSubBindings->InvalidateUnoControllers_Impl();
2294 sal_Bool SfxBindings::IsInUpdate() const
2296 sal_Bool bInUpdate = pImp->bInUpdate;
2297 if ( !bInUpdate && pImp->pSubBindings )
2298 bInUpdate = pImp->pSubBindings->IsInUpdate();
2299 return bInUpdate;
2302 void SfxBindings::SetVisibleState( sal_uInt16 nId, sal_Bool bShow )
2304 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
2305 SfxStateCache *pCache = GetStateCache( nId );
2306 if ( pCache )
2307 pCache->SetVisibleState( bShow );
2310 void SfxBindings::SetActiveFrame( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > & rFrame )
2312 if ( rFrame.is() || !pDispatcher )
2313 SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > ( rFrame, ::com::sun::star::uno::UNO_QUERY ) );
2314 else
2315 SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > (
2316 pDispatcher->GetFrame()->GetFrame()->GetFrameInterface(), ::com::sun::star::uno::UNO_QUERY ) );
2319 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > SfxBindings::GetActiveFrame() const
2321 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame( pImp->xProv, ::com::sun::star::uno::UNO_QUERY );
2322 if ( xFrame.is() || !pDispatcher )
2323 return xFrame;
2324 else
2325 return pDispatcher->GetFrame()->GetFrame()->GetFrameInterface();
2328 void SfxBindings::SetDispatchProvider_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & rProv )
2330 sal_Bool bInvalidate = ( rProv != pImp->xProv );
2331 if ( bInvalidate )
2333 pImp->xProv = rProv;
2334 InvalidateAll( sal_True );
2335 InvalidateUnoControllers_Impl();
2338 if ( pImp->pSubBindings )
2339 pImp->pSubBindings->SetDispatchProvider_Impl( pImp->xProv );
2342 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & SfxBindings::GetDispatchProvider_Impl() const
2344 return pImp->xProv;
2347 SystemWindow* SfxBindings::GetSystemWindow() const
2349 SfxViewFrame *pFrame = pDispatcher->GetFrame();
2350 while ( pFrame->GetParentViewFrame_Impl() )
2351 pFrame = pFrame->GetParentViewFrame_Impl();
2352 SfxTopViewFrame* pTop = PTR_CAST( SfxTopViewFrame, pFrame->GetTopViewFrame() );
2353 return pTop->GetTopFrame_Impl()->GetTopWindow_Impl();
2356 BOOL SfxBindings::ExecuteCommand_Impl( const String& rCommand )
2358 ::com::sun::star::util::URL aURL;
2359 aURL.Complete = rCommand;
2360 Reference < XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance( rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY );
2361 xTrans->parseStrict( aURL );
2362 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp = pImp->xProv->queryDispatch( aURL, ::rtl::OUString(), 0 );
2363 if ( xDisp.is() )
2365 if(::comphelper::UiEventsLogger::isEnabled()) //#i88653#
2367 ::rtl::OUString sAppName;
2370 static ::rtl::OUString our_aModuleManagerName = ::rtl::OUString::createFromAscii("com.sun.star.frame.ModuleManager");
2371 ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceManager =
2372 ::comphelper::getProcessServiceFactory();
2373 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModuleManager > xModuleManager(
2374 xServiceManager->createInstance(our_aModuleManagerName)
2375 , ::com::sun::star::uno::UNO_QUERY_THROW);
2376 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame(
2377 pDispatcher->GetFrame()->GetFrame()->GetFrameInterface(), UNO_QUERY_THROW);
2378 sAppName = xModuleManager->identify(xFrame);
2379 } catch(::com::sun::star::uno::Exception&) {}
2380 Sequence<beans::PropertyValue> source;
2381 ::comphelper::UiEventsLogger::appendDispatchOrigin(source, sAppName, ::rtl::OUString::createFromAscii("SfxAsyncExec"));
2382 ::comphelper::UiEventsLogger::logDispatch(aURL, source);
2384 new SfxAsyncExec_Impl( aURL, xDisp );
2385 return TRUE;
2388 return FALSE;
2391 com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder > SfxBindings::GetRecorder() const
2393 return pImp->xRecorder;
2396 void SfxBindings::SetRecorder_Impl( com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder >& rRecorder )
2398 pImp->xRecorder = rRecorder;
2401 void SfxBindings::ContextChanged_Impl()
2403 if ( !pImp->bInUpdate && ( !pImp->bContextChanged || !pImp->bAllMsgDirty ) )
2405 InvalidateAll( TRUE );
2409 uno::Reference < frame::XDispatch > SfxBindings::GetDispatch( const SfxSlot* pSlot, const util::URL& aURL, sal_Bool bMasterCommand )
2411 uno::Reference < frame::XDispatch > xRet;
2412 SfxStateCache* pCache = GetStateCache( pSlot->nSlotId );
2413 if ( pCache && !bMasterCommand )
2414 xRet = pCache->GetInternalDispatch();
2415 if ( !xRet.is() )
2417 // dispatches for slaves are unbound, they don't have a state
2418 SfxOfficeDispatch* pDispatch = bMasterCommand ?
2419 new SfxOfficeDispatch( pDispatcher, pSlot, aURL ) :
2420 new SfxOfficeDispatch( *this, pDispatcher, pSlot, aURL );
2422 pDispatch->SetMasterUnoCommand( bMasterCommand );
2423 xRet = uno::Reference < frame::XDispatch >( pDispatch );
2424 if ( !pCache )
2425 pCache = GetStateCache( pSlot->nSlotId );
2427 DBG_ASSERT( pCache, "No cache for OfficeDispatch!" );
2428 if ( pCache && !bMasterCommand )
2429 pCache->SetInternalDispatch( xRet );
2432 return xRet;