bump product version to 5.0.4.1
[LibreOffice.git] / sfx2 / source / control / bindings.cxx
blobcf4c8a875dde2f04956292821f6cfeed06f3e3ca
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <iomanip>
24 #include <sal/log.hxx>
25 #include <svl/itempool.hxx>
26 #include <svl/itemiter.hxx>
27 #include <svl/eitem.hxx>
28 #include <svl/aeitem.hxx>
29 #include <svl/intitem.hxx>
30 #include <svl/stritem.hxx>
31 #include <svl/visitem.hxx>
32 #include <com/sun/star/util/URLTransformer.hpp>
33 #include <com/sun/star/util/XURLTransformer.hpp>
34 #include <com/sun/star/frame/XDispatchProviderInterceptor.hpp>
35 #include <com/sun/star/frame/XDispatch.hpp>
36 #include <com/sun/star/frame/XDispatchProvider.hpp>
37 #include <com/sun/star/frame/XStatusListener.hpp>
38 #include <com/sun/star/frame/FrameSearchFlag.hpp>
39 #include <com/sun/star/frame/XDispatchProviderInterception.hpp>
40 #include <com/sun/star/frame/FeatureStateEvent.hpp>
41 #include <com/sun/star/frame/DispatchDescriptor.hpp>
42 #include <com/sun/star/frame/XController.hpp>
43 #include <comphelper/processfactory.hxx>
44 #include "itemdel.hxx"
46 //Includes below due to nInReschedule
47 #include "appdata.hxx"
48 #include <sfx2/bindings.hxx>
49 #include <sfx2/msg.hxx>
50 #include "statcach.hxx"
51 #include <sfx2/ctrlitem.hxx>
52 #include <sfx2/app.hxx>
53 #include <sfx2/dispatch.hxx>
54 #include <sfx2/request.hxx>
55 #include <sfx2/objface.hxx>
56 #include "sfxtypes.hxx"
57 #include "workwin.hxx"
58 #include <sfx2/unoctitm.hxx>
59 #include <sfx2/sfx.hrc>
60 #include <sfx2/sfxuno.hxx>
61 #include <sfx2/viewfrm.hxx>
62 #include <sfx2/objsh.hxx>
63 #include <sfx2/msgpool.hxx>
65 #include <com/sun/star/frame/XModuleManager.hpp>
66 #include <boost/scoped_array.hpp>
67 #include <boost/scoped_ptr.hpp>
68 #include <boost/ptr_container/ptr_vector.hpp>
69 #include <unordered_map>
71 using namespace ::com::sun::star;
72 using namespace ::com::sun::star::uno;
73 using namespace ::com::sun::star::util;
75 static sal_uInt16 nTimeOut = 300;
77 #define TIMEOUT_FIRST nTimeOut
78 #define TIMEOUT_UPDATING 20
79 #define TIMEOUT_IDLE 2500
81 typedef std::unordered_map< sal_uInt16, bool > InvalidateSlotMap;
85 typedef std::vector<SfxStateCache*> SfxStateCacheArr_Impl;
87 struct SfxFoundCache_Impl
89 sal_uInt16 nSlotId; // the Slot-Id
90 sal_uInt16 nWhichId; // If available: Which-Id, else: nSlotId
91 const SfxSlot* pSlot; // Pointer to <Master-Slot>
92 SfxStateCache* pCache; // Pointer to StatusCache, if possible NULL
94 SfxFoundCache_Impl(sal_uInt16 nS, sal_uInt16 nW, const SfxSlot *pS, SfxStateCache *pC ):
95 nSlotId(nS),
96 nWhichId(nW),
97 pSlot(pS),
98 pCache(pC)
102 class SfxFoundCacheArr_Impl
104 typedef boost::ptr_vector<SfxFoundCache_Impl> DataType;
105 DataType maData;
107 public:
109 SfxFoundCache_Impl& operator[] ( size_t i )
111 return maData[i];
114 size_t size() const
116 return maData.size();
119 void push_back( SfxFoundCache_Impl* p )
121 maData.push_back(p);
125 class SfxUnoControllerArr_Impl
127 typedef std::vector<SfxUnoControllerItem*> DataType;
128 DataType maData;
130 public:
132 typedef DataType::iterator iterator;
134 iterator begin()
136 return maData.begin();
139 iterator end()
141 return maData.end();
144 void erase( iterator it )
146 maData.erase(it);
149 SfxUnoControllerItem* operator[] ( size_t i )
151 return maData[i];
154 size_t size() const
156 return maData.size();
159 void push_back( SfxUnoControllerItem* p )
161 maData.push_back(p);
165 class SfxAsyncExec_Impl
167 ::com::sun::star::util::URL aCommand;
168 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
169 Timer aTimer;
171 public:
173 SfxAsyncExec_Impl( const ::com::sun::star::util::URL& rCmd, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch >& rDisp )
174 : aCommand( rCmd )
175 , xDisp( rDisp )
177 aTimer.SetTimeoutHdl( LINK(this, SfxAsyncExec_Impl, TimerHdl) );
178 aTimer.SetTimeout( 0 );
179 aTimer.Start();
182 DECL_LINK_TYPED( TimerHdl, Timer*, void);
185 IMPL_LINK_TYPED(SfxAsyncExec_Impl, TimerHdl, Timer*, pTimer, void)
187 (void)pTimer; // unused
188 aTimer.Stop();
190 Sequence<beans::PropertyValue> aSeq;
191 xDisp->dispatch( aCommand, aSeq );
193 delete this;
196 enum class SfxPopupAction
198 DELETE,
199 HIDE,
200 SHOW
204 class SfxBindings_Impl
206 public:
207 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchRecorder > xRecorder;
208 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv;
209 SfxUnoControllerArr_Impl*
210 pUnoCtrlArr;
211 SfxWorkWindow* pWorkWin;
212 SfxBindings* pSubBindings;
213 SfxBindings* pSuperBindings;
214 SfxStateCacheArr_Impl* pCaches; // One chache for each binding
215 sal_uInt16 nCachedFunc1; // index for the last one called
216 sal_uInt16 nCachedFunc2; // index for the second last called
217 sal_uInt16 nMsgPos; // Message-Position relative the one to be updated
218 SfxPopupAction ePopupAction; // Checked in DeleteFloatinWindow()
219 bool bContextChanged;
220 bool bMsgDirty; // Has a MessageServer been invalidated?
221 bool bAllMsgDirty; // Has a MessageServer been invalidated?
222 bool bAllDirty; // After InvalidateAll
223 bool bCtrlReleased; // while EnterRegistrations
224 AutoTimer aTimer; // for volatile Slots
225 bool bInUpdate; // for Assertions
226 bool bInNextJob; // for Assertions
227 bool bFirstRound; // First round in Update
228 sal_uInt16 nFirstShell; // Shell, the first round is preferred
229 sal_uInt16 nOwnRegLevel; // Counts the real Locks, except those of the Super Bindings
230 InvalidateSlotMap m_aInvalidateSlots; // store slots which are invalidated while in update
233 SfxBindings::SfxBindings()
234 : pImp(new SfxBindings_Impl),
235 pDispatcher(0),
236 nRegLevel(1) // first becomes 0, when the Dispatcher is set
238 pImp->nMsgPos = 0;
239 pImp->bAllMsgDirty = true;
240 pImp->bContextChanged = false;
241 pImp->bMsgDirty = true;
242 pImp->bAllDirty = true;
243 pImp->ePopupAction = SfxPopupAction::DELETE;
244 pImp->nCachedFunc1 = 0;
245 pImp->nCachedFunc2 = 0;
246 pImp->bCtrlReleased = false;
247 pImp->bFirstRound = false;
248 pImp->bInNextJob = false;
249 pImp->bInUpdate = false;
250 pImp->pSubBindings = NULL;
251 pImp->pSuperBindings = NULL;
252 pImp->pWorkWin = NULL;
253 pImp->pUnoCtrlArr = NULL;
254 pImp->nOwnRegLevel = nRegLevel;
256 // all caches are valid (no pending invalidate-job)
257 // create the list of caches
258 pImp->pCaches = new SfxStateCacheArr_Impl;
259 pImp->aTimer.SetTimeoutHdl( LINK(this, SfxBindings, NextJob) );
264 SfxBindings::~SfxBindings()
266 /* [Description]
268 Destructor of the SfxBindings class. The one, for each <SfxApplication>
269 existing Instance is automatically destroyed by the <SfxApplication>
270 after the execution of <SfxApplication::Exit()>.
272 The still existing <SfxControllerItem> instances, which are registered
273 by the SfxBindings instance, are automatically destroyed in the Destructor.
274 These are usually the Floating-Toolboxen, Value-Sets
275 etc. Arrays of SfxControllerItems may at this time no longer exist.
279 // The SubBindings should not be locked!
280 pImp->pSubBindings = NULL;
282 ENTERREGISTRATIONS();
284 pImp->aTimer.Stop();
285 DeleteControllers_Impl();
287 // Delete Caches
288 for(SfxStateCacheArr_Impl::const_iterator it = pImp->pCaches->begin(); it != pImp->pCaches->end(); ++it)
289 delete *it;
291 DELETEZ( pImp->pWorkWin );
293 delete pImp->pCaches;
294 delete pImp;
299 void SfxBindings::DeleteControllers_Impl()
301 // in the first round delete SfxPopupWindows
302 sal_uInt16 nCount = pImp->pCaches->size();
303 sal_uInt16 nCache;
304 for ( nCache = 0; nCache < nCount; ++nCache )
306 // Remember were you are
307 SfxStateCache *pCache = (*pImp->pCaches)[nCache];
308 sal_uInt16 nSlotId = pCache->GetId();
310 // Re-align, because the cache may have been reduced
311 sal_uInt16 nNewCount = pImp->pCaches->size();
312 if ( nNewCount < nCount )
314 nCache = GetSlotPos(nSlotId);
315 if ( nCache >= nNewCount ||
316 nSlotId != (*pImp->pCaches)[nCache]->GetId() )
317 --nCache;
318 nCount = nNewCount;
322 // Delete all Caches
323 for ( nCache = pImp->pCaches->size(); nCache > 0; --nCache )
325 // Get Cache via ::com::sun::star::sdbcx::Index
326 SfxStateCache *pCache = (*pImp->pCaches)[ nCache-1 ];
328 // unbind all controllers in the cache
329 SfxControllerItem *pNext;
330 for ( SfxControllerItem *pCtrl = pCache->GetItemLink();
331 pCtrl; pCtrl = pNext )
333 pNext = pCtrl->GetItemLink();
334 pCtrl->UnBind();
337 if ( pCache->GetInternalController() )
338 pCache->GetInternalController()->UnBind();
340 // Delete Cache
341 if( nCache-1 < (sal_uInt16) pImp->pCaches->size() )
342 delete (*pImp->pCaches)[nCache-1];
343 pImp->pCaches->erase(pImp->pCaches->begin()+ nCache - 1);
346 if( pImp->pUnoCtrlArr )
348 sal_uInt16 nCtrlCount = pImp->pUnoCtrlArr->size();
349 for ( sal_uInt16 n=nCtrlCount; n>0; n-- )
351 SfxUnoControllerItem *pCtrl = (*pImp->pUnoCtrlArr)[n-1];
352 pCtrl->ReleaseBindings();
355 DBG_ASSERT( !pImp->pUnoCtrlArr->size(), "Do not remove UnoControllerItems!" );
356 DELETEZ( pImp->pUnoCtrlArr );
362 void SfxBindings::HidePopups( bool bHide )
364 // Hide SfxPopupWindows
365 HidePopupCtrls_Impl( bHide );
366 SfxBindings *pSub = pImp->pSubBindings;
367 while ( pSub )
369 pImp->pSubBindings->HidePopupCtrls_Impl( bHide );
370 pSub = pSub->pImp->pSubBindings;
373 // Hide SfxChildWindows
374 DBG_ASSERT( pDispatcher, "HidePopups not allowed without dispatcher" );
375 if ( pImp->pWorkWin )
376 pImp->pWorkWin->HidePopups_Impl( bHide, true );
379 void SfxBindings::HidePopupCtrls_Impl( bool bHide )
381 if ( bHide )
383 // Hide SfxPopupWindows
384 pImp->ePopupAction = SfxPopupAction::HIDE;
386 else
388 // Show SfxPopupWindows
389 pImp->ePopupAction = SfxPopupAction::SHOW;
392 pImp->ePopupAction = SfxPopupAction::DELETE;
397 void SfxBindings::Update_Impl
399 SfxStateCache* pCache // The up to date SfxStatusCache
402 if( pCache->GetDispatch().is() && pCache->GetItemLink() )
404 pCache->SetCachedState(true);
405 if ( !pCache->GetInternalController() )
406 return;
409 if ( !pDispatcher )
410 return;
412 // gather together all with the same status method which are dirty
413 SfxDispatcher &rDispat = *pDispatcher;
414 const SfxSlot *pRealSlot = 0;
415 const SfxSlotServer* pMsgServer = 0;
416 SfxFoundCacheArr_Impl aFound;
417 SfxItemSet *pSet = CreateSet_Impl( pCache, pRealSlot, &pMsgServer, aFound );
418 bool bUpdated = false;
419 if ( pSet )
421 // Query Status
422 if ( rDispat._FillState( *pMsgServer, *pSet, pRealSlot ) )
424 // Post Status
425 const SfxInterface *pInterface =
426 rDispat.GetShell(pMsgServer->GetShellLevel())->GetInterface();
427 for ( sal_uInt16 nPos = 0; nPos < aFound.size(); ++nPos )
429 const SfxFoundCache_Impl& rFound = aFound[nPos];
430 sal_uInt16 nWhich = rFound.nWhichId;
431 const SfxPoolItem *pItem = 0;
432 SfxItemState eState = pSet->GetItemState(nWhich, true, &pItem);
433 if ( eState == SfxItemState::DEFAULT && SfxItemPool::IsWhich(nWhich) )
434 pItem = &pSet->Get(nWhich);
435 UpdateControllers_Impl( pInterface, aFound[nPos], pItem, eState );
437 bUpdated = true;
440 delete pSet;
443 if ( !bUpdated && pCache )
445 // When pCache == NULL and no SlotServer
446 // (for example due to locked Dispatcher! ),
447 // obviously do not try to update
448 SfxFoundCache_Impl aFoundCache(
449 pCache->GetId(), 0,
450 pRealSlot, pCache );
451 UpdateControllers_Impl( 0, aFoundCache, 0, SfxItemState::DISABLED);
457 void SfxBindings::InvalidateSlotsInMap_Impl()
459 InvalidateSlotMap::const_iterator pIter = pImp->m_aInvalidateSlots.begin();
460 while ( pIter != pImp->m_aInvalidateSlots.end() )
462 Invalidate( pIter->first );
463 ++pIter;
465 pImp->m_aInvalidateSlots.clear();
470 void SfxBindings::AddSlotToInvalidateSlotsMap_Impl( sal_uInt16 nId )
472 pImp->m_aInvalidateSlots[nId] = true;
477 void SfxBindings::Update
479 sal_uInt16 nId // the bound and up-to-date Slot-Id
482 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
484 if ( pDispatcher )
485 pDispatcher->Flush();
487 if ( pImp->pSubBindings )
488 pImp->pSubBindings->Update( nId );
490 SfxStateCache* pCache = GetStateCache( nId );
491 if ( pCache )
493 pImp->bInUpdate = true;
494 if ( pImp->bMsgDirty )
496 UpdateSlotServer_Impl();
497 pCache = GetStateCache( nId );
500 if (pCache)
502 bool bInternalUpdate = true;
503 if( pCache->GetDispatch().is() && pCache->GetItemLink() )
505 pCache->SetCachedState(true);
506 bInternalUpdate = ( pCache->GetInternalController() != 0 );
509 if ( bInternalUpdate )
511 // Query Status
512 const SfxSlotServer* pMsgServer = pDispatcher ? pCache->GetSlotServer(*pDispatcher, pImp->xProv) : NULL;
513 if ( !pCache->IsControllerDirty() &&
514 ( !pMsgServer ||
515 !pMsgServer->GetSlot()->IsMode(SfxSlotMode::VOLATILE) ) )
517 pImp->bInUpdate = false;
518 InvalidateSlotsInMap_Impl();
519 return;
521 if (!pMsgServer)
523 pCache->SetState(SfxItemState::DISABLED, 0);
524 pImp->bInUpdate = false;
525 InvalidateSlotsInMap_Impl();
526 return;
529 Update_Impl(pCache);
532 pImp->bAllDirty = false;
535 pImp->bInUpdate = false;
536 InvalidateSlotsInMap_Impl();
542 void SfxBindings::Update()
544 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
546 if ( pImp->pSubBindings )
547 pImp->pSubBindings->Update();
549 if ( pDispatcher )
551 if ( nRegLevel )
552 return;
554 pImp->bInUpdate = true;
555 pDispatcher->Flush();
556 pDispatcher->Update_Impl();
557 while ( !NextJob_Impl(0) )
558 ; // loop
559 pImp->bInUpdate = false;
560 InvalidateSlotsInMap_Impl();
566 void SfxBindings::SetState
568 const SfxItemSet& rSet // status values to be set
571 // when locked then only invalidate
572 if ( nRegLevel )
574 SfxItemIter aIter(rSet);
575 for ( const SfxPoolItem *pItem = aIter.FirstItem();
576 pItem;
577 pItem = aIter.NextItem() )
578 Invalidate( pItem->Which() );
580 else
582 // Status may be accepted only if all slot-pointers are set
583 if ( pImp->bMsgDirty )
584 UpdateSlotServer_Impl();
586 // Iterate over the itemset, update if the slot bound
587 //! Bug: Use WhichIter and possibly send VoidItems up
588 SfxItemIter aIter(rSet);
589 for ( const SfxPoolItem *pItem = aIter.FirstItem();
590 pItem;
591 pItem = aIter.NextItem() )
593 SfxStateCache* pCache =
594 GetStateCache( rSet.GetPool()->GetSlotId(pItem->Which()) );
595 if ( pCache )
597 // Update status
598 if ( !pCache->IsControllerDirty() )
599 pCache->Invalidate(false);
600 pCache->SetState( SfxItemState::DEFAULT, pItem );
602 //! Not implemented: Updates from EnumSlots via master slots
610 void SfxBindings::SetState
612 const SfxPoolItem& rItem // Status value to be set
615 if ( nRegLevel )
617 Invalidate( rItem.Which() );
619 else
621 // Status may be accepted only if all slot-pointers are set
622 if ( pImp->bMsgDirty )
623 UpdateSlotServer_Impl();
625 //update if the slot bound
626 DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ),
627 "cannot set items with which-id" );
628 SfxStateCache* pCache = GetStateCache( rItem.Which() );
629 if ( pCache )
631 // Update Status
632 if ( !pCache->IsControllerDirty() )
633 pCache->Invalidate(false);
634 pCache->SetState( SfxItemState::DEFAULT, &rItem );
636 //! Not implemented: Updates from EnumSlots via master slots
644 SfxStateCache* SfxBindings::GetAnyStateCache_Impl( sal_uInt16 nId )
646 SfxStateCache* pCache = GetStateCache( nId );
647 if ( !pCache && pImp->pSubBindings )
648 return pImp->pSubBindings->GetAnyStateCache_Impl( nId );
649 return pCache;
652 SfxStateCache* SfxBindings::GetStateCache
654 sal_uInt16 nId /* Slot-Id, which SfxStatusCache is to be found */
657 return GetStateCache(nId, 0);
660 SfxStateCache* SfxBindings::GetStateCache
662 sal_uInt16 nId, /* Slot-Id, which SfxStatusCache is to be found */
663 sal_uInt16* pPos /* NULL for instance the position from which the
664 bindings are to be searched binary. Returns the
665 position back for where the nId was found,
666 or where it was inserted. */
669 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
670 // is the specified function bound?
671 const sal_uInt16 nStart = ( pPos ? *pPos : 0 );
672 const sal_uInt16 nPos = GetSlotPos( nId, nStart );
674 if ( nPos < pImp->pCaches->size() &&
675 (*pImp->pCaches)[nPos]->GetId() == nId )
677 if ( pPos )
678 *pPos = nPos;
679 return (*pImp->pCaches)[nPos];
681 return 0;
686 void SfxBindings::InvalidateAll
688 bool bWithMsg /* true Mark Slot Server as invalid
689 false Slot Server remains valid */
692 DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
694 if ( pImp->pSubBindings )
695 pImp->pSubBindings->InvalidateAll( bWithMsg );
697 // everything is already set dirty or downing => nothing to do
698 if ( !pDispatcher ||
699 ( pImp->bAllDirty && ( !bWithMsg || pImp->bAllMsgDirty ) ) ||
700 SfxGetpApp()->IsDowning() )
702 return;
705 pImp->bAllMsgDirty = pImp->bAllMsgDirty || bWithMsg;
706 pImp->bMsgDirty = pImp->bMsgDirty || pImp->bAllMsgDirty || bWithMsg;
707 pImp->bAllDirty = true;
709 for ( sal_uInt16 n = 0; n < pImp->pCaches->size(); ++n )
710 (*pImp->pCaches)[n]->Invalidate(bWithMsg);
712 pImp->nMsgPos = 0;
713 if ( !nRegLevel )
715 pImp->aTimer.Stop();
716 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
717 pImp->aTimer.Start();
723 void SfxBindings::Invalidate
725 const sal_uInt16* pIds /* numerically sorted NULL-terminated array of
726 slot IDs (individual, not as a couple!) */
729 if ( pImp->bInUpdate )
731 sal_Int32 i = 0;
732 while ( pIds[i] != 0 )
733 AddSlotToInvalidateSlotsMap_Impl( pIds[i++] );
735 if ( pImp->pSubBindings )
736 pImp->pSubBindings->Invalidate( pIds );
737 return;
740 if ( pImp->pSubBindings )
741 pImp->pSubBindings->Invalidate( pIds );
743 // everything is already set dirty or downing => nothing to do
744 if ( !pDispatcher || pImp->bAllDirty || SfxGetpApp()->IsDowning() )
745 return;
747 // Search binary in always smaller areas
748 for ( sal_uInt16 n = GetSlotPos(*pIds);
749 *pIds && n < pImp->pCaches->size();
750 n = GetSlotPos(*pIds, n) )
752 // If SID is ever bound, then invalidate the cache
753 SfxStateCache *pCache = (*pImp->pCaches)[n];
754 if ( pCache->GetId() == *pIds )
755 pCache->Invalidate(false);
757 // Next SID
758 if ( !*++pIds )
759 break;
760 DBG_ASSERT( *pIds > *(pIds-1), "pIds unsorted" );
763 // if not enticed to start update timer
764 pImp->nMsgPos = 0;
765 if ( !nRegLevel )
767 pImp->aTimer.Stop();
768 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
769 pImp->aTimer.Start();
775 void SfxBindings::InvalidateShell
777 const SfxShell& rSh, /* <SfxShell> whose Slot-Ids should be
778 invalidated */
779 bool bDeep /* true
780 also the SfxShell's inherited slot IDs are invalidated
782 false
783 the inherited and not overridden Slot-Ids are
784 invalidated */
785 // for now always bDeep
788 DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
790 if ( pImp->pSubBindings )
791 pImp->pSubBindings->InvalidateShell( rSh, bDeep );
793 if ( !pDispatcher || pImp->bAllDirty || SfxGetpApp()->IsDowning() )
794 return;
796 // flush now already, it is done in GetShellLevel (rsh) anyway,
797 // important so that is set correctly: pimp-> ball(Msg)Dirty
798 pDispatcher->Flush();
800 if ((pImp->bAllDirty && pImp->bAllMsgDirty) || SfxGetpApp()->IsDowning())
802 // if the next one is anyway, then all the servers are collected
803 return;
806 // Find Level
807 sal_uInt16 nLevel = pDispatcher->GetShellLevel(rSh);
808 if ( nLevel != USHRT_MAX )
810 for ( sal_uInt16 n = 0; n < pImp->pCaches->size(); ++n )
812 SfxStateCache *pCache = (*pImp->pCaches)[n];
813 const SfxSlotServer *pMsgServer =
814 pCache->GetSlotServer(*pDispatcher, pImp->xProv);
815 if ( pMsgServer && pMsgServer->GetShellLevel() == nLevel )
816 pCache->Invalidate(false);
818 pImp->nMsgPos = 0;
819 if ( !nRegLevel )
821 pImp->aTimer.Stop();
822 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
823 pImp->aTimer.Start();
824 pImp->bFirstRound = true;
825 pImp->nFirstShell = nLevel;
832 void SfxBindings::Invalidate
834 sal_uInt16 nId // Status value to be set
837 if ( pImp->bInUpdate )
839 AddSlotToInvalidateSlotsMap_Impl( nId );
840 if ( pImp->pSubBindings )
841 pImp->pSubBindings->Invalidate( nId );
842 return;
845 if ( pImp->pSubBindings )
846 pImp->pSubBindings->Invalidate( nId );
848 if ( !pDispatcher || pImp->bAllDirty || SfxGetpApp()->IsDowning() )
849 return;
851 SfxStateCache* pCache = GetStateCache(nId);
852 if ( pCache )
854 pCache->Invalidate(false);
855 pImp->nMsgPos = std::min(GetSlotPos(nId), pImp->nMsgPos);
856 if ( !nRegLevel )
858 pImp->aTimer.Stop();
859 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
860 pImp->aTimer.Start();
867 void SfxBindings::Invalidate
869 sal_uInt16 nId, // Status value to be set
870 bool bWithItem, // Clear StateCache?
871 bool bWithMsg // Get new SlotServer?
874 DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
876 if ( pImp->pSubBindings )
877 pImp->pSubBindings->Invalidate( nId, bWithItem, bWithMsg );
879 if ( SfxGetpApp()->IsDowning() )
880 return;
882 SfxStateCache* pCache = GetStateCache(nId);
883 if ( pCache )
885 if ( bWithItem )
886 pCache->ClearCache();
887 pCache->Invalidate(bWithMsg);
889 if ( !pDispatcher || pImp->bAllDirty )
890 return;
892 pImp->nMsgPos = std::min(GetSlotPos(nId), pImp->nMsgPos);
893 if ( !nRegLevel )
895 pImp->aTimer.Stop();
896 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
897 pImp->aTimer.Start();
904 bool SfxBindings::IsBound( sal_uInt16 nSlotId, sal_uInt16 nStartSearchAt )
906 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
907 return GetStateCache(nSlotId, &nStartSearchAt ) != 0;
912 sal_uInt16 SfxBindings::GetSlotPos( sal_uInt16 nId, sal_uInt16 nStartSearchAt )
914 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
916 // answer immediately if a function-seek comes repeated
917 if ( pImp->nCachedFunc1 < pImp->pCaches->size() &&
918 (*pImp->pCaches)[pImp->nCachedFunc1]->GetId() == nId )
920 return pImp->nCachedFunc1;
922 if ( pImp->nCachedFunc2 < pImp->pCaches->size() &&
923 (*pImp->pCaches)[pImp->nCachedFunc2]->GetId() == nId )
925 // swap the caches
926 sal_uInt16 nTemp = pImp->nCachedFunc1;
927 pImp->nCachedFunc1 = pImp->nCachedFunc2;
928 pImp->nCachedFunc2 = nTemp;
929 return pImp->nCachedFunc1;
932 // binary search, if not found, seek to target-position
933 if ( pImp->pCaches->size() <= nStartSearchAt )
935 return 0;
937 if ( (sal_uInt16) pImp->pCaches->size() == (nStartSearchAt+1) )
939 return (*pImp->pCaches)[nStartSearchAt]->GetId() >= nId ? 0 : 1;
941 sal_uInt16 nLow = nStartSearchAt;
942 sal_uInt16 nMid = 0;
943 sal_uInt16 nHigh = 0;
944 bool bFound = false;
945 nHigh = pImp->pCaches->size() - 1;
946 while ( !bFound && nLow <= nHigh )
948 nMid = (nLow + nHigh) >> 1;
949 DBG_ASSERT( nMid < pImp->pCaches->size(), "bsearch is buggy" );
950 int nDiff = (int) nId - (int) ( ((*pImp->pCaches)[nMid])->GetId() );
951 if ( nDiff < 0)
952 { if ( nMid == 0 )
953 break;
954 nHigh = nMid - 1;
956 else if ( nDiff > 0 )
957 { nLow = nMid + 1;
958 if ( nLow == 0 )
959 break;
961 else
962 bFound = true;
964 sal_uInt16 nPos = bFound ? nMid : nLow;
965 DBG_ASSERT( nPos <= pImp->pCaches->size(), "" );
966 DBG_ASSERT( nPos == pImp->pCaches->size() ||
967 nId <= (*pImp->pCaches)[nPos]->GetId(), "" );
968 DBG_ASSERT( nPos == nStartSearchAt ||
969 nId > (*pImp->pCaches)[nPos-1]->GetId(), "" );
970 DBG_ASSERT( ( (nPos+1) >= (sal_uInt16) pImp->pCaches->size() ) ||
971 nId < (*pImp->pCaches)[nPos+1]->GetId(), "" );
972 pImp->nCachedFunc2 = pImp->nCachedFunc1;
973 pImp->nCachedFunc1 = nPos;
974 return nPos;
977 void SfxBindings::RegisterInternal_Impl( SfxControllerItem& rItem )
979 Register_Impl( rItem, true );
983 void SfxBindings::Register( SfxControllerItem& rItem )
985 Register_Impl( rItem, false );
988 void SfxBindings::Register_Impl( SfxControllerItem& rItem, bool bInternal )
990 // DBG_ASSERT( nRegLevel > 0, "registration without EnterRegistrations" );
991 DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Register while status-updating" );
993 // insert new cache if it does not already exist
994 sal_uInt16 nId = rItem.GetId();
995 sal_uInt16 nPos = GetSlotPos(nId);
996 if ( nPos >= pImp->pCaches->size() ||
997 (*pImp->pCaches)[nPos]->GetId() != nId )
999 SfxStateCache* pCache = new SfxStateCache(nId);
1000 pImp->pCaches->insert( pImp->pCaches->begin() + nPos, pCache );
1001 DBG_ASSERT( nPos == 0 ||
1002 (*pImp->pCaches)[nPos]->GetId() >
1003 (*pImp->pCaches)[nPos-1]->GetId(), "" );
1004 DBG_ASSERT( (nPos == pImp->pCaches->size()-1) ||
1005 (*pImp->pCaches)[nPos]->GetId() <
1006 (*pImp->pCaches)[nPos+1]->GetId(), "" );
1007 pImp->bMsgDirty = true;
1010 // enqueue the new binding
1011 if ( bInternal )
1013 (*pImp->pCaches)[nPos]->SetInternalController( &rItem );
1015 else
1017 SfxControllerItem *pOldItem = (*pImp->pCaches)[nPos]->ChangeItemLink(&rItem);
1018 rItem.ChangeItemLink(pOldItem);
1024 void SfxBindings::Release( SfxControllerItem& rItem )
1026 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1027 DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Release while status-updating" );
1028 ENTERREGISTRATIONS();
1030 // find the bound function
1031 sal_uInt16 nId = rItem.GetId();
1032 sal_uInt16 nPos = GetSlotPos(nId);
1033 SfxStateCache* pCache = (nPos < pImp->pCaches->size()) ? (*pImp->pCaches)[nPos] : 0;
1034 if ( pCache && pCache->GetId() == nId )
1036 if ( pCache->GetInternalController() == &rItem )
1038 pCache->ReleaseInternalController();
1040 else
1042 // is this the first binding in the list?
1043 SfxControllerItem* pItem = pCache->GetItemLink();
1044 if ( pItem == &rItem )
1045 pCache->ChangeItemLink( rItem.GetItemLink() );
1046 else
1048 // search the binding in the list
1049 while ( pItem && pItem->GetItemLink() != &rItem )
1050 pItem = pItem->GetItemLink();
1052 // unlink it if it was found
1053 if ( pItem )
1054 pItem->ChangeItemLink( rItem.GetItemLink() );
1058 // was this the last controller?
1059 if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() )
1061 pImp->bCtrlReleased = true;
1065 LEAVEREGISTRATIONS();
1069 const SfxPoolItem* SfxBindings::ExecuteSynchron( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi,
1070 const SfxPoolItem **ppInternalArgs )
1072 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1074 if( !nId || !pDispatcher )
1075 return NULL;
1077 return Execute_Impl( nId, ppItems, nModi, SfxCallMode::SYNCHRON, ppInternalArgs );
1080 bool SfxBindings::Execute( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode,
1081 const SfxPoolItem **ppInternalArgs )
1083 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1085 if( !nId || !pDispatcher )
1086 return false;
1088 const SfxPoolItem* pRet = Execute_Impl( nId, ppItems, nModi, nCallMode, ppInternalArgs );
1089 return ( pRet != 0 );
1092 const SfxPoolItem* SfxBindings::Execute_Impl( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode,
1093 const SfxPoolItem **ppInternalArgs, bool bGlobalOnly )
1095 SfxStateCache *pCache = GetStateCache( nId );
1096 if ( !pCache )
1098 SfxBindings *pBind = pImp->pSubBindings;
1099 while ( pBind )
1101 if ( pBind->GetStateCache( nId ) )
1102 return pBind->Execute_Impl( nId, ppItems, nModi, nCallMode, ppInternalArgs, bGlobalOnly );
1103 pBind = pBind->pImp->pSubBindings;
1107 SfxDispatcher &rDispatcher = *pDispatcher;
1108 rDispatcher.Flush();
1110 // get SlotServer (Slot+ShellLevel) and Shell from cache
1111 ::boost::scoped_ptr<SfxStateCache> xCache;
1112 if ( !pCache )
1114 // Execution of non cached slots (Accelerators don't use Controllers)
1115 // slot is uncached, use SlotCache to handle external dispatch providers
1116 xCache.reset(new SfxStateCache(nId));
1117 pCache = xCache.get();
1118 pCache->GetSlotServer( rDispatcher, pImp->xProv );
1121 if ( pCache->GetDispatch().is() )
1123 DBG_ASSERT( !ppInternalArgs, "Internal args get lost when dispatched!" );
1125 SfxItemPool &rPool = GetDispatcher()->GetFrame()->GetObjectShell()->GetPool();
1126 SfxRequest aReq( nId, nCallMode, rPool );
1127 aReq.SetModifier( nModi );
1128 if( ppItems )
1129 while( *ppItems )
1130 aReq.AppendItem( **ppItems++ );
1132 // cache binds to an external dispatch provider
1133 pCache->Dispatch( aReq.GetArgs(), nCallMode == SfxCallMode::SYNCHRON );
1134 SfxPoolItem *pVoid = new SfxVoidItem( nId );
1135 DeleteItemOnIdle( pVoid );
1136 return pVoid;
1139 // slot is handled internally by SfxDispatcher
1140 if ( pImp->bMsgDirty )
1141 UpdateSlotServer_Impl();
1143 SfxShell *pShell=0;
1144 const SfxSlot *pSlot=0;
1146 const SfxSlotServer* pServer = pCache->GetSlotServer( rDispatcher, pImp->xProv );
1147 if ( !pServer )
1149 return NULL;
1151 else
1153 pShell = rDispatcher.GetShell( pServer->GetShellLevel() );
1154 pSlot = pServer->GetSlot();
1157 if ( bGlobalOnly )
1158 if ( !pShell->ISA(SfxModule) && !pShell->ISA(SfxApplication) && !pShell->ISA(SfxViewFrame) )
1159 return NULL;
1161 SfxItemPool &rPool = pShell->GetPool();
1162 SfxRequest aReq( nId, nCallMode, rPool );
1163 aReq.SetModifier( nModi );
1164 if( ppItems )
1165 while( *ppItems )
1166 aReq.AppendItem( **ppItems++ );
1167 if ( ppInternalArgs )
1169 SfxAllItemSet aSet( rPool );
1170 for ( const SfxPoolItem **pArg = ppInternalArgs; *pArg; ++pArg )
1171 aSet.Put( **pArg );
1172 aReq.SetInternalArgs_Impl( aSet );
1175 Execute_Impl( aReq, pSlot, pShell );
1177 const SfxPoolItem* pRet = aReq.GetReturnValue();
1178 if ( !pRet )
1180 SfxPoolItem *pVoid = new SfxVoidItem( nId );
1181 DeleteItemOnIdle( pVoid );
1182 pRet = pVoid;
1185 return pRet;
1188 void SfxBindings::Execute_Impl( SfxRequest& aReq, const SfxSlot* pSlot, SfxShell* pShell )
1190 SfxItemPool &rPool = pShell->GetPool();
1192 if ( SFX_KIND_ENUM == pSlot->GetKind() )
1194 // for Enum-Slots, the Master has to be executed with the value
1195 // of the enums
1196 const SfxSlot *pRealSlot = pShell->GetInterface()->GetRealSlot(pSlot);
1197 const sal_uInt16 nSlotId = pRealSlot->GetSlotId();
1198 aReq.SetSlot( nSlotId );
1199 aReq.AppendItem( SfxAllEnumItem( rPool.GetWhich(nSlotId), pSlot->GetValue() ) );
1200 pDispatcher->_Execute( *pShell, *pRealSlot, aReq, aReq.GetCallMode() | SfxCallMode::RECORD );
1202 else if ( SFX_KIND_ATTR == pSlot->GetKind() )
1204 // Which value has to be mapped for Attribute slots
1205 const sal_uInt16 nSlotId = pSlot->GetSlotId();
1206 aReq.SetSlot( nSlotId );
1207 if ( pSlot->IsMode(SfxSlotMode::TOGGLE) )
1209 // The value is attached to a toggleable attribute (Bools)
1210 sal_uInt16 nWhich = pSlot->GetWhich(rPool);
1211 SfxItemSet aSet(rPool, nWhich, nWhich);
1212 SfxStateFunc aFunc = pSlot->GetStateFnc();
1213 pShell->CallState( aFunc, aSet );
1214 const SfxPoolItem *pOldItem;
1215 SfxItemState eState = aSet.GetItemState(nWhich, true, &pOldItem);
1216 if ( eState == SfxItemState::DISABLED )
1217 return;
1219 if ( SfxItemState::DEFAULT == eState && SfxItemPool::IsWhich(nWhich) )
1220 pOldItem = &aSet.Get(nWhich);
1222 if ( SfxItemState::SET == eState ||
1223 ( SfxItemState::DEFAULT == eState &&
1224 SfxItemPool::IsWhich(nWhich) &&
1225 pOldItem ) )
1227 if ( pOldItem->ISA(SfxBoolItem) )
1229 // we can toggle Bools
1230 bool bOldValue = static_cast<const SfxBoolItem *>(pOldItem)->GetValue();
1231 SfxBoolItem *pNewItem = static_cast<SfxBoolItem*>(pOldItem->Clone());
1232 pNewItem->SetValue( !bOldValue );
1233 aReq.AppendItem( *pNewItem );
1234 delete pNewItem;
1236 else if ( pOldItem->ISA(SfxEnumItemInterface) &&
1237 static_cast<const SfxEnumItemInterface *>(pOldItem)->HasBoolValue())
1239 // and Enums with Bool-Interface
1240 SfxEnumItemInterface *pNewItem =
1241 static_cast<SfxEnumItemInterface*>(pOldItem->Clone());
1242 pNewItem->SetBoolValue(!static_cast<const SfxEnumItemInterface *>(pOldItem)->GetBoolValue());
1243 aReq.AppendItem( *pNewItem );
1244 delete pNewItem;
1246 else {
1247 OSL_FAIL( "Toggle only for Enums and Bools allowed" );
1250 else if ( SfxItemState::DONTCARE == eState )
1252 // Create one Status-Item for each Factory
1253 SfxPoolItem *pNewItem = pSlot->GetType()->CreateItem();
1254 DBG_ASSERT( pNewItem, "Toggle to slot without ItemFactory" );
1255 pNewItem->SetWhich( nWhich );
1257 if ( pNewItem->ISA(SfxBoolItem) )
1259 // we can toggle Bools
1260 static_cast<SfxBoolItem*>(pNewItem)->SetValue( true );
1261 aReq.AppendItem( *pNewItem );
1263 else if ( pNewItem->ISA(SfxEnumItemInterface) &&
1264 static_cast<SfxEnumItemInterface *>(pNewItem)->HasBoolValue())
1266 // and Enums with Bool-Interface
1267 static_cast<SfxEnumItemInterface*>(pNewItem)->SetBoolValue(true);
1268 aReq.AppendItem( *pNewItem );
1270 else {
1271 OSL_FAIL( "Toggle only for Enums and Bools allowed" );
1273 delete pNewItem;
1275 else {
1276 OSL_FAIL( "suspicious Toggle-Slot" );
1280 pDispatcher->_Execute( *pShell, *pSlot, aReq, aReq.GetCallMode() | SfxCallMode::RECORD );
1282 else
1283 pDispatcher->_Execute( *pShell, *pSlot, aReq, aReq.GetCallMode() | SfxCallMode::RECORD );
1288 void SfxBindings::UpdateSlotServer_Impl()
1290 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1292 // synchronize
1293 pDispatcher->Flush();
1295 if ( pImp->bAllMsgDirty )
1297 if ( !nRegLevel )
1299 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame
1300 ( pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY );
1301 pImp->bContextChanged = false;
1303 else
1304 pImp->bContextChanged = true;
1307 for (size_t i = 0, nCount = pImp->pCaches->size(); i < nCount; ++i)
1309 SfxStateCache *pCache = (*pImp->pCaches)[i];
1310 //GetSlotServer can modify pImp->pCaches
1311 pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1313 pImp->bMsgDirty = pImp->bAllMsgDirty = false;
1315 Broadcast( SfxSimpleHint(SFX_HINT_DOCCHANGED) );
1320 SfxItemSet* SfxBindings::CreateSet_Impl
1322 SfxStateCache*& pCache, // in: Status-Cache from nId
1323 const SfxSlot*& pRealSlot, // out: RealSlot to nId
1324 const SfxSlotServer** pMsgServer, // out: Slot-Server to nId
1325 SfxFoundCacheArr_Impl& rFound // out: List of Caches for Siblings
1328 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1330 DBG_ASSERT( !pImp->bMsgDirty, "CreateSet_Impl with dirty MessageServer" );
1331 assert(pDispatcher);
1333 const SfxSlotServer* pMsgSvr = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1334 if (!pMsgSvr)
1335 return 0;
1337 pRealSlot = 0;
1338 *pMsgServer = pMsgSvr;
1340 sal_uInt16 nShellLevel = pMsgSvr->GetShellLevel();
1341 SfxShell *pShell = pDispatcher->GetShell( nShellLevel );
1342 if ( !pShell ) // rare GPF when browsing through update from Inet-Notify
1343 return 0;
1345 SfxItemPool &rPool = pShell->GetPool();
1347 // get the status method, which is served by the pCache
1348 SfxStateFunc pFnc = 0;
1349 const SfxInterface *pInterface = pShell->GetInterface();
1350 if ( SFX_KIND_ENUM == pMsgSvr->GetSlot()->GetKind() )
1352 pRealSlot = pInterface->GetRealSlot(pMsgSvr->GetSlot());
1353 pCache = GetStateCache( pRealSlot->GetSlotId() );
1355 else
1356 pRealSlot = pMsgSvr->GetSlot();
1358 // Note: pCache can be NULL!
1360 pFnc = pRealSlot->GetStateFnc();
1362 // the RealSlot is always on
1363 SfxFoundCache_Impl *pFound = new SfxFoundCache_Impl(
1364 pRealSlot->GetSlotId(), pRealSlot->GetWhich(rPool), pRealSlot, pCache );
1365 rFound.push_back( pFound );
1367 // Search through the bindings for slots served by the same function. This , // will only affect slots which are present in the found interface.
1369 // The position of the Statecaches in StateCache-Array
1370 sal_uInt16 nCachePos = pImp->nMsgPos;
1371 const SfxSlot *pSibling = pRealSlot->GetNextSlot();
1373 // the Slots ODF a interfaces ar linked in a circle
1374 while ( pSibling > pRealSlot )
1376 SfxStateFunc pSiblingFnc=0;
1377 SfxStateCache *pSiblingCache =
1378 GetStateCache( pSibling->GetSlotId(), &nCachePos );
1380 // Is the slot cached ?
1381 if ( pSiblingCache )
1383 const SfxSlotServer *pServ = pSiblingCache->GetSlotServer(*pDispatcher, pImp->xProv);
1384 if ( pServ && pServ->GetShellLevel() == nShellLevel )
1385 pSiblingFnc = pServ->GetSlot()->GetStateFnc();
1388 // Does the slot have to be updated at all?
1389 bool bInsert = pSiblingCache && pSiblingCache->IsControllerDirty();
1391 // It is not enough to ask for the same shell!!
1392 bool bSameMethod = pSiblingCache && pFnc == pSiblingFnc;
1394 // If the slot is a non-dirty master slot, then maybe one of his slaves
1395 // is dirty? Then the master slot is still inserted.
1396 if ( !bInsert && bSameMethod && pSibling->GetLinkedSlot() )
1398 // Also check slave slots for Binding
1399 const SfxSlot* pFirstSlave = pSibling->GetLinkedSlot();
1400 for ( const SfxSlot *pSlaveSlot = pFirstSlave;
1401 !bInsert;
1402 pSlaveSlot = pSlaveSlot->GetNextSlot())
1404 // the slaves points to its master
1405 DBG_ASSERT(pSlaveSlot->GetLinkedSlot() == pSibling,
1406 "Wrong Master/Slave relationship!");
1408 sal_uInt16 nCurMsgPos = pImp->nMsgPos;
1409 const SfxStateCache *pSlaveCache =
1410 GetStateCache( pSlaveSlot->GetSlotId(), &nCurMsgPos );
1412 // Is the slave slot chached and dirty ?
1413 bInsert = pSlaveCache && pSlaveCache->IsControllerDirty();
1415 // Slaves are chained together in a circle
1416 if (pSlaveSlot->GetNextSlot() == pFirstSlave)
1417 break;
1421 if ( bInsert && bSameMethod )
1423 SfxFoundCache_Impl *pFoundCache = new SfxFoundCache_Impl(
1424 pSibling->GetSlotId(), pSibling->GetWhich(rPool),
1425 pSibling, pSiblingCache );
1427 rFound.push_back( pFoundCache );
1430 pSibling = pSibling->GetNextSlot();
1433 // Create a Set from the ranges
1434 boost::scoped_array<sal_uInt16> pRanges(new sal_uInt16[rFound.size() * 2 + 1]);
1435 int j = 0;
1436 sal_uInt16 i = 0;
1437 while ( i < rFound.size() )
1439 pRanges[j++] = rFound[i].nWhichId;
1440 // consecutive numbers
1441 for ( ; i < rFound.size()-1; ++i )
1442 if ( rFound[i].nWhichId+1 != rFound[i+1].nWhichId )
1443 break;
1444 pRanges[j++] = rFound[i++].nWhichId;
1446 pRanges[j] = 0; // terminating NULL
1447 SfxItemSet *pSet = new SfxItemSet(rPool, pRanges.get());
1448 pRanges.reset();
1449 return pSet;
1454 void SfxBindings::UpdateControllers_Impl
1456 const SfxInterface* pIF, // Id of the current serving Interface
1457 const SfxFoundCache_Impl& rFound, // Cache, Slot, Which etc.
1458 const SfxPoolItem* pItem, // item to send to controller
1459 SfxItemState eState // state of item
1462 DBG_ASSERT( !rFound.pSlot || SFX_KIND_ENUM != rFound.pSlot->GetKind(),
1463 "direct update of enum slot isn't allowed" );
1465 SfxStateCache* pCache = rFound.pCache;
1466 const SfxSlot* pSlot = rFound.pSlot;
1467 DBG_ASSERT( !pCache || !pSlot || pCache->GetId() == pSlot->GetSlotId(), "SID mismatch" );
1469 // bound until now, the Controller to update the Slot.
1470 if ( pCache && pCache->IsControllerDirty() )
1472 if ( SfxItemState::DONTCARE == eState )
1474 // ambiguous
1475 pCache->SetState( SfxItemState::DONTCARE, reinterpret_cast<SfxPoolItem *>(-1) );
1477 else if ( SfxItemState::DEFAULT == eState &&
1478 rFound.nWhichId > SFX_WHICH_MAX )
1480 // no Status or Default but without Pool
1481 SfxVoidItem aVoid(0);
1482 pCache->SetState( SfxItemState::UNKNOWN, &aVoid );
1484 else if ( SfxItemState::DISABLED == eState )
1485 pCache->SetState(SfxItemState::DISABLED, 0);
1486 else
1487 pCache->SetState(SfxItemState::DEFAULT, pItem);
1490 // Update the slots for so far available and bound Controllers for
1491 // Slave-Slots (Enum-value)
1492 DBG_ASSERT( !pSlot || 0 == pSlot->GetLinkedSlot() || !pItem ||
1493 pItem->ISA(SfxEnumItemInterface),
1494 "master slot with non-enum-type found" );
1495 const SfxSlot *pFirstSlave = pSlot ? pSlot->GetLinkedSlot() : 0;
1496 if ( pIF && pFirstSlave)
1498 // Items cast on EnumItem
1499 const SfxEnumItemInterface *pEnumItem =
1500 PTR_CAST(SfxEnumItemInterface,pItem);
1501 if ( eState == SfxItemState::DEFAULT && !pEnumItem )
1502 eState = SfxItemState::DONTCARE;
1503 else
1504 eState = SfxControllerItem::GetItemState( pEnumItem );
1506 // Iterate over all Slaves-Slots
1507 for ( const SfxSlot *pSlave = pFirstSlave; pSlave; pSlave = pSlave->GetNextSlot() )
1509 DBG_ASSERT(pSlave, "Wrong SlaveSlot binding!");
1510 DBG_ASSERT(SFX_KIND_ENUM == pSlave->GetKind(),"non enum slaves aren't allowed");
1511 DBG_ASSERT(pSlave->GetMasterSlotId() == pSlot->GetSlotId(),"Wrong MasterSlot!");
1513 // Binding exist for function ?
1514 SfxStateCache *pEnumCache = GetStateCache( pSlave->GetSlotId() );
1515 if ( pEnumCache )
1517 pEnumCache->Invalidate(false);
1519 // HACK(CONTROL/SELECT Kram) ???
1520 if ( eState == SfxItemState::DONTCARE && rFound.nWhichId == 10144 )
1522 SfxVoidItem aVoid(0);
1523 pEnumCache->SetState( SfxItemState::UNKNOWN, &aVoid );
1525 if (pSlave->GetNextSlot() == pFirstSlave)
1526 break;
1528 continue;
1531 if ( SfxItemState::DISABLED == eState || (pEnumItem && !pEnumItem->IsEnabled( pSlave->GetSlotId())) )
1533 // disabled
1534 pEnumCache->SetState(SfxItemState::DISABLED, 0);
1536 else if ( SfxItemState::DEFAULT == eState && pEnumItem )
1538 // Determine enum value
1539 sal_uInt16 nValue = pEnumItem->GetEnumValue();
1540 SfxBoolItem aBool( rFound.nWhichId, pSlave->GetValue() == nValue );
1541 pEnumCache->SetState(SfxItemState::DEFAULT, &aBool);
1543 else
1545 // ambiguous
1546 pEnumCache->SetState( SfxItemState::DONTCARE, reinterpret_cast<SfxPoolItem *>(-1) );
1550 if (pSlave->GetNextSlot() == pFirstSlave)
1551 break;
1556 IMPL_LINK_TYPED( SfxBindings, NextJob, Timer *, pTimer, void )
1558 NextJob_Impl(pTimer);
1561 bool SfxBindings::NextJob_Impl(Timer * pTimer)
1563 #ifdef DBG_UTIL
1564 // on Windows very often C++ Exceptions (GPF etc.) are caught by MSVCRT
1565 // or another MS library try to get them here
1568 #endif
1569 const unsigned MAX_INPUT_DELAY = 200;
1571 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1573 if ( Application::GetLastInputInterval() < MAX_INPUT_DELAY && pTimer )
1575 pImp->aTimer.SetTimeout(TIMEOUT_UPDATING);
1576 return true;
1579 SfxApplication *pSfxApp = SfxGetpApp();
1581 if( pDispatcher )
1582 pDispatcher->Update_Impl();
1584 // modifying the SfxObjectInterface-stack without SfxBindings => nothing to do
1585 SfxViewFrame* pFrame = pDispatcher ? pDispatcher->GetFrame() : NULL;
1586 if ( (pFrame && !pFrame->GetObjectShell()->AcceptStateUpdate()) || pSfxApp->IsDowning() || pImp->pCaches->empty() )
1588 return true;
1590 if ( !pDispatcher || !pDispatcher->IsFlushed() )
1592 return true;
1595 // if possible Update all server / happens in its own time slice
1596 if ( pImp->bMsgDirty )
1598 UpdateSlotServer_Impl();
1599 return false;
1602 pImp->bAllDirty = false;
1603 pImp->aTimer.SetTimeout(TIMEOUT_UPDATING);
1605 // at least 10 loops and further if more jobs are available but no input
1606 bool bPreEmptive = pTimer && !pSfxApp->Get_Impl()->nInReschedule;
1607 sal_uInt16 nLoops = 10;
1608 pImp->bInNextJob = true;
1609 const sal_uInt16 nCount = pImp->pCaches->size();
1610 while ( pImp->nMsgPos < nCount )
1612 // iterate through the bound functions
1613 bool bJobDone = false;
1614 while ( !bJobDone )
1616 SfxStateCache* pCache = (*pImp->pCaches)[pImp->nMsgPos];
1617 DBG_ASSERT( pCache, "invalid SfxStateCache-position in job queue" );
1618 bool bWasDirty = pCache->IsControllerDirty();
1619 if ( bWasDirty )
1621 Update_Impl( pCache );
1622 DBG_ASSERT( nCount == pImp->pCaches->size(),
1623 "Reschedule in StateChanged => buff" );
1626 // skip to next function binding
1627 ++pImp->nMsgPos;
1629 // keep job if it is not completed, but any input is available
1630 bJobDone = pImp->nMsgPos >= nCount;
1631 if ( bJobDone && pImp->bFirstRound )
1634 // Update of the preferred shell has been done, now may
1635 // also the others shells be updated
1636 bJobDone = false;
1637 pImp->bFirstRound = false;
1638 pImp->nMsgPos = 0;
1641 if ( bWasDirty && !bJobDone && bPreEmptive && (--nLoops == 0) )
1643 pImp->bInNextJob = false;
1644 return false;
1649 pImp->nMsgPos = 0;
1651 // check for volatile slots
1652 bool bVolatileSlotsPresent = false;
1653 for ( sal_uInt16 n = 0; n < nCount; ++n )
1655 SfxStateCache* pCache = (*pImp->pCaches)[n];
1656 const SfxSlotServer *pSlotServer = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1657 if ( pSlotServer && pSlotServer->GetSlot()->IsMode(SfxSlotMode::VOLATILE) )
1659 pCache->Invalidate(false);
1660 bVolatileSlotsPresent = true;
1664 if (bVolatileSlotsPresent)
1665 pImp->aTimer.SetTimeout(TIMEOUT_IDLE);
1666 else
1667 pImp->aTimer.Stop();
1669 // Update round is finished
1670 pImp->bInNextJob = false;
1671 Broadcast(SfxSimpleHint(SFX_HINT_UPDATEDONE));
1672 return true;
1673 #ifdef DBG_UTIL
1675 catch (...)
1677 OSL_FAIL("C++ exception caught!");
1678 pImp->bInNextJob = false;
1681 return false;
1682 #endif
1687 sal_uInt16 SfxBindings::EnterRegistrations(const char *pFile, int nLine)
1689 SAL_INFO(
1690 "sfx.control",
1691 std::setw(std::min(nRegLevel, sal_uInt16(8))) << ' ' << "this = " << this
1692 << " Level = " << nRegLevel << " SfxBindings::EnterRegistrations "
1693 << (pFile
1694 ? SAL_STREAM("File: " << pFile << " Line: " << nLine) : ""));
1696 // When bindings are locked, also lock sub bindings.
1697 if ( pImp->pSubBindings )
1699 pImp->pSubBindings->ENTERREGISTRATIONS();
1701 // These EnterRegistrations are not "real" for the SubBindings
1702 pImp->pSubBindings->pImp->nOwnRegLevel--;
1704 // Synchronize Bindings
1705 pImp->pSubBindings->nRegLevel = nRegLevel + pImp->pSubBindings->pImp->nOwnRegLevel + 1;
1708 pImp->nOwnRegLevel++;
1710 // check if this is the outer most level
1711 if ( ++nRegLevel == 1 )
1713 // stop background-processing
1714 pImp->aTimer.Stop();
1716 // flush the cache
1717 pImp->nCachedFunc1 = 0;
1718 pImp->nCachedFunc2 = 0;
1720 // Mark if the all of the Caches have dissapered.
1721 pImp->bCtrlReleased = false;
1724 return nRegLevel;
1728 void SfxBindings::LeaveRegistrations( sal_uInt16 nLevel, const char *pFile, int nLine )
1730 (void)nLevel; // unused variable
1731 DBG_ASSERT( nRegLevel, "Leave without Enter" );
1732 DBG_ASSERT( nLevel == USHRT_MAX || nLevel == nRegLevel, "wrong Leave" );
1734 // Only when the SubBindings are still locked by the Superbindings,
1735 // remove this lock (i.e. if there are more locks than "real" ones)
1736 if ( pImp->pSubBindings && pImp->pSubBindings->nRegLevel > pImp->pSubBindings->pImp->nOwnRegLevel )
1738 // Synchronize Bindings
1739 pImp->pSubBindings->nRegLevel = nRegLevel + pImp->pSubBindings->pImp->nOwnRegLevel;
1741 // This LeaveRegistrations is not "real" for SubBindings
1742 pImp->pSubBindings->pImp->nOwnRegLevel++;
1743 pImp->pSubBindings->LEAVEREGISTRATIONS();
1746 pImp->nOwnRegLevel--;
1748 // check if this is the outer most level
1749 if ( --nRegLevel == 0 && !SfxGetpApp()->IsDowning() )
1751 if ( pImp->bContextChanged )
1753 pImp->bContextChanged = false;
1756 SfxViewFrame* pFrame = pDispatcher->GetFrame();
1758 // If possible remove unused Caches, for example prepare PlugInInfo
1759 if ( pImp->bCtrlReleased )
1761 for ( sal_uInt16 nCache = pImp->pCaches->size(); nCache > 0; --nCache )
1763 // Get Cache via ::com::sun::star::sdbcx::Index
1764 SfxStateCache *pCache = (*pImp->pCaches)[nCache-1];
1766 // No interested Controller present
1767 if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() )
1769 // Remove Cache. Safety: first remove and then delete
1770 pImp->pCaches->erase(pImp->pCaches->begin() + nCache - 1);
1771 delete pCache;
1776 // restart background-processing
1777 pImp->nMsgPos = 0;
1778 if ( !pFrame || !pFrame->GetObjectShell() )
1779 return;
1780 if ( pImp->pCaches && !pImp->pCaches->empty() )
1782 pImp->aTimer.Stop();
1783 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
1784 pImp->aTimer.Start();
1788 SAL_INFO(
1789 "sfx.control",
1790 std::setw(std::min(nRegLevel, sal_uInt16(8))) << ' ' << "this = " << this
1791 << " Level = " << nRegLevel << " SfxBindings::LeaveRegistrations "
1792 << (pFile
1793 ? SAL_STREAM("File: " << pFile << " Line: " << nLine) : ""));
1798 void SfxBindings::SetDispatcher( SfxDispatcher *pDisp )
1800 SfxDispatcher *pOldDispat = pDispatcher;
1801 if ( pDisp != pDispatcher )
1803 if ( pOldDispat )
1805 SfxBindings* pBind = pOldDispat->GetBindings();
1806 while ( pBind )
1808 if ( pBind->pImp->pSubBindings == this && pBind->pDispatcher != pDisp )
1809 pBind->SetSubBindings_Impl( NULL );
1810 pBind = pBind->pImp->pSubBindings;
1814 pDispatcher = pDisp;
1816 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider > xProv;
1817 if ( pDisp )
1818 xProv = ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider >
1819 ( pDisp->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY );
1821 SetDispatchProvider_Impl( xProv );
1822 InvalidateAll( true );
1823 InvalidateUnoControllers_Impl();
1825 if ( pDispatcher && !pOldDispat )
1827 if ( pImp->pSubBindings && pImp->pSubBindings->pDispatcher != pOldDispat )
1829 OSL_FAIL( "SubBindings already set before activating!" );
1830 pImp->pSubBindings->ENTERREGISTRATIONS();
1832 LEAVEREGISTRATIONS();
1834 else if( !pDispatcher )
1836 ENTERREGISTRATIONS();
1837 if ( pImp->pSubBindings && pImp->pSubBindings->pDispatcher != pOldDispat )
1839 OSL_FAIL( "SubBindings still set even when deactivating!" );
1840 pImp->pSubBindings->LEAVEREGISTRATIONS();
1844 Broadcast( SfxSimpleHint( SFX_HINT_DATACHANGED ) );
1846 if ( pDisp )
1848 SfxBindings* pBind = pDisp->GetBindings();
1849 while ( pBind && pBind != this )
1851 if ( !pBind->pImp->pSubBindings )
1853 pBind->SetSubBindings_Impl( this );
1854 break;
1857 pBind = pBind->pImp->pSubBindings;
1865 void SfxBindings::ClearCache_Impl( sal_uInt16 nSlotId )
1867 SfxStateCache* pCache = GetStateCache(nSlotId);
1868 if (!pCache)
1869 return;
1870 pCache->ClearCache();
1874 void SfxBindings::StartUpdate_Impl( bool bComplete )
1876 if ( pImp->pSubBindings )
1877 pImp->pSubBindings->StartUpdate_Impl( bComplete );
1879 if ( !bComplete )
1880 // Update may be interrupted
1881 NextJob_Impl(&pImp->aTimer);
1882 else
1883 // Update all slots in a row
1884 NextJob_Impl(0);
1889 SfxItemState SfxBindings::QueryState( sal_uInt16 nSlot, SfxPoolItem* &rpState )
1891 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
1892 SfxStateCache *pCache = GetStateCache( nSlot );
1893 if ( pCache )
1894 xDisp = pCache->GetDispatch();
1895 if ( xDisp.is() || !pCache )
1897 const SfxSlot* pSlot = SfxSlotPool::GetSlotPool( pDispatcher->GetFrame() ).GetSlot( nSlot );
1898 if ( !pSlot || !pSlot->pUnoName )
1899 return SfxItemState::DISABLED;
1901 ::com::sun::star::util::URL aURL;
1902 OUString aCmd( ".uno:" );
1903 aURL.Protocol = aCmd;
1904 aURL.Path = OUString::createFromAscii(pSlot->GetUnoName());
1905 aCmd += aURL.Path;
1906 aURL.Complete = aCmd;
1907 aURL.Main = aCmd;
1909 if ( !xDisp.is() )
1910 xDisp = pImp->xProv->queryDispatch( aURL, OUString(), 0 );
1912 if ( xDisp.is() )
1914 ::com::sun::star::uno::Reference< ::com::sun::star::lang::XUnoTunnel > xTunnel( xDisp, ::com::sun::star::uno::UNO_QUERY );
1915 SfxOfficeDispatch* pDisp = NULL;
1916 if ( xTunnel.is() )
1918 sal_Int64 nImplementation = xTunnel->getSomething(SfxOfficeDispatch::impl_getStaticIdentifier());
1919 pDisp = reinterpret_cast< SfxOfficeDispatch* >( sal::static_int_cast< sal_IntPtr >( nImplementation ));
1922 if ( !pDisp )
1924 bool bDeleteCache = false;
1925 if ( !pCache )
1927 pCache = new SfxStateCache( nSlot );
1928 pCache->GetSlotServer( *GetDispatcher_Impl(), pImp->xProv );
1929 bDeleteCache = true;
1932 SfxItemState eState = SfxItemState::SET;
1933 SfxPoolItem *pItem=NULL;
1934 BindDispatch_Impl *pBind = new BindDispatch_Impl( xDisp, aURL, pCache, pSlot );
1935 pBind->acquire();
1936 xDisp->addStatusListener( pBind, aURL );
1937 if ( !pBind->GetStatus().IsEnabled )
1939 eState = SfxItemState::DISABLED;
1941 else
1943 ::com::sun::star::uno::Any aAny = pBind->GetStatus().State;
1944 ::com::sun::star::uno::Type pType = aAny.getValueType();
1946 if ( pType == cppu::UnoType<bool>::get() )
1948 bool bTemp = false;
1949 aAny >>= bTemp ;
1950 pItem = new SfxBoolItem( nSlot, bTemp );
1952 else if ( pType == ::cppu::UnoType< ::cppu::UnoUnsignedShortType >::get() )
1954 sal_uInt16 nTemp = 0;
1955 aAny >>= nTemp ;
1956 pItem = new SfxUInt16Item( nSlot, nTemp );
1958 else if ( pType == cppu::UnoType<sal_uInt32>::get() )
1960 sal_uInt32 nTemp = 0;
1961 aAny >>= nTemp ;
1962 pItem = new SfxUInt32Item( nSlot, nTemp );
1964 else if ( pType == cppu::UnoType<OUString>::get() )
1966 OUString sTemp ;
1967 aAny >>= sTemp ;
1968 pItem = new SfxStringItem( nSlot, sTemp );
1970 else
1971 pItem = new SfxVoidItem( nSlot );
1974 xDisp->removeStatusListener( pBind, aURL );
1975 pBind->Release();
1976 rpState = pItem;
1977 if ( bDeleteCache )
1978 DELETEZ( pCache );
1979 return eState;
1984 // Then test at the dispatcher to check if the returned items from
1985 // there are always DELETE_ON_IDLE, a copy of it has to be made in
1986 // order to allow for transition of ownership.
1987 const SfxPoolItem *pItem = NULL;
1988 SfxItemState eState = pDispatcher->QueryState( nSlot, pItem );
1989 if ( eState == SfxItemState::SET )
1991 DBG_ASSERT( pItem, "SfxItemState::SET but no item!" );
1992 if ( pItem )
1993 rpState = pItem->Clone();
1995 else if ( eState == SfxItemState::DEFAULT && pItem )
1997 rpState = pItem->Clone();
2000 return eState;
2003 void SfxBindings::SetSubBindings_Impl( SfxBindings *pSub )
2005 if ( pImp->pSubBindings )
2007 pImp->pSubBindings->SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > () );
2008 pImp->pSubBindings->pImp->pSuperBindings = NULL;
2011 pImp->pSubBindings = pSub;
2013 if ( pSub )
2015 pImp->pSubBindings->SetDispatchProvider_Impl( pImp->xProv );
2016 pSub->pImp->pSuperBindings = this;
2020 SfxBindings* SfxBindings::GetSubBindings_Impl( bool bTop ) const
2022 SfxBindings *pRet = pImp->pSubBindings;
2023 if ( bTop )
2025 while ( pRet->pImp->pSubBindings )
2026 pRet = pRet->pImp->pSubBindings;
2029 return pRet;
2032 void SfxBindings::SetWorkWindow_Impl( SfxWorkWindow* pWork )
2034 pImp->pWorkWin = pWork;
2037 SfxWorkWindow* SfxBindings::GetWorkWindow_Impl() const
2039 return pImp->pWorkWin;
2042 void SfxBindings::RegisterUnoController_Impl( SfxUnoControllerItem* pControl )
2044 if ( !pImp->pUnoCtrlArr )
2045 pImp->pUnoCtrlArr = new SfxUnoControllerArr_Impl;
2046 pImp->pUnoCtrlArr->push_back( pControl );
2049 void SfxBindings::ReleaseUnoController_Impl( SfxUnoControllerItem* pControl )
2051 if ( pImp->pUnoCtrlArr )
2053 SfxUnoControllerArr_Impl::iterator it = std::find(
2054 pImp->pUnoCtrlArr->begin(), pImp->pUnoCtrlArr->end(), pControl );
2055 if ( it != pImp->pUnoCtrlArr->end() )
2057 pImp->pUnoCtrlArr->erase( it );
2058 return;
2062 if ( pImp->pSubBindings )
2063 pImp->pSubBindings->ReleaseUnoController_Impl( pControl );
2066 void SfxBindings::InvalidateUnoControllers_Impl()
2068 if ( pImp->pUnoCtrlArr )
2070 sal_uInt16 nCount = pImp->pUnoCtrlArr->size();
2071 for ( sal_uInt16 n=nCount; n>0; n-- )
2073 SfxUnoControllerItem *pCtrl = (*pImp->pUnoCtrlArr)[n-1];
2074 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > xRef( (::cppu::OWeakObject*)pCtrl, ::com::sun::star::uno::UNO_QUERY );
2075 pCtrl->ReleaseDispatch();
2076 pCtrl->GetNewDispatch();
2080 if ( pImp->pSubBindings )
2081 pImp->pSubBindings->InvalidateUnoControllers_Impl();
2084 bool SfxBindings::IsInUpdate() const
2086 bool bInUpdate = pImp->bInUpdate;
2087 if ( !bInUpdate && pImp->pSubBindings )
2088 bInUpdate = pImp->pSubBindings->IsInUpdate();
2089 return bInUpdate;
2092 void SfxBindings::SetVisibleState( sal_uInt16 nId, bool bShow )
2094 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
2095 SfxStateCache *pCache = GetStateCache( nId );
2096 if ( pCache )
2097 pCache->SetVisibleState( bShow );
2100 void SfxBindings::SetActiveFrame( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > & rFrame )
2102 if ( rFrame.is() || !pDispatcher )
2103 SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > ( rFrame, ::com::sun::star::uno::UNO_QUERY ) );
2104 else
2105 SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > (
2106 pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), ::com::sun::star::uno::UNO_QUERY ) );
2109 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > SfxBindings::GetActiveFrame() const
2111 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame( pImp->xProv, ::com::sun::star::uno::UNO_QUERY );
2112 if ( xFrame.is() || !pDispatcher )
2113 return xFrame;
2114 else
2115 return pDispatcher->GetFrame()->GetFrame().GetFrameInterface();
2118 void SfxBindings::SetDispatchProvider_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & rProv )
2120 bool bInvalidate = ( rProv != pImp->xProv );
2121 if ( bInvalidate )
2123 pImp->xProv = rProv;
2124 InvalidateAll( true );
2125 InvalidateUnoControllers_Impl();
2128 if ( pImp->pSubBindings )
2129 pImp->pSubBindings->SetDispatchProvider_Impl( pImp->xProv );
2132 bool SfxBindings::ExecuteCommand_Impl( const OUString& rCommand )
2134 ::com::sun::star::util::URL aURL;
2135 aURL.Complete = rCommand;
2136 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
2137 xTrans->parseStrict( aURL );
2138 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp = pImp->xProv->queryDispatch( aURL, OUString(), 0 );
2139 if ( xDisp.is() )
2141 new SfxAsyncExec_Impl( aURL, xDisp );
2142 return true;
2145 return false;
2148 com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder > SfxBindings::GetRecorder() const
2150 return pImp->xRecorder;
2153 void SfxBindings::SetRecorder_Impl( com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder >& rRecorder )
2155 pImp->xRecorder = rRecorder;
2158 void SfxBindings::ContextChanged_Impl()
2160 if ( !pImp->bInUpdate && ( !pImp->bContextChanged || !pImp->bAllMsgDirty ) )
2162 InvalidateAll( true );
2166 uno::Reference < frame::XDispatch > SfxBindings::GetDispatch( const SfxSlot* pSlot, const util::URL& aURL, bool bMasterCommand )
2168 uno::Reference < frame::XDispatch > xRet;
2169 SfxStateCache* pCache = GetStateCache( pSlot->nSlotId );
2170 if ( pCache && !bMasterCommand )
2171 xRet = pCache->GetInternalDispatch();
2172 if ( !xRet.is() )
2174 // dispatches for slaves are unbound, they don't have a state
2175 SfxOfficeDispatch* pDispatch = bMasterCommand ?
2176 new SfxOfficeDispatch( pDispatcher, pSlot, aURL ) :
2177 new SfxOfficeDispatch( *this, pDispatcher, pSlot, aURL );
2179 pDispatch->SetMasterUnoCommand( bMasterCommand );
2180 xRet = uno::Reference < frame::XDispatch >( pDispatch );
2181 if ( !pCache )
2182 pCache = GetStateCache( pSlot->nSlotId );
2184 DBG_ASSERT( pCache, "No cache for OfficeDispatch!" );
2185 if ( pCache && !bMasterCommand )
2186 pCache->SetInternalDispatch( xRet );
2189 return xRet;
2192 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */