1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sfx2.hxx"
31 #include <tools/debug.hxx>
32 #include <svl/eitem.hxx>
33 #include <svl/stritem.hxx>
34 #include <svl/intitem.hxx>
35 #include <svl/itemset.hxx>
36 #include <svl/visitem.hxx>
37 #include <svtools/javacontext.hxx>
38 #include <svl/itempool.hxx>
39 #include <tools/urlobj.hxx>
40 #include <com/sun/star/util/XURLTransformer.hpp>
41 #include <com/sun/star/frame/XController.hpp>
42 #include <com/sun/star/frame/XFrameActionListener.hpp>
43 #include <com/sun/star/frame/XComponentLoader.hpp>
44 #include <com/sun/star/frame/XFrame.hpp>
45 #include <com/sun/star/frame/FrameActionEvent.hpp>
46 #include <com/sun/star/frame/FrameAction.hpp>
47 #include <com/sun/star/frame/status/ItemStatus.hpp>
48 #include <com/sun/star/frame/status/ItemState.hpp>
49 #include <com/sun/star/frame/DispatchResultState.hpp>
50 #include <com/sun/star/frame/status/Visibility.hpp>
51 #include <comphelper/processfactory.hxx>
52 #include <comphelper/sequence.hxx>
53 #include <vos/mutex.hxx>
54 #include <uno/current_context.hxx>
55 #include <vcl/svapp.hxx>
57 #include <sfx2/app.hxx>
58 #include <sfx2/unoctitm.hxx>
59 #include <sfx2/viewfrm.hxx>
60 #include <sfx2/frame.hxx>
61 #include <sfx2/ctrlitem.hxx>
62 #include <sfx2/sfxuno.hxx>
63 #include <sfx2/bindings.hxx>
64 #include <sfx2/dispatch.hxx>
65 #include <sfx2/sfxsids.hrc>
66 #include <sfx2/request.hxx>
67 #include "statcach.hxx"
68 #include <sfx2/msgpool.hxx>
69 #include <sfx2/objsh.hxx>
71 namespace css
= ::com::sun::star
;
72 using namespace ::com::sun::star::uno
;
73 using namespace ::com::sun::star::util
;
74 //long nOfficeDispatchCount = 0;
89 const char* URLTypeNames
[URLType_COUNT
] =
101 SFX_IMPL_XINTERFACE_2( SfxUnoControllerItem
, OWeakObject
, ::com::sun::star::frame::XStatusListener
, ::com::sun::star::lang::XEventListener
)
102 SFX_IMPL_XTYPEPROVIDER_2( SfxUnoControllerItem
, ::com::sun::star::frame::XStatusListener
, ::com::sun::star::lang::XEventListener
)
104 SfxUnoControllerItem::SfxUnoControllerItem( SfxControllerItem
*pItem
, SfxBindings
& rBind
, const String
& rCmd
)
106 , pBindings( &rBind
)
108 DBG_ASSERT( !pCtrlItem
|| !pCtrlItem
->IsBound(), "ControllerItem fehlerhaft!" );
110 aCommand
.Complete
= rCmd
;
111 Reference
< XURLTransformer
> xTrans( ::comphelper::getProcessServiceFactory()->createInstance( rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY
);
112 xTrans
->parseStrict( aCommand
);
113 pBindings
->RegisterUnoController_Impl( this );
116 SfxUnoControllerItem::~SfxUnoControllerItem()
118 // tell bindings to forget this controller ( if still connected )
120 pBindings
->ReleaseUnoController_Impl( this );
123 void SfxUnoControllerItem::UnBind()
125 // connection to SfxControllerItem is lost
127 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XStatusListener
> aRef( (::cppu::OWeakObject
*)this, ::com::sun::star::uno::UNO_QUERY
);
131 void SAL_CALL
SfxUnoControllerItem::statusChanged(const ::com::sun::star::frame::FeatureStateEvent
& rEvent
) throw ( ::com::sun::star::uno::RuntimeException
)
133 ::vos::OGuard
aGuard( Application::GetSolarMutex() );
134 DBG_ASSERT( pCtrlItem
, "Dispatch hat den StatusListener nicht entfern!" );
136 if ( rEvent
.Requery
)
138 // Fehler kann nur passieren, wenn das alte Dispatch fehlerhaft implementiert
139 // ist, also removeStatusListener nicht gefunzt hat. Aber sowas soll
141 // Also besser vor ReleaseDispatch gegen Abflug sch"utzen!
142 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XStatusListener
> aRef( (::cppu::OWeakObject
*)this, ::com::sun::star::uno::UNO_QUERY
);
145 GetNewDispatch(); // asynchron ??
147 else if ( pCtrlItem
)
149 SfxItemState eState
= SFX_ITEM_DISABLED
;
150 SfxPoolItem
* pItem
= NULL
;
151 if ( rEvent
.IsEnabled
)
153 eState
= SFX_ITEM_AVAILABLE
;
154 ::com::sun::star::uno::Type pType
= rEvent
.State
.getValueType();
156 if ( pType
== ::getBooleanCppuType() )
158 sal_Bool bTemp
= false;
159 rEvent
.State
>>= bTemp
;
160 pItem
= new SfxBoolItem( pCtrlItem
->GetId(), bTemp
);
162 else if ( pType
== ::getCppuType((const sal_uInt16
*)0) )
164 sal_uInt16 nTemp
= 0;
165 rEvent
.State
>>= nTemp
;
166 pItem
= new SfxUInt16Item( pCtrlItem
->GetId(), nTemp
);
168 else if ( pType
== ::getCppuType((const sal_uInt32
*)0) )
170 sal_uInt32 nTemp
= 0;
171 rEvent
.State
>>= nTemp
;
172 pItem
= new SfxUInt32Item( pCtrlItem
->GetId(), nTemp
);
174 else if ( pType
== ::getCppuType((const ::rtl::OUString
*)0) )
176 ::rtl::OUString sTemp
;
177 rEvent
.State
>>= sTemp
;
178 pItem
= new SfxStringItem( pCtrlItem
->GetId(), sTemp
);
181 pItem
= new SfxVoidItem( pCtrlItem
->GetId() );
184 pCtrlItem
->StateChanged( pCtrlItem
->GetId(), eState
, pItem
);
189 void SAL_CALL
SfxUnoControllerItem::disposing( const ::com::sun::star::lang::EventObject
& ) throw ( ::com::sun::star::uno::RuntimeException
)
191 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XStatusListener
> aRef( (::cppu::OWeakObject
*)this, ::com::sun::star::uno::UNO_QUERY
);
195 void SfxUnoControllerItem::ReleaseDispatch()
197 if ( xDispatch
.is() )
199 xDispatch
->removeStatusListener( (::com::sun::star::frame::XStatusListener
*) this, aCommand
);
200 xDispatch
= ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatch
> ();
204 void SfxUnoControllerItem::GetNewDispatch()
209 DBG_ERROR( "Tried to get dispatch, but no Bindings!" );
213 // forget old dispatch
214 xDispatch
= ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatch
> ();
216 // no arms, no cookies !
217 if ( !pBindings
->GetDispatcher_Impl() || !pBindings
->GetDispatcher_Impl()->GetFrame() )
220 SfxFrame
& rFrame
= pBindings
->GetDispatcher_Impl()->GetFrame()->GetFrame();
221 SfxFrame
*pParent
= rFrame
.GetParentFrame();
223 // parent may intercept
224 xDispatch
= TryGetDispatch( pParent
);
226 if ( !xDispatch
.is() )
229 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XFrame
> xFrame
= rFrame
.GetFrameInterface();
230 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchProvider
> xProv( xFrame
, ::com::sun::star::uno::UNO_QUERY
);
232 xDispatch
= xProv
->queryDispatch( aCommand
, ::rtl::OUString(), 0 );
235 if ( xDispatch
.is() )
236 xDispatch
->addStatusListener( (::com::sun::star::frame::XStatusListener
*) this, aCommand
);
237 else if ( pCtrlItem
)
238 pCtrlItem
->StateChanged( pCtrlItem
->GetId(), SFX_ITEM_DISABLED
, NULL
);
241 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatch
> SfxUnoControllerItem::TryGetDispatch( SfxFrame
*pFrame
)
243 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatch
> xDisp
;
244 SfxFrame
*pParent
= pFrame
->GetParentFrame();
246 // parent may intercept
247 xDisp
= TryGetDispatch( pParent
);
249 // only components may intercept
250 if ( !xDisp
.is() && pFrame
->HasComponent() )
253 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XFrame
> xFrame
= pFrame
->GetFrameInterface();
254 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchProvider
> xProv( xFrame
, ::com::sun::star::uno::UNO_QUERY
);
256 xDisp
= xProv
->queryDispatch( aCommand
, ::rtl::OUString(), 0 );
262 void SfxUnoControllerItem::Execute()
264 // dispatch the resource
265 ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
> aSeq(1);
266 aSeq
[0].Name
= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Referer") );
267 aSeq
[0].Value
<<= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("private:select") );
268 if ( xDispatch
.is() )
269 xDispatch
->dispatch( aCommand
, aSeq
);
272 void SfxUnoControllerItem::ReleaseBindings()
274 // connection to binding is lost; so forget the binding and the dispatch
275 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XStatusListener
> aRef( (::cppu::OWeakObject
*)this, ::com::sun::star::uno::UNO_QUERY
);
278 pBindings
->ReleaseUnoController_Impl( this );
282 void SfxStatusDispatcher::ReleaseAll()
284 ::com::sun::star::lang::EventObject aObject
;
285 aObject
.Source
= (::cppu::OWeakObject
*) this;
286 aListeners
.disposeAndClear( aObject
);
289 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
)
293 void SAL_CALL
SfxStatusDispatcher::dispatchWithNotification(
294 const ::com::sun::star::util::URL
&,
295 const ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>&,
296 const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchResultListener
>& ) throw( ::com::sun::star::uno::RuntimeException
)
300 SFX_IMPL_XINTERFACE_2( SfxStatusDispatcher
, OWeakObject
, ::com::sun::star::frame::XNotifyingDispatch
, ::com::sun::star::frame::XDispatch
)
301 SFX_IMPL_XTYPEPROVIDER_2( SfxStatusDispatcher
, ::com::sun::star::frame::XNotifyingDispatch
, ::com::sun::star::frame::XDispatch
)
302 //IMPLNAME "com.sun.star.comp.sfx2.StatusDispatcher",
304 SfxStatusDispatcher::SfxStatusDispatcher()
305 : aListeners( aMutex
)
309 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
)
311 aListeners
.addInterface( aURL
.Complete
, aListener
);
312 if ( aURL
.Complete
.compareToAscii(".uno:LifeTime")==0 )
314 ::com::sun::star::frame::FeatureStateEvent aEvent
;
315 aEvent
.FeatureURL
= aURL
;
316 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) this;
317 aEvent
.IsEnabled
= sal_True
;
318 aEvent
.Requery
= sal_False
;
319 aListener
->statusChanged( aEvent
);
323 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
)
325 aListeners
.removeInterface( aURL
.Complete
, aListener
);
328 SFX_IMPL_XINTERFACE_1( SfxOfficeDispatch
, SfxStatusDispatcher
, ::com::sun::star::lang::XUnoTunnel
)
329 SFX_IMPL_XTYPEPROVIDER_2( SfxOfficeDispatch
, ::com::sun::star::frame::XNotifyingDispatch
, ::com::sun::star::lang::XUnoTunnel
)
332 //-------------------------------------------------------------------------
334 sal_Int64 SAL_CALL
SfxOfficeDispatch::getSomething( const ::com::sun::star::uno::Sequence
< sal_Int8
>& aIdentifier
) throw(::com::sun::star::uno::RuntimeException
)
336 if ( aIdentifier
== impl_getStaticIdentifier() )
337 return sal::static_int_cast
< sal_Int64
>( reinterpret_cast< sal_IntPtr
>( this ));
343 void* SfxOfficeDispatch::getImplementation(Reflection *p)
345 if( p == ::getCppuType((const SfxOfficeDispatch*)0) )
348 return ::cppu::OWeakObject::getImplementation(p);
352 Reflection* ::getCppuType((const SfxOfficeDispatch*)0)
354 static StandardClassReflection aRefl(
357 "SfxOfficeDispatch", ::cppu::OWeakObject::get::cppu::OWeakObjectIdlClass(),
359 ::getCppuType((const ::com::sun::star::frame::XDispatch*)0) ) );
364 SfxOfficeDispatch::SfxOfficeDispatch( SfxBindings
& rBindings
, SfxDispatcher
* pDispat
, const SfxSlot
* pSlot
, const ::com::sun::star::util::URL
& rURL
)
366 // nOfficeDispatchCount++;
368 // 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
369 pControllerItem
= new SfxDispatchController_Impl( this, &rBindings
, pDispat
, pSlot
, rURL
);
372 SfxOfficeDispatch::SfxOfficeDispatch( SfxDispatcher
* pDispat
, const SfxSlot
* pSlot
, const ::com::sun::star::util::URL
& rURL
)
374 // nOfficeDispatchCount++;
376 // 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
377 pControllerItem
= new SfxDispatchController_Impl( this, NULL
, pDispat
, pSlot
, rURL
);
380 SfxOfficeDispatch::~SfxOfficeDispatch()
382 // --nOfficeDispatchCount;
384 if ( pControllerItem
)
386 // when dispatch object is released, destroy its connection to this object and destroy it
387 pControllerItem
->UnBindController();
388 delete pControllerItem
;
392 const ::com::sun::star::uno::Sequence
< sal_Int8
>& SfxOfficeDispatch::impl_getStaticIdentifier()
394 // {38 57 CA 80 09 36 11 d4 83 FE 00 50 04 52 6B 21}
395 static sal_uInt8 pGUID
[16] = { 0x38, 0x57, 0xCA, 0x80, 0x09, 0x36, 0x11, 0xd4, 0x83, 0xFE, 0x00, 0x50, 0x04, 0x52, 0x6B, 0x21 };
396 static ::com::sun::star::uno::Sequence
< sal_Int8
> seqID((sal_Int8
*)pGUID
,16) ;
401 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
)
403 // ControllerItem is the Impl class
404 if ( pControllerItem
)
406 // The JavaContext contains an interaction handler which is used when
407 // the creation of a Java Virtual Machine fails. The second parameter
408 // indicates, that there shall only be one user notification (message box)
409 // even if the same error (interaction) reoccurs. The effect is, that if a
410 // user selects a menu entry than they may get only one notification that
411 // a JRE is not selected.
412 com::sun::star::uno::ContextLayer
layer(
413 new svt::JavaContext( com::sun::star::uno::getCurrentContext(),
416 pControllerItem
->dispatch( aURL
, aArgs
, ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchResultListener
>() );
420 void SAL_CALL
SfxOfficeDispatch::dispatchWithNotification( const ::com::sun::star::util::URL
& aURL
,
421 const ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& aArgs
,
422 const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchResultListener
>& rListener
) throw( ::com::sun::star::uno::RuntimeException
)
424 // ControllerItem is the Impl class
425 if ( pControllerItem
)
427 // see comment for SfxOfficeDispatch::dispatch
428 com::sun::star::uno::ContextLayer
layer(
429 new svt::JavaContext( com::sun::star::uno::getCurrentContext(),
432 pControllerItem
->dispatch( aURL
, aArgs
, rListener
);
436 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
)
438 GetListeners().addInterface( aURL
.Complete
, aListener
);
439 if ( pControllerItem
)
441 // ControllerItem is the Impl class
442 pControllerItem
->addStatusListener( aListener
, aURL
);
446 SfxDispatcher
* SfxOfficeDispatch::GetDispatcher_Impl()
448 return pControllerItem
->GetDispatcher();
451 void SfxOfficeDispatch::SetFrame(const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XFrame
>& xFrame
)
453 if ( pControllerItem
)
454 pControllerItem
->SetFrame( xFrame
);
457 void SfxOfficeDispatch::SetMasterUnoCommand( sal_Bool bSet
)
459 if ( pControllerItem
)
460 pControllerItem
->setMasterSlaveCommand( bSet
);
463 sal_Bool
SfxOfficeDispatch::IsMasterUnoCommand() const
465 if ( pControllerItem
)
466 return pControllerItem
->isMasterSlaveCommand();
470 // Determine if URL contains a master/slave command which must be handled a little bit different
471 sal_Bool
SfxOfficeDispatch::IsMasterUnoCommand( const ::com::sun::star::util::URL
& aURL
)
473 if ( aURL
.Protocol
.equalsAscii( ".uno:" ) &&
474 ( aURL
.Path
.indexOf( '.' ) > 0 ))
480 rtl::OUString
SfxOfficeDispatch::GetMasterUnoCommand( const ::com::sun::star::util::URL
& aURL
)
482 rtl::OUString aMasterCommand
;
483 if ( IsMasterUnoCommand( aURL
))
485 sal_Int32 nIndex
= aURL
.Path
.indexOf( '.' );
487 aMasterCommand
= aURL
.Path
.copy( 0, nIndex
);
490 return aMasterCommand
;
493 SfxDispatchController_Impl::SfxDispatchController_Impl(
494 SfxOfficeDispatch
* pDisp
,
496 SfxDispatcher
* pDispat
,
497 const SfxSlot
* pSlot
,
498 const ::com::sun::star::util::URL
& rURL
)
499 : aDispatchURL( rURL
)
500 , pDispatcher( pDispat
)
503 , nSlot( pSlot
->GetSlotId() )
505 , bMasterSlave( sal_False
)
506 , bVisible( sal_True
)
507 , pUnoName( pSlot
->pUnoName
)
509 if ( aDispatchURL
.Protocol
.equalsAscii("slot:") && pUnoName
)
511 ByteString
aTmp(".uno:");
513 aDispatchURL
.Complete
= ::rtl::OUString::createFromAscii( aTmp
.GetBuffer() );
514 Reference
< ::com::sun::star::util::XURLTransformer
> xTrans( ::comphelper::getProcessServiceFactory()->createInstance( rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY
);
515 xTrans
->parseStrict( aDispatchURL
);
521 // Bind immediately to enable the cache to recycle dispatches when asked for the same command
522 // a command in "slot" or in ".uno" notation must be treated as identical commands!
523 pBindings
->ENTERREGISTRATIONS();
524 BindInternal_Impl( nSlot
, pBindings
);
525 pBindings
->LEAVEREGISTRATIONS();
529 SfxDispatchController_Impl::~SfxDispatchController_Impl()
531 if ( pLastState
&& !IsInvalidItem( pLastState
) )
537 pDispatch
->pControllerItem
= NULL
;
539 // force all listeners to release the dispatch object
540 ::com::sun::star::lang::EventObject aObject
;
541 aObject
.Source
= (::cppu::OWeakObject
*) pDispatch
;
542 pDispatch
->GetListeners().disposeAndClear( aObject
);
546 void SfxDispatchController_Impl::SetFrame(const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XFrame
>& _xFrame
)
551 void SfxDispatchController_Impl::setMasterSlaveCommand( sal_Bool bSet
)
556 sal_Bool
SfxDispatchController_Impl::isMasterSlaveCommand() const
561 void SfxDispatchController_Impl::UnBindController()
566 GetBindings().ENTERREGISTRATIONS();
567 SfxControllerItem::UnBind();
568 GetBindings().LEAVEREGISTRATIONS();
572 void SfxDispatchController_Impl::addParametersToArgs( const com::sun::star::util::URL
& aURL
, ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& rArgs
) const
574 // Extract the parameter from the URL and put them into the property value sequence
575 sal_Int32 nQueryIndex
= aURL
.Complete
.indexOf( '?' );
576 if ( nQueryIndex
> 0 )
578 rtl::OUString
aParamString( aURL
.Complete
.copy( nQueryIndex
+1 ));
579 sal_Int32 nIndex
= 0;
582 rtl::OUString aToken
= aParamString
.getToken( 0, '&', nIndex
);
584 sal_Int32 nParmIndex
= 0;
585 rtl::OUString aParamType
;
586 rtl::OUString aParamName
= aToken
.getToken( 0, '=', nParmIndex
);
587 rtl::OUString aValue
= (nParmIndex
!=-1) ? aToken
.getToken( 0, '=', nParmIndex
) : ::rtl::OUString();
589 if ( aParamName
.getLength() > 0 )
593 aParamName
= (nParmIndex
!=-1) ? aToken
.getToken( 0, ':', nParmIndex
) : ::rtl::OUString();
594 aParamType
= (nParmIndex
!=-1) ? aToken
.getToken( 0, ':', nParmIndex
) : ::rtl::OUString();
597 sal_Int32 nLen
= rArgs
.getLength();
598 rArgs
.realloc( nLen
+1 );
599 rArgs
[nLen
].Name
= aParamName
;
601 if ( aParamType
.getLength() == 0 )
604 rArgs
[nLen
].Value
<<= aValue
.toInt32();
606 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_BOOL
], 4 ))
609 rArgs
[nLen
].Value
<<= aValue
.toBoolean();
611 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_BYTE
], 4 ))
614 rArgs
[nLen
].Value
<<= sal_Int8( aValue
.toInt32() );
616 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_LONG
], 4 ))
619 rArgs
[nLen
].Value
<<= aValue
.toInt32();
621 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_SHORT
], 5 ))
624 rArgs
[nLen
].Value
<<= sal_Int8( aValue
.toInt32() );
626 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_HYPER
], 5 ))
629 rArgs
[nLen
].Value
<<= aValue
.toInt64();
631 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_FLOAT
], 5 ))
634 rArgs
[nLen
].Value
<<= aValue
.toFloat();
636 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_STRING
], 6 ))
639 rArgs
[nLen
].Value
<<= rtl::OUString( INetURLObject::decode( aValue
, '%', INetURLObject::DECODE_WITH_CHARSET
));
641 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_DOUBLE
], 6))
644 rArgs
[nLen
].Value
<<= aValue
.toDouble();
647 while ( nIndex
>= 0 );
651 SfxMapUnit
SfxDispatchController_Impl::GetCoreMetric( SfxItemPool
& rPool
, sal_uInt16 nSlotId
)
653 sal_uInt16 nWhich
= rPool
.GetWhich( nSlotId
);
654 return rPool
.GetMetric( nWhich
);
657 rtl::OUString
SfxDispatchController_Impl::getSlaveCommand( const ::com::sun::star::util::URL
& rURL
)
659 rtl::OUString aSlaveCommand
;
660 sal_Int32 nIndex
= rURL
.Path
.indexOf( '.' );
661 if (( nIndex
> 0 ) && ( nIndex
< rURL
.Path
.getLength() ))
662 aSlaveCommand
= rURL
.Path
.copy( nIndex
+1 );
663 return aSlaveCommand
;
666 void SAL_CALL
SfxDispatchController_Impl::dispatch( const ::com::sun::star::util::URL
& aURL
,
667 const ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& aArgs
,
668 const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchResultListener
>& rListener
) throw( ::com::sun::star::uno::RuntimeException
)
670 ::vos::OGuard
aGuard( Application::GetSolarMutex() );
674 (aURL
.Protocol
.equalsAsciiL( ".uno:", 5 ) && aURL
.Path
== aDispatchURL
.Path
) ||
675 (aURL
.Protocol
.equalsAsciiL( "slot:", 5 ) && aURL
.Path
.toInt32() == GetId())
680 if ( !IsBound() && pBindings )
682 pBindings->ENTERREGISTRATIONS();
683 BindInternal_Impl( nSlot, pBindings );
684 pBindings->LEAVEREGISTRATIONS();
687 if ( !pDispatcher
&& pBindings
)
688 pDispatcher
= GetBindings().GetDispatcher_Impl();
690 ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
> lNewArgs
;
691 sal_Int32 nCount
= aArgs
.getLength();
693 // Support for URL based arguments
694 INetURLObject
aURLObj( aURL
.Complete
);
695 if ( aURLObj
.HasParam() )
696 addParametersToArgs( aURL
, lNewArgs
);
698 // Try to find call mode and frame name inside given arguments...
699 SfxCallMode nCall
= SFX_CALLMODE_STANDARD
;
700 sal_Int32 nMarkArg
= -1;
702 // Filter arguments which shouldn't be part of the sequence property value
703 sal_Bool bTemp
= sal_Bool();
704 sal_uInt16
nModifier(0);
705 std::vector
< ::com::sun::star::beans::PropertyValue
> aAddArgs
;
706 for( sal_Int32 n
=0; n
<nCount
; n
++ )
708 const ::com::sun::star::beans::PropertyValue
& rProp
= aArgs
[n
];
709 if( rProp
.Name
.equalsAsciiL("SynchronMode",12))
711 if( rProp
.Value
>>=bTemp
)
712 nCall
= bTemp
? SFX_CALLMODE_SYNCHRON
: SFX_CALLMODE_ASYNCHRON
;
714 else if( rProp
.Name
.equalsAsciiL("Bookmark",8))
717 aAddArgs
.push_back( aArgs
[n
] );
719 else if( rProp
.Name
.equalsAsciiL("KeyModifier",11))
720 rProp
.Value
>>= nModifier
;
722 aAddArgs
.push_back( aArgs
[n
] );
725 // Add needed arguments to sequence property value
726 sal_uInt32 nAddArgs
= aAddArgs
.size();
729 sal_uInt32
nIndex( lNewArgs
.getLength() );
731 lNewArgs
.realloc( lNewArgs
.getLength()+aAddArgs
.size() );
732 for ( sal_uInt32 i
= 0; i
< nAddArgs
; i
++ )
733 lNewArgs
[nIndex
++] = aAddArgs
[i
];
736 // Overwrite possible detected sychron argument, if real listener exists (currently no other way)
737 if ( rListener
.is() )
738 nCall
= SFX_CALLMODE_SYNCHRON
;
740 if( GetId() == SID_JUMPTOMARK
&& nMarkArg
== - 1 )
742 // we offer dispatches for SID_JUMPTOMARK if the URL points to a bookmark inside the document
743 // so we must retrieve this as an argument from the parsed URL
744 lNewArgs
.realloc( lNewArgs
.getLength()+1 );
745 nMarkArg
= lNewArgs
.getLength()-1;
746 lNewArgs
[nMarkArg
].Name
= ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Bookmark"));
747 lNewArgs
[nMarkArg
].Value
<<= aURL
.Mark
;
750 css::uno::Reference
< css::frame::XFrame
> xFrameRef(xFrame
.get(), css::uno::UNO_QUERY
);
751 if (! xFrameRef
.is() && pDispatcher
)
753 SfxViewFrame
* pViewFrame
= pDispatcher
->GetFrame();
755 xFrameRef
= pViewFrame
->GetFrame().GetFrameInterface();
757 SfxAllItemSet
aInternalSet( SFX_APP()->GetPool() );
758 if (xFrameRef
.is()) // an empty set is no problem ... but an empty frame reference can be a problem !
759 aInternalSet
.Put( SfxUnoFrameItem( SID_FILLFRAME
, xFrameRef
) );
761 sal_Bool bSuccess
= sal_False
;
762 sal_Bool bFailure
= sal_False
;
763 const SfxPoolItem
* pItem
= NULL
;
764 SfxShell
* pShell( 0 );
765 // #i102619# Retrieve metric from shell before execution - the shell could be destroyed after execution
766 SfxMapUnit
eMapUnit( SFX_MAPUNIT_100TH_MM
);
767 if ( pDispatcher
->GetBindings() )
769 if ( !pDispatcher
->IsLocked( GetId() ) )
771 const SfxSlot
*pSlot
= 0;
772 if ( pDispatcher
->GetShellAndSlot_Impl( GetId(), &pShell
, &pSlot
, sal_False
,
773 SFX_CALLMODE_MODAL
==(nCall
&SFX_CALLMODE_MODAL
), sal_False
) )
777 // Extract slave command and add argument to the args list. Master slot MUST
778 // have a argument that has the same name as the master slot and type is SfxStringItem.
779 sal_Int32 nIndex
= lNewArgs
.getLength();
780 lNewArgs
.realloc( nIndex
+1 );
781 lNewArgs
[nIndex
].Name
= rtl::OUString::createFromAscii( pSlot
->pUnoName
);
782 lNewArgs
[nIndex
].Value
= makeAny( SfxDispatchController_Impl::getSlaveCommand( aDispatchURL
));
785 eMapUnit
= GetCoreMetric( pShell
->GetPool(), GetId() );
786 SfxAllItemSet
aSet( pShell
->GetPool() );
787 TransformParameters( GetId(), lNewArgs
, aSet
, pSlot
);
790 // execute with arguments - call directly
791 pItem
= pDispatcher
->Execute( GetId(), nCall
, &aSet
, &aInternalSet
, nModifier
);
792 bSuccess
= (pItem
!= NULL
);
796 // execute using bindings, enables support for toggle/enum etc.
797 SfxRequest
aReq( GetId(), nCall
, pShell
->GetPool() );
798 aReq
.SetModifier( nModifier
);
799 aReq
.SetInternalArgs_Impl(aInternalSet
);
800 pDispatcher
->GetBindings()->Execute_Impl( aReq
, pSlot
, pShell
);
801 pItem
= aReq
.GetReturnValue();
802 bSuccess
= aReq
.IsDone() || pItem
!= NULL
;
803 bFailure
= aReq
.IsCancelled();
808 DBG_WARNING("MacroPlayer: Unknown slot dispatched!");
814 eMapUnit
= GetCoreMetric( SFX_APP()->GetPool(), GetId() );
816 SfxAllItemSet
aSet( SFX_APP()->GetPool() );
817 TransformParameters( GetId(), lNewArgs
, aSet
);
820 pItem
= pDispatcher
->Execute( GetId(), nCall
, &aSet
, &aInternalSet
, nModifier
);
822 // SfxRequests take empty sets as argument sets, GetArgs() returning non-zero!
823 pItem
= pDispatcher
->Execute( GetId(), nCall
, 0, &aInternalSet
, nModifier
);
825 // no bindings, no invalidate ( usually done in SfxDispatcher::Call_Impl()! )
826 if ( SfxApplication::Get() )
828 SfxDispatcher
* pAppDispat
= SFX_APP()->GetAppDispatcher_Impl();
831 const SfxPoolItem
* pState
=0;
832 SfxItemState eState
= pDispatcher
->QueryState( GetId(), pState
);
833 StateChanged( GetId(), eState
, pState
);
837 bSuccess
= (pItem
!= NULL
);
840 if ( rListener
.is() )
842 ::com::sun::star::frame::DispatchResultEvent aEvent
;
844 aEvent
.State
= com::sun::star::frame::DispatchResultState::SUCCESS
;
845 // else if ( bFailure )
847 aEvent
.State
= com::sun::star::frame::DispatchResultState::FAILURE
;
849 // aEvent.State = com::sun::star::frame::DispatchResultState::DONTKNOW;
851 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) pDispatch
;
852 if ( bSuccess
&& pItem
&& !pItem
->ISA(SfxVoidItem
) )
854 sal_uInt16
nSubId( 0 );
855 if ( eMapUnit
== SFX_MAPUNIT_TWIP
)
856 nSubId
|= CONVERT_TWIPS
;
857 pItem
->QueryValue( aEvent
.Result
, (sal_uInt8
)nSubId
);
860 rListener
->dispatchFinished( aEvent
);
865 SfxDispatcher
* SfxDispatchController_Impl::GetDispatcher()
867 if ( !pDispatcher
&& pBindings
)
868 pDispatcher
= GetBindings().GetDispatcher_Impl();
872 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
)
874 ::vos::OGuard
aGuard( Application::GetSolarMutex() );
878 /*if ( !IsBound() && pBindings )
880 pBindings->ENTERREGISTRATIONS();
881 BindInternal_Impl( nSlot, pBindings );
882 pBindings->LEAVEREGISTRATIONS();
885 // Use alternative QueryState call to have a valid UNO representation of the state.
886 ::com::sun::star::uno::Any aState
;
887 if ( !pDispatcher
&& pBindings
)
888 pDispatcher
= GetBindings().GetDispatcher_Impl();
889 SfxItemState eState
= pDispatcher
->QueryState( GetId(), aState
);
891 if ( eState
== SFX_ITEM_DONTCARE
)
893 // Use special uno struct to transport don't care state
894 ::com::sun::star::frame::status::ItemStatus aItemStatus
;
895 aItemStatus
.State
= ::com::sun::star::frame::status::ItemState::dont_care
;
896 aState
= makeAny( aItemStatus
);
899 ::com::sun::star::frame::FeatureStateEvent aEvent
;
900 aEvent
.FeatureURL
= aURL
;
901 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) pDispatch
;
902 aEvent
.Requery
= sal_False
;
905 aEvent
.IsEnabled
= eState
!= SFX_ITEM_DISABLED
;
906 aEvent
.State
= aState
;
910 ::com::sun::star::frame::status::Visibility aVisibilityStatus
;
911 aVisibilityStatus
.bVisible
= sal_False
;
913 // MBA: we might decide to *not* disable "invisible" slots, but this would be
914 // a change that needs to adjust at least the testtool
915 aEvent
.IsEnabled
= sal_False
;
916 aEvent
.State
= makeAny( aVisibilityStatus
);
919 aListener
->statusChanged( aEvent
);
922 void SfxDispatchController_Impl::StateChanged( sal_uInt16 nSID
, SfxItemState eState
, const SfxPoolItem
* pState
, SfxSlotServer
* pSlotServ
)
927 // Bindings instance notifies controller about a state change, listeners must be notified also
928 // Don't cache visibility state changes as they are volatile. We need our real state to send it
929 // to our controllers after visibility is set to true.
930 sal_Bool bNotify
= sal_True
;
931 if ( pState
&& !IsInvalidItem( pState
) )
933 if ( !pState
->ISA( SfxVisibilityItem
) )
935 sal_Bool bBothAvailable
= pLastState
&& !IsInvalidItem(pLastState
);
936 if ( bBothAvailable
)
937 bNotify
= pState
->Type() != pLastState
->Type() || *pState
!= *pLastState
;
938 if ( pLastState
&& !IsInvalidItem( pLastState
) )
940 pLastState
= !IsInvalidItem(pState
) ? pState
->Clone() : pState
;
944 bVisible
= ((SfxVisibilityItem
*)pState
)->GetValue();
948 if ( pLastState
&& !IsInvalidItem( pLastState
) )
953 ::cppu::OInterfaceContainerHelper
* pContnr
= pDispatch
->GetListeners().getContainer ( aDispatchURL
.Complete
);
954 if ( bNotify
&& pContnr
)
956 ::com::sun::star::uno::Any aState
;
957 if ( ( eState
>= SFX_ITEM_AVAILABLE
) && pState
&& !IsInvalidItem( pState
) && !pState
->ISA(SfxVoidItem
) )
959 // Retrieve metric from pool to have correct sub ID when calling QueryValue
960 sal_uInt16
nSubId( 0 );
961 SfxMapUnit
eMapUnit( SFX_MAPUNIT_100TH_MM
);
963 // retrieve the core metric
964 // it's enough to check the objectshell, the only shell that does not use the pool of the document
965 // is SfxViewFrame, but it hasn't any metric parameters
966 // TODO/LATER: what about the FormShell? Does it use any metric data?! Perhaps it should use the Pool of the document!
967 if ( pSlotServ
&& pDispatcher
)
969 SfxShell
* pShell
= pDispatcher
->GetShell( pSlotServ
->GetShellLevel() );
970 DBG_ASSERT( pShell
, "Can't get core metric without shell!" );
972 eMapUnit
= GetCoreMetric( pShell
->GetPool(), nSID
);
975 if ( eMapUnit
== SFX_MAPUNIT_TWIP
)
976 nSubId
|= CONVERT_TWIPS
;
978 pState
->QueryValue( aState
, (sal_uInt8
)nSubId
);
980 else if ( eState
== SFX_ITEM_DONTCARE
)
982 // Use special uno struct to transport don't care state
983 ::com::sun::star::frame::status::ItemStatus aItemStatus
;
984 aItemStatus
.State
= ::com::sun::star::frame::status::ItemState::dont_care
;
985 aState
= makeAny( aItemStatus
);
988 ::com::sun::star::frame::FeatureStateEvent aEvent
;
989 aEvent
.FeatureURL
= aDispatchURL
;
990 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) pDispatch
;
991 aEvent
.IsEnabled
= eState
!= SFX_ITEM_DISABLED
;
992 aEvent
.Requery
= sal_False
;
993 aEvent
.State
= aState
;
995 ::cppu::OInterfaceIteratorHelper
aIt( *pContnr
);
996 while( aIt
.hasMoreElements() )
1000 ((::com::sun::star::frame::XStatusListener
*)aIt
.next())->statusChanged( aEvent
);
1002 catch( ::com::sun::star::uno::RuntimeException
& )
1010 void SfxDispatchController_Impl::StateChanged( sal_uInt16 nSID
, SfxItemState eState
, const SfxPoolItem
* pState
)
1012 StateChanged( nSID
, eState
, pState
, 0 );