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