summaryrefslogtreecommitdiffstats
path: root/extensions/source/propctrlr
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /extensions/source/propctrlr
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--extensions/source/propctrlr/MasterDetailLinkDialog.cxx133
-rw-r--r--extensions/source/propctrlr/MasterDetailLinkDialog.hxx67
-rw-r--r--extensions/source/propctrlr/browserline.cxx405
-rw-r--r--extensions/source/propctrlr/browserline.hxx127
-rw-r--r--extensions/source/propctrlr/browserlistbox.cxx817
-rw-r--r--extensions/source/propctrlr/browserlistbox.hxx163
-rw-r--r--extensions/source/propctrlr/browserpage.cxx41
-rw-r--r--extensions/source/propctrlr/browserpage.hxx61
-rw-r--r--extensions/source/propctrlr/browserview.cxx64
-rw-r--r--extensions/source/propctrlr/browserview.hxx56
-rw-r--r--extensions/source/propctrlr/buttonnavigationhandler.cxx268
-rw-r--r--extensions/source/propctrlr/buttonnavigationhandler.hxx71
-rw-r--r--extensions/source/propctrlr/cellbindinghandler.cxx487
-rw-r--r--extensions/source/propctrlr/cellbindinghandler.hxx92
-rw-r--r--extensions/source/propctrlr/cellbindinghelper.cxx540
-rw-r--r--extensions/source/propctrlr/cellbindinghelper.hxx272
-rw-r--r--extensions/source/propctrlr/commoncontrol.cxx134
-rw-r--r--extensions/source/propctrlr/commoncontrol.hxx208
-rw-r--r--extensions/source/propctrlr/composeduiupdate.cxx786
-rw-r--r--extensions/source/propctrlr/composeduiupdate.hxx208
-rw-r--r--extensions/source/propctrlr/controlfontdialog.cxx148
-rw-r--r--extensions/source/propctrlr/controlfontdialog.hxx82
-rw-r--r--extensions/source/propctrlr/controltype.hxx35
-rw-r--r--extensions/source/propctrlr/defaultforminspection.cxx215
-rw-r--r--extensions/source/propctrlr/defaultforminspection.hxx66
-rw-r--r--extensions/source/propctrlr/defaulthelpprovider.cxx184
-rw-r--r--extensions/source/propctrlr/defaulthelpprovider.hxx78
-rw-r--r--extensions/source/propctrlr/editpropertyhandler.cxx308
-rw-r--r--extensions/source/propctrlr/editpropertyhandler.hxx68
-rw-r--r--extensions/source/propctrlr/eformshelper.cxx762
-rw-r--r--extensions/source/propctrlr/eformshelper.hxx255
-rw-r--r--extensions/source/propctrlr/eformspropertyhandler.cxx598
-rw-r--r--extensions/source/propctrlr/eformspropertyhandler.hxx95
-rw-r--r--extensions/source/propctrlr/enumrepresentation.hxx62
-rw-r--r--extensions/source/propctrlr/eventhandler.cxx1112
-rw-r--r--extensions/source/propctrlr/eventhandler.hxx241
-rw-r--r--extensions/source/propctrlr/fontdialog.cxx572
-rw-r--r--extensions/source/propctrlr/fontdialog.hxx68
-rw-r--r--extensions/source/propctrlr/fontitemids.hxx48
-rw-r--r--extensions/source/propctrlr/formbrowsertools.cxx132
-rw-r--r--extensions/source/propctrlr/formbrowsertools.hxx89
-rw-r--r--extensions/source/propctrlr/formcomponenthandler.cxx3305
-rw-r--r--extensions/source/propctrlr/formcomponenthandler.hxx435
-rw-r--r--extensions/source/propctrlr/formcontroller.cxx241
-rw-r--r--extensions/source/propctrlr/formcontroller.hxx103
-rw-r--r--extensions/source/propctrlr/formgeometryhandler.cxx820
-rw-r--r--extensions/source/propctrlr/formlinkdialog.cxx630
-rw-r--r--extensions/source/propctrlr/formlinkdialog.hxx127
-rw-r--r--extensions/source/propctrlr/formmetadata.cxx694
-rw-r--r--extensions/source/propctrlr/formmetadata.hxx345
-rw-r--r--extensions/source/propctrlr/formstrings.hxx302
-rw-r--r--extensions/source/propctrlr/genericpropertyhandler.cxx619
-rw-r--r--extensions/source/propctrlr/genericpropertyhandler.hxx139
-rw-r--r--extensions/source/propctrlr/handlerhelper.cxx314
-rw-r--r--extensions/source/propctrlr/handlerhelper.hxx231
-rw-r--r--extensions/source/propctrlr/inspectorhelpwindow.cxx42
-rw-r--r--extensions/source/propctrlr/inspectorhelpwindow.hxx44
-rw-r--r--extensions/source/propctrlr/inspectormodelbase.cxx246
-rw-r--r--extensions/source/propctrlr/inspectormodelbase.hxx93
-rw-r--r--extensions/source/propctrlr/linedescriptor.hxx51
-rw-r--r--extensions/source/propctrlr/listselectiondlg.cxx138
-rw-r--r--extensions/source/propctrlr/listselectiondlg.hxx60
-rw-r--r--extensions/source/propctrlr/modulepcr.cxx30
-rw-r--r--extensions/source/propctrlr/modulepcr.hxx30
-rw-r--r--extensions/source/propctrlr/newdatatype.cxx79
-rw-r--r--extensions/source/propctrlr/newdatatype.hxx53
-rw-r--r--extensions/source/propctrlr/objectinspectormodel.cxx194
-rw-r--r--extensions/source/propctrlr/pcr.component103
-rw-r--r--extensions/source/propctrlr/pcrcommon.cxx60
-rw-r--r--extensions/source/propctrlr/pcrcommon.hxx121
-rw-r--r--extensions/source/propctrlr/pcrcommontypes.hxx33
-rw-r--r--extensions/source/propctrlr/pcrstrings.hxx35
-rw-r--r--extensions/source/propctrlr/pcrunodialogs.cxx143
-rw-r--r--extensions/source/propctrlr/pcrunodialogs.hxx79
-rw-r--r--extensions/source/propctrlr/propcontroller.cxx1652
-rw-r--r--extensions/source/propctrlr/propcontroller.hxx368
-rw-r--r--extensions/source/propctrlr/propcontrolobserver.hxx46
-rw-r--r--extensions/source/propctrlr/propertycomposer.cxx484
-rw-r--r--extensions/source/propctrlr/propertycomposer.hxx142
-rw-r--r--extensions/source/propctrlr/propertycontrolextender.cxx125
-rw-r--r--extensions/source/propctrlr/propertycontrolextender.hxx63
-rw-r--r--extensions/source/propctrlr/propertyeditor.cxx380
-rw-r--r--extensions/source/propctrlr/propertyeditor.hxx134
-rw-r--r--extensions/source/propctrlr/propertyhandler.cxx421
-rw-r--r--extensions/source/propctrlr/propertyhandler.hxx369
-rw-r--r--extensions/source/propctrlr/propertyinfo.hxx50
-rw-r--r--extensions/source/propctrlr/propeventtranslation.cxx89
-rw-r--r--extensions/source/propctrlr/propeventtranslation.hxx70
-rw-r--r--extensions/source/propctrlr/proplinelistener.hxx43
-rw-r--r--extensions/source/propctrlr/pushbuttonnavigation.cxx298
-rw-r--r--extensions/source/propctrlr/pushbuttonnavigation.hxx98
-rw-r--r--extensions/source/propctrlr/selectlabeldialog.cxx279
-rw-r--r--extensions/source/propctrlr/selectlabeldialog.hxx62
-rw-r--r--extensions/source/propctrlr/sqlcommanddesign.cxx355
-rw-r--r--extensions/source/propctrlr/sqlcommanddesign.hxx193
-rw-r--r--extensions/source/propctrlr/standardcontrol.cxx865
-rw-r--r--extensions/source/propctrlr/standardcontrol.hxx412
-rw-r--r--extensions/source/propctrlr/stringrepresentation.cxx604
-rw-r--r--extensions/source/propctrlr/submissionhandler.cxx431
-rw-r--r--extensions/source/propctrlr/submissionhandler.hxx110
-rw-r--r--extensions/source/propctrlr/taborder.cxx320
-rw-r--r--extensions/source/propctrlr/taborder.hxx74
-rw-r--r--extensions/source/propctrlr/unourl.cxx65
-rw-r--r--extensions/source/propctrlr/unourl.hxx50
-rw-r--r--extensions/source/propctrlr/usercontrol.cxx276
-rw-r--r--extensions/source/propctrlr/usercontrol.hxx148
-rw-r--r--extensions/source/propctrlr/xsddatatypes.cxx185
-rw-r--r--extensions/source/propctrlr/xsddatatypes.hxx89
-rw-r--r--extensions/source/propctrlr/xsdvalidationhelper.cxx406
-rw-r--r--extensions/source/propctrlr/xsdvalidationhelper.hxx137
-rw-r--r--extensions/source/propctrlr/xsdvalidationpropertyhandler.cxx673
-rw-r--r--extensions/source/propctrlr/xsdvalidationpropertyhandler.hxx88
112 files changed, 30811 insertions, 0 deletions
diff --git a/extensions/source/propctrlr/MasterDetailLinkDialog.cxx b/extensions/source/propctrlr/MasterDetailLinkDialog.cxx
new file mode 100644
index 000000000..5f38856fc
--- /dev/null
+++ b/extensions/source/propctrlr/MasterDetailLinkDialog.cxx
@@ -0,0 +1,133 @@
+/* -*- 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/log.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <vcl/svapp.hxx>
+#include "MasterDetailLinkDialog.hxx"
+#include "formlinkdialog.hxx"
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+
+ MasterDetailLinkDialog::MasterDetailLinkDialog(const Reference< XComponentContext >& _rxContext )
+ :OGenericUnoDialog( _rxContext )
+ {
+ }
+
+ Sequence<sal_Int8> SAL_CALL MasterDetailLinkDialog::getImplementationId( )
+ {
+ return css::uno::Sequence<sal_Int8>();
+ }
+
+
+ OUString SAL_CALL MasterDetailLinkDialog::getImplementationName()
+ {
+ return "org.openoffice.comp.form.ui.MasterDetailLinkDialog";
+ }
+
+
+ css::uno::Sequence<OUString> SAL_CALL MasterDetailLinkDialog::getSupportedServiceNames()
+ {
+ return { "com.sun.star.form.MasterDetailLinkDialog" };
+ }
+
+
+ Reference<XPropertySetInfo> SAL_CALL MasterDetailLinkDialog::getPropertySetInfo()
+ {
+ Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+ }
+
+
+ ::cppu::IPropertyArrayHelper& MasterDetailLinkDialog::getInfoHelper()
+ {
+ return *getArrayHelper();
+ }
+
+
+ ::cppu::IPropertyArrayHelper* MasterDetailLinkDialog::createArrayHelper( ) const
+ {
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+ }
+
+ std::unique_ptr<weld::DialogController> MasterDetailLinkDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+ {
+ return std::make_unique<FormLinkDialog>(Application::GetFrameWeld(rParent), m_xDetail,
+ m_xMaster, m_aContext, m_sExplanation,
+ m_sDetailLabel, m_sMasterLabel);
+ }
+
+ void MasterDetailLinkDialog::implInitialize(const Any& _rValue)
+ {
+ PropertyValue aProperty;
+ if (_rValue >>= aProperty)
+ {
+ if (aProperty.Name == "Detail")
+ {
+ if ( ! (aProperty.Value >>= m_xDetail) )
+ SAL_WARN("extensions.propctrlr", "implInitialize: unable to get property Detail");
+ return;
+ }
+ else if (aProperty.Name == "Master")
+ {
+ if ( ! (aProperty.Value >>= m_xMaster) )
+ SAL_WARN("extensions.propctrlr", "implInitialize: unable to get property Master");
+ return;
+ }
+ else if (aProperty.Name == "Explanation")
+ {
+ if ( ! (aProperty.Value >>= m_sExplanation) )
+ SAL_WARN("extensions.propctrlr", "implInitialize: unable to get property Explanation");
+ return;
+ }
+ else if (aProperty.Name == "DetailLabel")
+ {
+ if ( ! (aProperty.Value >>= m_sDetailLabel) )
+ SAL_WARN("extensions.propctrlr", "implInitialize: unable to get property DetailLabel");
+ return;
+ }
+ else if (aProperty.Name == "MasterLabel")
+ {
+ if ( ! (aProperty.Value >>= m_sMasterLabel) )
+ SAL_WARN("extensions.propctrlr", "implInitialize: unable to get property MasterLabel");
+ return;
+ }
+ }
+ MasterDetailLinkDialog_DBase::implInitialize(_rValue);
+ }
+
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_MasterDetailLinkDialog_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::MasterDetailLinkDialog(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/MasterDetailLinkDialog.hxx b/extensions/source/propctrlr/MasterDetailLinkDialog.hxx
new file mode 100644
index 000000000..97911436a
--- /dev/null
+++ b/extensions/source/propctrlr/MasterDetailLinkDialog.hxx
@@ -0,0 +1,67 @@
+/* -*- 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 <comphelper/proparrhlp.hxx>
+#include <svtools/genericunodialog.hxx>
+
+namespace pcr
+{
+
+
+ class MasterDetailLinkDialog;
+ typedef ::svt::OGenericUnoDialog MasterDetailLinkDialog_DBase;
+ typedef ::comphelper::OPropertyArrayUsageHelper< MasterDetailLinkDialog > MasterDetailLinkDialog_PBase;
+
+ class MasterDetailLinkDialog : public MasterDetailLinkDialog_DBase
+ ,public MasterDetailLinkDialog_PBase
+ {
+ public:
+ explicit MasterDetailLinkDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+
+ private:
+ // XTypeProvider
+ virtual css::uno::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 css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // 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;
+
+ css::uno::Reference< css::beans::XPropertySet> m_xDetail;
+ css::uno::Reference< css::beans::XPropertySet> m_xMaster;
+ OUString m_sExplanation;
+ OUString m_sDetailLabel;
+ OUString m_sMasterLabel;
+ };
+
+
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/browserline.cxx b/extensions/source/propctrlr/browserline.cxx
new file mode 100644
index 000000000..814c24f4b
--- /dev/null
+++ b/extensions/source/propctrlr/browserline.cxx
@@ -0,0 +1,405 @@
+/* -*- 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 "browserline.hxx"
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/inspection/PropertyLineElement.hpp>
+#include <com/sun/star/graphic/GraphicProvider.hpp>
+#include <com/sun/star/graphic/XGraphicProvider.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/string.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/weldutils.hxx>
+
+namespace pcr
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::inspection::XPropertyControl;
+ using ::com::sun::star::inspection::XPropertyControlContext;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::graphic::GraphicProvider;
+ using ::com::sun::star::graphic::XGraphicProvider;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::beans::PropertyValue;
+ using ::com::sun::star::graphic::XGraphic;
+
+ namespace PropertyLineElement = ::com::sun::star::inspection::PropertyLineElement;
+
+ OBrowserLine::OBrowserLine(const OUString& rEntryName, weld::Container* pParent, weld::SizeGroup* pLabelGroup,
+ weld::Container* pInitialControlParent)
+ : m_sEntryName(rEntryName)
+ , m_xBuilder(Application::CreateBuilder(pParent, "modules/spropctrlr/ui/browserline.ui"))
+ , m_xContainer(m_xBuilder->weld_container("BrowserLine"))
+ , m_xFtTitle(m_xBuilder->weld_label("label"))
+ , m_xBrowseButton(m_xBuilder->weld_button("browse"))
+ , m_xAdditionalBrowseButton(m_xBuilder->weld_button("morebrowse"))
+ , m_pInitialControlParent(pInitialControlParent) // controls start with this as their parent and need to be moved into m_xContainer
+ , m_pParent(pParent)
+ , m_pControlWindow( nullptr )
+ , m_pBrowseButton(nullptr)
+ , m_pAdditionalBrowseButton( nullptr )
+ , m_pClickListener( nullptr )
+ , m_nNameWidth(0)
+ , m_nEnableFlags( 0xFFFF )
+ , m_bIndentTitle( false )
+ , m_bReadOnly( false )
+ {
+ pLabelGroup->add_widget(m_xFtTitle.get());
+ }
+
+ OBrowserLine::~OBrowserLine()
+ {
+ implHideBrowseButton(true);
+ implHideBrowseButton(false);
+ m_pParent->move(m_xContainer.get(), nullptr);
+ }
+
+ void OBrowserLine::IndentTitle( bool _bIndent )
+ {
+ if ( m_bIndentTitle != _bIndent )
+ {
+ m_bIndentTitle = _bIndent;
+ }
+ }
+
+ void OBrowserLine::SetComponentHelpIds(const OString& rHelpId)
+ {
+ if (m_pControlWindow)
+ m_pControlWindow->set_help_id(rHelpId);
+
+ if ( m_pBrowseButton )
+ {
+ m_pBrowseButton->set_help_id(rHelpId);
+
+ if ( m_pAdditionalBrowseButton )
+ {
+ m_pAdditionalBrowseButton->set_help_id(rHelpId);
+ }
+ }
+ }
+
+ void OBrowserLine::setControl( const Reference< XPropertyControl >& rxControl )
+ {
+ m_xControl = rxControl;
+ auto xWindow = m_xControl->getControlWindow();
+ if (weld::TransportAsXWindow* pTunnel = dynamic_cast<weld::TransportAsXWindow*>(xWindow.get()))
+ m_pControlWindow = pTunnel->getWidget();
+ else
+ m_pControlWindow = nullptr;
+ DBG_ASSERT( m_pControlWindow, "OBrowserLine::setControl: setting NULL controls/windows is not allowed!" );
+
+ if ( m_pControlWindow )
+ {
+ m_pInitialControlParent->move(m_pControlWindow, m_xContainer.get());
+ m_pControlWindow->set_grid_left_attach(1);
+ m_xFtTitle->set_mnemonic_widget(m_pControlWindow);
+ m_pControlWindow->show();
+ }
+ }
+
+ bool OBrowserLine::GrabFocus()
+ {
+ bool bRes=false;
+
+ if (m_pControlWindow && m_pControlWindow->get_sensitive())
+ {
+ m_pControlWindow->grab_focus();
+ bRes = true;
+ }
+ else if ( m_pAdditionalBrowseButton && m_pAdditionalBrowseButton->get_sensitive() )
+ {
+ m_pAdditionalBrowseButton->grab_focus();
+ bRes = true;
+ }
+ else if ( m_pBrowseButton && m_pBrowseButton->get_sensitive() )
+ {
+ m_pBrowseButton->grab_focus();
+ bRes = true;
+ }
+ return bRes;
+ }
+
+ void OBrowserLine::Show(bool bFlag)
+ {
+ m_xFtTitle->set_visible(bFlag);
+ if (m_pControlWindow)
+ m_pControlWindow->set_visible( bFlag );
+ if ( m_pBrowseButton )
+ m_pBrowseButton->set_visible( bFlag );
+ if ( m_pAdditionalBrowseButton )
+ m_pAdditionalBrowseButton->set_visible( bFlag );
+ }
+
+ void OBrowserLine::Hide()
+ {
+ Show(false);
+ }
+
+ void OBrowserLine::SetTitle(const OUString& rNewTitle )
+ {
+ if ( GetTitle() == rNewTitle )
+ return;
+ m_xFtTitle->set_label( rNewTitle );
+ if (m_pControlWindow)
+ m_pControlWindow->set_accessible_name(rNewTitle);
+ if ( m_pBrowseButton )
+ m_pBrowseButton->set_accessible_name( rNewTitle );
+ FullFillTitleString();
+ }
+
+ void OBrowserLine::FullFillTitleString()
+ {
+ OUStringBuffer aText(m_xFtTitle->get_label());
+
+ int n10DotsWidth = m_xFtTitle->get_pixel_size("..........").Width();
+ int nTextWidth = m_xFtTitle->get_pixel_size(OUString::unacquired(aText)).Width();
+ int nDiff = m_nNameWidth - nTextWidth;
+ int nExtraChars = (nDiff * 10) / n10DotsWidth;
+ for (int i = 0; i < nExtraChars; ++i)
+ aText.append(".");
+
+ // for Issue 69452
+ if (AllSettings::GetLayoutRTL())
+ {
+ sal_Unicode const cRTL_mark = 0x200F;
+ aText.append( cRTL_mark );
+ }
+
+ m_xFtTitle->set_label(aText.makeStringAndClear());
+ }
+
+ OUString OBrowserLine::GetTitle() const
+ {
+ OUString sDisplayName = m_xFtTitle->get_label();
+
+ // for Issue 69452
+ if (AllSettings::GetLayoutRTL())
+ {
+ sal_Unicode const cRTL_mark = 0x200F;
+ sDisplayName = comphelper::string::stripEnd(sDisplayName, cRTL_mark);
+ }
+
+ sDisplayName = comphelper::string::stripEnd(sDisplayName, '.');
+
+ return sDisplayName;
+ }
+
+ void OBrowserLine::SetReadOnly( bool _bReadOnly )
+ {
+ if ( m_bReadOnly != _bReadOnly )
+ {
+ m_bReadOnly = _bReadOnly;
+ implUpdateEnabledDisabled();
+ }
+ }
+
+ namespace
+ {
+ void implSetBitIfAffected(sal_uInt16& nEnabledBits, sal_Int16 _nAffectedMask, sal_Int16 _nTestBit, bool _bSet)
+ {
+ if ( _nAffectedMask & _nTestBit )
+ {
+ if ( _bSet )
+ nEnabledBits |= _nTestBit;
+ else
+ nEnabledBits &= ~_nTestBit;
+ }
+ }
+
+ void implEnable(weld::Widget* pWindow, bool bEnable)
+ {
+ // tdf#138131 get_sensitive comparison as bodge for
+ // vcl's recursive Enable behavior
+ if (pWindow && pWindow->get_sensitive() != bEnable)
+ pWindow->set_sensitive(bEnable);
+ }
+
+ void implEnable(weld::Widget* pWindow, sal_uInt16 nEnabledBits, sal_uInt16 nMatchBits)
+ {
+ bool bEnable = ((nEnabledBits & nMatchBits) == nMatchBits);
+ implEnable(pWindow, bEnable);
+ }
+ }
+
+ void OBrowserLine::implUpdateEnabledDisabled()
+ {
+ implEnable( m_xFtTitle.get(), m_nEnableFlags, PropertyLineElement::CompleteLine );
+ if ( m_pControlWindow )
+ implEnable( m_pControlWindow, m_nEnableFlags, PropertyLineElement::CompleteLine | PropertyLineElement::InputControl );
+
+ if ( m_bReadOnly )
+ {
+ implEnable( m_pBrowseButton, false );
+ implEnable( m_pAdditionalBrowseButton, false );
+ }
+ else
+ {
+ implEnable( m_pBrowseButton, m_nEnableFlags, PropertyLineElement::CompleteLine | PropertyLineElement::PrimaryButton );
+ implEnable( m_pAdditionalBrowseButton, m_nEnableFlags, PropertyLineElement::CompleteLine | PropertyLineElement::SecondaryButton );
+ }
+ }
+
+ void OBrowserLine::EnablePropertyLine( bool _bEnable )
+ {
+ implSetBitIfAffected( m_nEnableFlags, PropertyLineElement::CompleteLine, PropertyLineElement::CompleteLine, _bEnable );
+ implUpdateEnabledDisabled();
+ }
+
+
+ void OBrowserLine::EnablePropertyControls( sal_Int16 _nControls, bool _bEnable )
+ {
+ implSetBitIfAffected( m_nEnableFlags, _nControls, PropertyLineElement::InputControl, _bEnable );
+ implSetBitIfAffected( m_nEnableFlags, _nControls, PropertyLineElement::PrimaryButton, _bEnable );
+ implSetBitIfAffected( m_nEnableFlags, _nControls, PropertyLineElement::SecondaryButton, _bEnable );
+ implUpdateEnabledDisabled();
+ }
+
+ weld::Button& OBrowserLine::impl_ensureButton(bool bPrimary)
+ {
+ weld::Button* pButton;
+ if (bPrimary)
+ pButton = m_pBrowseButton;
+ else
+ pButton = m_pAdditionalBrowseButton;
+
+ if (!pButton )
+ {
+ if (bPrimary)
+ pButton = m_pBrowseButton = m_xBrowseButton.get();
+ else
+ pButton = m_pAdditionalBrowseButton = m_xAdditionalBrowseButton.get();
+ pButton->connect_focus_in(LINK(this, OBrowserLine, OnButtonFocus));
+ pButton->connect_clicked(LINK(this, OBrowserLine, OnButtonClicked));
+ }
+
+ pButton->show();
+
+ return *pButton;
+ }
+
+ void OBrowserLine::ShowBrowseButton( const OUString& rImageURL, bool bPrimary )
+ {
+ weld::Button& rButton( impl_ensureButton( bPrimary ) );
+
+ OSL_PRECOND( !rImageURL.isEmpty(), "OBrowserLine::ShowBrowseButton: use the other version if you don't have an image!" );
+ Reference<XGraphic> xGraphic;
+ try
+ {
+ Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ Reference< XGraphicProvider > xGraphicProvider( GraphicProvider::create(xContext) );
+
+ Sequence aMediaProperties{ comphelper::makePropertyValue("URL", rImageURL) };
+
+ xGraphic = Reference<XGraphic>(xGraphicProvider->queryGraphic(aMediaProperties), css::uno::UNO_SET_THROW);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+
+ rButton.set_image(xGraphic);
+ }
+
+ void OBrowserLine::ShowBrowseButton(const css::uno::Reference<css::graphic::XGraphic>& rGraphic, bool bPrimary)
+ {
+ weld::Button& rButton( impl_ensureButton( bPrimary ) );
+ rButton.set_image(rGraphic);
+ }
+
+ void OBrowserLine::ShowBrowseButton( bool bPrimary )
+ {
+ impl_ensureButton(bPrimary);
+ }
+
+ void OBrowserLine::implHideBrowseButton(bool bPrimary)
+ {
+ if (bPrimary)
+ {
+ if (m_pBrowseButton)
+ {
+ m_pBrowseButton->hide();
+ m_pBrowseButton->connect_focus_in(Link<weld::Widget&, void>());
+ m_pBrowseButton = nullptr;
+ }
+ }
+ else
+ {
+ if (m_pAdditionalBrowseButton)
+ {
+ m_pAdditionalBrowseButton->hide();
+ m_pAdditionalBrowseButton->connect_focus_in(Link<weld::Widget&, void>());
+ m_pAdditionalBrowseButton = nullptr;
+ }
+ }
+ }
+
+ void OBrowserLine::HideBrowseButton(bool bPrimary)
+ {
+ implHideBrowseButton(bPrimary);
+ }
+
+ void OBrowserLine::SetTitleWidth(sal_uInt16 nWidth)
+ {
+ int nMinDotsWidth = m_xFtTitle->get_pixel_size("...").Width();
+ if (m_nNameWidth != nWidth + nMinDotsWidth)
+ m_nNameWidth = nWidth + nMinDotsWidth;
+ FullFillTitleString();
+ }
+
+ void OBrowserLine::SetClickListener( IButtonClickListener* _pListener )
+ {
+ m_pClickListener = _pListener;
+ }
+
+ IMPL_LINK(OBrowserLine, OnButtonClicked, weld::Button&, rButton, void)
+ {
+ if ( m_pClickListener )
+ m_pClickListener->buttonClicked(this, &rButton == m_pBrowseButton);
+ }
+
+ IMPL_LINK_NOARG( OBrowserLine, OnButtonFocus, weld::Widget&, void )
+ {
+ if ( m_xControl.is() )
+ {
+ try
+ {
+ Reference< XPropertyControlContext > xContext( m_xControl->getControlContext(), css::uno::UNO_SET_THROW );
+ xContext->focusGained( m_xControl );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+ }
+
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/browserline.hxx b/extensions/source/propctrlr/browserline.hxx
new file mode 100644
index 000000000..db33b7a55
--- /dev/null
+++ b/extensions/source/propctrlr/browserline.hxx
@@ -0,0 +1,127 @@
+/* -*- 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/inspection/XPropertyControl.hpp>
+#include <vcl/weld.hxx>
+
+namespace com::sun::star::inspection::PropertyLineElement
+{
+ const sal_Int16 CompleteLine = 0x4000;
+}
+
+
+namespace pcr
+{
+
+
+ class OBrowserLine;
+
+
+ class IButtonClickListener
+ {
+ public:
+ virtual void buttonClicked( OBrowserLine* pLine, bool bPrimary ) = 0;
+
+ protected:
+ ~IButtonClickListener() {}
+ };
+
+
+ class OBrowserLine
+ {
+ private:
+ OUString m_sEntryName;
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+ std::unique_ptr<weld::Label> m_xFtTitle;
+ std::unique_ptr<weld::Button> m_xBrowseButton;
+ std::unique_ptr<weld::Button> m_xAdditionalBrowseButton;
+ css::uno::Reference< css::inspection::XPropertyControl >
+ m_xControl;
+ weld::Container* m_pInitialControlParent;
+ weld::Container* m_pParent;
+ weld::Widget* m_pControlWindow;
+ weld::Button* m_pBrowseButton;
+ weld::Button* m_pAdditionalBrowseButton;
+ IButtonClickListener* m_pClickListener;
+ sal_uInt16 m_nNameWidth;
+ sal_uInt16 m_nEnableFlags;
+ bool m_bIndentTitle;
+ bool m_bReadOnly;
+
+ public:
+ OBrowserLine(const OUString& rEntryName, weld::Container* pParent, weld::SizeGroup* pLabelGroup,
+ weld::Container* pInitialControlParent);
+ ~OBrowserLine();
+
+ void setControl( const css::uno::Reference< css::inspection::XPropertyControl >& rxControl );
+ const css::uno::Reference< css::inspection::XPropertyControl >& getControl() const
+ {
+ return m_xControl;
+ }
+ weld::Widget* getControlWindow() const
+ {
+ return m_pControlWindow;
+ }
+
+ const OUString& GetEntryName() const { return m_sEntryName; }
+
+ void SetComponentHelpIds(const OString& rHelpId);
+
+ void SetTitle(const OUString& rString );
+ void FullFillTitleString();
+ OUString GetTitle() const;
+ void SetTitleWidth(sal_uInt16);
+
+ int GetRowHeight() const { return m_xContainer->get_preferred_size().Height(); }
+ void Show(bool bFlag=true);
+ void Hide();
+
+ bool GrabFocus();
+ void ShowBrowseButton( const OUString& rImageURL, bool bPrimary );
+ void ShowBrowseButton( const css::uno::Reference<css::graphic::XGraphic>& rGraphic, bool bPrimary );
+ void ShowBrowseButton( bool bPrimary );
+ void HideBrowseButton( bool bPrimary );
+
+ void EnablePropertyControls( sal_Int16 nControls, bool bEnable );
+ void EnablePropertyLine( bool bEnable );
+
+ void SetReadOnly( bool bReadOnly );
+
+ void SetClickListener( IButtonClickListener* pListener );
+
+ void IndentTitle( bool bIndent );
+
+ private:
+ DECL_LINK( OnButtonClicked, weld::Button&, void );
+ DECL_LINK( OnButtonFocus, weld::Widget&, void );
+
+ void implHideBrowseButton(bool bPrimary);
+ void implUpdateEnabledDisabled();
+
+ weld::Button& impl_ensureButton(bool bPrimary);
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/browserlistbox.cxx b/extensions/source/propctrlr/browserlistbox.cxx
new file mode 100644
index 000000000..04e9e44b3
--- /dev/null
+++ b/extensions/source/propctrlr/browserlistbox.cxx
@@ -0,0 +1,817 @@
+/* -*- 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 "browserlistbox.hxx"
+#include "pcrcommon.hxx"
+#include "proplinelistener.hxx"
+#include "propcontrolobserver.hxx"
+#include "linedescriptor.hxx"
+#include "inspectorhelpwindow.hxx"
+
+#include <sal/log.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/inspection/PropertyControlType.hpp>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <comphelper/asyncnotification.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/mutex.hxx>
+
+
+namespace pcr
+{
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::inspection::XPropertyControlContext;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::inspection::XPropertyControl;
+ using ::com::sun::star::lang::DisposedException;
+ using ::com::sun::star::lang::XComponent;
+ using ::com::sun::star::uno::UNO_QUERY;
+
+ namespace PropertyControlType = ::com::sun::star::inspection::PropertyControlType;
+
+ namespace {
+
+ enum ControlEventType
+ {
+ FOCUS_GAINED,
+ VALUE_CHANGED,
+ ACTIVATE_NEXT
+ };
+
+ struct ControlEvent : public ::comphelper::AnyEvent
+ {
+ Reference< XPropertyControl > xControl;
+ ControlEventType eType;
+
+ ControlEvent( const Reference< XPropertyControl >& _rxControl, ControlEventType _eType )
+ :xControl( _rxControl )
+ ,eType( _eType )
+ {
+ }
+ };
+
+ class SharedNotifier
+ {
+ private:
+ static ::osl::Mutex& getMutex();
+ static ::rtl::Reference< ::comphelper::AsyncEventNotifier > s_pNotifier;
+
+ public:
+ SharedNotifier(const SharedNotifier&) = delete;
+ SharedNotifier& operator=(const SharedNotifier&) = delete;
+ static const ::rtl::Reference< ::comphelper::AsyncEventNotifier >&
+ getNotifier();
+ };
+
+ }
+
+ ::rtl::Reference< ::comphelper::AsyncEventNotifier > SharedNotifier::s_pNotifier;
+
+
+ ::osl::Mutex& SharedNotifier::getMutex()
+ {
+ static ::osl::Mutex s_aMutex;
+ return s_aMutex;
+ }
+
+
+ const ::rtl::Reference< ::comphelper::AsyncEventNotifier >& SharedNotifier::getNotifier()
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+ if ( !s_pNotifier.is() )
+ {
+ s_pNotifier.set(
+ new ::comphelper::AsyncEventNotifier("browserlistbox"));
+ s_pNotifier->launch();
+ //TODO: a protocol is missing how to join with the launched
+ // thread before exit(3), to ensure the thread is no longer
+ // relying on any infrastructure while that infrastructure is
+ // being shut down in atexit handlers
+ }
+ return s_pNotifier;
+ }
+
+
+ /** implementation for of <type scope="css::inspection">XPropertyControlContext</type>
+ which forwards all events to a non-UNO version of this interface
+ */
+ typedef ::cppu::WeakImplHelper< XPropertyControlContext > PropertyControlContext_Impl_Base;
+ class PropertyControlContext_Impl :public PropertyControlContext_Impl_Base
+ ,public ::comphelper::IEventProcessor
+ {
+ public:
+ enum NotificationMode
+ {
+ eSynchronously,
+ eAsynchronously
+ };
+
+ private:
+ OBrowserListBox* m_pContext;
+ NotificationMode m_eMode;
+
+ public:
+ /** creates an instance
+ @param _rContextImpl
+ the instance to delegate events to
+ */
+ explicit PropertyControlContext_Impl( OBrowserListBox& _rContextImpl );
+
+ /** disposes the context.
+
+ When you call this method, all subsequent callbacks to the
+ <type scope="css::inspection">XPropertyControlContext</type> methods
+ will throw a <type scope="css::lang">DisposedException</type>.
+ */
+ void dispose();
+
+ /** sets the notification mode, so that notifications received from the controls are
+ forwarded to our OBrowserListBox either synchronously or asynchronously
+ @param _eMode
+ the new notification mode
+ */
+ void setNotificationMode( NotificationMode _eMode );
+
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ protected:
+ virtual ~PropertyControlContext_Impl() override;
+
+ // XPropertyControlObserver
+ virtual void SAL_CALL focusGained( const Reference< XPropertyControl >& Control ) override;
+ virtual void SAL_CALL valueChanged( const Reference< XPropertyControl >& Control ) override;
+ // XPropertyControlContext
+ virtual void SAL_CALL activateNextControl( const Reference< XPropertyControl >& CurrentControl ) override;
+
+ // IEventProcessor
+ virtual void processEvent( const ::comphelper::AnyEvent& _rEvent ) override;
+
+ private:
+ /** processes the given event, i.e. notifies it to our OBrowserListBox
+ @param _rEvent
+ the event no notify
+ @precond
+ our mutex (well, the SolarMutex) is locked
+ */
+ void impl_processEvent_throw( const ::comphelper::AnyEvent& _rEvent );
+
+ /** checks whether the instance is already disposed
+ */
+ bool impl_isDisposed_nothrow() const { return m_pContext == nullptr; }
+
+ /** notifies the given event originating from the given control
+ @throws DisposedException
+ @param _rxControl
+ @param _eType
+ */
+ void impl_notify_throw( const Reference< XPropertyControl >& _rxControl, ControlEventType _eType );
+ };
+
+ PropertyControlContext_Impl::PropertyControlContext_Impl( OBrowserListBox& _rContextImpl )
+ : m_pContext( &_rContextImpl )
+ , m_eMode( eAsynchronously )
+ {
+ }
+
+ PropertyControlContext_Impl::~PropertyControlContext_Impl()
+ {
+ if ( !impl_isDisposed_nothrow() )
+ dispose();
+ }
+
+ void PropertyControlContext_Impl::dispose()
+ {
+ SolarMutexGuard aGuard;
+ if ( impl_isDisposed_nothrow() )
+ return;
+
+ SharedNotifier::getNotifier()->removeEventsForProcessor( this );
+ m_pContext = nullptr;
+ }
+
+ void PropertyControlContext_Impl::setNotificationMode( NotificationMode _eMode )
+ {
+ SolarMutexGuard aGuard;
+ m_eMode = _eMode;
+ }
+
+ void PropertyControlContext_Impl::impl_notify_throw( const Reference< XPropertyControl >& _rxControl, ControlEventType _eType )
+ {
+ ::comphelper::AnyEventRef pEvent;
+
+ {
+ SolarMutexGuard aGuard;
+ if ( impl_isDisposed_nothrow() )
+ throw DisposedException( OUString(), *this );
+ pEvent = new ControlEvent( _rxControl, _eType );
+
+ if ( m_eMode == eSynchronously )
+ {
+ impl_processEvent_throw( *pEvent );
+ return;
+ }
+ }
+
+ SharedNotifier::getNotifier()->addEvent( pEvent, this );
+ }
+
+ void SAL_CALL PropertyControlContext_Impl::focusGained( const Reference< XPropertyControl >& Control )
+ {
+ impl_notify_throw( Control, FOCUS_GAINED );
+ }
+
+ void SAL_CALL PropertyControlContext_Impl::valueChanged( const Reference< XPropertyControl >& Control )
+ {
+ impl_notify_throw( Control, VALUE_CHANGED );
+ }
+
+ void SAL_CALL PropertyControlContext_Impl::activateNextControl( const Reference< XPropertyControl >& CurrentControl )
+ {
+ impl_notify_throw( CurrentControl, ACTIVATE_NEXT );
+ }
+
+ void SAL_CALL PropertyControlContext_Impl::acquire() noexcept
+ {
+ PropertyControlContext_Impl_Base::acquire();
+ }
+
+ void SAL_CALL PropertyControlContext_Impl::release() noexcept
+ {
+ PropertyControlContext_Impl_Base::release();
+ }
+
+ void PropertyControlContext_Impl::processEvent( const ::comphelper::AnyEvent& _rEvent )
+ {
+ SolarMutexGuard aGuard;
+ if ( impl_isDisposed_nothrow() )
+ return;
+
+ try
+ {
+ impl_processEvent_throw( _rEvent );
+ }
+ catch( const Exception& )
+ {
+ // can't handle otherwise, since our caller (the notification thread) does not allow
+ // for exceptions (it could itself abort only)
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+ void PropertyControlContext_Impl::impl_processEvent_throw( const ::comphelper::AnyEvent& _rEvent )
+ {
+ const ControlEvent& rControlEvent = static_cast< const ControlEvent& >( _rEvent );
+ switch ( rControlEvent.eType )
+ {
+ case FOCUS_GAINED:
+ m_pContext->focusGained( rControlEvent.xControl );
+ break;
+ case VALUE_CHANGED:
+ m_pContext->valueChanged( rControlEvent.xControl );
+ break;
+ case ACTIVATE_NEXT:
+ m_pContext->activateNextControl( rControlEvent.xControl );
+ break;
+ }
+ }
+
+ OBrowserListBox::OBrowserListBox(weld::Builder& rBuilder, weld::Container* pContainer)
+ : m_xScrolledWindow(rBuilder.weld_scrolled_window("scrolledwindow"))
+ , m_xLinesPlayground(rBuilder.weld_container("playground"))
+ , m_xSizeGroup(rBuilder.create_size_group())
+ , m_xHelpWindow(new InspectorHelpWindow(rBuilder))
+ , m_pInitialControlParent(pContainer)
+ , m_pLineListener(nullptr)
+ , m_pControlObserver( nullptr )
+ , m_nTheNameSize(0)
+ , m_nRowHeight(0)
+ , m_pControlContextImpl( new PropertyControlContext_Impl( *this ) )
+ {
+ m_xScrolledWindow->set_size_request(-1, m_xScrolledWindow->get_text_height() * 20);
+ }
+
+ OBrowserListBox::~OBrowserListBox()
+ {
+ OSL_ENSURE( !IsModified(), "OBrowserListBox::~OBrowserListBox: still modified - should have been committed before!" );
+
+ // doing the commit here, while we, as well as our owner, as well as some other components,
+ // are already "half dead" (means within their dtor) is potentially dangerous.
+ // By definition, CommitModified has to be called (if necessary) before destruction
+ m_pControlContextImpl->dispose();
+ m_pControlContextImpl.clear();
+
+ Clear();
+ }
+
+ bool OBrowserListBox::IsModified() const
+ {
+ bool bModified = false;
+
+ if (m_xScrolledWindow->get_visible() && m_xActiveControl.is())
+ bModified = m_xActiveControl->isModified();
+
+ return bModified;
+ }
+
+ void OBrowserListBox::CommitModified( )
+ {
+ if ( !(IsModified() && m_xActiveControl.is()) )
+ return;
+
+ // for the time of this commit, notify all events synchronously
+ // #i63814#
+ m_pControlContextImpl->setNotificationMode( PropertyControlContext_Impl::eSynchronously );
+ try
+ {
+ m_xActiveControl->notifyModifiedValue();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ m_pControlContextImpl->setNotificationMode( PropertyControlContext_Impl::eAsynchronously );
+ }
+
+ void OBrowserListBox::SetListener( IPropertyLineListener* _pListener )
+ {
+ m_pLineListener = _pListener;
+ }
+
+ void OBrowserListBox::SetObserver( IPropertyControlObserver* _pObserver )
+ {
+ m_pControlObserver = _pObserver;
+ }
+
+ void OBrowserListBox::EnableHelpSection( bool _bEnable )
+ {
+ m_xHelpWindow->Show( _bEnable );
+ }
+
+ bool OBrowserListBox::HasHelpSection() const
+ {
+ return m_xHelpWindow->IsVisible();
+ }
+
+ void OBrowserListBox::SetHelpText( const OUString& _rHelpText )
+ {
+ OSL_ENSURE( HasHelpSection(), "OBrowserListBox::SetHelpText: help section not visible!" );
+ m_xHelpWindow->SetText( _rHelpText );
+ }
+
+ void OBrowserListBox::UpdatePlayGround()
+ {
+ for (auto& line : m_aLines)
+ line.pLine->SetTitleWidth(m_nTheNameSize);
+ }
+
+ void OBrowserListBox::SetPropertyValue(const OUString& _rEntryName, const Any& _rValue, bool _bUnknownValue )
+ {
+ ListBoxLines::iterator line = std::find_if(m_aLines.begin(), m_aLines.end(),
+ [&_rEntryName](const ListBoxLine& rLine) { return rLine.aName == _rEntryName; });
+
+ if ( line != m_aLines.end() )
+ {
+ if ( _bUnknownValue )
+ {
+ Reference< XPropertyControl > xControl( line->pLine->getControl() );
+ OSL_ENSURE( xControl.is(), "OBrowserListBox::SetPropertyValue: illegal control!" );
+ if ( xControl.is() )
+ xControl->setValue( Any() );
+ }
+ else
+ impl_setControlAsPropertyValue( *line, _rValue );
+ }
+ }
+
+ sal_uInt16 OBrowserListBox::GetPropertyPos( std::u16string_view _rEntryName ) const
+ {
+ sal_uInt16 nPos = 0;
+ for (auto const& line : m_aLines)
+ {
+ if ( line.aName == _rEntryName )
+ {
+ return nPos;
+ }
+ ++nPos;
+ }
+
+ return EDITOR_LIST_ENTRY_NOTFOUND;
+ }
+
+ bool OBrowserListBox::impl_getBrowserLineForName( const OUString& _rEntryName, BrowserLinePointer& _out_rpLine ) const
+ {
+ ListBoxLines::const_iterator line = std::find_if(m_aLines.begin(), m_aLines.end(),
+ [&_rEntryName](const ListBoxLine& rLine) { return rLine.aName == _rEntryName; });
+
+ if ( line != m_aLines.end() )
+ _out_rpLine = line->pLine;
+ else
+ _out_rpLine.reset();
+ return bool(_out_rpLine);
+ }
+
+ void OBrowserListBox::EnablePropertyControls( const OUString& _rEntryName, sal_Int16 _nControls, bool _bEnable )
+ {
+ BrowserLinePointer pLine;
+ if ( impl_getBrowserLineForName( _rEntryName, pLine ) )
+ pLine->EnablePropertyControls( _nControls, _bEnable );
+ }
+
+ void OBrowserListBox::EnablePropertyLine( const OUString& _rEntryName, bool _bEnable )
+ {
+ BrowserLinePointer pLine;
+ if ( impl_getBrowserLineForName( _rEntryName, pLine ) )
+ pLine->EnablePropertyLine( _bEnable );
+ }
+
+ Reference< XPropertyControl > OBrowserListBox::GetPropertyControl( const OUString& _rEntryName )
+ {
+ BrowserLinePointer pLine;
+ if ( impl_getBrowserLineForName( _rEntryName, pLine ) )
+ return pLine->getControl();
+ return nullptr;
+ }
+
+ void OBrowserListBox::InsertEntry(const OLineDescriptor& rPropertyData, sal_uInt16 _nPos)
+ {
+ // create a new line
+ BrowserLinePointer pBrowserLine = std::make_shared<OBrowserLine>(rPropertyData.sName, m_xLinesPlayground.get(),
+ m_xSizeGroup.get(), m_pInitialControlParent);
+
+ // check that the name is unique
+ for (auto const& line : m_aLines)
+ {
+ if (line.aName == rPropertyData.sName)
+ {
+ // already have another line for this name!
+ assert(false);
+ }
+ }
+
+ ListBoxLine aNewLine( rPropertyData.sName, pBrowserLine, rPropertyData.xPropertyHandler );
+ ListBoxLines::size_type nInsertPos = _nPos;
+ if ( _nPos >= m_aLines.size() )
+ {
+ nInsertPos = m_aLines.size();
+ m_aLines.push_back( aNewLine );
+ }
+ else
+ m_aLines.insert( m_aLines.begin() + _nPos, aNewLine );
+
+ pBrowserLine->SetTitleWidth(m_nTheNameSize);
+
+ // initialize the entry
+ ChangeEntry(rPropertyData, nInsertPos);
+
+ m_nRowHeight = std::max(m_nRowHeight, pBrowserLine->GetRowHeight() + 6); // 6 is spacing of the "playground" in browserpage.ui
+ m_xScrolledWindow->vadjustment_set_step_increment(m_nRowHeight);
+ }
+
+ void OBrowserListBox::ShowEntry(sal_uInt16 nPos)
+ {
+ if (nPos == 0)
+ {
+ // special case the simple entry 0 situation
+ m_xScrolledWindow->vadjustment_set_value(0);
+ return;
+ }
+
+ if (nPos >= m_aLines.size())
+ return;
+
+ unsigned const nWinHeight = m_xScrolledWindow->vadjustment_get_page_size();
+
+ auto nThumbPos = m_xScrolledWindow->vadjustment_get_value();
+ int const nWinTop = nThumbPos;
+ int const nWinBottom = nWinTop + nWinHeight;
+
+ auto nCtrlPosY = nPos * m_nRowHeight;
+
+ int const nSelectedItemTop = nCtrlPosY;
+ int const nSelectedItemBottom = nCtrlPosY + m_nRowHeight;
+ bool const shouldScrollDown = nSelectedItemBottom >= nWinBottom;
+ bool const shouldScrollUp = nSelectedItemTop <= nWinTop;
+ bool const isNeedToScroll = shouldScrollDown || shouldScrollUp;
+
+ if (!isNeedToScroll)
+ return;
+
+ if (shouldScrollDown)
+ {
+ int nOffset = nSelectedItemBottom - nWinBottom;
+ nThumbPos += nOffset;
+ }
+ else
+ {
+ int nOffset = nWinTop - nSelectedItemTop;
+ nThumbPos -= nOffset;
+ if(nThumbPos < 0)
+ nThumbPos = 0;
+ }
+ m_xScrolledWindow->vadjustment_set_value(nThumbPos);
+ }
+
+ void OBrowserListBox::buttonClicked( OBrowserLine* _pLine, bool _bPrimary )
+ {
+ DBG_ASSERT( _pLine, "OBrowserListBox::buttonClicked: invalid browser line!" );
+ if ( _pLine && m_pLineListener )
+ {
+ m_pLineListener->Clicked( _pLine->GetEntryName(), _bPrimary );
+ }
+ }
+
+ void OBrowserListBox::impl_setControlAsPropertyValue( const ListBoxLine& _rLine, const Any& _rPropertyValue )
+ {
+ Reference< XPropertyControl > xControl( _rLine.pLine->getControl() );
+ try
+ {
+ if ( _rPropertyValue.getValueType().equals( _rLine.pLine->getControl()->getValueType() ) )
+ {
+ xControl->setValue( _rPropertyValue );
+ }
+ else
+ {
+ SAL_WARN_IF( !_rLine.xHandler.is(), "extensions.propctrlr",
+ "OBrowserListBox::impl_setControlAsPropertyValue: no handler -> no conversion (property: '"
+ << _rLine.pLine->GetEntryName() << "')!" );
+ if ( _rLine.xHandler.is() )
+ {
+ Any aControlValue = _rLine.xHandler->convertToControlValue(
+ _rLine.pLine->GetEntryName(), _rPropertyValue, xControl->getValueType() );
+ xControl->setValue( aControlValue );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+ Any OBrowserListBox::impl_getControlAsPropertyValue( const ListBoxLine& _rLine )
+ {
+ Reference< XPropertyControl > xControl( _rLine.pLine->getControl() );
+ Any aPropertyValue;
+ try
+ {
+ SAL_WARN_IF( !_rLine.xHandler.is(), "extensions.propctrlr",
+ "OBrowserListBox::impl_getControlAsPropertyValue: no handler -> no conversion (property: '"
+ << _rLine.pLine->GetEntryName() << "')!" );
+ if ( _rLine.xHandler.is() )
+ aPropertyValue = _rLine.xHandler->convertToPropertyValue( _rLine.pLine->GetEntryName(), xControl->getValue() );
+ else
+ aPropertyValue = xControl->getValue();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ return aPropertyValue;
+ }
+
+ sal_uInt16 OBrowserListBox::impl_getControlPos( const Reference< XPropertyControl >& _rxControl ) const
+ {
+ sal_uInt16 nPos = 0;
+ for (auto const& search : m_aLines)
+ {
+ if ( search.pLine->getControl().get() == _rxControl.get() )
+ return nPos;
+ ++nPos;
+ }
+ OSL_FAIL( "OBrowserListBox::impl_getControlPos: invalid control - not part of any of our lines!" );
+ return sal_uInt16(-1);
+ }
+
+
+ void OBrowserListBox::focusGained( const Reference< XPropertyControl >& _rxControl )
+ {
+ DBG_TESTSOLARMUTEX();
+
+ DBG_ASSERT( _rxControl.is(), "OBrowserListBox::focusGained: invalid event source!" );
+ if ( !_rxControl.is() )
+ return;
+
+ if ( m_pControlObserver )
+ m_pControlObserver->focusGained( _rxControl );
+
+ m_xActiveControl = _rxControl;
+ ShowEntry( impl_getControlPos( m_xActiveControl ) );
+ }
+
+
+ void OBrowserListBox::valueChanged( const Reference< XPropertyControl >& _rxControl )
+ {
+ DBG_TESTSOLARMUTEX();
+
+ DBG_ASSERT( _rxControl.is(), "OBrowserListBox::valueChanged: invalid event source!" );
+ if ( !_rxControl.is() )
+ return;
+
+ if ( m_pControlObserver )
+ m_pControlObserver->valueChanged( _rxControl );
+
+ if ( m_pLineListener )
+ {
+ const ListBoxLine& rLine = m_aLines[ impl_getControlPos( _rxControl ) ];
+ m_pLineListener->Commit(
+ rLine.pLine->GetEntryName(),
+ impl_getControlAsPropertyValue( rLine )
+ );
+ }
+ }
+
+
+ void OBrowserListBox::activateNextControl( const Reference< XPropertyControl >& _rxCurrentControl )
+ {
+ DBG_TESTSOLARMUTEX();
+
+ sal_uInt16 nLine = impl_getControlPos( _rxCurrentControl );
+
+ // cycle forwards, 'til we've the next control which can grab the focus
+ ++nLine;
+ while ( static_cast< size_t >( nLine ) < m_aLines.size() )
+ {
+ if ( m_aLines[nLine].pLine->GrabFocus() )
+ break;
+ ++nLine;
+ }
+
+ // wrap around?
+ if ( ( static_cast< size_t >( nLine ) >= m_aLines.size() ) && ( !m_aLines.empty() ) )
+ m_aLines[0].pLine->GrabFocus();
+ }
+
+
+ namespace
+ {
+
+ void lcl_implDisposeControl_nothrow( const Reference< XPropertyControl >& _rxControl )
+ {
+ if ( !_rxControl.is() )
+ return;
+ try
+ {
+ _rxControl->setControlContext( nullptr );
+ Reference< XComponent > xControlComponent( _rxControl, UNO_QUERY );
+ if ( xControlComponent.is() )
+ xControlComponent->dispose();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+ }
+
+ void OBrowserListBox::Clear()
+ {
+ for (auto const& line : m_aLines)
+ {
+ // hide the line
+ line.pLine->Hide();
+ // reset the listener
+ lcl_implDisposeControl_nothrow( line.pLine->getControl() );
+ }
+
+ clearContainer( m_aLines );
+ }
+
+ bool OBrowserListBox::RemoveEntry( const OUString& _rName )
+ {
+ ListBoxLines::iterator it = std::find_if(m_aLines.begin(), m_aLines.end(),
+ [&_rName](const ListBoxLine& rLine) { return rLine.aName == _rName; });
+
+ if ( it == m_aLines.end() )
+ return false;
+
+ m_aLines.erase( it );
+
+ return true;
+ }
+
+ void OBrowserListBox::ChangeEntry( const OLineDescriptor& rPropertyData, ListBoxLines::size_type nPos )
+ {
+ OSL_PRECOND( rPropertyData.Control.is(), "OBrowserListBox::ChangeEntry: invalid control!" );
+ if ( !rPropertyData.Control.is() )
+ return;
+
+ if ( nPos == EDITOR_LIST_REPLACE_EXISTING )
+ nPos = GetPropertyPos( rPropertyData.sName );
+
+ if ( nPos >= m_aLines.size() )
+ return;
+
+ // the current line and control
+ ListBoxLine& rLine = m_aLines[nPos];
+
+ // the old control and some data about it
+ Reference< XPropertyControl > xControl = rLine.pLine->getControl();
+
+ // clean up the old control
+ lcl_implDisposeControl_nothrow( xControl );
+
+ // set the new control at the line
+ rLine.pLine->setControl( rPropertyData.Control );
+ xControl = rLine.pLine->getControl();
+
+ if ( xControl.is() )
+ xControl->setControlContext( m_pControlContextImpl );
+
+ // the initial property value
+ if ( rPropertyData.bUnknownValue )
+ xControl->setValue( Any() );
+ else
+ impl_setControlAsPropertyValue( rLine, rPropertyData.aValue );
+
+ rLine.pLine->SetTitle(rPropertyData.DisplayName);
+ rLine.xHandler = rPropertyData.xPropertyHandler;
+
+ if ( rPropertyData.HasPrimaryButton )
+ {
+ if ( !rPropertyData.PrimaryButtonImageURL.isEmpty() )
+ rLine.pLine->ShowBrowseButton( rPropertyData.PrimaryButtonImageURL, true );
+ else if ( rPropertyData.PrimaryButtonImage.is() )
+ rLine.pLine->ShowBrowseButton( rPropertyData.PrimaryButtonImage, true );
+ else
+ rLine.pLine->ShowBrowseButton( true );
+
+ if ( rPropertyData.HasSecondaryButton )
+ {
+ if ( !rPropertyData.SecondaryButtonImageURL.isEmpty() )
+ rLine.pLine->ShowBrowseButton( rPropertyData.SecondaryButtonImageURL, false );
+ else if ( rPropertyData.SecondaryButtonImage.is() )
+ rLine.pLine->ShowBrowseButton( rPropertyData.SecondaryButtonImage, false );
+ else
+ rLine.pLine->ShowBrowseButton( false );
+ }
+ else
+ rLine.pLine->HideBrowseButton( false );
+
+ rLine.pLine->SetClickListener( this );
+ }
+ else
+ {
+ rLine.pLine->HideBrowseButton( true );
+ rLine.pLine->HideBrowseButton( false );
+ }
+
+ DBG_ASSERT( ( rPropertyData.IndentLevel == 0 ) || ( rPropertyData.IndentLevel == 1 ),
+ "OBrowserListBox::ChangeEntry: unsupported indent level!" );
+ rLine.pLine->IndentTitle( rPropertyData.IndentLevel > 0 );
+
+ rLine.pLine->SetComponentHelpIds(
+ HelpIdUrl::getHelpId( rPropertyData.HelpURL )
+ );
+
+ if ( rPropertyData.bReadOnly )
+ {
+ rLine.pLine->SetReadOnly( true );
+
+ // user controls (i.e. the ones not provided by the usual
+ // XPropertyControlFactory) have no chance to know that they should be read-only,
+ // since XPropertyHandler::describePropertyLine does not transport this
+ // information.
+ // So, we manually switch this to read-only.
+ if ( xControl.is() && ( xControl->getControlType() == PropertyControlType::Unknown ) )
+ {
+ weld::Widget* pWindow = rLine.pLine->getControlWindow();
+ weld::Entry* pControlWindowAsEdit = dynamic_cast<weld::Entry*>(pWindow);
+ if (pControlWindowAsEdit)
+ pControlWindowAsEdit->set_editable(false);
+ else
+ pWindow->set_sensitive(false);
+ }
+ }
+
+ sal_uInt16 nTextWidth = m_xLinesPlayground->get_pixel_size(rPropertyData.DisplayName).Width();
+ if (m_nTheNameSize< nTextWidth)
+ {
+ m_nTheNameSize = nTextWidth;
+ UpdatePlayGround();
+ }
+ }
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/browserlistbox.hxx b/extensions/source/propctrlr/browserlistbox.hxx
new file mode 100644
index 000000000..1a7232612
--- /dev/null
+++ b/extensions/source/propctrlr/browserlistbox.hxx
@@ -0,0 +1,163 @@
+/* -*- 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 "browserline.hxx"
+
+#include <com/sun/star/inspection/XPropertyControl.hpp>
+#include <com/sun/star/inspection/XPropertyHandler.hpp>
+#include <vcl/weld.hxx>
+#include <rtl/ref.hxx>
+
+#include <memory>
+#include <vector>
+
+#define EDITOR_LIST_REPLACE_EXISTING \
+ std::numeric_limits<ListBoxLines::size_type>::max()
+
+namespace pcr
+{
+
+
+ class IPropertyLineListener;
+ class IPropertyControlObserver;
+ struct OLineDescriptor;
+ class InspectorHelpWindow;
+ class PropertyControlContext_Impl;
+
+
+ // administrative structures for OBrowserListBox
+
+ typedef std::shared_ptr< OBrowserLine > BrowserLinePointer;
+ struct ListBoxLine
+ {
+ OUString aName;
+ BrowserLinePointer pLine;
+ css::uno::Reference< css::inspection::XPropertyHandler >
+ xHandler;
+
+ ListBoxLine( const OUString& rName, const BrowserLinePointer& _pLine, const css::uno::Reference< css::inspection::XPropertyHandler >& _rxHandler )
+ : aName( rName ),
+ pLine( _pLine ),
+ xHandler( _rxHandler )
+ {
+ }
+ };
+ typedef std::vector< ListBoxLine > ListBoxLines;
+
+
+ class OBrowserListBox final : public IButtonClickListener
+ {
+ std::unique_ptr<weld::ScrolledWindow> m_xScrolledWindow;
+ std::unique_ptr<weld::Container> m_xLinesPlayground;
+ std::unique_ptr<weld::SizeGroup> m_xSizeGroup;
+ std::unique_ptr<InspectorHelpWindow> m_xHelpWindow;
+ weld::Container* m_pInitialControlParent;
+ ListBoxLines m_aLines;
+ IPropertyLineListener* m_pLineListener;
+ IPropertyControlObserver* m_pControlObserver;
+ css::uno::Reference< css::inspection::XPropertyControl >
+ m_xActiveControl;
+ sal_uInt16 m_nTheNameSize;
+ int m_nRowHeight;
+ ::rtl::Reference< PropertyControlContext_Impl >
+ m_pControlContextImpl;
+
+ void UpdatePlayGround();
+ void ShowEntry(sal_uInt16 nPos);
+
+ public:
+ explicit OBrowserListBox(weld::Builder& rBuilder, weld::Container* pContainer);
+ ~OBrowserListBox();
+
+ void SetListener( IPropertyLineListener* _pListener );
+ void SetObserver( IPropertyControlObserver* _pObserver );
+
+ void EnableHelpSection( bool _bEnable );
+ bool HasHelpSection() const;
+ void SetHelpText( const OUString& _rHelpText );
+
+ void Clear();
+
+ void InsertEntry( const OLineDescriptor&, sal_uInt16 nPos );
+ bool RemoveEntry( const OUString& _rName );
+ void ChangeEntry( const OLineDescriptor&, ListBoxLines::size_type nPos );
+
+ void SetPropertyValue( const OUString& rEntryName, const css::uno::Any& rValue, bool _bUnknownValue );
+ sal_uInt16 GetPropertyPos( std::u16string_view rEntryName ) const;
+ css::uno::Reference< css::inspection::XPropertyControl >
+ GetPropertyControl( const OUString& rEntryName );
+ void EnablePropertyControls( const OUString& _rEntryName, sal_Int16 _nControls, bool _bEnable );
+ void EnablePropertyLine( const OUString& _rEntryName, bool _bEnable );
+
+ bool IsModified( ) const;
+ void CommitModified( );
+
+ /// @throws css::uno::RuntimeException
+ void focusGained( const css::uno::Reference< css::inspection::XPropertyControl >& Control );
+ /// @throws css::uno::RuntimeException
+ void valueChanged( const css::uno::Reference< css::inspection::XPropertyControl >& Control );
+ /// @throws css::uno::RuntimeException
+ void activateNextControl( const css::uno::Reference< css::inspection::XPropertyControl >& CurrentControl );
+
+ private:
+ // IButtonClickListener
+ void buttonClicked( OBrowserLine* _pLine, bool _bPrimary ) override;
+
+ /** retrieves the index of a given control in our line list
+ @param _rxControl
+ The control to lookup. Must denote a control of one of the lines in ->m_aLines
+ */
+ sal_uInt16 impl_getControlPos( const css::uno::Reference< css::inspection::XPropertyControl >& _rxControl ) const;
+
+ /** sets the given property value at the given control, after converting it as necessary
+ @param _rLine
+ The line whose at which the value is to be set.
+ @param _rPropertyValue
+ the property value to set. If it's not compatible with the control value,
+ it will be converted, using <member>XPropertyHandler::convertToControlValue</member>
+ */
+ static void impl_setControlAsPropertyValue( const ListBoxLine& _rLine, const css::uno::Any& _rPropertyValue );
+
+ /** retrieves the value for the given control, as a property value, after converting it as necessary
+ @param _rLine
+ The line whose at which the value is to be set.
+ */
+ static css::uno::Any
+ impl_getControlAsPropertyValue( const ListBoxLine& _rLine );
+
+ /** retrieves the ->BrowserLinePointer for a given entry name
+ @param _rEntryName
+ the name whose line is to be looked up
+ @param _out_rpLine
+ contains, upon return, the found browser line, if any
+ @return
+ <TRUE/> if and only if a non-<NULL/> line for the given entry name could be
+ found.
+ */
+ bool impl_getBrowserLineForName( const OUString& _rEntryName, BrowserLinePointer& _out_rpLine ) const;
+ };
+
+
+} // namespace pcr
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/browserpage.cxx b/extensions/source/propctrlr/browserpage.cxx
new file mode 100644
index 000000000..5502418bd
--- /dev/null
+++ b/extensions/source/propctrlr/browserpage.cxx
@@ -0,0 +1,41 @@
+/* -*- 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 <vcl/svapp.hxx>
+#include "browserpage.hxx"
+
+namespace pcr
+{
+ OBrowserPage::OBrowserPage(weld::Container* pParent, weld::Container* pInitialControlContainer)
+ : m_pParent(pParent)
+ , m_xBuilder(Application::CreateBuilder(pParent, "modules/spropctrlr/ui/browserpage.ui"))
+ , m_xContainer(m_xBuilder->weld_container("BrowserPage"))
+ , m_xListBox(new OBrowserListBox(*m_xBuilder, pInitialControlContainer))
+ {
+ }
+
+ OBrowserPage::~OBrowserPage()
+ {
+ if (m_pParent)
+ detach();
+ assert(!m_pParent);
+ }
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/browserpage.hxx b/extensions/source/propctrlr/browserpage.hxx
new file mode 100644
index 000000000..0db6cc3c7
--- /dev/null
+++ b/extensions/source/propctrlr/browserpage.hxx
@@ -0,0 +1,61 @@
+/* -*- 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 <o3tl/deleter.hxx>
+#include "browserlistbox.hxx"
+
+namespace pcr
+{
+ class OBrowserPage
+ {
+ private:
+ weld::Container* m_pParent;
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+ std::unique_ptr<OBrowserListBox, o3tl::default_delete<OBrowserListBox>> m_xListBox;
+
+ public:
+ // TODO inherit from BuilderPage
+ explicit OBrowserPage(weld::Container* pParent, weld::Container* pContainer);
+ ~OBrowserPage();
+
+ void SetHelpId(const OString& rHelpId) { m_xContainer->set_help_id(rHelpId); }
+
+ OBrowserListBox& getListBox() { return *m_xListBox; }
+ const OBrowserListBox& getListBox() const { return *m_xListBox; }
+
+ void detach()
+ {
+ assert(m_pParent && "already attached");
+ m_pParent->move(m_xContainer.get(), nullptr);
+ m_pParent = nullptr;
+ }
+
+ void reattach(weld::Container* pNewParent)
+ {
+ assert(!m_pParent && "already attached");
+ m_pParent = pNewParent;
+ m_pParent->move(m_xContainer.get(), pNewParent);
+ }
+ };
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/browserview.cxx b/extensions/source/propctrlr/browserview.cxx
new file mode 100644
index 000000000..e7b7cb690
--- /dev/null
+++ b/extensions/source/propctrlr/browserview.cxx
@@ -0,0 +1,64 @@
+/* -*- 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 "browserview.hxx"
+#include "propertyeditor.hxx"
+#include <helpids.h>
+#include <memory>
+
+namespace pcr
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+
+ OPropertyBrowserView::OPropertyBrowserView(const css::uno::Reference<css::uno::XComponentContext>& rContext, weld::Builder& rBuilder)
+ : m_xPropBox(new OPropertyEditor(rContext, rBuilder))
+ , m_nActivePage(0)
+ {
+ m_xPropBox->SetHelpId(HID_FM_PROPDLG_TABCTR);
+ m_xPropBox->setPageActivationHandler(LINK(this, OPropertyBrowserView, OnPageActivation));
+ }
+
+ IMPL_LINK(OPropertyBrowserView, OnPageActivation, const OString&, rNewPage, void)
+ {
+ m_nActivePage = rNewPage.toUInt32();
+ m_aPageActivationHandler.Call(nullptr);
+ }
+
+ OPropertyBrowserView::~OPropertyBrowserView()
+ {
+ sal_uInt16 nTmpPage = m_xPropBox->GetCurPage();
+ if (nTmpPage)
+ m_nActivePage = nTmpPage;
+ }
+
+ void OPropertyBrowserView::activatePage(sal_uInt16 _nPage)
+ {
+ m_nActivePage = _nPage;
+ getPropertyBox().SetPage(m_nActivePage);
+ }
+
+ css::awt::Size OPropertyBrowserView::getMinimumSize() const
+ {
+ ::Size aSize = m_xPropBox->get_preferred_size();
+ return css::awt::Size(aSize.Width(), aSize.Height());
+ }
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/browserview.hxx b/extensions/source/propctrlr/browserview.hxx
new file mode 100644
index 000000000..7a0711fb1
--- /dev/null
+++ b/extensions/source/propctrlr/browserview.hxx
@@ -0,0 +1,56 @@
+/* -*- 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/awt/Size.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <o3tl/deleter.hxx>
+#include <vcl/weld.hxx>
+
+namespace pcr
+{
+ class OPropertyEditor;
+ class OPropertyBrowserView final
+ {
+ std::unique_ptr<OPropertyEditor, o3tl::default_delete<OPropertyEditor>> m_xPropBox;
+ sal_uInt16 m_nActivePage;
+ Link<LinkParamNone*,void> m_aPageActivationHandler;
+
+ public:
+ explicit OPropertyBrowserView(const css::uno::Reference<css::uno::XComponentContext>& rContext, weld::Builder& rBuilder);
+ ~OPropertyBrowserView();
+
+ OPropertyEditor& getPropertyBox() { return *m_xPropBox; }
+
+ // page handling
+ sal_uInt16 getActivePage() const { return m_nActivePage; }
+ void activatePage(sal_uInt16 _nPage);
+
+ void setPageActivationHandler(const Link<LinkParamNone*,void>& _rHdl) { m_aPageActivationHandler = _rHdl; }
+
+ css::awt::Size getMinimumSize() const;
+
+ private:
+ DECL_LINK(OnPageActivation, const OString&, void);
+ };
+
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/buttonnavigationhandler.cxx b/extensions/source/propctrlr/buttonnavigationhandler.cxx
new file mode 100644
index 000000000..618d9db46
--- /dev/null
+++ b/extensions/source/propctrlr/buttonnavigationhandler.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 "buttonnavigationhandler.hxx"
+#include "formstrings.hxx"
+#include "formmetadata.hxx"
+#include "pushbuttonnavigation.hxx"
+
+#include <com/sun/star/form/inspection/FormComponentPropertyHandler.hpp>
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::inspection;
+
+ ButtonNavigationHandler::ButtonNavigationHandler( const Reference< XComponentContext >& _rxContext )
+ :PropertyHandlerComponent( _rxContext )
+ {
+
+ m_xSlaveHandler = css::form::inspection::FormComponentPropertyHandler::create( m_xContext );
+ }
+
+
+ ButtonNavigationHandler::~ButtonNavigationHandler( )
+ {
+ }
+
+
+ OUString ButtonNavigationHandler::getImplementationName( )
+ {
+ return "com.sun.star.comp.extensions.ButtonNavigationHandler";
+ }
+
+
+ Sequence< OUString > ButtonNavigationHandler::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.form.inspection.ButtonNavigationHandler" };
+ }
+
+
+ void SAL_CALL ButtonNavigationHandler::inspect( const Reference< XInterface >& _rxIntrospectee )
+ {
+ PropertyHandlerComponent::inspect( _rxIntrospectee );
+ m_xSlaveHandler->inspect( _rxIntrospectee );
+ }
+
+
+ PropertyState SAL_CALL ButtonNavigationHandler::getPropertyState( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+ PropertyState eState = PropertyState_DIRECT_VALUE;
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_BUTTONTYPE:
+ {
+ PushButtonNavigation aHelper( m_xComponent );
+ eState = aHelper.getCurrentButtonTypeState();
+ }
+ break;
+ case PROPERTY_ID_TARGET_URL:
+ {
+ PushButtonNavigation aHelper( m_xComponent );
+ eState = aHelper.getCurrentTargetURLState();
+ }
+ break;
+
+ default:
+ OSL_FAIL( "ButtonNavigationHandler::getPropertyState: cannot handle this property!" );
+ break;
+ }
+
+ return eState;
+ }
+
+
+ Any SAL_CALL ButtonNavigationHandler::getPropertyValue( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ Any aReturn;
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_BUTTONTYPE:
+ {
+ PushButtonNavigation aHelper( m_xComponent );
+ aReturn = aHelper.getCurrentButtonType();
+ }
+ break;
+
+ case PROPERTY_ID_TARGET_URL:
+ {
+ PushButtonNavigation aHelper( m_xComponent );
+ aReturn = aHelper.getCurrentTargetURL();
+ }
+ break;
+
+ default:
+ OSL_FAIL( "ButtonNavigationHandler::getPropertyValue: cannot handle this property!" );
+ break;
+ }
+
+ return aReturn;
+ }
+
+
+ void SAL_CALL ButtonNavigationHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_BUTTONTYPE:
+ {
+ PushButtonNavigation aHelper( m_xComponent );
+ aHelper.setCurrentButtonType( _rValue );
+ }
+ break;
+
+ case PROPERTY_ID_TARGET_URL:
+ {
+ PushButtonNavigation aHelper( m_xComponent );
+ aHelper.setCurrentTargetURL( _rValue );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "ButtonNavigationHandler::setPropertyValue: cannot handle this id!" );
+ }
+ }
+
+
+ bool ButtonNavigationHandler::isNavigationCapableButton( const Reference< XPropertySet >& _rxComponent )
+ {
+ Reference< XPropertySetInfo > xPSI;
+ if ( _rxComponent.is() )
+ xPSI = _rxComponent->getPropertySetInfo();
+
+ return xPSI.is()
+ && xPSI->hasPropertyByName( PROPERTY_TARGET_URL )
+ && xPSI->hasPropertyByName( PROPERTY_BUTTONTYPE );
+ }
+
+
+ Sequence< Property > ButtonNavigationHandler::doDescribeSupportedProperties() const
+ {
+ std::vector< Property > aProperties;
+
+ if ( isNavigationCapableButton( m_xComponent ) )
+ {
+ addStringPropertyDescription( aProperties, PROPERTY_TARGET_URL );
+ implAddPropertyDescription( aProperties, PROPERTY_BUTTONTYPE, ::cppu::UnoType<sal_Int32>::get() );
+ }
+
+ if ( aProperties.empty() )
+ return Sequence< Property >();
+ return comphelper::containerToSequence(aProperties);
+ }
+
+
+ Sequence< OUString > SAL_CALL ButtonNavigationHandler::getActuatingProperties( )
+ {
+ Sequence< OUString > aActuating{ PROPERTY_BUTTONTYPE, PROPERTY_TARGET_URL };
+ return aActuating;
+ }
+
+
+ InteractiveSelectionResult SAL_CALL ButtonNavigationHandler::onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, Any& _rData, const Reference< XObjectInspectorUI >& _rxInspectorUI )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ InteractiveSelectionResult eReturn( InteractiveSelectionResult_Cancelled );
+
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_TARGET_URL:
+ eReturn = m_xSlaveHandler->onInteractivePropertySelection( _rPropertyName, _bPrimary, _rData, _rxInspectorUI );
+ break;
+ default:
+ eReturn = PropertyHandlerComponent::onInteractivePropertySelection( _rPropertyName, _bPrimary, _rData, _rxInspectorUI );
+ break;
+ }
+
+ return eReturn;
+ }
+
+
+ void SAL_CALL ButtonNavigationHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& /*_rNewValue*/, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool /*_bFirstTimeInit*/ )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwRuntime( _rActuatingPropertyName ) );
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_BUTTONTYPE:
+ {
+ PushButtonNavigation aHelper( m_xComponent );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_TARGET_URL, aHelper.currentButtonTypeIsOpenURL() );
+ }
+ break;
+
+ case PROPERTY_ID_TARGET_URL:
+ {
+ PushButtonNavigation aHelper( m_xComponent );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_TARGET_FRAME, aHelper.hasNonEmptyCurrentTargetURL() );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "ButtonNavigationHandler::actuatingPropertyChanged: cannot handle this id!" );
+ }
+ }
+
+
+ LineDescriptor SAL_CALL ButtonNavigationHandler::describePropertyLine( const OUString& _rPropertyName, const Reference< XPropertyControlFactory >& _rxControlFactory )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ LineDescriptor aReturn;
+
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_TARGET_URL:
+ aReturn = m_xSlaveHandler->describePropertyLine( _rPropertyName, _rxControlFactory );
+ break;
+ default:
+ aReturn = PropertyHandlerComponent::describePropertyLine( _rPropertyName, _rxControlFactory );
+ break;
+ }
+
+ return aReturn;
+ }
+
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_ButtonNavigationHandler_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::ButtonNavigationHandler(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/buttonnavigationhandler.hxx b/extensions/source/propctrlr/buttonnavigationhandler.hxx
new file mode 100644
index 000000000..c5e01e1df
--- /dev/null
+++ b/extensions/source/propctrlr/buttonnavigationhandler.hxx
@@ -0,0 +1,71 @@
+/* -*- 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 "propertyhandler.hxx"
+
+
+namespace pcr
+{
+
+ /** a property handler for any virtual string properties
+ */
+ class ButtonNavigationHandler : public PropertyHandlerComponent
+ {
+ private:
+ css::uno::Reference< css::inspection::XPropertyHandler >
+ m_xSlaveHandler;
+
+ public:
+ explicit ButtonNavigationHandler(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext
+ );
+
+ protected:
+ virtual ~ButtonNavigationHandler() override;
+
+ static bool isNavigationCapableButton( const css::uno::Reference< css::beans::XPropertySet >& _rxComponent );
+
+ protected:
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override;
+
+ // XPropertyHandler overriables
+ virtual void SAL_CALL inspect( const css::uno::Reference< css::uno::XInterface >& _rxIntrospectee ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override;
+ virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& _rPropertyName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getActuatingProperties( ) override;
+ virtual css::inspection::InteractiveSelectionResult
+ SAL_CALL onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, css::uno::Any& _rData, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) override;
+ virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override;
+ virtual css::inspection::LineDescriptor SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override;
+
+ // PropertyHandler overridables
+ virtual css::uno::Sequence< css::beans::Property >
+ doDescribeSupportedProperties() const override;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/cellbindinghandler.cxx b/extensions/source/propctrlr/cellbindinghandler.cxx
new file mode 100644
index 000000000..633a3574b
--- /dev/null
+++ b/extensions/source/propctrlr/cellbindinghandler.cxx
@@ -0,0 +1,487 @@
+/* -*- 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 "cellbindinghandler.hxx"
+#include "formstrings.hxx"
+#include "formmetadata.hxx"
+#include "cellbindinghelper.hxx"
+
+#include <com/sun/star/form/binding/XValueBinding.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/table/CellAddress.hpp>
+#include <com/sun/star/inspection/XObjectInspectorUI.hpp>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::table;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::inspection;
+ using namespace ::com::sun::star::form::binding;
+ using namespace ::comphelper;
+
+ CellBindingPropertyHandler::CellBindingPropertyHandler( const Reference< XComponentContext >& _rxContext )
+ :PropertyHandlerComponent( _rxContext )
+ ,m_pCellExchangeConverter( new DefaultEnumRepresentation( *m_pInfoService, ::cppu::UnoType<sal_Int16>::get(), PROPERTY_ID_CELL_EXCHANGE_TYPE ) )
+ {
+ }
+
+
+ OUString CellBindingPropertyHandler::getImplementationName( )
+ {
+ return "com.sun.star.comp.extensions.CellBindingPropertyHandler";
+ }
+
+
+ Sequence< OUString > CellBindingPropertyHandler::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.form.inspection.CellBindingPropertyHandler" };
+ }
+
+
+ void CellBindingPropertyHandler::onNewComponent()
+ {
+ PropertyHandlerComponent::onNewComponent();
+
+ Reference< XModel > xDocument( impl_getContextDocument_nothrow() );
+ DBG_ASSERT( xDocument.is(), "CellBindingPropertyHandler::onNewComponent: no document!" );
+ if ( CellBindingHelper::isSpreadsheetDocument( xDocument ) )
+ m_pHelper.reset( new CellBindingHelper( m_xComponent, xDocument ) );
+ }
+
+
+ CellBindingPropertyHandler::~CellBindingPropertyHandler( )
+ {
+ }
+
+
+ Sequence< OUString > SAL_CALL CellBindingPropertyHandler::getActuatingProperties( )
+ {
+ Sequence< OUString > aInterestingProperties{ PROPERTY_LIST_CELL_RANGE,
+ PROPERTY_BOUND_CELL,
+ PROPERTY_CONTROLSOURCE };
+ return aInterestingProperties;
+ }
+
+
+ void SAL_CALL CellBindingPropertyHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nActuatingPropId( impl_getPropertyId_throwRuntime( _rActuatingPropertyName ) );
+ OSL_PRECOND(m_pHelper,
+ "CellBindingPropertyHandler::actuatingPropertyChanged: inconsistency!");
+ // if we survived impl_getPropertyId_throwRuntime, we should have a helper, since no helper implies no properties
+
+ OSL_PRECOND( _rxInspectorUI.is(), "FormComponentPropertyHandler::actuatingPropertyChanged: no access to the UI!" );
+ if ( !_rxInspectorUI.is() )
+ throw NullPointerException();
+
+ std::vector< PropertyId > aDependentProperties;
+
+ switch ( nActuatingPropId )
+ {
+ // ----- BoundCell -----
+ case PROPERTY_ID_BOUND_CELL:
+ {
+ // the SQL-data-binding related properties need to be enabled if and only if
+ // there is *no* valid cell binding
+ Reference< XValueBinding > xBinding;
+ _rNewValue >>= xBinding;
+
+ if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_CELL_EXCHANGE_TYPE ) )
+ _rxInspectorUI->enablePropertyUI( PROPERTY_CELL_EXCHANGE_TYPE, xBinding.is() );
+ if ( impl_componentHasProperty_throw( PROPERTY_CONTROLSOURCE ) )
+ _rxInspectorUI->enablePropertyUI( PROPERTY_CONTROLSOURCE, !xBinding.is() );
+
+ if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_FILTERPROPOSAL ) )
+ _rxInspectorUI->enablePropertyUI( PROPERTY_FILTERPROPOSAL, !xBinding.is() );
+ if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_EMPTY_IS_NULL ) )
+ _rxInspectorUI->enablePropertyUI( PROPERTY_EMPTY_IS_NULL, !xBinding.is() );
+
+ aDependentProperties.push_back( PROPERTY_ID_BOUNDCOLUMN );
+
+ if ( !xBinding.is() && m_pHelper->getCurrentBinding().is() )
+ {
+ // ensure that the "transfer selection as" property is reset. Since we can't remember
+ // it at the object itself, but derive it from the binding only, we have to normalize
+ // it now that there *is* no binding anymore.
+ setPropertyValue( PROPERTY_CELL_EXCHANGE_TYPE, Any( sal_Int16(0) ) );
+ }
+ }
+ break;
+
+ // ----- CellRange -----
+ case PROPERTY_ID_LIST_CELL_RANGE:
+ {
+ // the list source related properties need to be enabled if and only if
+ // there is *no* valid external list source for the control
+ Reference< XListEntrySource > xSource;
+ _rNewValue >>= xSource;
+
+ _rxInspectorUI->enablePropertyUI( PROPERTY_STRINGITEMLIST, !xSource.is() );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_LISTSOURCE, !xSource.is() );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_LISTSOURCETYPE, !xSource.is() );
+
+ aDependentProperties.push_back( PROPERTY_ID_BOUNDCOLUMN );
+
+ // also reset the list entries if the cell range is reset
+ // #i28319#
+ if ( !_bFirstTimeInit )
+ {
+ try
+ {
+ if ( !xSource.is() )
+ {
+ setPropertyValue( PROPERTY_STRINGITEMLIST, Any( Sequence< OUString >() ) );
+ setPropertyValue( PROPERTY_TYPEDITEMLIST, Any( Sequence< Any >() ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION(
+ "extensions.propctrlr",
+ "ListCellRange: caught an exception while resetting the string items!");
+ }
+ }
+ }
+ break; // case PROPERTY_ID_LIST_CELL_RANGE
+
+ // ----- DataField -----
+ case PROPERTY_ID_CONTROLSOURCE:
+ {
+ OUString sControlSource;
+ _rNewValue >>= sControlSource;
+ if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_BOUND_CELL ) )
+ _rxInspectorUI->enablePropertyUI( PROPERTY_BOUND_CELL, sControlSource.isEmpty() );
+ }
+ break; // case PROPERTY_ID_CONTROLSOURCE
+
+ default:
+ OSL_FAIL( "CellBindingPropertyHandler::actuatingPropertyChanged: did not register for this property!" );
+ }
+
+ for (auto const& dependentProperty : aDependentProperties)
+ {
+ impl_updateDependentProperty_nothrow( dependentProperty, _rxInspectorUI );
+ }
+ }
+
+
+ void CellBindingPropertyHandler::impl_updateDependentProperty_nothrow( PropertyId _nPropId, const Reference< XObjectInspectorUI >& _rxInspectorUI ) const
+ {
+ try
+ {
+ switch ( _nPropId )
+ {
+ // ----- BoundColumn -----
+ case PROPERTY_ID_BOUNDCOLUMN:
+ {
+ CellBindingPropertyHandler* pNonConstThis = const_cast< CellBindingPropertyHandler* >( this );
+ Reference< XValueBinding > xBinding( pNonConstThis->getPropertyValue( PROPERTY_BOUND_CELL ), UNO_QUERY );
+ Reference< XListEntrySource > xListSource( pNonConstThis->getPropertyValue( PROPERTY_LIST_CELL_RANGE ), UNO_QUERY );
+
+ if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_BOUNDCOLUMN ) )
+ _rxInspectorUI->enablePropertyUI( PROPERTY_BOUNDCOLUMN, !xBinding.is() && !xListSource.is() );
+ }
+ break; // case PROPERTY_ID_BOUNDCOLUMN
+
+ } // switch
+
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "CellBindingPropertyHandler::impl_updateDependentProperty_nothrow" );
+ }
+ }
+
+
+ Any SAL_CALL CellBindingPropertyHandler::getPropertyValue( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ OSL_ENSURE(m_pHelper, "CellBindingPropertyHandler::getPropertyValue: inconsistency!");
+ // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties
+
+ Any aReturn;
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_BOUND_CELL:
+ {
+ Reference< XValueBinding > xBinding( m_pHelper->getCurrentBinding() );
+ if ( !CellBindingHelper::isCellBinding( xBinding ) )
+ xBinding.clear();
+
+ aReturn <<= xBinding;
+ }
+ break;
+
+ case PROPERTY_ID_LIST_CELL_RANGE:
+ {
+ Reference< XListEntrySource > xSource( m_pHelper->getCurrentListSource() );
+ if ( !CellBindingHelper::isCellRangeListSource( xSource ) )
+ xSource.clear();
+
+ aReturn <<= xSource;
+ }
+ break;
+
+ case PROPERTY_ID_CELL_EXCHANGE_TYPE:
+ {
+ Reference< XValueBinding > xBinding( m_pHelper->getCurrentBinding() );
+ aReturn <<= static_cast<sal_Int16>( CellBindingHelper::isCellIntegerBinding( xBinding ) ? 1 : 0 );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "CellBindingPropertyHandler::getPropertyValue: cannot handle this!" );
+ break;
+ }
+ return aReturn;
+ }
+
+
+ void SAL_CALL CellBindingPropertyHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ OSL_ENSURE(m_pHelper, "CellBindingPropertyHandler::setPropertyValue: inconsistency!");
+ // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties
+
+ try
+ {
+ Any aOldValue = getPropertyValue( _rPropertyName );
+
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_BOUND_CELL:
+ {
+ Reference< XValueBinding > xBinding;
+ _rValue >>= xBinding;
+ m_pHelper->setBinding( xBinding );
+ }
+ break;
+
+ case PROPERTY_ID_LIST_CELL_RANGE:
+ {
+ Reference< XListEntrySource > xSource;
+ _rValue >>= xSource;
+ m_pHelper->setListSource( xSource );
+ }
+ break;
+
+ case PROPERTY_ID_CELL_EXCHANGE_TYPE:
+ {
+ sal_Int16 nExchangeType = 0;
+ OSL_VERIFY( _rValue >>= nExchangeType );
+
+ Reference< XValueBinding > xBinding = m_pHelper->getCurrentBinding( );
+ if ( xBinding.is() )
+ {
+ bool bNeedIntegerBinding = ( nExchangeType == 1 );
+ if ( bNeedIntegerBinding != CellBindingHelper::isCellIntegerBinding( xBinding ) )
+ {
+ CellAddress aAddress;
+ if ( m_pHelper->getAddressFromCellBinding( xBinding, aAddress ) )
+ {
+ xBinding = m_pHelper->createCellBindingFromAddress( aAddress, bNeedIntegerBinding );
+ m_pHelper->setBinding( xBinding );
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ OSL_FAIL( "CellBindingPropertyHandler::setPropertyValue: cannot handle this!" );
+ break;
+ }
+
+ impl_setContextDocumentModified_nothrow();
+
+ Any aNewValue( getPropertyValue( _rPropertyName ) );
+ firePropertyChange( _rPropertyName, nPropId, aOldValue, aNewValue );
+ // TODO/UNOize: can't we make this a part of the base class, for all those "virtual"
+ // properties? Base class'es |setPropertyValue| could call some |doSetPropertyValue|,
+ // and handle the listener notification itself
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "CellBindingPropertyHandler::setPropertyValue" );
+ }
+ }
+
+
+ Any SAL_CALL CellBindingPropertyHandler::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Any aPropertyValue;
+
+ OSL_ENSURE(
+ m_pHelper,
+ "CellBindingPropertyHandler::convertToPropertyValue: we have no SupportedProperties!");
+ if (!m_pHelper)
+ return aPropertyValue;
+
+ PropertyId nPropId( m_pInfoService->getPropertyId( _rPropertyName ) );
+
+ OUString sControlValue;
+ OSL_VERIFY( _rControlValue >>= sControlValue );
+ switch( nPropId )
+ {
+ case PROPERTY_ID_LIST_CELL_RANGE:
+ aPropertyValue <<= m_pHelper->createCellListSourceFromStringAddress( sControlValue );
+ break;
+
+ case PROPERTY_ID_BOUND_CELL:
+ {
+ // if we have the possibility of an integer binding, then we must preserve
+ // this property's value (e.g. if the current binding is an integer binding, then
+ // the newly created one must be, too)
+ bool bIntegerBinding = false;
+ if ( m_pHelper->isCellIntegerBindingAllowed() )
+ {
+ sal_Int16 nCurrentBindingType = 0;
+ getPropertyValue( PROPERTY_CELL_EXCHANGE_TYPE ) >>= nCurrentBindingType;
+ bIntegerBinding = ( nCurrentBindingType != 0 );
+ }
+ aPropertyValue <<= m_pHelper->createCellBindingFromStringAddress( sControlValue, bIntegerBinding );
+ }
+ break;
+
+ case PROPERTY_ID_CELL_EXCHANGE_TYPE:
+ m_pCellExchangeConverter->getValueFromDescription( sControlValue, aPropertyValue );
+ break;
+
+ default:
+ OSL_FAIL( "CellBindingPropertyHandler::convertToPropertyValue: cannot handle this!" );
+ break;
+ }
+
+ return aPropertyValue;
+ }
+
+
+ Any SAL_CALL CellBindingPropertyHandler::convertToControlValue( const OUString& _rPropertyName,
+ const Any& _rPropertyValue, const Type& /*_rControlValueType*/ )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Any aControlValue;
+
+ OSL_ENSURE(
+ m_pHelper,
+ "CellBindingPropertyHandler::convertToControlValue: we have no SupportedProperties!");
+ if (!m_pHelper)
+ return aControlValue;
+
+ PropertyId nPropId( m_pInfoService->getPropertyId( _rPropertyName ) );
+
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_BOUND_CELL:
+ {
+ Reference< XValueBinding > xBinding;
+ bool bSuccess = _rPropertyValue >>= xBinding;
+ OSL_ENSURE( bSuccess, "CellBindingPropertyHandler::convertToControlValue: invalid value (1)!" );
+
+ // the only value binding we support so far is linking to spreadsheet cells
+ aControlValue <<= m_pHelper->getStringAddressFromCellBinding( xBinding );
+ }
+ break;
+
+ case PROPERTY_ID_LIST_CELL_RANGE:
+ {
+ Reference< XListEntrySource > xSource;
+ bool bSuccess = _rPropertyValue >>= xSource;
+ OSL_ENSURE( bSuccess, "CellBindingPropertyHandler::convertToControlValue: invalid value (2)!" );
+
+ // the only value binding we support so far is linking to spreadsheet cells
+ aControlValue <<= m_pHelper->getStringAddressFromCellListSource( xSource );
+ }
+ break;
+
+ case PROPERTY_ID_CELL_EXCHANGE_TYPE:
+ aControlValue <<= m_pCellExchangeConverter->getDescriptionForValue( _rPropertyValue );
+ break;
+
+ default:
+ OSL_FAIL( "CellBindingPropertyHandler::convertToControlValue: cannot handle this!" );
+ break;
+ }
+
+ return aControlValue;
+ }
+
+
+ Sequence< Property > CellBindingPropertyHandler::doDescribeSupportedProperties() const
+ {
+ std::vector< Property > aProperties;
+
+ bool bAllowCellLinking = m_pHelper && m_pHelper->isCellBindingAllowed();
+ bool bAllowCellIntLinking = m_pHelper && m_pHelper->isCellIntegerBindingAllowed();
+ bool bAllowListCellRange = m_pHelper && m_pHelper->isListCellRangeAllowed();
+ if ( bAllowCellLinking || bAllowListCellRange || bAllowCellIntLinking )
+ {
+ sal_Int32 nPos = ( bAllowCellLinking ? 1 : 0 )
+ + ( bAllowListCellRange ? 1 : 0 )
+ + ( bAllowCellIntLinking ? 1 : 0 );
+ aProperties.resize( nPos );
+
+ if ( bAllowCellLinking )
+ {
+ aProperties[ --nPos ] = Property( PROPERTY_BOUND_CELL, PROPERTY_ID_BOUND_CELL,
+ ::cppu::UnoType<OUString>::get(), 0 );
+ }
+ if ( bAllowCellIntLinking )
+ {
+ aProperties[ --nPos ] = Property( PROPERTY_CELL_EXCHANGE_TYPE, PROPERTY_ID_CELL_EXCHANGE_TYPE,
+ ::cppu::UnoType<sal_Int16>::get(), 0 );
+ }
+ if ( bAllowListCellRange )
+ {
+ aProperties[ --nPos ] = Property( PROPERTY_LIST_CELL_RANGE, PROPERTY_ID_LIST_CELL_RANGE,
+ ::cppu::UnoType<OUString>::get(), 0 );
+ }
+ }
+
+ if ( aProperties.empty() )
+ return Sequence< Property >();
+ return comphelper::containerToSequence(aProperties);
+ }
+
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_CellBindingPropertyHandler_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::CellBindingPropertyHandler(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/cellbindinghandler.hxx b/extensions/source/propctrlr/cellbindinghandler.hxx
new file mode 100644
index 000000000..4e81b0624
--- /dev/null
+++ b/extensions/source/propctrlr/cellbindinghandler.hxx
@@ -0,0 +1,92 @@
+/* -*- 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 "propertyhandler.hxx"
+
+#include <rtl/ref.hxx>
+
+#include <memory>
+
+
+namespace pcr
+{
+
+
+ class CellBindingHelper;
+ class IPropertyEnumRepresentation;
+
+ class CellBindingPropertyHandler : public PropertyHandlerComponent
+ {
+ private:
+ std::unique_ptr< CellBindingHelper > m_pHelper;
+ ::rtl::Reference< IPropertyEnumRepresentation > m_pCellExchangeConverter;
+
+ public:
+ explicit CellBindingPropertyHandler(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext
+ );
+
+ protected:
+ virtual ~CellBindingPropertyHandler() override;
+
+ protected:
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override;
+
+ // XPropertyHandler overriables
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override;
+ virtual css::uno::Any SAL_CALL convertToPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rControlValue ) override;
+ virtual css::uno::Any SAL_CALL convertToControlValue( const OUString& _rPropertyName, const css::uno::Any& _rPropertyValue, const css::uno::Type& _rControlValueType ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getActuatingProperties( ) override;
+ virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override;
+
+ // PropertyHandler overridables
+ virtual css::uno::Sequence< css::beans::Property >
+ doDescribeSupportedProperties() const override;
+ virtual void onNewComponent() override;
+
+ private:
+ /** updates a property (UI) whose state depends on more than one other property
+
+ ->actuatingPropertyChanged is called for certain properties in whose changes
+ we expressed interes (->getActuatingProperty). Now such a property change can
+ result in simple UI updates, for instance another property being enabled or disabled.
+
+ However, it can also result in a more complex change: The current (UI) state might
+ depend on the value of more than one other property. Those dependent properties (their
+ UI, more precisely) are updated in this method.
+
+ @param _nPropid
+ the ->PropertyId of the dependent property whose UI state is to be updated
+
+ @param _rxInspectorUI
+ provides access to the property browser UI. Must not be <NULL/>.
+ */
+ void impl_updateDependentProperty_nothrow( PropertyId _nPropId, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) const;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/cellbindinghelper.cxx b/extensions/source/propctrlr/cellbindinghelper.cxx
new file mode 100644
index 000000000..3c66fc8c9
--- /dev/null
+++ b/extensions/source/propctrlr/cellbindinghelper.cxx
@@ -0,0 +1,540 @@
+/* -*- 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 "cellbindinghelper.hxx"
+#include <com/sun/star/form/binding/XBindableValue.hpp>
+#include <com/sun/star/form/binding/XListEntrySink.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/form/XGridColumnFactory.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/form/XFormsSupplier.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <unotools/transliterationwrapper.hxx>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+#include "formstrings.hxx"
+
+#include <algorithm>
+
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::sheet;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::drawing;
+ using namespace ::com::sun::star::table;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::i18n;
+ using namespace ::com::sun::star::form::binding;
+
+ namespace
+ {
+
+ struct StringCompare
+ {
+ private:
+ OUString m_sReference;
+
+ public:
+ explicit StringCompare( const OUString& _rReference ) : m_sReference( _rReference ) { }
+
+ bool operator()( std::u16string_view _rCompare )
+ {
+ return ( _rCompare == m_sReference );
+ }
+ };
+ }
+
+
+ CellBindingHelper::CellBindingHelper( const Reference< XPropertySet >& _rxControlModel, const Reference< XModel >& _rxContextDocument )
+ :m_xControlModel( _rxControlModel )
+ {
+ OSL_ENSURE( m_xControlModel.is(), "CellBindingHelper::CellBindingHelper: invalid control model!" );
+
+ m_xDocument.set(_rxContextDocument, css::uno::UNO_QUERY);
+ OSL_ENSURE( m_xDocument.is(), "CellBindingHelper::CellBindingHelper: This is no spreadsheet document!" );
+
+ OSL_ENSURE( isSpreadsheetDocumentWhichSupplies( SERVICE_ADDRESS_CONVERSION ),
+ "CellBindingHelper::CellBindingHelper: the document cannot convert address representations!" );
+ }
+
+
+ bool CellBindingHelper::isSpreadsheetDocument( const Reference< XModel >& _rxContextDocument )
+ {
+ return Reference< XSpreadsheetDocument >::query( _rxContextDocument ).is();
+ }
+
+
+ sal_Int16 CellBindingHelper::getControlSheetIndex( Reference< XSpreadsheet >& _out_rxSheet ) const
+ {
+ sal_Int16 nSheetIndex = -1;
+ // every sheet has a draw page, and every draw page has a forms collection.
+ // Our control, OTOH, belongs to a forms collection. Match these...
+ try
+ {
+ // for determining the draw page, we need the forms collection which
+ // the object belongs to. This is the first object up the hierarchy which is
+ // *no* XForm (and, well, no XGridColumnFactory)
+ Reference< XChild > xCheck( m_xControlModel, UNO_QUERY );
+ Reference< XForm > xParentAsForm; if ( xCheck.is() ) xParentAsForm.set(xCheck->getParent(), css::uno::UNO_QUERY);
+ Reference< XGridColumnFactory > xParentAsGrid; if ( xCheck.is() ) xParentAsGrid.set(xCheck->getParent(), css::uno::UNO_QUERY);
+
+ while ( ( xParentAsForm.is() || xParentAsGrid.is() ) && xCheck.is() )
+ {
+ xCheck.set(xCheck->getParent(), css::uno::UNO_QUERY);
+ xParentAsForm.set(xCheck.is() ? xCheck->getParent() : Reference< XForm >(), css::uno::UNO_QUERY);
+ xParentAsGrid.set(xCheck.is() ? xCheck->getParent() : Reference< XGridColumnFactory >(), css::uno::UNO_QUERY);
+ }
+ Reference< XInterface > xFormsCollection( xCheck.is() ? xCheck->getParent() : Reference< XInterface >() );
+
+ // now iterate through the sheets
+ Reference< XIndexAccess > xSheets( m_xDocument->getSheets(), UNO_QUERY );
+ if ( xSheets.is() && xFormsCollection.is() )
+ {
+ for ( sal_Int32 i = 0; i < xSheets->getCount(); ++i )
+ {
+ Reference< XDrawPageSupplier > xSuppPage( xSheets->getByIndex( i ), UNO_QUERY_THROW );
+ Reference< XFormsSupplier > xSuppForms( xSuppPage->getDrawPage(), UNO_QUERY_THROW );
+
+ if ( xSuppForms->getForms() == xFormsCollection )
+ { // found it
+ nSheetIndex = static_cast<sal_Int16>(i);
+ _out_rxSheet.set( xSuppPage, UNO_QUERY_THROW );
+ break;
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+
+ return nSheetIndex;
+ }
+
+
+ bool CellBindingHelper::convertStringAddress( const OUString& _rAddressDescription, CellAddress& /* [out] */ _rAddress ) const
+ {
+ Any aAddress;
+ return doConvertAddressRepresentations(
+ PROPERTY_UI_REPRESENTATION,
+ Any( _rAddressDescription ),
+ PROPERTY_ADDRESS,
+ aAddress,
+ false
+ )
+ && ( aAddress >>= _rAddress );
+ }
+
+
+ bool CellBindingHelper::doConvertAddressRepresentations( const OUString& _rInputProperty, const Any& _rInputValue,
+ const OUString& _rOutputProperty, Any& _rOutputValue, bool _bIsRange ) const
+ {
+ bool bSuccess = false;
+
+ Reference< XPropertySet > xConverter(
+ createDocumentDependentInstance(
+ _bIsRange ? OUString(SERVICE_RANGEADDRESS_CONVERSION) : OUString(SERVICE_ADDRESS_CONVERSION),
+ OUString(),
+ Any()
+ ),
+ UNO_QUERY
+ );
+ OSL_ENSURE( xConverter.is(), "CellBindingHelper::doConvertAddressRepresentations: could not get a converter service!" );
+ if ( xConverter.is() )
+ {
+ try
+ {
+ Reference< XSpreadsheet > xSheet;
+ xConverter->setPropertyValue( PROPERTY_REFERENCE_SHEET, Any( static_cast<sal_Int32>(getControlSheetIndex( xSheet )) ) );
+ xConverter->setPropertyValue( _rInputProperty, _rInputValue );
+ _rOutputValue = xConverter->getPropertyValue( _rOutputProperty );
+ bSuccess = true;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "CellBindingHelper::doConvertAddressRepresentations" );
+ }
+ }
+
+ return bSuccess;
+ }
+
+
+ bool CellBindingHelper::convertStringAddress( const OUString& _rAddressDescription,
+ CellRangeAddress& /* [out] */ _rAddress ) const
+ {
+ Any aAddress;
+ return doConvertAddressRepresentations(
+ PROPERTY_UI_REPRESENTATION,
+ Any( _rAddressDescription ),
+ PROPERTY_ADDRESS,
+ aAddress,
+ true
+ )
+ && ( aAddress >>= _rAddress );
+ }
+
+
+ Reference< XValueBinding > CellBindingHelper::createCellBindingFromAddress( const CellAddress& _rAddress, bool _bSupportIntegerExchange ) const
+ {
+ Reference< XValueBinding > xBinding( createDocumentDependentInstance(
+ _bSupportIntegerExchange ? OUString(SERVICE_SHEET_CELL_INT_BINDING) : OUString(SERVICE_SHEET_CELL_BINDING),
+ PROPERTY_BOUND_CELL,
+ Any( _rAddress )
+ ), UNO_QUERY );
+
+ return xBinding;
+ }
+
+
+ Reference< XValueBinding > CellBindingHelper::createCellBindingFromStringAddress( const OUString& _rAddress, bool _bSupportIntegerExchange ) const
+ {
+ Reference< XValueBinding > xBinding;
+ if ( !m_xDocument.is() )
+ // very bad ...
+ return xBinding;
+
+ // get the UNO representation of the address
+ CellAddress aAddress;
+ if ( _rAddress.isEmpty() || !convertStringAddress( _rAddress, aAddress ) )
+ return xBinding;
+
+ return createCellBindingFromAddress( aAddress, _bSupportIntegerExchange );
+ }
+
+
+ Reference< XListEntrySource > CellBindingHelper::createCellListSourceFromStringAddress( const OUString& _rAddress ) const
+ {
+ Reference< XListEntrySource > xSource;
+
+ CellRangeAddress aRangeAddress;
+ if ( _rAddress.isEmpty() || !convertStringAddress( _rAddress, aRangeAddress ) )
+ return xSource;
+
+ // create a range object for this address
+ xSource.set(createDocumentDependentInstance(
+ SERVICE_SHEET_CELLRANGE_LISTSOURCE,
+ PROPERTY_LIST_CELL_RANGE,
+ Any( aRangeAddress )
+ ), css::uno::UNO_QUERY);
+
+ return xSource;
+ }
+
+
+ Reference< XInterface > CellBindingHelper::createDocumentDependentInstance( const OUString& _rService, const OUString& _rArgumentName,
+ const Any& _rArgumentValue ) const
+ {
+ Reference< XInterface > xReturn;
+
+ Reference< XMultiServiceFactory > xDocumentFactory( m_xDocument, UNO_QUERY );
+ OSL_ENSURE( xDocumentFactory.is(), "CellBindingHelper::createDocumentDependentInstance: no document service factory!" );
+ if ( xDocumentFactory.is() )
+ {
+ try
+ {
+ if ( !_rArgumentName.isEmpty() )
+ {
+ Sequence aArgs{ Any(NamedValue(_rArgumentName, _rArgumentValue)) };
+ xReturn = xDocumentFactory->createInstanceWithArguments( _rService, aArgs );
+ }
+ else
+ {
+ xReturn = xDocumentFactory->createInstance( _rService );
+ }
+ }
+ catch ( const Exception& )
+ {
+ OSL_FAIL( "CellBindingHelper::createDocumentDependentInstance: could not create the binding at the document!" );
+ }
+ }
+ return xReturn;
+ }
+
+
+ bool CellBindingHelper::getAddressFromCellBinding(
+ const Reference< XValueBinding >& _rxBinding, CellAddress& _rAddress ) const
+ {
+ OSL_PRECOND( !_rxBinding.is() || isCellBinding( _rxBinding ), "CellBindingHelper::getAddressFromCellBinding: this is no cell binding!" );
+
+ bool bReturn = false;
+ if ( !m_xDocument.is() )
+ // very bad ...
+ return bReturn;
+
+ try
+ {
+ Reference< XPropertySet > xBindingProps( _rxBinding, UNO_QUERY );
+ OSL_ENSURE( xBindingProps.is() || !_rxBinding.is(), "CellBindingHelper::getAddressFromCellBinding: no property set for the binding!" );
+ if ( xBindingProps.is() )
+ {
+ bReturn = ( xBindingProps->getPropertyValue( PROPERTY_BOUND_CELL ) >>= _rAddress );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "CellBindingHelper::getAddressFromCellBinding" );
+ }
+
+ return bReturn;
+ }
+
+
+ OUString CellBindingHelper::getStringAddressFromCellBinding( const Reference< XValueBinding >& _rxBinding ) const
+ {
+ CellAddress aAddress;
+ OUString sAddress;
+ if ( getAddressFromCellBinding( _rxBinding, aAddress ) )
+ {
+ Any aStringAddress;
+ doConvertAddressRepresentations( PROPERTY_ADDRESS, Any( aAddress ),
+ PROPERTY_UI_REPRESENTATION, aStringAddress, false );
+
+ aStringAddress >>= sAddress;
+ }
+
+ return sAddress;
+ }
+
+
+ OUString CellBindingHelper::getStringAddressFromCellListSource( const Reference< XListEntrySource >& _rxSource ) const
+ {
+ OSL_PRECOND( !_rxSource.is() || isCellRangeListSource( _rxSource ), "CellBindingHelper::getStringAddressFromCellListSource: this is no cell list source!" );
+
+ OUString sAddress;
+ if ( !m_xDocument.is() )
+ // very bad ...
+ return sAddress;
+
+ try
+ {
+ Reference< XPropertySet > xSourceProps( _rxSource, UNO_QUERY );
+ OSL_ENSURE( xSourceProps.is() || !_rxSource.is(), "CellBindingHelper::getStringAddressFromCellListSource: no property set for the list source!" );
+ if ( xSourceProps.is() )
+ {
+ CellRangeAddress aRangeAddress;
+ xSourceProps->getPropertyValue( PROPERTY_LIST_CELL_RANGE ) >>= aRangeAddress;
+
+ Any aStringAddress;
+ doConvertAddressRepresentations( PROPERTY_ADDRESS, Any( aRangeAddress ),
+ PROPERTY_UI_REPRESENTATION, aStringAddress, true );
+ aStringAddress >>= sAddress;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "CellBindingHelper::getStringAddressFromCellListSource" );
+ }
+
+ return sAddress;
+ }
+
+
+ bool CellBindingHelper::isSpreadsheetDocumentWhichSupplies( const OUString& _rService ) const
+ {
+ bool bYesItIs = false;
+
+ Reference< XServiceInfo > xSI( m_xDocument, UNO_QUERY );
+ if ( xSI.is() && xSI->supportsService( SERVICE_SPREADSHEET_DOCUMENT ) )
+ {
+ Reference< XMultiServiceFactory > xDocumentFactory( m_xDocument, UNO_QUERY );
+ OSL_ENSURE( xDocumentFactory.is(), "CellBindingHelper::isSpreadsheetDocumentWhichSupplies: spreadsheet document, but no factory?" );
+
+ if ( xDocumentFactory.is() )
+ {
+ const Sequence<OUString> aAvailableServices = xDocumentFactory->getAvailableServiceNames( );
+
+ bYesItIs = std::any_of(
+ aAvailableServices.begin(),
+ aAvailableServices.end(),
+ StringCompare( _rService )
+ );
+ }
+ }
+
+ return bYesItIs;
+ }
+
+
+ bool CellBindingHelper::isListCellRangeAllowed( ) const
+ {
+ bool bAllow( false );
+
+ Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY );
+ if ( xSink.is() )
+ {
+ bAllow = isSpreadsheetDocumentWhichSupplies( SERVICE_SHEET_CELLRANGE_LISTSOURCE );
+ }
+
+ return bAllow;
+ }
+
+
+ bool CellBindingHelper::isCellIntegerBindingAllowed( ) const
+ {
+ bool bAllow( true );
+
+ // first, we only offer this for controls which allow bindings in general
+ Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY );
+ if ( !xBindable.is() )
+ bAllow = false;
+
+ // then, we must live in a spreadsheet document which can provide the special
+ // service needed for exchanging integer values
+ if ( bAllow )
+ bAllow = isSpreadsheetDocumentWhichSupplies( SERVICE_SHEET_CELL_INT_BINDING );
+
+ // then, we only offer this for list boxes
+ if ( bAllow )
+ {
+ try
+ {
+ sal_Int16 nClassId = FormComponentType::CONTROL;
+ m_xControlModel->getPropertyValue( PROPERTY_CLASSID ) >>= nClassId;
+ if ( FormComponentType::LISTBOX != nClassId )
+ bAllow = false;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "CellBindingHelper::isCellIntegerBindingAllowed" );
+ // are there really control models which survive isCellBindingAllowed, but don't have a ClassId
+ // property?
+ bAllow = false;
+ }
+ }
+
+ return bAllow;
+ }
+
+
+ bool CellBindingHelper::isCellBindingAllowed( ) const
+ {
+ bool bAllow( false );
+
+ Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY );
+ if ( xBindable.is() )
+ {
+ // the control can potentially be bound to an external value
+ // Does it live within a Calc document, and is able to supply CellBindings?
+ bAllow = isSpreadsheetDocumentWhichSupplies( SERVICE_SHEET_CELL_BINDING );
+ }
+
+ // disallow for some types
+ // TODO: shouldn't the XBindableValue supply a list of supported types, and we can distinguish
+ // using this list? The current behavior below is somewhat hackish...
+ if ( bAllow )
+ {
+ try
+ {
+ sal_Int16 nClassId = FormComponentType::CONTROL;
+ m_xControlModel->getPropertyValue( PROPERTY_CLASSID ) >>= nClassId;
+ if ( ( FormComponentType::DATEFIELD == nClassId ) || ( FormComponentType::TIMEFIELD == nClassId ) )
+ bAllow = false;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "CellBindingHelper::isCellBindingAllowed" );
+ bAllow = false;
+ }
+ }
+ return bAllow;
+ }
+
+
+ bool CellBindingHelper::isCellBinding( const Reference< XValueBinding >& _rxBinding )
+ {
+ return doesComponentSupport( _rxBinding, SERVICE_SHEET_CELL_BINDING );
+ }
+
+
+ bool CellBindingHelper::isCellIntegerBinding( const Reference< XValueBinding >& _rxBinding )
+ {
+ return doesComponentSupport( _rxBinding, SERVICE_SHEET_CELL_INT_BINDING );
+ }
+
+
+ bool CellBindingHelper::isCellRangeListSource( const Reference< XListEntrySource >& _rxSource )
+ {
+ return doesComponentSupport( _rxSource, SERVICE_SHEET_CELLRANGE_LISTSOURCE );
+ }
+
+
+ bool CellBindingHelper::doesComponentSupport( const Reference< XInterface >& _rxComponent, const OUString& _rService )
+ {
+ Reference< XServiceInfo > xSI( _rxComponent, UNO_QUERY );
+ bool bDoes = xSI.is() && xSI->supportsService( _rService );
+ return bDoes;
+ }
+
+
+ Reference< XValueBinding > CellBindingHelper::getCurrentBinding( ) const
+ {
+ Reference< XValueBinding > xBinding;
+ Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY );
+ if ( xBindable.is() )
+ xBinding = xBindable->getValueBinding();
+ return xBinding;
+ }
+
+
+ Reference< XListEntrySource > CellBindingHelper::getCurrentListSource( ) const
+ {
+ Reference< XListEntrySource > xSource;
+ Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY );
+ if ( xSink.is() )
+ xSource = xSink->getListEntrySource();
+ return xSource;
+ }
+
+
+ void CellBindingHelper::setBinding( const Reference< XValueBinding >& _rxBinding )
+ {
+ Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY );
+ OSL_PRECOND( xBindable.is(), "CellBindingHelper::setBinding: the object is not bindable!" );
+ if ( xBindable.is() )
+ xBindable->setValueBinding( _rxBinding );
+ }
+
+
+ void CellBindingHelper::setListSource( const Reference< XListEntrySource >& _rxSource )
+ {
+ Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY );
+ OSL_PRECOND( xSink.is(), "CellBindingHelper::setListSource: the object is no list entry sink!" );
+ if ( xSink.is() )
+ xSink->setListEntrySource( _rxSource );
+ }
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/cellbindinghelper.hxx b/extensions/source/propctrlr/cellbindinghelper.hxx
new file mode 100644
index 000000000..a2c85cd65
--- /dev/null
+++ b/extensions/source/propctrlr/cellbindinghelper.hxx
@@ -0,0 +1,272 @@
+/* -*- 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/frame/XModel.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/table/CellAddress.hpp>
+#include <com/sun/star/table/CellRangeAddress.hpp>
+#include <com/sun/star/form/binding/XValueBinding.hpp>
+#include <com/sun/star/form/binding/XListEntrySource.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+
+
+namespace pcr
+{
+
+ /** encapsulates functionality related to binding a form control to a spreadsheet cell
+ */
+ class CellBindingHelper final
+ {
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xControlModel; // the model we work for
+ css::uno::Reference< css::sheet::XSpreadsheetDocument >
+ m_xDocument; // the document where the model lives
+
+ public:
+ /** ctor
+ @param _rxControlModel
+ the control model which is or will be bound
+ */
+ CellBindingHelper(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel,
+ const css::uno::Reference< css::frame::XModel >& _rxContextDocument
+ );
+
+ /** determines whether the given model is a spreadsheet document model
+
+ <p>If this method returns <FALSE/>, you cannot instantiate a CellBindingHelper with
+ the document, since then no of its functionality will be available.</p>
+ */
+ static bool isSpreadsheetDocument(
+ const css::uno::Reference< css::frame::XModel >& _rxContextDocument
+ );
+
+ /** gets a cell binding for the given address
+ @precond
+ isCellBindingAllowed returns <TRUE/>
+ */
+ css::uno::Reference< css::form::binding::XValueBinding >
+ createCellBindingFromStringAddress(
+ const OUString& _rAddress,
+ bool _bSupportIntegerExchange
+ ) const;
+
+ /** creates a cell binding (supporting integer exchange, if requested) for
+ the given address object
+ */
+ css::uno::Reference< css::form::binding::XValueBinding >
+ createCellBindingFromAddress(
+ const css::table::CellAddress& _rAddress,
+ bool _bSupportIntegerExchange
+ ) const;
+
+ /** gets a cell range list source binding for the given address
+ */
+ css::uno::Reference< css::form::binding::XListEntrySource >
+ createCellListSourceFromStringAddress( const OUString& _rAddress ) const;
+
+ /** creates a string representation for the given value binding's address
+
+ <p>If the sheet of the bound cell is the same as the sheet which our control belongs
+ to, then the sheet name is omitted in the resulting string representation.</p>
+
+ @precond
+ The binding is a valid cell binding, or <NULL/>
+ @see isCellBinding
+ */
+ OUString getStringAddressFromCellBinding(
+ const css::uno::Reference< css::form::binding::XValueBinding >& _rxBinding
+ ) const;
+
+ /** creates an address object for the given value binding's address
+
+ @precond
+ The binding is a valid cell binding, or <NULL/>
+ @return
+ <FALSE/> if and only if an error occurred and no valid address could be obtained
+ @see isCellBinding
+ */
+ bool getAddressFromCellBinding(
+ const css::uno::Reference< css::form::binding::XValueBinding >& _rxBinding,
+ css::table::CellAddress& _rAddress
+ ) const;
+
+ /** creates a string representation for the given list source's range address
+
+ <p>If the sheet of the cell range which acts as list source is the same as the
+ sheet which our control belongs to, then the sheet name is omitted in the
+ resulting string representation.</p>
+
+ @precond
+ The object is a valid cell range list source, or <NULL/>
+ @see isCellRangeListSource
+ */
+ OUString getStringAddressFromCellListSource(
+ const css::uno::Reference< css::form::binding::XListEntrySource >& _rxSource
+ ) const;
+
+ /** returns the current binding of our control model, if any.
+ */
+ css::uno::Reference< css::form::binding::XValueBinding >
+ getCurrentBinding( ) const;
+
+ /** returns the current external list source of the control model, if any
+ */
+ css::uno::Reference< css::form::binding::XListEntrySource >
+ getCurrentListSource( ) const;
+
+ /** sets a new binding for our control model
+ @precond
+ the control model is bindable (which is implied by <member>isCellBindingAllowed</member>
+ returning <TRUE/>)
+ */
+ void setBinding(
+ const css::uno::Reference< css::form::binding::XValueBinding >& _rxBinding
+ );
+
+ /** sets a list source for our control model
+ @precond
+ the control model is a list sink (which is implied by <member>isListCellRangeAllowed</member>
+ returning <TRUE/>)
+ */
+ void setListSource(
+ const css::uno::Reference< css::form::binding::XListEntrySource >& _rxSource
+ );
+
+ /** checks whether it's possible to bind the control model to a spreadsheet cell
+ */
+ bool isCellBindingAllowed( ) const;
+
+ /** checks whether it's possible to bind the control model to a spreadsheet cell,
+ with exchanging integer values
+ */
+ bool isCellIntegerBindingAllowed( ) const;
+
+ /** checks whether it's possible to bind the control model to range of spreadsheet cells
+ supplying the list entries
+ */
+ bool isListCellRangeAllowed( ) const;
+
+ /** checks whether a given binding is a spreadsheet cell binding
+ */
+ static bool isCellBinding(
+ const css::uno::Reference< css::form::binding::XValueBinding >& _rxBinding
+ );
+
+ /** checks whether a given binding is a spreadsheet cell binding, exchanging
+ integer values
+ */
+ static bool isCellIntegerBinding(
+ const css::uno::Reference< css::form::binding::XValueBinding >& _rxBinding
+ );
+
+ /** checks whether a given list source is a spreadsheet cell list source
+ */
+ static bool isCellRangeListSource(
+ const css::uno::Reference< css::form::binding::XListEntrySource >& _rxSource
+ );
+
+ /** retrieves the index of the sheet which our control belongs to
+ @return the index of the sheet which our control belongs to or -1, if an error occurred
+ */
+ sal_Int16 getControlSheetIndex(
+ css::uno::Reference< css::sheet::XSpreadsheet >& _out_rxSheet
+ ) const;
+
+ private:
+ /** creates an address object from a string representation of a cell address
+ */
+ bool convertStringAddress(
+ const OUString& _rAddressDescription,
+ css::table::CellAddress& /* [out] */ _rAddress
+ ) const;
+
+ /** creates an address range object from a string representation of a cell range address
+ */
+ bool convertStringAddress(
+ const OUString& _rAddressDescription,
+ css::table::CellRangeAddress& /* [out] */ _rAddress
+ ) const;
+
+ /** determines if our document is a spreadsheet document, *and* can supply
+ the given service
+ */
+ bool isSpreadsheetDocumentWhichSupplies( const OUString& _rService ) const;
+
+ /** checks whether a given component supports a given service
+ */
+ static bool doesComponentSupport(
+ const css::uno::Reference< css::uno::XInterface >& _rxComponent,
+ const OUString& _rService
+ );
+
+ /** uses the document (it's factory interface, respectively) to create a component instance
+ @param _rService
+ the service name
+ @param _rArgumentName
+ the name of the single argument to pass during creation. May be empty, in this case
+ no arguments are passed
+ @param _rArgumentValue
+ the value of the instantiation argument. Not evaluated if <arg>_rArgumentName</arg>
+ is empty.
+ */
+ css::uno::Reference< css::uno::XInterface >
+ createDocumentDependentInstance(
+ const OUString& _rService,
+ const OUString& _rArgumentName,
+ const css::uno::Any& _rArgumentValue
+ ) const;
+
+ /** converts an address representation into another one
+
+ @param _rInputProperty
+ the input property name for the conversion service
+ @param _rInputValue
+ the input property value for the conversion service
+ @param _rOutputProperty
+ the output property name for the conversion service
+ @param _rOutputValue
+ the output property value for the conversion service
+ @param _bIsRange
+ if <TRUE/>, the RangeAddressConversion service will be used, else
+ the AddressConversion service
+
+ @return
+ <TRUE/> if any only if the conversion was successful
+
+ @see css::table::CellAddressConversion
+ @see css::table::CellRangeAddressConversion
+ */
+ bool doConvertAddressRepresentations(
+ const OUString& _rInputProperty,
+ const css::uno::Any& _rInputValue,
+ const OUString& _rOutputProperty,
+ css::uno::Any& _rOutputValue,
+ bool _bIsRange
+ ) const;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/commoncontrol.cxx b/extensions/source/propctrlr/commoncontrol.cxx
new file mode 100644
index 000000000..243bbd813
--- /dev/null
+++ b/extensions/source/propctrlr/commoncontrol.cxx
@@ -0,0 +1,134 @@
+/* -*- 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 "commoncontrol.hxx"
+#include <tools/diagnose_ex.h>
+
+
+namespace pcr
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::inspection::XPropertyControlContext;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::inspection::XPropertyControl;
+
+ CommonBehaviourControlHelper::CommonBehaviourControlHelper( sal_Int16 _nControlType, XPropertyControl& _rAntiImpl )
+ :m_nControlType( _nControlType )
+ ,m_rAntiImpl( _rAntiImpl )
+ ,m_bModified( false )
+ {
+ }
+
+
+ CommonBehaviourControlHelper::~CommonBehaviourControlHelper()
+ {
+ }
+
+ void CommonBehaviourControlHelper::setControlContext( const Reference< XPropertyControlContext >& _controlcontext )
+ {
+ m_xContext = _controlcontext;
+ }
+
+ void CommonBehaviourControlHelper::notifyModifiedValue( )
+ {
+ if ( isModified() && m_xContext.is() )
+ {
+ try
+ {
+ m_xContext->valueChanged( &m_rAntiImpl );
+ m_bModified = false;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+ }
+
+ void CommonBehaviourControlHelper::editChanged()
+ {
+ setModified();
+ }
+
+ IMPL_LINK_NOARG( CommonBehaviourControlHelper, EditModifiedHdl, weld::Entry&, void )
+ {
+ editChanged();
+ }
+
+ IMPL_LINK_NOARG( CommonBehaviourControlHelper, ModifiedHdl, weld::ComboBox&, void )
+ {
+ setModified();
+ // notify as soon as the Data source is changed, don't wait until we lose focus
+ // because the Content dropdown cannot be populated after it is popped up
+ // and going from Data source direct to Content may give focus-lost to
+ // Content after the popup attempt is made
+ notifyModifiedValue();
+ }
+
+ IMPL_LINK_NOARG( CommonBehaviourControlHelper, MetricModifiedHdl, weld::MetricSpinButton&, void )
+ {
+ setModified();
+ }
+
+ IMPL_LINK_NOARG( CommonBehaviourControlHelper, FormattedModifiedHdl, weld::FormattedSpinButton&, void )
+ {
+ setModified();
+ }
+
+ IMPL_LINK_NOARG( CommonBehaviourControlHelper, TimeModifiedHdl, weld::FormattedSpinButton&, void )
+ {
+ setModified();
+ }
+
+ IMPL_LINK_NOARG( CommonBehaviourControlHelper, DateModifiedHdl, SvtCalendarBox&, void )
+ {
+ setModified();
+ }
+
+ IMPL_LINK_NOARG( CommonBehaviourControlHelper, ColorModifiedHdl, ColorListBox&, void )
+ {
+ setModified();
+ }
+
+ IMPL_LINK_NOARG( CommonBehaviourControlHelper, GetFocusHdl, weld::Widget&, void )
+ {
+ try
+ {
+ if ( m_xContext.is() )
+ m_xContext->focusGained( &m_rAntiImpl );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+ IMPL_LINK_NOARG( CommonBehaviourControlHelper, LoseFocusHdl, weld::Widget&, void )
+ {
+ // TODO/UNOize: should this be outside the default control's implementations? If somebody
+ // has an own control implementation, which does *not* do this - would this be allowed?
+ // If not, then we must move this logic out of here.
+ notifyModifiedValue();
+ }
+
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/commoncontrol.hxx b/extensions/source/propctrlr/commoncontrol.hxx
new file mode 100644
index 000000000..746f2f56f
--- /dev/null
+++ b/extensions/source/propctrlr/commoncontrol.hxx
@@ -0,0 +1,208 @@
+/* -*- 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/inspection/XPropertyControl.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <tools/link.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/weldutils.hxx>
+
+class NotifyEvent;
+class ColorListBox;
+class SvtCalendarBox;
+
+namespace pcr
+{
+
+ //= CommonBehaviourControlHelper
+
+ /** A helper class for implementing the <type scope="css::inspection">XPropertyControl</type>
+ or one of its derived interfaces.
+
+ This class is used as a base class the CommonBehaviourControl template.
+ */
+ class CommonBehaviourControlHelper
+ {
+ private:
+ sal_Int16 m_nControlType;
+ css::uno::Reference< css::inspection::XPropertyControlContext >
+ m_xContext;
+ css::inspection::XPropertyControl&
+ m_rAntiImpl;
+ bool m_bModified;
+
+ public:
+ /** creates the instance
+ @param nControlType
+ the type of the control - one of the <type scope="css::inspection">PropertyControlType</type>
+ constants
+ @param pAntiImpl
+ Reference to the instance as whose "impl-class" we act i.e. the CommonBehaviourControl<> template,
+ which is why we hold it without acquiring it/
+ */
+ CommonBehaviourControlHelper(
+ sal_Int16 nControlType,
+ css::inspection::XPropertyControl& rAntiImpl);
+
+ virtual ~CommonBehaviourControlHelper();
+
+ virtual void setModified() { m_bModified = true; }
+
+ virtual void editChanged();
+
+ // XPropertyControl
+ /// @throws css::uno::RuntimeException
+ ::sal_Int16 getControlType() const { return m_nControlType; }
+ /// @throws css::uno::RuntimeException
+ const css::uno::Reference< css::inspection::XPropertyControlContext >& getControlContext() const { return m_xContext; }
+ /// @throws css::uno::RuntimeException
+ void setControlContext( const css::uno::Reference< css::inspection::XPropertyControlContext >& controlcontext );
+ /// @throws css::uno::RuntimeException
+ bool isModified( ) const { return m_bModified; }
+ /// @throws css::uno::RuntimeException
+ void notifyModifiedValue( );
+
+ virtual weld::Widget* getWidget() = 0;
+
+ /// may be used by derived classes, they forward the event to the PropCtrListener
+ DECL_LINK( ModifiedHdl, weld::ComboBox&, void );
+ DECL_LINK( ColorModifiedHdl, ColorListBox&, void );
+ DECL_LINK( EditModifiedHdl, weld::Entry&, void );
+ DECL_LINK( MetricModifiedHdl, weld::MetricSpinButton&, void );
+ DECL_LINK( FormattedModifiedHdl, weld::FormattedSpinButton&, void );
+ DECL_LINK( TimeModifiedHdl, weld::FormattedSpinButton&, void );
+ DECL_LINK( DateModifiedHdl, SvtCalendarBox&, void );
+ DECL_LINK( GetFocusHdl, weld::Widget&, void );
+ DECL_LINK( LoseFocusHdl, weld::Widget&, void );
+ };
+
+
+ //= CommonBehaviourControl
+
+ /** implements a base class for <type scope="css::inspection">XPropertyControl</type>
+ implementations
+
+ @param TControlInterface
+ an interface class which is derived from (or identical to) <type scope="css::inspection">XPropertyControl</type>
+ @param TControlWindow
+ a class which is derived from weld::Widget
+ */
+ template < class TControlInterface, class TControlWindow >
+ class CommonBehaviourControl :public ::cppu::BaseMutex
+ ,public ::cppu::WeakComponentImplHelper< TControlInterface >
+ ,public CommonBehaviourControlHelper
+ {
+ protected:
+ typedef ::cppu::WeakComponentImplHelper< TControlInterface > ComponentBaseClass;
+
+ inline CommonBehaviourControl(sal_Int16 nControlType,
+ std::unique_ptr<weld::Builder> xBuilder,
+ std::unique_ptr<TControlWindow> xWidget,
+ bool bReadOnly);
+
+ virtual ~CommonBehaviourControl() override
+ {
+ clear_widgetry();
+ }
+
+ // XPropertyControl - delegated to ->m_aImplControl
+ virtual ::sal_Int16 SAL_CALL getControlType() override
+ { return CommonBehaviourControlHelper::getControlType(); }
+ virtual css::uno::Reference< css::inspection::XPropertyControlContext > SAL_CALL getControlContext() override
+ { return CommonBehaviourControlHelper::getControlContext(); }
+ virtual void SAL_CALL setControlContext( const css::uno::Reference< css::inspection::XPropertyControlContext >& controlcontext ) override
+ { CommonBehaviourControlHelper::setControlContext( controlcontext ); }
+ virtual css::uno::Reference< css::awt::XWindow > SAL_CALL getControlWindow() override
+ { return new weld::TransportAsXWindow(getWidget()); }
+ virtual sal_Bool SAL_CALL isModified( ) override
+ { return CommonBehaviourControlHelper::isModified(); }
+ virtual void SAL_CALL notifyModifiedValue( ) override
+ { CommonBehaviourControlHelper::notifyModifiedValue(); }
+
+ void clear_widgetry()
+ {
+ if (!m_xControlWindow)
+ return;
+ weld::Widget* pWidget = getWidget();
+ std::unique_ptr<weld::Container> xParent(pWidget->weld_parent());
+ xParent->move(pWidget, nullptr);
+ m_xControlWindow.reset();
+ m_xBuilder.reset();
+ }
+
+ // XComponent
+ virtual void SAL_CALL disposing() override
+ {
+ clear_widgetry();
+ }
+
+ TControlWindow* getTypedControlWindow()
+ { return m_xControlWindow.get(); }
+ const TControlWindow* getTypedControlWindow() const
+ { return m_xControlWindow.get(); }
+
+ virtual void SetModifyHandler()
+ {
+ m_xControlWindow->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) );
+ m_xControlWindow->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) );
+ }
+
+ /** checks whether the instance is already disposed
+ @throws DisposedException
+ if the instance is already disposed
+ */
+ inline void impl_checkDisposed_throw();
+ protected:
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ private:
+ std::unique_ptr<TControlWindow> m_xControlWindow;
+ };
+
+ //= CommonBehaviourControl - implementation
+ template< class TControlInterface, class TControlWindow >
+ inline CommonBehaviourControl< TControlInterface, TControlWindow >::CommonBehaviourControl(sal_Int16 nControlType,
+ std::unique_ptr<weld::Builder> xBuilder,
+ std::unique_ptr<TControlWindow> xWidget,
+ bool bReadOnly)
+ : ComponentBaseClass( m_aMutex )
+ , CommonBehaviourControlHelper( nControlType, *this )
+ , m_xBuilder(std::move(xBuilder))
+ , m_xControlWindow(std::move(xWidget))
+ {
+ if (bReadOnly)
+ {
+ // disable widget by default, entries will override to enable the widget but set it non-editable
+ m_xControlWindow->set_sensitive(false);
+ }
+ }
+
+ template< class TControlInterface, class TControlWindow >
+ inline void CommonBehaviourControl< TControlInterface, TControlWindow >::impl_checkDisposed_throw()
+ {
+ if ( ComponentBaseClass::rBHelper.bDisposed )
+ throw css::lang::DisposedException( OUString(), *this );
+ }
+
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/composeduiupdate.cxx b/extensions/source/propctrlr/composeduiupdate.cxx
new file mode 100644
index 000000000..0e32ef19a
--- /dev/null
+++ b/extensions/source/propctrlr/composeduiupdate.cxx
@@ -0,0 +1,786 @@
+/* -*- 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 "composeduiupdate.hxx"
+#include "pcrcommon.hxx"
+
+#include <com/sun/star/inspection/XObjectInspectorUI.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/inspection/PropertyLineElement.hpp>
+#include <osl/diagnose.h>
+#include <osl/mutex.hxx>
+#include <rtl/ref.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <algorithm>
+#include <map>
+#include <set>
+
+
+namespace pcr
+{
+
+
+ using ::com::sun::star::lang::DisposedException;
+ using ::com::sun::star::lang::NullPointerException;
+ using ::com::sun::star::inspection::XPropertyHandler;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::inspection::XObjectInspectorUI;
+ using ::com::sun::star::inspection::XPropertyControl;
+ using ::com::sun::star::inspection::XPropertyControlObserver;
+
+ namespace PropertyLineElement = ::com::sun::star::inspection::PropertyLineElement;
+
+ namespace
+ {
+ struct HandlerLess
+ {
+ bool operator()( const Reference< XPropertyHandler >& lhs, const Reference< XPropertyHandler >& rhs) const
+ {
+ return lhs.get() < rhs.get();
+ }
+ };
+
+
+ typedef std::set< OUString > StringBag;
+ typedef std::map< sal_Int16, StringBag > MapIntToStringBag;
+ }
+
+
+ // callbacks for CachedInspectorUI
+
+ typedef void (ComposedPropertyUIUpdate::*FNotifySingleUIChange)();
+
+ typedef ::cppu::WeakImplHelper < css::inspection::XObjectInspectorUI
+ > CachedInspectorUI_Base;
+
+ namespace {
+
+ struct CachedInspectorUI : public CachedInspectorUI_Base
+ {
+ private:
+ ::osl::Mutex m_aMutex;
+ bool m_bDisposed;
+ ComposedPropertyUIUpdate&
+ m_rMaster;
+ FNotifySingleUIChange m_pUIChangeNotification;
+
+ // enablePropertyUI cache
+ StringBag aEnabledProperties;
+ StringBag aDisabledProperties;
+
+ // show/hidePropertyUI cache
+ StringBag aShownProperties;
+ StringBag aHiddenProperties;
+
+ // rebuildPropertyUI cache
+ StringBag aRebuiltProperties;
+
+ // showCategory cache
+ StringBag aShownCategories;
+ StringBag aHiddenCategories;
+
+ // enablePropertyUIElements cache
+ MapIntToStringBag aEnabledElements;
+ MapIntToStringBag aDisabledElements;
+
+ public:
+ typedef StringBag& (CachedInspectorUI::*FGetStringBag)();
+
+ // enablePropertyUI cache
+ StringBag& getEnabledProperties() { return aEnabledProperties; }
+ StringBag& getDisabledProperties() { return aDisabledProperties; }
+
+ // show/hidePropertyUI cache
+ StringBag& getShownProperties() { return aShownProperties; }
+ StringBag& getHiddenProperties() { return aHiddenProperties; }
+
+ // rebuildPropertyUI cache
+ StringBag& getRebuiltProperties() { return aRebuiltProperties; }
+
+ // showCategory cache
+ StringBag& getShownCategories() { return aShownCategories; }
+ StringBag& getHiddenCategories() { return aHiddenCategories; }
+
+ // enablePropertyUIElements
+ StringBag& getEnabledInputControls() { return aEnabledElements[ PropertyLineElement::InputControl ]; }
+ StringBag& getDisabledInputControls() { return aDisabledElements[ PropertyLineElement::InputControl ]; }
+ StringBag& getEnabledPrimaryButtons() { return aEnabledElements[ PropertyLineElement::PrimaryButton ]; }
+ StringBag& getDisabledPrimaryButtons() { return aDisabledElements[ PropertyLineElement::PrimaryButton ]; }
+ StringBag& getEnabledSecondaryButtons() { return aEnabledElements[ PropertyLineElement::SecondaryButton ]; }
+ StringBag& getDisabledSecondaryButtons() { return aDisabledElements[ PropertyLineElement::SecondaryButton ]; }
+
+ public:
+ CachedInspectorUI( ComposedPropertyUIUpdate& _rMaster, FNotifySingleUIChange _pUIChangeNotification );
+ CachedInspectorUI(const CachedInspectorUI&) = delete;
+ CachedInspectorUI& operator=(const CachedInspectorUI&) = delete;
+
+ /// disposes the instance
+ void dispose();
+
+ // XObjectInspectorUI overridables
+ virtual void SAL_CALL enablePropertyUI( const OUString& _rPropertyName, sal_Bool _bEnable ) override;
+ virtual void SAL_CALL enablePropertyUIElements( const OUString& _rPropertyName, ::sal_Int16 _nElements, sal_Bool _bEnable ) override;
+ virtual void SAL_CALL rebuildPropertyUI( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL showPropertyUI( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL hidePropertyUI( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL showCategory( const OUString& _rCategory, sal_Bool _bShow ) override;
+ virtual Reference< XPropertyControl > SAL_CALL getPropertyControl( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL registerControlObserver( const Reference< XPropertyControlObserver >& Observer ) override;
+ virtual void SAL_CALL revokeControlObserver( const Reference< XPropertyControlObserver >& Observer ) override;
+ virtual void SAL_CALL setHelpSectionText( const OUString& HelpText ) override;
+
+ protected:
+ virtual ~CachedInspectorUI() override;
+
+ /// throws an exception if the component is already disposed
+ void checkDisposed() const;
+
+ private:
+ void impl_markElementEnabledOrDisabled( const OUString& _rPropertyName, sal_Int16 _nElementIdOrZero, bool _bEnable );
+
+ /** calls <member>m_pUIChangeNotification</member> at <member>m_rMaster</member>
+ */
+ void impl_notifySingleUIChange() const;
+
+ private:
+ class MethodGuard;
+ friend class MethodGuard;
+ class MethodGuard : public ::osl::MutexGuard
+ {
+ public:
+ explicit MethodGuard( CachedInspectorUI& rInstance )
+ : ::osl::MutexGuard( rInstance.m_aMutex )
+ {
+ rInstance.checkDisposed();
+ }
+ };
+ };
+
+ }
+
+ CachedInspectorUI::CachedInspectorUI( ComposedPropertyUIUpdate& _rMaster, FNotifySingleUIChange _pUIChangeNotification )
+ :m_bDisposed( false )
+ ,m_rMaster( _rMaster )
+ ,m_pUIChangeNotification( _pUIChangeNotification )
+ {
+ }
+
+
+ CachedInspectorUI::~CachedInspectorUI()
+ {
+ }
+
+
+ void CachedInspectorUI::dispose()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_bDisposed = true;
+
+ clearContainer( aEnabledProperties );
+ clearContainer( aDisabledProperties );
+ clearContainer( aRebuiltProperties );
+ clearContainer( aShownProperties );
+ clearContainer( aHiddenProperties );
+ clearContainer( aShownCategories );
+ clearContainer( aHiddenCategories );
+ clearContainer( aEnabledElements );
+ clearContainer( aDisabledElements );
+ }
+
+
+ void CachedInspectorUI::checkDisposed() const
+ {
+ if (m_bDisposed)
+ throw DisposedException();
+ }
+
+
+ namespace
+ {
+ void lcl_markStringKeyPositiveOrNegative( const OUString& _rKeyName, StringBag& _rPositives, StringBag& _rNegatives, bool _bMarkPositive )
+ {
+ if ( _bMarkPositive )
+ {
+ _rPositives.insert( _rKeyName );
+ // if the same key has been remember as in the "negative" list before, clear this information, since it's overruled
+ _rNegatives.erase( _rKeyName );
+ }
+ else
+ _rNegatives.insert( _rKeyName );
+ }
+ }
+
+
+ void CachedInspectorUI::enablePropertyUI( const OUString& _rPropertyName, sal_Bool _bEnable )
+ {
+ MethodGuard aGuard( *this );
+ if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) )
+ return;
+
+ lcl_markStringKeyPositiveOrNegative( _rPropertyName, aEnabledProperties, aDisabledProperties, _bEnable );
+ impl_notifySingleUIChange();
+ }
+
+
+ void CachedInspectorUI::impl_markElementEnabledOrDisabled( const OUString& _rPropertyName, sal_Int16 _nElementIdOrZero, bool _bEnable )
+ {
+ if ( _nElementIdOrZero == 0 )
+ return;
+
+ lcl_markStringKeyPositiveOrNegative(
+ _rPropertyName,
+ aEnabledElements[ _nElementIdOrZero ],
+ aDisabledElements[ _nElementIdOrZero ],
+ _bEnable
+ );
+ }
+
+
+ void CachedInspectorUI::impl_notifySingleUIChange() const
+ {
+ (m_rMaster.*m_pUIChangeNotification)();
+ }
+
+
+ void CachedInspectorUI::enablePropertyUIElements( const OUString& _rPropertyName, sal_Int16 _nElements, sal_Bool _bEnable )
+ {
+ MethodGuard aGuard( *this );
+ if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) )
+ return;
+
+ impl_markElementEnabledOrDisabled( _rPropertyName, _nElements & PropertyLineElement::InputControl, _bEnable );
+ impl_markElementEnabledOrDisabled( _rPropertyName, _nElements & PropertyLineElement::PrimaryButton, _bEnable );
+ impl_markElementEnabledOrDisabled( _rPropertyName, _nElements & PropertyLineElement::SecondaryButton, _bEnable );
+
+ impl_notifySingleUIChange();
+ }
+
+
+ void CachedInspectorUI::rebuildPropertyUI( const OUString& _rPropertyName )
+ {
+ MethodGuard aGuard( *this );
+ if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) )
+ return;
+
+ aRebuiltProperties.insert( _rPropertyName );
+
+ impl_notifySingleUIChange();
+ }
+
+
+ void CachedInspectorUI::showPropertyUI( const OUString& _rPropertyName )
+ {
+ MethodGuard aGuard( *this );
+ if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) )
+ return;
+
+ aShownProperties.insert( _rPropertyName );
+ // if the same category has been hidden before, clear this information, since it's overruled
+ aHiddenProperties.erase( _rPropertyName );
+
+ impl_notifySingleUIChange();
+ }
+
+
+ void CachedInspectorUI::hidePropertyUI( const OUString& _rPropertyName )
+ {
+ MethodGuard aGuard( *this );
+ if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) )
+ return;
+
+ aHiddenProperties.insert( _rPropertyName );
+ impl_notifySingleUIChange();
+ }
+
+
+ void CachedInspectorUI::showCategory( const OUString& _rCategory, sal_Bool _bShow )
+ {
+ MethodGuard aGuard( *this );
+
+ lcl_markStringKeyPositiveOrNegative( _rCategory, aShownCategories, aHiddenCategories, _bShow );
+ impl_notifySingleUIChange();
+ }
+
+
+ Reference< XPropertyControl > SAL_CALL CachedInspectorUI::getPropertyControl( const OUString& _rPropertyName )
+ {
+ MethodGuard aGuard( *this );
+ if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) )
+ return Reference< XPropertyControl >();
+
+ return m_rMaster.getDelegatorUI()->getPropertyControl( _rPropertyName );
+ }
+
+
+ void SAL_CALL CachedInspectorUI::registerControlObserver( const Reference< XPropertyControlObserver >& Observer )
+ {
+ OSL_FAIL( "CachedInspectorUI::registerControlObserver: not expected to be called!" );
+ // CachedInspectorUI is used as context for the controls, and we don't expect them to
+ // register listeners themself
+ m_rMaster.getDelegatorUI()->registerControlObserver( Observer );
+ }
+
+
+ void SAL_CALL CachedInspectorUI::revokeControlObserver( const Reference< XPropertyControlObserver >& Observer )
+ {
+ OSL_FAIL( "CachedInspectorUI::revokeControlObserver: not expected to be called!" );
+ // CachedInspectorUI is used as context for the controls, and we don't expect them to
+ // register listeners themself
+ m_rMaster.getDelegatorUI()->revokeControlObserver( Observer );
+ }
+
+
+ void SAL_CALL CachedInspectorUI::setHelpSectionText( const OUString& HelpText )
+ {
+ m_rMaster.getDelegatorUI()->setHelpSectionText( HelpText );
+ }
+
+
+ // HandlerMap
+
+ typedef std::map < Reference< XPropertyHandler >
+ , ::rtl::Reference< CachedInspectorUI >
+ , HandlerLess
+ > ImplMapHandlerToUI;
+ struct MapHandlerToUI
+ {
+ ImplMapHandlerToUI aHandlers;
+ };
+
+ ComposedPropertyUIUpdate::ComposedPropertyUIUpdate( const Reference< XObjectInspectorUI >& _rxDelegatorUI,
+ IPropertyExistenceCheck* _pPropertyCheck )
+ :m_pCollectedUIs( new MapHandlerToUI )
+ ,m_xDelegatorUI( _rxDelegatorUI )
+ ,m_nSuspendCounter( 0 )
+ ,m_pPropertyCheck( _pPropertyCheck )
+ {
+ if ( !m_xDelegatorUI.is() )
+ throw NullPointerException();
+ }
+
+
+ ComposedPropertyUIUpdate::~ComposedPropertyUIUpdate( )
+ {
+ }
+
+
+ Reference< XObjectInspectorUI > ComposedPropertyUIUpdate::getUIForPropertyHandler( const Reference< XPropertyHandler >& _rxHandler )
+ {
+ impl_checkDisposed();
+
+ ::rtl::Reference< CachedInspectorUI >& rUI = m_pCollectedUIs->aHandlers[ _rxHandler ];
+ if ( !rUI.is() )
+ rUI = new CachedInspectorUI( *this, &ComposedPropertyUIUpdate::callback_inspectorUIChanged_throw );
+ return rUI;
+ }
+
+
+ namespace
+ {
+
+ // an STL-compatible structure which collects strings from a CachedInspectorUI instances
+ struct StringBagCollector
+ {
+ private:
+ StringBag& m_rBag;
+ CachedInspectorUI::FGetStringBag m_pGetter;
+
+ public:
+ StringBagCollector( StringBag& _rBag, CachedInspectorUI::FGetStringBag _pGetter ) :m_rBag( _rBag ), m_pGetter( _pGetter ) { }
+
+ void operator()( const ImplMapHandlerToUI::value_type& _rUI )
+ {
+ StringBag& rBag( ((_rUI.second.get())->*m_pGetter)() );
+ m_rBag.insert( rBag.begin(), rBag.end() );
+ }
+
+ static void collectAll( StringBag& _rAll, const ImplMapHandlerToUI& _rMap, CachedInspectorUI::FGetStringBag _pGetter )
+ {
+ std::for_each( _rMap.begin(), _rMap.end(), StringBagCollector( _rAll, _pGetter ) );
+ }
+ };
+
+
+ // an STL-compatible structure which cleans a certain string bag in a CachedInspectorUI instances
+ struct StringBagClearer
+ {
+ private:
+ CachedInspectorUI::FGetStringBag m_pGetter;
+
+ public:
+ explicit StringBagClearer( CachedInspectorUI::FGetStringBag _pGetter ) :m_pGetter( _pGetter ) { }
+
+ void operator()( const ImplMapHandlerToUI::value_type& _rUI )
+ {
+ clearContainer( ((_rUI.second.get())->*m_pGetter)() );
+ }
+
+ static void clearAll( const ImplMapHandlerToUI& _rMap, CachedInspectorUI::FGetStringBag _pGetter )
+ {
+ std::for_each( _rMap.begin(), _rMap.end(), StringBagClearer( _pGetter ) );
+ }
+ };
+
+ // a typedef for a ->XObjectInspectorUI member function taking a string
+ typedef void ( SAL_CALL XObjectInspectorUI::*FPropertyUISetter )( const OUString& );
+
+
+ // an STL-compatible struct which calls a certain member method (taking a string) at a
+ // given ->XObjectInspectorUI instance
+ struct PropertyUIOperator
+ {
+ private:
+ Reference< XObjectInspectorUI > m_xUpdater;
+ FPropertyUISetter m_pSetter;
+
+ public:
+ PropertyUIOperator( const Reference< XObjectInspectorUI >& _rxInspectorUI, FPropertyUISetter _pSetter )
+ :m_xUpdater( _rxInspectorUI )
+ ,m_pSetter( _pSetter )
+ {
+ }
+
+ void operator()( const OUString& _rPropertyName )
+ {
+ ((m_xUpdater.get())->*m_pSetter)( _rPropertyName );
+ }
+
+ static void forEach( const StringBag& _rProperties, const Reference< XObjectInspectorUI >& _rxDelegatorUI, FPropertyUISetter _pSetter )
+ {
+ std::for_each( _rProperties.begin(), _rProperties.end(), PropertyUIOperator( _rxDelegatorUI, _pSetter ) );
+ }
+ };
+
+
+ // an interface which encapsulates access to a single aspect of the ->XObjectInspectorUI,
+ // where this aspect is given by a string key, and has a boolean value.
+ class IStringKeyBooleanUIUpdate
+ {
+ public:
+ virtual void updateUIForKey( const OUString& _rKey, bool _bFlag ) const = 0;
+
+ virtual ~IStringKeyBooleanUIUpdate() { }
+ };
+
+
+ // FPropertyUIFlagSetter
+
+ /** an implementation of the ->IStringKeyBooleanUIUpdate interface which,
+ for a fixed ->XObjectInspectorUI instance and a fixed UI element (->PropertyLineElement),
+ updates this element for a given property with a given boolean flag
+ (->XObjectInspectorUI::enablePropertyUIElements)
+ */
+ class EnablePropertyUIElement : public IStringKeyBooleanUIUpdate
+ {
+ private:
+ Reference< XObjectInspectorUI > m_xUIUpdate;
+ sal_Int16 m_nElement;
+
+ public:
+ EnablePropertyUIElement( const Reference< XObjectInspectorUI >& _rxUIUpdate, sal_Int16 _nElement )
+ :m_xUIUpdate( _rxUIUpdate )
+ ,m_nElement( _nElement )
+ {
+ }
+ // IStringKeyBooleanUIUpdate
+ virtual void updateUIForKey( const OUString& _rKey, bool _bFlag ) const override;
+ };
+
+
+ void EnablePropertyUIElement::updateUIForKey( const OUString& _rKey, bool _bFlag ) const
+ {
+ m_xUIUpdate->enablePropertyUIElements( _rKey, m_nElement, _bFlag );
+ }
+
+
+ // a ->XObjectInspectorUI method taking a string and a boolean
+ typedef void ( SAL_CALL XObjectInspectorUI::*FPropertyUIFlagSetter )( const OUString&, sal_Bool );
+
+
+ // an implementation of the ->IStringKeyBooleanUIUpdate interface which calls
+ // an arbitrary ->XObjectInspectorUI method taking a string and a boolean flag
+ class DefaultStringKeyBooleanUIUpdate : public IStringKeyBooleanUIUpdate
+ {
+ private:
+ Reference< XObjectInspectorUI > m_xUIUpdate;
+ FPropertyUIFlagSetter m_pSetter;
+
+ public:
+ DefaultStringKeyBooleanUIUpdate( const Reference< XObjectInspectorUI >& _rxUIUpdate, FPropertyUIFlagSetter _pSetter );
+ // IStringKeyBooleanUIUpdate
+ virtual void updateUIForKey( const OUString& _rKey, bool _bFlag ) const override;
+ };
+
+
+ DefaultStringKeyBooleanUIUpdate::DefaultStringKeyBooleanUIUpdate( const Reference< XObjectInspectorUI >& _rxUIUpdate, FPropertyUIFlagSetter _pSetter )
+ :m_xUIUpdate( _rxUIUpdate )
+ ,m_pSetter( _pSetter )
+ {
+ }
+
+
+ void DefaultStringKeyBooleanUIUpdate::updateUIForKey( const OUString& _rKey, bool _bFlag ) const
+ {
+ ((m_xUIUpdate.get())->*m_pSetter)( _rKey, _bFlag );
+ }
+
+
+ // an STL-compatible structure which applies a ->IStringKeyBooleanUIUpdate::updateUIForKey
+ // operation with a fixed boolean value, for a given string value
+ struct BooleanUIAspectUpdate
+ {
+ private:
+ const IStringKeyBooleanUIUpdate& m_rUpdater;
+ bool m_bFlag;
+
+ public:
+ BooleanUIAspectUpdate( const IStringKeyBooleanUIUpdate& _rUpdater, bool _bFlag )
+ :m_rUpdater( _rUpdater )
+ ,m_bFlag( _bFlag )
+ {
+ }
+
+ void operator()( const OUString& _rPropertyName )
+ {
+ m_rUpdater.updateUIForKey( _rPropertyName, m_bFlag );
+ }
+
+ static void forEach( const StringBag& _rProperties, const IStringKeyBooleanUIUpdate& _rUpdater, bool _bFlag )
+ {
+ std::for_each( _rProperties.begin(), _rProperties.end(), BooleanUIAspectUpdate( _rUpdater, _bFlag ) );
+ }
+ };
+
+
+ // BooleanUIAspectUpdate
+
+ // an STL-compatible structure subtracting a given string from a fixed ->StringBag
+ struct StringBagComplement
+ {
+ private:
+ StringBag& m_rMinuend;
+
+ public:
+ explicit StringBagComplement( StringBag& _rMinuend ) :m_rMinuend( _rMinuend ) { }
+
+ void operator()( const OUString& _rPropertyToSubtract )
+ {
+ m_rMinuend.erase( _rPropertyToSubtract );
+ }
+
+ static void subtract( StringBag& _rMinuend, const StringBag& _rSubtrahend )
+ {
+ std::for_each( _rSubtrahend.begin(), _rSubtrahend.end(), StringBagComplement( _rMinuend ) );
+ }
+ };
+
+
+ // BooleanUIAspectUpdate
+
+ void lcl_fireUIStateFlag(
+ const IStringKeyBooleanUIUpdate& _rUIUpdate,
+ const ImplMapHandlerToUI& _rHandlerUIs,
+ CachedInspectorUI::FGetStringBag _pGetPositives,
+ CachedInspectorUI::FGetStringBag _pGetNegatives
+ )
+ {
+ // all strings which are in the "positive" list of one handler
+ StringBag aAllPositives;
+ StringBagCollector::collectAll( aAllPositives, _rHandlerUIs, _pGetPositives );
+
+ // all strings which are in the "negative" list of one handler
+ StringBag aAllNegatives;
+ StringBagCollector::collectAll( aAllNegatives, _rHandlerUIs, _pGetNegatives );
+
+ // propagate the "negative" flags to the delegator UI
+ BooleanUIAspectUpdate::forEach( aAllNegatives, _rUIUpdate, false );
+
+ // propagate the "positive" flags to the delegator UI, for all elements where _no_
+ // "negative" flag exists
+ StringBagComplement::subtract( aAllPositives, aAllNegatives );
+ BooleanUIAspectUpdate::forEach( aAllPositives, _rUIUpdate, true );
+
+ // the "positive" request can be cleared no, only negative requests
+ // (such as "disable a property" or "hide a category") need to be preserved for the next round
+ StringBagClearer::clearAll( _rHandlerUIs, _pGetPositives );
+ }
+ }
+
+
+ void ComposedPropertyUIUpdate::impl_fireEnablePropertyUI_throw()
+ {
+ lcl_fireUIStateFlag(
+ DefaultStringKeyBooleanUIUpdate( m_xDelegatorUI, &XObjectInspectorUI::enablePropertyUI ),
+ m_pCollectedUIs->aHandlers,
+ &CachedInspectorUI::getEnabledProperties,
+ &CachedInspectorUI::getDisabledProperties
+ );
+ }
+
+
+ void ComposedPropertyUIUpdate::impl_fireRebuildPropertyUI_throw()
+ {
+ // collect all properties for which a rebuild request has been made
+ StringBag aAllRebuilt;
+ StringBagCollector::collectAll( aAllRebuilt, m_pCollectedUIs->aHandlers, &CachedInspectorUI::getRebuiltProperties );
+
+ // rebuild all those properties
+ PropertyUIOperator::forEach( aAllRebuilt, m_xDelegatorUI, &XObjectInspectorUI::rebuildPropertyUI );
+
+ // clear the "properties to rebuild" at all handlers, since the request has been fulfilled now.
+ StringBagClearer::clearAll( m_pCollectedUIs->aHandlers, &CachedInspectorUI::getRebuiltProperties );
+ }
+
+
+ void ComposedPropertyUIUpdate::impl_fireShowHidePropertyUI_throw()
+ {
+ // all properties which have been shown by at least one handler
+ StringBag aAllShown;
+ StringBagCollector::collectAll( aAllShown, m_pCollectedUIs->aHandlers, &CachedInspectorUI::getShownProperties );
+ // all properties which have been hidden by at least one handler
+ StringBag aAllHidden;
+ StringBagCollector::collectAll( aAllHidden, m_pCollectedUIs->aHandlers, &CachedInspectorUI::getHiddenProperties );
+
+ // hide properties as necessary
+ PropertyUIOperator::forEach( aAllHidden, m_xDelegatorUI, &XObjectInspectorUI::hidePropertyUI );
+
+ // for those properties which are hidden, ignore all "show" requests which other handlers might have had
+ StringBagComplement::subtract( aAllShown, aAllHidden );
+
+ // show properties
+ PropertyUIOperator::forEach( aAllShown, m_xDelegatorUI, &XObjectInspectorUI::showPropertyUI );
+ }
+
+
+ void ComposedPropertyUIUpdate::impl_fireShowCategory_throw()
+ {
+ lcl_fireUIStateFlag(
+ DefaultStringKeyBooleanUIUpdate( m_xDelegatorUI, &XObjectInspectorUI::showCategory ),
+ m_pCollectedUIs->aHandlers,
+ &CachedInspectorUI::getShownCategories,
+ &CachedInspectorUI::getHiddenCategories
+ );
+ }
+
+
+ void ComposedPropertyUIUpdate::impl_fireEnablePropertyUIElements_throw()
+ {
+ lcl_fireUIStateFlag(
+ EnablePropertyUIElement( m_xDelegatorUI, PropertyLineElement::InputControl ),
+ m_pCollectedUIs->aHandlers,
+ &CachedInspectorUI::getEnabledInputControls,
+ &CachedInspectorUI::getDisabledInputControls
+ );
+
+ lcl_fireUIStateFlag(
+ EnablePropertyUIElement( m_xDelegatorUI, PropertyLineElement::PrimaryButton ),
+ m_pCollectedUIs->aHandlers,
+ &CachedInspectorUI::getEnabledPrimaryButtons,
+ &CachedInspectorUI::getDisabledPrimaryButtons
+ );
+
+ lcl_fireUIStateFlag(
+ EnablePropertyUIElement( m_xDelegatorUI, PropertyLineElement::SecondaryButton ),
+ m_pCollectedUIs->aHandlers,
+ &CachedInspectorUI::getEnabledSecondaryButtons,
+ &CachedInspectorUI::getDisabledSecondaryButtons
+ );
+ }
+
+
+ void ComposedPropertyUIUpdate::impl_fireAll_throw()
+ {
+ OSL_PRECOND( !impl_isDisposed(), "ComposedPropertyUIUpdate::impl_fireAll_throw: already disposed, this will crash!" );
+
+ impl_fireEnablePropertyUI_throw();
+ impl_fireShowHidePropertyUI_throw();
+ impl_fireRebuildPropertyUI_throw();
+ impl_fireShowCategory_throw();
+ impl_fireEnablePropertyUIElements_throw();
+ }
+
+
+ void ComposedPropertyUIUpdate::suspendAutoFire()
+ {
+ impl_checkDisposed();
+ osl_atomic_increment( &m_nSuspendCounter );
+ }
+
+
+ void ComposedPropertyUIUpdate::resumeAutoFire()
+ {
+ impl_checkDisposed();
+ if ( 0 == osl_atomic_decrement( &m_nSuspendCounter ) )
+ impl_fireAll_throw();
+ }
+
+
+ void ComposedPropertyUIUpdate::impl_checkDisposed() const
+ {
+ if ( impl_isDisposed() )
+ throw DisposedException();
+ }
+
+
+ void ComposedPropertyUIUpdate::callback_inspectorUIChanged_throw()
+ {
+ if ( 0 == m_nSuspendCounter )
+ impl_fireAll_throw();
+ }
+
+
+ Reference< XObjectInspectorUI > const & ComposedPropertyUIUpdate::getDelegatorUI() const
+ {
+ impl_checkDisposed();
+ return m_xDelegatorUI;
+ }
+
+
+ void ComposedPropertyUIUpdate::dispose()
+ {
+ if ( impl_isDisposed() )
+ return;
+
+ OSL_ENSURE( m_nSuspendCounter == 0, "ComposedPropertyUIUpdate::dispose: still suspended, the changes will be lost!" );
+
+ for (auto const& singleUI : m_pCollectedUIs->aHandlers)
+ {
+ singleUI.second->dispose();
+ }
+ m_pCollectedUIs.reset();
+ m_xDelegatorUI.set( nullptr );
+ }
+
+
+ bool ComposedPropertyUIUpdate::shouldContinuePropertyHandling( const OUString& _rName ) const
+ {
+ if ( !m_pPropertyCheck )
+ return true;
+ if ( m_pPropertyCheck->hasPropertyByName( _rName ) )
+ return true;
+ return false;
+ }
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/composeduiupdate.hxx b/extensions/source/propctrlr/composeduiupdate.hxx
new file mode 100644
index 000000000..5e356af1f
--- /dev/null
+++ b/extensions/source/propctrlr/composeduiupdate.hxx
@@ -0,0 +1,208 @@
+/* -*- 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/inspection/XObjectInspectorUI.hpp>
+#include <com/sun/star/inspection/XPropertyHandler.hpp>
+
+#include <memory>
+
+
+namespace pcr
+{
+
+ struct MapHandlerToUI;
+
+ /** callback for a ComposedPropertyUIUpdate checking a given property for existence
+ */
+ class SAL_NO_VTABLE IPropertyExistenceCheck
+ {
+ public:
+ /// @throws css::uno::RuntimeException
+ virtual bool hasPropertyByName( const OUString& _rName ) = 0;
+
+ protected:
+ ~IPropertyExistenceCheck() {}
+ };
+
+ /** helper class composing requests to a ->XObjectInspectorUI interface, coming
+ from multiple sources
+
+ Usually, a handler tells the browser UI to enable to disable, or show or hide, certain
+ elements. Now when multiple handlers do this, their instructions must be combined:
+ If one handler disables a certain element, but others enable it, it must in the
+ result still be disabled. Similar for showing/hiding elements.
+
+ ->ComposedPropertyUIUpdate implements this combination. It does so by providing a dedicated
+ ->XObjectInspectorUI instance for every participating handler, and remembering the UI
+ state on a per-handler basis. Upon request (->fire), the combined UI state is
+ forwarded to another ->XObjectInspectorUI instance, the so-called delegator UI.
+ */
+ class ComposedPropertyUIUpdate
+ {
+ private:
+ std::unique_ptr< MapHandlerToUI > m_pCollectedUIs;
+ css::uno::Reference< css::inspection::XObjectInspectorUI >
+ m_xDelegatorUI;
+ oslInterlockedCount m_nSuspendCounter;
+ IPropertyExistenceCheck* m_pPropertyCheck;
+
+ public:
+ /** constructs a ->ComposedPropertyUIUpdate instance
+ @param _rxDelegatorUI
+ a ->XObjectInspectorUI instance to which composed UI requests should be forwarded. Must
+ not be <NULL/>.
+ @param _pPropertyCheck
+ an instance checking properties for existence. If this is not <NULL/>, it will be invoked
+ whenever one of the ->XObjectInspectorUI methods is called, to check the passed property
+ name.<br/>
+ Beware of lifetime issues. The instance pointed to by <arg>_pPropertyCheck</arg> must
+ live at least as long as the ->ComposedPropertyUIUpdate instance you're going to create.
+ @throws css::lang::NullPointerException
+ if ->_rxDelegatorUI is <NULL/>
+ */
+ ComposedPropertyUIUpdate(
+ const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxDelegatorUI,
+ IPropertyExistenceCheck* _pPropertyCheck );
+ ~ComposedPropertyUIUpdate();
+
+ /** returns the delegator UI
+ @throw css::lang::DisposedException
+ */
+ css::uno::Reference< css::inspection::XObjectInspectorUI > const & getDelegatorUI() const;
+
+ /** returns a ->XObjectInspectorUI instance belonging to a given property handler
+
+ In every call to an ->XPropertyHandler method which requires a ->XObjectInspectorUI,
+ the same UI instance should be used. The instance here will cache all requests passed
+ to it, and ->ComposedPropertyUIUpdate::fire will use the combination of all
+ cached UI states of all handlers to update the delegator UI.
+ */
+ css::uno::Reference< css::inspection::XObjectInspectorUI >
+ getUIForPropertyHandler( const css::uno::Reference< css::inspection::XPropertyHandler >& _rxHandler );
+
+ /** Suspends automatic firing of UI changes
+
+ normally, as soon as any of the property handlers does a request for an
+ arbitrary UI change, the set of collected UI changes is evaluated, and the combined
+ UI state is fired to the delegator UI.
+
+ You can disable this automatic firing by calling ->suspendAutoFire. As longs as auto
+ firing is suspended, only explicit ->fire calls trigger the notification to the
+ delegator UI.
+
+ Note that calls to ->suspendAutoFire are cumulative, that is, if you make multiple calls
+ they must be accompanied by an equal number of calls to ->resumeAutoFire, to enable
+ auto-firing again.
+
+ @seealso resumeAutoFire
+ */
+ void suspendAutoFire();
+
+ /** Suspends automatic firing of UI changes
+
+ @seealso suspendAutoFire
+ */
+ void resumeAutoFire();
+
+ /** disposes the instance, so it becomes non-functional.
+
+ All cached handlers and cached ->XObjectInspectorUI instances will be released,
+ the latter will also be disposed, so that if anybody still holds a reference to them
+ and tries to operate them will get a DisposedException.
+ */
+ void dispose();
+
+ /** invokes m_pPropertyCheck to check whether a given property should be handled
+ */
+ bool shouldContinuePropertyHandling( const OUString& _rName ) const;
+
+ private:
+ /// determines whether the instance is already disposed
+ bool impl_isDisposed() const { return !m_pCollectedUIs; }
+
+ /// throws an exception if the component is already disposed
+ void impl_checkDisposed() const;
+
+ /** fires the collected UI changes to our delegator UI
+
+ All operations for any elements are forwarded:
+ <ul><li>If an element has been hidden at least once, it's also hidden at the delegator UI.</li>
+ <li>If an element has been shown at least once, and never been hidden, it's also
+ shown at the delegator UI.</li>
+ <li>If an element has never been shown or hidden, it's also not touched at the delegator UI.</li>
+ <li>The same holds if you replace "hidden" in the last three items with "disabled",
+ and "shown" with "enabled".</li>
+ <li>If an element should have been rebuilt (->XObjectInspectorUI::rebuiltPropertyUI)
+ at least once, it's rebuilt at the delegator UI, too.<br/>
+ After that, the request to rebuild the UI for this property is cleared, so subsequent
+ calls to ->fire will not trigger a new rebuilt request.
+ </ul>
+
+ @precond
+ instance is not disposed
+ */
+ void impl_fireAll_throw();
+
+ /// fires the combination of ->XObjectInspectorUI::enablePropertyUI calls
+ void impl_fireEnablePropertyUI_throw();
+
+ /// fires the combination of ->XObjectInspectorUI::enablePropertyUIElements calls
+ void impl_fireEnablePropertyUIElements_throw();
+
+ /// fires the combination of ->XObjectInspectorUI::rebuildPropertyUI calls
+ void impl_fireRebuildPropertyUI_throw();
+
+ /// fires the combination of ->XObjectInspectorUI::showPropertyUI and ->XObjectInspectorUI::hidePropertyUI calls
+ void impl_fireShowHidePropertyUI_throw();
+
+ /// fires the combination of ->XObjectInspectorUI::showCategory calls
+ void impl_fireShowCategory_throw();
+
+ /** callback for when a single property handler requested any change in the inspector UI
+ */
+ void callback_inspectorUIChanged_throw();
+
+ private:
+ ComposedPropertyUIUpdate( const ComposedPropertyUIUpdate& ) = delete;
+ ComposedPropertyUIUpdate& operator=( const ComposedPropertyUIUpdate& ) = delete;
+ };
+
+ class ComposedUIAutoFireGuard
+ {
+ private:
+ ComposedPropertyUIUpdate& m_rUIUpdate;
+ public:
+ explicit ComposedUIAutoFireGuard( ComposedPropertyUIUpdate& _rUIUpdate )
+ :m_rUIUpdate( _rUIUpdate )
+ {
+ m_rUIUpdate.suspendAutoFire();
+ }
+ ~ComposedUIAutoFireGuard() COVERITY_NOEXCEPT_FALSE
+ {
+ m_rUIUpdate.resumeAutoFire();
+ }
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/controlfontdialog.cxx b/extensions/source/propctrlr/controlfontdialog.cxx
new file mode 100644
index 000000000..08088e074
--- /dev/null
+++ b/extensions/source/propctrlr/controlfontdialog.cxx
@@ -0,0 +1,148 @@
+/* -*- 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/PropertyAttribute.hpp>
+#include "controlfontdialog.hxx"
+
+#include <comphelper/propertyvalue.hxx>
+#include <vcl/svapp.hxx>
+#include "fontdialog.hxx"
+#include "formstrings.hxx"
+#include "pcrcommon.hxx"
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+
+ OControlFontDialog::OControlFontDialog(const Reference< XComponentContext >& _rxContext )
+ :OGenericUnoDialog( _rxContext )
+ ,m_pItemPoolDefaults(nullptr)
+ {
+ registerProperty(PROPERTY_INTROSPECTEDOBJECT, OWN_PROPERTY_ID_INTROSPECTEDOBJECT,
+ PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT,
+ &m_xControlModel, cppu::UnoType<decltype(m_xControlModel)>::get());
+ }
+
+
+ OControlFontDialog::~OControlFontDialog()
+ {
+ if (m_xDialog)
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if (m_xDialog)
+ {
+ destroyDialog();
+ ControlCharacterDialog::destroyItemSet(m_pFontItems, m_pItemPool, m_pItemPoolDefaults);
+ }
+ }
+ }
+
+
+ Sequence<sal_Int8> SAL_CALL OControlFontDialog::getImplementationId( )
+ {
+ return css::uno::Sequence<sal_Int8>();
+ }
+
+
+ OUString SAL_CALL OControlFontDialog::getImplementationName()
+ {
+ return "org.openoffice.comp.form.ui.OControlFontDialog";
+ }
+
+
+ css::uno::Sequence<OUString> SAL_CALL OControlFontDialog::getSupportedServiceNames()
+ {
+ return { "com.sun.star.form.ControlFontDialog" };
+ }
+
+ void OControlFontDialog::initialize( const Sequence< Any >& aArguments )
+ {
+ Reference<XPropertySet> xGridModel;
+ if (aArguments.getLength() == 1 && (aArguments[0] >>= xGridModel))
+ {
+ Sequence aNewArguments{ Any(comphelper::makePropertyValue("IntrospectedObject",
+ xGridModel)) };
+ OControlFontDialog_DBase::initialize(aNewArguments);
+ }
+ else
+ OControlFontDialog_DBase::initialize(aArguments);
+ }
+
+
+ Reference<XPropertySetInfo> SAL_CALL OControlFontDialog::getPropertySetInfo()
+ {
+ Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+ }
+
+
+ ::cppu::IPropertyArrayHelper& OControlFontDialog::getInfoHelper()
+ {
+ return *getArrayHelper();
+ }
+
+
+ ::cppu::IPropertyArrayHelper* OControlFontDialog::createArrayHelper( ) const
+ {
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+ }
+
+ std::unique_ptr<weld::DialogController> OControlFontDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+ {
+ ControlCharacterDialog::createItemSet(m_pFontItems, m_pItemPool, m_pItemPoolDefaults);
+
+ OSL_ENSURE(m_xControlModel.is(), "OControlFontDialog::createDialog: no introspectee set!");
+ if (m_xControlModel.is())
+ ControlCharacterDialog::translatePropertiesToItems(m_xControlModel, m_pFontItems.get());
+ // TODO: we need a mechanism to prevent that somebody creates us, sets an introspectee, executes us,
+ // sets a new introspectee and re-executes us. In this case, the dialog returned here (upon the first
+ // execute) will be re-used upon the second execute, and thus it won't be initialized correctly.
+
+ return std::make_unique<ControlCharacterDialog>(Application::GetFrameWeld(rParent), *m_pFontItems);
+ }
+
+ void OControlFontDialog::executedDialog(sal_Int16 _nExecutionResult)
+ {
+ OSL_ENSURE(m_xDialog, "OControlFontDialog::executedDialog: no dialog anymore?!!");
+ if (m_xDialog && (RET_OK == _nExecutionResult) && m_xControlModel.is())
+ {
+ const SfxItemSet* pOutput = static_cast<ControlCharacterDialog*>(m_xDialog.get())->GetOutputItemSet();
+ if (pOutput)
+ ControlCharacterDialog::translateItemsToProperties( *pOutput, m_xControlModel );
+ }
+ }
+
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_OControlFontDialog_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::OControlFontDialog(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/controlfontdialog.hxx b/extensions/source/propctrlr/controlfontdialog.hxx
new file mode 100644
index 000000000..8dc520102
--- /dev/null
+++ b/extensions/source/propctrlr/controlfontdialog.hxx
@@ -0,0 +1,82 @@
+/* -*- 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 <comphelper/proparrhlp.hxx>
+#include <svtools/genericunodialog.hxx>
+
+class SfxItemSet;
+class SfxItemPool;
+class SfxPoolItem;
+
+namespace pcr
+{
+
+ class OControlFontDialog;
+ typedef ::svt::OGenericUnoDialog OControlFontDialog_DBase;
+ typedef ::comphelper::OPropertyArrayUsageHelper< OControlFontDialog > OControlFontDialog_PBase;
+
+ class OControlFontDialog
+ :public OControlFontDialog_DBase
+ ,public OControlFontDialog_PBase
+ {
+ protected:
+ // <properties>
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xControlModel;
+ // </properties>
+
+ std::unique_ptr<SfxItemSet> m_pFontItems; // item set for the dialog
+ rtl::Reference<SfxItemPool> m_pItemPool; // item pool for the item set for the dialog
+ std::vector<SfxPoolItem*>*
+ m_pItemPoolDefaults; // pool defaults
+
+ public:
+ explicit OControlFontDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+ virtual ~OControlFontDialog() override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ protected:
+ // OGenericUnoDialog overridables
+ virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+ virtual void executedDialog(sal_Int16 _nExecutionResult) override;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/controltype.hxx b/extensions/source/propctrlr/controltype.hxx
new file mode 100644
index 000000000..89a400a76
--- /dev/null
+++ b/extensions/source/propctrlr/controltype.hxx
@@ -0,0 +1,35 @@
+/* -*- 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/types.h>
+
+
+namespace pcr::ControlType
+{
+ const sal_Int16 FIXEDLINE = sal_Int16(100);
+ const sal_Int16 FORMATTEDFIELD = sal_Int16(101);
+ const sal_Int16 PROGRESSBAR = sal_Int16(102);
+
+ // need only those which are not already covered as FormComponentType
+
+} // namespace pcr::ControlType
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/defaultforminspection.cxx b/extensions/source/propctrlr/defaultforminspection.cxx
new file mode 100644
index 000000000..1fe8ee60e
--- /dev/null
+++ b/extensions/source/propctrlr/defaultforminspection.cxx
@@ -0,0 +1,215 @@
+/* -*- 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 "defaultforminspection.hxx"
+#include "pcrcommon.hxx"
+#include <helpids.h>
+#include <strings.hrc>
+#include "modulepcr.hxx"
+#include "formmetadata.hxx"
+
+#include <com/sun/star/ucb/AlreadyInitializedException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <sal/macros.h>
+
+
+namespace pcr
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::inspection::PropertyCategoryDescriptor;
+ using ::com::sun::star::ucb::AlreadyInitializedException;
+ using ::com::sun::star::lang::IllegalArgumentException;
+
+ DefaultFormComponentInspectorModel::DefaultFormComponentInspectorModel( bool _bUseFormFormComponentHandlers )
+ :m_bUseFormComponentHandlers( _bUseFormFormComponentHandlers )
+ ,m_bConstructed( false )
+ ,m_pInfoService( new OPropertyInfoService )
+ {
+ }
+
+
+ DefaultFormComponentInspectorModel::~DefaultFormComponentInspectorModel()
+ {
+ }
+
+
+ OUString SAL_CALL DefaultFormComponentInspectorModel::getImplementationName( )
+ {
+ return "org.openoffice.comp.extensions.DefaultFormComponentInspectorModel";
+ }
+
+
+ Sequence< OUString > SAL_CALL DefaultFormComponentInspectorModel::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.form.inspection.DefaultFormComponentInspectorModel" };
+ }
+
+
+ Sequence< Any > SAL_CALL DefaultFormComponentInspectorModel::getHandlerFactories()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // service names for all our handlers
+ static struct
+ {
+ const char* serviceName;
+ bool isFormOnly;
+ } const aFactories[] = {
+
+ // a generic handler for form component properties (must precede the ButtonNavigationHandler)
+ { "com.sun.star.form.inspection.FormComponentPropertyHandler", false },
+
+ // generic virtual edit properties
+ { "com.sun.star.form.inspection.EditPropertyHandler", false },
+
+ // a handler which virtualizes the ButtonType property, to provide additional types like
+ // "move to next record"
+ { "com.sun.star.form.inspection.ButtonNavigationHandler", false },
+
+ // a handler for script events bound to form components or dialog elements
+ { "com.sun.star.form.inspection.EventHandler", false },
+
+ // a handler which introduces virtual properties for binding controls to spreadsheet cells
+ { "com.sun.star.form.inspection.CellBindingPropertyHandler", false },
+
+ // properties related to binding to an XForms DOM node
+ { "com.sun.star.form.inspection.XMLFormsPropertyHandler", true },
+
+ // properties related to the XSD data against which a control content is validated
+ { "com.sun.star.form.inspection.XSDValidationPropertyHandler", true },
+
+ // a handler which cares for XForms submissions
+ { "com.sun.star.form.inspection.SubmissionPropertyHandler", true },
+
+ // a handler which cares for geometry properties of form controls
+ { "com.sun.star.form.inspection.FormGeometryHandler", true }
+ };
+
+ sal_Int32 nFactories = SAL_N_ELEMENTS( aFactories );
+ Sequence< Any > aReturn( nFactories );
+ Any* pReturn = aReturn.getArray();
+ for ( sal_Int32 i = 0; i < nFactories; ++i )
+ {
+ if ( aFactories[i].isFormOnly && !m_bUseFormComponentHandlers )
+ continue;
+ *pReturn++ <<= OUString::createFromAscii( aFactories[i].serviceName );
+ }
+ aReturn.realloc( pReturn - aReturn.getArray() );
+
+ return aReturn;
+ }
+
+
+ Sequence< PropertyCategoryDescriptor > SAL_CALL DefaultFormComponentInspectorModel::describeCategories( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ static struct
+ {
+ const char* programmaticName;
+ TranslateId uiNameResId;
+ rtl::OUStringConstExpr helpId;
+ } const aCategories[] = {
+ { "General", RID_STR_PROPPAGE_DEFAULT, HID_FM_PROPDLG_TAB_GENERAL },
+ { "Data", RID_STR_PROPPAGE_DATA, HID_FM_PROPDLG_TAB_DATA },
+ { "Events", RID_STR_EVENTS, HID_FM_PROPDLG_TAB_EVT }
+ };
+
+ sal_Int32 nCategories = SAL_N_ELEMENTS( aCategories );
+ Sequence< PropertyCategoryDescriptor > aReturn( nCategories );
+ PropertyCategoryDescriptor* pReturn = aReturn.getArray();
+ for ( sal_Int32 i=0; i<nCategories; ++i, ++pReturn )
+ {
+ pReturn->ProgrammaticName = OUString::createFromAscii( aCategories[i].programmaticName );
+ pReturn->UIName = PcrRes( aCategories[i].uiNameResId );
+ pReturn->HelpURL = HelpIdUrl::getHelpURL( aCategories[i].helpId.asView() );
+ }
+
+ return aReturn;
+ }
+
+
+ ::sal_Int32 SAL_CALL DefaultFormComponentInspectorModel::getPropertyOrderIndex( const OUString& _rPropertyName )
+ {
+ sal_Int32 nPropertyId( m_pInfoService->getPropertyId( _rPropertyName ) );
+ if ( nPropertyId == -1 )
+ {
+ if ( _rPropertyName.indexOf( ';' ) != -1 )
+ // it's an event. Just give it an arbitrary number - events will be on a separate
+ // page, and by definition, if two properties have the same OrderIndex, then
+ // they will be ordered as they appear in the handler's getSupportedProperties.
+ return 1000;
+ return 0;
+ }
+ return m_pInfoService->getPropertyPos( nPropertyId );
+ }
+
+
+ void SAL_CALL DefaultFormComponentInspectorModel::initialize( const Sequence< Any >& _arguments )
+ {
+ if ( m_bConstructed )
+ throw AlreadyInitializedException();
+
+ StlSyntaxSequence< Any > arguments( _arguments );
+ if ( arguments.empty() )
+ { // constructor: "createDefault()"
+ m_bConstructed = true;
+ return;
+ }
+
+ if ( arguments.size() == 2 )
+ { // constructor: "createWithHelpSection( long, long )"
+ sal_Int32 nMinHelpTextLines( 0 ), nMaxHelpTextLines( 0 );
+ if ( !( arguments[0] >>= nMinHelpTextLines ) || !( arguments[1] >>= nMaxHelpTextLines ) )
+ throw IllegalArgumentException( OUString(), *this, 0 );
+ createWithHelpSection( nMinHelpTextLines, nMaxHelpTextLines );
+ return;
+ }
+
+ throw IllegalArgumentException( OUString(), *this, 0 );
+ }
+
+
+ void DefaultFormComponentInspectorModel::createWithHelpSection( sal_Int32 _nMinHelpTextLines, sal_Int32 _nMaxHelpTextLines )
+ {
+ if ( ( _nMinHelpTextLines <= 0 ) || ( _nMaxHelpTextLines <= 0 ) || ( _nMinHelpTextLines > _nMaxHelpTextLines ) )
+ throw IllegalArgumentException( OUString(), *this, 0 );
+
+ enableHelpSectionProperties( _nMinHelpTextLines, _nMaxHelpTextLines );
+ m_bConstructed = true;
+ }
+
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_DefaultFormComponentInspectorModel_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::DefaultFormComponentInspectorModel(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/defaultforminspection.hxx b/extensions/source/propctrlr/defaultforminspection.hxx
new file mode 100644
index 000000000..e118e9da6
--- /dev/null
+++ b/extensions/source/propctrlr/defaultforminspection.hxx
@@ -0,0 +1,66 @@
+/* -*- 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 "inspectormodelbase.hxx"
+
+#include <memory>
+
+
+namespace pcr
+{
+
+
+ class OPropertyInfoService;
+
+ class DefaultFormComponentInspectorModel final : public ImplInspectorModel
+ {
+ bool m_bUseFormComponentHandlers;
+ bool m_bConstructed;
+
+ /// access to property meta data
+ std::unique_ptr< OPropertyInfoService > m_pInfoService;
+
+ virtual ~DefaultFormComponentInspectorModel() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XObjectInspectorModel
+ virtual css::uno::Sequence< css::uno::Any > SAL_CALL getHandlerFactories() override;
+ virtual css::uno::Sequence< css::inspection::PropertyCategoryDescriptor > SAL_CALL describeCategories( ) override;
+ virtual ::sal_Int32 SAL_CALL getPropertyOrderIndex( const OUString& PropertyName ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ public:
+ explicit DefaultFormComponentInspectorModel( bool _bUseFormFormComponentHandlers = true );
+
+ private:
+ // Service constructors
+ void createWithHelpSection( sal_Int32 _nMinHelpTextLines, sal_Int32 _nMaxHelpTextLines );
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/defaulthelpprovider.cxx b/extensions/source/propctrlr/defaulthelpprovider.cxx
new file mode 100644
index 000000000..8f1e22b82
--- /dev/null
+++ b/extensions/source/propctrlr/defaulthelpprovider.cxx
@@ -0,0 +1,184 @@
+/* -*- 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 "defaulthelpprovider.hxx"
+#include "pcrcommon.hxx"
+
+#include <com/sun/star/ucb/AlreadyInitializedException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/window.hxx>
+#include <tools/diagnose_ex.h>
+#include <cppuhelper/supportsservice.hxx>
+
+
+namespace pcr
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::inspection::XPropertyControl;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::inspection::XObjectInspectorUI;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::ucb::AlreadyInitializedException;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::awt::XWindow;
+
+ DefaultHelpProvider::DefaultHelpProvider()
+ :m_bConstructed( false )
+ {
+ }
+
+
+ DefaultHelpProvider::~DefaultHelpProvider()
+ {
+ }
+
+
+ Sequence< OUString > SAL_CALL DefaultHelpProvider::getSupportedServiceNames()
+ {
+ return { "com.sun.star.inspection.DefaultHelpProvider" };
+ }
+
+ OUString SAL_CALL DefaultHelpProvider::getImplementationName()
+ {
+ return "org.openoffice.comp.extensions.DefaultHelpProvider";
+ }
+
+ sal_Bool SAL_CALL DefaultHelpProvider::supportsService(const OUString& aServiceName)
+ {
+ return cppu::supportsService(this, aServiceName);
+ }
+
+
+ void SAL_CALL DefaultHelpProvider::focusGained( const Reference< XPropertyControl >& Control )
+ {
+ if ( !m_xInspectorUI.is() )
+ throw RuntimeException( OUString(), *this );
+
+ try
+ {
+ m_xInspectorUI->setHelpSectionText( impl_getHelpText_nothrow( Control ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+
+ void SAL_CALL DefaultHelpProvider::valueChanged( const Reference< XPropertyControl >& )
+ {
+ // not interested in
+ }
+
+
+ void SAL_CALL DefaultHelpProvider::initialize( const Sequence< Any >& _arguments )
+ {
+ if ( m_bConstructed )
+ throw AlreadyInitializedException();
+
+ StlSyntaxSequence< Any > arguments( _arguments );
+ if ( arguments.size() == 1 )
+ { // constructor: "create( XObjectInspectorUI )"
+ Reference< XObjectInspectorUI > xUI( arguments[0], UNO_QUERY );
+ create( xUI );
+ return;
+ }
+
+ throw IllegalArgumentException( OUString(), *this, 0 );
+ }
+
+
+ void DefaultHelpProvider::create( const Reference< XObjectInspectorUI >& _rxUI )
+ {
+ if ( !_rxUI.is() )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+
+ try
+ {
+ m_xInspectorUI = _rxUI;
+ m_xInspectorUI->registerControlObserver( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+
+ m_bConstructed = true;
+ }
+
+
+ vcl::Window* DefaultHelpProvider::impl_getVclControlWindow_nothrow( const Reference< XPropertyControl >& _rxControl )
+ {
+ vcl::Window* pControlWindow = nullptr;
+ OSL_PRECOND( _rxControl.is(), "DefaultHelpProvider::impl_getVclControlWindow_nothrow: illegal control!" );
+ if ( !_rxControl.is() )
+ return pControlWindow;
+
+ try
+ {
+ Reference< XWindow > xControlWindow( _rxControl->getControlWindow(), css::uno::UNO_SET_THROW );
+ pControlWindow = VCLUnoHelper::GetWindow( xControlWindow );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+
+ return pControlWindow;
+ }
+
+
+ OUString DefaultHelpProvider::impl_getHelpText_nothrow( const Reference< XPropertyControl >& _rxControl )
+ {
+ OUString sHelpText;
+ OSL_PRECOND( _rxControl.is(), "DefaultHelpProvider::impl_getHelpText_nothrow: illegal control!" );
+ if ( !_rxControl.is() )
+ return sHelpText;
+
+ vcl::Window* pControlWindow( impl_getVclControlWindow_nothrow( _rxControl ) );
+ OSL_ENSURE( pControlWindow, "DefaultHelpProvider::impl_getHelpText_nothrow: could not determine the VCL window!" );
+ if ( !pControlWindow )
+ return sHelpText;
+
+ sHelpText = pControlWindow->GetHelpText();
+ return sHelpText;
+ }
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_DefaultHelpProvider_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::DefaultHelpProvider());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/defaulthelpprovider.hxx b/extensions/source/propctrlr/defaulthelpprovider.hxx
new file mode 100644
index 000000000..f647937dd
--- /dev/null
+++ b/extensions/source/propctrlr/defaulthelpprovider.hxx
@@ -0,0 +1,78 @@
+/* -*- 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/inspection/XPropertyControlObserver.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/inspection/XObjectInspectorUI.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+namespace vcl { class Window; }
+
+
+namespace pcr
+{
+
+
+ //= DefaultHelpProvider
+
+ typedef ::cppu::WeakImplHelper < css::inspection::XPropertyControlObserver
+ , css::lang::XInitialization
+ , css::lang::XServiceInfo
+ > DefaultHelpProvider_Base;
+ class DefaultHelpProvider final : public DefaultHelpProvider_Base
+ {
+ private:
+ bool m_bConstructed;
+ css::uno::Reference< css::inspection::XObjectInspectorUI >
+ m_xInspectorUI;
+
+ public:
+ DefaultHelpProvider();
+
+ private:
+ virtual ~DefaultHelpProvider() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override;
+
+ // XPropertyControlObserver
+ virtual void SAL_CALL focusGained( const css::uno::Reference< css::inspection::XPropertyControl >& Control ) override;
+ virtual void SAL_CALL valueChanged( const css::uno::Reference< css::inspection::XPropertyControl >& Control ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // Service constructors
+ void create( const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxUI );
+
+ static vcl::Window* impl_getVclControlWindow_nothrow( const css::uno::Reference< css::inspection::XPropertyControl >& _rxControl );
+ static OUString impl_getHelpText_nothrow( const css::uno::Reference< css::inspection::XPropertyControl >& _rxControl );
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/editpropertyhandler.cxx b/extensions/source/propctrlr/editpropertyhandler.cxx
new file mode 100644
index 000000000..22ad04988
--- /dev/null
+++ b/extensions/source/propctrlr/editpropertyhandler.cxx
@@ -0,0 +1,308 @@
+/* -*- 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 "editpropertyhandler.hxx"
+#include "formstrings.hxx"
+#include "formmetadata.hxx"
+
+#include <com/sun/star/inspection/XObjectInspectorUI.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <tools/diagnose_ex.h>
+
+#define TEXTTYPE_SINGLELINE 0
+#define TEXTTYPE_MULTILINE 1
+#define TEXTTYPE_RICHTEXT 2
+
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::inspection;
+
+
+ //= EditPropertyHandler
+
+
+ EditPropertyHandler::EditPropertyHandler( const Reference< XComponentContext >& _rxContext )
+ :PropertyHandlerComponent( _rxContext )
+ {
+ }
+
+
+ EditPropertyHandler::~EditPropertyHandler( )
+ {
+ }
+
+
+ OUString EditPropertyHandler::getImplementationName( )
+ {
+ return "com.sun.star.comp.extensions.EditPropertyHandler";
+ }
+
+
+ Sequence< OUString > EditPropertyHandler::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.form.inspection.EditPropertyHandler" };
+ }
+
+
+ Any SAL_CALL EditPropertyHandler::getPropertyValue( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ Any aReturn;
+ try
+ {
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_SHOW_SCROLLBARS:
+ {
+ bool bHasVScroll = false;
+ m_xComponent->getPropertyValue( PROPERTY_VSCROLL ) >>= bHasVScroll;
+ bool bHasHScroll = false;
+ m_xComponent->getPropertyValue( PROPERTY_HSCROLL ) >>= bHasHScroll;
+
+ aReturn <<= static_cast<sal_Int32>( ( bHasVScroll ? 2 : 0 ) + ( bHasHScroll ? 1 : 0 ) );
+ }
+ break;
+
+ case PROPERTY_ID_TEXTTYPE:
+ {
+ sal_Int32 nTextType = TEXTTYPE_SINGLELINE;
+ bool bRichText = false;
+ OSL_VERIFY( m_xComponent->getPropertyValue( PROPERTY_RICHTEXT ) >>= bRichText );
+ if ( bRichText )
+ nTextType = TEXTTYPE_RICHTEXT;
+ else
+ {
+ bool bMultiLine = false;
+ OSL_VERIFY( m_xComponent->getPropertyValue( PROPERTY_MULTILINE ) >>= bMultiLine );
+ if ( bMultiLine )
+ nTextType = TEXTTYPE_MULTILINE;
+ else
+ nTextType = TEXTTYPE_SINGLELINE;
+ }
+ aReturn <<= nTextType;
+ }
+ break;
+
+
+ default:
+ OSL_FAIL( "EditPropertyHandler::getPropertyValue: cannot handle this property!" );
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EditPropertyHandler::getPropertyValue" );
+ }
+
+ return aReturn;
+ }
+
+
+ void SAL_CALL EditPropertyHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ try
+ {
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_SHOW_SCROLLBARS:
+ {
+ sal_Int32 nScrollbars = 0;
+ _rValue >>= nScrollbars;
+
+ bool bHasVScroll = 0 != ( nScrollbars & 2 );
+ bool bHasHScroll = 0 != ( nScrollbars & 1 );
+
+ m_xComponent->setPropertyValue( PROPERTY_VSCROLL, Any( bHasVScroll ) );
+ m_xComponent->setPropertyValue( PROPERTY_HSCROLL, Any( bHasHScroll ) );
+ }
+ break;
+
+ case PROPERTY_ID_TEXTTYPE:
+ {
+ bool bMultiLine = false;
+ bool bRichText = false;
+ sal_Int32 nTextType = TEXTTYPE_SINGLELINE;
+ OSL_VERIFY( _rValue >>= nTextType );
+ switch ( nTextType )
+ {
+ case TEXTTYPE_SINGLELINE: bMultiLine = bRichText = false; break;
+ case TEXTTYPE_MULTILINE: bMultiLine = true; bRichText = false; break;
+ case TEXTTYPE_RICHTEXT: bMultiLine = true; bRichText = true; break;
+ default:
+ OSL_FAIL( "EditPropertyHandler::setPropertyValue: invalid text type!" );
+ }
+
+ m_xComponent->setPropertyValue( PROPERTY_MULTILINE, Any( bMultiLine ) );
+ m_xComponent->setPropertyValue( PROPERTY_RICHTEXT, Any( bRichText ) );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "EditPropertyHandler::setPropertyValue: cannot handle this id!" );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EditPropertyHandler::setPropertyValue" );
+ }
+ }
+
+
+ bool EditPropertyHandler::implHaveBothScrollBarProperties() const
+ {
+ // have a "Scrollbars" property if the object supports both "HScroll" and "VScroll"
+ Reference< XPropertySetInfo > xPSI;
+ if ( m_xComponent.is() )
+ xPSI = m_xComponent->getPropertySetInfo();
+
+ return xPSI.is()
+ && xPSI->hasPropertyByName( PROPERTY_HSCROLL )
+ && xPSI->hasPropertyByName( PROPERTY_VSCROLL );
+ }
+
+
+ bool EditPropertyHandler::implHaveTextTypeProperty() const
+ {
+ // have a "Scrollbars" property if the object supports both "HScroll" and "VScroll"
+ Reference< XPropertySetInfo > xPSI;
+ if ( m_xComponent.is() )
+ xPSI = m_xComponent->getPropertySetInfo();
+
+ return xPSI.is()
+ && xPSI->hasPropertyByName( PROPERTY_RICHTEXT )
+ && xPSI->hasPropertyByName( PROPERTY_MULTILINE );
+ }
+
+
+ Sequence< Property > EditPropertyHandler::doDescribeSupportedProperties() const
+ {
+ std::vector< Property > aProperties;
+
+ if ( implHaveBothScrollBarProperties() )
+ addInt32PropertyDescription( aProperties, PROPERTY_SHOW_SCROLLBARS );
+
+ if ( implHaveTextTypeProperty() )
+ addInt32PropertyDescription( aProperties, PROPERTY_TEXTTYPE );
+
+ if ( aProperties.empty() )
+ return Sequence< Property >();
+ return comphelper::containerToSequence(aProperties);
+ }
+
+
+ Sequence< OUString > SAL_CALL EditPropertyHandler::getSupersededProperties( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ std::vector< OUString > aSuperseded;
+ if ( implHaveBothScrollBarProperties() )
+ {
+ aSuperseded.push_back( PROPERTY_HSCROLL );
+ aSuperseded.push_back( PROPERTY_VSCROLL );
+ }
+ if ( implHaveTextTypeProperty() )
+ {
+ aSuperseded.push_back( PROPERTY_RICHTEXT );
+ aSuperseded.push_back( PROPERTY_MULTILINE );
+ }
+ if ( aSuperseded.empty() )
+ return Sequence< OUString >();
+ return comphelper::containerToSequence(aSuperseded);
+ }
+
+
+ Sequence< OUString > SAL_CALL EditPropertyHandler::getActuatingProperties( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ std::vector< OUString > aInterestingActuatingProps;
+ if ( implHaveTextTypeProperty() )
+ aInterestingActuatingProps.push_back( PROPERTY_TEXTTYPE );
+ aInterestingActuatingProps.push_back( PROPERTY_MULTILINE );
+ return comphelper::containerToSequence(aInterestingActuatingProps);
+ }
+
+
+ void SAL_CALL EditPropertyHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool )
+ {
+ if ( !_rxInspectorUI.is() )
+ throw NullPointerException();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nActuatingPropId( impl_getPropertyId_throwRuntime( _rActuatingPropertyName ) );
+ switch ( nActuatingPropId )
+ {
+ case PROPERTY_ID_TEXTTYPE:
+ {
+ sal_Int32 nTextType = TEXTTYPE_SINGLELINE;
+ getPropertyValue( PROPERTY_TEXTTYPE ) >>= nTextType;
+
+ if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_WORDBREAK ) )
+ _rxInspectorUI->enablePropertyUI( PROPERTY_WORDBREAK, nTextType == TEXTTYPE_RICHTEXT );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_MAXTEXTLEN, nTextType != TEXTTYPE_RICHTEXT );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_ECHO_CHAR, nTextType == TEXTTYPE_SINGLELINE );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_FONT, nTextType != TEXTTYPE_RICHTEXT );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_ALIGN, nTextType != TEXTTYPE_RICHTEXT );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_DEFAULT_TEXT, nTextType != TEXTTYPE_RICHTEXT );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_SHOW_SCROLLBARS, nTextType != TEXTTYPE_SINGLELINE );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_LINEEND_FORMAT, nTextType != TEXTTYPE_SINGLELINE );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_VERTICAL_ALIGN, nTextType == TEXTTYPE_SINGLELINE );
+
+ _rxInspectorUI->showCategory( "Data", nTextType != TEXTTYPE_RICHTEXT );
+ }
+ break;
+
+ case PROPERTY_ID_MULTILINE:
+ {
+ bool bIsMultiline = false;
+ _rNewValue >>= bIsMultiline;
+
+ _rxInspectorUI->enablePropertyUI( PROPERTY_SHOW_SCROLLBARS, bIsMultiline );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_ECHO_CHAR, !bIsMultiline );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_LINEEND_FORMAT, bIsMultiline );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "EditPropertyHandler::actuatingPropertyChanged: cannot handle this id!" );
+ }
+ }
+
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_EditPropertyHandler_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::EditPropertyHandler(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/editpropertyhandler.hxx b/extensions/source/propctrlr/editpropertyhandler.hxx
new file mode 100644
index 000000000..33ad8df98
--- /dev/null
+++ b/extensions/source/propctrlr/editpropertyhandler.hxx
@@ -0,0 +1,68 @@
+/* -*- 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 "propertyhandler.hxx"
+
+
+namespace pcr
+{
+
+
+ //= EditPropertyHandler
+
+ class EditPropertyHandler;
+ /** a property handler for any virtual string properties
+ */
+ class EditPropertyHandler : public PropertyHandlerComponent
+ {
+ public:
+ explicit EditPropertyHandler(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext
+ );
+
+ protected:
+ virtual ~EditPropertyHandler() override;
+
+ protected:
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override;
+
+ // XPropertyHandler overriables
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupersededProperties( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getActuatingProperties( ) override;
+ virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool ) override;
+
+ // PropertyHandler overridables
+ virtual css::uno::Sequence< css::beans::Property >
+ doDescribeSupportedProperties() const override;
+ private:
+ bool implHaveBothScrollBarProperties() const;
+ bool implHaveTextTypeProperty() const;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/eformshelper.cxx b/extensions/source/propctrlr/eformshelper.cxx
new file mode 100644
index 000000000..620368e9d
--- /dev/null
+++ b/extensions/source/propctrlr/eformshelper.cxx
@@ -0,0 +1,762 @@
+/* -*- 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 <string_view>
+
+#include "eformshelper.hxx"
+#include "formstrings.hxx"
+#include <strings.hrc>
+#include "modulepcr.hxx"
+#include "propeventtranslation.hxx"
+#include "formbrowsertools.hxx"
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/xforms/XFormsUIHelper1.hpp>
+#include <com/sun/star/xsd/DataTypeClass.hpp>
+#include <com/sun/star/form/binding/XListEntrySink.hpp>
+#include <tools/diagnose_ex.h>
+
+#include <algorithm>
+#include <o3tl/functional.hxx>
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::form::binding;
+ using namespace ::com::sun::star::xsd;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::form;
+
+
+ //= file-local helpers
+
+ namespace
+ {
+
+ OUString composeModelElementUIName( std::u16string_view _rModelName, std::u16string_view _rElementName )
+ {
+ OUString a = OUString::Concat("[")
+ + _rModelName + "] "
+ + _rElementName;
+ return a;
+ }
+ }
+
+
+ //= EFormsHelper
+
+
+ EFormsHelper::EFormsHelper( ::osl::Mutex& _rMutex, const Reference< XPropertySet >& _rxControlModel, const Reference< frame::XModel >& _rxContextDocument )
+ :m_xControlModel( _rxControlModel )
+ ,m_aPropertyListeners( _rMutex )
+ {
+ OSL_ENSURE( _rxControlModel.is(), "EFormsHelper::EFormsHelper: invalid control model!" );
+ m_xBindableControl.set(_rxControlModel, css::uno::UNO_QUERY);
+
+ m_xDocument.set(_rxContextDocument, css::uno::UNO_QUERY);
+ OSL_ENSURE( m_xDocument.is(), "EFormsHelper::EFormsHelper: invalid document!" );
+
+ }
+
+
+ bool EFormsHelper::isEForm( const Reference< frame::XModel >& _rxContextDocument )
+ {
+ try
+ {
+ Reference< xforms::XFormsSupplier > xDocument( _rxContextDocument, UNO_QUERY );
+ if ( !xDocument.is() )
+ return false;
+
+ return xDocument->getXForms().is();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::isEForm" );
+ }
+ return false;
+ }
+
+
+ bool EFormsHelper::canBindToDataType( sal_Int32 _nDataType ) const
+ {
+ if ( !m_xBindableControl.is() )
+ // cannot bind at all
+ return false;
+
+ // some types cannot be bound, independent from the control type
+ if ( ( DataTypeClass::hexBinary == _nDataType )
+ || ( DataTypeClass::base64Binary == _nDataType )
+ || ( DataTypeClass::QName == _nDataType )
+ || ( DataTypeClass::NOTATION == _nDataType )
+ )
+ return false;
+
+ bool bCan = false;
+ try
+ {
+ // classify the control model
+ sal_Int16 nControlType = FormComponentType::CONTROL;
+ OSL_VERIFY( m_xControlModel->getPropertyValue( PROPERTY_CLASSID ) >>= nControlType );
+
+ // some lists
+ sal_Int16 const nNumericCompatibleTypes[] = { DataTypeClass::DECIMAL, DataTypeClass::FLOAT, DataTypeClass::DOUBLE, 0 };
+ sal_Int16 const nDateCompatibleTypes[] = { DataTypeClass::DATE, 0 };
+ sal_Int16 const nTimeCompatibleTypes[] = { DataTypeClass::TIME, 0 };
+ sal_Int16 const nCheckboxCompatibleTypes[] = { DataTypeClass::BOOLEAN, DataTypeClass::STRING, DataTypeClass::anyURI, 0 };
+ sal_Int16 const nRadiobuttonCompatibleTypes[] = { DataTypeClass::STRING, DataTypeClass::anyURI, 0 };
+ sal_Int16 const nFormattedCompatibleTypes[] = { DataTypeClass::DECIMAL, DataTypeClass::FLOAT, DataTypeClass::DOUBLE, DataTypeClass::DATETIME, DataTypeClass::DATE, DataTypeClass::TIME, 0 };
+
+ sal_Int16 const * pCompatibleTypes = nullptr;
+ switch ( nControlType )
+ {
+ case FormComponentType::SPINBUTTON:
+ case FormComponentType::NUMERICFIELD:
+ pCompatibleTypes = nNumericCompatibleTypes;
+ break;
+ case FormComponentType::DATEFIELD:
+ pCompatibleTypes = nDateCompatibleTypes;
+ break;
+ case FormComponentType::TIMEFIELD:
+ pCompatibleTypes = nTimeCompatibleTypes;
+ break;
+ case FormComponentType::CHECKBOX:
+ pCompatibleTypes = nCheckboxCompatibleTypes;
+ break;
+ case FormComponentType::RADIOBUTTON:
+ pCompatibleTypes = nRadiobuttonCompatibleTypes;
+ break;
+
+ case FormComponentType::TEXTFIELD:
+ {
+ // both the normal text field, and the formatted field, claim to be a TEXTFIELD
+ // need to distinguish by service name
+ Reference< XServiceInfo > xSI( m_xControlModel, UNO_QUERY );
+ OSL_ENSURE( xSI.is(), "EFormsHelper::canBindToDataType: a control model which has no service info?" );
+ if ( xSI.is() )
+ {
+ if ( xSI->supportsService( SERVICE_COMPONENT_FORMATTEDFIELD ) )
+ {
+ pCompatibleTypes = nFormattedCompatibleTypes;
+ break;
+ }
+ }
+ [[fallthrough]];
+ }
+ case FormComponentType::LISTBOX:
+ case FormComponentType::COMBOBOX:
+ // edit fields and list/combo boxes can be bound to anything
+ bCan = true;
+ }
+
+ if ( !bCan && pCompatibleTypes )
+ {
+ if ( _nDataType == -1 )
+ {
+ // the control can be bound to at least one type, and exactly this is being asked for
+ bCan = true;
+ }
+ else
+ {
+ while ( *pCompatibleTypes && !bCan )
+ bCan = ( *pCompatibleTypes++ == _nDataType );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::canBindToDataType" );
+ }
+
+ return bCan;
+ }
+
+
+ bool EFormsHelper::isListEntrySink() const
+ {
+ bool bIs = false;
+ try
+ {
+ Reference< XListEntrySink > xAsSink( m_xControlModel, UNO_QUERY );
+ bIs = xAsSink.is();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::isListEntrySink" );
+ }
+ return bIs;
+ }
+
+
+ void EFormsHelper::impl_switchBindingListening_throw( bool _bDoListening, const Reference< XPropertyChangeListener >& _rxListener )
+ {
+ Reference< XPropertySet > xBindingProps;
+ if ( m_xBindableControl.is() )
+ xBindingProps.set(m_xBindableControl->getValueBinding(), css::uno::UNO_QUERY);
+ if ( !xBindingProps.is() )
+ return;
+
+ if ( _bDoListening )
+ {
+ xBindingProps->addPropertyChangeListener( OUString(), _rxListener );
+ }
+ else
+ {
+ xBindingProps->removePropertyChangeListener( OUString(), _rxListener );
+ }
+ }
+
+
+ void EFormsHelper::registerBindingListener( const Reference< XPropertyChangeListener >& _rxBindingListener )
+ {
+ if ( !_rxBindingListener.is() )
+ return;
+ impl_toggleBindingPropertyListening_throw( true, _rxBindingListener );
+ }
+
+
+ void EFormsHelper::impl_toggleBindingPropertyListening_throw( bool _bDoListen, const Reference< XPropertyChangeListener >& _rxConcreteListenerOrNull )
+ {
+ if ( !_bDoListen )
+ {
+ ::comphelper::OInterfaceIteratorHelper3 aListenerIterator(m_aPropertyListeners);
+ while ( aListenerIterator.hasMoreElements() )
+ {
+ PropertyEventTranslation* pTranslator = dynamic_cast< PropertyEventTranslation* >( aListenerIterator.next().get() );
+ OSL_ENSURE( pTranslator, "EFormsHelper::impl_toggleBindingPropertyListening_throw: invalid listener element in my container!" );
+ if ( !pTranslator )
+ continue;
+
+ Reference< XPropertyChangeListener > xEventSourceTranslator( pTranslator );
+ if ( _rxConcreteListenerOrNull.is() )
+ {
+ if ( pTranslator->getDelegator() == _rxConcreteListenerOrNull )
+ {
+ impl_switchBindingListening_throw( false, xEventSourceTranslator );
+ m_aPropertyListeners.removeInterface( xEventSourceTranslator );
+ break;
+ }
+ }
+ else
+ {
+ impl_switchBindingListening_throw( false, xEventSourceTranslator );
+ }
+ }
+ }
+ else
+ {
+ if ( _rxConcreteListenerOrNull.is() )
+ {
+ Reference< XPropertyChangeListener > xEventSourceTranslator( new PropertyEventTranslation( _rxConcreteListenerOrNull, m_xBindableControl ) );
+ m_aPropertyListeners.addInterface( xEventSourceTranslator );
+ impl_switchBindingListening_throw( true, xEventSourceTranslator );
+ }
+ else
+ {
+ ::comphelper::OInterfaceIteratorHelper3 aListenerIterator(m_aPropertyListeners);
+ while ( aListenerIterator.hasMoreElements() )
+ impl_switchBindingListening_throw( true, aListenerIterator.next() );
+ }
+ }
+ }
+
+
+ void EFormsHelper::revokeBindingListener( const Reference< XPropertyChangeListener >& _rxBindingListener )
+ {
+ impl_toggleBindingPropertyListening_throw( false, _rxBindingListener );
+ }
+
+
+ void EFormsHelper::getFormModelNames( std::vector< OUString >& /* [out] */ _rModelNames ) const
+ {
+ if ( !m_xDocument.is() )
+ return;
+
+ try
+ {
+ _rModelNames.resize( 0 );
+
+ Reference< XNameContainer > xForms( m_xDocument->getXForms() );
+ OSL_ENSURE( xForms.is(), "EFormsHelper::getFormModelNames: invalid forms container!" );
+ if ( xForms.is() )
+ {
+ const Sequence< OUString > aModelNames = xForms->getElementNames();
+ _rModelNames.resize( aModelNames.getLength() );
+ std::copy( aModelNames.begin(), aModelNames.end(), _rModelNames.begin() );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getFormModelNames" );
+ }
+ }
+
+
+ void EFormsHelper::getBindingNames( const OUString& _rModelName, std::vector< OUString >& /* [out] */ _rBindingNames ) const
+ {
+ _rBindingNames.resize( 0 );
+ try
+ {
+ Reference< xforms::XModel > xModel( getFormModelByName( _rModelName ) );
+ if ( xModel.is() )
+ {
+ Reference< XNameAccess > xBindings( xModel->getBindings(), UNO_QUERY );
+ OSL_ENSURE( xBindings.is(), "EFormsHelper::getBindingNames: invalid bindings container obtained from the model!" );
+ if ( xBindings.is() )
+ {
+ const Sequence< OUString > aNames = xBindings->getElementNames();
+ _rBindingNames.resize( aNames.getLength() );
+ std::copy( aNames.begin(), aNames.end(), _rBindingNames.begin() );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getBindingNames" );
+ }
+ }
+
+
+ Reference< xforms::XModel > EFormsHelper::getFormModelByName( const OUString& _rModelName ) const
+ {
+ Reference< xforms::XModel > xReturn;
+ try
+ {
+ Reference< XNameContainer > xForms( m_xDocument->getXForms() );
+ OSL_ENSURE( xForms.is(), "EFormsHelper::getFormModelByName: invalid forms container!" );
+ if ( xForms.is() )
+ OSL_VERIFY( xForms->getByName( _rModelName ) >>= xReturn );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getFormModelByName" );
+ }
+ return xReturn;
+ }
+
+
+ Reference< xforms::XModel > EFormsHelper::getCurrentFormModel() const
+ {
+ Reference< xforms::XModel > xModel;
+ try
+ {
+ Reference< XPropertySet > xBinding( getCurrentBinding() );
+ if ( xBinding.is() )
+ {
+ OSL_VERIFY( xBinding->getPropertyValue( PROPERTY_MODEL ) >>= xModel );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getCurrentFormModel" );
+ }
+ return xModel;
+ }
+
+
+ OUString EFormsHelper::getCurrentFormModelName() const
+ {
+ OUString sModelName;
+ try
+ {
+ Reference< xforms::XModel > xFormsModel( getCurrentFormModel() );
+ if ( xFormsModel.is() )
+ sModelName = xFormsModel->getID();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getCurrentFormModel" );
+ }
+ return sModelName;
+ }
+
+
+ Reference< XPropertySet > EFormsHelper::getCurrentBinding() const
+ {
+ Reference< XPropertySet > xBinding;
+
+ try
+ {
+ if ( m_xBindableControl.is() )
+ xBinding.set(m_xBindableControl->getValueBinding(), css::uno::UNO_QUERY);
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getCurrentBinding" );
+ }
+
+ return xBinding;
+ }
+
+
+ OUString EFormsHelper::getCurrentBindingName() const
+ {
+ OUString sBindingName;
+ try
+ {
+ Reference< XPropertySet > xBinding( getCurrentBinding() );
+ if ( xBinding.is() )
+ xBinding->getPropertyValue( PROPERTY_BINDING_ID ) >>= sBindingName;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getCurrentBindingName" );
+ }
+ return sBindingName;
+ }
+
+
+ Reference< XListEntrySource > EFormsHelper::getCurrentListSourceBinding() const
+ {
+ Reference< XListEntrySource > xReturn;
+ try
+ {
+ Reference< XListEntrySink > xAsSink( m_xControlModel, UNO_QUERY );
+ OSL_ENSURE( xAsSink.is(), "EFormsHelper::getCurrentListSourceBinding: you should have used isListEntrySink before!" );
+ if ( xAsSink.is() )
+ xReturn = xAsSink->getListEntrySource();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getCurrentListSourceBinding" );
+ }
+ return xReturn;
+ }
+
+
+ void EFormsHelper::setListSourceBinding( const Reference< XListEntrySource >& _rxListSource )
+ {
+ try
+ {
+ Reference< XListEntrySink > xAsSink( m_xControlModel, UNO_QUERY );
+ OSL_ENSURE( xAsSink.is(), "EFormsHelper::setListSourceBinding: you should have used isListEntrySink before!" );
+ if ( xAsSink.is() )
+ xAsSink->setListEntrySource( _rxListSource );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::setListSourceBinding" );
+ }
+ }
+
+
+ void EFormsHelper::setBinding( const Reference< css::beans::XPropertySet >& _rxBinding )
+ {
+ if ( !m_xBindableControl.is() )
+ return;
+
+ try
+ {
+ Reference< XPropertySet > xOldBinding( m_xBindableControl->getValueBinding(), UNO_QUERY );
+
+ Reference< XValueBinding > xBinding( _rxBinding, UNO_QUERY );
+ OSL_ENSURE( xBinding.is() || !_rxBinding.is(), "EFormsHelper::setBinding: invalid binding!" );
+
+ impl_toggleBindingPropertyListening_throw( false, nullptr );
+ m_xBindableControl->setValueBinding( xBinding );
+ impl_toggleBindingPropertyListening_throw( true, nullptr );
+
+ std::set< OUString > aSet;
+ firePropertyChanges( xOldBinding, _rxBinding, aSet );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::setBinding" );
+ }
+ }
+
+
+ Reference< XPropertySet > EFormsHelper::getOrCreateBindingForModel( const OUString& _rTargetModel, const OUString& _rBindingName ) const
+ {
+ OSL_ENSURE( !_rBindingName.isEmpty(), "EFormsHelper::getOrCreateBindingForModel: invalid binding name!" );
+ return implGetOrCreateBinding( _rTargetModel, _rBindingName );
+ }
+
+
+ Reference< XPropertySet > EFormsHelper::implGetOrCreateBinding( const OUString& _rTargetModel, const OUString& _rBindingName ) const
+ {
+ OSL_ENSURE( !( _rTargetModel.isEmpty() && !_rBindingName.isEmpty() ), "EFormsHelper::implGetOrCreateBinding: no model, but a binding name?" );
+
+ Reference< XPropertySet > xBinding;
+ try
+ {
+ OUString sTargetModel( _rTargetModel );
+ // determine the model which the binding should belong to
+ if ( sTargetModel.isEmpty() )
+ {
+ std::vector< OUString > aModelNames;
+ getFormModelNames( aModelNames );
+ if ( !aModelNames.empty() )
+ sTargetModel = *aModelNames.begin();
+ OSL_ENSURE( !sTargetModel.isEmpty(), "EFormsHelper::implGetOrCreateBinding: unable to obtain a default model!" );
+ }
+ Reference< xforms::XModel > xModel( getFormModelByName( sTargetModel ) );
+ Reference< XNameAccess > xBindingNames( xModel.is() ? xModel->getBindings() : Reference< XSet >(), UNO_QUERY );
+ if ( xBindingNames.is() )
+ {
+ // get or create the binding instance
+ if ( !_rBindingName.isEmpty() )
+ {
+ if ( xBindingNames->hasByName( _rBindingName ) )
+ OSL_VERIFY( xBindingNames->getByName( _rBindingName ) >>= xBinding );
+ else
+ {
+ xBinding = xModel->createBinding( );
+ if ( xBinding.is() )
+ {
+ xBinding->setPropertyValue( PROPERTY_BINDING_ID, Any( _rBindingName ) );
+ xModel->getBindings()->insert( Any( xBinding ) );
+ }
+ }
+ }
+ else
+ {
+ xBinding = xModel->createBinding( );
+ if ( xBinding.is() )
+ {
+ // find a nice name for it
+ OUString sBaseName(PcrRes(RID_STR_BINDING_NAME) + " ");
+ OUString sNewName;
+ sal_Int32 nNumber = 1;
+ do
+ {
+ sNewName = sBaseName + OUString::number( nNumber++ );
+ }
+ while ( xBindingNames->hasByName( sNewName ) );
+ Reference< XNamed > xName( xBinding, UNO_QUERY_THROW );
+ xName->setName( sNewName );
+ // and insert into the model
+ xModel->getBindings()->insert( Any( xBinding ) );
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+
+ return xBinding;
+ }
+
+
+ namespace
+ {
+
+ struct PropertyBagInserter
+ {
+ private:
+ PropertyBag& m_rProperties;
+
+ public:
+ explicit PropertyBagInserter( PropertyBag& rProperties ) : m_rProperties( rProperties ) { }
+
+ void operator()( const Property& _rProp )
+ {
+ m_rProperties.insert( _rProp );
+ }
+ };
+
+
+ Reference< XPropertySetInfo > collectPropertiesGetInfo( const Reference< XPropertySet >& _rxProps, PropertyBag& _rBag )
+ {
+ Reference< XPropertySetInfo > xInfo;
+ if ( _rxProps.is() )
+ xInfo = _rxProps->getPropertySetInfo();
+ if ( xInfo.is() )
+ {
+ const Sequence< Property > aProperties = xInfo->getProperties();
+ std::for_each( aProperties.begin(), aProperties.end(),
+ PropertyBagInserter( _rBag )
+ );
+ }
+ return xInfo;
+ }
+ }
+
+
+ OUString EFormsHelper::getModelElementUIName( const EFormsHelper::ModelElementType _eType, const Reference< XPropertySet >& _rxElement )
+ {
+ OUString sUIName;
+ try
+ {
+ // determine the model which the element belongs to
+ Reference< xforms::XFormsUIHelper1 > xHelper;
+ if ( _rxElement.is() )
+ _rxElement->getPropertyValue( PROPERTY_MODEL ) >>= xHelper;
+ OSL_ENSURE( xHelper.is(), "EFormsHelper::getModelElementUIName: invalid element or model!" );
+ if ( xHelper.is() )
+ {
+ OUString sElementName = ( _eType == Submission ) ? xHelper->getSubmissionName( _rxElement, true ) : xHelper->getBindingName( _rxElement, true );
+ Reference< xforms::XModel > xModel( xHelper, UNO_QUERY_THROW );
+ sUIName = composeModelElementUIName( xModel->getID(), sElementName );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getModelElementUIName" );
+ }
+
+ return sUIName;
+ }
+
+
+ Reference< XPropertySet > EFormsHelper::getModelElementFromUIName( const EFormsHelper::ModelElementType _eType, const OUString& _rUIName ) const
+ {
+ const MapStringToPropertySet& rMapUINameToElement( ( _eType == Submission ) ? m_aSubmissionUINames : m_aBindingUINames );
+ MapStringToPropertySet::const_iterator pos = rMapUINameToElement.find( _rUIName );
+ OSL_ENSURE( pos != rMapUINameToElement.end(), "EFormsHelper::getModelElementFromUIName: didn't find it!" );
+
+ return ( pos != rMapUINameToElement.end() ) ? pos->second : Reference< XPropertySet >();
+ }
+
+
+ void EFormsHelper::getAllElementUINames( const ModelElementType _eType, std::vector< OUString >& /* [out] */ _rElementNames, bool _bPrepentEmptyEntry )
+ {
+ MapStringToPropertySet& rMapUINameToElement( ( _eType == Submission ) ? m_aSubmissionUINames : m_aBindingUINames );
+ rMapUINameToElement.clear();
+ _rElementNames.resize( 0 );
+
+ if ( _bPrepentEmptyEntry )
+ rMapUINameToElement[ OUString() ].clear();
+
+ try
+ {
+ // obtain the model names
+ std::vector< OUString > aModels;
+ getFormModelNames( aModels );
+ _rElementNames.reserve( aModels.size() * 2 ); // heuristics
+
+ // for every model, obtain the element
+ for (auto const& modelName : aModels)
+ {
+ Reference< xforms::XModel > xModel = getFormModelByName(modelName);
+ OSL_ENSURE( xModel.is(), "EFormsHelper::getAllElementUINames: inconsistency in the models!" );
+ Reference< xforms::XFormsUIHelper1 > xHelper( xModel, UNO_QUERY );
+
+ Reference< XIndexAccess > xElements;
+ if ( xModel.is() )
+ xElements.set(( _eType == Submission ) ? xModel->getSubmissions() : xModel->getBindings(), css::uno::UNO_QUERY);
+ if ( !xElements.is() )
+ break;
+
+ sal_Int32 nElementCount = xElements->getCount();
+ for ( sal_Int32 i = 0; i < nElementCount; ++i )
+ {
+ Reference< XPropertySet > xElement( xElements->getByIndex( i ), UNO_QUERY );
+ OSL_ENSURE( xElement.is(), "EFormsHelper::getAllElementUINames: empty element!" );
+ if ( !xElement.is() )
+ continue;
+#if OSL_DEBUG_LEVEL > 0
+ {
+ Reference< xforms::XModel > xElementsModel;
+ xElement->getPropertyValue( PROPERTY_MODEL ) >>= xElementsModel;
+ OSL_ENSURE( xElementsModel == xModel, "EFormsHelper::getAllElementUINames: inconsistency in the model-element relationship!" );
+ if ( xElementsModel != xModel )
+ xElement->setPropertyValue( PROPERTY_MODEL, Any( xModel ) );
+ }
+#endif
+ OUString sElementName = ( _eType == Submission ) ? xHelper->getSubmissionName( xElement, true ) : xHelper->getBindingName( xElement, true );
+ OUString sUIName = composeModelElementUIName( modelName, sElementName );
+
+ OSL_ENSURE( rMapUINameToElement.find( sUIName ) == rMapUINameToElement.end(), "EFormsHelper::getAllElementUINames: duplicate name!" );
+ rMapUINameToElement.emplace( sUIName, xElement );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getAllElementUINames" );
+ }
+
+ _rElementNames.resize( rMapUINameToElement.size() );
+ std::transform( rMapUINameToElement.begin(), rMapUINameToElement.end(), _rElementNames.begin(),
+ ::o3tl::select1st< MapStringToPropertySet::value_type >() );
+ }
+
+
+ void EFormsHelper::firePropertyChange( const OUString& _rName, const Any& _rOldValue, const Any& _rNewValue ) const
+ {
+ if ( m_aPropertyListeners.getLength() == 0 )
+ return;
+
+ if ( _rOldValue == _rNewValue )
+ return;
+
+ try
+ {
+ PropertyChangeEvent aEvent;
+
+ aEvent.Source = m_xBindableControl.get();
+ aEvent.PropertyName = _rName;
+ aEvent.OldValue = _rOldValue;
+ aEvent.NewValue = _rNewValue;
+
+ const_cast< EFormsHelper* >( this )->m_aPropertyListeners.notifyEach( &XPropertyChangeListener::propertyChange, aEvent );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::firePropertyChange" );
+ }
+ }
+
+
+ void EFormsHelper::firePropertyChanges( const Reference< XPropertySet >& _rxOldProps, const Reference< XPropertySet >& _rxNewProps, std::set< OUString >& _rFilter ) const
+ {
+ if ( m_aPropertyListeners.getLength() == 0 )
+ return;
+
+ try
+ {
+ PropertyBag aProperties;
+ Reference< XPropertySetInfo > xOldInfo = collectPropertiesGetInfo( _rxOldProps, aProperties );
+ Reference< XPropertySetInfo > xNewInfo = collectPropertiesGetInfo( _rxNewProps, aProperties );
+
+ for (auto const& property : aProperties)
+ {
+ if ( _rFilter.find( property.Name ) != _rFilter.end() )
+ continue;
+
+ Any aOldValue( nullptr, property.Type );
+ if ( xOldInfo.is() && xOldInfo->hasPropertyByName( property.Name ) )
+ aOldValue = _rxOldProps->getPropertyValue( property.Name );
+
+ Any aNewValue( nullptr, property.Type );
+ if ( xNewInfo.is() && xNewInfo->hasPropertyByName( property.Name ) )
+ aNewValue = _rxNewProps->getPropertyValue( property.Name );
+
+ firePropertyChange( property.Name, aOldValue, aNewValue );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::firePropertyChanges" );
+ }
+ }
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/eformshelper.hxx b/extensions/source/propctrlr/eformshelper.hxx
new file mode 100644
index 000000000..e88cb7491
--- /dev/null
+++ b/extensions/source/propctrlr/eformshelper.hxx
@@ -0,0 +1,255 @@
+/* -*- 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 "pcrcommon.hxx"
+
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/xforms/XModel.hpp>
+#include <com/sun/star/xforms/XFormsSupplier.hpp>
+#include <com/sun/star/form/binding/XBindableValue.hpp>
+#include <com/sun/star/form/binding/XListEntrySource.hpp>
+#include <osl/mutex.hxx>
+#include <rtl/ustring.hxx>
+
+#include <vector>
+#include <set>
+#include <map>
+
+
+namespace pcr
+{
+
+
+ typedef std::map< OUString, css::uno::Reference< css::beans::XPropertySet >, std::less< OUString > >
+ MapStringToPropertySet;
+
+
+ //= EFormsHelper
+
+ class EFormsHelper
+ {
+ protected:
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xControlModel;
+ css::uno::Reference< css::form::binding::XBindableValue >
+ m_xBindableControl;
+ css::uno::Reference< css::xforms::XFormsSupplier >
+ m_xDocument;
+ PropertyChangeListeners
+ m_aPropertyListeners;
+ MapStringToPropertySet
+ m_aSubmissionUINames; // only filled upon request
+ MapStringToPropertySet
+ m_aBindingUINames; // only filled upon request
+
+ public:
+ EFormsHelper(
+ ::osl::Mutex& _rMutex,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel,
+ const css::uno::Reference< css::frame::XModel >& _rxContextDocument
+ );
+
+ /** determines whether the given document is an eForm
+
+ If this method returns <FALSE/>, you cannot instantiate an EFormsHelper with
+ this document, since none of its functionality will be available then.
+ */
+ static bool
+ isEForm(
+ const css::uno::Reference< css::frame::XModel >& _rxContextDocument
+ );
+
+ /** registers a listener to be notified when any aspect of the binding changes.
+
+ The listener will be registered at the current binding of the control model. If the binding
+ changes (see <method>setBinding</method>), the listener will be revoked from the old binding,
+ registered at the new binding, and for all properties which differ between both bindings,
+ the listener will be notified.
+ @see revokeBindingListener
+ */
+ void registerBindingListener(
+ const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxBindingListener
+ );
+
+ /** revokes the binding listener which has previously been registered
+ @see registerBindingListener
+ */
+ void revokeBindingListener(
+ const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxBindingListener
+ );
+
+ /** checks whether it's possible to bind the control model to a given XSD data type
+
+ @param _nDataType
+ the data type which should be bound. If this is -1, <TRUE/> is returned if the control model
+ can be bound to <em>any</em> data type.
+ */
+ bool canBindToDataType( sal_Int32 _nDataType = -1 ) const;
+
+ /** checks whether the control model can be bound to any XSD data type
+ */
+ bool canBindToAnyDataType() const { return canBindToDataType(); }
+
+ /** checks whether the control model is a source for list entries, as supplied by XML data bindings
+ */
+ bool isListEntrySink() const;
+
+ /** retrieves the names of all XForms models in the document the control lives in
+ */
+ void getFormModelNames( std::vector< OUString >& /* [out] */ _rModelNames ) const;
+
+ /** retrieves the names of all bindings for a given model
+ @see getFormModelNames
+ */
+ void getBindingNames( const OUString& _rModelName, std::vector< OUString >& /* [out] */ _rBindingNames ) const;
+
+ /// retrieves the XForms model (within the control model's document) with the given name
+ css::uno::Reference< css::xforms::XModel >
+ getFormModelByName( const OUString& _rModelName ) const;
+
+ /** retrieves the model which the active binding of the control model belongs to
+ */
+ css::uno::Reference< css::xforms::XModel >
+ getCurrentFormModel() const;
+
+ /** retrieves the name of the model which the active binding of the control model belongs to
+ */
+ OUString
+ getCurrentFormModelName() const;
+
+ /** retrieves the binding instance which is currently attached to the control model
+ */
+ css::uno::Reference< css::beans::XPropertySet >
+ getCurrentBinding() const;
+
+ /** retrieves the name of the binding instance which is currently attached to the control model
+ */
+ OUString
+ getCurrentBindingName() const;
+
+ /** sets a new binding at the control model
+ */
+ void setBinding( const css::uno::Reference< css::beans::XPropertySet >& _rxBinding );
+
+ /** retrieves the binding instance which is currently used as list source for the control model
+ @see isListEntrySink
+ */
+ css::uno::Reference< css::form::binding::XListEntrySource >
+ getCurrentListSourceBinding() const;
+
+ /** sets a new list source at the control model
+ @see isListEntrySink
+ */
+ void setListSourceBinding( const css::uno::Reference< css::form::binding::XListEntrySource >& _rxListSource );
+
+ /** retrieves a given binding for a given model, or creates a new one
+
+ @param _rTargetModel
+ the name of the model to create a binding for. Must not be empty
+ @param _rBindingName
+ the name of the binding to retrieve. If the model denoted by <arg>_rTargetModel</arg> does not
+ have a binding with this name, a new binding is created and returned.
+ */
+ css::uno::Reference< css::beans::XPropertySet >
+ getOrCreateBindingForModel( const OUString& _rTargetModel, const OUString& _rBindingName ) const;
+
+ /** types of sub-elements of a model
+ */
+ enum ModelElementType
+ {
+ Submission,
+ Binding
+ };
+
+ /** retrieves the name of a model's sub-element, as to be shown in the UI
+ @see getModelElementFromUIName
+ @see getAllElementUINames
+ */
+ static OUString
+ getModelElementUIName(
+ const ModelElementType _eType,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxElement
+ );
+
+ /** retrieves the submission object for an UI name
+
+ Note that <member>getAllElementUINames</member> must have been called before, for the given element type
+
+ @see getModelElementUIName
+ @see getAllElementUINames
+ */
+ css::uno::Reference< css::beans::XPropertySet >
+ getModelElementFromUIName(
+ const ModelElementType _eType,
+ const OUString& _rUIName
+ ) const;
+
+ /** retrieves the UI names of all elements of all models in our document
+ @param _eType
+ the type of elements for which the names should be retrieved
+ @param _rElementNames
+ the array of element names
+ @see getModelElementUIName
+ @see getModelElementFromUIName
+ */
+ void getAllElementUINames(
+ const ModelElementType _eType,
+ std::vector< OUString >& /* [out] */ _rElementNames,
+ bool _bPrepentEmptyEntry
+ );
+
+ protected:
+ void firePropertyChanges(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxOldProps,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxNewProps,
+ std::set< OUString >& _rFilter
+ ) const;
+
+ /** fires a change in a single property, if the property value changed, and if we have a listener
+ interested in property changes
+ */
+ void firePropertyChange(
+ const OUString& _rName,
+ const css::uno::Any& _rOldValue,
+ const css::uno::Any& _rNewValue
+ ) const;
+
+ private:
+ void impl_switchBindingListening_throw( bool _bDoListening, const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener );
+
+ /// implementation for both <member>getOrCreateBindingForModel</member>
+ css::uno::Reference< css::beans::XPropertySet >
+ implGetOrCreateBinding( const OUString& _rTargetModel, const OUString& _rBindingName ) const;
+
+ void
+ impl_toggleBindingPropertyListening_throw( bool _bDoListen, const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxConcreteListenerOrNull );
+
+ private:
+ EFormsHelper( const EFormsHelper& ) = delete;
+ EFormsHelper& operator=( const EFormsHelper& ) = delete;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/eformspropertyhandler.cxx b/extensions/source/propctrlr/eformspropertyhandler.cxx
new file mode 100644
index 000000000..42ca7ed1a
--- /dev/null
+++ b/extensions/source/propctrlr/eformspropertyhandler.cxx
@@ -0,0 +1,598 @@
+/* -*- 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 "eformspropertyhandler.hxx"
+#include "formstrings.hxx"
+#include "formmetadata.hxx"
+#include <propctrlr.h>
+#include "eformshelper.hxx"
+#include "handlerhelper.hxx"
+
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/inspection/PropertyControlType.hpp>
+#include <com/sun/star/inspection/XObjectInspectorUI.hpp>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::xforms;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::ui::dialogs;
+ using namespace ::com::sun::star::form::binding;
+ using namespace ::com::sun::star::inspection;
+
+
+ //= EFormsPropertyHandler
+
+
+ EFormsPropertyHandler::EFormsPropertyHandler( const Reference< XComponentContext >& _rxContext )
+ :PropertyHandlerComponent( _rxContext )
+ ,m_bSimulatingModelChange( false )
+ {
+ }
+
+
+ EFormsPropertyHandler::~EFormsPropertyHandler( )
+ {
+ }
+
+
+ OUString EFormsPropertyHandler::getImplementationName( )
+ {
+ return "com.sun.star.comp.extensions.EFormsPropertyHandler";
+ }
+
+
+ Sequence< OUString > EFormsPropertyHandler::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.form.inspection.XMLFormsPropertyHandler" };
+ }
+
+
+ OUString EFormsPropertyHandler::getModelNamePropertyValue() const
+ {
+ OUString sModelName = m_pHelper->getCurrentFormModelName();
+ if ( sModelName.isEmpty() )
+ sModelName = m_sBindingLessModelName;
+ return sModelName;
+ }
+
+
+ Any SAL_CALL EFormsPropertyHandler::getPropertyValue( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ OSL_ENSURE(
+ m_pHelper,
+ "EFormsPropertyHandler::getPropertyValue: we don't have any SupportedProperties!");
+ // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties
+
+ Any aReturn;
+ try
+ {
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_LIST_BINDING:
+ aReturn <<= m_pHelper->getCurrentListSourceBinding();
+ break;
+
+ case PROPERTY_ID_XML_DATA_MODEL:
+ aReturn <<= getModelNamePropertyValue();
+ break;
+
+ case PROPERTY_ID_BINDING_NAME:
+ aReturn <<= m_pHelper->getCurrentBindingName();
+ break;
+
+ case PROPERTY_ID_BIND_EXPRESSION:
+ case PROPERTY_ID_XSD_CONSTRAINT:
+ case PROPERTY_ID_XSD_CALCULATION:
+ case PROPERTY_ID_XSD_REQUIRED:
+ case PROPERTY_ID_XSD_RELEVANT:
+ case PROPERTY_ID_XSD_READONLY:
+ {
+ Reference< XPropertySet > xBindingProps( m_pHelper->getCurrentBinding() );
+ if ( xBindingProps.is() )
+ {
+ aReturn = xBindingProps->getPropertyValue( _rPropertyName );
+ DBG_ASSERT( aReturn.getValueType().equals( ::cppu::UnoType<OUString>::get() ),
+ "EFormsPropertyHandler::getPropertyValue: invalid BindingExpression value type!" );
+ }
+ else
+ aReturn <<= OUString();
+ }
+ break;
+
+ default:
+ OSL_FAIL( "EFormsPropertyHandler::getPropertyValue: cannot handle this property!" );
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsPropertyHandler::getPropertyValue: caught exception!"
+ "(have been asked for the \"" <<_rPropertyName << "\" property.)");
+ }
+ return aReturn;
+ }
+
+
+ void SAL_CALL EFormsPropertyHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ OSL_ENSURE(
+ m_pHelper,
+ "EFormsPropertyHandler::setPropertyValue: we don't have any SupportedProperties!");
+ // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties
+
+ try
+ {
+ Any aOldValue = getPropertyValue( _rPropertyName );
+
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_LIST_BINDING:
+ {
+ Reference< XListEntrySource > xSource;
+ OSL_VERIFY( _rValue >>= xSource );
+ m_pHelper->setListSourceBinding( xSource );
+ }
+ break;
+
+ case PROPERTY_ID_XML_DATA_MODEL:
+ {
+ OSL_VERIFY( _rValue >>= m_sBindingLessModelName );
+
+ // if the model changed, reset the binding to NULL
+ if ( m_pHelper->getCurrentFormModelName() != m_sBindingLessModelName )
+ {
+ OUString sOldBindingName = m_pHelper->getCurrentBindingName();
+ m_pHelper->setBinding( nullptr );
+ firePropertyChange( PROPERTY_BINDING_NAME, PROPERTY_ID_BINDING_NAME,
+ Any( sOldBindingName ), Any( OUString() ) );
+ }
+ }
+ break;
+
+ case PROPERTY_ID_BINDING_NAME:
+ {
+ OUString sNewBindingName;
+ OSL_VERIFY( _rValue >>= sNewBindingName );
+
+ bool bPreviouslyEmptyModel = !m_pHelper->getCurrentFormModel().is();
+
+ Reference< XPropertySet > xNewBinding;
+ if ( !sNewBindingName.isEmpty() )
+ // obtain the binding with this name, for the current model
+ xNewBinding = m_pHelper->getOrCreateBindingForModel( getModelNamePropertyValue(), sNewBindingName );
+
+ m_pHelper->setBinding( xNewBinding );
+
+ if ( bPreviouslyEmptyModel )
+ { // simulate a property change for the model property
+ // This is because we "simulate" the Model property by remembering the
+ // value ourself. Other instances might, however, not know this value,
+ // but prefer to retrieve it somewhere else - e.g. from the EFormsHelper
+
+ // The really correct solution would be if *all* property handlers
+ // obtain a "current property value" for *all* properties from a central
+ // instance. Then, handler A could ask it for the value of property
+ // X, and this request would be re-routed to handler B, which ultimately
+ // knows the current value.
+ // However, there's no such mechanism in place currently.
+ m_bSimulatingModelChange = true;
+ firePropertyChange( PROPERTY_XML_DATA_MODEL, PROPERTY_ID_XML_DATA_MODEL,
+ Any( OUString() ), Any( getModelNamePropertyValue() ) );
+ m_bSimulatingModelChange = false;
+ }
+ }
+ break;
+
+ case PROPERTY_ID_BIND_EXPRESSION:
+ {
+ Reference< XPropertySet > xBinding( m_pHelper->getCurrentBinding() );
+ OSL_ENSURE( xBinding.is(), "You should not reach this without an active binding!" );
+ if ( xBinding.is() )
+ xBinding->setPropertyValue( PROPERTY_BIND_EXPRESSION, _rValue );
+ }
+ break;
+
+ case PROPERTY_ID_XSD_REQUIRED:
+ case PROPERTY_ID_XSD_RELEVANT:
+ case PROPERTY_ID_XSD_READONLY:
+ case PROPERTY_ID_XSD_CONSTRAINT:
+ case PROPERTY_ID_XSD_CALCULATION:
+ {
+ Reference< XPropertySet > xBindingProps( m_pHelper->getCurrentBinding() );
+ DBG_ASSERT( xBindingProps.is(), "EFormsPropertyHandler::setPropertyValue: how can I set a property if there's no binding?" );
+ if ( xBindingProps.is() )
+ {
+ DBG_ASSERT( _rValue.getValueType().equals( ::cppu::UnoType<OUString>::get() ),
+ "EFormsPropertyHandler::setPropertyValue: invalid value type!" );
+ xBindingProps->setPropertyValue( _rPropertyName, _rValue );
+ }
+ }
+ break;
+
+ default:
+ OSL_FAIL( "EFormsPropertyHandler::setPropertyValue: cannot handle this property!" );
+ break;
+ }
+
+ impl_setContextDocumentModified_nothrow();
+
+ Any aNewValue( getPropertyValue( _rPropertyName ) );
+ firePropertyChange( _rPropertyName, nPropId, aOldValue, aNewValue );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsPropertyHandler::setPropertyValue" );
+ }
+ }
+
+
+ void EFormsPropertyHandler::onNewComponent()
+ {
+ PropertyHandlerComponent::onNewComponent();
+
+ Reference< frame::XModel > xDocument( impl_getContextDocument_nothrow() );
+ DBG_ASSERT( xDocument.is(), "EFormsPropertyHandler::onNewComponent: no document!" );
+ if ( EFormsHelper::isEForm( xDocument ) )
+ m_pHelper.reset( new EFormsHelper( m_aMutex, m_xComponent, xDocument ) );
+ else
+ m_pHelper.reset();
+ }
+
+
+ Sequence< Property > EFormsPropertyHandler::doDescribeSupportedProperties() const
+ {
+ std::vector< Property > aProperties;
+
+ if (m_pHelper)
+ {
+ if ( m_pHelper->canBindToAnyDataType() )
+ {
+ aProperties.reserve( 7 );
+ addStringPropertyDescription( aProperties, PROPERTY_XML_DATA_MODEL );
+ addStringPropertyDescription( aProperties, PROPERTY_BINDING_NAME );
+ addStringPropertyDescription( aProperties, PROPERTY_BIND_EXPRESSION );
+ addStringPropertyDescription( aProperties, PROPERTY_XSD_REQUIRED );
+ addStringPropertyDescription( aProperties, PROPERTY_XSD_RELEVANT );
+ addStringPropertyDescription( aProperties, PROPERTY_XSD_READONLY );
+ addStringPropertyDescription( aProperties, PROPERTY_XSD_CONSTRAINT );
+ addStringPropertyDescription( aProperties, PROPERTY_XSD_CALCULATION );
+ }
+ if ( m_pHelper->isListEntrySink() )
+ {
+ implAddPropertyDescription( aProperties, PROPERTY_LIST_BINDING,
+ cppu::UnoType<XListEntrySource>::get() );
+ }
+ }
+
+ if ( aProperties.empty() )
+ return Sequence< Property >();
+ return comphelper::containerToSequence(aProperties);
+ }
+
+
+ Any SAL_CALL EFormsPropertyHandler::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Any aReturn;
+
+ OSL_ENSURE(
+ m_pHelper,
+ "EFormsPropertyHandler::convertToPropertyValue: we have no SupportedProperties!");
+ if (!m_pHelper)
+ return aReturn;
+
+ PropertyId nPropId( m_pInfoService->getPropertyId( _rPropertyName ) );
+
+ OUString sControlValue;
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_LIST_BINDING:
+ {
+ OSL_VERIFY( _rControlValue >>= sControlValue );
+ Reference< XListEntrySource > xListSource( m_pHelper->getModelElementFromUIName( EFormsHelper::Binding, sControlValue ), UNO_QUERY );
+ OSL_ENSURE( xListSource.is() || !m_pHelper->getModelElementFromUIName( EFormsHelper::Binding, sControlValue ).is(),
+ "EFormsPropertyHandler::convertToPropertyValue: there's a binding which is no ListEntrySource!" );
+ aReturn <<= xListSource;
+ }
+ break;
+
+ default:
+ aReturn = PropertyHandlerComponent::convertToPropertyValue( _rPropertyName, _rControlValue );
+ break;
+ }
+
+ return aReturn;
+ }
+
+
+ Any SAL_CALL EFormsPropertyHandler::convertToControlValue( const OUString& _rPropertyName, const Any& _rPropertyValue, const Type& _rControlValueType )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Any aReturn;
+
+ OSL_ENSURE(m_pHelper,
+ "EFormsPropertyHandler::convertToControlValue: we have no SupportedProperties!");
+ if (!m_pHelper)
+ return aReturn;
+
+ PropertyId nPropId( m_pInfoService->getPropertyId( _rPropertyName ) );
+
+ OSL_ENSURE( _rControlValueType.getTypeClass() == TypeClass_STRING,
+ "EFormsPropertyHandler::convertToControlValue: all our controls should use strings for value exchange!" );
+
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_LIST_BINDING:
+ {
+ Reference< XPropertySet > xListSourceBinding( _rPropertyValue, UNO_QUERY );
+ if ( xListSourceBinding.is() )
+ aReturn <<= EFormsHelper::getModelElementUIName( EFormsHelper::Binding, xListSourceBinding );
+ }
+ break;
+
+ default:
+ aReturn = PropertyHandlerComponent::convertToControlValue( _rPropertyName, _rPropertyValue, _rControlValueType );
+ break;
+ }
+
+ return aReturn;
+ }
+
+
+ Sequence< OUString > SAL_CALL EFormsPropertyHandler::getActuatingProperties( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (!m_pHelper)
+ return Sequence< OUString >();
+
+ std::vector< OUString > aInterestedInActuations( 2 );
+ aInterestedInActuations[ 0 ] = PROPERTY_XML_DATA_MODEL;
+ aInterestedInActuations[ 1 ] = PROPERTY_BINDING_NAME;
+ return comphelper::containerToSequence(aInterestedInActuations);
+ }
+
+
+ Sequence< OUString > SAL_CALL EFormsPropertyHandler::getSupersededProperties( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (!m_pHelper)
+ return Sequence< OUString >();
+
+ Sequence<OUString> aReturn { PROPERTY_INPUT_REQUIRED };
+ return aReturn;
+ }
+
+ LineDescriptor SAL_CALL EFormsPropertyHandler::describePropertyLine( const OUString& _rPropertyName,
+ const Reference< XPropertyControlFactory >& _rxControlFactory )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !_rxControlFactory.is() )
+ throw NullPointerException();
+ if (!m_pHelper)
+ throw RuntimeException();
+
+ LineDescriptor aDescriptor;
+ sal_Int16 nControlType = PropertyControlType::TextField;
+ std::vector< OUString > aListEntries;
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_LIST_BINDING:
+ nControlType = PropertyControlType::ListBox;
+ m_pHelper->getAllElementUINames(EFormsHelper::Binding, aListEntries, true);
+ break;
+
+ case PROPERTY_ID_XML_DATA_MODEL:
+ nControlType = PropertyControlType::ListBox;
+ m_pHelper->getFormModelNames( aListEntries );
+ break;
+
+ case PROPERTY_ID_BINDING_NAME:
+ {
+ nControlType = PropertyControlType::ComboBox;
+ OUString sCurrentModel( getModelNamePropertyValue() );
+ if ( !sCurrentModel.isEmpty() )
+ m_pHelper->getBindingNames( sCurrentModel, aListEntries );
+ }
+ break;
+
+ case PROPERTY_ID_BIND_EXPRESSION: aDescriptor.PrimaryButtonId = UID_PROP_DLG_BIND_EXPRESSION; break;
+ case PROPERTY_ID_XSD_REQUIRED: aDescriptor.PrimaryButtonId = UID_PROP_DLG_XSD_REQUIRED; break;
+ case PROPERTY_ID_XSD_RELEVANT: aDescriptor.PrimaryButtonId = UID_PROP_DLG_XSD_RELEVANT; break;
+ case PROPERTY_ID_XSD_READONLY: aDescriptor.PrimaryButtonId = UID_PROP_DLG_XSD_READONLY; break;
+ case PROPERTY_ID_XSD_CONSTRAINT: aDescriptor.PrimaryButtonId = UID_PROP_DLG_XSD_CONSTRAINT; break;
+ case PROPERTY_ID_XSD_CALCULATION: aDescriptor.PrimaryButtonId = UID_PROP_DLG_XSD_CALCULATION; break;
+
+ default:
+ OSL_FAIL( "EFormsPropertyHandler::describePropertyLine: cannot handle this property!" );
+ break;
+ }
+
+ switch ( nControlType )
+ {
+ case PropertyControlType::ListBox:
+ aDescriptor.Control = PropertyHandlerHelper::createListBoxControl( _rxControlFactory, std::move(aListEntries), false, true );
+ break;
+ case PropertyControlType::ComboBox:
+ aDescriptor.Control = PropertyHandlerHelper::createComboBoxControl( _rxControlFactory, std::move(aListEntries), true );
+ break;
+ default:
+ aDescriptor.Control = _rxControlFactory->createPropertyControl( nControlType, false );
+ break;
+ }
+
+ aDescriptor.DisplayName = m_pInfoService->getPropertyTranslation( nPropId );
+ aDescriptor.Category = "Data";
+ aDescriptor.HelpURL = HelpIdUrl::getHelpURL( m_pInfoService->getPropertyHelpId( nPropId ) );
+ return aDescriptor;
+ }
+
+ InteractiveSelectionResult SAL_CALL EFormsPropertyHandler::onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool /*_bPrimary*/, Any& _rData, const Reference< XObjectInspectorUI >& _rxInspectorUI )
+ {
+ if ( !_rxInspectorUI.is() )
+ throw NullPointerException();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OSL_ENSURE(m_pHelper, "EFormsPropertyHandler::onInteractivePropertySelection: we do not "
+ "have any SupportedProperties!");
+ if (!m_pHelper)
+ return InteractiveSelectionResult_Cancelled;
+
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+ OSL_ENSURE( ( PROPERTY_ID_BINDING_NAME == nPropId )
+ || ( PROPERTY_ID_BIND_EXPRESSION == nPropId )
+ || ( PROPERTY_ID_XSD_REQUIRED == nPropId )
+ || ( PROPERTY_ID_XSD_RELEVANT == nPropId )
+ || ( PROPERTY_ID_XSD_READONLY == nPropId )
+ || ( PROPERTY_ID_XSD_CONSTRAINT == nPropId )
+ || ( PROPERTY_ID_XSD_CALCULATION == nPropId ), "EFormsPropertyHandler::onInteractivePropertySelection: unexpected!" );
+
+ try
+ {
+ Reference< XExecutableDialog > xDialog;
+ xDialog.set( m_xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.xforms.ui.dialogs.AddCondition", m_xContext ), UNO_QUERY );
+ Reference< XPropertySet > xDialogProps( xDialog, UNO_QUERY_THROW );
+
+ // the model for the dialog to work with
+ Reference< xforms::XModel > xModel( m_pHelper->getCurrentFormModel() );
+ // the binding for the dialog to work with
+ Reference< XPropertySet > xBinding( m_pHelper->getCurrentBinding() );
+ // the aspect of the binding which the dialog should modify
+ const OUString& sFacetName( _rPropertyName );
+
+ OSL_ENSURE( xModel.is() && xBinding.is() && !sFacetName.isEmpty(),
+ "EFormsPropertyHandler::onInteractivePropertySelection: something is missing for the dialog initialization!" );
+ if ( !xModel.is() || !xBinding.is() || sFacetName.isEmpty() )
+ return InteractiveSelectionResult_Cancelled;
+
+ xDialogProps->setPropertyValue("FormModel", Any( xModel ) );
+ xDialogProps->setPropertyValue("Binding", Any( xBinding ) );
+ xDialogProps->setPropertyValue("FacetName", Any( sFacetName ) );
+
+ if ( !xDialog->execute() )
+ // cancelled
+ return InteractiveSelectionResult_Cancelled;
+
+ _rData = xDialogProps->getPropertyValue("ConditionValue");
+ return InteractiveSelectionResult_ObtainedValue;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsPropertyHandler::onInteractivePropertySelection" );
+ }
+
+ // something went wrong here ...(but has been asserted already)
+ return InteractiveSelectionResult_Cancelled;
+ }
+
+
+ void SAL_CALL EFormsPropertyHandler::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyHandlerComponent::addPropertyChangeListener( _rxListener );
+ if (m_pHelper)
+ m_pHelper->registerBindingListener( _rxListener );
+ }
+
+
+ void SAL_CALL EFormsPropertyHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (m_pHelper)
+ m_pHelper->revokeBindingListener( _rxListener );
+ PropertyHandlerComponent::removePropertyChangeListener( _rxListener );
+ }
+
+
+ void SAL_CALL EFormsPropertyHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool )
+ {
+ if ( !_rxInspectorUI.is() )
+ throw NullPointerException();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nActuatingPropId( impl_getPropertyId_throwRuntime( _rActuatingPropertyName ) );
+ OSL_PRECOND(m_pHelper, "EFormsPropertyHandler::actuatingPropertyChanged: inconsistency!");
+ // if we survived impl_getPropertyId_throwRuntime, we should have a helper, since no helper implies no properties
+
+ DBG_ASSERT( _rxInspectorUI.is(), "EFormsPropertyHandler::actuatingPropertyChanged: invalid callback!" );
+ if ( !_rxInspectorUI.is() )
+ return;
+
+ switch ( nActuatingPropId )
+ {
+ case PROPERTY_ID_XML_DATA_MODEL:
+ {
+ if ( m_bSimulatingModelChange )
+ break;
+ OUString sDataModelName;
+ OSL_VERIFY( _rNewValue >>= sDataModelName );
+ bool bBoundToSomeModel = !sDataModelName.isEmpty();
+ _rxInspectorUI->rebuildPropertyUI( PROPERTY_BINDING_NAME );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_BINDING_NAME, bBoundToSomeModel );
+ [[fallthrough]];
+ }
+
+ case PROPERTY_ID_BINDING_NAME:
+ {
+ bool bHaveABinding = !m_pHelper->getCurrentBindingName().isEmpty();
+ _rxInspectorUI->enablePropertyUI( PROPERTY_BIND_EXPRESSION, bHaveABinding );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_XSD_REQUIRED, bHaveABinding );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_XSD_RELEVANT, bHaveABinding );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_XSD_READONLY, bHaveABinding );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_XSD_CONSTRAINT, bHaveABinding );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_XSD_CALCULATION, bHaveABinding );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_XSD_DATA_TYPE, bHaveABinding );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "EFormsPropertyHandler::actuatingPropertyChanged: cannot handle this property!" );
+ break;
+ }
+ }
+
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_EFormsPropertyHandler_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::EFormsPropertyHandler(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/eformspropertyhandler.hxx b/extensions/source/propctrlr/eformspropertyhandler.hxx
new file mode 100644
index 000000000..8945c24f4
--- /dev/null
+++ b/extensions/source/propctrlr/eformspropertyhandler.hxx
@@ -0,0 +1,95 @@
+/* -*- 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 "propertyhandler.hxx"
+
+#include <memory>
+
+
+namespace pcr
+{
+
+
+ class EFormsHelper;
+
+ //= EFormsPropertyHandler
+
+ class EFormsPropertyHandler;
+ class EFormsPropertyHandler : public PropertyHandlerComponent
+ {
+ private:
+ std::unique_ptr< EFormsHelper > m_pHelper;
+ /** current value of the Model property, if there is no binding, yet
+ */
+ OUString m_sBindingLessModelName;
+ /** are we currently simulating a propertyChange event of the Model property?
+ */
+ bool m_bSimulatingModelChange;
+
+ public:
+ explicit EFormsPropertyHandler(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext
+ );
+
+ protected:
+ virtual ~EFormsPropertyHandler() override;
+
+ protected:
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override;
+
+ // XPropertyHandler overriables
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override;
+ virtual css::uno::Sequence< OUString >
+ SAL_CALL getActuatingProperties( ) override;
+ virtual css::uno::Sequence< OUString >
+ SAL_CALL getSupersededProperties( ) override;
+ virtual css::inspection::LineDescriptor
+ SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override;
+ virtual css::inspection::InteractiveSelectionResult
+ SAL_CALL onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, css::uno::Any& _rData, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) override;
+ virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool ) override;
+ virtual css::uno::Any SAL_CALL convertToPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rControlValue ) override;
+ virtual css::uno::Any SAL_CALL convertToControlValue( const OUString& _rPropertyName, const css::uno::Any& _rPropertyValue, const css::uno::Type& _rControlValueType ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+
+ // PropertyHandler overridables
+ virtual css::uno::Sequence< css::beans::Property >
+ doDescribeSupportedProperties() const override;
+ virtual void onNewComponent() override;
+
+ protected:
+ /** returns the value of the PROPERTY_XML_DATA_MODEL property.
+
+ An extra method is necessary here, which respects both the value set at our helper,
+ and <member>m_sBindingLessModelName</member>
+ */
+ OUString getModelNamePropertyValue() const;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/enumrepresentation.hxx b/extensions/source/propctrlr/enumrepresentation.hxx
new file mode 100644
index 000000000..b3ba04c9a
--- /dev/null
+++ b/extensions/source/propctrlr/enumrepresentation.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 <com/sun/star/uno/Any.hxx>
+#include <rtl/ustring.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+
+#include <vector>
+
+
+namespace pcr
+{
+
+
+ //= IPropertyEnumRepresentation
+
+ class SAL_NO_VTABLE IPropertyEnumRepresentation : public salhelper::SimpleReferenceObject
+ {
+ public:
+ /** retrieves all descriptions of all possible values of the enumeration property
+ */
+ virtual std::vector< OUString > getDescriptions(
+ ) const = 0;
+
+ /** converts a given description into a property value
+ */
+ virtual void getValueFromDescription(
+ const OUString& _rDescription,
+ css::uno::Any& _out_rValue
+ ) const = 0;
+
+ /** converts a given property value into a description
+ */
+ virtual OUString getDescriptionForValue(
+ const css::uno::Any& _rEnumValue
+ ) const = 0;
+
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/eventhandler.cxx b/extensions/source/propctrlr/eventhandler.cxx
new file mode 100644
index 000000000..d07f524bf
--- /dev/null
+++ b/extensions/source/propctrlr/eventhandler.cxx
@@ -0,0 +1,1112 @@
+/* -*- 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 "eventhandler.hxx"
+#include <helpids.h>
+#include <propctrlr.h>
+#include "formbrowsertools.hxx"
+#include <strings.hrc>
+#include "formstrings.hxx"
+#include "handlerhelper.hxx"
+#include "modulepcr.hxx"
+#include "pcrcommon.hxx"
+#include "propertycontrolextender.hxx"
+
+#include <com/sun/star/awt/XTabControllerModel.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/UnknownPropertyException.hpp>
+#include <com/sun/star/beans/theIntrospection.hpp>
+#include <com/sun/star/beans/XIntrospectionAccess.hpp>
+#include <com/sun/star/container/NoSuchElementException.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/container/XNameReplace.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/form/runtime/FormController.hpp>
+#include <com/sun/star/inspection/PropertyControlType.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/script/XEventAttacherManager.hpp>
+#include <com/sun/star/script/XScriptEventsSupplier.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <com/sun/star/uri/XVndSunStarScriptUrlReference.hpp>
+
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/evtmethodhelper.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <svx/svxdlg.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <map>
+#include <algorithm>
+#include <iterator>
+#include <string_view>
+
+namespace pcr
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::TypeClass_STRING;
+ using ::com::sun::star::uno::Type;
+ using ::com::sun::star::beans::theIntrospection;
+ using ::com::sun::star::beans::XPropertyChangeListener;
+ using ::com::sun::star::beans::Property;
+ using ::com::sun::star::beans::PropertyState;
+ using ::com::sun::star::beans::PropertyState_DIRECT_VALUE;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::script::ScriptEventDescriptor;
+ using ::com::sun::star::script::XScriptEventsSupplier;
+ using ::com::sun::star::lang::NullPointerException;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::container::XChild;
+ using ::com::sun::star::container::XIndexAccess;
+ using ::com::sun::star::script::XEventAttacherManager;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::beans::XIntrospection;
+ using ::com::sun::star::beans::XIntrospectionAccess;
+ using ::com::sun::star::container::XNameContainer;
+ using ::com::sun::star::awt::XTabControllerModel;
+ using ::com::sun::star::form::XForm;
+ using ::com::sun::star::form::runtime::FormController;
+ using ::com::sun::star::form::runtime::XFormController;
+ using ::com::sun::star::beans::UnknownPropertyException;
+ using ::com::sun::star::container::NoSuchElementException;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::container::XNameReplace;
+ using ::com::sun::star::beans::PropertyValue;
+ using ::com::sun::star::inspection::LineDescriptor;
+ using ::com::sun::star::inspection::XPropertyControlFactory;
+ using ::com::sun::star::inspection::InteractiveSelectionResult;
+ using ::com::sun::star::inspection::InteractiveSelectionResult_Cancelled;
+ using ::com::sun::star::inspection::InteractiveSelectionResult_Success;
+ using ::com::sun::star::inspection::XObjectInspectorUI;
+ using ::com::sun::star::beans::PropertyChangeEvent;
+ using ::com::sun::star::frame::XFrame;
+ using ::com::sun::star::frame::XModel;
+ using ::com::sun::star::frame::XController;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using com::sun::star::uri::UriReferenceFactory;
+ using com::sun::star::uri::XUriReferenceFactory;
+ using com::sun::star::uri::XVndSunStarScriptUrlReference;
+ using ::com::sun::star::lang::XEventListener;
+
+ namespace PropertyControlType = css::inspection::PropertyControlType;
+ namespace PropertyAttribute = css::beans::PropertyAttribute;
+ namespace FormComponentType = css::form::FormComponentType;
+
+ EventDescription::EventDescription( EventId _nId, const char* _pListenerNamespaceAscii, const char* _pListenerClassAsciiName,
+ const char* _pListenerMethodAsciiName, TranslateId pDisplayNameResId, const OUString& _sHelpId, const OString& _sUniqueBrowseId )
+ :sDisplayName(PcrRes( pDisplayNameResId ))
+ ,sListenerMethodName( OUString::createFromAscii( _pListenerMethodAsciiName ) )
+ ,sHelpId( _sHelpId )
+ ,sUniqueBrowseId( _sUniqueBrowseId )
+ ,nId( _nId )
+ {
+ OUStringBuffer aQualifiedListenerClass;
+ aQualifiedListenerClass.append( "com.sun.star." );
+ aQualifiedListenerClass.appendAscii( _pListenerNamespaceAscii );
+ aQualifiedListenerClass.append( "." );
+ aQualifiedListenerClass.appendAscii( _pListenerClassAsciiName );
+ sListenerClassName = aQualifiedListenerClass.makeStringAndClear();
+ }
+
+ namespace
+ {
+ #define DESCRIBE_EVENT( map, asciinamespace, asciilistener, asciimethod, id_postfix ) \
+ map.emplace( \
+ asciimethod, \
+ EventDescription( ++nEventId, asciinamespace, asciilistener, asciimethod, RID_STR_EVT_##id_postfix, HID_EVT_##id_postfix, UID_BRWEVT_##id_postfix ) )
+
+ bool lcl_getEventDescriptionForMethod( const OUString& _rMethodName, EventDescription& _out_rDescription )
+ {
+ static EventMap s_aKnownEvents = []() {
+ EventMap aMap;
+ sal_Int32 nEventId = 0;
+
+ DESCRIBE_EVENT(aMap, "form", "XApproveActionListener", "approveAction", APPROVEACTIONPERFORMED);
+ DESCRIBE_EVENT(aMap, "awt", "XActionListener", "actionPerformed", ACTIONPERFORMED);
+ DESCRIBE_EVENT(aMap, "form", "XChangeListener", "changed", CHANGED);
+ DESCRIBE_EVENT(aMap, "awt", "XTextListener", "textChanged", TEXTCHANGED);
+ DESCRIBE_EVENT(aMap, "awt", "XItemListener", "itemStateChanged", ITEMSTATECHANGED);
+ DESCRIBE_EVENT(aMap, "awt", "XFocusListener", "focusGained", FOCUSGAINED);
+ DESCRIBE_EVENT(aMap, "awt", "XFocusListener", "focusLost", FOCUSLOST);
+ DESCRIBE_EVENT(aMap, "awt", "XKeyListener", "keyPressed", KEYTYPED);
+ DESCRIBE_EVENT(aMap, "awt", "XKeyListener", "keyReleased", KEYUP);
+ DESCRIBE_EVENT(aMap, "awt", "XMouseListener", "mouseEntered", MOUSEENTERED);
+ DESCRIBE_EVENT(aMap, "awt", "XMouseMotionListener", "mouseDragged", MOUSEDRAGGED);
+ DESCRIBE_EVENT(aMap, "awt", "XMouseMotionListener", "mouseMoved", MOUSEMOVED);
+ DESCRIBE_EVENT(aMap, "awt", "XMouseListener", "mousePressed", MOUSEPRESSED);
+ DESCRIBE_EVENT(aMap, "awt", "XMouseListener", "mouseReleased", MOUSERELEASED);
+ DESCRIBE_EVENT(aMap, "awt", "XMouseListener", "mouseExited", MOUSEEXITED);
+ DESCRIBE_EVENT(aMap, "form", "XResetListener", "approveReset", APPROVERESETTED);
+ DESCRIBE_EVENT(aMap, "form", "XResetListener", "resetted", RESETTED);
+ DESCRIBE_EVENT(aMap, "form", "XSubmitListener", "approveSubmit", SUBMITTED);
+ DESCRIBE_EVENT(aMap, "form", "XUpdateListener", "approveUpdate", BEFOREUPDATE);
+ DESCRIBE_EVENT(aMap, "form", "XUpdateListener", "updated", AFTERUPDATE);
+ DESCRIBE_EVENT(aMap, "form", "XLoadListener", "loaded", LOADED);
+ DESCRIBE_EVENT(aMap, "form", "XLoadListener", "reloading", RELOADING);
+ DESCRIBE_EVENT(aMap, "form", "XLoadListener", "reloaded", RELOADED);
+ DESCRIBE_EVENT(aMap, "form", "XLoadListener", "unloading", UNLOADING);
+ DESCRIBE_EVENT(aMap, "form", "XLoadListener", "unloaded", UNLOADED);
+ DESCRIBE_EVENT(aMap, "form", "XConfirmDeleteListener", "confirmDelete", CONFIRMDELETE);
+ DESCRIBE_EVENT(aMap, "sdb", "XRowSetApproveListener", "approveRowChange", APPROVEROWCHANGE);
+ DESCRIBE_EVENT(aMap, "sdbc", "XRowSetListener", "rowChanged", ROWCHANGE);
+ DESCRIBE_EVENT(aMap, "sdb", "XRowSetApproveListener", "approveCursorMove", POSITIONING);
+ DESCRIBE_EVENT(aMap, "sdbc", "XRowSetListener", "cursorMoved", POSITIONED);
+ DESCRIBE_EVENT(aMap, "form", "XDatabaseParameterListener", "approveParameter", APPROVEPARAMETER);
+ DESCRIBE_EVENT(aMap, "sdb", "XSQLErrorListener", "errorOccured", ERROROCCURRED);
+ DESCRIBE_EVENT(aMap, "awt", "XAdjustmentListener", "adjustmentValueChanged", ADJUSTMENTVALUECHANGED);
+
+ return aMap;
+ }();
+
+ EventMap::const_iterator pos = s_aKnownEvents.find( _rMethodName );
+ if ( pos == s_aKnownEvents.end() )
+ return false;
+
+ _out_rDescription = pos->second;
+ return true;
+ }
+
+ OUString lcl_getEventPropertyName( std::u16string_view _rListenerClassName, std::u16string_view _rMethodName )
+ {
+ return _rListenerClassName + OUStringChar(';') + _rMethodName;
+ }
+
+ ScriptEventDescriptor lcl_getAssignedScriptEvent( const EventDescription& _rEvent, const std::vector< ScriptEventDescriptor >& _rAllAssignedMacros )
+ {
+ ScriptEventDescriptor aScriptEvent;
+ // for the case there is actually no event assigned, initialize at least ListenerType and MethodName,
+ // so this ScriptEventDescriptor properly describes the given event
+ aScriptEvent.ListenerType = _rEvent.sListenerClassName;
+ aScriptEvent.EventMethod = _rEvent.sListenerMethodName;
+
+ for ( const ScriptEventDescriptor& rSED : _rAllAssignedMacros )
+ {
+ if ( rSED.ListenerType != _rEvent.sListenerClassName
+ || rSED.EventMethod != _rEvent.sListenerMethodName
+ )
+ continue;
+
+ if ( rSED.ScriptCode.isEmpty()
+ || rSED.ScriptType.isEmpty()
+ )
+ {
+ OSL_FAIL( "lcl_getAssignedScriptEvent: me thinks this should not happen!" );
+ continue;
+ }
+
+ aScriptEvent = rSED;
+
+ if ( aScriptEvent.ScriptType != "StarBasic" )
+ continue;
+
+ // this is an old-style macro specification:
+ // [document|application]:Library.Module.Function
+ // we need to translate this to the new-style macro specification
+ // vnd.sun.star.script:Library.Module.Function?language=Basic&location=[document|application]
+
+ sal_Int32 nPrefixLen = aScriptEvent.ScriptCode.indexOf( ':' );
+ OSL_ENSURE( nPrefixLen > 0, "lcl_getAssignedScriptEvent: illegal location!" );
+ std::u16string_view sLocation = aScriptEvent.ScriptCode.subView( 0, nPrefixLen );
+ std::u16string_view sMacroPath = aScriptEvent.ScriptCode.subView( nPrefixLen + 1 );
+
+ aScriptEvent.ScriptCode =
+ OUString::Concat("vnd.sun.star.script:") +
+ sMacroPath +
+ "?language=Basic&location=" +
+ sLocation;
+
+ // also, this new-style spec requires the script code to be "Script" instead of "StarBasic"
+ aScriptEvent.ScriptType = "Script";
+ }
+ return aScriptEvent;
+ }
+
+ OUString lcl_getQualifiedKnownListenerName( const ScriptEventDescriptor& _rFormComponentEventDescriptor )
+ {
+ EventDescription aKnownEvent;
+ if ( lcl_getEventDescriptionForMethod( _rFormComponentEventDescriptor.EventMethod, aKnownEvent ) )
+ return aKnownEvent.sListenerClassName;
+ OSL_FAIL( "lcl_getQualifiedKnownListenerName: unknown method name!" );
+ // somebody assigned an script to a form component event which we don't know
+ // Speaking strictly, this is not really an error - it is possible to do
+ // this programmatically -, but it should rarely happen, since it's not possible
+ // via UI
+ return _rFormComponentEventDescriptor.ListenerType;
+ }
+
+ typedef std::set< Type, TypeLessByName > TypeBag;
+
+ void lcl_addListenerTypesFor_throw( const Reference< XInterface >& _rxComponent,
+ const Reference< XIntrospection >& _rxIntrospection, TypeBag& _out_rTypes )
+ {
+ if ( !_rxComponent.is() )
+ return;
+ OSL_PRECOND( _rxIntrospection.is(), "lcl_addListenerTypesFor_throw: this will crash!" );
+
+ Reference< XIntrospectionAccess > xIntrospectionAccess(
+ _rxIntrospection->inspect( Any( _rxComponent ) ), UNO_SET_THROW );
+
+ const Sequence< Type > aListeners( xIntrospectionAccess->getSupportedListeners() );
+
+ std::copy( aListeners.begin(), aListeners.end(),
+ std::insert_iterator< TypeBag >( _out_rTypes, _out_rTypes.begin() ) );
+ }
+ }
+
+ typedef ::cppu::WeakImplHelper < css::container::XNameReplace
+ > EventHolder_Base;
+
+ namespace {
+
+ /* A UNO component holding assigned event descriptions, for use with a SvxMacroAssignDlg */
+ class EventHolder : public EventHolder_Base
+ {
+ private:
+ typedef std::unordered_map< OUString, ScriptEventDescriptor > EventMap;
+ typedef std::map< EventId, OUString > EventMapIndexAccess;
+
+ EventMap m_aEventNameAccess;
+ EventMapIndexAccess m_aEventIndexAccess;
+
+ public:
+ EventHolder( );
+
+ void addEvent( EventId _nId, const OUString& _rEventName, const ScriptEventDescriptor& _rScriptEvent );
+
+ /** effectively the same as getByName, but instead of converting the ScriptEventDescriptor to the weird
+ format used by the macro assignment dialog, it is returned directly
+ */
+ ScriptEventDescriptor getNormalizedDescriptorByName( const OUString& _rEventName ) const;
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& _rName, const Any& aElement ) override;
+ virtual Any SAL_CALL getByName( const OUString& _rName ) override;
+ virtual Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& _rName ) override;
+ virtual Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+ protected:
+ virtual ~EventHolder( ) override;
+
+ private:
+ ScriptEventDescriptor const & impl_getDescriptor_throw( const OUString& _rEventName ) const;
+ };
+
+ }
+
+ EventHolder::EventHolder()
+ {
+ }
+
+ EventHolder::~EventHolder()
+ {
+ m_aEventNameAccess.clear();
+ m_aEventIndexAccess.clear();
+ }
+
+ void EventHolder::addEvent( EventId _nId, const OUString& _rEventName, const ScriptEventDescriptor& _rScriptEvent )
+ {
+ std::pair< EventMap::iterator, bool > insertionResult =
+ m_aEventNameAccess.emplace( _rEventName, _rScriptEvent );
+ OSL_ENSURE( insertionResult.second, "EventHolder::addEvent: there already was a MacroURL for this event!" );
+ m_aEventIndexAccess[ _nId ] = _rEventName;
+ }
+
+ ScriptEventDescriptor EventHolder::getNormalizedDescriptorByName( const OUString& _rEventName ) const
+ {
+ return impl_getDescriptor_throw( _rEventName );
+ }
+
+ ScriptEventDescriptor const & EventHolder::impl_getDescriptor_throw( const OUString& _rEventName ) const
+ {
+ EventMap::const_iterator pos = m_aEventNameAccess.find( _rEventName );
+ if ( pos == m_aEventNameAccess.end() )
+ throw NoSuchElementException( OUString(), *const_cast< EventHolder* >( this ) );
+ return pos->second;
+ }
+
+ void SAL_CALL EventHolder::replaceByName( const OUString& _rName, const Any& _rElement )
+ {
+ EventMap::iterator pos = m_aEventNameAccess.find( _rName );
+ if ( pos == m_aEventNameAccess.end() )
+ throw NoSuchElementException( OUString(), *this );
+
+ Sequence< PropertyValue > aScriptDescriptor;
+ OSL_VERIFY( _rElement >>= aScriptDescriptor );
+
+ ::comphelper::NamedValueCollection aExtractor( aScriptDescriptor );
+
+ pos->second.ScriptType = aExtractor.getOrDefault( "EventType", OUString() );
+ pos->second.ScriptCode = aExtractor.getOrDefault( "Script", OUString() );
+ }
+
+ Any SAL_CALL EventHolder::getByName( const OUString& _rName )
+ {
+ ScriptEventDescriptor aDescriptor( impl_getDescriptor_throw( _rName ) );
+
+ Sequence< PropertyValue > aScriptDescriptor{
+ comphelper::makePropertyValue("EventType", aDescriptor.ScriptType),
+ comphelper::makePropertyValue("Script", aDescriptor.ScriptCode)
+ };
+
+ return Any( aScriptDescriptor );
+ }
+
+ Sequence< OUString > SAL_CALL EventHolder::getElementNames( )
+ {
+ Sequence< OUString > aReturn( m_aEventIndexAccess.size() );
+ OUString* pReturn = aReturn.getArray();
+
+ // SvxMacroAssignDlg has a weird API: It expects a XNameReplace, means a container whose
+ // main access method is by name. In its UI, it shows the possible events in exactly the
+ // order in which XNameAccess::getElementNames returns them.
+ // However, SvxMacroAssignDlg *also* takes an index for the initial selection, which is
+ // relative to the sequence returned by XNameAccess::getElementNames.
+ // This is IMO weird, since it mixes index access with name access, which decreases efficiency
+ // of the implementation.
+ // Well, it means we're forced to return the events in getElementNames in exactly the same as they
+ // appear in the property browser UI.
+ for (auto const& elem : m_aEventIndexAccess)
+ {
+ *pReturn = elem.second;
+ ++pReturn;
+ }
+ return aReturn;
+ }
+
+ sal_Bool SAL_CALL EventHolder::hasByName( const OUString& _rName )
+ {
+ EventMap::const_iterator pos = m_aEventNameAccess.find( _rName );
+ return pos != m_aEventNameAccess.end();
+ }
+
+ Type SAL_CALL EventHolder::getElementType( )
+ {
+ return cppu::UnoType<Sequence< PropertyValue >>::get();
+ }
+
+ sal_Bool SAL_CALL EventHolder::hasElements( )
+ {
+ return !m_aEventNameAccess.empty();
+ }
+
+
+ EventHandler::EventHandler( const Reference< XComponentContext >& _rxContext )
+ :EventHandler_Base( m_aMutex )
+ ,m_xContext( _rxContext )
+ ,m_aPropertyListeners( m_aMutex )
+ ,m_bEventsMapInitialized( false )
+ ,m_bIsDialogElement( false )
+ ,m_nGridColumnType( -1 )
+ {
+ }
+
+ EventHandler::~EventHandler()
+ {
+ }
+
+ OUString SAL_CALL EventHandler::getImplementationName( )
+ {
+ return "com.sun.star.comp.extensions.EventHandler";
+ }
+
+ sal_Bool SAL_CALL EventHandler::supportsService( const OUString& ServiceName )
+ {
+ return cppu::supportsService(this, ServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL EventHandler::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.form.inspection.EventHandler" };
+ }
+
+ void SAL_CALL EventHandler::inspect( const Reference< XInterface >& _rxIntrospectee )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !_rxIntrospectee.is() )
+ throw NullPointerException();
+
+ m_xComponent.set( _rxIntrospectee, UNO_QUERY_THROW );
+
+ m_bEventsMapInitialized = false;
+ EventMap().swap(m_aEvents);
+
+ m_bIsDialogElement = false;
+ m_nGridColumnType = -1;
+ try
+ {
+ Reference< XPropertySetInfo > xPSI( m_xComponent->getPropertySetInfo() );
+ m_bIsDialogElement = xPSI.is()
+ && xPSI->hasPropertyByName( PROPERTY_WIDTH )
+ && xPSI->hasPropertyByName( PROPERTY_HEIGHT )
+ && xPSI->hasPropertyByName( PROPERTY_POSITIONX )
+ && xPSI->hasPropertyByName( PROPERTY_POSITIONY );
+
+ Reference< XChild > xAsChild( _rxIntrospectee, UNO_QUERY );
+ if ( xAsChild.is() && !Reference< XForm >( _rxIntrospectee, UNO_QUERY ).is() )
+ {
+ if ( FormComponentType::GRIDCONTROL == classifyComponent( xAsChild->getParent() ) )
+ {
+ m_nGridColumnType = classifyComponent( _rxIntrospectee );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+ Any SAL_CALL EventHandler::getPropertyValue( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ const EventDescription& rEvent = impl_getEventForName_throw( _rPropertyName );
+
+ std::vector< ScriptEventDescriptor > aEvents;
+ impl_getComponentScriptEvents_nothrow( aEvents );
+
+ ScriptEventDescriptor aPropertyValue;
+ for ( const ScriptEventDescriptor& rSCD : aEvents )
+ {
+ if ( rEvent.sListenerClassName == rSCD.ListenerType
+ && rEvent.sListenerMethodName == rSCD.EventMethod
+ )
+ {
+ aPropertyValue = rSCD;
+ break;
+ }
+ }
+
+ return Any( aPropertyValue );
+ }
+
+ void SAL_CALL EventHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ const EventDescription& rEvent = impl_getEventForName_throw( _rPropertyName );
+
+ ScriptEventDescriptor aNewScriptEvent;
+ OSL_VERIFY( _rValue >>= aNewScriptEvent );
+
+ ScriptEventDescriptor aOldScriptEvent;
+ OSL_VERIFY( getPropertyValue( _rPropertyName ) >>= aOldScriptEvent );
+ if ( aOldScriptEvent == aNewScriptEvent )
+ return;
+
+ if ( m_bIsDialogElement )
+ impl_setDialogElementScriptEvent_nothrow( aNewScriptEvent );
+ else
+ impl_setFormComponentScriptEvent_nothrow( aNewScriptEvent );
+
+ PropertyHandlerHelper::setContextDocumentModified( m_xContext );
+
+ PropertyChangeEvent aEvent;
+ aEvent.Source = m_xComponent;
+ aEvent.PropertyHandle = rEvent.nId;
+ aEvent.PropertyName = _rPropertyName;
+ aEvent.OldValue <<= aOldScriptEvent;
+ aEvent.NewValue <<= aNewScriptEvent;
+ m_aPropertyListeners.notifyEach( &XPropertyChangeListener::propertyChange, aEvent );
+ }
+
+ Any SAL_CALL EventHandler::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ OUString sNewScriptCode;
+ OSL_VERIFY( _rControlValue >>= sNewScriptCode );
+
+ std::vector< ScriptEventDescriptor > aAllAssignedEvents;
+ impl_getComponentScriptEvents_nothrow( aAllAssignedEvents );
+
+ const EventDescription& rEvent = impl_getEventForName_throw( _rPropertyName );
+ ScriptEventDescriptor aAssignedScript = lcl_getAssignedScriptEvent( rEvent, aAllAssignedEvents );
+
+ OSL_ENSURE( sNewScriptCode.isEmpty(), "EventHandler::convertToPropertyValue: cannot convert a non-empty display name!" );
+ // Usually, there is no possibility for the user to change the content of an event binding directly in the
+ // input field, this instead is done with the macro assignment dialog.
+ // The only exception is the user pressing "DEL" while the control has the focus, in this case, we reset the
+ // control content to an empty string. So this is the only scenario where this method is allowed to be called.
+
+ // Strictly, we would be able to convert the display value to a property value,
+ // using the "name (location, language)" format we used in convertToControlValue. However,
+ // there is no need for this code...
+
+ aAssignedScript.ScriptCode = sNewScriptCode;
+ return Any( aAssignedScript );
+ }
+
+ Any SAL_CALL EventHandler::convertToControlValue( const OUString& /*_rPropertyName*/, const Any& _rPropertyValue, const Type& _rControlValueType )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ ScriptEventDescriptor aScriptEvent;
+ OSL_VERIFY( _rPropertyValue >>= aScriptEvent );
+
+ OSL_ENSURE( _rControlValueType.getTypeClass() == TypeClass_STRING,
+ "EventHandler::convertToControlValue: unexpected ControlValue type class!" );
+
+ OUString sScript( aScriptEvent.ScriptCode );
+ if ( !sScript.isEmpty() )
+ {
+ // format is: "name (location, language)"
+ try
+ {
+ // parse
+ Reference< XUriReferenceFactory > xUriRefFac = UriReferenceFactory::create( m_xContext );
+ Reference< XVndSunStarScriptUrlReference > xScriptUri( xUriRefFac->parse( sScript ), UNO_QUERY_THROW );
+
+ OUStringBuffer aComposeBuffer;
+
+ // name
+ aComposeBuffer.append( xScriptUri->getName() );
+
+ // location
+ const OUString sLocation = xScriptUri->getParameter( "location" );
+ const OUString sLanguage = xScriptUri->getParameter( "language" );
+
+ if ( !(sLocation.isEmpty() && sLanguage.isEmpty()) )
+ {
+ aComposeBuffer.append( " (" );
+
+ // location
+ OSL_ENSURE( !sLocation.isEmpty(), "EventHandler::convertToControlValue: unexpected: no location!" );
+ if ( !sLocation.isEmpty() )
+ {
+ aComposeBuffer.append( sLocation );
+ aComposeBuffer.append( ", " );
+ }
+
+ // language
+ if ( !sLanguage.isEmpty() )
+ {
+ aComposeBuffer.append( sLanguage );
+ }
+
+ aComposeBuffer.append( ')' );
+ }
+
+ sScript = aComposeBuffer.makeStringAndClear();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+ return Any( sScript );
+ }
+
+ PropertyState SAL_CALL EventHandler::getPropertyState( const OUString& /*_rPropertyName*/ )
+ {
+ return PropertyState_DIRECT_VALUE;
+ }
+
+ void SAL_CALL EventHandler::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !_rxListener.is() )
+ throw NullPointerException();
+ m_aPropertyListeners.addInterface( _rxListener );
+ }
+
+ void SAL_CALL EventHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_aPropertyListeners.removeInterface( _rxListener );
+ }
+
+ Sequence< Property > SAL_CALL EventHandler::getSupportedProperties()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !m_bEventsMapInitialized )
+ {
+ m_bEventsMapInitialized = true;
+ try
+ {
+ std::vector< Type > aListeners;
+ impl_getComponentListenerTypes_nothrow( aListeners );
+
+ OUString sListenerClassName;
+
+ // loop through all listeners and all methods, and see which we can present at the UI
+ for ( const Type& rListener : aListeners )
+ {
+ // the programmatic name of the listener, to be used as "property" name
+ sListenerClassName = rListener.getTypeName();
+ OSL_ENSURE( !sListenerClassName.isEmpty(), "EventHandler::getSupportedProperties: strange - no listener name ..." );
+ if ( sListenerClassName.isEmpty() )
+ continue;
+
+ // loop through all methods
+ const Sequence<OUString> aEventMethods = comphelper::getEventMethodsForType( rListener );
+ for (const OUString& rMethod : aEventMethods)
+ {
+ EventDescription aEvent;
+ if ( !lcl_getEventDescriptionForMethod( rMethod, aEvent ) )
+ continue;
+
+ if ( !impl_filterMethod_nothrow( aEvent ) )
+ continue;
+
+ m_aEvents.emplace(
+ lcl_getEventPropertyName( sListenerClassName, rMethod ), aEvent );
+ }
+ }
+
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+ // sort them by ID - this is the relative ordering in the UI
+ std::map< EventId, Property > aOrderedProperties;
+ for (auto const& event : m_aEvents)
+ {
+ aOrderedProperties[ event.second.nId ] = Property(
+ event.first, event.second.nId,
+ ::cppu::UnoType<OUString>::get(),
+ PropertyAttribute::BOUND );
+ }
+
+ return comphelper::mapValuesToSequence( aOrderedProperties );
+ }
+
+ Sequence< OUString > SAL_CALL EventHandler::getSupersededProperties( )
+ {
+ // none
+ return Sequence< OUString >( );
+ }
+
+ Sequence< OUString > SAL_CALL EventHandler::getActuatingProperties( )
+ {
+ // none
+ return Sequence< OUString >( );
+ }
+
+ LineDescriptor SAL_CALL EventHandler::describePropertyLine( const OUString& _rPropertyName,
+ const Reference< XPropertyControlFactory >& _rxControlFactory )
+ {
+ if ( !_rxControlFactory.is() )
+ throw NullPointerException();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ LineDescriptor aDescriptor;
+
+ aDescriptor.Control = _rxControlFactory->createPropertyControl( PropertyControlType::TextField, true );
+ new PropertyControlExtender( aDescriptor.Control );
+
+ const EventDescription& rEvent = impl_getEventForName_throw( _rPropertyName );
+ aDescriptor.DisplayName = rEvent.sDisplayName;
+ aDescriptor.HelpURL = HelpIdUrl::getHelpURL( rEvent.sHelpId );
+ aDescriptor.PrimaryButtonId = OStringToOUString(rEvent.sUniqueBrowseId, RTL_TEXTENCODING_UTF8);
+ aDescriptor.HasPrimaryButton = true;
+ aDescriptor.Category = "Events";
+ return aDescriptor;
+ }
+
+ sal_Bool SAL_CALL EventHandler::isComposable( const OUString& /*_rPropertyName*/ )
+ {
+ return false;
+ }
+
+ InteractiveSelectionResult SAL_CALL EventHandler::onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool /*_bPrimary*/, Any& /*_rData*/, const Reference< XObjectInspectorUI >& _rxInspectorUI )
+ {
+ if ( !_rxInspectorUI.is() )
+ throw NullPointerException();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ const EventDescription& rForEvent = impl_getEventForName_throw( _rPropertyName );
+
+ std::vector< ScriptEventDescriptor > aAllAssignedEvents;
+ impl_getComponentScriptEvents_nothrow( aAllAssignedEvents );
+
+ // SvxMacroAssignDlg-compatible structure holding all event/assignments
+ ::rtl::Reference< EventHolder > pEventHolder( new EventHolder );
+
+ for (auto const& event : m_aEvents)
+ {
+ // the script which is assigned to the current event (if any)
+ ScriptEventDescriptor aAssignedScript = lcl_getAssignedScriptEvent( event.second, aAllAssignedEvents );
+ pEventHolder->addEvent( event.second.nId, event.second.sListenerMethodName, aAssignedScript );
+ }
+
+ // the initial selection in the dialog
+ const Sequence< OUString > aNames( pEventHolder->getElementNames() );
+ const OUString* pChosenEvent = std::find( aNames.begin(), aNames.end(), rForEvent.sListenerMethodName );
+ sal_uInt16 nInitialSelection = static_cast<sal_uInt16>( pChosenEvent - aNames.begin() );
+
+ // the dialog
+ SvxAbstractDialogFactory* pFactory = SvxAbstractDialogFactory::Create();
+
+ ScopedVclPtr<VclAbstractDialog> pDialog( pFactory->CreateSvxMacroAssignDlg(
+ PropertyHandlerHelper::getDialogParentFrame( m_xContext ),
+ impl_getContextFrame_nothrow(),
+ m_bIsDialogElement,
+ pEventHolder,
+ nInitialSelection
+ ) );
+
+ if ( !pDialog )
+ return InteractiveSelectionResult_Cancelled;
+
+ // DF definite problem here
+ // OK & Cancel seem to be both returning 0
+ if ( pDialog->Execute() == RET_CANCEL )
+ return InteractiveSelectionResult_Cancelled;
+
+ try
+ {
+ for (auto const& event : m_aEvents)
+ {
+ ScriptEventDescriptor aScriptDescriptor( pEventHolder->getNormalizedDescriptorByName( event.second.sListenerMethodName ) );
+
+ // set the new "property value"
+ setPropertyValue(
+ lcl_getEventPropertyName( event.second.sListenerClassName, event.second.sListenerMethodName ),
+ Any( aScriptDescriptor )
+ );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+
+ return InteractiveSelectionResult_Success;
+ }
+
+ void SAL_CALL EventHandler::actuatingPropertyChanged( const OUString& /*_rActuatingPropertyName*/, const Any& /*_rNewValue*/, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& /*_rxInspectorUI*/, sal_Bool /*_bFirstTimeInit*/ )
+ {
+ OSL_FAIL( "EventHandler::actuatingPropertyChanged: no actuating properties -> no callback (well, this is how it *should* be!)" );
+ }
+
+ IMPLEMENT_FORWARD_XCOMPONENT( EventHandler, EventHandler_Base )
+
+ void SAL_CALL EventHandler::disposing()
+ {
+ EventMap().swap(m_aEvents);
+ m_xComponent.clear();
+ }
+
+ sal_Bool SAL_CALL EventHandler::suspend( sal_Bool /*_bSuspend*/ )
+ {
+ return true;
+ }
+
+ Reference< XFrame > EventHandler::impl_getContextFrame_nothrow() const
+ {
+ Reference< XFrame > xContextFrame;
+
+ try
+ {
+ Reference< XModel > xContextDocument( PropertyHandlerHelper::getContextDocument(m_xContext), UNO_QUERY_THROW );
+ Reference< XController > xController( xContextDocument->getCurrentController(), UNO_SET_THROW );
+ xContextFrame.set( xController->getFrame(), UNO_SET_THROW );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+
+ return xContextFrame;
+ }
+
+ sal_Int32 EventHandler::impl_getComponentIndexInParent_throw() const
+ {
+ Reference< XChild > xChild( m_xComponent, UNO_QUERY_THROW );
+ Reference< XIndexAccess > xParentAsIndexAccess( xChild->getParent(), UNO_QUERY_THROW );
+
+ // get the index of the inspected object within its parent container
+ sal_Int32 nElements = xParentAsIndexAccess->getCount();
+ for ( sal_Int32 i=0; i<nElements; ++i )
+ {
+ Reference< XInterface > xElement( xParentAsIndexAccess->getByIndex( i ), UNO_QUERY_THROW );
+ if ( xElement == m_xComponent )
+ return i;
+ }
+ throw NoSuchElementException();
+ }
+
+ void EventHandler::impl_getFormComponentScriptEvents_nothrow( std::vector < ScriptEventDescriptor >& _out_rEvents ) const
+ {
+ _out_rEvents.clear();
+ try
+ {
+ Reference< XChild > xChild( m_xComponent, UNO_QUERY_THROW );
+ Reference< XEventAttacherManager > xEventManager( xChild->getParent(), UNO_QUERY_THROW );
+ comphelper::sequenceToContainer(_out_rEvents, xEventManager->getScriptEvents( impl_getComponentIndexInParent_throw() ));
+
+ // the form component script API has unqualified listener names, but for normalization
+ // purpose, we want fully qualified ones
+ for ( ScriptEventDescriptor& rSED : _out_rEvents)
+ {
+ rSED.ListenerType = lcl_getQualifiedKnownListenerName( rSED );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+ void EventHandler::impl_getComponentListenerTypes_nothrow( std::vector< Type >& _out_rTypes ) const
+ {
+ _out_rTypes.clear();
+ try
+ {
+ // we use a set to avoid duplicates
+ TypeBag aListeners;
+
+ Reference< XIntrospection > xIntrospection = theIntrospection::get( m_xContext );
+
+ // --- model listeners
+ lcl_addListenerTypesFor_throw(
+ m_xComponent, xIntrospection, aListeners );
+
+ // --- "secondary component" (usually: "control" listeners)
+ {
+ Reference< XInterface > xSecondaryComponent( impl_getSecondaryComponentForEventInspection_throw() );
+ lcl_addListenerTypesFor_throw( xSecondaryComponent, xIntrospection, aListeners );
+ ::comphelper::disposeComponent( xSecondaryComponent );
+ }
+
+ // now that they're disambiguated, copy these types into our member
+ _out_rTypes.insert( _out_rTypes.end(), aListeners.begin(), aListeners.end() );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+ void EventHandler::impl_getDialogElementScriptEvents_nothrow( std::vector < ScriptEventDescriptor >& _out_rEvents ) const
+ {
+ _out_rEvents.clear();
+ try
+ {
+ Reference< XScriptEventsSupplier > xEventsSupplier( m_xComponent, UNO_QUERY_THROW );
+ Reference< XNameContainer > xEvents( xEventsSupplier->getEvents(), UNO_SET_THROW );
+ Sequence< OUString > aEventNames( xEvents->getElementNames() );
+
+ sal_Int32 nEventCount = aEventNames.getLength();
+ _out_rEvents.resize( nEventCount );
+
+ for( sal_Int32 i = 0; i < nEventCount; ++i )
+ OSL_VERIFY( xEvents->getByName( aEventNames[i] ) >>= _out_rEvents[i] );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+ Reference< XInterface > EventHandler::impl_getSecondaryComponentForEventInspection_throw( ) const
+ {
+ Reference< XInterface > xReturn;
+
+ // if it's a form, create a form controller for the additional events
+ Reference< XForm > xComponentAsForm( m_xComponent, UNO_QUERY );
+ if ( xComponentAsForm.is() )
+ {
+ Reference< XTabControllerModel > xComponentAsTCModel( m_xComponent, UNO_QUERY_THROW );
+ Reference< XFormController > xController = FormController::create( m_xContext );
+ xController->setModel( xComponentAsTCModel );
+
+ xReturn = xController;
+ }
+ else
+ {
+ OUString sControlService;
+ OSL_VERIFY( m_xComponent->getPropertyValue( PROPERTY_DEFAULTCONTROL ) >>= sControlService );
+
+ xReturn = m_xContext->getServiceManager()->createInstanceWithContext( sControlService, m_xContext );
+ }
+ return xReturn;
+ }
+
+ const EventDescription& EventHandler::impl_getEventForName_throw( const OUString& _rPropertyName ) const
+ {
+ EventMap::const_iterator pos = m_aEvents.find( _rPropertyName );
+ if ( pos == m_aEvents.end() )
+ throw UnknownPropertyException(_rPropertyName);
+ return pos->second;
+ }
+
+ namespace
+ {
+ bool lcl_endsWith( const OUString& _rText, const OUString& _rCheck )
+ {
+ sal_Int32 nTextLen = _rText.getLength();
+ sal_Int32 nCheckLen = _rCheck.getLength();
+ if ( nCheckLen > nTextLen )
+ return false;
+
+ return _rText.indexOf( _rCheck ) == ( nTextLen - nCheckLen );
+ }
+ }
+
+ void EventHandler::impl_setFormComponentScriptEvent_nothrow( const ScriptEventDescriptor& _rScriptEvent )
+ {
+ try
+ {
+ OUString sScriptCode( _rScriptEvent.ScriptCode );
+ OUString sScriptType( _rScriptEvent.ScriptType );
+ bool bResetScript = sScriptCode.isEmpty();
+
+ sal_Int32 nObjectIndex = impl_getComponentIndexInParent_throw();
+ Reference< XChild > xChild( m_xComponent, UNO_QUERY_THROW );
+ Reference< XEventAttacherManager > xEventManager( xChild->getParent(), UNO_QUERY_THROW );
+ std::vector< ScriptEventDescriptor > aEvents;
+ comphelper::sequenceToContainer( aEvents, xEventManager->getScriptEvents( nObjectIndex ) );
+
+ // is there already a registered script for this event?
+ sal_Int32 eventCount = aEvents.size(), event = 0;
+ for ( event = 0; event < eventCount; ++event )
+ {
+ ScriptEventDescriptor* pEvent = &aEvents[event];
+ if ( ( pEvent->EventMethod == _rScriptEvent.EventMethod )
+ && ( lcl_endsWith( _rScriptEvent.ListenerType, pEvent->ListenerType ) )
+ // (strange enough, the events we get from getScriptEvents are not fully qualified)
+ )
+ {
+ // yes
+ if ( !bResetScript )
+ {
+ // set to something non-empty -> overwrite
+ pEvent->ScriptCode = sScriptCode;
+ pEvent->ScriptType = sScriptType;
+ }
+ else
+ {
+ // set to empty -> remove from vector
+ aEvents.erase(aEvents.begin() + event );
+ --eventCount;
+ }
+ break;
+ }
+ }
+ if ( ( event >= eventCount ) && !bResetScript )
+ {
+ // no, did not find it -> append
+ aEvents.push_back( _rScriptEvent );
+ }
+
+ xEventManager->revokeScriptEvents( nObjectIndex );
+ xEventManager->registerScriptEvents( nObjectIndex, comphelper::containerToSequence(aEvents) );
+
+ PropertyHandlerHelper::setContextDocumentModified( m_xContext );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+ void EventHandler::impl_setDialogElementScriptEvent_nothrow( const ScriptEventDescriptor& _rScriptEvent )
+ {
+ try
+ {
+ OUString sScriptCode( _rScriptEvent.ScriptCode );
+ bool bResetScript = sScriptCode.isEmpty();
+
+ Reference< XScriptEventsSupplier > xEventsSupplier( m_xComponent, UNO_QUERY_THROW );
+ Reference< XNameContainer > xEvents( xEventsSupplier->getEvents(), UNO_SET_THROW );
+
+ OUString sCompleteName =
+ _rScriptEvent.ListenerType +
+ "::" +
+ _rScriptEvent.EventMethod;
+
+ bool bExists = xEvents->hasByName( sCompleteName );
+
+ if ( bResetScript )
+ {
+ if ( bExists )
+ xEvents->removeByName( sCompleteName );
+ }
+ else
+ {
+ Any aNewValue; aNewValue <<= _rScriptEvent;
+
+ if ( bExists )
+ xEvents->replaceByName( sCompleteName, aNewValue );
+ else
+ xEvents->insertByName( sCompleteName, aNewValue );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+ bool EventHandler::impl_filterMethod_nothrow( const EventDescription& _rEvent ) const
+ {
+ // some (control-triggered) events do not make sense for certain grid control columns. However,
+ // our mechanism to retrieve control-triggered events does not know about this, so we do some
+ // late filtering here.
+ switch ( m_nGridColumnType )
+ {
+ case FormComponentType::COMBOBOX:
+ if ( UID_BRWEVT_ACTIONPERFORMED == _rEvent.sUniqueBrowseId )
+ return false;
+ break;
+ case FormComponentType::LISTBOX:
+ if ( ( UID_BRWEVT_CHANGED == _rEvent.sUniqueBrowseId )
+ || ( UID_BRWEVT_ACTIONPERFORMED == _rEvent.sUniqueBrowseId )
+ )
+ return false;
+ break;
+ }
+
+ return true;
+ }
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_EventHandler_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::EventHandler(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/eventhandler.hxx b/extensions/source/propctrlr/eventhandler.hxx
new file mode 100644
index 000000000..4506f1b06
--- /dev/null
+++ b/extensions/source/propctrlr/eventhandler.hxx
@@ -0,0 +1,241 @@
+/* -*- 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 "pcrcommon.hxx"
+
+#include <com/sun/star/script/ScriptEventDescriptor.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/inspection/XPropertyHandler.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <unotools/resmgr.hxx>
+
+#include <unordered_map>
+
+namespace pcr
+{
+
+
+ //= EventDescription
+
+ typedef sal_Int32 EventId;
+ struct EventDescription
+ {
+ public:
+ OUString sDisplayName;
+ OUString sListenerClassName;
+ OUString sListenerMethodName;
+ OUString sHelpId;
+ OString sUniqueBrowseId;
+ EventId nId;
+
+ EventDescription()
+ :nId( 0 )
+ {
+ }
+
+ EventDescription(
+ EventId _nId,
+ const char* _pListenerNamespaceAscii,
+ const char* _pListenerClassAsciiName,
+ const char* _pListenerMethodAsciiName,
+ TranslateId pDisplayNameResId,
+ const OUString& _sHelpId,
+ const OString& _sUniqueBrowseId );
+ };
+
+ typedef std::unordered_map< OUString, EventDescription > EventMap;
+
+
+ //= EventHandler
+
+ typedef ::cppu::WeakComponentImplHelper < css::inspection::XPropertyHandler
+ , css::lang::XServiceInfo
+ > EventHandler_Base;
+ class EventHandler final : public EventHandler_Base
+ {
+ private:
+ mutable ::osl::Mutex m_aMutex;
+
+ /// the context in which the instance was created
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ /// the properties of the object we're handling
+ css::uno::Reference< css::beans::XPropertySet > m_xComponent;
+ /// our XPropertyChangeListener(s)
+ PropertyChangeListeners m_aPropertyListeners;
+ /// cache of the events we found at our introspectee
+ EventMap m_aEvents;
+ /// has m_aEvents been initialized?
+ bool m_bEventsMapInitialized;
+ /// is our introspectee a dialog element?
+ bool m_bIsDialogElement;
+ // TODO: move different handling into different derived classes?
+ /// (FormComponent) type of the grid column being inspected, or -1 if we're not inspecting a grid column
+ sal_Int16 m_nGridColumnType;
+
+ public:
+ explicit EventHandler(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext
+ );
+
+ virtual ~EventHandler() override;
+
+ private:
+ // XPropertyHandler overridables
+ virtual void SAL_CALL inspect( const css::uno::Reference< css::uno::XInterface >& _rxIntrospectee ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override;
+ virtual css::uno::Any SAL_CALL convertToPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rControlValue ) override;
+ virtual css::uno::Any SAL_CALL convertToControlValue( const OUString& _rPropertyName, const css::uno::Any& _rPropertyValue, const css::uno::Type& _rControlValueType ) override;
+ virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+ virtual css::uno::Sequence< css::beans::Property > SAL_CALL getSupportedProperties() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupersededProperties( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getActuatingProperties( ) override;
+ virtual css::inspection::LineDescriptor SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override;
+ virtual sal_Bool SAL_CALL isComposable( const OUString& _rPropertyName ) override;
+ virtual css::inspection::InteractiveSelectionResult SAL_CALL onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, css::uno::Any& _rData, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) override;
+ virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override;
+ virtual sal_Bool SAL_CALL suspend( sal_Bool _bSuspend ) override;
+
+ // XComponent
+ DECLARE_XCOMPONENT()
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ /** returns the script events associated with our introspectee
+ @param _out_rEvents
+ Takes, upon successful return, the events currently associated with the introspectee
+ @precond
+ Our introspectee is a form component
+ */
+ void impl_getFormComponentScriptEvents_nothrow(
+ std::vector< css::script::ScriptEventDescriptor >& _out_rEvents
+ ) const;
+
+ /** returns the script events associated with our introspectee
+ @param _out_rEvents
+ Takes, upon successful return, the events currently associated with the introspectee
+ @precond
+ Our introspectee is a dialog element
+ */
+ void impl_getDialogElementScriptEvents_nothrow(
+ std::vector< css::script::ScriptEventDescriptor >& _out_rEvents
+ ) const;
+
+ /** returns the script events associated with our introspectee
+ @param _out_rEvents
+ Takes, the events currently associated with the introspectee
+ */
+ void impl_getComponentScriptEvents_nothrow(
+ std::vector< css::script::ScriptEventDescriptor >& _out_rEvents
+ ) const
+ {
+ if ( m_bIsDialogElement )
+ impl_getDialogElementScriptEvents_nothrow( _out_rEvents );
+ else
+ impl_getFormComponentScriptEvents_nothrow( _out_rEvents );
+ }
+
+ /** returns the types of the listeners which can be registered at our introspectee
+ @param _out_rTypes
+ Takes, upon successful return, the types of possible listeners at the introspectee
+ */
+ void impl_getComponentListenerTypes_nothrow(
+ std::vector< css::uno::Type >& _out_rTypes
+ ) const;
+
+ /** returns a secondary component to be used for event inspection
+
+ In the UI, we want to mix events for the control model with events for the control.
+ Since our introspectee is a model, this method creates a control for it (if possible).
+
+ @return
+ the secondary component whose events should be mixed with the introspectee's events
+ The caller takes the ownership of the component (if not <NULL/>).
+
+ @throws
+ if an unexpected error occurs during creation of the secondary component.
+ A <NULL/> component to be returned is not unexpected, but allowed
+
+ @precond
+ ->m_xComponent is not <NULL/>
+ */
+ css::uno::Reference< css::uno::XInterface >
+ impl_getSecondaryComponentForEventInspection_throw( ) const;
+
+ /** returns the event description for the given (programmatic) property name
+ @param _rPropertyName
+ the name whose event description should be looked up
+ @return
+ the event description for the property name
+ @throws css::beans::UnknownPropertyException
+ if our introspectee does not have an event with the given logical name (see ->getSupportedProperties)
+ */
+ const EventDescription&
+ impl_getEventForName_throw( const OUString& _rPropertyName ) const;
+
+ /** returns the index of our component within its parent, if this parent can be
+ obtained (XChild::getParent) and supports an ->XIndexAccess interface
+ */
+ sal_Int32 impl_getComponentIndexInParent_throw() const;
+
+ /** sets a given script event as event handler at a form component
+
+ @param _rScriptEvent
+ the script event to set
+ */
+ void impl_setFormComponentScriptEvent_nothrow( const css::script::ScriptEventDescriptor& _rScriptEvent );
+
+ /** sets a given script event as event handler at a dialog component
+
+ @param _rScriptEvent
+ the script event to set
+ */
+ void impl_setDialogElementScriptEvent_nothrow( const css::script::ScriptEventDescriptor& _rScriptEvent );
+
+ /** returns the frame associated with our context document
+ */
+ css::uno::Reference< css::frame::XFrame >
+ impl_getContextFrame_nothrow() const;
+
+ /** approves or denies a certain method to be included in the UI
+ @return
+ <TRUE/> if and only if the given method is allowed.
+ */
+ bool impl_filterMethod_nothrow( const EventDescription& _rEvent ) const;
+
+ EventHandler( const EventHandler& ) = delete;
+ EventHandler& operator=( const EventHandler& ) = delete;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/fontdialog.cxx b/extensions/source/propctrlr/fontdialog.cxx
new file mode 100644
index 000000000..133367953
--- /dev/null
+++ b/extensions/source/propctrlr/fontdialog.cxx
@@ -0,0 +1,572 @@
+/* -*- 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 "fontdialog.hxx"
+#include <vcl/outdev.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/unohelp.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/extract.hxx>
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/awt/FontStrikeout.hpp>
+#include "formstrings.hxx"
+#include "fontitemids.hxx"
+#include <editeng/charreliefitem.hxx>
+#include <editeng/emphasismarkitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/wrlmitem.hxx>
+#include <editeng/cmapitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/flstitem.hxx>
+#include <svtools/ctrltool.hxx>
+#include <tools/diagnose_ex.h>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <svx/svxids.hrc>
+#include <svx/svxdlg.hxx>
+#include <svx/dialogs.hrc>
+#include <svx/flagsdef.hxx>
+
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+
+
+ //= OFontPropertyExtractor
+
+ namespace {
+
+ class OFontPropertyExtractor
+ {
+ protected:
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xPropValueAccess;
+ css::uno::Reference< css::beans::XPropertyState >
+ m_xPropStateAccess;
+
+ public:
+ explicit OFontPropertyExtractor( const css::uno::Reference< css::beans::XPropertySet >&
+ _rxProps );
+
+ public:
+ bool getCheckFontProperty(const OUString& _rPropName, css::uno::Any& _rValue);
+ OUString getStringFontProperty(const OUString& _rPropName, const OUString& _rDefault);
+ sal_Int16 getInt16FontProperty(const OUString& _rPropName, const sal_Int16 _nDefault);
+ sal_Int32 getInt32FontProperty(const OUString& _rPropName, const sal_Int32 _nDefault);
+ float getFloatFontProperty(const OUString& _rPropName, const float _nDefault);
+
+ void invalidateItem(
+ const OUString& _rPropName,
+ sal_uInt16 _nItemId,
+ SfxItemSet& _rSet,
+ bool _bForceInvalidation = false);
+ };
+
+ }
+
+ OFontPropertyExtractor::OFontPropertyExtractor(const Reference< XPropertySet >& _rxProps)
+ :m_xPropValueAccess(_rxProps)
+ ,m_xPropStateAccess(_rxProps, UNO_QUERY)
+ {
+ OSL_ENSURE(m_xPropValueAccess.is(), "OFontPropertyExtractor::OFontPropertyExtractor: invalid property set!");
+ }
+
+
+ bool OFontPropertyExtractor::getCheckFontProperty(const OUString& _rPropName, Any& _rValue)
+ {
+ _rValue = m_xPropValueAccess->getPropertyValue(_rPropName);
+ if (m_xPropStateAccess.is())
+ return PropertyState_DEFAULT_VALUE == m_xPropStateAccess->getPropertyState(_rPropName);
+
+ return false;
+ }
+
+
+ OUString OFontPropertyExtractor::getStringFontProperty(const OUString& _rPropName, const OUString& _rDefault)
+ {
+ Any aValue;
+ if (getCheckFontProperty(_rPropName, aValue))
+ return _rDefault;
+
+ return ::comphelper::getString(aValue);
+ }
+
+
+ sal_Int16 OFontPropertyExtractor::getInt16FontProperty(const OUString& _rPropName, const sal_Int16 _nDefault)
+ {
+ Any aValue;
+ if (getCheckFontProperty(_rPropName, aValue))
+ return _nDefault;
+
+ sal_Int32 nValue(_nDefault);
+ ::cppu::enum2int(nValue, aValue);
+ return static_cast<sal_Int16>(nValue);
+ }
+
+
+ sal_Int32 OFontPropertyExtractor::getInt32FontProperty(const OUString& _rPropName, const sal_Int32 _nDefault)
+ {
+ Any aValue;
+ if (getCheckFontProperty(_rPropName, aValue))
+ return _nDefault;
+
+ sal_Int32 nValue(_nDefault);
+ ::cppu::enum2int(nValue, aValue);
+ return nValue;
+ }
+
+
+ float OFontPropertyExtractor::getFloatFontProperty(const OUString& _rPropName, const float _nDefault)
+ {
+ Any aValue;
+ if (getCheckFontProperty(_rPropName, aValue))
+ return _nDefault;
+
+ return ::comphelper::getFloat(aValue);
+ }
+
+
+ void OFontPropertyExtractor::invalidateItem(const OUString& _rPropName, sal_uInt16 _nItemId, SfxItemSet& _rSet, bool _bForceInvalidation)
+ {
+ if ( _bForceInvalidation
+ || ( m_xPropStateAccess.is()
+ && (PropertyState_AMBIGUOUS_VALUE == m_xPropStateAccess->getPropertyState(_rPropName))
+ )
+ )
+ _rSet.InvalidateItem(_nItemId);
+ }
+
+ //= ControlCharacterDialog
+ ControlCharacterDialog::ControlCharacterDialog(weld::Window* pParent, const SfxItemSet& _rCoreSet)
+ : SfxTabDialogController(pParent, "modules/spropctrlr/ui/controlfontdialog.ui", "ControlFontDialog", &_rCoreSet)
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ AddTabPage("font", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_CHAR_NAME), nullptr );
+ AddTabPage("fonteffects", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_CHAR_EFFECTS), nullptr );
+ }
+
+ ControlCharacterDialog::~ControlCharacterDialog()
+ {
+ }
+
+ void ControlCharacterDialog::translatePropertiesToItems(const Reference< XPropertySet >& _rxModel, SfxItemSet* _pSet)
+ {
+ OSL_ENSURE(_pSet && _rxModel.is(), "ControlCharacterDialog::translatePropertiesToItems: invalid arguments!");
+ if (!_pSet || !_rxModel.is())
+ return;
+
+ try
+ {
+ OFontPropertyExtractor aPropExtractor(_rxModel);
+
+ // some items, which may be in default state, have to be filled with non-void information
+ vcl::Font aDefaultVCLFont = Application::GetDefaultDevice()->GetSettings().GetStyleSettings().GetAppFont();
+ css::awt::FontDescriptor aDefaultFont = VCLUnoHelper::CreateFontDescriptor(aDefaultVCLFont);
+
+ // get the current properties
+ OUString aFontName = aPropExtractor.getStringFontProperty(PROPERTY_FONT_NAME, aDefaultFont.Name);
+ OUString aFontStyleName = aPropExtractor.getStringFontProperty(PROPERTY_FONT_STYLENAME, aDefaultFont.StyleName);
+ sal_Int16 nFontFamily = aPropExtractor.getInt16FontProperty(PROPERTY_FONT_FAMILY, aDefaultFont.Family);
+ sal_Int16 nFontCharset = aPropExtractor.getInt16FontProperty(PROPERTY_FONT_CHARSET, aDefaultFont.CharSet);
+ float nFontHeight = aPropExtractor.getFloatFontProperty(PROPERTY_FONT_HEIGHT, static_cast<float>(aDefaultFont.Height));
+ float nFontWeight = aPropExtractor.getFloatFontProperty(PROPERTY_FONT_WEIGHT, aDefaultFont.Weight);
+ css::awt::FontSlant nFontSlant = static_cast<css::awt::FontSlant>(aPropExtractor.getInt16FontProperty(PROPERTY_FONT_SLANT, static_cast<sal_Int16>(aDefaultFont.Slant)));
+ sal_Int16 nFontLineStyle = aPropExtractor.getInt16FontProperty(PROPERTY_FONT_UNDERLINE, aDefaultFont.Underline);
+ sal_Int16 nFontStrikeout = aPropExtractor.getInt16FontProperty(PROPERTY_FONT_STRIKEOUT, aDefaultFont.Strikeout);
+
+ sal_Int32 nTextLineColor = aPropExtractor.getInt32FontProperty(PROPERTY_TEXTLINECOLOR, sal_uInt32(COL_AUTO));
+ sal_Int16 nFontRelief = aPropExtractor.getInt16FontProperty(PROPERTY_FONT_RELIEF, static_cast<sal_Int16>(aDefaultVCLFont.GetRelief()));
+ sal_Int16 nFontEmphasisMark = aPropExtractor.getInt16FontProperty(PROPERTY_FONT_EMPHASIS_MARK, static_cast<sal_uInt16>(aDefaultVCLFont.GetEmphasisMark()));
+
+ Any aValue;
+ bool bWordLineMode = aPropExtractor.getCheckFontProperty(PROPERTY_WORDLINEMODE, aValue) ? aDefaultFont.WordLineMode : ::cppu::any2bool(aValue);
+ sal_Int32 nColor32 = aPropExtractor.getInt32FontProperty(PROPERTY_TEXTCOLOR, 0);
+
+ // build SfxItems with the values
+ SvxFontItem aFontItem(static_cast<FontFamily>(nFontFamily), aFontName, aFontStyleName, PITCH_DONTKNOW, nFontCharset, CFID_FONT);
+
+ nFontHeight = static_cast<float>(o3tl::convert(nFontHeight, o3tl::Length::pt, o3tl::Length::twip));
+
+ SvxFontHeightItem aSvxFontHeightItem(static_cast<sal_uInt32>(nFontHeight),100,CFID_HEIGHT);
+
+ FontWeight eWeight=vcl::unohelper::ConvertFontWeight(nFontWeight);
+ FontItalic eItalic=vcl::unohelper::ConvertFontSlant(nFontSlant);
+ FontLineStyle eUnderline=static_cast<FontLineStyle>(nFontLineStyle);
+ FontStrikeout eStrikeout=static_cast<FontStrikeout>(nFontStrikeout);
+
+ SvxWeightItem aWeightItem(eWeight,CFID_WEIGHT);
+ SvxPostureItem aPostureItem(eItalic,CFID_POSTURE);
+
+ SvxCrossedOutItem aCrossedOutItem(eStrikeout,CFID_STRIKEOUT);
+ SvxWordLineModeItem aWordLineModeItem(bWordLineMode, CFID_WORDLINEMODE);
+
+ SvxUnderlineItem aUnderlineItem(eUnderline,CFID_UNDERLINE);
+ aUnderlineItem.SetColor(Color(ColorTransparency, nTextLineColor));
+
+ SvxColorItem aSvxColorItem(Color(ColorTransparency, nColor32),CFID_CHARCOLOR);
+ SvxLanguageItem aLanguageItem(Application::GetSettings().GetUILanguageTag().getLanguageType(), CFID_LANGUAGE);
+
+ // the 2 CJK props
+ SvxCharReliefItem aFontReliefItem(static_cast<FontRelief>(nFontRelief), CFID_RELIEF);
+ SvxEmphasisMarkItem aEmphasisMarkitem(static_cast<FontEmphasisMark>(nFontEmphasisMark), CFID_EMPHASIS);
+
+ _pSet->Put(aFontItem);
+ _pSet->Put(aSvxFontHeightItem);
+ _pSet->Put(aWeightItem);
+ _pSet->Put(aPostureItem);
+ _pSet->Put(aLanguageItem);
+ _pSet->Put(aUnderlineItem);
+ _pSet->Put(aCrossedOutItem);
+ _pSet->Put(aWordLineModeItem);
+ _pSet->Put(aSvxColorItem);
+ _pSet->Put(aFontReliefItem);
+ _pSet->Put(aEmphasisMarkitem);
+
+ aPropExtractor.invalidateItem(PROPERTY_FONT_NAME, CFID_FONT, *_pSet);
+ aPropExtractor.invalidateItem(PROPERTY_FONT_HEIGHT, CFID_HEIGHT, *_pSet);
+ aPropExtractor.invalidateItem(PROPERTY_FONT_WEIGHT, CFID_WEIGHT, *_pSet, css::awt::FontWeight::DONTKNOW == nFontWeight);
+ aPropExtractor.invalidateItem(PROPERTY_FONT_SLANT, CFID_POSTURE, *_pSet, css::awt::FontSlant_DONTKNOW == nFontSlant);
+ aPropExtractor.invalidateItem(PROPERTY_FONT_UNDERLINE, CFID_UNDERLINE, *_pSet, css::awt::FontUnderline::DONTKNOW == nFontLineStyle);
+ aPropExtractor.invalidateItem(PROPERTY_FONT_STRIKEOUT, CFID_STRIKEOUT, *_pSet, css::awt::FontStrikeout::DONTKNOW == nFontStrikeout);
+ aPropExtractor.invalidateItem(PROPERTY_WORDLINEMODE, CFID_WORDLINEMODE, *_pSet);
+ aPropExtractor.invalidateItem(PROPERTY_TEXTCOLOR, CFID_CHARCOLOR, *_pSet);
+ aPropExtractor.invalidateItem(PROPERTY_FONT_RELIEF, CFID_RELIEF, *_pSet);
+ aPropExtractor.invalidateItem(PROPERTY_FONT_EMPHASIS_MARK, CFID_EMPHASIS, *_pSet);
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "ControlCharacterDialog::translatePropertiesToItems");
+ }
+
+ _pSet->DisableItem(SID_ATTR_CHAR_CJK_FONT);
+ _pSet->DisableItem(SID_ATTR_CHAR_CJK_FONTHEIGHT);
+ _pSet->DisableItem(SID_ATTR_CHAR_CJK_LANGUAGE);
+ _pSet->DisableItem(SID_ATTR_CHAR_CJK_POSTURE);
+ _pSet->DisableItem(SID_ATTR_CHAR_CJK_WEIGHT);
+
+ _pSet->DisableItem(SID_ATTR_CHAR_CASEMAP);
+ _pSet->DisableItem(SID_ATTR_CHAR_CONTOUR);
+ _pSet->DisableItem(SID_ATTR_CHAR_SHADOWED);
+ }
+
+ namespace
+ {
+ void lcl_pushBackPropertyValue( std::vector< NamedValue >& _out_properties, const OUString& _name, const Any& _value )
+ {
+ _out_properties.push_back( NamedValue( _name, _value ) );
+ }
+ }
+
+ void ControlCharacterDialog::translateItemsToProperties( const SfxItemSet& _rSet, std::vector< NamedValue >& _out_properties )
+ {
+ _out_properties.clear();
+
+ try
+ {
+
+ // font name
+ SfxItemState eState = _rSet.GetItemState(CFID_FONT);
+
+ if ( eState == SfxItemState::SET )
+ {
+ const SvxFontItem& rFontItem =
+ static_cast<const SvxFontItem&>(_rSet.Get(CFID_FONT));
+
+ lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_NAME , Any(rFontItem.GetFamilyName()));
+ lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_STYLENAME, Any(rFontItem.GetStyleName()));
+ lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_FAMILY , Any(static_cast<sal_Int16>(rFontItem.GetFamily())));
+ lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_CHARSET , Any(static_cast<sal_Int16>(rFontItem.GetCharSet())));
+ }
+
+
+ // font height
+ eState = _rSet.GetItemState(CFID_HEIGHT);
+
+ if ( eState == SfxItemState::SET )
+ {
+ const SvxFontHeightItem& rSvxFontHeightItem =
+ static_cast<const SvxFontHeightItem&>(_rSet.Get(CFID_HEIGHT));
+
+ float nHeight = static_cast<float>(o3tl::convert(rSvxFontHeightItem.GetHeight(), o3tl::Length::twip, o3tl::Length::pt));
+ lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_HEIGHT,Any(nHeight));
+
+ }
+
+
+ // font weight
+ eState = _rSet.GetItemState(CFID_WEIGHT);
+
+ if ( eState == SfxItemState::SET )
+ {
+ const SvxWeightItem& rWeightItem =
+ static_cast<const SvxWeightItem&>(_rSet.Get(CFID_WEIGHT));
+
+ float nWeight = vcl::unohelper::ConvertFontWeight(rWeightItem.GetWeight());
+ lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_WEIGHT,Any(nWeight));
+ }
+
+
+ // font slant
+ eState = _rSet.GetItemState(CFID_POSTURE);
+
+ if ( eState == SfxItemState::SET )
+ {
+ const SvxPostureItem& rPostureItem =
+ static_cast<const SvxPostureItem&>(_rSet.Get(CFID_POSTURE));
+
+ css::awt::FontSlant eSlant = vcl::unohelper::ConvertFontSlant(rPostureItem.GetPosture());
+ lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_SLANT, Any(static_cast<sal_Int16>(eSlant)));
+ }
+
+
+ // font underline
+ eState = _rSet.GetItemState(CFID_UNDERLINE);
+
+ if ( eState == SfxItemState::SET )
+ {
+ const SvxUnderlineItem& rUnderlineItem =
+ static_cast<const SvxUnderlineItem&>(_rSet.Get(CFID_UNDERLINE));
+
+ sal_Int16 nUnderline = static_cast<sal_Int16>(rUnderlineItem.GetLineStyle());
+ lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_UNDERLINE,Any(nUnderline));
+
+ // the text line color is transported in this item, too
+ Color nColor = rUnderlineItem.GetColor();
+
+ Any aUnoColor;
+ if (COL_AUTO != nColor)
+ aUnoColor <<= nColor;
+
+ lcl_pushBackPropertyValue( _out_properties, PROPERTY_TEXTLINECOLOR, aUnoColor );
+ }
+
+
+ // font strikeout
+ eState = _rSet.GetItemState(CFID_STRIKEOUT);
+
+ if ( eState == SfxItemState::SET )
+ {
+ const SvxCrossedOutItem& rCrossedOutItem =
+ static_cast<const SvxCrossedOutItem&>(_rSet.Get(CFID_STRIKEOUT));
+
+ sal_Int16 nStrikeout = static_cast<sal_Int16>(rCrossedOutItem.GetStrikeout());
+ lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_STRIKEOUT,Any(nStrikeout));
+ }
+
+
+ // font wordline mode
+ eState = _rSet.GetItemState(CFID_WORDLINEMODE);
+
+ if ( eState == SfxItemState::SET )
+ {
+ const SvxWordLineModeItem& rWordLineModeItem =
+ static_cast<const SvxWordLineModeItem&>(_rSet.Get(CFID_WORDLINEMODE));
+
+ lcl_pushBackPropertyValue( _out_properties, PROPERTY_WORDLINEMODE, css::uno::Any(rWordLineModeItem.GetValue()));
+ }
+
+
+ // text color
+ eState = _rSet.GetItemState(CFID_CHARCOLOR);
+
+ if ( eState == SfxItemState::SET )
+ {
+ const SvxColorItem& rColorItem =
+ static_cast<const SvxColorItem&>(_rSet.Get(CFID_CHARCOLOR));
+
+ Color nColor = rColorItem.GetValue();
+
+ Any aUnoColor;
+ if (COL_AUTO != nColor)
+ aUnoColor <<= nColor;
+
+ lcl_pushBackPropertyValue( _out_properties, PROPERTY_TEXTCOLOR, aUnoColor );
+ }
+
+
+ // font relief
+ eState = _rSet.GetItemState(CFID_RELIEF);
+
+ if ( eState == SfxItemState::SET )
+ {
+ const SvxCharReliefItem& rReliefItem =
+ static_cast<const SvxCharReliefItem&>(_rSet.Get(CFID_RELIEF));
+
+ lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_RELIEF, Any(static_cast<sal_Int16>(rReliefItem.GetValue())) );
+ }
+
+
+ // font emphasis mark
+ eState = _rSet.GetItemState(CFID_EMPHASIS);
+
+ if ( eState == SfxItemState::SET )
+ {
+ const SvxEmphasisMarkItem& rEmphMarkItem =
+ static_cast<const SvxEmphasisMarkItem&>(_rSet.Get(CFID_EMPHASIS));
+
+ lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_EMPHASIS_MARK, Any(static_cast<sal_Int16>(rEmphMarkItem.GetEmphasisMark())) );
+ }
+ }
+ catch (const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+ void ControlCharacterDialog::translateItemsToProperties( const SfxItemSet& _rSet, const Reference< XPropertySet >& _rxModel)
+ {
+ OSL_ENSURE( _rxModel.is(), "ControlCharacterDialog::translateItemsToProperties: invalid arguments!" );
+ if ( !_rxModel.is())
+ return;
+
+ std::vector< NamedValue > aPropertyValues;
+ translateItemsToProperties( _rSet, aPropertyValues );
+ try
+ {
+ for ( const NamedValue& rNV : aPropertyValues )
+ _rxModel->setPropertyValue( rNV.Name, rNV.Value );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+ void ControlCharacterDialog::createItemSet(std::unique_ptr<SfxItemSet>& _rpSet, rtl::Reference<SfxItemPool>& _rpPool, std::vector<SfxPoolItem*>*& _rpDefaults)
+ {
+ // just to be sure...
+ _rpSet = nullptr;
+ _rpPool = nullptr;
+ _rpDefaults = nullptr;
+
+ // create and initialize the defaults
+ _rpDefaults = new std::vector<SfxPoolItem*>(CFID_LAST_ITEM_ID - CFID_FIRST_ITEM_ID + 1);
+
+ vcl::Font aDefaultVCLFont = Application::GetDefaultDevice()->GetSettings().GetStyleSettings().GetAppFont();
+
+ SfxPoolItem** pCounter = _rpDefaults->data(); // want to modify this without affecting the out param _rppDefaults
+ *pCounter++ = new SvxFontItem(aDefaultVCLFont.GetFamilyType(), aDefaultVCLFont.GetFamilyName(), aDefaultVCLFont.GetStyleName(), aDefaultVCLFont.GetPitch(), aDefaultVCLFont.GetCharSet(), CFID_FONT);
+ *pCounter++ = new SvxFontHeightItem(aDefaultVCLFont.GetFontHeight(), 100, CFID_HEIGHT);
+ *pCounter++ = new SvxWeightItem(aDefaultVCLFont.GetWeight(), CFID_WEIGHT);
+ *pCounter++ = new SvxPostureItem(aDefaultVCLFont.GetItalic(), CFID_POSTURE);
+ *pCounter++ = new SvxLanguageItem(Application::GetSettings().GetUILanguageTag().getLanguageType(), CFID_LANGUAGE);
+ *pCounter++ = new SvxUnderlineItem(aDefaultVCLFont.GetUnderline(), CFID_UNDERLINE);
+ *pCounter++ = new SvxCrossedOutItem(aDefaultVCLFont.GetStrikeout(), CFID_STRIKEOUT);
+ *pCounter++ = new SvxWordLineModeItem(aDefaultVCLFont.IsWordLineMode(), CFID_WORDLINEMODE);
+ *pCounter++ = new SvxColorItem(aDefaultVCLFont.GetColor(), CFID_CHARCOLOR);
+ *pCounter++ = new SvxCharReliefItem(aDefaultVCLFont.GetRelief(), CFID_RELIEF);
+ *pCounter++ = new SvxEmphasisMarkItem(aDefaultVCLFont.GetEmphasisMark(), CFID_EMPHASIS);
+
+ *pCounter++ = new SvxFontItem(aDefaultVCLFont.GetFamilyType(), aDefaultVCLFont.GetFamilyName(), aDefaultVCLFont.GetStyleName(), aDefaultVCLFont.GetPitch(), aDefaultVCLFont.GetCharSet(), CFID_CJK_FONT);
+ *pCounter++ = new SvxFontHeightItem(aDefaultVCLFont.GetFontHeight(), 100, CFID_CJK_HEIGHT);
+ *pCounter++ = new SvxWeightItem(aDefaultVCLFont.GetWeight(), CFID_CJK_WEIGHT);
+ *pCounter++ = new SvxPostureItem(aDefaultVCLFont.GetItalic(), CFID_CJK_POSTURE);
+ *pCounter++ = new SvxLanguageItem(Application::GetSettings().GetUILanguageTag().getLanguageType(), CFID_CJK_LANGUAGE);
+
+ *pCounter++ = new SvxCaseMapItem(SvxCaseMap::NotMapped, CFID_CASEMAP);
+ *pCounter++ = new SvxContourItem(false, CFID_CONTOUR);
+ *pCounter++ = new SvxShadowedItem(false, CFID_SHADOWED);
+
+ *pCounter++ = new SvxFontListItem (new FontList(Application::GetDefaultDevice()), CFID_FONTLIST);
+
+ // create the pool
+ static SfxItemInfo const aItemInfos[CFID_LAST_ITEM_ID - CFID_FIRST_ITEM_ID + 1] =
+ {
+ { SID_ATTR_CHAR_FONT, false },
+ { SID_ATTR_CHAR_FONTHEIGHT, false },
+ { SID_ATTR_CHAR_WEIGHT, false },
+ { SID_ATTR_CHAR_POSTURE, false },
+ { SID_ATTR_CHAR_LANGUAGE, false },
+ { SID_ATTR_CHAR_UNDERLINE, false },
+ { SID_ATTR_CHAR_STRIKEOUT, false },
+ { SID_ATTR_CHAR_WORDLINEMODE, false },
+ { SID_ATTR_CHAR_COLOR, false },
+ { SID_ATTR_CHAR_RELIEF, false },
+ { SID_ATTR_CHAR_EMPHASISMARK, false },
+ { 0, false },
+ { 0, false },
+ { 0, false },
+ { 0, false },
+ { 0, false },
+ { 0, false },
+ { 0, false },
+ { 0, false },
+ { SID_ATTR_CHAR_FONTLIST, false }
+ };
+
+ _rpPool = new SfxItemPool("PCRControlFontItemPool", CFID_FIRST_ITEM_ID, CFID_LAST_ITEM_ID,
+ aItemInfos, _rpDefaults);
+ _rpPool->FreezeIdRanges();
+
+ // and, finally, the set
+ _rpSet.reset(new SfxItemSet(*_rpPool));
+ }
+
+ void ControlCharacterDialog::destroyItemSet(std::unique_ptr<SfxItemSet>& _rpSet, rtl::Reference<SfxItemPool>& _rpPool, std::vector<SfxPoolItem*>*& _rpDefaults)
+ {
+ // from the pool, get and remember the font list (needs to be deleted)
+ const SvxFontListItem& rFontListItem = static_cast<const SvxFontListItem&>(_rpPool->GetDefaultItem(CFID_FONTLIST));
+ const FontList* pFontList = rFontListItem.GetFontList();
+
+ // _first_ delete the set (referring the pool)
+ _rpSet.reset();
+
+ // delete the pool
+ _rpPool->ReleaseDefaults(true);
+ // the "true" means delete the items, too
+ _rpPool = nullptr;
+
+ // reset the defaults ptr
+ _rpDefaults = nullptr;
+ // no need to explicitly delete the defaults, this has been done by the ReleaseDefaults
+
+ delete pFontList;
+ }
+
+ void ControlCharacterDialog::PageCreated(const OString& rId, SfxTabPage& rPage)
+ {
+ SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool()));
+ if (rId == "font")
+ {
+ aSet.Put (static_cast<const SvxFontListItem&>(GetInputSetImpl()->Get(CFID_FONTLIST)));
+ aSet.Put (SfxUInt16Item(SID_DISABLE_CTL,DISABLE_HIDE_LANGUAGE));
+ rPage.PageCreated(aSet);
+ }
+ }
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/fontdialog.hxx b/extensions/source/propctrlr/fontdialog.hxx
new file mode 100644
index 000000000..eaba29db0
--- /dev/null
+++ b/extensions/source/propctrlr/fontdialog.hxx
@@ -0,0 +1,68 @@
+/* -*- 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 <sfx2/tabdlg.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+
+
+namespace pcr
+{
+
+
+ //= ControlCharacterDialog
+ class ControlCharacterDialog : public SfxTabDialogController
+ {
+ public:
+ ControlCharacterDialog(weld::Window* pParent, const SfxItemSet& rCoreSet);
+ virtual ~ControlCharacterDialog() override;
+
+ /// creates an item set to be used with this dialog
+ static void createItemSet(std::unique_ptr<SfxItemSet>& _rpSet, rtl::Reference<SfxItemPool>& _rpPool, std::vector<SfxPoolItem*>*& _rpDefaults);
+
+ /// destroys an item previously created with <method>createItemSet</method>
+ static void destroyItemSet(std::unique_ptr<SfxItemSet>& _rpSet, rtl::Reference<SfxItemPool>& _rpPool, std::vector<SfxPoolItem*>*& _rpDefaults);
+
+ /// fills the given item set with values obtained from the given property set
+ static void translatePropertiesToItems(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxModel,
+ SfxItemSet* _pSet);
+
+ /** fills the given property set with values obtained from the given item set
+ */
+ static void translateItemsToProperties(
+ const SfxItemSet& _rSet,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxModel);
+
+ /** fills the given property set with values obtained from the given item set
+ */
+ static void translateItemsToProperties(
+ const SfxItemSet& _rSet,
+ std::vector< css::beans::NamedValue >& _out_properties );
+
+ protected:
+ virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override;
+ };
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/fontitemids.hxx b/extensions/source/propctrlr/fontitemids.hxx
new file mode 100644
index 000000000..c9b3a455f
--- /dev/null
+++ b/extensions/source/propctrlr/fontitemids.hxx
@@ -0,0 +1,48 @@
+/* -*- 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
+
+#define CFID_FONT 1
+#define CFID_HEIGHT 2
+#define CFID_WEIGHT 3
+#define CFID_POSTURE 4
+#define CFID_LANGUAGE 5
+#define CFID_UNDERLINE 6
+#define CFID_STRIKEOUT 7
+#define CFID_WORDLINEMODE 8
+#define CFID_CHARCOLOR 9
+#define CFID_RELIEF 10
+#define CFID_EMPHASIS 11
+
+#define CFID_CJK_FONT 12
+#define CFID_CJK_HEIGHT 13
+#define CFID_CJK_WEIGHT 14
+#define CFID_CJK_POSTURE 15
+#define CFID_CJK_LANGUAGE 16
+#define CFID_CASEMAP 17
+#define CFID_CONTOUR 18
+#define CFID_SHADOWED 19
+
+#define CFID_FONTLIST 20
+
+#define CFID_FIRST_ITEM_ID CFID_FONT
+#define CFID_LAST_ITEM_ID CFID_FONTLIST
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/formbrowsertools.cxx b/extensions/source/propctrlr/formbrowsertools.cxx
new file mode 100644
index 000000000..b31aa0ce4
--- /dev/null
+++ b/extensions/source/propctrlr/formbrowsertools.cxx
@@ -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 .
+ */
+
+#include "formbrowsertools.hxx"
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <osl/diagnose.h>
+#include <strings.hrc>
+#include "modulepcr.hxx"
+#include "formstrings.hxx"
+
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+
+
+ OUString GetUIHeadlineName(sal_Int16 nClassId, const Any& aUnoObj)
+ {
+ OUString sClassName;
+ switch (nClassId)
+ {
+ case FormComponentType::TEXTFIELD:
+ {
+ Reference< XInterface > xIFace;
+ aUnoObj >>= xIFace;
+ sClassName = PcrRes(RID_STR_PROPTITLE_EDIT);
+ if (xIFace.is())
+ { // we have a chance to check if it's a formatted field model
+ Reference< XServiceInfo > xInfo(xIFace, UNO_QUERY);
+ if (xInfo.is() && (xInfo->supportsService(SERVICE_COMPONENT_FORMATTEDFIELD)))
+ sClassName = PcrRes(RID_STR_PROPTITLE_FORMATTED);
+ else if (!xInfo.is())
+ {
+ // couldn't distinguish between formatted and edit with the service name, so try with the properties
+ Reference< XPropertySet > xProps(xIFace, UNO_QUERY);
+ if (xProps.is())
+ {
+ Reference< XPropertySetInfo > xPropsInfo = xProps->getPropertySetInfo();
+ if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(PROPERTY_FORMATSSUPPLIER))
+ sClassName = PcrRes(RID_STR_PROPTITLE_FORMATTED);
+ }
+ }
+ }
+ }
+ break;
+
+ case FormComponentType::COMMANDBUTTON:
+ sClassName = PcrRes(RID_STR_PROPTITLE_PUSHBUTTON); break;
+ case FormComponentType::RADIOBUTTON:
+ sClassName = PcrRes(RID_STR_PROPTITLE_RADIOBUTTON); break;
+ case FormComponentType::CHECKBOX:
+ sClassName = PcrRes(RID_STR_PROPTITLE_CHECKBOX); break;
+ case FormComponentType::LISTBOX:
+ sClassName = PcrRes(RID_STR_PROPTITLE_LISTBOX); break;
+ case FormComponentType::COMBOBOX:
+ sClassName = PcrRes(RID_STR_PROPTITLE_COMBOBOX); break;
+ case FormComponentType::GROUPBOX:
+ sClassName = PcrRes(RID_STR_PROPTITLE_GROUPBOX); break;
+ case FormComponentType::IMAGEBUTTON:
+ sClassName = PcrRes(RID_STR_PROPTITLE_IMAGEBUTTON); break;
+ case FormComponentType::FIXEDTEXT:
+ sClassName = PcrRes(RID_STR_PROPTITLE_FIXEDTEXT); break;
+ case FormComponentType::GRIDCONTROL:
+ sClassName = PcrRes(RID_STR_PROPTITLE_DBGRID); break;
+ case FormComponentType::FILECONTROL:
+ sClassName = PcrRes(RID_STR_PROPTITLE_FILECONTROL); break;
+
+ case FormComponentType::DATEFIELD:
+ sClassName = PcrRes(RID_STR_PROPTITLE_DATEFIELD); break;
+ case FormComponentType::TIMEFIELD:
+ sClassName = PcrRes(RID_STR_PROPTITLE_TIMEFIELD); break;
+ case FormComponentType::NUMERICFIELD:
+ sClassName = PcrRes(RID_STR_PROPTITLE_NUMERICFIELD); break;
+ case FormComponentType::CURRENCYFIELD:
+ sClassName = PcrRes(RID_STR_PROPTITLE_CURRENCYFIELD); break;
+ case FormComponentType::PATTERNFIELD:
+ sClassName = PcrRes(RID_STR_PROPTITLE_PATTERNFIELD); break;
+ case FormComponentType::IMAGECONTROL:
+ sClassName = PcrRes(RID_STR_PROPTITLE_IMAGECONTROL); break;
+ case FormComponentType::HIDDENCONTROL:
+ sClassName = PcrRes(RID_STR_PROPTITLE_HIDDENCONTROL); break;
+
+ case FormComponentType::CONTROL:
+ default:
+ sClassName = PcrRes(RID_STR_PROPTITLE_UNKNOWNCONTROL); break;
+ }
+
+ return sClassName;
+ }
+
+
+ sal_Int16 classifyComponent( const Reference< XInterface >& _rxComponent )
+ {
+ Reference< XPropertySet > xComponentProps( _rxComponent, UNO_QUERY_THROW );
+ Reference< XPropertySetInfo > xPSI( xComponentProps->getPropertySetInfo(), UNO_SET_THROW );
+
+ sal_Int16 nControlType( FormComponentType::CONTROL );
+ if ( xPSI->hasPropertyByName( PROPERTY_CLASSID ) )
+ {
+ OSL_VERIFY( xComponentProps->getPropertyValue( PROPERTY_CLASSID ) >>= nControlType );
+ }
+ return nControlType;
+ }
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/formbrowsertools.hxx b/extensions/source/propctrlr/formbrowsertools.hxx
new file mode 100644
index 000000000..08d48747c
--- /dev/null
+++ b/extensions/source/propctrlr/formbrowsertools.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/beans/Property.hpp>
+#include <rtl/ustring.hxx>
+
+#include <set>
+
+
+namespace pcr
+{
+
+
+ OUString GetUIHeadlineName(sal_Int16 _nClassId, const css::uno::Any& _rUnoObject);
+ sal_Int16 classifyComponent( const css::uno::Reference< css::uno::XInterface >& _rxComponent );
+
+
+ struct FindPropertyByHandle
+ {
+ private:
+ sal_Int32 m_nId;
+
+ public:
+ explicit FindPropertyByHandle( sal_Int32 _nId ) : m_nId ( _nId ) { }
+ bool operator()( const css::beans::Property& _rProp ) const
+ {
+ return m_nId == _rProp.Handle;
+ }
+ };
+
+
+ struct FindPropertyByName
+ {
+ private:
+ OUString m_sName;
+
+ public:
+ explicit FindPropertyByName( const OUString& _rName ) : m_sName( _rName ) { }
+ bool operator()( const css::beans::Property& _rProp ) const
+ {
+ return m_sName == _rProp.Name;
+ }
+ };
+
+
+ struct PropertyLessByName
+ {
+ bool operator() (const css::beans::Property& _rLhs, const css::beans::Property& _rRhs) const
+ {
+ return _rLhs.Name < _rRhs.Name;
+ }
+ };
+
+
+ struct TypeLessByName
+ {
+ bool operator() (const css::uno::Type& _rLhs, const css::uno::Type& _rRhs) const
+ {
+ return _rLhs.getTypeName() < _rRhs.getTypeName();
+ }
+ };
+
+
+ typedef std::set< css::beans::Property, PropertyLessByName > PropertyBag;
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/formcomponenthandler.cxx b/extensions/source/propctrlr/formcomponenthandler.cxx
new file mode 100644
index 000000000..d5f397662
--- /dev/null
+++ b/extensions/source/propctrlr/formcomponenthandler.cxx
@@ -0,0 +1,3305 @@
+/* -*- 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 "controltype.hxx"
+#include "modulepcr.hxx"
+#include <propctrlr.h>
+#include <helpids.h>
+#include "fontdialog.hxx"
+#include "formcomponenthandler.hxx"
+#include "formlinkdialog.hxx"
+#include "formmetadata.hxx"
+#include <strings.hrc>
+#include <showhide.hrc>
+#include <yesno.hrc>
+#include "formstrings.hxx"
+#include "handlerhelper.hxx"
+#include "listselectiondlg.hxx"
+#include "pcrcommon.hxx"
+#include "selectlabeldialog.hxx"
+#include "standardcontrol.hxx"
+#include "taborder.hxx"
+#include "usercontrol.hxx"
+
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/sdb/OrderDialog.hpp>
+#include <com/sun/star/sdb/FilterDialog.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/form/XGridColumnFactory.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/form/ListSourceType.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
+#include <com/sun/star/awt/XTabControllerModel.hpp>
+#include <com/sun/star/form/FormSubmitEncoding.hpp>
+#include <com/sun/star/awt/VisualEffect.hpp>
+#include <com/sun/star/form/FormButtonType.hpp>
+#include <com/sun/star/inspection/PropertyControlType.hpp>
+#include <com/sun/star/util/MeasureUnit.hpp>
+#include <com/sun/star/inspection/XObjectInspectorUI.hpp>
+#include <com/sun/star/inspection/PropertyLineElement.hpp>
+#include <com/sun/star/resource/XStringResourceManager.hpp>
+#include <com/sun/star/resource/MissingResourceException.hpp>
+#include <com/sun/star/report/XReportDefinition.hpp>
+#include <com/sun/star/graphic/GraphicObject.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+
+#include <comphelper/extract.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/dbexception.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/basedlgs.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <svl/ctloptions.hxx>
+#include <svtools/colrdlg.hxx>
+#include <svl/filenotation.hxx>
+#include <svl/intitem.hxx>
+#include <svl/itemset.hxx>
+#include <svl/numformat.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <svl/numuno.hxx>
+#include <svl/urihelper.hxx>
+#include <svx/dialogs.hrc>
+#include <svx/numinf.hxx>
+#include <svx/svxdlg.hxx>
+#include <svx/svxids.hrc>
+#include <vcl/graph.hxx>
+#include <vcl/unohelp.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/macros.h>
+#include <sal/log.hxx>
+
+#include <limits>
+#include <memory>
+#include <string_view>
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star;
+ using namespace uno;
+ using namespace lang;
+ using namespace beans;
+ using namespace frame;
+ using namespace script;
+ using namespace form;
+ using namespace util;
+ using namespace awt;
+ using namespace sdb;
+ using namespace sdbc;
+ using namespace sdbcx;
+ using namespace report;
+ using namespace container;
+ using namespace ui::dialogs;
+ using namespace inspection;
+ using namespace ::dbtools;
+
+ namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
+
+
+ //= FormComponentPropertyHandler
+
+#define PROPERTY_ID_ROWSET 1
+
+ FormComponentPropertyHandler::FormComponentPropertyHandler( const Reference< XComponentContext >& _rxContext )
+ :PropertyHandlerComponent( _rxContext )
+ ,::comphelper::OPropertyContainer(PropertyHandlerComponent::rBHelper)
+ ,m_sDefaultValueString( PcrRes(RID_STR_STANDARD) )
+ ,m_eComponentClass( eUnknown )
+ ,m_bComponentIsSubForm( false )
+ ,m_bHaveListSource( false )
+ ,m_bHaveCommand( false )
+ ,m_nClassId( 0 )
+ {
+ registerProperty(PROPERTY_ROWSET,PROPERTY_ID_ROWSET,0,&m_xRowSet,cppu::UnoType<decltype(m_xRowSet)>::get());
+ }
+
+
+ FormComponentPropertyHandler::~FormComponentPropertyHandler()
+ {
+ }
+
+ IMPLEMENT_FORWARD_XINTERFACE2(FormComponentPropertyHandler,PropertyHandlerComponent,::comphelper::OPropertyContainer)
+
+ OUString FormComponentPropertyHandler::getImplementationName( )
+ {
+ return "com.sun.star.comp.extensions.FormComponentPropertyHandler";
+ }
+
+
+ Sequence< OUString > FormComponentPropertyHandler::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.form.inspection.FormComponentPropertyHandler" };
+ }
+
+ namespace {
+
+ // TODO: -> export from toolkit
+ struct LanguageDependentProp
+ {
+ const char* pPropName;
+ sal_Int32 nPropNameLength;
+ };
+
+ }
+
+ const LanguageDependentProp aLanguageDependentProp[] =
+ {
+ { "Text", 4 },
+ { "Label", 5 },
+ { "Title", 5 },
+ { "HelpText", 8 },
+ { "CurrencySymbol", 14 },
+ { "StringItemList", 14 },
+ { nullptr, 0 }
+ };
+
+ namespace
+ {
+ bool lcl_isLanguageDependentProperty( const OUString& aName )
+ {
+ bool bRet = false;
+
+ const LanguageDependentProp* pLangDepProp = aLanguageDependentProp;
+ while( pLangDepProp->pPropName != nullptr )
+ {
+ if( aName.equalsAsciiL( pLangDepProp->pPropName, pLangDepProp->nPropNameLength ))
+ {
+ bRet = true;
+ break;
+ }
+ pLangDepProp++;
+ }
+ return bRet;
+ }
+
+ Reference< resource::XStringResourceResolver > lcl_getStringResourceResolverForProperty
+ ( const Reference< XPropertySet >& _xComponent, const OUString& _rPropertyName,
+ const Any& _rPropertyValue )
+ {
+ Reference< resource::XStringResourceResolver > xRet;
+ const TypeClass eType = _rPropertyValue.getValueType().getTypeClass();
+ if ( (eType == TypeClass_STRING || eType == TypeClass_SEQUENCE) &&
+ lcl_isLanguageDependentProperty( _rPropertyName ) )
+ {
+ Reference< resource::XStringResourceResolver > xStringResourceResolver;
+ try
+ {
+ xStringResourceResolver.set( _xComponent->getPropertyValue( "ResourceResolver" ),UNO_QUERY);
+ if( xStringResourceResolver.is() &&
+ xStringResourceResolver->getLocales().hasElements() )
+ {
+ xRet = xStringResourceResolver;
+ }
+ }
+ catch(const UnknownPropertyException&)
+ {
+ // nii
+ }
+ }
+
+ return xRet;
+ }
+ }
+
+
+ Any FormComponentPropertyHandler::impl_getPropertyValue_throw( const OUString& _rPropertyName ) const
+ {
+ const PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ // tdf#117159 crash with chart in database report
+ if (!m_xComponent)
+ return Any();
+
+ Any aPropertyValue( m_xComponent->getPropertyValue( _rPropertyName ) );
+
+ Reference< resource::XStringResourceResolver > xStringResourceResolver
+ = lcl_getStringResourceResolverForProperty( m_xComponent, _rPropertyName, aPropertyValue );
+ if( xStringResourceResolver.is() )
+ {
+ TypeClass eType = aPropertyValue.getValueType().getTypeClass();
+ if( eType == TypeClass_STRING )
+ {
+ OUString aPropStr;
+ aPropertyValue >>= aPropStr;
+ if( aPropStr.getLength() > 1 )
+ {
+ OUString aPureIdStr = aPropStr.copy( 1 );
+ if( xStringResourceResolver->hasEntryForId( aPureIdStr ) )
+ {
+ OUString aResourceStr = xStringResourceResolver->resolveString( aPureIdStr );
+ aPropertyValue <<= aResourceStr;
+ }
+ }
+ }
+ // StringItemList?
+ else if( eType == TypeClass_SEQUENCE )
+ {
+ Sequence< OUString > aStrings;
+ aPropertyValue >>= aStrings;
+
+ std::vector< OUString > aResolvedStrings;
+ aResolvedStrings.reserve( aStrings.getLength() );
+ try
+ {
+ for ( const OUString& rIdStr : std::as_const(aStrings) )
+ {
+ OUString aPureIdStr = rIdStr.copy( 1 );
+ if( xStringResourceResolver->hasEntryForId( aPureIdStr ) )
+ aResolvedStrings.push_back(xStringResourceResolver->resolveString( aPureIdStr ));
+ else
+ aResolvedStrings.push_back(rIdStr);
+ }
+ }
+ catch( const resource::MissingResourceException & )
+ {}
+ aPropertyValue <<= comphelper::containerToSequence(aResolvedStrings);
+ }
+ }
+ else
+ impl_normalizePropertyValue_nothrow( aPropertyValue, nPropId );
+
+ return aPropertyValue;
+ }
+
+ Any SAL_CALL FormComponentPropertyHandler::getPropertyValue( const OUString& _rPropertyName )
+ {
+ if( _rPropertyName == PROPERTY_ROWSET )
+ return ::comphelper::OPropertyContainer::getPropertyValue( _rPropertyName );
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return impl_getPropertyValue_throw( _rPropertyName );
+ }
+
+ void SAL_CALL FormComponentPropertyHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue )
+ {
+ if( _rPropertyName == PROPERTY_ROWSET )
+ {
+ ::comphelper::OPropertyContainer::setPropertyValue( _rPropertyName, _rValue );
+ return;
+ }
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); // check if property is known by the handler
+
+ Reference< graphic::XGraphicObject > xGrfObj;
+ if ( PROPERTY_ID_IMAGE_URL == nPropId && ( _rValue >>= xGrfObj ) )
+ {
+ DBG_ASSERT( xGrfObj.is(), "FormComponentPropertyHandler::setPropertyValue() xGrfObj is invalid");
+ m_xComponent->setPropertyValue(PROPERTY_GRAPHIC, uno::Any(xGrfObj->getGraphic()));
+ }
+ else if ( PROPERTY_ID_FONT == nPropId )
+ {
+ // special handling, the value is a faked value we generated ourself in impl_executeFontDialog_nothrow
+ Sequence< NamedValue > aFontPropertyValues;
+ if( ! (_rValue >>= aFontPropertyValues) )
+ SAL_WARN("extensions.propctrlr", "setPropertyValue: unable to get property " << PROPERTY_ID_FONT);
+
+ for ( const NamedValue& fontPropertyValue : std::as_const(aFontPropertyValues) )
+ m_xComponent->setPropertyValue( fontPropertyValue.Name, fontPropertyValue.Value );
+ }
+ else
+ {
+ Any aValue = _rValue;
+
+ Reference< resource::XStringResourceResolver > xStringResourceResolver
+ = lcl_getStringResourceResolverForProperty( m_xComponent, _rPropertyName, _rValue );
+ if( xStringResourceResolver.is() )
+ {
+ Reference< resource::XStringResourceManager >
+ xStringResourceManager( xStringResourceResolver, UNO_QUERY );
+ if( xStringResourceManager.is() )
+ {
+ Any aPropertyValue( m_xComponent->getPropertyValue( _rPropertyName ) );
+ TypeClass eType = aPropertyValue.getValueType().getTypeClass();
+ if( eType == TypeClass_STRING )
+ {
+ OUString aPropStr;
+ aPropertyValue >>= aPropStr;
+ if( aPropStr.getLength() > 1 )
+ {
+ OUString aPureIdStr = aPropStr.copy( 1 );
+ OUString aValueStr;
+ _rValue >>= aValueStr;
+ xStringResourceManager->setString( aPureIdStr, aValueStr );
+ aValue = aPropertyValue; // set value to force modified
+ }
+ }
+ // StringItemList?
+ else if( eType == TypeClass_SEQUENCE )
+ {
+ static const char aDot[] = ".";
+
+ // Put strings into resource using new ids
+ Sequence< OUString > aNewStrings;
+ _rValue >>= aNewStrings;
+
+ const sal_Int32 nNewCount = aNewStrings.getLength();
+
+ // Create new Ids
+ std::unique_ptr<OUString[]> pNewPureIds(new OUString[nNewCount]);
+ Any aNameAny = m_xComponent->getPropertyValue(PROPERTY_NAME);
+ OUString sControlName;
+ aNameAny >>= sControlName;
+ OUString aIdStrBase = aDot
+ + sControlName
+ + aDot
+ + _rPropertyName;
+ sal_Int32 i;
+ for ( i = 0; i < nNewCount; ++i )
+ {
+ sal_Int32 nUniqueId = xStringResourceManager->getUniqueNumericId();
+ OUString aPureIdStr = OUString::number( nUniqueId ) + aIdStrBase;
+ pNewPureIds[i] = aPureIdStr;
+ // Force usage of next Unique Id
+ xStringResourceManager->setString( aPureIdStr, OUString() );
+ }
+
+ // Move strings to new Ids for all locales
+ const Sequence< Locale > aLocaleSeq = xStringResourceManager->getLocales();
+ Sequence< OUString > aOldIdStrings;
+ aPropertyValue >>= aOldIdStrings;
+ try
+ {
+ const OUString* pOldIdStrings = aOldIdStrings.getConstArray();
+ sal_Int32 nOldIdCount = aOldIdStrings.getLength();
+ for ( i = 0; i < nNewCount; ++i )
+ {
+ OUString aOldPureIdStr;
+ if( i < nOldIdCount )
+ {
+ OUString aOldIdStr = pOldIdStrings[i];
+ aOldPureIdStr = aOldIdStr.copy( 1 );
+ }
+ OUString aNewPureIdStr = pNewPureIds[i];
+
+ for ( const Locale& rLocale : aLocaleSeq )
+ {
+ OUString aResourceStr;
+ if( !aOldPureIdStr.isEmpty() )
+ {
+ if( xStringResourceManager->hasEntryForIdAndLocale( aOldPureIdStr, rLocale ) )
+ {
+ aResourceStr = xStringResourceManager->
+ resolveStringForLocale( aOldPureIdStr, rLocale );
+ }
+ }
+ xStringResourceManager->setStringForLocale( aNewPureIdStr, aResourceStr, rLocale );
+ }
+ }
+ }
+ catch( const resource::MissingResourceException & )
+ {}
+
+
+ // Set new strings for current locale and create
+ // new Id sequence as new property value
+ Sequence< OUString > aNewIdStrings;
+ aNewIdStrings.realloc( nNewCount );
+ OUString* pNewIdStrings = aNewIdStrings.getArray();
+ for ( i = 0; i < nNewCount; ++i )
+ {
+ const OUString& aPureIdStr = pNewPureIds[i];
+ const OUString& aStr = aNewStrings[i];
+ xStringResourceManager->setString( aPureIdStr, aStr );
+
+ pNewIdStrings[i] = "&" + aPureIdStr;
+ }
+ aValue <<= aNewIdStrings;
+
+ // Remove old ids from resource for all locales
+ for( const OUString& rIdStr : std::as_const(aOldIdStrings) )
+ {
+ OUString aPureIdStr = rIdStr.copy( 1 );
+ for ( const Locale& rLocale : aLocaleSeq )
+ {
+ try
+ {
+ xStringResourceManager->removeIdForLocale( aPureIdStr, rLocale );
+ }
+ catch( const resource::MissingResourceException & )
+ {}
+ }
+ }
+ }
+ }
+ }
+
+ m_xComponent->setPropertyValue( _rPropertyName, aValue );
+ }
+ }
+
+ Any SAL_CALL FormComponentPropertyHandler::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+ Property aProperty( impl_getPropertyFromId_throw( nPropId ) );
+
+ Any aPropertyValue( _rControlValue );
+ if ( !aPropertyValue.hasValue() )
+ {
+ if ( ( aProperty.Attributes & PropertyAttribute::MAYBEVOID ) == 0 )
+ // default construct an instance of the proper type
+ aPropertyValue = Any( nullptr, aProperty.Type );
+ // nothing to do
+ return aPropertyValue;
+ }
+
+ /// care for the special "default" string, translate it to VOID
+ if ( m_aPropertiesWithDefListEntry.find( _rPropertyName ) != m_aPropertiesWithDefListEntry.end() )
+ {
+ // it's a control with a string list
+ OUString sStringValue;
+ if ( _rControlValue >>= sStringValue )
+ { // note that ColorListBoxes might transfer values either as string or as css.util.Color,
+ // so this check here is important
+ if ( sStringValue == m_sDefaultValueString )
+ return Any();
+ }
+ }
+
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_DATASOURCE:
+ {
+ OUString sControlValue;
+ if( ! (_rControlValue >>= sControlValue) )
+ SAL_WARN("extensions.propctrlr", "convertToPropertyValue: unable to get property " << PROPERTY_ID_DATASOURCE);
+
+ if ( !sControlValue.isEmpty() )
+ {
+ Reference< XDatabaseContext > xDatabaseContext = sdb::DatabaseContext::create( m_xContext );
+ if ( !xDatabaseContext->hasByName( sControlValue ) )
+ {
+ ::svt::OFileNotation aTransformer(sControlValue);
+ aPropertyValue <<= aTransformer.get( ::svt::OFileNotation::N_URL );
+ }
+ }
+ }
+ break; // case PROPERTY_ID_DATASOURCE
+
+ case PROPERTY_ID_SHOW_POSITION:
+ case PROPERTY_ID_SHOW_NAVIGATION:
+ case PROPERTY_ID_SHOW_RECORDACTIONS:
+ case PROPERTY_ID_SHOW_FILTERSORT:
+ {
+ OUString sControlValue;
+ if( ! (_rControlValue >>= sControlValue) )
+ SAL_WARN("extensions.propctrlr", "convertToControlValue: unable to get property for Show/Hide");
+
+ static_assert(SAL_N_ELEMENTS(RID_RSC_ENUM_SHOWHIDE) == 2, "FormComponentPropertyHandler::convertToPropertyValue: broken resource for Show/Hide!");
+ bool bShow = sControlValue == PcrRes(RID_RSC_ENUM_SHOWHIDE[1]);
+
+ aPropertyValue <<= bShow;
+ }
+ break;
+
+ case PROPERTY_ID_TARGET_URL:
+ case PROPERTY_ID_IMAGE_URL:
+ {
+ OUString sControlValue;
+ if( ! (_rControlValue >>= sControlValue) )
+ SAL_WARN("extensions.propctrlr", "convertToPropertyValue: unable to get property for URLs");
+ // Don't convert a placeholder
+ if ( nPropId == PROPERTY_ID_IMAGE_URL && sControlValue == PcrRes(RID_EMBED_IMAGE_PLACEHOLDER) )
+ aPropertyValue <<= sControlValue;
+ else
+ {
+ INetURLObject aDocURL( impl_getDocumentURL_nothrow() );
+ aPropertyValue <<= URIHelper::SmartRel2Abs( aDocURL, sControlValue, Link<OUString *, bool>(), false, true );
+ }
+ }
+ break;
+
+ case PROPERTY_ID_DATEMIN:
+ case PROPERTY_ID_DATEMAX:
+ case PROPERTY_ID_DEFAULT_DATE:
+ case PROPERTY_ID_DATE:
+ {
+ util::Date aDate;
+ if( ! (_rControlValue >>= aDate) )
+ SAL_WARN("extensions.propctrlr", "convertToControlValue: unable to get property for date");
+ aPropertyValue <<= aDate;
+ }
+ break;
+
+ case PROPERTY_ID_TIMEMIN:
+ case PROPERTY_ID_TIMEMAX:
+ case PROPERTY_ID_DEFAULT_TIME:
+ case PROPERTY_ID_TIME:
+ {
+ util::Time aTime;
+ if( ! (_rControlValue >>= aTime) )
+ SAL_WARN("extensions.propctrlr", "convertToControlValue: unable to get property for time");
+ aPropertyValue <<= aTime;
+ }
+ break;
+
+ case PROPERTY_ID_WRITING_MODE:
+ {
+ aPropertyValue = PropertyHandlerComponent::convertToPropertyValue( _rPropertyName, _rControlValue );
+
+ sal_Int16 nNormalizedValue( 2 );
+ if( ! (aPropertyValue >>= nNormalizedValue) )
+ SAL_WARN("extensions.propctrlr", "convertToControlValue: unable to get property for " << PROPERTY_ID_WRITING_MODE);
+
+ sal_Int16 nWritingMode = WritingMode2::CONTEXT;
+ switch ( nNormalizedValue )
+ {
+ case 0: nWritingMode = WritingMode2::LR_TB; break;
+ case 1: nWritingMode = WritingMode2::RL_TB; break;
+ case 2: nWritingMode = WritingMode2::CONTEXT; break;
+ default:
+ OSL_FAIL( "FormComponentPropertyHandler::convertToPropertyValue: unexpected 'normalized value' for WritingMode!" );
+ nWritingMode = WritingMode2::CONTEXT;
+ break;
+ }
+
+ aPropertyValue <<= nWritingMode;
+ }
+ break;
+
+ default:
+ aPropertyValue = PropertyHandlerComponent::convertToPropertyValue( _rPropertyName, _rControlValue );
+ break; // default
+
+ } // switch ( nPropId )
+
+ return aPropertyValue;
+ }
+
+ Any SAL_CALL FormComponentPropertyHandler::convertToControlValue( const OUString& _rPropertyName, const Any& _rPropertyValue, const Type& _rControlValueType )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ sal_Int32 nPropId = m_pInfoService->getPropertyId( _rPropertyName );
+ DBG_ASSERT( nPropId != -1, "FormComponentPropertyHandler::convertToPropertyValue: not one of my properties!!" );
+
+ impl_getPropertyFromId_throw( nPropId );
+
+ Any aControlValue( _rPropertyValue );
+ if ( !aControlValue.hasValue() )
+ {
+ // if the property is represented with a list box or color list box, we need to
+ // translate this into the string "Default"
+ if ( m_aPropertiesWithDefListEntry.find( _rPropertyName ) != m_aPropertiesWithDefListEntry.end() )
+ aControlValue <<= m_sDefaultValueString;
+
+ return aControlValue;
+ }
+
+ switch ( nPropId )
+ {
+
+ case PROPERTY_ID_SHOW_POSITION:
+ case PROPERTY_ID_SHOW_NAVIGATION:
+ case PROPERTY_ID_SHOW_RECORDACTIONS:
+ case PROPERTY_ID_SHOW_FILTERSORT:
+ {
+ static_assert(SAL_N_ELEMENTS(RID_RSC_ENUM_SHOWHIDE) == 2, "FormComponentPropertyHandler::convertToPropertyValue: broken resource for Show/Hide!");
+ OUString sControlValue = ::comphelper::getBOOL(_rPropertyValue)
+ ? PcrRes(RID_RSC_ENUM_SHOWHIDE[1])
+ : PcrRes(RID_RSC_ENUM_SHOWHIDE[0]);
+ aControlValue <<= sControlValue;
+ }
+ break;
+
+
+ case PROPERTY_ID_DATASOURCE:
+ {
+ OSL_ENSURE( _rControlValueType.getTypeClass() == TypeClass_STRING,
+ "FormComponentPropertyHandler::convertToControlValue: wrong ControlValueType!" );
+
+ OUString sDataSource;
+ _rPropertyValue >>= sDataSource;
+ if ( !sDataSource.isEmpty() )
+ {
+ ::svt::OFileNotation aTransformer( sDataSource );
+ sDataSource = aTransformer.get( ::svt::OFileNotation::N_SYSTEM );
+ }
+ aControlValue <<= sDataSource;
+ }
+ break;
+
+
+ case PROPERTY_ID_CONTROLLABEL:
+ {
+ OUString sControlValue;
+
+ Reference< XPropertySet > xSet;
+ _rPropertyValue >>= xSet;
+ Reference< XPropertySetInfo > xPSI;
+ if ( xSet.is() )
+ xPSI = xSet->getPropertySetInfo();
+ if ( xPSI.is() && xPSI->hasPropertyByName( PROPERTY_LABEL ) )
+ {
+ OUString sLabel;
+ if( ! (xSet->getPropertyValue( PROPERTY_LABEL) >>= sLabel) )
+ SAL_WARN("extensions.propctrlr", "convertToPropertyValue: unable to get property " << PROPERTY_LABEL);
+ sControlValue = "<" + sLabel + ">";
+ }
+
+ aControlValue <<= sControlValue;
+ }
+ break;
+
+
+ case PROPERTY_ID_DATEMIN:
+ case PROPERTY_ID_DATEMAX:
+ case PROPERTY_ID_DEFAULT_DATE:
+ case PROPERTY_ID_DATE:
+ {
+ sal_Int32 nDate = 0;
+ if( ! (_rPropertyValue >>= nDate) )
+ SAL_WARN("extensions.propctrlr", "convertToControlValue: unable to get property for dates");
+ aControlValue <<= DBTypeConversion::toDate( nDate );
+ }
+ break;
+
+ case PROPERTY_ID_TIMEMIN:
+ case PROPERTY_ID_TIMEMAX:
+ case PROPERTY_ID_DEFAULT_TIME:
+ case PROPERTY_ID_TIME:
+ {
+ sal_Int64 nTime = 0;
+ if( ! (_rPropertyValue >>= nTime) )
+ SAL_WARN("extensions.propctrlr", "convertToControlValue: unable to get property for times");
+ aControlValue <<= DBTypeConversion::toTime( nTime );
+ }
+ break;
+
+ case PROPERTY_ID_WRITING_MODE:
+ {
+ sal_Int16 nWritingMode( WritingMode2::CONTEXT );
+ if( ! (_rPropertyValue >>= nWritingMode) )
+ SAL_WARN("extensions.propctrlr", "convertToControlValue: unable to get property " << PROPERTY_ID_WRITING_MODE);
+
+ sal_Int16 nNormalized = 2;
+ switch ( nWritingMode )
+ {
+ case WritingMode2::LR_TB: nNormalized = 0; break;
+ case WritingMode2::RL_TB: nNormalized = 1; break;
+ case WritingMode2::CONTEXT: nNormalized = 2; break;
+ default:
+ OSL_FAIL( "FormComponentPropertyHandler::convertToControlValue: unsupported API value for WritingMode!" );
+ nNormalized = 2;
+ break;
+ }
+
+ aControlValue = PropertyHandlerComponent::convertToControlValue( _rPropertyName, Any( nNormalized ), _rControlValueType );
+ }
+ break;
+
+ case PROPERTY_ID_FONT:
+ {
+ FontDescriptor aFont;
+ if( ! (_rPropertyValue >>= aFont) )
+ SAL_WARN("extensions.propctrlr", "convertToControlValue: unable to get property " << PROPERTY_ID_FONT);
+
+ OUStringBuffer displayName;
+ if ( aFont.Name.isEmpty() )
+ {
+ displayName.append( PcrRes(RID_STR_FONT_DEFAULT) );
+ }
+ else
+ {
+ // font name
+ displayName.append( aFont.Name );
+ displayName.append( ", " );
+
+ // font style
+ ::FontWeight eWeight = vcl::unohelper::ConvertFontWeight( aFont.Weight );
+ TranslateId pStyleResID = RID_STR_FONTSTYLE_REGULAR;
+ if ( aFont.Slant == FontSlant_ITALIC )
+ {
+ if ( eWeight > WEIGHT_NORMAL )
+ pStyleResID = RID_STR_FONTSTYLE_BOLD_ITALIC;
+ else
+ pStyleResID = RID_STR_FONTSTYLE_ITALIC;
+ }
+ else
+ {
+ if ( eWeight > WEIGHT_NORMAL )
+ pStyleResID = RID_STR_FONTSTYLE_BOLD;
+ }
+ displayName.append(PcrRes(pStyleResID));
+
+ // font size
+ if ( aFont.Height )
+ {
+ displayName.append( ", " );
+ displayName.append( sal_Int32( aFont.Height ) );
+ }
+ }
+
+ aControlValue <<= displayName.makeStringAndClear();
+ }
+ break;
+
+ default:
+ aControlValue = PropertyHandlerComponent::convertToControlValue( _rPropertyName, _rPropertyValue, _rControlValueType );
+ break;
+
+ } // switch ( nPropId )
+
+ return aControlValue;
+ }
+
+ PropertyState SAL_CALL FormComponentPropertyHandler::getPropertyState( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_xPropertyState.is() )
+ return m_xPropertyState->getPropertyState( _rPropertyName );
+ return PropertyState_DIRECT_VALUE;
+ }
+
+ void SAL_CALL FormComponentPropertyHandler::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyHandlerComponent::addPropertyChangeListener( _rxListener );
+ if ( m_xComponent.is() )
+ m_xComponent->addPropertyChangeListener( OUString(), _rxListener );
+ }
+
+ void SAL_CALL FormComponentPropertyHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_xComponent.is() )
+ m_xComponent->removePropertyChangeListener( OUString(), _rxListener );
+ PropertyHandlerComponent::removePropertyChangeListener( _rxListener );
+ }
+
+ Sequence< Property > FormComponentPropertyHandler::doDescribeSupportedProperties() const
+ {
+ if ( !m_xComponentPropertyInfo.is() )
+ return Sequence< Property >();
+
+ std::vector< Property > aProperties;
+
+ Sequence< Property > aAllProperties( m_xComponentPropertyInfo->getProperties() );
+ aProperties.reserve( aAllProperties.getLength() );
+
+ // filter the properties
+ PropertyId nPropId( 0 );
+ OUString sDisplayName;
+
+ for ( Property & rProperty : asNonConstRange(aAllProperties) )
+ {
+ nPropId = m_pInfoService->getPropertyId( rProperty.Name );
+ if ( nPropId == -1 )
+ continue;
+ rProperty.Handle = nPropId;
+
+ sDisplayName = m_pInfoService->getPropertyTranslation( nPropId );
+ if ( sDisplayName.isEmpty() )
+ continue;
+
+ sal_uInt32 nPropertyUIFlags = m_pInfoService->getPropertyUIFlags( nPropId );
+ bool bIsVisibleForForms = ( nPropertyUIFlags & PROP_FLAG_FORM_VISIBLE ) != 0;
+ bool bIsVisibleForDialogs = ( nPropertyUIFlags & PROP_FLAG_DIALOG_VISIBLE ) != 0;
+
+ // depending on whether we're working for a form or a UNO dialog, some
+ // properties are not displayed
+ if ( ( m_eComponentClass == eFormControl && !bIsVisibleForForms )
+ || ( m_eComponentClass == eDialogControl && !bIsVisibleForDialogs )
+ )
+ continue;
+
+ // some generic sanity checks
+ if ( impl_shouldExcludeProperty_nothrow( rProperty ) )
+ continue;
+
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_BORDER:
+ case PROPERTY_ID_TABSTOP:
+ // BORDER and TABSTOP are normalized (see impl_normalizePropertyValue_nothrow)
+ // to not allow VOID values
+ rProperty.Attributes &= ~PropertyAttribute::MAYBEVOID;
+ break;
+
+ case PROPERTY_ID_LISTSOURCE:
+ // no cursor source if no Base is installed.
+ if ( SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) )
+ const_cast< FormComponentPropertyHandler* >( this )->m_bHaveListSource = true;
+ break;
+
+ case PROPERTY_ID_COMMAND:
+ // no cursor source if no Base is installed.
+ if ( SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) )
+ const_cast< FormComponentPropertyHandler* >( this )->m_bHaveCommand = true;
+ break;
+ } // switch ( nPropId )
+
+ aProperties.push_back( rProperty );
+ }
+
+ if ( aProperties.empty() )
+ return Sequence< Property >();
+ return comphelper::containerToSequence(aProperties);
+ }
+
+ Sequence< OUString > SAL_CALL FormComponentPropertyHandler::getSupersededProperties( )
+ {
+ return Sequence< OUString >( );
+ }
+
+ Sequence< OUString > SAL_CALL FormComponentPropertyHandler::getActuatingProperties( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return
+ {
+ PROPERTY_DATASOURCE,
+ PROPERTY_COMMAND,
+ PROPERTY_COMMANDTYPE,
+ PROPERTY_LISTSOURCE,
+ PROPERTY_LISTSOURCETYPE,
+ PROPERTY_SUBMIT_ENCODING,
+ PROPERTY_REPEAT,
+ PROPERTY_TABSTOP,
+ PROPERTY_BORDER,
+ PROPERTY_CONTROLSOURCE,
+ PROPERTY_DROPDOWN,
+ PROPERTY_IMAGE_URL,
+ PROPERTY_TARGET_URL,
+ PROPERTY_STRINGITEMLIST,
+ PROPERTY_BUTTONTYPE,
+ PROPERTY_ESCAPE_PROCESSING,
+ PROPERTY_TRISTATE,
+ PROPERTY_DECIMAL_ACCURACY,
+ PROPERTY_SHOWTHOUSANDSEP,
+ PROPERTY_FORMATKEY,
+ PROPERTY_EMPTY_IS_NULL,
+ PROPERTY_TOGGLE
+ };
+ }
+
+ LineDescriptor SAL_CALL FormComponentPropertyHandler::describePropertyLine( const OUString& _rPropertyName,
+ const Reference< XPropertyControlFactory >& _rxControlFactory )
+ {
+ if ( !_rxControlFactory.is() )
+ throw NullPointerException();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+ Property aProperty( impl_getPropertyFromId_throw( nPropId ) );
+
+
+ // for the MultiLine property, we have different UI translations depending on the control
+ // type
+ if ( nPropId == PROPERTY_ID_MULTILINE )
+ {
+ if ( ( m_nClassId == FormComponentType::FIXEDTEXT )
+ || ( m_nClassId == FormComponentType::COMMANDBUTTON )
+ || ( m_nClassId == FormComponentType::RADIOBUTTON )
+ || ( m_nClassId == FormComponentType::CHECKBOX )
+ )
+ nPropId = PROPERTY_ID_WORDBREAK;
+ }
+
+ OUString sDisplayName = m_pInfoService->getPropertyTranslation( nPropId );
+ if ( sDisplayName.isEmpty() )
+ {
+ OSL_FAIL( "FormComponentPropertyHandler::describePropertyLine: did getSupportedProperties not work properly?" );
+ throw UnknownPropertyException();
+ }
+
+
+ LineDescriptor aDescriptor;
+ aDescriptor.HelpURL = HelpIdUrl::getHelpURL( m_pInfoService->getPropertyHelpId( nPropId ) );
+ aDescriptor.DisplayName = sDisplayName;
+
+ // for the moment, assume a text field
+ sal_Int16 nControlType = PropertyControlType::TextField;
+ bool bReadOnly = false;
+ aDescriptor.Control.clear();
+
+
+ bool bNeedDefaultStringIfVoidAllowed = false;
+
+ TypeClass eType = aProperty.Type.getTypeClass();
+
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_DEFAULT_SELECT_SEQ:
+ case PROPERTY_ID_SELECTEDITEMS:
+ aDescriptor.PrimaryButtonId = UID_PROP_DLG_SELECTION;
+ break;
+
+ case PROPERTY_ID_FILTER:
+ aDescriptor.PrimaryButtonId = UID_PROP_DLG_FILTER;
+ break;
+
+ case PROPERTY_ID_SORT:
+ aDescriptor.PrimaryButtonId = UID_PROP_DLG_ORDER;
+ break;
+
+ case PROPERTY_ID_MASTERFIELDS:
+ case PROPERTY_ID_DETAILFIELDS:
+ nControlType = PropertyControlType::StringListField;
+ aDescriptor.PrimaryButtonId = UID_PROP_DLG_FORMLINKFIELDS;
+ break;
+
+ case PROPERTY_ID_COMMAND:
+ aDescriptor.PrimaryButtonId = UID_PROP_DLG_SQLCOMMAND;
+ break;
+
+ case PROPERTY_ID_TABINDEX:
+ {
+ Reference< XControlContainer > xControlContext( impl_getContextControlContainer_nothrow() );
+ if ( xControlContext.is() )
+ aDescriptor.PrimaryButtonId = UID_PROP_DLG_TABINDEX;
+ nControlType = PropertyControlType::NumericField;
+ };
+ break;
+
+ case PROPERTY_ID_FONT:
+ bReadOnly = true;
+ aDescriptor.PrimaryButtonId = UID_PROP_DLG_FONT_TYPE;
+ break;
+
+ case PROPERTY_ID_TARGET_URL:
+ case PROPERTY_ID_IMAGE_URL:
+ {
+ std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/urlcontrol.ui", m_xContext));
+ auto pURLBox = std::make_unique<SvtURLBox>(xBuilder->weld_combo_box("urlcontrol"));
+ rtl::Reference<OFileUrlControl> pControl = new OFileUrlControl(std::move(pURLBox), std::move(xBuilder), false);
+ pControl->SetModifyHandler();
+ aDescriptor.Control = pControl;
+
+ aDescriptor.PrimaryButtonId = PROPERTY_ID_TARGET_URL == nPropId
+ ? OUString(UID_PROP_DLG_ATTR_TARGET_URL)
+ : OUString(UID_PROP_DLG_IMAGE_URL);
+ break;
+ }
+
+ case PROPERTY_ID_ECHO_CHAR:
+ nControlType = PropertyControlType::CharacterField;
+ break;
+
+ case PROPERTY_ID_BACKGROUNDCOLOR:
+ case PROPERTY_ID_FILLCOLOR:
+ case PROPERTY_ID_SYMBOLCOLOR:
+ case PROPERTY_ID_BORDERCOLOR:
+ case PROPERTY_ID_GRIDLINECOLOR:
+ case PROPERTY_ID_HEADERBACKGROUNDCOLOR:
+ case PROPERTY_ID_HEADERTEXTCOLOR:
+ case PROPERTY_ID_ACTIVESELECTIONBACKGROUNDCOLOR:
+ case PROPERTY_ID_ACTIVESELECTIONTEXTCOLOR:
+ case PROPERTY_ID_INACTIVESELECTIONBACKGROUNDCOLOR:
+ case PROPERTY_ID_INACTIVESELECTIONTEXTCOLOR:
+ nControlType = PropertyControlType::ColorListBox;
+
+ switch( nPropId )
+ {
+ case PROPERTY_ID_BACKGROUNDCOLOR:
+ aDescriptor.PrimaryButtonId = UID_PROP_DLG_BACKGROUNDCOLOR; break;
+ case PROPERTY_ID_FILLCOLOR:
+ aDescriptor.PrimaryButtonId = UID_PROP_DLG_FILLCOLOR; break;
+ case PROPERTY_ID_SYMBOLCOLOR:
+ aDescriptor.PrimaryButtonId = UID_PROP_DLG_SYMBOLCOLOR; break;
+ case PROPERTY_ID_BORDERCOLOR:
+ aDescriptor.PrimaryButtonId = UID_PROP_DLG_BORDERCOLOR; break;
+ case PROPERTY_ID_GRIDLINECOLOR:
+ aDescriptor.PrimaryButtonId = HID_PROP_GRIDLINECOLOR; break;
+ case PROPERTY_ID_HEADERBACKGROUNDCOLOR:
+ aDescriptor.PrimaryButtonId = HID_PROP_HEADERBACKGROUNDCOLOR; break;
+ case PROPERTY_ID_HEADERTEXTCOLOR:
+ aDescriptor.PrimaryButtonId = HID_PROP_HEADERTEXTCOLOR; break;
+ case PROPERTY_ID_ACTIVESELECTIONBACKGROUNDCOLOR:
+ aDescriptor.PrimaryButtonId = HID_PROP_ACTIVESELECTIONBACKGROUNDCOLOR; break;
+ case PROPERTY_ID_ACTIVESELECTIONTEXTCOLOR:
+ aDescriptor.PrimaryButtonId = HID_PROP_ACTIVESELECTIONTEXTCOLOR; break;
+ case PROPERTY_ID_INACTIVESELECTIONBACKGROUNDCOLOR:
+ aDescriptor.PrimaryButtonId = HID_PROP_INACTIVESELECTIONBACKGROUNDCOLOR; break;
+ case PROPERTY_ID_INACTIVESELECTIONTEXTCOLOR:
+ aDescriptor.PrimaryButtonId = HID_PROP_INACTIVESELECTIONTEXTCOLOR; break;
+ }
+ break;
+
+ case PROPERTY_ID_LABEL:
+ case PROPERTY_ID_URL:
+ nControlType = PropertyControlType::MultiLineTextField;
+ break;
+
+ case PROPERTY_ID_DEFAULT_TEXT:
+ {
+ if (FormComponentType::FILECONTROL == m_nClassId)
+ nControlType = PropertyControlType::TextField;
+ else
+ nControlType = PropertyControlType::MultiLineTextField;
+ }
+ break;
+
+ case PROPERTY_ID_TEXT:
+ if ( impl_componentHasProperty_throw( PROPERTY_MULTILINE ) )
+ nControlType = PropertyControlType::MultiLineTextField;
+ break;
+
+ case PROPERTY_ID_CONTROLLABEL:
+ bReadOnly = true;
+ aDescriptor.PrimaryButtonId = UID_PROP_DLG_CONTROLLABEL;
+ break;
+
+ case PROPERTY_ID_FORMATKEY:
+ case PROPERTY_ID_EFFECTIVE_MIN:
+ case PROPERTY_ID_EFFECTIVE_MAX:
+ case PROPERTY_ID_EFFECTIVE_DEFAULT:
+ case PROPERTY_ID_EFFECTIVE_VALUE:
+ {
+ // and the supplier is really available
+ Reference< XNumberFormatsSupplier > xSupplier;
+ m_xComponent->getPropertyValue( PROPERTY_FORMATSSUPPLIER ) >>= xSupplier;
+ if (xSupplier.is())
+ {
+ Reference< XUnoTunnel > xTunnel(xSupplier,UNO_QUERY);
+ DBG_ASSERT(xTunnel.is(), "FormComponentPropertyHandler::describePropertyLine : xTunnel is invalid!");
+ if (auto pSupplier = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(xTunnel))
+ {
+ bool bIsFormatKey = (PROPERTY_ID_FORMATKEY == nPropId);
+
+ bReadOnly = bIsFormatKey;
+
+ if ( bIsFormatKey )
+ {
+ std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/formattedsample.ui", m_xContext));
+ auto pContainer = xBuilder->weld_container("formattedsample");
+ rtl::Reference<OFormatSampleControl> pControl = new OFormatSampleControl(std::move(pContainer), std::move(xBuilder), false);
+ pControl->SetModifyHandler();
+
+ pControl->SetFormatSupplier(pSupplier);
+
+ aDescriptor.Control = pControl;
+
+ aDescriptor.PrimaryButtonId = UID_PROP_DLG_NUMBER_FORMAT;
+ }
+ else
+ {
+ std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/formattedcontrol.ui", m_xContext));
+ auto pSpinButton = xBuilder->weld_formatted_spin_button("formattedcontrol");
+ rtl::Reference<OFormattedNumericControl> pControl = new OFormattedNumericControl(std::move(pSpinButton), std::move(xBuilder), false);
+ pControl->SetModifyHandler();
+
+ FormatDescription aDesc;
+ aDesc.pSupplier = pSupplier;
+ Any aFormatKeyValue = m_xComponent->getPropertyValue(PROPERTY_FORMATKEY);
+ if ( !( aFormatKeyValue >>= aDesc.nKey ) )
+ aDesc.nKey = 0;
+
+ pControl->SetFormatDescription( aDesc );
+
+ aDescriptor.Control = pControl;
+ }
+ }
+ }
+ }
+ break;
+
+ case PROPERTY_ID_DATEMIN:
+ case PROPERTY_ID_DATEMAX:
+ case PROPERTY_ID_DEFAULT_DATE:
+ case PROPERTY_ID_DATE:
+ nControlType = PropertyControlType::DateField;
+ break;
+
+ case PROPERTY_ID_TIMEMIN:
+ case PROPERTY_ID_TIMEMAX:
+ case PROPERTY_ID_DEFAULT_TIME:
+ case PROPERTY_ID_TIME:
+ nControlType = PropertyControlType::TimeField;
+ break;
+
+ case PROPERTY_ID_VALUEMIN:
+ case PROPERTY_ID_VALUEMAX:
+ case PROPERTY_ID_DEFAULT_VALUE:
+ case PROPERTY_ID_VALUE:
+ {
+ std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/formattedcontrol.ui", m_xContext));
+ auto pSpinButton = xBuilder->weld_formatted_spin_button("formattedcontrol");
+ rtl::Reference<OFormattedNumericControl> pControl = new OFormattedNumericControl(std::move(pSpinButton), std::move(xBuilder), false);
+ pControl->SetModifyHandler();
+ aDescriptor.Control = pControl;
+
+ // we don't set a formatter so the control uses a default (which uses the application
+ // language and a default numeric format)
+ // but we set the decimal digits
+ pControl->SetDecimalDigits(
+ ::comphelper::getINT16( m_xComponent->getPropertyValue( PROPERTY_DECIMAL_ACCURACY ) )
+ );
+
+ // and the default value for the property
+ try
+ {
+ if (m_xPropertyState.is() && ((PROPERTY_ID_VALUEMIN == nPropId) || (PROPERTY_ID_VALUEMAX == nPropId)))
+ {
+ double nDefault = 0;
+ if ( m_xPropertyState->getPropertyDefault( aProperty.Name ) >>= nDefault )
+ pControl->SetDefaultValue(nDefault);
+ }
+ }
+ catch (const Exception&)
+ {
+ // just ignore it
+ }
+
+ break;
+ }
+
+ default:
+ if ( TypeClass_BYTE <= eType && eType <= TypeClass_DOUBLE )
+ {
+ sal_Int16 nDigits = 0;
+ sal_Int16 nValueUnit = -1;
+ sal_Int16 nDisplayUnit = -1;
+ if ( m_eComponentClass == eFormControl )
+ {
+ if ( ( nPropId == PROPERTY_ID_WIDTH )
+ || ( nPropId == PROPERTY_ID_ROWHEIGHT )
+ || ( nPropId == PROPERTY_ID_HEIGHT )
+ )
+ {
+ nValueUnit = MeasureUnit::MM_10TH;
+ nDisplayUnit = impl_getDocumentMeasurementUnit_throw();
+ nDigits = 2;
+ }
+ }
+
+ Optional< double > aValueNotPresent( false, 0 );
+ aDescriptor.Control = PropertyHandlerHelper::createNumericControl(
+ _rxControlFactory, nDigits, aValueNotPresent, aValueNotPresent );
+
+ Reference< XNumericControl > xNumericControl( aDescriptor.Control, UNO_QUERY_THROW );
+ if ( nValueUnit != -1 )
+ xNumericControl->setValueUnit( nValueUnit );
+ if ( nDisplayUnit != -1 )
+ xNumericControl->setDisplayUnit( nDisplayUnit );
+ }
+ break;
+ }
+
+ if ( eType == TypeClass_SEQUENCE )
+ nControlType = PropertyControlType::StringListField;
+
+ // boolean values
+ if ( eType == TypeClass_BOOLEAN )
+ {
+ if ( ( nPropId == PROPERTY_ID_SHOW_POSITION )
+ || ( nPropId == PROPERTY_ID_SHOW_NAVIGATION )
+ || ( nPropId == PROPERTY_ID_SHOW_RECORDACTIONS )
+ || ( nPropId == PROPERTY_ID_SHOW_FILTERSORT )
+ )
+ {
+ aDescriptor.Control = PropertyHandlerHelper::createListBoxControl(_rxControlFactory, RID_RSC_ENUM_SHOWHIDE, SAL_N_ELEMENTS(RID_RSC_ENUM_SHOWHIDE), false);
+ }
+ else
+ aDescriptor.Control = PropertyHandlerHelper::createListBoxControl(_rxControlFactory, RID_RSC_ENUM_YESNO, SAL_N_ELEMENTS(RID_RSC_ENUM_YESNO), false);
+ bNeedDefaultStringIfVoidAllowed = true;
+ }
+
+
+ // enum properties
+ sal_uInt32 nPropertyUIFlags = m_pInfoService->getPropertyUIFlags( nPropId );
+ bool bIsEnumProperty = ( nPropertyUIFlags & PROP_FLAG_ENUM ) != 0;
+ if ( bIsEnumProperty || ( PROPERTY_ID_TARGET_FRAME == nPropId ) )
+ {
+ std::vector< OUString > aEnumValues = m_pInfoService->getPropertyEnumRepresentations( nPropId );
+ std::vector< OUString >::const_iterator pStart = aEnumValues.begin();
+ std::vector< OUString >::const_iterator pEnd = aEnumValues.end();
+
+ // for a checkbox: if "ambiguous" is not allowed, remove this from the sequence
+ if ( ( PROPERTY_ID_DEFAULT_STATE == nPropId )
+ || ( PROPERTY_ID_STATE == nPropId )
+ )
+ {
+ if ( impl_componentHasProperty_throw( PROPERTY_TRISTATE ) )
+ {
+ if ( !::comphelper::getBOOL( m_xComponent->getPropertyValue( PROPERTY_TRISTATE ) ) )
+ { // remove the last sequence element
+ if ( pEnd > pStart )
+ --pEnd;
+ }
+ }
+ else
+ --pEnd;
+ }
+
+ if ( PROPERTY_ID_LISTSOURCETYPE == nPropId )
+ if ( FormComponentType::COMBOBOX == m_nClassId )
+ // remove the first sequence element -> value list not possible for combo boxes
+ ++pStart;
+
+ // copy the sequence
+ std::vector< OUString > aListEntries( pEnd - pStart );
+ std::copy( pStart, pEnd, aListEntries.begin() );
+
+ // create the control
+ if ( PROPERTY_ID_TARGET_FRAME == nPropId )
+ aDescriptor.Control = PropertyHandlerHelper::createComboBoxControl( _rxControlFactory, std::move(aListEntries), false );
+ else
+ {
+ aDescriptor.Control = PropertyHandlerHelper::createListBoxControl( _rxControlFactory, std::move(aListEntries), false, false );
+ bNeedDefaultStringIfVoidAllowed = true;
+ }
+ }
+
+
+ switch( nPropId )
+ {
+ case PROPERTY_ID_REPEAT_DELAY:
+ {
+ std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/numericfield.ui", m_xContext));
+ auto pSpinButton = xBuilder->weld_metric_spin_button("numericfield", FieldUnit::MILLISECOND);
+ rtl::Reference<ONumericControl> pControl = new ONumericControl(std::move(pSpinButton), std::move(xBuilder), bReadOnly);
+ pControl->SetModifyHandler();
+ pControl->setMinValue( Optional< double >( true, 0 ) );
+ pControl->setMaxValue( Optional< double >( true, std::numeric_limits< double >::max() ) );
+ aDescriptor.Control = pControl;
+ }
+ break;
+
+ case PROPERTY_ID_TABINDEX:
+ case PROPERTY_ID_BOUNDCOLUMN:
+ case PROPERTY_ID_VISIBLESIZE:
+ case PROPERTY_ID_MAXTEXTLEN:
+ case PROPERTY_ID_LINEINCREMENT:
+ case PROPERTY_ID_BLOCKINCREMENT:
+ case PROPERTY_ID_SPININCREMENT:
+ {
+ Optional< double > aMinValue( true, 0 );
+ Optional< double > aMaxValue( true, 0x7FFFFFFF );
+
+ if ( nPropId == PROPERTY_ID_MAXTEXTLEN || nPropId == PROPERTY_ID_BOUNDCOLUMN )
+ aMinValue.Value = -1;
+ else if ( nPropId == PROPERTY_ID_VISIBLESIZE )
+ aMinValue.Value = 1;
+ else
+ aMinValue.Value = 0;
+
+ aDescriptor.Control = PropertyHandlerHelper::createNumericControl(
+ _rxControlFactory, 0, aMinValue, aMaxValue );
+ }
+ break;
+
+ case PROPERTY_ID_DECIMAL_ACCURACY:
+ {
+ Optional< double > aMinValue( true, 0 );
+ Optional< double > aMaxValue( true, 20 );
+
+ aDescriptor.Control = PropertyHandlerHelper::createNumericControl(
+ _rxControlFactory, 0, aMinValue, aMaxValue );
+ }
+ break;
+
+
+ // DataSource
+ case PROPERTY_ID_DATASOURCE:
+ {
+ aDescriptor.PrimaryButtonId = UID_PROP_DLG_ATTR_DATASOURCE;
+
+ std::vector< OUString > aListEntries;
+
+ Reference< XDatabaseContext > xDatabaseContext = sdb::DatabaseContext::create( m_xContext );
+ const Sequence< OUString > aDatasources = xDatabaseContext->getElementNames();
+ aListEntries.resize( aDatasources.getLength() );
+ std::copy( aDatasources.begin(), aDatasources.end(), aListEntries.begin() );
+ aDescriptor.Control = PropertyHandlerHelper::createComboBoxControl(
+ _rxControlFactory, std::move(aListEntries), true );
+ }
+ break;
+
+ case PROPERTY_ID_CONTROLSOURCE:
+ {
+ std::vector< OUString > aFieldNames;
+ impl_initFieldList_nothrow( aFieldNames );
+ aDescriptor.Control = PropertyHandlerHelper::createComboBoxControl(
+ _rxControlFactory, std::move(aFieldNames), false );
+ }
+ break;
+
+ case PROPERTY_ID_COMMAND:
+ impl_describeCursorSource_nothrow( aDescriptor, _rxControlFactory );
+ break;
+
+ case PROPERTY_ID_LISTSOURCE:
+ impl_describeListSourceUI_throw( aDescriptor, _rxControlFactory );
+ break;
+ }
+
+ if ( !aDescriptor.Control.is() )
+ aDescriptor.Control = _rxControlFactory->createPropertyControl( nControlType, bReadOnly );
+
+ if ( ( aProperty.Attributes & PropertyAttribute::MAYBEVOID ) != 0 )
+ {
+ // insert the string "Default" string, if necessary
+ if (bNeedDefaultStringIfVoidAllowed)
+ {
+ Reference< XStringListControl > xStringList( aDescriptor.Control, UNO_QUERY_THROW );
+ xStringList->prependListEntry( m_sDefaultValueString );
+ m_aPropertiesWithDefListEntry.insert( _rPropertyName );
+ }
+ }
+
+ if ( !aDescriptor.PrimaryButtonId.isEmpty() )
+ aDescriptor.HasPrimaryButton = true;
+ if ( !aDescriptor.SecondaryButtonId.isEmpty() )
+ aDescriptor.HasSecondaryButton = true;
+
+ bool bIsDataProperty = ( nPropertyUIFlags & PROP_FLAG_DATA_PROPERTY ) != 0;
+ aDescriptor.Category = bIsDataProperty ? std::u16string_view(u"Data") : std::u16string_view(u"General");
+ return aDescriptor;
+ }
+
+ InteractiveSelectionResult SAL_CALL FormComponentPropertyHandler::onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool /*_bPrimary*/, Any& _rData, const Reference< XObjectInspectorUI >& _rxInspectorUI )
+ {
+ if ( !_rxInspectorUI.is() )
+ throw NullPointerException();
+
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ InteractiveSelectionResult eResult = InteractiveSelectionResult_Cancelled;
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_DEFAULT_SELECT_SEQ:
+ case PROPERTY_ID_SELECTEDITEMS:
+ if ( impl_dialogListSelection_nothrow( _rPropertyName, aGuard ) )
+ eResult = InteractiveSelectionResult_Success;
+ break;
+
+ case PROPERTY_ID_FILTER:
+ case PROPERTY_ID_SORT:
+ {
+ OUString sClause;
+ if ( impl_dialogFilterOrSort_nothrow( PROPERTY_ID_FILTER == nPropId, sClause, aGuard ) )
+ {
+ _rData <<= sClause;
+ eResult = InteractiveSelectionResult_ObtainedValue;
+ }
+ }
+ break;
+
+ case PROPERTY_ID_MASTERFIELDS:
+ case PROPERTY_ID_DETAILFIELDS:
+ if ( impl_dialogLinkedFormFields_nothrow( aGuard ) )
+ eResult = InteractiveSelectionResult_Success;
+ break;
+
+ case PROPERTY_ID_FORMATKEY:
+ if ( impl_dialogFormatting_nothrow( _rData, aGuard ) )
+ eResult = InteractiveSelectionResult_ObtainedValue;
+ break;
+
+ case PROPERTY_ID_IMAGE_URL:
+ if ( impl_browseForImage_nothrow( _rData, aGuard ) )
+ eResult = InteractiveSelectionResult_ObtainedValue;
+ break;
+
+ case PROPERTY_ID_TARGET_URL:
+ if ( impl_browseForTargetURL_nothrow( _rData, aGuard ) )
+ eResult = InteractiveSelectionResult_ObtainedValue;
+ break;
+
+ case PROPERTY_ID_FONT:
+ if ( impl_executeFontDialog_nothrow( _rData, aGuard ) )
+ eResult = InteractiveSelectionResult_ObtainedValue;
+ break;
+
+ case PROPERTY_ID_DATASOURCE:
+ if ( impl_browseForDatabaseDocument_throw( _rData, aGuard ) )
+ eResult = InteractiveSelectionResult_ObtainedValue;
+ break;
+
+ case PROPERTY_ID_BACKGROUNDCOLOR:
+ case PROPERTY_ID_FILLCOLOR:
+ case PROPERTY_ID_SYMBOLCOLOR:
+ case PROPERTY_ID_BORDERCOLOR:
+ case PROPERTY_ID_GRIDLINECOLOR:
+ case PROPERTY_ID_HEADERBACKGROUNDCOLOR:
+ case PROPERTY_ID_HEADERTEXTCOLOR:
+ case PROPERTY_ID_ACTIVESELECTIONBACKGROUNDCOLOR:
+ case PROPERTY_ID_ACTIVESELECTIONTEXTCOLOR:
+ case PROPERTY_ID_INACTIVESELECTIONBACKGROUNDCOLOR:
+ case PROPERTY_ID_INACTIVESELECTIONTEXTCOLOR:
+ if ( impl_dialogColorChooser_throw( nPropId, _rData, aGuard ) )
+ eResult = InteractiveSelectionResult_ObtainedValue;
+ break;
+
+ case PROPERTY_ID_CONTROLLABEL:
+ if ( impl_dialogChooseLabelControl_nothrow( _rData, aGuard ) )
+ eResult = InteractiveSelectionResult_ObtainedValue;
+ break;
+
+ case PROPERTY_ID_TABINDEX:
+ if ( impl_dialogChangeTabOrder_nothrow( aGuard ) )
+ eResult = InteractiveSelectionResult_Success;
+ break;
+
+ case PROPERTY_ID_COMMAND:
+ case PROPERTY_ID_LISTSOURCE:
+ if ( impl_doDesignSQLCommand_nothrow( _rxInspectorUI, nPropId ) )
+ eResult = InteractiveSelectionResult_Pending;
+ break;
+ default:
+ OSL_FAIL( "FormComponentPropertyHandler::onInteractivePropertySelection: request for a property which does not have dedicated UI!" );
+ break;
+ }
+ return eResult;
+ }
+
+ namespace
+ {
+ void lcl_rebuildAndResetCommand( const Reference< XObjectInspectorUI >& _rxInspectorUI, const Reference< XPropertyHandler >& _rxHandler )
+ {
+ OSL_PRECOND( _rxInspectorUI.is(), "lcl_rebuildAndResetCommand: invalid BrowserUI!" );
+ OSL_PRECOND( _rxHandler.is(), "lcl_rebuildAndResetCommand: invalid handler!" );
+ _rxInspectorUI->rebuildPropertyUI( PROPERTY_COMMAND );
+ _rxHandler->setPropertyValue( PROPERTY_COMMAND, Any( OUString() ) );
+ }
+ }
+
+ void SAL_CALL FormComponentPropertyHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit )
+ {
+ if ( !_rxInspectorUI.is() )
+ throw NullPointerException();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nActuatingPropId( impl_getPropertyId_nothrow( _rActuatingPropertyName ) );
+
+ std::vector< PropertyId > aDependentProperties;
+
+ switch ( nActuatingPropId )
+ {
+ // ----- EscapeProcessing -----
+ case PROPERTY_ID_ESCAPE_PROCESSING:
+ aDependentProperties.push_back( PROPERTY_ID_FILTER );
+ aDependentProperties.push_back( PROPERTY_ID_SORT );
+ break; // case PROPERTY_ID_ESCAPE_PROCESSING
+
+ // ----- CommandType -----
+ case PROPERTY_ID_COMMANDTYPE:
+ // available commands (tables or queries) might have changed
+ if ( !_bFirstTimeInit && m_bHaveCommand )
+ lcl_rebuildAndResetCommand( _rxInspectorUI, this );
+ aDependentProperties.push_back( PROPERTY_ID_COMMAND );
+ break; // case PROPERTY_ID_COMMANDTYPE
+
+ // ----- DataSourceName -----
+ case PROPERTY_ID_DATASOURCE:
+ // reset the connection, now that we have a new data source
+ m_xRowSetConnection.clear();
+
+ // available list source values (tables or queries) might have changed
+ if ( !_bFirstTimeInit && m_bHaveListSource )
+ _rxInspectorUI->rebuildPropertyUI( PROPERTY_LISTSOURCE );
+
+ // available commands (tables or queries) might have changed
+ if ( !_bFirstTimeInit && m_bHaveCommand )
+ lcl_rebuildAndResetCommand( _rxInspectorUI, this );
+
+ // Command also depends on DataSource
+ aDependentProperties.push_back( PROPERTY_ID_COMMAND );
+ [[fallthrough]];
+
+ // ----- Command -----
+ case PROPERTY_ID_COMMAND:
+ aDependentProperties.push_back( PROPERTY_ID_FILTER );
+ aDependentProperties.push_back( PROPERTY_ID_SORT );
+ if ( m_bComponentIsSubForm )
+ aDependentProperties.push_back( PROPERTY_ID_DETAILFIELDS );
+ break;
+
+ // ----- ListSourceType -----
+ case PROPERTY_ID_LISTSOURCETYPE:
+ if ( !_bFirstTimeInit && m_bHaveListSource )
+ // available list source values (tables or queries) might have changed
+ _rxInspectorUI->rebuildPropertyUI( PROPERTY_LISTSOURCE );
+ aDependentProperties.push_back( PROPERTY_ID_STRINGITEMLIST );
+ aDependentProperties.push_back( PROPERTY_ID_TYPEDITEMLIST );
+ aDependentProperties.push_back( PROPERTY_ID_BOUNDCOLUMN );
+ [[fallthrough]];
+
+ // ----- StringItemList -----
+ case PROPERTY_ID_STRINGITEMLIST:
+ aDependentProperties.push_back( PROPERTY_ID_TYPEDITEMLIST );
+ aDependentProperties.push_back( PROPERTY_ID_SELECTEDITEMS );
+ aDependentProperties.push_back( PROPERTY_ID_DEFAULT_SELECT_SEQ );
+ break;
+
+ // ----- ListSource -----
+ case PROPERTY_ID_LISTSOURCE:
+ aDependentProperties.push_back( PROPERTY_ID_STRINGITEMLIST );
+ aDependentProperties.push_back( PROPERTY_ID_TYPEDITEMLIST );
+ break;
+
+ // ----- DataField -----
+ case PROPERTY_ID_CONTROLSOURCE:
+ {
+ OUString sControlSource;
+ _rNewValue >>= sControlSource;
+ if ( impl_componentHasProperty_throw( PROPERTY_FILTERPROPOSAL ) )
+ _rxInspectorUI->enablePropertyUI( PROPERTY_FILTERPROPOSAL, !sControlSource.isEmpty() );
+ if ( impl_componentHasProperty_throw( PROPERTY_EMPTY_IS_NULL ) )
+ _rxInspectorUI->enablePropertyUI( PROPERTY_EMPTY_IS_NULL, !sControlSource.isEmpty() );
+
+ aDependentProperties.push_back( PROPERTY_ID_BOUNDCOLUMN );
+ aDependentProperties.push_back( PROPERTY_ID_SCALEIMAGE );
+ aDependentProperties.push_back( PROPERTY_ID_SCALE_MODE );
+ aDependentProperties.push_back( PROPERTY_ID_INPUT_REQUIRED );
+ }
+ break;
+
+ case PROPERTY_ID_EMPTY_IS_NULL:
+ aDependentProperties.push_back( PROPERTY_ID_INPUT_REQUIRED );
+ break;
+
+ // ----- SubmitEncoding -----
+ case PROPERTY_ID_SUBMIT_ENCODING:
+ {
+ FormSubmitEncoding eEncoding = FormSubmitEncoding_URL;
+ if( ! (_rNewValue >>= eEncoding) )
+ SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_SUBMIT_ENCODING);
+ _rxInspectorUI->enablePropertyUI( PROPERTY_SUBMIT_METHOD, eEncoding == FormSubmitEncoding_URL );
+ }
+ break;
+
+ // ----- Repeat -----
+ case PROPERTY_ID_REPEAT:
+ {
+ bool bIsRepeating = false;
+ if( ! (_rNewValue >>= bIsRepeating) )
+ SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_REPEAT);
+ _rxInspectorUI->enablePropertyUI( PROPERTY_REPEAT_DELAY, bIsRepeating );
+ }
+ break;
+
+ // ----- TabStop -----
+ case PROPERTY_ID_TABSTOP:
+ {
+ if ( !impl_componentHasProperty_throw( PROPERTY_TABINDEX ) )
+ break;
+ bool bHasTabStop = false;
+ _rNewValue >>= bHasTabStop;
+ _rxInspectorUI->enablePropertyUI( PROPERTY_TABINDEX, bHasTabStop );
+ }
+ break;
+
+ // ----- Border -----
+ case PROPERTY_ID_BORDER:
+ {
+ sal_Int16 nBordeType = VisualEffect::NONE;
+ if( ! (_rNewValue >>= nBordeType) )
+ SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_BORDER);
+ _rxInspectorUI->enablePropertyUI( PROPERTY_BORDERCOLOR, nBordeType == VisualEffect::FLAT );
+ }
+ break;
+
+ // ----- DropDown -----
+ case PROPERTY_ID_DROPDOWN:
+ {
+ if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_LINECOUNT ) )
+ {
+ bool bDropDown = true;
+ _rNewValue >>= bDropDown;
+ _rxInspectorUI->enablePropertyUI( PROPERTY_LINECOUNT, bDropDown );
+ }
+ }
+ break;
+
+ // ----- ImageURL -----
+ case PROPERTY_ID_IMAGE_URL:
+ {
+ if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_IMAGEPOSITION ) )
+ {
+ OUString sImageURL;
+ if( ! (_rNewValue >>= sImageURL) )
+ SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_IMAGE_URL);
+ _rxInspectorUI->enablePropertyUI( PROPERTY_IMAGEPOSITION, !sImageURL.isEmpty() );
+ }
+
+ aDependentProperties.push_back( PROPERTY_ID_SCALEIMAGE );
+ aDependentProperties.push_back( PROPERTY_ID_SCALE_MODE );
+ }
+ break;
+
+ // ----- ButtonType -----
+ case PROPERTY_ID_BUTTONTYPE:
+ {
+ FormButtonType eButtonType( FormButtonType_PUSH );
+ if( ! (_rNewValue >>= eButtonType) )
+ SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_BUTTONTYPE);
+ _rxInspectorUI->enablePropertyUI( PROPERTY_TARGET_URL, FormButtonType_URL == eButtonType );
+ [[fallthrough]];
+ }
+
+ // ----- TargetURL -----
+ case PROPERTY_ID_TARGET_URL:
+ aDependentProperties.push_back( PROPERTY_ID_TARGET_FRAME );
+ break; // case PROPERTY_ID_TARGET_URL
+
+ // ----- TriState -----
+ case PROPERTY_ID_TRISTATE:
+ if ( !_bFirstTimeInit )
+ _rxInspectorUI->rebuildPropertyUI( m_eComponentClass == eFormControl ? OUString(PROPERTY_DEFAULT_STATE) : OUString(PROPERTY_STATE) );
+ break; // case PROPERTY_ID_TRISTATE
+
+ // ----- DecimalAccuracy -----
+ case PROPERTY_ID_DECIMAL_ACCURACY:
+ // ----- ShowThousandsSeparator -----
+ case PROPERTY_ID_SHOWTHOUSANDSEP:
+ {
+ bool bAccuracy = (PROPERTY_ID_DECIMAL_ACCURACY == nActuatingPropId);
+ sal_uInt16 nNewDigits = 0;
+ if ( bAccuracy )
+ {
+ if( ! (_rNewValue >>= nNewDigits) )
+ SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_DECIMAL_ACCURACY);
+ }
+ else
+ {
+ bool bUseSep = false;
+ if( ! (_rNewValue >>= bUseSep) )
+ SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_SHOWTHOUSANDSEP);
+ }
+
+ // propagate the changes to the min/max/default fields
+ OUString aAffectedProps[] = { OUString(PROPERTY_VALUE), OUString(PROPERTY_DEFAULT_VALUE), OUString(PROPERTY_VALUEMIN), OUString(PROPERTY_VALUEMAX) };
+ for (const OUString & aAffectedProp : aAffectedProps)
+ {
+ Reference< XPropertyControl > xControl;
+ try
+ {
+ xControl = _rxInspectorUI->getPropertyControl( aAffectedProp );
+ }
+ catch( const UnknownPropertyException& ) {}
+ if ( xControl.is() )
+ {
+ OFormattedNumericControl* pControl = dynamic_cast< OFormattedNumericControl* >( xControl.get() );
+ DBG_ASSERT( pControl, "FormComponentPropertyHandler::actuatingPropertyChanged: invalid control!" );
+ if (pControl)
+ {
+ if ( bAccuracy )
+ pControl->SetDecimalDigits( nNewDigits );
+ }
+ }
+ }
+ }
+ break;
+
+ // ----- FormatKey -----
+ case PROPERTY_ID_FORMATKEY:
+ {
+ FormatDescription aNewDesc;
+
+ Reference< XNumberFormatsSupplier > xSupplier;
+ if( ! (m_xComponent->getPropertyValue( PROPERTY_FORMATSSUPPLIER ) >>= xSupplier) )
+ SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_FORMATKEY);
+
+ Reference< XUnoTunnel > xTunnel( xSupplier, UNO_QUERY );
+ DBG_ASSERT(xTunnel.is(), "FormComponentPropertyHandler::actuatingPropertyChanged: xTunnel is invalid!");
+ if ( xTunnel.is() )
+ {
+ SvNumberFormatsSupplierObj* pSupplier = reinterpret_cast<SvNumberFormatsSupplierObj*>(xTunnel->getSomething(SvNumberFormatsSupplierObj::getUnoTunnelId()));
+ // the same again
+
+ aNewDesc.pSupplier = pSupplier;
+ if ( !( _rNewValue >>= aNewDesc.nKey ) )
+ aNewDesc.nKey = 0;
+
+ // give each control which has to know this an own copy of the description
+ OUString aFormattedPropertyControls[] = {
+ OUString(PROPERTY_EFFECTIVE_MIN), OUString(PROPERTY_EFFECTIVE_MAX), OUString(PROPERTY_EFFECTIVE_DEFAULT), OUString(PROPERTY_EFFECTIVE_VALUE)
+ };
+ for (const OUString & aFormattedPropertyControl : aFormattedPropertyControls)
+ {
+ Reference< XPropertyControl > xControl;
+ try
+ {
+ xControl = _rxInspectorUI->getPropertyControl( aFormattedPropertyControl );
+ }
+ catch( const UnknownPropertyException& ) {}
+ if ( xControl.is() )
+ {
+ OFormattedNumericControl* pControl = dynamic_cast< OFormattedNumericControl* >( xControl.get() );
+ DBG_ASSERT( pControl, "FormComponentPropertyHandler::actuatingPropertyChanged: invalid control!" );
+ if ( pControl )
+ pControl->SetFormatDescription( aNewDesc );
+ }
+ }
+ }
+ }
+ break;
+
+ case PROPERTY_ID_TOGGLE:
+ {
+ bool bIsToggleButton = false;
+ if( ! (_rNewValue >>= bIsToggleButton) )
+ SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_TOGGLE);
+ _rxInspectorUI->enablePropertyUI( PROPERTY_DEFAULT_STATE, bIsToggleButton );
+ }
+ break;
+ case -1:
+ throw RuntimeException();
+ break;
+ default:
+ OSL_FAIL( "FormComponentPropertyHandler::actuatingPropertyChanged: did not register for this property!" );
+ break;
+
+ } // switch ( nActuatingPropId )
+
+ for (auto const& dependentProperty : aDependentProperties)
+ {
+ if ( impl_isSupportedProperty_nothrow(dependentProperty) )
+ impl_updateDependentProperty_nothrow(dependentProperty, _rxInspectorUI);
+ }
+ }
+
+ void FormComponentPropertyHandler::impl_updateDependentProperty_nothrow( PropertyId _nPropId, const Reference< XObjectInspectorUI >& _rxInspectorUI ) const
+ {
+ try
+ {
+ switch ( _nPropId )
+ {
+ // ----- StringItemList -----
+ case PROPERTY_ID_STRINGITEMLIST:
+ {
+ ListSourceType eLSType = ListSourceType_VALUELIST;
+ if( ! (impl_getPropertyValue_throw( PROPERTY_LISTSOURCETYPE ) >>= eLSType) )
+ SAL_WARN("extensions.propctrlr", "impl_updateDependentProperty_nothrow: unable to get property " << PROPERTY_LISTSOURCETYPE);
+
+ OUString sListSource;
+ {
+ Sequence< OUString > aListSource;
+ Any aListSourceValue( impl_getPropertyValue_throw( PROPERTY_LISTSOURCE ) );
+ if ( aListSourceValue >>= aListSource )
+ {
+ if ( aListSource.hasElements() )
+ sListSource = aListSource[0];
+ }
+ else
+ if( ! (aListSourceValue >>= sListSource) )
+ SAL_WARN("extensions.propctrlr", "impl_updateDependentProperty_nothrow: unable to get property " << PROPERTY_LISTSOURCE);
+ }
+
+ bool bIsEnabled = ( ( eLSType == ListSourceType_VALUELIST )
+ || ( sListSource.isEmpty() )
+ );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_STRINGITEMLIST, bIsEnabled );
+ }
+ break; // case PROPERTY_ID_STRINGITEMLIST
+
+ // ----- TypedItemList -----
+ case PROPERTY_ID_TYPEDITEMLIST:
+ {
+ /* TODO: anything? */
+ }
+ break; // case PROPERTY_ID_TYPEDITEMLIST
+
+ // ----- BoundColumn -----
+ case PROPERTY_ID_BOUNDCOLUMN:
+ {
+ ListSourceType eLSType = ListSourceType_VALUELIST;
+ if( ! (impl_getPropertyValue_throw( PROPERTY_LISTSOURCETYPE ) >>= eLSType) )
+ SAL_WARN("extensions.propctrlr", "impl_updateDependentProperty_nothrow: unable to get property " << PROPERTY_LISTSOURCETYPE);
+
+ _rxInspectorUI->enablePropertyUI( PROPERTY_BOUNDCOLUMN,
+ ( eLSType != ListSourceType_VALUELIST )
+ );
+ }
+ break; // case PROPERTY_ID_BOUNDCOLUMN
+
+ // ----- ScaleImage, ScaleMode -----
+ case PROPERTY_ID_SCALEIMAGE:
+ case PROPERTY_ID_SCALE_MODE:
+ {
+ OUString sControlSource;
+ if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_CONTROLSOURCE ) )
+ impl_getPropertyValue_throw( PROPERTY_CONTROLSOURCE ) >>= sControlSource;
+
+ OUString sImageURL;
+ impl_getPropertyValue_throw( PROPERTY_IMAGE_URL ) >>= sImageURL;
+
+ _rxInspectorUI->enablePropertyUI( impl_getPropertyNameFromId_nothrow( _nPropId ),
+ ( !sControlSource.isEmpty() ) || ( !sImageURL.isEmpty() )
+ );
+ }
+ break; // case PROPERTY_ID_SCALEIMAGE, PROPERTY_ID_SCALE_MODE
+
+ // ----- InputRequired -----
+ case PROPERTY_ID_INPUT_REQUIRED:
+ {
+ OUString sControlSource;
+ if( ! (impl_getPropertyValue_throw( PROPERTY_CONTROLSOURCE ) >>= sControlSource) )
+ SAL_WARN("extensions.propctrlr", "impl_updateDependentProperty_nothrow: unable to get property " << PROPERTY_CONTROLSOURCE);
+
+ bool bEmptyIsNULL = false;
+ bool bHasEmptyIsNULL = impl_componentHasProperty_throw( PROPERTY_EMPTY_IS_NULL );
+ if ( bHasEmptyIsNULL )
+ if( ! (impl_getPropertyValue_throw( PROPERTY_EMPTY_IS_NULL ) >>= bEmptyIsNULL) )
+ SAL_WARN("extensions.propctrlr", "impl_updateDependentProperty_nothrow: unable to get property " << PROPERTY_EMPTY_IS_NULL);
+
+ // if the control is not bound to a DB field, there is no sense in having the "Input required"
+ // property
+ // Also, if an empty input of this control are *not* written as NULL, but as empty strings,
+ // then "Input required" does not make sense, too (since there's always an input, even if the control
+ // is empty).
+ _rxInspectorUI->enablePropertyUI( PROPERTY_INPUT_REQUIRED,
+ ( !sControlSource.isEmpty() ) && ( !bHasEmptyIsNULL || bEmptyIsNULL )
+ );
+ }
+ break;
+
+ // ----- SelectedItems, DefaultSelection -----
+ case PROPERTY_ID_SELECTEDITEMS:
+ case PROPERTY_ID_DEFAULT_SELECT_SEQ:
+ {
+ Sequence< OUString > aEntries;
+ impl_getPropertyValue_throw( PROPERTY_STRINGITEMLIST ) >>= aEntries;
+ bool isEnabled = aEntries.hasElements();
+
+ if ( ( m_nClassId == FormComponentType::LISTBOX ) && ( m_eComponentClass == eFormControl ) )
+ {
+ ListSourceType eLSType = ListSourceType_VALUELIST;
+ impl_getPropertyValue_throw( PROPERTY_LISTSOURCETYPE ) >>= eLSType;
+ isEnabled &= ( eLSType == ListSourceType_VALUELIST );
+ }
+ _rxInspectorUI->enablePropertyUIElements( impl_getPropertyNameFromId_nothrow( _nPropId ),
+ PropertyLineElement::PrimaryButton, isEnabled );
+ }
+ break; // case PROPERTY_ID_DEFAULT_SELECT_SEQ
+
+ // ----- TargetFrame ------
+ case PROPERTY_ID_TARGET_FRAME:
+ {
+ OUString sTargetURL;
+ impl_getPropertyValue_throw( PROPERTY_TARGET_URL ) >>= sTargetURL;
+ FormButtonType eButtonType( FormButtonType_URL );
+ if ( 0 != m_nClassId )
+ {
+ if( ! (impl_getPropertyValue_throw( PROPERTY_BUTTONTYPE ) >>= eButtonType) )
+ SAL_WARN("extensions.propctrlr", "impl_updateDependentProperty_nothrow: unable to get property " << PROPERTY_BUTTONTYPE);
+ }
+ // if m_nClassId is 0, then we're inspecting a form. In this case, eButtonType is always
+ // FormButtonType_URL here
+ _rxInspectorUI->enablePropertyUI( PROPERTY_TARGET_FRAME,
+ ( eButtonType == FormButtonType_URL ) && ( !sTargetURL.isEmpty() )
+ );
+ }
+ break;
+
+ // ----- Order ------
+ case PROPERTY_ID_SORT:
+ // ----- Filter ------
+ case PROPERTY_ID_FILTER:
+ {
+ Reference< XConnection > xConnection;
+ bool bAllowEmptyDS = ::dbtools::isEmbeddedInDatabase( m_xComponent, xConnection );
+
+ // if there's no escape processing, we cannot enter any values for this property
+ bool bDoEscapeProcessing( false );
+ impl_getPropertyValue_throw( PROPERTY_ESCAPE_PROCESSING ) >>= bDoEscapeProcessing;
+ _rxInspectorUI->enablePropertyUI(
+ impl_getPropertyNameFromId_nothrow( _nPropId ),
+ bDoEscapeProcessing
+ );
+
+ // also care for the browse button - enabled if we have escape processing, and a valid
+ // data source signature
+ _rxInspectorUI->enablePropertyUIElements(
+ impl_getPropertyNameFromId_nothrow( _nPropId ),
+ PropertyLineElement::PrimaryButton,
+ impl_hasValidDataSourceSignature_nothrow( m_xComponent, bAllowEmptyDS )
+ && bDoEscapeProcessing
+ );
+ }
+ break; // case PROPERTY_ID_FILTER:
+
+ // ----- Command -----
+ case PROPERTY_ID_COMMAND:
+ {
+ sal_Int32 nCommandType( CommandType::COMMAND );
+ if( ! (impl_getPropertyValue_throw( PROPERTY_COMMANDTYPE ) >>= nCommandType) )
+ SAL_WARN("extensions.propctrlr", "impl_updateDependentProperty_nothrow: unable to get property " << PROPERTY_COMMANDTYPE);
+
+ impl_ensureRowsetConnection_nothrow();
+ Reference< XConnection > xConnection = m_xRowSetConnection.getTyped();
+ bool bAllowEmptyDS = false;
+ if ( !xConnection.is() )
+ bAllowEmptyDS = ::dbtools::isEmbeddedInDatabase( m_xComponent, xConnection );
+
+ bool doEnable = ( nCommandType == CommandType::COMMAND )
+ && ( m_xRowSetConnection.is()
+ || xConnection.is()
+ || impl_hasValidDataSourceSignature_nothrow( m_xComponent, bAllowEmptyDS)
+ );
+
+ _rxInspectorUI->enablePropertyUIElements(
+ PROPERTY_COMMAND,
+ PropertyLineElement::PrimaryButton,
+ doEnable
+ );
+ }
+ break; // case PROPERTY_ID_COMMAND
+
+ // ----- DetailFields -----
+ case PROPERTY_ID_DETAILFIELDS:
+ {
+ Reference< XConnection > xConnection;
+ bool bAllowEmptyDS = ::dbtools::isEmbeddedInDatabase( m_xComponent, xConnection );
+
+ // both our current form, and its parent form, need to have a valid
+ // data source signature
+ bool bDoEnableMasterDetailFields =
+ impl_hasValidDataSourceSignature_nothrow( m_xComponent, bAllowEmptyDS )
+ && impl_hasValidDataSourceSignature_nothrow( Reference< XPropertySet >( m_xObjectParent, UNO_QUERY ), bAllowEmptyDS );
+
+ // in opposite to the other properties, here in real *two* properties are
+ // affected
+ _rxInspectorUI->enablePropertyUIElements( PROPERTY_DETAILFIELDS, PropertyLineElement::PrimaryButton, bDoEnableMasterDetailFields );
+ _rxInspectorUI->enablePropertyUIElements( PROPERTY_MASTERFIELDS, PropertyLineElement::PrimaryButton, bDoEnableMasterDetailFields );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "FormComponentPropertyHandler::impl_updateDependentProperty_nothrow: unexpected property to update!" );
+ break;
+
+ } // switch
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::impl_updateDependentProperty_nothrow" );
+ }
+ }
+
+ void SAL_CALL FormComponentPropertyHandler::disposing()
+ {
+ PropertyHandlerComponent::disposing();
+ if ( m_xCommandDesigner.is() && m_xCommandDesigner->isActive() )
+ m_xCommandDesigner->dispose();
+ }
+
+ sal_Bool SAL_CALL FormComponentPropertyHandler::suspend( sal_Bool _bSuspend )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( _bSuspend )
+ if ( m_xCommandDesigner.is() && m_xCommandDesigner->isActive() )
+ return m_xCommandDesigner->suspend();
+ return true;
+ }
+
+ void FormComponentPropertyHandler::onNewComponent()
+ {
+ PropertyHandlerComponent::onNewComponent();
+ if ( !m_xComponentPropertyInfo.is() && m_xComponent.is() )
+ throw NullPointerException();
+
+ m_xPropertyState.set( m_xComponent, UNO_QUERY );
+ m_eComponentClass = eUnknown;
+ m_bComponentIsSubForm = m_bHaveListSource = m_bHaveCommand = false;
+ m_nClassId = 0;
+
+ try
+ {
+ // component class
+ m_eComponentClass = eUnknown;
+
+ if ( impl_componentHasProperty_throw( PROPERTY_WIDTH )
+ && impl_componentHasProperty_throw( PROPERTY_HEIGHT )
+ && impl_componentHasProperty_throw( PROPERTY_POSITIONX )
+ && impl_componentHasProperty_throw( PROPERTY_POSITIONY )
+ && impl_componentHasProperty_throw( PROPERTY_STEP )
+ && impl_componentHasProperty_throw( PROPERTY_TABINDEX )
+ )
+ {
+ m_eComponentClass = eDialogControl;
+ }
+ else
+ {
+ m_eComponentClass = eFormControl;
+ }
+
+
+ // (database) sub form?
+ Reference< XForm > xAsForm( m_xComponent, UNO_QUERY );
+ if ( xAsForm.is() )
+ {
+ Reference< XForm > xFormsParent( xAsForm->getParent(), css::uno::UNO_QUERY );
+ m_bComponentIsSubForm = xFormsParent.is();
+ }
+
+
+ // ClassId
+ Reference< XChild > xCompAsChild( m_xComponent, UNO_QUERY );
+ if ( xCompAsChild.is() )
+ m_xObjectParent = xCompAsChild->getParent();
+
+
+ // ClassId
+ impl_classifyControlModel_throw();
+ }
+ catch( const RuntimeException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::onNewComponent" );
+ }
+ }
+
+ void FormComponentPropertyHandler::impl_classifyControlModel_throw( )
+ {
+ if ( impl_componentHasProperty_throw( PROPERTY_CLASSID ) )
+ {
+ if( ! (m_xComponent->getPropertyValue( PROPERTY_CLASSID ) >>= m_nClassId) )
+ SAL_WARN("extensions.propctrlr", "impl_classifyControlModel_throw: unable to get property " << PROPERTY_CLASSID);
+ }
+ else if ( eDialogControl == m_eComponentClass )
+ {
+ Reference< XServiceInfo > xServiceInfo( m_xComponent, UNO_QUERY );
+ if ( xServiceInfo.is() )
+ {
+ // it's a control model, and can tell about it's supported services
+ m_nClassId = FormComponentType::CONTROL;
+
+ const char* aControlModelServiceNames[] =
+ {
+ "UnoControlButtonModel",
+ "UnoControlCheckBoxModel",
+ "UnoControlComboBoxModel",
+ "UnoControlCurrencyFieldModel",
+ "UnoControlDateFieldModel",
+ "UnoControlEditModel",
+ "UnoControlFileControlModel",
+ "UnoControlFixedTextModel",
+ "UnoControlGroupBoxModel",
+ "UnoControlImageControlModel",
+ "UnoControlListBoxModel",
+ "UnoControlNumericFieldModel",
+ "UnoControlPatternFieldModel",
+ "UnoControlRadioButtonModel",
+ "UnoControlScrollBarModel",
+ "UnoControlSpinButtonModel",
+ "UnoControlTimeFieldModel",
+
+ "UnoControlFixedLineModel",
+ "UnoControlFormattedFieldModel",
+ "UnoControlProgressBarModel"
+ };
+ const sal_Int16 nClassIDs[] =
+ {
+ FormComponentType::COMMANDBUTTON,
+ FormComponentType::CHECKBOX,
+ FormComponentType::COMBOBOX,
+ FormComponentType::CURRENCYFIELD,
+ FormComponentType::DATEFIELD,
+ FormComponentType::TEXTFIELD,
+ FormComponentType::FILECONTROL,
+ FormComponentType::FIXEDTEXT,
+ FormComponentType::GROUPBOX,
+ FormComponentType::IMAGECONTROL,
+ FormComponentType::LISTBOX,
+ FormComponentType::NUMERICFIELD,
+ FormComponentType::PATTERNFIELD,
+ FormComponentType::RADIOBUTTON,
+ FormComponentType::SCROLLBAR,
+ FormComponentType::SPINBUTTON,
+ FormComponentType::TIMEFIELD,
+
+ ControlType::FIXEDLINE,
+ ControlType::FORMATTEDFIELD,
+ ControlType::PROGRESSBAR
+ };
+
+ sal_Int32 nKnownControlTypes = SAL_N_ELEMENTS( aControlModelServiceNames );
+ OSL_ENSURE( nKnownControlTypes == SAL_N_ELEMENTS( nClassIDs ),
+ "FormComponentPropertyHandler::impl_classifyControlModel_throw: inconsistence" );
+
+ for ( sal_Int32 i = 0; i < nKnownControlTypes; ++i )
+ {
+ OUString sServiceName = "com.sun.star.awt." +
+ OUString::createFromAscii( aControlModelServiceNames[ i ] );
+
+ if ( xServiceInfo->supportsService( sServiceName ) )
+ {
+ m_nClassId = nClassIDs[ i ];
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ void FormComponentPropertyHandler::impl_normalizePropertyValue_nothrow( Any& _rValue, PropertyId _nPropId ) const
+ {
+ switch ( _nPropId )
+ {
+ case PROPERTY_ID_TABSTOP:
+ if ( !_rValue.hasValue() )
+ {
+ switch ( m_nClassId )
+ {
+ case FormComponentType::COMMANDBUTTON:
+ case FormComponentType::RADIOBUTTON:
+ case FormComponentType::CHECKBOX:
+ case FormComponentType::TEXTFIELD:
+ case FormComponentType::LISTBOX:
+ case FormComponentType::COMBOBOX:
+ case FormComponentType::FILECONTROL:
+ case FormComponentType::DATEFIELD:
+ case FormComponentType::TIMEFIELD:
+ case FormComponentType::NUMERICFIELD:
+ case ControlType::FORMATTEDFIELD:
+ case FormComponentType::CURRENCYFIELD:
+ case FormComponentType::PATTERNFIELD:
+ _rValue <<= true;
+ break;
+ default:
+ _rValue <<= false;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ bool FormComponentPropertyHandler::isReportModel() const
+ {
+ Reference<XModel> xModel(impl_getContextDocument_nothrow());
+ Reference<XReportDefinition> xReportDef(xModel, css::uno::UNO_QUERY);
+ return xReportDef.is();
+ }
+
+ bool FormComponentPropertyHandler::impl_shouldExcludeProperty_nothrow( const Property& _rProperty ) const
+ {
+ OSL_ENSURE( _rProperty.Handle == m_pInfoService->getPropertyId( _rProperty.Name ),
+ "FormComponentPropertyHandler::impl_shouldExcludeProperty_nothrow: inconsistency in the property!" );
+
+ if ( _rProperty.Handle == PROPERTY_ID_CONTROLLABEL )
+ // prevent that this is caught below
+ return false;
+
+ if ( ( _rProperty.Type.getTypeClass() == TypeClass_INTERFACE )
+ || ( _rProperty.Type.getTypeClass() == TypeClass_UNKNOWN )
+ )
+ return true;
+
+ if ( ( _rProperty.Attributes & PropertyAttribute::TRANSIENT ) && ( m_eComponentClass != eDialogControl ) )
+ // strange enough, dialog controls declare a lot of their properties as transient
+ return true;
+
+ if ( _rProperty.Attributes & PropertyAttribute::READONLY )
+ return true;
+
+ switch ( _rProperty.Handle )
+ {
+ case PROPERTY_ID_MASTERFIELDS:
+ case PROPERTY_ID_DETAILFIELDS:
+ if ( !m_bComponentIsSubForm )
+ // no master and detail fields for forms which are no sub forms
+ return true;
+ break;
+
+ case PROPERTY_ID_DATASOURCE:
+ {
+ // don't show DataSource if the component is part of an embedded form document
+ Reference< XConnection > xConn;
+ if ( isEmbeddedInDatabase( m_xComponent, xConn ) )
+ return true;
+ }
+ break;
+
+ case PROPERTY_ID_TEXT:
+ // don't show the "Text" property of formatted fields
+ if ( ControlType::FORMATTEDFIELD == m_nClassId )
+ return true;
+ break;
+
+ case PROPERTY_ID_FORMATKEY:
+ case PROPERTY_ID_EFFECTIVE_MIN:
+ case PROPERTY_ID_EFFECTIVE_MAX:
+ case PROPERTY_ID_EFFECTIVE_DEFAULT:
+ case PROPERTY_ID_EFFECTIVE_VALUE:
+ // only if the set has a formats supplier, too
+ if ( !impl_componentHasProperty_throw( PROPERTY_FORMATSSUPPLIER ) )
+ return true;
+ // (form) date and time fields also have a formats supplier, but the format itself
+ // is reflected in another property
+ if ( ( FormComponentType::DATEFIELD == m_nClassId )
+ || ( FormComponentType::TIMEFIELD == m_nClassId )
+ )
+ return true;
+ break;
+
+ case PROPERTY_ID_SCALEIMAGE:
+ if ( impl_componentHasProperty_throw( PROPERTY_SCALE_MODE ) )
+ // ScaleImage is superseded by ScaleMode
+ return true;
+ break;
+
+ case PROPERTY_ID_WRITING_MODE:
+ if ( !SvtCTLOptions().IsCTLFontEnabled() )
+ return true;
+ break;
+ }
+
+ sal_uInt32 nPropertyUIFlags = m_pInfoService->getPropertyUIFlags( _rProperty.Handle );
+
+ // don't show experimental properties unless allowed to do so
+ if ( ( nPropertyUIFlags & PROP_FLAG_EXPERIMENTAL ) != 0 )
+ return true;
+
+ // no data properties if no Base is installed.
+ if ( ( nPropertyUIFlags & PROP_FLAG_DATA_PROPERTY ) != 0 )
+ if ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) )
+ return true;
+
+ if ((nPropertyUIFlags & PROP_FLAG_REPORT_INVISIBLE) != 0 && isReportModel())
+ return true;
+
+ return false;
+ }
+
+ Reference< XRowSet > FormComponentPropertyHandler::impl_getRowSet_throw( ) const
+ {
+ Reference< XRowSet > xRowSet = m_xRowSet;
+ if ( !xRowSet.is() )
+ {
+ xRowSet.set( m_xComponent, UNO_QUERY );
+ if ( !xRowSet.is() )
+ {
+ xRowSet.set( m_xObjectParent, UNO_QUERY );
+ if ( !xRowSet.is() )
+ {
+ // are we inspecting a grid column?
+ if (Reference< XGridColumnFactory >( m_xObjectParent, UNO_QUERY) .is())
+ { // yes
+ Reference< XChild > xParentAsChild( m_xObjectParent, UNO_QUERY );
+ if ( xParentAsChild.is() )
+ xRowSet.set( xParentAsChild->getParent(), UNO_QUERY );
+ }
+ }
+ if ( !xRowSet.is() )
+ xRowSet = m_xRowSet;
+ }
+ DBG_ASSERT( xRowSet.is(), "FormComponentPropertyHandler::impl_getRowSet_throw: could not obtain the rowset for the introspectee!" );
+ }
+ return xRowSet;
+ }
+
+
+ Reference< XRowSet > FormComponentPropertyHandler::impl_getRowSet_nothrow( ) const
+ {
+ Reference< XRowSet > xReturn;
+ try
+ {
+ xReturn = impl_getRowSet_throw();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::impl_getRowSet_nothrow" );
+ }
+ return xReturn;
+ }
+
+
+ void FormComponentPropertyHandler::impl_initFieldList_nothrow( std::vector< OUString >& _rFieldNames ) const
+ {
+ clearContainer( _rFieldNames );
+ try
+ {
+ weld::WaitObject aWaitCursor(impl_getDefaultDialogFrame_nothrow());
+
+ // get the form of the control we're inspecting
+ Reference< XPropertySet > xFormSet( impl_getRowSet_throw(), UNO_QUERY );
+ if ( !xFormSet.is() )
+ return;
+
+ OUString sObjectName;
+ if( ! (xFormSet->getPropertyValue( PROPERTY_COMMAND ) >>= sObjectName) )
+ SAL_WARN("extensions.propctrlr", "impl_initFieldList_nothrow: unable to get property " << PROPERTY_COMMAND);
+ // when there is no command we don't need to ask for columns
+ if ( !sObjectName.isEmpty() && impl_ensureRowsetConnection_nothrow() )
+ {
+ OUString aDatabaseName;
+ if( ! (xFormSet->getPropertyValue( PROPERTY_DATASOURCE ) >>= aDatabaseName) )
+ SAL_WARN("extensions.propctrlr", "impl_initFieldList_nothrow: unable to get property " << PROPERTY_DATASOURCE);
+ sal_Int32 nObjectType = CommandType::COMMAND;
+ if( ! (xFormSet->getPropertyValue( PROPERTY_COMMANDTYPE ) >>= nObjectType) )
+ SAL_WARN("extensions.propctrlr", "impl_initFieldList_nothrow: unable to get property " << PROPERTY_COMMANDTYPE);
+
+ const Sequence<OUString> aNames = ::dbtools::getFieldNamesByCommandDescriptor( m_xRowSetConnection, nObjectType, sObjectName );
+ _rFieldNames.insert( _rFieldNames.end(), aNames.begin(), aNames.end() );
+ }
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::impl_initFieldList_nothrow" );
+ }
+ }
+
+ void FormComponentPropertyHandler::impl_displaySQLError_nothrow( const ::dbtools::SQLExceptionInfo& _rErrorDescriptor ) const
+ {
+ auto pTopLevel = impl_getDefaultDialogFrame_nothrow();
+ ::dbtools::showError(_rErrorDescriptor, pTopLevel ? pTopLevel->GetXWindow() : nullptr, m_xContext);
+ }
+
+ bool FormComponentPropertyHandler::impl_ensureRowsetConnection_nothrow() const
+ {
+ if ( !m_xRowSetConnection.is() )
+ {
+ uno::Reference<sdbc::XConnection> xConnection;
+ Any any = m_xContext->getValueByName( "ActiveConnection" );
+ any >>= xConnection;
+ m_xRowSetConnection.reset(xConnection,::dbtools::SharedConnection::NoTakeOwnership);
+ }
+ if ( m_xRowSetConnection.is() )
+ return true;
+
+ Reference< XRowSet > xRowSet( impl_getRowSet_throw() );
+ Reference< XPropertySet > xRowSetProps( xRowSet, UNO_QUERY );
+
+ // connect the row set - this is delegated to elsewhere - while observing errors
+ SQLExceptionInfo aError;
+ try
+ {
+ if ( xRowSetProps.is() )
+ {
+ weld::WaitObject aWaitCursor(impl_getDefaultDialogFrame_nothrow());
+ m_xRowSetConnection = ::dbtools::ensureRowSetConnection( xRowSet, m_xContext, nullptr );
+ }
+ }
+ catch ( const SQLException& ) { aError = SQLExceptionInfo( ::cppu::getCaughtException() ); }
+ catch ( const WrappedTargetException& e ) { aError = SQLExceptionInfo( e.TargetException ); }
+ catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); }
+
+ // report errors, if necessary
+ if ( aError.isValid() )
+ {
+ OUString sDataSourceName;
+ try
+ {
+ xRowSetProps->getPropertyValue( PROPERTY_DATASOURCE ) >>= sDataSourceName;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::impl_ensureRowsetConnection_nothrow: caught an exception during error handling!" );
+ }
+ // additional info about what happened
+ INetURLObject aParser( sDataSourceName );
+ if ( aParser.GetProtocol() != INetProtocol::NotValid )
+ sDataSourceName = aParser.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset );
+ OUString sInfo(PcrRes(RID_STR_UNABLETOCONNECT).replaceAll("$name$", sDataSourceName));
+ SQLContext aContext;
+ aContext.Message = sInfo;
+ aContext.NextException = aError.get();
+ impl_displaySQLError_nothrow( aContext );
+ }
+
+ return m_xRowSetConnection.is();
+ }
+
+
+ void FormComponentPropertyHandler::impl_describeCursorSource_nothrow( LineDescriptor& _out_rProperty, const Reference< XPropertyControlFactory >& _rxControlFactory ) const
+ {
+ try
+ {
+ weld::WaitObject aWaitCursor(impl_getDefaultDialogFrame_nothrow());
+
+
+ // Set the UI data
+ _out_rProperty.DisplayName = m_pInfoService->getPropertyTranslation( PROPERTY_ID_COMMAND );
+
+ _out_rProperty.HelpURL = HelpIdUrl::getHelpURL( m_pInfoService->getPropertyHelpId( PROPERTY_ID_COMMAND ) );
+ _out_rProperty.PrimaryButtonId = UID_PROP_DLG_SQLCOMMAND;
+
+
+ sal_Int32 nCommandType = CommandType::COMMAND;
+ impl_getPropertyValue_throw( PROPERTY_COMMANDTYPE ) >>= nCommandType;
+
+ switch ( nCommandType )
+ {
+ case CommandType::TABLE:
+ case CommandType::QUERY:
+ {
+ std::vector< OUString > aNames;
+ if ( impl_ensureRowsetConnection_nothrow() )
+ {
+ if ( nCommandType == CommandType::TABLE )
+ impl_fillTableNames_throw( aNames );
+ else
+ impl_fillQueryNames_throw( aNames );
+ }
+ _out_rProperty.Control = PropertyHandlerHelper::createComboBoxControl( _rxControlFactory, std::move(aNames), true );
+ }
+ break;
+
+ default:
+ _out_rProperty.Control = _rxControlFactory->createPropertyControl( PropertyControlType::MultiLineTextField, false );
+ break;
+ }
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::impl_describeCursorSource_nothrow");
+ }
+ }
+
+
+ void FormComponentPropertyHandler::impl_fillTableNames_throw( std::vector< OUString >& _out_rNames ) const
+ {
+ OSL_PRECOND( m_xRowSetConnection.is(), "FormComponentPropertyHandler::impl_fillTableNames_throw: need a connection!" );
+ _out_rNames.resize( 0 );
+
+ Reference< XTablesSupplier > xSupplyTables( m_xRowSetConnection, UNO_QUERY );
+ Reference< XNameAccess > xTableNames;
+ if ( xSupplyTables.is() )
+ xTableNames = xSupplyTables->getTables();
+ DBG_ASSERT( xTableNames.is(), "FormComponentPropertyHandler::impl_fillTableNames_throw: no way to obtain the tables of the connection!" );
+ if ( !xTableNames.is() )
+ return;
+
+ const Sequence<OUString> aNames = xTableNames->getElementNames();
+ _out_rNames.insert( _out_rNames.end(), aNames.begin(), aNames.end() );
+ }
+
+
+ void FormComponentPropertyHandler::impl_fillQueryNames_throw( std::vector< OUString >& _out_rNames ) const
+ {
+ OSL_PRECOND( m_xRowSetConnection.is(), "FormComponentPropertyHandler::impl_fillQueryNames_throw: need a connection!" );
+ _out_rNames.resize( 0 );
+
+ Reference< XQueriesSupplier > xSupplyQueries( m_xRowSetConnection, UNO_QUERY );
+ Reference< XNameAccess > xQueryNames;
+ if ( xSupplyQueries.is() )
+ {
+ xQueryNames = xSupplyQueries->getQueries();
+ impl_fillQueryNames_throw(xQueryNames,_out_rNames);
+ }
+ }
+
+ void FormComponentPropertyHandler::impl_fillQueryNames_throw( const Reference< XNameAccess >& _xQueryNames,std::vector< OUString >& _out_rNames,std::u16string_view _sName ) const
+ {
+ DBG_ASSERT( _xQueryNames.is(), "FormComponentPropertyHandler::impl_fillQueryNames_throw: no way to obtain the queries of the connection!" );
+ if ( !_xQueryNames.is() )
+ return;
+
+ bool bAdd = !_sName.empty();
+
+ const Sequence<OUString> aQueryNames =_xQueryNames->getElementNames();
+ for ( const OUString& rQueryName : aQueryNames )
+ {
+ OUStringBuffer sTemp;
+ if ( bAdd )
+ {
+ sTemp.append(_sName);
+ sTemp.append("/");
+ }
+ sTemp.append(rQueryName);
+ Reference< XNameAccess > xSubQueries(_xQueryNames->getByName(rQueryName),UNO_QUERY);
+ if ( xSubQueries.is() )
+ impl_fillQueryNames_throw(xSubQueries,_out_rNames,sTemp.makeStringAndClear());
+ else
+ _out_rNames.push_back( sTemp.makeStringAndClear() );
+ }
+ }
+
+
+ void FormComponentPropertyHandler::impl_describeListSourceUI_throw( LineDescriptor& _out_rDescriptor, const Reference< XPropertyControlFactory >& _rxControlFactory ) const
+ {
+ OSL_PRECOND( m_xComponent.is(), "FormComponentPropertyHandler::impl_describeListSourceUI_throw: no component!" );
+
+
+ // read out ListSourceTypes
+ Any aListSourceType( m_xComponent->getPropertyValue( PROPERTY_LISTSOURCETYPE ) );
+
+ sal_Int32 nListSourceType = sal_Int32(ListSourceType_VALUELIST);
+ ::cppu::enum2int( nListSourceType, aListSourceType );
+ ListSourceType eListSourceType = static_cast<ListSourceType>(nListSourceType);
+
+ _out_rDescriptor.DisplayName = m_pInfoService->getPropertyTranslation( PROPERTY_ID_LISTSOURCE );
+ _out_rDescriptor.HelpURL = HelpIdUrl::getHelpURL( m_pInfoService->getPropertyHelpId( PROPERTY_ID_LISTSOURCE ) );
+
+
+ // set enums
+ switch( eListSourceType )
+ {
+ case ListSourceType_VALUELIST:
+ _out_rDescriptor.Control = _rxControlFactory->createPropertyControl( PropertyControlType::StringListField, false );
+ break;
+
+ case ListSourceType_TABLEFIELDS:
+ case ListSourceType_TABLE:
+ case ListSourceType_QUERY:
+ {
+ std::vector< OUString > aListEntries;
+ if ( impl_ensureRowsetConnection_nothrow() )
+ {
+ if ( eListSourceType == ListSourceType_QUERY )
+ impl_fillQueryNames_throw( aListEntries );
+ else
+ impl_fillTableNames_throw( aListEntries );
+ }
+ _out_rDescriptor.Control = PropertyHandlerHelper::createComboBoxControl( _rxControlFactory, std::move(aListEntries), false );
+ }
+ break;
+ case ListSourceType_SQL:
+ case ListSourceType_SQLPASSTHROUGH:
+ impl_ensureRowsetConnection_nothrow();
+ _out_rDescriptor.HasPrimaryButton = m_xRowSetConnection.is();
+ break;
+ default: break;
+ }
+ }
+
+ bool FormComponentPropertyHandler::impl_dialogListSelection_nothrow( const OUString& _rProperty, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const
+ {
+ OSL_PRECOND(m_pInfoService, "FormComponentPropertyHandler::impl_dialogListSelection_"
+ "nothrow: no property meta data!");
+
+ OUString sPropertyUIName( m_pInfoService->getPropertyTranslation( m_pInfoService->getPropertyId( _rProperty ) ) );
+ ListSelectionDialog aDialog(impl_getDefaultDialogFrame_nothrow(), m_xComponent, _rProperty, sPropertyUIName);
+ _rClearBeforeDialog.clear();
+ return ( RET_OK == aDialog.run() );
+ }
+
+ bool FormComponentPropertyHandler::impl_dialogFilterOrSort_nothrow( bool _bFilter, OUString& _out_rSelectedClause, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const
+ {
+ OSL_PRECOND( Reference< XRowSet >( m_xComponent, UNO_QUERY ).is(),
+ "FormComponentPropertyHandler::impl_dialogFilterOrSort_nothrow: to be called for forms only!" );
+
+ _out_rSelectedClause.clear();
+ bool bSuccess = false;
+ SQLExceptionInfo aErrorInfo;
+ try
+ {
+ if ( !impl_ensureRowsetConnection_nothrow() )
+ return false;
+
+ // get a composer for the statement which the form is currently based on
+ Reference< XSingleSelectQueryComposer > xComposer( ::dbtools::getCurrentSettingsComposer( m_xComponent, m_xContext, nullptr ) );
+ OSL_ENSURE( xComposer.is(), "FormComponentPropertyHandler::impl_dialogFilterOrSort_nothrow: could not obtain a composer!" );
+ if ( !xComposer.is() )
+ return false;
+
+ OUString sPropertyUIName( m_pInfoService->getPropertyTranslation( _bFilter ? PROPERTY_ID_FILTER : PROPERTY_ID_SORT ) );
+
+ // create the dialog
+ Reference< XExecutableDialog > xDialog;
+ if ( _bFilter)
+ {
+ xDialog.set( sdb::FilterDialog::createDefault(m_xContext) );
+ }
+ else
+ {
+ xDialog.set( sdb::OrderDialog::createDefault(m_xContext) );
+ }
+
+
+ // initialize the dialog
+ Reference< XPropertySet > xDialogProps( xDialog, UNO_QUERY_THROW );
+ xDialogProps->setPropertyValue("QueryComposer", Any( xComposer ) );
+ xDialogProps->setPropertyValue("RowSet", Any( m_xComponent ) );
+ if (auto pTopLevel = impl_getDefaultDialogFrame_nothrow())
+ xDialogProps->setPropertyValue("ParentWindow", Any(pTopLevel->GetXWindow()));
+ xDialogProps->setPropertyValue("Title", Any( sPropertyUIName ) );
+
+ _rClearBeforeDialog.clear();
+ bSuccess = ( xDialog->execute() != 0 );
+ if ( bSuccess )
+ _out_rSelectedClause = _bFilter ? xComposer->getFilter() : xComposer->getOrder();
+ }
+ catch (const SQLContext& e) { aErrorInfo = e; }
+ catch (const SQLWarning& e) { aErrorInfo = e; }
+ catch (const SQLException& e) { aErrorInfo = e; }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::impl_dialogFilterOrSort_nothrow" );
+ }
+
+ if ( aErrorInfo.isValid() )
+ impl_displaySQLError_nothrow( aErrorInfo );
+
+ return bSuccess;
+ }
+
+
+ bool FormComponentPropertyHandler::impl_dialogLinkedFormFields_nothrow( ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const
+ {
+ Reference< XForm > xDetailForm( m_xComponent, UNO_QUERY );
+ Reference< XForm > xMasterForm( m_xObjectParent, UNO_QUERY );
+ uno::Reference<beans::XPropertySet> xMasterProp(m_xObjectParent,uno::UNO_QUERY);
+ OSL_PRECOND( xDetailForm.is() && xMasterForm.is(), "FormComponentPropertyHandler::impl_dialogLinkedFormFields_nothrow: no forms!" );
+ if ( !xDetailForm.is() || !xMasterForm.is() )
+ return false;
+
+ FormLinkDialog aDialog(impl_getDefaultDialogFrame_nothrow(), m_xComponent, xMasterProp, m_xContext);
+ _rClearBeforeDialog.clear();
+ return ( RET_OK == aDialog.run() );
+ }
+
+ bool FormComponentPropertyHandler::impl_dialogFormatting_nothrow( Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const
+ {
+ bool bChanged = false;
+ try
+ {
+ // create the itemset for the dialog
+ SfxItemSet aCoreSet(
+ SfxGetpApp()->GetPool(),
+ svl::Items<
+ SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO>);
+ // ripped this somewhere ... don't understand it :(
+
+ // get the number formats supplier
+ Reference< XNumberFormatsSupplier > xSupplier;
+ m_xComponent->getPropertyValue( PROPERTY_FORMATSSUPPLIER ) >>= xSupplier;
+
+ DBG_ASSERT(xSupplier.is(), "FormComponentPropertyHandler::impl_dialogFormatting_nothrow: invalid call !" );
+ Reference< XUnoTunnel > xTunnel( xSupplier, UNO_QUERY_THROW );
+ SvNumberFormatsSupplierObj* pSupplier =
+ reinterpret_cast< SvNumberFormatsSupplierObj* >( xTunnel->getSomething( SvNumberFormatsSupplierObj::getUnoTunnelId() ) );
+ DBG_ASSERT( pSupplier != nullptr, "FormComponentPropertyHandler::impl_dialogFormatting_nothrow: invalid call !" );
+
+ sal_Int32 nFormatKey = 0;
+ impl_getPropertyValue_throw( PROPERTY_FORMATKEY ) >>= nFormatKey;
+ aCoreSet.Put( SfxUInt32Item( SID_ATTR_NUMBERFORMAT_VALUE, nFormatKey ) );
+
+ SvNumberFormatter* pFormatter = pSupplier->GetNumberFormatter();
+ double dPreviewVal = OFormatSampleControl::getPreviewValue(pFormatter,nFormatKey);
+ SvxNumberInfoItem aFormatter( pFormatter, dPreviewVal, PcrRes(RID_STR_TEXT_FORMAT), SID_ATTR_NUMBERFORMAT_INFO );
+ aCoreSet.Put( aFormatter );
+
+ // a tab dialog with a single page
+ SfxSingleTabDialogController aDialog(impl_getDefaultDialogFrame_nothrow(), &aCoreSet,
+ "cui/ui/formatnumberdialog.ui", "FormatNumberDialog");
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ::CreateTabPage fnCreatePage = pFact->GetTabPageCreatorFunc( RID_SVXPAGE_NUMBERFORMAT );
+ if ( !fnCreatePage )
+ throw RuntimeException(); // caught below
+
+ aDialog.SetTabPage((*fnCreatePage)(aDialog.get_content_area(), &aDialog, &aCoreSet));
+
+ _rClearBeforeDialog.clear();
+ if ( RET_OK == aDialog.run() )
+ {
+ const SfxItemSet* pResult = aDialog.GetOutputItemSet();
+
+ if (const SvxNumberInfoItem* pInfoItem = pResult->GetItem( SID_ATTR_NUMBERFORMAT_INFO ))
+ {
+ for (sal_uInt32 key : pInfoItem->GetDelFormats())
+ pFormatter->DeleteEntry(key);
+ }
+
+ if ( const SfxUInt32Item* pItem = pResult->GetItemIfSet( SID_ATTR_NUMBERFORMAT_VALUE, false ) )
+ {
+ _out_rNewValue <<= static_cast<sal_Int32>( pItem->GetValue() );
+ bChanged = true;
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::impl_dialogFormatting_nothrow" );
+ }
+ return bChanged;
+ }
+
+ bool FormComponentPropertyHandler::impl_browseForImage_nothrow( Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const
+ {
+ bool bIsLink = true;// reflect the legacy behavior
+ OUString aStrTrans = m_pInfoService->getPropertyTranslation( PROPERTY_ID_IMAGE_URL );
+
+ weld::Window* pWin = impl_getDefaultDialogFrame_nothrow();
+ ::sfx2::FileDialogHelper aFileDlg(
+ ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW,
+ FileDialogFlags::Graphic, pWin);
+ aFileDlg.SetContext(sfx2::FileDialogHelper::FormsInsertImage);
+ aFileDlg.SetTitle(aStrTrans);
+ // non-linked images ( e.g. those located in the document
+ // stream ) only if document is available
+ bool bHandleNonLink;
+ {
+ Reference< XModel > xModel( impl_getContextDocument_nothrow() );
+ bHandleNonLink = xModel.is();
+ // Not implemented in reports
+ if (bHandleNonLink)
+ {
+ Reference< XReportDefinition > xReportDef( xModel, css::uno::UNO_QUERY );
+ bHandleNonLink = !xReportDef.is();
+ }
+ }
+
+ Reference< XFilePickerControlAccess > xController(aFileDlg.GetFilePicker(), UNO_QUERY);
+ DBG_ASSERT(xController.is(), "FormComponentPropertyHandler::impl_browseForImage_nothrow: missing the controller interface on the file picker!");
+ if (xController.is())
+ {
+ // do a preview by default
+ xController->setValue(ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, 0, css::uno::Any(true));
+
+ xController->setValue(ExtendedFilePickerElementIds::CHECKBOX_LINK, 0, css::uno::Any(bIsLink));
+ xController->enableControl(ExtendedFilePickerElementIds::CHECKBOX_LINK, bHandleNonLink );
+
+ }
+
+ OUString sCurValue;
+ if( ! (impl_getPropertyValue_throw( PROPERTY_IMAGE_URL ) >>= sCurValue) )
+ SAL_WARN("extensions.propctrlr", "impl_browseForImage_nothrow: unable to get property " << PROPERTY_IMAGE_URL);
+ if (!sCurValue.isEmpty())
+ {
+ aFileDlg.SetDisplayDirectory( sCurValue );
+ // TODO: need to set the display directory _and_ the default name
+ }
+
+ _rClearBeforeDialog.clear();
+ bool bSuccess = ( ERRCODE_NONE == aFileDlg.Execute() );
+ if ( bSuccess )
+ {
+ if ( bHandleNonLink && xController.is() )
+ {
+ xController->getValue(ExtendedFilePickerElementIds::CHECKBOX_LINK, 0) >>= bIsLink;
+ }
+ if ( !bIsLink )
+ {
+ Graphic aGraphic;
+ aFileDlg.GetGraphic(aGraphic);
+
+ Reference< graphic::XGraphicObject > xGrfObj = graphic::GraphicObject::create( m_xContext );
+ xGrfObj->setGraphic( aGraphic.GetXGraphic() );
+
+ _out_rNewValue <<= xGrfObj;
+
+ }
+ else
+ _out_rNewValue <<= aFileDlg.GetPath();
+ }
+ return bSuccess;
+ }
+
+ bool FormComponentPropertyHandler::impl_browseForTargetURL_nothrow( Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const
+ {
+ weld::Window* pWin = impl_getDefaultDialogFrame_nothrow();
+ ::sfx2::FileDialogHelper aFileDlg(
+ ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION,
+ FileDialogFlags::NONE, pWin);
+
+ OUString sURL;
+ if( ! (impl_getPropertyValue_throw( PROPERTY_TARGET_URL ) >>= sURL) )
+ SAL_WARN("extensions.propctrlr", "impl_browseForTargetURL_nothrow: unable to get property " << PROPERTY_TARGET_URL);
+ INetURLObject aParser( sURL );
+ if ( INetProtocol::File == aParser.GetProtocol() )
+ // set the initial directory only for file-URLs. Everything else
+ // is considered to be potentially expensive
+ aFileDlg.SetDisplayDirectory( sURL );
+
+ _rClearBeforeDialog.clear();
+ bool bSuccess = ( ERRCODE_NONE == aFileDlg.Execute() );
+ if ( bSuccess )
+ _out_rNewValue <<= aFileDlg.GetPath();
+ return bSuccess;
+ }
+
+ bool FormComponentPropertyHandler::impl_executeFontDialog_nothrow( Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const
+ {
+ bool bSuccess = false;
+
+ // create an item set for use with the dialog
+ std::unique_ptr<SfxItemSet> pSet;
+ rtl::Reference<SfxItemPool> pPool;
+ std::vector<SfxPoolItem*>* pDefaults = nullptr;
+ ControlCharacterDialog::createItemSet(pSet, pPool, pDefaults);
+ ControlCharacterDialog::translatePropertiesToItems(m_xComponent, pSet.get());
+
+ { // do this in an own block. The dialog needs to be destroyed before we call
+ // destroyItemSet
+ ControlCharacterDialog aDlg(impl_getDefaultDialogFrame_nothrow(), *pSet);
+ _rClearBeforeDialog.clear();
+ if (RET_OK == aDlg.run())
+ {
+ const SfxItemSet* pOut = aDlg.GetOutputItemSet();
+ if ( pOut )
+ {
+ std::vector< NamedValue > aFontPropertyValues;
+ ControlCharacterDialog::translateItemsToProperties( *pOut, aFontPropertyValues );
+ _out_rNewValue <<= comphelper::containerToSequence(aFontPropertyValues);
+ bSuccess = true;
+ }
+ }
+ }
+
+ ControlCharacterDialog::destroyItemSet(pSet, pPool, pDefaults);
+ return bSuccess;
+ }
+
+
+ bool FormComponentPropertyHandler::impl_browseForDatabaseDocument_throw( Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const
+ {
+ weld::Window* pWin = impl_getDefaultDialogFrame_nothrow();
+ ::sfx2::FileDialogHelper aFileDlg(
+ ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION, FileDialogFlags::NONE,
+ "sdatabase", SfxFilterFlags::NONE, SfxFilterFlags::NONE, pWin);
+
+ OUString sDataSource;
+ if( ! (impl_getPropertyValue_throw( PROPERTY_DATASOURCE ) >>= sDataSource) )
+ SAL_WARN("extensions.propctrlr", "impl_browseForDatabaseDocument_throw: unable to get property " << PROPERTY_DATASOURCE);
+ INetURLObject aParser( sDataSource );
+ if ( INetProtocol::File == aParser.GetProtocol() )
+ // set the initial directory only for file-URLs. Everything else
+ // is considered to be potentially expensive
+ aFileDlg.SetDisplayDirectory( sDataSource );
+
+ std::shared_ptr<const SfxFilter> pFilter = SfxFilter::GetFilterByName("StarOffice XML (Base)");
+ OSL_ENSURE(pFilter,"Filter: StarOffice XML (Base) could not be found!");
+ if ( pFilter )
+ {
+ aFileDlg.SetCurrentFilter(pFilter->GetUIName());
+ //aFileDlg.AddFilter(pFilter->GetFilterName(),pFilter->GetDefaultExtension());
+ }
+
+ _rClearBeforeDialog.clear();
+ bool bSuccess = ( ERRCODE_NONE == aFileDlg.Execute() );
+ if ( bSuccess )
+ _out_rNewValue <<= aFileDlg.GetPath();
+ return bSuccess;
+ }
+
+ bool FormComponentPropertyHandler::impl_dialogColorChooser_throw( sal_Int32 _nColorPropertyId, Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const
+ {
+ ::Color aColor;
+ if( ! (impl_getPropertyValue_throw( impl_getPropertyNameFromId_nothrow( _nColorPropertyId )) >>= aColor) )
+ SAL_WARN("extensions.propctrlr", "impl_dialogColorChooser_throw: unable to get property " << _nColorPropertyId);
+ SvColorDialog aColorDlg;
+ aColorDlg.SetColor( aColor );
+
+ _rClearBeforeDialog.clear();
+ weld::Window* pParent = impl_getDefaultDialogFrame_nothrow();
+ if (!aColorDlg.Execute(pParent))
+ return false;
+
+ _out_rNewValue <<= aColorDlg.GetColor();
+ return true;
+ }
+
+ bool FormComponentPropertyHandler::impl_dialogChooseLabelControl_nothrow( Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const
+ {
+ weld::Window* pParent = impl_getDefaultDialogFrame_nothrow();
+ OSelectLabelDialog dlgSelectLabel(pParent, m_xComponent);
+ _rClearBeforeDialog.clear();
+ bool bSuccess = (RET_OK == dlgSelectLabel.run());
+ if ( bSuccess )
+ _out_rNewValue <<= dlgSelectLabel.GetSelected();
+ return bSuccess;
+ }
+
+
+ Reference< XControlContainer > FormComponentPropertyHandler::impl_getContextControlContainer_nothrow() const
+ {
+ Reference< XControlContainer > xControlContext;
+ Any any = m_xContext->getValueByName( "ControlContext" );
+ any >>= xControlContext;
+ return xControlContext;
+ }
+
+
+ bool FormComponentPropertyHandler::impl_dialogChangeTabOrder_nothrow( ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const
+ {
+ OSL_PRECOND( impl_getContextControlContainer_nothrow().is(), "FormComponentPropertyHandler::impl_dialogChangeTabOrder_nothrow: invalid control context!" );
+
+ Reference< XTabControllerModel > xTabControllerModel( impl_getRowSet_nothrow(), UNO_QUERY );
+ TabOrderDialog aDialog(impl_getDefaultDialogFrame_nothrow(), xTabControllerModel,
+ impl_getContextControlContainer_nothrow(), m_xContext);
+ _rClearBeforeDialog.clear();
+ return RET_OK == aDialog.run();
+ }
+
+ namespace
+ {
+
+ //- ISQLCommandPropertyUI
+
+ class ISQLCommandPropertyUI : public ISQLCommandAdapter
+ {
+ public:
+ /** returns the empty-string-terminated list of names of properties
+ whose UI is to be disabled while the SQL command property is
+ being edited.
+ */
+ virtual OUString* getPropertiesToDisable() = 0;
+ };
+
+
+ //- SQLCommandPropertyUI
+
+ class SQLCommandPropertyUI : public ISQLCommandPropertyUI
+ {
+ protected:
+ explicit SQLCommandPropertyUI( const Reference< XPropertySet >& _rxObject )
+ : m_xObject(_rxObject)
+ {
+ if ( !m_xObject.is() )
+ throw NullPointerException();
+ }
+
+ protected:
+ Reference< XPropertySet > m_xObject;
+ };
+
+
+ //- FormSQLCommandUI - declaration
+
+ class FormSQLCommandUI : public SQLCommandPropertyUI
+ {
+ public:
+ explicit FormSQLCommandUI( const Reference< XPropertySet >& _rxForm );
+
+ // ISQLCommandAdapter
+ virtual OUString getSQLCommand() const override;
+ virtual bool getEscapeProcessing() const override;
+ virtual void setSQLCommand( const OUString& _rCommand ) const override;
+ virtual void setEscapeProcessing( const bool _bEscapeProcessing ) const override;
+
+ // ISQLCommandPropertyUI
+ virtual OUString* getPropertiesToDisable() override;
+ };
+
+
+ //- FormSQLCommandUI - implementation
+
+
+ FormSQLCommandUI::FormSQLCommandUI( const Reference< XPropertySet >& _rxForm )
+ :SQLCommandPropertyUI( _rxForm )
+ {
+ }
+
+
+ OUString FormSQLCommandUI::getSQLCommand() const
+ {
+ OUString sCommand;
+ if( ! (m_xObject->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand) )
+ SAL_WARN("extensions.propctrlr", "getSQLCommand: unable to get property " << PROPERTY_COMMAND);
+ return sCommand;
+ }
+
+
+ bool FormSQLCommandUI::getEscapeProcessing() const
+ {
+ bool bEscapeProcessing( false );
+ if( ! (m_xObject->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bEscapeProcessing) )
+ SAL_WARN("extensions.propctrlr", "getSQLCommand: unable to get property " << PROPERTY_ESCAPE_PROCESSING);
+ return bEscapeProcessing;
+ }
+
+
+ void FormSQLCommandUI::setSQLCommand( const OUString& _rCommand ) const
+ {
+ m_xObject->setPropertyValue( PROPERTY_COMMAND, Any( _rCommand ) );
+ }
+
+
+ void FormSQLCommandUI::setEscapeProcessing( const bool _bEscapeProcessing ) const
+ {
+ m_xObject->setPropertyValue( PROPERTY_ESCAPE_PROCESSING, Any( _bEscapeProcessing ) );
+ }
+
+
+ OUString* FormSQLCommandUI::getPropertiesToDisable()
+ {
+ static OUString s_aCommandProps[] = {
+ OUString(PROPERTY_DATASOURCE),
+ OUString(PROPERTY_COMMAND),
+ OUString(PROPERTY_COMMANDTYPE),
+ OUString(PROPERTY_ESCAPE_PROCESSING),
+ OUString()
+ };
+ return s_aCommandProps;
+ }
+
+ //- ValueListCommandUI - declaration
+
+ class ValueListCommandUI : public SQLCommandPropertyUI
+ {
+ public:
+ explicit ValueListCommandUI( const Reference< XPropertySet >& _rxListOrCombo );
+
+ // ISQLCommandAdapter
+ virtual OUString getSQLCommand() const override;
+ virtual bool getEscapeProcessing() const override;
+ virtual void setSQLCommand( const OUString& _rCommand ) const override;
+ virtual void setEscapeProcessing( const bool _bEscapeProcessing ) const override;
+
+ // ISQLCommandPropertyUI
+ virtual OUString* getPropertiesToDisable() override;
+ private:
+ mutable bool m_bPropertyValueIsList;
+ };
+
+
+ //- ValueListCommandUI - implementation
+
+
+ ValueListCommandUI::ValueListCommandUI( const Reference< XPropertySet >& _rxListOrCombo )
+ :SQLCommandPropertyUI( _rxListOrCombo )
+ ,m_bPropertyValueIsList( false )
+ {
+ }
+
+
+ OUString ValueListCommandUI::getSQLCommand() const
+ {
+ OUString sValue;
+ m_bPropertyValueIsList = false;
+
+ // for combo boxes, the property is a mere string
+ Any aValue( m_xObject->getPropertyValue( PROPERTY_LISTSOURCE ) );
+ if ( aValue >>= sValue )
+ return sValue;
+
+ Sequence< OUString > aValueList;
+ if ( aValue >>= aValueList )
+ {
+ m_bPropertyValueIsList = true;
+ if ( aValueList.hasElements() )
+ sValue = aValueList[0];
+ return sValue;
+ }
+
+ OSL_FAIL( "ValueListCommandUI::getSQLCommand: unexpected property type!" );
+ return sValue;
+ }
+
+
+ bool ValueListCommandUI::getEscapeProcessing() const
+ {
+ ListSourceType eType = ListSourceType_SQL;
+ if( ! (m_xObject->getPropertyValue( PROPERTY_LISTSOURCETYPE ) >>= eType) )
+ SAL_WARN("extensions.propctrlr", "getEscapeProcessing: unable to get property " << PROPERTY_LISTSOURCETYPE);
+ OSL_ENSURE( ( eType == ListSourceType_SQL ) || ( eType == ListSourceType_SQLPASSTHROUGH ),
+ "ValueListCommandUI::getEscapeProcessing: unexpected list source type!" );
+ return ( eType == ListSourceType_SQL );
+ }
+
+
+ void ValueListCommandUI::setSQLCommand( const OUString& _rCommand ) const
+ {
+ Any aValue;
+ if ( m_bPropertyValueIsList )
+ aValue <<= Sequence< OUString >( &_rCommand, 1 );
+ else
+ aValue <<= _rCommand;
+ m_xObject->setPropertyValue( PROPERTY_LISTSOURCE, aValue );
+ }
+
+
+ void ValueListCommandUI::setEscapeProcessing( const bool _bEscapeProcessing ) const
+ {
+ m_xObject->setPropertyValue( PROPERTY_LISTSOURCETYPE, Any(
+ _bEscapeProcessing ? ListSourceType_SQL : ListSourceType_SQLPASSTHROUGH ) );
+ }
+
+
+ OUString* ValueListCommandUI::getPropertiesToDisable()
+ {
+ static OUString s_aListSourceProps[] = {
+ OUString(PROPERTY_LISTSOURCETYPE),
+ OUString(PROPERTY_LISTSOURCE),
+ OUString()
+ };
+ return s_aListSourceProps;
+ }
+ }
+
+
+ bool FormComponentPropertyHandler::impl_doDesignSQLCommand_nothrow( const Reference< XObjectInspectorUI >& _rxInspectorUI, PropertyId _nDesignForProperty )
+ {
+ try
+ {
+ if ( m_xCommandDesigner.is() )
+ {
+ if ( m_xCommandDesigner->isActive() )
+ {
+ m_xCommandDesigner->raise();
+ return true;
+ }
+ m_xCommandDesigner->dispose();
+ m_xCommandDesigner.set( nullptr );
+ }
+
+ if ( !impl_ensureRowsetConnection_nothrow() )
+ return false;
+
+ Reference< XPropertySet > xComponentProperties( m_xComponent, UNO_SET_THROW );
+
+ ::rtl::Reference< ISQLCommandPropertyUI > xCommandUI;
+ switch ( _nDesignForProperty )
+ {
+ case PROPERTY_ID_COMMAND:
+ xCommandUI = new FormSQLCommandUI( xComponentProperties );
+ break;
+ case PROPERTY_ID_LISTSOURCE:
+ xCommandUI = new ValueListCommandUI( xComponentProperties );
+ break;
+ default:
+ OSL_FAIL( "FormComponentPropertyHandler::OnDesignerClosed: invalid property id!" );
+ return false;
+ }
+
+ m_xCommandDesigner.set( new SQLCommandDesigner( m_xContext, xCommandUI, m_xRowSetConnection, LINK( this, FormComponentPropertyHandler, OnDesignerClosed ) ) );
+
+ DBG_ASSERT( _rxInspectorUI.is(), "FormComponentPropertyHandler::OnDesignerClosed: no access to the property browser ui!" );
+ if ( m_xCommandDesigner->isActive() && _rxInspectorUI.is() )
+ {
+ m_xBrowserUI = _rxInspectorUI;
+ // disable everything which would affect this property
+ const OUString* pToDisable = xCommandUI->getPropertiesToDisable();
+ while ( !pToDisable->isEmpty() )
+ {
+ m_xBrowserUI->enablePropertyUIElements( *pToDisable++, PropertyLineElement::All, false );
+ }
+
+ // but enable the browse button for the property itself - so it can be used to raise the query designer
+ OUString sPropertyName( impl_getPropertyNameFromId_nothrow( _nDesignForProperty ) );
+ m_xBrowserUI->enablePropertyUIElements( sPropertyName, PropertyLineElement::PrimaryButton, true );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ return m_xCommandDesigner.is();
+ }
+
+
+ IMPL_LINK_NOARG( FormComponentPropertyHandler, OnDesignerClosed, SQLCommandDesigner&, void )
+ {
+ OSL_ENSURE( m_xBrowserUI.is() && m_xCommandDesigner.is(), "FormComponentPropertyHandler::OnDesignerClosed: too many NULLs!" );
+ if ( !(m_xBrowserUI.is() && m_xCommandDesigner.is()) )
+ return;
+
+ try
+ {
+ ::rtl::Reference< ISQLCommandPropertyUI > xCommandUI(
+ dynamic_cast< ISQLCommandPropertyUI* >( m_xCommandDesigner->getPropertyAdapter().get() ) );
+ if ( !xCommandUI.is() )
+ throw NullPointerException();
+
+ const OUString* pToEnable = xCommandUI->getPropertiesToDisable();
+ while ( !pToEnable->isEmpty() )
+ {
+ m_xBrowserUI->enablePropertyUIElements( *pToEnable++, PropertyLineElement::All, true );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+
+ bool FormComponentPropertyHandler::impl_hasValidDataSourceSignature_nothrow( const Reference< XPropertySet >& _xFormProperties, bool _bAllowEmptyDataSourceName )
+ {
+ bool bHas = false;
+ if ( _xFormProperties.is() )
+ {
+ try
+ {
+ OUString sPropertyValue;
+ // first, we need the name of an existent data source
+ if ( _xFormProperties->getPropertySetInfo()->hasPropertyByName(PROPERTY_DATASOURCE) )
+ _xFormProperties->getPropertyValue( PROPERTY_DATASOURCE ) >>= sPropertyValue;
+ bHas = ( !sPropertyValue.isEmpty() ) || _bAllowEmptyDataSourceName;
+
+ // then, the command should not be empty
+ if ( bHas )
+ {
+ if ( _xFormProperties->getPropertySetInfo()->hasPropertyByName(PROPERTY_COMMAND) )
+ _xFormProperties->getPropertyValue( PROPERTY_COMMAND ) >>= sPropertyValue;
+ bHas = !sPropertyValue.isEmpty();
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::impl_hasValidDataSourceSignature_nothrow" );
+ }
+ }
+ return bHas;
+ }
+
+ OUString FormComponentPropertyHandler::impl_getDocumentURL_nothrow() const
+ {
+ OUString sURL;
+ try
+ {
+ Reference< XModel > xDocument( impl_getContextDocument_nothrow() );
+ if ( xDocument.is() )
+ sURL = xDocument->getURL();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ return sURL;
+ }
+
+ ::cppu::IPropertyArrayHelper* FormComponentPropertyHandler::createArrayHelper( ) const
+ {
+ uno::Sequence< beans::Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+
+ }
+
+ ::cppu::IPropertyArrayHelper & FormComponentPropertyHandler::getInfoHelper()
+ {
+ return *getArrayHelper();
+ }
+
+ uno::Reference< beans::XPropertySetInfo > SAL_CALL FormComponentPropertyHandler::getPropertySetInfo( )
+ {
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+ }
+
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_FormComponentPropertyHandler_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::FormComponentPropertyHandler(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/formcomponenthandler.hxx b/extensions/source/propctrlr/formcomponenthandler.hxx
new file mode 100644
index 000000000..bc7367abb
--- /dev/null
+++ b/extensions/source/propctrlr/formcomponenthandler.hxx
@@ -0,0 +1,435 @@
+/* -*- 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 <memory>
+#include "propertyhandler.hxx"
+#include "sqlcommanddesign.hxx"
+#include <comphelper/uno3.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/awt/XControlContainer.hpp>
+#include <connectivity/dbtools.hxx>
+
+#include <set>
+
+
+namespace pcr
+{
+
+
+ //= ComponentClassification
+
+ enum ComponentClassification
+ {
+ eFormControl,
+ eDialogControl,
+ eUnknown
+ };
+
+
+ //= FormComponentPropertyHandler
+
+ class FormComponentPropertyHandler;
+ typedef ::comphelper::OPropertyArrayUsageHelper<FormComponentPropertyHandler> FormComponentPropertyHandler_PROP;
+ /** default ->XPropertyHandler for all form components.
+ */
+ class FormComponentPropertyHandler : public PropertyHandlerComponent,
+ public ::comphelper::OPropertyContainer,
+ public FormComponentPropertyHandler_PROP
+ {
+ private:
+ /// access to property states
+ css::uno::Reference< css::beans::XPropertyState > m_xPropertyState;
+ /// the parent of our component
+ css::uno::Reference< css::uno::XInterface > m_xObjectParent;
+
+ /// the database connection. Owned by us if and only if we created it ourself.
+ mutable ::dbtools::SharedConnection m_xRowSetConnection;
+ css::uno::Reference< css::sdbc::XRowSet > m_xRowSet;
+ /** helper component encapsulating the handling for the QueryDesign component for
+ interactively designing an SQL command
+ */
+ ::rtl::Reference< SQLCommandDesigner > m_xCommandDesigner;
+ css::uno::Reference< css::inspection::XObjectInspectorUI > m_xBrowserUI;
+
+ /// the string indicating a "default" (VOID) value in list-like controls
+ OUString m_sDefaultValueString;
+ /// all properties to whose control's we added ->m_sDefaultValueString
+ std::set< OUString > m_aPropertiesWithDefListEntry;
+ /// type of our component
+ ComponentClassification m_eComponentClass;
+ /// is our component a (database) sub form?
+ bool m_bComponentIsSubForm : 1;
+ /// our component has a "ListSource" property
+ bool m_bHaveListSource : 1;
+ /// our component has a "Command" property
+ bool m_bHaveCommand : 1;
+ /// the class id of the component - if applicable
+ sal_Int16 m_nClassId;
+
+ public:
+ explicit FormComponentPropertyHandler(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext
+ );
+
+ DECLARE_XINTERFACE( )
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ protected:
+ virtual ~FormComponentPropertyHandler() override;
+
+ protected:
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override;
+
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ // XPropertyHandler overridables
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override;
+ virtual css::uno::Any SAL_CALL convertToPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rControlValue ) override;
+ virtual css::uno::Any SAL_CALL convertToControlValue( const OUString& _rPropertyName, const css::uno::Any& _rPropertyValue, const css::uno::Type& _rControlValueType ) override;
+ virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupersededProperties() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getActuatingProperties() override;
+ virtual css::inspection::LineDescriptor SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override;
+ virtual css::inspection::InteractiveSelectionResult
+ SAL_CALL onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, css::uno::Any& _rData, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) override;
+ virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override;
+ virtual sal_Bool SAL_CALL suspend( sal_Bool _bSuspend ) override;
+
+ // XComponent
+ virtual void SAL_CALL disposing() override;
+
+ // PropertyHandler
+ virtual css::uno::Sequence< css::beans::Property >
+ doDescribeSupportedProperties() const override;
+ virtual void onNewComponent() override;
+
+ private:
+ /** classifies our component, in case it's a control model, by ClassId
+
+ Note that UNO dialog controls are also classified, though they don't have the ClassId property
+ */
+ void impl_classifyControlModel_throw();
+
+ bool isReportModel() const;
+
+ /** const-version of ->getPropertyValue
+ */
+ css::uno::Any impl_getPropertyValue_throw( const OUString& _rPropertyName ) const;
+
+ // some property values are faked, and not used in the way they're provided by our component
+ void impl_normalizePropertyValue_nothrow( css::uno::Any& _rValue, PropertyId _nPropId ) const;
+
+ /** determines whether we should exclude a given property from our "supported properties"
+ */
+ bool impl_shouldExcludeProperty_nothrow( const css::beans::Property& _rProperty ) const;
+
+ /** initializes the list of field names, if we're handling a control which supports the
+ DataField property
+ */
+ void impl_initFieldList_nothrow( std::vector< OUString >& rFieldNames ) const;
+
+ /** obtains the RowSet to which our component belongs
+
+ If the component is a RowSet itself, it's returned directly. Else, the parent
+ is examined for the XRowSet interface. If the parent is no XRowSet, then
+ a check is made whether our component is a grid control column, and if so,
+ the parent of the grid control is examined for the XRowSet interface.
+
+ Normally, at least one of those methods should succeed.
+ */
+ css::uno::Reference< css::sdbc::XRowSet > impl_getRowSet_throw( ) const;
+
+ /** nothrow-version of ->impl_getRowSet_throw
+ */
+ css::uno::Reference< css::sdbc::XRowSet > impl_getRowSet_nothrow( ) const;
+
+ /** connects the row set belonging to our introspected data aware form component,
+ and remembers the connection in ->m_xRowSetConnection.
+
+ If the row set already is connected, ->m_xRowSetConnection will be set, too, but
+ not take the ownership of the connection.
+
+ If ->m_xRowSetConnection is already set, nothing happens, so if you want to
+ force creation of a connection, you need to clear ->m_xRowSetConnection.
+ */
+ bool impl_ensureRowsetConnection_nothrow() const;
+
+ /** fills an ->LineDescriptor with information to represent a cursor source
+ of our form - that is, a table, a query, or an SQL statement.
+
+ As an example, if our form has currently a CommandType of TABLE, then the
+ value list in the LineDescriptor will contain a list of all tables
+ of the data source which the form is bound to.
+
+ @seealso impl_fillTableNames_throw
+ @seealso impl_fillQueryNames_throw
+ */
+ void impl_describeCursorSource_nothrow(
+ css::inspection::LineDescriptor& _out_rProperty,
+ const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory
+ ) const;
+
+ /** describes the UI for selecting a table name
+
+ @precond
+ m_xRowSetConnection is not <NULL/>
+ */
+ void impl_fillTableNames_throw( std::vector< OUString >& _out_rNames ) const;
+
+ /** describes the UI for selecting a query name
+
+ @precond
+ m_xRowSetConnection is not <NULL/>
+ */
+ void impl_fillQueryNames_throw( std::vector< OUString >& _out_rNames ) const;
+
+ /** describes the UI for selecting a query name
+
+ @precond
+ m_xRowSetConnection is not <NULL/>
+ */
+ void impl_fillQueryNames_throw( const css::uno::Reference< css::container::XNameAccess >& _xQueryNames
+ ,std::vector< OUString >& _out_rNames
+ ,std::u16string_view _sName = std::u16string_view() ) const;
+
+ /** describes the UI for selecting a ListSource (for list-like form controls)
+ @precond
+ ->m_xRowSetConnection is not <NULL/>
+ @precond
+ ->m_xComponent is not <NULL/>
+ */
+ void impl_describeListSourceUI_throw(
+ css::inspection::LineDescriptor& _out_rDescriptor,
+ const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory
+ ) const;
+
+ /** displays a database-related error to the user
+ */
+ void impl_displaySQLError_nothrow( const ::dbtools::SQLExceptionInfo& _rErrorDescriptor ) const;
+
+ /** let's the user chose a selection of entries from a string list, and stores this
+ selection in the given property
+ @return
+ <TRUE/> if and only if the user successfully changed the property
+ */
+ bool impl_dialogListSelection_nothrow( const OUString& _rProperty, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
+
+ /** executes a dialog for choosing a filter or sort criterion for a database form
+ @param _bFilter
+ <TRUE/> if the Filter property should be used, <FALSE/> if it's the Order
+ property
+ @param _out_rSelectedClause
+ the filter or order clause as chosen by the user
+ @precond
+ we're really inspecting a database form (well, a RowSet at least)
+ @return
+ <TRUE/> if and only if the user successfully chose a clause
+ */
+ bool impl_dialogFilterOrSort_nothrow( bool _bFilter, OUString& _out_rSelectedClause, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
+
+ /** executes a dialog which allows the user to choose the columns linking
+ a sub to a master form, and sets the respective MasterFields / SlaveFields
+ properties at the form.
+ @precond
+ we're inspecting (sub) database form
+ @return
+ <TRUE/> if and only if the user successfully enter master and slave fields
+ */
+ bool impl_dialogLinkedFormFields_nothrow( ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
+
+ /** executes a dialog which allows the user to modify the FormatKey
+ property of our component, by choosing a (number) format.
+ @precond
+ Our component actually has a FormatKey property.
+ @param _out_rNewValue
+ the new property value, if the user chose a new formatting
+ @return
+ <TRUE/> if and only if a new formatting has been chosen by the user.
+ In this case, ->_out_rNewValue is filled with the new property value
+ */
+ bool impl_dialogFormatting_nothrow( css::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
+
+ /** executes a dialog which allows to the user to change the ImageURL property
+ of our component by browsing for an image file.
+ @precond
+ our component actually has an ImageURL property
+ @param _out_rNewValue
+ the new property value, if the user chose a new image url
+ @return
+ <TRUE/> if and only if a new image URL has been chosen by the user.
+ In this case, ->_out_rNewValue is filled with the new property value
+ */
+ bool impl_browseForImage_nothrow( css::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
+
+ /** executes a dialog which allows the user to change the TargetURL property of
+ our component
+ @precond
+ our component actually has a TargetURL property
+ @param _out_rNewValue
+ the new property value, if the user chose a new TargetURL
+ @return
+ <TRUE/> if and only if a new TargetURL has been chosen by the user.
+ In this case, ->_out_rNewValue is filled with the new property value
+ */
+ bool impl_browseForTargetURL_nothrow( css::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
+
+ /** executes a dialog which allows the user to change the font, plus related properties,
+ of our component
+ @precond
+ our component actually has a Font property
+ @param _out_rNewValue
+ a value describing the new font, as <code>Sequence&lt; NamedValue &gt;</code>
+ @return
+ <TRUE/> if and only if the user successfully changed the font of our component
+ */
+ bool impl_executeFontDialog_nothrow( css::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
+
+ /** allows the user browsing for a database document
+ @precond
+ our component actually has a DataSource property
+ @param _out_rNewValue
+ the new property value, if the user chose a new DataSource
+ @return
+ <TRUE/> if and only if a new DataSource has been chosen by the user.
+ In this case, ->_out_rNewValue is filled with the new property value
+ */
+ bool impl_browseForDatabaseDocument_throw( css::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
+
+ /** raises a dialog which allows the user to choose a color
+ @param _nColorPropertyId
+ the ID of the color property
+ @param _out_rNewValue
+ the chosen color value
+ @return
+ <TRUE/> if and only if a color was chosen by the user
+ */
+ bool impl_dialogColorChooser_throw( sal_Int32 _nColorPropertyId, css::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
+
+ /** raises a dialog which allows the user to choose a label control for our component
+ @param _out_rNewValue
+ the chosen label control, if any
+ @return
+ <TRUE/> if and only if a label control was chosen by the user
+ */
+ bool impl_dialogChooseLabelControl_nothrow( css::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
+
+ /** raises a dialog which lets the user chose the tab order of controls of a form
+ @precond
+ we have a view control container in which our controls live
+ @return
+ <TRUE/> if and only if the user successfully changed the tab order
+ @seealso impl_getContextControlContainer_nothrow
+ */
+ bool impl_dialogChangeTabOrder_nothrow( ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
+
+ /** retrieves the context for controls, whose model(s) we're inspecting
+
+ If we're inspecting a control model, this is usually part of a set of controls
+ and control models, where the controls live in a certain context (a ->XControlContainer).
+ If we know this context, we can enable additional special functionality.
+
+ The ->XComponentContext in which we were created is examined for a value
+ named "ControlContext", and this value is returned.
+ */
+ css::uno::Reference< css::awt::XControlContainer >
+ impl_getContextControlContainer_nothrow() const;
+
+ /** opens a query design window for interactively designing the SQL command of a
+ database form
+ @param _rxUIUpdate
+ access to the property browser UI
+ @param _nDesignForProperty
+ the ID for the property for which the designer is opened
+ @return
+ <TRUE/> if the window was successfully opened, or was previously open,
+ <FALSE/> otherwise
+ */
+ bool impl_doDesignSQLCommand_nothrow(
+ const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI,
+ PropertyId _nDesignForProperty
+ );
+
+ /** updates a property (UI) whose state depends on more than one other property
+
+ ->actuatingPropertyChanged is called for certain properties in whose changes
+ we expressed interes (->getActuatingProperty). Now such a property change can
+ result in simple UI updates, for instance another property being enabled or disabled.
+
+ However, it can also result in a more complex change: The current (UI) state might
+ depend on the value of more than one other property. Those dependent properties (their
+ UI, more precisely) are updated in this method.
+
+ @param _nPropid
+ the ->PropertyId of the dependent property whose UI state is to be updated
+
+ @param _rxInspectorUI
+ provides access to the property browser UI. Must not be <NULL/>.
+ */
+ void impl_updateDependentProperty_nothrow( PropertyId _nPropId, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) const;
+
+ /** determines whether the given form has a valid data source signature.
+
+ Valid here means that the DataSource property denotes an existing data source, and the
+ Command property is not empty. No check is made whether the value of the Command property
+ denotes an existent object, since this would be way too expensive.
+
+ @param _xFormProperties
+ the form to check. Must not be <NULL/>.
+ @param _bAllowEmptyDataSourceName
+ determine whether an empty data source name is allowed (<TRUE/>), and should not
+ lead to rejection
+ */
+ static bool impl_hasValidDataSourceSignature_nothrow(
+ const css::uno::Reference< css::beans::XPropertySet >& _xFormProperties,
+ bool _bAllowEmptyDataSourceName );
+
+ /** returns the URL of our context document
+ @return
+ */
+ OUString impl_getDocumentURL_nothrow() const;
+
+ private:
+ DECL_LINK( OnDesignerClosed, SQLCommandDesigner&, void );
+
+ private:
+ FormComponentPropertyHandler( const FormComponentPropertyHandler& ) = delete;
+ FormComponentPropertyHandler& operator=( const FormComponentPropertyHandler& ) = delete;
+
+ private:
+ using ::comphelper::OPropertyContainer::addPropertyChangeListener;
+ using ::comphelper::OPropertyContainer::removePropertyChangeListener;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/formcontroller.cxx b/extensions/source/propctrlr/formcontroller.cxx
new file mode 100644
index 000000000..6e94aa0d1
--- /dev/null
+++ b/extensions/source/propctrlr/formcontroller.cxx
@@ -0,0 +1,241 @@
+/* -*- 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 "formcontroller.hxx"
+#include "pcrcommon.hxx"
+#include "formstrings.hxx"
+#include "defaultforminspection.hxx"
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/util/VetoException.hpp>
+#include <cppuhelper/typeprovider.hxx>
+
+
+namespace pcr
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::TypeClass_INTERFACE;
+ using ::com::sun::star::uno::TypeClass_STRING;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::inspection::XObjectInspectorModel;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::beans::Property;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::uno::Type;
+ using ::com::sun::star::util::VetoException;
+ using ::com::sun::star::beans::PropertyVetoException;
+ using ::com::sun::star::uno::UNO_QUERY;
+
+ namespace PropertyAttribute = css::beans::PropertyAttribute;
+
+
+ //= FormController
+
+
+ FormController::FormController( const Reference< XComponentContext >& _rxContext,
+ const OUString& sImplementationName,
+ const css::uno::Sequence<OUString>& aSupportedServiceNames,
+ bool _bUseFormFormComponentHandlers )
+ :OPropertyBrowserController( _rxContext )
+ ,FormController_PropertyBase1( m_aBHelper )
+ ,m_sImplementationName( sImplementationName )
+ ,m_aSupportedServiceNames( aSupportedServiceNames )
+ {
+ osl_atomic_increment( &m_refCount );
+ {
+ Reference< XObjectInspectorModel > xModel(
+ *(new DefaultFormComponentInspectorModel( _bUseFormFormComponentHandlers )),
+ UNO_QUERY_THROW
+ );
+ setInspectorModel( xModel );
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+
+ FormController::~FormController()
+ {
+ }
+
+
+ IMPLEMENT_FORWARD_XINTERFACE2( FormController, OPropertyBrowserController, FormController_PropertyBase1 )
+
+
+ Sequence< Type > SAL_CALL FormController::getTypes( )
+ {
+ ::cppu::OTypeCollection aTypes(
+ cppu::UnoType<XPropertySet>::get(),
+ cppu::UnoType<XMultiPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ OPropertyBrowserController::getTypes());
+ return aTypes.getTypes();
+ }
+
+
+ IMPLEMENT_GET_IMPLEMENTATION_ID( FormController )
+
+
+ OUString SAL_CALL FormController::getImplementationName( )
+ {
+ return m_sImplementationName;
+ }
+
+
+ Sequence< OUString > SAL_CALL FormController::getSupportedServiceNames( )
+ {
+ Sequence< OUString > aSupported( m_aSupportedServiceNames );
+ aSupported.realloc( aSupported.getLength() + 1 );
+ aSupported.getArray()[ aSupported.getLength() - 1 ] = "com.sun.star.inspection.ObjectInspector";
+ return aSupported;
+ }
+
+
+ Reference< XPropertySetInfo > SAL_CALL FormController::getPropertySetInfo( )
+ {
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+ }
+
+
+ ::cppu::IPropertyArrayHelper& SAL_CALL FormController::getInfoHelper()
+ {
+ return *getArrayHelper();
+ }
+
+
+ ::cppu::IPropertyArrayHelper* FormController::createArrayHelper( ) const
+ {
+ Sequence< Property > aProps{
+ Property(
+ PROPERTY_CURRENTPAGE,
+ OWN_PROPERTY_ID_CURRENTPAGE,
+ ::cppu::UnoType<OUString>::get(),
+ PropertyAttribute::TRANSIENT
+ ),
+ Property(
+ PROPERTY_INTROSPECTEDOBJECT,
+ OWN_PROPERTY_ID_INTROSPECTEDOBJECT,
+ cppu::UnoType<XPropertySet>::get(),
+ PropertyAttribute::TRANSIENT | PropertyAttribute::CONSTRAINED
+ )
+ };
+ return new ::cppu::OPropertyArrayHelper( aProps );
+ }
+
+
+ sal_Bool SAL_CALL FormController::convertFastPropertyValue( Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
+ {
+ switch ( nHandle )
+ {
+ case OWN_PROPERTY_ID_INTROSPECTEDOBJECT:
+ if ( rValue.getValueTypeClass() != TypeClass_INTERFACE )
+ throw IllegalArgumentException();
+ break;
+ case OWN_PROPERTY_ID_CURRENTPAGE:
+ if ( rValue.getValueTypeClass() != TypeClass_STRING )
+ throw IllegalArgumentException();
+ break;
+ }
+
+ getFastPropertyValue( rOldValue, nHandle );
+ rConvertedValue = rValue;
+ return true;
+ }
+
+
+ void SAL_CALL FormController::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue)
+ {
+ switch ( _nHandle )
+ {
+ case OWN_PROPERTY_ID_INTROSPECTEDOBJECT:
+ {
+ Reference< XObjectInspectorModel > xModel( getInspectorModel() );
+ if ( xModel.is() )
+ {
+ try
+ {
+ m_xCurrentInspectee.set( _rValue, UNO_QUERY );
+ Sequence< Reference< XInterface > > aObjects;
+ if ( m_xCurrentInspectee.is() )
+ {
+ aObjects = { m_xCurrentInspectee };
+ }
+
+ Reference< XObjectInspector > xInspector( *this, UNO_QUERY_THROW );
+ xInspector->inspect( aObjects );
+ }
+ catch( const VetoException& e )
+ {
+ throw PropertyVetoException( e.Message, e.Context );
+ }
+ }
+ }
+ break;
+ case OWN_PROPERTY_ID_CURRENTPAGE:
+ restoreViewData( _rValue );
+ break;
+ }
+ }
+
+
+ void SAL_CALL FormController::getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const
+ {
+ switch ( nHandle )
+ {
+ case OWN_PROPERTY_ID_INTROSPECTEDOBJECT:
+ rValue <<= m_xCurrentInspectee;
+ break;
+
+ case OWN_PROPERTY_ID_CURRENTPAGE:
+ rValue = const_cast< FormController* >( this )->getViewData();
+ break;
+ }
+ }
+
+
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_FormController_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::FormController( context,
+ "org.openoffice.comp.extensions.FormController",
+ { "com.sun.star.form.PropertyBrowserController" },
+ true ) );
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_DialogController_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::FormController( context,
+ "org.openoffice.comp.extensions.DialogController",
+ { "com.sun.star.awt.PropertyBrowserController" },
+ false ) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/formcontroller.hxx b/extensions/source/propctrlr/formcontroller.hxx
new file mode 100644
index 000000000..8c285160e
--- /dev/null
+++ b/extensions/source/propctrlr/formcontroller.hxx
@@ -0,0 +1,103 @@
+/* -*- 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 "propcontroller.hxx"
+
+#include <cppuhelper/propshlp.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/uno3.hxx>
+
+
+namespace pcr
+{
+
+
+ //= FormController
+
+ class FormController;
+ typedef ::cppu::OPropertySetHelper FormController_PropertyBase1;
+ typedef ::comphelper::OPropertyArrayUsageHelper< FormController > FormController_PropertyBase2;
+
+ /** Legacy implementation of com.sun.star.form.PropertyBrowserController
+
+ Nowadays only a wrapper around an ObjectInspector using a
+ DefaultFormComponentInspectorModel.
+ */
+ class FormController :public OPropertyBrowserController
+ ,public FormController_PropertyBase1
+ ,public FormController_PropertyBase2
+ {
+ private:
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xCurrentInspectee;
+ OUString m_sImplementationName;
+ css::uno::Sequence<OUString> m_aSupportedServiceNames;
+ public:
+ FormController(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ const OUString& sImplementName,
+ const css::uno::Sequence<OUString>& aSupportedServiceNames,
+ bool _bUseFormFormComponentHandlers
+ );
+
+ protected:
+ virtual ~FormController() override;
+
+ DECLARE_XINTERFACE()
+ DECLARE_XTYPEPROVIDER()
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XPropertySet and friends
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue, css::uno::Any & rOldValue, sal_Int32 nHandle, const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle, const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue, sal_Int32 nHandle
+ ) const override;
+ private:
+ using FormController_PropertyBase1::getFastPropertyValue;
+ };
+
+
+ //= DialogController
+
+ /** Legacy implementation of com.sun.star.awt.PropertyBrowserController
+ */
+ class DialogController
+ {
+ private:
+ DialogController( const DialogController& ) = delete;
+ DialogController& operator=( const DialogController& ) = delete;
+ };
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/formgeometryhandler.cxx b/extensions/source/propctrlr/formgeometryhandler.cxx
new file mode 100644
index 000000000..26c432405
--- /dev/null
+++ b/extensions/source/propctrlr/formgeometryhandler.cxx
@@ -0,0 +1,820 @@
+/* -*- 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 "propertyhandler.hxx"
+#include "formmetadata.hxx"
+#include "formstrings.hxx"
+#include "handlerhelper.hxx"
+#include "cellbindinghelper.hxx"
+
+#include <com/sun/star/inspection/XObjectInspectorUI.hpp>
+#include <com/sun/star/awt/XControlModel.hpp>
+#include <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/container/XMap.hpp>
+#include <com/sun/star/inspection/XNumericControl.hpp>
+#include <com/sun/star/util/MeasureUnit.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/table/XColumnRowRange.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/form/XGridColumnFactory.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/interfacecontainer.hxx>
+#include <comphelper/interfacecontainer2.hxx>
+#include <comphelper/componentbase.hxx>
+#include <rtl/ref.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace pcr
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::beans::Property;
+ using ::com::sun::star::awt::XControlModel;
+ using ::com::sun::star::drawing::XControlShape;
+ using ::com::sun::star::container::XMap;
+ using ::com::sun::star::inspection::LineDescriptor;
+ using ::com::sun::star::inspection::XPropertyControlFactory;
+ using ::com::sun::star::lang::NullPointerException;
+ using ::com::sun::star::beans::Optional;
+ using ::com::sun::star::inspection::XNumericControl;
+ using ::com::sun::star::drawing::XShape;
+ using ::com::sun::star::beans::PropertyChangeEvent;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::beans::XPropertyChangeListener;
+ using ::com::sun::star::text::TextContentAnchorType;
+ using ::com::sun::star::text::TextContentAnchorType_AT_PARAGRAPH;
+ using ::com::sun::star::text::TextContentAnchorType_AS_CHARACTER;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::inspection::XObjectInspectorUI;
+ using ::com::sun::star::lang::XServiceInfo;
+ using ::com::sun::star::sheet::XSpreadsheet;
+ using ::com::sun::star::table::XColumnRowRange;
+ using ::com::sun::star::table::XTableColumns;
+ using ::com::sun::star::table::XTableRows;
+ using ::com::sun::star::container::XIndexAccess;
+ using ::com::sun::star::container::XChild;
+ using ::com::sun::star::form::XGridColumnFactory;
+
+ namespace MeasureUnit = css::util::MeasureUnit;
+
+ #define ANCHOR_TO_SHEET 0
+ #define ANCHOR_TO_CELL 1
+
+
+ //= BroadcastHelperBase
+
+ namespace {
+
+ class BroadcastHelperBase
+ {
+ protected:
+ explicit BroadcastHelperBase( ::osl::Mutex& _rMutex )
+ :maBHelper( _rMutex )
+ {
+ }
+
+ protected:
+ ::cppu::OBroadcastHelper& getBroadcastHelper() { return maBHelper; }
+
+ private:
+ ::cppu::OBroadcastHelper maBHelper;
+ };
+
+ }
+
+ //= ShapeGeometryChangeNotifier - declaration
+
+ /** helper class to work around the ...unfortunate implementation of property change broadcasts
+ in the XShape implementation, which broadcasts way too generous and unspecified
+ */
+ typedef ::comphelper::ComponentBase ShapeGeometryChangeNotifier_CBase;
+ typedef ::cppu::WeakImplHelper < css::beans::XPropertyChangeListener
+ > ShapeGeometryChangeNotifier_IBase;
+
+ namespace {
+
+ class ShapeGeometryChangeNotifier :public BroadcastHelperBase
+ ,public ShapeGeometryChangeNotifier_CBase
+ ,public ShapeGeometryChangeNotifier_IBase
+ {
+ public:
+ ShapeGeometryChangeNotifier( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rParentMutex, const Reference< XShape >& _shape )
+ :BroadcastHelperBase( _rParentMutex )
+ ,ShapeGeometryChangeNotifier_CBase( BroadcastHelperBase::getBroadcastHelper(), ::comphelper::ComponentBase::NoInitializationNeeded() )
+ ,m_rParent( _rParent )
+ ,m_aPropertyChangeListeners( _rParentMutex )
+ ,m_xShape( _shape )
+ {
+ ENSURE_OR_THROW( m_xShape.is(), "illegal shape!" );
+ impl_init_nothrow();
+ }
+
+ // property change broadcasting
+ void addPropertyChangeListener( const Reference< XPropertyChangeListener >& _listener )
+ {
+ m_aPropertyChangeListeners.addInterface( _listener );
+ }
+ void removePropertyChangeListener( const Reference< XPropertyChangeListener >& _listener )
+ {
+ m_aPropertyChangeListeners.removeInterface( _listener );
+ }
+
+ // XComponent equivalent
+ void dispose()
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+ impl_dispose_nothrow();
+ }
+
+ // XInterface
+ virtual void SAL_CALL acquire( ) noexcept override
+ {
+ m_rParent.acquire();
+ }
+
+ virtual void SAL_CALL release( ) noexcept override
+ {
+ m_rParent.release();
+ }
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const PropertyChangeEvent& _event ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const EventObject& _event ) override;
+
+ protected:
+ virtual ~ShapeGeometryChangeNotifier() override
+ {
+ if ( !getBroadcastHelper().bDisposed )
+ {
+ acquire();
+ dispose();
+ }
+ }
+
+ protected:
+ ::cppu::OBroadcastHelper& getBroadcastHelper() { return BroadcastHelperBase::getBroadcastHelper(); }
+
+ private:
+ void impl_init_nothrow();
+ void impl_dispose_nothrow();
+
+ private:
+ ::cppu::OWeakObject& m_rParent;
+ ::comphelper::OInterfaceContainerHelper2 m_aPropertyChangeListeners;
+ Reference< XShape > m_xShape;
+ };
+
+ }
+
+ //= FormGeometryHandler - declaration
+
+ namespace {
+
+ class FormGeometryHandler;
+
+ }
+
+ /** a property handler for any virtual string properties
+ */
+
+ namespace {
+
+ class FormGeometryHandler : public PropertyHandlerComponent
+ {
+ public:
+ explicit FormGeometryHandler(
+ const Reference< XComponentContext >& _rxContext
+ );
+
+ protected:
+ virtual ~FormGeometryHandler() override;
+
+ protected:
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override;
+
+ // XPropertyHandler overriables
+ virtual Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) override;
+ virtual LineDescriptor SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+ virtual Sequence< OUString > SAL_CALL getActuatingProperties( ) override;
+ virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& _rOldValue, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override;
+
+ // OComponentHandler overridables
+ virtual void SAL_CALL disposing() override;
+
+ // PropertyHandler overridables
+ virtual Sequence< Property > doDescribeSupportedProperties() const override;
+
+ protected:
+ virtual void onNewComponent() override;
+
+ private:
+ bool impl_haveTextAnchorType_nothrow() const;
+ bool impl_haveSheetAnchorType_nothrow() const;
+ void impl_setSheetAnchorType_nothrow( const sal_Int32 _nAnchorType ) const;
+
+ private:
+ Reference< XControlShape > m_xAssociatedShape;
+ Reference< XPropertySet > m_xShapeProperties;
+ ::rtl::Reference< ShapeGeometryChangeNotifier > m_xChangeNotifier;
+ };
+
+ }
+
+ //= FormGeometryHandler - implementation
+
+
+ FormGeometryHandler::FormGeometryHandler( const Reference< XComponentContext >& _rxContext )
+ :PropertyHandlerComponent( _rxContext )
+ {
+ }
+
+
+ FormGeometryHandler::~FormGeometryHandler( )
+ {
+ if ( !rBHelper.bDisposed )
+ {
+ acquire();
+ dispose();
+ }
+
+ }
+
+
+ void FormGeometryHandler::onNewComponent()
+ {
+ if ( m_xChangeNotifier.is() )
+ {
+ m_xChangeNotifier->dispose();
+ m_xChangeNotifier.clear();
+ }
+ m_xAssociatedShape.clear();
+ m_xShapeProperties.clear();
+
+ PropertyHandlerComponent::onNewComponent();
+
+ try
+ {
+ Reference< XControlModel > xControlModel( m_xComponent, UNO_QUERY );
+ if ( xControlModel.is() )
+ {
+ // do not ask the map for shapes for grid control columns...
+ Reference< XChild > xCompChild( m_xComponent, UNO_QUERY_THROW );
+ Reference< XGridColumnFactory > xCheckGrid( xCompChild->getParent(), UNO_QUERY );
+ if ( !xCheckGrid.is() )
+ {
+ Reference< XMap > xControlMap;
+ Any any = m_xContext->getValueByName( "ControlShapeAccess" );
+ any >>= xControlMap;
+ m_xAssociatedShape.set( xControlMap->get( Any( xControlModel ) ), UNO_QUERY_THROW );
+ m_xShapeProperties.set( m_xAssociatedShape, UNO_QUERY_THROW );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+
+ if ( m_xAssociatedShape.is() )
+ m_xChangeNotifier = new ShapeGeometryChangeNotifier( *this, m_aMutex, m_xAssociatedShape );
+ }
+
+
+ OUString FormGeometryHandler::getImplementationName( )
+ {
+ return "com.sun.star.comp.extensions.FormGeometryHandler";
+ }
+
+
+ Sequence< OUString > FormGeometryHandler::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.form.inspection.FormGeometryHandler" };
+ }
+
+
+ Any SAL_CALL FormGeometryHandler::getPropertyValue( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ ENSURE_OR_THROW2( m_xAssociatedShape.is(), "internal error: properties, but no shape!", *this );
+ ENSURE_OR_THROW2( m_xShapeProperties.is(), "internal error: no shape properties!", *this );
+
+ Any aReturn;
+ try
+ {
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_POSITIONX:
+ aReturn <<= m_xAssociatedShape->getPosition().X;
+ break;
+ case PROPERTY_ID_POSITIONY:
+ aReturn <<= m_xAssociatedShape->getPosition().Y;
+ break;
+ case PROPERTY_ID_WIDTH:
+ aReturn <<= m_xAssociatedShape->getSize().Width;
+ break;
+ case PROPERTY_ID_HEIGHT:
+ aReturn <<= m_xAssociatedShape->getSize().Height;
+ break;
+ case PROPERTY_ID_TEXT_ANCHOR_TYPE:
+ aReturn = m_xShapeProperties->getPropertyValue( PROPERTY_ANCHOR_TYPE );
+ OSL_ENSURE( aReturn.hasValue(), "FormGeometryHandler::getPropertyValue: illegal anchor type!" );
+ break;
+ case PROPERTY_ID_SHEET_ANCHOR_TYPE:
+ {
+ Reference< XSpreadsheet > xAnchorSheet( m_xShapeProperties->getPropertyValue( PROPERTY_ANCHOR ), UNO_QUERY );
+ aReturn <<= sal_Int32( xAnchorSheet.is() ? ANCHOR_TO_SHEET : ANCHOR_TO_CELL );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "FormGeometryHandler::getPropertyValue: huh?" );
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ return aReturn;
+ }
+
+
+ void SAL_CALL FormGeometryHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ ENSURE_OR_THROW2( m_xAssociatedShape.is(), "internal error: properties, but no shape!", *this );
+ ENSURE_OR_THROW2( m_xShapeProperties.is(), "internal error: properties, but no shape!", *this );
+
+ try
+ {
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_POSITIONX:
+ case PROPERTY_ID_POSITIONY:
+ {
+ sal_Int32 nPosition(0);
+ OSL_VERIFY( _rValue >>= nPosition );
+
+ css::awt::Point aPos( m_xAssociatedShape->getPosition() );
+ if ( nPropId == PROPERTY_ID_POSITIONX )
+ aPos.X = nPosition;
+ else
+ aPos.Y = nPosition;
+ m_xAssociatedShape->setPosition( aPos );
+ }
+ break;
+
+ case PROPERTY_ID_WIDTH:
+ case PROPERTY_ID_HEIGHT:
+ {
+ sal_Int32 nSize(0);
+ OSL_VERIFY( _rValue >>= nSize );
+
+ css::awt::Size aSize( m_xAssociatedShape->getSize() );
+ if ( nPropId == PROPERTY_ID_WIDTH )
+ aSize.Width = nSize;
+ else
+ aSize.Height = nSize;
+ m_xAssociatedShape->setSize( aSize );
+ }
+ break;
+
+ case PROPERTY_ID_TEXT_ANCHOR_TYPE:
+ m_xShapeProperties->setPropertyValue( PROPERTY_ANCHOR_TYPE, _rValue );
+ break;
+
+ case PROPERTY_ID_SHEET_ANCHOR_TYPE:
+ {
+ sal_Int32 nSheetAnchorType = 0;
+ OSL_VERIFY( _rValue >>= nSheetAnchorType );
+ impl_setSheetAnchorType_nothrow( nSheetAnchorType );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "FormGeometryHandler::getPropertyValue: huh?" );
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+
+ LineDescriptor SAL_CALL FormGeometryHandler::describePropertyLine( const OUString& _rPropertyName,
+ const Reference< XPropertyControlFactory >& _rxControlFactory )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ LineDescriptor aLineDesc( PropertyHandler::describePropertyLine( _rPropertyName, _rxControlFactory ) );
+ try
+ {
+ bool bIsSize = false;
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_WIDTH:
+ case PROPERTY_ID_HEIGHT:
+ bIsSize = true;
+ [[fallthrough]];
+ case PROPERTY_ID_POSITIONX:
+ case PROPERTY_ID_POSITIONY:
+ {
+ Optional< double > aZero( true, 0 );
+ Optional< double > aValueNotPresent( false, 0 );
+ aLineDesc.Control = PropertyHandlerHelper::createNumericControl(
+ _rxControlFactory, 2, bIsSize ? aZero : aValueNotPresent, aValueNotPresent );
+
+ Reference< XNumericControl > xNumericControl( aLineDesc.Control, UNO_QUERY_THROW );
+ xNumericControl->setValueUnit( MeasureUnit::MM_100TH );
+ xNumericControl->setDisplayUnit( impl_getDocumentMeasurementUnit_throw() );
+ }
+ break;
+
+ case PROPERTY_ID_TEXT_ANCHOR_TYPE:
+ case PROPERTY_ID_SHEET_ANCHOR_TYPE:
+ // default handling from PropertyHandler is sufficient
+ break;
+
+ default:
+ OSL_FAIL( "FormGeometryHandler::describePropertyLine: huh?" );
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ return aLineDesc;
+ }
+
+
+ void SAL_CALL FormGeometryHandler::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _listener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OSL_PRECOND( m_xChangeNotifier.is(), "FormGeometryHandler::addPropertyChangeListener: no notified, implies no shape!?" );
+ if ( m_xChangeNotifier.is() )
+ m_xChangeNotifier->addPropertyChangeListener( _listener );
+ }
+
+
+ void SAL_CALL FormGeometryHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _listener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OSL_PRECOND( m_xChangeNotifier.is(), "FormGeometryHandler::removePropertyChangeListener: no notified, implies no shape!?" );
+ if ( m_xChangeNotifier.is() )
+ m_xChangeNotifier->removePropertyChangeListener( _listener );
+ }
+
+
+ Sequence< OUString > SAL_CALL FormGeometryHandler::getActuatingProperties( )
+ {
+ Sequence< OUString > aInterestedIn { PROPERTY_TEXT_ANCHOR_TYPE };
+ return aInterestedIn;
+ }
+
+
+ void SAL_CALL FormGeometryHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool /*_bFirstTimeInit*/ )
+ {
+ if ( !_rxInspectorUI.is() )
+ throw NullPointerException();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nActuatingPropId( impl_getPropertyId_nothrow( _rActuatingPropertyName ) );
+
+ switch ( nActuatingPropId )
+ {
+ case PROPERTY_ID_TEXT_ANCHOR_TYPE:
+ {
+ TextContentAnchorType eAnchorType( TextContentAnchorType_AT_PARAGRAPH );
+ OSL_VERIFY( _rNewValue >>= eAnchorType );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_POSITIONX, eAnchorType != TextContentAnchorType_AS_CHARACTER );
+ }
+ break;
+ case -1:
+ throw RuntimeException();
+ break;
+ default:
+ OSL_FAIL( "FormGeometryHandler::actuatingPropertyChanged: not registered for this property!" );
+ break;
+ }
+ }
+
+
+ Sequence< Property > FormGeometryHandler::doDescribeSupportedProperties() const
+ {
+ if ( !m_xAssociatedShape.is() )
+ return Sequence< Property >();
+
+ std::vector< Property > aProperties;
+
+ addInt32PropertyDescription( aProperties, PROPERTY_POSITIONX );
+ addInt32PropertyDescription( aProperties, PROPERTY_POSITIONY );
+ addInt32PropertyDescription( aProperties, PROPERTY_WIDTH );
+ addInt32PropertyDescription( aProperties, PROPERTY_HEIGHT );
+
+ if ( impl_haveTextAnchorType_nothrow() )
+ implAddPropertyDescription( aProperties, PROPERTY_TEXT_ANCHOR_TYPE, ::cppu::UnoType< TextContentAnchorType >::get() );
+
+ if ( impl_haveSheetAnchorType_nothrow() )
+ addInt32PropertyDescription( aProperties, PROPERTY_SHEET_ANCHOR_TYPE );
+
+ return comphelper::containerToSequence(aProperties);
+ }
+
+
+ void SAL_CALL FormGeometryHandler::disposing()
+ {
+ PropertyHandlerComponent::disposing();
+
+ if ( m_xChangeNotifier.is() )
+ {
+ m_xChangeNotifier->dispose();
+ m_xChangeNotifier.clear();
+ }
+ }
+
+
+ bool FormGeometryHandler::impl_haveTextAnchorType_nothrow() const
+ {
+ ENSURE_OR_THROW( m_xShapeProperties.is(), "not to be called without shape properties" );
+ try
+ {
+ Reference< XPropertySetInfo > xPSI( m_xShapeProperties->getPropertySetInfo(), UNO_SET_THROW );
+ if ( xPSI->hasPropertyByName( PROPERTY_ANCHOR_TYPE ) )
+ return true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ return false;
+ }
+
+
+ bool FormGeometryHandler::impl_haveSheetAnchorType_nothrow() const
+ {
+ ENSURE_OR_THROW( m_xShapeProperties.is(), "not to be called without shape properties" );
+ try
+ {
+ Reference< XPropertySetInfo > xPSI( m_xShapeProperties->getPropertySetInfo(), UNO_SET_THROW );
+ if ( !xPSI->hasPropertyByName( PROPERTY_ANCHOR ) )
+ return false;
+ Reference< XServiceInfo > xSI( m_xAssociatedShape, UNO_QUERY_THROW );
+ if ( xSI->supportsService("com.sun.star.sheet.Shape") )
+ return true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ return false;
+ }
+
+
+ namespace
+ {
+ sal_Int32 lcl_getLowerBoundRowOrColumn( const Reference< XIndexAccess >& _rxRowsOrColumns, const bool _bRows,
+ const css::awt::Point& _rRelativePosition )
+ {
+ sal_Int32 nAccumulated = 0;
+
+ const sal_Int32& rRelativePos = _bRows ? _rRelativePosition.Y : _rRelativePosition.X;
+
+ sal_Int32 nElements = _rxRowsOrColumns->getCount();
+ sal_Int32 currentPos = 0;
+ for ( currentPos=0; currentPos<nElements; ++currentPos )
+ {
+ Reference< XPropertySet > xRowOrColumn( _rxRowsOrColumns->getByIndex( currentPos ), UNO_QUERY_THROW );
+
+ bool bIsVisible = true;
+ OSL_VERIFY( xRowOrColumn->getPropertyValue( PROPERTY_IS_VISIBLE ) >>= bIsVisible );
+ if ( !bIsVisible )
+ continue;
+
+ sal_Int32 nHeightOrWidth( 0 );
+ OSL_VERIFY( xRowOrColumn->getPropertyValue( _bRows ? OUString(PROPERTY_HEIGHT) : OUString(PROPERTY_WIDTH) ) >>= nHeightOrWidth );
+
+ if ( nAccumulated + nHeightOrWidth > rRelativePos )
+ break;
+
+ nAccumulated += nHeightOrWidth;
+ }
+
+ return currentPos;
+ }
+ }
+
+
+ void FormGeometryHandler::impl_setSheetAnchorType_nothrow( const sal_Int32 _nAnchorType ) const
+ {
+ ENSURE_OR_THROW( m_xShapeProperties.is(), "illegal to be called without shape properties." );
+ try
+ {
+ CellBindingHelper aHelper( m_xComponent, impl_getContextDocument_nothrow() );
+ // find the sheet which the control belongs to
+ Reference< XSpreadsheet > xSheet;
+ aHelper.getControlSheetIndex( xSheet );
+
+ switch ( _nAnchorType )
+ {
+ case ANCHOR_TO_SHEET:
+ OSL_ENSURE( xSheet.is(),
+ "FormGeometryHandler::impl_setSheetAnchorType_nothrow: sheet not found!" );
+ if ( xSheet.is() )
+ {
+ css::awt::Point aPreservePosition( m_xAssociatedShape->getPosition() );
+ m_xShapeProperties->setPropertyValue( PROPERTY_ANCHOR, Any( xSheet ) );
+ m_xAssociatedShape->setPosition( aPreservePosition );
+ }
+ break;
+
+ case ANCHOR_TO_CELL:
+ {
+ Reference< XColumnRowRange > xColsRows( xSheet, UNO_QUERY_THROW );
+
+ // get the current anchor
+ Reference< XSpreadsheet > xCurrentAnchor;
+ OSL_VERIFY( m_xShapeProperties->getPropertyValue( PROPERTY_ANCHOR ) >>= xCurrentAnchor );
+ OSL_ENSURE( xCurrentAnchor.is(), "FormGeometryHandler::impl_setSheetAnchorType_nothrow: only to be called when currently anchored to a sheet!" );
+
+ // get the current position
+ css::awt::Point aRelativePosition( m_xAssociatedShape->getPosition() );
+
+ Reference< XTableColumns > xCols( xColsRows->getColumns(), UNO_SET_THROW );
+ sal_Int32 nNewAnchorCol = lcl_getLowerBoundRowOrColumn( xCols, false, aRelativePosition );
+
+ Reference< XTableRows > xRows( xColsRows->getRows(), UNO_SET_THROW );
+ sal_Int32 nNewAnchorRow = lcl_getLowerBoundRowOrColumn( xRows, true, aRelativePosition );
+
+ Any aNewAnchorCell( xSheet->getCellByPosition( nNewAnchorCol, nNewAnchorRow ) );
+ m_xShapeProperties->setPropertyValue( PROPERTY_ANCHOR, aNewAnchorCell );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "FormGeometryHandler::impl_setSheetAnchorType_nothrow: illegal anchor type!" );
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+
+ //= ShapeGeometryChangeNotifier - implementation
+
+ namespace
+ {
+ struct EventTranslation
+ {
+ OUString sPropertyName;
+ Any aNewPropertyValue;
+
+ EventTranslation( const OUString& _propertyName, const Any& _newPropertyValue )
+ :sPropertyName( _propertyName )
+ ,aNewPropertyValue( _newPropertyValue )
+ {
+ }
+ };
+ }
+
+
+ void SAL_CALL ShapeGeometryChangeNotifier::propertyChange( const PropertyChangeEvent& _event )
+ {
+ ::comphelper::ComponentMethodGuard aGuard( *this );
+
+ std::vector< EventTranslation > aEventTranslations;
+ aEventTranslations.reserve(2);
+
+ if ( _event.PropertyName == "Position" )
+ {
+ css::awt::Point aPos = m_xShape->getPosition();
+ aEventTranslations.push_back( EventTranslation( PROPERTY_POSITIONX, Any( aPos.X ) ) );
+ aEventTranslations.push_back( EventTranslation( PROPERTY_POSITIONY, Any( aPos.Y ) ) );
+ }
+ else if ( _event.PropertyName == "Size" )
+ {
+ css::awt::Size aSize = m_xShape->getSize();
+ aEventTranslations.push_back( EventTranslation( PROPERTY_WIDTH, Any( aSize.Width ) ) );
+ aEventTranslations.push_back( EventTranslation( PROPERTY_HEIGHT, Any( aSize.Height ) ) );
+ }
+ else if ( _event.PropertyName == PROPERTY_ANCHOR_TYPE )
+ {
+ aEventTranslations.push_back( EventTranslation( PROPERTY_TEXT_ANCHOR_TYPE, _event.NewValue ) );
+ }
+ else if ( _event.PropertyName == PROPERTY_ANCHOR )
+ {
+ aEventTranslations.push_back( EventTranslation( PROPERTY_SHEET_ANCHOR_TYPE, _event.NewValue ) );
+ }
+
+ PropertyChangeEvent aTranslatedEvent( _event );
+ aTranslatedEvent.Source = m_rParent;
+
+ aGuard.clear();
+ for (auto const& eventTranslation : aEventTranslations)
+ {
+ aTranslatedEvent.PropertyName = eventTranslation.sPropertyName;
+ aTranslatedEvent.NewValue = eventTranslation.aNewPropertyValue;
+ m_aPropertyChangeListeners.notifyEach( &XPropertyChangeListener::propertyChange, aTranslatedEvent );
+ }
+ }
+
+
+ void SAL_CALL ShapeGeometryChangeNotifier::disposing( const EventObject& /*_event*/ )
+ {
+ ::comphelper::ComponentMethodGuard aGuard( *this );
+ impl_dispose_nothrow();
+ }
+
+
+ void ShapeGeometryChangeNotifier::impl_init_nothrow()
+ {
+ osl_atomic_increment( &m_refCount );
+ try
+ {
+ Reference< XPropertySet > xShapeProperties( m_xShape, UNO_QUERY_THROW );
+ xShapeProperties->addPropertyChangeListener( OUString(), this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+
+ void ShapeGeometryChangeNotifier::impl_dispose_nothrow()
+ {
+ try
+ {
+ Reference< XPropertySet > xShapeProperties( m_xShape, UNO_QUERY_THROW );
+ xShapeProperties->removePropertyChangeListener( OUString(), this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+
+ getBroadcastHelper().bDisposed = true;
+ }
+
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_FormGeometryHandler_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::FormGeometryHandler(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/formlinkdialog.cxx b/extensions/source/propctrlr/formlinkdialog.cxx
new file mode 100644
index 000000000..319ade956
--- /dev/null
+++ b/extensions/source/propctrlr/formlinkdialog.cxx
@@ -0,0 +1,630 @@
+/* -*- 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 "formlinkdialog.hxx"
+
+#include "modulepcr.hxx"
+#include <strings.hrc>
+#include "formstrings.hxx"
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+
+
+ //= FieldLinkRow
+
+ class FieldLinkRow
+ {
+ private:
+ std::unique_ptr<weld::ComboBox> m_xDetailColumn;
+ std::unique_ptr<weld::ComboBox> m_xMasterColumn;
+
+ Link<FieldLinkRow&,void> m_aLinkChangeHandler;
+
+ public:
+ FieldLinkRow(std::unique_ptr<weld::ComboBox> xDetailColumn,
+ std::unique_ptr<weld::ComboBox> xMasterColumn);
+
+
+ void SetLinkChangeHandler( const Link<FieldLinkRow&,void>& _rHdl ) { m_aLinkChangeHandler = _rHdl; }
+
+ enum LinkParticipant
+ {
+ eDetailField,
+ eMasterField
+ };
+ /** retrieves the selected field name for either the master or the detail field
+ @return <TRUE/> if and only a valid field is selected
+ */
+ bool GetFieldName( LinkParticipant _eWhich, OUString& /* [out] */ _rName ) const;
+ void SetFieldName( LinkParticipant _eWhich, const OUString& _rName );
+
+ void fillList( LinkParticipant _eWhich, const Sequence< OUString >& _rFieldNames );
+
+ void Show()
+ {
+ m_xDetailColumn->show();
+ m_xMasterColumn->show();
+ }
+
+ private:
+ DECL_LINK( OnFieldNameChanged, weld::ComboBox&, void );
+ };
+
+
+ FieldLinkRow::FieldLinkRow(std::unique_ptr<weld::ComboBox> xDetailColumn,
+ std::unique_ptr<weld::ComboBox> xMasterColumn)
+ : m_xDetailColumn(std::move(xDetailColumn))
+ , m_xMasterColumn(std::move(xMasterColumn))
+ {
+ m_xDetailColumn->connect_changed( LINK( this, FieldLinkRow, OnFieldNameChanged ) );
+ m_xMasterColumn->connect_changed( LINK( this, FieldLinkRow, OnFieldNameChanged ) );
+ }
+
+ void FieldLinkRow::fillList( LinkParticipant _eWhich, const Sequence< OUString >& _rFieldNames )
+ {
+ weld::ComboBox* pBox = ( _eWhich == eDetailField ) ? m_xDetailColumn.get() : m_xMasterColumn.get();
+
+ const OUString* pFieldName = _rFieldNames.getConstArray();
+ const OUString* pFieldNameEnd = pFieldName + _rFieldNames.getLength();
+ for ( ; pFieldName != pFieldNameEnd; ++pFieldName )
+ pBox->append_text( *pFieldName );
+ }
+
+ bool FieldLinkRow::GetFieldName( LinkParticipant _eWhich, OUString& /* [out] */ _rName ) const
+ {
+ const weld::ComboBox* pBox = ( _eWhich == eDetailField ) ? m_xDetailColumn.get() : m_xMasterColumn.get();
+ _rName = pBox->get_active_text();
+ return !_rName.isEmpty();
+ }
+
+ void FieldLinkRow::SetFieldName( LinkParticipant _eWhich, const OUString& _rName )
+ {
+ weld::ComboBox* pBox = ( _eWhich == eDetailField ) ? m_xDetailColumn.get() : m_xMasterColumn.get();
+ pBox->set_entry_text( _rName );
+ }
+
+ IMPL_LINK_NOARG( FieldLinkRow, OnFieldNameChanged, weld::ComboBox&, void )
+ {
+ m_aLinkChangeHandler.Call( *this );
+ }
+
+ //= FormLinkDialog
+
+ FormLinkDialog::FormLinkDialog(weld::Window* _pParent, const Reference< XPropertySet >& _rxDetailForm,
+ const Reference< XPropertySet >& _rxMasterForm, const Reference< XComponentContext >& _rxContext,
+ const OUString& _sExplanation,
+ const OUString& _sDetailLabel,
+ const OUString& _sMasterLabel)
+ : GenericDialogController(_pParent, "modules/spropctrlr/ui/formlinksdialog.ui", "FormLinks")
+ , m_xContext ( _rxContext )
+ , m_xDetailForm( _rxDetailForm )
+ , m_xMasterForm( _rxMasterForm )
+ , m_sDetailLabel(_sDetailLabel)
+ , m_sMasterLabel(_sMasterLabel)
+ , m_xExplanation(m_xBuilder->weld_label("explanationLabel"))
+ , m_xDetailLabel(m_xBuilder->weld_label("detailLabel"))
+ , m_xMasterLabel(m_xBuilder->weld_label("masterLabel"))
+ , m_xRow1(std::make_unique<FieldLinkRow>(m_xBuilder->weld_combo_box("detailCombobox1"),
+ m_xBuilder->weld_combo_box("masterCombobox1")))
+ , m_xRow2(std::make_unique<FieldLinkRow>(m_xBuilder->weld_combo_box("detailCombobox2"),
+ m_xBuilder->weld_combo_box("masterCombobox2")))
+ , m_xRow3(std::make_unique<FieldLinkRow>(m_xBuilder->weld_combo_box("detailCombobox3"),
+ m_xBuilder->weld_combo_box("masterCombobox3")))
+ , m_xRow4(std::make_unique<FieldLinkRow>(m_xBuilder->weld_combo_box("detailCombobox4"),
+ m_xBuilder->weld_combo_box("masterCombobox4")))
+ , m_xOK(m_xBuilder->weld_button("ok"))
+ , m_xSuggest(m_xBuilder->weld_button("suggestButton"))
+ {
+ m_xRow1->Show();
+ m_xRow2->Show();
+ m_xRow3->Show();
+ m_xRow4->Show();
+ m_xDialog->set_size_request(600, -1);
+
+ if ( !_sExplanation.isEmpty() )
+ m_xExplanation->set_label(_sExplanation);
+
+ m_xSuggest->connect_clicked(LINK(this, FormLinkDialog, OnSuggest));
+ m_xRow1->SetLinkChangeHandler( LINK( this, FormLinkDialog, OnFieldChanged ) );
+ m_xRow2->SetLinkChangeHandler( LINK( this, FormLinkDialog, OnFieldChanged ) );
+ m_xRow3->SetLinkChangeHandler( LINK( this, FormLinkDialog, OnFieldChanged ) );
+ m_xRow4->SetLinkChangeHandler( LINK( this, FormLinkDialog, OnFieldChanged ) );
+
+ Application::PostUserEvent(LINK(this, FormLinkDialog, OnInitialize));
+
+ updateOkButton();
+ }
+
+ FormLinkDialog::~FormLinkDialog()
+ {
+ }
+
+ void FormLinkDialog::commitLinkPairs()
+ {
+ // collect the field lists from the rows
+ std::vector< OUString > aDetailFields; aDetailFields.reserve( 4 );
+ std::vector< OUString > aMasterFields; aMasterFields.reserve( 4 );
+
+ const FieldLinkRow* aRows[] = {
+ m_xRow1.get(), m_xRow2.get(), m_xRow3.get(), m_xRow4.get()
+ };
+
+ for (const FieldLinkRow* aRow : aRows)
+ {
+ OUString sDetailField, sMasterField;
+ aRow->GetFieldName( FieldLinkRow::eDetailField, sDetailField );
+ aRow->GetFieldName( FieldLinkRow::eMasterField, sMasterField );
+ if ( sDetailField.isEmpty() && sMasterField.isEmpty() )
+ continue;
+
+ aDetailFields.push_back( sDetailField );
+ aMasterFields.push_back( sMasterField );
+ }
+
+ // and set as property values
+ try
+ {
+ if ( m_xDetailForm.is() )
+ {
+ m_xDetailForm->setPropertyValue( PROPERTY_DETAILFIELDS, Any( Sequence< OUString >( aDetailFields.data(), aDetailFields.size() ) ) );
+ m_xDetailForm->setPropertyValue( PROPERTY_MASTERFIELDS, Any( Sequence< OUString >( aMasterFields.data(), aMasterFields.size() ) ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("extensions.propctrlr",
+ "caught an exception while setting the properties!");
+ }
+ }
+
+ short FormLinkDialog::run()
+ {
+ short nResult = GenericDialogController::run();
+
+ if ( RET_OK == nResult )
+ commitLinkPairs();
+
+ return nResult;
+ }
+
+ void FormLinkDialog::initializeFieldLists()
+ {
+ Sequence< OUString > sDetailFields;
+ getFormFields( m_xDetailForm, sDetailFields );
+
+ Sequence< OUString > sMasterFields;
+ getFormFields( m_xMasterForm, sMasterFields );
+
+ FieldLinkRow* aRows[] = {
+ m_xRow1.get(), m_xRow2.get(), m_xRow3.get(), m_xRow4.get()
+ };
+ for (FieldLinkRow* aRow : aRows)
+ {
+ aRow->fillList( FieldLinkRow::eDetailField, sDetailFields );
+ aRow->fillList( FieldLinkRow::eMasterField, sMasterFields );
+ }
+
+ }
+
+
+ void FormLinkDialog::initializeColumnLabels()
+ {
+ // label for the detail form
+ OUString sDetailType = getFormDataSourceType( m_xDetailForm );
+ if ( sDetailType.isEmpty() )
+ {
+ if ( m_sDetailLabel.isEmpty() )
+ {
+ m_sDetailLabel = PcrRes(STR_DETAIL_FORM);
+ }
+ sDetailType = m_sDetailLabel;
+ }
+ m_xDetailLabel->set_label( sDetailType );
+
+ // label for the master form
+ OUString sMasterType = getFormDataSourceType( m_xMasterForm );
+ if ( sMasterType.isEmpty() )
+ {
+ if ( m_sMasterLabel.isEmpty() )
+ {
+ m_sMasterLabel = PcrRes(STR_MASTER_FORM);
+ }
+ sMasterType = m_sMasterLabel;
+ }
+ m_xMasterLabel->set_label( sMasterType );
+ }
+
+ void FormLinkDialog::initializeFieldRowsFrom( std::vector< OUString >& _rDetailFields, std::vector< OUString >& _rMasterFields )
+ {
+ // our UI does allow 4 fields max
+ _rDetailFields.resize( 4 );
+ _rMasterFields.resize( 4 );
+
+ FieldLinkRow* aRows[] = {
+ m_xRow1.get(), m_xRow2.get(), m_xRow3.get(), m_xRow4.get()
+ };
+ for ( sal_Int32 i = 0; i < 4; ++i )
+ {
+ aRows[ i ]->SetFieldName( FieldLinkRow::eDetailField, _rDetailFields[i] );
+ aRows[ i ]->SetFieldName( FieldLinkRow::eMasterField, _rMasterFields[i] );
+ }
+ }
+
+
+ void FormLinkDialog::initializeLinks()
+ {
+ try
+ {
+ Sequence< OUString > aDetailFields;
+ Sequence< OUString > aMasterFields;
+
+ if ( m_xDetailForm.is() )
+ {
+ m_xDetailForm->getPropertyValue( PROPERTY_DETAILFIELDS ) >>= aDetailFields;
+ m_xDetailForm->getPropertyValue( PROPERTY_MASTERFIELDS ) >>= aMasterFields;
+ }
+
+ std::vector< OUString > aDetailFields1;
+ comphelper::sequenceToContainer(aDetailFields1, aDetailFields);
+ std::vector< OUString > aMasterFields1;
+ comphelper::sequenceToContainer(aMasterFields1, aMasterFields);
+ initializeFieldRowsFrom( aDetailFields1, aMasterFields1 );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::initializeLinks" );
+ }
+ }
+
+
+ void FormLinkDialog::updateOkButton()
+ {
+ // in all rows, there must be either two valid selections, or none at all
+ // If there is at least one row with exactly one valid selection, then the
+ // OKButton needs to be disabled
+ bool bEnable = true;
+
+ const FieldLinkRow* aRows[] = {
+ m_xRow1.get(), m_xRow2.get(), m_xRow3.get(), m_xRow4.get()
+ };
+
+ for ( sal_Int32 i = 0; ( i < 4 ) && bEnable; ++i )
+ {
+ OUString sNotInterestedInRightNow;
+ if ( aRows[ i ]->GetFieldName( FieldLinkRow::eDetailField, sNotInterestedInRightNow )
+ != aRows[ i ]->GetFieldName( FieldLinkRow::eMasterField, sNotInterestedInRightNow )
+ )
+ bEnable = false;
+ }
+
+ m_xOK->set_sensitive(bEnable);
+ }
+
+ OUString FormLinkDialog::getFormDataSourceType( const Reference< XPropertySet >& _rxForm )
+ {
+ OUString sReturn;
+ if ( !_rxForm.is() )
+ return sReturn;
+
+ try
+ {
+ sal_Int32 nCommandType = CommandType::COMMAND;
+ OUString sCommand;
+
+ _rxForm->getPropertyValue( PROPERTY_COMMANDTYPE ) >>= nCommandType;
+ _rxForm->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand;
+
+ if ( ( nCommandType == CommandType::TABLE )
+ || ( nCommandType == CommandType::QUERY )
+ )
+ sReturn = sCommand;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::getFormDataSourceType" );
+ }
+ return sReturn;
+ }
+
+ void FormLinkDialog::getFormFields( const Reference< XPropertySet >& _rxForm, Sequence< OUString >& /* [out] */ _rNames ) const
+ {
+ _rNames.realloc( 0 );
+
+ ::dbtools::SQLExceptionInfo aErrorInfo;
+ OUString sCommand;
+ try
+ {
+ weld::WaitObject aWaitCursor(m_xDialog.get());
+
+ OSL_ENSURE( _rxForm.is(), "FormLinkDialog::getFormFields: invalid form!" );
+
+ sal_Int32 nCommandType = CommandType::COMMAND;
+
+ _rxForm->getPropertyValue( PROPERTY_COMMANDTYPE ) >>= nCommandType;
+ _rxForm->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand;
+
+ Reference< XConnection > xConnection;
+ ensureFormConnection( _rxForm, xConnection );
+
+ _rNames = ::dbtools::getFieldNamesByCommandDescriptor(
+ xConnection,
+ nCommandType,
+ sCommand,
+ &aErrorInfo
+ );
+ }
+ catch (const SQLContext& e) { aErrorInfo = e; }
+ catch (const SQLWarning& e) { aErrorInfo = e; }
+ catch (const SQLException& e ) { aErrorInfo = e; }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::getFormFields: caught a non-SQL exception!" );
+ }
+
+ if ( !aErrorInfo.isValid() )
+ return;
+
+ OUString sErrorMessage;
+ {
+ sErrorMessage = PcrRes(STR_ERROR_RETRIEVING_COLUMNS);
+ sErrorMessage = sErrorMessage.replaceFirst("#", sCommand);
+ }
+
+ SQLContext aContext;
+ aContext.Message = sErrorMessage;
+ aContext.NextException = aErrorInfo.get();
+ ::dbtools::showError(aContext, m_xDialog->GetXWindow(), m_xContext);
+ }
+
+ void FormLinkDialog::ensureFormConnection( const Reference< XPropertySet >& _rxFormProps, Reference< XConnection >& /* [out] */ _rxConnection ) const
+ {
+ OSL_PRECOND( _rxFormProps.is(), "FormLinkDialog::ensureFormConnection: invalid form!" );
+ if ( !_rxFormProps.is() )
+ return;
+ if ( _rxFormProps->getPropertySetInfo()->hasPropertyByName(PROPERTY_ACTIVE_CONNECTION) )
+ _rxConnection.set(_rxFormProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),UNO_QUERY);
+
+ if ( !_rxConnection.is() )
+ _rxConnection = ::dbtools::connectRowset( Reference< XRowSet >( _rxFormProps, UNO_QUERY ), m_xContext, nullptr );
+ }
+
+
+ void FormLinkDialog::getConnectionMetaData( const Reference< XPropertySet >& _rxFormProps, Reference< XDatabaseMetaData >& /* [out] */ _rxMeta )
+ {
+ if ( _rxFormProps.is() )
+ {
+ Reference< XConnection > xConnection;
+ if ( !::dbtools::isEmbeddedInDatabase( _rxFormProps, xConnection ) )
+ _rxFormProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConnection;
+ if ( xConnection.is() )
+ _rxMeta = xConnection->getMetaData();
+ }
+ }
+
+
+ Reference< XPropertySet > FormLinkDialog::getCanonicUnderlyingTable( const Reference< XPropertySet >& _rxFormProps ) const
+ {
+ Reference< XPropertySet > xTable;
+ try
+ {
+ Reference< XTablesSupplier > xTablesInForm( ::dbtools::getCurrentSettingsComposer( _rxFormProps, m_xContext, nullptr ), UNO_QUERY );
+ Reference< XNameAccess > xTables;
+ if ( xTablesInForm.is() )
+ xTables = xTablesInForm->getTables();
+ Sequence< OUString > aTableNames;
+ if ( xTables.is() )
+ aTableNames = xTables->getElementNames();
+
+ if ( aTableNames.getLength() == 1 )
+ {
+ xTables->getByName( aTableNames[ 0 ] ) >>= xTable;
+ OSL_ENSURE( xTable.is(), "FormLinkDialog::getCanonicUnderlyingTable: invalid table!" );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::getCanonicUnderlyingTable" );
+ }
+ return xTable;
+ }
+
+
+ bool FormLinkDialog::getExistingRelation( const Reference< XPropertySet >& _rxLHS, const Reference< XPropertySet >& /*_rxRHS*/,
+ // TODO: fix the usage of _rxRHS. This is issue #i81956#.
+ std::vector< OUString >& _rLeftFields, std::vector< OUString >& _rRightFields )
+ {
+ try
+ {
+ Reference< XKeysSupplier > xSuppKeys( _rxLHS, UNO_QUERY );
+ Reference< XIndexAccess > xKeys;
+ if ( xSuppKeys.is() )
+ xKeys = xSuppKeys->getKeys();
+
+ if ( xKeys.is() )
+ {
+ Reference< XPropertySet > xKey;
+ Reference< XColumnsSupplier > xKeyColSupp( xKey, UNO_QUERY );
+ Reference< XIndexAccess > xKeyColumns;
+ Reference< XPropertySet > xKeyColumn;
+ OUString sColumnName, sRelatedColumnName;
+
+ const sal_Int32 keyCount = xKeys->getCount();
+ for ( sal_Int32 key = 0; key < keyCount; ++key )
+ {
+ xKeys->getByIndex( key ) >>= xKey;
+ sal_Int32 nKeyType = 0;
+ xKey->getPropertyValue("Type") >>= nKeyType;
+ if ( nKeyType != KeyType::FOREIGN )
+ continue;
+
+ xKeyColumns.clear();
+ xKeyColSupp.set(xKey, css::uno::UNO_QUERY);
+ if ( xKeyColSupp.is() )
+ xKeyColumns.set(xKeyColSupp->getColumns(), css::uno::UNO_QUERY);
+ OSL_ENSURE( xKeyColumns.is(), "FormLinkDialog::getExistingRelation: could not obtain the columns for the key!" );
+
+ if ( !xKeyColumns.is() )
+ continue;
+
+ const sal_Int32 columnCount = xKeyColumns->getCount();
+ _rLeftFields.resize( columnCount );
+ _rRightFields.resize( columnCount );
+ for ( sal_Int32 column = 0; column < columnCount; ++column )
+ {
+ xKeyColumn.clear();
+ xKeyColumns->getByIndex( column ) >>= xKeyColumn;
+ OSL_ENSURE( xKeyColumn.is(), "FormLinkDialog::getExistingRelation: invalid key column!" );
+ if ( xKeyColumn.is() )
+ {
+ xKeyColumn->getPropertyValue( PROPERTY_NAME ) >>= sColumnName;
+ xKeyColumn->getPropertyValue("RelatedColumn") >>= sRelatedColumnName;
+
+ _rLeftFields[ column ] = sColumnName;
+ _rRightFields[ column ] = sRelatedColumnName;
+ }
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::getExistingRelation" );
+ }
+
+ return ( !_rLeftFields.empty() ) && ( !_rLeftFields[ 0 ].isEmpty() );
+ }
+
+
+ void FormLinkDialog::initializeSuggest()
+ {
+ if ( !m_xDetailForm.is() || !m_xMasterForm.is() )
+ return;
+
+ try
+ {
+ // only show the button when both forms are based on the same data source
+ OUString sMasterDS, sDetailDS;
+ m_xMasterForm->getPropertyValue( PROPERTY_DATASOURCE ) >>= sMasterDS;
+ m_xDetailForm->getPropertyValue( PROPERTY_DATASOURCE ) >>= sDetailDS;
+ bool bEnable = ( sMasterDS == sDetailDS );
+
+ // only show the button when the connection supports relations
+ if ( bEnable )
+ {
+ Reference< XDatabaseMetaData > xMeta;
+ getConnectionMetaData( m_xDetailForm, xMeta );
+ OSL_ENSURE( xMeta.is(), "FormLinkDialog::initializeSuggest: unable to retrieve the meta data for the connection!" );
+ try
+ {
+ bEnable = xMeta.is() && xMeta->supportsIntegrityEnhancementFacility();
+ }
+ catch(const Exception&)
+ {
+ bEnable = false;
+ }
+ }
+
+ // only enable the button if there is a "canonic" table underlying both forms
+ Reference< XPropertySet > xDetailTable, xMasterTable;
+ if ( bEnable )
+ {
+ xDetailTable = getCanonicUnderlyingTable( m_xDetailForm );
+ xMasterTable = getCanonicUnderlyingTable( m_xMasterForm );
+ bEnable = xDetailTable.is() && xMasterTable.is();
+ }
+
+ // only enable the button if there is a relation between both tables
+ m_aRelationDetailColumns.clear();
+ m_aRelationMasterColumns.clear();
+ if ( bEnable )
+ {
+ bEnable = getExistingRelation( xDetailTable, xMasterTable, m_aRelationDetailColumns, m_aRelationMasterColumns );
+ SAL_WARN_IF( m_aRelationMasterColumns.size() != m_aRelationDetailColumns.size(),
+ "extensions.propctrlr",
+ "FormLinkDialog::initializeSuggest: nonsense!" );
+ if ( m_aRelationMasterColumns.empty() )
+ { // okay, there is no relation "pointing" (via a foreign key) from the detail table to the master table
+ // but perhaps the other way round (would make less sense, but who knows ...)
+ bEnable = getExistingRelation( xMasterTable, xDetailTable, m_aRelationMasterColumns, m_aRelationDetailColumns );
+ }
+ }
+
+ // only enable the button if the relation contains at most 4 field pairs
+ if ( bEnable )
+ {
+ bEnable = ( m_aRelationMasterColumns.size() <= 4 );
+ }
+
+ m_xSuggest->set_sensitive(bEnable);
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::initializeSuggest" );
+ }
+ }
+
+ IMPL_LINK_NOARG( FormLinkDialog, OnSuggest, weld::Button&, void )
+ {
+ initializeFieldRowsFrom( m_aRelationDetailColumns, m_aRelationMasterColumns );
+ }
+
+ IMPL_LINK_NOARG( FormLinkDialog, OnFieldChanged, FieldLinkRow&, void )
+ {
+ updateOkButton();
+ }
+
+ IMPL_LINK_NOARG( FormLinkDialog, OnInitialize, void*, void )
+ {
+ initializeColumnLabels();
+ initializeFieldLists();
+ initializeLinks();
+ initializeSuggest();
+ }
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/formlinkdialog.hxx b/extensions/source/propctrlr/formlinkdialog.hxx
new file mode 100644
index 000000000..80cc086cc
--- /dev/null
+++ b/extensions/source/propctrlr/formlinkdialog.hxx
@@ -0,0 +1,127 @@
+/* -*- 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/weld.hxx>
+
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <memory>
+
+
+namespace pcr
+{
+ class FieldLinkRow;
+
+ //= FormLinkDialog
+
+ class FormLinkDialog : public weld::GenericDialogController
+ {
+ private:
+ css::uno::Reference< css::uno::XComponentContext >
+ m_xContext;
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xDetailForm;
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xMasterForm;
+
+ std::vector< OUString > m_aRelationDetailColumns;
+ std::vector< OUString > m_aRelationMasterColumns;
+
+ OUString m_sDetailLabel;
+ OUString m_sMasterLabel;
+
+ std::unique_ptr<weld::Label> m_xExplanation;
+ std::unique_ptr<weld::Label> m_xDetailLabel;
+ std::unique_ptr<weld::Label> m_xMasterLabel;
+ std::unique_ptr<FieldLinkRow> m_xRow1;
+ std::unique_ptr<FieldLinkRow> m_xRow2;
+ std::unique_ptr<FieldLinkRow> m_xRow3;
+ std::unique_ptr<FieldLinkRow> m_xRow4;
+ std::unique_ptr<weld::Button> m_xOK;
+ std::unique_ptr<weld::Button> m_xSuggest;
+
+ public:
+ FormLinkDialog(
+ weld::Window* _pParent,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxDetailForm,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxMasterForm,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ const OUString& _sExplanation = OUString(),
+ const OUString& _sDetailLabel = OUString(),
+ const OUString& _sMasterLabel = OUString()
+ );
+
+ virtual ~FormLinkDialog() override;
+
+ // Dialog overridables
+ virtual short run() override;
+
+ private:
+ DECL_LINK( OnSuggest, weld::Button&, void );
+ DECL_LINK( OnFieldChanged, FieldLinkRow&, void );
+ DECL_LINK( OnInitialize, void*, void);
+
+ void updateOkButton();
+ void initializeFieldLists();
+ void initializeColumnLabels();
+ void initializeLinks();
+ void initializeSuggest();
+ void commitLinkPairs();
+
+ void initializeFieldRowsFrom(
+ std::vector< OUString >& _rDetailFields,
+ std::vector< OUString >& _rMasterFields
+ );
+
+ static OUString getFormDataSourceType(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxForm
+ );
+
+ void getFormFields(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxForm,
+ css::uno::Sequence< OUString >& /* [out] */ _rNames
+ ) const;
+
+ void ensureFormConnection(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxFormProps,
+ css::uno::Reference< css::sdbc::XConnection >& /* [out] */ _rxConnection
+ ) const;
+
+ static void getConnectionMetaData(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxFormProps,
+ css::uno::Reference< css::sdbc::XDatabaseMetaData >& /* [out] */ _rxMeta
+ );
+
+ css::uno::Reference< css::beans::XPropertySet >
+ getCanonicUnderlyingTable( const css::uno::Reference< css::beans::XPropertySet >& _rxFormProps ) const;
+ static bool getExistingRelation(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxLHS,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxRHS,
+ std::vector< OUString >& /* [out] */ _rLeftFields,
+ std::vector< OUString >& /* [out] */ _rRightFields
+ );
+ };
+
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/formmetadata.cxx b/extensions/source/propctrlr/formmetadata.cxx
new file mode 100644
index 000000000..13a7b32e7
--- /dev/null
+++ b/extensions/source/propctrlr/formmetadata.cxx
@@ -0,0 +1,694 @@
+/* -*- 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 "formmetadata.hxx"
+#include "formstrings.hxx"
+#include "modulepcr.hxx"
+#include <command.hrc>
+#include <helpids.h>
+#include <strings.hrc>
+#include <stringarrays.hrc>
+#include <comphelper/extract.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <sal/macros.h>
+#include <algorithm>
+
+namespace pcr
+{
+ using namespace ::com::sun::star::uno;
+
+
+ //= OPropertyInfoImpl
+
+ struct OPropertyInfoImpl
+ {
+ OUString sName;
+ OUString sTranslation;
+ OUString sHelpId;
+ sal_Int32 nId;
+ sal_uInt16 nPos;
+ sal_uInt32 nUIFlags;
+
+ OPropertyInfoImpl(
+ const OUString& rName,
+ sal_Int32 _nId,
+ const OUString& aTranslation,
+ sal_uInt16 nPosId,
+ const OUString&,
+ sal_uInt32 _nUIFlags);
+ };
+
+
+ OPropertyInfoImpl::OPropertyInfoImpl(const OUString& _rName, sal_Int32 _nId,
+ const OUString& aString, sal_uInt16 nP, const OUString& sHid, sal_uInt32 _nUIFlags)
+ :sName(_rName)
+ ,sTranslation(aString)
+ ,sHelpId(sHid)
+ ,nId(_nId)
+ ,nPos(nP)
+ ,nUIFlags(_nUIFlags)
+ {
+ }
+
+ namespace {
+
+ // Compare PropertyInfo
+ struct PropertyInfoLessByName
+ {
+ bool operator()( const OPropertyInfoImpl& _rLHS, const OPropertyInfoImpl& _rRHS )
+ {
+ return _rLHS.sName.compareTo( _rRHS.sName ) < 0;
+ }
+ };
+
+ }
+
+ //= OPropertyInfoService
+
+#define DEF_INFO( ident, uinameres, pos, helpid, flags ) \
+ OPropertyInfoImpl( PROPERTY_##ident, PROPERTY_ID_##ident, \
+ PcrRes( RID_STR_##uinameres ), pos, HID_PROP_##helpid, flags )
+
+#define DEF_INFO_1( ident, uinameres, pos, helpid, flag1 ) \
+ DEF_INFO( ident, uinameres, pos, helpid, PROP_FLAG_##flag1 )
+
+#define DEF_INFO_2( ident, uinameres, pos, helpid, flag1, flag2 ) \
+ DEF_INFO( ident, uinameres, pos, helpid, PROP_FLAG_##flag1 | PROP_FLAG_##flag2 )
+
+#define DEF_INFO_3( ident, uinameres, pos, helpid, flag1, flag2, flag3 ) \
+ DEF_INFO( ident, uinameres, pos, helpid, PROP_FLAG_##flag1 | PROP_FLAG_##flag2 | PROP_FLAG_##flag3 )
+
+#define DEF_INFO_4( ident, uinameres, pos, helpid, flag1, flag2, flag3, flag4 ) \
+ DEF_INFO( ident, uinameres, pos, helpid, PROP_FLAG_##flag1 | PROP_FLAG_##flag2 | PROP_FLAG_##flag3 | PROP_FLAG_##flag4 )
+
+ sal_uInt16 OPropertyInfoService::s_nCount = 0;
+ OPropertyInfoImpl* OPropertyInfoService::s_pPropertyInfos = nullptr;
+
+ const OPropertyInfoImpl* OPropertyInfoService::getPropertyInfo()
+ {
+ if ( s_pPropertyInfos )
+ return s_pPropertyInfos;
+
+ static OPropertyInfoImpl aPropertyInfos[] =
+ {
+ /*
+ DEF_INFO_?( propname and id, resource id, pos, help id, flags ),
+ */
+ DEF_INFO_3( NAME, NAME, 0, NAME, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( TITLE, TITLE, 1, TITLE, FORM_VISIBLE, DIALOG_VISIBLE ),
+ DEF_INFO_3( LABEL, LABEL, 2, LABEL, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( CONTROLLABEL, LABELCONTROL, 3, CONTROLLABEL, FORM_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( WRITING_MODE, WRITING_MODE, 4, WRITING_MODE, FORM_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_3( GROUP_NAME, GROUP_NAME, 5, GROUP_NAME, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( TEXT, TEXT, 6, TEXT, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( MAXTEXTLEN, MAXTEXTLEN, 7, MAXTEXTLEN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( EDITMASK, EDITMASK, 8, EDITMASK, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( LITERALMASK, LITERALMASK, 9, LITERALMASK, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( STRICTFORMAT, STRICTFORMAT, 10, STRICTFORMAT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( ENABLED, ENABLED, 11, ENABLED, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( ENABLE_VISIBLE, ENABLE_VISIBLE, 12, ENABLE_VISIBLE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( READONLY, READONLY, 13, READONLY, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( PRINTABLE, PRINTABLE, 14, PRINTABLE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( STEP, STEP, 15, STEP, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( WHEEL_BEHAVIOR, WHEEL_BEHAVIOR, 16, WHEEL_BEHAVIOR, FORM_VISIBLE | PROP_FLAG_REPORT_INVISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_3( TABSTOP, TABSTOP, 17, TABSTOP, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( TABINDEX, TABINDEX, 18, TABINDEX, FORM_VISIBLE, DIALOG_VISIBLE ),
+
+ DEF_INFO_2( BOUND_CELL, BOUND_CELL, 19, BOUND_CELL, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_3( CELL_EXCHANGE_TYPE,CELL_EXCHANGE_TYPE, 20, CELL_EXCHANGE_TYPE,FORM_VISIBLE, DATA_PROPERTY, ENUM ),
+ DEF_INFO_2( LIST_CELL_RANGE, LIST_CELL_RANGE, 21, LIST_CELL_RANGE, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_3( CONTROLSOURCE, CONTROLSOURCE, 22, CONTROLSOURCE, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+ DEF_INFO_3( EMPTY_IS_NULL, EMPTY_IS_NULL, 23, EMPTY_IS_NULL, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+ DEF_INFO_3( INPUT_REQUIRED, INPUT_REQUIRED, 24, INPUT_REQUIRED, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+ DEF_INFO_3( REFVALUE, REFVALUE, 25, REFVALUE, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+ DEF_INFO_3( UNCHECKEDREFVALUE, UNCHECKEDREFVALUE, 26, UNCHECKEDREFVALUE, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+ DEF_INFO_3( DATASOURCE, DATASOURCE, 27, DATASOURCE, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+ DEF_INFO_4( COMMANDTYPE, CURSORSOURCETYPE, 28, CURSORSOURCETYPE, FORM_VISIBLE, DATA_PROPERTY, ENUM, COMPOSEABLE ),
+ DEF_INFO_3( COMMAND, CURSORSOURCE, 29, CURSORSOURCE, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+ DEF_INFO_3( ESCAPE_PROCESSING, ESCAPE_PROCESSING, 30, ESCAPE_PROCESSING, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+ DEF_INFO_3( FILTER, FILTER, 31, FILTER, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+ DEF_INFO_3( SORT, SORT_CRITERIA, 32, SORT_CRITERIA, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+ DEF_INFO_2( MASTERFIELDS, MASTERFIELDS, 33, MASTERFIELDS, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( DETAILFIELDS, SLAVEFIELDS, 34, SLAVEFIELDS, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_3( ALLOWADDITIONS, ALLOW_ADDITIONS, 35, ALLOW_ADDITIONS, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+ DEF_INFO_3( ALLOWEDITS, ALLOW_EDITS, 36, ALLOW_EDITS, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+ DEF_INFO_3( ALLOWDELETIONS, ALLOW_DELETIONS, 37, ALLOW_DELETIONS, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+ DEF_INFO_3( INSERTONLY, DATAENTRY, 38, DATAENTRY, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+ DEF_INFO_4( NAVIGATION, NAVIGATION, 39, NAVIGATION, FORM_VISIBLE, DATA_PROPERTY, ENUM, COMPOSEABLE ),
+ DEF_INFO_4( CYCLE, CYCLE, 40, CYCLE, FORM_VISIBLE, DATA_PROPERTY, ENUM, COMPOSEABLE ),
+ DEF_INFO_3( FILTERPROPOSAL, FILTERPROPOSAL, 41, FILTERPROPOSAL, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+ DEF_INFO_4( LISTSOURCETYPE, LISTSOURCETYPE, 42, LISTSOURCETYPE, FORM_VISIBLE, DATA_PROPERTY, ENUM, COMPOSEABLE ),
+ DEF_INFO_3( LISTSOURCE, LISTSOURCE, 43, LISTSOURCE, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+ DEF_INFO_3( BOUNDCOLUMN, BOUNDCOLUMN, 44, BOUNDCOLUMN, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ),
+
+ // <!----------------->
+ // XML node binding
+ DEF_INFO_2( LIST_BINDING, LIST_BINDING, 45, LIST_BINDING, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XML_DATA_MODEL, XML_DATA_MODEL, 46, XML_DATA_MODEL, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( BINDING_NAME, BINDING_NAME, 47, BINDING_NAME, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( BIND_EXPRESSION, BIND_EXPRESSION, 48, BIND_EXPRESSION, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_REQUIRED, XSD_REQUIRED, 49, XSD_REQUIRED, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_RELEVANT, XSD_RELEVANT, 50, XSD_RELEVANT, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_READONLY, XSD_READONLY, 51, XSD_READONLY, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_CONSTRAINT, XSD_CONSTRAINT, 52, XSD_CONSTRAINT, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_CALCULATION, XSD_CALCULATION, 53, XSD_CALCULATION, FORM_VISIBLE, DATA_PROPERTY ),
+
+ // data type
+ DEF_INFO_2( XSD_DATA_TYPE, XSD_DATA_TYPE, 54, XSD_DATA_TYPE, FORM_VISIBLE, DATA_PROPERTY ),
+ // data types facets
+ // common
+ DEF_INFO_3( XSD_WHITESPACES, XSD_WHITESPACES, 55, XSD_WHITESPACES, FORM_VISIBLE, DATA_PROPERTY, ENUM ),
+ DEF_INFO_2( XSD_PATTERN, XSD_PATTERN, 56, XSD_PATTERN, FORM_VISIBLE, DATA_PROPERTY ),
+ // string
+ DEF_INFO_2( XSD_LENGTH, XSD_LENGTH, 57, XSD_LENGTH, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MIN_LENGTH, XSD_MIN_LENGTH, 58, XSD_MIN_LENGTH, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MAX_LENGTH, XSD_MAX_LENGTH, 59, XSD_MAX_LENGTH, FORM_VISIBLE, DATA_PROPERTY ),
+ // decimal
+ DEF_INFO_2( XSD_TOTAL_DIGITS, XSD_TOTAL_DIGITS, 60, XSD_TOTAL_DIGITS, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_FRACTION_DIGITS,XSD_FRACTION_DIGITS,61,XSD_FRACTION_DIGITS,FORM_VISIBLE, DATA_PROPERTY ),
+ // int value types (year, month, day)
+ DEF_INFO_2( XSD_MAX_INCLUSIVE_INT, XSD_MAX_INCLUSIVE, 62, XSD_MAX_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MAX_EXCLUSIVE_INT, XSD_MAX_EXCLUSIVE, 63, XSD_MAX_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MIN_INCLUSIVE_INT, XSD_MIN_INCLUSIVE, 64, XSD_MIN_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MIN_EXCLUSIVE_INT, XSD_MIN_EXCLUSIVE, 65, XSD_MIN_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ // double value types (double, float, decimal)
+ DEF_INFO_2( XSD_MAX_INCLUSIVE_DOUBLE, XSD_MAX_INCLUSIVE, 66, XSD_MAX_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MAX_EXCLUSIVE_DOUBLE, XSD_MAX_EXCLUSIVE, 67, XSD_MAX_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MIN_INCLUSIVE_DOUBLE, XSD_MIN_INCLUSIVE, 68, XSD_MIN_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MIN_EXCLUSIVE_DOUBLE, XSD_MIN_EXCLUSIVE, 69, XSD_MIN_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ // date value type
+ DEF_INFO_2( XSD_MAX_INCLUSIVE_DATE, XSD_MAX_INCLUSIVE, 70, XSD_MAX_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MAX_EXCLUSIVE_DATE, XSD_MAX_EXCLUSIVE, 71, XSD_MAX_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MIN_INCLUSIVE_DATE, XSD_MIN_INCLUSIVE, 72, XSD_MIN_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MIN_EXCLUSIVE_DATE, XSD_MIN_EXCLUSIVE, 73, XSD_MIN_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ // time value type
+ DEF_INFO_2( XSD_MAX_INCLUSIVE_TIME, XSD_MAX_INCLUSIVE, 74, XSD_MAX_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MAX_EXCLUSIVE_TIME, XSD_MAX_EXCLUSIVE, 75, XSD_MAX_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MIN_INCLUSIVE_TIME, XSD_MIN_INCLUSIVE, 76, XSD_MIN_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MIN_EXCLUSIVE_TIME, XSD_MIN_EXCLUSIVE, 77, XSD_MIN_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ // dateTime value type
+ DEF_INFO_2( XSD_MAX_INCLUSIVE_DATE_TIME, XSD_MAX_INCLUSIVE, 78, XSD_MAX_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MAX_EXCLUSIVE_DATE_TIME, XSD_MAX_EXCLUSIVE, 79, XSD_MAX_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MIN_INCLUSIVE_DATE_TIME, XSD_MIN_INCLUSIVE, 80, XSD_MIN_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ DEF_INFO_2( XSD_MIN_EXCLUSIVE_DATE_TIME, XSD_MIN_EXCLUSIVE, 81, XSD_MIN_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ),
+ // <!----------------->
+
+ DEF_INFO_2( HIDDEN_VALUE, VALUE, 82, HIDDEN_VALUE, FORM_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( VALUE, VALUE, 83, VALUE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( VALUEMIN, VALUEMIN, 84, VALUEMIN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( VALUEMAX, VALUEMAX, 85, VALUEMAX, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( VALUESTEP, VALUESTEP, 86, VALUESTEP, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( DEFAULT_VALUE, DEFAULTVALUE, 87, DEFAULT_LONG_VALUE,FORM_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( DECIMAL_ACCURACY, DECIMAL_ACCURACY, 88, DECIMAL_ACCURACY, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( SHOWTHOUSANDSEP, SHOWTHOUSANDSEP, 89, SHOWTHOUSANDSEP, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+
+ DEF_INFO_3( CURRENCYSYMBOL, CURRENCYSYMBOL, 90, CURRENCYSYMBOL, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( CURRSYM_POSITION, CURRSYM_POSITION, 91, CURRSYM_POSITION, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+
+ DEF_INFO_2( DATE, DATE, 92, DATE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( DATEMIN, DATEMIN, 93, DATEMIN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( DATEMAX, DATEMAX, 94, DATEMAX, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_4( DATEFORMAT, DATEFORMAT, 95, DATEFORMAT, FORM_VISIBLE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_2( DEFAULT_DATE, DEFAULTDATE, 96, DEFAULT_DATE, FORM_VISIBLE, COMPOSEABLE ),
+
+ DEF_INFO_2( TIME, TIME, 97, TIME, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( TIMEMIN, TIMEMIN, 98, TIMEMIN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( TIMEMAX, TIMEMAX, 99, TIMEMAX, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_4( TIMEFORMAT, TIMEFORMAT, 100, TIMEFORMAT, FORM_VISIBLE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_2( DEFAULT_TIME, DEFAULTTIME, 101, DEFAULT_TIME, FORM_VISIBLE, COMPOSEABLE ),
+
+ DEF_INFO_1( EFFECTIVE_VALUE, VALUE, 102, VALUE, DIALOG_VISIBLE ),
+ DEF_INFO_3( EFFECTIVE_MIN, VALUEMIN, 103, EFFECTIVEMIN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( EFFECTIVE_MAX, VALUEMAX, 104, EFFECTIVEMAX, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( EFFECTIVE_DEFAULT, DEFAULTVALUE, 105, EFFECTIVEDEFAULT, FORM_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( FORMATKEY, FORMATKEY, 106, FORMATKEY, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+
+ DEF_INFO_3( PROGRESSVALUE, PROGRESSVALUE, 107, PROGRESSVALUE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( PROGRESSVALUE_MIN, PROGRESSVALUE_MIN, 108, PROGRESSVALUE_MIN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( PROGRESSVALUE_MAX, PROGRESSVALUE_MAX, 109, PROGRESSVALUE_MAX, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+
+ DEF_INFO_2( SCROLLVALUE, SCROLLVALUE, 110, SCROLLVALUE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( SCROLLVALUE_MIN, SCROLLVALUE_MIN, 111, SCROLLVALUE_MIN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( SCROLLVALUE_MAX, SCROLLVALUE_MAX, 112, SCROLLVALUE_MAX, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( SCROLL_WIDTH, SCROLL_WIDTH, 113, SCROLL_WIDTH, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( SCROLL_HEIGHT, SCROLL_HEIGHT, 114, SCROLL_HEIGHT, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( SCROLL_TOP, SCROLL_TOP, 115, SCROLL_TOP, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( SCROLL_LEFT, SCROLL_LEFT, 116, SCROLL_LEFT, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( DEFAULT_SCROLLVALUE,DEFAULT_SCROLLVALUE,117,DEFAULT_SCROLLVALUE,FORM_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( LINEINCREMENT, LINEINCREMENT, 118, LINEINCREMENT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( BLOCKINCREMENT, BLOCKINCREMENT, 119, BLOCKINCREMENT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+
+ DEF_INFO_2( SPINVALUE, VALUE, 120, SPINVALUE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( SPINVALUE_MIN, VALUEMIN, 121, SPINVALUE_MIN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( SPINVALUE_MAX, VALUEMAX, 122, SPINVALUE_MAX, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( DEFAULT_SPINVALUE,DEFAULTVALUE, 123, DEFAULT_SPINVALUE, FORM_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( SPININCREMENT, VALUESTEP, 124, SPININCREMENT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+
+ DEF_INFO_3( SPIN, SPIN, 125, SPIN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( REPEAT, REPEAT, 126, REPEAT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( REPEAT_DELAY, REPEAT_DELAY, 127, REPEAT_DELAY, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( VISIBLESIZE, VISIBLESIZE, 128, VISIBLESIZE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_4( ORIENTATION, ORIENTATION, 129, ORIENTATION, FORM_VISIBLE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_3( FOCUSONCLICK, FOCUSONCLICK, 130, FOCUSONCLICK, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( TOGGLE, TOGGLE, 131, TOGGLE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( DEFAULT_STATE, DEFAULT_STATE, 132, DEFAULT_STATE, FORM_VISIBLE, ENUM, COMPOSEABLE ),
+
+ DEF_INFO_3( TEXT_ANCHOR_TYPE, ANCHOR_TYPE, 133, ANCHOR_TYPE, FORM_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_3( SHEET_ANCHOR_TYPE, ANCHOR_TYPE, 134, ANCHOR_TYPE, FORM_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_3( POSITIONX, POSITIONX, 135, POSITIONX, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( POSITIONY, POSITIONY, 136, POSITIONY, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( WIDTH, WIDTH, 137, WIDTH, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( HEIGHT, HEIGHT, 138, HEIGHT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+
+ DEF_INFO_1( LISTINDEX, LISTINDEX, 139, LISTINDEX, FORM_VISIBLE ),
+ DEF_INFO_3( STRINGITEMLIST, STRINGITEMLIST, 140, STRINGITEMLIST, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( DEFAULT_TEXT, DEFAULTTEXT, 141, DEFAULTVALUE, FORM_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( FONT, FONT, 142, FONT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_4( VISUALEFFECT, VISUALEFFECT, 143, VISUALEFFECT, FORM_VISIBLE, DIALOG_VISIBLE, ENUM_ONE, COMPOSEABLE ),
+ DEF_INFO_4( ALIGN, ALIGN, 144, ALIGN, FORM_VISIBLE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_4( VERTICAL_ALIGN, VERTICAL_ALIGN, 145, VERTICAL_ALIGN, FORM_VISIBLE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_3( ROWHEIGHT, ROWHEIGHT, 146, ROWHEIGHT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( BACKGROUNDCOLOR, BACKGROUNDCOLOR, 147, BACKGROUNDCOLOR, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( SYMBOLCOLOR, SYMBOLCOLOR, 148, SYMBOLCOLOR, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( FILLCOLOR, FILLCOLOR, 149, FILLCOLOR, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( LINECOLOR, LINECOLOR, 150, LINECOLOR, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_4( BORDER, BORDER, 151, BORDER, FORM_VISIBLE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_3( BORDERCOLOR, BORDERCOLOR, 152, BORDERCOLOR, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( ICONSIZE, ICONSIZE, 153, ICONSIZE, FORM_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_2( SHOW_POSITION, SHOW_POSITION, 154, SHOW_POSITION, FORM_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( SHOW_NAVIGATION, SHOW_NAVIGATION, 155, SHOW_NAVIGATION, FORM_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( SHOW_RECORDACTIONS,SHOW_RECORDACTIONS, 156, SHOW_RECORDACTIONS,FORM_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( SHOW_FILTERSORT, SHOW_FILTERSORT, 157, SHOW_FILTERSORT, FORM_VISIBLE, COMPOSEABLE ),
+
+ DEF_INFO_3( DROPDOWN, DROPDOWN, 158, DROPDOWN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( LINECOUNT, LINECOUNT, 159, LINECOUNT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( AUTOCOMPLETE, AUTOCOMPLETE, 160, AUTOCOMPLETE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( MULTILINE, MULTILINE, 161, MULTILINE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( WORDBREAK, WORDBREAK, 162, WORDBREAK, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( TEXTTYPE, TEXTTYPE, 163, TEXTTYPE, FORM_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_3( LINEEND_FORMAT, LINEEND_FORMAT, 164, LINEEND_FORMAT, FORM_VISIBLE, ENUM_ONE, COMPOSEABLE ),
+ DEF_INFO_3( MULTISELECTION, MULTISELECTION, 165, MULTISELECTION, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_4( SHOW_SCROLLBARS, SHOW_SCROLLBARS, 166, SHOW_SCROLLBARS, FORM_VISIBLE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_3( HSCROLL, HSCROLL, 167, HSCROLL, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( VSCROLL, VSCROLL, 168, VSCROLL, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( BUTTONTYPE, BUTTONTYPE, 169, BUTTONTYPE, FORM_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_2( XFORMS_BUTTONTYPE, BUTTONTYPE, 170, BUTTONTYPE, FORM_VISIBLE, ENUM ),
+ DEF_INFO_1( SUBMISSION_ID, SUBMISSION_ID, 171, SUBMISSION_ID, FORM_VISIBLE ),
+ DEF_INFO_2( PUSHBUTTONTYPE, PUSHBUTTONTYPE, 172, PUSHBUTTONTYPE, DIALOG_VISIBLE, ENUM ),
+ DEF_INFO_2( TARGET_URL, TARGET_URL, 173, TARGET_URL, FORM_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_1( TARGET_FRAME, TARGET_FRAME, 174, TARGET_FRAME, FORM_VISIBLE ),
+ DEF_INFO_2( SUBMIT_ACTION, SUBMIT_ACTION, 175, SUBMIT_ACTION, FORM_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( SUBMIT_TARGET, SUBMIT_TARGET, 176, SUBMIT_TARGET, FORM_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( SUBMIT_ENCODING, SUBMIT_ENCODING, 177, SUBMIT_ENCODING, FORM_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_3( SUBMIT_METHOD, SUBMIT_METHOD, 178, SUBMIT_METHOD, FORM_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_3( STATE, STATE, 179, STATE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_3( DEFAULTBUTTON, DEFAULT_BUTTON, 180, DEFAULT_BUTTON, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( IMAGE_URL, IMAGE_URL, 181, IMAGE_URL, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_4( IMAGEPOSITION, IMAGEPOSITION, 182, IMAGEPOSITION, FORM_VISIBLE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_3( SCALEIMAGE, SCALEIMAGE, 183, SCALEIMAGE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_4( SCALE_MODE, SCALEIMAGE, 184, SCALEIMAGE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE, ENUM ),
+ DEF_INFO_2( DEFAULT_SELECT_SEQ,DEFAULT_SELECT_SEQ, 185, DEFAULT_SELECT_SEQ,FORM_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( SELECTEDITEMS, SELECTEDITEMS, 186, SELECTEDITEMS, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( ECHO_CHAR, ECHO_CHAR, 187, ECHO_CHAR, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( HIDEINACTIVESELECTION, HIDEINACTIVESELECTION, 188, HIDEINACTIVESELECTION, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( TRISTATE, TRISTATE, 189, TRISTATE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( HASNAVIGATION, NAVIGATION, 190, NAVIGATIONBAR, FORM_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( RECORDMARKER, RECORDMARKER, 191, RECORDMARKER, FORM_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( TAG, TAG, 192, TAG, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( HELPTEXT, HELPTEXT, 193, HELPTEXT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( HELPURL, HELPURL, 194, HELPURL, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( SELECTION_TYPE, SELECTION_TYPE, 195, SELECTION_TYPE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_2( ROOT_DISPLAYED, ROOT_DISPLAYED, 196, ROOT_DISPLAYED, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( SHOWS_HANDLES, SHOWS_HANDLES, 197, SHOWS_HANDLES, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( SHOWS_ROOT_HANDLES, SHOWS_ROOT_HANDLES, 198, SHOWS_ROOT_HANDLES, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( EDITABLE, EDITABLE, 199, EDITABLE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( INVOKES_STOP_NOT_EDITING, INVOKES_STOP_NOT_EDITING, 200, INVOKES_STOP_NOT_EDITING, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( DECORATION, DECORATION, 201, DECORATION, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( NOLABEL, NOLABEL, 202, NOLABEL, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_3( SELECTIONMODEL, SELECTIONMODEL, 203, SELECTIONMODEL, DIALOG_VISIBLE, ENUM, COMPOSEABLE ),
+ DEF_INFO_2( USEGRIDLINE, USEGRIDLINE, 204, USEGRIDLINE, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( GRIDLINECOLOR, GRIDLINECOLOR, 205, GRIDLINECOLOR, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( SHOWCOLUMNHEADER, SHOWCOLUMNHEADER, 206, SHOWCOLUMNHEADER, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( SHOWROWHEADER, SHOWROWHEADER, 207, SHOWROWHEADER, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( HEADERBACKGROUNDCOLOR, HEADERBACKGROUNDCOLOR, 208, HEADERBACKGROUNDCOLOR, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( HEADERTEXTCOLOR, HEADERTEXTCOLOR, 209, HEADERTEXTCOLOR, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( ACTIVESELECTIONBACKGROUNDCOLOR, ACTIVESELECTIONBACKGROUNDCOLOR, 210, ACTIVESELECTIONBACKGROUNDCOLOR, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( ACTIVESELECTIONTEXTCOLOR, ACTIVESELECTIONTEXTCOLOR, 211, ACTIVESELECTIONTEXTCOLOR, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( INACTIVESELECTIONBACKGROUNDCOLOR, INACTIVESELECTIONBACKGROUNDCOLOR, 212, INACTIVESELECTIONBACKGROUNDCOLOR, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( INACTIVESELECTIONTEXTCOLOR, INACTIVESELECTIONTEXTCOLOR, 213, INACTIVESELECTIONTEXTCOLOR, DIALOG_VISIBLE, COMPOSEABLE ),
+ DEF_INFO_2( URL, URL, 214, URL, DIALOG_VISIBLE, COMPOSEABLE ),
+
+ DEF_INFO_3( AUTOGROW, AUTOGROW, 215, AUTOGROW, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE)
+ };
+
+ s_pPropertyInfos = aPropertyInfos;
+ s_nCount = SAL_N_ELEMENTS(aPropertyInfos);
+
+ // sort
+ std::sort( s_pPropertyInfos, s_pPropertyInfos + s_nCount, PropertyInfoLessByName() );
+
+#if OSL_DEBUG_LEVEL > 0
+ for ( const OPropertyInfoImpl* pCheck = s_pPropertyInfos; pCheck != s_pPropertyInfos + s_nCount - 1; ++pCheck )
+ {
+ OSL_ENSURE( pCheck->sName != ( pCheck + 1 )->sName, "OPropertyInfoService::getPropertyInfo: duplicate entry in the table!" );
+ }
+#endif
+
+ return s_pPropertyInfos;
+ }
+
+
+ sal_Int32 OPropertyInfoService::getPropertyId(const OUString& _rName) const
+ {
+ const OPropertyInfoImpl* pInfo = getPropertyInfo(_rName);
+ return pInfo ? pInfo->nId : -1;
+ }
+
+
+ OUString OPropertyInfoService::getPropertyTranslation(sal_Int32 _nId) const
+ {
+ const OPropertyInfoImpl* pInfo = getPropertyInfo(_nId);
+ return pInfo ? pInfo->sTranslation : OUString();
+ }
+
+ OUString OPropertyInfoService::getPropertyHelpId(sal_Int32 _nId) const
+ {
+ const OPropertyInfoImpl* pInfo = getPropertyInfo(_nId);
+ return pInfo ? pInfo->sHelpId : OUString();
+ }
+
+ sal_Int16 OPropertyInfoService::getPropertyPos(sal_Int32 _nId) const
+ {
+ const OPropertyInfoImpl* pInfo = getPropertyInfo(_nId);
+ return pInfo ? pInfo->nPos : 0xFFFF;
+ }
+
+ sal_uInt32 OPropertyInfoService::getPropertyUIFlags(sal_Int32 _nId) const
+ {
+ const OPropertyInfoImpl* pInfo = getPropertyInfo(_nId);
+ return pInfo ? pInfo->nUIFlags : 0;
+ }
+
+ std::vector< OUString > OPropertyInfoService::getPropertyEnumRepresentations(sal_Int32 _nId) const
+ {
+ OSL_ENSURE( ( ( getPropertyUIFlags( _nId ) & PROP_FLAG_ENUM ) != 0 ) || ( _nId == PROPERTY_ID_TARGET_FRAME ),
+ "OPropertyInfoService::getPropertyEnumRepresentations: this is no enum property!" );
+
+ if (_nId == PROPERTY_ID_SUBMIT_METHOD)
+ {
+ return { "Get", "Post" };
+ }
+ const TranslateId* pStringItemsResId = nullptr;
+ int nElements = 0;
+ switch ( _nId )
+ {
+ case PROPERTY_ID_IMAGEPOSITION:
+ pStringItemsResId = RID_RSC_ENUM_IMAGE_POSITION;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_IMAGE_POSITION);
+ break;
+ case PROPERTY_ID_BORDER:
+ pStringItemsResId = RID_RSC_ENUM_BORDER_TYPE;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_BORDER_TYPE);
+ break;
+ case PROPERTY_ID_ICONSIZE:
+ pStringItemsResId = RID_RSC_ENUM_ICONSIZE_TYPE;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_ICONSIZE_TYPE);
+ break;
+ case PROPERTY_ID_COMMANDTYPE:
+ pStringItemsResId = RID_RSC_ENUM_COMMAND_TYPE;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_COMMAND_TYPE);
+ break;
+ case PROPERTY_ID_LISTSOURCETYPE:
+ pStringItemsResId = RID_RSC_ENUM_LISTSOURCE_TYPE;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_LISTSOURCE_TYPE);
+ break;
+ case PROPERTY_ID_ALIGN:
+ pStringItemsResId = RID_RSC_ENUM_ALIGNMENT;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_ALIGNMENT);
+ break;
+ case PROPERTY_ID_VERTICAL_ALIGN:
+ pStringItemsResId = RID_RSC_ENUM_VERTICAL_ALIGN;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_VERTICAL_ALIGN);
+ break;
+ case PROPERTY_ID_BUTTONTYPE:
+ pStringItemsResId = RID_RSC_ENUM_BUTTONTYPE;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_BUTTONTYPE);
+ break;
+ case PROPERTY_ID_PUSHBUTTONTYPE:
+ pStringItemsResId = RID_RSC_ENUM_PUSHBUTTONTYPE;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_PUSHBUTTONTYPE);
+ break;
+ case PROPERTY_ID_SUBMIT_ENCODING:
+ pStringItemsResId = RID_RSC_ENUM_SUBMIT_ENCODING;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_SUBMIT_ENCODING);
+ break;
+ case PROPERTY_ID_DATEFORMAT:
+ pStringItemsResId = RID_RSC_ENUM_DATEFORMAT_LIST;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_DATEFORMAT_LIST);
+ break;
+ case PROPERTY_ID_TIMEFORMAT:
+ pStringItemsResId = RID_RSC_ENUM_TIMEFORMAT_LIST;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_TIMEFORMAT_LIST);
+ break;
+ case PROPERTY_ID_DEFAULT_STATE:
+ case PROPERTY_ID_STATE:
+ pStringItemsResId = RID_RSC_ENUM_CHECKED;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_CHECKED);
+ break;
+ case PROPERTY_ID_CYCLE:
+ pStringItemsResId = RID_RSC_ENUM_CYCLE;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_CYCLE);
+ break;
+ case PROPERTY_ID_NAVIGATION:
+ pStringItemsResId = RID_RSC_ENUM_NAVIGATION;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_NAVIGATION);
+ break;
+ case PROPERTY_ID_TARGET_FRAME:
+ pStringItemsResId = RID_RSC_ENUM_SUBMIT_TARGET;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_SUBMIT_TARGET);
+ break;
+ case PROPERTY_ID_ORIENTATION:
+ pStringItemsResId = RID_RSC_ENUM_ORIENTATION;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_ORIENTATION);
+ break;
+ case PROPERTY_ID_CELL_EXCHANGE_TYPE:
+ pStringItemsResId = RID_RSC_ENUM_CELL_EXCHANGE_TYPE;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_CELL_EXCHANGE_TYPE);
+ break;
+ case PROPERTY_ID_SHOW_SCROLLBARS:
+ pStringItemsResId = RID_RSC_ENUM_SCROLLBARS;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_SCROLLBARS);
+ break;
+ case PROPERTY_ID_VISUALEFFECT:
+ pStringItemsResId = RID_RSC_ENUM_VISUALEFFECT;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_VISUALEFFECT);
+ break;
+ case PROPERTY_ID_TEXTTYPE:
+ pStringItemsResId = RID_RSC_ENUM_TEXTTYPE;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_TEXTTYPE);
+ break;
+ case PROPERTY_ID_LINEEND_FORMAT:
+ pStringItemsResId = RID_RSC_ENUM_LINEEND_FORMAT;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_LINEEND_FORMAT);
+ break;
+ case PROPERTY_ID_XSD_WHITESPACES:
+ pStringItemsResId = RID_RSC_ENUM_WHITESPACE_HANDLING;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_WHITESPACE_HANDLING);
+ break;
+ case PROPERTY_ID_SELECTION_TYPE:
+ case PROPERTY_ID_SELECTIONMODEL:
+ pStringItemsResId = RID_RSC_ENUM_SELECTION_TYPE;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_SELECTION_TYPE);
+ break;
+ case PROPERTY_ID_SCALE_MODE:
+ pStringItemsResId = RID_RSC_ENUM_SCALE_MODE;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_SCALE_MODE);
+ break;
+ case PROPERTY_ID_WRITING_MODE:
+ pStringItemsResId = RID_RSC_ENUM_WRITING_MODE;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_WRITING_MODE);
+ break;
+ case PROPERTY_ID_WHEEL_BEHAVIOR:
+ pStringItemsResId = RID_RSC_ENUM_WHEEL_BEHAVIOR;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_WHEEL_BEHAVIOR);
+ break;
+ case PROPERTY_ID_TEXT_ANCHOR_TYPE:
+ pStringItemsResId = RID_RSC_ENUM_TEXT_ANCHOR_TYPE;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_TEXT_ANCHOR_TYPE);
+ break;
+ case PROPERTY_ID_SHEET_ANCHOR_TYPE:
+ pStringItemsResId = RID_RSC_ENUM_SHEET_ANCHOR_TYPE;
+ nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_SHEET_ANCHOR_TYPE);
+ break;
+ default:
+ OSL_FAIL( "OPropertyInfoService::getPropertyEnumRepresentations: unknown enum property!" );
+ break;
+ }
+
+ std::vector< OUString > aReturn;
+
+ aReturn.reserve(nElements);
+ for (int i = 0; i < nElements; ++i)
+ {
+ aReturn.push_back(PcrRes(pStringItemsResId[i]));
+ }
+
+ return aReturn;
+ }
+
+ bool OPropertyInfoService::isComposeable( const OUString& _rPropertyName ) const
+ {
+ sal_Int32 nId = getPropertyId( _rPropertyName );
+ if ( nId == -1 )
+ return false;
+
+ sal_uInt32 nFlags = getPropertyUIFlags( nId );
+ return ( nFlags & PROP_FLAG_COMPOSEABLE ) != 0;
+ }
+
+
+ const OPropertyInfoImpl* OPropertyInfoService::getPropertyInfo(const OUString& _rName)
+ {
+ // Initialization
+ if(!s_pPropertyInfos)
+ getPropertyInfo();
+ OPropertyInfoImpl aSearch(_rName, 0, OUString(), 0, "", 0);
+
+ const OPropertyInfoImpl* pInfo = std::lower_bound(
+ s_pPropertyInfos, s_pPropertyInfos + s_nCount, aSearch, PropertyInfoLessByName() );
+
+ if ( pInfo == s_pPropertyInfos + s_nCount )
+ return nullptr;
+
+ if ( pInfo->sName != _rName )
+ return nullptr;
+
+ return pInfo;
+ }
+
+
+ const OPropertyInfoImpl* OPropertyInfoService::getPropertyInfo(sal_Int32 _nId)
+ {
+ // Initialization
+ if(!s_pPropertyInfos)
+ getPropertyInfo();
+
+ // TODO: a real structure which allows quick access by name as well as by id
+ for (sal_uInt16 i = 0; i < s_nCount; i++)
+ if (s_pPropertyInfos[i].nId == _nId)
+ return &s_pPropertyInfos[i];
+
+ return nullptr;
+ }
+
+
+ //= DefaultEnumRepresentation
+
+
+ DefaultEnumRepresentation::DefaultEnumRepresentation( const IPropertyInfoService& _rInfo, const Type& _rType, sal_Int32 _nPropertyId )
+ :m_rMetaData( _rInfo )
+ ,m_aType( _rType )
+ ,m_nPropertyId( _nPropertyId )
+ {
+ }
+
+
+ DefaultEnumRepresentation::~DefaultEnumRepresentation()
+ {
+ }
+
+
+ std::vector< OUString > DefaultEnumRepresentation::getDescriptions() const
+ {
+ return m_rMetaData.getPropertyEnumRepresentations( m_nPropertyId );
+ }
+
+
+ void DefaultEnumRepresentation::getValueFromDescription( const OUString& _rDescription, Any& _out_rValue ) const
+ {
+ sal_uInt32 nPropertyUIFlags = m_rMetaData.getPropertyUIFlags( m_nPropertyId );
+ std::vector< OUString > aEnumStrings = m_rMetaData.getPropertyEnumRepresentations( m_nPropertyId );
+ std::vector< OUString >::const_iterator pos = std::find( aEnumStrings.begin(), aEnumStrings.end(), _rDescription );
+ if ( pos != aEnumStrings.end() )
+ {
+ sal_Int32 nPos = pos - aEnumStrings.begin();
+ if ( ( nPropertyUIFlags & PROP_FLAG_ENUM_ONE ) == PROP_FLAG_ENUM_ONE )
+ // enum value starting with 1
+ ++nPos;
+
+ switch ( m_aType.getTypeClass() )
+ {
+ case TypeClass_ENUM:
+ _out_rValue = ::cppu::int2enum( nPos, m_aType );
+ break;
+
+ case TypeClass_SHORT:
+ _out_rValue <<= static_cast<sal_Int16>(nPos);
+ break;
+
+ case TypeClass_UNSIGNED_SHORT:
+ _out_rValue <<= static_cast<sal_uInt16>(nPos);
+ break;
+
+ case TypeClass_UNSIGNED_LONG:
+ _out_rValue <<= static_cast<sal_uInt32>(nPos);
+ break;
+
+ default:
+ _out_rValue <<= nPos;
+ break;
+ }
+ }
+ else
+ {
+ OSL_FAIL( "DefaultEnumRepresentation::getValueFromDescription: could not translate the enum string!" );
+ _out_rValue.clear();
+ }
+ }
+
+
+ OUString DefaultEnumRepresentation::getDescriptionForValue( const Any& _rEnumValue ) const
+ {
+ OUString sReturn;
+ sal_Int32 nIntValue = -1;
+ OSL_VERIFY( ::cppu::enum2int( nIntValue, _rEnumValue ) );
+
+ sal_uInt32 nUIFlags = m_rMetaData.getPropertyUIFlags( m_nPropertyId );
+ if ( ( nUIFlags & PROP_FLAG_ENUM_ONE ) == PROP_FLAG_ENUM_ONE )
+ // enum value starting with 1
+ --nIntValue;
+
+ std::vector< OUString > aEnumStrings = m_rMetaData.getPropertyEnumRepresentations( m_nPropertyId );
+ if ( ( nIntValue >= 0 ) && ( o3tl::make_unsigned(nIntValue) < aEnumStrings.size() ) )
+ {
+ sReturn = aEnumStrings[ nIntValue ];
+ }
+ else
+ {
+ OSL_FAIL( "DefaultEnumRepresentation::getDescriptionForValue: could not translate an enum value" );
+ }
+ return sReturn;
+ }
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/formmetadata.hxx b/extensions/source/propctrlr/formmetadata.hxx
new file mode 100644
index 000000000..0f7aa67d2
--- /dev/null
+++ b/extensions/source/propctrlr/formmetadata.hxx
@@ -0,0 +1,345 @@
+/* -*- 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 "propertyinfo.hxx"
+#include "enumrepresentation.hxx"
+
+
+namespace pcr
+{
+
+
+ struct OPropertyInfoImpl;
+
+
+ //= OPropertyInfoService
+
+ class OPropertyInfoService final
+ :public IPropertyInfoService
+ {
+ static sal_uInt16 s_nCount;
+ static OPropertyInfoImpl* s_pPropertyInfos;
+ // TODO: a real structure which allows quick access by name as well as by id
+
+ public:
+ // IPropertyInfoService
+ virtual sal_Int32 getPropertyId(const OUString& _rName) const override;
+ virtual OUString getPropertyTranslation(sal_Int32 _nId) const override;
+ virtual OUString getPropertyHelpId(sal_Int32 _nId) const override;
+ virtual sal_Int16 getPropertyPos(sal_Int32 _nId) const override;
+ virtual sal_uInt32 getPropertyUIFlags(sal_Int32 _nId) const override;
+ virtual std::vector< OUString > getPropertyEnumRepresentations(sal_Int32 _nId) const override;
+
+ bool isComposeable( const OUString& _rPropertyName ) const;
+
+ private:
+ static const OPropertyInfoImpl* getPropertyInfo();
+
+ static const OPropertyInfoImpl* getPropertyInfo(const OUString& _rName);
+ static const OPropertyInfoImpl* getPropertyInfo(sal_Int32 _nId);
+ };
+
+
+ //= DefaultEnumRepresentation
+
+ /** an implementation of the IPropertyEnumRepresentation
+
+ To be used with properties which, in formmetadata.cxx, are declared as ENUM.
+ */
+ class DefaultEnumRepresentation : public IPropertyEnumRepresentation
+ {
+ private:
+ const IPropertyInfoService& m_rMetaData;
+ css::uno::Type m_aType;
+ const sal_Int32 m_nPropertyId;
+
+ public:
+ /** constructs an instance
+
+ @param _rInfo
+ An instance implementing IPropertyInfoService. Must live at least as
+ long as the DefaultEnumRepresentation should live.
+ */
+ DefaultEnumRepresentation( const IPropertyInfoService& _rInfo, const css::uno::Type& _rType, sal_Int32 _nPropertyId );
+
+ protected:
+ virtual ~DefaultEnumRepresentation() override;
+
+ protected:
+ // IPropertyEnumRepresentation implementqation
+ virtual std::vector< OUString >
+ getDescriptions() const override;
+ virtual void getValueFromDescription( const OUString& _rDescription, css::uno::Any& _out_rValue ) const override;
+ virtual OUString getDescriptionForValue( const css::uno::Any& _rEnumValue ) const override;
+
+ private:
+ DefaultEnumRepresentation( const DefaultEnumRepresentation& ) = delete;
+ DefaultEnumRepresentation& operator=( const DefaultEnumRepresentation& ) = delete;
+ };
+
+
+ //= UI flags (for all browsable properties)
+
+
+#define PROP_FLAG_NONE 0x00000000 // no special flag
+#define PROP_FLAG_FORM_VISIBLE 0x00000001 // the property is visible when inspecting a form object
+#define PROP_FLAG_DIALOG_VISIBLE 0x00000002 // the property is visible when inspecting a dialog object
+#define PROP_FLAG_DATA_PROPERTY 0x00000004 // the property is to appear on the "Data" page
+#define PROP_FLAG_ENUM 0x00000020 // the property is some kind of enum property, i.e. its
+ // value is chosen from a fixed list of possible values
+#define PROP_FLAG_ENUM_ONE 0x00000060 // the property is an enum property starting with 1
+ // (note that this includes PROP_FLAG_ENUM)
+#define PROP_FLAG_COMPOSEABLE 0x00000080 // the property is "composeable", i.e. an intersection of property
+ // sets should expose it, if all elements do
+#define PROP_FLAG_EXPERIMENTAL 0x00000100 // the property is experimental, i.e. should not appear in the
+ // UI, unless experimental properties are enabled by a configuration
+ // option
+#define PROP_FLAG_REPORT_INVISIBLE 0x00000200 // the property should not appear in the Report Designer UI
+
+
+ //= property ids (for all browsable properties)
+
+
+ #define PROPERTY_ID_NAME 1
+ #define PROPERTY_ID_LABEL 2
+ #define PROPERTY_ID_CONTROLLABEL 3
+ #define PROPERTY_ID_MAXTEXTLEN 4
+ #define PROPERTY_ID_EDITMASK 5
+ #define PROPERTY_ID_LITERALMASK 6
+ #define PROPERTY_ID_STRICTFORMAT 7
+ #define PROPERTY_ID_ENABLED 8
+ #define PROPERTY_ID_READONLY 9
+ #define PROPERTY_ID_PRINTABLE 10
+ #define PROPERTY_ID_CONTROLSOURCE 11
+ #define PROPERTY_ID_TABSTOP 12
+ #define PROPERTY_ID_TABINDEX 13
+ #define PROPERTY_ID_DATASOURCE 14
+ #define PROPERTY_ID_COMMAND 15
+ #define PROPERTY_ID_COMMANDTYPE 16
+ #define PROPERTY_ID_FILTER 17
+ #define PROPERTY_ID_SORT 18
+ #define PROPERTY_ID_INSERTONLY 19
+ #define PROPERTY_ID_ALLOWADDITIONS 20
+ #define PROPERTY_ID_ALLOWEDITS 21
+ #define PROPERTY_ID_ALLOWDELETIONS 22
+ #define PROPERTY_ID_GROUP_NAME 23
+ #define PROPERTY_ID_NAVIGATION 24
+ #define PROPERTY_ID_CYCLE 25
+ #define PROPERTY_ID_HIDDEN_VALUE 26
+ #define PROPERTY_ID_VALUEMIN 27
+ #define PROPERTY_ID_VALUEMAX 28
+ #define PROPERTY_ID_VALUESTEP 29
+ #define PROPERTY_ID_DEFAULT_VALUE 30
+ #define PROPERTY_ID_DECIMAL_ACCURACY 31
+ #define PROPERTY_ID_SHOWTHOUSANDSEP 32
+ #define PROPERTY_ID_REFVALUE 33
+ #define PROPERTY_ID_CURRENCYSYMBOL 34
+ #define PROPERTY_ID_CURRSYM_POSITION 35
+ #define PROPERTY_ID_DATEMIN 36
+ #define PROPERTY_ID_DATEMAX 37
+ #define PROPERTY_ID_DATEFORMAT 38
+ #define PROPERTY_ID_SELECTEDITEMS 39
+ #define PROPERTY_ID_DEFAULT_DATE 40
+ #define PROPERTY_ID_TIMEMIN 41
+ #define PROPERTY_ID_TIMEMAX 42
+ #define PROPERTY_ID_TIMEFORMAT 43
+ #define PROPERTY_ID_DEFAULT_TIME 44
+ #define PROPERTY_ID_EFFECTIVE_MIN 45
+ #define PROPERTY_ID_EFFECTIVE_MAX 46
+ #define PROPERTY_ID_EFFECTIVE_DEFAULT 47
+ #define PROPERTY_ID_FORMATKEY 48
+ #define PROPERTY_ID_CLASSID 50
+ #define PROPERTY_ID_HEIGHT 51
+ #define PROPERTY_ID_WIDTH 52
+ #define PROPERTY_ID_BOUNDCOLUMN 53
+ #define PROPERTY_ID_LISTSOURCETYPE 54
+ #define PROPERTY_ID_LISTSOURCE 55
+ #define PROPERTY_ID_LISTINDEX 56
+ #define PROPERTY_ID_STRINGITEMLIST 57
+ #define PROPERTY_ID_DEFAULT_TEXT 58
+ #define PROPERTY_ID_FONT 59
+ #define PROPERTY_ID_ALIGN 60
+ #define PROPERTY_ID_ROWHEIGHT 61
+ #define PROPERTY_ID_BACKGROUNDCOLOR 62
+ #define PROPERTY_ID_FILLCOLOR 63
+ #define PROPERTY_ID_ESCAPE_PROCESSING 64
+ #define PROPERTY_ID_LINECOLOR 65
+ #define PROPERTY_ID_BORDER 66
+ #define PROPERTY_ID_DROPDOWN 67
+ #define PROPERTY_ID_AUTOCOMPLETE 68
+ #define PROPERTY_ID_LINECOUNT 69
+ #define PROPERTY_ID_WORDBREAK 70
+ #define PROPERTY_ID_MULTILINE 71
+ #define PROPERTY_ID_MULTISELECTION 72
+ #define PROPERTY_ID_AUTOLINEBREAK 73
+ #define PROPERTY_ID_HSCROLL 74
+ #define PROPERTY_ID_VSCROLL 75
+ #define PROPERTY_ID_SPIN 76
+ #define PROPERTY_ID_BUTTONTYPE 77
+ #define PROPERTY_ID_TARGET_URL 78
+ #define PROPERTY_ID_TARGET_FRAME 79
+ #define PROPERTY_ID_SUBMIT_ACTION 80
+ #define PROPERTY_ID_SUBMIT_TARGET 81
+ #define PROPERTY_ID_SUBMIT_METHOD 82
+ #define PROPERTY_ID_SUBMIT_ENCODING 83
+ #define PROPERTY_ID_DEFAULT_STATE 84
+ #define PROPERTY_ID_DEFAULTBUTTON 85
+ #define PROPERTY_ID_IMAGE_URL 86
+ #define PROPERTY_ID_DEFAULT_SELECT_SEQ 87
+ #define PROPERTY_ID_ECHO_CHAR 88
+ #define PROPERTY_ID_EMPTY_IS_NULL 89
+ #define PROPERTY_ID_TRISTATE 90
+ #define PROPERTY_ID_MASTERFIELDS 91
+ #define PROPERTY_ID_DETAILFIELDS 92
+ #define PROPERTY_ID_RECORDMARKER 93
+ #define PROPERTY_ID_FILTERPROPOSAL 94
+ #define PROPERTY_ID_TAG 95
+ #define PROPERTY_ID_HELPTEXT 96
+ #define PROPERTY_ID_HELPURL 97
+ #define PROPERTY_ID_HASNAVIGATION 98
+ #define PROPERTY_ID_POSITIONX 99
+ #define PROPERTY_ID_POSITIONY 100
+ #define PROPERTY_ID_TITLE 101
+ #define PROPERTY_ID_STEP 102
+ #define PROPERTY_ID_PROGRESSVALUE 103
+ #define PROPERTY_ID_PROGRESSVALUE_MIN 104
+ #define PROPERTY_ID_PROGRESSVALUE_MAX 105
+ #define PROPERTY_ID_SCROLLVALUE 106
+ #define PROPERTY_ID_SCROLLVALUE_MAX 107
+ #define PROPERTY_ID_LINEINCREMENT 108
+ #define PROPERTY_ID_BLOCKINCREMENT 109
+ #define PROPERTY_ID_VISIBLESIZE 110
+ #define PROPERTY_ID_ORIENTATION 111
+ #define PROPERTY_ID_IMAGEPOSITION 112
+ #define PROPERTY_ID_DATE 113
+ #define PROPERTY_ID_STATE 114
+ #define PROPERTY_ID_TIME 115
+ #define PROPERTY_ID_VALUE 116
+ #define PROPERTY_ID_SCALEIMAGE 117
+ #define PROPERTY_ID_PUSHBUTTONTYPE 118
+ #define PROPERTY_ID_EFFECTIVE_VALUE 119
+ #define PROPERTY_ID_TEXT 120
+ #define PROPERTY_ID_BOUND_CELL 121
+ #define PROPERTY_ID_LIST_CELL_RANGE 122
+ #define PROPERTY_ID_CELL_EXCHANGE_TYPE 123
+ #define PROPERTY_ID_SCROLLVALUE_MIN 124
+ #define PROPERTY_ID_DEFAULT_SCROLLVALUE 125
+ #define PROPERTY_ID_REPEAT_DELAY 126
+ #define PROPERTY_ID_SYMBOLCOLOR 127
+ #define PROPERTY_ID_SPINVALUE 128
+ #define PROPERTY_ID_SPINVALUE_MIN 129
+ #define PROPERTY_ID_SPINVALUE_MAX 130
+ #define PROPERTY_ID_DEFAULT_SPINVALUE 131
+ #define PROPERTY_ID_SPININCREMENT 132
+ #define PROPERTY_ID_REPEAT 133
+ #define PROPERTY_ID_SHOW_SCROLLBARS 134
+ #define PROPERTY_ID_ICONSIZE 135
+ #define PROPERTY_ID_SHOW_POSITION 136
+ #define PROPERTY_ID_SHOW_NAVIGATION 137
+ #define PROPERTY_ID_SHOW_RECORDACTIONS 138
+ #define PROPERTY_ID_SHOW_FILTERSORT 139
+ #define PROPERTY_ID_TEXTTYPE 140
+ #define PROPERTY_ID_LINEEND_FORMAT 141
+ #define PROPERTY_ID_TOGGLE 142
+ #define PROPERTY_ID_FOCUSONCLICK 143
+ #define PROPERTY_ID_HIDEINACTIVESELECTION 144
+ #define PROPERTY_ID_VISUALEFFECT 145
+ #define PROPERTY_ID_BORDERCOLOR 146
+ #define PROPERTY_ID_XML_DATA_MODEL 147
+ #define PROPERTY_ID_BIND_EXPRESSION 148
+ #define PROPERTY_ID_XSD_REQUIRED 149
+ #define PROPERTY_ID_XSD_RELEVANT 150
+ #define PROPERTY_ID_XSD_READONLY 151
+ #define PROPERTY_ID_XSD_CONSTRAINT 152
+ #define PROPERTY_ID_XSD_CALCULATION 153
+ #define PROPERTY_ID_XSD_DATA_TYPE 154
+ #define PROPERTY_ID_XSD_WHITESPACES 155
+ #define PROPERTY_ID_XSD_PATTERN 156
+ #define PROPERTY_ID_XSD_LENGTH 157
+ #define PROPERTY_ID_XSD_MIN_LENGTH 158
+ #define PROPERTY_ID_XSD_MAX_LENGTH 159
+ #define PROPERTY_ID_XSD_TOTAL_DIGITS 160
+ #define PROPERTY_ID_XSD_FRACTION_DIGITS 161
+ #define PROPERTY_ID_XSD_MAX_INCLUSIVE_INT 162
+ #define PROPERTY_ID_XSD_MAX_EXCLUSIVE_INT 163
+ #define PROPERTY_ID_XSD_MIN_INCLUSIVE_INT 164
+ #define PROPERTY_ID_XSD_MIN_EXCLUSIVE_INT 165
+ #define PROPERTY_ID_XSD_MAX_INCLUSIVE_DOUBLE 166
+ #define PROPERTY_ID_XSD_MAX_EXCLUSIVE_DOUBLE 167
+ #define PROPERTY_ID_XSD_MIN_INCLUSIVE_DOUBLE 168
+ #define PROPERTY_ID_XSD_MIN_EXCLUSIVE_DOUBLE 169
+ #define PROPERTY_ID_XSD_MAX_INCLUSIVE_DATE 170
+ #define PROPERTY_ID_XSD_MAX_EXCLUSIVE_DATE 171
+ #define PROPERTY_ID_XSD_MIN_INCLUSIVE_DATE 172
+ #define PROPERTY_ID_XSD_MIN_EXCLUSIVE_DATE 173
+ #define PROPERTY_ID_XSD_MAX_INCLUSIVE_TIME 174
+ #define PROPERTY_ID_XSD_MAX_EXCLUSIVE_TIME 175
+ #define PROPERTY_ID_XSD_MIN_INCLUSIVE_TIME 176
+ #define PROPERTY_ID_XSD_MIN_EXCLUSIVE_TIME 177
+ #define PROPERTY_ID_XSD_MAX_INCLUSIVE_DATE_TIME 178
+ #define PROPERTY_ID_XSD_MAX_EXCLUSIVE_DATE_TIME 179
+ #define PROPERTY_ID_XSD_MIN_INCLUSIVE_DATE_TIME 180
+ #define PROPERTY_ID_XSD_MIN_EXCLUSIVE_DATE_TIME 181
+ #define PROPERTY_ID_UNCHECKEDREFVALUE 182
+ #define PROPERTY_ID_SUBMISSION_ID 183
+ #define PROPERTY_ID_XFORMS_BUTTONTYPE 184
+ #define PROPERTY_ID_LIST_BINDING 185
+ #define PROPERTY_ID_VERTICAL_ALIGN 186
+ #define PROPERTY_ID_BINDING_NAME 187
+ #define PROPERTY_ID_DECORATION 188
+ #define PROPERTY_ID_SELECTION_TYPE 189
+ #define PROPERTY_ID_ROOT_DISPLAYED 190
+ #define PROPERTY_ID_SHOWS_HANDLES 191
+ #define PROPERTY_ID_SHOWS_ROOT_HANDLES 192
+ #define PROPERTY_ID_EDITABLE 193
+ #define PROPERTY_ID_INVOKES_STOP_NOT_EDITING 194
+ #define PROPERTY_ID_NOLABEL 195
+ #define PROPERTY_ID_SCALE_MODE 196
+ #define PROPERTY_ID_INPUT_REQUIRED 197
+ #define PROPERTY_ID_WRITING_MODE 198
+ #define PROPERTY_ID_ENABLE_VISIBLE 199
+ #define PROPERTY_ID_WHEEL_BEHAVIOR 200
+ #define PROPERTY_ID_TEXT_ANCHOR_TYPE 201
+ #define PROPERTY_ID_SHEET_ANCHOR_TYPE 202
+ #define PROPERTY_ID_SCROLL_WIDTH 203
+ #define PROPERTY_ID_SCROLL_HEIGHT 204
+ #define PROPERTY_ID_SCROLL_TOP 205
+ #define PROPERTY_ID_SCROLL_LEFT 206
+ #define PROPERTY_ID_TYPEDITEMLIST 207
+ #define PROPERTY_ID_SELECTIONMODEL 208
+ #define PROPERTY_ID_USEGRIDLINE 209
+ #define PROPERTY_ID_GRIDLINECOLOR 210
+ #define PROPERTY_ID_SHOWCOLUMNHEADER 211
+ #define PROPERTY_ID_SHOWROWHEADER 212
+ #define PROPERTY_ID_HEADERBACKGROUNDCOLOR 213
+ #define PROPERTY_ID_HEADERTEXTCOLOR 214
+ #define PROPERTY_ID_ACTIVESELECTIONBACKGROUNDCOLOR 215
+ #define PROPERTY_ID_ACTIVESELECTIONTEXTCOLOR 216
+ #define PROPERTY_ID_INACTIVESELECTIONBACKGROUNDCOLOR 217
+ #define PROPERTY_ID_INACTIVESELECTIONTEXTCOLOR 218
+ #define PROPERTY_ID_URL 219
+ #define PROPERTY_ID_AUTOGROW 220
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/formstrings.hxx b/extensions/source/propctrlr/formstrings.hxx
new file mode 100644
index 000000000..df151ab95
--- /dev/null
+++ b/extensions/source/propctrlr/formstrings.hxx
@@ -0,0 +1,302 @@
+/* -*- 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 <rtl/ustring.hxx>
+
+inline constexpr OUStringLiteral PROPERTY_DEFAULTCONTROL = u"DefaultControl";
+inline constexpr OUStringLiteral PROPERTY_INTROSPECTEDOBJECT = u"IntrospectedObject";
+inline constexpr OUStringLiteral PROPERTY_CURRENTPAGE = u"CurrentPage";
+inline constexpr OUStringLiteral PROPERTY_CONTROLCONTEXT = u"ControlContext";
+
+// properties
+inline constexpr OUStringLiteral PROPERTY_CLASSID = u"ClassId";
+inline constexpr OUStringLiteral PROPERTY_CONTROLLABEL = u"LabelControl";
+inline constexpr OUStringLiteral PROPERTY_LABEL = u"Label";
+inline constexpr OUStringLiteral PROPERTY_TABINDEX = u"TabIndex";
+inline constexpr OUStringLiteral PROPERTY_WHEEL_BEHAVIOR = u"MouseWheelBehavior";
+inline constexpr OUStringLiteral PROPERTY_TAG = u"Tag";
+inline constexpr OUStringLiteral PROPERTY_NAME = u"Name";
+inline constexpr OUStringLiteral PROPERTY_GROUP_NAME = u"GroupName";
+inline constexpr OUStringLiteral PROPERTY_VALUE = u"Value";
+inline constexpr OUStringLiteral PROPERTY_TEXT = u"Text";
+inline constexpr OUStringLiteral PROPERTY_NAVIGATION = u"NavigationBarMode";
+inline constexpr OUStringLiteral PROPERTY_CYCLE = u"Cycle";
+inline constexpr OUStringLiteral PROPERTY_CONTROLSOURCE = u"DataField";
+inline constexpr OUStringLiteral PROPERTY_INPUT_REQUIRED = u"InputRequired";
+inline constexpr OUStringLiteral PROPERTY_ENABLED = u"Enabled";
+inline constexpr OUStringLiteral PROPERTY_ENABLE_VISIBLE = u"EnableVisible";
+inline constexpr OUStringLiteral PROPERTY_READONLY = u"ReadOnly";
+inline constexpr OUStringLiteral PROPERTY_FILTER = u"Filter";
+inline constexpr OUStringLiteral PROPERTY_WIDTH = u"Width";
+inline constexpr OUStringLiteral PROPERTY_MULTILINE = u"MultiLine";
+inline constexpr OUStringLiteral PROPERTY_WORDBREAK = u"WordBreak";
+inline constexpr OUStringLiteral PROPERTY_TARGET_URL = u"TargetURL";
+inline constexpr OUStringLiteral PROPERTY_TARGET_FRAME = u"TargetFrame";
+inline constexpr OUStringLiteral PROPERTY_MAXTEXTLEN = u"MaxTextLen";
+inline constexpr OUStringLiteral PROPERTY_EDITMASK = u"EditMask";
+inline constexpr OUStringLiteral PROPERTY_SPIN = u"Spin";
+inline constexpr OUStringLiteral PROPERTY_TRISTATE = u"TriState";
+inline constexpr OUStringLiteral PROPERTY_HIDDEN_VALUE = u"HiddenValue";
+inline constexpr OUStringLiteral PROPERTY_BUTTONTYPE = u"ButtonType";
+inline constexpr OUStringLiteral PROPERTY_XFORMS_BUTTONTYPE = u"XFormsButtonType";
+inline constexpr OUStringLiteral PROPERTY_STRINGITEMLIST = u"StringItemList";
+inline constexpr OUStringLiteral PROPERTY_TYPEDITEMLIST = u"TypedItemList";
+inline constexpr OUStringLiteral PROPERTY_DEFAULT_TEXT = u"DefaultText";
+inline constexpr OUStringLiteral PROPERTY_DEFAULT_STATE = u"DefaultState";
+inline constexpr OUStringLiteral PROPERTY_FORMATKEY = u"FormatKey";
+inline constexpr OUStringLiteral PROPERTY_FORMATSSUPPLIER = u"FormatsSupplier";
+inline constexpr OUStringLiteral PROPERTY_SUBMIT_ACTION = u"SubmitAction";
+inline constexpr OUStringLiteral PROPERTY_SUBMIT_TARGET = u"SubmitTarget";
+inline constexpr OUStringLiteral PROPERTY_SUBMIT_METHOD = u"SubmitMethod";
+inline constexpr OUStringLiteral PROPERTY_SUBMIT_ENCODING = u"SubmitEncoding";
+inline constexpr OUStringLiteral PROPERTY_IMAGE_URL = u"ImageURL";
+inline constexpr OUStringLiteral PROPERTY_GRAPHIC = u"Graphic";
+inline constexpr OUStringLiteral PROPERTY_EMPTY_IS_NULL = u"ConvertEmptyToNull";
+inline constexpr OUStringLiteral PROPERTY_LISTSOURCETYPE = u"ListSourceType";
+inline constexpr OUStringLiteral PROPERTY_LISTSOURCE = u"ListSource";
+inline constexpr OUStringLiteral PROPERTY_DEFAULT_SELECT_SEQ = u"DefaultSelection";
+inline constexpr OUStringLiteral PROPERTY_MULTISELECTION = u"MultiSelection";
+inline constexpr OUStringLiteral PROPERTY_ALIGN = u"Align";
+inline constexpr OUStringLiteral PROPERTY_VERTICAL_ALIGN = u"VerticalAlign";
+inline constexpr OUStringLiteral PROPERTY_DEFAULT_DATE = u"DefaultDate";
+inline constexpr OUStringLiteral PROPERTY_DEFAULT_TIME = u"DefaultTime";
+inline constexpr OUStringLiteral PROPERTY_DEFAULT_VALUE = u"DefaultValue";
+inline constexpr OUStringLiteral PROPERTY_DECIMAL_ACCURACY = u"DecimalAccuracy";
+inline constexpr OUStringLiteral PROPERTY_REFVALUE = u"RefValue";
+inline constexpr OUStringLiteral PROPERTY_UNCHECKEDREFVALUE = u"SecondaryRefValue";
+inline constexpr OUStringLiteral PROPERTY_VALUEMIN = u"ValueMin";
+inline constexpr OUStringLiteral PROPERTY_VALUEMAX = u"ValueMax";
+inline constexpr OUStringLiteral PROPERTY_STRICTFORMAT = u"StrictFormat";
+inline constexpr OUStringLiteral PROPERTY_ALLOWADDITIONS = u"AllowInserts";
+inline constexpr OUStringLiteral PROPERTY_ALLOWEDITS = u"AllowUpdates";
+inline constexpr OUStringLiteral PROPERTY_ALLOWDELETIONS = u"AllowDeletes";
+inline constexpr OUStringLiteral PROPERTY_MASTERFIELDS = u"MasterFields";
+inline constexpr OUStringLiteral PROPERTY_LITERALMASK = u"LiteralMask";
+inline constexpr OUStringLiteral PROPERTY_VALUESTEP = u"ValueStep";
+inline constexpr OUStringLiteral PROPERTY_SHOWTHOUSANDSEP = u"ShowThousandsSeparator";
+inline constexpr OUStringLiteral PROPERTY_CURRENCYSYMBOL = u"CurrencySymbol";
+inline constexpr OUStringLiteral PROPERTY_DATEFORMAT = u"DateFormat";
+inline constexpr OUStringLiteral PROPERTY_DATEMIN = u"DateMin";
+inline constexpr OUStringLiteral PROPERTY_DATEMAX = u"DateMax";
+inline constexpr OUStringLiteral PROPERTY_TIMEFORMAT = u"TimeFormat";
+inline constexpr OUStringLiteral PROPERTY_TIMEMIN = u"TimeMin";
+inline constexpr OUStringLiteral PROPERTY_TIMEMAX = u"TimeMax";
+inline constexpr OUStringLiteral PROPERTY_LINECOUNT = u"LineCount";
+inline constexpr OUStringLiteral PROPERTY_BOUNDCOLUMN = u"BoundColumn";
+inline constexpr OUStringLiteral PROPERTY_BACKGROUNDCOLOR = u"BackgroundColor";
+inline constexpr OUStringLiteral PROPERTY_FILLCOLOR = u"FillColor";
+inline constexpr OUStringLiteral PROPERTY_TEXTCOLOR = u"TextColor";
+inline constexpr OUStringLiteral PROPERTY_LINECOLOR = u"LineColor";
+inline constexpr OUStringLiteral PROPERTY_BORDER = u"Border";
+inline constexpr OUStringLiteral PROPERTY_ICONSIZE = u"IconSize";
+inline constexpr OUStringLiteral PROPERTY_DROPDOWN = u"Dropdown";
+inline constexpr OUStringLiteral PROPERTY_HSCROLL = u"HScroll";
+inline constexpr OUStringLiteral PROPERTY_VSCROLL = u"VScroll";
+inline constexpr OUStringLiteral PROPERTY_SHOW_SCROLLBARS = u"ShowScrollbars";
+inline constexpr OUStringLiteral PROPERTY_TABSTOP = u"Tabstop";
+inline constexpr OUStringLiteral PROPERTY_AUTOCOMPLETE = u"Autocomplete";
+inline constexpr OUStringLiteral PROPERTY_PRINTABLE = u"Printable";
+inline constexpr OUStringLiteral PROPERTY_ECHO_CHAR = u"EchoChar";
+inline constexpr OUStringLiteral PROPERTY_ROWHEIGHT = u"RowHeight";
+inline constexpr OUStringLiteral PROPERTY_HELPTEXT = u"HelpText";
+inline constexpr OUStringLiteral PROPERTY_FONT = u"FontDescriptor";
+inline constexpr OUStringLiteral PROPERTY_FONT_NAME = u"FontName";
+inline constexpr OUStringLiteral PROPERTY_FONT_STYLENAME = u"FontStyleName";
+inline constexpr OUStringLiteral PROPERTY_FONT_FAMILY = u"FontFamily";
+inline constexpr OUStringLiteral PROPERTY_FONT_CHARSET = u"FontCharset";
+inline constexpr OUStringLiteral PROPERTY_FONT_HEIGHT = u"FontHeight";
+inline constexpr OUStringLiteral PROPERTY_FONT_WEIGHT = u"FontWeight";
+inline constexpr OUStringLiteral PROPERTY_FONT_SLANT = u"FontSlant";
+inline constexpr OUStringLiteral PROPERTY_FONT_UNDERLINE = u"FontUnderline";
+inline constexpr OUStringLiteral PROPERTY_FONT_STRIKEOUT = u"FontStrikeout";
+inline constexpr OUStringLiteral PROPERTY_FONT_RELIEF = u"FontRelief";
+inline constexpr OUStringLiteral PROPERTY_FONT_EMPHASIS_MARK = u"FontEmphasisMark";
+inline constexpr OUStringLiteral PROPERTY_TEXTLINECOLOR = u"TextLineColor";
+inline constexpr OUStringLiteral PROPERTY_HELPURL = u"HelpURL";
+inline constexpr OUStringLiteral PROPERTY_RECORDMARKER = u"HasRecordMarker";
+inline constexpr OUStringLiteral PROPERTY_EFFECTIVE_DEFAULT = u"EffectiveDefault";
+inline constexpr OUStringLiteral PROPERTY_EFFECTIVE_MIN = u"EffectiveMin";
+inline constexpr OUStringLiteral PROPERTY_EFFECTIVE_MAX = u"EffectiveMax";
+inline constexpr OUStringLiteral PROPERTY_FILTERPROPOSAL = u"UseFilterValueProposal";
+inline constexpr OUStringLiteral PROPERTY_CURRSYM_POSITION = u"PrependCurrencySymbol";
+inline constexpr OUStringLiteral PROPERTY_COMMAND = u"Command";
+inline constexpr OUStringLiteral PROPERTY_COMMANDTYPE = u"CommandType";
+inline constexpr OUStringLiteral PROPERTY_INSERTONLY = u"IgnoreResult";
+inline constexpr OUStringLiteral PROPERTY_ESCAPE_PROCESSING = u"EscapeProcessing";
+inline constexpr OUStringLiteral PROPERTY_TITLE = u"Title";
+inline constexpr OUStringLiteral PROPERTY_SORT = u"Order";
+inline constexpr OUStringLiteral PROPERTY_DATASOURCE = u"DataSourceName";
+inline constexpr OUStringLiteral PROPERTY_DETAILFIELDS = u"DetailFields";
+inline constexpr OUStringLiteral PROPERTY_DEFAULTBUTTON = u"DefaultButton";
+inline constexpr OUStringLiteral PROPERTY_LISTINDEX = u"ListIndex";
+inline constexpr OUStringLiteral PROPERTY_HEIGHT = u"Height";
+inline constexpr OUStringLiteral PROPERTY_HASNAVIGATION = u"HasNavigationBar";
+inline constexpr OUStringLiteral PROPERTY_POSITIONX = u"PositionX";
+inline constexpr OUStringLiteral PROPERTY_POSITIONY = u"PositionY";
+inline constexpr OUStringLiteral PROPERTY_AUTOGROW = u"AutoGrow";
+inline constexpr OUStringLiteral PROPERTY_STEP = u"Step";
+inline constexpr OUStringLiteral PROPERTY_WORDLINEMODE = u"FontWordLineMode";
+inline constexpr OUStringLiteral PROPERTY_PROGRESSVALUE = u"ProgressValue";
+inline constexpr OUStringLiteral PROPERTY_PROGRESSVALUE_MIN = u"ProgressValueMin";
+inline constexpr OUStringLiteral PROPERTY_PROGRESSVALUE_MAX = u"ProgressValueMax";
+inline constexpr OUStringLiteral PROPERTY_SCROLLVALUE = u"ScrollValue";
+inline constexpr OUStringLiteral PROPERTY_DEFAULT_SCROLLVALUE = u"DefaultScrollValue";
+inline constexpr OUStringLiteral PROPERTY_SCROLLVALUE_MIN = u"ScrollValueMin";
+inline constexpr OUStringLiteral PROPERTY_SCROLLVALUE_MAX = u"ScrollValueMax";
+inline constexpr OUStringLiteral PROPERTY_SCROLL_WIDTH = u"ScrollWidth";
+inline constexpr OUStringLiteral PROPERTY_SCROLL_HEIGHT = u"ScrollHeight";
+inline constexpr OUStringLiteral PROPERTY_SCROLL_TOP = u"ScrollTop";
+inline constexpr OUStringLiteral PROPERTY_SCROLL_LEFT = u"ScrollLeft";
+inline constexpr OUStringLiteral PROPERTY_LINEINCREMENT = u"LineIncrement";
+inline constexpr OUStringLiteral PROPERTY_BLOCKINCREMENT = u"BlockIncrement";
+inline constexpr OUStringLiteral PROPERTY_VISIBLESIZE = u"VisibleSize";
+inline constexpr OUStringLiteral PROPERTY_ORIENTATION = u"Orientation";
+inline constexpr OUStringLiteral PROPERTY_IMAGEPOSITION = u"ImagePosition";
+inline constexpr OUStringLiteral PROPERTY_ACTIVE_CONNECTION = u"ActiveConnection";
+inline constexpr OUStringLiteral PROPERTY_ACTIVECOMMAND = u"ActiveCommand";
+inline constexpr OUStringLiteral PROPERTY_DATE = u"Date";
+inline constexpr OUStringLiteral PROPERTY_STATE = u"State";
+inline constexpr OUStringLiteral PROPERTY_TIME = u"Time";
+inline constexpr OUStringLiteral PROPERTY_SCALEIMAGE = u"ScaleImage";
+inline constexpr OUStringLiteral PROPERTY_SCALE_MODE = u"ScaleMode";
+inline constexpr OUStringLiteral PROPERTY_PUSHBUTTONTYPE = u"PushButtonType";
+inline constexpr OUStringLiteral PROPERTY_EFFECTIVE_VALUE = u"EffectiveValue";
+inline constexpr OUStringLiteral PROPERTY_SELECTEDITEMS = u"SelectedItems";
+inline constexpr OUStringLiteral PROPERTY_REPEAT = u"Repeat";
+inline constexpr OUStringLiteral PROPERTY_REPEAT_DELAY = u"RepeatDelay";
+inline constexpr OUStringLiteral PROPERTY_SYMBOLCOLOR = u"SymbolColor";
+inline constexpr OUStringLiteral PROPERTY_SPINVALUE = u"SpinValue";
+inline constexpr OUStringLiteral PROPERTY_SPINVALUE_MIN = u"SpinValueMin";
+inline constexpr OUStringLiteral PROPERTY_SPINVALUE_MAX = u"SpinValueMax";
+inline constexpr OUStringLiteral PROPERTY_DEFAULT_SPINVALUE = u"DefaultSpinValue";
+inline constexpr OUStringLiteral PROPERTY_SPININCREMENT = u"SpinIncrement";
+inline constexpr OUStringLiteral PROPERTY_SHOW_POSITION = u"ShowPosition";
+inline constexpr OUStringLiteral PROPERTY_SHOW_NAVIGATION = u"ShowNavigation";
+inline constexpr OUStringLiteral PROPERTY_SHOW_RECORDACTIONS = u"ShowRecordActions";
+inline constexpr OUStringLiteral PROPERTY_SHOW_FILTERSORT = u"ShowFilterSort";
+inline constexpr OUStringLiteral PROPERTY_LINEEND_FORMAT = u"LineEndFormat";
+inline constexpr OUStringLiteral PROPERTY_DECORATION = u"Decoration";
+inline constexpr OUStringLiteral PROPERTY_NOLABEL = u"NoLabel";
+inline constexpr OUStringLiteral PROPERTY_URL = u"URL";
+
+inline constexpr OUStringLiteral PROPERTY_SELECTION_TYPE = u"SelectionType";
+inline constexpr OUStringLiteral PROPERTY_ROOT_DISPLAYED = u"RootDisplayed";
+inline constexpr OUStringLiteral PROPERTY_SHOWS_HANDLES = u"ShowsHandles";
+inline constexpr OUStringLiteral PROPERTY_SHOWS_ROOT_HANDLES = u"ShowsRootHandles";
+inline constexpr OUStringLiteral PROPERTY_EDITABLE = u"Editable";
+inline constexpr OUStringLiteral PROPERTY_INVOKES_STOP_NOT_EDITING = u"InvokesStopNodeEditing";
+
+inline constexpr OUStringLiteral PROPERTY_TOGGLE = u"Toggle";
+inline constexpr OUStringLiteral PROPERTY_FOCUSONCLICK = u"FocusOnClick";
+inline constexpr OUStringLiteral PROPERTY_HIDEINACTIVESELECTION = u"HideInactiveSelection";
+inline constexpr OUStringLiteral PROPERTY_VISUALEFFECT = u"VisualEffect";
+inline constexpr OUStringLiteral PROPERTY_BORDERCOLOR = u"BorderColor";
+
+inline constexpr OUStringLiteral PROPERTY_ADDRESS = u"Address";
+inline constexpr OUStringLiteral PROPERTY_REFERENCE_SHEET = u"ReferenceSheet";
+inline constexpr OUStringLiteral PROPERTY_UI_REPRESENTATION = u"UserInterfaceRepresentation";
+
+inline constexpr OUStringLiteral PROPERTY_XML_DATA_MODEL = u"XMLDataModel";
+inline constexpr OUStringLiteral PROPERTY_BINDING_NAME = u"BindingName";
+inline constexpr OUStringLiteral PROPERTY_BIND_EXPRESSION = u"BindingExpression";
+inline constexpr OUStringLiteral PROPERTY_LIST_BINDING = u"ListBinding";
+inline constexpr OUStringLiteral PROPERTY_XSD_REQUIRED = u"RequiredExpression";
+inline constexpr OUStringLiteral PROPERTY_XSD_RELEVANT = u"RelevantExpression";
+inline constexpr OUStringLiteral PROPERTY_XSD_READONLY = u"ReadonlyExpression";
+inline constexpr OUStringLiteral PROPERTY_XSD_CONSTRAINT = u"ConstraintExpression";
+inline constexpr OUStringLiteral PROPERTY_XSD_CALCULATION = u"CalculateExpression";
+inline constexpr OUStringLiteral PROPERTY_XSD_DATA_TYPE = u"Type";
+inline constexpr OUStringLiteral PROPERTY_XSD_WHITESPACES = u"WhiteSpace";
+inline constexpr OUStringLiteral PROPERTY_XSD_PATTERN = u"Pattern";
+inline constexpr OUStringLiteral PROPERTY_XSD_LENGTH = u"Length";
+inline constexpr OUStringLiteral PROPERTY_XSD_MIN_LENGTH = u"MinLength";
+inline constexpr OUStringLiteral PROPERTY_XSD_MAX_LENGTH = u"MaxLength";
+inline constexpr OUStringLiteral PROPERTY_XSD_TOTAL_DIGITS = u"TotalDigits";
+inline constexpr OUStringLiteral PROPERTY_XSD_FRACTION_DIGITS = u"FractionDigits";
+inline constexpr OUStringLiteral PROPERTY_XSD_MAX_INCLUSIVE_INT = u"MaxInclusiveInt";
+inline constexpr OUStringLiteral PROPERTY_XSD_MAX_EXCLUSIVE_INT = u"MaxExclusiveInt";
+inline constexpr OUStringLiteral PROPERTY_XSD_MIN_INCLUSIVE_INT = u"MinInclusiveInt";
+inline constexpr OUStringLiteral PROPERTY_XSD_MIN_EXCLUSIVE_INT = u"MinExclusiveInt";
+inline constexpr OUStringLiteral PROPERTY_XSD_MAX_INCLUSIVE_DOUBLE = u"MaxInclusiveDouble";
+inline constexpr OUStringLiteral PROPERTY_XSD_MAX_EXCLUSIVE_DOUBLE = u"MaxExclusiveDouble";
+inline constexpr OUStringLiteral PROPERTY_XSD_MIN_INCLUSIVE_DOUBLE = u"MinInclusiveDouble";
+inline constexpr OUStringLiteral PROPERTY_XSD_MIN_EXCLUSIVE_DOUBLE = u"MinExclusiveDouble";
+inline constexpr OUStringLiteral PROPERTY_XSD_MAX_INCLUSIVE_DATE = u"MaxInclusiveDate";
+inline constexpr OUStringLiteral PROPERTY_XSD_MAX_EXCLUSIVE_DATE = u"MaxExclusiveDate";
+inline constexpr OUStringLiteral PROPERTY_XSD_MIN_INCLUSIVE_DATE = u"MinInclusiveDate";
+inline constexpr OUStringLiteral PROPERTY_XSD_MIN_EXCLUSIVE_DATE = u"MinExclusiveDate";
+inline constexpr OUStringLiteral PROPERTY_XSD_MAX_INCLUSIVE_TIME = u"MaxInclusiveTime";
+inline constexpr OUStringLiteral PROPERTY_XSD_MAX_EXCLUSIVE_TIME = u"MaxExclusiveTime";
+inline constexpr OUStringLiteral PROPERTY_XSD_MIN_INCLUSIVE_TIME = u"MinInclusiveTime";
+inline constexpr OUStringLiteral PROPERTY_XSD_MIN_EXCLUSIVE_TIME = u"MinExclusiveTime";
+inline constexpr OUStringLiteral PROPERTY_XSD_MAX_INCLUSIVE_DATE_TIME = u"MaxInclusiveDateTime";
+inline constexpr OUStringLiteral PROPERTY_XSD_MAX_EXCLUSIVE_DATE_TIME = u"MaxExclusiveDateTime";
+inline constexpr OUStringLiteral PROPERTY_XSD_MIN_INCLUSIVE_DATE_TIME = u"MinInclusiveDateTime";
+inline constexpr OUStringLiteral PROPERTY_XSD_MIN_EXCLUSIVE_DATE_TIME = u"MinExclusiveDateTime";
+inline constexpr OUStringLiteral PROPERTY_SUBMISSION_ID = u"SubmissionID";
+inline constexpr OUStringLiteral PROPERTY_BINDING_ID = u"BindingID";
+inline constexpr OUStringLiteral PROPERTY_WRITING_MODE = u"WritingMode";
+inline constexpr OUStringLiteral PROPERTY_TEXT_ANCHOR_TYPE = u"TextAnchorType";
+inline constexpr OUStringLiteral PROPERTY_SHEET_ANCHOR_TYPE = u"SheetAnchorType";
+inline constexpr OUStringLiteral PROPERTY_ANCHOR_TYPE = u"AnchorType";
+inline constexpr OUStringLiteral PROPERTY_ANCHOR = u"Anchor";
+inline constexpr OUStringLiteral PROPERTY_IS_VISIBLE = u"IsVisible";
+
+inline constexpr OUStringLiteral PROPERTY_MODEL = u"Model";
+
+inline constexpr OUStringLiteral PROPERTY_CELL_EXCHANGE_TYPE = u"ExchangeSelectionIndex";
+inline constexpr OUStringLiteral PROPERTY_BOUND_CELL = u"BoundCell";
+inline constexpr OUStringLiteral PROPERTY_LIST_CELL_RANGE = u"CellRange";
+inline constexpr OUStringLiteral PROPERTY_TEXTTYPE = u"TextType";
+inline constexpr OUStringLiteral PROPERTY_RICHTEXT = u"RichText";
+inline constexpr OUStringLiteral PROPERTY_ROWSET = u"RowSet";
+inline constexpr OUStringLiteral PROPERTY_SELECTIONMODEL = u"SelectionModel";
+inline constexpr OUStringLiteral PROPERTY_USEGRIDLINE = u"UseGridLines";
+inline constexpr OUStringLiteral PROPERTY_GRIDLINECOLOR = u"GridLineColor";
+inline constexpr OUStringLiteral PROPERTY_SHOWCOLUMNHEADER = u"ShowColumnHeader";
+inline constexpr OUStringLiteral PROPERTY_SHOWROWHEADER = u"ShowRowHeader";
+inline constexpr OUStringLiteral PROPERTY_HEADERBACKGROUNDCOLOR = u"HeaderBackgroundColor";
+inline constexpr OUStringLiteral PROPERTY_HEADERTEXTCOLOR = u"HeaderTextColor";
+inline constexpr OUStringLiteral PROPERTY_ACTIVESELECTIONBACKGROUNDCOLOR = u"ActiveSelectionBackgroundColor";
+inline constexpr OUStringLiteral PROPERTY_ACTIVESELECTIONTEXTCOLOR = u"ActiveSelectionTextColor";
+inline constexpr OUStringLiteral PROPERTY_INACTIVESELECTIONBACKGROUNDCOLOR = u"InactiveSelectionBackgroundColor";
+inline constexpr OUStringLiteral PROPERTY_INACTIVESELECTIONTEXTCOLOR = u"InactiveSelectionTextColor";
+
+// services
+inline constexpr OUStringLiteral SERVICE_COMPONENT_GROUPBOX = u"com.sun.star.form.component.GroupBox";
+inline constexpr OUStringLiteral SERVICE_COMPONENT_FIXEDTEXT = u"com.sun.star.form.component.FixedText";
+inline constexpr OUStringLiteral SERVICE_COMPONENT_FORMATTEDFIELD = u"com.sun.star.form.component.FormattedField";
+
+inline constexpr OUStringLiteral SERVICE_TEXT_DOCUMENT = u"com.sun.star.text.TextDocument";
+inline constexpr OUStringLiteral SERVICE_WEB_DOCUMENT = u"com.sun.star.text.WebDocument";
+inline constexpr OUStringLiteral SERVICE_SPREADSHEET_DOCUMENT = u"com.sun.star.sheet.SpreadsheetDocument";
+inline constexpr OUStringLiteral SERVICE_DRAWING_DOCUMENT = u"com.sun.star.drawing.DrawingDocument";
+inline constexpr OUStringLiteral SERVICE_PRESENTATION_DOCUMENT = u"com.sun.star.presentation.PresentationDocument";
+
+inline constexpr OUStringLiteral SERVICE_SHEET_CELL_BINDING = u"com.sun.star.table.CellValueBinding";
+inline constexpr OUStringLiteral SERVICE_SHEET_CELL_INT_BINDING = u"com.sun.star.table.ListPositionCellBinding";
+inline constexpr OUStringLiteral SERVICE_SHEET_CELLRANGE_LISTSOURCE = u"com.sun.star.table.CellRangeListSource";
+inline constexpr OUStringLiteral SERVICE_ADDRESS_CONVERSION = u"com.sun.star.table.CellAddressConversion";
+inline constexpr OUStringLiteral SERVICE_RANGEADDRESS_CONVERSION = u"com.sun.star.table.CellRangeAddressConversion";
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/genericpropertyhandler.cxx b/extensions/source/propctrlr/genericpropertyhandler.cxx
new file mode 100644
index 000000000..8320e5154
--- /dev/null
+++ b/extensions/source/propctrlr/genericpropertyhandler.cxx
@@ -0,0 +1,619 @@
+/* -*- 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 "enumrepresentation.hxx"
+#include "genericpropertyhandler.hxx"
+#include "handlerhelper.hxx"
+
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/reflection/XEnumTypeDescription.hpp>
+#include <com/sun/star/beans/theIntrospection.hpp>
+#include <com/sun/star/inspection/PropertyControlType.hpp>
+#include <com/sun/star/inspection/XHyperlinkControl.hpp>
+#include <com/sun/star/awt/XActionListener.hpp>
+#include <com/sun/star/script/Converter.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/extract.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <o3tl/safeint.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <algorithm>
+
+namespace pcr
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::reflection;
+ using namespace ::com::sun::star::inspection;
+ using ::com::sun::star::awt::XActionListener;
+ using ::com::sun::star::awt::ActionEvent;
+
+ namespace {
+
+ class EnumRepresentation : public IPropertyEnumRepresentation
+ {
+ private:
+ Reference< XEnumTypeDescription > m_xTypeDescription;
+ Type m_aEnumType;
+
+ public:
+ EnumRepresentation( const Reference< XComponentContext >& _rxContext, const Type& _rEnumType );
+ EnumRepresentation(const EnumRepresentation&) = delete;
+ EnumRepresentation& operator=(const EnumRepresentation&) = delete;
+
+ // IPropertyEnumRepresentation implementqation
+ virtual std::vector< OUString >
+ getDescriptions() const override;
+ virtual void getValueFromDescription( const OUString& _rDescription, css::uno::Any& _out_rValue ) const override;
+ virtual OUString getDescriptionForValue( const css::uno::Any& _rEnumValue ) const override;
+
+ private:
+ void impl_getValues( Sequence< sal_Int32 >& _out_rValues ) const;
+ };
+
+ }
+
+ EnumRepresentation::EnumRepresentation( const Reference< XComponentContext >& _rxContext, const Type& _rEnumType )
+ :m_aEnumType( _rEnumType )
+ {
+ try
+ {
+ if ( _rxContext.is() )
+ {
+ Reference< XHierarchicalNameAccess > xTypeDescProv(
+ _rxContext->getValueByName("/singletons/com.sun.star.reflection.theTypeDescriptionManager"),
+ UNO_QUERY_THROW );
+
+ m_xTypeDescription.set( xTypeDescProv->getByHierarchicalName( m_aEnumType.getTypeName() ), UNO_QUERY_THROW );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EnumRepresentation::EnumRepresentation" );
+ }
+ }
+
+ std::vector< OUString > EnumRepresentation::getDescriptions() const
+ {
+ Sequence< OUString > aNames;
+ try
+ {
+ if ( m_xTypeDescription.is() )
+ aNames = m_xTypeDescription->getEnumNames();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EnumRepresentation::getDescriptions" );
+ }
+
+ return std::vector< OUString >( std::cbegin(aNames), std::cend(aNames) );
+ }
+
+ void EnumRepresentation::impl_getValues( Sequence< sal_Int32 >& _out_rValues ) const
+ {
+ _out_rValues.realloc( 0 );
+ try
+ {
+ if ( m_xTypeDescription.is() )
+ _out_rValues = m_xTypeDescription->getEnumValues();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EnumRepresentation::impl_getValues" );
+ }
+ }
+
+ void EnumRepresentation::getValueFromDescription( const OUString& _rDescription, Any& _out_rValue ) const
+ {
+ std::vector< OUString > aDescriptions( getDescriptions() );
+
+ sal_Int32 index = std::find( aDescriptions.begin(), aDescriptions.end(),
+ _rDescription ) - aDescriptions.begin();
+
+ Sequence< sal_Int32 > aValues;
+ impl_getValues( aValues );
+
+ if ( ( index >= 0 ) && ( index < aValues.getLength() ) )
+ _out_rValue = ::cppu::int2enum( aValues[ index ], m_aEnumType );
+ else
+ {
+ OSL_FAIL( "EnumRepresentation::getValueFromDescription: cannot convert!" );
+ _out_rValue.clear();
+ }
+ }
+
+ OUString EnumRepresentation::getDescriptionForValue( const Any& _rEnumValue ) const
+ {
+ OUString sDescription;
+
+ sal_Int32 nAsInt = 0;
+ OSL_VERIFY( ::cppu::enum2int( nAsInt, _rEnumValue ) );
+
+ Sequence< sal_Int32 > aValues;
+ impl_getValues( aValues );
+
+ sal_Int32 index = std::find( std::cbegin(aValues), std::cend(aValues), nAsInt ) - std::cbegin(aValues);
+
+ std::vector< OUString > aDescriptions( getDescriptions() );
+ if ( ( index >= 0 ) && ( o3tl::make_unsigned(index) < aDescriptions.size() ) )
+ sDescription = aDescriptions[ index ];
+ else
+ {
+ OSL_FAIL( "EnumRepresentation::getDescriptionForValue: cannot convert!" );
+ }
+ return sDescription;
+ }
+
+ typedef ::cppu::WeakImplHelper < XActionListener
+ > UrlClickHandler_Base;
+
+ namespace {
+
+ class UrlClickHandler : public UrlClickHandler_Base
+ {
+ Reference<XComponentContext> m_xContext;
+ public:
+ UrlClickHandler( const Reference<XComponentContext>& _rContext, const Reference< XHyperlinkControl >& _rxControl );
+
+ protected:
+ virtual ~UrlClickHandler() override;
+
+ // XActionListener
+ virtual void SAL_CALL actionPerformed( const ActionEvent& rEvent ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const EventObject& Source ) override;
+
+ protected:
+ void impl_dispatch_throw( const OUString& _rURL );
+ };
+
+ }
+
+ UrlClickHandler::UrlClickHandler( const Reference<XComponentContext>& _rContext, const Reference< XHyperlinkControl >& _rxControl )
+ :m_xContext( _rContext )
+ {
+ if ( !_rxControl.is() )
+ throw NullPointerException();
+
+ osl_atomic_increment( &m_refCount );
+ {
+ _rxControl->addActionListener( this );
+ }
+ osl_atomic_decrement( &m_refCount );
+ OSL_ENSURE( m_refCount > 0, "UrlClickHandler::UrlClickHandler: leaking!" );
+
+ }
+
+ UrlClickHandler::~UrlClickHandler()
+ {
+ }
+
+ void SAL_CALL UrlClickHandler::actionPerformed( const ActionEvent& rEvent )
+ {
+ Reference< XPropertyControl > xControl( rEvent.Source, UNO_QUERY_THROW );
+ Any aControlValue( xControl->getValue() );
+
+ OUString sURL;
+ if ( aControlValue.hasValue() && !( aControlValue >>= sURL ) )
+ throw RuntimeException( OUString(), *this );
+
+ if ( sURL.isEmpty() )
+ return;
+
+ impl_dispatch_throw( sURL );
+ }
+
+ void SAL_CALL UrlClickHandler::disposing( const EventObject& /*Source*/ )
+ {
+ // not interested in
+ }
+
+ void UrlClickHandler::impl_dispatch_throw( const OUString& _rURL )
+ {
+ Reference< XURLTransformer > xTransformer( URLTransformer::create(m_xContext) );
+ URL aURL; aURL.Complete = ".uno:OpenHyperlink";
+ xTransformer->parseStrict( aURL );
+
+ Reference< XDesktop2 > xDispProv = Desktop::create( m_xContext );
+ Reference< XDispatch > xDispatch( xDispProv->queryDispatch( aURL, OUString(), 0 ), UNO_SET_THROW );
+
+ Sequence aDispatchArgs{ comphelper::makePropertyValue("URL", _rURL) };
+
+ xDispatch->dispatch( aURL, aDispatchArgs );
+ }
+
+
+ GenericPropertyHandler::GenericPropertyHandler( const Reference< XComponentContext >& _rxContext )
+ :GenericPropertyHandler_Base( m_aMutex )
+ ,m_xContext( _rxContext )
+ ,m_aPropertyListeners( m_aMutex )
+ ,m_bPropertyMapInitialized( false )
+ {
+ m_xTypeConverter = Converter::create(_rxContext);
+ }
+
+ GenericPropertyHandler::~GenericPropertyHandler()
+ {
+ }
+
+ OUString SAL_CALL GenericPropertyHandler::getImplementationName( )
+ {
+ return "com.sun.star.comp.extensions.GenericPropertyHandler";
+ }
+
+ sal_Bool SAL_CALL GenericPropertyHandler::supportsService( const OUString& ServiceName )
+ {
+ return cppu::supportsService(this, ServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL GenericPropertyHandler::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.inspection.GenericPropertyHandler" };
+ }
+
+ void SAL_CALL GenericPropertyHandler::inspect( const Reference< XInterface >& _rxIntrospectee )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !_rxIntrospectee.is() )
+ throw NullPointerException();
+
+ // revoke old property change listeners
+ ::comphelper::OInterfaceIteratorHelper2 iterRemove( m_aPropertyListeners );
+ ::comphelper::OInterfaceIteratorHelper2 iterReAdd( m_aPropertyListeners ); // this holds a copy of the container ...
+ while ( iterRemove.hasMoreElements() )
+ m_xComponent->removePropertyChangeListener( OUString(), static_cast< XPropertyChangeListener* >( iterRemove.next() ) );
+
+ m_xComponentIntrospectionAccess.clear();
+ m_xComponent.clear();
+ m_xPropertyState.clear();
+
+ // create an introspection adapter for the component
+ Reference< XIntrospection > xIntrospection = theIntrospection::get( m_xContext );
+
+ Reference< XIntrospectionAccess > xIntrospectionAccess( xIntrospection->inspect( Any( _rxIntrospectee ) ) );
+ if ( !xIntrospectionAccess.is() )
+ throw RuntimeException("The introspection service could not handle the given component.", *this );
+
+ m_xComponent.set( xIntrospectionAccess->queryAdapter( cppu::UnoType<XPropertySet>::get() ), UNO_QUERY_THROW );
+ // now that we survived so far, remember m_xComponentIntrospectionAccess
+ m_xComponentIntrospectionAccess = xIntrospectionAccess;
+ m_xPropertyState.set(m_xComponent, css::uno::UNO_QUERY);
+
+ m_bPropertyMapInitialized = false;
+ m_aProperties.clear();
+
+ // re-add the property change listeners
+ while ( iterReAdd.hasMoreElements() )
+ m_xComponent->addPropertyChangeListener( OUString(), static_cast< XPropertyChangeListener* >( iterReAdd.next() ) );
+ }
+
+ Any SAL_CALL GenericPropertyHandler::getPropertyValue( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !m_xComponent.is() )
+ throw UnknownPropertyException(_rPropertyName);
+
+ return m_xComponent->getPropertyValue( _rPropertyName );
+ }
+
+ void SAL_CALL GenericPropertyHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !m_xComponent.is() )
+ throw UnknownPropertyException(_rPropertyName);
+
+ m_xComponent->setPropertyValue( _rPropertyName, _rValue );
+ }
+
+ ::rtl::Reference< IPropertyEnumRepresentation > GenericPropertyHandler::impl_getEnumConverter( const Type& _rEnumType )
+ {
+ ::rtl::Reference< IPropertyEnumRepresentation >& rConverter = m_aEnumConverters[ _rEnumType ];
+ if ( !rConverter.is() )
+ rConverter = new EnumRepresentation( m_xContext, _rEnumType );
+ return rConverter;
+ }
+
+ Any SAL_CALL GenericPropertyHandler::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_ensurePropertyMap();
+
+ PropertyMap::const_iterator pos = m_aProperties.find( _rPropertyName );
+ if ( pos == m_aProperties.end() )
+ throw UnknownPropertyException(_rPropertyName);
+
+ Any aPropertyValue;
+ if ( !_rControlValue.hasValue() )
+ // NULL is converted to NULL
+ return aPropertyValue;
+
+ if ( pos->second.Type.getTypeClass() == TypeClass_ENUM )
+ {
+ OUString sControlValue;
+ OSL_VERIFY( _rControlValue >>= sControlValue );
+ impl_getEnumConverter( pos->second.Type )->getValueFromDescription( sControlValue, aPropertyValue );
+ }
+ else
+ aPropertyValue = PropertyHandlerHelper::convertToPropertyValue( m_xContext, m_xTypeConverter, pos->second, _rControlValue );
+
+ return aPropertyValue;
+ }
+
+ Any SAL_CALL GenericPropertyHandler::convertToControlValue( const OUString& _rPropertyName, const Any& _rPropertyValue, const Type& _rControlValueType )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_ensurePropertyMap();
+
+ PropertyMap::const_iterator pos = m_aProperties.find( _rPropertyName );
+ if ( pos == m_aProperties.end() )
+ throw UnknownPropertyException(_rPropertyName);
+
+ Any aControlValue;
+ if ( !_rPropertyValue.hasValue() )
+ // NULL is converted to NULL
+ return aControlValue;
+
+ if ( pos->second.Type.getTypeClass() == TypeClass_ENUM )
+ {
+ aControlValue <<= impl_getEnumConverter( pos->second.Type )->getDescriptionForValue( _rPropertyValue );
+ }
+ else
+ aControlValue = PropertyHandlerHelper::convertToControlValue( m_xContext, m_xTypeConverter, _rPropertyValue, _rControlValueType );
+ return aControlValue;
+ }
+
+ PropertyState SAL_CALL GenericPropertyHandler::getPropertyState( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyState eState = PropertyState_DIRECT_VALUE;
+ if ( m_xPropertyState.is() )
+ eState = m_xPropertyState->getPropertyState( _rPropertyName );
+ return eState;
+ }
+
+ void SAL_CALL GenericPropertyHandler::addPropertyChangeListener(const Reference< XPropertyChangeListener >& _rxListener)
+ {
+ if ( !_rxListener.is() )
+ throw NullPointerException();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_aPropertyListeners.addInterface( _rxListener );
+ if ( m_xComponent.is() )
+ {
+ try
+ {
+ m_xComponent->addPropertyChangeListener( OUString(), _rxListener );
+ }
+ catch( const UnknownPropertyException& )
+ {
+ OSL_FAIL( "GenericPropertyHandler::addPropertyChangeListener:\nThe inspected component does not allow registering for all properties at once! This violates the interface contract!" );
+ }
+ }
+ }
+
+ void SAL_CALL GenericPropertyHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_xComponent.is() )
+ {
+ try
+ {
+ m_xComponent->removePropertyChangeListener( OUString(), _rxListener );
+ }
+ catch( const UnknownPropertyException& )
+ {
+ OSL_FAIL( "GenericPropertyHandler::removePropertyChangeListener:\nThe inspected component does not allow de-registering for all properties at once! This violates the interface contract!" );
+ }
+ }
+ m_aPropertyListeners.removeInterface( _rxListener );
+ }
+
+ void GenericPropertyHandler::impl_ensurePropertyMap()
+ {
+ if ( m_bPropertyMapInitialized )
+ return;
+
+ m_bPropertyMapInitialized = true;
+ try
+ {
+ Reference< XPropertySetInfo > xPSI;
+ if ( m_xComponent.is() )
+ xPSI = m_xComponent->getPropertySetInfo();
+ Sequence< Property > aProperties;
+ if ( xPSI.is() )
+ aProperties = xPSI->getProperties();
+ DBG_ASSERT( aProperties.hasElements(), "GenericPropertyHandler::getSupportedProperties: no properties!" );
+
+ for ( auto const & property : std::as_const(aProperties) )
+ {
+ switch ( property.Type.getTypeClass() )
+ {
+ case TypeClass_BOOLEAN:
+ case TypeClass_BYTE:
+ case TypeClass_SHORT:
+ case TypeClass_UNSIGNED_SHORT:
+ case TypeClass_LONG:
+ case TypeClass_UNSIGNED_LONG:
+ case TypeClass_HYPER:
+ case TypeClass_UNSIGNED_HYPER:
+ case TypeClass_FLOAT:
+ case TypeClass_DOUBLE:
+ case TypeClass_ENUM:
+ case TypeClass_STRING:
+ // allowed, we can handle this type
+ break;
+
+ case TypeClass_SEQUENCE:
+ {
+ TypeClass eElementTypeClass = ::comphelper::getSequenceElementType( property.Type ).getTypeClass();
+ if ( ( eElementTypeClass != TypeClass_STRING )
+ && ( eElementTypeClass != TypeClass_BYTE )
+ && ( eElementTypeClass != TypeClass_SHORT )
+ && ( eElementTypeClass != TypeClass_UNSIGNED_SHORT )
+ && ( eElementTypeClass != TypeClass_LONG )
+ && ( eElementTypeClass != TypeClass_UNSIGNED_LONG )
+ )
+ // can only handle the above
+ continue;
+ }
+ break;
+
+ default:
+ // next property, we don't support this type
+ continue;
+ }
+
+ m_aProperties.emplace( property.Name, property );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "GenericPropertyHandler::impl_ensurePropertyMap" );
+ }
+ }
+
+ Sequence< Property > SAL_CALL GenericPropertyHandler::getSupportedProperties()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_ensurePropertyMap();
+
+ return comphelper::mapValuesToSequence( m_aProperties );
+ }
+
+ Sequence< OUString > SAL_CALL GenericPropertyHandler::getSupersededProperties( )
+ {
+ // no superseded properties at all. This handler offers the very basic PropertyHandler
+ // functionality, so it's much more likely that other handlers want to supersede
+ // *our* properties...
+ return Sequence< OUString >( );
+ }
+
+ Sequence< OUString > SAL_CALL GenericPropertyHandler::getActuatingProperties( )
+ {
+ // This basic PropertyHandler implementation is too dumb^Wgeneric to know
+ // anything about property dependencies
+ return Sequence< OUString >( );
+ }
+
+ LineDescriptor SAL_CALL GenericPropertyHandler::describePropertyLine( const OUString& _rPropertyName,
+ const Reference< XPropertyControlFactory >& _rxControlFactory )
+ {
+ if ( !_rxControlFactory.is() )
+ throw NullPointerException();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_ensurePropertyMap();
+
+ PropertyMap::const_iterator pos = m_aProperties.find( _rPropertyName );
+ if ( pos == m_aProperties.end() )
+ throw UnknownPropertyException(_rPropertyName);
+
+ LineDescriptor aDescriptor;
+ aDescriptor.DisplayName = _rPropertyName;
+ switch ( pos->second.Type.getTypeClass() )
+ {
+ case TypeClass_ENUM:
+ aDescriptor.Control = PropertyHandlerHelper::createListBoxControl( _rxControlFactory,
+ impl_getEnumConverter( pos->second.Type )->getDescriptions(),
+ PropertyHandlerHelper::requiresReadOnlyControl( pos->second.Attributes ),
+ false );
+ break;
+ case TypeClass_STRING:
+ {
+ // some special handling for URL properties
+ bool bIsURLProperty = _rPropertyName.endsWith( "URL" );
+ if ( bIsURLProperty )
+ {
+ aDescriptor.Control = _rxControlFactory->createPropertyControl(
+ PropertyControlType::HyperlinkField, PropertyHandlerHelper::requiresReadOnlyControl( pos->second.Attributes ) );
+
+ Reference< XHyperlinkControl > xControl( aDescriptor.Control, UNO_QUERY_THROW );
+ new UrlClickHandler( m_xContext, xControl );
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ // fallback
+ if ( !aDescriptor.Control.is() )
+ PropertyHandlerHelper::describePropertyLine( pos->second, aDescriptor, _rxControlFactory );
+
+ aDescriptor.Category = "General";
+ return aDescriptor;
+ }
+
+ sal_Bool SAL_CALL GenericPropertyHandler::isComposable( const OUString& /*_rPropertyName*/ )
+ {
+ return false;
+ }
+
+ InteractiveSelectionResult SAL_CALL GenericPropertyHandler::onInteractivePropertySelection( const OUString& /*_rPropertyName*/, sal_Bool /*_bPrimary*/, Any& /*_rData*/, const Reference< XObjectInspectorUI >& /*_rxInspectorUI*/ )
+ {
+ OSL_FAIL( "GenericPropertyHandler::onInteractivePropertySelection: I'm too dumb to know anything about property browse buttons!" );
+ return InteractiveSelectionResult_Cancelled;
+ }
+
+ void SAL_CALL GenericPropertyHandler::actuatingPropertyChanged( const OUString& /*_rActuatingPropertyName*/, const Any& /*_rNewValue*/, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& /*_rxInspectorUI*/, sal_Bool /*_bFirstTimeInit*/ )
+ {
+ OSL_FAIL( "GenericPropertyHandler::actuatingPropertyChanged: no no no, I did not register for any actuating properties!" );
+ }
+
+ sal_Bool SAL_CALL GenericPropertyHandler::suspend( sal_Bool /*_bSuspend*/ )
+ {
+ return true;
+ }
+
+ void SAL_CALL GenericPropertyHandler::disposing()
+ {
+ m_aPropertyListeners.clear();
+ // not disposeAndClear: the listeners are (virtually) listeners at our introspectee, not
+ // at this handler instance
+ }
+
+ IMPLEMENT_FORWARD_XCOMPONENT( GenericPropertyHandler, GenericPropertyHandler_Base );
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_GenericPropertyHandler_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::GenericPropertyHandler(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/genericpropertyhandler.hxx b/extensions/source/propctrlr/genericpropertyhandler.hxx
new file mode 100644
index 000000000..b2114be3c
--- /dev/null
+++ b/extensions/source/propctrlr/genericpropertyhandler.hxx
@@ -0,0 +1,139 @@
+/* -*- 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 "pcrcommontypes.hxx"
+#include "pcrcommon.hxx"
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/XIntrospectionAccess.hpp>
+#include <com/sun/star/inspection/XPropertyHandler.hpp>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <comphelper/interfacecontainer2.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <rtl/ref.hxx>
+
+#include <map>
+
+
+namespace pcr
+{
+
+
+ struct TypeLess
+ {
+ bool operator()( const css::uno::Type& _rLHS, const css::uno::Type& _rRHS ) const
+ {
+ return _rLHS.getTypeName() < _rRHS.getTypeName();
+ }
+ };
+
+ class IPropertyEnumRepresentation;
+
+ //= GenericPropertyHandler
+
+ typedef ::cppu::WeakComponentImplHelper < css::inspection::XPropertyHandler
+ , css::lang::XServiceInfo
+ > GenericPropertyHandler_Base;
+ class GenericPropertyHandler final : public GenericPropertyHandler_Base
+ {
+ mutable ::osl::Mutex m_aMutex;
+
+ /// the service factory for creating services
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ /// need this to keep alive as long as m_xComponent lives
+ css::uno::Reference< css::beans::XIntrospectionAccess > m_xComponentIntrospectionAccess;
+ /// the properties of the object we're handling
+ css::uno::Reference< css::beans::XPropertySet > m_xComponent;
+ /// cached interface of ->m_xComponent
+ css::uno::Reference< css::beans::XPropertyState > m_xPropertyState;
+ /// type converter, needed on various occasions
+ css::uno::Reference< css::script::XTypeConverter > m_xTypeConverter;
+ /// cache of our supported properties
+ PropertyMap m_aProperties;
+ /// property change listeners
+ ::comphelper::OInterfaceContainerHelper2 m_aPropertyListeners;
+ std::map< css::uno::Type, ::rtl::Reference< IPropertyEnumRepresentation >, TypeLess >
+ m_aEnumConverters;
+
+ /// has ->m_aProperties been initialized?
+ bool m_bPropertyMapInitialized : 1;
+
+ public:
+ explicit GenericPropertyHandler(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext
+ );
+
+ virtual ~GenericPropertyHandler() override;
+
+ private:
+ // XPropertyHandler overridables
+ virtual void SAL_CALL inspect( const css::uno::Reference< css::uno::XInterface >& _rxIntrospectee ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override;
+ virtual css::uno::Any SAL_CALL convertToPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rControlValue ) override;
+ virtual css::uno::Any SAL_CALL convertToControlValue( const OUString& _rPropertyName, const css::uno::Any& _rPropertyValue, const css::uno::Type& _rControlValueType ) override;
+ virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+ virtual css::uno::Sequence< css::beans::Property >
+ SAL_CALL getSupportedProperties() override;
+ virtual css::uno::Sequence< OUString >
+ SAL_CALL getSupersededProperties() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getActuatingProperties() override;
+ virtual css::inspection::LineDescriptor SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override;
+ virtual sal_Bool SAL_CALL isComposable( const OUString& _rPropertyName ) override;
+ virtual css::inspection::InteractiveSelectionResult
+ SAL_CALL onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, css::uno::Any& _rData, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) override;
+ virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override;
+ virtual sal_Bool SAL_CALL suspend( sal_Bool _bSuspend ) override;
+
+ // XComponent
+ DECLARE_XCOMPONENT()
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ /** ensures that ->m_aProperties is initialized
+ @precond
+ our mutex is locked
+ */
+ void impl_ensurePropertyMap();
+
+ /** retrieves the enum converter for the given ENUM type
+ */
+ ::rtl::Reference< IPropertyEnumRepresentation >
+ impl_getEnumConverter( const css::uno::Type& _rEnumType );
+
+ GenericPropertyHandler( const GenericPropertyHandler& ) = delete;
+ GenericPropertyHandler& operator=( const GenericPropertyHandler& ) = delete;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/handlerhelper.cxx b/extensions/source/propctrlr/handlerhelper.cxx
new file mode 100644
index 000000000..89f149b92
--- /dev/null
+++ b/extensions/source/propctrlr/handlerhelper.cxx
@@ -0,0 +1,314 @@
+/* -*- 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 "handlerhelper.hxx"
+#include <yesno.hrc>
+#include "modulepcr.hxx"
+
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/inspection/StringRepresentation.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/inspection/LineDescriptor.hpp>
+#include <com/sun/star/inspection/PropertyControlType.hpp>
+#include <com/sun/star/inspection/XStringListControl.hpp>
+#include <com/sun/star/inspection/XNumericControl.hpp>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/weldutils.hxx>
+
+#include <algorithm>
+
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::inspection;
+
+
+ //= PropertyHandlerHelper
+
+
+ void PropertyHandlerHelper::describePropertyLine( const Property& _rProperty,
+ LineDescriptor& /* [out] */ _out_rDescriptor, const Reference< XPropertyControlFactory >& _rxControlFactory )
+ {
+ // display the pure property name - no L10N
+ _out_rDescriptor.DisplayName = _rProperty.Name;
+
+ OSL_PRECOND( _rxControlFactory.is(), "PropertyHandlerHelper::describePropertyLine: no factory -> no control!" );
+ if ( !_rxControlFactory.is() )
+ return;
+
+ bool bReadOnlyControl = requiresReadOnlyControl( _rProperty.Attributes );
+
+ // special handling for booleans (this will become a list)
+ if ( _rProperty.Type.getTypeClass() == TypeClass_BOOLEAN )
+ {
+ _out_rDescriptor.Control = createListBoxControl(_rxControlFactory, RID_RSC_ENUM_YESNO, SAL_N_ELEMENTS(RID_RSC_ENUM_YESNO), bReadOnlyControl);
+ return;
+ }
+
+ sal_Int16 nControlType = PropertyControlType::TextField;
+ switch ( _rProperty.Type.getTypeClass() )
+ {
+ case TypeClass_BYTE:
+ case TypeClass_SHORT:
+ case TypeClass_UNSIGNED_SHORT:
+ case TypeClass_LONG:
+ case TypeClass_UNSIGNED_LONG:
+ case TypeClass_HYPER:
+ case TypeClass_UNSIGNED_HYPER:
+ case TypeClass_FLOAT:
+ case TypeClass_DOUBLE:
+ nControlType = PropertyControlType::NumericField;
+ break;
+
+ case TypeClass_SEQUENCE:
+ nControlType = PropertyControlType::StringListField;
+ break;
+
+ default:
+ OSL_FAIL( "PropertyHandlerHelper::describePropertyLine: don't know how to represent this at the UI!" );
+ [[fallthrough]];
+
+ case TypeClass_STRING:
+ nControlType = PropertyControlType::TextField;
+ break;
+ }
+
+ // create a control
+ _out_rDescriptor.Control = _rxControlFactory->createPropertyControl( nControlType, bReadOnlyControl );
+ }
+
+
+ namespace
+ {
+ Reference< XPropertyControl > lcl_implCreateListLikeControl(
+ const Reference< XPropertyControlFactory >& _rxControlFactory,
+ std::vector< OUString >&& _rInitialListEntries,
+ bool _bReadOnlyControl,
+ bool _bSorted,
+ bool _bTrueIfListBoxFalseIfComboBox
+ )
+ {
+ Reference< XStringListControl > xListControl(
+ _rxControlFactory->createPropertyControl(
+ _bTrueIfListBoxFalseIfComboBox ? PropertyControlType::ListBox : PropertyControlType::ComboBox, _bReadOnlyControl
+ ),
+ UNO_QUERY_THROW
+ );
+
+ if ( _bSorted )
+ std::sort( _rInitialListEntries.begin(), _rInitialListEntries.end() );
+
+ for (auto const& initialEntry : _rInitialListEntries)
+ xListControl->appendListEntry(initialEntry);
+ return xListControl;
+ }
+ }
+
+ Reference< XPropertyControl > PropertyHandlerHelper::createListBoxControl( const Reference< XPropertyControlFactory >& _rxControlFactory,
+ std::vector< OUString >&& _rInitialListEntries, bool _bReadOnlyControl, bool _bSorted )
+ {
+ return lcl_implCreateListLikeControl(_rxControlFactory, std::move(_rInitialListEntries), _bReadOnlyControl, _bSorted, true);
+ }
+
+ Reference< XPropertyControl > PropertyHandlerHelper::createListBoxControl( const Reference< XPropertyControlFactory >& _rxControlFactory,
+ const TranslateId* pTransIds, size_t nElements, bool _bReadOnlyControl )
+ {
+ std::vector<OUString> aInitialListEntries;
+ for (size_t i = 0; i < nElements; ++i)
+ aInitialListEntries.push_back(PcrRes(pTransIds[i]));
+ return lcl_implCreateListLikeControl(_rxControlFactory, std::move(aInitialListEntries), _bReadOnlyControl, /*_bSorted*/false, true);
+ }
+
+ Reference< XPropertyControl > PropertyHandlerHelper::createComboBoxControl( const Reference< XPropertyControlFactory >& _rxControlFactory,
+ std::vector< OUString >&& _rInitialListEntries, bool _bSorted )
+ {
+ return lcl_implCreateListLikeControl( _rxControlFactory, std::move(_rInitialListEntries), /*_bReadOnlyControl*/false, _bSorted, false );
+ }
+
+
+ Reference< XPropertyControl > PropertyHandlerHelper::createNumericControl( const Reference< XPropertyControlFactory >& _rxControlFactory,
+ sal_Int16 _nDigits, const Optional< double >& _rMinValue, const Optional< double >& _rMaxValue )
+ {
+ Reference< XNumericControl > xNumericControl(
+ _rxControlFactory->createPropertyControl( PropertyControlType::NumericField, /*_bReadOnlyControl*/false ),
+ UNO_QUERY_THROW
+ );
+
+ xNumericControl->setDecimalDigits( _nDigits );
+ xNumericControl->setMinValue( _rMinValue );
+ xNumericControl->setMaxValue( _rMaxValue );
+
+ return xNumericControl;
+ }
+
+
+ Any PropertyHandlerHelper::convertToPropertyValue( const Reference< XComponentContext >& _rxContext,const Reference< XTypeConverter >& _rxTypeConverter,
+ const Property& _rProperty, const Any& _rControlValue )
+ {
+ Any aPropertyValue( _rControlValue );
+ if ( !aPropertyValue.hasValue() )
+ // NULL is converted to NULL
+ return aPropertyValue;
+
+ if ( aPropertyValue.getValueType().equals( _rProperty.Type ) )
+ // nothing to do, type is already as desired
+ return aPropertyValue;
+
+ if ( _rControlValue.getValueType().getTypeClass() == TypeClass_STRING )
+ {
+ OUString sControlValue;
+ _rControlValue >>= sControlValue;
+
+ Reference< XStringRepresentation > xConversionHelper = StringRepresentation::create( _rxContext,_rxTypeConverter );
+ aPropertyValue = xConversionHelper->convertToPropertyValue( sControlValue, _rProperty.Type );
+ }
+ else
+ {
+ try
+ {
+ if ( _rxTypeConverter.is() )
+ aPropertyValue = _rxTypeConverter->convertTo( _rControlValue, _rProperty.Type );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("extensions.propctrlr",
+ "caught an exception while converting via TypeConverter!");
+ }
+ }
+
+ return aPropertyValue;
+ }
+
+
+ Any PropertyHandlerHelper::convertToControlValue( const Reference< XComponentContext >& _rxContext,const Reference< XTypeConverter >& _rxTypeConverter,
+ const Any& _rPropertyValue, const Type& _rControlValueType )
+ {
+ Any aControlValue( _rPropertyValue );
+ if ( !aControlValue.hasValue() )
+ // NULL is converted to NULL
+ return aControlValue;
+
+ if ( _rControlValueType.getTypeClass() == TypeClass_STRING )
+ {
+ Reference< XStringRepresentation > xConversionHelper = StringRepresentation::create( _rxContext,_rxTypeConverter );
+ aControlValue <<= xConversionHelper->convertToControlValue( _rPropertyValue );
+ }
+ else
+ {
+ try
+ {
+ if ( _rxTypeConverter.is() )
+ aControlValue = _rxTypeConverter->convertTo( _rPropertyValue, _rControlValueType );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("extensions.propctrlr",
+ "caught an exception while converting via TypeConverter!");
+ }
+ }
+
+ return aControlValue;
+ }
+
+
+ void PropertyHandlerHelper::setContextDocumentModified( const Reference<XComponentContext> & rContext )
+ {
+ try
+ {
+ Reference< XModifiable > xDocumentModifiable( getContextDocument_throw(rContext), UNO_QUERY_THROW );
+ xDocumentModifiable->setModified( true );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+ Reference< XInterface > PropertyHandlerHelper::getContextDocument( const Reference<XComponentContext> & rContext )
+ {
+ Reference< XInterface > xI;
+ try
+ {
+ xI = getContextDocument_throw( rContext );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "PropertyHandler::getContextValueByName" );
+ }
+ return xI;
+ }
+
+ Reference< XInterface > PropertyHandlerHelper::getContextDocument_throw( const Reference<XComponentContext> & rContext )
+ {
+ Reference< XInterface > xI;
+ Any aReturn = rContext->getValueByName( "ContextDocument" );
+ aReturn >>= xI;
+ return xI;
+ }
+
+ weld::Window* PropertyHandlerHelper::getDialogParentFrame(const Reference<XComponentContext>& rContext)
+ {
+ weld::Window* pInspectorWindow = nullptr;
+ try
+ {
+ Reference< XWindow > xInspectorWindow(rContext->getValueByName( "DialogParentWindow" ), UNO_QUERY_THROW);
+ pInspectorWindow = Application::GetFrameWeld(xInspectorWindow);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ return pInspectorWindow;
+ }
+
+ std::unique_ptr<weld::Builder> PropertyHandlerHelper::makeBuilder(const OUString& rUIFile, const Reference<XComponentContext>& rContext)
+ {
+ Reference<XWindow> xWindow(rContext->getValueByName("BuilderParent"), UNO_QUERY_THROW);
+ weld::TransportAsXWindow& rTunnel = dynamic_cast<weld::TransportAsXWindow&>(*xWindow);
+ return Application::CreateBuilder(rTunnel.getWidget(), rUIFile);
+ }
+
+ void PropertyHandlerHelper::setBuilderParent(const css::uno::Reference<css::uno::XComponentContext>& rContext, weld::Widget* pParent)
+ {
+ Reference<css::container::XNameContainer> xName(rContext, UNO_QUERY_THROW);
+ Reference<XWindow> xWindow(new weld::TransportAsXWindow(pParent));
+ xName->insertByName("BuilderParent", Any(xWindow));
+ }
+
+ void PropertyHandlerHelper::clearBuilderParent(const css::uno::Reference<css::uno::XComponentContext>& rContext)
+ {
+ Reference<css::container::XNameContainer> xName(rContext, UNO_QUERY_THROW);
+ xName->removeByName("BuilderParent");
+ }
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/handlerhelper.hxx b/extensions/source/propctrlr/handlerhelper.hxx
new file mode 100644
index 000000000..555b8ee82
--- /dev/null
+++ b/extensions/source/propctrlr/handlerhelper.hxx
@@ -0,0 +1,231 @@
+/* -*- 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/beans/Property.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <com/sun/star/inspection/XPropertyControlFactory.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/Optional.hpp>
+#include <unotools/resmgr.hxx>
+
+#include <memory>
+#include <vector>
+
+namespace weld { class Builder; class Widget; class Window; }
+namespace com::sun::star {
+ namespace inspection {
+ struct LineDescriptor;
+ }
+}
+
+namespace pcr
+{
+
+
+ //= PropertyHandlerHelper
+
+ class PropertyHandlerHelper
+ {
+ public:
+ /** helper for implementing XPropertyHandler::describePropertyLine in a generic way
+ */
+ static void describePropertyLine(
+ const css::beans::Property& _rProperty,
+ css::inspection::LineDescriptor& /* [out] */ _out_rDescriptor,
+ const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory
+ );
+
+ /** helper for implementing XPropertyHandler::convertToPropertyValue
+ */
+ static css::uno::Any convertToPropertyValue(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ const css::uno::Reference< css::script::XTypeConverter >& _rxTypeConverter,
+ const css::beans::Property& _rProperty,
+ const css::uno::Any& _rControlValue
+ );
+
+ /// helper for implementing XPropertyHandler::convertToControlValue
+ static css::uno::Any convertToControlValue(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ const css::uno::Reference< css::script::XTypeConverter >& _rxTypeConverter,
+ const css::uno::Any& _rPropertyValue,
+ const css::uno::Type& _rControlValueType
+ );
+
+ /** creates an <member scope="css::inspection">PropertyControlType::ListBox</member>-type control
+ and fills it with initial values
+
+ @param _rxControlFactory
+ A control factory. Must not be <NULL/>.
+
+ @param _rInitialListEntries
+ the initial values of the control
+
+ @param _bReadOnlyControl
+ determines whether the control should be read-only
+
+ @param _bSorted
+ determines whether the list entries should be sorted
+
+ @return
+ the newly created control
+ */
+ static css::uno::Reference< css::inspection::XPropertyControl >
+ createListBoxControl(
+ const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory,
+ std::vector< OUString >&& _rInitialListEntries,
+ bool _bReadOnlyControl,
+ bool _bSorted
+ );
+
+ /** creates an <member scope="css::inspection">PropertyControlType::ListBox</member>-type control
+ and fills it with initial values.
+
+ @param _rxControlFactory
+ A control factory. Must not be <NULL/>.
+
+ @param pTransIds
+ the initial translation ids for the value of the control
+
+ @param nElements
+ the count of initial values of the control
+
+ @param _bReadOnlyControl
+ determines whether the control should be read-only
+
+ @return
+ the newly created control
+ */
+ static css::uno::Reference< css::inspection::XPropertyControl >
+ createListBoxControl(
+ const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory,
+ const TranslateId* pTransIds, size_t nElements,
+ bool _bReadOnlyControl
+ );
+
+ /** creates an <member scope="css::inspection">PropertyControlType::ComboBox</member>-type control
+ and fills it with initial values
+
+ @param _rxControlFactory
+ A control factory. Must not be <NULL/>.
+
+ @param _rInitialListEntries
+ the initial values of the control
+
+ @param _bSorted
+ determines whether the list entries should be sorted
+
+ @return
+ the newly created control
+ */
+ static css::uno::Reference< css::inspection::XPropertyControl >
+ createComboBoxControl(
+ const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory,
+ std::vector< OUString >&& _rInitialListEntries,
+ bool _bSorted
+ );
+
+ /** creates an <member scope="css::inspection">PropertyControlType::NumericField</member>-type control
+ and initializes it
+
+ @param _rxControlFactory
+ A control factory. Must not be <NULL/>.
+ @param _nDigits
+ number of decimal digits for the control
+ (<member scope="css::inspection">XNumericControl::DecimalDigits</member>)
+ @param _rMinValue
+ minimum value which can be entered in the control
+ (<member scope="css::inspection">XNumericControl::MinValue</member>)
+ @param _rMaxValue
+ maximum value which can be entered in the control
+ (<member scope="css::inspection">XNumericControl::MaxValue</member>)
+
+ @return
+ the newly created control
+ */
+ static css::uno::Reference< css::inspection::XPropertyControl >
+ createNumericControl(
+ const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory,
+ sal_Int16 _nDigits,
+ const css::beans::Optional< double >& _rMinValue,
+ const css::beans::Optional< double >& _rMaxValue
+ );
+
+ /** marks the document passed in our UNO context as modified
+
+ The method looks up a value called "ContextDocument" in the given UNO component context,
+ queries it for the ->css::util::XModifiable interface, and calls its
+ setModified method. If either of those steps fails, this is asserted in a non-product
+ version, and silently ignore otherwise.
+
+ @param _rContext
+ the component context which was used to create the component calling this method
+ */
+ static void setContextDocumentModified(
+ const css::uno::Reference< css::uno::XComponentContext > & _rContext
+ );
+
+ static css::uno::Reference< css::uno::XInterface > getContextDocument( const css::uno::Reference<css::uno::XComponentContext> & _rContext );
+
+ /// @throws css::uno::RuntimeException
+ static css::uno::Reference< css::uno::XInterface > getContextDocument_throw( const css::uno::Reference<css::uno::XComponentContext> & _rContext );
+
+ /** gets the window of the ObjectInspector in which a property handler lives
+
+ The method looks up a value called "DialogParentWindow" in the given UNO component context,
+ queries it for XWindow, and returns the respective weld::Window*. If either of those steps fails,
+ this is asserted in a non-product version, and silently ignore otherwise.
+
+ @param _rContext
+ the component context which was used to create the component calling this method
+ */
+ static weld::Window* getDialogParentFrame( const css::uno::Reference< css::uno::XComponentContext > & _rContext );
+
+
+ /** determines whether given PropertyAttributes require a to-be-created
+ <type scope="css::inspection">XPropertyControl</type> to be read-only
+
+ @param _nPropertyAttributes
+ the attributes of the property which should be reflected by a to-be-created
+ <type scope="css::inspection">XPropertyControl</type>
+ */
+ static bool requiresReadOnlyControl( sal_Int16 _nPropertyAttributes )
+ {
+ return ( _nPropertyAttributes & css::beans::PropertyAttribute::READONLY ) != 0;
+ }
+
+ static std::unique_ptr<weld::Builder> makeBuilder(const OUString& rUIFile, const css::uno::Reference<css::uno::XComponentContext>& rContext);
+
+ static void setBuilderParent(const css::uno::Reference<css::uno::XComponentContext>& rContext, weld::Widget* pParent);
+
+ static void clearBuilderParent(const css::uno::Reference<css::uno::XComponentContext>& rContext);
+
+ private:
+ PropertyHandlerHelper( const PropertyHandlerHelper& ) = delete;
+ PropertyHandlerHelper& operator=( const PropertyHandlerHelper& ) = delete;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/inspectorhelpwindow.cxx b/extensions/source/propctrlr/inspectorhelpwindow.cxx
new file mode 100644
index 000000000..a57c4ffed
--- /dev/null
+++ b/extensions/source/propctrlr/inspectorhelpwindow.cxx
@@ -0,0 +1,42 @@
+/* -*- 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 "inspectorhelpwindow.hxx"
+
+
+namespace pcr
+{
+ //= InspectorHelpWindow
+ InspectorHelpWindow::InspectorHelpWindow(weld::Builder& rBuilder)
+ : m_xHelpFrame(rBuilder.weld_widget("helpframe"))
+ , m_xHelpText(rBuilder.weld_text_view("helptext"))
+ {
+ }
+
+ InspectorHelpWindow::~InspectorHelpWindow()
+ {
+ }
+
+ void InspectorHelpWindow::SetText(const OUString& rStr)
+ {
+ m_xHelpText->set_text(rStr);
+ }
+
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/inspectorhelpwindow.hxx b/extensions/source/propctrlr/inspectorhelpwindow.hxx
new file mode 100644
index 000000000..98b8efbab
--- /dev/null
+++ b/extensions/source/propctrlr/inspectorhelpwindow.hxx
@@ -0,0 +1,44 @@
+/* -*- 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/weld.hxx>
+
+namespace pcr
+{
+ //= InspectorHelpWindow
+ class InspectorHelpWindow
+ {
+ private:
+ std::unique_ptr<weld::Widget> m_xHelpFrame;
+ std::unique_ptr<weld::TextView> m_xHelpText;
+
+ public:
+ explicit InspectorHelpWindow(weld::Builder& rBuilder);
+ ~InspectorHelpWindow();
+
+ void SetText(const OUString& rStr);
+
+ void Show(bool bShow) { m_xHelpFrame->set_visible(bShow); }
+ bool IsVisible() const { return m_xHelpFrame->get_visible(); }
+ };
+
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/inspectormodelbase.cxx b/extensions/source/propctrlr/inspectormodelbase.cxx
new file mode 100644
index 000000000..f8780ff99
--- /dev/null
+++ b/extensions/source/propctrlr/inspectormodelbase.cxx
@@ -0,0 +1,246 @@
+/* -*- 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 <memory>
+#include "inspectormodelbase.hxx"
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+#include <comphelper/propertycontainerhelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+
+namespace pcr
+{
+
+
+#define MODEL_PROPERTY_ID_HAS_HELP_SECTION 2000
+#define MODEL_PROPERTY_ID_MIN_HELP_TEXT_LINES 2001
+#define MODEL_PROPERTY_ID_MAX_HELP_TEXT_LINES 2002
+#define MODEL_PROPERTY_ID_IS_READ_ONLY 2003
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::beans::Property;
+
+ namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
+
+
+ //= InspectorModelProperties
+
+ /** helper class for implementing the property set related functionality
+ of an ImplInspectorModel
+ */
+ class InspectorModelProperties : public ::comphelper::OPropertyContainerHelper
+ {
+ private:
+ ::osl::Mutex& m_rMutex;
+ bool m_bHasHelpSection;
+ sal_Int32 m_nMinHelpTextLines;
+ sal_Int32 m_nMaxHelpTextLines;
+ bool m_bIsReadOnly;
+ std::unique_ptr< ::cppu::IPropertyArrayHelper >
+ m_pPropertyInfo;
+
+ public:
+ explicit InspectorModelProperties( ::osl::Mutex& _rMutex );
+
+ using ::comphelper::OPropertyContainerHelper::convertFastPropertyValue;
+ using ::comphelper::OPropertyContainerHelper::setFastPropertyValue;
+ using ::comphelper::OPropertyContainerHelper::getFastPropertyValue;
+
+ public:
+ bool hasHelpSection() const { return m_bHasHelpSection; }
+ bool isReadOnly() const { return m_bIsReadOnly; }
+ sal_Int32 getMinHelpTextLines() const { return m_nMinHelpTextLines; }
+ sal_Int32 getMaxHelpTextLines() const { return m_nMaxHelpTextLines; }
+
+ css::uno::Reference< css::beans::XPropertySetInfo >
+ getPropertySetInfo();
+ ::cppu::IPropertyArrayHelper&
+ getInfoHelper();
+
+ void constructWithHelpSection( sal_Int32 _nMinHelpTextLines, sal_Int32 _nMaxHelpTextLines );
+ };
+
+
+ //= InspectorModelProperties
+
+
+ InspectorModelProperties::InspectorModelProperties( ::osl::Mutex& _rMutex )
+ :m_rMutex( _rMutex )
+ ,m_bHasHelpSection( false )
+ ,m_nMinHelpTextLines( 3 )
+ ,m_nMaxHelpTextLines( 8 )
+ ,m_bIsReadOnly( false )
+ {
+ registerProperty(
+ "HasHelpSection",
+ MODEL_PROPERTY_ID_HAS_HELP_SECTION,
+ PropertyAttribute::READONLY,
+ &m_bHasHelpSection, cppu::UnoType<decltype(m_bHasHelpSection)>::get()
+ );
+ registerProperty(
+ "MinHelpTextLines",
+ MODEL_PROPERTY_ID_MIN_HELP_TEXT_LINES,
+ PropertyAttribute::READONLY,
+ &m_nMinHelpTextLines, cppu::UnoType<decltype(m_nMinHelpTextLines)>::get()
+ );
+ registerProperty(
+ "MaxHelpTextLines",
+ MODEL_PROPERTY_ID_MAX_HELP_TEXT_LINES,
+ PropertyAttribute::READONLY,
+ &m_nMaxHelpTextLines, cppu::UnoType<decltype(m_nMaxHelpTextLines)>::get()
+ );
+ registerProperty(
+ "IsReadOnly",
+ MODEL_PROPERTY_ID_IS_READ_ONLY,
+ PropertyAttribute::BOUND,
+ &m_bIsReadOnly, cppu::UnoType<decltype(m_bIsReadOnly)>::get()
+ );
+ }
+
+
+ void InspectorModelProperties::constructWithHelpSection( sal_Int32 _nMinHelpTextLines, sal_Int32 _nMaxHelpTextLines )
+ {
+ m_bHasHelpSection = true;
+ m_nMinHelpTextLines = _nMinHelpTextLines;
+ m_nMaxHelpTextLines = _nMaxHelpTextLines;
+ // no need to notify this, those properties are not bound. Also, the method should
+ // only be used during construction phase, where we don't expect to have any listeners.
+ }
+
+
+ ::cppu::IPropertyArrayHelper& InspectorModelProperties::getInfoHelper()
+ {
+ ::osl::MutexGuard aGuard( m_rMutex );
+ if (m_pPropertyInfo == nullptr)
+ {
+ Sequence< Property > aProperties;
+ describeProperties( aProperties );
+
+ m_pPropertyInfo.reset( new ::cppu::OPropertyArrayHelper( aProperties ) );
+ }
+ return *m_pPropertyInfo;
+ }
+
+
+ Reference< XPropertySetInfo > InspectorModelProperties::getPropertySetInfo()
+ {
+ return ::cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() );
+ }
+
+
+ //= ImplInspectorModel
+
+ ImplInspectorModel::ImplInspectorModel()
+ :ImplInspectorModel_PBase( GetBroadcastHelper() )
+ ,m_pProperties( new InspectorModelProperties( m_aMutex ) )
+ {
+ }
+
+
+ ImplInspectorModel::~ImplInspectorModel()
+ {
+ }
+
+
+ IMPLEMENT_FORWARD_XINTERFACE2( ImplInspectorModel, ImplInspectorModel_Base, ImplInspectorModel_PBase )
+
+
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2( ImplInspectorModel, ImplInspectorModel_Base, ImplInspectorModel_PBase )
+
+
+ Reference< XPropertySetInfo > SAL_CALL ImplInspectorModel::getPropertySetInfo( )
+ {
+ return m_pProperties->getPropertySetInfo();
+ }
+
+
+ ::cppu::IPropertyArrayHelper& SAL_CALL ImplInspectorModel::getInfoHelper()
+ {
+ return m_pProperties->getInfoHelper();
+ }
+
+
+ sal_Bool SAL_CALL ImplInspectorModel::convertFastPropertyValue( Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
+ {
+ return m_pProperties->convertFastPropertyValue( rConvertedValue, rOldValue, nHandle, rValue );
+ }
+
+
+ void SAL_CALL ImplInspectorModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
+ {
+ m_pProperties->setFastPropertyValue( nHandle, rValue );
+ }
+
+
+ void SAL_CALL ImplInspectorModel::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+ {
+ m_pProperties->getFastPropertyValue( rValue, nHandle );
+ }
+
+
+ sal_Bool SAL_CALL ImplInspectorModel::getHasHelpSection()
+ {
+ return m_pProperties->hasHelpSection();
+ }
+
+
+ ::sal_Int32 SAL_CALL ImplInspectorModel::getMinHelpTextLines()
+ {
+ return m_pProperties->getMinHelpTextLines();
+ }
+
+
+ ::sal_Int32 SAL_CALL ImplInspectorModel::getMaxHelpTextLines()
+ {
+ return m_pProperties->getMaxHelpTextLines();
+ }
+
+
+ sal_Bool SAL_CALL ImplInspectorModel::getIsReadOnly()
+ {
+ return m_pProperties->isReadOnly();
+ }
+
+
+ void SAL_CALL ImplInspectorModel::setIsReadOnly( sal_Bool IsReadOnly )
+ {
+ setFastPropertyValue( MODEL_PROPERTY_ID_IS_READ_ONLY, Any( IsReadOnly ) );
+ }
+
+ sal_Bool SAL_CALL ImplInspectorModel::supportsService( const OUString& ServiceName )
+ {
+ return cppu::supportsService(this, ServiceName);
+ }
+
+
+ void ImplInspectorModel::enableHelpSectionProperties( sal_Int32 _nMinHelpTextLines, sal_Int32 _nMaxHelpTextLines )
+ {
+ m_pProperties->constructWithHelpSection( _nMinHelpTextLines, _nMaxHelpTextLines );
+ }
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/inspectormodelbase.hxx b/extensions/source/propctrlr/inspectormodelbase.hxx
new file mode 100644
index 000000000..527668b2f
--- /dev/null
+++ b/extensions/source/propctrlr/inspectormodelbase.hxx
@@ -0,0 +1,93 @@
+/* -*- 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/inspection/XObjectInspectorModel.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/propshlp.hxx>
+
+#include <comphelper/broadcasthelper.hxx>
+#include <comphelper/uno3.hxx>
+
+#include <memory>
+
+
+namespace pcr
+{
+
+
+ class InspectorModelProperties;
+
+ //= ImplInspectorModel
+
+ typedef ::cppu::WeakImplHelper < css::inspection::XObjectInspectorModel
+ , css::lang::XInitialization
+ , css::lang::XServiceInfo
+ > ImplInspectorModel_Base;
+ typedef ::cppu::OPropertySetHelper ImplInspectorModel_PBase;
+
+ class ImplInspectorModel
+ :public ::comphelper::OMutexAndBroadcastHelper
+ ,public ImplInspectorModel_Base
+ ,public ImplInspectorModel_PBase
+ {
+ std::unique_ptr< InspectorModelProperties > m_pProperties;
+
+ protected:
+ virtual ~ImplInspectorModel() override;
+
+ public:
+ ImplInspectorModel();
+
+ DECLARE_XINTERFACE()
+ DECLARE_XTYPEPROVIDER()
+
+ // css::beans::XPropertySet and friends
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ virtual sal_Bool SAL_CALL convertFastPropertyValue( css::uno::Any & rConvertedValue, css::uno::Any & rOldValue, sal_Int32 nHandle, const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+
+ // css::inspection::XObjectInspectorModel
+ virtual sal_Bool SAL_CALL getHasHelpSection() override;
+ virtual ::sal_Int32 SAL_CALL getMinHelpTextLines() override;
+ virtual ::sal_Int32 SAL_CALL getMaxHelpTextLines() override;
+ virtual sal_Bool SAL_CALL getIsReadOnly() override;
+ virtual void SAL_CALL setIsReadOnly( sal_Bool IsReadOnly ) override;
+
+ // css::lang::XServiceInfo
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+
+ protected:
+ void enableHelpSectionProperties( sal_Int32 _nMinHelpTextLines, sal_Int32 _nMaxHelpTextLines );
+
+ private:
+ using ImplInspectorModel_PBase::getFastPropertyValue;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/linedescriptor.hxx b/extensions/source/propctrlr/linedescriptor.hxx
new file mode 100644
index 000000000..a73eda7cf
--- /dev/null
+++ b/extensions/source/propctrlr/linedescriptor.hxx
@@ -0,0 +1,51 @@
+/* -*- 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/inspection/LineDescriptor.hpp>
+#include <com/sun/star/inspection/XPropertyHandler.hpp>
+
+namespace pcr
+{
+ //= OLineDescriptor
+ struct OLineDescriptor : public css::inspection::LineDescriptor
+ {
+ OUString sName; // the name of the property
+ css::uno::Reference< css::inspection::XPropertyHandler >
+ xPropertyHandler; // the handler for this property
+ css::uno::Any aValue; // the current value of the property
+
+ bool bUnknownValue : 1; // is the property value currently "unknown"? (PropertyState_AMBIGUOUS)
+ bool bReadOnly : 1;
+
+ OLineDescriptor()
+ :bUnknownValue( false )
+ ,bReadOnly( false )
+ {
+ }
+
+ void assignFrom( const css::inspection::LineDescriptor& _rhs )
+ {
+ css::inspection::LineDescriptor::operator=( _rhs );
+ }
+ };
+
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/listselectiondlg.cxx b/extensions/source/propctrlr/listselectiondlg.cxx
new file mode 100644
index 000000000..18ab1d778
--- /dev/null
+++ b/extensions/source/propctrlr/listselectiondlg.cxx
@@ -0,0 +1,138 @@
+/* -*- 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 "listselectiondlg.hxx"
+
+#include "formstrings.hxx"
+#include <comphelper/sequence.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace pcr
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+
+ ListSelectionDialog::ListSelectionDialog(weld::Window* pParent, const Reference< XPropertySet >& _rxListBox,
+ const OUString& _rPropertyName, const OUString& _rPropertyUIName)
+ : GenericDialogController(pParent, "modules/spropctrlr/ui/listselectdialog.ui", "ListSelectDialog")
+ , m_xListBox ( _rxListBox )
+ , m_sPropertyName( _rPropertyName )
+ , m_xFrame(m_xBuilder->weld_frame("frame"))
+ , m_xEntries(m_xBuilder->weld_tree_view("treeview"))
+ {
+ OSL_PRECOND( m_xListBox.is(), "ListSelectionDialog::ListSelectionDialog: invalid list box!" );
+
+ m_xEntries->set_size_request(m_xEntries->get_approximate_digit_width() * 40, m_xEntries->get_height_rows(9));
+
+ m_xDialog->set_title(_rPropertyUIName);
+ m_xFrame->set_label(_rPropertyUIName);
+
+ initialize( );
+ }
+
+ ListSelectionDialog::~ListSelectionDialog()
+ {
+ }
+
+ short ListSelectionDialog::run()
+ {
+ short nResult = GenericDialogController::run();
+
+ if ( RET_OK == nResult )
+ commitSelection();
+
+ return nResult;
+ }
+
+
+ void ListSelectionDialog::initialize( )
+ {
+ if ( !m_xListBox.is() )
+ return;
+
+ try
+ {
+ // initialize the multi-selection flag
+ bool bMultiSelection = false;
+ OSL_VERIFY( m_xListBox->getPropertyValue( PROPERTY_MULTISELECTION ) >>= bMultiSelection );
+ m_xEntries->set_selection_mode(bMultiSelection ? SelectionMode::Single : SelectionMode::Multiple);
+
+ // fill the list box with all entries
+ Sequence< OUString > aListEntries;
+ OSL_VERIFY( m_xListBox->getPropertyValue( PROPERTY_STRINGITEMLIST ) >>= aListEntries );
+ fillEntryList( aListEntries );
+
+ // select entries according to the property
+ Sequence< sal_Int16 > aSelection;
+ OSL_VERIFY( m_xListBox->getPropertyValue( m_sPropertyName ) >>= aSelection );
+ selectEntries( aSelection );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "ListSelectionDialog::initialize" );
+ }
+ }
+
+ void ListSelectionDialog::commitSelection()
+ {
+ if ( !m_xListBox.is() )
+ return;
+
+ std::vector< sal_Int16 > aSelection;
+ collectSelection( aSelection );
+
+ try
+ {
+ m_xListBox->setPropertyValue( m_sPropertyName, Any( comphelper::containerToSequence(aSelection) ) );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "ListSelectionDialog::commitSelection" );
+ }
+ }
+
+ void ListSelectionDialog::fillEntryList( const Sequence< OUString >& _rListEntries )
+ {
+ m_xEntries->freeze();
+ m_xEntries->clear();
+ for (auto const & entry : _rListEntries)
+ m_xEntries->append_text(entry);
+ m_xEntries->thaw();
+ }
+
+ void ListSelectionDialog::collectSelection( std::vector< sal_Int16 >& /* [out] */ _rSelection )
+ {
+ auto aSelection = m_xEntries->get_selected_rows();
+ _rSelection.resize(aSelection.size());
+ for (auto row : aSelection)
+ _rSelection.push_back(row);
+ }
+
+ void ListSelectionDialog::selectEntries( const Sequence< sal_Int16 >& /* [in ] */ _rSelection )
+ {
+ m_xEntries->unselect_all();
+ for (auto const & selection : _rSelection)
+ m_xEntries->select(selection);
+ }
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/listselectiondlg.hxx b/extensions/source/propctrlr/listselectiondlg.hxx
new file mode 100644
index 000000000..51469c091
--- /dev/null
+++ b/extensions/source/propctrlr/listselectiondlg.hxx
@@ -0,0 +1,60 @@
+/* -*- 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/weld.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+namespace pcr
+{
+ class ListSelectionDialog : public weld::GenericDialogController
+ {
+ private:
+ css::uno::Reference<css::beans::XPropertySet> m_xListBox;
+ OUString m_sPropertyName;
+ std::unique_ptr<weld::Frame> m_xFrame;
+ std::unique_ptr<weld::TreeView> m_xEntries;
+
+ public:
+ ListSelectionDialog(
+ weld::Window* _pParent,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxListBox,
+ const OUString& _rPropertyName,
+ const OUString& _rPropertyUIName
+ );
+ virtual ~ListSelectionDialog() override;
+
+ virtual short run() override;
+
+ private:
+ void initialize( );
+ void commitSelection();
+
+ void fillEntryList ( const css::uno::Sequence< OUString >& _rListEntries );
+
+ void selectEntries ( const css::uno::Sequence< sal_Int16 >& /* [in ] */ _rSelection );
+ void collectSelection( std::vector< sal_Int16 >& /* [out] */ _rSelection );
+ };
+
+} // namespacepcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/modulepcr.cxx b/extensions/source/propctrlr/modulepcr.cxx
new file mode 100644
index 000000000..da8336e10
--- /dev/null
+++ b/extensions/source/propctrlr/modulepcr.cxx
@@ -0,0 +1,30 @@
+/* -*- 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 "modulepcr.hxx"
+
+#include <unotools/resmgr.hxx>
+
+namespace pcr
+{
+OUString PcrRes(TranslateId aId) { return Translate::get(aId, Translate::Create("pcr")); }
+
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/modulepcr.hxx b/extensions/source/propctrlr/modulepcr.hxx
new file mode 100644
index 000000000..d0b854893
--- /dev/null
+++ b/extensions/source/propctrlr/modulepcr.hxx
@@ -0,0 +1,30 @@
+/* -*- 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 <rtl/ustring.hxx>
+#include <unotools/resmgr.hxx>
+
+namespace pcr
+{
+OUString PcrRes(TranslateId pId);
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/newdatatype.cxx b/extensions/source/propctrlr/newdatatype.cxx
new file mode 100644
index 000000000..09c774d3a
--- /dev/null
+++ b/extensions/source/propctrlr/newdatatype.cxx
@@ -0,0 +1,79 @@
+/* -*- 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 "newdatatype.hxx"
+
+namespace pcr
+{
+
+
+ //= NewDataTypeDialog
+
+
+ NewDataTypeDialog::NewDataTypeDialog(weld::Window* pParent, const OUString& _rNameBase, const std::vector< OUString >& _rProhibitedNames)
+ : GenericDialogController(pParent, "modules/spropctrlr/ui/datatypedialog.ui", "DataTypeDialog")
+ , m_aProhibitedNames( _rProhibitedNames.begin(), _rProhibitedNames.end() )
+ , m_xName(m_xBuilder->weld_entry("entry"))
+ , m_xOK(m_xBuilder->weld_button("ok"))
+ {
+ m_xName->connect_changed(LINK(this, NewDataTypeDialog, OnNameModified));
+
+ // find an initial name
+ // for this, first remove trailing digits
+ sal_Int32 nStripUntil = _rNameBase.getLength();
+ while ( nStripUntil > 0 )
+ {
+ sal_Unicode nChar = _rNameBase[ --nStripUntil ];
+ if ( ( nChar < '0' ) || ( nChar > '9' ) )
+ {
+ if ( nChar == ' ' )
+ --nStripUntil; // strip the space, too
+ break;
+ }
+ }
+
+ OUString sNameBase = OUString::Concat(_rNameBase.subView( 0, nStripUntil ? nStripUntil + 1 : 0 )) + " ";
+ OUString sInitialName;
+ sal_Int32 nPostfixNumber = 1;
+ do
+ {
+ sInitialName = sNameBase + OUString::number(nPostfixNumber++);
+ }
+ while ( m_aProhibitedNames.find( sInitialName ) != m_aProhibitedNames.end() );
+
+ m_xName->set_text(sInitialName);
+ OnNameModified(*m_xName);
+ }
+
+ NewDataTypeDialog::~NewDataTypeDialog()
+ {
+ }
+
+ IMPL_LINK_NOARG(NewDataTypeDialog, OnNameModified, weld::Entry&, void)
+ {
+ OUString sCurrentName = GetName();
+ bool bNameIsOK = ( !sCurrentName.isEmpty() )
+ && ( m_aProhibitedNames.find( sCurrentName ) == m_aProhibitedNames.end() );
+
+ m_xOK->set_sensitive(bNameIsOK);
+ }
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/newdatatype.hxx b/extensions/source/propctrlr/newdatatype.hxx
new file mode 100644
index 000000000..e6d46f1af
--- /dev/null
+++ b/extensions/source/propctrlr/newdatatype.hxx
@@ -0,0 +1,53 @@
+/* -*- 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/weld.hxx>
+
+#include <set>
+#include <vector>
+
+
+namespace pcr
+{
+ //= NewDataTypeDialog
+ class NewDataTypeDialog : public weld::GenericDialogController
+ {
+ private:
+ std::set<OUString> m_aProhibitedNames;
+
+ std::unique_ptr<weld::Entry> m_xName;
+ std::unique_ptr<weld::Button> m_xOK;
+ public:
+ NewDataTypeDialog(weld::Window* _pParent, const OUString& _rNameBase,
+ const std::vector< OUString >& _rProhibitedNames );
+ virtual ~NewDataTypeDialog() override;
+
+ OUString GetName() const { return m_xName->get_text(); }
+
+ private:
+ DECL_LINK(OnNameModified, weld::Entry&, void);
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/objectinspectormodel.cxx b/extensions/source/propctrlr/objectinspectormodel.cxx
new file mode 100644
index 000000000..adad6e66f
--- /dev/null
+++ b/extensions/source/propctrlr/objectinspectormodel.cxx
@@ -0,0 +1,194 @@
+/* -*- 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 "pcrcommon.hxx"
+#include "inspectormodelbase.hxx"
+
+#include <com/sun/star/ucb/AlreadyInitializedException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+
+namespace pcr
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::inspection::PropertyCategoryDescriptor;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::ucb::AlreadyInitializedException;
+
+
+ //= ObjectInspectorModel
+
+ namespace {
+
+ class ObjectInspectorModel : public ImplInspectorModel
+ {
+ private:
+ Sequence< Any > m_aFactories;
+
+ public:
+ ObjectInspectorModel();
+
+ // XObjectInspectorModel
+ virtual Sequence< Any > SAL_CALL getHandlerFactories() override;
+ virtual Sequence< PropertyCategoryDescriptor > SAL_CALL describeCategories( ) override;
+ virtual ::sal_Int32 SAL_CALL getPropertyOrderIndex( const OUString& PropertyName ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ protected:
+ void createDefault();
+ void createWithHandlerFactories( const Sequence< Any >& _rFactories );
+ void createWithHandlerFactoriesAndHelpSection( const Sequence< Any >& _rFactories, sal_Int32 _nMinHelpTextLines, sal_Int32 _nMaxHelpTextLines );
+
+ private:
+ /** checks a given condition to be <TRUE/>, and throws an IllegalArgumentException if not
+ */
+ void impl_verifyArgument_throw( bool _bCondition, sal_Int16 _nArgumentPosition );
+ };
+
+ }
+
+ //= ObjectInspectorModel
+
+ ObjectInspectorModel::ObjectInspectorModel()
+ {
+ }
+
+
+ Sequence< Any > SAL_CALL ObjectInspectorModel::getHandlerFactories()
+ {
+ return m_aFactories;
+ }
+
+
+ Sequence< PropertyCategoryDescriptor > SAL_CALL ObjectInspectorModel::describeCategories( )
+ {
+ // no category info provided by this default implementation
+ return Sequence< PropertyCategoryDescriptor >( );
+ }
+
+
+ ::sal_Int32 SAL_CALL ObjectInspectorModel::getPropertyOrderIndex( const OUString& /*PropertyName*/ )
+ {
+ // no ordering provided by this default implementation
+ return 0;
+ }
+
+
+ void SAL_CALL ObjectInspectorModel::initialize( const Sequence< Any >& _arguments )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_aFactories.hasElements() )
+ throw AlreadyInitializedException();
+
+ StlSyntaxSequence< Any > arguments( _arguments );
+ if ( arguments.empty() )
+ { // constructor: "createDefault()"
+ createDefault();
+ return;
+ }
+
+ Sequence< Any > factories;
+ impl_verifyArgument_throw( arguments[0] >>= factories, 1 );
+
+ if ( arguments.size() == 1 )
+ { // constructor: "createWithHandlerFactories( any[] )"
+ createWithHandlerFactories( factories );
+ return;
+ }
+
+ if ( arguments.size() == 3 )
+ { // constructor: "createWithHandlerFactoriesAndHelpSection( any[], long, long )"
+ sal_Int32 nMinHelpTextLines( 0 ), nMaxHelpTextLines( 0 );
+ impl_verifyArgument_throw( arguments[1] >>= nMinHelpTextLines, 2 );
+ impl_verifyArgument_throw( arguments[2] >>= nMaxHelpTextLines, 3 );
+ createWithHandlerFactoriesAndHelpSection( factories, nMinHelpTextLines, nMaxHelpTextLines );
+ return;
+ }
+
+ impl_verifyArgument_throw( false, 2 );
+ }
+
+
+ OUString SAL_CALL ObjectInspectorModel::getImplementationName( )
+ {
+ return "org.openoffice.comp.extensions.ObjectInspectorModel";
+ }
+
+
+ Sequence< OUString > SAL_CALL ObjectInspectorModel::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.inspection.ObjectInspectorModel" };
+ }
+
+
+ void ObjectInspectorModel::createDefault()
+ {
+ m_aFactories = { Any(OUString( "com.sun.star.inspection.GenericPropertyHandler" )) };
+ }
+
+
+ void ObjectInspectorModel::createWithHandlerFactories( const Sequence< Any >& _rFactories )
+ {
+ impl_verifyArgument_throw( _rFactories.hasElements(), 1 );
+ m_aFactories = _rFactories;
+ }
+
+
+ void ObjectInspectorModel::createWithHandlerFactoriesAndHelpSection( const Sequence< Any >& _rFactories, sal_Int32 _nMinHelpTextLines, sal_Int32 _nMaxHelpTextLines )
+ {
+ impl_verifyArgument_throw( _rFactories.hasElements(), 1 );
+ impl_verifyArgument_throw( _nMinHelpTextLines >= 1, 2 );
+ impl_verifyArgument_throw( _nMaxHelpTextLines >= 1, 3 );
+ impl_verifyArgument_throw( _nMinHelpTextLines <= _nMaxHelpTextLines, 2 );
+
+ m_aFactories = _rFactories;
+ enableHelpSectionProperties( _nMinHelpTextLines, _nMaxHelpTextLines );
+ }
+
+
+ void ObjectInspectorModel::impl_verifyArgument_throw( bool _bCondition, sal_Int16 _nArgumentPosition )
+ {
+ if ( !_bCondition )
+ throw IllegalArgumentException( OUString(), *this, _nArgumentPosition );
+ }
+
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_ObjectInspectorModel_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::ObjectInspectorModel());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/pcr.component b/extensions/source/propctrlr/pcr.component
new file mode 100644
index 000000000..3d0214ded
--- /dev/null
+++ b/extensions/source/propctrlr/pcr.component
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="StringRepresentation"
+ constructor="extensions_propctrlr_StringRepresentation_get_implementation">
+ <service name="com.sun.star.inspection.StringRepresentation"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.extensions.ButtonNavigationHandler"
+ constructor="extensions_propctrlr_ButtonNavigationHandler_get_implementation">
+ <service name="com.sun.star.form.inspection.ButtonNavigationHandler"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.extensions.CellBindingPropertyHandler"
+ constructor="extensions_propctrlr_CellBindingPropertyHandler_get_implementation">
+ <service name="com.sun.star.form.inspection.CellBindingPropertyHandler"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.extensions.EFormsPropertyHandler"
+ constructor="extensions_propctrlr_EFormsPropertyHandler_get_implementation">
+ <service name="com.sun.star.form.inspection.XMLFormsPropertyHandler"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.extensions.EditPropertyHandler"
+ constructor="extensions_propctrlr_EditPropertyHandler_get_implementation">
+ <service name="com.sun.star.form.inspection.EditPropertyHandler"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.extensions.EventHandler"
+ constructor="extensions_propctrlr_EventHandler_get_implementation">
+ <service name="com.sun.star.form.inspection.EventHandler"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.extensions.FormComponentPropertyHandler"
+ constructor="extensions_propctrlr_FormComponentPropertyHandler_get_implementation">
+ <service name="com.sun.star.form.inspection.FormComponentPropertyHandler"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.extensions.FormGeometryHandler"
+ constructor="extensions_propctrlr_FormGeometryHandler_get_implementation">
+ <service name="com.sun.star.form.inspection.FormGeometryHandler"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.extensions.GenericPropertyHandler"
+ constructor="extensions_propctrlr_GenericPropertyHandler_get_implementation">
+ <service name="com.sun.star.inspection.GenericPropertyHandler"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.extensions.SubmissionPropertyHandler"
+ constructor="extensions_propctrlr_SubmissionPropertyHandler_get_implementation">
+ <service name="com.sun.star.form.inspection.SubmissionPropertyHandler"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.extensions.XSDValidationPropertyHandler"
+ constructor="extensions_propctrlr_XSDValidationPropertyHandler_get_implementation">
+ <service name="com.sun.star.form.inspection.XSDValidationPropertyHandler"/>
+ </implementation>
+ <implementation name="org.openoffice.comp.extensions.DefaultFormComponentInspectorModel"
+ constructor="extensions_propctrlr_DefaultFormComponentInspectorModel_get_implementation">
+ <service name="com.sun.star.form.inspection.DefaultFormComponentInspectorModel"/>
+ </implementation>
+ <implementation name="org.openoffice.comp.extensions.DefaultHelpProvider"
+ constructor="extensions_propctrlr_DefaultHelpProvider_get_implementation">
+ <service name="com.sun.star.inspection.DefaultHelpProvider"/>
+ </implementation>
+ <implementation name="org.openoffice.comp.extensions.DialogController"
+ constructor="extensions_propctrlr_DialogController_get_implementation">
+ <service name="com.sun.star.awt.PropertyBrowserController"/>
+ </implementation>
+ <implementation name="org.openoffice.comp.extensions.FormController"
+ constructor="extensions_propctrlr_FormController_get_implementation">
+ <service name="com.sun.star.form.PropertyBrowserController"/>
+ </implementation>
+ <implementation name="org.openoffice.comp.extensions.ObjectInspector"
+ constructor="extensions_propctrlr_OPropertyBrowserController_get_implementation">
+ <service name="com.sun.star.inspection.ObjectInspector"/>
+ </implementation>
+ <implementation name="org.openoffice.comp.extensions.ObjectInspectorModel"
+ constructor="extensions_propctrlr_ObjectInspectorModel_get_implementation">
+ <service name="com.sun.star.inspection.ObjectInspectorModel"/>
+ </implementation>
+ <implementation name="org.openoffice.comp.form.ui.MasterDetailLinkDialog"
+ constructor="extensions_propctrlr_MasterDetailLinkDialog_get_implementation">
+ <service name="com.sun.star.form.MasterDetailLinkDialog"/>
+ </implementation>
+ <implementation name="org.openoffice.comp.form.ui.OControlFontDialog"
+ constructor="extensions_propctrlr_OControlFontDialog_get_implementation">
+ <service name="com.sun.star.form.ControlFontDialog"/>
+ </implementation>
+ <implementation name="org.openoffice.comp.form.ui.OTabOrderDialog"
+ constructor="extensions_propcrltr_OTabOrderDialog_get_implementation">
+ <service name="com.sun.star.form.ui.TabOrderDialog"/>
+ <service name="com.sun.star.form.TabOrderDialog"/>
+ </implementation>
+</component>
diff --git a/extensions/source/propctrlr/pcrcommon.cxx b/extensions/source/propctrlr/pcrcommon.cxx
new file mode 100644
index 000000000..4151e6827
--- /dev/null
+++ b/extensions/source/propctrlr/pcrcommon.cxx
@@ -0,0 +1,60 @@
+/* -*- 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 "pcrcommon.hxx"
+
+#include <com/sun/star/util/MeasureUnit.hpp>
+#include <rtl/ustrbuf.hxx>
+#include <tools/urlobj.hxx>
+
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::util;
+
+
+ //= HelpIdUrl
+
+
+ OString HelpIdUrl::getHelpId( std::u16string_view _rHelpURL )
+ {
+ INetURLObject aHID( _rHelpURL );
+ if ( aHID.GetProtocol() == INetProtocol::Hid )
+ return OUStringToOString( aHID.GetURLPath(), RTL_TEXTENCODING_UTF8 );
+ else
+ return OUStringToOString( _rHelpURL, RTL_TEXTENCODING_UTF8 );
+ }
+
+
+ OUString HelpIdUrl::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();
+ }
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/pcrcommon.hxx b/extensions/source/propctrlr/pcrcommon.hxx
new file mode 100644
index 000000000..f9ec2838c
--- /dev/null
+++ b/extensions/source/propctrlr/pcrcommon.hxx
@@ -0,0 +1,121 @@
+/* -*- 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
+
+#define EDITOR_LIST_APPEND (SAL_MAX_UINT16)
+#define EDITOR_LIST_ENTRY_NOTFOUND (SAL_MAX_UINT16)
+
+#include <sal/config.h>
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <comphelper/interfacecontainer3.hxx>
+
+namespace pcr
+{
+
+
+ #define OWN_PROPERTY_ID_INTROSPECTEDOBJECT 0x0010
+ #define OWN_PROPERTY_ID_CURRENTPAGE 0x0011
+ #define OWN_PROPERTY_ID_CONTROLCONTEXT 0x0012
+ #define OWN_PROPERTY_ID_TABBINGMODEL 0x0013
+
+
+ //= types
+
+ typedef ::comphelper::OInterfaceContainerHelper3 < css::beans::XPropertyChangeListener
+ > PropertyChangeListeners;
+
+
+ //= helper
+
+ // small helper to make the "swap" call on an STL container a single-line call, which
+ // in its canonic form "aFoo.swap( Container() )" doesn't compile with GCC
+ template< class CONTAINER >
+ void clearContainer( CONTAINER& _rContainer )
+ {
+ CONTAINER().swap(_rContainer);
+ }
+
+
+ //= HelpIdUrl
+
+ /// small helper to translate help ids into help urls
+ class HelpIdUrl
+ {
+ public:
+ static OString getHelpId( std::u16string_view _rHelpURL );
+ static OUString getHelpURL( std::u16string_view );
+ };
+
+
+ //= StlSyntaxSequence
+
+ template< class ELEMENT >
+ class StlSyntaxSequence : public css::uno::Sequence< ELEMENT >
+ {
+ private:
+ typedef css::uno::Sequence< ELEMENT > UnoBase;
+
+ public:
+ StlSyntaxSequence() : UnoBase() { }
+ explicit StlSyntaxSequence( const UnoBase& rSeq ) : UnoBase( rSeq ) { }
+ explicit StlSyntaxSequence( sal_Int32 len ) : UnoBase( len ) { }
+
+ typedef const ELEMENT* const_iterator;
+ typedef ELEMENT* iterator;
+
+ const_iterator begin() const { return UnoBase::getConstArray(); }
+ const_iterator end() const { return UnoBase::getConstArray() + UnoBase::getLength(); }
+
+ iterator begin() { return UnoBase::getArray(); }
+ iterator end() { return UnoBase::getArray() + UnoBase::getLength(); }
+
+ sal_Int32 size() const { return UnoBase::getLength(); }
+ bool empty() const { return !UnoBase::hasElements(); }
+ };
+
+
+ //= UNO helpers
+
+#define DECLARE_XCOMPONENT() \
+ virtual void SAL_CALL dispose( ) override; \
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; \
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+
+#define IMPLEMENT_FORWARD_XCOMPONENT( classname, baseclass ) \
+ void SAL_CALL classname::dispose( ) \
+ { \
+ baseclass::WeakComponentImplHelperBase::dispose(); \
+ } \
+ void SAL_CALL classname::addEventListener( const css::uno::Reference< css::lang::XEventListener >& Listener ) \
+ { \
+ baseclass::WeakComponentImplHelperBase::addEventListener( Listener ); \
+ } \
+ void SAL_CALL classname::removeEventListener( const css::uno::Reference< css::lang::XEventListener >& Listener ) \
+ { \
+ baseclass::WeakComponentImplHelperBase::removeEventListener( Listener ); \
+ } \
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/pcrcommontypes.hxx b/extensions/source/propctrlr/pcrcommontypes.hxx
new file mode 100644
index 000000000..e2aa3570e
--- /dev/null
+++ b/extensions/source/propctrlr/pcrcommontypes.hxx
@@ -0,0 +1,33 @@
+/* -*- 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/beans/Property.hpp>
+#include <rtl/ustring.hxx>
+
+#include <unordered_map>
+
+namespace pcr
+{
+typedef std::unordered_map<OUString, css::beans::Property> PropertyMap;
+
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/pcrstrings.hxx b/extensions/source/propctrlr/pcrstrings.hxx
new file mode 100644
index 000000000..3bb0a888c
--- /dev/null
+++ b/extensions/source/propctrlr/pcrstrings.hxx
@@ -0,0 +1,35 @@
+/* -*- 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 <rtl/ustring.hxx>
+
+namespace pcr
+{
+
+
+ // properties
+ constexpr OUStringLiteral PROPERTY_TABBINGMODEL = u"TabbingModel";
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/pcrunodialogs.cxx b/extensions/source/propctrlr/pcrunodialogs.cxx
new file mode 100644
index 000000000..9083cb284
--- /dev/null
+++ b/extensions/source/propctrlr/pcrunodialogs.cxx
@@ -0,0 +1,143 @@
+/* -*- 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 <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <vcl/svapp.hxx>
+#include "pcrunodialogs.hxx"
+#include "formstrings.hxx"
+#include "pcrstrings.hxx"
+#include "taborder.hxx"
+#include "pcrcommon.hxx"
+
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+
+
+ //= OTabOrderDialog
+
+
+ OTabOrderDialog::OTabOrderDialog( const Reference< XComponentContext >& _rxContext )
+ :OGenericUnoDialog( _rxContext )
+ {
+ registerProperty( PROPERTY_CONTROLCONTEXT, OWN_PROPERTY_ID_CONTROLCONTEXT,
+ PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT,
+ &m_xControlContext, cppu::UnoType<decltype(m_xControlContext)>::get() );
+
+ registerProperty( PROPERTY_TABBINGMODEL, OWN_PROPERTY_ID_TABBINGMODEL,
+ PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT,
+ &m_xTabbingModel, cppu::UnoType<decltype(m_xTabbingModel)>::get() );
+ }
+
+ OTabOrderDialog::~OTabOrderDialog()
+ {
+ if (m_xDialog)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (m_xDialog)
+ destroyDialog();
+ }
+ }
+
+ Sequence<sal_Int8> SAL_CALL OTabOrderDialog::getImplementationId( )
+ {
+ return css::uno::Sequence<sal_Int8>();
+ }
+
+ OUString SAL_CALL OTabOrderDialog::getImplementationName()
+ {
+ return "org.openoffice.comp.form.ui.OTabOrderDialog";
+ }
+
+
+ css::uno::Sequence<OUString> SAL_CALL OTabOrderDialog::getSupportedServiceNames()
+ {
+ return { "com.sun.star.form.ui.TabOrderDialog", "com.sun.star.form.TabOrderDialog" };
+ }
+
+
+ Reference<XPropertySetInfo> SAL_CALL OTabOrderDialog::getPropertySetInfo()
+ {
+ Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+ }
+
+ ::cppu::IPropertyArrayHelper& OTabOrderDialog::getInfoHelper()
+ {
+ return *getArrayHelper();
+ }
+
+ ::cppu::IPropertyArrayHelper* OTabOrderDialog::createArrayHelper( ) const
+ {
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper( aProps );
+ }
+
+ std::unique_ptr<weld::DialogController> OTabOrderDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+ {
+ return std::make_unique<TabOrderDialog>(Application::GetFrameWeld(rParent), m_xTabbingModel, m_xControlContext, m_aContext);
+ }
+
+ void OTabOrderDialog::initialize( const Sequence< Any >& aArguments )
+ {
+ Reference<css::awt::XTabControllerModel> xTabbingModel;
+ Reference<css::awt::XControlContainer> xControlContext;
+ Reference<css::awt::XWindow> xParentWindow;
+ if (aArguments.getLength() == 3 && (aArguments[0] >>= xTabbingModel) && (aArguments[1] >>= xControlContext) && (aArguments[2] >>= xParentWindow))
+ {
+ Sequence< Any > aNewArguments{
+ Any(NamedValue(
+ "TabbingModel",
+ Any( xTabbingModel )
+ )),
+ Any(NamedValue(
+ "ControlContext",
+ Any( xControlContext )
+ )),
+ Any(NamedValue(
+ "ParentWindow",
+ Any( xParentWindow )
+ ))
+ };
+ OTabOrderDialog_DBase::initialize(aNewArguments);
+ }
+ else
+ OTabOrderDialog_DBase::initialize(aArguments);
+ }
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propcrltr_OTabOrderDialog_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::OTabOrderDialog(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/pcrunodialogs.hxx b/extensions/source/propctrlr/pcrunodialogs.hxx
new file mode 100644
index 000000000..87c99db35
--- /dev/null
+++ b/extensions/source/propctrlr/pcrunodialogs.hxx
@@ -0,0 +1,79 @@
+/* -*- 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 <svtools/genericunodialog.hxx>
+#include <com/sun/star/awt/XTabControllerModel.hpp>
+#include <com/sun/star/awt/XControlContainer.hpp>
+#include <comphelper/proparrhlp.hxx>
+
+
+namespace pcr
+{
+
+
+ //= OTabOrderDialog
+
+ class OTabOrderDialog;
+ typedef ::svt::OGenericUnoDialog OTabOrderDialog_DBase;
+ typedef ::comphelper::OPropertyArrayUsageHelper< OTabOrderDialog > OTabOrderDialog_PBase;
+
+ class OTabOrderDialog
+ :public OTabOrderDialog_DBase
+ ,public OTabOrderDialog_PBase
+ {
+ protected:
+ // <properties>
+ css::uno::Reference< css::awt::XTabControllerModel >
+ m_xTabbingModel;
+ css::uno::Reference< css::awt::XControlContainer >
+ m_xControlContext;
+ // </properties>
+
+ public:
+ explicit OTabOrderDialog( const css::uno::Reference< css::uno::XComponentContext >& _rxContext );
+ virtual ~OTabOrderDialog() override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ protected:
+ // OGenericUnoDialog overridables
+ virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+ };
+
+
+} // namespacepcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/propcontroller.cxx b/extensions/source/propctrlr/propcontroller.cxx
new file mode 100644
index 000000000..6bbcdcf5d
--- /dev/null
+++ b/extensions/source/propctrlr/propcontroller.cxx
@@ -0,0 +1,1652 @@
+/* -*- 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 "propcontroller.hxx"
+#include "handlerhelper.hxx"
+#include "standardcontrol.hxx"
+#include "linedescriptor.hxx"
+#include <strings.hrc>
+#include "propertyeditor.hxx"
+#include "modulepcr.hxx"
+#include "formstrings.hxx"
+#include "formbrowsertools.hxx"
+#include "propertycomposer.hxx"
+
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/inspection/PropertyControlType.hpp>
+#include <com/sun/star/ucb/AlreadyInitializedException.hpp>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/util/VetoException.hpp>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/weldutils.hxx>
+#include <osl/mutex.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <algorithm>
+#include <sal/log.hxx>
+
+namespace pcr
+{
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::inspection;
+ using namespace ::com::sun::star::ucb;
+ using namespace ::comphelper;
+
+ //= OPropertyBrowserController
+ OPropertyBrowserController::OPropertyBrowserController( const Reference< XComponentContext >& _rxContext )
+ :m_xContext(_rxContext)
+ ,m_aDisposeListeners( m_aMutex )
+ ,m_aControlObservers( m_aMutex )
+ ,m_bContainerFocusListening( false )
+ ,m_bSuspendingPropertyHandlers( false )
+ ,m_bConstructed( false )
+ ,m_bBindingIntrospectee( false )
+ {
+ }
+
+ OPropertyBrowserController::~OPropertyBrowserController()
+ {
+ // stop listening for property changes
+ acquire();
+ stopInspection( true );
+ }
+
+ IMPLEMENT_FORWARD_REFCOUNT( OPropertyBrowserController, OPropertyBrowserController_Base )
+
+ Any SAL_CALL OPropertyBrowserController::queryInterface( const Type& _rType )
+ {
+ Any aReturn = OPropertyBrowserController_Base::queryInterface( _rType );
+ if ( !aReturn.hasValue() )
+ aReturn = ::cppu::queryInterface(
+ _rType,
+ static_cast< XObjectInspectorUI* >( this )
+ );
+ return aReturn;
+ }
+
+
+ void OPropertyBrowserController::startContainerWindowListening()
+ {
+ if (m_bContainerFocusListening)
+ return;
+
+ if (m_xFrame.is())
+ {
+ Reference< XWindow > xContainerWindow = m_xFrame->getContainerWindow();
+ if (xContainerWindow.is())
+ {
+ xContainerWindow->addFocusListener(this);
+ m_bContainerFocusListening = true;
+ }
+ }
+
+ DBG_ASSERT(m_bContainerFocusListening, "OPropertyBrowserController::startContainerWindowListening: unable to start listening (inconsistence)!");
+ }
+
+
+ void OPropertyBrowserController::stopContainerWindowListening()
+ {
+ if (!m_bContainerFocusListening)
+ return;
+
+ if (m_xFrame.is())
+ {
+ Reference< XWindow > xContainerWindow = m_xFrame->getContainerWindow();
+ if (xContainerWindow.is())
+ {
+ xContainerWindow->removeFocusListener(this);
+ m_bContainerFocusListening = false;
+ }
+ }
+
+ DBG_ASSERT(!m_bContainerFocusListening, "OPropertyBrowserController::stopContainerWindowListening: unable to stop listening (inconsistence)!");
+ }
+
+
+ Reference< XObjectInspectorModel > SAL_CALL OPropertyBrowserController::getInspectorModel()
+ {
+ return m_xModel;
+ }
+
+
+ void OPropertyBrowserController::impl_initializeView_nothrow()
+ {
+ OSL_PRECOND( haveView(), "OPropertyBrowserController::impl_initializeView_nothrow: not to be called when we have no view!" );
+ if ( !haveView() )
+ return;
+
+ if ( !m_xModel.is() )
+ // allowed
+ return;
+
+ try
+ {
+ getPropertyBox().EnableHelpSection( m_xModel->getHasHelpSection() );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+
+ bool OPropertyBrowserController::impl_isReadOnlyModel_throw() const
+ {
+ if ( !m_xModel.is() )
+ return false;
+
+ return m_xModel->getIsReadOnly();
+ }
+
+
+ void OPropertyBrowserController::impl_startOrStopModelListening_nothrow( bool _bDoListen ) const
+ {
+ try
+ {
+ Reference< XPropertySet > xModelProperties( m_xModel, UNO_QUERY );
+ if ( !xModelProperties.is() )
+ // okay, so the model doesn't want to change its properties
+ // dynamically - fine with us
+ return;
+
+ void (SAL_CALL XPropertySet::*pListenerOperation)( const OUString&, const Reference< XPropertyChangeListener >& )
+ = _bDoListen ? &XPropertySet::addPropertyChangeListener : &XPropertySet::removePropertyChangeListener;
+
+ (xModelProperties.get()->*pListenerOperation)(
+ OUString( "IsReadOnly" ),
+ const_cast< OPropertyBrowserController* >( this )
+ );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+
+ void OPropertyBrowserController::impl_bindToNewModel_nothrow( const Reference< XObjectInspectorModel >& _rxInspectorModel )
+ {
+ impl_startOrStopModelListening_nothrow( false );
+ m_xModel = _rxInspectorModel;
+ impl_startOrStopModelListening_nothrow( true );
+
+ // initialize the view, if we already have one
+ if ( haveView() )
+ impl_initializeView_nothrow();
+
+ // inspect again, if we already have inspectees
+ if ( !m_aInspectedObjects.empty() )
+ impl_rebindToInspectee_nothrow( std::vector(m_aInspectedObjects) );
+ }
+
+
+ void SAL_CALL OPropertyBrowserController::setInspectorModel( const Reference< XObjectInspectorModel >& _inspectorModel )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_xModel == _inspectorModel )
+ return;
+
+ impl_bindToNewModel_nothrow( _inspectorModel );
+ }
+
+
+ Reference< XObjectInspectorUI > SAL_CALL OPropertyBrowserController::getInspectorUI()
+ {
+ // we're derived from this interface, though we do not expose it in queryInterface and getTypes.
+ return this;
+ }
+
+
+ void SAL_CALL OPropertyBrowserController::inspect( const Sequence< Reference< XInterface > >& _rObjects )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_bSuspendingPropertyHandlers || !suspendAll_nothrow() )
+ { // we already are trying to suspend the component (this is somewhere up the stack)
+ // OR one of our property handlers raised a veto against closing. Well, we *need* to close
+ // it in order to inspect another object.
+ throw VetoException();
+ }
+ if ( m_bBindingIntrospectee )
+ throw VetoException();
+
+ m_bBindingIntrospectee = true;
+ impl_rebindToInspectee_nothrow( InterfaceArray( _rObjects.begin(), _rObjects.end() ) );
+ m_bBindingIntrospectee = false;
+
+ }
+
+
+ Reference< XDispatch > SAL_CALL OPropertyBrowserController::queryDispatch( const URL& /*URL*/, const OUString& /*TargetFrameName*/, ::sal_Int32 /*SearchFlags*/ )
+ {
+ // we don't have any dispatches at all, right now
+ return Reference< XDispatch >();
+ }
+
+
+ Sequence< Reference< XDispatch > > SAL_CALL OPropertyBrowserController::queryDispatches( const Sequence< DispatchDescriptor >& Requests )
+ {
+ Sequence< Reference< XDispatch > > aReturn;
+ sal_Int32 nLen = Requests.getLength();
+ aReturn.realloc( nLen );
+
+ Reference< XDispatch >* pReturn = aReturn.getArray();
+ const Reference< XDispatch >* pReturnEnd = aReturn.getArray() + nLen;
+ const DispatchDescriptor* pDescripts = Requests.getConstArray();
+
+ for ( ; pReturn != pReturnEnd; ++ pReturn, ++pDescripts )
+ *pReturn = queryDispatch( pDescripts->FeatureURL, pDescripts->FrameName, pDescripts->SearchFlags );
+
+ return aReturn;
+ }
+
+
+ void SAL_CALL OPropertyBrowserController::initialize( const Sequence< Any >& _arguments )
+ {
+ if ( m_bConstructed )
+ throw AlreadyInitializedException();
+
+ StlSyntaxSequence< Any > arguments( _arguments );
+ if ( arguments.empty() )
+ { // constructor: "createDefault()"
+ m_bConstructed = true;
+ return;
+ }
+
+ Reference< XObjectInspectorModel > xModel;
+ if ( arguments.size() == 1 )
+ { // constructor: "createWithModel( XObjectInspectorModel )"
+ if ( !( arguments[0] >>= xModel ) )
+ throw IllegalArgumentException( OUString(), *this, 0 );
+ createWithModel( xModel );
+ return;
+ }
+
+ throw IllegalArgumentException( OUString(), *this, 0 );
+ }
+
+
+ void OPropertyBrowserController::createWithModel( const Reference< XObjectInspectorModel >& _rxModel )
+ {
+ osl_atomic_increment( &m_refCount );
+ {
+ setInspectorModel( _rxModel );
+ }
+ osl_atomic_decrement( &m_refCount );
+
+ m_bConstructed = true;
+ }
+
+
+ void SAL_CALL OPropertyBrowserController::attachFrame( const Reference< XFrame >& _rxFrame )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if (_rxFrame.is() && haveView())
+ throw RuntimeException("Unable to attach to a second frame.",*this);
+
+ // revoke as focus listener from the old container window
+ stopContainerWindowListening();
+
+ m_xPropView.reset();
+ m_xBuilder.reset();
+
+ m_xFrame = _rxFrame;
+ if (!m_xFrame.is())
+ return;
+
+ // TODO: this construction perhaps should be done outside. Don't know the exact meaning of attachFrame.
+ // Maybe it is intended to only announce the frame to the controller, and the instance doing this
+ // announcement is responsible for calling setComponent, too.
+ Reference<XWindow> xContainerWindow = m_xFrame->getContainerWindow();
+
+ OUString sUIFile("modules/spropctrlr/ui/formproperties.ui");
+ std::unique_ptr<weld::Builder> xBuilder;
+
+ if (weld::TransportAsXWindow* pTunnel = dynamic_cast<weld::TransportAsXWindow*>(xContainerWindow.get()))
+ {
+ xBuilder = Application::CreateBuilder(pTunnel->getWidget(), sUIFile);
+ }
+ else
+ {
+ VclPtr<vcl::Window> pParentWin = VCLUnoHelper::GetWindow(xContainerWindow);
+ if (!pParentWin)
+ throw RuntimeException("The frame is invalid. Unable to extract the container window.",*this);
+ xBuilder = Application::CreateInterimBuilder(pParentWin, sUIFile, true);
+ }
+
+ Construct(xContainerWindow, std::move(xBuilder));
+
+ startContainerWindowListening();
+
+ UpdateUI();
+ }
+
+ sal_Bool SAL_CALL OPropertyBrowserController::attachModel( const Reference< XModel >& _rxModel )
+ {
+ Reference< XObjectInspectorModel > xModel( _rxModel, UNO_QUERY );
+ if ( !xModel.is() )
+ return false;
+
+ setInspectorModel( xModel );
+ return getInspectorModel() == _rxModel;
+ }
+
+
+ bool OPropertyBrowserController::suspendAll_nothrow()
+ {
+ // if there is a handle inside its "onInteractivePropertySelection" method,
+ // then veto
+ // Normally, we could expect every handler to do this itself, but being
+ // realistic, it's safer to handle this here in general.
+ if ( m_xInteractiveHandler.is() )
+ return false;
+
+ m_bSuspendingPropertyHandlers = true;
+ bool bHandlerVeto = !suspendPropertyHandlers_nothrow( true );
+ m_bSuspendingPropertyHandlers = false;
+ return !bHandlerVeto;
+ }
+
+
+ bool OPropertyBrowserController::suspendPropertyHandlers_nothrow( bool _bSuspend )
+ {
+ PropertyHandlerArray aAllHandlers; // will contain every handler exactly once
+ for (auto const& propertyHandler : m_aPropertyHandlers)
+ {
+ if ( std::find( aAllHandlers.begin(), aAllHandlers.end(), propertyHandler.second ) != aAllHandlers.end() )
+ // already visited this particular handler (m_aPropertyHandlers usually contains
+ // the same handler more than once)
+ continue;
+ aAllHandlers.push_back(propertyHandler.second);
+ }
+
+ for (auto const& handler : aAllHandlers)
+ {
+ try
+ {
+ if ( !handler->suspend( _bSuspend ) )
+ if ( _bSuspend )
+ // if we're not suspending, but reactivating, ignore the error
+ return false;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "OPropertyBrowserController::suspendPropertyHandlers_nothrow" );
+ }
+ }
+ return true;
+ }
+
+
+ sal_Bool SAL_CALL OPropertyBrowserController::suspend( sal_Bool _bSuspend )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OSL_ENSURE( haveView(), "OPropertyBrowserController::suspend: don't have a view anymore!" );
+
+ if ( !_bSuspend )
+ { // this means a "suspend" is to be "revoked"
+ suspendPropertyHandlers_nothrow( false );
+ // we ourself cannot revoke our suspend
+ return false;
+ }
+
+ if ( !suspendAll_nothrow() )
+ return false;
+
+ // commit the editor's content
+ if ( haveView() )
+ getPropertyBox().CommitModified();
+
+ // stop listening
+ stopContainerWindowListening();
+
+ // outta here
+ return true;
+ }
+
+
+ Any SAL_CALL OPropertyBrowserController::getViewData( )
+ {
+ return Any( m_sPageSelection );
+ }
+
+
+ void SAL_CALL OPropertyBrowserController::restoreViewData( const Any& Data )
+ {
+ OUString sPageSelection;
+ if ( ( Data >>= sPageSelection ) && !sPageSelection.isEmpty() )
+ {
+ m_sPageSelection = sPageSelection;
+ selectPageFromViewData();
+ }
+ }
+
+ Reference< XModel > SAL_CALL OPropertyBrowserController::getModel( )
+ {
+ // have no model
+ return Reference< XModel >();
+ }
+
+ Reference< XFrame > SAL_CALL OPropertyBrowserController::getFrame( )
+ {
+ return m_xFrame;
+ }
+
+ void SAL_CALL OPropertyBrowserController::dispose()
+ {
+ SolarMutexGuard aSolarGuard;
+
+ // stop inspecting the current object
+ stopInspection( false );
+
+ // say our dispose listeners goodbye
+ css::lang::EventObject aEvt;
+ aEvt.Source = static_cast< ::cppu::OWeakObject* >(this);
+ m_aDisposeListeners.disposeAndClear(aEvt);
+ m_aControlObservers.disposeAndClear(aEvt);
+
+ m_xPropView.reset();
+ m_xBuilder.reset();
+
+ if ( m_xView.is() )
+ m_xView->removeEventListener( static_cast< XPropertyChangeListener* >( this ) );
+ m_xView.clear( );
+
+ m_aInspectedObjects.clear();
+ impl_bindToNewModel_nothrow( nullptr );
+ }
+
+ void SAL_CALL OPropertyBrowserController::addEventListener( const Reference< XEventListener >& _rxListener )
+ {
+ m_aDisposeListeners.addInterface(_rxListener);
+ }
+
+ void SAL_CALL OPropertyBrowserController::removeEventListener( const Reference< XEventListener >& _rxListener )
+ {
+ m_aDisposeListeners.removeInterface(_rxListener);
+ }
+
+ OUString SAL_CALL OPropertyBrowserController::getImplementationName( )
+ {
+ return "org.openoffice.comp.extensions.ObjectInspector";
+ }
+
+ sal_Bool SAL_CALL OPropertyBrowserController::supportsService( const OUString& ServiceName )
+ {
+ return cppu::supportsService(this, ServiceName);
+ }
+
+
+ Sequence< OUString > SAL_CALL OPropertyBrowserController::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.inspection.ObjectInspector" };
+ }
+
+
+ void SAL_CALL OPropertyBrowserController::focusGained( const FocusEvent& _rSource )
+ {
+ Reference< XWindow > xSourceWindow(_rSource.Source, UNO_QUERY);
+ Reference< XWindow > xContainerWindow;
+ if (m_xFrame.is())
+ xContainerWindow = m_xFrame->getContainerWindow();
+
+ if ( xContainerWindow.get() == xSourceWindow.get() )
+ { // our container window got the focus
+ if ( haveView() )
+ getPropertyBox().GrabFocus();
+ }
+ }
+
+
+ void SAL_CALL OPropertyBrowserController::focusLost( const FocusEvent& /*_rSource*/ )
+ {
+ // not interested in
+ }
+
+
+ void SAL_CALL OPropertyBrowserController::disposing( const EventObject& _rSource )
+ {
+ if ( m_xView.is() && ( m_xView == _rSource.Source ) )
+ {
+ m_xView = nullptr;
+ m_xPropView.reset();
+ m_xBuilder.reset();
+ }
+
+ auto it = std::find_if(m_aInspectedObjects.begin(), m_aInspectedObjects.end(),
+ [&_rSource](const InterfaceArray::value_type& rxObj) { return rxObj == _rSource.Source; });
+ if (it != m_aInspectedObjects.end())
+ m_aInspectedObjects.erase(it);
+ }
+
+
+ IMPL_LINK_NOARG(OPropertyBrowserController, OnPageActivation, LinkParamNone*, void)
+ {
+ updateViewDataFromActivePage();
+ }
+
+
+ void OPropertyBrowserController::updateViewDataFromActivePage()
+ {
+ if (!haveView())
+ return;
+
+ OUString sOldSelection = m_sPageSelection;
+ m_sPageSelection.clear();
+
+ const sal_uInt16 nCurrentPage = m_xPropView->getActivePage();
+ if ( sal_uInt16(-1) != nCurrentPage )
+ {
+ for (auto const& pageId : m_aPageIds)
+ {
+ if ( nCurrentPage == pageId.second )
+ {
+ m_sPageSelection = pageId.first;
+ break;
+ }
+ }
+ }
+
+ if ( !m_sPageSelection.isEmpty() )
+ m_sLastValidPageSelection = m_sPageSelection;
+ else if ( !sOldSelection.isEmpty() )
+ m_sLastValidPageSelection = sOldSelection;
+ }
+
+
+ sal_uInt16 OPropertyBrowserController::impl_getPageIdForCategory_nothrow( const OUString& _rCategoryName ) const
+ {
+ sal_uInt16 nPageId = sal_uInt16(-1);
+ HashString2Int16::const_iterator pagePos = m_aPageIds.find( _rCategoryName );
+ if ( pagePos != m_aPageIds.end() )
+ nPageId = pagePos->second;
+ return nPageId;
+ }
+
+ void OPropertyBrowserController::selectPageFromViewData()
+ {
+ sal_uInt16 nNewPage = impl_getPageIdForCategory_nothrow( m_sPageSelection );
+
+ if ( haveView() && ( nNewPage != sal_uInt16(-1) ) )
+ m_xPropView->activatePage( nNewPage );
+
+ // just in case ...
+ updateViewDataFromActivePage();
+ }
+
+ void OPropertyBrowserController::Construct(const Reference<XWindow>& rContainerWindow, std::unique_ptr<weld::Builder> xBuilder)
+ {
+ DBG_ASSERT(!haveView(), "OPropertyBrowserController::Construct: already have a view!");
+ assert(xBuilder && "OPropertyBrowserController::Construct: invalid parent window!");
+
+ m_xBuilder = std::move(xBuilder);
+
+ m_xPropView.reset(new OPropertyBrowserView(m_xContext, *m_xBuilder));
+ m_xPropView->setPageActivationHandler(LINK(this, OPropertyBrowserController, OnPageActivation));
+
+ // add as dispose listener for our view. The view is disposed by the frame we're plugged into,
+ // and this disposal _deletes_ the view, so it would be deadly if we use our m_xPropView member
+ // after that
+ m_xView = rContainerWindow;
+ if (m_xView.is())
+ m_xView->addEventListener( static_cast< XPropertyChangeListener* >( this ) );
+
+ getPropertyBox().SetLineListener(this);
+ getPropertyBox().SetControlObserver(this);
+ impl_initializeView_nothrow();
+ }
+
+ void SAL_CALL OPropertyBrowserController::propertyChange( const PropertyChangeEvent& _rEvent )
+ {
+ if ( _rEvent.Source == m_xModel )
+ {
+ if ( _rEvent.PropertyName == "IsReadOnly" )
+ // this is a huge cudgel, admitted.
+ // The problem is that in case we were previously read-only, all our controls
+ // were created read-only, too. We cannot simply switch them to not-read-only.
+ // Even if they had an API for this, we do not know whether they were
+ // originally created read-only, or if they are read-only just because
+ // the model was.
+ impl_rebindToInspectee_nothrow( std::vector(m_aInspectedObjects) );
+ return;
+ }
+
+ if ( m_sCommittingProperty == _rEvent.PropertyName )
+ return;
+
+ if ( !haveView() )
+ return;
+
+ Any aNewValue( _rEvent.NewValue );
+ if ( impl_hasPropertyHandlerFor_nothrow( _rEvent.PropertyName ) )
+ {
+ // forward the new value to the property box, to reflect the change in the UI
+ aNewValue = impl_getPropertyValue_throw( _rEvent.PropertyName );
+
+ // check whether the state is ambiguous. This is interesting in case we display the properties
+ // for multiple objects at once: In this case, we'll get a notification from one of the objects,
+ // but need to care for the "composed" value, which can be "ambiguous".
+ PropertyHandlerRef xHandler( impl_getHandlerForProperty_throw( _rEvent.PropertyName ), UNO_SET_THROW );
+ PropertyState ePropertyState( xHandler->getPropertyState( _rEvent.PropertyName ) );
+ bool bAmbiguousValue = ( PropertyState_AMBIGUOUS_VALUE == ePropertyState );
+
+ getPropertyBox().SetPropertyValue( _rEvent.PropertyName, aNewValue, bAmbiguousValue );
+ }
+
+ // if it's an actuating property, then update the UI for any dependent
+ // properties
+ if ( impl_isActuatingProperty_nothrow( _rEvent.PropertyName ) )
+ impl_broadcastPropertyChange_nothrow( _rEvent.PropertyName, aNewValue, _rEvent.OldValue, false );
+ }
+
+ Reference< XPropertyControl > SAL_CALL OPropertyBrowserController::createPropertyControl( ::sal_Int16 ControlType, sal_Bool bCreateReadOnly )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Reference< XPropertyControl > xControl;
+
+ // read-only-ness
+ bCreateReadOnly |= impl_isReadOnlyModel_throw() ? 1 : 0;
+
+ switch ( ControlType )
+ {
+ case PropertyControlType::MultiLineTextField:
+ case PropertyControlType::StringListField:
+ {
+ bool bMultiLineTextField = ControlType == PropertyControlType::MultiLineTextField;
+ std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/multiline.ui", m_xContext));
+ auto pContainer = xBuilder->weld_container("multiline");
+ rtl::Reference<OMultilineEditControl> pControl = new OMultilineEditControl(std::move(pContainer), std::move(xBuilder),
+ bMultiLineTextField ? eMultiLineText : eStringList, bCreateReadOnly);
+ pControl->SetModifyHandler();
+ xControl = pControl;
+ break;
+ }
+
+ case PropertyControlType::ListBox:
+ {
+ std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/listbox.ui", m_xContext));
+ auto pComboBox = xBuilder->weld_combo_box("listbox");
+ rtl::Reference<OListboxControl> pControl = new OListboxControl(std::move(pComboBox), std::move(xBuilder), bCreateReadOnly);
+ pControl->SetModifyHandler();
+ xControl = pControl;
+ break;
+ }
+
+ case PropertyControlType::ComboBox:
+ {
+ std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/combobox.ui", m_xContext));
+ auto pComboBox = xBuilder->weld_combo_box("combobox");
+ rtl::Reference<OComboboxControl> pControl = new OComboboxControl(std::move(pComboBox), std::move(xBuilder), bCreateReadOnly);
+ pControl->SetModifyHandler();
+ xControl = pControl;
+ break;
+ }
+
+ case PropertyControlType::TextField:
+ case PropertyControlType::CharacterField:
+ {
+ bool bCharacterField = ControlType == PropertyControlType::CharacterField;
+ std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/textfield.ui", m_xContext));
+ auto pEntry = xBuilder->weld_entry("textfield");
+ rtl::Reference<OEditControl> pControl = new OEditControl(std::move(pEntry), std::move(xBuilder), bCharacterField, bCreateReadOnly);
+ pControl->SetModifyHandler();
+ xControl = pControl;
+ break;
+ }
+
+ case PropertyControlType::NumericField:
+ {
+ std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/numericfield.ui", m_xContext));
+ auto pSpinButton = xBuilder->weld_metric_spin_button("numericfield", FieldUnit::NONE);
+ rtl::Reference<ONumericControl> pControl = new ONumericControl(std::move(pSpinButton), std::move(xBuilder), bCreateReadOnly);
+ pControl->SetModifyHandler();
+ xControl = pControl;
+ break;
+ }
+
+ case PropertyControlType::DateTimeField:
+ {
+ std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/datetimefield.ui", m_xContext));
+ auto pContainer = xBuilder->weld_container("datetimefield");
+ rtl::Reference<ODateTimeControl> pControl = new ODateTimeControl(std::move(pContainer), std::move(xBuilder), bCreateReadOnly);
+ pControl->SetModifyHandler();
+ xControl = pControl;
+ break;
+ }
+
+ case PropertyControlType::DateField:
+ {
+ std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/datefield.ui", m_xContext));
+ auto pContainer = xBuilder->weld_container("datefield");
+ rtl::Reference<ODateControl> pControl = new ODateControl(std::move(pContainer), std::move(xBuilder), bCreateReadOnly);
+ pControl->SetModifyHandler();
+ xControl = pControl;
+ break;
+ }
+
+ case PropertyControlType::TimeField:
+ {
+ std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/timefield.ui", m_xContext));
+ auto pTimeSpinButton = xBuilder->weld_formatted_spin_button("timefield");
+ rtl::Reference<OTimeControl> pControl = new OTimeControl(std::move(pTimeSpinButton), std::move(xBuilder), bCreateReadOnly);
+ pControl->SetModifyHandler();
+ xControl = pControl;
+ break;
+ }
+
+ case PropertyControlType::ColorListBox:
+ {
+ auto lambda = [this]{ return PropertyHandlerHelper::getDialogParentFrame(m_xContext); };
+ std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/colorlistbox.ui", m_xContext));
+ auto pMenuButton = xBuilder->weld_menu_button("colorlistbox");
+ rtl::Reference<OColorControl> pControl = new OColorControl(std::make_unique<ColorListBox>(std::move(pMenuButton), lambda), std::move(xBuilder), bCreateReadOnly);
+ pControl->SetModifyHandler();
+ xControl = pControl;
+ break;
+ }
+
+ case PropertyControlType::HyperlinkField:
+ {
+ std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/hyperlinkfield.ui", m_xContext));
+ auto pContainer = xBuilder->weld_container("hyperlinkfield");
+ rtl::Reference<OHyperlinkControl> pControl = new OHyperlinkControl(std::move(pContainer), std::move(xBuilder), bCreateReadOnly);
+ pControl->SetModifyHandler();
+ xControl = pControl;
+ break;
+ }
+
+ default:
+ throw IllegalArgumentException( OUString(), *this, 1 );
+ }
+
+ return xControl;
+ }
+
+
+ void OPropertyBrowserController::impl_toggleInspecteeListening_nothrow( bool _bOn )
+ {
+ for (auto const& inspectedObject : m_aInspectedObjects)
+ {
+ try
+ {
+ Reference< XComponent > xComp( inspectedObject, UNO_QUERY );
+ if ( xComp.is() )
+ {
+ if ( _bOn )
+ xComp->addEventListener( static_cast< XPropertyChangeListener* >( this ) );
+ else
+ xComp->removeEventListener( static_cast< XPropertyChangeListener* >( this ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+ }
+
+
+ void OPropertyBrowserController::stopInspection( bool _bCommitModified )
+ {
+ if ( haveView() )
+ {
+ if ( _bCommitModified )
+ // commit the editor's content
+ getPropertyBox().CommitModified();
+
+ // hide the property box so that it does not flicker
+ getPropertyBox().Hide();
+
+ // clear the property box
+ getPropertyBox().ClearAll();
+ }
+
+ // destroy the view first
+ if ( haveView() )
+ {
+ // remove the pages
+ for (auto const& pageId : m_aPageIds)
+ getPropertyBox().RemovePage( pageId.second );
+ clearContainer( m_aPageIds );
+ }
+
+ clearContainer( m_aProperties );
+
+ // de-register as dispose-listener from our inspected objects
+ impl_toggleInspecteeListening_nothrow( false );
+
+ // handlers are obsolete, so is our "composer" for their UI requests
+ if (m_pUIRequestComposer)
+ m_pUIRequestComposer->dispose();
+ m_pUIRequestComposer.reset();
+
+ // clean up the property handlers
+ PropertyHandlerArray aAllHandlers; // will contain every handler exactly once
+ for (auto const& propertyHandler : m_aPropertyHandlers)
+ if ( std::find( aAllHandlers.begin(), aAllHandlers.end(), propertyHandler.second ) == aAllHandlers.end() )
+ aAllHandlers.push_back( propertyHandler.second );
+
+ for (auto const& handler : aAllHandlers)
+ {
+ try
+ {
+ handler->removePropertyChangeListener( this );
+ handler->dispose();
+ }
+ catch( const DisposedException& )
+ {
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+ clearContainer( m_aPropertyHandlers );
+ clearContainer( m_aDependencyHandlers );
+ }
+
+
+ bool OPropertyBrowserController::impl_hasPropertyHandlerFor_nothrow( const OUString& _rPropertyName ) const
+ {
+ PropertyHandlerRepository::const_iterator handlerPos = m_aPropertyHandlers.find( _rPropertyName );
+ return ( handlerPos != m_aPropertyHandlers.end() );
+ }
+
+
+ OPropertyBrowserController::PropertyHandlerRef const & OPropertyBrowserController::impl_getHandlerForProperty_throw( const OUString& _rPropertyName ) const
+ {
+ PropertyHandlerRepository::const_iterator handlerPos = m_aPropertyHandlers.find( _rPropertyName );
+ if ( handlerPos == m_aPropertyHandlers.end() )
+ throw RuntimeException();
+ return handlerPos->second;
+ }
+
+
+ Any OPropertyBrowserController::impl_getPropertyValue_throw( const OUString& _rPropertyName )
+ {
+ PropertyHandlerRef handler = impl_getHandlerForProperty_throw( _rPropertyName );
+ return handler->getPropertyValue( _rPropertyName );
+ }
+
+
+ void OPropertyBrowserController::impl_rebindToInspectee_nothrow( InterfaceArray&& _rObjects )
+ {
+ try
+ {
+ // stop inspecting the old object(s)
+ stopInspection( true );
+
+ // inspect the new object(s)
+ m_aInspectedObjects = std::move(_rObjects);
+ doInspection();
+
+ // update the user interface
+ UpdateUI();
+ }
+
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("extensions.propctrlr", "");
+ }
+ }
+
+
+ void OPropertyBrowserController::doInspection()
+ {
+ try
+ {
+
+ // obtain the properties of the object
+ std::vector< Property > aProperties;
+
+ PropertyHandlerArray aPropertyHandlers;
+ getPropertyHandlers( m_aInspectedObjects, aPropertyHandlers );
+
+ PropertyHandlerArray::iterator aHandler( aPropertyHandlers.begin() );
+ while ( aHandler != aPropertyHandlers.end() )
+ {
+ DBG_ASSERT( aHandler->get(), "OPropertyBrowserController::doInspection: invalid handler!" );
+
+ StlSyntaxSequence< Property > aThisHandlersProperties( (*aHandler)->getSupportedProperties() );
+
+ if ( aThisHandlersProperties.empty() )
+ {
+ // this handler doesn't know anything about the current inspectee -> ignore it
+ (*aHandler)->dispose();
+ aHandler = aPropertyHandlers.erase( aHandler );
+ continue;
+ }
+
+ // append these properties to our "all properties" array
+ aProperties.reserve( aProperties.size() + aThisHandlersProperties.size() );
+ for (const auto & aThisHandlersProperty : aThisHandlersProperties)
+ {
+ auto noPrevious = std::none_of(
+ aProperties.begin(),
+ aProperties.end(),
+ FindPropertyByName( aThisHandlersProperty.Name )
+ );
+ if ( noPrevious )
+ {
+ aProperties.push_back( aThisHandlersProperty );
+ continue;
+ }
+
+ // there already was another (previous) handler which supported this property.
+ // Don't add it to aProperties, again.
+
+ // Also, ensure that handlers which previously expressed interest in *changes*
+ // of this property are not notified.
+ // This is 'cause we have a new handler which is responsible for this property,
+ // which means it can give it a completely different meaning than the previous
+ // handler for this property is prepared for.
+ std::pair< PropertyHandlerMultiRepository::iterator, PropertyHandlerMultiRepository::iterator >
+ aDepHandlers = m_aDependencyHandlers.equal_range( aThisHandlersProperty.Name );
+ m_aDependencyHandlers.erase( aDepHandlers.first, aDepHandlers.second );
+ }
+
+ // determine the superseded properties
+ StlSyntaxSequence< OUString > aSupersededByThisHandler( (*aHandler)->getSupersededProperties() );
+ for (const auto & superseded : aSupersededByThisHandler)
+ {
+ std::vector< Property >::iterator existent = std::find_if(
+ aProperties.begin(),
+ aProperties.end(),
+ FindPropertyByName( superseded )
+ );
+ if ( existent != aProperties.end() )
+ // one of the properties superseded by this handler was supported by a previous
+ // one -> erase
+ aProperties.erase( existent );
+ }
+
+ // be notified of changes which this handler is responsible for
+ (*aHandler)->addPropertyChangeListener( this );
+
+ // remember this handler for every of the properties which it is responsible
+ // for
+ for (const auto & aThisHandlersProperty : aThisHandlersProperties)
+ {
+ m_aPropertyHandlers[ aThisHandlersProperty.Name ] = *aHandler;
+ // note that this implies that if two handlers support the same property,
+ // the latter wins
+ }
+
+ // see if the handler expresses interest in any actuating properties
+ StlSyntaxSequence< OUString > aInterestingActuations( (*aHandler)->getActuatingProperties() );
+ for (const auto & aInterestingActuation : aInterestingActuations)
+ {
+ m_aDependencyHandlers.emplace( aInterestingActuation, *aHandler );
+ }
+
+ ++aHandler;
+ }
+
+ // create a new composer for UI requests coming from the handlers
+ m_pUIRequestComposer.reset( new ComposedPropertyUIUpdate( getInspectorUI(), this ) );
+
+ // sort the properties by relative position, as indicated by the model
+ sal_Int32 nPos = 0;
+ for (auto const& sourceProps : aProperties)
+ {
+ sal_Int32 nRelativePropertyOrder = nPos;
+ if ( m_xModel.is() )
+ nRelativePropertyOrder = m_xModel->getPropertyOrderIndex( sourceProps.Name );
+ m_aProperties.emplace(nRelativePropertyOrder, sourceProps);
+ ++nPos;
+ }
+
+ // be notified when one of our inspectees dies
+ impl_toggleInspecteeListening_nothrow( true );
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("extensions.propctrlr", "");
+ }
+ }
+
+
+ css::awt::Size SAL_CALL OPropertyBrowserController::getMinimumSize()
+ {
+ css::awt::Size aSize;
+ if( m_xPropView )
+ return m_xPropView->getMinimumSize();
+ else
+ return aSize;
+ }
+
+
+ css::awt::Size SAL_CALL OPropertyBrowserController::getPreferredSize()
+ {
+ return getMinimumSize();
+ }
+
+
+ css::awt::Size SAL_CALL OPropertyBrowserController::calcAdjustedSize( const css::awt::Size& _rNewSize )
+ {
+ awt::Size aMinSize = getMinimumSize( );
+ awt::Size aAdjustedSize( _rNewSize );
+ if ( aAdjustedSize.Width < aMinSize.Width )
+ aAdjustedSize.Width = aMinSize.Width;
+ if ( aAdjustedSize.Height < aMinSize.Height )
+ aAdjustedSize.Height = aMinSize.Height;
+ return aAdjustedSize;
+ }
+
+
+ void OPropertyBrowserController::describePropertyLine( const Property& _rProperty, OLineDescriptor& _rDescriptor )
+ {
+ try
+ {
+ PropertyHandlerRepository::const_iterator handler = m_aPropertyHandlers.find( _rProperty.Name );
+ if ( handler == m_aPropertyHandlers.end() )
+ throw RuntimeException(); // caught below
+
+ _rDescriptor.assignFrom( handler->second->describePropertyLine( _rProperty.Name, this ) );
+
+
+ _rDescriptor.xPropertyHandler = handler->second;
+ _rDescriptor.sName = _rProperty.Name;
+ _rDescriptor.aValue = _rDescriptor.xPropertyHandler->getPropertyValue( _rProperty.Name );
+
+ if ( _rDescriptor.DisplayName.isEmpty() )
+ {
+ #ifdef DBG_UTIL
+ SAL_WARN( "extensions.propctrlr", "OPropertyBrowserController::describePropertyLine: handler did not provide a display name for '"
+ <<_rProperty.Name << "'!" );
+ #endif
+ _rDescriptor.DisplayName = _rProperty.Name;
+ }
+
+ PropertyState ePropertyState( _rDescriptor.xPropertyHandler->getPropertyState( _rProperty.Name ) );
+ if ( PropertyState_AMBIGUOUS_VALUE == ePropertyState )
+ {
+ _rDescriptor.bUnknownValue = true;
+ _rDescriptor.aValue.clear();
+ }
+
+ _rDescriptor.bReadOnly = impl_isReadOnlyModel_throw();
+
+ // for ui-testing try and distinguish different instances of the controls
+ auto xWindow = _rDescriptor.Control->getControlWindow();
+ if (weld::TransportAsXWindow* pTunnel = dynamic_cast<weld::TransportAsXWindow*>(xWindow.get()))
+ {
+ weld::Widget* m_pControlWindow = pTunnel->getWidget();
+ if (m_pControlWindow)
+ m_pControlWindow->set_buildable_name(m_pControlWindow->get_buildable_name() + "-" + _rDescriptor.DisplayName.toUtf8());
+ }
+
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "OPropertyBrowserController::describePropertyLine" );
+ }
+ }
+
+
+ void OPropertyBrowserController::impl_buildCategories_throw()
+ {
+ OSL_PRECOND( m_aPageIds.empty(), "OPropertyBrowserController::impl_buildCategories_throw: duplicate call!" );
+
+ StlSyntaxSequence< PropertyCategoryDescriptor > aCategories;
+ if ( m_xModel.is() )
+ aCategories = StlSyntaxSequence< PropertyCategoryDescriptor >(m_xModel->describeCategories());
+
+ for (auto const& category : aCategories)
+ {
+ OSL_ENSURE( m_aPageIds.find( category.ProgrammaticName ) == m_aPageIds.end(),
+ "OPropertyBrowserController::impl_buildCategories_throw: duplicate programmatic name!" );
+
+ m_aPageIds[ category.ProgrammaticName ] =
+ getPropertyBox().AppendPage( category.UIName, HelpIdUrl::getHelpId( category.HelpURL ) );
+ }
+ }
+
+
+ void OPropertyBrowserController::UpdateUI()
+ {
+ try
+ {
+ if ( !haveView() )
+ // too early, will return later
+ return;
+
+ // create our tab pages
+ impl_buildCategories_throw();
+ // (and allow for pages to be actually unused)
+ std::set< sal_uInt16 > aUsedPages;
+
+ // when building the UI below, remember which properties are actuating,
+ // to allow for an initial actuatingPropertyChanged call
+ std::vector< OUString > aActuatingProperties;
+ std::vector< Any > aActuatingPropertyValues;
+
+ // ask the handlers to describe the property UI, and insert the resulting
+ // entries into our list boxes
+ for (auto const& property : m_aProperties)
+ {
+ OLineDescriptor aDescriptor;
+ describePropertyLine( property.second, aDescriptor );
+
+ bool bIsActuatingProperty = impl_isActuatingProperty_nothrow( property.second.Name );
+
+ SAL_WARN_IF( aDescriptor.Category.isEmpty(), "extensions.propctrlr",
+ "OPropertyBrowserController::UpdateUI: empty category provided for property '"
+ << property.second.Name << "'!");
+ // finally insert this property control
+ sal_uInt16 nTargetPageId = impl_getPageIdForCategory_nothrow( aDescriptor.Category );
+ if ( nTargetPageId == sal_uInt16(-1) )
+ {
+ // this category does not yet exist. This is allowed, as an inspector model might be lazy, and not provide
+ // any category information of its own. In this case, we have a fallback ...
+ m_aPageIds[ aDescriptor.Category ] =
+ getPropertyBox().AppendPage( aDescriptor.Category, OString() );
+ nTargetPageId = impl_getPageIdForCategory_nothrow( aDescriptor.Category );
+ }
+
+ getPropertyBox().InsertEntry( aDescriptor, nTargetPageId );
+ aUsedPages.insert( nTargetPageId );
+
+ // if it's an actuating property, remember it
+ if ( bIsActuatingProperty )
+ {
+ aActuatingProperties.push_back( property.second.Name );
+ aActuatingPropertyValues.push_back( impl_getPropertyValue_throw( property.second.Name ) );
+ }
+ }
+
+ // update any dependencies for the actuating properties which we encountered
+ {
+ std::vector< Any >::const_iterator aPropertyValue = aActuatingPropertyValues.begin();
+ for (auto const& actuatingProperty : aActuatingProperties)
+ {
+ impl_broadcastPropertyChange_nothrow( actuatingProperty, *aPropertyValue, *aPropertyValue, true );
+ ++aPropertyValue;
+ }
+ }
+
+ // remove any unused pages (which we did not encounter properties for)
+ HashString2Int16 aSurvivingPageIds;
+ for (auto const& pageId : m_aPageIds)
+ {
+ if ( aUsedPages.find( pageId.second ) == aUsedPages.end() )
+ getPropertyBox().RemovePage( pageId.second );
+ else
+ aSurvivingPageIds.insert(pageId);
+ }
+ m_aPageIds.swap( aSurvivingPageIds );
+
+ getPropertyBox().Show();
+
+ // activate the first page
+ if ( !m_aPageIds.empty() )
+ {
+ Sequence< PropertyCategoryDescriptor > aCategories( m_xModel->describeCategories() );
+ if ( aCategories.hasElements() )
+ m_xPropView->activatePage( m_aPageIds[ aCategories[0].ProgrammaticName ] );
+ else
+ // allowed: if we default-created the pages ...
+ m_xPropView->activatePage( m_aPageIds.begin()->second );
+ }
+
+ // activate the previously active page (if possible)
+ if ( !m_sLastValidPageSelection.isEmpty() )
+ m_sPageSelection = m_sLastValidPageSelection;
+ selectPageFromViewData();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+
+ void OPropertyBrowserController::Clicked( const OUString& _rName, bool _bPrimary )
+ {
+ try
+ {
+ // since the browse buttons do not get the focus when clicked with the mouse,
+ // we need to commit the changes in the current property field
+ getPropertyBox().CommitModified();
+
+ PropertyHandlerRepository::const_iterator handler = m_aPropertyHandlers.find( _rName );
+ DBG_ASSERT( handler != m_aPropertyHandlers.end(), "OPropertyBrowserController::Clicked: a property without handler? This will crash!" );
+
+ ComposedUIAutoFireGuard aAutoFireGuard( *m_pUIRequestComposer );
+
+ Any aData;
+ m_xInteractiveHandler = handler->second;
+ InteractiveSelectionResult eResult =
+ handler->second->onInteractivePropertySelection( _rName, _bPrimary, aData,
+ m_pUIRequestComposer->getUIForPropertyHandler( handler->second ) );
+
+ switch ( eResult )
+ {
+ case InteractiveSelectionResult_Cancelled:
+ case InteractiveSelectionResult_Success:
+ // okay, nothing to do
+ break;
+ case InteractiveSelectionResult_ObtainedValue:
+ handler->second->setPropertyValue( _rName, aData );
+ break;
+ case InteractiveSelectionResult_Pending:
+ // also okay, we expect that the handler has disabled the UI as necessary
+ break;
+ default:
+ OSL_FAIL( "OPropertyBrowserController::Clicked: unknown result value!" );
+ break;
+ }
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ m_xInteractiveHandler = nullptr;
+ }
+
+
+ bool OPropertyBrowserController::hasPropertyByName( const OUString& _rName )
+ {
+ for (auto const& property : m_aProperties)
+ if ( property.second.Name == _rName )
+ return true;
+ return false;
+ }
+
+
+ void OPropertyBrowserController::Commit( const OUString& rName, const Any& _rValue )
+ {
+ try
+ {
+ OUString sPlcHolder = PcrRes(RID_EMBED_IMAGE_PLACEHOLDER);
+ bool bIsPlaceHolderValue = false;
+
+ if ( rName == PROPERTY_IMAGE_URL )
+ {
+ // if the prop value is the PlaceHolder
+ // can ignore it
+ OUString sVal;
+ _rValue >>= sVal;
+ if ( sVal == sPlcHolder )
+ bIsPlaceHolderValue = true;
+ }
+ m_sCommittingProperty = rName;
+
+ bool bIsActuatingProperty = impl_isActuatingProperty_nothrow( rName );
+
+ Any aOldValue;
+ if ( bIsActuatingProperty )
+ aOldValue = impl_getPropertyValue_throw( rName );
+
+ // do we have a dedicated handler for this property, which we can delegate some tasks to?
+ PropertyHandlerRef handler = impl_getHandlerForProperty_throw( rName );
+
+
+ // set the value ( only if it's not a placeholder )
+ if ( !bIsPlaceHolderValue )
+ handler->setPropertyValue( rName, _rValue );
+
+
+ // re-retrieve the value
+ Any aNormalizedValue = handler->getPropertyValue( rName );
+
+ // care for any inter-property dependencies
+ if ( bIsActuatingProperty )
+ impl_broadcastPropertyChange_nothrow( rName, aNormalizedValue, aOldValue, false );
+
+ // and display it again. This ensures proper formatting
+ getPropertyBox().SetPropertyValue( rName, aNormalizedValue, false );
+ }
+ catch(const PropertyVetoException& eVetoException)
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xPropView->getPropertyBox().getWidget(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ eVetoException.Message));
+ xInfoBox->run();
+ PropertyHandlerRef handler = impl_getHandlerForProperty_throw( rName );
+ Any aNormalizedValue = handler->getPropertyValue( rName );
+ getPropertyBox().SetPropertyValue( rName, aNormalizedValue, false );
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("extensions.propctrlr", "");
+ }
+
+ m_sCommittingProperty.clear();
+ }
+
+
+ void OPropertyBrowserController::focusGained( const Reference< XPropertyControl >& Control )
+ {
+ m_aControlObservers.notifyEach( &XPropertyControlObserver::focusGained, Control );
+ }
+
+
+ void OPropertyBrowserController::valueChanged( const Reference< XPropertyControl >& Control )
+ {
+ m_aControlObservers.notifyEach( &XPropertyControlObserver::valueChanged, Control );
+ }
+
+
+ namespace
+ {
+ Reference< XPropertyHandler > lcl_createHandler( const Reference<XComponentContext>& _rContext, const Any& _rFactoryDescriptor )
+ {
+ Reference< XPropertyHandler > xHandler;
+
+ OUString sServiceName;
+ Reference< XSingleServiceFactory > xServiceFac;
+ Reference< XSingleComponentFactory > xComponentFac;
+
+ if ( _rFactoryDescriptor >>= sServiceName )
+ xHandler.set( _rContext->getServiceManager()->createInstanceWithContext( sServiceName, _rContext ), UNO_QUERY );
+ else if ( _rFactoryDescriptor >>= xServiceFac )
+ xHandler.set(xServiceFac->createInstance(), css::uno::UNO_QUERY);
+ else if ( _rFactoryDescriptor >>= xComponentFac )
+ xHandler.set(xComponentFac->createInstanceWithContext( _rContext ), css::uno::UNO_QUERY);
+ OSL_ENSURE(xHandler.is(),"lcl_createHandler: Can not create handler");
+ return xHandler;
+ }
+ }
+
+
+ void OPropertyBrowserController::getPropertyHandlers( const InterfaceArray& _rObjects, PropertyHandlerArray& _rHandlers )
+ {
+ _rHandlers.resize( 0 );
+ if ( _rObjects.empty() )
+ return;
+
+ Sequence< Any > aHandlerFactories;
+ if ( m_xModel.is() )
+ aHandlerFactories = m_xModel->getHandlerFactories();
+
+ for ( auto const & handlerFactory : std::as_const(aHandlerFactories) )
+ {
+ if ( _rObjects.size() == 1 )
+ { // we're inspecting only one object -> one handler
+ Reference< XPropertyHandler > xHandler( lcl_createHandler( m_xContext, handlerFactory ) );
+ if ( xHandler.is() )
+ {
+ xHandler->inspect( _rObjects[0] );
+ _rHandlers.push_back( xHandler );
+ }
+ }
+ else
+ {
+ // create a single handler for every single object
+ std::vector< Reference< XPropertyHandler > > aSingleHandlers( _rObjects.size() );
+ std::vector< Reference< XPropertyHandler > >::iterator pHandler = aSingleHandlers.begin();
+
+ for (auto const& elem : _rObjects)
+ {
+ *pHandler = lcl_createHandler( m_xContext, handlerFactory );
+ if ( pHandler->is() )
+ {
+ (*pHandler)->inspect(elem);
+ ++pHandler;
+ }
+ }
+ aSingleHandlers.resize( pHandler - aSingleHandlers.begin() );
+
+ // then create a handler which composes information out of those single handlers
+ if ( !aSingleHandlers.empty() )
+ _rHandlers.push_back( new PropertyComposer( std::move(aSingleHandlers) ) );
+ }
+ }
+
+ // note that the handlers will not be used by our caller, if they indicate that there are no
+ // properties they feel responsible for
+ }
+
+
+ bool OPropertyBrowserController::impl_findObjectProperty_nothrow( const OUString& _rName, OrderedPropertyMap::const_iterator* _pProperty )
+ {
+ OrderedPropertyMap::const_iterator search = std::find_if(m_aProperties.begin(), m_aProperties.end(),
+ [&_rName](const OrderedPropertyMap::value_type& rEntry) { return rEntry.second.Name == _rName; });
+ if ( _pProperty )
+ *_pProperty = search;
+ return ( search != m_aProperties.end() );
+ }
+
+
+ void OPropertyBrowserController::rebuildPropertyUI( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !haveView() )
+ throw RuntimeException();
+
+ OrderedPropertyMap::const_iterator propertyPos;
+ if ( !impl_findObjectProperty_nothrow( _rPropertyName, &propertyPos ) )
+ return;
+
+ OLineDescriptor aDescriptor;
+ try
+ {
+ describePropertyLine( propertyPos->second, aDescriptor );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "OPropertyBrowserController::rebuildPropertyUI" );
+ }
+
+ getPropertyBox().ChangeEntry( aDescriptor );
+ }
+
+
+ void OPropertyBrowserController::enablePropertyUI( const OUString& _rPropertyName, sal_Bool _bEnable )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !haveView() )
+ throw RuntimeException();
+
+ if ( !impl_findObjectProperty_nothrow( _rPropertyName ) )
+ return;
+
+ getPropertyBox().EnablePropertyLine( _rPropertyName, _bEnable );
+ }
+
+
+ void OPropertyBrowserController::enablePropertyUIElements( const OUString& _rPropertyName, sal_Int16 _nElements, sal_Bool _bEnable )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !haveView() )
+ throw RuntimeException();
+
+ if ( !impl_findObjectProperty_nothrow( _rPropertyName ) )
+ return;
+
+ getPropertyBox().EnablePropertyControls( _rPropertyName, _nElements, _bEnable );
+ }
+
+
+ void OPropertyBrowserController::showPropertyUI( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !haveView() )
+ throw RuntimeException();
+
+ // look up the property in our object properties
+ OrderedPropertyMap::const_iterator propertyPos;
+ if ( !impl_findObjectProperty_nothrow( _rPropertyName, &propertyPos ) )
+ return;
+
+ if ( getPropertyBox().GetPropertyPos( _rPropertyName ) != EDITOR_LIST_ENTRY_NOTFOUND )
+ {
+ rebuildPropertyUI( _rPropertyName );
+ return;
+ }
+
+ OLineDescriptor aDescriptor;
+ describePropertyLine( propertyPos->second, aDescriptor );
+
+ // look for the position to insert the property
+
+ // side note: The methods GetPropertyPos and InsertEntry of the OPropertyEditor work
+ // only on the current page. This implies that it's impossible to use this method here
+ // to show property lines which are *not* on the current page.
+ // This is sufficient for now, but should be changed in the future.
+
+ // by definition, the properties in m_aProperties are in the order in which they appear in the UI
+ // So all we need is a predecessor of pProperty in m_aProperties
+ sal_uInt16 nUIPos = EDITOR_LIST_ENTRY_NOTFOUND;
+ do
+ {
+ if ( propertyPos != m_aProperties.begin() )
+ --propertyPos;
+ nUIPos = getPropertyBox().GetPropertyPos( propertyPos->second.Name );
+ }
+ while ( ( nUIPos == EDITOR_LIST_ENTRY_NOTFOUND ) && ( propertyPos != m_aProperties.begin() ) );
+
+ if ( nUIPos == EDITOR_LIST_ENTRY_NOTFOUND )
+ // insert at the very top
+ nUIPos = 0;
+ else
+ // insert right after the predecessor we found
+ ++nUIPos;
+
+ getPropertyBox().InsertEntry(
+ aDescriptor, impl_getPageIdForCategory_nothrow( aDescriptor.Category ), nUIPos );
+ }
+
+
+ void OPropertyBrowserController::hidePropertyUI( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !haveView() )
+ throw RuntimeException();
+
+ if ( !impl_findObjectProperty_nothrow( _rPropertyName ) )
+ return;
+
+ getPropertyBox().RemoveEntry( _rPropertyName );
+ }
+
+
+ void OPropertyBrowserController::showCategory( const OUString& rCategory, sal_Bool bShow )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !haveView() )
+ throw RuntimeException();
+
+ sal_uInt16 nPageId = impl_getPageIdForCategory_nothrow( rCategory );
+ OSL_ENSURE( nPageId != sal_uInt16(-1), "OPropertyBrowserController::showCategory: invalid category!" );
+
+ getPropertyBox().ShowPropertyPage( nPageId, bShow );
+ }
+
+
+ Reference< XPropertyControl > SAL_CALL OPropertyBrowserController::getPropertyControl( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !haveView() )
+ throw RuntimeException();
+
+ Reference< XPropertyControl > xControl( getPropertyBox().GetPropertyControl( _rPropertyName ) );
+ return xControl;
+ }
+
+
+ void SAL_CALL OPropertyBrowserController::registerControlObserver( const Reference< XPropertyControlObserver >& Observer )
+ {
+ m_aControlObservers.addInterface( Observer );
+ }
+
+
+ void SAL_CALL OPropertyBrowserController::revokeControlObserver( const Reference< XPropertyControlObserver >& Observer )
+ {
+ m_aControlObservers.removeInterface( Observer );
+ }
+
+
+ void SAL_CALL OPropertyBrowserController::setHelpSectionText( const OUString& _rHelpText )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !haveView() )
+ throw DisposedException();
+
+ if ( !getPropertyBox().HasHelpSection() )
+ throw NoSupportException();
+
+ getPropertyBox().SetHelpText( _rHelpText );
+ }
+
+
+ void OPropertyBrowserController::impl_broadcastPropertyChange_nothrow( const OUString& _rPropertyName, const Any& _rNewValue, const Any& _rOldValue, bool _bFirstTimeInit ) const
+ {
+ // are there one or more handlers which are interested in the actuation?
+ std::pair< PropertyHandlerMultiRepository::const_iterator, PropertyHandlerMultiRepository::const_iterator > aInterestedHandlers =
+ m_aDependencyHandlers.equal_range( _rPropertyName );
+ if ( aInterestedHandlers.first == aInterestedHandlers.second )
+ // none of our handlers is interested in this
+ return;
+
+ ComposedUIAutoFireGuard aAutoFireGuard( *m_pUIRequestComposer );
+ try
+ {
+ // collect the responses from all interested handlers
+ PropertyHandlerMultiRepository::const_iterator handler = aInterestedHandlers.first;
+ while ( handler != aInterestedHandlers.second )
+ {
+ handler->second->actuatingPropertyChanged( _rPropertyName, _rNewValue, _rOldValue,
+ m_pUIRequestComposer->getUIForPropertyHandler( handler->second ),
+ _bFirstTimeInit );
+ ++handler;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_OPropertyBrowserController_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::OPropertyBrowserController(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/propcontroller.hxx b/extensions/source/propctrlr/propcontroller.hxx
new file mode 100644
index 000000000..a56a83979
--- /dev/null
+++ b/extensions/source/propctrlr/propcontroller.hxx
@@ -0,0 +1,368 @@
+/* -*- 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 "composeduiupdate.hxx"
+#include "proplinelistener.hxx"
+#include "propcontrolobserver.hxx"
+#include "browserview.hxx"
+
+#include <com/sun/star/awt/XFocusListener.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <com/sun/star/awt/XLayoutConstrains.hpp>
+#include <com/sun/star/inspection/XPropertyControlFactory.hpp>
+#include <com/sun/star/inspection/XObjectInspector.hpp>
+#include <com/sun/star/inspection/XObjectInspectorUI.hpp>
+#include <com/sun/star/inspection/XPropertyHandler.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <comphelper/interfacecontainer2.hxx>
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/broadcasthelper.hxx>
+#include <vcl/weld.hxx>
+
+#include <map>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+namespace pcr
+{
+ class OPropertyEditor;
+ struct OLineDescriptor;
+
+ typedef ::cppu::WeakImplHelper < css::lang::XServiceInfo
+ , css::awt::XFocusListener
+ , css::awt::XLayoutConstrains
+ , css::beans::XPropertyChangeListener
+ , css::inspection::XPropertyControlFactory
+ , css::inspection::XObjectInspector
+ , css::lang::XInitialization
+ > OPropertyBrowserController_Base;
+
+ class OPropertyBrowserController
+ :public ::comphelper::OMutexAndBroadcastHelper
+ ,public OPropertyBrowserController_Base
+ ,public css::inspection::XObjectInspectorUI
+ // that's intentionally *not* part of the OPropertyBrowserController_Base
+ // We do not want this to be available in queryInterface, getTypes, and the like.
+ ,public IPropertyLineListener
+ ,public IPropertyControlObserver
+ ,public IPropertyExistenceCheck
+ {
+ private:
+ typedef std::multimap< sal_Int32, css::beans::Property > OrderedPropertyMap;
+ typedef std::vector< css::uno::Reference< css::uno::XInterface > >
+ InterfaceArray;
+
+ protected:
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+ private:
+ css::uno::Reference< css::frame::XFrame > m_xFrame;
+ css::uno::Reference< css::awt::XWindow > m_xView;
+
+ ::comphelper::OInterfaceContainerHelper2 m_aDisposeListeners;
+ ::comphelper::OInterfaceContainerHelper2 m_aControlObservers;
+ // meta data about the properties
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<OPropertyBrowserView> m_xPropView;
+
+ OUString m_sPageSelection;
+ OUString m_sLastValidPageSelection;
+
+ typedef css::uno::Reference< css::inspection::XPropertyHandler >
+ PropertyHandlerRef;
+ typedef std::vector< PropertyHandlerRef > PropertyHandlerArray;
+ typedef std::unordered_map< OUString, PropertyHandlerRef >
+ PropertyHandlerRepository;
+ typedef std::unordered_multimap< OUString, PropertyHandlerRef >
+ PropertyHandlerMultiRepository;
+ PropertyHandlerRepository m_aPropertyHandlers;
+ PropertyHandlerMultiRepository m_aDependencyHandlers;
+ PropertyHandlerRef m_xInteractiveHandler;
+
+ std::unique_ptr< ComposedPropertyUIUpdate > m_pUIRequestComposer;
+
+ /// our InspectorModel
+ css::uno::Reference< css::inspection::XObjectInspectorModel >
+ m_xModel;
+ /// the object(s) we're currently inspecting
+ InterfaceArray m_aInspectedObjects;
+ /// the properties of the currently inspected object(s)
+ OrderedPropertyMap m_aProperties;
+ /// the property we're just committing
+ OUString m_sCommittingProperty;
+
+ typedef std::unordered_map< OUString, sal_uInt16 > HashString2Int16;
+ HashString2Int16 m_aPageIds;
+
+ bool m_bContainerFocusListening;
+ bool m_bSuspendingPropertyHandlers;
+ bool m_bConstructed;
+ bool m_bBindingIntrospectee;
+
+ protected:
+ DECLARE_XINTERFACE()
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XController
+ virtual void SAL_CALL attachFrame( const css::uno::Reference< css::frame::XFrame >& xFrame ) override;
+ virtual sal_Bool SAL_CALL attachModel( const css::uno::Reference< css::frame::XModel >& xModel ) override;
+ virtual sal_Bool SAL_CALL suspend( sal_Bool bSuspend ) override;
+ virtual css::uno::Any SAL_CALL getViewData( ) override;
+ virtual void SAL_CALL restoreViewData( const css::uno::Any& Data ) override;
+ virtual css::uno::Reference< css::frame::XModel > SAL_CALL getModel( ) override;
+ virtual css::uno::Reference< css::frame::XFrame > SAL_CALL getFrame( ) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+
+ // XFocusListener
+ virtual void SAL_CALL focusGained( const css::awt::FocusEvent& _rSource ) override;
+ virtual void SAL_CALL focusLost( const css::awt::FocusEvent& _rSource ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XLayoutConstrains
+ virtual css::awt::Size SAL_CALL getMinimumSize( ) override;
+ virtual css::awt::Size SAL_CALL getPreferredSize( ) override;
+ virtual css::awt::Size SAL_CALL calcAdjustedSize( const css::awt::Size& rNewSize ) override;
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& _rEvent ) override;
+
+ /** XPropertyControlFactory
+ */
+ virtual css::uno::Reference< css::inspection::XPropertyControl > SAL_CALL createPropertyControl( ::sal_Int16 ControlType, sal_Bool CreateReadOnly ) override;
+
+ public:
+ explicit OPropertyBrowserController(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+
+ protected:
+ virtual ~OPropertyBrowserController() override;
+
+ // IPropertyLineListener
+ virtual void Clicked( const OUString& _rName, bool _bPrimary ) override;
+ virtual void Commit( const OUString& _rName, const css::uno::Any& _rVal ) override;
+
+ // IPropertyControlObserver
+ virtual void focusGained( const css::uno::Reference< css::inspection::XPropertyControl >& Control ) override;
+ virtual void valueChanged( const css::uno::Reference< css::inspection::XPropertyControl >& Control ) override;
+
+ // IPropertyExistenceCheck
+ virtual bool hasPropertyByName( const OUString& _rName ) override;
+
+ // XObjectInspectorUI
+ virtual void SAL_CALL enablePropertyUI( const OUString& _rPropertyName, sal_Bool _bEnable ) override;
+ virtual void SAL_CALL enablePropertyUIElements( const OUString& _rPropertyName, ::sal_Int16 _nElements, sal_Bool _bEnable ) override;
+ virtual void SAL_CALL rebuildPropertyUI( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL showPropertyUI( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL hidePropertyUI( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL showCategory( const OUString& _rCategory, sal_Bool _bShow ) override;
+ virtual css::uno::Reference< css::inspection::XPropertyControl > SAL_CALL getPropertyControl( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL registerControlObserver( const css::uno::Reference< css::inspection::XPropertyControlObserver >& Observer ) override;
+ virtual void SAL_CALL revokeControlObserver( const css::uno::Reference< css::inspection::XPropertyControlObserver >& Observer ) override;
+ virtual void SAL_CALL setHelpSectionText( const OUString& HelpText ) override;
+
+ // XObjectInspector
+ virtual css::uno::Reference< css::inspection::XObjectInspectorModel > SAL_CALL getInspectorModel() override;
+ virtual void SAL_CALL setInspectorModel( const css::uno::Reference< css::inspection::XObjectInspectorModel >& _inspectormodel ) override;
+ virtual css::uno::Reference< css::inspection::XObjectInspectorUI > SAL_CALL getInspectorUI() override;
+ virtual void SAL_CALL inspect( const css::uno::Sequence< css::uno::Reference< css::uno::XInterface > >& Objects ) override;
+
+ // XDispatchProvider
+ virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL queryDispatch( const css::util::URL& URL, const OUString& TargetFrameName, ::sal_Int32 SearchFlags ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& Requests ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ private:
+ void UpdateUI();
+
+ void startContainerWindowListening();
+ void stopContainerWindowListening();
+
+ // stop the inspection
+ void stopInspection( bool _bCommitModified );
+
+ bool haveView() const { return bool(m_xPropView); }
+ OPropertyEditor& getPropertyBox() { return m_xPropView->getPropertyBox(); }
+
+ // does the inspection of the objects as indicated by our model
+ void doInspection();
+
+ // bind the browser to m_xIntrospecteeAsProperty
+ void impl_rebindToInspectee_nothrow( InterfaceArray&& _rObjects );
+
+ /** retrieves special property handlers for our introspectee
+ */
+ void getPropertyHandlers( const InterfaceArray& _rObjects, PropertyHandlerArray& _rHandlers );
+
+ /** called when a property changed, to broadcast any handlers which might have
+ registered for this property
+
+ @param _bFirstTimeInit
+ if set to <FALSE/>, this is a real change in the property value, not just a call
+ for purposes of initialization.
+ */
+ void impl_broadcastPropertyChange_nothrow( const OUString& _rPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, bool _bFirstTimeInit ) const;
+
+ /** determines whether the given property is an actuating property, that is, at least one
+ handler expressed interest in changes to this property's value.
+ */
+ bool impl_isActuatingProperty_nothrow( const OUString& _rPropertyName ) const
+ {
+ return ( m_aDependencyHandlers.find( _rPropertyName ) != m_aDependencyHandlers.end() );
+ }
+
+ /** retrieves the value of the given property, by asking the appropriate XPropertyHandler
+ @param _rPropertyName
+ the name whose handler is to be obtained. Must be the name of a property
+ for which a handler is registered.
+ @throws
+ RuntimeException if there is no handler for the given property
+ @return
+ the value of this property
+ */
+ css::uno::Any
+ impl_getPropertyValue_throw( const OUString& _rPropertyName );
+
+ /// calls XPropertyHandler::suspend for all our property handlers
+ bool suspendPropertyHandlers_nothrow( bool _bSuspend );
+
+ /// suspends the complete inspector
+ bool suspendAll_nothrow();
+
+ /** selects a page according to our current view data
+ */
+ void selectPageFromViewData();
+
+ /** updates our view data from the currently active page
+ */
+ void updateViewDataFromActivePage();
+
+ /// describes the UI for the given property
+ void describePropertyLine( const css::beans::Property& _rPropertyName, OLineDescriptor& _rDescriptor );
+
+ /** retrieves the position of the property given by name in m_aProperties
+ @return
+ <TRUE/> if and only if the property could be found. In this case, <arg>_pProperty</arg> (if
+ not <NULL/> contains the iterator pointing to this property.
+ */
+ bool impl_findObjectProperty_nothrow( const OUString& _rName, OrderedPropertyMap::const_iterator* _pProperty = nullptr );
+
+ void Construct(const css::uno::Reference<css::awt::XWindow>& rContainerWindow, std::unique_ptr<weld::Builder> xBuilder);
+
+ /** retrieves the property handler for a given property name
+ @param _rPropertyName
+ the name whose handler is to be obtained. Must be the name of a property
+ for which a handler is registered.
+ @throws
+ RuntimeException if there is no handler for the given property
+ @return
+ the handler which is responsible for the given property
+ */
+ PropertyHandlerRef const &
+ impl_getHandlerForProperty_throw( const OUString& _rPropertyName ) const;
+
+ /** determines whether we have a handler for the given property
+ @param _rPropertyName
+ the name of the property for which the existence of a handler should be checked
+ */
+ bool
+ impl_hasPropertyHandlerFor_nothrow( const OUString& _rPropertyName ) const;
+
+ /** builds up m_aPageIds from InspectorModel::describeCategories, and insert all the
+ respective tab pages into our view
+ @precond
+ m_aPageIds is empty
+ @throws css::uno::RuntimeException
+ if one of the callees of this method throws this exception
+ */
+ void
+ impl_buildCategories_throw();
+
+ /** retrieves the id of the tab page which represents a given category.
+ @param _rCategoryName
+ the programmatic name of a category.
+ @return
+ the id of the tab page, or <code>(sal_uInt16)-1</code> if there
+ is no tab page for the given category
+ */
+ sal_uInt16
+ impl_getPageIdForCategory_nothrow( const OUString& _rCategoryName ) const;
+
+ /** adds or removes ourself as XEventListener to/from all our inspectees
+ */
+ void impl_toggleInspecteeListening_nothrow( bool _bOn );
+
+ /** binds the instance to a new model
+ */
+ void impl_bindToNewModel_nothrow( const css::uno::Reference< css::inspection::XObjectInspectorModel >& _rxInspectorModel );
+
+ /** initializes our view, as indicated by the model's view-relevant properties
+
+ It's allowed to call this method when no model exists, yet. In this case, nothing
+ happens.
+ */
+ void impl_initializeView_nothrow();
+
+ /** determines whether the view should be readonly.
+
+ Effectively, this means that the method simply checks the IsReadOnly attribute of the model.
+ If there is no model, <FALSE/> is returned.
+
+ @throws css::uno::RuntimeException
+ in case asking the model for its IsReadOnly attribute throws a css::uno::RuntimeException
+ itself.
+ */
+ bool impl_isReadOnlyModel_throw() const;
+
+ /** starts or stops listening at the model
+ */
+ void impl_startOrStopModelListening_nothrow( bool _bDoListen ) const;
+
+ private:
+ DECL_LINK(OnPageActivation, LinkParamNone*, void);
+
+ private:
+ // constructors
+ void createWithModel( const css::uno::Reference< css::inspection::XObjectInspectorModel >& _rxModel );
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/propcontrolobserver.hxx b/extensions/source/propctrlr/propcontrolobserver.hxx
new file mode 100644
index 000000000..93e11053d
--- /dev/null
+++ b/extensions/source/propctrlr/propcontrolobserver.hxx
@@ -0,0 +1,46 @@
+/* -*- 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/inspection/XPropertyControl.hpp>
+
+
+namespace pcr
+{
+
+
+ //= IPropertyControlObserver
+
+ /** non-UNO version of the XPropertyControlObserver
+ */
+ class IPropertyControlObserver
+ {
+ public:
+ virtual void focusGained( const css::uno::Reference< css::inspection::XPropertyControl >& Control ) = 0;
+ virtual void valueChanged( const css::uno::Reference< css::inspection::XPropertyControl >& Control ) = 0;
+
+ protected:
+ ~IPropertyControlObserver() {}
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/propertycomposer.cxx b/extensions/source/propctrlr/propertycomposer.cxx
new file mode 100644
index 000000000..d77280d9f
--- /dev/null
+++ b/extensions/source/propctrlr/propertycomposer.cxx
@@ -0,0 +1,484 @@
+/* -*- 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 "propertycomposer.hxx"
+
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <comphelper/sequence.hxx>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+
+#include <algorithm>
+#include <iterator>
+
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::inspection;
+
+
+ //= helper
+
+ namespace
+ {
+
+ struct SetPropertyValue
+ {
+ OUString sPropertyName;
+ const Any& rValue;
+ SetPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) : sPropertyName( _rPropertyName ), rValue( _rValue ) { }
+ void operator()( const Reference< XPropertyHandler >& _rHandler )
+ {
+ _rHandler->setPropertyValue( sPropertyName, rValue );
+ }
+ };
+
+
+ template < class BagType >
+ void putIntoBag( const Sequence< typename BagType::value_type >& _rArray, BagType& /* [out] */ _rBag )
+ {
+ std::copy( _rArray.begin(), _rArray.end(),
+ std::insert_iterator< BagType >( _rBag, _rBag.begin() ) );
+ }
+
+
+ template < class BagType >
+ void copyBagToArray( const BagType& /* [out] */ _rBag, Sequence< typename BagType::value_type >& _rArray )
+ {
+ _rArray.realloc( _rBag.size() );
+ std::copy( _rBag.begin(), _rBag.end(), _rArray.getArray() );
+ }
+ }
+
+
+ //= PropertyComposer
+
+
+ // TODO: there are various places where we determine the first handler in our array which
+ // supports a given property id. This is, at the moment, done with searching all handlers,
+ // which is O( n * k ) at worst (n being the number of handlers, k being the maximum number
+ // of supported properties per handler). Shouldn't we cache this? So that it is O( log k )?
+
+
+ PropertyComposer::PropertyComposer( std::vector< Reference< XPropertyHandler > >&& _rSlaveHandlers )
+ :PropertyComposer_Base ( m_aMutex )
+ ,m_aSlaveHandlers ( std::move(_rSlaveHandlers) )
+ ,m_aPropertyListeners ( m_aMutex )
+ ,m_bSupportedPropertiesAreKnown ( false )
+ {
+ if ( m_aSlaveHandlers.empty() )
+ throw IllegalArgumentException();
+
+ osl_atomic_increment( &m_refCount );
+ {
+ Reference< XPropertyChangeListener > xMeMyselfAndI( this );
+ for (auto const& slaveHandler : m_aSlaveHandlers)
+ {
+ if ( !slaveHandler.is() )
+ throw NullPointerException();
+ slaveHandler->addPropertyChangeListener( xMeMyselfAndI );
+ }
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+
+ void SAL_CALL PropertyComposer::inspect( const Reference< XInterface >& _rxIntrospectee )
+ {
+ MethodGuard aGuard( *this );
+
+ for (auto const& slaveHandler : m_aSlaveHandlers)
+ {
+ slaveHandler->inspect( _rxIntrospectee );
+ }
+ }
+
+
+ Any SAL_CALL PropertyComposer::getPropertyValue( const OUString& _rPropertyName )
+ {
+ MethodGuard aGuard( *this );
+ return m_aSlaveHandlers[0]->getPropertyValue( _rPropertyName );
+ }
+
+
+ void SAL_CALL PropertyComposer::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue )
+ {
+ MethodGuard aGuard( *this );
+ std::for_each( m_aSlaveHandlers.begin(), m_aSlaveHandlers.end(), SetPropertyValue( _rPropertyName, _rValue ) );
+ }
+
+
+ Any SAL_CALL PropertyComposer::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue )
+ {
+ MethodGuard aGuard( *this );
+ return m_aSlaveHandlers[0]->convertToPropertyValue( _rPropertyName, _rControlValue );
+ }
+
+
+ Any SAL_CALL PropertyComposer::convertToControlValue( const OUString& _rPropertyName, const Any& _rPropertyValue, const Type& _rControlValueType )
+ {
+ MethodGuard aGuard( *this );
+ return m_aSlaveHandlers[0]->convertToControlValue( _rPropertyName, _rPropertyValue, _rControlValueType );
+ }
+
+
+ PropertyState SAL_CALL PropertyComposer::getPropertyState( const OUString& _rPropertyName )
+ {
+ MethodGuard aGuard( *this );
+
+ // assume DIRECT for the moment. This will stay this way if *all* slaves
+ // tell the property has DIRECT state, and if *all* values equal
+ PropertyState eState = PropertyState_DIRECT_VALUE;
+
+ // check the master state
+ Reference< XPropertyHandler > xPrimary( *m_aSlaveHandlers.begin() );
+ Any aPrimaryValue = xPrimary->getPropertyValue( _rPropertyName );
+ eState = xPrimary->getPropertyState( _rPropertyName );
+
+ // loop through the secondary sets
+ PropertyState eSecondaryState = PropertyState_DIRECT_VALUE;
+ for ( HandlerArray::const_iterator loop = m_aSlaveHandlers.begin() + 1;
+ loop != m_aSlaveHandlers.end();
+ ++loop
+ )
+ {
+ // the secondary state
+ eSecondaryState = (*loop)->getPropertyState( _rPropertyName );
+
+ // the secondary value
+ Any aSecondaryValue( (*loop)->getPropertyValue( _rPropertyName ) );
+
+ if ( ( PropertyState_AMBIGUOUS_VALUE == eSecondaryState ) // secondary is ambiguous
+ || ( aPrimaryValue != aSecondaryValue ) // unequal values
+ )
+ {
+ eState = PropertyState_AMBIGUOUS_VALUE;
+ break;
+ }
+ }
+
+ return eState;
+ }
+
+
+ void SAL_CALL PropertyComposer::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener )
+ {
+ MethodGuard aGuard( *this );
+ m_aPropertyListeners.addInterface( _rxListener );
+ }
+
+
+ void SAL_CALL PropertyComposer::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener )
+ {
+ MethodGuard aGuard( *this );
+ m_aPropertyListeners.removeInterface( _rxListener );
+ }
+
+
+ Sequence< Property > SAL_CALL PropertyComposer::getSupportedProperties()
+ {
+ MethodGuard aGuard( *this );
+
+ if ( !m_bSupportedPropertiesAreKnown )
+ {
+ // we support a property if and only if all of our slaves support it
+
+ // initially, use all the properties of an arbitrary handler (we take the first one)
+ putIntoBag( (*m_aSlaveHandlers.begin())->getSupportedProperties(), m_aSupportedProperties );
+
+ // now intersect with the properties of *all* other handlers
+ for ( HandlerArray::const_iterator loop = m_aSlaveHandlers.begin() + 1;
+ loop != m_aSlaveHandlers.end();
+ ++loop
+ )
+ {
+ // the properties supported by the current handler
+ PropertyBag aThisRound;
+ putIntoBag( (*loop)->getSupportedProperties(), aThisRound );
+
+ // the intersection of those properties with all we already have
+ PropertyBag aIntersection;
+ std::set_intersection( aThisRound.begin(), aThisRound.end(), m_aSupportedProperties.begin(), m_aSupportedProperties.end(),
+ std::insert_iterator< PropertyBag >( aIntersection, aIntersection.begin() ), PropertyLessByName() );
+
+ m_aSupportedProperties.swap( aIntersection );
+ if ( m_aSupportedProperties.empty() )
+ break;
+ }
+
+ // remove those properties which are not composable
+ for ( PropertyBag::iterator check = m_aSupportedProperties.begin();
+ check != m_aSupportedProperties.end();
+ )
+ {
+ bool bIsComposable = isComposable( check->Name );
+ if ( !bIsComposable )
+ {
+ check = m_aSupportedProperties.erase( check );
+ }
+ else
+ ++check;
+ }
+
+ m_bSupportedPropertiesAreKnown = true;
+ }
+
+ return comphelper::containerToSequence( m_aSupportedProperties );
+ }
+
+
+ static void uniteStringArrays( const PropertyComposer::HandlerArray& _rHandlers, Sequence< OUString > (SAL_CALL XPropertyHandler::*pGetter)( ),
+ Sequence< OUString >& /* [out] */ _rUnion )
+ {
+ std::set< OUString > aUnitedBag;
+
+ Sequence< OUString > aThisRound;
+ for (auto const& handler : _rHandlers)
+ {
+ aThisRound = (handler.get()->*pGetter)();
+ putIntoBag( aThisRound, aUnitedBag );
+ }
+
+ copyBagToArray( aUnitedBag, _rUnion );
+ }
+
+
+ Sequence< OUString > SAL_CALL PropertyComposer::getSupersededProperties( )
+ {
+ MethodGuard aGuard( *this );
+
+ // we supersede those properties which are superseded by at least one of our slaves
+ Sequence< OUString > aSuperseded;
+ uniteStringArrays( m_aSlaveHandlers, &XPropertyHandler::getSupersededProperties, aSuperseded );
+ return aSuperseded;
+ }
+
+
+ Sequence< OUString > SAL_CALL PropertyComposer::getActuatingProperties( )
+ {
+ MethodGuard aGuard( *this );
+
+ // we're interested in those properties which at least one handler wants to have
+ Sequence< OUString > aActuating;
+ uniteStringArrays( m_aSlaveHandlers, &XPropertyHandler::getActuatingProperties, aActuating );
+ return aActuating;
+ }
+
+
+ LineDescriptor SAL_CALL PropertyComposer::describePropertyLine( const OUString& _rPropertyName,
+ const Reference< XPropertyControlFactory >& _rxControlFactory )
+ {
+ MethodGuard aGuard( *this );
+ return m_aSlaveHandlers[0]->describePropertyLine( _rPropertyName, _rxControlFactory );
+ }
+
+
+ sal_Bool SAL_CALL PropertyComposer::isComposable( const OUString& _rPropertyName )
+ {
+ MethodGuard aGuard( *this );
+ return m_aSlaveHandlers[0]->isComposable( _rPropertyName );
+ }
+
+
+ InteractiveSelectionResult SAL_CALL PropertyComposer::onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, Any& _rData, const Reference< XObjectInspectorUI >& _rxInspectorUI )
+ {
+ if ( !_rxInspectorUI.is() )
+ throw NullPointerException();
+
+ MethodGuard aGuard( *this );
+
+ impl_ensureUIRequestComposer( _rxInspectorUI );
+ ComposedUIAutoFireGuard aAutoFireGuard( *m_pUIRequestComposer );
+
+ // ask the first of the handlers
+ InteractiveSelectionResult eResult = (*m_aSlaveHandlers.begin())->onInteractivePropertySelection(
+ _rPropertyName,
+ _bPrimary,
+ _rData,
+ m_pUIRequestComposer->getUIForPropertyHandler( *m_aSlaveHandlers.begin() )
+ );
+
+ switch ( eResult )
+ {
+ case InteractiveSelectionResult_Cancelled:
+ // fine
+ break;
+
+ case InteractiveSelectionResult_Success:
+ case InteractiveSelectionResult_Pending:
+ OSL_FAIL( "PropertyComposer::onInteractivePropertySelection: no chance to forward the new value to the other handlers!" );
+ // This means that we cannot know the new property value, which either has already been set
+ // at the first component ("Success"), or will be set later on once the asynchronous input
+ // is finished ("Pending"). So, we also cannot forward this new property value to the other
+ // handlers.
+ // We would need to be a listener at the property at the first component, but even this wouldn't
+ // be sufficient, since the property handler is free to change *any* property during a dedicated
+ // property UI.
+ eResult = InteractiveSelectionResult_Cancelled;
+ break;
+
+ case InteractiveSelectionResult_ObtainedValue:
+ // OK. Our own caller will pass this as setPropertyValue, and we will then pass it to
+ // all slave handlers
+ break;
+
+ default:
+ OSL_FAIL( "OPropertyBrowserController::onInteractivePropertySelection: unknown result value!" );
+ break;
+ }
+
+ return eResult;
+ }
+
+
+ void PropertyComposer::impl_ensureUIRequestComposer( const Reference< XObjectInspectorUI >& _rxInspectorUI )
+ {
+ OSL_ENSURE(!m_pUIRequestComposer
+ || m_pUIRequestComposer->getDelegatorUI().get() == _rxInspectorUI.get(),
+ "PropertyComposer::impl_ensureUIRequestComposer: somebody's changing the horse "
+ "in the mid of the race!");
+
+ if (!m_pUIRequestComposer)
+ m_pUIRequestComposer.reset( new ComposedPropertyUIUpdate( _rxInspectorUI, this ) );
+ }
+
+
+ void SAL_CALL PropertyComposer::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& _rOldValue, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit )
+ {
+ if ( !_rxInspectorUI.is() )
+ throw NullPointerException();
+
+ MethodGuard aGuard( *this );
+
+ impl_ensureUIRequestComposer( _rxInspectorUI );
+ ComposedUIAutoFireGuard aAutoFireGuard( *m_pUIRequestComposer );
+
+ // ask all handlers which expressed interest in this particular property, and "compose" their
+ // commands for the UIUpdater
+ for (auto const& slaveHandler : m_aSlaveHandlers)
+ {
+ // TODO: make this cheaper (cache it?)
+ const StlSyntaxSequence< OUString > aThisHandlersActuatingProps( slaveHandler->getActuatingProperties() );
+ for (const auto & aThisHandlersActuatingProp : aThisHandlersActuatingProps)
+ {
+ if ( aThisHandlersActuatingProp == _rActuatingPropertyName )
+ {
+ slaveHandler->actuatingPropertyChanged( _rActuatingPropertyName, _rNewValue, _rOldValue,
+ m_pUIRequestComposer->getUIForPropertyHandler(slaveHandler),
+ _bFirstTimeInit );
+ break;
+ }
+ }
+ }
+ }
+
+
+ IMPLEMENT_FORWARD_XCOMPONENT( PropertyComposer, PropertyComposer_Base )
+
+
+ void SAL_CALL PropertyComposer::disposing()
+ {
+ MethodGuard aGuard( *this );
+
+ // dispose our slave handlers
+ for (auto const& slaveHandler : m_aSlaveHandlers)
+ {
+ slaveHandler->removePropertyChangeListener( this );
+ slaveHandler->dispose();
+ }
+
+ clearContainer( m_aSlaveHandlers );
+
+ if (m_pUIRequestComposer)
+ m_pUIRequestComposer->dispose();
+ m_pUIRequestComposer.reset();
+ }
+
+
+ void SAL_CALL PropertyComposer::propertyChange( const PropertyChangeEvent& evt )
+ {
+ if ( !impl_isSupportedProperty_nothrow( evt.PropertyName ) )
+ // A slave handler might fire events for more properties than we support. Ignore those.
+ return;
+
+ PropertyChangeEvent aTranslatedEvent( evt );
+ try
+ {
+ aTranslatedEvent.NewValue = getPropertyValue( evt.PropertyName );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ m_aPropertyListeners.notifyEach( &XPropertyChangeListener::propertyChange, aTranslatedEvent );
+ }
+
+
+ void SAL_CALL PropertyComposer::disposing( const EventObject& Source )
+ {
+ MethodGuard aGuard( *this );
+ m_aPropertyListeners.disposeAndClear( Source );
+ }
+
+
+ sal_Bool SAL_CALL PropertyComposer::suspend( sal_Bool _bSuspend )
+ {
+ MethodGuard aGuard( *this );
+ for ( PropertyComposer::HandlerArray::const_iterator loop = m_aSlaveHandlers.begin();
+ loop != m_aSlaveHandlers.end();
+ ++loop
+ )
+ {
+ if ( !(*loop)->suspend( _bSuspend ) )
+ {
+ if ( _bSuspend && ( loop != m_aSlaveHandlers.begin() ) )
+ {
+ // if we tried to suspend, but one of the slave handlers vetoed,
+ // re-activate the handlers which actually did *not* veto
+ // the suspension
+ do
+ {
+ --loop;
+ (*loop)->suspend( false );
+ }
+ while ( loop != m_aSlaveHandlers.begin() );
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ bool PropertyComposer::hasPropertyByName( const OUString& _rName )
+ {
+ return impl_isSupportedProperty_nothrow( _rName );
+ }
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/propertycomposer.hxx b/extensions/source/propctrlr/propertycomposer.hxx
new file mode 100644
index 000000000..5bcc58e23
--- /dev/null
+++ b/extensions/source/propctrlr/propertycomposer.hxx
@@ -0,0 +1,142 @@
+/* -*- 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 "pcrcommon.hxx"
+#include "composeduiupdate.hxx"
+#include "formbrowsertools.hxx"
+
+#include <com/sun/star/inspection/XPropertyHandler.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+#include <memory>
+#include <vector>
+#include <set>
+
+
+namespace pcr
+{
+
+
+ //= PropertyComposer
+
+ typedef ::cppu::WeakComponentImplHelper < css::inspection::XPropertyHandler
+ , css::beans::XPropertyChangeListener
+ > PropertyComposer_Base;
+ /** implements an <type>XPropertyHandler</type> which composes its information
+ from a set of other property handlers
+ */
+ class PropertyComposer :public ::cppu::BaseMutex
+ ,public PropertyComposer_Base
+ ,public IPropertyExistenceCheck
+ {
+ public:
+ typedef std::vector< css::uno::Reference< css::inspection::XPropertyHandler > >
+ HandlerArray;
+
+ private:
+ HandlerArray m_aSlaveHandlers;
+ std::unique_ptr< ComposedPropertyUIUpdate > m_pUIRequestComposer;
+ PropertyChangeListeners m_aPropertyListeners;
+ bool m_bSupportedPropertiesAreKnown;
+ PropertyBag m_aSupportedProperties;
+
+ public:
+ /** constructs an <type>XPropertyHandler</type> which composes its information from a set
+ of other property handlers
+
+ @param _rSlaveHandlers
+ the set of slave handlers to invoke. Must not be <NULL/>
+ */
+ explicit PropertyComposer( std::vector< css::uno::Reference< css::inspection::XPropertyHandler > >&& _rSlaveHandlers );
+
+ public:
+ // XPropertyHandler overridables
+ virtual void SAL_CALL inspect( const css::uno::Reference< css::uno::XInterface >& _rxIntrospectee ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override;
+ virtual css::uno::Any SAL_CALL convertToPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rControlValue ) override;
+ virtual css::uno::Any SAL_CALL convertToControlValue( const OUString& _rPropertyName, const css::uno::Any& _rPropertyValue, const css::uno::Type& _rControlValueType ) override;
+ virtual css::beans::PropertyState
+ SAL_CALL getPropertyState( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+ virtual css::uno::Sequence< css::beans::Property >
+ SAL_CALL getSupportedProperties() override;
+ virtual css::uno::Sequence< OUString >
+ SAL_CALL getSupersededProperties( ) override;
+ virtual css::uno::Sequence< OUString >
+ SAL_CALL getActuatingProperties( ) override;
+ virtual css::inspection::LineDescriptor
+ SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override;
+ virtual sal_Bool SAL_CALL isComposable( const OUString& _rPropertyName ) override;
+ virtual css::inspection::InteractiveSelectionResult
+ SAL_CALL onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, css::uno::Any& _rData, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) override;
+ virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override;
+ virtual sal_Bool SAL_CALL suspend( sal_Bool _bSuspend ) override;
+
+ // XComponent
+ DECLARE_XCOMPONENT()
+ virtual void SAL_CALL disposing() override;
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // IPropertyExistenceCheck
+ virtual bool hasPropertyByName( const OUString& _rName ) override;
+
+ private:
+ /** ensures that m_pUIRequestComposer exists
+ */
+ void impl_ensureUIRequestComposer( const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI );
+
+ /** checks whether a given property exists in <member>m_aSupportedProperties</member>
+ */
+ bool impl_isSupportedProperty_nothrow( const OUString& _rPropertyName )
+ {
+ css::beans::Property aDummy; aDummy.Name = _rPropertyName;
+ return m_aSupportedProperties.find( aDummy ) != m_aSupportedProperties.end();
+ }
+
+ private:
+ class MethodGuard;
+ friend class MethodGuard;
+ class MethodGuard : public ::osl::MutexGuard
+ {
+ public:
+ explicit MethodGuard( PropertyComposer& _rInstance )
+ : ::osl::MutexGuard( _rInstance.m_aMutex )
+ {
+ if ( _rInstance.m_aSlaveHandlers.empty() )
+ throw css::lang::DisposedException( OUString(), _rInstance );
+ }
+ };
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/propertycontrolextender.cxx b/extensions/source/propctrlr/propertycontrolextender.cxx
new file mode 100644
index 000000000..142e288dd
--- /dev/null
+++ b/extensions/source/propctrlr/propertycontrolextender.cxx
@@ -0,0 +1,125 @@
+/* -*- 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 "propertycontrolextender.hxx"
+
+#include <com/sun/star/awt/KeyFunction.hpp>
+
+#include <tools/diagnose_ex.h>
+
+
+namespace pcr
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::awt::XWindow;
+ using ::com::sun::star::awt::KeyEvent;
+ using ::com::sun::star::inspection::XPropertyControl;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::inspection::XPropertyControlContext;
+
+ namespace KeyFunction = ::com::sun::star::awt::KeyFunction;
+
+
+ //= PropertyControlExtender_Data
+
+ struct PropertyControlExtender_Data
+ {
+ Reference< XPropertyControl > xControl;
+ Reference< XWindow > xControlWindow;
+ };
+
+
+ //= PropertyControlExtender
+
+
+ PropertyControlExtender::PropertyControlExtender( const Reference< XPropertyControl >& _rxObservedControl )
+ :m_pData( new PropertyControlExtender_Data )
+ {
+ try
+ {
+ m_pData->xControl.set( _rxObservedControl, UNO_SET_THROW );
+ m_pData->xControlWindow.set( m_pData->xControl->getControlWindow(), UNO_SET_THROW );
+ m_pData->xControlWindow->addKeyListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+
+ PropertyControlExtender::~PropertyControlExtender()
+ {
+ }
+
+
+ void SAL_CALL PropertyControlExtender::keyPressed( const KeyEvent& _event )
+ {
+ OSL_ENSURE( _event.Source == m_pData->xControlWindow, "PropertyControlExtender::keyPressed: where does this come from?" );
+ if ( ( _event.KeyFunc != KeyFunction::DELETE )
+ || ( _event.Modifiers != 0 )
+ )
+ return;
+
+ try
+ {
+ Reference< XPropertyControl > xControl( m_pData->xControl, UNO_SET_THROW );
+
+ // reset the value
+ xControl->setValue( Any() );
+
+ // and notify the change
+ // don't use XPropertyControl::notifyModifiedValue. It only notifies when the control content
+ // is recognized as being modified by the user, which is not the case, since we just modified
+ // it programmatically.
+ Reference< XPropertyControlContext > xControlContext( xControl->getControlContext(), UNO_SET_THROW );
+ xControlContext->valueChanged( xControl );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+
+ void SAL_CALL PropertyControlExtender::keyReleased( const KeyEvent& /*_event*/ )
+ {
+ // not interested in
+ }
+
+
+ void SAL_CALL PropertyControlExtender::disposing( const EventObject& Source )
+ {
+ OSL_ENSURE( Source.Source == m_pData->xControlWindow, "PropertyControlExtender::disposing: where does this come from?" );
+ (void)Source.Source;
+ m_pData->xControlWindow.clear();
+ m_pData->xControl.clear();
+ }
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/propertycontrolextender.hxx b/extensions/source/propctrlr/propertycontrolextender.hxx
new file mode 100644
index 000000000..ed7c4a06c
--- /dev/null
+++ b/extensions/source/propctrlr/propertycontrolextender.hxx
@@ -0,0 +1,63 @@
+/* -*- 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/awt/XKeyListener.hpp>
+#include <com/sun/star/inspection/XPropertyControl.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <memory>
+
+
+namespace pcr
+{
+
+
+ //= PropertyControlExtender
+
+ struct PropertyControlExtender_Data;
+ typedef ::cppu::WeakImplHelper < css::awt::XKeyListener
+ > PropertyControlExtender_Base;
+ class PropertyControlExtender : public PropertyControlExtender_Base
+ {
+ public:
+ explicit PropertyControlExtender(
+ const css::uno::Reference< css::inspection::XPropertyControl >& _rxObservedControl
+ );
+
+ // XKeyListener
+ virtual void SAL_CALL keyPressed( const css::awt::KeyEvent& e ) override;
+ virtual void SAL_CALL keyReleased( const css::awt::KeyEvent& e ) override;
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ protected:
+ virtual ~PropertyControlExtender() override;
+
+ private:
+ std::unique_ptr< PropertyControlExtender_Data > m_pData;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/propertyeditor.cxx b/extensions/source/propctrlr/propertyeditor.cxx
new file mode 100644
index 000000000..2fcf55649
--- /dev/null
+++ b/extensions/source/propctrlr/propertyeditor.cxx
@@ -0,0 +1,380 @@
+/* -*- 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 "handlerhelper.hxx"
+#include "propertyeditor.hxx"
+#include "browserpage.hxx"
+#include "linedescriptor.hxx"
+
+#include <tools/debug.hxx>
+#include <osl/diagnose.h>
+
+namespace pcr
+{
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::inspection::XPropertyControl;
+ using ::com::sun::star::uno::Reference;
+
+ OPropertyEditor::OPropertyEditor(const css::uno::Reference<css::uno::XComponentContext>& rContext, weld::Builder& rBuilder)
+ : m_xContainer(rBuilder.weld_container("box"))
+ , m_xTabControl(rBuilder.weld_notebook("tabcontrol"))
+ , m_xControlHoldingParent(rBuilder.weld_container("controlparent")) // controls initially have this parent before they are moved
+ , m_xContext(rContext)
+ , m_pListener(nullptr)
+ , m_pObserver(nullptr)
+ , m_nNextId(1)
+ , m_bHasHelpSection(false)
+ {
+ PropertyHandlerHelper::setBuilderParent(rContext, m_xControlHoldingParent.get());
+
+ m_xTabControl->connect_leave_page(LINK(this, OPropertyEditor, OnPageDeactivate));
+ m_xTabControl->connect_enter_page(LINK(this, OPropertyEditor, OnPageActivate));
+ }
+
+ OPropertyEditor::~OPropertyEditor()
+ {
+ PropertyHandlerHelper::clearBuilderParent(m_xContext);
+ ClearAll();
+ }
+
+ void OPropertyEditor::ClearAll()
+ {
+ m_nNextId=1;
+
+ m_aPropertyPageIds.clear();
+ m_aShownPages.clear();
+ m_aHiddenPages.clear();
+
+ int nCount = m_xTabControl->get_n_pages();
+ for (int i = nCount - 1; i >= 0; --i)
+ {
+ OString sID = m_xTabControl->get_page_ident(i);
+ m_xTabControl->remove_page(sID);
+ }
+
+ assert(m_xTabControl->get_n_pages() == 0);
+ }
+
+ Size OPropertyEditor::get_preferred_size() const
+ {
+ return m_xTabControl->get_preferred_size();
+ }
+
+ void OPropertyEditor::CommitModified()
+ {
+ // commit all of my pages, if necessary
+ for (const auto& page : m_aShownPages)
+ {
+ OBrowserPage* pPage = page.second.xPage.get();
+ if (pPage && pPage->getListBox().IsModified() )
+ pPage->getListBox().CommitModified();
+ }
+ }
+
+ OBrowserPage* OPropertyEditor::getPage(const OUString& rPropertyName)
+ {
+ OBrowserPage* pPage = nullptr;
+ MapStringToPageId::const_iterator aPropertyPageIdPos = m_aPropertyPageIds.find(rPropertyName);
+ if (aPropertyPageIdPos != m_aPropertyPageIds.end())
+ pPage = getPage(aPropertyPageIdPos->second);
+ return pPage;
+ }
+
+ const OBrowserPage* OPropertyEditor::getPage( const OUString& _rPropertyName ) const
+ {
+ return const_cast< OPropertyEditor* >( this )->getPage( _rPropertyName );
+ }
+
+ OBrowserPage* OPropertyEditor::getPage(sal_uInt16 rPageId)
+ {
+ OBrowserPage* pPage = nullptr;
+ auto aPagePos = m_aShownPages.find(rPageId);
+ if (aPagePos != m_aShownPages.end())
+ pPage = aPagePos->second.xPage.get();
+ return pPage;
+ }
+
+ const OBrowserPage* OPropertyEditor::getPage(sal_uInt16 rPageId) const
+ {
+ return const_cast<OPropertyEditor*>(this)->getPage(rPageId);
+ }
+
+ sal_uInt16 OPropertyEditor::AppendPage(const OUString& rText, const OString& rHelpId)
+ {
+ // obtain a new id
+ sal_uInt16 nId = m_nNextId++;
+ // insert the id
+ OString sIdent = OString::number(nId);
+ m_xTabControl->append_page(sIdent, rText);
+
+ // create a new page
+ auto xPage = std::make_unique<OBrowserPage>(m_xTabControl->get_page(sIdent), m_xControlHoldingParent.get());
+ // some knittings
+ xPage->getListBox().SetListener(m_pListener);
+ xPage->getListBox().SetObserver(m_pObserver);
+ xPage->getListBox().EnableHelpSection(m_bHasHelpSection);
+ xPage->SetHelpId(rHelpId);
+
+ m_aShownPages[nId] = PropertyPage(m_xTabControl->get_n_pages() - 1, rText, std::move(xPage));
+
+ // immediately activate the page
+ m_xTabControl->set_current_page(sIdent);
+
+ return nId;
+ }
+
+ void OPropertyEditor::SetHelpId( const OString& rHelpId )
+ {
+ m_xTabControl->set_help_id(rHelpId);
+ }
+
+ void OPropertyEditor::RemovePage(sal_uInt16 nID)
+ {
+ auto aPagePos = m_aShownPages.find(nID);
+ if (aPagePos == m_aShownPages.end())
+ return;
+
+ m_aShownPages.erase(aPagePos);
+ OString sIdent(OString::number(nID));
+ m_xTabControl->remove_page(sIdent);
+ }
+
+ void OPropertyEditor::SetPage(sal_uInt16 nId)
+ {
+ m_xTabControl->set_current_page(OString::number(nId));
+ }
+
+ sal_uInt16 OPropertyEditor::GetCurPage() const
+ {
+ return m_xTabControl->get_current_page_ident().toUInt32();
+ }
+
+ void OPropertyEditor::forEachPage( PageOperation _pOperation )
+ {
+ int nCount = m_xTabControl->get_n_pages();
+ for (int i = 0; i < nCount; ++i)
+ {
+ sal_uInt16 nID = m_xTabControl->get_page_ident(i).toUInt32();
+ OBrowserPage* pPage = getPage(nID);
+ if (!pPage)
+ continue;
+ (this->*_pOperation)( *pPage, nullptr );
+ }
+ }
+
+ void OPropertyEditor::setPageLineListener( OBrowserPage& rPage, const void* )
+ {
+ rPage.getListBox().SetListener( m_pListener );
+ }
+
+ void OPropertyEditor::SetLineListener(IPropertyLineListener* pListener)
+ {
+ m_pListener = pListener;
+ forEachPage( &OPropertyEditor::setPageLineListener );
+ }
+
+ void OPropertyEditor::setPageControlObserver( OBrowserPage& rPage, const void* )
+ {
+ rPage.getListBox().SetObserver( m_pObserver );
+ }
+
+ void OPropertyEditor::SetControlObserver( IPropertyControlObserver* _pObserver )
+ {
+ m_pObserver = _pObserver;
+ forEachPage( &OPropertyEditor::setPageControlObserver );
+ }
+
+ void OPropertyEditor::EnableHelpSection( bool bEnable )
+ {
+ m_bHasHelpSection = bEnable;
+ forEachPage( &OPropertyEditor::enableHelpSection );
+ }
+
+ void OPropertyEditor::SetHelpText( const OUString& rHelpText )
+ {
+ int nCount = m_xTabControl->get_n_pages();
+ for (int i = 0; i < nCount; ++i)
+ {
+ sal_uInt16 nID = m_xTabControl->get_page_ident(i).toUInt32();
+ OBrowserPage* pPage = getPage(nID);
+ if (!pPage)
+ continue;
+ setHelpSectionText( *pPage, &rHelpText );
+ }
+ }
+
+ void OPropertyEditor::enableHelpSection( OBrowserPage& rPage, const void* )
+ {
+ rPage.getListBox().EnableHelpSection( m_bHasHelpSection );
+ }
+
+ void OPropertyEditor::setHelpSectionText( OBrowserPage& rPage, const void* pPointerToOUString )
+ {
+ OSL_ENSURE( pPointerToOUString, "OPropertyEditor::setHelpSectionText: invalid argument!" );
+ if ( !pPointerToOUString )
+ return;
+
+ const OUString& rText( *static_cast<const OUString*>(pPointerToOUString) );
+ rPage.getListBox().SetHelpText( rText );
+ }
+
+ void OPropertyEditor::InsertEntry( const OLineDescriptor& rData, sal_uInt16 nPageId, sal_uInt16 nPos )
+ {
+ // let the current page handle this
+ OBrowserPage* pPage = getPage(nPageId);
+ DBG_ASSERT( pPage, "OPropertyEditor::InsertEntry: don't have such a page!" );
+ if ( !pPage )
+ return;
+
+ pPage->getListBox().InsertEntry( rData, nPos );
+
+ OSL_ENSURE( m_aPropertyPageIds.find( rData.sName ) == m_aPropertyPageIds.end(),
+ "OPropertyEditor::InsertEntry: property already present in the map!" );
+ m_aPropertyPageIds.emplace( rData.sName, nPageId );
+ }
+
+ void OPropertyEditor::RemoveEntry( const OUString& rName )
+ {
+ OBrowserPage* pPage = getPage( rName );
+ if ( pPage )
+ {
+ OSL_VERIFY( pPage->getListBox().RemoveEntry( rName ) );
+
+ OSL_ENSURE( m_aPropertyPageIds.find( rName ) != m_aPropertyPageIds.end(),
+ "OPropertyEditor::RemoveEntry: property not present in the map!" );
+ m_aPropertyPageIds.erase( rName );
+ }
+ }
+
+ void OPropertyEditor::ChangeEntry( const OLineDescriptor& rData )
+ {
+ OBrowserPage* pPage = getPage( rData.sName );
+ if ( pPage )
+ pPage->getListBox().ChangeEntry( rData, EDITOR_LIST_REPLACE_EXISTING );
+ }
+
+ void OPropertyEditor::SetPropertyValue( const OUString& rEntryName, const Any& _rValue, bool _bUnknownValue )
+ {
+ OBrowserPage* pPage = getPage( rEntryName );
+ if ( pPage )
+ pPage->getListBox().SetPropertyValue( rEntryName, _rValue, _bUnknownValue );
+ }
+
+ sal_uInt16 OPropertyEditor::GetPropertyPos( const OUString& rEntryName ) const
+ {
+ sal_uInt16 nVal=EDITOR_LIST_ENTRY_NOTFOUND;
+ const OBrowserPage* pPage = getPage( rEntryName );
+ if ( pPage )
+ nVal = pPage->getListBox().GetPropertyPos( rEntryName );
+ return nVal;
+ }
+
+ void OPropertyEditor::ShowPropertyPage(sal_uInt16 nPageId, bool bShow)
+ {
+ assert((m_aHiddenPages.find(nPageId) != m_aHiddenPages.end() ||
+ m_aShownPages.find(nPageId) != m_aShownPages.end()) && "page doesn't exist");
+ OString sIdent(OString::number(nPageId));
+ if (!bShow)
+ {
+ auto aPagePos = m_aShownPages.find(nPageId);
+ if (aPagePos != m_aShownPages.end())
+ {
+ aPagePos->second.xPage->detach();
+ m_xTabControl->remove_page(sIdent);
+
+ m_aHiddenPages[nPageId] = std::move(aPagePos->second);
+ m_aShownPages.erase(aPagePos);
+ }
+ }
+ else
+ {
+ auto aPagePos = m_aHiddenPages.find(nPageId);
+ if (aPagePos != m_aHiddenPages.end())
+ {
+ m_xTabControl->insert_page(sIdent, aPagePos->second.sLabel, aPagePos->second.nPos);
+ aPagePos->second.xPage->reattach(m_xTabControl->get_page(sIdent));
+
+ m_aShownPages[nPageId] = std::move(aPagePos->second);
+ m_aHiddenPages.erase(aPagePos);
+ }
+ }
+ }
+
+ void OPropertyEditor::EnablePropertyControls( const OUString& rEntryName, sal_Int16 nControls, bool bEnable )
+ {
+ for (const auto& rPage : m_aShownPages)
+ {
+ OBrowserPage* pPage = rPage.second.xPage.get();
+ if (pPage)
+ pPage->getListBox().EnablePropertyControls( rEntryName, nControls, bEnable );
+ }
+ }
+
+ void OPropertyEditor::EnablePropertyLine( const OUString& rEntryName, bool bEnable )
+ {
+ for (const auto& rPage : m_aShownPages)
+ {
+ OBrowserPage* pPage = rPage.second.xPage.get();
+ if (pPage)
+ pPage->getListBox().EnablePropertyLine( rEntryName, bEnable );
+ }
+ }
+
+ Reference< XPropertyControl > OPropertyEditor::GetPropertyControl(const OUString& rEntryName)
+ {
+ Reference< XPropertyControl > xControl;
+ // let the current page handle this
+ OBrowserPage* pPage = getPage(m_xTabControl->get_current_page_ident().toUInt32());
+ if (pPage)
+ xControl = pPage->getListBox().GetPropertyControl(rEntryName);
+ return xControl;
+ }
+
+ IMPL_LINK(OPropertyEditor, OnPageActivate, const OString&, rNewPage, void)
+ {
+ m_aPageActivationHandler.Call(rNewPage);
+ }
+
+ IMPL_LINK(OPropertyEditor, OnPageDeactivate, const OString&, rIdent, bool)
+ {
+ // commit the data on the current (to-be-deactivated) tab page
+ // (79404)
+ OBrowserPage* pCurrentPage = getPage(rIdent.toUInt32());
+ if (!pCurrentPage)
+ return true;
+
+ if (pCurrentPage->getListBox().IsModified())
+ pCurrentPage->getListBox().CommitModified();
+
+ return true;
+ }
+
+ OPropertyEditor::PropertyPage::PropertyPage()
+ : nPos(0)
+ {
+ }
+
+ OPropertyEditor::PropertyPage::PropertyPage(sal_uInt16 nPagePos, const OUString& rLabel, std::unique_ptr<OBrowserPage> pPage)
+ : nPos(nPagePos), sLabel(rLabel), xPage(std::move(pPage))
+ {
+ }
+
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/propertyeditor.hxx b/extensions/source/propctrlr/propertyeditor.hxx
new file mode 100644
index 000000000..1f28510ab
--- /dev/null
+++ b/extensions/source/propctrlr/propertyeditor.hxx
@@ -0,0 +1,134 @@
+/* -*- 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 "browserpage.hxx"
+#include "pcrcommon.hxx"
+
+#include <com/sun/star/inspection/XPropertyControl.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <vcl/weld.hxx>
+#include <map>
+
+namespace pcr
+{
+ class IPropertyLineListener;
+ class IPropertyControlObserver;
+ class OBrowserPage;
+ struct OLineDescriptor;
+ class OBrowserListBox;
+
+ //= OPropertyEditor
+ class OPropertyEditor final
+ {
+ private:
+ typedef std::map< OUString, sal_uInt16 > MapStringToPageId;
+ struct PropertyPage
+ {
+ sal_uInt16 nPos;
+ OUString sLabel;
+ std::unique_ptr<OBrowserPage> xPage;
+ PropertyPage();
+ PropertyPage(sal_uInt16 nPagePos, const OUString& rLabel, std::unique_ptr<OBrowserPage> pPage);
+ };
+
+ std::unique_ptr<weld::Container> m_xContainer;
+ std::unique_ptr<weld::Notebook> m_xTabControl;
+ // controls initially have this parent before they are moved
+ std::unique_ptr<weld::Container> m_xControlHoldingParent;
+ css::uno::Reference<css::uno::XComponentContext> m_xContext;
+ IPropertyLineListener* m_pListener;
+ IPropertyControlObserver* m_pObserver;
+ sal_uInt16 m_nNextId;
+ Link<const OString&,void> m_aPageActivationHandler;
+ bool m_bHasHelpSection;
+
+ MapStringToPageId m_aPropertyPageIds;
+ std::map<sal_uInt16, PropertyPage> m_aShownPages;
+ std::map<sal_uInt16, PropertyPage> m_aHiddenPages;
+
+ public:
+ explicit OPropertyEditor(const css::uno::Reference<css::uno::XComponentContext>& rContext, weld::Builder& rBuilder);
+ ~OPropertyEditor();
+
+ void SetLineListener( IPropertyLineListener* );
+ void SetControlObserver( IPropertyControlObserver* );
+
+ void EnableHelpSection( bool _bEnable );
+ bool HasHelpSection() const { return m_bHasHelpSection; }
+ void SetHelpText( const OUString& _rHelpText );
+
+ void SetHelpId( const OString& sHelpId );
+ sal_uInt16 AppendPage( const OUString& r, const OString& _rHelpId );
+ void SetPage( sal_uInt16 );
+ void RemovePage(sal_uInt16 nID);
+ sal_uInt16 GetCurPage() const;
+ void ClearAll();
+
+ void SetPropertyValue(const OUString& _rEntryName, const css::uno::Any& _rValue, bool _bUnknownValue );
+ sal_uInt16 GetPropertyPos(const OUString& rEntryName ) const;
+ css::uno::Reference< css::inspection::XPropertyControl >
+ GetPropertyControl( const OUString& rEntryName );
+ void EnablePropertyLine( const OUString& _rEntryName, bool _bEnable );
+ void EnablePropertyControls( const OUString& _rEntryName, sal_Int16 _nControls, bool _bEnable );
+
+ void ShowPropertyPage( sal_uInt16 _nPageId, bool _bShow );
+
+ void InsertEntry( const OLineDescriptor&, sal_uInt16 _nPageId, sal_uInt16 nPos = EDITOR_LIST_APPEND );
+ void RemoveEntry( const OUString& _rName );
+ void ChangeEntry( const OLineDescriptor& );
+
+ void setPageActivationHandler(const Link<const OString&,void>& _rHdl) { m_aPageActivationHandler = _rHdl; }
+
+ Size get_preferred_size() const;
+
+ weld::Widget* getWidget() const { return m_xTabControl.get(); }
+
+ void Show() { m_xTabControl->show(); }
+ void Hide() { m_xTabControl->hide(); }
+ void GrabFocus() { m_xTabControl->grab_focus(); }
+
+ void CommitModified();
+
+ private:
+ OBrowserPage* getPage( sal_uInt16 _rPageId );
+ const OBrowserPage* getPage( sal_uInt16 _rPageId ) const;
+
+ OBrowserPage* getPage( const OUString& _rPropertyName );
+ const OBrowserPage* getPage( const OUString& _rPropertyName ) const;
+
+ typedef void (OPropertyEditor::*PageOperation)( OBrowserPage&, const void* );
+ void forEachPage( PageOperation _pOperation );
+
+ void setPageLineListener( OBrowserPage& _rPage, const void* );
+ void setPageControlObserver( OBrowserPage& _rPage, const void* );
+ void enableHelpSection( OBrowserPage& _rPage, const void* );
+ static void setHelpSectionText( OBrowserPage& _rPage, const void* _pPointerToOUString );
+
+ DECL_LINK(OnPageDeactivate, const OString&, bool);
+ DECL_LINK(OnPageActivate, const OString&, void);
+ };
+
+
+} // namespace pcr
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/propertyhandler.cxx b/extensions/source/propctrlr/propertyhandler.cxx
new file mode 100644
index 000000000..53cf29fc6
--- /dev/null
+++ b/extensions/source/propctrlr/propertyhandler.cxx
@@ -0,0 +1,421 @@
+/* -*- 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 <memory>
+#include "propertyhandler.hxx"
+#include "formmetadata.hxx"
+#include "formbrowsertools.hxx"
+#include "handlerhelper.hxx"
+#include "formstrings.hxx"
+
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/script/Converter.hpp>
+
+#include <cppuhelper/supportsservice.hxx>
+#include <tools/debug.hxx>
+#include <unotools/confignode.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/syslocale.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <rtl/ref.hxx>
+
+#include <algorithm>
+
+namespace pcr
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::inspection;
+ using namespace ::comphelper;
+
+
+ PropertyHandler::PropertyHandler( const Reference< XComponentContext >& _rxContext )
+ :PropertyHandler_Base( m_aMutex )
+ ,m_bSupportedPropertiesAreKnown( false )
+ ,m_aPropertyListeners( m_aMutex )
+ ,m_xContext( _rxContext )
+ ,m_pInfoService ( new OPropertyInfoService )
+ {
+
+ m_xTypeConverter = Converter::create(_rxContext);
+ }
+
+ PropertyHandler::~PropertyHandler()
+ {
+ }
+
+ void SAL_CALL PropertyHandler::inspect( const Reference< XInterface >& _rxIntrospectee )
+ {
+ if ( !_rxIntrospectee.is() )
+ throw NullPointerException();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Reference< XPropertySet > xNewComponent( _rxIntrospectee, UNO_QUERY );
+ if ( xNewComponent == m_xComponent )
+ return;
+
+ // remove all old property change listeners
+ ::comphelper::OInterfaceIteratorHelper3 removeListener(m_aPropertyListeners);
+ ::comphelper::OInterfaceIteratorHelper3 readdListener(m_aPropertyListeners); // will copy the container as needed
+ while ( removeListener.hasMoreElements() )
+ removePropertyChangeListener( removeListener.next() );
+ OSL_ENSURE( m_aPropertyListeners.getLength() == 0, "PropertyHandler::inspect: derived classes are expected to forward the removePropertyChangeListener call to their base class (me)!" );
+
+ // remember the new component, and give derived classes the chance to react on it
+ m_xComponent = xNewComponent;
+ onNewComponent();
+
+ // add the listeners, again
+ while ( readdListener.hasMoreElements() )
+ addPropertyChangeListener( readdListener.next() );
+ }
+
+ void PropertyHandler::onNewComponent()
+ {
+ if ( m_xComponent.is() )
+ m_xComponentPropertyInfo = m_xComponent->getPropertySetInfo();
+ else
+ m_xComponentPropertyInfo.clear();
+
+ m_bSupportedPropertiesAreKnown = false;
+ m_aSupportedProperties.realloc( 0 );
+ }
+
+ Sequence< Property > SAL_CALL PropertyHandler::getSupportedProperties()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !m_bSupportedPropertiesAreKnown )
+ {
+ m_aSupportedProperties = StlSyntaxSequence<css::beans::Property>(doDescribeSupportedProperties());
+ m_bSupportedPropertiesAreKnown = true;
+ }
+ return m_aSupportedProperties;
+ }
+
+ Sequence< OUString > SAL_CALL PropertyHandler::getSupersededProperties( )
+ {
+ return Sequence< OUString >();
+ }
+
+ Sequence< OUString > SAL_CALL PropertyHandler::getActuatingProperties( )
+ {
+ return Sequence< OUString >();
+ }
+
+ Any SAL_CALL PropertyHandler::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId = m_pInfoService->getPropertyId( _rPropertyName );
+ Property aProperty( impl_getPropertyFromName_throw( _rPropertyName ) );
+
+ Any aPropertyValue;
+ if ( !_rControlValue.hasValue() )
+ // NULL is converted to NULL
+ return aPropertyValue;
+
+ if ( ( m_pInfoService->getPropertyUIFlags( nPropId ) & PROP_FLAG_ENUM ) != 0 )
+ {
+ OUString sControlValue;
+ OSL_VERIFY( _rControlValue >>= sControlValue );
+ ::rtl::Reference< IPropertyEnumRepresentation > aEnumConversion(
+ new DefaultEnumRepresentation( *m_pInfoService, aProperty.Type, nPropId ) );
+ // TODO/UNOize: cache those converters?
+ aEnumConversion->getValueFromDescription( sControlValue, aPropertyValue );
+ }
+ else
+ aPropertyValue = PropertyHandlerHelper::convertToPropertyValue(
+ m_xContext, m_xTypeConverter, aProperty, _rControlValue );
+ return aPropertyValue;
+ }
+
+ Any SAL_CALL PropertyHandler::convertToControlValue( const OUString& _rPropertyName, const Any& _rPropertyValue, const Type& _rControlValueType )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId = m_pInfoService->getPropertyId( _rPropertyName );
+
+ if ( ( m_pInfoService->getPropertyUIFlags( nPropId ) & PROP_FLAG_ENUM ) != 0 )
+ {
+ DBG_ASSERT( _rControlValueType.getTypeClass() == TypeClass_STRING, "PropertyHandler::convertToControlValue: ENUM, but not STRING?" );
+
+ ::rtl::Reference< IPropertyEnumRepresentation > aEnumConversion(
+ new DefaultEnumRepresentation( *m_pInfoService, _rPropertyValue.getValueType(), nPropId ) );
+ // TODO/UNOize: cache those converters?
+ return Any( aEnumConversion->getDescriptionForValue( _rPropertyValue ) );
+ }
+
+ return PropertyHandlerHelper::convertToControlValue(
+ m_xContext, m_xTypeConverter, _rPropertyValue, _rControlValueType );
+ }
+
+ PropertyState SAL_CALL PropertyHandler::getPropertyState( const OUString& /*_rPropertyName*/ )
+ {
+ return PropertyState_DIRECT_VALUE;
+ }
+
+ LineDescriptor SAL_CALL PropertyHandler::describePropertyLine( const OUString& _rPropertyName,
+ const Reference< XPropertyControlFactory >& _rxControlFactory )
+ {
+ if ( !_rxControlFactory.is() )
+ throw NullPointerException();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+ const Property& rProperty( impl_getPropertyFromId_throw( nPropId ) );
+
+ LineDescriptor aDescriptor;
+ if ( ( m_pInfoService->getPropertyUIFlags( nPropId ) & PROP_FLAG_ENUM ) != 0 )
+ {
+ aDescriptor.Control = PropertyHandlerHelper::createListBoxControl(
+ _rxControlFactory, m_pInfoService->getPropertyEnumRepresentations( nPropId ),
+ PropertyHandlerHelper::requiresReadOnlyControl( rProperty.Attributes ), false );
+ }
+ else
+ PropertyHandlerHelper::describePropertyLine( rProperty, aDescriptor, _rxControlFactory );
+
+ aDescriptor.HelpURL = HelpIdUrl::getHelpURL( m_pInfoService->getPropertyHelpId( nPropId ) );
+ aDescriptor.DisplayName = m_pInfoService->getPropertyTranslation( nPropId );
+
+ if ( ( m_pInfoService->getPropertyUIFlags( nPropId ) & PROP_FLAG_DATA_PROPERTY ) != 0 )
+ aDescriptor.Category = "Data";
+ else
+ aDescriptor.Category = "General";
+ return aDescriptor;
+ }
+
+ sal_Bool SAL_CALL PropertyHandler::isComposable( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return m_pInfoService->isComposeable( _rPropertyName );
+ }
+
+ InteractiveSelectionResult SAL_CALL PropertyHandler::onInteractivePropertySelection( const OUString& /*_rPropertyName*/, sal_Bool /*_bPrimary*/, Any& /*_rData*/, const Reference< XObjectInspectorUI >& /*_rxInspectorUI*/ )
+ {
+ OSL_FAIL( "PropertyHandler::onInteractivePropertySelection: not implemented!" );
+ return InteractiveSelectionResult_Cancelled;
+ }
+
+ void SAL_CALL PropertyHandler::actuatingPropertyChanged( const OUString& /*_rActuatingPropertyName*/, const Any& /*_rNewValue*/, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& /*_rxInspectorUI*/, sal_Bool /*_bFirstTimeInit*/ )
+ {
+ OSL_FAIL( "PropertyHandler::actuatingPropertyChanged: not implemented!" );
+ }
+
+ void SAL_CALL PropertyHandler::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !_rxListener.is() )
+ throw NullPointerException();
+ m_aPropertyListeners.addInterface( _rxListener );
+ }
+
+ void SAL_CALL PropertyHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_aPropertyListeners.removeInterface( _rxListener );
+ }
+
+ sal_Bool SAL_CALL PropertyHandler::suspend( sal_Bool /*_bSuspend*/ )
+ {
+ return true;
+ }
+
+ IMPLEMENT_FORWARD_XCOMPONENT( PropertyHandler, PropertyHandler_Base )
+
+ void SAL_CALL PropertyHandler::disposing()
+ {
+ m_xComponent.clear();
+ m_aPropertyListeners.clear();
+ m_xTypeConverter.clear();
+ m_aSupportedProperties.realloc( 0 );
+ }
+
+ void PropertyHandler::firePropertyChange( const OUString& _rPropName, PropertyId _nPropId, const Any& _rOldValue, const Any& _rNewValue )
+ {
+ PropertyChangeEvent aEvent;
+ aEvent.Source = m_xComponent;
+ aEvent.PropertyHandle = _nPropId;
+ aEvent.PropertyName = _rPropName;
+ aEvent.OldValue = _rOldValue;
+ aEvent.NewValue = _rNewValue;
+ m_aPropertyListeners.notifyEach( &XPropertyChangeListener::propertyChange, aEvent );
+ }
+
+ const Property* PropertyHandler::impl_getPropertyFromId_nothrow( PropertyId _nPropId ) const
+ {
+ const_cast< PropertyHandler* >( this )->getSupportedProperties();
+ const Property* pFound = std::find_if( m_aSupportedProperties.begin(), m_aSupportedProperties.end(),
+ FindPropertyByHandle( _nPropId )
+ );
+ if ( pFound != m_aSupportedProperties.end() )
+ return pFound;
+ return nullptr;
+ }
+
+ const Property& PropertyHandler::impl_getPropertyFromId_throw( PropertyId _nPropId ) const
+ {
+ const Property* pProperty = impl_getPropertyFromId_nothrow( _nPropId );
+ if ( !pProperty )
+ throw UnknownPropertyException();
+
+ return *pProperty;
+ }
+
+ const Property& PropertyHandler::impl_getPropertyFromName_throw( const OUString& _rPropertyName ) const
+ {
+ const_cast< PropertyHandler* >( this )->getSupportedProperties();
+ StlSyntaxSequence< Property >::const_iterator pFound = std::find_if( m_aSupportedProperties.begin(), m_aSupportedProperties.end(),
+ FindPropertyByName( _rPropertyName )
+ );
+ if ( pFound == m_aSupportedProperties.end() )
+ throw UnknownPropertyException(_rPropertyName);
+
+ return *pFound;
+ }
+
+ void PropertyHandler::implAddPropertyDescription( std::vector< Property >& _rProperties, const OUString& _rPropertyName, const Type& _rType, sal_Int16 _nAttribs ) const
+ {
+ _rProperties.push_back( Property(
+ _rPropertyName,
+ m_pInfoService->getPropertyId( _rPropertyName ),
+ _rType,
+ _nAttribs
+ ) );
+ }
+
+ weld::Window* PropertyHandler::impl_getDefaultDialogFrame_nothrow() const
+ {
+ return PropertyHandlerHelper::getDialogParentFrame(m_xContext);
+ }
+
+ PropertyId PropertyHandler::impl_getPropertyId_throwUnknownProperty( const OUString& _rPropertyName ) const
+ {
+ PropertyId nPropId = m_pInfoService->getPropertyId( _rPropertyName );
+ if ( nPropId == -1 )
+ throw UnknownPropertyException(_rPropertyName);
+ return nPropId;
+ }
+
+ PropertyId PropertyHandler::impl_getPropertyId_throwRuntime( const OUString& _rPropertyName ) const
+ {
+ PropertyId nPropId = m_pInfoService->getPropertyId( _rPropertyName );
+ if ( nPropId == -1 )
+ throw RuntimeException();
+ return nPropId;
+ }
+
+ PropertyId PropertyHandler::impl_getPropertyId_nothrow( const OUString& _rPropertyName ) const
+ {
+ return m_pInfoService->getPropertyId( _rPropertyName );
+ }
+
+ void PropertyHandler::impl_setContextDocumentModified_nothrow() const
+ {
+ Reference< XModifiable > xModifiable( impl_getContextDocument_nothrow(), UNO_QUERY );
+ if ( xModifiable.is() )
+ xModifiable->setModified( true );
+ }
+
+ bool PropertyHandler::impl_componentHasProperty_throw( const OUString& _rPropName ) const
+ {
+ return m_xComponentPropertyInfo.is() && m_xComponentPropertyInfo->hasPropertyByName( _rPropName );
+ }
+
+ sal_Int16 PropertyHandler::impl_getDocumentMeasurementUnit_throw() const
+ {
+ FieldUnit eUnit = FieldUnit::NONE;
+
+ Reference< XServiceInfo > xDocumentSI( impl_getContextDocument_nothrow(), UNO_QUERY );
+ OSL_ENSURE( xDocumentSI.is(), "PropertyHandlerHelper::impl_getDocumentMeasurementUnit_throw: No context document - where do I live?" );
+ if ( xDocumentSI.is() )
+ {
+ // determine the application type we live in
+ OUString sConfigurationLocation;
+ OUString sConfigurationProperty;
+ if ( xDocumentSI->supportsService( SERVICE_WEB_DOCUMENT ) )
+ { // writer
+ sConfigurationLocation = "/org.openoffice.Office.WriterWeb/Layout/Other";
+ sConfigurationProperty = "MeasureUnit";
+ }
+ else if ( xDocumentSI->supportsService( SERVICE_TEXT_DOCUMENT ) )
+ { // writer
+ sConfigurationLocation = "/org.openoffice.Office.Writer/Layout/Other";
+ sConfigurationProperty = "MeasureUnit";
+ }
+ else if ( xDocumentSI->supportsService( SERVICE_SPREADSHEET_DOCUMENT ) )
+ { // calc
+ sConfigurationLocation = "/org.openoffice.Office.Calc/Layout/Other/MeasureUnit";
+ sConfigurationProperty = "Metric";
+ }
+ else if ( xDocumentSI->supportsService( SERVICE_DRAWING_DOCUMENT ) )
+ {
+ sConfigurationLocation = "/org.openoffice.Office.Draw/Layout/Other/MeasureUnit";
+ sConfigurationProperty = "Metric";
+ }
+ else if ( xDocumentSI->supportsService( SERVICE_PRESENTATION_DOCUMENT ) )
+ {
+ sConfigurationLocation = "/org.openoffice.Office.Impress/Layout/Other/MeasureUnit";
+ sConfigurationProperty = "Metric";
+ }
+
+ // read the measurement unit from the configuration
+ if ( !(sConfigurationLocation.isEmpty() || sConfigurationProperty.isEmpty()) )
+ {
+ ::utl::OConfigurationTreeRoot aConfigTree( ::utl::OConfigurationTreeRoot::createWithComponentContext(
+ m_xContext, sConfigurationLocation, -1, ::utl::OConfigurationTreeRoot::CM_READONLY ) );
+ sal_Int32 nUnitAsInt = sal_Int32(FieldUnit::NONE);
+ aConfigTree.getNodeValue( sConfigurationProperty ) >>= nUnitAsInt;
+
+ // if this denotes a valid (and accepted) unit, then use it
+ if ( ( nUnitAsInt > sal_Int32(FieldUnit::NONE) ) && ( nUnitAsInt <= sal_Int32(FieldUnit::MM_100TH) ) )
+ eUnit = static_cast< FieldUnit >( nUnitAsInt );
+ }
+ }
+
+ if ( FieldUnit::NONE == eUnit )
+ {
+ MeasurementSystem eSystem = SvtSysLocale().GetLocaleData().getMeasurementSystemEnum();
+ eUnit = MeasurementSystem::Metric == eSystem ? FieldUnit::CM : FieldUnit::INCH;
+ }
+
+ return VCLUnoHelper::ConvertToMeasurementUnit( eUnit, 1 );
+ }
+
+ PropertyHandlerComponent::PropertyHandlerComponent( const Reference< XComponentContext >& _rxContext )
+ :PropertyHandler( _rxContext )
+ {
+ }
+
+ IMPLEMENT_FORWARD_XINTERFACE2( PropertyHandlerComponent, PropertyHandler, PropertyHandlerComponent_Base )
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2( PropertyHandlerComponent, PropertyHandler, PropertyHandlerComponent_Base )
+
+ sal_Bool SAL_CALL PropertyHandlerComponent::supportsService( const OUString& ServiceName )
+ {
+ return cppu::supportsService(this, ServiceName);
+ }
+
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/propertyhandler.hxx b/extensions/source/propctrlr/propertyhandler.hxx
new file mode 100644
index 000000000..3491a89be
--- /dev/null
+++ b/extensions/source/propctrlr/propertyhandler.hxx
@@ -0,0 +1,369 @@
+/* -*- 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 "pcrcommon.hxx"
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/Property.hpp>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/inspection/XPropertyHandler.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/implbase1.hxx>
+#include <comphelper/uno3.hxx>
+
+#include <memory>
+#include <vector>
+
+namespace com::sun::star {
+ namespace inspection {
+ struct LineDescriptor;
+ class XPropertyControlFactory;
+ }
+}
+
+namespace weld { class Window; }
+
+namespace pcr
+{
+
+
+ typedef sal_Int32 PropertyId;
+
+
+ //= PropertyHandler
+
+ class OPropertyInfoService;
+ typedef ::cppu::WeakComponentImplHelper < css::inspection::XPropertyHandler
+ > PropertyHandler_Base;
+ /** the base class for property handlers
+ */
+ class PropertyHandler : public ::cppu::BaseMutex
+ , public PropertyHandler_Base
+ {
+ private:
+ /// cache for getSupportedProperties
+ mutable StlSyntaxSequence< css::beans::Property >
+ m_aSupportedProperties;
+ mutable bool m_bSupportedPropertiesAreKnown;
+
+ private:
+ /// the property listener which has been registered
+ PropertyChangeListeners m_aPropertyListeners;
+
+ protected:
+ /// the context in which the instance was created
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ /// the component we're inspecting
+ css::uno::Reference< css::beans::XPropertySet > m_xComponent;
+ /// info about our component's properties
+ css::uno::Reference< css::beans::XPropertySetInfo > m_xComponentPropertyInfo;
+ /// type converter, needed on various occasions
+ css::uno::Reference< css::script::XTypeConverter > m_xTypeConverter;
+ /// access to property meta data
+ std::unique_ptr< OPropertyInfoService > m_pInfoService;
+
+ protected:
+ explicit PropertyHandler(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext
+ );
+ virtual ~PropertyHandler() override;
+
+ // default implementations for XPropertyHandler
+ virtual void SAL_CALL inspect( const css::uno::Reference< css::uno::XInterface >& _rxIntrospectee ) override;
+ virtual css::uno::Sequence< css::beans::Property > SAL_CALL getSupportedProperties() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupersededProperties( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getActuatingProperties( ) override;
+ virtual css::uno::Any SAL_CALL convertToPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rControlValue ) override;
+ virtual css::uno::Any SAL_CALL convertToControlValue( const OUString& _rPropertyName, const css::uno::Any& _rPropertyValue, const css::uno::Type& _rControlValueType ) override;
+ virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& _rPropertyName ) override;
+ virtual css::inspection::LineDescriptor SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override;
+ virtual sal_Bool SAL_CALL isComposable( const OUString& _rPropertyName ) override;
+ virtual css::inspection::InteractiveSelectionResult SAL_CALL onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, css::uno::Any& _rData, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) override;
+ virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+ virtual sal_Bool SAL_CALL suspend( sal_Bool _bSuspend ) override;
+
+ // XComponent
+ DECLARE_XCOMPONENT()
+ virtual void SAL_CALL disposing() override;
+
+ // own overridables
+ virtual css::uno::Sequence< css::beans::Property >
+ doDescribeSupportedProperties() const = 0;
+
+ /// called when XPropertyHandler::inspect has been called, and we thus have a new component to inspect
+ virtual void onNewComponent();
+
+ protected:
+ /** fires the change in a property value to our listener (if any)
+ @see addPropertyChangeListener
+ */
+ void firePropertyChange( const OUString& _rPropName, PropertyId _nPropId,
+ const css::uno::Any& _rOldValue, const css::uno::Any& _rNewValue );
+
+ /** retrieves a window which can be used as parent for dialogs
+ */
+ weld::Window* impl_getDefaultDialogFrame_nothrow() const;
+
+ /** retrieves the property id for a given property name
+ @throw css::beans::UnknownPropertyException
+ if the property name is not known to our ->m_pInfoService
+ */
+ PropertyId impl_getPropertyId_throwUnknownProperty( const OUString& _rPropertyName ) const;
+
+ /** retrieves the property id for a given property name
+ @throw css::uno::RuntimeException
+ if the property name is not known to our ->m_pInfoService
+ */
+ PropertyId impl_getPropertyId_throwRuntime( const OUString& _rPropertyName ) const;
+
+
+ /** retrieves the property id for a given property name
+ @returns -1
+ if the property name is not known to our ->m_pInfoService
+ */
+ PropertyId impl_getPropertyId_nothrow( const OUString& _rPropertyName ) const;
+
+ // helper for implementing doDescribeSupportedProperties
+ /** adds a description for the given string property to the given property vector
+ Most probably to be called from within getSupportedProperties
+ */
+ inline void addStringPropertyDescription(
+ std::vector< css::beans::Property >& _rProperties,
+ const OUString& _rPropertyName
+ ) const;
+
+ /** adds a description for the given int32 property to the given property vector
+ */
+ inline void addInt32PropertyDescription(
+ std::vector< css::beans::Property >& _rProperties,
+ const OUString& _rPropertyName,
+ sal_Int16 _nAttribs = 0
+ ) const;
+
+ /** adds a description for the given int16 property to the given property vector
+ */
+ inline void addInt16PropertyDescription(
+ std::vector< css::beans::Property >& _rProperties,
+ const OUString& _rPropertyName,
+ sal_Int16 _nAttribs = 0
+ ) const;
+
+ /** adds a description for the given double property to the given property vector
+ */
+ inline void addDoublePropertyDescription(
+ std::vector< css::beans::Property >& _rProperties,
+ const OUString& _rPropertyName,
+ sal_Int16 _nAttribs
+ ) const;
+
+ /** adds a description for the given date property to the given property vector
+ */
+ inline void addDatePropertyDescription(
+ std::vector< css::beans::Property >& _rProperties,
+ const OUString& _rPropertyName,
+ sal_Int16 _nAttribs
+ ) const;
+
+ /** adds a description for the given time property to the given property vector
+ */
+ inline void addTimePropertyDescription(
+ std::vector< css::beans::Property >& _rProperties,
+ const OUString& _rPropertyName,
+ sal_Int16 _nAttribs
+ ) const;
+
+ /** adds a description for the given DateTime property to the given property vector
+ */
+ inline void addDateTimePropertyDescription(
+ std::vector< css::beans::Property >& _rProperties,
+ const OUString& _rPropertyName,
+ sal_Int16 _nAttribs
+ ) const;
+
+ /// adds a Property, given by name only, to a given vector of Properties
+ void implAddPropertyDescription(
+ std::vector< css::beans::Property >& _rProperties,
+ const OUString& _rPropertyName,
+ const css::uno::Type& _rType,
+ sal_Int16 _nAttribs = 0
+ ) const;
+
+
+ // helper for accessing and maintaining meta data about our supported properties
+
+ /** retrieves a property given by handle
+
+ @return
+ a pointer to the descriptor for the given properties, if it is one of our
+ supported properties, <NULL/> else.
+
+ @see doDescribeSupportedProperties
+ @see impl_getPropertyFromId_throw
+ */
+ const css::beans::Property*
+ impl_getPropertyFromId_nothrow( PropertyId _nPropId ) const;
+
+ /** retrieves a property given by handle
+
+ @throws UnknownPropertyException
+ if the handler does not support a property with the given handle
+
+ @seealso doDescribeSupportedProperties
+ @see impl_getPropertyFromId_nothrow
+ */
+ const css::beans::Property&
+ impl_getPropertyFromId_throw( PropertyId _nPropId ) const;
+
+ /** determines whether a given property id is part of our supported properties
+ @see getSupportedProperties
+ @see doDescribeSupportedProperties
+ */
+ bool impl_isSupportedProperty_nothrow( PropertyId _nPropId ) const
+ {
+ return impl_getPropertyFromId_nothrow( _nPropId ) != nullptr;
+ }
+
+ /** retrieves a property given by name
+
+ @throws UnknownPropertyException
+ if the handler does not support a property with the given name
+
+ @seealso doDescribeSupportedProperties
+ */
+ const css::beans::Property&
+ impl_getPropertyFromName_throw( const OUString& _rPropertyName ) const;
+
+ /** get the name of a property given by handle
+ */
+ inline OUString
+ impl_getPropertyNameFromId_nothrow( PropertyId _nPropId ) const;
+
+ /** returns the value of the ContextDocument property in the ComponentContext which was used to create
+ this handler.
+ */
+ css::uno::Reference< css::frame::XModel >
+ impl_getContextDocument_nothrow() const
+ {
+ return css::uno::Reference< css::frame::XModel >(
+ m_xContext->getValueByName( "ContextDocument" ), css::uno::UNO_QUERY );
+ }
+
+ /** marks the context document as modified
+
+ @see impl_getContextDocument_nothrow
+ */
+ void impl_setContextDocumentModified_nothrow() const;
+
+ /// determines whether our component has a given property
+ bool impl_componentHasProperty_throw( const OUString& _rPropName ) const;
+
+ /** determines the default measure unit for the document in which our component lives
+ */
+ sal_Int16 impl_getDocumentMeasurementUnit_throw() const;
+
+ private:
+ PropertyHandler( const PropertyHandler& ) = delete;
+ PropertyHandler& operator=( const PropertyHandler& ) = delete;
+ };
+
+
+ inline void PropertyHandler::addStringPropertyDescription( std::vector< css::beans::Property >& _rProperties, const OUString& _rPropertyName ) const
+ {
+ implAddPropertyDescription( _rProperties, _rPropertyName, ::cppu::UnoType<OUString>::get() );
+ }
+
+ inline void PropertyHandler::addInt32PropertyDescription( std::vector< css::beans::Property >& _rProperties, const OUString& _rPropertyName, sal_Int16 _nAttribs ) const
+ {
+ implAddPropertyDescription( _rProperties, _rPropertyName, ::cppu::UnoType<sal_Int32>::get(), _nAttribs );
+ }
+
+ inline void PropertyHandler::addInt16PropertyDescription( std::vector< css::beans::Property >& _rProperties, const OUString& _rPropertyName, sal_Int16 _nAttribs ) const
+ {
+ implAddPropertyDescription( _rProperties, _rPropertyName, ::cppu::UnoType<sal_Int16>::get(), _nAttribs );
+ }
+
+ inline void PropertyHandler::addDoublePropertyDescription( std::vector< css::beans::Property >& _rProperties, const OUString& _rPropertyName, sal_Int16 _nAttribs ) const
+ {
+ implAddPropertyDescription( _rProperties, _rPropertyName, ::cppu::UnoType<double>::get(), _nAttribs );
+ }
+
+ inline void PropertyHandler::addDatePropertyDescription( std::vector< css::beans::Property >& _rProperties, const OUString& _rPropertyName, sal_Int16 _nAttribs ) const
+ {
+ implAddPropertyDescription( _rProperties, _rPropertyName, ::cppu::UnoType<css::util::Date>::get(), _nAttribs );
+ }
+
+ inline void PropertyHandler::addTimePropertyDescription( std::vector< css::beans::Property >& _rProperties, const OUString& _rPropertyName, sal_Int16 _nAttribs ) const
+ {
+ implAddPropertyDescription( _rProperties, _rPropertyName, ::cppu::UnoType<css::util::Time>::get(), _nAttribs );
+ }
+
+ inline void PropertyHandler::addDateTimePropertyDescription( std::vector< css::beans::Property >& _rProperties, const OUString& _rPropertyName, sal_Int16 _nAttribs ) const
+ {
+ implAddPropertyDescription( _rProperties, _rPropertyName, ::cppu::UnoType<css::util::DateTime>::get(), _nAttribs );
+ }
+
+ inline OUString PropertyHandler::impl_getPropertyNameFromId_nothrow( PropertyId _nPropId ) const
+ {
+ const css::beans::Property* pProp = impl_getPropertyFromId_nothrow( _nPropId );
+ return pProp ? pProp->Name : OUString();
+ }
+
+
+ //= PropertyHandlerComponent
+
+ typedef ::cppu::ImplHelper1 < css::lang::XServiceInfo
+ > PropertyHandlerComponent_Base;
+ /** PropertyHandler implementation which additionally supports XServiceInfo
+ */
+ class PropertyHandlerComponent :public PropertyHandler
+ ,public PropertyHandlerComponent_Base
+ {
+ protected:
+ explicit PropertyHandlerComponent(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext
+ );
+
+ DECLARE_XINTERFACE()
+ DECLARE_XTYPEPROVIDER()
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override = 0;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) final override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override = 0;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/propertyinfo.hxx b/extensions/source/propctrlr/propertyinfo.hxx
new file mode 100644
index 000000000..592557c2a
--- /dev/null
+++ b/extensions/source/propctrlr/propertyinfo.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <rtl/ustring.hxx>
+#include <vector>
+
+
+namespace pcr
+{
+
+
+ //= IPropertyInfoService
+
+ class SAL_NO_VTABLE IPropertyInfoService
+ {
+ public:
+ virtual sal_Int32 getPropertyId(const OUString& _rName) const = 0;
+ virtual OUString getPropertyTranslation(sal_Int32 _nId) const = 0;
+ virtual OUString getPropertyHelpId(sal_Int32 _nId) const = 0;
+ virtual sal_Int16 getPropertyPos(sal_Int32 _nId) const = 0;
+ virtual sal_uInt32 getPropertyUIFlags(sal_Int32 _nId) const = 0;
+ virtual std::vector< OUString > getPropertyEnumRepresentations(sal_Int32 _nId) const = 0;
+
+ virtual ~IPropertyInfoService() { }
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/propeventtranslation.cxx b/extensions/source/propctrlr/propeventtranslation.cxx
new file mode 100644
index 000000000..736c1e06f
--- /dev/null
+++ b/extensions/source/propctrlr/propeventtranslation.cxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "propeventtranslation.hxx"
+
+#include <com/sun/star/lang/DisposedException.hpp>
+
+
+namespace pcr
+{
+
+
+ using ::com::sun::star::beans::PropertyChangeEvent;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::beans::XPropertyChangeListener;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::lang::DisposedException;
+
+
+ //= PropertyEventTranslation
+
+
+ PropertyEventTranslation::PropertyEventTranslation( const Reference< XPropertyChangeListener >& _rxDelegator,
+ const Reference< XInterface >& _rxTranslatedEventSource )
+ :m_xDelegator( _rxDelegator )
+ ,m_xTranslatedEventSource( _rxTranslatedEventSource )
+ {
+ if ( !m_xDelegator.is() )
+ throw RuntimeException();
+ }
+
+
+ void SAL_CALL PropertyEventTranslation::propertyChange( const PropertyChangeEvent& evt )
+ {
+ if ( !m_xDelegator.is() )
+ throw DisposedException();
+
+ if ( !m_xTranslatedEventSource.is() )
+ m_xDelegator->propertyChange( evt );
+ else
+ {
+ PropertyChangeEvent aTranslatedEvent( evt );
+ aTranslatedEvent.Source = m_xTranslatedEventSource;
+ m_xDelegator->propertyChange( aTranslatedEvent );
+ }
+ }
+
+
+ void SAL_CALL PropertyEventTranslation::disposing( const EventObject& Source )
+ {
+ if ( !m_xDelegator.is() )
+ throw DisposedException();
+
+ if ( !m_xTranslatedEventSource.is() )
+ m_xDelegator->disposing( Source );
+ else
+ {
+ EventObject aTranslatedEvent( Source );
+ aTranslatedEvent.Source = m_xTranslatedEventSource;
+ m_xDelegator->disposing( aTranslatedEvent );
+ }
+
+ m_xDelegator.clear();
+ m_xTranslatedEventSource.clear();
+ }
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/propeventtranslation.hxx b/extensions/source/propctrlr/propeventtranslation.hxx
new file mode 100644
index 000000000..43155b8c6
--- /dev/null
+++ b/extensions/source/propctrlr/propeventtranslation.hxx
@@ -0,0 +1,70 @@
+/* -*- 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/beans/XPropertyChangeListener.hpp>
+#include <cppuhelper/implbase.hxx>
+
+
+namespace pcr
+{
+
+
+ //= PropertyEventTranslation
+
+ typedef ::cppu::WeakImplHelper < css::beans::XPropertyChangeListener
+ > PropertyEventTranslation_Base;
+
+ class PropertyEventTranslation : public PropertyEventTranslation_Base
+ {
+ css::uno::Reference< css::beans::XPropertyChangeListener >
+ m_xDelegator;
+ css::uno::Reference< css::uno::XInterface >
+ m_xTranslatedEventSource;
+
+ public:
+ /** constructs the object
+ @throws NullPointerException
+ if <arg>_rxDelegator</arg> is <NULL/>
+ */
+ PropertyEventTranslation(
+ const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxDelegator,
+ const css::uno::Reference< css::uno::XInterface >& _rxTranslatedEventSource
+ );
+
+ const css::uno::Reference< css::beans::XPropertyChangeListener >&
+ getDelegator() const { return m_xDelegator; }
+
+ protected:
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ private:
+ PropertyEventTranslation( const PropertyEventTranslation& ) = delete;
+ PropertyEventTranslation& operator=( const PropertyEventTranslation& ) = delete;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/proplinelistener.hxx b/extensions/source/propctrlr/proplinelistener.hxx
new file mode 100644
index 000000000..6931a1f33
--- /dev/null
+++ b/extensions/source/propctrlr/proplinelistener.hxx
@@ -0,0 +1,43 @@
+/* -*- 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 <rtl/ustring.hxx>
+#include <com/sun/star/uno/Any.hxx>
+
+namespace pcr
+{
+
+
+ class IPropertyLineListener
+ {
+ public:
+ virtual void Clicked( const OUString& _rName, bool _bPrimary ) = 0;
+ virtual void Commit( const OUString& _rName, const css::uno::Any& _rVal ) = 0;
+
+ protected:
+ ~IPropertyLineListener() {}
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/pushbuttonnavigation.cxx b/extensions/source/propctrlr/pushbuttonnavigation.cxx
new file mode 100644
index 000000000..449ffd583
--- /dev/null
+++ b/extensions/source/propctrlr/pushbuttonnavigation.cxx
@@ -0,0 +1,298 @@
+/* -*- 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 "pushbuttonnavigation.hxx"
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include "formstrings.hxx"
+#include <comphelper/extract.hxx>
+#include <comphelper/property.hxx>
+#include <o3tl/string_view.hxx>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::form;
+
+
+ namespace
+ {
+ const sal_Int32 s_nFirstVirtualButtonType = 1 + sal_Int32(FormButtonType_URL);
+
+ const char* pNavigationURLs[] =
+ {
+ ".uno:FormController/moveToFirst",
+ ".uno:FormController/moveToPrev",
+ ".uno:FormController/moveToNext",
+ ".uno:FormController/moveToLast",
+ ".uno:FormController/saveRecord",
+ ".uno:FormController/undoRecord",
+ ".uno:FormController/moveToNew",
+ ".uno:FormController/deleteRecord",
+ ".uno:FormController/refreshForm",
+ nullptr
+ };
+
+ sal_Int32 lcl_getNavigationURLIndex( std::u16string_view _rNavURL )
+ {
+ const char** pLookup = pNavigationURLs;
+ while ( *pLookup )
+ {
+ if ( o3tl::equalsAscii( _rNavURL, *pLookup ) )
+ return pLookup - pNavigationURLs;
+ ++pLookup;
+ }
+ return -1;
+ }
+
+ const char* lcl_getNavigationURL( sal_Int32 _nButtonTypeIndex )
+ {
+ const char** pLookup = pNavigationURLs;
+ while ( _nButtonTypeIndex-- && *pLookup++ )
+ ;
+ OSL_ENSURE( *pLookup, "lcl_getNavigationURL: invalid index!" );
+ return *pLookup;
+ }
+ }
+
+
+ //= PushButtonNavigation
+
+
+ PushButtonNavigation::PushButtonNavigation( const Reference< XPropertySet >& _rxControlModel )
+ :m_xControlModel( _rxControlModel )
+ ,m_bIsPushButton( false )
+ {
+ OSL_ENSURE( m_xControlModel.is(), "PushButtonNavigation::PushButtonNavigation: invalid control model!" );
+
+ try
+ {
+ m_bIsPushButton = ::comphelper::hasProperty( PROPERTY_BUTTONTYPE, m_xControlModel );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "PushButtonNavigation::PushButtonNavigation" );
+ }
+ }
+
+
+ FormButtonType PushButtonNavigation::implGetCurrentButtonType() const
+ {
+ sal_Int32 nButtonType = sal_Int32(FormButtonType_PUSH);
+ if ( !m_xControlModel.is() )
+ return static_cast<FormButtonType>(nButtonType);
+ OSL_VERIFY( ::cppu::enum2int( nButtonType, m_xControlModel->getPropertyValue( PROPERTY_BUTTONTYPE ) ) );
+
+ if ( nButtonType == sal_Int32(FormButtonType_URL) )
+ {
+ // there's a chance that this is a "virtual" button type
+ // (which are realized by special URLs)
+ OUString sTargetURL;
+ m_xControlModel->getPropertyValue( PROPERTY_TARGET_URL ) >>= sTargetURL;
+
+ sal_Int32 nNavigationURLIndex = lcl_getNavigationURLIndex( sTargetURL );
+ if ( nNavigationURLIndex >= 0)
+ // it actually *is* a virtual button type
+ nButtonType = s_nFirstVirtualButtonType + nNavigationURLIndex;
+ }
+ return static_cast<FormButtonType>(nButtonType);
+ }
+
+
+ Any PushButtonNavigation::getCurrentButtonType() const
+ {
+ OSL_ENSURE( m_bIsPushButton, "PushButtonNavigation::getCurrentButtonType: not expected to be called for forms!" );
+ Any aReturn;
+
+ try
+ {
+ aReturn <<= implGetCurrentButtonType();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "PushButtonNavigation::getCurrentButtonType" );
+ }
+ return aReturn;
+ }
+
+
+ void PushButtonNavigation::setCurrentButtonType( const Any& _rValue ) const
+ {
+ OSL_ENSURE( m_bIsPushButton, "PushButtonNavigation::setCurrentButtonType: not expected to be called for forms!" );
+ if ( !m_xControlModel.is() )
+ return;
+
+ try
+ {
+ sal_Int32 nButtonType = sal_Int32(FormButtonType_PUSH);
+ OSL_VERIFY( ::cppu::enum2int( nButtonType, _rValue ) );
+ OUString sTargetURL;
+
+ bool bIsVirtualButtonType = nButtonType >= s_nFirstVirtualButtonType;
+ if ( bIsVirtualButtonType )
+ {
+ const char* pURL = lcl_getNavigationURL( nButtonType - s_nFirstVirtualButtonType );
+ sTargetURL = OUString::createFromAscii( pURL );
+
+ nButtonType = sal_Int32(FormButtonType_URL);
+ }
+
+ m_xControlModel->setPropertyValue( PROPERTY_BUTTONTYPE, Any( static_cast< FormButtonType >( nButtonType ) ) );
+ m_xControlModel->setPropertyValue( PROPERTY_TARGET_URL, Any( sTargetURL ) );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "PushButtonNavigation::setCurrentButtonType" );
+ }
+ }
+
+
+ PropertyState PushButtonNavigation::getCurrentButtonTypeState( ) const
+ {
+ OSL_ENSURE( m_bIsPushButton, "PushButtonNavigation::getCurrentButtonTypeState: not expected to be called for forms!" );
+ PropertyState eState = PropertyState_DIRECT_VALUE;
+
+ try
+ {
+ Reference< XPropertyState > xStateAccess( m_xControlModel, UNO_QUERY );
+ if ( xStateAccess.is() )
+ {
+ // let's see what the model says about the ButtonType property
+ eState = xStateAccess->getPropertyState( PROPERTY_BUTTONTYPE );
+ if ( eState == PropertyState_DIRECT_VALUE )
+ {
+ sal_Int32 nRealButtonType = sal_Int32(FormButtonType_PUSH);
+ OSL_VERIFY( ::cppu::enum2int( nRealButtonType, m_xControlModel->getPropertyValue( PROPERTY_BUTTONTYPE ) ) );
+ // perhaps it's one of the virtual button types?
+ if ( sal_Int32(FormButtonType_URL) == nRealButtonType )
+ {
+ // yes, it is -> rely on the state of the URL property
+ eState = xStateAccess->getPropertyState( PROPERTY_TARGET_URL );
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "PushButtonNavigation::getCurrentButtonTypeState" );
+ }
+
+ return eState;
+ }
+
+
+ Any PushButtonNavigation::getCurrentTargetURL() const
+ {
+ Any aReturn;
+ if ( !m_xControlModel.is() )
+ return aReturn;
+
+ try
+ {
+ aReturn = m_xControlModel->getPropertyValue( PROPERTY_TARGET_URL );
+ if ( m_bIsPushButton )
+ {
+ FormButtonType nCurrentButtonType = implGetCurrentButtonType();
+ bool bIsVirtualButtonType = nCurrentButtonType >= FormButtonType(s_nFirstVirtualButtonType);
+ if ( bIsVirtualButtonType )
+ {
+ // pretend (to the user) that there's no URL set - since
+ // virtual button types imply a special (technical) URL which
+ // the user should not see
+ aReturn <<= OUString();
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "PushButtonNavigation::getCurrentTargetURL" );
+ }
+ return aReturn;
+ }
+
+
+ void PushButtonNavigation::setCurrentTargetURL( const Any& _rValue ) const
+ {
+ if ( !m_xControlModel.is() )
+ return;
+
+ try
+ {
+ m_xControlModel->setPropertyValue( PROPERTY_TARGET_URL, _rValue );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "PushButtonNavigation::setCurrentTargetURL" );
+ }
+ }
+
+
+ PropertyState PushButtonNavigation::getCurrentTargetURLState( ) const
+ {
+ PropertyState eState = PropertyState_DIRECT_VALUE;
+
+ try
+ {
+ Reference< XPropertyState > xStateAccess( m_xControlModel, UNO_QUERY );
+ if ( xStateAccess.is() )
+ {
+ eState = xStateAccess->getPropertyState( PROPERTY_TARGET_URL );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "PushButtonNavigation::setCurrentTargetURL" );
+ }
+
+ return eState;
+ }
+
+
+ bool PushButtonNavigation::currentButtonTypeIsOpenURL() const
+ {
+ FormButtonType nButtonType( FormButtonType_PUSH );
+ try
+ {
+ nButtonType = implGetCurrentButtonType();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ return nButtonType == FormButtonType_URL;
+ }
+
+
+ bool PushButtonNavigation::hasNonEmptyCurrentTargetURL() const
+ {
+ OUString sTargetURL;
+ OSL_VERIFY( getCurrentTargetURL() >>= sTargetURL );
+ return !sTargetURL.isEmpty();
+ }
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/pushbuttonnavigation.hxx b/extensions/source/propctrlr/pushbuttonnavigation.hxx
new file mode 100644
index 000000000..7248fb27d
--- /dev/null
+++ b/extensions/source/propctrlr/pushbuttonnavigation.hxx
@@ -0,0 +1,98 @@
+/* -*- 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/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <com/sun/star/form/FormButtonType.hpp>
+
+
+namespace pcr
+{
+
+
+ //= PushButtonNavigation
+
+ class PushButtonNavigation final
+ {
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xControlModel;
+ bool m_bIsPushButton;
+
+ public:
+ /** ctor
+ @param _rxControlModel
+ the control model which is or will be bound
+ */
+ explicit PushButtonNavigation(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel
+ );
+
+ /** returns the current value of the "ButtonType" property, taking into account
+ the "virtual" button types such as "move-to-next-record button".
+ */
+ css::uno::Any
+ getCurrentButtonType() const;
+
+ /** sets the current value of the "ButtonType" property, taking into account
+ the "virtual" button types such as "move-to-next-record button".
+ */
+ void setCurrentButtonType( const css::uno::Any& _rValue ) const;
+
+ /** retrieves the current state of the "ButtonType" property, taking into account
+ the "virtual" button types such as "move-to-next-record button".
+ */
+ css::beans::PropertyState
+ getCurrentButtonTypeState( ) const;
+
+ /** returns the current value of the "TargetURL" property, taking into account
+ that some URLs are special values caused by "virtual" ButtonTypes
+ */
+ css::uno::Any
+ getCurrentTargetURL() const;
+
+ /** sets the current value of the "TargetURL" property, taking into account
+ that some URLs are special values caused by "virtual" ButtonTypes
+ */
+ void setCurrentTargetURL( const css::uno::Any& _rValue ) const;
+
+ /** retrieves the current state of the "TargetURL" property, taking into account
+ that some URLs are special values caused by "virtual" ButtonTypes
+ */
+ css::beans::PropertyState
+ getCurrentTargetURLState( ) const;
+
+ /** determines whether the current button type is FormButtonType_URL
+ */
+ bool currentButtonTypeIsOpenURL() const;
+
+ /** determines whether the TargetURL property does currently denote a non-empty string
+ */
+ bool hasNonEmptyCurrentTargetURL() const;
+
+ private:
+ css::form::FormButtonType implGetCurrentButtonType() const;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/selectlabeldialog.cxx b/extensions/source/propctrlr/selectlabeldialog.cxx
new file mode 100644
index 000000000..c8c0a82a3
--- /dev/null
+++ b/extensions/source/propctrlr/selectlabeldialog.cxx
@@ -0,0 +1,279 @@
+/* -*- 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 "selectlabeldialog.hxx"
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include "formbrowsertools.hxx"
+#include "formstrings.hxx"
+#include "modulepcr.hxx"
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <comphelper/property.hxx>
+#include <comphelper/types.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::lang;
+
+
+ // OSelectLabelDialog
+ OSelectLabelDialog::OSelectLabelDialog(weld::Window* pParent, Reference< XPropertySet > const & _xControlModel)
+ : GenericDialogController(pParent, "modules/spropctrlr/ui/labelselectiondialog.ui", "LabelSelectionDialog")
+ , m_xControlModel(_xControlModel)
+ , m_bLastSelected(false)
+ , m_bHaveAssignableControl(false)
+ , m_xMainDesc(m_xBuilder->weld_label("label"))
+ , m_xControlTree(m_xBuilder->weld_tree_view("control"))
+ , m_xScratchIter(m_xControlTree->make_iterator())
+ , m_xNoAssignment(m_xBuilder->weld_check_button("noassignment"))
+ {
+ m_xControlTree->connect_changed(LINK(this, OSelectLabelDialog, OnEntrySelected));
+ m_xControlTree->set_size_request(-1, m_xControlTree->get_height_rows(8));
+
+ // fill the description
+ OUString sDescription = m_xMainDesc->get_label();
+ sal_Int16 nClassID = FormComponentType::CONTROL;
+ if (::comphelper::hasProperty(PROPERTY_CLASSID, m_xControlModel))
+ nClassID = ::comphelper::getINT16(m_xControlModel->getPropertyValue(PROPERTY_CLASSID));
+
+ sDescription = sDescription.replaceAll("$controlclass$",
+ GetUIHeadlineName(nClassID, Any(m_xControlModel)));
+ OUString sName = ::comphelper::getString(m_xControlModel->getPropertyValue(PROPERTY_NAME));
+ sDescription = sDescription.replaceAll("$controlname$", sName);
+ m_xMainDesc->set_label(sDescription);
+
+ // search for the root of the form hierarchy
+ Reference< XChild > xCont(m_xControlModel, UNO_QUERY);
+ Reference< XInterface > xSearch( xCont.is() ? xCont->getParent() : Reference< XInterface > ());
+ Reference< XResultSet > xParentAsResultSet(xSearch, UNO_QUERY);
+ while (xParentAsResultSet.is())
+ {
+ xCont.set(xSearch, UNO_QUERY);
+ xSearch = xCont.is() ? xCont->getParent() : Reference< XInterface > ();
+ xParentAsResultSet.set(xSearch, UNO_QUERY);
+ }
+
+ // and insert all entries below this root into the listbox
+ if (xSearch.is())
+ {
+ // check which service the allowed components must support
+ sal_Int16 nClassId = 0;
+ try { nClassId = ::comphelper::getINT16(m_xControlModel->getPropertyValue(PROPERTY_CLASSID)); } catch(...) { }
+ m_sRequiredService = (FormComponentType::RADIOBUTTON == nClassId) ? OUString(SERVICE_COMPONENT_GROUPBOX) : OUString(SERVICE_COMPONENT_FIXEDTEXT);
+ m_aRequiredControlImage = (FormComponentType::RADIOBUTTON == nClassId) ? OUString(RID_EXTBMP_GROUPBOX) : OUString(RID_EXTBMP_FIXEDTEXT);
+
+ // calc the currently set label control (so InsertEntries can calc m_xInitialSelection)
+ Any aCurrentLabelControl( m_xControlModel->getPropertyValue(PROPERTY_CONTROLLABEL) );
+ DBG_ASSERT((aCurrentLabelControl.getValueTypeClass() == TypeClass_INTERFACE) || !aCurrentLabelControl.hasValue(),
+
+ "OSelectLabelDialog::OSelectLabelDialog : invalid ControlLabel property !");
+ if (aCurrentLabelControl.hasValue())
+ aCurrentLabelControl >>= m_xInitialLabelControl;
+
+ // insert the root
+ OUString sRootName(PcrRes(RID_STR_FORMS));
+ m_xControlTree->insert(nullptr, -1, &sRootName, nullptr,
+ nullptr, nullptr, false, m_xScratchIter.get());
+ m_xControlTree->set_image(*m_xScratchIter, RID_EXTBMP_FORMS);
+
+ // build the tree
+ m_xInitialSelection.reset();
+ m_bHaveAssignableControl = false;
+ std::unique_ptr<weld::TreeIter> xRoot = m_xControlTree->make_iterator();
+ m_xControlTree->get_iter_first(*xRoot);
+ InsertEntries(xSearch, *xRoot);
+ m_xControlTree->expand_row(*xRoot);
+ }
+
+ if (m_xInitialSelection)
+ {
+ m_xControlTree->scroll_to_row(*m_xInitialSelection);
+ m_xControlTree->select(*m_xInitialSelection);
+ }
+ else
+ {
+ m_xControlTree->scroll_to_row(0);
+ m_xControlTree->unselect_all();
+ m_xNoAssignment->set_active(true);
+ }
+
+ if (!m_bHaveAssignableControl)
+ { // no controls which can be assigned
+ m_xNoAssignment->set_active(true);
+ m_xNoAssignment->set_sensitive(false);
+ }
+
+ m_xLastSelected = m_xControlTree->make_iterator(nullptr);
+
+ m_xNoAssignment->connect_toggled(LINK(this, OSelectLabelDialog, OnNoAssignmentClicked));
+ OnNoAssignmentClicked(*m_xNoAssignment);
+ }
+
+ OSelectLabelDialog::~OSelectLabelDialog()
+ {
+ }
+
+ sal_Int32 OSelectLabelDialog::InsertEntries(const Reference< XInterface > & _xContainer, const weld::TreeIter& rContainerEntry)
+ {
+ Reference< XIndexAccess > xContainer(_xContainer, UNO_QUERY);
+ if (!xContainer.is())
+ return 0;
+
+ sal_Int32 nChildren = 0;
+ OUString sName;
+ Reference< XPropertySet > xAsSet;
+ for (sal_Int32 i=0; i<xContainer->getCount(); ++i)
+ {
+ xContainer->getByIndex(i) >>= xAsSet;
+ if (!xAsSet.is())
+ {
+ SAL_INFO("extensions.propctrlr", "OSelectLabelDialog::InsertEntries : strange : a form component which isn't a property set !");
+ continue;
+ }
+
+ if (!::comphelper::hasProperty(PROPERTY_NAME, xAsSet))
+ // we need at least a name for displaying ...
+ continue;
+ sName = ::comphelper::getString(xAsSet->getPropertyValue(PROPERTY_NAME));
+
+ // we need to check if the control model supports the required service
+ Reference< XServiceInfo > xInfo(xAsSet, UNO_QUERY);
+ if (!xInfo.is())
+ continue;
+
+ if (!xInfo->supportsService(m_sRequiredService))
+ { // perhaps it is a container
+ Reference< XIndexAccess > xCont(xAsSet, UNO_QUERY);
+ if (xCont.is() && xCont->getCount())
+ { // yes -> step down
+ m_xControlTree->insert(&rContainerEntry, -1, &sName, nullptr,
+ nullptr, nullptr, false, m_xScratchIter.get());
+ m_xControlTree->set_image(*m_xScratchIter, RID_EXTBMP_FORM);
+ auto xIter = m_xControlTree->make_iterator(&rContainerEntry);
+ m_xControlTree->iter_nth_child(*xIter, nChildren);
+ sal_Int32 nContChildren = InsertEntries(xCont, *xIter);
+ if (nContChildren)
+ {
+ m_xControlTree->expand_row(*xIter);
+ ++nChildren;
+ }
+ else
+ { // oops, no valid children -> remove the entry
+ m_xControlTree->remove(*xIter);
+ }
+ }
+ continue;
+ }
+
+ // get the label
+ if (!::comphelper::hasProperty(PROPERTY_LABEL, xAsSet))
+ continue;
+
+ OUString sDisplayName =
+ ::comphelper::getString(xAsSet->getPropertyValue(PROPERTY_LABEL)) +
+ " (" + sName + ")";
+
+ // all requirements met -> insert
+ m_xUserData.emplace_back(new Reference<XPropertySet>(xAsSet));
+ OUString sId(weld::toId(m_xUserData.back().get()));
+ m_xControlTree->insert(&rContainerEntry, -1, &sDisplayName, &sId, nullptr, nullptr, false, m_xScratchIter.get());
+ m_xControlTree->set_image(*m_xScratchIter, m_aRequiredControlImage);
+
+ if (m_xInitialLabelControl == xAsSet)
+ {
+ m_xInitialSelection = m_xControlTree->make_iterator(&rContainerEntry);
+ m_xControlTree->iter_nth_child(*m_xInitialSelection, nChildren);
+ }
+
+ ++nChildren;
+ m_bHaveAssignableControl = true;
+ }
+
+ return nChildren;
+ }
+
+ IMPL_LINK(OSelectLabelDialog, OnEntrySelected, weld::TreeView&, rLB, void)
+ {
+ DBG_ASSERT(&rLB == m_xControlTree.get(), "OSelectLabelDialog::OnEntrySelected : where did this come from ?");
+ std::unique_ptr<weld::TreeIter> xIter = m_xControlTree->make_iterator();
+ bool bSelected = m_xControlTree->get_selected(xIter.get());
+ OUString sData = bSelected ? m_xControlTree->get_id(*xIter) : OUString();
+ if (!sData.isEmpty())
+ m_xSelectedControl.set(*weld::fromId<Reference<XPropertySet>*>(sData));
+ m_xNoAssignment->set_active(sData.isEmpty());
+ }
+
+ IMPL_LINK(OSelectLabelDialog, OnNoAssignmentClicked, weld::Toggleable&, rButton, void)
+ {
+ DBG_ASSERT(&rButton == m_xNoAssignment.get(), "OSelectLabelDialog::OnNoAssignmentClicked : where did this come from ?");
+
+ if (m_xNoAssignment->get_active())
+ {
+ m_bLastSelected = m_xControlTree->get_selected(m_xLastSelected.get());
+ }
+ else
+ {
+ DBG_ASSERT(m_bHaveAssignableControl, "OSelectLabelDialog::OnNoAssignmentClicked");
+ // search the first assignable entry
+ auto xSearch = m_xControlTree->make_iterator(nullptr);
+ bool bSearch = m_xControlTree->get_iter_first(*xSearch);
+ while (bSearch)
+ {
+ if (m_xControlTree->get_id(*xSearch).toInt64())
+ break;
+ bSearch = m_xControlTree->iter_next(*xSearch);
+ }
+ // and select it
+ if (bSearch)
+ {
+ m_xControlTree->copy_iterator(*xSearch, *m_xLastSelected);
+ m_xControlTree->select(*m_xLastSelected);
+ m_bLastSelected = true;
+ }
+ }
+
+ if (m_bLastSelected)
+ {
+ if (!m_xNoAssignment->get_active())
+ m_xControlTree->select(*m_xLastSelected);
+ else
+ m_xControlTree->unselect(*m_xLastSelected);
+ }
+ }
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/selectlabeldialog.hxx b/extensions/source/propctrlr/selectlabeldialog.hxx
new file mode 100644
index 000000000..9affa3512
--- /dev/null
+++ b/extensions/source/propctrlr/selectlabeldialog.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/weld.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+namespace pcr
+{
+ // OSelectLabelDialog
+ class OSelectLabelDialog final : public weld::GenericDialogController
+ {
+ css::uno::Reference< css::beans::XPropertySet > m_xControlModel;
+ OUString m_sRequiredService;
+ OUString m_aRequiredControlImage;
+ std::unique_ptr<weld::TreeIter> m_xInitialSelection;
+ // the entry data of the listbox entries
+ std::vector<std::unique_ptr<css::uno::Reference<css::beans::XPropertySet>>> m_xUserData;
+ css::uno::Reference< css::beans::XPropertySet > m_xInitialLabelControl;
+
+ css::uno::Reference< css::beans::XPropertySet > m_xSelectedControl;
+ std::unique_ptr<weld::TreeIter> m_xLastSelected;
+ bool m_bLastSelected;
+ bool m_bHaveAssignableControl;
+
+ std::unique_ptr<weld::Label> m_xMainDesc;
+ std::unique_ptr<weld::TreeView> m_xControlTree;
+ std::unique_ptr<weld::TreeIter> m_xScratchIter;
+ std::unique_ptr<weld::CheckButton> m_xNoAssignment;
+
+ public:
+ OSelectLabelDialog(weld::Window* pParent, css::uno::Reference< css::beans::XPropertySet > const & _xControlModel);
+ virtual ~OSelectLabelDialog() override;
+
+ css::uno::Reference< css::beans::XPropertySet > GetSelected() const { return m_xNoAssignment->get_active() ? css::uno::Reference< css::beans::XPropertySet > () : m_xSelectedControl; }
+
+ private:
+ sal_Int32 InsertEntries(const css::uno::Reference< css::uno::XInterface >& _xContainer, const weld::TreeIter& rContainerEntry);
+
+ DECL_LINK(OnEntrySelected, weld::TreeView&, void);
+ DECL_LINK(OnNoAssignmentClicked, weld::Toggleable&, void);
+ };
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/sqlcommanddesign.cxx b/extensions/source/propctrlr/sqlcommanddesign.cxx
new file mode 100644
index 000000000..73e205be4
--- /dev/null
+++ b/extensions/source/propctrlr/sqlcommanddesign.cxx
@@ -0,0 +1,355 @@
+/* -*- 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 "sqlcommanddesign.hxx"
+#include "formstrings.hxx"
+#include <command.hrc>
+#include "modulepcr.hxx"
+#include "unourl.hxx"
+
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/awt/XTopWindow.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XTitle.hpp>
+#include <com/sun/star/frame/XComponentLoader.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+
+
+namespace pcr
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::beans::PropertyChangeEvent;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::frame::XFrame;
+ using ::com::sun::star::awt::XTopWindow;
+ using ::com::sun::star::awt::XWindow;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::beans::PropertyValue;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::lang::XComponent;
+ using ::com::sun::star::frame::XComponentLoader;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::frame::XTitle;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::lang::NullPointerException;
+ using ::com::sun::star::lang::DisposedException;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::frame::XFrames;
+ using ::com::sun::star::util::XCloseable;
+ using ::com::sun::star::lang::XMultiServiceFactory;
+ using ::com::sun::star::frame::XDispatchProvider;
+ using ::com::sun::star::frame::XDispatch;
+ using ::com::sun::star::frame::Desktop;
+ using ::com::sun::star::frame::XDesktop2;
+
+ namespace FrameSearchFlag = ::com::sun::star::frame::FrameSearchFlag;
+ namespace CommandType = ::com::sun::star::sdb::CommandType;
+
+
+ //= ISQLCommandAdapter
+
+
+ ISQLCommandAdapter::~ISQLCommandAdapter()
+ {
+ }
+
+
+ //= SQLCommandDesigner
+
+
+ SQLCommandDesigner::SQLCommandDesigner( const Reference< XComponentContext >& _rxContext,
+ const ::rtl::Reference< ISQLCommandAdapter >& _rxPropertyAdapter,
+ const ::dbtools::SharedConnection& _rConnection, const Link<SQLCommandDesigner&,void>& _rCloseLink )
+ :m_xContext( _rxContext )
+ ,m_xConnection( _rConnection )
+ ,m_xObjectAdapter( _rxPropertyAdapter )
+ ,m_aCloseLink( _rCloseLink )
+ {
+ if ( m_xContext.is() )
+ m_xORB = m_xContext->getServiceManager();
+ if ( !m_xORB.is() || !_rxPropertyAdapter.is() || !m_xConnection.is() )
+ throw NullPointerException();
+
+ impl_doOpenDesignerFrame_nothrow();
+ }
+
+
+ SQLCommandDesigner::~SQLCommandDesigner()
+ {
+ }
+
+
+ void SAL_CALL SQLCommandDesigner::propertyChange( const PropertyChangeEvent& Event )
+ {
+ OSL_ENSURE( m_xDesigner.is() && ( Event.Source == m_xDesigner ), "SQLCommandDesigner::propertyChange: where did this come from?" );
+
+ if ( !(m_xDesigner.is() && ( Event.Source == m_xDesigner )) )
+ return;
+
+ try
+ {
+ if ( PROPERTY_ACTIVECOMMAND == Event.PropertyName )
+ {
+ OUString sCommand;
+ OSL_VERIFY( Event.NewValue >>= sCommand );
+ m_xObjectAdapter->setSQLCommand( sCommand );
+ }
+ else if ( PROPERTY_ESCAPE_PROCESSING == Event.PropertyName )
+ {
+ bool bEscapeProcessing( false );
+ OSL_VERIFY( Event.NewValue >>= bEscapeProcessing );
+ m_xObjectAdapter->setEscapeProcessing( bEscapeProcessing );
+ }
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const Exception& )
+ {
+ // not allowed to leave, so silence it
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+
+ void SAL_CALL SQLCommandDesigner::disposing( const EventObject& Source )
+ {
+ if ( m_xDesigner.is() && ( Source.Source == m_xDesigner ) )
+ {
+ m_aCloseLink.Call( *this );
+ m_xDesigner.clear();
+ }
+ }
+
+
+ void SQLCommandDesigner::dispose()
+ {
+ if ( impl_isDisposed() )
+ return;
+
+ if ( isActive() )
+ impl_closeDesigner_nothrow();
+
+ m_xConnection.clear();
+ m_xContext.clear();
+ m_xORB.clear();
+ }
+
+
+ void SQLCommandDesigner::impl_checkDisposed_throw() const
+ {
+ if ( impl_isDisposed() )
+ throw DisposedException();
+ }
+
+
+ void SQLCommandDesigner::raise() const
+ {
+ impl_checkDisposed_throw();
+ impl_raise_nothrow();
+ }
+
+
+ bool SQLCommandDesigner::suspend() const
+ {
+ impl_checkDisposed_throw();
+ return impl_trySuspendDesigner_nothrow();
+ }
+
+
+ void SQLCommandDesigner::impl_raise_nothrow() const
+ {
+ OSL_PRECOND( isActive(), "SQLCommandDesigner::impl_raise_nothrow: not active!" );
+ if ( !isActive() )
+ return;
+
+ try
+ {
+ // activate the frame for this component
+ Reference< XFrame > xFrame( m_xDesigner->getFrame(), css::uno::UNO_SET_THROW );
+ Reference< XWindow > xWindow( xFrame->getContainerWindow(), css::uno::UNO_SET_THROW );
+ Reference< XTopWindow > xTopWindow( xWindow, UNO_QUERY_THROW );
+
+ xTopWindow->toFront();
+ xWindow->setFocus();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+
+ void SQLCommandDesigner::impl_doOpenDesignerFrame_nothrow()
+ {
+ OSL_PRECOND( !isActive(),
+ "SQLCommandDesigner::impl_doOpenDesignerFrame_nothrow: already active!" );
+ OSL_PRECOND( m_xConnection.is(), "SQLCommandDesigner::impl_doOpenDesignerFrame_nothrow: this will crash!" );
+ osl_atomic_increment(&m_refCount);
+
+ try
+ {
+ // for various reasons, we don't want the new frame to appear in the desktop's frame list
+ // thus, we create a blank frame at the desktop, remove it from the desktop's frame list
+ // immediately, and then load the component into this blank (and now parent-less) frame
+ Reference< XComponentLoader > xLoader( impl_createEmptyParentlessTask_nothrow(), UNO_QUERY_THROW );
+ const bool bEscapeProcessing = m_xObjectAdapter->getEscapeProcessing();
+ Sequence< PropertyValue > aArgs{
+ comphelper::makePropertyValue(PROPERTY_ACTIVE_CONNECTION, m_xConnection.getTyped()),
+ comphelper::makePropertyValue(PROPERTY_COMMAND, m_xObjectAdapter->getSQLCommand()),
+ comphelper::makePropertyValue(PROPERTY_COMMANDTYPE, CommandType::COMMAND),
+ comphelper::makePropertyValue(PROPERTY_ESCAPE_PROCESSING, bEscapeProcessing),
+ comphelper::makePropertyValue("GraphicalDesign", bEscapeProcessing)
+ };
+
+ Reference< XComponent > xQueryDesign = xLoader->loadComponentFromURL(
+ ".component:DB/QueryDesign",
+ "_self",
+ FrameSearchFlag::TASKS | FrameSearchFlag::CREATE,
+ aArgs
+ );
+
+ // remember this newly loaded component - we need to care for it e.g. when we're suspended
+ m_xDesigner.set(xQueryDesign, css::uno::UNO_QUERY);
+ OSL_ENSURE( m_xDesigner.is() || !xQueryDesign.is(), "SQLCommandDesigner::impl_doOpenDesignerFrame_nothrow: the component is expected to be a controller!" );
+ if ( m_xDesigner.is() )
+ {
+ Reference< XPropertySet > xQueryDesignProps( m_xDesigner, UNO_QUERY );
+ OSL_ENSURE( xQueryDesignProps.is(), "SQLCommandDesigner::impl_doOpenDesignerFrame_nothrow: the controller should have properties!" );
+ if ( xQueryDesignProps.is() )
+ {
+ xQueryDesignProps->addPropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
+ xQueryDesignProps->addPropertyChangeListener( PROPERTY_ESCAPE_PROCESSING, this );
+ }
+ }
+
+ // get the frame which we just opened and set its title
+ Reference< XTitle> xTitle(xQueryDesign,UNO_QUERY);
+ if ( xTitle.is() )
+ {
+ OUString sDisplayName = PcrRes(RID_RSC_ENUM_COMMAND_TYPE[CommandType::COMMAND]);
+ xTitle->setTitle(sDisplayName);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ m_xDesigner.clear();
+ }
+ osl_atomic_decrement(&m_refCount);
+ }
+
+
+ Reference< XFrame > SQLCommandDesigner::impl_createEmptyParentlessTask_nothrow( ) const
+ {
+ OSL_PRECOND( m_xORB.is(), "SQLCommandDesigner::impl_createEmptyParentlessTask_nothrow: this will crash!" );
+
+ Reference< XFrame > xFrame;
+ try
+ {
+ Reference< XDesktop2 > xDesktop = Desktop::create(m_xContext);
+
+ Reference< XFrames > xDesktopFramesCollection( xDesktop->getFrames(), css::uno::UNO_SET_THROW );
+ xFrame = xDesktop->findFrame( "_blank", FrameSearchFlag::CREATE );
+ OSL_ENSURE( xFrame.is(), "SQLCommandDesigner::impl_createEmptyParentlessTask_nothrow: could not create an empty frame!" );
+ xDesktopFramesCollection->remove( xFrame );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ return xFrame;
+ }
+
+
+ void SQLCommandDesigner::impl_closeDesigner_nothrow()
+ {
+ OSL_PRECOND( isActive(), "SQLCommandDesigner::impl_closeDesigner_nothrow: invalid call!" );
+ // close it
+ try
+ {
+ // do not listen anymore...
+ Reference< XPropertySet > xProps( m_xDesigner, UNO_QUERY );
+ if ( xProps.is() )
+ xProps->removePropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
+
+ // we need to close the frame via the "user interface", by dispatching a close command,
+ // instead of calling XCloseable::close directly. The latter method would also close
+ // the frame, but not care for things like shutting down the office when the last
+ // frame is gone ...
+ const UnoURL aCloseURL( ".uno:CloseDoc",
+ Reference< XMultiServiceFactory >( m_xORB, UNO_QUERY ) );
+
+ Reference< XDispatchProvider > xProvider( m_xDesigner->getFrame(), UNO_QUERY_THROW );
+ Reference< XDispatch > xDispatch( xProvider->queryDispatch( aCloseURL, "_top", FrameSearchFlag::SELF ) );
+ OSL_ENSURE( xDispatch.is(), "SQLCommandDesigner::impl_closeDesigner_nothrow: no dispatcher for the CloseDoc command!" );
+ if ( xDispatch.is() )
+ {
+ xDispatch->dispatch( aCloseURL, Sequence< PropertyValue >( ) );
+ }
+ else
+ {
+ // fallback: use the XCloseable::close (with all possible disadvantages)
+ Reference< XCloseable > xClose( m_xDesigner->getFrame(), UNO_QUERY );
+ if ( xClose.is() )
+ xClose->close( true );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+
+ m_xDesigner.clear();
+ }
+
+
+ bool SQLCommandDesigner::impl_trySuspendDesigner_nothrow() const
+ {
+ OSL_PRECOND( isActive(), "SQLCommandDesigner::impl_trySuspendDesigner_nothrow: no active designer, this will crash!" );
+ bool bAllow = true;
+ try
+ {
+ bAllow = m_xDesigner->suspend( true );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ return bAllow;
+ }
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/sqlcommanddesign.hxx b/extensions/source/propctrlr/sqlcommanddesign.hxx
new file mode 100644
index 000000000..a72ba11b0
--- /dev/null
+++ b/extensions/source/propctrlr/sqlcommanddesign.hxx
@@ -0,0 +1,193 @@
+/* -*- 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/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <connectivity/dbtools.hxx>
+#include <tools/link.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+
+
+namespace pcr
+{
+
+
+ class ISQLCommandAdapter;
+
+ //= SQLCommandDesigner
+
+ typedef ::cppu::WeakImplHelper < css::beans::XPropertyChangeListener
+ > SQLCommandDesigner_Base;
+ /** encapsulates the code for calling and managing a query design frame, used
+ for interactively designing the Command property of a ->RowSet
+ */
+ class SQLCommandDesigner final : public SQLCommandDesigner_Base
+ {
+ private:
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::lang::XMultiComponentFactory > m_xORB;
+ ::dbtools::SharedConnection m_xConnection;
+ css::uno::Reference< css::frame::XController > m_xDesigner;
+ ::rtl::Reference< ISQLCommandAdapter > m_xObjectAdapter;
+ Link<SQLCommandDesigner&,void> m_aCloseLink;
+
+ public:
+ /** creates the instance, and immediately opens the SQL command design frame
+
+ @param _rxContext
+ our component context. Must not be <NULL/>, and must provide a non-<NULL/> XMultiComponentFactory
+ @param _rxPropertyAdapter
+ an adapter to the object's SQL command related properties
+ @param _rConnection
+ the current connection of ->_rxRowSet. Must not be <NULL/>.
+ @param _rCloseLink
+ link to call when the component has been closed
+ @throws css::lang::NullPointerException
+ if any of the arguments (except ->_rCloseLink) is <NULL/>, or if the component context
+ does not provide a valid component factory.
+ */
+ SQLCommandDesigner(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ const ::rtl::Reference< ISQLCommandAdapter >& _rxPropertyAdapter,
+ const ::dbtools::SharedConnection& _rConnection,
+ const Link<SQLCommandDesigner&,void>& _rCloseLink
+ );
+
+ /** determines whether the SQL Command designer is currently active, i.e.
+ if there currently exists a frame which allows the user entering the SQL command
+ */
+ bool isActive() const { return m_xDesigner.is(); }
+
+ /** returns the property adapter used by the instance
+ */
+ const ::rtl::Reference< ISQLCommandAdapter >& getPropertyAdapter() const { return m_xObjectAdapter; }
+
+ /** raises the designer window to top
+ @precond
+ the designer is active (->isActive)
+ @precond
+ the instance is not disposed
+ */
+ void raise() const;
+
+ /** suspends the designer
+ @precond
+ the designer is active (->isActive)
+ @precond
+ the instance is not disposed
+ */
+ bool suspend() const;
+
+ /** disposes the instance so that it becomes non-functional
+ */
+ void dispose();
+
+ private:
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ virtual ~SQLCommandDesigner() override;
+
+ /** opens a new frame for interactively designing an SQL command
+ @precond
+ the designer is not currently active (see ->isActive)
+ @precond
+ ->m_xConnection is not <NULL/>
+ */
+ void impl_doOpenDesignerFrame_nothrow();
+
+ /** impl-version of ->raise
+ */
+ void impl_raise_nothrow() const;
+
+ /** determines whether we are already disposed
+ */
+ bool impl_isDisposed() const
+ {
+ return !m_xContext.is();
+ }
+ /** checks whether we are already disposed
+ @throws css::lang::DisposedException
+ if we in fact are disposed
+ */
+ void impl_checkDisposed_throw() const;
+
+ /** create an empty top-level frame, which does not belong to the desktop's frame list
+ @precond
+ ->m_xORB is not <NULL/>
+ */
+ css::uno::Reference< css::frame::XFrame >
+ impl_createEmptyParentlessTask_nothrow() const;
+
+ /** closes the component denoted by m_xDesigner
+ @precond
+ our designer component is actually active (->isActive)
+ @precond
+ we're not disposed already
+ */
+ void impl_closeDesigner_nothrow();
+
+ /** suspends our designer component
+ @precond
+ the designer component is actually active (->isActive)
+ @return
+ <TRUE/> if the suspension was successful, <FALSE/> if it was vetoed
+ */
+ bool impl_trySuspendDesigner_nothrow() const;
+
+ SQLCommandDesigner( const SQLCommandDesigner& ) = delete;
+ SQLCommandDesigner& operator=( const SQLCommandDesigner& ) = delete;
+ };
+
+
+ //= ISQLCommandAdapter
+
+ /** an adapter to forward changed SQL command property values to a component
+ */
+ class ISQLCommandAdapter : public salhelper::SimpleReferenceObject
+ {
+ public:
+ /// retrieves the current SQL command of the component
+ virtual OUString getSQLCommand() const = 0;
+ /// retrieves the current value of the EscapeProcessing property of the component
+ virtual bool getEscapeProcessing() const = 0;
+
+ /// sets a new SQL command
+ virtual void setSQLCommand( const OUString& _rCommand ) const = 0;
+ /// sets a new EscapeProcessing property value
+ virtual void setEscapeProcessing( const bool _bEscapeProcessing ) const = 0;
+
+ virtual ~ISQLCommandAdapter() override;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/standardcontrol.cxx b/extensions/source/propctrlr/standardcontrol.cxx
new file mode 100644
index 000000000..95b4143c7
--- /dev/null
+++ b/extensions/source/propctrlr/standardcontrol.cxx
@@ -0,0 +1,865 @@
+/* -*- 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 "standardcontrol.hxx"
+#include "pcrcommon.hxx"
+
+#include <com/sun/star/beans/IllegalTypeException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/Color.hpp>
+#include <com/sun/star/util/MeasureUnit.hpp>
+#include <com/sun/star/inspection/PropertyControlType.hpp>
+#include <comphelper/string.hxx>
+#include <o3tl/float_int_conversion.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+
+
+// ugly dependencies for the OColorControl
+#include <svx/svxids.hrc>
+
+#include <tools/datetime.hxx>
+#include <unotools/datetime.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <limits>
+#include <memory>
+
+namespace pcr
+{
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::inspection;
+
+ //= OTimeControl
+ OTimeControl::OTimeControl(std::unique_ptr<weld::FormattedSpinButton> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly)
+ : OTimeControl_Base(PropertyControlType::TimeField, std::move(xBuilder), std::move(xWidget), bReadOnly)
+ , m_xFormatter(new weld::TimeFormatter(*getTypedControlWindow()))
+ {
+ m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
+ }
+
+ void SAL_CALL OTimeControl::setValue( const Any& _rValue )
+ {
+ util::Time aUNOTime;
+ if ( !( _rValue >>= aUNOTime ) )
+ {
+ getTypedControlWindow()->set_text("");
+ m_xFormatter->SetTime(tools::Time(tools::Time::EMPTY));
+ }
+ else
+ {
+ m_xFormatter->SetTime(::tools::Time(aUNOTime));
+ }
+ }
+
+ Any SAL_CALL OTimeControl::getValue()
+ {
+ Any aPropValue;
+ if ( !getTypedControlWindow()->get_text().isEmpty() )
+ {
+ aPropValue <<= m_xFormatter->GetTime().GetUNOTime();
+ }
+ return aPropValue;
+ }
+
+ Type SAL_CALL OTimeControl::getValueType()
+ {
+ return ::cppu::UnoType<util::Time>::get();
+ }
+
+ //= ODateControl
+ ODateControl::ODateControl(std::unique_ptr<weld::Container> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly)
+ : ODateControl_Base(PropertyControlType::DateField, std::move(xBuilder), std::move(xWidget), bReadOnly)
+ , m_xEntry(m_xBuilder->weld_entry("entry"))
+ , m_xCalendarBox(std::make_unique<SvtCalendarBox>(m_xBuilder->weld_menu_button("button"), false))
+ {
+ m_xEntryFormatter.reset(new weld::DateFormatter(*m_xEntry));
+
+ m_xEntryFormatter->SetStrictFormat(true);
+ m_xEntryFormatter->SetMin(::Date(1, 1, 1600));
+ m_xEntryFormatter->SetMax(::Date(1, 1, 9999));
+
+ m_xEntryFormatter->SetExtDateFormat(ExtDateFieldFormat::SystemShortYYYY);
+ m_xEntryFormatter->EnableEmptyField(true);
+
+ m_xCalendarBox->connect_activated(LINK(this, ODateControl, ActivateHdl));
+
+ m_xCalendarBox->get_button().connect_toggled(LINK(this, ODateControl, ToggleHdl));
+ }
+
+ void SAL_CALL ODateControl::disposing()
+ {
+ m_xEntryFormatter.reset();
+ m_xEntry.reset();
+ m_xCalendarBox.reset();
+ ODateControl_Base::disposing();
+ }
+
+ void SAL_CALL ODateControl::setValue( const Any& _rValue )
+ {
+ util::Date aUNODate;
+ if ( !( _rValue >>= aUNODate ) )
+ {
+ m_xEntry->set_text(OUString());
+ }
+ else
+ {
+ ::Date aDate( aUNODate.Day, aUNODate.Month, aUNODate.Year );
+ m_xEntryFormatter->SetDate(aDate);
+ }
+ }
+
+ IMPL_LINK_NOARG(ODateControl, ActivateHdl, SvtCalendarBox&, void)
+ {
+ m_xEntryFormatter->SetDate(m_xCalendarBox->get_date());
+ setModified();
+ m_xEntry->grab_focus();
+ }
+
+ IMPL_LINK(ODateControl, ToggleHdl, weld::Toggleable&, rToggle, void)
+ {
+ if (!rToggle.get_active())
+ return;
+ ::Date aDate = m_xEntryFormatter->GetDate();
+ if (aDate.IsEmpty())
+ {
+ // with an empty date preselect today in the calendar
+ aDate = ::Date(::Date::SYSTEM);
+ }
+ m_xCalendarBox->set_date(aDate);
+ }
+
+ Any SAL_CALL ODateControl::getValue()
+ {
+ Any aPropValue;
+ if (!m_xEntry->get_text().isEmpty())
+ {
+ ::Date aDate(m_xEntryFormatter->GetDate());
+ aPropValue <<= aDate.GetUNODate();
+ }
+ return aPropValue;
+ }
+
+ Type SAL_CALL ODateControl::getValueType()
+ {
+ return ::cppu::UnoType<util::Date>::get();
+ }
+
+ //= OEditControl
+ OEditControl::OEditControl(std::unique_ptr<weld::Entry> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bPW, bool bReadOnly)
+ : OEditControl_Base( bPW ? PropertyControlType::CharacterField : PropertyControlType::TextField, std::move(xBuilder), std::move(xWidget), bReadOnly )
+ {
+ m_bIsPassword = bPW;
+
+ auto pWidget = getTypedControlWindow();
+ pWidget->set_sensitive(true);
+ pWidget->set_editable(!bReadOnly);
+
+ if (m_bIsPassword)
+ pWidget->set_max_length( 1 );
+ }
+
+ void SAL_CALL OEditControl::setValue( const Any& _rValue )
+ {
+ OUString sText;
+ if ( m_bIsPassword )
+ {
+ sal_Int16 nValue = 0;
+ _rValue >>= nValue;
+ if ( nValue )
+ {
+ sText = OUString(static_cast<sal_Unicode>(nValue));
+ }
+ }
+ else
+ _rValue >>= sText;
+
+ getTypedControlWindow()->set_text( sText );
+ }
+
+ Any SAL_CALL OEditControl::getValue()
+ {
+ Any aPropValue;
+
+ OUString sText( getTypedControlWindow()->get_text() );
+ if ( m_bIsPassword )
+ {
+ if ( !sText.isEmpty() )
+ aPropValue <<= static_cast<sal_Int16>(sText[0]);
+ }
+ else
+ aPropValue <<= sText;
+
+ return aPropValue;
+ }
+
+ Type SAL_CALL OEditControl::getValueType()
+ {
+ return m_bIsPassword ? ::cppu::UnoType<sal_Int16>::get() : ::cppu::UnoType<OUString>::get();
+ }
+
+ void OEditControl::setModified()
+ {
+ OEditControl_Base::setModified();
+
+ // for password controls, we fire a commit for every single change
+ if ( m_bIsPassword )
+ notifyModifiedValue();
+ }
+
+ static sal_Int64 ImplCalcLongValue( double nValue, sal_uInt16 nDigits )
+ {
+ double n = nValue;
+ for ( sal_uInt16 d = 0; d < nDigits; ++d )
+ n *= 10;
+
+ return o3tl::saturating_cast<sal_Int64>(n);
+ }
+
+ static double ImplCalcDoubleValue(sal_Int64 nValue, sal_uInt16 nDigits )
+ {
+ double n = nValue;
+ for ( sal_uInt16 d = 0; d < nDigits; ++d )
+ n /= 10;
+ return n;
+ }
+
+ ODateTimeControl::ODateTimeControl(std::unique_ptr<weld::Container> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly)
+ : ODateTimeControl_Base(PropertyControlType::DateTimeField, std::move(xBuilder), std::move(xWidget), bReadOnly)
+ , m_xDate(std::make_unique<SvtCalendarBox>(m_xBuilder->weld_menu_button("datefield")))
+ , m_xTime(m_xBuilder->weld_formatted_spin_button("timefield"))
+ , m_xFormatter(new weld::TimeFormatter(*m_xTime))
+ {
+ m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
+ }
+
+ void SAL_CALL ODateTimeControl::setValue( const Any& _rValue )
+ {
+ if ( !_rValue.hasValue() )
+ {
+ m_xDate->set_date(::Date(::Date::SYSTEM));
+ m_xTime->set_text("");
+ m_xFormatter->SetTime(tools::Time(tools::Time::EMPTY));
+ }
+ else
+ {
+ util::DateTime aUNODateTime;
+ OSL_VERIFY( _rValue >>= aUNODateTime );
+
+ ::DateTime aDateTime( ::DateTime::EMPTY );
+ ::utl::typeConvert( aUNODateTime, aDateTime );
+
+ m_xDate->set_date(aDateTime);
+ m_xFormatter->SetTime(aDateTime);
+ }
+ }
+
+ Any SAL_CALL ODateTimeControl::getValue()
+ {
+ Any aPropValue;
+ if (!m_xTime->get_text().isEmpty())
+ {
+ ::DateTime aDateTime(m_xDate->get_date(), m_xFormatter->GetTime());
+
+ util::DateTime aUNODateTime;
+ ::utl::typeConvert( aDateTime, aUNODateTime );
+
+ aPropValue <<= aUNODateTime;
+ }
+ return aPropValue;
+ }
+
+ Type SAL_CALL ODateTimeControl::getValueType()
+ {
+ return ::cppu::UnoType<util::DateTime>::get();
+ }
+
+ //= OHyperlinkControl
+ OHyperlinkControl::OHyperlinkControl(std::unique_ptr<weld::Container> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly)
+ : OHyperlinkControl_Base(PropertyControlType::HyperlinkField, std::move(xBuilder), std::move(xWidget), bReadOnly)
+ , m_xEntry(m_xBuilder->weld_entry("entry"))
+ , m_xButton(m_xBuilder->weld_button("button"))
+ , m_aActionListeners(m_aMutex)
+ {
+ auto pWidget = getTypedControlWindow();
+ pWidget->set_sensitive(true);
+ m_xEntry->set_editable(!bReadOnly);
+
+ m_xButton->connect_clicked(LINK(this, OHyperlinkControl, OnHyperlinkClicked));
+ }
+
+ Any SAL_CALL OHyperlinkControl::getValue()
+ {
+ OUString sText = m_xEntry->get_text();
+ return Any( sText );
+ }
+
+ void SAL_CALL OHyperlinkControl::setValue( const Any& _value )
+ {
+ OUString sText;
+ _value >>= sText;
+ m_xEntry->set_text( sText );
+ }
+
+ Type SAL_CALL OHyperlinkControl::getValueType()
+ {
+ return ::cppu::UnoType<OUString>::get();
+ }
+
+ void SAL_CALL OHyperlinkControl::addActionListener( const Reference< XActionListener >& listener )
+ {
+ if ( listener.is() )
+ m_aActionListeners.addInterface( listener );
+ }
+
+ void SAL_CALL OHyperlinkControl::removeActionListener( const Reference< XActionListener >& listener )
+ {
+ m_aActionListeners.removeInterface( listener );
+ }
+
+ void SAL_CALL OHyperlinkControl::disposing()
+ {
+ m_xButton.reset();
+ m_xEntry.reset();
+ OHyperlinkControl_Base::disposing();
+
+ EventObject aEvent( *this );
+ m_aActionListeners.disposeAndClear( aEvent );
+ }
+
+ IMPL_LINK_NOARG( OHyperlinkControl, OnHyperlinkClicked, weld::Button&, void )
+ {
+ ActionEvent aEvent( *this, "clicked" );
+ m_aActionListeners.forEach< XActionListener >(
+ [&aEvent] (uno::Reference<awt::XActionListener> const& xListener)
+ { return xListener->actionPerformed(aEvent); });
+ }
+
+ //= ONumericControl
+ ONumericControl::ONumericControl(std::unique_ptr<weld::MetricSpinButton> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly)
+ : ONumericControl_Base(PropertyControlType::NumericField, std::move(xBuilder), std::move(xWidget), bReadOnly)
+ , m_eValueUnit( FieldUnit::NONE )
+ , m_nFieldToUNOValueFactor( 1 )
+ {
+ Optional< double > value( getMaxValue() );
+ value.Value = -value.Value;
+ setMinValue( value );
+ }
+
+ ::sal_Int16 SAL_CALL ONumericControl::getDecimalDigits()
+ {
+ return getTypedControlWindow()->get_digits();
+ }
+
+ void SAL_CALL ONumericControl::setDecimalDigits( ::sal_Int16 decimaldigits )
+ {
+ weld::MetricSpinButton* pControlWindow = getTypedControlWindow();
+ sal_Int64 min, max;
+ pControlWindow->get_range(min, max, FieldUnit::NONE);
+ pControlWindow->set_digits(decimaldigits);
+ pControlWindow->set_range(min, max, FieldUnit::NONE);
+ }
+
+ Optional< double > SAL_CALL ONumericControl::getMinValue()
+ {
+ Optional< double > aReturn( true, 0 );
+
+ sal_Int64 minValue = getTypedControlWindow()->get_min(FieldUnit::NONE);
+ if ( minValue == std::numeric_limits<sal_Int64>::min() )
+ aReturn.IsPresent = false;
+ else
+ aReturn.Value = static_cast<double>(minValue);
+
+ return aReturn;
+ }
+
+ void SAL_CALL ONumericControl::setMinValue( const Optional< double >& _minvalue )
+ {
+ if ( !_minvalue.IsPresent )
+ getTypedControlWindow()->set_min( std::numeric_limits<sal_Int64>::min(), FieldUnit::NONE );
+ else
+ getTypedControlWindow()->set_min( impl_apiValueToFieldValue_nothrow( _minvalue.Value ) , m_eValueUnit);
+ }
+
+ Optional< double > SAL_CALL ONumericControl::getMaxValue()
+ {
+ Optional< double > aReturn( true, 0 );
+
+ sal_Int64 maxValue = getTypedControlWindow()->get_max(FieldUnit::NONE);
+ if ( maxValue == std::numeric_limits<sal_Int64>::max() )
+ aReturn.IsPresent = false;
+ else
+ aReturn.Value = static_cast<double>(maxValue);
+
+ return aReturn;
+ }
+
+ void SAL_CALL ONumericControl::setMaxValue( const Optional< double >& _maxvalue )
+ {
+ if ( !_maxvalue.IsPresent )
+ getTypedControlWindow()->set_max( std::numeric_limits<sal_Int64>::max(), FieldUnit::NONE );
+ else
+ getTypedControlWindow()->set_max( impl_apiValueToFieldValue_nothrow( _maxvalue.Value ), m_eValueUnit );
+ }
+
+ ::sal_Int16 SAL_CALL ONumericControl::getDisplayUnit()
+ {
+ return VCLUnoHelper::ConvertToMeasurementUnit( getTypedControlWindow()->get_unit(), 1 );
+ }
+
+ void SAL_CALL ONumericControl::setDisplayUnit( ::sal_Int16 _displayunit )
+ {
+ if ( ( _displayunit < MeasureUnit::MM_100TH ) || ( _displayunit > MeasureUnit::PERCENT ) )
+ throw IllegalArgumentException();
+ if ( ( _displayunit == MeasureUnit::MM_100TH )
+ || ( _displayunit == MeasureUnit::MM_10TH )
+ || ( _displayunit == MeasureUnit::INCH_1000TH )
+ || ( _displayunit == MeasureUnit::INCH_100TH )
+ || ( _displayunit == MeasureUnit::INCH_10TH )
+ || ( _displayunit == MeasureUnit::PERCENT )
+ )
+ throw IllegalArgumentException();
+
+ sal_Int16 nDummyFactor = 1;
+ FieldUnit eFieldUnit = VCLUnoHelper::ConvertToFieldUnit( _displayunit, nDummyFactor );
+ if ( nDummyFactor != 1 )
+ // everything which survived the checks above should result in a factor of 1, i.e.,
+ // it should have a direct counterpart as FieldUnit
+ throw RuntimeException();
+ getTypedControlWindow()->set_unit(eFieldUnit);
+ }
+
+ ::sal_Int16 SAL_CALL ONumericControl::getValueUnit()
+ {
+ return VCLUnoHelper::ConvertToMeasurementUnit( m_eValueUnit, m_nFieldToUNOValueFactor );
+ }
+
+ void SAL_CALL ONumericControl::setValueUnit( ::sal_Int16 _valueunit )
+ {
+ if ( ( _valueunit < MeasureUnit::MM_100TH ) || ( _valueunit > MeasureUnit::PERCENT ) )
+ throw IllegalArgumentException();
+ m_eValueUnit = VCLUnoHelper::ConvertToFieldUnit( _valueunit, m_nFieldToUNOValueFactor );
+ }
+
+ void SAL_CALL ONumericControl::setValue( const Any& _rValue )
+ {
+ if ( !_rValue.hasValue() )
+ {
+ getTypedControlWindow()->set_text( "" );
+ }
+ else
+ {
+ double nValue( 0 );
+ OSL_VERIFY( _rValue >>= nValue );
+ auto nControlValue = impl_apiValueToFieldValue_nothrow( nValue );
+ getTypedControlWindow()->set_value( nControlValue, m_eValueUnit );
+ }
+ }
+
+ sal_Int64 ONumericControl::impl_apiValueToFieldValue_nothrow( double _nApiValue ) const
+ {
+ sal_Int64 nControlValue = ImplCalcLongValue( _nApiValue, getTypedControlWindow()->get_digits() );
+ nControlValue /= m_nFieldToUNOValueFactor;
+ return nControlValue;
+ }
+
+ double ONumericControl::impl_fieldValueToApiValue_nothrow(sal_Int64 nFieldValue) const
+ {
+ double nApiValue = ImplCalcDoubleValue( nFieldValue, getTypedControlWindow()->get_digits() );
+ nApiValue *= m_nFieldToUNOValueFactor;
+ return nApiValue;
+ }
+
+ Any SAL_CALL ONumericControl::getValue()
+ {
+ Any aPropValue;
+ if ( !getTypedControlWindow()->get_text().isEmpty() )
+ {
+ double nValue = impl_fieldValueToApiValue_nothrow( getTypedControlWindow()->get_value( m_eValueUnit ) );
+ aPropValue <<= nValue;
+ }
+ return aPropValue;
+ }
+
+ Type SAL_CALL ONumericControl::getValueType()
+ {
+ return ::cppu::UnoType<double>::get();
+ }
+
+ //= OColorControl
+ OColorControl::OColorControl(std::unique_ptr<ColorListBox> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly)
+ : OColorControl_Base(PropertyControlType::ColorListBox, std::move(xBuilder), std::move(xWidget), bReadOnly)
+ {
+ getTypedControlWindow()->SetSlotId(SID_FM_CTL_PROPERTIES);
+ }
+
+ void SAL_CALL OColorControl::setValue( const Any& _rValue )
+ {
+ css::util::Color nColor = sal_uInt32(COL_TRANSPARENT);
+ if (_rValue.hasValue())
+ _rValue >>= nColor;
+ getTypedControlWindow()->SelectEntry(::Color(ColorTransparency, nColor));
+ }
+
+ Any SAL_CALL OColorControl::getValue()
+ {
+ Any aPropValue;
+ ::Color aRgbCol = getTypedControlWindow()->GetSelectEntryColor();
+ if (aRgbCol == COL_TRANSPARENT)
+ return aPropValue;
+ aPropValue <<= aRgbCol;
+ return aPropValue;
+ }
+
+ Type SAL_CALL OColorControl::getValueType()
+ {
+ return ::cppu::UnoType<sal_Int32>::get();
+ }
+
+ void OColorControl::setModified()
+ {
+ OColorControl_Base::setModified();
+
+ // fire a commit
+ notifyModifiedValue();
+ }
+
+ //= OListboxControl
+ OListboxControl::OListboxControl(std::unique_ptr<weld::ComboBox> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly)
+ : OListboxControl_Base(PropertyControlType::ListBox, std::move(xBuilder), std::move(xWidget), bReadOnly)
+ {
+ }
+
+ Any SAL_CALL OListboxControl::getValue()
+ {
+ OUString sControlValue( getTypedControlWindow()->get_active_text() );
+
+ Any aPropValue;
+ if ( !sControlValue.isEmpty() )
+ aPropValue <<= sControlValue;
+ return aPropValue;
+ }
+
+ Type SAL_CALL OListboxControl::getValueType()
+ {
+ return ::cppu::UnoType<OUString>::get();
+ }
+
+ void SAL_CALL OListboxControl::setValue( const Any& _rValue )
+ {
+ if ( !_rValue.hasValue() )
+ getTypedControlWindow()->set_active(-1);
+ else
+ {
+ OUString sSelection;
+ _rValue >>= sSelection;
+
+ if (getTypedControlWindow()->find_text(sSelection) == -1)
+ getTypedControlWindow()->insert_text(0, sSelection);
+
+ if (sSelection != getTypedControlWindow()->get_active_text())
+ getTypedControlWindow()->set_active_text(sSelection);
+ }
+ }
+
+ void SAL_CALL OListboxControl::clearList()
+ {
+ getTypedControlWindow()->clear();
+ }
+
+ void SAL_CALL OListboxControl::prependListEntry( const OUString& NewEntry )
+ {
+ getTypedControlWindow()->insert_text(0, NewEntry);
+ }
+
+ void SAL_CALL OListboxControl::appendListEntry( const OUString& NewEntry )
+ {
+ getTypedControlWindow()->append_text(NewEntry);
+ }
+
+ Sequence< OUString > SAL_CALL OListboxControl::getListEntries()
+ {
+ const sal_Int32 nCount = getTypedControlWindow()->get_count();
+ Sequence< OUString > aRet(nCount);
+ OUString* pIter = aRet.getArray();
+ for (sal_Int32 i = 0; i < nCount ; ++i,++pIter)
+ *pIter = getTypedControlWindow()->get_text(i);
+
+ return aRet;
+ }
+
+ void OListboxControl::setModified()
+ {
+ OListboxControl_Base::setModified();
+
+ // fire a commit
+ notifyModifiedValue();
+ }
+
+ //= OComboboxControl
+ OComboboxControl::OComboboxControl(std::unique_ptr<weld::ComboBox> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly)
+ : OComboboxControl_Base(PropertyControlType::ComboBox, std::move(xBuilder), std::move(xWidget), bReadOnly)
+ {
+ getTypedControlWindow()->connect_changed( LINK( this, OComboboxControl, OnEntrySelected ) );
+ }
+
+ void SAL_CALL OComboboxControl::setValue( const Any& _rValue )
+ {
+ OUString sText;
+ _rValue >>= sText;
+ weld::ComboBox* pControlWindow = getTypedControlWindow();
+ // tdf#138701 leave current cursor valid if the contents won't change
+ if (pControlWindow->get_active_text() != sText)
+ pControlWindow->set_entry_text(sText);
+ }
+
+ Any SAL_CALL OComboboxControl::getValue()
+ {
+ return Any( getTypedControlWindow()->get_active_text() );
+ }
+
+ Type SAL_CALL OComboboxControl::getValueType()
+ {
+ return ::cppu::UnoType<OUString>::get();
+ }
+
+ void SAL_CALL OComboboxControl::clearList()
+ {
+ getTypedControlWindow()->clear();
+ }
+
+ void SAL_CALL OComboboxControl::prependListEntry( const OUString& NewEntry )
+ {
+ getTypedControlWindow()->insert_text(0, NewEntry);
+ }
+
+ void SAL_CALL OComboboxControl::appendListEntry( const OUString& NewEntry )
+ {
+ getTypedControlWindow()->append_text( NewEntry );
+ }
+
+ Sequence< OUString > SAL_CALL OComboboxControl::getListEntries( )
+ {
+ const sal_Int32 nCount = getTypedControlWindow()->get_count();
+ Sequence< OUString > aRet(nCount);
+ OUString* pIter = aRet.getArray();
+ for (sal_Int32 i = 0; i < nCount ; ++i,++pIter)
+ *pIter = getTypedControlWindow()->get_text(i);
+
+ return aRet;
+ }
+
+ IMPL_LINK_NOARG( OComboboxControl, OnEntrySelected, weld::ComboBox&, void )
+ {
+ // fire a commit
+ notifyModifiedValue();
+ }
+
+ namespace
+ {
+
+ StlSyntaxSequence< OUString > lcl_convertMultiLineToList( std::u16string_view _rCompsedTextWithLineBreaks )
+ {
+ sal_Int32 nLines = comphelper::string::getTokenCount(_rCompsedTextWithLineBreaks, '\n');
+ StlSyntaxSequence< OUString > aStrings( nLines );
+ if (nLines)
+ {
+ StlSyntaxSequence< OUString >::iterator stringItem = aStrings.begin();
+ sal_Int32 nIdx {0};
+ do
+ {
+ *stringItem = o3tl::getToken(_rCompsedTextWithLineBreaks, 0, '\n', nIdx );
+ ++stringItem;
+ }
+ while (nIdx>0);
+ }
+ return aStrings;
+ }
+
+ OUString lcl_convertListToMultiLine( const StlSyntaxSequence< OUString >& _rStrings )
+ {
+ OUStringBuffer sMultiLineText;
+ for ( StlSyntaxSequence< OUString >::const_iterator item = _rStrings.begin();
+ item != _rStrings.end();
+ )
+ {
+ sMultiLineText.append(*item);
+ if ( ++item != _rStrings.end() )
+ sMultiLineText.append("\n");
+ }
+ return sMultiLineText.makeStringAndClear();
+ }
+
+
+ OUString lcl_convertListToDisplayText( const StlSyntaxSequence< OUString >& _rStrings )
+ {
+ OUStringBuffer aComposed;
+ for ( StlSyntaxSequence< OUString >::const_iterator strings = _rStrings.begin();
+ strings != _rStrings.end();
+ ++strings
+ )
+ {
+ if ( strings != _rStrings.begin() )
+ aComposed.append( ';' );
+ aComposed.append( '\"' );
+ aComposed.append( *strings );
+ aComposed.append( '\"' );
+ }
+ return aComposed.makeStringAndClear();
+ }
+ }
+
+ void OMultilineEditControl::CheckEntryTextViewMisMatch()
+ {
+ // if there are newlines or something else which the entry cannot show, then make
+ // just the multiline dropdown editable as the canonical source for text
+ m_xEntry->set_sensitive(m_xEntry->get_text() == m_xTextView->get_text());
+ }
+
+ void OMultilineEditControl::SetStringListValue(const StlSyntaxSequence<OUString>& rStrings)
+ {
+ m_xEntry->set_text(lcl_convertListToDisplayText(rStrings));
+ m_xTextView->set_text(lcl_convertListToMultiLine(rStrings));
+ CheckEntryTextViewMisMatch();
+ }
+
+ StlSyntaxSequence<OUString> OMultilineEditControl::GetStringListValue() const
+ {
+ return lcl_convertMultiLineToList(m_xTextView->get_text());
+ }
+
+ void OMultilineEditControl::SetTextValue(const OUString& rText)
+ {
+ OSL_PRECOND( m_nOperationMode == eMultiLineText, "OMultilineEditControl::SetTextValue: illegal call!" );
+
+ m_xTextView->set_text(rText);
+ m_xEntry->set_text(rText);
+ CheckEntryTextViewMisMatch();
+ }
+
+ OUString OMultilineEditControl::GetTextValue() const
+ {
+ OSL_PRECOND( m_nOperationMode == eMultiLineText, "OMultilineEditControl::GetTextValue: illegal call!" );
+ return m_xTextView->get_text();
+ }
+
+ //= OMultilineEditControl
+ OMultilineEditControl::OMultilineEditControl(std::unique_ptr<weld::Container> xWidget, std::unique_ptr<weld::Builder> xBuilder, MultiLineOperationMode eMode, bool bReadOnly)
+ : OMultilineEditControl_Base(eMode == eMultiLineText ? PropertyControlType::MultiLineTextField : PropertyControlType::StringListField,
+ std::move(xBuilder), std::move(xWidget), bReadOnly)
+ , m_nOperationMode(eMode)
+ , m_xEntry(m_xBuilder->weld_entry("entry"))
+ , m_xButton(m_xBuilder->weld_menu_button("button"))
+ , m_xPopover(m_xBuilder->weld_widget("popover"))
+ , m_xTextView(m_xBuilder->weld_text_view("textview"))
+ , m_xOk(m_xBuilder->weld_button("ok"))
+ {
+ m_xButton->set_popover(m_xPopover.get());
+ m_xTextView->set_size_request(m_xTextView->get_approximate_digit_width() * 30, m_xTextView->get_height_rows(8));
+ m_xOk->connect_clicked(LINK(this, OMultilineEditControl, ButtonHandler));
+ }
+
+ IMPL_LINK_NOARG(OMultilineEditControl, TextViewModifiedHdl, weld::TextView&, void)
+ {
+ // tdf#139070 during editing update the entry to look like how it will
+ // look once editing is finished so that the default behaviour of vcl
+ // to strip newlines and the default behaviour of gtk to show a newline
+ // symbol is suppressed
+ OUString sText = m_xTextView->get_text();
+ auto aSeq = lcl_convertMultiLineToList(sText);
+ if (aSeq.getLength() > 1)
+ m_xEntry->set_text(lcl_convertListToDisplayText(aSeq));
+ else
+ m_xEntry->set_text(sText);
+ CheckEntryTextViewMisMatch();
+ setModified();
+ }
+
+ void OMultilineEditControl::editChanged()
+ {
+ m_xTextView->set_text(m_xEntry->get_text());
+ CheckEntryTextViewMisMatch();
+ setModified();
+ }
+
+ IMPL_LINK_NOARG(OMultilineEditControl, ButtonHandler, weld::Button&, void)
+ {
+ m_xButton->set_active(false);
+ notifyModifiedValue();
+ }
+
+ void SAL_CALL OMultilineEditControl::setValue( const Any& _rValue )
+ {
+ impl_checkDisposed_throw();
+
+ switch (m_nOperationMode)
+ {
+ case eMultiLineText:
+ {
+ OUString sText;
+ if ( !( _rValue >>= sText ) && _rValue.hasValue() )
+ throw IllegalTypeException();
+ SetTextValue(sText);
+ break;
+ }
+ case eStringList:
+ {
+ Sequence< OUString > aStringLines;
+ if ( !( _rValue >>= aStringLines ) && _rValue.hasValue() )
+ throw IllegalTypeException();
+ SetStringListValue( StlSyntaxSequence<OUString>(aStringLines) );
+ break;
+ }
+ }
+ }
+
+ Any SAL_CALL OMultilineEditControl::getValue()
+ {
+ impl_checkDisposed_throw();
+
+ Any aValue;
+ switch (m_nOperationMode)
+ {
+ case eMultiLineText:
+ aValue <<= GetTextValue();
+ break;
+ case eStringList:
+ aValue <<= GetStringListValue();
+ break;
+ }
+ return aValue;
+ }
+
+ Type SAL_CALL OMultilineEditControl::getValueType()
+ {
+ if (m_nOperationMode == eMultiLineText)
+ return ::cppu::UnoType<OUString>::get();
+ return cppu::UnoType<Sequence< OUString >>::get();
+ }
+
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/standardcontrol.hxx b/extensions/source/propctrlr/standardcontrol.hxx
new file mode 100644
index 000000000..fcd194886
--- /dev/null
+++ b/extensions/source/propctrlr/standardcontrol.hxx
@@ -0,0 +1,412 @@
+/* -*- 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 "commoncontrol.hxx"
+#include "pcrcommon.hxx"
+
+#include <com/sun/star/inspection/XNumericControl.hpp>
+#include <com/sun/star/inspection/XStringListControl.hpp>
+#include <com/sun/star/inspection/XHyperlinkControl.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <comphelper/interfacecontainer2.hxx>
+#include <svtools/ctrlbox.hxx>
+#include <svx/colorbox.hxx>
+
+namespace pcr
+{
+ //= OTimeControl
+ typedef CommonBehaviourControl<css::inspection::XPropertyControl, weld::FormattedSpinButton> OTimeControl_Base;
+ class OTimeControl : public OTimeControl_Base
+ {
+ std::unique_ptr<weld::TimeFormatter> m_xFormatter;
+ public:
+ OTimeControl(std::unique_ptr<weld::FormattedSpinButton> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly);
+
+ virtual void SAL_CALL disposing() override
+ {
+ m_xFormatter.reset();
+ OTimeControl_Base::disposing();
+ }
+
+ // XPropertyControl
+ virtual css::uno::Any SAL_CALL getValue() override;
+ virtual void SAL_CALL setValue( const css::uno::Any& _value ) override;
+ virtual css::uno::Type SAL_CALL getValueType() override;
+
+ virtual void SetModifyHandler() override
+ {
+ OTimeControl_Base::SetModifyHandler();
+ getTypedControlWindow()->connect_value_changed( LINK( this, CommonBehaviourControlHelper, TimeModifiedHdl ) );
+ }
+
+ virtual weld::Widget* getWidget() override { return getTypedControlWindow(); }
+ };
+
+ //= ODateControl
+ typedef CommonBehaviourControl<css::inspection::XPropertyControl, weld::Container> ODateControl_Base;
+ class ODateControl : public ODateControl_Base
+ {
+ std::unique_ptr<weld::Entry> m_xEntry;
+ std::unique_ptr<SvtCalendarBox> m_xCalendarBox;
+ std::unique_ptr<weld::DateFormatter> m_xEntryFormatter;
+
+ DECL_LINK(ActivateHdl, SvtCalendarBox&, void);
+ DECL_LINK(ToggleHdl, weld::Toggleable&, void);
+
+ public:
+ ODateControl(std::unique_ptr<weld::Container> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly);
+
+ // XPropertyControl
+ virtual css::uno::Any SAL_CALL getValue() override;
+ virtual void SAL_CALL setValue( const css::uno::Any& _value ) override;
+ virtual css::uno::Type SAL_CALL getValueType() override;
+
+ virtual void SetModifyHandler() override
+ {
+ ODateControl_Base::SetModifyHandler();
+
+ m_xEntry->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) );
+ m_xEntryFormatter->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) );
+ m_xCalendarBox->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) );
+ m_xCalendarBox->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) );
+
+ m_xEntryFormatter->connect_changed(LINK(this, CommonBehaviourControlHelper, EditModifiedHdl));
+ }
+
+ virtual void SAL_CALL disposing() override;
+
+ virtual weld::Widget* getWidget() override { return getTypedControlWindow(); }
+ };
+
+ //= OEditControl
+ typedef CommonBehaviourControl<css::inspection::XPropertyControl, weld::Entry> OEditControl_Base;
+ class OEditControl final : public OEditControl_Base
+ {
+ bool m_bIsPassword : 1;
+
+ public:
+ OEditControl(std::unique_ptr<weld::Entry> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bPassWord, bool bReadOnly);
+
+ // XPropertyControl
+ virtual css::uno::Any SAL_CALL getValue() override;
+ virtual void SAL_CALL setValue( const css::uno::Any& _value ) override;
+ virtual css::uno::Type SAL_CALL getValueType() override;
+
+ virtual void SetModifyHandler() override
+ {
+ OEditControl_Base::SetModifyHandler();
+ getTypedControlWindow()->connect_changed( LINK( this, CommonBehaviourControlHelper, EditModifiedHdl ) );
+ }
+
+ private:
+ // CommonBehaviourControlHelper::modified
+ virtual void setModified() override;
+ virtual weld::Widget* getWidget() override { return getTypedControlWindow(); }
+ };
+
+ //= ODateTimeControl
+ typedef CommonBehaviourControl<css::inspection::XPropertyControl, weld::Container> ODateTimeControl_Base;
+ class ODateTimeControl : public ODateTimeControl_Base
+ {
+ private:
+ std::unique_ptr<SvtCalendarBox> m_xDate;
+ std::unique_ptr<weld::FormattedSpinButton> m_xTime;
+ std::unique_ptr<weld::TimeFormatter> m_xFormatter;
+
+ public:
+ ODateTimeControl(std::unique_ptr<weld::Container> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly);
+
+ virtual void SetModifyHandler() override
+ {
+ m_xDate->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) );
+ m_xDate->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) );
+ m_xTime->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) );
+ m_xTime->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) );
+
+ m_xDate->connect_selected( LINK( this, CommonBehaviourControlHelper, DateModifiedHdl ) );
+ m_xTime->connect_value_changed( LINK( this, CommonBehaviourControlHelper, TimeModifiedHdl ) );
+ }
+
+ virtual void SAL_CALL disposing() override
+ {
+ m_xFormatter.reset();
+ m_xTime.reset();
+ m_xDate.reset();
+ ODateTimeControl_Base::disposing();
+ }
+
+ // XPropertyControl
+ virtual css::uno::Any SAL_CALL getValue() override;
+ virtual void SAL_CALL setValue( const css::uno::Any& _value ) override;
+ virtual css::uno::Type SAL_CALL getValueType() override;
+
+ virtual weld::Widget* getWidget() override { return getTypedControlWindow(); }
+ };
+
+ //= OHyperlinkControl
+ typedef CommonBehaviourControl<css::inspection::XHyperlinkControl, weld::Container> OHyperlinkControl_Base;
+ class OHyperlinkControl final : public OHyperlinkControl_Base
+ {
+ private:
+ std::unique_ptr<weld::Entry> m_xEntry;
+ std::unique_ptr<weld::Button> m_xButton;
+
+ ::comphelper::OInterfaceContainerHelper2 m_aActionListeners;
+
+ public:
+ OHyperlinkControl(std::unique_ptr<weld::Container> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly);
+
+ // XPropertyControl
+ virtual css::uno::Any SAL_CALL getValue() override;
+ virtual void SAL_CALL setValue( const css::uno::Any& _value ) override;
+ virtual css::uno::Type SAL_CALL getValueType() override;
+
+ virtual void SetModifyHandler() override
+ {
+ m_xEntry->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) );
+ m_xEntry->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) );
+ m_xButton->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) );
+ m_xButton->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) );
+
+ m_xEntry->connect_changed( LINK( this, CommonBehaviourControlHelper, EditModifiedHdl ) );
+ }
+
+ virtual weld::Widget* getWidget() override { return getTypedControlWindow(); }
+
+ // XHyperlinkControl
+ virtual void SAL_CALL addActionListener( const css::uno::Reference< css::awt::XActionListener >& listener ) override;
+ virtual void SAL_CALL removeActionListener( const css::uno::Reference< css::awt::XActionListener >& listener ) override;
+
+ private:
+ // XComponent
+ virtual void SAL_CALL disposing() override;
+
+ DECL_LINK(OnHyperlinkClicked, weld::Button&, void);
+ };
+
+ //= ONumericControl
+ typedef CommonBehaviourControl<css::inspection::XNumericControl, weld::MetricSpinButton> ONumericControl_Base;
+ class ONumericControl : public ONumericControl_Base
+ {
+ private:
+ FieldUnit m_eValueUnit;
+ sal_Int16 m_nFieldToUNOValueFactor;
+
+ public:
+ ONumericControl(std::unique_ptr<weld::MetricSpinButton> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly);
+
+ // XPropertyControl
+ virtual css::uno::Any SAL_CALL getValue() override;
+ virtual void SAL_CALL setValue( const css::uno::Any& _value ) override;
+ virtual css::uno::Type SAL_CALL getValueType() override;
+
+ // XNumericControl
+ virtual ::sal_Int16 SAL_CALL getDecimalDigits() override;
+ virtual void SAL_CALL setDecimalDigits( ::sal_Int16 _decimaldigits ) override;
+ virtual css::beans::Optional< double > SAL_CALL getMinValue() override;
+ virtual void SAL_CALL setMinValue( const css::beans::Optional< double >& _minvalue ) override;
+ virtual css::beans::Optional< double > SAL_CALL getMaxValue() override;
+ virtual void SAL_CALL setMaxValue( const css::beans::Optional< double >& _maxvalue ) override;
+ virtual ::sal_Int16 SAL_CALL getDisplayUnit() override;
+ virtual void SAL_CALL setDisplayUnit( ::sal_Int16 _displayunit ) override;
+ virtual ::sal_Int16 SAL_CALL getValueUnit() override;
+ virtual void SAL_CALL setValueUnit( ::sal_Int16 _valueunit ) override;
+
+ virtual void SetModifyHandler() override
+ {
+ ONumericControl_Base::SetModifyHandler();
+ weld::MetricSpinButton* pSpinButton = getTypedControlWindow();
+ pSpinButton->connect_value_changed( LINK( this, CommonBehaviourControlHelper, MetricModifiedHdl ) );
+ pSpinButton->get_widget().connect_changed( LINK( this, CommonBehaviourControlHelper, EditModifiedHdl ) );
+ }
+
+ private:
+ virtual weld::Widget* getWidget() override { return &getTypedControlWindow()->get_widget(); }
+
+ /** converts an API value (<code>double</code>, as passed into <code>set[Max|Min|]Value) into
+ a <code>int</code> value which can be passed to our NumericField.
+
+ The conversion respects our decimal digits as well as our value factor (<member>m_nFieldToUNOValueFactor</member>).
+ */
+ sal_Int64 impl_apiValueToFieldValue_nothrow( double nApiValue ) const;
+
+ /** converts a control value, as obtained from our Numeric field, into a value which can passed
+ to outer callers via our UNO API.
+ */
+ double impl_fieldValueToApiValue_nothrow(sal_Int64 nFieldValue) const;
+ };
+
+ //= OColorControl
+ typedef CommonBehaviourControl<css::inspection::XPropertyControl, ColorListBox> OColorControl_Base;
+ class OColorControl : public OColorControl_Base
+ {
+ public:
+ OColorControl(std::unique_ptr<ColorListBox> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly);
+
+ // XPropertyControl
+ virtual css::uno::Any SAL_CALL getValue() override;
+ virtual void SAL_CALL setValue( const css::uno::Any& _value ) override;
+ virtual css::uno::Type SAL_CALL getValueType() override;
+
+ virtual void SetModifyHandler() override
+ {
+ OColorControl_Base::SetModifyHandler();
+ getTypedControlWindow()->SetSelectHdl(LINK(this, CommonBehaviourControlHelper, ColorModifiedHdl));
+ }
+
+ protected:
+ // CommonBehaviourControlHelper::setModified
+ virtual void setModified() override;
+
+ private:
+ virtual weld::Widget* getWidget() override { return &getTypedControlWindow()->get_widget(); }
+ };
+
+ //= OListboxControl
+ typedef CommonBehaviourControl<css::inspection::XStringListControl, weld::ComboBox> OListboxControl_Base;
+ class OListboxControl : public OListboxControl_Base
+ {
+ public:
+ OListboxControl(std::unique_ptr<weld::ComboBox> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly);
+
+ // XPropertyControl
+ virtual css::uno::Any SAL_CALL getValue() override;
+ virtual void SAL_CALL setValue( const css::uno::Any& _value ) override;
+ virtual css::uno::Type SAL_CALL getValueType() override;
+
+ // XStringListControl
+ virtual void SAL_CALL clearList( ) override;
+ virtual void SAL_CALL prependListEntry( const OUString& NewEntry ) override;
+ virtual void SAL_CALL appendListEntry( const OUString& NewEntry ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getListEntries( ) override;
+
+ virtual void SetModifyHandler() override
+ {
+ OListboxControl_Base::SetModifyHandler();
+ getTypedControlWindow()->connect_changed(LINK(this, CommonBehaviourControlHelper, ModifiedHdl));
+ }
+
+ protected:
+ // CommonBehaviourControlHelper::setModified
+ virtual void setModified() override;
+ virtual weld::Widget* getWidget() override { return getTypedControlWindow(); }
+ };
+
+ //= OComboboxControl
+ typedef CommonBehaviourControl< css::inspection::XStringListControl, weld::ComboBox > OComboboxControl_Base;
+ class OComboboxControl final : public OComboboxControl_Base
+ {
+ public:
+ OComboboxControl(std::unique_ptr<weld::ComboBox> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly);
+
+ // XPropertyControl
+ virtual css::uno::Any SAL_CALL getValue() override;
+ virtual void SAL_CALL setValue( const css::uno::Any& _value ) override;
+ virtual css::uno::Type SAL_CALL getValueType() override;
+
+ // XStringListControl
+ virtual void SAL_CALL clearList( ) override;
+ virtual void SAL_CALL prependListEntry( const OUString& NewEntry ) override;
+ virtual void SAL_CALL appendListEntry( const OUString& NewEntry ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getListEntries( ) override;
+
+ virtual void SetModifyHandler() override
+ {
+ OComboboxControl_Base::SetModifyHandler();
+ getTypedControlWindow()->connect_changed(LINK(this, CommonBehaviourControlHelper, ModifiedHdl));
+ }
+
+ // CommonBehaviourControlHelper::setModified
+ virtual weld::Widget* getWidget() override { return getTypedControlWindow(); }
+
+ private:
+ DECL_LINK( OnEntrySelected, weld::ComboBox&, void );
+ };
+
+
+ //= DropDownEditControl
+
+ enum MultiLineOperationMode
+ {
+ eStringList,
+ eMultiLineText
+ };
+
+ //= OMultilineEditControl
+ typedef CommonBehaviourControl<css::inspection::XPropertyControl, weld::Container> OMultilineEditControl_Base;
+ class OMultilineEditControl : public OMultilineEditControl_Base
+ {
+ private:
+ MultiLineOperationMode m_nOperationMode;
+ std::unique_ptr<weld::Entry> m_xEntry;
+ std::unique_ptr<weld::MenuButton> m_xButton;
+ std::unique_ptr<weld::Widget> m_xPopover;
+ std::unique_ptr<weld::TextView> m_xTextView;
+ std::unique_ptr<weld::Button> m_xOk;
+
+ void SetTextValue(const OUString& rText);
+ OUString GetTextValue() const;
+
+ void SetStringListValue( const StlSyntaxSequence< OUString >& _rStrings );
+ StlSyntaxSequence< OUString >
+ GetStringListValue() const;
+
+ DECL_LINK(ButtonHandler, weld::Button&, void);
+ DECL_LINK(TextViewModifiedHdl, weld::TextView&, void);
+
+ void CheckEntryTextViewMisMatch();
+
+ public:
+ OMultilineEditControl(std::unique_ptr<weld::Container> xWidget, std::unique_ptr<weld::Builder> xBuilder, MultiLineOperationMode eMode, bool bReadOnly);
+
+ // XPropertyControl
+ virtual css::uno::Any SAL_CALL getValue() override;
+ virtual void SAL_CALL setValue( const css::uno::Any& _value ) override;
+ virtual css::uno::Type SAL_CALL getValueType() override;
+ virtual weld::Widget* getWidget() override { return getTypedControlWindow(); }
+
+ virtual void editChanged() override;
+
+ virtual void SetModifyHandler() override
+ {
+ m_xEntry->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) );
+ m_xEntry->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) );
+ m_xButton->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) );
+ m_xButton->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) );
+
+ m_xEntry->connect_changed( LINK( this, CommonBehaviourControlHelper, EditModifiedHdl ) );
+ m_xTextView->connect_changed( LINK( this, OMultilineEditControl, TextViewModifiedHdl ) );
+ }
+
+ virtual void SAL_CALL disposing() override
+ {
+ m_xOk.reset();
+ m_xTextView.reset();
+ m_xButton.reset();
+ m_xEntry.reset();
+ OMultilineEditControl_Base::disposing();
+ }
+
+ };
+
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/stringrepresentation.cxx b/extensions/source/propctrlr/stringrepresentation.cxx
new file mode 100644
index 000000000..143ab1363
--- /dev/null
+++ b/extensions/source/propctrlr/stringrepresentation.cxx
@@ -0,0 +1,604 @@
+/* -*- 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 <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/inspection/XStringRepresentation.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/script/CannotConvertException.hpp>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/reflection/XConstantsTypeDescription.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <connectivity/dbconversion.hxx>
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <yesno.hrc>
+#include <comphelper/types.hxx>
+#include <o3tl/string_view.hxx>
+#include "modulepcr.hxx"
+
+#include <algorithm>
+
+namespace pcr{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+class StringRepresentation:
+ public ::cppu::WeakImplHelper<
+ lang::XServiceInfo,
+ inspection::XStringRepresentation,
+ lang::XInitialization>
+{
+public:
+ explicit StringRepresentation(uno::Reference< uno::XComponentContext > const & context);
+ StringRepresentation (const StringRepresentation&) = delete;
+ StringRepresentation& operator=(const StringRepresentation&) = delete;
+
+ // lang::XServiceInfo:
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString & ServiceName) override;
+ virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // inspection::XStringRepresentation:
+ virtual OUString SAL_CALL convertToControlValue(const uno::Any & PropertyValue) override;
+ virtual uno::Any SAL_CALL convertToPropertyValue(const OUString & ControlValue, const uno::Type & ControlValueType) override;
+
+ // lang::XInitialization:
+ virtual void SAL_CALL initialize(const uno::Sequence< uno::Any > & aArguments) override;
+
+private:
+ virtual ~StringRepresentation() override {}
+
+ /** converts a generic value into a string representation
+
+ If you want to convert values whose string representation does not depend
+ on a concrete property, use this version
+
+ @return <TRUE/>
+ if and only if the value could be converted
+ */
+ static bool convertGenericValueToString(
+ const uno::Any& _rValue,
+ OUString& _rStringRep
+ );
+
+ /** converts string representation into generic value
+
+ If you want to convert values whose string representation does not depend
+ on a concrete property, use this version
+
+ @return <TRUE/>
+ if and only if the value could be converted
+ */
+ static bool convertStringToGenericValue(
+ const OUString& _rStringRep,
+ uno::Any& _rValue,
+ const uno::Type& _rTargetType
+ );
+
+ /** uses the simple convert method from the type converter
+ *
+ * \param _rValue the value to be converted
+ * \return the converted string.
+ */
+ OUString convertSimpleToString( const uno::Any& _rValue );
+
+ /** converts a string into his constant value if it exists, otherwise the type converter is used.
+ * \param _rValue the value to be converted
+ * \param _ePropertyType the type of the property to be converted into
+ * \return the converted value
+ */
+ uno::Any convertStringToSimple( const OUString& _rValue,const uno::TypeClass& _ePropertyType );
+
+ uno::Reference< uno::XComponentContext > m_xContext;
+ uno::Reference< script::XTypeConverter > m_xTypeConverter;
+ uno::Reference< reflection::XConstantsTypeDescription > m_xTypeDescription;
+ uno::Sequence< OUString > m_aValues;
+ uno::Sequence< uno::Reference< reflection::XConstantTypeDescription> > m_aConstants;
+
+};
+
+}
+
+StringRepresentation::StringRepresentation(uno::Reference< uno::XComponentContext > const & context) :
+ m_xContext(context)
+{}
+
+// com.sun.star.uno.XServiceInfo:
+OUString SAL_CALL StringRepresentation::getImplementationName()
+{
+ return "StringRepresentation";
+}
+
+sal_Bool SAL_CALL StringRepresentation::supportsService(OUString const & serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+uno::Sequence< OUString > SAL_CALL StringRepresentation::getSupportedServiceNames()
+{
+ return { "com.sun.star.inspection.StringRepresentation" };
+}
+
+// inspection::XStringRepresentation:
+OUString SAL_CALL StringRepresentation::convertToControlValue(const uno::Any & PropertyValue)
+{
+ OUString sReturn;
+ if ( !convertGenericValueToString( PropertyValue, sReturn ) )
+ {
+ sReturn = convertSimpleToString( PropertyValue );
+#ifdef DBG_UTIL
+ if ( sReturn.isEmpty() && PropertyValue.hasValue() )
+ {
+ SAL_WARN( "extensions.propctrlr", "StringRepresentation::convertPropertyValueToStringRepresentation: cannot convert values of type '"
+ << PropertyValue.getValueType().getTypeName()
+ << "'!" );
+ }
+#endif
+ }
+
+ return sReturn;
+}
+
+uno::Any SAL_CALL StringRepresentation::convertToPropertyValue(const OUString & ControlValue, const uno::Type & ControlValueType)
+{
+ uno::Any aReturn;
+
+ uno::TypeClass ePropertyType = ControlValueType.getTypeClass();
+ switch ( ePropertyType )
+ {
+ case uno::TypeClass_FLOAT:
+ case uno::TypeClass_DOUBLE:
+ case uno::TypeClass_BYTE:
+ case uno::TypeClass_SHORT:
+ case uno::TypeClass_LONG:
+ case uno::TypeClass_HYPER:
+ case uno::TypeClass_UNSIGNED_SHORT:
+ case uno::TypeClass_UNSIGNED_LONG:
+ case uno::TypeClass_UNSIGNED_HYPER:
+ try
+ {
+ aReturn = convertStringToSimple(ControlValue, ePropertyType);
+ }
+ catch( const script::CannotConvertException& ) { }
+ catch( const lang::IllegalArgumentException& ) { }
+ break;
+
+ default:
+ #if OSL_DEBUG_LEVEL > 0
+ bool bCanConvert =
+ #endif
+ convertStringToGenericValue( ControlValue, aReturn, ControlValueType );
+
+ #if OSL_DEBUG_LEVEL > 0
+ // could not convert ...
+ if ( !bCanConvert && !ControlValue.isEmpty() )
+ {
+ SAL_WARN( "extensions.propctrlr", "StringRepresentation::convertStringRepresentationToPropertyValue: cannot convert into values of type '"
+ << ControlValueType.getTypeName() << "'!" );
+ }
+ #endif
+ }
+
+ return aReturn;
+}
+
+namespace {
+
+// This comparison functor assumes an underlying set of constants with pairwise
+// unequal values that are all of UNO SHORT or LONG type:
+struct CompareConstants {
+ bool operator ()(
+ css::uno::Reference< css::reflection::XConstantTypeDescription > const &
+ c1,
+ css::uno::Reference< css::reflection::XConstantTypeDescription > const &
+ c2) const
+ {
+ return c1->getConstantValue().get<sal_Int32>()
+ < c2->getConstantValue().get<sal_Int32>();
+ }
+};
+
+}
+
+// lang::XInitialization:
+void SAL_CALL StringRepresentation::initialize(const uno::Sequence< uno::Any > & aArguments)
+{
+ sal_Int32 nLength = aArguments.getLength();
+ if ( !nLength )
+ return;
+
+ const uno::Any* pIter = aArguments.getConstArray();
+ m_xTypeConverter.set(*pIter++,uno::UNO_QUERY);
+ if ( nLength != 3 )
+ return;
+
+ OUString sConstantName;
+ *pIter++ >>= sConstantName;
+ *pIter >>= m_aValues;
+
+ if ( !m_xContext.is() )
+ return;
+
+ uno::Reference< container::XHierarchicalNameAccess > xTypeDescProv(
+ m_xContext->getValueByName("/singletons/com.sun.star.reflection.theTypeDescriptionManager"),
+ uno::UNO_QUERY_THROW );
+
+ m_xTypeDescription.set( xTypeDescProv->getByHierarchicalName( sConstantName ), uno::UNO_QUERY_THROW );
+ uno::Sequence<
+ uno::Reference< reflection::XConstantTypeDescription > >
+ cs(m_xTypeDescription->getConstants());
+ auto [begin, end] = asNonConstRange(cs);
+ std::sort(begin, end, CompareConstants());
+ m_aConstants = cs;
+}
+
+OUString StringRepresentation::convertSimpleToString( const uno::Any& _rValue )
+{
+ OUString sReturn;
+ if ( m_xTypeConverter.is() && _rValue.hasValue() )
+ {
+ try
+ {
+ if ( m_aConstants.hasElements() )
+ {
+ sal_Int16 nConstantValue = 0;
+ if ( _rValue >>= nConstantValue )
+ {
+ const uno::Reference< reflection::XConstantTypeDescription>* pIter = m_aConstants.getConstArray();
+ const uno::Reference< reflection::XConstantTypeDescription>* pEnd = pIter + m_aConstants.getLength();
+ for(sal_Int32 i = 0;pIter != pEnd;++pIter,++i)
+ {
+ if ( (*pIter)->getConstantValue() == _rValue )
+ {
+ OSL_ENSURE(i < m_aValues.getLength() ,"StringRepresentation::convertSimpleToString: Index is not in range of m_aValues");
+ sReturn = m_aValues[i];
+ break;
+ }
+ }
+ }
+ }
+
+ if ( sReturn.isEmpty() )
+ m_xTypeConverter->convertToSimpleType( _rValue, uno::TypeClass_STRING ) >>= sReturn;
+ }
+ catch( const script::CannotConvertException& ) { }
+ catch( const lang::IllegalArgumentException& ) { }
+ }
+ return sReturn;
+}
+
+
+namespace
+{
+ struct ConvertIntegerFromAndToString
+ {
+ OUString operator()( sal_Int32 _rIntValue ) const
+ {
+ return OUString::number( _rIntValue );
+ }
+ sal_Int32 operator()( std::u16string_view _rStringValue ) const
+ {
+ return o3tl::toInt32(_rStringValue);
+ }
+ };
+
+ struct StringIdentity
+ {
+ OUString operator()( const OUString& _rValue ) const
+ {
+ return _rValue;
+ }
+ };
+
+ template < class ElementType, class Transformer >
+ OUString composeSequenceElements( const Sequence< ElementType >& _rElements, const Transformer& _rTransformer )
+ {
+ OUStringBuffer sCompose;
+
+ // loop through the elements and concatenate the string representations of the integers
+ // (separated by a line break)
+ for (const auto& rElement : _rElements)
+ {
+ sCompose.append(OUString(_rTransformer(rElement)));
+ sCompose.append("\n");
+ }
+ sCompose.stripEnd('\n');
+
+ return sCompose.makeStringAndClear();
+ }
+
+ template < class ElementType, class Transformer >
+ void splitComposedStringToSequence( std::u16string_view _rComposed, Sequence< ElementType >& _out_SplitUp, const Transformer& _rTransformer )
+ {
+ _out_SplitUp.realloc( 0 );
+ if ( _rComposed.empty() )
+ return;
+ sal_Int32 tokenPos = 0;
+ do
+ {
+ _out_SplitUp.realloc( _out_SplitUp.getLength() + 1 );
+ _out_SplitUp.getArray()[ _out_SplitUp.getLength() - 1 ] = static_cast<ElementType>(_rTransformer( OUString(o3tl::getToken(_rComposed, 0, '\n', tokenPos )) ));
+ }
+ while ( tokenPos != -1 );
+ }
+}
+
+
+bool StringRepresentation::convertGenericValueToString( const uno::Any& _rValue, OUString& _rStringRep )
+{
+ bool bCanConvert = true;
+
+ switch ( _rValue.getValueTypeClass() )
+ {
+ case uno::TypeClass_STRING:
+ _rValue >>= _rStringRep;
+ break;
+
+ case uno::TypeClass_BOOLEAN:
+ {
+ bool bValue = false;
+ _rValue >>= bValue;
+ _rStringRep = bValue ? PcrRes(RID_RSC_ENUM_YESNO[1])
+ : PcrRes(RID_RSC_ENUM_YESNO[0]);
+ }
+ break;
+
+ // some sequence types
+ case uno::TypeClass_SEQUENCE:
+ {
+ Sequence< OUString > aStringValues;
+ Sequence< sal_Int8 > aInt8Values;
+ Sequence< sal_uInt16 > aUInt16Values;
+ Sequence< sal_Int16 > aInt16Values;
+ Sequence< sal_uInt32 > aUInt32Values;
+ Sequence< sal_Int32 > aInt32Values;
+
+ // string sequences
+ if ( _rValue >>= aStringValues )
+ {
+ _rStringRep = composeSequenceElements( aStringValues, StringIdentity() );
+ }
+ // byte sequences
+ else if ( _rValue >>= aInt8Values )
+ {
+ _rStringRep = composeSequenceElements( aInt8Values, ConvertIntegerFromAndToString() );
+ }
+ // uInt16 sequences
+ else if ( _rValue >>= aUInt16Values )
+ {
+ _rStringRep = composeSequenceElements( aUInt16Values, ConvertIntegerFromAndToString() );
+ }
+ // Int16 sequences
+ else if ( _rValue >>= aInt16Values )
+ {
+ _rStringRep = composeSequenceElements( aInt16Values, ConvertIntegerFromAndToString() );
+ }
+ // uInt32 sequences
+ else if ( _rValue >>= aUInt32Values )
+ {
+ _rStringRep = composeSequenceElements( aUInt32Values, ConvertIntegerFromAndToString() );
+ }
+ // Int32 sequences
+ else if ( _rValue >>= aInt32Values )
+ {
+ _rStringRep = composeSequenceElements( aInt32Values, ConvertIntegerFromAndToString() );
+ }
+ else
+ bCanConvert = false;
+ }
+ break;
+ case uno::TypeClass_CONSTANT:
+ break;
+
+ // some structs
+ case uno::TypeClass_STRUCT:
+ OSL_FAIL( "StringRepresentation::convertGenericValueToString(STRUCT): this is dead code - isn't it?" );
+ if ( _rValue.getValueType().equals( cppu::UnoType< util::Date >::get() ))
+ {
+ // weird enough, the string representation of dates, as used
+ // by the control displaying dates, and thus as passed through the layers,
+ // is YYYYMMDD.
+ util::Date aUnoDate;
+ _rValue >>= aUnoDate;
+ _rStringRep = ::dbtools::DBTypeConversion::toDateString(aUnoDate);
+ }
+ else if ( _rValue.getValueType().equals( cppu::UnoType< util::Time >::get() ))
+ {
+ // similar for time (HHMMSSHH)
+ util::Time aUnoTime;
+ _rValue >>= aUnoTime;
+ _rStringRep = ::dbtools::DBTypeConversion::toTimeString(aUnoTime);
+ }
+ else if ( _rValue.getValueType().equals( cppu::UnoType< util::DateTime >::get() ))
+ {
+ util::DateTime aUnoDateTime;
+ _rValue >>= aUnoDateTime;
+ _rStringRep = ::dbtools::DBTypeConversion::toDateTimeString(aUnoDateTime);
+ }
+ else
+ bCanConvert = false;
+ break;
+
+ default:
+ bCanConvert = false;
+ break;
+ }
+
+ return bCanConvert;
+}
+
+uno::Any StringRepresentation::convertStringToSimple( const OUString& _rValue,const uno::TypeClass& _ePropertyType )
+{
+ uno::Any aReturn;
+ if ( m_xTypeConverter.is() && !_rValue.isEmpty() )
+ {
+ try
+ {
+ if ( m_aConstants.hasElements() && m_aValues.hasElements() )
+ {
+ const OUString* pIter = m_aValues.getConstArray();
+ const OUString* pEnd = pIter + m_aValues.getLength();
+ for(sal_Int32 i = 0;pIter != pEnd;++pIter,++i)
+ {
+ if ( *pIter == _rValue )
+ {
+ OSL_ENSURE(i < m_aConstants.getLength() ,"StringRepresentation::convertSimpleToString: Index is not in range of m_aValues");
+ aReturn = m_aConstants[i]->getConstantValue();
+ break;
+ }
+ }
+ }
+
+ if ( !aReturn.hasValue() )
+ aReturn = m_xTypeConverter->convertToSimpleType( Any( _rValue ), _ePropertyType );
+ }
+ catch( const script::CannotConvertException& ) { }
+ catch( const lang::IllegalArgumentException& ) { }
+ }
+ return aReturn;
+}
+
+bool StringRepresentation::convertStringToGenericValue( const OUString& _rStringRep, uno::Any& _rValue, const uno::Type& _rTargetType )
+{
+ bool bCanConvert = true;
+
+ switch ( _rTargetType.getTypeClass() )
+ {
+ case uno::TypeClass_STRING:
+ _rValue <<= _rStringRep;
+ break;
+
+ case uno::TypeClass_BOOLEAN:
+ {
+ _rValue <<= PcrRes(RID_RSC_ENUM_YESNO[0]) != _rStringRep;
+ }
+ break;
+
+ case uno::TypeClass_SEQUENCE:
+ {
+ uno::Type aElementType = ::comphelper::getSequenceElementType( _rTargetType );
+
+ switch ( aElementType.getTypeClass() )
+ {
+ case uno::TypeClass_STRING:
+ {
+ Sequence< OUString > aElements;
+ splitComposedStringToSequence( _rStringRep, aElements, StringIdentity() );
+ _rValue <<= aElements;
+ }
+ break;
+ case uno::TypeClass_SHORT:
+ {
+ Sequence< sal_Int16 > aElements;
+ splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() );
+ _rValue <<= aElements;
+ }
+ break;
+ case uno::TypeClass_UNSIGNED_SHORT:
+ {
+ Sequence< sal_uInt16 > aElements;
+ splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() );
+ _rValue <<= aElements;
+ }
+ break;
+ case uno::TypeClass_LONG:
+ {
+ Sequence< sal_Int32 > aElements;
+ splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() );
+ _rValue <<= aElements;
+ }
+ break;
+ case uno::TypeClass_UNSIGNED_LONG:
+ {
+ Sequence< sal_uInt32 > aElements;
+ splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() );
+ _rValue <<= aElements;
+ }
+ break;
+ case uno::TypeClass_BYTE:
+ {
+ Sequence< sal_Int8 > aElements;
+ splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() );
+ _rValue <<= aElements;
+ }
+ break;
+ default:
+ bCanConvert = false;
+ break;
+ }
+ }
+ break;
+
+ case uno::TypeClass_STRUCT:
+ OSL_FAIL( "StringRepresentation::convertStringToGenericValue(STRUCT): this is dead code - isn't it?" );
+ if ( _rTargetType.equals( cppu::UnoType< util::Date >::get() ))
+ {
+ // weird enough, the string representation of dates, as used
+ // by the control displaying dates, and thus as passed through the layers,
+ // is YYYYMMDD.
+
+ _rValue <<= ::dbtools::DBTypeConversion::toDate(_rStringRep);
+ }
+ else if ( _rTargetType.equals( cppu::UnoType< util::Time >::get() ))
+ {
+ // similar for time (HHMMSSHH)
+ _rValue <<= ::dbtools::DBTypeConversion::toTime(_rStringRep);
+ }
+ else if ( _rTargetType.equals( cppu::UnoType< util::DateTime >::get() ))
+ {
+ _rValue <<= ::dbtools::DBTypeConversion::toDateTime(_rStringRep);
+ }
+ else
+ bCanConvert = false;
+ break;
+
+ default:
+ bCanConvert = false;
+ break;
+ }
+
+ return bCanConvert;
+}
+
+
+} // pcr
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_StringRepresentation_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::StringRepresentation(context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/submissionhandler.cxx b/extensions/source/propctrlr/submissionhandler.cxx
new file mode 100644
index 000000000..87609e905
--- /dev/null
+++ b/extensions/source/propctrlr/submissionhandler.cxx
@@ -0,0 +1,431 @@
+/* -*- 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 "submissionhandler.hxx"
+#include "formmetadata.hxx"
+#include "formstrings.hxx"
+#include "handlerhelper.hxx"
+
+#include <com/sun/star/form/FormButtonType.hpp>
+#include <com/sun/star/form/submission/XSubmissionSupplier.hpp>
+#include <com/sun/star/inspection/XObjectInspectorUI.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+
+namespace pcr
+{
+
+
+ using namespace ::comphelper;
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::xforms;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::inspection;
+
+
+ //= SubmissionHelper
+
+
+ SubmissionHelper::SubmissionHelper( ::osl::Mutex& _rMutex, const Reference< XPropertySet >& _rxIntrospectee, const Reference< frame::XModel >& _rxContextDocument )
+ :EFormsHelper( _rMutex, _rxIntrospectee, _rxContextDocument )
+ {
+ OSL_ENSURE( canTriggerSubmissions( _rxIntrospectee, _rxContextDocument ),
+ "SubmissionHelper::SubmissionHelper: you should not have instantiated me!" );
+ }
+
+
+ bool SubmissionHelper::canTriggerSubmissions( const Reference< XPropertySet >& _rxControlModel,
+ const Reference< frame::XModel >& _rxContextDocument )
+ {
+ if ( !EFormsHelper::isEForm( _rxContextDocument ) )
+ return false;
+
+ try
+ {
+ Reference< submission::XSubmissionSupplier > xSubmissionSupp( _rxControlModel, UNO_QUERY );
+ if ( xSubmissionSupp.is() )
+ return true;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "SubmissionHelper::canTriggerSubmissions" );
+ }
+ return false;
+ }
+
+
+ //= SubmissionPropertyHandler
+
+
+ SubmissionPropertyHandler::SubmissionPropertyHandler( const Reference< XComponentContext >& _rxContext )
+ :PropertyHandlerComponent( _rxContext )
+ ,OPropertyChangeListener( m_aMutex )
+ {
+ }
+
+
+ SubmissionPropertyHandler::~SubmissionPropertyHandler( )
+ {
+ disposeAdapter();
+ }
+
+
+ OUString SubmissionPropertyHandler::getImplementationName( )
+ {
+ return "com.sun.star.comp.extensions.SubmissionPropertyHandler";
+ }
+
+
+ Sequence< OUString > SubmissionPropertyHandler::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.form.inspection.SubmissionPropertyHandler" };
+ }
+
+
+ Any SAL_CALL SubmissionPropertyHandler::getPropertyValue( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ OSL_ENSURE(m_pHelper, "SubmissionPropertyHandler::getPropertyValue: inconsistency!");
+ // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties
+
+ Any aReturn;
+ try
+ {
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_SUBMISSION_ID:
+ {
+ Reference< submission::XSubmissionSupplier > xSubmissionSupp( m_xComponent, UNO_QUERY );
+ OSL_ENSURE( xSubmissionSupp.is(), "SubmissionPropertyHandler::getPropertyValue: this should never happen ..." );
+ // this handler is not intended for components which are no XSubmissionSupplier
+ Reference< submission::XSubmission > xSubmission;
+ if ( xSubmissionSupp.is() )
+ xSubmission = xSubmissionSupp->getSubmission( );
+ aReturn <<= xSubmission;
+ }
+ break;
+
+ case PROPERTY_ID_XFORMS_BUTTONTYPE:
+ {
+ FormButtonType eType = FormButtonType_PUSH;
+ OSL_VERIFY( m_xComponent->getPropertyValue( PROPERTY_BUTTONTYPE ) >>= eType );
+ if ( ( eType != FormButtonType_PUSH ) && ( eType != FormButtonType_SUBMIT ) )
+ eType = FormButtonType_PUSH;
+ aReturn <<= eType;
+ }
+ break;
+
+ default:
+ OSL_FAIL( "SubmissionPropertyHandler::getPropertyValue: cannot handle this property!" );
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "SubmissionPropertyHandler::getPropertyValue" );
+ }
+
+ return aReturn;
+ }
+
+
+ void SAL_CALL SubmissionPropertyHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ OSL_ENSURE(m_pHelper, "SubmissionPropertyHandler::setPropertyValue: inconsistency!");
+ // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties
+
+ try
+ {
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_SUBMISSION_ID:
+ {
+ Reference< submission::XSubmission > xSubmission;
+ OSL_VERIFY( _rValue >>= xSubmission );
+
+ Reference< submission::XSubmissionSupplier > xSubmissionSupp( m_xComponent, UNO_QUERY );
+ OSL_ENSURE( xSubmissionSupp.is(), "SubmissionPropertyHandler::setPropertyValue: this should never happen ..." );
+ // this handler is not intended for components which are no XSubmissionSupplier
+ if ( xSubmissionSupp.is() )
+ {
+ xSubmissionSupp->setSubmission( xSubmission );
+ impl_setContextDocumentModified_nothrow();
+ }
+ }
+ break;
+
+ case PROPERTY_ID_XFORMS_BUTTONTYPE:
+ m_xComponent->setPropertyValue( PROPERTY_BUTTONTYPE, _rValue );
+ break;
+
+ default:
+ OSL_FAIL( "SubmissionPropertyHandler::setPropertyValue: cannot handle this id!" );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "SubmissionPropertyHandler::setPropertyValue" );
+ }
+ }
+
+
+ Sequence< OUString > SAL_CALL SubmissionPropertyHandler::getActuatingProperties( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (!m_pHelper)
+ return Sequence< OUString >();
+
+ Sequence<OUString> aReturn { PROPERTY_XFORMS_BUTTONTYPE };
+ return aReturn;
+ }
+
+
+ Sequence< OUString > SAL_CALL SubmissionPropertyHandler::getSupersededProperties( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (!m_pHelper)
+ return Sequence< OUString >();
+
+ Sequence< OUString > aReturn{ PROPERTY_TARGET_URL,
+ PROPERTY_TARGET_FRAME,
+ PROPERTY_BUTTONTYPE };
+ return aReturn;
+ }
+
+
+ void SubmissionPropertyHandler::onNewComponent()
+ {
+ if ( m_xPropChangeMultiplexer.is() )
+ {
+ m_xPropChangeMultiplexer->dispose();
+ m_xPropChangeMultiplexer.clear();
+ }
+
+ PropertyHandlerComponent::onNewComponent();
+
+ Reference< frame::XModel > xDocument( impl_getContextDocument_nothrow() );
+ DBG_ASSERT( xDocument.is(), "SubmissionPropertyHandler::onNewComponent: no document!" );
+
+ m_pHelper.reset();
+
+ if ( SubmissionHelper::canTriggerSubmissions( m_xComponent, xDocument ) )
+ {
+ m_pHelper.reset( new SubmissionHelper( m_aMutex, m_xComponent, xDocument ) );
+
+ m_xPropChangeMultiplexer = new OPropertyChangeMultiplexer( this, m_xComponent );
+ m_xPropChangeMultiplexer->addProperty( PROPERTY_BUTTONTYPE );
+ }
+ }
+
+
+ Sequence< Property > SubmissionPropertyHandler::doDescribeSupportedProperties() const
+ {
+ std::vector< Property > aProperties;
+ if (m_pHelper)
+ {
+ implAddPropertyDescription( aProperties, PROPERTY_SUBMISSION_ID, cppu::UnoType<submission::XSubmission>::get() );
+ implAddPropertyDescription( aProperties, PROPERTY_XFORMS_BUTTONTYPE, ::cppu::UnoType<FormButtonType>::get() );
+ }
+ if ( aProperties.empty() )
+ return Sequence< Property >();
+ return comphelper::containerToSequence(aProperties);
+ }
+
+
+ LineDescriptor SAL_CALL SubmissionPropertyHandler::describePropertyLine( const OUString& _rPropertyName,
+ const Reference< XPropertyControlFactory >& _rxControlFactory )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !_rxControlFactory.is() )
+ throw NullPointerException();
+ if (!m_pHelper)
+ throw RuntimeException();
+
+ std::vector< OUString > aListEntries;
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_SUBMISSION_ID:
+ m_pHelper->getAllElementUINames(EFormsHelper::Submission, aListEntries, false);
+ break;
+
+ case PROPERTY_ID_XFORMS_BUTTONTYPE:
+ {
+ // available options are nearly the same as for the "normal" button type, but only the
+ // first two options
+ aListEntries = m_pInfoService->getPropertyEnumRepresentations( PROPERTY_ID_BUTTONTYPE );
+ aListEntries.resize( 2 );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "SubmissionPropertyHandler::describePropertyLine: cannot handle this id!" );
+ return LineDescriptor();
+ }
+
+ LineDescriptor aDescriptor;
+ aDescriptor.Control = PropertyHandlerHelper::createListBoxControl( _rxControlFactory, std::move(aListEntries), false, true );
+ aDescriptor.DisplayName = m_pInfoService->getPropertyTranslation( nPropId );
+ aDescriptor.Category = "General";
+ aDescriptor.HelpURL = HelpIdUrl::getHelpURL( m_pInfoService->getPropertyHelpId( nPropId ) );
+ return aDescriptor;
+ }
+
+
+ void SAL_CALL SubmissionPropertyHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool )
+ {
+ if ( !_rxInspectorUI.is() )
+ throw NullPointerException();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nActuatingPropId( impl_getPropertyId_throwRuntime( _rActuatingPropertyName ) );
+ OSL_PRECOND(m_pHelper,
+ "SubmissionPropertyHandler::actuatingPropertyChanged: inconsistency!");
+ // if we survived impl_getPropertyId_throwRuntime, we should have a helper, since no helper implies no properties
+
+ switch ( nActuatingPropId )
+ {
+ case PROPERTY_ID_XFORMS_BUTTONTYPE:
+ {
+ FormButtonType eType = FormButtonType_PUSH;
+ OSL_VERIFY( _rNewValue >>= eType );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_SUBMISSION_ID, eType == FormButtonType_SUBMIT );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "SubmissionPropertyHandler::actuatingPropertyChanged: cannot handle this id!" );
+ }
+ }
+
+
+ Any SAL_CALL SubmissionPropertyHandler::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Any aPropertyValue;
+
+ OSL_ENSURE(
+ m_pHelper,
+ "SubmissionPropertyHandler::convertToPropertyValue: we have no SupportedProperties!");
+ if (!m_pHelper)
+ return aPropertyValue;
+
+ OUString sControlValue;
+ OSL_VERIFY( _rControlValue >>= sControlValue );
+
+ PropertyId nPropId( m_pInfoService->getPropertyId( _rPropertyName ) );
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_SUBMISSION_ID:
+ {
+ Reference< XSubmission > xSubmission( m_pHelper->getModelElementFromUIName( EFormsHelper::Submission, sControlValue ), UNO_QUERY );
+ aPropertyValue <<= xSubmission;
+ }
+ break;
+
+ case PROPERTY_ID_XFORMS_BUTTONTYPE:
+ {
+ ::rtl::Reference< IPropertyEnumRepresentation > aEnumConversion(
+ new DefaultEnumRepresentation( *m_pInfoService, ::cppu::UnoType<FormButtonType>::get(), PROPERTY_ID_BUTTONTYPE ) );
+ // TODO/UNOize: make aEnumConversion a member?
+ aEnumConversion->getValueFromDescription( sControlValue, aPropertyValue );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "SubmissionPropertyHandler::convertToPropertyValue: cannot handle this id!" );
+ }
+
+ return aPropertyValue;
+ }
+
+
+ Any SAL_CALL SubmissionPropertyHandler::convertToControlValue( const OUString& _rPropertyName, const Any& _rPropertyValue, const Type& _rControlValueType )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Any aControlValue;
+
+ OSL_ENSURE(
+ m_pHelper,
+ "SubmissionPropertyHandler::convertToControlValue: we have no SupportedProperties!");
+ if (!m_pHelper)
+ return aControlValue;
+
+ OSL_ENSURE( _rControlValueType.getTypeClass() == TypeClass_STRING,
+ "SubmissionPropertyHandler::convertToControlValue: all our controls should use strings for value exchange!" );
+
+ PropertyId nPropId( m_pInfoService->getPropertyId( _rPropertyName ) );
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_SUBMISSION_ID:
+ {
+ Reference< XPropertySet > xSubmission( _rPropertyValue, UNO_QUERY );
+ if ( xSubmission.is() )
+ aControlValue <<= EFormsHelper::getModelElementUIName( EFormsHelper::Submission, xSubmission );
+ }
+ break;
+
+ case PROPERTY_ID_XFORMS_BUTTONTYPE:
+ {
+ ::rtl::Reference< IPropertyEnumRepresentation > aEnumConversion(
+ new DefaultEnumRepresentation( *m_pInfoService, _rPropertyValue.getValueType(), PROPERTY_ID_BUTTONTYPE ) );
+ // TODO/UNOize: make aEnumConversion a member?
+ aControlValue <<= aEnumConversion->getDescriptionForValue( _rPropertyValue );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "SubmissionPropertyHandler::convertToControlValue: cannot handle this id!" );
+ }
+
+ return aControlValue;
+ }
+
+
+ void SubmissionPropertyHandler::_propertyChanged( const PropertyChangeEvent& _rEvent )
+ {
+ if ( _rEvent.PropertyName == PROPERTY_BUTTONTYPE )
+ firePropertyChange( PROPERTY_XFORMS_BUTTONTYPE, PROPERTY_ID_XFORMS_BUTTONTYPE, _rEvent.OldValue, _rEvent.NewValue );
+ }
+
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_SubmissionPropertyHandler_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::SubmissionPropertyHandler(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/submissionhandler.hxx b/extensions/source/propctrlr/submissionhandler.hxx
new file mode 100644
index 000000000..f263041b2
--- /dev/null
+++ b/extensions/source/propctrlr/submissionhandler.hxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include "propertyhandler.hxx"
+#include "eformshelper.hxx"
+
+#include <comphelper/propmultiplex.hxx>
+#include <rtl/ref.hxx>
+
+namespace comphelper
+{
+ class OPropertyChangeMultiplexer;
+}
+
+
+namespace pcr
+{
+
+
+ //= SubmissionHelper
+
+ class SubmissionHelper : public EFormsHelper
+ {
+ public:
+ SubmissionHelper(
+ osl::Mutex& _rMutex,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxIntrospectee,
+ const css::uno::Reference< css::frame::XModel >& _rxContextDocument
+ );
+
+ /** determines whether the given control model is able to trigger submissions
+
+ Instances of the <type>SubmissionHelper</type> class should not be instantiated
+ for components where this method returned <FALSE/>
+ */
+ static bool canTriggerSubmissions(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel,
+ const css::uno::Reference< css::frame::XModel >& _rxContextDocument
+ );
+ };
+
+
+ //= SubmissionPropertyHandler
+
+ /** a property handler for any virtual string properties
+ */
+ class SubmissionPropertyHandler : public PropertyHandlerComponent, public ::comphelper::OPropertyChangeListener
+ {
+ private:
+ std::unique_ptr< SubmissionHelper > m_pHelper;
+ rtl::Reference<::comphelper::OPropertyChangeMultiplexer> m_xPropChangeMultiplexer;
+
+ public:
+ explicit SubmissionPropertyHandler(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext
+ );
+
+ virtual ~SubmissionPropertyHandler() override;
+ protected:
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override;
+
+ // XPropertyHandler overriables
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override;
+ virtual css::uno::Sequence< OUString >
+ SAL_CALL getActuatingProperties( ) override;
+ virtual css::uno::Sequence< OUString >
+ SAL_CALL getSupersededProperties( ) override;
+ virtual css::inspection::LineDescriptor
+ SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override;
+ virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool ) override;
+ virtual css::uno::Any SAL_CALL convertToPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rControlValue ) override;
+ virtual css::uno::Any SAL_CALL convertToControlValue( const OUString& _rPropertyName, const css::uno::Any& _rPropertyValue, const css::uno::Type& _rControlValueType ) override;
+
+ // PropertyHandler overridables
+ virtual css::uno::Sequence< css::beans::Property >
+ doDescribeSupportedProperties() const override;
+ virtual void onNewComponent() override;
+
+ private:
+ // OPropertyChangeListener
+ virtual void _propertyChanged(const css::beans::PropertyChangeEvent& _rEvent) override;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/taborder.cxx b/extensions/source/propctrlr/taborder.cxx
new file mode 100644
index 000000000..6ada66b5a
--- /dev/null
+++ b/extensions/source/propctrlr/taborder.cxx
@@ -0,0 +1,320 @@
+/* -*- 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 "taborder.hxx"
+
+#include <bitmaps.hlst>
+#include "formstrings.hxx"
+#include <comphelper/types.hxx>
+#include <comphelper/property.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/form/runtime/FormController.hpp>
+#include <osl/diagnose.h>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace pcr
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::datatransfer;
+
+ namespace {
+
+ OUString GetImage( const Reference< XPropertySet >& _rxSet )
+ {
+ OUString sImageId = RID_EXTBMP_CONTROL;
+ // TODO: classify controls also in Basic propbrw
+ if ( _rxSet.is() && ::comphelper::hasProperty( PROPERTY_CLASSID, _rxSet ) )
+ {
+ switch( ::comphelper::getINT16( _rxSet->getPropertyValue( PROPERTY_CLASSID ) ) )
+ {
+ case FormComponentType::COMMANDBUTTON: sImageId = RID_EXTBMP_BUTTON; break;
+ case FormComponentType::FIXEDTEXT: sImageId = RID_EXTBMP_FIXEDTEXT; break;
+ case FormComponentType::TEXTFIELD: sImageId = RID_EXTBMP_EDITBOX; break;
+ case FormComponentType::RADIOBUTTON: sImageId = RID_EXTBMP_RADIOBUTTON; break;
+ case FormComponentType::CHECKBOX: sImageId = RID_EXTBMP_CHECKBOX; break;
+ case FormComponentType::LISTBOX: sImageId = RID_EXTBMP_LISTBOX; break;
+ case FormComponentType::COMBOBOX: sImageId = RID_EXTBMP_COMBOBOX; break;
+ case FormComponentType::GROUPBOX: sImageId = RID_EXTBMP_GROUPBOX; break;
+ case FormComponentType::IMAGEBUTTON: sImageId = RID_EXTBMP_IMAGEBUTTON; break;
+ case FormComponentType::FILECONTROL: sImageId = RID_EXTBMP_FILECONTROL; break;
+ case FormComponentType::HIDDENCONTROL: sImageId = RID_EXTBMP_HIDDEN; break;
+ case FormComponentType::DATEFIELD: sImageId = RID_EXTBMP_DATEFIELD; break;
+ case FormComponentType::TIMEFIELD: sImageId = RID_EXTBMP_TIMEFIELD; break;
+ case FormComponentType::NUMERICFIELD: sImageId = RID_EXTBMP_NUMERICFIELD; break;
+ case FormComponentType::CURRENCYFIELD: sImageId = RID_EXTBMP_CURRENCYFIELD; break;
+ case FormComponentType::PATTERNFIELD: sImageId = RID_EXTBMP_PATTERNFIELD; break;
+ case FormComponentType::IMAGECONTROL: sImageId = RID_EXTBMP_IMAGECONTROL; break;
+ case FormComponentType::GRIDCONTROL: sImageId = RID_EXTBMP_GRID; break;
+ case FormComponentType::SCROLLBAR: sImageId = RID_EXTBMP_SCROLLBAR; break;
+ case FormComponentType::SPINBUTTON: sImageId = RID_EXTBMP_SPINBUTTON; break;
+ case FormComponentType::NAVIGATIONBAR: sImageId = RID_EXTBMP_NAVIGATIONBAR; break;
+ default:
+ OSL_FAIL( "TabOrderDialog::GetImage: unknown control type" );
+ }
+ }
+
+ return sImageId;
+ }
+
+ //= OSimpleTabModel
+
+ class OSimpleTabModel : public ::cppu::WeakImplHelper< XTabControllerModel>
+ {
+ Sequence< Reference< XControlModel > > m_aModels;
+
+ public:
+ explicit OSimpleTabModel( const Sequence< Reference< XControlModel > >& _rModels )
+ :m_aModels( _rModels )
+ {
+ }
+
+ // XTabControllerModel
+ virtual void SAL_CALL setControlModels(const Sequence< Reference< XControlModel > >& rModels) override {m_aModels = rModels;}
+ virtual Sequence< Reference< XControlModel > > SAL_CALL getControlModels() override {return m_aModels;}
+ virtual void SAL_CALL setGroup(const Sequence< Reference< XControlModel > >& /*Group*/, const OUString& /*GroupName*/) override {}
+ virtual sal_Int32 SAL_CALL getGroupCount() override {return 0;}
+ virtual void SAL_CALL getGroup(sal_Int32 /*nGroup*/, Sequence< Reference< XControlModel > >& /*Group*/, OUString& /*Name*/) override {}
+ virtual void SAL_CALL getGroupByName(const OUString& /*Name*/, Sequence< Reference< XControlModel > >& /*Group*/) override {}
+ virtual sal_Bool SAL_CALL getGroupControl() override {return false;} ;
+ virtual void SAL_CALL setGroupControl(sal_Bool /*GroupControl*/) override {};
+ };
+
+ }
+
+ //= TabOrderDialog
+ TabOrderDialog::TabOrderDialog(weld::Window* _pParent, const Reference< XTabControllerModel >& _rxTabModel,
+ const Reference< XControlContainer >& _rxControlCont, const Reference< XComponentContext >& _rxORB)
+ : GenericDialogController( _pParent, "modules/spropctrlr/ui/taborder.ui", "TabOrderDialog")
+ , m_xModel( _rxTabModel )
+ , m_xControlContainer( _rxControlCont )
+ , m_xORB( _rxORB )
+ , m_xLB_Controls(m_xBuilder->weld_tree_view("CTRLtree"))
+ , m_xPB_OK(m_xBuilder->weld_button("ok"))
+ , m_xPB_MoveUp(m_xBuilder->weld_button("upB"))
+ , m_xPB_MoveDown(m_xBuilder->weld_button("downB"))
+ , m_xPB_AutoOrder(m_xBuilder->weld_button("autoB"))
+ {
+ m_xLB_Controls->set_size_request(m_xLB_Controls->get_approximate_digit_width() * 60,
+ m_xLB_Controls->get_height_rows(10));
+ m_xLB_Controls->set_selection_mode(SelectionMode::Multiple);
+
+ m_xLB_Controls->connect_model_changed(LINK(this, TabOrderDialog, ModelHasMoved));
+ m_xPB_MoveUp->connect_clicked( LINK( this, TabOrderDialog, MoveUpClickHdl ) );
+ m_xPB_MoveDown->connect_clicked( LINK( this, TabOrderDialog, MoveDownClickHdl ) );
+ m_xPB_AutoOrder->connect_clicked( LINK( this, TabOrderDialog, AutoOrderClickHdl ) );
+ m_xPB_OK->connect_clicked( LINK( this, TabOrderDialog, OKClickHdl ) );
+ m_xPB_OK->set_sensitive(false);
+
+ if ( m_xModel.is() )
+ m_xTempModel = new OSimpleTabModel( m_xModel->getControlModels() );
+
+ if ( m_xTempModel.is() && m_xControlContainer.is() )
+ FillList();
+
+ if (m_xLB_Controls->n_children() < 2)
+ {
+ m_xPB_MoveUp->set_sensitive(false);
+ m_xPB_MoveDown->set_sensitive(false);
+ m_xPB_AutoOrder->set_sensitive(false);
+ }
+
+ }
+
+ void TabOrderDialog::SetModified()
+ {
+ m_xPB_OK->set_sensitive(true);
+ }
+
+ TabOrderDialog::~TabOrderDialog()
+ {
+ }
+
+ void TabOrderDialog::FillList()
+ {
+ DBG_ASSERT( m_xTempModel.is() && m_xControlContainer.is(), "TabOrderDialog::FillList: invalid call!" );
+ if ( !m_xTempModel.is() || !m_xControlContainer.is() )
+ return;
+
+ m_xLB_Controls->clear();
+
+ try
+ {
+ OUString aName;
+ OUString aImage;
+
+ const Sequence<Reference<css::awt::XControlModel>> aControlModels = m_xTempModel->getControlModels();
+ for ( auto const& rControlModel : aControlModels )
+ {
+ Reference< XPropertySet > xControl( rControlModel, UNO_QUERY );
+ Reference< XPropertySetInfo > xPI;
+ if ( xControl.is() )
+ xPI = xControl->getPropertySetInfo();
+
+ if ( xPI.is() )
+ {
+ if ( xPI->hasPropertyByName( PROPERTY_TABSTOP ) )
+ {
+ aName = ::comphelper::getString( xControl->getPropertyValue( PROPERTY_NAME ) );
+ // TODO: do Basic controls have a name?
+ aImage = GetImage( xControl );
+ OUString sId(weld::toId(xControl.get()));
+ m_xLB_Controls->append(sId, aName, aImage);
+ }
+ }
+ else
+ {
+ // no property set -> no tab order
+ OSL_FAIL( "TabOrderDialog::FillList: invalid control encountered!" );
+ m_xLB_Controls->clear();
+ break;
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "TabOrderDialog::FillList" );
+ }
+
+ // select first entry
+ if (m_xLB_Controls->n_children())
+ m_xLB_Controls->select(0);
+ }
+
+ IMPL_LINK_NOARG( TabOrderDialog, MoveUpClickHdl, weld::Button&, void )
+ {
+ MoveSelection(-1);
+ }
+
+ IMPL_LINK_NOARG( TabOrderDialog, MoveDownClickHdl, weld::Button&, void )
+ {
+ MoveSelection(1);
+ }
+
+ IMPL_LINK_NOARG( TabOrderDialog, AutoOrderClickHdl, weld::Button&, void )
+ {
+ try
+ {
+ Reference< css::form::runtime::XFormController > xTabController = css::form::runtime::FormController::create( m_xORB );
+
+ xTabController->setModel( m_xTempModel );
+ xTabController->setContainer( m_xControlContainer );
+ xTabController->autoTabOrder();
+
+ SetModified();
+ FillList();
+
+ ::comphelper::disposeComponent( xTabController );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "TabOrderDialog::AutoOrderClickHdl" );
+ }
+ }
+
+ IMPL_LINK_NOARG( TabOrderDialog, OKClickHdl, weld::Button&, void )
+ {
+ int nEntryCount = m_xLB_Controls->n_children();
+ Sequence< Reference< XControlModel > > aSortedControlModelSeq( nEntryCount );
+ const Sequence< Reference< XControlModel > > aControlModels( m_xTempModel->getControlModels());
+ Reference< XControlModel > * pSortedControlModels = aSortedControlModelSeq.getArray();
+
+ for (int i = 0; i < nEntryCount; ++i)
+ {
+ XPropertySet* pEntry = weld::fromId<XPropertySet*>(m_xLB_Controls->get_id(i));
+ for( auto const& rControlModel : aControlModels )
+ {
+ Reference< XPropertySet > xSet(rControlModel, UNO_QUERY);
+ if (xSet.get() == pEntry)
+ {
+ pSortedControlModels[i] = rControlModel;
+ break;
+ }
+ }
+ }
+
+ // TODO: UNO action (to bracket all the single actions which are being created)
+ m_xModel->setControlModels( aSortedControlModelSeq );
+
+ m_xDialog->response(RET_OK);
+ }
+
+ IMPL_LINK_NOARG(TabOrderDialog, ModelHasMoved, weld::TreeView&, void)
+ {
+ SetModified();
+ }
+
+ void TabOrderDialog::MoveSelection(int nRelPos)
+ {
+ std::vector<int> aRows(m_xLB_Controls->get_selected_rows());
+ if (aRows.empty())
+ return;
+
+ m_xLB_Controls->unselect_all();
+ for (int i = 0; i < abs(nRelPos); ++i)
+ {
+ SetModified();
+
+ // move entries
+ if (nRelPos < 0)
+ {
+ std::sort(aRows.begin(), aRows.end());
+
+ int nFirstSelPos = aRows[0];
+ if (nFirstSelPos == 0) return;
+
+ for (auto row : aRows)
+ {
+ int nInsertPos = row - 1;
+ m_xLB_Controls->swap(nInsertPos, row);
+ }
+
+ for (auto row : aRows)
+ m_xLB_Controls->select(row - 1);
+ }
+ else if (nRelPos > 0)
+ {
+ std::sort(aRows.rbegin(), aRows.rend());
+
+ int nLastSelPos = aRows[0];
+ if( (nLastSelPos + nRelPos - i) > (m_xLB_Controls->n_children()-1) ) return;
+
+ for (auto row : aRows)
+ {
+ int nInsertPos = row + 1;
+ m_xLB_Controls->swap(nInsertPos, row);
+ }
+
+ for (auto row : aRows)
+ m_xLB_Controls->select(row + 1);
+ }
+ }
+ }
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/taborder.hxx b/extensions/source/propctrlr/taborder.hxx
new file mode 100644
index 000000000..e43f010e8
--- /dev/null
+++ b/extensions/source/propctrlr/taborder.hxx
@@ -0,0 +1,74 @@
+/* -*- 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/awt/XTabControllerModel.hpp>
+#include <com/sun/star/awt/XControlContainer.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <vcl/weld.hxx>
+
+namespace pcr
+{
+ //= TabOrderDialog
+ class TabOrderDialog : public weld::GenericDialogController
+ {
+ css::uno::Reference< css::awt::XTabControllerModel >
+ m_xTempModel;
+ css::uno::Reference< css::awt::XTabControllerModel >
+ m_xModel;
+ css::uno::Reference< css::awt::XControlContainer >
+ m_xControlContainer;
+ css::uno::Reference< css::uno::XComponentContext >
+ m_xORB;
+
+ std::unique_ptr<weld::TreeView> m_xLB_Controls;
+ std::unique_ptr<weld::Button> m_xPB_OK;
+ std::unique_ptr<weld::Button> m_xPB_MoveUp;
+ std::unique_ptr<weld::Button> m_xPB_MoveDown;
+ std::unique_ptr<weld::Button> m_xPB_AutoOrder;
+
+ DECL_LINK( ModelHasMoved, weld::TreeView&, void );
+ DECL_LINK( MoveUpClickHdl, weld::Button&, void );
+ DECL_LINK( MoveDownClickHdl, weld::Button&, void );
+ DECL_LINK( AutoOrderClickHdl, weld::Button&, void );
+ DECL_LINK( OKClickHdl, weld::Button&, void );
+
+ void FillList();
+ void MoveSelection(int nRelPos);
+
+ public:
+ TabOrderDialog(
+ weld::Window* pParent,
+ const css::uno::Reference< css::awt::XTabControllerModel >& _rxTabModel,
+ const css::uno::Reference< css::awt::XControlContainer >& _rxControlCont,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxORB
+ );
+
+ virtual ~TabOrderDialog() override;
+
+ void SetModified();
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/unourl.cxx b/extensions/source/propctrlr/unourl.cxx
new file mode 100644
index 000000000..88c963012
--- /dev/null
+++ b/extensions/source/propctrlr/unourl.cxx
@@ -0,0 +1,65 @@
+/* -*- 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 "unourl.hxx"
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <comphelper/processfactory.hxx>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::util;
+
+
+ //= UnoURL
+
+ UnoURL::UnoURL( const OUString& _rCompleteURL, const Reference< XMultiServiceFactory >& _rxORB )
+ {
+ m_aURL.Complete = _rCompleteURL;
+
+ OSL_ENSURE( _rxORB.is(), "UnoURL::UnoURL: invalid ORB!" );
+ Reference< XURLTransformer > xTransform;
+ try
+ {
+ if ( _rxORB.is() )
+ {
+ xTransform.set( URLTransformer::create(comphelper::getComponentContext(_rxORB)) );
+ OSL_ENSURE( xTransform.is(), "UnoURL::UnoURL: could not create a URL transformer!" );
+ if ( xTransform.is() )
+ xTransform->parseStrict( m_aURL );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "UnoURL::UnoURL" );
+ }
+ }
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/unourl.hxx b/extensions/source/propctrlr/unourl.hxx
new file mode 100644
index 000000000..824c865ea
--- /dev/null
+++ b/extensions/source/propctrlr/unourl.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/util/URL.hpp>
+
+
+namespace pcr
+{
+
+
+ //= UnoURL
+
+ class UnoURL
+ {
+ private:
+ css::util::URL m_aURL;
+
+ public:
+ UnoURL(
+ const OUString& _rCompleteURL,
+ const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxORB
+ );
+
+ operator const css::util::URL& () const { return m_aURL; }
+ };
+
+
+} // namespacepcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/usercontrol.cxx b/extensions/source/propctrlr/usercontrol.cxx
new file mode 100644
index 000000000..8cccb48e8
--- /dev/null
+++ b/extensions/source/propctrlr/usercontrol.cxx
@@ -0,0 +1,276 @@
+/* -*- 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 "usercontrol.hxx"
+
+#include <com/sun/star/inspection/PropertyControlType.hpp>
+#include <svl/numuno.hxx>
+#include <vcl/GraphicObject.hxx>
+#include <vcl/event.hxx>
+#include <tools/debug.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zformat.hxx>
+#include <connectivity/dbconversion.hxx>
+#include "modulepcr.hxx"
+#include <strings.hrc>
+
+
+namespace pcr
+{
+
+
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Type;
+
+ namespace PropertyControlType = ::com::sun::star::inspection::PropertyControlType;
+
+ IMPL_LINK(OFormatSampleControl, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
+ {
+ // want to handle two keys myself : Del/Backspace should empty the window (setting my prop to "standard" this way)
+ sal_uInt16 nKey = rKeyEvent.GetKeyCode().GetCode();
+ if ((KEY_DELETE == nKey) || (KEY_BACKSPACE == nKey))
+ {
+ m_xSpinButton->set_text("");
+ m_xEntry->set_text("");
+ setModified();
+ }
+
+ return true;
+ }
+
+ void OFormatSampleControl::SetFormatSupplier( const SvNumberFormatsSupplierObj* pSupplier )
+ {
+ Formatter& rFieldFormatter = m_xSpinButton->GetFormatter();
+ if (pSupplier)
+ {
+ rFieldFormatter.TreatAsNumber(true);
+
+ SvNumberFormatter* pFormatter = pSupplier->GetNumberFormatter();
+ rFieldFormatter.SetFormatter(pFormatter);
+ rFieldFormatter.SetValue( 1234.56789 );
+ }
+ else
+ {
+ rFieldFormatter.TreatAsNumber(false);
+ rFieldFormatter.SetFormatter(nullptr);
+ m_xSpinButton->set_text( "" );
+ }
+
+ m_xEntry->set_text(m_xSpinButton->get_text());
+ }
+
+ OFormatSampleControl::OFormatSampleControl(std::unique_ptr<weld::Container> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly)
+ : OFormatSampleControl_Base(PropertyControlType::Unknown, std::move(xBuilder), std::move(xWidget), bReadOnly)
+ , m_xSpinButton(m_xBuilder->weld_formatted_spin_button("sample"))
+ , m_xEntry(m_xBuilder->weld_entry("entry"))
+ {
+ Formatter& rFieldFormatter = m_xSpinButton->GetFormatter();
+ rFieldFormatter.TreatAsNumber(true);
+ rFieldFormatter.ClearMinValue();
+ rFieldFormatter.ClearMaxValue();
+ m_xEntry->connect_key_press(LINK(this, OFormatSampleControl, KeyInputHdl));
+ }
+
+ void SAL_CALL OFormatSampleControl::setValue( const Any& _rValue )
+ {
+ sal_Int32 nFormatKey = 0;
+ if ( _rValue >>= nFormatKey )
+ {
+ // else set the new format key, the text will be reformatted
+ Formatter& rFieldFormatter = m_xSpinButton->GetFormatter();
+ rFieldFormatter.SetFormatKey(nFormatKey);
+
+ SvNumberFormatter* pNF = rFieldFormatter.GetFormatter();
+ const SvNumberformat* pEntry = pNF->GetEntry( nFormatKey );
+ OSL_ENSURE( pEntry, "OFormatSampleControl::setValue: invalid format entry!" );
+
+ const bool bIsTextFormat = ( pEntry && pEntry->IsTextFormat() );
+ if ( bIsTextFormat )
+ m_xSpinButton->set_text( PcrRes( RID_STR_TEXT_FORMAT ) );
+ else
+ rFieldFormatter.SetValue( pEntry ? getPreviewValue( *pEntry ) : 1234.56789 );
+ }
+ else
+ m_xSpinButton->set_text( "" );
+
+ m_xEntry->set_text(m_xSpinButton->get_text());
+ }
+
+ double OFormatSampleControl::getPreviewValue( const SvNumberformat& i_rEntry )
+ {
+ double nValue = 1234.56789;
+ switch ( i_rEntry.GetType() & ~SvNumFormatType::DEFINED )
+ {
+ case SvNumFormatType::DATE:
+ {
+ Date aCurrentDate( Date::SYSTEM );
+ static css::util::Date STANDARD_DB_DATE(30,12,1899);
+ nValue = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDate(aCurrentDate.GetDate()),STANDARD_DB_DATE);
+ }
+ break;
+ case SvNumFormatType::TIME:
+ case SvNumFormatType::DATETIME:
+ {
+ tools::Time aCurrentTime( tools::Time::SYSTEM );
+ nValue = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toTime(aCurrentTime.GetTime()));
+ }
+ break;
+ default:
+ break;
+ }
+ return nValue;
+ }
+
+
+ double OFormatSampleControl::getPreviewValue(SvNumberFormatter const * _pNF, sal_Int32 _nFormatKey)
+ {
+ const SvNumberformat* pEntry = _pNF->GetEntry(_nFormatKey);
+ DBG_ASSERT( pEntry, "OFormattedNumericControl::SetFormatDescription: invalid format key!" );
+ double nValue = 1234.56789;
+ if ( pEntry )
+ nValue = getPreviewValue( *pEntry );
+ return nValue;
+ }
+
+ Any SAL_CALL OFormatSampleControl::getValue()
+ {
+ Any aPropValue;
+ if ( !m_xSpinButton->get_text().isEmpty() )
+ {
+ Formatter& rFieldFormatter = m_xSpinButton->GetFormatter();
+ aPropValue <<= rFieldFormatter.GetValue();
+ }
+ return aPropValue;
+ }
+
+ Type SAL_CALL OFormatSampleControl::getValueType()
+ {
+ return ::cppu::UnoType<sal_Int32>::get();
+ }
+
+ OFormattedNumericControl::OFormattedNumericControl(std::unique_ptr<weld::FormattedSpinButton> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly)
+ : OFormattedNumericControl_Base(PropertyControlType::Unknown, std::move(xBuilder), std::move(xWidget), bReadOnly)
+ {
+ Formatter& rFormatter = getTypedControlWindow()->GetFormatter();
+ rFormatter.TreatAsNumber(true);
+ rFormatter.ClearMinValue();
+ rFormatter.ClearMaxValue();
+ }
+
+ OFormattedNumericControl::~OFormattedNumericControl()
+ {
+ }
+
+ void SAL_CALL OFormattedNumericControl::setValue( const Any& _rValue )
+ {
+ double nValue( 0 );
+ if ( _rValue >>= nValue )
+ getTypedControlWindow()->GetFormatter().SetValue(nValue);
+ else
+ getTypedControlWindow()->set_text("");
+ }
+
+ Any SAL_CALL OFormattedNumericControl::getValue()
+ {
+ Any aPropValue;
+ if ( !getTypedControlWindow()->get_text().isEmpty() )
+ aPropValue <<= getTypedControlWindow()->GetFormatter().GetValue();
+ return aPropValue;
+ }
+
+ Type SAL_CALL OFormattedNumericControl::getValueType()
+ {
+ return ::cppu::UnoType<double>::get();
+ }
+
+ void OFormattedNumericControl::SetFormatDescription(const FormatDescription& rDesc)
+ {
+ bool bFallback = true;
+
+ Formatter& rFieldFormatter = getTypedControlWindow()->GetFormatter();
+ if (rDesc.pSupplier)
+ {
+ rFieldFormatter.TreatAsNumber(true);
+
+ SvNumberFormatter* pFormatter = rDesc.pSupplier->GetNumberFormatter();
+ if (pFormatter != rFieldFormatter.GetFormatter())
+ rFieldFormatter.SetFormatter(pFormatter);
+ rFieldFormatter.SetFormatKey(rDesc.nKey);
+
+ const SvNumberformat* pEntry = rFieldFormatter.GetFormatter()->GetEntry(rFieldFormatter.GetFormatKey());
+ DBG_ASSERT( pEntry, "OFormattedNumericControl::SetFormatDescription: invalid format key!" );
+ if ( pEntry )
+ {
+ bFallback = false;
+ }
+
+ }
+
+ if ( bFallback )
+ {
+ rFieldFormatter.TreatAsNumber(false);
+ rFieldFormatter.SetFormatter(nullptr);
+ getTypedControlWindow()->set_text("");
+ }
+ }
+
+ //= OFileUrlControl
+ OFileUrlControl::OFileUrlControl(std::unique_ptr<SvtURLBox> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly)
+ : OFileUrlControl_Base(PropertyControlType::Unknown, std::move(xBuilder), std::move(xWidget), bReadOnly)
+ {
+ getTypedControlWindow()->DisableHistory();
+ getTypedControlWindow()->SetPlaceHolder( PcrRes( RID_EMBED_IMAGE_PLACEHOLDER ) ) ;
+ }
+
+ OFileUrlControl::~OFileUrlControl()
+ {
+ }
+
+ void SAL_CALL OFileUrlControl::setValue(const Any& rValue)
+ {
+ OUString sURL;
+ SvtURLBox* pControlWindow = getTypedControlWindow();
+ bool bSuccess = rValue >>= sURL;
+ if (bSuccess && GraphicObject::isGraphicObjectUniqueIdURL(sURL))
+ sURL = pControlWindow->GetPlaceHolder();
+ pControlWindow->set_entry_text(sURL);
+ }
+
+ Any SAL_CALL OFileUrlControl::getValue()
+ {
+ Any aPropValue;
+ if (!getTypedControlWindow()->get_active_text().isEmpty())
+ aPropValue <<= getTypedControlWindow()->GetURL();
+ return aPropValue;
+ }
+
+ Type SAL_CALL OFileUrlControl::getValueType()
+ {
+ return ::cppu::UnoType<OUString>::get();
+ }
+
+ IMPL_LINK_NOARG(OFileUrlControl, URLModifiedHdl, weld::ComboBox&, void)
+ {
+ editChanged();
+ }
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/usercontrol.hxx b/extensions/source/propctrlr/usercontrol.hxx
new file mode 100644
index 000000000..86b53e7f1
--- /dev/null
+++ b/extensions/source/propctrlr/usercontrol.hxx
@@ -0,0 +1,148 @@
+/* -*- 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 "commoncontrol.hxx"
+#include <svtools/inettbc.hxx>
+#include <svl/zforlist.hxx>
+
+class SvNumberFormatsSupplierObj;
+
+namespace pcr
+{
+ //= OFormatSampleControl
+ typedef CommonBehaviourControl<css::inspection::XPropertyControl, weld::Container> OFormatSampleControl_Base;
+ class OFormatSampleControl : public OFormatSampleControl_Base
+ {
+ private:
+ std::unique_ptr<weld::FormattedSpinButton> m_xSpinButton;
+ std::unique_ptr<weld::Entry> m_xEntry;
+
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+
+ public:
+ OFormatSampleControl(std::unique_ptr<weld::Container> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly);
+
+ // XPropertyControl
+ virtual css::uno::Any SAL_CALL getValue() override;
+ virtual void SAL_CALL setValue( const css::uno::Any& _value ) override;
+ virtual css::uno::Type SAL_CALL getValueType() override;
+
+ virtual void SAL_CALL disposing() override
+ {
+ m_xEntry.reset();
+ m_xSpinButton.reset();
+ OFormatSampleControl_Base::disposing();
+ }
+
+ virtual void SetModifyHandler() override
+ {
+ m_xEntry->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) );
+ m_xEntry->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) );
+ m_xSpinButton->connect_value_changed(LINK(this, CommonBehaviourControlHelper, FormattedModifiedHdl));
+ m_xSpinButton->connect_changed(LINK(this, CommonBehaviourControlHelper, EditModifiedHdl));
+ }
+
+ void SetFormatSupplier(const SvNumberFormatsSupplierObj* pSupplier);
+
+ virtual weld::Widget* getWidget() override { return getTypedControlWindow(); }
+
+ /** returns the default preview value for the given format key
+ *
+ * \param _pNF the number formatter
+ * \param _nFormatKey the format key
+ * \return current date or time or the value 1234.56789
+ */
+ static double getPreviewValue(SvNumberFormatter const * pNF, sal_Int32 nFormatKey);
+
+ private:
+ static double getPreviewValue( const SvNumberformat& i_rEntry );
+ };
+
+ //= FormatDescription
+ struct FormatDescription
+ {
+ SvNumberFormatsSupplierObj* pSupplier;
+ sal_Int32 nKey;
+ };
+
+ //= OFormattedNumericControl
+ typedef CommonBehaviourControl<css::inspection::XPropertyControl, weld::FormattedSpinButton> OFormattedNumericControl_Base;
+ class OFormattedNumericControl : public OFormattedNumericControl_Base
+ {
+ public:
+ OFormattedNumericControl(std::unique_ptr<weld::FormattedSpinButton> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly);
+
+ // XPropertyControl
+ virtual css::uno::Any SAL_CALL getValue() override;
+ virtual void SAL_CALL setValue( const css::uno::Any& _value ) override;
+ virtual css::uno::Type SAL_CALL getValueType() override;
+
+ void SetFormatDescription( const FormatDescription& rDesc );
+
+ // make some FormattedField methods available
+ void SetDecimalDigits(sal_uInt16 nPrecision) { getTypedControlWindow()->GetFormatter().SetDecimalDigits(nPrecision); }
+ void SetDefaultValue(double dDef) { getTypedControlWindow()->GetFormatter().SetDefaultValue(dDef); }
+
+ virtual void SetModifyHandler() override
+ {
+ OFormattedNumericControl_Base::SetModifyHandler();
+ getTypedControlWindow()->connect_value_changed(LINK(this, CommonBehaviourControlHelper, FormattedModifiedHdl));
+ getTypedControlWindow()->connect_changed(LINK(this, CommonBehaviourControlHelper, EditModifiedHdl));
+ }
+
+ virtual weld::Widget* getWidget() override { return getTypedControlWindow(); }
+
+ protected:
+ virtual ~OFormattedNumericControl() override;
+ };
+
+ //= OFileUrlControl
+ typedef CommonBehaviourControl<css::inspection::XPropertyControl, SvtURLBox> OFileUrlControl_Base;
+ class OFileUrlControl : public OFileUrlControl_Base
+ {
+ private:
+ DECL_LINK(URLModifiedHdl, weld::ComboBox&, void);
+ public:
+ OFileUrlControl(std::unique_ptr<SvtURLBox> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly);
+
+ // XPropertyControl
+ virtual css::uno::Any SAL_CALL getValue() override;
+ virtual void SAL_CALL setValue( const css::uno::Any& _value ) override;
+ virtual css::uno::Type SAL_CALL getValueType() override;
+
+ virtual void SetModifyHandler() override
+ {
+ OFileUrlControl_Base::SetModifyHandler();
+ SvtURLBox* pControlWindow = getTypedControlWindow();
+ // tdf#140239 and tdf#141084 don't notify that the control has changed content until focus-out
+ pControlWindow->connect_focus_out(LINK(this, CommonBehaviourControlHelper, LoseFocusHdl));
+ pControlWindow->connect_changed(LINK(this, OFileUrlControl, URLModifiedHdl));
+ }
+
+ virtual weld::Widget* getWidget() override { return getTypedControlWindow()->getWidget(); }
+
+ protected:
+ virtual ~OFileUrlControl() override;
+ };
+
+} // namespace pcr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/xsddatatypes.cxx b/extensions/source/propctrlr/xsddatatypes.cxx
new file mode 100644
index 000000000..fdaea8e21
--- /dev/null
+++ b/extensions/source/propctrlr/xsddatatypes.cxx
@@ -0,0 +1,185 @@
+/* -*- 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 "xsddatatypes.hxx"
+
+#include <com/sun/star/xsd/DataTypeClass.hpp>
+#include <com/sun/star/xsd/XDataType.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <tools/debug.hxx>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::xsd;
+ using namespace ::com::sun::star::beans;
+
+ template< typename INTERFACE, typename ARGUMENT >
+ static ARGUMENT getSave( INTERFACE* pObject, ARGUMENT ( SAL_CALL INTERFACE::*pGetter )( ) )
+ {
+ ARGUMENT aReturn = ARGUMENT();
+ try
+ {
+ aReturn = (pObject->*pGetter)( );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDDataType: getSave" );
+ }
+ return aReturn;
+ }
+
+ XSDDataType::XSDDataType( const Reference< XDataType >& _rxDataType )
+ :m_xDataType( _rxDataType )
+ {
+ DBG_ASSERT( m_xDataType.is(), "XSDDataType::XSDDataType: invalid UNO object!" );
+ if ( m_xDataType.is() )
+ m_xFacetInfo = m_xDataType->getPropertySetInfo();
+ }
+
+
+ XSDDataType::~XSDDataType()
+ {
+ }
+
+
+ sal_Int16 XSDDataType::classify() const
+ {
+ sal_Int16 nTypeClass = DataTypeClass::STRING;
+ try
+ {
+ if ( m_xDataType.is() )
+ nTypeClass = m_xDataType->getTypeClass();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDDataType::classify" );
+ }
+ return nTypeClass;
+ }
+
+
+ bool XSDDataType::isBasicType() const
+ {
+ return getSave( m_xDataType.get(), &XDataType::getIsBasic );
+ }
+
+
+ OUString XSDDataType::getName() const
+ {
+ return getSave( m_xDataType.get(), &XDataType::getName );
+ }
+
+
+ void XSDDataType::setFacet( const OUString& _rFacetName, const Any& _rValue )
+ {
+ try
+ {
+ m_xDataType->setPropertyValue( _rFacetName, _rValue );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDDataType::setFacet: caught an exception - sure this is the right data type class for this property?" );
+ }
+ }
+
+
+ bool XSDDataType::hasFacet( const OUString& _rFacetName ) const
+ {
+ bool bReturn = false;
+ try
+ {
+ bReturn = m_xFacetInfo.is() && m_xFacetInfo->hasPropertyByName( _rFacetName );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDDataType::hasFacet" );
+ }
+ return bReturn;
+ }
+
+ Any XSDDataType::getFacet( const OUString& _rFacetName )
+ {
+ Any aReturn;
+ try
+ {
+ aReturn = m_xDataType->getPropertyValue( _rFacetName );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDDataType::getFacet: caught an exception - sure this is the right data type class for this property?" );
+ }
+ return aReturn;
+ }
+
+
+ namespace
+ {
+ void lcl_copyProperties( const Reference< XPropertySet >& _rxSource, const Reference< XPropertySet >& _rxDest )
+ {
+ Reference< XPropertySetInfo > xSourceInfo;
+ if ( _rxSource.is() )
+ xSourceInfo = _rxSource->getPropertySetInfo();
+ Reference< XPropertySetInfo > xDestInfo;
+ if ( _rxDest.is() )
+ xDestInfo = _rxDest->getPropertySetInfo();
+ OSL_ENSURE( xSourceInfo.is() && xDestInfo.is(), "lcl_copyProperties: invalid property set( info)s!" );
+ if ( !xSourceInfo.is() || !xDestInfo.is() )
+ return;
+
+ Sequence< Property > aProperties( xSourceInfo->getProperties() );
+ const Property* pProperties = aProperties.getConstArray();
+ const Property* pPropertiesEnd = pProperties + aProperties.getLength();
+ for ( ; pProperties != pPropertiesEnd; ++pProperties )
+ {
+ if ( xDestInfo->hasPropertyByName( pProperties->Name ) )
+ _rxDest->setPropertyValue( pProperties->Name, _rxSource->getPropertyValue( pProperties->Name ) );
+ }
+ }
+ }
+
+
+ void XSDDataType::copyFacetsFrom( const ::rtl::Reference< XSDDataType >& _pSourceType )
+ {
+ OSL_ENSURE( _pSourceType.is(), "XSDDataType::copyFacetsFrom: invalid source type!" );
+ if ( !_pSourceType.is() )
+ return;
+
+ try
+ {
+ Reference< XPropertySet > xSource = _pSourceType->getUnoDataType();
+ Reference< XPropertySet > xDest = getUnoDataType();
+ lcl_copyProperties( xSource, xDest );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDDataType::copyFacetsFrom" );
+ }
+ }
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/xsddatatypes.hxx b/extensions/source/propctrlr/xsddatatypes.hxx
new file mode 100644
index 000000000..0413d0250
--- /dev/null
+++ b/extensions/source/propctrlr/xsddatatypes.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <rtl/ref.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+
+namespace com::sun::star {
+ namespace xsd {
+ class XDataType;
+ }
+ namespace beans {
+ class XPropertySetInfo;
+ }
+}
+
+
+namespace pcr
+{
+
+
+ //= XSDDataType
+
+ class XSDDataType : public salhelper::SimpleReferenceObject
+ {
+ private:
+ css::uno::Reference< css::xsd::XDataType >
+ m_xDataType;
+ css::uno::Reference< css::beans::XPropertySetInfo >
+ m_xFacetInfo;
+
+ public:
+ explicit XSDDataType(
+ const css::uno::Reference< css::xsd::XDataType >& _rxDataType
+ );
+
+ /// retrieves the underlying UNO component
+ const css::uno::Reference< css::xsd::XDataType >&
+ getUnoDataType() const { return m_xDataType; }
+
+ /// classifies the data typ
+ sal_Int16 classify() const;
+
+ // attribute access
+ OUString getName() const;
+ bool isBasicType() const;
+
+ /// determines whether a given facet exists at the type
+ bool hasFacet( const OUString& _rFacetName ) const;
+ /// retrieves a facet value
+ css::uno::Any getFacet( const OUString& _rFacetName );
+ /// sets a facet value
+ void setFacet( const OUString& _rFacetName, const css::uno::Any& _rFacetValue );
+
+ /** copies as much facets (values, respectively) from a give data type instance
+ */
+ void copyFacetsFrom( const ::rtl::Reference< XSDDataType >& _pSourceType );
+
+ protected:
+ virtual ~XSDDataType() override;
+
+ private:
+ XSDDataType( const XSDDataType& ) = delete;
+ XSDDataType& operator=( const XSDDataType& ) = delete;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/xsdvalidationhelper.cxx b/extensions/source/propctrlr/xsdvalidationhelper.cxx
new file mode 100644
index 000000000..b5b96cc28
--- /dev/null
+++ b/extensions/source/propctrlr/xsdvalidationhelper.cxx
@@ -0,0 +1,406 @@
+/* -*- 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 "xsdvalidationhelper.hxx"
+#include "xsddatatypes.hxx"
+#include "formstrings.hxx"
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/xsd/DataTypeClass.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/xforms/XDataTypeRepository.hpp>
+#include <unotools/syslocale.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <tools/diagnose_ex.h>
+
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::xsd;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::xforms;
+
+ namespace NumberFormat = ::com::sun::star::util::NumberFormat;
+
+
+ //= XSDValidationHelper
+
+
+ XSDValidationHelper::XSDValidationHelper( ::osl::Mutex& _rMutex, const Reference< XPropertySet >& _rxIntrospectee, const Reference< frame::XModel >& _rxContextDocument )
+ :EFormsHelper( _rMutex, _rxIntrospectee, _rxContextDocument )
+ ,m_bInspectingFormattedField( false )
+ {
+ try
+ {
+ Reference< XPropertySetInfo > xPSI;
+ Reference< XServiceInfo > xSI( _rxIntrospectee, UNO_QUERY );
+ if ( m_xControlModel.is() )
+ xPSI = m_xControlModel->getPropertySetInfo();
+ if ( xPSI.is()
+ && xPSI->hasPropertyByName( PROPERTY_FORMATKEY )
+ && xPSI->hasPropertyByName( PROPERTY_FORMATSSUPPLIER )
+ && xSI.is()
+ && xSI->supportsService( SERVICE_COMPONENT_FORMATTEDFIELD )
+ )
+ m_bInspectingFormattedField = true;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("extensions.propctrlr",
+ "caught an exception while examining the introspectee!");
+ }
+ }
+
+
+ void XSDValidationHelper::getAvailableDataTypeNames( std::vector< OUString >& /* [out] */ _rNames ) const
+ {
+ _rNames.resize( 0 );
+
+ try
+ {
+ Reference< XDataTypeRepository > xRepository = getDataTypeRepository();
+ if ( xRepository.is() )
+ {
+ const Sequence<OUString> aElements = xRepository->getElementNames();
+
+ _rNames.resize( aElements.getLength() );
+ std::copy( aElements.begin(), aElements.end(), _rNames.begin() );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDValidationHelper::getAvailableDataTypeNames" );
+ }
+ }
+
+
+ Reference< XDataTypeRepository > XSDValidationHelper::getDataTypeRepository() const
+ {
+ Reference< XDataTypeRepository > xRepository;
+
+ Reference< xforms::XModel > xModel( getCurrentFormModel( ) );
+ if ( xModel.is() )
+ xRepository = xModel->getDataTypeRepository();
+
+ return xRepository;
+ }
+
+
+ Reference< XDataTypeRepository > XSDValidationHelper::getDataTypeRepository( const OUString& _rModelName ) const
+ {
+ Reference< XDataTypeRepository > xRepository;
+
+ Reference< xforms::XModel > xModel( getFormModelByName( _rModelName ) );
+ if ( xModel.is() )
+ xRepository = xModel->getDataTypeRepository();
+
+ return xRepository;
+ }
+
+
+ Reference< XDataType > XSDValidationHelper::getDataType( const OUString& _rName ) const
+ {
+ Reference< XDataType > xDataType;
+
+ if ( !_rName.isEmpty() )
+ {
+ Reference< XDataTypeRepository > xRepository = getDataTypeRepository();
+ if ( xRepository.is() )
+ xDataType = xRepository->getDataType( _rName );
+ }
+ return xDataType;
+ }
+
+
+ OUString XSDValidationHelper::getValidatingDataTypeName( ) const
+ {
+ OUString sDataTypeName;
+ try
+ {
+ Reference< XPropertySet > xBinding( getCurrentBinding() );
+ // it's allowed here to not (yet) have a binding
+ if ( xBinding.is() )
+ {
+ OSL_VERIFY( xBinding->getPropertyValue( PROPERTY_XSD_DATA_TYPE ) >>= sDataTypeName );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDValidationHelper::getValidatingDataTypeName" );
+ }
+ return sDataTypeName;
+ }
+
+
+ ::rtl::Reference< XSDDataType > XSDValidationHelper::getDataTypeByName( const OUString& _rName ) const
+ {
+ ::rtl::Reference< XSDDataType > pReturn;
+
+ try
+ {
+ Reference< XDataType > xValidatedAgainst;
+
+ if ( !_rName.isEmpty() )
+ xValidatedAgainst = getDataType( _rName );
+
+ if ( xValidatedAgainst.is() )
+ pReturn = new XSDDataType( xValidatedAgainst );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDValidationHelper::getDataTypeByName" );
+ }
+
+ return pReturn;
+ }
+
+
+ ::rtl::Reference< XSDDataType > XSDValidationHelper::getValidatingDataType( ) const
+ {
+ return getDataTypeByName( getValidatingDataTypeName() );
+ }
+
+
+ bool XSDValidationHelper::cloneDataType( const ::rtl::Reference< XSDDataType >& _pDataType, const OUString& _rNewName ) const
+ {
+ OSL_ENSURE( _pDataType.is(), "XSDValidationHelper::removeDataTypeFromRepository: invalid data type!" );
+ if ( !_pDataType.is() )
+ return false;
+
+ try
+ {
+ Reference< XDataTypeRepository > xRepository( getDataTypeRepository() );
+ OSL_ENSURE( xRepository.is(), "XSDValidationHelper::removeDataTypeFromRepository: invalid data type repository!" );
+ if ( !xRepository.is() )
+ return false;
+
+ Reference< XDataType > xDataType( _pDataType->getUnoDataType() );
+ OSL_ENSURE( xDataType.is(), "XSDValidationHelper::removeDataTypeFromRepository: invalid data type (II)!" );
+ if ( !xDataType.is() )
+ return false;
+
+ xRepository->cloneDataType( xDataType->getName(), _rNewName );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDValidationHelper::cloneDataType" );
+ }
+ return true;
+ }
+
+
+ bool XSDValidationHelper::removeDataTypeFromRepository( const OUString& _rName ) const
+ {
+ try
+ {
+ Reference< XDataTypeRepository > xRepository( getDataTypeRepository() );
+ OSL_ENSURE( xRepository.is(), "XSDValidationHelper::removeDataTypeFromRepository: invalid data type repository!" );
+ if ( !xRepository.is() )
+ return false;
+
+ if ( !xRepository->hasByName( _rName ) )
+ {
+ OSL_FAIL( "XSDValidationHelper::removeDataTypeFromRepository: invalid repository and/or data type!" );
+ return false;
+ }
+
+ xRepository->revokeDataType( _rName );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDValidationHelper::removeDataTypeFromRepository" );
+ return false;
+ }
+ return true;
+ }
+
+
+ void XSDValidationHelper::setValidatingDataTypeByName( const OUString& _rName ) const
+ {
+ try
+ {
+ Reference< XPropertySet > xBinding( getCurrentBinding() );
+ OSL_ENSURE( xBinding.is(), "XSDValidationHelper::setValidatingDataTypeByName: no active binding - how this?" );
+
+ if ( xBinding.is() )
+ {
+ // get the old data type - this is necessary for notifying property changes
+ OUString sOldDataTypeName;
+ OSL_VERIFY( xBinding->getPropertyValue( PROPERTY_XSD_DATA_TYPE ) >>= sOldDataTypeName );
+ Reference< XPropertySet > xOldType;
+ try {
+ xOldType = getDataType( sOldDataTypeName );
+ } catch( const Exception& ) { }
+
+ // set the new data type name
+ xBinding->setPropertyValue( PROPERTY_XSD_DATA_TYPE, Any( _rName ) );
+
+ // retrieve the new data type object
+ Reference< XPropertySet > xNewType = getDataType( _rName );
+
+ // fire any changes in the properties which result from this new type
+ std::set< OUString > aFilter; aFilter.insert( PROPERTY_NAME );
+ firePropertyChanges( xOldType, xNewType, aFilter );
+
+ // fire the change in the Data Type property
+ OUString sNewDataTypeName;
+ OSL_VERIFY( xBinding->getPropertyValue( PROPERTY_XSD_DATA_TYPE ) >>= sNewDataTypeName );
+ firePropertyChange( PROPERTY_XSD_DATA_TYPE, Any( sOldDataTypeName ), Any( sNewDataTypeName ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+
+ void XSDValidationHelper::copyDataType( const OUString& _rFromModel, const OUString& _rToModel,
+ const OUString& _rDataTypeName ) const
+ {
+ if ( _rFromModel == _rToModel )
+ // nothing to do (me thinks)
+ return;
+
+ try
+ {
+ Reference< XDataTypeRepository > xFromRepository, xToRepository;
+ if ( !_rFromModel.isEmpty() )
+ xFromRepository = getDataTypeRepository( _rFromModel );
+ if ( !_rToModel.isEmpty() )
+ xToRepository = getDataTypeRepository( _rToModel );
+
+ if ( !xFromRepository.is() || !xToRepository.is() )
+ return;
+
+ if ( !xFromRepository->hasByName( _rDataTypeName ) || xToRepository->hasByName( _rDataTypeName ) )
+ // not existent in the source, or already existent (by name) in the destination
+ return;
+
+ // determine the built-in type belonging to the source type
+ ::rtl::Reference< XSDDataType > pSourceType = new XSDDataType( xFromRepository->getDataType( _rDataTypeName ) );
+ OUString sTargetBaseType = getBasicTypeNameForClass( pSourceType->classify(), xToRepository );
+
+ // create the target type
+ Reference< XDataType > xTargetType = xToRepository->cloneDataType( sTargetBaseType, _rDataTypeName );
+ ::rtl::Reference< XSDDataType > pTargetType = new XSDDataType( xTargetType );
+
+ // copy the facets
+ pTargetType->copyFacetsFrom( pSourceType );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDValidationHelper::copyDataType" );
+ }
+ }
+
+
+ void XSDValidationHelper::findDefaultFormatForIntrospectee()
+ {
+ try
+ {
+ ::rtl::Reference< XSDDataType > xDataType = getValidatingDataType();
+ if ( xDataType.is() )
+ {
+ // find a NumberFormat type corresponding to the DataTypeClass
+ sal_Int16 nNumberFormatType = NumberFormat::NUMBER;
+ switch ( xDataType->classify() )
+ {
+ case DataTypeClass::DATETIME:
+ nNumberFormatType = NumberFormat::DATETIME;
+ break;
+ case DataTypeClass::DATE:
+ nNumberFormatType = NumberFormat::DATE;
+ break;
+ case DataTypeClass::TIME:
+ nNumberFormatType = NumberFormat::TIME;
+ break;
+ case DataTypeClass::STRING:
+ case DataTypeClass::anyURI:
+ case DataTypeClass::QName:
+ case DataTypeClass::NOTATION:
+ nNumberFormatType = NumberFormat::TEXT;
+ break;
+ }
+
+ // get the number formatter from the introspectee
+ Reference< XNumberFormatsSupplier > xSupplier;
+ Reference< XNumberFormatTypes > xFormatTypes;
+ OSL_VERIFY( m_xControlModel->getPropertyValue( PROPERTY_FORMATSSUPPLIER ) >>= xSupplier );
+ if ( xSupplier.is() )
+ xFormatTypes.set(xSupplier->getNumberFormats(), css::uno::UNO_QUERY);
+ OSL_ENSURE( xFormatTypes.is(), "XSDValidationHelper::findDefaultFormatForIntrospectee: no number formats for the introspectee!" );
+ if ( !xFormatTypes.is() )
+ return;
+
+ // and the standard format for the given NumberFormat type
+ sal_Int32 nDesiredFormat = xFormatTypes->getStandardFormat( nNumberFormatType, SvtSysLocale().GetLanguageTag().getLocale() );
+
+ // set this at the introspectee
+ m_xControlModel->setPropertyValue( PROPERTY_FORMATKEY, Any( nDesiredFormat ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDValidationHelper::findDefaultFormatForIntrospectee" );
+ }
+ }
+
+
+ OUString XSDValidationHelper::getBasicTypeNameForClass( sal_Int16 _nClass ) const
+ {
+ return getBasicTypeNameForClass( _nClass, getDataTypeRepository() );
+ }
+
+
+ OUString XSDValidationHelper::getBasicTypeNameForClass( sal_Int16 _nClass, const Reference< XDataTypeRepository >& _rxRepository )
+ {
+ OUString sReturn;
+ OSL_ENSURE( _rxRepository.is(), "XSDValidationHelper::getBasicTypeNameForClass: invalid repository!" );
+ if ( !_rxRepository.is() )
+ return sReturn;
+
+ try
+ {
+ Reference< XDataType > xDataType = _rxRepository->getBasicDataType( _nClass );
+ OSL_ENSURE( xDataType.is(), "XSDValidationHelper::getBasicTypeNameForClass: invalid data type returned!" );
+ if ( xDataType.is() )
+ sReturn = xDataType->getName();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDValidationHelper::getBasicTypeNameForClass" );
+ }
+
+ return sReturn;
+ }
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/xsdvalidationhelper.hxx b/extensions/source/propctrlr/xsdvalidationhelper.hxx
new file mode 100644
index 000000000..2a77ff584
--- /dev/null
+++ b/extensions/source/propctrlr/xsdvalidationhelper.hxx
@@ -0,0 +1,137 @@
+/* -*- 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 "eformshelper.hxx"
+#include "xsddatatypes.hxx"
+
+#include <com/sun/star/xsd/XDataType.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <rtl/ref.hxx>
+
+
+namespace pcr
+{
+
+
+ class XSDDataType;
+
+ //= XSDValidationHelper
+
+ class XSDValidationHelper : public EFormsHelper
+ {
+ private:
+ bool m_bInspectingFormattedField;
+ public:
+ bool isInspectingFormattedField() const { return m_bInspectingFormattedField; }
+
+ public:
+ XSDValidationHelper(
+ ::osl::Mutex& _rMutex,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxIntrospectee,
+ const css::uno::Reference< css::frame::XModel >& _rxContextDocument
+ );
+
+ /** retrieves the names of all XForms models in the document the control lives in
+ */
+ void getAvailableDataTypeNames( std::vector< OUString >& /* [out] */ _rNames ) const;
+
+ /** retrieves a particular data type given by name
+ */
+ ::rtl::Reference< XSDDataType >
+ getDataTypeByName( const OUString& _rName ) const;
+
+ /** retrieves the DataType instance which the control model is currently validated against
+
+ If there is a binding set at our control model, which at the same time acts as validator,
+ and if this validator is bound to an XDataType, then this data type is retrieved here.
+ */
+ ::rtl::Reference< XSDDataType >
+ getValidatingDataType( ) const;
+
+ /** retrieves the name of the data type which the control model is currently validated against
+
+ @seealso getValidatingDataType
+ */
+ OUString
+ getValidatingDataTypeName( ) const;
+
+ /** binds the validator to a new data type
+
+ To be called with an active binding only.
+ */
+ void setValidatingDataTypeByName( const OUString& _rName ) const;
+
+ /** removes the data type given by name from the data type repository
+ */
+ bool removeDataTypeFromRepository( const OUString& _rName ) const;
+
+ /** creates a new data type, which is a clone of an existing data type
+ */
+ bool cloneDataType( const ::rtl::Reference< XSDDataType >& _pDataType, const OUString& _rNewName ) const;
+
+ /** retrieves the name of the basic data type which has the given class
+ */
+ OUString
+ getBasicTypeNameForClass( sal_Int16 _eClass ) const;
+
+ /** copy a data type from one model to another
+
+ If a data type with the given name already exists in the target model, then nothing
+ happens. In particular, the facets of the data type are not copied.
+ */
+ void copyDataType( const OUString& _rFromModel, const OUString& _rToModel,
+ const OUString& _rDataTypeName ) const;
+
+ /** finds (and sets) a default format for the formatted field we're inspecting,
+ according to the current data type the control value is evaluated against
+ */
+ void findDefaultFormatForIntrospectee();
+
+ private:
+ /** retrieves the data type repository associated with the current model
+ */
+ css::uno::Reference< css::xforms::XDataTypeRepository >
+ getDataTypeRepository() const;
+
+ /** retrieves the data type repository associated with any model
+ */
+ css::uno::Reference< css::xforms::XDataTypeRepository >
+ getDataTypeRepository( const OUString& _rModelName ) const;
+
+ /** retrieves the data type object for the given name
+ */
+ css::uno::Reference< css::xsd::XDataType >
+ getDataType( const OUString& _rName ) const;
+
+ /** retrieves the name of the basic data type which has the given class, in the given repository
+ */
+ static OUString
+ getBasicTypeNameForClass(
+ sal_Int16 _nClass,
+ const css::uno::Reference< css::xforms::XDataTypeRepository >& _rxRepository
+ );
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/xsdvalidationpropertyhandler.cxx b/extensions/source/propctrlr/xsdvalidationpropertyhandler.cxx
new file mode 100644
index 000000000..1f8351cdb
--- /dev/null
+++ b/extensions/source/propctrlr/xsdvalidationpropertyhandler.cxx
@@ -0,0 +1,673 @@
+/* -*- 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 "xsdvalidationpropertyhandler.hxx"
+#include "formstrings.hxx"
+#include "formmetadata.hxx"
+#include "xsddatatypes.hxx"
+#include "modulepcr.hxx"
+#include <strings.hrc>
+#include <propctrlr.h>
+#include "newdatatype.hxx"
+#include "xsdvalidationhelper.hxx"
+#include "pcrcommon.hxx"
+#include "handlerhelper.hxx"
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/xsd/WhiteSpaceTreatment.hpp>
+#include <com/sun/star/xsd/DataTypeClass.hpp>
+#include <com/sun/star/inspection/PropertyControlType.hpp>
+#include <com/sun/star/beans/Optional.hpp>
+#include <com/sun/star/inspection/XObjectInspectorUI.hpp>
+#include <com/sun/star/inspection/PropertyLineElement.hpp>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <tools/debug.hxx>
+#include <sal/macros.h>
+
+#include <algorithm>
+#include <limits>
+
+
+namespace pcr
+{
+
+
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::xforms;
+ using namespace ::com::sun::star::xsd;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::inspection;
+
+ using ::com::sun::star::beans::PropertyAttribute::MAYBEVOID;
+
+
+ //= XSDValidationPropertyHandler
+
+ XSDValidationPropertyHandler::XSDValidationPropertyHandler( const Reference< XComponentContext >& _rxContext )
+ :PropertyHandlerComponent( _rxContext )
+ {
+ }
+
+
+ XSDValidationPropertyHandler::~XSDValidationPropertyHandler()
+ {
+ }
+
+
+ OUString XSDValidationPropertyHandler::getImplementationName( )
+ {
+ return "com.sun.star.comp.extensions.XSDValidationPropertyHandler";
+ }
+
+
+ Sequence< OUString > XSDValidationPropertyHandler::getSupportedServiceNames( )
+ {
+ return{ "com.sun.star.form.inspection.XSDValidationPropertyHandler" };
+ }
+
+
+ Any SAL_CALL XSDValidationPropertyHandler::getPropertyValue( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ OSL_ENSURE(m_pHelper, "XSDValidationPropertyHandler::getPropertyValue: inconsistency!");
+ // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties
+
+ Any aReturn;
+ ::rtl::Reference< XSDDataType > pType = m_pHelper->getValidatingDataType();
+ switch ( nPropId )
+ {
+ // common facets
+ case PROPERTY_ID_XSD_DATA_TYPE: aReturn = pType.is() ? pType->getFacet( PROPERTY_NAME ) : Any( OUString() ); break;
+ case PROPERTY_ID_XSD_WHITESPACES:aReturn = pType.is() ? pType->getFacet( PROPERTY_XSD_WHITESPACES ) : Any( WhiteSpaceTreatment::Preserve ); break;
+ case PROPERTY_ID_XSD_PATTERN: aReturn = pType.is() ? pType->getFacet( PROPERTY_XSD_PATTERN ) : Any( OUString() ); break;
+
+ // all other properties are simply forwarded, if they exist at the given type
+ default:
+ {
+ if ( pType.is() && pType->hasFacet( _rPropertyName ) )
+ aReturn = pType->getFacet( _rPropertyName );
+ }
+ break;
+ }
+
+ return aReturn;
+ }
+
+
+ void SAL_CALL XSDValidationPropertyHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ OSL_ENSURE(m_pHelper, "XSDValidationPropertyHandler::getPropertyValue: inconsistency!");
+ // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties
+
+ if ( PROPERTY_ID_XSD_DATA_TYPE == nPropId )
+ {
+ OUString sTypeName;
+ OSL_VERIFY( _rValue >>= sTypeName );
+ m_pHelper->setValidatingDataTypeByName( sTypeName );
+ impl_setContextDocumentModified_nothrow();
+ return;
+ }
+
+ ::rtl::Reference< XSDDataType > pType = m_pHelper->getValidatingDataType();
+ if ( !pType.is() )
+ {
+ OSL_FAIL( "XSDValidationPropertyHandler::setPropertyValue: you're trying to set a type facet, without a current type!" );
+ return;
+ }
+
+ pType->setFacet( _rPropertyName, _rValue );
+ impl_setContextDocumentModified_nothrow();
+ }
+
+
+ void XSDValidationPropertyHandler::onNewComponent()
+ {
+ PropertyHandlerComponent::onNewComponent();
+
+ Reference< frame::XModel > xDocument( impl_getContextDocument_nothrow() );
+ DBG_ASSERT( xDocument.is(), "XSDValidationPropertyHandler::onNewComponent: no document!" );
+ if ( EFormsHelper::isEForm( xDocument ) )
+ m_pHelper.reset( new XSDValidationHelper( m_aMutex, m_xComponent, xDocument ) );
+ else
+ m_pHelper.reset();
+ }
+
+
+ Sequence< Property > XSDValidationPropertyHandler::doDescribeSupportedProperties() const
+ {
+ std::vector< Property > aProperties;
+
+ if (m_pHelper)
+ {
+ bool bAllowBinding = m_pHelper->canBindToAnyDataType();
+
+ if ( bAllowBinding )
+ {
+ aProperties.reserve( 12 );
+
+ addStringPropertyDescription( aProperties, PROPERTY_XSD_DATA_TYPE );
+ addInt16PropertyDescription ( aProperties, PROPERTY_XSD_WHITESPACES );
+ addStringPropertyDescription( aProperties, PROPERTY_XSD_PATTERN );
+
+ // string facets
+ addInt32PropertyDescription( aProperties, PROPERTY_XSD_LENGTH, MAYBEVOID );
+ addInt32PropertyDescription( aProperties, PROPERTY_XSD_MIN_LENGTH, MAYBEVOID );
+ addInt32PropertyDescription( aProperties, PROPERTY_XSD_MAX_LENGTH, MAYBEVOID );
+
+ // decimal facets
+ addInt32PropertyDescription( aProperties, PROPERTY_XSD_TOTAL_DIGITS, MAYBEVOID );
+ addInt32PropertyDescription( aProperties, PROPERTY_XSD_FRACTION_DIGITS, MAYBEVOID );
+
+ // facets for different types
+ addInt16PropertyDescription( aProperties, PROPERTY_XSD_MAX_INCLUSIVE_INT, MAYBEVOID );
+ addInt16PropertyDescription( aProperties, PROPERTY_XSD_MAX_EXCLUSIVE_INT, MAYBEVOID );
+ addInt16PropertyDescription( aProperties, PROPERTY_XSD_MIN_INCLUSIVE_INT, MAYBEVOID );
+ addInt16PropertyDescription( aProperties, PROPERTY_XSD_MIN_EXCLUSIVE_INT, MAYBEVOID );
+ addDoublePropertyDescription( aProperties, PROPERTY_XSD_MAX_INCLUSIVE_DOUBLE, MAYBEVOID );
+ addDoublePropertyDescription( aProperties, PROPERTY_XSD_MAX_EXCLUSIVE_DOUBLE, MAYBEVOID );
+ addDoublePropertyDescription( aProperties, PROPERTY_XSD_MIN_INCLUSIVE_DOUBLE, MAYBEVOID );
+ addDoublePropertyDescription( aProperties, PROPERTY_XSD_MIN_EXCLUSIVE_DOUBLE, MAYBEVOID );
+ addDatePropertyDescription( aProperties, PROPERTY_XSD_MAX_INCLUSIVE_DATE, MAYBEVOID );
+ addDatePropertyDescription( aProperties, PROPERTY_XSD_MAX_EXCLUSIVE_DATE, MAYBEVOID );
+ addDatePropertyDescription( aProperties, PROPERTY_XSD_MIN_INCLUSIVE_DATE, MAYBEVOID );
+ addDatePropertyDescription( aProperties, PROPERTY_XSD_MIN_EXCLUSIVE_DATE, MAYBEVOID );
+ addTimePropertyDescription( aProperties, PROPERTY_XSD_MAX_INCLUSIVE_TIME, MAYBEVOID );
+ addTimePropertyDescription( aProperties, PROPERTY_XSD_MAX_EXCLUSIVE_TIME, MAYBEVOID );
+ addTimePropertyDescription( aProperties, PROPERTY_XSD_MIN_INCLUSIVE_TIME, MAYBEVOID );
+ addTimePropertyDescription( aProperties, PROPERTY_XSD_MIN_EXCLUSIVE_TIME, MAYBEVOID );
+ addDateTimePropertyDescription( aProperties, PROPERTY_XSD_MAX_INCLUSIVE_DATE_TIME, MAYBEVOID );
+ addDateTimePropertyDescription( aProperties, PROPERTY_XSD_MAX_EXCLUSIVE_DATE_TIME, MAYBEVOID );
+ addDateTimePropertyDescription( aProperties, PROPERTY_XSD_MIN_INCLUSIVE_DATE_TIME, MAYBEVOID );
+ addDateTimePropertyDescription( aProperties, PROPERTY_XSD_MIN_EXCLUSIVE_DATE_TIME, MAYBEVOID );
+ }
+ }
+
+ return comphelper::containerToSequence( aProperties );
+ }
+
+
+ Sequence< OUString > SAL_CALL XSDValidationPropertyHandler::getSupersededProperties( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ std::vector< OUString > aSuperfluous;
+ if (m_pHelper)
+ {
+ aSuperfluous.push_back( OUString(PROPERTY_CONTROLSOURCE) );
+ aSuperfluous.push_back( OUString(PROPERTY_EMPTY_IS_NULL) );
+ aSuperfluous.push_back( OUString(PROPERTY_FILTERPROPOSAL) );
+ aSuperfluous.push_back( OUString(PROPERTY_LISTSOURCETYPE) );
+ aSuperfluous.push_back( OUString(PROPERTY_LISTSOURCE) );
+ aSuperfluous.push_back( OUString(PROPERTY_BOUNDCOLUMN) );
+
+ bool bAllowBinding = m_pHelper->canBindToAnyDataType();
+
+ if ( bAllowBinding )
+ {
+ aSuperfluous.push_back( OUString(PROPERTY_MAXTEXTLEN) );
+ aSuperfluous.push_back( OUString(PROPERTY_VALUEMIN) );
+ aSuperfluous.push_back( OUString(PROPERTY_VALUEMAX) );
+ aSuperfluous.push_back( OUString(PROPERTY_DECIMAL_ACCURACY) );
+ aSuperfluous.push_back( OUString(PROPERTY_TIMEMIN) );
+ aSuperfluous.push_back( OUString(PROPERTY_TIMEMAX) );
+ aSuperfluous.push_back( OUString(PROPERTY_DATEMIN) );
+ aSuperfluous.push_back( OUString(PROPERTY_DATEMAX) );
+ aSuperfluous.push_back( OUString(PROPERTY_EFFECTIVE_MIN) );
+ aSuperfluous.push_back( OUString(PROPERTY_EFFECTIVE_MAX) );
+ }
+ }
+
+ return comphelper::containerToSequence( aSuperfluous );
+ }
+
+
+ Sequence< OUString > SAL_CALL XSDValidationPropertyHandler::getActuatingProperties( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ std::vector< OUString > aInterestedInActuations;
+ if (m_pHelper)
+ {
+ aInterestedInActuations.push_back( OUString(PROPERTY_XSD_DATA_TYPE) );
+ aInterestedInActuations.push_back( OUString(PROPERTY_XML_DATA_MODEL) );
+ }
+ return comphelper::containerToSequence( aInterestedInActuations );
+ }
+
+
+ namespace
+ {
+ void showPropertyUI( const Reference< XObjectInspectorUI >& _rxInspectorUI, const OUString& _rPropertyName, bool _bShow )
+ {
+ if ( _bShow )
+ _rxInspectorUI->showPropertyUI( _rPropertyName );
+ else
+ _rxInspectorUI->hidePropertyUI( _rPropertyName );
+ }
+ }
+
+
+ LineDescriptor SAL_CALL XSDValidationPropertyHandler::describePropertyLine( const OUString& _rPropertyName,
+ const Reference< XPropertyControlFactory >& _rxControlFactory )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !_rxControlFactory.is() )
+ throw NullPointerException();
+ if (!m_pHelper)
+ throw RuntimeException();
+
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ LineDescriptor aDescriptor;
+ if ( nPropId != PROPERTY_ID_XSD_DATA_TYPE )
+ aDescriptor.IndentLevel = 1;
+
+ // collect some information about the to-be-created control
+ sal_Int16 nControlType = PropertyControlType::TextField;
+ std::vector< OUString > aListEntries;
+ Optional< double > aMinValue( false, 0 );
+ Optional< double > aMaxValue( false, 0 );
+
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_XSD_DATA_TYPE:
+ nControlType = PropertyControlType::ListBox;
+
+ implGetAvailableDataTypeNames( aListEntries );
+
+ aDescriptor.PrimaryButtonId = UID_PROP_ADD_DATA_TYPE;
+ aDescriptor.SecondaryButtonId = UID_PROP_REMOVE_DATA_TYPE;
+ aDescriptor.HasPrimaryButton = aDescriptor.HasSecondaryButton = true;
+ aDescriptor.PrimaryButtonImageURL = "private:graphicrepository/extensions/res/buttonplus.png";
+ aDescriptor.SecondaryButtonImageURL = "private:graphicrepository/extensions/res/buttonminus.png";
+ break;
+
+ case PROPERTY_ID_XSD_WHITESPACES:
+ {
+ nControlType = PropertyControlType::ListBox;
+ aListEntries = m_pInfoService->getPropertyEnumRepresentations( PROPERTY_ID_XSD_WHITESPACES );
+ }
+ break;
+
+ case PROPERTY_ID_XSD_PATTERN:
+ nControlType = PropertyControlType::TextField;
+ break;
+
+ case PROPERTY_ID_XSD_LENGTH:
+ case PROPERTY_ID_XSD_MIN_LENGTH:
+ case PROPERTY_ID_XSD_MAX_LENGTH:
+ nControlType = PropertyControlType::NumericField;
+ break;
+
+ case PROPERTY_ID_XSD_TOTAL_DIGITS:
+ case PROPERTY_ID_XSD_FRACTION_DIGITS:
+ nControlType = PropertyControlType::NumericField;
+ break;
+
+ case PROPERTY_ID_XSD_MAX_INCLUSIVE_INT:
+ case PROPERTY_ID_XSD_MAX_EXCLUSIVE_INT:
+ case PROPERTY_ID_XSD_MIN_INCLUSIVE_INT:
+ case PROPERTY_ID_XSD_MIN_EXCLUSIVE_INT:
+ {
+ nControlType = PropertyControlType::NumericField;
+
+ // handle limits for various 'INT' types according to
+ // their actual semantics (year, month, day)
+
+ ::rtl::Reference< XSDDataType > xDataType( m_pHelper->getValidatingDataType() );
+ sal_Int16 nTypeClass = xDataType.is() ? xDataType->classify() : DataTypeClass::STRING;
+
+ aMinValue.IsPresent = aMaxValue.IsPresent = true;
+ aMinValue.Value = DataTypeClass::gYear == nTypeClass ? 0 : 1;
+ aMaxValue.Value = std::numeric_limits< sal_Int32 >::max();
+ if ( DataTypeClass::gMonth == nTypeClass )
+ aMaxValue.Value = 12;
+ else if ( DataTypeClass::gDay == nTypeClass )
+ aMaxValue.Value = 31;
+ }
+ break;
+
+ case PROPERTY_ID_XSD_MAX_INCLUSIVE_DOUBLE:
+ case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DOUBLE:
+ case PROPERTY_ID_XSD_MIN_INCLUSIVE_DOUBLE:
+ case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DOUBLE:
+ nControlType = PropertyControlType::NumericField;
+ // TODO/eForms: do we have "auto-digits"?
+ break;
+
+ case PROPERTY_ID_XSD_MAX_INCLUSIVE_DATE:
+ case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DATE:
+ case PROPERTY_ID_XSD_MIN_INCLUSIVE_DATE:
+ case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DATE:
+ nControlType = PropertyControlType::DateField;
+ break;
+
+ case PROPERTY_ID_XSD_MAX_INCLUSIVE_TIME:
+ case PROPERTY_ID_XSD_MAX_EXCLUSIVE_TIME:
+ case PROPERTY_ID_XSD_MIN_INCLUSIVE_TIME:
+ case PROPERTY_ID_XSD_MIN_EXCLUSIVE_TIME:
+ nControlType = PropertyControlType::TimeField;
+ break;
+
+ case PROPERTY_ID_XSD_MAX_INCLUSIVE_DATE_TIME:
+ case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DATE_TIME:
+ case PROPERTY_ID_XSD_MIN_INCLUSIVE_DATE_TIME:
+ case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DATE_TIME:
+ nControlType = PropertyControlType::DateTimeField;
+ break;
+
+ default:
+ OSL_FAIL( "XSDValidationPropertyHandler::describePropertyLine: cannot handle this property!" );
+ break;
+ }
+
+ switch ( nControlType )
+ {
+ case PropertyControlType::ListBox:
+ aDescriptor.Control = PropertyHandlerHelper::createListBoxControl( _rxControlFactory, std::move(aListEntries), false, false );
+ break;
+ case PropertyControlType::NumericField:
+ aDescriptor.Control = PropertyHandlerHelper::createNumericControl( _rxControlFactory, 0, aMinValue, aMaxValue );
+ break;
+ default:
+ aDescriptor.Control = _rxControlFactory->createPropertyControl( nControlType, false );
+ break;
+ }
+
+ aDescriptor.Category = "Data";
+ aDescriptor.DisplayName = m_pInfoService->getPropertyTranslation( nPropId );
+ aDescriptor.HelpURL = HelpIdUrl::getHelpURL( m_pInfoService->getPropertyHelpId( nPropId ) );
+
+ return aDescriptor;
+ }
+
+
+ InteractiveSelectionResult SAL_CALL XSDValidationPropertyHandler::onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, Any& /*_rData*/, const Reference< XObjectInspectorUI >& _rxInspectorUI )
+ {
+ if ( !_rxInspectorUI.is() )
+ throw NullPointerException();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OSL_ENSURE(m_pHelper, "XSDValidationPropertyHandler::onInteractivePropertySelection: we "
+ "don't have any SupportedProperties!");
+ if (!m_pHelper)
+ return InteractiveSelectionResult_Cancelled;
+
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_XSD_DATA_TYPE:
+ {
+ if ( _bPrimary )
+ {
+ OUString sNewDataTypeName;
+ if ( implPrepareCloneDataCurrentType( sNewDataTypeName ) )
+ {
+ implDoCloneCurrentDataType( sNewDataTypeName );
+ return InteractiveSelectionResult_Success;
+ }
+ }
+ else
+ return implPrepareRemoveCurrentDataType() && implDoRemoveCurrentDataType() ? InteractiveSelectionResult_Success : InteractiveSelectionResult_Cancelled;
+ }
+ break;
+
+ default:
+ OSL_FAIL( "XSDValidationPropertyHandler::onInteractivePropertySelection: unexpected property to build a dedicated UI!" );
+ break;
+ }
+ return InteractiveSelectionResult_Cancelled;
+ }
+
+
+ void SAL_CALL XSDValidationPropertyHandler::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyHandlerComponent::addPropertyChangeListener( _rxListener );
+ if (m_pHelper)
+ m_pHelper->registerBindingListener( _rxListener );
+ }
+
+
+ void SAL_CALL XSDValidationPropertyHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (m_pHelper)
+ m_pHelper->revokeBindingListener( _rxListener );
+ PropertyHandlerComponent::removePropertyChangeListener( _rxListener );
+ }
+
+
+ bool XSDValidationPropertyHandler::implPrepareCloneDataCurrentType( OUString& _rNewName )
+ {
+ OSL_PRECOND(
+ m_pHelper,
+ "XSDValidationPropertyHandler::implPrepareCloneDataCurrentType: this will crash!");
+
+ ::rtl::Reference< XSDDataType > pType = m_pHelper->getValidatingDataType();
+ if ( !pType.is() )
+ {
+ OSL_FAIL( "XSDValidationPropertyHandler::implPrepareCloneDataCurrentType: invalid current data type!" );
+ return false;
+ }
+
+ std::vector< OUString > aExistentNames;
+ m_pHelper->getAvailableDataTypeNames( aExistentNames );
+
+ NewDataTypeDialog aDialog( nullptr, pType->getName(), aExistentNames ); // TODO/eForms: proper parent
+ if (aDialog.run() != RET_OK)
+ return false;
+
+ _rNewName = aDialog.GetName();
+ return true;
+ }
+
+
+ void XSDValidationPropertyHandler::implDoCloneCurrentDataType( const OUString& _rNewName )
+ {
+ OSL_PRECOND(m_pHelper,
+ "XSDValidationPropertyHandler::implDoCloneCurrentDataType: this will crash!");
+
+ ::rtl::Reference< XSDDataType > pType = m_pHelper->getValidatingDataType();
+ if ( !pType.is() )
+ return;
+
+ if ( !m_pHelper->cloneDataType( pType, _rNewName ) )
+ return;
+
+ m_pHelper->setValidatingDataTypeByName( _rNewName );
+ }
+
+ bool XSDValidationPropertyHandler::implPrepareRemoveCurrentDataType()
+ {
+ OSL_PRECOND(
+ m_pHelper,
+ "XSDValidationPropertyHandler::implPrepareRemoveCurrentDataType: this will crash!");
+
+ ::rtl::Reference< XSDDataType > pType = m_pHelper->getValidatingDataType();
+ if ( !pType.is() )
+ {
+ OSL_FAIL( "XSDValidationPropertyHandler::implPrepareRemoveCurrentDataType: invalid current data type!" );
+ return false;
+ }
+
+ // confirmation message
+ OUString sConfirmation( PcrRes( RID_STR_CONFIRM_DELETE_DATA_TYPE ) );
+ sConfirmation = sConfirmation.replaceFirst( "#type#", pType->getName() );
+
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr, // TODO/eForms: proper parent
+ VclMessageType::Question, VclButtonsType::YesNo,
+ sConfirmation));
+ return xQueryBox->run() == RET_YES;
+ }
+
+ bool XSDValidationPropertyHandler::implDoRemoveCurrentDataType()
+ {
+ OSL_PRECOND(m_pHelper,
+ "XSDValidationPropertyHandler::implDoRemoveCurrentDataType: this will crash!");
+
+ ::rtl::Reference< XSDDataType > pType = m_pHelper->getValidatingDataType();
+ if ( !pType.is() )
+ return false;
+
+ // set a new data type at the binding, which is the "basic" type for the one
+ // we are going to delete
+ // (do this before the actual deletion, so the old type is still valid for property change
+ // notifications)
+ m_pHelper->setValidatingDataTypeByName( m_pHelper->getBasicTypeNameForClass( pType->classify() ) );
+ // now remove the type
+ m_pHelper->removeDataTypeFromRepository( pType->getName() );
+
+ return true;
+ }
+
+
+ void SAL_CALL XSDValidationPropertyHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& _rOldValue, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit )
+ {
+ if ( !_rxInspectorUI.is() )
+ throw NullPointerException();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nActuatingPropId( impl_getPropertyId_throwRuntime( _rActuatingPropertyName ) );
+ if (!m_pHelper)
+ throw RuntimeException();
+ // if we survived impl_getPropertyId_throwRuntime, we should have a helper, since no helper implies no properties
+
+ switch ( nActuatingPropId )
+ {
+ case PROPERTY_ID_XSD_DATA_TYPE:
+ {
+ ::rtl::Reference< XSDDataType > xDataType( m_pHelper->getValidatingDataType() );
+
+ // is removal of this type possible?
+ bool bIsBasicType = xDataType.is() && xDataType->isBasicType();
+ _rxInspectorUI->enablePropertyUIElements( PROPERTY_XSD_DATA_TYPE, PropertyLineElement::PrimaryButton, xDataType.is() );
+ _rxInspectorUI->enablePropertyUIElements( PROPERTY_XSD_DATA_TYPE, PropertyLineElement::SecondaryButton, xDataType.is() && !bIsBasicType );
+
+
+ // show the facets which are available at the data type
+ OUString aFacets[] = {
+ OUString(PROPERTY_XSD_WHITESPACES), OUString(PROPERTY_XSD_PATTERN),
+ OUString(PROPERTY_XSD_LENGTH), OUString(PROPERTY_XSD_MIN_LENGTH), OUString(PROPERTY_XSD_MAX_LENGTH), OUString(PROPERTY_XSD_TOTAL_DIGITS),
+ OUString(PROPERTY_XSD_FRACTION_DIGITS),
+ OUString(PROPERTY_XSD_MAX_INCLUSIVE_INT),
+ OUString(PROPERTY_XSD_MAX_EXCLUSIVE_INT),
+ OUString(PROPERTY_XSD_MIN_INCLUSIVE_INT),
+ OUString(PROPERTY_XSD_MIN_EXCLUSIVE_INT),
+ OUString(PROPERTY_XSD_MAX_INCLUSIVE_DOUBLE),
+ OUString(PROPERTY_XSD_MAX_EXCLUSIVE_DOUBLE),
+ OUString(PROPERTY_XSD_MIN_INCLUSIVE_DOUBLE),
+ OUString(PROPERTY_XSD_MIN_EXCLUSIVE_DOUBLE),
+ OUString(PROPERTY_XSD_MAX_INCLUSIVE_DATE),
+ OUString(PROPERTY_XSD_MAX_EXCLUSIVE_DATE),
+ OUString(PROPERTY_XSD_MIN_INCLUSIVE_DATE),
+ OUString(PROPERTY_XSD_MIN_EXCLUSIVE_DATE),
+ OUString(PROPERTY_XSD_MAX_INCLUSIVE_TIME),
+ OUString(PROPERTY_XSD_MAX_EXCLUSIVE_TIME),
+ OUString(PROPERTY_XSD_MIN_INCLUSIVE_TIME),
+ OUString(PROPERTY_XSD_MIN_EXCLUSIVE_TIME),
+ OUString(PROPERTY_XSD_MAX_INCLUSIVE_DATE_TIME),
+ OUString(PROPERTY_XSD_MAX_EXCLUSIVE_DATE_TIME),
+ OUString(PROPERTY_XSD_MIN_INCLUSIVE_DATE_TIME),
+ OUString(PROPERTY_XSD_MIN_EXCLUSIVE_DATE_TIME)
+ };
+
+ size_t i=0;
+ const OUString* pLoop = nullptr;
+ for ( i = 0, pLoop = aFacets;
+ i < SAL_N_ELEMENTS( aFacets );
+ ++i, ++pLoop
+ )
+ {
+ showPropertyUI( _rxInspectorUI, *pLoop, xDataType.is() && xDataType->hasFacet( *pLoop ) );
+ _rxInspectorUI->enablePropertyUI( *pLoop, !bIsBasicType );
+ }
+ }
+ break;
+
+ case PROPERTY_ID_XML_DATA_MODEL:
+ {
+ // The data type which the current binding works with may not be present in the
+ // new model. Thus, transfer it.
+ OUString sOldModelName; _rOldValue >>= sOldModelName;
+ OUString sNewModelName; _rNewValue >>= sNewModelName;
+ OUString sDataType = m_pHelper->getValidatingDataTypeName();
+ m_pHelper->copyDataType( sOldModelName, sNewModelName, sDataType );
+
+ // the list of available data types depends on the chosen model, so update this
+ if ( !_bFirstTimeInit )
+ _rxInspectorUI->rebuildPropertyUI( PROPERTY_XSD_DATA_TYPE );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "XSDValidationPropertyHandler::actuatingPropertyChanged: cannot handle this property!" );
+ return;
+ }
+
+ // in both cases, we need to care for the current value of the XSD_DATA_TYPE property,
+ // and update the FormatKey of the formatted field we're inspecting (if any)
+ if ( !_bFirstTimeInit && m_pHelper->isInspectingFormattedField() )
+ m_pHelper->findDefaultFormatForIntrospectee();
+ }
+
+
+ void XSDValidationPropertyHandler::implGetAvailableDataTypeNames( std::vector< OUString >& /* [out] */ _rNames ) const
+ {
+ OSL_PRECOND(
+ m_pHelper,
+ "XSDValidationPropertyHandler::implGetAvailableDataTypeNames: this will crash!");
+ // start with *all* types which are available at the model
+ std::vector< OUString > aAllTypes;
+ m_pHelper->getAvailableDataTypeNames( aAllTypes );
+ _rNames.clear();
+ _rNames.reserve( aAllTypes.size() );
+
+ // then allow only those which are "compatible" with our control
+ for (auto const& dataType : aAllTypes)
+ {
+ ::rtl::Reference< XSDDataType > pType = m_pHelper->getDataTypeByName(dataType);
+ if ( pType.is() && m_pHelper->canBindToDataType( pType->classify() ) )
+ _rNames.push_back(dataType);
+ }
+ }
+
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_XSDValidationPropertyHandler_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::XSDValidationPropertyHandler(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/propctrlr/xsdvalidationpropertyhandler.hxx b/extensions/source/propctrlr/xsdvalidationpropertyhandler.hxx
new file mode 100644
index 000000000..32803b215
--- /dev/null
+++ b/extensions/source/propctrlr/xsdvalidationpropertyhandler.hxx
@@ -0,0 +1,88 @@
+/* -*- 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 "propertyhandler.hxx"
+
+#include <memory>
+
+
+namespace pcr
+{
+
+
+ class XSDValidationHelper;
+
+ //= XSDValidationPropertyHandler
+
+ class XSDValidationPropertyHandler : public PropertyHandlerComponent
+ {
+ private:
+ std::unique_ptr< XSDValidationHelper > m_pHelper;
+
+ public:
+ explicit XSDValidationPropertyHandler(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext
+ );
+
+ protected:
+ virtual ~XSDValidationPropertyHandler() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override;
+
+ // XPropertyHandler overriables
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override;
+ virtual css::uno::Sequence< OUString >
+ SAL_CALL getSupersededProperties( ) override;
+ virtual css::uno::Sequence< OUString >
+ SAL_CALL getActuatingProperties( ) override;
+ virtual css::inspection::LineDescriptor
+ SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override;
+ virtual css::inspection::InteractiveSelectionResult
+ SAL_CALL onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, css::uno::Any& _rData, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) override;
+ virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+
+ // PropertyHandler overridables
+ virtual css::uno::Sequence< css::beans::Property >
+ doDescribeSupportedProperties() const override;
+ virtual void onNewComponent() override;
+
+ private:
+ bool implPrepareRemoveCurrentDataType();
+ bool implDoRemoveCurrentDataType();
+
+ bool implPrepareCloneDataCurrentType( OUString& _rNewName );
+ void implDoCloneCurrentDataType( const OUString& _rNewName );
+
+ /** retrieves the names of the data types which our introspectee can be validated against
+ */
+ void implGetAvailableDataTypeNames( std::vector< OUString >& /* [out] */ _rNames ) const;
+ };
+
+
+} // namespace pcr
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */