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