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