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 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_framework.hxx" 24 25 #include <uielement/popuptoolbarcontroller.hxx> 26 #include <framework/menuconfiguration.hxx> 27 #include <toolkit/awt/vclxmenu.hxx> 28 #include <comphelper/processfactory.hxx> 29 #include <svtools/imagemgr.hxx> 30 #include <svtools/miscopt.hxx> 31 #include <toolkit/helper/vclunohelper.hxx> 32 #include <tools/urlobj.hxx> 33 #include <unotools/moduleoptions.hxx> 34 #include <vcl/svapp.hxx> 35 #include <vcl/toolbox.hxx> 36 #include <vos/mutex.hxx> 37 38 #include <com/sun/star/awt/PopupMenuDirection.hpp> 39 #include <com/sun/star/frame/PopupMenuControllerFactory.hpp> 40 #include <com/sun/star/frame/XDispatchProvider.hpp> 41 42 #define UNO_COMMAND_RECENT_FILE_LIST ".uno:RecentFileList" 43 #define SFX_REFERER_USER "private:user" 44 45 using rtl::OUString; 46 namespace css = ::com::sun::star; 47 48 namespace framework 49 { 50 51 PopupMenuToolbarController::PopupMenuToolbarController( 52 const css::uno::Reference< css::uno::XComponentContext >& xContext, 53 const OUString &rPopupCommand ) 54 : svt::ToolboxController() 55 , m_xContext( xContext ) 56 , m_bHasController( sal_False ) 57 , m_aPopupCommand( rPopupCommand ) 58 { 59 } 60 61 PopupMenuToolbarController::~PopupMenuToolbarController() 62 { 63 } 64 65 void SAL_CALL PopupMenuToolbarController::dispose() 66 throw ( css::uno::RuntimeException ) 67 { 68 svt::ToolboxController::dispose(); 69 70 osl::MutexGuard aGuard( m_aMutex ); 71 if( m_xPopupMenuController.is() ) 72 { 73 css::uno::Reference< css::lang::XComponent > xComponent( 74 m_xPopupMenuController, css::uno::UNO_QUERY ); 75 if( xComponent.is() ) 76 { 77 try 78 { 79 xComponent->dispose(); 80 } 81 catch (...) 82 {} 83 } 84 m_xPopupMenuController.clear(); 85 } 86 87 m_xContext.clear(); 88 m_xPopupMenuFactory.clear(); 89 m_xPopupMenu.clear(); 90 } 91 92 void SAL_CALL PopupMenuToolbarController::initialize( 93 const css::uno::Sequence< css::uno::Any >& aArguments ) 94 throw ( css::uno::Exception, css::uno::RuntimeException ) 95 { 96 ToolboxController::initialize( aArguments ); 97 98 osl::MutexGuard aGuard( m_aMutex ); 99 if ( !m_aPopupCommand.getLength() ) 100 m_aPopupCommand = m_aCommandURL; 101 102 try 103 { 104 m_xPopupMenuFactory.set( 105 css::frame::PopupMenuControllerFactory::create( m_xContext ) ); 106 m_bHasController = m_xPopupMenuFactory->hasController( 107 m_aPopupCommand, getModuleName() ); 108 } 109 catch (const css::uno::Exception& e) 110 { 111 OSL_TRACE( "PopupMenuToolbarController - caught an exception! %s", 112 rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); 113 (void) e; 114 } 115 116 vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() ); 117 ToolBox* pToolBox = static_cast< ToolBox* >( VCLUnoHelper::GetWindow( getParent() ) ); 118 if ( pToolBox ) 119 { 120 ToolBoxItemBits nCurStyle( pToolBox->GetItemBits( m_nToolBoxId ) ); 121 ToolBoxItemBits nSetStyle( getDropDownStyle() ); 122 pToolBox->SetItemBits( m_nToolBoxId, 123 m_bHasController ? 124 nCurStyle | nSetStyle : 125 nCurStyle & ~nSetStyle ); 126 } 127 128 } 129 130 void SAL_CALL 131 PopupMenuToolbarController::statusChanged( 132 const css::frame::FeatureStateEvent& rEvent ) 133 throw ( css::uno::RuntimeException ) 134 { 135 // TODO move to base class 136 137 svt::ToolboxController::statusChanged( rEvent ); 138 enable( rEvent.IsEnabled ); 139 } 140 141 css::uno::Reference< css::awt::XWindow > SAL_CALL 142 PopupMenuToolbarController::createPopupWindow() 143 throw ( css::uno::RuntimeException ) 144 { 145 css::uno::Reference< css::awt::XWindow > xRet; 146 147 osl::MutexGuard aGuard( m_aMutex ); 148 if ( !m_bHasController ) 149 return xRet; 150 151 createPopupMenuController(); 152 153 vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() ); 154 ToolBox* pToolBox = static_cast< ToolBox* >( VCLUnoHelper::GetWindow( getParent() ) ); 155 if ( !pToolBox ) 156 return xRet; 157 158 pToolBox->SetItemDown( m_nToolBoxId, sal_True ); 159 sal_uInt16 nId = m_xPopupMenu->execute( 160 css::uno::Reference< css::awt::XWindowPeer >( getParent(), css::uno::UNO_QUERY ), 161 VCLUnoHelper::ConvertToAWTRect( pToolBox->GetItemRect( m_nToolBoxId ) ), 162 css::awt::PopupMenuDirection::EXECUTE_DEFAULT ); 163 pToolBox->SetItemDown( m_nToolBoxId, sal_False ); 164 165 if ( nId ) 166 functionExecuted( m_xPopupMenu->getCommand( nId ) ); 167 168 return xRet; 169 } 170 171 void PopupMenuToolbarController::functionExecuted( const OUString &/*rCommand*/) 172 { 173 } 174 175 sal_uInt16 PopupMenuToolbarController::getDropDownStyle() const 176 { 177 return TIB_DROPDOWN; 178 } 179 180 void PopupMenuToolbarController::createPopupMenuController() 181 { 182 if( !m_bHasController ) 183 return; 184 185 if ( !m_xPopupMenuController.is() ) 186 { 187 css::uno::Sequence< css::uno::Any > aArgs( 2 ); 188 css::beans::PropertyValue aProp; 189 190 aProp.Name = DECLARE_ASCII( "Frame" ); 191 aProp.Value <<= m_xFrame; 192 aArgs[0] <<= aProp; 193 194 aProp.Name = DECLARE_ASCII( "ModuleIdentifier" ); 195 aProp.Value <<= getModuleName(); 196 aArgs[1] <<= aProp; 197 try 198 { 199 m_xPopupMenu.set( 200 m_xContext->getServiceManager()->createInstanceWithContext( 201 DECLARE_ASCII( "com.sun.star.awt.PopupMenu" ), m_xContext ), 202 css::uno::UNO_QUERY_THROW ); 203 m_xPopupMenuController.set( 204 m_xPopupMenuFactory->createInstanceWithArgumentsAndContext( 205 m_aPopupCommand, aArgs, m_xContext), css::uno::UNO_QUERY_THROW ); 206 207 m_xPopupMenuController->setPopupMenu( m_xPopupMenu ); 208 } 209 catch ( const css::uno::Exception &e ) 210 { 211 m_xPopupMenu.clear(); 212 OSL_TRACE( "PopupMenuToolbarController - caught an exception! %s", 213 rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); 214 (void) e; 215 } 216 } 217 } 218 219 DEFINE_XSERVICEINFO_MULTISERVICE_2( WizardsToolbarController, 220 ::cppu::OWeakObject, 221 DECLARE_ASCII("com.sun.star.frame.ToolbarController"), 222 DECLARE_ASCII("org.apache.openoffice.comp.framework.WizardsToolbarController") 223 ) 224 225 DEFINE_INIT_SERVICE( WizardsToolbarController, {} ) 226 227 WizardsToolbarController::WizardsToolbarController( 228 const css::uno::Reference< css::uno::XComponentContext >& xContext ) 229 : PopupMenuToolbarController( xContext ) 230 { 231 } 232 233 sal_uInt16 WizardsToolbarController::getDropDownStyle() const 234 { 235 return TIB_DROPDOWNONLY; 236 } 237 238 DEFINE_XSERVICEINFO_MULTISERVICE_2( OpenToolbarController, 239 ::cppu::OWeakObject, 240 DECLARE_ASCII("com.sun.star.frame.ToolbarController"), 241 DECLARE_ASCII("org.apache.openoffice.comp.framework.OpenToolbarController") 242 ) 243 244 DEFINE_INIT_SERVICE( OpenToolbarController, {} ) 245 246 OpenToolbarController::OpenToolbarController( 247 const css::uno::Reference< css::uno::XComponentContext >& xContext ) 248 : PopupMenuToolbarController( xContext, DECLARE_ASCII( UNO_COMMAND_RECENT_FILE_LIST ) ) 249 { 250 } 251 252 253 DEFINE_XSERVICEINFO_MULTISERVICE_2( NewToolbarController, 254 ::cppu::OWeakObject, 255 DECLARE_ASCII("com.sun.star.frame.ToolbarController"), 256 DECLARE_ASCII("org.apache.openoffice.comp.framework.NewToolbarController") 257 ) 258 259 DEFINE_INIT_SERVICE( NewToolbarController, {} ) 260 261 NewToolbarController::NewToolbarController( 262 const css::uno::Reference< css::uno::XComponentContext >& xContext ) 263 : PopupMenuToolbarController( xContext ) 264 { 265 } 266 267 void SAL_CALL 268 NewToolbarController::statusChanged( 269 const css::frame::FeatureStateEvent& rEvent ) 270 throw ( css::uno::RuntimeException ) 271 { 272 if ( rEvent.IsEnabled ) 273 { 274 OUString aState; 275 rEvent.State >>= aState; 276 // set the image even if the state is not a string 277 // this will set the image of the default module 278 setItemImage( aState ); 279 } 280 281 enable( rEvent.IsEnabled ); 282 } 283 284 void SAL_CALL 285 NewToolbarController::execute( sal_Int16 /*KeyModifier*/ ) 286 throw ( css::uno::RuntimeException ) 287 { 288 osl::MutexGuard aGuard( m_aMutex ); 289 if ( !m_aLastURL.getLength() ) 290 return; 291 292 OUString aTarget( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ); 293 if ( m_xPopupMenu.is() ) 294 { 295 // TODO investigate how to wrap Get/SetUserValue in css::awt::XMenu 296 MenuConfiguration::Attributes* pMenuAttributes( 0 ); 297 VCLXPopupMenu* pTkPopupMenu = dynamic_cast< VCLXPopupMenu * >( 298 VCLXMenu::GetImplementation( m_xPopupMenu ) ); 299 300 vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() ); 301 PopupMenu* pVCLPopupMenu = dynamic_cast< PopupMenu * >( pTkPopupMenu->GetMenu() ); 302 if ( pVCLPopupMenu ) 303 pMenuAttributes = reinterpret_cast< MenuConfiguration::Attributes* >( 304 pVCLPopupMenu->GetUserValue( pVCLPopupMenu->GetCurItemId() ) ); 305 306 if ( pMenuAttributes ) 307 aTarget = pMenuAttributes->aTargetFrame; 308 } 309 310 css::uno::Sequence< css::beans::PropertyValue > aArgs( 1 ); 311 aArgs[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "Referer" )); 312 aArgs[0].Value <<= OUString( RTL_CONSTASCII_USTRINGPARAM( SFX_REFERER_USER ) ); 313 314 dispatchCommand( m_aLastURL, aArgs, aTarget ); 315 } 316 317 void NewToolbarController::functionExecuted( const OUString &rCommand ) 318 { 319 setItemImage( rCommand ); 320 } 321 322 /** 323 it return the existing state of the given URL in the popupmenu of this toolbox control. 324 325 If the given URL can be located as an action command of one menu item of the 326 popup menu of this control, we return sal_True. Otherwhise we return sal_False. 327 Further we return a fallback URL, in case we have to return sal_False. Because 328 the outside code must select a valid item of the popup menu everytime ... 329 and we define it here. By the way this m ethod was written to handle 330 error situations gracefully. E.g. it can be called during creation time 331 but then we have no valid menu. For this case we know another fallback URL. 332 Then we return the private:factory/ URL of the default factory. 333 334 @param rPopupMenu 335 pounts to the popup menu, on which item we try to locate the given URL 336 Can be NULL! Search will be supressed then. 337 338 @param sURL 339 the URL for searching 340 341 @param sFallback 342 contains the fallback URL in case we return FALSE 343 Must point to valid memory! 344 345 @param aImage 346 contains the image of the menu for the URL. 347 348 @return sal_True - if URL could be located as an item of the popup menu. 349 sal_False - otherwhise. 350 */ 351 static sal_Bool Impl_ExistURLInMenu( 352 const css::uno::Reference< css::awt::XPopupMenu > &rPopupMenu, 353 OUString &sURL, 354 OUString &sFallback, 355 Image &aImage ) 356 { 357 sal_Bool bValidFallback( sal_False ); 358 sal_uInt16 nCount( 0 ); 359 if ( rPopupMenu.is() && ( nCount = rPopupMenu->getItemCount() ) != 0 && sURL.getLength() ) 360 { 361 for ( sal_uInt16 n = 0; n < nCount; ++n ) 362 { 363 sal_uInt16 nId = rPopupMenu->getItemId( n ); 364 OUString aCmd( rPopupMenu->getCommand( nId ) ); 365 366 if ( !bValidFallback && aCmd.getLength() ) 367 { 368 sFallback = aCmd; 369 bValidFallback = sal_True; 370 } 371 372 // match even if the menu command is more detailed 373 // (maybe an additional query) #i28667# 374 if ( aCmd.match( sURL ) ) 375 { 376 sURL = aCmd; 377 const css::uno::Reference< css::graphic::XGraphic > xGraphic( 378 rPopupMenu->getItemImage( nId ) ); 379 if ( xGraphic.is() ) 380 aImage = Image( xGraphic ); 381 return sal_True; 382 } 383 } 384 } 385 386 if ( !bValidFallback ) 387 { 388 rtl::OUStringBuffer aBuffer; 389 aBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM( "private:factory/" ) ); 390 aBuffer.append( SvtModuleOptions().GetDefaultModuleName() ); 391 sFallback = aBuffer.makeStringAndClear(); 392 } 393 394 return sal_False; 395 } 396 397 /** We accept URL's here only, which exist as items of our internal popup menu. 398 All other ones will be ignored and a fallback is used. 399 */ 400 void NewToolbarController::setItemImage( const OUString &rCommand ) 401 { 402 vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() ); 403 ToolBox* pToolBox = static_cast< ToolBox* >( VCLUnoHelper::GetWindow( getParent() ) ); 404 if ( !pToolBox ) 405 return; 406 407 OUString aURL = rCommand; 408 OUString sFallback; 409 Image aMenuImage; 410 411 sal_Bool bValid( Impl_ExistURLInMenu( m_xPopupMenu, aURL, sFallback, aMenuImage ) ); 412 // do not change aURL if Impl_ExistURLInMenu returned sal_False 413 // this allows later initialization of the PopupMenuController on createPopupWindow() 414 // and works even if SvFileInformationManager does not know the module 415 if ( !aURL.getLength() ) 416 aURL = sFallback; 417 418 sal_Bool bBig = SvtMiscOptions().AreCurrentSymbolsLarge(); 419 sal_Bool bHC = pToolBox->GetSettings().GetStyleSettings().GetHighContrastMode(); 420 421 INetURLObject aURLObj( aURL ); 422 Image aImage = SvFileInformationManager::GetImageNoDefault( aURLObj, bBig, bHC ); 423 if ( !aImage ) 424 { 425 if ( !!aMenuImage ) 426 aImage = aMenuImage; 427 else if ( !bValid ) 428 // If SvFileInformationManager didn't know the module, try with the default 429 aImage = SvFileInformationManager::GetImageNoDefault( INetURLObject( sFallback ), bBig, bHC ); 430 431 if ( !aImage ) 432 aImage = SvFileInformationManager::GetImage( aURLObj, bBig, bHC ); 433 } 434 435 // if everything failed, just use the image associated with the toolbar item command 436 if ( !aImage ) 437 return; 438 439 Size aBigSize( pToolBox->GetDefaultImageSize() ); 440 if ( bBig && aImage.GetSizePixel() != aBigSize ) 441 { 442 BitmapEx aScaleBmpEx( aImage.GetBitmapEx() ); 443 aScaleBmpEx.Scale( aBigSize, BMP_SCALE_INTERPOLATE ); 444 pToolBox->SetItemImage( m_nToolBoxId, Image( aScaleBmpEx ) ); 445 } 446 else 447 pToolBox->SetItemImage( m_nToolBoxId, aImage ); 448 449 m_aLastURL = aURL; 450 } 451 452 453 } 454