bump product version to 4.2.0.1
[LibreOffice.git] / sfx2 / source / control / unoctitm.cxx
blobbeb36f7a7e21417bd6beb4903a24349d5eb30ebf
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 .
20 #include <config_features.h>
22 #include <tools/debug.hxx>
23 #include <svl/eitem.hxx>
24 #include <svl/stritem.hxx>
25 #include <svl/intitem.hxx>
26 #include <svl/itemset.hxx>
27 #include <svl/visitem.hxx>
28 #include <svtools/javacontext.hxx>
29 #include <svl/itempool.hxx>
30 #include <tools/urlobj.hxx>
31 #include <com/sun/star/util/URLTransformer.hpp>
32 #include <com/sun/star/util/XURLTransformer.hpp>
33 #include <com/sun/star/frame/XController.hpp>
34 #include <com/sun/star/frame/XFrameActionListener.hpp>
35 #include <com/sun/star/frame/XComponentLoader.hpp>
36 #include <com/sun/star/frame/XFrame.hpp>
37 #include <com/sun/star/frame/FrameActionEvent.hpp>
38 #include <com/sun/star/frame/FrameAction.hpp>
39 #include <com/sun/star/frame/status/ItemStatus.hpp>
40 #include <com/sun/star/frame/status/ItemState.hpp>
41 #include <com/sun/star/frame/DispatchResultState.hpp>
42 #include <com/sun/star/frame/status/Visibility.hpp>
43 #include <comphelper/processfactory.hxx>
44 #include <comphelper/sequence.hxx>
45 #include <osl/mutex.hxx>
46 #include <uno/current_context.hxx>
47 #include <vcl/svapp.hxx>
49 #include <sfx2/app.hxx>
50 #include <sfx2/unoctitm.hxx>
51 #include <sfx2/viewfrm.hxx>
52 #include <sfx2/frame.hxx>
53 #include <sfx2/ctrlitem.hxx>
54 #include <sfx2/sfxuno.hxx>
55 #include <sfx2/bindings.hxx>
56 #include <sfx2/dispatch.hxx>
57 #include <sfx2/sfxsids.hrc>
58 #include <sfx2/request.hxx>
59 #include "statcach.hxx"
60 #include <sfx2/msgpool.hxx>
61 #include <sfx2/objsh.hxx>
63 #include <boost/scoped_ptr.hpp>
65 using namespace ::com::sun::star::uno;
66 using namespace ::com::sun::star::util;
68 enum URLTypeId
70 URLType_BOOL,
71 URLType_BYTE,
72 URLType_SHORT,
73 URLType_LONG,
74 URLType_HYPER,
75 URLType_STRING,
76 URLType_FLOAT,
77 URLType_DOUBLE,
78 URLType_COUNT
81 const char* URLTypeNames[URLType_COUNT] =
83 "bool",
84 "byte",
85 "short",
86 "long",
87 "hyper",
88 "string",
89 "float",
90 "double"
93 SfxUnoControllerItem::SfxUnoControllerItem( SfxControllerItem *pItem, SfxBindings& rBind, const OUString& rCmd )
94 : pCtrlItem( pItem )
95 , pBindings( &rBind )
97 DBG_ASSERT( !pCtrlItem || !pCtrlItem->IsBound(), "ControllerItem is incorrect!" );
99 aCommand.Complete = rCmd;
100 Reference< XURLTransformer > xTrans( URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
101 xTrans->parseStrict( aCommand );
102 pBindings->RegisterUnoController_Impl( this );
105 SfxUnoControllerItem::~SfxUnoControllerItem()
107 // tell bindings to forget this controller ( if still connected )
108 if ( pBindings )
109 pBindings->ReleaseUnoController_Impl( this );
112 void SfxUnoControllerItem::UnBind()
114 // connection to SfxControllerItem is lost
115 pCtrlItem = NULL;
116 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY );
117 ReleaseDispatch();
120 void SAL_CALL SfxUnoControllerItem::statusChanged(const ::com::sun::star::frame::FeatureStateEvent& rEvent) throw ( ::com::sun::star::uno::RuntimeException )
122 SolarMutexGuard aGuard;
123 DBG_ASSERT( pCtrlItem, "dispatch implementation didn't respect our previous removeStatusListener call!" );
125 if ( rEvent.Requery )
127 // Error can only happen if the old Dispatch is implemented incorrectly
128 // i.e. removeStatusListener did not work. But such things can happen...
129 // So protect before ReleaseDispatch from release!
130 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY );
131 ReleaseDispatch();
132 if ( pCtrlItem )
133 GetNewDispatch(); // asynchronous ??
135 else if ( pCtrlItem )
137 SfxItemState eState = SFX_ITEM_DISABLED;
138 SfxPoolItem* pItem = NULL;
139 if ( rEvent.IsEnabled )
141 eState = SFX_ITEM_AVAILABLE;
142 ::com::sun::star::uno::Type pType = rEvent.State.getValueType();
144 if ( pType == ::getBooleanCppuType() )
146 sal_Bool bTemp = false;
147 rEvent.State >>= bTemp ;
148 pItem = new SfxBoolItem( pCtrlItem->GetId(), bTemp );
150 else if ( pType == ::getCppuType((const sal_uInt16*)0) )
152 sal_uInt16 nTemp = 0;
153 rEvent.State >>= nTemp ;
154 pItem = new SfxUInt16Item( pCtrlItem->GetId(), nTemp );
156 else if ( pType == ::getCppuType((const sal_uInt32*)0) )
158 sal_uInt32 nTemp = 0;
159 rEvent.State >>= nTemp ;
160 pItem = new SfxUInt32Item( pCtrlItem->GetId(), nTemp );
162 else if ( pType == ::getCppuType((const OUString*)0) )
164 OUString sTemp ;
165 rEvent.State >>= sTemp ;
166 pItem = new SfxStringItem( pCtrlItem->GetId(), sTemp );
168 else
169 pItem = new SfxVoidItem( pCtrlItem->GetId() );
172 pCtrlItem->StateChanged( pCtrlItem->GetId(), eState, pItem );
173 delete pItem;
177 void SAL_CALL SfxUnoControllerItem::disposing( const ::com::sun::star::lang::EventObject& ) throw ( ::com::sun::star::uno::RuntimeException )
179 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY );
180 ReleaseDispatch();
183 void SfxUnoControllerItem::ReleaseDispatch()
185 if ( xDispatch.is() )
187 xDispatch->removeStatusListener( (::com::sun::star::frame::XStatusListener*) this, aCommand );
188 xDispatch = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > ();
192 void SfxUnoControllerItem::GetNewDispatch()
194 if ( !pBindings )
196 // Bindings released
197 OSL_FAIL( "Tried to get dispatch, but no Bindings!" );
198 return;
201 // forget old dispatch
202 xDispatch = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > ();
204 // no arms, no cookies !
205 if ( !pBindings->GetDispatcher_Impl() || !pBindings->GetDispatcher_Impl()->GetFrame() )
206 return;
208 SfxFrame& rFrame = pBindings->GetDispatcher_Impl()->GetFrame()->GetFrame();
209 SfxFrame *pParent = rFrame.GetParentFrame();
210 if ( pParent )
211 // parent may intercept
212 xDispatch = TryGetDispatch( pParent );
214 if ( !xDispatch.is() )
216 // no interception
217 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame = rFrame.GetFrameInterface();
218 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv( xFrame, ::com::sun::star::uno::UNO_QUERY );
219 if ( xProv.is() )
220 xDispatch = xProv->queryDispatch( aCommand, OUString(), 0 );
223 if ( xDispatch.is() )
224 xDispatch->addStatusListener( (::com::sun::star::frame::XStatusListener*) this, aCommand );
225 else if ( pCtrlItem )
226 pCtrlItem->StateChanged( pCtrlItem->GetId(), SFX_ITEM_DISABLED, NULL );
229 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > SfxUnoControllerItem::TryGetDispatch( SfxFrame *pFrame )
231 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
232 SfxFrame *pParent = pFrame->GetParentFrame();
233 if ( pParent )
234 // parent may intercept
235 xDisp = TryGetDispatch( pParent );
237 // only components may intercept
238 if ( !xDisp.is() && pFrame->HasComponent() )
240 // no interception
241 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame = pFrame->GetFrameInterface();
242 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv( xFrame, ::com::sun::star::uno::UNO_QUERY );
243 if ( xProv.is() )
244 xDisp = xProv->queryDispatch( aCommand, OUString(), 0 );
247 return xDisp;
250 void SfxUnoControllerItem::ReleaseBindings()
252 // connection to binding is lost; so forget the binding and the dispatch
253 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY );
254 ReleaseDispatch();
255 if ( pBindings )
256 pBindings->ReleaseUnoController_Impl( this );
257 pBindings = NULL;
260 void SfxStatusDispatcher::ReleaseAll()
262 ::com::sun::star::lang::EventObject aObject;
263 aObject.Source = (::cppu::OWeakObject*) this;
264 aListeners.disposeAndClear( aObject );
267 void SAL_CALL SfxStatusDispatcher::dispatch( const ::com::sun::star::util::URL&, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& ) throw ( ::com::sun::star::uno::RuntimeException )
271 void SAL_CALL SfxStatusDispatcher::dispatchWithNotification(
272 const ::com::sun::star::util::URL&,
273 const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >&,
274 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchResultListener >& ) throw( ::com::sun::star::uno::RuntimeException )
278 SfxStatusDispatcher::SfxStatusDispatcher()
279 : aListeners( aMutex )
283 void SAL_CALL SfxStatusDispatcher::addStatusListener(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > & aListener, const ::com::sun::star::util::URL& aURL) throw ( ::com::sun::star::uno::RuntimeException )
285 aListeners.addInterface( aURL.Complete, aListener );
286 if ( aURL.Complete.equalsAscii(".uno:LifeTime") )
288 ::com::sun::star::frame::FeatureStateEvent aEvent;
289 aEvent.FeatureURL = aURL;
290 aEvent.Source = (::com::sun::star::frame::XDispatch*) this;
291 aEvent.IsEnabled = sal_True;
292 aEvent.Requery = sal_False;
293 aListener->statusChanged( aEvent );
297 void SAL_CALL SfxStatusDispatcher::removeStatusListener( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > & aListener, const ::com::sun::star::util::URL& aURL ) throw ( ::com::sun::star::uno::RuntimeException )
299 aListeners.removeInterface( aURL.Complete, aListener );
302 //-------------------------------------------------------------------------
303 // XUnoTunnel
304 sal_Int64 SAL_CALL SfxOfficeDispatch::getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) throw(::com::sun::star::uno::RuntimeException)
306 if ( aIdentifier == impl_getStaticIdentifier() )
307 return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >( this ));
308 else
309 return 0;
312 SfxOfficeDispatch::SfxOfficeDispatch( SfxBindings& rBindings, SfxDispatcher* pDispat, const SfxSlot* pSlot, const ::com::sun::star::util::URL& rURL )
314 // this object is an adapter that shows a ::com::sun::star::frame::XDispatch-Interface to the outside and uses a SfxControllerItem to monitor a state
315 pControllerItem = new SfxDispatchController_Impl( this, &rBindings, pDispat, pSlot, rURL );
318 SfxOfficeDispatch::SfxOfficeDispatch( SfxDispatcher* pDispat, const SfxSlot* pSlot, const ::com::sun::star::util::URL& rURL )
320 // this object is an adapter that shows a ::com::sun::star::frame::XDispatch-Interface to the outside and uses a SfxControllerItem to monitor a state
321 pControllerItem = new SfxDispatchController_Impl( this, NULL, pDispat, pSlot, rURL );
324 SfxOfficeDispatch::~SfxOfficeDispatch()
326 if ( pControllerItem )
328 // when dispatch object is released, destroy its connection to this object and destroy it
329 pControllerItem->UnBindController();
330 delete pControllerItem;
334 const ::com::sun::star::uno::Sequence< sal_Int8 >& SfxOfficeDispatch::impl_getStaticIdentifier()
336 // {38 57 CA 80 09 36 11 d4 83 FE 00 50 04 52 6B 21}
337 static const sal_uInt8 pGUID[16] = { 0x38, 0x57, 0xCA, 0x80, 0x09, 0x36, 0x11, 0xd4, 0x83, 0xFE, 0x00, 0x50, 0x04, 0x52, 0x6B, 0x21 };
338 static ::com::sun::star::uno::Sequence< sal_Int8 > seqID((const sal_Int8*)pGUID,16) ;
339 return seqID ;
343 void SAL_CALL SfxOfficeDispatch::dispatch( const ::com::sun::star::util::URL& aURL, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs ) throw ( ::com::sun::star::uno::RuntimeException )
345 // ControllerItem is the Impl class
346 if ( pControllerItem )
348 #if HAVE_FEATURE_JAVA
349 // The JavaContext contains an interaction handler which is used when
350 // the creation of a Java Virtual Machine fails. The second parameter
351 // indicates, that there shall only be one user notification (message box)
352 // even if the same error (interaction) reoccurs. The effect is, that if a
353 // user selects a menu entry than they may get only one notification that
354 // a JRE is not selected.
355 com::sun::star::uno::ContextLayer layer(
356 new svt::JavaContext( com::sun::star::uno::getCurrentContext(),
357 true) );
358 #endif
359 pControllerItem->dispatch( aURL, aArgs, ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchResultListener >() );
363 void SAL_CALL SfxOfficeDispatch::dispatchWithNotification( const ::com::sun::star::util::URL& aURL,
364 const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs,
365 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchResultListener >& rListener ) throw( ::com::sun::star::uno::RuntimeException )
367 // ControllerItem is the Impl class
368 if ( pControllerItem )
370 #if HAVE_FEATURE_JAVA
371 // see comment for SfxOfficeDispatch::dispatch
372 com::sun::star::uno::ContextLayer layer(
373 new svt::JavaContext( com::sun::star::uno::getCurrentContext(),
374 true) );
375 #endif
376 pControllerItem->dispatch( aURL, aArgs, rListener );
380 void SAL_CALL SfxOfficeDispatch::addStatusListener(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > & aListener, const ::com::sun::star::util::URL& aURL) throw ( ::com::sun::star::uno::RuntimeException )
382 GetListeners().addInterface( aURL.Complete, aListener );
383 if ( pControllerItem )
385 // ControllerItem is the Impl class
386 pControllerItem->addStatusListener( aListener, aURL );
390 SfxDispatcher* SfxOfficeDispatch::GetDispatcher_Impl()
392 return pControllerItem->GetDispatcher();
395 void SfxOfficeDispatch::SetFrame(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame)
397 if ( pControllerItem )
398 pControllerItem->SetFrame( xFrame );
401 void SfxOfficeDispatch::SetMasterUnoCommand( sal_Bool bSet )
403 if ( pControllerItem )
404 pControllerItem->setMasterSlaveCommand( bSet );
407 // Determine if URL contains a master/slave command which must be handled a little bit different
408 sal_Bool SfxOfficeDispatch::IsMasterUnoCommand( const ::com::sun::star::util::URL& aURL )
410 if ( aURL.Protocol == ".uno:" && ( aURL.Path.indexOf( '.' ) > 0 ))
411 return sal_True;
413 return sal_False;
416 OUString SfxOfficeDispatch::GetMasterUnoCommand( const ::com::sun::star::util::URL& aURL )
418 OUString aMasterCommand;
419 if ( IsMasterUnoCommand( aURL ))
421 sal_Int32 nIndex = aURL.Path.indexOf( '.' );
422 if ( nIndex > 0 )
423 aMasterCommand = aURL.Path.copy( 0, nIndex );
426 return aMasterCommand;
429 SfxDispatchController_Impl::SfxDispatchController_Impl(
430 SfxOfficeDispatch* pDisp,
431 SfxBindings* pBind,
432 SfxDispatcher* pDispat,
433 const SfxSlot* pSlot,
434 const ::com::sun::star::util::URL& rURL )
435 : aDispatchURL( rURL )
436 , pDispatcher( pDispat )
437 , pBindings( pBind )
438 , pLastState( 0 )
439 , nSlot( pSlot->GetSlotId() )
440 , pDispatch( pDisp )
441 , bMasterSlave( sal_False )
442 , bVisible( sal_True )
443 , pUnoName( pSlot->pUnoName )
445 if ( aDispatchURL.Protocol == "slot:" && pUnoName )
447 OStringBuffer aTmp(".uno:");
448 aTmp.append(pUnoName);
449 aDispatchURL.Complete = OStringToOUString(aTmp.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US);
450 Reference< XURLTransformer > xTrans( URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
451 xTrans->parseStrict( aDispatchURL );
454 SetId( nSlot );
455 if ( pBindings )
457 // Bind immediately to enable the cache to recycle dispatches when asked for the same command
458 // a command in "slot" or in ".uno" notation must be treated as identical commands!
459 pBindings->ENTERREGISTRATIONS();
460 BindInternal_Impl( nSlot, pBindings );
461 pBindings->LEAVEREGISTRATIONS();
465 SfxDispatchController_Impl::~SfxDispatchController_Impl()
467 if ( pLastState && !IsInvalidItem( pLastState ) )
468 delete pLastState;
470 if ( pDispatch )
472 // disconnect
473 pDispatch->pControllerItem = NULL;
475 // force all listeners to release the dispatch object
476 ::com::sun::star::lang::EventObject aObject;
477 aObject.Source = (::cppu::OWeakObject*) pDispatch;
478 pDispatch->GetListeners().disposeAndClear( aObject );
482 void SfxDispatchController_Impl::SetFrame(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& _xFrame)
484 xFrame = _xFrame;
487 void SfxDispatchController_Impl::setMasterSlaveCommand( sal_Bool bSet )
489 bMasterSlave = bSet;
492 void SfxDispatchController_Impl::UnBindController()
494 pDispatch = NULL;
495 if ( IsBound() )
497 GetBindings().ENTERREGISTRATIONS();
498 SfxControllerItem::UnBind();
499 GetBindings().LEAVEREGISTRATIONS();
503 void SfxDispatchController_Impl::addParametersToArgs( const com::sun::star::util::URL& aURL, ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rArgs ) const
505 // Extract the parameter from the URL and put them into the property value sequence
506 sal_Int32 nQueryIndex = aURL.Complete.indexOf( '?' );
507 if ( nQueryIndex > 0 )
509 OUString aParamString( aURL.Complete.copy( nQueryIndex+1 ));
510 sal_Int32 nIndex = 0;
513 OUString aToken = aParamString.getToken( 0, '&', nIndex );
515 sal_Int32 nParmIndex = 0;
516 OUString aParamType;
517 OUString aParamName = aToken.getToken( 0, '=', nParmIndex );
518 OUString aValue = (nParmIndex!=-1) ? aToken.getToken( 0, '=', nParmIndex ) : OUString();
520 if ( !aParamName.isEmpty() )
522 nParmIndex = 0;
523 aToken = aParamName;
524 aParamName = (nParmIndex!=-1) ? aToken.getToken( 0, ':', nParmIndex ) : OUString();
525 aParamType = (nParmIndex!=-1) ? aToken.getToken( 0, ':', nParmIndex ) : OUString();
528 sal_Int32 nLen = rArgs.getLength();
529 rArgs.realloc( nLen+1 );
530 rArgs[nLen].Name = aParamName;
532 if ( aParamType.isEmpty() )
534 // Default: LONG
535 rArgs[nLen].Value <<= aValue.toInt32();
537 else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_BOOL], 4 ))
539 // sal_Bool support
540 rArgs[nLen].Value <<= aValue.toBoolean();
542 else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_BYTE], 4 ))
544 // sal_uInt8 support
545 rArgs[nLen].Value <<= sal_Int8( aValue.toInt32() );
547 else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_LONG], 4 ))
549 // LONG support
550 rArgs[nLen].Value <<= aValue.toInt32();
552 else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_SHORT], 5 ))
554 // SHORT support
555 rArgs[nLen].Value <<= sal_Int8( aValue.toInt32() );
557 else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_HYPER], 5 ))
559 // HYPER support
560 rArgs[nLen].Value <<= aValue.toInt64();
562 else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_FLOAT], 5 ))
564 // FLOAT support
565 rArgs[nLen].Value <<= aValue.toFloat();
567 else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_STRING], 6 ))
569 // STRING support
570 rArgs[nLen].Value <<= OUString( INetURLObject::decode( aValue, '%', INetURLObject::DECODE_WITH_CHARSET ));
572 else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_DOUBLE], 6))
574 // DOUBLE support
575 rArgs[nLen].Value <<= aValue.toDouble();
578 while ( nIndex >= 0 );
582 SfxMapUnit SfxDispatchController_Impl::GetCoreMetric( SfxItemPool& rPool, sal_uInt16 nSlotId )
584 sal_uInt16 nWhich = rPool.GetWhich( nSlotId );
585 return rPool.GetMetric( nWhich );
588 OUString SfxDispatchController_Impl::getSlaveCommand( const ::com::sun::star::util::URL& rURL )
590 OUString aSlaveCommand;
591 sal_Int32 nIndex = rURL.Path.indexOf( '.' );
592 if (( nIndex > 0 ) && ( nIndex < rURL.Path.getLength() ))
593 aSlaveCommand = rURL.Path.copy( nIndex+1 );
594 return aSlaveCommand;
597 void SAL_CALL SfxDispatchController_Impl::dispatch( const ::com::sun::star::util::URL& aURL,
598 const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs,
599 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchResultListener >& rListener ) throw( ::com::sun::star::uno::RuntimeException )
601 SolarMutexGuard aGuard;
602 if (
603 pDispatch &&
605 (aURL.Protocol == ".uno:" && aURL.Path == aDispatchURL.Path) ||
606 (aURL.Protocol == "slot:" && aURL.Path.toInt32() == GetId())
610 if ( !pDispatcher && pBindings )
611 pDispatcher = GetBindings().GetDispatcher_Impl();
613 ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > lNewArgs;
614 sal_Int32 nCount = aArgs.getLength();
616 // Support for URL based arguments
617 INetURLObject aURLObj( aURL.Complete );
618 if ( aURLObj.HasParam() )
619 addParametersToArgs( aURL, lNewArgs );
621 // Try to find call mode and frame name inside given arguments...
622 SfxCallMode nCall = SFX_CALLMODE_STANDARD;
623 sal_Int32 nMarkArg = -1;
625 // Filter arguments which shouldn't be part of the sequence property value
626 sal_Bool bTemp = sal_Bool();
627 sal_uInt16 nModifier(0);
628 std::vector< ::com::sun::star::beans::PropertyValue > aAddArgs;
629 for( sal_Int32 n=0; n<nCount; n++ )
631 const ::com::sun::star::beans::PropertyValue& rProp = aArgs[n];
632 if( rProp.Name == "SynchronMode" )
634 if( rProp.Value >>=bTemp )
635 nCall = bTemp ? SFX_CALLMODE_SYNCHRON : SFX_CALLMODE_ASYNCHRON;
637 else if( rProp.Name == "Bookmark" )
639 nMarkArg = n;
640 aAddArgs.push_back( aArgs[n] );
642 else if( rProp.Name == "KeyModifier" )
643 rProp.Value >>= nModifier;
644 else
645 aAddArgs.push_back( aArgs[n] );
648 // Add needed arguments to sequence property value
649 sal_uInt32 nAddArgs = aAddArgs.size();
650 if ( nAddArgs > 0 )
652 sal_uInt32 nIndex( lNewArgs.getLength() );
654 lNewArgs.realloc( lNewArgs.getLength()+aAddArgs.size() );
655 for ( sal_uInt32 i = 0; i < nAddArgs; i++ )
656 lNewArgs[nIndex++] = aAddArgs[i];
659 // Overwrite possible detected sychron argument, if real listener exists (currently no other way)
660 if ( rListener.is() )
661 nCall = SFX_CALLMODE_SYNCHRON;
663 if( GetId() == SID_JUMPTOMARK && nMarkArg == - 1 )
665 // we offer dispatches for SID_JUMPTOMARK if the URL points to a bookmark inside the document
666 // so we must retrieve this as an argument from the parsed URL
667 lNewArgs.realloc( lNewArgs.getLength()+1 );
668 nMarkArg = lNewArgs.getLength()-1;
669 lNewArgs[nMarkArg].Name = "Bookmark";
670 lNewArgs[nMarkArg].Value <<= aURL.Mark;
673 css::uno::Reference< css::frame::XFrame > xFrameRef(xFrame.get(), css::uno::UNO_QUERY);
674 if (! xFrameRef.is() && pDispatcher)
676 SfxViewFrame* pViewFrame = pDispatcher->GetFrame();
677 if (pViewFrame)
678 xFrameRef = pViewFrame->GetFrame().GetFrameInterface();
681 sal_Bool bSuccess = sal_False;
682 const SfxPoolItem* pItem = NULL;
683 SfxMapUnit eMapUnit( SFX_MAPUNIT_100TH_MM );
685 // Extra scope so that aInternalSet is destroyed before
686 // rListener->dispatchFinished potentially calls
687 // framework::Desktop::terminate -> SfxApplication::Deinitialize ->
688 // ~CntItemPool:
690 SfxAllItemSet aInternalSet( SFX_APP()->GetPool() );
691 if (xFrameRef.is()) // an empty set is no problem ... but an empty frame reference can be a problem !
692 aInternalSet.Put( SfxUnoFrameItem( SID_FILLFRAME, xFrameRef ) );
694 SfxShell* pShell( 0 );
695 // #i102619# Retrieve metric from shell before execution - the shell could be destroyed after execution
696 if ( pDispatcher->GetBindings() )
698 if ( !pDispatcher->IsLocked( GetId() ) )
700 const SfxSlot *pSlot = 0;
701 if ( pDispatcher->GetShellAndSlot_Impl( GetId(), &pShell, &pSlot, sal_False,
702 SFX_CALLMODE_MODAL==(nCall&SFX_CALLMODE_MODAL), sal_False ) )
704 if ( bMasterSlave )
706 // Extract slave command and add argument to the args list. Master slot MUST
707 // have a argument that has the same name as the master slot and type is SfxStringItem.
708 sal_Int32 nIndex = lNewArgs.getLength();
709 lNewArgs.realloc( nIndex+1 );
710 lNewArgs[nIndex].Name = OUString::createFromAscii( pSlot->pUnoName );
711 lNewArgs[nIndex].Value = makeAny( SfxDispatchController_Impl::getSlaveCommand( aDispatchURL ));
714 eMapUnit = GetCoreMetric( pShell->GetPool(), GetId() );
715 boost::scoped_ptr<SfxAllItemSet> xSet(new SfxAllItemSet(pShell->GetPool()));
716 TransformParameters(GetId(), lNewArgs, *xSet, pSlot);
717 if (xSet->Count())
719 // execute with arguments - call directly
720 pItem = pDispatcher->Execute(GetId(), nCall, xSet.get(), &aInternalSet, nModifier);
721 bSuccess = (pItem != NULL);
723 else
725 // Be sure to delete this before we send a dispatch
726 // request, which will destroy the current shell.
727 xSet.reset();
729 // execute using bindings, enables support for toggle/enum etc.
730 SfxRequest aReq( GetId(), nCall, pShell->GetPool() );
731 aReq.SetModifier( nModifier );
732 aReq.SetInternalArgs_Impl(aInternalSet);
733 pDispatcher->GetBindings()->Execute_Impl( aReq, pSlot, pShell );
734 pItem = aReq.GetReturnValue();
735 bSuccess = aReq.IsDone() || pItem != NULL;
738 #ifdef DBG_UTIL
739 else
740 DBG_WARNING("MacroPlayer: Unknown slot dispatched!");
741 #endif
744 else
746 eMapUnit = GetCoreMetric( SFX_APP()->GetPool(), GetId() );
747 // AppDispatcher
748 SfxAllItemSet aSet( SFX_APP()->GetPool() );
749 TransformParameters( GetId(), lNewArgs, aSet );
751 if ( aSet.Count() )
752 pItem = pDispatcher->Execute( GetId(), nCall, &aSet, &aInternalSet, nModifier );
753 else
754 // SfxRequests take empty sets as argument sets, GetArgs() returning non-zero!
755 pItem = pDispatcher->Execute( GetId(), nCall, 0, &aInternalSet, nModifier );
757 // no bindings, no invalidate ( usually done in SfxDispatcher::Call_Impl()! )
758 if ( SfxApplication::Get() )
760 SfxDispatcher* pAppDispat = SFX_APP()->GetAppDispatcher_Impl();
761 if ( pAppDispat )
763 const SfxPoolItem* pState=0;
764 SfxItemState eState = pDispatcher->QueryState( GetId(), pState );
765 StateChanged( GetId(), eState, pState );
769 bSuccess = (pItem != NULL);
773 if ( rListener.is() )
775 ::com::sun::star::frame::DispatchResultEvent aEvent;
776 if ( bSuccess )
777 aEvent.State = com::sun::star::frame::DispatchResultState::SUCCESS;
778 else
779 aEvent.State = com::sun::star::frame::DispatchResultState::FAILURE;
781 aEvent.Source = (::com::sun::star::frame::XDispatch*) pDispatch;
782 if ( bSuccess && pItem && !pItem->ISA(SfxVoidItem) )
784 sal_uInt16 nSubId( 0 );
785 if ( eMapUnit == SFX_MAPUNIT_TWIP )
786 nSubId |= CONVERT_TWIPS;
787 pItem->QueryValue( aEvent.Result, (sal_uInt8)nSubId );
790 rListener->dispatchFinished( aEvent );
795 SfxDispatcher* SfxDispatchController_Impl::GetDispatcher()
797 if ( !pDispatcher && pBindings )
798 pDispatcher = GetBindings().GetDispatcher_Impl();
799 return pDispatcher;
802 void SAL_CALL SfxDispatchController_Impl::addStatusListener(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > & aListener, const ::com::sun::star::util::URL& aURL) throw ( ::com::sun::star::uno::RuntimeException )
804 SolarMutexGuard aGuard;
805 if ( !pDispatch )
806 return;
808 // Use alternative QueryState call to have a valid UNO representation of the state.
809 ::com::sun::star::uno::Any aState;
810 if ( !pDispatcher && pBindings )
811 pDispatcher = GetBindings().GetDispatcher_Impl();
812 SfxItemState eState = pDispatcher->QueryState( GetId(), aState );
814 if ( eState == SFX_ITEM_DONTCARE )
816 // Use special uno struct to transport don't care state
817 ::com::sun::star::frame::status::ItemStatus aItemStatus;
818 aItemStatus.State = ::com::sun::star::frame::status::ItemState::dont_care;
819 aState = makeAny( aItemStatus );
822 ::com::sun::star::frame::FeatureStateEvent aEvent;
823 aEvent.FeatureURL = aURL;
824 aEvent.Source = (::com::sun::star::frame::XDispatch*) pDispatch;
825 aEvent.Requery = sal_False;
826 if ( bVisible )
828 aEvent.IsEnabled = eState != SFX_ITEM_DISABLED;
829 aEvent.State = aState;
831 else
833 ::com::sun::star::frame::status::Visibility aVisibilityStatus;
834 aVisibilityStatus.bVisible = sal_False;
836 // MBA: we might decide to *not* disable "invisible" slots, but this would be
837 // a change that needs to adjust at least the testtool
838 aEvent.IsEnabled = sal_False;
839 aEvent.State = makeAny( aVisibilityStatus );
842 aListener->statusChanged( aEvent );
845 void SfxDispatchController_Impl::StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState, SfxSlotServer* pSlotServ )
847 if ( !pDispatch )
848 return;
850 // Bindings instance notifies controller about a state change, listeners must be notified also
851 // Don't cache visibility state changes as they are volatile. We need our real state to send it
852 // to our controllers after visibility is set to true.
853 sal_Bool bNotify = sal_True;
854 if ( pState && !IsInvalidItem( pState ) )
856 if ( !pState->ISA( SfxVisibilityItem ) )
858 sal_Bool bBothAvailable = pLastState && !IsInvalidItem(pLastState);
859 if ( bBothAvailable )
860 bNotify = pState->Type() != pLastState->Type() || *pState != *pLastState;
861 if ( pLastState && !IsInvalidItem( pLastState ) )
862 delete pLastState;
863 pLastState = !IsInvalidItem(pState) ? pState->Clone() : pState;
864 bVisible = sal_True;
866 else
867 bVisible = ((SfxVisibilityItem *)pState)->GetValue();
869 else
871 if ( pLastState && !IsInvalidItem( pLastState ) )
872 delete pLastState;
873 pLastState = pState;
876 ::cppu::OInterfaceContainerHelper* pContnr = pDispatch->GetListeners().getContainer ( aDispatchURL.Complete );
877 if ( bNotify && pContnr )
879 ::com::sun::star::uno::Any aState;
880 if ( ( eState >= SFX_ITEM_AVAILABLE ) && pState && !IsInvalidItem( pState ) && !pState->ISA(SfxVoidItem) )
882 // Retrieve metric from pool to have correct sub ID when calling QueryValue
883 sal_uInt16 nSubId( 0 );
884 SfxMapUnit eMapUnit( SFX_MAPUNIT_100TH_MM );
886 // retrieve the core metric
887 // it's enough to check the objectshell, the only shell that does not use the pool of the document
888 // is SfxViewFrame, but it hasn't any metric parameters
889 // TODO/LATER: what about the FormShell? Does it use any metric data?! Perhaps it should use the Pool of the document!
890 if ( pSlotServ && pDispatcher )
892 SfxShell* pShell = pDispatcher->GetShell( pSlotServ->GetShellLevel() );
893 DBG_ASSERT( pShell, "Can't get core metric without shell!" );
894 if ( pShell )
895 eMapUnit = GetCoreMetric( pShell->GetPool(), nSID );
898 if ( eMapUnit == SFX_MAPUNIT_TWIP )
899 nSubId |= CONVERT_TWIPS;
901 pState->QueryValue( aState, (sal_uInt8)nSubId );
903 else if ( eState == SFX_ITEM_DONTCARE )
905 // Use special uno struct to transport don't care state
906 ::com::sun::star::frame::status::ItemStatus aItemStatus;
907 aItemStatus.State = ::com::sun::star::frame::status::ItemState::dont_care;
908 aState = makeAny( aItemStatus );
911 ::com::sun::star::frame::FeatureStateEvent aEvent;
912 aEvent.FeatureURL = aDispatchURL;
913 aEvent.Source = (::com::sun::star::frame::XDispatch*) pDispatch;
914 aEvent.IsEnabled = eState != SFX_ITEM_DISABLED;
915 aEvent.Requery = sal_False;
916 aEvent.State = aState;
918 ::cppu::OInterfaceIteratorHelper aIt( *pContnr );
919 while( aIt.hasMoreElements() )
923 ((::com::sun::star::frame::XStatusListener *)aIt.next())->statusChanged( aEvent );
925 catch (const ::com::sun::star::uno::RuntimeException&)
927 aIt.remove();
933 void SfxDispatchController_Impl::StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState )
935 StateChanged( nSID, eState, pState, 0 );
938 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */