summaryrefslogtreecommitdiffstats
path: root/framework/source/fwe/helper/actiontriggerhelper.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'framework/source/fwe/helper/actiontriggerhelper.cxx')
-rw-r--r--framework/source/fwe/helper/actiontriggerhelper.cxx376
1 files changed, 376 insertions, 0 deletions
diff --git a/framework/source/fwe/helper/actiontriggerhelper.cxx b/framework/source/fwe/helper/actiontriggerhelper.cxx
new file mode 100644
index 000000000..88edd70be
--- /dev/null
+++ b/framework/source/fwe/helper/actiontriggerhelper.cxx
@@ -0,0 +1,376 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <framework/actiontriggerhelper.hxx>
+#include <classes/actiontriggerseparatorpropertyset.hxx>
+#include <classes/rootactiontriggercontainer.hxx>
+#include <framework/addonsoptions.hxx>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/awt/XPopupMenu.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <toolkit/awt/vclxmenu.hxx>
+#include <tools/stream.hxx>
+#include <vcl/dibtools.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/svapp.hxx>
+#include <o3tl/string_view.hxx>
+
+const sal_uInt16 START_ITEMID = 1000;
+
+using namespace com::sun::star::awt;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::container;
+
+namespace framework
+{
+
+// implementation helper ( menu => ActionTrigger )
+
+static bool IsSeparator( const Reference< XPropertySet >& xPropertySet )
+{
+ Reference< XServiceInfo > xServiceInfo( xPropertySet, UNO_QUERY );
+ try
+ {
+ return xServiceInfo->supportsService( SERVICENAME_ACTIONTRIGGERSEPARATOR );
+ }
+ catch (const Exception&)
+ {
+ }
+
+ return false;
+}
+
+static void GetMenuItemAttributes( const Reference< XPropertySet >& xActionTriggerPropertySet,
+ OUString& aMenuLabel,
+ OUString& aCommandURL,
+ OUString& aHelpURL,
+ Reference< XBitmap >& xBitmap,
+ Reference< XIndexContainer >& xSubContainer )
+{
+ Any a;
+
+ try
+ {
+ // mandatory properties
+ a = xActionTriggerPropertySet->getPropertyValue("Text");
+ a >>= aMenuLabel;
+ a = xActionTriggerPropertySet->getPropertyValue("CommandURL");
+ a >>= aCommandURL;
+ a = xActionTriggerPropertySet->getPropertyValue("Image");
+ a >>= xBitmap;
+ a = xActionTriggerPropertySet->getPropertyValue("SubContainer");
+ a >>= xSubContainer;
+ }
+ catch (const Exception&)
+ {
+ }
+
+ // optional properties
+ try
+ {
+ a = xActionTriggerPropertySet->getPropertyValue("HelpURL");
+ a >>= aHelpURL;
+ }
+ catch (const Exception&)
+ {
+ }
+}
+
+static void InsertSubMenuItems(const Reference<XPopupMenu>& rSubMenu, sal_uInt16& nItemId,
+ const Reference<XIndexContainer>& xActionTriggerContainer)
+{
+ if ( !xActionTriggerContainer.is() )
+ return;
+
+ AddonsOptions aAddonOptions;
+ OUString aSlotURL( "slot:" );
+
+ for ( sal_Int32 i = 0; i < xActionTriggerContainer->getCount(); i++ )
+ {
+ try
+ {
+ Reference< XPropertySet > xPropSet;
+ if (( xActionTriggerContainer->getByIndex( i ) >>= xPropSet ) && ( xPropSet.is() ))
+ {
+ if ( IsSeparator( xPropSet ))
+ {
+ // Separator
+ SolarMutexGuard aGuard;
+ rSubMenu->insertSeparator(i);
+ }
+ else
+ {
+ // Menu item
+ OUString aLabel;
+ OUString aCommandURL;
+ OUString aHelpURL;
+ Reference< XBitmap > xBitmap;
+ Reference< XIndexContainer > xSubContainer;
+
+ sal_uInt16 nNewItemId = nItemId++;
+ GetMenuItemAttributes( xPropSet, aLabel, aCommandURL, aHelpURL, xBitmap, xSubContainer );
+
+ SolarMutexGuard aGuard;
+ {
+ // insert new menu item
+ sal_Int32 nIndex = aCommandURL.indexOf( aSlotURL );
+ if ( nIndex >= 0 )
+ {
+ // Special code for our menu implementation: some menu items don't have a
+ // command url but uses the item id as a unique identifier. These entries
+ // got a special url during conversion from menu=>actiontriggercontainer.
+ // Now we have to extract this special url and set the correct item id!!!
+ nNewItemId = static_cast<sal_uInt16>(o3tl::toInt32(aCommandURL.subView( nIndex+aSlotURL.getLength() )));
+ rSubMenu->insertItem(nNewItemId, aLabel, 0, i);
+ }
+ else
+ {
+ rSubMenu->insertItem(nNewItemId, aLabel, 0, i);
+ rSubMenu->setCommand(nNewItemId, aCommandURL);
+ }
+
+ // handle bitmap
+ if ( xBitmap.is() )
+ {
+ bool bImageSet = false;
+
+ Reference<css::graphic::XGraphic> xGraphic(xBitmap, UNO_QUERY);
+ if (xGraphic.is())
+ {
+ // we can take the optimized route if XGraphic is supported
+ rSubMenu->setItemImage(nNewItemId, xGraphic, false);
+ bImageSet = true;
+ }
+
+ if ( !bImageSet )
+ {
+ // This is an unknown implementation of a XBitmap interface. We have to
+ // use a more time consuming way to build an Image!
+ BitmapEx aBitmap;
+
+ Sequence< sal_Int8 > aDIBSeq;
+ {
+ aDIBSeq = xBitmap->getDIB();
+ SvMemoryStream aMem( const_cast<sal_Int8 *>(aDIBSeq.getConstArray()), aDIBSeq.getLength(), StreamMode::READ );
+ ReadDIBBitmapEx(aBitmap, aMem);
+ }
+
+ aDIBSeq = xBitmap->getMaskDIB();
+ if ( aDIBSeq.hasElements() )
+ {
+ Bitmap aMaskBitmap;
+ SvMemoryStream aMem( const_cast<sal_Int8 *>(aDIBSeq.getConstArray()), aDIBSeq.getLength(), StreamMode::READ );
+ ReadDIB(aMaskBitmap, aMem, true);
+ aBitmap = BitmapEx(aBitmap.GetBitmap(), aMaskBitmap);
+ }
+
+ if (!aBitmap.IsEmpty())
+ rSubMenu->setItemImage(nNewItemId, Graphic(aBitmap).GetXGraphic(), false);
+ }
+ }
+ else
+ {
+ // Support add-on images for context menu interceptors
+ BitmapEx aBitmap(aAddonOptions.GetImageFromURL(aCommandURL, false, true));
+ if (!aBitmap.IsEmpty())
+ rSubMenu->setItemImage(nNewItemId, Graphic(aBitmap).GetXGraphic(), false);
+ }
+
+ if ( xSubContainer.is() )
+ {
+ rtl::Reference xNewSubMenu(new VCLXPopupMenu);
+
+ // Sub menu (recursive call CreateSubMenu )
+ InsertSubMenuItems(xNewSubMenu, nItemId, xSubContainer);
+ rSubMenu->setPopupMenu(nNewItemId, xNewSubMenu);
+ }
+ }
+ }
+ }
+ }
+ catch (const IndexOutOfBoundsException&)
+ {
+ return;
+ }
+ catch (const WrappedTargetException&)
+ {
+ return;
+ }
+ catch (const RuntimeException&)
+ {
+ return;
+ }
+ }
+}
+
+// implementation helper ( ActionTrigger => menu )
+
+/// @throws RuntimeException
+static Reference< XPropertySet > CreateActionTrigger(sal_uInt16 nItemId,
+ const Reference<XPopupMenu>& rMenu,
+ const Reference<XIndexContainer>& rActionTriggerContainer)
+{
+ Reference< XPropertySet > xPropSet;
+
+ Reference< XMultiServiceFactory > xMultiServiceFactory( rActionTriggerContainer, UNO_QUERY );
+ if ( xMultiServiceFactory.is() )
+ {
+ xPropSet.set( xMultiServiceFactory->createInstance( "com.sun.star.ui.ActionTrigger" ),
+ UNO_QUERY );
+
+ Any a;
+
+ try
+ {
+ // Retrieve the menu attributes and set them in our PropertySet
+ OUString aLabel = rMenu->getItemText(nItemId);
+ a <<= aLabel;
+ xPropSet->setPropertyValue("Text", a );
+
+ OUString aCommandURL = rMenu->getCommand(nItemId);
+
+ if ( aCommandURL.isEmpty() )
+ {
+ aCommandURL = "slot:" + OUString::number( nItemId );
+ }
+
+ a <<= aCommandURL;
+ xPropSet->setPropertyValue("CommandURL", a );
+
+ Reference<XBitmap> xBitmap(rMenu->getItemImage(nItemId), UNO_QUERY);
+ if (xBitmap.is())
+ {
+ a <<= xBitmap;
+ xPropSet->setPropertyValue("Image", a );
+ }
+ }
+ catch (const Exception&)
+ {
+ }
+ }
+
+ return xPropSet;
+}
+
+/// @throws RuntimeException
+static Reference< XPropertySet > CreateActionTriggerSeparator( const Reference< XIndexContainer >& rActionTriggerContainer )
+{
+ Reference< XMultiServiceFactory > xMultiServiceFactory( rActionTriggerContainer, UNO_QUERY );
+ if ( xMultiServiceFactory.is() )
+ {
+ return Reference< XPropertySet >( xMultiServiceFactory->createInstance(
+ "com.sun.star.ui.ActionTriggerSeparator" ),
+ UNO_QUERY );
+ }
+
+ return Reference< XPropertySet >();
+}
+
+/// @throws RuntimeException
+static Reference< XIndexContainer > CreateActionTriggerContainer( const Reference< XIndexContainer >& rActionTriggerContainer )
+{
+ Reference< XMultiServiceFactory > xMultiServiceFactory( rActionTriggerContainer, UNO_QUERY );
+ if ( xMultiServiceFactory.is() )
+ {
+ return Reference< XIndexContainer >( xMultiServiceFactory->createInstance(
+ "com.sun.star.ui.ActionTriggerContainer" ),
+ UNO_QUERY );
+ }
+
+ return Reference< XIndexContainer >();
+}
+
+static void FillActionTriggerContainerWithMenu(const Reference<XPopupMenu>& rMenu,
+ const Reference<XIndexContainer>& rActionTriggerContainer)
+{
+ SolarMutexGuard aGuard;
+
+ for (sal_uInt16 nPos = 0, nCount = rMenu->getItemCount(); nPos < nCount; ++nPos)
+ {
+ sal_uInt16 nItemId = rMenu->getItemId(nPos);
+ css::awt::MenuItemType nType = rMenu->getItemType(nPos);
+
+ try
+ {
+ Any a;
+ Reference< XPropertySet > xPropSet;
+
+ if (nType == css::awt::MenuItemType_SEPARATOR)
+ {
+ xPropSet = CreateActionTriggerSeparator( rActionTriggerContainer );
+
+ a <<= xPropSet;
+ rActionTriggerContainer->insertByIndex( nPos, a );
+ }
+ else
+ {
+ xPropSet = CreateActionTrigger(nItemId, rMenu, rActionTriggerContainer);
+
+ a <<= xPropSet;
+ rActionTriggerContainer->insertByIndex( nPos, a );
+
+ css::uno::Reference<XPopupMenu> xPopupMenu = rMenu->getPopupMenu(nItemId);
+ if (xPopupMenu.is())
+ {
+ // recursive call to build next sub menu
+ Reference< XIndexContainer > xSubContainer = CreateActionTriggerContainer( rActionTriggerContainer );
+
+ a <<= xSubContainer;
+ xPropSet->setPropertyValue("SubContainer", a );
+ FillActionTriggerContainerWithMenu(xPopupMenu, xSubContainer);
+ }
+ }
+ }
+ catch (const Exception&)
+ {
+ }
+ }
+}
+
+void ActionTriggerHelper::CreateMenuFromActionTriggerContainer(
+ const Reference<XPopupMenu>& rNewMenu,
+ const Reference<XIndexContainer>& rActionTriggerContainer)
+{
+ sal_uInt16 nItemId = START_ITEMID;
+
+ if ( rActionTriggerContainer.is() )
+ InsertSubMenuItems(rNewMenu, nItemId, rActionTriggerContainer);
+}
+
+void ActionTriggerHelper::FillActionTriggerContainerFromMenu(
+ Reference< XIndexContainer > const & xActionTriggerContainer,
+ const css::uno::Reference<XPopupMenu>& rMenu)
+{
+ FillActionTriggerContainerWithMenu(rMenu, xActionTriggerContainer);
+}
+
+Reference< XIndexContainer > ActionTriggerHelper::CreateActionTriggerContainerFromMenu(
+ const css::uno::Reference<XPopupMenu>& rMenu,
+ const OUString* pMenuIdentifier )
+{
+ return new RootActionTriggerContainer(rMenu, pMenuIdentifier);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */