summaryrefslogtreecommitdiffstats
path: root/framework/source/fwe/helper/actiontriggerhelper.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /framework/source/fwe/helper/actiontriggerhelper.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--framework/source/fwe/helper/actiontriggerhelper.cxx385
1 files changed, 385 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..deb14f0e1
--- /dev/null
+++ b/framework/source/fwe/helper/actiontriggerhelper.cxx
@@ -0,0 +1,385 @@
+/* -*- 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 <classes/imagewrapper.hxx>
+#include <framework/addonsoptions.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <vcl/svapp.hxx>
+#include <tools/stream.hxx>
+#include <cppuhelper/weak.hxx>
+#include <vcl/dibtools.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( Menu* pSubMenu, 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;
+ pSubMenu->InsertSeparator();
+ }
+ 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>(aCommandURL.copy( nIndex+aSlotURL.getLength() ).toInt32());
+ pSubMenu->InsertItem( nNewItemId, aLabel );
+ }
+ else
+ {
+ pSubMenu->InsertItem( nNewItemId, aLabel );
+ pSubMenu->SetItemCommand( nNewItemId, aCommandURL );
+ }
+
+ // handle bitmap
+ if ( xBitmap.is() )
+ {
+ bool bImageSet = false;
+
+ Reference< XUnoTunnel > xUnoTunnel( xBitmap, UNO_QUERY );
+ if ( xUnoTunnel.is() )
+ {
+ // Try to get implementation pointer through XUnoTunnel
+ sal_Int64 nPointer = xUnoTunnel->getSomething( ImageWrapper::GetUnoTunnelId() );
+ if ( nPointer )
+ {
+ // This is our own optimized implementation of menu images!
+ ImageWrapper* pImageWrapper = reinterpret_cast< ImageWrapper * >( nPointer );
+ const Image& aMenuImage = pImageWrapper->GetImage();
+
+ if ( !!aMenuImage )
+ pSubMenu->SetItemImage( nNewItemId, aMenuImage );
+
+ 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!
+ Image aImage;
+ 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);
+ aImage = Image(BitmapEx(aBitmap.GetBitmap(), aMaskBitmap));
+ }
+ else
+ aImage = Image( aBitmap );
+
+ if ( !!aImage )
+ pSubMenu->SetItemImage( nNewItemId, aImage );
+ }
+ }
+ else
+ {
+ // Support add-on images for context menu interceptors
+ Image aImage = aAddonOptions.GetImageFromURL( aCommandURL, false, true );
+ if ( !!aImage )
+ pSubMenu->SetItemImage( nNewItemId, aImage );
+ }
+
+ if ( xSubContainer.is() )
+ {
+ VclPtr<PopupMenu> pNewSubMenu = VclPtr<PopupMenu>::Create();
+
+ // Sub menu (recursive call CreateSubMenu )
+ InsertSubMenuItems( pNewSubMenu, nItemId, xSubContainer );
+ pSubMenu->SetPopupMenu( nNewItemId, pNewSubMenu );
+ }
+ }
+ }
+ }
+ }
+ 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 Menu* pMenu, 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 = pMenu->GetItemText( nItemId );
+ a <<= aLabel;
+ xPropSet->setPropertyValue("Text", a );
+
+ OUString aCommandURL = pMenu->GetItemCommand( nItemId );
+
+ if ( aCommandURL.isEmpty() )
+ {
+ aCommandURL = "slot:" + OUString::number( nItemId );
+ }
+
+ a <<= aCommandURL;
+ xPropSet->setPropertyValue("CommandURL", a );
+
+ Image aImage = pMenu->GetItemImage( nItemId );
+ if ( !!aImage )
+ {
+ // We use our own optimized XBitmap implementation
+ Reference< XBitmap > xBitmap( static_cast< cppu::OWeakObject* >( new ImageWrapper( aImage )), UNO_QUERY );
+ 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 Menu* pMenu, Reference< XIndexContainer > const & rActionTriggerContainer )
+{
+ SolarMutexGuard aGuard;
+
+ for ( sal_uInt16 nPos = 0; nPos < pMenu->GetItemCount(); nPos++ )
+ {
+ sal_uInt16 nItemId = pMenu->GetItemId( nPos );
+ MenuItemType nType = pMenu->GetItemType( nPos );
+
+ try
+ {
+ Any a;
+ Reference< XPropertySet > xPropSet;
+
+ if ( nType == MenuItemType::SEPARATOR )
+ {
+ xPropSet = CreateActionTriggerSeparator( rActionTriggerContainer );
+
+ a <<= xPropSet;
+ rActionTriggerContainer->insertByIndex( nPos, a );
+ }
+ else
+ {
+ xPropSet = CreateActionTrigger( nItemId, pMenu, rActionTriggerContainer );
+
+ a <<= xPropSet;
+ rActionTriggerContainer->insertByIndex( nPos, a );
+
+ PopupMenu* pPopupMenu = pMenu->GetPopupMenu( nItemId );
+ if ( pPopupMenu )
+ {
+ // recursive call to build next sub menu
+ Reference< XIndexContainer > xSubContainer = CreateActionTriggerContainer( rActionTriggerContainer );
+
+ a <<= xSubContainer;
+ xPropSet->setPropertyValue("SubContainer", a );
+ FillActionTriggerContainerWithMenu( pPopupMenu, xSubContainer );
+ }
+ }
+ }
+ catch (const Exception&)
+ {
+ }
+ }
+}
+
+void ActionTriggerHelper::CreateMenuFromActionTriggerContainer(
+ Menu* pNewMenu,
+ const Reference< XIndexContainer >& rActionTriggerContainer )
+{
+ sal_uInt16 nItemId = START_ITEMID;
+
+ if ( rActionTriggerContainer.is() )
+ InsertSubMenuItems( pNewMenu, nItemId, rActionTriggerContainer );
+}
+
+void ActionTriggerHelper::FillActionTriggerContainerFromMenu(
+ Reference< XIndexContainer > const & xActionTriggerContainer,
+ const Menu* pMenu )
+{
+ FillActionTriggerContainerWithMenu( pMenu, xActionTriggerContainer );
+}
+
+Reference< XIndexContainer > ActionTriggerHelper::CreateActionTriggerContainerFromMenu(
+ const Menu* pMenu,
+ const OUString* pMenuIdentifier )
+{
+ return new RootActionTriggerContainer( pMenu, pMenuIdentifier );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */