bump product version to 5.0.4.1
[LibreOffice.git] / sfx2 / source / control / statcach.cxx
blob553cf4a1b645ea896e5d60250b774fd57c1d9928
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #ifdef SOLARIS
22 #include <ctime>
23 #endif
25 #include <string>
26 #include <com/sun/star/util/XURLTransformer.hpp>
27 #include <com/sun/star/frame/XController.hpp>
28 #include <com/sun/star/frame/XFrameActionListener.hpp>
29 #include <com/sun/star/frame/XComponentLoader.hpp>
30 #include <com/sun/star/frame/XFrame.hpp>
31 #include <com/sun/star/frame/FrameActionEvent.hpp>
32 #include <com/sun/star/frame/FrameAction.hpp>
33 #include <com/sun/star/beans/PropertyValue.hpp>
34 #include <cppuhelper/weak.hxx>
35 #include <svl/eitem.hxx>
36 #include <svl/intitem.hxx>
37 #include <svl/stritem.hxx>
38 #include <svl/visitem.hxx>
39 #include <comphelper/processfactory.hxx>
41 #include <sfx2/app.hxx>
42 #include "statcach.hxx"
43 #include <sfx2/msg.hxx>
44 #include <sfx2/ctrlitem.hxx>
45 #include <sfx2/dispatch.hxx>
46 #include "sfxtypes.hxx"
47 #include <sfx2/sfxuno.hxx>
48 #include <sfx2/unoctitm.hxx>
49 #include <sfx2/msgpool.hxx>
50 #include <sfx2/viewfrm.hxx>
52 using namespace ::com::sun::star;
53 using namespace ::com::sun::star::uno;
54 using namespace ::com::sun::star::util;
56 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 )
57 : xDisp( rDisp )
58 , aURL( rURL )
59 , pCache( pStateCache )
60 , pSlot( pS )
62 DBG_ASSERT( pCache && pSlot, "Invalid BindDispatch!");
63 aStatus.IsEnabled = sal_True;
66 void SAL_CALL BindDispatch_Impl::disposing( const ::com::sun::star::lang::EventObject& ) throw( ::com::sun::star::uno::RuntimeException, std::exception )
68 if ( xDisp.is() )
70 xDisp->removeStatusListener( (::com::sun::star::frame::XStatusListener*) this, aURL );
71 xDisp = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > ();
75 void SAL_CALL BindDispatch_Impl::statusChanged( const ::com::sun::star::frame::FeatureStateEvent& rEvent ) throw( ::com::sun::star::uno::RuntimeException, std::exception )
77 aStatus = rEvent;
78 if ( !pCache )
79 return;
81 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > xRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY );
82 if ( aStatus.Requery )
83 pCache->Invalidate( true );
84 else
86 SfxPoolItem *pItem=NULL;
87 sal_uInt16 nId = pCache->GetId();
88 SfxItemState eState = SfxItemState::DISABLED;
89 if ( !aStatus.IsEnabled )
91 // default
93 else if (aStatus.State.hasValue())
95 eState = SfxItemState::DEFAULT;
96 ::com::sun::star::uno::Any aAny = aStatus.State;
98 ::com::sun::star::uno::Type pType = aAny.getValueType();
99 if ( pType == cppu::UnoType< bool >::get() )
101 bool bTemp = false;
102 aAny >>= bTemp ;
103 pItem = new SfxBoolItem( nId, bTemp );
105 else if ( pType == ::cppu::UnoType< ::cppu::UnoUnsignedShortType >::get() )
107 sal_uInt16 nTemp = 0;
108 aAny >>= nTemp ;
109 pItem = new SfxUInt16Item( nId, nTemp );
111 else if ( pType == cppu::UnoType<sal_uInt32>::get() )
113 sal_uInt32 nTemp = 0;
114 aAny >>= nTemp ;
115 pItem = new SfxUInt32Item( nId, nTemp );
117 else if ( pType == cppu::UnoType<OUString>::get() )
119 OUString sTemp ;
120 aAny >>= sTemp ;
121 pItem = new SfxStringItem( nId, sTemp );
123 else
125 if ( pSlot )
126 pItem = pSlot->GetType()->CreateItem();
127 if ( pItem )
129 pItem->SetWhich( nId );
130 pItem->PutValue( aAny );
132 else
133 pItem = new SfxVoidItem( nId );
136 else
138 // DONTCARE status
139 pItem = new SfxVoidItem(0);
140 eState = SfxItemState::UNKNOWN;
143 for ( SfxControllerItem *pCtrl = pCache->GetItemLink();
144 pCtrl;
145 pCtrl = pCtrl->GetItemLink() )
146 pCtrl->StateChanged( nId, eState, pItem );
148 delete pItem;
152 void BindDispatch_Impl::Release()
154 if ( xDisp.is() )
156 xDisp->removeStatusListener( (::com::sun::star::frame::XStatusListener*) this, aURL );
157 xDisp = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > ();
160 pCache = NULL;
161 release();
165 void BindDispatch_Impl::Dispatch( const uno::Sequence < beans::PropertyValue >& aProps, bool bForceSynchron )
167 if ( xDisp.is() && aStatus.IsEnabled )
169 sal_Int32 nLength = aProps.getLength();
170 uno::Sequence < beans::PropertyValue > aProps2 = aProps;
171 aProps2.realloc(nLength+1);
172 aProps2[nLength].Name = "SynchronMode";
173 aProps2[nLength].Value <<= bForceSynchron ;
174 xDisp->dispatch( aURL, aProps2 );
179 // This constructor for an invalid cache that is updated in the first request.
181 SfxStateCache::SfxStateCache( sal_uInt16 nFuncId ):
182 pDispatch( 0 ),
183 nId(nFuncId),
184 pInternalController(0),
185 pController(0),
186 pLastItem( 0 ),
187 eLastState( SfxItemState::UNKNOWN ),
188 bItemVisible( true )
190 bCtrlDirty = true;
191 bSlotDirty = true;
192 bItemDirty = true;
196 // The Destructor checks by assertion, even if controllers are registered.
198 SfxStateCache::~SfxStateCache()
200 DBG_ASSERT( pController == 0 && pInternalController == 0, "there are still Controllers registered" );
201 if ( !IsInvalidItem(pLastItem) )
202 delete pLastItem;
203 if ( pDispatch )
205 pDispatch->Release();
206 pDispatch = NULL;
211 // invalidates the cache (next request will force update)
212 void SfxStateCache::Invalidate( bool bWithMsg )
214 bCtrlDirty = true;
215 if ( bWithMsg )
217 bSlotDirty = true;
218 aSlotServ.SetSlot( 0 );
219 if ( pDispatch )
221 pDispatch->Release();
222 pDispatch = NULL;
228 // gets the corresponding function from the dispatcher or the cache
230 const SfxSlotServer* SfxStateCache::GetSlotServer( SfxDispatcher &rDispat , const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & xProv )
233 if ( bSlotDirty )
235 // get the SlotServer; we need it for internal controllers anyway, but also in most cases
236 rDispat._FindServer( nId, aSlotServ, false );
238 DBG_ASSERT( !pDispatch, "Old Dispatch not removed!" );
240 // we don't need to check the dispatch provider if we only have an internal controller
241 if ( xProv.is() )
243 const SfxSlot* pSlot = aSlotServ.GetSlot();
244 if ( !pSlot )
245 // get the slot - even if it is disabled on the dispatcher
246 pSlot = SfxSlotPool::GetSlotPool( rDispat.GetFrame() ).GetSlot( nId );
248 if ( !pSlot || !pSlot->pUnoName )
250 bSlotDirty = false;
251 bCtrlDirty = true;
252 return aSlotServ.GetSlot()? &aSlotServ: 0;
255 // create the dispatch URL from the slot data
256 ::com::sun::star::util::URL aURL;
257 OUString aCmd = ".uno:";
258 aURL.Protocol = aCmd;
259 aURL.Path = OUString::createFromAscii( pSlot->GetUnoName() );
260 aCmd += aURL.Path;
261 aURL.Complete = aCmd;
262 aURL.Main = aCmd;
264 // try to get a dispatch object for this command
265 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp = xProv->queryDispatch( aURL, OUString(), 0 );
266 if ( xDisp.is() )
268 // test the dispatch object if it is just a wrapper for a SfxDispatcher
269 ::com::sun::star::uno::Reference< ::com::sun::star::lang::XUnoTunnel > xTunnel( xDisp, ::com::sun::star::uno::UNO_QUERY );
270 SfxOfficeDispatch* pDisp = NULL;
271 if ( xTunnel.is() )
273 sal_Int64 nImplementation = xTunnel->getSomething(SfxOfficeDispatch::impl_getStaticIdentifier());
274 pDisp = reinterpret_cast< SfxOfficeDispatch* >(sal::static_int_cast< sal_IntPtr >( nImplementation ));
277 if ( pDisp )
279 // The intercepting object is an SFX component
280 // If this dispatch object does not use the wanted dispatcher or the AppDispatcher, it's treated like any other UNO component
281 // (intercepting by internal dispatches)
282 SfxDispatcher *pDispatcher = pDisp->GetDispatcher_Impl();
283 if ( pDispatcher == &rDispat || pDispatcher == SfxGetpApp()->GetAppDispatcher_Impl() )
285 // so we can use it directly
286 bSlotDirty = false;
287 bCtrlDirty = true;
288 return aSlotServ.GetSlot()? &aSlotServ: 0;
292 // so the dispatch object isn't a SfxDispatcher wrapper or it is one, but it uses another dispatcher, but not rDispat
293 pDispatch = new BindDispatch_Impl( xDisp, aURL, this, pSlot );
294 pDispatch->acquire();
296 // flags must be set before adding StatusListener because the dispatch object will set the state
297 bSlotDirty = false;
298 bCtrlDirty = true;
299 xDisp->addStatusListener( pDispatch, aURL );
301 else if ( rDispat.GetFrame() )
303 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider > xFrameProv(
304 rDispat.GetFrame()->GetFrame().GetFrameInterface(), ::com::sun::star::uno::UNO_QUERY );
305 if ( xFrameProv != xProv )
306 return GetSlotServer( rDispat, xFrameProv );
310 bSlotDirty = false;
311 bCtrlDirty = true;
314 // we *always* return a SlotServer (if there is one); but in case of an external dispatch we might not use it
315 // for the "real" (non internal) controllers
316 return aSlotServ.GetSlot()? &aSlotServ: 0;
322 // Set Status in all Controllers
324 void SfxStateCache::SetState
326 SfxItemState eState, // <SfxItemState> from 'pState'
327 const SfxPoolItem* pState, // Slot Status, 0 or -1
328 bool bMaybeDirty
331 /* [Description]
333 This method distributes the status of all of this SID bound
334 <SfxControllerItem>s. If the value is the same as before, and if neither
335 controller was registered nor invalidated inbetween, then no value is
336 passed. This way the flickering is for example avoided in ListBoxes.
339 SetState_Impl( eState, pState, bMaybeDirty );
344 void SfxStateCache::SetVisibleState( bool bShow )
346 if ( bShow != bItemVisible )
348 SfxItemState eState( SfxItemState::DEFAULT );
349 const SfxPoolItem* pState( NULL );
350 bool bDeleteItem( false );
352 bItemVisible = bShow;
353 if ( bShow )
355 if ( IsInvalidItem(pLastItem) || ( pLastItem == NULL ))
357 pState = new SfxVoidItem( nId );
358 bDeleteItem = true;
360 else
361 pState = pLastItem;
363 eState = eLastState;
365 else
367 pState = new SfxVisibilityItem( nId, false );
368 bDeleteItem = true;
371 // Update Controller
372 if ( !pDispatch && pController )
374 for ( SfxControllerItem *pCtrl = pController;
375 pCtrl;
376 pCtrl = pCtrl->GetItemLink() )
377 pCtrl->StateChanged( nId, eState, pState );
380 if ( pInternalController )
381 pInternalController->StateChanged( nId, eState, pState );
383 if ( bDeleteItem )
384 delete pState;
390 void SfxStateCache::SetState_Impl
392 SfxItemState eState, // <SfxItemState> from 'pState'
393 const SfxPoolItem* pState, // Slot Status, 0 or -1
394 bool bMaybeDirty
397 (void)bMaybeDirty; //unused
399 // If a hard update occurs between enter- and leave-registrations is a
400 // can also intermediate Cached exist without controller.
401 if ( !pController && !pInternalController )
402 return;
404 DBG_ASSERT( bMaybeDirty || !bSlotDirty, "setting state of dirty message" );
405 DBG_ASSERT( SfxControllerItem::GetItemState(pState) == eState, "invalid SfxItemState" );
407 // does the controller have to be notified at all?
408 bool bNotify = bItemDirty;
409 if ( !bItemDirty )
411 bool bBothAvailable = pLastItem && pState &&
412 !IsInvalidItem(pState) && !IsInvalidItem(pLastItem);
413 DBG_ASSERT( !bBothAvailable || pState != pLastItem, "setting state with own item" );
414 if ( bBothAvailable )
415 bNotify = pState->Type() != pLastItem->Type() ||
416 *pState != *pLastItem;
417 else
418 bNotify = ( pState != pLastItem ) || ( eState != eLastState );
421 if ( bNotify )
423 // Update Controller
424 if ( !pDispatch && pController )
426 for ( SfxControllerItem *pCtrl = pController;
427 pCtrl;
428 pCtrl = pCtrl->GetItemLink() )
429 pCtrl->StateChanged( nId, eState, pState );
432 if ( pInternalController )
433 static_cast<SfxDispatchController_Impl *>(pInternalController)->StateChanged( nId, eState, pState, &aSlotServ );
435 // Remember new value
436 if ( !IsInvalidItem(pLastItem) )
437 DELETEZ(pLastItem);
438 if ( pState && !IsInvalidItem(pState) )
439 pLastItem = pState->Clone();
440 else
441 pLastItem = 0;
442 eLastState = eState;
443 bItemDirty = false;
446 bCtrlDirty = false;
451 // Set old status again in all the controllers
453 void SfxStateCache::SetCachedState( bool bAlways )
455 DBG_ASSERT(pController==NULL||pController->GetId()==nId, "Cache with wrong ControllerItem" );
457 // Only update if cached item exists and also able to process.
458 // (If the State is sent, it must be ensured that a SlotServer is present,
459 // see SfxControllerItem:: GetCoreMetric())
460 if ( bAlways || ( !bItemDirty && !bSlotDirty ) )
462 // Update Controller
463 if ( !pDispatch && pController )
465 for ( SfxControllerItem *pCtrl = pController;
466 pCtrl;
467 pCtrl = pCtrl->GetItemLink() )
468 pCtrl->StateChanged( nId, eLastState, pLastItem );
471 if ( pInternalController )
472 static_cast<SfxDispatchController_Impl *>(pInternalController)->StateChanged( nId, eLastState, pLastItem, &aSlotServ );
474 // Controller is now ok
475 bCtrlDirty = true;
481 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > SfxStateCache::GetDispatch() const
483 if ( pDispatch )
484 return pDispatch->xDisp;
485 return ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > ();
488 void SfxStateCache::Dispatch( const SfxItemSet* pSet, bool bForceSynchron )
490 // protect pDispatch against destruction in the call
491 ::com::sun::star::uno::Reference < ::com::sun::star::frame::XStatusListener > xKeepAlive( pDispatch );
492 if ( pDispatch )
494 uno::Sequence < beans::PropertyValue > aArgs;
495 if (pSet)
496 TransformItems( nId, *pSet, aArgs );
497 pDispatch->Dispatch( aArgs, bForceSynchron );
502 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */