diff options
Diffstat (limited to 'xmloff/source/xforms')
21 files changed, 2997 insertions, 0 deletions
diff --git a/xmloff/source/xforms/SchemaContext.cxx b/xmloff/source/xforms/SchemaContext.cxx new file mode 100644 index 0000000000..573805a251 --- /dev/null +++ b/xmloff/source/xforms/SchemaContext.cxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "SchemaContext.hxx" + +#include "SchemaSimpleTypeContext.hxx" + +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltkmap.hxx> +#include <xmloff/xmlimp.hxx> +#include <sal/log.hxx> + +#include <com/sun/star/xforms/XDataTypeRepository.hpp> + +using com::sun::star::uno::Reference; +using com::sun::star::xml::sax::XFastAttributeList; +using com::sun::star::xforms::XDataTypeRepository; +using namespace xmloff::token; + + +SchemaContext::SchemaContext( + SvXMLImport& rImport, + const Reference<XDataTypeRepository>& rRepository ) : + TokenContext( rImport ), + mxRepository( rRepository ) +{ +} + +void SchemaContext::HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & ) +{ +} + +SvXMLImportContext* SchemaContext::HandleChild( + sal_Int32 nElementToken, + const Reference<XFastAttributeList>& ) +{ + if ( nElementToken == XML_ELEMENT(XSD, XML_SIMPLETYPE) ) + return new SchemaSimpleTypeContext( GetImport(), mxRepository ); + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElementToken); + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/SchemaContext.hxx b/xmloff/source/xforms/SchemaContext.hxx new file mode 100644 index 0000000000..e6896e760c --- /dev/null +++ b/xmloff/source/xforms/SchemaContext.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "TokenContext.hxx" +#include <com/sun/star/uno/Reference.hxx> + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } + namespace xforms { class XDataTypeRepository; } +} + +class SvXMLImport; +class SvXMLImportContext; + +/** import the data type declarations from an xsd:schema element */ +class SchemaContext : public TokenContext +{ + css::uno::Reference<css::xforms::XDataTypeRepository> mxRepository; + +public: + SchemaContext( SvXMLImport& rImport, + const css::uno::Reference<css::xforms::XDataTypeRepository>& rRepository ); + + // implement TokenContext methods: + +protected: + virtual void HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) override; + + virtual SvXMLImportContext* HandleChild( + sal_Int32 nElementToken, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/SchemaRestrictionContext.cxx b/xmloff/source/xforms/SchemaRestrictionContext.cxx new file mode 100644 index 0000000000..0a1114f7d4 --- /dev/null +++ b/xmloff/source/xforms/SchemaRestrictionContext.cxx @@ -0,0 +1,336 @@ +/* -*- 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 "SchemaRestrictionContext.hxx" +#include "xformsapi.hxx" + +#include <utility> +#include <xmloff/xmltoken.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltkmap.hxx> +#include <xmloff/xmlimp.hxx> + +#include <sax/tools/converter.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/Duration.hpp> +#include <com/sun/star/xforms/XDataTypeRepository.hpp> +#include <com/sun/star/xsd/DataTypeClass.hpp> +#include <com/sun/star/xsd/WhiteSpaceTreatment.hpp> + +#include <o3tl/string_view.hxx> +#include <sal/log.hxx> +#include <comphelper/diagnose_ex.hxx> + + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Exception; +using com::sun::star::uno::Any; +using namespace com::sun::star; +using com::sun::star::util::Duration; +using com::sun::star::xml::sax::XFastAttributeList; +using com::sun::star::xforms::XDataTypeRepository; +using namespace xmloff::token; + + +SchemaRestrictionContext::SchemaRestrictionContext( + SvXMLImport& rImport, + Reference<css::xforms::XDataTypeRepository> const & rRepository, + OUString sTypeName ) : + TokenContext( rImport ), + mxRepository( rRepository ), + msTypeName(std::move( sTypeName )) +{ + SAL_WARN_IF( !mxRepository.is(), "xmloff", "need repository" ); +} + +void SchemaRestrictionContext::CreateDataType() +{ + // only do something if we don't have a data type already + if( mxDataType.is() ) + return; + + SAL_WARN_IF( msBaseName.isEmpty(), "xmloff", "no base name?" ); + SAL_WARN_IF( !mxRepository.is(), "xmloff", "no repository?" ); + + try + { + mxDataType = + mxRepository->cloneDataType( + xforms_getBasicTypeName( mxRepository, + GetImport().GetNamespaceMap(), + msBaseName ), + msTypeName ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff", "exception during type creation"); + } + SAL_WARN_IF( !mxDataType.is(), "xmloff", "can't create type" ); +} + +void SchemaRestrictionContext::HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken() & TOKEN_MASK) + { + case XML_BASE: + msBaseName = aIter.toString(); + break; + } +} + +typedef Any (*convert_t)( const OUString& ); + +static Any xforms_string( const OUString& rValue ) +{ + return Any( rValue ); +} + +static Any xforms_int32( const OUString& rValue ) +{ + sal_Int32 nValue; + bool bSuccess = ::sax::Converter::convertNumber( nValue, rValue ); + return bSuccess ? Any( nValue ) : Any(); +} + +static Any xforms_int16( const OUString& rValue ) +{ + sal_Int32 nValue; + bool bSuccess = ::sax::Converter::convertNumber( nValue, rValue ); + return bSuccess ? Any( static_cast<sal_Int16>( nValue ) ) : Any(); +} + +static Any xforms_whitespace( const OUString& rValue ) +{ + Any aValue; + if( IsXMLToken( rValue, XML_PRESERVE ) ) + aValue <<= css::xsd::WhiteSpaceTreatment::Preserve; + else if( IsXMLToken( rValue, XML_REPLACE ) ) + aValue <<= css::xsd::WhiteSpaceTreatment::Replace; + else if( IsXMLToken( rValue, XML_COLLAPSE ) ) + aValue <<= css::xsd::WhiteSpaceTreatment::Collapse; + return aValue; +} + +static Any xforms_double( const OUString& rValue ) +{ + double fValue; + bool bSuccess = ::sax::Converter::convertDouble( fValue, rValue ); + return bSuccess ? Any( fValue ) : Any(); +} + +static Any xforms_date( const OUString& rValue ) +{ + Any aAny; + + // parse ISO date + sal_Int32 nPos1 = rValue.indexOf( '-' ); + sal_Int32 nPos2 = rValue.indexOf( '-', nPos1 + 1 ); + if( nPos1 > 0 && nPos2 > 0 ) + { + util::Date aDate; + aDate.Year = static_cast<sal_uInt16>( + o3tl::toInt32(rValue.subView( 0, nPos1 )) ); + aDate.Month = static_cast<sal_uInt16>( + o3tl::toInt32(rValue.subView( nPos1 + 1, nPos2 - nPos1 - 1 )) ); + aDate.Day = static_cast<sal_uInt16>( + o3tl::toInt32(rValue.subView( nPos2 + 1 )) ); + aAny <<= aDate; + } + return aAny; +} + +static Any xforms_dateTime( const OUString& rValue ) +{ + util::DateTime aDateTime; + bool const bSuccess = ::sax::Converter::parseDateTime(aDateTime, rValue); + return bSuccess ? Any( aDateTime ) : Any(); +} + +static Any xforms_time( const OUString& rValue ) +{ + Any aAny; + Duration aDuration; + if (::sax::Converter::convertDuration( aDuration, rValue )) + { + css::util::Time aTime; + aTime.Hours = aDuration.Hours; + aTime.Minutes = aDuration.Minutes; + aTime.Seconds = aDuration.Seconds; + aTime.NanoSeconds = aDuration.NanoSeconds; + aAny <<= aTime; + } + return aAny; +} + + +SvXMLImportContext* SchemaRestrictionContext::HandleChild( + sal_Int32 nElementToken, + const Reference<XFastAttributeList>& xAttrList ) +{ + // find value + OUString sValue; + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( ( aIter.getToken() & TOKEN_MASK) == XML_VALUE ) + { + sValue = aIter.toString(); + break; + } + } + + // determine property name + suitable converter + OUString sPropertyName; + convert_t pConvert = nullptr; + switch( nElementToken & TOKEN_MASK ) + { + case XML_LENGTH: + sPropertyName = "Length"; + pConvert = &xforms_int32; + break; + case XML_MINLENGTH: + sPropertyName = "MinLength"; + pConvert = &xforms_int32; + break; + case XML_MAXLENGTH: + sPropertyName = "MaxLength"; + pConvert = &xforms_int32; + break; + case XML_TOTALDIGITS: + sPropertyName = "TotalDigits"; + pConvert = &xforms_int32; + break; + case XML_FRACTIONDIGITS: + sPropertyName = "FractionDigits"; + pConvert = &xforms_int32; + break; + case XML_PATTERN: + sPropertyName = "Pattern"; + pConvert = &xforms_string; + break; + case XML_WHITESPACE: + sPropertyName = "WhiteSpace"; + pConvert = &xforms_whitespace; + break; + case XML_MININCLUSIVE: + case XML_MINEXCLUSIVE: + case XML_MAXINCLUSIVE: + case XML_MAXEXCLUSIVE: + { + // these attributes are mapped to different properties. + // To determine the property name, we use an attribute + // dependent prefix and a type dependent suffix. The + // converter is only type dependent. + + // first, attribute-dependent prefix + switch( nElementToken & TOKEN_MASK ) + { + case XML_MININCLUSIVE: + sPropertyName = "MinInclusive"; + break; + case XML_MINEXCLUSIVE: + sPropertyName = "MinExclusive"; + break; + case XML_MAXINCLUSIVE: + sPropertyName = "MaxInclusive"; + break; + case XML_MAXEXCLUSIVE: + sPropertyName = "MaxExclusive"; + break; + } + + // second, type-dependent suffix + converter + switch( xforms_getTypeClass( mxRepository, + GetImport().GetNamespaceMap(), + msBaseName ) ) + { + case css::xsd::DataTypeClass::DECIMAL: + case css::xsd::DataTypeClass::DOUBLE: + case css::xsd::DataTypeClass::FLOAT: + sPropertyName += "Double"; + pConvert = &xforms_double; + break; + case css::xsd::DataTypeClass::DATETIME: + sPropertyName += "DateTime"; + pConvert = &xforms_dateTime; + break; + case css::xsd::DataTypeClass::DATE: + sPropertyName += "Date"; + pConvert = &xforms_date; + break; + case css::xsd::DataTypeClass::TIME: + sPropertyName += "Time"; + pConvert = &xforms_time; + break; + case css::xsd::DataTypeClass::gYear: + case css::xsd::DataTypeClass::gDay: + case css::xsd::DataTypeClass::gMonth: + sPropertyName += "Int"; + pConvert = &xforms_int16; + break; + + case css::xsd::DataTypeClass::STRING: + case css::xsd::DataTypeClass::anyURI: + case css::xsd::DataTypeClass::BOOLEAN: + // invalid: These shouldn't have min/max-inclusive + break; + + /* data types not yet supported: + case css::xsd::DataTypeClass::DURATION: + case css::xsd::DataTypeClass::gYearMonth: + case css::xsd::DataTypeClass::gMonthDay: + case css::xsd::DataTypeClass::hexBinary: + case css::xsd::DataTypeClass::base64Binary: + case css::xsd::DataTypeClass::QName: + case css::xsd::DataTypeClass::NOTATION: + */ + } + } + break; + + default: + OSL_FAIL( "unknown facet" ); + } + + // finally, set the property + CreateDataType(); + if( mxDataType.is() + && !sPropertyName.isEmpty() + && pConvert != nullptr + && mxDataType->getPropertySetInfo()->hasPropertyByName(sPropertyName) ) + { + try + { + mxDataType->setPropertyValue( sPropertyName, pConvert( sValue ) ); + } + catch( const Exception& ) + { + ; // can't set property? Then ignore. + } + } + + return new SvXMLImportContext( GetImport() ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/SchemaRestrictionContext.hxx b/xmloff/source/xforms/SchemaRestrictionContext.hxx new file mode 100644 index 0000000000..66a5eb5250 --- /dev/null +++ b/xmloff/source/xforms/SchemaRestrictionContext.hxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "TokenContext.hxx" +#include <com/sun/star/uno/Reference.hxx> + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } + namespace xforms { class XDataTypeRepository; } +} + +class SvXMLImport; +class SvXMLImportContext; + +/** import the xsd:restriction element */ +class SchemaRestrictionContext : public TokenContext +{ + css::uno::Reference<css::xforms::XDataTypeRepository> mxRepository; + css::uno::Reference<css::beans::XPropertySet> mxDataType; + OUString const msTypeName; + OUString msBaseName; + +public: + SchemaRestrictionContext( SvXMLImport& rImport, + css::uno::Reference<css::xforms::XDataTypeRepository> const & rRepository, + OUString sTypeName ); + +private: + // create mxDataType (if not already present) + void CreateDataType(); + + // implement TokenContext methods: + + virtual void HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) override; + + virtual SvXMLImportContext* HandleChild( + sal_Int32 nElementToken, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/SchemaSimpleTypeContext.cxx b/xmloff/source/xforms/SchemaSimpleTypeContext.cxx new file mode 100644 index 0000000000..cd24519309 --- /dev/null +++ b/xmloff/source/xforms/SchemaSimpleTypeContext.cxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "SchemaSimpleTypeContext.hxx" + +#include "SchemaRestrictionContext.hxx" +#include <xmloff/xmltoken.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltkmap.hxx> +#include <xmloff/xmlimp.hxx> + +#include <osl/diagnose.h> +#include <sal/log.hxx> + +using com::sun::star::uno::Reference; +using com::sun::star::xml::sax::XFastAttributeList; +using com::sun::star::xforms::XDataTypeRepository; +using namespace xmloff::token; + + +SchemaSimpleTypeContext::SchemaSimpleTypeContext( + SvXMLImport& rImport, + const Reference<XDataTypeRepository>& rRepository ) : + TokenContext( rImport ), + mxRepository( rRepository ) +{ +} + +void SchemaSimpleTypeContext::HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken() & TOKEN_MASK) + { + case XML_NAME: + msTypeName = aIter.toString(); + break; + } +} + +SvXMLImportContext* SchemaSimpleTypeContext::HandleChild( + sal_Int32 nElementToken, + const Reference<XFastAttributeList>& ) +{ + switch( nElementToken ) + { + case XML_ELEMENT(XSD, XML_RESTRICTION): + return new SchemaRestrictionContext( GetImport(), + mxRepository, msTypeName ); + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElementToken); + } + + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/SchemaSimpleTypeContext.hxx b/xmloff/source/xforms/SchemaSimpleTypeContext.hxx new file mode 100644 index 0000000000..3489e2a6c7 --- /dev/null +++ b/xmloff/source/xforms/SchemaSimpleTypeContext.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 "TokenContext.hxx" +#include <com/sun/star/uno/Reference.hxx> + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } + namespace xforms { class XDataTypeRepository; } +} + +class SvXMLImport; +class SvXMLImportContext; + +/** import the xsd:simpleType element */ +class SchemaSimpleTypeContext : public TokenContext +{ + css::uno::Reference<css::xforms::XDataTypeRepository> mxRepository; + OUString msTypeName; + +public: + SchemaSimpleTypeContext( SvXMLImport& rImport, + const css::uno::Reference<css::xforms::XDataTypeRepository>& rRepository ); + + // implement TokenContext methods: + +protected: + virtual void HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) override; + + virtual SvXMLImportContext* HandleChild( + sal_Int32 nElementToken, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/TokenContext.cxx b/xmloff/source/xforms/TokenContext.cxx new file mode 100644 index 0000000000..928ea87889 --- /dev/null +++ b/xmloff/source/xforms/TokenContext.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 <sal/log.hxx> + +#include "TokenContext.hxx" +#include <xmloff/xmltkmap.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlerror.hxx> + +#include <algorithm> + +using com::sun::star::uno::Reference; + +TokenContext::TokenContext( SvXMLImport& rImport ) + : SvXMLImportContext( rImport ) +{ +} + +void TokenContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // iterate over attributes + // - if in map: call HandleAttribute + // - xmlns:... : ignore + // - other: warning + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + HandleAttribute( aIter ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > TokenContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // call handle child, and pass down arguments + SvXMLImportContext* pContext = HandleChild( nElement, xAttrList ); + // error handling: create default context and generate warning + if( pContext == nullptr ) + { + GetImport().SetError( XMLERROR_UNKNOWN_ELEMENT, SvXMLImport::getNameFromToken( nElement ) ); + } + return pContext; +} + + css::uno::Reference< css::xml::sax::XFastContextHandler > TokenContext::createUnknownChildContext( + const OUString& Namespace, const OUString& Name, const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + GetImport().SetError( XMLERROR_UNKNOWN_ELEMENT, Namespace + " " + Name ); + return nullptr; +} + +static bool lcl_IsWhiteSpace( sal_Unicode c ) +{ + return c == ' ' + || c == u'\x0009' + || c == u'\x000A' + || c == u'\x000D'; +} + +void TokenContext::characters( const OUString& rCharacters ) +{ + // get iterators for string data + const sal_Unicode* pBegin = rCharacters.getStr(); + const sal_Unicode* pEnd = &( pBegin[ rCharacters.getLength() ] ); + + // raise error if non-whitespace character is found + if( !::std::all_of( pBegin, pEnd, lcl_IsWhiteSpace ) ) + GetImport().SetError( XMLERROR_UNKNOWN_CHARACTERS, rCharacters ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/TokenContext.hxx b/xmloff/source/xforms/TokenContext.hxx new file mode 100644 index 0000000000..84ed18ab53 --- /dev/null +++ b/xmloff/source/xforms/TokenContext.hxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmltkmap.hxx> + +namespace com::sun::star { + namespace xml::sax { class XFastAttributeList; } + namespace uno { template<typename T> class Reference; } +} + +class SvXMLImport; + +/** handle attributes through an SvXMLTokenMap */ +class TokenContext : public SvXMLImportContext +{ +public: + TokenContext( SvXMLImport& rImport ); + + // implement SvXMLImportContext methods: + + /** call HandleAttribute for each attribute in the token map; + * create a warning for all others. Classes that wish to override + * StartElement need to call the parent method. */ + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + /** call HandleChild for each child element in the token map; + * create a warning for all others. Classes that wish to override + * CreateChildContext may want to call the parent method for + * handling of defaults. */ + 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 css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createUnknownChildContext( + const OUString& Namespace, const OUString& Name, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override; + + /** Create a warning for all non-namespace character + * content. Classes that wish to deal with character content have + * to override this method anyway, and will thus get rid of the + * warnings. */ + virtual void SAL_CALL characters( const OUString& rChars ) override; + +protected: + /** will be called for each attribute */ + virtual void HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) = 0; + + /** will be called for each child element */ + virtual SvXMLImportContext* HandleChild( + sal_Int32 nElementToken, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList ) = 0; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsBindContext.cxx b/xmloff/source/xforms/XFormsBindContext.cxx new file mode 100644 index 0000000000..9c799d53f3 --- /dev/null +++ b/xmloff/source/xforms/XFormsBindContext.cxx @@ -0,0 +1,155 @@ +/* -*- 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 "XFormsBindContext.hxx" + +#include "xformsapi.hxx" + +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlerror.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmltkmap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> + +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/xforms/XModel2.hpp> + +#include <osl/diagnose.h> +#include <sal/log.hxx> + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Any; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::container::XNameContainer; +using com::sun::star::xml::sax::XFastAttributeList; +using com::sun::star::xforms::XModel2; +using namespace xmloff::token; + +// helper function; see below +static void lcl_fillNamespaceContainer( const SvXMLNamespaceMap&, + Reference<XNameContainer> const & ); + +XFormsBindContext::XFormsBindContext( + SvXMLImport& rImport, + const Reference<XModel2>& xModel ) : + TokenContext( rImport ), + mxModel( xModel ) +{ + // attach binding to model + mxBinding = mxModel->createBinding(); + SAL_WARN_IF( !mxBinding.is(), "xmloff", "can't create binding" ); + mxModel->getBindings()->insert( Any( mxBinding ) ); +} + +void XFormsBindContext::HandleAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() & TOKEN_MASK ) + { + case XML_NODESET: + xforms_setValue( mxBinding, "BindingExpression", aIter.toString() ); + break; + case XML_ID: + xforms_setValue( mxBinding, "BindingID", aIter.toString() ); + break; + case XML_READONLY: + xforms_setValue( mxBinding, "ReadonlyExpression", aIter.toString() ); + break; + case XML_RELEVANT: + xforms_setValue( mxBinding, "RelevantExpression", aIter.toString() ); + break; + case XML_REQUIRED: + xforms_setValue( mxBinding, "RequiredExpression", aIter.toString() ); + break; + case XML_CONSTRAINT: + xforms_setValue( mxBinding, "ConstraintExpression", aIter.toString() ); + break; + case XML_CALCULATE: + xforms_setValue( mxBinding, "CalculateExpression", aIter.toString() ); + break; + case XML_TYPE: + xforms_setValue( mxBinding, "Type", + xforms_getTypeName( mxModel->getDataTypeRepository(), + GetImport().GetNamespaceMap(), + aIter.toString() ) ); + break; + default: + assert( false && "should not happen" ); + break; + } +} + +void XFormsBindContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // we need to register the namespaces + Reference<XNameContainer> xContainer( + mxBinding->getPropertyValue( "BindingNamespaces" ), + UNO_QUERY ); + + SAL_WARN_IF( !xContainer.is(), "xmloff", "binding should have a namespace container" ); + if( xContainer.is() ) + lcl_fillNamespaceContainer( GetImport().GetNamespaceMap(), xContainer); + + // call super-class for attribute handling + TokenContext::startFastElement( nElement, xAttrList ); +} + +/** will be called for each child element */ +SvXMLImportContext* XFormsBindContext::HandleChild( + sal_Int32, + const Reference<XFastAttributeList>& ) +{ + assert( false && "no children supported" ); + return nullptr; +} + + +static void lcl_fillNamespaceContainer( + const SvXMLNamespaceMap& aMap, + Reference<XNameContainer> const & xContainer ) +{ + sal_uInt16 nKeyIter = aMap.GetFirstKey(); + do + { + // get prefix and namespace + const OUString& sPrefix = aMap.GetPrefixByKey( nKeyIter ); + const OUString& sNamespace = aMap.GetNameByKey( nKeyIter ); + + // as a hack, we will ignore our own 'default' namespaces + SAL_WARN_IF( sPrefix.isEmpty(), "xmloff", "no prefix?" ); + if( !sPrefix.startsWith("_") && + nKeyIter >= XML_NAMESPACE_META_SO52) + { + // insert prefix (use replace if already known) + if( xContainer->hasByName( sPrefix ) ) + xContainer->replaceByName( sPrefix, Any( sNamespace ) ); + else + xContainer->insertByName( sPrefix, Any( sNamespace ) ); + } + + // proceed to next + nKeyIter = aMap.GetNextKey( nKeyIter ); + } + while( nKeyIter != XML_NAMESPACE_UNKNOWN ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsBindContext.hxx b/xmloff/source/xforms/XFormsBindContext.hxx new file mode 100644 index 0000000000..5aa7846740 --- /dev/null +++ b/xmloff/source/xforms/XFormsBindContext.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 "TokenContext.hxx" +#include <com/sun/star/uno/Reference.hxx> + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } + namespace xforms { class XModel2; } +} + +class SvXMLImport; +class SvXMLImportContext; + +/** import the xforms:binding element */ +class XFormsBindContext : public TokenContext +{ + const css::uno::Reference<css::xforms::XModel2> mxModel; + css::uno::Reference<css::beans::XPropertySet> mxBinding; + +public: + XFormsBindContext( SvXMLImport& rImport, + const css::uno::Reference<css::xforms::XModel2>& xModel ); + + // implement SvXMLImportContext & TokenContext methods: + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + +protected: + virtual void HandleAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) override; + + virtual SvXMLImportContext* HandleChild( + sal_Int32 nElementToken, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList ) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsInstanceContext.cxx b/xmloff/source/xforms/XFormsInstanceContext.cxx new file mode 100644 index 0000000000..e6e6ec2a2f --- /dev/null +++ b/xmloff/source/xforms/XFormsInstanceContext.cxx @@ -0,0 +1,161 @@ +/* -*- 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 "XFormsInstanceContext.hxx" + +#include <DomBuilderContext.hxx> + +#include <rtl/ustring.hxx> +#include <sal/log.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/xml/dom/XDocument.hpp> +#include <com/sun/star/xforms/XModel2.hpp> +#include <osl/diagnose.h> + +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlerror.hxx> +#include <xmloff/namespacemap.hxx> + + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Any; +using com::sun::star::uno::Sequence; +using com::sun::star::xforms::XModel2; +using com::sun::star::beans::PropertyValue; + +using xmloff::token::XML_SRC; +using xmloff::token::XML_ID; + +XFormsInstanceContext::XFormsInstanceContext( + SvXMLImport& rImport, + const Reference<XModel2> & xModel ) : + TokenContext( rImport ), + mxModel( xModel ) +{ + SAL_WARN_IF( !mxModel.is(), "xmloff", "need model" ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XFormsInstanceContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + + // only the first element child of an xforms:instance element + // is used as an instance. The other children remainder must be + // ignored. + if( mxInstance.is() ) + { + const OUString& rLocalName = SvXMLImport::getNameFromToken( nElement ); + GetImport().SetError( XMLERROR_XFORMS_ONLY_ONE_INSTANCE_ELEMENT, rLocalName ); + } + else + { + // create new DomBuilderContext. Save reference to tree in Model. + DomBuilderContext* pInstance = new DomBuilderContext( GetImport(), nElement ); + mxInstance = pInstance->getTree(); + pContext = pInstance; + } + + SAL_WARN_IF( pContext == nullptr, "xmloff", "no context!" ); + return pContext; + +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XFormsInstanceContext::createUnknownChildContext( + const OUString & rNamespace, const OUString &rName, const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*Attribs*/) +{ + SvXMLImportContext* pContext = nullptr; + + // only the first element child of an xforms:instance element + // is used as an instance. The other children remainder must be + // ignored. + if( mxInstance.is() ) + { + GetImport().SetError( XMLERROR_XFORMS_ONLY_ONE_INSTANCE_ELEMENT, rName ); + } + else + { + // create new DomBuilderContext. Save reference to tree in Model. + DomBuilderContext* pInstance = new DomBuilderContext( GetImport(), rNamespace, rName ); + mxInstance = pInstance->getTree(); + pContext = pInstance; + } + + SAL_WARN_IF( pContext == nullptr, "xmloff", "no context!" ); + return pContext; + +} + +void XFormsInstanceContext::endFastElement(sal_Int32 ) +{ + Sequence<PropertyValue> aSequence( 3 ); + PropertyValue* pSequence = aSequence.getArray(); + pSequence[0].Name = "Instance"; + pSequence[0].Value <<= mxInstance; + pSequence[1].Name = "ID"; + pSequence[1].Value <<= msId; + pSequence[2].Name = "URL"; + pSequence[2].Value <<= msURL; + + mxModel->getInstances()->insert( Any( aSequence ) ); +} + +void XFormsInstanceContext::endUnknownElement(const OUString & /*Namespace*/, const OUString & /*Name*/) +{ + Sequence<PropertyValue> aSequence( 3 ); + PropertyValue* pSequence = aSequence.getArray(); + pSequence[0].Name = "Instance"; + pSequence[0].Value <<= mxInstance; + pSequence[1].Name = "ID"; + pSequence[1].Value <<= msId; + pSequence[2].Name = "URL"; + pSequence[2].Value <<= msURL; + + mxModel->getInstances()->insert( Any( aSequence ) ); +} + +void XFormsInstanceContext::HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() & TOKEN_MASK ) + { + case XML_SRC: + msURL = aIter.toString(); + break; + case XML_ID: + msId = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + assert( false && "this should not happen" ); + break; + } +} + +SvXMLImportContext* XFormsInstanceContext::HandleChild( + sal_Int32, + const Reference<css::xml::sax::XFastAttributeList>& ) +{ + assert( false && "to be handled by CreateChildContext" ); + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsInstanceContext.hxx b/xmloff/source/xforms/XFormsInstanceContext.hxx new file mode 100644 index 0000000000..7583c2da3b --- /dev/null +++ b/xmloff/source/xforms/XFormsInstanceContext.hxx @@ -0,0 +1,69 @@ +/* -*- 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 "TokenContext.hxx" +#include <com/sun/star/uno/Reference.hxx> + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace xml::dom { class XDocument; } + namespace beans { class XPropertySet; } + namespace xforms { class XModel2; } +} + +class SvXMLImport; +class SvXMLImportContext; + +/** import the xforms:instance element */ +class XFormsInstanceContext : public TokenContext +{ + css::uno::Reference<css::xforms::XModel2> mxModel; + css::uno::Reference<css::xml::dom::XDocument> mxInstance; + OUString msId; + OUString msURL; + +public: + XFormsInstanceContext( SvXMLImport& rImport, + const css::uno::Reference<css::xforms::XModel2> & xModel ); + + // implement SvXMLImportContext & TokenContext methods: + // We override CreateChildContext, because we want to read + // arbitrary DOM elements. For the attributes, we use the + // TokenContext mechanism. + + 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 css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createUnknownChildContext( + const OUString& Namespace, const OUString& Name, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual void SAL_CALL endUnknownElement(const OUString & Namespace, const OUString & Name) override; + +protected: + virtual void HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) override; + + virtual SvXMLImportContext* HandleChild( + sal_Int32 nElementToken, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsModelContext.cxx b/xmloff/source/xforms/XFormsModelContext.cxx new file mode 100644 index 0000000000..479909fb54 --- /dev/null +++ b/xmloff/source/xforms/XFormsModelContext.cxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "XFormsModelContext.hxx" + +#include "XFormsBindContext.hxx" +#include "XFormsSubmissionContext.hxx" +#include "XFormsInstanceContext.hxx" +#include "SchemaContext.hxx" +#include "xformsapi.hxx" + +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlerror.hxx> + +#include <osl/diagnose.h> +#include <sal/log.hxx> + +#include <com/sun/star/util/XUpdatable.hpp> +#include <com/sun/star/xforms/XModel2.hpp> + + +using com::sun::star::util::XUpdatable; +using namespace com::sun::star::uno; +using namespace xmloff::token; + + +XFormsModelContext::XFormsModelContext( SvXMLImport& rImport ) : + TokenContext( rImport ), + mxModel( xforms_createXFormsModel() ) +{ +} + +void XFormsModelContext::HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() & TOKEN_MASK) + { + case XML_ID: + mxModel->setPropertyValue( "ID", Any( aIter.toString() ) ); + break; + case XML_SCHEMA: + GetImport().SetError( XMLERROR_XFORMS_NO_SCHEMA_SUPPORT ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + assert( false && "this should not happen" ); + break; + } +} + +SvXMLImportContext* XFormsModelContext::HandleChild( + sal_Int32 nElementToken, + const Reference<css::xml::sax::XFastAttributeList>& ) +{ + SvXMLImportContext* pContext = nullptr; + + switch( nElementToken ) + { + case XML_ELEMENT(XFORMS, XML_INSTANCE): + pContext = new XFormsInstanceContext( GetImport(), mxModel ); + break; + case XML_ELEMENT(XFORMS, XML_BIND): + pContext = new XFormsBindContext( GetImport(), mxModel ); + break; + case XML_ELEMENT(XFORMS, XML_SUBMISSION): + pContext = new XFormsSubmissionContext( GetImport(), mxModel ); + break; + case XML_ELEMENT(XSD, XML_SCHEMA): + pContext = new SchemaContext( GetImport(), mxModel->getDataTypeRepository() ); + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElementToken); + assert( false && "Boooo!" ); + break; + } + + return pContext; +} + +void XFormsModelContext::endFastElement(sal_Int32 ) +{ + // update before putting model into document + Reference<XUpdatable> xUpdate( mxModel, UNO_QUERY ); + if( xUpdate.is() ) + xUpdate->update(); + + GetImport().initXForms(); + xforms_addXFormsModel( GetImport().GetModel(), mxModel ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsModelContext.hxx b/xmloff/source/xforms/XFormsModelContext.hxx new file mode 100644 index 0000000000..0579850dfc --- /dev/null +++ b/xmloff/source/xforms/XFormsModelContext.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 "TokenContext.hxx" +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/xforms/XModel2.hpp> + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + +class SvXMLImport; +class SvXMLImportContext; + +/** import the xforms:model element */ +class XFormsModelContext : public TokenContext +{ + css::uno::Reference<css::xforms::XModel2> mxModel; + +public: + XFormsModelContext( SvXMLImport& rImport ); + + // implement SvXMLImportContext & TokenContext methods: + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + +protected: + virtual void HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) override; + + virtual SvXMLImportContext* HandleChild( + sal_Int32 nElementToken, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsModelExport.hxx b/xmloff/source/xforms/XFormsModelExport.hxx new file mode 100644 index 0000000000..03d83e97c9 --- /dev/null +++ b/xmloff/source/xforms/XFormsModelExport.hxx @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/types.h> + +class SvXMLExport; +namespace com::sun::star { + namespace uno { template<typename T> class Reference; } + namespace beans { class XPropertySet; } +} + +void exportXFormsModel( SvXMLExport&, + const css::uno::Reference<css::beans::XPropertySet>& ); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsSubmissionContext.cxx b/xmloff/source/xforms/XFormsSubmissionContext.cxx new file mode 100644 index 0000000000..4936976582 --- /dev/null +++ b/xmloff/source/xforms/XFormsSubmissionContext.cxx @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "XFormsSubmissionContext.hxx" + +#include "xformsapi.hxx" + +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmltkmap.hxx> +#include <xmloff/namespacemap.hxx> + +#include <sax/tools/converter.hxx> + +#include <com/sun/star/xforms/XModel2.hpp> + +#include <osl/diagnose.h> +#include <sal/log.hxx> + +using com::sun::star::xforms::XModel2; + +using namespace com::sun::star::uno; +using namespace xmloff::token; + + +XFormsSubmissionContext::XFormsSubmissionContext( + SvXMLImport& rImport, + const Reference<XModel2>& xModel ) : + TokenContext( rImport ) +{ + // register submission with model + SAL_WARN_IF( !xModel.is(), "xmloff", "need model" ); + mxSubmission = xModel->createSubmission().get(); + SAL_WARN_IF( !mxSubmission.is(), "xmloff", "can't create submission" ); + xModel->getSubmissions()->insert( Any( mxSubmission ) ); +} + +namespace { + +Any toBool( std::string_view rValue ) +{ + Any aValue; + bool bValue(false); + if (::sax::Converter::convertBool( bValue, rValue )) + { + aValue <<= bValue; + } + return aValue; +} + +} // namespace + +void XFormsSubmissionContext::HandleAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() & TOKEN_MASK ) + { + case XML_ID: + xforms_setValue( mxSubmission, "ID", aIter.toString() ); + break; + case XML_BIND: + xforms_setValue( mxSubmission, "Bind", aIter.toString() ); + break; + case XML_REF: + xforms_setValue( mxSubmission, "Ref", aIter.toString() ); + break; + case XML_ACTION: + xforms_setValue( mxSubmission, "Action", aIter.toString() ); + break; + case XML_METHOD: + xforms_setValue( mxSubmission, "Method", aIter.toString() ); + break; + case XML_VERSION: + xforms_setValue( mxSubmission, "Version", aIter.toString() ); + break; + case XML_INDENT: + xforms_setValue( mxSubmission, "Indent", toBool( aIter.toView() ) ); + break; + case XML_MEDIATYPE: + xforms_setValue( mxSubmission, "MediaType", aIter.toString() ); + break; + case XML_ENCODING: + xforms_setValue( mxSubmission, "Encoding", aIter.toString() ); + break; + case XML_OMIT_XML_DECLARATION: + xforms_setValue( mxSubmission, "OmitXmlDeclaration", + toBool( aIter.toView() ) ); + break; + case XML_STANDALONE: + xforms_setValue( mxSubmission, "Standalone", toBool( aIter.toView() ) ); + break; + case XML_CDATA_SECTION_ELEMENTS: + xforms_setValue( mxSubmission, "CDataSectionElement", aIter.toString() ); + break; + case XML_REPLACE: + xforms_setValue( mxSubmission, "Replace", aIter.toString() ); + break; + case XML_SEPARATOR: + xforms_setValue( mxSubmission, "Separator", aIter.toString() ); + break; + case XML_INCLUDENAMESPACEPREFIXES: + xforms_setValue( mxSubmission, "IncludeNamespacePrefixes", aIter.toString() ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + assert( false && "unknown attribute" ); + break; + } +} + +/** will be called for each child element */ +SvXMLImportContext* XFormsSubmissionContext::HandleChild( + sal_Int32, + const Reference<css::xml::sax::XFastAttributeList>& ) +{ + assert( false && "no children supported" ); + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsSubmissionContext.hxx b/xmloff/source/xforms/XFormsSubmissionContext.hxx new file mode 100644 index 0000000000..b000db0eb9 --- /dev/null +++ b/xmloff/source/xforms/XFormsSubmissionContext.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 "TokenContext.hxx" +#include <com/sun/star/uno/Reference.hxx> + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } + namespace xforms { class XModel2; } +} + +class SvXMLImport; +class SvXMLImportContext; + +/** import the xforms:submission element */ +class XFormsSubmissionContext : public TokenContext +{ + css::uno::Reference<css::beans::XPropertySet> mxSubmission; + +public: + XFormsSubmissionContext( SvXMLImport& rImport, + const css::uno::Reference<css::xforms::XModel2>& xModel ); + + // implement TokenContext methods: + +protected: + virtual void HandleAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) override; + + virtual SvXMLImportContext* HandleChild( + sal_Int32 nElementToken, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList ) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/xformsapi.cxx b/xmloff/source/xforms/xformsapi.cxx new file mode 100644 index 0000000000..feb5d732b0 --- /dev/null +++ b/xmloff/source/xforms/xformsapi.cxx @@ -0,0 +1,295 @@ +/* -*- 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 "xformsapi.hxx" + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/xforms/XFormsSupplier.hpp> +#include <com/sun/star/xforms/XDataTypeRepository.hpp> +#include <com/sun/star/xforms/Model.hpp> +#include <com/sun/star/xforms/XModel2.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/xsd/DataTypeClass.hpp> + +#include <comphelper/processfactory.hxx> +#include <sal/log.hxx> +#include <comphelper/diagnose_ex.hxx> + +#include <xmloff/xmltoken.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltkmap.hxx> + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::UNO_QUERY_THROW; +using com::sun::star::beans::XPropertySet; +using com::sun::star::container::XNameAccess; +using com::sun::star::xforms::XFormsSupplier; +using com::sun::star::xforms::XDataTypeRepository; +using com::sun::star::xforms::Model; +using com::sun::star::xforms::XModel2; +using com::sun::star::container::XNameContainer; +using com::sun::star::uno::Any; +using com::sun::star::uno::Exception; + +using namespace com::sun::star; +using namespace xmloff::token; + +Reference<XModel2> xforms_createXFormsModel() +{ + Reference<XModel2> xModel = Model::create( comphelper::getProcessComponentContext() ); + + return xModel; +} + +void xforms_addXFormsModel( + const Reference<frame::XModel>& xDocument, + const Reference<xforms::XModel2>& xModel ) +{ + bool bSuccess = false; + try + { + Reference<XFormsSupplier> xSupplier( xDocument, UNO_QUERY ); + if( xSupplier.is() ) + { + Reference<XNameContainer> xForms = xSupplier->getXForms(); + if( xForms.is() ) + { + OUString sName; + xModel->getPropertyValue("ID") >>= sName; + xForms->insertByName( sName, Any( xModel ) ); + bSuccess = true; + } + } + } + catch( const Exception& ) + { + ; // no success! + } + + // TODO: implement proper error handling + SAL_WARN_IF( !bSuccess, "xmloff", "can't import model" ); +} + +static Reference<XPropertySet> lcl_findXFormsBindingOrSubmission( + Reference<frame::XModel> const & xDocument, + const OUString& rBindingID, + bool bBinding ) +{ + // find binding by iterating over all models, and look for the + // given binding ID + + Reference<XPropertySet> xRet; + try + { + // get supplier + Reference<XFormsSupplier> xSupplier( xDocument, UNO_QUERY ); + if( xSupplier.is() ) + { + // get XForms models + Reference<XNameContainer> xForms = xSupplier->getXForms(); + if( xForms.is() ) + { + // iterate over all models + const Sequence<OUString> aNames = xForms->getElementNames(); + for( const auto& rName : aNames ) + { + Reference<xforms::XModel2> xModel( + xForms->getByName( rName ), UNO_QUERY ); + if( xModel.is() ) + { + // ask model for bindings + Reference<XNameAccess> xBindings( + bBinding + ? xModel->getBindings() + : xModel->getSubmissions(), + UNO_QUERY_THROW ); + + // finally, ask binding for name + if( xBindings->hasByName( rBindingID ) ) + xRet.set( xBindings->getByName( rBindingID ), + UNO_QUERY ); + } + + if (xRet.is()) + break; + } + } + } + } + catch( const Exception& ) + { + ; // no success! + } + + // TODO: if (!xRet.is()) rImport.SetError(...); + + return xRet; +} + +Reference<XPropertySet> xforms_findXFormsBinding( + Reference<frame::XModel> const & xDocument, + const OUString& rBindingID ) +{ + return lcl_findXFormsBindingOrSubmission( xDocument, rBindingID, true ); +} + +Reference<XPropertySet> xforms_findXFormsSubmission( + Reference<frame::XModel> const & xDocument, + const OUString& rBindingID ) +{ + return lcl_findXFormsBindingOrSubmission( xDocument, rBindingID, false ); +} + +void xforms_setValueAny( Reference<XPropertySet> const & xPropertySet, + const OUString& rName, + const Any& rAny ) +{ + xPropertySet->setPropertyValue( rName, rAny ); +} + +const SvXMLTokenMapEntry aTypes[] = +{ + { XML_NAMESPACE_XSD, xmloff::token::XML_STRING, xmloff::token::XML_STRING }, + { XML_NAMESPACE_XSD, xmloff::token::XML_DECIMAL, xmloff::token::XML_DECIMAL }, + { XML_NAMESPACE_XSD, xmloff::token::XML_DOUBLE, xmloff::token::XML_DOUBLE }, + { XML_NAMESPACE_XSD, xmloff::token::XML_FLOAT, xmloff::token::XML_FLOAT }, + { XML_NAMESPACE_XSD, xmloff::token::XML_BOOLEAN, xmloff::token::XML_BOOLEAN }, + { XML_NAMESPACE_XSD, xmloff::token::XML_ANYURI, xmloff::token::XML_ANYURI }, + { XML_NAMESPACE_XSD, xmloff::token::XML_DATETIME_XSD, xmloff::token::XML_DATETIME_XSD }, + { XML_NAMESPACE_XSD, xmloff::token::XML_DATE, xmloff::token::XML_DATE }, + { XML_NAMESPACE_XSD, xmloff::token::XML_TIME, xmloff::token::XML_TIME }, + { XML_NAMESPACE_XSD, xmloff::token::XML_YEAR, xmloff::token::XML_YEAR }, + { XML_NAMESPACE_XSD, xmloff::token::XML_MONTH, xmloff::token::XML_MONTH }, + { XML_NAMESPACE_XSD, xmloff::token::XML_DAY, xmloff::token::XML_DAY }, + XML_TOKEN_MAP_END +}; + +sal_uInt16 xforms_getTypeClass( + const Reference<XDataTypeRepository>& xRepository, + const SvXMLNamespaceMap& rNamespaceMap, + const OUString& rXMLName ) +{ + // translate name into token for local name + OUString sLocalName; + sal_uInt16 nPrefix = rNamespaceMap.GetKeyByAttrValueQName(rXMLName, &sLocalName); + static const SvXMLTokenMap aMap( aTypes ); + sal_uInt16 nToken = aMap.Get( nPrefix, sLocalName ); + + sal_uInt16 nTypeClass = css::xsd::DataTypeClass::STRING; + if( nToken != XML_TOK_UNKNOWN ) + { + // we found an XSD name: then get the proper API name for it + SAL_WARN_IF( !xRepository.is(), "xmloff", "can't find type without repository"); + switch( nToken ) + { + case XML_STRING: + nTypeClass = css::xsd::DataTypeClass::STRING; + break; + case XML_ANYURI: + nTypeClass = css::xsd::DataTypeClass::anyURI; + break; + case XML_DECIMAL: + nTypeClass = css::xsd::DataTypeClass::DECIMAL; + break; + case XML_DOUBLE: + nTypeClass = css::xsd::DataTypeClass::DOUBLE; + break; + case XML_FLOAT: + nTypeClass = css::xsd::DataTypeClass::FLOAT; + break; + case XML_BOOLEAN: + nTypeClass = css::xsd::DataTypeClass::BOOLEAN; + break; + case XML_DATETIME_XSD: + nTypeClass = css::xsd::DataTypeClass::DATETIME; + break; + case XML_DATE: + nTypeClass = css::xsd::DataTypeClass::DATE; + break; + case XML_TIME: + nTypeClass = css::xsd::DataTypeClass::TIME; + break; + case XML_YEAR: + nTypeClass = css::xsd::DataTypeClass::gYear; + break; + case XML_DAY: + nTypeClass = css::xsd::DataTypeClass::gDay; + break; + case XML_MONTH: + nTypeClass = css::xsd::DataTypeClass::gMonth; + break; + + /* data types not yet supported: + nTypeClass = css::xsd::DataTypeClass::DURATION; + nTypeClass = css::xsd::DataTypeClass::gYearMonth; + nTypeClass = css::xsd::DataTypeClass::gMonthDay; + nTypeClass = css::xsd::DataTypeClass::hexBinary; + nTypeClass = css::xsd::DataTypeClass::base64Binary; + nTypeClass = css::xsd::DataTypeClass::QName; + nTypeClass = css::xsd::DataTypeClass::NOTATION; + */ + } + } + + return nTypeClass; +} + + +OUString xforms_getTypeName( + const Reference<XDataTypeRepository>& xRepository, + const SvXMLNamespaceMap& rNamespaceMap, + const OUString& rXMLName ) +{ + OUString sLocalName; + sal_uInt16 nPrefix = rNamespaceMap.GetKeyByAttrValueQName(rXMLName, &sLocalName); + static const SvXMLTokenMap aMap( aTypes ); + sal_uInt16 nToken = aMap.Get( nPrefix, sLocalName ); + return ( nToken == XML_TOK_UNKNOWN ) + ? rXMLName + : xforms_getBasicTypeName( xRepository, rNamespaceMap, rXMLName ); +} + +OUString xforms_getBasicTypeName( + const Reference<XDataTypeRepository>& xRepository, + const SvXMLNamespaceMap& rNamespaceMap, + const OUString& rXMLName ) +{ + OUString sTypeName = rXMLName; + try + { + sTypeName = + xRepository->getBasicDataType( + xforms_getTypeClass( xRepository, rNamespaceMap, rXMLName ) ) + ->getName(); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff", "exception during type creation"); + } + return sTypeName; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/xformsapi.hxx b/xmloff/source/xforms/xformsapi.hxx new file mode 100644 index 0000000000..ba66e985b5 --- /dev/null +++ b/xmloff/source/xforms/xformsapi.hxx @@ -0,0 +1,83 @@ +/* -*- 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 + + +// this is a collection of several functions to make dealing with the XForms +// API a little easier + + +#include <com/sun/star/uno/Any.hxx> + +namespace com::sun::star { + namespace beans { class XPropertySet; } + namespace frame { class XModel; } + namespace uno { template<class A> class Reference; } + namespace xforms { class XDataTypeRepository; class XModel2; } +} +class SvXMLNamespaceMap; + +css::uno::Reference<css::xforms::XModel2> xforms_createXFormsModel(); + +void xforms_addXFormsModel( + const css::uno::Reference<css::frame::XModel>& xDocument, + const css::uno::Reference<css::xforms::XModel2>& xModel ); + +css::uno::Reference<css::beans::XPropertySet> xforms_findXFormsBinding( css::uno::Reference<css::frame::XModel> const &, const OUString& ); + +css::uno::Reference<css::beans::XPropertySet> xforms_findXFormsSubmission( css::uno::Reference<css::frame::XModel> const &, const OUString& ); + +void xforms_setValueAny( + css::uno::Reference<css::beans::XPropertySet> const & xPropSet, + const OUString& rName, + const css::uno::Any& rAny ); + +template<typename T> +inline void xforms_setValue( + const css::uno::Reference<css::beans::XPropertySet>& xPropSet, + const OUString& rName, + const T& aValue ) +{ + xforms_setValueAny( xPropSet, rName, css::uno::Any( aValue ) ); +} +template<> +inline void xforms_setValue( + const css::uno::Reference<css::beans::XPropertySet>& xPropSet, + const OUString& rName, + const css::uno::Any& aValue ) +{ + xforms_setValueAny( xPropSet, rName, aValue ); +} + +sal_uInt16 xforms_getTypeClass( + const css::uno::Reference<css::xforms::XDataTypeRepository>& xRepository, + const SvXMLNamespaceMap& rNamespaceMap, + const OUString& rXMLName ); + +OUString xforms_getTypeName( + const css::uno::Reference<css::xforms::XDataTypeRepository>& xRepository, + const SvXMLNamespaceMap& rNamespaceMap, + const OUString& rXMLName ); + +OUString xforms_getBasicTypeName( + const css::uno::Reference<css::xforms::XDataTypeRepository>& xRepository, + const SvXMLNamespaceMap& rNamespaceMap, + const OUString& rXMLName ); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/xformsexport.cxx b/xmloff/source/xforms/xformsexport.cxx new file mode 100644 index 0000000000..b0d5c9e998 --- /dev/null +++ b/xmloff/source/xforms/xformsexport.cxx @@ -0,0 +1,801 @@ +/* -*- 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/xformsexport.hxx> + +#include "XFormsModelExport.hxx" + +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <DomExport.hxx> + +#include <sax/tools/converter.hxx> + +#include <comphelper/processfactory.hxx> +#include <comphelper/propertyvalue.hxx> + +#include <comphelper/diagnose_ex.hxx> +#include <sal/log.hxx> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/document/NamedPropertyValues.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/xml/dom/XDocument.hpp> +#include <com/sun/star/form/binding/XBindableValue.hpp> +#include <com/sun/star/form/binding/XListEntrySink.hpp> +#include <com/sun/star/form/submission/XSubmissionSupplier.hpp> +#include <com/sun/star/xforms/XModel.hpp> +#include <com/sun/star/xforms/XDataTypeRepository.hpp> +#include <com/sun/star/xforms/XFormsSupplier.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/xsd/WhiteSpaceTreatment.hpp> +#include <com/sun/star/xsd/DataTypeClass.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/Duration.hpp> + +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace xmloff::token; + +using com::sun::star::beans::XPropertySet; +using com::sun::star::beans::XPropertySetInfo; +using com::sun::star::container::XIndexAccess; +using com::sun::star::container::XNameAccess; +using com::sun::star::container::XNameContainer; +using com::sun::star::container::XEnumerationAccess; +using com::sun::star::container::XEnumeration; +using com::sun::star::xml::dom::XDocument; +using com::sun::star::form::binding::XBindableValue; +using com::sun::star::form::binding::XListEntrySink; +using com::sun::star::form::submission::XSubmissionSupplier; +using com::sun::star::beans::PropertyValue; +using com::sun::star::xforms::XDataTypeRepository; +using com::sun::star::xforms::XFormsSupplier; +using com::sun::star::util::Duration; + +void exportXForms( SvXMLExport& rExport ) +{ + Reference<XFormsSupplier> xSupplier( rExport.GetModel(), UNO_QUERY ); + if( !xSupplier.is() ) + return; + + Reference<XNameContainer> xForms = xSupplier->getXForms(); + if( xForms.is() ) + { + const Sequence<OUString> aNames = xForms->getElementNames(); + + for( const auto& rName : aNames ) + { + Reference<XPropertySet> xModel( xForms->getByName( rName ), + UNO_QUERY ); + exportXFormsModel( rExport, xModel ); + } + } +} + + +static void exportXFormsInstance( SvXMLExport&, const Sequence<PropertyValue>& ); +static void exportXFormsBinding( SvXMLExport&, const Reference<XPropertySet>& ); +static void exportXFormsSubmission( SvXMLExport&, const Reference<XPropertySet>& ); +static void exportXFormsSchemas( SvXMLExport&, const Reference<css::xforms::XModel>& ); + + +typedef OUString (*convert_t)( const Any& ); + +namespace { + +struct ExportTable +{ + const char* pPropertyName; + sal_uInt16 const nNamespace; + sal_uInt16 nToken; + convert_t const aConverter; +}; + +} + +static void lcl_export( const Reference<XPropertySet>& rPropertySet, + SvXMLExport& rExport, + const ExportTable* pTable ); + +#define TABLE_END { nullptr, 0, 0, nullptr } + +// any conversion functions +static OUString xforms_string( const Any& ); +static OUString xforms_bool( const Any& ); +static OUString xforms_whitespace( const Any& ); +template<typename T, void (*FUNC)( OUStringBuffer&, T )> static OUString xforms_convert( const Any& ); +template<typename T, void (*FUNC)( OUStringBuffer&, const T& )> static OUString xforms_convertRef( const Any& ); + +static void xforms_formatDate( OUStringBuffer& aBuffer, const util::Date& aDate ); +static void xforms_formatTime( OUStringBuffer& aBuffer, const css::util::Time& aTime ); +static void xforms_formatDateTime( OUStringBuffer& aBuffer, const util::DateTime& aDateTime ); + +static void convertNumber(OUStringBuffer & b, sal_Int32 n) { + b.append(n); +} + +convert_t const xforms_int32 = &xforms_convert<sal_Int32,&convertNumber>; +convert_t const xforms_double = &xforms_convert<double,&::sax::Converter::convertDouble>; +convert_t const xforms_dateTime = &xforms_convertRef<util::DateTime,&xforms_formatDateTime>; +convert_t const xforms_date = &xforms_convertRef<util::Date,&xforms_formatDate>; +convert_t const xforms_time = &xforms_convertRef<css::util::Time,&xforms_formatTime>; + +// other functions +static OUString lcl_getXSDType( SvXMLExport const & rExport, + const Reference<XPropertySet>& xType ); + + +// the model + + +const ExportTable aXFormsModelTable[] = +{ + { "ID", XML_NAMESPACE_NONE, xmloff::token::XML_ID, xforms_string }, + { "SchemaRef", XML_NAMESPACE_NONE, xmloff::token::XML_SCHEMA, xforms_string }, + TABLE_END +}; + +void exportXFormsModel( SvXMLExport& rExport, + const Reference<XPropertySet>& xModelPropSet ) +{ + // no model -> don't do anything! + Reference<css::xforms::XModel> xModel( xModelPropSet, UNO_QUERY ); + if( ! xModel.is() || ! xModelPropSet.is() ) + return; + + lcl_export( xModelPropSet, rExport, aXFormsModelTable ); + SvXMLElementExport aModelElement( rExport, XML_NAMESPACE_XFORMS, XML_MODEL, + true, true ); + + // instances + Reference<XIndexAccess> xInstances( xModel->getInstances(), + UNO_QUERY_THROW); + sal_Int32 nCount = xInstances->getCount(); + sal_Int32 i = 0; + for( i = 0; i < nCount; i++ ) + { + Sequence<PropertyValue> aInstance; + xInstances->getByIndex( i ) >>= aInstance; + exportXFormsInstance( rExport, aInstance ); + } + + + // bindings + Reference<XIndexAccess> xBindings( xModel->getBindings(), UNO_QUERY_THROW); + nCount = xBindings->getCount(); + for( i = 0; i < nCount; i++ ) + { + Reference<XPropertySet> aBinding( xBindings->getByIndex( i ), + UNO_QUERY_THROW ); + exportXFormsBinding( rExport, aBinding ); + } + + // submissions + Reference<XIndexAccess> xSubmissions( xModel->getSubmissions(), + UNO_QUERY_THROW ); + nCount = xSubmissions->getCount(); + for( i = 0; i < nCount; i++ ) + { + Reference<XPropertySet> xSubmission( xSubmissions->getByIndex( i ), + UNO_QUERY_THROW ); + exportXFormsSubmission( rExport, xSubmission ); + } + + // schemas + exportXFormsSchemas( rExport, xModel ); +} + + +// the instance + + +void exportXFormsInstance( SvXMLExport& rExport, + const Sequence<PropertyValue>& xInstance ) +{ + OUString sId; + OUString sURL; + Reference<XDocument> xDoc; + + for( const auto& rProp : xInstance ) + { + OUString sName = rProp.Name; + const Any& rAny = rProp.Value; + if ( sName == "ID" ) + rAny >>= sId; + else if ( sName == "URL" ) + rAny >>= sURL; + else if ( sName == "Instance" ) + rAny >>= xDoc; + } + + if( !sId.isEmpty() ) + rExport.AddAttribute( XML_NAMESPACE_NONE, XML_ID, sId ); + + if( !sURL.isEmpty() ) + rExport.AddAttribute( XML_NAMESPACE_NONE, XML_SRC, sURL ); + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_XFORMS, XML_INSTANCE, + true, true ); + rExport.IgnorableWhitespace(); + if( xDoc.is() ) + { + exportDom( rExport, xDoc ); + } +} + + +// the binding + + +const ExportTable aXFormsBindingTable[] = +{ + { "BindingID", XML_NAMESPACE_NONE, xmloff::token::XML_ID, xforms_string }, + { "BindingExpression", XML_NAMESPACE_NONE, xmloff::token::XML_NODESET, xforms_string }, + { "ReadonlyExpression", XML_NAMESPACE_NONE, xmloff::token::XML_READONLY, xforms_string }, + { "RelevantExpression", XML_NAMESPACE_NONE, xmloff::token::XML_RELEVANT, xforms_string }, + { "RequiredExpression", XML_NAMESPACE_NONE, xmloff::token::XML_REQUIRED, xforms_string }, + { "ConstraintExpression", XML_NAMESPACE_NONE, xmloff::token::XML_CONSTRAINT, xforms_string }, + { "CalculateExpression", XML_NAMESPACE_NONE, xmloff::token::XML_CALCULATE, xforms_string }, + // type handled separately, for type name <-> XSD type conversion + // { "Type", XML_NAMESPACE_NONE, xmloff::token::XML_TYPE, xforms_string }, + TABLE_END +}; + +void exportXFormsBinding( SvXMLExport& rExport, + const Reference<XPropertySet>& xBinding ) +{ + // name check; generate binding ID if necessary + { + OUString sName; + xBinding->getPropertyValue( "BindingID" ) >>= sName; + if( sName.isEmpty() ) + { + // if we don't have a name yet, generate one on the fly + sal_Int64 nId = reinterpret_cast<sal_uInt64>( xBinding.get() ); + sName = "bind_" + OUString::number( nId , 16 ); + xBinding->setPropertyValue( "BindingID", Any(sName)); + } + } + + lcl_export( xBinding, rExport, aXFormsBindingTable ); + + // handle type attribute + { + OUString sTypeName; + xBinding->getPropertyValue( "Type" ) >>= sTypeName; + + try + { + // now get type, and determine whether it's a standard type. If + // so, export the XSD name + Reference<css::xforms::XModel> xModel( + xBinding->getPropertyValue( "Model" ), + UNO_QUERY ); + Reference<XDataTypeRepository> xRepository( + xModel.is() ? xModel->getDataTypeRepository() : Reference<XDataTypeRepository>() ); + if( xRepository.is() ) + { + Reference<XPropertySet> xDataType = + xRepository->getDataType( sTypeName ); + + // if it's a basic data type, write out the XSD name + // for the XSD type class + bool bIsBasic = false; + xDataType->getPropertyValue( "IsBasic" ) >>= bIsBasic; + if( bIsBasic ) + sTypeName = lcl_getXSDType( rExport, xDataType ); + } + } + catch( Exception& ) + { + ; // ignore; just use typename + } + + // now that we have the proper type name, write out the attribute + if( !sTypeName.isEmpty() ) + { + rExport.AddAttribute( XML_NAMESPACE_NONE, XML_TYPE, + sTypeName ); + } + } + + // we need to ensure all the namespaces in the binding will work correctly. + // to do so, we will write out all missing namespace declaractions. + const SvXMLNamespaceMap& rMap = rExport.GetNamespaceMap(); + Reference<XNameAccess> xNamespaces( + xBinding->getPropertyValue( "ModelNamespaces" ), UNO_QUERY); + if( xNamespaces.is() ) + { + // iterate over Prefixes for this binding + const Sequence<OUString> aPrefixes = xNamespaces->getElementNames(); + for( const OUString& rPrefix : aPrefixes ) + { + OUString sURI; + xNamespaces->getByName( rPrefix ) >>= sURI; + + // check whether prefix/URI pair is in map; else write declaration + // (we don't need to change the map, since this element has no + // other content) + sal_uInt16 nKey = rMap.GetKeyByPrefix( rPrefix ); + if( nKey == XML_NAMESPACE_UNKNOWN || + rMap.GetNameByKey( nKey ) != sURI ) + { + // add declaration if it doesn't already exist + comphelper::AttributeList& rAttrList = rExport.GetAttrList(); + OUString sName = "xmlns:" + rPrefix; + sal_Int16 nFound = rAttrList.GetIndexByName(sName); + // duplicate xmlns:script, http://openoffice.org/2000/script seen + assert(nFound == -1 || rAttrList.getValueByIndex(nFound) == sURI); + if (nFound != -1) + continue; + rAttrList.AddAttribute(sName, sURI); + } + } + } + + SvXMLElementExport aElement( rExport, XML_NAMESPACE_XFORMS, XML_BIND, + true, true ); +} + + +// the submission + + +const ExportTable aXFormsSubmissionTable[] = +{ + { "ID", XML_NAMESPACE_NONE, xmloff::token::XML_ID, xforms_string }, + { "Bind", XML_NAMESPACE_NONE, xmloff::token::XML_BIND, xforms_string }, + { "Ref", XML_NAMESPACE_NONE, xmloff::token::XML_REF, xforms_string }, + { "Action", XML_NAMESPACE_NONE, xmloff::token::XML_ACTION, xforms_string }, + { "Method", XML_NAMESPACE_NONE, xmloff::token::XML_METHOD, xforms_string }, + { "Version", XML_NAMESPACE_NONE, xmloff::token::XML_VERSION, xforms_string }, + { "Indent", XML_NAMESPACE_NONE, xmloff::token::XML_INDENT, xforms_bool }, + { "MediaType", XML_NAMESPACE_NONE, xmloff::token::XML_MEDIATYPE, xforms_string }, + { "Encoding", XML_NAMESPACE_NONE, xmloff::token::XML_ENCODING, xforms_string }, + { "OmitXmlDeclaration", XML_NAMESPACE_NONE, xmloff::token::XML_OMIT_XML_DECLARATION, xforms_bool }, + { "Standalone", XML_NAMESPACE_NONE, xmloff::token::XML_STANDALONE, xforms_bool }, + { "CDataSectionElement", XML_NAMESPACE_NONE, xmloff::token::XML_CDATA_SECTION_ELEMENTS, xforms_string }, + { "Replace", XML_NAMESPACE_NONE, xmloff::token::XML_REPLACE, xforms_string }, + { "Separator", XML_NAMESPACE_NONE, xmloff::token::XML_SEPARATOR, xforms_string }, + { "IncludeNamespacePrefixes", XML_NAMESPACE_NONE, xmloff::token::XML_INCLUDENAMESPACEPREFIXES, xforms_string }, + TABLE_END +}; + +void exportXFormsSubmission( SvXMLExport& rExport, + const Reference<XPropertySet>& xSubmission ) +{ + lcl_export( xSubmission, rExport, aXFormsSubmissionTable ); + SvXMLElementExport aElement( rExport, XML_NAMESPACE_XFORMS, XML_SUBMISSION, + true, true ); +} + + +// export data types as XSD schema + + +const ExportTable aDataTypeFacetTable[] = +{ + { "Length", XML_NAMESPACE_XSD, xmloff::token::XML_LENGTH, xforms_int32 }, + { "MinLength", XML_NAMESPACE_XSD, xmloff::token::XML_MINLENGTH, xforms_int32 }, + { "MaxLength", XML_NAMESPACE_XSD, xmloff::token::XML_MAXLENGTH, xforms_int32 }, + { "MinInclusiveInt", XML_NAMESPACE_XSD, xmloff::token::XML_MININCLUSIVE, xforms_int32 }, + { "MinExclusiveInt", XML_NAMESPACE_XSD, xmloff::token::XML_MINEXCLUSIVE, xforms_int32 }, + { "MaxInclusiveInt", XML_NAMESPACE_XSD, xmloff::token::XML_MAXINCLUSIVE, xforms_int32 }, + { "MaxExclusiveInt", XML_NAMESPACE_XSD, xmloff::token::XML_MAXEXCLUSIVE, xforms_int32 }, + { "MinInclusiveDouble", XML_NAMESPACE_XSD, xmloff::token::XML_MININCLUSIVE, xforms_double }, + { "MinExclusiveDouble", XML_NAMESPACE_XSD, xmloff::token::XML_MINEXCLUSIVE, xforms_double }, + { "MaxInclusiveDouble", XML_NAMESPACE_XSD, xmloff::token::XML_MAXINCLUSIVE, xforms_double }, + { "MaxExclusiveDouble", XML_NAMESPACE_XSD, xmloff::token::XML_MAXEXCLUSIVE, xforms_double }, + { "MinInclusiveDate", XML_NAMESPACE_XSD, xmloff::token::XML_MININCLUSIVE, xforms_date }, + { "MinExclusiveDate", XML_NAMESPACE_XSD, xmloff::token::XML_MINEXCLUSIVE, xforms_date }, + { "MaxInclusiveDate", XML_NAMESPACE_XSD, xmloff::token::XML_MAXINCLUSIVE, xforms_date }, + { "MaxExclusiveDate", XML_NAMESPACE_XSD, xmloff::token::XML_MAXEXCLUSIVE, xforms_date }, + { "MinInclusiveTime", XML_NAMESPACE_XSD, xmloff::token::XML_MININCLUSIVE, xforms_time }, + { "MinExclusiveTime", XML_NAMESPACE_XSD, xmloff::token::XML_MINEXCLUSIVE, xforms_time }, + { "MaxInclusiveTime", XML_NAMESPACE_XSD, xmloff::token::XML_MAXINCLUSIVE, xforms_time }, + { "MaxExclusiveTime", XML_NAMESPACE_XSD, xmloff::token::XML_MAXEXCLUSIVE, xforms_time }, + { "MinInclusiveDateTime", XML_NAMESPACE_XSD, xmloff::token::XML_MININCLUSIVE, xforms_dateTime }, + { "MinExclusiveDateTime", XML_NAMESPACE_XSD, xmloff::token::XML_MINEXCLUSIVE, xforms_dateTime }, + { "MaxInclusiveDateTime", XML_NAMESPACE_XSD, xmloff::token::XML_MAXINCLUSIVE, xforms_dateTime }, + { "MaxExclusiveDateTime", XML_NAMESPACE_XSD, xmloff::token::XML_MAXEXCLUSIVE, xforms_dateTime }, + { "Pattern", XML_NAMESPACE_XSD, xmloff::token::XML_PATTERN, xforms_string }, + // ??? XML_ENUMERATION, + { "WhiteSpace", XML_NAMESPACE_XSD, xmloff::token::XML_WHITESPACE, xforms_whitespace }, + { "TotalDigits", XML_NAMESPACE_XSD, xmloff::token::XML_TOTALDIGITS, xforms_int32 }, + { "FractionDigits", XML_NAMESPACE_XSD, xmloff::token::XML_FRACTIONDIGITS, xforms_int32 }, + TABLE_END +}; + +// export facets through table; use the same table as lcl_export does +static void lcl_exportDataTypeFacets( SvXMLExport& rExport, + const Reference<XPropertySet>& rPropertySet, + const ExportTable* pTable ) +{ + Reference<XPropertySetInfo> xInfo = rPropertySet->getPropertySetInfo(); + for( const ExportTable* pCurrent = pTable; + pCurrent->pPropertyName != nullptr; + pCurrent++ ) + { + OUString sName( OUString::createFromAscii( pCurrent->pPropertyName ) ); + if( xInfo->hasPropertyByName( sName ) ) + { + OUString sValue = (*pCurrent->aConverter)( + rPropertySet->getPropertyValue( sName ) ); + + if( !sValue.isEmpty() ) + { + rExport.AddAttribute( XML_NAMESPACE_NONE, XML_VALUE, sValue ); + SvXMLElementExport aFacet( + rExport, + pCurrent->nNamespace, + static_cast<XMLTokenEnum>( pCurrent->nToken ), + true, true ); + } + } + } +} + +static OUString lcl_getXSDType( SvXMLExport const & rExport, + const Reference<XPropertySet>& xType ) +{ + // we use string as default... + XMLTokenEnum eToken = XML_STRING; + + sal_uInt16 nDataTypeClass = 0; + xType->getPropertyValue( "TypeClass" ) >>= nDataTypeClass; + switch( nDataTypeClass ) + { + case css::xsd::DataTypeClass::STRING: + eToken = XML_STRING; + break; + case css::xsd::DataTypeClass::anyURI: + eToken = XML_ANYURI; + break; + case css::xsd::DataTypeClass::DECIMAL: + eToken = XML_DECIMAL; + break; + case css::xsd::DataTypeClass::DOUBLE: + eToken = XML_DOUBLE; + break; + case css::xsd::DataTypeClass::FLOAT: + eToken = XML_FLOAT; + break; + case css::xsd::DataTypeClass::BOOLEAN: + eToken = XML_BOOLEAN; + break; + case css::xsd::DataTypeClass::DATETIME: + eToken = XML_DATETIME_XSD; + break; + case css::xsd::DataTypeClass::TIME: + eToken = XML_TIME; + break; + case css::xsd::DataTypeClass::DATE: + eToken = XML_DATE; + break; + case css::xsd::DataTypeClass::gYear: + eToken = XML_YEAR; + break; + case css::xsd::DataTypeClass::gDay: + eToken = XML_DAY; + break; + case css::xsd::DataTypeClass::gMonth: + eToken = XML_MONTH; + break; + case css::xsd::DataTypeClass::DURATION: + case css::xsd::DataTypeClass::gYearMonth: + case css::xsd::DataTypeClass::gMonthDay: + case css::xsd::DataTypeClass::hexBinary: + case css::xsd::DataTypeClass::base64Binary: + case css::xsd::DataTypeClass::QName: + case css::xsd::DataTypeClass::NOTATION: + default: + OSL_FAIL( "unknown data type" ); + } + + return rExport.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_XSD, + GetXMLToken( eToken ) ); +} + +static void lcl_exportDataType( SvXMLExport& rExport, + const Reference<XPropertySet>& xType ) +{ + // we do not need to export basic types; exit if we have one + bool bIsBasic = false; + xType->getPropertyValue( "IsBasic" ) >>= bIsBasic; + if( bIsBasic ) + return; + + // no basic type -> export + + // <xsd:simpleType name="..."> + OUString sName; + xType->getPropertyValue( "Name" ) >>= sName; + rExport.AddAttribute( XML_NAMESPACE_NONE, XML_NAME, sName ); + SvXMLElementExport aSimpleType( rExport, + XML_NAMESPACE_XSD, XML_SIMPLETYPE, + true, true ); + + // <xsd:restriction base="xsd:..."> + rExport.AddAttribute( XML_NAMESPACE_NONE, XML_BASE, + lcl_getXSDType( rExport, xType ) ); + SvXMLElementExport aRestriction( rExport, + XML_NAMESPACE_XSD, + XML_RESTRICTION, + true, true ); + + // export facets + lcl_exportDataTypeFacets( rExport, + xType, + aDataTypeFacetTable ); +} + +void exportXFormsSchemas( SvXMLExport& rExport, + const Reference<css::xforms::XModel>& xModel ) +{ + // TODO: for now, we'll fake this... + { + SvXMLElementExport aSchemaElem( rExport, XML_NAMESPACE_XSD, XML_SCHEMA, + true, true ); + + // now get data type repository, and export + Reference<XEnumerationAccess> xTypes = xModel->getDataTypeRepository(); + if( xTypes.is() ) + { + Reference<XEnumeration> xEnum = xTypes->createEnumeration(); + SAL_WARN_IF( !xEnum.is(), "xmloff", "no enum?" ); + while( xEnum->hasMoreElements() ) + { + Reference<XPropertySet> xType( xEnum->nextElement(), UNO_QUERY ); + lcl_exportDataType( rExport, xType ); + } + } + } + + // export other, 'foreign' schemas + Reference<XPropertySet> xPropSet( xModel, UNO_QUERY ); + if( xPropSet.is() ) + { + Reference<XDocument> xDocument( + xPropSet->getPropertyValue( "ForeignSchema" ), + UNO_QUERY ); + + if( xDocument.is() ) + exportDom( rExport, xDocument ); + } +} + + +// helper functions + + +static void lcl_export( const Reference<XPropertySet>& rPropertySet, + SvXMLExport& rExport, + const ExportTable* pTable ) +{ + for( const ExportTable* pCurrent = pTable; + pCurrent->pPropertyName != nullptr; + pCurrent++ ) + { + Any aAny = rPropertySet->getPropertyValue( + OUString::createFromAscii( pCurrent->pPropertyName ) ); + OUString sValue = (*pCurrent->aConverter)( aAny ); + + if( !sValue.isEmpty() ) + rExport.AddAttribute( + pCurrent->nNamespace, + static_cast<XMLTokenEnum>( pCurrent->nToken ), + sValue ); + } +} + + +// any conversion functions + + +template<typename T, void (*FUNC)( OUStringBuffer&, T )> +OUString xforms_convert( const Any& rAny ) +{ + OUStringBuffer aBuffer; + T aData = T(); + if( rAny >>= aData ) + { + FUNC( aBuffer, aData ); + } + return aBuffer.makeStringAndClear(); +} + +template<typename T, void (*FUNC)( OUStringBuffer&, const T& )> +OUString xforms_convertRef( const Any& rAny ) +{ + OUStringBuffer aBuffer; + T aData; + if( rAny >>= aData ) + { + FUNC( aBuffer, aData ); + } + return aBuffer.makeStringAndClear(); +} + +OUString xforms_string( const Any& rAny ) +{ + OUString aResult; + rAny >>= aResult; + return aResult; +} + +OUString xforms_bool( const Any& rAny ) +{ + bool bResult = bool(); + if( rAny >>= bResult ) + return GetXMLToken( bResult ? XML_TRUE : XML_FALSE ); + OSL_FAIL( "expected boolean value" ); + return OUString(); +} + +void xforms_formatDate( OUStringBuffer& aBuffer, const util::Date& rDate ) +{ + aBuffer.append( OUString::number( rDate.Year ) + + "-" + OUString::number( rDate.Month ) + + "-" + OUString::number( rDate.Day ) ); +} + +void xforms_formatTime( OUStringBuffer& aBuffer, const css::util::Time& rTime ) +{ + Duration aDuration; + aDuration.Hours = rTime.Hours; + aDuration.Minutes = rTime.Minutes; + aDuration.Seconds = rTime.Seconds; + aDuration.NanoSeconds = rTime.NanoSeconds; + ::sax::Converter::convertDuration( aBuffer, aDuration ); +} + +void xforms_formatDateTime( OUStringBuffer& aBuffer, const util::DateTime& aDateTime ) +{ + ::sax::Converter::convertDateTime(aBuffer, aDateTime, nullptr); +} + +OUString xforms_whitespace( const Any& rAny ) +{ + OUString sResult; + sal_uInt16 n = sal_uInt16(); + if( rAny >>= n ) + { + switch( n ) + { + case css::xsd::WhiteSpaceTreatment::Preserve: + sResult = GetXMLToken( XML_PRESERVE ); + break; + case css::xsd::WhiteSpaceTreatment::Replace: + sResult = GetXMLToken( XML_REPLACE ); + break; + case css::xsd::WhiteSpaceTreatment::Collapse: + sResult = GetXMLToken( XML_COLLAPSE ); + break; + } + } + return sResult; +} + + +/// return name of Binding +static OUString lcl_getXFormsBindName( const Reference<XPropertySet>& xBinding ) +{ + OUString sProp( "BindingID" ); + + OUString sReturn; + if( xBinding.is() && + xBinding->getPropertySetInfo()->hasPropertyByName( sProp ) ) + { + xBinding->getPropertyValue( sProp ) >>= sReturn; + } + return sReturn; +} + +// return name of binding +OUString getXFormsBindName( const Reference<XPropertySet>& xControl ) +{ + Reference<XBindableValue> xBindable( xControl, UNO_QUERY ); + return xBindable.is() + ? lcl_getXFormsBindName( + Reference<XPropertySet>( xBindable->getValueBinding(), UNO_QUERY )) + : OUString(); +} + +// return name of list binding +OUString getXFormsListBindName( const Reference<XPropertySet>& xControl ) +{ + Reference<XListEntrySink> xListEntrySink( xControl, UNO_QUERY ); + return xListEntrySink.is() + ? lcl_getXFormsBindName( + Reference<XPropertySet>( xListEntrySink->getListEntrySource(), + UNO_QUERY ) ) + : OUString(); +} + +OUString getXFormsSubmissionName( const Reference<XPropertySet>& xBinding ) +{ + OUString sReturn; + + Reference<XSubmissionSupplier> xSubmissionSupplier( xBinding, UNO_QUERY ); + if( xSubmissionSupplier.is() ) + { + Reference<XPropertySet> xPropertySet( + xSubmissionSupplier->getSubmission(), UNO_QUERY ); + OUString sProp( "ID" ); + if( xPropertySet.is() && + xPropertySet->getPropertySetInfo()->hasPropertyByName( sProp ) ) + { + xPropertySet->getPropertyValue( sProp ) >>= sReturn; + } + } + + return sReturn; +} + +void getXFormsSettings( const Reference< XNameAccess >& _rXForms, Sequence< PropertyValue >& _out_rSettings ) +{ + _out_rSettings = Sequence< PropertyValue >(); + + OSL_PRECOND( _rXForms.is(), "getXFormsSettings: invalid XForms container!" ); + if ( !_rXForms.is() ) + return; + + try + { + // we want to export some special properties of our XForms models as config-item-map-named, + // which implies we need a PropertyValue whose value is an XNameAccess, whose keys + // are the names of the XForm models, and which in turn provides named sequences of + // PropertyValues - which denote the actual property values of the given named model. + + const Sequence< OUString > aModelNames( _rXForms->getElementNames() ); + + Reference< XNameContainer > xModelSettings = document::NamedPropertyValues::create( comphelper::getProcessComponentContext() ); + + for ( auto const & modelName : aModelNames ) + { + Reference< XPropertySet > xModelProps( _rXForms->getByName( modelName ), UNO_QUERY_THROW ); + + static constexpr OUString sExternalData = u"ExternalData"_ustr; + Sequence<PropertyValue> aModelSettings{ comphelper::makePropertyValue( + sExternalData, xModelProps->getPropertyValue(sExternalData)) }; + + xModelSettings->insertByName( modelName, Any( aModelSettings ) ); + } + + if ( xModelSettings->hasElements() ) + { + _out_rSettings = { comphelper::makePropertyValue("XFormModels", xModelSettings) }; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/xformsimport.cxx b/xmloff/source/xforms/xformsimport.cxx new file mode 100644 index 0000000000..7ff2743329 --- /dev/null +++ b/xmloff/source/xforms/xformsimport.cxx @@ -0,0 +1,184 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "XFormsModelContext.hxx" +#include <utility> +#include <xmloff/xformsimport.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/form/binding/XValueBinding.hpp> +#include <com/sun/star/form/binding/XBindableValue.hpp> +#include <com/sun/star/form/binding/XListEntrySource.hpp> +#include <com/sun/star/form/binding/XListEntrySink.hpp> +#include <com/sun/star/form/submission/XSubmission.hpp> +#include <com/sun/star/form/submission/XSubmissionSupplier.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <rtl/ustring.hxx> +#include "xformsapi.hxx" +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/diagnose_ex.hxx> + +using std::pair; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Exception; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::UNO_QUERY_THROW; +using com::sun::star::uno::UNO_SET_THROW; +using com::sun::star::uno::Sequence; +using com::sun::star::beans::XPropertySet; +using com::sun::star::beans::XPropertySetInfo; +using com::sun::star::beans::PropertyValue; +using com::sun::star::frame::XModel; +using com::sun::star::container::XNameAccess; +using com::sun::star::form::binding::XValueBinding; +using com::sun::star::form::binding::XBindableValue; +using com::sun::star::form::binding::XListEntrySource; +using com::sun::star::form::binding::XListEntrySink; +using com::sun::star::form::submission::XSubmission; +using com::sun::star::form::submission::XSubmissionSupplier; + +SvXMLImportContext* createXFormsModelContext( + SvXMLImport& rImport ) +{ + return new XFormsModelContext( rImport ); +} + +void bindXFormsValueBinding(Reference<XModel> const& xModel, + const pair<Reference<XPropertySet>, OUString>& aPair) +{ + Reference<XBindableValue> xBindable( + aPair.first, + UNO_QUERY ); + Reference<XValueBinding> xBinding( + xforms_findXFormsBinding( xModel, aPair.second ), + UNO_QUERY ); + + if( xBindable.is() && xBinding.is() ) + { + try + { + xBindable->setValueBinding( xBinding ); + } + catch( const Exception& ) + { + // ignore problems during binding + // TODO: call XML error handling + } + } +} + +void bindXFormsListBinding(Reference<XModel> const& xModel, + const ::pair<Reference<XPropertySet>, OUString>& aPair) +{ + Reference<XListEntrySink> xListEntrySink( + aPair.first, + UNO_QUERY ); + Reference<XListEntrySource> xListEntrySource( + xforms_findXFormsBinding( xModel, aPair.second ), + UNO_QUERY ); + + if( xListEntrySink.is() && xListEntrySource.is() ) + { + try + { + xListEntrySink->setListEntrySource( xListEntrySource ); + } + catch( const Exception& ) + { + // ignore problems during binding + // TODO: call XML error handling + } + } +} + +void bindXFormsSubmission(Reference<XModel> const& xModel, + const pair<Reference<XPropertySet>, OUString>& aPair) +{ + Reference<XSubmissionSupplier> xSubmissionSupp( aPair.first, UNO_QUERY ); + Reference<XSubmission> xSubmission( + xforms_findXFormsSubmission( xModel, aPair.second ), + UNO_QUERY ); + + if( xSubmissionSupp.is() && xSubmission.is() ) + { + try + { + xSubmissionSupp->setSubmission( xSubmission ); + } + catch( const Exception& ) + { + // ignore problems during binding + // TODO: call XML error handling + } + } +} + +void applyXFormsSettings( const Reference< XNameAccess >& _rXForms, const Sequence< PropertyValue >& _rSettings ) +{ + OSL_PRECOND( _rXForms.is(), "applyXFormsSettings: invalid XForms container!" ); + if ( !_rXForms.is() ) + return; + + Reference< XNameAccess > xModelSettings( ::comphelper::NamedValueCollection::get( _rSettings, u"XFormModels" ), UNO_QUERY ); + if ( !xModelSettings.is() ) + { + OSL_FAIL( "applyXFormsSettings: wrong type for the XFormModels settings!" ); + return; + } + + try + { + const Sequence< OUString > aSettingsForModels( xModelSettings->getElementNames() ); + for ( auto const & modelName : aSettingsForModels ) + { + // the settings for this particular model + Sequence< PropertyValue > aModelSettings; + OSL_VERIFY( xModelSettings->getByName( modelName ) >>= aModelSettings ); + + // the model itself + if ( !_rXForms->hasByName( modelName ) ) + { + OSL_FAIL( "applyXFormsSettings: have settings for a non-existent XForms model!" ); + continue; + } + + // propagate the settings, being tolerant by omitting properties which are not supported + Reference< XPropertySet > xModelProps( _rXForms->getByName( modelName ), UNO_QUERY_THROW ); + Reference< XPropertySetInfo > xModelPSI( xModelProps->getPropertySetInfo(), UNO_SET_THROW ); + + for ( auto const & setting : std::as_const(aModelSettings) ) + { + if ( !xModelPSI->hasPropertyByName( setting.Name ) ) + { + OSL_FAIL( "applyXFormsSettings: non-existent model property!" ); + continue; + } + + xModelProps->setPropertyValue( setting.Name, setting.Value ); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |