1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
;
80 const char* URLTypeNames
[URLType_COUNT
] =
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
)
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 )
111 pBindings
->ReleaseUnoController_Impl( this );
114 void SfxUnoControllerItem::UnBind()
116 // connection to SfxControllerItem is lost
118 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XStatusListener
> aRef( (::cppu::OWeakObject
*)this, ::com::sun::star::uno::UNO_QUERY
);
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
);
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) )
167 rEvent
.State
>>= sTemp
;
168 pItem
= new SfxStringItem( pCtrlItem
->GetId(), sTemp
);
171 pItem
= new SfxVoidItem( pCtrlItem
->GetId() );
174 pCtrlItem
->StateChanged( pCtrlItem
->GetId(), eState
, 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
);
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()
199 OSL_FAIL( "Tried to get dispatch, but no Bindings!" );
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() )
210 SfxFrame
& rFrame
= pBindings
->GetDispatcher_Impl()->GetFrame()->GetFrame();
211 SfxFrame
*pParent
= rFrame
.GetParentFrame();
213 // parent may intercept
214 xDispatch
= TryGetDispatch( pParent
);
216 if ( !xDispatch
.is() )
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
);
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();
236 // parent may intercept
237 xDisp
= TryGetDispatch( pParent
);
239 // only components may intercept
240 if ( !xDisp
.is() && pFrame
->HasComponent() )
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
);
246 xDisp
= xProv
->queryDispatch( aCommand
, OUString(), 0 );
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
);
258 pBindings
->ReleaseUnoController_Impl( this );
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 //-------------------------------------------------------------------------
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 ));
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) ;
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
)
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(),
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
)
381 // see comment for SfxOfficeDispatch::dispatch
382 com::sun::star::uno::ContextLayer
layer(
383 new svt::JavaContext( com::sun::star::uno::getCurrentContext(),
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 ))
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( '.' );
433 aMasterCommand
= aURL
.Path
.copy( 0, nIndex
);
436 return aMasterCommand
;
439 SfxDispatchController_Impl::SfxDispatchController_Impl(
440 SfxOfficeDispatch
* pDisp
,
442 SfxDispatcher
* pDispat
,
443 const SfxSlot
* pSlot
,
444 const ::com::sun::star::util::URL
& rURL
)
445 : aDispatchURL( rURL
)
446 , pDispatcher( pDispat
)
449 , nSlot( pSlot
->GetSlotId() )
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
);
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
) )
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
)
497 void SfxDispatchController_Impl::setMasterSlaveCommand( sal_Bool bSet
)
502 void SfxDispatchController_Impl::UnBindController()
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;
527 OUString aParamName
= aToken
.getToken( 0, '=', nParmIndex
);
528 OUString aValue
= (nParmIndex
!=-1) ? aToken
.getToken( 0, '=', nParmIndex
) : OUString();
530 if ( !aParamName
.isEmpty() )
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() )
545 rArgs
[nLen
].Value
<<= aValue
.toInt32();
547 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_BOOL
], 4 ))
550 rArgs
[nLen
].Value
<<= aValue
.toBoolean();
552 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_BYTE
], 4 ))
555 rArgs
[nLen
].Value
<<= sal_Int8( aValue
.toInt32() );
557 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_LONG
], 4 ))
560 rArgs
[nLen
].Value
<<= aValue
.toInt32();
562 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_SHORT
], 5 ))
565 rArgs
[nLen
].Value
<<= sal_Int8( aValue
.toInt32() );
567 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_HYPER
], 5 ))
570 rArgs
[nLen
].Value
<<= aValue
.toInt64();
572 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_FLOAT
], 5 ))
575 rArgs
[nLen
].Value
<<= aValue
.toFloat();
577 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_STRING
], 6 ))
580 rArgs
[nLen
].Value
<<= OUString( INetURLObject::decode( aValue
, '%', INetURLObject::DECODE_WITH_CHARSET
));
582 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_DOUBLE
], 6))
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
;
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))
650 aAddArgs
.push_back( aArgs
[n
] );
652 else if( rProp
.Name
.equalsAsciiL("KeyModifier",11))
653 rProp
.Value
>>= nModifier
;
655 aAddArgs
.push_back( aArgs
[n
] );
658 // Add needed arguments to sequence property value
659 sal_uInt32 nAddArgs
= aAddArgs
.size();
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();
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
) )
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
);
722 // execute with arguments - call directly
723 pItem
= pDispatcher
->Execute(GetId(), nCall
, xSet
.get(), &aInternalSet
, nModifier
);
724 bSuccess
= (pItem
!= NULL
);
728 // Be sure to delete this before we send a dispatch
729 // request, which will destroy the current shell.
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
;
743 DBG_WARNING("MacroPlayer: Unknown slot dispatched!");
749 eMapUnit
= GetCoreMetric( SFX_APP()->GetPool(), GetId() );
751 SfxAllItemSet
aSet( SFX_APP()->GetPool() );
752 TransformParameters( GetId(), lNewArgs
, aSet
);
755 pItem
= pDispatcher
->Execute( GetId(), nCall
, &aSet
, &aInternalSet
, nModifier
);
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();
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
;
779 aEvent
.State
= com::sun::star::frame::DispatchResultState::SUCCESS
;
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();
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
;
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
;
830 aEvent
.IsEnabled
= eState
!= SFX_ITEM_DISABLED
;
831 aEvent
.State
= aState
;
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
)
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
) )
865 pLastState
= !IsInvalidItem(pState
) ? pState
->Clone() : pState
;
869 bVisible
= ((SfxVisibilityItem
*)pState
)->GetValue();
873 if ( pLastState
&& !IsInvalidItem( pLastState
) )
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!" );
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
&)
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: */