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