xref: /AOO41X/main/framework/source/fwe/helper/actiontriggerhelper.cxx (revision 8809db7a87f97847b57a57f4cd2b0104b2b83182)
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