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 <framework/actiontriggerhelper.hxx> 31 #include <classes/actiontriggerseparatorpropertyset.hxx> 32 #include <classes/rootactiontriggercontainer.hxx> 33 #include <classes/imagewrapper.hxx> 34 #include <framework/addonsoptions.hxx> 35 #include <com/sun/star/lang/XServiceInfo.hpp> 36 #include <com/sun/star/beans/XPropertySet.hpp> 37 #include <com/sun/star/awt/XBitmap.hpp> 38 #include <vcl/svapp.hxx> 39 #include <vos/mutex.hxx> 40 #include <tools/stream.hxx> 41 #include <cppuhelper/weak.hxx> 42 #include <comphelper/processfactory.hxx> 43 44 45 const sal_uInt16 START_ITEMID = 1000; 46 47 using namespace rtl; 48 using namespace vos; 49 using namespace com::sun::star::awt; 50 using namespace com::sun::star::uno; 51 using namespace com::sun::star::lang; 52 using namespace com::sun::star::beans; 53 using namespace com::sun::star::container; 54 55 namespace framework 56 { 57 58 // ---------------------------------------------------------------------------- 59 // implementation helper ( menu => ActionTrigger ) 60 // ---------------------------------------------------------------------------- 61 62 sal_Bool IsSeparator( Reference< XPropertySet > xPropertySet ) 63 { 64 Reference< XServiceInfo > xServiceInfo( xPropertySet, UNO_QUERY ); 65 try 66 { 67 return xServiceInfo->supportsService( OUString( RTL_CONSTASCII_USTRINGPARAM( SERVICENAME_ACTIONTRIGGERSEPARATOR )) ); 68 } 69 catch ( Exception& ) 70 { 71 } 72 73 return sal_False; 74 } 75 76 void GetMenuItemAttributes( Reference< XPropertySet > xActionTriggerPropertySet, 77 OUString& aMenuLabel, 78 OUString& aCommandURL, 79 OUString& aHelpURL, 80 Reference< XBitmap >& xBitmap, 81 Reference< XIndexContainer >& xSubContainer ) 82 { 83 Any a; 84 85 try 86 { 87 // mandatory properties 88 a = xActionTriggerPropertySet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "Text" )) ); 89 a >>= aMenuLabel; 90 a = xActionTriggerPropertySet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "CommandURL" )) ); 91 a >>= aCommandURL; 92 a = xActionTriggerPropertySet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "Image" )) ); 93 a >>= xBitmap; 94 a = xActionTriggerPropertySet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "SubContainer" )) ); 95 a >>= xSubContainer; 96 } 97 catch ( Exception& ) 98 { 99 } 100 101 // optional properties 102 try 103 { 104 a = xActionTriggerPropertySet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "HelpURL" )) ); 105 a >>= aHelpURL; 106 } 107 catch ( Exception& ) 108 { 109 } 110 } 111 112 void InsertSubMenuItems( Menu* pSubMenu, sal_uInt16& nItemId, Reference< XIndexContainer > xActionTriggerContainer ) 113 { 114 Reference< XIndexAccess > xIndexAccess( xActionTriggerContainer, UNO_QUERY ); 115 if ( xIndexAccess.is() ) 116 { 117 AddonsOptions aAddonOptions; 118 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); 119 sal_Bool bHiContrast = rSettings.GetHighContrastMode(); 120 121 OUString aSlotURL( RTL_CONSTASCII_USTRINGPARAM( "slot:" )); 122 123 for ( sal_Int32 i = 0; i < xIndexAccess->getCount(); i++ ) 124 { 125 try 126 { 127 Reference< XPropertySet > xPropSet; 128 if (( xIndexAccess->getByIndex( i ) >>= xPropSet ) && ( xPropSet.is() )) 129 { 130 if ( IsSeparator( xPropSet )) 131 { 132 // Separator 133 OGuard aGuard( Application::GetSolarMutex() ); 134 pSubMenu->InsertSeparator(); 135 } 136 else 137 { 138 // Menu item 139 OUString aLabel; 140 OUString aCommandURL; 141 OUString aHelpURL; 142 Reference< XBitmap > xBitmap; 143 Reference< XIndexContainer > xSubContainer; 144 sal_Bool bSpecialItemId = sal_False; 145 146 sal_uInt16 nNewItemId = nItemId++; 147 GetMenuItemAttributes( xPropSet, aLabel, aCommandURL, aHelpURL, xBitmap, xSubContainer ); 148 149 OGuard aGuard( Application::GetSolarMutex() ); 150 { 151 // insert new menu item 152 sal_Int32 nIndex = aCommandURL.indexOf( aSlotURL ); 153 if ( nIndex >= 0 ) 154 { 155 // Special code for our menu implementation: some menu items don't have a 156 // command url but uses the item id as a unqiue identifier. These entries 157 // got a special url during conversion from menu=>actiontriggercontainer. 158 // Now we have to extract this special url and set the correct item id!!! 159 bSpecialItemId = sal_True; 160 nNewItemId = (sal_uInt16)aCommandURL.copy( nIndex+aSlotURL.getLength() ).toInt32(); 161 pSubMenu->InsertItem( nNewItemId, aLabel ); 162 } 163 else 164 { 165 pSubMenu->InsertItem( nNewItemId, aLabel ); 166 pSubMenu->SetItemCommand( nNewItemId, aCommandURL ); 167 } 168 169 // handle bitmap 170 if ( xBitmap.is() ) 171 { 172 sal_Bool bImageSet = sal_False; 173 174 Reference< XUnoTunnel > xUnoTunnel( xBitmap, UNO_QUERY ); 175 if ( xUnoTunnel.is() ) 176 { 177 // Try to get implementation pointer through XUnoTunnel 178 sal_Int64 nPointer = xUnoTunnel->getSomething( ImageWrapper::GetUnoTunnelId() ); 179 if ( nPointer ) 180 { 181 // This is our own optimized implementation of menu images! 182 ImageWrapper* pImageWrapper = reinterpret_cast< ImageWrapper * >( nPointer ); 183 Image aMenuImage = pImageWrapper->GetImage(); 184 185 if ( !!aMenuImage ) 186 pSubMenu->SetItemImage( nNewItemId, aMenuImage ); 187 188 bImageSet = sal_True; 189 } 190 } 191 192 if ( !bImageSet ) 193 { 194 // This is an unknown implementation of a XBitmap interface. We have to 195 // use a more time consuming way to build an Image! 196 Image aImage; 197 Bitmap aBitmap; 198 199 Sequence< sal_Int8 > aDIBSeq; 200 { 201 aDIBSeq = xBitmap->getDIB(); 202 SvMemoryStream aMem( (void *)aDIBSeq.getConstArray(), aDIBSeq.getLength(), STREAM_READ ); 203 aMem >> aBitmap; 204 } 205 206 aDIBSeq = xBitmap->getMaskDIB(); 207 if ( aDIBSeq.getLength() > 0 ) 208 { 209 Bitmap aMaskBitmap; 210 SvMemoryStream aMem( (void *)aDIBSeq.getConstArray(), aDIBSeq.getLength(), STREAM_READ ); 211 aMem >> aMaskBitmap; 212 aImage = Image( aBitmap, aMaskBitmap ); 213 } 214 else 215 aImage = Image( aBitmap ); 216 217 if ( !!aImage ) 218 pSubMenu->SetItemImage( nNewItemId, aImage ); 219 } 220 } 221 else 222 { 223 // Support add-on images for context menu interceptors 224 Image aImage = aAddonOptions.GetImageFromURL( aCommandURL, sal_False, bHiContrast, sal_True ); 225 if ( !!aImage ) 226 pSubMenu->SetItemImage( nNewItemId, aImage ); 227 } 228 229 if ( xSubContainer.is() ) 230 { 231 PopupMenu* pNewSubMenu = new PopupMenu; 232 233 // Sub menu (recursive call CreateSubMenu ) 234 InsertSubMenuItems( pNewSubMenu, nItemId, xSubContainer ); 235 pSubMenu->SetPopupMenu( nNewItemId, pNewSubMenu ); 236 } 237 } 238 } 239 } 240 } 241 catch ( IndexOutOfBoundsException ) 242 { 243 return; 244 } 245 catch ( WrappedTargetException ) 246 { 247 return; 248 } 249 catch ( RuntimeException ) 250 { 251 return; 252 } 253 } 254 } 255 } 256 257 258 // ---------------------------------------------------------------------------- 259 // implementation helper ( ActionTrigger => menu ) 260 // ---------------------------------------------------------------------------- 261 262 Reference< XPropertySet > CreateActionTrigger( sal_uInt16 nItemId, const Menu* pMenu, const Reference< XIndexContainer >& rActionTriggerContainer ) throw ( RuntimeException ) 263 { 264 Reference< XPropertySet > xPropSet; 265 266 Reference< XMultiServiceFactory > xMultiServiceFactory( rActionTriggerContainer, UNO_QUERY ); 267 if ( xMultiServiceFactory.is() ) 268 { 269 xPropSet = Reference< XPropertySet >( xMultiServiceFactory->createInstance( 270 OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ui.ActionTrigger" )) ), 271 UNO_QUERY ); 272 273 Any a; 274 275 try 276 { 277 // Retrieve the menu attributes and set them in our PropertySet 278 OUString aLabel = pMenu->GetItemText( nItemId ); 279 a <<= aLabel; 280 xPropSet->setPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "Text" )), a ); 281 282 OUString aCommandURL = pMenu->GetItemCommand( nItemId ); 283 284 if ( aCommandURL.getLength() == 0 ) 285 { 286 aCommandURL = OUString( RTL_CONSTASCII_USTRINGPARAM( "slot:" )); 287 aCommandURL += OUString::valueOf( (sal_Int32)nItemId ); 288 } 289 290 a <<= aCommandURL; 291 xPropSet->setPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "CommandURL" )), a ); 292 293 Image aImage = pMenu->GetItemImage( nItemId ); 294 if ( !!aImage ) 295 { 296 // We use our own optimized XBitmap implementation 297 Reference< XBitmap > xBitmap( static_cast< cppu::OWeakObject* >( new ImageWrapper( aImage )), UNO_QUERY ); 298 a <<= xBitmap; 299 xPropSet->setPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "Image" )), a ); 300 } 301 } 302 catch ( Exception& ) 303 { 304 } 305 } 306 307 return xPropSet; 308 } 309 310 Reference< XPropertySet > CreateActionTriggerSeparator( const Reference< XIndexContainer >& rActionTriggerContainer ) throw ( RuntimeException ) 311 { 312 Reference< XMultiServiceFactory > xMultiServiceFactory( rActionTriggerContainer, UNO_QUERY ); 313 if ( xMultiServiceFactory.is() ) 314 { 315 return Reference< XPropertySet >( xMultiServiceFactory->createInstance( 316 OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ui.ActionTriggerSeparator" )) ), 317 UNO_QUERY ); 318 } 319 320 return Reference< XPropertySet >(); 321 } 322 323 Reference< XIndexContainer > CreateActionTriggerContainer( const Reference< XIndexContainer >& rActionTriggerContainer ) throw ( RuntimeException ) 324 { 325 Reference< XMultiServiceFactory > xMultiServiceFactory( rActionTriggerContainer, UNO_QUERY ); 326 if ( xMultiServiceFactory.is() ) 327 { 328 return Reference< XIndexContainer >( xMultiServiceFactory->createInstance( 329 OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ui.ActionTriggerContainer" )) ), 330 UNO_QUERY ); 331 } 332 333 return Reference< XIndexContainer >(); 334 } 335 336 void FillActionTriggerContainerWithMenu( const Menu* pMenu, Reference< XIndexContainer >& rActionTriggerContainer ) 337 { 338 OGuard aGuard( Application::GetSolarMutex() ); 339 340 for ( sal_uInt16 nPos = 0; nPos < pMenu->GetItemCount(); nPos++ ) 341 { 342 sal_uInt16 nItemId = pMenu->GetItemId( nPos ); 343 MenuItemType nType = pMenu->GetItemType( nPos ); 344 345 try 346 { 347 Any a; 348 Reference< XPropertySet > xPropSet; 349 350 if ( nType == MENUITEM_SEPARATOR ) 351 { 352 xPropSet = CreateActionTriggerSeparator( rActionTriggerContainer ); 353 354 a <<= xPropSet; 355 rActionTriggerContainer->insertByIndex( nPos, a ); 356 } 357 else 358 { 359 xPropSet = CreateActionTrigger( nItemId, pMenu, rActionTriggerContainer ); 360 361 a <<= xPropSet; 362 rActionTriggerContainer->insertByIndex( nPos, a ); 363 364 PopupMenu* pPopupMenu = pMenu->GetPopupMenu( nItemId ); 365 if ( pPopupMenu ) 366 { 367 // recursive call to build next sub menu 368 Reference< XIndexContainer > xSubContainer = CreateActionTriggerContainer( rActionTriggerContainer ); 369 370 a <<= xSubContainer; 371 xPropSet->setPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "SubContainer" )), a ); 372 FillActionTriggerContainerWithMenu( pPopupMenu, xSubContainer ); 373 } 374 } 375 } 376 catch ( Exception& ) 377 { 378 } 379 } 380 } 381 382 void ActionTriggerHelper::CreateMenuFromActionTriggerContainer( 383 Menu* pNewMenu, 384 const Reference< XIndexContainer >& rActionTriggerContainer ) 385 { 386 sal_uInt16 nItemId = START_ITEMID; 387 388 if ( rActionTriggerContainer.is() ) 389 InsertSubMenuItems( pNewMenu, nItemId, rActionTriggerContainer ); 390 } 391 392 void ActionTriggerHelper::FillActionTriggerContainerFromMenu( 393 Reference< XIndexContainer >& xActionTriggerContainer, 394 const Menu* pMenu ) 395 { 396 FillActionTriggerContainerWithMenu( pMenu, xActionTriggerContainer ); 397 } 398 399 Reference< XIndexContainer > ActionTriggerHelper::CreateActionTriggerContainerFromMenu( 400 // #110897# 401 const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xServiceFactory, 402 const Menu* pMenu, 403 const ::rtl::OUString* pMenuIdentifier ) 404 { 405 return new RootActionTriggerContainer( pMenu, pMenuIdentifier, xServiceFactory ); 406 } 407 408 } 409