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