Bump version to 4.1-6
[LibreOffice.git] / sfx2 / source / control / bindings.cxx
blob5735738dd87ef0141dc35a1fb200f7a8e1111856
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 <boost/unordered_map.hpp>
25 #include <sal/log.hxx>
26 #include <svl/itempool.hxx>
27 #include <svl/itemiter.hxx>
28 #include <svl/eitem.hxx>
29 #include <svl/aeitem.hxx>
30 #include <svl/intitem.hxx>
31 #include <svl/stritem.hxx>
32 #include <svl/visitem.hxx>
33 #include <com/sun/star/util/URLTransformer.hpp>
34 #include <com/sun/star/util/XURLTransformer.hpp>
35 #include <com/sun/star/frame/XDispatchProviderInterceptor.hpp>
36 #include <com/sun/star/frame/XDispatch.hpp>
37 #include <com/sun/star/frame/XDispatchProvider.hpp>
38 #include <com/sun/star/frame/XStatusListener.hpp>
39 #include <com/sun/star/frame/FrameSearchFlag.hpp>
40 #include <com/sun/star/frame/XDispatchProviderInterception.hpp>
41 #include <com/sun/star/frame/FeatureStateEvent.hpp>
42 #include <com/sun/star/frame/DispatchDescriptor.hpp>
43 #include <com/sun/star/frame/XController.hpp>
44 #include <comphelper/processfactory.hxx>
45 #include <svtools/itemdel.hxx>
47 //Includes below due to nInReschedule
48 #include "appdata.hxx"
49 #include <sfx2/bindings.hxx>
50 #include <sfx2/msg.hxx>
51 #include "statcach.hxx"
52 #include <sfx2/ctrlitem.hxx>
53 #include <sfx2/app.hxx>
54 #include <sfx2/dispatch.hxx>
55 #include <sfx2/request.hxx>
56 #include <sfx2/objface.hxx>
57 #include "sfxtypes.hxx"
58 #include "workwin.hxx"
59 #include <sfx2/unoctitm.hxx>
60 #include <sfx2/sfx.hrc>
61 #include <sfx2/sfxuno.hxx>
62 #include <sfx2/viewfrm.hxx>
63 #include <sfx2/objsh.hxx>
64 #include <sfx2/msgpool.hxx>
66 #include <com/sun/star/frame/XModuleManager.hpp>
68 #include <boost/scoped_ptr.hpp>
70 using namespace ::com::sun::star;
71 using namespace ::com::sun::star::uno;
72 using namespace ::com::sun::star::util;
74 DBG_NAME(SfxBindingsMsgPos)
75 DBG_NAME(SfxBindingsUpdateServers)
76 DBG_NAME(SfxBindingsCreateSet)
77 DBG_NAME(SfxBindingsUpdateCtrl1)
78 DBG_NAME(SfxBindingsUpdateCtrl2)
79 DBG_NAME(SfxBindingsNextJob_Impl0)
80 DBG_NAME(SfxBindingsNextJob_Impl)
81 DBG_NAME(SfxBindingsUpdate_Impl)
82 DBG_NAME(SfxBindingsInvalidateAll)
84 //====================================================================
86 static sal_uInt16 nTimeOut = 300;
88 #define TIMEOUT_FIRST nTimeOut
89 #define TIMEOUT_UPDATING 20
90 #define TIMEOUT_IDLE 2500
92 typedef boost::unordered_map< sal_uInt16, bool > InvalidateSlotMap;
94 //====================================================================
96 typedef std::vector<SfxStateCache*> SfxStateCacheArr_Impl;
98 //====================================================================
100 class SfxAsyncExec_Impl
102 ::com::sun::star::util::URL aCommand;
103 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
104 Timer aTimer;
106 public:
108 SfxAsyncExec_Impl( const ::com::sun::star::util::URL& rCmd, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch >& rDisp )
109 : aCommand( rCmd )
110 , xDisp( rDisp )
112 aTimer.SetTimeoutHdl( LINK(this, SfxAsyncExec_Impl, TimerHdl) );
113 aTimer.SetTimeout( 0 );
114 aTimer.Start();
117 DECL_LINK( TimerHdl, Timer*);
120 IMPL_LINK(SfxAsyncExec_Impl, TimerHdl, Timer*, pTimer)
122 (void)pTimer; // unused
123 aTimer.Stop();
125 Sequence<beans::PropertyValue> aSeq;
126 xDisp->dispatch( aCommand, aSeq );
128 delete this;
129 return 0L;
132 class SfxBindings_Impl
134 public:
135 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchRecorder > xRecorder;
136 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv;
137 SfxUnoControllerArr_Impl*
138 pUnoCtrlArr;
139 SfxWorkWindow* pWorkWin;
140 SfxBindings* pSubBindings;
141 SfxBindings* pSuperBindings;
142 SfxStateCacheArr_Impl* pCaches; // One chache for each binding
143 sal_uInt16 nCachedFunc1; // index for the last one called
144 sal_uInt16 nCachedFunc2; // index for the second last called
145 sal_uInt16 nMsgPos; // Message-Position relative the one to be updated
146 SfxPopupAction ePopupAction; // Checked in DeleteFloatinWindow()
147 sal_Bool bContextChanged;
148 sal_Bool bMsgDirty; // Has a MessageServer been invalidated?
149 sal_Bool bAllMsgDirty; // Has a MessageServer been invalidated?
150 sal_Bool bAllDirty; // After InvalidateAll
151 sal_Bool bCtrlReleased; // while EnterRegistrations
152 AutoTimer aTimer; // for volatile Slots
153 sal_Bool bInUpdate; // for Assertions
154 sal_Bool bInNextJob; // for Assertions
155 sal_Bool bFirstRound; // First round in Update
156 sal_uInt16 nFirstShell; // Shell, the first round is prefered
157 sal_uInt16 nOwnRegLevel; // Counts the real Locks, exept those of the Super Bindings
158 InvalidateSlotMap m_aInvalidateSlots; // store slots which are invalidated while in update
161 //--------------------------------------------------------------------
163 struct SfxFoundCache_Impl
165 sal_uInt16 nSlotId; // the Slot-Id
166 sal_uInt16 nWhichId; // If available: Which-Id, else: nSlotId
167 const SfxSlot* pSlot; // Pointer to <Master-Slot>
168 SfxStateCache* pCache; // Pointer to StatusCache, if possible NULL
170 SfxFoundCache_Impl():
171 nSlotId(0),
172 nWhichId(0),
173 pSlot(0),
174 pCache(0)
177 SfxFoundCache_Impl(SfxFoundCache_Impl&r):
178 nSlotId(r.nSlotId),
179 nWhichId(r.nWhichId),
180 pSlot(r.pSlot),
181 pCache(r.pCache)
184 SfxFoundCache_Impl(sal_uInt16 nS, sal_uInt16 nW, const SfxSlot *pS, SfxStateCache *pC ):
185 nSlotId(nS),
186 nWhichId(nW),
187 pSlot(pS),
188 pCache(pC)
191 int operator<( const SfxFoundCache_Impl &r ) const
192 { return nWhichId < r.nWhichId; }
194 int operator==( const SfxFoundCache_Impl &r ) const
195 { return nWhichId== r.nWhichId; }
198 //--------------------------------------------------------------------------
200 class SfxFoundCacheArr_Impl : public std::vector<SfxFoundCache_Impl*>
202 public:
203 ~SfxFoundCacheArr_Impl()
205 for(const_iterator it = begin(); it != end(); ++it)
206 delete *it;
210 //==========================================================================
212 SfxBindings::SfxBindings()
213 : pImp(new SfxBindings_Impl),
214 pDispatcher(0),
215 nRegLevel(1) // first becomes 0, when the Dispatcher is set
217 pImp->nMsgPos = 0;
218 pImp->bAllMsgDirty = sal_True;
219 pImp->bContextChanged = sal_False;
220 pImp->bMsgDirty = sal_True;
221 pImp->bAllDirty = sal_True;
222 pImp->ePopupAction = SFX_POPUP_DELETE;
223 pImp->nCachedFunc1 = 0;
224 pImp->nCachedFunc2 = 0;
225 pImp->bCtrlReleased = sal_False;
226 pImp->bFirstRound = sal_False;
227 pImp->bInNextJob = sal_False;
228 pImp->bInUpdate = sal_False;
229 pImp->pSubBindings = NULL;
230 pImp->pSuperBindings = NULL;
231 pImp->pWorkWin = NULL;
232 pImp->pUnoCtrlArr = NULL;
233 pImp->nOwnRegLevel = nRegLevel;
235 // all caches are valid (no pending invalidate-job)
236 // create the list of caches
237 pImp->pCaches = new SfxStateCacheArr_Impl;
238 pImp->aTimer.SetTimeoutHdl( LINK(this, SfxBindings, NextJob_Impl) );
241 //====================================================================
243 SfxBindings::~SfxBindings()
245 /* [Description]
247 Destructor of the SfxBindings class. The one, for each <SfxApplication>
248 existing Instance is automatically destroyed by the <SfxApplication>
249 after the execution of <SfxApplication::Exit()>.
251 The still existing <SfxControllerItem> instances, which are registered
252 by the SfxBindings instance, are automatically destroyed in the Destructor.
253 These are usually the Floating-Toolboxen, Value-Sets
254 etc. Arrays of SfxControllerItems may at this time no longer exist.
258 // The SubBindings should not be locked!
259 pImp->pSubBindings = NULL;
261 ENTERREGISTRATIONS();
263 pImp->aTimer.Stop();
264 DeleteControllers_Impl();
266 // Delete Caches
267 for(SfxStateCacheArr_Impl::const_iterator it = pImp->pCaches->begin(); it != pImp->pCaches->end(); ++it)
268 delete *it;
270 DELETEZ( pImp->pWorkWin );
272 delete pImp->pCaches;
273 delete pImp;
276 //--------------------------------------------------------------------
278 void SfxBindings::DeleteControllers_Impl()
280 // in the first round delete SfxPopupWindows
281 sal_uInt16 nCount = pImp->pCaches->size();
282 sal_uInt16 nCache;
283 for ( nCache = 0; nCache < nCount; ++nCache )
285 // Remember were you are
286 SfxStateCache *pCache = (*pImp->pCaches)[nCache];
287 sal_uInt16 nSlotId = pCache->GetId();
289 // Delete SfxPopupWindow
290 pCache->DeleteFloatingWindows();
292 // Re-align, because the cache may have been reduced
293 sal_uInt16 nNewCount = pImp->pCaches->size();
294 if ( nNewCount < nCount )
296 nCache = GetSlotPos(nSlotId);
297 if ( nCache >= nNewCount ||
298 nSlotId != (*pImp->pCaches)[nCache]->GetId() )
299 --nCache;
300 nCount = nNewCount;
304 // Delete all Caches
305 for ( nCache = pImp->pCaches->size(); nCache > 0; --nCache )
307 // Get Cache via ::com::sun::star::sdbcx::Index
308 SfxStateCache *pCache = (*pImp->pCaches)[ nCache-1 ];
310 // unbind all controllers in the cache
311 SfxControllerItem *pNext;
312 for ( SfxControllerItem *pCtrl = pCache->GetItemLink();
313 pCtrl; pCtrl = pNext )
315 pNext = pCtrl->GetItemLink();
316 pCtrl->UnBind();
319 if ( pCache->GetInternalController() )
320 pCache->GetInternalController()->UnBind();
322 // Delete Cache
323 if( nCache-1 < (sal_uInt16) pImp->pCaches->size() )
324 delete (*pImp->pCaches)[nCache-1];
325 pImp->pCaches->erase(pImp->pCaches->begin()+ nCache - 1);
328 if( pImp->pUnoCtrlArr )
330 sal_uInt16 nCtrlCount = pImp->pUnoCtrlArr->size();
331 for ( sal_uInt16 n=nCtrlCount; n>0; n-- )
333 SfxUnoControllerItem *pCtrl = (*pImp->pUnoCtrlArr)[n-1];
334 pCtrl->ReleaseBindings();
337 DBG_ASSERT( !pImp->pUnoCtrlArr->size(), "Do not remove UnoControllerItems!" );
338 DELETEZ( pImp->pUnoCtrlArr );
342 //--------------------------------------------------------------------
344 void SfxBindings::HidePopups( bool bHide )
346 // Hide SfxPopupWindows
347 HidePopupCtrls_Impl( bHide );
348 SfxBindings *pSub = pImp->pSubBindings;
349 while ( pSub )
351 pImp->pSubBindings->HidePopupCtrls_Impl( bHide );
352 pSub = pSub->pImp->pSubBindings;
355 // Hide SfxChildWindows
356 DBG_ASSERT( pDispatcher, "HidePopups not allowed without dispatcher" );
357 if ( pImp->pWorkWin )
358 pImp->pWorkWin->HidePopups_Impl( bHide, sal_True );
361 void SfxBindings::HidePopupCtrls_Impl( bool bHide )
363 if ( bHide )
365 // Hide SfxPopupWindows
366 pImp->ePopupAction = SFX_POPUP_HIDE;
368 else
370 // Show SfxPopupWindows
371 pImp->ePopupAction = SFX_POPUP_SHOW;
374 for(SfxStateCacheArr_Impl::const_iterator it = pImp->pCaches->begin(); it != pImp->pCaches->end(); ++it)
375 (*it)->DeleteFloatingWindows();
376 pImp->ePopupAction = SFX_POPUP_DELETE;
379 //--------------------------------------------------------------------
381 void SfxBindings::Update_Impl
383 SfxStateCache* pCache // The up to date SfxStatusCache
386 if( pCache->GetDispatch().is() && pCache->GetItemLink() )
388 pCache->SetCachedState(sal_True);
389 if ( !pCache->GetInternalController() )
390 return;
393 if ( !pDispatcher )
394 return;
395 DBG_PROFSTART(SfxBindingsUpdate_Impl);
397 // gather together all with the same status method which are dirty
398 SfxDispatcher &rDispat = *pDispatcher;
399 const SfxSlot *pRealSlot = 0;
400 const SfxSlotServer* pMsgServer = 0;
401 SfxFoundCacheArr_Impl aFound;
402 SfxItemSet *pSet = CreateSet_Impl( pCache, pRealSlot, &pMsgServer, aFound );
403 sal_Bool bUpdated = sal_False;
404 if ( pSet )
406 // Query Status
407 if ( rDispat._FillState( *pMsgServer, *pSet, pRealSlot ) )
409 // Post Status
410 const SfxInterface *pInterface =
411 rDispat.GetShell(pMsgServer->GetShellLevel())->GetInterface();
412 for ( sal_uInt16 nPos = 0; nPos < aFound.size(); ++nPos )
414 const SfxFoundCache_Impl *pFound = aFound[nPos];
415 sal_uInt16 nWhich = pFound->nWhichId;
416 const SfxPoolItem *pItem = 0;
417 SfxItemState eState = pSet->GetItemState(nWhich, sal_True, &pItem);
418 if ( eState == SFX_ITEM_DEFAULT && SfxItemPool::IsWhich(nWhich) )
419 pItem = &pSet->Get(nWhich);
420 UpdateControllers_Impl( pInterface, aFound[nPos], pItem, eState );
422 bUpdated = sal_True;
425 delete pSet;
428 if ( !bUpdated && pCache )
430 // When pCache == NULL and no SlotServer
431 // (for example due to locked Dispatcher! ),
432 // obviously do not try to update
433 SfxFoundCache_Impl aFoundCache(
434 pCache->GetId(), 0,
435 pRealSlot, pCache );
436 UpdateControllers_Impl( 0, &aFoundCache, 0, SFX_ITEM_DISABLED);
439 DBG_PROFSTOP(SfxBindingsUpdate_Impl);
442 //--------------------------------------------------------------------
444 void SfxBindings::InvalidateSlotsInMap_Impl()
446 InvalidateSlotMap::const_iterator pIter = pImp->m_aInvalidateSlots.begin();
447 while ( pIter != pImp->m_aInvalidateSlots.end() )
449 Invalidate( pIter->first );
450 ++pIter;
452 pImp->m_aInvalidateSlots.clear();
455 //--------------------------------------------------------------------
457 void SfxBindings::AddSlotToInvalidateSlotsMap_Impl( sal_uInt16 nId )
459 pImp->m_aInvalidateSlots[nId] = sal_True;
462 //--------------------------------------------------------------------
464 void SfxBindings::Update
466 sal_uInt16 nId // the bound and up-to-date Slot-Id
469 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
471 if ( pDispatcher )
472 pDispatcher->Flush();
474 if ( pImp->pSubBindings )
475 pImp->pSubBindings->Update( nId );
477 SfxStateCache* pCache = GetStateCache( nId );
478 if ( pCache )
480 pImp->bInUpdate = sal_True;
481 if ( pImp->bMsgDirty )
483 UpdateSlotServer_Impl();
484 pCache = GetStateCache( nId );
487 if (pCache)
489 sal_Bool bInternalUpdate = sal_True;
490 if( pCache->GetDispatch().is() && pCache->GetItemLink() )
492 pCache->SetCachedState(sal_True);
493 bInternalUpdate = ( pCache->GetInternalController() != 0 );
496 if ( bInternalUpdate )
498 // Query Status
499 const SfxSlotServer* pMsgServer = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
500 if ( !pCache->IsControllerDirty() &&
501 ( !pMsgServer ||
502 !pMsgServer->GetSlot()->IsMode(SFX_SLOT_VOLATILE) ) )
504 pImp->bInUpdate = sal_False;
505 InvalidateSlotsInMap_Impl();
506 return;
508 if (!pMsgServer)
510 pCache->SetState(SFX_ITEM_DISABLED, 0);
511 pImp->bInUpdate = sal_False;
512 InvalidateSlotsInMap_Impl();
513 return;
516 Update_Impl(pCache);
519 pImp->bAllDirty = sal_False;
522 pImp->bInUpdate = sal_False;
523 InvalidateSlotsInMap_Impl();
527 //--------------------------------------------------------------------
529 void SfxBindings::Update()
531 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
533 if ( pImp->pSubBindings )
534 pImp->pSubBindings->Update();
536 if ( pDispatcher )
538 if ( nRegLevel )
539 return;
541 pImp->bInUpdate = sal_True;
542 pDispatcher->Flush();
543 pDispatcher->Update_Impl();
544 while ( !NextJob_Impl(0) )
545 ; // loop
546 pImp->bInUpdate = sal_False;
547 InvalidateSlotsInMap_Impl();
551 //--------------------------------------------------------------------
553 void SfxBindings::SetState
555 const SfxItemSet& rSet // status values to be set
558 // when locked then only invalidate
559 if ( nRegLevel )
561 SfxItemIter aIter(rSet);
562 for ( const SfxPoolItem *pItem = aIter.FirstItem();
563 pItem;
564 pItem = aIter.NextItem() )
565 Invalidate( pItem->Which() );
567 else
569 // Status may be accepted only if all slot-pointers are set
570 if ( pImp->bMsgDirty )
571 UpdateSlotServer_Impl();
573 // Iterate over the itemset, update if the slot bound
574 //! Bug: Use WhichIter and possibly send VoidItems up
575 SfxItemIter aIter(rSet);
576 for ( const SfxPoolItem *pItem = aIter.FirstItem();
577 pItem;
578 pItem = aIter.NextItem() )
580 SfxStateCache* pCache =
581 GetStateCache( rSet.GetPool()->GetSlotId(pItem->Which()) );
582 if ( pCache )
584 // Update status
585 if ( !pCache->IsControllerDirty() )
586 pCache->Invalidate(sal_False);
587 pCache->SetState( SFX_ITEM_AVAILABLE, pItem );
589 //! Not implemented: Updates from EnumSlots via master slots
595 //--------------------------------------------------------------------
597 void SfxBindings::SetState
599 const SfxPoolItem& rItem // Status value to be set
602 if ( nRegLevel )
604 Invalidate( rItem.Which() );
606 else
608 // Status may be accepted only if all slot-pointers are set
609 if ( pImp->bMsgDirty )
610 UpdateSlotServer_Impl();
612 //update if the slot bound
613 DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ),
614 "cannot set items with which-id" );
615 SfxStateCache* pCache = GetStateCache( rItem.Which() );
616 if ( pCache )
618 // Update Status
619 if ( !pCache->IsControllerDirty() )
620 pCache->Invalidate(sal_False);
621 pCache->SetState( SFX_ITEM_AVAILABLE, &rItem );
623 //! Not implemented: Updates from EnumSlots via master slots
629 //--------------------------------------------------------------------
631 SfxStateCache* SfxBindings::GetAnyStateCache_Impl( sal_uInt16 nId )
633 SfxStateCache* pCache = GetStateCache( nId );
634 if ( !pCache && pImp->pSubBindings )
635 return pImp->pSubBindings->GetAnyStateCache_Impl( nId );
636 return pCache;
639 SfxStateCache* SfxBindings::GetStateCache
641 sal_uInt16 nId /* Slot-Id, which SfxStatusCache is to be found */
644 return GetStateCache(nId, 0);
647 SfxStateCache* SfxBindings::GetStateCache
649 sal_uInt16 nId, /* Slot-Id, which SfxStatusCache is to be found */
650 sal_uInt16* pPos /* NULL for instance the position from which the
651 bindings are to be searched binary. Returns the
652 position back for where the nId was found,
653 or where it was inserted. */
656 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
657 // is the specified function bound?
658 const sal_uInt16 nStart = ( pPos ? *pPos : 0 );
659 const sal_uInt16 nPos = GetSlotPos( nId, nStart );
661 if ( nPos < pImp->pCaches->size() &&
662 (*pImp->pCaches)[nPos]->GetId() == nId )
664 if ( pPos )
665 *pPos = nPos;
666 return (*pImp->pCaches)[nPos];
668 return 0;
671 //--------------------------------------------------------------------
673 void SfxBindings::InvalidateAll
675 sal_Bool bWithMsg /* sal_True Mark Slot Server as invalid
676 sal_False Slot Server remains valid */
679 DBG_PROFSTART(SfxBindingsInvalidateAll);
680 DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
682 if ( pImp->pSubBindings )
683 pImp->pSubBindings->InvalidateAll( bWithMsg );
685 // everything is already set dirty or downing => nothing to do
686 if ( !pDispatcher ||
687 ( pImp->bAllDirty && ( !bWithMsg || pImp->bAllMsgDirty ) ) ||
688 SFX_APP()->IsDowning() )
690 DBG_PROFSTOP(SfxBindingsInvalidateAll);
691 return;
694 pImp->bAllMsgDirty = pImp->bAllMsgDirty || bWithMsg;
695 pImp->bMsgDirty = pImp->bMsgDirty || pImp->bAllMsgDirty || bWithMsg;
696 pImp->bAllDirty = sal_True;
698 for ( sal_uInt16 n = 0; n < pImp->pCaches->size(); ++n )
699 (*pImp->pCaches)[n]->Invalidate(bWithMsg);
701 pImp->nMsgPos = 0;
702 if ( !nRegLevel )
704 pImp->aTimer.Stop();
705 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
706 pImp->aTimer.Start();
709 DBG_PROFSTOP(SfxBindingsInvalidateAll);
712 //--------------------------------------------------------------------
714 void SfxBindings::Invalidate
716 const sal_uInt16* pIds /* numerically sorted NULL-terminated array of
717 slot IDs (individual, not as a couple!) */
720 DBG_PROFSTART(SfxBindingsInvalidateAll);
722 if ( pImp->bInUpdate )
724 sal_Int32 i = 0;
725 while ( pIds[i] != 0 )
726 AddSlotToInvalidateSlotsMap_Impl( pIds[i++] );
728 if ( pImp->pSubBindings )
729 pImp->pSubBindings->Invalidate( pIds );
730 return;
733 if ( pImp->pSubBindings )
734 pImp->pSubBindings->Invalidate( pIds );
736 // everything is already set dirty or downing => nothing to do
737 if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
738 return;
740 // Search binary in always smaller areas
741 for ( sal_uInt16 n = GetSlotPos(*pIds);
742 *pIds && n < pImp->pCaches->size();
743 n = GetSlotPos(*pIds, n) )
745 // If SID is ever bound, then invalidate the cache
746 SfxStateCache *pCache = (*pImp->pCaches)[n];
747 if ( pCache->GetId() == *pIds )
748 pCache->Invalidate(sal_False);
750 // Next SID
751 if ( !*++pIds )
752 break;
753 DBG_ASSERT( *pIds > *(pIds-1), "pIds unsorted" );
756 // if not enticed to start update timer
757 pImp->nMsgPos = 0;
758 if ( !nRegLevel )
760 pImp->aTimer.Stop();
761 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
762 pImp->aTimer.Start();
765 DBG_PROFSTOP(SfxBindingsInvalidateAll);
768 //--------------------------------------------------------------------
770 void SfxBindings::InvalidateShell
772 const SfxShell& rSh, /* <SfxShell>, which Slot-Ids should be
773 invalidated */
774 sal_Bool bDeep /* sal_True
775 also inherited slot IDs of SfxShell are invalidert
777 sal_False
778 the inherited and not overloaded Slot-Ids were
779 invalidiert */
780 // for now always bDeep
783 DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
785 if ( pImp->pSubBindings )
786 pImp->pSubBindings->InvalidateShell( rSh, bDeep );
788 if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
789 return;
791 DBG_PROFSTART(SfxBindingsInvalidateAll);
793 // flush now already, it is done in GetShellLevel (rsh) anyway,
794 // important so that is set correctly: pimp-> ball(Msg)Dirty
795 pDispatcher->Flush();
797 if ( !pDispatcher ||
798 ( pImp->bAllDirty && pImp->bAllMsgDirty ) ||
799 SFX_APP()->IsDowning() )
801 // if the next one is anyway, then all the servers are collected
802 return;
805 // Find Level
806 sal_uInt16 nLevel = pDispatcher->GetShellLevel(rSh);
807 if ( nLevel != USHRT_MAX )
809 for ( sal_uInt16 n = 0; n < pImp->pCaches->size(); ++n )
811 SfxStateCache *pCache = (*pImp->pCaches)[n];
812 const SfxSlotServer *pMsgServer =
813 pCache->GetSlotServer(*pDispatcher, pImp->xProv);
814 if ( pMsgServer && pMsgServer->GetShellLevel() == nLevel )
815 pCache->Invalidate(sal_False);
817 pImp->nMsgPos = 0;
818 if ( !nRegLevel )
820 pImp->aTimer.Stop();
821 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
822 pImp->aTimer.Start();
823 pImp->bFirstRound = sal_True;
824 pImp->nFirstShell = nLevel;
828 DBG_PROFSTOP(SfxBindingsInvalidateAll);
831 //--------------------------------------------------------------------
833 void SfxBindings::Invalidate
835 sal_uInt16 nId // Status value to be set
838 if ( pImp->bInUpdate )
840 AddSlotToInvalidateSlotsMap_Impl( nId );
841 if ( pImp->pSubBindings )
842 pImp->pSubBindings->Invalidate( nId );
843 return;
846 if ( pImp->pSubBindings )
847 pImp->pSubBindings->Invalidate( nId );
849 if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
850 return;
852 SfxStateCache* pCache = GetStateCache(nId);
853 if ( pCache )
855 pCache->Invalidate(sal_False);
856 pImp->nMsgPos = std::min(GetSlotPos(nId), pImp->nMsgPos);
857 if ( !nRegLevel )
859 pImp->aTimer.Stop();
860 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
861 pImp->aTimer.Start();
866 //--------------------------------------------------------------------
868 void SfxBindings::Invalidate
870 sal_uInt16 nId, // Status value to be set
871 sal_Bool bWithItem, // Clear StateCache?
872 sal_Bool bWithMsg // Get new SlotServer?
875 DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
877 if ( pImp->pSubBindings )
878 pImp->pSubBindings->Invalidate( nId, bWithItem, bWithMsg );
880 if ( SFX_APP()->IsDowning() )
881 return;
883 SfxStateCache* pCache = GetStateCache(nId);
884 if ( pCache )
886 if ( bWithItem )
887 pCache->ClearCache();
888 pCache->Invalidate(bWithMsg);
890 if ( !pDispatcher || pImp->bAllDirty )
891 return;
893 pImp->nMsgPos = std::min(GetSlotPos(nId), pImp->nMsgPos);
894 if ( !nRegLevel )
896 pImp->aTimer.Stop();
897 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
898 pImp->aTimer.Start();
903 //--------------------------------------------------------------------
905 sal_Bool SfxBindings::IsBound( sal_uInt16 nSlotId, sal_uInt16 nStartSearchAt )
907 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
908 return GetStateCache(nSlotId, &nStartSearchAt ) != 0;
911 //--------------------------------------------------------------------
913 sal_uInt16 SfxBindings::GetSlotPos( sal_uInt16 nId, sal_uInt16 nStartSearchAt )
915 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
916 DBG_PROFSTART(SfxBindingsMsgPos);
918 // answer immediately if a function-seek comes repeated
919 if ( pImp->nCachedFunc1 < pImp->pCaches->size() &&
920 (*pImp->pCaches)[pImp->nCachedFunc1]->GetId() == nId )
922 DBG_PROFSTOP(SfxBindingsMsgPos);
923 return pImp->nCachedFunc1;
925 if ( pImp->nCachedFunc2 < pImp->pCaches->size() &&
926 (*pImp->pCaches)[pImp->nCachedFunc2]->GetId() == nId )
928 // swap the caches
929 sal_uInt16 nTemp = pImp->nCachedFunc1;
930 pImp->nCachedFunc1 = pImp->nCachedFunc2;
931 pImp->nCachedFunc2 = nTemp;
932 DBG_PROFSTOP(SfxBindingsMsgPos);
933 return pImp->nCachedFunc1;
936 // binary search, if not found, seek to target-position
937 if ( pImp->pCaches->size() <= nStartSearchAt )
939 DBG_PROFSTOP(SfxBindingsMsgPos);
940 return 0;
942 if ( (sal_uInt16) pImp->pCaches->size() == (nStartSearchAt+1) )
944 DBG_PROFSTOP(SfxBindingsMsgPos);
945 return (*pImp->pCaches)[nStartSearchAt]->GetId() >= nId ? 0 : 1;
947 sal_uInt16 nLow = nStartSearchAt;
948 sal_uInt16 nMid = 0;
949 sal_uInt16 nHigh = 0;
950 sal_Bool bFound = sal_False;
951 nHigh = pImp->pCaches->size() - 1;
952 while ( !bFound && nLow <= nHigh )
954 nMid = (nLow + nHigh) >> 1;
955 DBG_ASSERT( nMid < pImp->pCaches->size(), "bsearch is buggy" );
956 int nDiff = (int) nId - (int) ( ((*pImp->pCaches)[nMid])->GetId() );
957 if ( nDiff < 0)
958 { if ( nMid == 0 )
959 break;
960 nHigh = nMid - 1;
962 else if ( nDiff > 0 )
963 { nLow = nMid + 1;
964 if ( nLow == 0 )
965 break;
967 else
968 bFound = sal_True;
970 sal_uInt16 nPos = bFound ? nMid : nLow;
971 DBG_ASSERT( nPos <= pImp->pCaches->size(), "" );
972 DBG_ASSERT( nPos == pImp->pCaches->size() ||
973 nId <= (*pImp->pCaches)[nPos]->GetId(), "" );
974 DBG_ASSERT( nPos == nStartSearchAt ||
975 nId > (*pImp->pCaches)[nPos-1]->GetId(), "" );
976 DBG_ASSERT( ( (nPos+1) >= (sal_uInt16) pImp->pCaches->size() ) ||
977 nId < (*pImp->pCaches)[nPos+1]->GetId(), "" );
978 pImp->nCachedFunc2 = pImp->nCachedFunc1;
979 pImp->nCachedFunc1 = nPos;
980 DBG_PROFSTOP(SfxBindingsMsgPos);
981 return nPos;
983 //--------------------------------------------------------------------
984 void SfxBindings::RegisterInternal_Impl( SfxControllerItem& rItem )
986 Register_Impl( rItem, sal_True );
990 void SfxBindings::Register( SfxControllerItem& rItem )
992 Register_Impl( rItem, sal_False );
995 void SfxBindings::Register_Impl( SfxControllerItem& rItem, sal_Bool bInternal )
997 // DBG_ASSERT( nRegLevel > 0, "registration without EnterRegistrations" );
998 DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Register while status-updating" );
1000 // insert new cache if it does not already exist
1001 sal_uInt16 nId = rItem.GetId();
1002 sal_uInt16 nPos = GetSlotPos(nId);
1003 if ( nPos >= pImp->pCaches->size() ||
1004 (*pImp->pCaches)[nPos]->GetId() != nId )
1006 SfxStateCache* pCache = new SfxStateCache(nId);
1007 pImp->pCaches->insert( pImp->pCaches->begin() + nPos, pCache );
1008 DBG_ASSERT( nPos == 0 ||
1009 (*pImp->pCaches)[nPos]->GetId() >
1010 (*pImp->pCaches)[nPos-1]->GetId(), "" );
1011 DBG_ASSERT( (nPos == pImp->pCaches->size()-1) ||
1012 (*pImp->pCaches)[nPos]->GetId() <
1013 (*pImp->pCaches)[nPos+1]->GetId(), "" );
1014 pImp->bMsgDirty = sal_True;
1017 // enqueue the new binding
1018 if ( bInternal )
1020 (*pImp->pCaches)[nPos]->SetInternalController( &rItem );
1022 else
1024 SfxControllerItem *pOldItem = (*pImp->pCaches)[nPos]->ChangeItemLink(&rItem);
1025 rItem.ChangeItemLink(pOldItem);
1029 //--------------------------------------------------------------------
1031 void SfxBindings::Release( SfxControllerItem& rItem )
1033 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1034 DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Release while status-updating" );
1035 ENTERREGISTRATIONS();
1037 // find the bound function
1038 sal_uInt16 nId = rItem.GetId();
1039 sal_uInt16 nPos = GetSlotPos(nId);
1040 SfxStateCache* pCache = (*pImp->pCaches)[nPos];
1041 if ( pCache->GetId() == nId )
1043 if ( pCache->GetInternalController() == &rItem )
1045 pCache->ReleaseInternalController();
1047 else
1049 // is this the first binding in the list?
1050 SfxControllerItem* pItem = pCache->GetItemLink();
1051 if ( pItem == &rItem )
1052 pCache->ChangeItemLink( rItem.GetItemLink() );
1053 else
1055 // search the binding in the list
1056 while ( pItem && pItem->GetItemLink() != &rItem )
1057 pItem = pItem->GetItemLink();
1059 // unlink it if it was found
1060 if ( pItem )
1061 pItem->ChangeItemLink( rItem.GetItemLink() );
1065 // was this the last controller?
1066 if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() )
1068 pImp->bCtrlReleased = sal_True;
1072 LEAVEREGISTRATIONS();
1075 //--------------------------------------------------------------------
1076 const SfxPoolItem* SfxBindings::ExecuteSynchron( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi,
1077 const SfxPoolItem **ppInternalArgs )
1079 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1081 if( !nId || !pDispatcher )
1082 return NULL;
1084 return Execute_Impl( nId, ppItems, nModi, SFX_CALLMODE_SYNCHRON, ppInternalArgs );
1087 sal_Bool SfxBindings::Execute( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode,
1088 const SfxPoolItem **ppInternalArgs )
1090 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1092 if( !nId || !pDispatcher )
1093 return sal_False;
1095 const SfxPoolItem* pRet = Execute_Impl( nId, ppItems, nModi, nCallMode, ppInternalArgs );
1096 return ( pRet != 0 );
1099 const SfxPoolItem* SfxBindings::Execute_Impl( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode,
1100 const SfxPoolItem **ppInternalArgs, sal_Bool bGlobalOnly )
1102 SfxStateCache *pCache = GetStateCache( nId );
1103 if ( !pCache )
1105 SfxBindings *pBind = pImp->pSubBindings;
1106 while ( pBind )
1108 if ( pBind->GetStateCache( nId ) )
1109 return pBind->Execute_Impl( nId, ppItems, nModi, nCallMode, ppInternalArgs, bGlobalOnly );
1110 pBind = pBind->pImp->pSubBindings;
1114 SfxDispatcher &rDispatcher = *pDispatcher;
1115 rDispatcher.Flush();
1116 rDispatcher.GetFrame(); // -Wall is this required???
1118 // get SlotServer (Slot+ShellLevel) and Shell from cache
1119 ::boost::scoped_ptr<SfxStateCache> xCache;
1120 if ( !pCache )
1122 // Execution of non cached slots (Accelerators don't use Controllers)
1123 // slot is uncached, use SlotCache to handle external dispatch providers
1124 xCache.reset(new SfxStateCache(nId));
1125 pCache = xCache.get();
1126 pCache->GetSlotServer( rDispatcher, pImp->xProv );
1129 if ( pCache && pCache->GetDispatch().is() )
1131 DBG_ASSERT( !ppInternalArgs, "Internal args get lost when dispatched!" );
1133 SfxItemPool &rPool = GetDispatcher()->GetFrame()->GetObjectShell()->GetPool();
1134 SfxRequest aReq( nId, nCallMode, rPool );
1135 aReq.SetModifier( nModi );
1136 if( ppItems )
1137 while( *ppItems )
1138 aReq.AppendItem( **ppItems++ );
1140 // cache binds to an external dispatch provider
1141 pCache->Dispatch( aReq.GetArgs(), nCallMode == SFX_CALLMODE_SYNCHRON );
1142 SfxPoolItem *pVoid = new SfxVoidItem( nId );
1143 DeleteItemOnIdle( pVoid );
1144 return pVoid;
1147 // slot is handled internally by SfxDispatcher
1148 if ( pImp->bMsgDirty )
1149 UpdateSlotServer_Impl();
1151 SfxShell *pShell=0;
1152 const SfxSlot *pSlot=0;
1154 // if slot was uncached, we should have created a cache in this method!
1155 DBG_ASSERT( pCache, "This code needs a cache!");
1156 const SfxSlotServer* pServer = pCache ? pCache->GetSlotServer( rDispatcher, pImp->xProv ) : 0;
1157 if ( !pServer )
1159 return NULL;
1161 else
1163 pShell = rDispatcher.GetShell( pServer->GetShellLevel() );
1164 pSlot = pServer->GetSlot();
1167 if ( bGlobalOnly )
1168 if ( !pShell->ISA(SfxModule) && !pShell->ISA(SfxApplication) && !pShell->ISA(SfxViewFrame) )
1169 return NULL;
1171 SfxItemPool &rPool = pShell->GetPool();
1172 SfxRequest aReq( nId, nCallMode, rPool );
1173 aReq.SetModifier( nModi );
1174 if( ppItems )
1175 while( *ppItems )
1176 aReq.AppendItem( **ppItems++ );
1177 if ( ppInternalArgs )
1179 SfxAllItemSet aSet( rPool );
1180 for ( const SfxPoolItem **pArg = ppInternalArgs; *pArg; ++pArg )
1181 aSet.Put( **pArg );
1182 aReq.SetInternalArgs_Impl( aSet );
1185 Execute_Impl( aReq, pSlot, pShell );
1187 const SfxPoolItem* pRet = aReq.GetReturnValue();
1188 if ( !pRet )
1190 SfxPoolItem *pVoid = new SfxVoidItem( nId );
1191 DeleteItemOnIdle( pVoid );
1192 pRet = pVoid;
1195 return pRet;
1198 void SfxBindings::Execute_Impl( SfxRequest& aReq, const SfxSlot* pSlot, SfxShell* pShell )
1200 SfxItemPool &rPool = pShell->GetPool();
1202 if ( SFX_KIND_ENUM == pSlot->GetKind() )
1204 // for Enum-Slots, the Master has to be excecuted with the value
1205 // of the enums
1206 const SfxSlot *pRealSlot = pShell->GetInterface()->GetRealSlot(pSlot);
1207 const sal_uInt16 nSlotId = pRealSlot->GetSlotId();
1208 aReq.SetSlot( nSlotId );
1209 aReq.AppendItem( SfxAllEnumItem( rPool.GetWhich(nSlotId), pSlot->GetValue() ) );
1210 pDispatcher->_Execute( *pShell, *pRealSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD );
1212 else if ( SFX_KIND_ATTR == pSlot->GetKind() )
1214 // Which value has to be mapped for Attribute slots
1215 const sal_uInt16 nSlotId = pSlot->GetSlotId();
1216 aReq.SetSlot( nSlotId );
1217 if ( pSlot->IsMode(SFX_SLOT_TOGGLE) )
1219 // The value is attached to a toggleable attribute (Bools)
1220 sal_uInt16 nWhich = pSlot->GetWhich(rPool);
1221 SfxItemSet aSet(rPool, nWhich, nWhich);
1222 SfxStateFunc aFunc = pSlot->GetStateFnc();
1223 pShell->CallState( aFunc, aSet );
1224 const SfxPoolItem *pOldItem;
1225 SfxItemState eState = aSet.GetItemState(nWhich, sal_True, &pOldItem);
1226 if ( eState == SFX_ITEM_DISABLED )
1227 return;
1229 if ( SFX_ITEM_AVAILABLE == eState && SfxItemPool::IsWhich(nWhich) )
1230 pOldItem = &aSet.Get(nWhich);
1232 if ( SFX_ITEM_SET == eState ||
1233 ( SFX_ITEM_AVAILABLE == eState &&
1234 SfxItemPool::IsWhich(nWhich) &&
1235 pOldItem ) )
1237 if ( pOldItem->ISA(SfxBoolItem) )
1239 // we can toggle Bools
1240 sal_Bool bOldValue = ((const SfxBoolItem *)pOldItem)->GetValue();
1241 SfxBoolItem *pNewItem = (SfxBoolItem*) (pOldItem->Clone());
1242 pNewItem->SetValue( !bOldValue );
1243 aReq.AppendItem( *pNewItem );
1244 delete pNewItem;
1246 else if ( pOldItem->ISA(SfxEnumItemInterface) &&
1247 ((SfxEnumItemInterface *)pOldItem)->HasBoolValue())
1249 // and Enums with Bool-Interface
1250 SfxEnumItemInterface *pNewItem =
1251 (SfxEnumItemInterface*) (pOldItem->Clone());
1252 pNewItem->SetBoolValue(!((SfxEnumItemInterface *)pOldItem)->GetBoolValue());
1253 aReq.AppendItem( *pNewItem );
1254 delete pNewItem;
1256 else {
1257 OSL_FAIL( "Toggle only for Enums and Bools allowed" );
1260 else if ( SFX_ITEM_DONTCARE == eState )
1262 // Create one Status-Item for each Factory
1263 SfxPoolItem *pNewItem = pSlot->GetType()->CreateItem();
1264 DBG_ASSERT( pNewItem, "Toggle to slot without ItemFactory" );
1265 pNewItem->SetWhich( nWhich );
1267 if ( pNewItem->ISA(SfxBoolItem) )
1269 // we can toggle Bools
1270 ((SfxBoolItem*)pNewItem)->SetValue( sal_True );
1271 aReq.AppendItem( *pNewItem );
1273 else if ( pNewItem->ISA(SfxEnumItemInterface) &&
1274 ((SfxEnumItemInterface *)pNewItem)->HasBoolValue())
1276 // and Enums with Bool-Interface
1277 ((SfxEnumItemInterface*)pNewItem)->SetBoolValue(sal_True);
1278 aReq.AppendItem( *pNewItem );
1280 else {
1281 OSL_FAIL( "Toggle only for Enums and Bools allowed" );
1283 delete pNewItem;
1285 else {
1286 OSL_FAIL( "suspicious Toggle-Slot" );
1290 pDispatcher->_Execute( *pShell, *pSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD );
1292 else
1293 pDispatcher->_Execute( *pShell, *pSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD );
1296 //--------------------------------------------------------------------
1298 void SfxBindings::UpdateSlotServer_Impl()
1300 DBG_PROFSTART(SfxBindingsUpdateServers);
1301 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1303 // synchronize
1304 pDispatcher->Flush();
1306 if ( pImp->bAllMsgDirty )
1308 if ( !nRegLevel )
1310 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame
1311 ( pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY );
1312 pImp->bContextChanged = sal_False;
1314 else
1315 pImp->bContextChanged = sal_True;
1318 for (size_t i = 0, nCount = pImp->pCaches->size(); i < nCount; ++i)
1320 SfxStateCache *pCache = (*pImp->pCaches)[i];
1321 //GetSlotServer can modify pImp->pCaches
1322 pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1324 pImp->bMsgDirty = pImp->bAllMsgDirty = sal_False;
1326 Broadcast( SfxSimpleHint(SFX_HINT_DOCCHANGED) );
1328 DBG_PROFSTOP(SfxBindingsUpdateServers);
1331 //--------------------------------------------------------------------
1333 SfxItemSet* SfxBindings::CreateSet_Impl
1335 SfxStateCache*& pCache, // in: Status-Cache from nId
1336 const SfxSlot*& pRealSlot, // out: RealSlot to nId
1337 const SfxSlotServer** pMsgServer, // out: Slot-Server to nId
1338 SfxFoundCacheArr_Impl& rFound // out: List of Caches for Siblings
1341 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1343 DBG_ASSERT( !pImp->bMsgDirty, "CreateSet_Impl with dirty MessageServer" );
1345 const SfxSlotServer* pMsgSvr = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1346 if(!pMsgSvr || !pDispatcher)
1347 return 0;
1349 DBG_PROFSTART(SfxBindingsCreateSet);
1350 pRealSlot = 0;
1351 *pMsgServer = pMsgSvr;
1353 sal_uInt16 nShellLevel = pMsgSvr->GetShellLevel();
1354 SfxShell *pShell = pDispatcher->GetShell( nShellLevel );
1355 if ( !pShell ) // rare GPF when browsing through update from Inet-Notify
1356 return 0;
1358 SfxItemPool &rPool = pShell->GetPool();
1360 // get the status method, which is served by the pCache
1361 SfxStateFunc pFnc = 0;
1362 const SfxInterface *pInterface = pShell->GetInterface();
1363 if ( SFX_KIND_ENUM == pMsgSvr->GetSlot()->GetKind() )
1365 pRealSlot = pInterface->GetRealSlot(pMsgSvr->GetSlot());
1366 pCache = GetStateCache( pRealSlot->GetSlotId() );
1368 else
1369 pRealSlot = pMsgSvr->GetSlot();
1371 // Note: pCache can be NULL!
1373 pFnc = pRealSlot->GetStateFnc();
1375 // the RealSlot is always on
1376 SfxFoundCache_Impl *pFound = new SfxFoundCache_Impl(
1377 pRealSlot->GetSlotId(), pRealSlot->GetWhich(rPool), pRealSlot, pCache );
1378 rFound.push_back( pFound );
1380 sal_uInt16 nSlot = pRealSlot->GetSlotId();
1381 if ( !(nSlot >= SID_VERB_START && nSlot <= SID_VERB_END) )
1383 pInterface = pInterface->GetRealInterfaceForSlot( pRealSlot );
1384 DBG_ASSERT (pInterface,"Slot in the given shell is not found");
1387 // Search through the bindings for slots served by the same function. This , // will only affect slots which are present in the found interface.
1389 // The position of the Statecaches in StateCache-Array
1390 sal_uInt16 nCachePos = pImp->nMsgPos;
1391 const SfxSlot *pSibling = pRealSlot->GetNextSlot();
1393 // the Slots ODF a interfaces ar linked in a circle
1394 while ( pSibling > pRealSlot )
1396 SfxStateFunc pSiblingFnc=0;
1397 SfxStateCache *pSiblingCache =
1398 GetStateCache( pSibling->GetSlotId(), &nCachePos );
1400 // Is the slot cached ?
1401 if ( pSiblingCache )
1403 const SfxSlotServer *pServ = pSiblingCache->GetSlotServer(*pDispatcher, pImp->xProv);
1404 if ( pServ && pServ->GetShellLevel() == nShellLevel )
1405 pSiblingFnc = pServ->GetSlot()->GetStateFnc();
1408 // Does the slot have to be updated at all?
1409 bool bInsert = pSiblingCache && pSiblingCache->IsControllerDirty();
1411 // It is not enough to ask for the same shell!!
1412 bool bSameMethod = pSiblingCache && pFnc == pSiblingFnc;
1414 // If the slot is a non-dirty master slot, then maybe one of his slaves
1415 // is dirty? Then the master slot is still inserted.
1416 if ( !bInsert && bSameMethod && pSibling->GetLinkedSlot() )
1418 // Also check slave slots for Binding
1419 const SfxSlot* pFirstSlave = pSibling->GetLinkedSlot();
1420 for ( const SfxSlot *pSlaveSlot = pFirstSlave;
1421 !bInsert;
1422 pSlaveSlot = pSlaveSlot->GetNextSlot())
1424 // the slaves points to its master
1425 DBG_ASSERT(pSlaveSlot->GetLinkedSlot() == pSibling,
1426 "Wrong Master/Slave relationship!");
1428 sal_uInt16 nCurMsgPos = pImp->nMsgPos;
1429 const SfxStateCache *pSlaveCache =
1430 GetStateCache( pSlaveSlot->GetSlotId(), &nCurMsgPos );
1432 // Is the slave slot chached and dirty ?
1433 bInsert = pSlaveCache && pSlaveCache->IsControllerDirty();
1435 // Slaves are chained together in a circle
1436 if (pSlaveSlot->GetNextSlot() == pFirstSlave)
1437 break;
1441 if ( bInsert && bSameMethod )
1443 SfxFoundCache_Impl *pFoundCache = new SfxFoundCache_Impl(
1444 pSibling->GetSlotId(), pSibling->GetWhich(rPool),
1445 pSibling, pSiblingCache );
1447 rFound.push_back( pFoundCache );
1450 pSibling = pSibling->GetNextSlot();
1453 // Create a Set from the ranges
1454 sal_uInt16 *pRanges = new sal_uInt16[rFound.size() * 2 + 1];
1455 int j = 0;
1456 sal_uInt16 i = 0;
1457 while ( i < rFound.size() )
1459 pRanges[j++] = rFound[i]->nWhichId;
1460 // consecutive numbers
1461 for ( ; i < rFound.size()-1; ++i )
1462 if ( rFound[i]->nWhichId+1 != rFound[i+1]->nWhichId )
1463 break;
1464 pRanges[j++] = rFound[i++]->nWhichId;
1466 pRanges[j] = 0; // terminating NULL
1467 SfxItemSet *pSet = new SfxItemSet(rPool, pRanges);
1468 delete [] pRanges;
1469 DBG_PROFSTOP(SfxBindingsCreateSet);
1470 return pSet;
1473 //--------------------------------------------------------------------
1475 void SfxBindings::UpdateControllers_Impl
1477 const SfxInterface* pIF, // Id of the current serving Interface
1478 const SfxFoundCache_Impl* pFound, // Cache, Slot, Which etc.
1479 const SfxPoolItem* pItem, // item to send to controller
1480 SfxItemState eState // state of item
1483 DBG_ASSERT( !pFound->pSlot || SFX_KIND_ENUM != pFound->pSlot->GetKind(),
1484 "direct update of enum slot isn't allowed" );
1485 DBG_PROFSTART(SfxBindingsUpdateCtrl1);
1487 SfxStateCache* pCache = pFound->pCache;
1488 const SfxSlot* pSlot = pFound->pSlot;
1489 DBG_ASSERT( !pCache || !pSlot || pCache->GetId() == pSlot->GetSlotId(), "SID mismatch" );
1491 // bound until now, the Controller to update the Slot.
1492 if ( pCache && pCache->IsControllerDirty() )
1494 if ( SFX_ITEM_DONTCARE == eState )
1496 // ambiguous
1497 pCache->SetState( SFX_ITEM_DONTCARE, (SfxPoolItem *)-1 );
1499 else if ( SFX_ITEM_DEFAULT == eState &&
1500 pFound->nWhichId > SFX_WHICH_MAX )
1502 // no Status or Default but without Pool
1503 SfxVoidItem aVoid(0);
1504 pCache->SetState( SFX_ITEM_UNKNOWN, &aVoid );
1506 else if ( SFX_ITEM_DISABLED == eState )
1507 pCache->SetState(SFX_ITEM_DISABLED, 0);
1508 else
1509 pCache->SetState(SFX_ITEM_AVAILABLE, pItem);
1512 DBG_PROFSTOP(SfxBindingsUpdateCtrl1);
1514 // Update the slots for so far available and bound Controllers for
1515 // Slave-Slots (Enum-value)
1516 DBG_PROFSTART(SfxBindingsUpdateCtrl2);
1517 DBG_ASSERT( !pSlot || 0 == pSlot->GetLinkedSlot() || !pItem ||
1518 pItem->ISA(SfxEnumItemInterface),
1519 "master slot with non-enum-type found" );
1520 const SfxSlot *pFirstSlave = pSlot ? pSlot->GetLinkedSlot() : 0;
1521 if ( pIF && pFirstSlave)
1523 // Items cast on EnumItem
1524 const SfxEnumItemInterface *pEnumItem =
1525 PTR_CAST(SfxEnumItemInterface,pItem);
1526 if ( eState == SFX_ITEM_AVAILABLE && !pEnumItem )
1527 eState = SFX_ITEM_DONTCARE;
1528 else
1529 eState = SfxControllerItem::GetItemState( pEnumItem );
1531 // Iterate over all Slaves-Slots
1532 for ( const SfxSlot *pSlave = pFirstSlave; pSlave; pSlave = pSlave->GetNextSlot() )
1534 DBG_ASSERT(pSlave, "Wrong SlaveSlot binding!");
1535 DBG_ASSERT(SFX_KIND_ENUM == pSlave->GetKind(),"non enum slaves aren't allowed");
1536 DBG_ASSERT(pSlave->GetMasterSlotId() == pSlot->GetSlotId(),"Wrong MasterSlot!");
1538 // Binding exist for function ?
1539 SfxStateCache *pEnumCache = GetStateCache( pSlave->GetSlotId() );
1540 if ( pEnumCache )
1542 pEnumCache->Invalidate(sal_False);
1544 // HACK(CONTROL/SELECT Kram) ???
1545 if ( eState == SFX_ITEM_DONTCARE && pFound->nWhichId == 10144 )
1547 SfxVoidItem aVoid(0);
1548 pEnumCache->SetState( SFX_ITEM_UNKNOWN, &aVoid );
1550 if (pSlave->GetNextSlot() == pFirstSlave)
1551 break;
1553 continue;
1556 if ( SFX_ITEM_DISABLED == eState || !pEnumItem->IsEnabled( pSlave->GetSlotId()) )
1558 // disabled
1559 pEnumCache->SetState(SFX_ITEM_DISABLED, 0);
1561 else if ( SFX_ITEM_AVAILABLE == eState )
1563 // Determine enum value
1564 sal_uInt16 nValue = pEnumItem->GetEnumValue();
1565 SfxBoolItem aBool( pFound->nWhichId, pSlave->GetValue() == nValue );
1566 pEnumCache->SetState(SFX_ITEM_AVAILABLE, &aBool);
1568 else
1570 // ambiguous
1571 pEnumCache->SetState( SFX_ITEM_DONTCARE, (SfxPoolItem *)-1 );
1575 if (pSlave->GetNextSlot() == pFirstSlave)
1576 break;
1580 DBG_PROFSTOP(SfxBindingsUpdateCtrl2);
1584 //--------------------------------------------------------------------
1586 IMPL_LINK( SfxBindings, NextJob_Impl, Timer *, pTimer )
1588 #ifdef DBG_UTIL
1589 // on Windows very often C++ Exceptions (GPF etc.) are caught by MSVCRT
1590 // or another MS library try to get them here
1593 #endif
1594 const unsigned MAX_INPUT_DELAY = 200;
1596 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1598 DBG_PROFSTART(SfxBindingsNextJob_Impl0);
1600 if ( Application::GetLastInputInterval() < MAX_INPUT_DELAY && pTimer )
1602 pImp->aTimer.SetTimeout(TIMEOUT_UPDATING);
1603 return sal_True;
1606 SfxApplication *pSfxApp = SFX_APP();
1608 if( pDispatcher )
1609 pDispatcher->Update_Impl();
1611 // modifying the SfxObjectInterface-stack without SfxBindings => nothing to do
1612 SfxViewFrame* pFrame = pDispatcher->GetFrame();
1613 if ( (pFrame && !pFrame->GetObjectShell()->AcceptStateUpdate()) || pSfxApp->IsDowning() || pImp->pCaches->empty() )
1615 DBG_PROFSTOP(SfxBindingsNextJob_Impl0);
1616 return sal_True;
1618 if ( !pDispatcher || !pDispatcher->IsFlushed() )
1620 DBG_PROFSTOP(SfxBindingsNextJob_Impl0);
1621 return sal_True;
1624 // if possible Update all server / happens in its own time slice
1625 if ( pImp->bMsgDirty )
1627 UpdateSlotServer_Impl();
1628 DBG_PROFSTOP(SfxBindingsNextJob_Impl0);
1629 return sal_False;
1632 DBG_PROFSTOP(SfxBindingsNextJob_Impl0);
1633 DBG_PROFSTART(SfxBindingsNextJob_Impl);
1634 pImp->bAllDirty = sal_False;
1635 pImp->aTimer.SetTimeout(TIMEOUT_UPDATING);
1637 // at least 10 loops and further if more jobs are available but no input
1638 bool bPreEmptive = pTimer && !pSfxApp->Get_Impl()->nInReschedule;
1639 sal_uInt16 nLoops = 10;
1640 pImp->bInNextJob = sal_True;
1641 const sal_uInt16 nCount = pImp->pCaches->size();
1642 while ( pImp->nMsgPos < nCount )
1644 // iterate through the bound functions
1645 sal_Bool bJobDone = sal_False;
1646 while ( !bJobDone )
1648 SfxStateCache* pCache = (*pImp->pCaches)[pImp->nMsgPos];
1649 DBG_ASSERT( pCache, "invalid SfxStateCache-position in job queue" );
1650 sal_Bool bWasDirty = pCache->IsControllerDirty();
1651 if ( bWasDirty )
1653 Update_Impl( pCache );
1654 DBG_ASSERT( nCount == pImp->pCaches->size(),
1655 "Reschedule in StateChanged => buff" );
1658 // skip to next function binding
1659 ++pImp->nMsgPos;
1661 // keep job if it is not completed, but any input is available
1662 bJobDone = pImp->nMsgPos >= nCount;
1663 if ( bJobDone && pImp->bFirstRound )
1666 // Update of the preferred shell has been done, now may
1667 // also the others shells be updated
1668 bJobDone = sal_False;
1669 pImp->bFirstRound = sal_False;
1670 pImp->nMsgPos = 0;
1673 if ( bWasDirty && !bJobDone && bPreEmptive && (--nLoops == 0) )
1675 DBG_PROFSTOP(SfxBindingsNextJob_Impl);
1676 pImp->bInNextJob = sal_False;
1677 return sal_False;
1682 pImp->nMsgPos = 0;
1684 // check for volatile slots
1685 bool bVolatileSlotsPresent = false;
1686 for ( sal_uInt16 n = 0; n < nCount; ++n )
1688 SfxStateCache* pCache = (*pImp->pCaches)[n];
1689 const SfxSlotServer *pSlotServer = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1690 if ( pSlotServer && pSlotServer->GetSlot()->IsMode(SFX_SLOT_VOLATILE) )
1692 pCache->Invalidate(sal_False);
1693 bVolatileSlotsPresent = true;
1697 if (bVolatileSlotsPresent)
1698 pImp->aTimer.SetTimeout(TIMEOUT_IDLE);
1699 else
1700 pImp->aTimer.Stop();
1702 // Update round is finished
1703 pImp->bInNextJob = sal_False;
1704 Broadcast(SfxSimpleHint(SFX_HINT_UPDATEDONE));
1705 DBG_PROFSTOP(SfxBindingsNextJob_Impl);
1706 return sal_True;
1707 #ifdef DBG_UTIL
1709 catch (...)
1711 OSL_FAIL("C++ exception caught!");
1712 pImp->bInNextJob = sal_False;
1715 return sal_False;
1716 #endif
1719 //--------------------------------------------------------------------
1721 sal_uInt16 SfxBindings::EnterRegistrations(const char *pFile, int nLine)
1723 SAL_INFO(
1724 "sfx2.control",
1725 std::setw(std::min(nRegLevel, sal_uInt16(8))) << ' ' << "this = " << this
1726 << " Level = " << nRegLevel << " SfxBindings::EnterRegistrations "
1727 << (pFile
1728 ? SAL_STREAM("File: " << pFile << " Line: " << nLine) : ""));
1730 // When bindings are locked, also lock sub bindings.
1731 if ( pImp->pSubBindings )
1733 pImp->pSubBindings->ENTERREGISTRATIONS();
1735 // These EnterRegistrations are not "real" for the SubBindings
1736 pImp->pSubBindings->pImp->nOwnRegLevel--;
1738 // Synchronize Bindings
1739 pImp->pSubBindings->nRegLevel = nRegLevel + pImp->pSubBindings->pImp->nOwnRegLevel + 1;
1742 pImp->nOwnRegLevel++;
1744 // check if this is the outer most level
1745 if ( ++nRegLevel == 1 )
1747 // stop background-processing
1748 pImp->aTimer.Stop();
1750 // flush the cache
1751 pImp->nCachedFunc1 = 0;
1752 pImp->nCachedFunc2 = 0;
1754 // Mark if the all of the Caches have dissapered.
1755 pImp->bCtrlReleased = sal_False;
1758 return nRegLevel;
1760 //--------------------------------------------------------------------
1762 void SfxBindings::LeaveRegistrations( sal_uInt16 nLevel, const char *pFile, int nLine )
1764 (void)nLevel; // unused variable
1765 DBG_ASSERT( nRegLevel, "Leave without Enter" );
1766 DBG_ASSERT( nLevel == USHRT_MAX || nLevel == nRegLevel, "wrong Leave" );
1768 // Only when the SubBindings are still locked by the Superbindings,
1769 // remove this lock (i.e. if there are more locks than "real" ones)
1770 if ( pImp->pSubBindings && pImp->pSubBindings->nRegLevel > pImp->pSubBindings->pImp->nOwnRegLevel )
1772 // Synchronize Bindings
1773 pImp->pSubBindings->nRegLevel = nRegLevel + pImp->pSubBindings->pImp->nOwnRegLevel;
1775 // This LeaveRegistrations is not "real" for SubBindings
1776 pImp->pSubBindings->pImp->nOwnRegLevel++;
1777 pImp->pSubBindings->LEAVEREGISTRATIONS();
1780 pImp->nOwnRegLevel--;
1782 // check if this is the outer most level
1783 if ( --nRegLevel == 0 && !SFX_APP()->IsDowning() )
1785 if ( pImp->bContextChanged )
1787 pImp->bContextChanged = sal_False;
1790 SfxViewFrame* pFrame = pDispatcher->GetFrame();
1792 // If possible remove unused Caches, for example prepare PlugInInfo
1793 if ( pImp->bCtrlReleased )
1795 for ( sal_uInt16 nCache = pImp->pCaches->size(); nCache > 0; --nCache )
1797 // Get Cache via ::com::sun::star::sdbcx::Index
1798 SfxStateCache *pCache = (*pImp->pCaches)[nCache-1];
1800 // No interested Controller present
1801 if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() )
1803 // Remove Cache. Safety: first remove and then delete
1804 pImp->pCaches->erase(pImp->pCaches->begin() + nCache - 1);
1805 delete pCache;
1810 // restart background-processing
1811 pImp->nMsgPos = 0;
1812 if ( !pFrame || !pFrame->GetObjectShell() )
1813 return;
1814 if ( pImp->pCaches && !pImp->pCaches->empty() )
1816 pImp->aTimer.Stop();
1817 pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
1818 pImp->aTimer.Start();
1822 SAL_INFO(
1823 "sfx2.control",
1824 std::setw(std::min(nRegLevel, sal_uInt16(8))) << ' ' << "this = " << this
1825 << " Level = " << nRegLevel << " SfxBindings::LeaveRegistrations "
1826 << (pFile
1827 ? SAL_STREAM("File: " << pFile << " Line: " << nLine) : ""));
1830 //--------------------------------------------------------------------
1832 const SfxSlot* SfxBindings::GetSlot(sal_uInt16 nSlotId)
1834 DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1836 // synchronizing
1837 pDispatcher->Flush();
1838 if ( pImp->bMsgDirty )
1839 UpdateSlotServer_Impl();
1841 // get the cache for the specified function; return if not bound
1842 SfxStateCache* pCache = GetStateCache(nSlotId);
1843 return pCache && pCache->GetSlotServer(*pDispatcher, pImp->xProv)?
1844 pCache->GetSlotServer(*pDispatcher, pImp->xProv)->GetSlot(): 0;
1847 //--------------------------------------------------------------------
1849 void SfxBindings::SetDispatcher( SfxDispatcher *pDisp )
1851 SfxDispatcher *pOldDispat = pDispatcher;
1852 if ( pDisp != pDispatcher )
1854 if ( pOldDispat )
1856 SfxBindings* pBind = pOldDispat->GetBindings();
1857 while ( pBind )
1859 if ( pBind->pImp->pSubBindings == this && pBind->pDispatcher != pDisp )
1860 pBind->SetSubBindings_Impl( NULL );
1861 pBind = pBind->pImp->pSubBindings;
1865 pDispatcher = pDisp;
1867 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider > xProv;
1868 if ( pDisp )
1869 xProv = ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider >
1870 ( pDisp->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY );
1872 SetDispatchProvider_Impl( xProv );
1873 InvalidateAll( sal_True );
1874 InvalidateUnoControllers_Impl();
1876 if ( pDispatcher && !pOldDispat )
1878 if ( pImp->pSubBindings && pImp->pSubBindings->pDispatcher != pOldDispat )
1880 OSL_FAIL( "SubBindings already set before activating!" );
1881 pImp->pSubBindings->ENTERREGISTRATIONS();
1883 LEAVEREGISTRATIONS();
1885 else if( !pDispatcher )
1887 ENTERREGISTRATIONS();
1888 if ( pImp->pSubBindings && pImp->pSubBindings->pDispatcher != pOldDispat )
1890 OSL_FAIL( "SubBindings still set even when deactivating!" );
1891 pImp->pSubBindings->LEAVEREGISTRATIONS();
1895 Broadcast( SfxSimpleHint( SFX_HINT_DATACHANGED ) );
1897 if ( pDisp )
1899 SfxBindings* pBind = pDisp->GetBindings();
1900 while ( pBind && pBind != this )
1902 if ( !pBind->pImp->pSubBindings )
1904 pBind->SetSubBindings_Impl( this );
1905 break;
1908 pBind = pBind->pImp->pSubBindings;
1914 //--------------------------------------------------------------------
1916 void SfxBindings::ClearCache_Impl( sal_uInt16 nSlotId )
1918 GetStateCache(nSlotId)->ClearCache();
1921 //--------------------------------------------------------------------
1922 void SfxBindings::StartUpdate_Impl( sal_Bool bComplete )
1924 if ( pImp->pSubBindings )
1925 pImp->pSubBindings->StartUpdate_Impl( bComplete );
1927 if ( !bComplete )
1928 // Update may be interrupted
1929 NextJob_Impl(&pImp->aTimer);
1930 else
1931 // Update all slots in a row
1932 NextJob_Impl(0);
1935 //-------------------------------------------------------------------------
1937 SfxItemState SfxBindings::QueryState( sal_uInt16 nSlot, SfxPoolItem* &rpState )
1939 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
1940 SfxStateCache *pCache = GetStateCache( nSlot );
1941 if ( pCache )
1942 xDisp = pCache->GetDispatch();
1943 if ( xDisp.is() || !pCache )
1945 const SfxSlot* pSlot = SfxSlotPool::GetSlotPool( pDispatcher->GetFrame() ).GetSlot( nSlot );
1946 if ( !pSlot || !pSlot->pUnoName )
1947 return SFX_ITEM_DISABLED;
1949 ::com::sun::star::util::URL aURL;
1950 OUString aCmd( ".uno:" );
1951 aURL.Protocol = aCmd;
1952 aURL.Path = OUString::createFromAscii(pSlot->GetUnoName());
1953 aCmd += aURL.Path;
1954 aURL.Complete = aCmd;
1955 aURL.Main = aCmd;
1957 if ( !xDisp.is() )
1958 xDisp = pImp->xProv->queryDispatch( aURL, OUString(), 0 );
1960 if ( xDisp.is() )
1962 ::com::sun::star::uno::Reference< ::com::sun::star::lang::XUnoTunnel > xTunnel( xDisp, ::com::sun::star::uno::UNO_QUERY );
1963 SfxOfficeDispatch* pDisp = NULL;
1964 if ( xTunnel.is() )
1966 sal_Int64 nImplementation = xTunnel->getSomething(SfxOfficeDispatch::impl_getStaticIdentifier());
1967 pDisp = reinterpret_cast< SfxOfficeDispatch* >( sal::static_int_cast< sal_IntPtr >( nImplementation ));
1970 if ( !pDisp )
1972 sal_Bool bDeleteCache = sal_False;
1973 if ( !pCache )
1975 pCache = new SfxStateCache( nSlot );
1976 pCache->GetSlotServer( *GetDispatcher_Impl(), pImp->xProv );
1977 bDeleteCache = sal_True;
1980 SfxItemState eState = SFX_ITEM_SET;
1981 SfxPoolItem *pItem=NULL;
1982 BindDispatch_Impl *pBind = new BindDispatch_Impl( xDisp, aURL, pCache, pSlot );
1983 pBind->acquire();
1984 xDisp->addStatusListener( pBind, aURL );
1985 if ( !pBind->GetStatus().IsEnabled )
1987 eState = SFX_ITEM_DISABLED;
1989 else
1991 ::com::sun::star::uno::Any aAny = pBind->GetStatus().State;
1992 ::com::sun::star::uno::Type pType = aAny.getValueType();
1994 if ( pType == ::getBooleanCppuType() )
1996 sal_Bool bTemp = false;
1997 aAny >>= bTemp ;
1998 pItem = new SfxBoolItem( nSlot, bTemp );
2000 else if ( pType == ::getCppuType((const sal_uInt16*)0) )
2002 sal_uInt16 nTemp = 0;
2003 aAny >>= nTemp ;
2004 pItem = new SfxUInt16Item( nSlot, nTemp );
2006 else if ( pType == ::getCppuType((const sal_uInt32*)0) )
2008 sal_uInt32 nTemp = 0;
2009 aAny >>= nTemp ;
2010 pItem = new SfxUInt32Item( nSlot, nTemp );
2012 else if ( pType == ::getCppuType((const OUString*)0) )
2014 OUString sTemp ;
2015 aAny >>= sTemp ;
2016 pItem = new SfxStringItem( nSlot, sTemp );
2018 else
2019 pItem = new SfxVoidItem( nSlot );
2022 xDisp->removeStatusListener( pBind, aURL );
2023 pBind->Release();
2024 rpState = pItem;
2025 if ( bDeleteCache )
2026 DELETEZ( pCache );
2027 return eState;
2032 // Then test at the dispatcher to check if the returned items from
2033 // there are always DELETE_ON_IDLE, a copy of it has to be made in
2034 // order to allow for transition of ownership.
2035 const SfxPoolItem *pItem = NULL;
2036 SfxItemState eState = pDispatcher->QueryState( nSlot, pItem );
2037 if ( eState == SFX_ITEM_SET )
2039 DBG_ASSERT( pItem, "SFX_ITEM_SET but no item!" );
2040 if ( pItem )
2041 rpState = pItem->Clone();
2043 else if ( eState == SFX_ITEM_AVAILABLE && pItem )
2045 rpState = pItem->Clone();
2048 return eState;
2051 void SfxBindings::SetSubBindings_Impl( SfxBindings *pSub )
2053 if ( pImp->pSubBindings )
2055 pImp->pSubBindings->SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > () );
2056 pImp->pSubBindings->pImp->pSuperBindings = NULL;
2059 pImp->pSubBindings = pSub;
2061 if ( pSub )
2063 pImp->pSubBindings->SetDispatchProvider_Impl( pImp->xProv );
2064 pSub->pImp->pSuperBindings = this;
2068 SfxBindings* SfxBindings::GetSubBindings_Impl( sal_Bool bTop ) const
2070 SfxBindings *pRet = pImp->pSubBindings;
2071 if ( bTop )
2073 while ( pRet->pImp->pSubBindings )
2074 pRet = pRet->pImp->pSubBindings;
2077 return pRet;
2080 void SfxBindings::SetWorkWindow_Impl( SfxWorkWindow* pWork )
2082 pImp->pWorkWin = pWork;
2085 SfxWorkWindow* SfxBindings::GetWorkWindow_Impl() const
2087 return pImp->pWorkWin;
2090 void SfxBindings::RegisterUnoController_Impl( SfxUnoControllerItem* pControl )
2092 if ( !pImp->pUnoCtrlArr )
2093 pImp->pUnoCtrlArr = new SfxUnoControllerArr_Impl;
2094 pImp->pUnoCtrlArr->push_back( pControl );
2097 void SfxBindings::ReleaseUnoController_Impl( SfxUnoControllerItem* pControl )
2099 if ( pImp->pUnoCtrlArr )
2101 SfxUnoControllerArr_Impl::iterator it = std::find(
2102 pImp->pUnoCtrlArr->begin(), pImp->pUnoCtrlArr->end(), pControl );
2103 if ( it != pImp->pUnoCtrlArr->end() )
2105 pImp->pUnoCtrlArr->erase( it );
2106 return;
2110 if ( pImp->pSubBindings )
2111 pImp->pSubBindings->ReleaseUnoController_Impl( pControl );
2114 void SfxBindings::InvalidateUnoControllers_Impl()
2116 if ( pImp->pUnoCtrlArr )
2118 sal_uInt16 nCount = pImp->pUnoCtrlArr->size();
2119 for ( sal_uInt16 n=nCount; n>0; n-- )
2121 SfxUnoControllerItem *pCtrl = (*pImp->pUnoCtrlArr)[n-1];
2122 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > xRef( (::cppu::OWeakObject*)pCtrl, ::com::sun::star::uno::UNO_QUERY );
2123 pCtrl->ReleaseDispatch();
2124 pCtrl->GetNewDispatch();
2128 if ( pImp->pSubBindings )
2129 pImp->pSubBindings->InvalidateUnoControllers_Impl();
2132 sal_Bool SfxBindings::IsInUpdate() const
2134 sal_Bool bInUpdate = pImp->bInUpdate;
2135 if ( !bInUpdate && pImp->pSubBindings )
2136 bInUpdate = pImp->pSubBindings->IsInUpdate();
2137 return bInUpdate;
2140 void SfxBindings::SetVisibleState( sal_uInt16 nId, sal_Bool bShow )
2142 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
2143 SfxStateCache *pCache = GetStateCache( nId );
2144 if ( pCache )
2145 pCache->SetVisibleState( bShow );
2148 void SfxBindings::SetActiveFrame( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > & rFrame )
2150 if ( rFrame.is() || !pDispatcher )
2151 SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > ( rFrame, ::com::sun::star::uno::UNO_QUERY ) );
2152 else
2153 SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > (
2154 pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), ::com::sun::star::uno::UNO_QUERY ) );
2157 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > SfxBindings::GetActiveFrame() const
2159 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame( pImp->xProv, ::com::sun::star::uno::UNO_QUERY );
2160 if ( xFrame.is() || !pDispatcher )
2161 return xFrame;
2162 else
2163 return pDispatcher->GetFrame()->GetFrame().GetFrameInterface();
2166 void SfxBindings::SetDispatchProvider_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & rProv )
2168 sal_Bool bInvalidate = ( rProv != pImp->xProv );
2169 if ( bInvalidate )
2171 pImp->xProv = rProv;
2172 InvalidateAll( sal_True );
2173 InvalidateUnoControllers_Impl();
2176 if ( pImp->pSubBindings )
2177 pImp->pSubBindings->SetDispatchProvider_Impl( pImp->xProv );
2180 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & SfxBindings::GetDispatchProvider_Impl() const
2182 return pImp->xProv;
2185 SystemWindow* SfxBindings::GetSystemWindow() const
2187 SfxViewFrame *pFrame = pDispatcher->GetFrame();
2188 while ( pFrame->GetParentViewFrame_Impl() )
2189 pFrame = pFrame->GetParentViewFrame_Impl();
2190 SfxViewFrame* pTop = pFrame->GetTopViewFrame();
2191 return pTop->GetFrame().GetTopWindow_Impl();
2194 sal_Bool SfxBindings::ExecuteCommand_Impl( const String& rCommand )
2196 ::com::sun::star::util::URL aURL;
2197 aURL.Complete = rCommand;
2198 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
2199 xTrans->parseStrict( aURL );
2200 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp = pImp->xProv->queryDispatch( aURL, OUString(), 0 );
2201 if ( xDisp.is() )
2203 new SfxAsyncExec_Impl( aURL, xDisp );
2204 return sal_True;
2207 return sal_False;
2210 com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder > SfxBindings::GetRecorder() const
2212 return pImp->xRecorder;
2215 void SfxBindings::SetRecorder_Impl( com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder >& rRecorder )
2217 pImp->xRecorder = rRecorder;
2220 void SfxBindings::ContextChanged_Impl()
2222 if ( !pImp->bInUpdate && ( !pImp->bContextChanged || !pImp->bAllMsgDirty ) )
2224 InvalidateAll( sal_True );
2228 uno::Reference < frame::XDispatch > SfxBindings::GetDispatch( const SfxSlot* pSlot, const util::URL& aURL, sal_Bool bMasterCommand )
2230 uno::Reference < frame::XDispatch > xRet;
2231 SfxStateCache* pCache = GetStateCache( pSlot->nSlotId );
2232 if ( pCache && !bMasterCommand )
2233 xRet = pCache->GetInternalDispatch();
2234 if ( !xRet.is() )
2236 // dispatches for slaves are unbound, they don't have a state
2237 SfxOfficeDispatch* pDispatch = bMasterCommand ?
2238 new SfxOfficeDispatch( pDispatcher, pSlot, aURL ) :
2239 new SfxOfficeDispatch( *this, pDispatcher, pSlot, aURL );
2241 pDispatch->SetMasterUnoCommand( bMasterCommand );
2242 xRet = uno::Reference < frame::XDispatch >( pDispatch );
2243 if ( !pCache )
2244 pCache = GetStateCache( pSlot->nSlotId );
2246 DBG_ASSERT( pCache, "No cache for OfficeDispatch!" );
2247 if ( pCache && !bMasterCommand )
2248 pCache->SetInternalDispatch( xRet );
2251 return xRet;
2254 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */