1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
35 const sal_uInt16 START_ITEMID
= 1000;
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
;
46 // implementation helper ( menu => ActionTrigger )
48 bool IsSeparator( Reference
< XPropertySet
> xPropertySet
)
50 Reference
< XServiceInfo
> xServiceInfo( xPropertySet
, UNO_QUERY
);
53 return xServiceInfo
->supportsService( OUString( SERVICENAME_ACTIONTRIGGERSEPARATOR
) );
55 catch (const Exception
&)
62 void GetMenuItemAttributes( Reference
< XPropertySet
> xActionTriggerPropertySet
,
64 OUString
& aCommandURL
,
66 Reference
< XBitmap
>& xBitmap
,
67 Reference
< XIndexContainer
>& xSubContainer
)
73 // mandatory properties
74 a
= xActionTriggerPropertySet
->getPropertyValue("Text");
76 a
= xActionTriggerPropertySet
->getPropertyValue("CommandURL");
78 a
= xActionTriggerPropertySet
->getPropertyValue("Image");
80 a
= xActionTriggerPropertySet
->getPropertyValue("SubContainer");
83 catch (const Exception
&)
87 // optional properties
90 a
= xActionTriggerPropertySet
->getPropertyValue("HelpURL");
93 catch (const Exception
&)
98 void InsertSubMenuItems( Menu
* pSubMenu
, sal_uInt16
& nItemId
, Reference
< XIndexContainer
> xActionTriggerContainer
)
100 if ( xActionTriggerContainer
.is() )
102 AddonsOptions aAddonOptions
;
103 OUString
aSlotURL( "slot:" );
105 for ( sal_Int32 i
= 0; i
< xActionTriggerContainer
->getCount(); i
++ )
109 Reference
< XPropertySet
> xPropSet
;
110 if (( xActionTriggerContainer
->getByIndex( i
) >>= xPropSet
) && ( xPropSet
.is() ))
112 if ( IsSeparator( xPropSet
))
115 SolarMutexGuard aGuard
;
116 pSubMenu
->InsertSeparator();
122 OUString aCommandURL
;
124 Reference
< XBitmap
> xBitmap
;
125 Reference
< XIndexContainer
> xSubContainer
;
127 sal_uInt16 nNewItemId
= nItemId
++;
128 GetMenuItemAttributes( xPropSet
, aLabel
, aCommandURL
, aHelpURL
, xBitmap
, xSubContainer
);
130 SolarMutexGuard aGuard
;
132 // insert new menu item
133 sal_Int32 nIndex
= aCommandURL
.indexOf( aSlotURL
);
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 nNewItemId
= (sal_uInt16
)aCommandURL
.copy( nIndex
+aSlotURL
.getLength() ).toInt32();
141 pSubMenu
->InsertItem( nNewItemId
, aLabel
);
145 pSubMenu
->InsertItem( nNewItemId
, aLabel
);
146 pSubMenu
->SetItemCommand( nNewItemId
, aCommandURL
);
152 bool bImageSet
= false;
154 Reference
< XUnoTunnel
> xUnoTunnel( xBitmap
, UNO_QUERY
);
155 if ( xUnoTunnel
.is() )
157 // Try to get implementation pointer through XUnoTunnel
158 sal_Int64 nPointer
= xUnoTunnel
->getSomething( ImageWrapper::GetUnoTunnelId() );
161 // This is our own optimized implementation of menu images!
162 ImageWrapper
* pImageWrapper
= reinterpret_cast< ImageWrapper
* >( nPointer
);
163 Image aMenuImage
= pImageWrapper
->GetImage();
166 pSubMenu
->SetItemImage( nNewItemId
, aMenuImage
);
174 // This is an unknown implementation of a XBitmap interface. We have to
175 // use a more time consuming way to build an Image!
179 Sequence
< sal_Int8
> aDIBSeq
;
181 aDIBSeq
= xBitmap
->getDIB();
182 SvMemoryStream
aMem( (void *)aDIBSeq
.getConstArray(), aDIBSeq
.getLength(), StreamMode::READ
);
183 ReadDIB(aBitmap
, aMem
, true);
186 aDIBSeq
= xBitmap
->getMaskDIB();
187 if ( aDIBSeq
.getLength() > 0 )
190 SvMemoryStream
aMem( (void *)aDIBSeq
.getConstArray(), aDIBSeq
.getLength(), StreamMode::READ
);
191 ReadDIB(aMaskBitmap
, aMem
, true);
192 aImage
= Image( aBitmap
, aMaskBitmap
);
195 aImage
= Image( aBitmap
);
198 pSubMenu
->SetItemImage( nNewItemId
, aImage
);
203 // Support add-on images for context menu interceptors
204 Image aImage
= aAddonOptions
.GetImageFromURL( aCommandURL
, false, true );
206 pSubMenu
->SetItemImage( nNewItemId
, aImage
);
209 if ( xSubContainer
.is() )
211 PopupMenu
* pNewSubMenu
= new PopupMenu
;
213 // Sub menu (recursive call CreateSubMenu )
214 InsertSubMenuItems( pNewSubMenu
, nItemId
, xSubContainer
);
215 pSubMenu
->SetPopupMenu( nNewItemId
, pNewSubMenu
);
221 catch (const IndexOutOfBoundsException
&)
225 catch (const WrappedTargetException
&)
229 catch (const RuntimeException
&)
237 // implementation helper ( ActionTrigger => menu )
239 Reference
< XPropertySet
> CreateActionTrigger( sal_uInt16 nItemId
, const Menu
* pMenu
, const Reference
< XIndexContainer
>& rActionTriggerContainer
) throw ( RuntimeException
)
241 Reference
< XPropertySet
> xPropSet
;
243 Reference
< XMultiServiceFactory
> xMultiServiceFactory( rActionTriggerContainer
, UNO_QUERY
);
244 if ( xMultiServiceFactory
.is() )
246 xPropSet
= Reference
< XPropertySet
>( xMultiServiceFactory
->createInstance(
247 OUString( "com.sun.star.ui.ActionTrigger" ) ),
254 // Retrieve the menu attributes and set them in our PropertySet
255 OUString aLabel
= pMenu
->GetItemText( nItemId
);
257 xPropSet
->setPropertyValue("Text", a
);
259 OUString aCommandURL
= pMenu
->GetItemCommand( nItemId
);
261 if ( aCommandURL
.isEmpty() )
263 aCommandURL
= "slot:" + OUString::number( nItemId
);
267 xPropSet
->setPropertyValue("CommandURL", a
);
269 Image aImage
= pMenu
->GetItemImage( nItemId
);
272 // We use our own optimized XBitmap implementation
273 Reference
< XBitmap
> xBitmap( static_cast< cppu::OWeakObject
* >( new ImageWrapper( aImage
)), UNO_QUERY
);
275 xPropSet
->setPropertyValue("Image", a
);
278 catch (const Exception
&)
286 Reference
< XPropertySet
> CreateActionTriggerSeparator( const Reference
< XIndexContainer
>& rActionTriggerContainer
) throw ( RuntimeException
)
288 Reference
< XMultiServiceFactory
> xMultiServiceFactory( rActionTriggerContainer
, UNO_QUERY
);
289 if ( xMultiServiceFactory
.is() )
291 return Reference
< XPropertySet
>( xMultiServiceFactory
->createInstance(
292 OUString( "com.sun.star.ui.ActionTriggerSeparator" ) ),
296 return Reference
< XPropertySet
>();
299 Reference
< XIndexContainer
> CreateActionTriggerContainer( const Reference
< XIndexContainer
>& rActionTriggerContainer
) throw ( RuntimeException
)
301 Reference
< XMultiServiceFactory
> xMultiServiceFactory( rActionTriggerContainer
, UNO_QUERY
);
302 if ( xMultiServiceFactory
.is() )
304 return Reference
< XIndexContainer
>( xMultiServiceFactory
->createInstance(
305 OUString( "com.sun.star.ui.ActionTriggerContainer" ) ),
309 return Reference
< XIndexContainer
>();
312 void FillActionTriggerContainerWithMenu( const Menu
* pMenu
, Reference
< XIndexContainer
>& rActionTriggerContainer
)
314 SolarMutexGuard aGuard
;
316 for ( sal_uInt16 nPos
= 0; nPos
< pMenu
->GetItemCount(); nPos
++ )
318 sal_uInt16 nItemId
= pMenu
->GetItemId( nPos
);
319 MenuItemType nType
= pMenu
->GetItemType( nPos
);
324 Reference
< XPropertySet
> xPropSet
;
326 if ( nType
== MenuItemType::SEPARATOR
)
328 xPropSet
= CreateActionTriggerSeparator( rActionTriggerContainer
);
331 rActionTriggerContainer
->insertByIndex( nPos
, a
);
335 xPropSet
= CreateActionTrigger( nItemId
, pMenu
, rActionTriggerContainer
);
338 rActionTriggerContainer
->insertByIndex( nPos
, a
);
340 PopupMenu
* pPopupMenu
= pMenu
->GetPopupMenu( nItemId
);
343 // recursive call to build next sub menu
344 Reference
< XIndexContainer
> xSubContainer
= CreateActionTriggerContainer( rActionTriggerContainer
);
347 xPropSet
->setPropertyValue("SubContainer", a
);
348 FillActionTriggerContainerWithMenu( pPopupMenu
, xSubContainer
);
352 catch (const Exception
&)
358 void ActionTriggerHelper::CreateMenuFromActionTriggerContainer(
360 const Reference
< XIndexContainer
>& rActionTriggerContainer
)
362 sal_uInt16 nItemId
= START_ITEMID
;
364 if ( rActionTriggerContainer
.is() )
365 InsertSubMenuItems( pNewMenu
, nItemId
, rActionTriggerContainer
);
368 void ActionTriggerHelper::FillActionTriggerContainerFromMenu(
369 Reference
< XIndexContainer
>& xActionTriggerContainer
,
372 FillActionTriggerContainerWithMenu( pMenu
, xActionTriggerContainer
);
375 Reference
< XIndexContainer
> ActionTriggerHelper::CreateActionTriggerContainerFromMenu(
377 const OUString
* pMenuIdentifier
)
379 return new RootActionTriggerContainer( pMenu
, pMenuIdentifier
);
384 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */