diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /svtools/source/uno | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'svtools/source/uno')
-rw-r--r-- | svtools/source/uno/addrtempuno.cxx | 213 | ||||
-rw-r--r-- | svtools/source/uno/fpicker.cxx | 178 | ||||
-rw-r--r-- | svtools/source/uno/fpicker.hxx | 45 | ||||
-rw-r--r-- | svtools/source/uno/framestatuslistener.cxx | 268 | ||||
-rw-r--r-- | svtools/source/uno/genericunodialog.cxx | 263 | ||||
-rw-r--r-- | svtools/source/uno/miscservices.cxx | 77 | ||||
-rw-r--r-- | svtools/source/uno/popupmenucontrollerbase.cxx | 366 | ||||
-rw-r--r-- | svtools/source/uno/popupwindowcontroller.cxx | 270 | ||||
-rw-r--r-- | svtools/source/uno/statusbarcontroller.cxx | 587 | ||||
-rw-r--r-- | svtools/source/uno/toolboxcontroller.cxx | 795 | ||||
-rw-r--r-- | svtools/source/uno/unoevent.cxx | 450 | ||||
-rw-r--r-- | svtools/source/uno/unoimap.cxx | 699 | ||||
-rw-r--r-- | svtools/source/uno/wizard/unowizard.cxx | 450 | ||||
-rw-r--r-- | svtools/source/uno/wizard/wizardpagecontroller.cxx | 136 | ||||
-rw-r--r-- | svtools/source/uno/wizard/wizardpagecontroller.hxx | 62 | ||||
-rw-r--r-- | svtools/source/uno/wizard/wizardshell.cxx | 267 | ||||
-rw-r--r-- | svtools/source/uno/wizard/wizardshell.hxx | 132 |
17 files changed, 5258 insertions, 0 deletions
diff --git a/svtools/source/uno/addrtempuno.cxx b/svtools/source/uno/addrtempuno.cxx new file mode 100644 index 0000000000..54cb28afc0 --- /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 0000000000..e02d8abebb --- /dev/null +++ b/svtools/source/uno/fpicker.cxx @@ -0,0 +1,178 @@ +/* -*- 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 +} + +// Ensure that we use not the system file dialogs as headless mode relies on +// Application::EnableHeadlessMode() which only works for VCL dialogs +static bool UseSystemFileDialog() +{ + return !Application::IsHeadlessModeEnabled() && officecfg::Office::Common::Misc::UseSystemFileDialog::get(); +} + +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() && UseSystemFileDialog()) + { + 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() && UseSystemFileDialog()) + { + 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 0000000000..9fcbacd548 --- /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 0000000000..166433dff1 --- /dev/null +++ b/svtools/source/uno/framestatuslistener.cxx @@ -0,0 +1,268 @@ +/* -*- 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 ) + return; + + 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; + + aDispatchVector.push_back( Listener( std::move(aTargetURL), xDispatch ) ); + } + } + } + + // 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 0000000000..349d9a73a4 --- /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 <comphelper/diagnose_ex.hxx> +#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 0000000000..625b336c5e --- /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 0000000000..61df2a4645 --- /dev/null +++ b/svtools/source/uno/popupmenucontrollerbase.cxx @@ -0,0 +1,366 @@ +/* -*- 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 <utility> +#include <vcl/svapp.hxx> +#include <osl/mutex.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <toolkit/awt/vclxmenu.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, URL aURL, const Sequence< PropertyValue >& rArgs ) + : mxDispatch( xDispatch ), maURL(std::move( aURL )), maArgs( rArgs ) {} +}; + +} + +PopupMenuControllerBase::PopupMenuControllerBase( const Reference< XComponentContext >& xContext ) : + m_bInitialized( false ) +{ + if ( xContext.is() ) + m_xURLTransformer.set( util::URLTransformer::create( xContext ) ); +} + +PopupMenuControllerBase::~PopupMenuControllerBase() +{ +} + +// protected function +void PopupMenuControllerBase::resetPopupMenu( css::uno::Reference< css::awt::XPopupMenu > const & rPopupMenu ) +{ + if ( rPopupMenu.is() && rPopupMenu->getItemCount() > 0 ) + { + rPopupMenu->clear(); + } +} + +void PopupMenuControllerBase::disposing(std::unique_lock<std::mutex>& /*rGuard*/) +{ + // Reset our members and set disposed flag + 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& ) +{ + std::unique_lock 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 ) +{ + std::unique_lock aLock( m_aMutex ); + throwIfDisposed(aLock); + + if( m_xPopupMenu.is() ) + { + Sequence<PropertyValue> aArgs; + dispatchCommandImpl( aLock, m_xPopupMenu->getCommand( rEvent.MenuId ), aArgs, OUString() ); + } +} + +void PopupMenuControllerBase::dispatchCommand( const OUString& sCommandURL, + const css::uno::Sequence< css::beans::PropertyValue >& rArgs, + const OUString& sTarget ) +{ + std::unique_lock aLock( m_aMutex ); + throwIfDisposed(aLock); + dispatchCommandImpl(aLock, sCommandURL, rArgs, sTarget); +} + +void PopupMenuControllerBase::dispatchCommandImpl( std::unique_lock<std::mutex>& /*rGuard*/, + const OUString& sCommandURL, + const css::uno::Sequence< css::beans::PropertyValue >& rArgs, + const OUString& sTarget ) +{ + + 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, std::move(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() +{ + { + std::unique_lock aLock(m_aMutex); + throwIfDisposed(aLock); + } + + updateCommand( m_aCommandURL ); +} + +void PopupMenuControllerBase::updateCommand( const OUString& rCommandURL ) +{ + std::unique_lock aLock( m_aMutex ); + Reference< XStatusListener > xStatusListener(this); + Reference< XDispatch > xDispatch( m_xDispatch ); + URL aTargetURL; + aTargetURL.Complete = rCommandURL; + m_xURLTransformer->parseStrict( aTargetURL ); + aLock.unlock(); + + // 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 + std::unique_lock aLock( m_aMutex ); + throwIfDisposed(aLock); + + 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! + { + std::unique_lock aLock(m_aMutex); + throwIfDisposed(aLock); + } + + 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 + std::unique_lock aLock( m_aMutex ); + throwIfDisposed(aLock); +} + +void SAL_CALL +PopupMenuControllerBase::addStatusListener( + const Reference< XStatusListener >& xControl, + const URL& aURL ) +{ + std::unique_lock aLock( m_aMutex ); + throwIfDisposed(aLock); + + bool bStatusUpdate( false ); + maStatusListeners.addInterface( aLock, xControl ); + + if ( aURL.Complete.startsWith( m_aBaseURL ) ) + bStatusUpdate = true; + aLock.unlock(); + + 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*/ ) +{ + std::unique_lock aLock( m_aMutex ); + maStatusListeners.removeInterface( aLock, xControl ); +} + +OUString PopupMenuControllerBase::determineBaseURL( std::u16string_view aURL ) +{ + // Just use the main part of the URL for popup menu controllers + OUString aMainURL( "vnd.sun.star.popup:" ); + + size_t nSchemePart = aURL.find( ':' ); + if (( nSchemePart != std::u16string_view::npos && nSchemePart > 0 ) && + ( aURL.size() > ( nSchemePart+1 ))) + { + size_t nQueryPart = aURL.find( '?', nSchemePart ); + if ( nQueryPart != std::u16string_view::npos && nQueryPart > 0 ) + aMainURL += aURL.substr( nSchemePart, nQueryPart-nSchemePart ); + else if ( nQueryPart == std::u16string_view::npos ) + aMainURL += aURL.substr( nSchemePart+1 ); + } + + return aMainURL; +} + +// XInitialization +void SAL_CALL PopupMenuControllerBase::initialize( const Sequence< Any >& aArguments ) +{ + std::unique_lock aLock( m_aMutex ); + initializeImpl(aLock, aArguments); +} + +// XInitialization +void PopupMenuControllerBase::initializeImpl( std::unique_lock<std::mutex>& /*rGuard*/, const Sequence< Any >& aArguments ) +{ + 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 ) +{ + { + std::unique_lock aLock( m_aMutex ); + throwIfDisposed(aLock); + + if ( !m_xFrame.is() || m_xPopupMenu.is() ) + return; + + // Create popup menu on demand + SolarMutexGuard aSolarMutexGuard; + + m_xPopupMenu = dynamic_cast<VCLXPopupMenu*>(xPopupMenu.get()); + assert(bool(xPopupMenu) == bool(m_xPopupMenu) && "we only support VCLXPopupMenu"); + 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 0000000000..63326fcf57 --- /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) + { + m_pToolbar->set_item_active(m_aCommandURL, bValue); + m_pToolbar->set_item_sensitive(m_aCommandURL, 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 VCLUnoHelper::GetInterface(pWin.get()); + } + } + return Reference< awt::XWindow >(); +} + +void SAL_CALL PopupWindowController::click() +{ + if (m_pToolbar) + { + if (m_pToolbar->get_menu_item_active(m_aCommandURL)) + createPopupWindow(); + else + mxPopoverContainer->unsetPopover(); + } + + svt::ToolboxController::click(); +} + +void PopupWindowController::EndPopupMode() +{ + if (m_pToolbar) + m_pToolbar->set_menu_item_active(m_aCommandURL, 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 0000000000..7ab3a2e29c --- /dev/null +++ b/svtools/source/uno/statusbarcontroller.cxx @@ -0,0 +1,587 @@ +/* -*- 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 <utility> +#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, + OUString aCommandURL, + unsigned short nID ) : + OWeakObject() + , m_bInitialized( false ) + , m_bDisposed( false ) + , m_nID( nID ) + , m_xFrame( xFrame ) + , m_xContext( rxContext ) + , m_aCommandURL(std::move( 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 ) +{ + SolarMutexGuard aSolarMutexGuard; + + if ( m_bDisposed ) + throw DisposedException(); + + if ( m_bInitialized ) + return; + + 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 ) + return; + } + + 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; + + aDispatchVector.push_back( Listener( std::move(aTargetURL), xDispatch ) ); + } + } + } + + // 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/toolboxcontroller.cxx b/svtools/source/uno/toolboxcontroller.cxx new file mode 100644 index 0000000000..90f44c1d5e --- /dev/null +++ b/svtools/source/uno/toolboxcontroller.cxx @@ -0,0 +1,795 @@ +/* -*- 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 <utility> +#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 OUString TOOLBARCONTROLLER_PROPNAME_SUPPORTSVISIBLE = u"SupportsVisible"_ustr; + + +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, + 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(std::move( 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 ) +{ + SolarMutexGuard aSolarMutexGuard; + + if ( m_bDisposed ) + throw DisposedException(); + + if ( m_bInitialized ) + return; + + 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 ) + return; + } + + 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; + + aDispatchVector.push_back( Listener( aTargetURL, xDispatch ) ); + } + } + } + + // 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, std::move(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/unoevent.cxx b/svtools/source/uno/unoevent.cxx new file mode 100644 index 0000000000..2266d65f2d --- /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 OUString sAPI_ServiceName = u"com.sun.star.container.XNameReplace"_ustr; +constexpr OUString sEventType = u"EventType"_ustr; +constexpr OUString sMacroName = u"MacroName"_ustr; +constexpr OUString sLibrary = u"Library"_ustr; +constexpr OUString sStarBasic = u"StarBasic"_ustr; +constexpr OUString sScript = u"Script"_ustr; +constexpr OUString sNone = u"None"_ustr; + +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, 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, 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, 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/unoimap.cxx b/svtools/source/uno/unoimap.cxx new file mode 100644 index 0000000000..1776f2ce73 --- /dev/null +++ b/svtools/source/uno/unoimap.cxx @@ -0,0 +1,699 @@ +/* -*- 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/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/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 OWeakObject, + public XEventsSupplier, + public XServiceInfo, + public PropertySetHelper, + public XTypeProvider +{ +public: + SvUnoImageMapObject( IMapObjectType nType, const SvEventDescription* pSupportedMacroItems ); + SvUnoImageMapObject( const IMapObject& rMapObject, const SvEventDescription* pSupportedMacroItems ); + + 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 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; +}; + +} + +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 ) +{ + 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 + aAny = OWeakObject::queryInterface( rType ); + + return aAny; +} + +void SAL_CALL SvUnoImageMapObject::acquire() noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL SvUnoImageMapObject::release() noexcept +{ + OWeakObject::release(); +} + +uno::Sequence< uno::Type > SAL_CALL SvUnoImageMapObject::getTypes() +{ + static const uno::Sequence< uno::Type > aTypes { + cppu::UnoType<XEventsSupplier>::get(), + cppu::UnoType<XServiceInfo>::get(), + cppu::UnoType<XPropertySet>::get(), + cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<XTypeProvider>::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 > +{ +public: + explicit SvUnoImageMap(); + SvUnoImageMap( const ImageMap& rMap, const SvEventDescription* pSupportedMacroItems ); + + void fillImageMap( ImageMap& rMap ) const; + /// @throws IllegalArgumentException + static SvUnoImageMapObject* getObject( const Any& aElement ); + + // 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; +}; + +} + +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 = dynamic_cast<SvUnoImageMapObject*>( xObject.get() ); + 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 getXWeak(new SvUnoImageMapObject( IMapObjectType::Rectangle, pSupportedMacroItems )); +} + +Reference< XInterface > SvUnoImageMapCircleObject_createInstance( const SvEventDescription* pSupportedMacroItems ) +{ + return getXWeak(new SvUnoImageMapObject( IMapObjectType::Circle, pSupportedMacroItems )); +} + +Reference< XInterface > SvUnoImageMapPolygonObject_createInstance( const SvEventDescription* pSupportedMacroItems ) +{ + return getXWeak(new SvUnoImageMapObject( IMapObjectType::Polygon, pSupportedMacroItems )); +} + +Reference< XInterface > SvUnoImageMap_createInstance() +{ + return getXWeak(new SvUnoImageMap); +} + +Reference< XInterface > SvUnoImageMap_createInstance( const ImageMap& rMap, const SvEventDescription* pSupportedMacroItems ) +{ + return getXWeak(new SvUnoImageMap( rMap, pSupportedMacroItems )); +} + +bool SvUnoImageMap_fillImageMap( const Reference< XInterface >& xImageMap, ImageMap& rMap ) +{ + SvUnoImageMap* pUnoImageMap = dynamic_cast<SvUnoImageMap*>( xImageMap.get() ); + 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 0000000000..4ec742a24a --- /dev/null +++ b/svtools/source/uno/wizard/unowizard.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 <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 <comphelper/diagnose_ex.hxx> +#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::u16string_view sHelpId ) + { + OUStringBuffer aBuffer; + INetURLObject aHID(sHelpId); + if ( aHID.GetProtocol() == INetProtocol::NotValid ) + aBuffer.append( INET_HID_SCHEME ); + aBuffer.append(sHelpId); + 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; + } + + OUString lcl_getHelpId( const OUString& _rHelpURL ) + { + INetURLObject aHID( _rHelpURL ); + if ( aHID.GetProtocol() == INetProtocol::Hid ) + return aHID.GetURLPath(); + else + return _rHelpURL; + } + + 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 0000000000..67776a38e9 --- /dev/null +++ b/svtools/source/uno/wizard/wizardpagecontroller.cxx @@ -0,0 +1,136 @@ +/* -*- 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 <comphelper/diagnose_ex.hxx> + + +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 + css::uno::Reference<css::awt::XWindow> xChildFrame = pParent->CreateChildFrame(); + m_xWizardPage.set(m_xController->createPage(xChildFrame, i_nPageId), UNO_SET_THROW); + + css::uno::Reference<css::awt::XWindow> xPageWindow(m_xWizardPage->getWindow(), UNO_SET_THROW); + + // tdf#132110 use the current size of the child as the size request + com::sun::star::awt::Rectangle aChildRect = xPageWindow->getPosSize(); + pParent->set_size_request(aChildRect.Width, aChildRect.Height); + + 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 0000000000..68d724591f --- /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 0000000000..d9cbca5874 --- /dev/null +++ b/svtools/source/uno/wizard/wizardshell.cxx @@ -0,0 +1,267 @@ +/* -*- 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 <comphelper/diagnose_ex.hxx> + +#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(); + } + + OUString WizardShell::getPageIdentForState(WizardState nState) const + { + return OUString::number(impl_stateToPageId(nState)); + } + + WizardState WizardShell::getStateFromPageIdent(const OUString& rIdent) const + { + return impl_pageIdToState(rIdent.toInt32()); + } + + 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); + + OUString sIdent(OUString::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 0000000000..eb2e8150bc --- /dev/null +++ b/svtools/source/uno/wizard/wizardshell.hxx @@ -0,0 +1,132 @@ +/* -*- 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; + + virtual OUString getPageIdentForState(WizardState nState) const override; + virtual WizardState getStateFromPageIdent(const OUString& rIdent) const override; + + // 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: */ |