Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <sal/config.h>
21 :
22 : #include <iomanip>
23 :
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>
46 :
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>
65 :
66 : #include <com/sun/star/frame/XModuleManager.hpp>
67 : #include <boost/scoped_array.hpp>
68 : #include <boost/scoped_ptr.hpp>
69 :
70 : using namespace ::com::sun::star;
71 : using namespace ::com::sun::star::uno;
72 : using namespace ::com::sun::star::util;
73 :
74 : static sal_uInt16 nTimeOut = 300;
75 :
76 : #define TIMEOUT_FIRST nTimeOut
77 : #define TIMEOUT_UPDATING 20
78 : #define TIMEOUT_IDLE 2500
79 :
80 : typedef boost::unordered_map< sal_uInt16, bool > InvalidateSlotMap;
81 :
82 :
83 :
84 : typedef std::vector<SfxStateCache*> SfxStateCacheArr_Impl;
85 :
86 :
87 :
88 0 : class SfxAsyncExec_Impl
89 : {
90 : ::com::sun::star::util::URL aCommand;
91 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
92 : Timer aTimer;
93 :
94 : public:
95 :
96 0 : SfxAsyncExec_Impl( const ::com::sun::star::util::URL& rCmd, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch >& rDisp )
97 : : aCommand( rCmd )
98 0 : , xDisp( rDisp )
99 : {
100 0 : aTimer.SetTimeoutHdl( LINK(this, SfxAsyncExec_Impl, TimerHdl) );
101 0 : aTimer.SetTimeout( 0 );
102 0 : aTimer.Start();
103 0 : }
104 :
105 : DECL_LINK( TimerHdl, Timer*);
106 : };
107 :
108 0 : IMPL_LINK(SfxAsyncExec_Impl, TimerHdl, Timer*, pTimer)
109 : {
110 : (void)pTimer; // unused
111 0 : aTimer.Stop();
112 :
113 0 : Sequence<beans::PropertyValue> aSeq;
114 0 : xDisp->dispatch( aCommand, aSeq );
115 :
116 0 : delete this;
117 0 : return 0L;
118 : }
119 :
120 0 : class SfxBindings_Impl
121 : {
122 : public:
123 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchRecorder > xRecorder;
124 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv;
125 : SfxUnoControllerArr_Impl*
126 : pUnoCtrlArr;
127 : SfxWorkWindow* pWorkWin;
128 : SfxBindings* pSubBindings;
129 : SfxBindings* pSuperBindings;
130 : SfxStateCacheArr_Impl* pCaches; // One chache for each binding
131 : sal_uInt16 nCachedFunc1; // index for the last one called
132 : sal_uInt16 nCachedFunc2; // index for the second last called
133 : sal_uInt16 nMsgPos; // Message-Position relative the one to be updated
134 : SfxPopupAction ePopupAction; // Checked in DeleteFloatinWindow()
135 : bool bContextChanged;
136 : bool bMsgDirty; // Has a MessageServer been invalidated?
137 : bool bAllMsgDirty; // Has a MessageServer been invalidated?
138 : bool bAllDirty; // After InvalidateAll
139 : bool bCtrlReleased; // while EnterRegistrations
140 : AutoTimer aTimer; // for volatile Slots
141 : bool bInUpdate; // for Assertions
142 : bool bInNextJob; // for Assertions
143 : bool bFirstRound; // First round in Update
144 : sal_uInt16 nFirstShell; // Shell, the first round is preferred
145 : sal_uInt16 nOwnRegLevel; // Counts the real Locks, exept those of the Super Bindings
146 : InvalidateSlotMap m_aInvalidateSlots; // store slots which are invalidated while in update
147 : };
148 :
149 :
150 :
151 : struct SfxFoundCache_Impl
152 : {
153 : sal_uInt16 nSlotId; // the Slot-Id
154 : sal_uInt16 nWhichId; // If available: Which-Id, else: nSlotId
155 : const SfxSlot* pSlot; // Pointer to <Master-Slot>
156 : SfxStateCache* pCache; // Pointer to StatusCache, if possible NULL
157 :
158 0 : SfxFoundCache_Impl(sal_uInt16 nS, sal_uInt16 nW, const SfxSlot *pS, SfxStateCache *pC ):
159 : nSlotId(nS),
160 : nWhichId(nW),
161 : pSlot(pS),
162 0 : pCache(pC)
163 0 : {}
164 : };
165 :
166 :
167 :
168 0 : class SfxFoundCacheArr_Impl : public std::vector<SfxFoundCache_Impl*>
169 : {
170 : public:
171 0 : ~SfxFoundCacheArr_Impl()
172 0 : {
173 0 : for(const_iterator it = begin(); it != end(); ++it)
174 0 : delete *it;
175 0 : }
176 : };
177 :
178 :
179 :
180 0 : SfxBindings::SfxBindings()
181 0 : : pImp(new SfxBindings_Impl),
182 : pDispatcher(0),
183 0 : nRegLevel(1) // first becomes 0, when the Dispatcher is set
184 : {
185 0 : pImp->nMsgPos = 0;
186 0 : pImp->bAllMsgDirty = true;
187 0 : pImp->bContextChanged = false;
188 0 : pImp->bMsgDirty = true;
189 0 : pImp->bAllDirty = true;
190 0 : pImp->ePopupAction = SFX_POPUP_DELETE;
191 0 : pImp->nCachedFunc1 = 0;
192 0 : pImp->nCachedFunc2 = 0;
193 0 : pImp->bCtrlReleased = false;
194 0 : pImp->bFirstRound = false;
195 0 : pImp->bInNextJob = false;
196 0 : pImp->bInUpdate = false;
197 0 : pImp->pSubBindings = NULL;
198 0 : pImp->pSuperBindings = NULL;
199 0 : pImp->pWorkWin = NULL;
200 0 : pImp->pUnoCtrlArr = NULL;
201 0 : pImp->nOwnRegLevel = nRegLevel;
202 :
203 : // all caches are valid (no pending invalidate-job)
204 : // create the list of caches
205 0 : pImp->pCaches = new SfxStateCacheArr_Impl;
206 0 : pImp->aTimer.SetTimeoutHdl( LINK(this, SfxBindings, NextJob_Impl) );
207 0 : }
208 :
209 :
210 :
211 0 : SfxBindings::~SfxBindings()
212 :
213 : /* [Description]
214 :
215 : Destructor of the SfxBindings class. The one, for each <SfxApplication>
216 : existing Instance is automatically destroyed by the <SfxApplication>
217 : after the execution of <SfxApplication::Exit()>.
218 :
219 : The still existing <SfxControllerItem> instances, which are registered
220 : by the SfxBindings instance, are automatically destroyed in the Destructor.
221 : These are usually the Floating-Toolboxen, Value-Sets
222 : etc. Arrays of SfxControllerItems may at this time no longer exist.
223 : */
224 :
225 : {
226 : // The SubBindings should not be locked!
227 0 : pImp->pSubBindings = NULL;
228 :
229 0 : ENTERREGISTRATIONS();
230 :
231 0 : pImp->aTimer.Stop();
232 0 : DeleteControllers_Impl();
233 :
234 : // Delete Caches
235 0 : for(SfxStateCacheArr_Impl::const_iterator it = pImp->pCaches->begin(); it != pImp->pCaches->end(); ++it)
236 0 : delete *it;
237 :
238 0 : DELETEZ( pImp->pWorkWin );
239 :
240 0 : delete pImp->pCaches;
241 0 : delete pImp;
242 0 : }
243 :
244 :
245 :
246 0 : void SfxBindings::DeleteControllers_Impl()
247 : {
248 : // in the first round delete SfxPopupWindows
249 0 : sal_uInt16 nCount = pImp->pCaches->size();
250 : sal_uInt16 nCache;
251 0 : for ( nCache = 0; nCache < nCount; ++nCache )
252 : {
253 : // Remember were you are
254 0 : SfxStateCache *pCache = (*pImp->pCaches)[nCache];
255 0 : sal_uInt16 nSlotId = pCache->GetId();
256 :
257 : // Delete SfxPopupWindow
258 0 : pCache->DeleteFloatingWindows();
259 :
260 : // Re-align, because the cache may have been reduced
261 0 : sal_uInt16 nNewCount = pImp->pCaches->size();
262 0 : if ( nNewCount < nCount )
263 : {
264 0 : nCache = GetSlotPos(nSlotId);
265 0 : if ( nCache >= nNewCount ||
266 0 : nSlotId != (*pImp->pCaches)[nCache]->GetId() )
267 0 : --nCache;
268 0 : nCount = nNewCount;
269 : }
270 : }
271 :
272 : // Delete all Caches
273 0 : for ( nCache = pImp->pCaches->size(); nCache > 0; --nCache )
274 : {
275 : // Get Cache via ::com::sun::star::sdbcx::Index
276 0 : SfxStateCache *pCache = (*pImp->pCaches)[ nCache-1 ];
277 :
278 : // unbind all controllers in the cache
279 : SfxControllerItem *pNext;
280 0 : for ( SfxControllerItem *pCtrl = pCache->GetItemLink();
281 : pCtrl; pCtrl = pNext )
282 : {
283 0 : pNext = pCtrl->GetItemLink();
284 0 : pCtrl->UnBind();
285 : }
286 :
287 0 : if ( pCache->GetInternalController() )
288 0 : pCache->GetInternalController()->UnBind();
289 :
290 : // Delete Cache
291 0 : if( nCache-1 < (sal_uInt16) pImp->pCaches->size() )
292 0 : delete (*pImp->pCaches)[nCache-1];
293 0 : pImp->pCaches->erase(pImp->pCaches->begin()+ nCache - 1);
294 : }
295 :
296 0 : if( pImp->pUnoCtrlArr )
297 : {
298 0 : sal_uInt16 nCtrlCount = pImp->pUnoCtrlArr->size();
299 0 : for ( sal_uInt16 n=nCtrlCount; n>0; n-- )
300 : {
301 0 : SfxUnoControllerItem *pCtrl = (*pImp->pUnoCtrlArr)[n-1];
302 0 : pCtrl->ReleaseBindings();
303 : }
304 :
305 : DBG_ASSERT( !pImp->pUnoCtrlArr->size(), "Do not remove UnoControllerItems!" );
306 0 : DELETEZ( pImp->pUnoCtrlArr );
307 : }
308 0 : }
309 :
310 :
311 :
312 0 : void SfxBindings::HidePopups( bool bHide )
313 : {
314 : // Hide SfxPopupWindows
315 0 : HidePopupCtrls_Impl( bHide );
316 0 : SfxBindings *pSub = pImp->pSubBindings;
317 0 : while ( pSub )
318 : {
319 0 : pImp->pSubBindings->HidePopupCtrls_Impl( bHide );
320 0 : pSub = pSub->pImp->pSubBindings;
321 : }
322 :
323 : // Hide SfxChildWindows
324 : DBG_ASSERT( pDispatcher, "HidePopups not allowed without dispatcher" );
325 0 : if ( pImp->pWorkWin )
326 0 : pImp->pWorkWin->HidePopups_Impl( bHide, true );
327 0 : }
328 :
329 0 : void SfxBindings::HidePopupCtrls_Impl( bool bHide )
330 : {
331 0 : if ( bHide )
332 : {
333 : // Hide SfxPopupWindows
334 0 : pImp->ePopupAction = SFX_POPUP_HIDE;
335 : }
336 : else
337 : {
338 : // Show SfxPopupWindows
339 0 : pImp->ePopupAction = SFX_POPUP_SHOW;
340 : }
341 :
342 0 : for(SfxStateCacheArr_Impl::const_iterator it = pImp->pCaches->begin(); it != pImp->pCaches->end(); ++it)
343 0 : (*it)->DeleteFloatingWindows();
344 0 : pImp->ePopupAction = SFX_POPUP_DELETE;
345 0 : }
346 :
347 :
348 :
349 0 : void SfxBindings::Update_Impl
350 : (
351 : SfxStateCache* pCache // The up to date SfxStatusCache
352 : )
353 : {
354 0 : if( pCache->GetDispatch().is() && pCache->GetItemLink() )
355 : {
356 0 : pCache->SetCachedState(true);
357 0 : if ( !pCache->GetInternalController() )
358 0 : return;
359 : }
360 :
361 0 : if ( !pDispatcher )
362 0 : return;
363 :
364 : // gather together all with the same status method which are dirty
365 0 : SfxDispatcher &rDispat = *pDispatcher;
366 0 : const SfxSlot *pRealSlot = 0;
367 0 : const SfxSlotServer* pMsgServer = 0;
368 0 : SfxFoundCacheArr_Impl aFound;
369 0 : SfxItemSet *pSet = CreateSet_Impl( pCache, pRealSlot, &pMsgServer, aFound );
370 0 : bool bUpdated = false;
371 0 : if ( pSet )
372 : {
373 : // Query Status
374 0 : if ( rDispat._FillState( *pMsgServer, *pSet, pRealSlot ) )
375 : {
376 : // Post Status
377 : const SfxInterface *pInterface =
378 0 : rDispat.GetShell(pMsgServer->GetShellLevel())->GetInterface();
379 0 : for ( sal_uInt16 nPos = 0; nPos < aFound.size(); ++nPos )
380 : {
381 0 : const SfxFoundCache_Impl *pFound = aFound[nPos];
382 0 : sal_uInt16 nWhich = pFound->nWhichId;
383 0 : const SfxPoolItem *pItem = 0;
384 0 : SfxItemState eState = pSet->GetItemState(nWhich, true, &pItem);
385 0 : if ( eState == SFX_ITEM_DEFAULT && SfxItemPool::IsWhich(nWhich) )
386 0 : pItem = &pSet->Get(nWhich);
387 0 : UpdateControllers_Impl( pInterface, aFound[nPos], pItem, eState );
388 : }
389 0 : bUpdated = true;
390 : }
391 :
392 0 : delete pSet;
393 : }
394 :
395 0 : if ( !bUpdated && pCache )
396 : {
397 : // When pCache == NULL and no SlotServer
398 : // (for example due to locked Dispatcher! ),
399 : // obviously do not try to update
400 : SfxFoundCache_Impl aFoundCache(
401 0 : pCache->GetId(), 0,
402 0 : pRealSlot, pCache );
403 0 : UpdateControllers_Impl( 0, &aFoundCache, 0, SFX_ITEM_DISABLED);
404 0 : }
405 : }
406 :
407 :
408 :
409 0 : void SfxBindings::InvalidateSlotsInMap_Impl()
410 : {
411 0 : InvalidateSlotMap::const_iterator pIter = pImp->m_aInvalidateSlots.begin();
412 0 : while ( pIter != pImp->m_aInvalidateSlots.end() )
413 : {
414 0 : Invalidate( pIter->first );
415 0 : ++pIter;
416 : }
417 0 : pImp->m_aInvalidateSlots.clear();
418 0 : }
419 :
420 :
421 :
422 0 : void SfxBindings::AddSlotToInvalidateSlotsMap_Impl( sal_uInt16 nId )
423 : {
424 0 : pImp->m_aInvalidateSlots[nId] = true;
425 0 : }
426 :
427 :
428 :
429 0 : void SfxBindings::Update
430 : (
431 : sal_uInt16 nId // the bound and up-to-date Slot-Id
432 : )
433 : {
434 : DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
435 :
436 0 : if ( pDispatcher )
437 0 : pDispatcher->Flush();
438 :
439 0 : if ( pImp->pSubBindings )
440 0 : pImp->pSubBindings->Update( nId );
441 :
442 0 : SfxStateCache* pCache = GetStateCache( nId );
443 0 : if ( pCache )
444 : {
445 0 : pImp->bInUpdate = true;
446 0 : if ( pImp->bMsgDirty )
447 : {
448 0 : UpdateSlotServer_Impl();
449 0 : pCache = GetStateCache( nId );
450 : }
451 :
452 0 : if (pCache)
453 : {
454 0 : bool bInternalUpdate = true;
455 0 : if( pCache->GetDispatch().is() && pCache->GetItemLink() )
456 : {
457 0 : pCache->SetCachedState(true);
458 0 : bInternalUpdate = ( pCache->GetInternalController() != 0 );
459 : }
460 :
461 0 : if ( bInternalUpdate )
462 : {
463 : // Query Status
464 0 : const SfxSlotServer* pMsgServer = pDispatcher ? pCache->GetSlotServer(*pDispatcher, pImp->xProv) : NULL;
465 0 : if ( !pCache->IsControllerDirty() &&
466 0 : ( !pMsgServer ||
467 0 : !pMsgServer->GetSlot()->IsMode(SFX_SLOT_VOLATILE) ) )
468 : {
469 0 : pImp->bInUpdate = false;
470 0 : InvalidateSlotsInMap_Impl();
471 0 : return;
472 : }
473 0 : if (!pMsgServer)
474 : {
475 0 : pCache->SetState(SFX_ITEM_DISABLED, 0);
476 0 : pImp->bInUpdate = false;
477 0 : InvalidateSlotsInMap_Impl();
478 0 : return;
479 : }
480 :
481 0 : Update_Impl(pCache);
482 : }
483 :
484 0 : pImp->bAllDirty = false;
485 : }
486 :
487 0 : pImp->bInUpdate = false;
488 0 : InvalidateSlotsInMap_Impl();
489 : }
490 : }
491 :
492 :
493 :
494 0 : void SfxBindings::Update()
495 : {
496 : DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
497 :
498 0 : if ( pImp->pSubBindings )
499 0 : pImp->pSubBindings->Update();
500 :
501 0 : if ( pDispatcher )
502 : {
503 0 : if ( nRegLevel )
504 0 : return;
505 :
506 0 : pImp->bInUpdate = true;
507 0 : pDispatcher->Flush();
508 0 : pDispatcher->Update_Impl();
509 0 : while ( !NextJob_Impl(0) )
510 : ; // loop
511 0 : pImp->bInUpdate = false;
512 0 : InvalidateSlotsInMap_Impl();
513 : }
514 : }
515 :
516 :
517 :
518 0 : void SfxBindings::SetState
519 : (
520 : const SfxItemSet& rSet // status values to be set
521 : )
522 : {
523 : // when locked then only invalidate
524 0 : if ( nRegLevel )
525 : {
526 0 : SfxItemIter aIter(rSet);
527 0 : for ( const SfxPoolItem *pItem = aIter.FirstItem();
528 : pItem;
529 : pItem = aIter.NextItem() )
530 0 : Invalidate( pItem->Which() );
531 : }
532 : else
533 : {
534 : // Status may be accepted only if all slot-pointers are set
535 0 : if ( pImp->bMsgDirty )
536 0 : UpdateSlotServer_Impl();
537 :
538 : // Iterate over the itemset, update if the slot bound
539 : //! Bug: Use WhichIter and possibly send VoidItems up
540 0 : SfxItemIter aIter(rSet);
541 0 : for ( const SfxPoolItem *pItem = aIter.FirstItem();
542 : pItem;
543 : pItem = aIter.NextItem() )
544 : {
545 : SfxStateCache* pCache =
546 0 : GetStateCache( rSet.GetPool()->GetSlotId(pItem->Which()) );
547 0 : if ( pCache )
548 : {
549 : // Update status
550 0 : if ( !pCache->IsControllerDirty() )
551 0 : pCache->Invalidate(false);
552 0 : pCache->SetState( SFX_ITEM_AVAILABLE, pItem );
553 :
554 : //! Not implemented: Updates from EnumSlots via master slots
555 : }
556 0 : }
557 : }
558 0 : }
559 :
560 :
561 :
562 0 : void SfxBindings::SetState
563 : (
564 : const SfxPoolItem& rItem // Status value to be set
565 : )
566 : {
567 0 : if ( nRegLevel )
568 : {
569 0 : Invalidate( rItem.Which() );
570 : }
571 : else
572 : {
573 : // Status may be accepted only if all slot-pointers are set
574 0 : if ( pImp->bMsgDirty )
575 0 : UpdateSlotServer_Impl();
576 :
577 : //update if the slot bound
578 : DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ),
579 : "cannot set items with which-id" );
580 0 : SfxStateCache* pCache = GetStateCache( rItem.Which() );
581 0 : if ( pCache )
582 : {
583 : // Update Status
584 0 : if ( !pCache->IsControllerDirty() )
585 0 : pCache->Invalidate(false);
586 0 : pCache->SetState( SFX_ITEM_AVAILABLE, &rItem );
587 :
588 : //! Not implemented: Updates from EnumSlots via master slots
589 : }
590 : }
591 0 : }
592 :
593 :
594 :
595 :
596 0 : SfxStateCache* SfxBindings::GetAnyStateCache_Impl( sal_uInt16 nId )
597 : {
598 0 : SfxStateCache* pCache = GetStateCache( nId );
599 0 : if ( !pCache && pImp->pSubBindings )
600 0 : return pImp->pSubBindings->GetAnyStateCache_Impl( nId );
601 0 : return pCache;
602 : }
603 :
604 0 : SfxStateCache* SfxBindings::GetStateCache
605 : (
606 : sal_uInt16 nId /* Slot-Id, which SfxStatusCache is to be found */
607 : )
608 : {
609 0 : return GetStateCache(nId, 0);
610 : }
611 :
612 0 : SfxStateCache* SfxBindings::GetStateCache
613 : (
614 : sal_uInt16 nId, /* Slot-Id, which SfxStatusCache is to be found */
615 : sal_uInt16* pPos /* NULL for instance the position from which the
616 : bindings are to be searched binary. Returns the
617 : position back for where the nId was found,
618 : or where it was inserted. */
619 : )
620 : {
621 : DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
622 : // is the specified function bound?
623 0 : const sal_uInt16 nStart = ( pPos ? *pPos : 0 );
624 0 : const sal_uInt16 nPos = GetSlotPos( nId, nStart );
625 :
626 0 : if ( nPos < pImp->pCaches->size() &&
627 0 : (*pImp->pCaches)[nPos]->GetId() == nId )
628 : {
629 0 : if ( pPos )
630 0 : *pPos = nPos;
631 0 : return (*pImp->pCaches)[nPos];
632 : }
633 0 : return 0;
634 : }
635 :
636 :
637 :
638 0 : void SfxBindings::InvalidateAll
639 : (
640 : bool bWithMsg /* true Mark Slot Server as invalid
641 : false Slot Server remains valid */
642 : )
643 : {
644 : DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
645 :
646 0 : if ( pImp->pSubBindings )
647 0 : pImp->pSubBindings->InvalidateAll( bWithMsg );
648 :
649 : // everything is already set dirty or downing => nothing to do
650 0 : if ( !pDispatcher ||
651 0 : ( pImp->bAllDirty && ( !bWithMsg || pImp->bAllMsgDirty ) ) ||
652 0 : SFX_APP()->IsDowning() )
653 : {
654 0 : return;
655 : }
656 :
657 0 : pImp->bAllMsgDirty = pImp->bAllMsgDirty || bWithMsg;
658 0 : pImp->bMsgDirty = pImp->bMsgDirty || pImp->bAllMsgDirty || bWithMsg;
659 0 : pImp->bAllDirty = true;
660 :
661 0 : for ( sal_uInt16 n = 0; n < pImp->pCaches->size(); ++n )
662 0 : (*pImp->pCaches)[n]->Invalidate(bWithMsg);
663 :
664 0 : pImp->nMsgPos = 0;
665 0 : if ( !nRegLevel )
666 : {
667 0 : pImp->aTimer.Stop();
668 0 : pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
669 0 : pImp->aTimer.Start();
670 : }
671 : }
672 :
673 :
674 :
675 0 : void SfxBindings::Invalidate
676 : (
677 : const sal_uInt16* pIds /* numerically sorted NULL-terminated array of
678 : slot IDs (individual, not as a couple!) */
679 : )
680 : {
681 0 : if ( pImp->bInUpdate )
682 : {
683 0 : sal_Int32 i = 0;
684 0 : while ( pIds[i] != 0 )
685 0 : AddSlotToInvalidateSlotsMap_Impl( pIds[i++] );
686 :
687 0 : if ( pImp->pSubBindings )
688 0 : pImp->pSubBindings->Invalidate( pIds );
689 0 : return;
690 : }
691 :
692 0 : if ( pImp->pSubBindings )
693 0 : pImp->pSubBindings->Invalidate( pIds );
694 :
695 : // everything is already set dirty or downing => nothing to do
696 0 : if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
697 0 : return;
698 :
699 : // Search binary in always smaller areas
700 0 : for ( sal_uInt16 n = GetSlotPos(*pIds);
701 0 : *pIds && n < pImp->pCaches->size();
702 0 : n = GetSlotPos(*pIds, n) )
703 : {
704 : // If SID is ever bound, then invalidate the cache
705 0 : SfxStateCache *pCache = (*pImp->pCaches)[n];
706 0 : if ( pCache->GetId() == *pIds )
707 0 : pCache->Invalidate(false);
708 :
709 : // Next SID
710 0 : if ( !*++pIds )
711 0 : break;
712 : DBG_ASSERT( *pIds > *(pIds-1), "pIds unsorted" );
713 : }
714 :
715 : // if not enticed to start update timer
716 0 : pImp->nMsgPos = 0;
717 0 : if ( !nRegLevel )
718 : {
719 0 : pImp->aTimer.Stop();
720 0 : pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
721 0 : pImp->aTimer.Start();
722 : }
723 : }
724 :
725 :
726 :
727 0 : void SfxBindings::InvalidateShell
728 : (
729 : const SfxShell& rSh, /* <SfxShell>, which Slot-Ids should be
730 : invalidated */
731 : bool bDeep /* true
732 : also inherited slot IDs of SfxShell are invalidert
733 :
734 : false
735 : the inherited and not overloaded Slot-Ids were
736 : invalidiert */
737 : // for now always bDeep
738 : )
739 : {
740 : DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
741 :
742 0 : if ( pImp->pSubBindings )
743 0 : pImp->pSubBindings->InvalidateShell( rSh, bDeep );
744 :
745 0 : if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
746 0 : return;
747 :
748 : // flush now already, it is done in GetShellLevel (rsh) anyway,
749 : // important so that is set correctly: pimp-> ball(Msg)Dirty
750 0 : pDispatcher->Flush();
751 :
752 0 : if ( !pDispatcher ||
753 0 : ( pImp->bAllDirty && pImp->bAllMsgDirty ) ||
754 0 : SFX_APP()->IsDowning() )
755 : {
756 : // if the next one is anyway, then all the servers are collected
757 0 : return;
758 : }
759 :
760 : // Find Level
761 0 : sal_uInt16 nLevel = pDispatcher->GetShellLevel(rSh);
762 0 : if ( nLevel != USHRT_MAX )
763 : {
764 0 : for ( sal_uInt16 n = 0; n < pImp->pCaches->size(); ++n )
765 : {
766 0 : SfxStateCache *pCache = (*pImp->pCaches)[n];
767 : const SfxSlotServer *pMsgServer =
768 0 : pCache->GetSlotServer(*pDispatcher, pImp->xProv);
769 0 : if ( pMsgServer && pMsgServer->GetShellLevel() == nLevel )
770 0 : pCache->Invalidate(false);
771 : }
772 0 : pImp->nMsgPos = 0;
773 0 : if ( !nRegLevel )
774 : {
775 0 : pImp->aTimer.Stop();
776 0 : pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
777 0 : pImp->aTimer.Start();
778 0 : pImp->bFirstRound = true;
779 0 : pImp->nFirstShell = nLevel;
780 : }
781 : }
782 : }
783 :
784 :
785 :
786 0 : void SfxBindings::Invalidate
787 : (
788 : sal_uInt16 nId // Status value to be set
789 : )
790 : {
791 0 : if ( pImp->bInUpdate )
792 : {
793 0 : AddSlotToInvalidateSlotsMap_Impl( nId );
794 0 : if ( pImp->pSubBindings )
795 0 : pImp->pSubBindings->Invalidate( nId );
796 0 : return;
797 : }
798 :
799 0 : if ( pImp->pSubBindings )
800 0 : pImp->pSubBindings->Invalidate( nId );
801 :
802 0 : if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
803 0 : return;
804 :
805 0 : SfxStateCache* pCache = GetStateCache(nId);
806 0 : if ( pCache )
807 : {
808 0 : pCache->Invalidate(false);
809 0 : pImp->nMsgPos = std::min(GetSlotPos(nId), pImp->nMsgPos);
810 0 : if ( !nRegLevel )
811 : {
812 0 : pImp->aTimer.Stop();
813 0 : pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
814 0 : pImp->aTimer.Start();
815 : }
816 : }
817 : }
818 :
819 :
820 :
821 0 : void SfxBindings::Invalidate
822 : (
823 : sal_uInt16 nId, // Status value to be set
824 : bool bWithItem, // Clear StateCache?
825 : bool bWithMsg // Get new SlotServer?
826 : )
827 : {
828 : DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
829 :
830 0 : if ( pImp->pSubBindings )
831 0 : pImp->pSubBindings->Invalidate( nId, bWithItem, bWithMsg );
832 :
833 0 : if ( SFX_APP()->IsDowning() )
834 0 : return;
835 :
836 0 : SfxStateCache* pCache = GetStateCache(nId);
837 0 : if ( pCache )
838 : {
839 0 : if ( bWithItem )
840 0 : pCache->ClearCache();
841 0 : pCache->Invalidate(bWithMsg);
842 :
843 0 : if ( !pDispatcher || pImp->bAllDirty )
844 0 : return;
845 :
846 0 : pImp->nMsgPos = std::min(GetSlotPos(nId), pImp->nMsgPos);
847 0 : if ( !nRegLevel )
848 : {
849 0 : pImp->aTimer.Stop();
850 0 : pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
851 0 : pImp->aTimer.Start();
852 : }
853 : }
854 : }
855 :
856 :
857 :
858 0 : bool SfxBindings::IsBound( sal_uInt16 nSlotId, sal_uInt16 nStartSearchAt )
859 : {
860 : DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
861 0 : return GetStateCache(nSlotId, &nStartSearchAt ) != 0;
862 : }
863 :
864 :
865 :
866 0 : sal_uInt16 SfxBindings::GetSlotPos( sal_uInt16 nId, sal_uInt16 nStartSearchAt )
867 : {
868 : DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
869 :
870 : // answer immediately if a function-seek comes repeated
871 0 : if ( pImp->nCachedFunc1 < pImp->pCaches->size() &&
872 0 : (*pImp->pCaches)[pImp->nCachedFunc1]->GetId() == nId )
873 : {
874 0 : return pImp->nCachedFunc1;
875 : }
876 0 : if ( pImp->nCachedFunc2 < pImp->pCaches->size() &&
877 0 : (*pImp->pCaches)[pImp->nCachedFunc2]->GetId() == nId )
878 : {
879 : // swap the caches
880 0 : sal_uInt16 nTemp = pImp->nCachedFunc1;
881 0 : pImp->nCachedFunc1 = pImp->nCachedFunc2;
882 0 : pImp->nCachedFunc2 = nTemp;
883 0 : return pImp->nCachedFunc1;
884 : }
885 :
886 : // binary search, if not found, seek to target-position
887 0 : if ( pImp->pCaches->size() <= nStartSearchAt )
888 : {
889 0 : return 0;
890 : }
891 0 : if ( (sal_uInt16) pImp->pCaches->size() == (nStartSearchAt+1) )
892 : {
893 0 : return (*pImp->pCaches)[nStartSearchAt]->GetId() >= nId ? 0 : 1;
894 : }
895 0 : sal_uInt16 nLow = nStartSearchAt;
896 0 : sal_uInt16 nMid = 0;
897 0 : sal_uInt16 nHigh = 0;
898 0 : bool bFound = false;
899 0 : nHigh = pImp->pCaches->size() - 1;
900 0 : while ( !bFound && nLow <= nHigh )
901 : {
902 0 : nMid = (nLow + nHigh) >> 1;
903 : DBG_ASSERT( nMid < pImp->pCaches->size(), "bsearch is buggy" );
904 0 : int nDiff = (int) nId - (int) ( ((*pImp->pCaches)[nMid])->GetId() );
905 0 : if ( nDiff < 0)
906 0 : { if ( nMid == 0 )
907 0 : break;
908 0 : nHigh = nMid - 1;
909 : }
910 0 : else if ( nDiff > 0 )
911 0 : { nLow = nMid + 1;
912 0 : if ( nLow == 0 )
913 0 : break;
914 : }
915 : else
916 0 : bFound = true;
917 : }
918 0 : sal_uInt16 nPos = bFound ? nMid : nLow;
919 : DBG_ASSERT( nPos <= pImp->pCaches->size(), "" );
920 : DBG_ASSERT( nPos == pImp->pCaches->size() ||
921 : nId <= (*pImp->pCaches)[nPos]->GetId(), "" );
922 : DBG_ASSERT( nPos == nStartSearchAt ||
923 : nId > (*pImp->pCaches)[nPos-1]->GetId(), "" );
924 : DBG_ASSERT( ( (nPos+1) >= (sal_uInt16) pImp->pCaches->size() ) ||
925 : nId < (*pImp->pCaches)[nPos+1]->GetId(), "" );
926 0 : pImp->nCachedFunc2 = pImp->nCachedFunc1;
927 0 : pImp->nCachedFunc1 = nPos;
928 0 : return nPos;
929 : }
930 :
931 0 : void SfxBindings::RegisterInternal_Impl( SfxControllerItem& rItem )
932 : {
933 0 : Register_Impl( rItem, true );
934 :
935 0 : }
936 :
937 0 : void SfxBindings::Register( SfxControllerItem& rItem )
938 : {
939 0 : Register_Impl( rItem, false );
940 0 : }
941 :
942 0 : void SfxBindings::Register_Impl( SfxControllerItem& rItem, bool bInternal )
943 : {
944 : // DBG_ASSERT( nRegLevel > 0, "registration without EnterRegistrations" );
945 : DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Register while status-updating" );
946 :
947 : // insert new cache if it does not already exist
948 0 : sal_uInt16 nId = rItem.GetId();
949 0 : sal_uInt16 nPos = GetSlotPos(nId);
950 0 : if ( nPos >= pImp->pCaches->size() ||
951 0 : (*pImp->pCaches)[nPos]->GetId() != nId )
952 : {
953 0 : SfxStateCache* pCache = new SfxStateCache(nId);
954 0 : pImp->pCaches->insert( pImp->pCaches->begin() + nPos, pCache );
955 : DBG_ASSERT( nPos == 0 ||
956 : (*pImp->pCaches)[nPos]->GetId() >
957 : (*pImp->pCaches)[nPos-1]->GetId(), "" );
958 : DBG_ASSERT( (nPos == pImp->pCaches->size()-1) ||
959 : (*pImp->pCaches)[nPos]->GetId() <
960 : (*pImp->pCaches)[nPos+1]->GetId(), "" );
961 0 : pImp->bMsgDirty = true;
962 : }
963 :
964 : // enqueue the new binding
965 0 : if ( bInternal )
966 : {
967 0 : (*pImp->pCaches)[nPos]->SetInternalController( &rItem );
968 : }
969 : else
970 : {
971 0 : SfxControllerItem *pOldItem = (*pImp->pCaches)[nPos]->ChangeItemLink(&rItem);
972 0 : rItem.ChangeItemLink(pOldItem);
973 : }
974 0 : }
975 :
976 :
977 :
978 0 : void SfxBindings::Release( SfxControllerItem& rItem )
979 : {
980 : DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
981 : DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Release while status-updating" );
982 0 : ENTERREGISTRATIONS();
983 :
984 : // find the bound function
985 0 : sal_uInt16 nId = rItem.GetId();
986 0 : sal_uInt16 nPos = GetSlotPos(nId);
987 0 : SfxStateCache* pCache = (*pImp->pCaches)[nPos];
988 0 : if ( pCache->GetId() == nId )
989 : {
990 0 : if ( pCache->GetInternalController() == &rItem )
991 : {
992 0 : pCache->ReleaseInternalController();
993 : }
994 : else
995 : {
996 : // is this the first binding in the list?
997 0 : SfxControllerItem* pItem = pCache->GetItemLink();
998 0 : if ( pItem == &rItem )
999 0 : pCache->ChangeItemLink( rItem.GetItemLink() );
1000 : else
1001 : {
1002 : // search the binding in the list
1003 0 : while ( pItem && pItem->GetItemLink() != &rItem )
1004 0 : pItem = pItem->GetItemLink();
1005 :
1006 : // unlink it if it was found
1007 0 : if ( pItem )
1008 0 : pItem->ChangeItemLink( rItem.GetItemLink() );
1009 : }
1010 : }
1011 :
1012 : // was this the last controller?
1013 0 : if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() )
1014 : {
1015 0 : pImp->bCtrlReleased = true;
1016 : }
1017 : }
1018 :
1019 0 : LEAVEREGISTRATIONS();
1020 0 : }
1021 :
1022 :
1023 0 : const SfxPoolItem* SfxBindings::ExecuteSynchron( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi,
1024 : const SfxPoolItem **ppInternalArgs )
1025 : {
1026 : DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1027 :
1028 0 : if( !nId || !pDispatcher )
1029 0 : return NULL;
1030 :
1031 0 : return Execute_Impl( nId, ppItems, nModi, SFX_CALLMODE_SYNCHRON, ppInternalArgs );
1032 : }
1033 :
1034 0 : bool SfxBindings::Execute( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode,
1035 : const SfxPoolItem **ppInternalArgs )
1036 : {
1037 : DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1038 :
1039 0 : if( !nId || !pDispatcher )
1040 0 : return false;
1041 :
1042 0 : const SfxPoolItem* pRet = Execute_Impl( nId, ppItems, nModi, nCallMode, ppInternalArgs );
1043 0 : return ( pRet != 0 );
1044 : }
1045 :
1046 0 : const SfxPoolItem* SfxBindings::Execute_Impl( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode,
1047 : const SfxPoolItem **ppInternalArgs, bool bGlobalOnly )
1048 : {
1049 0 : SfxStateCache *pCache = GetStateCache( nId );
1050 0 : if ( !pCache )
1051 : {
1052 0 : SfxBindings *pBind = pImp->pSubBindings;
1053 0 : while ( pBind )
1054 : {
1055 0 : if ( pBind->GetStateCache( nId ) )
1056 0 : return pBind->Execute_Impl( nId, ppItems, nModi, nCallMode, ppInternalArgs, bGlobalOnly );
1057 0 : pBind = pBind->pImp->pSubBindings;
1058 : };
1059 : }
1060 :
1061 0 : SfxDispatcher &rDispatcher = *pDispatcher;
1062 0 : rDispatcher.Flush();
1063 0 : rDispatcher.GetFrame(); // -Wall is this required???
1064 :
1065 : // get SlotServer (Slot+ShellLevel) and Shell from cache
1066 0 : ::boost::scoped_ptr<SfxStateCache> xCache;
1067 0 : if ( !pCache )
1068 : {
1069 : // Execution of non cached slots (Accelerators don't use Controllers)
1070 : // slot is uncached, use SlotCache to handle external dispatch providers
1071 0 : xCache.reset(new SfxStateCache(nId));
1072 0 : pCache = xCache.get();
1073 0 : pCache->GetSlotServer( rDispatcher, pImp->xProv );
1074 : }
1075 :
1076 0 : if ( pCache->GetDispatch().is() )
1077 : {
1078 : DBG_ASSERT( !ppInternalArgs, "Internal args get lost when dispatched!" );
1079 :
1080 0 : SfxItemPool &rPool = GetDispatcher()->GetFrame()->GetObjectShell()->GetPool();
1081 0 : SfxRequest aReq( nId, nCallMode, rPool );
1082 0 : aReq.SetModifier( nModi );
1083 0 : if( ppItems )
1084 0 : while( *ppItems )
1085 0 : aReq.AppendItem( **ppItems++ );
1086 :
1087 : // cache binds to an external dispatch provider
1088 0 : pCache->Dispatch( aReq.GetArgs(), nCallMode == SFX_CALLMODE_SYNCHRON );
1089 0 : SfxPoolItem *pVoid = new SfxVoidItem( nId );
1090 0 : DeleteItemOnIdle( pVoid );
1091 0 : return pVoid;
1092 : }
1093 :
1094 : // slot is handled internally by SfxDispatcher
1095 0 : if ( pImp->bMsgDirty )
1096 0 : UpdateSlotServer_Impl();
1097 :
1098 0 : SfxShell *pShell=0;
1099 0 : const SfxSlot *pSlot=0;
1100 :
1101 0 : const SfxSlotServer* pServer = pCache->GetSlotServer( rDispatcher, pImp->xProv );
1102 0 : if ( !pServer )
1103 : {
1104 0 : return NULL;
1105 : }
1106 : else
1107 : {
1108 0 : pShell = rDispatcher.GetShell( pServer->GetShellLevel() );
1109 0 : pSlot = pServer->GetSlot();
1110 : }
1111 :
1112 0 : if ( bGlobalOnly )
1113 0 : if ( !pShell->ISA(SfxModule) && !pShell->ISA(SfxApplication) && !pShell->ISA(SfxViewFrame) )
1114 0 : return NULL;
1115 :
1116 0 : SfxItemPool &rPool = pShell->GetPool();
1117 0 : SfxRequest aReq( nId, nCallMode, rPool );
1118 0 : aReq.SetModifier( nModi );
1119 0 : if( ppItems )
1120 0 : while( *ppItems )
1121 0 : aReq.AppendItem( **ppItems++ );
1122 0 : if ( ppInternalArgs )
1123 : {
1124 0 : SfxAllItemSet aSet( rPool );
1125 0 : for ( const SfxPoolItem **pArg = ppInternalArgs; *pArg; ++pArg )
1126 0 : aSet.Put( **pArg );
1127 0 : aReq.SetInternalArgs_Impl( aSet );
1128 : }
1129 :
1130 0 : Execute_Impl( aReq, pSlot, pShell );
1131 :
1132 0 : const SfxPoolItem* pRet = aReq.GetReturnValue();
1133 0 : if ( !pRet )
1134 : {
1135 0 : SfxPoolItem *pVoid = new SfxVoidItem( nId );
1136 0 : DeleteItemOnIdle( pVoid );
1137 0 : pRet = pVoid;
1138 : }
1139 :
1140 0 : return pRet;
1141 : }
1142 :
1143 0 : void SfxBindings::Execute_Impl( SfxRequest& aReq, const SfxSlot* pSlot, SfxShell* pShell )
1144 : {
1145 0 : SfxItemPool &rPool = pShell->GetPool();
1146 :
1147 0 : if ( SFX_KIND_ENUM == pSlot->GetKind() )
1148 : {
1149 : // for Enum-Slots, the Master has to be excecuted with the value
1150 : // of the enums
1151 0 : const SfxSlot *pRealSlot = pShell->GetInterface()->GetRealSlot(pSlot);
1152 0 : const sal_uInt16 nSlotId = pRealSlot->GetSlotId();
1153 0 : aReq.SetSlot( nSlotId );
1154 0 : aReq.AppendItem( SfxAllEnumItem( rPool.GetWhich(nSlotId), pSlot->GetValue() ) );
1155 0 : pDispatcher->_Execute( *pShell, *pRealSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD );
1156 : }
1157 0 : else if ( SFX_KIND_ATTR == pSlot->GetKind() )
1158 : {
1159 : // Which value has to be mapped for Attribute slots
1160 0 : const sal_uInt16 nSlotId = pSlot->GetSlotId();
1161 0 : aReq.SetSlot( nSlotId );
1162 0 : if ( pSlot->IsMode(SFX_SLOT_TOGGLE) )
1163 : {
1164 : // The value is attached to a toggleable attribute (Bools)
1165 0 : sal_uInt16 nWhich = pSlot->GetWhich(rPool);
1166 0 : SfxItemSet aSet(rPool, nWhich, nWhich);
1167 0 : SfxStateFunc aFunc = pSlot->GetStateFnc();
1168 0 : pShell->CallState( aFunc, aSet );
1169 : const SfxPoolItem *pOldItem;
1170 0 : SfxItemState eState = aSet.GetItemState(nWhich, true, &pOldItem);
1171 0 : if ( eState == SFX_ITEM_DISABLED )
1172 0 : return;
1173 :
1174 0 : if ( SFX_ITEM_AVAILABLE == eState && SfxItemPool::IsWhich(nWhich) )
1175 0 : pOldItem = &aSet.Get(nWhich);
1176 :
1177 0 : if ( SFX_ITEM_SET == eState ||
1178 0 : ( SFX_ITEM_AVAILABLE == eState &&
1179 0 : SfxItemPool::IsWhich(nWhich) &&
1180 : pOldItem ) )
1181 : {
1182 0 : if ( pOldItem->ISA(SfxBoolItem) )
1183 : {
1184 : // we can toggle Bools
1185 0 : bool bOldValue = ((const SfxBoolItem *)pOldItem)->GetValue();
1186 0 : SfxBoolItem *pNewItem = (SfxBoolItem*) (pOldItem->Clone());
1187 0 : pNewItem->SetValue( !bOldValue );
1188 0 : aReq.AppendItem( *pNewItem );
1189 0 : delete pNewItem;
1190 : }
1191 0 : else if ( pOldItem->ISA(SfxEnumItemInterface) &&
1192 0 : ((SfxEnumItemInterface *)pOldItem)->HasBoolValue())
1193 : {
1194 : // and Enums with Bool-Interface
1195 : SfxEnumItemInterface *pNewItem =
1196 0 : (SfxEnumItemInterface*) (pOldItem->Clone());
1197 0 : pNewItem->SetBoolValue(!((SfxEnumItemInterface *)pOldItem)->GetBoolValue());
1198 0 : aReq.AppendItem( *pNewItem );
1199 0 : delete pNewItem;
1200 : }
1201 : else {
1202 : OSL_FAIL( "Toggle only for Enums and Bools allowed" );
1203 : }
1204 : }
1205 0 : else if ( SFX_ITEM_DONTCARE == eState )
1206 : {
1207 : // Create one Status-Item for each Factory
1208 0 : SfxPoolItem *pNewItem = pSlot->GetType()->CreateItem();
1209 : DBG_ASSERT( pNewItem, "Toggle to slot without ItemFactory" );
1210 0 : pNewItem->SetWhich( nWhich );
1211 :
1212 0 : if ( pNewItem->ISA(SfxBoolItem) )
1213 : {
1214 : // we can toggle Bools
1215 0 : ((SfxBoolItem*)pNewItem)->SetValue( true );
1216 0 : aReq.AppendItem( *pNewItem );
1217 : }
1218 0 : else if ( pNewItem->ISA(SfxEnumItemInterface) &&
1219 0 : ((SfxEnumItemInterface *)pNewItem)->HasBoolValue())
1220 : {
1221 : // and Enums with Bool-Interface
1222 0 : ((SfxEnumItemInterface*)pNewItem)->SetBoolValue(true);
1223 0 : aReq.AppendItem( *pNewItem );
1224 : }
1225 : else {
1226 : OSL_FAIL( "Toggle only for Enums and Bools allowed" );
1227 : }
1228 0 : delete pNewItem;
1229 : }
1230 : else {
1231 : OSL_FAIL( "suspicious Toggle-Slot" );
1232 0 : }
1233 : }
1234 :
1235 0 : pDispatcher->_Execute( *pShell, *pSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD );
1236 : }
1237 : else
1238 0 : pDispatcher->_Execute( *pShell, *pSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD );
1239 : }
1240 :
1241 :
1242 :
1243 0 : void SfxBindings::UpdateSlotServer_Impl()
1244 : {
1245 : DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1246 :
1247 : // synchronize
1248 0 : pDispatcher->Flush();
1249 :
1250 0 : if ( pImp->bAllMsgDirty )
1251 : {
1252 0 : if ( !nRegLevel )
1253 : {
1254 : ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame
1255 0 : ( pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY );
1256 0 : pImp->bContextChanged = false;
1257 : }
1258 : else
1259 0 : pImp->bContextChanged = true;
1260 : }
1261 :
1262 0 : for (size_t i = 0, nCount = pImp->pCaches->size(); i < nCount; ++i)
1263 : {
1264 0 : SfxStateCache *pCache = (*pImp->pCaches)[i];
1265 : //GetSlotServer can modify pImp->pCaches
1266 0 : pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1267 : }
1268 0 : pImp->bMsgDirty = pImp->bAllMsgDirty = false;
1269 :
1270 0 : Broadcast( SfxSimpleHint(SFX_HINT_DOCCHANGED) );
1271 0 : }
1272 :
1273 :
1274 :
1275 0 : SfxItemSet* SfxBindings::CreateSet_Impl
1276 : (
1277 : SfxStateCache*& pCache, // in: Status-Cache from nId
1278 : const SfxSlot*& pRealSlot, // out: RealSlot to nId
1279 : const SfxSlotServer** pMsgServer, // out: Slot-Server to nId
1280 : SfxFoundCacheArr_Impl& rFound // out: List of Caches for Siblings
1281 : )
1282 : {
1283 : DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1284 :
1285 : DBG_ASSERT( !pImp->bMsgDirty, "CreateSet_Impl with dirty MessageServer" );
1286 :
1287 0 : const SfxSlotServer* pMsgSvr = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1288 0 : if(!pMsgSvr || !pDispatcher)
1289 0 : return 0;
1290 :
1291 0 : pRealSlot = 0;
1292 0 : *pMsgServer = pMsgSvr;
1293 :
1294 0 : sal_uInt16 nShellLevel = pMsgSvr->GetShellLevel();
1295 0 : SfxShell *pShell = pDispatcher->GetShell( nShellLevel );
1296 0 : if ( !pShell ) // rare GPF when browsing through update from Inet-Notify
1297 0 : return 0;
1298 :
1299 0 : SfxItemPool &rPool = pShell->GetPool();
1300 :
1301 : // get the status method, which is served by the pCache
1302 0 : SfxStateFunc pFnc = 0;
1303 0 : const SfxInterface *pInterface = pShell->GetInterface();
1304 0 : if ( SFX_KIND_ENUM == pMsgSvr->GetSlot()->GetKind() )
1305 : {
1306 0 : pRealSlot = pInterface->GetRealSlot(pMsgSvr->GetSlot());
1307 0 : pCache = GetStateCache( pRealSlot->GetSlotId() );
1308 : }
1309 : else
1310 0 : pRealSlot = pMsgSvr->GetSlot();
1311 :
1312 : // Note: pCache can be NULL!
1313 :
1314 0 : pFnc = pRealSlot->GetStateFnc();
1315 :
1316 : // the RealSlot is always on
1317 : SfxFoundCache_Impl *pFound = new SfxFoundCache_Impl(
1318 0 : pRealSlot->GetSlotId(), pRealSlot->GetWhich(rPool), pRealSlot, pCache );
1319 0 : rFound.push_back( pFound );
1320 :
1321 0 : sal_uInt16 nSlot = pRealSlot->GetSlotId();
1322 0 : if ( !(nSlot >= SID_VERB_START && nSlot <= SID_VERB_END) )
1323 : {
1324 0 : pInterface = pInterface->GetRealInterfaceForSlot( pRealSlot );
1325 : DBG_ASSERT (pInterface,"Slot in the given shell is not found");
1326 : }
1327 :
1328 : // Search through the bindings for slots served by the same function. This , // will only affect slots which are present in the found interface.
1329 :
1330 : // The position of the Statecaches in StateCache-Array
1331 0 : sal_uInt16 nCachePos = pImp->nMsgPos;
1332 0 : const SfxSlot *pSibling = pRealSlot->GetNextSlot();
1333 :
1334 : // the Slots ODF a interfaces ar linked in a circle
1335 0 : while ( pSibling > pRealSlot )
1336 : {
1337 0 : SfxStateFunc pSiblingFnc=0;
1338 : SfxStateCache *pSiblingCache =
1339 0 : GetStateCache( pSibling->GetSlotId(), &nCachePos );
1340 :
1341 : // Is the slot cached ?
1342 0 : if ( pSiblingCache )
1343 : {
1344 0 : const SfxSlotServer *pServ = pSiblingCache->GetSlotServer(*pDispatcher, pImp->xProv);
1345 0 : if ( pServ && pServ->GetShellLevel() == nShellLevel )
1346 0 : pSiblingFnc = pServ->GetSlot()->GetStateFnc();
1347 : }
1348 :
1349 : // Does the slot have to be updated at all?
1350 0 : bool bInsert = pSiblingCache && pSiblingCache->IsControllerDirty();
1351 :
1352 : // It is not enough to ask for the same shell!!
1353 0 : bool bSameMethod = pSiblingCache && pFnc == pSiblingFnc;
1354 :
1355 : // If the slot is a non-dirty master slot, then maybe one of his slaves
1356 : // is dirty? Then the master slot is still inserted.
1357 0 : if ( !bInsert && bSameMethod && pSibling->GetLinkedSlot() )
1358 : {
1359 : // Also check slave slots for Binding
1360 0 : const SfxSlot* pFirstSlave = pSibling->GetLinkedSlot();
1361 0 : for ( const SfxSlot *pSlaveSlot = pFirstSlave;
1362 0 : !bInsert;
1363 : pSlaveSlot = pSlaveSlot->GetNextSlot())
1364 : {
1365 : // the slaves points to its master
1366 : DBG_ASSERT(pSlaveSlot->GetLinkedSlot() == pSibling,
1367 : "Wrong Master/Slave relationship!");
1368 :
1369 0 : sal_uInt16 nCurMsgPos = pImp->nMsgPos;
1370 : const SfxStateCache *pSlaveCache =
1371 0 : GetStateCache( pSlaveSlot->GetSlotId(), &nCurMsgPos );
1372 :
1373 : // Is the slave slot chached and dirty ?
1374 0 : bInsert = pSlaveCache && pSlaveCache->IsControllerDirty();
1375 :
1376 : // Slaves are chained together in a circle
1377 0 : if (pSlaveSlot->GetNextSlot() == pFirstSlave)
1378 0 : break;
1379 : }
1380 : }
1381 :
1382 0 : if ( bInsert && bSameMethod )
1383 : {
1384 : SfxFoundCache_Impl *pFoundCache = new SfxFoundCache_Impl(
1385 0 : pSibling->GetSlotId(), pSibling->GetWhich(rPool),
1386 0 : pSibling, pSiblingCache );
1387 :
1388 0 : rFound.push_back( pFoundCache );
1389 : }
1390 :
1391 0 : pSibling = pSibling->GetNextSlot();
1392 : }
1393 :
1394 : // Create a Set from the ranges
1395 0 : boost::scoped_array<sal_uInt16> pRanges(new sal_uInt16[rFound.size() * 2 + 1]);
1396 0 : int j = 0;
1397 0 : sal_uInt16 i = 0;
1398 0 : while ( i < rFound.size() )
1399 : {
1400 0 : pRanges[j++] = rFound[i]->nWhichId;
1401 : // consecutive numbers
1402 0 : for ( ; i < rFound.size()-1; ++i )
1403 0 : if ( rFound[i]->nWhichId+1 != rFound[i+1]->nWhichId )
1404 0 : break;
1405 0 : pRanges[j++] = rFound[i++]->nWhichId;
1406 : }
1407 0 : pRanges[j] = 0; // terminating NULL
1408 0 : SfxItemSet *pSet = new SfxItemSet(rPool, pRanges.get());
1409 0 : pRanges.reset();
1410 0 : return pSet;
1411 : }
1412 :
1413 :
1414 :
1415 0 : void SfxBindings::UpdateControllers_Impl
1416 : (
1417 : const SfxInterface* pIF, // Id of the current serving Interface
1418 : const SfxFoundCache_Impl* pFound, // Cache, Slot, Which etc.
1419 : const SfxPoolItem* pItem, // item to send to controller
1420 : SfxItemState eState // state of item
1421 : )
1422 : {
1423 : DBG_ASSERT( !pFound->pSlot || SFX_KIND_ENUM != pFound->pSlot->GetKind(),
1424 : "direct update of enum slot isn't allowed" );
1425 :
1426 0 : SfxStateCache* pCache = pFound->pCache;
1427 0 : const SfxSlot* pSlot = pFound->pSlot;
1428 : DBG_ASSERT( !pCache || !pSlot || pCache->GetId() == pSlot->GetSlotId(), "SID mismatch" );
1429 :
1430 : // bound until now, the Controller to update the Slot.
1431 0 : if ( pCache && pCache->IsControllerDirty() )
1432 : {
1433 0 : if ( SFX_ITEM_DONTCARE == eState )
1434 : {
1435 : // ambiguous
1436 0 : pCache->SetState( SFX_ITEM_DONTCARE, (SfxPoolItem *)-1 );
1437 : }
1438 0 : else if ( SFX_ITEM_DEFAULT == eState &&
1439 0 : pFound->nWhichId > SFX_WHICH_MAX )
1440 : {
1441 : // no Status or Default but without Pool
1442 0 : SfxVoidItem aVoid(0);
1443 0 : pCache->SetState( SFX_ITEM_UNKNOWN, &aVoid );
1444 : }
1445 0 : else if ( SFX_ITEM_DISABLED == eState )
1446 0 : pCache->SetState(SFX_ITEM_DISABLED, 0);
1447 : else
1448 0 : pCache->SetState(SFX_ITEM_AVAILABLE, pItem);
1449 : }
1450 :
1451 : // Update the slots for so far available and bound Controllers for
1452 : // Slave-Slots (Enum-value)
1453 : DBG_ASSERT( !pSlot || 0 == pSlot->GetLinkedSlot() || !pItem ||
1454 : pItem->ISA(SfxEnumItemInterface),
1455 : "master slot with non-enum-type found" );
1456 0 : const SfxSlot *pFirstSlave = pSlot ? pSlot->GetLinkedSlot() : 0;
1457 0 : if ( pIF && pFirstSlave)
1458 : {
1459 : // Items cast on EnumItem
1460 : const SfxEnumItemInterface *pEnumItem =
1461 0 : PTR_CAST(SfxEnumItemInterface,pItem);
1462 0 : if ( eState == SFX_ITEM_AVAILABLE && !pEnumItem )
1463 0 : eState = SFX_ITEM_DONTCARE;
1464 : else
1465 0 : eState = SfxControllerItem::GetItemState( pEnumItem );
1466 :
1467 : // Iterate over all Slaves-Slots
1468 0 : for ( const SfxSlot *pSlave = pFirstSlave; pSlave; pSlave = pSlave->GetNextSlot() )
1469 : {
1470 : DBG_ASSERT(pSlave, "Wrong SlaveSlot binding!");
1471 : DBG_ASSERT(SFX_KIND_ENUM == pSlave->GetKind(),"non enum slaves aren't allowed");
1472 : DBG_ASSERT(pSlave->GetMasterSlotId() == pSlot->GetSlotId(),"Wrong MasterSlot!");
1473 :
1474 : // Binding exist for function ?
1475 0 : SfxStateCache *pEnumCache = GetStateCache( pSlave->GetSlotId() );
1476 0 : if ( pEnumCache )
1477 : {
1478 0 : pEnumCache->Invalidate(false);
1479 :
1480 : // HACK(CONTROL/SELECT Kram) ???
1481 0 : if ( eState == SFX_ITEM_DONTCARE && pFound->nWhichId == 10144 )
1482 : {
1483 0 : SfxVoidItem aVoid(0);
1484 0 : pEnumCache->SetState( SFX_ITEM_UNKNOWN, &aVoid );
1485 :
1486 0 : if (pSlave->GetNextSlot() == pFirstSlave)
1487 0 : break;
1488 :
1489 0 : continue;
1490 : }
1491 :
1492 0 : if ( SFX_ITEM_DISABLED == eState || (pEnumItem && !pEnumItem->IsEnabled( pSlave->GetSlotId())) )
1493 : {
1494 : // disabled
1495 0 : pEnumCache->SetState(SFX_ITEM_DISABLED, 0);
1496 : }
1497 0 : else if ( SFX_ITEM_AVAILABLE == eState && pEnumItem )
1498 : {
1499 : // Determine enum value
1500 0 : sal_uInt16 nValue = pEnumItem->GetEnumValue();
1501 0 : SfxBoolItem aBool( pFound->nWhichId, pSlave->GetValue() == nValue );
1502 0 : pEnumCache->SetState(SFX_ITEM_AVAILABLE, &aBool);
1503 : }
1504 : else
1505 : {
1506 : // ambiguous
1507 0 : pEnumCache->SetState( SFX_ITEM_DONTCARE, (SfxPoolItem *)-1 );
1508 : }
1509 : }
1510 :
1511 0 : if (pSlave->GetNextSlot() == pFirstSlave)
1512 0 : break;
1513 : }
1514 : }
1515 0 : }
1516 :
1517 :
1518 :
1519 :
1520 0 : IMPL_LINK( SfxBindings, NextJob_Impl, Timer *, pTimer )
1521 : {
1522 : #ifdef DBG_UTIL
1523 : // on Windows very often C++ Exceptions (GPF etc.) are caught by MSVCRT
1524 : // or another MS library try to get them here
1525 : try
1526 : {
1527 : #endif
1528 0 : const unsigned MAX_INPUT_DELAY = 200;
1529 :
1530 : DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1531 :
1532 0 : if ( Application::GetLastInputInterval() < MAX_INPUT_DELAY && pTimer )
1533 : {
1534 0 : pImp->aTimer.SetTimeout(TIMEOUT_UPDATING);
1535 0 : return sal_True;
1536 : }
1537 :
1538 0 : SfxApplication *pSfxApp = SFX_APP();
1539 :
1540 0 : if( pDispatcher )
1541 0 : pDispatcher->Update_Impl();
1542 :
1543 : // modifying the SfxObjectInterface-stack without SfxBindings => nothing to do
1544 0 : SfxViewFrame* pFrame = pDispatcher ? pDispatcher->GetFrame() : NULL;
1545 0 : if ( (pFrame && !pFrame->GetObjectShell()->AcceptStateUpdate()) || pSfxApp->IsDowning() || pImp->pCaches->empty() )
1546 : {
1547 0 : return sal_True;
1548 : }
1549 0 : if ( !pDispatcher || !pDispatcher->IsFlushed() )
1550 : {
1551 0 : return sal_True;
1552 : }
1553 :
1554 : // if possible Update all server / happens in its own time slice
1555 0 : if ( pImp->bMsgDirty )
1556 : {
1557 0 : UpdateSlotServer_Impl();
1558 0 : return sal_False;
1559 : }
1560 :
1561 0 : pImp->bAllDirty = false;
1562 0 : pImp->aTimer.SetTimeout(TIMEOUT_UPDATING);
1563 :
1564 : // at least 10 loops and further if more jobs are available but no input
1565 0 : bool bPreEmptive = pTimer && !pSfxApp->Get_Impl()->nInReschedule;
1566 0 : sal_uInt16 nLoops = 10;
1567 0 : pImp->bInNextJob = true;
1568 0 : const sal_uInt16 nCount = pImp->pCaches->size();
1569 0 : while ( pImp->nMsgPos < nCount )
1570 : {
1571 : // iterate through the bound functions
1572 0 : bool bJobDone = false;
1573 0 : while ( !bJobDone )
1574 : {
1575 0 : SfxStateCache* pCache = (*pImp->pCaches)[pImp->nMsgPos];
1576 : DBG_ASSERT( pCache, "invalid SfxStateCache-position in job queue" );
1577 0 : bool bWasDirty = pCache->IsControllerDirty();
1578 0 : if ( bWasDirty )
1579 : {
1580 0 : Update_Impl( pCache );
1581 : DBG_ASSERT( nCount == pImp->pCaches->size(),
1582 : "Reschedule in StateChanged => buff" );
1583 : }
1584 :
1585 : // skip to next function binding
1586 0 : ++pImp->nMsgPos;
1587 :
1588 : // keep job if it is not completed, but any input is available
1589 0 : bJobDone = pImp->nMsgPos >= nCount;
1590 0 : if ( bJobDone && pImp->bFirstRound )
1591 : {
1592 :
1593 : // Update of the preferred shell has been done, now may
1594 : // also the others shells be updated
1595 0 : bJobDone = false;
1596 0 : pImp->bFirstRound = false;
1597 0 : pImp->nMsgPos = 0;
1598 : }
1599 :
1600 0 : if ( bWasDirty && !bJobDone && bPreEmptive && (--nLoops == 0) )
1601 : {
1602 0 : pImp->bInNextJob = false;
1603 0 : return sal_False;
1604 : }
1605 : }
1606 : }
1607 :
1608 0 : pImp->nMsgPos = 0;
1609 :
1610 : // check for volatile slots
1611 0 : bool bVolatileSlotsPresent = false;
1612 0 : for ( sal_uInt16 n = 0; n < nCount; ++n )
1613 : {
1614 0 : SfxStateCache* pCache = (*pImp->pCaches)[n];
1615 0 : const SfxSlotServer *pSlotServer = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1616 0 : if ( pSlotServer && pSlotServer->GetSlot()->IsMode(SFX_SLOT_VOLATILE) )
1617 : {
1618 0 : pCache->Invalidate(false);
1619 0 : bVolatileSlotsPresent = true;
1620 : }
1621 : }
1622 :
1623 0 : if (bVolatileSlotsPresent)
1624 0 : pImp->aTimer.SetTimeout(TIMEOUT_IDLE);
1625 : else
1626 0 : pImp->aTimer.Stop();
1627 :
1628 : // Update round is finished
1629 0 : pImp->bInNextJob = false;
1630 0 : Broadcast(SfxSimpleHint(SFX_HINT_UPDATEDONE));
1631 0 : return sal_True;
1632 : #ifdef DBG_UTIL
1633 : }
1634 : catch (...)
1635 : {
1636 : OSL_FAIL("C++ exception caught!");
1637 : pImp->bInNextJob = false;
1638 : }
1639 :
1640 : return sal_False;
1641 : #endif
1642 : }
1643 :
1644 :
1645 :
1646 0 : sal_uInt16 SfxBindings::EnterRegistrations(const char *pFile, int nLine)
1647 : {
1648 : SAL_INFO(
1649 : "sfx.control",
1650 : std::setw(std::min(nRegLevel, sal_uInt16(8))) << ' ' << "this = " << this
1651 : << " Level = " << nRegLevel << " SfxBindings::EnterRegistrations "
1652 : << (pFile
1653 : ? SAL_STREAM("File: " << pFile << " Line: " << nLine) : ""));
1654 :
1655 : // When bindings are locked, also lock sub bindings.
1656 0 : if ( pImp->pSubBindings )
1657 : {
1658 0 : pImp->pSubBindings->ENTERREGISTRATIONS();
1659 :
1660 : // These EnterRegistrations are not "real" for the SubBindings
1661 0 : pImp->pSubBindings->pImp->nOwnRegLevel--;
1662 :
1663 : // Synchronize Bindings
1664 0 : pImp->pSubBindings->nRegLevel = nRegLevel + pImp->pSubBindings->pImp->nOwnRegLevel + 1;
1665 : }
1666 :
1667 0 : pImp->nOwnRegLevel++;
1668 :
1669 : // check if this is the outer most level
1670 0 : if ( ++nRegLevel == 1 )
1671 : {
1672 : // stop background-processing
1673 0 : pImp->aTimer.Stop();
1674 :
1675 : // flush the cache
1676 0 : pImp->nCachedFunc1 = 0;
1677 0 : pImp->nCachedFunc2 = 0;
1678 :
1679 : // Mark if the all of the Caches have dissapered.
1680 0 : pImp->bCtrlReleased = false;
1681 : }
1682 :
1683 0 : return nRegLevel;
1684 : }
1685 :
1686 :
1687 0 : void SfxBindings::LeaveRegistrations( sal_uInt16 nLevel, const char *pFile, int nLine )
1688 : {
1689 : (void)nLevel; // unused variable
1690 : DBG_ASSERT( nRegLevel, "Leave without Enter" );
1691 : DBG_ASSERT( nLevel == USHRT_MAX || nLevel == nRegLevel, "wrong Leave" );
1692 :
1693 : // Only when the SubBindings are still locked by the Superbindings,
1694 : // remove this lock (i.e. if there are more locks than "real" ones)
1695 0 : if ( pImp->pSubBindings && pImp->pSubBindings->nRegLevel > pImp->pSubBindings->pImp->nOwnRegLevel )
1696 : {
1697 : // Synchronize Bindings
1698 0 : pImp->pSubBindings->nRegLevel = nRegLevel + pImp->pSubBindings->pImp->nOwnRegLevel;
1699 :
1700 : // This LeaveRegistrations is not "real" for SubBindings
1701 0 : pImp->pSubBindings->pImp->nOwnRegLevel++;
1702 0 : pImp->pSubBindings->LEAVEREGISTRATIONS();
1703 : }
1704 :
1705 0 : pImp->nOwnRegLevel--;
1706 :
1707 : // check if this is the outer most level
1708 0 : if ( --nRegLevel == 0 && !SFX_APP()->IsDowning() )
1709 : {
1710 0 : if ( pImp->bContextChanged )
1711 : {
1712 0 : pImp->bContextChanged = false;
1713 : }
1714 :
1715 0 : SfxViewFrame* pFrame = pDispatcher->GetFrame();
1716 :
1717 : // If possible remove unused Caches, for example prepare PlugInInfo
1718 0 : if ( pImp->bCtrlReleased )
1719 : {
1720 0 : for ( sal_uInt16 nCache = pImp->pCaches->size(); nCache > 0; --nCache )
1721 : {
1722 : // Get Cache via ::com::sun::star::sdbcx::Index
1723 0 : SfxStateCache *pCache = (*pImp->pCaches)[nCache-1];
1724 :
1725 : // No interested Controller present
1726 0 : if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() )
1727 : {
1728 : // Remove Cache. Safety: first remove and then delete
1729 0 : pImp->pCaches->erase(pImp->pCaches->begin() + nCache - 1);
1730 0 : delete pCache;
1731 : }
1732 : }
1733 : }
1734 :
1735 : // restart background-processing
1736 0 : pImp->nMsgPos = 0;
1737 0 : if ( !pFrame || !pFrame->GetObjectShell() )
1738 0 : return;
1739 0 : if ( pImp->pCaches && !pImp->pCaches->empty() )
1740 : {
1741 0 : pImp->aTimer.Stop();
1742 0 : pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
1743 0 : pImp->aTimer.Start();
1744 : }
1745 : }
1746 :
1747 : SAL_INFO(
1748 : "sfx.control",
1749 : std::setw(std::min(nRegLevel, sal_uInt16(8))) << ' ' << "this = " << this
1750 : << " Level = " << nRegLevel << " SfxBindings::LeaveRegistrations "
1751 : << (pFile
1752 : ? SAL_STREAM("File: " << pFile << " Line: " << nLine) : ""));
1753 : }
1754 :
1755 :
1756 :
1757 0 : void SfxBindings::SetDispatcher( SfxDispatcher *pDisp )
1758 : {
1759 0 : SfxDispatcher *pOldDispat = pDispatcher;
1760 0 : if ( pDisp != pDispatcher )
1761 : {
1762 0 : if ( pOldDispat )
1763 : {
1764 0 : SfxBindings* pBind = pOldDispat->GetBindings();
1765 0 : while ( pBind )
1766 : {
1767 0 : if ( pBind->pImp->pSubBindings == this && pBind->pDispatcher != pDisp )
1768 0 : pBind->SetSubBindings_Impl( NULL );
1769 0 : pBind = pBind->pImp->pSubBindings;
1770 : }
1771 : }
1772 :
1773 0 : pDispatcher = pDisp;
1774 :
1775 0 : ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider > xProv;
1776 0 : if ( pDisp )
1777 0 : xProv = ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider >
1778 0 : ( pDisp->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY );
1779 :
1780 0 : SetDispatchProvider_Impl( xProv );
1781 0 : InvalidateAll( true );
1782 0 : InvalidateUnoControllers_Impl();
1783 :
1784 0 : if ( pDispatcher && !pOldDispat )
1785 : {
1786 0 : if ( pImp->pSubBindings && pImp->pSubBindings->pDispatcher != pOldDispat )
1787 : {
1788 : OSL_FAIL( "SubBindings already set before activating!" );
1789 0 : pImp->pSubBindings->ENTERREGISTRATIONS();
1790 : }
1791 0 : LEAVEREGISTRATIONS();
1792 : }
1793 0 : else if( !pDispatcher )
1794 : {
1795 0 : ENTERREGISTRATIONS();
1796 0 : if ( pImp->pSubBindings && pImp->pSubBindings->pDispatcher != pOldDispat )
1797 : {
1798 : OSL_FAIL( "SubBindings still set even when deactivating!" );
1799 0 : pImp->pSubBindings->LEAVEREGISTRATIONS();
1800 : }
1801 : }
1802 :
1803 0 : Broadcast( SfxSimpleHint( SFX_HINT_DATACHANGED ) );
1804 :
1805 0 : if ( pDisp )
1806 : {
1807 0 : SfxBindings* pBind = pDisp->GetBindings();
1808 0 : while ( pBind && pBind != this )
1809 : {
1810 0 : if ( !pBind->pImp->pSubBindings )
1811 : {
1812 0 : pBind->SetSubBindings_Impl( this );
1813 0 : break;
1814 : }
1815 :
1816 0 : pBind = pBind->pImp->pSubBindings;
1817 : }
1818 0 : }
1819 : }
1820 0 : }
1821 :
1822 :
1823 :
1824 0 : void SfxBindings::ClearCache_Impl( sal_uInt16 nSlotId )
1825 : {
1826 0 : SfxStateCache* pCache = GetStateCache(nSlotId);
1827 0 : if (!pCache)
1828 0 : return;
1829 0 : pCache->ClearCache();
1830 : }
1831 :
1832 :
1833 0 : void SfxBindings::StartUpdate_Impl( bool bComplete )
1834 : {
1835 0 : if ( pImp->pSubBindings )
1836 0 : pImp->pSubBindings->StartUpdate_Impl( bComplete );
1837 :
1838 0 : if ( !bComplete )
1839 : // Update may be interrupted
1840 0 : NextJob_Impl(&pImp->aTimer);
1841 : else
1842 : // Update all slots in a row
1843 0 : NextJob_Impl(0);
1844 0 : }
1845 :
1846 :
1847 :
1848 0 : SfxItemState SfxBindings::QueryState( sal_uInt16 nSlot, SfxPoolItem* &rpState )
1849 : {
1850 0 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
1851 0 : SfxStateCache *pCache = GetStateCache( nSlot );
1852 0 : if ( pCache )
1853 0 : xDisp = pCache->GetDispatch();
1854 0 : if ( xDisp.is() || !pCache )
1855 : {
1856 0 : const SfxSlot* pSlot = SfxSlotPool::GetSlotPool( pDispatcher->GetFrame() ).GetSlot( nSlot );
1857 0 : if ( !pSlot || !pSlot->pUnoName )
1858 0 : return SFX_ITEM_DISABLED;
1859 :
1860 0 : ::com::sun::star::util::URL aURL;
1861 0 : OUString aCmd( ".uno:" );
1862 0 : aURL.Protocol = aCmd;
1863 0 : aURL.Path = OUString::createFromAscii(pSlot->GetUnoName());
1864 0 : aCmd += aURL.Path;
1865 0 : aURL.Complete = aCmd;
1866 0 : aURL.Main = aCmd;
1867 :
1868 0 : if ( !xDisp.is() )
1869 0 : xDisp = pImp->xProv->queryDispatch( aURL, OUString(), 0 );
1870 :
1871 0 : if ( xDisp.is() )
1872 : {
1873 0 : ::com::sun::star::uno::Reference< ::com::sun::star::lang::XUnoTunnel > xTunnel( xDisp, ::com::sun::star::uno::UNO_QUERY );
1874 0 : SfxOfficeDispatch* pDisp = NULL;
1875 0 : if ( xTunnel.is() )
1876 : {
1877 0 : sal_Int64 nImplementation = xTunnel->getSomething(SfxOfficeDispatch::impl_getStaticIdentifier());
1878 0 : pDisp = reinterpret_cast< SfxOfficeDispatch* >( sal::static_int_cast< sal_IntPtr >( nImplementation ));
1879 : }
1880 :
1881 0 : if ( !pDisp )
1882 : {
1883 0 : bool bDeleteCache = false;
1884 0 : if ( !pCache )
1885 : {
1886 0 : pCache = new SfxStateCache( nSlot );
1887 0 : pCache->GetSlotServer( *GetDispatcher_Impl(), pImp->xProv );
1888 0 : bDeleteCache = true;
1889 : }
1890 :
1891 0 : SfxItemState eState = SFX_ITEM_SET;
1892 0 : SfxPoolItem *pItem=NULL;
1893 0 : BindDispatch_Impl *pBind = new BindDispatch_Impl( xDisp, aURL, pCache, pSlot );
1894 0 : pBind->acquire();
1895 0 : xDisp->addStatusListener( pBind, aURL );
1896 0 : if ( !pBind->GetStatus().IsEnabled )
1897 : {
1898 0 : eState = SFX_ITEM_DISABLED;
1899 : }
1900 : else
1901 : {
1902 0 : ::com::sun::star::uno::Any aAny = pBind->GetStatus().State;
1903 0 : ::com::sun::star::uno::Type pType = aAny.getValueType();
1904 :
1905 0 : if ( pType == ::getBooleanCppuType() )
1906 : {
1907 0 : bool bTemp = false;
1908 0 : aAny >>= bTemp ;
1909 0 : pItem = new SfxBoolItem( nSlot, bTemp );
1910 : }
1911 0 : else if ( pType == ::getCppuType((const sal_uInt16*)0) )
1912 : {
1913 0 : sal_uInt16 nTemp = 0;
1914 0 : aAny >>= nTemp ;
1915 0 : pItem = new SfxUInt16Item( nSlot, nTemp );
1916 : }
1917 0 : else if ( pType == ::getCppuType((const sal_uInt32*)0) )
1918 : {
1919 0 : sal_uInt32 nTemp = 0;
1920 0 : aAny >>= nTemp ;
1921 0 : pItem = new SfxUInt32Item( nSlot, nTemp );
1922 : }
1923 0 : else if ( pType == ::getCppuType((const OUString*)0) )
1924 : {
1925 0 : OUString sTemp ;
1926 0 : aAny >>= sTemp ;
1927 0 : pItem = new SfxStringItem( nSlot, sTemp );
1928 : }
1929 : else
1930 0 : pItem = new SfxVoidItem( nSlot );
1931 : }
1932 :
1933 0 : xDisp->removeStatusListener( pBind, aURL );
1934 0 : pBind->Release();
1935 0 : rpState = pItem;
1936 0 : if ( bDeleteCache )
1937 0 : DELETEZ( pCache );
1938 0 : return eState;
1939 0 : }
1940 0 : }
1941 : }
1942 :
1943 : // Then test at the dispatcher to check if the returned items from
1944 : // there are always DELETE_ON_IDLE, a copy of it has to be made in
1945 : // order to allow for transition of ownership.
1946 0 : const SfxPoolItem *pItem = NULL;
1947 0 : SfxItemState eState = pDispatcher->QueryState( nSlot, pItem );
1948 0 : if ( eState == SFX_ITEM_SET )
1949 : {
1950 : DBG_ASSERT( pItem, "SFX_ITEM_SET but no item!" );
1951 0 : if ( pItem )
1952 0 : rpState = pItem->Clone();
1953 : }
1954 0 : else if ( eState == SFX_ITEM_AVAILABLE && pItem )
1955 : {
1956 0 : rpState = pItem->Clone();
1957 : }
1958 :
1959 0 : return eState;
1960 : }
1961 :
1962 0 : void SfxBindings::SetSubBindings_Impl( SfxBindings *pSub )
1963 : {
1964 0 : if ( pImp->pSubBindings )
1965 : {
1966 0 : pImp->pSubBindings->SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > () );
1967 0 : pImp->pSubBindings->pImp->pSuperBindings = NULL;
1968 : }
1969 :
1970 0 : pImp->pSubBindings = pSub;
1971 :
1972 0 : if ( pSub )
1973 : {
1974 0 : pImp->pSubBindings->SetDispatchProvider_Impl( pImp->xProv );
1975 0 : pSub->pImp->pSuperBindings = this;
1976 : }
1977 0 : }
1978 :
1979 0 : SfxBindings* SfxBindings::GetSubBindings_Impl( bool bTop ) const
1980 : {
1981 0 : SfxBindings *pRet = pImp->pSubBindings;
1982 0 : if ( bTop )
1983 : {
1984 0 : while ( pRet->pImp->pSubBindings )
1985 0 : pRet = pRet->pImp->pSubBindings;
1986 : }
1987 :
1988 0 : return pRet;
1989 : }
1990 :
1991 0 : void SfxBindings::SetWorkWindow_Impl( SfxWorkWindow* pWork )
1992 : {
1993 0 : pImp->pWorkWin = pWork;
1994 0 : }
1995 :
1996 0 : SfxWorkWindow* SfxBindings::GetWorkWindow_Impl() const
1997 : {
1998 0 : return pImp->pWorkWin;
1999 : }
2000 :
2001 0 : void SfxBindings::RegisterUnoController_Impl( SfxUnoControllerItem* pControl )
2002 : {
2003 0 : if ( !pImp->pUnoCtrlArr )
2004 0 : pImp->pUnoCtrlArr = new SfxUnoControllerArr_Impl;
2005 0 : pImp->pUnoCtrlArr->push_back( pControl );
2006 0 : }
2007 :
2008 0 : void SfxBindings::ReleaseUnoController_Impl( SfxUnoControllerItem* pControl )
2009 : {
2010 0 : if ( pImp->pUnoCtrlArr )
2011 : {
2012 : SfxUnoControllerArr_Impl::iterator it = std::find(
2013 0 : pImp->pUnoCtrlArr->begin(), pImp->pUnoCtrlArr->end(), pControl );
2014 0 : if ( it != pImp->pUnoCtrlArr->end() )
2015 : {
2016 0 : pImp->pUnoCtrlArr->erase( it );
2017 0 : return;
2018 : }
2019 : }
2020 :
2021 0 : if ( pImp->pSubBindings )
2022 0 : pImp->pSubBindings->ReleaseUnoController_Impl( pControl );
2023 : }
2024 :
2025 0 : void SfxBindings::InvalidateUnoControllers_Impl()
2026 : {
2027 0 : if ( pImp->pUnoCtrlArr )
2028 : {
2029 0 : sal_uInt16 nCount = pImp->pUnoCtrlArr->size();
2030 0 : for ( sal_uInt16 n=nCount; n>0; n-- )
2031 : {
2032 0 : SfxUnoControllerItem *pCtrl = (*pImp->pUnoCtrlArr)[n-1];
2033 0 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > xRef( (::cppu::OWeakObject*)pCtrl, ::com::sun::star::uno::UNO_QUERY );
2034 0 : pCtrl->ReleaseDispatch();
2035 0 : pCtrl->GetNewDispatch();
2036 0 : }
2037 : }
2038 :
2039 0 : if ( pImp->pSubBindings )
2040 0 : pImp->pSubBindings->InvalidateUnoControllers_Impl();
2041 0 : }
2042 :
2043 0 : bool SfxBindings::IsInUpdate() const
2044 : {
2045 0 : bool bInUpdate = pImp->bInUpdate;
2046 0 : if ( !bInUpdate && pImp->pSubBindings )
2047 0 : bInUpdate = pImp->pSubBindings->IsInUpdate();
2048 0 : return bInUpdate;
2049 : }
2050 :
2051 0 : void SfxBindings::SetVisibleState( sal_uInt16 nId, bool bShow )
2052 : {
2053 0 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
2054 0 : SfxStateCache *pCache = GetStateCache( nId );
2055 0 : if ( pCache )
2056 0 : pCache->SetVisibleState( bShow );
2057 0 : }
2058 :
2059 0 : void SfxBindings::SetActiveFrame( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > & rFrame )
2060 : {
2061 0 : if ( rFrame.is() || !pDispatcher )
2062 0 : SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > ( rFrame, ::com::sun::star::uno::UNO_QUERY ) );
2063 : else
2064 : SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > (
2065 0 : pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), ::com::sun::star::uno::UNO_QUERY ) );
2066 0 : }
2067 :
2068 0 : const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > SfxBindings::GetActiveFrame() const
2069 : {
2070 0 : const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame( pImp->xProv, ::com::sun::star::uno::UNO_QUERY );
2071 0 : if ( xFrame.is() || !pDispatcher )
2072 0 : return xFrame;
2073 : else
2074 0 : return pDispatcher->GetFrame()->GetFrame().GetFrameInterface();
2075 : }
2076 :
2077 0 : void SfxBindings::SetDispatchProvider_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & rProv )
2078 : {
2079 0 : bool bInvalidate = ( rProv != pImp->xProv );
2080 0 : if ( bInvalidate )
2081 : {
2082 0 : pImp->xProv = rProv;
2083 0 : InvalidateAll( true );
2084 0 : InvalidateUnoControllers_Impl();
2085 : }
2086 :
2087 0 : if ( pImp->pSubBindings )
2088 0 : pImp->pSubBindings->SetDispatchProvider_Impl( pImp->xProv );
2089 0 : }
2090 :
2091 0 : bool SfxBindings::ExecuteCommand_Impl( const OUString& rCommand )
2092 : {
2093 0 : ::com::sun::star::util::URL aURL;
2094 0 : aURL.Complete = rCommand;
2095 0 : Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
2096 0 : xTrans->parseStrict( aURL );
2097 0 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp = pImp->xProv->queryDispatch( aURL, OUString(), 0 );
2098 0 : if ( xDisp.is() )
2099 : {
2100 0 : new SfxAsyncExec_Impl( aURL, xDisp );
2101 0 : return true;
2102 : }
2103 :
2104 0 : return false;
2105 : }
2106 :
2107 0 : com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder > SfxBindings::GetRecorder() const
2108 : {
2109 0 : return pImp->xRecorder;
2110 : }
2111 :
2112 0 : void SfxBindings::SetRecorder_Impl( com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder >& rRecorder )
2113 : {
2114 0 : pImp->xRecorder = rRecorder;
2115 0 : }
2116 :
2117 0 : void SfxBindings::ContextChanged_Impl()
2118 : {
2119 0 : if ( !pImp->bInUpdate && ( !pImp->bContextChanged || !pImp->bAllMsgDirty ) )
2120 : {
2121 0 : InvalidateAll( true );
2122 : }
2123 0 : }
2124 :
2125 0 : uno::Reference < frame::XDispatch > SfxBindings::GetDispatch( const SfxSlot* pSlot, const util::URL& aURL, bool bMasterCommand )
2126 : {
2127 0 : uno::Reference < frame::XDispatch > xRet;
2128 0 : SfxStateCache* pCache = GetStateCache( pSlot->nSlotId );
2129 0 : if ( pCache && !bMasterCommand )
2130 0 : xRet = pCache->GetInternalDispatch();
2131 0 : if ( !xRet.is() )
2132 : {
2133 : // dispatches for slaves are unbound, they don't have a state
2134 : SfxOfficeDispatch* pDispatch = bMasterCommand ?
2135 0 : new SfxOfficeDispatch( pDispatcher, pSlot, aURL ) :
2136 0 : new SfxOfficeDispatch( *this, pDispatcher, pSlot, aURL );
2137 :
2138 0 : pDispatch->SetMasterUnoCommand( bMasterCommand );
2139 0 : xRet = uno::Reference < frame::XDispatch >( pDispatch );
2140 0 : if ( !pCache )
2141 0 : pCache = GetStateCache( pSlot->nSlotId );
2142 :
2143 : DBG_ASSERT( pCache, "No cache for OfficeDispatch!" );
2144 0 : if ( pCache && !bMasterCommand )
2145 0 : pCache->SetInternalDispatch( xRet );
2146 : }
2147 :
2148 0 : return xRet;
2149 : }
2150 :
2151 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|