update dev300-m58
[ooovba.git] / sfx2 / source / control / bindings.cxx
blob487c460de60c0fd5ee1a3e64dc0260459c4aa635
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 /* [Beschreibung]
151 Diese Implementations-Struktur der Klasse SfxBindings dient
152 der Entkopplung von "Anderungen vom exportierten Interface sowie
153 der Verringerung von extern sichtbaren Symbolen.
155 Eine Instanz exisitiert pro SfxBindings-Instanz f"ur deren Laufzeit.
159 public:
160 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchRecorder > xRecorder;
161 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv;
162 SfxUnoControllerArr_Impl*
163 pUnoCtrlArr;
164 SfxWorkWindow* pWorkWin;
165 SfxBindings* pSubBindings;
166 SfxBindings* pSuperBindings;
167 SfxStateCacheArr_Impl* pCaches; // je ein cache fuer jede gebundene
168 sal_uInt16 nCachedFunc1; // index der zuletzt gerufenen
169 sal_uInt16 nCachedFunc2; // index der vorletzt gerufenen
170 sal_uInt16 nMsgPos; // Message-Position, ab der zu aktualisieren ist
171 SfxPopupAction ePopupAction; // in DeleteFloatinWindow() abgefragt
172 sal_Bool bContextChanged;
173 sal_Bool bMsgDirty; // wurde ein MessageServer invalidiert?
174 sal_Bool bAllMsgDirty; // wurden die MessageServer invalidiert?
175 sal_Bool bAllDirty; // nach InvalidateAll
176 sal_Bool bCtrlReleased; // waehrend EnterRegistrations
177 AutoTimer aTimer; // fuer volatile Slots
178 sal_Bool bInUpdate; // fuer Assertions
179 sal_Bool bInNextJob; // fuer Assertions
180 sal_Bool bFirstRound; // Erste Runde im Update
181 sal_uInt16 nFirstShell; // Shell, die in erster Runde bevorzugt wird
182 sal_uInt16 nOwnRegLevel; // z"ahlt die echten Locks, ohne die der SuperBindings
183 InvalidateSlotMap m_aInvalidateSlots; // store slots which are invalidated while in update
186 //--------------------------------------------------------------------
188 struct SfxFoundCache_Impl
190 /* [Beschreibung]
192 In Instanzen dieser Struktur werden in <SfxBindings::CreateSet_Impl()>
193 weitere Informationen zu den gemeinsam von einem <Slot-Server> zu
194 erfragenden Status gesammelt, deren Ids dort in die Ranges eines
195 <SfxItemSet>s aufgenommen werden.
197 Diese Informationen werden w"ahrend der Suche nach den zusammen
198 upzudatenden Ids sowieso als Zwischenergebnis ermittelt und nachher
199 wieder ben"otigt, daher macht es Sinn, sie f"ur diesen kurzen Zeitraum
200 gleich aufzubewahren.
204 sal_uInt16 nSlotId; // die Slot-Id
205 sal_uInt16 nWhichId; // falls verf"ugbar die Which-Id, sonst nSlotId
206 const SfxSlot* pSlot; // Pointer auf den <Master-Slot>
207 SfxStateCache* pCache; // Pointer auf den StatusCache, ggf. 0
209 SfxFoundCache_Impl():
210 nSlotId(0),
211 nWhichId(0),
212 pSlot(0),
213 pCache(0)
216 SfxFoundCache_Impl(SfxFoundCache_Impl&r):
217 nSlotId(r.nSlotId),
218 nWhichId(r.nWhichId),
219 pSlot(r.pSlot),
220 pCache(r.pCache)
223 SfxFoundCache_Impl(sal_uInt16 nS, sal_uInt16 nW, const SfxSlot *pS, SfxStateCache *pC ):
224 nSlotId(nS),
225 nWhichId(nW),
226 pSlot(pS),
227 pCache(pC)
230 int operator<( const SfxFoundCache_Impl &r ) const
231 { return nWhichId < r.nWhichId; }
233 int operator==( const SfxFoundCache_Impl &r ) const
234 { return nWhichId== r.nWhichId; }
237 //--------------------------------------------------------------------------
239 SV_DECL_PTRARR_SORT_DEL(SfxFoundCacheArr_Impl, SfxFoundCache_Impl*, 16, 16 )
240 SV_IMPL_OP_PTRARR_SORT(SfxFoundCacheArr_Impl, SfxFoundCache_Impl*);
242 //==========================================================================
244 SfxBindings::SfxBindings()
246 /* [Beschreibung]
248 Konstruktor der Klasse SfxBindings. Genau eine Instanz wird automatisch
249 von der <SfxApplication> vor <SfxApplication::Init()> angelegt. Wird
250 eine Instanz ben"otigt, z.B. zum Invalidieren von Slots, sollte diese
251 "uber den zugeh"origen <SfxViewFrame> besorgt werden. Bestimmte
252 SfxViewFrame Subklassen (z.B. <SfxInPlaceFrame>) legen ihre eigene
253 Instanz der SfxBindings an.
255 <SfxControllerItem> Instanzen k"onnen erst angelegt werden, wenn
256 die zugeh"orige SfxBindings Instanz existiert.
259 : pImp(new SfxBindings_Impl),
260 pDispatcher(0),
261 nRegLevel(1) // geht erst auf 0, wenn Dispatcher gesetzt
263 pImp->nMsgPos = 0;
264 pImp->bAllMsgDirty = sal_True;
265 pImp->bContextChanged = sal_False;
266 pImp->bMsgDirty = sal_True;
267 pImp->bAllDirty = sal_True;
268 pImp->ePopupAction = SFX_POPUP_DELETE;
269 pImp->nCachedFunc1 = 0;
270 pImp->nCachedFunc2 = 0;
271 pImp->bCtrlReleased = sal_False;
272 pImp->bFirstRound = sal_False;
273 pImp->bInNextJob = sal_False;
274 pImp->bInUpdate = sal_False;
275 pImp->pSubBindings = NULL;
276 pImp->pSuperBindings = NULL;
277 pImp->pWorkWin = NULL;
278 pImp->pUnoCtrlArr = NULL;
279 pImp->nOwnRegLevel = nRegLevel;
281 // all caches are valid (no pending invalidate-job)
282 // create the list of caches
283 pImp->pCaches = new SfxStateCacheArr_Impl;
284 pImp->aTimer.SetTimeoutHdl( LINK(this, SfxBindings, NextJob_Impl) );
287 //====================================================================
289 SfxBindings::~SfxBindings()
291 /* [Beschreibung]
293 Destruktor der Klasse SfxBindings. Die eine, f"ur jede <SfxApplication>
294 existierende Instanz wird von der <SfxApplication> nach Ausf"urhung
295 von <SfxApplication::Exit()> automatisch zerst"ort.
297 Noch existierende <SfxControllerItem> Instanzen, die bei dieser
298 SfxBindings Instanz angemeldet sind, werden im Destruktor
299 automatisch zerst"ort. Dies sind i.d.R. Floating-Toolboxen, Value-Sets
300 etc. Arrays von SfxControllerItems d"urfen zu diesem Zeitpunkt nicht
301 mehr exisitieren.
305 // Die SubBindings sollen ja nicht gelocked werden !
306 pImp->pSubBindings = NULL;
308 ENTERREGISTRATIONS();
310 pImp->aTimer.Stop();
311 DeleteControllers_Impl();
313 // Caches selbst l"oschen
314 sal_uInt16 nCount = pImp->pCaches->Count();
315 for ( sal_uInt16 nCache = 0; nCache < nCount; ++nCache )
316 delete pImp->pCaches->GetObject(nCache);
318 DELETEZ( pImp->pWorkWin );
320 delete pImp->pCaches;
321 delete pImp;
324 //--------------------------------------------------------------------
326 void SfxBindings::DeleteControllers_Impl()
328 /* [Beschreibung]
330 Interne Methode zum l"oschen noch existierender <SfxControllerItem>
331 Instanzen, die bei dieser SfxBindings Instanz angemeldet sind.
333 Dies sind i.d.R. <SfxPopupWindow>s. Nich sich selbst geh"orende
334 SfxControllerItems d"urfen bei Aufruf nur noch existieren, wenn sie
335 einem der restlichen SfxPopupWindows geh"oren.
338 [Anmerkung]
340 Wird beim Beenden der Applikation gerufen, bevor das Applikations-
341 Fenster gel"oscht wird.
345 // in der ersten Runde den SfxPopupWindows l"oschen
346 sal_uInt16 nCount = pImp->pCaches->Count();
347 sal_uInt16 nCache;
348 for ( nCache = 0; nCache < nCount; ++nCache )
350 // merken wo man ist
351 SfxStateCache *pCache = pImp->pCaches->GetObject(nCache);
352 sal_uInt16 nSlotId = pCache->GetId();
354 // SfxPopupWindow l"oschen lassen
355 pCache->DeleteFloatingWindows();
357 // da der Cache verkleinert worden sein kann, wiederaufsetzen
358 sal_uInt16 nNewCount = pImp->pCaches->Count();
359 if ( nNewCount < nCount )
361 nCache = GetSlotPos(nSlotId);
362 if ( nCache >= nNewCount ||
363 nSlotId != pImp->pCaches->GetObject(nCache)->GetId() )
364 --nCache;
365 nCount = nNewCount;
369 // alle Caches l"oschen
370 for ( nCache = pImp->pCaches->Count(); nCache > 0; --nCache )
372 // Cache via ::com::sun::star::sdbcx::Index besorgen
373 SfxStateCache *pCache = pImp->pCaches->GetObject(nCache-1);
375 // alle Controller in dem Cache unbinden
376 SfxControllerItem *pNext;
377 for ( SfxControllerItem *pCtrl = pCache->GetItemLink();
378 pCtrl; pCtrl = pNext )
380 pNext = pCtrl->GetItemLink();
381 pCtrl->UnBind();
384 if ( pCache->GetInternalController() )
385 pCache->GetInternalController()->UnBind();
387 // Cache l"oschen
388 if( nCache-1 < pImp->pCaches->Count() )
389 delete (*pImp->pCaches)[nCache-1];
390 pImp->pCaches->Remove(nCache-1, 1);
393 if( pImp->pUnoCtrlArr )
395 sal_uInt16 nCtrlCount = pImp->pUnoCtrlArr->Count();
396 for ( sal_uInt16 n=nCtrlCount; n>0; n-- )
398 SfxUnoControllerItem *pCtrl = (*pImp->pUnoCtrlArr)[n-1];
399 pCtrl->ReleaseBindings();
402 DBG_ASSERT( !pImp->pUnoCtrlArr->Count(), "UnoControllerItems nicht entfernt!" );
403 DELETEZ( pImp->pUnoCtrlArr );
407 //--------------------------------------------------------------------
409 SfxPopupAction SfxBindings::GetPopupAction_Impl() const
411 return pImp->ePopupAction;
415 //--------------------------------------------------------------------
417 void SfxBindings::HidePopups( bool bHide )
419 /* [Beschreibung]
421 Dieser Methode versteckt und zeigt die <SfxPopupWindows>, die aus
422 <SfxToolboxControl>s dieser SfxBindings-Instanz abgerissen wurden bzw.
423 floating <SfxChildWindow>-Instanzen dieser SfxBindings-Instanz.
426 [Anmerkung]
428 Es k"onnten noch weitere Floating-Windows exisitieren, die durch
429 diese Methode nicht erfa\st werden.
433 // SfxPopupWindows hiden
434 HidePopupCtrls_Impl( bHide );
435 SfxBindings *pSub = pImp->pSubBindings;
436 while ( pSub )
438 pImp->pSubBindings->HidePopupCtrls_Impl( bHide );
439 pSub = pSub->pImp->pSubBindings;
442 // SfxChildWindows hiden
443 DBG_ASSERT( pDispatcher, "HidePopups not allowed without dispatcher" );
444 if ( pImp->pWorkWin )
445 pImp->pWorkWin->HidePopups_Impl( bHide, sal_True );
448 void SfxBindings::HidePopupCtrls_Impl( FASTBOOL bHide )
450 if ( bHide )
452 // SfxPopupWindows hiden
453 pImp->ePopupAction = SFX_POPUP_HIDE;
455 else
457 // SfxPopupWindows showen
458 pImp->ePopupAction = SFX_POPUP_SHOW;
461 for ( sal_uInt16 nCache = 0; nCache < pImp->pCaches->Count(); ++nCache )
462 pImp->pCaches->GetObject(nCache)->DeleteFloatingWindows();
463 pImp->ePopupAction = SFX_POPUP_DELETE;
466 //--------------------------------------------------------------------
468 void SfxBindings::Update_Impl
470 SfxStateCache* pCache // der upzudatende SfxStatusCache
473 /* [Beschreibung]
475 Interne Methode zum Updaten eines Caches und den von derselben
476 Status-Methode in derselben Shell bedienten und dirty Slots.
480 if( pCache->GetDispatch().is() && pCache->GetItemLink() )
482 pCache->SetCachedState(TRUE);
483 if ( !pCache->GetInternalController() )
484 return;
487 if ( !pDispatcher )
488 return;
489 DBG_PROFSTART(SfxBindingsUpdate_Impl);
491 // alle mit derselben Statusmethode zusammensammeln, die dirty sind
492 SfxDispatcher &rDispat = *pDispatcher;
493 const SfxSlot *pRealSlot = 0;
494 const SfxSlotServer* pMsgServer = 0;
495 SfxFoundCacheArr_Impl aFound;
496 SfxItemSet *pSet = CreateSet_Impl( pCache, pRealSlot, &pMsgServer, aFound );
497 sal_Bool bUpdated = sal_False;
498 if ( pSet )
500 // Status erfragen
501 if ( rDispat._FillState( *pMsgServer, *pSet, pRealSlot ) )
503 // Status posten
504 const SfxInterface *pInterface =
505 rDispat.GetShell(pMsgServer->GetShellLevel())->GetInterface();
506 for ( sal_uInt16 nPos = 0; nPos < aFound.Count(); ++nPos )
508 const SfxFoundCache_Impl *pFound = aFound[nPos];
509 sal_uInt16 nWhich = pFound->nWhichId;
510 const SfxPoolItem *pItem = 0;
511 SfxItemState eState = pSet->GetItemState(nWhich, sal_True, &pItem);
512 if ( eState == SFX_ITEM_DEFAULT && SfxItemPool::IsWhich(nWhich) )
513 pItem = &pSet->Get(nWhich);
514 UpdateControllers_Impl( pInterface, aFound[nPos], pItem, eState );
516 bUpdated = sal_True;
519 delete pSet;
522 if ( !bUpdated && pCache )
524 // Wenn pCache == NULL und kein SlotServer ( z.B. weil Dispatcher gelockt! ),
525 // darf nat"urlich kein Update versucht werden
526 SfxFoundCache_Impl aFoundCache(
527 pCache->GetId(), 0,
528 pRealSlot, pCache );
529 UpdateControllers_Impl( 0, &aFoundCache, 0, SFX_ITEM_DISABLED);
532 DBG_PROFSTOP(SfxBindingsUpdate_Impl);
535 //--------------------------------------------------------------------
537 void SfxBindings::InvalidateSlotsInMap_Impl()
539 InvalidateSlotMap::const_iterator pIter = pImp->m_aInvalidateSlots.begin();
540 while ( pIter != pImp->m_aInvalidateSlots.end() )
542 Invalidate( pIter->first );
543 ++pIter;
545 pImp->m_aInvalidateSlots.clear();
548 //--------------------------------------------------------------------
550 void SfxBindings::AddSlotToInvalidateSlotsMap_Impl( USHORT nId )
552 pImp->m_aInvalidateSlots[nId] = sal_True;
555 //--------------------------------------------------------------------
557 void SfxBindings::Update
559 sal_uInt16 nId // die gebundene und upzudatende Slot-Id
562 /* [Beschreibung]
564 Diese Methode sorgt f"ur synchrones Updaten der auf die Slot-Id nId
565 gebundenen <SfxContollerItem> Instanzen, die an dieser SfxBindings
566 Instanz angemeldet sind. Vergleichbar zu Window::Update()
567 (StarView) erfolgt ein Update nur, wenn entweder ein auf diese
568 Slot-Id gebundenes SfxContollerItem dirty ist, oder die Slot-Id
569 selbst dirty ist. Dies kann durch einen vorhergehendes Aufruf von
570 <SfxBindings::Invalidate(sal_uInt16)> erzwungen werden.
573 [Anmerkung]
575 Es ist g"unstiger, zun"achst alle zu invalidierenden Slot-Ids per
576 <SfxBindings::Invalidate(sal_uInt16)> zu invalidieren und dann
577 Update() aufzurufen, als einzelne abwechselnde Invalidate/Update,
578 da von derselben Status-Methode bediente Status-Anfragen von
579 den SfxBindings automatisch zusammengefa"st werden.
582 [Querverweise]
584 <SfxShell::Invalidate(sal_uInt16)>
585 <SfxBindings::Invalidate(sal_uInt16)>
586 <SfxBindings::InvalidateAll(sal_Bool)>
587 <SfxBindings::Update()>
591 DBG_MEMTEST();
592 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
594 //!!TLX: Fuehrte zu Vorlagenkatalogstillstand
595 // if ( nRegLevel )
596 // return;
598 if ( pDispatcher )
599 pDispatcher->Flush();
601 if ( pImp->pSubBindings )
602 pImp->pSubBindings->Update( nId );
604 SfxStateCache* pCache = GetStateCache( nId );
605 if ( pCache )
607 pImp->bInUpdate = sal_True;
608 if ( pImp->bMsgDirty )
610 UpdateSlotServer_Impl();
611 pCache = GetStateCache( nId );
614 if (pCache)
616 BOOL bInternalUpdate = TRUE;
617 if( pCache->GetDispatch().is() && pCache->GetItemLink() )
619 pCache->SetCachedState(TRUE);
620 bInternalUpdate = ( pCache->GetInternalController() != 0 );
623 if ( bInternalUpdate )
625 // Status erfragen
626 const SfxSlotServer* pMsgServer = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
627 if ( !pCache->IsControllerDirty() &&
628 ( !pMsgServer ||
629 !pMsgServer->GetSlot()->IsMode(SFX_SLOT_VOLATILE) ) )
631 pImp->bInUpdate = sal_False;
632 InvalidateSlotsInMap_Impl();
633 return;
635 if (!pMsgServer)
637 pCache->SetState(SFX_ITEM_DISABLED, 0);
638 pImp->bInUpdate = sal_False;
639 InvalidateSlotsInMap_Impl();
640 return;
643 Update_Impl(pCache);
646 pImp->bAllDirty = sal_False;
649 pImp->bInUpdate = sal_False;
650 InvalidateSlotsInMap_Impl();
654 //--------------------------------------------------------------------
656 void SfxBindings::Update()
658 /* [Beschreibung]
660 Diese Methode sorgt f"ur synchrones Updaten aller <SfxContollerItem>
661 Instanzen, die an dieser SfxBindings Instanz angemeldet sind. Vergleichbar
662 zu Window::Update() (StarView) erfolgt ein Update nur, wenn entweder ein
663 SfxContollerItem dirty ist, in einem Status-Cache der Zeiger auf den
664 <Slot-Server> dirty ist. Ersteres kann durch einen Aufruf von
665 <SfxBindings::Invalidate(sal_uInt16)> erzwungen werden, letzters durch
666 <SfxBindings::InvalidateAll(sal_Bool)>.
669 [Querverweise]
671 <SfxShell::Invalidate(sal_uInt16)>
672 <SfxBindings::Invalidate(sal_uInt16)>
673 <SfxBindings::InvalidateAll(sal_Bool)>
674 <SfxBindings::Update(sal_uInt16)>
678 DBG_MEMTEST();
679 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
681 if ( pImp->pSubBindings )
682 pImp->pSubBindings->Update();
684 if ( pDispatcher )
686 if ( nRegLevel )
687 return;
689 pImp->bInUpdate = sal_True;
690 pDispatcher->Flush();
691 pDispatcher->Update_Impl();
692 while ( !NextJob_Impl(0) )
693 ; // loop
694 pImp->bInUpdate = sal_False;
695 InvalidateSlotsInMap_Impl();
699 //--------------------------------------------------------------------
701 void SfxBindings::SetState
703 const SfxItemSet& rSet // zu setzende Status-Werte
706 /* [Beschreibung]
708 Diese Methode erlaubt das direkte Setzen neuer Status-Werte, ohne
709 den Umweg "uber <SfxBindings::Invalidate()> und das dann im Update
710 erfolgende Rufen der Status-Methoden an den <SfxShell>s.
713 [Querverweise]
715 <SfxBindings::SetState(const SfxPoolItem&)>
719 // wenn gelockt, dann nur invalidieren
720 if ( nRegLevel )
722 SfxItemIter aIter(rSet);
723 for ( const SfxPoolItem *pItem = aIter.FirstItem();
724 pItem;
725 pItem = aIter.NextItem() )
726 Invalidate( pItem->Which() );
728 else
730 // Status d"urfen nur angenommen werden, wenn alle Slot-Pointer gesetzt sind
731 if ( pImp->bMsgDirty )
732 UpdateSlotServer_Impl();
734 // "uber das ItemSet iterieren, falls Slot gebunden, updaten
735 //! Bug: WhichIter verwenden und ggf. VoidItems hochschicken
736 SfxItemIter aIter(rSet);
737 for ( const SfxPoolItem *pItem = aIter.FirstItem();
738 pItem;
739 pItem = aIter.NextItem() )
741 SfxStateCache* pCache =
742 GetStateCache( rSet.GetPool()->GetSlotId(pItem->Which()) );
743 if ( pCache )
745 // Status updaten
746 if ( !pCache->IsControllerDirty() )
747 pCache->Invalidate(sal_False);
748 pCache->SetState( SFX_ITEM_AVAILABLE, pItem );
750 //! nicht implementiert: Updates von EnumSlots via MasterSlots
756 //--------------------------------------------------------------------
758 void SfxBindings::SetState
760 const SfxPoolItem& rItem // zu setzender Status-Wert
763 /* [Beschreibung]
765 Diese Methode erlaubt das direkte Setzen eines neuen Status-Wertes,
766 ohne den Umweg "uber <SfxBindings::Invalidate()> und das dann im Update
767 erfolgende Rufen der Status-Methoden an den <SfxShell>s.
769 Mit dieser Methode k"onnen nur <SfxPoolItem>s mit Slot, nicht
770 aber mit Which-Id gesetzt werden, da kein <SfxItemPool> bekannt ist,
771 "uber den gemappt werden k"onnte.
774 [Querverweise]
776 <SfxBindings::SetState(const SfxItemSet&)>
780 if ( nRegLevel )
782 Invalidate( rItem.Which() );
784 else
786 // Status d"urfen nur angenommen werden, wenn alle Slot-Pointer gesetzt sind
787 if ( pImp->bMsgDirty )
788 UpdateSlotServer_Impl();
790 // falls der Slot gebunden ist, updaten
791 DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ),
792 "cannot set items with which-id" );
793 SfxStateCache* pCache = GetStateCache( rItem.Which() );
794 if ( pCache )
796 // Status updaten
797 if ( !pCache->IsControllerDirty() )
798 pCache->Invalidate(sal_False);
799 pCache->SetState( SFX_ITEM_AVAILABLE, &rItem );
801 //! nicht implementiert: Updates von EnumSlots via MasterSlots
807 //--------------------------------------------------------------------
809 SfxStateCache* SfxBindings::GetAnyStateCache_Impl( sal_uInt16 nId )
811 SfxStateCache* pCache = GetStateCache( nId );
812 if ( !pCache && pImp->pSubBindings )
813 return pImp->pSubBindings->GetAnyStateCache_Impl( nId );
814 return pCache;
817 SfxStateCache* SfxBindings::GetStateCache
819 sal_uInt16 nId /* Slot-Id, deren SfxStatusCache gefunden
820 werden soll */,
821 sal_uInt16* pPos /* 0 bzw. Position, ab der die Bindings
822 bin"ar durchsucht werden sollen. Liefert
823 die Position zur"uck, an der nId gefunden
824 wurde, bzw. an der es einfef"ugt werden
825 w"urde. */
828 /* [Beschreibung]
830 Diese Methode sucht die zu einer Slot-Id geh"orige <SfxStatusCache>
831 Instanz. Falls die Slot-Id in keinem Controller gebunden ist, wird
832 ein 0-Pointer zur"uckgegeben.
834 Falls pPos != 0, wird erst ab der Position mit der Suche angefangen.
835 Dieses ist eine Optimierung, f"ur den Fall, da"s die kleineren
836 Ids bereits abgearbeitet wurden.
838 In *pPos wird der ::com::sun::star::sdbcx::Index innerhalb der SfxBindings zur"uckgegeben,
839 unter dem dieser Cache z.Zt. abgelegt ist. Dieser ::com::sun::star::sdbcx::Index ist bis zum
840 n"achsten Aufruf von <SfxBindings::EnterRegistrations()> g"ultig.
841 W"ahrend der Umkonfiguration (<SfxBindings::IsInRegistrations()> == sal_True)
842 kann ist der ::com::sun::star::sdbcx::Index und der R"uckgabewert nur sehr kurzfristig
843 g"ultig.
847 DBG_MEMTEST();
848 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
849 // is the specified function bound?
850 const sal_uInt16 nStart = ( pPos ? *pPos : 0 );
851 const sal_uInt16 nPos = GetSlotPos( nId, nStart );
853 if ( nPos < pImp->pCaches->Count() &&
854 (*pImp->pCaches)[nPos]->GetId() == nId )
856 if ( pPos )
857 *pPos = nPos;
858 return (*pImp->pCaches)[nPos];
860 return 0;
863 //--------------------------------------------------------------------
865 void SfxBindings::InvalidateAll
867 sal_Bool bWithMsg /* sal_True
868 Slot-Server als ung"ultig markieren
870 sal_False
871 Slot-Server bleiben g"ultig */
874 /* [Beschreibung]
876 Invalidiert alle <SfxControllerItem> Instanzen, die an dieser
877 SfxBindings Instanz angemeldet sind, und bei bWithMsg == sal_True
878 ebenfalls die <Slot-Server>-Caches.
880 Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten
881 beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden,
882 bevor "uberhaupt etwas passiert.
885 [Querverweise]
887 <SfxShell::Invalidate(sal_uInt16)>
888 <SfxBindings::Invalidate(sal_uInt16)>
889 <SfxBindings::Invalidate(sal_uInt16*)>
890 <SfxBindings::Update()>
891 <SfxBindings::Update(sal_uInt16)>
895 DBG_PROFSTART(SfxBindingsInvalidateAll);
896 DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
898 DBG_MEMTEST();
900 if ( pImp->pSubBindings )
901 pImp->pSubBindings->InvalidateAll( bWithMsg );
903 // ist schon alles dirty gesetzt oder downing => nicht zu tun
904 if ( !pDispatcher ||
905 ( pImp->bAllDirty && ( !bWithMsg || pImp->bAllMsgDirty ) ) ||
906 SFX_APP()->IsDowning() )
908 DBG_PROFSTOP(SfxBindingsInvalidateAll);
909 return;
912 pImp->bAllMsgDirty = pImp->bAllMsgDirty || bWithMsg;
913 pImp->bMsgDirty = pImp->bMsgDirty || pImp->bAllMsgDirty || bWithMsg;
914 pImp->bAllDirty = sal_True;
916 for ( sal_uInt16 n = 0; n < pImp->pCaches->Count(); ++n )
917 pImp->pCaches->GetObject(n)->Invalidate(bWithMsg);
919 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame
920 ( pDispatcher->GetFrame()->GetFrame()->GetFrameInterface(), UNO_QUERY );
922 if ( bWithMsg && xFrame.is() )
923 xFrame->contextChanged();
925 pImp->nMsgPos = 0;
926 if ( !nRegLevel )
928 pImp->aTimer.Stop();
929 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
930 pImp->aTimer.Start();
931 // pImp->bFirstRound = sal_True;
932 // pImp->nFirstShell = 0;
935 DBG_PROFSTOP(SfxBindingsInvalidateAll);
938 //--------------------------------------------------------------------
940 void SfxBindings::Invalidate
942 const sal_uInt16* pIds /* numerisch sortiertes 0-terminiertes Array
943 von Slot-Ids (einzel, nicht als Paare!) */
946 /* [Beschreibung]
948 Invalidiert die <SfxControllerItem> Instanzen der Slot-Ids in 'pIds',
949 die an dieser SfxBindings Instanz angemeldet sind.
951 Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten
952 beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden,
953 bevor "uberhaupt etwas passiert.
956 [Querverweise]
958 <SfxShell::Invalidate(sal_uInt16)>
959 <SfxBindings::Invalidate(sal_uInt16)>
960 <SfxBindings::InvalidateAll(sal_uInt16)>
961 <SfxBindings::Update()>
962 <SfxBindings::Update(sal_uInt16)>
966 DBG_PROFSTART(SfxBindingsInvalidateAll);
967 // DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
969 DBG_MEMTEST();
971 if ( pImp->bInUpdate )
973 sal_Int32 i = 0;
974 while ( pIds[i] != 0 )
975 AddSlotToInvalidateSlotsMap_Impl( pIds[i++] );
977 if ( pImp->pSubBindings )
978 pImp->pSubBindings->Invalidate( pIds );
979 return;
982 if ( pImp->pSubBindings )
983 pImp->pSubBindings->Invalidate( pIds );
985 // ist schon alles dirty gesetzt oder downing => nicht zu tun
986 if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
987 return;
989 // in immer kleiner werdenden Berichen bin"ar suchen
990 for ( sal_uInt16 n = GetSlotPos(*pIds);
991 *pIds && n < pImp->pCaches->Count();
992 n = GetSlotPos(*pIds, n) )
994 // falls SID "uberhaupt gebunden ist, den Cache invalidieren
995 SfxStateCache *pCache = pImp->pCaches->GetObject(n);
996 if ( pCache->GetId() == *pIds )
997 pCache->Invalidate(sal_False);
999 // n"achste SID
1000 if ( !*++pIds )
1001 break;
1002 DBG_ASSERT( *pIds > *(pIds-1), "pIds unsorted" );
1005 // falls nicht gelockt, Update-Timer starten
1006 pImp->nMsgPos = 0;
1007 if ( !nRegLevel )
1009 pImp->aTimer.Stop();
1010 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
1011 pImp->aTimer.Start();
1012 // pImp->bFirstRound = sal_True;
1013 // pImp->nFirstShell = 0;
1016 DBG_PROFSTOP(SfxBindingsInvalidateAll);
1019 //--------------------------------------------------------------------
1021 void SfxBindings::InvalidateShell
1023 const SfxShell& rSh /* Die <SfxShell>, deren Slot-Ids
1024 invalidiert werden sollen. */,
1026 sal_Bool bDeep /* sal_True
1027 auch die, von der SfxShell
1028 ererbten Slot-Ids werden invalidert
1030 sal_False
1031 die ererbten und nicht "uberladenen
1032 Slot-Ids werden invalidiert */
1033 //! MI: z. Zt. immer bDeep
1036 /* [Beschreibung]
1038 Invalidiert alle <SfxControllerItem> Instanzen, die zur Zeit von
1039 der angegebenen SfxShell Instanz bedient werden und an dieser
1040 SfxBindings Instanz angemeldet sind
1042 Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten
1043 beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden,
1044 bevor "uberhaupt etwas passiert.
1047 [Querverweise]
1049 <SfxShell::Invalidate(sal_uInt16)>
1050 <SfxBindings::Invalidate(sal_uInt16)>
1051 <SfxBindings::Update()>
1052 <SfxBindings::Update(sal_uInt16)>
1056 DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
1058 if ( pImp->pSubBindings )
1059 pImp->pSubBindings->InvalidateShell( rSh, bDeep );
1061 if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
1062 return;
1064 DBG_PROFSTART(SfxBindingsInvalidateAll);
1065 DBG_MEMTEST();
1067 // Jetzt schon flushen, wird in GetShellLevel(rSh) sowieso gemacht; wichtig,
1068 // damit pImp->bAll(Msg)Dirty korrekt gesetzt ist
1069 pDispatcher->Flush();
1071 if ( !pDispatcher ||
1072 ( pImp->bAllDirty && pImp->bAllMsgDirty ) ||
1073 SFX_APP()->IsDowning() )
1075 // Wenn sowieso demn"achst alle Server geholt werden
1076 return;
1079 // Level finden
1080 sal_uInt16 nLevel = pDispatcher->GetShellLevel(rSh);
1081 if ( nLevel != USHRT_MAX )
1083 for ( sal_uInt16 n = 0; n < pImp->pCaches->Count(); ++n )
1085 SfxStateCache *pCache = pImp->pCaches->GetObject(n);
1086 const SfxSlotServer *pMsgServer =
1087 pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1088 if ( pMsgServer && pMsgServer->GetShellLevel() == nLevel )
1089 pCache->Invalidate(sal_False);
1091 pImp->nMsgPos = 0;
1092 if ( !nRegLevel )
1094 pImp->aTimer.Stop();
1095 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
1096 pImp->aTimer.Start();
1097 pImp->bFirstRound = sal_True;
1098 pImp->nFirstShell = nLevel;
1102 DBG_PROFSTOP(SfxBindingsInvalidateAll);
1105 //--------------------------------------------------------------------
1107 void SfxBindings::Invalidate
1109 sal_uInt16 nId // zu invalidierende Slot-Id
1112 /* [Beschreibung]
1114 Invalidiert alle <SfxControllerItem> Instanzen, die auf die Slot-Id
1115 nId gebunden sind und an dieser SfxBindings Instanz angemeldet sind.
1117 Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten
1118 beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden,
1119 bevor "uberhaupt etwas passiert.
1122 [Querverweise]
1123 <SfxBindings::Invalidate(sal_uInt16*)>
1124 <SfxBindings::InvalidateAll(sal_Bool)>
1125 <SfxBindings::Update()>
1126 <SfxBindings::Update(sal_uInt16)>
1130 DBG_MEMTEST();
1131 // DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
1133 if ( pImp->bInUpdate )
1135 AddSlotToInvalidateSlotsMap_Impl( nId );
1136 if ( pImp->pSubBindings )
1137 pImp->pSubBindings->Invalidate( nId );
1138 return;
1141 if ( pImp->pSubBindings )
1142 pImp->pSubBindings->Invalidate( nId );
1144 if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
1145 return;
1147 SfxStateCache* pCache = GetStateCache(nId);
1148 if ( pCache )
1150 pCache->Invalidate(sal_False);
1151 pImp->nMsgPos = Min(GetSlotPos(nId), pImp->nMsgPos);
1152 if ( !nRegLevel )
1154 pImp->aTimer.Stop();
1155 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
1156 pImp->aTimer.Start();
1161 //--------------------------------------------------------------------
1163 void SfxBindings::Invalidate
1165 sal_uInt16 nId, // zu invalidierende Slot-Id
1166 sal_Bool bWithItem, // StateCache clearen ?
1167 sal_Bool bWithMsg // SlotServer neu holen ?
1170 /* [Beschreibung]
1172 Invalidiert alle <SfxControllerItem> Instanzen, die auf die Slot-Id
1173 nId gebunden sind und an dieser SfxBindings Instanz angemeldet sind,
1174 und bei bWithMsg == sal_True ebenfalls den <Slot-Server>-Cache.
1176 Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten
1177 beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden,
1178 bevor "uberhaupt etwas passiert.
1180 [Querverweise]
1181 <SfxBindings::Invalidate(sal_uInt16*)>
1182 <SfxBindings::InvalidateAll(sal_Bool)>
1183 <SfxBindings::Update()>
1184 <SfxBindings::Update(sal_uInt16)>
1188 DBG_MEMTEST();
1189 DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
1191 if ( pImp->pSubBindings )
1192 pImp->pSubBindings->Invalidate( nId, bWithItem, bWithMsg );
1194 if ( SFX_APP()->IsDowning() )
1195 return;
1197 SfxStateCache* pCache = GetStateCache(nId);
1198 if ( pCache )
1200 if ( bWithItem )
1201 pCache->ClearCache();
1202 pCache->Invalidate(bWithMsg);
1204 if ( !pDispatcher || pImp->bAllDirty )
1205 return;
1207 pImp->nMsgPos = Min(GetSlotPos(nId), pImp->nMsgPos);
1208 if ( !nRegLevel )
1210 pImp->aTimer.Stop();
1211 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
1212 pImp->aTimer.Start();
1217 void SfxBindings::Invalidate
1219 sal_uInt16, // zu invalidierende Slot-Id
1220 sal_Bool // SlotServer neu holen ?
1223 /* [Beschreibung]
1225 Invalidiert alle <SfxControllerItem> Instanzen, die auf die Slot-Id
1226 nId gebunden sind und an dieser SfxBindings Instanz angemeldet sind,
1227 und bei bWithMsg == sal_True ebenfalls den <Slot-Server>-Cache.
1229 Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten
1230 beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden,
1231 bevor "uberhaupt etwas passiert.
1233 [Querverweise]
1234 <SfxBindings::Invalidate(sal_uInt16*)>
1235 <SfxBindings::InvalidateAll(sal_Bool)>
1236 <SfxBindings::Update()>
1237 <SfxBindings::Update(sal_uInt16)>
1241 DBG_ERROR( "Methode veraltet!" );
1244 //--------------------------------------------------------------------
1246 sal_Bool SfxBindings::IsBound( sal_uInt16 nSlotId, sal_uInt16 nStartSearchAt )
1248 /* [Beschreibung]
1250 Stellt fest, ob die angegebene Slot-Id in einem <SfxControllerItem>
1251 gebunden ist, der an dieser SfxBindings Instanz angemeldet ist.
1254 [R"uckgabewert]
1256 sal_Bool sal_True
1257 Die angegeben Slot-Id ist gebunden.
1259 sal_False
1260 Die angegeben Slot-Id ist nicht gebunden.
1264 DBG_MEMTEST();
1265 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1266 return GetStateCache(nSlotId, &nStartSearchAt ) != 0;
1269 //--------------------------------------------------------------------
1271 sal_uInt16 SfxBindings::GetSlotPos( sal_uInt16 nId, sal_uInt16 nStartSearchAt )
1273 /* [Beschreibung]
1275 Ermittelt den ::com::sun::star::sdbcx::Index der angegebenen Slot-Id in den SfxBindings.
1276 Falls die Slot-Id nicht gebunden ist, wird der ::com::sun::star::sdbcx::Index zur"uckgegeben,
1277 an dem sie eingef"ugt w"urde.
1281 DBG_MEMTEST();
1282 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1283 DBG_PROFSTART(SfxBindingsMsgPos);
1285 // answer immediately if a function-seek comes repeated
1286 if ( pImp->nCachedFunc1 < pImp->pCaches->Count() &&
1287 (*pImp->pCaches)[pImp->nCachedFunc1]->GetId() == nId )
1289 ++nCache1;
1290 DBG_PROFSTOP(SfxBindingsMsgPos);
1291 return pImp->nCachedFunc1;
1293 if ( pImp->nCachedFunc2 < pImp->pCaches->Count() &&
1294 (*pImp->pCaches)[pImp->nCachedFunc2]->GetId() == nId )
1296 ++nCache2;
1298 // swap the caches
1299 sal_uInt16 nTemp = pImp->nCachedFunc1;
1300 pImp->nCachedFunc1 = pImp->nCachedFunc2;
1301 pImp->nCachedFunc2 = nTemp;
1302 DBG_PROFSTOP(SfxBindingsMsgPos);
1303 return pImp->nCachedFunc1;
1306 // binary search, if not found, seek to target-position
1307 if ( pImp->pCaches->Count() <= nStartSearchAt )
1309 DBG_PROFSTOP(SfxBindingsMsgPos);
1310 return 0;
1312 if ( pImp->pCaches->Count() == (nStartSearchAt+1) )
1314 DBG_PROFSTOP(SfxBindingsMsgPos);
1315 return (*pImp->pCaches)[nStartSearchAt]->GetId() >= nId ? 0 : 1;
1317 sal_uInt16 nLow = nStartSearchAt;
1318 sal_uInt16 nMid = 0;
1319 sal_uInt16 nHigh = 0;
1320 sal_Bool bFound = sal_False;
1321 nHigh = pImp->pCaches->Count() - 1;
1322 while ( !bFound && nLow <= nHigh )
1324 nMid = (nLow + nHigh) >> 1;
1325 DBG_ASSERT( nMid < pImp->pCaches->Count(), "bsearch ist buggy" );
1326 int nDiff = (int) nId - (int) ( ((*pImp->pCaches)[nMid])->GetId() );
1327 if ( nDiff < 0)
1328 { if ( nMid == 0 )
1329 break;
1330 nHigh = nMid - 1;
1332 else if ( nDiff > 0 )
1333 { nLow = nMid + 1;
1334 if ( nLow == 0 )
1335 break;
1337 else
1338 bFound = sal_True;
1340 sal_uInt16 nPos = bFound ? nMid : nLow;
1341 DBG_ASSERT( nPos <= pImp->pCaches->Count(), "" );
1342 DBG_ASSERT( nPos == pImp->pCaches->Count() ||
1343 nId <= (*pImp->pCaches)[nPos]->GetId(), "" );
1344 DBG_ASSERT( nPos == nStartSearchAt ||
1345 nId > (*pImp->pCaches)[nPos-1]->GetId(), "" );
1346 DBG_ASSERT( ( (nPos+1) >= pImp->pCaches->Count() ) ||
1347 nId < (*pImp->pCaches)[nPos+1]->GetId(), "" );
1348 pImp->nCachedFunc2 = pImp->nCachedFunc1;
1349 pImp->nCachedFunc1 = nPos;
1350 DBG_PROFSTOP(SfxBindingsMsgPos);
1351 return nPos;
1353 //--------------------------------------------------------------------
1354 void SfxBindings::RegisterInternal_Impl( SfxControllerItem& rItem )
1356 Register_Impl( rItem, TRUE );
1360 void SfxBindings::Register( SfxControllerItem& rItem )
1362 Register_Impl( rItem, FALSE );
1365 void SfxBindings::Register_Impl( SfxControllerItem& rItem, BOOL bInternal )
1367 DBG_MEMTEST();
1368 DBG_ASSERT( nRegLevel > 0, "registration without EnterRegistrations" );
1369 DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Register while status-updating" );
1371 // insert new cache if it does not already exist
1372 sal_uInt16 nId = rItem.GetId();
1373 sal_uInt16 nPos = GetSlotPos(nId);
1374 if ( nPos >= pImp->pCaches->Count() ||
1375 (*pImp->pCaches)[nPos]->GetId() != nId )
1377 SfxStateCache* pCache = new SfxStateCache(nId);
1378 pImp->pCaches->Insert( nPos, pCache );
1379 DBG_ASSERT( nPos == 0 ||
1380 (*pImp->pCaches)[nPos]->GetId() >
1381 (*pImp->pCaches)[nPos-1]->GetId(), "" );
1382 DBG_ASSERT( (nPos == pImp->pCaches->Count()-1) ||
1383 (*pImp->pCaches)[nPos]->GetId() <
1384 (*pImp->pCaches)[nPos+1]->GetId(), "" );
1385 pImp->bMsgDirty = sal_True;
1388 // enqueue the new binding
1389 if ( bInternal )
1391 (*pImp->pCaches)[nPos]->SetInternalController( &rItem );
1393 else
1395 SfxControllerItem *pOldItem = (*pImp->pCaches)[nPos]->ChangeItemLink(&rItem);
1396 rItem.ChangeItemLink(pOldItem);
1400 //--------------------------------------------------------------------
1402 void SfxBindings::Release( SfxControllerItem& rItem )
1404 DBG_MEMTEST();
1405 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1406 //! DBG_ASSERT( nRegLevel > 0, "release without EnterRegistrations" );
1407 DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Release while status-updating" );
1408 ENTERREGISTRATIONS();
1410 // find the bound function
1411 sal_uInt16 nId = rItem.GetId();
1412 sal_uInt16 nPos = GetSlotPos(nId);
1413 SfxStateCache* pCache = (*pImp->pCaches)[nPos];
1414 if ( pCache->GetId() == nId )
1416 if ( pCache->GetInternalController() == &rItem )
1418 pCache->ReleaseInternalController();
1420 else
1422 // is this the first binding in the list?
1423 SfxControllerItem* pItem = pCache->GetItemLink();
1424 if ( pItem == &rItem )
1425 pCache->ChangeItemLink( rItem.GetItemLink() );
1426 else
1428 // search the binding in the list
1429 while ( pItem && pItem->GetItemLink() != &rItem )
1430 pItem = pItem->GetItemLink();
1432 // unlink it if it was found
1433 if ( pItem )
1434 pItem->ChangeItemLink( rItem.GetItemLink() );
1438 // was this the last controller?
1439 if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() )
1441 #ifdef slow
1442 // remove the BoundFunc
1443 delete (*pImp->pCaches)[nPos];
1444 pImp->pCaches->Remove(nPos, 1);
1445 #endif
1446 if ( SfxMacroConfig::IsMacroSlot( nId ) )
1448 delete (*pImp->pCaches)[nPos];
1449 pImp->pCaches->Remove(nPos, 1);
1451 else
1452 pImp->bCtrlReleased = sal_True;
1456 LEAVEREGISTRATIONS();
1459 //--------------------------------------------------------------------
1460 const SfxPoolItem* SfxBindings::ExecuteSynchron( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi,
1461 const SfxPoolItem **ppInternalArgs )
1463 DBG_MEMTEST();
1464 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1466 if( !nId || !pDispatcher )
1467 return NULL;
1469 return Execute_Impl( nId, ppItems, nModi, SFX_CALLMODE_SYNCHRON, ppInternalArgs );
1472 sal_Bool SfxBindings::Execute( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode,
1473 const SfxPoolItem **ppInternalArgs )
1475 /* [Beschreibung]
1477 F"uhrt den Slot mit der Slot-Id nId "uber den <Slot-Server> Cache
1478 aus. Dies ist nur bei in dieser SfxBindings INstanz gebundenen
1479 Slot-Ids m"oglich.
1482 [R"uckgabewert]
1484 sal_Bool sal_True
1485 Das Execute wurde ausgef"uhrt.
1487 sal_False
1488 Das Execute konnte nicht ausgef"uhrt werden,
1489 weil der Slot entweder nicht zur Verf"ugung steht
1490 (in keiner aktiven <SfxShell> vorhanden oder
1491 disabled) ist oder der Anwender die Ausf"uhrung
1492 abgebrochen hat (Cancel in einem Dialog).
1495 [Querverweise]
1496 <SfxDispatcher>
1499 DBG_MEMTEST();
1500 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1502 if( !nId || !pDispatcher )
1503 return sal_False;
1505 const SfxPoolItem* pRet = Execute_Impl( nId, ppItems, nModi, nCallMode, ppInternalArgs );
1506 return ( pRet != 0 );
1509 void SfxBindings::ExecuteGlobal_Impl( USHORT nId )
1511 if( nId && pDispatcher )
1512 Execute_Impl( nId, NULL, 0, SFX_CALLMODE_ASYNCHRON, NULL, TRUE );
1515 const SfxPoolItem* SfxBindings::Execute_Impl( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode,
1516 const SfxPoolItem **ppInternalArgs, BOOL bGlobalOnly )
1518 SfxStateCache *pCache = GetStateCache( nId );
1519 if ( !pCache )
1521 SfxBindings *pBind = pImp->pSubBindings;
1522 while ( pBind )
1524 if ( pBind->GetStateCache( nId ) )
1525 return pBind->Execute_Impl( nId, ppItems, nModi, nCallMode, ppInternalArgs, bGlobalOnly );
1526 pBind = pBind->pImp->pSubBindings;
1530 SfxDispatcher &rDispatcher = *pDispatcher;
1531 rDispatcher.Flush();
1532 rDispatcher.GetFrame(); // -Wall is this required???
1534 // get SlotServer (Slot+ShellLevel) and Shell from cache
1535 sal_Bool bDeleteCache = sal_False;
1536 if ( !pCache )
1538 // Execution of non cached slots (Accelerators don't use Controllers)
1539 // slot is uncached, use SlotCache to handle external dispatch providers
1540 pCache = new SfxStateCache( nId );
1541 pCache->GetSlotServer( rDispatcher, pImp->xProv );
1542 bDeleteCache = sal_True;
1545 if ( pCache && pCache->GetDispatch().is() )
1547 DBG_ASSERT( !ppInternalArgs, "Internal args get lost when dispatched!" );
1549 SfxItemPool &rPool = GetDispatcher()->GetFrame()->GetObjectShell()->GetPool();
1550 SfxRequest aReq( nId, nCallMode, rPool );
1551 aReq.SetModifier( nModi );
1552 if( ppItems )
1553 while( *ppItems )
1554 aReq.AppendItem( **ppItems++ );
1556 // cache binds to an external dispatch provider
1557 pCache->Dispatch( aReq.GetArgs(), nCallMode == SFX_CALLMODE_SYNCHRON );
1558 if ( bDeleteCache )
1559 DELETEZ( pCache );
1560 SfxPoolItem *pVoid = new SfxVoidItem( nId );
1561 DeleteItemOnIdle( pVoid );
1562 return pVoid;
1565 // slot is handled internally by SfxDispatcher
1566 if ( pImp->bMsgDirty )
1567 UpdateSlotServer_Impl();
1569 SfxShell *pShell=0;
1570 const SfxSlot *pSlot=0;
1572 // if slot was uncached, we should have created a cache in this method!
1573 DBG_ASSERT( pCache, "This code needs a cache!");
1574 const SfxSlotServer* pServer = pCache ? pCache->GetSlotServer( rDispatcher, pImp->xProv ) : 0;
1575 if ( !pServer )
1577 return NULL;
1579 else
1581 pShell = rDispatcher.GetShell( pServer->GetShellLevel() );
1582 pSlot = pServer->GetSlot();
1585 if ( bGlobalOnly )
1586 if ( !pShell->ISA(SfxModule) && !pShell->ISA(SfxApplication) && !pShell->ISA(SfxViewFrame) )
1587 return NULL;
1589 SfxItemPool &rPool = pShell->GetPool();
1590 SfxRequest aReq( nId, nCallMode, rPool );
1591 aReq.SetModifier( nModi );
1592 if( ppItems )
1593 while( *ppItems )
1594 aReq.AppendItem( **ppItems++ );
1595 if ( ppInternalArgs )
1597 SfxAllItemSet aSet( rPool );
1598 for ( const SfxPoolItem **pArg = ppInternalArgs; *pArg; ++pArg )
1599 aSet.Put( **pArg );
1600 aReq.SetInternalArgs_Impl( aSet );
1603 Execute_Impl( aReq, pSlot, pShell );
1605 const SfxPoolItem* pRet = aReq.GetReturnValue();
1606 if ( !pRet )
1608 SfxPoolItem *pVoid = new SfxVoidItem( nId );
1609 DeleteItemOnIdle( pVoid );
1610 pRet = pVoid;
1613 if ( bDeleteCache )
1614 delete pCache;
1616 return pRet;
1619 void SfxBindings::Execute_Impl( SfxRequest& aReq, const SfxSlot* pSlot, SfxShell* pShell )
1621 SfxItemPool &rPool = pShell->GetPool();
1623 if ( SFX_KIND_ENUM == pSlot->GetKind() )
1625 // bei Enum-Slots muss der Master mit dem Wert des Enums executet werden
1626 const SfxSlot *pRealSlot = pShell->GetInterface()->GetRealSlot(pSlot);
1627 const sal_uInt16 nSlotId = pRealSlot->GetSlotId();
1628 aReq.SetSlot( nSlotId );
1629 aReq.AppendItem( SfxAllEnumItem( rPool.GetWhich(nSlotId), pSlot->GetValue() ) );
1630 pDispatcher->_Execute( *pShell, *pRealSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD );
1632 else if ( SFX_KIND_ATTR == pSlot->GetKind() )
1634 // bei Attr-Slots muss der Which-Wert gemapped werden
1635 const sal_uInt16 nSlotId = pSlot->GetSlotId();
1636 aReq.SetSlot( nSlotId );
1637 if ( pSlot->IsMode(SFX_SLOT_TOGGLE) )
1639 // an togglebare-Attribs (Bools) wird der Wert angeheangt
1640 sal_uInt16 nWhich = pSlot->GetWhich(rPool);
1641 SfxItemSet aSet(rPool, nWhich, nWhich, 0);
1642 SfxStateFunc aFunc = pSlot->GetStateFnc();
1643 pShell->CallState( aFunc, aSet );
1644 const SfxPoolItem *pOldItem;
1645 SfxItemState eState = aSet.GetItemState(nWhich, sal_True, &pOldItem);
1646 if ( eState == SFX_ITEM_DISABLED )
1647 return;
1649 if ( SFX_ITEM_AVAILABLE == eState && SfxItemPool::IsWhich(nWhich) )
1650 pOldItem = &aSet.Get(nWhich);
1652 if ( SFX_ITEM_SET == eState ||
1653 ( SFX_ITEM_AVAILABLE == eState &&
1654 SfxItemPool::IsWhich(nWhich) &&
1655 pOldItem ) )
1657 if ( pOldItem->ISA(SfxBoolItem) )
1659 // wir koennen Bools toggeln
1660 sal_Bool bOldValue = ((const SfxBoolItem *)pOldItem)->GetValue();
1661 SfxBoolItem *pNewItem = (SfxBoolItem*) (pOldItem->Clone());
1662 pNewItem->SetValue( !bOldValue );
1663 aReq.AppendItem( *pNewItem );
1664 delete pNewItem;
1666 else if ( pOldItem->ISA(SfxEnumItemInterface) &&
1667 ((SfxEnumItemInterface *)pOldItem)->HasBoolValue())
1669 // und Enums mit Bool-Interface
1670 SfxEnumItemInterface *pNewItem =
1671 (SfxEnumItemInterface*) (pOldItem->Clone());
1672 pNewItem->SetBoolValue(!((SfxEnumItemInterface *)pOldItem)->GetBoolValue());
1673 aReq.AppendItem( *pNewItem );
1674 delete pNewItem;
1676 else {
1677 DBG_ERROR( "Toggle only for Enums and Bools allowed" );
1680 else if ( SFX_ITEM_DONTCARE == eState )
1682 // ein Status-Item per Factory erzeugen
1683 SfxPoolItem *pNewItem = pSlot->GetType()->CreateItem();
1684 DBG_ASSERT( pNewItem, "Toggle an Slot ohne ItemFactory" );
1685 pNewItem->SetWhich( nWhich );
1687 if ( pNewItem->ISA(SfxBoolItem) )
1689 // wir koennen Bools toggeln
1690 ((SfxBoolItem*)pNewItem)->SetValue( sal_True );
1691 aReq.AppendItem( *pNewItem );
1693 else if ( pNewItem->ISA(SfxEnumItemInterface) &&
1694 ((SfxEnumItemInterface *)pNewItem)->HasBoolValue())
1696 // und Enums mit Bool-Interface
1697 ((SfxEnumItemInterface*)pNewItem)->SetBoolValue(sal_True);
1698 aReq.AppendItem( *pNewItem );
1700 else {
1701 DBG_ERROR( "Toggle only for Enums and Bools allowed" );
1703 delete pNewItem;
1705 else {
1706 DBG_ERROR( "suspicious Toggle-Slot" );
1710 pDispatcher->_Execute( *pShell, *pSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD );
1712 else
1713 pDispatcher->_Execute( *pShell, *pSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD );
1716 //--------------------------------------------------------------------
1718 void SfxBindings::UpdateSlotServer_Impl()
1720 /* [Beschreibung]
1722 Interne Methode zum Updaten der Pointer auf die SlotServer
1723 nach <SfxBindings::InvalidateAll(sal_Bool)>.
1727 DBG_PROFSTART(SfxBindingsUpdateServers);
1728 DBG_MEMTEST();
1729 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1731 // synchronisieren
1732 pDispatcher->Flush();
1733 // pDispatcher->Update_Impl();
1735 if ( pImp->bAllMsgDirty )
1737 if ( !nRegLevel )
1739 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame
1740 ( pDispatcher->GetFrame()->GetFrame()->GetFrameInterface(), UNO_QUERY );
1741 //if ( xFrame.is() )
1742 // xFrame->contextChanged();
1743 pImp->bContextChanged = FALSE;
1745 else
1746 pImp->bContextChanged = TRUE;
1749 const sal_uInt16 nCount = pImp->pCaches->Count();
1750 for(sal_uInt16 i = 0; i < nCount; ++i)
1752 SfxStateCache *pCache = pImp->pCaches->GetObject(i);
1753 pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1755 pImp->bMsgDirty = pImp->bAllMsgDirty = sal_False;
1757 Broadcast( SfxSimpleHint(SFX_HINT_DOCCHANGED) );
1759 DBG_PROFSTOP(SfxBindingsUpdateServers);
1762 //--------------------------------------------------------------------
1764 #ifdef WNT
1765 int __cdecl CmpUS_Impl(const void *p1, const void *p2)
1766 #else
1767 int CmpUS_Impl(const void *p1, const void *p2)
1768 #endif
1770 /* [Beschreibung]
1772 Interne Vergleichsfunktion fuer qsort.
1776 return *(sal_uInt16 *)p1 - *(sal_uInt16 *)p2;
1779 //--------------------------------------------------------------------
1781 SfxItemSet* SfxBindings::CreateSet_Impl
1783 SfxStateCache*& pCache, // in: Status-Cache von nId
1784 const SfxSlot*& pRealSlot, // out: RealSlot zu nId
1785 const SfxSlotServer** pMsgServer, // out: Slot-Server zu nId
1786 SfxFoundCacheArr_Impl& rFound // out: Liste der Caches der Siblings
1789 /* [Beschreibung]
1791 Diese interne Methode sucht zu pCache die Slot-Ids, die von derselben
1792 Status-Methode bedient werden und ebenfalls gebunden und dirty sind.
1793 Es wird ein SfxItemSet zusammengestellt, das die Slot-Ids (oder falls
1794 vorhanden die mit dem Pool der Shell gemappten Which-Ids) enth"alt.
1795 Die Caches dieser Slots werden in pFoundCaches zur"uckgeliefert.
1799 DBG_MEMTEST();
1800 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1802 DBG_ASSERT( !pImp->bMsgDirty, "CreateSet_Impl mit dirty MessageServer" );
1804 const SfxSlotServer* pMsgSvr = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1805 if(!pMsgSvr || !pDispatcher)
1806 return 0;
1808 DBG_PROFSTART(SfxBindingsCreateSet);
1809 pRealSlot = 0;
1810 *pMsgServer = pMsgSvr;
1812 sal_uInt16 nShellLevel = pMsgSvr->GetShellLevel();
1813 SfxShell *pShell = pDispatcher->GetShell( nShellLevel );
1814 if ( !pShell ) // seltener GPF beim Browsen durch Update aus Inet-Notify
1815 return 0;
1817 SfxItemPool &rPool = pShell->GetPool();
1819 // hole die Status-Methode, von der pCache bedient wird
1820 SfxStateFunc pFnc = 0;
1821 const SfxInterface *pInterface = pShell->GetInterface();
1822 if ( SFX_KIND_ENUM == pMsgSvr->GetSlot()->GetKind() )
1824 pRealSlot = pInterface->GetRealSlot(pMsgSvr->GetSlot());
1825 pCache = GetStateCache( pRealSlot->GetSlotId() );
1826 // DBG_ASSERT( pCache, "Kein Slotcache fuer den Masterslot gefunden!" );
1828 else
1829 pRealSlot = pMsgSvr->GetSlot();
1832 // Achtung: pCache darf auch NULL sein !!!
1835 pFnc = pRealSlot->GetStateFnc();
1837 // der RealSlot ist immer drin
1838 const SfxFoundCache_Impl *pFound = new SfxFoundCache_Impl(
1839 pRealSlot->GetSlotId(), pRealSlot->GetWhich(rPool), pRealSlot, pCache );
1840 rFound.Insert( pFound );
1842 USHORT nSlot = pRealSlot->GetSlotId();
1843 if ( !SfxMacroConfig::IsMacroSlot( nSlot ) && !(nSlot >= SID_VERB_START && nSlot <= SID_VERB_END) )
1845 pInterface = pInterface->GetRealInterfaceForSlot( pRealSlot );
1846 DBG_ASSERT (pInterface,"Slot in angegebener Shell nicht gefunden!");
1849 // Durchsuche die Bindings nach den von derselben Funktion bedienten Slots.
1850 // Daf"ur kommen nur Slots in Frage, die es im gefundenen Interface gibt.
1852 // Die Position des Statecaches im StateCache-Array
1853 sal_uInt16 nCachePos = pImp->nMsgPos;
1854 const SfxSlot *pSibling = pRealSlot->GetNextSlot();
1856 // Die Slots eines Interfaces sind im Kreis verkettet
1857 while ( pSibling > pRealSlot )
1859 SfxStateFunc pSiblingFnc=0;
1860 SfxStateCache *pSiblingCache =
1861 GetStateCache( pSibling->GetSlotId(), &nCachePos );
1863 // Ist der Slot "uberhaupt gecached ?
1864 if ( pSiblingCache )
1866 const SfxSlotServer *pServ = pSiblingCache->GetSlotServer(*pDispatcher, pImp->xProv);
1867 if ( pServ && pServ->GetShellLevel() == nShellLevel )
1868 pSiblingFnc = pServ->GetSlot()->GetStateFnc();
1871 // Mu\s der Slot "uberhaupt upgedatet werden ?
1872 FASTBOOL bInsert = pSiblingCache && pSiblingCache->IsControllerDirty();
1874 // Bugfix #26161#: Es reicht nicht, nach der selben Shell zu fragen !!
1875 FASTBOOL bSameMethod = pSiblingCache && pFnc == pSiblingFnc;
1877 // Wenn der Slot ein nicht-dirty MasterSlot ist, dann ist vielleicht
1878 // einer seiner Slaves dirty ? Dann wird der Masterslot doch eingef"ugt.
1879 if ( !bInsert && bSameMethod && pSibling->GetLinkedSlot() )
1881 // auch Slave-Slots auf Binding pru"fen
1882 const SfxSlot* pFirstSlave = pSibling->GetLinkedSlot();
1883 for ( const SfxSlot *pSlaveSlot = pFirstSlave;
1884 !bInsert;
1885 pSlaveSlot = pSlaveSlot->GetNextSlot())
1887 // Die Slaves zeigen auf ihren Master
1888 DBG_ASSERT(pSlaveSlot->GetLinkedSlot() == pSibling,
1889 "Falsche Master/Slave-Beziehung!");
1891 sal_uInt16 nCurMsgPos = pImp->nMsgPos;
1892 const SfxStateCache *pSlaveCache =
1893 GetStateCache( pSlaveSlot->GetSlotId(), &nCurMsgPos );
1895 // Ist der Slave-Slot gecached und dirty ?
1896 bInsert = pSlaveCache && pSlaveCache->IsControllerDirty();
1898 // Slaves sind untereinander im Kreis verkettet
1899 if (pSlaveSlot->GetNextSlot() == pFirstSlave)
1900 break;
1904 if ( bInsert && bSameMethod )
1906 const SfxFoundCache_Impl *pFoundCache = new SfxFoundCache_Impl(
1907 pSibling->GetSlotId(), pSibling->GetWhich(rPool),
1908 pSibling, pSiblingCache );
1910 rFound.Insert( pFoundCache );
1913 pSibling = pSibling->GetNextSlot();
1916 // aus den Ranges ein Set erzeugen
1917 sal_uInt16 *pRanges = new sal_uInt16[rFound.Count() * 2 + 1];
1918 int j = 0;
1919 USHORT i = 0;
1920 while ( i < rFound.Count() )
1922 pRanges[j++] = rFound[i]->nWhichId;
1923 // aufeinanderfolgende Zahlen
1924 for ( ; i < rFound.Count()-1; ++i )
1925 if ( rFound[i]->nWhichId+1 != rFound[i+1]->nWhichId )
1926 break;
1927 pRanges[j++] = rFound[i++]->nWhichId;
1929 pRanges[j] = 0; // terminierende NULL
1930 SfxItemSet *pSet = new SfxItemSet(rPool, pRanges);
1931 delete [] pRanges;
1932 DBG_PROFSTOP(SfxBindingsCreateSet);
1933 return pSet;
1936 //--------------------------------------------------------------------
1938 void SfxBindings::UpdateControllers_Impl
1940 const SfxInterface* pIF, // das diese Id momentan bedienende Interface
1941 const SfxFoundCache_Impl* pFound, // Cache, Slot, Which etc.
1942 const SfxPoolItem* pItem, // item to send to controller
1943 SfxItemState eState // state of item
1946 /* [Beschreibung]
1948 Dieses ist eine Hilfsmethode f"ur NextJob_Impl mit der die SfxController,
1949 welche auf nSlotId gebunden sind, upgedated werden. Dabei wird der
1950 Wert aus dem SfxPoolItem unter dem Which-Wert nWhich aus dem Set rSet
1951 genommen.
1953 Falls zu rSlot Enum-Werte in der Slotmap eingetragen sind, und diese
1954 gebunden sind, werden sie ebenfalls upgedated.
1958 DBG_ASSERT( !pFound->pSlot || SFX_KIND_ENUM != pFound->pSlot->GetKind(),
1959 "direct update of enum slot isn't allowed" );
1960 DBG_PROFSTART(SfxBindingsUpdateCtrl1);
1962 SfxStateCache* pCache = pFound->pCache;
1963 const SfxSlot* pSlot = pFound->pSlot;
1964 DBG_ASSERT( !pCache || !pSlot || pCache->GetId() == pSlot->GetSlotId(), "SID mismatch" );
1966 // insofern gebunden, die Controller f"uer den Slot selbst updaten
1967 if ( pCache && pCache->IsControllerDirty() )
1969 if ( SFX_ITEM_DONTCARE == eState )
1971 // uneindeuting
1972 pCache->SetState( SFX_ITEM_DONTCARE, (SfxPoolItem *)-1 );
1974 else if ( SFX_ITEM_DEFAULT == eState &&
1975 pFound->nWhichId > SFX_WHICH_MAX )
1977 // kein Status oder Default aber ohne Pool
1978 SfxVoidItem aVoid(0);
1979 pCache->SetState( SFX_ITEM_UNKNOWN, &aVoid );
1981 else if ( SFX_ITEM_DISABLED == eState )
1982 pCache->SetState(SFX_ITEM_DISABLED, 0);
1983 else
1984 pCache->SetState(SFX_ITEM_AVAILABLE, pItem);
1987 DBG_PROFSTOP(SfxBindingsUpdateCtrl1);
1989 // insofern vorhanden und gebunden, die Controller f"uer Slave-Slots
1990 // (Enum-Werte) des Slots updaten
1991 DBG_PROFSTART(SfxBindingsUpdateCtrl2);
1992 DBG_ASSERT( !pSlot || 0 == pSlot->GetLinkedSlot() || !pItem ||
1993 pItem->ISA(SfxEnumItemInterface),
1994 "master slot with non-enum-type found" );
1995 const SfxSlot *pFirstSlave = pSlot ? pSlot->GetLinkedSlot() : 0;
1996 if ( pIF && pFirstSlave)
1998 // Items auf EnumItem casten
1999 const SfxEnumItemInterface *pEnumItem =
2000 PTR_CAST(SfxEnumItemInterface,pItem);
2001 if ( eState == SFX_ITEM_AVAILABLE && !pEnumItem )
2002 eState = SFX_ITEM_DONTCARE;
2003 else
2004 eState = SfxControllerItem::GetItemState( pEnumItem );
2006 // "uber alle Slaves-Slots iterieren
2007 for ( const SfxSlot *pSlave = pFirstSlave; pSlave; pSlave = pSlave->GetNextSlot() )
2009 DBG_ASSERT(pSlave, "Falsche SlaveSlot-Verkettung!");
2010 DBG_ASSERT(SFX_KIND_ENUM == pSlave->GetKind(),"non enum slaves aren't allowed");
2011 DBG_ASSERT(pSlave->GetMasterSlotId() == pSlot->GetSlotId(),"falscher MasterSlot!");
2013 // ist die Funktion gebunden?
2014 SfxStateCache *pEnumCache = GetStateCache( pSlave->GetSlotId() );
2015 if ( pEnumCache )
2017 pEnumCache->Invalidate(sal_False);
2019 HACK(CONTROL/SELECT Kram)
2020 if ( eState == SFX_ITEM_DONTCARE && pFound->nWhichId == 10144 )
2022 SfxVoidItem aVoid(0);
2023 pEnumCache->SetState( SFX_ITEM_UNKNOWN, &aVoid );
2025 if (pSlave->GetNextSlot() == pFirstSlave)
2026 break;
2028 continue;
2031 if ( SFX_ITEM_DISABLED == eState || !pEnumItem->IsEnabled( pSlave->GetSlotId()) )
2033 // disabled
2034 pEnumCache->SetState(SFX_ITEM_DISABLED, 0);
2036 else if ( SFX_ITEM_AVAILABLE == eState )
2038 // enum-Wert ermitteln
2039 sal_uInt16 nValue = pEnumItem->GetEnumValue();
2040 SfxBoolItem aBool( pFound->nWhichId, pSlave->GetValue() == nValue );
2041 pEnumCache->SetState(SFX_ITEM_AVAILABLE, &aBool);
2043 else
2045 // uneindeuting
2046 pEnumCache->SetState( SFX_ITEM_DONTCARE, (SfxPoolItem *)-1 );
2050 if (pSlave->GetNextSlot() == pFirstSlave)
2051 break;
2055 DBG_PROFSTOP(SfxBindingsUpdateCtrl2);
2059 //--------------------------------------------------------------------
2061 IMPL_LINK( SfxBindings, NextJob_Impl, Timer *, pTimer )
2063 /* [Beschreibung]
2065 Die SfxController werden "uber einen Timer updated. Dieses ist der
2066 dazugeh"orige interne TimeOut-Handler.
2070 #ifdef DBG_UTIL
2071 // on Windows very often C++ Exceptions (GPF etc.) are caught by MSVCRT or another MS library
2072 // try to get them here
2075 #endif
2076 const unsigned MAX_INPUT_DELAY = 200;
2078 DBG_MEMTEST();
2079 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
2081 DBG_PROFSTART(SfxBindingsNextJob_Impl0);
2083 if ( Application::GetLastInputInterval() < MAX_INPUT_DELAY && pTimer )
2085 pImp->aTimer.SetTimeout(TIMEOUT_UPDATING);
2086 return sal_True;
2089 SfxApplication *pSfxApp = SFX_APP();
2091 if( pDispatcher )
2092 pDispatcher->Update_Impl();
2094 // modifying the SfxObjectInterface-stack without SfxBindings => nothing to do
2095 SfxViewFrame* pFrame = pDispatcher->GetFrame();
2096 if ( (pFrame && pFrame->GetObjectShell()->IsInModalMode()) || pSfxApp->IsDowning() || !pImp->pCaches->Count() )
2098 DBG_PROFSTOP(SfxBindingsNextJob_Impl0);
2099 return sal_True;
2101 if ( !pDispatcher || !pDispatcher->IsFlushed() )
2103 DBG_PROFSTOP(SfxBindingsNextJob_Impl0);
2104 return sal_True;
2107 // gfs. alle Server aktualisieren / geschieht in eigener Zeitscheibe
2108 if ( pImp->bMsgDirty )
2110 UpdateSlotServer_Impl();
2111 DBG_PROFSTOP(SfxBindingsNextJob_Impl0);
2112 return sal_False;
2115 DBG_PROFSTOP(SfxBindingsNextJob_Impl0);
2116 DBG_PROFSTART(SfxBindingsNextJob_Impl);
2117 pImp->bAllDirty = sal_False;
2118 pImp->aTimer.SetTimeout(TIMEOUT_UPDATING);
2120 // at least 10 loops and further if more jobs are available but no input
2121 FASTBOOL bPreEmptive = pTimer && !pSfxApp->Get_Impl()->nInReschedule;
2122 sal_uInt16 nLoops = 10;
2123 pImp->bInNextJob = sal_True;
2124 const sal_uInt16 nCount = pImp->pCaches->Count();
2125 while ( pImp->nMsgPos < nCount )
2127 // iterate through the bound functions
2128 sal_Bool bJobDone = sal_False;
2129 while ( !bJobDone )
2131 SfxStateCache* pCache = (*pImp->pCaches)[pImp->nMsgPos];
2132 DBG_ASSERT( pCache, "invalid SfxStateCache-position in job queue" );
2133 sal_Bool bWasDirty = pCache->IsControllerDirty();
2134 if ( bWasDirty )
2137 sal_Bool bSkip = sal_False;
2138 if ( pImp->bFirstRound )
2140 // Falls beim Update eine Shell vorgezogen werden soll,
2141 // kommt in einer ersten Update-Runde nur diese dran
2142 const SfxSlotServer *pMsgServer =
2143 pCache->GetSlotServer(*pDispatcher, pImp->xProv);
2144 if ( pMsgServer &&
2145 pMsgServer->GetShellLevel() != pImp->nFirstShell )
2146 bSkip = sal_True;
2149 if ( !bSkip )
2152 Update_Impl( pCache );
2153 DBG_ASSERT( nCount == pImp->pCaches->Count(),
2154 "Reschedule in StateChanged => buff" );
2155 // }
2158 // skip to next function binding
2159 ++pImp->nMsgPos;
2161 // keep job if it is not completed, but any input is available
2162 bJobDone = pImp->nMsgPos >= nCount;
2163 if ( bJobDone && pImp->bFirstRound )
2165 // Update der bevorzugten Shell ist gelaufen, nun d"urfen
2166 // auch die anderen
2167 bJobDone = sal_False;
2168 pImp->bFirstRound = sal_False;
2169 pImp->nMsgPos = 0;
2172 if ( bWasDirty && !bJobDone && bPreEmptive && (--nLoops == 0) )
2174 DBG_PROFSTOP(SfxBindingsNextJob_Impl);
2175 pImp->bInNextJob = sal_False;
2176 return sal_False;
2181 // volatiles wieder von vorne starten
2182 pImp->nMsgPos = 0;
2183 pImp->aTimer.SetTimeout(TIMEOUT_IDLE);
2184 for ( sal_uInt16 n = 0; n < nCount; ++n )
2186 SfxStateCache* pCache = (*pImp->pCaches)[n];
2187 const SfxSlotServer *pSlotServer = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
2188 if ( pSlotServer &&
2189 pSlotServer->GetSlot()->IsMode(SFX_SLOT_VOLATILE) )
2190 pCache->Invalidate(sal_False);
2193 // Update-Runde ist beendet
2194 pImp->bInNextJob = sal_False;
2195 Broadcast(SfxSimpleHint(SFX_HINT_UPDATEDONE));
2196 DBG_PROFSTOP(SfxBindingsNextJob_Impl);
2197 return sal_True;
2198 #ifdef DBG_UTIL
2200 catch (...)
2202 DBG_ERROR("C++ exception caught!");
2203 pImp->bInNextJob = sal_False;
2206 return sal_False;
2207 #endif
2210 //--------------------------------------------------------------------
2212 sal_uInt16 SfxBindings::EnterRegistrations(const char *pFile, int nLine)
2214 /* [Beschreibung]
2216 Die An- oder Abmeldung von <SfxControllerItem> Instanzen mu"s in
2217 EnterRegistrations() und LeaveRegistrations() geklammert werden.
2218 W"ahrend dieser Zeit erfolgen keine Udates der <SfxContollerItem>
2219 Instanzen (weder der alten noch der neu angemeldeten).
2221 [Parameter]
2223 pFile, nLine Dateiname und Zeilennummer der rufenden
2224 Methode (nur Debug)
2226 [R"uckgabewert]
2228 sal_uInt16 Level der Registrierung. Dieser kann in
2229 <SfxBindings::LeaveRegistrations(sal_uInt16)> als
2230 Parameter angegeben werden, um die Paarigkeit
2231 der EnterRegistrations() und LeaveRegistrations()
2232 zu pr"ufen.
2235 [Querverweise]
2236 <SfxBindings::IsInRegistrations()>
2237 <SfxBindings::Register(SfxControllerItem&)>
2238 <SfxBindings::Release(SfxControllerItem&)>
2239 <SfxBindings::LeaveRegistrations()>
2243 (void)pFile;
2244 (void)nLine;
2245 DBG_MEMTEST();
2246 #ifdef DBG_UTIL
2247 ByteString aMsg;
2248 aMsg.Fill( Min(nRegLevel, sal_uInt16(8) ) );
2249 aMsg += "this = ";
2250 aMsg += ByteString::CreateFromInt32((long)this);
2251 aMsg += " Level = ";
2252 aMsg += ByteString::CreateFromInt32(nRegLevel);
2253 aMsg += " SfxBindings::EnterRegistrations ";
2254 if(pFile) {
2255 aMsg += "File: ";
2256 aMsg += pFile;
2257 aMsg += " Line: ";
2258 aMsg += ByteString::CreateFromInt32(nLine);
2260 // FILE* pLog = fopen( "c:\\bindings.log", "a+w" );
2261 // fwrite( aMsg.GetBuffer(), 1, aMsg.Len(), pLog );
2262 // fclose( pLog );
2263 DbgTrace( aMsg.GetBuffer() );
2264 #endif
2266 // Wenn Bindings gelockt werden, auch SubBindings locken
2267 if ( pImp->pSubBindings )
2269 pImp->pSubBindings->ENTERREGISTRATIONS();
2271 // Dieses EnterRegistrations ist f"ur die SubBindings kein "echtes"
2272 pImp->pSubBindings->pImp->nOwnRegLevel--;
2274 // Bindings synchronisieren
2275 pImp->pSubBindings->nRegLevel = nRegLevel + pImp->pSubBindings->pImp->nOwnRegLevel + 1;
2278 pImp->nOwnRegLevel++;
2280 // check if this is the outer most level
2281 if ( ++nRegLevel == 1 )
2283 // stop background-processing
2284 pImp->aTimer.Stop();
2286 // flush the cache
2287 pImp->nCachedFunc1 = 0;
2288 pImp->nCachedFunc2 = 0;
2290 // merken, ob ganze Caches verschwunden sind
2291 pImp->bCtrlReleased = sal_False;
2294 return nRegLevel;
2296 //--------------------------------------------------------------------
2298 void SfxBindings::LeaveRegistrations( sal_uInt16 nLevel, const char *pFile, int nLine )
2300 /* [Beschreibung]
2302 Die An- oder Abmeldung von <SfxControllerItem> Instanzen mu"s in
2303 EnterRegistrations() und LeaveRegistrations() geklammert werden.
2304 W"ahrend dieser Zeit erfolgen keine Udates der <SfxContollerItem>
2305 Instanzen (weder der alten noch der neu angemeldeten).
2308 [Parameter]
2310 sal_uInt16 nLevel == USRT_MAX
2311 keine Paarigkeits-Pr"ufung f"ur diese Klammerung
2314 pFile, nLine Dateiname und Zeilennummer der rufenden
2315 Methode (nur Debug)
2317 < USHRT_MAX
2318 R"uckgabewert des zugeh"origen EnterRegistrations()
2319 zum pr"ufen der Paarigkeit.
2322 [Querverweise]
2323 <SfxBindings::IsInRegistrations()>
2324 <SfxBindings::Register(SfxControllerItem&)>
2325 <SfxBindings::Release(SfxControllerItem&)>
2326 <SfxBindings::EnterRegistrations()>
2330 (void)nLevel; // unused variable
2331 (void)pFile;
2332 (void)nLine;
2333 DBG_MEMTEST();
2334 DBG_ASSERT( nRegLevel, "Leave without Enter" );
2335 DBG_ASSERT( nLevel == USHRT_MAX || nLevel == nRegLevel, "wrong Leave" );
2337 // Nur wenn die SubBindings noch von den SuperBindings gelockt sind, diesen Lock entfernen
2338 // ( d.h. wenn es mehr Locks als "echte" Locks dort gibt )
2339 if ( pImp->pSubBindings && pImp->pSubBindings->nRegLevel > pImp->pSubBindings->pImp->nOwnRegLevel )
2341 // Bindings synchronisieren
2342 pImp->pSubBindings->nRegLevel = nRegLevel + pImp->pSubBindings->pImp->nOwnRegLevel;
2344 // Dieses LeaveRegistrations ist f"ur die SubBindings kein "echtes"
2345 pImp->pSubBindings->pImp->nOwnRegLevel++;
2346 pImp->pSubBindings->LEAVEREGISTRATIONS();
2349 pImp->nOwnRegLevel--;
2351 // check if this is the outer most level
2352 if ( --nRegLevel == 0 && !SFX_APP()->IsDowning() )
2354 if ( pImp->bContextChanged )
2356 pImp->bContextChanged = FALSE;
2358 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame
2359 ( pDispatcher->GetFrame()->GetFrame()->GetFrameInterface(), UNO_QUERY );
2360 if ( xFrame.is() )
2361 xFrame->contextChanged();*/
2364 #ifndef slow
2365 SfxViewFrame* pFrame = pDispatcher->GetFrame();
2367 // ggf unbenutzte Caches entfernen bzw. PlugInInfo aufbereiten
2368 if ( pImp->bCtrlReleased )
2370 for ( sal_uInt16 nCache = pImp->pCaches->Count(); nCache > 0; --nCache )
2372 // Cache via ::com::sun::star::sdbcx::Index besorgen
2373 SfxStateCache *pCache = pImp->pCaches->GetObject(nCache-1);
2375 // kein Controller mehr interessiert
2376 if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() )
2378 // Cache entfernen. Safety: first remove and then delete
2379 SfxStateCache* pSfxStateCache = (*pImp->pCaches)[nCache-1];
2380 pImp->pCaches->Remove(nCache-1, 1);
2381 delete pSfxStateCache;
2383 else
2385 // neue Controller mit den alten Items benachrichtigen
2386 //!pCache->SetCachedState();
2390 #endif
2391 // restart background-processing
2392 pImp->nMsgPos = 0;
2393 if ( !pFrame || !pFrame->GetObjectShell() )
2394 return;
2395 if ( pImp->pCaches && pImp->pCaches->Count() )
2397 pImp->aTimer.Stop();
2398 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
2399 pImp->aTimer.Start();
2400 // pImp->bFirstRound = sal_True;
2404 #ifdef DBG_UTIL
2405 ByteString aMsg;
2406 aMsg.Fill( Min(nRegLevel, sal_uInt16(8)) );
2407 aMsg += "this = ";
2408 aMsg += ByteString::CreateFromInt32((long)this);
2409 aMsg += " Level = ";
2410 aMsg += ByteString::CreateFromInt32(nRegLevel);
2411 aMsg += " SfxBindings::LeaveRegistrations ";
2412 if(pFile) {
2413 aMsg += "File: ";
2414 aMsg += pFile;
2415 aMsg += " Line: ";
2416 aMsg += ByteString::CreateFromInt32(nLine);
2418 // FILE* pLog = fopen( "c:\\bindings.log", "a+w" );
2419 // fwrite( aMsg.GetBuffer(), 1, aMsg.Len(), pLog );
2420 // fclose( pLog );
2421 DbgTrace( aMsg.GetBuffer() );
2422 #endif
2425 //--------------------------------------------------------------------
2427 const SfxSlot* SfxBindings::GetSlot(sal_uInt16 nSlotId)
2429 /* [Beschreibung]
2431 Diese Methode liefert einen Pointer auf den zur Zeit gecacheten
2432 SfxSlot f"ur die angegebene Slot-Id.
2435 [R"uckgabewert]
2437 const <SfxSlot>* 0
2438 Falls die Slot-Id nicht gebunden ist oder
2439 ein solcher Slot momentan in keiner aktiven
2440 <SfxShell> vorhanden ist.
2442 != 0
2443 Falls die Slot-Id gebunden ist und ein solcher
2444 Slot momentan in einer aktiven <SfxShell>
2445 vorhanden ist.
2449 DBG_MEMTEST();
2450 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
2452 // syncronisieren
2453 pDispatcher->Flush();
2454 if ( pImp->bMsgDirty )
2455 UpdateSlotServer_Impl();
2457 // get the cache for the specified function; return if not bound
2458 SfxStateCache* pCache = GetStateCache(nSlotId);
2459 return pCache && pCache->GetSlotServer(*pDispatcher, pImp->xProv)?
2460 pCache->GetSlotServer(*pDispatcher, pImp->xProv)->GetSlot(): 0;
2463 //--------------------------------------------------------------------
2465 void SfxBindings::SetDispatcher( SfxDispatcher *pDisp )
2467 /* [Beschreibung]
2469 Setzt den zur Zeit von dieser SfxBindings Instanz zu verwendenden
2470 Dispatcher um.
2472 Falls sich der Dispatcher dadurch "andert, wird intern
2473 <SFxBindings::InvalidateAll(sal_Bool)> mit sal_True gerufen, also jegliche
2474 gecachete Information der Bindings weggeworfen.
2478 SfxDispatcher *pOldDispat = pDispatcher;
2479 if ( pDisp != pDispatcher )
2481 if ( pOldDispat )
2483 SfxBindings* pBind = pOldDispat->GetBindings();
2484 while ( pBind )
2486 if ( pBind->pImp->pSubBindings == this && pBind->pDispatcher != pDisp )
2487 pBind->SetSubBindings_Impl( NULL );
2488 pBind = pBind->pImp->pSubBindings;
2492 pDispatcher = pDisp;
2494 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider > xProv;
2495 if ( pDisp )
2496 xProv = ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider >
2497 ( pDisp->GetFrame()->GetFrame()->GetFrameInterface(), UNO_QUERY );
2499 SetDispatchProvider_Impl( xProv );
2500 InvalidateAll( sal_True );
2501 InvalidateUnoControllers_Impl();
2503 if ( pDispatcher && !pOldDispat )
2505 if ( pImp->pSubBindings && pImp->pSubBindings->pDispatcher != pOldDispat )
2507 DBG_ERROR( "SubBindings vor Aktivieren schon gesetzt!" );
2508 pImp->pSubBindings->ENTERREGISTRATIONS();
2510 LEAVEREGISTRATIONS();
2512 else if( !pDispatcher )
2514 ENTERREGISTRATIONS();
2515 if ( pImp->pSubBindings && pImp->pSubBindings->pDispatcher != pOldDispat )
2517 DBG_ERROR( "SubBindings im Deaktivieren immer noch gesetzt!" );
2518 pImp->pSubBindings->LEAVEREGISTRATIONS();
2522 Broadcast( SfxSimpleHint( SFX_HINT_DATACHANGED ) );
2524 if ( pDisp )
2526 SfxBindings* pBind = pDisp->GetBindings();
2527 while ( pBind && pBind != this )
2529 if ( !pBind->pImp->pSubBindings )
2531 pBind->SetSubBindings_Impl( this );
2532 break;
2535 pBind = pBind->pImp->pSubBindings;
2541 //--------------------------------------------------------------------
2543 void SfxBindings::ClearCache_Impl( sal_uInt16 nSlotId )
2545 // interne Methode zum forwarden dieses Methodenaufrufs
2548 GetStateCache(nSlotId)->ClearCache();
2551 //--------------------------------------------------------------------
2553 // interne Methode zum Ansto\sen des Statusupdates
2555 void SfxBindings::StartUpdate_Impl( sal_Bool bComplete )
2557 if ( pImp->pSubBindings )
2558 pImp->pSubBindings->StartUpdate_Impl( bComplete );
2560 if ( !bComplete )
2561 // Update darf unterbrochen werden
2562 NextJob_Impl(&pImp->aTimer);
2563 else
2564 // alle Slots am St"uck updaten
2565 NextJob_Impl(0);
2568 //-------------------------------------------------------------------------
2570 SfxItemState SfxBindings::QueryState( sal_uInt16 nSlot, SfxPoolItem* &rpState )
2571 /* [Beschreibung]
2573 Wird gerufen, um den Status f"ur 'nSlot' zu erfragen. Wenn der return
2574 value SFX_ITEM_SET ist, wird ein SfxPoolItem zur"uckgegeben, indem der
2575 rpState entsprechend gesetzt wird. Es findet dabei ein Eigent"umer"ubergang
2576 statt, d.h. die aufrufende Methode mu\s das Item l"oschen.
2578 Anmerkung: diese Methode ist sehr teuer und sollte nur gerufen werden,
2579 wenn kein Controller f"ur das Erfragen des Status angelegt werden kann oder
2580 der Status unbedingt sofort geliefert werden mu\s.
2584 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
2585 SfxStateCache *pCache = GetStateCache( nSlot );
2586 if ( pCache )
2587 xDisp = pCache->GetDispatch();
2588 if ( xDisp.is() || !pCache )
2590 const SfxSlot* pSlot = SfxSlotPool::GetSlotPool( pDispatcher->GetFrame() ).GetSlot( nSlot );
2591 if ( !pSlot || !pSlot->pUnoName )
2592 return SFX_ITEM_DISABLED;
2594 ::com::sun::star::util::URL aURL;
2595 ::rtl::OUString aCmd( DEFINE_CONST_UNICODE(".uno:"));
2596 aURL.Protocol = aCmd;
2597 aURL.Path = ::rtl::OUString::createFromAscii(pSlot->GetUnoName());
2598 aCmd += aURL.Path;
2599 aURL.Complete = aCmd;
2600 aURL.Main = aCmd;
2602 if ( !xDisp.is() )
2603 xDisp = pImp->xProv->queryDispatch( aURL, ::rtl::OUString(), 0 );
2605 if ( xDisp.is() )
2607 ::com::sun::star::uno::Reference< ::com::sun::star::lang::XUnoTunnel > xTunnel( xDisp, ::com::sun::star::uno::UNO_QUERY );
2608 SfxOfficeDispatch* pDisp = NULL;
2609 if ( xTunnel.is() )
2611 sal_Int64 nImplementation = xTunnel->getSomething(SfxOfficeDispatch::impl_getStaticIdentifier());
2612 pDisp = reinterpret_cast< SfxOfficeDispatch* >( sal::static_int_cast< sal_IntPtr >( nImplementation ));
2615 if ( !pDisp )
2617 BOOL bDeleteCache = FALSE;
2618 if ( !pCache )
2620 pCache = new SfxStateCache( nSlot );
2621 pCache->GetSlotServer( *GetDispatcher_Impl(), pImp->xProv );
2622 bDeleteCache = TRUE;
2625 SfxItemState eState = SFX_ITEM_SET;
2626 SfxPoolItem *pItem=NULL;
2627 BindDispatch_Impl *pBind = new BindDispatch_Impl( xDisp, aURL, pCache, pSlot );
2628 pBind->acquire();
2629 xDisp->addStatusListener( pBind, aURL );
2630 if ( !pBind->GetStatus().IsEnabled )
2632 eState = SFX_ITEM_DISABLED;
2634 else
2636 ::com::sun::star::uno::Any aAny = pBind->GetStatus().State;
2637 ::com::sun::star::uno::Type pType = aAny.getValueType();
2639 if ( pType == ::getBooleanCppuType() )
2641 sal_Bool bTemp = false;
2642 aAny >>= bTemp ;
2643 pItem = new SfxBoolItem( nSlot, bTemp );
2645 else if ( pType == ::getCppuType((const sal_uInt16*)0) )
2647 sal_uInt16 nTemp = 0;
2648 aAny >>= nTemp ;
2649 pItem = new SfxUInt16Item( nSlot, nTemp );
2651 else if ( pType == ::getCppuType((const sal_uInt32*)0) )
2653 sal_uInt32 nTemp = 0;
2654 aAny >>= nTemp ;
2655 pItem = new SfxUInt32Item( nSlot, nTemp );
2657 else if ( pType == ::getCppuType((const ::rtl::OUString*)0) )
2659 ::rtl::OUString sTemp ;
2660 aAny >>= sTemp ;
2661 pItem = new SfxStringItem( nSlot, sTemp );
2663 else
2664 pItem = new SfxVoidItem( nSlot );
2667 xDisp->removeStatusListener( pBind, aURL );
2668 pBind->Release();
2669 rpState = pItem;
2670 if ( bDeleteCache )
2671 DELETEZ( pCache );
2672 return eState;
2677 // Dann am Dispatcher testen; da die von dort zur"uckgegebenen Items immer
2678 // DELETE_ON_IDLE sind, mu\s eine Kopie davon gezogen werden, um einen
2679 // Eigent"umer"ubergang zu erm"oglichen
2680 const SfxPoolItem *pItem = NULL;
2681 SfxItemState eState = pDispatcher->QueryState( nSlot, pItem );
2682 if ( eState == SFX_ITEM_SET )
2684 DBG_ASSERT( pItem, "SFX_ITEM_SET aber kein Item!" );
2685 if ( pItem )
2686 rpState = pItem->Clone();
2688 else if ( eState == SFX_ITEM_AVAILABLE && pItem )
2690 rpState = pItem->Clone();
2693 return eState;
2696 void SfxBindings::SetSubBindings_Impl( SfxBindings *pSub )
2698 if ( pImp->pSubBindings )
2700 pImp->pSubBindings->SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > () );
2701 pImp->pSubBindings->pImp->pSuperBindings = NULL;
2704 pImp->pSubBindings = pSub;
2706 if ( pSub )
2708 pImp->pSubBindings->SetDispatchProvider_Impl( pImp->xProv );
2709 pSub->pImp->pSuperBindings = this;
2713 SfxBindings* SfxBindings::GetSubBindings_Impl( sal_Bool bTop ) const
2715 SfxBindings *pRet = pImp->pSubBindings;
2716 if ( bTop )
2718 while ( pRet->pImp->pSubBindings )
2719 pRet = pRet->pImp->pSubBindings;
2722 return pRet;
2725 void SfxBindings::SetWorkWindow_Impl( SfxWorkWindow* pWork )
2727 pImp->pWorkWin = pWork;
2730 SfxWorkWindow* SfxBindings::GetWorkWindow_Impl() const
2732 return pImp->pWorkWin;
2735 void SfxBindings::RegisterUnoController_Impl( SfxUnoControllerItem* pControl )
2737 if ( !pImp->pUnoCtrlArr )
2738 pImp->pUnoCtrlArr = new SfxUnoControllerArr_Impl;
2739 pImp->pUnoCtrlArr->Insert( pControl, pImp->pUnoCtrlArr->Count() );
2742 void SfxBindings::ReleaseUnoController_Impl( SfxUnoControllerItem* pControl )
2744 if ( pImp->pUnoCtrlArr )
2746 sal_uInt16 nPos = pImp->pUnoCtrlArr->GetPos( pControl );
2747 if ( nPos != 0xFFFF )
2749 pImp->pUnoCtrlArr->Remove( nPos );
2750 return;
2754 if ( pImp->pSubBindings )
2755 pImp->pSubBindings->ReleaseUnoController_Impl( pControl );
2758 void SfxBindings::InvalidateUnoControllers_Impl()
2760 if ( pImp->pUnoCtrlArr )
2762 sal_uInt16 nCount = pImp->pUnoCtrlArr->Count();
2763 for ( sal_uInt16 n=nCount; n>0; n-- )
2765 SfxUnoControllerItem *pCtrl = (*pImp->pUnoCtrlArr)[n-1];
2766 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > xRef( (::cppu::OWeakObject*)pCtrl, ::com::sun::star::uno::UNO_QUERY );
2767 pCtrl->ReleaseDispatch();
2768 pCtrl->GetNewDispatch();
2772 if ( pImp->pSubBindings )
2773 pImp->pSubBindings->InvalidateUnoControllers_Impl();
2776 sal_Bool SfxBindings::IsInUpdate() const
2778 sal_Bool bInUpdate = pImp->bInUpdate;
2779 if ( !bInUpdate && pImp->pSubBindings )
2780 bInUpdate = pImp->pSubBindings->IsInUpdate();
2781 return bInUpdate;
2784 void SfxBindings::SetVisibleState( sal_uInt16 nId, sal_Bool bShow )
2786 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
2787 SfxStateCache *pCache = GetStateCache( nId );
2788 if ( pCache )
2789 pCache->SetVisibleState( bShow );
2792 void SfxBindings::SetActiveFrame( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > & rFrame )
2794 if ( rFrame.is() || !pDispatcher )
2795 SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > ( rFrame, ::com::sun::star::uno::UNO_QUERY ) );
2796 else
2797 SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > (
2798 pDispatcher->GetFrame()->GetFrame()->GetFrameInterface(), ::com::sun::star::uno::UNO_QUERY ) );
2801 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > SfxBindings::GetActiveFrame() const
2803 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame( pImp->xProv, ::com::sun::star::uno::UNO_QUERY );
2804 if ( xFrame.is() || !pDispatcher )
2805 return xFrame;
2806 else
2807 return pDispatcher->GetFrame()->GetFrame()->GetFrameInterface();
2810 void SfxBindings::SetDispatchProvider_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & rProv )
2812 sal_Bool bInvalidate = ( rProv != pImp->xProv );
2813 if ( bInvalidate )
2815 pImp->xProv = rProv;
2816 InvalidateAll( sal_True );
2817 InvalidateUnoControllers_Impl();
2820 if ( pImp->pSubBindings )
2821 pImp->pSubBindings->SetDispatchProvider_Impl( pImp->xProv );
2824 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & SfxBindings::GetDispatchProvider_Impl() const
2826 return pImp->xProv;
2829 SystemWindow* SfxBindings::GetSystemWindow() const
2831 SfxViewFrame *pFrame = pDispatcher->GetFrame();
2832 while ( pFrame->GetParentViewFrame_Impl() )
2833 pFrame = pFrame->GetParentViewFrame_Impl();
2834 SfxTopViewFrame* pTop = PTR_CAST( SfxTopViewFrame, pFrame->GetTopViewFrame() );
2835 return pTop->GetTopFrame_Impl()->GetTopWindow_Impl();
2838 BOOL SfxBindings::ExecuteCommand_Impl( const String& rCommand )
2840 ::com::sun::star::util::URL aURL;
2841 aURL.Complete = rCommand;
2842 Reference < XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance( rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY );
2843 xTrans->parseStrict( aURL );
2844 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp = pImp->xProv->queryDispatch( aURL, ::rtl::OUString(), 0 );
2845 if ( xDisp.is() )
2847 if(::comphelper::UiEventsLogger::isEnabled()) //#i88653#
2849 ::rtl::OUString sAppName;
2852 static ::rtl::OUString our_aModuleManagerName = ::rtl::OUString::createFromAscii("com.sun.star.frame.ModuleManager");
2853 ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceManager =
2854 ::comphelper::getProcessServiceFactory();
2855 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModuleManager > xModuleManager(
2856 xServiceManager->createInstance(our_aModuleManagerName)
2857 , ::com::sun::star::uno::UNO_QUERY_THROW);
2858 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame(
2859 pDispatcher->GetFrame()->GetFrame()->GetFrameInterface(), UNO_QUERY_THROW);
2860 sAppName = xModuleManager->identify(xFrame);
2861 } catch(::com::sun::star::uno::Exception&) {}
2862 Sequence<beans::PropertyValue> source;
2863 ::comphelper::UiEventsLogger::appendDispatchOrigin(source, sAppName, ::rtl::OUString::createFromAscii("SfxAsyncExec"));
2864 ::comphelper::UiEventsLogger::logDispatch(aURL, source);
2866 new SfxAsyncExec_Impl( aURL, xDisp );
2867 return TRUE;
2870 return FALSE;
2873 //REMOVE SfxConfigManager* SfxBindings::GetConfigManager( USHORT nType ) const
2875 //REMOVE SfxConfigManager *pMgr = pDispatcher->GetFrame()->GetObjectShell()->GetConfigManager();
2876 //REMOVE if ( pMgr && pMgr->HasConfigItem( nType ) )
2877 //REMOVE return pMgr;
2878 //REMOVE else
2879 // return SFX_APP()->GetConfigManager_Impl();
2882 com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder > SfxBindings::GetRecorder() const
2884 return pImp->xRecorder;
2887 void SfxBindings::SetRecorder_Impl( com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder >& rRecorder )
2889 pImp->xRecorder = rRecorder;
2892 void SfxBindings::ContextChanged_Impl()
2894 if ( !pImp->bInUpdate && ( !pImp->bContextChanged || !pImp->bAllMsgDirty ) )
2896 InvalidateAll( TRUE );
2900 uno::Reference < frame::XDispatch > SfxBindings::GetDispatch( const SfxSlot* pSlot, const util::URL& aURL, sal_Bool bMasterCommand )
2902 uno::Reference < frame::XDispatch > xRet;
2903 SfxStateCache* pCache = GetStateCache( pSlot->nSlotId );
2904 if ( pCache && !bMasterCommand )
2905 xRet = pCache->GetInternalDispatch();
2906 if ( !xRet.is() )
2908 // dispatches for slaves are unbound, they don't have a state
2909 SfxOfficeDispatch* pDispatch = bMasterCommand ?
2910 new SfxOfficeDispatch( pDispatcher, pSlot, aURL ) :
2911 new SfxOfficeDispatch( *this, pDispatcher, pSlot, aURL );
2913 pDispatch->SetMasterUnoCommand( bMasterCommand );
2914 xRet = uno::Reference < frame::XDispatch >( pDispatch );
2915 if ( !pCache )
2916 pCache = GetStateCache( pSlot->nSlotId );
2918 DBG_ASSERT( pCache, "No cache for OfficeDispatch!" );
2919 if ( pCache && !bMasterCommand )
2920 pCache->SetInternalDispatch( xRet );
2923 return xRet;