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