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