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 .
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
;
81 const char* URLTypeNames
[URLType_COUNT
] =
93 SfxUnoControllerItem::SfxUnoControllerItem( SfxControllerItem
*pItem
, SfxBindings
& rBind
, const OUString
& rCmd
)
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 )
109 pBindings
->ReleaseUnoController_Impl( this );
112 void SfxUnoControllerItem::UnBind()
114 // connection to SfxControllerItem is lost
116 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XStatusListener
> aRef( (::cppu::OWeakObject
*)this, ::com::sun::star::uno::UNO_QUERY
);
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
);
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) )
165 rEvent
.State
>>= sTemp
;
166 pItem
= new SfxStringItem( pCtrlItem
->GetId(), sTemp
);
169 pItem
= new SfxVoidItem( pCtrlItem
->GetId() );
172 pCtrlItem
->StateChanged( pCtrlItem
->GetId(), eState
, 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
);
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()
197 OSL_FAIL( "Tried to get dispatch, but no Bindings!" );
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() )
208 SfxFrame
& rFrame
= pBindings
->GetDispatcher_Impl()->GetFrame()->GetFrame();
209 SfxFrame
*pParent
= rFrame
.GetParentFrame();
211 // parent may intercept
212 xDispatch
= TryGetDispatch( pParent
);
214 if ( !xDispatch
.is() )
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
);
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();
234 // parent may intercept
235 xDisp
= TryGetDispatch( pParent
);
237 // only components may intercept
238 if ( !xDisp
.is() && pFrame
->HasComponent() )
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
);
244 xDisp
= xProv
->queryDispatch( aCommand
, OUString(), 0 );
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
);
256 pBindings
->ReleaseUnoController_Impl( this );
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 //-------------------------------------------------------------------------
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 ));
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) ;
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(),
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(),
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 ))
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( '.' );
423 aMasterCommand
= aURL
.Path
.copy( 0, nIndex
);
426 return aMasterCommand
;
429 SfxDispatchController_Impl::SfxDispatchController_Impl(
430 SfxOfficeDispatch
* pDisp
,
432 SfxDispatcher
* pDispat
,
433 const SfxSlot
* pSlot
,
434 const ::com::sun::star::util::URL
& rURL
)
435 : aDispatchURL( rURL
)
436 , pDispatcher( pDispat
)
439 , nSlot( pSlot
->GetSlotId() )
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
);
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
) )
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
)
487 void SfxDispatchController_Impl::setMasterSlaveCommand( sal_Bool bSet
)
492 void SfxDispatchController_Impl::UnBindController()
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;
517 OUString aParamName
= aToken
.getToken( 0, '=', nParmIndex
);
518 OUString aValue
= (nParmIndex
!=-1) ? aToken
.getToken( 0, '=', nParmIndex
) : OUString();
520 if ( !aParamName
.isEmpty() )
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() )
535 rArgs
[nLen
].Value
<<= aValue
.toInt32();
537 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_BOOL
], 4 ))
540 rArgs
[nLen
].Value
<<= aValue
.toBoolean();
542 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_BYTE
], 4 ))
545 rArgs
[nLen
].Value
<<= sal_Int8( aValue
.toInt32() );
547 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_LONG
], 4 ))
550 rArgs
[nLen
].Value
<<= aValue
.toInt32();
552 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_SHORT
], 5 ))
555 rArgs
[nLen
].Value
<<= sal_Int8( aValue
.toInt32() );
557 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_HYPER
], 5 ))
560 rArgs
[nLen
].Value
<<= aValue
.toInt64();
562 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_FLOAT
], 5 ))
565 rArgs
[nLen
].Value
<<= aValue
.toFloat();
567 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_STRING
], 6 ))
570 rArgs
[nLen
].Value
<<= OUString( INetURLObject::decode( aValue
, '%', INetURLObject::DECODE_WITH_CHARSET
));
572 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_DOUBLE
], 6))
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
;
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" )
640 aAddArgs
.push_back( aArgs
[n
] );
642 else if( rProp
.Name
== "KeyModifier" )
643 rProp
.Value
>>= nModifier
;
645 aAddArgs
.push_back( aArgs
[n
] );
648 // Add needed arguments to sequence property value
649 sal_uInt32 nAddArgs
= aAddArgs
.size();
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();
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 ->
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
) )
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
);
719 // execute with arguments - call directly
720 pItem
= pDispatcher
->Execute(GetId(), nCall
, xSet
.get(), &aInternalSet
, nModifier
);
721 bSuccess
= (pItem
!= NULL
);
725 // Be sure to delete this before we send a dispatch
726 // request, which will destroy the current shell.
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
;
740 DBG_WARNING("MacroPlayer: Unknown slot dispatched!");
746 eMapUnit
= GetCoreMetric( SFX_APP()->GetPool(), GetId() );
748 SfxAllItemSet
aSet( SFX_APP()->GetPool() );
749 TransformParameters( GetId(), lNewArgs
, aSet
);
752 pItem
= pDispatcher
->Execute( GetId(), nCall
, &aSet
, &aInternalSet
, nModifier
);
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();
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
;
777 aEvent
.State
= com::sun::star::frame::DispatchResultState::SUCCESS
;
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();
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
;
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
;
828 aEvent
.IsEnabled
= eState
!= SFX_ITEM_DISABLED
;
829 aEvent
.State
= aState
;
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
)
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
) )
863 pLastState
= !IsInvalidItem(pState
) ? pState
->Clone() : pState
;
867 bVisible
= ((SfxVisibilityItem
*)pState
)->GetValue();
871 if ( pLastState
&& !IsInvalidItem( pLastState
) )
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!" );
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
&)
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: */