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