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_svtools.hxx" 30 31 //_________________________________________________________________________________________________________________ 32 // my own includes 33 //_________________________________________________________________________________________________________________ 34 #include "svtools/popupmenucontrollerbase.hxx" 35 36 37 //_________________________________________________________________________________________________________________ 38 // interface includes 39 //_________________________________________________________________________________________________________________ 40 #include <com/sun/star/awt/XDevice.hpp> 41 #include <com/sun/star/beans/PropertyValue.hpp> 42 #include <com/sun/star/awt/MenuItemStyle.hpp> 43 #include <com/sun/star/frame/XDispatchProvider.hpp> 44 #include <com/sun/star/lang/DisposedException.hpp> 45 #include <com/sun/star/awt/XMenuExtended.hpp> 46 47 //_________________________________________________________________________________________________________________ 48 // includes of other projects 49 //_________________________________________________________________________________________________________________ 50 51 #ifndef _VCL_MENU_HXX_ 52 #include <vcl/menu.hxx> 53 #endif 54 #include <vcl/svapp.hxx> 55 #include <rtl/ustrbuf.hxx> 56 #include <rtl/logfile.hxx> 57 #include <vos/mutex.hxx> 58 59 //_________________________________________________________________________________________________________________ 60 // Defines 61 //_________________________________________________________________________________________________________________ 62 // 63 64 using ::rtl::OUString; 65 66 using namespace com::sun::star; 67 using namespace com::sun::star::uno; 68 using namespace com::sun::star::lang; 69 using namespace com::sun::star::frame; 70 using namespace com::sun::star::beans; 71 using namespace com::sun::star::util; 72 73 namespace svt 74 { 75 76 struct PopupMenuControllerBaseDispatchInfo 77 { 78 Reference< XDispatch > mxDispatch; 79 const URL maURL; 80 const Sequence< PropertyValue > maArgs; 81 82 PopupMenuControllerBaseDispatchInfo( const Reference< XDispatch >& xDispatch, const URL& rURL, const Sequence< PropertyValue >& rArgs ) 83 : mxDispatch( xDispatch ), maURL( rURL ), maArgs( rArgs ) {} 84 }; 85 86 PopupMenuControllerBase::PopupMenuControllerBase( const Reference< XMultiServiceFactory >& xServiceManager ) : 87 ::comphelper::OBaseMutex(), 88 PopupMenuControllerBaseType(m_aMutex), 89 m_bInitialized( false ), 90 m_xServiceManager( xServiceManager ) 91 { 92 if ( m_xServiceManager.is() ) 93 m_xURLTransformer.set( m_xServiceManager->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.util.URLTransformer"))),UNO_QUERY ); 94 } 95 96 PopupMenuControllerBase::~PopupMenuControllerBase() 97 { 98 } 99 100 // protected function 101 void PopupMenuControllerBase::throwIfDisposed() throw ( RuntimeException ) 102 { 103 if (rBHelper.bDisposed || rBHelper.bInDispose) 104 throw com::sun::star::lang::DisposedException(); 105 } 106 107 // protected function 108 void PopupMenuControllerBase::resetPopupMenu( com::sun::star::uno::Reference< com::sun::star::awt::XPopupMenu >& rPopupMenu ) 109 { 110 VCLXPopupMenu* pPopupMenu = 0; 111 if ( rPopupMenu.is() && rPopupMenu->getItemCount() > 0 ) 112 { 113 pPopupMenu = (VCLXPopupMenu *)VCLXMenu::GetImplementation( rPopupMenu ); 114 if ( pPopupMenu ) 115 { 116 vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() ); 117 118 PopupMenu* pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu(); 119 pVCLPopupMenu->Clear(); 120 } 121 } 122 } 123 124 void SAL_CALL PopupMenuControllerBase::disposing() 125 { 126 // Reset our members and set disposed flag 127 osl::MutexGuard aLock( m_aMutex ); 128 m_xFrame.clear(); 129 m_xDispatch.clear(); 130 m_xPopupMenu.clear(); 131 m_xServiceManager.clear(); 132 } 133 134 // XServiceInfo 135 136 sal_Bool SAL_CALL PopupMenuControllerBase::supportsService( const ::rtl::OUString& ServiceName ) throw (RuntimeException) 137 { 138 const Sequence< rtl::OUString > aSNL( getSupportedServiceNames() ); 139 const rtl::OUString * pArray = aSNL.getConstArray(); 140 141 for( sal_Int32 i = 0; i < aSNL.getLength(); i++ ) 142 if( pArray[i] == ServiceName ) 143 return true; 144 145 return false; 146 } 147 148 // XEventListener 149 void SAL_CALL PopupMenuControllerBase::disposing( const EventObject& ) throw ( RuntimeException ) 150 { 151 osl::MutexGuard aLock( m_aMutex ); 152 m_xFrame.clear(); 153 m_xDispatch.clear(); 154 m_xPopupMenu.clear(); 155 } 156 157 // XMenuListener 158 void SAL_CALL PopupMenuControllerBase::highlight( const awt::MenuEvent& ) throw (RuntimeException) 159 { 160 } 161 162 void PopupMenuControllerBase::impl_select(const Reference< XDispatch >& _xDispatch,const URL& aURL) 163 { 164 Sequence<PropertyValue> aArgs; 165 OSL_ENSURE(_xDispatch.is(),"PopupMenuControllerBase::impl_select: No dispatch"); 166 if ( _xDispatch.is() ) 167 _xDispatch->dispatch( aURL, aArgs ); 168 } 169 170 void SAL_CALL PopupMenuControllerBase::select( const awt::MenuEvent& rEvent ) throw (RuntimeException) 171 { 172 throwIfDisposed(); 173 174 osl::MutexGuard aLock( m_aMutex ); 175 176 Reference< awt::XMenuExtended > xExtMenu( m_xPopupMenu, UNO_QUERY ); 177 if( xExtMenu.is() ) 178 { 179 Sequence<PropertyValue> aArgs; 180 dispatchCommand( xExtMenu->getCommand( rEvent.MenuId ), aArgs ); 181 } 182 } 183 184 void PopupMenuControllerBase::dispatchCommand( const ::rtl::OUString& sCommandURL, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rArgs ) 185 { 186 osl::MutexGuard aLock( m_aMutex ); 187 188 throwIfDisposed(); 189 190 try 191 { 192 Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY_THROW ); 193 URL aURL; 194 aURL.Complete = sCommandURL; 195 m_xURLTransformer->parseStrict( aURL ); 196 197 Reference< XDispatch > xDispatch( xDispatchProvider->queryDispatch( aURL, OUString(), 0 ), UNO_QUERY_THROW ); 198 199 Application::PostUserEvent( STATIC_LINK(0, PopupMenuControllerBase, ExecuteHdl_Impl), new PopupMenuControllerBaseDispatchInfo( xDispatch, aURL, rArgs ) ); 200 201 } 202 catch( Exception& ) 203 { 204 } 205 206 } 207 208 IMPL_STATIC_LINK_NOINSTANCE( PopupMenuControllerBase, ExecuteHdl_Impl, PopupMenuControllerBaseDispatchInfo*, pDispatchInfo ) 209 { 210 pDispatchInfo->mxDispatch->dispatch( pDispatchInfo->maURL, pDispatchInfo->maArgs ); 211 delete pDispatchInfo; 212 return 0; 213 } 214 215 void SAL_CALL PopupMenuControllerBase::activate( const awt::MenuEvent& ) throw (RuntimeException) 216 { 217 } 218 219 void SAL_CALL PopupMenuControllerBase::deactivate( const awt::MenuEvent& ) throw (RuntimeException) 220 { 221 } 222 223 void SAL_CALL PopupMenuControllerBase::updatePopupMenu() throw ( ::com::sun::star::uno::RuntimeException ) 224 { 225 osl::ClearableMutexGuard aLock( m_aMutex ); 226 throwIfDisposed(); 227 aLock.clear(); 228 229 updateCommand( m_aCommandURL ); 230 } 231 232 void SAL_CALL PopupMenuControllerBase::updateCommand( const rtl::OUString& rCommandURL ) 233 { 234 osl::ClearableMutexGuard aLock( m_aMutex ); 235 Reference< XStatusListener > xStatusListener( static_cast< OWeakObject* >( this ), UNO_QUERY ); 236 Reference< XDispatch > xDispatch( m_xDispatch ); 237 URL aTargetURL; 238 aTargetURL.Complete = rCommandURL; 239 m_xURLTransformer->parseStrict( aTargetURL ); 240 aLock.clear(); 241 242 // Add/remove status listener to get a status update once 243 if ( xDispatch.is() ) 244 { 245 xDispatch->addStatusListener( xStatusListener, aTargetURL ); 246 xDispatch->removeStatusListener( xStatusListener, aTargetURL ); 247 } 248 } 249 250 251 // XDispatchProvider 252 Reference< XDispatch > SAL_CALL 253 PopupMenuControllerBase::queryDispatch( 254 const URL& /*aURL*/, 255 const rtl::OUString& /*sTarget*/, 256 sal_Int32 /*nFlags*/ ) 257 throw( RuntimeException ) 258 { 259 // must be implemented by subclass 260 osl::MutexGuard aLock( m_aMutex ); 261 throwIfDisposed(); 262 263 return Reference< XDispatch >(); 264 } 265 266 Sequence< Reference< XDispatch > > SAL_CALL PopupMenuControllerBase::queryDispatches( const Sequence< DispatchDescriptor >& lDescriptor ) throw( RuntimeException ) 267 { 268 // Create return list - which must have same size then the given descriptor 269 // It's not allowed to pack it! 270 osl::ClearableMutexGuard aLock( m_aMutex ); 271 throwIfDisposed(); 272 aLock.clear(); 273 274 sal_Int32 nCount = lDescriptor.getLength(); 275 uno::Sequence< uno::Reference< frame::XDispatch > > lDispatcher( nCount ); 276 277 // Step over all descriptors and try to get any dispatcher for it. 278 for( sal_Int32 i=0; i<nCount; ++i ) 279 { 280 lDispatcher[i] = queryDispatch( lDescriptor[i].FeatureURL , 281 lDescriptor[i].FrameName , 282 lDescriptor[i].SearchFlags ); 283 } 284 285 return lDispatcher; 286 } 287 288 // XDispatch 289 void SAL_CALL 290 PopupMenuControllerBase::dispatch( 291 const URL& /*aURL*/, 292 const Sequence< PropertyValue >& /*seqProperties*/ ) 293 throw( ::com::sun::star::uno::RuntimeException ) 294 { 295 // must be implemented by subclass 296 osl::MutexGuard aLock( m_aMutex ); 297 throwIfDisposed(); 298 } 299 300 void SAL_CALL 301 PopupMenuControllerBase::addStatusListener( 302 const Reference< XStatusListener >& xControl, 303 const URL& aURL ) 304 throw( ::com::sun::star::uno::RuntimeException ) 305 { 306 osl::ResettableMutexGuard aLock( m_aMutex ); 307 throwIfDisposed(); 308 aLock.clear(); 309 310 bool bStatusUpdate( false ); 311 rBHelper.addListener( ::getCppuType( &xControl ), xControl ); 312 313 aLock.reset(); 314 if ( aURL.Complete.indexOf( m_aBaseURL ) == 0 ) 315 bStatusUpdate = true; 316 aLock.clear(); 317 318 if ( bStatusUpdate ) 319 { 320 // Dummy update for popup menu controllers 321 FeatureStateEvent aEvent; 322 aEvent.FeatureURL = aURL; 323 aEvent.IsEnabled = sal_True; 324 aEvent.Requery = sal_False; 325 aEvent.State = Any(); 326 xControl->statusChanged( aEvent ); 327 } 328 } 329 330 void SAL_CALL PopupMenuControllerBase::removeStatusListener( 331 const Reference< XStatusListener >& xControl, 332 const URL& /*aURL*/ ) 333 throw( ::com::sun::star::uno::RuntimeException ) 334 { 335 rBHelper.removeListener( ::getCppuType( &xControl ), xControl ); 336 } 337 338 ::rtl::OUString PopupMenuControllerBase::determineBaseURL( const ::rtl::OUString& aURL ) 339 { 340 // Just use the main part of the URL for popup menu controllers 341 sal_Int32 nQueryPart( 0 ); 342 sal_Int32 nSchemePart( 0 ); 343 rtl::OUString aMainURL( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.popup:" )); 344 345 nSchemePart = aURL.indexOf( ':' ); 346 if (( nSchemePart > 0 ) && 347 ( aURL.getLength() > ( nSchemePart+1 ))) 348 { 349 nQueryPart = aURL.indexOf( '?', nSchemePart ); 350 if ( nQueryPart > 0 ) 351 aMainURL += aURL.copy( nSchemePart, nQueryPart-nSchemePart ); 352 else if ( nQueryPart == -1 ) 353 aMainURL += aURL.copy( nSchemePart+1 ); 354 } 355 356 return aMainURL; 357 } 358 359 // XInitialization 360 void SAL_CALL PopupMenuControllerBase::initialize( const Sequence< Any >& aArguments ) throw ( Exception, RuntimeException ) 361 { 362 osl::MutexGuard aLock( m_aMutex ); 363 364 sal_Bool bInitalized( m_bInitialized ); 365 if ( !bInitalized ) 366 { 367 PropertyValue aPropValue; 368 rtl::OUString aCommandURL; 369 Reference< XFrame > xFrame; 370 371 for ( int i = 0; i < aArguments.getLength(); i++ ) 372 { 373 if ( aArguments[i] >>= aPropValue ) 374 { 375 if ( aPropValue.Name.equalsAscii( "Frame" )) 376 aPropValue.Value >>= xFrame; 377 else if ( aPropValue.Name.equalsAscii( "CommandURL" )) 378 aPropValue.Value >>= aCommandURL; 379 } 380 } 381 382 if ( xFrame.is() && aCommandURL.getLength() ) 383 { 384 m_xFrame = xFrame; 385 m_aCommandURL = aCommandURL; 386 m_aBaseURL = determineBaseURL( aCommandURL ); 387 m_bInitialized = true; 388 } 389 } 390 } 391 // XPopupMenuController 392 void SAL_CALL PopupMenuControllerBase::setPopupMenu( const Reference< awt::XPopupMenu >& xPopupMenu ) throw ( RuntimeException ) 393 { 394 osl::MutexGuard aLock( m_aMutex ); 395 throwIfDisposed(); 396 397 if ( m_xFrame.is() && !m_xPopupMenu.is() ) 398 { 399 // Create popup menu on demand 400 vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() ); 401 402 m_xPopupMenu = xPopupMenu; 403 m_xPopupMenu->addMenuListener( Reference< awt::XMenuListener >( (OWeakObject*)this, UNO_QUERY )); 404 405 Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY ); 406 407 URL aTargetURL; 408 aTargetURL.Complete = m_aCommandURL; 409 m_xURLTransformer->parseStrict( aTargetURL ); 410 m_xDispatch = xDispatchProvider->queryDispatch( aTargetURL, ::rtl::OUString(), 0 ); 411 412 impl_setPopupMenu(); 413 414 updatePopupMenu(); 415 } 416 } 417 void PopupMenuControllerBase::impl_setPopupMenu() 418 { 419 } 420 } 421