Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
21 : #include <tools/debug.hxx>
22 : #include <svl/eitem.hxx>
23 : #include <svl/stritem.hxx>
24 : #include <svl/intitem.hxx>
25 : #include <svl/itemset.hxx>
26 : #include <svl/visitem.hxx>
27 : #include <svtools/javacontext.hxx>
28 : #include <svl/itempool.hxx>
29 : #include <tools/urlobj.hxx>
30 : #include <com/sun/star/util/URLTransformer.hpp>
31 : #include <com/sun/star/util/XURLTransformer.hpp>
32 : #include <com/sun/star/frame/XController.hpp>
33 : #include <com/sun/star/frame/XFrameActionListener.hpp>
34 : #include <com/sun/star/frame/XComponentLoader.hpp>
35 : #include <com/sun/star/frame/XFrame.hpp>
36 : #include <com/sun/star/frame/FrameActionEvent.hpp>
37 : #include <com/sun/star/frame/FrameAction.hpp>
38 : #include <com/sun/star/frame/status/ItemStatus.hpp>
39 : #include <com/sun/star/frame/status/ItemState.hpp>
40 : #include <com/sun/star/frame/DispatchResultState.hpp>
41 : #include <com/sun/star/frame/status/Visibility.hpp>
42 : #include <comphelper/processfactory.hxx>
43 : #include <comphelper/sequence.hxx>
44 : #include <osl/mutex.hxx>
45 : #include <uno/current_context.hxx>
46 : #include <vcl/svapp.hxx>
47 :
48 : #include <sfx2/app.hxx>
49 : #include <sfx2/unoctitm.hxx>
50 : #include <sfx2/viewfrm.hxx>
51 : #include <sfx2/frame.hxx>
52 : #include <sfx2/ctrlitem.hxx>
53 : #include <sfx2/sfxuno.hxx>
54 : #include <sfx2/bindings.hxx>
55 : #include <sfx2/dispatch.hxx>
56 : #include <sfx2/sfxsids.hrc>
57 : #include <sfx2/request.hxx>
58 : #include "statcach.hxx"
59 : #include <sfx2/msgpool.hxx>
60 : #include <sfx2/objsh.hxx>
61 :
62 : #include <boost/scoped_ptr.hpp>
63 :
64 : using namespace ::com::sun::star::uno;
65 : using namespace ::com::sun::star::util;
66 :
67 : enum URLTypeId
68 : {
69 : URLType_BOOL,
70 : URLType_BYTE,
71 : URLType_SHORT,
72 : URLType_LONG,
73 : URLType_HYPER,
74 : URLType_STRING,
75 : URLType_FLOAT,
76 : URLType_DOUBLE,
77 : URLType_COUNT
78 : };
79 :
80 : const char* URLTypeNames[URLType_COUNT] =
81 : {
82 : "bool",
83 : "byte",
84 : "short",
85 : "long",
86 : "hyper",
87 : "string",
88 : "float",
89 : "double"
90 : };
91 :
92 0 : SFX_IMPL_XINTERFACE_2( SfxUnoControllerItem, OWeakObject, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener )
93 0 : SFX_IMPL_XTYPEPROVIDER_2( SfxUnoControllerItem, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener )
94 :
95 0 : SfxUnoControllerItem::SfxUnoControllerItem( SfxControllerItem *pItem, SfxBindings& rBind, const String& rCmd )
96 : : pCtrlItem( pItem )
97 0 : , pBindings( &rBind )
98 : {
99 : DBG_ASSERT( !pCtrlItem || !pCtrlItem->IsBound(), "ControllerItem is incorrect!" );
100 :
101 0 : aCommand.Complete = rCmd;
102 0 : Reference< XURLTransformer > xTrans( URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
103 0 : xTrans->parseStrict( aCommand );
104 0 : pBindings->RegisterUnoController_Impl( this );
105 0 : }
106 :
107 0 : SfxUnoControllerItem::~SfxUnoControllerItem()
108 : {
109 : // tell bindings to forget this controller ( if still connected )
110 0 : if ( pBindings )
111 0 : pBindings->ReleaseUnoController_Impl( this );
112 0 : }
113 :
114 0 : void SfxUnoControllerItem::UnBind()
115 : {
116 : // connection to SfxControllerItem is lost
117 0 : pCtrlItem = NULL;
118 0 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY );
119 0 : ReleaseDispatch();
120 0 : }
121 :
122 0 : void SAL_CALL SfxUnoControllerItem::statusChanged(const ::com::sun::star::frame::FeatureStateEvent& rEvent) throw ( ::com::sun::star::uno::RuntimeException )
123 : {
124 0 : SolarMutexGuard aGuard;
125 : DBG_ASSERT( pCtrlItem, "dispatch implementation didn't respect our previous removeStatusListener call!" );
126 :
127 0 : if ( rEvent.Requery )
128 : {
129 : // Error can only happen if the old Dispatch is implemented incorrectly
130 : // i.e. removeStatusListener did not work. But such things can happen...
131 : // So protect before ReleaseDispatch from release!
132 0 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY );
133 0 : ReleaseDispatch();
134 0 : if ( pCtrlItem )
135 0 : GetNewDispatch(); // asynchronous ??
136 : }
137 0 : else if ( pCtrlItem )
138 : {
139 0 : SfxItemState eState = SFX_ITEM_DISABLED;
140 0 : SfxPoolItem* pItem = NULL;
141 0 : if ( rEvent.IsEnabled )
142 : {
143 0 : eState = SFX_ITEM_AVAILABLE;
144 0 : ::com::sun::star::uno::Type pType = rEvent.State.getValueType();
145 :
146 0 : if ( pType == ::getBooleanCppuType() )
147 : {
148 0 : sal_Bool bTemp = false;
149 0 : rEvent.State >>= bTemp ;
150 0 : pItem = new SfxBoolItem( pCtrlItem->GetId(), bTemp );
151 : }
152 0 : else if ( pType == ::getCppuType((const sal_uInt16*)0) )
153 : {
154 0 : sal_uInt16 nTemp = 0;
155 0 : rEvent.State >>= nTemp ;
156 0 : pItem = new SfxUInt16Item( pCtrlItem->GetId(), nTemp );
157 : }
158 0 : else if ( pType == ::getCppuType((const sal_uInt32*)0) )
159 : {
160 0 : sal_uInt32 nTemp = 0;
161 0 : rEvent.State >>= nTemp ;
162 0 : pItem = new SfxUInt32Item( pCtrlItem->GetId(), nTemp );
163 : }
164 0 : else if ( pType == ::getCppuType((const OUString*)0) )
165 : {
166 0 : OUString sTemp ;
167 0 : rEvent.State >>= sTemp ;
168 0 : pItem = new SfxStringItem( pCtrlItem->GetId(), sTemp );
169 : }
170 : else
171 0 : pItem = new SfxVoidItem( pCtrlItem->GetId() );
172 : }
173 :
174 0 : pCtrlItem->StateChanged( pCtrlItem->GetId(), eState, pItem );
175 0 : delete pItem;
176 0 : }
177 0 : }
178 :
179 0 : void SAL_CALL SfxUnoControllerItem::disposing( const ::com::sun::star::lang::EventObject& ) throw ( ::com::sun::star::uno::RuntimeException )
180 : {
181 0 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY );
182 0 : ReleaseDispatch();
183 0 : }
184 :
185 0 : void SfxUnoControllerItem::ReleaseDispatch()
186 : {
187 0 : if ( xDispatch.is() )
188 : {
189 0 : xDispatch->removeStatusListener( (::com::sun::star::frame::XStatusListener*) this, aCommand );
190 0 : xDispatch = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > ();
191 : }
192 0 : }
193 :
194 0 : void SfxUnoControllerItem::GetNewDispatch()
195 : {
196 0 : if ( !pBindings )
197 : {
198 : // Bindings released
199 : OSL_FAIL( "Tried to get dispatch, but no Bindings!" );
200 0 : return;
201 : }
202 :
203 : // forget old dispatch
204 0 : xDispatch = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > ();
205 :
206 : // no arms, no cookies !
207 0 : if ( !pBindings->GetDispatcher_Impl() || !pBindings->GetDispatcher_Impl()->GetFrame() )
208 0 : return;
209 :
210 0 : SfxFrame& rFrame = pBindings->GetDispatcher_Impl()->GetFrame()->GetFrame();
211 0 : SfxFrame *pParent = rFrame.GetParentFrame();
212 0 : if ( pParent )
213 : // parent may intercept
214 0 : xDispatch = TryGetDispatch( pParent );
215 :
216 0 : if ( !xDispatch.is() )
217 : {
218 : // no interception
219 0 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame = rFrame.GetFrameInterface();
220 0 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv( xFrame, ::com::sun::star::uno::UNO_QUERY );
221 0 : if ( xProv.is() )
222 0 : xDispatch = xProv->queryDispatch( aCommand, OUString(), 0 );
223 : }
224 :
225 0 : if ( xDispatch.is() )
226 0 : xDispatch->addStatusListener( (::com::sun::star::frame::XStatusListener*) this, aCommand );
227 0 : else if ( pCtrlItem )
228 0 : pCtrlItem->StateChanged( pCtrlItem->GetId(), SFX_ITEM_DISABLED, NULL );
229 : }
230 :
231 0 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > SfxUnoControllerItem::TryGetDispatch( SfxFrame *pFrame )
232 : {
233 0 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
234 0 : SfxFrame *pParent = pFrame->GetParentFrame();
235 0 : if ( pParent )
236 : // parent may intercept
237 0 : xDisp = TryGetDispatch( pParent );
238 :
239 : // only components may intercept
240 0 : if ( !xDisp.is() && pFrame->HasComponent() )
241 : {
242 : // no interception
243 0 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame = pFrame->GetFrameInterface();
244 0 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv( xFrame, ::com::sun::star::uno::UNO_QUERY );
245 0 : if ( xProv.is() )
246 0 : xDisp = xProv->queryDispatch( aCommand, OUString(), 0 );
247 : }
248 :
249 0 : return xDisp;
250 : }
251 :
252 0 : void SfxUnoControllerItem::ReleaseBindings()
253 : {
254 : // connection to binding is lost; so forget the binding and the dispatch
255 0 : ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY );
256 0 : ReleaseDispatch();
257 0 : if ( pBindings )
258 0 : pBindings->ReleaseUnoController_Impl( this );
259 0 : pBindings = NULL;
260 0 : }
261 :
262 83 : void SfxStatusDispatcher::ReleaseAll()
263 : {
264 83 : ::com::sun::star::lang::EventObject aObject;
265 83 : aObject.Source = (::cppu::OWeakObject*) this;
266 83 : aListeners.disposeAndClear( aObject );
267 83 : }
268 :
269 0 : 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 )
270 : {
271 0 : }
272 :
273 0 : void SAL_CALL SfxStatusDispatcher::dispatchWithNotification(
274 : const ::com::sun::star::util::URL&,
275 : const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >&,
276 : const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchResultListener >& ) throw( ::com::sun::star::uno::RuntimeException )
277 : {
278 0 : }
279 :
280 2652885 : SFX_IMPL_XINTERFACE_2( SfxStatusDispatcher, OWeakObject, ::com::sun::star::frame::XNotifyingDispatch, ::com::sun::star::frame::XDispatch )
281 0 : SFX_IMPL_XTYPEPROVIDER_2( SfxStatusDispatcher, ::com::sun::star::frame::XNotifyingDispatch, ::com::sun::star::frame::XDispatch )
282 : //IMPLNAME "com.sun.star.comp.sfx2.StatusDispatcher",
283 :
284 55641 : SfxStatusDispatcher::SfxStatusDispatcher()
285 55641 : : aListeners( aMutex )
286 : {
287 55641 : }
288 :
289 0 : 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 )
290 : {
291 0 : aListeners.addInterface( aURL.Complete, aListener );
292 0 : if ( aURL.Complete.compareToAscii(".uno:LifeTime")==0 )
293 : {
294 0 : ::com::sun::star::frame::FeatureStateEvent aEvent;
295 0 : aEvent.FeatureURL = aURL;
296 0 : aEvent.Source = (::com::sun::star::frame::XDispatch*) this;
297 0 : aEvent.IsEnabled = sal_True;
298 0 : aEvent.Requery = sal_False;
299 0 : aListener->statusChanged( aEvent );
300 : }
301 0 : }
302 :
303 58473 : 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 )
304 : {
305 58473 : aListeners.removeInterface( aURL.Complete, aListener );
306 58473 : }
307 :
308 2745567 : SFX_IMPL_XINTERFACE_1( SfxOfficeDispatch, SfxStatusDispatcher, ::com::sun::star::lang::XUnoTunnel )
309 0 : SFX_IMPL_XTYPEPROVIDER_2( SfxOfficeDispatch, ::com::sun::star::frame::XNotifyingDispatch, ::com::sun::star::lang::XUnoTunnel )
310 :
311 :
312 : //-------------------------------------------------------------------------
313 : // XUnoTunnel
314 93064 : sal_Int64 SAL_CALL SfxOfficeDispatch::getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) throw(::com::sun::star::uno::RuntimeException)
315 : {
316 93064 : if ( aIdentifier == impl_getStaticIdentifier() )
317 93064 : return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >( this ));
318 : else
319 0 : return 0;
320 : }
321 :
322 55332 : SfxOfficeDispatch::SfxOfficeDispatch( SfxBindings& rBindings, SfxDispatcher* pDispat, const SfxSlot* pSlot, const ::com::sun::star::util::URL& rURL )
323 : {
324 : // this object is an adapter that shows a ::com::sun::star::frame::XDispatch-Interface to the outside and uses a SfxControllerItem to monitor a state
325 55332 : pControllerItem = new SfxDispatchController_Impl( this, &rBindings, pDispat, pSlot, rURL );
326 55332 : }
327 :
328 176 : SfxOfficeDispatch::SfxOfficeDispatch( SfxDispatcher* pDispat, const SfxSlot* pSlot, const ::com::sun::star::util::URL& rURL )
329 : {
330 : // this object is an adapter that shows a ::com::sun::star::frame::XDispatch-Interface to the outside and uses a SfxControllerItem to monitor a state
331 176 : pControllerItem = new SfxDispatchController_Impl( this, NULL, pDispat, pSlot, rURL );
332 176 : }
333 :
334 166524 : SfxOfficeDispatch::~SfxOfficeDispatch()
335 : {
336 55508 : if ( pControllerItem )
337 : {
338 : // when dispatch object is released, destroy its connection to this object and destroy it
339 55508 : pControllerItem->UnBindController();
340 55508 : delete pControllerItem;
341 : }
342 111016 : }
343 :
344 186128 : const ::com::sun::star::uno::Sequence< sal_Int8 >& SfxOfficeDispatch::impl_getStaticIdentifier()
345 : {
346 : // {38 57 CA 80 09 36 11 d4 83 FE 00 50 04 52 6B 21}
347 : static sal_uInt8 pGUID[16] = { 0x38, 0x57, 0xCA, 0x80, 0x09, 0x36, 0x11, 0xd4, 0x83, 0xFE, 0x00, 0x50, 0x04, 0x52, 0x6B, 0x21 };
348 186128 : static ::com::sun::star::uno::Sequence< sal_Int8 > seqID((sal_Int8*)pGUID,16) ;
349 186128 : return seqID ;
350 : }
351 :
352 :
353 179 : 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 )
354 : {
355 : // ControllerItem is the Impl class
356 179 : if ( pControllerItem )
357 : {
358 : #ifdef SOLAR_JAVA
359 : // The JavaContext contains an interaction handler which is used when
360 : // the creation of a Java Virtual Machine fails. The second parameter
361 : // indicates, that there shall only be one user notification (message box)
362 : // even if the same error (interaction) reoccurs. The effect is, that if a
363 : // user selects a menu entry than they may get only one notification that
364 : // a JRE is not selected.
365 : com::sun::star::uno::ContextLayer layer(
366 : new svt::JavaContext( com::sun::star::uno::getCurrentContext(),
367 179 : true) );
368 : #endif
369 179 : pControllerItem->dispatch( aURL, aArgs, ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchResultListener >() );
370 : }
371 179 : }
372 :
373 5 : void SAL_CALL SfxOfficeDispatch::dispatchWithNotification( const ::com::sun::star::util::URL& aURL,
374 : const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs,
375 : const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchResultListener >& rListener ) throw( ::com::sun::star::uno::RuntimeException )
376 : {
377 : // ControllerItem is the Impl class
378 5 : if ( pControllerItem )
379 : {
380 : #ifdef SOLAR_JAVA
381 : // see comment for SfxOfficeDispatch::dispatch
382 : com::sun::star::uno::ContextLayer layer(
383 : new svt::JavaContext( com::sun::star::uno::getCurrentContext(),
384 5 : true) );
385 : #endif
386 5 : pControllerItem->dispatch( aURL, aArgs, rListener );
387 : }
388 5 : }
389 :
390 56603 : 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 )
391 : {
392 56603 : GetListeners().addInterface( aURL.Complete, aListener );
393 56603 : if ( pControllerItem )
394 : {
395 : // ControllerItem is the Impl class
396 56603 : pControllerItem->addStatusListener( aListener, aURL );
397 : }
398 56603 : }
399 :
400 93064 : SfxDispatcher* SfxOfficeDispatch::GetDispatcher_Impl()
401 : {
402 93064 : return pControllerItem->GetDispatcher();
403 : }
404 :
405 72 : void SfxOfficeDispatch::SetFrame(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame)
406 : {
407 72 : if ( pControllerItem )
408 72 : pControllerItem->SetFrame( xFrame );
409 72 : }
410 :
411 55508 : void SfxOfficeDispatch::SetMasterUnoCommand( sal_Bool bSet )
412 : {
413 55508 : if ( pControllerItem )
414 55508 : pControllerItem->setMasterSlaveCommand( bSet );
415 55508 : }
416 :
417 : // Determine if URL contains a master/slave command which must be handled a little bit different
418 153565 : sal_Bool SfxOfficeDispatch::IsMasterUnoCommand( const ::com::sun::star::util::URL& aURL )
419 : {
420 153565 : if ( aURL.Protocol == ".uno:" && ( aURL.Path.indexOf( '.' ) > 0 ))
421 104 : return sal_True;
422 :
423 153461 : return sal_False;
424 : }
425 :
426 151389 : OUString SfxOfficeDispatch::GetMasterUnoCommand( const ::com::sun::star::util::URL& aURL )
427 : {
428 151389 : OUString aMasterCommand;
429 151389 : if ( IsMasterUnoCommand( aURL ))
430 : {
431 104 : sal_Int32 nIndex = aURL.Path.indexOf( '.' );
432 104 : if ( nIndex > 0 )
433 104 : aMasterCommand = aURL.Path.copy( 0, nIndex );
434 : }
435 :
436 151389 : return aMasterCommand;
437 : }
438 :
439 55508 : SfxDispatchController_Impl::SfxDispatchController_Impl(
440 : SfxOfficeDispatch* pDisp,
441 : SfxBindings* pBind,
442 : SfxDispatcher* pDispat,
443 : const SfxSlot* pSlot,
444 : const ::com::sun::star::util::URL& rURL )
445 : : aDispatchURL( rURL )
446 : , pDispatcher( pDispat )
447 : , pBindings( pBind )
448 : , pLastState( 0 )
449 55508 : , nSlot( pSlot->GetSlotId() )
450 : , pDispatch( pDisp )
451 : , bMasterSlave( sal_False )
452 : , bVisible( sal_True )
453 111016 : , pUnoName( pSlot->pUnoName )
454 : {
455 55508 : if ( aDispatchURL.Protocol == "slot:" && pUnoName )
456 : {
457 0 : OStringBuffer aTmp(RTL_CONSTASCII_STRINGPARAM(".uno:"));
458 0 : aTmp.append(pUnoName);
459 0 : aDispatchURL.Complete = OStringToOUString(aTmp.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US);
460 0 : Reference< XURLTransformer > xTrans( URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
461 0 : xTrans->parseStrict( aDispatchURL );
462 : }
463 :
464 55508 : SetId( nSlot );
465 55508 : if ( pBindings )
466 : {
467 : // Bind immediately to enable the cache to recycle dispatches when asked for the same command
468 : // a command in "slot" or in ".uno" notation must be treated as identical commands!
469 55332 : pBindings->ENTERREGISTRATIONS();
470 55332 : BindInternal_Impl( nSlot, pBindings );
471 55332 : pBindings->LEAVEREGISTRATIONS();
472 : }
473 55508 : }
474 :
475 166524 : SfxDispatchController_Impl::~SfxDispatchController_Impl()
476 : {
477 55508 : if ( pLastState && !IsInvalidItem( pLastState ) )
478 26010 : delete pLastState;
479 :
480 55508 : if ( pDispatch )
481 : {
482 : // disconnect
483 0 : pDispatch->pControllerItem = NULL;
484 :
485 : // force all listeners to release the dispatch object
486 0 : ::com::sun::star::lang::EventObject aObject;
487 0 : aObject.Source = (::cppu::OWeakObject*) pDispatch;
488 0 : pDispatch->GetListeners().disposeAndClear( aObject );
489 : }
490 111016 : }
491 :
492 72 : void SfxDispatchController_Impl::SetFrame(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& _xFrame)
493 : {
494 72 : xFrame = _xFrame;
495 72 : }
496 :
497 55508 : void SfxDispatchController_Impl::setMasterSlaveCommand( sal_Bool bSet )
498 : {
499 55508 : bMasterSlave = bSet;
500 55508 : }
501 :
502 55508 : void SfxDispatchController_Impl::UnBindController()
503 : {
504 55508 : pDispatch = NULL;
505 55508 : if ( IsBound() )
506 : {
507 0 : GetBindings().ENTERREGISTRATIONS();
508 0 : SfxControllerItem::UnBind();
509 0 : GetBindings().LEAVEREGISTRATIONS();
510 : }
511 55508 : }
512 :
513 0 : void SfxDispatchController_Impl::addParametersToArgs( const com::sun::star::util::URL& aURL, ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rArgs ) const
514 : {
515 : // Extract the parameter from the URL and put them into the property value sequence
516 0 : sal_Int32 nQueryIndex = aURL.Complete.indexOf( '?' );
517 0 : if ( nQueryIndex > 0 )
518 : {
519 0 : OUString aParamString( aURL.Complete.copy( nQueryIndex+1 ));
520 0 : sal_Int32 nIndex = 0;
521 0 : do
522 : {
523 0 : OUString aToken = aParamString.getToken( 0, '&', nIndex );
524 :
525 0 : sal_Int32 nParmIndex = 0;
526 0 : OUString aParamType;
527 0 : OUString aParamName = aToken.getToken( 0, '=', nParmIndex );
528 0 : OUString aValue = (nParmIndex!=-1) ? aToken.getToken( 0, '=', nParmIndex ) : OUString();
529 :
530 0 : if ( !aParamName.isEmpty() )
531 : {
532 0 : nParmIndex = 0;
533 0 : aToken = aParamName;
534 0 : aParamName = (nParmIndex!=-1) ? aToken.getToken( 0, ':', nParmIndex ) : OUString();
535 0 : aParamType = (nParmIndex!=-1) ? aToken.getToken( 0, ':', nParmIndex ) : OUString();
536 : }
537 :
538 0 : sal_Int32 nLen = rArgs.getLength();
539 0 : rArgs.realloc( nLen+1 );
540 0 : rArgs[nLen].Name = aParamName;
541 :
542 0 : if ( aParamType.isEmpty() )
543 : {
544 : // Default: LONG
545 0 : rArgs[nLen].Value <<= aValue.toInt32();
546 : }
547 0 : else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_BOOL], 4 ))
548 : {
549 : // sal_Bool support
550 0 : rArgs[nLen].Value <<= aValue.toBoolean();
551 : }
552 0 : else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_BYTE], 4 ))
553 : {
554 : // sal_uInt8 support
555 0 : rArgs[nLen].Value <<= sal_Int8( aValue.toInt32() );
556 : }
557 0 : else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_LONG], 4 ))
558 : {
559 : // LONG support
560 0 : rArgs[nLen].Value <<= aValue.toInt32();
561 : }
562 0 : else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_SHORT], 5 ))
563 : {
564 : // SHORT support
565 0 : rArgs[nLen].Value <<= sal_Int8( aValue.toInt32() );
566 : }
567 0 : else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_HYPER], 5 ))
568 : {
569 : // HYPER support
570 0 : rArgs[nLen].Value <<= aValue.toInt64();
571 : }
572 0 : else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_FLOAT], 5 ))
573 : {
574 : // FLOAT support
575 0 : rArgs[nLen].Value <<= aValue.toFloat();
576 : }
577 0 : else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_STRING], 6 ))
578 : {
579 : // STRING support
580 0 : rArgs[nLen].Value <<= OUString( INetURLObject::decode( aValue, '%', INetURLObject::DECODE_WITH_CHARSET ));
581 : }
582 0 : else if ( aParamType.equalsAsciiL( URLTypeNames[URLType_DOUBLE], 6))
583 : {
584 : // DOUBLE support
585 0 : rArgs[nLen].Value <<= aValue.toDouble();
586 0 : }
587 : }
588 0 : while ( nIndex >= 0 );
589 : }
590 0 : }
591 :
592 16343 : SfxMapUnit SfxDispatchController_Impl::GetCoreMetric( SfxItemPool& rPool, sal_uInt16 nSlotId )
593 : {
594 16343 : sal_uInt16 nWhich = rPool.GetWhich( nSlotId );
595 16343 : return rPool.GetMetric( nWhich );
596 : }
597 :
598 0 : OUString SfxDispatchController_Impl::getSlaveCommand( const ::com::sun::star::util::URL& rURL )
599 : {
600 0 : OUString aSlaveCommand;
601 0 : sal_Int32 nIndex = rURL.Path.indexOf( '.' );
602 0 : if (( nIndex > 0 ) && ( nIndex < rURL.Path.getLength() ))
603 0 : aSlaveCommand = rURL.Path.copy( nIndex+1 );
604 0 : return aSlaveCommand;
605 : }
606 :
607 184 : void SAL_CALL SfxDispatchController_Impl::dispatch( const ::com::sun::star::util::URL& aURL,
608 : const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs,
609 : const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchResultListener >& rListener ) throw( ::com::sun::star::uno::RuntimeException )
610 : {
611 184 : SolarMutexGuard aGuard;
612 184 : if (
613 552 : pDispatch &&
614 : (
615 368 : (aURL.Protocol.equalsAsciiL( ".uno:", 5 ) && aURL.Path == aDispatchURL.Path) ||
616 0 : (aURL.Protocol.equalsAsciiL( "slot:", 5 ) && aURL.Path.toInt32() == GetId())
617 : )
618 : )
619 : {
620 184 : if ( !pDispatcher && pBindings )
621 0 : pDispatcher = GetBindings().GetDispatcher_Impl();
622 :
623 184 : ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > lNewArgs;
624 184 : sal_Int32 nCount = aArgs.getLength();
625 :
626 : // Support for URL based arguments
627 368 : INetURLObject aURLObj( aURL.Complete );
628 184 : if ( aURLObj.HasParam() )
629 0 : addParametersToArgs( aURL, lNewArgs );
630 :
631 : // Try to find call mode and frame name inside given arguments...
632 184 : SfxCallMode nCall = SFX_CALLMODE_STANDARD;
633 184 : sal_Int32 nMarkArg = -1;
634 :
635 : // Filter arguments which shouldn't be part of the sequence property value
636 184 : sal_Bool bTemp = sal_Bool();
637 184 : sal_uInt16 nModifier(0);
638 368 : std::vector< ::com::sun::star::beans::PropertyValue > aAddArgs;
639 349 : for( sal_Int32 n=0; n<nCount; n++ )
640 : {
641 165 : const ::com::sun::star::beans::PropertyValue& rProp = aArgs[n];
642 165 : if( rProp.Name.equalsAsciiL("SynchronMode",12))
643 : {
644 5 : if( rProp.Value >>=bTemp )
645 5 : nCall = bTemp ? SFX_CALLMODE_SYNCHRON : SFX_CALLMODE_ASYNCHRON;
646 : }
647 160 : else if( rProp.Name.equalsAsciiL("Bookmark",8))
648 : {
649 0 : nMarkArg = n;
650 0 : aAddArgs.push_back( aArgs[n] );
651 : }
652 160 : else if( rProp.Name.equalsAsciiL("KeyModifier",11))
653 2 : rProp.Value >>= nModifier;
654 : else
655 158 : aAddArgs.push_back( aArgs[n] );
656 : }
657 :
658 : // Add needed arguments to sequence property value
659 184 : sal_uInt32 nAddArgs = aAddArgs.size();
660 184 : if ( nAddArgs > 0 )
661 : {
662 158 : sal_uInt32 nIndex( lNewArgs.getLength() );
663 :
664 158 : lNewArgs.realloc( lNewArgs.getLength()+aAddArgs.size() );
665 316 : for ( sal_uInt32 i = 0; i < nAddArgs; i++ )
666 158 : lNewArgs[nIndex++] = aAddArgs[i];
667 : }
668 :
669 : // Overwrite possible detected sychron argument, if real listener exists (currently no other way)
670 184 : if ( rListener.is() )
671 5 : nCall = SFX_CALLMODE_SYNCHRON;
672 :
673 184 : if( GetId() == SID_JUMPTOMARK && nMarkArg == - 1 )
674 : {
675 : // we offer dispatches for SID_JUMPTOMARK if the URL points to a bookmark inside the document
676 : // so we must retrieve this as an argument from the parsed URL
677 0 : lNewArgs.realloc( lNewArgs.getLength()+1 );
678 0 : nMarkArg = lNewArgs.getLength()-1;
679 0 : lNewArgs[nMarkArg].Name = OUString("Bookmark");
680 0 : lNewArgs[nMarkArg].Value <<= aURL.Mark;
681 : }
682 :
683 368 : css::uno::Reference< css::frame::XFrame > xFrameRef(xFrame.get(), css::uno::UNO_QUERY);
684 184 : if (! xFrameRef.is() && pDispatcher)
685 : {
686 184 : SfxViewFrame* pViewFrame = pDispatcher->GetFrame();
687 184 : if (pViewFrame)
688 184 : xFrameRef = pViewFrame->GetFrame().GetFrameInterface();
689 : }
690 368 : SfxAllItemSet aInternalSet( SFX_APP()->GetPool() );
691 184 : if (xFrameRef.is()) // an empty set is no problem ... but an empty frame reference can be a problem !
692 184 : aInternalSet.Put( SfxUnoFrameItem( SID_FILLFRAME, xFrameRef ) );
693 :
694 184 : sal_Bool bSuccess = sal_False;
695 184 : const SfxPoolItem* pItem = NULL;
696 184 : SfxShell* pShell( 0 );
697 : // #i102619# Retrieve metric from shell before execution - the shell could be destroyed after execution
698 184 : SfxMapUnit eMapUnit( SFX_MAPUNIT_100TH_MM );
699 184 : if ( pDispatcher->GetBindings() )
700 : {
701 184 : if ( !pDispatcher->IsLocked( GetId() ) )
702 : {
703 184 : const SfxSlot *pSlot = 0;
704 368 : if ( pDispatcher->GetShellAndSlot_Impl( GetId(), &pShell, &pSlot, sal_False,
705 368 : SFX_CALLMODE_MODAL==(nCall&SFX_CALLMODE_MODAL), sal_False ) )
706 : {
707 184 : if ( bMasterSlave )
708 : {
709 : // Extract slave command and add argument to the args list. Master slot MUST
710 : // have a argument that has the same name as the master slot and type is SfxStringItem.
711 0 : sal_Int32 nIndex = lNewArgs.getLength();
712 0 : lNewArgs.realloc( nIndex+1 );
713 0 : lNewArgs[nIndex].Name = OUString::createFromAscii( pSlot->pUnoName );
714 0 : lNewArgs[nIndex].Value = makeAny( SfxDispatchController_Impl::getSlaveCommand( aDispatchURL ));
715 : }
716 :
717 184 : eMapUnit = GetCoreMetric( pShell->GetPool(), GetId() );
718 184 : boost::scoped_ptr<SfxAllItemSet> xSet(new SfxAllItemSet(pShell->GetPool()));
719 184 : TransformParameters(GetId(), lNewArgs, *xSet, pSlot);
720 184 : if (xSet->Count())
721 : {
722 : // execute with arguments - call directly
723 158 : pItem = pDispatcher->Execute(GetId(), nCall, xSet.get(), &aInternalSet, nModifier);
724 158 : bSuccess = (pItem != NULL);
725 : }
726 : else
727 : {
728 : // Be sure to delete this before we send a dispatch
729 : // request, which will destroy the current shell.
730 26 : xSet.reset();
731 :
732 : // execute using bindings, enables support for toggle/enum etc.
733 26 : SfxRequest aReq( GetId(), nCall, pShell->GetPool() );
734 26 : aReq.SetModifier( nModifier );
735 26 : aReq.SetInternalArgs_Impl(aInternalSet);
736 26 : pDispatcher->GetBindings()->Execute_Impl( aReq, pSlot, pShell );
737 26 : pItem = aReq.GetReturnValue();
738 26 : bSuccess = aReq.IsDone() || pItem != NULL;
739 184 : }
740 : }
741 : #ifdef DBG_UTIL
742 : else
743 : DBG_WARNING("MacroPlayer: Unknown slot dispatched!");
744 : #endif
745 : }
746 : }
747 : else
748 : {
749 0 : eMapUnit = GetCoreMetric( SFX_APP()->GetPool(), GetId() );
750 : // AppDispatcher
751 0 : SfxAllItemSet aSet( SFX_APP()->GetPool() );
752 0 : TransformParameters( GetId(), lNewArgs, aSet );
753 :
754 0 : if ( aSet.Count() )
755 0 : pItem = pDispatcher->Execute( GetId(), nCall, &aSet, &aInternalSet, nModifier );
756 : else
757 : // SfxRequests take empty sets as argument sets, GetArgs() returning non-zero!
758 0 : pItem = pDispatcher->Execute( GetId(), nCall, 0, &aInternalSet, nModifier );
759 :
760 : // no bindings, no invalidate ( usually done in SfxDispatcher::Call_Impl()! )
761 0 : if ( SfxApplication::Get() )
762 : {
763 0 : SfxDispatcher* pAppDispat = SFX_APP()->GetAppDispatcher_Impl();
764 0 : if ( pAppDispat )
765 : {
766 0 : const SfxPoolItem* pState=0;
767 0 : SfxItemState eState = pDispatcher->QueryState( GetId(), pState );
768 0 : StateChanged( GetId(), eState, pState );
769 : }
770 : }
771 :
772 0 : bSuccess = (pItem != NULL);
773 : }
774 :
775 184 : if ( rListener.is() )
776 : {
777 5 : ::com::sun::star::frame::DispatchResultEvent aEvent;
778 5 : if ( bSuccess )
779 1 : aEvent.State = com::sun::star::frame::DispatchResultState::SUCCESS;
780 : else
781 4 : aEvent.State = com::sun::star::frame::DispatchResultState::FAILURE;
782 :
783 5 : aEvent.Source = (::com::sun::star::frame::XDispatch*) pDispatch;
784 5 : if ( bSuccess && pItem && !pItem->ISA(SfxVoidItem) )
785 : {
786 1 : sal_uInt16 nSubId( 0 );
787 1 : if ( eMapUnit == SFX_MAPUNIT_TWIP )
788 0 : nSubId |= CONVERT_TWIPS;
789 1 : pItem->QueryValue( aEvent.Result, (sal_uInt8)nSubId );
790 : }
791 :
792 5 : rListener->dispatchFinished( aEvent );
793 184 : }
794 184 : }
795 184 : }
796 :
797 93064 : SfxDispatcher* SfxDispatchController_Impl::GetDispatcher()
798 : {
799 93064 : if ( !pDispatcher && pBindings )
800 0 : pDispatcher = GetBindings().GetDispatcher_Impl();
801 93064 : return pDispatcher;
802 : }
803 :
804 56603 : 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 )
805 : {
806 56603 : SolarMutexGuard aGuard;
807 56603 : if ( !pDispatch )
808 56603 : return;
809 :
810 : // Use alternative QueryState call to have a valid UNO representation of the state.
811 113206 : ::com::sun::star::uno::Any aState;
812 56603 : if ( !pDispatcher && pBindings )
813 0 : pDispatcher = GetBindings().GetDispatcher_Impl();
814 56603 : SfxItemState eState = pDispatcher->QueryState( GetId(), aState );
815 :
816 56603 : if ( eState == SFX_ITEM_DONTCARE )
817 : {
818 : // Use special uno struct to transport don't care state
819 0 : ::com::sun::star::frame::status::ItemStatus aItemStatus;
820 0 : aItemStatus.State = ::com::sun::star::frame::status::ItemState::dont_care;
821 0 : aState = makeAny( aItemStatus );
822 : }
823 :
824 113206 : ::com::sun::star::frame::FeatureStateEvent aEvent;
825 56603 : aEvent.FeatureURL = aURL;
826 56603 : aEvent.Source = (::com::sun::star::frame::XDispatch*) pDispatch;
827 56603 : aEvent.Requery = sal_False;
828 56603 : if ( bVisible )
829 : {
830 56601 : aEvent.IsEnabled = eState != SFX_ITEM_DISABLED;
831 56601 : aEvent.State = aState;
832 : }
833 : else
834 : {
835 2 : ::com::sun::star::frame::status::Visibility aVisibilityStatus;
836 2 : aVisibilityStatus.bVisible = sal_False;
837 :
838 : // MBA: we might decide to *not* disable "invisible" slots, but this would be
839 : // a change that needs to adjust at least the testtool
840 2 : aEvent.IsEnabled = sal_False;
841 2 : aEvent.State = makeAny( aVisibilityStatus );
842 : }
843 :
844 113206 : aListener->statusChanged( aEvent );
845 : }
846 :
847 31683 : void SfxDispatchController_Impl::StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState, SfxSlotServer* pSlotServ )
848 : {
849 31683 : if ( !pDispatch )
850 31683 : return;
851 :
852 : // Bindings instance notifies controller about a state change, listeners must be notified also
853 : // Don't cache visibility state changes as they are volatile. We need our real state to send it
854 : // to our controllers after visibility is set to true.
855 31683 : sal_Bool bNotify = sal_True;
856 31683 : if ( pState && !IsInvalidItem( pState ) )
857 : {
858 26610 : if ( !pState->ISA( SfxVisibilityItem ) )
859 : {
860 26609 : sal_Bool bBothAvailable = pLastState && !IsInvalidItem(pLastState);
861 26609 : if ( bBothAvailable )
862 511 : bNotify = pState->Type() != pLastState->Type() || *pState != *pLastState;
863 26609 : if ( pLastState && !IsInvalidItem( pLastState ) )
864 511 : delete pLastState;
865 26609 : pLastState = !IsInvalidItem(pState) ? pState->Clone() : pState;
866 26609 : bVisible = sal_True;
867 : }
868 : else
869 1 : bVisible = ((SfxVisibilityItem *)pState)->GetValue();
870 : }
871 : else
872 : {
873 5073 : if ( pLastState && !IsInvalidItem( pLastState ) )
874 88 : delete pLastState;
875 5073 : pLastState = pState;
876 : }
877 :
878 31683 : ::cppu::OInterfaceContainerHelper* pContnr = pDispatch->GetListeners().getContainer ( aDispatchURL.Complete );
879 31683 : if ( bNotify && pContnr )
880 : {
881 26250 : ::com::sun::star::uno::Any aState;
882 26250 : if ( ( eState >= SFX_ITEM_AVAILABLE ) && pState && !IsInvalidItem( pState ) && !pState->ISA(SfxVoidItem) )
883 : {
884 : // Retrieve metric from pool to have correct sub ID when calling QueryValue
885 16159 : sal_uInt16 nSubId( 0 );
886 16159 : SfxMapUnit eMapUnit( SFX_MAPUNIT_100TH_MM );
887 :
888 : // retrieve the core metric
889 : // it's enough to check the objectshell, the only shell that does not use the pool of the document
890 : // is SfxViewFrame, but it hasn't any metric parameters
891 : // TODO/LATER: what about the FormShell? Does it use any metric data?! Perhaps it should use the Pool of the document!
892 16159 : if ( pSlotServ && pDispatcher )
893 : {
894 16159 : SfxShell* pShell = pDispatcher->GetShell( pSlotServ->GetShellLevel() );
895 : DBG_ASSERT( pShell, "Can't get core metric without shell!" );
896 16159 : if ( pShell )
897 16159 : eMapUnit = GetCoreMetric( pShell->GetPool(), nSID );
898 : }
899 :
900 16159 : if ( eMapUnit == SFX_MAPUNIT_TWIP )
901 13302 : nSubId |= CONVERT_TWIPS;
902 :
903 16159 : pState->QueryValue( aState, (sal_uInt8)nSubId );
904 : }
905 10091 : else if ( eState == SFX_ITEM_DONTCARE )
906 : {
907 : // Use special uno struct to transport don't care state
908 10 : ::com::sun::star::frame::status::ItemStatus aItemStatus;
909 10 : aItemStatus.State = ::com::sun::star::frame::status::ItemState::dont_care;
910 10 : aState = makeAny( aItemStatus );
911 : }
912 :
913 52500 : ::com::sun::star::frame::FeatureStateEvent aEvent;
914 26250 : aEvent.FeatureURL = aDispatchURL;
915 26250 : aEvent.Source = (::com::sun::star::frame::XDispatch*) pDispatch;
916 26250 : aEvent.IsEnabled = eState != SFX_ITEM_DISABLED;
917 26250 : aEvent.Requery = sal_False;
918 26250 : aEvent.State = aState;
919 :
920 52500 : ::cppu::OInterfaceIteratorHelper aIt( *pContnr );
921 79894 : while( aIt.hasMoreElements() )
922 : {
923 : try
924 : {
925 27394 : ((::com::sun::star::frame::XStatusListener *)aIt.next())->statusChanged( aEvent );
926 : }
927 0 : catch (const ::com::sun::star::uno::RuntimeException&)
928 : {
929 0 : aIt.remove();
930 : }
931 26250 : }
932 : }
933 : }
934 :
935 0 : void SfxDispatchController_Impl::StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState )
936 : {
937 0 : StateChanged( nSID, eState, pState, 0 );
938 408 : }
939 :
940 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|