merge the formfield patch from ooo-build
[ooovba.git] / sfx2 / source / control / statcach.cxx
blob795fb5e9becb4567446002bcee5e33344eb02ea6
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: statcach.cxx,v $
10 * $Revision: 1.36.180.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sfx2.hxx"
34 #ifdef SOLARIS
35 // HACK: prevent conflict between STLPORT and Workshop headers on Solaris 8
36 #include <ctime>
37 #endif
39 #include <string> // HACK: prevent conflict between STLPORT and Workshop headers
40 #include <com/sun/star/util/XURLTransformer.hpp>
41 #include <com/sun/star/frame/XController.hpp>
42 #include <com/sun/star/frame/XFrameActionListener.hpp>
43 #include <com/sun/star/frame/XComponentLoader.hpp>
44 #include <com/sun/star/frame/XFrame.hpp>
45 #include <com/sun/star/frame/FrameActionEvent.hpp>
46 #include <com/sun/star/frame/FrameAction.hpp>
47 #include <com/sun/star/beans/PropertyValue.hpp>
48 #include <cppuhelper/weak.hxx>
49 #include <svtools/eitem.hxx>
50 #include <svtools/intitem.hxx>
51 #include <svtools/stritem.hxx>
52 #include <svtools/visitem.hxx>
53 #include <comphelper/processfactory.hxx>
55 #ifndef GCC
56 #endif
58 #include <sfx2/app.hxx>
59 #include <sfx2/appuno.hxx>
60 #include "statcach.hxx"
61 #include <sfx2/msg.hxx>
62 #include <sfx2/ctrlitem.hxx>
63 #include <sfx2/dispatch.hxx>
64 #include "sfxtypes.hxx"
65 #include <sfx2/sfxuno.hxx>
66 #include <sfx2/unoctitm.hxx>
67 #include <sfx2/msgpool.hxx>
68 #include <sfx2/viewfrm.hxx>
70 using namespace ::com::sun::star;
71 using namespace ::com::sun::star::uno;
72 using namespace ::com::sun::star::util;
74 //====================================================================
76 DBG_NAME(SfxStateCache)
77 DBG_NAME(SfxStateCacheSetState)
79 SFX_IMPL_XINTERFACE_2( BindDispatch_Impl, OWeakObject, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener )
80 SFX_IMPL_XTYPEPROVIDER_2( BindDispatch_Impl, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener )
82 //-----------------------------------------------------------------------------
83 BindDispatch_Impl::BindDispatch_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > & rDisp, const ::com::sun::star::util::URL& rURL, SfxStateCache *pStateCache, const SfxSlot* pS )
84 : xDisp( rDisp )
85 , aURL( rURL )
86 , pCache( pStateCache )
87 , pSlot( pS )
89 DBG_ASSERT( pCache && pSlot, "Invalid BindDispatch!");
90 aStatus.IsEnabled = sal_True;
93 void SAL_CALL BindDispatch_Impl::disposing( const ::com::sun::star::lang::EventObject& ) throw( ::com::sun::star::uno::RuntimeException )
95 if ( xDisp.is() )
97 xDisp->removeStatusListener( (::com::sun::star::frame::XStatusListener*) this, aURL );
98 xDisp = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > ();
102 void SAL_CALL BindDispatch_Impl::statusChanged( const ::com::sun::star::frame::FeatureStateEvent& rEvent ) throw( ::com::sun::star::uno::RuntimeException )
104 aStatus = rEvent;
105 if ( !pCache )
106 return;
108 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > xRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY );
109 if ( aStatus.Requery )
110 pCache->Invalidate( sal_True );
111 else
113 SfxPoolItem *pItem=NULL;
114 sal_uInt16 nId = pCache->GetId();
115 SfxItemState eState = SFX_ITEM_DISABLED;
116 // pCache->Invalidate( sal_False );
117 if ( !aStatus.IsEnabled )
119 // default
121 else if (aStatus.State.hasValue())
123 eState = SFX_ITEM_AVAILABLE;
124 ::com::sun::star::uno::Any aAny = aStatus.State;
126 ::com::sun::star::uno::Type pType = aAny.getValueType();
127 if ( pType == ::getBooleanCppuType() )
129 sal_Bool bTemp = false;
130 aAny >>= bTemp ;
131 pItem = new SfxBoolItem( nId, bTemp );
133 else if ( pType == ::getCppuType((const sal_uInt16*)0) )
135 sal_uInt16 nTemp = 0;
136 aAny >>= nTemp ;
137 pItem = new SfxUInt16Item( nId, nTemp );
139 else if ( pType == ::getCppuType((const sal_uInt32*)0) )
141 sal_uInt32 nTemp = 0;
142 aAny >>= nTemp ;
143 pItem = new SfxUInt32Item( nId, nTemp );
145 else if ( pType == ::getCppuType((const ::rtl::OUString*)0) )
147 ::rtl::OUString sTemp ;
148 aAny >>= sTemp ;
149 pItem = new SfxStringItem( nId, sTemp );
151 else
153 if ( pSlot )
154 pItem = pSlot->GetType()->CreateItem();
155 if ( pItem )
157 pItem->SetWhich( nId );
158 pItem->PutValue( aAny );
160 else
161 pItem = new SfxVoidItem( nId );
164 else
166 // DONTCARE status
167 pItem = new SfxVoidItem(0);
168 eState = SFX_ITEM_UNKNOWN;
171 for ( SfxControllerItem *pCtrl = pCache->GetItemLink();
172 pCtrl;
173 pCtrl = pCtrl->GetItemLink() )
174 pCtrl->StateChanged( nId, eState, pItem );
176 delete pItem;
180 void BindDispatch_Impl::Release()
182 if ( xDisp.is() )
184 xDisp->removeStatusListener( (::com::sun::star::frame::XStatusListener*) this, aURL );
185 xDisp = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > ();
188 pCache = NULL;
189 release();
192 const ::com::sun::star::frame::FeatureStateEvent& BindDispatch_Impl::GetStatus() const
194 return aStatus;
197 void BindDispatch_Impl::Dispatch( uno::Sequence < beans::PropertyValue > aProps, sal_Bool bForceSynchron )
199 if ( xDisp.is() && aStatus.IsEnabled )
201 sal_Int32 nLength = aProps.getLength();
202 aProps.realloc(nLength+1);
203 aProps[nLength].Name = DEFINE_CONST_UNICODE("SynchronMode");
204 aProps[nLength].Value <<= bForceSynchron ;
205 xDisp->dispatch( aURL, aProps );
209 //--------------------------------------------------------------------
211 /* Dieser Konstruktor fuer einen ungueltigen Cache, der sich also
212 bei der ersten Anfrage zun"achst updated.
215 SfxStateCache::SfxStateCache( sal_uInt16 nFuncId ):
216 pDispatch( 0 ),
217 nId(nFuncId),
218 pInternalController(0),
219 pController(0),
220 pLastItem( 0 ),
221 eLastState( 0 ),
222 bItemVisible( sal_True )
224 DBG_MEMTEST();
225 DBG_CTOR(SfxStateCache, 0);
226 bCtrlDirty = sal_True;
227 bSlotDirty = sal_True;
228 bItemDirty = sal_True;
231 //--------------------------------------------------------------------
233 /* Der Destruktor pr"uft per Assertion, ob noch Controller angemeldet
234 sind.
237 SfxStateCache::~SfxStateCache()
239 DBG_MEMTEST();
240 DBG_DTOR(SfxStateCache, 0);
241 DBG_ASSERT( pController == 0 && pInternalController == 0, "es sind noch Controller angemeldet" );
242 if ( !IsInvalidItem(pLastItem) )
243 delete pLastItem;
244 if ( pDispatch )
246 pDispatch->Release();
247 pDispatch = NULL;
251 //--------------------------------------------------------------------
252 // invalidates the cache (next request will force update)
253 void SfxStateCache::Invalidate( sal_Bool bWithMsg )
255 bCtrlDirty = sal_True;
256 if ( bWithMsg )
258 bSlotDirty = sal_True;
259 aSlotServ.SetSlot( 0 );
260 if ( pDispatch )
262 pDispatch->Release();
263 pDispatch = NULL;
268 //--------------------------------------------------------------------
270 // gets the corresponding function from the dispatcher or the cache
272 const SfxSlotServer* SfxStateCache::GetSlotServer( SfxDispatcher &rDispat , const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & xProv )
274 DBG_MEMTEST();
275 DBG_CHKTHIS(SfxStateCache, 0);
277 if ( bSlotDirty )
279 // get the SlotServer; we need it for internal controllers anyway, but also in most cases
280 rDispat._FindServer( nId, aSlotServ, sal_False );
282 DBG_ASSERT( !pDispatch, "Old Dispatch not removed!" );
284 // we don't need to check the dispatch provider if we only have an internal controller
285 if ( xProv.is() )
287 const SfxSlot* pSlot = aSlotServ.GetSlot();
288 if ( !pSlot )
289 // get the slot - even if it is disabled on the dispatcher
290 pSlot = SfxSlotPool::GetSlotPool( rDispat.GetFrame() ).GetSlot( nId );
292 if ( !pSlot || !pSlot->pUnoName )
294 bSlotDirty = sal_False;
295 bCtrlDirty = sal_True;
296 return aSlotServ.GetSlot()? &aSlotServ: 0;
299 // create the dispatch URL from the slot data
300 ::com::sun::star::util::URL aURL;
301 ::rtl::OUString aCmd = DEFINE_CONST_UNICODE(".uno:");
302 aURL.Protocol = aCmd;
303 aURL.Path = ::rtl::OUString::createFromAscii( pSlot->GetUnoName() );
304 aCmd += aURL.Path;
305 aURL.Complete = aCmd;
306 aURL.Main = aCmd;
308 // try to get a dispatch object for this command
309 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp = xProv->queryDispatch( aURL, ::rtl::OUString(), 0 );
310 if ( xDisp.is() )
312 // test the dispatch object if it is just a wrapper for a SfxDispatcher
313 ::com::sun::star::uno::Reference< ::com::sun::star::lang::XUnoTunnel > xTunnel( xDisp, ::com::sun::star::uno::UNO_QUERY );
314 SfxOfficeDispatch* pDisp = NULL;
315 if ( xTunnel.is() )
317 sal_Int64 nImplementation = xTunnel->getSomething(SfxOfficeDispatch::impl_getStaticIdentifier());
318 pDisp = reinterpret_cast< SfxOfficeDispatch* >(sal::static_int_cast< sal_IntPtr >( nImplementation ));
321 if ( pDisp )
323 // The intercepting object is an SFX component
324 // If this dispatch object does not use the wanted dispatcher or the AppDispatcher, it's treated like any other UNO component
325 // (intercepting by internal dispatches)
326 SfxDispatcher *pDispatcher = pDisp->GetDispatcher_Impl();
327 if ( pDispatcher == &rDispat || pDispatcher == SFX_APP()->GetAppDispatcher_Impl() )
329 // so we can use it directly
330 bSlotDirty = sal_False;
331 bCtrlDirty = sal_True;
332 return aSlotServ.GetSlot()? &aSlotServ: 0;
336 // so the dispatch object isn't a SfxDispatcher wrapper or it is one, but it uses another dispatcher, but not rDispat
337 pDispatch = new BindDispatch_Impl( xDisp, aURL, this, pSlot );
338 pDispatch->acquire();
340 // flags must be set before adding StatusListener because the dispatch object will set the state
341 bSlotDirty = sal_False;
342 bCtrlDirty = sal_True;
343 xDisp->addStatusListener( pDispatch, aURL );
345 else if ( rDispat.GetFrame() )
347 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider > xFrameProv(
348 rDispat.GetFrame()->GetFrame()->GetFrameInterface(), ::com::sun::star::uno::UNO_QUERY );
349 if ( xFrameProv != xProv )
350 return GetSlotServer( rDispat, xFrameProv );
354 bSlotDirty = sal_False;
355 bCtrlDirty = sal_True;
358 // we *always* return a SlotServer (if there is one); but in case of an external dispatch we might not use it
359 // for the "real" (non internal) controllers
360 return aSlotServ.GetSlot()? &aSlotServ: 0;
364 //--------------------------------------------------------------------
366 // Status setzen in allen Controllern
368 void SfxStateCache::SetState
370 SfxItemState eState, // <SfxItemState> von 'pState'
371 const SfxPoolItem* pState, // Status des Slots, ggf. 0 oder -1
372 BOOL bMaybeDirty
375 /* [Beschreibung]
377 Diese Methode verteilt die Status auf alle an dieser SID gebundenen
378 <SfxControllerItem>s. Ist der Wert derselbe wie zuvor und wurde in-
379 zwischen weder ein Controller angemeldet, noch ein Controller invalidiert,
380 dann wird kein Wert weitergeleitet. Dadurch wird z.B. Flackern in
381 ListBoxen vermieden.
385 // if ( pDispatch )
386 // return;
387 SetState_Impl( eState, pState, bMaybeDirty );
390 //--------------------------------------------------------------------
392 void SfxStateCache::SetVisibleState( BOOL bShow )
394 SfxItemState eState( SFX_ITEM_AVAILABLE );
395 const SfxPoolItem* pState( NULL );
396 sal_Bool bNotify( sal_False );
397 sal_Bool bDeleteItem( sal_False );
399 if ( bShow != bItemVisible )
401 bItemVisible = bShow;
402 if ( bShow )
404 if ( IsInvalidItem(pLastItem) || ( pLastItem == NULL ))
406 pState = new SfxVoidItem( nId );
407 bDeleteItem = sal_True;
409 else
410 pState = pLastItem;
412 eState = eLastState;
413 bNotify = ( pState != 0 );
415 else
417 pState = new SfxVisibilityItem( nId, FALSE );
418 bDeleteItem = sal_True;
421 // Controller updaten
422 if ( !pDispatch && pController )
424 for ( SfxControllerItem *pCtrl = pController;
425 pCtrl;
426 pCtrl = pCtrl->GetItemLink() )
427 pCtrl->StateChanged( nId, eState, pState );
430 if ( pInternalController )
431 pInternalController->StateChanged( nId, eState, pState );
433 if ( !bDeleteItem )
434 delete pState;
438 //--------------------------------------------------------------------
440 void SfxStateCache::SetState_Impl
442 SfxItemState eState, // <SfxItemState> von 'pState'
443 const SfxPoolItem* pState, // Status des Slots, ggf. 0 oder -1
444 BOOL bMaybeDirty
447 (void)bMaybeDirty; //unused
448 DBG_MEMTEST();
449 DBG_CHKTHIS(SfxStateCache, 0);
451 // wenn zwischen Enter- und LeaveRegistrations ein hartes Update kommt
452 // k"onnen zwischenzeitlich auch Cached ohne Controller exisitieren
453 if ( !pController && !pInternalController )
454 return;
456 DBG_ASSERT( bMaybeDirty || !bSlotDirty, "setting state of dirty message" );
457 // DBG_ASSERT( bCtrlDirty || ( aSlotServ.GetSlot() && aSlotServ.GetSlot()->IsMode(SFX_SLOT_VOLATILE) ), ! Discussed with MBA
458 // "setting state of non dirty controller" );
459 DBG_ASSERT( SfxControllerItem::GetItemState(pState) == eState, "invalid SfxItemState" );
460 DBG_PROFSTART(SfxStateCacheSetState);
462 // m"ussen die Controller "uberhaupt benachrichtigt werden?
463 FASTBOOL bNotify = bItemDirty;
464 if ( !bItemDirty )
466 FASTBOOL bBothAvailable = pLastItem && pState &&
467 !IsInvalidItem(pState) && !IsInvalidItem(pLastItem);
468 DBG_ASSERT( !bBothAvailable || pState != pLastItem, "setting state with own item" );
469 if ( bBothAvailable )
470 bNotify = pState->Type() != pLastItem->Type() ||
471 *pState != *pLastItem;
472 else
473 bNotify = ( pState != pLastItem ) || ( eState != eLastState );
476 if ( bNotify )
478 // Controller updaten
479 if ( !pDispatch && pController )
481 for ( SfxControllerItem *pCtrl = pController;
482 pCtrl;
483 pCtrl = pCtrl->GetItemLink() )
484 pCtrl->StateChanged( nId, eState, pState );
487 if ( pInternalController )
488 ((SfxDispatchController_Impl *)pInternalController)->StateChanged( nId, eState, pState, &aSlotServ );
490 // neuen Wert merken
491 if ( !IsInvalidItem(pLastItem) )
492 DELETEZ(pLastItem);
493 if ( pState && !IsInvalidItem(pState) )
494 pLastItem = pState->Clone();
495 else
496 pLastItem = 0;
497 eLastState = eState;
498 bItemDirty = sal_False;
501 bCtrlDirty = sal_False;
502 DBG_PROFSTOP(SfxStateCacheSetState);
506 //--------------------------------------------------------------------
508 // alten Status in allen Controllern nochmal setzen
510 void SfxStateCache::SetCachedState( BOOL bAlways )
512 DBG_MEMTEST();
513 DBG_CHKTHIS(SfxStateCache, 0);
514 DBG_ASSERT(pController==NULL||pController->GetId()==nId, "Cache mit falschem ControllerItem" );
515 DBG_PROFSTART(SfxStateCacheSetState);
517 // nur updaten wenn cached item vorhanden und auch verarbeitbar
518 // (Wenn der State gesendet wird, mu\s sichergestellt sein, da\s ein
519 // Slotserver vorhanden ist, s. SfxControllerItem::GetCoreMetric() )
520 if ( bAlways || ( !bItemDirty && !bSlotDirty ) )
522 // Controller updaten
523 if ( !pDispatch && pController )
525 for ( SfxControllerItem *pCtrl = pController;
526 pCtrl;
527 pCtrl = pCtrl->GetItemLink() )
528 pCtrl->StateChanged( nId, eLastState, pLastItem );
531 if ( pInternalController )
532 ((SfxDispatchController_Impl *)pInternalController)->StateChanged( nId, eLastState, pLastItem, &aSlotServ );
534 // Controller sind jetzt ok
535 bCtrlDirty = sal_True;
538 DBG_PROFSTOP(SfxStateCacheSetState);
542 //--------------------------------------------------------------------
544 // FloatingWindows in allen Controls mit dieser Id zerstoeren
546 void SfxStateCache::DeleteFloatingWindows()
548 DBG_MEMTEST();
549 DBG_CHKTHIS(SfxStateCache, 0);
551 SfxControllerItem *pNextCtrl=0;
552 for ( SfxControllerItem *pCtrl=pController; pCtrl; pCtrl=pNextCtrl )
554 DBG_TRACE((ByteString("pCtrl: ").Append(ByteString::CreateFromInt64((sal_uIntPtr)pCtrl))).GetBuffer());
555 pNextCtrl = pCtrl->GetItemLink();
556 pCtrl->DeleteFloatingWindow();
560 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > SfxStateCache::GetDispatch() const
562 if ( pDispatch )
563 return pDispatch->xDisp;
564 return ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > ();
567 void SfxStateCache::Dispatch( const SfxItemSet* pSet, sal_Bool bForceSynchron )
569 // protect pDispatch against destruction in the call
570 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XStatusListener > xKeepAlive( pDispatch );
571 if ( pDispatch )
573 uno::Sequence < beans::PropertyValue > aArgs;
574 if (pSet)
575 TransformItems( nId, *pSet, aArgs );
576 pDispatch->Dispatch( aArgs, bForceSynchron );