Bump version to 4.1-6
[LibreOffice.git] / sfx2 / source / control / unoctitm.cxx
blob9f30889f93109464b4c286fb923239e5098f9f17
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 #include <tools/debug.hxx>
22 #include <svl/eitem.hxx>
23 #include <svl/stritem.hxx>
24 #include <svl/intitem.hxx>
25 #include <svl/itemset.hxx>
26 #include <svl/visitem.hxx>
27 #include <svtools/javacontext.hxx>
28 #include <svl/itempool.hxx>
29 #include <tools/urlobj.hxx>
30 #include <com/sun/star/util/URLTransformer.hpp>
31 #include <com/sun/star/util/XURLTransformer.hpp>
32 #include <com/sun/star/frame/XController.hpp>
33 #include <com/sun/star/frame/XFrameActionListener.hpp>
34 #include <com/sun/star/frame/XComponentLoader.hpp>
35 #include <com/sun/star/frame/XFrame.hpp>
36 #include <com/sun/star/frame/FrameActionEvent.hpp>
37 #include <com/sun/star/frame/FrameAction.hpp>
38 #include <com/sun/star/frame/status/ItemStatus.hpp>
39 #include <com/sun/star/frame/status/ItemState.hpp>
40 #include <com/sun/star/frame/DispatchResultState.hpp>
41 #include <com/sun/star/frame/status/Visibility.hpp>
42 #include <comphelper/processfactory.hxx>
43 #include <comphelper/sequence.hxx>
44 #include <osl/mutex.hxx>
45 #include <uno/current_context.hxx>
46 #include <vcl/svapp.hxx>
48 #include <sfx2/app.hxx>
49 #include <sfx2/unoctitm.hxx>
50 #include <sfx2/viewfrm.hxx>
51 #include <sfx2/frame.hxx>
52 #include <sfx2/ctrlitem.hxx>
53 #include <sfx2/sfxuno.hxx>
54 #include <sfx2/bindings.hxx>
55 #include <sfx2/dispatch.hxx>
56 #include <sfx2/sfxsids.hrc>
57 #include <sfx2/request.hxx>
58 #include "statcach.hxx"
59 #include <sfx2/msgpool.hxx>
60 #include <sfx2/objsh.hxx>
62 #include <boost/scoped_ptr.hpp>
64 using namespace ::com::sun::star::uno;
65 using namespace ::com::sun::star::util;
67 enum URLTypeId
69 URLType_BOOL,
70 URLType_BYTE,
71 URLType_SHORT,
72 URLType_LONG,
73 URLType_HYPER,
74 URLType_STRING,
75 URLType_FLOAT,
76 URLType_DOUBLE,
77 URLType_COUNT
80 const char* URLTypeNames[URLType_COUNT] =
82 "bool",
83 "byte",
84 "short",
85 "long",
86 "hyper",
87 "string",
88 "float",
89 "double"
92 SFX_IMPL_XINTERFACE_2( SfxUnoControllerItem, OWeakObject, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener )
93 SFX_IMPL_XTYPEPROVIDER_2( SfxUnoControllerItem, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener )
95 SfxUnoControllerItem::SfxUnoControllerItem( SfxControllerItem *pItem, SfxBindings& rBind, const String& rCmd )
96 : pCtrlItem( pItem )
97 , pBindings( &rBind )
99 DBG_ASSERT( !pCtrlItem || !pCtrlItem->IsBound(), "ControllerItem is incorrect!" );
101 aCommand.Complete = rCmd;
102 Reference< XURLTransformer > xTrans( URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
103 xTrans->parseStrict( aCommand );
104 pBindings->RegisterUnoController_Impl( this );
107 SfxUnoControllerItem::~SfxUnoControllerItem()
109 // tell bindings to forget this controller ( if still connected )
110 if ( pBindings )
111 pBindings->ReleaseUnoController_Impl( this );
114 void SfxUnoControllerItem::UnBind()
116 // connection to SfxControllerItem is lost
117 pCtrlItem = NULL;
118 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY );
119 ReleaseDispatch();
122 void SAL_CALL SfxUnoControllerItem::statusChanged(const ::com::sun::star::frame::FeatureStateEvent& rEvent) throw ( ::com::sun::star::uno::RuntimeException )
124 SolarMutexGuard aGuard;
125 DBG_ASSERT( pCtrlItem, "dispatch implementation didn't respect our previous removeStatusListener call!" );
127 if ( rEvent.Requery )
129 // Error can only happen if the old Dispatch is implemented incorrectly
130 // i.e. removeStatusListener did not work. But such things can happen...
131 // So protect before ReleaseDispatch from release!
132 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY );
133 ReleaseDispatch();
134 if ( pCtrlItem )
135 GetNewDispatch(); // asynchronous ??
137 else if ( pCtrlItem )
139 SfxItemState eState = SFX_ITEM_DISABLED;
140 SfxPoolItem* pItem = NULL;
141 if ( rEvent.IsEnabled )
143 eState = SFX_ITEM_AVAILABLE;
144 ::com::sun::star::uno::Type pType = rEvent.State.getValueType();
146 if ( pType == ::getBooleanCppuType() )
148 sal_Bool bTemp = false;
149 rEvent.State >>= bTemp ;
150 pItem = new SfxBoolItem( pCtrlItem->GetId(), bTemp );
152 else if ( pType == ::getCppuType((const sal_uInt16*)0) )
154 sal_uInt16 nTemp = 0;
155 rEvent.State >>= nTemp ;
156 pItem = new SfxUInt16Item( pCtrlItem->GetId(), nTemp );
158 else if ( pType == ::getCppuType((const sal_uInt32*)0) )
160 sal_uInt32 nTemp = 0;
161 rEvent.State >>= nTemp ;
162 pItem = new SfxUInt32Item( pCtrlItem->GetId(), nTemp );
164 else if ( pType == ::getCppuType((const OUString*)0) )
166 OUString sTemp ;
167 rEvent.State >>= sTemp ;
168 pItem = new SfxStringItem( pCtrlItem->GetId(), sTemp );
170 else
171 pItem = new SfxVoidItem( pCtrlItem->GetId() );
174 pCtrlItem->StateChanged( pCtrlItem->GetId(), eState, pItem );
175 delete pItem;
179 void SAL_CALL SfxUnoControllerItem::disposing( const ::com::sun::star::lang::EventObject& ) throw ( ::com::sun::star::uno::RuntimeException )
181 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY );
182 ReleaseDispatch();
185 void SfxUnoControllerItem::ReleaseDispatch()
187 if ( xDispatch.is() )
189 xDispatch->removeStatusListener( (::com::sun::star::frame::XStatusListener*) this, aCommand );
190 xDispatch = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > ();
194 void SfxUnoControllerItem::GetNewDispatch()
196 if ( !pBindings )
198 // Bindings released
199 OSL_FAIL( "Tried to get dispatch, but no Bindings!" );
200 return;
203 // forget old dispatch
204 xDispatch = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > ();
206 // no arms, no cookies !
207 if ( !pBindings->GetDispatcher_Impl() || !pBindings->GetDispatcher_Impl()->GetFrame() )
208 return;
210 SfxFrame& rFrame = pBindings->GetDispatcher_Impl()->GetFrame()->GetFrame();
211 SfxFrame *pParent = rFrame.GetParentFrame();
212 if ( pParent )
213 // parent may intercept
214 xDispatch = TryGetDispatch( pParent );
216 if ( !xDispatch.is() )
218 // no interception
219 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame = rFrame.GetFrameInterface();
220 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv( xFrame, ::com::sun::star::uno::UNO_QUERY );
221 if ( xProv.is() )
222 xDispatch = xProv->queryDispatch( aCommand, OUString(), 0 );
225 if ( xDispatch.is() )
226 xDispatch->addStatusListener( (::com::sun::star::frame::XStatusListener*) this, aCommand );
227 else if ( pCtrlItem )
228 pCtrlItem->StateChanged( pCtrlItem->GetId(), SFX_ITEM_DISABLED, NULL );
231 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > SfxUnoControllerItem::TryGetDispatch( SfxFrame *pFrame )
233 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
234 SfxFrame *pParent = pFrame->GetParentFrame();
235 if ( pParent )
236 // parent may intercept
237 xDisp = TryGetDispatch( pParent );
239 // only components may intercept
240 if ( !xDisp.is() && pFrame->HasComponent() )
242 // no interception
243 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame = pFrame->GetFrameInterface();
244 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv( xFrame, ::com::sun::star::uno::UNO_QUERY );
245 if ( xProv.is() )
246 xDisp = xProv->queryDispatch( aCommand, OUString(), 0 );
249 return xDisp;
252 void SfxUnoControllerItem::ReleaseBindings()
254 // connection to binding is lost; so forget the binding and the dispatch
255 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY );
256 ReleaseDispatch();
257 if ( pBindings )
258 pBindings->ReleaseUnoController_Impl( this );
259 pBindings = NULL;
262 void SfxStatusDispatcher::ReleaseAll()
264 ::com::sun::star::lang::EventObject aObject;
265 aObject.Source = (::cppu::OWeakObject*) this;
266 aListeners.disposeAndClear( aObject );
269 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 )
273 void SAL_CALL SfxStatusDispatcher::dispatchWithNotification(
274 const ::com::sun::star::util::URL&,
275 const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >&,
276 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchResultListener >& ) throw( ::com::sun::star::uno::RuntimeException )
280 SFX_IMPL_XINTERFACE_2( SfxStatusDispatcher, OWeakObject, ::com::sun::star::frame::XNotifyingDispatch, ::com::sun::star::frame::XDispatch )
281 SFX_IMPL_XTYPEPROVIDER_2( SfxStatusDispatcher, ::com::sun::star::frame::XNotifyingDispatch, ::com::sun::star::frame::XDispatch )
282 //IMPLNAME "com.sun.star.comp.sfx2.StatusDispatcher",
284 SfxStatusDispatcher::SfxStatusDispatcher()
285 : aListeners( aMutex )
289 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 )
291 aListeners.addInterface( aURL.Complete, aListener );
292 if ( aURL.Complete.compareToAscii(".uno:LifeTime")==0 )
294 ::com::sun::star::frame::FeatureStateEvent aEvent;
295 aEvent.FeatureURL = aURL;
296 aEvent.Source = (::com::sun::star::frame::XDispatch*) this;
297 aEvent.IsEnabled = sal_True;
298 aEvent.Requery = sal_False;
299 aListener->statusChanged( aEvent );
303 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 )
305 aListeners.removeInterface( aURL.Complete, aListener );
308 SFX_IMPL_XINTERFACE_1( SfxOfficeDispatch, SfxStatusDispatcher, ::com::sun::star::lang::XUnoTunnel )
309 SFX_IMPL_XTYPEPROVIDER_2( SfxOfficeDispatch, ::com::sun::star::frame::XNotifyingDispatch, ::com::sun::star::lang::XUnoTunnel )
312 //-------------------------------------------------------------------------
313 // XUnoTunnel
314 sal_Int64 SAL_CALL SfxOfficeDispatch::getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) throw(::com::sun::star::uno::RuntimeException)
316 if ( aIdentifier == impl_getStaticIdentifier() )
317 return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >( this ));
318 else
319 return 0;
322 SfxOfficeDispatch::SfxOfficeDispatch( SfxBindings& rBindings, SfxDispatcher* pDispat, const SfxSlot* pSlot, const ::com::sun::star::util::URL& rURL )
324 // 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
325 pControllerItem = new SfxDispatchController_Impl( this, &rBindings, pDispat, pSlot, rURL );
328 SfxOfficeDispatch::SfxOfficeDispatch( SfxDispatcher* pDispat, const SfxSlot* pSlot, const ::com::sun::star::util::URL& rURL )
330 // 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
331 pControllerItem = new SfxDispatchController_Impl( this, NULL, pDispat, pSlot, rURL );
334 SfxOfficeDispatch::~SfxOfficeDispatch()
336 if ( pControllerItem )
338 // when dispatch object is released, destroy its connection to this object and destroy it
339 pControllerItem->UnBindController();
340 delete pControllerItem;
344 const ::com::sun::star::uno::Sequence< sal_Int8 >& SfxOfficeDispatch::impl_getStaticIdentifier()
346 // {38 57 CA 80 09 36 11 d4 83 FE 00 50 04 52 6B 21}
347 static sal_uInt8 pGUID[16] = { 0x38, 0x57, 0xCA, 0x80, 0x09, 0x36, 0x11, 0xd4, 0x83, 0xFE, 0x00, 0x50, 0x04, 0x52, 0x6B, 0x21 };
348 static ::com::sun::star::uno::Sequence< sal_Int8 > seqID((sal_Int8*)pGUID,16) ;
349 return seqID ;
353 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 )
355 // ControllerItem is the Impl class
356 if ( pControllerItem )
358 #ifdef SOLAR_JAVA
359 // The JavaContext contains an interaction handler which is used when
360 // the creation of a Java Virtual Machine fails. The second parameter
361 // indicates, that there shall only be one user notification (message box)
362 // even if the same error (interaction) reoccurs. The effect is, that if a
363 // user selects a menu entry than they may get only one notification that
364 // a JRE is not selected.
365 com::sun::star::uno::ContextLayer layer(
366 new svt::JavaContext( com::sun::star::uno::getCurrentContext(),
367 true) );
368 #endif
369 pControllerItem->dispatch( aURL, aArgs, ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchResultListener >() );
373 void SAL_CALL SfxOfficeDispatch::dispatchWithNotification( const ::com::sun::star::util::URL& aURL,
374 const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs,
375 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchResultListener >& rListener ) throw( ::com::sun::star::uno::RuntimeException )
377 // ControllerItem is the Impl class
378 if ( pControllerItem )
380 #ifdef SOLAR_JAVA
381 // see comment for SfxOfficeDispatch::dispatch
382 com::sun::star::uno::ContextLayer layer(
383 new svt::JavaContext( com::sun::star::uno::getCurrentContext(),
384 true) );
385 #endif
386 pControllerItem->dispatch( aURL, aArgs, rListener );
390 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 )
392 GetListeners().addInterface( aURL.Complete, aListener );
393 if ( pControllerItem )
395 // ControllerItem is the Impl class
396 pControllerItem->addStatusListener( aListener, aURL );
400 SfxDispatcher* SfxOfficeDispatch::GetDispatcher_Impl()
402 return pControllerItem->GetDispatcher();
405 void SfxOfficeDispatch::SetFrame(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame)
407 if ( pControllerItem )
408 pControllerItem->SetFrame( xFrame );
411 void SfxOfficeDispatch::SetMasterUnoCommand( sal_Bool bSet )
413 if ( pControllerItem )
414 pControllerItem->setMasterSlaveCommand( bSet );
417 // Determine if URL contains a master/slave command which must be handled a little bit different
418 sal_Bool SfxOfficeDispatch::IsMasterUnoCommand( const ::com::sun::star::util::URL& aURL )
420 if ( aURL.Protocol == ".uno:" && ( aURL.Path.indexOf( '.' ) > 0 ))
421 return sal_True;
423 return sal_False;
426 OUString SfxOfficeDispatch::GetMasterUnoCommand( const ::com::sun::star::util::URL& aURL )
428 OUString aMasterCommand;
429 if ( IsMasterUnoCommand( aURL ))
431 sal_Int32 nIndex = aURL.Path.indexOf( '.' );
432 if ( nIndex > 0 )
433 aMasterCommand = aURL.Path.copy( 0, nIndex );
436 return aMasterCommand;
439 SfxDispatchController_Impl::SfxDispatchController_Impl(
440 SfxOfficeDispatch* pDisp,
441 SfxBindings* pBind,
442 SfxDispatcher* pDispat,
443 const SfxSlot* pSlot,
444 const ::com::sun::star::util::URL& rURL )
445 : aDispatchURL( rURL )
446 , pDispatcher( pDispat )
447 , pBindings( pBind )
448 , pLastState( 0 )
449 , nSlot( pSlot->GetSlotId() )
450 , pDispatch( pDisp )
451 , bMasterSlave( sal_False )
452 , bVisible( sal_True )
453 , pUnoName( pSlot->pUnoName )
455 if ( aDispatchURL.Protocol == "slot:" && pUnoName )
457 OStringBuffer aTmp(RTL_CONSTASCII_STRINGPARAM(".uno:"));
458 aTmp.append(pUnoName);
459 aDispatchURL.Complete = OStringToOUString(aTmp.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US);
460 Reference< XURLTransformer > xTrans( URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
461 xTrans->parseStrict( aDispatchURL );
464 SetId( nSlot );
465 if ( pBindings )
467 // Bind immediately to enable the cache to recycle dispatches when asked for the same command
468 // a command in "slot" or in ".uno" notation must be treated as identical commands!
469 pBindings->ENTERREGISTRATIONS();
470 BindInternal_Impl( nSlot, pBindings );
471 pBindings->LEAVEREGISTRATIONS();
475 SfxDispatchController_Impl::~SfxDispatchController_Impl()
477 if ( pLastState && !IsInvalidItem( pLastState ) )
478 delete pLastState;
480 if ( pDispatch )
482 // disconnect
483 pDispatch->pControllerItem = NULL;
485 // force all listeners to release the dispatch object
486 ::com::sun::star::lang::EventObject aObject;
487 aObject.Source = (::cppu::OWeakObject*) pDispatch;
488 pDispatch->GetListeners().disposeAndClear( aObject );
492 void SfxDispatchController_Impl::SetFrame(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& _xFrame)
494 xFrame = _xFrame;
497 void SfxDispatchController_Impl::setMasterSlaveCommand( sal_Bool bSet )
499 bMasterSlave = bSet;
502 void SfxDispatchController_Impl::UnBindController()
504 pDispatch = NULL;
505 if ( IsBound() )
507 GetBindings().ENTERREGISTRATIONS();
508 SfxControllerItem::UnBind();
509 GetBindings().LEAVEREGISTRATIONS();
513 void SfxDispatchController_Impl::addParametersToArgs( const com::sun::star::util::URL& aURL, ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rArgs ) const
515 // Extract the parameter from the URL and put them into the property value sequence
516 sal_Int32 nQueryIndex = aURL.Complete.indexOf( '?' );
517 if ( nQueryIndex > 0 )
519 OUString aParamString( aURL.Complete.copy( nQueryIndex+1 ));
520 sal_Int32 nIndex = 0;
523 OUString aToken = aParamString.getToken( 0, '&', nIndex );
525 sal_Int32 nParmIndex = 0;
526 OUString aParamType;
527 OUString aParamName = aToken.getToken( 0, '=', nParmIndex );
528 OUString aValue = (nParmIndex!=-1) ? aToken.getToken( 0, '=', nParmIndex ) : OUString();
530 if ( !aParamName.isEmpty() )
532 nParmIndex = 0;
533 aToken = aParamName;
534 aParamName = (nParmIndex!=-1) ? aToken.getToken( 0, ':', nParmIndex ) : OUString();
535 aParamType = (nParmIndex!=-1) ? aToken.getToken( 0, ':', nParmIndex ) : OUString();
538 sal_Int32 nLen = rArgs.getLength();
539 rArgs.realloc( nLen+1 );
540 rArgs[nLen].Name = aParamName;
542 if ( aParamType.isEmpty() )
544 // Default: LONG
545 rArgs[nLen].Value <<= aValue.toInt32();
547 else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_BOOL], 4 ))
549 // sal_Bool support
550 rArgs[nLen].Value <<= aValue.toBoolean();
552 else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_BYTE], 4 ))
554 // sal_uInt8 support
555 rArgs[nLen].Value <<= sal_Int8( aValue.toInt32() );
557 else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_LONG], 4 ))
559 // LONG support
560 rArgs[nLen].Value <<= aValue.toInt32();
562 else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_SHORT], 5 ))
564 // SHORT support
565 rArgs[nLen].Value <<= sal_Int8( aValue.toInt32() );
567 else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_HYPER], 5 ))
569 // HYPER support
570 rArgs[nLen].Value <<= aValue.toInt64();
572 else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_FLOAT], 5 ))
574 // FLOAT support
575 rArgs[nLen].Value <<= aValue.toFloat();
577 else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_STRING], 6 ))
579 // STRING support
580 rArgs[nLen].Value <<= OUString( INetURLObject::decode( aValue, '%', INetURLObject::DECODE_WITH_CHARSET ));
582 else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_DOUBLE], 6))
584 // DOUBLE support
585 rArgs[nLen].Value <<= aValue.toDouble();
588 while ( nIndex >= 0 );
592 SfxMapUnit SfxDispatchController_Impl::GetCoreMetric( SfxItemPool& rPool, sal_uInt16 nSlotId )
594 sal_uInt16 nWhich = rPool.GetWhich( nSlotId );
595 return rPool.GetMetric( nWhich );
598 OUString SfxDispatchController_Impl::getSlaveCommand( const ::com::sun::star::util::URL& rURL )
600 OUString aSlaveCommand;
601 sal_Int32 nIndex = rURL.Path.indexOf( '.' );
602 if (( nIndex > 0 ) && ( nIndex < rURL.Path.getLength() ))
603 aSlaveCommand = rURL.Path.copy( nIndex+1 );
604 return aSlaveCommand;
607 void SAL_CALL SfxDispatchController_Impl::dispatch( const ::com::sun::star::util::URL& aURL,
608 const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs,
609 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchResultListener >& rListener ) throw( ::com::sun::star::uno::RuntimeException )
611 SolarMutexGuard aGuard;
612 if (
613 pDispatch &&
615 (aURL.Protocol.equalsAsciiL( ".uno:", 5 ) && aURL.Path == aDispatchURL.Path) ||
616 (aURL.Protocol.equalsAsciiL( "slot:", 5 ) && aURL.Path.toInt32() == GetId())
620 if ( !pDispatcher && pBindings )
621 pDispatcher = GetBindings().GetDispatcher_Impl();
623 ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > lNewArgs;
624 sal_Int32 nCount = aArgs.getLength();
626 // Support for URL based arguments
627 INetURLObject aURLObj( aURL.Complete );
628 if ( aURLObj.HasParam() )
629 addParametersToArgs( aURL, lNewArgs );
631 // Try to find call mode and frame name inside given arguments...
632 SfxCallMode nCall = SFX_CALLMODE_STANDARD;
633 sal_Int32 nMarkArg = -1;
635 // Filter arguments which shouldn't be part of the sequence property value
636 sal_Bool bTemp = sal_Bool();
637 sal_uInt16 nModifier(0);
638 std::vector< ::com::sun::star::beans::PropertyValue > aAddArgs;
639 for( sal_Int32 n=0; n<nCount; n++ )
641 const ::com::sun::star::beans::PropertyValue& rProp = aArgs[n];
642 if( rProp.Name.equalsAsciiL("SynchronMode",12))
644 if( rProp.Value >>=bTemp )
645 nCall = bTemp ? SFX_CALLMODE_SYNCHRON : SFX_CALLMODE_ASYNCHRON;
647 else if( rProp.Name.equalsAsciiL("Bookmark",8))
649 nMarkArg = n;
650 aAddArgs.push_back( aArgs[n] );
652 else if( rProp.Name.equalsAsciiL("KeyModifier",11))
653 rProp.Value >>= nModifier;
654 else
655 aAddArgs.push_back( aArgs[n] );
658 // Add needed arguments to sequence property value
659 sal_uInt32 nAddArgs = aAddArgs.size();
660 if ( nAddArgs > 0 )
662 sal_uInt32 nIndex( lNewArgs.getLength() );
664 lNewArgs.realloc( lNewArgs.getLength()+aAddArgs.size() );
665 for ( sal_uInt32 i = 0; i < nAddArgs; i++ )
666 lNewArgs[nIndex++] = aAddArgs[i];
669 // Overwrite possible detected sychron argument, if real listener exists (currently no other way)
670 if ( rListener.is() )
671 nCall = SFX_CALLMODE_SYNCHRON;
673 if( GetId() == SID_JUMPTOMARK && nMarkArg == - 1 )
675 // we offer dispatches for SID_JUMPTOMARK if the URL points to a bookmark inside the document
676 // so we must retrieve this as an argument from the parsed URL
677 lNewArgs.realloc( lNewArgs.getLength()+1 );
678 nMarkArg = lNewArgs.getLength()-1;
679 lNewArgs[nMarkArg].Name = OUString("Bookmark");
680 lNewArgs[nMarkArg].Value <<= aURL.Mark;
683 css::uno::Reference< css::frame::XFrame > xFrameRef(xFrame.get(), css::uno::UNO_QUERY);
684 if (! xFrameRef.is() && pDispatcher)
686 SfxViewFrame* pViewFrame = pDispatcher->GetFrame();
687 if (pViewFrame)
688 xFrameRef = pViewFrame->GetFrame().GetFrameInterface();
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 sal_Bool bSuccess = sal_False;
695 const SfxPoolItem* pItem = NULL;
696 SfxShell* pShell( 0 );
697 // #i102619# Retrieve metric from shell before execution - the shell could be destroyed after execution
698 SfxMapUnit eMapUnit( SFX_MAPUNIT_100TH_MM );
699 if ( pDispatcher->GetBindings() )
701 if ( !pDispatcher->IsLocked( GetId() ) )
703 const SfxSlot *pSlot = 0;
704 if ( pDispatcher->GetShellAndSlot_Impl( GetId(), &pShell, &pSlot, sal_False,
705 SFX_CALLMODE_MODAL==(nCall&SFX_CALLMODE_MODAL), sal_False ) )
707 if ( bMasterSlave )
709 // Extract slave command and add argument to the args list. Master slot MUST
710 // have a argument that has the same name as the master slot and type is SfxStringItem.
711 sal_Int32 nIndex = lNewArgs.getLength();
712 lNewArgs.realloc( nIndex+1 );
713 lNewArgs[nIndex].Name = OUString::createFromAscii( pSlot->pUnoName );
714 lNewArgs[nIndex].Value = makeAny( SfxDispatchController_Impl::getSlaveCommand( aDispatchURL ));
717 eMapUnit = GetCoreMetric( pShell->GetPool(), GetId() );
718 boost::scoped_ptr<SfxAllItemSet> xSet(new SfxAllItemSet(pShell->GetPool()));
719 TransformParameters(GetId(), lNewArgs, *xSet, pSlot);
720 if (xSet->Count())
722 // execute with arguments - call directly
723 pItem = pDispatcher->Execute(GetId(), nCall, xSet.get(), &aInternalSet, nModifier);
724 bSuccess = (pItem != NULL);
726 else
728 // Be sure to delete this before we send a dispatch
729 // request, which will destroy the current shell.
730 xSet.reset();
732 // execute using bindings, enables support for toggle/enum etc.
733 SfxRequest aReq( GetId(), nCall, pShell->GetPool() );
734 aReq.SetModifier( nModifier );
735 aReq.SetInternalArgs_Impl(aInternalSet);
736 pDispatcher->GetBindings()->Execute_Impl( aReq, pSlot, pShell );
737 pItem = aReq.GetReturnValue();
738 bSuccess = aReq.IsDone() || pItem != NULL;
741 #ifdef DBG_UTIL
742 else
743 DBG_WARNING("MacroPlayer: Unknown slot dispatched!");
744 #endif
747 else
749 eMapUnit = GetCoreMetric( SFX_APP()->GetPool(), GetId() );
750 // AppDispatcher
751 SfxAllItemSet aSet( SFX_APP()->GetPool() );
752 TransformParameters( GetId(), lNewArgs, aSet );
754 if ( aSet.Count() )
755 pItem = pDispatcher->Execute( GetId(), nCall, &aSet, &aInternalSet, nModifier );
756 else
757 // SfxRequests take empty sets as argument sets, GetArgs() returning non-zero!
758 pItem = pDispatcher->Execute( GetId(), nCall, 0, &aInternalSet, nModifier );
760 // no bindings, no invalidate ( usually done in SfxDispatcher::Call_Impl()! )
761 if ( SfxApplication::Get() )
763 SfxDispatcher* pAppDispat = SFX_APP()->GetAppDispatcher_Impl();
764 if ( pAppDispat )
766 const SfxPoolItem* pState=0;
767 SfxItemState eState = pDispatcher->QueryState( GetId(), pState );
768 StateChanged( GetId(), eState, pState );
772 bSuccess = (pItem != NULL);
775 if ( rListener.is() )
777 ::com::sun::star::frame::DispatchResultEvent aEvent;
778 if ( bSuccess )
779 aEvent.State = com::sun::star::frame::DispatchResultState::SUCCESS;
780 else
781 aEvent.State = com::sun::star::frame::DispatchResultState::FAILURE;
783 aEvent.Source = (::com::sun::star::frame::XDispatch*) pDispatch;
784 if ( bSuccess && pItem && !pItem->ISA(SfxVoidItem) )
786 sal_uInt16 nSubId( 0 );
787 if ( eMapUnit == SFX_MAPUNIT_TWIP )
788 nSubId |= CONVERT_TWIPS;
789 pItem->QueryValue( aEvent.Result, (sal_uInt8)nSubId );
792 rListener->dispatchFinished( aEvent );
797 SfxDispatcher* SfxDispatchController_Impl::GetDispatcher()
799 if ( !pDispatcher && pBindings )
800 pDispatcher = GetBindings().GetDispatcher_Impl();
801 return pDispatcher;
804 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 )
806 SolarMutexGuard aGuard;
807 if ( !pDispatch )
808 return;
810 // Use alternative QueryState call to have a valid UNO representation of the state.
811 ::com::sun::star::uno::Any aState;
812 if ( !pDispatcher && pBindings )
813 pDispatcher = GetBindings().GetDispatcher_Impl();
814 SfxItemState eState = pDispatcher->QueryState( GetId(), aState );
816 if ( eState == SFX_ITEM_DONTCARE )
818 // Use special uno struct to transport don't care state
819 ::com::sun::star::frame::status::ItemStatus aItemStatus;
820 aItemStatus.State = ::com::sun::star::frame::status::ItemState::dont_care;
821 aState = makeAny( aItemStatus );
824 ::com::sun::star::frame::FeatureStateEvent aEvent;
825 aEvent.FeatureURL = aURL;
826 aEvent.Source = (::com::sun::star::frame::XDispatch*) pDispatch;
827 aEvent.Requery = sal_False;
828 if ( bVisible )
830 aEvent.IsEnabled = eState != SFX_ITEM_DISABLED;
831 aEvent.State = aState;
833 else
835 ::com::sun::star::frame::status::Visibility aVisibilityStatus;
836 aVisibilityStatus.bVisible = sal_False;
838 // MBA: we might decide to *not* disable "invisible" slots, but this would be
839 // a change that needs to adjust at least the testtool
840 aEvent.IsEnabled = sal_False;
841 aEvent.State = makeAny( aVisibilityStatus );
844 aListener->statusChanged( aEvent );
847 void SfxDispatchController_Impl::StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState, SfxSlotServer* pSlotServ )
849 if ( !pDispatch )
850 return;
852 // Bindings instance notifies controller about a state change, listeners must be notified also
853 // Don't cache visibility state changes as they are volatile. We need our real state to send it
854 // to our controllers after visibility is set to true.
855 sal_Bool bNotify = sal_True;
856 if ( pState && !IsInvalidItem( pState ) )
858 if ( !pState->ISA( SfxVisibilityItem ) )
860 sal_Bool bBothAvailable = pLastState && !IsInvalidItem(pLastState);
861 if ( bBothAvailable )
862 bNotify = pState->Type() != pLastState->Type() || *pState != *pLastState;
863 if ( pLastState && !IsInvalidItem( pLastState ) )
864 delete pLastState;
865 pLastState = !IsInvalidItem(pState) ? pState->Clone() : pState;
866 bVisible = sal_True;
868 else
869 bVisible = ((SfxVisibilityItem *)pState)->GetValue();
871 else
873 if ( pLastState && !IsInvalidItem( pLastState ) )
874 delete pLastState;
875 pLastState = pState;
878 ::cppu::OInterfaceContainerHelper* pContnr = pDispatch->GetListeners().getContainer ( aDispatchURL.Complete );
879 if ( bNotify && pContnr )
881 ::com::sun::star::uno::Any aState;
882 if ( ( eState >= SFX_ITEM_AVAILABLE ) && pState && !IsInvalidItem( pState ) && !pState->ISA(SfxVoidItem) )
884 // Retrieve metric from pool to have correct sub ID when calling QueryValue
885 sal_uInt16 nSubId( 0 );
886 SfxMapUnit eMapUnit( SFX_MAPUNIT_100TH_MM );
888 // retrieve the core metric
889 // it's enough to check the objectshell, the only shell that does not use the pool of the document
890 // is SfxViewFrame, but it hasn't any metric parameters
891 // TODO/LATER: what about the FormShell? Does it use any metric data?! Perhaps it should use the Pool of the document!
892 if ( pSlotServ && pDispatcher )
894 SfxShell* pShell = pDispatcher->GetShell( pSlotServ->GetShellLevel() );
895 DBG_ASSERT( pShell, "Can't get core metric without shell!" );
896 if ( pShell )
897 eMapUnit = GetCoreMetric( pShell->GetPool(), nSID );
900 if ( eMapUnit == SFX_MAPUNIT_TWIP )
901 nSubId |= CONVERT_TWIPS;
903 pState->QueryValue( aState, (sal_uInt8)nSubId );
905 else if ( eState == SFX_ITEM_DONTCARE )
907 // Use special uno struct to transport don't care state
908 ::com::sun::star::frame::status::ItemStatus aItemStatus;
909 aItemStatus.State = ::com::sun::star::frame::status::ItemState::dont_care;
910 aState = makeAny( aItemStatus );
913 ::com::sun::star::frame::FeatureStateEvent aEvent;
914 aEvent.FeatureURL = aDispatchURL;
915 aEvent.Source = (::com::sun::star::frame::XDispatch*) pDispatch;
916 aEvent.IsEnabled = eState != SFX_ITEM_DISABLED;
917 aEvent.Requery = sal_False;
918 aEvent.State = aState;
920 ::cppu::OInterfaceIteratorHelper aIt( *pContnr );
921 while( aIt.hasMoreElements() )
925 ((::com::sun::star::frame::XStatusListener *)aIt.next())->statusChanged( aEvent );
927 catch (const ::com::sun::star::uno::RuntimeException&)
929 aIt.remove();
935 void SfxDispatchController_Impl::StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState )
937 StateChanged( nSID, eState, pState, 0 );
940 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */