xref: /trunk/main/framework/source/fwe/helper/actiontriggerhelper.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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