1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: unoctitm.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sfx2.hxx"
34 #include <tools/debug.hxx>
35 #include <svtools/eitem.hxx>
36 #include <svtools/stritem.hxx>
37 #include <svtools/intitem.hxx>
38 #include <svtools/itemset.hxx>
39 #include <svtools/visitem.hxx>
40 #include <svtools/javacontext.hxx>
41 #include <svtools/itempool.hxx>
42 #include <tools/urlobj.hxx>
43 #include <com/sun/star/util/XURLTransformer.hpp>
44 #include <com/sun/star/frame/XController.hpp>
45 #include <com/sun/star/frame/XFrameActionListener.hpp>
46 #include <com/sun/star/frame/XComponentLoader.hpp>
47 #include <com/sun/star/frame/XFrame.hpp>
48 #include <com/sun/star/frame/FrameActionEvent.hpp>
49 #include <com/sun/star/frame/FrameAction.hpp>
50 #include <com/sun/star/frame/status/ItemStatus.hpp>
51 #include <com/sun/star/frame/status/ItemState.hpp>
52 #include <com/sun/star/frame/DispatchResultState.hpp>
53 #include <com/sun/star/frame/status/Visibility.hpp>
54 #include <comphelper/processfactory.hxx>
55 #include <comphelper/sequence.hxx>
56 #include <vos/mutex.hxx>
57 #include <uno/current_context.hxx>
58 #include <vcl/svapp.hxx>
60 #include <sfx2/app.hxx>
61 #include <sfx2/unoctitm.hxx>
62 #include <sfx2/viewfrm.hxx>
63 #include <sfx2/frame.hxx>
64 #include <sfx2/ctrlitem.hxx>
65 #include <sfx2/sfxuno.hxx>
66 #include <sfx2/bindings.hxx>
67 #include <sfx2/dispatch.hxx>
68 #include <sfx2/sfxsids.hrc>
69 #include <sfx2/request.hxx>
70 #include "statcach.hxx"
71 #include <sfx2/msgpool.hxx>
72 #include <sfx2/objsh.hxx>
74 namespace css
= ::com::sun::star
;
75 using namespace ::com::sun::star::uno
;
76 using namespace ::com::sun::star::util
;
77 //long nOfficeDispatchCount = 0;
92 const char* URLTypeNames
[URLType_COUNT
] =
104 SFX_IMPL_XINTERFACE_2( SfxUnoControllerItem
, OWeakObject
, ::com::sun::star::frame::XStatusListener
, ::com::sun::star::lang::XEventListener
)
105 SFX_IMPL_XTYPEPROVIDER_2( SfxUnoControllerItem
, ::com::sun::star::frame::XStatusListener
, ::com::sun::star::lang::XEventListener
)
107 SfxUnoControllerItem::SfxUnoControllerItem( SfxControllerItem
*pItem
, SfxBindings
& rBind
, const String
& rCmd
)
109 , pBindings( &rBind
)
111 DBG_ASSERT( !pCtrlItem
|| !pCtrlItem
->IsBound(), "ControllerItem fehlerhaft!" );
113 aCommand
.Complete
= rCmd
;
114 Reference
< XURLTransformer
> xTrans( ::comphelper::getProcessServiceFactory()->createInstance( rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY
);
115 xTrans
->parseStrict( aCommand
);
116 pBindings
->RegisterUnoController_Impl( this );
119 SfxUnoControllerItem::~SfxUnoControllerItem()
121 // tell bindings to forget this controller ( if still connected )
123 pBindings
->ReleaseUnoController_Impl( this );
126 void SfxUnoControllerItem::UnBind()
128 // connection to SfxControllerItem is lost
130 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XStatusListener
> aRef( (::cppu::OWeakObject
*)this, ::com::sun::star::uno::UNO_QUERY
);
134 void SAL_CALL
SfxUnoControllerItem::statusChanged(const ::com::sun::star::frame::FeatureStateEvent
& rEvent
) throw ( ::com::sun::star::uno::RuntimeException
)
136 ::vos::OGuard
aGuard( Application::GetSolarMutex() );
137 DBG_ASSERT( pCtrlItem
, "Dispatch hat den StatusListener nicht entfern!" );
139 if ( rEvent
.Requery
)
141 // Fehler kann nur passieren, wenn das alte Dispatch fehlerhaft implementiert
142 // ist, also removeStatusListener nicht gefunzt hat. Aber sowas soll
144 // Also besser vor ReleaseDispatch gegen Abflug sch"utzen!
145 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XStatusListener
> aRef( (::cppu::OWeakObject
*)this, ::com::sun::star::uno::UNO_QUERY
);
148 GetNewDispatch(); // asynchron ??
150 else if ( pCtrlItem
)
152 SfxItemState eState
= SFX_ITEM_DISABLED
;
153 SfxPoolItem
* pItem
= NULL
;
154 if ( rEvent
.IsEnabled
)
156 eState
= SFX_ITEM_AVAILABLE
;
157 ::com::sun::star::uno::Type pType
= rEvent
.State
.getValueType();
159 if ( pType
== ::getBooleanCppuType() )
161 sal_Bool bTemp
= false;
162 rEvent
.State
>>= bTemp
;
163 pItem
= new SfxBoolItem( pCtrlItem
->GetId(), bTemp
);
165 else if ( pType
== ::getCppuType((const sal_uInt16
*)0) )
167 sal_uInt16 nTemp
= 0;
168 rEvent
.State
>>= nTemp
;
169 pItem
= new SfxUInt16Item( pCtrlItem
->GetId(), nTemp
);
171 else if ( pType
== ::getCppuType((const sal_uInt32
*)0) )
173 sal_uInt32 nTemp
= 0;
174 rEvent
.State
>>= nTemp
;
175 pItem
= new SfxUInt32Item( pCtrlItem
->GetId(), nTemp
);
177 else if ( pType
== ::getCppuType((const ::rtl::OUString
*)0) )
179 ::rtl::OUString sTemp
;
180 rEvent
.State
>>= sTemp
;
181 pItem
= new SfxStringItem( pCtrlItem
->GetId(), sTemp
);
184 pItem
= new SfxVoidItem( pCtrlItem
->GetId() );
187 pCtrlItem
->StateChanged( pCtrlItem
->GetId(), eState
, pItem
);
192 void SAL_CALL
SfxUnoControllerItem::disposing( const ::com::sun::star::lang::EventObject
& ) throw ( ::com::sun::star::uno::RuntimeException
)
194 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XStatusListener
> aRef( (::cppu::OWeakObject
*)this, ::com::sun::star::uno::UNO_QUERY
);
198 void SfxUnoControllerItem::ReleaseDispatch()
200 if ( xDispatch
.is() )
202 xDispatch
->removeStatusListener( (::com::sun::star::frame::XStatusListener
*) this, aCommand
);
203 xDispatch
= ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatch
> ();
207 void SfxUnoControllerItem::GetNewDispatch()
212 DBG_ERROR( "Tried to get dispatch, but no Bindings!" );
216 // forget old dispatch
217 xDispatch
= ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatch
> ();
219 // no arms, no cookies !
220 if ( !pBindings
->GetDispatcher_Impl() || !pBindings
->GetDispatcher_Impl()->GetFrame() )
223 SfxFrame
*pFrame
= pBindings
->GetDispatcher_Impl()->GetFrame()->GetFrame();
224 SfxFrame
*pParent
= pFrame
->GetParentFrame();
226 // parent may intercept
227 xDispatch
= TryGetDispatch( pParent
);
229 if ( !xDispatch
.is() )
232 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XFrame
> xFrame
= pFrame
->GetFrameInterface();
233 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchProvider
> xProv( xFrame
, ::com::sun::star::uno::UNO_QUERY
);
235 xDispatch
= xProv
->queryDispatch( aCommand
, ::rtl::OUString(), 0 );
238 if ( xDispatch
.is() )
239 xDispatch
->addStatusListener( (::com::sun::star::frame::XStatusListener
*) this, aCommand
);
240 else if ( pCtrlItem
)
241 pCtrlItem
->StateChanged( pCtrlItem
->GetId(), SFX_ITEM_DISABLED
, NULL
);
244 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatch
> SfxUnoControllerItem::TryGetDispatch( SfxFrame
*pFrame
)
246 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatch
> xDisp
;
247 SfxFrame
*pParent
= pFrame
->GetParentFrame();
249 // parent may intercept
250 xDisp
= TryGetDispatch( pParent
);
252 // only components may intercept
253 if ( !xDisp
.is() && pFrame
->HasComponent() )
256 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XFrame
> xFrame
= pFrame
->GetFrameInterface();
257 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchProvider
> xProv( xFrame
, ::com::sun::star::uno::UNO_QUERY
);
259 xDisp
= xProv
->queryDispatch( aCommand
, ::rtl::OUString(), 0 );
265 void SfxUnoControllerItem::Execute()
267 // dispatch the resource
268 ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
> aSeq(1);
269 aSeq
[0].Name
= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Referer") );
270 aSeq
[0].Value
<<= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("private:select") );
271 if ( xDispatch
.is() )
272 xDispatch
->dispatch( aCommand
, aSeq
);
275 void SfxUnoControllerItem::ReleaseBindings()
277 // connection to binding is lost; so forget the binding and the dispatch
278 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XStatusListener
> aRef( (::cppu::OWeakObject
*)this, ::com::sun::star::uno::UNO_QUERY
);
281 pBindings
->ReleaseUnoController_Impl( this );
285 void SfxStatusDispatcher::ReleaseAll()
287 ::com::sun::star::lang::EventObject aObject
;
288 aObject
.Source
= (::cppu::OWeakObject
*) this;
289 aListeners
.disposeAndClear( aObject
);
292 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
)
296 void SAL_CALL
SfxStatusDispatcher::dispatchWithNotification(
297 const ::com::sun::star::util::URL
&,
298 const ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>&,
299 const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchResultListener
>& ) throw( ::com::sun::star::uno::RuntimeException
)
303 SFX_IMPL_XINTERFACE_2( SfxStatusDispatcher
, OWeakObject
, ::com::sun::star::frame::XNotifyingDispatch
, ::com::sun::star::frame::XDispatch
)
304 SFX_IMPL_XTYPEPROVIDER_2( SfxStatusDispatcher
, ::com::sun::star::frame::XNotifyingDispatch
, ::com::sun::star::frame::XDispatch
)
305 //IMPLNAME "com.sun.star.comp.sfx2.StatusDispatcher",
307 SfxStatusDispatcher::SfxStatusDispatcher()
308 : aListeners( aMutex
)
312 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
)
314 aListeners
.addInterface( aURL
.Complete
, aListener
);
315 if ( aURL
.Complete
.compareToAscii(".uno:LifeTime")==0 )
317 ::com::sun::star::frame::FeatureStateEvent aEvent
;
318 aEvent
.FeatureURL
= aURL
;
319 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) this;
320 aEvent
.IsEnabled
= sal_True
;
321 aEvent
.Requery
= sal_False
;
322 aListener
->statusChanged( aEvent
);
326 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
)
328 aListeners
.removeInterface( aURL
.Complete
, aListener
);
331 SFX_IMPL_XINTERFACE_1( SfxOfficeDispatch
, SfxStatusDispatcher
, ::com::sun::star::lang::XUnoTunnel
)
332 SFX_IMPL_XTYPEPROVIDER_2( SfxOfficeDispatch
, ::com::sun::star::frame::XNotifyingDispatch
, ::com::sun::star::lang::XUnoTunnel
)
335 //-------------------------------------------------------------------------
337 sal_Int64 SAL_CALL
SfxOfficeDispatch::getSomething( const ::com::sun::star::uno::Sequence
< sal_Int8
>& aIdentifier
) throw(::com::sun::star::uno::RuntimeException
)
339 if ( aIdentifier
== impl_getStaticIdentifier() )
340 return sal::static_int_cast
< sal_Int64
>( reinterpret_cast< sal_IntPtr
>( this ));
346 void* SfxOfficeDispatch::getImplementation(Reflection *p)
348 if( p == ::getCppuType((const SfxOfficeDispatch*)0) )
351 return ::cppu::OWeakObject::getImplementation(p);
355 Reflection* ::getCppuType((const SfxOfficeDispatch*)0)
357 static StandardClassReflection aRefl(
360 "SfxOfficeDispatch", ::cppu::OWeakObject::get::cppu::OWeakObjectIdlClass(),
362 ::getCppuType((const ::com::sun::star::frame::XDispatch*)0) ) );
367 SfxOfficeDispatch::SfxOfficeDispatch( SfxBindings
& rBindings
, SfxDispatcher
* pDispat
, const SfxSlot
* pSlot
, const ::com::sun::star::util::URL
& rURL
)
369 // nOfficeDispatchCount++;
371 // 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
372 pControllerItem
= new SfxDispatchController_Impl( this, &rBindings
, pDispat
, pSlot
, rURL
);
375 SfxOfficeDispatch::SfxOfficeDispatch( SfxDispatcher
* pDispat
, const SfxSlot
* pSlot
, const ::com::sun::star::util::URL
& rURL
)
377 // nOfficeDispatchCount++;
379 // 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
380 pControllerItem
= new SfxDispatchController_Impl( this, NULL
, pDispat
, pSlot
, rURL
);
383 SfxOfficeDispatch::~SfxOfficeDispatch()
385 // --nOfficeDispatchCount;
387 if ( pControllerItem
)
389 // when dispatch object is released, destroy its connection to this object and destroy it
390 pControllerItem
->UnBindController();
391 delete pControllerItem
;
395 const ::com::sun::star::uno::Sequence
< sal_Int8
>& SfxOfficeDispatch::impl_getStaticIdentifier()
397 // {38 57 CA 80 09 36 11 d4 83 FE 00 50 04 52 6B 21}
398 static sal_uInt8 pGUID
[16] = { 0x38, 0x57, 0xCA, 0x80, 0x09, 0x36, 0x11, 0xd4, 0x83, 0xFE, 0x00, 0x50, 0x04, 0x52, 0x6B, 0x21 };
399 static ::com::sun::star::uno::Sequence
< sal_Int8
> seqID((sal_Int8
*)pGUID
,16) ;
404 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
)
406 // ControllerItem is the Impl class
407 if ( pControllerItem
)
409 // The JavaContext contains an interaction handler which is used when
410 // the creation of a Java Virtual Machine fails. The second parameter
411 // indicates, that there shall only be one user notification (message box)
412 // even if the same error (interaction) reoccurs. The effect is, that if a
413 // user selects a menu entry than they may get only one notification that
414 // a JRE is not selected.
415 com::sun::star::uno::ContextLayer
layer(
416 new svt::JavaContext( com::sun::star::uno::getCurrentContext(),
419 pControllerItem
->dispatch( aURL
, aArgs
, ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchResultListener
>() );
423 void SAL_CALL
SfxOfficeDispatch::dispatchWithNotification( const ::com::sun::star::util::URL
& aURL
,
424 const ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& aArgs
,
425 const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchResultListener
>& rListener
) throw( ::com::sun::star::uno::RuntimeException
)
427 // ControllerItem is the Impl class
428 if ( pControllerItem
)
430 // see comment for SfxOfficeDispatch::dispatch
431 com::sun::star::uno::ContextLayer
layer(
432 new svt::JavaContext( com::sun::star::uno::getCurrentContext(),
435 pControllerItem
->dispatch( aURL
, aArgs
, rListener
);
439 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
)
441 GetListeners().addInterface( aURL
.Complete
, aListener
);
442 if ( pControllerItem
)
444 // ControllerItem is the Impl class
445 pControllerItem
->addStatusListener( aListener
, aURL
);
449 SfxDispatcher
* SfxOfficeDispatch::GetDispatcher_Impl()
451 return pControllerItem
->GetDispatcher();
454 void SfxOfficeDispatch::SetFrame(const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XFrame
>& xFrame
)
456 if ( pControllerItem
)
457 pControllerItem
->SetFrame( xFrame
);
460 void SfxOfficeDispatch::SetMasterUnoCommand( sal_Bool bSet
)
462 if ( pControllerItem
)
463 pControllerItem
->setMasterSlaveCommand( bSet
);
466 sal_Bool
SfxOfficeDispatch::IsMasterUnoCommand() const
468 if ( pControllerItem
)
469 pControllerItem
->isMasterSlaveCommand();
473 // Determine if URL contains a master/slave command which must be handled a little bit different
474 sal_Bool
SfxOfficeDispatch::IsMasterUnoCommand( const ::com::sun::star::util::URL
& aURL
)
476 if ( aURL
.Protocol
.equalsAscii( ".uno:" ) &&
477 ( aURL
.Path
.indexOf( '.' ) > 0 ))
483 rtl::OUString
SfxOfficeDispatch::GetMasterUnoCommand( const ::com::sun::star::util::URL
& aURL
)
485 rtl::OUString aMasterCommand
;
486 if ( IsMasterUnoCommand( aURL
))
488 sal_Int32 nIndex
= aURL
.Path
.indexOf( '.' );
490 aMasterCommand
= aURL
.Path
.copy( 0, nIndex
);
493 return aMasterCommand
;
496 SfxDispatchController_Impl::SfxDispatchController_Impl(
497 SfxOfficeDispatch
* pDisp
,
499 SfxDispatcher
* pDispat
,
500 const SfxSlot
* pSlot
,
501 const ::com::sun::star::util::URL
& rURL
)
502 : aDispatchURL( rURL
)
503 , pDispatcher( pDispat
)
506 , nSlot( pSlot
->GetSlotId() )
508 , bMasterSlave( sal_False
)
509 , bVisible( sal_True
)
510 , pUnoName( pSlot
->pUnoName
)
512 if ( aDispatchURL
.Protocol
.equalsAscii("slot:") && pUnoName
)
514 ByteString
aTmp(".uno:");
516 aDispatchURL
.Complete
= ::rtl::OUString::createFromAscii( aTmp
.GetBuffer() );
517 Reference
< ::com::sun::star::util::XURLTransformer
> xTrans( ::comphelper::getProcessServiceFactory()->createInstance( rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY
);
518 xTrans
->parseStrict( aDispatchURL
);
524 // Bind immediately to enable the cache to recycle dispatches when asked for the same command
525 // a command in "slot" or in ".uno" notation must be treated as identical commands!
526 pBindings
->ENTERREGISTRATIONS();
527 BindInternal_Impl( nSlot
, pBindings
);
528 pBindings
->LEAVEREGISTRATIONS();
532 SfxDispatchController_Impl::~SfxDispatchController_Impl()
534 if ( pLastState
&& !IsInvalidItem( pLastState
) )
540 pDispatch
->pControllerItem
= NULL
;
542 // force all listeners to release the dispatch object
543 ::com::sun::star::lang::EventObject aObject
;
544 aObject
.Source
= (::cppu::OWeakObject
*) pDispatch
;
545 pDispatch
->GetListeners().disposeAndClear( aObject
);
549 void SfxDispatchController_Impl::SetFrame(const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XFrame
>& _xFrame
)
554 void SfxDispatchController_Impl::setMasterSlaveCommand( sal_Bool bSet
)
559 sal_Bool
SfxDispatchController_Impl::isMasterSlaveCommand() const
564 void SfxDispatchController_Impl::UnBindController()
569 GetBindings().ENTERREGISTRATIONS();
570 SfxControllerItem::UnBind();
571 GetBindings().LEAVEREGISTRATIONS();
575 void SfxDispatchController_Impl::addParametersToArgs( const com::sun::star::util::URL
& aURL
, ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& rArgs
) const
577 // Extract the parameter from the URL and put them into the property value sequence
578 sal_Int32 nQueryIndex
= aURL
.Complete
.indexOf( '?' );
579 if ( nQueryIndex
> 0 )
581 rtl::OUString
aParamString( aURL
.Complete
.copy( nQueryIndex
+1 ));
582 sal_Int32 nIndex
= 0;
585 rtl::OUString aToken
= aParamString
.getToken( 0, '&', nIndex
);
587 sal_Int32 nParmIndex
= 0;
588 rtl::OUString aParamType
;
589 rtl::OUString aParamName
= aToken
.getToken( 0, '=', nParmIndex
);
590 rtl::OUString aValue
= (nParmIndex
!=-1) ? aToken
.getToken( 0, '=', nParmIndex
) : ::rtl::OUString();
592 if ( aParamName
.getLength() > 0 )
596 aParamName
= (nParmIndex
!=-1) ? aToken
.getToken( 0, ':', nParmIndex
) : ::rtl::OUString();
597 aParamType
= (nParmIndex
!=-1) ? aToken
.getToken( 0, ':', nParmIndex
) : ::rtl::OUString();
600 sal_Int32 nLen
= rArgs
.getLength();
601 rArgs
.realloc( nLen
+1 );
602 rArgs
[nLen
].Name
= aParamName
;
604 if ( aParamType
.getLength() == 0 )
607 rArgs
[nLen
].Value
<<= aValue
.toInt32();
609 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_BOOL
], 4 ))
612 rArgs
[nLen
].Value
<<= aValue
.toBoolean();
614 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_BYTE
], 4 ))
617 rArgs
[nLen
].Value
<<= sal_Int8( aValue
.toInt32() );
619 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_LONG
], 4 ))
622 rArgs
[nLen
].Value
<<= aValue
.toInt32();
624 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_SHORT
], 5 ))
627 rArgs
[nLen
].Value
<<= sal_Int8( aValue
.toInt32() );
629 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_HYPER
], 5 ))
632 rArgs
[nLen
].Value
<<= aValue
.toInt64();
634 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_FLOAT
], 5 ))
637 rArgs
[nLen
].Value
<<= aValue
.toFloat();
639 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_STRING
], 6 ))
642 rArgs
[nLen
].Value
<<= rtl::OUString( INetURLObject::decode( aValue
, '%', INetURLObject::DECODE_WITH_CHARSET
));
644 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_DOUBLE
], 6))
647 rArgs
[nLen
].Value
<<= aValue
.toDouble();
650 while ( nIndex
>= 0 );
654 SfxMapUnit
SfxDispatchController_Impl::GetCoreMetric( SfxItemPool
& rPool
, sal_uInt16 nSlotId
)
656 USHORT nWhich
= rPool
.GetWhich( nSlotId
);
657 return rPool
.GetMetric( nWhich
);
660 rtl::OUString
SfxDispatchController_Impl::getSlaveCommand( const ::com::sun::star::util::URL
& rURL
)
662 rtl::OUString aSlaveCommand
;
663 sal_Int32 nIndex
= rURL
.Path
.indexOf( '.' );
664 if (( nIndex
> 0 ) && ( nIndex
< rURL
.Path
.getLength() ))
665 aSlaveCommand
= rURL
.Path
.copy( nIndex
+1 );
666 return aSlaveCommand
;
669 void SAL_CALL
SfxDispatchController_Impl::dispatch( const ::com::sun::star::util::URL
& aURL
,
670 const ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& aArgs
,
671 const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchResultListener
>& rListener
) throw( ::com::sun::star::uno::RuntimeException
)
673 ::vos::OGuard
aGuard( Application::GetSolarMutex() );
677 (aURL
.Protocol
.equalsAsciiL( ".uno:", 5 ) && aURL
.Path
== aDispatchURL
.Path
) ||
678 (aURL
.Protocol
.equalsAsciiL( "slot:", 5 ) && aURL
.Path
.toInt32() == GetId())
683 if ( !IsBound() && pBindings )
685 pBindings->ENTERREGISTRATIONS();
686 BindInternal_Impl( nSlot, pBindings );
687 pBindings->LEAVEREGISTRATIONS();
690 if ( !pDispatcher
&& pBindings
)
691 pDispatcher
= GetBindings().GetDispatcher_Impl();
693 ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
> lNewArgs
;
694 sal_Int32 nCount
= aArgs
.getLength();
696 // Support for URL based arguments
697 INetURLObject
aURLObj( aURL
.Complete
);
698 if ( aURLObj
.HasParam() )
699 addParametersToArgs( aURL
, lNewArgs
);
701 // Try to find call mode and frame name inside given arguments...
702 SfxCallMode nCall
= SFX_CALLMODE_STANDARD
;
703 sal_Int32 nMarkArg
= -1;
705 // Filter arguments which shouldn't be part of the sequence property value
706 sal_Bool bTemp
= sal_Bool();
707 sal_uInt16
nModifier(0);
708 std::vector
< ::com::sun::star::beans::PropertyValue
> aAddArgs
;
709 for( sal_Int32 n
=0; n
<nCount
; n
++ )
711 const ::com::sun::star::beans::PropertyValue
& rProp
= aArgs
[n
];
712 if( rProp
.Name
.equalsAsciiL("SynchronMode",12))
714 if( rProp
.Value
>>=bTemp
)
715 nCall
= bTemp
? SFX_CALLMODE_SYNCHRON
: SFX_CALLMODE_ASYNCHRON
;
717 else if( rProp
.Name
.equalsAsciiL("Bookmark",8))
720 aAddArgs
.push_back( aArgs
[n
] );
722 else if( rProp
.Name
.equalsAsciiL("KeyModifier",11))
723 rProp
.Value
>>= nModifier
;
725 aAddArgs
.push_back( aArgs
[n
] );
728 // Add needed arguments to sequence property value
729 sal_uInt32 nAddArgs
= aAddArgs
.size();
732 sal_uInt32
nIndex( lNewArgs
.getLength() );
734 lNewArgs
.realloc( lNewArgs
.getLength()+aAddArgs
.size() );
735 for ( sal_uInt32 i
= 0; i
< nAddArgs
; i
++ )
736 lNewArgs
[nIndex
++] = aAddArgs
[i
];
739 // Overwrite possible detected sychron argument, if real listener exists (currently no other way)
740 if ( rListener
.is() )
741 nCall
= SFX_CALLMODE_SYNCHRON
;
743 if( GetId() == SID_JUMPTOMARK
&& nMarkArg
== - 1 )
745 // we offer dispatches for SID_JUMPTOMARK if the URL points to a bookmark inside the document
746 // so we must retrieve this as an argument from the parsed URL
747 lNewArgs
.realloc( lNewArgs
.getLength()+1 );
748 nMarkArg
= lNewArgs
.getLength()-1;
749 lNewArgs
[nMarkArg
].Name
= ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Bookmark"));
750 lNewArgs
[nMarkArg
].Value
<<= aURL
.Mark
;
753 css::uno::Reference
< css::frame::XFrame
> xFrameRef(xFrame
.get(), css::uno::UNO_QUERY
);
754 if (! xFrameRef
.is() && pDispatcher
)
756 SfxViewFrame
* pViewFrame
= pDispatcher
->GetFrame();
758 xFrameRef
= pViewFrame
->GetFrame()->GetFrameInterface();
760 SfxAllItemSet
aInternalSet( SFX_APP()->GetPool() );
761 if (xFrameRef
.is()) // an empty set is no problem ... but an empty frame reference can be a problem !
762 aInternalSet
.Put( SfxUnoAnyItem( SID_FILLFRAME
, css::uno::makeAny(xFrameRef
) ) );
764 sal_Bool bSuccess
= sal_False
;
765 sal_Bool bFailure
= sal_False
;
766 const SfxPoolItem
* pItem
= NULL
;
767 SfxShell
* pShell( 0 );
768 // #i102619# Retrieve metric from shell before execution - the shell could be destroyed after execution
769 SfxMapUnit
eMapUnit( SFX_MAPUNIT_100TH_MM
);
770 if ( pDispatcher
->GetBindings() )
772 if ( !pDispatcher
->IsLocked( GetId() ) )
774 const SfxSlot
*pSlot
= 0;
775 if ( pDispatcher
->GetShellAndSlot_Impl( GetId(), &pShell
, &pSlot
, sal_False
,
776 SFX_CALLMODE_MODAL
==(nCall
&SFX_CALLMODE_MODAL
), FALSE
) )
780 // Extract slave command and add argument to the args list. Master slot MUST
781 // have a argument that has the same name as the master slot and type is SfxStringItem.
782 sal_Int32 nIndex
= lNewArgs
.getLength();
783 lNewArgs
.realloc( nIndex
+1 );
784 lNewArgs
[nIndex
].Name
= rtl::OUString::createFromAscii( pSlot
->pUnoName
);
785 lNewArgs
[nIndex
].Value
= makeAny( SfxDispatchController_Impl::getSlaveCommand( aDispatchURL
));
788 eMapUnit
= GetCoreMetric( pShell
->GetPool(), GetId() );
789 SfxAllItemSet
aSet( pShell
->GetPool() );
790 TransformParameters( GetId(), lNewArgs
, aSet
, pSlot
);
793 // execute with arguments - call directly
794 pItem
= pDispatcher
->Execute( GetId(), nCall
, &aSet
, &aInternalSet
, nModifier
);
795 bSuccess
= (pItem
!= NULL
);
799 // execute using bindings, enables support for toggle/enum etc.
800 SfxRequest
aReq( GetId(), nCall
, pShell
->GetPool() );
801 aReq
.SetModifier( nModifier
);
802 aReq
.SetInternalArgs_Impl(aInternalSet
);
803 pDispatcher
->GetBindings()->Execute_Impl( aReq
, pSlot
, pShell
);
804 pItem
= aReq
.GetReturnValue();
805 bSuccess
= aReq
.IsDone() || pItem
!= NULL
;
806 bFailure
= aReq
.IsCancelled();
811 DBG_WARNING("MacroPlayer: Unknown slot dispatched!");
817 eMapUnit
= GetCoreMetric( SFX_APP()->GetPool(), GetId() );
819 SfxAllItemSet
aSet( SFX_APP()->GetPool() );
820 TransformParameters( GetId(), lNewArgs
, aSet
);
823 pItem
= pDispatcher
->Execute( GetId(), nCall
, &aSet
, &aInternalSet
, nModifier
);
825 // SfxRequests take empty sets as argument sets, GetArgs() returning non-zero!
826 pItem
= pDispatcher
->Execute( GetId(), nCall
, 0, &aInternalSet
, nModifier
);
828 // no bindings, no invalidate ( usually done in SfxDispatcher::Call_Impl()! )
829 if ( SfxApplication::Is_Impl() )
831 SfxDispatcher
* pAppDispat
= SFX_APP()->GetAppDispatcher_Impl();
834 const SfxPoolItem
* pState
=0;
835 SfxItemState eState
= pDispatcher
->QueryState( GetId(), pState
);
836 StateChanged( GetId(), eState
, pState
);
840 bSuccess
= (pItem
!= NULL
);
843 if ( rListener
.is() )
845 ::com::sun::star::frame::DispatchResultEvent aEvent
;
847 aEvent
.State
= com::sun::star::frame::DispatchResultState::SUCCESS
;
848 // else if ( bFailure )
850 aEvent
.State
= com::sun::star::frame::DispatchResultState::FAILURE
;
852 // aEvent.State = com::sun::star::frame::DispatchResultState::DONTKNOW;
854 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) pDispatch
;
855 if ( bSuccess
&& pItem
&& !pItem
->ISA(SfxVoidItem
) )
858 if ( eMapUnit
== SFX_MAPUNIT_TWIP
)
859 nSubId
|= CONVERT_TWIPS
;
860 pItem
->QueryValue( aEvent
.Result
, (BYTE
)nSubId
);
863 rListener
->dispatchFinished( aEvent
);
868 SfxDispatcher
* SfxDispatchController_Impl::GetDispatcher()
870 if ( !pDispatcher
&& pBindings
)
871 pDispatcher
= GetBindings().GetDispatcher_Impl();
875 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
)
877 ::vos::OGuard
aGuard( Application::GetSolarMutex() );
881 /*if ( !IsBound() && pBindings )
883 pBindings->ENTERREGISTRATIONS();
884 BindInternal_Impl( nSlot, pBindings );
885 pBindings->LEAVEREGISTRATIONS();
888 // Use alternative QueryState call to have a valid UNO representation of the state.
889 ::com::sun::star::uno::Any aState
;
890 if ( !pDispatcher
&& pBindings
)
891 pDispatcher
= GetBindings().GetDispatcher_Impl();
892 SfxItemState eState
= pDispatcher
->QueryState( GetId(), aState
);
894 if ( eState
== SFX_ITEM_DONTCARE
)
896 // Use special uno struct to transport don't care state
897 ::com::sun::star::frame::status::ItemStatus aItemStatus
;
898 aItemStatus
.State
= ::com::sun::star::frame::status::ItemState::dont_care
;
899 aState
= makeAny( aItemStatus
);
902 ::com::sun::star::frame::FeatureStateEvent aEvent
;
903 aEvent
.FeatureURL
= aURL
;
904 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) pDispatch
;
905 aEvent
.Requery
= sal_False
;
908 aEvent
.IsEnabled
= eState
!= SFX_ITEM_DISABLED
;
909 aEvent
.State
= aState
;
913 ::com::sun::star::frame::status::Visibility aVisibilityStatus
;
914 aVisibilityStatus
.bVisible
= sal_False
;
916 // MBA: we might decide to *not* disable "invisible" slots, but this would be
917 // a change that needs to adjust at least the testtool
918 aEvent
.IsEnabled
= sal_False
;
919 aEvent
.State
= makeAny( aVisibilityStatus
);
922 aListener
->statusChanged( aEvent
);
925 void SfxDispatchController_Impl::StateChanged( sal_uInt16 nSID
, SfxItemState eState
, const SfxPoolItem
* pState
, SfxSlotServer
* pSlotServ
)
930 // Bindings instance notifies controller about a state change, listeners must be notified also
931 // Don't cache visibility state changes as they are volatile. We need our real state to send it
932 // to our controllers after visibility is set to true.
933 sal_Bool bNotify
= sal_True
;
934 if ( pState
&& !IsInvalidItem( pState
) )
936 if ( !pState
->ISA( SfxVisibilityItem
) )
938 sal_Bool bBothAvailable
= pLastState
&& !IsInvalidItem(pLastState
);
939 if ( bBothAvailable
)
940 bNotify
= pState
->Type() != pLastState
->Type() || *pState
!= *pLastState
;
941 if ( pLastState
&& !IsInvalidItem( pLastState
) )
943 pLastState
= !IsInvalidItem(pState
) ? pState
->Clone() : pState
;
947 bVisible
= ((SfxVisibilityItem
*)pState
)->GetValue();
951 if ( pLastState
&& !IsInvalidItem( pLastState
) )
956 ::cppu::OInterfaceContainerHelper
* pContnr
= pDispatch
->GetListeners().getContainer ( aDispatchURL
.Complete
);
957 if ( bNotify
&& pContnr
)
959 ::com::sun::star::uno::Any aState
;
960 if ( ( eState
>= SFX_ITEM_AVAILABLE
) && pState
&& !IsInvalidItem( pState
) && !pState
->ISA(SfxVoidItem
) )
962 // Retrieve metric from pool to have correct sub ID when calling QueryValue
964 SfxMapUnit
eMapUnit( SFX_MAPUNIT_100TH_MM
);
966 // retrieve the core metric
967 // it's enough to check the objectshell, the only shell that does not use the pool of the document
968 // is SfxViewFrame, but it hasn't any metric parameters
969 // TODO/LATER: what about the FormShell? Does it use any metric data?! Perhaps it should use the Pool of the document!
970 if ( pSlotServ
&& pDispatcher
)
972 SfxShell
* pShell
= pDispatcher
->GetShell( pSlotServ
->GetShellLevel() );
973 DBG_ASSERT( pShell
, "Can't get core metric without shell!" );
975 eMapUnit
= GetCoreMetric( pShell
->GetPool(), nSID
);
978 if ( eMapUnit
== SFX_MAPUNIT_TWIP
)
979 nSubId
|= CONVERT_TWIPS
;
981 pState
->QueryValue( aState
, (BYTE
)nSubId
);
983 else if ( eState
== SFX_ITEM_DONTCARE
)
985 // Use special uno struct to transport don't care state
986 ::com::sun::star::frame::status::ItemStatus aItemStatus
;
987 aItemStatus
.State
= ::com::sun::star::frame::status::ItemState::dont_care
;
988 aState
= makeAny( aItemStatus
);
991 ::com::sun::star::frame::FeatureStateEvent aEvent
;
992 aEvent
.FeatureURL
= aDispatchURL
;
993 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) pDispatch
;
994 aEvent
.IsEnabled
= eState
!= SFX_ITEM_DISABLED
;
995 aEvent
.Requery
= sal_False
;
996 aEvent
.State
= aState
;
998 ::cppu::OInterfaceIteratorHelper
aIt( *pContnr
);
999 while( aIt
.hasMoreElements() )
1003 ((::com::sun::star::frame::XStatusListener
*)aIt
.next())->statusChanged( aEvent
);
1005 catch( ::com::sun::star::uno::RuntimeException
& )
1013 void SfxDispatchController_Impl::StateChanged( sal_uInt16 nSID
, SfxItemState eState
, const SfxPoolItem
* pState
)
1015 StateChanged( nSID
, eState
, pState
, 0 );