summaryrefslogtreecommitdiffstats
path: root/xmloff/source/forms
diff options
context:
space:
mode:
Diffstat (limited to 'xmloff/source/forms')
-rw-r--r--xmloff/source/forms/callbacks.hxx79
-rw-r--r--xmloff/source/forms/controlelement.cxx87
-rw-r--r--xmloff/source/forms/controlelement.hxx88
-rw-r--r--xmloff/source/forms/controlpropertyhdl.cxx343
-rw-r--r--xmloff/source/forms/controlpropertymap.cxx119
-rw-r--r--xmloff/source/forms/controlpropertymap.hxx51
-rw-r--r--xmloff/source/forms/elementexport.cxx2185
-rw-r--r--xmloff/source/forms/elementexport.hxx311
-rw-r--r--xmloff/source/forms/elementimport.cxx2073
-rw-r--r--xmloff/source/forms/elementimport.hxx674
-rw-r--r--xmloff/source/forms/eventexport.cxx126
-rw-r--r--xmloff/source/forms/eventexport.hxx71
-rw-r--r--xmloff/source/forms/eventimport.cxx135
-rw-r--r--xmloff/source/forms/eventimport.hxx77
-rw-r--r--xmloff/source/forms/formattributes.cxx405
-rw-r--r--xmloff/source/forms/formattributes.hxx414
-rw-r--r--xmloff/source/forms/formcellbinding.cxx433
-rw-r--r--xmloff/source/forms/formcellbinding.hxx260
-rw-r--r--xmloff/source/forms/formenums.cxx191
-rw-r--r--xmloff/source/forms/formenums.hxx54
-rw-r--r--xmloff/source/forms/formevents.cxx70
-rw-r--r--xmloff/source/forms/formevents.hxx30
-rw-r--r--xmloff/source/forms/formlayerexport.cxx121
-rw-r--r--xmloff/source/forms/formlayerimport.cxx90
-rw-r--r--xmloff/source/forms/gridcolumnproptranslator.cxx299
-rw-r--r--xmloff/source/forms/gridcolumnproptranslator.hxx66
-rw-r--r--xmloff/source/forms/handler/form_handler_factory.cxx65
-rw-r--r--xmloff/source/forms/handler/vcl_date_handler.cxx93
-rw-r--r--xmloff/source/forms/handler/vcl_date_handler.hxx40
-rw-r--r--xmloff/source/forms/handler/vcl_time_handler.cxx96
-rw-r--r--xmloff/source/forms/handler/vcl_time_handler.hxx40
-rw-r--r--xmloff/source/forms/layerexport.cxx727
-rw-r--r--xmloff/source/forms/layerexport.hxx299
-rw-r--r--xmloff/source/forms/layerimport.cxx553
-rw-r--r--xmloff/source/forms/layerimport.hxx175
-rw-r--r--xmloff/source/forms/logging.cxx41
-rw-r--r--xmloff/source/forms/logging.hxx59
-rw-r--r--xmloff/source/forms/officeforms.cxx177
-rw-r--r--xmloff/source/forms/officeforms.hxx92
-rw-r--r--xmloff/source/forms/property_description.hxx103
-rw-r--r--xmloff/source/forms/property_meta_data.cxx156
-rw-r--r--xmloff/source/forms/property_meta_data.hxx42
-rw-r--r--xmloff/source/forms/propertyexport.cxx683
-rw-r--r--xmloff/source/forms/propertyexport.hxx413
-rw-r--r--xmloff/source/forms/propertyimport.cxx524
-rw-r--r--xmloff/source/forms/propertyimport.hxx226
-rw-r--r--xmloff/source/forms/strings.hxx209
-rw-r--r--xmloff/source/forms/valueproperties.cxx180
-rw-r--r--xmloff/source/forms/valueproperties.hxx67
49 files changed, 13912 insertions, 0 deletions
diff --git a/xmloff/source/forms/callbacks.hxx b/xmloff/source/forms/callbacks.hxx
new file mode 100644
index 000000000..0134152b8
--- /dev/null
+++ b/xmloff/source/forms/callbacks.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 <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/script/ScriptEventDescriptor.hpp>
+#include <rtl/ref.hxx>
+
+class SvXMLExport;
+class SvXMLExportPropertyMapper;
+
+namespace xmloff
+{
+
+ //= IFormsExportContext
+ class IFormsExportContext
+ {
+ public:
+ virtual SvXMLExport& getGlobalContext() = 0;
+ virtual ::rtl::Reference< SvXMLExportPropertyMapper > getStylePropertyMapper() = 0;
+
+ /** steps through a collection and exports all children of this collection
+ */
+ virtual void exportCollectionElements(
+ const css::uno::Reference< css::container::XIndexAccess >& _rxCollection) = 0;
+
+ virtual OUString getObjectStyleName(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) = 0;
+
+ protected:
+ ~IFormsExportContext() {}
+ };
+
+ //= IEventAttacherManager
+ class IEventAttacherManager
+ {
+ public:
+ virtual void registerEvents(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxElement,
+ const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents
+ ) = 0;
+
+ protected:
+ ~IEventAttacherManager() {}
+ };
+
+ //= IEventAttacher
+ class IEventAttacher
+ {
+ public:
+ virtual void registerEvents(
+ const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents
+ ) = 0;
+
+ protected:
+ ~IEventAttacher() {}
+ };
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/controlelement.cxx b/xmloff/source/forms/controlelement.cxx
new file mode 100644
index 000000000..af752ae4b
--- /dev/null
+++ b/xmloff/source/forms/controlelement.cxx
@@ -0,0 +1,87 @@
+/* -*- 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 "controlelement.hxx"
+#include <xmloff/xmltoken.hxx>
+
+using namespace ::xmloff::token;
+
+namespace xmloff
+{
+
+ //= OControlElement
+ const char* OControlElement::getElementName(ElementType _eType)
+ {
+ switch (_eType)
+ {
+ case TEXT: return "text";
+ case TEXT_AREA: return "textarea";
+ case PASSWORD: return "password";
+ case FILE: return "file";
+ case FORMATTED_TEXT: return "formatted-text";
+ case FIXED_TEXT: return "fixed-text";
+ case COMBOBOX: return "combobox";
+ case LISTBOX: return "listbox";
+ case BUTTON: return "button";
+ case IMAGE: return "image";
+ case CHECKBOX: return "checkbox";
+ case RADIO: return "radio";
+ case FRAME: return "frame";
+ case IMAGE_FRAME: return "image-frame";
+ case HIDDEN: return "hidden";
+ case GRID: return "grid";
+ case VALUERANGE: return "value-range";
+ case TIME: return "time";
+ case DATE: return "date";
+
+ default: return "generic-control";
+ }
+ }
+
+ sal_Int32 OControlElement::getElementToken(ElementType _eType)
+ {
+ switch (_eType)
+ {
+ case TEXT: return XML_TEXT;
+ case TEXT_AREA: return XML_TEXTAREA;
+ case PASSWORD: return XML_PASSWORD;
+ case FILE: return XML_FILE;
+ case FORMATTED_TEXT: return XML_FORMATTED_TEXT;
+ case FIXED_TEXT: return XML_FIXED_TEXT;
+ case COMBOBOX: return XML_COMBOBOX;
+ case LISTBOX: return XML_LISTBOX;
+ case BUTTON: return XML_BUTTON;
+ case IMAGE: return XML_IMAGE;
+ case CHECKBOX: return XML_CHECKBOX;
+ case RADIO: return XML_RADIO;
+ case FRAME: return XML_FRAME;
+ case IMAGE_FRAME: return XML_IMAGE_FRAME;
+ case HIDDEN: return XML_HIDDEN;
+ case GRID: return XML_GRID;
+ case VALUERANGE: return XML_VALUE_RANGE;
+ case TIME: return XML_TIME;
+ case DATE: return XML_DATE;
+
+ default: return XML_GENERIC_CONTROL;
+ }
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/controlelement.hxx b/xmloff/source/forms/controlelement.hxx
new file mode 100644
index 000000000..df7f12a43
--- /dev/null
+++ b/xmloff/source/forms/controlelement.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 <sal/types.h>
+
+namespace xmloff
+{
+
+ //= OControlElement
+ /** helper for translating between control types and XML tags
+ */
+ class OControlElement
+ {
+ public:
+ enum ElementType
+ {
+ TEXT = 0,
+ TEXT_AREA,
+ PASSWORD,
+ FILE,
+ FORMATTED_TEXT,
+ FIXED_TEXT,
+ COMBOBOX,
+ LISTBOX,
+ BUTTON,
+ IMAGE,
+ CHECKBOX,
+ RADIO,
+ FRAME,
+ IMAGE_FRAME,
+ HIDDEN,
+ GRID,
+ VALUERANGE,
+ GENERIC_CONTROL,
+ TIME,
+ DATE,
+
+ UNKNOWN // must be the last element
+ };
+
+ protected:
+ /** ctor.
+ <p>This default constructor is protected, 'cause this class is not intended to be instantiated
+ directly. Instead, the derived classes should be used.</p>
+ */
+ OControlElement() { }
+
+ public:
+ /** retrieves the tag name to be used to describe a control of the given type
+
+ <p>The returned string is the pure element name, without any namespace.</p>
+
+ @param _eType
+ the element type
+ */
+ static const char* getElementName(ElementType _eType);
+
+ /** retrieves the tag name to be used to describe a control of the given type
+
+ <p>The returned string is the pure token, without any namespace.</p>
+
+ @param _eType
+ the element type
+ */
+ static sal_Int32 getElementToken(ElementType _eType);
+ };
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/controlpropertyhdl.cxx b/xmloff/source/forms/controlpropertyhdl.cxx
new file mode 100644
index 000000000..cb3badee2
--- /dev/null
+++ b/xmloff/source/forms/controlpropertyhdl.cxx
@@ -0,0 +1,343 @@
+/* -*- 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 <xmloff/controlpropertyhdl.hxx>
+
+#include <com/sun/star/util/MeasureUnit.hpp>
+#include <com/sun/star/awt/TextAlign.hpp>
+#include <com/sun/star/awt/FontEmphasisMark.hpp>
+
+#include <sax/tools/converter.hxx>
+
+#include <xmloff/xmltypes.hxx>
+#include <xmloff/NamedBoolPropertyHdl.hxx>
+#include "formenums.hxx"
+#include <xmloff/xmluconv.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <xmloff/XMLConstantsPropertyHandler.hxx>
+
+namespace xmloff
+{
+
+ 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 ::xmloff::token;
+
+ //= OControlPropertyHandlerFactory
+ OControlPropertyHandlerFactory::OControlPropertyHandlerFactory()
+ {
+ }
+
+ const XMLPropertyHandler* OControlPropertyHandlerFactory::GetPropertyHandler(sal_Int32 _nType) const
+ {
+ const XMLPropertyHandler* pHandler = nullptr;
+
+ switch (_nType)
+ {
+ case XML_TYPE_TEXT_ALIGN:
+ if (!m_pTextAlignHandler)
+ m_pTextAlignHandler = std::make_unique<XMLConstantsPropertyHandler>(aTextAlignMap, XML_TOKEN_INVALID );
+ pHandler = m_pTextAlignHandler.get();
+ break;
+
+ case XML_TYPE_CONTROL_BORDER:
+ if (!m_pControlBorderStyleHandler)
+ m_pControlBorderStyleHandler = std::make_unique<OControlBorderHandler>( OControlBorderHandler::STYLE );
+ pHandler = m_pControlBorderStyleHandler.get();
+ break;
+
+ case XML_TYPE_CONTROL_BORDER_COLOR:
+ if ( !m_pControlBorderColorHandler )
+ m_pControlBorderColorHandler = std::make_unique<OControlBorderHandler>( OControlBorderHandler::COLOR );
+ pHandler = m_pControlBorderColorHandler.get();
+ break;
+
+ case XML_TYPE_ROTATION_ANGLE:
+ if (!m_pRotationAngleHandler)
+ m_pRotationAngleHandler = std::make_unique<ORotationAngleHandler>();
+ pHandler = m_pRotationAngleHandler.get();
+ break;
+
+ case XML_TYPE_FONT_WIDTH:
+ if (!m_pFontWidthHandler)
+ m_pFontWidthHandler = std::make_unique<OFontWidthHandler>();
+ pHandler = m_pFontWidthHandler.get();
+ break;
+
+ case XML_TYPE_CONTROL_TEXT_EMPHASIZE:
+ if (!m_pFontEmphasisHandler)
+ m_pFontEmphasisHandler = std::make_unique<XMLConstantsPropertyHandler>( aFontEmphasisMap, XML_NONE );
+ pHandler = m_pFontEmphasisHandler.get();
+ break;
+
+ case XML_TYPE_TEXT_FONT_RELIEF:
+ if (!m_pFontReliefHandler)
+ m_pFontReliefHandler = std::make_unique<XMLConstantsPropertyHandler>( aFontReliefMap, XML_NONE );
+ pHandler = m_pFontReliefHandler.get();
+ break;
+ case XML_TYPE_TEXT_LINE_MODE:
+ if (!m_pTextLineModeHandler)
+ {
+ m_pTextLineModeHandler = std::make_unique<XMLNamedBoolPropertyHdl>(
+ ::xmloff::token::XML_SKIP_WHITE_SPACE,
+ ::xmloff::token::XML_CONTINUOUS);
+ }
+ pHandler = m_pTextLineModeHandler.get();
+ break;
+ }
+
+ if (!pHandler)
+ pHandler = XMLPropertyHandlerFactory::GetPropertyHandler(_nType);
+ return pHandler;
+ }
+
+ //= OControlTextEmphasisHandler
+ OControlTextEmphasisHandler::OControlTextEmphasisHandler()
+ {
+ }
+
+ bool OControlTextEmphasisHandler::exportXML( OUString& _rStrExpValue, const Any& _rValue, const SvXMLUnitConverter& ) const
+ {
+ bool bSuccess = false;
+ sal_Int16 nFontEmphasis = sal_Int16();
+ if (_rValue >>= nFontEmphasis)
+ {
+ // the type
+ sal_uInt16 nType = nFontEmphasis & ~(awt::FontEmphasisMark::ABOVE | awt::FontEmphasisMark::BELOW);
+ // the position of the mark
+ bool bBelow = 0 != (nFontEmphasis & awt::FontEmphasisMark::BELOW);
+
+ // convert
+ OUStringBuffer aReturn;
+ bSuccess = SvXMLUnitConverter::convertEnum(aReturn, nType, aFontEmphasisMap, XML_NONE);
+ if (bSuccess)
+ {
+ aReturn.append( ' ' );
+ aReturn.append( GetXMLToken(bBelow ? XML_BELOW : XML_ABOVE) );
+
+ _rStrExpValue = aReturn.makeStringAndClear();
+ }
+ }
+
+ return bSuccess;
+ }
+
+ bool OControlTextEmphasisHandler::importXML( const OUString& _rStrImpValue, Any& _rValue, const SvXMLUnitConverter& ) const
+ {
+ bool bSuccess = true;
+ sal_uInt16 nEmphasis = awt::FontEmphasisMark::NONE;
+
+ bool bBelow = false;
+ bool bHasPos = false, bHasType = false;
+
+ std::u16string_view sToken;
+ SvXMLTokenEnumerator aTokenEnum(_rStrImpValue);
+ while (aTokenEnum.getNextToken(sToken))
+ {
+ if (!bHasPos)
+ {
+ if (IsXMLToken(sToken, XML_ABOVE))
+ {
+ bBelow = false;
+ bHasPos = true;
+ }
+ else if (IsXMLToken(sToken, XML_BELOW))
+ {
+ bBelow = true;
+ bHasPos = true;
+ }
+ }
+ if (!bHasType)
+ {
+ if (SvXMLUnitConverter::convertEnum(nEmphasis, sToken, aFontEmphasisMap))
+ {
+ bHasType = true;
+ }
+ else
+ {
+ bSuccess = false;
+ break;
+ }
+ }
+ }
+
+ if (bSuccess)
+ {
+ nEmphasis |= bBelow ? awt::FontEmphasisMark::BELOW : awt::FontEmphasisMark::ABOVE;
+ _rValue <<= nEmphasis;
+ }
+
+ return bSuccess;
+ }
+
+ //= OControlBorderHandlerBase
+ OControlBorderHandler::OControlBorderHandler( const OControlBorderHandler::BorderFacet _eFacet )
+ :m_eFacet( _eFacet )
+ {
+ }
+
+ bool OControlBorderHandler::importXML( const OUString& _rStrImpValue, Any& _rValue, const SvXMLUnitConverter& ) const
+ {
+ std::u16string_view sToken;
+ SvXMLTokenEnumerator aTokens(_rStrImpValue);
+
+ sal_uInt16 nStyle = 1;
+
+ while ( aTokens.getNextToken(sToken) // have a new token
+ && (!sToken.empty()) // really have a new token
+ )
+ {
+ // try interpreting the token as border style
+ if ( m_eFacet == STYLE )
+ {
+ // is it a valid enum value?
+ if ( SvXMLUnitConverter::convertEnum( nStyle, sToken, aBorderTypeMap ) )
+ {
+ _rValue <<= nStyle;
+ return true;
+ }
+ }
+
+ // try interpreting it as color value
+ if ( m_eFacet == COLOR )
+ {
+ sal_Int32 nColor(0);
+ if (::sax::Converter::convertColor( nColor, sToken ))
+ {
+ _rValue <<= nColor;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ bool OControlBorderHandler::exportXML( OUString& _rStrExpValue, const Any& _rValue, const SvXMLUnitConverter& ) const
+ {
+ bool bSuccess = false;
+
+ OUStringBuffer aOut;
+ switch ( m_eFacet )
+ {
+ case STYLE:
+ {
+ sal_uInt16 nBorder = 0;
+ bSuccess = (_rValue >>= nBorder)
+ && SvXMLUnitConverter::convertEnum( aOut, nBorder, aBorderTypeMap );
+ }
+ break;
+ case COLOR:
+ {
+ sal_Int32 nBorderColor = 0;
+ if ( _rValue >>= nBorderColor )
+ {
+ ::sax::Converter::convertColor(aOut, nBorderColor);
+ bSuccess = true;
+ }
+ }
+ break;
+ } // switch ( m_eFacet )
+
+ if ( !bSuccess )
+ return false;
+
+ if ( !_rStrExpValue.isEmpty() )
+ _rStrExpValue += " ";
+ _rStrExpValue += aOut;
+
+ return true;
+ }
+
+ //= OFontWidthHandler
+ OFontWidthHandler::OFontWidthHandler()
+ {
+ }
+
+ bool OFontWidthHandler::importXML( const OUString& _rStrImpValue, Any& _rValue, const SvXMLUnitConverter& ) const
+ {
+ sal_Int32 nWidth = 0;
+ bool const bSuccess = ::sax::Converter::convertMeasure(
+ nWidth, _rStrImpValue, util::MeasureUnit::POINT);
+ if (bSuccess)
+ _rValue <<= static_cast<sal_Int16>(nWidth);
+
+ return bSuccess;
+ }
+
+ bool OFontWidthHandler::exportXML( OUString& _rStrExpValue, const Any& _rValue, const SvXMLUnitConverter& ) const
+ {
+ sal_Int16 nWidth = 0;
+ OUStringBuffer aResult;
+ if (_rValue >>= nWidth)
+ {
+ ::sax::Converter::convertMeasure(aResult, nWidth,
+ util::MeasureUnit::POINT, util::MeasureUnit::POINT);
+ }
+ _rStrExpValue = aResult.makeStringAndClear();
+
+ return !_rStrExpValue.isEmpty();
+ }
+
+ //= ORotationAngleHandler
+ ORotationAngleHandler::ORotationAngleHandler()
+ {
+ }
+
+ bool ORotationAngleHandler::importXML( const OUString& _rStrImpValue, Any& _rValue, const SvXMLUnitConverter& ) const
+ {
+ double fValue;
+ bool const bSucces =
+ ::sax::Converter::convertDouble(fValue, _rStrImpValue);
+ if (bSucces)
+ {
+ fValue *= 10;
+ _rValue <<= static_cast<float>(fValue);
+ }
+
+ return bSucces;
+ }
+
+ bool ORotationAngleHandler::exportXML( OUString& _rStrExpValue, const Any& _rValue, const SvXMLUnitConverter& ) const
+ {
+ float fAngle = 0;
+ bool bSuccess = (_rValue >>= fAngle);
+
+ if (bSuccess)
+ {
+ OUStringBuffer sValue;
+ ::sax::Converter::convertDouble(sValue, static_cast<double>(fAngle) / 10);
+ _rStrExpValue = sValue.makeStringAndClear();
+ }
+
+ return bSuccess;
+ }
+
+ //= ImageScaleModeHandler
+ ImageScaleModeHandler::ImageScaleModeHandler()
+ :XMLConstantsPropertyHandler( aScaleModeMap, XML_STRETCH )
+ {
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/controlpropertymap.cxx b/xmloff/source/forms/controlpropertymap.cxx
new file mode 100644
index 000000000..d0716bd8d
--- /dev/null
+++ b/xmloff/source/forms/controlpropertymap.cxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rtl/ref.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/maptype.hxx>
+#include <xmloff/xmltypes.hxx>
+#include <algorithm>
+#include "strings.hxx"
+#include <xmloff/contextid.hxx>
+#include "controlpropertymap.hxx"
+
+#include <string.h>
+
+using namespace ::xmloff::token;
+
+namespace xmloff
+{
+
+#define MAP_ASCII( name, prefix, token, type, context ) { name, prefix, token, type|XML_TYPE_PROP_TEXT, context, SvtSaveOptions::ODFSVER_010, false }
+#define MAP_CONST( name, prefix, token, type, context ) { name, prefix, token, type|XML_TYPE_PROP_TEXT, context, SvtSaveOptions::ODFSVER_010, false }
+#define MAP_CONST_P( name, prefix, token, type, context ){ name, prefix, token, type|XML_TYPE_PROP_PARAGRAPH, context, SvtSaveOptions::ODFSVER_010, false }
+#define MAP_END() { nullptr, 0, XML_TOKEN_INVALID, 0, 0, SvtSaveOptions::ODFSVER_010, false }
+
+ XMLPropertyMapEntry const aControlStyleProperties[] =
+ {
+ MAP_CONST_P( PROPERTY_ALIGN, XML_NAMESPACE_FO, XML_TEXT_ALIGN, XML_TYPE_TEXT_ALIGN, 0 ),
+ MAP_CONST( PROPERTY_BACKGROUNDCOLOR, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLOR, 0 ),
+ MAP_CONST( PROPERTY_BORDER, XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_CONTROL_BORDER|MID_FLAG_MULTI_PROPERTY|MID_FLAG_MERGE_ATTRIBUTE, 0 ),
+ MAP_ASCII( "BorderColor", XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_CONTROL_BORDER_COLOR|MID_FLAG_MULTI_PROPERTY|MID_FLAG_MERGE_ATTRIBUTE, 0 ),
+ MAP_ASCII( "FontCharWidth", XML_NAMESPACE_STYLE, XML_FONT_CHAR_WIDTH, XML_TYPE_NUMBER16, 0 ),
+ MAP_ASCII( "FontCharset", XML_NAMESPACE_STYLE, XML_FONT_CHARSET, XML_TYPE_TEXT_FONTENCODING, 0 ),
+ MAP_ASCII( "FontEmphasisMark", XML_NAMESPACE_STYLE, XML_TEXT_EMPHASIZE, XML_TYPE_CONTROL_TEXT_EMPHASIZE, 0 ),
+ MAP_ASCII( "FontFamily", XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC, XML_TYPE_TEXT_FONTFAMILY, 0 ),
+ MAP_ASCII( "FontHeight", XML_NAMESPACE_FO, XML_FONT_SIZE, XML_TYPE_CHAR_HEIGHT, 0 ),
+ MAP_ASCII( "FontKerning", XML_NAMESPACE_STYLE, XML_LETTER_KERNING, XML_TYPE_BOOL, 0 ),
+ MAP_ASCII( "FontName", XML_NAMESPACE_STYLE, XML_FONT_NAME, XML_TYPE_STRING, 0 ),
+ MAP_ASCII( "FontOrientation", XML_NAMESPACE_STYLE, XML_ROTATION_ANGLE, XML_TYPE_ROTATION_ANGLE, 0 ),
+ MAP_ASCII( "FontPitch", XML_NAMESPACE_STYLE, XML_FONT_PITCH, XML_TYPE_TEXT_FONTPITCH, 0 ),
+ MAP_ASCII( "FontRelief", XML_NAMESPACE_STYLE, XML_FONT_RELIEF, XML_TYPE_TEXT_FONT_RELIEF|MID_FLAG_MULTI_PROPERTY, 0 ),
+ MAP_ASCII( "FontSlant", XML_NAMESPACE_FO, XML_FONT_STYLE, XML_TYPE_TEXT_POSTURE, 0 ),
+
+ MAP_ASCII( "FontStrikeout", XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_STYLE, XML_TYPE_TEXT_CROSSEDOUT_STYLE|MID_FLAG_MERGE_PROPERTY, 0),
+ MAP_ASCII( "FontStrikeout", XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TYPE, XML_TYPE_TEXT_CROSSEDOUT_TYPE|MID_FLAG_MERGE_PROPERTY, 0),
+ MAP_ASCII( "FontStrikeout", XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_WIDTH, XML_TYPE_TEXT_CROSSEDOUT_WIDTH|MID_FLAG_MERGE_PROPERTY, 0),
+ MAP_ASCII( "FontStrikeout", XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TEXT, XML_TYPE_TEXT_CROSSEDOUT_TEXT|MID_FLAG_MERGE_PROPERTY, 0),
+
+ MAP_ASCII( "FontStyleName", XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME, XML_TYPE_STRING, 0 ),
+ MAP_ASCII( "FontUnderline", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_STYLE, XML_TYPE_TEXT_UNDERLINE_STYLE|MID_FLAG_MERGE_PROPERTY, 0 ),
+ MAP_ASCII( "FontUnderline", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_TYPE, XML_TYPE_TEXT_UNDERLINE_TYPE|MID_FLAG_MERGE_PROPERTY, 0 ),
+ MAP_ASCII( "FontUnderline", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_WIDTH, XML_TYPE_TEXT_UNDERLINE_WIDTH|MID_FLAG_MERGE_PROPERTY, 0 ),
+ MAP_ASCII( "FontWeight", XML_NAMESPACE_FO, XML_FONT_WEIGHT, XML_TYPE_TEXT_WEIGHT, 0 ),
+ MAP_ASCII( "FontWidth", XML_NAMESPACE_STYLE, XML_FONT_WIDTH, XML_TYPE_FONT_WIDTH, 0 ),
+ MAP_ASCII( "FontWordLineMode", XML_NAMESPACE_FO, XML_SCORE_SPACES, XML_TYPE_NBOOL, 0 ),
+
+ MAP_CONST( PROPERTY_FORMATKEY, XML_NAMESPACE_STYLE, XML_DATA_STYLE_NAME, XML_TYPE_STRING | MID_FLAG_NO_PROPERTY_EXPORT | MID_FLAG_SPECIAL_ITEM, CTF_FORMS_DATA_STYLE ),
+
+ MAP_ASCII( "SymbolColor", XML_NAMESPACE_STYLE, XML_COLOR, XML_TYPE_COLOR, 0 ),
+ MAP_ASCII( "TextColor", XML_NAMESPACE_FO, XML_COLOR, XML_TYPE_COLOR, 0 ),
+ MAP_ASCII( "TextLineColor", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_COLOR|MID_FLAG_MULTI_PROPERTY, 0 ),
+ MAP_END()
+ };
+
+ const XMLPropertyMapEntry* getControlStylePropertyMap( )
+ {
+ return aControlStyleProperties;
+ }
+
+ void initializePropertyMaps()
+ {
+ static bool bSorted = false;
+ if (!bSorted)
+ {
+ XMLPropertyMapEntry const * pEnd;
+ // determine the last element
+ for ( pEnd = aControlStyleProperties; pEnd->msApiName; ++pEnd)
+ ;
+ assert( ::std::is_sorted(aControlStyleProperties, pEnd,
+ [](const XMLPropertyMapEntry& _rLeft, const XMLPropertyMapEntry& _rRight)
+ { return strcmp(_rLeft.msApiName, _rRight.msApiName) < 0; }) );
+ bSorted = true;
+ }
+ }
+
+ //= OFormComponentStyleExportMapper
+ OFormComponentStyleExportMapper::OFormComponentStyleExportMapper( const rtl::Reference< XMLPropertySetMapper >& _rMapper )
+ :SvXMLExportPropertyMapper( _rMapper )
+ {
+ }
+
+ void OFormComponentStyleExportMapper::handleSpecialItem( SvXMLAttributeList& _rAttrList, const XMLPropertyState& _rProperty, const SvXMLUnitConverter& _rUnitConverter,
+ const SvXMLNamespaceMap& _rNamespaceMap, const ::std::vector< XMLPropertyState >* _pProperties,
+ sal_uInt32 _nIdx ) const
+ {
+ // ignore the number style of grid columns - this is formatted elsewhere
+ if ( CTF_FORMS_DATA_STYLE != getPropertySetMapper()->GetEntryContextId( _rProperty.mnIndex ) )
+ SvXMLExportPropertyMapper::handleSpecialItem( _rAttrList, _rProperty, _rUnitConverter, _rNamespaceMap, _pProperties, _nIdx );
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/controlpropertymap.hxx b/xmloff/source/forms/controlpropertymap.hxx
new file mode 100644
index 000000000..ff575c137
--- /dev/null
+++ b/xmloff/source/forms/controlpropertymap.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 <xmloff/xmlprmap.hxx>
+#include <xmloff/xmlexppr.hxx>
+
+struct XMLPropertyMapEntry;
+namespace xmloff
+{
+
+ const XMLPropertyMapEntry* getControlStylePropertyMap( );
+
+ void initializePropertyMaps();
+
+ //= OFormComponentStyleExportMapper
+ class OFormComponentStyleExportMapper : public SvXMLExportPropertyMapper
+ {
+ public:
+ explicit OFormComponentStyleExportMapper( const rtl::Reference< XMLPropertySetMapper >& _rMapper );
+
+ void handleSpecialItem(
+ SvXMLAttributeList& _rAttrList,
+ const XMLPropertyState& _rProperty,
+ const SvXMLUnitConverter& _rUnitConverter,
+ const SvXMLNamespaceMap& _rNamespaceMap,
+ const ::std::vector< XMLPropertyState >* _pProperties,
+ sal_uInt32 _nIdx
+ ) const override;
+ };
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/elementexport.cxx b/xmloff/source/forms/elementexport.cxx
new file mode 100644
index 000000000..72cb6e0ef
--- /dev/null
+++ b/xmloff/source/forms/elementexport.cxx
@@ -0,0 +1,2185 @@
+/* -*- 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 "elementexport.hxx"
+
+#include "strings.hxx"
+#include <xmloff/xmlnamespace.hxx>
+#include "eventexport.hxx"
+#include "formenums.hxx"
+#include "formcellbinding.hxx"
+#include <xmloff/xformsexport.hxx>
+#include "property_meta_data.hxx"
+
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/io/XPersistObject.hpp>
+#include <com/sun/star/util/Duration.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/form/FormSubmitEncoding.hpp>
+#include <com/sun/star/form/FormSubmitMethod.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/form/NavigationBarMode.hpp>
+#include <com/sun/star/form/TabulatorCycle.hpp>
+#include <com/sun/star/form/FormButtonType.hpp>
+#include <com/sun/star/awt/ScrollBarOrientation.hpp>
+#include <com/sun/star/awt/VisualEffect.hpp>
+#include <com/sun/star/form/ListSourceType.hpp>
+#include <com/sun/star/awt/ImagePosition.hpp>
+
+#include <sax/tools/converter.hxx>
+#include <tools/gen.hxx>
+#include <xmloff/txtprmap.hxx>
+#include <com/sun/star/form/binding/XBindableValue.hpp>
+#include <com/sun/star/form/binding/XListEntrySink.hpp>
+#include <tools/urlobj.hxx>
+#include <xmloff/xmlexp.hxx>
+#include <xmloff/namespacemap.hxx>
+#include <xmloff/XMLEventExport.hxx>
+#include <xmloff/xmluconv.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/maptype.hxx>
+#include <tools/time.hxx>
+#include <tools/diagnose_ex.h>
+#include <comphelper/extract.hxx>
+#include <sal/macros.h>
+#include <sal/log.hxx>
+
+#include <algorithm>
+#include <string_view>
+
+namespace xmloff
+{
+
+ #if OSL_DEBUG_LEVEL > 0
+ #define RESET_BIT( bitfield, bit ) \
+ bitfield = bitfield & ~bit
+ #else
+ #define RESET_BIT( bitfield, bit )
+ #endif
+
+ using namespace ::xmloff::token;
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::io;
+ using namespace ::com::sun::star::table;
+ using namespace ::com::sun::star::text;
+ using namespace ::com::sun::star::form::binding;
+
+ //= OElementExport
+ OElementExport::OElementExport(IFormsExportContext& _rContext, const Reference< XPropertySet >& _rxProps,
+ const Sequence< ScriptEventDescriptor >& _rEvents)
+ :OPropertyExport(_rContext, _rxProps)
+ ,m_aEvents(_rEvents)
+ {
+ }
+
+ OElementExport::~OElementExport()
+ {
+ }
+
+ void OElementExport::doExport()
+ {
+ // collect some general information about the element
+ examine();
+
+ // first add the attributes necessary for the element
+ m_rContext.getGlobalContext().ClearAttrList();
+
+ // add the attributes
+ exportAttributes();
+
+ // start the XML element
+ implStartElement(getXMLElementName());
+
+ // the sub elements (mostly control type dependent)
+ exportSubTags();
+
+ implEndElement();
+ }
+
+ void OElementExport::examine()
+ {
+ // nothing to do here
+ }
+
+ void OElementExport::exportAttributes()
+ {
+ // nothing to do here
+ }
+
+ void OElementExport::exportSubTags()
+ {
+ // the properties which where not exported 'til now
+ exportRemainingProperties();
+
+ // the script:events sub tags
+ exportEvents();
+ }
+
+ void OElementExport::implStartElement(const char* _pName)
+ {
+ m_pXMLElement = std::make_unique<SvXMLElementExport>(m_rContext.getGlobalContext(), XML_NAMESPACE_FORM, _pName, true, true);
+ }
+
+ void OElementExport::implEndElement()
+ {
+ m_pXMLElement.reset();
+ }
+
+ void OElementExport::exportServiceNameAttribute()
+ {
+ Reference< XPersistObject > xPersistence(m_xProps, UNO_QUERY);
+ if (!xPersistence.is())
+ {
+ OSL_FAIL("OElementExport::exportServiceNameAttribute: no XPersistObject!");
+ return;
+ }
+
+ OUString sServiceName = xPersistence->getServiceName();
+ // we don't want to write the old service name directly: it's a name used for compatibility reasons, but
+ // as we start some kind of new file format here (with this xml export), we don't care about
+ // compatibility ...
+ // So we translate the old persistence service name into new ones, if possible
+
+ OUString sToWriteServiceName = sServiceName;
+#define CHECK_N_TRANSLATE( name ) \
+ else if (sServiceName == SERVICE_PERSISTENT_COMPONENT_##name) \
+ sToWriteServiceName = SERVICE_##name
+
+ if (sServiceName == SERVICE_PERSISTENT_COMPONENT_EDIT)
+ {
+ // special handling for the edit field: we have two controls using this as persistence service name
+ sToWriteServiceName = SERVICE_EDIT;
+ Reference< XServiceInfo > xSI(m_xProps, UNO_QUERY);
+ if (xSI.is() && xSI->supportsService(SERVICE_FORMATTEDFIELD))
+ sToWriteServiceName = SERVICE_FORMATTEDFIELD;
+ }
+ CHECK_N_TRANSLATE( FORM );
+ CHECK_N_TRANSLATE( LISTBOX );
+ CHECK_N_TRANSLATE( COMBOBOX );
+ CHECK_N_TRANSLATE( RADIOBUTTON );
+ CHECK_N_TRANSLATE( GROUPBOX );
+ CHECK_N_TRANSLATE( FIXEDTEXT );
+ CHECK_N_TRANSLATE( COMMANDBUTTON );
+ CHECK_N_TRANSLATE( CHECKBOX );
+ CHECK_N_TRANSLATE( GRID );
+ CHECK_N_TRANSLATE( IMAGEBUTTON );
+ CHECK_N_TRANSLATE( FILECONTROL );
+ CHECK_N_TRANSLATE( TIMEFIELD );
+ CHECK_N_TRANSLATE( DATEFIELD );
+ CHECK_N_TRANSLATE( NUMERICFIELD );
+ CHECK_N_TRANSLATE( CURRENCYFIELD );
+ CHECK_N_TRANSLATE( PATTERNFIELD );
+ CHECK_N_TRANSLATE( HIDDENCONTROL );
+ CHECK_N_TRANSLATE( IMAGECONTROL );
+ CHECK_N_TRANSLATE( FORMATTEDFIELD );
+#if OSL_DEBUG_LEVEL > 0
+ Reference< XServiceInfo > xSI(m_xProps, UNO_QUERY);
+ OSL_ENSURE(xSI.is() && xSI->supportsService(sToWriteServiceName),
+ "OElementExport::exportServiceNameAttribute: wrong service name translation!");
+
+#endif
+ sToWriteServiceName =
+ m_rContext.getGlobalContext().GetNamespaceMap().GetQNameByKey(
+ XML_NAMESPACE_OOO, sToWriteServiceName );
+
+ // now write this
+ AddAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::ServiceName),
+ OAttributeMetaData::getCommonControlAttributeName(CCAFlags::ServiceName),
+ sToWriteServiceName);
+ }
+
+ void OElementExport::exportEvents()
+ {
+ if (!m_aEvents.hasElements())
+ // nothing to do
+ return;
+
+ Reference< XNameReplace > xWrapper = new OEventDescriptorMapper(m_aEvents);
+ m_rContext.getGlobalContext().GetEventExport().Export(xWrapper);
+ }
+
+ //= OControlExport
+ OControlExport::OControlExport(IFormsExportContext& _rContext, const Reference< XPropertySet >& _rxControl,
+ const OUString& _rControlId, const OUString& _rReferringControls,
+ const Sequence< ScriptEventDescriptor >& _rEvents)
+ :OElementExport(_rContext, _rxControl, _rEvents)
+ ,m_sControlId(_rControlId)
+ ,m_sReferringControls(_rReferringControls)
+ ,m_nClassId(FormComponentType::CONTROL)
+ ,m_eType( UNKNOWN )
+ ,m_nIncludeCommon(CCAFlags::NONE)
+ ,m_nIncludeDatabase(DAFlags::NONE)
+ ,m_nIncludeSpecial(SCAFlags::NONE)
+ ,m_nIncludeEvents(EAFlags::NONE)
+ ,m_nIncludeBindings(BAFlags::NONE)
+ {
+ OSL_ENSURE(m_xProps.is(), "OControlExport::OControlExport: invalid arguments!");
+ }
+
+ void OControlExport::exportOuterAttributes()
+ {
+ // the control id
+ if (CCAFlags::Name & m_nIncludeCommon)
+ {
+ exportStringPropertyAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::Name),
+ OAttributeMetaData::getCommonControlAttributeName(CCAFlags::Name),
+ PROPERTY_NAME
+ );
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::Name;
+ #endif
+ }
+
+ // the service name
+ if (m_nIncludeCommon & CCAFlags::ServiceName)
+ {
+ exportServiceNameAttribute();
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::ServiceName;
+ #endif
+ }
+ }
+
+ void OControlExport::exportInnerAttributes()
+ {
+ // the control id
+ if (CCAFlags::ControlId & m_nIncludeCommon)
+ {
+ OSL_ENSURE(!m_sControlId.isEmpty(), "OControlExport::exportInnerAttributes: have no control id for the control!");
+ m_rContext.getGlobalContext().AddAttributeIdLegacy(
+ XML_NAMESPACE_FORM, m_sControlId);
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::ControlId;
+ #endif
+ }
+
+ // "new-style" properties ...
+ exportGenericHandlerAttributes();
+
+ // common control attributes
+ exportCommonControlAttributes();
+
+ // common database attributes
+ exportDatabaseAttributes();
+
+ // attributes related to external bindings
+ exportBindingAttributes();
+
+ // attributes special to the respective control type
+ exportSpecialAttributes();
+
+ // add the style references to the attributes
+ flagStyleProperties();
+ }
+
+ void OControlExport::exportAttributes()
+ {
+ exportOuterAttributes();
+ }
+
+ void OControlExport::exportSubTags()
+ {
+ // for the upcoming exportRemainingProperties:
+ // if a control has the LabelControl property, this is not stored with the control itself, but instead with
+ // the control which is referenced by this property. As the base class' exportRemainingProperties doesn't
+ // know anything about this, we need to prevent that it tries to export this property
+ exportedProperty(PROPERTY_CONTROLLABEL);
+
+ // if it's a control supporting XText, then we need to declare all text-related properties
+ // as "already exported". This prevents them from being exported as generic "form:property"-tags.
+ // *If* we would export them this way, they would be completely superfluous, and sometimes even
+ // disastrous, since they may, at import time, override paragraph properties which already have
+ // been set before
+ Reference< XText > xControlText( m_xProps, UNO_QUERY );
+ if ( xControlText.is() )
+ {
+ const XMLPropertyMapEntry* pCharAttributeProperties = XMLTextPropertySetMapper::getPropertyMapForType( TextPropMap::TEXT );
+ while ( pCharAttributeProperties->msApiName )
+ {
+ exportedProperty( OUString::createFromAscii( pCharAttributeProperties->msApiName ) );
+ ++pCharAttributeProperties;
+ }
+
+ const XMLPropertyMapEntry* pParaAttributeProperties = XMLTextPropertySetMapper::getPropertyMapForType( TextPropMap::SHAPE_PARA );
+ while ( pParaAttributeProperties->msApiName )
+ {
+ exportedProperty( OUString::createFromAscii( pParaAttributeProperties->msApiName ) );
+ ++pParaAttributeProperties;
+ }
+
+ // the RichText property is not exported. The presence of the text:p element
+ // will be used - upon reading - as indicator for the value of the RichText property
+ exportedProperty( PROPERTY_RICH_TEXT );
+
+ // strange thing: paragraphs support both a CharStrikeout and a CharCrossedOut property
+ // The former is a short/enum value, the latter a boolean. The former has a real meaning
+ // (the strikeout type), the latter hasn't. But, when the CharCrossedOut is exported and
+ // later on imported, it overwrites anything which has previously been imported for
+ // CharStrikeout.
+ // #i27729#
+ exportedProperty( "CharCrossedOut" );
+ }
+
+ if ( m_eType == LISTBOX )
+ {
+ // will be exported in exportListSourceAsElements:
+ if ( controlHasUserSuppliedListEntries() )
+ exportedProperty( PROPERTY_DEFAULT_SELECT_SEQ );
+
+ // will not be exported in a generic way. Either exportListSourceAsElements cares
+ // for them, or we don't need them
+ exportedProperty( PROPERTY_STRING_ITEM_LIST );
+ exportedProperty( PROPERTY_VALUE_SEQ );
+ exportedProperty( PROPERTY_SELECT_SEQ );
+ exportedProperty( PROPERTY_LISTSOURCE );
+ }
+ if ( m_eType == COMBOBOX )
+ exportedProperty( PROPERTY_STRING_ITEM_LIST );
+
+ // let the base class export the remaining properties and the events
+ OElementExport::exportSubTags();
+
+ // special sub tags for some controls
+ switch (m_eType)
+ {
+ case LISTBOX:
+ // don't export the list entries if the are not provided by the user, but obtained implicitly
+ // from other sources
+ // #i26944#
+ if ( controlHasUserSuppliedListEntries() )
+ exportListSourceAsElements();
+ break;
+ case GRID:
+ { // a grid control requires us to store all columns as sub elements
+ Reference< XIndexAccess > xColumnContainer(m_xProps, UNO_QUERY);
+ OSL_ENSURE(xColumnContainer.is(), "OControlExport::exportSubTags: a grid control which is no IndexAccess?!!");
+ if (xColumnContainer.is())
+ m_rContext.exportCollectionElements(xColumnContainer);
+ }
+ break;
+ case COMBOBOX:
+ { // a combox box description has sub elements: the items
+ DBG_CHECK_PROPERTY( PROPERTY_STRING_ITEM_LIST, Sequence< OUString > );
+
+ // don't export the list entries if the are not provided by the user, but obtained implicitly
+ // from other sources
+ // #i26944#
+ if ( controlHasUserSuppliedListEntries() )
+ {
+ // get the item list
+ Sequence< OUString > aListItems;
+ m_xProps->getPropertyValue(PROPERTY_STRING_ITEM_LIST) >>= aListItems;
+ // loop through it and write the sub elements
+ for (const auto& rListItem : std::as_const(aListItems))
+ {
+ m_rContext.getGlobalContext().ClearAttrList();
+ AddAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::Label),
+ OAttributeMetaData::getCommonControlAttributeName(CCAFlags::Label),
+ rListItem);
+ SvXMLElementExport aFormElement(m_rContext.getGlobalContext(), XML_NAMESPACE_FORM, "item", true, true);
+ }
+ }
+ }
+ break;
+
+ case TEXT_AREA:
+ {
+ // if we act as rich text control, we need to export some text:p elements
+ if ( xControlText.is() )
+ {
+ bool bActingAsRichText = false;
+ if ( m_xPropertyInfo->hasPropertyByName( PROPERTY_RICH_TEXT ) )
+ {
+ OSL_VERIFY(m_xProps->getPropertyValue( PROPERTY_RICH_TEXT ) >>= bActingAsRichText );
+ }
+
+ if ( bActingAsRichText )
+ m_rContext.getGlobalContext().GetTextParagraphExport()->exportText( xControlText );
+ }
+ }
+ break;
+ default:
+ // nothing do to
+ break;
+ }
+ }
+
+ void OControlExport::exportGenericHandlerAttributes()
+ {
+ const Sequence< Property > aProperties = m_xPropertyInfo->getProperties();
+ for ( auto const & prop : aProperties )
+ {
+ try
+ {
+ // see if this property can already be handled with an IPropertyHandler (which, on the long
+ // term, should be the case for most, if not all, properties)
+ const PropertyDescription* propDescription = metadata::getPropertyDescription( prop.Name );
+ if ( propDescription == nullptr )
+ continue;
+
+ // let the factory provide the concrete handler. Note that caching, if desired, is the task
+ // of the factory
+ PPropertyHandler handler = (*propDescription->factory)( propDescription->propertyId );
+ if ( !handler )
+ {
+ SAL_WARN( "xmloff.forms", "OControlExport::exportGenericHandlerAttributes: invalid property handler provided by the factory!" );
+ continue;
+ }
+
+ // that's a property which has a direct mapping to an attribute
+ if ( !shouldExportProperty( prop.Name ) )
+ // TODO: in the future, we surely need a more sophisticated approach to this, involving the property
+ // handler, or the property description
+ {
+ exportedProperty( prop.Name );
+ continue;
+ }
+
+ const Any propValue = m_xProps->getPropertyValue( prop.Name );
+ OUString attributeValue = handler->getAttributeValue( propValue );
+
+ AddAttribute(
+ propDescription->attribute.namespacePrefix,
+ token::GetXMLToken( propDescription->attribute.attributeToken ),
+ attributeValue
+ );
+
+ exportedProperty( prop.Name );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("xmloff.forms");
+ }
+ }
+ }
+
+ void OControlExport::exportCommonControlAttributes()
+ {
+ size_t i=0;
+
+ // I decided to handle all the properties here with some static arrays describing the property-attribute
+ // relations. This leads to somewhat ugly code :), but the only alternative I can think of right now
+ // would require maps and O(log n) searches, which seems somewhat expensive as this code is used
+ // very frequently.
+
+ // the extra indents for the respective blocks are to ensure that there is no copy'n'paste error, using
+ // map identifiers from the wrong block
+
+ // some string properties
+ {
+ // the attribute ids of all properties which are expected to be of type string
+ static const CCAFlags nStringPropertyAttributeIds[] =
+ {
+ CCAFlags::Label, CCAFlags::Title
+ };
+ // the names of all properties which are expected to be of type string
+ static const char * aStringPropertyNames[] =
+ {
+ PROPERTY_LABEL, PROPERTY_TITLE
+ };
+ OSL_ENSURE( SAL_N_ELEMENTS(aStringPropertyNames) ==
+ SAL_N_ELEMENTS(nStringPropertyAttributeIds),
+ "OControlExport::exportCommonControlAttributes: somebody tampered with the maps (1)!");
+
+ for (i=0; i<SAL_N_ELEMENTS(nStringPropertyAttributeIds); ++i)
+ if (nStringPropertyAttributeIds[i] & m_nIncludeCommon)
+ {
+ exportStringPropertyAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace(nStringPropertyAttributeIds[i]),
+ OAttributeMetaData::getCommonControlAttributeName(nStringPropertyAttributeIds[i]),
+ OUString::createFromAscii(aStringPropertyNames[i])
+ );
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeCommon = m_nIncludeCommon & ~nStringPropertyAttributeIds[i];
+ #endif
+ }
+ }
+
+ // some boolean properties
+ {
+ static const CCAFlags nBooleanPropertyAttributeIds[] =
+ { // attribute flags
+ CCAFlags::CurrentSelected, CCAFlags::Disabled, CCAFlags::Dropdown, CCAFlags::Printable, CCAFlags::ReadOnly, CCAFlags::Selected, CCAFlags::TabStop, CCAFlags::EnableVisible
+ };
+ static const char * pBooleanPropertyNames[] =
+ { // property names
+ PROPERTY_STATE, PROPERTY_ENABLED,
+ PROPERTY_DROPDOWN, PROPERTY_PRINTABLE,
+ PROPERTY_READONLY, PROPERTY_DEFAULT_STATE,
+ PROPERTY_TABSTOP, PROPERTY_ENABLEVISIBLE
+ };
+ static const BoolAttrFlags nBooleanPropertyAttrFlags[] =
+ { // attribute defaults
+ BoolAttrFlags::DefaultFalse, BoolAttrFlags::DefaultFalse | BoolAttrFlags::InverseSemantics, BoolAttrFlags::DefaultFalse, BoolAttrFlags::DefaultTrue, BoolAttrFlags::DefaultFalse, BoolAttrFlags::DefaultFalse, BoolAttrFlags::DefaultVoid, BoolAttrFlags::DefaultFalse
+ };
+ #if OSL_DEBUG_LEVEL > 0
+ static const sal_Int32 nIdCount = SAL_N_ELEMENTS(nBooleanPropertyAttributeIds);
+ static const sal_Int32 nNameCount = SAL_N_ELEMENTS(pBooleanPropertyNames);
+ static const sal_Int32 nFlagsCount = SAL_N_ELEMENTS(nBooleanPropertyAttrFlags);
+ OSL_ENSURE((nIdCount == nNameCount) && (nNameCount == nFlagsCount),
+ "OControlExport::exportCommonControlAttributes: somebody tampered with the maps (2)!");
+ #endif
+ for (i=0; i<SAL_N_ELEMENTS(nBooleanPropertyAttributeIds); ++i)
+ if (nBooleanPropertyAttributeIds[i] & m_nIncludeCommon)
+ {
+ exportBooleanPropertyAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace(nBooleanPropertyAttributeIds[i]),
+ OAttributeMetaData::getCommonControlAttributeName(nBooleanPropertyAttributeIds[i]),
+ OUString::createFromAscii(pBooleanPropertyNames[i]),
+ nBooleanPropertyAttrFlags[i]);
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeCommon = m_nIncludeCommon & ~nBooleanPropertyAttributeIds[i];
+ #endif
+ }
+ }
+
+ // some integer properties
+ {
+ // now the common handling
+ static const CCAFlags nIntegerPropertyAttributeIds[] =
+ { // attribute flags
+ CCAFlags::Size, CCAFlags::TabIndex
+ };
+ static const char * pIntegerPropertyNames[] =
+ { // property names
+ PROPERTY_LINECOUNT, PROPERTY_TABINDEX
+ };
+ static const sal_Int16 nIntegerPropertyAttrDefaults[] =
+ { // attribute defaults
+ 5, 0
+ };
+
+ if ( m_nIncludeCommon & CCAFlags::MaxLength )
+ exportedProperty(PROPERTY_MAXTEXTLENGTH);
+
+ #if OSL_DEBUG_LEVEL > 0
+ static const sal_Int32 nIdCount = SAL_N_ELEMENTS(nIntegerPropertyAttributeIds);
+ static const sal_Int32 nNameCount = SAL_N_ELEMENTS(pIntegerPropertyNames);
+ static const sal_Int32 nDefaultCount = SAL_N_ELEMENTS(nIntegerPropertyAttrDefaults);
+ OSL_ENSURE((nIdCount == nNameCount) && (nNameCount == nDefaultCount),
+ "OControlExport::exportCommonControlAttributes: somebody tampered with the maps (3)!");
+ #endif
+ for (i=0; i<SAL_N_ELEMENTS(nIntegerPropertyAttributeIds); ++i)
+ if (nIntegerPropertyAttributeIds[i] & m_nIncludeCommon)
+ {
+ exportInt16PropertyAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace(nIntegerPropertyAttributeIds[i]),
+ OAttributeMetaData::getCommonControlAttributeName(nIntegerPropertyAttributeIds[i]),
+ OUString::createFromAscii(pIntegerPropertyNames[i]),
+ nIntegerPropertyAttrDefaults[i]);
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeCommon = m_nIncludeCommon & ~nIntegerPropertyAttributeIds[i];
+ #endif
+ }
+
+ }
+
+ // some enum properties
+ {
+ if (m_nIncludeCommon & CCAFlags::ButtonType)
+ {
+ exportEnumPropertyAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::ButtonType),
+ OAttributeMetaData::getCommonControlAttributeName(CCAFlags::ButtonType),
+ PROPERTY_BUTTONTYPE,
+ aFormButtonTypeMap,
+ FormButtonType_PUSH);
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::ButtonType;
+ #endif
+ }
+ if ( m_nIncludeCommon & CCAFlags::Orientation )
+ {
+ exportEnumPropertyAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace( CCAFlags::Orientation ),
+ OAttributeMetaData::getCommonControlAttributeName( CCAFlags::Orientation ),
+ PROPERTY_ORIENTATION,
+ aOrientationMap,
+ ScrollBarOrientation::HORIZONTAL
+ );
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::Orientation;
+ #endif
+ }
+
+ if ( m_nIncludeCommon & CCAFlags::VisualEffect )
+ {
+ exportEnumPropertyAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace( CCAFlags::VisualEffect ),
+ OAttributeMetaData::getCommonControlAttributeName( CCAFlags::VisualEffect ),
+ PROPERTY_VISUAL_EFFECT,
+ aVisualEffectMap,
+ VisualEffect::LOOK3D
+ );
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::VisualEffect;
+ #endif
+ }
+ }
+
+ // some properties which require a special handling
+
+ // the target frame
+ if (m_nIncludeCommon & CCAFlags::TargetFrame)
+ {
+ exportTargetFrameAttribute();
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::TargetFrame;
+ #endif
+ }
+
+ // max text length
+ if ( m_nIncludeCommon & CCAFlags::MaxLength )
+ {
+ // normally, the respective property would be "MaxTextLen"
+ // However, if the model has a property "PersistenceMaxTextLength", then we prefer this
+
+ // determine the name of the property to export
+ OUString sTextLenPropertyName( PROPERTY_MAXTEXTLENGTH );
+ if ( m_xPropertyInfo->hasPropertyByName( PROPERTY_PERSISTENCE_MAXTEXTLENGTH ) )
+ sTextLenPropertyName = PROPERTY_PERSISTENCE_MAXTEXTLENGTH;
+
+ // export it
+ exportInt16PropertyAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace( CCAFlags::MaxLength ),
+ OAttributeMetaData::getCommonControlAttributeName( CCAFlags::MaxLength ),
+ sTextLenPropertyName,
+ 0
+ );
+
+ // in either way, both properties count as "exported"
+ exportedProperty( PROPERTY_MAXTEXTLENGTH );
+ exportedProperty( PROPERTY_PERSISTENCE_MAXTEXTLENGTH );
+
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::MaxLength;
+ #endif
+ }
+
+ if (m_nIncludeCommon & CCAFlags::TargetLocation)
+ {
+ exportTargetLocationAttribute(false);
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::TargetLocation;
+ #endif
+ }
+
+ // OJ #99721#
+ if (m_nIncludeCommon & CCAFlags::ImageData)
+ {
+ exportImageDataAttribute();
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::ImageData;
+ #endif
+ }
+
+ // the for attribute
+ // the target frame
+ if (m_nIncludeCommon & CCAFlags::For)
+ {
+ if (!m_sReferringControls.isEmpty())
+ { // there is at least one control referring to the one we're handling currently
+ AddAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::For),
+ OAttributeMetaData::getCommonControlAttributeName(CCAFlags::For),
+ m_sReferringControls);
+ }
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::For;
+ #endif
+ }
+
+ if ((CCAFlags::CurrentValue | CCAFlags::Value) & m_nIncludeCommon)
+ {
+ const char* pCurrentValuePropertyName = nullptr;
+ const char* pValuePropertyName = nullptr;
+
+ // get the property names
+ getValuePropertyNames(m_eType, m_nClassId, pCurrentValuePropertyName, pValuePropertyName);
+
+ // add the attributes if necessary and possible
+ if (pCurrentValuePropertyName && (CCAFlags::CurrentValue & m_nIncludeCommon))
+ {
+ static const OUString pCurrentValueAttributeName = OAttributeMetaData::getCommonControlAttributeName(CCAFlags::CurrentValue);
+ // don't export the current-value if this value originates from a data binding
+ // #i26944#
+ if ( controlHasActiveDataBinding() )
+ exportedProperty( OUString::createFromAscii( pCurrentValuePropertyName ) );
+ else
+ {
+ static const sal_uInt16 nCurrentValueAttributeNamespaceKey = OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::CurrentValue);
+ exportGenericPropertyAttribute(
+ nCurrentValueAttributeNamespaceKey,
+ pCurrentValueAttributeName,
+ pCurrentValuePropertyName
+ );
+ }
+ }
+
+ if (pValuePropertyName && (CCAFlags::Value & m_nIncludeCommon))
+ {
+ static const OUString pValueAttributeName = OAttributeMetaData::getCommonControlAttributeName(CCAFlags::Value);
+ static const sal_uInt16 nValueAttributeNamespaceKey = OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::Value);
+ exportGenericPropertyAttribute(
+ nValueAttributeNamespaceKey,
+ pValueAttributeName,
+ pValuePropertyName);
+ }
+
+ OSL_ENSURE((nullptr == pValuePropertyName) == (CCAFlags::NONE == (CCAFlags::Value & m_nIncludeCommon)),
+ "OControlExport::exportCommonControlAttributes: no property found for the value attribute!");
+ OSL_ENSURE((nullptr == pCurrentValuePropertyName ) == (CCAFlags::NONE == (CCAFlags::CurrentValue & m_nIncludeCommon)),
+ "OControlExport::exportCommonControlAttributes: no property found for the current-value attribute!");
+
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags(CCAFlags::CurrentValue | CCAFlags::Value);
+ #endif
+ }
+
+ OSL_ENSURE(CCAFlags::NONE == m_nIncludeCommon,
+ "OControlExport::exportCommonControlAttributes: forgot some flags!");
+ // in the dbg_util version, we should have removed every bit we handled from the mask, so it should
+ // be 0 now ...
+ }
+
+ void OControlExport::exportDatabaseAttributes()
+ {
+#if OSL_DEBUG_LEVEL > 0
+ DAFlags nIncludeDatabase = m_nIncludeDatabase;
+#endif
+ // the only string property: DataField
+ if (DAFlags::DataField & m_nIncludeDatabase)
+ {
+ exportStringPropertyAttribute(
+ OAttributeMetaData::getDatabaseAttributeNamespace(),
+ OAttributeMetaData::getDatabaseAttributeName(DAFlags::DataField),
+ PROPERTY_DATAFIELD);
+ RESET_BIT( nIncludeDatabase, DAFlags::DataField );
+ }
+
+ // InputRequired
+ if ( DAFlags::InputRequired & m_nIncludeDatabase )
+ {
+ exportBooleanPropertyAttribute(
+ OAttributeMetaData::getDatabaseAttributeNamespace(),
+ OAttributeMetaData::getDatabaseAttributeName( DAFlags::InputRequired ),
+ PROPERTY_INPUT_REQUIRED,
+ BoolAttrFlags::DefaultFalse | BoolAttrFlags::DefaultVoid
+ );
+ RESET_BIT( nIncludeDatabase, DAFlags::InputRequired );
+ }
+
+ // the only int16 property: BoundColumn
+ if (DAFlags::BoundColumn & m_nIncludeDatabase)
+ {
+ exportInt16PropertyAttribute(
+ OAttributeMetaData::getDatabaseAttributeNamespace(),
+ OAttributeMetaData::getDatabaseAttributeName(DAFlags::BoundColumn),
+ PROPERTY_BOUNDCOLUMN,
+ 0,
+ true);
+ RESET_BIT( nIncludeDatabase, DAFlags::BoundColumn );
+ }
+
+ // ConvertEmptyToNull
+ if (DAFlags::ConvertEmpty & m_nIncludeDatabase)
+ {
+ exportBooleanPropertyAttribute(
+ OAttributeMetaData::getDatabaseAttributeNamespace(),
+ OAttributeMetaData::getDatabaseAttributeName(DAFlags::ConvertEmpty),
+ PROPERTY_EMPTY_IS_NULL,
+ BoolAttrFlags::DefaultFalse
+ );
+ RESET_BIT( nIncludeDatabase, DAFlags::ConvertEmpty );
+ }
+
+ // the only enum property: ListSourceType
+ if (DAFlags::ListSource_TYPE & m_nIncludeDatabase)
+ {
+ exportEnumPropertyAttribute(
+ OAttributeMetaData::getDatabaseAttributeNamespace(),
+ OAttributeMetaData::getDatabaseAttributeName(DAFlags::ListSource_TYPE),
+ PROPERTY_LISTSOURCETYPE,
+ aListSourceTypeMap,
+ ListSourceType_VALUELIST
+ );
+ RESET_BIT( nIncludeDatabase, DAFlags::ListSource_TYPE );
+ }
+
+ if (m_nIncludeDatabase & DAFlags::ListSource)
+ {
+ exportListSourceAsAttribute();
+ RESET_BIT( nIncludeDatabase, DAFlags::ListSource );
+ }
+
+#if OSL_DEBUG_LEVEL > 0
+ OSL_ENSURE(DAFlags::NONE == nIncludeDatabase,
+ "OControlExport::exportDatabaseAttributes: forgot some flags!");
+ // in the dbg_util version, we should have removed every bit we handled from the mask, so it should
+ // be 0 now ...
+#endif
+ }
+
+ void OControlExport::exportBindingAttributes()
+ {
+#if OSL_DEBUG_LEVEL > 0
+ BAFlags nIncludeBinding = m_nIncludeBindings;
+#endif
+
+ if ( m_nIncludeBindings & BAFlags::LinkedCell )
+ {
+ exportCellBindingAttributes( bool(m_nIncludeBindings & BAFlags::ListLinkingType) );
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ nIncludeBinding = nIncludeBinding & ~BAFlags( BAFlags::LinkedCell | BAFlags::ListLinkingType );
+ #endif
+ }
+
+ if ( m_nIncludeBindings & BAFlags::ListCellRange )
+ {
+ exportCellListSourceRange();
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ nIncludeBinding = nIncludeBinding & ~BAFlags::ListCellRange;
+ #endif
+ }
+
+ if ( m_nIncludeBindings & BAFlags::XFormsBind )
+ {
+ exportXFormsBindAttributes();
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ nIncludeBinding = nIncludeBinding & ~BAFlags::XFormsBind;
+ #endif
+ }
+
+ if ( m_nIncludeBindings & BAFlags::XFormsListBind )
+ {
+ exportXFormsListAttributes();
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ nIncludeBinding = nIncludeBinding & ~BAFlags::XFormsListBind;
+ #endif
+ }
+
+ if ( m_nIncludeBindings & BAFlags::XFormsSubmission )
+ {
+ exportXFormsSubmissionAttributes();
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ nIncludeBinding = nIncludeBinding & ~BAFlags::XFormsSubmission;
+ #endif
+ }
+
+ #if OSL_DEBUG_LEVEL > 0
+ OSL_ENSURE( BAFlags::NONE == nIncludeBinding,
+ "OControlExport::exportBindingAttributes: forgot some flags!");
+ // in the debug version, we should have removed every bit we handled from the mask, so it should
+ // be 0 now ...
+ #endif
+ }
+
+ void OControlExport::exportSpecialAttributes()
+ {
+ sal_Int32 i=0;
+
+ // the boolean properties
+ {
+ static const SCAFlags nBooleanPropertyAttributeIds[] =
+ { // attribute flags
+ SCAFlags::Validation, SCAFlags::MultiLine, SCAFlags::AutoCompletion, SCAFlags::Multiple, SCAFlags::DefaultButton, SCAFlags::IsTristate,
+ SCAFlags::Toggle, SCAFlags::FocusOnClick
+ };
+ static const char * pBooleanPropertyNames[] =
+ { // property names
+ PROPERTY_STRICTFORMAT, PROPERTY_MULTILINE,
+ PROPERTY_AUTOCOMPLETE,
+ PROPERTY_MULTISELECTION,
+ PROPERTY_DEFAULTBUTTON, PROPERTY_TRISTATE,
+ PROPERTY_TOGGLE, PROPERTY_FOCUS_ON_CLICK
+ };
+ static const sal_Int32 nIdCount = SAL_N_ELEMENTS(nBooleanPropertyAttributeIds);
+ #if OSL_DEBUG_LEVEL > 0
+ static const sal_Int32 nNameCount = SAL_N_ELEMENTS(pBooleanPropertyNames);
+ OSL_ENSURE((nIdCount == nNameCount),
+ "OControlExport::exportSpecialAttributes: somebody tampered with the maps (1)!");
+ #endif
+ const SCAFlags* pAttributeId = nBooleanPropertyAttributeIds;
+ for ( i = 0; i < nIdCount; ++i, ++pAttributeId )
+ {
+ if ( *pAttributeId & m_nIncludeSpecial)
+ {
+ exportBooleanPropertyAttribute(
+ OAttributeMetaData::getSpecialAttributeNamespace( *pAttributeId ),
+ OAttributeMetaData::getSpecialAttributeName( *pAttributeId ),
+ OUString::createFromAscii(pBooleanPropertyNames[i]),
+ ( *pAttributeId == SCAFlags::FocusOnClick ) ? BoolAttrFlags::DefaultTrue : BoolAttrFlags::DefaultFalse
+ );
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeSpecial = m_nIncludeSpecial & ~*pAttributeId;
+ #endif
+ }
+ }
+ }
+
+ // the integer properties
+ {
+ static const SCAFlags nIntegerPropertyAttributeIds[] =
+ { // attribute flags
+ SCAFlags::PageStepSize
+ };
+ static const char * pIntegerPropertyNames[] =
+ { // property names
+ PROPERTY_BLOCK_INCREMENT
+ };
+ static const sal_Int32 nIntegerPropertyAttrDefaults[] =
+ { // attribute defaults (XML defaults, not runtime defaults!)
+ 10
+ };
+
+ static const sal_Int32 nIdCount = SAL_N_ELEMENTS( nIntegerPropertyAttributeIds );
+ #if OSL_DEBUG_LEVEL > 0
+ static const sal_Int32 nNameCount = SAL_N_ELEMENTS( pIntegerPropertyNames );
+ OSL_ENSURE( ( nIdCount == nNameCount ),
+ "OControlExport::exportSpecialAttributes: somebody tampered with the maps (2)!" );
+ static const sal_Int32 nDefaultCount = SAL_N_ELEMENTS( nIntegerPropertyAttrDefaults );
+ OSL_ENSURE( ( nIdCount == nDefaultCount ),
+ "OControlExport::exportSpecialAttributes: somebody tampered with the maps (3)!" );
+ #endif
+ for ( i = 0; i < nIdCount; ++i )
+ if ( nIntegerPropertyAttributeIds[i] & m_nIncludeSpecial )
+ {
+ exportInt32PropertyAttribute(
+ OAttributeMetaData::getSpecialAttributeNamespace( nIntegerPropertyAttributeIds[i] ),
+ OAttributeMetaData::getSpecialAttributeName( nIntegerPropertyAttributeIds[i] ),
+ OUString::createFromAscii(pIntegerPropertyNames[i]),
+ nIntegerPropertyAttrDefaults[i]
+ );
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeSpecial = m_nIncludeSpecial & ~nIntegerPropertyAttributeIds[i];
+ #endif
+ }
+
+ if ( SCAFlags::StepSize & m_nIncludeSpecial )
+ {
+ OUString sPropertyName;
+ if ( m_xPropertyInfo->hasPropertyByName( PROPERTY_LINE_INCREMENT ) )
+ sPropertyName = PROPERTY_LINE_INCREMENT;
+ else if ( m_xPropertyInfo->hasPropertyByName( PROPERTY_SPIN_INCREMENT ) )
+ sPropertyName = PROPERTY_SPIN_INCREMENT;
+ else
+ OSL_FAIL( "OControlExport::exportSpecialAttributes: not property which can be mapped to step-size attribute!" );
+
+ if ( !sPropertyName.isEmpty() )
+ exportInt32PropertyAttribute(
+ OAttributeMetaData::getSpecialAttributeNamespace( SCAFlags::StepSize ),
+ OAttributeMetaData::getSpecialAttributeName( SCAFlags::StepSize ),
+ sPropertyName,
+ 1
+ );
+
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeSpecial = m_nIncludeSpecial & ~SCAFlags::StepSize;
+ #endif
+ }
+
+ }
+
+ // the enum properties
+ {
+ if (SCAFlags::State & m_nIncludeSpecial)
+ {
+ exportEnumPropertyAttribute(
+ OAttributeMetaData::getSpecialAttributeNamespace(SCAFlags::State),
+ OAttributeMetaData::getSpecialAttributeName(SCAFlags::State),
+ PROPERTY_DEFAULT_STATE,
+ aCheckStateMap,
+ TRISTATE_FALSE);
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeSpecial = m_nIncludeSpecial & ~SCAFlags::State;
+ #endif
+ }
+
+ if (SCAFlags::CurrentState & m_nIncludeSpecial)
+ {
+ exportEnumPropertyAttribute(
+ OAttributeMetaData::getSpecialAttributeNamespace(SCAFlags::CurrentState),
+ OAttributeMetaData::getSpecialAttributeName(SCAFlags::CurrentState),
+ PROPERTY_STATE,
+ aCheckStateMap,
+ TRISTATE_FALSE);
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeSpecial = m_nIncludeSpecial & ~SCAFlags::CurrentState;
+ #endif
+ }
+ }
+
+ // some properties which require a special handling
+ // the repeat delay
+ {
+ if ( m_nIncludeSpecial & SCAFlags::RepeatDelay )
+ {
+ DBG_CHECK_PROPERTY( PROPERTY_REPEAT_DELAY, sal_Int32 );
+
+ sal_Int32 nRepeatDelay = 0;
+ m_xProps->getPropertyValue( PROPERTY_REPEAT_DELAY ) >>= nRepeatDelay;
+ tools::Time aTime( tools::Time::SYSTEM );
+ aTime.MakeTimeFromMS( nRepeatDelay );
+ util::Duration aDuration;
+ aDuration.Hours = aTime.GetHour();
+ aDuration.Minutes = aTime.GetMin();
+ aDuration.Seconds = aTime.GetSec();
+ aDuration.NanoSeconds = (nRepeatDelay % 1000) * 1000000;
+
+ OUStringBuffer buf;
+ ::sax::Converter::convertDuration(buf, aDuration);
+ AddAttribute(OAttributeMetaData::getSpecialAttributeNamespace( SCAFlags::RepeatDelay )
+ ,OAttributeMetaData::getSpecialAttributeName( SCAFlags::RepeatDelay )
+ ,buf.makeStringAndClear());
+
+ exportedProperty( PROPERTY_REPEAT_DELAY );
+
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeSpecial = m_nIncludeSpecial & ~SCAFlags::RepeatDelay;
+ #endif
+ }
+ }
+
+ // the EchoChar property needs special handling, cause it's a Int16, but must be stored as one-character-string
+ {
+ if (SCAFlags::EchoChar & m_nIncludeSpecial)
+ {
+ DBG_CHECK_PROPERTY( PROPERTY_ECHO_CHAR, sal_Int16 );
+ sal_Int16 nValue(0);
+ m_xProps->getPropertyValue(PROPERTY_ECHO_CHAR) >>= nValue;
+ if (nValue)
+ {
+ OUString sCharacter(reinterpret_cast<const sal_Unicode*>(&nValue), 1);
+ AddAttribute(
+ OAttributeMetaData::getSpecialAttributeNamespace(SCAFlags::EchoChar),
+ OAttributeMetaData::getSpecialAttributeName(SCAFlags::EchoChar),
+ sCharacter);
+ }
+ exportedProperty(PROPERTY_ECHO_CHAR);
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeSpecial = m_nIncludeSpecial & ~SCAFlags::EchoChar;
+ #endif
+ }
+ }
+
+ // the string properties
+ {
+ static const SCAFlags nStringPropertyAttributeIds[] =
+ { // attribute flags
+ SCAFlags::GroupName
+ };
+ static const std::u16string_view pStringPropertyNames[] =
+ { // property names
+ u"" PROPERTY_GROUP_NAME
+ };
+
+ static const sal_Int32 nIdCount = SAL_N_ELEMENTS( nStringPropertyAttributeIds );
+ #if OSL_DEBUG_LEVEL > 0
+ static const sal_Int32 nNameCount = SAL_N_ELEMENTS( pStringPropertyNames );
+ OSL_ENSURE( ( nIdCount == nNameCount ),
+ "OControlExport::exportSpecialAttributes: somebody tampered with the maps (2)!" );
+ #endif
+ for ( i = 0; i < nIdCount; ++i )
+ if ( nStringPropertyAttributeIds[i] & m_nIncludeSpecial )
+ {
+ exportStringPropertyAttribute(
+ OAttributeMetaData::getSpecialAttributeNamespace( nStringPropertyAttributeIds[i] ),
+ OAttributeMetaData::getSpecialAttributeName( nStringPropertyAttributeIds[i] ),
+ OUString(pStringPropertyNames[i])
+ );
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeSpecial = m_nIncludeSpecial & ~nStringPropertyAttributeIds[i];
+ #endif
+ }
+ }
+
+ if ((SCAFlags::MinValue | SCAFlags::MaxValue) & m_nIncludeSpecial)
+ {
+ // need to export the min value and the max value as attributes
+ // It depends on the real type (FormComponentType) of the control, which properties hold these
+ // values
+ const char* pMinValuePropertyName = nullptr;
+ const char* pMaxValuePropertyName = nullptr;
+ getValueLimitPropertyNames(m_nClassId, pMinValuePropertyName, pMaxValuePropertyName);
+
+ OSL_ENSURE((nullptr == pMinValuePropertyName) == (SCAFlags::NONE == (SCAFlags::MinValue & m_nIncludeSpecial)),
+ "OControlExport::exportCommonControlAttributes: no property found for the min value attribute!");
+ OSL_ENSURE((nullptr == pMaxValuePropertyName) == (SCAFlags::NONE == (SCAFlags::MaxValue & m_nIncludeSpecial)),
+ "OControlExport::exportCommonControlAttributes: no property found for the max value attribute!");
+
+ // add the two attributes
+ static const OUString pMinValueAttributeName = OAttributeMetaData::getSpecialAttributeName(SCAFlags::MinValue);
+ static const OUString pMaxValueAttributeName = OAttributeMetaData::getSpecialAttributeName(SCAFlags::MaxValue);
+ static const sal_uInt16 nMinValueNamespaceKey = OAttributeMetaData::getSpecialAttributeNamespace(SCAFlags::MinValue);
+ static const sal_uInt16 nMaxValueNamespaceKey = OAttributeMetaData::getSpecialAttributeNamespace(SCAFlags::MaxValue);
+
+ if (pMinValuePropertyName && (SCAFlags::MinValue & m_nIncludeSpecial))
+ exportGenericPropertyAttribute(
+ nMinValueNamespaceKey,
+ pMinValueAttributeName,
+ pMinValuePropertyName);
+
+ if (pMaxValuePropertyName && (SCAFlags::MaxValue & m_nIncludeSpecial))
+ exportGenericPropertyAttribute(
+ nMaxValueNamespaceKey,
+ pMaxValueAttributeName,
+ pMaxValuePropertyName);
+ #if OSL_DEBUG_LEVEL > 0
+ // reset the bit for later checking
+ m_nIncludeSpecial = m_nIncludeSpecial & ~SCAFlags(SCAFlags::MinValue | SCAFlags::MaxValue);
+ #endif
+ }
+
+ if ( SCAFlags::ImagePosition & m_nIncludeSpecial )
+ {
+ exportImagePositionAttributes();
+ RESET_BIT( m_nIncludeSpecial, SCAFlags::ImagePosition );
+ }
+
+ OSL_ENSURE(SCAFlags::NONE == m_nIncludeSpecial,
+ "OControlExport::exportSpecialAttributes: forgot some flags!");
+ // in the dbg_util version, we should have removed every bit we handled from the mask, so it should
+ // be 0 now ...
+ }
+
+ OUString OControlExport::getScalarListSourceValue() const
+ {
+ OUString sListSource;
+ Any aListSource = m_xProps->getPropertyValue( PROPERTY_LISTSOURCE );
+ if ( !( aListSource >>= sListSource ) )
+ {
+ Sequence< OUString > aListSourceSequence;
+ aListSource >>= aListSourceSequence;
+ if ( aListSourceSequence.hasElements() )
+ sListSource = aListSourceSequence[ 0 ];
+ }
+ return sListSource;
+ }
+
+ void OControlExport::exportListSourceAsAttribute()
+ {
+ // DAFlags::ListSource needs some special handling
+ DBG_CHECK_PROPERTY_NO_TYPE( PROPERTY_LISTSOURCE );
+
+ OUString sListSource = getScalarListSourceValue();
+ if ( !sListSource.isEmpty() )
+ { // the ListSource property needs to be exported as attribute, and it is not empty
+ AddAttribute(
+ OAttributeMetaData::getDatabaseAttributeNamespace(),
+ OAttributeMetaData::getDatabaseAttributeName(DAFlags::ListSource),
+ sListSource);
+ }
+
+ exportedProperty( PROPERTY_LISTSOURCE );
+ }
+
+ void OControlExport::getSequenceInt16PropertyAsSet(const OUString& _rPropertyName, Int16Set& _rOut)
+ {
+ Sequence< sal_Int16 > aValueSequence;
+ DBG_CHECK_PROPERTY(_rPropertyName, Sequence< sal_Int16 >);
+ m_xProps->getPropertyValue(_rPropertyName) >>= aValueSequence;
+
+ for (const auto& rValue : std::as_const(aValueSequence))
+ _rOut.insert(rValue);
+ }
+
+ void OControlExport::exportListSourceAsElements()
+ {
+ // the string lists
+ Sequence< OUString > aItems, aValues;
+ DBG_CHECK_PROPERTY( PROPERTY_STRING_ITEM_LIST, Sequence< OUString > );
+ m_xProps->getPropertyValue(PROPERTY_STRING_ITEM_LIST) >>= aItems;
+
+ DBG_CHECK_PROPERTY( PROPERTY_LISTSOURCE, Sequence< OUString > );
+ if ( DAFlags::NONE == ( m_nIncludeDatabase & DAFlags::ListSource ) )
+ m_xProps->getPropertyValue(PROPERTY_LISTSOURCE) >>= aValues;
+ // if we exported the list source as attribute, we do not repeat it as sub elements
+
+ // the selection lists
+ Int16Set aSelection, aDefaultSelection;
+ getSequenceInt16PropertyAsSet(PROPERTY_SELECT_SEQ, aSelection);
+ getSequenceInt16PropertyAsSet(PROPERTY_DEFAULT_SELECT_SEQ, aDefaultSelection);
+
+ // the string for "true"
+ OUString sTrue;
+ OUStringBuffer sBuffer;
+ ::sax::Converter::convertBool(sBuffer, true);
+ sTrue = sBuffer.makeStringAndClear();
+
+ // loop through both lists ('til the maximum of both lengths)
+ const OUString* pItems = aItems.getConstArray();
+ const OUString* pValues = aValues.getConstArray();
+
+ sal_Int32 nItems = aItems.getLength();
+ sal_Int32 nValues = aValues.getLength();
+
+ sal_Int16 nMaxLen = static_cast<sal_Int16>(std::max(nItems, nValues));
+
+ for (sal_Int16 i=0; i<nMaxLen; ++i )
+ {
+ m_rContext.getGlobalContext().ClearAttrList();
+ if (i < nItems)
+ {
+ // there is an item at this position
+ AddAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::Label),
+ OAttributeMetaData::getCommonControlAttributeName(CCAFlags::Label),
+ *pItems);
+ ++pItems;
+ }
+ if (i < nValues)
+ {
+ // there is a value at this position
+ AddAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::Value),
+ OAttributeMetaData::getCommonControlAttributeName(CCAFlags::Value),
+ *pValues);
+ ++pValues;
+ }
+
+ Int16Set::const_iterator aSelectedPos = aSelection.find(i);
+ if (aSelection.end() != aSelectedPos)
+ { // the item at this position is selected
+ AddAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::CurrentSelected),
+ OAttributeMetaData::getCommonControlAttributeName(CCAFlags::CurrentSelected),
+ sTrue
+ );
+ aSelection.erase(aSelectedPos);
+ }
+
+ Int16Set::const_iterator aDefaultSelectedPos = aDefaultSelection.find(i);
+ if (aDefaultSelection.end() != aDefaultSelectedPos)
+ { // the item at this position is selected as default
+ AddAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::Selected),
+ OAttributeMetaData::getCommonControlAttributeName(CCAFlags::Selected),
+ sTrue
+ );
+ aDefaultSelection.erase(aDefaultSelectedPos);
+ }
+ SvXMLElementExport aFormElement(m_rContext.getGlobalContext(), XML_NAMESPACE_FORM, "option", true, true);
+ }
+
+ // There may be more "selected" or "default-selected" items than there are in the lists in real,
+ // so we need to store some additional "form:option" items which have no name and no label, but
+ // one or both of the selected flags.
+ // 21.05.2001 - 85388 - frank.schoenheit@germany.sun.com
+
+ if (aSelection.empty() && aDefaultSelection.empty())
+ return;
+
+ sal_Int16 nLastSelected = -1;
+ if ( !aSelection.empty() )
+ nLastSelected = *(--aSelection.end());
+
+ sal_Int16 nLastDefaultSelected = -1;
+ if ( !aDefaultSelection.empty() )
+ nLastDefaultSelected = *(--aDefaultSelection.end());
+
+ // the maximum element in both sets
+ sal_Int16 nLastReferredEntry = std::max(nLastSelected, nLastDefaultSelected);
+ OSL_ENSURE(nLastReferredEntry >= nMaxLen, "OControlExport::exportListSourceAsElements: inconsistence!");
+ // if the maximum (selected or default selected) entry number is less than the maximum item count
+ // in both lists, the entry number should have been removed from the set
+
+ for (sal_Int16 i=nMaxLen; i<=nLastReferredEntry; ++i)
+ {
+ if (aSelection.end() != aSelection.find(i))
+ { // the (not existent) item at this position is selected
+ AddAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::CurrentSelected),
+ OAttributeMetaData::getCommonControlAttributeName(CCAFlags::CurrentSelected),
+ sTrue
+ );
+ }
+
+ if (aDefaultSelection.end() != aDefaultSelection.find(i))
+ { // the (not existent) item at this position is selected as default
+ AddAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::Selected),
+ OAttributeMetaData::getCommonControlAttributeName(CCAFlags::Selected),
+ sTrue
+ );
+ }
+ SvXMLElementExport aFormElement(m_rContext.getGlobalContext(), XML_NAMESPACE_FORM, "option", true, true);
+ }
+ }
+
+ void OControlExport::implStartElement(const char* _pName)
+ {
+ // before we let the base class start it's outer element, we add a wrapper element
+ const char *pOuterElementName = getOuterXMLElementName();
+ if (pOuterElementName)
+ m_pOuterElement = std::make_unique<SvXMLElementExport>(
+ m_rContext.getGlobalContext(),
+ XML_NAMESPACE_FORM,
+ pOuterElementName, true,
+ true);
+
+ // add the attributes for the inner element
+ exportInnerAttributes();
+
+ // and start the inner element
+ OElementExport::implStartElement(_pName);
+ }
+
+ void OControlExport::implEndElement()
+ {
+ // end the inner element
+ OElementExport::implEndElement();
+
+ // end the outer element if it exists
+ m_pOuterElement.reset();
+ }
+
+ const char* OControlExport::getOuterXMLElementName() const
+ {
+ return nullptr;
+ }
+
+ const char* OControlExport::getXMLElementName() const
+ {
+ return getElementName(m_eType);
+ }
+
+ void OControlExport::examine()
+ {
+ OSL_ENSURE( ( m_nIncludeCommon == CCAFlags::NONE ) && ( m_nIncludeSpecial == SCAFlags::NONE ) && ( m_nIncludeDatabase == DAFlags::NONE )
+ && ( m_nIncludeEvents == EAFlags::NONE ) && ( m_nIncludeBindings == BAFlags::NONE),
+ "OControlExport::examine: called me twice? Not initialized?" );
+
+ // get the class id to decide which kind of element we need in the XML stream
+ m_nClassId = FormComponentType::CONTROL;
+ DBG_CHECK_PROPERTY( PROPERTY_CLASSID, sal_Int16 );
+ m_xProps->getPropertyValue(PROPERTY_CLASSID) >>= m_nClassId;
+ bool knownType = false;
+ switch (m_nClassId)
+ {
+ case FormComponentType::DATEFIELD:
+ m_eType = DATE;
+ knownType = true;
+ [[fallthrough]];
+ case FormComponentType::TIMEFIELD:
+ if ( !knownType )
+ {
+ m_eType = TIME;
+ knownType = true;
+ }
+ m_nIncludeSpecial |= SCAFlags::Validation;
+ [[fallthrough]];
+ case FormComponentType::NUMERICFIELD:
+ case FormComponentType::CURRENCYFIELD:
+ case FormComponentType::PATTERNFIELD:
+ if ( !knownType )
+ {
+ m_eType = FORMATTED_TEXT;
+ knownType = true;
+ }
+ [[fallthrough]];
+ case FormComponentType::TEXTFIELD:
+ { // it's some kind of edit. To know which type we need further investigation
+
+ if ( !knownType )
+ {
+ // check if it's a formatted field
+ if (m_xPropertyInfo->hasPropertyByName(PROPERTY_FORMATKEY))
+ {
+ m_eType = FORMATTED_TEXT;
+ }
+ else
+ {
+ // all other controls are represented by an ordinary edit control, but which XML control type
+ // it is depends on the current values of some properties
+
+ // if the EchoChar string is not empty, it is a password field
+ sal_Int16 nEchoChar = 0;
+ if (m_xPropertyInfo->hasPropertyByName(PROPERTY_ECHOCHAR))
+ // grid columns do not have this property...
+ m_xProps->getPropertyValue(PROPERTY_ECHOCHAR) >>= nEchoChar;
+ if (nEchoChar)
+ {
+ m_eType = PASSWORD;
+ m_nIncludeSpecial |= SCAFlags::EchoChar;
+ }
+ else
+ {
+ // if the MultiLine property is sal_True, it is a TextArea
+ bool bMultiLine = false;
+ if (m_xPropertyInfo->hasPropertyByName(PROPERTY_MULTILINE))
+ // grid columns do not have this property...
+ bMultiLine = ::cppu::any2bool(m_xProps->getPropertyValue(PROPERTY_MULTILINE));
+
+ if ( bMultiLine )
+ m_eType = TEXT_AREA;
+ else
+ // the only case left is represented by a Text element
+ m_eType = TEXT;
+ }
+ }
+ }
+
+ // attributes which are common to all the types:
+ // common attributes
+ m_nIncludeCommon =
+ CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Disabled |
+ CCAFlags::Printable | CCAFlags::TabIndex | CCAFlags::TabStop | CCAFlags::Title;
+
+ if ( ( m_nClassId != FormComponentType::DATEFIELD )
+ && ( m_nClassId != FormComponentType::TIMEFIELD )
+ )
+ // date and time field values are handled differently nowadays
+ m_nIncludeCommon |= CCAFlags::Value;
+
+ // database attributes
+ m_nIncludeDatabase = DAFlags::DataField | DAFlags::InputRequired;
+
+ // event attributes
+ m_nIncludeEvents = EAFlags::ControlEvents | EAFlags::OnChange | EAFlags::OnSelect;
+
+ // only text and pattern fields have a ConvertEmptyToNull property
+ if ( ( m_nClassId == FormComponentType::TEXTFIELD )
+ || ( m_nClassId == FormComponentType::PATTERNFIELD )
+ )
+ m_nIncludeDatabase |= DAFlags::ConvertEmpty;
+
+ // all controls but the file control fields have a readonly property
+ if ( m_nClassId != FormComponentType::FILECONTROL )
+ m_nIncludeCommon |= CCAFlags::ReadOnly;
+
+ // a text field has a max text len
+ if ( m_nClassId == FormComponentType::TEXTFIELD )
+ m_nIncludeCommon |= CCAFlags::MaxLength;
+
+ // max and min values and validation:
+ if (FORMATTED_TEXT == m_eType)
+ { // in general all controls represented as formatted-text have these props
+ if ( FormComponentType::PATTERNFIELD != m_nClassId ) // except the PatternField
+ m_nIncludeSpecial |= SCAFlags::MaxValue | SCAFlags::MinValue;
+
+ if (FormComponentType::TEXTFIELD != m_nClassId)
+ // and the FormattedField does not have a validation flag
+ m_nIncludeSpecial |= SCAFlags::Validation;
+ }
+
+ // if it's not a password field or rich text control, the CurrentValue needs to be stored, too
+ if ( ( PASSWORD != m_eType )
+ && ( DATE != m_eType )
+ && ( TIME != m_eType )
+ )
+ {
+ m_nIncludeCommon |= CCAFlags::CurrentValue;
+ }
+ }
+ break;
+
+ case FormComponentType::FILECONTROL:
+ m_eType = FILE;
+ m_nIncludeCommon =
+ CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::CurrentValue | CCAFlags::Disabled |
+ CCAFlags::Printable | CCAFlags::TabIndex | CCAFlags::TabStop | CCAFlags::Title |
+ CCAFlags::Value;
+ m_nIncludeEvents = EAFlags::ControlEvents | EAFlags::OnChange | EAFlags::OnSelect;
+ break;
+
+ case FormComponentType::FIXEDTEXT:
+ m_eType = FIXED_TEXT;
+ m_nIncludeCommon =
+ CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Disabled | CCAFlags::Label |
+ CCAFlags::Printable | CCAFlags::Title | CCAFlags::For;
+ m_nIncludeSpecial = SCAFlags::MultiLine;
+ m_nIncludeEvents = EAFlags::ControlEvents;
+ break;
+
+ case FormComponentType::COMBOBOX:
+ m_eType = COMBOBOX;
+ m_nIncludeCommon =
+ CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::CurrentValue |
+ CCAFlags::Disabled | CCAFlags::Dropdown | CCAFlags::MaxLength | CCAFlags::Printable | CCAFlags::ReadOnly | CCAFlags::Size |
+ CCAFlags::TabIndex | CCAFlags::TabStop | CCAFlags::Title | CCAFlags::Value;
+ m_nIncludeSpecial = SCAFlags::AutoCompletion;
+ m_nIncludeDatabase = DAFlags::ConvertEmpty | DAFlags::DataField | DAFlags::InputRequired | DAFlags::ListSource | DAFlags::ListSource_TYPE;
+ m_nIncludeEvents = EAFlags::ControlEvents | EAFlags::OnChange | EAFlags::OnSelect;
+ break;
+
+ case FormComponentType::LISTBOX:
+ m_eType = LISTBOX;
+ m_nIncludeCommon =
+ CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Disabled | CCAFlags::Dropdown |
+ CCAFlags::Printable | CCAFlags::Size | CCAFlags::TabIndex | CCAFlags::TabStop | CCAFlags::Title;
+ m_nIncludeSpecial = SCAFlags::Multiple;
+ m_nIncludeDatabase = DAFlags::BoundColumn | DAFlags::DataField | DAFlags::InputRequired | DAFlags::ListSource_TYPE;
+ m_nIncludeEvents = EAFlags::ControlEvents | EAFlags::OnChange | EAFlags::OnClick | EAFlags::OnDoubleClick;
+ // check if we need to export the ListSource as attribute
+ {
+ // for a list box, if the ListSourceType is VALUE_LIST, no ListSource is stored, but instead
+ // a sequence of pairs which is build from the StringItemList and the ValueList
+ ListSourceType eListSourceType = ListSourceType_VALUELIST;
+ bool bSuccess =
+ m_xProps->getPropertyValue(PROPERTY_LISTSOURCETYPE) >>= eListSourceType;
+ OSL_ENSURE(bSuccess, "OControlExport::examineControl: could not retrieve the ListSourceType!");
+ if (ListSourceType_VALUELIST != eListSourceType)
+ {
+ m_nIncludeDatabase |= DAFlags::ListSource;
+ }
+ }
+
+ break;
+
+ case FormComponentType::COMMANDBUTTON:
+ m_eType = BUTTON;
+ m_nIncludeCommon |= CCAFlags::TabStop | CCAFlags::Label;
+ m_nIncludeSpecial = SCAFlags::DefaultButton | SCAFlags::Toggle | SCAFlags::FocusOnClick | SCAFlags::ImagePosition | SCAFlags::RepeatDelay;
+ [[fallthrough]];
+ case FormComponentType::IMAGEBUTTON:
+ if (BUTTON != m_eType)
+ {
+ // not coming from the previous case
+ m_eType = IMAGE;
+ }
+ m_nIncludeCommon |=
+ CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::ButtonType | CCAFlags::Disabled |
+ CCAFlags::ImageData | CCAFlags::Printable | CCAFlags::TabIndex | CCAFlags::TargetFrame |
+ CCAFlags::TargetLocation | CCAFlags::Title;
+ m_nIncludeEvents = EAFlags::ControlEvents | EAFlags::OnClick | EAFlags::OnDoubleClick;
+ break;
+
+ case FormComponentType::CHECKBOX:
+ m_eType = CHECKBOX;
+ m_nIncludeSpecial = SCAFlags::CurrentState | SCAFlags::IsTristate | SCAFlags::State;
+ [[fallthrough]];
+ case FormComponentType::RADIOBUTTON:
+ m_nIncludeCommon =
+ CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Disabled | CCAFlags::Label | CCAFlags::Printable |
+ CCAFlags::TabIndex | CCAFlags::TabStop | CCAFlags::Title | CCAFlags::Value | CCAFlags::VisualEffect;
+ if (CHECKBOX != m_eType)
+ { // not coming from the previous case
+ m_eType = RADIO;
+ m_nIncludeCommon |= CCAFlags::CurrentSelected | CCAFlags::Selected;
+ }
+ if ( m_xPropertyInfo->hasPropertyByName( PROPERTY_IMAGE_POSITION ) )
+ m_nIncludeSpecial |= SCAFlags::ImagePosition;
+ if ( m_xPropertyInfo->hasPropertyByName( PROPERTY_GROUP_NAME ) )
+ m_nIncludeSpecial |= SCAFlags::GroupName;
+ m_nIncludeDatabase = DAFlags::DataField | DAFlags::InputRequired;
+ m_nIncludeEvents = EAFlags::ControlEvents | EAFlags::OnChange;
+ break;
+
+ case FormComponentType::GROUPBOX:
+ m_eType = FRAME;
+ m_nIncludeCommon =
+ CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Disabled | CCAFlags::Label |
+ CCAFlags::Printable | CCAFlags::Title | CCAFlags::For;
+ m_nIncludeEvents = EAFlags::ControlEvents;
+ break;
+
+ case FormComponentType::IMAGECONTROL:
+ m_eType = IMAGE_FRAME;
+ m_nIncludeCommon =
+ CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Disabled | CCAFlags::ImageData |
+ CCAFlags::Printable | CCAFlags::ReadOnly | CCAFlags::Title;
+ m_nIncludeDatabase = DAFlags::DataField | DAFlags::InputRequired;
+ m_nIncludeEvents = EAFlags::ControlEvents;
+ break;
+
+ case FormComponentType::HIDDENCONTROL:
+ m_eType = HIDDEN;
+ m_nIncludeCommon =
+ CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Value;
+ break;
+
+ case FormComponentType::GRIDCONTROL:
+ m_eType = GRID;
+ m_nIncludeCommon =
+ CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Disabled | CCAFlags::Printable |
+ CCAFlags::TabIndex | CCAFlags::TabStop | CCAFlags::Title;
+ m_nIncludeEvents = EAFlags::ControlEvents;
+ break;
+
+ case FormComponentType::SCROLLBAR:
+ case FormComponentType::SPINBUTTON:
+ m_eType = VALUERANGE;
+ m_nIncludeCommon =
+ CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Disabled | CCAFlags::Printable |
+ CCAFlags::Title | CCAFlags::CurrentValue | CCAFlags::Value | CCAFlags::Orientation;
+ m_nIncludeSpecial = SCAFlags::MaxValue | SCAFlags::StepSize | SCAFlags::MinValue | SCAFlags::RepeatDelay;
+
+ if ( m_nClassId == FormComponentType::SCROLLBAR )
+ m_nIncludeSpecial |= SCAFlags::PageStepSize ;
+
+ m_nIncludeEvents = EAFlags::ControlEvents;
+ break;
+
+ default:
+ OSL_FAIL("OControlExport::examineControl: unknown control type (class id)!");
+ [[fallthrough]];
+
+ case FormComponentType::NAVIGATIONBAR:
+ // TODO: should we have an own file format for this?
+ // NO break
+
+ case FormComponentType::CONTROL:
+ m_eType = GENERIC_CONTROL;
+ // unknown control type
+ m_nIncludeCommon = CCAFlags::Name | CCAFlags::ServiceName;
+ // at least a name should be there, 'cause without a name the control could never have been
+ // inserted into its parent container
+ // In addition, the service name is absolutely necessary to create the control upon reading.
+ m_nIncludeEvents = EAFlags::ControlEvents;
+ // we always should be able to export events - this is not control type dependent
+ break;
+ }
+
+ // in general, all control types need to export the control id
+ m_nIncludeCommon |= CCAFlags::ControlId;
+
+ // is it a control bound to a calc cell?
+ if ( FormCellBindingHelper::livesInSpreadsheetDocument( m_xProps ) )
+ {
+ FormCellBindingHelper aHelper( m_xProps, nullptr );
+ {
+ if ( FormCellBindingHelper::isCellBinding( aHelper.getCurrentBinding( ) ) )
+ {
+ m_nIncludeBindings |= BAFlags::LinkedCell;
+ if ( m_nClassId == FormComponentType::LISTBOX )
+ m_nIncludeBindings |= BAFlags::ListLinkingType;
+ }
+ }
+
+ // is it a list-like control which uses a calc cell range as list source?
+ {
+ if ( FormCellBindingHelper::isCellRangeListSource( aHelper.getCurrentListSource( ) ) )
+ m_nIncludeBindings |= BAFlags::ListCellRange;
+ }
+ }
+
+ // is control bound to XForms?
+ if( !getXFormsBindName( m_xProps ).isEmpty() )
+ {
+ m_nIncludeBindings |= BAFlags::XFormsBind;
+ }
+
+ // is (list-)control bound to XForms list?
+ if( !getXFormsListBindName( m_xProps ).isEmpty() )
+ {
+ m_nIncludeBindings |= BAFlags::XFormsListBind;
+ }
+
+ // does the control have an XForms submission?
+ if( !getXFormsSubmissionName( m_xProps ).isEmpty() )
+ {
+ m_nIncludeBindings |= BAFlags::XFormsSubmission;
+ }
+ }
+
+ void OControlExport::exportCellBindingAttributes( bool _bIncludeListLinkageType )
+ {
+ try
+ {
+ FormCellBindingHelper aHelper( m_xProps, nullptr );
+ Reference< XValueBinding > xBinding( aHelper.getCurrentBinding() );
+ OSL_ENSURE( xBinding.is(), "OControlExport::exportCellBindingAttributes: invalid bindable or invalid binding!" );
+ if ( xBinding.is() )
+ {
+ AddAttribute(
+ OAttributeMetaData::getBindingAttributeNamespace(),
+ OAttributeMetaData::getBindingAttributeName( BAFlags::LinkedCell ),
+ aHelper.getStringAddressFromCellBinding( xBinding )
+ );
+
+ if ( _bIncludeListLinkageType )
+ {
+ sal_Int16 nLinkageType = FormCellBindingHelper::isCellIntegerBinding( xBinding ) ? 1 : 0;
+
+ OUStringBuffer sBuffer;
+ SvXMLUnitConverter::convertEnum(
+ sBuffer,
+ nLinkageType,
+ aListLinkageMap
+ );
+
+ AddAttribute(
+ OAttributeMetaData::getBindingAttributeNamespace(),
+ OAttributeMetaData::getBindingAttributeName( BAFlags::ListLinkingType ),
+ sBuffer.makeStringAndClear()
+ );
+ }
+
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "xmloff.forms", "OControlExport::exportCellBindingAttributes" );
+ }
+ }
+
+ void OControlExport::exportXFormsBindAttributes()
+ {
+ OUString sBindName = getXFormsBindName( m_xProps );
+ AddAttribute( XML_NAMESPACE_XFORMS, XML_BIND, sBindName );
+ }
+ void OControlExport::exportXFormsListAttributes()
+ {
+ OUString sBindName = getXFormsListBindName( m_xProps );
+ AddAttribute( XML_NAMESPACE_FORM, XML_XFORMS_LIST_SOURCE, sBindName );
+ }
+ void OControlExport::exportXFormsSubmissionAttributes()
+ {
+ OUString sSubmission = getXFormsSubmissionName( m_xProps );
+ AddAttribute( XML_NAMESPACE_FORM, XML_XFORMS_SUBMISSION, sSubmission );
+ }
+ void OControlExport::exportCellListSourceRange( )
+ {
+ try
+ {
+ Reference< XListEntrySink > xSink( m_xProps, UNO_QUERY );
+ Reference< XListEntrySource > xSource;
+ if ( xSink.is() )
+ xSource = xSink->getListEntrySource();
+ OSL_ENSURE( xSource.is(), "OControlExport::exportCellListSourceRange: list source or sink!" );
+ if ( xSource.is() )
+ {
+ FormCellBindingHelper aHelper( m_xProps, nullptr );
+
+ AddAttribute(
+ OAttributeMetaData::getBindingAttributeNamespace(),
+ OAttributeMetaData::getBindingAttributeName( BAFlags::ListCellRange ),
+ aHelper.getStringAddressFromCellListSource( xSource )
+ );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "xmloff.forms", "OControlExport::exportCellListSourceRange" );
+ }
+ }
+
+ void OControlExport::exportImagePositionAttributes()
+ {
+ try
+ {
+ sal_Int16 nImagePosition = ImagePosition::Centered;
+ OSL_VERIFY( m_xProps->getPropertyValue( PROPERTY_IMAGE_POSITION ) >>= nImagePosition );
+ OSL_ENSURE( ( nImagePosition >= ImagePosition::LeftTop ) && ( nImagePosition <= ImagePosition::Centered ),
+ "OControlExport::exportImagePositionAttributes: don't know this image position!" );
+
+ if ( ( nImagePosition < ImagePosition::LeftTop ) || ( nImagePosition > ImagePosition::Centered ) )
+ // this is important to prevent potential buffer overflows below, so don't optimize
+ nImagePosition = ImagePosition::Centered;
+
+ if ( nImagePosition == ImagePosition::Centered )
+ {
+ AddAttribute( XML_NAMESPACE_FORM, GetXMLToken( XML_IMAGE_POSITION ), GetXMLToken( XML_CENTER ) );
+ }
+ else
+ {
+ const XMLTokenEnum eXmlImagePositions[] =
+ {
+ XML_START, XML_END, XML_TOP, XML_BOTTOM
+ };
+ const XMLTokenEnum eXmlImageAligns[] =
+ {
+ XML_START, XML_CENTER, XML_END
+ };
+
+ XMLTokenEnum eXmlImagePosition = eXmlImagePositions[ nImagePosition / 3 ];
+ XMLTokenEnum eXmlImageAlign = eXmlImageAligns [ nImagePosition % 3 ];
+
+ AddAttribute( XML_NAMESPACE_FORM, GetXMLToken( XML_IMAGE_POSITION ), GetXMLToken( eXmlImagePosition ) );
+ AddAttribute( XML_NAMESPACE_FORM, GetXMLToken( XML_IMAGE_ALIGN ), GetXMLToken( eXmlImageAlign ) );
+ }
+
+ exportedProperty( PROPERTY_IMAGE_POSITION );
+ // some of the controls which have an ImagePosition also have an ImageAlign for compatibility
+ // reasons. Since the ImageAlign values simply represent a sub set of the ImagePosition values,
+ // we don't need to export ImageAlign anymore
+ exportedProperty( PROPERTY_IMAGE_ALIGN );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("xmloff.forms");
+ }
+ }
+
+ bool OControlExport::controlHasActiveDataBinding() const
+ {
+ try
+ {
+ // currently exchanging the data with a database column?
+ OUString sBoundFieldPropertyName( "BoundField" );
+ if ( m_xPropertyInfo.is() && m_xPropertyInfo->hasPropertyByName( sBoundFieldPropertyName ) )
+ {
+ Reference< XPropertySet > xBoundField;
+ m_xProps->getPropertyValue( sBoundFieldPropertyName ) >>= xBoundField;
+ if ( xBoundField.is() )
+ return true;
+ }
+
+ // currently exchanging data with an external binding?
+ Reference< XBindableValue > xBindable( m_xProps, UNO_QUERY );
+ if ( xBindable.is() && xBindable->getValueBinding().is() )
+ return true;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "xmloff.forms", "OColumnExport::controlHasActiveDataBinding" );
+ }
+
+ return false;
+ }
+
+ bool OControlExport::controlHasUserSuppliedListEntries() const
+ {
+ try
+ {
+ // an external list source?
+ Reference< XListEntrySink > xEntrySink( m_xProps, UNO_QUERY );
+ if ( xEntrySink.is() && xEntrySink->getListEntrySource().is() )
+ return false;
+
+ if ( m_xPropertyInfo.is() && m_xPropertyInfo->hasPropertyByName( PROPERTY_LISTSOURCETYPE ) )
+ {
+ ListSourceType eListSourceType = ListSourceType_VALUELIST;
+ OSL_VERIFY( m_xProps->getPropertyValue( PROPERTY_LISTSOURCETYPE ) >>= eListSourceType );
+ if ( eListSourceType == ListSourceType_VALUELIST )
+ // for value lists, the list entries as entered by the user are used
+ return true;
+
+ // for every other type, the list entries are filled with some data obtained
+ // from a database - if and only if the ListSource property is not empty
+ return getScalarListSourceValue().isEmpty();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("xmloff.forms");
+ }
+
+ OSL_FAIL( "OControlExport::controlHasUserSuppliedListEntries: unreachable code!" );
+ // this method should be called for list and combo boxes only
+ return true;
+ }
+
+ //= OColumnExport
+ OColumnExport::OColumnExport(IFormsExportContext& _rContext, const Reference< XPropertySet >& _rxControl, const OUString& _rControlId,
+ const Sequence< ScriptEventDescriptor >& _rEvents)
+ :OControlExport(_rContext, _rxControl, _rControlId, OUString(), _rEvents)
+ {
+ }
+
+ OColumnExport::~OColumnExport()
+ {
+ }
+
+ void OColumnExport::exportServiceNameAttribute()
+ {
+ // the attribute "service name" (which has a slightly different meaning for columns
+ DBG_CHECK_PROPERTY( PROPERTY_COLUMNSERVICENAME, OUString );
+ OUString sColumnServiceName;
+ m_xProps->getPropertyValue(PROPERTY_COLUMNSERVICENAME) >>= sColumnServiceName;
+ // the service name is a full qualified one (i.e. com.sun.star.form.TextField), but the
+ // real service name for the column (for use with the XGridColumnFactory) is only the last
+ // token of this complete name.
+ sal_Int32 nLastSep = sColumnServiceName.lastIndexOf('.');
+ OSL_ENSURE(-1 != nLastSep, "OColumnExport::startExportElement: invalid service name!");
+ sColumnServiceName = sColumnServiceName.copy(nLastSep + 1);
+ sColumnServiceName =
+ m_rContext.getGlobalContext().GetNamespaceMap().GetQNameByKey(
+ XML_NAMESPACE_OOO, sColumnServiceName );
+ // add the attribute
+ AddAttribute( OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::ServiceName)
+ , OAttributeMetaData::getCommonControlAttributeName(CCAFlags::ServiceName)
+ , sColumnServiceName);
+ // flag the property as "handled"
+ exportedProperty(PROPERTY_COLUMNSERVICENAME);
+
+ }
+
+ const char* OColumnExport::getOuterXMLElementName() const
+ {
+ return "column";
+ }
+
+ void OColumnExport::exportAttributes()
+ {
+ OControlExport::exportAttributes();
+
+ // the attribute "label"
+ exportStringPropertyAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::Label),
+ OAttributeMetaData::getCommonControlAttributeName(CCAFlags::Label),
+ PROPERTY_LABEL);
+
+ // the style attribute
+ OUString sStyleName = m_rContext.getObjectStyleName( m_xProps );
+ if ( !sStyleName.isEmpty() )
+ {
+ AddAttribute(
+ OAttributeMetaData::getSpecialAttributeNamespace( SCAFlags::ColumnStyleName ),
+ OAttributeMetaData::getSpecialAttributeName( SCAFlags::ColumnStyleName ),
+ sStyleName
+ );
+ }
+ }
+
+ void OColumnExport::examine()
+ {
+ OControlExport::examine();
+
+ // grid columns miss some properties of the controls they're representing
+ m_nIncludeCommon &= ~CCAFlags(CCAFlags::For | CCAFlags::Printable | CCAFlags::TabIndex | CCAFlags::TabStop | CCAFlags::Label);
+ m_nIncludeSpecial &= ~SCAFlags(SCAFlags::EchoChar | SCAFlags::AutoCompletion | SCAFlags::Multiple | SCAFlags::MultiLine);
+
+ if (FormComponentType::DATEFIELD != m_nClassId)
+ // except date fields, no column has the DropDown property
+ m_nIncludeCommon &= ~CCAFlags::Dropdown;
+ }
+
+ //= OFormExport
+ OFormExport::OFormExport(IFormsExportContext& _rContext, const Reference< XPropertySet >& _rxForm,
+ const Sequence< ScriptEventDescriptor >& _rEvents)
+ :OElementExport(_rContext, _rxForm, _rEvents)
+ ,m_bCreateConnectionResourceElement(false)
+ {
+ OSL_ENSURE(m_xProps.is(), "OFormExport::OFormExport: invalid arguments!");
+ }
+
+ const char* OFormExport::getXMLElementName() const
+ {
+ return "form";
+ }
+
+ void OFormExport::exportSubTags()
+ {
+ if ( m_bCreateConnectionResourceElement && m_xProps.is() )
+ {
+ m_rContext.getGlobalContext().ClearAttrList();
+ OUString sPropValue;
+ m_xProps->getPropertyValue( PROPERTY_DATASOURCENAME ) >>= sPropValue; // if set it is a file url
+ if ( sPropValue.isEmpty() )
+ m_xProps->getPropertyValue( PROPERTY_URL ) >>= sPropValue;
+ if ( !sPropValue.isEmpty() )
+ AddAttribute(
+ OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::TargetLocation),
+ OAttributeMetaData::getCommonControlAttributeName(CCAFlags::TargetLocation),
+ m_rContext.getGlobalContext().GetRelativeReference(sPropValue));
+ if ( m_rContext.getGlobalContext().GetAttrList().getLength() )
+ {
+ SvXMLElementExport aFormElement(m_rContext.getGlobalContext(), XML_NAMESPACE_FORM, xmloff::token::XML_CONNECTION_RESOURCE, true, true);
+ }
+ }
+
+ // let the base class export the remaining properties and the events
+ OElementExport::exportSubTags();
+ // loop through all children
+ Reference< XIndexAccess > xCollection(m_xProps, UNO_QUERY);
+ OSL_ENSURE(xCollection.is(), "OFormLayerXMLExport::implExportForm: a form which is not an index access? Suspicious!");
+
+ if (xCollection.is())
+ m_rContext.exportCollectionElements(xCollection);
+ }
+
+ void OFormExport::exportAttributes()
+ {
+ sal_Int32 i=0;
+
+ // the string properties
+ {
+ static const FormAttributes eStringPropertyIds[] =
+ {
+ faName, /*faAction,*/ faCommand, faFilter, faOrder
+ };
+ static const char * aStringPropertyNames[] =
+ {
+ PROPERTY_NAME, /*PROPERTY_TARGETURL,*/ PROPERTY_COMMAND, PROPERTY_FILTER, PROPERTY_ORDER
+ };
+ static const sal_Int32 nIdCount = SAL_N_ELEMENTS(eStringPropertyIds);
+ #if OSL_DEBUG_LEVEL > 0
+ static const sal_Int32 nNameCount = SAL_N_ELEMENTS(aStringPropertyNames);
+ OSL_ENSURE((nIdCount == nNameCount),
+ "OFormExport::exportAttributes: somebody tampered with the maps (1)!");
+ #endif
+ for (i=0; i<nIdCount; ++i)
+ exportStringPropertyAttribute(
+ OAttributeMetaData::getFormAttributeNamespace(eStringPropertyIds[i]),
+ OAttributeMetaData::getFormAttributeName(eStringPropertyIds[i]),
+ OUString::createFromAscii(aStringPropertyNames[i]));
+
+ // #i112082# xlink:type is added as part of exportTargetLocationAttribute
+
+ // now export the data source name or databaselocation or connection resource
+ OUString sPropValue;
+ m_xProps->getPropertyValue( PROPERTY_DATASOURCENAME ) >>= sPropValue;
+ m_bCreateConnectionResourceElement = sPropValue.isEmpty();
+ if ( !m_bCreateConnectionResourceElement )
+ {
+ INetURLObject aURL(sPropValue);
+ m_bCreateConnectionResourceElement = ( aURL.GetProtocol() == INetProtocol::File );
+ if ( !m_bCreateConnectionResourceElement )
+ exportStringPropertyAttribute(
+ OAttributeMetaData::getFormAttributeNamespace(faDatasource),
+ OAttributeMetaData::getFormAttributeName(faDatasource),
+ PROPERTY_DATASOURCENAME);
+ }
+ else
+ exportedProperty(PROPERTY_URL);
+ if ( m_bCreateConnectionResourceElement )
+ exportedProperty(PROPERTY_DATASOURCENAME);
+ }
+
+ // the boolean properties
+ {
+ static const FormAttributes eBooleanPropertyIds[] =
+ {
+ faAllowDeletes, faAllowInserts, faAllowUpdates, faApplyFilter, faEscapeProcessing, faIgnoreResult
+ };
+ static const char * pBooleanPropertyNames[] =
+ {
+ PROPERTY_ALLOWDELETES,
+ PROPERTY_ALLOWINSERTS,
+ PROPERTY_ALLOWUPDATES,
+ PROPERTY_APPLYFILTER,
+ PROPERTY_ESCAPEPROCESSING,
+ PROPERTY_IGNORERESULT
+ };
+ static const BoolAttrFlags nBooleanPropertyAttrFlags[] =
+ {
+ BoolAttrFlags::DefaultTrue, BoolAttrFlags::DefaultTrue, BoolAttrFlags::DefaultTrue, BoolAttrFlags::DefaultFalse, BoolAttrFlags::DefaultTrue, BoolAttrFlags::DefaultFalse
+ };
+ static const sal_Int32 nIdCount = SAL_N_ELEMENTS(eBooleanPropertyIds);
+ #if OSL_DEBUG_LEVEL > 0
+ static const sal_Int32 nNameCount = SAL_N_ELEMENTS(pBooleanPropertyNames);
+ static const sal_Int32 nFlagsCount = SAL_N_ELEMENTS(nBooleanPropertyAttrFlags);
+ OSL_ENSURE((nIdCount == nNameCount) && (nNameCount == nFlagsCount),
+ "OFormExport::exportAttributes: somebody tampered with the maps (2)!");
+ #endif
+ for (i=0; i<nIdCount; ++i)
+ exportBooleanPropertyAttribute(
+ OAttributeMetaData::getFormAttributeNamespace(eBooleanPropertyIds[i]),
+ OAttributeMetaData::getFormAttributeName(eBooleanPropertyIds[i]),
+ OUString::createFromAscii(pBooleanPropertyNames[i]),
+ nBooleanPropertyAttrFlags[i]
+ );
+ }
+
+ // the enum properties
+ {
+ exportEnumPropertyAttribute(
+ OAttributeMetaData::getFormAttributeNamespace(faEnctype),
+ OAttributeMetaData::getFormAttributeName(faEnctype),
+ PROPERTY_SUBMIT_ENCODING,
+ aSubmitEncodingMap,
+ FormSubmitEncoding_URL,
+ false
+ );
+ exportEnumPropertyAttribute(
+ OAttributeMetaData::getFormAttributeNamespace(faMethod),
+ OAttributeMetaData::getFormAttributeName(faMethod),
+ PROPERTY_SUBMIT_METHOD,
+ aSubmitMethodMap,
+ FormSubmitMethod_GET,
+ false
+ );
+ exportEnumPropertyAttribute(
+ OAttributeMetaData::getFormAttributeNamespace(faCommandType),
+ OAttributeMetaData::getFormAttributeName(faCommandType),
+ PROPERTY_COMMAND_TYPE,
+ aCommandTypeMap,
+ CommandType::COMMAND,
+ false
+ );
+ exportEnumPropertyAttribute(
+ OAttributeMetaData::getFormAttributeNamespace(faNavigationMode),
+ OAttributeMetaData::getFormAttributeName(faNavigationMode),
+ PROPERTY_NAVIGATION,
+ aNavigationTypeMap,
+ NavigationBarMode_CURRENT,
+ false
+ );
+ exportEnumPropertyAttribute(
+ OAttributeMetaData::getFormAttributeNamespace(faTabbingCycle),
+ OAttributeMetaData::getFormAttributeName(faTabbingCycle),
+ PROPERTY_CYCLE,
+ aTabulatorCycleMap,
+ TabulatorCycle_RECORDS,
+ true
+ );
+ }
+
+ // the service name
+ exportServiceNameAttribute();
+ // the target frame
+ exportTargetFrameAttribute();
+ // the target URL
+ exportTargetLocationAttribute(true); // #i110911# add type attribute (for form, but not for control)
+
+ // master fields
+ exportStringSequenceAttribute(
+ OAttributeMetaData::getFormAttributeNamespace(faMasterFields),
+ OAttributeMetaData::getFormAttributeName(faMasterFields),
+ PROPERTY_MASTERFIELDS);
+ // detail fields
+ exportStringSequenceAttribute(
+ OAttributeMetaData::getFormAttributeNamespace(faDetailFields),
+ OAttributeMetaData::getFormAttributeName(faDetailFields),
+ PROPERTY_DETAILFIELDS);
+ }
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/elementexport.hxx b/xmloff/source/forms/elementexport.hxx
new file mode 100644
index 000000000..deb9cfea6
--- /dev/null
+++ b/xmloff/source/forms/elementexport.hxx
@@ -0,0 +1,311 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <memory>
+#include <o3tl/sorted_vector.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/script/ScriptEventDescriptor.hpp>
+#include <xmloff/xmlexp.hxx>
+#include "propertyexport.hxx"
+#include "callbacks.hxx"
+#include "controlelement.hxx"
+#include "valueproperties.hxx"
+
+class SvXMLElementExport;
+namespace xmloff
+{
+
+ //= OElementExport
+ class OElementExport : public OPropertyExport
+ {
+ protected:
+ css::uno::Sequence< css::script::ScriptEventDescriptor >
+ m_aEvents;
+
+ std::unique_ptr<SvXMLElementExport> m_pXMLElement; // XML element doing the concrete startElement etc.
+
+ public:
+ OElementExport(IFormsExportContext& _rContext,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxProps,
+ const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents);
+ virtual ~OElementExport();
+
+ void doExport();
+
+ protected:
+ /// get the name of the XML element
+ virtual const char* getXMLElementName() const = 0;
+ /// examine the element we're exporting
+ virtual void examine();
+ /// export the attributes
+ virtual void exportAttributes();
+ /// export any sub tags
+ virtual void exportSubTags();
+
+ /** exports the events (as script:events tag)
+ */
+ void exportEvents();
+
+ /** add the service-name attribute to the export context
+ */
+ virtual void exportServiceNameAttribute();
+
+ /// start the XML element
+ virtual void implStartElement(const char* _pName);
+
+ /// ends the XML element
+ virtual void implEndElement();
+ };
+
+ //= OControlExport
+ /** Helper class for handling xml elements representing a form control
+ */
+ class OControlExport
+ :public OControlElement
+ ,public OValuePropertiesMetaData
+ ,public OElementExport
+ {
+ protected:
+ typedef o3tl::sorted_vector<sal_Int16> Int16Set;
+ // used below
+
+ OUString m_sControlId; // the control id to use when exporting
+ OUString m_sReferringControls; // list of referring controls (i.e. their id's)
+ sal_Int16 m_nClassId; // class id of the control we're representing
+ ElementType m_eType; // (XML) type of the control we're representing
+ CCAFlags m_nIncludeCommon; // common control attributes to include
+ DAFlags m_nIncludeDatabase; // common database attributes to include
+ SCAFlags m_nIncludeSpecial; // special attributes to include
+ EAFlags m_nIncludeEvents; // events to include
+ BAFlags m_nIncludeBindings; // binding attributes to include
+
+ std::unique_ptr<SvXMLElementExport> m_pOuterElement; // XML element doing the concrete startElement etc. for the outer element
+
+ public:
+ /** constructs an object capable of exporting controls
+
+ <p>You need at least two pre-requisites from outside: The control to be exported needs to have a class id
+ assigned, and you need the list control-ids of all the controls referring to this one as LabelControl.<br/>
+ This information can't be collected when known only the control itself and not it's complete context.</p>
+
+ @param _rControlId
+ the control id to use when exporting the control
+ @param _rReferringControls
+ the comma-separated list of control-ids of all the controls referring to this one as LabelControl
+ */
+ OControlExport(IFormsExportContext& _rContext,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControl,
+ const OUString& _rControlId,
+ const OUString& _rReferringControls,
+ const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rxEvents);
+
+ protected:
+ /// start the XML element
+ virtual void implStartElement(const char* _pName) override;
+
+ /// ends the XML element
+ virtual void implEndElement() override;
+
+ /// get the name of the outer XML element
+ virtual const char* getOuterXMLElementName() const;
+
+ // get the name of the XML element
+ virtual const char* getXMLElementName() const override;
+
+ /** examine the control. Some kind of CtorImpl.
+ */
+ virtual void examine() override;
+
+ /// exports the attributes for the outer element
+ void exportOuterAttributes();
+
+ /// exports the attributes for the inner element
+ void exportInnerAttributes();
+
+ /// export the attributes
+ virtual void exportAttributes() override;
+
+ /** writes everything which needs to be represented as sub tag
+ */
+ void exportSubTags() override;
+
+ /** adds the attributes which are handled via generic IPropertyHandlers
+
+ <p>In the future, this really should be *all* attributes, instead of this shitload of
+ hand-crafted code we have currently...</p>
+ */
+ void exportGenericHandlerAttributes();
+
+ /** adds common control attributes to the XMLExport context given
+
+ <p>The attribute list of the context is not cleared initially, this is the responsibility of the caller.</p>
+ */
+ void exportCommonControlAttributes();
+
+ /** adds database attributes to the XMLExport context given
+
+ <p>The attribute list of the context is not cleared initially, this is the responsibility of the caller.</p>
+ */
+ void exportDatabaseAttributes();
+
+ /** adds the XML attributes which are related to binding controls to
+ external values and/or list sources
+ */
+ void exportBindingAttributes();
+
+ /** adds attributes which are special to a control type to the export context's attribute list
+ */
+ void exportSpecialAttributes();
+
+ /** exports the ListSource property of a control as attribute
+
+ The ListSource property may be exported in different ways: For a ComboBox, it is an attribute
+ of the form:combobox element.
+
+ For a ListBox, it's an attribute if the ListSourceType states that the ListBox does <em>not</em>
+ display a value list. In case of a value list, the ListSource is not exported, and the pairs of
+ StringItem/ValueItem are exported as sub-elements.
+
+ This method does the attribute part: It exports the ListSource property as attribute, not caring
+ about whether the object is a ComboBox or a ListBox.
+ */
+ void exportListSourceAsAttribute();
+
+ /** exports the ListSource property of a control as XML elements
+
+ @see exportListSourceAsAttribute
+ */
+ void exportListSourceAsElements();
+
+ /** gets a Sequence&lt; sal_Int16 &gt; property value as set of sal_Int16's
+ @param _rPropertyName
+ the property name to use
+ @param _rOut
+ out parameter. The set of integers.
+ */
+ void getSequenceInt16PropertyAsSet(const OUString& _rPropertyName, Int16Set& _rOut);
+
+ /** exports the attribute which descrives a cell value binding of a control
+ in a spreadsheet document
+ */
+ void exportCellBindingAttributes( bool _bIncludeListLinkageType );
+
+ /** exports the attribute(s) which bind this control to XForms */
+ void exportXFormsBindAttributes();
+
+ /** exports the attribute(s) which bind the list of a list
+ control to XForms */
+ void exportXFormsListAttributes();
+
+ /** exports the attribute(s) for an XForms submission */
+ void exportXFormsSubmissionAttributes();
+
+ /** exports the attribute which descrives a cell range which acts as list source for
+ a list-like control
+ */
+ void exportCellListSourceRange( );
+
+ /** exports the attribute(s) for the ImagePosition property
+ */
+ void exportImagePositionAttributes();
+
+ /** determines whether the control we're exporting has an active data binding.
+
+ Bindings which count here are:
+ <ul><li>an established connection to a database field</li>
+ <li>a binding to an external value supplier (<type scope="css::form::binding">XValueBinding</type>)</li>
+ </ul>
+ */
+ bool controlHasActiveDataBinding() const;
+
+ /** retrieves the string specifying the ListSource of a list or combo box
+ */
+ OUString getScalarListSourceValue() const;
+
+ /** determines whether the list entries (of a combo or list box) are supplied by the user
+
+ List entries may be
+ <ul><li>specified by the user</li>
+ <li>specified by an external list source (<type scope="css::form::binding">XListEntrySource</type>)</li>
+ <li>obtained from a database query (in various ways)</li>
+ </ul>
+
+ In the latter two cases, this method will return <FALSE/>
+ */
+ bool controlHasUserSuppliedListEntries() const;
+ };
+
+ //= OColumnExport
+ /** Helper class for exporting a grid column
+ */
+ class OColumnExport : public OControlExport
+ {
+ public:
+ /** ctor
+ @see OColumnExport::OColumnExport
+ */
+ OColumnExport(IFormsExportContext& _rContext,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControl,
+ const OUString& _rControlId,
+ const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rxEvents);
+
+ virtual ~OColumnExport() override;
+
+ protected:
+ // OControlExport overridables
+ virtual const char* getOuterXMLElementName() const override;
+ virtual void exportServiceNameAttribute() override;
+ virtual void exportAttributes() override;
+
+ // OElementExport overridables
+ virtual void examine() override;
+ };
+
+ //= OFormExport
+ /** Helper class for handling xml elements representing a form
+
+ <p>In opposite to the class <type>OControlExport</type>, OFormExport is unable to export a <em>complete</em>
+ form. Instead the client has to care for sub elements of the form itself.</p>
+ */
+ class OFormExport
+ :public OControlElement
+ ,public OElementExport
+ {
+ bool m_bCreateConnectionResourceElement;
+ public:
+ /** constructs an object capable of exporting controls
+ */
+ OFormExport(IFormsExportContext& _rContext,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxForm,
+ const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rxEvents
+ );
+
+ protected:
+ virtual const char* getXMLElementName() const override;
+ virtual void exportSubTags() override;
+ virtual void exportAttributes() override;
+ };
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/elementimport.cxx b/xmloff/source/forms/elementimport.cxx
new file mode 100644
index 000000000..19f247aae
--- /dev/null
+++ b/xmloff/source/forms/elementimport.cxx
@@ -0,0 +1,2073 @@
+/* -*- 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 "elementimport.hxx"
+#include <xmloff/xmlimp.hxx>
+#include <xmloff/namespacemap.hxx>
+#include "strings.hxx"
+#include "callbacks.hxx"
+#include <xmloff/xmlnamespace.hxx>
+#include "eventimport.hxx"
+#include <xmloff/txtstyli.hxx>
+#include "formenums.hxx"
+#include <xmloff/xmltoken.hxx>
+#include "gridcolumnproptranslator.hxx"
+#include "property_description.hxx"
+#include "property_meta_data.hxx"
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/util/XCloneable.hpp>
+#include <com/sun/star/util/Duration.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/awt/ImagePosition.hpp>
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyContainer.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+#include <sax/tools/converter.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/diagnose_ex.h>
+#include <rtl/strbuf.hxx>
+#include <sal/log.hxx>
+#include <comphelper/extract.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/sequence.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <algorithm>
+
+namespace xmloff
+{
+
+ using namespace ::xmloff::token;
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::xml;
+ using namespace ::com::sun::star::xml::sax;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::text;
+ using namespace ::comphelper;
+ using ::com::sun::star::xml::sax::XAttributeList;
+
+#define PROPID_VALUE 1
+#define PROPID_CURRENT_VALUE 2
+#define PROPID_MIN_VALUE 3
+#define PROPID_MAX_VALUE 4
+
+ namespace {
+
+ struct PropertyValueLess
+ {
+ bool operator()(const PropertyValue& _rLeft, const PropertyValue& _rRight)
+ {
+ return _rLeft.Name < _rRight.Name;
+ }
+ };
+
+ }
+
+ //= OElementNameMap
+ std::map<sal_Int32, OControlElement::ElementType> OElementNameMap::s_sElementTranslations2;
+
+ const OControlElement::ElementType& operator ++(OControlElement::ElementType& _e)
+ {
+ OControlElement::ElementType e = _e;
+ sal_Int32 nAsInt = static_cast<sal_Int32>(e);
+ _e = static_cast<OControlElement::ElementType>( ++nAsInt );
+ return _e;
+ }
+
+ OControlElement::ElementType OElementNameMap::getElementType(sal_Int32 nElement)
+ {
+ if ( s_sElementTranslations2.empty() )
+ { // initialize
+ for (ElementType eType=ElementType(0); eType<UNKNOWN; ++eType)
+ s_sElementTranslations2[getElementToken(eType)] = eType;
+ }
+ auto aPos = s_sElementTranslations2.find(nElement & TOKEN_MASK);
+ if (s_sElementTranslations2.end() != aPos)
+ return aPos->second;
+
+ return UNKNOWN;
+ }
+
+ //= OElementImport
+ OElementImport::OElementImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const Reference< XNameContainer >& _rxParentContainer)
+ :OPropertyImport(_rImport)
+ ,m_rFormImport(_rImport)
+ ,m_rEventManager(_rEventManager)
+ ,m_pStyleElement( nullptr )
+ ,m_xParentContainer(_rxParentContainer)
+ ,m_bImplicitGenericAttributeHandling( true )
+ {
+ OSL_ENSURE(m_xParentContainer.is(), "OElementImport::OElementImport: invalid parent container!");
+ }
+
+ OElementImport::~OElementImport()
+ {
+ }
+
+ OUString OElementImport::determineDefaultServiceName() const
+ {
+ return OUString();
+ }
+
+ void OElementImport::startFastElement(sal_Int32 nElement, const Reference< css::xml::sax::XFastAttributeList >& _rxAttrList)
+ {
+ ENTER_LOG_CONTEXT( "xmloff::OElementImport - importing one element" );
+
+ const OUString sControlImplementation = _rxAttrList->getOptionalValue( XML_ELEMENT(FORM, XML_CONTROL_IMPLEMENTATION) );
+
+ // retrieve the service name
+ if ( !sControlImplementation.isEmpty() )
+ {
+ OUString sOOoImplementationName;
+ const sal_uInt16 nImplPrefix = GetImport().GetNamespaceMap().GetKeyByAttrValueQName( sControlImplementation, &sOOoImplementationName );
+ m_sServiceName = ( nImplPrefix == XML_NAMESPACE_OOO ) ? sOOoImplementationName : sControlImplementation;
+ }
+
+ if ( m_sServiceName.isEmpty() )
+ m_sServiceName = determineDefaultServiceName();
+
+ // create the object *now*. This allows setting properties in the various handleAttribute methods.
+ // (Though currently not all code is migrated to this pattern, most attributes are still handled
+ // by remembering the value (via implPushBackPropertyValue), and setting the correct property value
+ // later (in OControlImport::StartElement).)
+ m_xElement = createElement();
+ if ( m_xElement.is() )
+ m_xInfo = m_xElement->getPropertySetInfo();
+
+ // call the base class
+ OPropertyImport::startFastElement( nElement, _rxAttrList );
+ }
+
+ css::uno::Reference< css::xml::sax::XFastContextHandler > OElementImport::createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList )
+ {
+ if( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) )
+ return new OFormEventsImportContext(m_rFormImport.getGlobalContext(), *this);
+
+ return OPropertyImport::createFastChildContext(nElement, _rxAttrList);
+ }
+
+ void OElementImport::endFastElement(sal_Int32 )
+ {
+ OSL_ENSURE(m_xElement.is(), "OElementImport::EndElement: invalid element created!");
+ if (!m_xElement.is())
+ return;
+
+ // apply the non-generic properties
+ implApplySpecificProperties();
+
+ // set the generic properties
+ implApplyGenericProperties();
+
+ // set the style properties
+ if ( m_pStyleElement && m_xElement.is() )
+ {
+ Reference< XPropertySet > xPropTranslation =
+ new OGridColumnPropertyTranslator( Reference< XMultiPropertySet >( m_xElement, UNO_QUERY ) );
+ const_cast< XMLTextStyleContext* >( m_pStyleElement )->FillPropertySet( xPropTranslation );
+
+ const OUString sNumberStyleName = m_pStyleElement->GetDataStyleName( );
+ if ( !sNumberStyleName.isEmpty() )
+ // the style also has a number (sub) style
+ m_rContext.applyControlNumberStyle( m_xElement, sNumberStyleName );
+ }
+
+ // insert the element into the parent container
+ if (m_sName.isEmpty())
+ {
+ OSL_FAIL("OElementImport::EndElement: did not find a name attribute!");
+ m_sName = implGetDefaultName();
+ }
+
+ if (m_xParentContainer.is())
+ m_xParentContainer->insertByName(m_sName, Any(m_xElement));
+
+ LEAVE_LOG_CONTEXT( );
+ }
+
+ void OElementImport::implApplySpecificProperties()
+ {
+ if ( m_aValues.empty() )
+ return;
+
+ // set all the properties we collected
+#if OSL_DEBUG_LEVEL > 0
+ // check if the object has all the properties
+ // (We do this in the non-pro version only. Doing it all the time would be too much expensive)
+ if ( m_xInfo.is() )
+ {
+ for ( const auto& rCheck : m_aValues )
+ {
+ OSL_ENSURE(m_xInfo->hasPropertyByName(rCheck.Name),
+ OStringBuffer("OElementImport::implApplySpecificProperties: read a property (" +
+ OUStringToOString(rCheck.Name, RTL_TEXTENCODING_ASCII_US) +
+ ") which does not exist on the element!").getStr());
+ }
+ }
+#endif
+
+ // set the properties
+ const Reference< XMultiPropertySet > xMultiProps(m_xElement, UNO_QUERY);
+ bool bSuccess = false;
+ if (xMultiProps.is())
+ {
+ // translate our properties so that the XMultiPropertySet can handle them
+
+ // sort our property value array so that we can use it in a setPropertyValues
+ ::std::sort( m_aValues.begin(), m_aValues.end(), PropertyValueLess());
+
+ // the names
+ Sequence< OUString > aNames(m_aValues.size());
+ OUString* pNames = aNames.getArray();
+ // the values
+ Sequence< Any > aValues(m_aValues.size());
+ Any* pValues = aValues.getArray();
+ // copy
+
+ for ( const auto& rPropValues : m_aValues )
+ {
+ *pNames = rPropValues.Name;
+ *pValues = rPropValues.Value;
+ ++pNames;
+ ++pValues;
+ }
+
+ try
+ {
+ xMultiProps->setPropertyValues(aNames, aValues);
+ bSuccess = true;
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("xmloff.forms");
+ OSL_FAIL("OElementImport::implApplySpecificProperties: could not set the properties (using the XMultiPropertySet)!");
+ }
+ }
+
+ if (bSuccess)
+ return;
+
+ // no XMultiPropertySet or setting all properties at once failed
+ for ( const auto& rPropValues : m_aValues )
+ {
+ // this try/catch here is expensive, but because this is just a fallback which should normally not be
+ // used it's acceptable this way ...
+ try
+ {
+ m_xElement->setPropertyValue(rPropValues.Name, rPropValues.Value);
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("xmloff.forms");
+ OSL_FAIL(OStringBuffer("OElementImport::implApplySpecificProperties: could not set the property \"" +
+ OUStringToOString(rPropValues.Name, RTL_TEXTENCODING_ASCII_US) +
+ "\"!").getStr());
+ }
+ }
+ }
+
+ void OElementImport::implApplyGenericProperties()
+ {
+ if ( m_aGenericValues.empty() )
+ return;
+
+ Reference< XPropertyContainer > xDynamicProperties( m_xElement, UNO_QUERY );
+
+ // PropertyValueArray::iterator aEnd = m_aGenericValues.end();
+ for ( auto& rPropValues : m_aGenericValues )
+ {
+ // check property type for numeric types before setting
+ // the property
+ try
+ {
+ // if such a property does not yet exist at the element, create it if necessary
+ const bool bExistentProperty = m_xInfo->hasPropertyByName( rPropValues.Name );
+ if ( !bExistentProperty )
+ {
+ if ( !xDynamicProperties.is() )
+ {
+ SAL_WARN( "xmloff", "OElementImport::implApplyGenericProperties: encountered an unknown property ("
+ << rPropValues.Name << "), but component is no PropertyBag!");
+ continue;
+ }
+
+ xDynamicProperties->addProperty(
+ rPropValues.Name,
+ PropertyAttribute::BOUND | PropertyAttribute::REMOVABLE,
+ rPropValues.Value
+ );
+
+ // re-fetch the PropertySetInfo
+ m_xInfo = m_xElement->getPropertySetInfo();
+ }
+
+ // determine the type of the value (source for the following conversion)
+ TypeClass eValueTypeClass = rPropValues.Value.getValueTypeClass();
+ const bool bValueIsSequence = TypeClass_SEQUENCE == eValueTypeClass;
+ if ( bValueIsSequence )
+ {
+ uno::Type aSimpleType( getSequenceElementType( rPropValues.Value.getValueType() ) );
+ eValueTypeClass = aSimpleType.getTypeClass();
+ }
+
+ // determine the type of the property (target for the following conversion)
+ const Property aProperty( m_xInfo->getPropertyByName( rPropValues.Name ) );
+ TypeClass ePropTypeClass = aProperty.Type.getTypeClass();
+ const bool bPropIsSequence = TypeClass_SEQUENCE == ePropTypeClass;
+ if( bPropIsSequence )
+ {
+ uno::Type aSimpleType( ::comphelper::getSequenceElementType( aProperty.Type ) );
+ ePropTypeClass = aSimpleType.getTypeClass();
+ }
+
+ if ( bPropIsSequence != bValueIsSequence )
+ {
+ OSL_FAIL( "OElementImport::implImportGenericProperties: either both value and property should be a sequence, or none of them!" );
+ continue;
+ }
+
+ if ( bValueIsSequence )
+ {
+ Sequence< Any > aXMLValueList;
+ rPropValues.Value >>= aXMLValueList;
+ // just skip this part if empty sequence
+ if (!aXMLValueList.getLength())
+ continue;
+
+ Sequence< sal_Int16 > aPropertyValueList( aXMLValueList.getLength() );
+
+ SAL_WARN_IF( eValueTypeClass != TypeClass_ANY, "xmloff",
+ "OElementImport::implApplyGenericProperties: only ANYs should have been imported as generic list property!" );
+ // (OPropertyImport should produce only Sequencer< Any >, since it cannot know the real type
+
+ SAL_WARN_IF( ePropTypeClass != TypeClass_SHORT, "xmloff",
+ "OElementImport::implApplyGenericProperties: conversion to sequences other than 'sequence< short >' not implemented, yet!" );
+
+
+ std::transform(std::cbegin(aXMLValueList), std::cend(aXMLValueList), aPropertyValueList.getArray(),
+ [](const Any& rXMLValue) -> sal_Int16 {
+ // only value sequences of numeric types implemented so far.
+ double nVal( 0 );
+ OSL_VERIFY( rXMLValue >>= nVal );
+ return static_cast< sal_Int16 >( nVal );
+ });
+
+ rPropValues.Value <<= aPropertyValueList;
+ }
+ else if ( ePropTypeClass != eValueTypeClass )
+ {
+ switch ( eValueTypeClass )
+ {
+ case TypeClass_DOUBLE:
+ {
+ double nVal = 0;
+ rPropValues.Value >>= nVal;
+ switch( ePropTypeClass )
+ {
+ case TypeClass_BYTE:
+ rPropValues.Value <<= static_cast< sal_Int8 >( nVal );
+ break;
+ case TypeClass_SHORT:
+ rPropValues.Value <<= static_cast< sal_Int16 >( nVal );
+ break;
+ case TypeClass_UNSIGNED_SHORT:
+ rPropValues.Value <<= static_cast< sal_uInt16 >( nVal );
+ break;
+ case TypeClass_LONG:
+ case TypeClass_ENUM:
+ rPropValues.Value <<= static_cast< sal_Int32 >( nVal );
+ break;
+ case TypeClass_UNSIGNED_LONG:
+ rPropValues.Value <<= static_cast< sal_uInt32 >( nVal );
+ break;
+ case TypeClass_UNSIGNED_HYPER:
+ rPropValues.Value <<= static_cast< sal_uInt64 >( nVal );
+ break;
+ case TypeClass_HYPER:
+ rPropValues.Value <<= static_cast< sal_Int64 >( nVal );
+ break;
+ default:
+ OSL_FAIL( "OElementImport::implImportGenericProperties: unsupported value type!" );
+ break;
+ }
+ }
+ break;
+ default:
+ OSL_FAIL( "OElementImport::implImportGenericProperties: non-double values not supported!" );
+ break;
+ }
+ }
+
+ m_xElement->setPropertyValue( rPropValues.Name, rPropValues.Value );
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("xmloff.forms");
+ OSL_FAIL(OStringBuffer("OElementImport::EndElement: could not set the property \"" +
+ OUStringToOString(rPropValues.Name, RTL_TEXTENCODING_ASCII_US) +
+ "\"!").getStr());
+ }
+ }
+ }
+
+ OUString OElementImport::implGetDefaultName() const
+ {
+ // no optimization here. If this method gets called, the XML stream did not contain a name for the
+ // element, which is a heavy error. So in this case we don't care for performance
+ static constexpr OUStringLiteral sUnnamedName = u"unnamed";
+ OSL_ENSURE(m_xParentContainer.is(), "OElementImport::implGetDefaultName: no parent container!");
+ if (!m_xParentContainer.is())
+ return sUnnamedName;
+ Sequence< OUString > aNames = m_xParentContainer->getElementNames();
+
+ for (sal_Int32 i=0; i<32768; ++i) // the limit is nearly arbitrary...
+ {
+ // assemble the new name (suggestion)
+ OUString sReturn = sUnnamedName + OUString::number(i);
+ // check the existence (this is the bad performance part...)
+ if (comphelper::findValue(aNames, sReturn) == -1)
+ // not found the name
+ return sReturn;
+ }
+ OSL_FAIL("OElementImport::implGetDefaultName: did not find a free name!");
+ return sUnnamedName;
+ }
+
+ PropertyGroups::const_iterator OElementImport::impl_matchPropertyGroup( const PropertyGroups& i_propertyGroups ) const
+ {
+ ENSURE_OR_RETURN( m_xInfo.is(), "OElementImport::impl_matchPropertyGroup: no property set info!", i_propertyGroups.end() );
+
+ return std::find_if(i_propertyGroups.cbegin(), i_propertyGroups.cend(), [&](const PropertyDescriptionList& rGroup) {
+ return std::all_of(rGroup.cbegin(), rGroup.cend(), [&](const PropertyDescription* prop) {
+ return m_xInfo->hasPropertyByName( prop->propertyName );
+ });
+ });
+ }
+
+ bool OElementImport::tryGenericAttribute( sal_Int32 nElement, const OUString& _rValue )
+ {
+ // the generic approach (which I hope all props will be migrated to, on the medium term): property handlers
+ const AttributeDescription attribute( metadata::getAttributeDescription( nElement ) );
+ if ( attribute.attributeToken != XML_TOKEN_INVALID )
+ {
+ PropertyGroups propertyGroups;
+ metadata::getPropertyGroupList( attribute, propertyGroups );
+ const PropertyGroups::const_iterator pos = impl_matchPropertyGroup( propertyGroups );
+ if ( pos == propertyGroups.end() )
+ return false;
+
+ do
+ {
+ const PropertyDescriptionList& rProperties( *pos );
+ const PropertyDescription* first = *rProperties.begin();
+ if ( !first )
+ {
+ SAL_WARN( "xmloff.forms", "OElementImport::handleAttribute: invalid property description!" );
+ break;
+ }
+
+ const PPropertyHandler handler = (*first->factory)( first->propertyId );
+ if ( !handler )
+ {
+ SAL_WARN( "xmloff.forms", "OElementImport::handleAttribute: invalid property handler!" );
+ break;
+ }
+
+ PropertyValues aValues;
+ for ( const auto& propDesc : rProperties )
+ {
+ aValues[ propDesc->propertyId ] = Any();
+ }
+ if ( handler->getPropertyValues( _rValue, aValues ) )
+ {
+ for ( const auto& propDesc : rProperties )
+ {
+ implPushBackPropertyValue( propDesc->propertyName, aValues[ propDesc->propertyId ] );
+ }
+ }
+ }
+ while ( false );
+
+ // handled
+ return true;
+ }
+ return false;
+ }
+
+ bool OElementImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue)
+ {
+ auto nLocal = nElement & TOKEN_MASK;
+ if ( nLocal == XML_CONTROL_IMPLEMENTATION )
+ // ignore this, it has already been handled in OElementImport::StartElement
+ return true;
+
+ if ( nLocal == XML_NAME )
+ {
+ if ( m_sName.isEmpty() )
+ // remember the name for later use in EndElement
+ m_sName = _rValue;
+ return true;
+ }
+
+ // maybe it's the style attribute?
+ if ( nLocal == XML_TEXT_STYLE_NAME )
+ {
+ const SvXMLStyleContext* pStyleContext = m_rContext.getStyleElement( _rValue );
+ OSL_ENSURE( pStyleContext, "OElementImport::handleAttribute: do not know the style!" );
+ // remember the element for later usage.
+ m_pStyleElement = dynamic_cast<const XMLTextStyleContext*>( pStyleContext );
+ return true;
+ }
+
+ if ( m_bImplicitGenericAttributeHandling )
+ if ( tryGenericAttribute( nElement, _rValue ) )
+ return true;
+
+ // let the base class handle it
+ return OPropertyImport::handleAttribute( nElement, _rValue);
+ }
+
+ Reference< XPropertySet > OElementImport::createElement()
+ {
+ Reference< XPropertySet > xReturn;
+ if (!m_sServiceName.isEmpty())
+ {
+ Reference< XComponentContext > xContext = m_rFormImport.getGlobalContext().GetComponentContext();
+ Reference< XInterface > xPure = xContext->getServiceManager()->createInstanceWithContext(m_sServiceName, xContext);
+ OSL_ENSURE(xPure.is(),
+ OStringBuffer("OElementImport::createElement: service factory gave me no object (service name: " +
+ OUStringToOString(m_sServiceName, RTL_TEXTENCODING_ASCII_US) +
+ ")!").getStr());
+ xReturn.set(xPure, UNO_QUERY);
+ }
+ else
+ OSL_FAIL("OElementImport::createElement: no service name to create an element!");
+
+ return xReturn;
+ }
+
+ void OElementImport::registerEvents(const Sequence< ScriptEventDescriptor >& _rEvents)
+ {
+ OSL_ENSURE(m_xElement.is(), "OElementImport::registerEvents: no element to register events for!");
+ m_rEventManager.registerEvents(m_xElement, _rEvents);
+ }
+
+ void OElementImport::simulateDefaultedAttribute(sal_Int32 nElement, const OUString& _rPropertyName, const char* _pAttributeDefault)
+ {
+ OSL_ENSURE( m_xInfo.is(), "OPropertyImport::simulateDefaultedAttribute: the component should be more gossipy about it's properties!" );
+
+ if ( !m_xInfo.is() || m_xInfo->hasPropertyByName( _rPropertyName ) )
+ {
+ if ( !encounteredAttribute( nElement ) )
+ OSL_VERIFY( handleAttribute( XML_ELEMENT(FORM, (nElement & TOKEN_MASK)), OUString::createFromAscii( _pAttributeDefault ) ) );
+ }
+ }
+
+ //= OControlImport
+ OControlImport::OControlImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const Reference< XNameContainer >& _rxParentContainer)
+ :OElementImport(_rImport, _rEventManager, _rxParentContainer)
+ ,m_eElementType(OControlElement::UNKNOWN)
+ {
+ disableImplicitGenericAttributeHandling();
+ }
+
+ OControlImport::OControlImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const Reference< XNameContainer >& _rxParentContainer, OControlElement::ElementType _eType)
+ :OElementImport(_rImport, _rEventManager, _rxParentContainer)
+ ,m_eElementType(_eType)
+ {
+ disableImplicitGenericAttributeHandling();
+ }
+
+ OUString OControlImport::determineDefaultServiceName() const
+ {
+ const char* pServiceName = nullptr;
+ switch ( m_eElementType )
+ {
+ case OControlElement::TEXT:
+ case OControlElement::TEXT_AREA:
+ case OControlElement::PASSWORD: pServiceName = "com.sun.star.form.component.TextField"; break;
+ case OControlElement::FILE: pServiceName = "com.sun.star.form.component.FileControl"; break;
+ case OControlElement::FORMATTED_TEXT: pServiceName = "com.sun.star.form.component.FormattedField"; break;
+ case OControlElement::FIXED_TEXT: pServiceName = "com.sun.star.form.component.FixedText"; break;
+ case OControlElement::COMBOBOX: pServiceName = "com.sun.star.form.component.ComboBox"; break;
+ case OControlElement::LISTBOX: pServiceName = "com.sun.star.form.component.ListBox"; break;
+ case OControlElement::BUTTON: pServiceName = "com.sun.star.form.component.CommandButton"; break;
+ case OControlElement::IMAGE: pServiceName = "com.sun.star.form.component.ImageButton"; break;
+ case OControlElement::CHECKBOX: pServiceName = "com.sun.star.form.component.CheckBox"; break;
+ case OControlElement::RADIO: pServiceName = "com.sun.star.form.component.RadioButton"; break;
+ case OControlElement::FRAME: pServiceName = "com.sun.star.form.component.GroupBox"; break;
+ case OControlElement::IMAGE_FRAME: pServiceName = "com.sun.star.form.component.DatabaseImageControl"; break;
+ case OControlElement::HIDDEN: pServiceName = "com.sun.star.form.component.HiddenControl"; break;
+ case OControlElement::GRID: pServiceName = "com.sun.star.form.component.GridControl"; break;
+ case OControlElement::VALUERANGE: pServiceName = "com.sun.star.form.component.ScrollBar"; break;
+ case OControlElement::TIME: pServiceName = "com.sun.star.form.component.TimeField"; break;
+ case OControlElement::DATE: pServiceName = "com.sun.star.form.component.DateField"; break;
+ default: break;
+ }
+ if ( pServiceName != nullptr )
+ return OUString::createFromAscii( pServiceName );
+ return OUString();
+ }
+
+ void OControlImport::addOuterAttributes(const Reference< XFastAttributeList >& _rxOuterAttribs)
+ {
+ OSL_ENSURE(!m_xOuterAttributes.is(), "OControlImport::addOuterAttributes: already have these attributes!");
+ m_xOuterAttributes = _rxOuterAttribs;
+ }
+
+ bool OControlImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue)
+ {
+ static sal_Int32 nLinkedCellAttributeName = OAttributeMetaData::getBindingAttributeToken(BAFlags::LinkedCell);
+
+ if ((nElement & TOKEN_MASK) == XML_ID)
+ { // it's the control id
+ if (IsTokenInNamespace(nElement, XML_NAMESPACE_XML))
+ {
+ m_sControlId = _rValue;
+ }
+ else if (IsTokenInNamespace(nElement, XML_NAMESPACE_FORM))
+ {
+ if (m_sControlId.isEmpty())
+ {
+ m_sControlId = _rValue;
+ }
+ }
+ return true;
+ }
+
+ if ( (nElement & TOKEN_MASK) == nLinkedCellAttributeName )
+ { // it's the address of a spreadsheet cell
+ m_sBoundCellAddress = _rValue;
+ return true;
+ }
+
+ if ( nElement == XML_ELEMENT(XFORMS, XML_BIND ) )
+ {
+ m_sBindingID = _rValue;
+ return true;
+ }
+
+ if ( nElement == XML_ELEMENT(FORM, XML_XFORMS_LIST_SOURCE) )
+ {
+ m_sListBindingID = _rValue;
+ return true;
+ }
+
+ if ( nElement == XML_ELEMENT(FORM, XML_XFORMS_SUBMISSION)
+ || nElement == XML_ELEMENT(XFORMS, XML_SUBMISSION) )
+ {
+ m_sSubmissionID = _rValue;
+ return true;
+ }
+
+ if ( OElementImport::tryGenericAttribute( nElement, _rValue ) )
+ return true;
+
+ static const sal_Int32 nValueAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Value);
+ static const sal_Int32 nCurrentValueAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::CurrentValue);
+ static const sal_Int32 nMinValueAttributeName = OAttributeMetaData::getSpecialAttributeToken(SCAFlags::MinValue);
+ static const sal_Int32 nMaxValueAttributeName = OAttributeMetaData::getSpecialAttributeToken(SCAFlags::MaxValue);
+ static const sal_Int32 nRepeatDelayAttributeName = OAttributeMetaData::getSpecialAttributeToken( SCAFlags::RepeatDelay );
+
+ sal_Int32 nHandle = -1;
+ if ( (nElement & TOKEN_MASK) == nValueAttributeName )
+ nHandle = PROPID_VALUE;
+ else if ( (nElement & TOKEN_MASK) == nCurrentValueAttributeName )
+ nHandle = PROPID_CURRENT_VALUE;
+ else if ( (nElement & TOKEN_MASK) == nMinValueAttributeName )
+ nHandle = PROPID_MIN_VALUE;
+ else if ( (nElement & TOKEN_MASK) == nMaxValueAttributeName )
+ nHandle = PROPID_MAX_VALUE;
+ if ( nHandle != -1 )
+ {
+ // for the moment, simply remember the name and the value
+ PropertyValue aProp;
+ aProp.Name = SvXMLImport::getNameFromToken(nElement);
+ aProp.Handle = nHandle;
+ aProp.Value <<= _rValue;
+ m_aValueProperties.push_back(aProp);
+ return true;
+ }
+
+ if ( (nElement & TOKEN_MASK) == nRepeatDelayAttributeName )
+ {
+ util::Duration aDuration;
+ if (::sax::Converter::convertDuration(aDuration, _rValue))
+ {
+ PropertyValue aProp;
+ aProp.Name = PROPERTY_REPEAT_DELAY;
+ sal_Int32 const nMS =
+ ((aDuration.Hours * 60 + aDuration.Minutes) * 60
+ + aDuration.Seconds) * 1000 + aDuration.NanoSeconds/1000000;
+ aProp.Value <<= nMS;
+
+ implPushBackPropertyValue(aProp);
+ }
+ return true;
+ }
+
+ return OElementImport::handleAttribute( nElement, _rValue );
+ }
+
+ void OControlImport::startFastElement(sal_Int32 nElement, const Reference< css::xml::sax::XFastAttributeList >& _rxAttrList)
+ {
+ css::uno::Reference< css::xml::sax::XFastAttributeList > xMergedAttributes;
+ if( m_xOuterAttributes.is() )
+ {
+ // merge the attribute lists, our own one
+ rtl::Reference<sax_fastparser::FastAttributeList> xMerger(new sax_fastparser::FastAttributeList(_rxAttrList));
+ // and the ones of our enclosing element
+ xMerger->add(m_xOuterAttributes);
+ xMergedAttributes = xMerger.get();
+ }
+ else
+ {
+ xMergedAttributes = _rxAttrList;
+ }
+
+ // let the base class handle all the attributes
+ OElementImport::startFastElement(nElement, xMergedAttributes);
+
+ if ( m_aValueProperties.empty() || !m_xElement.is())
+ return;
+
+ // get the property set info
+ if (!m_xInfo.is())
+ {
+ OSL_FAIL("OControlImport::StartElement: no PropertySetInfo!");
+ return;
+ }
+
+ const char* pValueProperty = nullptr;
+ const char* pCurrentValueProperty = nullptr;
+ const char* pMinValueProperty = nullptr;
+ const char* pMaxValueProperty = nullptr;
+
+ bool bRetrievedValues = false;
+ bool bRetrievedValueLimits = false;
+
+ // get the class id of our element
+ sal_Int16 nClassId = FormComponentType::CONTROL;
+ m_xElement->getPropertyValue(PROPERTY_CLASSID) >>= nClassId;
+
+ // translate the value properties we collected in handleAttributes
+ for ( auto& rValueProps : m_aValueProperties )
+ {
+ bool bSuccess = false;
+ switch (rValueProps.Handle)
+ {
+ case PROPID_VALUE:
+ case PROPID_CURRENT_VALUE:
+ {
+ // get the property names
+ if (!bRetrievedValues)
+ {
+ getValuePropertyNames(m_eElementType, nClassId, pCurrentValueProperty, pValueProperty);
+ if ( !pCurrentValueProperty && !pValueProperty )
+ {
+ SAL_WARN( "xmloff.forms", "OControlImport::StartElement: illegal value property names!" );
+ break;
+ }
+
+ bRetrievedValues = true;
+ }
+ if ( PROPID_VALUE == rValueProps.Handle && !pValueProperty )
+ {
+ SAL_WARN( "xmloff.forms", "OControlImport::StartElement: the control does not have a value property!");
+ break;
+ }
+
+ if ( PROPID_CURRENT_VALUE == rValueProps.Handle && !pCurrentValueProperty )
+ {
+ SAL_WARN( "xmloff.forms", "OControlImport::StartElement: the control does not have a current-value property!");
+ break;
+ }
+
+ // transfer the name
+ if (PROPID_VALUE == rValueProps.Handle)
+ rValueProps.Name = OUString::createFromAscii(pValueProperty);
+ else
+ rValueProps.Name = OUString::createFromAscii(pCurrentValueProperty);
+ bSuccess = true;
+ }
+ break;
+ case PROPID_MIN_VALUE:
+ case PROPID_MAX_VALUE:
+ {
+ // get the property names
+ if (!bRetrievedValueLimits)
+ {
+ getValueLimitPropertyNames(nClassId, pMinValueProperty, pMaxValueProperty);
+ if ( !pMinValueProperty || !pMaxValueProperty )
+ {
+ SAL_WARN( "xmloff.forms", "OControlImport::StartElement: illegal value limit property names!" );
+ break;
+ }
+
+ bRetrievedValueLimits = true;
+ }
+ OSL_ENSURE((PROPID_MIN_VALUE != rValueProps.Handle) || pMinValueProperty,
+ "OControlImport::StartElement: the control does not have a value property!");
+ OSL_ENSURE((PROPID_MAX_VALUE != rValueProps.Handle) || pMaxValueProperty,
+ "OControlImport::StartElement: the control does not have a current-value property!");
+
+ // transfer the name
+ if (PROPID_MIN_VALUE == rValueProps.Handle)
+ rValueProps.Name = OUString::createFromAscii(pMinValueProperty);
+ else
+ rValueProps.Name = OUString::createFromAscii(pMaxValueProperty);
+ bSuccess = true;
+ }
+ break;
+ }
+
+ if ( !bSuccess )
+ continue;
+
+ // translate the value
+ implTranslateValueProperty(m_xInfo, rValueProps);
+ // add the property to the base class' array
+ implPushBackPropertyValue(rValueProps);
+ }
+
+ }
+
+ void OControlImport::implTranslateValueProperty(const Reference< XPropertySetInfo >& _rxPropInfo,
+ PropertyValue& _rPropValue)
+ {
+ OSL_ENSURE(_rxPropInfo->hasPropertyByName(_rPropValue.Name),
+ "OControlImport::implTranslateValueProperty: invalid property name!");
+
+ // retrieve the type of the property
+ Property aProp = _rxPropInfo->getPropertyByName(_rPropValue.Name);
+ // the untranslated string value as read in handleAttribute
+ OUString sValue;
+ bool bSuccess = _rPropValue.Value >>= sValue;
+ OSL_ENSURE(bSuccess, "OControlImport::implTranslateValueProperty: supposed to be called with non-translated string values!");
+
+ if (TypeClass_ANY == aProp.Type.getTypeClass())
+ {
+ // we have exactly 2 properties where this type class is allowed:
+ SAL_WARN_IF(
+ _rPropValue.Name != PROPERTY_EFFECTIVE_VALUE
+ && _rPropValue.Name != PROPERTY_EFFECTIVE_DEFAULT, "xmloff",
+ "OControlImport::implTranslateValueProperty: invalid property type/name combination, Any and " << _rPropValue.Name);
+
+ // Both properties are allowed to have a double or a string value,
+ // so first try to convert the string into a number
+ double nValue;
+ if (::sax::Converter::convertDouble(nValue, sValue))
+ _rPropValue.Value <<= nValue;
+ else
+ _rPropValue.Value <<= sValue;
+ }
+ else
+ _rPropValue.Value = PropertyConversion::convertString(aProp.Type, sValue);
+ }
+
+ void OControlImport::endFastElement(sal_Int32 nElement)
+ {
+ OSL_ENSURE(m_xElement.is(), "OControlImport::EndElement: invalid control!");
+ if ( !m_xElement.is() )
+ return;
+
+ // register our control with its id
+ if (!m_sControlId.isEmpty())
+ m_rFormImport.registerControlId(m_xElement, m_sControlId);
+ // it's allowed to have no control id. In this case we're importing a column
+
+ // one more pre-work to do:
+ // when we set default values, then by definition the respective value is set
+ // to this default value, too. This means if the sequence contains for example
+ // a DefaultText value, then the Text will be affected by this, too.
+ // In case the Text is not part of the property sequence (or occurs _before_
+ // the DefaultText, which can happen for other value/default-value property names),
+ // this means that the Text (the value property) is incorrectly imported.
+
+ bool bRestoreValuePropertyValue = false;
+ Any aValuePropertyValue;
+
+ sal_Int16 nClassId = FormComponentType::CONTROL;
+ try
+ {
+ // get the class id of our element
+ m_xElement->getPropertyValue(PROPERTY_CLASSID) >>= nClassId;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("xmloff.forms",
+ "caught an exception while retrieving the class id!");
+ }
+
+ const char* pValueProperty = nullptr;
+ const char* pDefaultValueProperty = nullptr;
+ getRuntimeValuePropertyNames(m_eElementType, nClassId, pValueProperty, pDefaultValueProperty);
+ if ( pDefaultValueProperty && pValueProperty )
+ {
+ bool bNonDefaultValuePropertyValue = false;
+ // is the "value property" part of the sequence?
+
+ // look up this property in our sequence
+ for ( const auto& rCheck : m_aValues )
+ {
+ if ( rCheck.Name.equalsAscii( pDefaultValueProperty ) )
+ bRestoreValuePropertyValue = true;
+ else if ( rCheck.Name.equalsAscii( pValueProperty ) )
+ {
+ bNonDefaultValuePropertyValue = true;
+ // we need to restore the value property we found here, nothing else
+ aValuePropertyValue = rCheck.Value;
+ }
+ }
+
+ if ( bRestoreValuePropertyValue && !bNonDefaultValuePropertyValue )
+ {
+ // found it -> need to remember (and restore) the "value property value", which is not set explicitly
+ try
+ {
+ aValuePropertyValue = m_xElement->getPropertyValue( OUString::createFromAscii( pValueProperty ) );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION(
+ "xmloff.forms",
+ "caught an exception while retrieving the current value property!");
+ }
+ }
+ }
+
+ // let the base class set all the values
+ OElementImport::endFastElement(nElement);
+
+ // restore the "value property value", if necessary
+ if ( bRestoreValuePropertyValue && pValueProperty )
+ {
+ try
+ {
+ m_xElement->setPropertyValue( OUString::createFromAscii( pValueProperty ), aValuePropertyValue );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("xmloff.forms",
+ "caught an exception while restoring the value property!");
+ }
+ }
+
+ // the external cell binding, if applicable
+ if ( m_xElement.is() && !m_sBoundCellAddress.isEmpty() )
+ doRegisterCellValueBinding( m_sBoundCellAddress );
+
+ // XForms binding, if applicable
+ if ( m_xElement.is() && !m_sBindingID.isEmpty() )
+ doRegisterXFormsValueBinding( m_sBindingID );
+
+ // XForms list binding, if applicable
+ if ( m_xElement.is() && !m_sListBindingID.isEmpty() )
+ doRegisterXFormsListBinding( m_sListBindingID );
+
+ // XForms submission, if applicable
+ if ( m_xElement.is() && !m_sSubmissionID.isEmpty() )
+ doRegisterXFormsSubmission( m_sSubmissionID );
+ }
+
+ void OControlImport::doRegisterCellValueBinding( const OUString& _rBoundCellAddress )
+ {
+ OSL_PRECOND( m_xElement.is(), "OControlImport::doRegisterCellValueBinding: invalid element!" );
+ OSL_PRECOND( !_rBoundCellAddress.isEmpty(),
+ "OControlImport::doRegisterCellValueBinding: invalid address!" );
+
+ m_rContext.registerCellValueBinding( m_xElement, _rBoundCellAddress );
+ }
+
+ void OControlImport::doRegisterXFormsValueBinding( const OUString& _rBindingID )
+ {
+ OSL_PRECOND( m_xElement.is(), "need element" );
+ OSL_PRECOND( !_rBindingID.isEmpty(), "binding ID is not valid" );
+
+ m_rContext.registerXFormsValueBinding( m_xElement, _rBindingID );
+ }
+
+ void OControlImport::doRegisterXFormsListBinding( const OUString& _rBindingID )
+ {
+ OSL_PRECOND( m_xElement.is(), "need element" );
+ OSL_PRECOND( !_rBindingID.isEmpty(), "binding ID is not valid" );
+
+ m_rContext.registerXFormsListBinding( m_xElement, _rBindingID );
+ }
+
+ void OControlImport::doRegisterXFormsSubmission( const OUString& _rSubmissionID )
+ {
+ OSL_PRECOND( m_xElement.is(), "need element" );
+ OSL_PRECOND( !_rSubmissionID.isEmpty(), "binding ID is not valid" );
+
+ m_rContext.registerXFormsSubmission( m_xElement, _rSubmissionID );
+ }
+
+ Reference< XPropertySet > OControlImport::createElement()
+ {
+ const Reference<XPropertySet> xPropSet = OElementImport::createElement();
+ if ( xPropSet.is() )
+ {
+ m_xInfo = xPropSet->getPropertySetInfo();
+ if ( m_xInfo.is() && m_xInfo->hasPropertyByName(PROPERTY_ALIGN) )
+ {
+ Any aValue;
+ xPropSet->setPropertyValue(PROPERTY_ALIGN,aValue);
+ }
+ }
+ return xPropSet;
+ }
+
+ //= OImagePositionImport
+ OImagePositionImport::OImagePositionImport( OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const Reference< XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType )
+ :OControlImport( _rImport, _rEventManager, _rxParentContainer, _eType )
+ ,m_nImagePosition( -1 )
+ ,m_nImageAlign( 0 )
+ ,m_bHaveImagePosition( false )
+ {
+ }
+
+ bool OImagePositionImport::handleAttribute( sal_Int32 nElement,
+ const OUString& _rValue )
+ {
+ static const sal_Int32 s_nImageDataAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::ImageData);
+
+ if ( (nElement & TOKEN_MASK) == s_nImageDataAttributeName)
+ {
+ m_xGraphic = m_rContext.getGlobalContext().loadGraphicByURL(_rValue);
+ return true;
+ }
+ else if ( (nElement & TOKEN_MASK) == XML_IMAGE_POSITION )
+ {
+ OSL_VERIFY( PropertyConversion::convertString(
+ cppu::UnoType<decltype(m_nImagePosition)>::get(),
+ _rValue, aImagePositionMap
+ ) >>= m_nImagePosition );
+ m_bHaveImagePosition = true;
+ return true;
+ }
+ else if ( (nElement & TOKEN_MASK) == XML_IMAGE_ALIGN )
+ {
+ OSL_VERIFY( PropertyConversion::convertString(
+ cppu::UnoType<decltype(m_nImageAlign)>::get(),
+ _rValue, aImageAlignMap
+ ) >>= m_nImageAlign );
+ return true;
+ }
+
+ return OControlImport::handleAttribute( nElement, _rValue );
+ }
+
+ void OImagePositionImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList)
+ {
+ OControlImport::startFastElement( nElement, _rxAttrList );
+
+ if (m_xGraphic.is())
+ {
+ PropertyValue aGraphicProperty;
+ aGraphicProperty.Name = PROPERTY_GRAPHIC;
+ aGraphicProperty.Value <<= m_xGraphic;
+ implPushBackPropertyValue(aGraphicProperty);
+ }
+ if ( !m_bHaveImagePosition )
+ return;
+
+ sal_Int16 nUnoImagePosition = ImagePosition::Centered;
+ if ( m_nImagePosition >= 0 )
+ {
+ OSL_ENSURE( ( m_nImagePosition <= 3 ) && ( m_nImageAlign >= 0 ) && ( m_nImageAlign < 3 ),
+ "OImagePositionImport::StartElement: unknown image align and/or position!" );
+ nUnoImagePosition = m_nImagePosition * 3 + m_nImageAlign;
+ }
+
+ PropertyValue aImagePosition;
+ aImagePosition.Name = PROPERTY_IMAGE_POSITION;
+ aImagePosition.Value <<= nUnoImagePosition;
+ implPushBackPropertyValue( aImagePosition );
+ }
+
+ //= OReferredControlImport
+ OReferredControlImport::OReferredControlImport(
+ OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const Reference< XNameContainer >& _rxParentContainer )
+ :OControlImport(_rImport, _rEventManager, _rxParentContainer)
+ {
+ }
+
+ void OReferredControlImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList)
+ {
+ OControlImport::startFastElement(nElement, _rxAttrList);
+
+ // the base class should have created the control, so we can register it
+ if ( !m_sReferringControls.isEmpty() )
+ m_rFormImport.registerControlReferences(m_xElement, m_sReferringControls);
+ }
+
+ bool OReferredControlImport::handleAttribute(sal_Int32 nElement,
+ const OUString& _rValue)
+ {
+ static const sal_Int32 s_nReferenceAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::For);
+ if ((nElement & TOKEN_MASK) == s_nReferenceAttributeName)
+ {
+ m_sReferringControls = _rValue;
+ return true;
+ }
+ return OControlImport::handleAttribute(nElement, _rValue);
+ }
+
+ //= OPasswordImport
+ OPasswordImport::OPasswordImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const Reference< XNameContainer >& _rxParentContainer, OControlElement::ElementType _eType)
+ :OControlImport(_rImport, _rEventManager, _rxParentContainer, _eType)
+ {
+ }
+
+ bool OPasswordImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue)
+ {
+ static const sal_Int32 s_nEchoCharAttributeName = OAttributeMetaData::getSpecialAttributeToken(SCAFlags::EchoChar);
+ if ((nElement & TOKEN_MASK) == s_nEchoCharAttributeName)
+ {
+ // need a special handling for the EchoChar property
+ PropertyValue aEchoChar;
+ aEchoChar.Name = PROPERTY_ECHOCHAR;
+ OSL_ENSURE(_rValue.getLength() == 1, "OPasswordImport::handleAttribute: invalid echo char attribute!");
+ // we ourself should not have written values other than of length 1
+ if (_rValue.getLength() >= 1)
+ aEchoChar.Value <<= static_cast<sal_Int16>(_rValue[0]);
+ else
+ aEchoChar.Value <<= sal_Int16(0);
+ implPushBackPropertyValue(aEchoChar);
+ return true;
+ }
+ return OControlImport::handleAttribute(nElement, _rValue);
+ }
+
+ //= ORadioImport
+ ORadioImport::ORadioImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const Reference< XNameContainer >& _rxParentContainer, OControlElement::ElementType _eType)
+ :OImagePositionImport( _rImport, _rEventManager, _rxParentContainer, _eType )
+ {
+ }
+
+ bool ORadioImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue)
+ {
+ // need special handling for the State & CurrentState properties:
+ // they're stored as booleans, but expected to be int16 properties
+ static const sal_Int32 nCurrentSelectedAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::CurrentSelected);
+ static const sal_Int32 nSelectedAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Selected);
+ if ( (nElement & TOKEN_MASK) == nCurrentSelectedAttributeName
+ || (nElement & TOKEN_MASK) == nSelectedAttributeName
+ )
+ {
+ const OAttribute2Property::AttributeAssignment* pProperty = m_rContext.getAttributeMap().getAttributeTranslation(nElement & TOKEN_MASK);
+ assert(pProperty && "ORadioImport::handleAttribute: invalid property map!");
+ if (pProperty)
+ {
+ const Any aBooleanValue( PropertyConversion::convertString(pProperty->aPropertyType, _rValue, pProperty->pEnumMap) );
+
+ // create and store a new PropertyValue
+ PropertyValue aNewValue;
+ aNewValue.Name = pProperty->sPropertyName;
+ aNewValue.Value <<= static_cast<sal_Int16>(::cppu::any2bool(aBooleanValue));
+
+ implPushBackPropertyValue(aNewValue);
+ }
+ return true;
+ }
+ return OImagePositionImport::handleAttribute( nElement, _rValue );
+ }
+
+ //= OURLReferenceImport
+ OURLReferenceImport::OURLReferenceImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const Reference< XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType)
+ :OImagePositionImport(_rImport, _rEventManager, _rxParentContainer, _eType)
+ {
+ }
+
+ bool OURLReferenceImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue)
+ {
+ static const sal_Int32 s_nTargetLocationAttributeName = OAttributeMetaData::getCommonControlAttributeToken( CCAFlags::TargetLocation );
+ static const sal_Int32 s_nImageDataAttributeName = OAttributeMetaData::getCommonControlAttributeToken( CCAFlags::ImageData );
+
+ // need to make the URL absolute if
+ // * it's the image-data attribute
+ // * it's the target-location attribute, and we're dealing with an object which has the respective property
+ bool bMakeAbsolute =
+ (nElement & TOKEN_MASK) == s_nImageDataAttributeName
+ || ( (nElement & TOKEN_MASK) == s_nTargetLocationAttributeName
+ && ( ( OControlElement::BUTTON == m_eElementType )
+ || ( OControlElement::IMAGE == m_eElementType )
+ )
+ );
+
+ if (bMakeAbsolute && !_rValue.isEmpty())
+ {
+ OUString sAdjustedValue = _rValue;
+ if ((nElement & TOKEN_MASK) != s_nImageDataAttributeName)
+ sAdjustedValue = m_rContext.getGlobalContext().GetAbsoluteReference( _rValue );
+ return OImagePositionImport::handleAttribute( nElement, sAdjustedValue );
+ }
+
+ return OImagePositionImport::handleAttribute( nElement, _rValue );
+ }
+
+ //= OButtonImport
+ OButtonImport::OButtonImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const Reference< XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType)
+ :OURLReferenceImport(_rImport, _rEventManager, _rxParentContainer, _eType)
+ {
+ enableTrackAttributes();
+ }
+
+ void OButtonImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList)
+ {
+ OURLReferenceImport::startFastElement(nElement, _rxAttrList);
+
+ // handle the target-frame attribute
+ simulateDefaultedAttribute(OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::TargetFrame), PROPERTY_TARGETFRAME, "_blank");
+ }
+
+ //= OValueRangeImport
+ OValueRangeImport::OValueRangeImport( OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const Reference< XNameContainer >& _rxParentContainer, OControlElement::ElementType _eType )
+ :OControlImport( _rImport, _rEventManager, _rxParentContainer, _eType )
+ ,m_nStepSizeValue( 1 )
+ {
+
+ }
+
+ bool OValueRangeImport::handleAttribute( sal_Int32 nElement, const OUString& _rValue )
+ {
+ if ( (nElement & TOKEN_MASK) == OAttributeMetaData::getSpecialAttributeToken( SCAFlags::StepSize ) )
+ {
+ ::sax::Converter::convertNumber( m_nStepSizeValue, _rValue );
+ return true;
+ }
+ return OControlImport::handleAttribute( nElement, _rValue );
+ }
+
+ void OValueRangeImport::startFastElement( sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList )
+ {
+ OControlImport::startFastElement( nElement, _rxAttrList );
+
+ if ( m_xInfo.is() )
+ {
+ if ( m_xInfo->hasPropertyByName( PROPERTY_SPIN_INCREMENT ) )
+ m_xElement->setPropertyValue( PROPERTY_SPIN_INCREMENT, Any( m_nStepSizeValue ) );
+ else if ( m_xInfo->hasPropertyByName( PROPERTY_LINE_INCREMENT ) )
+ m_xElement->setPropertyValue( PROPERTY_LINE_INCREMENT, Any( m_nStepSizeValue ) );
+ }
+ }
+
+ //= OTextLikeImport
+ OTextLikeImport::OTextLikeImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const Reference< XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType)
+ :OControlImport(_rImport, _rEventManager, _rxParentContainer, _eType)
+ ,m_bEncounteredTextPara( false )
+ {
+ enableTrackAttributes();
+ }
+
+ css::uno::Reference< css::xml::sax::XFastContextHandler > OTextLikeImport::createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+ {
+ if ( nElement == XML_ELEMENT(TEXT, XML_P) )
+ {
+ OSL_ENSURE( m_eElementType == OControlElement::TEXT_AREA,
+ "OTextLikeImport::CreateChildContext: text paragraphs in a non-text-area?" );
+
+ if ( m_eElementType == OControlElement::TEXT_AREA )
+ {
+ Reference< XText > xTextElement( m_xElement, UNO_QUERY );
+ if ( xTextElement.is() )
+ {
+ rtl::Reference < XMLTextImportHelper > xTextImportHelper( m_rContext.getGlobalContext().GetTextImport() );
+
+ if ( !m_xCursor.is() )
+ {
+ m_xOldCursor = xTextImportHelper->GetCursor();
+ m_xCursor = xTextElement->createTextCursor();
+
+ if ( m_xCursor.is() )
+ xTextImportHelper->SetCursor( m_xCursor );
+ }
+ if ( m_xCursor.is() )
+ {
+ m_bEncounteredTextPara = true;
+ return xTextImportHelper->CreateTextChildContext( m_rContext.getGlobalContext(), nElement, xAttrList );
+ }
+ }
+ else
+ {
+ // in theory, we could accumulate all the text portions (without formatting),
+ // and set it as Text property at the model ...
+ }
+ }
+ }
+
+ return OControlImport::createFastChildContext( nElement, xAttrList );
+ }
+
+ void OTextLikeImport::startFastElement(sal_Int32 nElement, const Reference< css::xml::sax::XFastAttributeList >& _rxAttrList)
+ {
+ OControlImport::startFastElement(nElement, _rxAttrList);
+
+ // handle the convert-empty-to-null attribute, whose default is different from the property default
+ // unfortunately, different classes are imported by this class ('cause they're represented by the
+ // same XML element), though not all of them know this property.
+ // So we have to do a check ...
+ if (m_xElement.is() && m_xInfo.is() && m_xInfo->hasPropertyByName(PROPERTY_EMPTY_IS_NULL) )
+ simulateDefaultedAttribute(OAttributeMetaData::getDatabaseAttributeToken(DAFlags::ConvertEmpty), PROPERTY_EMPTY_IS_NULL, "false");
+ }
+
+ namespace {
+
+ struct EqualHandle
+ {
+ const sal_Int32 m_nHandle;
+ explicit EqualHandle( sal_Int32 _nHandle ) : m_nHandle( _nHandle ) { }
+
+ bool operator()( const PropertyValue& _rProp )
+ {
+ return _rProp.Handle == m_nHandle;
+ }
+ };
+
+ }
+
+ void OTextLikeImport::removeRedundantCurrentValue()
+ {
+ if ( !m_bEncounteredTextPara )
+ return;
+
+ // In case the text is written in the text:p elements, we need to ignore what we read as
+ // current-value attribute, since it's redundant.
+ // fortunately, OElementImport tagged the value property with the PROPID_CURRENT_VALUE
+ // handle, so we do not need to determine the name of our value property here
+ // (normally, it should be "Text", since no other controls than the edit field should
+ // have the text:p elements)
+ PropertyValueArray::iterator aValuePropertyPos = ::std::find_if(
+ m_aValues.begin(),
+ m_aValues.end(),
+ EqualHandle( PROPID_CURRENT_VALUE )
+ );
+ if ( aValuePropertyPos != m_aValues.end() )
+ {
+ OSL_ENSURE( aValuePropertyPos->Name == PROPERTY_TEXT, "OTextLikeImport::EndElement: text:p was present, but our value property is *not* 'Text'!" );
+ if ( aValuePropertyPos->Name == PROPERTY_TEXT )
+ {
+ m_aValues.erase(aValuePropertyPos);
+ }
+ }
+
+ // additionally, we need to set the "RichText" property of our element to sal_True
+ // (the presence of the text:p is used as indicator for the value of the RichText property)
+ bool bHasRichTextProperty = false;
+ if ( m_xInfo.is() )
+ bHasRichTextProperty = m_xInfo->hasPropertyByName( PROPERTY_RICH_TEXT );
+ OSL_ENSURE( bHasRichTextProperty, "OTextLikeImport::EndElement: text:p, but no rich text control?" );
+ if ( bHasRichTextProperty )
+ m_xElement->setPropertyValue( PROPERTY_RICH_TEXT, Any( true ) );
+ // Note that we do *not* set the RichText property (in case our element has one) to sal_False here
+ // since this is the default of this property, anyway.
+ }
+
+ namespace {
+
+ struct EqualName
+ {
+ const OUString & m_sName;
+ explicit EqualName( const OUString& _rName ) : m_sName( _rName ) { }
+
+ bool operator()( const PropertyValue& _rProp )
+ {
+ return _rProp.Name == m_sName;
+ }
+ };
+
+ }
+
+ void OTextLikeImport::adjustDefaultControlProperty()
+ {
+ // In OpenOffice.org 2.0, we changed the implementation of the css.form.component.TextField (the model of a text field control),
+ // so that it now uses another default control. So if we encounter a text field where the *old* default
+ // control property is writing, we are not allowed to use it
+ PropertyValueArray::iterator aDefaultControlPropertyPos = ::std::find_if(
+ m_aValues.begin(),
+ m_aValues.end(),
+ EqualName( "DefaultControl" )
+ );
+ if ( aDefaultControlPropertyPos != m_aValues.end() )
+ {
+ OUString sDefaultControl;
+ OSL_VERIFY( aDefaultControlPropertyPos->Value >>= sDefaultControl );
+ if ( sDefaultControl == "stardiv.one.form.control.Edit" )
+ {
+ // complete remove this property value from the array. Today's "default value" of the "DefaultControl"
+ // property is sufficient
+ m_aValues.erase(aDefaultControlPropertyPos);
+ }
+ }
+ }
+
+ void OTextLikeImport::endFastElement(sal_Int32 nElement)
+ {
+ removeRedundantCurrentValue();
+ adjustDefaultControlProperty();
+
+ // let the base class do the stuff
+ OControlImport::endFastElement(nElement);
+
+ // some cleanups
+ rtl::Reference < XMLTextImportHelper > xTextImportHelper( m_rContext.getGlobalContext().GetTextImport() );
+ if ( m_xCursor.is() )
+ {
+ // delete the newline which has been imported erroneously
+ // TODO (fs): stole this code somewhere - why don't we fix the text import??
+ m_xCursor->gotoEnd( false );
+ m_xCursor->goLeft( 1, true );
+ m_xCursor->setString( OUString() );
+
+ // reset cursor
+ xTextImportHelper->ResetCursor();
+ }
+
+ if ( m_xOldCursor.is() )
+ xTextImportHelper->SetCursor( m_xOldCursor );
+
+ }
+
+ //= OListAndComboImport
+ OListAndComboImport::OListAndComboImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const Reference< XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType)
+ :OControlImport(_rImport, _rEventManager, _rxParentContainer, _eType)
+ ,m_nEmptyListItems( 0 )
+ ,m_nEmptyValueItems( 0 )
+ ,m_bEncounteredLSAttrib( false )
+ ,m_bLinkWithIndexes( false )
+ {
+ if (OControlElement::COMBOBOX == m_eElementType)
+ enableTrackAttributes();
+ }
+
+ css::uno::Reference< css::xml::sax::XFastContextHandler > OListAndComboImport::createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList )
+ {
+ // is it the "option" sub tag of a listbox ?
+ if ((nElement & TOKEN_MASK) == XML_OPTION)
+ return new OListOptionImport(GetImport(), this);
+
+ // is it the "item" sub tag of a combobox ?
+ if ((nElement & TOKEN_MASK) == XML_ITEM)
+ return new OComboItemImport(GetImport(), this);
+
+ // everything else
+ return OControlImport::createFastChildContext(nElement, _rxAttrList);
+ }
+
+ void OListAndComboImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList)
+ {
+ m_bLinkWithIndexes = false;
+
+ OControlImport::startFastElement(nElement, _rxAttrList);
+
+ if (OControlElement::COMBOBOX == m_eElementType)
+ {
+ // for the auto-completion
+ // the attribute default does not equal the property default, so in case we did not read this attribute,
+ // we have to simulate it
+ simulateDefaultedAttribute( OAttributeMetaData::getSpecialAttributeToken( SCAFlags::AutoCompletion ), PROPERTY_AUTOCOMPLETE, "false");
+
+ // same for the convert-empty-to-null attribute, which's default is different from the property default
+ simulateDefaultedAttribute( OAttributeMetaData::getDatabaseAttributeToken( DAFlags::ConvertEmpty ), PROPERTY_EMPTY_IS_NULL, "false");
+ }
+ }
+
+ void OListAndComboImport::endFastElement(sal_Int32 nElement)
+ {
+ // append the list source property the properties sequence of our importer
+ // the string item list
+ PropertyValue aItemList;
+ aItemList.Name = PROPERTY_STRING_ITEM_LIST;
+ aItemList.Value <<= comphelper::containerToSequence(m_aListSource);
+ implPushBackPropertyValue(aItemList);
+
+ if (OControlElement::LISTBOX == m_eElementType)
+ {
+ OSL_ENSURE((m_aListSource.size() + m_nEmptyListItems) == (m_aValueList.size() + m_nEmptyValueItems),
+ "OListAndComboImport::EndElement: inconsistence between labels and values!");
+
+ if ( !m_bEncounteredLSAttrib )
+ {
+ // the value sequence
+ PropertyValue aValueList;
+ aValueList.Name = PROPERTY_LISTSOURCE;
+ aValueList.Value <<= comphelper::containerToSequence(m_aValueList);
+ implPushBackPropertyValue(aValueList);
+ }
+
+ // the select sequence
+ PropertyValue aSelected;
+ aSelected.Name = PROPERTY_SELECT_SEQ;
+ aSelected.Value <<= comphelper::containerToSequence(m_aSelectedSeq);
+ implPushBackPropertyValue(aSelected);
+
+ // the default select sequence
+ PropertyValue aDefaultSelected;
+ aDefaultSelected.Name = PROPERTY_DEFAULT_SELECT_SEQ;
+ aDefaultSelected.Value <<= comphelper::containerToSequence(m_aDefaultSelectedSeq);
+ implPushBackPropertyValue(aDefaultSelected);
+ }
+
+ OControlImport::endFastElement(nElement);
+
+ // the external list source, if applicable
+ if ( m_xElement.is() && !m_sCellListSource.isEmpty() )
+ m_rContext.registerCellRangeListSource( m_xElement, m_sCellListSource );
+ }
+
+ void OListAndComboImport::doRegisterCellValueBinding( const OUString& _rBoundCellAddress )
+ {
+ OUString sBoundCellAddress( _rBoundCellAddress );
+ if ( m_bLinkWithIndexes )
+ {
+ // This is a HACK. We register a string which is no valid address, but allows
+ // (somewhere else) to determine that a non-standard binding should be created.
+ // This hack is acceptable for OOo 1.1.1, since the file format for value
+ // bindings of form controls is to be changed afterwards, anyway.
+ sBoundCellAddress += ":index";
+ }
+
+ OControlImport::doRegisterCellValueBinding( sBoundCellAddress );
+ }
+
+ bool OListAndComboImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue)
+ {
+ static const sal_Int32 nListSourceAttributeName = OAttributeMetaData::getDatabaseAttributeToken(DAFlags::ListSource);
+ if ( (nElement & TOKEN_MASK) == nListSourceAttributeName )
+ {
+ PropertyValue aListSource;
+ aListSource.Name = PROPERTY_LISTSOURCE;
+
+ // it's the ListSource attribute
+ m_bEncounteredLSAttrib = true;
+ if ( OControlElement::COMBOBOX == m_eElementType )
+ {
+ aListSource.Value <<= _rValue;
+ }
+ else
+ {
+ // a listbox which has a list-source attribute must have a list-source-type of something
+ // not equal to ValueList.
+ // In this case, the list-source value is simply the one and only element of the ListSource property.
+ Sequence<OUString> aListSourcePropValue { _rValue };
+ aListSource.Value <<= aListSourcePropValue;
+ }
+
+ implPushBackPropertyValue( aListSource );
+ return true;
+ }
+
+ if ( (nElement & TOKEN_MASK) == OAttributeMetaData::getBindingAttributeToken( BAFlags::ListCellRange ) )
+ {
+ m_sCellListSource = _rValue;
+ return true;
+ }
+
+ if ( (nElement & TOKEN_MASK) == OAttributeMetaData::getBindingAttributeToken( BAFlags::ListLinkingType ) )
+ {
+ sal_Int16 nLinkageType = 0;
+ PropertyConversion::convertString(
+ ::cppu::UnoType<sal_Int16>::get(),
+ _rValue,
+ aListLinkageMap
+ ) >>= nLinkageType;
+
+ m_bLinkWithIndexes = ( nLinkageType != 0 );
+ return true;
+ }
+
+ return OControlImport::handleAttribute(nElement, _rValue);
+ }
+
+ void OListAndComboImport::implPushBackLabel(const OUString& _rLabel)
+ {
+ OSL_ENSURE(!m_nEmptyListItems, "OListAndComboImport::implPushBackValue: label list is already done!");
+ if (!m_nEmptyListItems)
+ m_aListSource.push_back(_rLabel);
+ }
+
+ void OListAndComboImport::implPushBackValue(const OUString& _rValue)
+ {
+ OSL_ENSURE(!m_nEmptyValueItems, "OListAndComboImport::implPushBackValue: value list is already done!");
+ if (!m_nEmptyValueItems)
+ {
+ OSL_ENSURE( !m_bEncounteredLSAttrib, "OListAndComboImport::implPushBackValue: invalid structure! Did you save this document with a version prior SRC641 m?" );
+ // We already had the list-source attribute, which means that the ListSourceType is
+ // not ValueList, which means that the ListSource should contain only one string in
+ // the first element of the sequence
+ // All other values in the file are invalid
+
+ m_aValueList.push_back( _rValue );
+ }
+ }
+
+ void OListAndComboImport::implEmptyLabelFound()
+ {
+ ++m_nEmptyListItems;
+ }
+
+ void OListAndComboImport::implEmptyValueFound()
+ {
+ ++m_nEmptyValueItems;
+ }
+
+ void OListAndComboImport::implSelectCurrentItem()
+ {
+ OSL_ENSURE((m_aListSource.size() + m_nEmptyListItems) == (m_aValueList.size() + m_nEmptyValueItems),
+ "OListAndComboImport::implSelectCurrentItem: inconsistence between labels and values!");
+
+ sal_Int16 nItemNumber = static_cast<sal_Int16>(m_aListSource.size() - 1 + m_nEmptyListItems);
+ m_aSelectedSeq.push_back(nItemNumber);
+ }
+
+ void OListAndComboImport::implDefaultSelectCurrentItem()
+ {
+ OSL_ENSURE((m_aListSource.size() + m_nEmptyListItems) == (m_aValueList.size() + m_nEmptyValueItems),
+ "OListAndComboImport::implDefaultSelectCurrentItem: inconsistence between labels and values!");
+
+ sal_Int16 nItemNumber = static_cast<sal_Int16>(m_aListSource.size() - 1 + m_nEmptyListItems);
+ m_aDefaultSelectedSeq.push_back(nItemNumber);
+ }
+
+ //= OListOptionImport
+ OListOptionImport::OListOptionImport(SvXMLImport& _rImport,
+ const OListAndComboImportRef& _rListBox)
+ :SvXMLImportContext(_rImport)
+ ,m_xListBoxImport(_rListBox)
+ {
+ }
+
+ void OListOptionImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList)
+ {
+ // the label and the value
+ const sal_Int32 nLabelAttribute = (nElement & ~TOKEN_MASK) | XML_LABEL;
+ const sal_Int32 nValueAttribute = (nElement & ~TOKEN_MASK) | XML_VALUE;
+
+ // the label attribute
+ OUString sValue = _rxAttrList->getOptionalValue(nLabelAttribute);
+ bool bNonexistentAttribute = !_rxAttrList->hasAttribute(nLabelAttribute);
+
+ if (bNonexistentAttribute)
+ m_xListBoxImport->implEmptyLabelFound();
+ else
+ m_xListBoxImport->implPushBackLabel( sValue );
+
+ // the value attribute
+ sValue = _rxAttrList->getOptionalValue(nValueAttribute);
+ bNonexistentAttribute = !_rxAttrList->hasAttribute(nValueAttribute);
+
+ if (bNonexistentAttribute)
+ m_xListBoxImport->implEmptyValueFound();
+ else
+ m_xListBoxImport->implPushBackValue( sValue );
+
+ // the current-selected and selected
+ const sal_Int32 nSelectedAttribute = (nElement & ~TOKEN_MASK) | OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::CurrentSelected);
+ const sal_Int32 nDefaultSelectedAttribute = (nElement & ~TOKEN_MASK) | OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Selected);
+
+ // propagate the selected flag
+ bool bSelected(false);
+ (void)::sax::Converter::convertBool(bSelected,
+ _rxAttrList->getOptionalValue(nSelectedAttribute));
+ if (bSelected)
+ m_xListBoxImport->implSelectCurrentItem();
+
+ // same for the default selected
+ bool bDefaultSelected(false);
+ (void)::sax::Converter::convertBool(bDefaultSelected,
+ _rxAttrList->getOptionalValue(nDefaultSelectedAttribute));
+ if (bDefaultSelected)
+ m_xListBoxImport->implDefaultSelectCurrentItem();
+ }
+
+ //= OComboItemImport
+ OComboItemImport::OComboItemImport(SvXMLImport& _rImport,
+ const OListAndComboImportRef& _rListBox)
+ :SvXMLImportContext(_rImport)
+ ,m_xListBoxImport(_rListBox)
+ {
+ }
+
+ void OComboItemImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList)
+ {
+ const sal_Int32 nLabelAttributeName = (nElement & ~TOKEN_MASK) |
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Label);
+ m_xListBoxImport->implPushBackLabel(_rxAttrList->getOptionalValue(nLabelAttributeName));
+ }
+
+ //= OColumnWrapperImport
+ OColumnWrapperImport::OColumnWrapperImport(OFormLayerXMLImport_Impl& _rImport,
+ IEventAttacherManager& _rEventManager, sal_Int32 /*nElement*/,
+ const Reference< XNameContainer >& _rxParentContainer)
+ :SvXMLImportContext(_rImport.getGlobalContext())
+ ,m_xParentContainer(_rxParentContainer)
+ ,m_rFormImport(_rImport)
+ ,m_rEventManager(_rEventManager)
+ {
+ }
+ css::uno::Reference< css::xml::sax::XFastContextHandler > OColumnWrapperImport::createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& )
+ {
+ OControlImport* pReturn = implCreateChildContext(nElement, OElementNameMap::getElementType(nElement & TOKEN_MASK));
+ if (pReturn)
+ {
+ OSL_ENSURE(m_xOwnAttributes.is(), "OColumnWrapperImport::CreateChildContext: had no form:column element!");
+ pReturn->addOuterAttributes(m_xOwnAttributes);
+ }
+ return pReturn;
+ }
+ void OColumnWrapperImport::startFastElement(sal_Int32 /*nElement*/, const Reference< XFastAttributeList >& _rxAttrList)
+ {
+ OSL_ENSURE(!m_xOwnAttributes.is(), "OColumnWrapperImport::StartElement: already have the cloned list!");
+
+ // clone the attributes
+ Reference< XCloneable > xCloneList(_rxAttrList, UNO_QUERY_THROW);
+ m_xOwnAttributes.set(xCloneList->createClone(), UNO_QUERY_THROW);
+ }
+
+ OControlImport* OColumnWrapperImport::implCreateChildContext(
+ sal_Int32 /*nElement*/,
+ OControlElement::ElementType _eType)
+ {
+ OSL_ENSURE( (OControlElement::TEXT == _eType)
+ || (OControlElement::TEXT_AREA == _eType)
+ || (OControlElement::FORMATTED_TEXT == _eType)
+ || (OControlElement::CHECKBOX == _eType)
+ || (OControlElement::LISTBOX == _eType)
+ || (OControlElement::COMBOBOX == _eType)
+ || (OControlElement::TIME == _eType)
+ || (OControlElement::DATE == _eType),
+ "OColumnWrapperImport::implCreateChildContext: invalid or unrecognized sub element!");
+
+ switch (_eType)
+ {
+ case OControlElement::COMBOBOX:
+ case OControlElement::LISTBOX:
+ return new OColumnImport<OListAndComboImport>(m_rFormImport, m_rEventManager, m_xParentContainer, _eType );
+
+ case OControlElement::PASSWORD:
+ return new OColumnImport<OPasswordImport>(m_rFormImport, m_rEventManager, m_xParentContainer, _eType );
+
+ case OControlElement::TEXT:
+ case OControlElement::TEXT_AREA:
+ case OControlElement::FORMATTED_TEXT:
+ return new OColumnImport< OTextLikeImport >( m_rFormImport, m_rEventManager, m_xParentContainer, _eType );
+
+ default:
+ return new OColumnImport<OControlImport>(m_rFormImport, m_rEventManager, m_xParentContainer, _eType );
+ }
+ }
+
+ //= OGridImport
+ OGridImport::OGridImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const Reference< XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType)
+ :OControlImport(_rImport, _rEventManager, _rxParentContainer)
+ {
+ setElementType(_eType);
+ }
+
+ css::uno::Reference< css::xml::sax::XFastContextHandler > OGridImport::createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+ {
+ // maybe it's a sub control
+ if ((nElement & TOKEN_MASK) == XML_COLUMN)
+ {
+ if (m_xMeAsContainer.is())
+ return new OColumnWrapperImport(m_rFormImport, *this, nElement, m_xMeAsContainer);
+ else
+ {
+ OSL_FAIL("OGridImport::CreateChildContext: don't have an element!");
+ return nullptr;
+ }
+ }
+
+ return OControlImport::createFastChildContext(nElement, xAttrList);
+ }
+
+ void OGridImport::endFastElement(sal_Int32 nElement)
+ {
+ OControlImport::endFastElement(nElement);
+
+ // now that we have all children, attach the events
+ css::uno::Reference< css::container::XIndexAccess > xIndexContainer(m_xMeAsContainer, css::uno::UNO_QUERY);
+ if (xIndexContainer.is())
+ ODefaultEventAttacherManager::setEvents(xIndexContainer);
+ }
+
+ css::uno::Reference< css::beans::XPropertySet > OGridImport::createElement()
+ {
+ // let the base class create the object
+ css::uno::Reference< css::beans::XPropertySet > xReturn = OControlImport::createElement();
+ if (!xReturn.is())
+ return xReturn;
+
+ // ensure that the object is a XNameContainer (we strongly need this for inserting child elements)
+ m_xMeAsContainer.set(xReturn, css::uno::UNO_QUERY);
+ if (!m_xMeAsContainer.is())
+ {
+ OSL_FAIL("OContainerImport::createElement: invalid element (no XNameContainer) created!");
+ xReturn.clear();
+ }
+
+ return xReturn;
+ }
+
+ //= OFormImport
+ OFormImport::OFormImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const Reference< XNameContainer >& _rxParentContainer)
+ :OElementImport(_rImport, _rEventManager, _rxParentContainer)
+ {
+ enableTrackAttributes();
+ }
+
+ css::uno::Reference< css::xml::sax::XFastContextHandler > OFormImport::createFastChildContext(
+ sal_Int32 nElement,
+ const uno::Reference< xml::sax::XFastAttributeList>& _rxAttrList )
+ {
+ auto nToken = (nElement & TOKEN_MASK);
+ if( nToken == XML_FORM )
+ return new OFormImport( m_rFormImport, *this, m_xMeAsContainer);
+ else if ( nToken == XML_CONNECTION_RESOURCE )
+ return new OXMLDataSourceImport(GetImport(), _rxAttrList, m_xElement);
+ else if( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ||
+ nToken == XML_PROPERTIES )
+ return OElementImport::createFastChildContext( nElement, _rxAttrList );
+ else
+ {
+ OControlElement::ElementType eType = OElementNameMap::getElementType(nToken);
+ switch (eType)
+ {
+ case OControlElement::TEXT:
+ case OControlElement::TEXT_AREA:
+ case OControlElement::FORMATTED_TEXT:
+ return new OTextLikeImport(m_rFormImport, *this, m_xMeAsContainer, eType);
+ case OControlElement::GRID:
+ return new OGridImport(m_rFormImport, *this, m_xMeAsContainer, eType);
+ case OControlElement::COMBOBOX:
+ case OControlElement::LISTBOX:
+ return new OListAndComboImport(m_rFormImport, *this, m_xMeAsContainer, eType);
+ case OControlElement::PASSWORD:
+ return new OPasswordImport(m_rFormImport, *this, m_xMeAsContainer, eType);
+ case OControlElement::BUTTON:
+ case OControlElement::IMAGE:
+ case OControlElement::IMAGE_FRAME:
+ return new OButtonImport( m_rFormImport, *this, m_xMeAsContainer, eType );
+ case OControlElement::RADIO:
+ return new ORadioImport(m_rFormImport, *this, m_xMeAsContainer, eType);
+ case OControlElement::CHECKBOX:
+ return new OImagePositionImport(m_rFormImport, *this, m_xMeAsContainer, eType);
+ case OControlElement::FRAME:
+ case OControlElement::FIXED_TEXT:
+ return new OReferredControlImport(m_rFormImport, *this, m_xMeAsContainer);
+ case OControlElement::VALUERANGE:
+ return new OValueRangeImport( m_rFormImport, *this, m_xMeAsContainer, eType );
+ default:
+ return new OControlImport(m_rFormImport, *this, m_xMeAsContainer, eType);
+ }
+ }
+ }
+
+ void OFormImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList)
+ {
+ m_rFormImport.enterEventContext();
+ OElementImport::startFastElement(nElement, _rxAttrList);
+
+ // handle the target-frame attribute
+ simulateDefaultedAttribute(OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::TargetFrame), PROPERTY_TARGETFRAME, "_blank");
+ }
+
+ void OFormImport::endFastElement(sal_Int32 nElement)
+ {
+ OElementImport::endFastElement(nElement);
+
+ // now that we have all children, attach the events
+ css::uno::Reference< css::container::XIndexAccess > xIndexContainer(m_xMeAsContainer, css::uno::UNO_QUERY);
+ if (xIndexContainer.is())
+ ODefaultEventAttacherManager::setEvents(xIndexContainer);
+
+ m_rFormImport.leaveEventContext();
+ }
+
+ css::uno::Reference< css::beans::XPropertySet > OFormImport::createElement()
+ {
+ // let the base class create the object
+ css::uno::Reference< css::beans::XPropertySet > xReturn = OElementImport::createElement();
+ if (!xReturn.is())
+ return xReturn;
+
+ // ensure that the object is a XNameContainer (we strongly need this for inserting child elements)
+ m_xMeAsContainer.set(xReturn, css::uno::UNO_QUERY);
+ if (!m_xMeAsContainer.is())
+ {
+ OSL_FAIL("OContainerImport::createElement: invalid element (no XNameContainer) created!");
+ xReturn.clear();
+ }
+
+ return xReturn;
+ }
+
+ bool OFormImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue)
+ {
+ // handle the master/details field attributes (they're way too special to let the OPropertyImport handle them)
+ static const sal_Int32 s_nMasterFieldsAttributeName = OAttributeMetaData::getFormAttributeToken(faMasterFields);
+ static const sal_Int32 s_nDetailFieldsAttributeName = OAttributeMetaData::getFormAttributeToken(faDetailFields);
+
+ if ( (nElement & TOKEN_MASK) == s_nMasterFieldsAttributeName)
+ {
+ implTranslateStringListProperty(PROPERTY_MASTERFIELDS, _rValue);
+ return true;
+ }
+
+ if ( (nElement & TOKEN_MASK) == s_nDetailFieldsAttributeName)
+ {
+ implTranslateStringListProperty(PROPERTY_DETAILFIELDS, _rValue);
+ return true;
+ }
+
+ return OElementImport::handleAttribute(nElement, _rValue);
+ }
+
+ void OFormImport::implTranslateStringListProperty(const OUString& _rPropertyName, const OUString& _rValue)
+ {
+ PropertyValue aProp;
+ aProp.Name = _rPropertyName;
+
+ Sequence< OUString > aList;
+
+ // split up the value string
+ if (!_rValue.isEmpty())
+ {
+ // For the moment, we build a vector instead of a Sequence. It's easier to handle because of its
+ // push_back method
+ ::std::vector< OUString > aElements;
+ // estimate the number of tokens
+ sal_Int32 nEstimate = 0, nLength = _rValue.getLength();
+ const sal_Unicode* pChars = _rValue.getStr();
+ for (sal_Int32 i=0; i<nLength; ++i, ++pChars)
+ if (*pChars == ',')
+ ++nEstimate;
+ aElements.reserve(nEstimate + 1);
+ // that's the worst case. If the string contains the separator character _quoted_, we reserved too much...
+
+ sal_Int32 nElementStart = 0;
+ sal_Int32 nNextSep = 0;
+ do
+ {
+ // extract the current element
+ nNextSep = ::sax::Converter::indexOfComma(
+ _rValue, nElementStart);
+ if (-1 == nNextSep)
+ nNextSep = nLength;
+ std::u16string_view sElement = _rValue.subView(nElementStart, nNextSep - nElementStart);
+
+ size_t nElementLength = sElement.size();
+ // when writing the sequence, we quoted the single elements with " characters
+ OSL_ENSURE( o3tl::starts_with(sElement, u"\"") && o3tl::ends_with(sElement, u"\""),
+ "OFormImport::implTranslateStringListProperty: invalid quoted element name.");
+ sElement = sElement.substr(1, nElementLength - 2);
+
+ aElements.push_back(OUString(sElement));
+
+ // switch to the next element
+ nElementStart = 1 + nNextSep;
+ }
+ while (nElementStart < nLength);
+
+ aList = Sequence< OUString >(aElements.data(), aElements.size());
+ }
+ else
+ {
+ OSL_FAIL("OFormImport::implTranslateStringListProperty: invalid value (empty)!");
+ }
+
+ aProp.Value <<= aList;
+
+ // add the property to the base class' array
+ implPushBackPropertyValue(aProp);
+ }
+ //= OXMLDataSourceImport
+ OXMLDataSourceImport::OXMLDataSourceImport(
+ SvXMLImport& _rImport
+ ,const Reference< css::xml::sax::XFastAttributeList > & _xAttrList
+ ,const css::uno::Reference< css::beans::XPropertySet >& _xElement) :
+ SvXMLImportContext( _rImport)
+ {
+ for( auto& aIter : sax_fastparser::castToFastAttributeList(_xAttrList) )
+ {
+ if ( aIter.getToken() ==
+ XML_ELEMENT(XLINK, OAttributeMetaData::getCommonControlAttributeToken( CCAFlags::TargetLocation ) ) )
+ {
+ OUString sValue = aIter.toString();
+ sValue = _rImport.GetAbsoluteReference(sValue);
+ INetURLObject aURL(sValue);
+ if ( aURL.GetProtocol() == INetProtocol::File )
+ _xElement->setPropertyValue(PROPERTY_DATASOURCENAME,Any(sValue));
+ else
+ _xElement->setPropertyValue(PROPERTY_URL,Any(sValue)); // the url is the "sdbc:" string
+ break;
+ }
+ else
+ SAL_WARN("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString());
+ }
+ }
+
+ OUString OFormImport::determineDefaultServiceName() const
+ {
+ return "com.sun.star.form.component.Form";
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/elementimport.hxx b/xmloff/source/forms/elementimport.hxx
new file mode 100644
index 000000000..dcf4a6043
--- /dev/null
+++ b/xmloff/source/forms/elementimport.hxx
@@ -0,0 +1,674 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include "propertyimport.hxx"
+#include "controlelement.hxx"
+#include "valueproperties.hxx"
+#include "eventimport.hxx"
+#include "logging.hxx"
+#include "property_description.hxx"
+
+#include <com/sun/star/text/XTextCursor.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/form/XGridColumnFactory.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <osl/diagnose.h>
+
+#include <map>
+#include <vector>
+
+class XMLTextStyleContext;
+namespace xmloff
+{
+
+ class OFormLayerXMLImport_Impl;
+
+ //= OElementNameMap
+ const OControlElement::ElementType& operator ++(OControlElement::ElementType& _e);
+
+ /** helper class which allows fast translation of xml tag names into element types.
+ */
+ class OElementNameMap : public OControlElement
+ {
+ typedef std::map<OUString, ElementType> MapString2Element;
+ static std::map<sal_Int32, ElementType> s_sElementTranslations2;
+
+ OElementNameMap() = delete;
+
+ public:
+ static ElementType getElementType(sal_Int32 nToken);
+ };
+
+ //= OElementImport
+ /** implements common behaviour for importing forms, controls and columns
+ */
+ class OElementImport
+ :public OPropertyImport
+ ,public IEventAttacher
+ ,public OStackedLogging
+ {
+ protected:
+ OUString m_sServiceName; // the service name as extracted from the service-name attribute
+ OUString m_sName; // the name of the object (redundant, already contained in the base class' array)
+ OFormLayerXMLImport_Impl& m_rFormImport; // the form import context
+ IEventAttacherManager& m_rEventManager; // the event attacher manager
+
+ const XMLTextStyleContext* m_pStyleElement; // the XML element which describes the style we encountered
+ // while reading our element
+
+ /// the parent container to insert the new element into
+ css::uno::Reference< css::container::XNameContainer >
+ m_xParentContainer;
+
+ /// the element we're creating. Valid after StartElement
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xElement;
+ css::uno::Reference< css::beans::XPropertySetInfo >
+ m_xInfo;
+
+ bool m_bImplicitGenericAttributeHandling;
+
+ public:
+ /** ctor
+ @param _rImport
+ the importer
+ @param _rEventManager
+ the event attacher manager for the control being imported
+ @param _rAttributeMap
+ the attribute map to be used for translating attributes into properties
+ @param _rxParentContainer
+ the container in which the new element should be inserted
+ */
+ OElementImport(
+ OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer
+ );
+ virtual ~OElementImport() override;
+
+ protected:
+ // SvXMLImportContext overridables
+ virtual void SAL_CALL startFastElement( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+
+ // OPropertyImport overridables
+ virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override;
+
+ // IEventAttacher
+ virtual void registerEvents(
+ const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents
+ ) override;
+
+ /** create the (uninitialized) element which is to represent the read data
+
+ <p>The default implementation uses <member>m_xORB</member> to create an object with <member>m_sServiceName</member>.
+ */
+ virtual css::uno::Reference< css::beans::XPropertySet >
+ createElement();
+
+ protected:
+ /** can be used to handle properties where the attribute default and the property default differ.
+ <p>In such case, if the property had the attribute default upon writing, nothing is read, so upon reading,
+ the property is still at its own default (which is not the attribute default).<p/>
+ <p>This method, if told the attribute and the property, and the (implied) attribute default, sets the
+ property value as if the attribute was encountered.</p>
+ @see encounteredAttribute
+ */
+ void simulateDefaultedAttribute(sal_Int32 nElement, const OUString& _rPropertyName, const char* _pAttributeDefault);
+
+ /** to be called from within handleAttribute, checks whether the given attribute is covered by our generic
+ attribute handler mechanisms
+ */
+ bool tryGenericAttribute( sal_Int32 nElement, const OUString& _rValue );
+
+ /** controls whether |handleAttribute| implicitly calls |tryGenericAttribute|, or whether the derived class
+ must do this explicitly at a suitable place in its own |handleAttribute|
+ */
+ void disableImplicitGenericAttributeHandling() { m_bImplicitGenericAttributeHandling = false; }
+
+ private:
+ OUString implGetDefaultName() const;
+ void implApplyGenericProperties();
+ void implApplySpecificProperties();
+
+ PropertyGroups::const_iterator impl_matchPropertyGroup( const PropertyGroups& i_propertyGroups ) const;
+
+ virtual OUString determineDefaultServiceName() const;
+ };
+
+ //= OControlImport
+ /** helper class for importing the description of a single control
+ */
+ class OControlImport
+ :public OElementImport
+ ,public OValuePropertiesMetaData
+ {
+ protected:
+ OUString m_sControlId;
+ OControlElement::ElementType m_eElementType;
+
+ PropertyValueArray m_aValueProperties;
+ // the value properties (value, current-value, min-value, max-value) require some special
+ // handling
+
+ // we fake the attributes our base class gets: we add the attributes of the outer wrapper
+ // element which encloses us
+ css::uno::Reference< css::xml::sax::XFastAttributeList >
+ m_xOuterAttributes;
+
+ /** the address of the calc cell which the control model should be bound to,
+ if applicable
+ */
+ OUString m_sBoundCellAddress;
+
+ /** name of a value binding (xforms:bind attribute) */
+ OUString m_sBindingID;
+
+ /** name of a list binding (form:xforms-list-source attribute) */
+ OUString m_sListBindingID;
+
+ /** name of a submission (xforms:submission attribute) */
+ OUString m_sSubmissionID;
+
+ protected:
+ // for use by derived classes only
+ OControlImport(
+ OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer
+ );
+
+ public:
+ OControlImport(
+ OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType
+ );
+
+ // SvXMLImportContext overridables
+ virtual void SAL_CALL startFastElement( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+
+ // OPropertyImport overridables
+ virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override;
+
+ void addOuterAttributes(const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxOuterAttribs);
+
+ protected:
+ void setElementType(OControlElement::ElementType _eType) { m_eElementType = _eType; }
+
+ protected:
+ static void implTranslateValueProperty(
+ const css::uno::Reference< css::beans::XPropertySetInfo >& _rxPropInfo,
+ css::beans::PropertyValue& /* [in/out] */ _rPropValue);
+
+ virtual OUString determineDefaultServiceName() const override;
+
+ /** registers the given cell address as value binding address for our element
+
+ <p>The default implementation simply calls registerCellValueBinding at our import
+ context, but you may want to override this behaviour.</p>
+
+ @param _rBoundCellAddress
+ the cell address to register for our element. Must not be <NULL/>.
+ @precond
+ we have a valid element (m_xElement)
+ */
+ virtual void doRegisterCellValueBinding( const OUString& _rBoundCellAddress );
+
+ /** register the given XForms binding */
+ void doRegisterXFormsValueBinding( const OUString& );
+
+ /** register the given XForms list binding */
+ void doRegisterXFormsListBinding( const OUString& );
+
+ /** register the given XForms submission */
+ void doRegisterXFormsSubmission( const OUString& );
+
+ protected:
+
+ // OElementImport overridables
+ virtual css::uno::Reference< css::beans::XPropertySet >
+ createElement() override;
+ };
+
+ // TODO:
+ // this whole mechanism doesn't scale. Instead of deriving even more classes for every new attribute,
+ // we should have dedicated attribute handlers
+ // The rest of xmloff implements it this way - why don't we do, too?
+
+ //= OImagePositionImport
+ class OImagePositionImport : public OControlImport
+ {
+ css::uno::Reference<css::graphic::XGraphic> m_xGraphic;
+ sal_Int16 m_nImagePosition;
+ sal_Int16 m_nImageAlign;
+ bool m_bHaveImagePosition;
+
+ public:
+ OImagePositionImport(
+ OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType
+ );
+
+ protected:
+ // SvXMLImportContext overridables
+ virtual void SAL_CALL startFastElement(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) override;
+
+ // OPropertyImport overridables
+ virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override;
+ };
+
+ //= OReferredControlImport
+ class OReferredControlImport : public OControlImport
+ {
+ OUString m_sReferringControls; // the list of ids of controls referring to the one being imported
+
+ public:
+ OReferredControlImport(
+ OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer
+ );
+
+ // SvXMLImportContext overridables
+ virtual void SAL_CALL startFastElement(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) override;
+
+ // OPropertyImport overridables
+ virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override;
+ };
+
+ //= OPasswordImport
+ class OPasswordImport : public OControlImport
+ {
+ public:
+ OPasswordImport(
+ OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType
+ );
+
+ // OPropertyImport overridables
+ virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override;
+ };
+
+ //= ORadioImport
+ class ORadioImport : public OImagePositionImport
+ {
+ public:
+ ORadioImport(
+ OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType
+ );
+
+ protected:
+ // OPropertyImport overridables
+ virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override;
+ };
+
+ //= OURLReferenceImport
+ /** a specialized version of the <type>OControlImport</type> class, which is able
+ to handle attributes which denote URLs (and stored relative)
+ */
+ class OURLReferenceImport : public OImagePositionImport
+ {
+ public:
+ OURLReferenceImport(
+ OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType
+ );
+
+ protected:
+ // OPropertyImport overridables
+ virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override;
+ };
+
+ //= OButtonImport
+ /** A specialized version of the <type>OControlImport</type> class, which handles
+ the target frame for image and command buttons
+ */
+ class OButtonImport : public OURLReferenceImport
+ {
+ public:
+ OButtonImport(
+ OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType
+ );
+
+ protected:
+ // SvXMLImportContext overridables
+ virtual void SAL_CALL startFastElement(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) override;
+ };
+
+ //= OValueRangeImport
+ /** A specialized version of the <type>OControlImport</type> class, which imports
+ the value-range elements
+ */
+ class OValueRangeImport : public OControlImport
+ {
+ private:
+ sal_Int32 m_nStepSizeValue;
+
+ public:
+ OValueRangeImport(
+ OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType
+ );
+
+ protected:
+ // SvXMLImportContext overridables
+ virtual void SAL_CALL startFastElement(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList ) override;
+
+ // OPropertyImport overridables
+ virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override;
+ };
+
+ //= OTextLikeImport
+ /** A specialized version of the <type>OControlImport</type> class, which handles
+ text like controls which have the convert-empty-to-null attribute</p>
+ */
+ class OTextLikeImport : public OControlImport
+ {
+ private:
+ css::uno::Reference< css::text::XTextCursor > m_xCursor;
+ css::uno::Reference< css::text::XTextCursor > m_xOldCursor;
+ bool m_bEncounteredTextPara;
+
+ public:
+ OTextLikeImport(
+ OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType
+ );
+
+ // SvXMLImportContext overridables
+ virtual void SAL_CALL startFastElement(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) override;
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+
+ private:
+ void adjustDefaultControlProperty();
+ void removeRedundantCurrentValue();
+ };
+
+ //= OListAndComboImport
+ /** A specialized version of the <type>OControlImport</type> class, which handles
+ attributes / sub elements which are special to list and combo boxes
+ */
+ class OListAndComboImport : public OControlImport
+ {
+ friend class OListOptionImport;
+ friend class OComboItemImport;
+
+ protected:
+ std::vector<OUString >
+ m_aListSource;
+ std::vector< OUString >
+ m_aValueList;
+
+ std::vector< sal_Int16 >
+ m_aSelectedSeq;
+ std::vector< sal_Int16 >
+ m_aDefaultSelectedSeq;
+
+ OUString m_sCellListSource; /// the cell range which acts as list source for the control
+
+ sal_Int32 m_nEmptyListItems; /// number of empty list items encountered during reading
+ sal_Int32 m_nEmptyValueItems; /// number of empty value items encountered during reading
+
+ bool m_bEncounteredLSAttrib;
+ bool m_bLinkWithIndexes; /** <TRUE/> if and only if we should use a cell value binding
+ which exchanges the selection index (instead of the selection text
+ */
+
+ public:
+ OListAndComboImport(
+ OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType
+ );
+
+ // SvXMLImportContext overridables
+ virtual void SAL_CALL startFastElement( sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override;
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+
+ // OPropertyImport overridables
+ virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override;
+
+ // OControlImport overridables
+ virtual void doRegisterCellValueBinding( const OUString& _rBoundCellAddress ) override;
+
+ protected:
+ void implPushBackLabel(const OUString& _rLabel);
+ void implPushBackValue(const OUString& _rValue);
+
+ void implEmptyLabelFound();
+ void implEmptyValueFound();
+
+ void implSelectCurrentItem();
+ void implDefaultSelectCurrentItem();
+ };
+ typedef rtl::Reference<OListAndComboImport> OListAndComboImportRef;
+
+ //= OListOptionImport
+ /** helper class for importing a single &lt;form:option&gt; element.
+ */
+ class OListOptionImport
+ :public SvXMLImportContext
+ {
+ OListAndComboImportRef m_xListBoxImport;
+
+ public:
+ OListOptionImport(SvXMLImport& _rImport,
+ const OListAndComboImportRef& _rListBox);
+
+ virtual void SAL_CALL startFastElement( sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override;
+ };
+
+ //= OComboItemImport
+ /** helper class for importing a single &lt;form:item&gt; element.
+ */
+ class OComboItemImport
+ :public SvXMLImportContext
+ {
+ OListAndComboImportRef m_xListBoxImport;
+
+ public:
+ OComboItemImport(SvXMLImport& _rImport,
+ const OListAndComboImportRef& _rListBox);
+
+ protected:
+ // SvXMLImportContext overridables
+ virtual void SAL_CALL startFastElement( sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override;
+ };
+
+
+ //= OColumnImport
+ /** helper class importing a single grid column (without the &lt;form:column&gt; element wrapping
+ the column).
+
+ <p>BASE (the template argument) must be a derivee of OControlImport</p>
+ */
+ template <class BASE>
+ class OColumnImport : public BASE
+ {
+ css::uno::Reference< css::form::XGridColumnFactory >
+ m_xColumnFactory;
+
+ public:
+ OColumnImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType);
+
+ protected:
+ // OElementImport overridables
+ virtual css::uno::Reference< css::beans::XPropertySet >
+ createElement() override;
+ };
+
+ //= OColumnWrapperImport
+ class OColumnWrapperImport : public SvXMLImportContext
+ {
+ css::uno::Reference< css::xml::sax::XFastAttributeList >
+ m_xOwnAttributes;
+ css::uno::Reference< css::container::XNameContainer >
+ m_xParentContainer;
+ OFormLayerXMLImport_Impl& m_rFormImport;
+ IEventAttacherManager& m_rEventManager;
+
+ public:
+ OColumnWrapperImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ sal_Int32 nElement,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer);
+
+ // SvXMLImportContext overridables
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+ virtual void SAL_CALL startFastElement(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) override;
+ private:
+ OControlImport* implCreateChildContext(
+ sal_Int32 nElement,
+ OControlElement::ElementType _eType);
+ };
+
+ /** helper class importing a single &lt;form:grid&gt; element
+ */
+ class OGridImport : public OControlImport, public ODefaultEventAttacherManager
+ {
+ public:
+ OGridImport(
+ OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType);
+
+ // SvXMLImportContext overridables
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+
+ private:
+ // OElementImport overridables
+ virtual css::uno::Reference< css::beans::XPropertySet > createElement() override;
+
+ css::uno::Reference< css::container::XNameContainer > m_xMeAsContainer;
+ };
+
+ /** helper class importing a single &lt;form:form&gt; element
+ */
+ class OFormImport : public OElementImport, public ODefaultEventAttacherManager
+ {
+ public:
+ OFormImport(
+ OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer
+ );
+
+ private:
+ // SvXMLImportContext overridables
+ virtual void SAL_CALL startFastElement(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList) override;
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+
+ // OPropertyImport overridables
+ virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override;
+
+ // OElementImport overridables
+ virtual css::uno::Reference< css::beans::XPropertySet >
+ createElement() override;
+
+ virtual OUString determineDefaultServiceName() const override;
+ void implTranslateStringListProperty(const OUString& _rPropertyName, const OUString& _rValue);
+
+ css::uno::Reference< css::container::XNameContainer > m_xMeAsContainer;
+ };
+
+ //= OXMLDataSourceImport
+ class OXMLDataSourceImport : public SvXMLImportContext
+ {
+ public:
+ OXMLDataSourceImport( SvXMLImport& _rImport
+ ,const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList
+ ,const css::uno::Reference< css::beans::XPropertySet >& _xElement);
+ };
+
+ //= OColumnImport
+ template <class BASE>
+ OColumnImport< BASE >::OColumnImport(OFormLayerXMLImport_Impl& _rImport,
+ IEventAttacherManager& _rEventManager,
+ const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer,
+ OControlElement::ElementType _eType)
+ :BASE(_rImport, _rEventManager, _rxParentContainer, _eType)
+ ,m_xColumnFactory(_rxParentContainer, css::uno::UNO_QUERY)
+ {
+ OSL_ENSURE(m_xColumnFactory.is(), "OColumnImport::OColumnImport: invalid parent container (no factory)!");
+ }
+
+ // OElementImport overridables
+ template <class BASE>
+ css::uno::Reference< css::beans::XPropertySet > OColumnImport< BASE >::createElement()
+ {
+ css::uno::Reference< css::beans::XPropertySet > xReturn;
+ // no call to the base class' method. We have to use the grid column factory
+ if (m_xColumnFactory.is())
+ {
+ // create the column
+ xReturn = m_xColumnFactory->createColumn(this->m_sServiceName);
+ OSL_ENSURE(xReturn.is(), "OColumnImport::createElement: the factory returned an invalid object!");
+ }
+ return xReturn;
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/eventexport.cxx b/xmloff/source/forms/eventexport.cxx
new file mode 100644
index 000000000..25548fb0a
--- /dev/null
+++ b/xmloff/source/forms/eventexport.cxx
@@ -0,0 +1,126 @@
+/* -*- 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 "eventexport.hxx"
+#include "strings.hxx"
+#include <comphelper/sequence.hxx>
+#include <sal/log.hxx>
+
+namespace xmloff
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::lang;
+
+ //= OEventDescriptorMapper
+ OEventDescriptorMapper::OEventDescriptorMapper(const Sequence< ScriptEventDescriptor >& _rEvents)
+ {
+ // translate the events
+ OUString sLibrary, sLocalMacroName;
+ for (const auto& rEvent : _rEvents)
+ {
+ // the name of the event is build from listener interface and listener method name
+ OUString sName = rEvent.ListenerType
+ + EVENT_NAME_SEPARATOR
+ + rEvent.EventMethod;
+
+ Sequence< PropertyValue >& rMappedEvent = m_aMappedEvents[sName];
+
+ sLocalMacroName = rEvent.ScriptCode;
+ sLibrary.clear();
+ if (rEvent.ScriptType == EVENT_STARBASIC)
+ { // for StarBasic, the library name is part of the ScriptCode
+ sal_Int32 nPrefixLen = sLocalMacroName.indexOf( ':' );
+ SAL_WARN_IF( 0 > nPrefixLen, "xmloff", "OEventDescriptorMapper::OEventDescriptorMapper: invalid script code prefix!" );
+ if ( 0 <= nPrefixLen )
+ {
+ // the export handler for StarBasic expects "StarOffice", not "application" for application modules ...
+ sLibrary = sLocalMacroName.copy( 0, nPrefixLen );
+ if (sLibrary == EVENT_APPLICATION)
+ sLibrary = EVENT_STAROFFICE;
+
+ sLocalMacroName = sLocalMacroName.copy( nPrefixLen + 1 );
+ }
+ // tree property values to describe one event ...
+ rMappedEvent.realloc( sLibrary.isEmpty() ? 2 : 3 );
+ auto pMappedEvent = rMappedEvent.getArray();
+
+ // ... the type
+ pMappedEvent[0] = PropertyValue(EVENT_TYPE, -1, Any(rEvent.ScriptType), PropertyState_DIRECT_VALUE);
+
+ // and the macro name
+ pMappedEvent[1] = PropertyValue(EVENT_LOCALMACRONAME, -1, Any(sLocalMacroName), PropertyState_DIRECT_VALUE);
+
+ // the library
+ if ( !sLibrary.isEmpty() )
+ pMappedEvent[2] = PropertyValue(EVENT_LIBRARY, -1, Any(sLibrary), PropertyState_DIRECT_VALUE);
+ }
+ else
+ {
+ rMappedEvent = { PropertyValue(EVENT_TYPE, -1, Any(rEvent.ScriptType), PropertyState_DIRECT_VALUE),
+ // and the macro name
+ PropertyValue(EVENT_SCRIPTURL, -1, Any(rEvent.ScriptCode), PropertyState_DIRECT_VALUE) };
+ }
+ }
+ }
+
+ void SAL_CALL OEventDescriptorMapper::replaceByName( const OUString&, const Any& )
+ {
+ throw IllegalArgumentException(
+ "replacing is not implemented for this wrapper class.", static_cast< ::cppu::OWeakObject* >(this), 1);
+ }
+
+ Any SAL_CALL OEventDescriptorMapper::getByName( const OUString& _rName )
+ {
+ MapString2PropertyValueSequence::const_iterator aPos = m_aMappedEvents.find(_rName);
+ if (m_aMappedEvents.end() == aPos)
+ throw NoSuchElementException(
+ "There is no element named " + _rName,
+ static_cast< ::cppu::OWeakObject* >(this));
+
+ return Any(aPos->second);
+ }
+
+ Sequence< OUString > SAL_CALL OEventDescriptorMapper::getElementNames( )
+ {
+ return comphelper::mapKeysToSequence(m_aMappedEvents);
+ }
+
+ sal_Bool SAL_CALL OEventDescriptorMapper::hasByName( const OUString& _rName )
+ {
+ MapString2PropertyValueSequence::const_iterator aPos = m_aMappedEvents.find(_rName);
+ return m_aMappedEvents.end() != aPos;
+ }
+
+ Type SAL_CALL OEventDescriptorMapper::getElementType( )
+ {
+ return ::cppu::UnoType<PropertyValue>::get();
+ }
+
+ sal_Bool SAL_CALL OEventDescriptorMapper::hasElements( )
+ {
+ return !m_aMappedEvents.empty();
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/eventexport.hxx b/xmloff/source/forms/eventexport.hxx
new file mode 100644
index 000000000..c4bb752c4
--- /dev/null
+++ b/xmloff/source/forms/eventexport.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 <sal/config.h>
+
+#include <map>
+
+#include <com/sun/star/container/XNameReplace.hpp>
+#include <com/sun/star/script/ScriptEventDescriptor.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <cppuhelper/implbase.hxx>
+
+namespace xmloff
+{
+
+ //= OEventDescriptorMapper
+ typedef ::cppu::WeakImplHelper < css::container::XNameReplace
+ > OEventDescriptorMapper_Base;
+ /** helper class wrapping different script event representations
+
+ <p>In the form layer, the script events are represented by <type scope="com.sun.star.script">ScriptEventDescriptor</type>
+ instances. The office applications, on the other hand, represent their a single script event as sequence
+ of <type scope="com.sun.star.beans">PropertyValue</type>s, where all events of a given object are
+ accessible through a <type scope="com.sun.star.container">XNameReplace</type> interface.</p>
+ <p>This class maps the first representation of events of a single object to the second one.</p>
+ <p>This way, we can use the helper classes here in the project.</p>
+ */
+ class OEventDescriptorMapper : public OEventDescriptorMapper_Base
+ {
+ typedef std::map< OUString, css::uno::Sequence < css::beans::PropertyValue > > MapString2PropertyValueSequence;
+ MapString2PropertyValueSequence m_aMappedEvents;
+
+ public:
+ explicit OEventDescriptorMapper(
+ const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents);
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override;
+
+ // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+ };
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/eventimport.cxx b/xmloff/source/forms/eventimport.cxx
new file mode 100644
index 000000000..02bfe7764
--- /dev/null
+++ b/xmloff/source/forms/eventimport.cxx
@@ -0,0 +1,135 @@
+/* -*- 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 "eventimport.hxx"
+#include <com/sun/star/script/XEventAttacherManager.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <osl/diagnose.h>
+#include "strings.hxx"
+
+namespace xmloff
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::container;
+
+ //= OFormEventsImportContext
+ OFormEventsImportContext::OFormEventsImportContext(SvXMLImport& _rImport, IEventAttacher& _rEventAttacher)
+ :XMLEventsImportContext(_rImport)
+ ,m_rEventAttacher(_rEventAttacher)
+ {
+ }
+
+ void OFormEventsImportContext::endFastElement(sal_Int32 )
+ {
+ Sequence< ScriptEventDescriptor > aTranslated(aCollectEvents.size());
+ ScriptEventDescriptor* pTranslated = aTranslated.getArray();
+
+ // loop through the collected events and translate them
+ sal_Int32 nSeparatorPos = -1;
+ for ( const auto& rEvent : aCollectEvents )
+ {
+ // the name of the event is built from ListenerType::EventMethod
+ nSeparatorPos = rEvent.first.indexOf(EVENT_NAME_SEPARATOR);
+ OSL_ENSURE(-1 != nSeparatorPos, "OFormEventsImportContext::EndElement: invalid (unrecognized) event name!");
+ pTranslated->ListenerType = rEvent.first.copy(0, nSeparatorPos);
+ pTranslated->EventMethod = rEvent.first.copy(nSeparatorPos + sizeof(EVENT_NAME_SEPARATOR) - 1);
+
+ OUString sLibrary;
+
+ // the local macro name and the event type are specified as properties
+ const PropertyValue* pEventDescription = rEvent.second.getConstArray();
+ const PropertyValue* pEventDescriptionEnd = pEventDescription + rEvent.second.getLength();
+ for (;pEventDescription != pEventDescriptionEnd; ++pEventDescription)
+ {
+ if (pEventDescription->Name == EVENT_LOCALMACRONAME ||
+ pEventDescription->Name == EVENT_SCRIPTURL)
+ pEventDescription->Value >>= pTranslated->ScriptCode;
+ else if (pEventDescription->Name == EVENT_TYPE)
+ pEventDescription->Value >>= pTranslated->ScriptType;
+ else if (pEventDescription->Name == EVENT_LIBRARY)
+ pEventDescription->Value >>= sLibrary;
+ }
+
+ if (pTranslated->ScriptType == EVENT_STARBASIC)
+ {
+ if (sLibrary == EVENT_STAROFFICE)
+ sLibrary = EVENT_APPLICATION;
+
+ if ( !sLibrary.isEmpty() )
+ {
+ // for StarBasic, the library is prepended
+ sLibrary += ":";
+ }
+ sLibrary += pTranslated->ScriptCode;
+ pTranslated->ScriptCode = sLibrary;
+ }
+
+ ++pTranslated;
+ }
+
+ // register the events
+ m_rEventAttacher.registerEvents(aTranslated);
+ }
+
+ //= ODefaultEventAttacherManager
+
+ ODefaultEventAttacherManager::~ODefaultEventAttacherManager()
+ {
+ }
+
+ void ODefaultEventAttacherManager::registerEvents(const Reference< XPropertySet >& _rxElement,
+ const Sequence< ScriptEventDescriptor >& _rEvents)
+ {
+ OSL_ENSURE(m_aEvents.end() == m_aEvents.find(_rxElement),
+ "ODefaultEventAttacherManager::registerEvents: already have events for this object!");
+ // for the moment, only remember the script events
+ m_aEvents[_rxElement] = _rEvents;
+ }
+
+ void ODefaultEventAttacherManager::setEvents(const Reference< XIndexAccess >& _rxContainer)
+ {
+ Reference< XEventAttacherManager > xEventManager(_rxContainer, UNO_QUERY);
+ if (!xEventManager.is())
+ {
+ OSL_FAIL("ODefaultEventAttacherManager::setEvents: invalid argument!");
+ return;
+ }
+
+ // loop through all elements
+ sal_Int32 nCount = _rxContainer->getCount();
+ Reference< XPropertySet > xCurrent;
+ MapPropertySet2ScriptSequence::const_iterator aRegisteredEventsPos;
+ for (sal_Int32 i=0; i<nCount; ++i)
+ {
+ xCurrent.set(_rxContainer->getByIndex(i), css::uno::UNO_QUERY);
+ if (xCurrent.is())
+ {
+ aRegisteredEventsPos = m_aEvents.find(xCurrent);
+ if (m_aEvents.end() != aRegisteredEventsPos)
+ xEventManager->registerScriptEvents(i, aRegisteredEventsPos->second);
+ }
+ }
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/eventimport.hxx b/xmloff/source/forms/eventimport.hxx
new file mode 100644
index 000000000..6e3f686df
--- /dev/null
+++ b/xmloff/source/forms/eventimport.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+
+#include <xmloff/XMLEventsImportContext.hxx>
+#include "callbacks.hxx"
+#include <com/sun/star/container/XIndexAccess.hpp>
+
+class SvXMLImport;
+namespace xmloff
+{
+
+ //= OFormEventsImportContext
+ class OFormEventsImportContext : public XMLEventsImportContext
+ {
+ IEventAttacher& m_rEventAttacher;
+
+ public:
+ OFormEventsImportContext(SvXMLImport& _rImport,
+ IEventAttacher& _rEventAttacher);
+
+ protected:
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+ };
+
+ //= ODefaultEventAttacherManager
+ class ODefaultEventAttacherManager : public IEventAttacherManager
+ {
+ typedef std::map<
+ css::uno::Reference< css::beans::XPropertySet >,
+ css::uno::Sequence< css::script::ScriptEventDescriptor >>
+ MapPropertySet2ScriptSequence;
+ // usually an event attacher manager will need to collect all script events registered, 'cause
+ // the _real_ XEventAttacherManager handles it's events by index, but out indices are not fixed
+ // until _all_ controls have been inserted.
+
+ MapPropertySet2ScriptSequence m_aEvents;
+
+ public:
+ // IEventAttacherManager
+ virtual void registerEvents(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxElement,
+ const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents
+ ) override;
+
+ protected:
+ void setEvents(
+ const css::uno::Reference< css::container::XIndexAccess >& _rxContainer
+ );
+
+ virtual ~ODefaultEventAttacherManager();
+ };
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/formattributes.cxx b/xmloff/source/forms/formattributes.cxx
new file mode 100644
index 000000000..6b7b3fb9f
--- /dev/null
+++ b/xmloff/source/forms/formattributes.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 "formattributes.hxx"
+
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmluconv.hxx>
+#include <xmloff/xmlimp.hxx>
+#include <osl/diagnose.h>
+
+using namespace xmloff::token;
+
+namespace xmloff
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+
+ //= OAttributeMetaData
+ OUString OAttributeMetaData::getCommonControlAttributeName(CCAFlags _nId)
+ {
+ switch (_nId)
+ {
+ case CCAFlags::Name: return "name";
+ case CCAFlags::ServiceName: return "control-implementation";
+ case CCAFlags::ButtonType: return "button-type";
+// disabled(AddAttributeIdLegacy) case CCAFlags::ControlId: return "id";
+ case CCAFlags::CurrentSelected: return "current-selected";
+ case CCAFlags::CurrentValue: return "current-value";
+ case CCAFlags::Disabled: return "disabled";
+ case CCAFlags::EnableVisible: return "visible";
+ case CCAFlags::Dropdown: return "dropdown";
+ case CCAFlags::For: return "for";
+ case CCAFlags::ImageData: return "image-data";
+ case CCAFlags::Label: return "label";
+ case CCAFlags::MaxLength: return "max-length";
+ case CCAFlags::Printable: return "printable";
+ case CCAFlags::ReadOnly: return "readonly";
+ case CCAFlags::Selected: return "selected";
+ case CCAFlags::Size: return "size";
+ case CCAFlags::TabIndex: return "tab-index";
+ case CCAFlags::TargetFrame: return "target-frame";
+ case CCAFlags::TargetLocation: return "href"; // the only special thing here: TargetLocation is represented by an xlink:href attribute
+ case CCAFlags::TabStop: return "tab-stop";
+ case CCAFlags::Title: return "title";
+ case CCAFlags::Value: return "value";
+ case CCAFlags::Orientation: return "orientation";
+ case CCAFlags::VisualEffect: return "visual-effect";
+ default:
+ OSL_FAIL("OAttributeMetaData::getCommonControlAttributeName: invalid id (maybe you or-ed two flags?)!");
+ }
+ return "";
+ }
+
+ sal_Int32 OAttributeMetaData::getCommonControlAttributeToken(CCAFlags _nId)
+ {
+ switch (_nId)
+ {
+ case CCAFlags::Name: return XML_NAME;
+ case CCAFlags::ServiceName: return XML_CONTROL_IMPLEMENTATION;
+ case CCAFlags::ButtonType: return XML_BUTTON_TYPE;
+// disabled(AddAttributeIdLegacy) case CCAFlags::ControlId: return "id";
+ case CCAFlags::CurrentSelected: return XML_CURRENT_SELECTED;
+ case CCAFlags::CurrentValue: return XML_CURRENT_VALUE;
+ case CCAFlags::Disabled: return XML_DISABLED;
+ case CCAFlags::EnableVisible: return XML_VISIBLE;
+ case CCAFlags::Dropdown: return XML_DROPDOWN;
+ case CCAFlags::For: return XML_FOR;
+ case CCAFlags::ImageData: return XML_IMAGE_DATA;
+ case CCAFlags::Label: return XML_LABEL;
+ case CCAFlags::MaxLength: return XML_MAX_LENGTH;
+ case CCAFlags::Printable: return XML_PRINTABLE;
+ case CCAFlags::ReadOnly: return XML_READONLY;
+ case CCAFlags::Selected: return XML_SELECTED;
+ case CCAFlags::Size: return XML_SIZE;
+ case CCAFlags::TabIndex: return XML_TAB_INDEX;
+ case CCAFlags::TargetFrame: return XML_TARGET_FRAME;
+ case CCAFlags::TargetLocation: return XML_HREF; // the only special thing here: TargetLocation is represented by an xlink:href attribute
+ case CCAFlags::TabStop: return XML_TAB_STOP;
+ case CCAFlags::Title: return XML_TITLE;
+ case CCAFlags::Value: return XML_VALUE;
+ case CCAFlags::Orientation: return XML_ORIENTATION;
+ case CCAFlags::VisualEffect: return XML_VISUAL_EFFECT;
+ default:
+ assert(false && "OAttributeMetaData::getCommonControlAttributeName: invalid id (maybe you or-ed two flags?)!");
+ }
+ return XML_UNKNOWN;
+ }
+
+ sal_uInt16 OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags _nId)
+ {
+ if (CCAFlags::TargetLocation == _nId)
+ return XML_NAMESPACE_XLINK;
+
+ if (CCAFlags::TargetFrame == _nId)
+ return XML_NAMESPACE_OFFICE;
+
+ return XML_NAMESPACE_FORM;
+ }
+
+ OUString OAttributeMetaData::getFormAttributeName(FormAttributes _eAttrib)
+ {
+ switch (_eAttrib)
+ {
+ case faName: return "name";
+ case faAction: return "href"; // the only special thing here: Action is represented by an xlink:href attribute
+ case faEnctype: return "enctype";
+ case faMethod: return "method";
+ case faAllowDeletes: return "allow-deletes";
+ case faAllowInserts: return "allow-inserts";
+ case faAllowUpdates: return "allow-updates";
+ case faApplyFilter: return "apply-filter";
+ case faCommand: return "command";
+ case faCommandType: return "command-type";
+ case faEscapeProcessing: return "escape-processing";
+ case faDatasource: return "datasource";
+ case faDetailFields: return "detail-fields";
+ case faFilter: return "filter";
+ case faIgnoreResult: return "ignore-result";
+ case faMasterFields: return "master-fields";
+ case faNavigationMode: return "navigation-mode";
+ case faOrder: return "order";
+ case faTabbingCycle: return "tab-cycle";
+ default:
+ OSL_FAIL("OAttributeMetaData::getFormAttributeName: invalid id!");
+ }
+ return "";
+ }
+
+ sal_Int32 OAttributeMetaData::getFormAttributeToken(FormAttributes _eAttrib)
+ {
+ switch (_eAttrib)
+ {
+ case faName: return XML_NAME;
+ case faAction: return XML_HREF; // the only special thing here: Action is represented by an xlink:href attribute
+ case faEnctype: return XML_ENCTYPE;
+ case faMethod: return XML_METHOD;
+ case faAllowDeletes: return XML_ALLOW_DELETES;
+ case faAllowInserts: return XML_ALLOW_INSERTS;
+ case faAllowUpdates: return XML_ALLOW_UPDATES;
+ case faApplyFilter: return XML_APPLY_FILTER;
+ case faCommand: return XML_COMMAND;
+ case faCommandType: return XML_COMMAND_TYPE;
+ case faEscapeProcessing: return XML_ESCAPE_PROCESSING;
+ case faDatasource: return XML_DATASOURCE;
+ case faDetailFields: return XML_DETAIL_FIELDS;
+ case faFilter: return XML_FILTER;
+ case faIgnoreResult: return XML_IGNORE_RESULT;
+ case faMasterFields: return XML_MASTER_FIELDS;
+ case faNavigationMode: return XML_NAVIGATION_MODE;
+ case faOrder: return XML_ORDER;
+ case faTabbingCycle: return XML_TAB_CYCLE;
+ default:
+ assert(false && "OAttributeMetaData::getFormAttributeName: invalid id!");
+ }
+ return XML_NONE;
+ }
+
+ sal_uInt16 OAttributeMetaData::getFormAttributeNamespace(FormAttributes _eAttrib)
+ {
+ if (faAction == _eAttrib)
+ return XML_NAMESPACE_XLINK;
+
+ return XML_NAMESPACE_FORM;
+ }
+
+ OUString OAttributeMetaData::getDatabaseAttributeName(DAFlags _nId)
+ {
+ switch (_nId)
+ {
+ case DAFlags::BoundColumn: return "bound-column";
+ case DAFlags::ConvertEmpty: return "convert-empty-to-null";
+ case DAFlags::DataField: return "data-field";
+ case DAFlags::ListSource: return "list-source";
+ case DAFlags::ListSource_TYPE: return "list-source-type";
+ case DAFlags::InputRequired: return "input-required";
+ default:
+ OSL_FAIL("OAttributeMetaData::getDatabaseAttributeName: invalid id (maybe you or-ed two flags?)!");
+ }
+ return "";
+ }
+
+ sal_Int32 OAttributeMetaData::getDatabaseAttributeToken(DAFlags _nId)
+ {
+ switch (_nId)
+ {
+ case DAFlags::BoundColumn: return XML_BOUND_COLUMN;
+ case DAFlags::ConvertEmpty: return XML_CONVERT_EMPTY_TO_NULL;
+ case DAFlags::DataField: return XML_DATA_FIELD;
+ case DAFlags::ListSource: return XML_LIST_SOURCE;
+ case DAFlags::ListSource_TYPE: return XML_LIST_SOURCE_TYPE;
+ case DAFlags::InputRequired: return XML_INPUT_REQUIRED;
+ default:
+ assert(false && "OAttributeMetaData::getDatabaseAttributeName: invalid id (maybe you or-ed two flags?)!");
+ }
+ return XML_NONE;
+ }
+
+ OUString OAttributeMetaData::getBindingAttributeName(BAFlags _nId)
+ {
+ switch (_nId)
+ {
+ case BAFlags::LinkedCell: return "linked-cell";
+ case BAFlags::ListLinkingType: return "list-linkage-type";
+ case BAFlags::ListCellRange: return "source-cell-range";
+ default:
+ OSL_FAIL("OAttributeMetaData::getBindingAttributeName: invalid id (maybe you or-ed two flags?)!");
+ }
+ return "";
+ }
+
+ sal_Int32 OAttributeMetaData::getBindingAttributeToken(BAFlags _nId)
+ {
+ switch (_nId)
+ {
+ case BAFlags::LinkedCell: return XML_LINKED_CELL;
+ case BAFlags::ListLinkingType: return XML_LIST_LINKAGE_TYPE;
+ case BAFlags::ListCellRange: return XML_SOURCE_CELL_RANGE;
+ default:
+ assert(false && "OAttributeMetaData::getBindingAttributeName: invalid id (maybe you or-ed two flags?)!");
+ }
+ return XML_UNKNOWN;
+ }
+
+ OUString OAttributeMetaData::getSpecialAttributeName(SCAFlags _nId)
+ {
+ switch (_nId)
+ {
+ case SCAFlags::EchoChar: return "echo-char";
+ case SCAFlags::MaxValue: return "max-value";
+ case SCAFlags::MinValue: return "min-value";
+ case SCAFlags::Validation: return "validation";
+ case SCAFlags::GroupName: return "group-name";
+ case SCAFlags::MultiLine: return "multi-line";
+ case SCAFlags::AutoCompletion: return "auto-complete";
+ case SCAFlags::Multiple: return "multiple";
+ case SCAFlags::DefaultButton: return "default-button";
+ case SCAFlags::CurrentState: return "current-state";
+ case SCAFlags::IsTristate: return "is-tristate";
+ case SCAFlags::State: return "state";
+ case SCAFlags::ColumnStyleName: return "text-style-name";
+ case SCAFlags::StepSize: return "step-size";
+ case SCAFlags::PageStepSize: return "page-step-size";
+ case SCAFlags::RepeatDelay: return "delay-for-repeat";
+ case SCAFlags::Toggle: return "toggle";
+ case SCAFlags::FocusOnClick: return "focus-on-click";
+ default:
+ OSL_FAIL("OAttributeMetaData::getSpecialAttributeName: invalid id (maybe you or-ed two flags?)!");
+ }
+ return "";
+ }
+
+ sal_Int32 OAttributeMetaData::getSpecialAttributeToken(SCAFlags _nId)
+ {
+ switch (_nId)
+ {
+ case SCAFlags::EchoChar: return XML_ECHO_CHAR;
+ case SCAFlags::MaxValue: return XML_MAX_VALUE;
+ case SCAFlags::MinValue: return XML_MIN_VALUE;
+ case SCAFlags::Validation: return XML_VALIDATION;
+ case SCAFlags::GroupName: return XML_GROUP_NAME;
+ case SCAFlags::MultiLine: return XML_MULTI_LINE;
+ case SCAFlags::AutoCompletion: return XML_AUTO_COMPLETE;
+ case SCAFlags::Multiple: return XML_MULTIPLE;
+ case SCAFlags::DefaultButton: return XML_DEFAULT_BUTTON;
+ case SCAFlags::CurrentState: return XML_CURRENT_STATE;
+ case SCAFlags::IsTristate: return XML_IS_TRISTATE;
+ case SCAFlags::State: return XML_STATE;
+ case SCAFlags::ColumnStyleName: return XML_TEXT_STYLE_NAME;
+ case SCAFlags::StepSize: return XML_STEP_SIZE;
+ case SCAFlags::PageStepSize: return XML_PAGE_STEP_SIZE;
+ case SCAFlags::RepeatDelay: return XML_DELAY_FOR_REPEAT;
+ case SCAFlags::Toggle: return XML_TOGGLE;
+ case SCAFlags::FocusOnClick: return XML_FOCUS_ON_CLICK;
+ default:
+ assert(false && "OAttributeMetaData::getSpecialAttributeName: invalid id (maybe you or-ed two flags?)!");
+ }
+ return XML_UNKNOWN;
+ }
+
+ sal_uInt16 OAttributeMetaData::getSpecialAttributeNamespace(SCAFlags _nId)
+ {
+ switch( _nId )
+ {
+ case SCAFlags::GroupName: return XML_NAMESPACE_FORMX;
+ default: break;
+ }
+ return XML_NAMESPACE_FORM;
+ }
+
+ OUString OAttributeMetaData::getOfficeFormsAttributeName(OfficeFormsAttributes _eAttrib)
+ {
+ switch (_eAttrib)
+ {
+ case ofaAutomaticFocus: return "automatic-focus";
+ case ofaApplyDesignMode: return "apply-design-mode";
+ default:
+ OSL_FAIL("OAttributeMetaData::getOfficeFormsAttributeName: invalid id!");
+ }
+ return "";
+ }
+
+ xmloff::token::XMLTokenEnum OAttributeMetaData::getOfficeFormsAttributeToken(OfficeFormsAttributes _eAttrib)
+ {
+ switch (_eAttrib)
+ {
+ case ofaAutomaticFocus: return token::XML_AUTOMATIC_FOCUS;
+ case ofaApplyDesignMode: return token::XML_APPLY_DESIGN_MODE;
+ default:
+ assert(false && "OAttributeMetaData::getOfficeFormsAttributeName: invalid id!");
+ }
+ return token::XML_NONE;
+ }
+
+ //= OAttribute2Property
+ OAttribute2Property::OAttribute2Property()
+ {
+ }
+
+ OAttribute2Property::~OAttribute2Property()
+ {
+ }
+
+ const OAttribute2Property::AttributeAssignment* OAttribute2Property::getAttributeTranslation(
+ sal_Int32 nAttributeToken)
+ {
+ auto aPos = m_aKnownProperties.find(nAttributeToken & TOKEN_MASK);
+ if (m_aKnownProperties.end() != aPos)
+ return &aPos->second;
+ return nullptr;
+ }
+
+ void OAttribute2Property::addStringProperty(
+ sal_Int32 nAttributeToken, const OUString& _rPropertyName)
+ {
+ implAdd(nAttributeToken, _rPropertyName, ::cppu::UnoType<OUString>::get());
+ }
+
+ void OAttribute2Property::addBooleanProperty(
+ sal_Int32 nAttributeToken, const OUString& _rPropertyName,
+ const bool /*_bAttributeDefault*/, const bool _bInverseSemantics)
+ {
+ AttributeAssignment& aAssignment = implAdd(nAttributeToken, _rPropertyName, cppu::UnoType<bool>::get());
+ aAssignment.bInverseSemantics = _bInverseSemantics;
+ }
+
+ void OAttribute2Property::addInt16Property(
+ sal_Int32 nAttributeToken, const OUString& _rPropertyName)
+ {
+ implAdd(nAttributeToken, _rPropertyName, ::cppu::UnoType<sal_Int16>::get());
+ }
+
+ void OAttribute2Property::addInt32Property(
+ sal_Int32 nAttributeToken, const OUString& _rPropertyName)
+ {
+ implAdd( nAttributeToken, _rPropertyName, ::cppu::UnoType<sal_Int32>::get() );
+ }
+
+ void OAttribute2Property::addEnumPropertyImpl(
+ sal_Int32 nAttributeToken, const OUString& _rPropertyName,
+ const SvXMLEnumMapEntry<sal_uInt16>* _pValueMap,
+ const css::uno::Type* _pType)
+ {
+ AttributeAssignment& aAssignment = implAdd(nAttributeToken, _rPropertyName,
+ _pType ? *_pType : ::cppu::UnoType<sal_Int32>::get());
+ aAssignment.pEnumMap = _pValueMap;
+ }
+
+ OAttribute2Property::AttributeAssignment& OAttribute2Property::implAdd(
+ sal_Int32 nAttributeToken, const OUString& _rPropertyName,
+ const css::uno::Type& _rType)
+ {
+ nAttributeToken &= TOKEN_MASK;
+ OSL_ENSURE(m_aKnownProperties.end() == m_aKnownProperties.find(nAttributeToken),
+ "OAttribute2Property::implAdd: already have this attribute!");
+
+ AttributeAssignment aAssignment;
+ aAssignment.sPropertyName = _rPropertyName;
+ aAssignment.aPropertyType = _rType;
+
+ // redundance, the accessor is stored in aAssignment.sAttributeName, too
+ m_aKnownProperties[nAttributeToken] = aAssignment;
+ return m_aKnownProperties[nAttributeToken];
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/formattributes.hxx b/xmloff/source/forms/formattributes.hxx
new file mode 100644
index 000000000..ae36fd65d
--- /dev/null
+++ b/xmloff/source/forms/formattributes.hxx
@@ -0,0 +1,414 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+
+#include <com/sun/star/uno/Type.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <o3tl/typed_flags_set.hxx>
+
+template<typename EnumT>
+struct SvXMLEnumMapEntry;
+
+ // flags for common control attributes
+enum class CCAFlags {
+ NONE = 0x00000000,
+ Name = 0x00000001,
+ ServiceName = 0x00000002,
+ ButtonType = 0x00000004,
+ ControlId = 0x00000008,
+ CurrentSelected = 0x00000010,
+ CurrentValue = 0x00000020,
+ Disabled = 0x00000040,
+ Dropdown = 0x00000080,
+ For = 0x00000100,
+ ImageData = 0x00000200,
+ Label = 0x00000400,
+ MaxLength = 0x00000800,
+ Printable = 0x00001000,
+ ReadOnly = 0x00002000,
+ Selected = 0x00004000,
+ Size = 0x00008000,
+ TabIndex = 0x00010000,
+ TargetFrame = 0x00020000,
+ TargetLocation = 0x00040000,
+ TabStop = 0x00080000,
+ Title = 0x00100000,
+ Value = 0x00200000,
+ Orientation = 0x00400000,
+ VisualEffect = 0x00800000,
+ EnableVisible = 0x01000000,
+};
+namespace o3tl {
+ template<> struct typed_flags<CCAFlags> : is_typed_flags<CCAFlags, 0x01ffffff> {};
+}
+
+ // flags for database control attributes
+enum class DAFlags {
+ NONE = 0x0000,
+ BoundColumn = 0x0001,
+ ConvertEmpty = 0x0002,
+ DataField = 0x0004,
+ ListSource = 0x0008,
+ ListSource_TYPE = 0x0010,
+ InputRequired = 0x0020,
+};
+namespace o3tl {
+ template<> struct typed_flags<DAFlags> : is_typed_flags<DAFlags, 0x003f> {};
+}
+
+ // flags for binding related control attributes
+enum class BAFlags {
+ NONE = 0x0000,
+ LinkedCell = 0x0001,
+ ListLinkingType = 0x0002,
+ ListCellRange = 0x0004,
+ XFormsBind = 0x0008,
+ XFormsListBind = 0x0010,
+ XFormsSubmission = 0x0020
+};
+namespace o3tl {
+ template<> struct typed_flags<BAFlags> : is_typed_flags<BAFlags, 0x003f> {};
+}
+
+ // flags for event attributes
+enum class EAFlags {
+ NONE = 0x0000,
+ ControlEvents = 0x0001,
+ OnChange = 0x0002,
+ OnClick = 0x0004,
+ OnDoubleClick = 0x0008,
+ OnSelect = 0x0010
+};
+namespace o3tl {
+ template<> struct typed_flags<EAFlags> : is_typed_flags<EAFlags, 0x001f> {};
+}
+
+ // any other attributes, which are special to some control types
+enum class SCAFlags {
+ NONE = 0x000000,
+ EchoChar = 0x000001,
+ MaxValue = 0x000002,
+ MinValue = 0x000004,
+ Validation = 0x000008,
+ GroupName = 0x000010,
+ MultiLine = 0x000020,
+ AutoCompletion = 0x000080,
+ Multiple = 0x000100,
+ DefaultButton = 0x000200,
+ CurrentState = 0x000400,
+ IsTristate = 0x000800,
+ State = 0x001000,
+ ColumnStyleName = 0x002000,
+ StepSize = 0x004000,
+ PageStepSize = 0x008000,
+ RepeatDelay = 0x010000,
+ Toggle = 0x020000,
+ FocusOnClick = 0x040000,
+ ImagePosition = 0x080000
+};
+namespace o3tl {
+ template<> struct typed_flags<SCAFlags> : is_typed_flags<SCAFlags, 0x0fffbf> {};
+}
+
+
+namespace xmloff
+{
+
+ /// attributes in the xml tag representing a form
+ enum FormAttributes
+ {
+ faName,
+ faAction,
+ faEnctype,
+ faMethod,
+ faAllowDeletes,
+ faAllowInserts,
+ faAllowUpdates,
+ faApplyFilter,
+ faCommand,
+ faCommandType,
+ faEscapeProcessing,
+ faDatasource,
+ faDetailFields,
+ faFilter,
+ faIgnoreResult,
+ faMasterFields,
+ faNavigationMode,
+ faOrder,
+ faTabbingCycle
+ };
+
+ // attributes of the office:forms element
+ enum OfficeFormsAttributes
+ {
+ ofaAutomaticFocus,
+ ofaApplyDesignMode
+ };
+
+ //= OAttributeMetaData
+ /** allows the translation of attribute ids into strings.
+
+ <p>This class does not allow to connect xml attributes to property names or
+ something like that, it only deals with the xml side</p>
+ */
+ class OAttributeMetaData
+ {
+ public:
+ /** calculates the xml attribute representation of a common control attribute.
+ @param _nId
+ the id of the attribute. Has to be one of the CCA_* constants.
+ */
+ static OUString getCommonControlAttributeName(CCAFlags _nId);
+
+ /** calculates the xml attribute representation of a common control attribute.
+ @param _nId
+ the id of the attribute. Has to be one of the CCA_* constants.
+ */
+ static sal_Int32 getCommonControlAttributeToken(CCAFlags _nId);
+
+ /** calculates the xml namespace key to use for a common control attribute
+ @param _nId
+ the id of the attribute. Has to be one of the CCA_* constants.
+ */
+ static sal_uInt16 getCommonControlAttributeNamespace(CCAFlags _nId);
+
+ /** retrieves the name of an attribute of a form xml representation
+ @param _eAttrib
+ enum value specifying the attribute
+ */
+ static OUString getFormAttributeName(FormAttributes _eAttrib);
+
+ /** retrieves the name of an attribute of a form xml representation
+ @param _eAttrib
+ enum value specifying the attribute
+ */
+ static sal_Int32 getFormAttributeToken(FormAttributes _eAttrib);
+
+ /** calculates the xml namespace key to use for an attribute of a form xml representation
+ @param _eAttrib
+ enum value specifying the attribute
+ */
+ static sal_uInt16 getFormAttributeNamespace(FormAttributes _eAttrib);
+
+ /** calculates the xml attribute representation of a database attribute.
+ @param _nId
+ the id of the attribute. Has to be one of the DA_* constants.
+ */
+ static OUString getDatabaseAttributeName(DAFlags _nId);
+
+ /** calculates the xml attribute representation of a database attribute.
+ @param _nId
+ the id of the attribute. Has to be one of the DA_* constants.
+ */
+ static sal_Int32 getDatabaseAttributeToken(DAFlags _nId);
+
+ /** calculates the xml namespace key to use for a database attribute.
+ @param _nId
+ the id of the attribute. Has to be one of the DA_* constants.
+ */
+ static sal_uInt16 getDatabaseAttributeNamespace()
+ {
+ // nothing special here
+ return XML_NAMESPACE_FORM;
+ }
+
+ /** calculates the xml attribute representation of a special attribute.
+ @param _nId
+ the id of the attribute. Has to be one of the SCA_* constants.
+ */
+ static OUString getSpecialAttributeName(SCAFlags _nId);
+
+ /** calculates the xml attribute representation of a special attribute.
+ @param _nId
+ the id of the attribute. Has to be one of the SCA_* constants.
+ */
+ static sal_Int32 getSpecialAttributeToken(SCAFlags _nId);
+
+ /** calculates the xml attribute representation of a binding attribute.
+ @param _nId
+ the id of the attribute. Has to be one of the BA_* constants.
+ */
+ static OUString getBindingAttributeName(BAFlags _nId);
+
+ /** calculates the xml attribute representation of a binding attribute.
+ @param _nId
+ the id of the attribute. Has to be one of the BA_* constants.
+ */
+ static sal_Int32 getBindingAttributeToken(BAFlags _nId);
+
+ /** calculates the xml namespace key to use for a binding attribute.
+ @param _nId
+ the id of the attribute. Has to be one of the BA_* constants.
+ */
+ static sal_uInt16 getBindingAttributeNamespace()
+ {
+ // nothing special here
+ return XML_NAMESPACE_FORM;
+ }
+
+ /** calculates the xml namespace key to use for a special attribute.
+ @param _nId
+ the id of the attribute. Has to be one of the SCA_* constants.
+ */
+ static sal_uInt16 getSpecialAttributeNamespace(SCAFlags _nId);
+
+ /** calculates the xml attribute representation of an attribute of the office:forms element
+ @param _nId
+ the id of the attribute
+ */
+ static OUString getOfficeFormsAttributeName(OfficeFormsAttributes _eAttrib);
+ static xmloff::token::XMLTokenEnum getOfficeFormsAttributeToken(OfficeFormsAttributes _eAttrib);
+
+ /** calculates the xml namedspace key of an attribute of the office:forms element
+ @param _nId
+ the id of the attribute
+ */
+ static sal_uInt16 getOfficeFormsAttributeNamespace()
+ { // nothing special here
+ return XML_NAMESPACE_FORM;
+ }
+ };
+
+ //= OAttribute2Property
+ /** some kind of opposite to the OAttributeMetaData class. Able to translate
+ attributes into property names/types
+
+ <p>The construction of this class is rather expensive (or at least it's initialization from outside),
+ so it should be shared</p>
+ */
+ class OAttribute2Property final
+ {
+ public:
+ // TODO: maybe the following struct should be used for exports, too. In this case we would not need to
+ // store it's instances in a map, but in a vector for faster access.
+ struct AttributeAssignment
+ {
+ OUString sPropertyName; // the property name
+ css::uno::Type aPropertyType; // the property type
+
+ // entries which are special to some value types
+ const SvXMLEnumMapEntry<sal_uInt16>*
+ pEnumMap; // the enum map, if applicable
+ bool bInverseSemantics; // for booleans: attribute and property value have the same or an inverse semantics?
+
+ AttributeAssignment() : pEnumMap(nullptr), bInverseSemantics(false) { }
+ };
+
+ private:
+ std::map<sal_Int32, AttributeAssignment> m_aKnownProperties;
+
+ public:
+ OAttribute2Property();
+ ~OAttribute2Property();
+
+ /** return the AttributeAssignment which corresponds to the given attribute
+
+ @return
+ a pointer to the <type>AttributeAssignment</type> structure as requested, NULL if the attribute
+ does not represent a property.
+ */
+ const AttributeAssignment* getAttributeTranslation(sal_Int32 nAttributeToken);
+
+ /** add an attribute assignment referring to a string property to the map
+ @param _pAttributeName
+ the name of the attribute
+ @param _rPropertyName
+ the name of the property assigned to the attribute
+ */
+ void addStringProperty(
+ sal_Int32 nAttributeToken, const OUString& _rPropertyName);
+
+ /** add an attribute assignment referring to a boolean property to the map
+
+ @param _pAttributeName
+ the name of the attribute
+ @param _rPropertyName
+ the name of the property assigned to the attribute
+ @param _bAttributeDefault
+ the default value for the attribute.
+ @param _bInverseSemantics
+ if <TRUE/>, an attribute value of <TRUE/> means a property value of <FALSE/> and vice verse.<br/>
+ if <FALSE/>, the attribute value is used as property value directly
+ */
+ void addBooleanProperty(
+ sal_Int32 nAttributeToken, const OUString& _rPropertyName,
+ const bool _bAttributeDefault, const bool _bInverseSemantics = false);
+
+ /** add an attribute assignment referring to an int16 property to the map
+
+ @param _pAttributeName
+ the name of the attribute
+ @param _rPropertyName
+ the name of the property assigned to the attribute
+ */
+ void addInt16Property(
+ sal_Int32 nAttributeToken, const OUString& _rPropertyName);
+
+ /** add an attribute assignment referring to an int32 property to the map
+
+ @param _pAttributeName
+ the name of the attribute
+ @param _rPropertyName
+ the name of the property assigned to the attribute
+ */
+ void addInt32Property(
+ sal_Int32 nAttributeToken, const OUString& _rPropertyName );
+
+ /** add an attribute assignment referring to an enum property to the map
+
+ @param _pAttributeName
+ the name of the attribute
+ @param _rPropertyName
+ the name of the property assigned to the attribute
+ @param _pValueMap
+ the map to translate strings into enum values
+ @param _pType
+ the type of the property. May be NULL, in this case 32bit integer is assumed.
+ */
+ template<typename EnumT>
+ void addEnumProperty(
+ sal_Int32 nAttributeToken, const OUString& _rPropertyName,
+ const SvXMLEnumMapEntry<EnumT>* _pValueMap,
+ const css::uno::Type* _pType = nullptr)
+ {
+ addEnumPropertyImpl(nAttributeToken, _rPropertyName,
+ reinterpret_cast<const SvXMLEnumMapEntry<sal_uInt16>*>(_pValueMap), _pType);
+ }
+
+ private:
+ void addEnumPropertyImpl(
+ sal_Int32 nAttributeToken, const OUString& _rPropertyName,
+ const SvXMLEnumMapEntry<sal_uInt16>* _pValueMap,
+ const css::uno::Type* _pType);
+ /// some common code for the various add*Property methods
+ AttributeAssignment& implAdd(
+ sal_Int32 nAttributeToken, const OUString& _rPropertyName,
+ const css::uno::Type& _rType);
+ };
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/formcellbinding.cxx b/xmloff/source/forms/formcellbinding.cxx
new file mode 100644
index 000000000..e9220fd79
--- /dev/null
+++ b/xmloff/source/forms/formcellbinding.cxx
@@ -0,0 +1,433 @@
+/* -*- 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 "formcellbinding.hxx"
+#include <com/sun/star/form/binding/XBindableValue.hpp>
+#include <com/sun/star/form/binding/XListEntrySink.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include "strings.hxx"
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+
+#include <algorithm>
+
+namespace xmloff
+{
+
+ 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::form::binding;
+
+namespace
+{
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::container::XChild;
+ using ::com::sun::star::frame::XModel;
+ using ::com::sun::star::uno::UNO_QUERY;
+
+ template< class TYPE >
+ Reference< TYPE > getTypedModelNode( const Reference< XInterface >& _rxModelNode )
+ {
+ Reference< TYPE > xTypedNode( _rxModelNode, UNO_QUERY );
+ if ( xTypedNode.is() )
+ return xTypedNode;
+ else
+ {
+ Reference< XChild > xChild( _rxModelNode, UNO_QUERY );
+ if ( xChild.is() )
+ return getTypedModelNode< TYPE >( xChild->getParent() );
+ else
+ return nullptr;
+ }
+ }
+
+ Reference< XModel > getDocument( const Reference< XInterface >& _rxModelNode )
+ {
+ return getTypedModelNode< XModel >( _rxModelNode );
+ }
+
+ struct StringCompare
+ {
+ private:
+ const OUString & m_sReference;
+
+ public:
+ explicit StringCompare( const OUString& _rReference ) : m_sReference( _rReference ) { }
+
+ bool operator()( std::u16string_view _rCompare )
+ {
+ return ( _rCompare == m_sReference );
+ }
+ };
+}
+
+//= FormCellBindingHelper
+FormCellBindingHelper::FormCellBindingHelper( const Reference< XPropertySet >& _rxControlModel, const Reference< XModel >& _rxDocument )
+ :m_xControlModel( _rxControlModel )
+ ,m_xDocument( _rxDocument, UNO_QUERY )
+{
+ OSL_ENSURE( m_xControlModel.is(), "FormCellBindingHelper::FormCellBindingHelper: invalid control model!" );
+
+ if ( !m_xDocument.is() )
+ m_xDocument.set(getDocument( m_xControlModel ), css::uno::UNO_QUERY);
+ OSL_ENSURE( m_xDocument.is(), "FormCellBindingHelper::FormCellBindingHelper: Did not find the spreadsheet document!" );
+}
+
+bool FormCellBindingHelper::livesInSpreadsheetDocument( const Reference< XPropertySet >& _rxControlModel )
+{
+ Reference< XSpreadsheetDocument > xDocument( getDocument( _rxControlModel ), UNO_QUERY );
+ return xDocument.is();
+}
+
+bool FormCellBindingHelper::convertStringAddress( const OUString& _rAddressDescription, CellAddress& /* [out] */ _rAddress ) const
+{
+ Any aAddress;
+ return doConvertAddressRepresentations(
+ PROPERTY_FILE_REPRESENTATION,
+ Any( _rAddressDescription ),
+ PROPERTY_ADDRESS,
+ aAddress,
+ false
+ )
+ && ( aAddress >>= _rAddress );
+}
+
+bool FormCellBindingHelper::convertStringAddress( const OUString& _rAddressDescription,
+ CellRangeAddress& /* [out] */ _rAddress ) const
+{
+ Any aAddress;
+ return doConvertAddressRepresentations(
+ PROPERTY_FILE_REPRESENTATION,
+ Any( _rAddressDescription ),
+ PROPERTY_ADDRESS,
+ aAddress,
+ true
+ )
+ && ( aAddress >>= _rAddress );
+}
+
+Reference< XValueBinding > FormCellBindingHelper::createCellBindingFromStringAddress( const OUString& _rAddress, bool _bUseIntegerBinding ) 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;
+
+ xBinding.set(createDocumentDependentInstance(
+ _bUseIntegerBinding ? OUString(SERVICE_LISTINDEXCELLBINDING) : OUString(SERVICE_CELLVALUEBINDING),
+ PROPERTY_BOUND_CELL,
+ Any( aAddress )
+ ), css::uno::UNO_QUERY);
+
+ return xBinding;
+}
+
+Reference< XListEntrySource > FormCellBindingHelper::createCellListSourceFromStringAddress( const OUString& _rAddress ) const
+{
+ Reference< XListEntrySource > xSource;
+
+ CellRangeAddress aRangeAddress;
+ if ( !convertStringAddress( _rAddress, aRangeAddress ) )
+ return xSource;
+
+ // create a range object for this address
+ xSource.set(createDocumentDependentInstance(
+ SERVICE_CELLRANGELISTSOURCE,
+ PROPERTY_LIST_CELL_RANGE,
+ Any( aRangeAddress )
+ ), css::uno::UNO_QUERY);
+
+ return xSource;
+}
+
+OUString FormCellBindingHelper::getStringAddressFromCellBinding( const Reference< XValueBinding >& _rxBinding ) const
+{
+ OSL_PRECOND( !_rxBinding.is() || isCellBinding( _rxBinding ), "FormCellBindingHelper::getStringAddressFromCellBinding: this is no cell binding!" );
+
+ OUString sAddress;
+ try
+ {
+ Reference< XPropertySet > xBindingProps( _rxBinding, UNO_QUERY );
+ OSL_ENSURE( xBindingProps.is() || !_rxBinding.is(), "FormCellBindingHelper::getStringAddressFromCellBinding: no property set for the binding!" );
+ if ( xBindingProps.is() )
+ {
+ CellAddress aAddress;
+ xBindingProps->getPropertyValue( PROPERTY_BOUND_CELL ) >>= aAddress;
+
+ Any aStringAddress;
+ doConvertAddressRepresentations( PROPERTY_ADDRESS, Any( aAddress ),
+ PROPERTY_FILE_REPRESENTATION, aStringAddress, false );
+
+ aStringAddress >>= sAddress;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "xmloff", "FormCellBindingHelper::getStringAddressFromCellBinding" );
+ }
+
+ return sAddress;
+}
+
+OUString FormCellBindingHelper::getStringAddressFromCellListSource( const Reference< XListEntrySource >& _rxSource ) const
+{
+ OSL_PRECOND( !_rxSource.is() || isCellRangeListSource( _rxSource ), "FormCellBindingHelper::getStringAddressFromCellListSource: this is no cell list source!" );
+
+ OUString sAddress;
+ try
+ {
+ Reference< XPropertySet > xSourceProps( _rxSource, UNO_QUERY );
+ OSL_ENSURE( xSourceProps.is() || !_rxSource.is(), "FormCellBindingHelper::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_FILE_REPRESENTATION, aStringAddress, true );
+ aStringAddress >>= sAddress;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "xmloff", "FormCellBindingHelper::getStringAddressFromCellListSource" );
+ }
+
+ return sAddress;
+}
+
+bool FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies( const Reference< XSpreadsheetDocument >& _rxDocument, const OUString& _rService )
+{
+ bool bYesItIs = false;
+
+ try
+ {
+ Reference< XServiceInfo > xSI( _rxDocument, UNO_QUERY );
+ if ( xSI.is() && xSI->supportsService( SERVICE_SPREADSHEET_DOCUMENT ) )
+ {
+ Reference< XMultiServiceFactory > xDocumentFactory( _rxDocument, UNO_QUERY );
+ OSL_ENSURE( xDocumentFactory.is(), "FormCellBindingHelper::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 ) );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "xmloff", "FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies" );
+ }
+
+ return bYesItIs;
+}
+
+bool FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies( const OUString& _rService ) const
+{
+ return isSpreadsheetDocumentWhichSupplies( m_xDocument, _rService );
+}
+
+bool FormCellBindingHelper::isListCellRangeAllowed( const Reference< XModel >& _rxDocument )
+{
+ return isSpreadsheetDocumentWhichSupplies(
+ Reference< XSpreadsheetDocument >( _rxDocument, UNO_QUERY ),
+ SERVICE_CELLRANGELISTSOURCE
+ );
+}
+
+bool FormCellBindingHelper::isListCellRangeAllowed( ) const
+{
+ bool bAllow( false );
+
+ Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY );
+ if ( xSink.is() )
+ {
+ bAllow = isSpreadsheetDocumentWhichSupplies( SERVICE_CELLRANGELISTSOURCE );
+ }
+
+ return bAllow;
+}
+
+bool FormCellBindingHelper::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_CELLVALUEBINDING );
+ }
+
+ return bAllow;
+}
+
+bool FormCellBindingHelper::isCellBindingAllowed( const Reference< XModel >& _rxDocument )
+{
+ return isSpreadsheetDocumentWhichSupplies(
+ Reference< XSpreadsheetDocument >( _rxDocument, UNO_QUERY ),
+ SERVICE_CELLVALUEBINDING
+ );
+}
+
+bool FormCellBindingHelper::isCellBinding( const Reference< XValueBinding >& _rxBinding )
+{
+ return doesComponentSupport( _rxBinding, SERVICE_CELLVALUEBINDING );
+}
+
+bool FormCellBindingHelper::isCellIntegerBinding( const Reference< XValueBinding >& _rxBinding )
+{
+ return doesComponentSupport( _rxBinding, SERVICE_LISTINDEXCELLBINDING );
+}
+
+bool FormCellBindingHelper::isCellRangeListSource( const Reference< XListEntrySource >& _rxSource )
+{
+ return doesComponentSupport( _rxSource, SERVICE_CELLRANGELISTSOURCE );
+}
+
+bool FormCellBindingHelper::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 > FormCellBindingHelper::getCurrentBinding( ) const
+{
+ Reference< XValueBinding > xBinding;
+ Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY );
+ if ( xBindable.is() )
+ xBinding = xBindable->getValueBinding();
+ return xBinding;
+}
+
+Reference< XListEntrySource > FormCellBindingHelper::getCurrentListSource( ) const
+{
+ Reference< XListEntrySource > xSource;
+ Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY );
+ if ( xSink.is() )
+ xSource = xSink->getListEntrySource();
+ return xSource;
+}
+
+void FormCellBindingHelper::setBinding( const Reference< XValueBinding >& _rxBinding )
+{
+ Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY );
+ OSL_PRECOND( xBindable.is(), "FormCellBindingHelper::setBinding: the object is not bindable!" );
+ if ( xBindable.is() )
+ xBindable->setValueBinding( _rxBinding );
+}
+
+void FormCellBindingHelper::setListSource( const Reference< XListEntrySource >& _rxSource )
+{
+ Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY );
+ OSL_PRECOND( xSink.is(), "FormCellBindingHelper::setListSource: the object is no list entry sink!" );
+ if ( xSink.is() )
+ xSink->setListEntrySource( _rxSource );
+}
+
+Reference< XInterface > FormCellBindingHelper::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(), "FormCellBindingHelper::createDocumentDependentInstance: no document service factory!" );
+ if ( xDocumentFactory.is() )
+ {
+ try
+ {
+ if ( !_rArgumentName.isEmpty() )
+ {
+ NamedValue aArg;
+ aArg.Name = _rArgumentName;
+ aArg.Value = _rArgumentValue;
+
+ Sequence< Any > aArgs{ Any(aArg) };
+ xReturn = xDocumentFactory->createInstanceWithArguments( _rService, aArgs );
+ }
+ else
+ {
+ xReturn = xDocumentFactory->createInstance( _rService );
+ }
+ }
+ catch ( const Exception& )
+ {
+ OSL_FAIL( "FormCellBindingHelper::createDocumentDependentInstance: could not create the binding at the document!" );
+ }
+ }
+ return xReturn;
+}
+
+bool FormCellBindingHelper::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(), "FormCellBindingHelper::doConvertAddressRepresentations: could not get a converter service!" );
+ if ( xConverter.is() )
+ {
+ try
+ {
+ xConverter->setPropertyValue( _rInputProperty, _rInputValue );
+ _rOutputValue = xConverter->getPropertyValue( _rOutputProperty );
+ bSuccess = true;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "xmloff", "FormCellBindingHelper::doConvertAddressRepresentations" );
+ }
+ }
+
+ return bSuccess;
+}
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/formcellbinding.hxx b/xmloff/source/forms/formcellbinding.hxx
new file mode 100644
index 000000000..a05413181
--- /dev/null
+++ b/xmloff/source/forms/formcellbinding.hxx
@@ -0,0 +1,260 @@
+/* -*- 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/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/frame/XModel.hpp>
+
+namespace xmloff
+{
+
+ //= FormCellBindingHelper
+ /** encapsulates functionality related to binding a form control to a spreadsheet cell
+ */
+ class FormCellBindingHelper
+ {
+ 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:
+ /** determines whether the given control model lives in a spreadsheet document
+ <p>If this method returns <FALSE/>, you cannot instantiate a CellBindingHelper with
+ this model, since then no of its functionality will be available.</p>
+ */
+ static bool livesInSpreadsheetDocument(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel
+ );
+
+ /** ctor
+ @param _rxControlModel
+ the control model which is or will be bound
+ @param _rxDocument
+ the document. If this is <NULL/>, the document will be obtained from the model
+ itself by walk on up the chain of its ancestors.<br/>
+ This parameter can be used if the control model is not (yet) part of a document
+ model.
+ */
+ FormCellBindingHelper(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel,
+ const css::uno::Reference< css::frame::XModel >& _rxDocument
+ );
+
+ /** gets a cell binding for the given address
+ @precond
+ isCellBindingAllowed returns <TRUE/>
+ */
+ css::uno::Reference< css::form::binding::XValueBinding >
+ createCellBindingFromStringAddress(
+ const OUString& _rAddress,
+ bool _bUseIntegerBinding
+ ) 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 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 within the given document, it's possible to bind control models to spreadsheet cells
+ */
+ static bool isCellBindingAllowed(
+ const css::uno::Reference< css::frame::XModel >& _rxDocument
+ );
+
+ /** checks whether it's possible to bind the control model to a range of spreadsheet cells
+ supplying the list entries
+ */
+ bool isListCellRangeAllowed( ) const;
+
+ /** checks whether within the given document, it's possible to bind the control model to a range of
+ spreadsheet cells supplying the list entries
+ */
+ static bool isListCellRangeAllowed(
+ const css::uno::Reference< css::frame::XModel >& _rxDocument
+ );
+
+ /** 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
+ );
+
+ 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;
+
+ /** determines if our document is a spreadsheet document, *and* can supply
+ the given service
+ */
+ static bool isSpreadsheetDocumentWhichSupplies(
+ const css::uno::Reference< css::sheet::XSpreadsheetDocument >& _rxDocument,
+ const OUString& _rService
+ );
+
+ /** 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 xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/formenums.cxx b/xmloff/source/forms/formenums.cxx
new file mode 100644
index 000000000..31567ddf7
--- /dev/null
+++ b/xmloff/source/forms/formenums.cxx
@@ -0,0 +1,191 @@
+/* -*- 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 "formenums.hxx"
+#include <com/sun/star/form/FormSubmitEncoding.hpp>
+#include <com/sun/star/form/FormSubmitMethod.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/form/NavigationBarMode.hpp>
+#include <com/sun/star/form/TabulatorCycle.hpp>
+#include <com/sun/star/form/FormButtonType.hpp>
+#include <com/sun/star/form/ListSourceType.hpp>
+#include <com/sun/star/awt/TextAlign.hpp>
+#include <com/sun/star/awt/FontEmphasisMark.hpp>
+#include <com/sun/star/awt/FontRelief.hpp>
+#include <com/sun/star/awt/ScrollBarOrientation.hpp>
+#include <com/sun/star/awt/VisualEffect.hpp>
+#include <com/sun/star/awt/ImageScaleMode.hpp>
+#include <tools/gen.hxx>
+#include <xmloff/xmltoken.hxx>
+
+namespace xmloff
+{
+
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star;
+using namespace ::xmloff::token;
+
+const SvXMLEnumMapEntry<FormSubmitEncoding> aSubmitEncodingMap[] =
+{
+ { XML_APPLICATION_X_WWW_FORM_URLENCODED, FormSubmitEncoding_URL },
+ { XML_MULTIPART_FORMDATA, FormSubmitEncoding_MULTIPART },
+ { XML_APPLICATION_TEXT, FormSubmitEncoding_TEXT },
+ { XML_TOKEN_INVALID, FormSubmitEncoding(0) }
+};
+const SvXMLEnumMapEntry<FormSubmitMethod> aSubmitMethodMap[] =
+{
+ { XML_GET, FormSubmitMethod_GET },
+ { XML_POST, FormSubmitMethod_POST },
+ { XML_TOKEN_INVALID, FormSubmitMethod(0) }
+};
+const SvXMLEnumMapEntry<sal_Int32> aCommandTypeMap[] =
+{
+ { XML_TABLE, CommandType::TABLE },
+ { XML_QUERY, CommandType::QUERY },
+ { XML_COMMAND, CommandType::COMMAND },
+ { XML_TOKEN_INVALID, 0 }
+};
+const SvXMLEnumMapEntry<NavigationBarMode> aNavigationTypeMap[] =
+{
+ { XML_NONE, NavigationBarMode_NONE },
+ { XML_CURRENT, NavigationBarMode_CURRENT },
+ { XML_PARENT, NavigationBarMode_PARENT },
+ { XML_TOKEN_INVALID, NavigationBarMode(0) }
+};
+const SvXMLEnumMapEntry<TabulatorCycle> aTabulatorCycleMap[] =
+{
+ { XML_RECORDS, TabulatorCycle_RECORDS },
+ { XML_CURRENT, TabulatorCycle_CURRENT },
+ { XML_PAGE, TabulatorCycle_PAGE },
+ { XML_TOKEN_INVALID, TabulatorCycle(0) }
+};
+const SvXMLEnumMapEntry<FormButtonType> aFormButtonTypeMap[] =
+{
+ { XML_PUSH, FormButtonType_PUSH },
+ { XML_SUBMIT, FormButtonType_SUBMIT },
+ { XML_RESET, FormButtonType_RESET },
+ { XML_URL, FormButtonType_URL },
+ { XML_TOKEN_INVALID, FormButtonType(0) }
+};
+const SvXMLEnumMapEntry<ListSourceType> aListSourceTypeMap[] =
+{
+ { XML_VALUE_LIST, ListSourceType_VALUELIST },
+ { XML_TABLE, ListSourceType_TABLE },
+ { XML_QUERY, ListSourceType_QUERY },
+ { XML_SQL, ListSourceType_SQL },
+ { XML_SQL_PASS_THROUGH, ListSourceType_SQLPASSTHROUGH },
+ { XML_TABLE_FIELDS, ListSourceType_TABLEFIELDS },
+ { XML_TOKEN_INVALID, ListSourceType(0) }
+};
+// check state of a checkbox
+const SvXMLEnumMapEntry<TriState> aCheckStateMap[] =
+{
+ { XML_UNCHECKED, TRISTATE_FALSE },
+ { XML_CHECKED, TRISTATE_TRUE },
+ { XML_UNKNOWN, TRISTATE_INDET },
+ { XML_TOKEN_INVALID, TriState(0) }
+};
+const SvXMLEnumMapEntry<sal_Int16> aTextAlignMap[] =
+{
+ { XML_START, sal_uInt16(awt::TextAlign::LEFT) },
+ { XML_CENTER, sal_uInt16(awt::TextAlign::CENTER) },
+ { XML_END, sal_uInt16(awt::TextAlign::RIGHT) },
+ { XML_JUSTIFY, -1 },
+ { XML_JUSTIFIED, -1 },
+ { XML_TOKEN_INVALID, 0 }
+};
+const SvXMLEnumMapEntry<sal_uInt16> aBorderTypeMap[] =
+{
+ { XML_NONE, 0 },
+ { XML_HIDDEN, 0 },
+ { XML_SOLID, 2 },
+ { XML_DOUBLE, 2 },
+ { XML_DOTTED, 2 },
+ { XML_DASHED, 2 },
+ { XML_GROOVE, 1 },
+ { XML_RIDGE, 1 },
+ { XML_INSET, 1 },
+ { XML_OUTSET, 1 },
+ { XML_TOKEN_INVALID, 0 }
+};
+const SvXMLEnumMapEntry<sal_uInt16> aFontEmphasisMap[] =
+{
+ { XML_NONE, awt::FontEmphasisMark::NONE },
+ { XML_DOT, awt::FontEmphasisMark::DOT },
+ { XML_CIRCLE, awt::FontEmphasisMark::CIRCLE },
+ { XML_DISC, awt::FontEmphasisMark::DISC },
+ { XML_ACCENT, awt::FontEmphasisMark::ACCENT },
+ { XML_TOKEN_INVALID, 0 }
+};
+const SvXMLEnumMapEntry<sal_uInt16> aFontReliefMap[] =
+{
+ { XML_NONE, FontRelief::NONE },
+ { XML_ENGRAVED, FontRelief::ENGRAVED },
+ { XML_EMBOSSED, FontRelief::EMBOSSED },
+ { XML_TOKEN_INVALID, 0 }
+};
+const SvXMLEnumMapEntry<sal_Int16> aListLinkageMap[] =
+{
+ { XML_SELECTION, 0 },
+ { XML_SELECTION_INDEXES, 1 },
+ { XML_TOKEN_INVALID, 0 }
+};
+const SvXMLEnumMapEntry<sal_Int32> aOrientationMap[] =
+{
+ { XML_HORIZONTAL, ScrollBarOrientation::HORIZONTAL },
+ { XML_VERTICAL, ScrollBarOrientation::VERTICAL },
+ { XML_TOKEN_INVALID, 0 }
+};
+const SvXMLEnumMapEntry<sal_Int16> aVisualEffectMap[] =
+{
+ { XML_NONE, VisualEffect::NONE },
+ { XML_3D, VisualEffect::LOOK3D },
+ { XML_FLAT, VisualEffect::FLAT },
+ { XML_TOKEN_INVALID, 0 }
+};
+const SvXMLEnumMapEntry<sal_Int16> aImagePositionMap[] =
+{
+ { XML_START, 0 },
+ { XML_END, 1 },
+ { XML_TOP, 2 },
+ { XML_BOTTOM, 3 },
+ { XML_CENTER, -1 },
+ { XML_TOKEN_INVALID, 0 }
+};
+const SvXMLEnumMapEntry<sal_uInt16> aImageAlignMap[] =
+{
+ { XML_START, 0 },
+ { XML_CENTER, 1 },
+ { XML_END, 2 },
+ { XML_TOKEN_INVALID, 0 }
+};
+const SvXMLEnumMapEntry<sal_uInt16> aScaleModeMap[] =
+{
+ { XML_BACKGROUND_NO_REPEAT, ImageScaleMode::NONE },
+ { XML_REPEAT, ImageScaleMode::NONE }, // repeating the image is not supported
+ { XML_STRETCH, ImageScaleMode::ANISOTROPIC },
+ { XML_SCALE, ImageScaleMode::ISOTROPIC },
+ { XML_TOKEN_INVALID, 0 }
+};
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/formenums.hxx b/xmloff/source/forms/formenums.hxx
new file mode 100644
index 000000000..d0d20ff8d
--- /dev/null
+++ b/xmloff/source/forms/formenums.hxx
@@ -0,0 +1,54 @@
+/* -*- 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 <xmloff/xmlement.hxx>
+#include <com/sun/star/form/FormButtonType.hpp>
+#include <com/sun/star/form/FormSubmitEncoding.hpp>
+#include <com/sun/star/form/FormSubmitMethod.hpp>
+#include <com/sun/star/form/ListSourceType.hpp>
+#include <com/sun/star/form/NavigationBarMode.hpp>
+#include <com/sun/star/form/TabulatorCycle.hpp>
+#include <tools/gen.hxx>
+
+namespace xmloff
+{
+extern const SvXMLEnumMapEntry<css::form::FormSubmitEncoding> aSubmitEncodingMap[];
+extern const SvXMLEnumMapEntry<css::form::FormSubmitMethod> aSubmitMethodMap[];
+extern const SvXMLEnumMapEntry<sal_Int32> aCommandTypeMap[];
+extern const SvXMLEnumMapEntry<css::form::NavigationBarMode> aNavigationTypeMap[];
+extern const SvXMLEnumMapEntry<css::form::TabulatorCycle> aTabulatorCycleMap[];
+extern const SvXMLEnumMapEntry<css::form::FormButtonType> aFormButtonTypeMap[];
+extern const SvXMLEnumMapEntry<css::form::ListSourceType> aListSourceTypeMap[];
+extern const SvXMLEnumMapEntry<TriState> aCheckStateMap[];
+extern const SvXMLEnumMapEntry<sal_Int16> aTextAlignMap[];
+extern const SvXMLEnumMapEntry<sal_uInt16> aBorderTypeMap[];
+extern const SvXMLEnumMapEntry<sal_uInt16> aFontEmphasisMap[];
+extern const SvXMLEnumMapEntry<sal_uInt16> aFontReliefMap[];
+extern const SvXMLEnumMapEntry<sal_Int16> aListLinkageMap[];
+extern const SvXMLEnumMapEntry<sal_Int32> aOrientationMap[];
+extern const SvXMLEnumMapEntry<sal_Int16> aVisualEffectMap[];
+extern const SvXMLEnumMapEntry<sal_Int16> aImagePositionMap[];
+extern const SvXMLEnumMapEntry<sal_uInt16> aImageAlignMap[];
+extern const SvXMLEnumMapEntry<sal_uInt16> aScaleModeMap[];
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/formevents.cxx b/xmloff/source/forms/formevents.cxx
new file mode 100644
index 000000000..85e3137cb
--- /dev/null
+++ b/xmloff/source/forms/formevents.cxx
@@ -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 .
+ */
+
+#include "formevents.hxx"
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmlevent.hxx>
+
+namespace xmloff
+{
+
+ //= event translation table
+ const XMLEventNameTranslation aEventTranslations[] =
+ {
+ { "XApproveActionListener::approveAction", XML_NAMESPACE_FORM, "approveaction" }, // "on-approveaction"
+ { "XActionListener::actionPerformed", XML_NAMESPACE_FORM, "performaction" }, // "on-performaction"
+ { "XChangeListener::changed", XML_NAMESPACE_DOM, "change" }, // "on-change"
+ { "XTextListener::textChanged", XML_NAMESPACE_FORM, "textchange" }, // "on-textchange"
+ { "XItemListener::itemStateChanged", XML_NAMESPACE_FORM, "itemstatechange" }, // "on-itemstatechange"
+ { "XFocusListener::focusGained", XML_NAMESPACE_DOM, "DOMFocusIn" }, // "on-focus"
+ { "XFocusListener::focusLost", XML_NAMESPACE_DOM, "DOMFocusOut" }, // "on-blur"
+ { "XKeyListener::keyPressed", XML_NAMESPACE_DOM, "keydown" }, // "on-keydown"
+ { "XKeyListener::keyReleased", XML_NAMESPACE_DOM, "keyup" }, // "on-keyup"
+ { "XMouseListener::mouseEntered", XML_NAMESPACE_DOM, "mouseover" }, // "on-mouseover"
+ { "XMouseMotionListener::mouseDragged", XML_NAMESPACE_FORM, "mousedrag" }, // "on-mousedrag"
+ { "XMouseMotionListener::mouseMoved", XML_NAMESPACE_DOM, "mousemove" }, // "on-mousemove"
+ { "XMouseListener::mousePressed", XML_NAMESPACE_DOM, "mousedown" }, // "on-mousedown"
+ { "XMouseListener::mouseReleased", XML_NAMESPACE_DOM, "mouseup" }, // "on-mouseup"
+ { "XMouseListener::mouseExited", XML_NAMESPACE_DOM, "mouseout" }, // "on-mouseout"
+ { "XResetListener::approveReset", XML_NAMESPACE_FORM, "approvereset" }, // "on-approvereset"
+ { "XResetListener::resetted", XML_NAMESPACE_DOM, "reset" }, // "on-reset"
+ { "XSubmitListener::approveSubmit", XML_NAMESPACE_DOM, "submit" }, // "on-submit"
+ { "XUpdateListener::approveUpdate", XML_NAMESPACE_FORM, "approveupdate" }, // "on-approveupdate"
+ { "XUpdateListener::updated", XML_NAMESPACE_FORM, "update" }, // "on-update"
+ { "XLoadListener::loaded", XML_NAMESPACE_DOM, "load" }, // "on-load"
+ { "XLoadListener::reloading", XML_NAMESPACE_FORM, "startreload" }, // "on-startreload"
+ { "XLoadListener::reloaded", XML_NAMESPACE_FORM, "reload" }, // "on-reload"
+ { "XLoadListener::unloading", XML_NAMESPACE_FORM, "startunload" }, // "on-startunload"
+ { "XLoadListener::unloaded", XML_NAMESPACE_DOM, "unload" }, // "on-unload"
+ { "XConfirmDeleteListener::confirmDelete", XML_NAMESPACE_FORM, "confirmdelete" }, // "on-confirmdelete"
+ { "XRowSetApproveListener::approveRowChange", XML_NAMESPACE_FORM, "approverowchange" }, // "on-approverowchange"
+ { "XRowSetListener::rowChanged", XML_NAMESPACE_FORM, "rowchange" }, // "on-rowchange"
+ { "XRowSetApproveListener::approveCursorMove", XML_NAMESPACE_FORM, "approvecursormove" }, // "on-approvecursormove"
+ { "XRowSetListener::cursorMoved", XML_NAMESPACE_FORM, "cursormove" }, // "on-cursormove"
+ { "XDatabaseParameterListener::approveParameter",XML_NAMESPACE_FORM, "supplyparameter" }, // "on-supplyparameter"
+ { "XSQLErrorListener::errorOccured", XML_NAMESPACE_DOM, "error" }, // "on-error"
+ { "XAdjustmentListener::adjustmentValueChanged",XML_NAMESPACE_FORM, "adjust" }, // "on-adjust"
+ { nullptr, 0, nullptr }
+ };
+
+ const XMLEventNameTranslation* g_pFormsEventTranslation = aEventTranslations;
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/formevents.hxx b/xmloff/source/forms/formevents.hxx
new file mode 100644
index 000000000..7077f7522
--- /dev/null
+++ b/xmloff/source/forms/formevents.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
+
+struct XMLEventNameTranslation;
+namespace xmloff
+{
+//= event translation table
+extern const XMLEventNameTranslation* g_pFormsEventTranslation;
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/formlayerexport.cxx b/xmloff/source/forms/formlayerexport.cxx
new file mode 100644
index 000000000..661e83630
--- /dev/null
+++ b/xmloff/source/forms/formlayerexport.cxx
@@ -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 .
+ */
+
+#include <xmloff/formlayerexport.hxx>
+#include <xmloff/xmlexp.hxx>
+#include "layerexport.hxx"
+#include <osl/diagnose.h>
+#include "officeforms.hxx"
+
+namespace xmloff
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::drawing;
+
+ //= OFormLayerXMLExport
+
+ OFormLayerXMLExport::OFormLayerXMLExport(SvXMLExport& _rContext)
+ :m_pImpl(new OFormLayerXMLExport_Impl(_rContext))
+ {
+ }
+
+ OFormLayerXMLExport::~OFormLayerXMLExport()
+ {
+ }
+
+ bool OFormLayerXMLExport::seekPage(const Reference< XDrawPage >& _rxDrawPage)
+ {
+ return m_pImpl->seekPage(_rxDrawPage);
+ }
+
+ OUString OFormLayerXMLExport::getControlId(const Reference< XPropertySet >& _rxControl)
+ {
+ return m_pImpl->getControlId(_rxControl);
+ }
+
+ OUString OFormLayerXMLExport::getControlNumberStyle( const Reference< XPropertySet >& _rxControl )
+ {
+ return m_pImpl->getControlNumberStyle(_rxControl);
+ }
+
+ void OFormLayerXMLExport::examineForms(const Reference< XDrawPage >& _rxDrawPage)
+ {
+ try
+ {
+ m_pImpl->examineForms(_rxDrawPage);
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("OFormLayerXMLExport::examine: could not examine the draw page!");
+ }
+ }
+
+ void OFormLayerXMLExport::exportForms(const Reference< XDrawPage >& _rxDrawPage)
+ {
+ m_pImpl->exportForms(_rxDrawPage);
+ }
+
+ void OFormLayerXMLExport::exportXForms() const
+ {
+ m_pImpl->exportXForms();
+ }
+
+ bool OFormLayerXMLExport::pageContainsForms( const Reference< XDrawPage >& _rxDrawPage )
+ {
+ return OFormLayerXMLExport_Impl::pageContainsForms( _rxDrawPage );
+ }
+
+ bool OFormLayerXMLExport::documentContainsXForms() const
+ {
+ return m_pImpl->documentContainsXForms();
+ }
+
+ void OFormLayerXMLExport::exportAutoControlNumberStyles()
+ {
+ m_pImpl->exportAutoControlNumberStyles();
+ }
+
+ void OFormLayerXMLExport::exportAutoStyles()
+ {
+ m_pImpl->exportAutoStyles();
+ }
+
+ void OFormLayerXMLExport::excludeFromExport( const Reference< XControlModel >& _rxControl )
+ {
+ m_pImpl->excludeFromExport( _rxControl );
+ }
+
+ //= OOfficeFormsExport
+ OOfficeFormsExport::OOfficeFormsExport( SvXMLExport& _rExp )
+ :m_pImpl( new OFormsRootExport(_rExp) )
+ {
+ }
+
+ OOfficeFormsExport::~OOfficeFormsExport()
+ {
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/formlayerimport.cxx b/xmloff/source/forms/formlayerimport.cxx
new file mode 100644
index 000000000..400466bfd
--- /dev/null
+++ b/xmloff/source/forms/formlayerimport.cxx
@@ -0,0 +1,90 @@
+/* -*- 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/PropertyValue.hpp>
+
+#include <xmloff/formlayerimport.hxx>
+#include "layerimport.hxx"
+
+namespace xmloff
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::drawing;
+ using namespace ::com::sun::star;
+
+ OFormLayerXMLImport::OFormLayerXMLImport(SvXMLImport& _rImporter)
+ : m_pImpl( new OFormLayerXMLImport_Impl(_rImporter) )
+ {
+ }
+
+ OFormLayerXMLImport::~OFormLayerXMLImport()
+ {
+ }
+
+ void OFormLayerXMLImport::setAutoStyleContext(SvXMLStylesContext* _pNewContext)
+ {
+ m_pImpl->setAutoStyleContext(_pNewContext);
+ }
+
+ void OFormLayerXMLImport::startPage(const Reference< XDrawPage >& _rxDrawPage)
+ {
+ m_pImpl->startPage(_rxDrawPage);
+ }
+
+ void OFormLayerXMLImport::endPage()
+ {
+ m_pImpl->endPage();
+ }
+
+ Reference< XPropertySet > OFormLayerXMLImport::lookupControl(const OUString& _rId)
+ {
+ return m_pImpl->lookupControlId(_rId);
+ }
+
+ SvXMLImportContext* OFormLayerXMLImport::createOfficeFormsContext(
+ SvXMLImport& _rImport)
+ {
+ return OFormLayerXMLImport_Impl::createOfficeFormsContext(_rImport);
+ }
+
+ SvXMLImportContext* OFormLayerXMLImport::createContext(sal_Int32 nElement,
+ const Reference< xml::sax::XFastAttributeList >& _rxAttribs)
+ {
+ return m_pImpl->createContext(nElement, _rxAttribs);
+ }
+
+ void OFormLayerXMLImport::applyControlNumberStyle(const Reference< XPropertySet >& _rxControlModel, const OUString& _rControlNumberStyleName)
+ {
+ m_pImpl->applyControlNumberStyle(_rxControlModel, _rControlNumberStyleName);
+ }
+
+ void OFormLayerXMLImport::documentDone( )
+ {
+ m_pImpl->documentDone( );
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/gridcolumnproptranslator.cxx b/xmloff/source/forms/gridcolumnproptranslator.cxx
new file mode 100644
index 000000000..aeb1de438
--- /dev/null
+++ b/xmloff/source/forms/gridcolumnproptranslator.cxx
@@ -0,0 +1,299 @@
+/* -*- 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 "gridcolumnproptranslator.hxx"
+
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/awt/TextAlign.hpp>
+#include <com/sun/star/style/ParagraphAdjust.hpp>
+#include <osl/diagnose.h>
+#include <cppuhelper/implbase1.hxx>
+
+#include <algorithm>
+
+namespace xmloff
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::style;
+
+ namespace
+ {
+ OUString getParaAlignProperty()
+ {
+ return "ParaAdjust";
+ }
+
+ OUString getAlignProperty()
+ {
+ return "Align";
+ }
+
+ sal_Int32 findStringElement( const Sequence< OUString >& _rNames, const OUString& _rName )
+ {
+ const OUString* pPos = ::std::find( _rNames.begin(), _rNames.end(), _rName );
+ if ( pPos != _rNames.end() )
+ return pPos - _rNames.begin();
+ return -1;
+ }
+
+ struct AlignmentTranslationEntry
+ {
+ ParagraphAdjust nParagraphValue;
+ sal_Int16 nControlValue;
+ }
+ const AlignmentTranslations[] =
+ {
+ // note that order matters:
+ // valueAlignToParaAdjust and valueParaAdjustToAlign search this map from the _beginning_
+ // and use the first matching entry
+ { ParagraphAdjust_LEFT, awt::TextAlign::LEFT },
+ { ParagraphAdjust_CENTER, awt::TextAlign::CENTER },
+ { ParagraphAdjust_RIGHT, awt::TextAlign::RIGHT },
+ { ParagraphAdjust_BLOCK, awt::TextAlign::RIGHT },
+ { ParagraphAdjust_STRETCH, awt::TextAlign::LEFT },
+ { ParagraphAdjust::ParagraphAdjust_MAKE_FIXED_SIZE, awt::TextAlign::LEFT },
+ { ParagraphAdjust::ParagraphAdjust_MAKE_FIXED_SIZE, -1 }
+ };
+
+ void valueAlignToParaAdjust(Any& rValue)
+ {
+ sal_Int16 nValue = 0;
+ rValue >>= nValue;
+ const AlignmentTranslationEntry* pTranslation = AlignmentTranslations;
+ while (-1 != pTranslation->nControlValue)
+ {
+ if ( nValue == pTranslation->nControlValue )
+ {
+ rValue <<= pTranslation->nParagraphValue;
+ return;
+ }
+ ++pTranslation;
+ }
+ OSL_FAIL( "valueAlignToParaAdjust: unreachable!" );
+ }
+
+ void valueParaAdjustToAlign(Any& rValue)
+ {
+ sal_Int32 nValue = 0;
+ rValue >>= nValue;
+ const AlignmentTranslationEntry* pTranslation = AlignmentTranslations;
+ while ( ParagraphAdjust::ParagraphAdjust_MAKE_FIXED_SIZE != pTranslation->nParagraphValue)
+ {
+ if ( static_cast<ParagraphAdjust>(nValue) == pTranslation->nParagraphValue)
+ {
+ rValue <<= pTranslation->nControlValue;
+ return;
+ }
+ ++pTranslation;
+ }
+ OSL_FAIL( "valueParaAdjustToAlign: unreachable!" );
+ }
+
+ //= OMergedPropertySetInfo
+ typedef ::cppu::WeakAggImplHelper1 < XPropertySetInfo
+ > OMergedPropertySetInfo_Base;
+ class OMergedPropertySetInfo : public OMergedPropertySetInfo_Base
+ {
+ private:
+ Reference< XPropertySetInfo > m_xMasterInfo;
+
+ public:
+ explicit OMergedPropertySetInfo( const Reference< XPropertySetInfo >& _rxMasterInfo );
+
+ protected:
+ virtual ~OMergedPropertySetInfo() override;
+
+ // XPropertySetInfo
+ virtual css::uno::Sequence< css::beans::Property > SAL_CALL getProperties( ) override;
+ virtual css::beans::Property SAL_CALL getPropertyByName( const OUString& aName ) override;
+ virtual sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) override;
+ };
+
+ OMergedPropertySetInfo::OMergedPropertySetInfo( const Reference< XPropertySetInfo >& _rxMasterInfo )
+ :m_xMasterInfo( _rxMasterInfo )
+ {
+ OSL_ENSURE( m_xMasterInfo.is(), "OMergedPropertySetInfo::OMergedPropertySetInfo: hmm?" );
+ }
+
+ OMergedPropertySetInfo::~OMergedPropertySetInfo()
+ {
+ }
+
+ Sequence< Property > SAL_CALL OMergedPropertySetInfo::getProperties( )
+ {
+ // add a "ParaAdjust" property to the master properties
+ Sequence< Property > aProperties;
+ if ( m_xMasterInfo.is() )
+ aProperties = m_xMasterInfo->getProperties();
+
+ sal_Int32 nOldLength = aProperties.getLength();
+ aProperties.realloc( nOldLength + 1 );
+ aProperties.getArray()[ nOldLength ] = getPropertyByName( getParaAlignProperty() );
+
+ return aProperties;
+ }
+
+ Property SAL_CALL OMergedPropertySetInfo::getPropertyByName( const OUString& aName )
+ {
+ if ( aName == getParaAlignProperty() )
+ return Property( getParaAlignProperty(), -1,
+ ::cppu::UnoType<ParagraphAdjust>::get(), 0 );
+
+ if ( !m_xMasterInfo.is() )
+ return Property();
+
+ return m_xMasterInfo->getPropertyByName( aName );
+ }
+
+ sal_Bool SAL_CALL OMergedPropertySetInfo::hasPropertyByName( const OUString& Name )
+ {
+ if ( Name == getParaAlignProperty() )
+ return true;
+
+ if ( !m_xMasterInfo.is() )
+ return false;
+
+ return m_xMasterInfo->hasPropertyByName( Name );
+ }
+ }
+
+ //= OGridColumnPropertyTranslator
+ OGridColumnPropertyTranslator::OGridColumnPropertyTranslator( const Reference< XMultiPropertySet >& _rxGridColumn )
+ :m_xGridColumn( _rxGridColumn )
+ {
+ OSL_ENSURE( m_xGridColumn.is(), "OGridColumnPropertyTranslator: invalid grid column!" );
+ }
+
+ OGridColumnPropertyTranslator::~OGridColumnPropertyTranslator()
+ {
+ }
+
+ Reference< XPropertySetInfo > SAL_CALL OGridColumnPropertyTranslator::getPropertySetInfo( )
+ {
+ Reference< XPropertySetInfo > xColumnPropInfo;
+ if ( m_xGridColumn.is() )
+ xColumnPropInfo = m_xGridColumn->getPropertySetInfo();
+ return new OMergedPropertySetInfo( xColumnPropInfo );
+ }
+
+ void SAL_CALL OGridColumnPropertyTranslator::setPropertyValue( const OUString& _rPropertyName, const Any& aValue )
+ {
+ // we implement this by delegating it to setPropertyValues, which is to ignore unknown properties. On the other hand, our
+ // contract requires us to throw a UnknownPropertyException for unknown properties, so check this first.
+
+ if ( !getPropertySetInfo()->hasPropertyByName( _rPropertyName ) )
+ throw UnknownPropertyException( _rPropertyName, *this );
+
+ Sequence< OUString > aNames( &_rPropertyName, 1 );
+ Sequence< Any > aValues( &aValue, 1 );
+ setPropertyValues( aNames, aValues );
+ }
+
+ Any SAL_CALL OGridColumnPropertyTranslator::getPropertyValue( const OUString& PropertyName )
+ {
+ Sequence< OUString > aNames( &PropertyName, 1 );
+ Sequence< Any > aValues = getPropertyValues( aNames );
+ OSL_ENSURE( aValues.getLength() == 1, "OGridColumnPropertyTranslator::getPropertyValue: nonsense!" );
+ if ( aValues.getLength() == 1 )
+ return aValues[0];
+ return Any();
+ }
+
+ void SAL_CALL OGridColumnPropertyTranslator::addPropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& )
+ {
+ OSL_FAIL( "OGridColumnPropertyTranslator::addPropertyChangeListener: not implemented - this should not be needed!" );
+ }
+
+ void SAL_CALL OGridColumnPropertyTranslator::removePropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& )
+ {
+ OSL_FAIL( "OGridColumnPropertyTranslator::removePropertyChangeListener: not implemented - this should not be needed!" );
+ }
+
+ void SAL_CALL OGridColumnPropertyTranslator::addVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& )
+ {
+ OSL_FAIL( "OGridColumnPropertyTranslator::addVetoableChangeListener: not implemented - this should not be needed!" );
+ }
+
+ void SAL_CALL OGridColumnPropertyTranslator::removeVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& )
+ {
+ OSL_FAIL( "OGridColumnPropertyTranslator::removeVetoableChangeListener: not implemented - this should not be needed!" );
+ }
+
+ void SAL_CALL OGridColumnPropertyTranslator::setPropertyValues( const Sequence< OUString >& aPropertyNames, const Sequence< Any >& aValues )
+ {
+ if ( !m_xGridColumn.is() )
+ return;
+
+ // if there's ever the need for more than one property being translated, then we should
+ // certainly have a more clever implementation than this ...
+
+ Sequence< OUString > aTranslatedNames( aPropertyNames );
+ Sequence< Any > aTranslatedValues( aValues );
+
+ sal_Int32 nParaAlignPos = findStringElement( aTranslatedNames, getParaAlignProperty() );
+ if ( nParaAlignPos != -1 )
+ {
+ aTranslatedNames.getArray()[ nParaAlignPos ] = getAlignProperty();
+ valueParaAdjustToAlign( aTranslatedValues.getArray()[ nParaAlignPos ] );
+ }
+
+ m_xGridColumn->setPropertyValues( aTranslatedNames, aTranslatedValues );
+ }
+
+ Sequence< Any > SAL_CALL OGridColumnPropertyTranslator::getPropertyValues( const Sequence< OUString >& aPropertyNames )
+ {
+ Sequence< Any > aValues( aPropertyNames.getLength() );
+ if ( !m_xGridColumn.is() )
+ return aValues;
+
+ Sequence< OUString > aTranslatedNames( aPropertyNames );
+ sal_Int32 nAlignPos = findStringElement( aTranslatedNames, getParaAlignProperty() );
+ if ( nAlignPos != -1 )
+ aTranslatedNames.getArray()[ nAlignPos ] = getAlignProperty();
+
+ aValues = m_xGridColumn->getPropertyValues( aPropertyNames );
+ if ( nAlignPos != -1 )
+ valueAlignToParaAdjust( aValues.getArray()[ nAlignPos ] );
+
+ return aValues;
+ }
+
+ void SAL_CALL OGridColumnPropertyTranslator::addPropertiesChangeListener( const Sequence< OUString >&, const Reference< XPropertiesChangeListener >& )
+ {
+ OSL_FAIL( "OGridColumnPropertyTranslator::addPropertiesChangeListener: not implemented - this should not be needed!" );
+ }
+
+ void SAL_CALL OGridColumnPropertyTranslator::removePropertiesChangeListener( const Reference< XPropertiesChangeListener >& )
+ {
+ OSL_FAIL( "OGridColumnPropertyTranslator::removePropertiesChangeListener: not implemented - this should not be needed!" );
+ }
+
+ void SAL_CALL OGridColumnPropertyTranslator::firePropertiesChangeEvent( const Sequence< OUString >&, const Reference< XPropertiesChangeListener >& )
+ {
+ OSL_FAIL( "OGridColumnPropertyTranslator::firePropertiesChangeEvent: not implemented - this should not be needed!" );
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/gridcolumnproptranslator.hxx b/xmloff/source/forms/gridcolumnproptranslator.hxx
new file mode 100644
index 000000000..9a49cd9c3
--- /dev/null
+++ b/xmloff/source/forms/gridcolumnproptranslator.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 <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace xmloff
+{
+
+ //= OGridColumnPropertyTranslator
+ typedef ::cppu::WeakImplHelper < css::beans::XPropertySet
+ , css::beans::XMultiPropertySet
+ > OGridColumnPropertyTranslator_Base;
+ class OGridColumnPropertyTranslator : public OGridColumnPropertyTranslator_Base
+ {
+ private:
+ css::uno::Reference< css::beans::XMultiPropertySet >
+ m_xGridColumn;
+
+ public:
+ explicit OGridColumnPropertyTranslator(
+ const css::uno::Reference< css::beans::XMultiPropertySet >& _rxGridColumn
+ );
+
+ protected:
+ virtual ~OGridColumnPropertyTranslator() override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override;
+ virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+
+ // XMultiPropertySet
+ virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ) override;
+ virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames ) override;
+ virtual void SAL_CALL addPropertiesChangeListener( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertiesChangeListener( const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override;
+ virtual void SAL_CALL firePropertiesChangeEvent( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override;
+ };
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/handler/form_handler_factory.cxx b/xmloff/source/forms/handler/form_handler_factory.cxx
new file mode 100644
index 000000000..2a943aa82
--- /dev/null
+++ b/xmloff/source/forms/handler/form_handler_factory.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 <forms/form_handler_factory.hxx>
+#include "vcl_date_handler.hxx"
+#include "vcl_time_handler.hxx"
+#include <osl/diagnose.h>
+
+namespace xmloff
+{
+
+ //= FormHandlerFactory
+ PPropertyHandler FormHandlerFactory::getFormPropertyHandler( const PropertyId i_propertyId )
+ {
+ PPropertyHandler pHandler;
+
+ switch ( i_propertyId )
+ {
+ case PID_DATE_MIN:
+ case PID_DATE_MAX:
+ case PID_DEFAULT_DATE:
+ case PID_DATE:
+ {
+ static PPropertyHandler s_pVCLDateHandler = new VCLDateHandler();
+ pHandler = s_pVCLDateHandler;
+ }
+ break;
+
+ case PID_TIME_MIN:
+ case PID_TIME_MAX:
+ case PID_DEFAULT_TIME:
+ case PID_TIME:
+ {
+ static PPropertyHandler s_pVCLTimeHandler = new VCLTimeHandler();
+ pHandler = s_pVCLTimeHandler;
+ }
+ break;
+
+ default:
+ OSL_ENSURE( false, "FormHandlerFactory::getFormPropertyHandler: unknown property ID!" );
+ break;
+ }
+
+ return pHandler;
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/handler/vcl_date_handler.cxx b/xmloff/source/forms/handler/vcl_date_handler.cxx
new file mode 100644
index 000000000..1dfaadd61
--- /dev/null
+++ b/xmloff/source/forms/handler/vcl_date_handler.cxx
@@ -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 .
+ */
+
+#include "vcl_date_handler.hxx"
+
+#include <rtl/ustrbuf.hxx>
+
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Date.hpp>
+
+#include <sax/tools/converter.hxx>
+
+#include <osl/diagnose.h>
+#include <tools/date.hxx>
+
+namespace xmloff
+{
+
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::util::DateTime;
+ using ::com::sun::star::util::Date;
+
+ //= VCLDateHandler
+ VCLDateHandler::VCLDateHandler()
+ {
+ }
+
+ OUString VCLDateHandler::getAttributeValue( const Any& i_propertyValue ) const
+ {
+ Date aDate;
+ OSL_VERIFY( i_propertyValue >>= aDate );
+
+ DateTime aDateTime; // default-inited to 0
+ aDateTime.Day = aDate.Day;
+ aDateTime.Month = aDate.Month;
+ aDateTime.Year = aDate.Year;
+
+ OUStringBuffer aBuffer;
+ ::sax::Converter::convertDateTime( aBuffer, aDateTime, nullptr );
+ return aBuffer.makeStringAndClear();
+ }
+
+ bool VCLDateHandler::getPropertyValues( const OUString& i_attributeValue, PropertyValues& o_propertyValues ) const
+ {
+ DateTime aDateTime;
+ Date aDate;
+ if (::sax::Converter::parseDateTime( aDateTime, i_attributeValue ))
+ {
+ aDate.Day = aDateTime.Day;
+ aDate.Month = aDateTime.Month;
+ aDate.Year = aDateTime.Year;
+ }
+ else
+ {
+ // compatibility format, before we wrote those values in XML-schema compatible form
+ sal_Int32 nVCLDate(0);
+ if (!::sax::Converter::convertNumber(nVCLDate, i_attributeValue))
+ {
+ OSL_ENSURE( false, "VCLDateHandler::getPropertyValues: unknown date format (no XML-schema date, no legacy integer)!" );
+ return false;
+ }
+ aDate = ::Date(nVCLDate).GetUNODate();
+ }
+
+ const Any aPropertyValue( aDate );
+
+ OSL_ENSURE( o_propertyValues.size() == 1, "VCLDateHandler::getPropertyValues: date strings represent exactly one property - not more, not less!" );
+ for ( auto& prop : o_propertyValues )
+ {
+ prop.second = aPropertyValue;
+ }
+ return true;
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/handler/vcl_date_handler.hxx b/xmloff/source/forms/handler/vcl_date_handler.hxx
new file mode 100644
index 000000000..626ca4c77
--- /dev/null
+++ b/xmloff/source/forms/handler/vcl_date_handler.hxx
@@ -0,0 +1,40 @@
+/* -*- 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 <forms/property_handler.hxx>
+
+namespace xmloff
+{
+
+ //= VCLDateHandler
+ class VCLDateHandler : public PropertyHandlerBase
+ {
+ public:
+ VCLDateHandler();
+
+ // IPropertyHandler
+ virtual OUString getAttributeValue( const css::uno::Any& i_propertyValue ) const override;
+ virtual bool getPropertyValues( const OUString& i_attributeValue, PropertyValues& o_propertyValues ) const override;
+ };
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/handler/vcl_time_handler.cxx b/xmloff/source/forms/handler/vcl_time_handler.cxx
new file mode 100644
index 000000000..6a8c2cba1
--- /dev/null
+++ b/xmloff/source/forms/handler/vcl_time_handler.cxx
@@ -0,0 +1,96 @@
+/* -*- 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_time_handler.hxx"
+
+#include <rtl/ustrbuf.hxx>
+
+#include <com/sun/star/util/Duration.hpp>
+#include <com/sun/star/util/Time.hpp>
+
+#include <sax/tools/converter.hxx>
+
+#include <osl/diagnose.h>
+#include <tools/time.hxx>
+
+namespace xmloff
+{
+
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::util::Duration;
+ using ::com::sun::star::util::Time;
+
+ //= VCLTimeHandler
+ VCLTimeHandler::VCLTimeHandler()
+ {
+ }
+
+ OUString VCLTimeHandler::getAttributeValue( const Any& i_propertyValue ) const
+ {
+ css::util::Time aTime;
+ OSL_VERIFY( i_propertyValue >>= aTime );
+
+ Duration aDuration; // default-inited to 0
+ aDuration.Hours = aTime.Hours;
+ aDuration.Minutes = aTime.Minutes;
+ aDuration.Seconds = aTime.Seconds;
+ aDuration.NanoSeconds = aTime.NanoSeconds;
+
+ OUStringBuffer aBuffer;
+ ::sax::Converter::convertDuration( aBuffer, aDuration );
+ return aBuffer.makeStringAndClear();
+ }
+
+ bool VCLTimeHandler::getPropertyValues( const OUString& i_attributeValue, PropertyValues& o_propertyValues ) const
+ {
+ Duration aDuration;
+ css::util::Time aTime;
+ if (::sax::Converter::convertDuration( aDuration, i_attributeValue ))
+ {
+ aTime = Time(aDuration.NanoSeconds, aDuration.Seconds,
+ aDuration.Minutes, aDuration.Hours,
+ false);
+ }
+ else
+ {
+ // compatibility format, before we wrote those values in XML-schema compatible form
+ sal_Int64 nVCLTime(0);
+ if (!::sax::Converter::convertNumber64(nVCLTime, i_attributeValue))
+ {
+ OSL_ENSURE( false, "VCLTimeHandler::getPropertyValues: unknown time format (no XML-schema time, no legacy integer)!" );
+ return false;
+ }
+ // legacy integer was in centiseconds
+ nVCLTime *= ::tools::Time::nanoPerCenti;
+ aTime = ::tools::Time(nVCLTime).GetUNOTime();
+ }
+
+ const Any aPropertyValue( aTime );
+
+ OSL_ENSURE( o_propertyValues.size() == 1, "VCLTimeHandler::getPropertyValues: time strings represent exactly one property - not more, not less!" );
+ for ( auto& prop : o_propertyValues )
+ {
+ prop.second = aPropertyValue;
+ }
+ return true;
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/handler/vcl_time_handler.hxx b/xmloff/source/forms/handler/vcl_time_handler.hxx
new file mode 100644
index 000000000..a5b3b14a9
--- /dev/null
+++ b/xmloff/source/forms/handler/vcl_time_handler.hxx
@@ -0,0 +1,40 @@
+/* -*- 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 <forms/property_handler.hxx>
+
+namespace xmloff
+{
+
+ //= VCLTimeHandler
+ class VCLTimeHandler : public PropertyHandlerBase
+ {
+ public:
+ VCLTimeHandler();
+
+ // IPropertyHandler
+ virtual OUString getAttributeValue( const css::uno::Any& i_propertyValue ) const override;
+ virtual bool getPropertyValues( const OUString& i_attributeValue, PropertyValues& o_propertyValues ) const override;
+ };
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/layerexport.cxx b/xmloff/source/forms/layerexport.cxx
new file mode 100644
index 000000000..87c3b5b40
--- /dev/null
+++ b/xmloff/source/forms/layerexport.cxx
@@ -0,0 +1,727 @@
+/* -*- 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 "layerexport.hxx"
+#include "strings.hxx"
+#include <xmloff/xmlexp.hxx>
+#include <xmloff/xmlprmap.hxx>
+#include <xmloff/prhdlfac.hxx>
+#include "elementexport.hxx"
+#include <xmloff/families.hxx>
+#include <xmloff/contextid.hxx>
+#include <xmloff/controlpropertyhdl.hxx>
+#include <xmloff/maptype.hxx>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+#include "controlpropertymap.hxx"
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/form/XFormsSupplier2.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/xforms/XFormsSupplier.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/script/XEventAttacherManager.hpp>
+#include <com/sun/star/util/NumberFormatsSupplier.hpp>
+#include <xmloff/XMLEventExport.hxx>
+#include "formevents.hxx"
+#include <xmloff/xmlnumfe.hxx>
+#include <xmloff/xformsexport.hxx>
+
+#include <com/sun/star/text/XText.hpp>
+
+#include <stack>
+#include <numeric>
+
+namespace xmloff
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::drawing;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::text;
+
+ //= OFormLayerXMLExport_Impl
+ const OUString& OFormLayerXMLExport_Impl::getControlNumberStyleNamePrefix()
+ {
+ static const OUString s_sControlNumberStyleNamePrefix("C");
+ return s_sControlNumberStyleNamePrefix;
+ }
+
+ OFormLayerXMLExport_Impl::OFormLayerXMLExport_Impl(SvXMLExport& _rContext)
+ :m_rContext(_rContext)
+ ,m_pControlNumberStyles(nullptr)
+ {
+ initializePropertyMaps();
+
+ // add our style family to the export context's style pool
+ m_xPropertyHandlerFactory = new OControlPropertyHandlerFactory();
+ ::rtl::Reference< XMLPropertySetMapper > xStylePropertiesMapper = new XMLPropertySetMapper( getControlStylePropertyMap(), m_xPropertyHandlerFactory, true );
+ m_xStyleExportMapper = new OFormComponentStyleExportMapper( xStylePropertiesMapper );
+
+ // our style family
+ m_rContext.GetAutoStylePool()->AddFamily(
+ XmlStyleFamily::CONTROL_ID, token::GetXMLToken(token::XML_PARAGRAPH),
+ m_xStyleExportMapper.get(),
+ OUString( XML_STYLE_FAMILY_CONTROL_PREFIX )
+ );
+
+ // add our event translation table
+ m_rContext.GetEventExport().AddTranslationTable(g_pFormsEventTranslation);
+
+ clear();
+ }
+
+ OFormLayerXMLExport_Impl::~OFormLayerXMLExport_Impl()
+ {
+ }
+
+ bool OFormLayerXMLExport_Impl::impl_isFormPageContainingForms(const Reference< XDrawPage >& _rxDrawPage, Reference< XIndexAccess >& _rxForms)
+ {
+ Reference< XFormsSupplier2 > xFormsSupp(_rxDrawPage, UNO_QUERY);
+ OSL_ENSURE(xFormsSupp.is(), "OFormLayerXMLExport_Impl::impl_isFormPageContainingForms: invalid draw page (no XFormsSupplier)! Doin' nothing!");
+ if (!xFormsSupp.is())
+ return false;
+
+ if ( !xFormsSupp->hasForms() )
+ // nothing to do at all
+ return false;
+
+ _rxForms.set(xFormsSupp->getForms(), UNO_QUERY);
+ Reference< XServiceInfo > xSI(_rxForms, UNO_QUERY); // order is important!
+ OSL_ENSURE(xSI.is(), "OFormLayerXMLExport_Impl::impl_isFormPageContainingForms: invalid collection (must not be NULL and must have a ServiceInfo)!");
+ if (!xSI.is())
+ return false;
+
+ if (!xSI->supportsService("com.sun.star.form.Forms"))
+ {
+ OSL_FAIL("OFormLayerXMLExport_Impl::impl_isFormPageContainingForms: invalid collection (is no com.sun.star.form.Forms)!");
+ // nothing to do
+ return false;
+ }
+ return true;
+ }
+
+ void OFormLayerXMLExport_Impl::exportGridColumn(const Reference< XPropertySet >& _rxColumn,
+ const Sequence< ScriptEventDescriptor >& _rEvents)
+ {
+ // do the exporting
+ OColumnExport aExportImpl(*this, _rxColumn, getControlId( _rxColumn ), _rEvents);
+ aExportImpl.doExport();
+ }
+
+ void OFormLayerXMLExport_Impl::exportControl(const Reference< XPropertySet >& _rxControl,
+ const Sequence< ScriptEventDescriptor >& _rEvents)
+ {
+ // the list of the referring controls
+ OUString sReferringControls;
+ MapPropertySet2String::const_iterator aReferring = m_aCurrentPageReferring->second.find(_rxControl);
+ if (aReferring != m_aCurrentPageReferring->second.end())
+ sReferringControls = aReferring->second;
+
+ // the control id (should already have been created in examineForms)
+ OUString sControlId( getControlId( _rxControl ) );
+
+ // do the exporting
+ OControlExport aExportImpl(*this, _rxControl, sControlId, sReferringControls, _rEvents);
+ aExportImpl.doExport();
+ }
+
+ void OFormLayerXMLExport_Impl::exportForm(const Reference< XPropertySet >& _rxProps,
+ const Sequence< ScriptEventDescriptor >& _rEvents)
+ {
+ OSL_ENSURE(_rxProps.is(), "OFormLayerXMLExport_Impl::exportForm: invalid property set!");
+ OFormExport aAttributeHandler(*this, _rxProps, _rEvents);
+ aAttributeHandler.doExport();
+ }
+
+ ::rtl::Reference< SvXMLExportPropertyMapper > OFormLayerXMLExport_Impl::getStylePropertyMapper()
+ {
+ return m_xStyleExportMapper;
+ }
+
+ SvXMLExport& OFormLayerXMLExport_Impl::getGlobalContext()
+ {
+ return m_rContext;
+ }
+
+ void OFormLayerXMLExport_Impl::exportCollectionElements(const Reference< XIndexAccess >& _rxCollection)
+ {
+ // step through all the elements of the collection
+ sal_Int32 nElements = _rxCollection->getCount();
+
+ Reference< XEventAttacherManager > xElementEventManager(_rxCollection, UNO_QUERY);
+ Sequence< ScriptEventDescriptor > aElementEvents;
+
+ Reference< XPropertySetInfo > xPropsInfo;
+ for (sal_Int32 i=0; i<nElements; ++i)
+ {
+ try
+ {
+ // extract the current element
+ Reference< XPropertySet > xCurrentProps( _rxCollection->getByIndex(i), UNO_QUERY );
+ OSL_ENSURE(xCurrentProps.is(), "OFormLayerXMLExport_Impl::exportCollectionElements: invalid child element, skipping!");
+ if (!xCurrentProps.is())
+ continue;
+
+ // check if there is a ClassId property on the current element. If so, we assume it to be a control
+ xPropsInfo = xCurrentProps->getPropertySetInfo();
+ OSL_ENSURE(xPropsInfo.is(), "OFormLayerXMLExport_Impl::exportCollectionElements: no property set info!");
+ if (!xPropsInfo.is())
+ // without this, a lot of stuff in the export routines may fail
+ continue;
+
+ // if the element is part of an ignore list, we are not allowed to export it
+ if ( m_aIgnoreList.end() != m_aIgnoreList.find( xCurrentProps ) )
+ continue;
+
+ if (xElementEventManager.is())
+ aElementEvents = xElementEventManager->getScriptEvents(i);
+
+ if (xPropsInfo->hasPropertyByName(PROPERTY_COLUMNSERVICENAME))
+ {
+ exportGridColumn(xCurrentProps, aElementEvents);
+ }
+ else if (xPropsInfo->hasPropertyByName(PROPERTY_CLASSID))
+ {
+ exportControl(xCurrentProps, aElementEvents);
+ }
+ else
+ {
+ exportForm(xCurrentProps, aElementEvents);
+ }
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("xmloff.forms",
+ "caught an exception ... skipping the current element!");
+ continue;
+ }
+ }
+ }
+
+ OUString OFormLayerXMLExport_Impl::getObjectStyleName( const Reference< XPropertySet >& _rxObject )
+ {
+ OUString aObjectStyle;
+
+ MapPropertySet2String::const_iterator aObjectStylePos = m_aGridColumnStyles.find( _rxObject );
+ if ( m_aGridColumnStyles.end() != aObjectStylePos )
+ aObjectStyle = aObjectStylePos->second;
+ return aObjectStyle;
+ }
+
+ void OFormLayerXMLExport_Impl::clear()
+ {
+ m_aControlIds.clear();
+ m_aReferringControls.clear();
+ m_aCurrentPageIds = m_aControlIds.end();
+ m_aCurrentPageReferring = m_aReferringControls.end();
+
+ m_aControlNumberFormats.clear();
+ m_aGridColumnStyles.clear();
+
+ m_aIgnoreList.clear();
+ }
+
+ void OFormLayerXMLExport_Impl::exportAutoControlNumberStyles()
+ {
+ if ( m_pControlNumberStyles )
+ m_pControlNumberStyles->Export( true );
+ }
+
+ void OFormLayerXMLExport_Impl::exportAutoStyles()
+ {
+ m_rContext.GetAutoStylePool()->exportXML( XmlStyleFamily::CONTROL_ID );
+ }
+
+ void OFormLayerXMLExport_Impl::exportForms(const Reference< XDrawPage >& _rxDrawPage)
+ {
+ // get the forms collection of the page
+ Reference< XIndexAccess > xCollectionIndex;
+ if (!impl_isFormPageContainingForms(_rxDrawPage, xCollectionIndex))
+ {
+ return;
+ }
+
+ bool bPageIsKnown = implMoveIterators(_rxDrawPage, false);
+ OSL_ENSURE(bPageIsKnown, "OFormLayerXMLExport_Impl::exportForms: exporting a page which has not been examined!");
+
+ // export forms collection
+ exportCollectionElements(xCollectionIndex);
+ }
+
+ void OFormLayerXMLExport_Impl::exportXForms() const
+ {
+ // export XForms models
+ ::exportXForms( m_rContext );
+ }
+
+ bool OFormLayerXMLExport_Impl::pageContainsForms( const Reference< XDrawPage >& _rxDrawPage )
+ {
+ Reference< XFormsSupplier2 > xFormsSupp( _rxDrawPage, UNO_QUERY );
+ SAL_WARN_IF( !xFormsSupp.is(), "xmloff", "OFormLayerXMLExport_Impl::pageContainsForms: no XFormsSupplier2!" );
+ return xFormsSupp.is() && xFormsSupp->hasForms();
+ }
+
+ bool OFormLayerXMLExport_Impl::documentContainsXForms() const
+ {
+ Reference< css::xforms::XFormsSupplier > xXFormSupp( m_rContext.GetModel(), UNO_QUERY );
+ Reference< XNameContainer > xForms;
+ if ( xXFormSupp.is() )
+ xForms = xXFormSupp->getXForms();
+ return xForms.is() && xForms->hasElements();
+ }
+
+ bool OFormLayerXMLExport_Impl::implMoveIterators(const Reference< XDrawPage >& _rxDrawPage, bool _bClear)
+ {
+ if (!_rxDrawPage.is())
+ return false;
+
+ bool bKnownPage = false;
+
+ // the one for the ids
+ m_aCurrentPageIds = m_aControlIds.find(_rxDrawPage);
+ if (m_aControlIds.end() == m_aCurrentPageIds)
+ {
+ m_aControlIds[_rxDrawPage] = MapPropertySet2String();
+ m_aCurrentPageIds = m_aControlIds.find(_rxDrawPage);
+ }
+ else
+ {
+ bKnownPage = true;
+ if (_bClear && !m_aCurrentPageIds->second.empty() )
+ m_aCurrentPageIds->second.clear();
+ }
+
+ // the one for the ids of the referring controls
+ m_aCurrentPageReferring = m_aReferringControls.find(_rxDrawPage);
+ if (m_aReferringControls.end() == m_aCurrentPageReferring)
+ {
+ m_aReferringControls[_rxDrawPage] = MapPropertySet2String();
+ m_aCurrentPageReferring = m_aReferringControls.find(_rxDrawPage);
+ }
+ else
+ {
+ bKnownPage = true;
+ if (_bClear && !m_aCurrentPageReferring->second.empty() )
+ m_aCurrentPageReferring->second.clear();
+ }
+ return bKnownPage;
+ }
+
+ bool OFormLayerXMLExport_Impl::seekPage(const Reference< XDrawPage >& _rxDrawPage)
+ {
+ bool bKnownPage = implMoveIterators( _rxDrawPage, false );
+ if ( bKnownPage )
+ return true;
+
+ // if the page is not yet known, this does not automatically mean that it has
+ // not been examined. Instead, examineForms returns silently and successfully
+ // if a page is a XFormsPageSupplier2, but does not have a forms collection
+ // (This behaviour of examineForms is a performance optimization, to not force
+ // the page to create a forms container just to see that it's empty.)
+
+ // So, in such a case, seekPage is considered to be successful, too, though the
+ // page was not yet known
+ Reference< XFormsSupplier2 > xFormsSupp( _rxDrawPage, UNO_QUERY );
+ if ( xFormsSupp.is() && !xFormsSupp->hasForms() )
+ return true;
+
+ // anything else means that the page has not been examined before, or it's no
+ // valid form page. Both cases are Bad (TM).
+ return false;
+ }
+
+ OUString OFormLayerXMLExport_Impl::getControlId(const Reference< XPropertySet >& _rxControl)
+ {
+ if (m_aCurrentPageIds == m_aControlIds.end())
+ return OUString();
+
+ OSL_ENSURE(m_aCurrentPageIds->second.end() != m_aCurrentPageIds->second.find(_rxControl),
+ "OFormLayerXMLExport_Impl::getControlId: can not find the control!");
+ return m_aCurrentPageIds->second[_rxControl];
+ }
+
+ OUString OFormLayerXMLExport_Impl::getImmediateNumberStyle( const Reference< XPropertySet >& _rxObject )
+ {
+ OUString sNumberStyle;
+
+ sal_Int32 nOwnFormatKey = implExamineControlNumberFormat( _rxObject );
+ if ( -1 != nOwnFormatKey )
+ sNumberStyle = getControlNumberStyleExport()->GetStyleName( nOwnFormatKey );
+
+ return sNumberStyle;
+ }
+
+ OUString OFormLayerXMLExport_Impl::getControlNumberStyle( const Reference< XPropertySet >& _rxControl )
+ {
+ OUString sNumberStyle;
+
+ MapPropertySet2Int::const_iterator aControlFormatPos = m_aControlNumberFormats.find(_rxControl);
+ if (m_aControlNumberFormats.end() != aControlFormatPos)
+ {
+ OSL_ENSURE(m_pControlNumberStyles, "OFormLayerXMLExport_Impl::getControlNumberStyle: have a control which has a format style, but no style exporter!");
+ sNumberStyle = getControlNumberStyleExport()->GetStyleName(aControlFormatPos->second);
+ }
+ // it's allowed to ask for a control which does not have format information.
+ // (This is for performance reasons)
+
+ return sNumberStyle;
+ }
+
+ void OFormLayerXMLExport_Impl::examineForms(const Reference< XDrawPage >& _rxDrawPage)
+ {
+ // get the forms collection of the page
+ Reference< XIndexAccess > xCollectionIndex;
+ if (!impl_isFormPageContainingForms(_rxDrawPage, xCollectionIndex))
+ {
+ return;
+ }
+
+ // move the iterator which specify the currently handled page
+ bool bPageIsKnown = implMoveIterators(_rxDrawPage, true);
+ OSL_ENSURE(!bPageIsKnown, "OFormLayerXMLExport_Impl::examineForms: examining a page twice!");
+
+ ::std::stack< Reference< XIndexAccess > > aContainerHistory;
+ ::std::stack< sal_Int32 > aIndexHistory;
+
+ Reference< XIndexAccess > xLoop = xCollectionIndex;
+ sal_Int32 nChildPos = 0;
+ do
+ {
+ if (nChildPos < xLoop->getCount())
+ {
+ Reference< XPropertySet > xCurrent( xLoop->getByIndex( nChildPos ), UNO_QUERY );
+ OSL_ENSURE(xCurrent.is(), "OFormLayerXMLExport_Impl::examineForms: invalid child object");
+ if (!xCurrent.is())
+ continue;
+
+ if (!checkExamineControl(xCurrent))
+ {
+ // step down
+ Reference< XIndexAccess > xNextContainer(xCurrent, UNO_QUERY);
+ OSL_ENSURE(xNextContainer.is(), "OFormLayerXMLExport_Impl::examineForms: what the heck is this ... no control, no container?");
+ aContainerHistory.push(xLoop);
+ aIndexHistory.push(nChildPos);
+
+ xLoop = xNextContainer;
+ nChildPos = -1; // will be incremented below
+ }
+ ++nChildPos;
+ }
+ else
+ {
+ // step up
+ while ((nChildPos >= xLoop->getCount()) && !aContainerHistory.empty() )
+ {
+ xLoop = aContainerHistory.top();
+ aContainerHistory.pop();
+ nChildPos = aIndexHistory.top();
+ aIndexHistory.pop();
+
+ ++nChildPos;
+ }
+ if (nChildPos >= xLoop->getCount())
+ // exited the loop above because we have no history anymore (0 == aContainerHistory.size()),
+ // and on the current level there are no more children
+ // -> leave
+ break;
+ }
+ }
+ while (xLoop.is());
+ }
+
+ namespace
+ {
+ struct AccumulateSize
+ {
+ size_t operator()( size_t _size, const MapPropertySet2Map::value_type& _map ) const
+ {
+ return _size + _map.second.size();
+ }
+ };
+
+ OUString lcl_findFreeControlId( const MapPropertySet2Map& _rAllPagesControlIds )
+ {
+ OUString sControlId = "control";
+
+ size_t nKnownControlCount = ::std::accumulate( _rAllPagesControlIds.begin(), _rAllPagesControlIds.end(), size_t(0), AccumulateSize() );
+ sControlId += OUString::number( static_cast<sal_Int32>(nKnownControlCount) + 1 );
+
+ #ifdef DBG_UTIL
+ // Check if the id is already used. It shouldn't, as we currently have no mechanism for removing entries
+ // from the map, so the approach used above (take the accumulated map size) should be sufficient. But if
+ // somebody changes this (e.g. allows removing entries from the map), the assertion below probably will fail.
+ for ( const auto& outer : _rAllPagesControlIds )
+ for ( const auto& inner : outer.second )
+ {
+ OSL_ENSURE( inner.second != sControlId,
+ "lcl_findFreeControlId: auto-generated control ID is already used!" );
+ }
+ #endif
+ return sControlId;
+ }
+ }
+
+ bool OFormLayerXMLExport_Impl::checkExamineControl(const Reference< XPropertySet >& _rxObject)
+ {
+ Reference< XPropertySetInfo > xCurrentInfo = _rxObject->getPropertySetInfo();
+ OSL_ENSURE(xCurrentInfo.is(), "OFormLayerXMLExport_Impl::checkExamineControl: no property set info");
+
+ bool bIsControl = xCurrentInfo->hasPropertyByName( PROPERTY_CLASSID );
+ if (bIsControl)
+ {
+ // generate a new control id
+
+ // find a free id
+ OUString sCurrentId = lcl_findFreeControlId( m_aControlIds );
+ // add it to the map
+ m_aCurrentPageIds->second[_rxObject] = sCurrentId;
+
+ // check if this control has a "LabelControl" property referring another control
+ if ( xCurrentInfo->hasPropertyByName( PROPERTY_CONTROLLABEL ) )
+ {
+ Reference< XPropertySet > xCurrentReference( _rxObject->getPropertyValue( PROPERTY_CONTROLLABEL ), UNO_QUERY );
+ if (xCurrentReference.is())
+ {
+ OUString& sReferencedBy = m_aCurrentPageReferring->second[xCurrentReference];
+ if (!sReferencedBy.isEmpty())
+ // it's not the first _rxObject referring to the xCurrentReference
+ // -> separate the id
+ sReferencedBy += ",";
+ sReferencedBy += sCurrentId;
+ }
+ }
+
+ // check if the control needs a number format style
+ if ( xCurrentInfo->hasPropertyByName( PROPERTY_FORMATKEY ) )
+ {
+ examineControlNumberFormat(_rxObject);
+ }
+
+ // check if it's a control providing text
+ Reference< XText > xControlText( _rxObject, UNO_QUERY );
+ if ( xControlText.is() )
+ {
+ m_rContext.GetTextParagraphExport()->collectTextAutoStyles( xControlText );
+ }
+
+ // check if it is a grid control - in this case, we need special handling for the columns
+ sal_Int16 nControlType = FormComponentType::CONTROL;
+ _rxObject->getPropertyValue( PROPERTY_CLASSID ) >>= nControlType;
+ if ( FormComponentType::GRIDCONTROL == nControlType )
+ {
+ collectGridColumnStylesAndIds( _rxObject );
+ }
+ }
+
+ return bIsControl;
+ }
+
+ void OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds( const Reference< XPropertySet >& _rxControl )
+ {
+ // loop through all columns of the grid
+ try
+ {
+ Reference< XIndexAccess > xContainer( _rxControl, UNO_QUERY );
+ OSL_ENSURE( xContainer.is(), "OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds: grid control not being a container?!" );
+ if ( !xContainer.is() )
+ return;
+
+ Reference< XPropertySetInfo > xColumnPropertiesMeta;
+
+ sal_Int32 nCount = xContainer->getCount();
+ for ( sal_Int32 i=0; i<nCount; ++i )
+ {
+ Reference< XPropertySet > xColumnProperties( xContainer->getByIndex( i ), UNO_QUERY );
+ OSL_ENSURE( xColumnProperties.is(), "OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds: invalid grid column encountered!" );
+ if ( !xColumnProperties.is() )
+ continue;
+
+ // generate a new control id
+
+ // find a free id
+ OUString sCurrentId = lcl_findFreeControlId( m_aControlIds );
+ // add it to the map
+ m_aCurrentPageIds->second[ xColumnProperties ] = sCurrentId;
+
+ // determine a number style, if needed
+ xColumnPropertiesMeta = xColumnProperties->getPropertySetInfo();
+ // get the styles of the column
+ ::std::vector<XMLPropertyState> aPropertyStates = m_xStyleExportMapper->Filter(m_rContext, xColumnProperties);
+
+ // care for the number format, additionally
+ OUString sColumnNumberStyle;
+ if ( xColumnPropertiesMeta.is() && xColumnPropertiesMeta->hasPropertyByName( PROPERTY_FORMATKEY ) )
+ sColumnNumberStyle = getImmediateNumberStyle( xColumnProperties );
+
+ if ( !sColumnNumberStyle.isEmpty() )
+ { // the column indeed has a formatting
+ sal_Int32 nStyleMapIndex = m_xStyleExportMapper->getPropertySetMapper()->FindEntryIndex( CTF_FORMS_DATA_STYLE );
+ // TODO: move this to the ctor
+ OSL_ENSURE ( -1 != nStyleMapIndex, "OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds: could not obtain the index for our context id!");
+
+ XMLPropertyState aNumberStyleState( nStyleMapIndex, Any( sColumnNumberStyle ) );
+ aPropertyStates.push_back( aNumberStyleState );
+ }
+
+ // determine the column style
+
+ if ( !aPropertyStates.empty() )
+ { // add to the style pool
+ OUString sColumnStyleName = m_rContext.GetAutoStylePool()->Add( XmlStyleFamily::CONTROL_ID, std::move(aPropertyStates) );
+
+ OSL_ENSURE( m_aGridColumnStyles.end() == m_aGridColumnStyles.find( xColumnProperties ),
+ "OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds: already have a style for this column!" );
+
+ m_aGridColumnStyles.emplace( xColumnProperties, sColumnStyleName );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("xmloff.forms");
+ }
+ }
+
+ sal_Int32 OFormLayerXMLExport_Impl::implExamineControlNumberFormat( const Reference< XPropertySet >& _rxObject )
+ {
+ // get the format key relative to our own formats supplier
+ sal_Int32 nOwnFormatKey = ensureTranslateFormat( _rxObject );
+
+ if ( -1 != nOwnFormatKey )
+ // tell the exporter that we used this format
+ getControlNumberStyleExport()->SetUsed( nOwnFormatKey );
+
+ return nOwnFormatKey;
+ }
+
+ void OFormLayerXMLExport_Impl::examineControlNumberFormat( const Reference< XPropertySet >& _rxControl )
+ {
+ sal_Int32 nOwnFormatKey = implExamineControlNumberFormat( _rxControl );
+
+ if ( -1 == nOwnFormatKey )
+ // nothing to do, the number format of this control is void
+ return;
+
+ // remember the format key for this control (we'll be asked in getControlNumberStyle for this)
+ OSL_ENSURE(m_aControlNumberFormats.end() == m_aControlNumberFormats.find(_rxControl),
+ "OFormLayerXMLExport_Impl::examineControlNumberFormat: already handled this control!");
+ m_aControlNumberFormats[_rxControl] = nOwnFormatKey;
+ }
+
+ sal_Int32 OFormLayerXMLExport_Impl::ensureTranslateFormat(const Reference< XPropertySet >& _rxFormattedControl)
+ {
+ ensureControlNumberStyleExport();
+ OSL_ENSURE(m_xControlNumberFormats.is(), "OFormLayerXMLExport_Impl::ensureTranslateFormat: no own formats supplier!");
+ // (should have been created in ensureControlNumberStyleExport)
+
+ sal_Int32 nOwnFormatKey = -1;
+
+ // the format key (relative to the control's supplier)
+ sal_Int32 nControlFormatKey = -1;
+ Any aControlFormatKey = _rxFormattedControl->getPropertyValue(PROPERTY_FORMATKEY);
+ if (aControlFormatKey >>= nControlFormatKey)
+ {
+ // the control's number format
+ Reference< XNumberFormatsSupplier > xControlFormatsSupplier;
+ _rxFormattedControl->getPropertyValue(PROPERTY_FORMATSSUPPLIER) >>= xControlFormatsSupplier;
+ Reference< XNumberFormats > xControlFormats;
+ if (xControlFormatsSupplier.is())
+ xControlFormats = xControlFormatsSupplier->getNumberFormats();
+ OSL_ENSURE(xControlFormats.is(), "OFormLayerXMLExport_Impl::ensureTranslateFormat: formatted control without supplier!");
+
+ // obtain the persistent (does not depend on the formats supplier) representation of the control's format
+ Locale aFormatLocale;
+ OUString sFormatDescription;
+ if (xControlFormats.is())
+ {
+ Reference< XPropertySet > xControlFormat = xControlFormats->getByKey(nControlFormatKey);
+
+ xControlFormat->getPropertyValue(PROPERTY_LOCALE) >>= aFormatLocale;
+ xControlFormat->getPropertyValue(PROPERTY_FORMATSTRING) >>= sFormatDescription;
+ }
+
+ // check if our own formats collection already knows the format
+ nOwnFormatKey = m_xControlNumberFormats->queryKey(sFormatDescription, aFormatLocale, false);
+ if (-1 == nOwnFormatKey)
+ { // no, we don't
+ // -> create a new format
+ nOwnFormatKey = m_xControlNumberFormats->addNew(sFormatDescription, aFormatLocale);
+ }
+ OSL_ENSURE(-1 != nOwnFormatKey, "OFormLayerXMLExport_Impl::ensureTranslateFormat: could not translate the controls format key!");
+ }
+ else
+ OSL_ENSURE(!aControlFormatKey.hasValue(), "OFormLayerXMLExport_Impl::ensureTranslateFormat: invalid number format property value!");
+
+ return nOwnFormatKey;
+ }
+
+ void OFormLayerXMLExport_Impl::ensureControlNumberStyleExport()
+ {
+ if (m_pControlNumberStyles)
+ return;
+
+ // create our number formats supplier (if necessary)
+ Reference< XNumberFormatsSupplier > xFormatsSupplier;
+
+ OSL_ENSURE(!m_xControlNumberFormats.is(), "OFormLayerXMLExport_Impl::getControlNumberStyleExport: inconsistence!");
+ // the m_xControlNumberFormats and m_pControlNumberStyles should be maintained together
+
+ try
+ {
+ // create it for en-US (does not really matter, as we will specify a locale for every
+ // concrete language to use)
+ Locale aLocale ( "en", "US", OUString() );
+ xFormatsSupplier = NumberFormatsSupplier::createWithLocale( m_rContext.getComponentContext(), aLocale );
+ m_xControlNumberFormats = xFormatsSupplier->getNumberFormats();
+ }
+ catch(const Exception&)
+ {
+ }
+
+ OSL_ENSURE(m_xControlNumberFormats.is(), "OFormLayerXMLExport_Impl::getControlNumberStyleExport: could not obtain my default number formats!");
+
+ // create the exporter
+ m_pControlNumberStyles = new SvXMLNumFmtExport(m_rContext, xFormatsSupplier, getControlNumberStyleNamePrefix());
+ }
+
+ SvXMLNumFmtExport* OFormLayerXMLExport_Impl::getControlNumberStyleExport()
+ {
+ ensureControlNumberStyleExport();
+ return m_pControlNumberStyles;
+ }
+
+ void OFormLayerXMLExport_Impl::excludeFromExport( const Reference< XControlModel >& _rxControl )
+ {
+ Reference< XPropertySet > xProps( _rxControl, UNO_QUERY );
+ OSL_ENSURE( xProps.is(), "OFormLayerXMLExport_Impl::excludeFromExport: invalid control model!" );
+ ::std::pair< PropertySetBag::const_iterator, bool > aPos =
+ m_aIgnoreList.insert( xProps );
+ OSL_ENSURE( aPos.second, "OFormLayerXMLExport_Impl::excludeFromExport: element already exists in the ignore list!" );
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/layerexport.hxx b/xmloff/source/forms/layerexport.hxx
new file mode 100644
index 000000000..4d19386ef
--- /dev/null
+++ b/xmloff/source/forms/layerexport.hxx
@@ -0,0 +1,299 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <unordered_map>
+
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/script/ScriptEventDescriptor.hpp>
+#include <com/sun/star/util/XNumberFormats.hpp>
+#include <com/sun/star/awt/XControlModel.hpp>
+#include "callbacks.hxx"
+#include <rtl/ref.hxx>
+#include <o3tl/sorted_vector.hxx>
+
+class SvXMLExport;
+class SvXMLNumFmtExport;
+class XMLPropertyHandlerFactory;
+class SvXMLExportPropertyMapper;
+
+namespace xmloff
+{
+
+ typedef o3tl::sorted_vector< css::uno::Reference< css::beans::XPropertySet > > PropertySetBag;
+
+ // maps objects (property sets) to strings, e.g. control ids.
+ typedef ::std::unordered_map < css::uno::Reference< css::beans::XPropertySet >
+ , OUString
+ > MapPropertySet2String;
+
+ // map pages to maps (of property sets to strings)
+ typedef ::std::unordered_map < css::uno::Reference< css::drawing::XDrawPage >
+ , MapPropertySet2String
+ > MapPropertySet2Map;
+
+ //= OFormLayerXMLExport_Impl
+ /** the implementation class for OFormLayerXMLExport
+ */
+ class OFormLayerXMLExport_Impl
+ :public IFormsExportContext
+ {
+ friend class OFormLayerXMLExport;
+
+ SvXMLExport& m_rContext;
+ SvXMLNumFmtExport* m_pControlNumberStyles;
+
+ // ignore list for control models
+ PropertySetBag m_aIgnoreList;
+
+ // style handling
+ ::rtl::Reference< XMLPropertyHandlerFactory > m_xPropertyHandlerFactory;
+ ::rtl::Reference< SvXMLExportPropertyMapper > m_xStyleExportMapper;
+
+ // we need our own number formats supplier:
+ // Controls which have a number formats do not work with the formats supplier of the document they reside
+ // in, instead they use the formats of the data source their form is associated with. If there is no
+ // such form or no such data source, they work with an own formatter.
+ // Even more, time and date fields do not work with a central formatter at all, they have their own one
+ // (which is shared internally, but this is a (hidden) implementation detail.)
+
+ // To not contaminate the global (document) number formats supplier (which could be obtained from the context),
+ // we have an own one.
+ // (Contaminate means: If a user adds a user-defined format to a formatted field, this format is stored in
+ // in the data source's formats supplier. To export this _and_ reuse existing structures, we would need to
+ // add this format to the global (document) formats supplier.
+ // In case of an export we could do some cleanup afterwards, but in case of an import, there is no such
+ // chance, as (if other user-defined formats exist in the document as well) we can't distinguish
+ // between user-defined formats really needed for the doc (i.e. in a calc cell) and formats only added
+ // to the supplier because the controls needed it.
+ css::uno::Reference< css::util::XNumberFormats >
+ m_xControlNumberFormats;
+
+ MapPropertySet2Map m_aControlIds;
+ // the control ids of all controls on all pages we ever examined
+
+ MapPropertySet2Map m_aReferringControls;
+ // for a given page (iter->first), and a given control (iter->second->first), this is the comma-separated
+ // lists of ids of the controls referring to the control given.
+
+ MapPropertySet2Map::iterator
+ m_aCurrentPageIds;
+ // the iterator for the control id map for the page being handled
+ MapPropertySet2Map::iterator
+ m_aCurrentPageReferring;
+ // the same for the map of referring controls
+
+ // TODO: To avoid this construct above, and to have a cleaner implementation, a class encapsulating the
+ // export of a single page should be introduced.
+
+ typedef std::unordered_map<css::uno::Reference<css::beans::XPropertySet>, sal_Int32> MapPropertySet2Int;
+ MapPropertySet2Int m_aControlNumberFormats;
+ // maps controls to format keys, which are relative to our own formats supplier
+
+ MapPropertySet2String m_aGridColumnStyles;
+ // style names of grid columns
+
+ public:
+ explicit OFormLayerXMLExport_Impl(SvXMLExport& _rContext);
+ virtual ~OFormLayerXMLExport_Impl();
+
+ private:
+ /** exports one single grid column
+ */
+ void exportGridColumn(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxColumn,
+ const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents
+ );
+
+ /** exports one single control
+ */
+ void exportControl(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControl,
+ const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents
+ );
+
+ /** exports one single form
+ */
+ void exportForm(const css::uno::Reference< css::beans::XPropertySet >& _rxProps,
+ const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents
+ );
+
+ /** seek to the page given.
+
+ <p>This must be called before you can retrieve any ids for controls on the page.</p>
+
+ @see
+ getControlId
+ */
+ bool seekPage(
+ const css::uno::Reference< css::drawing::XDrawPage >& _rxDrawPage);
+
+ /** get the id of the given control.
+
+ <p>You must have sought to the page of the control before calling this.</p>
+ */
+ OUString
+ getControlId(const css::uno::Reference< css::beans::XPropertySet >& _rxControl);
+
+ /** retrieves the style name for the control's number style.
+
+ <p>For performance reasons, this method is allowed to be called for any controls, even those which
+ do not have a number style. In this case, an empty string is returned.</p>
+ */
+ OUString
+ getControlNumberStyle( const css::uno::Reference< css::beans::XPropertySet >& _rxControl );
+
+ // IFormsExportContext
+ virtual void exportCollectionElements(const css::uno::Reference< css::container::XIndexAccess >& _rxCollection) override;
+ virtual SvXMLExport& getGlobalContext() override;
+ virtual OUString getObjectStyleName(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) override;
+ virtual ::rtl::Reference< SvXMLExportPropertyMapper > getStylePropertyMapper() override;
+
+ /** clear any structures which have been build in the recent <method>examine</method> calls.
+ */
+ void clear();
+
+ /** examine a forms collection.
+
+ <p>The method will collect control ids and add styles to the export context as necessary.</p>
+
+ <p>Every control in the object hierarchy given will be assigned to a unique id, which is stored for later
+ use.</p>
+
+ <p>In addition, any references the controls may have between each other, are collected and stored for
+ later use.</p>
+
+ <p>Upon calling this method, the id map will be cleared before collecting the new ids, so any ids
+ you collected previously will be lost</p>
+
+ @param _rxDrawPage
+ the draw page which's forms collection should be examined
+
+ @see getControlId
+ @see exportControl
+ @see exportForms
+ */
+ void examineForms(
+ const css::uno::Reference< css::drawing::XDrawPage >& _rxDrawPage);
+
+ /** export a forms collection of a draw page
+
+ <p>The method will obtain the forms collection of the page and call
+ <method>exportCollectionElements</method>.</p>
+ */
+ void exportForms(
+ const css::uno::Reference< css::drawing::XDrawPage >& _rxDrawPage);
+
+ /** exports the XForms model data
+ */
+ void exportXForms() const;
+
+ /** determines whether the given page contains logical forms
+ */
+ static bool pageContainsForms( const css::uno::Reference< css::drawing::XDrawPage >& _rxDrawPage );
+
+ /** determines whether the given page contains XForm instances
+ */
+ bool documentContainsXForms() const;
+
+ /** exports the automatic control number styles
+ */
+ void exportAutoControlNumberStyles();
+
+ /** exports the auto-styles collected during the examineForms calls
+ */
+ void exportAutoStyles();
+
+ static bool impl_isFormPageContainingForms(
+ const css::uno::Reference< css::drawing::XDrawPage >& _rxDrawPage,
+ css::uno::Reference< css::container::XIndexAccess >& _rxForms);
+
+ /** moves the m_aCurrentPage* members to the positions specifying the given page.
+
+ @return <TRUE/> if there already were structures for the given page
+ */
+ bool implMoveIterators(
+ const css::uno::Reference< css::drawing::XDrawPage >& _rxDrawPage,
+ bool _bClear);
+
+ /** check the object given if it's a control, if so, examine it.
+ @return <TRUE/> if the object has been handled
+ */
+ bool checkExamineControl(const css::uno::Reference< css::beans::XPropertySet >& _rxObject);
+
+ /** examines the control's number format, so later the format style can be referred
+
+ <p>remembers the format key for the control, so it can later be asked for in getControlNumberStyle</p>
+ */
+ void examineControlNumberFormat(const css::uno::Reference< css::beans::XPropertySet >& _rxControl);
+
+ /** examines the control's number format, so later the format style can be referred
+
+ <p>does not remember the information returned in any way</p>
+ */
+ sal_Int32 implExamineControlNumberFormat( const css::uno::Reference< css::beans::XPropertySet >& _rxObject );
+
+ /** collects AutoStyles for grid columns
+ */
+ void collectGridColumnStylesAndIds( const css::uno::Reference< css::beans::XPropertySet >& _rxControl );
+
+ /** ensures that the number format of the given control exist in our own formats supplier.
+
+ <p>The given control is examined for its format (i.e. it's FormatKey/FormatsSupplier properties),
+ and the format is added (if necessary) to m_xControlNumberFormats</p>.
+
+ @return
+ the format key of the control's format relative to our own formats supplier
+
+ */
+ sal_Int32 ensureTranslateFormat(const css::uno::Reference< css::beans::XPropertySet >& _rxFormattedControl);
+
+ /// returns the instance exporting our control's number styles
+ SvXMLNumFmtExport* getControlNumberStyleExport();
+
+ /// ensures that the instance exporting our control's number styles exists
+ void ensureControlNumberStyleExport();
+
+ /** determines the number format style for the given object without remembering it
+ */
+ OUString
+ getImmediateNumberStyle( const css::uno::Reference< css::beans::XPropertySet >& _rxObject );
+
+ /** returns the prefix to be used for control number styles
+ */
+ static const OUString& getControlNumberStyleNamePrefix();
+
+ /** exclude the given control (model) from export.
+
+ <p>If your document contains form controls which are not to be exported for whatever reason,
+ you need to announce the models of these controls (can be retrieved from XControlShape::getControl)
+ to the form layer exporter.<br/>
+ Of course you have to do this before calling <member>exportForms</member></p>
+ */
+ void excludeFromExport( const css::uno::Reference< css::awt::XControlModel >& _rxControl );
+ };
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/layerimport.cxx b/xmloff/source/forms/layerimport.cxx
new file mode 100644
index 000000000..e5d2c62af
--- /dev/null
+++ b/xmloff/source/forms/layerimport.cxx
@@ -0,0 +1,553 @@
+/* -*- 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 "layerimport.hxx"
+#include "formenums.hxx"
+#include "elementimport.hxx"
+#include "officeforms.hxx"
+#include "strings.hxx"
+#include <xmloff/xmlictxt.hxx>
+#include <xmloff/xmlstyle.hxx>
+#include <xmloff/families.hxx>
+#include <xmloff/xmlimp.hxx>
+#include <XMLEventImportHelper.hxx>
+#include <xmloff/xmlnumfi.hxx>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/form/FormSubmitEncoding.hpp>
+#include <com/sun/star/form/FormSubmitMethod.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/form/NavigationBarMode.hpp>
+#include <com/sun/star/form/TabulatorCycle.hpp>
+#include <com/sun/star/form/FormButtonType.hpp>
+#include <com/sun/star/form/ListSourceType.hpp>
+#include "formevents.hxx"
+#include "formcellbinding.hxx"
+#include <xmloff/xformsimport.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <rtl/strbuf.hxx>
+#include <tools/diagnose_ex.h>
+#include <algorithm>
+
+namespace xmloff
+{
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::sdb;
+using namespace token;
+
+//= OFormLayerXMLImport_Impl
+OFormLayerXMLImport_Impl::OFormLayerXMLImport_Impl(SvXMLImport& _rImporter)
+ :m_rImporter(_rImporter)
+{
+ // build the attribute2property map
+ // string properties which are exported as attributes
+ m_aAttributeMetaData.addStringProperty(
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Name), PROPERTY_NAME);
+ m_aAttributeMetaData.addStringProperty(
+ OAttributeMetaData::getSpecialAttributeToken(SCAFlags::GroupName), PROPERTY_GROUP_NAME);
+ m_aAttributeMetaData.addStringProperty(
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Label), PROPERTY_LABEL);
+ m_aAttributeMetaData.addStringProperty(
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::TargetLocation), PROPERTY_TARGETURL);
+ m_aAttributeMetaData.addStringProperty(
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Title), PROPERTY_TITLE);
+ m_aAttributeMetaData.addStringProperty(
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::TargetFrame), PROPERTY_TARGETFRAME);
+ m_aAttributeMetaData.addStringProperty(
+ OAttributeMetaData::getDatabaseAttributeToken(DAFlags::DataField), PROPERTY_DATAFIELD);
+ m_aAttributeMetaData.addStringProperty(
+ OAttributeMetaData::getFormAttributeToken(faCommand), PROPERTY_COMMAND);
+ m_aAttributeMetaData.addStringProperty(
+ OAttributeMetaData::getFormAttributeToken(faDatasource), PROPERTY_DATASOURCENAME);
+ m_aAttributeMetaData.addStringProperty(
+ OAttributeMetaData::getFormAttributeToken(faFilter), PROPERTY_FILTER);
+ m_aAttributeMetaData.addStringProperty(
+ OAttributeMetaData::getFormAttributeToken(faOrder), PROPERTY_ORDER);
+
+ // properties not added because they're already present in another form
+ OSL_ENSURE(
+ OAttributeMetaData::getCommonControlAttributeName(CCAFlags::TargetLocation).equals(
+ OAttributeMetaData::getFormAttributeName(faAction)),
+ "OFormLayerXMLImport_Impl::OFormLayerXMLImport_Impl: invalid attribute names (1)!");
+ // if this fails, we would have to add a translation from faAction->PROPERTY_TARGETURL
+ // We did not because we already have one CCAFlags::TargetLocation->PROPERTY_TARGETURL,
+ // and CCAFlags::TargetLocation and faAction should be represented by the same attribute
+
+ OSL_ENSURE(
+ OAttributeMetaData::getCommonControlAttributeName(CCAFlags::Name).equals(
+ OAttributeMetaData::getFormAttributeName(faName)),
+ "OFormLayerXMLImport_Impl::OFormLayerXMLImport_Impl: invalid attribute names (2)!");
+ // the same for faName, CCAFlags::Name and PROPERTY_NAME
+
+ // boolean properties which are exported as attributes
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::CurrentSelected), PROPERTY_STATE, false);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Disabled), PROPERTY_ENABLED, false, true);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Dropdown), PROPERTY_DROPDOWN, false);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Printable), PROPERTY_PRINTABLE, true);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::ReadOnly), PROPERTY_READONLY, false);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Selected), PROPERTY_DEFAULT_STATE, false);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::TabStop), PROPERTY_TABSTOP, true);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getDatabaseAttributeToken(DAFlags::ConvertEmpty), PROPERTY_EMPTY_IS_NULL, false);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getSpecialAttributeToken(SCAFlags::Validation), PROPERTY_STRICTFORMAT, false);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getSpecialAttributeToken(SCAFlags::MultiLine), PROPERTY_MULTILINE, false);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getSpecialAttributeToken(SCAFlags::AutoCompletion), PROPERTY_AUTOCOMPLETE, false);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getSpecialAttributeToken(SCAFlags::Multiple), PROPERTY_MULTISELECTION, false);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getSpecialAttributeToken(SCAFlags::DefaultButton), PROPERTY_DEFAULTBUTTON, false);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getSpecialAttributeToken(SCAFlags::IsTristate), PROPERTY_TRISTATE, false);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getFormAttributeToken(faAllowDeletes), PROPERTY_ALLOWDELETES, true);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getFormAttributeToken(faAllowInserts), PROPERTY_ALLOWINSERTS, true);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getFormAttributeToken(faAllowUpdates), PROPERTY_ALLOWUPDATES, true);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getFormAttributeToken(faApplyFilter), PROPERTY_APPLYFILTER, false);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getFormAttributeToken(faEscapeProcessing), PROPERTY_ESCAPEPROCESSING, true);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getFormAttributeToken(faIgnoreResult), PROPERTY_IGNORERESULT, false);
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getSpecialAttributeToken( SCAFlags::Toggle ), PROPERTY_TOGGLE, false );
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getSpecialAttributeToken( SCAFlags::FocusOnClick ), PROPERTY_FOCUS_ON_CLICK, true );
+ m_aAttributeMetaData.addBooleanProperty(
+ OAttributeMetaData::getDatabaseAttributeToken( DAFlags::InputRequired ), PROPERTY_INPUT_REQUIRED, false );
+
+ // the int16 attributes
+ m_aAttributeMetaData.addInt16Property(
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::MaxLength), PROPERTY_MAXTEXTLENGTH);
+ m_aAttributeMetaData.addInt16Property(
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Size), PROPERTY_LINECOUNT);
+ m_aAttributeMetaData.addInt16Property(
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::TabIndex), PROPERTY_TABINDEX);
+ m_aAttributeMetaData.addInt16Property(
+ OAttributeMetaData::getDatabaseAttributeToken(DAFlags::BoundColumn), PROPERTY_BOUNDCOLUMN);
+
+ // the int32 attributes
+ m_aAttributeMetaData.addInt32Property(
+ OAttributeMetaData::getSpecialAttributeToken( SCAFlags::PageStepSize ), PROPERTY_BLOCK_INCREMENT );
+
+ // the enum attributes
+ m_aAttributeMetaData.addEnumProperty(
+ OAttributeMetaData::getCommonControlAttributeToken( CCAFlags::VisualEffect ), PROPERTY_VISUAL_EFFECT,
+ aVisualEffectMap,
+ &::cppu::UnoType<sal_Int16>::get() );
+ m_aAttributeMetaData.addEnumProperty(
+ OAttributeMetaData::getCommonControlAttributeToken( CCAFlags::Orientation ), PROPERTY_ORIENTATION,
+ aOrientationMap,
+ &::cppu::UnoType<sal_Int32>::get() );
+ m_aAttributeMetaData.addEnumProperty(
+ OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::ButtonType), PROPERTY_BUTTONTYPE,
+ aFormButtonTypeMap,
+ &::cppu::UnoType<FormButtonType>::get());
+ m_aAttributeMetaData.addEnumProperty(
+ OAttributeMetaData::getDatabaseAttributeToken(DAFlags::ListSource_TYPE), PROPERTY_LISTSOURCETYPE,
+ aListSourceTypeMap,
+ &::cppu::UnoType<ListSourceType>::get());
+ m_aAttributeMetaData.addEnumProperty(
+ OAttributeMetaData::getSpecialAttributeToken(SCAFlags::State), PROPERTY_DEFAULT_STATE,
+ aCheckStateMap,
+ &::cppu::UnoType<sal_Int16>::get());
+ m_aAttributeMetaData.addEnumProperty(
+ OAttributeMetaData::getSpecialAttributeToken(SCAFlags::CurrentState), PROPERTY_STATE,
+ aCheckStateMap,
+ &::cppu::UnoType<sal_Int16>::get());
+ m_aAttributeMetaData.addEnumProperty(
+ OAttributeMetaData::getFormAttributeToken(faEnctype), PROPERTY_SUBMIT_ENCODING,
+ aSubmitEncodingMap,
+ &::cppu::UnoType<FormSubmitEncoding>::get());
+ m_aAttributeMetaData.addEnumProperty(
+ OAttributeMetaData::getFormAttributeToken(faMethod), PROPERTY_SUBMIT_METHOD,
+ aSubmitMethodMap,
+ &::cppu::UnoType<FormSubmitMethod>::get());
+ m_aAttributeMetaData.addEnumProperty(
+ OAttributeMetaData::getFormAttributeToken(faCommandType), PROPERTY_COMMAND_TYPE,
+ aCommandTypeMap);
+ m_aAttributeMetaData.addEnumProperty(
+ OAttributeMetaData::getFormAttributeToken(faNavigationMode), PROPERTY_NAVIGATION,
+ aNavigationTypeMap,
+ &::cppu::UnoType<NavigationBarMode>::get());
+ m_aAttributeMetaData.addEnumProperty(
+ OAttributeMetaData::getFormAttributeToken(faTabbingCycle), PROPERTY_CYCLE,
+ aTabulatorCycleMap,
+ &::cppu::UnoType<TabulatorCycle>::get());
+
+ // 'initialize'
+ m_aCurrentPageIds = m_aControlIds.end();
+}
+
+OFormLayerXMLImport_Impl::~OFormLayerXMLImport_Impl()
+{}
+
+void OFormLayerXMLImport_Impl::setAutoStyleContext(SvXMLStylesContext* _pNewContext)
+{
+ OSL_ENSURE(!m_xAutoStyles.is(), "OFormLayerXMLImport_Impl::setAutoStyleContext: not to be called twice!");
+ m_xAutoStyles.set(_pNewContext);
+}
+
+void OFormLayerXMLImport_Impl::applyControlNumberStyle(const Reference< XPropertySet >& _rxControlModel, const OUString& _rControlNumberStyleName)
+{
+ OSL_ENSURE(_rxControlModel.is() && (!_rControlNumberStyleName.isEmpty()),
+ "OFormLayerXMLImport_Impl::applyControlNumberStyle: invalid arguments (this will crash)!");
+
+ OSL_ENSURE(m_xAutoStyles.is(), "OFormLayerXMLImport_Impl::applyControlNumberStyle: have no auto style context!");
+ if (!m_xAutoStyles.is())
+ {
+ m_xAutoStyles.set(m_rImporter.GetShapeImport()->GetAutoStylesContext());
+ }
+
+ if (!m_xAutoStyles.is())
+ return;
+
+ const SvXMLStyleContext* pStyle = m_xAutoStyles->FindStyleChildContext(XmlStyleFamily::DATA_STYLE, _rControlNumberStyleName);
+ if (pStyle)
+ {
+ const SvXMLNumFormatContext* pDataStyle = static_cast<const SvXMLNumFormatContext*>(pStyle);
+
+ // set this format at the control model
+ try
+ {
+ // the models number format supplier and formats
+ Reference< XNumberFormatsSupplier > xFormatsSupplier;
+ _rxControlModel->getPropertyValue(PROPERTY_FORMATSSUPPLIER) >>= xFormatsSupplier;
+ Reference< XNumberFormats > xFormats;
+ if (xFormatsSupplier.is())
+ xFormats = xFormatsSupplier->getNumberFormats();
+ OSL_ENSURE(xFormats.is(), "OFormLayerXMLImport_Impl::applyControlNumberStyle: could not obtain the controls number formats!");
+
+ // obtain a key
+ if (xFormats.is())
+ {
+ sal_Int32 nFormatKey = const_cast<SvXMLNumFormatContext*>(pDataStyle)->CreateAndInsert( xFormatsSupplier );
+ OSL_ENSURE(-1 != nFormatKey, "OFormLayerXMLImport_Impl::applyControlNumberStyle: could not obtain a format key!");
+
+ // set the format on the control model
+ _rxControlModel->setPropertyValue(PROPERTY_FORMATKEY, Any(nFormatKey));
+ }
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("OFormLayerXMLImport_Impl::applyControlNumberStyle: couldn't set the format!");
+ }
+ }
+ else
+ OSL_FAIL("OFormLayerXMLImport_Impl::applyControlNumberStyle: did not find the style with the given name!");
+}
+
+void OFormLayerXMLImport_Impl::registerCellValueBinding( const Reference< XPropertySet >& _rxControlModel, const OUString& _rCellAddress )
+{
+ OSL_ENSURE( _rxControlModel.is() && !_rCellAddress.isEmpty(),
+ "OFormLayerXMLImport_Impl::registerCellValueBinding: invalid arguments!" );
+ m_aCellValueBindings.emplace_back( _rxControlModel, _rCellAddress );
+}
+
+void OFormLayerXMLImport_Impl::registerXFormsValueBinding(
+ const Reference< XPropertySet >& _rxControlModel,
+ const OUString& _rBindingID )
+{
+ // TODO: is an empty binding name allowed?
+ OSL_ENSURE( _rxControlModel.is(), "need model" );
+
+ m_aXFormsValueBindings.emplace_back( _rxControlModel, _rBindingID );
+}
+
+void OFormLayerXMLImport_Impl::registerXFormsListBinding(
+ const Reference< XPropertySet >& _rxControlModel,
+ const OUString& _rBindingID )
+{
+ // TODO: is an empty binding name allowed?
+ OSL_ENSURE( _rxControlModel.is(), "need model" );
+
+ m_aXFormsListBindings.emplace_back( _rxControlModel, _rBindingID );
+}
+
+void OFormLayerXMLImport_Impl::registerXFormsSubmission(
+ const Reference< XPropertySet >& _rxControlModel,
+ const OUString& _rSubmissionID )
+{
+ // TODO: is an empty binding name allowed?
+ OSL_ENSURE( _rxControlModel.is(), "need model" );
+
+ m_aXFormsSubmissions.emplace_back( _rxControlModel, _rSubmissionID );
+}
+
+void OFormLayerXMLImport_Impl::registerCellRangeListSource( const Reference< XPropertySet >& _rxControlModel, const OUString& _rCellRangeAddress )
+{
+ OSL_ENSURE( _rxControlModel.is() && !_rCellRangeAddress.isEmpty(),
+ "OFormLayerXMLImport_Impl::registerCellRangeListSource: invalid arguments!" );
+ m_aCellRangeListSources.emplace_back( _rxControlModel, _rCellRangeAddress );
+}
+const SvXMLStyleContext* OFormLayerXMLImport_Impl::getStyleElement(const OUString& _rStyleName) const
+{
+ OSL_ENSURE( m_xAutoStyles.is(), "OFormLayerXMLImport_Impl::getStyleElement: have no auto style context!" );
+ // did you use setAutoStyleContext?
+
+ const SvXMLStyleContext* pControlStyle =
+ m_xAutoStyles.is() ? m_xAutoStyles->FindStyleChildContext( XmlStyleFamily::TEXT_PARAGRAPH, _rStyleName ) : nullptr;
+ OSL_ENSURE( pControlStyle || !m_xAutoStyles.is(),
+ OStringBuffer("OFormLayerXMLImport_Impl::getStyleElement: did not find the style named \"" +
+ OUStringToOString(_rStyleName, RTL_TEXTENCODING_ASCII_US) +
+ "\"!").getStr() );
+ return pControlStyle;
+}
+
+void OFormLayerXMLImport_Impl::enterEventContext()
+{
+ // install our own translation table. We need to disable the other tables because of name conflicts.
+ m_rImporter.GetEventImport().PushTranslationTable();
+ m_rImporter.GetEventImport().AddTranslationTable(g_pFormsEventTranslation);
+}
+
+void OFormLayerXMLImport_Impl::leaveEventContext()
+{
+ // install the original event tables.
+ m_rImporter.GetEventImport().PopTranslationTable();
+}
+
+void OFormLayerXMLImport_Impl::registerControlId(const Reference< XPropertySet >& _rxControl, const OUString& _rId)
+{
+ OSL_ENSURE(m_aCurrentPageIds != m_aControlIds.end(), "OFormLayerXMLImport_Impl::registerControlId: no current page!");
+ OSL_ENSURE(!_rId.isEmpty(), "OFormLayerXMLImport_Impl::registerControlId: invalid (empty) control id!");
+
+ OSL_ENSURE(m_aCurrentPageIds->second.end() == m_aCurrentPageIds->second.find(_rId), "OFormLayerXMLImport_Impl::registerControlId: control id already used!");
+ m_aCurrentPageIds->second[_rId] = _rxControl;
+}
+
+void OFormLayerXMLImport_Impl::registerControlReferences(const Reference< XPropertySet >& _rxControl, const OUString& _rReferringControls)
+{
+ OSL_ENSURE(!_rReferringControls.isEmpty(), "OFormLayerXMLImport_Impl::registerControlReferences: invalid (empty) control id list!");
+ OSL_ENSURE(_rxControl.is(), "OFormLayerXMLImport_Impl::registerControlReferences: invalid (NULL) control!");
+ m_aControlReferences.emplace_back( _rxControl, _rReferringControls );
+}
+
+void OFormLayerXMLImport_Impl::startPage(const Reference< XDrawPage >& _rxDrawPage)
+{
+ m_xCurrentPageFormsSupp.clear();
+
+ OSL_ENSURE(_rxDrawPage.is(), "OFormLayerXMLImport_Impl::startPage: NULL page!");
+ m_xCurrentPageFormsSupp.set(_rxDrawPage, css::uno::UNO_QUERY);
+ OSL_ENSURE( m_xCurrentPageFormsSupp.is(), "OFormLayerXMLImport_Impl::startPage: invalid draw page (no XFormsSupplier)!" );
+ if ( !m_xCurrentPageFormsSupp.is() )
+ return;
+
+ // add a new entry to our page map
+ ::std::pair< MapDrawPage2Map::iterator, bool > aPagePosition = m_aControlIds.emplace(_rxDrawPage, MapString2PropertySet());
+ OSL_ENSURE(aPagePosition.second, "OFormLayerXMLImport_Impl::startPage: already imported this page!");
+ m_aCurrentPageIds = aPagePosition.first;
+}
+
+void OFormLayerXMLImport_Impl::endPage()
+{
+ OSL_ENSURE( m_xCurrentPageFormsSupp.is(), "OFormLayerXMLImport_Impl::endPage: sure you called startPage before?" );
+
+ // do some knittings for the controls which are referring to each other
+ try
+ {
+ static const sal_Unicode s_nSeparator = ',';
+ OUString sCurrentReferring;
+ OUString sSeparator(&s_nSeparator, 1);
+ Reference< XPropertySet > xCurrentReferring;
+ sal_Int32 nSeparator, nPrevSep;
+ for ( const auto& rReferences : m_aControlReferences )
+ {
+ // the list of control ids is comma separated
+
+ // in a list of n ids there are only n-1 separators ... have to catch this last id
+ // -> normalize the list
+ OUString sReferring = rReferences.second + sSeparator;
+
+ nPrevSep = -1;
+ while (-1 != (nSeparator = sReferring.indexOf(s_nSeparator, nPrevSep + 1)))
+ {
+ sCurrentReferring = sReferring.copy(nPrevSep + 1, nSeparator - nPrevSep - 1);
+ xCurrentReferring = lookupControlId(sCurrentReferring);
+ if (xCurrentReferring.is())
+ // if this condition fails, this is an error, but lookupControlId should have asserted this ...
+ xCurrentReferring->setPropertyValue( PROPERTY_CONTROLLABEL, Any( rReferences.first ) );
+
+ nPrevSep = nSeparator;
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("xmloff.forms",
+ "unable to knit the control references (caught an exception)!");
+ }
+
+ // now that we have all children of the forms collection, attach the events
+ Reference< XIndexAccess > xIndexContainer;
+ if ( m_xCurrentPageFormsSupp.is() && m_xCurrentPageFormsSupp->hasForms() )
+ xIndexContainer.set(m_xCurrentPageFormsSupp->getForms(), css::uno::UNO_QUERY);
+ if ( xIndexContainer.is() )
+ ODefaultEventAttacherManager::setEvents( xIndexContainer );
+
+ // clear the structures for the control references.
+ m_aControlReferences.clear();
+
+ // and no we have no current page anymore
+ m_aCurrentPageIds = m_aControlIds.end();
+}
+
+Reference< XPropertySet > OFormLayerXMLImport_Impl::lookupControlId(const OUString& _rControlId)
+{
+ OSL_ENSURE(m_aCurrentPageIds != m_aControlIds.end(), "OFormLayerXMLImport_Impl::lookupControlId: no current page!");
+ Reference< XPropertySet > xReturn;
+ if (m_aCurrentPageIds != m_aControlIds.end())
+ {
+ MapString2PropertySet::const_iterator aPos = m_aCurrentPageIds->second.find(_rControlId);
+ if (m_aCurrentPageIds->second.end() != aPos)
+ xReturn = aPos->second;
+ else
+ SAL_WARN("xmloff", "unknown control id " << _rControlId);
+ }
+ return xReturn;
+}
+
+SvXMLImportContext* OFormLayerXMLImport_Impl::createOfficeFormsContext(
+ SvXMLImport& _rImport)
+{
+ return new OFormsRootImport( _rImport );
+}
+
+SvXMLImportContext* OFormLayerXMLImport_Impl::createContext(
+ sal_Int32 nElement,
+ const Reference< xml::sax::XFastAttributeList >&)
+{
+ SvXMLImportContext* pContext = nullptr;
+ if ( (nElement & TOKEN_MASK) == XML_FORM )
+ {
+ if ( m_xCurrentPageFormsSupp.is() )
+ pContext = new OFormImport(*this, *this, m_xCurrentPageFormsSupp->getForms() );
+ }
+ else if ( nElement == XML_ELEMENT(XFORMS, XML_MODEL) )
+ {
+ pContext = createXFormsModelContext( m_rImporter );
+ }
+ else
+ SAL_WARN("xmloff", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement));
+
+ return pContext;
+}
+
+void OFormLayerXMLImport_Impl::documentDone( )
+{
+ SvXMLImport& rImport = getGlobalContext();
+ if ( !( rImport.getImportFlags() & SvXMLImportFlags::CONTENT ) )
+ return;
+
+ // create (and bind) the spreadsheet cell bindings
+ if ( !m_aCellValueBindings.empty()
+ && FormCellBindingHelper::isCellBindingAllowed( rImport.GetModel() )
+ )
+ {
+ for ( const auto& rCellBindings : m_aCellValueBindings )
+ {
+ try
+ {
+ FormCellBindingHelper aHelper( rCellBindings.first, rImport.GetModel() );
+ OSL_ENSURE( aHelper.isCellBindingAllowed(), "OFormLayerXMLImport_Impl::documentDone: can't bind this control model!" );
+ if ( aHelper.isCellBindingAllowed() )
+ {
+ // There are special bindings for listboxes. See
+ // OListAndComboImport::doRegisterCellValueBinding for a comment on this HACK.
+ OUString sBoundCellAddress( rCellBindings.second );
+ sal_Int32 nIndicator = sBoundCellAddress.lastIndexOf( ":index" );
+
+ bool bUseIndexBinding = false;
+ if ( nIndicator != -1 )
+ {
+ sBoundCellAddress = sBoundCellAddress.copy( 0, nIndicator );
+ bUseIndexBinding = true;
+ }
+
+ aHelper.setBinding( aHelper.createCellBindingFromStringAddress( sBoundCellAddress, bUseIndexBinding ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("xmloff.forms",
+ "caught an exception while binding to a cell!");
+ }
+ }
+ m_aCellValueBindings.clear();
+ }
+
+ // the same for the spreadsheet cell range list sources
+ if ( !m_aCellRangeListSources.empty()
+ && FormCellBindingHelper::isListCellRangeAllowed( rImport.GetModel() )
+ )
+ {
+ for ( const auto& rRangeBindings : m_aCellRangeListSources )
+ {
+ try
+ {
+ FormCellBindingHelper aHelper( rRangeBindings.first, rImport.GetModel() );
+ OSL_ENSURE( aHelper.isListCellRangeAllowed(), "OFormLayerXMLImport_Impl::documentDone: can't bind this control model!" );
+ if ( aHelper.isListCellRangeAllowed() )
+ {
+ aHelper.setListSource( aHelper.createCellListSourceFromStringAddress( rRangeBindings.second ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("xmloff.forms",
+ "caught an exception while binding to a cell range!");
+ }
+ }
+ m_aCellRangeListSources.clear();
+ }
+
+ // process XForms-bindings; call registerXFormsValueBinding for each
+ for (const auto& aXFormsValueBinding : m_aXFormsValueBindings)
+ bindXFormsValueBinding(rImport.GetModel(), aXFormsValueBinding);
+ // same for list bindings
+ for (const auto& aXFormsListBindings : m_aXFormsListBindings)
+ bindXFormsListBinding(rImport.GetModel(), aXFormsListBindings);
+ // same for submissions
+ for (const auto& aXFormsSubmission : m_aXFormsSubmissions)
+ bindXFormsSubmission(rImport.GetModel(), aXFormsSubmission);
+}
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/layerimport.hxx b/xmloff/source/forms/layerimport.hxx
new file mode 100644
index 000000000..21e3a79c7
--- /dev/null
+++ b/xmloff/source/forms/layerimport.hxx
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+#include <unordered_map>
+
+#include <com/sun/star/xml/sax/XAttributeList.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/form/XFormsSupplier2.hpp>
+#include <rtl/ref.hxx>
+#include "formattributes.hxx"
+#include "eventimport.hxx"
+
+class SvXMLImport;
+class SvXMLImportContext;
+class SvXMLStyleContext;
+class SvXMLStylesContext;
+
+ // unfortunately, we can't put this into our namespace, as the macro expands to (amongst others) a forward
+ // declaration of the class name, which then would be in the namespace, too
+
+namespace xmloff
+{
+
+ class OAttribute2Property;
+
+ //= OFormLayerXMLImport_Impl
+ class OFormLayerXMLImport_Impl
+ : public ODefaultEventAttacherManager
+ {
+ friend class OFormLayerXMLImport;
+
+ SvXMLImport& m_rImporter;
+ OAttribute2Property m_aAttributeMetaData;
+
+ /// the supplier for the forms of the currently imported page
+ css::uno::Reference< css::form::XFormsSupplier2 >
+ m_xCurrentPageFormsSupp;
+ rtl::Reference<SvXMLStylesContext> m_xAutoStyles;
+
+ typedef std::map< OUString, css::uno::Reference< css::beans::XPropertySet > > MapString2PropertySet;
+ typedef std::unordered_map<css::uno::Reference<css::drawing::XDrawPage>, MapString2PropertySet> MapDrawPage2Map;
+
+ MapDrawPage2Map m_aControlIds; // ids of the controls on all known page
+ MapDrawPage2Map::iterator m_aCurrentPageIds; // ifs of the controls on the current page
+
+ typedef ::std::pair< css::uno::Reference< css::beans::XPropertySet >, OUString >
+ ModelStringPair;
+ ::std::vector< ModelStringPair >
+ m_aControlReferences; // control reference descriptions for current page
+ ::std::vector< ModelStringPair >
+ m_aCellValueBindings; // information about controls bound to spreadsheet cells
+ ::std::vector< ModelStringPair >
+ m_aCellRangeListSources;// information about controls bound to spreadsheet cell range list sources
+
+ ::std::vector< ModelStringPair >
+ m_aXFormsValueBindings; // collect xforms:bind attributes to be resolved
+
+ ::std::vector< ModelStringPair >
+ m_aXFormsListBindings; // collect forms:xforms-list-source attributes to be resolved
+
+ ::std::vector< ModelStringPair >
+ m_aXFormsSubmissions; // collect xforms:submission attributes to be resolved
+
+ public:
+ // IControlIdMap
+ void registerControlId(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControl,
+ const OUString& _rId);
+ void registerControlReferences(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControl,
+ const OUString& _rReferringControls);
+
+ // OFormLayerXMLImport_Impl
+ OAttribute2Property& getAttributeMap() { return m_aAttributeMetaData; }
+ SvXMLImport& getGlobalContext() { return m_rImporter; }
+ const SvXMLStyleContext* getStyleElement(const OUString& _rStyleName) const;
+ void enterEventContext();
+ void leaveEventContext();
+ void applyControlNumberStyle(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel,
+ const OUString& _rControlNumberStyleName
+ );
+ void registerCellValueBinding(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel,
+ const OUString& _rCellAddress
+ );
+
+ void registerCellRangeListSource(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel,
+ const OUString& _rCellRangeAddress
+ );
+
+ void registerXFormsValueBinding(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel,
+ const OUString& _rBindingID
+ );
+
+ void registerXFormsListBinding(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel,
+ const OUString& _rBindingID
+ );
+
+ void registerXFormsSubmission(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel,
+ const OUString& _rSubmissionID
+ );
+
+ ~OFormLayerXMLImport_Impl() override;
+
+ private:
+ explicit OFormLayerXMLImport_Impl(SvXMLImport& _rImporter);
+
+ /** start importing the forms of the given page
+ */
+ void startPage(
+ const css::uno::Reference< css::drawing::XDrawPage >& _rxDrawPage);
+
+ /** end importing the forms of the current page
+ */
+ void endPage();
+
+ /** creates an import context for the office:forms element
+ */
+ static SvXMLImportContext* createOfficeFormsContext(
+ SvXMLImport& _rImport);
+
+ /** create an <type>SvXMLImportContext</type> instance which is able to import the &lt;form:form&gt;
+ element.
+ */
+ SvXMLImportContext* createContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttribs);
+
+ /** get the control with the given id
+ */
+ css::uno::Reference< css::beans::XPropertySet >
+ lookupControlId(const OUString& _rControlId);
+
+ /** announces the auto-style context to the form importer
+ */
+ void setAutoStyleContext(SvXMLStylesContext* _pNewContext);
+
+ /** to be called when the document has been completely imported
+
+ <p>For some documents (currently: only some spreadsheet documents) it's necessary
+ do to a post processing, since not all information from the file can be processed
+ if the document is not completed, yet.</p>
+ */
+ void documentDone( );
+ };
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/logging.cxx b/xmloff/source/forms/logging.cxx
new file mode 100644
index 000000000..6c2bb5922
--- /dev/null
+++ b/xmloff/source/forms/logging.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 "logging.hxx"
+
+namespace xmloff
+{
+
+#ifdef TIMELOG
+ //= OStackedLogging
+ void OStackedLogging::enterContext( const char* _pContextName )
+ {
+ m_aLogger.push( new ::rtl::Logfile( _pContextName ) );
+ }
+
+ void OStackedLogging::leaveTopContext( )
+ {
+ delete m_aLogger.top();
+ m_aLogger.pop();
+ }
+#endif
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/logging.hxx b/xmloff/source/forms/logging.hxx
new file mode 100644
index 000000000..501b6c14e
--- /dev/null
+++ b/xmloff/source/forms/logging.hxx
@@ -0,0 +1,59 @@
+/* -*- 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 <stack>
+
+namespace rtl { class Logfile; }
+
+namespace xmloff
+{
+
+#ifdef TIMELOG
+
+ //= OStackedLogging
+ class OStackedLogging
+ {
+ private:
+ ::std::stack< ::rtl::Logfile* > m_aLogger;
+
+ protected:
+ OStackedLogging() { }
+
+ protected:
+ void enterContext( const char* _pContextName );
+ void leaveTopContext( );
+ };
+
+#define ENTER_LOG_CONTEXT( name ) enterContext( name )
+#define LEAVE_LOG_CONTEXT( ) leaveTopContext( )
+
+#else
+ struct OStackedLogging { };
+
+#define ENTER_LOG_CONTEXT( name )
+#define LEAVE_LOG_CONTEXT( )
+
+#endif
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/officeforms.cxx b/xmloff/source/forms/officeforms.cxx
new file mode 100644
index 000000000..07f2682d2
--- /dev/null
+++ b/xmloff/source/forms/officeforms.cxx
@@ -0,0 +1,177 @@
+/* -*- 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 "officeforms.hxx"
+
+#include <sax/tools/converter.hxx>
+
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmlexp.hxx>
+#include <xmloff/xmlimp.hxx>
+#include <xmloff/namespacemap.hxx>
+#include <com/sun/star/frame/XModel.hpp>
+#include <comphelper/extract.hxx>
+#include <tools/diagnose_ex.h>
+#include "strings.hxx"
+
+namespace xmloff
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::xml;
+ using ::xmloff::token::XML_FORMS;
+ using ::com::sun::star::xml::sax::XAttributeList;
+ using ::com::sun::star::xml::sax::XFastAttributeList;
+
+ //= OFormsRootImport
+ OFormsRootImport::OFormsRootImport( SvXMLImport& rImport )
+ :SvXMLImportContext(rImport)
+ {
+ }
+
+ OFormsRootImport::~OFormsRootImport()
+ {
+ }
+
+ css::uno::Reference< css::xml::sax::XFastContextHandler > OFormsRootImport::createFastChildContext(
+ sal_Int32 _nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList )
+ {
+ SvXMLImportContext* pRet = nullptr;
+ try
+ {
+ pRet = GetImport().GetFormImport()->createContext( _nElement, xAttrList );
+ } catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("xmloff.forms");
+ }
+ return pRet;
+ }
+
+ void OFormsRootImport::implImportBool(const Reference< XFastAttributeList >& _rxAttributes, OfficeFormsAttributes _eAttribute,
+ const Reference< XPropertySet >& _rxProps, const Reference< XPropertySetInfo >& _rxPropInfo,
+ const OUString& _rPropName, bool _bDefault)
+ {
+ // the complete attribute name to look for
+ sal_Int32 nCompleteAttributeName = XML_ELEMENT(
+ FORM,
+ OAttributeMetaData::getOfficeFormsAttributeToken(_eAttribute));
+
+ // get and convert the value
+ OUString sAttributeValue = _rxAttributes->getOptionalValue(nCompleteAttributeName);
+ bool bValue = _bDefault;
+ (void)::sax::Converter::convertBool(bValue, sAttributeValue);
+
+ // set the property
+ if (_rxPropInfo->hasPropertyByName(_rPropName))
+ {
+ _rxProps->setPropertyValue(_rPropName, Any(bValue));
+ }
+ }
+
+ void OFormsRootImport::startFastElement( sal_Int32 /*nElement*/, const Reference< XFastAttributeList >& _rxAttrList )
+ {
+ ENTER_LOG_CONTEXT( "xmloff::OFormsRootImport - importing the complete tree" );
+
+ try
+ {
+ Reference< XPropertySet > xDocProperties(GetImport().GetModel(), UNO_QUERY);
+ if ( xDocProperties.is() )
+ { // an empty model is allowed: when doing a copy'n'paste from e.g. Writer to Calc,
+ // this is done via streaming the controls as XML.
+ Reference< XPropertySetInfo > xDocPropInfo;
+ if (xDocProperties.is())
+ xDocPropInfo = xDocProperties->getPropertySetInfo();
+
+ implImportBool(_rxAttrList, ofaAutomaticFocus, xDocProperties, xDocPropInfo, PROPERTY_AUTOCONTROLFOCUS, false);
+ implImportBool(_rxAttrList, ofaApplyDesignMode, xDocProperties, xDocPropInfo, PROPERTY_APPLYDESIGNMODE, true);
+ }
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("xmloff.forms",
+ "caught an exception while setting the document properties!");
+ }
+ }
+
+ void OFormsRootImport::endFastElement(sal_Int32 )
+ {
+ LEAVE_LOG_CONTEXT( );
+ }
+
+ //= OFormsRootExport
+ OFormsRootExport::OFormsRootExport( SvXMLExport& _rExp )
+ {
+ addModelAttributes(_rExp);
+
+ m_pImplElement.reset( new SvXMLElementExport(_rExp, XML_NAMESPACE_OFFICE, XML_FORMS, true, true) );
+ }
+
+ OFormsRootExport::~OFormsRootExport( )
+ {
+ }
+
+ void OFormsRootExport::implExportBool(SvXMLExport& _rExp, OfficeFormsAttributes _eAttribute,
+ const Reference< XPropertySet >& _rxProps, const Reference< XPropertySetInfo >& _rxPropInfo,
+ const OUString& _rPropName, bool _bDefault)
+ {
+ // retrieve the property value
+ bool bValue = _bDefault;
+ if (_rxPropInfo->hasPropertyByName(_rPropName))
+ bValue = ::cppu::any2bool(_rxProps->getPropertyValue(_rPropName));
+
+ // convert into a string
+ OUStringBuffer aValue;
+ ::sax::Converter::convertBool(aValue, bValue);
+
+ // add the attribute
+ _rExp.AddAttribute(
+ OAttributeMetaData::getOfficeFormsAttributeNamespace(),
+ OAttributeMetaData::getOfficeFormsAttributeName(_eAttribute),
+ aValue.makeStringAndClear());
+ }
+
+ void OFormsRootExport::addModelAttributes(SvXMLExport& _rExp)
+ {
+ try
+ {
+ Reference< XPropertySet > xDocProperties(_rExp.GetModel(), UNO_QUERY);
+ if ( xDocProperties.is() )
+ { // an empty model is allowed: when doing a copy'n'paste from e.g. Writer to Calc,
+ // this is done via streaming the controls as XML.
+ Reference< XPropertySetInfo > xDocPropInfo;
+ if (xDocProperties.is())
+ xDocPropInfo = xDocProperties->getPropertySetInfo();
+
+ implExportBool(_rExp, ofaAutomaticFocus, xDocProperties, xDocPropInfo, PROPERTY_AUTOCONTROLFOCUS, false);
+ implExportBool(_rExp, ofaApplyDesignMode, xDocProperties, xDocPropInfo, PROPERTY_APPLYDESIGNMODE, true);
+ }
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("xmloff.forms",
+ "caught an exception while retrieving the document properties!");
+ }
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/officeforms.hxx b/xmloff/source/forms/officeforms.hxx
new file mode 100644
index 000000000..56694835c
--- /dev/null
+++ b/xmloff/source/forms/officeforms.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 <com/sun/star/beans/XPropertySet.hpp>
+
+#include "formattributes.hxx"
+#include <xmloff/xmlictxt.hxx>
+#include <memory>
+#include "logging.hxx"
+
+class SvXMLElementExport;
+class SvXMLExport;
+
+namespace xmloff
+{
+
+ //= OFormsRootImport
+ class OFormsRootImport
+ :public SvXMLImportContext
+ ,public OStackedLogging
+ {
+ public:
+
+ OFormsRootImport( SvXMLImport& _rImport);
+ virtual ~OFormsRootImport() override;
+
+ // SvXMLImportContext overridable
+ virtual void SAL_CALL startFastElement(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList) override;
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+
+ private:
+ static void implImportBool(
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttributes,
+ OfficeFormsAttributes _eAttribute,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxProps,
+ const css::uno::Reference< css::beans::XPropertySetInfo >& _rxPropInfo,
+ const OUString& _rPropName,
+ bool _bDefault
+ );
+ };
+
+ //= OFormsRootExport
+ class OFormsRootExport
+ {
+ private:
+ std::unique_ptr<SvXMLElementExport> m_pImplElement;
+
+ public:
+ explicit OFormsRootExport( SvXMLExport& _rExp );
+ ~OFormsRootExport();
+
+ private:
+ static void addModelAttributes(SvXMLExport& _rExp);
+
+ static void implExportBool(
+ SvXMLExport& _rExp,
+ OfficeFormsAttributes _eAttribute,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxProps,
+ const css::uno::Reference< css::beans::XPropertySetInfo >& _rxPropInfo,
+ const OUString& _rPropName,
+ bool _bDefault
+ );
+
+ OFormsRootExport(const OFormsRootExport&) = delete;
+ OFormsRootExport& operator=(const OFormsRootExport&) = delete;
+ };
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/property_description.hxx b/xmloff/source/forms/property_description.hxx
new file mode 100644
index 000000000..d30afcd29
--- /dev/null
+++ b/xmloff/source/forms/property_description.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 <forms/property_handler.hxx>
+#include <xmloff/xmltoken.hxx>
+
+#include <vector>
+
+namespace xmloff
+{
+
+ //= PropertyDescription
+ struct AttributeDescription
+ {
+ sal_uInt16 namespacePrefix; // usually XML_NAMESPACE_FORM
+ ::xmloff::token::XMLTokenEnum attributeToken;
+
+ AttributeDescription()
+ :namespacePrefix( 0 )
+ ,attributeToken( ::xmloff::token::XML_TOKEN_INVALID )
+ {
+ }
+
+ AttributeDescription(
+ const sal_uInt16 i_namespacePrefix,
+ const ::xmloff::token::XMLTokenEnum i_attributeToken
+ )
+ :namespacePrefix( i_namespacePrefix )
+ ,attributeToken( i_attributeToken )
+ {
+ }
+ };
+
+ inline bool operator==( const AttributeDescription& i_lhs, const AttributeDescription& i_rhs )
+ {
+ return ( i_lhs.namespacePrefix == i_rhs.namespacePrefix )
+ && ( i_lhs.attributeToken == i_rhs.attributeToken );
+ }
+
+ //= PropertyDescription
+ struct PropertyDescription
+ {
+ /// is the name of the property
+ const OUString propertyName;
+ /** denotes the attribute which represents the property. Note that multiple properties might comprise a single
+ attribute value.
+ */
+ /// is the factory for creating a handler for reading and writing the property
+ const PropertyHandlerFactory factory;
+ /// the unique ID of the property. The property meta data table must not contain two entries with the same property ID
+ const PropertyId propertyId;
+ const AttributeDescription attribute;
+
+ PropertyDescription()
+ :propertyName()
+ ,factory( nullptr )
+ ,propertyId( PID_INVALID )
+ ,attribute()
+ {
+ }
+
+ PropertyDescription(
+ const OUString& i_propertyName,
+ const sal_uInt16 i_namespacePrefix,
+ const ::xmloff::token::XMLTokenEnum i_attributeToken,
+ const PropertyHandlerFactory i_factory,
+ const PropertyId i_propertyId
+ )
+ :propertyName( i_propertyName )
+ ,factory( i_factory )
+ ,propertyId( i_propertyId )
+ ,attribute( i_namespacePrefix, i_attributeToken )
+ {
+ }
+ };
+
+ //= PropertyDescriptionList
+ typedef ::std::vector< const PropertyDescription* > PropertyDescriptionList;
+
+ //= PropertyGroups
+ typedef ::std::vector< PropertyDescriptionList > PropertyGroups;
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/property_meta_data.cxx b/xmloff/source/forms/property_meta_data.cxx
new file mode 100644
index 000000000..ce5760856
--- /dev/null
+++ b/xmloff/source/forms/property_meta_data.cxx
@@ -0,0 +1,156 @@
+/* -*- 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 "property_description.hxx"
+#include "property_meta_data.hxx"
+#include <forms/form_handler_factory.hxx>
+#include "strings.hxx"
+#include <xmloff/xmlimp.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmlnamespace.hxx>
+
+#include <o3tl/hash_combine.hxx>
+#include <tools/debug.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+
+#include <unordered_map>
+
+namespace xmloff::metadata
+{
+
+ using namespace ::xmloff::token;
+
+#define FORM_SINGLE_PROPERTY( id, att ) \
+ PropertyDescription( PROPERTY_##id, XML_NAMESPACE_FORM, att, &FormHandlerFactory::getFormPropertyHandler, PID_##id )
+
+ //= property meta data
+ namespace
+ {
+ const PropertyDescription* lcl_getPropertyMetaData()
+ {
+ static const PropertyDescription s_propertyMetaData[] =
+ {
+ FORM_SINGLE_PROPERTY( DATE_MIN, XML_MIN_VALUE ),
+ FORM_SINGLE_PROPERTY( DATE_MAX, XML_MAX_VALUE ),
+ FORM_SINGLE_PROPERTY( DEFAULT_DATE, XML_VALUE ),
+ FORM_SINGLE_PROPERTY( DATE, XML_CURRENT_VALUE ),
+ FORM_SINGLE_PROPERTY( TIME_MIN, XML_MIN_VALUE ),
+ FORM_SINGLE_PROPERTY( TIME_MAX, XML_MAX_VALUE ),
+ FORM_SINGLE_PROPERTY( DEFAULT_TIME, XML_VALUE ),
+ FORM_SINGLE_PROPERTY( TIME, XML_CURRENT_VALUE ),
+
+ PropertyDescription()
+ };
+ return s_propertyMetaData;
+ }
+ }
+
+ namespace
+ {
+ // TODO: instead of having all of the below static, it should be some per-instance data. This way, the
+ // approach used here would scale much better.
+ // That is, if you have multiple "meta data instances", which manage a small, but closed set of properties,
+ // then looking through those multiple instances would probably be faster than searching within
+ // one big instance, since in this case, every instance can quickly decide whether it is responsible
+ // for some attribute or property, and otherwise delegate to the next instance.
+
+ typedef std::unordered_map< OUString, const PropertyDescription* > DescriptionsByName;
+
+ const DescriptionsByName& lcl_getPropertyDescriptions()
+ {
+ DBG_TESTSOLARMUTEX();
+ static DescriptionsByName s_propertyDescriptionsByName;
+ if ( s_propertyDescriptionsByName.empty() )
+ {
+ const PropertyDescription* desc = lcl_getPropertyMetaData();
+ while ( !desc->propertyName.isEmpty() )
+ {
+ s_propertyDescriptionsByName[ desc->propertyName ] = desc;
+ ++desc;
+ }
+ }
+ return s_propertyDescriptionsByName;
+ }
+
+ typedef std::unordered_map< OUString, XMLTokenEnum > ReverseTokenLookup;
+
+ struct AttributeHash
+ {
+ size_t operator()( const AttributeDescription& i_attribute ) const
+ {
+ std::size_t seed = 0;
+ o3tl::hash_combine(seed, i_attribute.attributeToken);
+ o3tl::hash_combine(seed, i_attribute.namespacePrefix);
+ return seed;
+ }
+ };
+
+ typedef std::unordered_map< AttributeDescription, PropertyGroups, AttributeHash > AttributesWithoutGroup;
+
+ const AttributesWithoutGroup& lcl_getAttributesWithoutGroups()
+ {
+ DBG_TESTSOLARMUTEX();
+ static AttributesWithoutGroup s_attributesWithoutGroup;
+ if ( s_attributesWithoutGroup.empty() )
+ {
+ const PropertyDescription* desc = lcl_getPropertyMetaData();
+ while ( !desc->propertyName.isEmpty() )
+ {
+ PropertyDescriptionList singleElementList;
+ singleElementList.push_back( desc );
+
+ s_attributesWithoutGroup[ desc->attribute ].push_back( singleElementList );
+ ++desc;
+ }
+ }
+ return s_attributesWithoutGroup;
+ }
+ }
+
+ const PropertyDescription* getPropertyDescription( const OUString& i_propertyName )
+ {
+ const DescriptionsByName& rAllDescriptions( lcl_getPropertyDescriptions() );
+ DescriptionsByName::const_iterator pos = rAllDescriptions.find( i_propertyName );
+ if ( pos != rAllDescriptions.end() )
+ return pos->second;
+ return nullptr;
+ }
+
+ void getPropertyGroupList( const AttributeDescription& i_attribute, PropertyGroups& o_propertyGroups )
+ {
+ // the attribute is not used for any non-trivial group, which means it is mapped directly to
+ // a single property
+ const AttributesWithoutGroup& attributesWithoutGroups( lcl_getAttributesWithoutGroups() );
+ const AttributesWithoutGroup::const_iterator pos = attributesWithoutGroups.find( i_attribute );
+ if ( pos != attributesWithoutGroups.end() )
+ o_propertyGroups = pos->second;
+ }
+
+ AttributeDescription getAttributeDescription( sal_Int32 nAttributeToken )
+ {
+ AttributeDescription attribute;
+ attribute.namespacePrefix = (nAttributeToken >> NMSP_SHIFT) - 1;
+ attribute.attributeToken = static_cast<XMLTokenEnum>(nAttributeToken & TOKEN_MASK);
+ return attribute;
+ }
+
+} // namespace xmloff::metadata
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/property_meta_data.hxx b/xmloff/source/forms/property_meta_data.hxx
new file mode 100644
index 000000000..0d012fbc2
--- /dev/null
+++ b/xmloff/source/forms/property_meta_data.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include "property_description.hxx"
+
+namespace xmloff::metadata
+{
+
+ const PropertyDescription* getPropertyDescription( const OUString& i_propertyName );
+
+ /** retrieves all known property groups which are mapped to the given attribute
+ */
+ void getPropertyGroupList(
+ const AttributeDescription& i_attribute,
+ PropertyGroups& o_propertyGroups
+ );
+
+ /** retrieves the attribute descriptor for the attribute given by namespace prefix and attribute name
+ */
+ AttributeDescription getAttributeDescription( sal_Int32 nElement );
+
+} // namespace xmloff::metadata
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/propertyexport.cxx b/xmloff/source/forms/propertyexport.cxx
new file mode 100644
index 000000000..79637d743
--- /dev/null
+++ b/xmloff/source/forms/propertyexport.cxx
@@ -0,0 +1,683 @@
+/* -*- 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 "propertyexport.hxx"
+
+#include <memory>
+
+#include <xmloff/xmlexp.hxx>
+#include "strings.hxx"
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmluconv.hxx>
+#include <xmloff/xmlexppr.hxx>
+#include <xmloff/xmlprmap.hxx>
+#include <sax/tools/converter.hxx>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <comphelper/extract.hxx>
+#include <comphelper/types.hxx>
+#include "callbacks.hxx"
+#include <unotools/datetime.hxx>
+#include <tools/date.hxx>
+#include <tools/datetime.hxx>
+
+namespace xmloff
+{
+
+ using namespace css;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+
+ // NO using namespace ...util !!!
+ // need a tools Date/Time/DateTime below, which would conflict with the uno types then
+
+ using namespace ::comphelper;
+
+ //= OPropertyExport
+ OPropertyExport::OPropertyExport(IFormsExportContext& _rContext, const Reference< XPropertySet >& _rxProps)
+ :m_rContext(_rContext)
+ ,m_xProps(_rxProps)
+ ,m_xPropertyInfo( m_xProps->getPropertySetInfo() )
+ ,m_xPropertyState( _rxProps, UNO_QUERY )
+ {
+ // caching
+ OUStringBuffer aBuffer;
+ ::sax::Converter::convertBool(aBuffer, true);
+ m_sValueTrue = aBuffer.makeStringAndClear();
+ ::sax::Converter::convertBool(aBuffer, false);
+ m_sValueFalse = aBuffer.makeStringAndClear();
+
+ OSL_ENSURE(m_xPropertyInfo.is(), "OPropertyExport::OPropertyExport: need an XPropertySetInfo!");
+
+ // collect the properties which need to be exported
+ examinePersistence();
+ }
+
+ bool OPropertyExport::shouldExportProperty( const OUString& i_propertyName ) const
+ {
+ // if the property state is DEFAULT, it does not need to be written - at least
+ // if it's a built-in property, and not a dynamically-added one.
+ bool bIsDefaultValue = m_xPropertyState.is()
+ && ( PropertyState_DEFAULT_VALUE == m_xPropertyState->getPropertyState( i_propertyName ) );
+ bool bIsDynamicProperty = m_xPropertyInfo.is()
+ && ( ( m_xPropertyInfo->getPropertyByName( i_propertyName ).Attributes & PropertyAttribute::REMOVABLE ) != 0 );
+ return ( !bIsDefaultValue || bIsDynamicProperty );
+ }
+
+ template< typename T > void
+ OPropertyExport::exportRemainingPropertiesSequence(
+ Any const & value, token::XMLTokenEnum eValueAttName)
+ {
+ css::uno::Sequence<T> anySeq;
+ bool bSuccess = value >>= anySeq;
+ assert(bSuccess); (void)bSuccess;
+ for (T const & i : std::as_const(anySeq))
+ {
+ OUString sValue(implConvertAny(Any(i)));
+ AddAttribute(XML_NAMESPACE_OFFICE, eValueAttName, sValue );
+ SvXMLElementExport aValueTag(
+ m_rContext.getGlobalContext(), XML_NAMESPACE_FORM,
+ token::XML_LIST_VALUE, true, false);
+ }
+ }
+
+ void OPropertyExport::exportRemainingProperties()
+ {
+ // the properties tag (will be created if we have at least one no-default property)
+ std::unique_ptr<SvXMLElementExport> pPropertiesTag;
+
+ Any aValue;
+ OUString sValue;
+
+ // loop through all the properties which are yet to be exported
+ for ( const auto& rProperty : m_aRemainingProps )
+ {
+ DBG_CHECK_PROPERTY_NO_TYPE(rProperty);
+
+ if ( !shouldExportProperty( rProperty ) )
+ continue;
+
+ // now that we have the first sub-tag we need the form:properties element
+ if (!pPropertiesTag)
+ pPropertiesTag = std::make_unique<SvXMLElementExport>(m_rContext.getGlobalContext(), XML_NAMESPACE_FORM, token::XML_PROPERTIES, true, true);
+
+ // add the name attribute
+ AddAttribute(XML_NAMESPACE_FORM, token::XML_PROPERTY_NAME, rProperty);
+
+ // get the value
+ aValue = m_xProps->getPropertyValue(rProperty);
+
+ // the type to export
+ Type aExportType;
+
+ // is it a sequence
+ bool bIsSequence = TypeClass_SEQUENCE == aValue.getValueTypeClass();
+ // the type of the property, maybe reduced to the element type of a sequence
+ if (bIsSequence)
+ aExportType = getSequenceElementType( aValue.getValueType() );
+ else
+ aExportType = aValue.getValueType();
+
+ // the type attribute
+
+ bool bIsEmptyValue = TypeClass_VOID == aValue.getValueType().getTypeClass();
+ if ( bIsEmptyValue )
+ {
+ css::beans::Property aPropDesc = m_xPropertyInfo->getPropertyByName( rProperty );
+ aExportType = aPropDesc.Type;
+ }
+ token::XMLTokenEnum eValueType = implGetPropertyXMLType( aExportType );
+
+ if ( bIsEmptyValue )
+ AddAttribute( XML_NAMESPACE_OFFICE, token::XML_VALUE_TYPE, token::XML_VOID );
+ else
+ AddAttribute( XML_NAMESPACE_OFFICE, token::XML_VALUE_TYPE, eValueType );
+
+ token::XMLTokenEnum eValueAttName( token::XML_VALUE );
+ switch ( eValueType )
+ {
+ case token::XML_BOOLEAN: eValueAttName = token::XML_BOOLEAN_VALUE; break;
+ case token::XML_STRING: eValueAttName = token::XML_STRING_VALUE; break;
+ default: break;
+ }
+
+ if( !bIsSequence && !bIsEmptyValue )
+ { // the simple case
+
+ sValue = implConvertAny(aValue);
+ AddAttribute(XML_NAMESPACE_OFFICE, eValueAttName, sValue );
+ }
+
+ // start the property tag
+ SvXMLElementExport aValueTag1(m_rContext.getGlobalContext(),
+ XML_NAMESPACE_FORM,
+ bIsSequence ? token::XML_LIST_PROPERTY
+ : token::XML_PROPERTY, true, true);
+
+ if (!bIsSequence)
+ continue;
+
+ // the not-that-simple case, we need to iterate through the sequence elements
+ switch ( aExportType.getTypeClass() )
+ {
+ case TypeClass_STRING:
+ exportRemainingPropertiesSequence< OUString >(
+ aValue, eValueAttName);
+ break;
+ case TypeClass_DOUBLE:
+ exportRemainingPropertiesSequence< double >(
+ aValue, eValueAttName);
+ break;
+ case TypeClass_BOOLEAN:
+ exportRemainingPropertiesSequence< sal_Bool >(
+ aValue, eValueAttName);
+ break;
+ case TypeClass_BYTE:
+ exportRemainingPropertiesSequence< sal_Int8 >(
+ aValue, eValueAttName);
+ break;
+ case TypeClass_SHORT:
+ exportRemainingPropertiesSequence< sal_Int16 >(
+ aValue, eValueAttName);
+ break;
+ case TypeClass_LONG:
+ exportRemainingPropertiesSequence< sal_Int32 >(
+ aValue, eValueAttName);
+ break;
+ case TypeClass_HYPER:
+ exportRemainingPropertiesSequence< sal_Int64 >(
+ aValue, eValueAttName);
+ break;
+ default:
+ OSL_FAIL("OPropertyExport::exportRemainingProperties: unsupported sequence type !");
+ break;
+ }
+ }
+ }
+
+ void OPropertyExport::examinePersistence()
+ {
+ m_aRemainingProps.clear();
+ const Sequence< Property > aProperties = m_xPropertyInfo->getProperties();
+ for (const auto& rProp : aProperties)
+ {
+ // no transient props
+ if ( rProp.Attributes & PropertyAttribute::TRANSIENT )
+ continue;
+ // no read-only props
+ if ( ( rProp.Attributes & PropertyAttribute::READONLY ) != 0 )
+ // except they're dynamically added
+ if ( ( rProp.Attributes & PropertyAttribute::REMOVABLE ) == 0 )
+ continue;
+ m_aRemainingProps.insert(rProp.Name);
+ }
+ }
+
+ void OPropertyExport::exportStringPropertyAttribute( const sal_uInt16 _nNamespaceKey, const OUString& _pAttributeName,
+ const OUString& _rPropertyName )
+ {
+ DBG_CHECK_PROPERTY( _rPropertyName, OUString );
+
+ // no try-catch here, this would be too expensive. The outer scope has to handle exceptions (which should not
+ // happen if we're used correctly :)
+
+ // this is way simple, as we don't need to convert anything (the property already is a string)
+
+ // get the string
+ OUString sPropValue;
+ m_xProps->getPropertyValue( _rPropertyName ) >>= sPropValue;
+
+ // add the attribute
+ if ( !sPropValue.isEmpty() )
+ AddAttribute( _nNamespaceKey, _pAttributeName, sPropValue );
+
+ // the property does not need to be handled anymore
+ exportedProperty( _rPropertyName );
+ }
+
+ void OPropertyExport::exportBooleanPropertyAttribute(const sal_uInt16 _nNamespaceKey, const OUString& _pAttributeName,
+ const OUString& _rPropertyName, const BoolAttrFlags _nBooleanAttributeFlags)
+ {
+ DBG_CHECK_PROPERTY_NO_TYPE( _rPropertyName );
+ // no check of the property value type: this method is allowed to be called with any integer properties
+ // (e.g. sal_Int32, sal_uInt16 etc)
+
+ bool bDefault(BoolAttrFlags::DefaultTrue & _nBooleanAttributeFlags);
+ bool bDefaultVoid(BoolAttrFlags::DefaultVoid & _nBooleanAttributeFlags);
+
+ // get the value
+ bool bCurrentValue = bDefault;
+ Any aCurrentValue = m_xProps->getPropertyValue( _rPropertyName );
+ if (aCurrentValue.hasValue())
+ {
+ bCurrentValue = ::cppu::any2bool(aCurrentValue);
+ // this will extract a boolean value even if the Any contains a int or short or something like that ...
+
+ if (_nBooleanAttributeFlags & BoolAttrFlags::InverseSemantics)
+ bCurrentValue = !bCurrentValue;
+
+ // we have a non-void current value
+ if (bDefaultVoid || (bDefault != bCurrentValue))
+ // and (the default is void, or the non-void default does not equal the current value)
+ // -> write the attribute
+ AddAttribute(_nNamespaceKey, _pAttributeName, bCurrentValue ? m_sValueTrue : m_sValueFalse);
+ }
+ else
+ // we have a void current value
+ if (!bDefaultVoid)
+ // and we have a non-void default
+ // -> write the attribute
+ AddAttribute(_nNamespaceKey, _pAttributeName, bCurrentValue ? m_sValueTrue : m_sValueFalse);
+
+ // the property does not need to be handled anymore
+ exportedProperty( _rPropertyName );
+ }
+
+ void OPropertyExport::exportInt16PropertyAttribute(const sal_uInt16 _nNamespaceKey, const OUString& _pAttributeName,
+ const OUString& _rPropertyName, const sal_Int16 _nDefault, bool force)
+ {
+ DBG_CHECK_PROPERTY( _rPropertyName, sal_Int16 );
+
+ // get the value
+ sal_Int16 nCurrentValue(_nDefault);
+ m_xProps->getPropertyValue( _rPropertyName ) >>= nCurrentValue;
+
+ // add the attribute
+ if (force || _nDefault != nCurrentValue)
+ {
+ // let the formatter of the export context build a string
+ AddAttribute(_nNamespaceKey, _pAttributeName, OUString::number(nCurrentValue));
+ }
+
+ // the property does not need to be handled anymore
+ exportedProperty( _rPropertyName );
+ }
+
+ void OPropertyExport::exportInt32PropertyAttribute( const sal_uInt16 _nNamespaceKey, const OUString& _pAttributeName,
+ const OUString& _rPropertyName, const sal_Int32 _nDefault )
+ {
+ DBG_CHECK_PROPERTY( _rPropertyName, sal_Int32 );
+
+ // get the value
+ sal_Int32 nCurrentValue( _nDefault );
+ m_xProps->getPropertyValue( _rPropertyName ) >>= nCurrentValue;
+
+ // add the attribute
+ if ( _nDefault != nCurrentValue )
+ {
+ // let the formatter of the export context build a string
+ AddAttribute( _nNamespaceKey, _pAttributeName, OUString::number(nCurrentValue) );
+ }
+
+ // the property does not need to be handled anymore
+ exportedProperty( _rPropertyName );
+ }
+
+ void OPropertyExport::exportEnumPropertyAttributeImpl(
+ const sal_uInt16 _nNamespaceKey, const OUString& _pAttributeName,
+ const OUString &rPropertyName, const SvXMLEnumMapEntry<sal_uInt16>* _pValueMap,
+ const sal_uInt16 _nDefault, const bool _bVoidDefault)
+ {
+ // get the value
+ Any aValue = m_xProps->getPropertyValue(rPropertyName);
+
+ if (aValue.hasValue())
+ { // we have a non-void current value
+ sal_Int32 nCurrentValue(_nDefault);
+ ::cppu::enum2int(nCurrentValue, aValue);
+
+ // add the attribute
+ if ((_nDefault != nCurrentValue) || _bVoidDefault)
+ { // the default does not equal the value, or the default is void and the value isn't
+
+ // let the formatter of the export context build a string
+ OUStringBuffer sBuffer;
+ SvXMLUnitConverter::convertEnum(sBuffer, static_cast<sal_uInt16>(nCurrentValue), _pValueMap);
+
+ AddAttribute(_nNamespaceKey, _pAttributeName, sBuffer.makeStringAndClear());
+ }
+ }
+ else
+ {
+ if (!_bVoidDefault)
+ AddAttribute(_nNamespaceKey, _pAttributeName, OUString());
+ }
+
+ // the property does not need to be handled anymore
+ exportedProperty(rPropertyName);
+ }
+
+ void OPropertyExport::exportTargetFrameAttribute()
+ {
+ DBG_CHECK_PROPERTY( PROPERTY_TARGETFRAME, OUString );
+
+ OUString sTargetFrame = comphelper::getString(m_xProps->getPropertyValue(PROPERTY_TARGETFRAME));
+ if( sTargetFrame != "_blank" )
+ { // an empty string and "_blank" have the same meaning and don't have to be written
+ AddAttribute(OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::TargetFrame)
+ ,OAttributeMetaData::getCommonControlAttributeName(CCAFlags::TargetFrame)
+ ,sTargetFrame);
+ }
+
+ exportedProperty(PROPERTY_TARGETFRAME);
+ }
+
+ void OPropertyExport::exportRelativeTargetLocation(const OUString& _sPropertyName,CCAFlags _nProperty,bool _bAddType)
+ {
+ Any aAny = m_xProps->getPropertyValue(_sPropertyName);
+
+ OUString sTargetLocation;
+ if (aAny.has<uno::Reference<graphic::XGraphic>>())
+ {
+ auto xGraphic = aAny.get<uno::Reference<graphic::XGraphic>>();
+ OUString sOutMimeType;
+ sTargetLocation = m_rContext.getGlobalContext().AddEmbeddedXGraphic(xGraphic, sOutMimeType);
+ }
+ else if (aAny.has<OUString>())
+ {
+ auto sURL = aAny.get<OUString>();
+ sTargetLocation = m_rContext.getGlobalContext().AddEmbeddedObject(sURL);
+ }
+ else
+ {
+ SAL_WARN("xmloff.forms", "OPropertyExport::exportRelativeTargetLocation: "
+ "Value of " << _sPropertyName << " not found!");
+ }
+
+ if (!sTargetLocation.isEmpty())
+ {
+ AddAttribute(OAttributeMetaData::getCommonControlAttributeNamespace(_nProperty)
+ ,OAttributeMetaData::getCommonControlAttributeName(_nProperty)
+ , sTargetLocation);
+
+ // #i110911# add xlink:type="simple" if required
+ if (_bAddType)
+ AddAttribute(XML_NAMESPACE_XLINK, token::XML_TYPE, token::XML_SIMPLE);
+
+ exportedProperty(_sPropertyName);
+ }
+ }
+ void OPropertyExport::flagStyleProperties()
+ {
+ // flag all the properties which are part of the style as "handled"
+ rtl::Reference< XMLPropertySetMapper > xStylePropertiesSupplier = m_rContext.getStylePropertyMapper()->getPropertySetMapper();
+ for (sal_Int32 i=0; i<xStylePropertiesSupplier->GetEntryCount(); ++i)
+ exportedProperty(xStylePropertiesSupplier->GetEntryAPIName(i));
+
+ // the font properties are exported as single properties, but there is a FontDescriptor property which
+ // collects them all-in-one, this has been exported implicitly
+ exportedProperty(PROPERTY_FONT);
+
+ // for the DateFormat and TimeFormat, there exist wrapper properties which has been exported as
+ // style, too
+ exportedProperty(PROPERTY_DATEFORMAT);
+ exportedProperty(PROPERTY_TIMEFORMAT);
+
+ // the following properties should have been exported at the shape already:
+ exportedProperty( "VerticalAlign" );
+ exportedProperty( "WritingMode" );
+ exportedProperty( "ScaleMode" );
+ // ditto the TextWritingMode
+ exportedProperty( "WritingMode" );
+ }
+
+ void OPropertyExport::exportGenericPropertyAttribute(
+ const sal_uInt16 _nAttributeNamespaceKey, const OUString& _pAttributeName, const char* _pPropertyName)
+ {
+ DBG_CHECK_PROPERTY_ASCII_NO_TYPE( _pPropertyName );
+
+ OUString sPropertyName = OUString::createFromAscii(_pPropertyName);
+ exportedProperty(sPropertyName);
+
+ Any aCurrentValue = m_xProps->getPropertyValue(sPropertyName);
+ if (!aCurrentValue.hasValue())
+ // nothing to do without a concrete value
+ return;
+
+ OUString sValue = implConvertAny(aCurrentValue);
+ if (sValue.isEmpty() && (TypeClass_STRING == aCurrentValue.getValueTypeClass()))
+ {
+ // check whether or not the property is allowed to be VOID
+ Property aProperty = m_xPropertyInfo->getPropertyByName(sPropertyName);
+ if ((aProperty.Attributes & PropertyAttribute::MAYBEVOID) == 0)
+ // the string is empty, and the property is not allowed to be void
+ // -> don't need to write the attribute, 'cause missing it is unambiguous
+ return;
+ }
+
+ // finally add the attribute to the context
+ AddAttribute(_nAttributeNamespaceKey, _pAttributeName, sValue);
+ }
+
+ void OPropertyExport::exportStringSequenceAttribute(const sal_uInt16 _nAttributeNamespaceKey, const OUString& _pAttributeName,
+ const OUString& _rPropertyName)
+ {
+ const sal_Unicode _aListSeparator = ',';
+ const sal_Unicode _aQuoteCharacter = '"';
+ DBG_CHECK_PROPERTY( _rPropertyName, Sequence< OUString > );
+
+ Sequence< OUString > aItems;
+ m_xProps->getPropertyValue( _rPropertyName ) >>= aItems;
+
+ OUStringBuffer sFinalList;
+
+ // unfortunately the OUString can't append single sal_Unicode characters ...
+ const OUString sQuote(&_aQuoteCharacter, 1);
+ const OUString sSeparator(&_aListSeparator, 1);
+ const bool bQuote = !sQuote.isEmpty();
+
+ // concatenate the string items
+ const OUString* pItems = aItems.getConstArray();
+ const OUString* pEnd = pItems + aItems.getLength();
+ const OUString* pLastElement = pEnd - 1;
+ for ( ;
+ pItems != pEnd;
+ ++pItems
+ )
+ {
+ OSL_ENSURE(-1 == pItems->indexOf(_aQuoteCharacter),
+ "OPropertyExport::exportStringSequenceAttribute: there is an item which contains the quote character!");
+
+ if (bQuote)
+ sFinalList.append(sQuote);
+ sFinalList.append(*pItems);
+ if (bQuote)
+ sFinalList.append(sQuote);
+
+ if (pItems != pLastElement)
+ sFinalList.append(sSeparator);
+ }
+
+ if (!sFinalList.isEmpty())
+ AddAttribute(_nAttributeNamespaceKey, _pAttributeName, sFinalList.makeStringAndClear());
+
+ exportedProperty( _rPropertyName );
+ }
+
+ OUString OPropertyExport::implConvertAny(const Any& _rValue)
+ {
+ OUStringBuffer aBuffer;
+ switch (_rValue.getValueTypeClass())
+ {
+ case TypeClass_STRING:
+ { // extract the string
+ OUString sCurrentValue;
+ _rValue >>= sCurrentValue;
+ aBuffer.append(sCurrentValue);
+ }
+ break;
+ case TypeClass_DOUBLE:
+ // let the unit converter format is as string
+ ::sax::Converter::convertDouble(aBuffer, getDouble(_rValue));
+ break;
+ case TypeClass_BOOLEAN:
+ aBuffer = getBOOL(_rValue) ? m_sValueTrue : m_sValueFalse;
+ break;
+ case TypeClass_BYTE:
+ case TypeClass_UNSIGNED_SHORT:
+ case TypeClass_SHORT:
+ case TypeClass_LONG:
+ // let the unit converter format is as string
+ aBuffer.append(getINT32(_rValue));
+ break;
+ case TypeClass_UNSIGNED_LONG:
+ case TypeClass_HYPER:
+ aBuffer.append(getINT64(_rValue));
+ break;
+ case TypeClass_UNSIGNED_HYPER:
+ aBuffer.append(static_cast<sal_Int64>(_rValue.get<sal_uInt64>()));
+ break;
+ case TypeClass_ENUM:
+ {
+ // convert it into an int32
+ sal_Int32 nValue = 0;
+ ::cppu::enum2int(nValue, _rValue);
+ aBuffer.append(nValue);
+ }
+ break;
+ default:
+ { // hmmm... what else do we know?
+ double fValue = 0;
+ css::util::Date aDate;
+ css::util::Time aTime;
+ css::util::DateTime aDateTime;
+ if (_rValue >>= aDate)
+ {
+ Date aToolsDate( Date::EMPTY );
+ ::utl::typeConvert(aDate, aToolsDate);
+ fValue = aToolsDate.GetDate();
+ }
+ else if (_rValue >>= aTime)
+ {
+ fValue = aTime.Hours / static_cast<double>(::tools::Time::hourPerDay) +
+ aTime.Minutes / static_cast<double>(::tools::Time::minutePerDay) +
+ aTime.Seconds / static_cast<double>(::tools::Time::secondPerDay) +
+ aTime.NanoSeconds / static_cast<double>(::tools::Time::nanoSecPerDay);
+ }
+ else if (_rValue >>= aDateTime)
+ {
+ DateTime aToolsDateTime( DateTime::EMPTY );
+ ::utl::typeConvert(aDateTime, aToolsDateTime);
+ // the time part (the digits behind the comma)
+ fValue = aTime.Hours / static_cast<double>(::tools::Time::hourPerDay) +
+ aTime.Minutes / static_cast<double>(::tools::Time::minutePerDay) +
+ aTime.Seconds / static_cast<double>(::tools::Time::secondPerDay) +
+ aTime.NanoSeconds / static_cast<double>(::tools::Time::nanoSecPerDay);
+ // plus the data part (the digits in front of the comma)
+ fValue += aToolsDateTime.GetDate();
+ }
+ else
+ {
+ // if any other types are added here, please remember to adjust implGetPropertyXMLType accordingly
+
+ // no more options ...
+ OSL_FAIL("OPropertyExport::implConvertAny: unsupported value type!");
+ break;
+ }
+ // let the unit converter format is as string
+ ::sax::Converter::convertDouble(aBuffer, fValue);
+ }
+ break;
+ }
+
+ return aBuffer.makeStringAndClear();
+ }
+
+ token::XMLTokenEnum OPropertyExport::implGetPropertyXMLType(const css::uno::Type& _rType)
+ {
+ // handle the type description
+ switch (_rType.getTypeClass())
+ {
+ case TypeClass_STRING:
+ return token::XML_STRING;
+ case TypeClass_DOUBLE:
+ case TypeClass_BYTE:
+ case TypeClass_SHORT:
+ case TypeClass_LONG:
+ case TypeClass_HYPER:
+ case TypeClass_ENUM:
+ return token::XML_FLOAT;
+ case TypeClass_BOOLEAN:
+ return token::XML_BOOLEAN;
+
+ default:
+ return token::XML_FLOAT;
+ }
+ }
+
+#ifdef DBG_UTIL
+ void OPropertyExport::AddAttribute( sal_uInt16 _nPrefix, const OUString& _rName, const OUString& _rValue )
+ {
+ OSL_ENSURE(m_rContext.getGlobalContext().GetXAttrList()->getValueByName( _rName ).isEmpty(),
+ "OPropertyExport::AddAttribute: already have such an attribute");
+
+ m_rContext.getGlobalContext().AddAttribute( _nPrefix, _rName, _rValue );
+ }
+
+ void OPropertyExport::AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, const OUString& _rValue)
+ {
+ OSL_ENSURE(m_rContext.getGlobalContext().GetXAttrList()->getValueByName(::xmloff::token::GetXMLToken(_eName)).isEmpty(),
+ "OPropertyExport::AddAttribute: already have such an attribute");
+
+ m_rContext.getGlobalContext().AddAttribute(_nPrefix, _eName, _rValue);
+ }
+
+ void OPropertyExport::AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, ::xmloff::token::XMLTokenEnum _eValue )
+ {
+ OSL_ENSURE(m_rContext.getGlobalContext().GetXAttrList()->getValueByName(::xmloff::token::GetXMLToken(_eName)).isEmpty(),
+ "OPropertyExport::AddAttribute: already have such an attribute");
+
+ m_rContext.getGlobalContext().AddAttribute(_nPrefix, _eName, _eValue);
+ }
+
+ void OPropertyExport::dbg_implCheckProperty(const OUString& _rPropertyName, const Type* _pType)
+ {
+ try
+ {
+ // the property must exist
+ if (!m_xPropertyInfo->hasPropertyByName(_rPropertyName))
+ {
+ SAL_WARN("xmloff.forms", "OPropertyExport: "
+ "no property with the name " + _rPropertyName + "!");
+ return;
+ }
+
+ if (_pType)
+ {
+ // and it must have the correct type
+ Property aPropertyDescription = m_xPropertyInfo->getPropertyByName(_rPropertyName);
+ OSL_ENSURE(aPropertyDescription.Type.equals(*_pType), "OPropertyExport::dbg_implCheckProperty: invalid property type!");
+ }
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("xmloff.forms", "could not check the property!");
+ }
+ }
+#endif // DBG_UTIL - dbg_implCheckProperty
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/propertyexport.hxx b/xmloff/source/forms/propertyexport.hxx
new file mode 100644
index 000000000..b848ab6e4
--- /dev/null
+++ b/xmloff/source/forms/propertyexport.hxx
@@ -0,0 +1,413 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <set>
+
+#include "formattributes.hxx"
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmlexp.hxx>
+#include "callbacks.hxx"
+#include "strings.hxx"
+
+enum class BoolAttrFlags {
+ DefaultFalse = 0x00,
+ DefaultTrue = 0x01,
+ DefaultVoid = 0x02,
+ InverseSemantics = 0x04,
+};
+namespace o3tl {
+ template<> struct typed_flags<BoolAttrFlags> : is_typed_flags<BoolAttrFlags, 0x07> {};
+}
+
+namespace xmloff
+{
+
+ // if sal_True, indicates that the semantic of the property referred by <arg>_pPropertyName</arg>
+ // is inverse to the semantic of the XML attribute.<br/>
+ // I.e. if the property value is <TRUE/>, <FALSE/> has to be written and vice versa.
+ // <p>Be careful with <arg>_bDefault</arg> and <arg>_bInverseSemantics</arg>: if <arg>_bInverseSemantics</arg>
+ // is <TRUE/>, the current property value is inverted <em>before</em> comparing it to the default.</p>
+
+ class IFormsExportContext;
+ //= OPropertyExport
+ /** provides export related tools for attribute handling
+
+ <p>(The name is somewhat misleading. It's not only a PropertyExport, but in real an ElementExport.
+ Anyway.)</p>
+ */
+ class OPropertyExport
+ {
+ private:
+ std::set<OUString> m_aRemainingProps;
+ // see examinePersistence
+
+ void exportRelativeTargetLocation(const OUString& _sPropertyName, CCAFlags _nProperty,bool _bAddType);
+
+ protected:
+ IFormsExportContext& m_rContext;
+
+ const css::uno::Reference< css::beans::XPropertySet >
+ m_xProps;
+ const css::uno::Reference< css::beans::XPropertySetInfo >
+ m_xPropertyInfo;
+ const css::uno::Reference< css::beans::XPropertyState >
+ m_xPropertyState;
+
+ // caching
+ OUString m_sValueTrue;
+ OUString m_sValueFalse;
+
+ public:
+ /** constructs an object capable of handling attributes for export
+ @param _rContext
+ the export context to which's attribute list the property translation should be added
+ @param m_xControl
+ the property set to be exported
+ */
+ OPropertyExport(IFormsExportContext& _rContext,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxProps);
+
+ protected:
+ /** examines a property set given for all properties which's value are to made persistent
+
+ <p>upon return the <method>m_aRemainingProps</method> will be filled with the names of all properties
+ which need to be stored</p>
+ */
+ void examinePersistence();
+
+ template< typename T > void exportRemainingPropertiesSequence(
+ css::uno::Any const & value,
+ token::XMLTokenEnum eValueAttName);
+
+ void exportRemainingProperties();
+
+ /** indicates that a property has been handled by a derived class, without using the helper methods of this
+ class.
+
+ <p>Calling this method is necessary in case you use the suggested mechanism for the generic export of
+ properties. This means that you want to use <method>exportRemainingProperties</method>, which exports
+ all properties which need to ('cause they haven't been exported with one of the other type-specific
+ methods).</p>
+
+ <p>In this case you should call exportedProperty for every property you export yourself, so the property
+ will be flagged as <em>already handled</em></p>
+ */
+ void exportedProperty(const OUString& _rPropertyName)
+ { m_aRemainingProps.erase(_rPropertyName); }
+
+ /** add an attribute which is represented by a string property to the export context
+
+ @param _nNamespaceKey
+ the key of the namespace to use for the attribute name. Is used with the namespace map
+ provided by the export context.
+ @param _pAttributeName
+ the name of the attribute to add. Must not contain any namespace
+ @param _pPropertyName
+ the name of the property to ask the control for
+ */
+ void exportStringPropertyAttribute(
+ const sal_uInt16 _nNamespaceKey,
+ const OUString& _pAttributeName,
+ const OUString& _rPropertyName
+ );
+
+ /** add an attribute which is represented by a boolean property to the export context
+
+ @param _nNamespaceKey
+ the key of the namespace to use for the attribute name. Is used with the namespace map
+ provided by the export context.
+ @param _pAttributeName
+ the name of the attribute to add. Must not contain any namespace (it's added automatically)
+ @param _pPropertyName
+ the name of the property to ask the control for
+ @param _nBooleanAttributeFlags
+ specifies the default and the "alignment" (inverse semantics) of the boolean property
+ */
+ void exportBooleanPropertyAttribute(
+ const sal_uInt16 _nNamespaceKey,
+ const OUString& _pAttributeName,
+ const OUString& _rPropertyName,
+ const BoolAttrFlags _nBooleanAttributeFlags);
+
+ /** add an attribute which is represented by a sal_Int16 property to the export context
+
+ @param _nNamespaceKey
+ the key of the namespace to use for the attribute name. Is used with the namespace map
+ provided by the export context.
+ @param _pAttributeName
+ the name of the attribute to add. Must not contain any namespace (it's added automatically)
+ @param _pPropertyName
+ the name of the property to ask the control for
+ @param _nDefault
+ the default of the attribute. See force parameter.
+ @param force
+ if true and the property is not set or does not contain a sal_Int16,
+ then _nDefault is written out.
+ if false and the current property value equals _nDefault,
+ then no attribute is added.
+ */
+ void exportInt16PropertyAttribute(
+ const sal_uInt16 _nNamespaceKey,
+ const OUString& _pAttributeName,
+ const OUString& _rPropertyName,
+ const sal_Int16 _nDefault,
+ const bool force = false);
+
+ /** add an attribute which is represented by a sal_Int32 property to the export context
+
+ @param _nNamespaceKey
+ the key of the namespace to use for the attribute name. Is used with the namespace map
+ provided by the export context.
+ @param _pAttributeName
+ the name of the attribute to add. Must not contain any namespace (it's added automatically)
+ @param _pPropertyName
+ the name of the property to ask the control for
+ @param _nDefault
+ the default of the attribute. If the current property value equals this default, no
+ attribute is added.
+ */
+ void exportInt32PropertyAttribute(
+ const sal_uInt16 _nNamespaceKey,
+ const OUString& _pAttributeName,
+ const OUString& _rPropertyName,
+ const sal_Int32 _nDefault);
+
+ /** add an attribute which is represented by an enum property to the export context
+
+ @param _nNamespaceKey
+ the key of the namespace to use for the attribute name. Is used with the namespace map
+ provided by the export context.
+ @param _pAttributeName
+ the name of the attribute to add. Must not contain any namespace (it's added automatically)
+ @param _pPropertyName
+ the name of the property to ask the control for
+ @param _pValueMap
+ the map to use when converting the property value to an attribute value
+ @param _nDefault
+ the default of the attribute. If the current property value equals this default, no
+ attribute is added.
+ */
+ template<typename EnumT>
+ void exportEnumPropertyAttribute(
+ const sal_uInt16 _nNamespaceKey,
+ const OUString& _pAttributeName,
+ const OUString& _rPropertyName,
+ const SvXMLEnumMapEntry<EnumT>* _pValueMap,
+ const EnumT _nDefault,
+ const bool _bVoidDefault = false)
+ {
+ exportEnumPropertyAttributeImpl(_nNamespaceKey, _pAttributeName, _rPropertyName,
+ reinterpret_cast<const SvXMLEnumMapEntry<sal_uInt16>*>(_pValueMap),
+ static_cast<sal_Int16>(_nDefault), _bVoidDefault);
+ }
+ void exportEnumPropertyAttributeImpl(
+ const sal_uInt16 _nNamespaceKey,
+ const OUString& _pAttributeName,
+ const OUString& _rPropertyName,
+ const SvXMLEnumMapEntry<sal_uInt16>* _pValueMap,
+ const sal_uInt16 _nDefault,
+ const bool _bVoidDefault);
+
+ // some very special methods for some very special attribute/property pairs
+
+ /** add the hlink:target-frame attribute to the export context.
+
+ <p>The value of this attribute is extracted from the TargetFrame property of the object given.</p>
+
+ <p>The property needs a special handling because conflicts between the default values for the attribute
+ and the property.</p>
+ */
+ void exportTargetFrameAttribute();
+
+ /** add the form:href attribute to the export context.
+
+ <p>The value of this attribute is extracted from the TargetURL property of the object given.</p>
+
+ <p>The property needs a special handling because the URL's need to be made relative</p>
+
+ <p>If _bAddType is set, an additional xlink:type="simple" attribute is also added.</p>
+ */
+ void exportTargetLocationAttribute(bool _bAddType) { exportRelativeTargetLocation(PROPERTY_TARGETURL,CCAFlags::TargetLocation,_bAddType); }
+
+ /** add the form:image attribute to the export context.
+
+ <p>The value of this attribute is extracted from the ImageURL property of the object given.</p>
+
+ <p>The property needs a special handling because the URL's need to be made relative</p>
+ */
+ void exportImageDataAttribute() { exportRelativeTargetLocation(PROPERTY_GRAPHIC, CCAFlags::ImageData, false); }
+
+ /** flag the style properties as 'already exported'
+
+ <p>We don't have style support right now, so the only thing the method does is removing the style-relevant
+ properties from the list of yet-to-be-exported properties (<member>m_aRemainingProps</member>)</p>
+ */
+ void flagStyleProperties();
+
+ /** add an arbitrary attribute extracted from an arbitrary property to the export context
+
+ <p>The current value of the property specified with <arg>_pPropertyName</arg> is taken and converted
+ into a string, no matter what type it has. (Okay, there are the usual limitations: We know Date, Datetime,
+ double, integer ... to name just a few).</p>
+
+ <p>In case the property value is <NULL/> (void), no attribute is added</p>
+
+ <p>In case the property value is an empty string, and the property is a not allowed to be <NULL/> (void),
+ no attribute is added</p>
+
+ <p>In case the property value is a sequence of any type, no attribute is added, 'cause sequences can't be
+ transported as attribute. In the debug version, an additional assertion will occur if you nonetheless try
+ to do this.</p>
+
+ @param _nNamespaceKey
+ the key of the namespace to use for the attribute name. Is used with the namespace map
+ provided by the export context.
+ @param _pAttributeName
+ the name of the attribute to add. Must not contain any namespace (it's added automatically)
+ @param _pPropertyName
+ the name of the property to ask the object for
+ */
+ void exportGenericPropertyAttribute(
+ const sal_uInt16 _nAttributeNamespaceKey,
+ const OUString& _pAttributeName,
+ const char* _pPropertyName);
+
+ /** exports a property value, which is a string sequence, as attribute
+
+ <p>The elements of the string sequence given are quoted and concatenated, with the characters used for
+ this to be chosen by the caller</p>
+
+ <p>If you use the quote character, no check (except assertions) is made if one of the list items
+ contains the quote character</p>
+
+ <p>If you don't use the quote character, no check (except assertions) is made if one of the list items
+ contains the separator character (which would be deadly when reimporting the string)</p>
+
+ @param _nNamespaceKey
+ the key of the namespace to use for the attribute name. Is used with the namespace map
+ provided by the export context.
+ @param _pAttributeName
+ the name of the attribute to add. Must not contain any namespace (it's added automatically)
+ @param _pPropertyName
+ the name of the property to ask the object for
+ */
+ void exportStringSequenceAttribute(
+ const sal_uInt16 _nAttributeNamespaceKey,
+ const OUString& _pAttributeName,
+ const OUString& _rPropertyName);
+
+ /** determines whether the given property is to be exported
+
+ <p>Currently, the method simply checks whether the property's state is <em>not</em> PropertyState.DEFAULT,
+ or whether the property is a dynamic property (i.e. added via an <code>XPropertyContainer</code>).
+ So, take care when using the method - the heuristics is not applicable for all properties.</p>
+ */
+ bool shouldExportProperty( const OUString& i_propertyName ) const;
+
+ /** tries to convert an arbitrary <type scope="com.sun:star.uno">Any</type> into an string
+
+ <p>If the type contained in the Any is not supported, the returned string will be empty. In the
+ debug version, an additional assertion occurs.</p>
+
+ @param _rValue
+ the value to convert
+ */
+ OUString implConvertAny(
+ const css::uno::Any& _rValue);
+
+ /**
+ @return
+ token which can be used in the <code>form:property</code> element's <code>type</code> attribute
+ to describe the type of a value.<br/>
+ Possible types returned are
+ <ul>
+ <li><b>boolean</b>: <arg>_rValue</arg> was interpreted as boolean value before converting
+ it into a string</li>
+ <li><b>float</b>: <arg>_rValue</arg> was interpreted as 64 bit floating point 16bit integer, 32bit integer or 64 bit integer value before
+ converting it into a string</li>
+ <li><b>string</b>: <arg>_rValue</arg> did not need any conversion as it already was a string</li>
+ </ul>
+ If the type is not convertible, float is returned
+ */
+ static ::xmloff::token::XMLTokenEnum implGetPropertyXMLType(const css::uno::Type& _rType);
+
+#ifdef DBG_UTIL
+ void AddAttribute( sal_uInt16 _nPrefix, const OUString& _rName, const OUString& _rValue );
+ void AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, const OUString& _rValue);
+ void AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, ::xmloff::token::XMLTokenEnum _eValue );
+#else
+ // in the product version, inline this, so it does not cost us extra time calling into our method
+ void AddAttribute( sal_uInt16 _nPrefix, const OUString& _rName, const OUString& _rValue )
+ { m_rContext.getGlobalContext().AddAttribute( _nPrefix, _rName, _rValue ); }
+ void AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, const OUString& _rValue)
+ { m_rContext.getGlobalContext().AddAttribute(_nPrefix, _eName, _rValue); }
+ void AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, ::xmloff::token::XMLTokenEnum _eValue )
+ { m_rContext.getGlobalContext().AddAttribute(_nPrefix, _eName, _eValue); }
+#endif
+
+#ifdef DBG_UTIL
+ protected:
+ /** check a given property set for the existence and type correctness of a given property
+
+ <p>This method is available in the non-product version only.</p>
+
+ @param _rPropertyName
+ the name of the property to ask the control model for
+ @param _pType
+ the expected type of the property. May be NULL, in this case no type check is made.
+ @return sal_True, if the property exists and is of the correct type
+ */
+ void dbg_implCheckProperty(
+ const OUString& _rPropertyName,
+ const css::uno::Type* _pType);
+
+// void dbg_implCheckProperty(
+// const char* _rPropertyName,
+// const css::uno::Type* _pType)
+// {
+// dbg_implCheckProperty(OUString::createFromAscii(_rPropertyName), _pType);
+// }
+#endif
+ };
+
+ //= helper
+#ifdef DBG_UTIL
+ #define DBG_CHECK_PROPERTY(name, type) \
+ dbg_implCheckProperty(name, &cppu::UnoType<type>::get())
+
+ #define DBG_CHECK_PROPERTY_NO_TYPE(name) \
+ dbg_implCheckProperty(name, nullptr)
+
+ #define DBG_CHECK_PROPERTY_ASCII_NO_TYPE( name ) \
+ dbg_implCheckProperty( OUString::createFromAscii( name ), nullptr )
+#else
+ #define DBG_CHECK_PROPERTY(name, type)
+ #define DBG_CHECK_PROPERTY_NO_TYPE(name)
+ #define DBG_CHECK_PROPERTY_ASCII_NO_TYPE( name )
+#endif
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/propertyimport.cxx b/xmloff/source/forms/propertyimport.cxx
new file mode 100644
index 000000000..ded9fa856
--- /dev/null
+++ b/xmloff/source/forms/propertyimport.cxx
@@ -0,0 +1,524 @@
+/* -*- 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 <cmath>
+
+#include "propertyimport.hxx"
+
+#include <sax/tools/converter.hxx>
+
+#include <xmloff/xmlimp.hxx>
+#include <xmloff/xmluconv.hxx>
+#include <xmloff/namespacemap.hxx>
+#include <o3tl/temporary.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <comphelper/extract.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <tools/date.hxx>
+#include <tools/time.hxx>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <unotools/datetime.hxx>
+#include <rtl/strbuf.hxx>
+
+using namespace ::xmloff::token;
+
+namespace xmloff
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::xml;
+ using ::com::sun::star::xml::sax::XAttributeList;
+ using ::com::sun::star::xml::sax::XFastAttributeList;
+
+ // NO using namespace ...util !!!
+ // need a tools Date/Time/DateTime below, which would conflict with the uno types then
+
+#define TYPE_DATE 1
+#define TYPE_TIME 2
+#define TYPE_DATETIME 3
+
+//= PropertyConversion
+namespace
+{
+ css::util::Time lcl_getTime(double _nValue)
+ {
+ css::util::Time aTime;
+ sal_uInt64 nIntValue = static_cast<sal_uInt64>(_nValue * ::tools::Time::nanoSecPerDay);
+ aTime.NanoSeconds = nIntValue % ::tools::Time::nanoSecPerSec;
+ nIntValue /= ::tools::Time::nanoSecPerSec;
+ aTime.Seconds = nIntValue % ::tools::Time::secondPerMinute;
+ nIntValue /= ::tools::Time::secondPerMinute;
+ aTime.Minutes = nIntValue % ::tools::Time::minutePerHour;
+ nIntValue /= ::tools::Time::minutePerHour;
+ OSL_ENSURE(nIntValue < 24, "lcl_getTime: more than a day?");
+ aTime.Hours = nIntValue;
+
+ return aTime;
+ }
+
+ css::util::Date lcl_getDate( double _nValue )
+ {
+ Date aToolsDate(static_cast<sal_uInt32>(_nValue));
+ css::util::Date aDate;
+ ::utl::typeConvert(aToolsDate, aDate);
+ return aDate;
+ }
+}
+
+Any PropertyConversion::convertString( const css::uno::Type& _rExpectedType,
+ const OUString& _rReadCharacters, const SvXMLEnumMapEntry<sal_uInt16>* _pEnumMap, const bool _bInvertBoolean )
+{
+ Any aReturn;
+ bool bEnumAsInt = false;
+ switch (_rExpectedType.getTypeClass())
+ {
+ case TypeClass_BOOLEAN: // sal_Bool
+ {
+ bool bValue;
+ bool bSuccess =
+ ::sax::Converter::convertBool(bValue, _rReadCharacters);
+ OSL_ENSURE(bSuccess,
+ OStringBuffer("PropertyConversion::convertString: could not convert \"" +
+ OUStringToOString(_rReadCharacters, RTL_TEXTENCODING_ASCII_US) +
+ "\" into a boolean!").getStr());
+ aReturn <<= (_bInvertBoolean ? !bValue : bValue);
+ }
+ break;
+ case TypeClass_SHORT: // sal_Int16
+ case TypeClass_LONG: // sal_Int32
+ if (!_pEnumMap)
+ { // it's a real int32/16 property
+ sal_Int32 nValue(0);
+ bool bSuccess =
+ ::sax::Converter::convertNumber(nValue, _rReadCharacters);
+ OSL_ENSURE(bSuccess,
+ OStringBuffer("PropertyConversion::convertString: could not convert \"" +
+ OUStringToOString(_rReadCharacters, RTL_TEXTENCODING_ASCII_US) +
+ "\" into an integer!").getStr());
+ if (TypeClass_SHORT == _rExpectedType.getTypeClass())
+ aReturn <<= static_cast<sal_Int16>(nValue);
+ else
+ aReturn <<= nValue;
+ break;
+ }
+ bEnumAsInt = true;
+ [[fallthrough]];
+ case TypeClass_ENUM:
+ {
+ sal_uInt16 nEnumValue(0);
+ bool bSuccess = SvXMLUnitConverter::convertEnum(nEnumValue, _rReadCharacters, _pEnumMap);
+ OSL_ENSURE(bSuccess, "PropertyConversion::convertString: could not convert to an enum value!");
+
+ if (bEnumAsInt)
+ if (TypeClass_SHORT == _rExpectedType.getTypeClass())
+ aReturn <<= static_cast<sal_Int16>(nEnumValue);
+ else
+ aReturn <<= static_cast<sal_Int32>(nEnumValue);
+ else
+ aReturn = ::cppu::int2enum(static_cast<sal_Int32>(nEnumValue), _rExpectedType);
+ }
+ break;
+ case TypeClass_HYPER:
+ {
+ OSL_FAIL("PropertyConversion::convertString: 64-bit integers not implemented yet!");
+ }
+ break;
+ case TypeClass_DOUBLE:
+ {
+ double nValue;
+ bool bSuccess =
+ ::sax::Converter::convertDouble(nValue, _rReadCharacters);
+ OSL_ENSURE(bSuccess,
+ OStringBuffer(OString::Concat("PropertyConversion::convertString: could not convert \"") +
+ OUStringToOString(_rReadCharacters, RTL_TEXTENCODING_ASCII_US) +
+ "\" into a double!").getStr());
+ aReturn <<= nValue;
+ }
+ break;
+ case TypeClass_STRING:
+ aReturn <<= _rReadCharacters;
+ break;
+ case TypeClass_STRUCT:
+ {
+ sal_Int32 nType = 0;
+ if ( _rExpectedType.equals( ::cppu::UnoType< css::util::Date >::get() ) )
+ nType = TYPE_DATE;
+ else if ( _rExpectedType.equals( ::cppu::UnoType< css::util::Time >::get() ) )
+ nType = TYPE_TIME;
+ else if ( _rExpectedType.equals( ::cppu::UnoType< css::util::DateTime >::get() ) )
+ nType = TYPE_DATETIME;
+
+ if ( nType )
+ {
+ // first extract the double
+ double nValue = 0;
+ bool bSuccess =
+ ::sax::Converter::convertDouble(nValue, _rReadCharacters);
+ OSL_ENSURE(bSuccess,
+ OStringBuffer("PropertyConversion::convertString: could not convert \"" +
+ OUStringToOString(_rReadCharacters, RTL_TEXTENCODING_ASCII_US) +
+ "\" into a double!").getStr());
+
+ // then convert it into the target type
+ switch (nType)
+ {
+ case TYPE_DATE:
+ {
+ OSL_ENSURE(std::modf(nValue, &o3tl::temporary(double())) == 0,
+ "PropertyConversion::convertString: a Date value with a fractional part?");
+ aReturn <<= lcl_getDate(nValue);
+ }
+ break;
+ case TYPE_TIME:
+ {
+ OSL_ENSURE((static_cast<sal_uInt32>(nValue)) == 0,
+ "PropertyConversion::convertString: a tools::Time value with more than a fractional part?");
+ aReturn <<= lcl_getTime(nValue);
+ }
+ break;
+ case TYPE_DATETIME:
+ {
+ css::util::Time aTime = lcl_getTime(nValue);
+ css::util::Date aDate = lcl_getDate(nValue);
+
+ css::util::DateTime aDateTime;
+ aDateTime.NanoSeconds = aTime.NanoSeconds;
+ aDateTime.Seconds = aTime.Seconds;
+ aDateTime.Minutes = aTime.Minutes;
+ aDateTime.Hours = aTime.Hours;
+ aDateTime.Day = aDate.Day;
+ aDateTime.Month = aDate.Month;
+ aDateTime.Year = aDate.Year;
+ aReturn <<= aDateTime;
+ }
+ break;
+ }
+ }
+ else
+ OSL_FAIL("PropertyConversion::convertString: unsupported property type!");
+ }
+ break;
+ default:
+ OSL_FAIL("PropertyConversion::convertString: invalid type class!");
+ }
+
+ return aReturn;
+}
+
+Type PropertyConversion::xmlTypeToUnoType( const OUString& _rType )
+{
+ Type aUnoType( cppu::UnoType<void>::get() );
+
+ static std::map< OUString, css::uno::Type > s_aTypeNameMap
+ {
+ { token::GetXMLToken( token::XML_BOOLEAN ) , cppu::UnoType<bool>::get()},
+ // Not a copy paste error, quotation from:
+ // http://nabble.documentfoundation.org/Question-unoType-for-getXmlToken-dbaccess-reportdesign-module-tp4109071p4109116.html
+ // all numeric types (including the UNO double)
+ // consistently map to XML_FLOAT, so taking the extra precision from the
+ // C++ type "float" to "double" makes absolute sense
+ { token::GetXMLToken( token::XML_FLOAT ) , ::cppu::UnoType<double>::get()},
+ { token::GetXMLToken( token::XML_STRING ) , ::cppu::UnoType<OUString>::get()},
+ { token::GetXMLToken( token::XML_VOID ) , cppu::UnoType<void>::get() },
+ };
+
+ const std::map< OUString, css::uno::Type >::iterator aTypePos = s_aTypeNameMap.find( _rType );
+ OSL_ENSURE( s_aTypeNameMap.end() != aTypePos, "PropertyConversion::xmlTypeToUnoType: invalid property name!" );
+ if ( s_aTypeNameMap.end() != aTypePos )
+ aUnoType = aTypePos->second;
+
+ return aUnoType;
+}
+
+//= OPropertyImport
+OPropertyImport::OPropertyImport(OFormLayerXMLImport_Impl& _rImport)
+ :SvXMLImportContext(_rImport.getGlobalContext())
+ ,m_rContext(_rImport)
+ ,m_bTrackAttributes(false)
+{
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > OPropertyImport::createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ )
+{
+ if( (nElement & TOKEN_MASK) == token::XML_PROPERTIES )
+ {
+ return new OPropertyElementsContext( m_rContext.getGlobalContext(), this);
+ }
+ else
+ SAL_WARN("xmloff", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement));
+ return nullptr;
+}
+
+void OPropertyImport::startFastElement(sal_Int32 /*nElement*/, const Reference< XFastAttributeList >& xAttrList)
+{
+
+ // assume the 'worst' case: all attributes describe properties. This should save our property array
+ // some reallocs
+ m_aValues.reserve(sax_fastparser::castToFastAttributeList(xAttrList).size());
+
+ for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
+ {
+ handleAttribute(aIter.getToken(), aIter.toString());
+
+ if (m_bTrackAttributes)
+ m_aEncounteredAttributes.insert(aIter.getToken() & TOKEN_MASK);
+ }
+
+ // TODO: create PropertyValues for all the attributes which were not present, because they were implied
+ // this is necessary as soon as we have properties where the XML default is different from the property
+ // default
+}
+
+bool OPropertyImport::encounteredAttribute(sal_Int32 nAttributeToken) const
+{
+ OSL_ENSURE(m_bTrackAttributes, "OPropertyImport::encounteredAttribute: attribute tracking not enabled!");
+ return m_aEncounteredAttributes.end() != m_aEncounteredAttributes.find(nAttributeToken & TOKEN_MASK);
+}
+
+void OPropertyImport::characters(const OUString& _rChars )
+{
+ // ignore them (should be whitespace only)
+ OSL_ENSURE(_rChars.trim().isEmpty(), "OPropertyImport::Characters: non-whitespace characters!");
+}
+
+bool OPropertyImport::handleAttribute(sal_Int32 nAttributeToken, const OUString& _rValue)
+{
+ const OAttribute2Property::AttributeAssignment* pProperty = m_rContext.getAttributeMap().getAttributeTranslation(nAttributeToken & TOKEN_MASK);
+ if (pProperty)
+ {
+ // create and store a new PropertyValue
+ PropertyValue aNewValue;
+ aNewValue.Name = pProperty->sPropertyName;
+
+ // convert the value string into the target type
+ if ((nAttributeToken & TOKEN_MASK) == token::XML_HREF)
+ {
+ aNewValue.Value <<= m_rContext.getGlobalContext().GetAbsoluteReference(_rValue);
+ }
+ else
+ {
+ aNewValue.Value = PropertyConversion::convertString(
+ pProperty->aPropertyType, _rValue, pProperty->pEnumMap,
+ pProperty->bInverseSemantics);
+ }
+ implPushBackPropertyValue( aNewValue );
+ return true;
+ }
+ if ((nAttributeToken & TOKEN_MASK) != token::XML_TYPE) // xlink:type is valid but ignored for <form:form>
+ {
+ SAL_WARN( "xmloff", "OPropertyImport::handleAttribute: Can't handle "
+ << SvXMLImport::getPrefixAndNameFromToken(nAttributeToken) << "=" << _rValue );
+ return false;
+ }
+ return true;
+}
+
+//= OPropertyElementsContext
+OPropertyElementsContext::OPropertyElementsContext(SvXMLImport& _rImport,
+ const OPropertyImportRef& _rPropertyImporter)
+ :SvXMLImportContext(_rImport)
+ ,m_xPropertyImporter(_rPropertyImporter)
+{
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > OPropertyElementsContext::createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& )
+{
+ if( (nElement & TOKEN_MASK) == XML_PROPERTY )
+ {
+ return new OSinglePropertyContext(GetImport(), m_xPropertyImporter);
+ }
+ else if( (nElement & TOKEN_MASK) == XML_LIST_PROPERTY )
+ {
+ return new OListPropertyContext( GetImport(), m_xPropertyImporter );
+ }
+ return nullptr;
+}
+
+#if OSL_DEBUG_LEVEL > 0
+ void OPropertyElementsContext::startFastElement(
+ sal_Int32 /*nElement*/,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+ {
+ OSL_ENSURE(0 == xAttrList->getFastAttributes().getLength(), "OPropertyElementsContext::StartElement: the form:properties element should not have attributes!");
+ }
+
+ void OPropertyElementsContext::characters(const OUString& _rChars)
+ {
+ OSL_ENSURE(_rChars.trim().isEmpty(), "OPropertyElementsContext::Characters: non-whitespace characters detected!");
+ }
+#endif
+
+//= OSinglePropertyContext
+OSinglePropertyContext::OSinglePropertyContext(SvXMLImport& _rImport,
+ const OPropertyImportRef& _rPropertyImporter)
+ :SvXMLImportContext(_rImport)
+ ,m_xPropertyImporter(_rPropertyImporter)
+{
+}
+
+void OSinglePropertyContext::startFastElement(
+ sal_Int32 /*nElement*/,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+{
+ css::beans::PropertyValue aPropValue; // the property the instance imports currently
+ css::uno::Type aPropType; // the type of the property the instance imports currently
+
+ OUString sType, sValue;
+ for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
+ {
+ switch (aIter.getToken())
+ {
+ case XML_ELEMENT(FORM, XML_PROPERTY_NAME):
+ aPropValue.Name = aIter.toString();
+ break;
+ case XML_ELEMENT(OFFICE, XML_VALUE_TYPE):
+ sType = aIter.toString();
+ break;
+ case XML_ELEMENT(OFFICE, XML_VALUE):
+ case XML_ELEMENT(OFFICE, XML_BOOLEAN_VALUE):
+ case XML_ELEMENT(OFFICE, XML_STRING_VALUE):
+ sValue = aIter.toString();
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("xmloff", aIter);
+ }
+ }
+
+ // the name of the property
+ OSL_ENSURE(!aPropValue.Name.isEmpty(), "OSinglePropertyContext::StartElement: invalid property name!");
+
+ // needs to be translated into a css::uno::Type
+ aPropType = PropertyConversion::xmlTypeToUnoType( sType );
+ if( TypeClass_VOID == aPropType.getTypeClass() )
+ {
+ aPropValue.Value = Any();
+ }
+ else
+ {
+ aPropValue.Value =
+ PropertyConversion::convertString(aPropType,
+ sValue);
+ }
+
+ // now that we finally have our property value, add it to our parent object
+ if( !aPropValue.Name.isEmpty() )
+ m_xPropertyImporter->implPushBackGenericPropertyValue(aPropValue);
+}
+
+//= OListPropertyContext
+OListPropertyContext::OListPropertyContext( SvXMLImport& _rImport,
+ const OPropertyImportRef& _rPropertyImporter )
+ :SvXMLImportContext( _rImport )
+ ,m_xPropertyImporter( _rPropertyImporter )
+{
+}
+
+void OListPropertyContext::startFastElement(
+ sal_Int32 /*nElement*/,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+{
+ for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
+ {
+ switch (aIter.getToken())
+ {
+ case XML_ELEMENT(FORM, XML_PROPERTY_NAME):
+ m_sPropertyName = aIter.toString();
+ break;
+ case XML_ELEMENT(OFFICE, XML_VALUE_TYPE):
+ m_sPropertyType = aIter.toString();
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("xmloff", aIter);
+ }
+ }
+}
+
+void OListPropertyContext::endFastElement(sal_Int32 )
+{
+ OSL_ENSURE( !m_sPropertyName.isEmpty() && !m_sPropertyType.isEmpty(),
+ "OListPropertyContext::EndElement: no property name or type!" );
+
+ if ( m_sPropertyName.isEmpty() || m_sPropertyType.isEmpty() )
+ return;
+
+ Sequence< Any > aListElements( m_aListValues.size() );
+ Any* pListElement = aListElements.getArray();
+ css::uno::Type aType = PropertyConversion::xmlTypeToUnoType( m_sPropertyType );
+ for ( const auto& rListValue : m_aListValues )
+ {
+ *pListElement = PropertyConversion::convertString( aType, rListValue );
+ ++pListElement;
+ }
+
+ PropertyValue aSequenceValue;
+ aSequenceValue.Name = m_sPropertyName;
+ aSequenceValue.Value <<= aListElements;
+
+ m_xPropertyImporter->implPushBackGenericPropertyValue( aSequenceValue );
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > OListPropertyContext::createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& )
+{
+ if ( (nElement & TOKEN_MASK) == XML_LIST_VALUE )
+ {
+ m_aListValues.emplace_back();
+ return new OListValueContext( GetImport(), *m_aListValues.rbegin() );
+ }
+ return nullptr;
+}
+
+//= OListValueContext
+OListValueContext::OListValueContext( SvXMLImport& _rImport, OUString& _rListValueHolder )
+ :SvXMLImportContext( _rImport )
+ ,m_rListValueHolder( _rListValueHolder )
+{
+}
+
+void OListValueContext::startFastElement(
+ sal_Int32 /*nElement*/,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+{
+ for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
+ {
+ switch(aIter.getToken())
+ {
+ case XML_ELEMENT(OFFICE, XML_VALUE):
+ case XML_ELEMENT(OFFICE, XML_STRING_VALUE):
+ case XML_ELEMENT(OFFICE, XML_BOOLEAN_VALUE):
+ m_rListValueHolder = aIter.toString();
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("xmloff", aIter);
+ }
+ }
+}
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/propertyimport.hxx b/xmloff/source/forms/propertyimport.hxx
new file mode 100644
index 000000000..b4b660d5b
--- /dev/null
+++ b/xmloff/source/forms/propertyimport.hxx
@@ -0,0 +1,226 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <o3tl/sorted_vector.hxx>
+
+#include <xmloff/xmlictxt.hxx>
+#include "formattributes.hxx"
+#include <rtl/ref.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include "layerimport.hxx"
+
+namespace com::sun::star::util {
+ struct Time;
+ struct Date;
+}
+
+namespace xmloff
+{
+
+ //= PropertyConversion
+ class PropertyConversion
+ {
+ public:
+ template<typename EnumT>
+ static css::uno::Any convertString(
+ const css::uno::Type& _rExpectedType,
+ const OUString& _rReadCharacters,
+ const SvXMLEnumMapEntry<EnumT>* _pEnumMap = nullptr
+ )
+ {
+ return convertString(_rExpectedType, _rReadCharacters,
+ reinterpret_cast<const SvXMLEnumMapEntry<sal_uInt16>*>(_pEnumMap), /*_bInvertBoolean*/false);
+ }
+ static css::uno::Any convertString(
+ const css::uno::Type& _rExpectedType,
+ const OUString& _rReadCharacters,
+ const SvXMLEnumMapEntry<sal_uInt16>* _pEnumMap = nullptr,
+ const bool _bInvertBoolean = false
+ );
+
+ static css::uno::Type xmlTypeToUnoType( const OUString& _rType );
+ };
+
+ class OFormLayerXMLImport_Impl;
+ //= OPropertyImport
+ /** Helper class for importing property values
+
+ <p>This class imports properties which are stored as attributes as well as properties which
+ are stored in </em>&lt;form:properties&gt;</em> elements.</p>
+ */
+ class OPropertyImport : public SvXMLImportContext
+ {
+ friend class OSinglePropertyContext;
+ friend class OListPropertyContext;
+
+ protected:
+ typedef ::std::vector< css::beans::PropertyValue > PropertyValueArray;
+ PropertyValueArray m_aValues;
+ PropertyValueArray m_aGenericValues;
+ // the values which the instance collects between StartElement and EndElement
+
+ o3tl::sorted_vector<sal_Int32> m_aEncounteredAttributes;
+
+ OFormLayerXMLImport_Impl& m_rContext;
+
+ bool m_bTrackAttributes;
+
+ // TODO: think about the restriction that the class does not know anything about the object it is importing.
+ // Perhaps this object should be known to the class, so setting the properties ('normal' ones as well as
+ // style properties) can be done in our own EndElement instead of letting derived classes do this.
+
+ public:
+ OPropertyImport(OFormLayerXMLImport_Impl& _rImport);
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+
+ virtual void SAL_CALL startFastElement(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) override;
+ virtual void SAL_CALL characters(const OUString& _rChars) override;
+
+ protected:
+ /** handle one single attribute.
+
+ <p>This is called for every attribute of the element. This class' implementation checks if the attribute
+ describes a property, if so, it is added to <member>m_aValues</member>.</p>
+
+ <p>All non-property attributes should be handled in derived classes.</p>
+
+ @param _nNamespaceKey
+ key of the namespace used in the attribute
+ @param _rLocalName
+ local (relative to the namespace) attribute name
+ @param _rValue
+ attribute value
+ */
+ virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue);
+
+ /** determine if the element imported by the object had a given attribute.
+ <p>Please be aware of the fact that the name given must be a local name, i.e. not contain a namespace.
+ All form relevant attributes are in the same namespace, so this would be a redundant information.</p>
+ */
+ bool encounteredAttribute(sal_Int32 nElement) const;
+
+ /** enables the tracking of the encountered attributes
+ <p>The tracking will raise the import costs a little bit, but it's cheaper than
+ derived classes tracking this themself.</p>
+ */
+ void enableTrackAttributes() { m_bTrackAttributes = true; }
+
+ void implPushBackPropertyValue(const css::beans::PropertyValue& _rProp)
+ {
+ m_aValues.push_back(_rProp);
+ }
+
+ void implPushBackPropertyValue( const OUString& _rName, const css::uno::Any& _rValue )
+ {
+ m_aValues.push_back( css::beans::PropertyValue(
+ _rName, -1, _rValue, css::beans::PropertyState_DIRECT_VALUE ) );
+ }
+
+ void implPushBackGenericPropertyValue(const css::beans::PropertyValue& _rProp)
+ {
+ m_aGenericValues.push_back(_rProp);
+ }
+ };
+ typedef rtl::Reference<OPropertyImport> OPropertyImportRef;
+
+ //= OPropertyElementsContext
+ /** helper class for importing the &lt;form:properties&gt; element
+ */
+ class OPropertyElementsContext : public SvXMLImportContext
+ {
+ OPropertyImportRef m_xPropertyImporter; // to add the properties
+
+ public:
+ OPropertyElementsContext(SvXMLImport& _rImport,
+ const OPropertyImportRef& _rPropertyImporter);
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+
+#if OSL_DEBUG_LEVEL > 0
+ virtual void SAL_CALL startFastElement(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
+ virtual void SAL_CALL characters(const OUString& _rChars) override;
+#endif
+ };
+
+ //= OSinglePropertyContext
+ /** helper class for importing a single &lt;form:property&gt; element
+ */
+ class OSinglePropertyContext : public SvXMLImportContext
+ {
+ OPropertyImportRef m_xPropertyImporter; // to add the properties
+
+ public:
+ OSinglePropertyContext(SvXMLImport& _rImport,
+ const OPropertyImportRef& _rPropertyImporter);
+
+ virtual void SAL_CALL startFastElement(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
+ };
+
+ //= OListPropertyContext
+ class OListPropertyContext : public SvXMLImportContext
+ {
+ OPropertyImportRef m_xPropertyImporter;
+ OUString m_sPropertyName;
+ OUString m_sPropertyType;
+ ::std::vector< OUString > m_aListValues;
+
+ public:
+ OListPropertyContext( SvXMLImport& _rImport,
+ const OPropertyImportRef& _rPropertyImporter );
+
+ virtual void SAL_CALL startFastElement(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
+
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+ };
+
+ //= OListValueContext
+ class OListValueContext : public SvXMLImportContext
+ {
+ OUString& m_rListValueHolder;
+
+ public:
+ OListValueContext( SvXMLImport& _rImport, OUString& _rListValueHolder );
+
+ virtual void SAL_CALL startFastElement(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
+ };
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/strings.hxx b/xmloff/source/forms/strings.hxx
new file mode 100644
index 000000000..f12067504
--- /dev/null
+++ b/xmloff/source/forms/strings.hxx
@@ -0,0 +1,209 @@
+/* -*- 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 xmloff
+{
+
+ // properties
+ #define PROPERTY_CLASSID "ClassId"
+ #define PROPERTY_ECHOCHAR "EchoChar"
+ #define PROPERTY_MULTILINE "MultiLine"
+ #define PROPERTY_NAME "Name"
+ #define PROPERTY_GRAPHIC "Graphic"
+ #define PROPERTY_LABEL "Label"
+ #define PROPERTY_TARGETFRAME "TargetFrame"
+ #define PROPERTY_TARGETURL "TargetURL"
+ #define PROPERTY_TITLE "Tag"
+ #define PROPERTY_DROPDOWN "Dropdown"
+ #define PROPERTY_PRINTABLE "Printable"
+ #define PROPERTY_READONLY "ReadOnly"
+ #define PROPERTY_DEFAULT_STATE "DefaultState"
+ #define PROPERTY_TABSTOP "Tabstop"
+ #define PROPERTY_STATE "State"
+ #define PROPERTY_ENABLED "Enabled"
+ #define PROPERTY_ENABLEVISIBLE "EnableVisible"
+ #define PROPERTY_MAXTEXTLENGTH "MaxTextLen"
+ #define PROPERTY_LINECOUNT "LineCount"
+ #define PROPERTY_TABINDEX "TabIndex"
+ #define PROPERTY_COMMAND "Command"
+ #define PROPERTY_DATASOURCENAME "DataSourceName"
+ #define PROPERTY_FILTER "Filter"
+ #define PROPERTY_ORDER "Order"
+ #define PROPERTY_ALLOWDELETES "AllowDeletes"
+ #define PROPERTY_ALLOWINSERTS "AllowInserts"
+ #define PROPERTY_ALLOWUPDATES "AllowUpdates"
+ #define PROPERTY_APPLYFILTER "ApplyFilter"
+ #define PROPERTY_ESCAPEPROCESSING "EscapeProcessing"
+ #define PROPERTY_IGNORERESULT "IgnoreResult"
+ #define PROPERTY_SUBMIT_ENCODING "SubmitEncoding"
+ #define PROPERTY_SUBMIT_METHOD "SubmitMethod"
+ #define PROPERTY_COMMAND_TYPE "CommandType"
+ #define PROPERTY_NAVIGATION "NavigationBarMode"
+ #define PROPERTY_CYCLE "Cycle"
+ #define PROPERTY_BUTTONTYPE "ButtonType"
+ #define PROPERTY_DATAFIELD "DataField"
+ #define PROPERTY_BOUNDCOLUMN "BoundColumn"
+ #define PROPERTY_EMPTY_IS_NULL "ConvertEmptyToNull"
+ #define PROPERTY_INPUT_REQUIRED "InputRequired"
+ #define PROPERTY_LISTSOURCE "ListSource"
+ #define PROPERTY_LISTSOURCETYPE "ListSourceType"
+ #define PROPERTY_ECHO_CHAR "EchoChar"
+ #define PROPERTY_STRICTFORMAT "StrictFormat"
+ #define PROPERTY_AUTOCOMPLETE "Autocomplete"
+ #define PROPERTY_MULTISELECTION "MultiSelection"
+ #define PROPERTY_DEFAULTBUTTON "DefaultButton"
+ #define PROPERTY_TRISTATE "TriState"
+ #define PROPERTY_CONTROLLABEL "LabelControl"
+ #define PROPERTY_STRING_ITEM_LIST "StringItemList"
+ #define PROPERTY_VALUE_SEQ "ValueItemList"
+ #define PROPERTY_DEFAULT_SELECT_SEQ "DefaultSelection"
+ #define PROPERTY_SELECT_SEQ "SelectedItems"
+ #define PROPERTY_DATE_MIN "DateMin"
+ #define PROPERTY_DATE_MAX "DateMax"
+ #define PROPERTY_TIME_MIN "TimeMin"
+ #define PROPERTY_TIME_MAX "TimeMax"
+ #define PROPERTY_VALUE_MIN "ValueMin"
+ #define PROPERTY_VALUE_MAX "ValueMax"
+ #define PROPERTY_EFFECTIVE_MIN "EffectiveMin"
+ #define PROPERTY_EFFECTIVE_MAX "EffectiveMax"
+ #define PROPERTY_DEFAULT_DATE "DefaultDate"
+ #define PROPERTY_DATE "Date"
+ #define PROPERTY_DEFAULT_TIME "DefaultTime"
+ #define PROPERTY_TIME "Time"
+ #define PROPERTY_DEFAULT_VALUE "DefaultValue"
+ #define PROPERTY_VALUE "Value"
+ #define PROPERTY_HIDDEN_VALUE "HiddenValue"
+ #define PROPERTY_DEFAULT_TEXT "DefaultText"
+ #define PROPERTY_TEXT "Text"
+ #define PROPERTY_EFFECTIVE_VALUE "EffectiveValue"
+ #define PROPERTY_EFFECTIVE_DEFAULT "EffectiveDefault"
+ #define PROPERTY_REFVALUE "RefValue"
+ #define PROPERTY_URL "URL"
+ #define PROPERTY_FONT "FontDescriptor"
+ #define PROPERTY_BACKGROUNDCOLOR "BackgroundColor"
+ #define PROPERTY_MASTERFIELDS "MasterFields"
+ #define PROPERTY_DETAILFIELDS "DetailFields"
+ #define PROPERTY_COLUMNSERVICENAME "ColumnServiceName"
+ #define PROPERTY_FORMATKEY "FormatKey"
+ #define PROPERTY_ALIGN "Align"
+ #define PROPERTY_BORDER "Border"
+ #define PROPERTY_AUTOCONTROLFOCUS "AutomaticControlFocus"
+ #define PROPERTY_APPLYDESIGNMODE "ApplyFormDesignMode"
+ #define PROPERTY_FORMATSSUPPLIER "FormatsSupplier"
+ #define PROPERTY_LOCALE "Locale"
+ #define PROPERTY_FORMATSTRING "FormatString"
+ #define PROPERTY_DATEFORMAT "DateFormat"
+ #define PROPERTY_TIMEFORMAT "TimeFormat"
+ #define PROPERTY_PERSISTENCE_MAXTEXTLENGTH "PersistenceMaxTextLength"
+ #define PROPERTY_SCROLLVALUE_MIN "ScrollValueMin"
+ #define PROPERTY_SCROLLVALUE_MAX "ScrollValueMax"
+ #define PROPERTY_SCROLLVALUE "ScrollValue"
+ #define PROPERTY_SCROLLVALUE_DEFAULT "DefaultScrollValue"
+ #define PROPERTY_LINE_INCREMENT "LineIncrement"
+ #define PROPERTY_BLOCK_INCREMENT "BlockIncrement"
+ #define PROPERTY_REPEAT_DELAY "RepeatDelay"
+ #define PROPERTY_SPINVALUE "SpinValue"
+ #define PROPERTY_SPINVALUE_MIN "SpinValueMin"
+ #define PROPERTY_SPINVALUE_MAX "SpinValueMax"
+ #define PROPERTY_DEFAULT_SPINVALUE "DefaultSpinValue"
+ #define PROPERTY_SPIN_INCREMENT "SpinIncrement"
+ #define PROPERTY_ORIENTATION "Orientation"
+ #define PROPERTY_TOGGLE "Toggle"
+ #define PROPERTY_FOCUS_ON_CLICK "FocusOnClick"
+ #define PROPERTY_VISUAL_EFFECT "VisualEffect"
+ #define PROPERTY_IMAGE_POSITION "ImagePosition"
+ #define PROPERTY_IMAGE_ALIGN "ImageAlign"
+ #define PROPERTY_SCALE_IMAGE "ScaleImage"
+ #define PROPERTY_GROUP_NAME "GroupName"
+
+ #define PROPERTY_BOUND_CELL "BoundCell"
+ #define PROPERTY_LIST_CELL_RANGE "CellRange"
+ #define PROPERTY_ADDRESS "Address"
+ #define PROPERTY_FILE_REPRESENTATION "PersistentRepresentation"
+ #define PROPERTY_RICH_TEXT "RichText"
+
+ // services
+ inline constexpr OUStringLiteral SERVICE_SPREADSHEET_DOCUMENT = u"com.sun.star.sheet.SpreadsheetDocument";
+ inline constexpr OUStringLiteral SERVICE_CELLVALUEBINDING = u"com.sun.star.table.CellValueBinding";
+ inline constexpr OUStringLiteral SERVICE_LISTINDEXCELLBINDING = u"com.sun.star.table.ListPositionCellBinding";
+ inline constexpr OUStringLiteral SERVICE_CELLRANGELISTSOURCE = 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";
+
+ // old service names (compatibility)
+ #define SERVICE_PERSISTENT_COMPONENT_FORM "stardiv.one.form.component.Form"
+ #define SERVICE_PERSISTENT_COMPONENT_EDIT "stardiv.one.form.component.Edit"
+ #define SERVICE_PERSISTENT_COMPONENT_LISTBOX "stardiv.one.form.component.ListBox"
+ #define SERVICE_PERSISTENT_COMPONENT_COMBOBOX "stardiv.one.form.component.ComboBox"
+ #define SERVICE_PERSISTENT_COMPONENT_RADIOBUTTON "stardiv.one.form.component.RadioButton"
+ #define SERVICE_PERSISTENT_COMPONENT_GROUPBOX "stardiv.one.form.component.GroupBox"
+ #define SERVICE_PERSISTENT_COMPONENT_FIXEDTEXT "stardiv.one.form.component.FixedText"
+ #define SERVICE_PERSISTENT_COMPONENT_COMMANDBUTTON "stardiv.one.form.component.CommandButton"
+ #define SERVICE_PERSISTENT_COMPONENT_CHECKBOX "stardiv.one.form.component.CheckBox"
+ #define SERVICE_PERSISTENT_COMPONENT_GRID "stardiv.one.form.component.Grid"
+ #define SERVICE_PERSISTENT_COMPONENT_IMAGEBUTTON "stardiv.one.form.component.ImageButton"
+ #define SERVICE_PERSISTENT_COMPONENT_FILECONTROL "stardiv.one.form.component.FileControl"
+ #define SERVICE_PERSISTENT_COMPONENT_TIMEFIELD "stardiv.one.form.component.TimeField"
+ #define SERVICE_PERSISTENT_COMPONENT_DATEFIELD "stardiv.one.form.component.DateField"
+ #define SERVICE_PERSISTENT_COMPONENT_NUMERICFIELD "stardiv.one.form.component.NumericField"
+ #define SERVICE_PERSISTENT_COMPONENT_CURRENCYFIELD "stardiv.one.form.component.CurrencyField"
+ #define SERVICE_PERSISTENT_COMPONENT_PATTERNFIELD "stardiv.one.form.component.PatternField"
+ #define SERVICE_PERSISTENT_COMPONENT_HIDDENCONTROL "stardiv.one.form.component.Hidden"
+ #define SERVICE_PERSISTENT_COMPONENT_IMAGECONTROL "stardiv.one.form.component.ImageControl"
+ #define SERVICE_PERSISTENT_COMPONENT_FORMATTEDFIELD "stardiv.one.form.component.FormattedField"
+
+ // new service names, the old ones are translated into this new ones
+ inline constexpr OUStringLiteral SERVICE_FORM = u"com.sun.star.form.component.Form";
+ inline constexpr OUStringLiteral SERVICE_EDIT = u"com.sun.star.form.component.TextField";
+ inline constexpr OUStringLiteral SERVICE_LISTBOX = u"com.sun.star.form.component.ListBox";
+ inline constexpr OUStringLiteral SERVICE_COMBOBOX = u"com.sun.star.form.component.ComboBox";
+ inline constexpr OUStringLiteral SERVICE_RADIOBUTTON = u"com.sun.star.form.component.RadioButton";
+ inline constexpr OUStringLiteral SERVICE_GROUPBOX = u"com.sun.star.form.component.GroupBox";
+ inline constexpr OUStringLiteral SERVICE_FIXEDTEXT = u"com.sun.star.form.component.FixedText";
+ inline constexpr OUStringLiteral SERVICE_COMMANDBUTTON = u"com.sun.star.form.component.CommandButton";
+ inline constexpr OUStringLiteral SERVICE_CHECKBOX = u"com.sun.star.form.component.CheckBox";
+ inline constexpr OUStringLiteral SERVICE_GRID = u"com.sun.star.form.component.GridControl";
+ inline constexpr OUStringLiteral SERVICE_IMAGEBUTTON = u"com.sun.star.form.component.ImageButton";
+ inline constexpr OUStringLiteral SERVICE_FILECONTROL = u"com.sun.star.form.component.FileControl";
+ inline constexpr OUStringLiteral SERVICE_TIMEFIELD = u"com.sun.star.form.component.TimeField";
+ inline constexpr OUStringLiteral SERVICE_DATEFIELD = u"com.sun.star.form.component.DateField";
+ inline constexpr OUStringLiteral SERVICE_NUMERICFIELD = u"com.sun.star.form.component.NumericField";
+ inline constexpr OUStringLiteral SERVICE_CURRENCYFIELD = u"com.sun.star.form.component.CurrencyField";
+ inline constexpr OUStringLiteral SERVICE_PATTERNFIELD = u"com.sun.star.form.component.PatternField";
+ inline constexpr OUStringLiteral SERVICE_HIDDENCONTROL = u"com.sun.star.form.component.HiddenControl";
+ inline constexpr OUStringLiteral SERVICE_IMAGECONTROL = u"com.sun.star.form.component.DatabaseImageControl";
+ inline constexpr OUStringLiteral SERVICE_FORMATTEDFIELD = u"com.sun.star.form.component.FormattedField";
+
+ // various strings
+ #define EVENT_NAME_SEPARATOR "::"
+ inline constexpr OUStringLiteral EVENT_TYPE = u"EventType";
+ inline constexpr OUStringLiteral EVENT_LIBRARY = u"Library";
+ inline constexpr OUStringLiteral EVENT_LOCALMACRONAME = u"MacroName";
+ inline constexpr OUStringLiteral EVENT_SCRIPTURL = u"Script";
+ inline constexpr OUStringLiteral EVENT_STAROFFICE = u"StarOffice";
+ #define EVENT_STARBASIC "StarBasic"
+ inline constexpr OUStringLiteral EVENT_APPLICATION = u"application";
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/valueproperties.cxx b/xmloff/source/forms/valueproperties.cxx
new file mode 100644
index 000000000..c2f60e5a2
--- /dev/null
+++ b/xmloff/source/forms/valueproperties.cxx
@@ -0,0 +1,180 @@
+/* -*- 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 "valueproperties.hxx"
+#include "strings.hxx"
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <sal/log.hxx>
+
+namespace xmloff
+{
+
+ using namespace ::com::sun::star::form;
+
+ //= OValuePropertiesMetaData
+ void OValuePropertiesMetaData::getValuePropertyNames(
+ OControlElement::ElementType _eType, sal_Int16 _nFormComponentType,
+ char const * & _rpCurrentValuePropertyName, char const * & _rpValuePropertyName)
+ {
+ // reset the pointers in case we can't determine the property names
+ _rpCurrentValuePropertyName = _rpValuePropertyName = nullptr;
+ switch (_nFormComponentType)
+ {
+ case FormComponentType::TEXTFIELD:
+ if (OControlElement::FORMATTED_TEXT == _eType)
+ {
+ _rpCurrentValuePropertyName = PROPERTY_EFFECTIVE_VALUE;
+ _rpValuePropertyName = PROPERTY_EFFECTIVE_DEFAULT;
+ }
+ else
+ {
+ if (OControlElement::PASSWORD != _eType)
+ // no CurrentValue" for passwords
+ _rpCurrentValuePropertyName = PROPERTY_TEXT;
+ _rpValuePropertyName = PROPERTY_DEFAULT_TEXT;
+ }
+ break;
+
+ case FormComponentType::NUMERICFIELD:
+ case FormComponentType::CURRENCYFIELD:
+ _rpCurrentValuePropertyName = PROPERTY_VALUE;
+ _rpValuePropertyName = PROPERTY_DEFAULT_VALUE;
+ break;
+
+ case FormComponentType::PATTERNFIELD:
+ case FormComponentType::FILECONTROL:
+ case FormComponentType::COMBOBOX:
+ _rpValuePropertyName = PROPERTY_DEFAULT_TEXT;
+ [[fallthrough]];
+ case FormComponentType::COMMANDBUTTON:
+ _rpCurrentValuePropertyName = PROPERTY_TEXT;
+ break;
+
+ case FormComponentType::CHECKBOX:
+ case FormComponentType::RADIOBUTTON:
+ _rpValuePropertyName = PROPERTY_REFVALUE;
+ break;
+
+ case FormComponentType::HIDDENCONTROL:
+ _rpValuePropertyName = PROPERTY_HIDDEN_VALUE;
+ break;
+
+ case FormComponentType::SCROLLBAR:
+ _rpCurrentValuePropertyName = PROPERTY_SCROLLVALUE;
+ _rpValuePropertyName = PROPERTY_SCROLLVALUE_DEFAULT;
+ break;
+
+ case FormComponentType::SPINBUTTON:
+ _rpCurrentValuePropertyName = PROPERTY_SPINVALUE;
+ _rpValuePropertyName = PROPERTY_DEFAULT_SPINVALUE;
+ break;
+
+ default:
+ SAL_WARN( "xmloff", "OValuePropertiesMetaData::getValuePropertyNames: unsupported component type!" );
+ break;
+ }
+ }
+
+ void OValuePropertiesMetaData::getValueLimitPropertyNames(sal_Int16 _nFormComponentType,
+ char const * & _rpMinValuePropertyName, char const * & _rpMaxValuePropertyName)
+ {
+ _rpMinValuePropertyName = _rpMaxValuePropertyName = nullptr;
+ switch (_nFormComponentType)
+ {
+ case FormComponentType::NUMERICFIELD:
+ case FormComponentType::CURRENCYFIELD:
+ _rpMinValuePropertyName = PROPERTY_VALUE_MIN;
+ _rpMaxValuePropertyName = PROPERTY_VALUE_MAX;
+ break;
+
+ case FormComponentType::TEXTFIELD:
+ _rpMinValuePropertyName = PROPERTY_EFFECTIVE_MIN;
+ _rpMaxValuePropertyName = PROPERTY_EFFECTIVE_MAX;
+ break;
+
+ case FormComponentType::SCROLLBAR:
+ _rpMinValuePropertyName = PROPERTY_SCROLLVALUE_MIN;
+ _rpMaxValuePropertyName = PROPERTY_SCROLLVALUE_MAX;
+ break;
+
+ case FormComponentType::SPINBUTTON:
+ _rpMinValuePropertyName = PROPERTY_SPINVALUE_MIN;
+ _rpMaxValuePropertyName = PROPERTY_SPINVALUE_MAX;
+ break;
+
+ default:
+ SAL_WARN("xmloff", "OValuePropertiesMetaData::getValueLimitPropertyNames: unsupported component type!" );
+ break;
+ }
+ }
+
+ void OValuePropertiesMetaData::getRuntimeValuePropertyNames(
+ OControlElement::ElementType _eType, sal_Int16 _nFormComponentType,
+ char const * & _rpValuePropertyName, char const * & _rpDefaultValuePropertyName )
+ {
+ // reset the pointers in case we can't determine the property names
+ _rpValuePropertyName = _rpDefaultValuePropertyName = nullptr;
+ switch (_nFormComponentType)
+ {
+ case FormComponentType::TEXTFIELD:
+ if (OControlElement::FORMATTED_TEXT == _eType)
+ {
+ _rpValuePropertyName = PROPERTY_EFFECTIVE_VALUE;
+ _rpDefaultValuePropertyName = PROPERTY_EFFECTIVE_DEFAULT;
+ }
+ else
+ {
+ _rpValuePropertyName = PROPERTY_TEXT;
+ _rpDefaultValuePropertyName = PROPERTY_DEFAULT_TEXT;
+ }
+ break;
+
+ case FormComponentType::DATEFIELD:
+ _rpValuePropertyName = PROPERTY_DATE;
+ _rpDefaultValuePropertyName = PROPERTY_DEFAULT_DATE;
+ break;
+
+ case FormComponentType::TIMEFIELD:
+ _rpValuePropertyName = PROPERTY_TIME;
+ _rpDefaultValuePropertyName = PROPERTY_DEFAULT_TIME;
+ break;
+
+ case FormComponentType::NUMERICFIELD:
+ case FormComponentType::CURRENCYFIELD:
+ case FormComponentType::PATTERNFIELD:
+ case FormComponentType::FILECONTROL:
+ case FormComponentType::COMBOBOX:
+ case FormComponentType::SCROLLBAR:
+ case FormComponentType::SPINBUTTON:
+ // For these types, the runtime properties are the same as the ones which in the XML
+ // stream are named "value properties"
+ getValuePropertyNames( _eType, _nFormComponentType, _rpValuePropertyName, _rpDefaultValuePropertyName );
+ break;
+
+ case FormComponentType::CHECKBOX:
+ case FormComponentType::RADIOBUTTON:
+ _rpValuePropertyName = PROPERTY_STATE;
+ _rpDefaultValuePropertyName = PROPERTY_DEFAULT_STATE;
+ break;
+ }
+ }
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/forms/valueproperties.hxx b/xmloff/source/forms/valueproperties.hxx
new file mode 100644
index 000000000..b22b57bb0
--- /dev/null
+++ b/xmloff/source/forms/valueproperties.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 "controlelement.hxx"
+
+namespace xmloff
+{
+
+ //= OValuePropertiesMetaData
+ class OValuePropertiesMetaData
+ {
+ protected:
+ OValuePropertiesMetaData() { }
+
+ public:
+ /** calculate the property names for the <em>current-value</em> and the <em>value</em> attribute.
+
+ <p>If controls of the given FormComponentType do not have any of the properties requested,
+ the respective out parameter will be set to NULL.</p>
+ */
+ static void getValuePropertyNames(
+ OControlElement::ElementType _eType,
+ sal_Int16 _nFormComponentType,
+ char const * & _rpCurrentValuePropertyName,
+ char const * & _rpValuePropertyName);
+
+ /** calculate the property names for the <em>min-value</em> and the <em>max-value</em> attribute.
+
+ <p>If controls of the given FormComponentType do not have any of the properties requested,
+ the respective out parameter will be set to NULL.</p>
+ */
+ static void getValueLimitPropertyNames(
+ sal_Int16 _nFormComponentType,
+ char const * & _rpMinValuePropertyName,
+ char const * & _rpMaxValuePropertyName);
+
+ /** calculate the names of the properties which, at runtime, are used for <em>value</em> and
+ <em>default value</em>.
+ */
+ static void getRuntimeValuePropertyNames(
+ OControlElement::ElementType _eType,
+ sal_Int16 _nFormComponentType,
+ char const * & _rpValuePropertyName,
+ char const * & _rpDefaultValuePropertyName);
+ };
+
+} // namespace xmloff
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */