xref: /AOO41X/main/framework/source/fwe/helper/actiontriggerhelper.cxx (revision 47148b3bc50811ceb41802e4cc50a5db21535900)
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 
IsSeparator(Reference<XPropertySet> xPropertySet)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 
GetMenuItemAttributes(Reference<XPropertySet> xActionTriggerPropertySet,OUString & aMenuLabel,OUString & aCommandURL,OUString & aHelpURL,Reference<XBitmap> & xBitmap,Reference<XIndexContainer> & xSubContainer)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 
InsertSubMenuItems(Menu * pSubMenu,sal_uInt16 & nItemId,Reference<XIndexContainer> xActionTriggerContainer)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 
CreateActionTrigger(sal_uInt16 nItemId,const Menu * pMenu,const Reference<XIndexContainer> & rActionTriggerContainer)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 
CreateActionTriggerSeparator(const Reference<XIndexContainer> & rActionTriggerContainer)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 
CreateActionTriggerContainer(const Reference<XIndexContainer> & rActionTriggerContainer)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 
FillActionTriggerContainerWithMenu(const Menu * pMenu,Reference<XIndexContainer> & rActionTriggerContainer)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 
CreateMenuFromActionTriggerContainer(Menu * pNewMenu,const Reference<XIndexContainer> & rActionTriggerContainer)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 
FillActionTriggerContainerFromMenu(Reference<XIndexContainer> & xActionTriggerContainer,const Menu * pMenu)386 void ActionTriggerHelper::FillActionTriggerContainerFromMenu(
387     Reference< XIndexContainer >& xActionTriggerContainer,
388     const Menu* pMenu )
389 {
390     FillActionTriggerContainerWithMenu( pMenu, xActionTriggerContainer );
391 }
392 
CreateActionTriggerContainerFromMenu(const::com::sun::star::uno::Reference<::com::sun::star::lang::XMultiServiceFactory> & xServiceFactory,const Menu * pMenu,const::rtl::OUString * pMenuIdentifier)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