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