1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_framework.hxx" 30 #include <uielement/controlmenucontroller.hxx> 31 32 //_________________________________________________________________________________________________________________ 33 // my own includes 34 //_________________________________________________________________________________________________________________ 35 #include <threadhelp/resetableguard.hxx> 36 #include "services.h" 37 38 //_________________________________________________________________________________________________________________ 39 // interface includes 40 //_________________________________________________________________________________________________________________ 41 #include <com/sun/star/awt/XDevice.hpp> 42 #include <com/sun/star/beans/PropertyValue.hpp> 43 #include <com/sun/star/awt/MenuItemStyle.hpp> 44 #include <com/sun/star/frame/XDispatchProvider.hpp> 45 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> 46 #include <com/sun/star/container/XNameContainer.hpp> 47 #include <com/sun/star/beans/XPropertySet.hpp> 48 49 //_________________________________________________________________________________________________________________ 50 // includes of other projects 51 //_________________________________________________________________________________________________________________ 52 53 #include <vcl/menu.hxx> 54 #include <vcl/svapp.hxx> 55 #include <vcl/i18nhelp.hxx> 56 #include <tools/urlobj.hxx> 57 #include <rtl/ustrbuf.hxx> 58 #include <rtl/strbuf.hxx> 59 #include <svl/solar.hrc> 60 #include <tools/rcid.h> 61 #include <vcl/image.hxx> 62 #include <svtools/menuoptions.hxx> 63 #include <dispatch/uieventloghelper.hxx> 64 #include <vos/mutex.hxx> 65 66 // Copied from svx 67 // Function-Id's 68 #define RID_FMSHELL_CONVERSIONMENU (RID_FORMS_START + 4) 69 #define RID_SVXIMGLIST_FMEXPL (RID_FORMS_START + 0) 70 #define RID_SVXIMGLIST_FMEXPL_HC (RID_FORMS_START + 2) 71 72 // Forms - Ids, used to address images from image list 73 #define SID_FMSLOTS_START (SID_SVX_START + 592) 74 #define SID_MORE_FMSLOTS_START (SID_SVX_START + 702) 75 76 #define SID_FM_CONVERTTO_EDIT (SID_MORE_FMSLOTS_START + 32) 77 #define SID_FM_CONVERTTO_BUTTON (SID_MORE_FMSLOTS_START + 33) 78 #define SID_FM_CONVERTTO_FIXEDTEXT (SID_MORE_FMSLOTS_START + 34) 79 #define SID_FM_CONVERTTO_LISTBOX (SID_MORE_FMSLOTS_START + 35) 80 #define SID_FM_CONVERTTO_CHECKBOX (SID_MORE_FMSLOTS_START + 36) 81 #define SID_FM_CONVERTTO_RADIOBUTTON (SID_MORE_FMSLOTS_START + 37) 82 #define SID_FM_CONVERTTO_GROUPBOX (SID_MORE_FMSLOTS_START + 38) 83 #define SID_FM_CONVERTTO_COMBOBOX (SID_MORE_FMSLOTS_START + 39) 84 #define SID_FM_CONVERTTO_GRID (SID_MORE_FMSLOTS_START + 40) 85 #define SID_FM_CONVERTTO_IMAGEBUTTON (SID_MORE_FMSLOTS_START + 41) 86 #define SID_FM_CONVERTTO_FILECONTROL (SID_MORE_FMSLOTS_START + 42) 87 #define SID_FM_CONVERTTO_DATE (SID_MORE_FMSLOTS_START + 43) 88 #define SID_FM_CONVERTTO_TIME (SID_MORE_FMSLOTS_START + 44) 89 #define SID_FM_CONVERTTO_NUMERIC (SID_MORE_FMSLOTS_START + 45) 90 #define SID_FM_CONVERTTO_CURRENCY (SID_MORE_FMSLOTS_START + 46) 91 #define SID_FM_CONVERTTO_PATTERN (SID_MORE_FMSLOTS_START + 47) 92 #define SID_FM_CONVERTTO_IMAGECONTROL (SID_MORE_FMSLOTS_START + 48) 93 #define SID_FM_CONVERTTO_FORMATTED (SID_MORE_FMSLOTS_START + 49) 94 #define SID_FM_CONVERTTO_SCROLLBAR (SID_MORE_FMSLOTS_START + 68) 95 #define SID_FM_CONVERTTO_SPINBUTTON (SID_MORE_FMSLOTS_START + 69) 96 97 #define SID_FM_DATEFIELD (SID_MORE_FMSLOTS_START + 2) 98 #define SID_FM_TIMEFIELD (SID_MORE_FMSLOTS_START + 3) 99 #define SID_FM_NUMERICFIELD (SID_MORE_FMSLOTS_START + 4) 100 #define SID_FM_CURRENCYFIELD (SID_MORE_FMSLOTS_START + 5) 101 #define SID_FM_PATTERNFIELD (SID_MORE_FMSLOTS_START + 6) 102 #define SID_FM_IMAGECONTROL (SID_MORE_FMSLOTS_START + 8) 103 #define SID_FM_FORMATTEDFIELD (SID_MORE_FMSLOTS_START + 26) 104 #define SID_FM_SCROLLBAR (SID_MORE_FMSLOTS_START + 66) 105 #define SID_FM_SPINBUTTON (SID_MORE_FMSLOTS_START + 67) 106 #define SID_FM_CONFIG (SID_FMSLOTS_START + 1) 107 #define SID_FM_PUSHBUTTON (SID_FMSLOTS_START + 2) 108 #define SID_FM_RADIOBUTTON (SID_FMSLOTS_START + 3) 109 #define SID_FM_CHECKBOX (SID_FMSLOTS_START + 4) 110 #define SID_FM_FIXEDTEXT (SID_FMSLOTS_START + 5) 111 #define SID_FM_GROUPBOX (SID_FMSLOTS_START + 6) 112 #define SID_FM_EDIT (SID_FMSLOTS_START + 7) 113 #define SID_FM_LISTBOX (SID_FMSLOTS_START + 8) 114 #define SID_FM_COMBOBOX (SID_FMSLOTS_START + 9) 115 #define SID_FM_URLBUTTON (SID_FMSLOTS_START + 10) 116 #define SID_FM_DBGRID (SID_FMSLOTS_START + 11) 117 #define SID_FM_IMAGEBUTTON (SID_FMSLOTS_START + 12) 118 #define SID_FM_FILECONTROL (SID_FMSLOTS_START + 13) 119 120 sal_Int16 nConvertSlots[] = 121 { 122 SID_FM_CONVERTTO_EDIT, 123 SID_FM_CONVERTTO_BUTTON, 124 SID_FM_CONVERTTO_FIXEDTEXT, 125 SID_FM_CONVERTTO_LISTBOX, 126 SID_FM_CONVERTTO_CHECKBOX, 127 SID_FM_CONVERTTO_RADIOBUTTON, 128 SID_FM_CONVERTTO_GROUPBOX, 129 SID_FM_CONVERTTO_COMBOBOX, 130 // SID_FM_CONVERTTO_GRID, 131 SID_FM_CONVERTTO_IMAGEBUTTON, 132 SID_FM_CONVERTTO_FILECONTROL, 133 SID_FM_CONVERTTO_DATE, 134 SID_FM_CONVERTTO_TIME, 135 SID_FM_CONVERTTO_NUMERIC, 136 SID_FM_CONVERTTO_CURRENCY, 137 SID_FM_CONVERTTO_PATTERN, 138 SID_FM_CONVERTTO_IMAGECONTROL, 139 SID_FM_CONVERTTO_FORMATTED, 140 SID_FM_CONVERTTO_SCROLLBAR, 141 SID_FM_CONVERTTO_SPINBUTTON 142 }; 143 144 sal_Int16 nCreateSlots[] = 145 { 146 SID_FM_EDIT, 147 SID_FM_PUSHBUTTON, 148 SID_FM_FIXEDTEXT, 149 SID_FM_LISTBOX, 150 SID_FM_CHECKBOX, 151 SID_FM_RADIOBUTTON, 152 SID_FM_GROUPBOX, 153 SID_FM_COMBOBOX, 154 // SID_FM_DBGRID, 155 SID_FM_IMAGEBUTTON, 156 SID_FM_FILECONTROL, 157 SID_FM_DATEFIELD, 158 SID_FM_TIMEFIELD, 159 SID_FM_NUMERICFIELD, 160 SID_FM_CURRENCYFIELD, 161 SID_FM_PATTERNFIELD, 162 SID_FM_IMAGECONTROL, 163 SID_FM_FORMATTEDFIELD, 164 SID_FM_SCROLLBAR, 165 SID_FM_SPINBUTTON 166 }; 167 168 const char* aCommands[] = 169 { 170 ".uno:ConvertToEdit", 171 ".uno:ConvertToButton", 172 ".uno:ConvertToFixed", 173 ".uno:ConvertToList", 174 ".uno:ConvertToCheckBox", 175 ".uno:ConvertToRadio", 176 ".uno:ConvertToGroup", 177 ".uno:ConvertToCombo", 178 // ".uno:ConvertToGrid", 179 ".uno:ConvertToImageBtn", 180 ".uno:ConvertToFileControl", 181 ".uno:ConvertToDate", 182 ".uno:ConvertToTime", 183 ".uno:ConvertToNumeric", 184 ".uno:ConvertToCurrency", 185 ".uno:ConvertToPattern", 186 ".uno:ConvertToImageControl", 187 ".uno:ConvertToFormatted", 188 ".uno:ConvertToScrollBar", 189 ".uno:ConvertToSpinButton" 190 }; 191 192 //_________________________________________________________________________________________________________________ 193 // Defines 194 //_________________________________________________________________________________________________________________ 195 // 196 197 using namespace com::sun::star::uno; 198 using namespace com::sun::star::lang; 199 using namespace com::sun::star::frame; 200 using namespace com::sun::star::beans; 201 using namespace com::sun::star::util; 202 using namespace com::sun::star::style; 203 using namespace com::sun::star::container; 204 205 namespace framework 206 { 207 208 DEFINE_XSERVICEINFO_MULTISERVICE ( ControlMenuController , 209 OWeakObject , 210 SERVICENAME_POPUPMENUCONTROLLER , 211 IMPLEMENTATIONNAME_CONTROLMENUCONTROLLER 212 ) 213 214 DEFINE_INIT_SERVICE ( ControlMenuController, {} ) 215 216 ControlMenuController::ControlMenuController( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xServiceManager ) : 217 svt::PopupMenuControllerBase( xServiceManager ), 218 m_pResPopupMenu( 0 ) 219 { 220 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); 221 m_bWasHiContrast = rSettings.GetHighContrastMode(); 222 m_bShowMenuImages = rSettings.GetUseImagesInMenus(); 223 224 } 225 226 ControlMenuController::~ControlMenuController() 227 { 228 } 229 230 // private function 231 void ControlMenuController::updateImagesPopupMenu( PopupMenu* pPopupMenu ) 232 { 233 rtl::OUString aResName( RTL_CONSTASCII_USTRINGPARAM( "svx" )); 234 235 ResMgr* pResMgr = ResMgr::CreateResMgr( rtl::OUStringToOString( aResName, RTL_TEXTENCODING_ASCII_US )); 236 ResId aResId( m_bWasHiContrast ? RID_SVXIMGLIST_FMEXPL_HC : RID_SVXIMGLIST_FMEXPL, *pResMgr ); 237 aResId.SetRT( RSC_IMAGELIST ); 238 239 if ( pResMgr->IsAvailable( aResId )) 240 { 241 ImageList aImageList( aResId ); 242 for ( sal_uInt32 i=0; i < sizeof(nConvertSlots)/sizeof(nConvertSlots[0]); ++i ) 243 { 244 // das entsprechende Image dran 245 if ( m_bShowMenuImages ) 246 pPopupMenu->SetItemImage( nConvertSlots[i], aImageList.GetImage(nCreateSlots[i])); 247 else 248 pPopupMenu->SetItemImage( nConvertSlots[i], Image() ); 249 } 250 } 251 252 delete pResMgr; 253 } 254 255 // private function 256 void ControlMenuController::fillPopupMenu( Reference< css::awt::XPopupMenu >& rPopupMenu ) 257 { 258 VCLXPopupMenu* pPopupMenu = (VCLXPopupMenu *)VCLXMenu::GetImplementation( rPopupMenu ); 259 PopupMenu* pVCLPopupMenu = 0; 260 261 vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() ); 262 263 resetPopupMenu( rPopupMenu ); 264 if ( pPopupMenu ) 265 pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu(); 266 267 if ( pVCLPopupMenu && m_pResPopupMenu ) 268 *pVCLPopupMenu = *m_pResPopupMenu; 269 } 270 271 // XEventListener 272 void SAL_CALL ControlMenuController::disposing( const EventObject& ) throw ( RuntimeException ) 273 { 274 Reference< css::awt::XMenuListener > xHolder(( OWeakObject *)this, UNO_QUERY ); 275 276 osl::ResettableMutexGuard aLock( m_aMutex ); 277 m_xFrame.clear(); 278 m_xDispatch.clear(); 279 m_xServiceManager.clear(); 280 281 if ( m_xPopupMenu.is() ) 282 m_xPopupMenu->removeMenuListener( Reference< css::awt::XMenuListener >(( OWeakObject *)this, UNO_QUERY )); 283 m_xPopupMenu.clear(); 284 delete m_pResPopupMenu; 285 } 286 287 // XStatusListener 288 void SAL_CALL ControlMenuController::statusChanged( const FeatureStateEvent& Event ) throw ( RuntimeException ) 289 { 290 osl::ResettableMutexGuard aLock( m_aMutex ); 291 292 sal_uInt16 nMenuId = 0; 293 for (sal_uInt32 i=0; i < sizeof(aCommands)/sizeof(aCommands[0]); ++i) 294 { 295 if ( Event.FeatureURL.Complete.equalsAscii( aCommands[i] )) 296 { 297 nMenuId = nConvertSlots[i]; 298 break; 299 } 300 } 301 302 if ( nMenuId ) 303 { 304 VCLXPopupMenu* pPopupMenu = (VCLXPopupMenu *)VCLXMenu::GetImplementation( m_xPopupMenu ); 305 306 vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() ); 307 308 PopupMenu* pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu(); 309 310 if ( !Event.IsEnabled && pVCLPopupMenu->GetItemPos( nMenuId ) != MENU_ITEM_NOTFOUND ) 311 pVCLPopupMenu->RemoveItem( pVCLPopupMenu->GetItemPos( nMenuId )); 312 else if ( Event.IsEnabled && pVCLPopupMenu->GetItemPos( nMenuId ) == MENU_ITEM_NOTFOUND ) 313 { 314 sal_Int16 nSourcePos = m_pResPopupMenu->GetItemPos(nMenuId); 315 sal_Int16 nPrevInSource = nSourcePos; 316 sal_uInt16 nPrevInConversion = MENU_ITEM_NOTFOUND; 317 while (nPrevInSource>0) 318 { 319 sal_Int16 nPrevId = m_pResPopupMenu->GetItemId(--nPrevInSource); 320 321 // do we have the source's predecessor in our conversion menu, too ? 322 nPrevInConversion = pVCLPopupMenu->GetItemPos( nPrevId ); 323 if ( nPrevInConversion != MENU_ITEM_NOTFOUND ) 324 break; 325 } 326 327 if ( MENU_ITEM_NOTFOUND == nPrevInConversion ) 328 // none of the items which precede the nSID-slot in the source menu are present in our conversion menu 329 nPrevInConversion = sal::static_int_cast< sal_uInt16 >(-1); // put the item at the first position 330 331 pVCLPopupMenu->InsertItem( nMenuId, m_pResPopupMenu->GetItemText( nMenuId ), m_pResPopupMenu->GetItemBits( nMenuId ), ++nPrevInConversion ); 332 pVCLPopupMenu->SetItemImage( nMenuId, m_pResPopupMenu->GetItemImage( nMenuId )); 333 pVCLPopupMenu->SetHelpId( nMenuId, m_pResPopupMenu->GetHelpId( nMenuId )); 334 } 335 } 336 } 337 338 // XMenuListener 339 void ControlMenuController::impl_select(const Reference< XDispatch >& /*_xDispatch*/,const ::com::sun::star::util::URL& aURL) 340 { 341 UrlToDispatchMap::iterator pIter = m_aURLToDispatchMap.find( aURL.Complete ); 342 if ( pIter != m_aURLToDispatchMap.end() ) 343 { 344 Sequence<PropertyValue> aArgs; 345 Reference< XDispatch > xDispatch = pIter->second; 346 if(::comphelper::UiEventsLogger::isEnabled()) //#i88653# 347 UiEventLogHelper(::rtl::OUString::createFromAscii("ControlMenuController")).log(m_xServiceManager, m_xFrame, aURL, aArgs); 348 if ( xDispatch.is() ) 349 xDispatch->dispatch( aURL, aArgs ); 350 } 351 } 352 353 void SAL_CALL ControlMenuController::activate( const css::awt::MenuEvent& ) throw (RuntimeException) 354 { 355 osl::ResettableMutexGuard aLock( m_aMutex ); 356 357 if ( m_xPopupMenu.is() ) 358 { 359 vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() ); 360 361 // Check if some modes have changed so we have to update our menu images 362 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); 363 sal_Bool bIsHiContrast = rSettings.GetHighContrastMode(); 364 sal_Bool bShowMenuImages = rSettings.GetUseImagesInMenus(); 365 sal_Bool bUpdateImages = (( m_bWasHiContrast != bIsHiContrast ) || ( bShowMenuImages != m_bShowMenuImages )); 366 367 if ( bUpdateImages ) 368 { 369 // The mode has changed or the complete menu so we have to retrieve all images again 370 m_bWasHiContrast = bIsHiContrast; 371 m_bShowMenuImages = bShowMenuImages; 372 373 VCLXPopupMenu* pPopupMenu = (VCLXPopupMenu *)VCLXPopupMenu::GetImplementation( m_xPopupMenu ); 374 if ( pPopupMenu ) 375 { 376 PopupMenu* pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu(); 377 if ( pVCLPopupMenu && bUpdateImages ) 378 updateImagesPopupMenu( pVCLPopupMenu ); 379 } 380 } 381 } 382 } 383 384 // XPopupMenuController 385 void ControlMenuController::impl_setPopupMenu() 386 { 387 if ( m_pResPopupMenu == 0 ) 388 { 389 rtl::OStringBuffer aBuf( 32 ); 390 aBuf.append( "svx" ); 391 392 ResMgr* pResMgr = ResMgr::CreateResMgr( aBuf.getStr() ); 393 if ( pResMgr ) 394 { 395 ResId aResId( RID_FMSHELL_CONVERSIONMENU, *pResMgr ); 396 aResId.SetRT( RSC_MENU ); 397 if ( pResMgr->IsAvailable( aResId )) 398 m_pResPopupMenu = new PopupMenu( aResId ); 399 400 updateImagesPopupMenu( m_pResPopupMenu ); 401 delete pResMgr; 402 } 403 } // if ( m_pResPopupMenu == 0 ) 404 } 405 406 void SAL_CALL ControlMenuController::updatePopupMenu() throw (::com::sun::star::uno::RuntimeException) 407 { 408 osl::ResettableMutexGuard aLock( m_aMutex ); 409 410 throwIfDisposed(); 411 412 if ( m_xFrame.is() && m_xPopupMenu.is() ) 413 { 414 URL aTargetURL; 415 Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY ); 416 fillPopupMenu( m_xPopupMenu ); 417 m_aURLToDispatchMap.free(); 418 419 for (sal_uInt32 i=0; i<sizeof(aCommands)/sizeof(aCommands[0]); ++i) 420 { 421 aTargetURL.Complete = rtl::OUString::createFromAscii( aCommands[i] ); 422 m_xURLTransformer->parseStrict( aTargetURL ); 423 424 Reference< XDispatch > xDispatch = xDispatchProvider->queryDispatch( aTargetURL, ::rtl::OUString(), 0 ); 425 if ( xDispatch.is() ) 426 { 427 xDispatch->addStatusListener( SAL_STATIC_CAST( XStatusListener*, this ), aTargetURL ); 428 xDispatch->removeStatusListener( SAL_STATIC_CAST( XStatusListener*, this ), aTargetURL ); 429 m_aURLToDispatchMap.insert( UrlToDispatchMap::value_type( aTargetURL.Complete, xDispatch )); 430 } 431 } 432 } 433 } 434 435 // XInitialization 436 void SAL_CALL ControlMenuController::initialize( const Sequence< Any >& aArguments ) throw ( Exception, RuntimeException ) 437 { 438 osl::ResettableMutexGuard aLock( m_aMutex ); 439 svt::PopupMenuControllerBase::initialize(aArguments); 440 m_aBaseURL = ::rtl::OUString(); 441 } 442 443 } 444