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