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 4095 : 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 54218 : SfxFoundCache_Impl(sal_uInt16 nS, sal_uInt16 nW, const SfxSlot *pS, SfxStateCache *pC ):
159 : nSlotId(nS),
160 : nWhichId(nW),
161 : pSlot(pS),
162 54218 : pCache(pC)
163 54218 : {}
164 : };
165 :
166 :
167 :
168 15413 : class SfxFoundCacheArr_Impl : public std::vector<SfxFoundCache_Impl*>
169 : {
170 : public:
171 15413 : ~SfxFoundCacheArr_Impl()
172 15413 : {
173 69143 : for(const_iterator it = begin(); it != end(); ++it)
174 53730 : delete *it;
175 15413 : }
176 : };
177 :
178 :
179 :
180 2052 : SfxBindings::SfxBindings()
181 2052 : : pImp(new SfxBindings_Impl),
182 : pDispatcher(0),
183 4104 : nRegLevel(1) // first becomes 0, when the Dispatcher is set
184 : {
185 2052 : pImp->nMsgPos = 0;
186 2052 : pImp->bAllMsgDirty = true;
187 2052 : pImp->bContextChanged = false;
188 2052 : pImp->bMsgDirty = true;
189 2052 : pImp->bAllDirty = true;
190 2052 : pImp->ePopupAction = SFX_POPUP_DELETE;
191 2052 : pImp->nCachedFunc1 = 0;
192 2052 : pImp->nCachedFunc2 = 0;
193 2052 : pImp->bCtrlReleased = false;
194 2052 : pImp->bFirstRound = false;
195 2052 : pImp->bInNextJob = false;
196 2052 : pImp->bInUpdate = false;
197 2052 : pImp->pSubBindings = NULL;
198 2052 : pImp->pSuperBindings = NULL;
199 2052 : pImp->pWorkWin = NULL;
200 2052 : pImp->pUnoCtrlArr = NULL;
201 2052 : pImp->nOwnRegLevel = nRegLevel;
202 :
203 : // all caches are valid (no pending invalidate-job)
204 : // create the list of caches
205 2052 : pImp->pCaches = new SfxStateCacheArr_Impl;
206 2052 : pImp->aTimer.SetTimeoutHdl( LINK(this, SfxBindings, NextJob_Impl) );
207 2052 : }
208 :
209 :
210 :
211 6125 : 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 2043 : pImp->pSubBindings = NULL;
228 :
229 2043 : ENTERREGISTRATIONS();
230 :
231 2043 : pImp->aTimer.Stop();
232 2043 : DeleteControllers_Impl();
233 :
234 : // Delete Caches
235 2043 : for(SfxStateCacheArr_Impl::const_iterator it = pImp->pCaches->begin(); it != pImp->pCaches->end(); ++it)
236 0 : delete *it;
237 :
238 2043 : DELETEZ( pImp->pWorkWin );
239 :
240 2043 : delete pImp->pCaches;
241 2043 : delete pImp;
242 4082 : }
243 :
244 :
245 :
246 2043 : void SfxBindings::DeleteControllers_Impl()
247 : {
248 : // in the first round delete SfxPopupWindows
249 2043 : sal_uInt16 nCount = pImp->pCaches->size();
250 : sal_uInt16 nCache;
251 78408 : for ( nCache = 0; nCache < nCount; ++nCache )
252 : {
253 : // Remember were you are
254 76365 : SfxStateCache *pCache = (*pImp->pCaches)[nCache];
255 76365 : sal_uInt16 nSlotId = pCache->GetId();
256 :
257 : // Delete SfxPopupWindow
258 76365 : pCache->DeleteFloatingWindows();
259 :
260 : // Re-align, because the cache may have been reduced
261 76365 : sal_uInt16 nNewCount = pImp->pCaches->size();
262 76365 : 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 78408 : for ( nCache = pImp->pCaches->size(); nCache > 0; --nCache )
274 : {
275 : // Get Cache via ::com::sun::star::sdbcx::Index
276 76365 : SfxStateCache *pCache = (*pImp->pCaches)[ nCache-1 ];
277 :
278 : // unbind all controllers in the cache
279 : SfxControllerItem *pNext;
280 76365 : for ( SfxControllerItem *pCtrl = pCache->GetItemLink();
281 : pCtrl; pCtrl = pNext )
282 : {
283 0 : pNext = pCtrl->GetItemLink();
284 0 : pCtrl->UnBind();
285 : }
286 :
287 76365 : if ( pCache->GetInternalController() )
288 59257 : pCache->GetInternalController()->UnBind();
289 :
290 : // Delete Cache
291 76365 : if( nCache-1 < (sal_uInt16) pImp->pCaches->size() )
292 76365 : delete (*pImp->pCaches)[nCache-1];
293 76365 : pImp->pCaches->erase(pImp->pCaches->begin()+ nCache - 1);
294 : }
295 :
296 2043 : 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 2043 : }
309 :
310 :
311 :
312 2 : void SfxBindings::HidePopups( bool bHide )
313 : {
314 : // Hide SfxPopupWindows
315 2 : HidePopupCtrls_Impl( bHide );
316 2 : SfxBindings *pSub = pImp->pSubBindings;
317 4 : 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 2 : if ( pImp->pWorkWin )
326 2 : pImp->pWorkWin->HidePopups_Impl( bHide, true );
327 2 : }
328 :
329 4052 : void SfxBindings::HidePopupCtrls_Impl( bool bHide )
330 : {
331 4052 : if ( bHide )
332 : {
333 : // Hide SfxPopupWindows
334 2025 : pImp->ePopupAction = SFX_POPUP_HIDE;
335 : }
336 : else
337 : {
338 : // Show SfxPopupWindows
339 2027 : pImp->ePopupAction = SFX_POPUP_SHOW;
340 : }
341 :
342 117996 : for(SfxStateCacheArr_Impl::const_iterator it = pImp->pCaches->begin(); it != pImp->pCaches->end(); ++it)
343 113944 : (*it)->DeleteFloatingWindows();
344 4052 : pImp->ePopupAction = SFX_POPUP_DELETE;
345 4052 : }
346 :
347 :
348 :
349 15413 : void SfxBindings::Update_Impl
350 : (
351 : SfxStateCache* pCache // The up to date SfxStatusCache
352 : )
353 : {
354 15413 : if( pCache->GetDispatch().is() && pCache->GetItemLink() )
355 : {
356 0 : pCache->SetCachedState(true);
357 0 : if ( !pCache->GetInternalController() )
358 0 : return;
359 : }
360 :
361 15413 : if ( !pDispatcher )
362 0 : return;
363 :
364 : // gather together all with the same status method which are dirty
365 15413 : SfxDispatcher &rDispat = *pDispatcher;
366 15413 : const SfxSlot *pRealSlot = 0;
367 15413 : const SfxSlotServer* pMsgServer = 0;
368 15413 : SfxFoundCacheArr_Impl aFound;
369 15413 : SfxItemSet *pSet = CreateSet_Impl( pCache, pRealSlot, &pMsgServer, aFound );
370 15413 : bool bUpdated = false;
371 15413 : if ( pSet )
372 : {
373 : // Query Status
374 14925 : if ( rDispat._FillState( *pMsgServer, *pSet, pRealSlot ) )
375 : {
376 : // Post Status
377 : const SfxInterface *pInterface =
378 14925 : rDispat.GetShell(pMsgServer->GetShellLevel())->GetInterface();
379 68655 : for ( sal_uInt16 nPos = 0; nPos < aFound.size(); ++nPos )
380 : {
381 53730 : const SfxFoundCache_Impl *pFound = aFound[nPos];
382 53730 : sal_uInt16 nWhich = pFound->nWhichId;
383 53730 : const SfxPoolItem *pItem = 0;
384 53730 : SfxItemState eState = pSet->GetItemState(nWhich, true, &pItem);
385 53730 : if ( eState == SFX_ITEM_DEFAULT && SfxItemPool::IsWhich(nWhich) )
386 379 : pItem = &pSet->Get(nWhich);
387 53730 : UpdateControllers_Impl( pInterface, aFound[nPos], pItem, eState );
388 : }
389 14925 : bUpdated = true;
390 : }
391 :
392 14925 : delete pSet;
393 : }
394 :
395 15413 : 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 488 : pCache->GetId(), 0,
402 976 : pRealSlot, pCache );
403 488 : UpdateControllers_Impl( 0, &aFoundCache, 0, SFX_ITEM_DISABLED);
404 15413 : }
405 : }
406 :
407 :
408 :
409 1236 : void SfxBindings::InvalidateSlotsInMap_Impl()
410 : {
411 1236 : InvalidateSlotMap::const_iterator pIter = pImp->m_aInvalidateSlots.begin();
412 2483 : while ( pIter != pImp->m_aInvalidateSlots.end() )
413 : {
414 11 : Invalidate( pIter->first );
415 11 : ++pIter;
416 : }
417 1236 : pImp->m_aInvalidateSlots.clear();
418 1236 : }
419 :
420 :
421 :
422 11 : void SfxBindings::AddSlotToInvalidateSlotsMap_Impl( sal_uInt16 nId )
423 : {
424 11 : pImp->m_aInvalidateSlots[nId] = true;
425 11 : }
426 :
427 :
428 :
429 1455 : 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 1455 : if ( pDispatcher )
437 1455 : pDispatcher->Flush();
438 :
439 1455 : if ( pImp->pSubBindings )
440 0 : pImp->pSubBindings->Update( nId );
441 :
442 1455 : SfxStateCache* pCache = GetStateCache( nId );
443 1455 : if ( pCache )
444 : {
445 1236 : pImp->bInUpdate = true;
446 1236 : if ( pImp->bMsgDirty )
447 : {
448 216 : UpdateSlotServer_Impl();
449 216 : pCache = GetStateCache( nId );
450 : }
451 :
452 1236 : if (pCache)
453 : {
454 1236 : bool bInternalUpdate = true;
455 1236 : if( pCache->GetDispatch().is() && pCache->GetItemLink() )
456 : {
457 0 : pCache->SetCachedState(true);
458 0 : bInternalUpdate = ( pCache->GetInternalController() != 0 );
459 : }
460 :
461 1236 : if ( bInternalUpdate )
462 : {
463 : // Query Status
464 1236 : const SfxSlotServer* pMsgServer = pDispatcher ? pCache->GetSlotServer(*pDispatcher, pImp->xProv) : NULL;
465 1524 : if ( !pCache->IsControllerDirty() &&
466 288 : ( !pMsgServer ||
467 288 : !pMsgServer->GetSlot()->IsMode(SFX_SLOT_VOLATILE) ) )
468 : {
469 288 : pImp->bInUpdate = false;
470 288 : InvalidateSlotsInMap_Impl();
471 288 : return;
472 : }
473 948 : if (!pMsgServer)
474 : {
475 354 : pCache->SetState(SFX_ITEM_DISABLED, 0);
476 354 : pImp->bInUpdate = false;
477 354 : InvalidateSlotsInMap_Impl();
478 354 : return;
479 : }
480 :
481 594 : Update_Impl(pCache);
482 : }
483 :
484 594 : pImp->bAllDirty = false;
485 : }
486 :
487 594 : pImp->bInUpdate = false;
488 594 : 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 328 : void SfxBindings::SetState
563 : (
564 : const SfxPoolItem& rItem // Status value to be set
565 : )
566 : {
567 328 : if ( nRegLevel )
568 : {
569 1 : Invalidate( rItem.Which() );
570 : }
571 : else
572 : {
573 : // Status may be accepted only if all slot-pointers are set
574 327 : if ( pImp->bMsgDirty )
575 212 : UpdateSlotServer_Impl();
576 :
577 : //update if the slot bound
578 : DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ),
579 : "cannot set items with which-id" );
580 327 : SfxStateCache* pCache = GetStateCache( rItem.Which() );
581 327 : if ( pCache )
582 : {
583 : // Update Status
584 111 : if ( !pCache->IsControllerDirty() )
585 44 : pCache->Invalidate(false);
586 111 : pCache->SetState( SFX_ITEM_AVAILABLE, &rItem );
587 :
588 : //! Not implemented: Updates from EnumSlots via master slots
589 : }
590 : }
591 328 : }
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 262650 : SfxStateCache* SfxBindings::GetStateCache
605 : (
606 : sal_uInt16 nId /* Slot-Id, which SfxStatusCache is to be found */
607 : )
608 : {
609 262650 : return GetStateCache(nId, 0);
610 : }
611 :
612 554115 : 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 554115 : const sal_uInt16 nStart = ( pPos ? *pPos : 0 );
624 554115 : const sal_uInt16 nPos = GetSlotPos( nId, nStart );
625 :
626 1092870 : if ( nPos < pImp->pCaches->size() &&
627 538755 : (*pImp->pCaches)[nPos]->GetId() == nId )
628 : {
629 224659 : if ( pPos )
630 44623 : *pPos = nPos;
631 224659 : return (*pImp->pCaches)[nPos];
632 : }
633 329456 : return 0;
634 : }
635 :
636 :
637 :
638 40926 : 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 40926 : if ( pImp->pSubBindings )
647 15 : pImp->pSubBindings->InvalidateAll( bWithMsg );
648 :
649 : // everything is already set dirty or downing => nothing to do
650 118697 : if ( !pDispatcher ||
651 78535 : ( pImp->bAllDirty && ( !bWithMsg || pImp->bAllMsgDirty ) ) ||
652 1841 : SFX_APP()->IsDowning() )
653 : {
654 80011 : return;
655 : }
656 :
657 1841 : pImp->bAllMsgDirty = pImp->bAllMsgDirty || bWithMsg;
658 1841 : pImp->bMsgDirty = pImp->bMsgDirty || pImp->bAllMsgDirty || bWithMsg;
659 1841 : pImp->bAllDirty = true;
660 :
661 156035 : for ( sal_uInt16 n = 0; n < pImp->pCaches->size(); ++n )
662 154194 : (*pImp->pCaches)[n]->Invalidate(bWithMsg);
663 :
664 1841 : pImp->nMsgPos = 0;
665 1841 : if ( !nRegLevel )
666 : {
667 670 : pImp->aTimer.Stop();
668 670 : pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
669 670 : pImp->aTimer.Start();
670 : }
671 : }
672 :
673 :
674 :
675 15126 : 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 15126 : 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 15126 : if ( pImp->pSubBindings )
693 0 : pImp->pSubBindings->Invalidate( pIds );
694 :
695 : // everything is already set dirty or downing => nothing to do
696 15126 : if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
697 15011 : return;
698 :
699 : // Search binary in always smaller areas
700 2990 : for ( sal_uInt16 n = GetSlotPos(*pIds);
701 1495 : *pIds && n < pImp->pCaches->size();
702 1380 : n = GetSlotPos(*pIds, n) )
703 : {
704 : // If SID is ever bound, then invalidate the cache
705 1495 : SfxStateCache *pCache = (*pImp->pCaches)[n];
706 1495 : if ( pCache->GetId() == *pIds )
707 1495 : pCache->Invalidate(false);
708 :
709 : // Next SID
710 1495 : if ( !*++pIds )
711 115 : break;
712 : DBG_ASSERT( *pIds > *(pIds-1), "pIds unsorted" );
713 : }
714 :
715 : // if not enticed to start update timer
716 115 : pImp->nMsgPos = 0;
717 115 : if ( !nRegLevel )
718 : {
719 110 : pImp->aTimer.Stop();
720 110 : pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
721 110 : pImp->aTimer.Start();
722 : }
723 : }
724 :
725 :
726 :
727 432 : 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 432 : if ( pImp->pSubBindings )
743 0 : pImp->pSubBindings->InvalidateShell( rSh, bDeep );
744 :
745 432 : if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
746 343 : 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 89 : pDispatcher->Flush();
751 :
752 267 : if ( !pDispatcher ||
753 178 : ( pImp->bAllDirty && pImp->bAllMsgDirty ) ||
754 89 : 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 89 : sal_uInt16 nLevel = pDispatcher->GetShellLevel(rSh);
762 89 : if ( nLevel != USHRT_MAX )
763 : {
764 8247 : for ( sal_uInt16 n = 0; n < pImp->pCaches->size(); ++n )
765 : {
766 8158 : SfxStateCache *pCache = (*pImp->pCaches)[n];
767 : const SfxSlotServer *pMsgServer =
768 8158 : pCache->GetSlotServer(*pDispatcher, pImp->xProv);
769 8158 : if ( pMsgServer && pMsgServer->GetShellLevel() == nLevel )
770 6404 : pCache->Invalidate(false);
771 : }
772 89 : pImp->nMsgPos = 0;
773 89 : if ( !nRegLevel )
774 : {
775 89 : pImp->aTimer.Stop();
776 89 : pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
777 89 : pImp->aTimer.Start();
778 89 : pImp->bFirstRound = true;
779 89 : pImp->nFirstShell = nLevel;
780 : }
781 : }
782 : }
783 :
784 :
785 :
786 243168 : void SfxBindings::Invalidate
787 : (
788 : sal_uInt16 nId // Status value to be set
789 : )
790 : {
791 243168 : if ( pImp->bInUpdate )
792 : {
793 11 : AddSlotToInvalidateSlotsMap_Impl( nId );
794 11 : if ( pImp->pSubBindings )
795 0 : pImp->pSubBindings->Invalidate( nId );
796 11 : return;
797 : }
798 :
799 243157 : if ( pImp->pSubBindings )
800 56 : pImp->pSubBindings->Invalidate( nId );
801 :
802 243157 : if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
803 193071 : return;
804 :
805 50086 : SfxStateCache* pCache = GetStateCache(nId);
806 50086 : if ( pCache )
807 : {
808 24135 : pCache->Invalidate(false);
809 24135 : pImp->nMsgPos = std::min(GetSlotPos(nId), pImp->nMsgPos);
810 24135 : if ( !nRegLevel )
811 : {
812 23983 : pImp->aTimer.Stop();
813 23983 : pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
814 23983 : pImp->aTimer.Start();
815 : }
816 : }
817 : }
818 :
819 :
820 :
821 2409 : 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 2409 : if ( pImp->pSubBindings )
831 0 : pImp->pSubBindings->Invalidate( nId, bWithItem, bWithMsg );
832 :
833 2409 : if ( SFX_APP()->IsDowning() )
834 0 : return;
835 :
836 2409 : SfxStateCache* pCache = GetStateCache(nId);
837 2409 : if ( pCache )
838 : {
839 610 : if ( bWithItem )
840 610 : pCache->ClearCache();
841 610 : pCache->Invalidate(bWithMsg);
842 :
843 610 : if ( !pDispatcher || pImp->bAllDirty )
844 1 : return;
845 :
846 609 : pImp->nMsgPos = std::min(GetSlotPos(nId), pImp->nMsgPos);
847 609 : if ( !nRegLevel )
848 : {
849 9 : pImp->aTimer.Stop();
850 9 : pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
851 9 : 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 841766 : 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 1608212 : if ( pImp->nCachedFunc1 < pImp->pCaches->size() &&
872 766446 : (*pImp->pCaches)[pImp->nCachedFunc1]->GetId() == nId )
873 : {
874 102640 : return pImp->nCachedFunc1;
875 : }
876 1405796 : if ( pImp->nCachedFunc2 < pImp->pCaches->size() &&
877 666670 : (*pImp->pCaches)[pImp->nCachedFunc2]->GetId() == nId )
878 : {
879 : // swap the caches
880 9964 : sal_uInt16 nTemp = pImp->nCachedFunc1;
881 9964 : pImp->nCachedFunc1 = pImp->nCachedFunc2;
882 9964 : pImp->nCachedFunc2 = nTemp;
883 9964 : return pImp->nCachedFunc1;
884 : }
885 :
886 : // binary search, if not found, seek to target-position
887 729162 : if ( pImp->pCaches->size() <= nStartSearchAt )
888 : {
889 5343 : return 0;
890 : }
891 723819 : if ( (sal_uInt16) pImp->pCaches->size() == (nStartSearchAt+1) )
892 : {
893 6455 : return (*pImp->pCaches)[nStartSearchAt]->GetId() >= nId ? 0 : 1;
894 : }
895 717364 : sal_uInt16 nLow = nStartSearchAt;
896 717364 : sal_uInt16 nMid = 0;
897 717364 : sal_uInt16 nHigh = 0;
898 717364 : bool bFound = false;
899 717364 : nHigh = pImp->pCaches->size() - 1;
900 5130557 : while ( !bFound && nLow <= nHigh )
901 : {
902 3706275 : nMid = (nLow + nHigh) >> 1;
903 : DBG_ASSERT( nMid < pImp->pCaches->size(), "bsearch is buggy" );
904 3706275 : int nDiff = (int) nId - (int) ( ((*pImp->pCaches)[nMid])->GetId() );
905 3706275 : if ( nDiff < 0)
906 1499180 : { if ( nMid == 0 )
907 10446 : break;
908 1488734 : nHigh = nMid - 1;
909 : }
910 2207095 : else if ( nDiff > 0 )
911 1911149 : { nLow = nMid + 1;
912 1911149 : if ( nLow == 0 )
913 0 : break;
914 : }
915 : else
916 295946 : bFound = true;
917 : }
918 717364 : 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 717364 : pImp->nCachedFunc2 = pImp->nCachedFunc1;
927 717364 : pImp->nCachedFunc1 = nPos;
928 717364 : return nPos;
929 : }
930 :
931 59257 : void SfxBindings::RegisterInternal_Impl( SfxControllerItem& rItem )
932 : {
933 59257 : Register_Impl( rItem, true );
934 :
935 59257 : }
936 :
937 71451 : void SfxBindings::Register( SfxControllerItem& rItem )
938 : {
939 71451 : Register_Impl( rItem, false );
940 71451 : }
941 :
942 130708 : 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 130708 : sal_uInt16 nId = rItem.GetId();
949 130708 : sal_uInt16 nPos = GetSlotPos(nId);
950 241336 : if ( nPos >= pImp->pCaches->size() ||
951 110628 : (*pImp->pCaches)[nPos]->GetId() != nId )
952 : {
953 102933 : SfxStateCache* pCache = new SfxStateCache(nId);
954 102933 : 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 102933 : pImp->bMsgDirty = true;
962 : }
963 :
964 : // enqueue the new binding
965 130708 : if ( bInternal )
966 : {
967 59257 : (*pImp->pCaches)[nPos]->SetInternalController( &rItem );
968 : }
969 : else
970 : {
971 71451 : SfxControllerItem *pOldItem = (*pImp->pCaches)[nPos]->ChangeItemLink(&rItem);
972 71451 : rItem.ChangeItemLink(pOldItem);
973 : }
974 130708 : }
975 :
976 :
977 :
978 130704 : 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 130704 : ENTERREGISTRATIONS();
983 :
984 : // find the bound function
985 130704 : sal_uInt16 nId = rItem.GetId();
986 130704 : sal_uInt16 nPos = GetSlotPos(nId);
987 130704 : SfxStateCache* pCache = (*pImp->pCaches)[nPos];
988 130704 : if ( pCache->GetId() == nId )
989 : {
990 130704 : if ( pCache->GetInternalController() == &rItem )
991 : {
992 59257 : pCache->ReleaseInternalController();
993 : }
994 : else
995 : {
996 : // is this the first binding in the list?
997 71447 : SfxControllerItem* pItem = pCache->GetItemLink();
998 71447 : if ( pItem == &rItem )
999 62534 : pCache->ChangeItemLink( rItem.GetItemLink() );
1000 : else
1001 : {
1002 : // search the binding in the list
1003 17826 : while ( pItem && pItem->GetItemLink() != &rItem )
1004 0 : pItem = pItem->GetItemLink();
1005 :
1006 : // unlink it if it was found
1007 8913 : if ( pItem )
1008 8913 : pItem->ChangeItemLink( rItem.GetItemLink() );
1009 : }
1010 : }
1011 :
1012 : // was this the last controller?
1013 130704 : if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() )
1014 : {
1015 102929 : pImp->bCtrlReleased = true;
1016 : }
1017 : }
1018 :
1019 130704 : LEAVEREGISTRATIONS();
1020 130704 : }
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 26 : void SfxBindings::Execute_Impl( SfxRequest& aReq, const SfxSlot* pSlot, SfxShell* pShell )
1144 : {
1145 26 : SfxItemPool &rPool = pShell->GetPool();
1146 :
1147 26 : 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 26 : else if ( SFX_KIND_ATTR == pSlot->GetKind() )
1158 : {
1159 : // Which value has to be mapped for Attribute slots
1160 26 : const sal_uInt16 nSlotId = pSlot->GetSlotId();
1161 26 : aReq.SetSlot( nSlotId );
1162 26 : if ( pSlot->IsMode(SFX_SLOT_TOGGLE) )
1163 : {
1164 : // The value is attached to a toggleable attribute (Bools)
1165 10 : sal_uInt16 nWhich = pSlot->GetWhich(rPool);
1166 10 : SfxItemSet aSet(rPool, nWhich, nWhich);
1167 10 : SfxStateFunc aFunc = pSlot->GetStateFnc();
1168 10 : pShell->CallState( aFunc, aSet );
1169 : const SfxPoolItem *pOldItem;
1170 10 : SfxItemState eState = aSet.GetItemState(nWhich, true, &pOldItem);
1171 10 : if ( eState == SFX_ITEM_DISABLED )
1172 26 : return;
1173 :
1174 10 : if ( SFX_ITEM_AVAILABLE == eState && SfxItemPool::IsWhich(nWhich) )
1175 0 : pOldItem = &aSet.Get(nWhich);
1176 :
1177 20 : if ( SFX_ITEM_SET == eState ||
1178 0 : ( SFX_ITEM_AVAILABLE == eState &&
1179 0 : SfxItemPool::IsWhich(nWhich) &&
1180 : pOldItem ) )
1181 : {
1182 10 : if ( pOldItem->ISA(SfxBoolItem) )
1183 : {
1184 : // we can toggle Bools
1185 10 : bool bOldValue = ((const SfxBoolItem *)pOldItem)->GetValue();
1186 10 : SfxBoolItem *pNewItem = (SfxBoolItem*) (pOldItem->Clone());
1187 10 : pNewItem->SetValue( !bOldValue );
1188 10 : aReq.AppendItem( *pNewItem );
1189 10 : 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 10 : }
1233 : }
1234 :
1235 26 : 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 1412 : void SfxBindings::UpdateSlotServer_Impl()
1244 : {
1245 : DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1246 :
1247 : // synchronize
1248 1412 : pDispatcher->Flush();
1249 :
1250 1412 : if ( pImp->bAllMsgDirty )
1251 : {
1252 874 : if ( !nRegLevel )
1253 : {
1254 : ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame
1255 814 : ( pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY );
1256 814 : pImp->bContextChanged = false;
1257 : }
1258 : else
1259 60 : pImp->bContextChanged = true;
1260 : }
1261 :
1262 87331 : for (size_t i = 0, nCount = pImp->pCaches->size(); i < nCount; ++i)
1263 : {
1264 85919 : SfxStateCache *pCache = (*pImp->pCaches)[i];
1265 : //GetSlotServer can modify pImp->pCaches
1266 85919 : pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1267 : }
1268 1412 : pImp->bMsgDirty = pImp->bAllMsgDirty = false;
1269 :
1270 1412 : Broadcast( SfxSimpleHint(SFX_HINT_DOCCHANGED) );
1271 1412 : }
1272 :
1273 :
1274 :
1275 15413 : 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 15413 : const SfxSlotServer* pMsgSvr = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1288 15413 : if(!pMsgSvr || !pDispatcher)
1289 488 : return 0;
1290 :
1291 14925 : pRealSlot = 0;
1292 14925 : *pMsgServer = pMsgSvr;
1293 :
1294 14925 : sal_uInt16 nShellLevel = pMsgSvr->GetShellLevel();
1295 14925 : SfxShell *pShell = pDispatcher->GetShell( nShellLevel );
1296 14925 : if ( !pShell ) // rare GPF when browsing through update from Inet-Notify
1297 0 : return 0;
1298 :
1299 14925 : SfxItemPool &rPool = pShell->GetPool();
1300 :
1301 : // get the status method, which is served by the pCache
1302 14925 : SfxStateFunc pFnc = 0;
1303 14925 : const SfxInterface *pInterface = pShell->GetInterface();
1304 14925 : 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 14925 : pRealSlot = pMsgSvr->GetSlot();
1311 :
1312 : // Note: pCache can be NULL!
1313 :
1314 14925 : pFnc = pRealSlot->GetStateFnc();
1315 :
1316 : // the RealSlot is always on
1317 : SfxFoundCache_Impl *pFound = new SfxFoundCache_Impl(
1318 14925 : pRealSlot->GetSlotId(), pRealSlot->GetWhich(rPool), pRealSlot, pCache );
1319 14925 : rFound.push_back( pFound );
1320 :
1321 14925 : sal_uInt16 nSlot = pRealSlot->GetSlotId();
1322 14925 : if ( !(nSlot >= SID_VERB_START && nSlot <= SID_VERB_END) )
1323 : {
1324 14925 : 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 14925 : sal_uInt16 nCachePos = pImp->nMsgPos;
1332 14925 : const SfxSlot *pSibling = pRealSlot->GetNextSlot();
1333 :
1334 : // the Slots ODF a interfaces ar linked in a circle
1335 321315 : while ( pSibling > pRealSlot )
1336 : {
1337 291465 : SfxStateFunc pSiblingFnc=0;
1338 : SfxStateCache *pSiblingCache =
1339 291465 : GetStateCache( pSibling->GetSlotId(), &nCachePos );
1340 :
1341 : // Is the slot cached ?
1342 291465 : if ( pSiblingCache )
1343 : {
1344 44623 : const SfxSlotServer *pServ = pSiblingCache->GetSlotServer(*pDispatcher, pImp->xProv);
1345 44623 : if ( pServ && pServ->GetShellLevel() == nShellLevel )
1346 40803 : pSiblingFnc = pServ->GetSlot()->GetStateFnc();
1347 : }
1348 :
1349 : // Does the slot have to be updated at all?
1350 291465 : bool bInsert = pSiblingCache && pSiblingCache->IsControllerDirty();
1351 :
1352 : // It is not enough to ask for the same shell!!
1353 291465 : 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 291465 : 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 291465 : if ( bInsert && bSameMethod )
1383 : {
1384 : SfxFoundCache_Impl *pFoundCache = new SfxFoundCache_Impl(
1385 77610 : pSibling->GetSlotId(), pSibling->GetWhich(rPool),
1386 77610 : pSibling, pSiblingCache );
1387 :
1388 38805 : rFound.push_back( pFoundCache );
1389 : }
1390 :
1391 291465 : pSibling = pSibling->GetNextSlot();
1392 : }
1393 :
1394 : // Create a Set from the ranges
1395 14925 : boost::scoped_array<sal_uInt16> pRanges(new sal_uInt16[rFound.size() * 2 + 1]);
1396 14925 : int j = 0;
1397 14925 : sal_uInt16 i = 0;
1398 70554 : while ( i < rFound.size() )
1399 : {
1400 40704 : pRanges[j++] = rFound[i]->nWhichId;
1401 : // consecutive numbers
1402 53730 : for ( ; i < rFound.size()-1; ++i )
1403 38805 : if ( rFound[i]->nWhichId+1 != rFound[i+1]->nWhichId )
1404 25779 : break;
1405 40704 : pRanges[j++] = rFound[i++]->nWhichId;
1406 : }
1407 14925 : pRanges[j] = 0; // terminating NULL
1408 14925 : SfxItemSet *pSet = new SfxItemSet(rPool, pRanges.get());
1409 14925 : pRanges.reset();
1410 14925 : return pSet;
1411 : }
1412 :
1413 :
1414 :
1415 54218 : 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 54218 : SfxStateCache* pCache = pFound->pCache;
1427 54218 : 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 54218 : if ( pCache && pCache->IsControllerDirty() )
1432 : {
1433 54218 : if ( SFX_ITEM_DONTCARE == eState )
1434 : {
1435 : // ambiguous
1436 10 : pCache->SetState( SFX_ITEM_DONTCARE, (SfxPoolItem *)-1 );
1437 : }
1438 68387 : else if ( SFX_ITEM_DEFAULT == eState &&
1439 14179 : pFound->nWhichId > SFX_WHICH_MAX )
1440 : {
1441 : // no Status or Default but without Pool
1442 13800 : SfxVoidItem aVoid(0);
1443 13800 : pCache->SetState( SFX_ITEM_UNKNOWN, &aVoid );
1444 : }
1445 40408 : else if ( SFX_ITEM_DISABLED == eState )
1446 6791 : pCache->SetState(SFX_ITEM_DISABLED, 0);
1447 : else
1448 33617 : 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 54218 : const SfxSlot *pFirstSlave = pSlot ? pSlot->GetLinkedSlot() : 0;
1457 54218 : if ( pIF && pFirstSlave)
1458 : {
1459 : // Items cast on EnumItem
1460 : const SfxEnumItemInterface *pEnumItem =
1461 292 : PTR_CAST(SfxEnumItemInterface,pItem);
1462 292 : if ( eState == SFX_ITEM_AVAILABLE && !pEnumItem )
1463 0 : eState = SFX_ITEM_DONTCARE;
1464 : else
1465 292 : eState = SfxControllerItem::GetItemState( pEnumItem );
1466 :
1467 : // Iterate over all Slaves-Slots
1468 4380 : 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 4380 : SfxStateCache *pEnumCache = GetStateCache( pSlave->GetSlotId() );
1476 4380 : 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 4380 : if (pSlave->GetNextSlot() == pFirstSlave)
1512 292 : break;
1513 : }
1514 : }
1515 54218 : }
1516 :
1517 :
1518 :
1519 :
1520 5292 : 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 2646 : const unsigned MAX_INPUT_DELAY = 200;
1529 :
1530 : DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
1531 :
1532 2646 : if ( Application::GetLastInputInterval() < MAX_INPUT_DELAY && pTimer )
1533 : {
1534 0 : pImp->aTimer.SetTimeout(TIMEOUT_UPDATING);
1535 0 : return sal_True;
1536 : }
1537 :
1538 2646 : SfxApplication *pSfxApp = SFX_APP();
1539 :
1540 2646 : if( pDispatcher )
1541 2646 : pDispatcher->Update_Impl();
1542 :
1543 : // modifying the SfxObjectInterface-stack without SfxBindings => nothing to do
1544 2646 : SfxViewFrame* pFrame = pDispatcher ? pDispatcher->GetFrame() : NULL;
1545 2646 : if ( (pFrame && !pFrame->GetObjectShell()->AcceptStateUpdate()) || pSfxApp->IsDowning() || pImp->pCaches->empty() )
1546 : {
1547 0 : return sal_True;
1548 : }
1549 2646 : 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 2646 : if ( pImp->bMsgDirty )
1556 : {
1557 984 : UpdateSlotServer_Impl();
1558 984 : return sal_False;
1559 : }
1560 :
1561 1662 : pImp->bAllDirty = false;
1562 1662 : pImp->aTimer.SetTimeout(TIMEOUT_UPDATING);
1563 :
1564 : // at least 10 loops and further if more jobs are available but no input
1565 1662 : bool bPreEmptive = pTimer && !pSfxApp->Get_Impl()->nInReschedule;
1566 1662 : sal_uInt16 nLoops = 10;
1567 1662 : pImp->bInNextJob = true;
1568 1662 : const sal_uInt16 nCount = pImp->pCaches->size();
1569 3703 : while ( pImp->nMsgPos < nCount )
1570 : {
1571 : // iterate through the bound functions
1572 1662 : bool bJobDone = false;
1573 48654 : while ( !bJobDone )
1574 : {
1575 46613 : SfxStateCache* pCache = (*pImp->pCaches)[pImp->nMsgPos];
1576 : DBG_ASSERT( pCache, "invalid SfxStateCache-position in job queue" );
1577 46613 : bool bWasDirty = pCache->IsControllerDirty();
1578 46613 : if ( bWasDirty )
1579 : {
1580 14819 : Update_Impl( pCache );
1581 : DBG_ASSERT( nCount == pImp->pCaches->size(),
1582 : "Reschedule in StateChanged => buff" );
1583 : }
1584 :
1585 : // skip to next function binding
1586 46613 : ++pImp->nMsgPos;
1587 :
1588 : // keep job if it is not completed, but any input is available
1589 46613 : bJobDone = pImp->nMsgPos >= nCount;
1590 46613 : 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 10 : bJobDone = false;
1596 10 : pImp->bFirstRound = false;
1597 10 : pImp->nMsgPos = 0;
1598 : }
1599 :
1600 46613 : if ( bWasDirty && !bJobDone && bPreEmptive && (--nLoops == 0) )
1601 : {
1602 1283 : pImp->bInNextJob = false;
1603 1283 : return sal_False;
1604 : }
1605 : }
1606 : }
1607 :
1608 379 : pImp->nMsgPos = 0;
1609 :
1610 : // check for volatile slots
1611 379 : bool bVolatileSlotsPresent = false;
1612 35922 : for ( sal_uInt16 n = 0; n < nCount; ++n )
1613 : {
1614 35543 : SfxStateCache* pCache = (*pImp->pCaches)[n];
1615 35543 : const SfxSlotServer *pSlotServer = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
1616 35543 : if ( pSlotServer && pSlotServer->GetSlot()->IsMode(SFX_SLOT_VOLATILE) )
1617 : {
1618 0 : pCache->Invalidate(false);
1619 0 : bVolatileSlotsPresent = true;
1620 : }
1621 : }
1622 :
1623 379 : if (bVolatileSlotsPresent)
1624 0 : pImp->aTimer.SetTimeout(TIMEOUT_IDLE);
1625 : else
1626 379 : pImp->aTimer.Stop();
1627 :
1628 : // Update round is finished
1629 379 : pImp->bInNextJob = false;
1630 379 : Broadcast(SfxSimpleHint(SFX_HINT_UPDATEDONE));
1631 379 : 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 238066 : 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 238066 : 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 238066 : pImp->nOwnRegLevel++;
1668 :
1669 : // check if this is the outer most level
1670 238066 : if ( ++nRegLevel == 1 )
1671 : {
1672 : // stop background-processing
1673 66080 : pImp->aTimer.Stop();
1674 :
1675 : // flush the cache
1676 66080 : pImp->nCachedFunc1 = 0;
1677 66080 : pImp->nCachedFunc2 = 0;
1678 :
1679 : // Mark if the all of the Caches have dissapered.
1680 66080 : pImp->bCtrlReleased = false;
1681 : }
1682 :
1683 238066 : return nRegLevel;
1684 : }
1685 :
1686 :
1687 233993 : 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 233993 : 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 233993 : pImp->nOwnRegLevel--;
1706 :
1707 : // check if this is the outer most level
1708 233993 : if ( --nRegLevel == 0 && !SFX_APP()->IsDowning() )
1709 : {
1710 66089 : if ( pImp->bContextChanged )
1711 : {
1712 60 : pImp->bContextChanged = false;
1713 : }
1714 :
1715 66089 : SfxViewFrame* pFrame = pDispatcher->GetFrame();
1716 :
1717 : // If possible remove unused Caches, for example prepare PlugInInfo
1718 66089 : if ( pImp->bCtrlReleased )
1719 : {
1720 33939 : for ( sal_uInt16 nCache = pImp->pCaches->size(); nCache > 0; --nCache )
1721 : {
1722 : // Get Cache via ::com::sun::star::sdbcx::Index
1723 32049 : SfxStateCache *pCache = (*pImp->pCaches)[nCache-1];
1724 :
1725 : // No interested Controller present
1726 32049 : if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() )
1727 : {
1728 : // Remove Cache. Safety: first remove and then delete
1729 26564 : pImp->pCaches->erase(pImp->pCaches->begin() + nCache - 1);
1730 26564 : delete pCache;
1731 : }
1732 : }
1733 : }
1734 :
1735 : // restart background-processing
1736 66089 : pImp->nMsgPos = 0;
1737 66089 : if ( !pFrame || !pFrame->GetObjectShell() )
1738 236041 : return;
1739 64041 : if ( pImp->pCaches && !pImp->pCaches->empty() )
1740 : {
1741 56501 : pImp->aTimer.Stop();
1742 56501 : pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
1743 56501 : 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 6121 : void SfxBindings::SetDispatcher( SfxDispatcher *pDisp )
1758 : {
1759 6121 : SfxDispatcher *pOldDispat = pDispatcher;
1760 6121 : if ( pDisp != pDispatcher )
1761 : {
1762 4095 : if ( pOldDispat )
1763 : {
1764 2043 : SfxBindings* pBind = pOldDispat->GetBindings();
1765 6129 : while ( pBind )
1766 : {
1767 2043 : if ( pBind->pImp->pSubBindings == this && pBind->pDispatcher != pDisp )
1768 4 : pBind->SetSubBindings_Impl( NULL );
1769 2043 : pBind = pBind->pImp->pSubBindings;
1770 : }
1771 : }
1772 :
1773 4095 : pDispatcher = pDisp;
1774 :
1775 4095 : ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider > xProv;
1776 4095 : if ( pDisp )
1777 4104 : xProv = ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider >
1778 4104 : ( pDisp->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY );
1779 :
1780 4095 : SetDispatchProvider_Impl( xProv );
1781 4095 : InvalidateAll( true );
1782 4095 : InvalidateUnoControllers_Impl();
1783 :
1784 4095 : if ( pDispatcher && !pOldDispat )
1785 : {
1786 2052 : if ( pImp->pSubBindings && pImp->pSubBindings->pDispatcher != pOldDispat )
1787 : {
1788 : OSL_FAIL( "SubBindings already set before activating!" );
1789 0 : pImp->pSubBindings->ENTERREGISTRATIONS();
1790 : }
1791 2052 : LEAVEREGISTRATIONS();
1792 : }
1793 2043 : else if( !pDispatcher )
1794 : {
1795 2043 : ENTERREGISTRATIONS();
1796 2043 : 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 4095 : Broadcast( SfxSimpleHint( SFX_HINT_DATACHANGED ) );
1804 :
1805 4095 : if ( pDisp )
1806 : {
1807 2052 : SfxBindings* pBind = pDisp->GetBindings();
1808 4104 : while ( pBind && pBind != this )
1809 : {
1810 4 : if ( !pBind->pImp->pSubBindings )
1811 : {
1812 4 : pBind->SetSubBindings_Impl( this );
1813 4 : break;
1814 : }
1815 :
1816 0 : pBind = pBind->pImp->pSubBindings;
1817 : }
1818 4095 : }
1819 : }
1820 6121 : }
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 8 : void SfxBindings::SetSubBindings_Impl( SfxBindings *pSub )
1963 : {
1964 8 : if ( pImp->pSubBindings )
1965 : {
1966 4 : pImp->pSubBindings->SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > () );
1967 4 : pImp->pSubBindings->pImp->pSuperBindings = NULL;
1968 : }
1969 :
1970 8 : pImp->pSubBindings = pSub;
1971 :
1972 8 : if ( pSub )
1973 : {
1974 4 : pImp->pSubBindings->SetDispatchProvider_Impl( pImp->xProv );
1975 4 : pSub->pImp->pSuperBindings = this;
1976 : }
1977 8 : }
1978 :
1979 6097 : SfxBindings* SfxBindings::GetSubBindings_Impl( bool bTop ) const
1980 : {
1981 6097 : SfxBindings *pRet = pImp->pSubBindings;
1982 6097 : if ( bTop )
1983 : {
1984 0 : while ( pRet->pImp->pSubBindings )
1985 0 : pRet = pRet->pImp->pSubBindings;
1986 : }
1987 :
1988 6097 : return pRet;
1989 : }
1990 :
1991 2048 : void SfxBindings::SetWorkWindow_Impl( SfxWorkWindow* pWork )
1992 : {
1993 2048 : pImp->pWorkWin = pWork;
1994 2048 : }
1995 :
1996 5660 : SfxWorkWindow* SfxBindings::GetWorkWindow_Impl() const
1997 : {
1998 5660 : 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 8190 : void SfxBindings::InvalidateUnoControllers_Impl()
2026 : {
2027 8190 : 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 8190 : if ( pImp->pSubBindings )
2040 0 : pImp->pSubBindings->InvalidateUnoControllers_Impl();
2041 8190 : }
2042 :
2043 11198 : bool SfxBindings::IsInUpdate() const
2044 : {
2045 11198 : bool bInUpdate = pImp->bInUpdate;
2046 11198 : if ( !bInUpdate && pImp->pSubBindings )
2047 0 : bInUpdate = pImp->pSubBindings->IsInUpdate();
2048 11198 : return bInUpdate;
2049 : }
2050 :
2051 308 : void SfxBindings::SetVisibleState( sal_uInt16 nId, bool bShow )
2052 : {
2053 308 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
2054 308 : SfxStateCache *pCache = GetStateCache( nId );
2055 308 : if ( pCache )
2056 0 : pCache->SetVisibleState( bShow );
2057 308 : }
2058 :
2059 7223 : void SfxBindings::SetActiveFrame( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > & rFrame )
2060 : {
2061 7223 : if ( rFrame.is() || !pDispatcher )
2062 2026 : 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 5197 : pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), ::com::sun::star::uno::UNO_QUERY ) );
2066 7223 : }
2067 :
2068 4811 : const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > SfxBindings::GetActiveFrame() const
2069 : {
2070 4811 : const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame( pImp->xProv, ::com::sun::star::uno::UNO_QUERY );
2071 4811 : if ( xFrame.is() || !pDispatcher )
2072 4810 : return xFrame;
2073 : else
2074 1 : return pDispatcher->GetFrame()->GetFrame().GetFrameInterface();
2075 : }
2076 :
2077 11326 : void SfxBindings::SetDispatchProvider_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & rProv )
2078 : {
2079 11326 : bool bInvalidate = ( rProv != pImp->xProv );
2080 11326 : if ( bInvalidate )
2081 : {
2082 4095 : pImp->xProv = rProv;
2083 4095 : InvalidateAll( true );
2084 4095 : InvalidateUnoControllers_Impl();
2085 : }
2086 :
2087 11326 : if ( pImp->pSubBindings )
2088 0 : pImp->pSubBindings->SetDispatchProvider_Impl( pImp->xProv );
2089 11326 : }
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 2039 : void SfxBindings::SetRecorder_Impl( com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder >& rRecorder )
2113 : {
2114 2039 : pImp->xRecorder = rRecorder;
2115 2039 : }
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 153614 : uno::Reference < frame::XDispatch > SfxBindings::GetDispatch( const SfxSlot* pSlot, const util::URL& aURL, bool bMasterCommand )
2126 : {
2127 153614 : uno::Reference < frame::XDispatch > xRet;
2128 153614 : SfxStateCache* pCache = GetStateCache( pSlot->nSlotId );
2129 153614 : if ( pCache && !bMasterCommand )
2130 104149 : xRet = pCache->GetInternalDispatch();
2131 153614 : if ( !xRet.is() )
2132 : {
2133 : // dispatches for slaves are unbound, they don't have a state
2134 : SfxOfficeDispatch* pDispatch = bMasterCommand ?
2135 80 : new SfxOfficeDispatch( pDispatcher, pSlot, aURL ) :
2136 59417 : new SfxOfficeDispatch( *this, pDispatcher, pSlot, aURL );
2137 :
2138 59337 : pDispatch->SetMasterUnoCommand( bMasterCommand );
2139 59337 : xRet = uno::Reference < frame::XDispatch >( pDispatch );
2140 59337 : if ( !pCache )
2141 49385 : pCache = GetStateCache( pSlot->nSlotId );
2142 :
2143 : DBG_ASSERT( pCache, "No cache for OfficeDispatch!" );
2144 59337 : if ( pCache && !bMasterCommand )
2145 59257 : pCache->SetInternalDispatch( xRet );
2146 : }
2147 :
2148 153614 : return xRet;
2149 : }
2150 :
2151 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|