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