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