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 : namespace framework
44 : {
45 :
46 : // implementation helper ( menu => ActionTrigger )
47 :
48 0 : bool IsSeparator( Reference< XPropertySet > xPropertySet )
49 : {
50 0 : Reference< XServiceInfo > xServiceInfo( xPropertySet, UNO_QUERY );
51 : try
52 : {
53 0 : return xServiceInfo->supportsService( OUString( SERVICENAME_ACTIONTRIGGERSEPARATOR ) );
54 : }
55 0 : catch (const Exception&)
56 : {
57 : }
58 :
59 0 : return false;
60 : }
61 :
62 0 : void GetMenuItemAttributes( Reference< XPropertySet > xActionTriggerPropertySet,
63 : OUString& aMenuLabel,
64 : OUString& aCommandURL,
65 : OUString& aHelpURL,
66 : Reference< XBitmap >& xBitmap,
67 : Reference< XIndexContainer >& xSubContainer )
68 : {
69 0 : Any a;
70 :
71 : try
72 : {
73 : // mandatory properties
74 0 : a = xActionTriggerPropertySet->getPropertyValue("Text");
75 0 : a >>= aMenuLabel;
76 0 : a = xActionTriggerPropertySet->getPropertyValue("CommandURL");
77 0 : a >>= aCommandURL;
78 0 : a = xActionTriggerPropertySet->getPropertyValue("Image");
79 0 : a >>= xBitmap;
80 0 : a = xActionTriggerPropertySet->getPropertyValue("SubContainer");
81 0 : a >>= xSubContainer;
82 : }
83 0 : catch (const Exception&)
84 : {
85 : }
86 :
87 : // optional properties
88 : try
89 : {
90 0 : a = xActionTriggerPropertySet->getPropertyValue("HelpURL");
91 0 : a >>= aHelpURL;
92 : }
93 0 : catch (const Exception&)
94 : {
95 0 : }
96 0 : }
97 :
98 0 : void InsertSubMenuItems( Menu* pSubMenu, sal_uInt16& nItemId, Reference< XIndexContainer > xActionTriggerContainer )
99 : {
100 0 : if ( xActionTriggerContainer.is() )
101 : {
102 0 : AddonsOptions aAddonOptions;
103 0 : OUString aSlotURL( "slot:" );
104 :
105 0 : for ( sal_Int32 i = 0; i < xActionTriggerContainer->getCount(); i++ )
106 : {
107 : try
108 : {
109 0 : Reference< XPropertySet > xPropSet;
110 0 : if (( xActionTriggerContainer->getByIndex( i ) >>= xPropSet ) && ( xPropSet.is() ))
111 : {
112 0 : if ( IsSeparator( xPropSet ))
113 : {
114 : // Separator
115 0 : SolarMutexGuard aGuard;
116 0 : pSubMenu->InsertSeparator();
117 : }
118 : else
119 : {
120 : // Menu item
121 0 : OUString aLabel;
122 0 : OUString aCommandURL;
123 0 : OUString aHelpURL;
124 0 : Reference< XBitmap > xBitmap;
125 0 : Reference< XIndexContainer > xSubContainer;
126 :
127 0 : sal_uInt16 nNewItemId = nItemId++;
128 0 : GetMenuItemAttributes( xPropSet, aLabel, aCommandURL, aHelpURL, xBitmap, xSubContainer );
129 :
130 0 : SolarMutexGuard aGuard;
131 : {
132 : // insert new menu item
133 0 : sal_Int32 nIndex = aCommandURL.indexOf( aSlotURL );
134 0 : if ( nIndex >= 0 )
135 : {
136 : // Special code for our menu implementation: some menu items don't have a
137 : // command url but uses the item id as a unqiue identifier. These entries
138 : // got a special url during conversion from menu=>actiontriggercontainer.
139 : // Now we have to extract this special url and set the correct item id!!!
140 0 : nNewItemId = (sal_uInt16)aCommandURL.copy( nIndex+aSlotURL.getLength() ).toInt32();
141 0 : pSubMenu->InsertItem( nNewItemId, aLabel );
142 : }
143 : else
144 : {
145 0 : pSubMenu->InsertItem( nNewItemId, aLabel );
146 0 : pSubMenu->SetItemCommand( nNewItemId, aCommandURL );
147 : }
148 :
149 : // handle bitmap
150 0 : if ( xBitmap.is() )
151 : {
152 0 : bool bImageSet = false;
153 :
154 0 : Reference< XUnoTunnel > xUnoTunnel( xBitmap, UNO_QUERY );
155 0 : if ( xUnoTunnel.is() )
156 : {
157 : // Try to get implementation pointer through XUnoTunnel
158 0 : sal_Int64 nPointer = xUnoTunnel->getSomething( ImageWrapper::GetUnoTunnelId() );
159 0 : if ( nPointer )
160 : {
161 : // This is our own optimized implementation of menu images!
162 0 : ImageWrapper* pImageWrapper = reinterpret_cast< ImageWrapper * >( nPointer );
163 0 : Image aMenuImage = pImageWrapper->GetImage();
164 :
165 0 : if ( !!aMenuImage )
166 0 : pSubMenu->SetItemImage( nNewItemId, aMenuImage );
167 :
168 0 : bImageSet = true;
169 : }
170 : }
171 :
172 0 : if ( !bImageSet )
173 : {
174 : // This is an unknown implementation of a XBitmap interface. We have to
175 : // use a more time consuming way to build an Image!
176 0 : Image aImage;
177 0 : Bitmap aBitmap;
178 :
179 0 : Sequence< sal_Int8 > aDIBSeq;
180 : {
181 0 : aDIBSeq = xBitmap->getDIB();
182 0 : SvMemoryStream aMem( const_cast<sal_Int8 *>(aDIBSeq.getConstArray()), aDIBSeq.getLength(), StreamMode::READ );
183 0 : ReadDIB(aBitmap, aMem, true);
184 : }
185 :
186 0 : aDIBSeq = xBitmap->getMaskDIB();
187 0 : if ( aDIBSeq.getLength() > 0 )
188 : {
189 0 : Bitmap aMaskBitmap;
190 0 : SvMemoryStream aMem( const_cast<sal_Int8 *>(aDIBSeq.getConstArray()), aDIBSeq.getLength(), StreamMode::READ );
191 0 : ReadDIB(aMaskBitmap, aMem, true);
192 0 : aImage = Image( aBitmap, aMaskBitmap );
193 : }
194 : else
195 0 : aImage = Image( aBitmap );
196 :
197 0 : if ( !!aImage )
198 0 : pSubMenu->SetItemImage( nNewItemId, aImage );
199 0 : }
200 : }
201 : else
202 : {
203 : // Support add-on images for context menu interceptors
204 0 : Image aImage = aAddonOptions.GetImageFromURL( aCommandURL, false, true );
205 0 : if ( !!aImage )
206 0 : pSubMenu->SetItemImage( nNewItemId, aImage );
207 : }
208 :
209 0 : if ( xSubContainer.is() )
210 : {
211 0 : PopupMenu* pNewSubMenu = new PopupMenu;
212 :
213 : // Sub menu (recursive call CreateSubMenu )
214 0 : InsertSubMenuItems( pNewSubMenu, nItemId, xSubContainer );
215 0 : pSubMenu->SetPopupMenu( nNewItemId, pNewSubMenu );
216 : }
217 0 : }
218 : }
219 0 : }
220 : }
221 0 : catch (const IndexOutOfBoundsException&)
222 : {
223 0 : return;
224 : }
225 0 : catch (const WrappedTargetException&)
226 : {
227 0 : return;
228 : }
229 0 : catch (const RuntimeException&)
230 : {
231 0 : return;
232 : }
233 0 : }
234 : }
235 : }
236 :
237 : // implementation helper ( ActionTrigger => menu )
238 :
239 0 : Reference< XPropertySet > CreateActionTrigger( sal_uInt16 nItemId, const Menu* pMenu, const Reference< XIndexContainer >& rActionTriggerContainer ) throw ( RuntimeException )
240 : {
241 0 : Reference< XPropertySet > xPropSet;
242 :
243 0 : Reference< XMultiServiceFactory > xMultiServiceFactory( rActionTriggerContainer, UNO_QUERY );
244 0 : if ( xMultiServiceFactory.is() )
245 : {
246 0 : xPropSet = Reference< XPropertySet >( xMultiServiceFactory->createInstance(
247 0 : OUString( "com.sun.star.ui.ActionTrigger" ) ),
248 0 : UNO_QUERY );
249 :
250 0 : Any a;
251 :
252 : try
253 : {
254 : // Retrieve the menu attributes and set them in our PropertySet
255 0 : OUString aLabel = pMenu->GetItemText( nItemId );
256 0 : a <<= aLabel;
257 0 : xPropSet->setPropertyValue("Text", a );
258 :
259 0 : OUString aCommandURL = pMenu->GetItemCommand( nItemId );
260 :
261 0 : if ( aCommandURL.isEmpty() )
262 : {
263 0 : aCommandURL = "slot:" + OUString::number( nItemId );
264 : }
265 :
266 0 : a <<= aCommandURL;
267 0 : xPropSet->setPropertyValue("CommandURL", a );
268 :
269 0 : Image aImage = pMenu->GetItemImage( nItemId );
270 0 : if ( !!aImage )
271 : {
272 : // We use our own optimized XBitmap implementation
273 0 : Reference< XBitmap > xBitmap( static_cast< cppu::OWeakObject* >( new ImageWrapper( aImage )), UNO_QUERY );
274 0 : a <<= xBitmap;
275 0 : xPropSet->setPropertyValue("Image", a );
276 0 : }
277 : }
278 0 : catch (const Exception&)
279 : {
280 0 : }
281 : }
282 :
283 0 : return xPropSet;
284 : }
285 :
286 0 : Reference< XPropertySet > CreateActionTriggerSeparator( const Reference< XIndexContainer >& rActionTriggerContainer ) throw ( RuntimeException )
287 : {
288 0 : Reference< XMultiServiceFactory > xMultiServiceFactory( rActionTriggerContainer, UNO_QUERY );
289 0 : if ( xMultiServiceFactory.is() )
290 : {
291 0 : return Reference< XPropertySet >( xMultiServiceFactory->createInstance(
292 0 : OUString( "com.sun.star.ui.ActionTriggerSeparator" ) ),
293 0 : UNO_QUERY );
294 : }
295 :
296 0 : return Reference< XPropertySet >();
297 : }
298 :
299 0 : Reference< XIndexContainer > CreateActionTriggerContainer( const Reference< XIndexContainer >& rActionTriggerContainer ) throw ( RuntimeException )
300 : {
301 0 : Reference< XMultiServiceFactory > xMultiServiceFactory( rActionTriggerContainer, UNO_QUERY );
302 0 : if ( xMultiServiceFactory.is() )
303 : {
304 0 : return Reference< XIndexContainer >( xMultiServiceFactory->createInstance(
305 0 : OUString( "com.sun.star.ui.ActionTriggerContainer" ) ),
306 0 : UNO_QUERY );
307 : }
308 :
309 0 : return Reference< XIndexContainer >();
310 : }
311 :
312 0 : void FillActionTriggerContainerWithMenu( const Menu* pMenu, Reference< XIndexContainer >& rActionTriggerContainer )
313 : {
314 0 : SolarMutexGuard aGuard;
315 :
316 0 : for ( sal_uInt16 nPos = 0; nPos < pMenu->GetItemCount(); nPos++ )
317 : {
318 0 : sal_uInt16 nItemId = pMenu->GetItemId( nPos );
319 0 : MenuItemType nType = pMenu->GetItemType( nPos );
320 :
321 : try
322 : {
323 0 : Any a;
324 0 : Reference< XPropertySet > xPropSet;
325 :
326 0 : if ( nType == MenuItemType::SEPARATOR )
327 : {
328 0 : xPropSet = CreateActionTriggerSeparator( rActionTriggerContainer );
329 :
330 0 : a <<= xPropSet;
331 0 : rActionTriggerContainer->insertByIndex( nPos, a );
332 : }
333 : else
334 : {
335 0 : xPropSet = CreateActionTrigger( nItemId, pMenu, rActionTriggerContainer );
336 :
337 0 : a <<= xPropSet;
338 0 : rActionTriggerContainer->insertByIndex( nPos, a );
339 :
340 0 : PopupMenu* pPopupMenu = pMenu->GetPopupMenu( nItemId );
341 0 : if ( pPopupMenu )
342 : {
343 : // recursive call to build next sub menu
344 0 : Reference< XIndexContainer > xSubContainer = CreateActionTriggerContainer( rActionTriggerContainer );
345 :
346 0 : a <<= xSubContainer;
347 0 : xPropSet->setPropertyValue("SubContainer", a );
348 0 : FillActionTriggerContainerWithMenu( pPopupMenu, xSubContainer );
349 : }
350 0 : }
351 : }
352 0 : catch (const Exception&)
353 : {
354 : }
355 0 : }
356 0 : }
357 :
358 0 : void ActionTriggerHelper::CreateMenuFromActionTriggerContainer(
359 : Menu* pNewMenu,
360 : const Reference< XIndexContainer >& rActionTriggerContainer )
361 : {
362 0 : sal_uInt16 nItemId = START_ITEMID;
363 :
364 0 : if ( rActionTriggerContainer.is() )
365 0 : InsertSubMenuItems( pNewMenu, nItemId, rActionTriggerContainer );
366 0 : }
367 :
368 0 : void ActionTriggerHelper::FillActionTriggerContainerFromMenu(
369 : Reference< XIndexContainer >& xActionTriggerContainer,
370 : const Menu* pMenu )
371 : {
372 0 : FillActionTriggerContainerWithMenu( pMenu, xActionTriggerContainer );
373 0 : }
374 :
375 0 : Reference< XIndexContainer > ActionTriggerHelper::CreateActionTriggerContainerFromMenu(
376 : const Menu* pMenu,
377 : const OUString* pMenuIdentifier )
378 : {
379 0 : return new RootActionTriggerContainer( pMenu, pMenuIdentifier );
380 : }
381 :
382 : }
383 :
384 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|