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/Desktop.hpp>
34 #include <com/sun/star/frame/XController.hpp>
35 #include <com/sun/star/frame/XFrameActionListener.hpp>
36 #include <com/sun/star/frame/XComponentLoader.hpp>
37 #include <com/sun/star/frame/XFrame.hpp>
38 #include <com/sun/star/frame/FrameActionEvent.hpp>
39 #include <com/sun/star/frame/FrameAction.hpp>
40 #include <com/sun/star/frame/status/ItemStatus.hpp>
41 #include <com/sun/star/frame/status/ItemState.hpp>
42 #include <com/sun/star/frame/DispatchResultState.hpp>
43 #include <com/sun/star/frame/ModuleManager.hpp>
44 #include <com/sun/star/frame/status/Visibility.hpp>
45 #include <comphelper/processfactory.hxx>
46 #include <comphelper/sequence.hxx>
47 #include <officecfg/Office/Common.hxx>
48 #include <osl/mutex.hxx>
49 #include <uno/current_context.hxx>
50 #include <vcl/svapp.hxx>
52 #include <sfx2/app.hxx>
53 #include <sfx2/unoctitm.hxx>
54 #include <sfx2/viewfrm.hxx>
55 #include <sfx2/frame.hxx>
56 #include <sfx2/ctrlitem.hxx>
57 #include <sfx2/sfxuno.hxx>
58 #include <sfx2/bindings.hxx>
59 #include <sfx2/dispatch.hxx>
60 #include <sfx2/sfxsids.hrc>
61 #include <sfx2/request.hxx>
62 #include "statcach.hxx"
63 #include <sfx2/msgpool.hxx>
64 #include <sfx2/objsh.hxx>
66 #include <boost/scoped_ptr.hpp>
71 #include <sal/log.hxx>
72 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
74 using namespace ::com::sun::star
;
75 using namespace ::com::sun::star::uno
;
76 using namespace ::com::sun::star::util
;
91 const char* URLTypeNames
[URLType_COUNT
] =
103 SfxUnoControllerItem::SfxUnoControllerItem( SfxControllerItem
*pItem
, SfxBindings
& rBind
, const OUString
& rCmd
)
105 , pBindings( &rBind
)
107 DBG_ASSERT( !pCtrlItem
|| !pCtrlItem
->IsBound(), "ControllerItem is incorrect!" );
109 aCommand
.Complete
= rCmd
;
110 Reference
< XURLTransformer
> xTrans( URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
111 xTrans
->parseStrict( aCommand
);
112 pBindings
->RegisterUnoController_Impl( this );
115 SfxUnoControllerItem::~SfxUnoControllerItem()
117 // tell bindings to forget this controller ( if still connected )
119 pBindings
->ReleaseUnoController_Impl( this );
122 void SfxUnoControllerItem::UnBind()
124 // connection to SfxControllerItem is lost
126 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XStatusListener
> aRef( (::cppu::OWeakObject
*)this, ::com::sun::star::uno::UNO_QUERY
);
130 void SAL_CALL
SfxUnoControllerItem::statusChanged(const ::com::sun::star::frame::FeatureStateEvent
& rEvent
) throw ( ::com::sun::star::uno::RuntimeException
, std::exception
)
132 SolarMutexGuard aGuard
;
133 DBG_ASSERT( pCtrlItem
, "dispatch implementation didn't respect our previous removeStatusListener call!" );
135 if ( rEvent
.Requery
)
137 // Error can only happen if the old Dispatch is implemented incorrectly
138 // i.e. removeStatusListener did not work. But such things can happen...
139 // So protect before ReleaseDispatch from release!
140 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XStatusListener
> aRef( (::cppu::OWeakObject
*)this, ::com::sun::star::uno::UNO_QUERY
);
143 GetNewDispatch(); // asynchronous ??
145 else if ( pCtrlItem
)
147 SfxItemState eState
= SfxItemState::DISABLED
;
148 SfxPoolItem
* pItem
= NULL
;
149 if ( rEvent
.IsEnabled
)
151 eState
= SfxItemState::DEFAULT
;
152 ::com::sun::star::uno::Type pType
= rEvent
.State
.getValueType();
154 if ( pType
== cppu::UnoType
< bool >::get() )
157 rEvent
.State
>>= bTemp
;
158 pItem
= new SfxBoolItem( pCtrlItem
->GetId(), bTemp
);
160 else if ( pType
== cppu::UnoType
< ::cppu::UnoUnsignedShortType
>::get() )
162 sal_uInt16 nTemp
= 0;
163 rEvent
.State
>>= nTemp
;
164 pItem
= new SfxUInt16Item( pCtrlItem
->GetId(), nTemp
);
166 else if ( pType
== cppu::UnoType
<sal_uInt32
>::get() )
168 sal_uInt32 nTemp
= 0;
169 rEvent
.State
>>= nTemp
;
170 pItem
= new SfxUInt32Item( pCtrlItem
->GetId(), nTemp
);
172 else if ( pType
== cppu::UnoType
<OUString
>::get() )
175 rEvent
.State
>>= sTemp
;
176 pItem
= new SfxStringItem( pCtrlItem
->GetId(), sTemp
);
179 pItem
= new SfxVoidItem( pCtrlItem
->GetId() );
182 pCtrlItem
->StateChanged( pCtrlItem
->GetId(), eState
, pItem
);
187 void SAL_CALL
SfxUnoControllerItem::disposing( const ::com::sun::star::lang::EventObject
& ) throw ( ::com::sun::star::uno::RuntimeException
, std::exception
)
189 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XStatusListener
> aRef( (::cppu::OWeakObject
*)this, ::com::sun::star::uno::UNO_QUERY
);
193 void SfxUnoControllerItem::ReleaseDispatch()
195 if ( xDispatch
.is() )
197 xDispatch
->removeStatusListener( (::com::sun::star::frame::XStatusListener
*) this, aCommand
);
198 xDispatch
= ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatch
> ();
202 void SfxUnoControllerItem::GetNewDispatch()
207 OSL_FAIL( "Tried to get dispatch, but no Bindings!" );
211 // forget old dispatch
212 xDispatch
= ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatch
> ();
214 // no arms, no cookies !
215 if ( !pBindings
->GetDispatcher_Impl() || !pBindings
->GetDispatcher_Impl()->GetFrame() )
218 SfxFrame
& rFrame
= pBindings
->GetDispatcher_Impl()->GetFrame()->GetFrame();
219 SfxFrame
*pParent
= rFrame
.GetParentFrame();
221 // parent may intercept
222 xDispatch
= TryGetDispatch( pParent
);
224 if ( !xDispatch
.is() )
227 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XFrame
> xFrame
= rFrame
.GetFrameInterface();
228 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchProvider
> xProv( xFrame
, ::com::sun::star::uno::UNO_QUERY
);
230 xDispatch
= xProv
->queryDispatch( aCommand
, OUString(), 0 );
233 if ( xDispatch
.is() )
234 xDispatch
->addStatusListener( (::com::sun::star::frame::XStatusListener
*) this, aCommand
);
235 else if ( pCtrlItem
)
236 pCtrlItem
->StateChanged( pCtrlItem
->GetId(), SfxItemState::DISABLED
, NULL
);
239 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatch
> SfxUnoControllerItem::TryGetDispatch( SfxFrame
*pFrame
)
241 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatch
> xDisp
;
242 SfxFrame
*pParent
= pFrame
->GetParentFrame();
244 // parent may intercept
245 xDisp
= TryGetDispatch( pParent
);
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
, std::exception
)
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
, std::exception
)
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
, std::exception
)
285 aListeners
.addInterface( aURL
.Complete
, aListener
);
286 if ( aURL
.Complete
== ".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
, std::exception
)
299 aListeners
.removeInterface( aURL
.Complete
, aListener
);
304 sal_Int64 SAL_CALL
SfxOfficeDispatch::getSomething( const ::com::sun::star::uno::Sequence
< sal_Int8
>& aIdentifier
) throw(::com::sun::star::uno::RuntimeException
, std::exception
)
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(reinterpret_cast<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
, std::exception
)
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
, std::exception
)
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
, std::exception
)
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( 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 bool SfxOfficeDispatch::IsMasterUnoCommand( const ::com::sun::star::util::URL
& aURL
)
410 return aURL
.Protocol
== ".uno:" && ( aURL
.Path
.indexOf( '.' ) > 0 );
413 OUString
SfxOfficeDispatch::GetMasterUnoCommand( const ::com::sun::star::util::URL
& aURL
)
415 OUString aMasterCommand
;
416 if ( IsMasterUnoCommand( aURL
))
418 sal_Int32 nIndex
= aURL
.Path
.indexOf( '.' );
420 aMasterCommand
= aURL
.Path
.copy( 0, nIndex
);
423 return aMasterCommand
;
426 SfxDispatchController_Impl::SfxDispatchController_Impl(
427 SfxOfficeDispatch
* pDisp
,
429 SfxDispatcher
* pDispat
,
430 const SfxSlot
* pSlot
,
431 const ::com::sun::star::util::URL
& rURL
)
432 : aDispatchURL( rURL
)
433 , pDispatcher( pDispat
)
436 , nSlot( pSlot
->GetSlotId() )
438 , bMasterSlave( false )
440 , pUnoName( pSlot
->pUnoName
)
442 if ( aDispatchURL
.Protocol
== "slot:" && pUnoName
)
444 OStringBuffer
aTmp(".uno:");
445 aTmp
.append(pUnoName
);
446 aDispatchURL
.Complete
= OStringToOUString(aTmp
.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US
);
447 Reference
< XURLTransformer
> xTrans( URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
448 xTrans
->parseStrict( aDispatchURL
);
454 // Bind immediately to enable the cache to recycle dispatches when asked for the same command
455 // a command in "slot" or in ".uno" notation must be treated as identical commands!
456 pBindings
->ENTERREGISTRATIONS();
457 BindInternal_Impl( nSlot
, pBindings
);
458 pBindings
->LEAVEREGISTRATIONS();
462 SfxDispatchController_Impl::~SfxDispatchController_Impl()
464 if ( pLastState
&& !IsInvalidItem( pLastState
) )
470 pDispatch
->pControllerItem
= NULL
;
472 // force all listeners to release the dispatch object
473 ::com::sun::star::lang::EventObject aObject
;
474 aObject
.Source
= (::cppu::OWeakObject
*) pDispatch
;
475 pDispatch
->GetListeners().disposeAndClear( aObject
);
479 void SfxDispatchController_Impl::SetFrame(const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XFrame
>& _xFrame
)
484 void SfxDispatchController_Impl::setMasterSlaveCommand( bool bSet
)
489 void SfxDispatchController_Impl::UnBindController()
494 GetBindings().ENTERREGISTRATIONS();
495 SfxControllerItem::UnBind();
496 GetBindings().LEAVEREGISTRATIONS();
500 void SfxDispatchController_Impl::addParametersToArgs( const com::sun::star::util::URL
& aURL
, ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& rArgs
)
502 // Extract the parameter from the URL and put them into the property value sequence
503 sal_Int32 nQueryIndex
= aURL
.Complete
.indexOf( '?' );
504 if ( nQueryIndex
> 0 )
506 OUString
aParamString( aURL
.Complete
.copy( nQueryIndex
+1 ));
507 sal_Int32 nIndex
= 0;
510 OUString aToken
= aParamString
.getToken( 0, '&', nIndex
);
512 sal_Int32 nParmIndex
= 0;
514 OUString aParamName
= aToken
.getToken( 0, '=', nParmIndex
);
515 OUString aValue
= (nParmIndex
!=-1) ? aToken
.getToken( 0, '=', nParmIndex
) : OUString();
517 if ( !aParamName
.isEmpty() )
521 aParamName
= aToken
.getToken( 0, ':', nParmIndex
);
522 aParamType
= (nParmIndex
!=-1) ? aToken
.getToken( 0, ':', nParmIndex
) : OUString();
525 sal_Int32 nLen
= rArgs
.getLength();
526 rArgs
.realloc( nLen
+1 );
527 rArgs
[nLen
].Name
= aParamName
;
529 if ( aParamType
.isEmpty() )
532 rArgs
[nLen
].Value
<<= aValue
.toInt32();
534 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_BOOL
], 4 ))
537 rArgs
[nLen
].Value
<<= aValue
.toBoolean();
539 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_BYTE
], 4 ))
542 rArgs
[nLen
].Value
<<= sal_Int8( aValue
.toInt32() );
544 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_LONG
], 4 ))
547 rArgs
[nLen
].Value
<<= aValue
.toInt32();
549 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_SHORT
], 5 ))
552 rArgs
[nLen
].Value
<<= sal_Int8( aValue
.toInt32() );
554 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_HYPER
], 5 ))
557 rArgs
[nLen
].Value
<<= aValue
.toInt64();
559 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_FLOAT
], 5 ))
562 rArgs
[nLen
].Value
<<= aValue
.toFloat();
564 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_STRING
], 6 ))
567 rArgs
[nLen
].Value
<<= OUString( INetURLObject::decode( aValue
, INetURLObject::DECODE_WITH_CHARSET
));
569 else if ( aParamType
.equalsAsciiL( URLTypeNames
[URLType_DOUBLE
], 6))
572 rArgs
[nLen
].Value
<<= aValue
.toDouble();
575 while ( nIndex
>= 0 );
579 SfxMapUnit
SfxDispatchController_Impl::GetCoreMetric( SfxItemPool
& rPool
, sal_uInt16 nSlotId
)
581 sal_uInt16 nWhich
= rPool
.GetWhich( nSlotId
);
582 return rPool
.GetMetric( nWhich
);
585 OUString
SfxDispatchController_Impl::getSlaveCommand( const ::com::sun::star::util::URL
& rURL
)
587 OUString aSlaveCommand
;
588 sal_Int32 nIndex
= rURL
.Path
.indexOf( '.' );
589 if (( nIndex
> 0 ) && ( nIndex
< rURL
.Path
.getLength() ))
590 aSlaveCommand
= rURL
.Path
.copy( nIndex
+1 );
591 return aSlaveCommand
;
596 /// Class that collects the usage information - how many times what .uno: command was used.
599 typedef std::map
<OUString
, int> UsageMap
;
601 /// Are we collecting the info? We cache the value because the call to save can happen very late.
604 /// Command vs. how many times it was used
608 UsageInfo() : mbIsCollecting(false)
617 /// Increment command's use.
618 void increment(const OUString
&rCommand
);
620 /// Save the usage data for the next session.
623 /// Modify the flag whether we are collecting.
624 void setCollecting(bool bIsCollecting
) { mbIsCollecting
= bIsCollecting
; }
627 void UsageInfo::increment(const OUString
&rCommand
)
629 UsageMap::iterator it
= maUsage
.find(rCommand
);
631 if (it
!= maUsage
.end())
634 maUsage
[rCommand
] = 1;
637 void UsageInfo::save()
642 // TODO - do a real saving here, not only dump to the screen
643 std::cerr
<< "Usage information:" << std::endl
;
644 for (UsageMap::const_iterator it
= maUsage
.begin(); it
!= maUsage
.end(); ++it
)
646 std::cerr
<< it
->first
<< ';' << it
->second
<< std::endl
;
648 std::cerr
<< "Usage information end" << std::endl
;
651 class theUsageInfo
: public rtl::Static
<UsageInfo
, theUsageInfo
> {};
653 /// Extracts information about the command + args, and stores that.
654 void collectUsageInformation(const util::URL
& rURL
, const uno::Sequence
<beans::PropertyValue
>& rArgs
)
656 bool bCollecting
= officecfg::Office::Common::Misc::CollectUsageInformation::get();
657 theUsageInfo::get().setCollecting(bCollecting
);
661 OUStringBuffer aBuffer
;
663 // app identification [uh, several UNO calls :-(]
664 uno::Reference
<uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
665 uno::Reference
<frame::XModuleManager2
> xModuleManager(frame::ModuleManager::create(xContext
));
666 uno::Reference
<frame::XDesktop2
> xDesktop
= frame::Desktop::create(xContext
);
667 uno::Reference
<frame::XFrame
> xFrame
= xDesktop
->getCurrentFrame();
669 OUString
aModule(xModuleManager
->identify(xFrame
));
670 sal_Int32 nLastDot
= aModule
.lastIndexOf('.');
672 aModule
= aModule
.copy(nLastDot
+ 1);
674 aBuffer
.append(aModule
);
678 aBuffer
.append(rURL
.Protocol
);
679 aBuffer
.append(rURL
.Path
);
680 sal_Int32 nCount
= rArgs
.getLength();
682 // parameters - only their names, not the values (could be sensitive!)
686 for (sal_Int32 n
= 0; n
< nCount
; n
++)
688 const ::com::sun::star::beans::PropertyValue
& rProp
= rArgs
[n
];
691 aBuffer
.append(rProp
.Name
);
696 OUString
aCommand(aBuffer
.makeStringAndClear());
699 theUsageInfo::get().increment(aCommand
);
704 void SAL_CALL
SfxDispatchController_Impl::dispatch( const ::com::sun::star::util::URL
& aURL
,
705 const ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& aArgs
,
706 const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchResultListener
>& rListener
)
707 throw (css::uno::RuntimeException
, std::exception
)
709 collectUsageInformation(aURL
, aArgs
);
711 SolarMutexGuard aGuard
;
715 (aURL
.Protocol
== ".uno:" && aURL
.Path
== aDispatchURL
.Path
) ||
716 (aURL
.Protocol
== "slot:" && aURL
.Path
.toInt32() == GetId())
720 if ( !pDispatcher
&& pBindings
)
721 pDispatcher
= GetBindings().GetDispatcher_Impl();
723 ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
> lNewArgs
;
724 sal_Int32 nCount
= aArgs
.getLength();
726 // Support for URL based arguments
727 INetURLObject
aURLObj( aURL
.Complete
);
728 if ( aURLObj
.HasParam() )
729 addParametersToArgs( aURL
, lNewArgs
);
731 // Try to find call mode and frame name inside given arguments...
732 SfxCallMode nCall
= SfxCallMode::RECORD
;
733 sal_Int32 nMarkArg
= -1;
735 // Filter arguments which shouldn't be part of the sequence property value
736 sal_uInt16
nModifier(0);
737 std::vector
< ::com::sun::star::beans::PropertyValue
> aAddArgs
;
738 for( sal_Int32 n
=0; n
<nCount
; n
++ )
740 const ::com::sun::star::beans::PropertyValue
& rProp
= aArgs
[n
];
741 if( rProp
.Name
== "SynchronMode" )
744 if( rProp
.Value
>>= bTemp
)
745 nCall
= bTemp
? SfxCallMode::SYNCHRON
: SfxCallMode::ASYNCHRON
;
747 else if( rProp
.Name
== "Bookmark" )
750 aAddArgs
.push_back( aArgs
[n
] );
752 else if( rProp
.Name
== "KeyModifier" )
753 rProp
.Value
>>= nModifier
;
755 aAddArgs
.push_back( aArgs
[n
] );
758 // Add needed arguments to sequence property value
759 sal_uInt32 nAddArgs
= aAddArgs
.size();
762 sal_uInt32
nIndex( lNewArgs
.getLength() );
764 lNewArgs
.realloc( lNewArgs
.getLength()+aAddArgs
.size() );
765 for ( sal_uInt32 i
= 0; i
< nAddArgs
; i
++ )
766 lNewArgs
[nIndex
++] = aAddArgs
[i
];
769 // Overwrite possible detected sychron argument, if real listener exists (currently no other way)
770 if ( rListener
.is() )
771 nCall
= SfxCallMode::SYNCHRON
;
773 if( GetId() == SID_JUMPTOMARK
&& nMarkArg
== - 1 )
775 // we offer dispatches for SID_JUMPTOMARK if the URL points to a bookmark inside the document
776 // so we must retrieve this as an argument from the parsed URL
777 lNewArgs
.realloc( lNewArgs
.getLength()+1 );
778 nMarkArg
= lNewArgs
.getLength()-1;
779 lNewArgs
[nMarkArg
].Name
= "Bookmark";
780 lNewArgs
[nMarkArg
].Value
<<= aURL
.Mark
;
783 css::uno::Reference
< css::frame::XFrame
> xFrameRef(xFrame
.get(), css::uno::UNO_QUERY
);
784 if (! xFrameRef
.is() && pDispatcher
)
786 SfxViewFrame
* pViewFrame
= pDispatcher
->GetFrame();
788 xFrameRef
= pViewFrame
->GetFrame().GetFrameInterface();
791 bool bSuccess
= false;
792 const SfxPoolItem
* pItem
= NULL
;
793 SfxMapUnit
eMapUnit( SFX_MAPUNIT_100TH_MM
);
795 // Extra scope so that aInternalSet is destroyed before
796 // rListener->dispatchFinished potentially calls
797 // framework::Desktop::terminate -> SfxApplication::Deinitialize ->
801 SfxAllItemSet
aInternalSet( SfxGetpApp()->GetPool() );
802 if (xFrameRef
.is()) // an empty set is no problem ... but an empty frame reference can be a problem !
803 aInternalSet
.Put( SfxUnoFrameItem( SID_FILLFRAME
, xFrameRef
) );
805 SfxShell
* pShell( 0 );
806 // #i102619# Retrieve metric from shell before execution - the shell could be destroyed after execution
807 if ( pDispatcher
->GetBindings() )
809 if ( !pDispatcher
->IsLocked( GetId() ) )
811 const SfxSlot
*pSlot
= 0;
812 if ( pDispatcher
->GetShellAndSlot_Impl( GetId(), &pShell
, &pSlot
, false,
813 SfxCallMode::MODAL
==(nCall
&SfxCallMode::MODAL
), false ) )
817 // Extract slave command and add argument to the args list. Master slot MUST
818 // have a argument that has the same name as the master slot and type is SfxStringItem.
819 sal_Int32 nIndex
= lNewArgs
.getLength();
820 lNewArgs
.realloc( nIndex
+1 );
821 lNewArgs
[nIndex
].Name
= OUString::createFromAscii( pSlot
->pUnoName
);
822 lNewArgs
[nIndex
].Value
= makeAny( SfxDispatchController_Impl::getSlaveCommand( aDispatchURL
));
825 eMapUnit
= GetCoreMetric( pShell
->GetPool(), GetId() );
826 boost::scoped_ptr
<SfxAllItemSet
> xSet(new SfxAllItemSet(pShell
->GetPool()));
827 TransformParameters(GetId(), lNewArgs
, *xSet
, pSlot
);
830 // execute with arguments - call directly
831 pItem
= pDispatcher
->Execute(GetId(), nCall
, xSet
.get(), &aInternalSet
, nModifier
);
832 bSuccess
= (pItem
!= NULL
);
836 // Be sure to delete this before we send a dispatch
837 // request, which will destroy the current shell.
840 // execute using bindings, enables support for toggle/enum etc.
841 SfxRequest
aReq( GetId(), nCall
, pShell
->GetPool() );
842 aReq
.SetModifier( nModifier
);
843 aReq
.SetInternalArgs_Impl(aInternalSet
);
844 pDispatcher
->GetBindings()->Execute_Impl( aReq
, pSlot
, pShell
);
845 pItem
= aReq
.GetReturnValue();
846 bSuccess
= aReq
.IsDone() || pItem
!= NULL
;
851 DBG_WARNING("MacroPlayer: Unknown slot dispatched!");
857 eMapUnit
= GetCoreMetric( SfxGetpApp()->GetPool(), GetId() );
859 SfxAllItemSet
aSet( SfxGetpApp()->GetPool() );
860 TransformParameters( GetId(), lNewArgs
, aSet
);
863 pItem
= pDispatcher
->Execute( GetId(), nCall
, &aSet
, &aInternalSet
, nModifier
);
865 // SfxRequests take empty sets as argument sets, GetArgs() returning non-zero!
866 pItem
= pDispatcher
->Execute( GetId(), nCall
, 0, &aInternalSet
, nModifier
);
868 // no bindings, no invalidate ( usually done in SfxDispatcher::Call_Impl()! )
869 if ( SfxApplication::Get() )
871 SfxDispatcher
* pAppDispat
= SfxGetpApp()->GetAppDispatcher_Impl();
874 const SfxPoolItem
* pState
=0;
875 SfxItemState eState
= pDispatcher
->QueryState( GetId(), pState
);
876 StateChanged( GetId(), eState
, pState
);
880 bSuccess
= (pItem
!= NULL
);
884 if ( rListener
.is() )
886 ::com::sun::star::frame::DispatchResultEvent aEvent
;
888 aEvent
.State
= com::sun::star::frame::DispatchResultState::SUCCESS
;
890 aEvent
.State
= com::sun::star::frame::DispatchResultState::FAILURE
;
892 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) pDispatch
;
893 if ( bSuccess
&& pItem
&& !pItem
->ISA(SfxVoidItem
) )
895 sal_uInt16
nSubId( 0 );
896 if ( eMapUnit
== SFX_MAPUNIT_TWIP
)
897 nSubId
|= CONVERT_TWIPS
;
898 pItem
->QueryValue( aEvent
.Result
, (sal_uInt8
)nSubId
);
901 rListener
->dispatchFinished( aEvent
);
906 SfxDispatcher
* SfxDispatchController_Impl::GetDispatcher()
908 if ( !pDispatcher
&& pBindings
)
909 pDispatcher
= GetBindings().GetDispatcher_Impl();
913 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
)
915 SolarMutexGuard aGuard
;
919 // Use alternative QueryState call to have a valid UNO representation of the state.
920 ::com::sun::star::uno::Any aState
;
921 if ( !pDispatcher
&& pBindings
)
922 pDispatcher
= GetBindings().GetDispatcher_Impl();
923 SfxItemState eState
= pDispatcher
? pDispatcher
->QueryState( GetId(), aState
) : SfxItemState::DONTCARE
;
925 if ( eState
== SfxItemState::DONTCARE
)
927 // Use special uno struct to transport don't care state
928 ::com::sun::star::frame::status::ItemStatus aItemStatus
;
929 aItemStatus
.State
= ::com::sun::star::frame::status::ItemState::DONT_CARE
;
930 aState
= makeAny( aItemStatus
);
933 ::com::sun::star::frame::FeatureStateEvent aEvent
;
934 aEvent
.FeatureURL
= aURL
;
935 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) pDispatch
;
936 aEvent
.Requery
= sal_False
;
939 aEvent
.IsEnabled
= eState
!= SfxItemState::DISABLED
;
940 aEvent
.State
= aState
;
944 ::com::sun::star::frame::status::Visibility aVisibilityStatus
;
945 aVisibilityStatus
.bVisible
= sal_False
;
947 // MBA: we might decide to *not* disable "invisible" slots, but this would be
948 // a change that needs to adjust at least the testtool
949 aEvent
.IsEnabled
= sal_False
;
950 aEvent
.State
= makeAny( aVisibilityStatus
);
953 aListener
->statusChanged( aEvent
);
956 void SfxDispatchController_Impl::StateChanged( sal_uInt16 nSID
, SfxItemState eState
, const SfxPoolItem
* pState
, SfxSlotServer
* pSlotServ
)
961 // Bindings instance notifies controller about a state change, listeners must be notified also
962 // Don't cache visibility state changes as they are volatile. We need our real state to send it
963 // to our controllers after visibility is set to true.
965 if ( pState
&& !IsInvalidItem( pState
) )
967 if ( !pState
->ISA( SfxVisibilityItem
) )
969 if (pLastState
&& !IsInvalidItem(pLastState
))
971 bNotify
= pState
->Type() != pLastState
->Type() || *pState
!= *pLastState
;
974 pLastState
= !IsInvalidItem(pState
) ? pState
->Clone() : pState
;
978 bVisible
= static_cast<const SfxVisibilityItem
*>(pState
)->GetValue();
982 if ( pLastState
&& !IsInvalidItem( pLastState
) )
989 ::com::sun::star::uno::Any aState
;
990 if ( ( eState
>= SfxItemState::DEFAULT
) && pState
&& !IsInvalidItem( pState
) && !pState
->ISA(SfxVoidItem
) )
992 // Retrieve metric from pool to have correct sub ID when calling QueryValue
993 sal_uInt16
nSubId( 0 );
994 SfxMapUnit
eMapUnit( SFX_MAPUNIT_100TH_MM
);
996 // retrieve the core metric
997 // it's enough to check the objectshell, the only shell that does not use the pool of the document
998 // is SfxViewFrame, but it hasn't any metric parameters
999 // TODO/LATER: what about the FormShell? Does it use any metric data?! Perhaps it should use the Pool of the document!
1000 if ( pSlotServ
&& pDispatcher
)
1002 SfxShell
* pShell
= pDispatcher
->GetShell( pSlotServ
->GetShellLevel() );
1003 DBG_ASSERT( pShell
, "Can't get core metric without shell!" );
1005 eMapUnit
= GetCoreMetric( pShell
->GetPool(), nSID
);
1008 if ( eMapUnit
== SFX_MAPUNIT_TWIP
)
1009 nSubId
|= CONVERT_TWIPS
;
1011 pState
->QueryValue( aState
, (sal_uInt8
)nSubId
);
1013 else if ( eState
== SfxItemState::DONTCARE
)
1015 // Use special uno struct to transport don't care state
1016 ::com::sun::star::frame::status::ItemStatus aItemStatus
;
1017 aItemStatus
.State
= ::com::sun::star::frame::status::ItemState::DONT_CARE
;
1018 aState
= makeAny( aItemStatus
);
1021 ::com::sun::star::frame::FeatureStateEvent aEvent
;
1022 aEvent
.FeatureURL
= aDispatchURL
;
1023 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) pDispatch
;
1024 aEvent
.IsEnabled
= eState
!= SfxItemState::DISABLED
;
1025 aEvent
.Requery
= sal_False
;
1026 aEvent
.State
= aState
;
1028 if (pDispatcher
&& pDispatcher
->GetFrame())
1030 InterceptLOKStateChangeEvent(
1031 pDispatcher
->GetFrame()->GetObjectShell(), aEvent
);
1034 ::cppu::OInterfaceContainerHelper
* pContnr
= pDispatch
->GetListeners().getContainer ( aDispatchURL
.Complete
);
1036 ::cppu::OInterfaceIteratorHelper
aIt( *pContnr
);
1037 while( aIt
.hasMoreElements() )
1041 static_cast< ::com::sun::star::frame::XStatusListener
*>(aIt
.next())->statusChanged( aEvent
);
1043 catch (const ::com::sun::star::uno::RuntimeException
&)
1052 void SfxDispatchController_Impl::StateChanged( sal_uInt16 nSID
, SfxItemState eState
, const SfxPoolItem
* pState
)
1054 StateChanged( nSID
, eState
, pState
, 0 );
1057 void SfxDispatchController_Impl::InterceptLOKStateChangeEvent(const SfxObjectShell
* objSh
, const ::com::sun::star::frame::FeatureStateEvent
& aEvent
)
1059 if (!objSh
|| !objSh
->isTiledRendering())
1062 if (aEvent
.FeatureURL
.Path
== "Bold" ||
1063 aEvent
.FeatureURL
.Path
== "Italic" ||
1064 aEvent
.FeatureURL
.Path
== "Underline" ||
1065 aEvent
.FeatureURL
.Path
== "Strikeout")
1068 OUStringBuffer aBuffer
;
1069 aBuffer
.append(aEvent
.FeatureURL
.Complete
);
1070 aBuffer
.append("=");
1072 aEvent
.State
>>= bTemp
;
1073 aBuffer
.append(bTemp
);
1075 OUString payload
= aBuffer
.makeStringAndClear();
1076 objSh
->libreOfficeKitCallback(LOK_CALLBACK_STATE_CHANGED
, payload
.toUtf8().getStr());
1080 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */