LibreOffice Module framework (master) 1
actiontriggerhelper.cxx
Go to the documentation of this file.
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
24#include <com/sun/star/awt/XBitmap.hpp>
25#include <com/sun/star/awt/XPopupMenu.hpp>
26#include <com/sun/star/beans/XPropertySet.hpp>
27#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
28#include <com/sun/star/lang/XServiceInfo.hpp>
30#include <tools/stream.hxx>
31#include <vcl/dibtools.hxx>
32#include <vcl/graph.hxx>
33#include <vcl/svapp.hxx>
34#include <o3tl/string_view.hxx>
35
36const sal_uInt16 START_ITEMID = 1000;
37
38using namespace com::sun::star::awt;
39using namespace com::sun::star::uno;
40using namespace com::sun::star::lang;
41using namespace com::sun::star::beans;
42using namespace com::sun::star::container;
43
44namespace framework
45{
46
47// implementation helper ( menu => ActionTrigger )
48
49static bool IsSeparator( const Reference< XPropertySet >& xPropertySet )
50{
51 Reference< XServiceInfo > xServiceInfo( xPropertySet, UNO_QUERY );
52 try
53 {
54 return xServiceInfo->supportsService( SERVICENAME_ACTIONTRIGGERSEPARATOR );
55 }
56 catch (const Exception&)
57 {
58 }
59
60 return false;
61}
62
63static void GetMenuItemAttributes( const Reference< XPropertySet >& xActionTriggerPropertySet,
64 OUString& aMenuLabel,
65 OUString& aCommandURL,
66 OUString& aHelpURL,
67 Reference< XBitmap >& xBitmap,
68 Reference< XIndexContainer >& xSubContainer )
69{
70 Any a;
71
72 try
73 {
74 // mandatory properties
75 a = xActionTriggerPropertySet->getPropertyValue("Text");
76 a >>= aMenuLabel;
77 a = xActionTriggerPropertySet->getPropertyValue("CommandURL");
78 a >>= aCommandURL;
79 a = xActionTriggerPropertySet->getPropertyValue("Image");
80 a >>= xBitmap;
81 a = xActionTriggerPropertySet->getPropertyValue("SubContainer");
82 a >>= xSubContainer;
83 }
84 catch (const Exception&)
85 {
86 }
87
88 // optional properties
89 try
90 {
91 a = xActionTriggerPropertySet->getPropertyValue("HelpURL");
92 a >>= aHelpURL;
93 }
94 catch (const Exception&)
95 {
96 }
97}
98
99static void InsertSubMenuItems(const Reference<XPopupMenu>& rSubMenu, sal_uInt16& nItemId,
100 const Reference<XIndexContainer>& xActionTriggerContainer)
101{
102 if ( !xActionTriggerContainer.is() )
103 return;
104
105 AddonsOptions aAddonOptions;
106 OUString aSlotURL( "slot:" );
107
108 for ( sal_Int32 i = 0; i < xActionTriggerContainer->getCount(); i++ )
109 {
110 try
111 {
113 if (( xActionTriggerContainer->getByIndex( i ) >>= xPropSet ) && ( xPropSet.is() ))
114 {
115 if ( IsSeparator( xPropSet ))
116 {
117 // Separator
118 SolarMutexGuard aGuard;
119 rSubMenu->insertSeparator(i);
120 }
121 else
122 {
123 // Menu item
124 OUString aLabel;
125 OUString aCommandURL;
126 OUString aHelpURL;
127 Reference< XBitmap > xBitmap;
128 Reference< XIndexContainer > xSubContainer;
129
130 sal_uInt16 nNewItemId = nItemId++;
131 GetMenuItemAttributes( xPropSet, aLabel, aCommandURL, aHelpURL, xBitmap, xSubContainer );
132
133 SolarMutexGuard aGuard;
134 {
135 // insert new menu item
136 sal_Int32 nIndex = aCommandURL.indexOf( aSlotURL );
137 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 unique 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 nNewItemId = static_cast<sal_uInt16>(o3tl::toInt32(aCommandURL.subView( nIndex+aSlotURL.getLength() )));
144 rSubMenu->insertItem(nNewItemId, aLabel, 0, i);
145 }
146 else
147 {
148 rSubMenu->insertItem(nNewItemId, aLabel, 0, i);
149 rSubMenu->setCommand(nNewItemId, aCommandURL);
150 }
151
152 // handle bitmap
153 if ( xBitmap.is() )
154 {
155 bool bImageSet = false;
156
157 Reference<css::graphic::XGraphic> xGraphic(xBitmap, UNO_QUERY);
158 if (xGraphic.is())
159 {
160 // we can take the optimized route if XGraphic is supported
161 rSubMenu->setItemImage(nNewItemId, xGraphic, false);
162 bImageSet = true;
163 }
164
165 if ( !bImageSet )
166 {
167 // This is an unknown implementation of a XBitmap interface. We have to
168 // use a more time consuming way to build an Image!
169 BitmapEx aBitmap;
170
171 Sequence< sal_Int8 > aDIBSeq;
172 {
173 aDIBSeq = xBitmap->getDIB();
174 SvMemoryStream aMem( const_cast<sal_Int8 *>(aDIBSeq.getConstArray()), aDIBSeq.getLength(), StreamMode::READ );
175 ReadDIBBitmapEx(aBitmap, aMem);
176 }
177
178 aDIBSeq = xBitmap->getMaskDIB();
179 if ( aDIBSeq.hasElements() )
180 {
181 Bitmap aMaskBitmap;
182 SvMemoryStream aMem( const_cast<sal_Int8 *>(aDIBSeq.getConstArray()), aDIBSeq.getLength(), StreamMode::READ );
183 ReadDIB(aMaskBitmap, aMem, true);
184 aBitmap = BitmapEx(aBitmap.GetBitmap(), aMaskBitmap);
185 }
186
187 if (!aBitmap.IsEmpty())
188 rSubMenu->setItemImage(nNewItemId, Graphic(aBitmap).GetXGraphic(), false);
189 }
190 }
191 else
192 {
193 // Support add-on images for context menu interceptors
194 BitmapEx aBitmap(aAddonOptions.GetImageFromURL(aCommandURL, false, true));
195 if (!aBitmap.IsEmpty())
196 rSubMenu->setItemImage(nNewItemId, Graphic(aBitmap).GetXGraphic(), false);
197 }
198
199 if ( xSubContainer.is() )
200 {
201 rtl::Reference xNewSubMenu(new VCLXPopupMenu);
202
203 // Sub menu (recursive call CreateSubMenu )
204 InsertSubMenuItems(xNewSubMenu, nItemId, xSubContainer);
205 rSubMenu->setPopupMenu(nNewItemId, xNewSubMenu);
206 }
207 }
208 }
209 }
210 }
211 catch (const IndexOutOfBoundsException&)
212 {
213 return;
214 }
215 catch (const WrappedTargetException&)
216 {
217 return;
218 }
219 catch (const RuntimeException&)
220 {
221 return;
222 }
223 }
224}
225
226// implementation helper ( ActionTrigger => menu )
227
230 const Reference<XPopupMenu>& rMenu,
231 const Reference<XIndexContainer>& rActionTriggerContainer)
232{
234
235 Reference< XMultiServiceFactory > xMultiServiceFactory( rActionTriggerContainer, UNO_QUERY );
236 if ( xMultiServiceFactory.is() )
237 {
238 xPropSet.set( xMultiServiceFactory->createInstance( "com.sun.star.ui.ActionTrigger" ),
239 UNO_QUERY );
240
241 Any a;
242
243 try
244 {
245 // Retrieve the menu attributes and set them in our PropertySet
246 OUString aLabel = rMenu->getItemText(nItemId);
247 a <<= aLabel;
248 xPropSet->setPropertyValue("Text", a );
249
250 OUString aCommandURL = rMenu->getCommand(nItemId);
251
252 if ( aCommandURL.isEmpty() )
253 {
254 aCommandURL = "slot:" + OUString::number( nItemId );
255 }
256
257 a <<= aCommandURL;
258 xPropSet->setPropertyValue("CommandURL", a );
259
260 Reference<XBitmap> xBitmap(rMenu->getItemImage(nItemId), UNO_QUERY);
261 if (xBitmap.is())
262 {
263 a <<= xBitmap;
264 xPropSet->setPropertyValue("Image", a );
265 }
266 }
267 catch (const Exception&)
268 {
269 }
270 }
271
272 return xPropSet;
273}
274
277{
278 Reference< XMultiServiceFactory > xMultiServiceFactory( rActionTriggerContainer, UNO_QUERY );
279 if ( xMultiServiceFactory.is() )
280 {
281 return Reference< XPropertySet >( xMultiServiceFactory->createInstance(
282 "com.sun.star.ui.ActionTriggerSeparator" ),
283 UNO_QUERY );
284 }
285
287}
288
291{
292 Reference< XMultiServiceFactory > xMultiServiceFactory( rActionTriggerContainer, UNO_QUERY );
293 if ( xMultiServiceFactory.is() )
294 {
295 return Reference< XIndexContainer >( xMultiServiceFactory->createInstance(
296 "com.sun.star.ui.ActionTriggerContainer" ),
297 UNO_QUERY );
298 }
299
301}
302
304 const Reference<XIndexContainer>& rActionTriggerContainer)
305{
306 SolarMutexGuard aGuard;
307
308 for (sal_uInt16 nPos = 0, nCount = rMenu->getItemCount(); nPos < nCount; ++nPos)
309 {
310 sal_uInt16 nItemId = rMenu->getItemId(nPos);
311 css::awt::MenuItemType nType = rMenu->getItemType(nPos);
312
313 try
314 {
315 Any a;
317
318 if (nType == css::awt::MenuItemType_SEPARATOR)
319 {
320 xPropSet = CreateActionTriggerSeparator( rActionTriggerContainer );
321
322 a <<= xPropSet;
323 rActionTriggerContainer->insertByIndex( nPos, a );
324 }
325 else
326 {
327 xPropSet = CreateActionTrigger(nItemId, rMenu, rActionTriggerContainer);
328
329 a <<= xPropSet;
330 rActionTriggerContainer->insertByIndex( nPos, a );
331
332 css::uno::Reference<XPopupMenu> xPopupMenu = rMenu->getPopupMenu(nItemId);
333 if (xPopupMenu.is())
334 {
335 // recursive call to build next sub menu
336 Reference< XIndexContainer > xSubContainer = CreateActionTriggerContainer( rActionTriggerContainer );
337
338 a <<= xSubContainer;
339 xPropSet->setPropertyValue("SubContainer", a );
340 FillActionTriggerContainerWithMenu(xPopupMenu, xSubContainer);
341 }
342 }
343 }
344 catch (const Exception&)
345 {
346 }
347 }
348}
349
351 const Reference<XPopupMenu>& rNewMenu,
352 const Reference<XIndexContainer>& rActionTriggerContainer)
353{
354 sal_uInt16 nItemId = START_ITEMID;
355
356 if ( rActionTriggerContainer.is() )
357 InsertSubMenuItems(rNewMenu, nItemId, rActionTriggerContainer);
358}
359
361 Reference< XIndexContainer > const & xActionTriggerContainer,
362 const css::uno::Reference<XPopupMenu>& rMenu)
363{
364 FillActionTriggerContainerWithMenu(rMenu, xActionTriggerContainer);
365}
366
368 const css::uno::Reference<XPopupMenu>& rMenu,
369 const OUString* pMenuIdentifier )
370{
371 return new RootActionTriggerContainer(rMenu, pMenuIdentifier);
372}
373
374}
375
376/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const sal_uInt16 START_ITEMID
constexpr OUStringLiteral SERVICENAME_ACTIONTRIGGERSEPARATOR
bool IsEmpty() const
Bitmap GetBitmap(Color aTransparentReplaceColor) const
static void FillActionTriggerContainerFromMenu(css::uno::Reference< css::container::XIndexContainer > const &rActionTriggerContainer, const css::uno::Reference< css::awt::XPopupMenu > &rMenu)
static void CreateMenuFromActionTriggerContainer(const css::uno::Reference< css::awt::XPopupMenu > &rNewMenu, const css::uno::Reference< css::container::XIndexContainer > &rActionTriggerContainer)
static css::uno::Reference< css::container::XIndexContainer > CreateActionTriggerContainerFromMenu(const css::uno::Reference< css::awt::XPopupMenu > &rMenu, const OUString *pMenuIdentifier)
int nCount
bool VCL_DLLPUBLIC ReadDIB(Bitmap &rTarget, SvStream &rIStm, bool bFileHeader, bool bMSOFormat=false)
bool VCL_DLLPUBLIC ReadDIBBitmapEx(BitmapEx &rTarget, SvStream &rIStm, bool bFileHeader=true, bool bMSOFormat=false)
sal_Int32 nIndex
uno_Any a
sal_uInt16 nPos
@ Exception
static void InsertSubMenuItems(const Reference< XPopupMenu > &rSubMenu, sal_uInt16 &nItemId, const Reference< XIndexContainer > &xActionTriggerContainer)
static void GetMenuItemAttributes(const Reference< XPropertySet > &xActionTriggerPropertySet, OUString &aMenuLabel, OUString &aCommandURL, OUString &aHelpURL, Reference< XBitmap > &xBitmap, Reference< XIndexContainer > &xSubContainer)
static void FillActionTriggerContainerWithMenu(const Reference< XPopupMenu > &rMenu, const Reference< XIndexContainer > &rActionTriggerContainer)
static Reference< XPropertySet > CreateActionTriggerSeparator(const Reference< XIndexContainer > &rActionTriggerContainer)
static Reference< XPropertySet > CreateActionTrigger(sal_uInt16 nItemId, const Reference< XPopupMenu > &rMenu, const Reference< XIndexContainer > &rActionTriggerContainer)
static bool IsSeparator(const Reference< XPropertySet > &xPropertySet)
static Reference< XIndexContainer > CreateActionTriggerContainer(const Reference< XIndexContainer > &rActionTriggerContainer)
int i
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
QPRO_FUNC_TYPE nType
signed char sal_Int8
OUString aLabel