summaryrefslogtreecommitdiffstats
path: root/svtools/source/uno
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /svtools/source/uno
parentInitial commit. (diff)
downloadlibreoffice-upstream/4%7.4.7.tar.xz
libreoffice-upstream/4%7.4.7.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--svtools/source/uno/addrtempuno.cxx213
-rw-r--r--svtools/source/uno/fpicker.cxx171
-rw-r--r--svtools/source/uno/fpicker.hxx45
-rw-r--r--svtools/source/uno/framestatuslistener.cxx269
-rw-r--r--svtools/source/uno/genericunodialog.cxx263
-rw-r--r--svtools/source/uno/miscservices.cxx77
-rw-r--r--svtools/source/uno/popupmenucontrollerbase.cxx363
-rw-r--r--svtools/source/uno/popupwindowcontroller.cxx270
-rw-r--r--svtools/source/uno/statusbarcontroller.cxx594
-rw-r--r--svtools/source/uno/svtxgridcontrol.cxx909
-rw-r--r--svtools/source/uno/svtxgridcontrol.hxx110
-rw-r--r--svtools/source/uno/toolboxcontroller.cxx802
-rw-r--r--svtools/source/uno/unocontroltablemodel.cxx835
-rw-r--r--svtools/source/uno/unocontroltablemodel.hxx181
-rw-r--r--svtools/source/uno/unoevent.cxx450
-rw-r--r--svtools/source/uno/unogridcolumnfacade.cxx310
-rw-r--r--svtools/source/uno/unogridcolumnfacade.hxx89
-rw-r--r--svtools/source/uno/unoiface.cxx50
-rw-r--r--svtools/source/uno/unoimap.cxx720
-rw-r--r--svtools/source/uno/wizard/unowizard.cxx452
-rw-r--r--svtools/source/uno/wizard/wizardpagecontroller.cxx130
-rw-r--r--svtools/source/uno/wizard/wizardpagecontroller.hxx62
-rw-r--r--svtools/source/uno/wizard/wizardshell.cxx257
-rw-r--r--svtools/source/uno/wizard/wizardshell.hxx129
24 files changed, 7751 insertions, 0 deletions
diff --git a/svtools/source/uno/addrtempuno.cxx b/svtools/source/uno/addrtempuno.cxx
new file mode 100644
index 000000000..54cb28afc
--- /dev/null
+++ b/svtools/source/uno/addrtempuno.cxx
@@ -0,0 +1,213 @@
+/* -*- 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 <svtools/addresstemplate.hxx>
+#include <svtools/genericunodialog.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/util/AliasProgrammaticPair.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <vcl/svapp.hxx>
+
+using namespace svt;
+
+namespace {
+
+#define UNODIALOG_PROPERTY_ID_ALIASES 100
+constexpr OUStringLiteral UNODIALOG_PROPERTY_ALIASES = u"FieldMapping";
+
+ using namespace css::uno;
+ using namespace css::lang;
+ using namespace css::util;
+ using namespace css::beans;
+ using namespace css::sdbc;
+
+ class OAddressBookSourceDialogUno
+ :public OGenericUnoDialog
+ ,public ::comphelper::OPropertyArrayUsageHelper< OAddressBookSourceDialogUno >
+ {
+ private:
+ Sequence< AliasProgrammaticPair > m_aAliases;
+ Reference< XDataSource > m_xDataSource;
+ OUString m_sDataSourceName;
+ OUString m_sTable;
+
+ public:
+ explicit OAddressBookSourceDialogUno(const Reference< XComponentContext >& _rxORB);
+
+ // XTypeProvider
+ virtual Sequence<sal_Int8> SAL_CALL getImplementationId( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XPropertySet
+ virtual Reference< XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ virtual void SAL_CALL initialize(const Sequence< Any >& aArguments) override;
+
+ protected:
+ // OGenericUnoDialog overridables
+ virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+
+ virtual void implInitialize(const css::uno::Any& _rValue) override;
+
+ virtual void executedDialog(sal_Int16 _nExecutionResult) override;
+ };
+
+
+ OAddressBookSourceDialogUno::OAddressBookSourceDialogUno(const Reference< XComponentContext >& _rxORB)
+ :OGenericUnoDialog(_rxORB)
+ {
+ registerProperty(UNODIALOG_PROPERTY_ALIASES, UNODIALOG_PROPERTY_ID_ALIASES, PropertyAttribute::READONLY,
+ &m_aAliases, cppu::UnoType<decltype(m_aAliases)>::get());
+ }
+
+
+ Sequence<sal_Int8> SAL_CALL OAddressBookSourceDialogUno::getImplementationId( )
+ {
+ return css::uno::Sequence<sal_Int8>();
+ }
+
+
+ OUString SAL_CALL OAddressBookSourceDialogUno::getImplementationName()
+ {
+ return "com.sun.star.comp.svtools.OAddressBookSourceDialogUno";
+ }
+
+
+ css::uno::Sequence<OUString> SAL_CALL OAddressBookSourceDialogUno::getSupportedServiceNames()
+ {
+ return { "com.sun.star.ui.AddressBookSourceDialog" };
+ }
+
+
+ Reference<XPropertySetInfo> SAL_CALL OAddressBookSourceDialogUno::getPropertySetInfo()
+ {
+ Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+ }
+
+ ::cppu::IPropertyArrayHelper& OAddressBookSourceDialogUno::getInfoHelper()
+ {
+ return *getArrayHelper();
+ }
+
+ ::cppu::IPropertyArrayHelper* OAddressBookSourceDialogUno::createArrayHelper( ) const
+ {
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+ }
+
+ void OAddressBookSourceDialogUno::executedDialog(sal_Int16 _nExecutionResult)
+ {
+ OGenericUnoDialog::executedDialog(_nExecutionResult);
+
+ if ( _nExecutionResult && m_xDialog )
+ static_cast<AddressBookSourceDialog*>(m_xDialog.get())->getFieldMapping(m_aAliases);
+ }
+
+ void SAL_CALL OAddressBookSourceDialogUno::initialize(const Sequence< Any >& rArguments)
+ {
+ if( rArguments.getLength() == 5 )
+ {
+ Reference<css::awt::XWindow> xParentWindow;
+ Reference<css::beans::XPropertySet> xDataSource;
+ OUString sDataSourceName;
+ OUString sCommand;
+ OUString sTitle;
+ if ( (rArguments[0] >>= xParentWindow)
+ && (rArguments[1] >>= xDataSource)
+ && (rArguments[2] >>= sDataSourceName)
+ && (rArguments[3] >>= sCommand)
+ && (rArguments[4] >>= sTitle) )
+ {
+
+ // convert the parameters for creating the dialog to PropertyValues
+ Sequence<Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {"ParentWindow", Any(xParentWindow)},
+ {"DataSource", Any(xDataSource)},
+ {"DataSourceName", Any(sDataSourceName)},
+ {"Command", Any(sCommand)}, // the table to use
+ {"Title", Any(sTitle)}
+ }));
+ OGenericUnoDialog::initialize(aArguments);
+ return;
+ }
+ }
+ OGenericUnoDialog::initialize(rArguments);
+ }
+
+ void OAddressBookSourceDialogUno::implInitialize(const css::uno::Any& _rValue)
+ {
+ PropertyValue aVal;
+ if (_rValue >>= aVal)
+ {
+ if (aVal.Name == "DataSource")
+ {
+ bool bSuccess = aVal.Value >>= m_xDataSource;
+ OSL_ENSURE( bSuccess, "OAddressBookSourceDialogUno::implInitialize: invalid type for DataSource!" );
+ return;
+ }
+
+ if (aVal.Name == "DataSourceName")
+ {
+ bool bSuccess = aVal.Value >>= m_sDataSourceName;
+ OSL_ENSURE( bSuccess, "OAddressBookSourceDialogUno::implInitialize: invalid type for DataSourceName!" );
+ return;
+ }
+
+ if (aVal.Name == "Command")
+ {
+ bool bSuccess = aVal.Value >>= m_sTable;
+ OSL_ENSURE( bSuccess, "OAddressBookSourceDialogUno::implInitialize: invalid type for Command!" );
+ return;
+ }
+ }
+
+ OGenericUnoDialog::implInitialize( _rValue );
+ }
+
+ std::unique_ptr<weld::DialogController> OAddressBookSourceDialogUno::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+ {
+ weld::Window* pParent = Application::GetFrameWeld(rParent);
+ if ( m_xDataSource.is() && !m_sTable.isEmpty() )
+ return std::make_unique<AddressBookSourceDialog>(pParent, m_aContext, m_xDataSource, m_sDataSourceName, m_sTable, m_aAliases);
+ return std::make_unique<AddressBookSourceDialog>(pParent, m_aContext);
+ }
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svtools_OAddressBookSourceDialogUno_get_implementation(
+ css::uno::XComponentContext * context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new OAddressBookSourceDialogUno(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/fpicker.cxx b/svtools/source/uno/fpicker.cxx
new file mode 100644
index 000000000..dbb69d601
--- /dev/null
+++ b/svtools/source/uno/fpicker.cxx
@@ -0,0 +1,171 @@
+/* -*- 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 <rtl/ustring.hxx>
+
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+
+#include <svl/pickerhistoryaccess.hxx>
+#include <officecfg/Office/Common.hxx>
+
+#include <vcl/svapp.hxx>
+
+#include "fpicker.hxx"
+
+using css::uno::Reference;
+using css::uno::Sequence;
+
+/*
+ * FilePicker implementation.
+ */
+static OUString FilePicker_getSystemPickerServiceName()
+{
+#ifdef UNX
+ OUString aDesktopEnvironment (Application::GetDesktopEnvironment());
+ if (aDesktopEnvironment.equalsIgnoreAsciiCase("macosx"))
+ return "com.sun.star.ui.dialogs.AquaFilePicker";
+ else
+ return "com.sun.star.ui.dialogs.SystemFilePicker";
+#endif
+#ifdef _WIN32
+ return "com.sun.star.ui.dialogs.Win32FilePicker";
+#endif
+}
+
+Reference< css::uno::XInterface > FilePicker_CreateInstance (
+ Reference< css::uno::XComponentContext > const & context)
+{
+ Reference< css::uno::XInterface > xResult;
+
+ if (!context.is())
+ return xResult;
+
+ Reference< css::lang::XMultiComponentFactory > xFactory (context->getServiceManager());
+ if (xFactory.is() && officecfg::Office::Common::Misc::UseSystemFileDialog::get())
+ {
+ xResult.set( Application::createFilePicker( context ) );
+
+ if (!xResult.is())
+ {
+ try
+ {
+ xResult = xFactory->createInstanceWithContext (
+ FilePicker_getSystemPickerServiceName(),
+ context);
+ }
+ catch (css::uno::Exception const &)
+ {
+ // Handled below (see @ fallback).
+ }
+ }
+ }
+
+
+ if (!xResult.is() && xFactory.is())
+ {
+ // Always fall back to OfficeFilePicker.
+ xResult = xFactory->createInstanceWithContext (
+ "com.sun.star.ui.dialogs.OfficeFilePicker",
+ context);
+ }
+ if (xResult.is())
+ {
+ // Add to FilePicker history.
+ svt::addFilePicker (xResult);
+ }
+ return xResult;
+}
+
+OUString FilePicker_getImplementationName()
+{
+ return "com.sun.star.comp.svt.FilePicker";
+}
+
+Sequence< OUString > FilePicker_getSupportedServiceNames()
+{
+ Sequence< OUString > aServiceNames { "com.sun.star.ui.dialogs.FilePicker" };
+ return aServiceNames;
+}
+
+/*
+ * FolderPicker implementation.
+ */
+static OUString FolderPicker_getSystemPickerServiceName()
+{
+#ifdef UNX
+ OUString aDesktopEnvironment (Application::GetDesktopEnvironment());
+ if (aDesktopEnvironment.equalsIgnoreAsciiCase("macosx"))
+ return "com.sun.star.ui.dialogs.AquaFolderPicker";
+#endif
+ return "com.sun.star.ui.dialogs.SystemFolderPicker";
+}
+
+Reference< css::uno::XInterface > FolderPicker_CreateInstance (
+ Reference< css::uno::XComponentContext > const & context)
+{
+ Reference< css::uno::XInterface > xResult;
+
+ if (!context.is())
+ return xResult;
+
+ Reference< css::lang::XMultiComponentFactory > xFactory (context->getServiceManager());
+ if (xFactory.is() && officecfg::Office::Common::Misc::UseSystemFileDialog::get())
+ {
+ xResult.set( Application::createFolderPicker( context ) );
+ if (!xResult.is())
+ {
+ try
+ {
+ xResult = xFactory->createInstanceWithContext (
+ FolderPicker_getSystemPickerServiceName(),
+ context);
+ }
+ catch (css::uno::Exception const &)
+ {
+ // Handled below (see @ fallback).
+ }
+ }
+ }
+ if (!xResult.is() && xFactory.is() )
+ {
+ // Always fall back to OfficeFolderPicker.
+ xResult = xFactory->createInstanceWithContext (
+ "com.sun.star.ui.dialogs.OfficeFolderPicker",
+ context);
+ }
+ if (xResult.is())
+ {
+ // Add to FolderPicker history.
+ svt::addFolderPicker (xResult);
+ }
+ return xResult;
+}
+
+OUString FolderPicker_getImplementationName()
+{
+ return "com.sun.star.comp.svt.FolderPicker";
+}
+
+Sequence< OUString > FolderPicker_getSupportedServiceNames()
+{
+ Sequence< OUString > aServiceNames { "com.sun.star.ui.dialogs.FolderPicker" };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/fpicker.hxx b/svtools/source/uno/fpicker.hxx
new file mode 100644
index 000000000..9fcbacd54
--- /dev/null
+++ b/svtools/source/uno/fpicker.hxx
@@ -0,0 +1,45 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+#include <rtl/ustring.hxx>
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace com::sun::star {
+ namespace lang { class XMultiServiceFactory; }
+ namespace uno { class XInterface; }
+}
+
+css::uno::Reference<css::uno::XInterface> FilePicker_CreateInstance(
+ css::uno::Reference< css::uno::XComponentContext > const & context);
+css::uno::Sequence<OUString> FilePicker_getSupportedServiceNames();
+OUString FilePicker_getImplementationName();
+
+css::uno::Reference<css::uno::XInterface> FolderPicker_CreateInstance(
+ css::uno::Reference< css::uno::XComponentContext > const & context);
+css::uno::Sequence<OUString> FolderPicker_getSupportedServiceNames();
+OUString FolderPicker_getImplementationName();
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/framestatuslistener.cxx b/svtools/source/uno/framestatuslistener.cxx
new file mode 100644
index 000000000..0ad4271a1
--- /dev/null
+++ b/svtools/source/uno/framestatuslistener.cxx
@@ -0,0 +1,269 @@
+/* -*- 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 <framestatuslistener.hxx>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <cppuhelper/queryinterface.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::cppu;
+using namespace css::awt;
+using namespace css::uno;
+using namespace css::util;
+using namespace css::beans;
+using namespace css::lang;
+using namespace css::frame;
+
+namespace svt
+{
+
+FrameStatusListener::FrameStatusListener(
+ const Reference< XComponentContext >& rxContext,
+ const Reference< XFrame >& xFrame ) :
+ OWeakObject()
+ , m_bDisposed( false )
+ , m_xFrame( xFrame )
+ , m_xContext( rxContext )
+{
+}
+
+FrameStatusListener::~FrameStatusListener()
+{
+}
+
+// XInterface
+Any SAL_CALL FrameStatusListener::queryInterface( const Type& rType )
+{
+ Any a = ::cppu::queryInterface(
+ rType ,
+ static_cast< XComponent* >( this ),
+ static_cast< XFrameActionListener* >( this ),
+ static_cast< XStatusListener* >( this ),
+ static_cast< XEventListener* >( static_cast< XStatusListener* >( this )),
+ static_cast< XEventListener* >( static_cast< XFrameActionListener* >( this )));
+
+ if ( a.hasValue() )
+ return a;
+
+ return OWeakObject::queryInterface( rType );
+}
+
+void SAL_CALL FrameStatusListener::acquire() noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL FrameStatusListener::release() noexcept
+{
+ OWeakObject::release();
+}
+
+// XComponent
+void SAL_CALL FrameStatusListener::dispose()
+{
+ Reference< XComponent > xThis = this;
+
+ SolarMutexGuard aSolarMutexGuard;
+ if ( m_bDisposed )
+ throw DisposedException();
+
+ for (auto const& listener : m_aListenerMap)
+ {
+ try
+ {
+ Reference< XDispatch > xDispatch( listener.second );
+ Reference< XURLTransformer > xURLTransformer( css::util::URLTransformer::create( m_xContext ) );
+ css::util::URL aTargetURL;
+ aTargetURL.Complete = listener.first;
+ xURLTransformer->parseStrict( aTargetURL );
+
+ if ( xDispatch.is() )
+ xDispatch->removeStatusListener( this, aTargetURL );
+ }
+ catch (const Exception&)
+ {
+ }
+ }
+
+ m_bDisposed = true;
+}
+
+void SAL_CALL FrameStatusListener::addEventListener( const Reference< XEventListener >& )
+{
+ // helper class for status updates - no need to support listener
+}
+
+void SAL_CALL FrameStatusListener::removeEventListener( const Reference< XEventListener >& )
+{
+ // helper class for status updates - no need to support listener
+}
+
+// XEventListener
+void SAL_CALL FrameStatusListener::disposing( const EventObject& Source )
+{
+ Reference< XInterface > xSource( Source.Source );
+
+ SolarMutexGuard aSolarMutexGuard;
+
+ for (auto & listener : m_aListenerMap)
+ {
+ // Compare references and release dispatch references if they are equal.
+ Reference< XInterface > xIfac( listener.second, UNO_QUERY );
+ if ( xSource == xIfac )
+ listener.second.clear();
+ }
+
+ Reference< XInterface > xIfac( m_xFrame, UNO_QUERY );
+ if ( xIfac == xSource )
+ m_xFrame.clear();
+}
+
+void FrameStatusListener::frameAction( const FrameActionEvent& Action )
+{
+ if ( Action.Action == FrameAction_CONTEXT_CHANGED )
+ bindListener();
+}
+
+void FrameStatusListener::addStatusListener( const OUString& aCommandURL )
+{
+ Reference< XDispatch > xDispatch;
+ Reference< XStatusListener > xStatusListener;
+ css::util::URL aTargetURL;
+
+ {
+ SolarMutexGuard aSolarMutexGuard;
+ URLToDispatchMap::iterator pIter = m_aListenerMap.find( aCommandURL );
+
+ // Already in the list of status listener. Do nothing.
+ if ( pIter != m_aListenerMap.end() )
+ return;
+
+ Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
+ if ( m_xContext.is() && xDispatchProvider.is() )
+ {
+ Reference< XURLTransformer > xURLTransformer( css::util::URLTransformer::create( m_xContext ) );
+ aTargetURL.Complete = aCommandURL;
+ xURLTransformer->parseStrict( aTargetURL );
+ xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
+
+ xStatusListener = this;
+ URLToDispatchMap::iterator aIter = m_aListenerMap.find( aCommandURL );
+ if ( aIter != m_aListenerMap.end() )
+ {
+ Reference< XDispatch > xOldDispatch( aIter->second );
+ aIter->second = xDispatch;
+
+ try
+ {
+ if ( xOldDispatch.is() )
+ xOldDispatch->removeStatusListener( xStatusListener, aTargetURL );
+ }
+ catch (const Exception&)
+ {
+ }
+ }
+ else
+ m_aListenerMap.emplace( aCommandURL, xDispatch );
+ }
+ }
+
+ // Call without locked mutex as we are called back from dispatch implementation
+ try
+ {
+ if ( xDispatch.is() )
+ xDispatch->addStatusListener( xStatusListener, aTargetURL );
+ }
+ catch (const Exception&)
+ {
+ }
+}
+
+
+void FrameStatusListener::bindListener()
+{
+ std::vector< Listener > aDispatchVector;
+ Reference< XStatusListener > xStatusListener;
+
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ // Collect all registered command URL's and store them temporary
+ Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
+ if ( m_xContext.is() && xDispatchProvider.is() )
+ {
+ xStatusListener = this;
+ for (auto & listener : m_aListenerMap)
+ {
+ Reference< XURLTransformer > xURLTransformer( css::util::URLTransformer::create( m_xContext ) );
+ css::util::URL aTargetURL;
+ aTargetURL.Complete = listener.first;
+ xURLTransformer->parseStrict( aTargetURL );
+
+ Reference< XDispatch > xDispatch( listener.second );
+ if ( xDispatch.is() )
+ {
+ // We already have a dispatch object => we have to requery.
+ // Release old dispatch object and remove it as listener
+ try
+ {
+ xDispatch->removeStatusListener( xStatusListener, aTargetURL );
+ }
+ catch (const Exception&)
+ {
+ }
+ }
+
+ // Query for dispatch object. Old dispatch will be released with this, too.
+ try
+ {
+ xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
+ }
+ catch (const Exception&)
+ {
+ }
+ listener.second = xDispatch;
+
+ Listener aListener( aTargetURL, xDispatch );
+ aDispatchVector.push_back( aListener );
+ }
+ }
+ }
+
+ // Call without locked mutex as we are called back from dispatch implementation
+ if ( !xStatusListener.is() )
+ return;
+
+ try
+ {
+ for (Listener & rListener : aDispatchVector)
+ {
+ if ( rListener.xDispatch.is() )
+ rListener.xDispatch->addStatusListener( xStatusListener, rListener.aURL );
+ }
+ }
+ catch (const Exception&)
+ {
+ }
+}
+
+} // svt
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/genericunodialog.cxx b/svtools/source/uno/genericunodialog.cxx
new file mode 100644
index 000000000..b6a493654
--- /dev/null
+++ b/svtools/source/uno/genericunodialog.cxx
@@ -0,0 +1,263 @@
+/* -*- 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 <svtools/genericunodialog.hxx>
+
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/ucb/AlreadyInitializedException.hpp>
+
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+#include <osl/mutex.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::beans;
+using namespace css::ucb;
+
+
+namespace svt
+{
+
+
+OGenericUnoDialog::OGenericUnoDialog(const Reference< XComponentContext >& _rxContext)
+ :OPropertyContainer(GetBroadcastHelper())
+ ,m_bExecuting(false)
+ ,m_bTitleAmbiguous(true)
+ ,m_bInitialized( false )
+ ,m_aContext(_rxContext)
+{
+ registerProperty(UNODIALOG_PROPERTY_TITLE, UNODIALOG_PROPERTY_ID_TITLE, PropertyAttribute::TRANSIENT,
+ &m_sTitle, cppu::UnoType<decltype(m_sTitle)>::get());
+ registerProperty(UNODIALOG_PROPERTY_PARENT, UNODIALOG_PROPERTY_ID_PARENT, PropertyAttribute::TRANSIENT,
+ &m_xParent, cppu::UnoType<decltype(m_xParent)>::get());
+}
+
+
+OGenericUnoDialog::~OGenericUnoDialog()
+{
+ if (m_xDialog)
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (m_xDialog)
+ destroyDialog();
+ }
+}
+
+
+Any SAL_CALL OGenericUnoDialog::queryInterface(const Type& _rType)
+{
+ Any aReturn = OGenericUnoDialogBase::queryInterface(_rType);
+
+ if (!aReturn.hasValue())
+ aReturn = ::cppu::queryInterface(_rType
+ ,static_cast<XPropertySet*>(this)
+ ,static_cast<XMultiPropertySet*>(this)
+ ,static_cast<XFastPropertySet*>(this)
+ );
+
+ return aReturn;
+}
+
+
+Sequence<Type> SAL_CALL OGenericUnoDialog::getTypes( )
+{
+ return ::comphelper::concatSequences(
+ OGenericUnoDialogBase::getTypes(),
+ getBaseTypes()
+ );
+}
+
+sal_Bool SAL_CALL OGenericUnoDialog::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+
+void OGenericUnoDialog::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
+{
+ // TODO: need some handling if we're currently executing ...
+
+ OPropertyContainer::setFastPropertyValue_NoBroadcast(nHandle, rValue);
+
+ if (UNODIALOG_PROPERTY_ID_TITLE == nHandle)
+ {
+ // from now on m_sTitle is valid
+ m_bTitleAmbiguous = false;
+
+ if (m_xDialog)
+ m_xDialog->set_title(m_sTitle);
+ }
+}
+
+
+sal_Bool OGenericUnoDialog::convertFastPropertyValue( Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue)
+{
+ switch (nHandle)
+ {
+ case UNODIALOG_PROPERTY_ID_PARENT:
+ {
+ Reference<css::awt::XWindow> xNew(rValue, css::uno::UNO_QUERY);
+ if (xNew != m_xParent)
+ {
+ rConvertedValue <<= xNew;
+ rOldValue <<= m_xParent;
+ return true;
+ }
+ return false;
+ }
+ }
+ return OPropertyContainer::convertFastPropertyValue(rConvertedValue, rOldValue, nHandle, rValue);
+}
+
+
+void SAL_CALL OGenericUnoDialog::setTitle( const OUString& _rTitle )
+{
+ UnoDialogEntryGuard aGuard( *this );
+
+ try
+ {
+ setPropertyValue(UNODIALOG_PROPERTY_TITLE, Any(_rTitle));
+ }
+ catch(RuntimeException&)
+ {
+ // allowed to pass
+ throw;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ // not allowed to pass
+ }
+}
+
+
+bool OGenericUnoDialog::impl_ensureDialog_lck()
+{
+ if (m_xDialog)
+ return true;
+
+ // get the parameters for the dialog from the current settings
+
+ // the title
+ OUString sTitle = m_sTitle;
+
+ auto xDialog(createDialog(m_xParent));
+ OSL_ENSURE(xDialog, "OGenericUnoDialog::impl_ensureDialog_lck: createDialog returned nonsense!");
+ if (!xDialog)
+ return false;
+
+ // do some initialisations
+ if (!m_bTitleAmbiguous)
+ xDialog->set_title(sTitle);
+
+ m_xDialog = std::move(xDialog);
+
+ return true;
+}
+
+sal_Int16 SAL_CALL OGenericUnoDialog::execute()
+{
+ // both creation and execution of the dialog must be guarded with the SolarMutex, so be generous here
+ SolarMutexGuard aSolarGuard;
+
+ // create the dialog, if necessary
+ {
+ UnoDialogEntryGuard aGuard( *this );
+
+ if (m_bExecuting)
+ throw RuntimeException(
+ "already executing the dialog (recursive call)",
+ *this
+ );
+
+ m_bExecuting = true;
+
+ if ( !impl_ensureDialog_lck() )
+ return 0;
+ }
+
+ // start execution
+ sal_Int16 nReturn(0);
+ if (m_xDialog)
+ nReturn = m_xDialog->run();
+
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ // get the settings of the dialog
+ executedDialog( nReturn );
+
+ m_bExecuting = false;
+ }
+
+ // outta here
+ return nReturn;
+}
+
+void OGenericUnoDialog::implInitialize(const Any& _rValue)
+{
+ try
+ {
+ PropertyValue aProperty;
+ NamedValue aValue;
+ if ( _rValue >>= aProperty )
+ {
+ setPropertyValue( aProperty.Name, aProperty.Value );
+ }
+ else if ( _rValue >>= aValue )
+ {
+ setPropertyValue( aValue.Name, aValue.Value );
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+}
+
+void SAL_CALL OGenericUnoDialog::initialize( const Sequence< Any >& aArguments )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bInitialized )
+ throw AlreadyInitializedException( OUString(), *this );
+
+ for (const Any& rArgument : aArguments)
+ implInitialize(rArgument);
+
+ m_bInitialized = true;
+}
+
+void OGenericUnoDialog::destroyDialog()
+{
+ SolarMutexGuard aSolarGuard;
+ m_xDialog.reset();
+}
+
+} // namespace svt
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/miscservices.cxx b/svtools/source/uno/miscservices.cxx
new file mode 100644
index 000000000..625b336c5
--- /dev/null
+++ b/svtools/source/uno/miscservices.cxx
@@ -0,0 +1,77 @@
+/* -*- 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 <sal/types.h>
+
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/implementationentry.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include "fpicker.hxx"
+
+using namespace ::com::sun::star;
+using namespace css::uno;
+using namespace css::lang;
+
+namespace
+{
+ const struct ::cppu::ImplementationEntry s_aServiceEntries[] =
+ {
+ {
+ // FilePicker should not use a constructor, it is only a
+ // trampoline to a real impl.
+ FilePicker_CreateInstance,
+ FilePicker_getImplementationName,
+ FilePicker_getSupportedServiceNames,
+ ::cppu::createSingleComponentFactory, nullptr, 0
+ },
+ {
+ // FolderPicker should not use a constructor, it is only a
+ // trampoline to a real impl.
+ FolderPicker_CreateInstance,
+ FolderPicker_getImplementationName,
+ FolderPicker_getSupportedServiceNames,
+ ::cppu::createSingleComponentFactory, nullptr, 0
+ },
+ { nullptr, nullptr, nullptr, nullptr, nullptr, 0 }
+ };
+}
+
+extern "C"
+{
+
+SAL_DLLPUBLIC_EXPORT void * svt_component_getFactory(
+ const char * pImplementationName, void * _pServiceManager, void * pRegistryKey)
+{
+ void * pResult = nullptr;
+ if (_pServiceManager)
+ {
+ Reference< XMultiServiceFactory > xHoldAlive(static_cast< XMultiServiceFactory * >(_pServiceManager));
+
+ pResult = cppu::component_getFactoryHelper(pImplementationName,
+ _pServiceManager,
+ pRegistryKey,
+ s_aServiceEntries);
+ }
+ return pResult;
+}
+
+} // extern "C"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/popupmenucontrollerbase.cxx b/svtools/source/uno/popupmenucontrollerbase.cxx
new file mode 100644
index 000000000..3e5d47c36
--- /dev/null
+++ b/svtools/source/uno/popupmenucontrollerbase.cxx
@@ -0,0 +1,363 @@
+/* -*- 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 <svtools/popupmenucontrollerbase.hxx>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+
+#include <vcl/svapp.hxx>
+#include <osl/mutex.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace com::sun::star;
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::frame;
+using namespace css::beans;
+using namespace css::util;
+
+namespace svt
+{
+
+namespace {
+
+struct PopupMenuControllerBaseDispatchInfo
+{
+ Reference< XDispatch > mxDispatch;
+ const URL maURL;
+ const Sequence< PropertyValue > maArgs;
+
+ PopupMenuControllerBaseDispatchInfo( const Reference< XDispatch >& xDispatch, const URL& rURL, const Sequence< PropertyValue >& rArgs )
+ : mxDispatch( xDispatch ), maURL( rURL ), maArgs( rArgs ) {}
+};
+
+}
+
+PopupMenuControllerBase::PopupMenuControllerBase( const Reference< XComponentContext >& xContext ) :
+ ::cppu::BaseMutex(),
+ PopupMenuControllerBaseType(m_aMutex),
+ m_bInitialized( false )
+{
+ if ( xContext.is() )
+ m_xURLTransformer.set( util::URLTransformer::create( xContext ) );
+}
+
+PopupMenuControllerBase::~PopupMenuControllerBase()
+{
+}
+
+// protected function
+void PopupMenuControllerBase::throwIfDisposed()
+{
+ if (rBHelper.bDisposed || rBHelper.bInDispose)
+ throw css::lang::DisposedException();
+}
+
+// protected function
+void PopupMenuControllerBase::resetPopupMenu( css::uno::Reference< css::awt::XPopupMenu > const & rPopupMenu )
+{
+ if ( rPopupMenu.is() && rPopupMenu->getItemCount() > 0 )
+ {
+ rPopupMenu->clear();
+ }
+}
+
+void SAL_CALL PopupMenuControllerBase::disposing()
+{
+ // Reset our members and set disposed flag
+ osl::MutexGuard aLock( m_aMutex );
+ m_xFrame.clear();
+ m_xDispatch.clear();
+ m_xPopupMenu.clear();
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL PopupMenuControllerBase::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XEventListener
+void SAL_CALL PopupMenuControllerBase::disposing( const EventObject& )
+{
+ osl::MutexGuard aLock( m_aMutex );
+ m_xFrame.clear();
+ m_xDispatch.clear();
+ m_xPopupMenu.clear();
+}
+
+// XMenuListener
+void SAL_CALL PopupMenuControllerBase::itemHighlighted( const awt::MenuEvent& )
+{
+}
+
+void SAL_CALL PopupMenuControllerBase::itemSelected( const awt::MenuEvent& rEvent )
+{
+ throwIfDisposed();
+
+ osl::MutexGuard aLock( m_aMutex );
+
+ if( m_xPopupMenu.is() )
+ {
+ Sequence<PropertyValue> aArgs;
+ dispatchCommand( m_xPopupMenu->getCommand( rEvent.MenuId ), aArgs );
+ }
+}
+
+void PopupMenuControllerBase::dispatchCommand( const OUString& sCommandURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& rArgs,
+ const OUString& sTarget )
+{
+ osl::MutexGuard aLock( m_aMutex );
+
+ throwIfDisposed();
+
+ try
+ {
+ Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY_THROW );
+ URL aURL;
+ aURL.Complete = sCommandURL;
+ m_xURLTransformer->parseStrict( aURL );
+
+ Reference< XDispatch > xDispatch( xDispatchProvider->queryDispatch( aURL, sTarget, 0 ), UNO_SET_THROW );
+
+ Application::PostUserEvent( LINK(nullptr, PopupMenuControllerBase, ExecuteHdl_Impl), new PopupMenuControllerBaseDispatchInfo( xDispatch, aURL, rArgs ) );
+
+ }
+ catch( Exception& )
+ {
+ }
+
+}
+
+IMPL_STATIC_LINK( PopupMenuControllerBase, ExecuteHdl_Impl, void*, p, void )
+{
+ PopupMenuControllerBaseDispatchInfo* pDispatchInfo = static_cast<PopupMenuControllerBaseDispatchInfo*>(p);
+ pDispatchInfo->mxDispatch->dispatch( pDispatchInfo->maURL, pDispatchInfo->maArgs );
+ delete pDispatchInfo;
+}
+
+void SAL_CALL PopupMenuControllerBase::itemActivated( const awt::MenuEvent& )
+{
+}
+
+void SAL_CALL PopupMenuControllerBase::itemDeactivated( const awt::MenuEvent& )
+{
+}
+
+void SAL_CALL PopupMenuControllerBase::updatePopupMenu()
+{
+ {
+ osl::MutexGuard aLock(m_aMutex);
+ throwIfDisposed();
+ }
+
+ updateCommand( m_aCommandURL );
+}
+
+void PopupMenuControllerBase::updateCommand( const OUString& rCommandURL )
+{
+ osl::ClearableMutexGuard aLock( m_aMutex );
+ Reference< XStatusListener > xStatusListener(this);
+ Reference< XDispatch > xDispatch( m_xDispatch );
+ URL aTargetURL;
+ aTargetURL.Complete = rCommandURL;
+ m_xURLTransformer->parseStrict( aTargetURL );
+ aLock.clear();
+
+ // Add/remove status listener to get a status update once
+ if ( xDispatch.is() )
+ {
+ xDispatch->addStatusListener( xStatusListener, aTargetURL );
+ xDispatch->removeStatusListener( xStatusListener, aTargetURL );
+ }
+}
+
+
+// XDispatchProvider
+Reference< XDispatch > SAL_CALL
+PopupMenuControllerBase::queryDispatch(
+ const URL& /*aURL*/,
+ const OUString& /*sTarget*/,
+ sal_Int32 /*nFlags*/ )
+{
+ // must be implemented by subclass
+ osl::MutexGuard aLock( m_aMutex );
+ throwIfDisposed();
+
+ return Reference< XDispatch >();
+}
+
+Sequence< Reference< XDispatch > > SAL_CALL PopupMenuControllerBase::queryDispatches( const Sequence< DispatchDescriptor >& lDescriptor )
+{
+ // Create return list - which must have same size then the given descriptor
+ // It's not allowed to pack it!
+ {
+ osl::MutexGuard aLock(m_aMutex);
+ throwIfDisposed();
+ }
+
+ sal_Int32 nCount = lDescriptor.getLength();
+ uno::Sequence< uno::Reference< frame::XDispatch > > lDispatcher( nCount );
+
+ // Step over all descriptors and try to get any dispatcher for it.
+ std::transform(lDescriptor.begin(), lDescriptor.end(), lDispatcher.getArray(),
+ [this](const DispatchDescriptor& rDesc) -> uno::Reference< frame::XDispatch > {
+ return queryDispatch(rDesc.FeatureURL, rDesc.FrameName, rDesc.SearchFlags); });
+
+ return lDispatcher;
+}
+
+// XDispatch
+void SAL_CALL
+PopupMenuControllerBase::dispatch(
+ const URL& /*aURL*/,
+ const Sequence< PropertyValue >& /*seqProperties*/ )
+{
+ // must be implemented by subclass
+ osl::MutexGuard aLock( m_aMutex );
+ throwIfDisposed();
+}
+
+void SAL_CALL
+PopupMenuControllerBase::addStatusListener(
+ const Reference< XStatusListener >& xControl,
+ const URL& aURL )
+{
+ osl::ResettableMutexGuard aLock( m_aMutex );
+ throwIfDisposed();
+ aLock.clear();
+
+ bool bStatusUpdate( false );
+ rBHelper.addListener( cppu::UnoType<decltype(xControl)>::get(), xControl );
+
+ aLock.reset();
+ if ( aURL.Complete.startsWith( m_aBaseURL ) )
+ bStatusUpdate = true;
+ aLock.clear();
+
+ if ( bStatusUpdate )
+ {
+ // Dummy update for popup menu controllers
+ FeatureStateEvent aEvent;
+ aEvent.FeatureURL = aURL;
+ aEvent.IsEnabled = true;
+ aEvent.Requery = false;
+ aEvent.State = Any();
+ xControl->statusChanged( aEvent );
+ }
+}
+
+void SAL_CALL PopupMenuControllerBase::removeStatusListener(
+ const Reference< XStatusListener >& xControl,
+ const URL& /*aURL*/ )
+{
+ rBHelper.removeListener( cppu::UnoType<decltype(xControl)>::get(), xControl );
+}
+
+OUString PopupMenuControllerBase::determineBaseURL( const OUString& aURL )
+{
+ // Just use the main part of the URL for popup menu controllers
+ sal_Int32 nSchemePart( 0 );
+ OUString aMainURL( "vnd.sun.star.popup:" );
+
+ nSchemePart = aURL.indexOf( ':' );
+ if (( nSchemePart > 0 ) &&
+ ( aURL.getLength() > ( nSchemePart+1 )))
+ {
+ sal_Int32 nQueryPart = aURL.indexOf( '?', nSchemePart );
+ if ( nQueryPart > 0 )
+ aMainURL += aURL.subView( nSchemePart, nQueryPart-nSchemePart );
+ else if ( nQueryPart == -1 )
+ aMainURL += aURL.subView( nSchemePart+1 );
+ }
+
+ return aMainURL;
+}
+
+// XInitialization
+void SAL_CALL PopupMenuControllerBase::initialize( const Sequence< Any >& aArguments )
+{
+ osl::MutexGuard aLock( m_aMutex );
+
+ bool bInitialized( m_bInitialized );
+ if ( bInitialized )
+ return;
+
+ PropertyValue aPropValue;
+ OUString aCommandURL;
+ Reference< XFrame > xFrame;
+
+ for ( const auto& rArgument : aArguments )
+ {
+ if ( rArgument >>= aPropValue )
+ {
+ if ( aPropValue.Name == "Frame" )
+ aPropValue.Value >>= xFrame;
+ else if ( aPropValue.Name == "CommandURL" )
+ aPropValue.Value >>= aCommandURL;
+ else if ( aPropValue.Name == "ModuleIdentifier" )
+ aPropValue.Value >>= m_aModuleName;
+ }
+ }
+
+ if ( xFrame.is() && !aCommandURL.isEmpty() )
+ {
+ m_xFrame = xFrame;
+ m_aCommandURL = aCommandURL;
+ m_aBaseURL = determineBaseURL( aCommandURL );
+ m_bInitialized = true;
+ }
+}
+// XPopupMenuController
+void SAL_CALL PopupMenuControllerBase::setPopupMenu( const Reference< awt::XPopupMenu >& xPopupMenu )
+{
+ osl::MutexGuard aLock( m_aMutex );
+ throwIfDisposed();
+
+ if ( !m_xFrame.is() || m_xPopupMenu.is() )
+ return;
+
+ // Create popup menu on demand
+ SolarMutexGuard aSolarMutexGuard;
+
+ m_xPopupMenu = xPopupMenu;
+ m_xPopupMenu->addMenuListener( Reference< awt::XMenuListener >(this) );
+
+ Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
+
+ URL aTargetURL;
+ aTargetURL.Complete = m_aCommandURL;
+ m_xURLTransformer->parseStrict( aTargetURL );
+ m_xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
+
+ impl_setPopupMenu();
+
+ updatePopupMenu();
+}
+void PopupMenuControllerBase::impl_setPopupMenu()
+{
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/popupwindowcontroller.cxx b/svtools/source/uno/popupwindowcontroller.cxx
new file mode 100644
index 000000000..83419b4d9
--- /dev/null
+++ b/svtools/source/uno/popupwindowcontroller.cxx
@@ -0,0 +1,270 @@
+/* -*- 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 <cppuhelper/supportsservice.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/toolbox.hxx>
+
+#include <svtools/popupwindowcontroller.hxx>
+#include <svtools/toolbarmenu.hxx>
+
+using namespace ::com::sun::star;
+using namespace css::uno;
+using namespace css::lang;
+
+
+namespace svt
+{
+
+class PopupWindowControllerImpl
+{
+public:
+ PopupWindowControllerImpl();
+ ~PopupWindowControllerImpl() COVERITY_NOEXCEPT_FALSE;
+
+ void SetPopupWindow( vcl::Window* pPopupWindow, ToolBox* pToolBox );
+ void SetFloatingWindow();
+ DECL_LINK( WindowEventListener, VclWindowEvent&, void );
+
+private:
+ VclPtr<vcl::Window> mpPopupWindow, mpFloatingWindow;
+ VclPtr<ToolBox> mpToolBox;
+};
+
+PopupWindowControllerImpl::PopupWindowControllerImpl()
+{
+}
+
+PopupWindowControllerImpl::~PopupWindowControllerImpl() COVERITY_NOEXCEPT_FALSE
+{
+ SetPopupWindow(nullptr,nullptr);
+ SetFloatingWindow();
+}
+
+void PopupWindowControllerImpl::SetPopupWindow( vcl::Window* pPopupWindow, ToolBox* pToolBox )
+{
+ if( mpPopupWindow )
+ {
+ mpPopupWindow->RemoveEventListener( LINK( this, PopupWindowControllerImpl, WindowEventListener ) );
+ mpPopupWindow.disposeAndClear();
+ }
+ mpPopupWindow = pPopupWindow;
+ mpToolBox = pToolBox;
+
+ if( mpPopupWindow )
+ {
+ mpPopupWindow->AddEventListener( LINK( this, PopupWindowControllerImpl, WindowEventListener ));
+ }
+}
+
+void PopupWindowControllerImpl::SetFloatingWindow()
+{
+ if( mpFloatingWindow )
+ {
+ mpFloatingWindow->RemoveEventListener( LINK( this, PopupWindowControllerImpl, WindowEventListener ) );
+ mpFloatingWindow.disposeAndClear();
+ }
+ mpFloatingWindow = mpPopupWindow;
+ mpPopupWindow.clear();
+}
+
+IMPL_LINK( PopupWindowControllerImpl, WindowEventListener, VclWindowEvent&, rWindowEvent, void )
+{
+ switch( rWindowEvent.GetId() )
+ {
+ case VclEventId::WindowEndPopupMode:
+ {
+ EndPopupModeData* pData = static_cast< EndPopupModeData* >( rWindowEvent.GetData() );
+ if( pData && pData->mbTearoff )
+ {
+ vcl::Window::GetDockingManager()->SetFloatingMode( mpPopupWindow.get(), true );
+ vcl::Window::GetDockingManager()->SetPosSizePixel( mpPopupWindow.get(),
+ pData->maFloatingPos.X(),
+ pData->maFloatingPos.Y(),
+ 0, 0,
+ PosSizeFlags::Pos );
+ SetFloatingWindow();
+ mpFloatingWindow->Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
+ }
+ SetPopupWindow(nullptr,nullptr);
+ break;
+ }
+ case VclEventId::WindowPrepareToggleFloating:
+ {
+ if ( mpFloatingWindow && rWindowEvent.GetWindow() == mpFloatingWindow.get() )
+ {
+ bool* pData = static_cast< bool* >( rWindowEvent.GetData() );
+ *pData = false;
+ }
+ break;
+ }
+ case VclEventId::WindowClose:
+ {
+ SetPopupWindow(nullptr,nullptr);
+ SetFloatingWindow();
+ break;
+ }
+ case VclEventId::WindowShow:
+ {
+ if( mpPopupWindow )
+ {
+ if( mpToolBox )
+ mpToolBox->CallEventListeners( VclEventId::DropdownOpen, static_cast<void*>(mpPopupWindow) );
+ mpPopupWindow->CallEventListeners( VclEventId::WindowGetFocus );
+ break;
+ }
+ break;
+ }
+ case VclEventId::WindowHide:
+ {
+ if( mpPopupWindow )
+ {
+ mpPopupWindow->CallEventListeners( VclEventId::WindowLoseFocus );
+ if( mpToolBox )
+ mpToolBox->CallEventListeners( VclEventId::DropdownClose, static_cast<void*>(mpPopupWindow) );
+ }
+ break;
+ }
+ default: break;
+ }
+}
+
+
+
+
+PopupWindowController::PopupWindowController( const Reference< uno::XComponentContext >& rxContext,
+ const Reference< frame::XFrame >& xFrame,
+ const OUString& aCommandURL )
+: PopupWindowController_Base( rxContext, xFrame, aCommandURL )
+, mxImpl( new PopupWindowControllerImpl() )
+{
+}
+
+PopupWindowController::~PopupWindowController()
+{
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL PopupWindowController::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XComponent
+void SAL_CALL PopupWindowController::dispose()
+{
+ mxInterimPopover.clear();
+ mxPopoverContainer.reset();
+ mxImpl.reset();
+ svt::ToolboxController::dispose();
+}
+
+// XStatusListener
+void SAL_CALL PopupWindowController::statusChanged( const frame::FeatureStateEvent& rEvent )
+{
+ SolarMutexGuard aSolarLock;
+
+ bool bValue = false;
+ rEvent.State >>= bValue;
+
+ if (m_pToolbar)
+ {
+ OString sId = m_aCommandURL.toUtf8();
+ m_pToolbar->set_item_active(sId, bValue);
+ m_pToolbar->set_item_sensitive(sId, rEvent.IsEnabled);
+ return;
+ }
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nItemId;
+ if ( getToolboxId( nItemId, &pToolBox ) )
+ {
+ pToolBox->CheckItem( nItemId, bValue );
+ pToolBox->EnableItem( nItemId, rEvent.IsEnabled );
+ }
+}
+
+VclPtr<vcl::Window> PopupWindowController::createVclPopupWindow(vcl::Window* /*pParent*/)
+{
+ return nullptr;
+}
+
+Reference< awt::XWindow > SAL_CALL PopupWindowController::createPopupWindow()
+{
+ if (m_pToolbar)
+ {
+ mxPopoverContainer->unsetPopover();
+ mxPopoverContainer->setPopover(weldPopupWindow());
+ return Reference<awt::XWindow>();
+ }
+
+ VclPtr< ToolBox > pToolBox = dynamic_cast< ToolBox* >( VCLUnoHelper::GetWindow( getParent() ) );
+ if( pToolBox )
+ {
+ vcl::Window* pItemWindow = pToolBox->GetItemWindow( pToolBox->GetDownItemId() );
+ VclPtr<vcl::Window> pWin = createVclPopupWindow( pItemWindow ? pItemWindow : pToolBox );
+ if( pWin )
+ {
+ FloatWinPopupFlags eFloatFlags = FloatWinPopupFlags::GrabFocus |
+ FloatWinPopupFlags::AllMouseButtonClose |
+ FloatWinPopupFlags::NoMouseUpClose;
+
+ WinBits nWinBits;
+ if ( pWin->GetType() == WindowType::DOCKINGWINDOW )
+ nWinBits = static_cast< DockingWindow* >( pWin.get() )->GetFloatStyle();
+ else
+ nWinBits = pWin->GetStyle();
+
+ if ( nWinBits & ( WB_SIZEABLE | WB_CLOSEABLE ) )
+ eFloatFlags |= FloatWinPopupFlags::AllowTearOff;
+
+ pWin->EnableDocking();
+ mxImpl->SetPopupWindow(pWin,pToolBox);
+ vcl::Window::GetDockingManager()->StartPopupMode( pToolBox, pWin, eFloatFlags );
+ }
+ }
+ return Reference< awt::XWindow >();
+}
+
+void SAL_CALL PopupWindowController::click()
+{
+ if (m_pToolbar)
+ {
+ if (m_pToolbar->get_menu_item_active(m_aCommandURL.toUtf8()))
+ createPopupWindow();
+ else
+ mxPopoverContainer->unsetPopover();
+ }
+
+ svt::ToolboxController::click();
+}
+
+void PopupWindowController::EndPopupMode()
+{
+ if (m_pToolbar)
+ m_pToolbar->set_menu_item_active(m_aCommandURL.toUtf8(), false);
+ else if (mxInterimPopover)
+ mxInterimPopover->EndPopupMode();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/statusbarcontroller.cxx b/svtools/source/uno/statusbarcontroller.cxx
new file mode 100644
index 000000000..fae89f287
--- /dev/null
+++ b/svtools/source/uno/statusbarcontroller.cxx
@@ -0,0 +1,594 @@
+/* -*- 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 <svtools/statusbarcontroller.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/ui/XStatusbarItem.hpp>
+#include <cppuhelper/queryinterface.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <vcl/status.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <comphelper/processfactory.hxx>
+
+using namespace ::cppu;
+using namespace css::awt;
+using namespace css::uno;
+using namespace css::util;
+using namespace css::beans;
+using namespace css::lang;
+using namespace css::frame;
+
+namespace svt
+{
+
+StatusbarController::StatusbarController(
+ const Reference< XComponentContext >& rxContext,
+ const Reference< XFrame >& xFrame,
+ const OUString& aCommandURL,
+ unsigned short nID ) :
+ OWeakObject()
+ , m_bInitialized( false )
+ , m_bDisposed( false )
+ , m_nID( nID )
+ , m_xFrame( xFrame )
+ , m_xContext( rxContext )
+ , m_aCommandURL( aCommandURL )
+ , m_aListenerContainer( m_aMutex )
+{
+}
+
+StatusbarController::StatusbarController() :
+ OWeakObject()
+ , m_bInitialized( false )
+ , m_bDisposed( false )
+ , m_nID( 0 )
+ , m_aListenerContainer( m_aMutex )
+{
+}
+
+StatusbarController::~StatusbarController()
+{
+}
+
+Reference< XFrame > StatusbarController::getFrameInterface() const
+{
+ SolarMutexGuard aSolarMutexGuard;
+ return m_xFrame;
+}
+
+Reference< XURLTransformer > StatusbarController::getURLTransformer() const
+{
+ SolarMutexGuard aSolarMutexGuard;
+ if ( !m_xURLTransformer.is() && m_xContext.is() )
+ {
+ m_xURLTransformer = css::util::URLTransformer::create( m_xContext );
+ }
+
+ return m_xURLTransformer;
+}
+
+// XInterface
+Any SAL_CALL StatusbarController::queryInterface( const Type& rType )
+{
+ Any a = ::cppu::queryInterface(
+ rType ,
+ static_cast< XStatusbarController* >( this ),
+ static_cast< XStatusListener* >( this ),
+ static_cast< XEventListener* >( this ),
+ static_cast< XInitialization* >( this ),
+ static_cast< XComponent* >( this ),
+ static_cast< XUpdatable* >( this ));
+
+ if ( a.hasValue() )
+ return a;
+
+ return OWeakObject::queryInterface( rType );
+}
+
+void SAL_CALL StatusbarController::acquire() noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL StatusbarController::release() noexcept
+{
+ OWeakObject::release();
+}
+
+void SAL_CALL StatusbarController::initialize( const Sequence< Any >& aArguments )
+{
+ bool bInitialized( true );
+
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ if ( m_bDisposed )
+ throw DisposedException();
+
+ bInitialized = m_bInitialized;
+ }
+
+ if ( bInitialized )
+ return;
+
+ SolarMutexGuard aSolarMutexGuard;
+ m_bInitialized = true;
+
+ PropertyValue aPropValue;
+ for ( const auto& rArgument : aArguments )
+ {
+ if ( rArgument >>= aPropValue )
+ {
+ if ( aPropValue.Name == "Frame" )
+ aPropValue.Value >>= m_xFrame;
+ else if ( aPropValue.Name == "CommandURL" )
+ aPropValue.Value >>= m_aCommandURL;
+ else if ( aPropValue.Name == "ServiceManager" )
+ {
+ Reference<XMultiServiceFactory> xMSF;
+ aPropValue.Value >>= xMSF;
+ if( xMSF.is() )
+ m_xContext = comphelper::getComponentContext(xMSF);
+ }
+ else if ( aPropValue.Name == "ParentWindow" )
+ aPropValue.Value >>= m_xParentWindow;
+ else if ( aPropValue.Name == "Identifier" )
+ aPropValue.Value >>= m_nID;
+ else if ( aPropValue.Name == "StatusbarItem" )
+ aPropValue.Value >>= m_xStatusbarItem;
+ }
+ }
+
+ if ( !m_aCommandURL.isEmpty() )
+ m_aListenerMap.emplace( m_aCommandURL, Reference< XDispatch >() );
+}
+
+void SAL_CALL StatusbarController::update()
+{
+ {
+ SolarMutexGuard aSolarMutexGuard;
+ if ( m_bDisposed )
+ throw DisposedException();
+ }
+
+ // Bind all registered listeners to their dispatch objects
+ bindListener();
+}
+
+// XComponent
+void SAL_CALL StatusbarController::dispose()
+{
+ Reference< XComponent > xThis = this;
+
+ {
+ SolarMutexGuard aSolarMutexGuard;
+ if ( m_bDisposed )
+ throw DisposedException();
+ }
+
+ css::lang::EventObject aEvent( xThis );
+ m_aListenerContainer.disposeAndClear( aEvent );
+
+ SolarMutexGuard aSolarMutexGuard;
+ Reference< XStatusListener > xStatusListener = this;
+ Reference< XURLTransformer > xURLTransformer = getURLTransformer();
+ css::util::URL aTargetURL;
+ for (auto const& listener : m_aListenerMap)
+ {
+ try
+ {
+ Reference< XDispatch > xDispatch(listener.second);
+ aTargetURL.Complete = listener.first;
+ xURLTransformer->parseStrict( aTargetURL );
+
+ if ( xDispatch.is() && xStatusListener.is() )
+ xDispatch->removeStatusListener( xStatusListener, aTargetURL );
+ }
+ catch ( Exception& )
+ {
+ }
+ }
+
+ // clear hash map
+ m_aListenerMap.clear();
+
+ // release references
+ m_xURLTransformer.clear();
+ m_xContext.clear();
+ m_xFrame.clear();
+ m_xParentWindow.clear();
+ m_xStatusbarItem.clear();
+
+ m_bDisposed = true;
+}
+
+void SAL_CALL StatusbarController::addEventListener( const Reference< XEventListener >& xListener )
+{
+ m_aListenerContainer.addInterface( cppu::UnoType<XEventListener>::get(), xListener );
+}
+
+void SAL_CALL StatusbarController::removeEventListener( const Reference< XEventListener >& aListener )
+{
+ m_aListenerContainer.removeInterface( cppu::UnoType<XEventListener>::get(), aListener );
+}
+
+// XEventListener
+void SAL_CALL StatusbarController::disposing( const EventObject& Source )
+{
+ SolarMutexGuard aSolarMutexGuard;
+
+ if ( m_bDisposed )
+ return;
+
+ Reference< XFrame > xFrame( Source.Source, UNO_QUERY );
+ if ( xFrame.is() )
+ {
+ if ( xFrame == m_xFrame )
+ m_xFrame.clear();
+ return;
+ }
+
+ Reference< XDispatch > xDispatch( Source.Source, UNO_QUERY );
+ if ( !xDispatch.is() )
+ return;
+
+ for (auto & listener : m_aListenerMap)
+ {
+ // Compare references and release dispatch references if they are equal.
+ if ( xDispatch == listener.second )
+ listener.second.clear();
+ }
+}
+
+// XStatusListener
+void SAL_CALL StatusbarController::statusChanged( const FeatureStateEvent& Event )
+{
+ SolarMutexGuard aSolarMutexGuard;
+
+ if ( m_bDisposed )
+ return;
+
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( m_xParentWindow );
+ if ( pWindow && pWindow->GetType() == WindowType::STATUSBAR && m_nID != 0 )
+ {
+ OUString aStrValue;
+ StatusBar* pStatusBar = static_cast<StatusBar *>(pWindow.get());
+
+ if ( Event.State >>= aStrValue )
+ pStatusBar->SetItemText( m_nID, aStrValue );
+ else if ( !Event.State.hasValue() )
+ pStatusBar->SetItemText( m_nID, "" );
+ }
+}
+
+// XStatusbarController
+sal_Bool SAL_CALL StatusbarController::mouseButtonDown(
+ const css::awt::MouseEvent& )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL StatusbarController::mouseMove(
+ const css::awt::MouseEvent& )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL StatusbarController::mouseButtonUp(
+ const css::awt::MouseEvent& )
+{
+ return false;
+}
+
+void SAL_CALL StatusbarController::command(
+ const css::awt::Point&,
+ ::sal_Int32,
+ sal_Bool,
+ const css::uno::Any& )
+{
+}
+
+void SAL_CALL StatusbarController::paint(
+ const css::uno::Reference< css::awt::XGraphics >&,
+ const css::awt::Rectangle&,
+ ::sal_Int32 )
+{
+}
+
+void SAL_CALL StatusbarController::click( const css::awt::Point& )
+{
+}
+
+void SAL_CALL StatusbarController::doubleClick( const css::awt::Point& )
+{
+ SolarMutexGuard aSolarMutexGuard;
+
+ if ( m_bDisposed )
+ return;
+
+ Sequence< PropertyValue > aArgs;
+ execute( aArgs );
+}
+
+void StatusbarController::addStatusListener( const OUString& aCommandURL )
+{
+ Reference< XDispatch > xDispatch;
+ Reference< XStatusListener > xStatusListener;
+ css::util::URL aTargetURL;
+
+ {
+ SolarMutexGuard aSolarMutexGuard;
+ URLToDispatchMap::iterator pIter = m_aListenerMap.find( aCommandURL );
+
+ // Already in the list of status listener. Do nothing.
+ if ( pIter != m_aListenerMap.end() )
+ return;
+
+ // Check if we are already initialized. Implementation starts adding itself as status listener when
+ // initialize is called.
+ if ( !m_bInitialized )
+ {
+ // Put into the unordered_map of status listener. Will be activated when initialized is called
+ m_aListenerMap.emplace( aCommandURL, Reference< XDispatch >() );
+ return;
+ }
+ else
+ {
+ // Add status listener directly as initialize has already been called.
+ Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
+ if ( m_xContext.is() && xDispatchProvider.is() )
+ {
+ Reference< XURLTransformer > xURLTransformer = getURLTransformer();
+ aTargetURL.Complete = aCommandURL;
+ xURLTransformer->parseStrict( aTargetURL );
+ xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
+
+ xStatusListener = this;
+ URLToDispatchMap::iterator aIter = m_aListenerMap.find( aCommandURL );
+ if ( aIter != m_aListenerMap.end() )
+ {
+ Reference< XDispatch > xOldDispatch( aIter->second );
+ aIter->second = xDispatch;
+
+ try
+ {
+ if ( xOldDispatch.is() )
+ xOldDispatch->removeStatusListener( xStatusListener, aTargetURL );
+ }
+ catch ( Exception& )
+ {
+ }
+ }
+ else
+ m_aListenerMap.emplace( aCommandURL, xDispatch );
+ }
+ }
+ }
+
+ // Call without locked mutex as we are called back from dispatch implementation
+ try
+ {
+ if ( xDispatch.is() )
+ xDispatch->addStatusListener( xStatusListener, aTargetURL );
+ }
+ catch ( Exception& )
+ {
+ }
+}
+
+void StatusbarController::bindListener()
+{
+ std::vector< Listener > aDispatchVector;
+ Reference< XStatusListener > xStatusListener;
+
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ if ( !m_bInitialized )
+ return;
+
+ // Collect all registered command URL's and store them temporary
+ Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
+ if ( m_xContext.is() && xDispatchProvider.is() )
+ {
+ xStatusListener = this;
+ for (auto & listener : m_aListenerMap)
+ {
+ Reference< XURLTransformer > xURLTransformer = getURLTransformer();
+ css::util::URL aTargetURL;
+ aTargetURL.Complete = listener.first;
+ xURLTransformer->parseStrict( aTargetURL );
+
+ Reference< XDispatch > xDispatch(listener.second);
+ if ( xDispatch.is() )
+ {
+ // We already have a dispatch object => we have to requery.
+ // Release old dispatch object and remove it as listener
+ try
+ {
+ xDispatch->removeStatusListener( xStatusListener, aTargetURL );
+ }
+ catch ( Exception& )
+ {
+ }
+ }
+
+ listener.second.clear();
+ xDispatch.clear();
+
+ // Query for dispatch object. Old dispatch will be released with this, too.
+ try
+ {
+ xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
+ }
+ catch ( Exception& )
+ {
+ }
+ listener.second = xDispatch;
+
+ Listener aListener( aTargetURL, xDispatch );
+ aDispatchVector.push_back( aListener );
+ }
+ }
+ }
+
+ // Call without locked mutex as we are called back from dispatch implementation
+ if ( !xStatusListener.is() )
+ return;
+
+ for (Listener & rListener : aDispatchVector)
+ {
+ try
+ {
+ if ( rListener.xDispatch.is() )
+ rListener.xDispatch->addStatusListener( xStatusListener, rListener.aURL );
+ else if ( rListener.aURL.Complete == m_aCommandURL )
+ {
+ // Send status changed for the main URL, if we cannot get a valid dispatch object.
+ // UI disables the button. Catch exception as we release our mutex, it is possible
+ // that someone else already disposed this instance!
+ FeatureStateEvent aFeatureStateEvent;
+ aFeatureStateEvent.IsEnabled = false;
+ aFeatureStateEvent.FeatureURL = rListener.aURL;
+ aFeatureStateEvent.State = Any();
+ xStatusListener->statusChanged( aFeatureStateEvent );
+ }
+ }
+ catch ( ... ){}
+ }
+}
+
+::tools::Rectangle StatusbarController::getControlRect() const
+{
+ ::tools::Rectangle aRect;
+
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ if ( m_bDisposed )
+ throw DisposedException();
+
+ if ( m_xParentWindow.is() )
+ {
+ VclPtr< StatusBar > pStatusBar = dynamic_cast< StatusBar* >( VCLUnoHelper::GetWindow( m_xParentWindow ) );
+ if ( pStatusBar && pStatusBar->GetType() == WindowType::STATUSBAR )
+ aRect = pStatusBar->GetItemRect( m_nID );
+ }
+ }
+
+ return aRect;
+}
+
+void StatusbarController::execute( const css::uno::Sequence< css::beans::PropertyValue >& aArgs )
+{
+ Reference< XDispatch > xDispatch;
+ Reference< XURLTransformer > xURLTransformer;
+ OUString aCommandURL;
+
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ if ( m_bDisposed )
+ throw DisposedException();
+
+ if ( m_bInitialized &&
+ m_xFrame.is() &&
+ m_xContext.is() &&
+ !m_aCommandURL.isEmpty() )
+ {
+ xURLTransformer = getURLTransformer();
+ aCommandURL = m_aCommandURL;
+ URLToDispatchMap::iterator pIter = m_aListenerMap.find( m_aCommandURL );
+ if ( pIter != m_aListenerMap.end() )
+ xDispatch = pIter->second;
+ }
+ }
+
+ if ( !(xDispatch.is() && xURLTransformer.is()) )
+ return;
+
+ try
+ {
+ css::util::URL aTargetURL;
+
+ aTargetURL.Complete = aCommandURL;
+ xURLTransformer->parseStrict( aTargetURL );
+ xDispatch->dispatch( aTargetURL, aArgs );
+ }
+ catch ( DisposedException& )
+ {
+ }
+}
+
+void StatusbarController::execute(
+ const OUString& aCommandURL,
+ const Sequence< css::beans::PropertyValue >& aArgs )
+{
+ Reference< XDispatch > xDispatch;
+ css::util::URL aTargetURL;
+
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ if ( m_bDisposed )
+ throw DisposedException();
+
+ if ( m_bInitialized &&
+ m_xFrame.is() &&
+ m_xContext.is() &&
+ !m_aCommandURL.isEmpty() )
+ {
+ Reference< XURLTransformer > xURLTransformer( getURLTransformer() );
+ aTargetURL.Complete = aCommandURL;
+ xURLTransformer->parseStrict( aTargetURL );
+
+ URLToDispatchMap::iterator pIter = m_aListenerMap.find( aCommandURL );
+ if ( pIter != m_aListenerMap.end() )
+ xDispatch = pIter->second;
+ else
+ {
+ Reference< css::frame::XDispatchProvider > xDispatchProvider(
+ m_xFrame->getController(), UNO_QUERY );
+ if ( xDispatchProvider.is() )
+ xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
+ }
+ }
+ }
+
+ if ( xDispatch.is() )
+ {
+ try
+ {
+ xDispatch->dispatch( aTargetURL, aArgs );
+ }
+ catch ( DisposedException& )
+ {
+ }
+ }
+}
+
+} // svt
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/svtxgridcontrol.cxx b/svtools/source/uno/svtxgridcontrol.cxx
new file mode 100644
index 000000000..4aee46f2c
--- /dev/null
+++ b/svtools/source/uno/svtxgridcontrol.cxx
@@ -0,0 +1,909 @@
+/* -*- 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 "svtxgridcontrol.hxx"
+#include <com/sun/star/view/SelectionType.hpp>
+#include <table/tablecontrolinterface.hxx>
+#include <table/gridtablerenderer.hxx>
+#include <table/tablecontrol.hxx>
+#include "unocontroltablemodel.hxx"
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+#include <toolkit/helper/property.hxx>
+#include <com/sun/star/awt/grid/XGridColumn.hpp>
+#include <com/sun/star/awt/grid/GridInvalidDataException.hpp>
+#include <com/sun/star/awt/grid/GridInvalidModelException.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/util/Color.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+
+#include <vcl/svapp.hxx>
+
+#include <algorithm>
+
+using css::uno::Reference;
+using css::uno::Exception;
+using css::uno::UNO_QUERY;
+using css::uno::UNO_QUERY_THROW;
+using css::uno::Any;
+using css::uno::Sequence;
+using css::awt::grid::XGridSelectionListener;
+using css::style::VerticalAlignment;
+using css::style::VerticalAlignment_TOP;
+using css::view::SelectionType;
+using css::view::SelectionType_NONE;
+using css::view::SelectionType_RANGE;
+using css::view::SelectionType_SINGLE;
+using css::view::SelectionType_MULTI;
+using css::awt::grid::XGridDataModel;
+using css::awt::grid::GridInvalidDataException;
+using css::lang::EventObject;
+using css::lang::IndexOutOfBoundsException;
+using css::awt::grid::XGridColumnModel;
+using css::awt::grid::GridSelectionEvent;
+using css::awt::grid::XGridColumn;
+using css::container::ContainerEvent;
+using css::awt::grid::GridDataEvent;
+using css::awt::grid::GridInvalidModelException;
+
+namespace AccessibleEventId = css::accessibility::AccessibleEventId;
+namespace AccessibleStateType = css::accessibility::AccessibleStateType;
+
+using namespace ::svt::table;
+
+
+SVTXGridControl::SVTXGridControl()
+ :m_xTableModel( std::make_shared<UnoControlTableModel>() )
+ ,m_bTableModelInitCompleted( false )
+ ,m_aSelectionListeners( *this )
+{
+}
+
+
+SVTXGridControl::~SVTXGridControl()
+{
+}
+
+
+void SVTXGridControl::SetWindow( const VclPtr< vcl::Window > &pWindow )
+{
+ SVTXGridControl_Base::SetWindow( pWindow );
+ impl_checkTableModelInit();
+}
+
+
+void SVTXGridControl::impl_checkColumnIndex_throw( ::svt::table::TableControl const & i_table, sal_Int32 const i_columnIndex ) const
+{
+ if ( ( i_columnIndex < 0 ) || ( i_columnIndex >= i_table.GetColumnCount() ) )
+ throw IndexOutOfBoundsException( OUString(), *const_cast< SVTXGridControl* >( this ) );
+}
+
+
+void SVTXGridControl::impl_checkRowIndex_throw( ::svt::table::TableControl const & i_table, sal_Int32 const i_rowIndex ) const
+{
+ if ( ( i_rowIndex < 0 ) || ( i_rowIndex >= i_table.GetRowCount() ) )
+ throw IndexOutOfBoundsException( OUString(), *const_cast< SVTXGridControl* >( this ) );
+}
+
+
+sal_Int32 SAL_CALL SVTXGridControl::getRowAtPoint(::sal_Int32 x, ::sal_Int32 y)
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN( pTable, "SVTXGridControl::getRowAtPoint: no control (anymore)!", -1 );
+
+ TableCell const tableCell = pTable->getTableControlInterface().hitTest( Point( x, y ) );
+ return ( tableCell.nRow >= 0 ) ? tableCell.nRow : -1;
+}
+
+
+sal_Int32 SAL_CALL SVTXGridControl::getColumnAtPoint(::sal_Int32 x, ::sal_Int32 y)
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN( pTable, "SVTXGridControl::getColumnAtPoint: no control (anymore)!", -1 );
+
+ TableCell const tableCell = pTable->getTableControlInterface().hitTest( Point( x, y ) );
+ return ( tableCell.nColumn >= 0 ) ? tableCell.nColumn : -1;
+}
+
+
+sal_Int32 SAL_CALL SVTXGridControl::getCurrentColumn( )
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN( pTable, "SVTXGridControl::getCurrentColumn: no control (anymore)!", -1 );
+
+ sal_Int32 const nColumn = pTable->GetCurrentColumn();
+ return ( nColumn >= 0 ) ? nColumn : -1;
+}
+
+
+sal_Int32 SAL_CALL SVTXGridControl::getCurrentRow( )
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN( pTable, "SVTXGridControl::getCurrentRow: no control (anymore)!", -1 );
+
+ sal_Int32 const nRow = pTable->GetCurrentRow();
+ return ( nRow >= 0 ) ? nRow : -1;
+}
+
+
+void SAL_CALL SVTXGridControl::goToCell( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex )
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN_VOID( pTable, "SVTXGridControl::getCurrentRow: no control (anymore)!" );
+
+ impl_checkColumnIndex_throw( *pTable, i_columnIndex );
+ impl_checkRowIndex_throw( *pTable, i_rowIndex );
+
+ pTable->GoTo( i_columnIndex, i_rowIndex );
+}
+
+
+void SAL_CALL SVTXGridControl::addSelectionListener(const Reference< XGridSelectionListener > & listener)
+{
+ m_aSelectionListeners.addInterface(listener);
+}
+
+
+void SAL_CALL SVTXGridControl::removeSelectionListener(const Reference< XGridSelectionListener > & listener)
+{
+ m_aSelectionListeners.removeInterface(listener);
+}
+
+
+void SVTXGridControl::setProperty( const OUString& PropertyName, const Any& aValue)
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN_VOID( pTable, "SVTXGridControl::setProperty: no control (anymore)!" );
+
+ switch( GetPropertyId( PropertyName ) )
+ {
+ case BASEPROPERTY_ROW_HEADER_WIDTH:
+ {
+ sal_Int32 rowHeaderWidth( -1 );
+ aValue >>= rowHeaderWidth;
+ if ( rowHeaderWidth <= 0 )
+ {
+ SAL_WARN( "svtools.uno", "SVTXGridControl::setProperty: illegal row header width!" );
+ break;
+ }
+
+ m_xTableModel->setRowHeaderWidth( rowHeaderWidth );
+ // TODO: the model should broadcast this change itself, and the table should invalidate itself as needed
+ pTable->Invalidate();
+ }
+ break;
+
+ case BASEPROPERTY_COLUMN_HEADER_HEIGHT:
+ {
+ sal_Int32 columnHeaderHeight = 0;
+ if ( !aValue.hasValue() )
+ {
+ columnHeaderHeight = pTable->PixelToLogic(Size(0, pTable->GetTextHeight() + 3), MapMode(MapUnit::MapAppFont)).Height();
+ }
+ else
+ {
+ aValue >>= columnHeaderHeight;
+ }
+ if ( columnHeaderHeight <= 0 )
+ {
+ SAL_WARN( "svtools.uno", "SVTXGridControl::setProperty: illegal column header width!" );
+ break;
+ }
+
+ m_xTableModel->setColumnHeaderHeight( columnHeaderHeight );
+ // TODO: the model should broadcast this change itself, and the table should invalidate itself as needed
+ pTable->Invalidate();
+ }
+ break;
+
+ case BASEPROPERTY_USE_GRID_LINES:
+ {
+ GridTableRenderer* pGridRenderer = dynamic_cast< GridTableRenderer* >(
+ m_xTableModel->getRenderer().get() );
+ if ( !pGridRenderer )
+ {
+ SAL_WARN( "svtools.uno", "SVTXGridControl::setProperty(UseGridLines): invalid renderer!" );
+ break;
+ }
+
+ bool bUseGridLines = false;
+ OSL_VERIFY( aValue >>= bUseGridLines );
+ pGridRenderer->useGridLines( bUseGridLines );
+ pTable->Invalidate();
+ }
+ break;
+
+ case BASEPROPERTY_ROW_HEIGHT:
+ {
+ sal_Int32 rowHeight = 0;
+ if ( !aValue.hasValue() )
+ {
+ rowHeight = pTable->PixelToLogic(Size(0, pTable->GetTextHeight() + 3), MapMode(MapUnit::MapAppFont)).Height();
+ }
+ else
+ {
+ aValue >>= rowHeight;
+ }
+ m_xTableModel->setRowHeight( rowHeight );
+ if ( rowHeight <= 0 )
+ {
+ SAL_WARN( "svtools.uno", "SVTXGridControl::setProperty: illegal row height!" );
+ break;
+ }
+
+ // TODO: the model should broadcast this change itself, and the table should invalidate itself as needed
+ pTable->Invalidate();
+ }
+ break;
+
+ case BASEPROPERTY_BACKGROUNDCOLOR:
+ {
+ // let the base class handle this for the TableControl
+ VCLXWindow::setProperty( PropertyName, aValue );
+ // and forward to the grid control's data window
+ if ( pTable->IsBackground() )
+ pTable->getDataWindow().SetBackground( pTable->GetBackground() );
+ else
+ pTable->getDataWindow().SetBackground();
+ }
+ break;
+
+ case BASEPROPERTY_GRID_SELECTIONMODE:
+ {
+ SelectionType eSelectionType;
+ if( aValue >>= eSelectionType )
+ {
+ SelectionMode eSelMode;
+ switch( eSelectionType )
+ {
+ case SelectionType_SINGLE: eSelMode = SelectionMode::Single; break;
+ case SelectionType_RANGE: eSelMode = SelectionMode::Range; break;
+ case SelectionType_MULTI: eSelMode = SelectionMode::Multiple; break;
+ default: eSelMode = SelectionMode::NONE; break;
+ }
+ if( pTable->getSelEngine()->GetSelectionMode() != eSelMode )
+ pTable->getSelEngine()->SetSelectionMode( eSelMode );
+ }
+ break;
+ }
+ case BASEPROPERTY_HSCROLL:
+ {
+ bool bHScroll = true;
+ if( aValue >>= bHScroll )
+ m_xTableModel->setHorizontalScrollbarVisibility( bHScroll ? ScrollbarShowAlways : ScrollbarShowSmart );
+ break;
+ }
+
+ case BASEPROPERTY_VSCROLL:
+ {
+ bool bVScroll = true;
+ if( aValue >>= bVScroll )
+ {
+ m_xTableModel->setVerticalScrollbarVisibility( bVScroll ? ScrollbarShowAlways : ScrollbarShowSmart );
+ }
+ break;
+ }
+
+ case BASEPROPERTY_GRID_SHOWROWHEADER:
+ {
+ bool rowHeader = true;
+ if( aValue >>= rowHeader )
+ {
+ m_xTableModel->setRowHeaders(rowHeader);
+ }
+ break;
+ }
+
+ case BASEPROPERTY_GRID_ROW_BACKGROUND_COLORS:
+ m_xTableModel->setRowBackgroundColors( aValue );
+ pTable->Invalidate();
+ break;
+
+ case BASEPROPERTY_GRID_LINE_COLOR:
+ m_xTableModel->setLineColor( aValue );
+ pTable->Invalidate();
+ break;
+
+ case BASEPROPERTY_GRID_HEADER_BACKGROUND:
+ m_xTableModel->setHeaderBackgroundColor( aValue );
+ pTable->Invalidate();
+ break;
+
+ case BASEPROPERTY_GRID_HEADER_TEXT_COLOR:
+ m_xTableModel->setHeaderTextColor( aValue );
+ pTable->Invalidate();
+ break;
+
+ case BASEPROPERTY_ACTIVE_SEL_BACKGROUND_COLOR:
+ m_xTableModel->setActiveSelectionBackColor( aValue );
+ pTable->Invalidate();
+ break;
+
+ case BASEPROPERTY_INACTIVE_SEL_BACKGROUND_COLOR:
+ m_xTableModel->setInactiveSelectionBackColor( aValue );
+ pTable->Invalidate();
+ break;
+
+ case BASEPROPERTY_ACTIVE_SEL_TEXT_COLOR:
+ m_xTableModel->setActiveSelectionTextColor( aValue );
+ pTable->Invalidate();
+ break;
+
+ case BASEPROPERTY_INACTIVE_SEL_TEXT_COLOR:
+ m_xTableModel->setInactiveSelectionTextColor( aValue );
+ pTable->Invalidate();
+ break;
+
+
+ case BASEPROPERTY_TEXTCOLOR:
+ m_xTableModel->setTextColor( aValue );
+ pTable->Invalidate();
+ break;
+
+ case BASEPROPERTY_TEXTLINECOLOR:
+ m_xTableModel->setTextLineColor( aValue );
+ pTable->Invalidate();
+ break;
+
+ case BASEPROPERTY_VERTICALALIGN:
+ {
+ VerticalAlignment eAlign( VerticalAlignment_TOP );
+ if ( aValue >>= eAlign )
+ m_xTableModel->setVerticalAlign( eAlign );
+ break;
+ }
+
+ case BASEPROPERTY_GRID_SHOWCOLUMNHEADER:
+ {
+ bool colHeader = true;
+ if( aValue >>= colHeader )
+ {
+ m_xTableModel->setColumnHeaders(colHeader);
+ }
+ break;
+ }
+ case BASEPROPERTY_GRID_DATAMODEL:
+ {
+ Reference< XGridDataModel > const xDataModel( aValue, UNO_QUERY );
+ if ( !xDataModel.is() )
+ throw GridInvalidDataException("Invalid data model.", *this );
+
+ m_xTableModel->setDataModel( xDataModel );
+ impl_checkTableModelInit();
+ }
+ break;
+
+ case BASEPROPERTY_GRID_COLUMNMODEL:
+ {
+ // obtain new col model
+ Reference< XGridColumnModel > const xColumnModel( aValue, UNO_QUERY );
+ if ( !xColumnModel.is() )
+ throw GridInvalidModelException("Invalid column model.", *this );
+
+ // remove all old columns
+ m_xTableModel->removeAllColumns();
+
+ // announce to the TableModel
+ m_xTableModel->setColumnModel( xColumnModel );
+ impl_checkTableModelInit();
+
+ // add new columns
+ impl_updateColumnsFromModel_nothrow();
+ break;
+ }
+ default:
+ VCLXWindow::setProperty( PropertyName, aValue );
+ break;
+ }
+}
+
+
+void SVTXGridControl::impl_checkTableModelInit()
+{
+ if ( !(!m_bTableModelInitCompleted && m_xTableModel->hasColumnModel() && m_xTableModel->hasDataModel()) )
+ return;
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ if ( !pTable )
+ return;
+
+ pTable->SetModel( PTableModel( m_xTableModel ) );
+
+ m_bTableModelInitCompleted = true;
+
+ // ensure default columns exist, if they have not previously been added
+ Reference< XGridDataModel > const xDataModel( m_xTableModel->getDataModel(), css::uno::UNO_SET_THROW );
+ Reference< XGridColumnModel > const xColumnModel( m_xTableModel->getColumnModel(), css::uno::UNO_SET_THROW );
+
+ sal_Int32 const nDataColumnCount = xDataModel->getColumnCount();
+ if ( ( nDataColumnCount > 0 ) && ( xColumnModel->getColumnCount() == 0 ) )
+ xColumnModel->setDefaultColumns( nDataColumnCount );
+ // this will trigger notifications, which in turn will let us update our m_xTableModel
+}
+
+namespace
+{
+ void lcl_convertColor( ::std::optional< ::Color > const & i_color, Any & o_colorValue )
+ {
+ if ( !i_color )
+ o_colorValue.clear();
+ else
+ o_colorValue <<= sal_Int32(*i_color);
+ }
+}
+
+Any SVTXGridControl::getProperty( const OUString& PropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN( pTable, "SVTXGridControl::getProperty: no control (anymore)!", Any() );
+
+ Any aPropertyValue;
+
+ const sal_uInt16 nPropId = GetPropertyId( PropertyName );
+ switch(nPropId)
+ {
+ case BASEPROPERTY_GRID_SELECTIONMODE:
+ {
+ SelectionType eSelectionType;
+
+ SelectionMode eSelMode = pTable->getSelEngine()->GetSelectionMode();
+ switch( eSelMode )
+ {
+ case SelectionMode::Single: eSelectionType = SelectionType_SINGLE; break;
+ case SelectionMode::Range: eSelectionType = SelectionType_RANGE; break;
+ case SelectionMode::Multiple:eSelectionType = SelectionType_MULTI; break;
+ default: eSelectionType = SelectionType_NONE; break;
+ }
+ aPropertyValue <<= eSelectionType;
+ break;
+ }
+
+ case BASEPROPERTY_GRID_SHOWROWHEADER:
+ aPropertyValue <<= m_xTableModel->hasRowHeaders();
+ break;
+
+ case BASEPROPERTY_GRID_SHOWCOLUMNHEADER:
+ aPropertyValue <<= m_xTableModel->hasColumnHeaders();
+ break;
+
+ case BASEPROPERTY_GRID_DATAMODEL:
+ aPropertyValue <<= m_xTableModel->getDataModel();
+ break;
+
+ case BASEPROPERTY_GRID_COLUMNMODEL:
+ aPropertyValue <<= m_xTableModel->getColumnModel();
+ break;
+
+ case BASEPROPERTY_HSCROLL:
+ {
+ bool const bHasScrollbar = ( m_xTableModel->getHorizontalScrollbarVisibility() != ScrollbarShowNever );
+ aPropertyValue <<= bHasScrollbar;
+ break;
+ }
+
+ case BASEPROPERTY_VSCROLL:
+ {
+ bool const bHasScrollbar = ( m_xTableModel->getVerticalScrollbarVisibility() != ScrollbarShowNever );
+ aPropertyValue <<= bHasScrollbar;
+ break;
+ }
+
+ case BASEPROPERTY_USE_GRID_LINES:
+ {
+ GridTableRenderer* pGridRenderer = dynamic_cast< GridTableRenderer* >(
+ m_xTableModel->getRenderer().get() );
+ if ( !pGridRenderer )
+ {
+ SAL_WARN( "svtools.uno", "SVTXGridControl::getProperty(UseGridLines): invalid renderer!" );
+ break;
+ }
+
+ aPropertyValue <<= pGridRenderer->useGridLines();
+ }
+ break;
+
+ case BASEPROPERTY_GRID_ROW_BACKGROUND_COLORS:
+ {
+ ::std::optional< ::std::vector< ::Color > > aColors( m_xTableModel->getRowBackgroundColors() );
+ if ( !aColors )
+ aPropertyValue.clear();
+ else
+ {
+ Sequence< css::util::Color > aAPIColors( aColors->size() );
+ std::transform(aColors->begin(), aColors->end(), aAPIColors.getArray(),
+ [](const auto& color) { return sal_Int32(color); });
+ aPropertyValue <<= aAPIColors;
+ }
+ }
+ break;
+
+ case BASEPROPERTY_GRID_LINE_COLOR:
+ lcl_convertColor( m_xTableModel->getLineColor(), aPropertyValue );
+ break;
+
+ case BASEPROPERTY_GRID_HEADER_BACKGROUND:
+ lcl_convertColor( m_xTableModel->getHeaderBackgroundColor(), aPropertyValue );
+ break;
+
+ case BASEPROPERTY_GRID_HEADER_TEXT_COLOR:
+ lcl_convertColor( m_xTableModel->getHeaderTextColor(), aPropertyValue );
+ break;
+
+ case BASEPROPERTY_ACTIVE_SEL_BACKGROUND_COLOR:
+ lcl_convertColor( m_xTableModel->getActiveSelectionBackColor(), aPropertyValue );
+ break;
+
+ case BASEPROPERTY_INACTIVE_SEL_BACKGROUND_COLOR:
+ lcl_convertColor( m_xTableModel->getInactiveSelectionBackColor(), aPropertyValue );
+ break;
+
+ case BASEPROPERTY_ACTIVE_SEL_TEXT_COLOR:
+ lcl_convertColor( m_xTableModel->getActiveSelectionTextColor(), aPropertyValue );
+ break;
+
+ case BASEPROPERTY_INACTIVE_SEL_TEXT_COLOR:
+ lcl_convertColor( m_xTableModel->getInactiveSelectionTextColor(), aPropertyValue );
+ break;
+
+ case BASEPROPERTY_TEXTCOLOR:
+ lcl_convertColor( m_xTableModel->getTextColor(), aPropertyValue );
+ break;
+
+ case BASEPROPERTY_TEXTLINECOLOR:
+ lcl_convertColor( m_xTableModel->getTextLineColor(), aPropertyValue );
+ break;
+
+ default:
+ aPropertyValue = VCLXWindow::getProperty( PropertyName );
+ break;
+ }
+
+ return aPropertyValue;
+}
+
+
+void SAL_CALL SVTXGridControl::rowsInserted( const GridDataEvent& i_event )
+{
+ SolarMutexGuard aGuard;
+ m_xTableModel->notifyRowsInserted( i_event );
+}
+
+
+void SAL_CALL
+ SVTXGridControl::rowsRemoved( const GridDataEvent& i_event )
+{
+ SolarMutexGuard aGuard;
+ m_xTableModel->notifyRowsRemoved( i_event );
+}
+
+
+void SAL_CALL SVTXGridControl::dataChanged( const GridDataEvent& i_event )
+{
+ SolarMutexGuard aGuard;
+
+ m_xTableModel->notifyDataChanged( i_event );
+
+ // if the data model is sortable, a dataChanged event is also fired in case the sort order changed.
+ // So, just in case, invalidate the column header area, too.
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN_VOID( pTable, "SVTXGridControl::dataChanged: no control (anymore)!" );
+ pTable->getTableControlInterface().invalidate( TableArea::ColumnHeaders );
+}
+
+
+void SAL_CALL SVTXGridControl::rowHeadingChanged( const GridDataEvent& )
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN_VOID( pTable, "SVTXGridControl::rowHeadingChanged: no control (anymore)!" );
+
+ // TODO: we could do better than this - invalidate the header area only
+ pTable->getTableControlInterface().invalidate( TableArea::RowHeaders );
+}
+
+
+void SAL_CALL SVTXGridControl::elementInserted( const ContainerEvent& i_event )
+{
+ SolarMutexGuard aGuard;
+
+ Reference< XGridColumn > const xGridColumn( i_event.Element, UNO_QUERY_THROW );
+
+ sal_Int32 nIndex( m_xTableModel->getColumnCount() );
+ OSL_VERIFY( i_event.Accessor >>= nIndex );
+ m_xTableModel->insertColumn( nIndex, xGridColumn );
+}
+
+
+void SAL_CALL SVTXGridControl::elementRemoved( const ContainerEvent& i_event )
+{
+ SolarMutexGuard aGuard;
+
+ sal_Int32 nIndex( -1 );
+ OSL_VERIFY( i_event.Accessor >>= nIndex );
+ m_xTableModel->removeColumn( nIndex );
+}
+
+
+void SAL_CALL SVTXGridControl::elementReplaced( const ContainerEvent& )
+{
+ OSL_ENSURE( false, "SVTXGridControl::elementReplaced: not implemented!" );
+ // at the moment, the XGridColumnModel API does not allow replacing columns
+ // TODO: replace the respective column in our table model
+}
+
+
+void SAL_CALL SVTXGridControl::disposing( const EventObject& Source )
+{
+ VCLXWindow::disposing( Source );
+}
+
+
+void SAL_CALL SVTXGridControl::selectRow( ::sal_Int32 i_rowIndex )
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN_VOID( pTable, "SVTXGridControl::selectRow: no control (anymore)!" );
+
+ impl_checkRowIndex_throw( *pTable, i_rowIndex );
+
+ pTable->SelectRow( i_rowIndex, true );
+}
+
+
+void SAL_CALL SVTXGridControl::selectAllRows()
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN_VOID( pTable, "SVTXGridControl::selectAllRows: no control (anymore)!" );
+
+ pTable->SelectAllRows( true );
+}
+
+
+void SAL_CALL SVTXGridControl::deselectRow( ::sal_Int32 i_rowIndex )
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN_VOID( pTable, "SVTXGridControl::deselectRow: no control (anymore)!" );
+
+ impl_checkRowIndex_throw( *pTable, i_rowIndex );
+
+ pTable->SelectRow( i_rowIndex, false );
+}
+
+
+void SAL_CALL SVTXGridControl::deselectAllRows()
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN_VOID( pTable, "SVTXGridControl::deselectAllRows: no control (anymore)!" );
+
+ pTable->SelectAllRows( false );
+}
+
+
+Sequence< ::sal_Int32 > SAL_CALL SVTXGridControl::getSelectedRows()
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN( pTable, "SVTXGridControl::getSelectedRows: no control (anymore)!", Sequence< sal_Int32 >() );
+
+ sal_Int32 selectionCount = pTable->GetSelectedRowCount();
+ Sequence< sal_Int32 > selectedRows( selectionCount );
+ auto selectedRowsRange = asNonConstRange(selectedRows);
+ for ( sal_Int32 i=0; i<selectionCount; ++i )
+ selectedRowsRange[i] = pTable->GetSelectedRowIndex(i);
+ return selectedRows;
+}
+
+
+sal_Bool SAL_CALL SVTXGridControl::hasSelectedRows()
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN( pTable, "SVTXGridControl::hasSelectedRows: no control (anymore)!", true );
+
+ return pTable->GetSelectedRowCount() > 0;
+}
+
+
+sal_Bool SAL_CALL SVTXGridControl::isRowSelected( ::sal_Int32 index )
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN( pTable, "SVTXGridControl::isRowSelected: no control (anymore)!", false );
+
+ return pTable->IsRowSelected( index );
+}
+
+
+void SVTXGridControl::dispose()
+{
+ EventObject aObj;
+ aObj.Source = static_cast<cppu::OWeakObject*>(this);
+ m_aSelectionListeners.disposeAndClear( aObj );
+ VCLXWindow::dispose();
+}
+
+
+void SVTXGridControl::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
+{
+ SolarMutexGuard aGuard;
+
+ Reference< XWindow > xKeepAlive( this );
+
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN_VOID( pTable, "SVTXGridControl::ProcessWindowEvent: no control (anymore)!" );
+
+ bool handled = false;
+ switch ( rVclWindowEvent.GetId() )
+ {
+ case VclEventId::TableRowSelect:
+ {
+ if ( m_aSelectionListeners.getLength() )
+ ImplCallItemListeners();
+ handled = true;
+ }
+ break;
+
+ case VclEventId::ControlGetFocus:
+ {
+ // TODO: this doesn't belong here. It belongs into the TableControl/_Impl, so A11Y also
+ // works when the control is used outside the UNO context
+ if ( pTable->GetRowCount()>0 )
+ {
+ pTable->commitCellEventIfAccessibleAlive(
+ AccessibleEventId::STATE_CHANGED,
+ Any( AccessibleStateType::FOCUSED ),
+ Any()
+ );
+ pTable->commitTableEventIfAccessibleAlive(
+ AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
+ Any(),
+ Any()
+ );
+ }
+ else
+ {
+ pTable->commitTableEventIfAccessibleAlive(
+ AccessibleEventId::STATE_CHANGED,
+ Any( AccessibleStateType::FOCUSED ),
+ Any()
+ );
+ }
+ }
+ break;
+
+ case VclEventId::ControlLoseFocus:
+ {
+ // TODO: this doesn't belong here. It belongs into the TableControl/_Impl, so A11Y also
+ // works when the control is used outside the UNO context
+ if ( pTable->GetRowCount()>0 )
+ {
+ pTable->commitCellEventIfAccessibleAlive(
+ AccessibleEventId::STATE_CHANGED,
+ Any(),
+ Any( AccessibleStateType::FOCUSED )
+ );
+ }
+ else
+ {
+ pTable->commitTableEventIfAccessibleAlive(
+ AccessibleEventId::STATE_CHANGED,
+ Any(),
+ Any( AccessibleStateType::FOCUSED )
+ );
+ }
+ }
+ break;
+
+ default: break;
+ }
+
+ if ( !handled )
+ VCLXWindow::ProcessWindowEvent( rVclWindowEvent );
+}
+
+
+void SVTXGridControl::setEnable( sal_Bool bEnable )
+{
+ SolarMutexGuard aGuard;
+
+ m_xTableModel->setEnabled( bEnable );
+ VclPtr<vcl::Window> pWindow = GetWindow();
+ if ( pWindow )
+ {
+ pWindow->Enable( bEnable );
+ pWindow->EnableInput( bEnable );
+ pWindow->Invalidate();
+ }
+}
+
+
+void SVTXGridControl::ImplCallItemListeners()
+{
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN_VOID( pTable, "SVTXGridControl::ImplCallItemListeners: no control (anymore)!" );
+
+ if ( m_aSelectionListeners.getLength() )
+ {
+ GridSelectionEvent aEvent;
+ aEvent.Source = static_cast<cppu::OWeakObject*>(this);
+
+ sal_Int32 const nSelectedRowCount( pTable->GetSelectedRowCount() );
+ aEvent.SelectedRowIndexes.realloc( nSelectedRowCount );
+ auto pSelectedRowIndexes = aEvent.SelectedRowIndexes.getArray();
+ for ( sal_Int32 i=0; i<nSelectedRowCount; ++i )
+ pSelectedRowIndexes[i] = pTable->GetSelectedRowIndex( i );
+ m_aSelectionListeners.selectionChanged( aEvent );
+ }
+}
+
+
+void SVTXGridControl::impl_updateColumnsFromModel_nothrow()
+{
+ Reference< XGridColumnModel > const xColumnModel( m_xTableModel->getColumnModel() );
+ ENSURE_OR_RETURN_VOID( xColumnModel.is(), "no model!" );
+ VclPtr< TableControl > pTable = GetAsDynamic< TableControl >();
+ ENSURE_OR_RETURN_VOID( pTable, "no table!" );
+
+ try
+ {
+ const Sequence< Reference< XGridColumn > > columns = xColumnModel->getColumns();
+ for ( auto const & colRef : columns )
+ {
+ if ( !colRef.is() )
+ {
+ SAL_WARN( "svtools.uno", "illegal column!" );
+ continue;
+ }
+
+ m_xTableModel->appendColumn( colRef );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/svtxgridcontrol.hxx b/svtools/source/uno/svtxgridcontrol.hxx
new file mode 100644
index 000000000..9e4fd85fe
--- /dev/null
+++ b/svtools/source/uno/svtxgridcontrol.hxx
@@ -0,0 +1,110 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "unocontroltablemodel.hxx"
+#include <table/tablecontrol.hxx>
+#include <com/sun/star/awt/grid/XGridControl.hpp>
+#include <com/sun/star/awt/grid/XGridRowSelection.hpp>
+#include <com/sun/star/awt/grid/XGridDataListener.hpp>
+#include <com/sun/star/awt/grid/GridDataEvent.hpp>
+#include <com/sun/star/awt/grid/XGridSelectionListener.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <toolkit/awt/vclxwindow.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <toolkit/helper/listenermultiplexer.hxx>
+
+
+namespace svt::table {
+ class TableControl;
+}
+
+typedef ::cppu::ImplInheritanceHelper < VCLXWindow
+ , css::awt::grid::XGridControl
+ , css::awt::grid::XGridRowSelection
+ , css::awt::grid::XGridDataListener
+ , css::container::XContainerListener
+ > SVTXGridControl_Base;
+class SVTXGridControl final : public SVTXGridControl_Base
+{
+public:
+ SVTXGridControl();
+ virtual ~SVTXGridControl() override;
+
+ // XGridDataListener
+ virtual void SAL_CALL rowsInserted( const css::awt::grid::GridDataEvent& Event ) override;
+ virtual void SAL_CALL rowsRemoved( const css::awt::grid::GridDataEvent& Event ) override;
+ virtual void SAL_CALL dataChanged( const css::awt::grid::GridDataEvent& Event ) override;
+ virtual void SAL_CALL rowHeadingChanged( const css::awt::grid::GridDataEvent& Event ) override;
+
+ // XContainerListener
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XGridControl
+ virtual ::sal_Int32 SAL_CALL getRowAtPoint(::sal_Int32 x, ::sal_Int32 y) override;
+ virtual ::sal_Int32 SAL_CALL getColumnAtPoint(::sal_Int32 x, ::sal_Int32 y) override;
+ virtual ::sal_Int32 SAL_CALL getCurrentColumn( ) override;
+ virtual ::sal_Int32 SAL_CALL getCurrentRow( ) override;
+ virtual void SAL_CALL goToCell( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex ) override;
+
+ // XGridRowSelection
+ virtual void SAL_CALL selectRow( ::sal_Int32 i_rowIndex ) override;
+ virtual void SAL_CALL selectAllRows() override;
+ virtual void SAL_CALL deselectRow( ::sal_Int32 i_rowIndex ) override;
+ virtual void SAL_CALL deselectAllRows() override;
+ virtual css::uno::Sequence< ::sal_Int32 > SAL_CALL getSelectedRows() override;
+ virtual sal_Bool SAL_CALL hasSelectedRows() override;
+ virtual sal_Bool SAL_CALL isRowSelected(::sal_Int32 index) override;
+ virtual void SAL_CALL addSelectionListener(const css::uno::Reference< css::awt::grid::XGridSelectionListener > & listener) override;
+ virtual void SAL_CALL removeSelectionListener(const css::uno::Reference< css::awt::grid::XGridSelectionListener > & listener) override;
+
+ void SAL_CALL setProperty( const OUString& PropertyName, const css::uno::Any& Value ) override;
+ css::uno::Any SAL_CALL getProperty( const OUString& PropertyName ) override;
+
+ // css::lang::XComponent
+ void SAL_CALL dispose( ) override;
+
+ // XWindow
+ void SAL_CALL setEnable( sal_Bool bEnable ) override;
+
+private:
+ // VCLXWindow
+ virtual void SetWindow( const VclPtr< vcl::Window > &pWindow ) override;
+
+ void impl_updateColumnsFromModel_nothrow();
+ void impl_checkTableModelInit();
+
+ void impl_checkColumnIndex_throw( ::svt::table::TableControl const & i_table, sal_Int32 const i_columnIndex ) const;
+ void impl_checkRowIndex_throw( ::svt::table::TableControl const & i_table, sal_Int32 const i_rowIndex ) const;
+
+ virtual void ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) override;
+ void ImplCallItemListeners();
+
+ std::shared_ptr< ::svt::table::UnoControlTableModel > m_xTableModel;
+ bool m_bTableModelInitCompleted;
+ SelectionListenerMultiplexer m_aSelectionListeners;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/toolboxcontroller.cxx b/svtools/source/uno/toolboxcontroller.cxx
new file mode 100644
index 000000000..21e186baf
--- /dev/null
+++ b/svtools/source/uno/toolboxcontroller.cxx
@@ -0,0 +1,802 @@
+/* -*- 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 <svtools/toolboxcontroller.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/svapp.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/weldutils.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+
+const int TOOLBARCONTROLLER_PROPHANDLE_SUPPORTSVISIBLE = 1;
+constexpr OUStringLiteral TOOLBARCONTROLLER_PROPNAME_SUPPORTSVISIBLE = u"SupportsVisible";
+
+
+using namespace ::cppu;
+using namespace css::awt;
+using namespace css::uno;
+using namespace css::util;
+using namespace css::beans;
+using namespace css::lang;
+using namespace css::frame;
+
+namespace svt
+{
+
+ToolboxController::ToolboxController(
+ const Reference< XComponentContext >& rxContext,
+ const Reference< XFrame >& xFrame,
+ const OUString& aCommandURL ) :
+ OPropertyContainer( GetBroadcastHelper() )
+ , m_bSupportVisible( false )
+ , m_bInitialized( false )
+ , m_bDisposed( false )
+ , m_bSidebar( false )
+ , m_nToolBoxId( SAL_MAX_UINT16 )
+ , m_xFrame( xFrame )
+ , m_xContext( rxContext )
+ , m_aCommandURL( aCommandURL )
+ , m_aListenerContainer( m_aMutex )
+ , m_pToolbar(nullptr)
+ , m_pBuilder(nullptr)
+{
+ OSL_ASSERT( m_xContext.is() );
+ registerProperty( TOOLBARCONTROLLER_PROPNAME_SUPPORTSVISIBLE,
+ TOOLBARCONTROLLER_PROPHANDLE_SUPPORTSVISIBLE,
+ css::beans::PropertyAttribute::TRANSIENT | css::beans::PropertyAttribute::READONLY,
+ &m_bSupportVisible, cppu::UnoType<decltype(m_bSupportVisible)>::get());
+
+ try
+ {
+ m_xUrlTransformer = URLTransformer::create( rxContext );
+ }
+ catch(const Exception&)
+ {
+ }
+}
+
+ToolboxController::ToolboxController() :
+ OPropertyContainer(GetBroadcastHelper())
+ , m_bSupportVisible(false)
+ , m_bInitialized( false )
+ , m_bDisposed( false )
+ , m_bSidebar( false )
+ , m_nToolBoxId( SAL_MAX_UINT16 )
+ , m_aListenerContainer( m_aMutex )
+ , m_pToolbar(nullptr)
+ , m_pBuilder(nullptr)
+{
+ registerProperty( TOOLBARCONTROLLER_PROPNAME_SUPPORTSVISIBLE,
+ TOOLBARCONTROLLER_PROPHANDLE_SUPPORTSVISIBLE,
+ css::beans::PropertyAttribute::TRANSIENT | css::beans::PropertyAttribute::READONLY,
+ &m_bSupportVisible, cppu::UnoType<decltype(m_bSupportVisible)>::get());
+}
+
+ToolboxController::~ToolboxController()
+{
+}
+
+Reference< XFrame > ToolboxController::getFrameInterface() const
+{
+ SolarMutexGuard aSolarMutexGuard;
+ return m_xFrame;
+}
+
+const Reference< XComponentContext > & ToolboxController::getContext() const
+{
+ SolarMutexGuard aSolarMutexGuard;
+ return m_xContext;
+}
+
+Reference< XLayoutManager > ToolboxController::getLayoutManager() const
+{
+ Reference< XLayoutManager > xLayoutManager;
+ Reference< XPropertySet > xPropSet;
+ {
+ SolarMutexGuard aSolarMutexGuard;
+ xPropSet.set( m_xFrame, UNO_QUERY );
+ }
+
+ if ( xPropSet.is() )
+ {
+ try
+ {
+ xLayoutManager.set(xPropSet->getPropertyValue("LayoutManager"),UNO_QUERY);
+ }
+ catch ( Exception& )
+ {
+ }
+ }
+
+ return xLayoutManager;
+}
+
+// XInterface
+Any SAL_CALL ToolboxController::queryInterface( const Type& rType )
+{
+ css::uno::Any a(ToolboxController_Base::queryInterface(rType));
+ return a.hasValue() ? a : OPropertyContainer::queryInterface(rType);
+}
+
+void SAL_CALL ToolboxController::acquire() noexcept
+{
+ ToolboxController_Base::acquire();
+}
+
+void SAL_CALL ToolboxController::release() noexcept
+{
+ ToolboxController_Base::release();
+}
+
+css::uno::Sequence<css::uno::Type> ToolboxController::getTypes()
+{
+ return comphelper::concatSequences(ToolboxController_Base::getTypes(),
+ getBaseTypes());
+}
+
+void SAL_CALL ToolboxController::initialize( const Sequence< Any >& aArguments )
+{
+ bool bInitialized( true );
+
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ if ( m_bDisposed )
+ throw DisposedException();
+
+ bInitialized = m_bInitialized;
+ }
+
+ if ( bInitialized )
+ return;
+
+ SolarMutexGuard aSolarMutexGuard;
+ m_bInitialized = true;
+ m_bSupportVisible = false;
+ PropertyValue aPropValue;
+ for ( const auto& rArgument : aArguments )
+ {
+ if ( rArgument >>= aPropValue )
+ {
+ if ( aPropValue.Name == "Frame" )
+ m_xFrame.set(aPropValue.Value,UNO_QUERY);
+ else if ( aPropValue.Name == "CommandURL" )
+ aPropValue.Value >>= m_aCommandURL;
+ else if ( aPropValue.Name == "ServiceManager" )
+ {
+ Reference<XMultiServiceFactory> xMSF(aPropValue.Value, UNO_QUERY);
+ if (xMSF.is())
+ m_xContext = comphelper::getComponentContext(xMSF);
+ }
+ else if ( aPropValue.Name == "ParentWindow" )
+ m_xParentWindow.set(aPropValue.Value,UNO_QUERY);
+ else if ( aPropValue.Name == "ModuleIdentifier" )
+ aPropValue.Value >>= m_sModuleName;
+ else if ( aPropValue.Name == "Identifier" )
+ {
+ sal_uInt16 nTmp;
+ if (aPropValue.Value >>= nTmp)
+ m_nToolBoxId = ToolBoxItemId(nTmp);
+ }
+ else if ( aPropValue.Name == "IsSidebar" )
+ aPropValue.Value >>= m_bSidebar;
+ }
+ }
+
+ try
+ {
+ if ( !m_xUrlTransformer.is() && m_xContext.is() )
+ m_xUrlTransformer = URLTransformer::create( m_xContext );
+ }
+ catch(const Exception&)
+ {
+ }
+
+ if ( !m_aCommandURL.isEmpty() )
+ m_aListenerMap.emplace( m_aCommandURL, Reference< XDispatch >() );
+
+ if (weld::TransportAsXWindow* pTunnel = dynamic_cast<weld::TransportAsXWindow*>(getParent().get()))
+ {
+ m_pToolbar = dynamic_cast<weld::Toolbar*>(pTunnel->getWidget());
+ assert(m_pToolbar && "must be a toolbar");
+ m_pBuilder = pTunnel->getBuilder();
+ }
+}
+
+void SAL_CALL ToolboxController::update()
+{
+ {
+ SolarMutexGuard aSolarMutexGuard;
+ if ( m_bDisposed )
+ throw DisposedException();
+ }
+
+ // Bind all registered listeners to their dispatch objects
+ bindListener();
+}
+
+// XComponent
+void SAL_CALL ToolboxController::dispose()
+{
+ Reference< XComponent > xThis(this);
+
+ {
+ SolarMutexGuard aSolarMutexGuard;
+ if ( m_bDisposed )
+ throw DisposedException();
+ }
+
+ css::lang::EventObject aEvent( xThis );
+ m_aListenerContainer.disposeAndClear( aEvent );
+
+ SolarMutexGuard aSolarMutexGuard;
+ Reference< XStatusListener > xStatusListener(this);
+ for (auto const& listener : m_aListenerMap)
+ {
+ try
+ {
+ Reference< XDispatch > xDispatch( listener.second );
+
+ css::util::URL aTargetURL;
+ aTargetURL.Complete = listener.first;
+ if ( m_xUrlTransformer.is() )
+ m_xUrlTransformer->parseStrict( aTargetURL );
+
+ if ( xDispatch.is() && xStatusListener.is() )
+ xDispatch->removeStatusListener( xStatusListener, aTargetURL );
+ }
+ catch ( Exception& )
+ {
+ }
+
+ }
+
+ m_bDisposed = true;
+}
+
+void SAL_CALL ToolboxController::addEventListener( const Reference< XEventListener >& xListener )
+{
+ m_aListenerContainer.addInterface( cppu::UnoType<XEventListener>::get(), xListener );
+}
+
+void SAL_CALL ToolboxController::removeEventListener( const Reference< XEventListener >& aListener )
+{
+ m_aListenerContainer.removeInterface( cppu::UnoType<XEventListener>::get(), aListener );
+}
+
+// XEventListener
+void SAL_CALL ToolboxController::disposing( const EventObject& Source )
+{
+ Reference< XInterface > xSource( Source.Source );
+
+ SolarMutexGuard aSolarMutexGuard;
+
+ if ( m_bDisposed )
+ return;
+
+ for (auto & listener : m_aListenerMap)
+ {
+ // Compare references and release dispatch references if they are equal.
+ Reference< XInterface > xIfac(listener.second, UNO_QUERY);
+ if ( xSource == xIfac )
+ listener.second.clear();
+ }
+
+ Reference< XInterface > xIfac( m_xFrame, UNO_QUERY );
+ if ( xIfac == xSource )
+ m_xFrame.clear();
+}
+
+// XStatusListener
+void SAL_CALL ToolboxController::statusChanged( const FeatureStateEvent& )
+{
+ // must be implemented by sub class
+}
+
+// XToolbarController
+void SAL_CALL ToolboxController::execute( sal_Int16 KeyModifier )
+{
+ Reference< XDispatch > xDispatch;
+ OUString aCommandURL;
+
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ if ( m_bDisposed )
+ throw DisposedException();
+
+ if ( m_bInitialized &&
+ m_xFrame.is() &&
+ !m_aCommandURL.isEmpty() )
+ {
+ aCommandURL = m_aCommandURL;
+ URLToDispatchMap::iterator pIter = m_aListenerMap.find( m_aCommandURL );
+ if ( pIter != m_aListenerMap.end() )
+ xDispatch = pIter->second;
+ }
+ }
+
+ if ( !xDispatch.is() )
+ return;
+
+ try
+ {
+ css::util::URL aTargetURL;
+
+ // Provide key modifier information to dispatch function
+ Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("KeyModifier", KeyModifier) };
+
+ aTargetURL.Complete = aCommandURL;
+ if ( m_xUrlTransformer.is() )
+ m_xUrlTransformer->parseStrict( aTargetURL );
+ xDispatch->dispatch( aTargetURL, aArgs );
+ }
+ catch ( DisposedException& )
+ {
+ }
+}
+
+void SAL_CALL ToolboxController::click()
+{
+}
+
+void SAL_CALL ToolboxController::doubleClick()
+{
+}
+
+Reference< XWindow > SAL_CALL ToolboxController::createPopupWindow()
+{
+ return Reference< XWindow >();
+}
+
+Reference< XWindow > SAL_CALL ToolboxController::createItemWindow( const Reference< XWindow >& )
+{
+ return Reference< XWindow >();
+}
+
+void ToolboxController::addStatusListener( const OUString& aCommandURL )
+{
+ Reference< XDispatch > xDispatch;
+ Reference< XStatusListener > xStatusListener;
+ css::util::URL aTargetURL;
+
+ {
+ SolarMutexGuard aSolarMutexGuard;
+ URLToDispatchMap::iterator pIter = m_aListenerMap.find( aCommandURL );
+
+ // Already in the list of status listener. Do nothing.
+ if ( pIter != m_aListenerMap.end() )
+ return;
+
+ // Check if we are already initialized. Implementation starts adding itself as status listener when
+ // initialize is called.
+ if ( !m_bInitialized )
+ {
+ // Put into the unordered_map of status listener. Will be activated when initialized is called
+ m_aListenerMap.emplace( aCommandURL, Reference< XDispatch >() );
+ return;
+ }
+ else
+ {
+ // Add status listener directly as initialize has already been called.
+ Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
+ if ( m_xContext.is() && xDispatchProvider.is() )
+ {
+ aTargetURL.Complete = aCommandURL;
+ if ( m_xUrlTransformer.is() )
+ m_xUrlTransformer->parseStrict( aTargetURL );
+ xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
+
+ xStatusListener = this;
+ URLToDispatchMap::iterator aIter = m_aListenerMap.find( aCommandURL );
+ if ( aIter != m_aListenerMap.end() )
+ {
+ Reference< XDispatch > xOldDispatch( aIter->second );
+ aIter->second = xDispatch;
+
+ try
+ {
+ if ( xOldDispatch.is() )
+ xOldDispatch->removeStatusListener( xStatusListener, aTargetURL );
+ }
+ catch ( Exception& )
+ {
+ }
+ }
+ else
+ m_aListenerMap.emplace( aCommandURL, xDispatch );
+ }
+ }
+ }
+
+ // Call without locked mutex as we are called back from dispatch implementation
+ try
+ {
+ if ( xDispatch.is() )
+ xDispatch->addStatusListener( xStatusListener, aTargetURL );
+ }
+ catch ( Exception& )
+ {
+ }
+}
+
+void ToolboxController::removeStatusListener( const OUString& aCommandURL )
+{
+ SolarMutexGuard aSolarMutexGuard;
+
+ URLToDispatchMap::iterator pIter = m_aListenerMap.find( aCommandURL );
+ if ( pIter == m_aListenerMap.end() )
+ return;
+
+ Reference< XDispatch > xDispatch( pIter->second );
+ Reference< XStatusListener > xStatusListener(this);
+ m_aListenerMap.erase( pIter );
+
+ try
+ {
+ css::util::URL aTargetURL;
+ aTargetURL.Complete = aCommandURL;
+ if ( m_xUrlTransformer.is() )
+ m_xUrlTransformer->parseStrict( aTargetURL );
+
+ if ( xDispatch.is() && xStatusListener.is() )
+ xDispatch->removeStatusListener( xStatusListener, aTargetURL );
+ }
+ catch ( Exception& )
+ {
+ }
+}
+
+void ToolboxController::bindListener()
+{
+ std::vector< Listener > aDispatchVector;
+ Reference< XStatusListener > xStatusListener;
+
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ if ( !m_bInitialized )
+ return;
+
+ // Collect all registered command URL's and store them temporary
+ Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
+ if ( m_xContext.is() && xDispatchProvider.is() )
+ {
+ xStatusListener = this;
+ for (auto & listener : m_aListenerMap)
+ {
+ css::util::URL aTargetURL;
+ aTargetURL.Complete = listener.first;
+ if ( m_xUrlTransformer.is() )
+ m_xUrlTransformer->parseStrict( aTargetURL );
+
+ Reference< XDispatch > xDispatch(listener.second);
+ if ( xDispatch.is() )
+ {
+ // We already have a dispatch object => we have to requery.
+ // Release old dispatch object and remove it as listener
+ try
+ {
+ xDispatch->removeStatusListener( xStatusListener, aTargetURL );
+ }
+ catch ( Exception& )
+ {
+ }
+ }
+
+ listener.second.clear();
+ xDispatch.clear();
+
+ // Query for dispatch object. Old dispatch will be released with this, too.
+ try
+ {
+ xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
+ }
+ catch ( Exception& )
+ {
+ }
+
+ // it may be a command alias
+ if (!xDispatch.is())
+ {
+ try
+ {
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(listener.first,
+ vcl::CommandInfoProvider::GetModuleIdentifier(m_xFrame));
+ OUString sRealCommand = vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties);
+
+ if (!sRealCommand.isEmpty())
+ {
+ aTargetURL.Complete = sRealCommand;
+ if ( m_xUrlTransformer.is() )
+ m_xUrlTransformer->parseStrict( aTargetURL );
+
+ xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
+ }
+ }
+ catch ( Exception& )
+ {
+ }
+ }
+
+ listener.second = xDispatch;
+
+ Listener aListener( aTargetURL, xDispatch );
+ aDispatchVector.push_back( aListener );
+ }
+ }
+ }
+
+ // Call without locked mutex as we are called back from dispatch implementation
+ if ( !xStatusListener.is() )
+ return;
+
+ try
+ {
+ for (Listener & rListener : aDispatchVector)
+ {
+ if ( rListener.xDispatch.is() )
+ rListener.xDispatch->addStatusListener( xStatusListener, rListener.aURL );
+ else if ( rListener.aURL.Complete == m_aCommandURL )
+ {
+ try
+ {
+ // Send status changed for the main URL, if we cannot get a valid dispatch object.
+ // UI disables the button. Catch exception as we release our mutex, it is possible
+ // that someone else already disposed this instance!
+ FeatureStateEvent aFeatureStateEvent;
+ aFeatureStateEvent.IsEnabled = false;
+ aFeatureStateEvent.FeatureURL = rListener.aURL;
+ aFeatureStateEvent.State = Any();
+ xStatusListener->statusChanged( aFeatureStateEvent );
+ }
+ catch ( Exception& )
+ {
+ }
+ }
+ }
+ }
+ catch ( Exception& )
+ {
+ }
+}
+
+void ToolboxController::unbindListener()
+{
+ SolarMutexGuard aSolarMutexGuard;
+
+ if ( !m_bInitialized )
+ return;
+
+ // Collect all registered command URL's and store them temporary
+ Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
+ if ( !(m_xContext.is() && xDispatchProvider.is()) )
+ return;
+
+ Reference< XStatusListener > xStatusListener(this);
+ for (auto & listener : m_aListenerMap)
+ {
+ css::util::URL aTargetURL;
+ aTargetURL.Complete = listener.first;
+ if ( m_xUrlTransformer.is() )
+ m_xUrlTransformer->parseStrict( aTargetURL );
+
+ Reference< XDispatch > xDispatch(listener.second);
+ if ( xDispatch.is() )
+ {
+ // We already have a dispatch object => we have to requery.
+ // Release old dispatch object and remove it as listener
+ try
+ {
+ xDispatch->removeStatusListener( xStatusListener, aTargetURL );
+ }
+ catch ( Exception& )
+ {
+ }
+ }
+ listener.second.clear();
+ }
+}
+
+void ToolboxController::updateStatus()
+{
+ bindListener();
+}
+
+void ToolboxController::updateStatus( const OUString& aCommandURL )
+{
+ Reference< XDispatch > xDispatch;
+ Reference< XStatusListener > xStatusListener;
+ css::util::URL aTargetURL;
+
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ if ( !m_bInitialized )
+ return;
+
+ // Try to find a dispatch object for the requested command URL
+ Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
+ xStatusListener = this;
+ if ( m_xContext.is() && xDispatchProvider.is() )
+ {
+ aTargetURL.Complete = aCommandURL;
+ if ( m_xUrlTransformer.is() )
+ m_xUrlTransformer->parseStrict( aTargetURL );
+ xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
+ }
+ }
+
+ if ( !(xDispatch.is() && xStatusListener.is()) )
+ return;
+
+ // Catch exception as we release our mutex, it is possible that someone else
+ // has already disposed this instance!
+ // Add/remove status listener to get an update status information from the
+ // requested command.
+ try
+ {
+ xDispatch->addStatusListener( xStatusListener, aTargetURL );
+ xDispatch->removeStatusListener( xStatusListener, aTargetURL );
+ }
+ catch ( Exception& )
+ {
+ }
+}
+
+
+void ToolboxController::dispatchCommand( const OUString& sCommandURL, const Sequence< PropertyValue >& rArgs, const OUString &sTarget )
+{
+ try
+ {
+ Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY_THROW );
+ URL aURL;
+ aURL.Complete = sCommandURL;
+ getURLTransformer()->parseStrict( aURL );
+
+ Reference< XDispatch > xDispatch( xDispatchProvider->queryDispatch( aURL, sTarget, 0 ), UNO_SET_THROW );
+
+ std::unique_ptr<DispatchInfo> pDispatchInfo(new DispatchInfo( xDispatch, aURL, rArgs ));
+ if ( Application::PostUserEvent( LINK(nullptr, ToolboxController, ExecuteHdl_Impl),
+ pDispatchInfo.get() ) )
+ pDispatchInfo.release();
+
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL ToolboxController::getPropertySetInfo()
+{
+ Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+
+::cppu::IPropertyArrayHelper& ToolboxController::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+
+::cppu::IPropertyArrayHelper* ToolboxController::createArrayHelper( ) const
+{
+ css::uno::Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+sal_Bool SAL_CALL ToolboxController::convertFastPropertyValue( css::uno::Any& aConvertedValue ,
+ css::uno::Any& aOldValue ,
+ sal_Int32 nHandle ,
+ const css::uno::Any& aValue )
+{
+ switch (nHandle)
+ {
+ case TOOLBARCONTROLLER_PROPHANDLE_SUPPORTSVISIBLE:
+ {
+ bool aNewValue(false);
+ aValue >>= aNewValue;
+ if (aNewValue != m_bSupportVisible)
+ {
+ aConvertedValue <<= aNewValue;
+ aOldValue <<= m_bSupportVisible;
+ return true;
+ }
+ return false;
+ }
+ }
+ return OPropertyContainer::convertFastPropertyValue(aConvertedValue, aOldValue, nHandle, aValue);
+}
+
+void SAL_CALL ToolboxController::setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& aValue )
+{
+ OPropertyContainer::setFastPropertyValue_NoBroadcast(nHandle, aValue);
+ if (TOOLBARCONTROLLER_PROPHANDLE_SUPPORTSVISIBLE == nHandle)
+ {
+ bool rValue(false);
+ if (( aValue >>= rValue ) && m_bInitialized)
+ m_bSupportVisible = rValue;
+ }
+}
+
+
+IMPL_STATIC_LINK( ToolboxController, ExecuteHdl_Impl, void*, p, void )
+{
+ DispatchInfo* pDispatchInfo = static_cast<DispatchInfo*>(p);
+ pDispatchInfo->mxDispatch->dispatch( pDispatchInfo->maURL, pDispatchInfo->maArgs );
+ delete pDispatchInfo;
+}
+
+void ToolboxController::enable( bool bEnable )
+{
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nItemId;
+ if( getToolboxId( nItemId, &pToolBox ) )
+ {
+ pToolBox->EnableItem( nItemId, bEnable );
+ }
+}
+
+bool ToolboxController::getToolboxId( ToolBoxItemId& rItemId, ToolBox** ppToolBox )
+{
+ if( (m_nToolBoxId != ToolBoxItemId(SAL_MAX_UINT16)) && (ppToolBox == nullptr) )
+ return false;
+
+ ToolBox* pToolBox = static_cast< ToolBox* >( VCLUnoHelper::GetWindow( getParent() ) );
+
+ if( (m_nToolBoxId == ToolBoxItemId(SAL_MAX_UINT16)) && pToolBox )
+ {
+ const ToolBox::ImplToolItems::size_type nCount = pToolBox->GetItemCount();
+ for ( ToolBox::ImplToolItems::size_type nPos = 0; nPos < nCount; ++nPos )
+ {
+ const ToolBoxItemId nItemId = pToolBox->GetItemId( nPos );
+ if ( pToolBox->GetItemCommand( nItemId ) == m_aCommandURL )
+ {
+ m_nToolBoxId = nItemId;
+ break;
+ }
+ }
+ }
+
+ if( ppToolBox )
+ *ppToolBox = pToolBox;
+
+ rItemId = m_nToolBoxId;
+
+ return (rItemId != ToolBoxItemId(SAL_MAX_UINT16)) && (( ppToolBox == nullptr) || (*ppToolBox != nullptr) );
+}
+//end
+
+} // svt
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/unocontroltablemodel.cxx b/svtools/source/uno/unocontroltablemodel.cxx
new file mode 100644
index 000000000..14f9c6977
--- /dev/null
+++ b/svtools/source/uno/unocontroltablemodel.cxx
@@ -0,0 +1,835 @@
+/* -*- 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 "unocontroltablemodel.hxx"
+#include "unogridcolumnfacade.hxx"
+
+#include <table/defaultinputhandler.hxx>
+#include <table/gridtablerenderer.hxx>
+
+#include <com/sun/star/awt/grid/XSortableGridData.hpp>
+#include <com/sun/star/util/Color.hpp>
+#include <o3tl/safeint.hxx>
+#include <sal/log.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+
+namespace svt::table
+{
+
+
+ using css::uno::Reference;
+ using css::uno::Sequence;
+ using css::uno::UNO_QUERY_THROW;
+ using css::uno::UNO_QUERY;
+ using css::awt::grid::XGridColumn;
+ using css::uno::Exception;
+ using css::awt::grid::XGridDataModel;
+ using css::awt::grid::XGridColumnModel;
+ using css::uno::Any;
+ using css::style::VerticalAlignment_TOP;
+ using css::style::VerticalAlignment;
+ using css::uno::WeakReference;
+ using css::awt::grid::GridDataEvent;
+ using css::awt::grid::XSortableGridData;
+ using css::beans::Pair;
+
+
+ //= UnoControlTableModel
+#define DBG_CHECK_ME() \
+ DBG_TESTSOLARMUTEX(); \
+
+ UnoControlTableModel::UnoControlTableModel()
+ :aColumns ( )
+ ,bHasColumnHeaders ( true )
+ ,bHasRowHeaders ( false )
+ ,eVScrollMode ( ScrollbarShowNever )
+ ,eHScrollMode ( ScrollbarShowNever )
+ ,pRenderer ( )
+ ,pInputHandler ( )
+ ,nRowHeight ( 10 )
+ ,nColumnHeaderHeight ( 10 )
+ ,nRowHeaderWidth ( 10 )
+ ,m_aGridLineColor ( )
+ ,m_aHeaderBackgroundColor ( )
+ ,m_aHeaderTextColor ( )
+ ,m_aActiveSelectionBackColor ( )
+ ,m_aInactiveSelectionBackColor ( )
+ ,m_aActiveSelectionTextColor ( )
+ ,m_aInactiveSelectionTextColor ( )
+ ,m_aTextColor ( )
+ ,m_aTextLineColor ( )
+ ,m_aRowColors ( )
+ ,m_eVerticalAlign ( VerticalAlignment_TOP )
+ ,bEnabled ( true )
+ {
+ pRenderer = std::make_shared<GridTableRenderer>( *this );
+ pInputHandler = std::make_shared<DefaultInputHandler>();
+ }
+
+
+ UnoControlTableModel::~UnoControlTableModel()
+ {
+ }
+
+
+ TableSize UnoControlTableModel::getColumnCount() const
+ {
+ DBG_CHECK_ME();
+ return static_cast<TableSize>(aColumns.size());
+ }
+
+
+ TableSize UnoControlTableModel::getRowCount() const
+ {
+ DBG_CHECK_ME();
+
+ TableSize nRowCount = 0;
+ try
+ {
+ Reference< XGridDataModel > const xDataModel( m_aDataModel );
+ ENSURE_OR_THROW( xDataModel.is(), "no data model anymore!" );
+ nRowCount = xDataModel->getRowCount();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+ return nRowCount;
+ }
+
+
+ bool UnoControlTableModel::hasColumnHeaders() const
+ {
+ DBG_CHECK_ME();
+ return bHasColumnHeaders;
+ }
+
+
+ bool UnoControlTableModel::hasRowHeaders() const
+ {
+ DBG_CHECK_ME();
+ return bHasRowHeaders;
+ }
+
+
+ void UnoControlTableModel::setRowHeaders(bool _bRowHeaders)
+ {
+ DBG_CHECK_ME();
+ if ( bHasRowHeaders == _bRowHeaders )
+ return;
+
+ bHasRowHeaders = _bRowHeaders;
+ impl_notifyTableMetricsChanged();
+ }
+
+
+ void UnoControlTableModel::setColumnHeaders(bool _bColumnHeaders)
+ {
+ DBG_CHECK_ME();
+ if ( bHasColumnHeaders == _bColumnHeaders )
+ return;
+
+ bHasColumnHeaders = _bColumnHeaders;
+ impl_notifyTableMetricsChanged();
+ }
+
+
+ PColumnModel UnoControlTableModel::getColumnModel( ColPos column )
+ {
+ DBG_CHECK_ME();
+ ENSURE_OR_RETURN( ( column >= 0 ) && ( column < getColumnCount() ),
+ "DefaultTableModel::getColumnModel: invalid index!", PColumnModel() );
+ return aColumns[ column ];
+ }
+
+
+ void UnoControlTableModel::appendColumn( Reference< XGridColumn > const & i_column )
+ {
+ DBG_CHECK_ME();
+ insertColumn( aColumns.size(), i_column );
+ }
+
+
+ void UnoControlTableModel::insertColumn( ColPos const i_position, Reference< XGridColumn > const & i_column )
+ {
+ DBG_CHECK_ME();
+ ENSURE_OR_RETURN_VOID( ( i_position >= 0 ) && ( o3tl::make_unsigned( i_position ) <= aColumns.size() ),
+ "UnoControlTableModel::insertColumn: illegal position!" );
+
+ const PColumnModel pColumn = std::make_shared<UnoGridColumnFacade>( *this, i_column );
+ aColumns.insert( aColumns.begin() + i_position, pColumn );
+
+ // notify listeners
+ ModellListeners aListeners( m_aListeners );
+ for (auto const& listener : aListeners)
+ {
+ listener->columnInserted();
+ }
+ }
+
+
+ void UnoControlTableModel::removeColumn( ColPos const i_position )
+ {
+ DBG_CHECK_ME();
+ ENSURE_OR_RETURN_VOID( ( i_position >= 0 ) && ( o3tl::make_unsigned( i_position ) <= aColumns.size() ),
+ "UnoControlTableModel::removeColumn: illegal position!" );
+
+ // remove the column
+ ColumnModels::iterator pos = aColumns.begin() + i_position;
+ const PColumnModel pColumn = *pos;
+ aColumns.erase( pos );
+
+ // notify listeners
+ ModellListeners aListeners( m_aListeners );
+ for (auto const& listener : aListeners)
+ {
+ listener->columnRemoved();
+ }
+
+ // dispose the column
+ UnoGridColumnFacade* pColumnImpl = dynamic_cast< UnoGridColumnFacade* >( pColumn.get() );
+ OSL_ENSURE( pColumnImpl != nullptr, "UnoControlTableModel::removeColumn: illegal column implementation!" );
+ if ( pColumnImpl )
+ pColumnImpl->dispose();
+ }
+
+
+ void UnoControlTableModel::removeAllColumns()
+ {
+ DBG_CHECK_ME();
+ if ( aColumns.empty() )
+ return;
+
+ // dispose the column instances
+ for (auto const& col : aColumns)
+ {
+ UnoGridColumnFacade* pColumn = dynamic_cast< UnoGridColumnFacade* >( col.get() );
+ if ( !pColumn )
+ {
+ SAL_WARN( "svtools.uno", "UnoControlTableModel::removeAllColumns: illegal column implementation!" );
+ continue;
+ }
+
+ pColumn->dispose();
+ }
+ aColumns.clear();
+
+ // notify listeners
+ ModellListeners aListeners( m_aListeners );
+ for (auto const& listener : aListeners)
+ {
+ listener->allColumnsRemoved();
+ }
+ }
+
+
+ void UnoControlTableModel::impl_notifyTableMetricsChanged() const
+ {
+ ModellListeners aListeners( m_aListeners );
+ for (auto const& listener : aListeners)
+ {
+ listener->tableMetricsChanged();
+ }
+ }
+
+
+ PTableRenderer UnoControlTableModel::getRenderer() const
+ {
+ DBG_CHECK_ME();
+ return pRenderer;
+ }
+
+
+ PTableInputHandler UnoControlTableModel::getInputHandler() const
+ {
+ DBG_CHECK_ME();
+ return pInputHandler;
+ }
+
+
+ TableMetrics UnoControlTableModel::getRowHeight() const
+ {
+ DBG_CHECK_ME();
+ return nRowHeight;
+ }
+
+
+ void UnoControlTableModel::setRowHeight(TableMetrics _nRowHeight)
+ {
+ DBG_CHECK_ME();
+ if ( nRowHeight == _nRowHeight )
+ return;
+
+ nRowHeight = _nRowHeight;
+ impl_notifyTableMetricsChanged();
+ }
+
+
+ TableMetrics UnoControlTableModel::getColumnHeaderHeight() const
+ {
+ DBG_CHECK_ME();
+ DBG_ASSERT( hasColumnHeaders(), "DefaultTableModel::getColumnHeaderHeight: invalid call!" );
+ return nColumnHeaderHeight;
+ }
+
+
+ TableMetrics UnoControlTableModel::getRowHeaderWidth() const
+ {
+ DBG_CHECK_ME();
+ DBG_ASSERT( hasRowHeaders(), "DefaultTableModel::getRowHeaderWidth: invalid call!" );
+ return nRowHeaderWidth;
+ }
+
+ void UnoControlTableModel::setColumnHeaderHeight(TableMetrics _nHeight)
+ {
+ DBG_CHECK_ME();
+ if ( nColumnHeaderHeight == _nHeight )
+ return;
+
+ nColumnHeaderHeight = _nHeight;
+ impl_notifyTableMetricsChanged();
+ }
+
+
+ void UnoControlTableModel::setRowHeaderWidth(TableMetrics _nWidth)
+ {
+ DBG_CHECK_ME();
+ if ( nRowHeaderWidth == _nWidth )
+ return;
+
+ nRowHeaderWidth = _nWidth;
+ impl_notifyTableMetricsChanged();
+ }
+
+
+ ScrollbarVisibility UnoControlTableModel::getVerticalScrollbarVisibility() const
+ {
+ DBG_CHECK_ME();
+ return eVScrollMode;
+ }
+
+
+ ScrollbarVisibility UnoControlTableModel::getHorizontalScrollbarVisibility() const
+ {
+ DBG_CHECK_ME();
+ return eHScrollMode;
+ }
+
+
+ void UnoControlTableModel::addTableModelListener( const PTableModelListener& i_listener )
+ {
+ DBG_CHECK_ME();
+ ENSURE_OR_RETURN_VOID( !!i_listener, "illegal NULL listener" );
+ m_aListeners.push_back( i_listener );
+ }
+
+
+ void UnoControlTableModel::removeTableModelListener( const PTableModelListener& i_listener )
+ {
+ DBG_CHECK_ME();
+ auto lookup = std::find(m_aListeners.begin(), m_aListeners.end(), i_listener);
+ if (lookup != m_aListeners.end())
+ {
+ m_aListeners.erase( lookup );
+ return;
+ }
+ OSL_ENSURE( false, "UnoControlTableModel::removeTableModelListener: listener is not registered - sure you're doing the right thing here?" );
+ }
+
+
+ void UnoControlTableModel::setVerticalScrollbarVisibility( ScrollbarVisibility const i_visibility )
+ {
+ DBG_CHECK_ME();
+ eVScrollMode = i_visibility;
+ }
+
+
+ void UnoControlTableModel::setHorizontalScrollbarVisibility( ScrollbarVisibility const i_visibility )
+ {
+ DBG_CHECK_ME();
+ eHScrollMode = i_visibility;
+ }
+
+
+ void UnoControlTableModel::setDataModel( Reference< XGridDataModel > const & i_gridDataModel )
+ {
+ DBG_CHECK_ME();
+ m_aDataModel = i_gridDataModel;
+ // TODO: register as listener, so we're notified of row/data changes, and can multiplex them to our
+ // own listeners
+ }
+
+
+ Reference< XGridDataModel > UnoControlTableModel::getDataModel() const
+ {
+ Reference< XGridDataModel > const xDataModel( m_aDataModel );
+ return xDataModel;
+ }
+
+
+ bool UnoControlTableModel::hasDataModel() const
+ {
+ return getDataModel().is();
+ }
+
+
+ void UnoControlTableModel::setColumnModel( Reference< XGridColumnModel > const & i_gridColumnModel )
+ {
+ DBG_CHECK_ME();
+ m_aColumnModel = i_gridColumnModel;
+ }
+
+
+ Reference< XGridColumnModel > UnoControlTableModel::getColumnModel() const
+ {
+ Reference< XGridColumnModel > const xColumnModel( m_aColumnModel );
+ return xColumnModel;
+ }
+
+
+ bool UnoControlTableModel::hasColumnModel() const
+ {
+ return getColumnModel().is();
+ }
+
+
+ void UnoControlTableModel::getCellContent( ColPos const i_col, RowPos const i_row, Any& o_cellContent )
+ {
+ DBG_CHECK_ME();
+
+ o_cellContent.clear();
+ try
+ {
+ Reference< XGridDataModel > const xDataModel( m_aDataModel );
+ ENSURE_OR_RETURN_VOID( xDataModel.is(), "UnoControlTableModel::getCellContent: no data model anymore!" );
+
+ PColumnModel const pColumn = getColumnModel( i_col );
+ UnoGridColumnFacade* pColumnImpl = dynamic_cast< UnoGridColumnFacade* >( pColumn.get() );
+ ENSURE_OR_RETURN_VOID( pColumnImpl != nullptr, "UnoControlTableModel::getCellContent: no (valid) column at this position!" );
+ sal_Int32 const nDataColumnIndex = pColumnImpl->getDataColumnIndex() >= 0 ? pColumnImpl->getDataColumnIndex() : i_col;
+
+ if ( nDataColumnIndex >= xDataModel->getColumnCount() )
+ {
+ // this is allowed, in case the column model has been dynamically extended, but the data model does
+ // not (yet?) know about it.
+ // So, handle it gracefully.
+ #if OSL_DEBUG_LEVEL > 0
+ Reference< XGridColumnModel > const xColumnModel( m_aColumnModel );
+ OSL_ENSURE( xColumnModel.is() && i_col < xColumnModel->getColumnCount(),
+ "UnoControlTableModel::getCellContent: request a column's value which the ColumnModel doesn't know about!" );
+ #endif
+ }
+ else
+ {
+ o_cellContent = xDataModel->getCellData( nDataColumnIndex, i_row );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+ }
+
+
+ void UnoControlTableModel::getCellToolTip( ColPos const i_col, RowPos const i_row, Any& o_cellToolTip )
+ {
+ DBG_CHECK_ME();
+ try
+ {
+ Reference< XGridDataModel > const xDataModel( m_aDataModel );
+ ENSURE_OR_THROW( xDataModel.is(), "no data model anymore!" );
+
+ o_cellToolTip = xDataModel->getCellToolTip( i_col, i_row );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+ }
+
+
+ Any UnoControlTableModel::getRowHeading( RowPos const i_rowPos ) const
+ {
+ DBG_CHECK_ME();
+
+ Any aRowHeading;
+
+ Reference< XGridDataModel > const xDataModel( m_aDataModel );
+ ENSURE_OR_RETURN( xDataModel.is(), "UnoControlTableModel::getRowHeading: no data model anymore!", aRowHeading );
+
+ try
+ {
+ aRowHeading = xDataModel->getRowHeading( i_rowPos );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+ return aRowHeading;
+ }
+
+
+ namespace
+ {
+ void lcl_setColor( Any const & i_color, ::std::optional< ::Color > & o_convertedColor )
+ {
+ if ( !i_color.hasValue() )
+ o_convertedColor.reset();
+ else
+ {
+ Color nColor = COL_TRANSPARENT;
+ if ( i_color >>= nColor )
+ {
+ o_convertedColor = nColor;
+ }
+ else
+ {
+ OSL_ENSURE( false, "lcl_setColor: could not extract color value!" );
+ }
+ }
+ }
+ }
+
+
+ ::std::optional< ::Color > UnoControlTableModel::getLineColor() const
+ {
+ DBG_CHECK_ME();
+ return m_aGridLineColor;
+ }
+
+
+ void UnoControlTableModel::setLineColor( Any const & i_color )
+ {
+ DBG_CHECK_ME();
+ lcl_setColor( i_color, m_aGridLineColor );
+ }
+
+
+ ::std::optional< ::Color > UnoControlTableModel::getHeaderBackgroundColor() const
+ {
+ DBG_CHECK_ME();
+ return m_aHeaderBackgroundColor;
+ }
+
+
+ void UnoControlTableModel::setHeaderBackgroundColor( Any const & i_color )
+ {
+ DBG_CHECK_ME();
+ lcl_setColor( i_color, m_aHeaderBackgroundColor );
+ }
+
+
+ ::std::optional< ::Color > UnoControlTableModel::getHeaderTextColor() const
+ {
+ DBG_CHECK_ME();
+ return m_aHeaderTextColor;
+ }
+
+
+ ::std::optional< ::Color > UnoControlTableModel::getActiveSelectionBackColor() const
+ {
+ DBG_CHECK_ME();
+ return m_aActiveSelectionBackColor;
+ }
+
+
+ ::std::optional< ::Color > UnoControlTableModel::getInactiveSelectionBackColor() const
+ {
+ DBG_CHECK_ME();
+ return m_aInactiveSelectionBackColor;
+ }
+
+
+ ::std::optional< ::Color > UnoControlTableModel::getActiveSelectionTextColor() const
+ {
+ DBG_CHECK_ME();
+ return m_aActiveSelectionTextColor;
+ }
+
+
+ ::std::optional< ::Color > UnoControlTableModel::getInactiveSelectionTextColor() const
+ {
+ DBG_CHECK_ME();
+ return m_aInactiveSelectionTextColor;
+ }
+
+
+ void UnoControlTableModel::setHeaderTextColor( Any const & i_color )
+ {
+ DBG_CHECK_ME();
+ lcl_setColor( i_color, m_aHeaderTextColor );
+ }
+
+
+ void UnoControlTableModel::setActiveSelectionBackColor( Any const & i_color )
+ {
+ DBG_CHECK_ME();
+ lcl_setColor( i_color, m_aActiveSelectionBackColor );
+ }
+
+
+ void UnoControlTableModel::setInactiveSelectionBackColor( Any const & i_color )
+ {
+ DBG_CHECK_ME();
+ lcl_setColor( i_color, m_aInactiveSelectionBackColor );
+ }
+
+
+ void UnoControlTableModel::setActiveSelectionTextColor( Any const & i_color )
+ {
+ DBG_CHECK_ME();
+ lcl_setColor( i_color, m_aActiveSelectionTextColor );
+ }
+
+
+ void UnoControlTableModel::setInactiveSelectionTextColor( Any const & i_color )
+ {
+ DBG_CHECK_ME();
+ lcl_setColor( i_color, m_aInactiveSelectionTextColor );
+ }
+
+
+ ::std::optional< ::Color > UnoControlTableModel::getTextColor() const
+ {
+ DBG_CHECK_ME();
+ return m_aTextColor;
+ }
+
+
+ void UnoControlTableModel::setTextColor( Any const & i_color )
+ {
+ DBG_CHECK_ME();
+ lcl_setColor( i_color, m_aTextColor );
+ }
+
+
+ ::std::optional< ::Color > UnoControlTableModel::getTextLineColor() const
+ {
+ DBG_CHECK_ME();
+ return m_aTextColor;
+ }
+
+
+ void UnoControlTableModel::setTextLineColor( Any const & i_color )
+ {
+ DBG_CHECK_ME();
+ lcl_setColor( i_color, m_aTextLineColor );
+ }
+
+
+ ::std::optional< ::std::vector< ::Color > > UnoControlTableModel::getRowBackgroundColors() const
+ {
+ DBG_CHECK_ME();
+ return m_aRowColors;
+ }
+
+
+ void UnoControlTableModel::setRowBackgroundColors( css::uno::Any const & i_APIValue )
+ {
+ DBG_CHECK_ME();
+ Sequence< css::util::Color > aAPIColors;
+ if ( !( i_APIValue >>= aAPIColors ) )
+ m_aRowColors.reset();
+ else
+ {
+ ::std::vector< ::Color > aColors( aAPIColors.getLength() );
+ std::transform(std::cbegin(aAPIColors), std::cend(aAPIColors), aColors.begin(),
+ [](const css::util::Color& rAPIColor) -> ::Color { return Color(ColorTransparency, rAPIColor); });
+ m_aRowColors = aColors;
+ }
+ }
+
+
+ VerticalAlignment UnoControlTableModel::getVerticalAlign() const
+ {
+ DBG_CHECK_ME();
+ return m_eVerticalAlign;
+ }
+
+
+ void UnoControlTableModel::setVerticalAlign( VerticalAlignment _xAlign )
+ {
+ DBG_CHECK_ME();
+ m_eVerticalAlign = _xAlign;
+ }
+
+
+ ColPos UnoControlTableModel::getColumnPos( UnoGridColumnFacade const & i_column ) const
+ {
+ DBG_CHECK_ME();
+ ColPos nPos = 0;
+ for (auto const& col : aColumns)
+ {
+ if ( &i_column == col.get() )
+ return nPos;
+ ++nPos;
+ }
+ OSL_ENSURE( false, "UnoControlTableModel::getColumnPos: column not found!" );
+ return COL_INVALID;
+ }
+
+
+ ITableDataSort* UnoControlTableModel::getSortAdapter()
+ {
+ DBG_CHECK_ME();
+
+ Reference< XSortableGridData > const xSortAccess( getDataModel(), UNO_QUERY );
+ if ( xSortAccess.is() )
+ return this;
+ return nullptr;
+ }
+
+
+ bool UnoControlTableModel::isEnabled() const
+ {
+ DBG_CHECK_ME();
+ return bEnabled;
+ }
+
+
+ void UnoControlTableModel::setEnabled( bool _bEnabled )
+ {
+ DBG_CHECK_ME();
+ bEnabled = _bEnabled;
+ }
+
+
+ void UnoControlTableModel::sortByColumn( ColPos const i_column, ColumnSortDirection const i_sortDirection )
+ {
+ DBG_CHECK_ME();
+
+ try
+ {
+ Reference< XSortableGridData > const xSortAccess( getDataModel(), UNO_QUERY_THROW );
+ xSortAccess->sortByColumn( i_column, i_sortDirection == ColumnSortAscending );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+ }
+
+
+ ColumnSort UnoControlTableModel::getCurrentSortOrder() const
+ {
+ DBG_CHECK_ME();
+
+ ColumnSort currentSort;
+ try
+ {
+ Reference< XSortableGridData > const xSortAccess( getDataModel(), UNO_QUERY_THROW );
+ Pair< ::sal_Int32, sal_Bool > const aCurrentSortOrder( xSortAccess->getCurrentSortOrder() );
+ currentSort.nColumnPos = aCurrentSortOrder.First;
+ currentSort.eSortDirection = aCurrentSortOrder.Second ? ColumnSortAscending : ColumnSortDescending;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+ return currentSort;
+ }
+
+
+ void UnoControlTableModel::notifyColumnChange( ColPos const i_columnPos, ColumnAttributeGroup const i_attributeGroup ) const
+ {
+ DBG_CHECK_ME();
+ ENSURE_OR_RETURN_VOID( ( i_columnPos >= 0 ) && ( i_columnPos < getColumnCount() ),
+ "UnoControlTableModel::notifyColumnChange: invalid column index!" );
+
+ ModellListeners aListeners( m_aListeners );
+ for (auto const& listener : aListeners)
+ {
+ listener->columnChanged( i_columnPos, i_attributeGroup );
+ }
+ }
+
+
+ void UnoControlTableModel::notifyRowsInserted( GridDataEvent const & i_event ) const
+ {
+ // check sanity of the event
+ ENSURE_OR_RETURN_VOID( i_event.FirstRow >= 0, "UnoControlTableModel::notifyRowsInserted: invalid first row!" );
+ ENSURE_OR_RETURN_VOID( i_event.LastRow >= i_event.FirstRow, "UnoControlTableModel::notifyRowsInserted: invalid row indexes!" );
+
+ // check own sanity
+ Reference< XGridColumnModel > const xColumnModel( m_aColumnModel );
+ ENSURE_OR_RETURN_VOID( xColumnModel.is(), "UnoControlTableModel::notifyRowsInserted: no column model anymore!" );
+
+ Reference< XGridDataModel > const xDataModel( m_aDataModel );
+ ENSURE_OR_RETURN_VOID( xDataModel.is(), "UnoControlTableModel::notifyRowsInserted: no data model anymore!" );
+
+ // implicitly add columns to the column model
+ // TODO: is this really a good idea?
+ sal_Int32 const dataColumnCount = xDataModel->getColumnCount();
+ OSL_ENSURE( dataColumnCount > 0, "UnoControlTableModel::notifyRowsInserted: no columns at all?" );
+
+ sal_Int32 const modelColumnCount = xColumnModel->getColumnCount();
+ if ( ( modelColumnCount == 0 ) && ( dataColumnCount > 0 ) )
+ {
+ // TODO: shouldn't we clear the mutexes guard for this call?
+ xColumnModel->setDefaultColumns( dataColumnCount );
+ }
+
+ // multiplex the event to our own listeners
+ ModellListeners aListeners( m_aListeners );
+ for (auto const& listener : aListeners)
+ {
+ listener->rowsInserted( i_event.FirstRow, i_event.LastRow );
+ }
+ }
+
+
+ void UnoControlTableModel::notifyRowsRemoved( GridDataEvent const & i_event ) const
+ {
+ ModellListeners aListeners( m_aListeners );
+ for (auto const& listener : aListeners)
+ {
+ listener->rowsRemoved( i_event.FirstRow, i_event.LastRow );
+ }
+ }
+
+
+ void UnoControlTableModel::notifyDataChanged( css::awt::grid::GridDataEvent const & i_event ) const
+ {
+ RowPos const firstRow = i_event.FirstRow == -1 ? 0 : i_event.FirstRow;
+ RowPos const lastRow = i_event.FirstRow == -1 ? getRowCount() - 1 : i_event.LastRow;
+
+ ModellListeners aListeners( m_aListeners );
+ for (auto const& listener : aListeners)
+ {
+ listener->cellsUpdated( firstRow, lastRow );
+ }
+ }
+
+
+ void UnoControlTableModel::notifyAllDataChanged() const
+ {
+ ModellListeners aListeners( m_aListeners );
+ for (auto const& listener : aListeners)
+ {
+ listener->cellsUpdated( 0, getRowCount() - 1 );
+ }
+ }
+
+
+} // svt::table
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/unocontroltablemodel.hxx b/svtools/source/uno/unocontroltablemodel.hxx
new file mode 100644
index 000000000..4a6935762
--- /dev/null
+++ b/svtools/source/uno/unocontroltablemodel.hxx
@@ -0,0 +1,181 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <table/tablemodel.hxx>
+#include <table/tablesort.hxx>
+#include <tools/color.hxx>
+
+#include <com/sun/star/awt/grid/GridDataEvent.hpp>
+#include <com/sun/star/awt/grid/XGridColumnModel.hpp>
+#include <com/sun/star/awt/grid/XGridDataModel.hpp>
+#include <com/sun/star/awt/grid/XGridColumn.hpp>
+#include <com/sun/star/awt/grid/XGridColumn.hpp>
+#include <com/sun/star/style/VerticalAlignment.hpp>
+#include <cppuhelper/weakref.hxx>
+
+
+namespace svt::table
+{
+
+
+ //= UnoControlTableModel
+
+ class UnoGridColumnFacade;
+ class UnoControlTableModel : public ITableModel, public ITableDataSort
+ {
+ public:
+ UnoControlTableModel();
+ virtual ~UnoControlTableModel() override;
+
+ public:
+ // ITableModel overridables
+ virtual TableSize getColumnCount() const override;
+ virtual TableSize getRowCount() const override;
+ virtual bool hasColumnHeaders() const override;
+ virtual bool hasRowHeaders() const override;
+ virtual PColumnModel getColumnModel( ColPos column ) override;
+ virtual PTableRenderer getRenderer() const override;
+ virtual PTableInputHandler getInputHandler() const override;
+ virtual TableMetrics getRowHeight() const override;
+ virtual TableMetrics getColumnHeaderHeight() const override;
+ virtual TableMetrics getRowHeaderWidth() const override;
+ virtual ScrollbarVisibility getVerticalScrollbarVisibility() const override;
+ virtual ScrollbarVisibility getHorizontalScrollbarVisibility() const override;
+ virtual void addTableModelListener( const PTableModelListener& i_listener ) override;
+ virtual void removeTableModelListener( const PTableModelListener& i_listener ) override;
+ virtual void getCellContent( ColPos const i_col, RowPos const i_row, css::uno::Any& o_cellContent ) override;
+ virtual void getCellToolTip( ColPos const i_col, RowPos const i_row, css::uno::Any & o_cellToolTip ) override;
+ virtual css::uno::Any getRowHeading( RowPos const i_rowPos ) const override;
+ virtual ::std::optional< ::Color > getLineColor() const override;
+ virtual ::std::optional< ::Color > getHeaderBackgroundColor() const override;
+ virtual ::std::optional< ::Color > getHeaderTextColor() const override;
+ virtual ::std::optional< ::Color > getActiveSelectionBackColor() const override;
+ virtual ::std::optional< ::Color > getInactiveSelectionBackColor() const override;
+ virtual ::std::optional< ::Color > getActiveSelectionTextColor() const override;
+ virtual ::std::optional< ::Color > getInactiveSelectionTextColor() const override;
+ virtual ::std::optional< ::Color > getTextColor() const override;
+ virtual ::std::optional< ::Color > getTextLineColor() const override;
+ virtual ::std::optional< ::std::vector< ::Color > >
+ getRowBackgroundColors() const override;
+ virtual css::style::VerticalAlignment
+ getVerticalAlign() const override;
+ virtual ITableDataSort* getSortAdapter() override;
+ virtual bool isEnabled() const override;
+
+ // ITableDataSort overridables
+ virtual void sortByColumn( ColPos const i_column, ColumnSortDirection const i_sortDirection ) override;
+ virtual ColumnSort getCurrentSortOrder() const override;
+
+ // column write access
+ void appendColumn( css::uno::Reference< css::awt::grid::XGridColumn > const & i_column );
+ void insertColumn( ColPos const i_position, css::uno::Reference< css::awt::grid::XGridColumn > const & i_column );
+ void removeColumn( ColPos const i_position );
+ void removeAllColumns();
+
+ // other operations
+ void setVerticalScrollbarVisibility( ScrollbarVisibility const i_visibility );
+ void setHorizontalScrollbarVisibility( ScrollbarVisibility const i_visibility );
+
+ void setDataModel( css::uno::Reference< css::awt::grid::XGridDataModel > const & i_gridDataModel );
+ bool hasDataModel() const;
+ css::uno::Reference< css::awt::grid::XGridDataModel >
+ getDataModel() const;
+ void setColumnModel( css::uno::Reference< css::awt::grid::XGridColumnModel > const & i_gridColumnModel );
+ bool hasColumnModel() const;
+ css::uno::Reference< css::awt::grid::XGridColumnModel >
+ getColumnModel() const;
+
+ void setRowHeaders(bool _bRowHeaders);
+ void setColumnHeaders(bool _bColumnHeaders);
+
+ void setRowHeight( TableMetrics _nHeight );
+ void setRowHeaderWidth( TableMetrics _nWidth );
+ void setColumnHeaderHeight( TableMetrics _nHeight );
+
+ void setLineColor( css::uno::Any const & i_color );
+ void setHeaderBackgroundColor( css::uno::Any const & i_color );
+ void setHeaderTextColor( css::uno::Any const & i_color );
+ void setActiveSelectionBackColor( css::uno::Any const & i_color );
+ void setInactiveSelectionBackColor( css::uno::Any const & i_color );
+ void setActiveSelectionTextColor( css::uno::Any const & i_color );
+ void setInactiveSelectionTextColor( css::uno::Any const & i_color );
+ void setTextColor( css::uno::Any const & i_color );
+ void setTextLineColor( css::uno::Any const & i_color );
+ void setRowBackgroundColors( css::uno::Any const & i_APIValue );
+
+ void setVerticalAlign(css::style::VerticalAlignment _rAlign);
+ void setEnabled( bool _bEnabled );
+
+ // multiplexing of XGridDataListener events
+ void notifyRowsInserted( css::awt::grid::GridDataEvent const & i_event ) const;
+ void notifyRowsRemoved( css::awt::grid::GridDataEvent const & i_event ) const;
+ void notifyDataChanged( css::awt::grid::GridDataEvent const & i_event ) const;
+
+ /// retrieves the index of a column within the model
+ ColPos getColumnPos( UnoGridColumnFacade const & i_column ) const;
+
+ /// notifies a change in a column belonging to the model
+ void notifyColumnChange( ColPos const i_columnPos, ColumnAttributeGroup const i_attributeGroup ) const;
+
+ /** notifies a change in all data represented by the model. To be used if you cannot specified the changed data
+ in more detail.
+ */
+ void notifyAllDataChanged() const;
+
+ private:
+ void impl_notifyTableMetricsChanged() const;
+
+ typedef ::std::vector< PTableModelListener > ModellListeners;
+ typedef ::std::vector< PColumnModel > ColumnModels;
+
+ ColumnModels aColumns;
+ bool bHasColumnHeaders;
+ bool bHasRowHeaders;
+ ScrollbarVisibility eVScrollMode;
+ ScrollbarVisibility eHScrollMode;
+ PTableRenderer pRenderer;
+ PTableInputHandler pInputHandler;
+ TableMetrics nRowHeight;
+ TableMetrics nColumnHeaderHeight;
+ TableMetrics nRowHeaderWidth;
+ ::std::optional< ::Color > m_aGridLineColor;
+ ::std::optional< ::Color > m_aHeaderBackgroundColor;
+ ::std::optional< ::Color > m_aHeaderTextColor;
+ ::std::optional< ::Color > m_aActiveSelectionBackColor;
+ ::std::optional< ::Color > m_aInactiveSelectionBackColor;
+ ::std::optional< ::Color > m_aActiveSelectionTextColor;
+ ::std::optional< ::Color > m_aInactiveSelectionTextColor;
+ ::std::optional< ::Color > m_aTextColor;
+ ::std::optional< ::Color > m_aTextLineColor;
+ ::std::optional< ::std::vector< ::Color > > m_aRowColors;
+ css::style::VerticalAlignment m_eVerticalAlign;
+ bool bEnabled;
+ ModellListeners m_aListeners;
+ css::uno::WeakReference< css::awt::grid::XGridDataModel > m_aDataModel;
+ css::uno::WeakReference< css::awt::grid::XGridColumnModel > m_aColumnModel;
+ };
+
+
+} // svt::table
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/unoevent.cxx b/svtools/source/uno/unoevent.cxx
new file mode 100644
index 000000000..30f4cbecb
--- /dev/null
+++ b/svtools/source/uno/unoevent.cxx
@@ -0,0 +1,450 @@
+/* -*- 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 <com/sun/star/beans/PropertyValue.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <o3tl/string_view.hxx>
+#include <osl/diagnose.h>
+#include <sfx2/event.hxx>
+#include <svtools/unoevent.hxx>
+#include <svl/macitem.hxx>
+
+using namespace ::com::sun::star;
+using namespace css::uno;
+
+using css::container::NoSuchElementException;
+using css::container::XNameReplace;
+using css::lang::IllegalArgumentException;
+using css::beans::PropertyValue;
+
+
+constexpr OUStringLiteral sAPI_ServiceName = u"com.sun.star.container.XNameReplace";
+constexpr OUStringLiteral sEventType = u"EventType";
+constexpr OUStringLiteral sMacroName = u"MacroName";
+constexpr OUStringLiteral sLibrary = u"Library";
+constexpr OUStringLiteral sStarBasic = u"StarBasic";
+constexpr OUStringLiteral sScript = u"Script";
+constexpr OUStringLiteral sNone = u"None";
+
+namespace {
+
+void getAnyFromMacro(Any& rAny, const SvxMacro& rMacro)
+{
+ bool bRetValueOK = false; // do we have a ret value?
+
+ if (rMacro.HasMacro())
+ {
+ switch (rMacro.GetScriptType())
+ {
+ case STARBASIC:
+ {
+ // create sequence
+ Sequence<PropertyValue> aSequence(
+ // create type
+ { comphelper::makePropertyValue(sEventType, OUString(sStarBasic)),
+ // macro name
+ comphelper::makePropertyValue(sMacroName, rMacro.GetMacName()),
+ // library name
+ comphelper::makePropertyValue(sLibrary, rMacro.GetLibName()) });
+
+ rAny <<= aSequence;
+ bRetValueOK = true;
+ break;
+ }
+ case EXTENDED_STYPE:
+ {
+ // create sequence
+ Sequence<PropertyValue> aSequence(
+ // create type
+ { comphelper::makePropertyValue(sEventType, OUString(sScript)),
+ // macro name
+ comphelper::makePropertyValue(sScript, rMacro.GetMacName()) });
+
+ rAny <<= aSequence;
+ bRetValueOK = true;
+ break;
+ }
+ case JAVASCRIPT:
+ default:
+ OSL_FAIL("not implemented");
+ }
+ }
+ // else: bRetValueOK not set
+
+ // if we don't have a return value, make an empty one
+ if ( bRetValueOK)
+ return;
+
+ // create "None" macro
+ Sequence<PropertyValue> aSequence{ comphelper::makePropertyValue(sEventType, OUString(sNone)) };
+ rAny <<= aSequence;
+}
+
+/// @throws IllegalArgumentException
+void getMacroFromAny(
+ SvxMacro& rMacro,
+ const Any& rAny)
+{
+ // get sequence
+ Sequence<PropertyValue> aSequence;
+ rAny >>= aSequence;
+
+ // process ...
+ bool bTypeOK = false;
+ bool bNone = false; // true if EventType=="None"
+ enum ScriptType eType = EXTENDED_STYPE;
+ OUString sScriptVal;
+ OUString sMacroVal;
+ OUString sLibVal;
+ for (const PropertyValue& aValue : std::as_const(aSequence))
+ {
+ if (aValue.Name == sEventType)
+ {
+ OUString sTmp;
+ aValue.Value >>= sTmp;
+ if (sTmp == sStarBasic)
+ {
+ eType = STARBASIC;
+ bTypeOK = true;
+ }
+ else if (sTmp == "JavaScript")
+ {
+ eType = JAVASCRIPT;
+ bTypeOK = true;
+ }
+ else if (sTmp == sScript)
+ {
+ eType = EXTENDED_STYPE;
+ bTypeOK = true;
+ }
+ else if (sTmp == sNone)
+ {
+ bNone = true;
+ bTypeOK = true;
+ }
+ // else: unknown script type
+ }
+ else if (aValue.Name == sMacroName)
+ {
+ aValue.Value >>= sMacroVal;
+ }
+ else if (aValue.Name == sLibrary)
+ {
+ aValue.Value >>= sLibVal;
+ }
+ else if (aValue.Name == sScript)
+ {
+ aValue.Value >>= sScriptVal;
+ }
+ // else: unknown PropertyValue -> ignore
+ }
+
+ if (!bTypeOK)
+ {
+ // no valid type: abort
+ throw IllegalArgumentException();
+ }
+
+ if (bNone)
+ {
+ // return empty macro
+ rMacro = SvxMacro( "", "" );
+ }
+ else
+ {
+ if (eType == STARBASIC)
+ {
+ // create macro and return
+ SvxMacro aMacro(sMacroVal, sLibVal, eType);
+ rMacro = aMacro;
+ }
+ else if (eType == EXTENDED_STYPE)
+ {
+ SvxMacro aMacro(sScriptVal, sScript);
+ rMacro = aMacro;
+ }
+ else
+ {
+ // we can't process type: abort
+ // TODO: JavaScript macros
+ throw IllegalArgumentException();
+ }
+ }
+}
+
+}
+
+SvBaseEventDescriptor::SvBaseEventDescriptor( const SvEventDescription* pSupportedMacroItems ) :
+ mpSupportedMacroItems(pSupportedMacroItems),
+ mnMacroItems(0)
+{
+ assert(pSupportedMacroItems != nullptr && "Need a list of supported events!");
+
+ for( ; mpSupportedMacroItems[mnMacroItems].mnEvent != SvMacroItemId::NONE; mnMacroItems++) ;
+}
+
+
+SvBaseEventDescriptor::~SvBaseEventDescriptor()
+{
+}
+
+void SvBaseEventDescriptor::replaceByName(
+ const OUString& rName,
+ const Any& rElement )
+{
+ SvMacroItemId nMacroID = getMacroID(rName);
+
+ // error checking
+ if (SvMacroItemId::NONE == nMacroID)
+ throw NoSuchElementException();
+ if (rElement.getValueType() != getElementType())
+ throw IllegalArgumentException();
+
+ // get sequence
+ Sequence<PropertyValue> aSequence;
+ rElement >>= aSequence;
+
+ // perform replace (in subclass)
+ SvxMacro aMacro("","");
+ getMacroFromAny(aMacro, rElement);
+ replaceByName(nMacroID, aMacro);
+}
+
+Any SvBaseEventDescriptor::getByName(
+ const OUString& rName )
+{
+ SvMacroItemId nMacroID = getMacroID(rName);
+
+ // error checking
+ if (SvMacroItemId::NONE == nMacroID)
+ throw NoSuchElementException();
+
+ // perform get (in subclass)
+ Any aAny;
+ SvxMacro aMacro( "", "" );
+ getByName(aMacro, nMacroID);
+ getAnyFromMacro(aAny, aMacro);
+ return aAny;
+}
+
+Sequence<OUString> SvBaseEventDescriptor::getElementNames()
+{
+ // create and fill sequence
+ Sequence<OUString> aSequence(mnMacroItems);
+ auto aSequenceRange = asNonConstRange(aSequence);
+ for( sal_Int16 i = 0; i < mnMacroItems; i++)
+ {
+ aSequenceRange[i] = OUString::createFromAscii( mpSupportedMacroItems[i].mpEventName );
+ }
+
+ return aSequence;
+}
+
+sal_Bool SvBaseEventDescriptor::hasByName(
+ const OUString& rName )
+{
+ SvMacroItemId nMacroID = getMacroID(rName);
+ return (nMacroID != SvMacroItemId::NONE);
+}
+
+Type SvBaseEventDescriptor::getElementType()
+{
+ return cppu::UnoType<Sequence<PropertyValue>>::get();
+}
+
+sal_Bool SvBaseEventDescriptor::hasElements()
+{
+ return mnMacroItems != 0;
+}
+
+sal_Bool SvBaseEventDescriptor::supportsService(const OUString& rServiceName)
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+Sequence<OUString> SvBaseEventDescriptor::getSupportedServiceNames()
+{
+ return { sAPI_ServiceName };
+}
+
+SvMacroItemId SvBaseEventDescriptor::mapNameToEventID(std::u16string_view rName) const
+{
+ // iterate over known event names
+ for(sal_Int16 i = 0; i < mnMacroItems; i++)
+ {
+ if( o3tl::equalsAscii(rName, mpSupportedMacroItems[i].mpEventName))
+ {
+ return mpSupportedMacroItems[i].mnEvent;
+ }
+ }
+
+ // not found -> return zero
+ return SvMacroItemId::NONE;
+}
+
+SvMacroItemId SvBaseEventDescriptor::getMacroID(std::u16string_view rName) const
+{
+ return mapNameToEventID(rName);
+}
+
+SvEventDescriptor::SvEventDescriptor(
+ XInterface& rParent,
+ const SvEventDescription* pSupportedMacroItems) :
+ SvBaseEventDescriptor(pSupportedMacroItems),
+ xParentRef(&rParent)
+{
+}
+
+
+SvEventDescriptor::~SvEventDescriptor()
+{
+ // automatically release xParentRef !
+}
+
+void SvEventDescriptor::replaceByName(
+ const SvMacroItemId nEvent,
+ const SvxMacro& rMacro)
+{
+ SvxMacroItem aItem(getMacroItemWhich());
+ aItem.SetMacroTable(getMacroItem().GetMacroTable());
+ aItem.SetMacro(nEvent, rMacro);
+ setMacroItem(aItem);
+}
+
+void SvEventDescriptor::getByName(
+ SvxMacro& rMacro,
+ const SvMacroItemId nEvent )
+{
+ const SvxMacroItem& rItem = getMacroItem();
+ if( rItem.HasMacro( nEvent ) )
+ rMacro = rItem.GetMacro(nEvent);
+ else
+ {
+ SvxMacro aEmptyMacro("", "");
+ rMacro = aEmptyMacro;
+ }
+}
+
+SvDetachedEventDescriptor::SvDetachedEventDescriptor(
+ const SvEventDescription* pSupportedMacroItems) :
+ SvBaseEventDescriptor(pSupportedMacroItems)
+{
+ aMacros.resize(mnMacroItems);
+}
+
+SvDetachedEventDescriptor::~SvDetachedEventDescriptor()
+{
+}
+
+sal_Int16 SvDetachedEventDescriptor::getIndex(const SvMacroItemId nID) const
+{
+ // iterate over supported events
+ sal_Int16 nIndex = 0;
+ while ( (mpSupportedMacroItems[nIndex].mnEvent != nID) &&
+ (mpSupportedMacroItems[nIndex].mnEvent != SvMacroItemId::NONE) )
+ {
+ nIndex++;
+ }
+ return (mpSupportedMacroItems[nIndex].mnEvent == nID) ? nIndex : -1;
+}
+
+OUString SvDetachedEventDescriptor::getImplementationName()
+{
+ return "SvDetachedEventDescriptor";
+}
+
+
+void SvDetachedEventDescriptor::replaceByName(
+ const SvMacroItemId nEvent,
+ const SvxMacro& rMacro)
+{
+ sal_Int16 nIndex = getIndex(nEvent);
+ if (-1 == nIndex)
+ throw IllegalArgumentException();
+
+ aMacros[nIndex].reset( new SvxMacro(rMacro.GetMacName(), rMacro.GetLibName(),
+ rMacro.GetScriptType() ) );
+}
+
+
+void SvDetachedEventDescriptor::getByName(
+ SvxMacro& rMacro,
+ const SvMacroItemId nEvent )
+{
+ sal_Int16 nIndex = getIndex(nEvent);
+ if (-1 == nIndex )
+ throw NoSuchElementException();
+
+ if( aMacros[nIndex] )
+ rMacro = *aMacros[nIndex];
+}
+
+bool SvDetachedEventDescriptor::hasById(
+ const SvMacroItemId nEvent ) const /// item ID of event
+{
+ sal_Int16 nIndex = getIndex(nEvent);
+ if (-1 == nIndex)
+ throw IllegalArgumentException();
+
+ return (nullptr != aMacros[nIndex]) && aMacros[nIndex]->HasMacro();
+}
+
+
+SvMacroTableEventDescriptor::SvMacroTableEventDescriptor(const SvEventDescription* pSupportedMacroItems) :
+ SvDetachedEventDescriptor(pSupportedMacroItems)
+{
+}
+
+SvMacroTableEventDescriptor::SvMacroTableEventDescriptor(
+ const SvxMacroTableDtor& rMacroTable,
+ const SvEventDescription* pSupportedMacroItems) :
+ SvDetachedEventDescriptor(pSupportedMacroItems)
+{
+ assert(mpSupportedMacroItems);
+ for(sal_Int16 i = 0; mpSupportedMacroItems[i].mnEvent != SvMacroItemId::NONE; i++)
+ {
+ const SvMacroItemId nEvent = mpSupportedMacroItems[i].mnEvent;
+ const SvxMacro* pMacro = rMacroTable.Get(nEvent);
+ if (nullptr != pMacro)
+ replaceByName(nEvent, *pMacro);
+ }
+}
+
+SvMacroTableEventDescriptor::~SvMacroTableEventDescriptor()
+{
+}
+
+void SvMacroTableEventDescriptor::copyMacrosIntoTable(
+ SvxMacroTableDtor& rMacroTable)
+{
+ for(sal_Int16 i = 0; mpSupportedMacroItems[i].mnEvent != SvMacroItemId::NONE; i++)
+ {
+ const SvMacroItemId nEvent = mpSupportedMacroItems[i].mnEvent;
+ if (hasById(nEvent))
+ {
+ SvxMacro& rMacro = rMacroTable.Insert(nEvent, SvxMacro("", ""));
+ getByName(rMacro, nEvent);
+ }
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/unogridcolumnfacade.cxx b/svtools/source/uno/unogridcolumnfacade.cxx
new file mode 100644
index 000000000..c41600cee
--- /dev/null
+++ b/svtools/source/uno/unogridcolumnfacade.cxx
@@ -0,0 +1,310 @@
+/* -*- 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 "unogridcolumnfacade.hxx"
+#include "unocontroltablemodel.hxx"
+
+#include <com/sun/star/awt/grid/XGridColumn.hpp>
+#include <com/sun/star/awt/grid/XGridColumnListener.hpp>
+
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+#include <cppuhelper/implbase.hxx>
+
+
+namespace svt::table
+{
+
+
+ using css::uno::Reference;
+ using css::awt::grid::XGridColumn;
+ using css::uno::Exception;
+ using css::awt::grid::XGridColumnListener;
+ using css::lang::EventObject;
+ using css::awt::grid::GridColumnEvent;
+ using css::style::HorizontalAlignment_LEFT;
+ using css::style::HorizontalAlignment;
+
+
+ namespace
+ {
+ template< class T1, class T2 >
+ void lcl_set( Reference< XGridColumn > const & i_column, void ( SAL_CALL XGridColumn::*i_setter )( T1 ),
+ T2 i_value )
+ {
+ try
+ {
+ (i_column.get()->*i_setter) ( i_value );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+ }
+
+ template< class ATTRIBUTE_TYPE >
+ ATTRIBUTE_TYPE lcl_get( Reference< XGridColumn > const & i_column, ATTRIBUTE_TYPE ( SAL_CALL XGridColumn::*i_getter )() )
+ {
+ ATTRIBUTE_TYPE value = ATTRIBUTE_TYPE();
+ try
+ {
+ value = (i_column.get()->*i_getter)();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+ return value;
+ }
+ }
+
+
+ //= ColumnChangeMultiplexer
+
+ typedef ::cppu::WeakImplHelper < XGridColumnListener
+ > ColumnChangeMultiplexer_Base;
+ class ColumnChangeMultiplexer :public ColumnChangeMultiplexer_Base
+ {
+ public:
+ explicit ColumnChangeMultiplexer( UnoGridColumnFacade& i_colImpl );
+ ColumnChangeMultiplexer(const ColumnChangeMultiplexer&) = delete;
+ ColumnChangeMultiplexer& operator=(const ColumnChangeMultiplexer&) = delete;
+
+ void dispose();
+
+ protected:
+ virtual ~ColumnChangeMultiplexer() override;
+
+ // XGridColumnListener
+ virtual void SAL_CALL columnChanged( const GridColumnEvent& i_event ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const EventObject& i_event ) override;
+
+ private:
+ UnoGridColumnFacade* m_pColumnImplementation;
+ };
+
+
+ ColumnChangeMultiplexer::ColumnChangeMultiplexer( UnoGridColumnFacade& i_colImpl )
+ :m_pColumnImplementation( &i_colImpl )
+ {
+ }
+
+
+ ColumnChangeMultiplexer::~ColumnChangeMultiplexer()
+ {
+ }
+
+
+ void ColumnChangeMultiplexer::dispose()
+ {
+ DBG_TESTSOLARMUTEX();
+ m_pColumnImplementation = nullptr;
+ }
+
+
+ void SAL_CALL ColumnChangeMultiplexer::columnChanged( const GridColumnEvent& i_event )
+ {
+ if ( i_event.AttributeName == "DataColumnIndex" )
+ {
+ SolarMutexGuard aGuard;
+ if ( m_pColumnImplementation != nullptr )
+ m_pColumnImplementation->dataColumnIndexChanged();
+ return;
+ }
+
+ ColumnAttributeGroup nChangedAttributes( ColumnAttributeGroup::NONE );
+
+ if ( i_event.AttributeName == "HorizontalAlign" )
+ nChangedAttributes |= ColumnAttributeGroup::APPEARANCE;
+
+ if ( i_event.AttributeName == "ColumnWidth"
+ || i_event.AttributeName == "MaxWidth"
+ || i_event.AttributeName == "MinWidth"
+ || i_event.AttributeName == "PreferredWidth"
+ || i_event.AttributeName == "Resizeable"
+ || i_event.AttributeName == "Flexibility"
+ )
+ nChangedAttributes |= ColumnAttributeGroup::WIDTH;
+
+ OSL_ENSURE( nChangedAttributes != ColumnAttributeGroup::NONE,
+ "ColumnChangeMultiplexer::columnChanged: unknown column attributed changed!" );
+
+ SolarMutexGuard aGuard;
+ if ( m_pColumnImplementation != nullptr )
+ m_pColumnImplementation->columnChanged( nChangedAttributes );
+ }
+
+
+ void SAL_CALL ColumnChangeMultiplexer::disposing( const EventObject& )
+ {
+ }
+
+
+ //= UnoGridColumnFacade
+
+
+ UnoGridColumnFacade::UnoGridColumnFacade( UnoControlTableModel const & i_owner, Reference< XGridColumn > const & i_gridColumn )
+ :m_pOwner( &i_owner )
+ ,m_nDataColumnIndex( -1 )
+ ,m_xGridColumn( i_gridColumn, css::uno::UNO_SET_THROW )
+ ,m_pChangeMultiplexer( new ColumnChangeMultiplexer( *this ) )
+ {
+ m_xGridColumn->addGridColumnListener( m_pChangeMultiplexer );
+ impl_updateDataColumnIndex_nothrow();
+ }
+
+
+ UnoGridColumnFacade::~UnoGridColumnFacade()
+ {
+ }
+
+
+ void UnoGridColumnFacade::dispose()
+ {
+ DBG_TESTSOLARMUTEX();
+ ENSURE_OR_RETURN_VOID( m_pOwner != nullptr, "UnoGridColumnFacade::dispose: already disposed!" );
+
+ m_xGridColumn->removeGridColumnListener( m_pChangeMultiplexer );
+ m_pChangeMultiplexer->dispose();
+ m_pChangeMultiplexer.clear();
+ m_xGridColumn.clear();
+ m_pOwner = nullptr;
+ }
+
+
+ void UnoGridColumnFacade::impl_updateDataColumnIndex_nothrow()
+ {
+ m_nDataColumnIndex = -1;
+ ENSURE_OR_RETURN_VOID( m_xGridColumn.is(), "UnoGridColumnFacade: already disposed!" );
+ try
+ {
+ m_nDataColumnIndex = m_xGridColumn->getDataColumnIndex();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+ }
+
+
+ void UnoGridColumnFacade::dataColumnIndexChanged()
+ {
+ DBG_TESTSOLARMUTEX();
+ impl_updateDataColumnIndex_nothrow();
+ if ( m_pOwner != nullptr )
+ m_pOwner->notifyAllDataChanged();
+ }
+
+
+ void UnoGridColumnFacade::columnChanged( ColumnAttributeGroup const i_attributeGroup )
+ {
+ DBG_TESTSOLARMUTEX();
+ if ( m_pOwner != nullptr )
+ m_pOwner->notifyColumnChange( m_pOwner->getColumnPos( *this ), i_attributeGroup );
+ }
+
+
+ OUString UnoGridColumnFacade::getName() const
+ {
+ OUString sName;
+ ENSURE_OR_RETURN( m_xGridColumn.is(), "UnoGridColumnFacade: already disposed!", sName );
+ try
+ {
+ sName = m_xGridColumn->getTitle();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+ return sName;
+ }
+
+
+ OUString UnoGridColumnFacade::getHelpText() const
+ {
+ OUString sHelpText;
+ ENSURE_OR_RETURN( m_xGridColumn.is(), "UnoGridColumnFacade: already disposed!", sHelpText );
+ try
+ {
+ sHelpText = m_xGridColumn->getHelpText();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+ return sHelpText;
+ }
+
+
+ bool UnoGridColumnFacade::isResizable() const
+ {
+ ENSURE_OR_RETURN( m_xGridColumn.is(), "UnoGridColumnFacade: already disposed!", false );
+ return lcl_get( m_xGridColumn, &XGridColumn::getResizeable );
+ }
+
+
+ sal_Int32 UnoGridColumnFacade::getFlexibility() const
+ {
+ ENSURE_OR_RETURN( m_xGridColumn.is(), "UnoGridColumnFacade: already disposed!", 1 );
+ return lcl_get( m_xGridColumn, &XGridColumn::getFlexibility );
+ }
+
+
+ TableMetrics UnoGridColumnFacade::getWidth() const
+ {
+ ENSURE_OR_RETURN( m_xGridColumn.is(), "UnoGridColumnFacade: already disposed!", 0 );
+ return lcl_get( m_xGridColumn, &XGridColumn::getColumnWidth );
+ }
+
+
+ void UnoGridColumnFacade::setWidth( TableMetrics _nWidth )
+ {
+ ENSURE_OR_RETURN_VOID( m_xGridColumn.is(), "UnoGridColumnFacade: already disposed!" );
+ lcl_set( m_xGridColumn, &XGridColumn::setColumnWidth, _nWidth );
+ }
+
+
+ TableMetrics UnoGridColumnFacade::getMinWidth() const
+ {
+ ENSURE_OR_RETURN( m_xGridColumn.is(), "UnoGridColumnFacade: already disposed!", 0 );
+ return lcl_get( m_xGridColumn, &XGridColumn::getMinWidth );
+ }
+
+
+ TableMetrics UnoGridColumnFacade::getMaxWidth() const
+ {
+ ENSURE_OR_RETURN( m_xGridColumn.is(), "UnoGridColumnFacade: already disposed!", 0 );
+ return lcl_get( m_xGridColumn, &XGridColumn::getMaxWidth );
+ }
+
+
+ css::style::HorizontalAlignment UnoGridColumnFacade::getHorizontalAlign()
+ {
+ ENSURE_OR_RETURN( m_xGridColumn.is(), "UnoGridColumnFacade: already disposed!", HorizontalAlignment_LEFT );
+ return lcl_get( m_xGridColumn, &XGridColumn::getHorizontalAlign );
+ }
+
+
+} // svt::table
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/unogridcolumnfacade.hxx b/svtools/source/uno/unogridcolumnfacade.hxx
new file mode 100644
index 000000000..672397276
--- /dev/null
+++ b/svtools/source/uno/unogridcolumnfacade.hxx
@@ -0,0 +1,89 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <table/tablemodel.hxx>
+
+#include <com/sun/star/awt/grid/XGridColumn.hpp>
+#include <com/sun/star/style/HorizontalAlignment.hpp>
+
+#include <rtl/ref.hxx>
+
+
+namespace svt::table
+{
+
+
+ //= UnoGridColumnFacade
+
+ class ColumnChangeMultiplexer;
+ class UnoControlTableModel;
+ class UnoGridColumnFacade :public IColumnModel
+ {
+ public:
+ UnoGridColumnFacade(
+ UnoControlTableModel const & i_owner,
+ css::uno::Reference< css::awt::grid::XGridColumn > const & i_gridColumn
+ );
+ virtual ~UnoGridColumnFacade() override;
+ UnoGridColumnFacade(const UnoGridColumnFacade&) = delete;
+ UnoGridColumnFacade& operator=(const UnoGridColumnFacade&) = delete;
+
+ // IColumnModel overridables
+ virtual OUString getName() const override;
+ virtual OUString getHelpText() const override;
+ virtual bool isResizable() const override;
+ virtual sal_Int32 getFlexibility() const override;
+ virtual TableMetrics getWidth() const override;
+ virtual void setWidth( TableMetrics _nWidth ) override;
+ virtual TableMetrics getMinWidth() const override;
+ virtual TableMetrics getMaxWidth() const override;
+ virtual css::style::HorizontalAlignment getHorizontalAlign() override;
+
+ /** disposes the column wrapper
+
+ Note that the XGridColumn which is wrapped by the instance is <strong>not</strong> disposed, as we
+ do not own it.
+ */
+ void dispose();
+
+ sal_Int32
+ getDataColumnIndex() const { return m_nDataColumnIndex; }
+
+ // callbacks for the XGridColumnListener
+ void columnChanged( ColumnAttributeGroup const i_attributeGroup );
+ void dataColumnIndexChanged();
+
+ private:
+ void impl_updateDataColumnIndex_nothrow();
+
+ private:
+ UnoControlTableModel const * m_pOwner;
+ sal_Int32 m_nDataColumnIndex;
+ css::uno::Reference< css::awt::grid::XGridColumn > m_xGridColumn;
+ ::rtl::Reference< ColumnChangeMultiplexer > m_pChangeMultiplexer;
+ };
+
+
+} // svt::table
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/unoiface.cxx b/svtools/source/uno/unoiface.cxx
new file mode 100644
index 000000000..71bc18150
--- /dev/null
+++ b/svtools/source/uno/unoiface.cxx
@@ -0,0 +1,50 @@
+/* -*- 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 <unoiface.hxx>
+#include "svtxgridcontrol.hxx"
+#include <table/tablecontrol.hxx>
+
+// help function for the toolkit...
+
+extern "C" {
+
+SAL_DLLPUBLIC_EXPORT vcl::Window* CreateWindow( rtl::Reference<VCLXWindow>* ppNewComp, const css::awt::WindowDescriptor* pDescriptor, vcl::Window* pParent, WinBits nWinBits )
+{
+ vcl::Window* pWindow = nullptr;
+ OUString aServiceName( pDescriptor->WindowServiceName );
+ if ( aServiceName.equalsIgnoreAsciiCase( "Grid" ) )
+ {
+ if ( pParent )
+ {
+ pWindow = VclPtr< ::svt::table::TableControl>::Create(pParent, nWinBits);
+ *ppNewComp = new SVTXGridControl;
+ }
+ else
+ {
+ *ppNewComp = nullptr;
+ return nullptr;
+ }
+ }
+ return pWindow;
+}
+
+} // extern "C"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/unoimap.cxx b/svtools/source/uno/unoimap.cxx
new file mode 100644
index 000000000..4d64cc8b4
--- /dev/null
+++ b/svtools/source/uno/unoimap.cxx
@@ -0,0 +1,720 @@
+/* -*- 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 <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/document/XEventsSupplier.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/awt/Point.hpp>
+#include <com/sun/star/drawing/PointSequence.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/propertysethelper.hxx>
+#include <comphelper/propertysetinfo.hxx>
+#include <cppuhelper/weakagg.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <algorithm>
+#include <osl/diagnose.h>
+#include <rtl/ref.hxx>
+#include <svtools/unoevent.hxx>
+#include <svtools/unoimap.hxx>
+#include <vcl/imap.hxx>
+#include <vcl/imapcirc.hxx>
+#include <vcl/imaprect.hxx>
+#include <vcl/imappoly.hxx>
+
+using namespace comphelper;
+using namespace cppu;
+using namespace com::sun::star;
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::container;
+using namespace css::beans;
+using namespace css::document;
+using namespace css::drawing;
+
+const sal_Int32 HANDLE_URL = 1;
+const sal_Int32 HANDLE_DESCRIPTION = 2;
+const sal_Int32 HANDLE_TARGET = 3;
+const sal_Int32 HANDLE_NAME = 4;
+const sal_Int32 HANDLE_ISACTIVE = 5;
+const sal_Int32 HANDLE_POLYGON = 6;
+const sal_Int32 HANDLE_CENTER = 7;
+const sal_Int32 HANDLE_RADIUS = 8;
+const sal_Int32 HANDLE_BOUNDARY = 9;
+const sal_Int32 HANDLE_TITLE = 10;
+
+namespace {
+
+class SvUnoImageMapObject : public OWeakAggObject,
+ public XEventsSupplier,
+ public XServiceInfo,
+ public PropertySetHelper,
+ public XTypeProvider,
+ public XUnoTunnel
+{
+public:
+ SvUnoImageMapObject( IMapObjectType nType, const SvEventDescription* pSupportedMacroItems );
+ SvUnoImageMapObject( const IMapObject& rMapObject, const SvEventDescription* pSupportedMacroItems );
+
+ UNO3_GETIMPLEMENTATION_DECL( SvUnoImageMapObject )
+
+ std::unique_ptr<IMapObject> createIMapObject() const;
+
+ rtl::Reference<SvMacroTableEventDescriptor> mxEvents;
+
+ // overridden helpers from PropertySetHelper
+ virtual void _setPropertyValues( const PropertyMapEntry** ppEntries, const Any* pValues ) override;
+ virtual void _getPropertyValues( const PropertyMapEntry** ppEntries, Any* pValue ) override;
+
+ // XInterface
+ virtual Any SAL_CALL queryAggregation( const Type & rType ) override;
+ virtual Any SAL_CALL queryInterface( const Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider
+ virtual Sequence< Type > SAL_CALL getTypes( ) override;
+ virtual Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override;
+
+ // XEventsSupplier
+ virtual Reference< css::container::XNameReplace > SAL_CALL getEvents( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+private:
+ static rtl::Reference<PropertySetInfo> createPropertySetInfo( IMapObjectType nType );
+
+
+ IMapObjectType mnType;
+
+ OUString maURL;
+ OUString maAltText;
+ OUString maDesc;
+ OUString maTarget;
+ OUString maName;
+ bool mbIsActive;
+ awt::Rectangle maBoundary;
+ awt::Point maCenter;
+ sal_Int32 mnRadius;
+ PointSequence maPolygon;
+};
+
+}
+
+UNO3_GETIMPLEMENTATION_IMPL( SvUnoImageMapObject );
+
+rtl::Reference<PropertySetInfo> SvUnoImageMapObject::createPropertySetInfo( IMapObjectType nType )
+{
+ switch( nType )
+ {
+ case IMapObjectType::Polygon:
+ {
+ static PropertyMapEntry const aPolygonObj_Impl[] =
+ {
+ { OUString("URL"), HANDLE_URL, cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("Title"), HANDLE_TITLE, cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("Description"), HANDLE_DESCRIPTION, cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("Target"), HANDLE_TARGET, cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("Name"), HANDLE_NAME, cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("IsActive"), HANDLE_ISACTIVE, cppu::UnoType<bool>::get(), 0, 0 },
+ { OUString("Polygon"), HANDLE_POLYGON, cppu::UnoType<PointSequence>::get(), 0, 0 },
+ };
+
+ return rtl::Reference<PropertySetInfo>(new PropertySetInfo( aPolygonObj_Impl ));
+ }
+ case IMapObjectType::Circle:
+ {
+ static PropertyMapEntry const aCircleObj_Impl[] =
+ {
+ { OUString("URL"), HANDLE_URL, cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("Title"), HANDLE_TITLE, cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("Description"), HANDLE_DESCRIPTION, cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("Target"), HANDLE_TARGET, cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("Name"), HANDLE_NAME, cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("IsActive"), HANDLE_ISACTIVE, cppu::UnoType<bool>::get(), 0, 0 },
+ { OUString("Center"), HANDLE_CENTER, cppu::UnoType<awt::Point>::get(), 0, 0 },
+ { OUString("Radius"), HANDLE_RADIUS, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ };
+
+ return rtl::Reference<PropertySetInfo>(new PropertySetInfo( aCircleObj_Impl ));
+ }
+ case IMapObjectType::Rectangle:
+ default:
+ {
+ static PropertyMapEntry const aRectangleObj_Impl[] =
+ {
+ { OUString("URL"), HANDLE_URL, cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("Title"), HANDLE_TITLE, cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("Description"), HANDLE_DESCRIPTION, cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("Target"), HANDLE_TARGET, cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("Name"), HANDLE_NAME, cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("IsActive"), HANDLE_ISACTIVE, cppu::UnoType<bool>::get(), 0, 0 },
+ { OUString("Boundary"), HANDLE_BOUNDARY, cppu::UnoType<awt::Rectangle>::get(), 0, 0 },
+ };
+
+ return rtl::Reference<PropertySetInfo>(new PropertySetInfo( aRectangleObj_Impl ));
+ }
+ }
+}
+
+SvUnoImageMapObject::SvUnoImageMapObject( IMapObjectType nType, const SvEventDescription* pSupportedMacroItems )
+: PropertySetHelper( createPropertySetInfo( nType ) ),
+ mnType( nType )
+, mbIsActive( true )
+, mnRadius( 0 )
+{
+ mxEvents = new SvMacroTableEventDescriptor( pSupportedMacroItems );
+}
+
+SvUnoImageMapObject::SvUnoImageMapObject( const IMapObject& rMapObject, const SvEventDescription* pSupportedMacroItems )
+: PropertySetHelper( createPropertySetInfo( rMapObject.GetType() ) ),
+ mnType( rMapObject.GetType() )
+, mbIsActive( true )
+, mnRadius( 0 )
+{
+ maURL = rMapObject.GetURL();
+ maAltText = rMapObject.GetAltText();
+ maDesc = rMapObject.GetDesc();
+ maTarget = rMapObject.GetTarget();
+ maName = rMapObject.GetName();
+ mbIsActive = rMapObject.IsActive();
+
+ switch( mnType )
+ {
+ case IMapObjectType::Rectangle:
+ {
+ const tools::Rectangle aRect( static_cast<const IMapRectangleObject*>(&rMapObject)->GetRectangle(false) );
+ maBoundary.X = aRect.Left();
+ maBoundary.Y = aRect.Top();
+ maBoundary.Width = aRect.GetWidth();
+ maBoundary.Height = aRect.GetHeight();
+ }
+ break;
+ case IMapObjectType::Circle:
+ {
+ mnRadius = static_cast<const IMapCircleObject*>(&rMapObject)->GetRadius(false);
+ const Point aPoint( static_cast<const IMapCircleObject*>(&rMapObject)->GetCenter(false) );
+
+ maCenter.X = aPoint.X();
+ maCenter.Y = aPoint.Y();
+ }
+ break;
+ case IMapObjectType::Polygon:
+ default:
+ {
+ const tools::Polygon aPoly( static_cast<const IMapPolygonObject*>(&rMapObject)->GetPolygon(false) );
+
+ const sal_uInt16 nCount = aPoly.GetSize();
+ maPolygon.realloc( nCount );
+ awt::Point* pPoints = maPolygon.getArray();
+
+ for( sal_uInt16 nPoint = 0; nPoint < nCount; nPoint++ )
+ {
+ const Point& rPoint = aPoly.GetPoint( nPoint );
+ pPoints->X = rPoint.X();
+ pPoints->Y = rPoint.Y();
+
+ pPoints++;
+ }
+ }
+ }
+
+ mxEvents = new SvMacroTableEventDescriptor( rMapObject.GetMacroTable(), pSupportedMacroItems );
+}
+
+std::unique_ptr<IMapObject> SvUnoImageMapObject::createIMapObject() const
+{
+ const OUString aURL( maURL );
+ const OUString aAltText( maAltText );
+ const OUString aDesc( maDesc );
+ const OUString aTarget( maTarget );
+ const OUString aName( maName );
+
+ std::unique_ptr<IMapObject> pNewIMapObject;
+
+ switch( mnType )
+ {
+ case IMapObjectType::Rectangle:
+ {
+ const tools::Rectangle aRect( maBoundary.X, maBoundary.Y, maBoundary.X + maBoundary.Width - 1, maBoundary.Y + maBoundary.Height - 1 );
+ pNewIMapObject.reset(new IMapRectangleObject( aRect, aURL, aAltText, aDesc, aTarget, aName, mbIsActive, false ));
+ }
+ break;
+
+ case IMapObjectType::Circle:
+ {
+ const Point aCenter( maCenter.X, maCenter.Y );
+ pNewIMapObject.reset(new IMapCircleObject( aCenter, mnRadius, aURL, aAltText, aDesc, aTarget, aName, mbIsActive, false ));
+ }
+ break;
+
+ case IMapObjectType::Polygon:
+ default:
+ {
+ const sal_uInt16 nCount = static_cast<sal_uInt16>(maPolygon.getLength());
+
+ tools::Polygon aPoly( nCount );
+ for( sal_uInt16 nPoint = 0; nPoint < nCount; nPoint++ )
+ {
+ Point aPoint( maPolygon[nPoint].X, maPolygon[nPoint].Y );
+ aPoly.SetPoint( aPoint, nPoint );
+ }
+
+ aPoly.Optimize( PolyOptimizeFlags::CLOSE );
+ pNewIMapObject.reset(new IMapPolygonObject( aPoly, aURL, aAltText, aDesc, aTarget, aName, mbIsActive, false ));
+ }
+ break;
+ }
+
+ SvxMacroTableDtor aMacroTable;
+ mxEvents->copyMacrosIntoTable(aMacroTable);
+ pNewIMapObject->SetMacroTable( aMacroTable );
+
+ return pNewIMapObject;
+}
+
+// XInterface
+
+Any SAL_CALL SvUnoImageMapObject::queryInterface( const Type & rType )
+{
+ return OWeakAggObject::queryInterface( rType );
+}
+
+Any SAL_CALL SvUnoImageMapObject::queryAggregation( const Type & rType )
+{
+ Any aAny;
+
+ if( rType == cppu::UnoType<XServiceInfo>::get())
+ aAny <<= Reference< XServiceInfo >(this);
+ else if( rType == cppu::UnoType<XTypeProvider>::get())
+ aAny <<= Reference< XTypeProvider >(this);
+ else if( rType == cppu::UnoType<XPropertySet>::get())
+ aAny <<= Reference< XPropertySet >(this);
+ else if( rType == cppu::UnoType<XEventsSupplier>::get())
+ aAny <<= Reference< XEventsSupplier >(this);
+ else if( rType == cppu::UnoType<XMultiPropertySet>::get())
+ aAny <<= Reference< XMultiPropertySet >(this);
+ else if( rType == cppu::UnoType<XUnoTunnel>::get())
+ aAny <<= Reference< XUnoTunnel >(this);
+ else
+ aAny = OWeakAggObject::queryAggregation( rType );
+
+ return aAny;
+}
+
+void SAL_CALL SvUnoImageMapObject::acquire() noexcept
+{
+ OWeakAggObject::acquire();
+}
+
+void SAL_CALL SvUnoImageMapObject::release() noexcept
+{
+ OWeakAggObject::release();
+}
+
+uno::Sequence< uno::Type > SAL_CALL SvUnoImageMapObject::getTypes()
+{
+ static const uno::Sequence< uno::Type > aTypes {
+ cppu::UnoType<XAggregation>::get(),
+ cppu::UnoType<XEventsSupplier>::get(),
+ cppu::UnoType<XServiceInfo>::get(),
+ cppu::UnoType<XPropertySet>::get(),
+ cppu::UnoType<XMultiPropertySet>::get(),
+ cppu::UnoType<XTypeProvider>::get(),
+ cppu::UnoType<XUnoTunnel>::get() };
+ return aTypes;
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL SvUnoImageMapObject::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL SvUnoImageMapObject::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > SAL_CALL SvUnoImageMapObject::getSupportedServiceNames()
+{
+ Sequence< OUString > aSNS( 2 );
+ aSNS.getArray()[0] = "com.sun.star.image.ImageMapObject";
+ switch( mnType )
+ {
+ case IMapObjectType::Polygon:
+ default:
+ aSNS.getArray()[1] = "com.sun.star.image.ImageMapPolygonObject";
+ break;
+ case IMapObjectType::Rectangle:
+ aSNS.getArray()[1] = "com.sun.star.image.ImageMapRectangleObject";
+ break;
+ case IMapObjectType::Circle:
+ aSNS.getArray()[1] = "com.sun.star.image.ImageMapCircleObject";
+ break;
+ }
+ return aSNS;
+}
+
+OUString SAL_CALL SvUnoImageMapObject::getImplementationName()
+{
+ switch( mnType )
+ {
+ case IMapObjectType::Polygon:
+ default:
+ return "org.openoffice.comp.svt.ImageMapPolygonObject";
+ case IMapObjectType::Circle:
+ return "org.openoffice.comp.svt.ImageMapCircleObject";
+ case IMapObjectType::Rectangle:
+ return "org.openoffice.comp.svt.ImageMapRectangleObject";
+ }
+}
+
+// overridden helpers from PropertySetHelper
+void SvUnoImageMapObject::_setPropertyValues( const PropertyMapEntry** ppEntries, const Any* pValues )
+{
+ bool bOk = false;
+
+ while( *ppEntries )
+ {
+ switch( (*ppEntries)->mnHandle )
+ {
+ case HANDLE_URL:
+ bOk = *pValues >>= maURL;
+ break;
+ case HANDLE_TITLE:
+ bOk = *pValues >>= maAltText;
+ break;
+ case HANDLE_DESCRIPTION:
+ bOk = *pValues >>= maDesc;
+ break;
+ case HANDLE_TARGET:
+ bOk = *pValues >>= maTarget;
+ break;
+ case HANDLE_NAME:
+ bOk = *pValues >>= maName;
+ break;
+ case HANDLE_ISACTIVE:
+ bOk = *pValues >>= mbIsActive;
+ break;
+ case HANDLE_BOUNDARY:
+ bOk = *pValues >>= maBoundary;
+ break;
+ case HANDLE_CENTER:
+ bOk = *pValues >>= maCenter;
+ break;
+ case HANDLE_RADIUS:
+ bOk = *pValues >>= mnRadius;
+ break;
+ case HANDLE_POLYGON:
+ bOk = *pValues >>= maPolygon;
+ break;
+ default:
+ OSL_FAIL( "SvUnoImageMapObject::_setPropertyValues: unexpected property handle" );
+ break;
+ }
+
+ if( !bOk )
+ throw IllegalArgumentException();
+
+ ppEntries++;
+ pValues++;
+ }
+}
+
+void SvUnoImageMapObject::_getPropertyValues( const PropertyMapEntry** ppEntries, Any* pValues )
+{
+ while( *ppEntries )
+ {
+ switch( (*ppEntries)->mnHandle )
+ {
+ case HANDLE_URL:
+ *pValues <<= maURL;
+ break;
+ case HANDLE_TITLE:
+ *pValues <<= maAltText;
+ break;
+ case HANDLE_DESCRIPTION:
+ *pValues <<= maDesc;
+ break;
+ case HANDLE_TARGET:
+ *pValues <<= maTarget;
+ break;
+ case HANDLE_NAME:
+ *pValues <<= maName;
+ break;
+ case HANDLE_ISACTIVE:
+ *pValues <<= mbIsActive;
+ break;
+ case HANDLE_BOUNDARY:
+ *pValues <<= maBoundary;
+ break;
+ case HANDLE_CENTER:
+ *pValues <<= maCenter;
+ break;
+ case HANDLE_RADIUS:
+ *pValues <<= mnRadius;
+ break;
+ case HANDLE_POLYGON:
+ *pValues <<= maPolygon;
+ break;
+ default:
+ OSL_FAIL( "SvUnoImageMapObject::_getPropertyValues: unexpected property handle" );
+ break;
+ }
+
+ ppEntries++;
+ pValues++;
+ }
+}
+
+
+Reference< XNameReplace > SAL_CALL SvUnoImageMapObject::getEvents()
+{
+ return mxEvents;
+}
+
+namespace {
+
+class SvUnoImageMap : public WeakImplHelper< XIndexContainer, XServiceInfo, XUnoTunnel >
+{
+public:
+ explicit SvUnoImageMap();
+ SvUnoImageMap( const ImageMap& rMap, const SvEventDescription* pSupportedMacroItems );
+
+ void fillImageMap( ImageMap& rMap ) const;
+ /// @throws IllegalArgumentException
+ static SvUnoImageMapObject* getObject( const Any& aElement );
+
+ UNO3_GETIMPLEMENTATION_DECL( SvUnoImageMap )
+
+ // XIndexContainer
+ virtual void SAL_CALL insertByIndex( sal_Int32 Index, const Any& Element ) override;
+ virtual void SAL_CALL removeByIndex( sal_Int32 Index ) override;
+
+ // XIndexReplace
+ virtual void SAL_CALL replaceByIndex( sal_Int32 Index, const Any& Element ) override;
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount( ) override;
+ virtual Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+
+ // XElementAccess
+ virtual Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+private:
+ OUString maName;
+
+ std::vector< rtl::Reference<SvUnoImageMapObject> > maObjectList;
+};
+
+}
+
+UNO3_GETIMPLEMENTATION_IMPL( SvUnoImageMap );
+
+SvUnoImageMap::SvUnoImageMap()
+{
+}
+
+SvUnoImageMap::SvUnoImageMap( const ImageMap& rMap, const SvEventDescription* pSupportedMacroItems )
+{
+ maName = rMap.GetName();
+
+ const std::size_t nCount = rMap.GetIMapObjectCount();
+ for( std::size_t nPos = 0; nPos < nCount; nPos++ )
+ {
+ IMapObject* pMapObject = rMap.GetIMapObject( nPos );
+ rtl::Reference<SvUnoImageMapObject> xUnoObj = new SvUnoImageMapObject( *pMapObject, pSupportedMacroItems );
+ maObjectList.push_back( xUnoObj );
+ }
+}
+
+SvUnoImageMapObject* SvUnoImageMap::getObject( const Any& aElement )
+{
+ Reference< XInterface > xObject;
+ aElement >>= xObject;
+
+ SvUnoImageMapObject* pObject = comphelper::getFromUnoTunnel<SvUnoImageMapObject>( xObject );
+ if( nullptr == pObject )
+ throw IllegalArgumentException();
+
+ return pObject;
+}
+
+// XIndexContainer
+void SAL_CALL SvUnoImageMap::insertByIndex( sal_Int32 nIndex, const Any& Element )
+{
+ SvUnoImageMapObject* pObject = getObject( Element );
+ const sal_Int32 nCount = maObjectList.size();
+ if( nullptr == pObject || nIndex > nCount )
+ throw IndexOutOfBoundsException();
+
+ if( nIndex == nCount )
+ maObjectList.emplace_back(pObject );
+ else
+ {
+ auto aIter = maObjectList.begin();
+ std::advance(aIter, nIndex);
+ maObjectList.insert( aIter, pObject );
+ }
+}
+
+void SAL_CALL SvUnoImageMap::removeByIndex( sal_Int32 nIndex )
+{
+ const sal_Int32 nCount = maObjectList.size();
+ if( nIndex >= nCount )
+ throw IndexOutOfBoundsException();
+
+ if( nCount - 1 == nIndex )
+ {
+ maObjectList.pop_back();
+ }
+ else
+ {
+ auto aIter = maObjectList.begin();
+ std::advance(aIter, nIndex);
+ maObjectList.erase( aIter );
+ }
+}
+
+// XIndexReplace
+void SAL_CALL SvUnoImageMap::replaceByIndex( sal_Int32 nIndex, const Any& Element )
+{
+ SvUnoImageMapObject* pObject = getObject( Element );
+ const sal_Int32 nCount = maObjectList.size();
+ if( nullptr == pObject || nIndex >= nCount )
+ throw IndexOutOfBoundsException();
+
+ auto aIter = maObjectList.begin();
+ std::advance(aIter, nIndex);
+ *aIter = pObject;
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL SvUnoImageMap::getCount( )
+{
+ return maObjectList.size();
+}
+
+Any SAL_CALL SvUnoImageMap::getByIndex( sal_Int32 nIndex )
+{
+ const sal_Int32 nCount = maObjectList.size();
+ if( nIndex >= nCount )
+ throw IndexOutOfBoundsException();
+
+ auto aIter = maObjectList.begin();
+ std::advance(aIter, nIndex);
+
+ Reference< XPropertySet > xObj( *aIter );
+ return Any( xObj );
+}
+
+// XElementAccess
+Type SAL_CALL SvUnoImageMap::getElementType( )
+{
+ return cppu::UnoType<XPropertySet>::get();
+}
+
+sal_Bool SAL_CALL SvUnoImageMap::hasElements( )
+{
+ return (!maObjectList.empty());
+}
+
+// XServiceInfo
+OUString SAL_CALL SvUnoImageMap::getImplementationName( )
+{
+ return "org.openoffice.comp.svt.SvUnoImageMap";
+}
+
+sal_Bool SAL_CALL SvUnoImageMap::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > SAL_CALL SvUnoImageMap::getSupportedServiceNames( )
+{
+ return { "com.sun.star.image.ImageMap" };
+}
+
+void SvUnoImageMap::fillImageMap( ImageMap& rMap ) const
+{
+ rMap.ClearImageMap();
+
+ rMap.SetName( maName );
+
+ for (auto const& elem : maObjectList)
+ {
+ std::unique_ptr<IMapObject> pNewMapObject = elem->createIMapObject();
+ rMap.InsertIMapObject( std::move(pNewMapObject) );
+ }
+}
+
+
+// factory helper methods
+
+
+Reference< XInterface > SvUnoImageMapRectangleObject_createInstance( const SvEventDescription* pSupportedMacroItems )
+{
+ return static_cast<XWeak*>(new SvUnoImageMapObject( IMapObjectType::Rectangle, pSupportedMacroItems ));
+}
+
+Reference< XInterface > SvUnoImageMapCircleObject_createInstance( const SvEventDescription* pSupportedMacroItems )
+{
+ return static_cast<XWeak*>(new SvUnoImageMapObject( IMapObjectType::Circle, pSupportedMacroItems ));
+}
+
+Reference< XInterface > SvUnoImageMapPolygonObject_createInstance( const SvEventDescription* pSupportedMacroItems )
+{
+ return static_cast<XWeak*>(new SvUnoImageMapObject( IMapObjectType::Polygon, pSupportedMacroItems ));
+}
+
+Reference< XInterface > SvUnoImageMap_createInstance()
+{
+ return static_cast<XWeak*>(new SvUnoImageMap);
+}
+
+Reference< XInterface > SvUnoImageMap_createInstance( const ImageMap& rMap, const SvEventDescription* pSupportedMacroItems )
+{
+ return static_cast<XWeak*>(new SvUnoImageMap( rMap, pSupportedMacroItems ));
+}
+
+bool SvUnoImageMap_fillImageMap( const Reference< XInterface >& xImageMap, ImageMap& rMap )
+{
+ SvUnoImageMap* pUnoImageMap = comphelper::getFromUnoTunnel<SvUnoImageMap>( xImageMap );
+ if( nullptr == pUnoImageMap )
+ return false;
+
+ pUnoImageMap->fillImageMap( rMap );
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/wizard/unowizard.cxx b/svtools/source/uno/wizard/unowizard.cxx
new file mode 100644
index 000000000..0a73eb49a
--- /dev/null
+++ b/svtools/source/uno/wizard/unowizard.cxx
@@ -0,0 +1,452 @@
+/* -*- 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 <sal/config.h>
+
+#include <string_view>
+
+#include "wizardshell.hxx"
+
+#include <com/sun/star/container/NoSuchElementException.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/ucb/AlreadyInitializedException.hpp>
+#include <com/sun/star/ui/dialogs/XWizard.hpp>
+#include <com/sun/star/ui/dialogs/XWizardController.hpp>
+#include <com/sun/star/ui/dialogs/WizardButton.hpp>
+#include <com/sun/star/util/InvalidStateException.hpp>
+
+#include <comphelper/proparrhlp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <svtools/genericunodialog.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/mutex.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/urlobj.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::svt::uno;
+
+namespace {
+
+ using css::uno::Reference;
+ using css::uno::XInterface;
+ using css::uno::UNO_QUERY;
+ using css::uno::Any;
+ using css::uno::Sequence;
+ using css::ui::dialogs::XWizard;
+ using css::beans::XPropertySetInfo;
+ using css::uno::XComponentContext;
+ using css::beans::Property;
+ using css::lang::IllegalArgumentException;
+ using css::ucb::AlreadyInitializedException;
+ using css::ui::dialogs::XWizardController;
+ using css::ui::dialogs::XWizardPage;
+ using css::container::NoSuchElementException;
+ using css::util::InvalidStateException;
+ using css::awt::XWindow;
+
+ namespace WizardButton = css::ui::dialogs::WizardButton;
+
+ WizardButtonFlags lcl_convertWizardButtonToWZB( const sal_Int16 i_nWizardButton )
+ {
+ switch ( i_nWizardButton )
+ {
+ case WizardButton::NONE: return WizardButtonFlags::NONE;
+ case WizardButton::NEXT: return WizardButtonFlags::NEXT;
+ case WizardButton::PREVIOUS: return WizardButtonFlags::PREVIOUS;
+ case WizardButton::FINISH: return WizardButtonFlags::FINISH;
+ case WizardButton::CANCEL: return WizardButtonFlags::CANCEL;
+ case WizardButton::HELP: return WizardButtonFlags::HELP;
+ }
+ OSL_FAIL( "lcl_convertWizardButtonToWZB: invalid WizardButton constant!" );
+ return WizardButtonFlags::NONE;
+ }
+
+ typedef ::cppu::ImplInheritanceHelper < ::svt::OGenericUnoDialog
+ , ui::dialogs::XWizard
+ > Wizard_Base;
+ class Wizard;
+ typedef ::comphelper::OPropertyArrayUsageHelper< Wizard > Wizard_PBase;
+ class Wizard : public Wizard_Base
+ , public Wizard_PBase
+ {
+ public:
+ explicit Wizard( const css::uno::Reference< css::uno::XComponentContext >& i_rContext );
+
+ // lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // beans::XPropertySet
+ virtual css::uno::Reference< beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // ui::dialogs::XWizard
+ virtual OUString SAL_CALL getHelpURL() override;
+ virtual void SAL_CALL setHelpURL( const OUString& _helpurl ) override;
+ virtual css::uno::Reference< awt::XWindow > SAL_CALL getDialogWindow() override;
+ virtual css::uno::Reference< ui::dialogs::XWizardPage > SAL_CALL getCurrentPage( ) override;
+ virtual void SAL_CALL enableButton( ::sal_Int16 WizardButton, sal_Bool Enable ) override;
+ virtual void SAL_CALL setDefaultButton( ::sal_Int16 WizardButton ) override;
+ virtual sal_Bool SAL_CALL travelNext( ) override;
+ virtual sal_Bool SAL_CALL travelPrevious( ) override;
+ virtual void SAL_CALL enablePage( ::sal_Int16 PageID, sal_Bool Enable ) override;
+ virtual void SAL_CALL updateTravelUI( ) override;
+ virtual sal_Bool SAL_CALL advanceTo( ::sal_Int16 PageId ) override;
+ virtual sal_Bool SAL_CALL goBackTo( ::sal_Int16 PageId ) override;
+ virtual void SAL_CALL activatePath( ::sal_Int16 PathIndex, sal_Bool Final ) override;
+
+ // ui::dialogs::XExecutableDialog
+ virtual void SAL_CALL setTitle( const OUString& aTitle ) override;
+ virtual ::sal_Int16 SAL_CALL execute( ) override;
+
+ // lang::XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ protected:
+ virtual ~Wizard() override;
+
+ protected:
+ virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+
+ private:
+ css::uno::Sequence< css::uno::Sequence< sal_Int16 > > m_aWizardSteps;
+ css::uno::Reference< ui::dialogs::XWizardController > m_xController;
+ OUString m_sHelpURL;
+ };
+
+ Wizard::Wizard( const Reference< XComponentContext >& _rxContext )
+ :Wizard_Base( _rxContext )
+ {
+ }
+
+ OUString lcl_getHelpURL( std::string_view sHelpId )
+ {
+ OUStringBuffer aBuffer;
+ OUString aTmp(
+ OStringToOUString( sHelpId, RTL_TEXTENCODING_UTF8 ) );
+ INetURLObject aHID( aTmp );
+ if ( aHID.GetProtocol() == INetProtocol::NotValid )
+ aBuffer.append( INET_HID_SCHEME );
+ aBuffer.append( aTmp );
+ return aBuffer.makeStringAndClear();
+ }
+
+ Wizard::~Wizard()
+ {
+ if (m_xDialog)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (m_xDialog)
+ {
+ m_sHelpURL = lcl_getHelpURL(m_xDialog->get_help_id());
+ destroyDialog();
+ }
+ }
+ }
+
+ void lcl_checkPaths( const Sequence< Sequence< sal_Int16 > >& i_rPaths, const Reference< XInterface >& i_rContext )
+ {
+ // need at least one path
+ if ( !i_rPaths.hasElements() )
+ throw IllegalArgumentException( OUString(), i_rContext, 2 );
+
+ // each path must be of length 1, at least
+ sal_Int32 i = 0;
+ for ( const Sequence< sal_Int16 >& rPath : i_rPaths )
+ {
+ if ( !rPath.hasElements() )
+ throw IllegalArgumentException( OUString(), i_rContext, 2 );
+
+ // page IDs must be in ascending order
+ auto pPageId = std::adjacent_find(rPath.begin(), rPath.end(), std::greater_equal<sal_Int16>());
+ if (pPageId != rPath.end())
+ {
+ throw IllegalArgumentException(
+ "Path " + OUString::number(i)
+ + ": invalid page ID sequence - each page ID must be greater than the previous one.",
+ i_rContext, 2 );
+ }
+ ++i;
+ }
+
+ // if we have one path, that's okay
+ if ( i_rPaths.getLength() == 1 )
+ return;
+
+ // if we have multiple paths, they must start with the same page id
+ const sal_Int16 nFirstPageId = i_rPaths[0][0];
+ if (std::any_of(i_rPaths.begin(), i_rPaths.end(),
+ [nFirstPageId](const Sequence< sal_Int16 >& rPath) { return rPath[0] != nFirstPageId; }))
+ throw IllegalArgumentException(
+ "All paths must start with the same page id.",
+ i_rContext, 2 );
+ }
+
+ void SAL_CALL Wizard::initialize( const Sequence< Any >& i_Arguments )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bInitialized )
+ throw AlreadyInitializedException( OUString(), *this );
+
+ if ( i_Arguments.getLength() != 2 )
+ throw IllegalArgumentException( OUString(), *this, -1 );
+
+ // the second argument must be a XWizardController, for each constructor
+ m_xController.set( i_Arguments[1], UNO_QUERY );
+ if ( !m_xController.is() )
+ throw IllegalArgumentException( OUString(), *this, 2 );
+
+ // the first arg is either a single path (short[]), or multiple paths (short[][])
+ Sequence< sal_Int16 > aSinglePath;
+ i_Arguments[0] >>= aSinglePath;
+ Sequence< Sequence< sal_Int16 > > aMultiplePaths;
+ i_Arguments[0] >>= aMultiplePaths;
+
+ if ( !aMultiplePaths.hasElements() )
+ {
+ aMultiplePaths = { aSinglePath };
+ }
+ lcl_checkPaths( aMultiplePaths, *this );
+ // if we survived this, the paths are valid, and we're done here ...
+ m_aWizardSteps = aMultiplePaths;
+
+ m_bInitialized = true;
+ }
+
+ OString lcl_getHelpId( std::u16string_view _rHelpURL )
+ {
+ INetURLObject aHID( _rHelpURL );
+ if ( aHID.GetProtocol() == INetProtocol::Hid )
+ return OUStringToOString( aHID.GetURLPath(), RTL_TEXTENCODING_UTF8 );
+ else
+ return OUStringToOString( _rHelpURL, RTL_TEXTENCODING_UTF8 );
+ }
+
+ std::unique_ptr<weld::DialogController> Wizard::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+ {
+ auto xDialog = std::make_unique<WizardShell>(Application::GetFrameWeld(rParent), m_xController, m_aWizardSteps);
+ xDialog->set_help_id(lcl_getHelpId(m_sHelpURL));
+ xDialog->setTitleBase( m_sTitle );
+ return xDialog;
+ }
+
+ OUString SAL_CALL Wizard::getImplementationName()
+ {
+ return "com.sun.star.comp.svtools.uno.Wizard";
+ }
+
+ Sequence< OUString > SAL_CALL Wizard::getSupportedServiceNames()
+ {
+ return { "com.sun.star.ui.dialogs.Wizard" };
+ }
+
+ Reference< XPropertySetInfo > SAL_CALL Wizard::getPropertySetInfo()
+ {
+ return createPropertySetInfo( getInfoHelper() );
+ }
+
+ ::cppu::IPropertyArrayHelper& SAL_CALL Wizard::getInfoHelper()
+ {
+ return *getArrayHelper();
+ }
+
+ ::cppu::IPropertyArrayHelper* Wizard::createArrayHelper( ) const
+ {
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper( aProps );
+ }
+
+ OUString SAL_CALL Wizard::getHelpURL()
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if (!m_xDialog)
+ return m_sHelpURL;
+
+ return lcl_getHelpURL(m_xDialog->get_help_id());
+ }
+
+ void SAL_CALL Wizard::setHelpURL( const OUString& i_HelpURL )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if (!m_xDialog)
+ m_sHelpURL = i_HelpURL;
+ else
+ m_xDialog->set_help_id(lcl_getHelpId(i_HelpURL));
+ }
+
+ Reference< XWindow > SAL_CALL Wizard::getDialogWindow()
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ ENSURE_OR_RETURN( m_xDialog, "Wizard::getDialogWindow: illegal call (execution did not start, yet)!", nullptr );
+ return m_xDialog->getDialog()->GetXWindow();
+ }
+
+ void SAL_CALL Wizard::enableButton( ::sal_Int16 i_WizardButton, sal_Bool i_Enable )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ WizardShell* pWizardImpl = dynamic_cast<WizardShell*>(m_xDialog.get());
+ ENSURE_OR_RETURN_VOID( pWizardImpl, "Wizard::enableButtons: invalid dialog implementation!" );
+
+ pWizardImpl->enableButtons( lcl_convertWizardButtonToWZB( i_WizardButton ), i_Enable );
+ }
+
+ void SAL_CALL Wizard::setDefaultButton( ::sal_Int16 i_WizardButton )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ WizardShell* pWizardImpl = dynamic_cast<WizardShell*>(m_xDialog.get());
+ ENSURE_OR_RETURN_VOID( pWizardImpl, "Wizard::setDefaultButton: invalid dialog implementation!" );
+
+ pWizardImpl->defaultButton( lcl_convertWizardButtonToWZB( i_WizardButton ) );
+ }
+
+ sal_Bool SAL_CALL Wizard::travelNext( )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ WizardShell* pWizardImpl = dynamic_cast<WizardShell*>(m_xDialog.get());
+ ENSURE_OR_RETURN_FALSE( pWizardImpl, "Wizard::travelNext: invalid dialog implementation!" );
+
+ return pWizardImpl->travelNext();
+ }
+
+ sal_Bool SAL_CALL Wizard::travelPrevious( )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ WizardShell* pWizardImpl = dynamic_cast<WizardShell*>(m_xDialog.get());
+ ENSURE_OR_RETURN_FALSE( pWizardImpl, "Wizard::travelPrevious: invalid dialog implementation!" );
+
+ return pWizardImpl->travelPrevious();
+ }
+
+ void SAL_CALL Wizard::enablePage( ::sal_Int16 i_PageID, sal_Bool i_Enable )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ WizardShell* pWizardImpl = dynamic_cast<WizardShell*>(m_xDialog.get());
+ ENSURE_OR_RETURN_VOID( pWizardImpl, "Wizard::enablePage: invalid dialog implementation!" );
+
+ if ( !pWizardImpl->knowsPage( i_PageID ) )
+ throw NoSuchElementException( OUString(), *this );
+
+ if ( i_PageID == pWizardImpl->getCurrentPage() )
+ throw InvalidStateException( OUString(), *this );
+
+ pWizardImpl->enablePage( i_PageID, i_Enable );
+ }
+
+ void SAL_CALL Wizard::updateTravelUI( )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ WizardShell* pWizardImpl = dynamic_cast<WizardShell*>(m_xDialog.get());
+ ENSURE_OR_RETURN_VOID( pWizardImpl, "Wizard::updateTravelUI: invalid dialog implementation!" );
+
+ pWizardImpl->updateTravelUI();
+ }
+
+ sal_Bool SAL_CALL Wizard::advanceTo( ::sal_Int16 i_PageId )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ WizardShell* pWizardImpl = dynamic_cast<WizardShell*>(m_xDialog.get());
+ ENSURE_OR_RETURN_FALSE( pWizardImpl, "Wizard::advanceTo: invalid dialog implementation!" );
+
+ return pWizardImpl->advanceTo( i_PageId );
+ }
+
+ sal_Bool SAL_CALL Wizard::goBackTo( ::sal_Int16 i_PageId )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ WizardShell* pWizardImpl = dynamic_cast<WizardShell*>(m_xDialog.get());
+ ENSURE_OR_RETURN_FALSE( pWizardImpl, "Wizard::goBackTo: invalid dialog implementation!" );
+
+ return pWizardImpl->goBackTo( i_PageId );
+ }
+
+ Reference< XWizardPage > SAL_CALL Wizard::getCurrentPage( )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ WizardShell* pWizardImpl = dynamic_cast<WizardShell*>(m_xDialog.get());
+ ENSURE_OR_RETURN( pWizardImpl, "Wizard::getCurrentPage: invalid dialog implementation!", Reference< XWizardPage >() );
+
+ return pWizardImpl->getCurrentWizardPage();
+ }
+
+ void SAL_CALL Wizard::activatePath( ::sal_Int16 i_PathIndex, sal_Bool i_Final )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( ( i_PathIndex < 0 ) || ( i_PathIndex >= m_aWizardSteps.getLength() ) )
+ throw NoSuchElementException( OUString(), *this );
+
+ WizardShell* pWizardImpl = dynamic_cast<WizardShell*>(m_xDialog.get());
+ ENSURE_OR_RETURN_VOID( pWizardImpl, "Wizard::activatePath: invalid dialog implementation!" );
+
+ pWizardImpl->activatePath( i_PathIndex, i_Final );
+ }
+
+ void SAL_CALL Wizard::setTitle( const OUString& i_Title )
+ {
+ // simply disambiguate
+ Wizard_Base::OGenericUnoDialog::setTitle( i_Title );
+ }
+
+ ::sal_Int16 SAL_CALL Wizard::execute( )
+ {
+ return Wizard_Base::OGenericUnoDialog::execute();
+ }
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svtools_uno_Wizard_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new Wizard(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/wizard/wizardpagecontroller.cxx b/svtools/source/uno/wizard/wizardpagecontroller.cxx
new file mode 100644
index 000000000..69b864fbf
--- /dev/null
+++ b/svtools/source/uno/wizard/wizardpagecontroller.cxx
@@ -0,0 +1,130 @@
+/* -*- 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 "wizardpagecontroller.hxx"
+#include "wizardshell.hxx"
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/diagnose_ex.h>
+
+
+namespace svt::uno
+{
+
+
+ using css::uno::Reference;
+ using css::uno::UNO_SET_THROW;
+ using css::uno::Exception;
+ using css::ui::dialogs::XWizardController;
+ using css::awt::XWindow;
+
+ using namespace ::com::sun::star;
+
+
+ //= WizardPageController
+
+
+ WizardPageController::WizardPageController(weld::Container* pParent, const Reference< XWizardController >& i_rController,
+ const sal_Int16 i_nPageId )
+ :m_xController( i_rController )
+ ,m_xWizardPage()
+ {
+ ENSURE_OR_THROW( m_xController.is(), "no controller" );
+ try
+ {
+ // Plug a toplevel SalFrame into the native page which can host our awt widgetry
+ m_xWizardPage.set(m_xController->createPage(pParent->CreateChildFrame(), i_nPageId), UNO_SET_THROW);
+
+ Reference< XWindow > xPageWindow(m_xWizardPage->getWindow(), UNO_SET_THROW);
+ xPageWindow->setVisible( true );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+ }
+
+ WizardPageController::~WizardPageController()
+ {
+ try
+ {
+ if ( m_xWizardPage.is() )
+ m_xWizardPage->dispose();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+ }
+
+ void WizardPageController::initializePage()
+ {
+ if ( !m_xWizardPage.is() )
+ return;
+
+ try
+ {
+ m_xWizardPage->activatePage();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+ }
+
+ bool WizardPageController::commitPage( vcl::WizardTypes::CommitPageReason i_eReason )
+ {
+ if ( !m_xWizardPage.is() )
+ return true;
+
+ try
+ {
+ return m_xWizardPage->commitPage( WizardShell::convertCommitReasonToTravelType( i_eReason ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+
+ return true;
+ }
+
+ bool WizardPageController::canAdvance() const
+ {
+ if ( !m_xWizardPage.is() )
+ return true;
+
+ try
+ {
+ return m_xWizardPage->canAdvance();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+
+ return true;
+ }
+
+
+} // namespace svt::uno
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/wizard/wizardpagecontroller.hxx b/svtools/source/uno/wizard/wizardpagecontroller.hxx
new file mode 100644
index 000000000..68d724591
--- /dev/null
+++ b/svtools/source/uno/wizard/wizardpagecontroller.hxx
@@ -0,0 +1,62 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <vcl/wizardmachine.hxx>
+#include <com/sun/star/ui/dialogs/XWizardController.hpp>
+
+namespace svt::uno
+{
+
+
+ class WizardShell;
+
+
+ //= WizardPageController
+
+ class WizardPageController : public vcl::IWizardPageController
+ {
+ public:
+ WizardPageController(
+ weld::Container* pParent,
+ const css::uno::Reference< css::ui::dialogs::XWizardController >& i_rController,
+ const sal_Int16 i_nPageId
+ );
+ virtual ~WizardPageController();
+
+ // IWizardPageController overridables
+ virtual void initializePage() override;
+ virtual bool commitPage( vcl::WizardTypes::CommitPageReason _eReason ) override;
+ virtual bool canAdvance() const override;
+
+ const css::uno::Reference< css::ui::dialogs::XWizardPage >&
+ getWizardPage() const { return m_xWizardPage; }
+
+ private:
+ const css::uno::Reference< css::ui::dialogs::XWizardController > m_xController;
+ css::uno::Reference< css::ui::dialogs::XWizardPage > m_xWizardPage;
+ };
+
+
+} // namespace svt::uno
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/wizard/wizardshell.cxx b/svtools/source/uno/wizard/wizardshell.cxx
new file mode 100644
index 000000000..7c946f0cf
--- /dev/null
+++ b/svtools/source/uno/wizard/wizardshell.cxx
@@ -0,0 +1,257 @@
+/* -*- 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 "wizardshell.hxx"
+#include "wizardpagecontroller.hxx"
+
+#include <tools/diagnose_ex.h>
+
+#include <com/sun/star/ui/dialogs/WizardTravelType.hpp>
+
+using vcl::RoadmapWizardTypes::WizardPath;
+
+namespace svt::uno
+{
+
+
+ using css::uno::Reference;
+ using css::uno::Exception;
+ using css::uno::Sequence;
+ using css::ui::dialogs::XWizardController;
+ using css::ui::dialogs::XWizardPage;
+
+ namespace WizardTravelType = css::ui::dialogs::WizardTravelType;
+
+
+ namespace
+ {
+
+ sal_Int16 lcl_determineFirstPageID( const Sequence< Sequence< sal_Int16 > >& i_rPaths )
+ {
+ ENSURE_OR_THROW( i_rPaths.hasElements() && i_rPaths[0].hasElements(), "illegal paths" );
+ return i_rPaths[0][0];
+ }
+ }
+
+ //= WizardShell
+ WizardShell::WizardShell(weld::Window* i_pParent, const Reference< XWizardController >& i_rController,
+ const Sequence< Sequence< sal_Int16 > >& i_rPaths)
+ :WizardShell_Base( i_pParent )
+ ,m_xController( i_rController )
+ ,m_nFirstPageID( lcl_determineFirstPageID( i_rPaths ) )
+ {
+ ENSURE_OR_THROW( m_xController.is(), "invalid controller" );
+
+ // declare the paths
+ for ( sal_Int32 i=0; i<i_rPaths.getLength(); ++i )
+ {
+ const Sequence< sal_Int16 >& rPath( i_rPaths[i] );
+ WizardPath aPath( rPath.getLength() );
+ std::transform(rPath.begin(), rPath.end(), aPath.begin(),
+ [this](const sal_Int16 nPageId) -> WizardPath::value_type { return impl_pageIdToState(nPageId); });
+ declarePath( i, aPath );
+ }
+
+ // create the first page, to know the page size
+ GetOrCreatePage( impl_pageIdToState( i_rPaths[0][0] ) );
+ m_xAssistant->set_current_page(0);
+
+ // some defaults
+ enableAutomaticNextButtonState();
+ }
+
+ short WizardShell::run()
+ {
+ ActivatePage();
+ return WizardShell_Base::run();
+ }
+
+ sal_Int16 WizardShell::convertCommitReasonToTravelType( const CommitPageReason i_eReason )
+ {
+ switch ( i_eReason )
+ {
+ case vcl::WizardTypes::eTravelForward:
+ return WizardTravelType::FORWARD;
+
+ case vcl::WizardTypes::eTravelBackward:
+ return WizardTravelType::BACKWARD;
+
+ case vcl::WizardTypes::eFinish:
+ return WizardTravelType::FINISH;
+
+ default:
+ break;
+ }
+ OSL_FAIL( "WizardShell::convertCommitReasonToTravelType: unsupported CommitPageReason!" );
+ return WizardTravelType::FINISH;
+ }
+
+
+ void WizardShell::enterState( WizardState i_nState )
+ {
+ WizardShell_Base::enterState( i_nState );
+
+ if ( !m_xController.is() )
+ return;
+
+ try
+ {
+ m_xController->onActivatePage( impl_stateToPageId( i_nState ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+ }
+
+
+ bool WizardShell::leaveState( WizardState i_nState )
+ {
+ if ( !WizardShell_Base::leaveState( i_nState ) )
+ return false;
+
+ if ( !m_xController.is() )
+ return true;
+
+ try
+ {
+ m_xController->onDeactivatePage( impl_stateToPageId( i_nState ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+
+ return true;
+ }
+
+
+ PWizardPageController WizardShell::impl_getController(BuilderPage* i_pPage) const
+ {
+ Page2ControllerMap::const_iterator pos = m_aPageControllers.find( i_pPage );
+ ENSURE_OR_RETURN( pos != m_aPageControllers.end(), "WizardShell::impl_getController: no controller for this page!", PWizardPageController() );
+ return pos->second;
+ }
+
+
+ Reference< XWizardPage > WizardShell::getCurrentWizardPage() const
+ {
+ const WizardState eState = getCurrentState();
+
+ PWizardPageController pController( impl_getController( GetPage( eState ) ) );
+ ENSURE_OR_RETURN( pController, "WizardShell::getCurrentWizardPage: invalid page/controller!", nullptr );
+
+ return pController->getWizardPage();
+ }
+
+ void WizardShell::enablePage( const sal_Int16 i_nPageID, const bool i_bEnable )
+ {
+ enableState( impl_pageIdToState( i_nPageID ), i_bEnable );
+ }
+
+ namespace
+ {
+ class EmptyPage : public BuilderPage
+ {
+ public:
+ EmptyPage(weld::Widget* pParent, weld::DialogController* pController)
+ : BuilderPage(pParent, pController, "svt/ui/emptypage.ui", "EmptyPage")
+ {
+ m_xContainer->set_size_request(m_xContainer->get_approximate_digit_width() * 70,
+ m_xContainer->get_text_height() * 10);
+ }
+ weld::Container* GetContainer() const { return m_xContainer.get(); }
+ };
+ }
+
+ std::unique_ptr<BuilderPage> WizardShell::createPage( WizardState i_nState )
+ {
+ ENSURE_OR_RETURN( m_xController.is(), "WizardShell::createPage: no WizardController!", nullptr );
+
+ sal_Int16 nPageId = impl_stateToPageId(i_nState);
+
+ OString sIdent(OString::number(nPageId));
+ weld::Container* pPageContainer = m_xAssistant->append_page(sIdent);
+
+ auto xPage = std::make_unique<EmptyPage>(pPageContainer, this);
+ auto pController = std::make_shared<WizardPageController>(xPage->GetContainer(), m_xController, nPageId);
+
+ m_aPageControllers[xPage.get()] = pController;
+
+ return xPage;
+ }
+
+ vcl::IWizardPageController* WizardShell::getPageController(BuilderPage* i_pCurrentPage) const
+ {
+ return impl_getController( i_pCurrentPage ).get();
+ }
+
+ OUString WizardShell::getStateDisplayName( WizardState i_nState ) const
+ {
+ try
+ {
+ if ( m_xController.is() )
+ return m_xController->getPageTitle( impl_stateToPageId( i_nState ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+ // fallback for ill-behaved clients: the numeric state
+ return OUString::number(i_nState);
+ }
+
+
+ bool WizardShell::canAdvance() const
+ {
+ try
+ {
+ if ( m_xController.is() && !m_xController->canAdvance() )
+ return false;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+
+ return WizardShell_Base::canAdvance();
+ }
+
+
+ bool WizardShell::onFinish()
+ {
+ try
+ {
+ if ( m_xController.is() && !m_xController->confirmFinish() )
+ return false;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svtools.uno");
+ }
+
+ return WizardShell_Base::onFinish();
+ }
+
+
+} // namespace svt::uno
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/uno/wizard/wizardshell.hxx b/svtools/source/uno/wizard/wizardshell.hxx
new file mode 100644
index 000000000..a563ab954
--- /dev/null
+++ b/svtools/source/uno/wizard/wizardshell.hxx
@@ -0,0 +1,129 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/ui/dialogs/XWizardController.hpp>
+#include <vcl/roadmapwizard.hxx>
+#include <map>
+#include <memory>
+
+using vcl::WizardTypes::WizardState;
+using vcl::WizardTypes::CommitPageReason;
+
+namespace svt::uno
+{
+
+
+ class WizardPageController;
+ typedef std::shared_ptr< WizardPageController > PWizardPageController;
+
+
+ //= WizardShell
+
+ typedef ::vcl::RoadmapWizardMachine WizardShell_Base;
+ class WizardShell : public WizardShell_Base
+ {
+ public:
+ WizardShell(
+ weld::Window* pParent,
+ const css::uno::Reference< css::ui::dialogs::XWizardController >& i_rController,
+ const css::uno::Sequence< css::uno::Sequence< sal_Int16 > >& i_rPaths
+ );
+
+ // Dialog overridables
+ virtual short run() override;
+
+ // OWizardMachine overridables
+ virtual std::unique_ptr<BuilderPage> createPage( WizardState i_nState ) override;
+ virtual void enterState( WizardState i_nState ) override;
+ virtual bool leaveState( WizardState i_nState ) override;
+ virtual OUString getStateDisplayName( WizardState i_nState ) const override;
+ virtual bool canAdvance() const override;
+ virtual bool onFinish() override;
+ virtual vcl::IWizardPageController* getPageController(BuilderPage* pCurrentPage) const override;
+
+ static sal_Int16 convertCommitReasonToTravelType( const CommitPageReason i_eReason );
+
+ // operations
+ bool advanceTo( const sal_Int16 i_nPageId )
+ {
+ return skipUntil( impl_pageIdToState( i_nPageId ) );
+ }
+ bool goBackTo( const sal_Int16 i_nPageId )
+ {
+ return skipBackwardUntil( impl_pageIdToState( i_nPageId ) );
+ }
+ using WizardShell_Base::travelNext;
+ using WizardShell_Base::travelPrevious;
+
+ void activatePath( const sal_Int16 i_nPathID, const bool i_bFinal )
+ {
+ WizardShell_Base::activatePath( vcl::RoadmapWizardTypes::PathId( i_nPathID ), i_bFinal );
+ }
+
+ css::uno::Reference< css::ui::dialogs::XWizardPage >
+ getCurrentWizardPage() const;
+
+ sal_Int16 getCurrentPage() const
+ {
+ return impl_stateToPageId( getCurrentState() );
+ }
+
+ void enablePage( const sal_Int16 i_PageID, const bool i_Enable );
+
+ bool knowsPage( const sal_Int16 i_nPageID ) const
+ {
+ return knowsState( impl_pageIdToState( i_nPageID ) );
+ }
+
+ private:
+ sal_Int16 impl_stateToPageId( const WizardState i_nState ) const
+ {
+ return static_cast< sal_Int16 >( i_nState + m_nFirstPageID );
+ }
+
+ WizardState impl_pageIdToState( const sal_Int16 i_nPageId ) const
+ {
+ return static_cast<WizardState>(i_nPageId - m_nFirstPageID);
+ }
+
+ PWizardPageController impl_getController(BuilderPage* i_pPage) const;
+
+ // prevent outside access to some base class members
+ using WizardShell_Base::skip;
+ using WizardShell_Base::skipUntil;
+ using WizardShell_Base::skipBackwardUntil;
+ using WizardShell_Base::getCurrentState;
+ using WizardShell_Base::activatePath;
+
+ private:
+ typedef std::map<BuilderPage*, PWizardPageController> Page2ControllerMap;
+
+ const css::uno::Reference< css::ui::dialogs::XWizardController > m_xController;
+ const sal_Int16 m_nFirstPageID;
+ Page2ControllerMap m_aPageControllers;
+ };
+
+
+} // namespace svt::uno
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */