diff options
Diffstat (limited to 'xmloff/source/text')
142 files changed, 43835 insertions, 0 deletions
diff --git a/xmloff/source/text/XMLAnchorTypePropHdl.hxx b/xmloff/source/text/XMLAnchorTypePropHdl.hxx new file mode 100644 index 0000000000..64bddb078f --- /dev/null +++ b/xmloff/source/text/XMLAnchorTypePropHdl.hxx @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <xmloff/xmlprhdl.hxx> + + +class XMLAnchorTypePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLAnchorTypePropHdl () override; + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const override; + static bool convert( std::string_view rStrImpValue, + css::text::TextContentAnchorType& rType ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAutoMarkFileContext.cxx b/xmloff/source/text/XMLAutoMarkFileContext.cxx new file mode 100644 index 0000000000..c7237aa783 --- /dev/null +++ b/xmloff/source/text/XMLAutoMarkFileContext.cxx @@ -0,0 +1,81 @@ +/* -*- 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 "XMLAutoMarkFileContext.hxx" +#include <xmloff/xmlimp.hxx> +#include <rtl/ustring.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <sal/log.hxx> + + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::beans::XPropertySet; + +using ::xmloff::token::XML_HREF; + + +XMLAutoMarkFileContext::XMLAutoMarkFileContext( + SvXMLImport& rImport) : + SvXMLImportContext(rImport) +{ +} + +XMLAutoMarkFileContext::~XMLAutoMarkFileContext() +{ +} + + +void XMLAutoMarkFileContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // scan for text:alphabetical-index-auto-mark-file attribute, and if + // found set value with the document + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(XLINK, XML_HREF): + { + Any aAny; + aAny <<= GetImport().GetAbsoluteReference( aIter.toString() ); + Reference<XPropertySet> xPropertySet( + GetImport().GetModel(), UNO_QUERY ); + if (xPropertySet.is()) + { + xPropertySet->setPropertyValue( "IndexAutoMarkFileURL", aAny ); + } + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAutoMarkFileContext.hxx b/xmloff/source/text/XMLAutoMarkFileContext.hxx new file mode 100644 index 0000000000..cf74dd596a --- /dev/null +++ b/xmloff/source/text/XMLAutoMarkFileContext.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> + + +namespace com::sun::star { + namespace uno { template<class X> class Reference; } + namespace beans { class XPropertySet; } + namespace xml::sax { class XAttributeList; } +} + + +class XMLAutoMarkFileContext : public SvXMLImportContext +{ +public: + + XMLAutoMarkFileContext( + SvXMLImport& rImport); + + virtual ~XMLAutoMarkFileContext() override; + +protected: + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAutoTextContainerEventImport.cxx b/xmloff/source/text/XMLAutoTextContainerEventImport.cxx new file mode 100644 index 0000000000..9ac584865c --- /dev/null +++ b/xmloff/source/text/XMLAutoTextContainerEventImport.cxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "XMLAutoTextContainerEventImport.hxx" +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/container/XNameReplace.hpp> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/XMLEventsImportContext.hxx> +#include <sal/log.hxx> + + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::container::XNameReplace; +using ::xmloff::token::XML_EVENT_LISTENERS; + + +XMLAutoTextContainerEventImport::XMLAutoTextContainerEventImport( + SvXMLImport& rImport, + const Reference<XNameReplace> & rEvnts ) : + SvXMLImportContext(rImport), + rEvents(rEvnts) +{ +} + +XMLAutoTextContainerEventImport::~XMLAutoTextContainerEventImport() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLAutoTextContainerEventImport::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if ( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + return new XMLEventsImportContext(GetImport(), rEvents); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAutoTextContainerEventImport.hxx b/xmloff/source/text/XMLAutoTextContainerEventImport.hxx new file mode 100644 index 0000000000..2640f27edf --- /dev/null +++ b/xmloff/source/text/XMLAutoTextContainerEventImport.hxx @@ -0,0 +1,58 @@ +/* -*- 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 <com/sun/star/uno/Reference.hxx> + + +namespace com::sun::star { + namespace container { class XNameReplace; } + namespace xml::sax { class XAttributeList; } +} + + +/** + * Import the text:auto-text-container element. + * This only instantiates text:auto-text-group context. + */ +class XMLAutoTextContainerEventImport : public SvXMLImportContext +{ + /// the parent auto text container + const css::uno::Reference<css::container::XNameReplace> & rEvents; + +public: + + + XMLAutoTextContainerEventImport( + SvXMLImport& rImport, + const css::uno::Reference<css::container::XNameReplace > & rEvents ); + + virtual ~XMLAutoTextContainerEventImport() override; + + +protected: + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAutoTextEventExport.cxx b/xmloff/source/text/XMLAutoTextEventExport.cxx new file mode 100644 index 0000000000..b6a089e8a0 --- /dev/null +++ b/xmloff/source/text/XMLAutoTextEventExport.cxx @@ -0,0 +1,216 @@ +/* -*- 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 "XMLAutoTextEventExport.hxx" +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#include <com/sun/star/util/MeasureUnit.hpp> +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/container/XNameReplace.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <osl/diagnose.h> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/XMLEventExport.hxx> +#include <tools/debug.hxx> +#include <comphelper/processfactory.hxx> + + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::container::XNameReplace; +using ::com::sun::star::document::XEventsSupplier; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::xml::sax::XDocumentHandler; + + +XMLAutoTextEventExport::XMLAutoTextEventExport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + OUString const & implementationName, SvXMLExportFlags nFlags + ) +: SvXMLExport(xContext, implementationName, util::MeasureUnit::INCH, XML_AUTO_TEXT, nFlags) +{ +} + +XMLAutoTextEventExport::~XMLAutoTextEventExport() +{ +} + +void XMLAutoTextEventExport::initialize( + const Sequence<Any> & rArguments ) +{ + if (rArguments.getLength() > 1) + { + Reference<XEventsSupplier> xSupplier; + rArguments[1] >>= xSupplier; + if (xSupplier.is()) + { + xEvents = xSupplier->getEvents(); + } + else + { + Reference<XNameReplace> xReplace; + rArguments[1] >>= xReplace; + if (xReplace.is()) + { + xEvents = xReplace; + } + else + { + rArguments[1] >>= xEvents; + } + } + } + + // call super class (for XHandler) + SvXMLExport::initialize(rArguments); +} + + +ErrCode XMLAutoTextEventExport::exportDoc( enum XMLTokenEnum ) +{ + if( !(getExportFlags() & SvXMLExportFlags::OASIS) ) + { + Reference< uno::XComponentContext> xContext = getComponentContext(); + try + { + + Sequence<Any> aArgs{ Any(GetDocHandler()) }; + + // get filter component + Reference< xml::sax::XDocumentHandler > xTmpDocHandler( + xContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.comp.Oasis2OOoTransformer", + aArgs, + xContext), + UNO_QUERY); + OSL_ENSURE( xTmpDocHandler.is(), + "can't instantiate OASIS transformer component" ); + if( xTmpDocHandler.is() ) + { + SetDocHandler( xTmpDocHandler ); + } + } + catch( css::uno::Exception& ) + { + } + } + if (hasEvents()) + { + GetDocHandler()->startDocument(); + + addChaffWhenEncryptedStorage(); + + addNamespaces(); + + { + // container element + SvXMLElementExport aContainerElement( + *this, XML_NAMESPACE_OOO, XML_AUTO_TEXT_EVENTS, + true, true); + + exportEvents(); + } + + // and close document again + GetDocHandler()->endDocument(); + } + + return ERRCODE_NONE; +} + +bool XMLAutoTextEventExport::hasEvents() const +{ + // TODO: provide full implementation that check for presence of events + return xEvents.is(); +} + +void XMLAutoTextEventExport::addNamespaces() +{ + // namespaces for office:, text: and script: + GetAttrList().AddAttribute( + GetNamespaceMap().GetAttrNameByIndex( XML_NAMESPACE_OFFICE ), + GetNamespaceMap().GetNameByIndex( XML_NAMESPACE_OFFICE ) ); + GetAttrList().AddAttribute( + GetNamespaceMap().GetAttrNameByIndex( XML_NAMESPACE_TEXT ), + GetNamespaceMap().GetNameByIndex( XML_NAMESPACE_TEXT ) ); + GetAttrList().AddAttribute( + GetNamespaceMap().GetAttrNameByIndex( XML_NAMESPACE_SCRIPT ), + GetNamespaceMap().GetNameByIndex( XML_NAMESPACE_SCRIPT ) ); + GetAttrList().AddAttribute( + GetNamespaceMap().GetAttrNameByIndex( XML_NAMESPACE_DOM ), + GetNamespaceMap().GetNameByIndex( XML_NAMESPACE_DOM ) ); + GetAttrList().AddAttribute( + GetNamespaceMap().GetAttrNameByIndex( XML_NAMESPACE_OOO ), + GetNamespaceMap().GetNameByIndex( XML_NAMESPACE_OOO ) ); + GetAttrList().AddAttribute( + GetNamespaceMap().GetAttrNameByIndex( XML_NAMESPACE_XLINK ), + GetNamespaceMap().GetNameByIndex( XML_NAMESPACE_XLINK ) ); +} + +void XMLAutoTextEventExport::exportEvents() +{ + DBG_ASSERT(hasEvents(), "no events to export!"); + + GetEventExport().Export(xEvents); +} + + +// methods without content: + +void XMLAutoTextEventExport::ExportMeta_() {} +void XMLAutoTextEventExport::ExportScripts_() {} +void XMLAutoTextEventExport::ExportFontDecls_() {} +void XMLAutoTextEventExport::ExportStyles_( bool ) {} +void XMLAutoTextEventExport::ExportAutoStyles_() {} +void XMLAutoTextEventExport::ExportMasterStyles_() {} +void XMLAutoTextEventExport::ExportContent_() {} + + +// methods to support the component registration + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Writer_XMLOasisAutotextEventsExporter_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new XMLAutoTextEventExport( + context, "com.sun.star.comp.Writer.XMLOasisAutotextEventsExporter", + SvXMLExportFlags::ALL | SvXMLExportFlags::OASIS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Writer_XMLAutotextEventsExporter_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new XMLAutoTextEventExport( + context, "com.sun.star.comp.Writer.XMLAutotextEventsExporter", + SvXMLExportFlags::ALL)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAutoTextEventExport.hxx b/xmloff/source/text/XMLAutoTextEventExport.hxx new file mode 100644 index 0000000000..27e6de771c --- /dev/null +++ b/xmloff/source/text/XMLAutoTextEventExport.hxx @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <xmloff/xmlexp.hxx> + + +namespace com::sun::star { + namespace container { class XNameAccess; } + namespace frame { class XModel; } + namespace lang { class XMultiServiceFactory; } + namespace uno { template<class X> class Reference; } + namespace uno { template<class X> class Sequence; } + namespace uno { class XInterface; } + namespace uno { class Exception; } + namespace xml::sax { class XDocumentHandler; } +} + + +/** + * Component for the export of events attached to autotext blocks. + * Via the XInitialization interface it expects up to two strings, the + * first giving the file name (URL) of the autotext group, and the second + * identifying the autotext. If one of the strings is not given, it + * will export the whole group / all groups. + */ +class XMLAutoTextEventExport : public SvXMLExport +{ + css::uno::Reference<css::container::XNameAccess> xEvents; + +public: + + XMLAutoTextEventExport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, OUString const & implementationName, SvXMLExportFlags nFlags + ); + + virtual ~XMLAutoTextEventExport() override; + + // XInitialization + virtual void SAL_CALL initialize( + const css::uno::Sequence<css::uno::Any> & rArguments ) override; + +private: + + /// export the events off all autotexts + virtual ErrCode exportDoc( + enum ::xmloff::token::XMLTokenEnum eClass = xmloff::token::XML_TOKEN_INVALID ) override; + + /// does the document have any events ? + bool hasEvents() const; + + /// export the events element + void exportEvents(); + + + /// add the namespaces used by events + /// (to be called for the document element) + void addNamespaces(); + + + // methods without content: + virtual void ExportMeta_() override; + virtual void ExportScripts_() override; + virtual void ExportFontDecls_() override; + virtual void ExportStyles_( bool bUsed ) override ; + virtual void ExportAutoStyles_() override; + virtual void ExportMasterStyles_() override; + virtual void ExportContent_() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAutoTextEventImport.cxx b/xmloff/source/text/XMLAutoTextEventImport.cxx new file mode 100644 index 0000000000..cb76f062ba --- /dev/null +++ b/xmloff/source/text/XMLAutoTextEventImport.cxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "XMLAutoTextEventImport.hxx" +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include "XMLAutoTextContainerEventImport.hxx" +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <tools/debug.hxx> +#include <comphelper/processfactory.hxx> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Type; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::document::XEventsSupplier; +using ::com::sun::star::container::XNameReplace; +using ::xmloff::token::XML_AUTO_TEXT_EVENTS; + +XMLAutoTextEventImport::XMLAutoTextEventImport( + const css::uno::Reference<css::uno::XComponentContext>& xContext) + : SvXMLImport(xContext, "com.sun.star.comp.Writer.XMLOasisAutotextEventsImporter") +{ +} + +XMLAutoTextEventImport::~XMLAutoTextEventImport() noexcept {} + +void XMLAutoTextEventImport::initialize(const Sequence<Any>& rArguments) +{ + // The events may come as either an XNameReplace or XEventsSupplier. + + for (const auto& rArgument : rArguments) + { + const Type& rType = rArgument.getValueType(); + if (rType == cppu::UnoType<XEventsSupplier>::get()) + { + Reference<XEventsSupplier> xSupplier; + rArgument >>= xSupplier; + DBG_ASSERT(xSupplier.is(), "need XEventsSupplier or XNameReplace"); + + xEvents = xSupplier->getEvents(); + } + else if (rType == cppu::UnoType<XNameReplace>::get()) + { + rArgument >>= xEvents; + DBG_ASSERT(xEvents.is(), "need XEventsSupplier or XNameReplace"); + } + } + + // call parent + SvXMLImport::initialize(rArguments); +} + +SvXMLImportContext* XMLAutoTextEventImport::CreateFastContext( + sal_Int32 nElement, const Reference<css::xml::sax::XFastAttributeList>& /*xAttrList*/) +{ + if (xEvents.is() && nElement == XML_ELEMENT(OOO, XML_AUTO_TEXT_EVENTS)) + { + return new XMLAutoTextContainerEventImport(*this, xEvents); + } + return nullptr; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Writer_XMLOasisAutotextEventsImporter_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new XMLAutoTextEventImport(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAutoTextEventImport.hxx b/xmloff/source/text/XMLAutoTextEventImport.hxx new file mode 100644 index 0000000000..b79b231c53 --- /dev/null +++ b/xmloff/source/text/XMLAutoTextEventImport.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 <xmloff/xmlimp.hxx> +#include <com/sun/star/container/XNameReplace.hpp> +#include <com/sun/star/uno/Reference.hxx> + + +namespace com::sun::star { + namespace frame { class XModel; } + namespace text { class XAutoTextContainer; } + namespace text { class XAutoTextGroup; } + namespace text { class XAutoTextEntry; } + namespace uno { template<class X> class Reference; } + namespace uno { template<class X> class Sequence; } + namespace xml::sax { class XDocumentHandler; } +} + + +class XMLAutoTextEventImport : public SvXMLImport +{ + css::uno::Reference<css::container::XNameReplace> xEvents; + +public: + explicit XMLAutoTextEventImport( + const css::uno::Reference< css::uno::XComponentContext >& xContext); + + virtual ~XMLAutoTextEventImport() noexcept override; + + // XInitialization + virtual void SAL_CALL initialize( + const css::uno::Sequence<css::uno::Any> & rArguments ) override; + +protected: + + virtual SvXMLImportContext *CreateFastContext( sal_Int32 Element, + const ::css::uno::Reference< ::css::xml::sax::XFastAttributeList >& xAttrList ) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLCalculationSettingsContext.cxx b/xmloff/source/text/XMLCalculationSettingsContext.cxx new file mode 100644 index 0000000000..fa7ff42365 --- /dev/null +++ b/xmloff/source/text/XMLCalculationSettingsContext.cxx @@ -0,0 +1,73 @@ +/* -*- 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 "XMLCalculationSettingsContext.hxx" + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/text/XTextDocument.hpp> + +#include <sal/log.hxx> +#include <sax/tools/converter.hxx> + +#include <xmloff/xmlimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + +XMLCalculationSettingsContext::XMLCalculationSettingsContext( SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +: SvXMLImportContext ( rImport ) +, nYear( 1930 ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if (aIter.getToken() == XML_ELEMENT(TABLE, XML_NULL_YEAR) ) + { + nYear = static_cast <sal_Int16> (aIter.toInt32()); + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +XMLCalculationSettingsContext::~XMLCalculationSettingsContext() +{ +} +void XMLCalculationSettingsContext::endFastElement(sal_Int32 ) +{ + if (nYear != 1930 ) + { + Reference < XTextDocument > xTextDoc ( GetImport().GetModel(), UNO_QUERY); + if (xTextDoc.is()) + { + Reference < XPropertySet > xPropSet ( xTextDoc, UNO_QUERY ); + xPropSet->setPropertyValue ( "TwoDigitYear", Any(nYear) ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLCalculationSettingsContext.hxx b/xmloff/source/text/XMLCalculationSettingsContext.hxx new file mode 100644 index 0000000000..d0668b2e51 --- /dev/null +++ b/xmloff/source/text/XMLCalculationSettingsContext.hxx @@ -0,0 +1,38 @@ +/* -*- 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> + +class XMLCalculationSettingsContext : public SvXMLImportContext +{ + sal_Int16 nYear; +public: + XMLCalculationSettingsContext( SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + + virtual ~XMLCalculationSettingsContext() override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangeElementImportContext.cxx b/xmloff/source/text/XMLChangeElementImportContext.cxx new file mode 100644 index 0000000000..550bbcd965 --- /dev/null +++ b/xmloff/source/text/XMLChangeElementImportContext.cxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "XMLChangeElementImportContext.hxx" +#include "XMLChangedRegionImportContext.hxx" +#include "XMLChangeInfoContext.hxx" +#include <com/sun/star/uno/Reference.h> +#include <utility> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> + + +using ::com::sun::star::uno::Reference; +using ::xmloff::token::XML_CHANGE_INFO; + + +XMLChangeElementImportContext::XMLChangeElementImportContext( + SvXMLImport& rImport, + bool bAccContent, + XMLChangedRegionImportContext& rParent, + OUString aType) : + SvXMLImportContext(rImport), + bAcceptContent(bAccContent), + maType(std::move(aType)), + rChangedRegion(rParent) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLChangeElementImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContextRef xContext; + + if ( nElement == XML_ELEMENT(OFFICE, XML_CHANGE_INFO) ) + { + xContext = new XMLChangeInfoContext(GetImport(), + rChangedRegion, maType); + } + else + { + // import into redline -> create XText + rChangedRegion.UseRedlineText(); + + xContext = GetImport().GetTextImport()->CreateTextChildContext( + GetImport(), nElement, xAttrList, + XMLTextType::ChangedRegion); + + if (!xContext) + { + // no text element + // illegal element content! TODO: discard this redline! + // for the moment -> use default + } + } + + return xContext; +} + +void XMLChangeElementImportContext::startFastElement( sal_Int32, const Reference< css::xml::sax::XFastAttributeList >& ) +{ + if(bAcceptContent) + { + GetImport().GetTextImport()->SetInsideDeleteContext(true); + } +} + +void XMLChangeElementImportContext::endFastElement(sal_Int32 ) +{ + if(bAcceptContent) + { + GetImport().GetTextImport()->SetInsideDeleteContext(false); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangeElementImportContext.hxx b/xmloff/source/text/XMLChangeElementImportContext.hxx new file mode 100644 index 0000000000..7cd7c85975 --- /dev/null +++ b/xmloff/source/text/XMLChangeElementImportContext.hxx @@ -0,0 +1,80 @@ +/* -*- 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 <com/sun/star/uno/Reference.h> + + +namespace com::sun::star { + namespace xml::sax { + class XAttributeList; + } +} +class XMLChangedRegionImportContext; + + +/** + * Import <text:deletion> and <text:insertion> elements contained in a + * <text:changed-region> element. + */ + class XMLChangeElementImportContext : public SvXMLImportContext +{ + /** + * accept text content (paragraphs) in element as redline content? + * + * From the "5.5.4 <text:deletion>" section of the ODF 1.2 standard : + * The <text:deletion> element may also contain content that was + * deleted while change tracking was enabled. + * + * No other section in the "5.5 Change Tracking" chapter contain + * this sentence. + * + * So if bAcceptContent is true, we are importing a <text:deletion> element + */ + bool bAcceptContent; + + OUString maType; + + /// context of enclosing <text:changed-region> element + XMLChangedRegionImportContext& rChangedRegion; + +public: + + XMLChangeElementImportContext( + SvXMLImport& rImport, + /// accept text content (paragraphs) in element as redline content? + bool bAcceptContent, + /// context of enclosing <text:changed-region> element + XMLChangedRegionImportContext& rParent, + OUString aType); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + // Start- and EndElement are needed here to set the inside_deleted_section + // flag at the corresponding TextImportHelper + virtual void SAL_CALL startFastElement( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangeImportContext.cxx b/xmloff/source/text/XMLChangeImportContext.cxx new file mode 100644 index 0000000000..35e766e768 --- /dev/null +++ b/xmloff/source/text/XMLChangeImportContext.cxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "XMLChangeImportContext.hxx" +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmltoken.hxx> +#include <sal/log.hxx> + +using ::com::sun::star::uno::Reference; +using ::xmloff::token::XML_CHANGE_ID; + + +XMLChangeImportContext::XMLChangeImportContext( + SvXMLImport& rImport, + Element const eElement, + bool bOutsideOfParagraph) + : SvXMLImportContext(rImport) + , m_Element(eElement) + , m_bIsOutsideOfParagraph(bOutsideOfParagraph) +{ +} + +XMLChangeImportContext::~XMLChangeImportContext() +{ +} + +void XMLChangeImportContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_CHANGE_ID): + { + // Id found! Now call RedlineImportHelper + + // prepare parameters + rtl::Reference<XMLTextImportHelper> rHelper = + GetImport().GetTextImport(); + OUString sID = aIter.toString(); + + // <text:change> is both start and end + if (Element::START == m_Element || Element::POINT == m_Element) + rHelper->RedlineSetCursor(sID, true, m_bIsOutsideOfParagraph); + if (Element::END == m_Element || Element::POINT == m_Element) + rHelper->RedlineSetCursor(sID, false, m_bIsOutsideOfParagraph); + + // outside of paragraph and still open? set open redline ID + if (m_bIsOutsideOfParagraph) + { + rHelper->SetOpenRedlineId(sID); + } + break; + } + // else: ignore + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangeImportContext.hxx b/xmloff/source/text/XMLChangeImportContext.hxx new file mode 100644 index 0000000000..c2e128c552 --- /dev/null +++ b/xmloff/source/text/XMLChangeImportContext.hxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + + +#include <xmloff/xmlictxt.hxx> +#include <com/sun/star/uno/Reference.h> + + +namespace com::sun::star { + namespace xml::sax { + class XAttributeList; + } +} + + +/** + * import change tracking/redlining markers + * <text:change>, <text:change-start>, <text:change-end> + */ +class XMLChangeImportContext : public SvXMLImportContext +{ +public: + enum class Element { START, END, POINT }; + + /** + * import a change mark + * (<text:change>, <text:change-start>, <text:change-end>) + * Note: a <text:change> mark denotes start and end of a change + * simultaneously, as in Element::POINT. + */ + XMLChangeImportContext( + SvXMLImport& rImport, + Element eElement, + /// true if change mark is encountered outside of a paragraph + /// (usually before a section or table) + bool bIsOutsideOfParagraph); + + virtual ~XMLChangeImportContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + +private: + Element m_Element; + bool m_bIsOutsideOfParagraph; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangeInfoContext.cxx b/xmloff/source/text/XMLChangeInfoContext.cxx new file mode 100644 index 0000000000..8782013966 --- /dev/null +++ b/xmloff/source/text/XMLChangeInfoContext.cxx @@ -0,0 +1,86 @@ +/* -*- 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 "XMLChangeInfoContext.hxx" +#include "XMLChangedRegionImportContext.hxx" +#include <XMLStringBufferImportContext.hxx> +#include <com/sun/star/uno/Reference.h> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlimp.hxx> +#include <sal/log.hxx> + + +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Reference; + + +XMLChangeInfoContext::XMLChangeInfoContext( + SvXMLImport& rImport, + XMLChangedRegionImportContext& rPParent, + const OUString& rChangeType) +: SvXMLImportContext(rImport) +, rType(rChangeType) +, rChangedRegion(rPParent) +{ +} + +XMLChangeInfoContext::~XMLChangeInfoContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLChangeInfoContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContextRef xContext; + + switch (nElement) + { + case XML_ELEMENT(DC, XML_CREATOR): + xContext = new XMLStringBufferImportContext(GetImport(), sAuthorBuffer); + break; + case XML_ELEMENT(DC, XML_DATE): + xContext = new XMLStringBufferImportContext(GetImport(), sDateTimeBuffer); + break; + case XML_ELEMENT(LO_EXT, XML_MOVE_ID): + xContext = new XMLStringBufferImportContext(GetImport(), sMovedIDBuffer); + break; + case XML_ELEMENT(TEXT, XML_P): + case XML_ELEMENT(LO_EXT, XML_P): + xContext = new XMLStringBufferImportContext(GetImport(), sCommentBuffer); + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + + return xContext; +} + +void XMLChangeInfoContext::endFastElement(sal_Int32 ) +{ + // set values at changed region context + rChangedRegion.SetChangeInfo(rType, sAuthorBuffer.makeStringAndClear(), + sCommentBuffer.makeStringAndClear(), sDateTimeBuffer, + sMovedIDBuffer.makeStringAndClear()); + sDateTimeBuffer.setLength(0); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangeInfoContext.hxx b/xmloff/source/text/XMLChangeInfoContext.hxx new file mode 100644 index 0000000000..994e285d04 --- /dev/null +++ b/xmloff/source/text/XMLChangeInfoContext.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 <xmloff/xmlictxt.hxx> +#include <com/sun/star/uno/Reference.h> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } +} +class XMLChangedRegionImportContext; + + +/** + * Import <office:change-info> elements as children of <text:changed-region> + * elements. The attribute values will be passed to the enclosing + * XMLChangedRegionImportContext (which has to be passed down in the + * constructor). + */ +class XMLChangeInfoContext : public SvXMLImportContext +{ + const OUString& rType; + + OUStringBuffer sAuthorBuffer; + OUStringBuffer sDateTimeBuffer; + OUStringBuffer sMovedIDBuffer; + OUStringBuffer sCommentBuffer; + + XMLChangedRegionImportContext& rChangedRegion; + +public: + + + XMLChangeInfoContext( + SvXMLImport& rImport, + XMLChangedRegionImportContext& rChangedRegion, + const OUString& rChangeType); + + virtual ~XMLChangeInfoContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangedRegionImportContext.cxx b/xmloff/source/text/XMLChangedRegionImportContext.cxx new file mode 100644 index 0000000000..7143ee4d08 --- /dev/null +++ b/xmloff/source/text/XMLChangedRegionImportContext.cxx @@ -0,0 +1,176 @@ +/* -*- 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 "XMLChangedRegionImportContext.hxx" +#include "XMLChangeElementImportContext.hxx" +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/text/XTextCursor.hpp> + +#include <sal/log.hxx> +#include <sax/tools/converter.hxx> + +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmltoken.hxx> + + +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::text::XTextCursor; +using namespace ::com::sun::star; + + +XMLChangedRegionImportContext::XMLChangedRegionImportContext(SvXMLImport& rImport) : + SvXMLImportContext(rImport), + bMergeLastPara(true) +{ +} + +XMLChangedRegionImportContext::~XMLChangedRegionImportContext() +{ +} + +void XMLChangedRegionImportContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // process attributes: id + bool bHaveXmlId( false ); + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(XML, XML_ID): + { + sID = aIter.toString(); + bHaveXmlId = true; + break; + } + case XML_ELEMENT(TEXT, XML_ID): + { + if (!bHaveXmlId) { sID = aIter.toString(); } + break; + } + case XML_ELEMENT(TEXT, XML_MERGE_LAST_PARAGRAPH): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bMergeLastPara = bTmp; + } + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLChangedRegionImportContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContextRef xContext; + + // from the ODF 1.2 standard : + // The <text:changed-region> element has the following child elements: + // <text:deletion>, <text:format-change> and <text:insertion>. + if (nElement == XML_ELEMENT(TEXT, XML_INSERTION) || + nElement == XML_ELEMENT(TEXT, XML_DELETION) || + nElement == XML_ELEMENT(TEXT, XML_FORMAT_CHANGE) ) + { + // create XMLChangeElementImportContext for all kinds of changes + xContext = new XMLChangeElementImportContext( + GetImport(), + nElement == XML_ELEMENT(TEXT, XML_DELETION), + *this, + SvXMLImport::getNameFromToken(nElement)); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + // illegal element content! TODO: discard the redlines + // for the moment -> use text + // or default if text fail + + return xContext; +} + +void XMLChangedRegionImportContext::endFastElement(sal_Int32 ) +{ + // restore old XCursor (if necessary) + if (xOldCursor.is()) + { + // delete last paragraph + // (one extra paragraph was inserted in the beginning) + try + { + GetImport().GetTextImport()->DeleteParagraph(); + } + catch (uno::Exception const&) + { // cursor may be disposed - must reset to old cursor! + SAL_INFO("xmloff.text", "XMLChangedRegionImportContext: delete paragraph failed"); + } + + GetImport().GetTextImport()->SetCursor(xOldCursor); + xOldCursor = nullptr; + } +} + +void XMLChangedRegionImportContext::SetChangeInfo( + const OUString& rType, + const OUString& rAuthor, + const OUString& rComment, + std::u16string_view rDate, + const OUString& rMovedID) +{ + util::DateTime aDateTime; + if (::sax::Converter::parseDateTime(aDateTime, rDate)) + { + GetImport().GetTextImport()->RedlineAdd( + rType, sID, rAuthor, rComment, aDateTime, rMovedID, bMergeLastPara); + } +} + +void XMLChangedRegionImportContext::UseRedlineText() +{ + // if we haven't already installed the redline cursor, do it now + if ( xOldCursor.is()) + return; + + // get TextImportHelper and old Cursor + rtl::Reference<XMLTextImportHelper> rHelper(GetImport().GetTextImport()); + Reference<XTextCursor> xCursor( rHelper->GetCursor() ); + + // create Redline and new Cursor + Reference<XTextCursor> xNewCursor = + rHelper->RedlineCreateText(xCursor, sID); + + if (xNewCursor.is()) + { + // save old cursor and install new one + xOldCursor = xCursor; + rHelper->SetCursor( xNewCursor ); + } + // else: leave as is +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangedRegionImportContext.hxx b/xmloff/source/text/XMLChangedRegionImportContext.hxx new file mode 100644 index 0000000000..e05e97c932 --- /dev/null +++ b/xmloff/source/text/XMLChangedRegionImportContext.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <com/sun/star/uno/Reference.h> + + +namespace com::sun::star { + namespace text { + class XTextCursor; + } + namespace xml::sax { + class XAttributeList; + } +} + +/** + * Import <text:changed-region> elements contained in a + * <text:tracked-changes> element. + */ +class XMLChangedRegionImportContext : public SvXMLImportContext +{ + /// if we replace the current XTextCursor/XText by the ones for + /// the redline, we remember the old cursor here. + css::uno::Reference<css::text::XTextCursor> xOldCursor; + + /// redline-ID + OUString sID; + + /// merge-last-paragraph flag + bool bMergeLastPara; + +public: + + + XMLChangedRegionImportContext(SvXMLImport& rImport); + + virtual ~XMLChangedRegionImportContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + + /// change info: To be called from change-info context + void SetChangeInfo(const OUString& rType, + const OUString& rAuthor, + const OUString& rComment, + std::u16string_view rDate, + const OUString& rMovedId); + + /// create redline XText/XTextCursor on demand and register with + /// XMLTextImportHelper + void UseRedlineText(); +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLComplexColorContext.cxx b/xmloff/source/text/XMLComplexColorContext.cxx new file mode 100644 index 0000000000..c580b02225 --- /dev/null +++ b/xmloff/source/text/XMLComplexColorContext.cxx @@ -0,0 +1,172 @@ +/* -*- 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/. + */ + +#include <sal/config.h> + +#include <sal/log.hxx> +#include <sax/tools/converter.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlement.hxx> +#include <xmloff/xmlprhdl.hxx> +#include <xmloff/XMLComplexColorContext.hxx> +#include <docmodel/uno/UnoComplexColor.hxx> + +using namespace css; +using namespace xmloff::token; + +SvXMLEnumMapEntry<sal_Int16> const pXML_ThemeColor_Enum[] = { { XML_NONE, -1 }, + { XML_DARK1, 0 }, + { XML_LIGHT1, 1 }, + { XML_DARK2, 2 }, + { XML_LIGHT2, 3 }, + { XML_ACCENT1, 4 }, + { XML_ACCENT2, 5 }, + { XML_ACCENT3, 6 }, + { XML_ACCENT4, 7 }, + { XML_ACCENT5, 8 }, + { XML_ACCENT6, 9 }, + { XML_HYPERLINK, 10 }, + { XML_FOLLOWED_HYPERLINK, 11 }, + { XML_TOKEN_INVALID, 0 } }; + +XMLComplexColorImport::XMLComplexColorImport(model::ComplexColor& rComplexColor) + : mrComplexColor(rComplexColor) +{ +} + +void XMLComplexColorImport::fillAttributes( + const uno::Reference<xml::sax::XFastAttributeList>& xAttrList) +{ + for (auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(LO_EXT, XML_THEME_TYPE): + { + sal_Int16 nValue = -1; + if (SvXMLUnitConverter::convertEnum(nValue, aIter.toView(), pXML_ThemeColor_Enum)) + { + mrComplexColor.setThemeColor(model::convertToThemeColorType(nValue)); + } + break; + } + case XML_ELEMENT(LO_EXT, XML_COLOR_TYPE): + { + const OUString aValue = aIter.toString(); + if (aValue == u"theme") + mrComplexColor.setType(model::ColorType::Theme); + // TODO - handle other color types + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + break; + } + } +} + +bool XMLComplexColorImport::handleTransformContext( + sal_Int32 nElement, const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) +{ + if (nElement == XML_ELEMENT(LO_EXT, XML_TRANSFORMATION)) + { + auto eTransformationType = model::TransformationType::Undefined; + sal_Int16 nTransformationValue = 0; + for (auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(LO_EXT, XML_TYPE): + { + const OUString aValue = aIter.toString(); + if (aValue == u"tint") + eTransformationType = model::TransformationType::Tint; + else if (aValue == u"shade") + eTransformationType = model::TransformationType::Shade; + else if (aValue == u"lumoff") + eTransformationType = model::TransformationType::LumOff; + else if (aValue == u"lummod") + eTransformationType = model::TransformationType::LumMod; + break; + } + case XML_ELEMENT(LO_EXT, XML_VALUE): + { + sal_Int32 nValue; + if (::sax::Converter::convertNumber(nValue, aIter.toView(), SHRT_MIN, SHRT_MAX)) + nTransformationValue = static_cast<sal_Int16>(nValue); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + break; + } + } + mrComplexColor.addTransformation({ eTransformationType, nTransformationValue }); + return true; + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return false; +} + +XMLPropertyComplexColorContext::XMLPropertyComplexColorContext( + SvXMLImport& rImport, sal_Int32 nElement, + const uno::Reference<xml::sax::XFastAttributeList>& xAttrList, const XMLPropertyState& rProp, + std::vector<XMLPropertyState>& rProps) + : XMLElementPropertyContext(rImport, nElement, rProp, rProps) + , mnRootElement(nElement) + , maComplexColorImport(maComplexColor) +{ + maComplexColorImport.fillAttributes(xAttrList); +} + +css::uno::Reference<css::xml::sax::XFastContextHandler> +XMLPropertyComplexColorContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) +{ + if (maComplexColorImport.handleTransformContext(nElement, xAttrList)) + return this; + return nullptr; +} + +void XMLPropertyComplexColorContext::endFastElement(sal_Int32 nElement) +{ + if (nElement == mnRootElement) + { + if (getComplexColor().getThemeColorType() != model::ThemeColorType::Unknown) + { + aProp.maValue <<= model::color::createXComplexColor(getComplexColor()); + SetInsert(true); + } + } + XMLElementPropertyContext::endFastElement(nElement); +} + +XMLComplexColorContext::XMLComplexColorContext( + SvXMLImport& rImport, model::ComplexColor& rComplexColor, + const uno::Reference<xml::sax::XFastAttributeList>& xAttrList) + : SvXMLImportContext(rImport) + , maComplexColorImport(rComplexColor) +{ + maComplexColorImport.fillAttributes(xAttrList); +} + +css::uno::Reference<css::xml::sax::XFastContextHandler> +XMLComplexColorContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) +{ + if (maComplexColorImport.handleTransformContext(nElement, xAttrList)) + return this; + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLComplexColorExport.cxx b/xmloff/source/text/XMLComplexColorExport.cxx new file mode 100644 index 0000000000..feac9d0d6e --- /dev/null +++ b/xmloff/source/text/XMLComplexColorExport.cxx @@ -0,0 +1,97 @@ +/* -*- 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/. + */ + +#include <xmloff/XMLComplexColorExport.hxx> + +#include <sal/config.h> + +#include <docmodel/uno/UnoComplexColor.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlexp.hxx> +#include <array> + +using namespace css; +using namespace ::xmloff::token; + +XMLComplexColorExport::XMLComplexColorExport(SvXMLExport& rExport) + : mrExport(rExport) +{ +} + +namespace +{ +constexpr const std::array<XMLTokenEnum, 12> constThemeColorTypeToToken{ + XML_DARK1, XML_LIGHT1, XML_DARK2, XML_LIGHT2, XML_ACCENT1, XML_ACCENT2, + XML_ACCENT3, XML_ACCENT4, XML_ACCENT5, XML_ACCENT6, XML_HYPERLINK, XML_FOLLOWED_HYPERLINK +}; +} + +void XMLComplexColorExport::doExport(model::ComplexColor const& rComplexColor, sal_uInt16 nPrefix, + const OUString& rLocalName) +{ + auto eThemeType = rComplexColor.getThemeColorType(); + if (eThemeType == model::ThemeColorType::Unknown) + return; + + XMLTokenEnum nToken = constThemeColorTypeToToken[sal_Int16(eThemeType)]; + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_THEME_TYPE, nToken); + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_COLOR_TYPE, "theme"); + SvXMLElementExport aComplexColorElement(mrExport, nPrefix, rLocalName, true, true); + + for (auto const& rTransform : rComplexColor.getTransformations()) + { + OUString aType; + switch (rTransform.meType) + { + case model::TransformationType::Tint: + aType = "tint"; + break; + case model::TransformationType::Shade: + aType = "shade"; + break; + case model::TransformationType::LumMod: + aType = "lummod"; + break; + case model::TransformationType::LumOff: + aType = "lumoff"; + break; + default: + break; + } + if (!aType.isEmpty()) + { + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_TYPE, aType); + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_VALUE, + OUString::number(rTransform.mnValue)); + SvXMLElementExport aTransformElement(mrExport, XML_NAMESPACE_LO_EXT, XML_TRANSFORMATION, + true, true); + } + } +} + +void XMLComplexColorExport::exportComplexColor(model::ComplexColor const& rComplexColor, + sal_uInt16 nPrefix, XMLTokenEnum nToken) +{ + doExport(rComplexColor, nPrefix, GetXMLToken(nToken)); +} + +void XMLComplexColorExport::exportXML(const uno::Any& rAny, sal_uInt16 nPrefix, + const OUString& rLocalName) +{ + uno::Reference<util::XComplexColor> xComplexColor; + rAny >>= xComplexColor; + if (!xComplexColor.is()) + return; + + model::ComplexColor aComplexColor = model::color::getFromXComplexColor(xComplexColor); + doExport(aComplexColor, nPrefix, rLocalName); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLFootnoteBodyImportContext.cxx b/xmloff/source/text/XMLFootnoteBodyImportContext.cxx new file mode 100644 index 0000000000..2e9b76ccaa --- /dev/null +++ b/xmloff/source/text/XMLFootnoteBodyImportContext.cxx @@ -0,0 +1,47 @@ +/* -*- 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 "XMLFootnoteBodyImportContext.hxx" + +#include <rtl/ustring.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/txtimp.hxx> +#include <com/sun/star/xml/sax/XAttributeList.hpp> + +using ::com::sun::star::uno::Reference; + + +XMLFootnoteBodyImportContext::XMLFootnoteBodyImportContext( SvXMLImport& rImport ) : + SvXMLImportContext(rImport) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLFootnoteBodyImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // return text context + return + GetImport().GetTextImport()->CreateTextChildContext(GetImport(), + nElement, + xAttrList, + XMLTextType::Footnote); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLFootnoteBodyImportContext.hxx b/xmloff/source/text/XMLFootnoteBodyImportContext.hxx new file mode 100644 index 0000000000..d52557797e --- /dev/null +++ b/xmloff/source/text/XMLFootnoteBodyImportContext.hxx @@ -0,0 +1,49 @@ +/* -*- 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 <com/sun/star/uno/Reference.h> + + +namespace com::sun::star { + namespace xml::sax { + class XAttributeList; + } +} + + +/// import foot- and endnote body elements (<text:footnote-body>) +class XMLFootnoteBodyImportContext : public SvXMLImportContext +{ + +public: + + XMLFootnoteBodyImportContext( SvXMLImport& rImport ); + +protected: + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLFootnoteConfigurationImportContext.cxx b/xmloff/source/text/XMLFootnoteConfigurationImportContext.cxx new file mode 100644 index 0000000000..8e67b2d909 --- /dev/null +++ b/xmloff/source/text/XMLFootnoteConfigurationImportContext.cxx @@ -0,0 +1,335 @@ +/* -*- 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 <XMLFootnoteConfigurationImportContext.hxx> + +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> + +#include <sax/tools/converter.hxx> + +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlement.hxx> + +#include <xmloff/families.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlimp.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/text/XFootnotesSupplier.hpp> +#include <com/sun/star/text/XEndnotesSupplier.hpp> +#include <com/sun/star/text/FootnoteNumbering.hpp> +#include <com/sun/star/style/NumberingType.hpp> + + +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + + +// XMLFootnoteConfigHelper + +namespace { + +/// local helper class for import of quo-vadis and ergo-sum elements +class XMLFootnoteConfigHelper : public SvXMLImportContext +{ + OUStringBuffer sBuffer; + XMLFootnoteConfigurationImportContext& rConfig; + bool bIsBegin; + +public: + + XMLFootnoteConfigHelper( + SvXMLImport& rImport, + XMLFootnoteConfigurationImportContext& rConfigImport, + bool bBegin); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual void SAL_CALL characters( const OUString& rChars ) override; +}; + +} + +XMLFootnoteConfigHelper::XMLFootnoteConfigHelper( + SvXMLImport& rImport, + XMLFootnoteConfigurationImportContext& rConfigImport, + bool bBegin) +: SvXMLImportContext(rImport) +, rConfig(rConfigImport) +, bIsBegin(bBegin) +{ +} + +void XMLFootnoteConfigHelper::endFastElement(sal_Int32 ) +{ + if (bIsBegin) + { + rConfig.SetBeginNotice(sBuffer.makeStringAndClear()); + } + else + { + rConfig.SetEndNotice(sBuffer.makeStringAndClear()); + } +// rConfig = NULL; // import contexts are ref-counted +} + +void XMLFootnoteConfigHelper::characters( const OUString& rChars ) +{ + sBuffer.append(rChars); +} + + +// XMLFootnoteConfigurationImportContext + +constexpr OUStringLiteral gsPropertyAnchorCharStyleName(u"AnchorCharStyleName"); +constexpr OUStringLiteral gsPropertyCharStyleName(u"CharStyleName"); +constexpr OUStringLiteral gsPropertyNumberingType(u"NumberingType"); +constexpr OUStringLiteral gsPropertyPageStyleName(u"PageStyleName"); +constexpr OUStringLiteral gsPropertyParagraphStyleName(u"ParaStyleName"); +constexpr OUStringLiteral gsPropertyPrefix(u"Prefix"); +constexpr OUStringLiteral gsPropertyStartAt(u"StartAt"); +constexpr OUStringLiteral gsPropertySuffix(u"Suffix"); +constexpr OUStringLiteral gsPropertyPositionEndOfDoc(u"PositionEndOfDoc"); +constexpr OUStringLiteral gsPropertyFootnoteCounting(u"FootnoteCounting"); +constexpr OUStringLiteral gsPropertyEndNotice(u"EndNotice"); +constexpr OUStringLiteral gsPropertyBeginNotice(u"BeginNotice"); + +XMLFootnoteConfigurationImportContext::XMLFootnoteConfigurationImportContext( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference<XFastAttributeList> & xAttrList) +: SvXMLStyleContext(rImport, XmlStyleFamily::TEXT_FOOTNOTECONFIG) +, sNumFormat("1") +, sNumSync("false") +, nOffset(0) +, nNumbering(FootnoteNumbering::PER_PAGE) +, bPosition(false) +, bIsEndnote(false) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if( aIter.getToken() == XML_ELEMENT(TEXT, XML_NOTE_CLASS) ) + { + if( IsXMLToken(aIter, XML_ENDNOTE ) ) + { + bIsEndnote = true; + SetFamily( XmlStyleFamily::TEXT_FOOTNOTECONFIG ); + } + break; + } + } + +} +XMLFootnoteConfigurationImportContext::~XMLFootnoteConfigurationImportContext() +{ +} + +SvXMLEnumMapEntry<sal_Int16> const aFootnoteNumberingMap[] = +{ + { XML_PAGE, FootnoteNumbering::PER_PAGE }, + { XML_CHAPTER, FootnoteNumbering::PER_CHAPTER }, + { XML_DOCUMENT, FootnoteNumbering::PER_DOCUMENT }, + { XML_TOKEN_INVALID, 0 }, +}; + +void XMLFootnoteConfigurationImportContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_CITATION_STYLE_NAME): + sCitationStyle = rValue; + break; + case XML_ELEMENT(TEXT, XML_CITATION_BODY_STYLE_NAME): + sAnchorStyle = rValue; + break; + case XML_ELEMENT(TEXT, XML_DEFAULT_STYLE_NAME): + sDefaultStyle = rValue; + break; + case XML_ELEMENT(TEXT, XML_MASTER_PAGE_NAME): + sPageStyle = rValue; + break; + case XML_ELEMENT(TEXT, XML_START_VALUE): + case XML_ELEMENT(TEXT, XML_OFFSET): // for backwards compatibility with SRC630 & earlier + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber(nTmp, rValue)) + { + nOffset = static_cast<sal_uInt16>(nTmp); + } + break; + } + case XML_ELEMENT(STYLE, XML_NUM_PREFIX): + case XML_ELEMENT(TEXT, XML_NUM_PREFIX): // for backwards compatibility with SRC630 & earlier + sPrefix = rValue; + break; + case XML_ELEMENT(STYLE, XML_NUM_SUFFIX): + case XML_ELEMENT(TEXT, XML_NUM_SUFFIX): // for backwards compatibility with SRC630 & earlier + sSuffix = rValue; + break; + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + sNumFormat = rValue; + break; + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + sNumSync = rValue; + break; + case XML_ELEMENT(TEXT, XML_START_NUMBERING_AT): + { + (void)SvXMLUnitConverter::convertEnum(nNumbering, rValue, + aFootnoteNumberingMap); + break; + } + case XML_ELEMENT(TEXT, XML_FOOTNOTES_POSITION): + bPosition = IsXMLToken( rValue, XML_DOCUMENT ); + break; + default: + ; // ignore + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLFootnoteConfigurationImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + css::uno::Reference< css::xml::sax::XFastContextHandler > xContext; + + if (bIsEndnote) + return nullptr; + + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_FOOTNOTE_CONTINUATION_NOTICE_FORWARD): + xContext = new XMLFootnoteConfigHelper(GetImport(), *this, false); + break; + case XML_ELEMENT(TEXT, XML_FOOTNOTE_CONTINUATION_NOTICE_BACKWARD): + xContext = new XMLFootnoteConfigHelper(GetImport(), *this, true); + break; + } + + return xContext; +} + +// Rename method <CreateAndInsertLate(..)> to <Finish(..)> (#i40597#) +void XMLFootnoteConfigurationImportContext::Finish( bool bOverwrite ) +{ + + if (!bOverwrite) + return; + + if (bIsEndnote) + { + Reference<XEndnotesSupplier> xSupplier( + GetImport().GetModel(), UNO_QUERY); + if (xSupplier.is()) + { + ProcessSettings(xSupplier->getEndnoteSettings()); + } + } + else + { + Reference<XFootnotesSupplier> xSupplier( + GetImport().GetModel(), UNO_QUERY); + if (xSupplier.is()) + { + ProcessSettings(xSupplier->getFootnoteSettings()); + } + } + // else: ignore (there's only one configuration, so we can only overwrite) +} + +void XMLFootnoteConfigurationImportContext::ProcessSettings( + const Reference<XPropertySet> & rConfig) +{ + Any aAny; + + if (!sCitationStyle.isEmpty()) + { + aAny <<= GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, sCitationStyle ); + rConfig->setPropertyValue(gsPropertyCharStyleName, aAny); + } + + if (!sAnchorStyle.isEmpty()) + { + aAny <<= GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, sAnchorStyle ); + rConfig->setPropertyValue(gsPropertyAnchorCharStyleName, aAny); + } + + if (!sPageStyle.isEmpty()) + { + aAny <<= GetImport().GetStyleDisplayName( + XmlStyleFamily::MASTER_PAGE, sPageStyle ); + rConfig->setPropertyValue(gsPropertyPageStyleName, aAny); + } + + if (!sDefaultStyle.isEmpty()) + { + aAny <<= GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_PARAGRAPH, sDefaultStyle ); + rConfig->setPropertyValue(gsPropertyParagraphStyleName, aAny); + } + + rConfig->setPropertyValue(gsPropertyPrefix, Any(sPrefix)); + + rConfig->setPropertyValue(gsPropertySuffix, Any(sSuffix)); + + sal_Int16 nNumType = NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, sNumFormat, + sNumSync ); + // #i61399: Corrupt file? It contains "Bullet" as numbering style for footnotes. + // Okay, even it seems to be corrupt, we will oversee this and set the style to ARABIC + if( NumberingType::CHAR_SPECIAL == nNumType ) + nNumType = NumberingType::ARABIC; + + rConfig->setPropertyValue(gsPropertyNumberingType, Any(nNumType)); + + rConfig->setPropertyValue(gsPropertyStartAt, Any(nOffset)); + + if (!bIsEndnote) + { + rConfig->setPropertyValue(gsPropertyPositionEndOfDoc, Any(bPosition)); + rConfig->setPropertyValue(gsPropertyFootnoteCounting, Any(nNumbering)); + rConfig->setPropertyValue(gsPropertyEndNotice, Any(sEndNotice)); + rConfig->setPropertyValue(gsPropertyBeginNotice, Any(sBeginNotice)); + } +} + +void XMLFootnoteConfigurationImportContext::SetBeginNotice( + const OUString& sText) +{ + sBeginNotice = sText; +} + +void XMLFootnoteConfigurationImportContext::SetEndNotice( + const OUString& sText) +{ + sEndNotice = sText; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLFootnoteImportContext.cxx b/xmloff/source/text/XMLFootnoteImportContext.cxx new file mode 100644 index 0000000000..cf206e5d6e --- /dev/null +++ b/xmloff/source/text/XMLFootnoteImportContext.cxx @@ -0,0 +1,168 @@ +/* -*- 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 "XMLFootnoteImportContext.hxx" + +#include <rtl/ustring.hxx> +#include <sal/log.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/txtimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> + +#include "XMLFootnoteBodyImportContext.hxx" + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/text/XFootnote.hpp> + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +XMLFootnoteImportContext::XMLFootnoteImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp ) +: SvXMLImportContext(rImport) +, mbListContextPushed(false) +, rHelper(rHlp) +{ +} + +void XMLFootnoteImportContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // create footnote + Reference<XMultiServiceFactory> xFactory(GetImport().GetModel(), + UNO_QUERY); + if( !xFactory.is() ) + return; + + // create endnote or footnote + bool bIsEndnote = false; + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(TEXT, XML_NOTE_CLASS) ) + { + if( IsXMLToken( aIter, XML_ENDNOTE ) ) + bIsEndnote = true; + break; + } + } + + Reference<XInterface> xIfc = xFactory->createInstance( + bIsEndnote ? + OUString("com.sun.star.text.Endnote") : + OUString("com.sun.star.text.Footnote") ); + + // attach footnote to document + Reference<XTextContent> xTextContent(xIfc, UNO_QUERY); + rHelper.InsertTextContent(xTextContent); + + // process id attribute + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(TEXT, XML_ID) ) + { + // get ID ... + Reference<XPropertySet> xPropertySet(xTextContent, UNO_QUERY); + Any aAny =xPropertySet->getPropertyValue("ReferenceId"); + sal_Int16 nID = 0; + aAny >>= nID; + + // ... and insert into map + rHelper.InsertFootnoteID( aIter.toString(), nID); + break; + } + } + + // save old cursor and install new one + xOldCursor = rHelper.GetCursor(); + Reference<XText> xText(xTextContent, UNO_QUERY); + rHelper.SetCursor(xText->createTextCursor()); + + // remember old list item and block (#89891#) and reset them + // for the footnote + rHelper.PushListContext(); + mbListContextPushed = true; + + // remember footnote (for CreateChildContext) + xFootnote.set(xTextContent, UNO_QUERY); + + // else: ignore footnote! Content will be merged into document. +} + +void XMLFootnoteImportContext::endFastElement(sal_Int32 ) +{ + // get rid of last dummy paragraph + rHelper.DeleteParagraph(); + + // reinstall old cursor + rHelper.SetCursor(xOldCursor); + + // reinstall old list item + if (mbListContextPushed) { + rHelper.PopListContext(); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLFootnoteImportContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContextRef xContext; + + switch(nElement) + { + case XML_ELEMENT(TEXT, XML_NOTE_CITATION): + { + // little hack: we only care for one attribute of the citation + // element. We handle that here, and then return a + // default context. + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_LABEL) ) + xFootnote->setLabel(aIter.toString()); + } + + // ignore content: return default context + break; + } + + case XML_ELEMENT(TEXT, XML_NOTE_BODY): + // return footnote body + xContext = new XMLFootnoteBodyImportContext(GetImport()); + break; + + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + + return xContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLFootnoteImportContext.hxx b/xmloff/source/text/XMLFootnoteImportContext.hxx new file mode 100644 index 0000000000..d05b7b631c --- /dev/null +++ b/xmloff/source/text/XMLFootnoteImportContext.hxx @@ -0,0 +1,72 @@ +/* -*- 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 <com/sun/star/uno/Reference.h> + + +namespace com::sun::star { + namespace text { + class XTextCursor; + class XFootnote; + } + namespace xml::sax { + class XAttributeList; + } +} +class XMLTextImportHelper; + +/// import footnote elements (<text:footnote>) +class XMLFootnoteImportContext : public SvXMLImportContext +{ + /// old document cursor + css::uno::Reference<css::text::XTextCursor> xOldCursor; + + /// old list item and block (#89891#) + bool mbListContextPushed; + + /// text import helper; holds current XTextCursor (and XText) + XMLTextImportHelper& rHelper; + + /// the footnote + css::uno::Reference<css::text::XFootnote> xFootnote; + +public: + + + XMLFootnoteImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp ); + +protected: + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexAlphabeticalSourceContext.cxx b/xmloff/source/text/XMLIndexAlphabeticalSourceContext.cxx new file mode 100644 index 0000000000..fe6013619d --- /dev/null +++ b/xmloff/source/text/XMLIndexAlphabeticalSourceContext.cxx @@ -0,0 +1,212 @@ +/* -*- 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 "XMLIndexAlphabeticalSourceContext.hxx" + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameContainer.hpp> + +#include <sax/tools/converter.hxx> + +#include "XMLIndexTemplateContext.hxx" +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/txtimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <rtl/ustring.hxx> + + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using namespace ::xmloff::token; + +XMLIndexAlphabeticalSourceContext::XMLIndexAlphabeticalSourceContext( + SvXMLImport& rImport, + Reference<XPropertySet> & rPropSet) +: XMLIndexSourceBaseContext(rImport, rPropSet, UseStyles::None) +, bMainEntryStyleNameOK(false) +, bSeparators(false) +, bCombineEntries(true) +, bCaseSensitive(true) +, bEntry(false) +, bUpperCase(false) +, bCombineDash(false) +, bCombinePP(true) +, bCommaSeparated(false) +{ +} + +XMLIndexAlphabeticalSourceContext::~XMLIndexAlphabeticalSourceContext() +{ +} + +void XMLIndexAlphabeticalSourceContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + bool bTmp(false); + + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_MAIN_ENTRY_STYLE_NAME): + { + sMainEntryStyleName = aIter.toString(); + OUString sDisplayStyleName = GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, sMainEntryStyleName ); + const Reference < css::container::XNameContainer >& + rStyles = GetImport().GetTextImport()->GetTextStyles(); + bMainEntryStyleNameOK = rStyles.is() && rStyles->hasByName( sDisplayStyleName ); + } + break; + + case XML_ELEMENT(TEXT, XML_IGNORE_CASE): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bCaseSensitive = !bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_SEPARATORS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bSeparators = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_COMBINE_ENTRIES): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bCombineEntries = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_COMBINE_ENTRIES_WITH_DASH): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bCombineDash = bTmp; + } + break; + case XML_ELEMENT(TEXT, XML_USE_KEYS_AS_ENTRIES): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bEntry = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_COMBINE_ENTRIES_WITH_PP): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bCombinePP = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_CAPITALIZE_ENTRIES): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUpperCase = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_COMMA_SEPARATED): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bCommaSeparated = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_SORT_ALGORITHM): + sAlgorithm = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_RFC_LANGUAGE_TAG): + maLanguageTagODF.maRfcLanguageTag = aIter.toString(); + break; + case XML_ELEMENT(FO, XML_LANGUAGE): + maLanguageTagODF.maLanguage = aIter.toString(); + break; + case XML_ELEMENT(FO, XML_SCRIPT): + maLanguageTagODF.maScript = aIter.toString(); + break; + case XML_ELEMENT(FO, XML_COUNTRY): + maLanguageTagODF.maCountry = aIter.toString(); + break; + + default: + XMLIndexSourceBaseContext::ProcessAttribute(aIter); + break; + } +} + +void XMLIndexAlphabeticalSourceContext::endFastElement(sal_Int32 nElement) +{ + + Any aAny; + + if (bMainEntryStyleNameOK) + { + aAny <<= GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, sMainEntryStyleName ); + rIndexPropertySet->setPropertyValue("MainEntryCharacterStyleName",aAny); + } + + rIndexPropertySet->setPropertyValue("UseAlphabeticalSeparators", css::uno::Any(bSeparators)); + rIndexPropertySet->setPropertyValue("UseCombinedEntries", css::uno::Any(bCombineEntries)); + rIndexPropertySet->setPropertyValue("IsCaseSensitive", css::uno::Any(bCaseSensitive)); + rIndexPropertySet->setPropertyValue("UseKeyAsEntry", css::uno::Any(bEntry)); + rIndexPropertySet->setPropertyValue("UseUpperCase", css::uno::Any(bUpperCase)); + rIndexPropertySet->setPropertyValue("UseDash", css::uno::Any(bCombineDash)); + rIndexPropertySet->setPropertyValue("UsePP", css::uno::Any(bCombinePP)); + rIndexPropertySet->setPropertyValue("IsCommaSeparated", css::uno::Any(bCommaSeparated)); + + + if (!sAlgorithm.isEmpty()) + { + rIndexPropertySet->setPropertyValue("SortAlgorithm", css::uno::Any(sAlgorithm)); + } + + if ( !maLanguageTagODF.isEmpty() ) + { + aAny <<= maLanguageTagODF.getLanguageTag().getLocale( false); + rIndexPropertySet->setPropertyValue("Locale", aAny); + } + + XMLIndexSourceBaseContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexAlphabeticalSourceContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_ENTRY_TEMPLATE) ) + { + return new XMLIndexTemplateContext(GetImport(), rIndexPropertySet, + aLevelNameAlphaMap, + XML_OUTLINE_LEVEL, + aLevelStylePropNameAlphaMap, + aAllowedTokenTypesAlpha); + } + else + { + return XMLIndexSourceBaseContext::createFastChildContext(nElement, + xAttrList); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexAlphabeticalSourceContext.hxx b/xmloff/source/text/XMLIndexAlphabeticalSourceContext.hxx new file mode 100644 index 0000000000..45fcea4ba0 --- /dev/null +++ b/xmloff/source/text/XMLIndexAlphabeticalSourceContext.hxx @@ -0,0 +1,73 @@ +/* -*- 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 "XMLIndexSourceBaseContext.hxx" +#include <xmloff/languagetagodf.hxx> +#include <com/sun/star/uno/Reference.h> + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +/** + * Import alphabetical (keyword) index source element + */ +class XMLIndexAlphabeticalSourceContext : public XMLIndexSourceBaseContext +{ + LanguageTagODF maLanguageTagODF; + OUString sAlgorithm; + + OUString sMainEntryStyleName; + bool bMainEntryStyleNameOK; + + bool bSeparators; + bool bCombineEntries; + bool bCaseSensitive; + bool bEntry; + bool bUpperCase; + bool bCombineDash; + bool bCombinePP; + bool bCommaSeparated; + +public: + + + XMLIndexAlphabeticalSourceContext( + SvXMLImport& rImport, + css::uno::Reference<css::beans::XPropertySet> & rPropSet); + + virtual ~XMLIndexAlphabeticalSourceContext() override; + +protected: + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexBibliographyConfigurationContext.cxx b/xmloff/source/text/XMLIndexBibliographyConfigurationContext.cxx new file mode 100644 index 0000000000..e7ba5e6bae --- /dev/null +++ b/xmloff/source/text/XMLIndexBibliographyConfigurationContext.cxx @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <comphelper/propertyvalue.hxx> +#include <XMLIndexBibliographyConfigurationContext.hxx> +#include "XMLIndexBibliographyEntryContext.hxx" +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/txtimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <sal/log.hxx> +#include <sax/tools/converter.hxx> +#include <rtl/ustring.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <comphelper/sequence.hxx> + +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +using ::com::sun::star::xml::sax::XFastAttributeList; +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::lang::XMultiServiceFactory; + + +constexpr OUString gsFieldMaster_Bibliography(u"com.sun.star.text.FieldMaster.Bibliography"_ustr); +constexpr OUStringLiteral gsBracketBefore(u"BracketBefore"); +constexpr OUStringLiteral gsBracketAfter(u"BracketAfter"); +constexpr OUStringLiteral gsIsNumberEntries(u"IsNumberEntries"); +constexpr OUStringLiteral gsIsSortByPosition(u"IsSortByPosition"); +constexpr OUStringLiteral gsSortKeys(u"SortKeys"); +constexpr OUString gsSortKey(u"SortKey"_ustr); +constexpr OUString gsIsSortAscending(u"IsSortAscending"_ustr); +constexpr OUStringLiteral gsSortAlgorithm(u"SortAlgorithm"); +constexpr OUStringLiteral gsLocale(u"Locale"); + +XMLIndexBibliographyConfigurationContext::XMLIndexBibliographyConfigurationContext( + SvXMLImport& rImport) : + SvXMLStyleContext(rImport, XmlStyleFamily::TEXT_BIBLIOGRAPHYCONFIG), + maLanguageTagODF(), + bNumberedEntries(false), + bSortByPosition(true) +{ +} + +XMLIndexBibliographyConfigurationContext::~XMLIndexBibliographyConfigurationContext() +{ +} + +void XMLIndexBibliographyConfigurationContext::SetAttribute( + sal_Int32 nElement, + const OUString& sValue) +{ + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_PREFIX): + sPrefix = sValue; + break; + case XML_ELEMENT(TEXT, XML_SUFFIX): + sSuffix = sValue; + break; + case XML_ELEMENT(TEXT, XML_NUMBERED_ENTRIES): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sValue)) + { + bNumberedEntries = bTmp; + } + break; + } + case XML_ELEMENT(TEXT, XML_SORT_BY_POSITION): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sValue)) + { + bSortByPosition = bTmp; + } + break; + } + case XML_ELEMENT(TEXT, XML_SORT_ALGORITHM): + sAlgorithm = sValue; + break; + case XML_ELEMENT(FO, XML_LANGUAGE): + maLanguageTagODF.maLanguage = sValue; + break; + case XML_ELEMENT(FO, XML_SCRIPT): + maLanguageTagODF.maScript = sValue; + break; + case XML_ELEMENT(FO, XML_COUNTRY): + maLanguageTagODF.maCountry = sValue; + break; + case XML_ELEMENT(STYLE, XML_RFC_LANGUAGE_TAG): + maLanguageTagODF.maRfcLanguageTag = sValue; + break; + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexBibliographyConfigurationContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // process children here and use default context! + if ( nElement == XML_ELEMENT(TEXT, XML_SORT_KEY) ) + { + std::string_view sKey; + bool bSort(true); + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_KEY): + sKey = aIter.toView(); + break; + case XML_ELEMENT(TEXT, XML_SORT_ASCENDING): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + bSort = bTmp; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + break; + } + } + + // valid data? + sal_uInt16 nKey; + if (SvXMLUnitConverter::convertEnum(nKey, sKey, + aBibliographyDataFieldMap)) + { + Sequence<PropertyValue> aKey + { + comphelper::makePropertyValue(gsSortKey, static_cast<sal_Int16>(nKey)), + comphelper::makePropertyValue(gsIsSortAscending, bSort) + }; + + aSortKeys.push_back(aKey); + } + } + + return nullptr; +} + +void XMLIndexBibliographyConfigurationContext::CreateAndInsert(bool) +{ + // (code almost the same as export...) + + // insert and block mode is handled in insertStyleFamily + + // first: get field master + // (we'll create one, and get the only master for this type) + Reference<XMultiServiceFactory> xFactory(GetImport().GetModel(),UNO_QUERY); + if( !xFactory.is() ) + return; + + Sequence<OUString> aServices = xFactory->getAvailableServiceNames(); + // here we should use a method which compares in reverse order if available + if (comphelper::findValue(aServices, gsFieldMaster_Bibliography) == -1) + return; + + Reference<XInterface> xIfc = + xFactory->createInstance(gsFieldMaster_Bibliography); + if( !xIfc.is() ) + return; + + Reference<XPropertySet> xPropSet( xIfc, UNO_QUERY ); + Any aAny; + + xPropSet->setPropertyValue(gsBracketAfter, Any(sSuffix)); + xPropSet->setPropertyValue(gsBracketBefore, Any(sPrefix)); + xPropSet->setPropertyValue(gsIsNumberEntries, Any(bNumberedEntries)); + xPropSet->setPropertyValue(gsIsSortByPosition, Any(bSortByPosition)); + + if( !maLanguageTagODF.isEmpty() ) + { + aAny <<= maLanguageTagODF.getLanguageTag().getLocale( false); + xPropSet->setPropertyValue(gsLocale, aAny); + } + + if( !sAlgorithm.isEmpty() ) + { + xPropSet->setPropertyValue(gsSortAlgorithm, Any(sAlgorithm)); + } + + Sequence<Sequence<PropertyValue> > aKeysSeq = comphelper::containerToSequence(aSortKeys); + xPropSet->setPropertyValue(gsSortKeys, Any(aKeysSeq)); + // else: can't get FieldMaster -> ignore + // else: can't even get Factory -> ignore +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexBibliographyEntryContext.cxx b/xmloff/source/text/XMLIndexBibliographyEntryContext.cxx new file mode 100644 index 0000000000..8ae78e9902 --- /dev/null +++ b/xmloff/source/text/XMLIndexBibliographyEntryContext.cxx @@ -0,0 +1,156 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "XMLIndexBibliographyEntryContext.hxx" +#include "XMLIndexTemplateContext.hxx" +#include <xmloff/xmlimp.hxx> +#include <xmloff/txtimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> +#include <com/sun/star/text/BibliographyDataField.hpp> +#include <sal/log.hxx> + + +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + + +XMLIndexBibliographyEntryContext::XMLIndexBibliographyEntryContext( + SvXMLImport& rImport, + XMLIndexTemplateContext& rTemplate ) : + XMLIndexSimpleEntryContext(rImport, + "TokenBibliographyDataField", + rTemplate), + nBibliographyInfo(BibliographyDataField::IDENTIFIER), + bBibliographyInfoOK(false) +{ +} + +XMLIndexBibliographyEntryContext::~XMLIndexBibliographyEntryContext() +{ +} + +const SvXMLEnumMapEntry<sal_uInt16> aBibliographyDataFieldMap[] = +{ + { XML_ADDRESS, BibliographyDataField::ADDRESS }, + { XML_ANNOTE, BibliographyDataField::ANNOTE }, + { XML_AUTHOR, BibliographyDataField::AUTHOR }, + { XML_BIBLIOGRAPHY_TYPE, BibliographyDataField::BIBILIOGRAPHIC_TYPE }, + // #96658#: also read old documents (bib*i*liographic...) + { XML_BIBILIOGRAPHIC_TYPE, BibliographyDataField::BIBILIOGRAPHIC_TYPE }, + { XML_BOOKTITLE, BibliographyDataField::BOOKTITLE }, + { XML_CHAPTER, BibliographyDataField::CHAPTER }, + { XML_CUSTOM1, BibliographyDataField::CUSTOM1 }, + { XML_CUSTOM2, BibliographyDataField::CUSTOM2 }, + { XML_CUSTOM3, BibliographyDataField::CUSTOM3 }, + { XML_CUSTOM4, BibliographyDataField::CUSTOM4 }, + { XML_CUSTOM5, BibliographyDataField::CUSTOM5 }, + { XML_EDITION, BibliographyDataField::EDITION }, + { XML_EDITOR, BibliographyDataField::EDITOR }, + { XML_HOWPUBLISHED, BibliographyDataField::HOWPUBLISHED }, + { XML_IDENTIFIER, BibliographyDataField::IDENTIFIER }, + { XML_INSTITUTION, BibliographyDataField::INSTITUTION }, + { XML_ISBN, BibliographyDataField::ISBN }, + { XML_JOURNAL, BibliographyDataField::JOURNAL }, + { XML_MONTH, BibliographyDataField::MONTH }, + { XML_NOTE, BibliographyDataField::NOTE }, + { XML_NUMBER, BibliographyDataField::NUMBER }, + { XML_ORGANIZATIONS, BibliographyDataField::ORGANIZATIONS }, + { XML_PAGES, BibliographyDataField::PAGES }, + { XML_PUBLISHER, BibliographyDataField::PUBLISHER }, + { XML_REPORT_TYPE, BibliographyDataField::REPORT_TYPE }, + { XML_SCHOOL, BibliographyDataField::SCHOOL }, + { XML_SERIES, BibliographyDataField::SERIES }, + { XML_TITLE, BibliographyDataField::TITLE }, + { XML_URL, BibliographyDataField::URL }, + { XML_VOLUME, BibliographyDataField::VOLUME }, + { XML_YEAR, BibliographyDataField::YEAR }, + { XML_TOKEN_INVALID, 0 } +}; + +void XMLIndexBibliographyEntryContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // handle both, style name and bibliography info + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + { + m_sCharStyleName = aIter.toString(); + m_bCharStyleNameOK = true; + break; + } + case XML_ELEMENT(TEXT, XML_BIBLIOGRAPHY_DATA_FIELD): + { + sal_uInt16 nTmp; + if (SvXMLUnitConverter::convertEnum(nTmp, aIter.toView(), aBibliographyDataFieldMap)) + { + nBibliographyInfo = nTmp; + bBibliographyInfoOK = true; + } + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // if we have a style name, set it! + if (m_bCharStyleNameOK) + { + m_nValues++; + } + + // always bibliography; else element is not valid + m_nValues++; +} + +void XMLIndexBibliographyEntryContext::endFastElement(sal_Int32 nElement) +{ + // only valid, if we have bibliography info + if (bBibliographyInfoOK) + { + XMLIndexSimpleEntryContext::endFastElement(nElement); + } +} + +void XMLIndexBibliographyEntryContext::FillPropertyValues( + css::uno::Sequence<css::beans::PropertyValue> & rValues) +{ + // entry name and (optionally) style name in parent class + XMLIndexSimpleEntryContext::FillPropertyValues(rValues); + + // bibliography data field + sal_Int32 nIndex = m_bCharStyleNameOK ? 2 : 1; + auto pValues = rValues.getArray(); + pValues[nIndex].Name = "BibliographyDataField"; + pValues[nIndex].Value <<= nBibliographyInfo; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexBibliographyEntryContext.hxx b/xmloff/source/text/XMLIndexBibliographyEntryContext.hxx new file mode 100644 index 0000000000..4c586a5a85 --- /dev/null +++ b/xmloff/source/text/XMLIndexBibliographyEntryContext.hxx @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "XMLIndexSimpleEntryContext.hxx" +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/beans/PropertyValue.hpp> + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } +} +class XMLIndexTemplateContext; +template<typename EnumT> struct SvXMLEnumMapEntry; + +extern const SvXMLEnumMapEntry<sal_uInt16> aBibliographyDataFieldMap[]; + +/** + * Import bibliography index entry templates + */ +class XMLIndexBibliographyEntryContext : public XMLIndexSimpleEntryContext +{ + // bibliography info + sal_Int16 nBibliographyInfo; + bool bBibliographyInfoOK; + +public: + + + XMLIndexBibliographyEntryContext( + SvXMLImport& rImport, + XMLIndexTemplateContext& rTemplate ); + + virtual ~XMLIndexBibliographyEntryContext() override; + +protected: + + /** process parameters */ + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + /** call FillPropertyValues and insert into template */ + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + /** fill property values for this template entry */ + virtual void FillPropertyValues( + css::uno::Sequence<css::beans::PropertyValue> & rValues) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexBibliographySourceContext.cxx b/xmloff/source/text/XMLIndexBibliographySourceContext.cxx new file mode 100644 index 0000000000..426505fc27 --- /dev/null +++ b/xmloff/source/text/XMLIndexBibliographySourceContext.cxx @@ -0,0 +1,80 @@ +/* -*- 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 "XMLIndexBibliographySourceContext.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include "XMLIndexTemplateContext.hxx" +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> + + +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; + + +XMLIndexBibliographySourceContext::XMLIndexBibliographySourceContext( + SvXMLImport& rImport, + Reference<XPropertySet> & rPropSet) + : XMLIndexSourceBaseContext(rImport, rPropSet, UseStyles::None) +{ +} + +XMLIndexBibliographySourceContext::~XMLIndexBibliographySourceContext() +{ +} + +void XMLIndexBibliographySourceContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + // We have no attributes. Who wants attributes, anyway? + XMLOFF_WARN_UNKNOWN("xmloff", aIter); +} + +void XMLIndexBibliographySourceContext::endFastElement(sal_Int32 ) +{ + // No attributes, no properties. +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexBibliographySourceContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_BIBLIOGRAPHY_ENTRY_TEMPLATE) ) + { + return new XMLIndexTemplateContext(GetImport(), rIndexPropertySet, + aLevelNameBibliographyMap, + XML_BIBLIOGRAPHY_TYPE, + aLevelStylePropNameBibliographyMap, + aAllowedTokenTypesBibliography); + } + else + { + return XMLIndexSourceBaseContext::createFastChildContext(nElement, + xAttrList); + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexBibliographySourceContext.hxx b/xmloff/source/text/XMLIndexBibliographySourceContext.hxx new file mode 100644 index 0000000000..497c33d1cf --- /dev/null +++ b/xmloff/source/text/XMLIndexBibliographySourceContext.hxx @@ -0,0 +1,57 @@ +/* -*- 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 "XMLIndexSourceBaseContext.hxx" +#include <com/sun/star/uno/Reference.h> + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +/** + * Import bibliography source element + */ +class XMLIndexBibliographySourceContext : public XMLIndexSourceBaseContext +{ + +public: + + XMLIndexBibliographySourceContext( + SvXMLImport& rImport, + css::uno::Reference<css::beans::XPropertySet> & rPropSet); + + virtual ~XMLIndexBibliographySourceContext() override; + +protected: + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexBodyContext.cxx b/xmloff/source/text/XMLIndexBodyContext.cxx new file mode 100644 index 0000000000..53a7def1d2 --- /dev/null +++ b/xmloff/source/text/XMLIndexBodyContext.cxx @@ -0,0 +1,52 @@ +/* -*- 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 "XMLIndexBodyContext.hxx" +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/txtimp.hxx> +#include <rtl/ustring.hxx> + +using ::com::sun::star::uno::Reference; + + +XMLIndexBodyContext::XMLIndexBodyContext( SvXMLImport& rImport ) : + SvXMLImportContext(rImport), + bHasContent(false) +{ +} + +XMLIndexBodyContext::~XMLIndexBodyContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexBodyContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // return text content (if possible) + SvXMLImportContext* pContext = GetImport().GetTextImport()->CreateTextChildContext( + GetImport(), nElement, xAttrList, XMLTextType::Section ); + if (pContext) + bHasContent = true; + + return pContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexBodyContext.hxx b/xmloff/source/text/XMLIndexBodyContext.hxx new file mode 100644 index 0000000000..5962bacf34 --- /dev/null +++ b/xmloff/source/text/XMLIndexBodyContext.hxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <com/sun/star/uno/Reference.h> + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + +/** + * Import index body. + * + * This class basically delegates all CreateChildContext() calls to + * the text import and doesn't do much else. + */ +class XMLIndexBodyContext : public SvXMLImportContext +{ + bool bHasContent; + +public: + + + XMLIndexBodyContext( SvXMLImport& rImport ); + + virtual ~XMLIndexBodyContext() override; + + /// return whether any content elements were encountered + inline bool HasContent() const; + +protected: + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +inline bool XMLIndexBodyContext::HasContent() const +{ + return bHasContent; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexChapterInfoEntryContext.cxx b/xmloff/source/text/XMLIndexChapterInfoEntryContext.cxx new file mode 100644 index 0000000000..b17d05739c --- /dev/null +++ b/xmloff/source/text/XMLIndexChapterInfoEntryContext.cxx @@ -0,0 +1,185 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "XMLIndexChapterInfoEntryContext.hxx" + +#include <com/sun/star/text/ChapterFormat.hpp> + +#include <sax/tools/converter.hxx> +#include <sal/log.hxx> + +#include "XMLIndexTemplateContext.hxx" +#include <xmloff/xmlimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> + + +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + + +XMLIndexChapterInfoEntryContext::XMLIndexChapterInfoEntryContext( + SvXMLImport& rImport, + XMLIndexTemplateContext& rTemplate, + bool bT ) : + XMLIndexSimpleEntryContext(rImport, + (bT ? OUString("TokenEntryNumber") + : OUString("TokenChapterInfo")), + rTemplate), + nChapterInfo(ChapterFormat::NAME_NUMBER), + bChapterInfoOK(false), + bTOC( bT ), + nOutlineLevel( 0 ), + bOutlineLevelOK(false) +{ +} + +XMLIndexChapterInfoEntryContext::~XMLIndexChapterInfoEntryContext() +{ +} + +const SvXMLEnumMapEntry<sal_uInt16> aChapterDisplayMap[] = +{ + { XML_NAME, ChapterFormat::NAME }, + { XML_NUMBER, ChapterFormat::NUMBER }, + { XML_NUMBER_AND_NAME, ChapterFormat::NAME_NUMBER }, + //---> i89791 + // enabled for ODF 1.2, full index support in 3.0 + { XML_PLAIN_NUMBER_AND_NAME, ChapterFormat::NO_PREFIX_SUFFIX }, + { XML_PLAIN_NUMBER, ChapterFormat::DIGIT }, + { XML_TOKEN_INVALID, 0 } +}; + +void XMLIndexChapterInfoEntryContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // handle both, style name and bibliography info + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + { + m_sCharStyleName = aIter.toString(); + m_bCharStyleNameOK = true; + break; + } + case XML_ELEMENT(TEXT, XML_DISPLAY): //i53420, always true, in TOC as well + { + sal_uInt16 nTmp; + if (SvXMLUnitConverter::convertEnum(nTmp, aIter.toView(), aChapterDisplayMap)) + { + nChapterInfo = nTmp; + bChapterInfoOK = true; + } + break; + } + case XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL): + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber(nTmp, aIter.toView())) + { +//control on range is carried out in the UNO level + nOutlineLevel = static_cast<sal_uInt16>(nTmp); + bOutlineLevelOK = true; + } + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // if we have a style name, set it! + if (m_bCharStyleNameOK) + { + m_nValues++; + } + + // if we have chapter info, set it! + if (bChapterInfoOK) + { + m_nValues++; + /* Some of the index chapter information attributes written to ODF 1.1 + and 1.2 don't reflect the displaying (#i89791#) + */ + if ( !bTOC ) + { + bool bConvert( false ); + { + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + const bool bBuildIdFound = GetImport().getBuildIds( nUPD, nBuild ); + if ( GetImport().IsTextDocInOOoFileFormat() || + ( bBuildIdFound && + ( nUPD== 680 || nUPD == 645 || nUPD == 641 ) ) ) + { + bConvert = true; + } + } + if ( bConvert ) + { + if ( nChapterInfo == ChapterFormat::NUMBER ) + { + nChapterInfo = ChapterFormat::DIGIT; + } + else if ( nChapterInfo == ChapterFormat::NAME_NUMBER ) + { + nChapterInfo = ChapterFormat::NO_PREFIX_SUFFIX; + } + } + } + } + if (bOutlineLevelOK) + m_nValues++; +} + +void XMLIndexChapterInfoEntryContext::FillPropertyValues( + css::uno::Sequence<css::beans::PropertyValue> & rValues) +{ + // entry name and (optionally) style name in parent class + XMLIndexSimpleEntryContext::FillPropertyValues(rValues); + + sal_Int32 nIndex = m_bCharStyleNameOK ? 2 : 1; + auto pValues = rValues.getArray(); + + if( bChapterInfoOK ) + { + // chapter info field + pValues[nIndex].Name = "ChapterFormat"; + pValues[nIndex].Value <<= nChapterInfo; + nIndex++; + } + if( bOutlineLevelOK ) + { + pValues[nIndex].Name = "ChapterLevel"; + pValues[nIndex].Value <<= nOutlineLevel; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexChapterInfoEntryContext.hxx b/xmloff/source/text/XMLIndexChapterInfoEntryContext.hxx new file mode 100644 index 0000000000..f1cc400e5e --- /dev/null +++ b/xmloff/source/text/XMLIndexChapterInfoEntryContext.hxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "XMLIndexSimpleEntryContext.hxx" +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/beans/PropertyValue.hpp> + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } +} +class XMLIndexTemplateContext; + +/** + * Import chapter info index entry templates + */ +class XMLIndexChapterInfoEntryContext : public XMLIndexSimpleEntryContext +{ + // chapter format + sal_Int16 nChapterInfo; + bool bChapterInfoOK; + bool bTOC; + sal_Int16 nOutlineLevel; + bool bOutlineLevelOK; + +public: + + + XMLIndexChapterInfoEntryContext( + SvXMLImport& rImport, + XMLIndexTemplateContext& rTemplate, + bool bTOC ); + + virtual ~XMLIndexChapterInfoEntryContext() override; + +protected: + + /** process parameters */ + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + /** fill property values for this template entry */ + virtual void FillPropertyValues( + css::uno::Sequence<css::beans::PropertyValue> & rValues) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexIllustrationSourceContext.cxx b/xmloff/source/text/XMLIndexIllustrationSourceContext.cxx new file mode 100644 index 0000000000..3148bc71ec --- /dev/null +++ b/xmloff/source/text/XMLIndexIllustrationSourceContext.cxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "XMLIndexIllustrationSourceContext.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include "XMLIndexTemplateContext.hxx" +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <rtl/ustring.hxx> + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::xmloff::token::XML_ILLUSTRATION_INDEX_ENTRY_TEMPLATE; +using ::xmloff::token::XML_TOKEN_INVALID; + + +XMLIndexIllustrationSourceContext::XMLIndexIllustrationSourceContext( + SvXMLImport& rImport, + Reference<XPropertySet> & rPropSet) + : XMLIndexTableSourceContext(rImport, rPropSet) +{ +} + +XMLIndexIllustrationSourceContext::~XMLIndexIllustrationSourceContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexIllustrationSourceContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_ILLUSTRATION_INDEX_ENTRY_TEMPLATE) ) + { + return new XMLIndexTemplateContext(GetImport(), rIndexPropertySet, + aLevelNameTableMap, + XML_TOKEN_INVALID, // no outline-level attr + aLevelStylePropNameTableMap, + aAllowedTokenTypesTable); + } + else + { + return XMLIndexSourceBaseContext::createFastChildContext(nElement, + xAttrList); + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexIllustrationSourceContext.hxx b/xmloff/source/text/XMLIndexIllustrationSourceContext.hxx new file mode 100644 index 0000000000..b482c63fff --- /dev/null +++ b/xmloff/source/text/XMLIndexIllustrationSourceContext.hxx @@ -0,0 +1,55 @@ +/* -*- 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 "XMLIndexTableSourceContext.hxx" +#include <com/sun/star/uno/Reference.h> + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +/** + * Import illustration index source element; + * + * All logic is inherited from table source context. The only difference is + * the different child context (illustration entry template). + */ +class XMLIndexIllustrationSourceContext : public XMLIndexTableSourceContext +{ +public: + + XMLIndexIllustrationSourceContext( + SvXMLImport& rImport, + css::uno::Reference<css::beans::XPropertySet> & rPropSet); + + virtual ~XMLIndexIllustrationSourceContext() override; + +protected: + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexMarkExport.cxx b/xmloff/source/text/XMLIndexMarkExport.cxx new file mode 100644 index 0000000000..f27c87d9ea --- /dev/null +++ b/xmloff/source/text/XMLIndexMarkExport.cxx @@ -0,0 +1,228 @@ +/* -*- 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 "XMLIndexMarkExport.hxx" +#include <o3tl/any.hxx> +#include <tools/debug.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <sax/tools/converter.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlexp.hxx> + + +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::beans::XPropertySetInfo; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; + +XMLIndexMarkExport::XMLIndexMarkExport( + SvXMLExport& rExp) +: rExport(rExp) +{ +} + +const enum XMLTokenEnum lcl_pTocMarkNames[] = + { XML_TOC_MARK, XML_TOC_MARK_START, XML_TOC_MARK_END }; +const enum XMLTokenEnum lcl_pUserIndexMarkName[] = + { XML_USER_INDEX_MARK, + XML_USER_INDEX_MARK_START, XML_USER_INDEX_MARK_END }; +const enum XMLTokenEnum lcl_pAlphaIndexMarkName[] = + { XML_ALPHABETICAL_INDEX_MARK, + XML_ALPHABETICAL_INDEX_MARK_START, + XML_ALPHABETICAL_INDEX_MARK_END }; + + +void XMLIndexMarkExport::ExportIndexMark( + const Reference<XPropertySet> & rPropSet, + bool bAutoStyles) +{ + /// index marks have no styles! + if (bAutoStyles) + return; + + const enum XMLTokenEnum * pElements = nullptr; + sal_Int8 nElementNo = -1; + + // get index mark + Any aAny = rPropSet->getPropertyValue(gsDocumentIndexMark); + Reference<XPropertySet> xIndexMarkPropSet; + aAny >>= xIndexMarkPropSet; + + // common: handling of start, end, collapsed entries and + // alternative text + + // collapsed/alternative text entry? + aAny = rPropSet->getPropertyValue(gsIsCollapsed); + if (*o3tl::doAccess<bool>(aAny)) + { + // collapsed entry: needs alternative text + nElementNo = 0; + + aAny = xIndexMarkPropSet->getPropertyValue(gsAlternativeText); + OUString sTmp; + aAny >>= sTmp; + DBG_ASSERT(!sTmp.isEmpty(), + "collapsed index mark without alternative text"); + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_STRING_VALUE, sTmp); + } + else + { + // start and end entries: has ID + aAny = rPropSet->getPropertyValue(gsIsStart); + nElementNo = *o3tl::doAccess<bool>(aAny) ? 1 : 2; + + // generate ID + OUStringBuffer sBuf; + GetID(sBuf, xIndexMarkPropSet); + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_ID, + sBuf.makeStringAndClear()); + } + + // distinguish between TOC, user, alphab. index marks by + // asking for specific properties + // Export attributes for -mark-start and -mark elements, + // but not for -mark-end + Reference<XPropertySetInfo> xPropertySetInfo = + xIndexMarkPropSet->getPropertySetInfo(); + if (xPropertySetInfo->hasPropertyByName(gsUserIndexName)) + { + // user index mark + pElements = lcl_pUserIndexMarkName; + if (nElementNo != 2) + { + ExportUserIndexMarkAttributes(xIndexMarkPropSet); + } + } + else if (xPropertySetInfo->hasPropertyByName(gsPrimaryKey)) + { + // alphabetical index mark + pElements = lcl_pAlphaIndexMarkName; + if (nElementNo != 2) + { + ExportAlphabeticalIndexMarkAttributes(xIndexMarkPropSet); + } + } + else + { + // table of content: + pElements = lcl_pTocMarkNames; + if (nElementNo != 2) + { + ExportTOCMarkAttributes(xIndexMarkPropSet); + } + } + + // export element + DBG_ASSERT(pElements != nullptr, "illegal element array"); + DBG_ASSERT(nElementNo >= 0, "illegal name array index"); + DBG_ASSERT(nElementNo <= 2, "illegal name array index"); + + if ((pElements != nullptr) && (nElementNo != -1)) + { + SvXMLElementExport aElem(rExport, + XML_NAMESPACE_TEXT, + pElements[nElementNo], + false, false); + } + +} + +void XMLIndexMarkExport::ExportTOCMarkAttributes( + const Reference<XPropertySet> & rPropSet) +{ + // outline level + sal_Int16 nLevel = 0; + Any aAny = rPropSet->getPropertyValue(gsLevel); + aAny >>= nLevel; + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_OUTLINE_LEVEL, + OUString::number(nLevel + 1)); +} + +static void lcl_ExportPropertyString( SvXMLExport& rExport, + const Reference<XPropertySet> & rPropSet, + const OUString & sProperty, + XMLTokenEnum eToken, + Any& rAny ) +{ + rAny = rPropSet->getPropertyValue( sProperty ); + + OUString sValue; + if( (rAny >>= sValue) && !sValue.isEmpty() ) + { + rExport.AddAttribute( XML_NAMESPACE_TEXT, eToken, sValue ); + } +} + +static void lcl_ExportPropertyBool( SvXMLExport& rExport, + const Reference<XPropertySet> & rPropSet, + const OUString & sProperty, + XMLTokenEnum eToken, + Any& rAny ) +{ + rAny = rPropSet->getPropertyValue( sProperty ); + + bool bValue; + if( (rAny >>= bValue) && bValue ) + { + rExport.AddAttribute( XML_NAMESPACE_TEXT, eToken, XML_TRUE ); + } +} + +void XMLIndexMarkExport::ExportUserIndexMarkAttributes( + const Reference<XPropertySet> & rPropSet) +{ + // name of user index + // (unless it's the default index; then it has no name) + Any aAny; + lcl_ExportPropertyString( rExport, rPropSet, gsUserIndexName, XML_INDEX_NAME, aAny ); + + // additionally export outline level; just reuse ExportTOCMarkAttributes + ExportTOCMarkAttributes( rPropSet ); +} + +void XMLIndexMarkExport::ExportAlphabeticalIndexMarkAttributes( + const Reference<XPropertySet> & rPropSet) +{ + // primary and secondary keys (if available) + Any aAny; + lcl_ExportPropertyString( rExport, rPropSet, gsTextReading, XML_STRING_VALUE_PHONETIC, aAny ); + lcl_ExportPropertyString( rExport, rPropSet, gsPrimaryKey, XML_KEY1, aAny ); + lcl_ExportPropertyString( rExport, rPropSet, gsPrimaryKeyReading, XML_KEY1_PHONETIC, aAny ); + lcl_ExportPropertyString( rExport, rPropSet, gsSecondaryKey, XML_KEY2, aAny ); + lcl_ExportPropertyString( rExport, rPropSet, gsSecondaryKeyReading, XML_KEY2_PHONETIC, aAny ); + lcl_ExportPropertyBool( rExport, rPropSet, gsMainEntry, XML_MAIN_ENTRY, aAny ); +} + +void XMLIndexMarkExport::GetID( + OUStringBuffer& sBuf, + const Reference<XPropertySet> & rPropSet) +{ + // HACK: use address of object to form identifier + sal_Int64 nId = sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_uIntPtr>(rPropSet.get())); + sBuf.append("IMark"); + sBuf.append(nId); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexMarkExport.hxx b/xmloff/source/text/XMLIndexMarkExport.hxx new file mode 100644 index 0000000000..a62ce9b503 --- /dev/null +++ b/xmloff/source/text/XMLIndexMarkExport.hxx @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/uno/Reference.h> + +class SvXMLExport; +namespace com::sun::star { + namespace beans { class XPropertySet; } +} + + +/** + * This class handles the export of index marks for table of content, + * alphabetical and user index. + * + * Marks for bibliography indices are internally modelled as text + * fields and thus handled in txtparae.cxx + */ +class XMLIndexMarkExport +{ + static constexpr OUString gsLevel = u"Level"_ustr; + static constexpr OUString gsUserIndexName = u"UserIndexName"_ustr; + static constexpr OUString gsPrimaryKey = u"PrimaryKey"_ustr; + static constexpr OUString gsSecondaryKey = u"SecondaryKey"_ustr; + static constexpr OUString gsDocumentIndexMark = u"DocumentIndexMark"_ustr; + static constexpr OUString gsIsStart = u"IsStart"_ustr; + static constexpr OUString gsIsCollapsed = u"IsCollapsed"_ustr; + static constexpr OUString gsAlternativeText = u"AlternativeText"_ustr; + static constexpr OUString gsTextReading = u"TextReading"_ustr; + static constexpr OUString gsPrimaryKeyReading = u"PrimaryKeyReading"_ustr; + static constexpr OUString gsSecondaryKeyReading = u"SecondaryKeyReading"_ustr; + static constexpr OUString gsMainEntry = u"IsMainEntry"_ustr; + + SvXMLExport& rExport; + +public: + explicit XMLIndexMarkExport(SvXMLExport& rExp); + + /** + * export by the property set of its *text* *portion*. + * + * The text portion supplies us with the properties of the index + * mark itself, as well as the information whether we are at the + * start or end of an index mark, or whether the index mark is + * collapsed. + */ + void ExportIndexMark( + const css::uno::Reference<css::beans::XPropertySet> & rPropSet, + bool bAutoStyles); + +private: + + /// export attributes of table-of-content index marks + void ExportTOCMarkAttributes( + const css::uno::Reference<css::beans::XPropertySet> & rPropSet); + + /// export attributes of user index marks + void ExportUserIndexMarkAttributes( + const css::uno::Reference<css::beans::XPropertySet> & rPropSet); + + /// export attributes of alphabetical index marks + void ExportAlphabeticalIndexMarkAttributes( + const css::uno::Reference<css::beans::XPropertySet> & rPropSet); + + /// create a numerical ID for this index mark + /// (represented by its properties) + static void GetID( + OUStringBuffer& sBuffer, + const css::uno::Reference<css::beans::XPropertySet> & rPropSet); + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexObjectSourceContext.cxx b/xmloff/source/text/XMLIndexObjectSourceContext.cxx new file mode 100644 index 0000000000..805ce796aa --- /dev/null +++ b/xmloff/source/text/XMLIndexObjectSourceContext.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 "XMLIndexObjectSourceContext.hxx" + +#include <rtl/ustring.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <sax/tools/converter.hxx> + +#include "XMLIndexTemplateContext.hxx" +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> + + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using namespace ::xmloff::token; + + +XMLIndexObjectSourceContext::XMLIndexObjectSourceContext( + SvXMLImport& rImport, + Reference<XPropertySet> & rPropSet) + : XMLIndexSourceBaseContext(rImport, rPropSet, UseStyles::Single), + bUseCalc(false), + bUseChart(false), + bUseDraw(false), + bUseMath(false), + bUseOtherObjects(false) +{ +} + +XMLIndexObjectSourceContext::~XMLIndexObjectSourceContext() +{ +} + +void XMLIndexObjectSourceContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + bool bTmp(false); + + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_USE_OTHER_OBJECTS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseOtherObjects = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_SPREADSHEET_OBJECTS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseCalc = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_CHART_OBJECTS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseChart = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_DRAW_OBJECTS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseDraw = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_MATH_OBJECTS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseMath = bTmp; + } + break; + + default: + XMLIndexSourceBaseContext::ProcessAttribute(aIter); + break; + } +} + +void XMLIndexObjectSourceContext::endFastElement(sal_Int32 nElement) +{ + rIndexPropertySet->setPropertyValue("CreateFromStarCalc", css::uno::Any(bUseCalc)); + rIndexPropertySet->setPropertyValue("CreateFromStarChart", css::uno::Any(bUseChart)); + rIndexPropertySet->setPropertyValue("CreateFromStarDraw", css::uno::Any(bUseDraw)); + rIndexPropertySet->setPropertyValue("CreateFromStarMath", css::uno::Any(bUseMath)); + rIndexPropertySet->setPropertyValue("CreateFromOtherEmbeddedObjects", css::uno::Any(bUseOtherObjects)); + + XMLIndexSourceBaseContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexObjectSourceContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_OBJECT_INDEX_ENTRY_TEMPLATE) ) + { + return new XMLIndexTemplateContext(GetImport(), rIndexPropertySet, + aLevelNameTableMap, + XML_TOKEN_INVALID, // no outline-level attr + aLevelStylePropNameTableMap, + aAllowedTokenTypesTable); + } + else + { + return XMLIndexSourceBaseContext::createFastChildContext(nElement, + xAttrList); + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexObjectSourceContext.hxx b/xmloff/source/text/XMLIndexObjectSourceContext.hxx new file mode 100644 index 0000000000..6240a5c28a --- /dev/null +++ b/xmloff/source/text/XMLIndexObjectSourceContext.hxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "XMLIndexSourceBaseContext.hxx" +#include <com/sun/star/uno/Reference.h> + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +/** + * Import object index source element + */ +class XMLIndexObjectSourceContext : public XMLIndexSourceBaseContext +{ + bool bUseCalc; + bool bUseChart; + bool bUseDraw; + bool bUseMath; + bool bUseOtherObjects; + +public: + + + XMLIndexObjectSourceContext( + SvXMLImport& rImport, + css::uno::Reference<css::beans::XPropertySet> & rPropSet); + + virtual ~XMLIndexObjectSourceContext() override; + +protected: + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexSimpleEntryContext.cxx b/xmloff/source/text/XMLIndexSimpleEntryContext.cxx new file mode 100644 index 0000000000..6c59f13380 --- /dev/null +++ b/xmloff/source/text/XMLIndexSimpleEntryContext.cxx @@ -0,0 +1,123 @@ +/* -*- 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 "XMLIndexSimpleEntryContext.hxx" +#include "XMLIndexTemplateContext.hxx" +#include <utility> +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/txtimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <sal/log.hxx> + +#include <com/sun/star/container/XNameContainer.hpp> + +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; +using ::xmloff::token::XML_STYLE_NAME; + + +XMLIndexSimpleEntryContext::XMLIndexSimpleEntryContext( + SvXMLImport& rImport, + OUString aEntry, + XMLIndexTemplateContext& rTemplate ) +: SvXMLImportContext(rImport) +, m_rEntryType(std::move(aEntry)) +, m_bCharStyleNameOK(false) +, m_rTemplateContext(rTemplate) +, m_nValues(1) +{ +} + +XMLIndexSimpleEntryContext::~XMLIndexSimpleEntryContext() +{ +} + +void XMLIndexSimpleEntryContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // we know only one attribute: style-name + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if(aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME)) + { + m_sCharStyleName = aIter.toString(); + OUString sDisplayStyleName = GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, m_sCharStyleName ); + // #142494#: Check if style exists + const Reference < css::container::XNameContainer > & rStyles = + GetImport().GetTextImport()->GetTextStyles(); + if( rStyles.is() && rStyles->hasByName( sDisplayStyleName ) ) + m_bCharStyleNameOK = true; + else + m_bCharStyleNameOK = false; + } + else + XMLOFF_INFO_UNKNOWN("xmloff", aIter); + } + + // if we have a style name, set it! + if (m_bCharStyleNameOK) + { + m_nValues++; + } + +} + +void XMLIndexSimpleEntryContext::endFastElement(sal_Int32 ) +{ + Sequence<PropertyValue> aValues(m_nValues); + + FillPropertyValues(aValues); + m_rTemplateContext.addTemplateEntry(aValues); +} + +void XMLIndexSimpleEntryContext::FillPropertyValues( + css::uno::Sequence<css::beans::PropertyValue> & rValues) +{ + // due to the limited number of subclasses, we fill the values + // directly into the slots. Subclasses will have to know they can + // only use slot so-and-so. + + Any aAny; + auto pValues = rValues.getArray(); + + // token type + pValues[0].Name = "TokenType"; + pValues[0].Value <<= m_rEntryType; + + // char style + if (m_bCharStyleNameOK) + { + pValues[1].Name = "CharacterStyleName"; + aAny <<= GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, + m_sCharStyleName ); + pValues[1].Value = aAny; + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexSimpleEntryContext.hxx b/xmloff/source/text/XMLIndexSimpleEntryContext.hxx new file mode 100644 index 0000000000..684245184e --- /dev/null +++ b/xmloff/source/text/XMLIndexSimpleEntryContext.hxx @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/beans/PropertyValue.hpp> + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } +} +class XMLIndexTemplateContext; + +/** + * Import index entry templates + */ +class XMLIndexSimpleEntryContext : public SvXMLImportContext +{ + + // entry type + const OUString m_rEntryType; + +protected: + // character style + OUString m_sCharStyleName; + bool m_bCharStyleNameOK; + + // surrounding template + XMLIndexTemplateContext& m_rTemplateContext; + + // number of values for PropertyValues + sal_Int32 m_nValues; + +public: + + + XMLIndexSimpleEntryContext( + SvXMLImport& rImport, + OUString aEntry, + XMLIndexTemplateContext& rTemplate ); + + virtual ~XMLIndexSimpleEntryContext() override; + +protected: + + /** process parameters */ + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + /** call FillPropertyValues and insert into template */ + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + /** fill property values for this template entry */ + virtual void FillPropertyValues( + css::uno::Sequence<css::beans::PropertyValue> & rValues); + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexSourceBaseContext.cxx b/xmloff/source/text/XMLIndexSourceBaseContext.cxx new file mode 100644 index 0000000000..366daed58f --- /dev/null +++ b/xmloff/source/text/XMLIndexSourceBaseContext.cxx @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "XMLIndexSourceBaseContext.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include "XMLIndexTitleTemplateContext.hxx" +#include "XMLIndexTOCStylesContext.hxx" +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmltoken.hxx> +#include <sax/tools/converter.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> + + +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; + + +XMLIndexSourceBaseContext::XMLIndexSourceBaseContext( + SvXMLImport& rImport, + Reference<XPropertySet> & rPropSet, + UseStyles const eUseStyles) +: SvXMLImportContext(rImport) +, m_UseStyles(eUseStyles) +, bChapterIndex(false) +, bRelativeTabs(true) +, rIndexPropertySet(rPropSet) +{ +} + +XMLIndexSourceBaseContext::~XMLIndexSourceBaseContext() +{ +} + +void XMLIndexSourceBaseContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // process attributes + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + ProcessAttribute(aIter); +} + +void XMLIndexSourceBaseContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_INDEX_SCOPE): + if ( IsXMLToken( aIter, XML_CHAPTER ) ) + { + bChapterIndex = true; + } + break; + + case XML_ELEMENT(TEXT, XML_RELATIVE_TAB_STOP_POSITION): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bRelativeTabs = bTmp; + } + break; + } + + default: + // unknown attribute -> ignore + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + break; + } +} + +void XMLIndexSourceBaseContext::endFastElement(sal_Int32 ) +{ + rIndexPropertySet->setPropertyValue("IsRelativeTabstops", css::uno::Any(bRelativeTabs)); + rIndexPropertySet->setPropertyValue("CreateFromChapter", css::uno::Any(bChapterIndex)); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexSourceBaseContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) +{ + SvXMLImportContextRef xContext; + + if (nElement == XML_ELEMENT(TEXT, XML_INDEX_TITLE_TEMPLATE) ) + { + xContext = new XMLIndexTitleTemplateContext(GetImport(), + rIndexPropertySet); + } + else if (m_UseStyles == UseStyles::Level + && nElement == XML_ELEMENT(TEXT, XML_INDEX_SOURCE_STYLES)) + { + xContext = new XMLIndexTOCStylesContext(GetImport(), + rIndexPropertySet); + } + else if (m_UseStyles == UseStyles::Single + && (nElement == XML_ELEMENT(LO_EXT, XML_INDEX_SOURCE_STYLE) + || nElement == XML_ELEMENT(TEXT, XML_INDEX_SOURCE_STYLE))) + { + OUString const styleName(xmloff::GetIndexSourceStyleName(xAttrList)); + if (!styleName.isEmpty()) + { + OUString const convertedStyleName(GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_PARAGRAPH, styleName)); + rIndexPropertySet->setPropertyValue("CreateFromParagraphStyle", css::uno::Any(convertedStyleName)); + } + } + + // else: unknown namespace -> ignore + + return xContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexSourceBaseContext.hxx b/xmloff/source/text/XMLIndexSourceBaseContext.hxx new file mode 100644 index 0000000000..b927954e5f --- /dev/null +++ b/xmloff/source/text/XMLIndexSourceBaseContext.hxx @@ -0,0 +1,84 @@ +/* -*- 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 <com/sun/star/uno/Reference.h> +#include <rtl/ustring.hxx> +#include <sax/fastattribs.hxx> + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + +/** + * Superclass for index source elements + */ +class XMLIndexSourceBaseContext : public SvXMLImportContext +{ +protected: + enum class UseStyles { None, Level, Single }; + +private: + UseStyles m_UseStyles; + bool bChapterIndex; /// chapter-wise or document index? + bool bRelativeTabs; /// tab stops relative to margin or indent? + +protected: + + /// property set of index; must be accessible to subclasses + css::uno::Reference<css::beans::XPropertySet> & rIndexPropertySet; + +public: + + + XMLIndexSourceBaseContext( + SvXMLImport& rImport, + css::uno::Reference<css::beans::XPropertySet> & rPropSet, + UseStyles eUseStyles); + + virtual ~XMLIndexSourceBaseContext() override; + +protected: + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + + +namespace xmloff { + +OUString GetIndexSourceStyleName( + css::uno::Reference<css::xml::sax::XFastAttributeList> const& xAttrList); + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexSpanEntryContext.cxx b/xmloff/source/text/XMLIndexSpanEntryContext.cxx new file mode 100644 index 0000000000..ba0c976cfc --- /dev/null +++ b/xmloff/source/text/XMLIndexSpanEntryContext.cxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "XMLIndexSpanEntryContext.hxx" +#include <rtl/ustring.hxx> +#include "XMLIndexTemplateContext.hxx" +#include <xmloff/xmlictxt.hxx> + + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; +using ::com::sun::star::beans::PropertyValue; + + +XMLIndexSpanEntryContext::XMLIndexSpanEntryContext( + SvXMLImport& rImport, + XMLIndexTemplateContext& rTemplate ) : + XMLIndexSimpleEntryContext(rImport, "TokenText", + rTemplate) +{ + m_nValues++; // one more for the text string +} + +XMLIndexSpanEntryContext::~XMLIndexSpanEntryContext() +{ +} + +void XMLIndexSpanEntryContext::characters(const OUString& sString) +{ + sContent.append(sString); +} + +void XMLIndexSpanEntryContext::FillPropertyValues( + Sequence<PropertyValue> & rValues) +{ + // call superclass for token type, stylename, + XMLIndexSimpleEntryContext::FillPropertyValues(rValues); + + // content + auto pValues = rValues.getArray(); + Any aAny; + aAny <<= sContent.makeStringAndClear(); + pValues[m_nValues-1].Name = "Text"; + pValues[m_nValues-1].Value = aAny; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexSpanEntryContext.hxx b/xmloff/source/text/XMLIndexSpanEntryContext.hxx new file mode 100644 index 0000000000..8b4711c1f8 --- /dev/null +++ b/xmloff/source/text/XMLIndexSpanEntryContext.hxx @@ -0,0 +1,57 @@ +/* -*- 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 "XMLIndexSimpleEntryContext.hxx" +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <rtl/ustrbuf.hxx> + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } +} + +/** + * Import index entry templates + */ +class XMLIndexSpanEntryContext : public XMLIndexSimpleEntryContext +{ + OUStringBuffer sContent; + +public: + + + XMLIndexSpanEntryContext( + SvXMLImport& rImport, + XMLIndexTemplateContext& rTemplate ); + + virtual ~XMLIndexSpanEntryContext() override; + +protected: + + /// Collect element contents + virtual void SAL_CALL characters(const OUString& sString) override; + + /// add Text PropertyValue + virtual void FillPropertyValues( + css::uno::Sequence<css::beans::PropertyValue> & rValues) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTOCContext.cxx b/xmloff/source/text/XMLIndexTOCContext.cxx new file mode 100644 index 0000000000..2e3f1e3a47 --- /dev/null +++ b/xmloff/source/text/XMLIndexTOCContext.cxx @@ -0,0 +1,343 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "XMLIndexTOCContext.hxx" +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <sax/tools/converter.hxx> +#include <sal/log.hxx> +#include "XMLIndexTOCSourceContext.hxx" +#include "XMLIndexObjectSourceContext.hxx" +#include "XMLIndexAlphabeticalSourceContext.hxx" +#include "XMLIndexUserSourceContext.hxx" +#include "XMLIndexBibliographySourceContext.hxx" +#include "XMLIndexTableSourceContext.hxx" +#include "XMLIndexIllustrationSourceContext.hxx" +#include "XMLIndexBodyContext.hxx" +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/txtimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/prstylei.hxx> +#include <xmloff/xmlerror.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> +#include <rtl/ustring.hxx> +#include <osl/diagnose.h> + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::lang::IllegalArgumentException; + + +static const char* aIndexServiceMap[] = +{ + "com.sun.star.text.ContentIndex", + "com.sun.star.text.DocumentIndex", + "com.sun.star.text.TableIndex", + "com.sun.star.text.ObjectIndex", + "com.sun.star.text.Bibliography", + "com.sun.star.text.UserIndex", + "com.sun.star.text.IllustrationsIndex" +}; + +const XMLTokenEnum aIndexSourceElementMap[] = +{ + XML_TABLE_OF_CONTENT_SOURCE, + XML_ALPHABETICAL_INDEX_SOURCE, + XML_TABLE_INDEX_SOURCE, + XML_OBJECT_INDEX_SOURCE, + XML_BIBLIOGRAPHY_SOURCE, + XML_USER_INDEX_SOURCE, + XML_ILLUSTRATION_INDEX_SOURCE +}; + +SvXMLEnumMapEntry<IndexTypeEnum> const aIndexTypeMap[] = +{ + { XML_TABLE_OF_CONTENT, TEXT_INDEX_TOC }, + { XML_ALPHABETICAL_INDEX, TEXT_INDEX_ALPHABETICAL }, + { XML_TABLE_INDEX, TEXT_INDEX_TABLE }, + { XML_OBJECT_INDEX, TEXT_INDEX_OBJECT }, + { XML_BIBLIOGRAPHY, TEXT_INDEX_BIBLIOGRAPHY }, + { XML_USER_INDEX, TEXT_INDEX_USER }, + { XML_ILLUSTRATION_INDEX, TEXT_INDEX_ILLUSTRATION }, + { XML_TOKEN_INVALID, IndexTypeEnum(0) } +}; + + +XMLIndexTOCContext::XMLIndexTOCContext(SvXMLImport& rImport, + sal_Int32 nElement) + : SvXMLImportContext(rImport) + , eIndexType(TEXT_INDEX_UNKNOWN) + , bValid(false) +{ + if (IsTokenInNamespace(nElement, XML_NAMESPACE_TEXT)) + { + if (SvXMLUnitConverter::convertEnum(eIndexType, SvXMLImport::getNameFromToken(nElement), aIndexTypeMap)) + { + // check for array index: + OSL_ENSURE(unsigned(eIndexType) < (SAL_N_ELEMENTS(aIndexServiceMap)), "index out of range"); + OSL_ENSURE(SAL_N_ELEMENTS(aIndexServiceMap) == + SAL_N_ELEMENTS(aIndexSourceElementMap), + "service and source element maps must be same size"); + bValid = true; + } + } +} + +XMLIndexTOCContext::~XMLIndexTOCContext() +{ +} + +void XMLIndexTOCContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if (!bValid) + return; + + // find text:style-name attribute and set section style + // find text:protected and set value + // find text:name and set value (if not empty) + bool bProtected = false; + OUString sIndexName; + OUString sXmlId; + XMLPropStyleContext* pStyle(nullptr); + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + { + pStyle = GetImport().GetTextImport()->FindSectionStyle( + aIter.toString()); + break; + } + case XML_ELEMENT(TEXT, XML_PROTECTED): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bProtected = bTmp; + } + break; + } + case XML_ELEMENT(TEXT, XML_NAME): + { + sIndexName = aIter.toString(); + break; + } + case XML_ELEMENT(XML, XML_ID): + { + sXmlId = aIter.toString(); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // create table of content (via MultiServiceFactory) + Reference<XMultiServiceFactory> xFactory(GetImport().GetModel(), + UNO_QUERY); + if( xFactory.is() ) + { + Reference<XInterface> xIfc = + xFactory->createInstance( + OUString::createFromAscii(aIndexServiceMap[eIndexType])); + if( xIfc.is() ) + { + // get Property set + Reference<XPropertySet> xPropSet(xIfc, UNO_QUERY); + xTOCPropertySet = xPropSet; + + // insert section + // a) insert section + // The inserted index consists of an empty paragraph + // only, as well as an empty paragraph *after* the index + // b) insert marker after index, and put Cursor inside of the + // index + + // preliminaries +#ifndef DBG_UTIL + static constexpr OUStringLiteral sMarker(u" "); +#else + static constexpr OUStringLiteral sMarker(u"Y"); +#endif + rtl::Reference<XMLTextImportHelper> rImport = + GetImport().GetTextImport(); + + // a) insert index + Reference<XTextContent> xTextContent(xIfc, UNO_QUERY); + try + { + GetImport().GetTextImport()->InsertTextContent( + xTextContent); + } + catch(const IllegalArgumentException& e) + { + // illegal argument? Then we can't accept indices here! + Sequence<OUString> aSeq { SvXMLImport::getNameFromToken(nElement) }; + GetImport().SetError( + XMLERROR_FLAG_ERROR | XMLERROR_NO_INDEX_ALLOWED_HERE, + aSeq, e.Message, nullptr ); + + // set bValid to false, and return prematurely + bValid = false; + return; + } + + // xml:id for RDF metadata + GetImport().SetXmlId(xIfc, sXmlId); + + // b) insert marker and move cursor + rImport->InsertString(sMarker); + rImport->GetCursor()->goLeft(2, false); + } + } + + // finally, check for redlines that should start at + // the section start node + if( bValid ) + GetImport().GetTextImport()->RedlineAdjustStartNodeCursor(); + + if (pStyle != nullptr) + { + pStyle->FillPropertySet( xTOCPropertySet ); + } + + xTOCPropertySet->setPropertyValue( "IsProtected", Any(bProtected) ); + + if (!sIndexName.isEmpty()) + { + xTOCPropertySet->setPropertyValue( "Name", Any(sIndexName) ); + } + +} + +void XMLIndexTOCContext::endFastElement(sal_Int32 ) +{ + // complete import of index by removing the markers (if the index + // was actually inserted, that is) + if( !bValid ) + return; + + // preliminaries + rtl::Reference<XMLTextImportHelper> rHelper= GetImport().GetTextImport(); + + // get rid of last paragraph (unless it's the only paragraph) + rHelper->GetCursor()->goRight(1, false); + if( xBodyContextRef.is() && xBodyContextRef->HasContent() ) + { + rHelper->GetCursor()->goLeft(1, true); + rHelper->GetText()->insertString(rHelper->GetCursorAsRange(), + "", true); + } + + // and delete second marker + rHelper->GetCursor()->goRight(1, true); + rHelper->GetText()->insertString(rHelper->GetCursorAsRange(), + "", true); + + // check for Redlines on our end node + GetImport().GetTextImport()->RedlineAdjustStartNodeCursor(); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexTOCContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContextRef xContext; + + // not valid -> ignore + if (!bValid) + return nullptr; + + if (nElement == XML_ELEMENT(TEXT, XML_INDEX_BODY) ) + { + rtl::Reference<XMLIndexBodyContext> xNewBodyContext = new XMLIndexBodyContext(GetImport()); + xContext = xNewBodyContext; + if ( !xBodyContextRef.is() || !xBodyContextRef->HasContent() ) + { + xBodyContextRef = xNewBodyContext; + } + } + else if (nElement == XML_ELEMENT(TEXT, aIndexSourceElementMap[eIndexType])) + { + // instantiate source context for the appropriate index type + switch (eIndexType) + { + case TEXT_INDEX_TOC: + xContext = new XMLIndexTOCSourceContext( + GetImport(), xTOCPropertySet); + break; + + case TEXT_INDEX_OBJECT: + xContext = new XMLIndexObjectSourceContext( + GetImport(), xTOCPropertySet); + break; + + case TEXT_INDEX_ALPHABETICAL: + xContext = new XMLIndexAlphabeticalSourceContext( + GetImport(), xTOCPropertySet); + break; + + case TEXT_INDEX_USER: + xContext = new XMLIndexUserSourceContext( + GetImport(), xTOCPropertySet); + break; + + case TEXT_INDEX_BIBLIOGRAPHY: + xContext = new XMLIndexBibliographySourceContext( + GetImport(), xTOCPropertySet); + break; + + case TEXT_INDEX_TABLE: + xContext = new XMLIndexTableSourceContext( + GetImport(), xTOCPropertySet); + break; + + case TEXT_INDEX_ILLUSTRATION: + xContext = new XMLIndexIllustrationSourceContext( + GetImport(), xTOCPropertySet); + break; + + default: + OSL_FAIL("index type not implemented"); + break; + } + } + // else: ignore + + return xContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTOCContext.hxx b/xmloff/source/text/XMLIndexTOCContext.hxx new file mode 100644 index 0000000000..47cd8ad2c2 --- /dev/null +++ b/xmloff/source/text/XMLIndexTOCContext.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <com/sun/star/uno/Reference.h> + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +enum IndexTypeEnum +{ + TEXT_INDEX_TOC, + TEXT_INDEX_ALPHABETICAL, + TEXT_INDEX_TABLE, + TEXT_INDEX_OBJECT, + TEXT_INDEX_BIBLIOGRAPHY, + TEXT_INDEX_USER, + TEXT_INDEX_ILLUSTRATION, + + TEXT_INDEX_UNKNOWN +}; + +class XMLIndexBodyContext; +/** + * Import all indices. + * + * Originally, this class would import only the TOC (table of + * content), but now it's role has been expanded to handle all + * indices, and hence is named inappropriately. Depending on the + * element name it decides which index source element context to create. + */ +class XMLIndexTOCContext final : public SvXMLImportContext +{ + /** XPropertySet of the index */ + css::uno::Reference<css::beans::XPropertySet> xTOCPropertySet; + + enum IndexTypeEnum eIndexType; + + bool bValid; + + rtl::Reference<XMLIndexBodyContext> xBodyContextRef; + +public: + + XMLIndexTOCContext( SvXMLImport& rImport, sal_Int32 nElement ); + + virtual ~XMLIndexTOCContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTOCSourceContext.cxx b/xmloff/source/text/XMLIndexTOCSourceContext.cxx new file mode 100644 index 0000000000..8850493b86 --- /dev/null +++ b/xmloff/source/text/XMLIndexTOCSourceContext.cxx @@ -0,0 +1,149 @@ +/* -*- 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 "XMLIndexTOCSourceContext.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <sax/tools/converter.hxx> +#include "XMLIndexTemplateContext.hxx" +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/txtimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <rtl/ustring.hxx> + + +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; + +XMLIndexTOCSourceContext::XMLIndexTOCSourceContext( + SvXMLImport& rImport, + Reference<XPropertySet> & rPropSet) +: XMLIndexSourceBaseContext(rImport, rPropSet, UseStyles::Level) + // use all chapters by default +, nOutlineLevel(rImport.GetTextImport()->GetChapterNumbering()->getCount()) +, bUseOutline(true) +, bUseMarks(true) +, bUseParagraphStyles(false) +{ +} + +XMLIndexTOCSourceContext::~XMLIndexTOCSourceContext() +{ +} + +void XMLIndexTOCSourceContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL): + if ( IsXMLToken( aIter, XML_NONE ) ) + { + // #104651# use OUTLINE_LEVEL and USE_OUTLINE_LEVEL instead of + // OUTLINE_LEVEL with values none|1..10. For backwards + // compatibility, 'none' must still be read. + bUseOutline = false; + } + else + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber( + nTmp, aIter.toView(), 1, GetImport().GetTextImport()-> + GetChapterNumbering()->getCount())) + { + bUseOutline = true; + nOutlineLevel = nTmp; + } + } + break; + + case XML_ELEMENT(TEXT, XML_USE_OUTLINE_LEVEL): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseOutline = bTmp; + } + break; + } + + + case XML_ELEMENT(TEXT, XML_USE_INDEX_MARKS): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseMarks = bTmp; + } + break; + } + + case XML_ELEMENT(TEXT, XML_USE_INDEX_SOURCE_STYLES): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseParagraphStyles = bTmp; + } + break; + } + + default: + // default: ask superclass + XMLIndexSourceBaseContext::ProcessAttribute(aIter); + break; + } +} + +void XMLIndexTOCSourceContext::endFastElement(sal_Int32 nElement) +{ + rIndexPropertySet->setPropertyValue("CreateFromMarks", css::uno::Any(bUseMarks)); + rIndexPropertySet->setPropertyValue("CreateFromOutline", css::uno::Any(bUseOutline)); + rIndexPropertySet->setPropertyValue("CreateFromLevelParagraphStyles", css::uno::Any(bUseParagraphStyles)); + + rIndexPropertySet->setPropertyValue("Level", css::uno::Any(static_cast<sal_Int16>(nOutlineLevel))); + + // process common attributes + XMLIndexSourceBaseContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexTOCSourceContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_TABLE_OF_CONTENT_ENTRY_TEMPLATE) ) + { + return new XMLIndexTemplateContext(GetImport(), rIndexPropertySet, + aSvLevelNameTOCMap, + XML_OUTLINE_LEVEL, + aLevelStylePropNameTOCMap, + aAllowedTokenTypesTOC, true ); + } + else + { + return XMLIndexSourceBaseContext::createFastChildContext(nElement, + xAttrList); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTOCSourceContext.hxx b/xmloff/source/text/XMLIndexTOCSourceContext.hxx new file mode 100644 index 0000000000..f8129fc149 --- /dev/null +++ b/xmloff/source/text/XMLIndexTOCSourceContext.hxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "XMLIndexSourceBaseContext.hxx" +#include <com/sun/star/uno/Reference.h> + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +/** + * Import table of context source element + */ +class XMLIndexTOCSourceContext : public XMLIndexSourceBaseContext +{ + sal_Int32 nOutlineLevel; + bool bUseOutline; + bool bUseMarks; + bool bUseParagraphStyles; + +public: + + + XMLIndexTOCSourceContext( + SvXMLImport& rImport, + css::uno::Reference<css::beans::XPropertySet> & rPropSet); + + virtual ~XMLIndexTOCSourceContext() override; + +protected: + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTOCStylesContext.cxx b/xmloff/source/text/XMLIndexTOCStylesContext.cxx new file mode 100644 index 0000000000..ff9cfaa4cb --- /dev/null +++ b/xmloff/source/text/XMLIndexTOCStylesContext.cxx @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "XMLIndexTOCStylesContext.hxx" + +#include "XMLIndexSourceBaseContext.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/txtimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmltoken.hxx> +#include <sax/tools/converter.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <rtl/ustring.hxx> + + +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; +using ::com::sun::star::container::XIndexReplace; + + + +XMLIndexTOCStylesContext::XMLIndexTOCStylesContext( + SvXMLImport& rImport, Reference<XPropertySet> & rPropSet) + : SvXMLImportContext(rImport) + , rTOCPropertySet(rPropSet) + , nOutlineLevel(0) +{ +} + +XMLIndexTOCStylesContext::~XMLIndexTOCStylesContext() +{ +} + +void XMLIndexTOCStylesContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // find text:outline-level attribute + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL) ) + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber( + nTmp, aIter.toView(), 1, + GetImport().GetTextImport()->GetChapterNumbering()-> + getCount())) + { + // API numbers 0..9, we number 1..10 + nOutlineLevel = nTmp-1; + } + break; + } + } +} + +void XMLIndexTOCStylesContext::endFastElement(sal_Int32 ) +{ + // if valid... + if (nOutlineLevel < 0) + return; + + // copy vector into sequence + const sal_Int32 nCount = aStyleNames.size(); + Sequence<OUString> aStyleNamesSequence(nCount); + auto aStyleNamesSequenceRange = asNonConstRange(aStyleNamesSequence); + for(sal_Int32 i = 0; i < nCount; i++) + { + aStyleNamesSequenceRange[i] = GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_PARAGRAPH, + aStyleNames[i] ); + } + + // get index replace + Any aAny = rTOCPropertySet->getPropertyValue("LevelParagraphStyles"); + Reference<XIndexReplace> xIndexReplace; + aAny >>= xIndexReplace; + + // set style names + xIndexReplace->replaceByIndex(nOutlineLevel, Any(aStyleNamesSequence)); +} + +namespace xmloff { + +OUString GetIndexSourceStyleName( + css::uno::Reference<css::xml::sax::XFastAttributeList> const& xAttrList) +{ + for (auto& rIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + if (rIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME)) + { + return rIter.toString(); + } + } + return OUString(); +} + +} // namespace xmloff + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexTOCStylesContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // check for index-source-style + if ( nElement == XML_ELEMENT(TEXT, XML_INDEX_SOURCE_STYLE) ) + { + // find text:style-name attribute and record in aStyleNames + OUString const styleName(xmloff::GetIndexSourceStyleName(xAttrList)); + if (!styleName.isEmpty()) + { + aStyleNames.emplace_back(styleName); + } + } + + // always return default context; we already got the interesting info + return new SvXMLImportContext(GetImport()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTOCStylesContext.hxx b/xmloff/source/text/XMLIndexTOCStylesContext.hxx new file mode 100644 index 0000000000..a34cf604f1 --- /dev/null +++ b/xmloff/source/text/XMLIndexTOCStylesContext.hxx @@ -0,0 +1,73 @@ +/* -*- 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 <com/sun/star/uno/Reference.h> + +#include <vector> + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +/** + * Import <test:index-source-styles> elements and their children + * + * (Small hackery here: Because there's only one type of child + * elements with only one interesting attribute, we completely handle + * them inside the CreateChildContext method, rather than creating a + * new import class for them. This must be changed if children become + * more complex in future versions.) + */ +class XMLIndexTOCStylesContext : public SvXMLImportContext +{ + /// XPropertySet of the index + css::uno::Reference<css::beans::XPropertySet> & rTOCPropertySet; + + /// style names for this level + ::std::vector< OUString > aStyleNames; + + /// outline level + sal_Int32 nOutlineLevel; + +public: + XMLIndexTOCStylesContext( + SvXMLImport& rImport, + css::uno::Reference<css::beans::XPropertySet> & rPropSet ); + + virtual ~XMLIndexTOCStylesContext() override; + +protected: + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTabStopEntryContext.cxx b/xmloff/source/text/XMLIndexTabStopEntryContext.cxx new file mode 100644 index 0000000000..cf7b339a04 --- /dev/null +++ b/xmloff/source/text/XMLIndexTabStopEntryContext.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 "XMLIndexTabStopEntryContext.hxx" + +#include <sax/tools/converter.hxx> + +#include "XMLIndexTemplateContext.hxx" +#include <xmloff/xmlimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> + +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::PropertyValue; + + +XMLIndexTabStopEntryContext::XMLIndexTabStopEntryContext( + SvXMLImport& rImport, + XMLIndexTemplateContext& rTemplate ) : + XMLIndexSimpleEntryContext(rImport, "TokenTabStop", + rTemplate), + nTabPosition(0), + bTabPositionOK(false), + bTabRightAligned(false), + bLeaderCharOK(false), + bWithTab(true) // #i21237# +{ +} + +XMLIndexTabStopEntryContext::~XMLIndexTabStopEntryContext() +{ +} + +void XMLIndexTabStopEntryContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // process three attributes: type, position, leader char + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(STYLE, XML_TYPE): + { + // if it's neither left nor right, value is + // ignored. Since left is default, we only need to + // check for right + bTabRightAligned = IsXMLToken( aIter, XML_RIGHT ); + break; + } + case XML_ELEMENT(STYLE, XML_POSITION): + { + sal_Int32 nTmp; + if (GetImport().GetMM100UnitConverter(). + convertMeasureToCore(nTmp, aIter.toView())) + { + nTabPosition = nTmp; + bTabPositionOK = true; + } + break; + } + case XML_ELEMENT(STYLE, XML_LEADER_CHAR): + { + sLeaderChar = aIter.toString(); + // valid only, if we have a char! + bLeaderCharOK = !sLeaderChar.isEmpty(); + break; + } + case XML_ELEMENT(STYLE, XML_WITH_TAB): + { + // #i21237# + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + bWithTab = bTmp; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + // else: unknown style: attribute -> ignore + } + } + + // how many entries? #i21237# + m_nValues += 2 + (bTabPositionOK ? 1 : 0) + (bLeaderCharOK ? 1 : 0); + + // now try parent class (for character style) + XMLIndexSimpleEntryContext::startFastElement( nElement, xAttrList ); +} + +void XMLIndexTabStopEntryContext::FillPropertyValues( + Sequence<PropertyValue> & rValues) +{ + // fill values from parent class (type + style name) + XMLIndexSimpleEntryContext::FillPropertyValues(rValues); + + // get values array and next entry to be written; + sal_Int32 nNextEntry = m_bCharStyleNameOK ? 2 : 1; + PropertyValue* pValues = rValues.getArray(); + + // right aligned? + pValues[nNextEntry].Name = "TabStopRightAligned"; + pValues[nNextEntry].Value <<= bTabRightAligned; + nNextEntry++; + + // position + if (bTabPositionOK) + { + pValues[nNextEntry].Name = "TabStopPosition"; + pValues[nNextEntry].Value <<= nTabPosition; + nNextEntry++; + } + + // leader char + if (bLeaderCharOK) + { + pValues[nNextEntry].Name = "TabStopFillCharacter"; + pValues[nNextEntry].Value <<= sLeaderChar; + nNextEntry++; + } + + // tab character #i21237# + pValues[nNextEntry].Name = "WithTab"; + pValues[nNextEntry].Value <<= bWithTab; + nNextEntry++; + + // check whether we really filled all elements of the sequence + SAL_WARN_IF( nNextEntry != rValues.getLength(), "xmloff", + "length incorrectly precomputed!" ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTabStopEntryContext.hxx b/xmloff/source/text/XMLIndexTabStopEntryContext.hxx new file mode 100644 index 0000000000..5c208f6385 --- /dev/null +++ b/xmloff/source/text/XMLIndexTabStopEntryContext.hxx @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "XMLIndexSimpleEntryContext.hxx" +#include <rtl/ustring.hxx> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/beans/PropertyValue.hpp> + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } +} +class XMLIndexTemplateContext; + +/** + * Import index entry templates + */ +class XMLIndexTabStopEntryContext : public XMLIndexSimpleEntryContext +{ + OUString sLeaderChar; /// fill ("leader") character + sal_Int32 nTabPosition; /// tab position + bool bTabPositionOK; /// is tab right aligned? + bool bTabRightAligned; /// is nTabPosition valid? + bool bLeaderCharOK; /// is sLeaderChar valid? + bool bWithTab; /// is tab char present? #i21237# + +public: + + + XMLIndexTabStopEntryContext( + SvXMLImport& rImport, + XMLIndexTemplateContext& rTemplate ); + + virtual ~XMLIndexTabStopEntryContext() override; + +protected: + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + /** fill property values for this template entry */ + virtual void FillPropertyValues( + css::uno::Sequence<css::beans::PropertyValue> & rValues) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTableSourceContext.cxx b/xmloff/source/text/XMLIndexTableSourceContext.cxx new file mode 100644 index 0000000000..48855b6ac0 --- /dev/null +++ b/xmloff/source/text/XMLIndexTableSourceContext.cxx @@ -0,0 +1,146 @@ +/* -*- 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 "XMLIndexTableSourceContext.hxx" + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/text/ReferenceFieldPart.hpp> + +#include <sax/tools/converter.hxx> + +#include "XMLIndexTemplateContext.hxx" +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> +#include <rtl/ustring.hxx> + + +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; + +XMLIndexTableSourceContext::XMLIndexTableSourceContext( + SvXMLImport& rImport, Reference<XPropertySet> & rPropSet) + : XMLIndexSourceBaseContext(rImport, rPropSet, UseStyles::Single) + , nDisplayFormat(0) + , bSequenceOK(false) + , bDisplayFormatOK(false) + , bUseCaption(true) +{ +} + +XMLIndexTableSourceContext::~XMLIndexTableSourceContext() +{ +} + +SvXMLEnumMapEntry<sal_uInt16> const lcl_aReferenceTypeTokenMap[] = +{ + + { XML_TEXT, ReferenceFieldPart::TEXT }, + { XML_CATEGORY_AND_VALUE, ReferenceFieldPart::CATEGORY_AND_NUMBER }, + { XML_CAPTION, ReferenceFieldPart::ONLY_CAPTION }, + + // wrong values that previous versions wrote: + { XML_CHAPTER, ReferenceFieldPart::CATEGORY_AND_NUMBER }, + { XML_PAGE, ReferenceFieldPart::ONLY_CAPTION }, + + { XML_TOKEN_INVALID, 0 } +}; + +void XMLIndexTableSourceContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + bool bTmp(false); + + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_USE_CAPTION): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseCaption = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_CAPTION_SEQUENCE_NAME): + sSequence = aIter.toString(); + bSequenceOK = true; + break; + + case XML_ELEMENT(TEXT, XML_CAPTION_SEQUENCE_FORMAT): + { + sal_uInt16 nTmp; + if (SvXMLUnitConverter::convertEnum(nTmp, aIter.toView(), + lcl_aReferenceTypeTokenMap)) + { + nDisplayFormat = nTmp; + bDisplayFormatOK = true; + } + break; + } + + default: + XMLIndexSourceBaseContext::ProcessAttribute(aIter); + break; + } +} + +void XMLIndexTableSourceContext::endFastElement(sal_Int32 nElement) +{ + rIndexPropertySet->setPropertyValue("CreateFromLabels", css::uno::Any(bUseCaption)); + + if (bSequenceOK) + { + rIndexPropertySet->setPropertyValue("LabelCategory", css::uno::Any(sSequence)); + } + + if (bDisplayFormatOK) + { + rIndexPropertySet->setPropertyValue("LabelDisplayType", css::uno::Any(nDisplayFormat)); + } + + XMLIndexSourceBaseContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexTableSourceContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_TABLE_INDEX_ENTRY_TEMPLATE) ) + { + return new XMLIndexTemplateContext(GetImport(), rIndexPropertySet, + aLevelNameTableMap, + XML_TOKEN_INVALID, // no outline-level attr + aLevelStylePropNameTableMap, + aAllowedTokenTypesTable); + } + else + { + return XMLIndexSourceBaseContext::createFastChildContext(nElement, + xAttrList); + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTableSourceContext.hxx b/xmloff/source/text/XMLIndexTableSourceContext.hxx new file mode 100644 index 0000000000..1a0a7b0bfb --- /dev/null +++ b/xmloff/source/text/XMLIndexTableSourceContext.hxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "XMLIndexSourceBaseContext.hxx" +#include <com/sun/star/uno/Reference.h> + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +/** + * Import table index source element + */ +class XMLIndexTableSourceContext : public XMLIndexSourceBaseContext +{ + OUString sSequence; + sal_Int16 nDisplayFormat; + + bool bSequenceOK; + bool bDisplayFormatOK; + bool bUseCaption; + +public: + + XMLIndexTableSourceContext( + SvXMLImport& rImport, + css::uno::Reference<css::beans::XPropertySet> & rPropSet); + + virtual ~XMLIndexTableSourceContext() override; + +protected: + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTemplateContext.cxx b/xmloff/source/text/XMLIndexTemplateContext.cxx new file mode 100644 index 0000000000..411e4c6b94 --- /dev/null +++ b/xmloff/source/text/XMLIndexTemplateContext.cxx @@ -0,0 +1,420 @@ +/* -*- 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 "XMLIndexTemplateContext.hxx" +#include "XMLIndexSimpleEntryContext.hxx" +#include "XMLIndexSpanEntryContext.hxx" +#include "XMLIndexTabStopEntryContext.hxx" +#include "XMLIndexBibliographyEntryContext.hxx" +#include "XMLIndexChapterInfoEntryContext.hxx" +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/txtimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> +#include <tools/debug.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <algorithm> + +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::beans::PropertyValues; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; +using ::com::sun::star::container::XIndexReplace; + +XMLIndexTemplateContext::XMLIndexTemplateContext( + SvXMLImport& rImport, + Reference<XPropertySet> & rPropSet, + const SvXMLEnumMapEntry<sal_uInt16>* pLevelNameMap, + enum XMLTokenEnum eLevelAttrName, + const char** pLevelStylePropMap, + const bool* pAllowedTokenTypes, + bool bT ) +: SvXMLImportContext(rImport) +, pOutlineLevelNameMap(pLevelNameMap) +, eOutlineLevelAttrName(eLevelAttrName) +, pOutlineLevelStylePropMap(pLevelStylePropMap) +, pAllowedTokenTypesMap(pAllowedTokenTypes) +, nOutlineLevel(1) // all indices have level 1 (0 is for header) +, bStyleNameOK(false) +, bOutlineLevelOK(false) +, bTOC( bT ) +, rPropertySet(rPropSet) +{ + DBG_ASSERT( ((XML_TOKEN_INVALID != eLevelAttrName) && (nullptr != pLevelNameMap)) + || ((XML_TOKEN_INVALID == eLevelAttrName) && (nullptr == pLevelNameMap)), + "need both, attribute name and value map, or neither" ); + SAL_WARN_IF( nullptr == pOutlineLevelStylePropMap, "xmloff", "need property name map" ); + SAL_WARN_IF( nullptr == pAllowedTokenTypes, "xmloff", "need allowed tokens map" ); + + // no map for outline-level? then use 1 + if (nullptr == pLevelNameMap) + { + nOutlineLevel = 1; + bOutlineLevelOK = true; + } +} + +XMLIndexTemplateContext::~XMLIndexTemplateContext() +{ +} + + +void XMLIndexTemplateContext::addTemplateEntry( + const PropertyValues& aValues) +{ + aValueVector.push_back(aValues); +} + + +void XMLIndexTemplateContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // process two attributes: style-name, outline-level + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if(aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME)) + { + // style name + sStyleName = aIter.toString(); + bStyleNameOK = true; + } + else if (aIter.getToken() == XML_ELEMENT(TEXT, eOutlineLevelAttrName)) + { + // we have an attr name! Then see if we have the attr, too. + // outline level + sal_uInt16 nTmp; + if (SvXMLUnitConverter::convertEnum(nTmp, aIter.toView(), pOutlineLevelNameMap)) + { + nOutlineLevel = nTmp; + bOutlineLevelOK = true; + } + // else: illegal value -> ignore + } + // else: attribute not in text namespace -> ignore + } +} + +void XMLIndexTemplateContext::endFastElement(sal_Int32 ) +{ + if (!bOutlineLevelOK) + return; + + const sal_Int32 nCount = aValueVector.size(); + Sequence<PropertyValues> aValueSequence(nCount); + std::copy(aValueVector.begin(), aValueVector.end(), aValueSequence.getArray()); + + // get LevelFormat IndexReplace ... + Any aAny = rPropertySet->getPropertyValue("LevelFormat"); + Reference<XIndexReplace> xIndexReplace; + aAny >>= xIndexReplace; + + // ... and insert + xIndexReplace->replaceByIndex(nOutlineLevel, Any(aValueSequence)); + + if (!bStyleNameOK) + return; + + const char* pStyleProperty = + pOutlineLevelStylePropMap[nOutlineLevel]; + + DBG_ASSERT(nullptr != pStyleProperty, "need property name"); + if (nullptr == pStyleProperty) + return; + + OUString sDisplayStyleName = + GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_PARAGRAPH, + sStyleName ); + // #i50288#: Check if style exists + const Reference < css::container::XNameContainer > & rStyles = + GetImport().GetTextImport()->GetParaStyles(); + if( rStyles.is() && + rStyles->hasByName( sDisplayStyleName ) ) + { + rPropertySet->setPropertyValue( + OUString::createFromAscii(pStyleProperty), css::uno::Any(sDisplayStyleName)); + } +} + +namespace { +/// template token types; used for aTokenTypeMap parameter +enum TemplateTokenType +{ + XML_TOK_INDEX_TYPE_ENTRY_TEXT = 0, + XML_TOK_INDEX_TYPE_TAB_STOP, + XML_TOK_INDEX_TYPE_TEXT, + XML_TOK_INDEX_TYPE_PAGE_NUMBER, + XML_TOK_INDEX_TYPE_CHAPTER, + XML_TOK_INDEX_TYPE_LINK_START, + XML_TOK_INDEX_TYPE_LINK_END, + XML_TOK_INDEX_TYPE_BIBLIOGRAPHY +}; + +} + +SvXMLEnumMapEntry<TemplateTokenType> const aTemplateTokenTypeMap[] = +{ + { XML_INDEX_ENTRY_TEXT, XML_TOK_INDEX_TYPE_ENTRY_TEXT }, + { XML_INDEX_ENTRY_TAB_STOP, XML_TOK_INDEX_TYPE_TAB_STOP }, + { XML_INDEX_ENTRY_SPAN, XML_TOK_INDEX_TYPE_TEXT }, + { XML_INDEX_ENTRY_PAGE_NUMBER, XML_TOK_INDEX_TYPE_PAGE_NUMBER }, + { XML_INDEX_ENTRY_CHAPTER, XML_TOK_INDEX_TYPE_CHAPTER }, + { XML_INDEX_ENTRY_LINK_START, XML_TOK_INDEX_TYPE_LINK_START }, + { XML_INDEX_ENTRY_LINK_END, XML_TOK_INDEX_TYPE_LINK_END }, + { XML_INDEX_ENTRY_BIBLIOGRAPHY, XML_TOK_INDEX_TYPE_BIBLIOGRAPHY }, + { XML_TOKEN_INVALID, TemplateTokenType(0) } +}; + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexTemplateContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + + if (IsTokenInNamespace(nElement, XML_NAMESPACE_TEXT) || IsTokenInNamespace(nElement, XML_NAMESPACE_LO_EXT)) + { + TemplateTokenType nToken; + if (SvXMLUnitConverter::convertEnum(nToken, SvXMLImport::getNameFromToken(nElement), + aTemplateTokenTypeMap)) + { + // can this index accept this kind of token? + if (pAllowedTokenTypesMap[nToken]) + { + switch (nToken) + { + case XML_TOK_INDEX_TYPE_ENTRY_TEXT: + pContext = new XMLIndexSimpleEntryContext( + GetImport(), "TokenEntryText", *this); + break; + + case XML_TOK_INDEX_TYPE_PAGE_NUMBER: + pContext = new XMLIndexSimpleEntryContext( + GetImport(), "TokenPageNumber", *this); + break; + + case XML_TOK_INDEX_TYPE_LINK_START: + pContext = new XMLIndexSimpleEntryContext( + GetImport(), "TokenHyperlinkStart", *this); + break; + + case XML_TOK_INDEX_TYPE_LINK_END: + pContext = new XMLIndexSimpleEntryContext( + GetImport(), "TokenHyperlinkEnd", *this); + break; + + case XML_TOK_INDEX_TYPE_TEXT: + pContext = new XMLIndexSpanEntryContext( + GetImport(), *this); + break; + + case XML_TOK_INDEX_TYPE_TAB_STOP: + pContext = new XMLIndexTabStopEntryContext( + GetImport(), *this); + break; + + case XML_TOK_INDEX_TYPE_BIBLIOGRAPHY: + pContext = new XMLIndexBibliographyEntryContext( + GetImport(), *this); + break; + + case XML_TOK_INDEX_TYPE_CHAPTER: + pContext = new XMLIndexChapterInfoEntryContext( + GetImport(), *this, bTOC ); + break; + + default: + // ignore! + break; + } + } + } + } + + // ignore unknown + return pContext; +} + + +// maps for the XMLIndexTemplateContext constructor + + +// table of content and user defined index: + +const SvXMLEnumMapEntry<sal_uInt16> aSvLevelNameTOCMap[] = +{ + { XML_1, 1 }, + { XML_2, 2 }, + { XML_3, 3 }, + { XML_4, 4 }, + { XML_5, 5 }, + { XML_6, 6 }, + { XML_7, 7 }, + { XML_8, 8 }, + { XML_9, 9 }, + { XML_10, 10 }, + { XML_TOKEN_INVALID, 0 } +}; + +const char* aLevelStylePropNameTOCMap[] = + { nullptr, "ParaStyleLevel1", "ParaStyleLevel2", "ParaStyleLevel3", + "ParaStyleLevel4", "ParaStyleLevel5", "ParaStyleLevel6", + "ParaStyleLevel7", "ParaStyleLevel8", "ParaStyleLevel9", + "ParaStyleLevel10", nullptr }; + +const bool aAllowedTokenTypesTOC[] = +{ + true, // XML_TOK_INDEX_TYPE_ENTRY_TEXT = + true, // XML_TOK_INDEX_TYPE_TAB_STOP, + true, // XML_TOK_INDEX_TYPE_TEXT, + true, // XML_TOK_INDEX_TYPE_PAGE_NUMBER, + true, // XML_TOK_INDEX_TYPE_CHAPTER, + true, // XML_TOK_INDEX_TYPE_LINK_START, + true, // XML_TOK_INDEX_TYPE_LINK_END, + false // XML_TOK_INDEX_TYPE_BIBLIOGRAPHY +}; + +const bool aAllowedTokenTypesUser[] = +{ + true, // XML_TOK_INDEX_TYPE_ENTRY_TEXT = + true, // XML_TOK_INDEX_TYPE_TAB_STOP, + true, // XML_TOK_INDEX_TYPE_TEXT, + true, // XML_TOK_INDEX_TYPE_PAGE_NUMBER, + true, // XML_TOK_INDEX_TYPE_CHAPTER, + true, // XML_TOK_INDEX_TYPE_LINK_START, + true, // XML_TOK_INDEX_TYPE_LINK_END, + false // XML_TOK_INDEX_TYPE_BIBLIOGRAPHY +}; + + +// alphabetical index + +const SvXMLEnumMapEntry<sal_uInt16> aLevelNameAlphaMap[] = +{ + { XML_SEPARATOR, 1 }, + { XML_1, 2 }, + { XML_2, 3 }, + { XML_3, 4 }, + { XML_TOKEN_INVALID, 0 } +}; + +const char* aLevelStylePropNameAlphaMap[] = + { nullptr, "ParaStyleSeparator", "ParaStyleLevel1", "ParaStyleLevel2", + "ParaStyleLevel3", nullptr }; + +const bool aAllowedTokenTypesAlpha[] = +{ + true, // XML_TOK_INDEX_TYPE_ENTRY_TEXT = + true, // XML_TOK_INDEX_TYPE_TAB_STOP, + true, // XML_TOK_INDEX_TYPE_TEXT, + true, // XML_TOK_INDEX_TYPE_PAGE_NUMBER, + true, // XML_TOK_INDEX_TYPE_CHAPTER, + false, // XML_TOK_INDEX_TYPE_LINK_START, + false, // XML_TOK_INDEX_TYPE_LINK_END, + false // XML_TOK_INDEX_TYPE_BIBLIOGRAPHY +}; + + +// bibliography index: + +const SvXMLEnumMapEntry<sal_uInt16> aLevelNameBibliographyMap[] = +{ + { XML_ARTICLE, 1 }, + { XML_BOOK, 2 }, + { XML_BOOKLET, 3 }, + { XML_CONFERENCE, 4 }, + { XML_CUSTOM1, 5 }, + { XML_CUSTOM2, 6 }, + { XML_CUSTOM3, 7 }, + { XML_CUSTOM4, 8 }, + { XML_CUSTOM5, 9 }, + { XML_EMAIL, 10 }, + { XML_INBOOK, 11 }, + { XML_INCOLLECTION, 12 }, + { XML_INPROCEEDINGS, 13 }, + { XML_JOURNAL, 14 }, + { XML_MANUAL, 15 }, + { XML_MASTERSTHESIS, 16 }, + { XML_MISC, 17 }, + { XML_PHDTHESIS, 18 }, + { XML_PROCEEDINGS, 19 }, + { XML_TECHREPORT, 20 }, + { XML_UNPUBLISHED, 21 }, + { XML_WWW, 22 }, + { XML_TOKEN_INVALID, 0 } +}; + +// TODO: replace with real property names, when available +const char* aLevelStylePropNameBibliographyMap[] = +{ + nullptr, "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", nullptr }; + +const bool aAllowedTokenTypesBibliography[] = +{ + true, // XML_TOK_INDEX_TYPE_ENTRY_TEXT = + true, // XML_TOK_INDEX_TYPE_TAB_STOP, + true, // XML_TOK_INDEX_TYPE_TEXT, + true, // XML_TOK_INDEX_TYPE_PAGE_NUMBER, + false, // XML_TOK_INDEX_TYPE_CHAPTER, + false, // XML_TOK_INDEX_TYPE_LINK_START, + false, // XML_TOK_INDEX_TYPE_LINK_END, + true // XML_TOK_INDEX_TYPE_BIBLIOGRAPHY +}; + + +// table, illustration and object index + +// no name map +const SvXMLEnumMapEntry<sal_uInt16>* aLevelNameTableMap = nullptr; + +const char* aLevelStylePropNameTableMap[] = + { nullptr, "ParaStyleLevel1", nullptr }; + +const bool aAllowedTokenTypesTable[] = +{ + true, // XML_TOK_INDEX_TYPE_ENTRY_TEXT = + true, // XML_TOK_INDEX_TYPE_TAB_STOP, + true, // XML_TOK_INDEX_TYPE_TEXT, + true, // XML_TOK_INDEX_TYPE_PAGE_NUMBER, + true, // XML_TOK_INDEX_TYPE_CHAPTER, + true, // XML_TOK_INDEX_TYPE_LINK_START, + true, // XML_TOK_INDEX_TYPE_LINK_END, + false // XML_TOK_INDEX_TYPE_BIBLIOGRAPHY +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTemplateContext.hxx b/xmloff/source/text/XMLIndexTemplateContext.hxx new file mode 100644 index 0000000000..424693d7e4 --- /dev/null +++ b/xmloff/source/text/XMLIndexTemplateContext.hxx @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmltoken.hxx> + +#include <vector> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/beans/PropertyValues.hpp> + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} +template<typename EnumT> struct SvXMLEnumMapEntry; + + +// constants for the XMLIndexTemplateContext constructor + +// TOC and user defined index: +extern const SvXMLEnumMapEntry<sal_uInt16> aSvLevelNameTOCMap[]; +extern const char* aLevelStylePropNameTOCMap[]; +extern const bool aAllowedTokenTypesTOC[]; +extern const bool aAllowedTokenTypesUser[]; + +// alphabetical index: +extern const SvXMLEnumMapEntry<sal_uInt16> aLevelNameAlphaMap[]; +extern const char* aLevelStylePropNameAlphaMap[]; +extern const bool aAllowedTokenTypesAlpha[]; + +// bibliography: +extern const SvXMLEnumMapEntry<sal_uInt16> aLevelNameBibliographyMap[]; +extern const char* aLevelStylePropNameBibliographyMap[]; +extern const bool aAllowedTokenTypesBibliography[]; + +// table, illustration and object tables: +extern const SvXMLEnumMapEntry<sal_uInt16>* aLevelNameTableMap; // NULL: no outline-level +extern const char* aLevelStylePropNameTableMap[]; +extern const bool aAllowedTokenTypesTable[]; + + +/** + * Import index entry templates + */ +class XMLIndexTemplateContext : public SvXMLImportContext +{ + // pick up PropertyValues to be turned into a sequence. + ::std::vector< css::beans::PropertyValues > aValueVector; + + OUString sStyleName; + + const SvXMLEnumMapEntry<sal_uInt16>* pOutlineLevelNameMap; + enum ::xmloff::token::XMLTokenEnum eOutlineLevelAttrName; + const char** pOutlineLevelStylePropMap; + const bool* pAllowedTokenTypesMap; + + sal_Int32 nOutlineLevel; + bool bStyleNameOK; + bool bOutlineLevelOK; + bool bTOC; + + // PropertySet of current index + css::uno::Reference<css::beans::XPropertySet> & rPropertySet; + +public: + template<typename EnumT> + XMLIndexTemplateContext( + SvXMLImport& rImport, + css::uno::Reference<css::beans::XPropertySet> & rPropSet, + const SvXMLEnumMapEntry<EnumT>* aLevelNameMap, + enum ::xmloff::token::XMLTokenEnum eLevelAttrName, + const char** aLevelStylePropNameMap, + const bool* aAllowedTokenTypes, + bool bTOC_=false) + : XMLIndexTemplateContext(rImport,rPropSet, + reinterpret_cast<const SvXMLEnumMapEntry<sal_uInt16>*>(aLevelNameMap), + eLevelAttrName, aLevelStylePropNameMap, aAllowedTokenTypes, bTOC_) {} + XMLIndexTemplateContext( + SvXMLImport& rImport, + css::uno::Reference<css::beans::XPropertySet> & rPropSet, + const SvXMLEnumMapEntry<sal_uInt16>* aLevelNameMap, + enum ::xmloff::token::XMLTokenEnum eLevelAttrName, + const char** aLevelStylePropNameMap, + const bool* aAllowedTokenTypes, + bool bTOC); + + virtual ~XMLIndexTemplateContext() override; + + /** add template; to be called by child template entry contexts */ + void addTemplateEntry( + const css::beans::PropertyValues& aValues); + +protected: + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTitleTemplateContext.cxx b/xmloff/source/text/XMLIndexTitleTemplateContext.cxx new file mode 100644 index 0000000000..5d1f47fdb8 --- /dev/null +++ b/xmloff/source/text/XMLIndexTitleTemplateContext.cxx @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "XMLIndexTitleTemplateContext.hxx" +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <sal/log.hxx> + +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::xmloff::token::XML_STYLE_NAME; + + +XMLIndexTitleTemplateContext::XMLIndexTitleTemplateContext( + SvXMLImport& rImport, + Reference<XPropertySet> & rPropSet) +: SvXMLImportContext(rImport) +, bStyleNameOK(false) +, rTOCPropertySet(rPropSet) +{ +} + + +XMLIndexTitleTemplateContext::~XMLIndexTitleTemplateContext() +{ +} + +void XMLIndexTitleTemplateContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // there's only one attribute: style-name + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME) ) + { + sStyleName = aIter.toString(); + OUString sDisplayStyleName = GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_PARAGRAPH, sStyleName ); + const Reference < css::container::XNameContainer >& + rStyles = GetImport().GetTextImport()->GetParaStyles(); + bStyleNameOK = rStyles.is() && rStyles->hasByName( sDisplayStyleName ); + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +void XMLIndexTitleTemplateContext::endFastElement(sal_Int32 ) +{ + Any aAny; + + aAny <<= sContent.makeStringAndClear(); + rTOCPropertySet->setPropertyValue("Title", aAny); + + if (bStyleNameOK) + { + aAny <<= GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_PARAGRAPH, + sStyleName ); + rTOCPropertySet->setPropertyValue("ParaStyleHeading", aAny); + } +} + +void XMLIndexTitleTemplateContext::characters( + const OUString& sString) +{ + sContent.append(sString); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTitleTemplateContext.hxx b/xmloff/source/text/XMLIndexTitleTemplateContext.hxx new file mode 100644 index 0000000000..2de1954997 --- /dev/null +++ b/xmloff/source/text/XMLIndexTitleTemplateContext.hxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <com/sun/star/uno/Reference.h> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> + + +namespace com::sun::star { + namespace beans { class XPropertySet; } + namespace xml::sax { class XAttributeList; } +} + + +/** + * Import index title templates + */ +class XMLIndexTitleTemplateContext : public SvXMLImportContext +{ + // paragraph style + OUString sStyleName; + bool bStyleNameOK; + + // content + OUStringBuffer sContent; + + // TOC property set + css::uno::Reference<css::beans::XPropertySet> & rTOCPropertySet; + +public: + + XMLIndexTitleTemplateContext( + SvXMLImport& rImport, + css::uno::Reference<css::beans::XPropertySet> & rPropSet); + + virtual ~XMLIndexTitleTemplateContext() override; + +protected: + + /** process parameters */ + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + /** set values */ + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + /** pick up title characters */ + virtual void SAL_CALL characters(const OUString& sString) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexUserSourceContext.cxx b/xmloff/source/text/XMLIndexUserSourceContext.cxx new file mode 100644 index 0000000000..e139a66c83 --- /dev/null +++ b/xmloff/source/text/XMLIndexUserSourceContext.cxx @@ -0,0 +1,157 @@ +/* -*- 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 "XMLIndexUserSourceContext.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <sax/tools/converter.hxx> +#include "XMLIndexTemplateContext.hxx" +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <rtl/ustring.hxx> + + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using namespace ::xmloff::token; + +XMLIndexUserSourceContext::XMLIndexUserSourceContext( + SvXMLImport& rImport, + Reference<XPropertySet> & rPropSet) + : XMLIndexSourceBaseContext(rImport, rPropSet, UseStyles::Level), + bUseObjects(false), + bUseGraphic(false), + bUseMarks(false), + bUseTables(false), + bUseFrames(false), + bUseLevelFromSource(false), + bUseLevelParagraphStyles(false) +{ +} + +XMLIndexUserSourceContext::~XMLIndexUserSourceContext() +{ +} + +void XMLIndexUserSourceContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + bool bTmp(false); + + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_USE_INDEX_MARKS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseMarks = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_OBJECTS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseObjects = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_GRAPHICS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseGraphic = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_TABLES): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseTables = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_FLOATING_FRAMES): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseFrames = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_COPY_OUTLINE_LEVELS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseLevelFromSource = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_INDEX_SOURCE_STYLES): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseLevelParagraphStyles = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_INDEX_NAME): + sIndexName = aIter.toString(); + break; + + default: + XMLIndexSourceBaseContext::ProcessAttribute(aIter); + break; + } +} + +void XMLIndexUserSourceContext::endFastElement(sal_Int32 nElement) +{ + rIndexPropertySet->setPropertyValue("CreateFromEmbeddedObjects", css::uno::Any(bUseObjects)); + rIndexPropertySet->setPropertyValue("CreateFromGraphicObjects", css::uno::Any(bUseGraphic)); + rIndexPropertySet->setPropertyValue("UseLevelFromSource", css::uno::Any(bUseLevelFromSource)); + rIndexPropertySet->setPropertyValue("CreateFromMarks", css::uno::Any(bUseMarks)); + rIndexPropertySet->setPropertyValue("CreateFromTables", css::uno::Any(bUseTables)); + rIndexPropertySet->setPropertyValue("CreateFromTextFrames", css::uno::Any(bUseFrames)); + rIndexPropertySet->setPropertyValue("CreateFromLevelParagraphStyles", css::uno::Any(bUseLevelParagraphStyles)); + + if( !sIndexName.isEmpty() ) + { + rIndexPropertySet->setPropertyValue("UserIndexName", css::uno::Any(sIndexName)); + } + + XMLIndexSourceBaseContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexUserSourceContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_USER_INDEX_ENTRY_TEMPLATE) ) + { + return new XMLIndexTemplateContext(GetImport(), rIndexPropertySet, + aSvLevelNameTOCMap, + XML_OUTLINE_LEVEL, + aLevelStylePropNameTOCMap, + aAllowedTokenTypesUser); + } + else + { + return XMLIndexSourceBaseContext::createFastChildContext(nElement, + xAttrList); + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexUserSourceContext.hxx b/xmloff/source/text/XMLIndexUserSourceContext.hxx new file mode 100644 index 0000000000..c275f8a053 --- /dev/null +++ b/xmloff/source/text/XMLIndexUserSourceContext.hxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "XMLIndexSourceBaseContext.hxx" +#include <com/sun/star/uno/Reference.h> + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +/** + * Import user defined index source element + */ +class XMLIndexUserSourceContext : public XMLIndexSourceBaseContext +{ + bool bUseObjects; + bool bUseGraphic; + bool bUseMarks; + bool bUseTables; + bool bUseFrames; + bool bUseLevelFromSource; + bool bUseLevelParagraphStyles; + OUString sIndexName; + +public: + + XMLIndexUserSourceContext( + SvXMLImport& rImport, + css::uno::Reference<css::beans::XPropertySet> & rPropSet); + + virtual ~XMLIndexUserSourceContext() override; + +protected: + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLLineNumberingExport.cxx b/xmloff/source/text/XMLLineNumberingExport.cxx new file mode 100644 index 0000000000..613f2d0334 --- /dev/null +++ b/xmloff/source/text/XMLLineNumberingExport.cxx @@ -0,0 +1,185 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "XMLLineNumberingExport.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/text/XLineNumberingProperties.hpp> +#include <com/sun/star/style/LineNumberPosition.hpp> +#include <o3tl/any.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlement.hxx> + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::text::XLineNumberingProperties; + + +XMLLineNumberingExport::XMLLineNumberingExport(SvXMLExport& rExp) +: rExport(rExp) +{ +} + +SvXMLEnumMapEntry<sal_uInt16> const aLineNumberPositionMap[] = +{ + { XML_LEFT, style::LineNumberPosition::LEFT }, + { XML_RIGHT, style::LineNumberPosition::RIGHT }, + { XML_INSIDE, style::LineNumberPosition::INSIDE }, + { XML_OUTSIDE, style::LineNumberPosition::OUTSIDE }, + { XML_TOKEN_INVALID, 0 } +}; + + +void XMLLineNumberingExport::Export() +{ + // export element if we have line numbering info + Reference<XLineNumberingProperties> xSupplier(rExport.GetModel(), + UNO_QUERY); + if (!xSupplier.is()) + return; + + Reference<XPropertySet> xLineNumbering = + xSupplier->getLineNumberingProperties(); + + if (!xLineNumbering.is()) + return; + + // char style + Any aAny = xLineNumbering->getPropertyValue("CharStyleName"); + OUString sTmp; + aAny >>= sTmp; + if (!sTmp.isEmpty()) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME, + rExport.EncodeStyleName( sTmp )); + } + + // enable + aAny = xLineNumbering->getPropertyValue("IsOn"); + if (! *o3tl::doAccess<bool>(aAny)) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, + XML_NUMBER_LINES, XML_FALSE); + } + + // count empty lines + aAny = xLineNumbering->getPropertyValue("CountEmptyLines"); + if (! *o3tl::doAccess<bool>(aAny)) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, + XML_COUNT_EMPTY_LINES, XML_FALSE); + } + + // count in frames + aAny = xLineNumbering->getPropertyValue("CountLinesInFrames"); + if (*o3tl::doAccess<bool>(aAny)) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, + XML_COUNT_IN_TEXT_BOXES, XML_TRUE); + } + + // restart numbering + aAny = xLineNumbering->getPropertyValue("RestartAtEachPage"); + if (*o3tl::doAccess<bool>(aAny)) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, + XML_RESTART_ON_PAGE, XML_TRUE); + } + + // Distance + aAny = xLineNumbering->getPropertyValue("Distance"); + sal_Int32 nLength = 0; + aAny >>= nLength; + if (nLength != 0) + { + OUStringBuffer sBuf; + rExport.GetMM100UnitConverter().convertMeasureToXML( + sBuf, nLength); + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_OFFSET, + sBuf.makeStringAndClear()); + } + + // NumberingType + OUStringBuffer sNumPosBuf; + aAny = xLineNumbering->getPropertyValue("NumberingType"); + sal_Int16 nFormat = 0; + aAny >>= nFormat; + rExport.GetMM100UnitConverter().convertNumFormat( sNumPosBuf, nFormat ); + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_NUM_FORMAT, + sNumPosBuf.makeStringAndClear()); + SvXMLUnitConverter::convertNumLetterSync( sNumPosBuf, nFormat ); + if( !sNumPosBuf.isEmpty() ) + { + rExport.AddAttribute(XML_NAMESPACE_STYLE, + XML_NUM_LETTER_SYNC, + sNumPosBuf.makeStringAndClear() ); + } + + // number position + aAny = xLineNumbering->getPropertyValue("NumberPosition"); + sal_uInt16 nPosition = 0; + aAny >>= nPosition; + if (SvXMLUnitConverter::convertEnum(sNumPosBuf, nPosition, + aLineNumberPositionMap)) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_NUMBER_POSITION, + sNumPosBuf.makeStringAndClear()); + } + + // sInterval + aAny = xLineNumbering->getPropertyValue("Interval"); + sal_Int16 nLineInterval = 0; + aAny >>= nLineInterval; + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_INCREMENT, + OUString::number(nLineInterval)); + + SvXMLElementExport aConfigElem(rExport, XML_NAMESPACE_TEXT, + XML_LINENUMBERING_CONFIGURATION, + true, true); + + // line separator + aAny = xLineNumbering->getPropertyValue("SeparatorText"); + OUString sSeparator; + aAny >>= sSeparator; + if (sSeparator.isEmpty()) + return; + + // SeparatorInterval + aAny = xLineNumbering->getPropertyValue("SeparatorInterval"); + sal_Int16 nLineDistance = 0; + aAny >>= nLineDistance; + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_INCREMENT, + OUString::number(nLineDistance)); + + SvXMLElementExport aSeparatorElem(rExport, XML_NAMESPACE_TEXT, + XML_LINENUMBERING_SEPARATOR, + true, false); + rExport.Characters(sSeparator); + // else: no configuration: don't save -> default + // can't even get supplier: don't save -> default +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLLineNumberingExport.hxx b/xmloff/source/text/XMLLineNumberingExport.hxx new file mode 100644 index 0000000000..4beb2a2b46 --- /dev/null +++ b/xmloff/source/text/XMLLineNumberingExport.hxx @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +class SvXMLExport; + +/** export <text:linenumbering-configuration> and its child elements */ +class XMLLineNumberingExport +{ + SvXMLExport& rExport; + +public: + explicit XMLLineNumberingExport(SvXMLExport& rExp); + + void Export(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLLineNumberingImportContext.cxx b/xmloff/source/text/XMLLineNumberingImportContext.cxx new file mode 100644 index 0000000000..0ba08972df --- /dev/null +++ b/xmloff/source/text/XMLLineNumberingImportContext.cxx @@ -0,0 +1,233 @@ +/* -*- 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 <XMLLineNumberingImportContext.hxx> +#include "XMLLineNumberingSeparatorImportContext.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/text/XLineNumberingProperties.hpp> +#include <com/sun/star/style/LineNumberPosition.hpp> +#include <com/sun/star/style/NumberingType.hpp> +#include <sax/tools/converter.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlement.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::xml::sax::XFastAttributeList; +using ::com::sun::star::text::XLineNumberingProperties; + + +constexpr OUStringLiteral gsCharStyleName(u"CharStyleName"); +constexpr OUStringLiteral gsCountEmptyLines(u"CountEmptyLines"); +constexpr OUStringLiteral gsCountLinesInFrames(u"CountLinesInFrames"); +constexpr OUStringLiteral gsDistance(u"Distance"); +constexpr OUStringLiteral gsInterval(u"Interval"); +constexpr OUStringLiteral gsSeparatorText(u"SeparatorText"); +constexpr OUStringLiteral gsNumberPosition(u"NumberPosition"); +constexpr OUStringLiteral gsNumberingType(u"NumberingType"); +constexpr OUStringLiteral gsIsOn(u"IsOn"); +constexpr OUStringLiteral gsRestartAtEachPage(u"RestartAtEachPage"); +constexpr OUStringLiteral gsSeparatorInterval(u"SeparatorInterval"); + +XMLLineNumberingImportContext::XMLLineNumberingImportContext( + SvXMLImport& rImport) +: SvXMLStyleContext(rImport, XmlStyleFamily::TEXT_LINENUMBERINGCONFIG) +, sNumFormat(GetXMLToken(XML_1)) +, sNumLetterSync(GetXMLToken(XML_FALSE)) +, nOffset(-1) +, nNumberPosition(style::LineNumberPosition::LEFT) +, nIncrement(-1) +, nSeparatorIncrement(-1) +, bNumberLines(true) +, bCountEmptyLines(true) +, bCountInFloatingFrames(false) +, bRestartNumbering(false) +{ +} + +XMLLineNumberingImportContext::~XMLLineNumberingImportContext() +{ +} + +void XMLLineNumberingImportContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + bool bTmp(false); + sal_Int32 nTmp; + + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + sStyleName = rValue; + break; + + case XML_ELEMENT(TEXT, XML_NUMBER_LINES): + if (::sax::Converter::convertBool(bTmp, rValue)) + { + bNumberLines = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_COUNT_EMPTY_LINES): + if (::sax::Converter::convertBool(bTmp, rValue)) + { + bCountEmptyLines = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_COUNT_IN_TEXT_BOXES): + if (::sax::Converter::convertBool(bTmp, rValue)) + { + bCountInFloatingFrames = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_RESTART_ON_PAGE): + if (::sax::Converter::convertBool(bTmp, rValue)) + { + bRestartNumbering = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_OFFSET): + if (GetImport().GetMM100UnitConverter(). + convertMeasureToCore(nTmp, rValue)) + { + nOffset = nTmp; + } + break; + + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + sNumFormat = rValue; + break; + + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + sNumLetterSync = rValue; + break; + + case XML_ELEMENT(TEXT, XML_NUMBER_POSITION): + { + static const SvXMLEnumMapEntry<sal_Int16> aLineNumberPositionMap[] = + { + { XML_LEFT, style::LineNumberPosition::LEFT }, + { XML_RIGHT, style::LineNumberPosition::RIGHT }, + { XML_INSIDE, style::LineNumberPosition::INSIDE }, + { XML_OUTSIDE, style::LineNumberPosition::OUTSIDE }, + { XML_TOKEN_INVALID, 0 } + }; + + (void)SvXMLUnitConverter::convertEnum(nNumberPosition, rValue, + aLineNumberPositionMap); + break; + } + + case XML_ELEMENT(TEXT, XML_INCREMENT): + if (::sax::Converter::convertNumber(nTmp, rValue, 0)) + { + nIncrement = static_cast<sal_Int16>(nTmp); + } + break; + } +} + +void XMLLineNumberingImportContext::CreateAndInsert(bool) +{ + // insert and block mode is handled in insertStyleFamily + + // we'll try to get the LineNumberingProperties + Reference<XLineNumberingProperties> xSupplier(GetImport().GetModel(), + UNO_QUERY); + if (!xSupplier.is()) + return; + + Reference<XPropertySet> xLineNumbering = + xSupplier->getLineNumberingProperties(); + + if (!xLineNumbering.is()) + return; + + Any aAny; + + // set style name (if it exists) + if ( GetImport().GetStyles()->FindStyleChildContext( + XmlStyleFamily::TEXT_TEXT, sStyleName ) != nullptr ) + { + aAny <<= GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, sStyleName ); + xLineNumbering->setPropertyValue(gsCharStyleName, aAny); + } + + xLineNumbering->setPropertyValue(gsSeparatorText, Any(sSeparator)); + xLineNumbering->setPropertyValue(gsDistance, Any(nOffset)); + xLineNumbering->setPropertyValue(gsNumberPosition, Any(nNumberPosition)); + + if (nIncrement >= 0) + { + xLineNumbering->setPropertyValue(gsInterval, Any(nIncrement)); + } + + if (nSeparatorIncrement >= 0) + { + xLineNumbering->setPropertyValue(gsSeparatorInterval, Any(nSeparatorIncrement)); + } + + xLineNumbering->setPropertyValue(gsIsOn, Any(bNumberLines)); + xLineNumbering->setPropertyValue(gsCountEmptyLines, Any(bCountEmptyLines)); + xLineNumbering->setPropertyValue(gsCountLinesInFrames, Any(bCountInFloatingFrames)); + xLineNumbering->setPropertyValue(gsRestartAtEachPage, Any(bRestartNumbering)); + + sal_Int16 nNumType = NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, + sNumFormat, + sNumLetterSync ); + xLineNumbering->setPropertyValue(gsNumberingType, Any(nNumType)); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLLineNumberingImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_LINENUMBERING_SEPARATOR) ) + return new XMLLineNumberingSeparatorImportContext(GetImport(), *this); + return nullptr; +} + +void XMLLineNumberingImportContext::SetSeparatorText( + const OUString& sText) +{ + sSeparator = sText; +} + +void XMLLineNumberingImportContext::SetSeparatorIncrement( + sal_Int16 nIncr) +{ + nSeparatorIncrement = nIncr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLLineNumberingSeparatorImportContext.cxx b/xmloff/source/text/XMLLineNumberingSeparatorImportContext.cxx new file mode 100644 index 0000000000..1482494aed --- /dev/null +++ b/xmloff/source/text/XMLLineNumberingSeparatorImportContext.cxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "XMLLineNumberingSeparatorImportContext.hxx" + +#include <sax/tools/converter.hxx> +#include <XMLLineNumberingImportContext.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> + + +using namespace ::com::sun::star::uno; + +using ::xmloff::token::XML_INCREMENT; + + +XMLLineNumberingSeparatorImportContext::XMLLineNumberingSeparatorImportContext( + SvXMLImport& rImport, + XMLLineNumberingImportContext& rLineNumbering) : + SvXMLImportContext(rImport), + rLineNumberingContext(rLineNumbering) +{ +} + +XMLLineNumberingSeparatorImportContext::~XMLLineNumberingSeparatorImportContext() +{ +} + +void XMLLineNumberingSeparatorImportContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_INCREMENT) ) + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber(nTmp, aIter.toView(), 0)) + { + rLineNumberingContext.SetSeparatorIncrement(static_cast<sal_Int16>(nTmp)); + } + // else: invalid number -> ignore + } + // else: unknown attribute -> ignore + } +} + +void XMLLineNumberingSeparatorImportContext::characters( + const OUString& rChars ) +{ + sSeparatorBuf.append(rChars); +} + +void XMLLineNumberingSeparatorImportContext::endFastElement(sal_Int32 ) +{ + rLineNumberingContext.SetSeparatorText(sSeparatorBuf.makeStringAndClear()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLLineNumberingSeparatorImportContext.hxx b/xmloff/source/text/XMLLineNumberingSeparatorImportContext.hxx new file mode 100644 index 0000000000..110aae6dc9 --- /dev/null +++ b/xmloff/source/text/XMLLineNumberingSeparatorImportContext.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 <xmloff/xmlictxt.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/uno/Reference.h> + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } +} +class XMLLineNumberingImportContext; + + +/** import <text:linenumbering-separator> elements */ +class XMLLineNumberingSeparatorImportContext : public SvXMLImportContext +{ + OUStringBuffer sSeparatorBuf; + XMLLineNumberingImportContext& rLineNumberingContext; + +public: + + + XMLLineNumberingSeparatorImportContext( + SvXMLImport& rImport, + XMLLineNumberingImportContext& rLineNumbering); + + virtual ~XMLLineNumberingSeparatorImportContext() override; + +protected: + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override; + + virtual void SAL_CALL characters( const OUString& rChars ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLPropertyBackpatcher.cxx b/xmloff/source/text/XMLPropertyBackpatcher.cxx new file mode 100644 index 0000000000..fef92ad213 --- /dev/null +++ b/xmloff/source/text/XMLPropertyBackpatcher.cxx @@ -0,0 +1,208 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <memory> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/uno/Reference.h> + +#include <rtl/ustring.hxx> +#include "XMLPropertyBackpatcher.hxx" +#include <utility> +#include <xmloff/txtimp.hxx> + +using ::std::map; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::com::sun::star::beans::XPropertySet; + + +template<class A> +XMLPropertyBackpatcher<A>::XMLPropertyBackpatcher( + OUString sPropName) +: sPropertyName(std::move(sPropName)) +{ +} + + +template<class A> +XMLPropertyBackpatcher<A>::~XMLPropertyBackpatcher() +{ +} + + +template<class A> +void XMLPropertyBackpatcher<A>::ResolveId( + const OUString& sName, + A aValue) +{ + // insert ID into ID map + aIDMap[sName] = aValue; + + // backpatch old references, if backpatch list exists + auto it = aBackpatchListMap.find(sName); + if (it == aBackpatchListMap.end()) + return; + + // aah, we have a backpatch list! + std::unique_ptr<BackpatchListType> pList = std::move(it->second); + + // a) remove list from list map + aBackpatchListMap.erase(it); + + // b) for every item, set SequenceNumber + // (and preserve Property, if appropriate) + Any aAny; + aAny <<= aValue; + for(const auto& rBackpatch : *pList) + { + rBackpatch->setPropertyValue(sPropertyName, aAny); + } + // else: no backpatch list -> then we're finished +} + +template<class A> +void XMLPropertyBackpatcher<A>::SetProperty( + const Reference<XPropertySet> & xPropSet, + const OUString& sName) +{ + if (aIDMap.count(sName)) + { + // we know this ID -> set property + xPropSet->setPropertyValue(sPropertyName, css::uno::Any(aIDMap[sName])); + } + else + { + // ID unknown -> into backpatch list for later fixup + if (! aBackpatchListMap.count(sName)) + { + // create backpatch list for this name + aBackpatchListMap.emplace(sName, new BackpatchListType); + } + + // insert footnote + aBackpatchListMap[sName]->push_back(xPropSet); + } +} + +// force instantiation of templates +template class XMLPropertyBackpatcher<sal_Int16>; +template class XMLPropertyBackpatcher<OUString>; + +struct XMLTextImportHelper::BackpatcherImpl +{ + /// backpatcher for references to footnotes and endnotes + ::std::unique_ptr< XMLPropertyBackpatcher<sal_Int16> > + m_pFootnoteBackpatcher; + + /// backpatchers for references to sequences + ::std::unique_ptr< XMLPropertyBackpatcher<sal_Int16> > + m_pSequenceIdBackpatcher; + + ::std::unique_ptr< XMLPropertyBackpatcher< OUString> > + m_pSequenceNameBackpatcher; +}; + +std::shared_ptr<XMLTextImportHelper::BackpatcherImpl> +XMLTextImportHelper::MakeBackpatcherImpl() +{ + // n.b.: the shared_ptr stores the dtor! + return std::make_shared<BackpatcherImpl>(); +} + +static OUString GetSequenceNumber() +{ + return "SequenceNumber"; +} + + +// XMLTextImportHelper + +// Code from XMLTextImportHelper using the XMLPropertyBackpatcher is +// implemented here. The reason is that in the unxsols2 environment, +// all templates are instantiated as file local (switch +// -instances=static), and thus are not accessible from the outside. + +// The previous solution was to force additional instantiation of +// XMLPropertyBackpatcher in txtimp.cxx. This solution combines all +// usage of the XMLPropertyBackpatcher in XMLPropertyBackpatcher.cxx +// instead. + + +XMLPropertyBackpatcher<sal_Int16>& XMLTextImportHelper::GetFootnoteBP() +{ + if (!m_xBackpatcherImpl->m_pFootnoteBackpatcher) + { + m_xBackpatcherImpl->m_pFootnoteBackpatcher.reset( + new XMLPropertyBackpatcher<sal_Int16>(GetSequenceNumber())); + } + return *m_xBackpatcherImpl->m_pFootnoteBackpatcher; +} + +XMLPropertyBackpatcher<sal_Int16>& XMLTextImportHelper::GetSequenceIdBP() +{ + if (!m_xBackpatcherImpl->m_pSequenceIdBackpatcher) + { + m_xBackpatcherImpl->m_pSequenceIdBackpatcher.reset( + new XMLPropertyBackpatcher<sal_Int16>(GetSequenceNumber())); + } + return *m_xBackpatcherImpl->m_pSequenceIdBackpatcher; +} + +XMLPropertyBackpatcher<OUString>& XMLTextImportHelper::GetSequenceNameBP() +{ + if (!m_xBackpatcherImpl->m_pSequenceNameBackpatcher) + { + m_xBackpatcherImpl->m_pSequenceNameBackpatcher.reset( + new XMLPropertyBackpatcher<OUString>("SourceName")); + } + return *m_xBackpatcherImpl->m_pSequenceNameBackpatcher; +} + +void XMLTextImportHelper::InsertFootnoteID( + const OUString& sXMLId, + sal_Int16 nAPIId) +{ + GetFootnoteBP().ResolveId(sXMLId, nAPIId); +} + +void XMLTextImportHelper::ProcessFootnoteReference( + const OUString& sXMLId, + const Reference<XPropertySet> & xPropSet) +{ + GetFootnoteBP().SetProperty(xPropSet, sXMLId); +} + +void XMLTextImportHelper::InsertSequenceID( + const OUString& sXMLId, + const OUString& sName, + sal_Int16 nAPIId) +{ + GetSequenceIdBP().ResolveId(sXMLId, nAPIId); + GetSequenceNameBP().ResolveId(sXMLId, sName); +} + +void XMLTextImportHelper::ProcessSequenceReference( + const OUString& sXMLId, + const Reference<XPropertySet> & xPropSet) +{ + GetSequenceIdBP().SetProperty(xPropSet, sXMLId); + GetSequenceNameBP().SetProperty(xPropSet, sXMLId); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLPropertyBackpatcher.hxx b/xmloff/source/text/XMLPropertyBackpatcher.hxx new file mode 100644 index 0000000000..3b3f273208 --- /dev/null +++ b/xmloff/source/text/XMLPropertyBackpatcher.hxx @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#pragma once + +#include <rtl/ustring.hxx> + +#include <map> +#include <memory> +#include <vector> + +namespace com::sun::star { + namespace beans { class XPropertySet; } + namespace uno { template<class A> class Reference; } +} + + +/** This class maintains an OUString->sal_Int16 mapping for cases in + * which an XPropertySet needs to be filled with values that are not + * yet known. + * + * A good example for appropriate use are footnotes and references to + * footnotes. Internally, the LibreOffice API numbers footnotes, and + * references to footnotes refer to that internal numbering. In the + * XML file format, these numbers are replaced with name strings. Now + * if during import of a document a reference to a footnote is + * encountered, two things can happen: 1) The footnote already + * appeared in the document. In this case the name is already known + * and the proper ID can be requested from the footnote. 2) The + * footnote will appear later in the document. In this case the ID is + * not yet known, and the reference-ID property of the reference + * cannot be determined. Hence, the reference has to be stored and the + * ID needs to bet set later, when the footnote is eventually found in + * the document. + * + * This class simplifies this process: If the footnote is found, + * ResolveId with the XML name and the ID is called. When a reference + * is encountered, SetProperty gets called with the reference's + * XPropertySet and the XML name. All remaining tasks are handled by + * the class. + */ +template <class A> +class XMLPropertyBackpatcher +{ + + /// name of property that gets set or backpatched + OUString sPropertyName; + + /// backpatch list type + typedef ::std::vector< + css::uno::Reference<css::beans::XPropertySet> > BackpatchListType; + + /// backpatch list for unresolved IDs + ::std::map<const OUString, std::unique_ptr<BackpatchListType>> aBackpatchListMap; + + /// mapping of names -> IDs + ::std::map<const OUString, A> aIDMap; + +public: + + explicit XMLPropertyBackpatcher( + OUString sPropertyName); + + ~XMLPropertyBackpatcher(); + + /// resolve a known ID. + /// Call this as soon as the value for a particular name is known. + void ResolveId( + const OUString& sName, + A aValue); + + /// Set property with the proper value for this name. If the value + /// is not yet known, store the XPropertySet in the backpatch list. + /// Use this whenever the value should be set, even if it is not yet known. + void SetProperty( + const css::uno::Reference<css::beans::XPropertySet> & xPropSet, + const OUString& sName); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLRedlineExport.cxx b/xmloff/source/text/XMLRedlineExport.cxx new file mode 100644 index 0000000000..33ddcdb179 --- /dev/null +++ b/xmloff/source/text/XMLRedlineExport.cxx @@ -0,0 +1,656 @@ +/* -*- 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 "XMLRedlineExport.hxx" +#include <o3tl/any.hxx> +#include <tools/debug.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <osl/diagnose.h> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> + +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/document/XRedlinesSupplier.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/text/XTextSection.hpp> +#include <com/sun/star/util/DateTime.hpp> + +#include <sax/tools/converter.hxx> + +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmluconv.hxx> +#include <unotools/securityoptions.hxx> +#include <tools/date.hxx> +#include <tools/datetime.hxx> + + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::beans::UnknownPropertyException; +using ::com::sun::star::document::XRedlinesSupplier; +using ::com::sun::star::container::XEnumerationAccess; +using ::com::sun::star::container::XEnumeration; +using ::com::sun::star::text::XText; +using ::com::sun::star::text::XTextContent; +using ::com::sun::star::text::XTextSection; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + + +XMLRedlineExport::XMLRedlineExport(SvXMLExport& rExp) +: sDeletion(GetXMLToken(XML_DELETION)) +, sFormatChange(GetXMLToken(XML_FORMAT_CHANGE)) +, sInsertion(GetXMLToken(XML_INSERTION)) +, rExport(rExp) +, pCurrentChangesList(nullptr) +{ +} + + +XMLRedlineExport::~XMLRedlineExport() +{ +} + + +void XMLRedlineExport::ExportChange( + const Reference<XPropertySet> & rPropSet, + bool bAutoStyle) +{ + if (bAutoStyle) + { + // For the headers/footers, we have to collect the autostyles + // here. For the general case, however, it's better to collect + // the autostyles by iterating over the global redline + // list. So that's what we do: Here, we collect autostyles + // only if we have no current list of changes. For the + // main-document case, the autostyles are collected in + // ExportChangesListAutoStyles(). + if (pCurrentChangesList != nullptr) + ExportChangeAutoStyle(rPropSet); + } + else + { + ExportChangeInline(rPropSet); + } +} + + +void XMLRedlineExport::ExportChangesList(bool bAutoStyles) +{ + if (bAutoStyles) + { + ExportChangesListAutoStyles(); + } + else + { + ExportChangesListElements(); + } +} + + +void XMLRedlineExport::ExportChangesList( + const Reference<XText> & rText, + bool bAutoStyles) +{ + // in the header/footer case, auto styles are collected from the + // inline change elements. + if (bAutoStyles) + return; + + // look for changes list for this XText + ChangesMapType::iterator aFind = aChangeMap.find(rText); + if (aFind == aChangeMap.end()) + return; + + ChangesVectorType& rChangesList = aFind->second; + + // export only if changes are found + if (rChangesList.empty()) + return; + + // changes container element + SvXMLElementExport aChanges(rExport, XML_NAMESPACE_TEXT, + XML_TRACKED_CHANGES, + true, true); + + // iterate over changes list + for (auto const& change : rChangesList) + { + ExportChangedRegion(change); + } + // else: changes list empty -> ignore + // else: no changes list found -> empty +} + +void XMLRedlineExport::SetCurrentXText( + const Reference<XText> & rText) +{ + if (rText.is()) + { + // look for appropriate list in map; use the found one, or create new + ChangesMapType::iterator aIter = aChangeMap.find(rText); + if (aIter == aChangeMap.end()) + { + auto rv = aChangeMap.emplace(std::piecewise_construct, std::forward_as_tuple(rText), std::forward_as_tuple()); + pCurrentChangesList = &rv.first->second; + } + else + pCurrentChangesList = &aIter->second; + } + else + { + // don't record changes + SetCurrentXText(); + } +} + +void XMLRedlineExport::SetCurrentXText() +{ + pCurrentChangesList = nullptr; +} + + +void XMLRedlineExport::ExportChangesListElements() +{ + // get redlines (aka tracked changes) from the model + Reference<XRedlinesSupplier> xSupplier(rExport.GetModel(), uno::UNO_QUERY); + if (!xSupplier.is()) + return; + + Reference<XEnumerationAccess> aEnumAccess = xSupplier->getRedlines(); + + // redline protection key + Reference<XPropertySet> aDocPropertySet( rExport.GetModel(), + uno::UNO_QUERY ); + // redlining enabled? + bool bEnabled = *o3tl::doAccess<bool>(aDocPropertySet->getPropertyValue( + "RecordChanges" )); + + // only export if we have redlines or attributes + if ( !(aEnumAccess->hasElements() || bEnabled) ) + return; + + + // export only if we have changes, but tracking is not enabled + if ( !bEnabled != !aEnumAccess->hasElements() ) + { + rExport.AddAttribute( + XML_NAMESPACE_TEXT, XML_TRACK_CHANGES, + bEnabled ? XML_TRUE : XML_FALSE ); + } + + // changes container element + SvXMLElementExport aChanges(rExport, XML_NAMESPACE_TEXT, + XML_TRACKED_CHANGES, + true, true); + + // get enumeration and iterate over elements + Reference<XEnumeration> aEnum = aEnumAccess->createEnumeration(); + while (aEnum->hasMoreElements()) + { + Any aAny = aEnum->nextElement(); + Reference<XPropertySet> xPropSet; + aAny >>= xPropSet; + + DBG_ASSERT(xPropSet.is(), + "can't get XPropertySet; skipping Redline"); + if (xPropSet.is()) + { + // export only if not in header or footer + // (those must be exported with their XText) + aAny = xPropSet->getPropertyValue("IsInHeaderFooter"); + if (! *o3tl::doAccess<bool>(aAny)) + { + // and finally, export change + ExportChangedRegion(xPropSet); + } + } + // else: no XPropertySet -> no export + } + // else: no redlines -> no export + // else: no XRedlineSupplier -> no export +} + +void XMLRedlineExport::ExportChangeAutoStyle( + const Reference<XPropertySet> & rPropSet) +{ + // record change (if changes should be recorded) + if (nullptr != pCurrentChangesList) + { + // put redline in list if it's collapsed or the redline start + Any aIsStart = rPropSet->getPropertyValue("IsStart"); + Any aIsCollapsed = rPropSet->getPropertyValue("IsCollapsed"); + + if ( *o3tl::doAccess<bool>(aIsStart) || + *o3tl::doAccess<bool>(aIsCollapsed) ) + pCurrentChangesList->push_back(rPropSet); + } + + // get XText for export of redline auto styles + Any aAny = rPropSet->getPropertyValue("RedlineText"); + Reference<XText> xText; + aAny >>= xText; + if (xText.is()) + { + // export the auto styles + rExport.GetTextParagraphExport()->collectTextAutoStyles(xText); + } +} + +void XMLRedlineExport::ExportChangesListAutoStyles() +{ + // get redlines (aka tracked changes) from the model + Reference<XRedlinesSupplier> xSupplier(rExport.GetModel(), uno::UNO_QUERY); + if (!xSupplier.is()) + return; + + Reference<XEnumerationAccess> aEnumAccess = xSupplier->getRedlines(); + + // only export if we actually have redlines + if (!aEnumAccess->hasElements()) + return; + + // get enumeration and iterate over elements + Reference<XEnumeration> aEnum = aEnumAccess->createEnumeration(); + while (aEnum->hasMoreElements()) + { + Any aAny = aEnum->nextElement(); + Reference<XPropertySet> xPropSet; + aAny >>= xPropSet; + + DBG_ASSERT(xPropSet.is(), + "can't get XPropertySet; skipping Redline"); + if (xPropSet.is()) + { + + // export only if not in header or footer + // (those must be exported with their XText) + aAny = xPropSet->getPropertyValue("IsInHeaderFooter"); + if (! *o3tl::doAccess<bool>(aAny)) + { + ExportChangeAutoStyle(xPropSet); + } + } + } +} + +void XMLRedlineExport::ExportChangeInline( + const Reference<XPropertySet> & rPropSet) +{ + // determine element name (depending on collapsed, start/end) + enum XMLTokenEnum eElement = XML_TOKEN_INVALID; + Any aAny = rPropSet->getPropertyValue("IsCollapsed"); + bool bCollapsed = *o3tl::doAccess<bool>(aAny); + if (bCollapsed) + { + eElement = XML_CHANGE; + } + else + { + aAny = rPropSet->getPropertyValue("IsStart"); + const bool bStart = *o3tl::doAccess<bool>(aAny); + eElement = bStart ? XML_CHANGE_START : XML_CHANGE_END; + } + + if (XML_TOKEN_INVALID != eElement) + { + // we always need the ID + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_CHANGE_ID, + GetRedlineID(rPropSet)); + + // export the element (no whitespace because we're in the text body) + SvXMLElementExport aChangeElem(rExport, XML_NAMESPACE_TEXT, + eElement, false, false); + } +} + + +void XMLRedlineExport::ExportChangedRegion( + const Reference<XPropertySet> & rPropSet) +{ + // Redline-ID + rExport.AddAttributeIdLegacy(XML_NAMESPACE_TEXT, GetRedlineID(rPropSet)); + + // merge-last-paragraph + Any aAny = rPropSet->getPropertyValue("MergeLastPara"); + if( ! *o3tl::doAccess<bool>(aAny) ) + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_MERGE_LAST_PARAGRAPH, + XML_FALSE); + + // export change region element + SvXMLElementExport aChangedRegion(rExport, XML_NAMESPACE_TEXT, + XML_CHANGED_REGION, true, true); + + + // scope for (first) change element + { + aAny = rPropSet->getPropertyValue("RedlineType"); + OUString sType; + aAny >>= sType; + SvXMLElementExport aChange(rExport, XML_NAMESPACE_TEXT, + ConvertTypeName(sType), true, true); + + ExportChangeInfo(rPropSet); + + // get XText from the redline and export (if the XText exists) + aAny = rPropSet->getPropertyValue("RedlineText"); + Reference<XText> xText; + aAny >>= xText; + if (xText.is()) + { + rExport.GetTextParagraphExport()->exportText(xText); + // default parameters: bProgress, bExportParagraph ??? + } + // else: no text interface -> content is inline and will + // be exported there + } + + // changed change? Hierarchical changes can only be two levels + // deep. Here we check for the second level. + aAny = rPropSet->getPropertyValue("RedlineSuccessorData"); + Sequence<PropertyValue> aSuccessorData; + aAny >>= aSuccessorData; + + // if we actually got a hierarchical change, make element and + // process change info + if (aSuccessorData.hasElements()) + { + // The only change that can be "undone" is an insertion - + // after all, you can't re-insert a deletion, but you can + // delete an insertion. This assumption is asserted in + // ExportChangeInfo(Sequence<PropertyValue>&). + SvXMLElementExport aSecondChangeElem( + rExport, XML_NAMESPACE_TEXT, XML_INSERTION, + true, true); + + ExportChangeInfo(aSuccessorData); + } + // else: no hierarchical change +} + + +OUString const & XMLRedlineExport::ConvertTypeName( + std::u16string_view sApiName) +{ + if (sApiName == u"Delete") + { + return sDeletion; + } + else if (sApiName == u"Insert") + { + return sInsertion; + } + else if (sApiName == u"Format") + { + return sFormatChange; + } + else + { + OSL_FAIL("unknown redline type"); + static constexpr OUString sUnknownChange(u"UnknownChange"_ustr); + return sUnknownChange; + } +} + + +/** Create a Redline-ID */ +OUString XMLRedlineExport::GetRedlineID( + const Reference<XPropertySet> & rPropSet) +{ + Any aAny = rPropSet->getPropertyValue("RedlineIdentifier"); + OUString sTmp; + aAny >>= sTmp; + + return "ct" + sTmp; +} + + +void XMLRedlineExport::ExportChangeInfo( + const Reference<XPropertySet> & rPropSet) +{ + bool bRemovePersonalInfo = SvtSecurityOptions::IsOptionSet( + SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo ) && !SvtSecurityOptions::IsOptionSet( + SvtSecurityOptions::EOption::DocWarnKeepRedlineInfo); + + SvXMLElementExport aChangeInfo(rExport, XML_NAMESPACE_OFFICE, + XML_CHANGE_INFO, true, true); + + Any aAny = rPropSet->getPropertyValue("RedlineAuthor"); + OUString sTmp; + aAny >>= sTmp; + if (!sTmp.isEmpty()) + { + SvXMLElementExport aCreatorElem( rExport, XML_NAMESPACE_DC, + XML_CREATOR, true, + false ); + rExport.Characters(bRemovePersonalInfo + ? "Author" + OUString::number(rExport.GetInfoID(sTmp)) + : sTmp ); + } + + aAny = rPropSet->getPropertyValue("RedlineMovedID"); + sal_uInt32 nTmp(0); + aAny >>= nTmp; + if (nTmp > 1) + { + SvXMLElementExport aCreatorElem(rExport, XML_NAMESPACE_LO_EXT, XML_MOVE_ID, true, false); + rExport.Characters( OUString::number( nTmp ) ); + } + + aAny = rPropSet->getPropertyValue("RedlineDateTime"); + util::DateTime aDateTime; + aAny >>= aDateTime; + { + OUStringBuffer sBuf; + ::sax::Converter::convertDateTime(sBuf, bRemovePersonalInfo + ? util::DateTime(0, 0, 0, 0, 1, 1, 1970, true) // Epoch time + : aDateTime, nullptr); + SvXMLElementExport aDateElem( rExport, XML_NAMESPACE_DC, + XML_DATE, true, + false ); + rExport.Characters(sBuf.makeStringAndClear()); + } + + // comment as <text:p> sequence + aAny = rPropSet->getPropertyValue("RedlineComment"); + aAny >>= sTmp; + WriteComment( sTmp ); +} + +// write RedlineSuccessorData +void XMLRedlineExport::ExportChangeInfo( + const Sequence<PropertyValue> & rPropertyValues) +{ + OUString sComment; + bool bRemovePersonalInfo = SvtSecurityOptions::IsOptionSet( + SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo ) && !SvtSecurityOptions::IsOptionSet( + SvtSecurityOptions::EOption::DocWarnKeepRedlineInfo); + + SvXMLElementExport aChangeInfo(rExport, XML_NAMESPACE_OFFICE, + XML_CHANGE_INFO, true, true); + + for(const PropertyValue& rVal : rPropertyValues) + { + if( rVal.Name == "RedlineAuthor" ) + { + OUString sTmp; + rVal.Value >>= sTmp; + if (!sTmp.isEmpty()) + { + SvXMLElementExport aCreatorElem( rExport, XML_NAMESPACE_DC, + XML_CREATOR, true, + false ); + rExport.Characters(bRemovePersonalInfo + ? "Author" + OUString::number(rExport.GetInfoID(sTmp)) + : sTmp ); + } + } + else if( rVal.Name == "RedlineComment" ) + { + rVal.Value >>= sComment; + } + else if( rVal.Name == "RedlineDateTime" ) + { + util::DateTime aDateTime; + rVal.Value >>= aDateTime; + OUStringBuffer sBuf; + ::sax::Converter::convertDateTime(sBuf, bRemovePersonalInfo + ? util::DateTime(0, 0, 0, 0, 1, 1, 1970, true) // Epoch time + : aDateTime, nullptr); + SvXMLElementExport aDateElem( rExport, XML_NAMESPACE_DC, + XML_DATE, true, + false ); + rExport.Characters(sBuf.makeStringAndClear()); + } + else if( rVal.Name == "RedlineType" ) + { + // check if this is an insertion; cf. comment at calling location + OUString sTmp; + rVal.Value >>= sTmp; + DBG_ASSERT(sTmp == "Insert", + "hierarchical change must be insertion"); + } + // else: unknown value -> ignore + } + + // finally write comment paragraphs + WriteComment( sComment ); +} + +void XMLRedlineExport::ExportStartOrEndRedline( + const Reference<XPropertySet> & rPropSet, + bool bStart) +{ + if( ! rPropSet.is() ) + return; + + // get appropriate (start or end) property + Any aAny; + try + { + aAny = rPropSet->getPropertyValue(bStart ? OUString("StartRedline") : OUString("EndRedline")); + } + catch(const UnknownPropertyException&) + { + // If we don't have the property, there's nothing to do. + return; + } + + Sequence<PropertyValue> aValues; + aAny >>= aValues; + + // seek for redline properties + bool bIsCollapsed = false; + bool bIsStart = true; + OUString sId; + bool bIdOK = false; // have we seen an ID? + for(const auto& rValue : std::as_const(aValues)) + { + if (rValue.Name == "RedlineIdentifier") + { + rValue.Value >>= sId; + bIdOK = true; + } + else if (rValue.Name == "IsCollapsed") + { + bIsCollapsed = *o3tl::doAccess<bool>(rValue.Value); + } + else if (rValue.Name == "IsStart") + { + bIsStart = *o3tl::doAccess<bool>(rValue.Value); + } + } + + if( !bIdOK ) + return; + + SAL_WARN_IF( sId.isEmpty(), "xmloff", "Redlines must have IDs" ); + + // TODO: use GetRedlineID or eliminate that function + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_CHANGE_ID, + "ct" + sId); + + // export the element + // (whitespace because we're not inside paragraphs) + SvXMLElementExport aChangeElem( + rExport, XML_NAMESPACE_TEXT, + bIsCollapsed ? XML_CHANGE : + ( bIsStart ? XML_CHANGE_START : XML_CHANGE_END ), + true, true); +} + +void XMLRedlineExport::ExportStartOrEndRedline( + const Reference<XTextContent> & rContent, + bool bStart) +{ + Reference<XPropertySet> xPropSet(rContent, uno::UNO_QUERY); + if (xPropSet.is()) + { + ExportStartOrEndRedline(xPropSet, bStart); + } + else + { + OSL_FAIL("XPropertySet expected"); + } +} + +void XMLRedlineExport::ExportStartOrEndRedline( + const Reference<XTextSection> & rSection, + bool bStart) +{ + Reference<XPropertySet> xPropSet(rSection, uno::UNO_QUERY); + if (xPropSet.is()) + { + ExportStartOrEndRedline(xPropSet, bStart); + } + else + { + OSL_FAIL("XPropertySet expected"); + } +} + +void XMLRedlineExport::WriteComment(std::u16string_view rComment) +{ + if (rComment.empty()) + return; + + // iterate over all string-pieces separated by return (0x0a) and + // put each inside a paragraph element. + SvXMLTokenEnumerator aEnumerator(rComment, char(0x0a)); + std::u16string_view aSubString; + while (aEnumerator.getNextToken(aSubString)) + { + SvXMLElementExport aParagraph( + rExport, XML_NAMESPACE_TEXT, XML_P, true, false); + rExport.Characters(OUString(aSubString)); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLRedlineExport.hxx b/xmloff/source/text/XMLRedlineExport.hxx new file mode 100644 index 0000000000..9031aacdbd --- /dev/null +++ b/xmloff/source/text/XMLRedlineExport.hxx @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/Sequence.h> + +#include <vector> +#include <memory> +#include <map> + +class SvXMLExport; +namespace com::sun::star { + namespace beans { class XPropertySet; } + namespace beans { struct PropertyValue; } + namespace text { class XText; } + namespace text { class XTextContent; } + namespace text { class XTextSection; } +} + +// store a list of redline properties +typedef ::std::vector< + css::uno::Reference<css::beans::XPropertySet> > ChangesVectorType; + +// store a list of redline properties for each XText +typedef ::std::map< + css::uno::Reference< css::text::XText>, + ChangesVectorType > ChangesMapType; + + +/** + * This class handles the export of redline portions. + * It is to be called from XMLTextParagraphExport. + */ +class XMLRedlineExport +{ + const OUString sDeletion; + const OUString sFormatChange; + const OUString sInsertion; + + SvXMLExport& rExport; + + + // handling of change recording: + + // To support change tracking in headers and footers we need to + // write these changes separately. To do this, we record the + // changes for headers and footers. For the main document body, we + // get the complete list of changes from the document, which + // should be much more efficient than recording all of those. + + ChangesMapType aChangeMap; /// map of recorded changes + + /// list of current changes; is NULL or points to member of aChangeMap + ChangesVectorType* pCurrentChangesList; + + +public: + explicit XMLRedlineExport(SvXMLExport& rExp); + + ~XMLRedlineExport(); + + /// export a change + void ExportChange( + /// PropertySet of RedlinePortion + const css::uno::Reference<css::beans::XPropertySet> & rPropSet, + bool bAutoStyle); + + /// export the list of changes (complete list minus recorded changed) + void ExportChangesList(bool bAutoStyles); + + /// export the list of changes (recorded changes for this XText only) + void ExportChangesList( + const css::uno::Reference<css::text::XText> & rText, + bool bAutoStyles); + + /// set the current XText for which changes should be recorded. + /// An empty XText means: don't record changes + void SetCurrentXText( + const css::uno::Reference<css::text::XText> & rText); + + /// Do not record changes. + /// Same as SetCurrentXText(Reference<XText>) with empty argument. + void SetCurrentXText(); + + /// export redline marks which start or end at start nodes, + /// i.e. that include the complete paragraph/table/section + void ExportStartOrEndRedline( + const css::uno::Reference< + css::beans::XPropertySet> & rPropSet, + bool bStart); /// start or end of text entity (e.g. paragraph)? + + /// convenience method, calls XPropertySet-version of this method + void ExportStartOrEndRedline( + /// XTextContent; must also be an XPropertySet + const css::uno::Reference<css::text::XTextContent> & rContent, + bool bStart); + + /// convenience method, calls XPropertySet-version of this method + void ExportStartOrEndRedline( + /// XTextSection; must also be an XPropertySet + const css::uno::Reference<css::text::XTextSection> & rSection, + bool bStart); + +private: + + /// export the change mark contained in the text body + void ExportChangeInline( + /// PropertySet of RedlinePortion + const css::uno::Reference<css::beans::XPropertySet> & rPropSet); + + /// export the auto styles used in this change + void ExportChangeAutoStyle( + /// PropertySet of RedlinePortion + const css::uno::Reference<css::beans::XPropertySet> & rPropSet); + + /// export the changes list (<text:tracked-changes>) + void ExportChangesListElements(); + + /// export the auto styles needed by the changes list + void ExportChangesListAutoStyles(); + + /// export the changed-region element + void ExportChangedRegion( + const css::uno::Reference<css::beans::XPropertySet> & rPropSet); + + /// export a change-info element (from a PropertySet) + void ExportChangeInfo( + const css::uno::Reference<css::beans::XPropertySet> & rPropSet); + + /// export a change-info element (from PropertyValues) + void ExportChangeInfo( + const css::uno::Sequence<css::beans::PropertyValue> & rValues); + + /// convert the change type from API to XML names + OUString const & ConvertTypeName(std::u16string_view sApiName); + + /// Get ID string! + static OUString GetRedlineID( + const css::uno::Reference<css::beans::XPropertySet> & rPropSet); + + /// write a comment string as sequence of <text:p> elements + void WriteComment(std::u16string_view rComment); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionExport.cxx b/xmloff/source/text/XMLSectionExport.cxx new file mode 100644 index 0000000000..fc3adc0c88 --- /dev/null +++ b/xmloff/source/text/XMLSectionExport.cxx @@ -0,0 +1,1836 @@ +/* -*- 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 "XMLSectionExport.hxx" +#include <o3tl/any.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/diagnose.h> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/PropertyValues.hpp> +#include <com/sun/star/text/XTextSection.hpp> +#include <com/sun/star/text/SectionFileLink.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/text/XDocumentIndex.hpp> +#include <com/sun/star/text/BibliographyDataField.hpp> +#include <com/sun/star/text/XTextFieldsSupplier.hpp> +#include <com/sun/star/text/XChapterNumberingSupplier.hpp> +#include <com/sun/star/text/ChapterFormat.hpp> + +#include <comphelper/base64.hxx> + +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/families.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlement.hxx> +#include <txtflde.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::beans::PropertyValues; +using ::com::sun::star::container::XIndexReplace; +using ::com::sun::star::container::XNameAccess; +using ::com::sun::star::container::XNamed; +using ::com::sun::star::lang::Locale; + + +XMLSectionExport::XMLSectionExport( + SvXMLExport& rExp, + XMLTextParagraphExport& rParaExp) +: rExport(rExp) +, rParaExport(rParaExp) +, bHeadingDummiesExported( false ) +{ +} + + +void XMLSectionExport::ExportSectionStart( + const Reference<XTextSection> & rSection, + bool bAutoStyles) +{ + Reference<XPropertySet> xPropertySet(rSection, UNO_QUERY); + + // always export section (auto) style + if (bAutoStyles) + { + // get PropertySet and add section style + GetParaExport().Add( XmlStyleFamily::TEXT_SECTION, xPropertySet ); + } + else + { + // always export section style + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetParaExport().Find( + XmlStyleFamily::TEXT_SECTION, + xPropertySet, "" ) ); + + // xml:id for RDF metadata + GetExport().AddAttributeXmlId(rSection); + + // export index or regular section + Reference<XDocumentIndex> xIndex; + if (GetIndex(rSection, xIndex)) + { + if (xIndex.is()) + { + // we are an index + ExportIndexStart(xIndex); + } + else + { + // we are an index header + ExportIndexHeaderStart(rSection); + } + } + else + { + // we are not an index + ExportRegularSectionStart(rSection); + } + } +} + +bool XMLSectionExport::GetIndex( + const Reference<XTextSection> & rSection, + Reference<XDocumentIndex> & rIndex) +{ + // first, reset result + bool bRet = false; + rIndex = nullptr; + + // get section Properties + Reference<XPropertySet> xSectionPropSet(rSection, UNO_QUERY); + + // then check if this section happens to be inside an index + if (xSectionPropSet->getPropertySetInfo()-> + hasPropertyByName("DocumentIndex")) + { + Any aAny = xSectionPropSet->getPropertyValue("DocumentIndex"); + Reference<XDocumentIndex> xDocumentIndex; + aAny >>= xDocumentIndex; + + // OK, are we inside of an index + if (xDocumentIndex.is()) + { + // is the enclosing index identical with "our" section? + Reference<XPropertySet> xIndexPropSet(xDocumentIndex, UNO_QUERY); + aAny = xIndexPropSet->getPropertyValue("ContentSection"); + Reference<XTextSection> xEnclosingSection; + aAny >>= xEnclosingSection; + + // if the enclosing section is "our" section, then we are an index! + if (rSection == xEnclosingSection) + { + rIndex = xDocumentIndex; + bRet = true; + } + // else: index header or regular section + + // is the enclosing index identical with the header section? + aAny = xIndexPropSet->getPropertyValue("HeaderSection"); + // now mis-named: contains header section + aAny >>= xEnclosingSection; + + // if the enclosing section is "our" section, then we are an index! + if (rSection == xEnclosingSection) + { + bRet = true; + } + // else: regular section + } + // else: we aren't even inside of an index + } + // else: we don't even know what an index is. + + return bRet; +} + + +void XMLSectionExport::ExportSectionEnd( + const Reference<XTextSection> & rSection, + bool bAutoStyles) +{ + // no end section for styles + if (bAutoStyles) + return; + + enum XMLTokenEnum eElement = XML_TOKEN_INVALID; + + // export index or regular section end + Reference<XDocumentIndex> xIndex; + if (GetIndex(rSection, xIndex)) + { + if (xIndex.is()) + { + // index end: close index body element + GetExport().EndElement( XML_NAMESPACE_TEXT, XML_INDEX_BODY, + true ); + GetExport().IgnorableWhitespace(); + + switch (MapSectionType(xIndex->getServiceName())) + { + case TEXT_SECTION_TYPE_TOC: + eElement = XML_TABLE_OF_CONTENT; + break; + + case TEXT_SECTION_TYPE_ILLUSTRATION: + eElement = XML_ILLUSTRATION_INDEX; + break; + + case TEXT_SECTION_TYPE_ALPHABETICAL: + eElement = XML_ALPHABETICAL_INDEX; + break; + + case TEXT_SECTION_TYPE_TABLE: + eElement = XML_TABLE_INDEX; + break; + + case TEXT_SECTION_TYPE_OBJECT: + eElement = XML_OBJECT_INDEX; + break; + + case TEXT_SECTION_TYPE_USER: + eElement = XML_USER_INDEX; + break; + + case TEXT_SECTION_TYPE_BIBLIOGRAPHY: + eElement = XML_BIBLIOGRAPHY; + break; + + default: + OSL_FAIL("unknown index type"); + // default: skip index! + break; + } + } + else + { + eElement = XML_INDEX_TITLE; + } + } + else + { + eElement = XML_SECTION; + } + + if (XML_TOKEN_INVALID != eElement) + { + // any old attributes? + GetExport().CheckAttrList(); + + // element surrounded by whitespace + GetExport().EndElement( XML_NAMESPACE_TEXT, eElement, true); + GetExport().IgnorableWhitespace(); + } + else + { + OSL_FAIL("Need element name!"); + } + // else: autostyles -> ignore +} + +void XMLSectionExport::ExportIndexStart( + const Reference<XDocumentIndex> & rIndex) +{ + // get PropertySet + Reference<XPropertySet> xPropertySet(rIndex, UNO_QUERY); + + switch (MapSectionType(rIndex->getServiceName())) + { + case TEXT_SECTION_TYPE_TOC: + ExportTableOfContentStart(xPropertySet); + break; + + case TEXT_SECTION_TYPE_ILLUSTRATION: + ExportIllustrationIndexStart(xPropertySet); + break; + + case TEXT_SECTION_TYPE_ALPHABETICAL: + ExportAlphabeticalIndexStart(xPropertySet); + break; + + case TEXT_SECTION_TYPE_TABLE: + ExportTableIndexStart(xPropertySet); + break; + + case TEXT_SECTION_TYPE_OBJECT: + ExportObjectIndexStart(xPropertySet); + break; + + case TEXT_SECTION_TYPE_USER: + ExportUserIndexStart(xPropertySet); + break; + + case TEXT_SECTION_TYPE_BIBLIOGRAPHY: + ExportBibliographyStart(xPropertySet); + break; + + default: + // skip index + OSL_FAIL("unknown index type"); + break; + } +} + +void XMLSectionExport::ExportIndexHeaderStart( + const Reference<XTextSection> & rSection) +{ + // export name, dammit! + Reference<XNamed> xName(rSection, UNO_QUERY); + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, xName->getName()); + + // format already handled -> export only start element + GetExport().StartElement( XML_NAMESPACE_TEXT, XML_INDEX_TITLE, true ); + GetExport().IgnorableWhitespace(); +} + + +SvXMLEnumStringMapEntry<SectionTypeEnum> const aIndexTypeMap[] = +{ + ENUM_STRING_MAP_ENTRY( "com.sun.star.text.ContentIndex", TEXT_SECTION_TYPE_TOC ), + ENUM_STRING_MAP_ENTRY( "com.sun.star.text.DocumentIndex", TEXT_SECTION_TYPE_ALPHABETICAL ), + ENUM_STRING_MAP_ENTRY( "com.sun.star.text.TableIndex", TEXT_SECTION_TYPE_TABLE ), + ENUM_STRING_MAP_ENTRY( "com.sun.star.text.ObjectIndex", TEXT_SECTION_TYPE_OBJECT ), + ENUM_STRING_MAP_ENTRY( "com.sun.star.text.Bibliography", TEXT_SECTION_TYPE_BIBLIOGRAPHY ), + ENUM_STRING_MAP_ENTRY( "com.sun.star.text.UserIndex", TEXT_SECTION_TYPE_USER ), + ENUM_STRING_MAP_ENTRY( "com.sun.star.text.IllustrationsIndex", TEXT_SECTION_TYPE_ILLUSTRATION ), + { nullptr, 0, SectionTypeEnum(0) } +}; + +enum SectionTypeEnum XMLSectionExport::MapSectionType( + std::u16string_view rServiceName) +{ + enum SectionTypeEnum eType = TEXT_SECTION_TYPE_UNKNOWN; + + SvXMLUnitConverter::convertEnum(eType, rServiceName, aIndexTypeMap); + + // TODO: index header section types, etc. + + return eType; +} + +void XMLSectionExport::ExportRegularSectionStart( + const Reference<XTextSection> & rSection) +{ + // style name already handled in ExportSectionStart(...) + + Reference<XNamed> xName(rSection, UNO_QUERY); + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, xName->getName()); + + // get XPropertySet for other values + Reference<XPropertySet> xPropSet(rSection, UNO_QUERY); + + // condition and display + Any aAny = xPropSet->getPropertyValue("Condition"); + OUString sCond; + aAny >>= sCond; + enum XMLTokenEnum eDisplay = XML_TOKEN_INVALID; + if (!sCond.isEmpty()) + { + OUString sQValue = + GetExport().GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OOOW, + sCond, false ); + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_CONDITION, sQValue); + eDisplay = XML_CONDITION; + + // #97450# store hidden-status (of conditional sections only) + aAny = xPropSet->getPropertyValue("IsCurrentlyVisible"); + if (! *o3tl::doAccess<bool>(aAny)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_IS_HIDDEN, + XML_TRUE); + } + } + else + { + eDisplay = XML_NONE; + } + aAny = xPropSet->getPropertyValue("IsVisible"); + if (! *o3tl::doAccess<bool>(aAny)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_DISPLAY, eDisplay); + } + + // protect + protection key + aAny = xPropSet->getPropertyValue("IsProtected"); + if (*o3tl::doAccess<bool>(aAny)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_PROTECTED, XML_TRUE); + } + Sequence<sal_Int8> aPassword; + xPropSet->getPropertyValue("ProtectionKey") >>= aPassword; + if (aPassword.hasElements()) + { + OUStringBuffer aBuffer; + ::comphelper::Base64::encode(aBuffer, aPassword); + // in ODF 1.0/1.1 the algorithm was left unspecified so we can write anything + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_PROTECTION_KEY, + aBuffer.makeStringAndClear()); + if (aPassword.getLength() == 32 && GetExport().getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + { + // attribute exists in ODF 1.2 or later; default is SHA1 so no need to write that + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_PROTECTION_KEY_DIGEST_ALGORITHM, + // write the URL from ODF 1.2, not the W3C one + "http://www.w3.org/2000/09/xmldsig#sha256"); + } + } + + // export element + GetExport().IgnorableWhitespace(); + GetExport().StartElement( XML_NAMESPACE_TEXT, XML_SECTION, true ); + + // data source + // unfortunately, we have to test all relevant strings for non-zero length + aAny = xPropSet->getPropertyValue("FileLink"); + SectionFileLink aFileLink; + aAny >>= aFileLink; + + aAny = xPropSet->getPropertyValue("LinkRegion"); + OUString sRegionName; + aAny >>= sRegionName; + + if ( !aFileLink.FileURL.isEmpty() || + !aFileLink.FilterName.isEmpty() || + !sRegionName.isEmpty()) + { + if (!aFileLink.FileURL.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, + GetExport().GetRelativeReference( aFileLink.FileURL) ); + } + + if (!aFileLink.FilterName.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_FILTER_NAME, + aFileLink.FilterName); + } + + if (!sRegionName.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_SECTION_NAME, + sRegionName); + } + + SvXMLElementExport aElem(GetExport(), + XML_NAMESPACE_TEXT, XML_SECTION_SOURCE, + true, true); + } + else + { + // check for DDE first + if (xPropSet->getPropertySetInfo()->hasPropertyByName("DDECommandFile")) + { + // data source DDE + // unfortunately, we have to test all relevant strings for + // non-zero length + aAny = xPropSet->getPropertyValue("DDECommandFile"); + OUString sApplication; + aAny >>= sApplication; + aAny = xPropSet->getPropertyValue("DDECommandType"); + OUString sTopic; + aAny >>= sTopic; + aAny = xPropSet->getPropertyValue("DDECommandElement"); + OUString sItem; + aAny >>= sItem; + + if ( !sApplication.isEmpty() || + !sTopic.isEmpty() || + !sItem.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_OFFICE, + XML_DDE_APPLICATION, sApplication); + GetExport().AddAttribute(XML_NAMESPACE_OFFICE, XML_DDE_TOPIC, + sTopic); + GetExport().AddAttribute(XML_NAMESPACE_OFFICE, XML_DDE_ITEM, + sItem); + + aAny = xPropSet->getPropertyValue("IsAutomaticUpdate"); + if (*o3tl::doAccess<bool>(aAny)) + { + GetExport().AddAttribute(XML_NAMESPACE_OFFICE, + XML_AUTOMATIC_UPDATE, XML_TRUE); + } + + SvXMLElementExport aElem(GetExport(), + XML_NAMESPACE_OFFICE, + XML_DDE_SOURCE, true, true); + } + // else: no DDE data source + } + // else: no DDE on this system + } +} + +void XMLSectionExport::ExportTableOfContentStart( + const Reference<XPropertySet> & rPropertySet) +{ + // export TOC element start + ExportBaseIndexStart(XML_TABLE_OF_CONTENT, rPropertySet); + + // scope for table-of-content-source element + { + // TOC specific index source attributes: + + // outline-level: 1..10 + sal_Int16 nLevel = sal_Int16(); + if( rPropertySet->getPropertyValue("Level") >>= nLevel ) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_OUTLINE_LEVEL, + OUString::number(nLevel)); + } + + // use outline level + ExportBoolean(rPropertySet, "CreateFromOutline", + XML_USE_OUTLINE_LEVEL, true); + + // use index marks + ExportBoolean(rPropertySet, "CreateFromMarks", + XML_USE_INDEX_MARKS, true); + + // use level styles + ExportBoolean(rPropertySet, "CreateFromLevelParagraphStyles", + XML_USE_INDEX_SOURCE_STYLES, false); + + ExportBaseIndexSource(TEXT_SECTION_TYPE_TOC, rPropertySet); + } + + ExportBaseIndexBody(TEXT_SECTION_TYPE_TOC, rPropertySet); +} + +void XMLSectionExport::ExportObjectIndexStart( + const Reference<XPropertySet> & rPropertySet) +{ + // export index start + ExportBaseIndexStart(XML_OBJECT_INDEX, rPropertySet); + + // scope for index source element + { + ExportBoolean(rPropertySet, "CreateFromOtherEmbeddedObjects", + XML_USE_OTHER_OBJECTS, false); + ExportBoolean(rPropertySet, "CreateFromStarCalc", + XML_USE_SPREADSHEET_OBJECTS, false); + ExportBoolean(rPropertySet, "CreateFromStarChart", + XML_USE_CHART_OBJECTS, false); + ExportBoolean(rPropertySet, "CreateFromStarDraw", + XML_USE_DRAW_OBJECTS, false); + ExportBoolean(rPropertySet, "CreateFromStarMath", + XML_USE_MATH_OBJECTS, false); + + ExportBaseIndexSource(TEXT_SECTION_TYPE_OBJECT, rPropertySet); + } + + ExportBaseIndexBody(TEXT_SECTION_TYPE_OBJECT, rPropertySet); +} + +void XMLSectionExport::ExportIllustrationIndexStart( + const Reference<XPropertySet> & rPropertySet) +{ + // export index start + ExportBaseIndexStart(XML_ILLUSTRATION_INDEX, rPropertySet); + + // scope for index source element + { + // export common attributes for illustration and table indices + ExportTableAndIllustrationIndexSourceAttributes(rPropertySet); + + ExportBaseIndexSource(TEXT_SECTION_TYPE_ILLUSTRATION, rPropertySet); + } + + ExportBaseIndexBody(TEXT_SECTION_TYPE_ILLUSTRATION, rPropertySet); +} + +void XMLSectionExport::ExportTableIndexStart( + const Reference<XPropertySet> & rPropertySet) +{ + // export index start + ExportBaseIndexStart(XML_TABLE_INDEX, rPropertySet); + + // scope for index source element + { + // export common attributes for illustration and table indices + ExportTableAndIllustrationIndexSourceAttributes(rPropertySet); + + ExportBaseIndexSource(TEXT_SECTION_TYPE_TABLE, rPropertySet); + } + + ExportBaseIndexBody(TEXT_SECTION_TYPE_TABLE, rPropertySet); +} + +void XMLSectionExport::ExportAlphabeticalIndexStart( + const Reference<XPropertySet> & rPropertySet) +{ + // export TOC element start + ExportBaseIndexStart(XML_ALPHABETICAL_INDEX, rPropertySet); + + // scope for table-of-content-source element + { + + // style name (if present) + Any aAny = rPropertySet->getPropertyValue("MainEntryCharacterStyleName"); + OUString sStyleName; + aAny >>= sStyleName; + if (!sStyleName.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_MAIN_ENTRY_STYLE_NAME, + GetExport().EncodeStyleName( sStyleName )); + } + + // other (boolean) attributes + ExportBoolean(rPropertySet, "IsCaseSensitive", XML_IGNORE_CASE, + false, true); + ExportBoolean(rPropertySet, "UseAlphabeticalSeparators", + XML_ALPHABETICAL_SEPARATORS, false); + ExportBoolean(rPropertySet, "UseCombinedEntries", XML_COMBINE_ENTRIES, + true); + ExportBoolean(rPropertySet, "UseDash", XML_COMBINE_ENTRIES_WITH_DASH, + false); + ExportBoolean(rPropertySet, "UseKeyAsEntry", XML_USE_KEYS_AS_ENTRIES, + false); + ExportBoolean(rPropertySet, "UsePP", XML_COMBINE_ENTRIES_WITH_PP, + true); + ExportBoolean(rPropertySet, "UseUpperCase", XML_CAPITALIZE_ENTRIES, + false); + ExportBoolean(rPropertySet, "IsCommaSeparated", XML_COMMA_SEPARATED, + false); + + // sort algorithm + aAny = rPropertySet->getPropertyValue("SortAlgorithm"); + OUString sAlgorithm; + aAny >>= sAlgorithm; + if (!sAlgorithm.isEmpty()) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_SORT_ALGORITHM, + sAlgorithm ); + } + + // locale + aAny = rPropertySet->getPropertyValue("Locale"); + Locale aLocale; + aAny >>= aLocale; + GetExport().AddLanguageTagAttributes( XML_NAMESPACE_FO, XML_NAMESPACE_STYLE, aLocale, true); + + ExportBaseIndexSource(TEXT_SECTION_TYPE_ALPHABETICAL, rPropertySet); + } + + ExportBaseIndexBody(TEXT_SECTION_TYPE_ALPHABETICAL, rPropertySet); +} + +void XMLSectionExport::ExportUserIndexStart( + const Reference<XPropertySet> & rPropertySet) +{ + // export TOC element start + ExportBaseIndexStart(XML_USER_INDEX, rPropertySet); + + // scope for table-of-content-source element + { + // bool attributes + ExportBoolean(rPropertySet, "CreateFromEmbeddedObjects", + XML_USE_OBJECTS, false); + ExportBoolean(rPropertySet, "CreateFromGraphicObjects", + XML_USE_GRAPHICS, false); + ExportBoolean(rPropertySet, "CreateFromMarks", + XML_USE_INDEX_MARKS, false); + ExportBoolean(rPropertySet, "CreateFromTables", + XML_USE_TABLES, false); + ExportBoolean(rPropertySet, "CreateFromTextFrames", + XML_USE_FLOATING_FRAMES, false); + ExportBoolean(rPropertySet, "UseLevelFromSource", + XML_COPY_OUTLINE_LEVELS, false); + ExportBoolean(rPropertySet, "CreateFromLevelParagraphStyles", + XML_USE_INDEX_SOURCE_STYLES, false); + + Any aAny = rPropertySet->getPropertyValue( "UserIndexName" ); + OUString sIndexName; + aAny >>= sIndexName; + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_INDEX_NAME, + sIndexName); + + ExportBaseIndexSource(TEXT_SECTION_TYPE_USER, rPropertySet); + } + + ExportBaseIndexBody(TEXT_SECTION_TYPE_USER, rPropertySet); +} + +void XMLSectionExport::ExportBibliographyStart( + const Reference<XPropertySet> & rPropertySet) +{ + // export TOC element start + ExportBaseIndexStart(XML_BIBLIOGRAPHY, rPropertySet); + + // scope for table-of-content-source element + { + // No attributes. Fine. + + ExportBaseIndexSource(TEXT_SECTION_TYPE_BIBLIOGRAPHY, rPropertySet); + } + + ExportBaseIndexBody(TEXT_SECTION_TYPE_BIBLIOGRAPHY, rPropertySet); +} + + +void XMLSectionExport::ExportBaseIndexStart( + XMLTokenEnum eElement, + const Reference<XPropertySet> & rPropertySet) +{ + // protect + protection key + Any aAny = rPropertySet->getPropertyValue("IsProtected"); + if (*o3tl::doAccess<bool>(aAny)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_PROTECTED, XML_TRUE); + } + + // index name + OUString sIndexName; + rPropertySet->getPropertyValue("Name") >>= sIndexName; + if ( !sIndexName.isEmpty() ) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, sIndexName); + } + + // index Element start + GetExport().IgnorableWhitespace(); + GetExport().StartElement( XML_NAMESPACE_TEXT, eElement, false ); +} + +const XMLTokenEnum aTypeSourceElementNameMap[] = +{ + XML_TABLE_OF_CONTENT_SOURCE, // TOC + XML_TABLE_INDEX_SOURCE, // table index + XML_ILLUSTRATION_INDEX_SOURCE, // illustration index + XML_OBJECT_INDEX_SOURCE, // object index + XML_USER_INDEX_SOURCE, // user index + XML_ALPHABETICAL_INDEX_SOURCE, // alphabetical index + XML_BIBLIOGRAPHY_SOURCE // bibliography +}; + +void XMLSectionExport::ExportBaseIndexSource( + SectionTypeEnum eType, + const Reference<XPropertySet> & rPropertySet) +{ + // check type + OSL_ENSURE(eType >= TEXT_SECTION_TYPE_TOC, "illegal index type"); + OSL_ENSURE(eType <= TEXT_SECTION_TYPE_BIBLIOGRAPHY, "illegal index type"); + + Any aAny; + + // common attributes; not supported by bibliography + if (eType != TEXT_SECTION_TYPE_BIBLIOGRAPHY) + { + // document or chapter index? + aAny = rPropertySet->getPropertyValue("CreateFromChapter"); + if (*o3tl::doAccess<bool>(aAny)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_INDEX_SCOPE, XML_CHAPTER); + } + + // tab-stops relative to margin? + aAny = rPropertySet->getPropertyValue("IsRelativeTabstops"); + if (! *o3tl::doAccess<bool>(aAny)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_RELATIVE_TAB_STOP_POSITION, + XML_FALSE); + } + } + + // the index source element (all indices) + SvXMLElementExport aElem(GetExport(), + XML_NAMESPACE_TEXT, + GetXMLToken( + aTypeSourceElementNameMap[ + eType - TEXT_SECTION_TYPE_TOC]), + true, true); + + // scope for title template (all indices) + { + // header style name + aAny = rPropertySet->getPropertyValue("ParaStyleHeading"); + OUString sStyleName; + aAny >>= sStyleName; + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_STYLE_NAME, + GetExport().EncodeStyleName( sStyleName )); + + // title template + SvXMLElementExport aHeaderTemplate(GetExport(), + XML_NAMESPACE_TEXT, + XML_INDEX_TITLE_TEMPLATE, + true, false); + + // title as element content + aAny = rPropertySet->getPropertyValue("Title"); + OUString sTitleString; + aAny >>= sTitleString; + GetExport().Characters(sTitleString); + } + + // export level templates (all indices) + aAny = rPropertySet->getPropertyValue("LevelFormat"); + Reference<XIndexReplace> xLevelTemplates; + aAny >>= xLevelTemplates; + + // iterate over level formats; + // skip element 0 (empty template for title) + sal_Int32 nLevelCount = xLevelTemplates->getCount(); + for(sal_Int32 i = 1; i<nLevelCount; i++) + { + // get sequence + Sequence<PropertyValues> aTemplateSequence; + aAny = xLevelTemplates->getByIndex(i); + aAny >>= aTemplateSequence; + + // export the sequence (abort export if an error occurred; #91214#) + bool bResult = + ExportIndexTemplate(eType, i, rPropertySet, aTemplateSequence); + if ( !bResult ) + break; + } + + // only TOC and user index: + // styles from which to build the index (LevelParagraphStyles) + if ( (TEXT_SECTION_TYPE_TOC == eType) || + (TEXT_SECTION_TYPE_USER == eType) ) + { + aAny = rPropertySet->getPropertyValue("LevelParagraphStyles"); + Reference<XIndexReplace> xLevelParagraphStyles; + aAny >>= xLevelParagraphStyles; + ExportLevelParagraphStyles(xLevelParagraphStyles); + } + else if (TEXT_SECTION_TYPE_ILLUSTRATION == eType + || TEXT_SECTION_TYPE_OBJECT == eType + || TEXT_SECTION_TYPE_TABLE == eType) + { + Any const any(rPropertySet->getPropertyValue("CreateFromParagraphStyle")); + if (any.hasValue() && + (rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)) + { + OUString const styleName(any.get<OUString>()); + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName(styleName)); + + SvXMLElementExport const e(GetExport(), + XML_NAMESPACE_LO_EXT, XML_INDEX_SOURCE_STYLE, true, false); + } + } +} + + +void XMLSectionExport::ExportBaseIndexBody( + SectionTypeEnum eType, + const Reference<XPropertySet> &) +{ + // type not used; checked anyway. + OSL_ENSURE(eType >= TEXT_SECTION_TYPE_TOC, "illegal index type"); + OSL_ENSURE(eType <= TEXT_SECTION_TYPE_BIBLIOGRAPHY, "illegal index type"); + + // export start only + + // any old attributes? + GetExport().CheckAttrList(); + + // start surrounded by whitespace + GetExport().IgnorableWhitespace(); + GetExport().StartElement( XML_NAMESPACE_TEXT, XML_INDEX_BODY, true ); +} + +void XMLSectionExport::ExportTableAndIllustrationIndexSourceAttributes( + const Reference<XPropertySet> & rPropertySet) +{ + // use caption + Any aAny = rPropertySet->getPropertyValue("CreateFromLabels"); + if (! *o3tl::doAccess<bool>(aAny)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_USE_CAPTION, XML_FALSE); + } + + // sequence name + aAny = rPropertySet->getPropertyValue("LabelCategory"); + OUString sSequenceName; + aAny >>= sSequenceName; + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_CAPTION_SEQUENCE_NAME, + sSequenceName); + + // caption format + aAny = rPropertySet->getPropertyValue("LabelDisplayType"); + sal_Int16 nType = 0; + aAny >>= nType; + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_CAPTION_SEQUENCE_FORMAT, + XMLTextFieldExport::MapReferenceType(nType)); +} + + +// map index of LevelFormats to attribute value; +// level 0 is always the header +const XMLTokenEnum aLevelNameTOCMap[] = + { XML_TOKEN_INVALID, XML_1, XML_2, XML_3, XML_4, XML_5, XML_6, XML_7, + XML_8, XML_9, XML_10, XML_TOKEN_INVALID }; +const XMLTokenEnum aLevelNameTableMap[] = + { XML_TOKEN_INVALID, XML__EMPTY, XML_TOKEN_INVALID }; +const XMLTokenEnum aLevelNameAlphaMap[] = + { XML_TOKEN_INVALID, XML_SEPARATOR, XML_1, XML_2, XML_3, XML_TOKEN_INVALID }; +const XMLTokenEnum aLevelNameBibliographyMap[] = + { XML_TOKEN_INVALID, XML_ARTICLE, XML_BOOK, XML_BOOKLET, XML_CONFERENCE, + XML_CUSTOM1, XML_CUSTOM2, XML_CUSTOM3, XML_CUSTOM4, + XML_CUSTOM5, XML_EMAIL, XML_INBOOK, XML_INCOLLECTION, + XML_INPROCEEDINGS, XML_JOURNAL, + XML_MANUAL, XML_MASTERSTHESIS, XML_MISC, XML_PHDTHESIS, + XML_PROCEEDINGS, XML_TECHREPORT, XML_UNPUBLISHED, XML_WWW, + XML_TOKEN_INVALID }; + +static const XMLTokenEnum* aTypeLevelNameMap[] = +{ + aLevelNameTOCMap, // TOC + aLevelNameTableMap, // table index + aLevelNameTableMap, // illustration index + aLevelNameTableMap, // object index + aLevelNameTOCMap, // user index + aLevelNameAlphaMap, // alphabetical index + aLevelNameBibliographyMap // bibliography +}; + +static const char* aLevelStylePropNameTOCMap[] = + { nullptr, "ParaStyleLevel1", "ParaStyleLevel2", "ParaStyleLevel3", + "ParaStyleLevel4", "ParaStyleLevel5", "ParaStyleLevel6", + "ParaStyleLevel7", "ParaStyleLevel8", "ParaStyleLevel9", + "ParaStyleLevel10", nullptr }; +static const char* aLevelStylePropNameTableMap[] = + { nullptr, "ParaStyleLevel1", nullptr }; +static const char* aLevelStylePropNameAlphaMap[] = + { nullptr, "ParaStyleSeparator", "ParaStyleLevel1", "ParaStyleLevel2", + "ParaStyleLevel3", nullptr }; +static const char* aLevelStylePropNameBibliographyMap[] = + // TODO: replace with real property names, when available + { nullptr, "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", + nullptr }; + +static const char** aTypeLevelStylePropNameMap[] = +{ + aLevelStylePropNameTOCMap, // TOC + aLevelStylePropNameTableMap, // table index + aLevelStylePropNameTableMap, // illustration index + aLevelStylePropNameTableMap, // object index + aLevelStylePropNameTOCMap, // user index + aLevelStylePropNameAlphaMap, // alphabetical index + aLevelStylePropNameBibliographyMap // bibliography +}; + +const XMLTokenEnum aTypeLevelAttrMap[] = +{ + XML_OUTLINE_LEVEL, // TOC + XML_TOKEN_INVALID, // table index + XML_TOKEN_INVALID, // illustration index + XML_TOKEN_INVALID, // object index + XML_OUTLINE_LEVEL, // user index + XML_OUTLINE_LEVEL, // alphabetical index + XML_BIBLIOGRAPHY_TYPE // bibliography +}; + +const XMLTokenEnum aTypeElementNameMap[] = +{ + XML_TABLE_OF_CONTENT_ENTRY_TEMPLATE, // TOC + XML_TABLE_INDEX_ENTRY_TEMPLATE, // table index + XML_ILLUSTRATION_INDEX_ENTRY_TEMPLATE, // illustration index + XML_OBJECT_INDEX_ENTRY_TEMPLATE, // object index + XML_USER_INDEX_ENTRY_TEMPLATE, // user index + XML_ALPHABETICAL_INDEX_ENTRY_TEMPLATE, // alphabetical index + XML_BIBLIOGRAPHY_ENTRY_TEMPLATE // bibliography +}; + + +bool XMLSectionExport::ExportIndexTemplate( + SectionTypeEnum eType, + sal_Int32 nOutlineLevel, + const Reference<XPropertySet> & rPropertySet, + const Sequence<Sequence<PropertyValue> > & rValues) +{ + OSL_ENSURE(eType >= TEXT_SECTION_TYPE_TOC, "illegal index type"); + OSL_ENSURE(eType <= TEXT_SECTION_TYPE_BIBLIOGRAPHY, "illegal index type"); + OSL_ENSURE(nOutlineLevel >= 0, "illegal outline level"); + + if ( (eType >= TEXT_SECTION_TYPE_TOC) && + (eType <= TEXT_SECTION_TYPE_BIBLIOGRAPHY) && + (nOutlineLevel >= 0) ) + { + // get level name and level attribute name from aLevelNameMap; + const XMLTokenEnum eLevelAttrName( + aTypeLevelAttrMap[eType-TEXT_SECTION_TYPE_TOC]); + const XMLTokenEnum eLevelName( + aTypeLevelNameMap[eType-TEXT_SECTION_TYPE_TOC][nOutlineLevel]); + + // #92124#: some old documents may be broken, then they have + // too many template levels; we need to recognize this and + // export only as many as is legal for the respective index + // type. To do this, we simply return an error flag, which + // will then abort further template level exports. + OSL_ENSURE(XML_TOKEN_INVALID != eLevelName, "can't find level name"); + if ( XML_TOKEN_INVALID == eLevelName ) + { + // output level not found? Then end of templates! #91214# + return false; + } + + // output level name + if ((XML_TOKEN_INVALID != eLevelName) && (XML_TOKEN_INVALID != eLevelAttrName)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + GetXMLToken(eLevelAttrName), + GetXMLToken(eLevelName)); + } + + // paragraph level style name + const char* pPropName( + aTypeLevelStylePropNameMap[eType-TEXT_SECTION_TYPE_TOC][nOutlineLevel]); + OSL_ENSURE(nullptr != pPropName, "can't find property name"); + if (nullptr != pPropName) + { + Any aAny = rPropertySet->getPropertyValue( + OUString::createFromAscii(pPropName)); + OUString sParaStyleName; + aAny >>= sParaStyleName; + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_STYLE_NAME, + GetExport().EncodeStyleName( sParaStyleName )); + } + + // template element + const XMLTokenEnum eElementName( + aTypeElementNameMap[eType - TEXT_SECTION_TYPE_TOC]); + SvXMLElementExport aLevelTemplate(GetExport(), + XML_NAMESPACE_TEXT, + GetXMLToken(eElementName), + true, true); + + // export sequence + for(auto& rValue : rValues) + { + ExportIndexTemplateElement( + eType, //i90246 + rValue); + } + } + + return true; +} + +namespace { + +enum TemplateTypeEnum +{ + TOK_TTYPE_ENTRY_NUMBER, + TOK_TTYPE_ENTRY_TEXT, + TOK_TTYPE_TAB_STOP, + TOK_TTYPE_TEXT, + TOK_TTYPE_PAGE_NUMBER, + TOK_TTYPE_CHAPTER_INFO, + TOK_TTYPE_HYPERLINK_START, + TOK_TTYPE_HYPERLINK_END, + TOK_TTYPE_BIBLIOGRAPHY, + TOK_TTYPE_INVALID +}; + +enum TemplateParamEnum +{ + TOK_TPARAM_TOKEN_TYPE, + TOK_TPARAM_CHAR_STYLE, + TOK_TPARAM_TAB_RIGHT_ALIGNED, + TOK_TPARAM_TAB_POSITION, + TOK_TPARAM_TAB_WITH_TAB, // #i21237# + TOK_TPARAM_TAB_FILL_CHAR, + TOK_TPARAM_TEXT, + TOK_TPARAM_CHAPTER_FORMAT, + TOK_TPARAM_CHAPTER_LEVEL,//i53420 + TOK_TPARAM_BIBLIOGRAPHY_DATA +}; + +} + +SvXMLEnumStringMapEntry<TemplateTypeEnum> const aTemplateTypeMap[] = +{ + ENUM_STRING_MAP_ENTRY( "TokenEntryNumber", TOK_TTYPE_ENTRY_NUMBER ), + ENUM_STRING_MAP_ENTRY( "TokenEntryText", TOK_TTYPE_ENTRY_TEXT ), + ENUM_STRING_MAP_ENTRY( "TokenTabStop", TOK_TTYPE_TAB_STOP ), + ENUM_STRING_MAP_ENTRY( "TokenText", TOK_TTYPE_TEXT ), + ENUM_STRING_MAP_ENTRY( "TokenPageNumber", TOK_TTYPE_PAGE_NUMBER ), + ENUM_STRING_MAP_ENTRY( "TokenChapterInfo", TOK_TTYPE_CHAPTER_INFO ), + ENUM_STRING_MAP_ENTRY( "TokenHyperlinkStart", TOK_TTYPE_HYPERLINK_START ), + ENUM_STRING_MAP_ENTRY( "TokenHyperlinkEnd", TOK_TTYPE_HYPERLINK_END ), + ENUM_STRING_MAP_ENTRY( "TokenBibliographyDataField", TOK_TTYPE_BIBLIOGRAPHY ), + { nullptr, 0, TemplateTypeEnum(0)} +}; + +SvXMLEnumStringMapEntry<TemplateParamEnum> const aTemplateParamMap[] = +{ + ENUM_STRING_MAP_ENTRY( "TokenType", TOK_TPARAM_TOKEN_TYPE ), + ENUM_STRING_MAP_ENTRY( "CharacterStyleName", TOK_TPARAM_CHAR_STYLE ), + ENUM_STRING_MAP_ENTRY( "TabStopRightAligned", TOK_TPARAM_TAB_RIGHT_ALIGNED ), + ENUM_STRING_MAP_ENTRY( "TabStopPosition", TOK_TPARAM_TAB_POSITION ), + ENUM_STRING_MAP_ENTRY( "TabStopFillCharacter", TOK_TPARAM_TAB_FILL_CHAR ), + // #i21237# + ENUM_STRING_MAP_ENTRY( "WithTab", TOK_TPARAM_TAB_WITH_TAB ), + ENUM_STRING_MAP_ENTRY( "Text", TOK_TPARAM_TEXT ), + ENUM_STRING_MAP_ENTRY( "ChapterFormat", TOK_TPARAM_CHAPTER_FORMAT ), + ENUM_STRING_MAP_ENTRY( "ChapterLevel", TOK_TPARAM_CHAPTER_LEVEL ),//i53420 + ENUM_STRING_MAP_ENTRY( "BibliographyDataField", TOK_TPARAM_BIBLIOGRAPHY_DATA ), + { nullptr, 0, TemplateParamEnum(0)} +}; + +SvXMLEnumMapEntry<sal_Int16> const aBibliographyDataFieldMap[] = +{ + { XML_ADDRESS, BibliographyDataField::ADDRESS }, + { XML_ANNOTE, BibliographyDataField::ANNOTE }, + { XML_AUTHOR, BibliographyDataField::AUTHOR }, + { XML_BIBLIOGRAPHY_TYPE, BibliographyDataField::BIBILIOGRAPHIC_TYPE }, + { XML_BOOKTITLE, BibliographyDataField::BOOKTITLE }, + { XML_CHAPTER, BibliographyDataField::CHAPTER }, + { XML_CUSTOM1, BibliographyDataField::CUSTOM1 }, + { XML_CUSTOM2, BibliographyDataField::CUSTOM2 }, + { XML_CUSTOM3, BibliographyDataField::CUSTOM3 }, + { XML_CUSTOM4, BibliographyDataField::CUSTOM4 }, + { XML_CUSTOM5, BibliographyDataField::CUSTOM5 }, + { XML_EDITION, BibliographyDataField::EDITION }, + { XML_EDITOR, BibliographyDataField::EDITOR }, + { XML_HOWPUBLISHED, BibliographyDataField::HOWPUBLISHED }, + { XML_IDENTIFIER, BibliographyDataField::IDENTIFIER }, + { XML_INSTITUTION, BibliographyDataField::INSTITUTION }, + { XML_ISBN, BibliographyDataField::ISBN }, + { XML_JOURNAL, BibliographyDataField::JOURNAL }, + { XML_MONTH, BibliographyDataField::MONTH }, + { XML_NOTE, BibliographyDataField::NOTE }, + { XML_NUMBER, BibliographyDataField::NUMBER }, + { XML_ORGANIZATIONS, BibliographyDataField::ORGANIZATIONS }, + { XML_PAGES, BibliographyDataField::PAGES }, + { XML_PUBLISHER, BibliographyDataField::PUBLISHER }, + { XML_REPORT_TYPE, BibliographyDataField::REPORT_TYPE }, + { XML_SCHOOL, BibliographyDataField::SCHOOL }, + { XML_SERIES, BibliographyDataField::SERIES }, + { XML_TITLE, BibliographyDataField::TITLE }, + { XML_URL, BibliographyDataField::URL }, + { XML_VOLUME, BibliographyDataField::VOLUME }, + { XML_YEAR, BibliographyDataField::YEAR }, + { XML_TOKEN_INVALID, 0 } +}; + +void XMLSectionExport::ExportIndexTemplateElement( + SectionTypeEnum eType, //i90246 + const Sequence<PropertyValue> & rValues) +{ + // variables for template values + + // char style + OUString sCharStyle; + bool bCharStyleOK = false; + + // text + OUString sText; + bool bTextOK = false; + + // tab position + bool bRightAligned = false; + + // tab position + sal_Int32 nTabPosition = 0; + bool bTabPositionOK = false; + + // fill character + OUString sFillChar; + bool bFillCharOK = false; + + // chapter format + sal_Int16 nChapterFormat = 0; + bool bChapterFormatOK = false; + + // outline max level + sal_Int16 nLevel = 0; + bool bLevelOK = false; + + // Bibliography Data + sal_Int16 nBibliographyData = 0; + bool bBibliographyDataOK = false; + + // With Tab Stop #i21237# + bool bWithTabStop = false; + bool bWithTabStopOK = false; + + //i90246, the ODF version being written to is: + const SvtSaveOptions::ODFSaneDefaultVersion aODFVersion = rExport.getSaneDefaultVersion(); + //the above version cannot be used for old OOo (OOo 1.0) formats! + + // token type + enum TemplateTypeEnum nTokenType = TOK_TTYPE_INVALID; + + for(const auto& rValue : rValues) + { + TemplateParamEnum nToken; + if ( SvXMLUnitConverter::convertEnum( nToken, rValue.Name, + aTemplateParamMap ) ) + { + // Only use direct and default values. + // Wrong. no property states, so ignore. + // if ( (beans::PropertyState_DIRECT_VALUE == rValues[i].State) || + // (beans::PropertyState_DEFAULT_VALUE == rValues[i].State) ) + + switch (nToken) + { + case TOK_TPARAM_TOKEN_TYPE: + { + OUString sVal; + rValue.Value >>= sVal; + SvXMLUnitConverter::convertEnum( nTokenType, sVal, aTemplateTypeMap); + break; + } + + case TOK_TPARAM_CHAR_STYLE: + // only valid, if not empty + rValue.Value >>= sCharStyle; + bCharStyleOK = !sCharStyle.isEmpty(); + break; + + case TOK_TPARAM_TEXT: + rValue.Value >>= sText; + bTextOK = true; + break; + + case TOK_TPARAM_TAB_RIGHT_ALIGNED: + bRightAligned = + *o3tl::doAccess<bool>(rValue.Value); + break; + + case TOK_TPARAM_TAB_POSITION: + rValue.Value >>= nTabPosition; + bTabPositionOK = true; + break; + + // #i21237# + case TOK_TPARAM_TAB_WITH_TAB: + bWithTabStop = *o3tl::doAccess<bool>(rValue.Value); + bWithTabStopOK = true; + break; + + case TOK_TPARAM_TAB_FILL_CHAR: + rValue.Value >>= sFillChar; + bFillCharOK = true; + break; + + case TOK_TPARAM_CHAPTER_FORMAT: + rValue.Value >>= nChapterFormat; + bChapterFormatOK = true; + break; +//---> i53420 + case TOK_TPARAM_CHAPTER_LEVEL: + rValue.Value >>= nLevel; + bLevelOK = true; + break; + case TOK_TPARAM_BIBLIOGRAPHY_DATA: + rValue.Value >>= nBibliographyData; + bBibliographyDataOK = true; + break; + } + } + } + + // convert type to token (and check validity) ... + XMLTokenEnum eElement(XML_TOKEN_INVALID); + sal_uInt16 nNamespace(XML_NAMESPACE_TEXT); + switch(nTokenType) + { + case TOK_TTYPE_ENTRY_TEXT: + eElement = XML_INDEX_ENTRY_TEXT; + break; + case TOK_TTYPE_TAB_STOP: + // test validity + if ( bRightAligned || bTabPositionOK || bFillCharOK ) + { + eElement = XML_INDEX_ENTRY_TAB_STOP; + } + break; + case TOK_TTYPE_TEXT: + // test validity + if (bTextOK) + { + eElement = XML_INDEX_ENTRY_SPAN; + } + break; + case TOK_TTYPE_PAGE_NUMBER: + eElement = XML_INDEX_ENTRY_PAGE_NUMBER; + break; + case TOK_TTYPE_CHAPTER_INFO: // keyword index + eElement = XML_INDEX_ENTRY_CHAPTER; + break; + case TOK_TTYPE_ENTRY_NUMBER: // table of content + eElement = XML_INDEX_ENTRY_CHAPTER; + break; + case TOK_TTYPE_HYPERLINK_START: + eElement = XML_INDEX_ENTRY_LINK_START; + break; + case TOK_TTYPE_HYPERLINK_END: + eElement = XML_INDEX_ENTRY_LINK_END; + break; + case TOK_TTYPE_BIBLIOGRAPHY: + if (bBibliographyDataOK) + { + eElement = XML_INDEX_ENTRY_BIBLIOGRAPHY; + } + break; + default: + ; // unknown/unimplemented template + break; + } + + if (eType != TEXT_SECTION_TYPE_TOC) + { + switch (nTokenType) + { + case TOK_TTYPE_HYPERLINK_START: + case TOK_TTYPE_HYPERLINK_END: + if (SvtSaveOptions::ODFSVER_012 < aODFVersion) + { + assert(eType == TEXT_SECTION_TYPE_ILLUSTRATION + || eType == TEXT_SECTION_TYPE_OBJECT + || eType == TEXT_SECTION_TYPE_TABLE + || eType == TEXT_SECTION_TYPE_USER); + // ODF 1.3 OFFICE-3941 + nNamespace = (SvtSaveOptions::ODFSVER_013 <= aODFVersion) + ? XML_NAMESPACE_TEXT + : XML_NAMESPACE_LO_EXT; + } + else + { + eElement = XML_TOKEN_INVALID; // not allowed in ODF <= 1.2 + } + break; + default: + break; + } + } + + //--->i90246 + //check the ODF version being exported + if (aODFVersion == SvtSaveOptions::ODFSVER_011 + || aODFVersion == SvtSaveOptions::ODFSVER_010) + { + bLevelOK = false; + if (TOK_TTYPE_CHAPTER_INFO == nTokenType) + { + //if we are emitting for ODF 1.1 or 1.0, this information can be used for alphabetical index only + //it's not permitted in other indexes + if (eType != TEXT_SECTION_TYPE_ALPHABETICAL) + { + eElement = XML_TOKEN_INVALID; //not permitted, invalidate the element + } + else //maps format for 1.1 & 1.0 + { + // a few word here: OOo up to 2.4 uses the field chapter info in Alphabetical index + // in a way different from the ODF 1.1/1.0 specification: + + // ODF1.1/1.0 OOo display in chapter info ODF1.2 + // (used in alphabetical index only + + // number chapter number without pre/postfix plain-number + // number-and-name chapter number without pre/postfix plus title plain-number-and-name + + // with issue i89791 the reading of ODF 1.1 and 1.0 was corrected + // this one corrects the writing back from ODF 1.2 to ODF 1.1/1.0 + // unfortunately if there is another application which interprets correctly ODF1.1/1.0, + // the resulting alphabetical index will be rendered wrong by OOo 2.4 version + + switch( nChapterFormat ) + { + case ChapterFormat::DIGIT: + nChapterFormat = ChapterFormat::NUMBER; + break; + case ChapterFormat::NO_PREFIX_SUFFIX: + nChapterFormat = ChapterFormat::NAME_NUMBER; + break; + } + } + } + else if (TOK_TTYPE_ENTRY_NUMBER == nTokenType) + { + //in case of ODF 1.1 or 1.0 the only allowed number format is "number" + //so, force it... + // The only expected 'foreign' nChapterFormat is + // ' ChapterFormat::DIGIT', forced to 'none, since the + // 'value allowed in ODF 1.1 and 1.0 is 'number' the default + // this can be obtained by simply disabling the chapter format + bChapterFormatOK = false; + } + } + + // ... and write Element + if (eElement == XML_TOKEN_INVALID) + return; + + // character style (for most templates) + if (bCharStyleOK) + { + switch (nTokenType) + { + case TOK_TTYPE_ENTRY_TEXT: + case TOK_TTYPE_TEXT: + case TOK_TTYPE_PAGE_NUMBER: + case TOK_TTYPE_ENTRY_NUMBER: + case TOK_TTYPE_HYPERLINK_START: + case TOK_TTYPE_HYPERLINK_END: + case TOK_TTYPE_BIBLIOGRAPHY: + case TOK_TTYPE_CHAPTER_INFO: + case TOK_TTYPE_TAB_STOP: + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_STYLE_NAME, + GetExport().EncodeStyleName( sCharStyle) ); + break; + default: + ; // nothing: no character style + break; + } + } + + // tab properties + if (TOK_TTYPE_TAB_STOP == nTokenType) + { + // tab type + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_TYPE, + bRightAligned ? XML_RIGHT : XML_LEFT); + + if (bTabPositionOK && (! bRightAligned)) + { + // position for left tabs (convert to measure) + OUStringBuffer sBuf; + GetExport().GetMM100UnitConverter().convertMeasureToXML(sBuf, + nTabPosition); + GetExport().AddAttribute(XML_NAMESPACE_STYLE, + XML_POSITION, + sBuf.makeStringAndClear()); + } + + // fill char ("leader char") + if (bFillCharOK && !sFillChar.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, + XML_LEADER_CHAR, sFillChar); + } + + // #i21237# + if (bWithTabStopOK && ! bWithTabStop) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, + XML_WITH_TAB, + XML_FALSE); + } + } + + // bibliography data + if (TOK_TTYPE_BIBLIOGRAPHY == nTokenType) + { + OSL_ENSURE(bBibliographyDataOK, "need bibl data"); + OUStringBuffer sBuf; + if (SvXMLUnitConverter::convertEnum( sBuf, nBibliographyData, + aBibliographyDataFieldMap ) ) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_BIBLIOGRAPHY_DATA_FIELD, + sBuf.makeStringAndClear()); + } + } + + // chapter info + if (TOK_TTYPE_CHAPTER_INFO == nTokenType) + { + OSL_ENSURE(bChapterFormatOK, "need chapter info"); + GetExport().AddAttribute( + XML_NAMESPACE_TEXT, XML_DISPLAY, + XMLTextFieldExport::MapChapterDisplayFormat(nChapterFormat)); +//---> i53420 + if (bLevelOK) + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_OUTLINE_LEVEL, + OUString::number(nLevel)); + } + +//--->i53420 + if (TOK_TTYPE_ENTRY_NUMBER == nTokenType) + { + if (bChapterFormatOK) + GetExport().AddAttribute( + XML_NAMESPACE_TEXT, XML_DISPLAY, + XMLTextFieldExport::MapChapterDisplayFormat(nChapterFormat)); + + if (bLevelOK) + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_OUTLINE_LEVEL, + OUString::number(nLevel)); + } + // export template + SvXMLElementExport aTemplateElement(GetExport(), nNamespace, + GetXMLToken(eElement), + true, false) + ; + + // entry text or span element: write text + if (TOK_TTYPE_TEXT == nTokenType) + { + GetExport().Characters(sText); + } +} + +void XMLSectionExport::ExportLevelParagraphStyles( + Reference<XIndexReplace> const & xLevelParagraphStyles) +{ + // iterate over levels + sal_Int32 nPLevelCount = xLevelParagraphStyles->getCount(); + for(sal_Int32 nLevel = 0; nLevel < nPLevelCount; nLevel++) + { + Any aAny = xLevelParagraphStyles->getByIndex(nLevel); + Sequence<OUString> aStyleNames; + aAny >>= aStyleNames; + + // export only if at least one style is contained + if (aStyleNames.hasElements()) + { + // level attribute; we count 1..10; API 0..9 + sal_Int32 nLevelPlusOne = nLevel + 1; + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_OUTLINE_LEVEL, + OUString::number(nLevelPlusOne)); + + // source styles element + SvXMLElementExport aParaStyles(GetExport(), + XML_NAMESPACE_TEXT, + XML_INDEX_SOURCE_STYLES, + true, true); + + // iterate over styles in this level + for(const auto& rStyleName : std::as_const(aStyleNames)) + { + // stylename attribute + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_STYLE_NAME, + GetExport().EncodeStyleName(rStyleName) ); + + // element + SvXMLElementExport aParaStyle(GetExport(), + XML_NAMESPACE_TEXT, + XML_INDEX_SOURCE_STYLE, + true, false); + } + } + } +} + +void XMLSectionExport::ExportBoolean( + const Reference<XPropertySet> & rPropSet, + const OUString& sPropertyName, + enum XMLTokenEnum eAttributeName, + bool bDefault, + bool bInvert) +{ + OSL_ENSURE(eAttributeName != XML_TOKEN_INVALID, "Need attribute name"); + + Any aAny = rPropSet->getPropertyValue(sPropertyName); + bool bTmp = *o3tl::doAccess<bool>(aAny); + + // value = value ^ bInvert + // omit if value == default + if ( (bTmp != bInvert) != bDefault ) + { + // export non-default value (since default is omitted) + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + eAttributeName, + bDefault ? XML_FALSE : XML_TRUE); + } +} + +void XMLSectionExport::ExportBibliographyConfiguration(SvXMLExport& rExport) +{ + // first: get field master (via text field supplier) + Reference<XTextFieldsSupplier> xTextFieldsSupp( rExport.GetModel(), + UNO_QUERY ); + if ( !xTextFieldsSupp.is() ) + return; + + static constexpr OUString sFieldMaster_Bibliography(u"com.sun.star.text.FieldMaster.Bibliography"_ustr); + + // get bibliography field master + Reference<XNameAccess> xMasters = + xTextFieldsSupp->getTextFieldMasters(); + if ( !xMasters->hasByName(sFieldMaster_Bibliography) ) + return; + + Any aAny = + xMasters->getByName(sFieldMaster_Bibliography); + Reference<XPropertySet> xPropSet; + aAny >>= xPropSet; + + OSL_ENSURE( xPropSet.is(), "field master must have XPropSet" ); + + OUString sTmp; + + aAny = xPropSet->getPropertyValue("BracketBefore"); + aAny >>= sTmp; + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_PREFIX, sTmp); + + aAny = xPropSet->getPropertyValue("BracketAfter"); + aAny >>= sTmp; + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_SUFFIX, sTmp); + + aAny = xPropSet->getPropertyValue("IsNumberEntries"); + if (*o3tl::doAccess<bool>(aAny)) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, + XML_NUMBERED_ENTRIES, XML_TRUE); + } + + aAny = xPropSet->getPropertyValue("IsSortByPosition"); + if (! *o3tl::doAccess<bool>(aAny)) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, + XML_SORT_BY_POSITION, XML_FALSE); + } + + // sort algorithm + aAny = xPropSet->getPropertyValue("SortAlgorithm"); + OUString sAlgorithm; + aAny >>= sAlgorithm; + if( !sAlgorithm.isEmpty() ) + { + rExport.AddAttribute( XML_NAMESPACE_TEXT, + XML_SORT_ALGORITHM, sAlgorithm ); + } + + // locale + aAny = xPropSet->getPropertyValue("Locale"); + Locale aLocale; + aAny >>= aLocale; + rExport.AddLanguageTagAttributes( XML_NAMESPACE_FO, XML_NAMESPACE_STYLE, aLocale, true); + + // configuration element + SvXMLElementExport aElement(rExport, XML_NAMESPACE_TEXT, + XML_BIBLIOGRAPHY_CONFIGURATION, + true, true); + + // sort keys + aAny = xPropSet->getPropertyValue("SortKeys"); + Sequence<Sequence<PropertyValue> > aKeys; + aAny >>= aKeys; + for(const Sequence<PropertyValue> & rKey : std::as_const(aKeys)) + { + for(const PropertyValue& rValue : rKey) + { + if (rValue.Name == "SortKey") + { + sal_Int16 nKey = 0; + rValue.Value >>= nKey; + OUStringBuffer sBuf; + if (SvXMLUnitConverter::convertEnum( sBuf, nKey, + aBibliographyDataFieldMap ) ) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_KEY, + sBuf.makeStringAndClear()); + } + } + else if (rValue.Name == "IsSortAscending") + { + bool bTmp = *o3tl::doAccess<bool>(rValue.Value); + rExport.AddAttribute(XML_NAMESPACE_TEXT, + XML_SORT_ASCENDING, + bTmp ? XML_TRUE : XML_FALSE); + } + } + + SvXMLElementExport aKeyElem(rExport, + XML_NAMESPACE_TEXT, XML_SORT_KEY, + true, true); + } +} + + +bool XMLSectionExport::IsMuteSection( + const Reference<XTextSection> & rSection) const +{ + bool bRet = false; + + // a section is mute if + // 1) it exists + // 2) the SaveLinkedSections flag (at the export) is false + // 3) the IsGlobalDocumentSection property is true + // 4) it is not an Index + + if ( (!rExport.IsSaveLinkedSections()) && rSection.is() ) + { + // walk the section chain and set bRet if any is linked + for(Reference<XTextSection> aSection(rSection); + aSection.is(); + aSection = aSection->getParentSection()) + { + // check if it is a global document section (linked or index) + Reference<XPropertySet> xPropSet(aSection, UNO_QUERY); + if (xPropSet.is()) + { + Any aAny = xPropSet->getPropertyValue("IsGlobalDocumentSection"); + + if ( *o3tl::doAccess<bool>(aAny) ) + { + Reference<XDocumentIndex> xIndex; + if (! GetIndex(rSection, xIndex)) + { + bRet = true; + + // early out if result is known + break; + } + } + } + // section has no properties: ignore + } + } + // else: no section, or always save sections: default (false) + + return bRet; +} + +bool XMLSectionExport::IsMuteSection( + const Reference<XTextContent> & rSection, + bool bDefault) const +{ + // default: like default argument + bool bRet = bDefault; + + Reference<XPropertySet> xPropSet(rSection->getAnchor(), UNO_QUERY); + if (xPropSet.is()) + { + if (xPropSet->getPropertySetInfo()->hasPropertyByName("TextSection")) + { + Any aAny = xPropSet->getPropertyValue("TextSection"); + Reference<XTextSection> xSection; + aAny >>= xSection; + + bRet = IsMuteSection(xSection); + } + // else: return default + } + // else: return default + + return bRet; +} + +bool XMLSectionExport::IsInSection( + const Reference<XTextSection> & rEnclosingSection, + const Reference<XTextContent> & rContent, + bool bDefault) +{ + // default: like default argument + bool bRet = bDefault; + OSL_ENSURE(rEnclosingSection.is(), "enclosing section expected"); + + Reference<XPropertySet> xPropSet(rContent, UNO_QUERY); + if (xPropSet.is()) + { + if (xPropSet->getPropertySetInfo()->hasPropertyByName("TextSection")) + { + Any aAny = xPropSet->getPropertyValue("TextSection"); + Reference<XTextSection> xSection; + aAny >>= xSection; + + // now walk chain of text sections (if we have one) + if (xSection.is()) + { + do + { + bRet = (rEnclosingSection == xSection); + xSection = xSection->getParentSection(); + } + while (!bRet && xSection.is()); + } + else + bRet = false; // no section -> can't be inside + } + // else: no TextSection property -> return default + } + // else: no XPropertySet -> return default + + return bRet; +} + + +void XMLSectionExport::ExportMasterDocHeadingDummies() +{ + if( bHeadingDummiesExported ) + return; + + Reference< XChapterNumberingSupplier > xCNSupplier( rExport.GetModel(), + UNO_QUERY ); + + Reference< XIndexReplace > xChapterNumbering; + if( xCNSupplier.is() ) + xChapterNumbering = xCNSupplier->getChapterNumberingRules(); + + if( !xChapterNumbering.is() ) + return; + + sal_Int32 nCount = xChapterNumbering->getCount(); + for( sal_Int32 nLevel = 0; nLevel < nCount; nLevel++ ) + { + OUString sStyle; + Sequence<PropertyValue> aProperties; + xChapterNumbering->getByIndex( nLevel ) >>= aProperties; + auto pProp = std::find_if(std::cbegin(aProperties), std::cend(aProperties), + [](const PropertyValue& rProp) { return rProp.Name == "HeadingStyleName"; }); + if (pProp != std::cend(aProperties)) + pProp->Value >>= sStyle; + + if( !sStyle.isEmpty() ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sStyle ) ); + + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_LEVEL, + OUString::number( nLevel + 1 ) ); + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, XML_H, + true, false ); + } + } + + bHeadingDummiesExported = true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionExport.hxx b/xmloff/source/text/XMLSectionExport.hxx new file mode 100644 index 0000000000..05180e2f2d --- /dev/null +++ b/xmloff/source/text/XMLSectionExport.hxx @@ -0,0 +1,262 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <rtl/ustring.hxx> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <xmloff/xmltoken.hxx> + +class SvXMLExport; +class XMLTextParagraphExport; +namespace com::sun::star { + namespace text + { + class XTextSection; + class XDocumentIndex; + class XTextContent; + } + namespace beans + { + class XPropertySet; + } + namespace container + { + class XIndexReplace; + } +} + + +enum SectionTypeEnum +{ + TEXT_SECTION_TYPE_TOC, + TEXT_SECTION_TYPE_TABLE, + TEXT_SECTION_TYPE_ILLUSTRATION, + TEXT_SECTION_TYPE_OBJECT, + TEXT_SECTION_TYPE_USER, + TEXT_SECTION_TYPE_ALPHABETICAL, + TEXT_SECTION_TYPE_BIBLIOGRAPHY, + TEXT_SECTION_TYPE_UNKNOWN +}; + + +/** + * This class handles the export of sections and indices (which are, + * internally, just sections). It is intended to be used only from + * within the XMLTextParagraphExport class. + */ +class XMLSectionExport +{ + SvXMLExport& rExport; + XMLTextParagraphExport& rParaExport; + + bool bHeadingDummiesExported; + +public: + XMLSectionExport(SvXMLExport& rExp, + XMLTextParagraphExport& rParaExp); + + /** + * export section or index start and source elements. This + * method handles the section styles, and delegates to the + * appropriate section or index method. + */ + void ExportSectionStart( + const css::uno::Reference < css::text::XTextSection > & rSection, + bool bAutoStyles); + + /** + * export section or index end elements + */ + void ExportSectionEnd( + const css::uno::Reference < css::text::XTextSection > & rSection, + bool bAutoStyles); + + /** + * Should the content of this section be exported? + * (E.g. linked sections in global documents are not always exported) + */ + bool IsMuteSection( + const css::uno::Reference < css::text::XTextSection > & rSection) const; + + /** + * XTextContent-version of IsMuteSection(Reference<XTextSection>&) + * returns *true* for all non-section elements + */ + bool IsMuteSection( + const css::uno::Reference < css::text::XTextContent > & rSection, + /// return value if this content doesn't support the section property + bool bDefault) const; + + /** + * Determine whether rContent is contained in rEnclosingSection. If the + * current section of rContent can not be determined, return bDefault. + */ + static bool IsInSection( + const css::uno::Reference < css::text::XTextSection > & rEnclosingSection, + const css::uno::Reference < css::text::XTextContent > & rContent, + /// return value if this content doesn't support the section property + bool bDefault); + + /** + * Export the configuration element for bibliography indices. + * + * (This is part of XMLSectionExport because all section- and + * index-related items are handled here.) + */ + static void ExportBibliographyConfiguration(SvXMLExport& rExport); + + /** export a heading for every level. This is used by master documents + * to not lose the heading information if master documents are exported + * without section contents + */ + void ExportMasterDocHeadingDummies(); + + +private: + + SvXMLExport& GetExport() { return rExport; } + XMLTextParagraphExport& GetParaExport() { return rParaExport; } + + // export methods for section and index start: + + /// export an index start element. + void ExportIndexStart( + const css::uno::Reference < css::text::XDocumentIndex > & rSection); + + /// export an index header start element. + void ExportIndexHeaderStart( + const css::uno::Reference < css::text::XTextSection > & rSection); + + /// export a proper section (and source elements) + void ExportRegularSectionStart( + const css::uno::Reference < css::text::XTextSection > & rSection); + + /// export a table of content (and source element) + void ExportTableOfContentStart( + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + /// export a table index (and source element) + void ExportTableIndexStart( + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + /// export an object index (and source element) + void ExportObjectIndexStart( + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + /// export an illustration index (and source element) + void ExportIllustrationIndexStart( + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + /// export an alphabetical/keyword index (and source element) + void ExportAlphabeticalIndexStart( + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + /// export a user index (and source element) + void ExportUserIndexStart( + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + /// export the bibliography (and source element) + void ExportBibliographyStart( + const css::uno::Reference < css::beans::XPropertySet > & rIndex); + + // helper methods: + + /** + * If this section is an index, the index is written in the + * rIndex parameter. The return value is sal_True for all "special" + * sections. + * + * Thus we have: + * return sal_False: regular section + * return sal_True, xIndex is empty: index header section + * return sal_True, xIndex is set: index section */ + static bool GetIndex( + const css::uno::Reference < css::text::XTextSection > & rSection, + css::uno::Reference < css::text::XDocumentIndex > & rIndex); + + /// map service name to section type + static enum SectionTypeEnum MapSectionType(std::u16string_view rSectionName); + + /** + * Export the index element start (for all index types). + * + * All additional attributes (usually none) for the index element + * should have been set at GetExport() before calling this method. + */ + void ExportBaseIndexStart( + ::xmloff::token::XMLTokenEnum eElement, + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + /** + * Export the index source element (common for all index types). + * + * All additional attributes for the source element should have + * been set at the GetExport() before calling this method. + */ + void ExportBaseIndexSource( + SectionTypeEnum eType, /// index type + const css::uno::Reference < + css::beans::XPropertySet > & rSection); + + /** + * Export the index body (common for all index types). + */ + void ExportBaseIndexBody( + SectionTypeEnum eType, /// index type + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + + /** + * Helper method to export common attributes for table and + * illustration indices + */ + void ExportTableAndIllustrationIndexSourceAttributes( + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + /// export one template for the specific index type + bool ExportIndexTemplate( + SectionTypeEnum eType, /// index type + sal_Int32 nLevel, /// outline level (if applicable) + const css::uno::Reference< css::beans::XPropertySet> & rPropSet, + const css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue> > & rValues); + + /// export a single template element (e.g. span or tab-stop) + void ExportIndexTemplateElement( + SectionTypeEnum eType, //i90246, needed for ODF 1.0, 1.0 and 1.2 management + const css::uno::Sequence< + css::beans::PropertyValue> & rValues); + + /// export level paragraph styles + void ExportLevelParagraphStyles( + css::uno::Reference< css::container::XIndexReplace> const & xStyles); + + + /// helper to export boolean properties + void ExportBoolean( + const css::uno::Reference<css::beans::XPropertySet> & rPropSet, + const OUString& sPropertyName, + enum ::xmloff::token::XMLTokenEnum eAttributeName, + bool bDefault, + bool bInvert = false); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionFootnoteConfigExport.cxx b/xmloff/source/text/XMLSectionFootnoteConfigExport.cxx new file mode 100644 index 0000000000..6e1c063191 --- /dev/null +++ b/xmloff/source/text/XMLSectionFootnoteConfigExport.cxx @@ -0,0 +1,179 @@ +/* -*- 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 "XMLSectionFootnoteConfigExport.hxx" +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlprmap.hxx> +#include <com/sun/star/style/NumberingType.hpp> +#include <xmloff/maptype.hxx> + +#include <xmloff/txtprmap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmltoken.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> + +#include <vector> + + +using namespace ::xmloff::token; + +using ::std::vector; +using css::style::NumberingType::ARABIC; + + +void XMLSectionFootnoteConfigExport::exportXML( + SvXMLExport& rExport, + bool bEndnote, + const vector<XMLPropertyState> *pProperties, + sal_uInt32 nIdx, + const rtl::Reference<XMLPropertySetMapper> & rMapper) +{ + // store and initialize the values + bool bNumOwn = false; + bool bNumRestart = false; + sal_Int16 nNumRestartAt = 0; + sal_Int16 nNumberingType = ARABIC; + OUString sNumPrefix; + OUString sNumSuffix; + bool bEnd = false; + + // find entries in property states vector + sal_uInt32 nCount = pProperties->size(); + for(sal_uInt32 i = 0; i < nCount; i++) + { + const XMLPropertyState& rState = (*pProperties)[i]; + + sal_Int16 nContextId = rMapper->GetEntryContextId(rState.mnIndex); + if (!bEndnote) + { + switch (nContextId) + { + case CTF_SECTION_FOOTNOTE_NUM_OWN: + rState.maValue >>= bNumOwn; + break; + case CTF_SECTION_FOOTNOTE_NUM_RESTART: + rState.maValue >>= bNumRestart; + break; + case CTF_SECTION_FOOTNOTE_NUM_RESTART_AT: + rState.maValue >>= nNumRestartAt; + break; + case CTF_SECTION_FOOTNOTE_NUM_TYPE: + rState.maValue >>= nNumberingType; + break; + case CTF_SECTION_FOOTNOTE_NUM_PREFIX: + rState.maValue >>= sNumPrefix; + break; + case CTF_SECTION_FOOTNOTE_NUM_SUFFIX: + rState.maValue >>= sNumSuffix; + break; + case CTF_SECTION_FOOTNOTE_END: + SAL_WARN_IF( i != nIdx, "xmloff", + "received wrong property state index" ); + rState.maValue >>= bEnd; + break; + } + } + else + { + switch (nContextId) + { + case CTF_SECTION_ENDNOTE_NUM_OWN: + rState.maValue >>= bNumOwn; + break; + case CTF_SECTION_ENDNOTE_NUM_RESTART: + rState.maValue >>= bNumRestart; + break; + case CTF_SECTION_ENDNOTE_NUM_RESTART_AT: + rState.maValue >>= nNumRestartAt; + break; + case CTF_SECTION_ENDNOTE_NUM_TYPE: + rState.maValue >>= nNumberingType; + break; + case CTF_SECTION_ENDNOTE_NUM_PREFIX: + rState.maValue >>= sNumPrefix; + break; + case CTF_SECTION_ENDNOTE_NUM_SUFFIX: + rState.maValue >>= sNumSuffix; + break; + case CTF_SECTION_ENDNOTE_END: + SAL_WARN_IF( i != nIdx, "xmloff", + "received wrong property state index" ); + rState.maValue >>= bEnd; + break; + } + } + } + + // we only make an element if we have an own footnote/endnote numbering + if (!bEnd) + return; + + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_NOTE_CLASS, + GetXMLToken( bEndnote ? XML_ENDNOTE + : XML_FOOTNOTE ) ); + // start numbering + if (bNumRestart) + { + // restart number is stored as 0.., but interpreted as 1.. + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_START_VALUE, + OUString::number(nNumRestartAt+1)); + } + + if (bNumOwn) + { + // prefix and suffix + if (!sNumPrefix.isEmpty()) + { + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_NUM_PREFIX, + sNumPrefix); + } + if (!sNumSuffix.isEmpty()) + { + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_NUM_SUFFIX, + sNumSuffix); + } + + // number type: num format + OUStringBuffer sBuf; + rExport.GetMM100UnitConverter().convertNumFormat( sBuf, + nNumberingType ); + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_NUM_FORMAT, + sBuf.makeStringAndClear()); + + // and letter sync, if applicable + SvXMLUnitConverter::convertNumLetterSync( + sBuf, nNumberingType ); + if (!sBuf.isEmpty()) + { + rExport.AddAttribute(XML_NAMESPACE_STYLE, + XML_NUM_LETTER_SYNC, + sBuf.makeStringAndClear()); + } + } + + // and finally, the element + SvXMLElementExport rElem(rExport, XML_NAMESPACE_TEXT, + XML_NOTES_CONFIGURATION, + true, true); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionFootnoteConfigExport.hxx b/xmloff/source/text/XMLSectionFootnoteConfigExport.hxx new file mode 100644 index 0000000000..dcbf66c2e0 --- /dev/null +++ b/xmloff/source/text/XMLSectionFootnoteConfigExport.hxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#pragma once + +#include <sal/types.h> + +#include <vector> + +class SvXMLExport; +class XMLPropertySetMapper; +struct XMLPropertyState; +namespace rtl { + template<class X> class Reference; +} + +/** + * Export the footnote-/endnote-configuration element in section styles. + * + * Because this class contains only one method, and all information is + * available during that method call, we simply make it static. + */ +class XMLSectionFootnoteConfigExport +{ + +public: + static void exportXML( + SvXMLExport& rExport, + bool bEndnote, + const ::std::vector<XMLPropertyState> * pProperties, + sal_uInt32 nIdx, + const rtl::Reference<XMLPropertySetMapper> & rMapper); /// used only for debugging +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionFootnoteConfigImport.cxx b/xmloff/source/text/XMLSectionFootnoteConfigImport.cxx new file mode 100644 index 0000000000..113e7f2d22 --- /dev/null +++ b/xmloff/source/text/XMLSectionFootnoteConfigImport.cxx @@ -0,0 +1,170 @@ +/* -*- 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 "XMLSectionFootnoteConfigImport.hxx" + +#include <rtl/ustring.hxx> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/style/NumberingType.hpp> +#include <sal/log.hxx> +#include <sax/tools/converter.hxx> +#include <utility> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlprmap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/maptype.hxx> +#include <xmloff/txtprmap.hxx> + +#include <vector> + + +using namespace ::xmloff::token; +using namespace ::com::sun::star::style; + +using ::std::vector; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; + + +XMLSectionFootnoteConfigImport::XMLSectionFootnoteConfigImport( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + vector<XMLPropertyState> & rProps, + rtl::Reference<XMLPropertySetMapper> xMapperRef) : + SvXMLImportContext(rImport), + rProperties(rProps), + rMapper(std::move(xMapperRef)) +{ +} + +XMLSectionFootnoteConfigImport::~XMLSectionFootnoteConfigImport() +{ +} + +void XMLSectionFootnoteConfigImport::startFastElement( + sal_Int32 /*nElement*/, + const Reference<css::xml::sax::XFastAttributeList> & xAttrList) +{ + bool bNumOwn = false; + bool bNumRestart = false; + bool bEndnote = false; + sal_Int16 nNumRestartAt = 0; + OUString sNumPrefix; + OUString sNumSuffix; + OUString sNumFormat; + OUString sNumLetterSync; + + // iterate over xattribute list and fill values + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_START_VALUE): + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber(nTmp, aIter.toView())) + { + nNumRestartAt = static_cast< sal_Int16 >( nTmp ) - 1; + bNumRestart = true; + } + break; + } + case XML_ELEMENT(TEXT, XML_NOTE_CLASS): + { + if( IsXMLToken( aIter, XML_ENDNOTE ) ) + bEndnote = true; + break; + } + case XML_ELEMENT(STYLE, XML_NUM_PREFIX): + { + sNumPrefix = aIter.toString(); + bNumOwn = true; + break; + } + case XML_ELEMENT(STYLE, XML_NUM_SUFFIX): + { + sNumSuffix = aIter.toString(); + bNumOwn = true; + break; + } + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + { + sNumFormat = aIter.toString(); + bNumOwn = true; + break; + } + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + { + sNumLetterSync = aIter.toString(); + bNumOwn = true; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // OK, now we have all values and can fill the XMLPropertyState vector + + sal_Int32 nIndex = rMapper->FindEntryIndex( bEndnote ? + CTF_SECTION_ENDNOTE_NUM_OWN : CTF_SECTION_FOOTNOTE_NUM_OWN ); + XMLPropertyState aNumOwn( nIndex, css::uno::Any(bNumOwn) ); + rProperties.push_back( aNumOwn ); + + nIndex = rMapper->FindEntryIndex( bEndnote ? + CTF_SECTION_ENDNOTE_NUM_RESTART : CTF_SECTION_FOOTNOTE_NUM_RESTART ); + XMLPropertyState aNumRestart( nIndex, css::uno::Any(bNumRestart) ); + rProperties.push_back( aNumRestart ); + + nIndex = rMapper->FindEntryIndex( bEndnote ? + CTF_SECTION_ENDNOTE_NUM_RESTART_AT : + CTF_SECTION_FOOTNOTE_NUM_RESTART_AT ); + XMLPropertyState aNumRestartAtState( nIndex, css::uno::Any(nNumRestartAt) ); + rProperties.push_back( aNumRestartAtState ); + + sal_Int16 nNumType = NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, + sNumFormat, + sNumLetterSync ); + nIndex = rMapper->FindEntryIndex( bEndnote ? + CTF_SECTION_ENDNOTE_NUM_TYPE : CTF_SECTION_FOOTNOTE_NUM_TYPE ); + XMLPropertyState aNumFormatState( nIndex, css::uno::Any(nNumType) ); + rProperties.push_back( aNumFormatState ); + + nIndex = rMapper->FindEntryIndex( bEndnote ? + CTF_SECTION_ENDNOTE_NUM_PREFIX : CTF_SECTION_FOOTNOTE_NUM_PREFIX ); + XMLPropertyState aPrefixState( nIndex, css::uno::Any(sNumPrefix) ); + rProperties.push_back( aPrefixState ); + + nIndex = rMapper->FindEntryIndex( bEndnote ? + CTF_SECTION_ENDNOTE_NUM_SUFFIX : CTF_SECTION_FOOTNOTE_NUM_SUFFIX ); + XMLPropertyState aSuffixState( nIndex, css::uno::Any(sNumSuffix) ); + rProperties.push_back( aSuffixState ); + + nIndex = rMapper->FindEntryIndex( bEndnote ? + CTF_SECTION_ENDNOTE_END : CTF_SECTION_FOOTNOTE_END ); + XMLPropertyState aEndState( nIndex, css::uno::Any(true) ); // we're inside the element, so this is true + rProperties.push_back( aEndState ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionFootnoteConfigImport.hxx b/xmloff/source/text/XMLSectionFootnoteConfigImport.hxx new file mode 100644 index 0000000000..7a25690334 --- /dev/null +++ b/xmloff/source/text/XMLSectionFootnoteConfigImport.hxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <rtl/ref.hxx> +#include <vector> + + +class SvXMLImport; +struct XMLPropertyState; +class XMLPropertySetMapper; +namespace com::sun::star { + namespace uno { template<class X> class Reference; } + namespace xml::sax { class XAttributeList; } +} + + +/** + * Import the footnote-/endnote-configuration element in section styles. + */ +class XMLSectionFootnoteConfigImport : public SvXMLImportContext +{ + ::std::vector<XMLPropertyState> & rProperties; + rtl::Reference<XMLPropertySetMapper> rMapper; + +public: + + + XMLSectionFootnoteConfigImport( + SvXMLImport& rImport, + sal_Int32 nElement, + ::std::vector<XMLPropertyState> & rProperties, + rtl::Reference<XMLPropertySetMapper> xMapperRef); + + virtual ~XMLSectionFootnoteConfigImport() override; + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionImportContext.cxx b/xmloff/source/text/XMLSectionImportContext.cxx new file mode 100644 index 0000000000..554096c887 --- /dev/null +++ b/xmloff/source/text/XMLSectionImportContext.cxx @@ -0,0 +1,324 @@ +/* -*- 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 "XMLSectionImportContext.hxx" +#include "XMLSectionSourceImportContext.hxx" +#include "XMLSectionSourceDDEImportContext.hxx" +#include <comphelper/base64.hxx> +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/txtimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/prstylei.hxx> +#include <sal/log.hxx> +#include <sax/tools/converter.hxx> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/text/ControlCharacter.hpp> + + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XFastAttributeList; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::container::XNamed; + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + + +// section import: This one is fairly tricky due to a variety of +// limits of the core or the API. The main problem is that if you +// insert a section within another section, you can't move the cursor +// between the ends of the inner and the enclosing section. To avoid +// these problems, additional markers are first inserted and later deleted. +XMLSectionImportContext::XMLSectionImportContext( SvXMLImport& rImport ) +: SvXMLImportContext(rImport) +, bProtect(false) +, bCondOK(false) +, bIsVisible(true) +, bValid(false) +, bSequenceOK(false) +, bIsCurrentlyVisible(true) +, bIsCurrentlyVisibleOK(false) +, bHasContent(false) +{ +} + +XMLSectionImportContext::~XMLSectionImportContext() +{ +} + +void XMLSectionImportContext::startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // process attributes + ProcessAttributes(xAttrList); + + // process index headers: + bool bIsIndexHeader = (nElement & TOKEN_MASK) == XML_INDEX_TITLE; + if (bIsIndexHeader) + { + bValid = true; + } + + rtl::Reference<XMLTextImportHelper> rHelper = GetImport().GetTextImport(); + + // valid? + if (!bValid) + return; + + // create text section (as XPropertySet) + Reference<XMultiServiceFactory> xFactory( + GetImport().GetModel(),UNO_QUERY); + if (!xFactory.is()) + return; + + Reference<XInterface> xIfc = + xFactory->createInstance( bIsIndexHeader ? OUString("com.sun.star.text.IndexHeaderSection") + : OUString("com.sun.star.text.TextSection") ); + if (!xIfc.is()) + return; + + Reference<XPropertySet> xPropSet(xIfc, UNO_QUERY); + + // save PropertySet (for CreateChildContext) + xSectionPropertySet = xPropSet; + + // name + Reference<XNamed> xNamed(xPropSet, UNO_QUERY); + xNamed->setName(sName); + + // stylename? + if (!sStyleName.isEmpty()) + { + XMLPropStyleContext* pStyle = rHelper-> + FindSectionStyle(sStyleName); + + if (pStyle != nullptr) + { + pStyle->FillPropertySet( xPropSet ); + } + } + + // IsVisible and condition (not for index headers) + if (! bIsIndexHeader) + { + xPropSet->setPropertyValue( "IsVisible", Any(bIsVisible) ); + + // #97450# hidden sections must be hidden on reload + // For backwards compatibility, set flag only if it is + // present + if( bIsCurrentlyVisibleOK ) + { + xPropSet->setPropertyValue( "IsCurrentlyVisible", Any(bIsCurrentlyVisible)); + } + + if (bCondOK) + { + xPropSet->setPropertyValue( "Condition", Any(sCond) ); + } + } + + // password (only for regular sections) + if ( bSequenceOK && + (nElement & TOKEN_MASK) == XML_SECTION ) + { + xPropSet->setPropertyValue("ProtectionKey", Any(aSequence)); + } + + // protection + xPropSet->setPropertyValue( "IsProtected", Any(bProtect) ); + + // insert marker, <paragraph>, marker; then insert + // section over the first marker character, and delete the + // last paragraph (and marker) when closing a section. + Reference<XTextRange> xStart = + rHelper->GetCursor()->getStart(); +#ifndef DBG_UTIL + OUString sMarkerString(" "); +#else + OUString sMarkerString("X"); +#endif + rHelper->InsertString(sMarkerString); + rHelper->InsertControlCharacter( + ControlCharacter::APPEND_PARAGRAPH ); + rHelper->InsertString(sMarkerString); + + // select first marker + rHelper->GetCursor()->gotoRange(xStart, false); + rHelper->GetCursor()->goRight(1, true); + + // convert section to XTextContent + Reference<XTextContent> xTextContent(xSectionPropertySet, + UNO_QUERY); + + // and insert (over marker) + rHelper->GetText()->insertTextContent( + rHelper->GetCursorAsRange(), xTextContent, true ); + + // and delete first marker (in section) + rHelper->GetText()->insertString( + rHelper->GetCursorAsRange(), "", true); + + // finally, check for redlines that should start at + // the section start node + rHelper->RedlineAdjustStartNodeCursor(); // start ??? + + // xml:id for RDF metadata + GetImport().SetXmlId(xIfc, sXmlId); +} + +void XMLSectionImportContext::ProcessAttributes( + const Reference<XFastAttributeList> & xAttrList ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(XML, XML_ID): + sXmlId = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + sStyleName = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_NAME): + sName = aIter.toString(); + bValid = true; + break; + case XML_ELEMENT(TEXT, XML_CONDITION): + { + OUString sValue = aIter.toString(); + OUString sTmp; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap(). + GetKeyByAttrValueQName(sValue, &sTmp); + if( XML_NAMESPACE_OOOW == nPrefix ) + { + sCond = sTmp; + bCondOK = true; + } + else + sCond = sValue; + } + break; + case XML_ELEMENT(TEXT, XML_DISPLAY): + if (IsXMLToken(aIter, XML_TRUE)) + { + bIsVisible = true; + } + else if ( IsXMLToken(aIter, XML_NONE) || + IsXMLToken(aIter, XML_CONDITION) ) + { + bIsVisible = false; + } + // else: ignore + break; + case XML_ELEMENT(TEXT, XML_IS_HIDDEN): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bIsCurrentlyVisible = !bTmp; + bIsCurrentlyVisibleOK = true; + } + } + break; + case XML_ELEMENT(TEXT, XML_PROTECTION_KEY): + ::comphelper::Base64::decode(aSequence, aIter.toString()); + bSequenceOK = true; + break; + case XML_ELEMENT(TEXT, XML_PROTECTED): + // compatibility with SRC629 (or earlier) versions + case XML_ELEMENT(TEXT, XML_PROTECT): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bProtect = bTmp; + } + break; + } + default: + // ignore + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + break; + } + } +} + +void XMLSectionImportContext::endFastElement(sal_Int32 ) +{ + // get rid of last paragraph + // (unless it's the only paragraph in the section) + rtl::Reference<XMLTextImportHelper> rHelper = GetImport().GetTextImport(); + rHelper->GetCursor()->goRight(1, false); + if (bHasContent) + { + rHelper->GetCursor()->goLeft(1, true); + rHelper->GetText()->insertString(rHelper->GetCursorAsRange(), + "", true); + } + + // and delete second marker + rHelper->GetCursor()->goRight(1, true); + rHelper->GetText()->insertString(rHelper->GetCursorAsRange(), + "", true); + + // check for redlines to our endnode + rHelper->RedlineAdjustStartNodeCursor(); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLSectionImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // section-source (-dde) elements + if ( nElement == XML_ELEMENT(TEXT, XML_SECTION_SOURCE) ) + { + return new XMLSectionSourceImportContext(GetImport(), + xSectionPropertySet); + } + else if ( nElement == XML_ELEMENT(OFFICE, XML_DDE_SOURCE) ) + { + return new XMLSectionSourceDDEImportContext(GetImport(), + xSectionPropertySet); + } + else + { + // otherwise: text context + auto pContext = GetImport().GetTextImport()->CreateTextChildContext( + GetImport(), nElement, xAttrList, XMLTextType::Section ); + + // if that fails, default context + if (pContext) + bHasContent = true; + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return pContext; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionImportContext.hxx b/xmloff/source/text/XMLSectionImportContext.hxx new file mode 100644 index 0000000000..83f40d05eb --- /dev/null +++ b/xmloff/source/text/XMLSectionImportContext.hxx @@ -0,0 +1,80 @@ +/* -*- 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 <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/Sequence.h> + +namespace com::sun::star { + namespace text { class XTextRange; } + namespace beans { class XPropertySet; } + namespace xml::sax { class XAttributeList; } +} + + +/** + * Import text sections. + * + * This context may *also* be used for index header sections. The + * differentiates its behaviour based on GetLocalName(). + */ +class XMLSectionImportContext final : public SvXMLImportContext +{ + /// TextSection (as XPropertySet) for passing down to data source elements + css::uno::Reference<css::beans::XPropertySet> xSectionPropertySet; + + OUString sXmlId; + OUString sStyleName; + OUString sName; + OUString sCond; + css::uno::Sequence<sal_Int8> aSequence; + bool bProtect; + bool bCondOK; + bool bIsVisible; + bool bValid; + bool bSequenceOK; + bool bIsCurrentlyVisible; + bool bIsCurrentlyVisibleOK; + + bool bHasContent; + +public: + + XMLSectionImportContext( SvXMLImport& rImport ); + + virtual ~XMLSectionImportContext() override; + +private: + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + void ProcessAttributes( + const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionSourceDDEImportContext.cxx b/xmloff/source/text/XMLSectionSourceDDEImportContext.cxx new file mode 100644 index 0000000000..e2d8f1ce84 --- /dev/null +++ b/xmloff/source/text/XMLSectionSourceDDEImportContext.cxx @@ -0,0 +1,108 @@ +/* -*- 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 "XMLSectionSourceDDEImportContext.hxx" +#include "XMLSectionImportContext.hxx" +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <sax/tools/converter.hxx> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <tools/debug.hxx> + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::beans::XMultiPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XFastAttributeList; + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + +XMLSectionSourceDDEImportContext::XMLSectionSourceDDEImportContext( + SvXMLImport& rImport, + Reference<XPropertySet> & rSectPropSet) : + SvXMLImportContext(rImport), + rSectionPropertySet(rSectPropSet) +{ +} + +XMLSectionSourceDDEImportContext::~XMLSectionSourceDDEImportContext() +{ +} + +void XMLSectionSourceDDEImportContext::startFastElement(sal_Int32 /*nElement*/, + const Reference<XFastAttributeList> & xAttrList) +{ + OUString sApplication; + OUString sTopic; + OUString sItem; + bool bAutomaticUpdate = false; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(OFFICE, XML_DDE_APPLICATION): + sApplication = aIter.toString(); + break; + case XML_ELEMENT(OFFICE, XML_DDE_TOPIC): + sTopic = aIter.toString(); + break; + case XML_ELEMENT(OFFICE, XML_DDE_ITEM): + sItem = aIter.toString(); + break; + case XML_ELEMENT(OFFICE, XML_AUTOMATIC_UPDATE): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bAutomaticUpdate = bTmp; + } + break; + } + default: + ; // ignore + break; + } + } + + // DDE not supported on all platforms; query property first + if (!rSectionPropertySet->getPropertySetInfo()-> + hasPropertyByName("DDECommandFile")) + return; + + // use multi property set to force single update of connection #83654# + Sequence<OUString> aNames { "DDECommandFile", "DDECommandType", "DDECommandElement", "IsAutomaticUpdate" }; + Sequence<Any> aValues { Any(sApplication), Any(sTopic), Any(sItem), Any(bAutomaticUpdate) }; + + Reference<XMultiPropertySet> rMultiPropSet(rSectionPropertySet, + UNO_QUERY); + DBG_ASSERT(rMultiPropSet.is(), "we'd really like a XMultiPropertySet"); + if (rMultiPropSet.is()) + rMultiPropSet->setPropertyValues(aNames, aValues); + // else: ignore + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionSourceDDEImportContext.hxx b/xmloff/source/text/XMLSectionSourceDDEImportContext.hxx new file mode 100644 index 0000000000..31726f0982 --- /dev/null +++ b/xmloff/source/text/XMLSectionSourceDDEImportContext.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <com/sun/star/uno/Reference.h> + +namespace com::sun::star { + namespace beans { class XPropertySet; } + namespace xml::sax { class XAttributeList; } +} + +class XMLSectionSourceDDEImportContext : public SvXMLImportContext +{ + css::uno::Reference<css::beans::XPropertySet> & rSectionPropertySet; + +public: + + XMLSectionSourceDDEImportContext( + SvXMLImport& rImport, + css::uno::Reference<css::beans::XPropertySet> & rSectPropSet); + + virtual ~XMLSectionSourceDDEImportContext() override; + +protected: + + virtual void SAL_CALL startFastElement(sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionSourceImportContext.cxx b/xmloff/source/text/XMLSectionSourceImportContext.cxx new file mode 100644 index 0000000000..e8f12a85a2 --- /dev/null +++ b/xmloff/source/text/XMLSectionSourceImportContext.cxx @@ -0,0 +1,97 @@ +/* -*- 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 "XMLSectionSourceImportContext.hxx" +#include "XMLSectionImportContext.hxx" +#include <com/sun/star/text/SectionFileLink.hpp> +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/beans/XPropertySet.hpp> + + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + + +XMLSectionSourceImportContext::XMLSectionSourceImportContext( + SvXMLImport& rImport, + Reference<XPropertySet> & rSectPropSet) : + SvXMLImportContext(rImport), + rSectionPropertySet(rSectPropSet) +{ +} + +XMLSectionSourceImportContext::~XMLSectionSourceImportContext() +{ +} + +void XMLSectionSourceImportContext::startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + OUString sURL; + OUString sFilterName; + OUString sSectionName; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + OUString sValue = aIter.toString(); + switch (aIter.getToken()) + { + case XML_ELEMENT(XLINK, XML_HREF): + sURL = sValue; + break; + + case XML_ELEMENT(TEXT, XML_FILTER_NAME): + sFilterName = sValue; + break; + + case XML_ELEMENT(TEXT, XML_SECTION_NAME): + sSectionName = sValue; + break; + + default: + ; // ignore + break; + } + } + + if (!sURL.isEmpty() || !sFilterName.isEmpty()) + { + SectionFileLink aFileLink; + aFileLink.FileURL = GetImport().GetAbsoluteReference( sURL ); + aFileLink.FilterName = sFilterName; + + rSectionPropertySet->setPropertyValue("FileLink", Any(aFileLink)); + } + + if (!sSectionName.isEmpty()) + { + rSectionPropertySet->setPropertyValue("LinkRegion", Any(sSectionName)); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionSourceImportContext.hxx b/xmloff/source/text/XMLSectionSourceImportContext.hxx new file mode 100644 index 0000000000..f47dddcbb7 --- /dev/null +++ b/xmloff/source/text/XMLSectionSourceImportContext.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <com/sun/star/uno/Reference.h> + +namespace com::sun::star { + namespace beans { class XPropertySet; } + namespace xml::sax { class XAttributeList; } +} + +class XMLSectionSourceImportContext final : public SvXMLImportContext +{ + css::uno::Reference<css::beans::XPropertySet> & rSectionPropertySet; + +public: + + XMLSectionSourceImportContext( + SvXMLImport& rImport, + css::uno::Reference<css::beans::XPropertySet> & rSectPropSet); + + virtual ~XMLSectionSourceImportContext() override; + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLStringBufferImportContext.cxx b/xmloff/source/text/XMLStringBufferImportContext.cxx new file mode 100644 index 0000000000..254994a3ad --- /dev/null +++ b/xmloff/source/text/XMLStringBufferImportContext.cxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <XMLStringBufferImportContext.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> + + +using ::com::sun::star::uno::Reference; +using ::xmloff::token::XML_P; + +XMLStringBufferImportContext::XMLStringBufferImportContext( + SvXMLImport& rImport, + OUStringBuffer& rBuffer) : + SvXMLImportContext(rImport), + rTextBuffer(rBuffer) +{ +} + +XMLStringBufferImportContext::~XMLStringBufferImportContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLStringBufferImportContext::createFastChildContext( + sal_Int32 /*nElement*/, const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + return new XMLStringBufferImportContext(GetImport(), rTextBuffer); +} + +void XMLStringBufferImportContext::characters(const OUString& rChars ) +{ + rTextBuffer.append(rChars); +} + +void XMLStringBufferImportContext::endFastElement(sal_Int32 nElement) +{ + // add return for paragraph elements + if ( nElement == XML_ELEMENT(TEXT, XML_P) || nElement == XML_ELEMENT(LO_EXT, XML_P)) + { + rTextBuffer.append(u'\x000a'); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextCharStyleNamesElementExport.cxx b/xmloff/source/text/XMLTextCharStyleNamesElementExport.cxx new file mode 100644 index 0000000000..4cdbbc2b05 --- /dev/null +++ b/xmloff/source/text/XMLTextCharStyleNamesElementExport.cxx @@ -0,0 +1,75 @@ +/* -*- 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 "XMLTextCharStyleNamesElementExport.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlexp.hxx> +#include <osl/diagnose.h> + +namespace com::sun::star::beans { class XPropertySet; } + +using namespace ::com::sun::star::uno; +using ::com::sun::star::beans::XPropertySet; +using namespace ::xmloff::token; + +XMLTextCharStyleNamesElementExport::XMLTextCharStyleNamesElementExport( + SvXMLExport& rExp, + bool bDoSth, + bool bAllStyles, + const Reference < XPropertySet > & rPropSet, + const OUString& rPropName ) : + rExport( rExp ), + nCount( 0 ) +{ + if( !bDoSth ) + return; + + Any aAny = rPropSet->getPropertyValue( rPropName ); + Sequence < OUString > aNames; + if( !(aAny >>= aNames) ) + return; + + nCount = aNames.getLength(); + OSL_ENSURE( nCount > 0, "no char style found" ); + if ( bAllStyles ) ++nCount; + if( nCount > 1 ) + { + aName = rExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, GetXMLToken(XML_SPAN) ); + for( sal_Int32 i = 1; i < nCount; ++i ) + { + rExport.AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + rExport.EncodeStyleName( aNames[i - 1] ) ); + rExport.StartElement( aName, false ); + } + } +} + +XMLTextCharStyleNamesElementExport::~XMLTextCharStyleNamesElementExport() +{ + if( nCount > 1 ) + { + for( sal_Int32 i = 1; i < nCount; ++i ) + rExport.EndElement( aName, false ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextCharStyleNamesElementExport.hxx b/xmloff/source/text/XMLTextCharStyleNamesElementExport.hxx new file mode 100644 index 0000000000..0eaad5d33b --- /dev/null +++ b/xmloff/source/text/XMLTextCharStyleNamesElementExport.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include <rtl/ustring.hxx> +#include <com/sun/star/uno/Reference.hxx> + + +namespace com::sun::star { + namespace beans { class XPropertySet; } +} + +class SvXMLExport; + +class XMLTextCharStyleNamesElementExport +{ + SvXMLExport& rExport; + OUString aName; + sal_Int32 nCount; + +public: + + XMLTextCharStyleNamesElementExport( + SvXMLExport& rExp, bool bDoSomething, bool bAllStyles, + const css::uno::Reference < css::beans::XPropertySet > & rPropSet, + const OUString& rPropName ); + ~XMLTextCharStyleNamesElementExport(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextColumnsContext.cxx b/xmloff/source/text/XMLTextColumnsContext.cxx new file mode 100644 index 0000000000..09c6ac1eb9 --- /dev/null +++ b/xmloff/source/text/XMLTextColumnsContext.cxx @@ -0,0 +1,369 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/text/XTextColumns.hpp> +#include <com/sun/star/text/TextColumn.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/style/VerticalAlignment.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <sal/log.hxx> +#include <sax/tools/converter.hxx> +#include <xmloff/xmltkmap.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlement.hxx> +#include <XMLTextColumnsContext.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry<sal_Int8> const pXML_Sep_Style_Enum[] = +{ + { XML_NONE, 0 }, + { XML_SOLID, 1 }, + { XML_DOTTED, 2 }, + { XML_DASHED, 3 }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<VerticalAlignment> const pXML_Sep_Align_Enum[] = +{ + { XML_TOP, VerticalAlignment_TOP }, + { XML_MIDDLE, VerticalAlignment_MIDDLE }, + { XML_BOTTOM, VerticalAlignment_BOTTOM }, + { XML_TOKEN_INVALID, VerticalAlignment(0) } +}; + +class XMLTextColumnContext_Impl: public SvXMLImportContext +{ + text::TextColumn aColumn; + +public: + + XMLTextColumnContext_Impl( SvXMLImport& rImport, sal_Int32 nElement, + const uno::Reference< + xml::sax::XFastAttributeList > & xAttrList ); + + text::TextColumn& getTextColumn() { return aColumn; } +}; + + +XMLTextColumnContext_Impl::XMLTextColumnContext_Impl( + SvXMLImport& rImport, sal_Int32 /*nElement*/, + const uno::Reference< + xml::sax::XFastAttributeList > & xAttrList ) : + SvXMLImportContext( rImport ) +{ + aColumn.Width = 0; + aColumn.LeftMargin = 0; + aColumn.RightMargin = 0; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + sal_Int32 nVal; + switch( aIter.getToken() ) + { + case XML_ELEMENT(STYLE, XML_REL_WIDTH): + { + size_t nPos = aIter.toView().find( '*' ); + if( nPos != std::string_view::npos && static_cast<sal_Int32>(nPos+1) == aIter.getLength() ) + { + if (::sax::Converter::convertNumber( + nVal, + aIter.toView().substr(0, nPos), + 0, USHRT_MAX)) + aColumn.Width = nVal; + } + } + break; + case XML_ELEMENT(FO, XML_START_INDENT): + case XML_ELEMENT(FO_COMPAT, XML_START_INDENT): + if( GetImport().GetMM100UnitConverter(). + convertMeasureToCore( nVal, aIter.toView() ) ) + aColumn.LeftMargin = nVal; + break; + case XML_ELEMENT(FO, XML_END_INDENT): + case XML_ELEMENT(FO_COMPAT, XML_END_INDENT): + if( GetImport().GetMM100UnitConverter(). + convertMeasureToCore( nVal, aIter.toView() ) ) + aColumn.RightMargin = nVal; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + break; + } + } +} + +class XMLTextColumnSepContext_Impl: public SvXMLImportContext +{ + sal_Int32 nWidth; + sal_Int32 nColor; + sal_Int8 nHeight; + sal_Int8 nStyle; + VerticalAlignment eVertAlign; + +public: + + XMLTextColumnSepContext_Impl( SvXMLImport& rImport, sal_Int32 nElement, + const uno::Reference< + xml::sax::XFastAttributeList > & xAttrList ); + + sal_Int32 GetWidth() const { return nWidth; } + sal_Int32 GetColor() const { return nColor; } + sal_Int8 GetHeight() const { return nHeight; } + sal_Int8 GetStyle() const { return nStyle; } + VerticalAlignment GetVertAlign() const { return eVertAlign; } +}; + + +XMLTextColumnSepContext_Impl::XMLTextColumnSepContext_Impl( + SvXMLImport& rImport, sal_Int32 /*nElement*/, + const uno::Reference< + xml::sax::XFastAttributeList > & xAttrList) : + SvXMLImportContext( rImport ), + nWidth( 2 ), + nColor( 0 ), + nHeight( 100 ), + nStyle( 1 ), + eVertAlign( VerticalAlignment_TOP ) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + sal_Int32 nVal; + switch( aIter.getToken() ) + { + case XML_ELEMENT(STYLE, XML_WIDTH): + if( GetImport().GetMM100UnitConverter(). + convertMeasureToCore( nVal, aIter.toView() ) ) + nWidth = nVal; + break; + case XML_ELEMENT(STYLE, XML_HEIGHT): + if (::sax::Converter::convertPercent( nVal, aIter.toView() ) && + nVal >=1 && nVal <= 100 ) + nHeight = static_cast<sal_Int8>(nVal); + break; + case XML_ELEMENT(STYLE, XML_COLOR): + ::sax::Converter::convertColor( nColor, aIter.toView() ); + break; + case XML_ELEMENT(STYLE, XML_VERTICAL_ALIGN): + SvXMLUnitConverter::convertEnum( eVertAlign, aIter.toView(), + pXML_Sep_Align_Enum ); + break; + case XML_ELEMENT(STYLE, XML_STYLE): + SvXMLUnitConverter::convertEnum( nStyle, aIter.toView(), + pXML_Sep_Style_Enum ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +constexpr OUStringLiteral gsSeparatorLineIsOn(u"SeparatorLineIsOn"); +constexpr OUStringLiteral gsSeparatorLineWidth(u"SeparatorLineWidth"); +constexpr OUStringLiteral gsSeparatorLineColor(u"SeparatorLineColor"); +constexpr OUStringLiteral gsSeparatorLineRelativeHeight(u"SeparatorLineRelativeHeight"); +constexpr OUStringLiteral gsSeparatorLineVerticalAlignment(u"SeparatorLineVerticalAlignment"); +constexpr OUStringLiteral gsAutomaticDistance(u"AutomaticDistance"); +constexpr OUStringLiteral gsSeparatorLineStyle(u"SeparatorLineStyle"); + +XMLTextColumnsContext::XMLTextColumnsContext( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList >& xAttrList, + const XMLPropertyState& rProp, + ::std::vector< XMLPropertyState > &rProps ) +: XMLElementPropertyContext( rImport, nElement, rProp, rProps ) +, nCount( 0 ) +, bAutomatic( false ) +, nAutomaticDistance( 0 ) +{ + sal_Int32 nVal; + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(FO, XML_COLUMN_COUNT): + case XML_ELEMENT(FO_COMPAT, XML_COLUMN_COUNT): + if(::sax::Converter::convertNumber( nVal, aIter.toView(), 0, SHRT_MAX )) + nCount = static_cast<sal_Int16>(nVal); + break; + case XML_ELEMENT(FO, XML_COLUMN_GAP): + case XML_ELEMENT(FO_COMPAT, XML_COLUMN_GAP): + { + bAutomatic = GetImport().GetMM100UnitConverter(). + convertMeasureToCore( nAutomaticDistance, aIter.toView() ); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextColumnsContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_COLUMN) ) + { + const rtl::Reference<XMLTextColumnContext_Impl> xColumn{ + new XMLTextColumnContext_Impl( GetImport(), nElement, xAttrList )}; + + // add new tabstop to array of tabstops + maColumns.push_back( xColumn ); + + return xColumn; + } + else if( nElement == XML_ELEMENT(STYLE, XML_COLUMN_SEP) ) + { + mxColumnSep.set( + new XMLTextColumnSepContext_Impl( GetImport(), nElement, xAttrList )); + + return mxColumnSep; + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void XMLTextColumnsContext::endFastElement(sal_Int32 nElement ) +{ + Reference<XMultiServiceFactory> xFactory(GetImport().GetModel(),UNO_QUERY); + if( !xFactory.is() ) + return; + + Reference<XInterface> xIfc = xFactory->createInstance("com.sun.star.text.TextColumns"); + if( !xIfc.is() ) + return; + + Reference< XTextColumns > xColumns( xIfc, UNO_QUERY ); + if ( 0 == nCount ) + { + // zero columns = no columns -> 1 column + xColumns->setColumnCount( 1 ); + } + else if( !bAutomatic && + maColumns.size() == static_cast<sal_uInt16>(nCount) ) + { + // if we have column descriptions, one per column, and we don't use + // automatic width, then set the column widths + + sal_Int32 nRelWidth = 0; + sal_uInt16 nColumnsWithWidth = 0; + sal_Int16 i; + + for( i = 0; i < nCount; i++ ) + { + const TextColumn& rColumn = + maColumns[static_cast<sal_uInt16>(i)]->getTextColumn(); + if( rColumn.Width > 0 ) + { + nRelWidth += rColumn.Width; + nColumnsWithWidth++; + } + } + if( nColumnsWithWidth < nCount ) + { + sal_Int32 nColWidth = 0==nRelWidth + ? USHRT_MAX / nCount + : nRelWidth / nColumnsWithWidth; + + for( i=0; i < nCount; i++ ) + { + TextColumn& rColumn = + maColumns[static_cast<sal_uInt16>(i)]->getTextColumn(); + if( rColumn.Width == 0 ) + { + rColumn.Width = nColWidth; + nRelWidth += rColumn.Width; + if( 0 == --nColumnsWithWidth ) + break; + } + } + } + + Sequence< TextColumn > aColumns( static_cast<sal_Int32>(nCount) ); + TextColumn *pTextColumns = aColumns.getArray(); + for( i=0; i < nCount; i++ ) + *pTextColumns++ = maColumns[static_cast<sal_uInt16>(i)]->getTextColumn(); + + xColumns->setColumns( aColumns ); + } + else + { + // only set column count (and let the columns be distributed + // automatically) + + xColumns->setColumnCount( nCount ); + } + + Reference < XPropertySet > xPropSet( xColumns, UNO_QUERY ); + if( xPropSet.is() ) + { + bool bOn = mxColumnSep != nullptr; + + xPropSet->setPropertyValue( gsSeparatorLineIsOn, Any(bOn) ); + + if( mxColumnSep.is() ) + { + if( mxColumnSep->GetWidth() ) + { + xPropSet->setPropertyValue( gsSeparatorLineWidth, Any(mxColumnSep->GetWidth()) ); + } + if( mxColumnSep->GetHeight() ) + { + xPropSet->setPropertyValue( gsSeparatorLineRelativeHeight, + Any(mxColumnSep->GetHeight()) ); + } + if ( mxColumnSep->GetStyle() ) + { + xPropSet->setPropertyValue( gsSeparatorLineStyle, Any(mxColumnSep->GetStyle()) ); + } + + xPropSet->setPropertyValue( gsSeparatorLineColor, Any(mxColumnSep->GetColor()) ); + + xPropSet->setPropertyValue( gsSeparatorLineVerticalAlignment, Any(mxColumnSep->GetVertAlign()) ); + } + + // handle 'automatic columns': column distance + if( bAutomatic ) + { + xPropSet->setPropertyValue( gsAutomaticDistance, Any(nAutomaticDistance) ); + } + } + + aProp.maValue <<= xColumns; + + SetInsert( true ); + XMLElementPropertyContext::endFastElement(nElement); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextColumnsExport.cxx b/xmloff/source/text/XMLTextColumnsExport.cxx new file mode 100644 index 0000000000..ec80f2ed90 --- /dev/null +++ b/xmloff/source/text/XMLTextColumnsExport.cxx @@ -0,0 +1,196 @@ +/* -*- 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 <o3tl/any.hxx> +#include <rtl/ustrbuf.hxx> + + +#include <com/sun/star/text/XTextColumns.hpp> +#include <com/sun/star/text/ColumnSeparatorStyle.hpp> +#include <com/sun/star/text/TextColumn.hpp> +#include <com/sun/star/style/VerticalAlignment.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <sax/tools/converter.hxx> + +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlexp.hxx> +#include <XMLTextColumnsExport.hxx> + +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + + +constexpr OUStringLiteral gsSeparatorLineIsOn(u"SeparatorLineIsOn"); +constexpr OUStringLiteral gsSeparatorLineWidth(u"SeparatorLineWidth"); +constexpr OUStringLiteral gsSeparatorLineColor(u"SeparatorLineColor"); +constexpr OUStringLiteral gsSeparatorLineRelativeHeight(u"SeparatorLineRelativeHeight"); +constexpr OUStringLiteral gsSeparatorLineVerticalAlignment(u"SeparatorLineVerticalAlignment"); +constexpr OUStringLiteral gsIsAutomatic(u"IsAutomatic"); +constexpr OUStringLiteral gsAutomaticDistance(u"AutomaticDistance"); +constexpr OUStringLiteral gsSeparatorLineStyle(u"SeparatorLineStyle"); + +XMLTextColumnsExport::XMLTextColumnsExport( SvXMLExport& rExp ) : + rExport( rExp ) +{ +} + +void XMLTextColumnsExport::exportXML( const Any& rAny ) +{ + Reference < XTextColumns > xColumns; + rAny >>= xColumns; + if (!xColumns) + return; + + const Sequence < TextColumn > aColumns = xColumns->getColumns(); + sal_Int32 nCount = aColumns.getLength(); + + OUStringBuffer sValue; + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_COLUMN_COUNT, + OUString::number(nCount ? nCount : 1) ); + + // handle 'automatic' columns + Reference < XPropertySet > xPropSet( xColumns, UNO_QUERY ); + if( xPropSet.is() ) + { + Any aAny = xPropSet->getPropertyValue( gsIsAutomatic ); + if ( *o3tl::doAccess<bool>(aAny) ) + { + aAny = xPropSet->getPropertyValue( gsAutomaticDistance ); + sal_Int32 nDistance = 0; + aAny >>= nDistance; + OUStringBuffer aBuffer; + GetExport().GetMM100UnitConverter().convertMeasureToXML( + aBuffer, nDistance ); + GetExport().AddAttribute( XML_NAMESPACE_FO, + XML_COLUMN_GAP, + aBuffer.makeStringAndClear() ); + } + } + + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, XML_COLUMNS, + true, true ); + + if( xPropSet.is() ) + { + Any aAny = xPropSet->getPropertyValue( gsSeparatorLineIsOn ); + if( *o3tl::doAccess<bool>(aAny) ) + { + // style:width + aAny = xPropSet->getPropertyValue( gsSeparatorLineWidth ); + sal_Int32 nWidth = 0; + aAny >>= nWidth; + GetExport().GetMM100UnitConverter().convertMeasureToXML( sValue, + nWidth ); + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_WIDTH, + sValue.makeStringAndClear() ); + + // style:color + aAny = xPropSet->getPropertyValue( gsSeparatorLineColor ); + sal_Int32 nColor = 0; + aAny >>= nColor; + ::sax::Converter::convertColor( sValue, nColor ); + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_COLOR, + sValue.makeStringAndClear() ); + + // style:height + aAny = xPropSet->getPropertyValue( gsSeparatorLineRelativeHeight ); + sal_Int32 nHeight = 0; + aAny >>= nHeight; + ::sax::Converter::convertPercent( sValue, nHeight ); + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_HEIGHT, + sValue.makeStringAndClear() ); + + // style::style + aAny = xPropSet->getPropertyValue( gsSeparatorLineStyle ); + sal_Int16 nStyle = css::text::ColumnSeparatorStyle::NONE; + aAny >>= nStyle; + + enum XMLTokenEnum eStr = XML_TOKEN_INVALID; + switch ( nStyle ) + { + case css::text::ColumnSeparatorStyle::NONE: eStr = XML_NONE; break; + case css::text::ColumnSeparatorStyle::SOLID: eStr = XML_SOLID; break; + case css::text::ColumnSeparatorStyle::DOTTED: eStr = XML_DOTTED; break; + case css::text::ColumnSeparatorStyle::DASHED: eStr = XML_DASHED; break; + default: + break; + } + if ( eStr != XML_TOKEN_INVALID ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_STYLE, eStr ); + + // style:vertical-align + aAny = xPropSet->getPropertyValue( gsSeparatorLineVerticalAlignment ); + VerticalAlignment eVertAlign; + aAny >>= eVertAlign; + + eStr = XML_TOKEN_INVALID; + switch( eVertAlign ) + { +// case VerticalAlignment_TOP: eStr = XML_TOP; + case VerticalAlignment_MIDDLE: eStr = XML_MIDDLE; break; + case VerticalAlignment_BOTTOM: eStr = XML_BOTTOM; break; + default: + break; + } + + if( eStr != XML_TOKEN_INVALID) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_VERTICAL_ALIGN, eStr ); + + // style:column-sep + SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_STYLE, + XML_COLUMN_SEP, + true, true ); + } + } + + for (const auto& rColumn : aColumns) + { + // style:rel-width + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_WIDTH, + OUString::number(rColumn.Width) + "*" ); + + // fo:margin-left + GetExport().GetMM100UnitConverter().convertMeasureToXML( sValue, + rColumn.LeftMargin ); + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_START_INDENT, + sValue.makeStringAndClear() ); + + // fo:margin-right + GetExport().GetMM100UnitConverter().convertMeasureToXML( sValue, + rColumn.RightMargin ); + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_END_INDENT, + sValue.makeStringAndClear() ); + + // style:column + SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_STYLE, XML_COLUMN, + true, true ); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextFrameContext.cxx b/xmloff/source/text/XMLTextFrameContext.cxx new file mode 100644 index 0000000000..b00b2b84d9 --- /dev/null +++ b/xmloff/source/text/XMLTextFrameContext.cxx @@ -0,0 +1,1751 @@ +/* -*- 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 <o3tl/string_view.hxx> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <comphelper/base64.hxx> +#include <comphelper/mediamimetype.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/text/XTextFrame.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/text/SizeType.hpp> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/document/XEmbeddedObjectSupplier.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/text/VertOrientation.hpp> +#include <sax/tools/converter.hxx> +#include <utility> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmluconv.hxx> +#include "XMLAnchorTypePropHdl.hxx" +#include <XMLEmbeddedObjectImportContext.hxx> +#include <xmloff/XMLBase64ImportContext.hxx> +#include <XMLReplacementImageContext.hxx> +#include <xmloff/prstylei.hxx> +#include <xmloff/i18nmap.hxx> +#include <xexptran.hxx> +#include <xmloff/shapeimport.hxx> +#include <xmloff/XMLEventsImportContext.hxx> +#include <XMLImageMapContext.hxx> +#include "XMLTextFrameContext.hxx" +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <map> +#include <string_view> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::document; +using namespace ::xmloff::token; +using ::com::sun::star::document::XEventsSupplier; + +#define XML_TEXT_FRAME_TEXTBOX 1 +#define XML_TEXT_FRAME_GRAPHIC 2 +#define XML_TEXT_FRAME_OBJECT 3 +#define XML_TEXT_FRAME_OBJECT_OLE 4 +#define XML_TEXT_FRAME_APPLET 5 +#define XML_TEXT_FRAME_PLUGIN 6 +#define XML_TEXT_FRAME_FLOATING_FRAME 7 + +typedef ::std::map < const OUString, OUString > ParamMap; + +class XMLTextFrameContextHyperlink_Impl +{ + OUString sHRef; + OUString sName; + OUString sTargetFrameName; + bool bMap; + +public: + + inline XMLTextFrameContextHyperlink_Impl( OUString aHRef, + OUString aName, + OUString aTargetFrameName, + bool bMap ); + + const OUString& GetHRef() const { return sHRef; } + const OUString& GetName() const { return sName; } + const OUString& GetTargetFrameName() const { return sTargetFrameName; } + bool GetMap() const { return bMap; } +}; + +inline XMLTextFrameContextHyperlink_Impl::XMLTextFrameContextHyperlink_Impl( + OUString aHRef, OUString aName, + OUString aTargetFrameName, bool bM ) : + sHRef(std::move( aHRef )), + sName(std::move( aName )), + sTargetFrameName(std::move( aTargetFrameName )), + bMap( bM ) +{ +} + +namespace { + +// Implement Title/Description Elements UI (#i73249#) +class XMLTextFrameTitleOrDescContext_Impl : public SvXMLImportContext +{ + OUString& mrTitleOrDesc; + +public: + + + XMLTextFrameTitleOrDescContext_Impl( SvXMLImport& rImport, + OUString& rTitleOrDesc ); + + virtual void SAL_CALL characters( const OUString& rText ) override; +}; + +} + +XMLTextFrameTitleOrDescContext_Impl::XMLTextFrameTitleOrDescContext_Impl( + SvXMLImport& rImport, + OUString& rTitleOrDesc ) + : SvXMLImportContext( rImport ) + , mrTitleOrDesc( rTitleOrDesc ) +{ +} + +void XMLTextFrameTitleOrDescContext_Impl::characters( const OUString& rText ) +{ + mrTitleOrDesc += rText; +} + +namespace { + +class XMLTextFrameParam_Impl : public SvXMLImportContext +{ +public: + XMLTextFrameParam_Impl( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + ParamMap &rParamMap); +}; + +} + +XMLTextFrameParam_Impl::XMLTextFrameParam_Impl( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + ParamMap &rParamMap): + SvXMLImportContext( rImport ) +{ + OUString sName, sValue; + bool bFoundValue = false; // to allow empty values + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_VALUE): + { + sValue = aIter.toString(); + bFoundValue = true; + break; + } + case XML_ELEMENT(DRAW, XML_NAME): + sName = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + if (!sName.isEmpty() && bFoundValue ) + rParamMap[sName] = sValue; +} + +namespace { + +class XMLTextFrameContourContext_Impl : public SvXMLImportContext +{ + Reference < XPropertySet > xPropSet; + +public: + + + XMLTextFrameContourContext_Impl( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + const Reference < XPropertySet >& rPropSet, + bool bPath ); +}; + +} + +XMLTextFrameContourContext_Impl::XMLTextFrameContourContext_Impl( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< XFastAttributeList > & xAttrList, + const Reference < XPropertySet >& rPropSet, + bool bPath ) : + SvXMLImportContext( rImport ), + xPropSet( rPropSet ) +{ + OUString sD, sPoints, sViewBox; + bool bPixelWidth = false, bPixelHeight = false; + bool bAuto = false; + sal_Int32 nWidth = 0; + sal_Int32 nHeight = 0; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(SVG, XML_VIEWBOX): + case XML_ELEMENT(SVG_COMPAT, XML_VIEWBOX): + sViewBox = aIter.toString(); + break; + case XML_ELEMENT(SVG, XML_D): + case XML_ELEMENT(SVG_COMPAT, XML_D): + if( bPath ) + sD = aIter.toString(); + break; + case XML_ELEMENT(DRAW,XML_POINTS): + if( !bPath ) + sPoints = aIter.toString(); + break; + case XML_ELEMENT(SVG, XML_WIDTH): + case XML_ELEMENT(SVG_COMPAT, XML_WIDTH): + if (::sax::Converter::convertMeasurePx(nWidth, aIter.toView())) + bPixelWidth = true; + else + GetImport().GetMM100UnitConverter().convertMeasureToCore( + nWidth, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_HEIGHT): + case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT): + if (::sax::Converter::convertMeasurePx(nHeight, aIter.toView())) + bPixelHeight = true; + else + GetImport().GetMM100UnitConverter().convertMeasureToCore( + nHeight, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_RECREATE_ON_EDIT): + bAuto = IsXMLToken(aIter, XML_TRUE); + break; + } + } + + OUString sContourPolyPolygon("ContourPolyPolygon"); + Reference < XPropertySetInfo > xPropSetInfo = rPropSet->getPropertySetInfo(); + + if(!xPropSetInfo->hasPropertyByName(sContourPolyPolygon) || + nWidth <= 0 || nHeight <= 0 || bPixelWidth != bPixelHeight || + !(bPath ? sD : sPoints).getLength()) + return; + + const SdXMLImExViewBox aViewBox( sViewBox, GetImport().GetMM100UnitConverter()); + basegfx::B2DPolyPolygon aPolyPolygon; + + if( bPath ) + { + basegfx::utils::importFromSvgD(aPolyPolygon, sD, GetImport().needFixPositionAfterZ(), nullptr); + } + else + { + basegfx::B2DPolygon aPolygon; + + if(basegfx::utils::importFromSvgPoints(aPolygon, sPoints)) + { + aPolyPolygon = basegfx::B2DPolyPolygon(aPolygon); + } + } + + if(aPolyPolygon.count()) + { + const basegfx::B2DRange aSourceRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aViewBox.GetWidth(), aViewBox.GetY() + aViewBox.GetHeight()); + const basegfx::B2DRange aTargetRange( + 0.0, 0.0, + nWidth, nHeight); + + if(!aSourceRange.equal(aTargetRange)) + { + aPolyPolygon.transform( + basegfx::utils::createSourceRangeTargetRangeTransform( + aSourceRange, + aTargetRange)); + } + + css::drawing::PointSequenceSequence aPointSequenceSequence; + basegfx::utils::B2DPolyPolygonToUnoPointSequenceSequence(aPolyPolygon, aPointSequenceSequence); + xPropSet->setPropertyValue( sContourPolyPolygon, Any(aPointSequenceSequence) ); + } + + static constexpr OUString sIsPixelContour(u"IsPixelContour"_ustr); + + if( xPropSetInfo->hasPropertyByName( sIsPixelContour ) ) + { + xPropSet->setPropertyValue( sIsPixelContour, Any(bPixelWidth) ); + } + + static constexpr OUString sIsAutomaticContour(u"IsAutomaticContour"_ustr); + + if( xPropSetInfo->hasPropertyByName( sIsAutomaticContour ) ) + { + xPropSet->setPropertyValue( sIsAutomaticContour, Any(bAuto) ); + } +} + +namespace { + +class XMLTextFrameContext_Impl : public SvXMLImportContext +{ + css::uno::Reference < css::text::XTextCursor > xOldTextCursor; + css::uno::Reference < css::beans::XPropertySet > xPropSet; + css::uno::Reference < css::io::XOutputStream > xBase64Stream; + + /// old list item and block (#89891#) + bool mbListContextPushed; + + OUString m_sOrigName; + OUString sName; + OUString sStyleName; + OUString sNextName; + OUString sHRef; + OUString sCode; + OUString sMimeType; + OUString sFrameName; + OUString sAppletName; + OUString sFilterService; + OUString sBase64CharsLeft; + OUString sTblName; + OUStringBuffer maUrlBuffer; + + ParamMap aParamMap; + + sal_Int32 nX; + sal_Int32 nY; + sal_Int32 nWidth; + sal_Int32 nHeight; + sal_Int32 nZIndex; + sal_Int16 nPage; + sal_Int16 nRotation; + sal_Int16 nRelWidth; + sal_Int16 nRelHeight; + + sal_uInt16 nType; + css::text::TextContentAnchorType eAnchorType; + + bool bMayScript : 1; + bool bMinWidth : 1; + bool bMinHeight : 1; + bool bSyncWidth : 1; + bool bSyncHeight : 1; + bool bCreateFailed : 1; + bool bOwnBase64Stream : 1; + bool mbMultipleContent : 1; // This context is created based on a multiple content (image) + bool m_isDecorative = false; + bool m_isSplitAllowed = false; + + void Create(); + +public: + + + bool CreateIfNotThere(); + const OUString& GetHRef() const { return sHRef; } + + XMLTextFrameContext_Impl( SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList > & rAttrList, + css::text::TextContentAnchorType eAnchorType, + sal_uInt16 nType, + const css::uno::Reference<css::xml::sax::XFastAttributeList > & rFrameAttrList, + bool bMultipleContent = false ); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual void SAL_CALL characters( const OUString& rChars ) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + void SetHyperlink( const OUString& rHRef, + const OUString& rName, + const OUString& rTargetFrameName, + bool bMap ); + + // Implement Title/Description Elements UI (#i73249#) + void SetTitle( const OUString& rTitle ); + + void SetDesc( const OUString& rDesc ); + + void SetName(); + + const OUString& GetOrigName() const { return m_sOrigName; } + + css::text::TextContentAnchorType GetAnchorType() const { return eAnchorType; } + OUString GetMimeType() const { return sMimeType; } + + const css::uno::Reference < css::beans::XPropertySet >& GetPropSet() const { return xPropSet; } +}; + +} + +void XMLTextFrameContext_Impl::Create() +{ + rtl::Reference < XMLTextImportHelper > xTextImportHelper = + GetImport().GetTextImport(); + + switch ( nType) + { + case XML_TEXT_FRAME_OBJECT: + case XML_TEXT_FRAME_OBJECT_OLE: + if( xBase64Stream.is() ) + { + OUString sURL( GetImport().ResolveEmbeddedObjectURLFromBase64() ); + if( !sURL.isEmpty() ) + xPropSet = GetImport().GetTextImport() + ->createAndInsertOLEObject( GetImport(), sURL, + sStyleName, + sTblName, + nWidth, nHeight ); + } + else if( !sHRef.isEmpty() ) + { + OUString sURL( GetImport().ResolveEmbeddedObjectURL( sHRef, + std::u16string_view() ) ); + + if( GetImport().IsPackageURL( sHRef ) ) + { + xPropSet = GetImport().GetTextImport() + ->createAndInsertOLEObject( GetImport(), sURL, + sStyleName, + sTblName, + nWidth, nHeight ); + } + else + { + // it should be an own OOo link that has no storage persistence + xPropSet = GetImport().GetTextImport() + ->createAndInsertOOoLink( GetImport(), + sURL, + sStyleName, + sTblName, + nWidth, nHeight ); + } + } + else + { + OUString sURL = "vnd.sun.star.ServiceName:" + sFilterService; + xPropSet = GetImport().GetTextImport() + ->createAndInsertOLEObject( GetImport(), sURL, + sStyleName, + sTblName, + nWidth, nHeight ); + + } + break; + case XML_TEXT_FRAME_APPLET: + { + xPropSet = GetImport().GetTextImport() + ->createAndInsertApplet( sAppletName, sCode, + bMayScript, sHRef, + nWidth, nHeight); + break; + } + case XML_TEXT_FRAME_PLUGIN: + { + if(!sHRef.isEmpty()) + GetImport().GetAbsoluteReference(sHRef); + xPropSet = GetImport().GetTextImport() + ->createAndInsertPlugin( sMimeType, sHRef, + nWidth, nHeight); + + break; + } + case XML_TEXT_FRAME_FLOATING_FRAME: + { + xPropSet = GetImport().GetTextImport() + ->createAndInsertFloatingFrame( sFrameName, sHRef, + sStyleName, + nWidth, nHeight); + break; + } + default: + { + Reference<XMultiServiceFactory> xFactory( GetImport().GetModel(), + UNO_QUERY ); + if( xFactory.is() ) + { + OUString sServiceName; + switch( nType ) + { + case XML_TEXT_FRAME_TEXTBOX: sServiceName = "com.sun.star.text.TextFrame"; break; + case XML_TEXT_FRAME_GRAPHIC: sServiceName = "com.sun.star.text.GraphicObject"; break; + } + Reference<XInterface> xIfc = xFactory->createInstance( sServiceName ); + SAL_WARN_IF( !xIfc.is(), "xmloff.text", "couldn't create frame" ); + if( xIfc.is() ) + xPropSet.set( xIfc, UNO_QUERY ); + } + } + } + + if( !xPropSet.is() ) + { + bCreateFailed = true; + return; + } + + Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo(); + + // Skip duplicated frames + if(!mbMultipleContent && // It's allowed to have multiple image for the same frame + !sName.isEmpty() && + xTextImportHelper->IsDuplicateFrame(sName, nX, nY, nWidth, nHeight)) + { + bCreateFailed = true; + return; + } + + // set name + Reference < XNamed > xNamed( xPropSet, UNO_QUERY ); + if( xNamed.is() ) + { + OUString sOrigName( xNamed->getName() ); + if( sOrigName.isEmpty() || + (!sName.isEmpty() && sOrigName != sName) ) + { + OUString sOldName( sName ); + + sal_Int32 i = 0; + while( xTextImportHelper->HasFrameByName( sName ) ) + { + sName = sOldName + OUString::number( ++i ); + } + xNamed->setName( sName ); + if( sName != sOldName ) + { + xTextImportHelper->GetRenameMap().Add( XML_TEXT_RENAME_TYPE_FRAME, + sOldName, sName ); + + } + } + } + + // frame style + XMLPropStyleContext *pStyle = nullptr; + if( !sStyleName.isEmpty() ) + { + pStyle = xTextImportHelper->FindAutoFrameStyle( sStyleName ); + if( pStyle ) + sStyleName = pStyle->GetParentName(); + } + + Any aAny; + if( !sStyleName.isEmpty() ) + { + OUString sDisplayStyleName( GetImport().GetStyleDisplayName( + XmlStyleFamily::SD_GRAPHICS_ID, sStyleName ) ); + const Reference < XNameContainer > & rStyles = + xTextImportHelper->GetFrameStyles(); + if( rStyles.is() && + rStyles->hasByName( sDisplayStyleName ) ) + { + xPropSet->setPropertyValue( "FrameStyleName", Any(sDisplayStyleName) ); + } + } + + // anchor type (must be set before any other properties, because + // otherwise some orientations cannot be set or will be changed + // afterwards) + xPropSet->setPropertyValue( "AnchorType", Any(eAnchorType) ); + + // hard properties + if( pStyle ) + pStyle->FillPropertySet( xPropSet ); + + // x and y + sal_Int16 nHoriOrient = HoriOrientation::NONE; + aAny = xPropSet->getPropertyValue( "HoriOrient" ); + aAny >>= nHoriOrient; + if( HoriOrientation::NONE == nHoriOrient ) + { + xPropSet->setPropertyValue( "HoriOrientPosition", Any(nX) ); + } + + sal_Int16 nVertOrient = VertOrientation::NONE; + aAny = xPropSet->getPropertyValue( "VertOrient" ); + aAny >>= nVertOrient; + if( VertOrientation::NONE == nVertOrient ) + { + xPropSet->setPropertyValue( "VertOrientPosition", Any(nY) ); + } + + // width + if( nWidth > 0 ) + { + xPropSet->setPropertyValue( "Width", Any(nWidth) ); + } + if( nRelWidth > 0 || nWidth > 0 ) + { + xPropSet->setPropertyValue( "RelativeWidth", Any(nRelWidth) ); + } + if( bSyncWidth || nWidth > 0 ) + { + xPropSet->setPropertyValue( "IsSyncWidthToHeight", Any(bSyncWidth) ); + } + if( xPropSetInfo->hasPropertyByName( "WidthType" ) && + (bMinWidth || nWidth > 0 || nRelWidth > 0 ) ) + { + sal_Int16 nSizeType = + (bMinWidth && XML_TEXT_FRAME_TEXTBOX == nType) ? SizeType::MIN + : SizeType::FIX; + xPropSet->setPropertyValue( "WidthType", Any(nSizeType) ); + } + + if( nHeight > 0 ) + { + xPropSet->setPropertyValue( "Height", Any(nHeight) ); + } + if( nRelHeight > 0 || nHeight > 0 ) + { + xPropSet->setPropertyValue( "RelativeHeight", Any(nRelHeight) ); + } + if( bSyncHeight || nHeight > 0 ) + { + xPropSet->setPropertyValue( "IsSyncHeightToWidth", Any(bSyncHeight) ); + } + if( xPropSetInfo->hasPropertyByName( "SizeType" ) && + (bMinHeight || nHeight > 0 || nRelHeight > 0 ) ) + { + sal_Int16 nSizeType = + (bMinHeight && XML_TEXT_FRAME_TEXTBOX == nType) ? SizeType::MIN + : SizeType::FIX; + xPropSet->setPropertyValue( "SizeType", Any(nSizeType) ); + } + + if( XML_TEXT_FRAME_GRAPHIC == nType ) + { + // URL + OSL_ENSURE( !sHRef.isEmpty() || xBase64Stream.is(), + "neither URL nor base64 image data given" ); + uno::Reference<graphic::XGraphic> xGraphic; + if (!sHRef.isEmpty()) + { + xGraphic = GetImport().loadGraphicByURL(sHRef); + } + else if (xBase64Stream.is()) + { + xGraphic = GetImport().loadGraphicFromBase64(xBase64Stream); + xBase64Stream = nullptr; + } + + if (xGraphic.is()) + xPropSet->setPropertyValue("Graphic", Any(xGraphic)); + + // filter name + xPropSet->setPropertyValue( "GraphicFilter", Any(OUString()) ); + + // rotation + xPropSet->setPropertyValue( "GraphicRotation", Any(nRotation) ); + } + + // page number (must be set after the frame is inserted, because it + // will be overwritten then inserting the frame. + if( TextContentAnchorType_AT_PAGE == eAnchorType && nPage > 0 ) + { + xPropSet->setPropertyValue( "AnchorPageNo", Any(nPage) ); + } + + if (m_isDecorative && xPropSetInfo->hasPropertyByName("Decorative")) + { + xPropSet->setPropertyValue("Decorative", uno::Any(true)); + } + + if (m_isSplitAllowed && xPropSetInfo->hasPropertyByName("IsSplitAllowed")) + { + xPropSet->setPropertyValue("IsSplitAllowed", uno::Any(true)); + } + + if( XML_TEXT_FRAME_OBJECT != nType && + XML_TEXT_FRAME_OBJECT_OLE != nType && + XML_TEXT_FRAME_APPLET != nType && + XML_TEXT_FRAME_PLUGIN!= nType && + XML_TEXT_FRAME_FLOATING_FRAME != nType) + { + Reference < XTextContent > xTxtCntnt( xPropSet, UNO_QUERY ); + try + { + xTextImportHelper->InsertTextContent(xTxtCntnt); + } + catch (lang::IllegalArgumentException const&) + { + TOOLS_WARN_EXCEPTION("xmloff.text", "Cannot import part of the text - probably an image in the text frame?"); + return; + } + } + + // Make adding the shape to Z-Ordering dependent from if we are + // inside an inside_deleted_section (redlining). That is necessary + // since the shape will be removed again later. It would lead to + // errors if it would stay inside the Z-Ordering. Thus, the + // easiest way to solve that conflict is to not add it here. + if(!GetImport().HasTextImport() + || !GetImport().GetTextImport()->IsInsideDeleteContext()) + { + Reference < XShape > xShape( xPropSet, UNO_QUERY ); + + GetImport().GetShapeImport()->shapeWithZIndexAdded( xShape, nZIndex ); + } + + if( XML_TEXT_FRAME_TEXTBOX != nType ) + return; + + xTextImportHelper->ConnectFrameChains( sName, sNextName, xPropSet ); + Reference < XTextFrame > xTxtFrame( xPropSet, UNO_QUERY ); + Reference < XText > xTxt = xTxtFrame->getText(); + xOldTextCursor = xTextImportHelper->GetCursor(); + xTextImportHelper->SetCursor( xTxt->createTextCursor() ); + + // remember old list item and block (#89892#) and reset them + // for the text frame + xTextImportHelper->PushListContext(); + mbListContextPushed = true; +} + +void XMLTextFrameContext::removeGraphicFromImportContext(const SvXMLImportContext& rContext) +{ + const XMLTextFrameContext_Impl* pXMLTextFrameContext_Impl = dynamic_cast< const XMLTextFrameContext_Impl* >(&rContext); + + if(!pXMLTextFrameContext_Impl) + return; + + try + { + // just dispose to delete + uno::Reference< lang::XComponent > xComp(pXMLTextFrameContext_Impl->GetPropSet(), UNO_QUERY); + + // Inform shape importer about the removal so it can adjust + // z-indexes. + uno::Reference<drawing::XShape> xShape(xComp, uno::UNO_QUERY); + GetImport().GetShapeImport()->shapeRemoved(xShape); + + if(xComp.is()) + { + xComp->dispose(); + } + } + catch( uno::Exception& ) + { + OSL_FAIL( "Error in cleanup of multiple graphic object import (!)" ); + } +} + +OUString XMLTextFrameContext::getMimeTypeFromImportContext(const SvXMLImportContext& rContext) const +{ + const XMLTextFrameContext_Impl* pXMLTextFrameContext_Impl = dynamic_cast<const XMLTextFrameContext_Impl*>(&rContext); + + if (pXMLTextFrameContext_Impl) + return pXMLTextFrameContext_Impl->GetMimeType(); + + return OUString(); +} + +OUString XMLTextFrameContext::getGraphicPackageURLFromImportContext(const SvXMLImportContext& rContext) const +{ + const XMLTextFrameContext_Impl* pXMLTextFrameContext_Impl = dynamic_cast< const XMLTextFrameContext_Impl* >(&rContext); + + if(pXMLTextFrameContext_Impl) + { + return "vnd.sun.star.Package:" + pXMLTextFrameContext_Impl->GetHRef(); + } + + return OUString(); +} + +css::uno::Reference<css::graphic::XGraphic> XMLTextFrameContext::getGraphicFromImportContext(const SvXMLImportContext& rContext) const +{ + uno::Reference<graphic::XGraphic> xGraphic; + + const XMLTextFrameContext_Impl* pXMLTextFrameContext_Impl = dynamic_cast<const XMLTextFrameContext_Impl*>(&rContext); + + if (pXMLTextFrameContext_Impl) + { + try + { + const uno::Reference<beans::XPropertySet>& xPropertySet = pXMLTextFrameContext_Impl->GetPropSet(); + + if (xPropertySet.is()) + { + xPropertySet->getPropertyValue("Graphic") >>= xGraphic; + } + } + catch (uno::Exception&) + {} + } + return xGraphic; +} + +bool XMLTextFrameContext_Impl::CreateIfNotThere() +{ + if( !xPropSet.is() && + ( XML_TEXT_FRAME_OBJECT_OLE == nType || + XML_TEXT_FRAME_GRAPHIC == nType ) && + xBase64Stream.is() && !bCreateFailed ) + { + if( bOwnBase64Stream ) + xBase64Stream->closeOutput(); + Create(); + } + + return xPropSet.is(); +} + +XMLTextFrameContext_Impl::XMLTextFrameContext_Impl( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< XFastAttributeList > & rAttrList, + TextContentAnchorType eATyp, + sal_uInt16 nNewType, + const Reference< XFastAttributeList > & rFrameAttrList, + bool bMultipleContent ) +: SvXMLImportContext( rImport ) +, mbListContextPushed( false ) +, nType( nNewType ) +, eAnchorType( eATyp ) +{ + nX = 0; + nY = 0; + nWidth = 0; + nHeight = 0; + nZIndex = -1; + nPage = 0; + nRotation = 0; + nRelWidth = 0; + nRelHeight = 0; + bMayScript = false; + + bMinHeight = false; + bMinWidth = false; + bSyncWidth = false; + bSyncHeight = false; + bCreateFailed = false; + bOwnBase64Stream = false; + mbMultipleContent = bMultipleContent; + + auto processAttr = [&](sal_Int32 nElement, const sax_fastparser::FastAttributeList::FastAttributeIter& aIter) -> void + { + switch( nElement ) + { + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + sStyleName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_NAME): + m_sOrigName = aIter.toString(); + sName = m_sOrigName; + break; + case XML_ELEMENT(DRAW, XML_FRAME_NAME): + sFrameName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_APPLET_NAME): + sAppletName = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_ANCHOR_TYPE): + if( TextContentAnchorType_AT_PARAGRAPH == eAnchorType || + TextContentAnchorType_AT_CHARACTER == eAnchorType || + TextContentAnchorType_AS_CHARACTER == eAnchorType ) + { + + TextContentAnchorType eNew; + if( XMLAnchorTypePropHdl::convert( aIter.toView(), eNew ) && + ( TextContentAnchorType_AT_PARAGRAPH == eNew || + TextContentAnchorType_AT_CHARACTER == eNew || + TextContentAnchorType_AS_CHARACTER == eNew || + TextContentAnchorType_AT_PAGE == eNew) ) + eAnchorType = eNew; + } + break; + case XML_ELEMENT(TEXT, XML_ANCHOR_PAGE_NUMBER): + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber(nTmp, aIter.toView(), 1, SHRT_MAX)) + nPage = static_cast<sal_Int16>(nTmp); + } + break; + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + nX, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + nY, aIter.toView() ); + break; + case XML_ELEMENT(SVG, XML_WIDTH): + case XML_ELEMENT(SVG_COMPAT, XML_WIDTH): + // relative widths are obsolete since SRC617. Remove them some day! + if( aIter.toView().find( '%' ) != std::string_view::npos ) + { + sal_Int32 nTmp; + if (::sax::Converter::convertPercent(nTmp, aIter.toView())) + nRelWidth = static_cast<sal_Int16>(nTmp); + } + else + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + nWidth, aIter.toView(), 0 ); + } + break; + case XML_ELEMENT(STYLE, XML_REL_WIDTH): + if( IsXMLToken(aIter, XML_SCALE) ) + { + bSyncWidth = true; + } + else + { + sal_Int32 nTmp; + if (::sax::Converter::convertPercent( nTmp, aIter.toView() )) + nRelWidth = static_cast<sal_Int16>(nTmp); + } + break; + case XML_ELEMENT(FO, XML_MIN_WIDTH): + case XML_ELEMENT(FO_COMPAT, XML_MIN_WIDTH): + if( aIter.toView().find( '%' ) != std::string_view::npos ) + { + sal_Int32 nTmp; + if (::sax::Converter::convertPercent(nTmp, aIter.toView())) + nRelWidth = static_cast<sal_Int16>(nTmp); + } + else + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + nWidth, aIter.toView(), 0 ); + } + bMinWidth = true; + break; + case XML_ELEMENT(SVG, XML_HEIGHT): + case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT): + // relative heights are obsolete since SRC617. Remove them some day! + if( aIter.toView().find( '%' ) != std::string_view::npos ) + { + sal_Int32 nTmp; + if (::sax::Converter::convertPercent(nTmp, aIter.toView())) + nRelHeight = static_cast<sal_Int16>(nTmp); + } + else + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + nHeight, aIter.toView(), 0 ); + } + break; + case XML_ELEMENT(STYLE, XML_REL_HEIGHT): + if( IsXMLToken( aIter, XML_SCALE ) ) + { + bSyncHeight = true; + } + else if( IsXMLToken( aIter, XML_SCALE_MIN ) ) + { + bSyncHeight = true; + bMinHeight = true; + } + else + { + sal_Int32 nTmp; + if (::sax::Converter::convertPercent( nTmp, aIter.toView() )) + nRelHeight = static_cast<sal_Int16>(nTmp); + } + break; + case XML_ELEMENT(FO, XML_MIN_HEIGHT): + case XML_ELEMENT(FO_COMPAT, XML_MIN_HEIGHT): + if( aIter.toView().find( '%' ) != std::string_view::npos ) + { + sal_Int32 nTmp; + if (::sax::Converter::convertPercent(nTmp, aIter.toView())) + nRelHeight = static_cast<sal_Int16>(nTmp); + } + else + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + nHeight, aIter.toView(), 0 ); + } + bMinHeight = true; + break; + case XML_ELEMENT(DRAW, XML_ZINDEX): + ::sax::Converter::convertNumber( nZIndex, aIter.toView(), -1 ); + break; + case XML_ELEMENT(DRAW, XML_CHAIN_NEXT_NAME): + sNextName = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_HREF): + sHRef = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_TRANSFORM): + { + // RotateFlyFrameFix: im/export full 'draw:transform' using existing tooling + // Currently only rotation is used, but combinations with 'draw:transform' + // may be necessary in the future, so that svg:x/svg:y/svg:width/svg:height + // may be extended/replaced with 'draw:transform' (see draw objects) + SdXMLImExTransform2D aSdXMLImExTransform2D; + basegfx::B2DHomMatrix aFullTransform; + + // Use SdXMLImExTransform2D to convert to transformation + // Note: using GetTwipUnitConverter instead of GetMM100UnitConverter may be needed, + // but is not generally available (as it should be, a 'current' UnitConverter should + // be available at GetExport() - and maybe was once). May have to be addressed as soon + // as translate transformations are used here. + aSdXMLImExTransform2D.SetString(aIter.toString(), GetImport().GetMM100UnitConverter()); + aSdXMLImExTransform2D.GetFullTransform(aFullTransform); + + if(!aFullTransform.isIdentity()) + { + const basegfx::utils::B2DHomMatrixBufferedDecompose aDecomposedTransform(aFullTransform); + + // currently we *only* use rotation (and translation indirectly), so warn if *any* + // of the other transform parts is used + SAL_WARN_IF(!basegfx::fTools::equal(1.0, aDecomposedTransform.getScale().getX()), "xmloff.text", "draw:transform uses scaleX" ); + SAL_WARN_IF(!basegfx::fTools::equal(1.0, aDecomposedTransform.getScale().getY()), "xmloff.text", "draw:transform uses scaleY" ); + SAL_WARN_IF(!basegfx::fTools::equalZero(aDecomposedTransform.getShearX()), "xmloff.text", "draw:transform uses shearX" ); + + // Translation comes from the translate to RotCenter, rot and BackTranslate. + // This means that it represents the translation between unrotated TopLeft + // and rotated TopLeft. This may be checked here now, but currently we only + // use rotation around center and assume that this *was* a rotation around + // center. The check would compare the object's center with the RotCenter + // that can be extracted from the transformation in aFullTransform. + // The definition contains implicitly the RotationCenter absolute + // to the scaled and translated object, so this may be used if needed (see + // _exportTextGraphic how the -trans/rot/trans is composed) + + if(!basegfx::fTools::equalZero(aDecomposedTransform.getRotate())) + { + // rotation is used, set it. Convert from deg to 10th degree integer + // CAUTION: due to #i78696# (rotation mirrored using API) the rotate + // value is already mirrored, so do not do it again here (to be in sync + // with XMLTextParagraphExport::_exportTextGraphic normally it would need + // to me mirrored using * -1.0, see conversion there) + // CAUTION-II: due to tdf#115782 it is better for current ODF to indeed use it + // with the wrong orientation as in all other cases - ARGH! We will need to + // correct this in future ODF ASAP! For now, mirror the rotation here AGAIN + const double fRotate(-basegfx::rad2deg<10>(aDecomposedTransform.getRotate())); + nRotation = static_cast< sal_Int16 >(basegfx::fround(fRotate) % 3600); + + // tdf#115529 may be negative, with the above modulo maximal -3599, so + // no loop needed here. nRotation is used in setPropertyValue("GraphicRotation") + // and *has* to be in the range [0 .. 3600[ + if(nRotation < 0) + { + nRotation += 3600; + } + } + } + } + break; + case XML_ELEMENT(DRAW, XML_CODE): + sCode = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_OBJECT): + break; + case XML_ELEMENT(DRAW, XML_ARCHIVE): + break; + case XML_ELEMENT(DRAW, XML_MAY_SCRIPT): + bMayScript = IsXMLToken( aIter, XML_TRUE ); + break; + case XML_ELEMENT(DRAW, XML_MIME_TYPE): + case XML_ELEMENT(LO_EXT, XML_MIME_TYPE): + sMimeType = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_NOTIFY_ON_UPDATE_OF_RANGES): + case XML_ELEMENT(DRAW, XML_NOTIFY_ON_UPDATE_OF_TABLE): + sTblName = aIter.toString(); + break; + case XML_ELEMENT(LO_EXT, XML_DECORATIVE): + case XML_ELEMENT(DRAW, XML_DECORATIVE): + ::sax::Converter::convertBool(m_isDecorative, aIter.toString()); + break; + case XML_ELEMENT(LO_EXT, XML_MAY_BREAK_BETWEEN_PAGES): + case XML_ELEMENT(DRAW, XML_MAY_BREAK_BETWEEN_PAGES): + sax::Converter::convertBool(m_isSplitAllowed, aIter.toString()); + break; + default: + SAL_INFO("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << " value=" << aIter.toString()); + } + }; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(rAttrList) ) + processAttr(aIter.getToken(), aIter); + for( auto& aIter : sax_fastparser::castToFastAttributeList(rFrameAttrList) ) + processAttr(aIter.getToken(), aIter); + + if( ( (XML_TEXT_FRAME_GRAPHIC == nType || + XML_TEXT_FRAME_OBJECT == nType || + XML_TEXT_FRAME_OBJECT_OLE == nType) && + sHRef.isEmpty() ) || + ( XML_TEXT_FRAME_APPLET == nType && sCode.isEmpty() ) || + ( XML_TEXT_FRAME_PLUGIN == nType && + sHRef.isEmpty() && sMimeType.isEmpty() ) ) + return; // no URL: no image or OLE object + + Create(); +} + +void XMLTextFrameContext_Impl::endFastElement(sal_Int32 ) +{ + if( ( XML_TEXT_FRAME_OBJECT_OLE == nType || + XML_TEXT_FRAME_GRAPHIC == nType) && + !xPropSet.is() && !bCreateFailed ) + { + std::u16string_view sTrimmedChars = o3tl::trim(maUrlBuffer); + if( !sTrimmedChars.empty() ) + { + if( !xBase64Stream.is() ) + { + if( XML_TEXT_FRAME_GRAPHIC == nType ) + { + xBase64Stream = + GetImport().GetStreamForGraphicObjectURLFromBase64(); + } + else + { + xBase64Stream = + GetImport().GetStreamForEmbeddedObjectURLFromBase64(); + } + if( xBase64Stream.is() ) + bOwnBase64Stream = true; + } + if( bOwnBase64Stream && xBase64Stream.is() ) + { + OUString sChars; + if( !sBase64CharsLeft.isEmpty() ) + { + sChars = sBase64CharsLeft + sTrimmedChars; + sBase64CharsLeft.clear(); + } + else + { + sChars = sTrimmedChars; + } + Sequence< sal_Int8 > aBuffer( (sChars.getLength() / 4) * 3 ); + sal_Int32 nCharsDecoded = + ::comphelper::Base64::decodeSomeChars( aBuffer, sChars ); + xBase64Stream->writeBytes( aBuffer ); + if( nCharsDecoded != sChars.getLength() ) + sBase64CharsLeft = sChars.copy( nCharsDecoded ); + } + } + maUrlBuffer.setLength(0); + } + + CreateIfNotThere(); + + if( xOldTextCursor.is() ) + { + GetImport().GetTextImport()->DeleteParagraph(); + GetImport().GetTextImport()->SetCursor( xOldTextCursor ); + } + + // reinstall old list item (if necessary) #89892# + if (mbListContextPushed) { + GetImport().GetTextImport()->PopListContext(); + } + + if (( nType == XML_TEXT_FRAME_APPLET || nType == XML_TEXT_FRAME_PLUGIN ) && xPropSet.is()) + GetImport().GetTextImport()->endAppletOrPlugin( xPropSet, aParamMap); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextFrameContext_Impl::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(DRAW, XML_PARAM) ) + { + if ( nType == XML_TEXT_FRAME_APPLET || nType == XML_TEXT_FRAME_PLUGIN ) + return new XMLTextFrameParam_Impl( GetImport(), + xAttrList, aParamMap ); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_BINARY_DATA) ) + { + if( !xPropSet.is() && !xBase64Stream.is() && !bCreateFailed ) + { + switch( nType ) + { + case XML_TEXT_FRAME_GRAPHIC: + xBase64Stream = + GetImport().GetStreamForGraphicObjectURLFromBase64(); + break; + case XML_TEXT_FRAME_OBJECT_OLE: + xBase64Stream = + GetImport().GetStreamForEmbeddedObjectURLFromBase64(); + break; + } + if( xBase64Stream.is() ) + return new XMLBase64ImportContext( GetImport(), xBase64Stream ); + } + } + // Correction of condition which also avoids warnings. (#i100480#) + if( XML_TEXT_FRAME_OBJECT == nType && + ( nElement == XML_ELEMENT(OFFICE, XML_DOCUMENT) || + nElement == XML_ELEMENT(MATH, XML_MATH) ) ) + { + if( !xPropSet.is() && !bCreateFailed ) + { + XMLEmbeddedObjectImportContext *pEContext = + new XMLEmbeddedObjectImportContext( GetImport(), nElement, xAttrList ); + sFilterService = pEContext->GetFilterServiceName(); + if( !sFilterService.isEmpty() ) + { + Create(); + if( xPropSet.is() ) + { + Reference < XEmbeddedObjectSupplier > xEOS( xPropSet, + UNO_QUERY ); + OSL_ENSURE( xEOS.is(), + "no embedded object supplier for own object" ); + Reference<css::lang::XComponent> aXComponent(xEOS->getEmbeddedObject()); + pEContext->SetComponent( aXComponent ); + } + } + return pEContext; + } + } + + if( xOldTextCursor.is() ) // text-box + { + auto p = GetImport().GetTextImport()->CreateTextChildContext( + GetImport(), nElement, xAttrList, + XMLTextType::TextBox ); + if (p) + return p; + } + + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + +void XMLTextFrameContext_Impl::characters( const OUString& rChars ) +{ + maUrlBuffer.append(rChars); +} + +void XMLTextFrameContext_Impl::SetHyperlink( const OUString& rHRef, + const OUString& rName, + const OUString& rTargetFrameName, + bool bMap ) +{ + static constexpr OUString s_HyperLinkURL = u"HyperLinkURL"_ustr; + static constexpr OUString s_HyperLinkName = u"HyperLinkName"_ustr; + static constexpr OUString s_HyperLinkTarget = u"HyperLinkTarget"_ustr; + static constexpr OUString s_ServerMap = u"ServerMap"_ustr; + if( !xPropSet.is() ) + return; + + Reference < XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + if( !xPropSetInfo.is() || + !xPropSetInfo->hasPropertyByName(s_HyperLinkURL)) + return; + + xPropSet->setPropertyValue( s_HyperLinkURL, Any(rHRef) ); + + if (xPropSetInfo->hasPropertyByName(s_HyperLinkName)) + { + xPropSet->setPropertyValue(s_HyperLinkName, Any(rName)); + } + + if (xPropSetInfo->hasPropertyByName(s_HyperLinkTarget)) + { + xPropSet->setPropertyValue( s_HyperLinkTarget, Any(rTargetFrameName) ); + } + + if (xPropSetInfo->hasPropertyByName(s_ServerMap)) + { + xPropSet->setPropertyValue(s_ServerMap, Any(bMap)); + } +} + +void XMLTextFrameContext_Impl::SetName() +{ + Reference<XNamed> xNamed(xPropSet, UNO_QUERY); + if (m_sOrigName.isEmpty() || !xNamed.is()) + return; + + OUString const name(xNamed->getName()); + if (name != m_sOrigName) + { + try + { + xNamed->setName(m_sOrigName); + } + catch (uno::Exception const&) + { // fdo#71698 document contains 2 frames with same draw:name + TOOLS_INFO_EXCEPTION("xmloff.text", "SetName(): exception setting \"" + << m_sOrigName << "\""); + } + } +} + +// Implement Title/Description Elements UI (#i73249#) +void XMLTextFrameContext_Impl::SetTitle( const OUString& rTitle ) +{ + if ( xPropSet.is() ) + { + Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo(); + if( xPropSetInfo->hasPropertyByName( "Title" ) ) + { + xPropSet->setPropertyValue( "Title", Any( rTitle ) ); + } + } +} + +void XMLTextFrameContext_Impl::SetDesc( const OUString& rDesc ) +{ + if ( xPropSet.is() ) + { + Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo(); + if( xPropSetInfo->hasPropertyByName( "Description" ) ) + { + xPropSet->setPropertyValue( "Description", Any( rDesc ) ); + } + } +} + + +bool XMLTextFrameContext::CreateIfNotThere( css::uno::Reference < css::beans::XPropertySet >& rPropSet ) +{ + SvXMLImportContext *pContext = m_xImplContext.get(); + XMLTextFrameContext_Impl *pImpl = dynamic_cast< XMLTextFrameContext_Impl*>( pContext ); + if( pImpl && pImpl->CreateIfNotThere() ) + rPropSet = pImpl->GetPropSet(); + + return rPropSet.is(); +} + +XMLTextFrameContext::XMLTextFrameContext( + SvXMLImport& rImport, + const Reference< XFastAttributeList > & xAttrList, + TextContentAnchorType eATyp ) +: SvXMLImportContext( rImport ) +, m_xAttrList( new sax_fastparser::FastAttributeList( xAttrList ) ) + // Implement Title/Description Elements UI (#i73249#) +, m_eDefaultAnchorType( eATyp ) + // Shapes in Writer cannot be named via context menu (#i51726#) +, m_HasAutomaticStyleWithoutParentStyle( false ) +, m_bSupportsReplacement( false ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + // New distinguish attribute between Writer objects and Draw objects is: + // Draw objects have an automatic style without a parent style (#i51726#) + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + { + OUString aStyleName = aIter.toString(); + if( !aStyleName.isEmpty() ) + { + rtl::Reference < XMLTextImportHelper > xTxtImport = + GetImport().GetTextImport(); + XMLPropStyleContext* pStyle = xTxtImport->FindAutoFrameStyle( aStyleName ); + if ( pStyle && pStyle->GetParentName().isEmpty() ) + { + m_HasAutomaticStyleWithoutParentStyle = true; + } + } + break; + } + case XML_ELEMENT(TEXT, XML_ANCHOR_TYPE): + { + TextContentAnchorType eNew; + if( XMLAnchorTypePropHdl::convert( aIter.toView(), eNew ) && + ( TextContentAnchorType_AT_PARAGRAPH == eNew || + TextContentAnchorType_AT_CHARACTER == eNew || + TextContentAnchorType_AS_CHARACTER == eNew || + TextContentAnchorType_AT_PAGE == eNew) ) + m_eDefaultAnchorType = eNew; + break; + } + } + } +} + +void XMLTextFrameContext::endFastElement(sal_Int32 ) +{ + /// solve if multiple image child contexts were imported + SvXMLImportContextRef const pMultiContext(solveMultipleImages()); + + SvXMLImportContext const*const pContext = + (pMultiContext.is()) ? pMultiContext.get() : m_xImplContext.get(); + XMLTextFrameContext_Impl *pImpl = const_cast<XMLTextFrameContext_Impl*>(dynamic_cast< const XMLTextFrameContext_Impl*>( pContext )); + assert(!pMultiContext.is() || pImpl); + + // When we are dealing with a textbox, pImpl will be null; + // we need to set the hyperlink to the shape instead + Reference<XShape> xShape = GetShape(); + if (xShape.is() && m_pHyperlink) + { + Reference<XPropertySet> xProps(xShape, UNO_QUERY); + if (xProps.is()) + xProps->setPropertyValue("Hyperlink", Any(m_pHyperlink->GetHRef())); + } + + if( !pImpl ) + return; + + pImpl->CreateIfNotThere(); + + // fdo#68839: in case the surviving image was not the first one, + // it will have a counter added to its name - set the original name + if (pMultiContext.is()) // do this only when necessary; esp. not for text + { // frames that may have entries in GetRenameMap()! + pImpl->SetName(); + } + + if( !m_sTitle.isEmpty() ) + { + pImpl->SetTitle( m_sTitle ); + } + if( !m_sDesc.isEmpty() ) + { + pImpl->SetDesc( m_sDesc ); + } + + if( m_pHyperlink ) + { + pImpl->SetHyperlink( m_pHyperlink->GetHRef(), m_pHyperlink->GetName(), + m_pHyperlink->GetTargetFrameName(), m_pHyperlink->GetMap() ); + m_pHyperlink.reset(); + } + + GetImport().GetTextImport()->StoreLastImportedFrameName(pImpl->GetOrigName()); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextFrameContext::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + SvXMLImportContextRef xContext; + + if( !m_xImplContext.is() ) + { + // no child exists + if( IsTokenInNamespace(nElement, XML_NAMESPACE_DRAW) ) + { + sal_uInt16 nFrameType = USHRT_MAX; + switch (nElement & TOKEN_MASK) + { + case XML_TEXT_BOX: + nFrameType = XML_TEXT_FRAME_TEXTBOX; + break; + case XML_IMAGE: + nFrameType = XML_TEXT_FRAME_GRAPHIC; + break; + case XML_OBJECT: + nFrameType = XML_TEXT_FRAME_OBJECT; + break; + case XML_OBJECT_OLE: + nFrameType = XML_TEXT_FRAME_OBJECT_OLE; + break; + case XML_APPLET: + nFrameType = XML_TEXT_FRAME_APPLET; + break; + case XML_PLUGIN: + nFrameType = XML_TEXT_FRAME_PLUGIN; + break; + case XML_FLOATING_FRAME: + nFrameType = XML_TEXT_FRAME_FLOATING_FRAME; + break; + } + + if( USHRT_MAX != nFrameType ) + { + // Shapes in Writer cannot be named via context menu (#i51726#) + if ( ( XML_TEXT_FRAME_TEXTBOX == nFrameType || + XML_TEXT_FRAME_GRAPHIC == nFrameType ) && + m_HasAutomaticStyleWithoutParentStyle ) + { + Reference < XShapes > xShapes; + xContext = XMLShapeImportHelper::CreateFrameChildContext( + GetImport(), nElement, xAttrList, xShapes, m_xAttrList ); + } + else if( XML_TEXT_FRAME_PLUGIN == nFrameType ) + { + bool bMedia = false; + + // check, if we have a media object + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_MIME_TYPE) ) + { + if (::comphelper::IsMediaMimeType(aIter.toView())) + bMedia = true; + + // leave this loop + break; + } + } + + if( bMedia ) + { + Reference < XShapes > xShapes; + xContext = XMLShapeImportHelper::CreateFrameChildContext( + GetImport(), nElement, xAttrList, xShapes, m_xAttrList ); + } + } + else if( XML_TEXT_FRAME_OBJECT == nFrameType || + XML_TEXT_FRAME_OBJECT_OLE == nFrameType ) + { + m_bSupportsReplacement = true; + } + else if(XML_TEXT_FRAME_GRAPHIC == nFrameType) + { + setSupportsMultipleContents( (nElement & TOKEN_MASK) == XML_IMAGE ); + } + + if (!xContext) + { + xContext = new XMLTextFrameContext_Impl( GetImport(), nElement, + xAttrList, + m_eDefaultAnchorType, + nFrameType, + m_xAttrList ); + } + + m_xImplContext = xContext; + + if(getSupportsMultipleContents() && XML_TEXT_FRAME_GRAPHIC == nFrameType) + { + addContent(*m_xImplContext); + } + } + } + } + else if(getSupportsMultipleContents() && nElement == XML_ELEMENT(DRAW, XML_IMAGE)) + { + // read another image + xContext = new XMLTextFrameContext_Impl( + GetImport(), nElement, xAttrList, + m_eDefaultAnchorType, XML_TEXT_FRAME_GRAPHIC, m_xAttrList, true); + + m_xImplContext = xContext; + addContent(*m_xImplContext); + } + else if( m_bSupportsReplacement && !m_xReplImplContext.is() && + nElement == XML_ELEMENT(DRAW, XML_IMAGE) ) + { + // read replacement image + Reference < XPropertySet > xPropSet; + if( CreateIfNotThere( xPropSet ) ) + { + xContext = new XMLReplacementImageContext( GetImport(), + nElement, xAttrList, xPropSet ); + m_xReplImplContext = xContext; + } + } + else if( nullptr != dynamic_cast< const XMLTextFrameContext_Impl*>( m_xImplContext.get() )) + { + // the child is a writer frame + if( IsTokenInNamespace(nElement, XML_NAMESPACE_SVG) || + IsTokenInNamespace(nElement, XML_NAMESPACE_SVG_COMPAT) ) + { + // Implement Title/Description Elements UI (#i73249#) + const bool bOld = SvXMLImport::OOo_2x >= GetImport().getGeneratorVersion(); + if ( bOld ) + { + if ( (nElement & TOKEN_MASK) == XML_DESC ) + { + xContext = new XMLTextFrameTitleOrDescContext_Impl( GetImport(), + m_sTitle ); + } + } + else + { + if( (nElement & TOKEN_MASK) == XML_TITLE ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + m_xImplContext = solveMultipleImages(); + } + xContext = new XMLTextFrameTitleOrDescContext_Impl( GetImport(), + m_sTitle ); + } + else if ( (nElement & TOKEN_MASK) == XML_DESC ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + m_xImplContext = solveMultipleImages(); + } + xContext = new XMLTextFrameTitleOrDescContext_Impl( GetImport(), + m_sDesc ); + } + } + } + else if( IsTokenInNamespace(nElement, XML_NAMESPACE_DRAW) ) + { + Reference < XPropertySet > xPropSet; + if( (nElement & TOKEN_MASK) == XML_CONTOUR_POLYGON ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + m_xImplContext = solveMultipleImages(); + } + if( CreateIfNotThere( xPropSet ) ) + xContext = new XMLTextFrameContourContext_Impl( GetImport(), nElement, + xAttrList, xPropSet, false ); + } + else if( (nElement & TOKEN_MASK) == XML_CONTOUR_PATH ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + m_xImplContext = solveMultipleImages(); + } + if( CreateIfNotThere( xPropSet ) ) + xContext = new XMLTextFrameContourContext_Impl( GetImport(), nElement, + xAttrList, xPropSet, true ); + } + else if( (nElement & TOKEN_MASK) == XML_IMAGE_MAP ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + m_xImplContext = solveMultipleImages(); + } + if( CreateIfNotThere( xPropSet ) ) + xContext = new XMLImageMapContext( GetImport(), xPropSet ); + } + } + else if( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + m_xImplContext = solveMultipleImages(); + } + // do we still have the frame object? + Reference < XPropertySet > xPropSet; + if( CreateIfNotThere( xPropSet ) ) + { + // is it an event supplier? + Reference<XEventsSupplier> xEventsSupplier(xPropSet, UNO_QUERY); + if (xEventsSupplier.is()) + { + // OK, we have the events, so create the context + xContext = new XMLEventsImportContext(GetImport(), xEventsSupplier); + } + } + } + } + // #i68101# + else if( nElement == XML_ELEMENT(SVG, XML_TITLE) || nElement == XML_ELEMENT(SVG, XML_DESC ) || + nElement == XML_ELEMENT(SVG_COMPAT, XML_TITLE) || nElement == XML_ELEMENT(SVG_COMPAT, XML_DESC ) ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + // note: no more draw:image can be added once we get here + m_xImplContext = solveMultipleImages(); + } + xContext = static_cast<SvXMLImportContext*>(m_xImplContext->createFastChildContext( nElement, xAttrList ).get()); + } + else if (nElement == XML_ELEMENT(LO_EXT, XML_SIGNATURELINE)) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + // note: no more draw:image can be added once we get here + m_xImplContext = solveMultipleImages(); + } + xContext = static_cast<SvXMLImportContext*>(m_xImplContext->createFastChildContext(nElement, xAttrList).get()); + } + else if (nElement == XML_ELEMENT(LO_EXT, XML_QRCODE)) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + // note: no more draw:image can be added once we get here + m_xImplContext = solveMultipleImages(); + } + xContext = static_cast<SvXMLImportContext*>(m_xImplContext->createFastChildContext(nElement, xAttrList).get()); + } + else if (nElement == XML_ELEMENT(DRAW, XML_A)) + { + xContext = static_cast<SvXMLImportContext*>(m_xImplContext->createFastChildContext(nElement, xAttrList).get()); + } + else + { + // the child is a drawing shape + return XMLShapeImportHelper::CreateFrameChildContext( + m_xImplContext.get(), nElement, xAttrList ); + } + + return xContext; +} + +void XMLTextFrameContext::SetHyperlink( const OUString& rHRef, + const OUString& rName, + const OUString& rTargetFrameName, + bool bMap ) +{ + OSL_ENSURE( !m_pHyperlink, "recursive SetHyperlink call" ); + m_pHyperlink = std::make_unique<XMLTextFrameContextHyperlink_Impl>( + rHRef, rName, rTargetFrameName, bMap ); +} + +TextContentAnchorType XMLTextFrameContext::GetAnchorType() const +{ + SvXMLImportContext *pContext = m_xImplContext.get(); + XMLTextFrameContext_Impl *pImpl = dynamic_cast< XMLTextFrameContext_Impl*>( pContext ); + if( pImpl ) + return pImpl->GetAnchorType(); + else + return m_eDefaultAnchorType; +} + +Reference < XTextContent > XMLTextFrameContext::GetTextContent() const +{ + Reference < XTextContent > xTxtCntnt; + SvXMLImportContext *pContext = m_xImplContext.get(); + XMLTextFrameContext_Impl *pImpl = dynamic_cast< XMLTextFrameContext_Impl* >( pContext ); + if( pImpl ) + xTxtCntnt.set( pImpl->GetPropSet(), UNO_QUERY ); + + return xTxtCntnt; +} + +Reference < XShape > XMLTextFrameContext::GetShape() const +{ + Reference < XShape > xShape; + SvXMLImportContext* pContext = m_xImplContext.get(); + SvXMLShapeContext* pImpl = dynamic_cast<SvXMLShapeContext*>( pContext ); + if ( pImpl ) + { + xShape = pImpl->getShape(); + } + + return xShape; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextFrameContext.hxx b/xmloff/source/text/XMLTextFrameContext.hxx new file mode 100644 index 0000000000..4f7e01118b --- /dev/null +++ b/xmloff/source/text/XMLTextFrameContext.hxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <memory> + +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <xmloff/xmlictxt.hxx> +#include <xmlmultiimagehelper.hxx> + +namespace com::sun::star { + namespace text { class XTextCursor; class XTextContent; } +} + +class XMLTextFrameContextHyperlink_Impl; + +class XMLTextFrameContext : public SvXMLImportContext, public MultiImageImportHelper +{ + rtl::Reference< sax_fastparser::FastAttributeList > m_xAttrList; + + SvXMLImportContextRef m_xImplContext; + SvXMLImportContextRef m_xReplImplContext; + + std::unique_ptr<XMLTextFrameContextHyperlink_Impl> m_pHyperlink; + // Implement Title/Description Elements UI (#i73249#) + OUString m_sTitle; + OUString m_sDesc; + + css::text::TextContentAnchorType m_eDefaultAnchorType; + + /* The <draw:name> can longer be used to distinguish Writer graphic/text box + objects and Draw graphic/text box objects. + The new distinguish attribute is the parent style of the automatic style + of the object. All Draw objects have an automatic style without a parent style. + (#i51726#) + */ + bool m_HasAutomaticStyleWithoutParentStyle; + bool m_bSupportsReplacement; + + bool CreateIfNotThere( css::uno::Reference < css::beans::XPropertySet >& rPropSet ); + +protected: + /// helper to get the created xShape instance, needs to be overridden + void removeGraphicFromImportContext(const SvXMLImportContext& rContext) override; + OUString getGraphicPackageURLFromImportContext(const SvXMLImportContext& rContext) const override; + OUString getMimeTypeFromImportContext(const SvXMLImportContext& rContext) const override; + css::uno::Reference<css::graphic::XGraphic> getGraphicFromImportContext(const SvXMLImportContext& rContext) const override; + +public: + + + XMLTextFrameContext( SvXMLImport& rImport, + const css::uno::Reference< + css::xml::sax::XFastAttributeList > & xAttrList, + css::text::TextContentAnchorType eDfltAnchorType ); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + void SetHyperlink( const OUString& rHRef, + const OUString& rName, + const OUString& rTargetFrameName, + bool bMap ); + + css::text::TextContentAnchorType GetAnchorType() const; + + css::uno::Reference < css::text::XTextContent > GetTextContent() const; + + // Frame "to character": anchor moves from first to last char after saving (#i33242#) + css::uno::Reference < css::drawing::XShape > GetShape() const; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextFrameHyperlinkContext.cxx b/xmloff/source/text/XMLTextFrameHyperlinkContext.cxx new file mode 100644 index 0000000000..64e16f1470 --- /dev/null +++ b/xmloff/source/text/XMLTextFrameHyperlinkContext.cxx @@ -0,0 +1,183 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/log.hxx> +#include <sax/tools/converter.hxx> + +#include <xmloff/shapeimport.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include "XMLTextFrameContext.hxx" +#include "XMLTextFrameHyperlinkContext.hxx" + +#include <com/sun/star/drawing/XShapes.hpp> + +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + +namespace drawing = com::sun::star::drawing; + + +XMLTextFrameHyperlinkContext::XMLTextFrameHyperlinkContext( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< XFastAttributeList > & xAttrList, + TextContentAnchorType eATyp ) : + SvXMLImportContext( rImport ), + eDefaultAnchorType( eATyp ), + bMap( false ) +{ + OUString sShow; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(XLINK, XML_HREF): + sHRef = GetImport().GetAbsoluteReference( aIter.toString() ); + break; + case XML_ELEMENT(OFFICE, XML_NAME): + sName = aIter.toString(); + break; + case XML_ELEMENT(OFFICE, XML_TARGET_FRAME_NAME): + sTargetFrameName = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_SHOW): + sShow = aIter.toString(); + break; + case XML_ELEMENT(OFFICE, XML_SERVER_MAP): + { + bool bTmp(false); + if (::sax::Converter::convertBool( bTmp, aIter.toView() )) + { + bMap = bTmp; + } + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( !sShow.isEmpty() && sTargetFrameName.isEmpty() ) + { + if( IsXMLToken( sShow, XML_NEW ) ) + sTargetFrameName = "_blank"; + else if( IsXMLToken( sShow, XML_REPLACE ) ) + sTargetFrameName = "_self"; + } +} + +XMLTextFrameHyperlinkContext::~XMLTextFrameHyperlinkContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextFrameHyperlinkContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ) +{ + SvXMLImportContext *pContext = nullptr; + XMLTextFrameContext *pTextFrameContext = nullptr; + + switch (nElement) + { + case XML_ELEMENT(DRAW, XML_FRAME): + { + pTextFrameContext = new XMLTextFrameContext(GetImport(), xAttrList, eDefaultAnchorType); + pTextFrameContext->SetHyperlink(sHRef, sName, sTargetFrameName, bMap); + pContext = pTextFrameContext; + xFrameContext = pContext; + } + break; + case XML_ELEMENT(DRAW, XML_CUSTOM_SHAPE): + case XML_ELEMENT(DRAW, XML_PATH): + case XML_ELEMENT(DRAW, XML_ELLIPSE): + case XML_ELEMENT(DRAW, XML_LINE): + case XML_ELEMENT(DRAW, XML_RECT): + case XML_ELEMENT(DRAW, XML_CAPTION): + case XML_ELEMENT(DRAW, XML_POLYGON): + case XML_ELEMENT(DRAW, XML_POLYLINE): + case XML_ELEMENT(DRAW, XML_MEASURE): + case XML_ELEMENT(DRAW, XML_CIRCLE): + case XML_ELEMENT(DRAW, XML_CONNECTOR): + case XML_ELEMENT(DRAW, XML_CONTROL): + case XML_ELEMENT(DRAW, XML_PAGE_THUMBNAIL): + case XML_ELEMENT(DRAW, XML_G): + case XML_ELEMENT(DR3D, XML_SCENE): + { + Reference<XShapes> xShapes; + SvXMLShapeContext* pShapeContext = XMLShapeImportHelper::CreateGroupChildContext( + GetImport(), nElement, xAttrList, xShapes); + pShapeContext->setHyperlink(sHRef); + pContext = pShapeContext; + } + break; + } + + if (!pContext) + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return pContext; +} + + +TextContentAnchorType XMLTextFrameHyperlinkContext::GetAnchorType() const +{ + if( xFrameContext.is() ) + { + SvXMLImportContext *pContext = xFrameContext.get(); + return dynamic_cast<XMLTextFrameContext&>(*pContext).GetAnchorType(); + } + else + return eDefaultAnchorType; + +} + +Reference < XTextContent > XMLTextFrameHyperlinkContext::GetTextContent() const +{ + Reference <XTextContent > xTxt; + if( xFrameContext.is() ) + { + SvXMLImportContext *pContext = xFrameContext.get(); + xTxt = dynamic_cast<XMLTextFrameContext&>(*pContext).GetTextContent(); + } + + return xTxt; +} + +// Frame "to character": anchor moves from first to last char after saving (#i33242#) +Reference < drawing::XShape > XMLTextFrameHyperlinkContext::GetShape() const +{ + Reference < drawing::XShape > xShape; + if( xFrameContext.is() ) + { + SvXMLImportContext *pContext = xFrameContext.get(); + xShape = dynamic_cast<XMLTextFrameContext&>(*pContext).GetShape(); + } + + return xShape; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextFrameHyperlinkContext.hxx b/xmloff/source/text/XMLTextFrameHyperlinkContext.hxx new file mode 100644 index 0000000000..a76081632a --- /dev/null +++ b/xmloff/source/text/XMLTextFrameHyperlinkContext.hxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <xmloff/xmlictxt.hxx> + +namespace com::sun::star { + namespace text { class XTextCursor; class XTextFrame; } + namespace beans { class XPropertySet; } +} + +/// Used for hyperlinks attached to objects (drawing objects, text boxes, Writer frames) +class XMLTextFrameHyperlinkContext : public SvXMLImportContext +{ + OUString sHRef; + OUString sName; + OUString sTargetFrameName; + css::text::TextContentAnchorType eDefaultAnchorType; + SvXMLImportContextRef xFrameContext; + bool bMap; + +public: + + XMLTextFrameHyperlinkContext( SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + css::text::TextContentAnchorType eDefaultAnchorType ); + virtual ~XMLTextFrameHyperlinkContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + css::text::TextContentAnchorType GetAnchorType() const; + + css::uno::Reference < css::text::XTextContent > GetTextContent() const; + + // Frame "to character": anchor moves from first to last char after saving (#i33242#) + css::uno::Reference < css::drawing::XShape > GetShape() const; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextHeaderFooterContext.cxx b/xmloff/source/text/XMLTextHeaderFooterContext.cxx new file mode 100644 index 0000000000..786528201d --- /dev/null +++ b/xmloff/source/text/XMLTextHeaderFooterContext.cxx @@ -0,0 +1,190 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/text/XParagraphAppend.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <o3tl/any.hxx> +#include <XMLTextHeaderFooterContext.hxx> +#include <xmloff/xmlimp.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::beans; + + +XMLTextHeaderFooterContext::XMLTextHeaderFooterContext( SvXMLImport& rImport, + const Reference < XPropertySet > & rPageStylePropSet, + bool bFooter, bool bLft, bool bFrst ) : + SvXMLImportContext( rImport ), + xPropSet( rPageStylePropSet ), + sOn( bFooter ? OUString("FooterIsOn") : OUString("HeaderIsOn") ), + sShareContent( bFooter ? OUString("FooterIsShared") : OUString("HeaderIsShared") ), + sText( bFooter ? OUString("FooterText") : OUString("HeaderText") ), + sTextFirst(bFooter ? OUString("FooterTextFirst") : OUString("HeaderTextFirst")), + sTextLeft( bFooter ? OUString("FooterTextLeft") : OUString("HeaderTextLeft") ), + bInsertContent( true ), + bLeft( bLft ), + bFirst( bFrst ) +{ + // NOTE: if this ever handles XML_DISPLAY attr then beware of fdo#72850 ! + if( !(bLeft || bFirst) ) + return; + + Any aAny = xPropSet->getPropertyValue( sOn ); + bool bOn = *o3tl::doAccess<bool>(aAny); + + if( bOn ) + { + if (bLeft) + { + aAny = xPropSet->getPropertyValue( sShareContent ); + bool bShared = bool(); + if (!(aAny >>= bShared)) + assert(false); // should return a value! + if( bShared ) + { + // Don't share headers any longer + xPropSet->setPropertyValue( sShareContent, Any(false) ); + } + } + if (bFirst) + { + static constexpr OUString sShareContentFirst( u"FirstIsShared"_ustr ); + aAny = xPropSet->getPropertyValue( sShareContentFirst ); + bool bSharedFirst = bool(); + if (!(aAny >>= bSharedFirst)) + assert(false); // should return a value! + if( bSharedFirst ) + { + // Don't share first/right headers any longer + xPropSet->setPropertyValue( sShareContentFirst, Any(false) ); + } + } + } + else + { + // If headers or footers are switched off, no content must be + // inserted. + bInsertContent = false; + } +} + +XMLTextHeaderFooterContext::~XMLTextHeaderFooterContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextHeaderFooterContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContext *pContext = nullptr; + if( bInsertContent ) + { + if( !xOldTextCursor.is() ) + { + bool bRemoveContent = true; + Any aAny; + if( bLeft || bFirst ) + { + // Headers and footers are switched on already, + // and they aren't shared. + if (bLeft) + aAny = xPropSet->getPropertyValue( sTextLeft ); + else + aAny = xPropSet->getPropertyValue( sTextFirst ); + } + else + { + aAny = xPropSet->getPropertyValue( sOn ); + bool bOn = *o3tl::doAccess<bool>(aAny); + + if( !bOn ) + { + // Switch header on + xPropSet->setPropertyValue( sOn, Any(true) ); + + // The content has not to be removed, because the header + // or footer is empty already. + bRemoveContent = false; + } + + // If a header or footer is not shared, share it now. + aAny = xPropSet->getPropertyValue( sShareContent ); + bool bShared = *o3tl::doAccess<bool>(aAny); + if( !bShared ) + { + xPropSet->setPropertyValue( sShareContent, Any(true) ); + } + + aAny = xPropSet->getPropertyValue( sText ); + } + + Reference < XText > xText; + aAny >>= xText; + + if( bRemoveContent ) + { + xText->setString(OUString()); + // fdo#82165 shapes anchored at the beginning or end survive + // setString("") - kill them the hard way: SwDoc::DelFullPara() + uno::Reference<text::XParagraphAppend> const xAppend( + xText, uno::UNO_QUERY_THROW); + uno::Reference<lang::XComponent> const xPara( + xAppend->finishParagraph( + uno::Sequence<beans::PropertyValue>()), + uno::UNO_QUERY_THROW); + xPara->dispose(); + } + + rtl::Reference < XMLTextImportHelper > xTxtImport = + GetImport().GetTextImport(); + + xOldTextCursor = xTxtImport->GetCursor(); + xTxtImport->SetCursor( xText->createTextCursor() ); + } + + pContext = + GetImport().GetTextImport()->CreateTextChildContext( + GetImport(), nElement, xAttrList, + XMLTextType::HeaderFooter ); + } + + return pContext; +} + +void XMLTextHeaderFooterContext::endFastElement(sal_Int32 ) +{ + if( xOldTextCursor.is() ) + { + GetImport().GetTextImport()->DeleteParagraph(); + GetImport().GetTextImport()->SetCursor( xOldTextCursor ); + } + else if( !bLeft ) + { + // If no content has been inserted into the header or footer, + // switch it off. + xPropSet->setPropertyValue( sOn, Any(false) ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextListAutoStylePool.cxx b/xmloff/source/text/XMLTextListAutoStylePool.cxx new file mode 100644 index 0000000000..affca2cc98 --- /dev/null +++ b/xmloff/source/text/XMLTextListAutoStylePool.cxx @@ -0,0 +1,294 @@ +/* -*- 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 <utility> +#include <vector> + +#include <tools/solar.h> +#include <o3tl/sorted_vector.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/ucb/XAnyCompareFactory.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <xmloff/xmlnume.hxx> +#include <xmloff/XMLTextListAutoStylePool.hxx> +#include <xmloff/xmlexp.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::style; + + +class XMLTextListAutoStylePoolEntry_Impl +{ + OUString sName; + OUString sInternalName; + Reference < XIndexReplace > xNumRules; + sal_uInt32 nPos; + bool bIsNamed; + + +public: + + XMLTextListAutoStylePoolEntry_Impl( + sal_uInt32 nPos, + const Reference < XIndexReplace > & rNumRules, + XMLTextListAutoStylePoolNames_Impl& rNames, + std::u16string_view rPrefix, + sal_uInt32& rName ); + + explicit XMLTextListAutoStylePoolEntry_Impl( + const Reference < XIndexReplace > & rNumRules ) : + xNumRules( rNumRules ), + nPos( 0 ), + bIsNamed( false ) + { + Reference < XNamed > xNamed( xNumRules, UNO_QUERY ); + if( xNamed.is() ) + { + sInternalName = xNamed->getName(); + bIsNamed = true; + } + } + + explicit XMLTextListAutoStylePoolEntry_Impl( + OUString aInternalName ) : + sInternalName(std::move( aInternalName )), + nPos( 0 ), + bIsNamed( true ) + { + } + + const OUString& GetName() const { return sName; } + const OUString& GetInternalName() const { return sInternalName; } + const Reference < XIndexReplace > & GetNumRules() const { return xNumRules; } + sal_uInt32 GetPos() const { return nPos; } + bool IsNamed() const { return bIsNamed; } +}; + +XMLTextListAutoStylePoolEntry_Impl::XMLTextListAutoStylePoolEntry_Impl( + sal_uInt32 nP, + const Reference < XIndexReplace > & rNumRules, + XMLTextListAutoStylePoolNames_Impl& rNames, + std::u16string_view rPrefix, + sal_uInt32& rName ) : + xNumRules( rNumRules ), + nPos( nP ), + bIsNamed( false ) +{ + Reference < XNamed > xNamed( xNumRules, UNO_QUERY ); + if( xNamed.is() ) + { + sInternalName = xNamed->getName(); + bIsNamed = true; + } + + // create a name that hasn't been used before. The created name has not + // to be added to the array, because it will never tried again + do + { + rName++; + sName = rPrefix + OUString::number( static_cast<sal_Int32>(rName) ); + } + while (rNames.find(sName) != rNames.end()); +} + +namespace { + +struct XMLTextListAutoStylePoolEntryCmp_Impl +{ + bool operator()( + std::unique_ptr<XMLTextListAutoStylePoolEntry_Impl> const& r1, + std::unique_ptr<XMLTextListAutoStylePoolEntry_Impl> const& r2 ) const + { + if( r1->IsNamed() ) + { + if( r2->IsNamed() ) + return r1->GetInternalName().compareTo( r2->GetInternalName() ) < 0; + else + return true; + } + else + { + if( r2->IsNamed() ) + return false; + else + return r1->GetNumRules().get() < r2->GetNumRules().get(); + } + } +}; + +} + +class XMLTextListAutoStylePool_Impl : public o3tl::sorted_vector<std::unique_ptr<XMLTextListAutoStylePoolEntry_Impl>, XMLTextListAutoStylePoolEntryCmp_Impl> {}; + +XMLTextListAutoStylePool::XMLTextListAutoStylePool( SvXMLExport& rExp ) : + m_rExport( rExp ), + m_sPrefix( "L" ), + m_pPool( new XMLTextListAutoStylePool_Impl ), + m_nName( 0 ) +{ + Reference<ucb::XAnyCompareFactory> xCompareFac( rExp.GetModel(), uno::UNO_QUERY ); + if( xCompareFac.is() ) + mxNumRuleCompare = xCompareFac->createAnyCompareByName( "NumberingRules" ); + SvXMLExportFlags nExportFlags = m_rExport.getExportFlags(); + bool bStylesOnly = (nExportFlags & SvXMLExportFlags::STYLES) && !(nExportFlags & SvXMLExportFlags::CONTENT); + if( bStylesOnly ) + m_sPrefix = "ML"; + + Reference<XStyleFamiliesSupplier> xFamiliesSupp(m_rExport.GetModel(), UNO_QUERY); + SAL_WARN_IF(!xFamiliesSupp.is(), "xmloff", "getStyleFamilies() from XModel failed for export!"); + Reference< XNameAccess > xFamilies; + if (xFamiliesSupp.is()) + xFamilies = xFamiliesSupp->getStyleFamilies(); + + Reference<XIndexAccess> xStyles; + static constexpr OUString aNumberStyleName(u"NumberingStyles"_ustr); + if (xFamilies.is() && xFamilies->hasByName(aNumberStyleName)) + xFamilies->getByName(aNumberStyleName) >>= xStyles; + + const sal_Int32 nStyles = xStyles.is() ? xStyles->getCount() : 0; + for (sal_Int32 i = 0; i < nStyles; i++) + { + Reference<XStyle> xStyle; + xStyles->getByIndex(i) >>= xStyle; + RegisterName(xStyle->getName()); + } +} + +XMLTextListAutoStylePool::~XMLTextListAutoStylePool() +{ +} + +void XMLTextListAutoStylePool::RegisterName( const OUString& rName ) +{ + m_aNames.insert(rName); +} + +sal_uInt32 XMLTextListAutoStylePool::Find( const XMLTextListAutoStylePoolEntry_Impl* pEntry ) const +{ + if( !pEntry->IsNamed() && mxNumRuleCompare.is() ) + { + const sal_uInt32 nCount = m_pPool->size(); + + uno::Any aAny1, aAny2; + aAny1 <<= pEntry->GetNumRules(); + + for( sal_uInt32 nPos = 0; nPos < nCount; nPos++ ) + { + aAny2 <<= (*m_pPool)[nPos]->GetNumRules(); + + if( mxNumRuleCompare->compare( aAny1, aAny2 ) == 0 ) + return nPos; + } + } + else + { + XMLTextListAutoStylePool_Impl::const_iterator it = m_pPool->find( pEntry ); + if( it != m_pPool->end() ) + return it - m_pPool->begin(); + } + + return sal_uInt32(-1); +} + +OUString XMLTextListAutoStylePool::Add( + const Reference < XIndexReplace > & rNumRules ) +{ + OUString sName; + XMLTextListAutoStylePoolEntry_Impl aTmp( rNumRules ); + + sal_uInt32 nPos = Find( &aTmp ); + if( nPos != sal_uInt32(-1) ) + { + sName = (*m_pPool)[ nPos ]->GetName(); + } + else + { + std::unique_ptr<XMLTextListAutoStylePoolEntry_Impl> pEntry( + new XMLTextListAutoStylePoolEntry_Impl( m_pPool->size(), + rNumRules, m_aNames, m_sPrefix, + m_nName )); + sName = pEntry->GetName(); + m_pPool->insert( std::move(pEntry) ); + } + + return sName; +} + +OUString XMLTextListAutoStylePool::Find( + const Reference < XIndexReplace > & rNumRules ) const +{ + OUString sName; + XMLTextListAutoStylePoolEntry_Impl aTmp( rNumRules ); + + sal_uInt32 nPos = Find( &aTmp ); + if( nPos != sal_uInt32(-1) ) + sName = (*m_pPool)[ nPos ]->GetName(); + + return sName; +} + +OUString XMLTextListAutoStylePool::Find( + const OUString& rInternalName ) const +{ + OUString sName; + XMLTextListAutoStylePoolEntry_Impl aTmp( rInternalName ); + sal_uInt32 nPos = Find( &aTmp ); + if( nPos != sal_uInt32(-1) ) + sName = (*m_pPool)[ nPos ]->GetName(); + + return sName; +} + +void XMLTextListAutoStylePool::exportXML() const +{ + sal_uInt32 nCount = m_pPool->size(); + if( !nCount ) + return; + + std::vector<XMLTextListAutoStylePoolEntry_Impl*> aExpEntries(nCount); + + sal_uInt32 i; + for( i=0; i < nCount; i++ ) + { + XMLTextListAutoStylePoolEntry_Impl *pEntry = (*m_pPool)[i].get(); + SAL_WARN_IF( pEntry->GetPos() >= nCount, "xmloff", "Illegal pos" ); + aExpEntries[pEntry->GetPos()] = pEntry; + } + + SvxXMLNumRuleExport aNumRuleExp( m_rExport ); + + for( i=0; i < nCount; i++ ) + { + XMLTextListAutoStylePoolEntry_Impl *pEntry = aExpEntries[i]; + aNumRuleExp.exportNumberingRule( pEntry->GetName(), false, + pEntry->GetNumRules() ); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextListBlockContext.cxx b/xmloff/source/text/XMLTextListBlockContext.cxx new file mode 100644 index 0000000000..ffacadf6cf --- /dev/null +++ b/xmloff/source/text/XMLTextListBlockContext.cxx @@ -0,0 +1,277 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <xmloff/xmlimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include "XMLTextListItemContext.hxx" +#include "XMLTextListBlockContext.hxx" +#include <txtlists.hxx> +#include <sal/log.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + + +// OD 2008-05-07 #refactorlists# +// add optional parameter <bRestartNumberingAtSubList> and its handling +XMLTextListBlockContext::XMLTextListBlockContext( + SvXMLImport& rImport, + XMLTextImportHelper& rTxtImp, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + const bool bRestartNumberingAtSubList ) +: SvXMLImportContext( rImport ) +, mrTxtImport( rTxtImp ) +, mnLevel( 0 ) +, mbRestartNumbering( false ) +, mbSetDefaults( false ) +{ + static constexpr OUString s_PropNameDefaultListId = u"DefaultListId"_ustr; + { + // get the parent list block context (if any); this is a bit ugly... + XMLTextListBlockContext * pLB(nullptr); + XMLTextListItemContext * pLI(nullptr); + XMLNumberedParaContext * pNP(nullptr); + rTxtImp.GetTextListHelper().ListContextTop(pLB, pLI, pNP); + mxParentListBlock = pLB; + } + // Inherit style name from parent list, as well as the flags whether + // numbering must be restarted and formats have to be created. + OUString sParentListStyleName; + if( mxParentListBlock.is() ) + { + XMLTextListBlockContext *pParent = mxParentListBlock.get(); + msListStyleName = pParent->msListStyleName; + sParentListStyleName = msListStyleName; + mxNumRules = pParent->GetNumRules(); + mnLevel = pParent->GetLevel() + 1; + mbRestartNumbering = pParent->IsRestartNumbering() || + bRestartNumberingAtSubList; + mbSetDefaults = pParent->mbSetDefaults; + msListId = pParent->GetListId(); + msContinueListId = pParent->GetContinueListId(); + } + + bool bIsContinueNumberingAttributePresent( false ); + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(XML, XML_ID): +//FIXME: there is no UNO API for lists + // xml:id is also the list ID (#i92221#) + if ( mnLevel == 0 ) // root <list> element + { + msListId = aIter.toString(); + } + break; + case XML_ELEMENT(TEXT, XML_CONTINUE_NUMBERING): + mbRestartNumbering = !IsXMLToken(aIter, XML_TRUE); + bIsContinueNumberingAttributePresent = true; + break; + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + msListStyleName = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_CONTINUE_LIST): + if ( mnLevel == 0 ) // root <list> element + { + msContinueListId = aIter.toString(); + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // Remember this list block. + mrTxtImport.GetTextListHelper().PushListContext( this ); + try + { + mxNumRules = XMLTextListsHelper::MakeNumRule(GetImport(), mxNumRules, + sParentListStyleName, msListStyleName, + mnLevel, &mbRestartNumbering, &mbSetDefaults ); + if( !mxNumRules.is() ) + return; + + if ( mnLevel != 0 ) // root <list> element + return; + + XMLTextListsHelper& rTextListsHelper( mrTxtImport.GetTextListHelper() ); + // Inconsistent behavior regarding lists (#i92811#) + OUString sListStyleDefaultListId; + { + uno::Reference< beans::XPropertySet > xNumRuleProps( mxNumRules, UNO_QUERY ); + if ( xNumRuleProps.is() ) + { + uno::Reference< beans::XPropertySetInfo > xNumRulePropSetInfo( + xNumRuleProps->getPropertySetInfo()); + if (xNumRulePropSetInfo.is() && + xNumRulePropSetInfo->hasPropertyByName( + s_PropNameDefaultListId)) + { + xNumRuleProps->getPropertyValue(s_PropNameDefaultListId) + >>= sListStyleDefaultListId; + SAL_WARN_IF( sListStyleDefaultListId.isEmpty(), "xmloff", + "no default list id found at numbering rules instance. Serious defect." ); + } + } + } + if ( msListId.isEmpty() ) // no text:id property found + { + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + const bool bBuildIdFound = GetImport().getBuildIds( nUPD, nBuild ); + if ( rImport.IsTextDocInOOoFileFormat() || + ( bBuildIdFound && nUPD == 680 ) ) + { + /* handling former documents written by OpenOffice.org: + use default list id of numbering rules instance, if existing + (#i92811#) + */ + if ( !sListStyleDefaultListId.isEmpty() ) + { + msListId = sListStyleDefaultListId; + if ( !bIsContinueNumberingAttributePresent && + !mbRestartNumbering && + rTextListsHelper.IsListProcessed( msListId ) ) + { + mbRestartNumbering = true; + } + } + } + if ( msListId.isEmpty() ) + { + // generate a new list id for the list + msListId = rTextListsHelper.GenerateNewListId(); + } + } + + if ( bIsContinueNumberingAttributePresent && !mbRestartNumbering && + msContinueListId.isEmpty() ) + { + const OUString& Last( rTextListsHelper.GetLastProcessedListId() ); + if ( rTextListsHelper.GetListStyleOfLastProcessedList() == msListStyleName + && Last != msListId ) + { + msContinueListId = Last; + } + } + + bool bContinueNumbering = bIsContinueNumberingAttributePresent && !mbRestartNumbering; + if (msContinueListId.isEmpty() && bContinueNumbering && GetImport().IsMSO()) + { + // No "continue list" id, but continue numbering was requested. Connect to the last list of + // the same list style in the Word case, even if there was a different list in the meantime. + msContinueListId = rTextListsHelper.GetLastIdOfStyleName(msListStyleName); + } + + if ( !msContinueListId.isEmpty() ) + { + if ( !rTextListsHelper.IsListProcessed( msContinueListId ) ) + { + msContinueListId.clear(); + } + else + { + // search continue list chain for master list and + // continue the master list. + OUString sTmpStr = + rTextListsHelper.GetContinueListIdOfProcessedList( msContinueListId ); + while ( !sTmpStr.isEmpty() ) + { + msContinueListId = sTmpStr; + + sTmpStr = + rTextListsHelper.GetContinueListIdOfProcessedList( msContinueListId ); + } + } + } + + if ( !rTextListsHelper.IsListProcessed( msListId ) ) + { + // Inconsistent behavior regarding lists (#i92811#) + rTextListsHelper.KeepListAsProcessed( + msListId, msListStyleName, msContinueListId, + sListStyleDefaultListId ); + } + } + catch (uno::Exception&) + { + // pop ourselves if anything goes wrong to avoid use-after-free + rTxtImp.GetTextListHelper().PopListContext(); + throw; + } +} + +XMLTextListBlockContext::~XMLTextListBlockContext() +{ +} + +void XMLTextListBlockContext::endFastElement(sal_Int32 ) +{ + // Numbering has not to be restarted if it has been restarted within + // a child list. + XMLTextListBlockContext *pParent = mxParentListBlock.get(); + if( pParent ) + { + pParent->mbRestartNumbering = mbRestartNumbering; + } + + // Restore current list block. + mrTxtImport.GetTextListHelper().PopListContext(); + + // Any paragraph following the list within the same list item must not + // be numbered. + mrTxtImport.GetTextListHelper().SetListItem( nullptr ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextListBlockContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContext *pContext = nullptr; + + bool bHeader = false; + switch( nElement ) + { + case XML_ELEMENT(TEXT, XML_LIST_HEADER): + bHeader = true; + [[fallthrough]]; + case XML_ELEMENT(TEXT, XML_LIST_ITEM): + pContext = new XMLTextListItemContext( GetImport(), mrTxtImport, + xAttrList, bHeader ); + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + + return pContext; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextListBlockContext.hxx b/xmloff/source/text/XMLTextListBlockContext.hxx new file mode 100644 index 0000000000..4b18d625cc --- /dev/null +++ b/xmloff/source/text/XMLTextListBlockContext.hxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/container/XIndexReplace.hpp> +#include <xmloff/xmlictxt.hxx> + +class XMLTextImportHelper; + +class XMLTextListBlockContext : public SvXMLImportContext +{ + XMLTextImportHelper& mrTxtImport; + + css::uno::Reference< css::container::XIndexReplace > mxNumRules; + + // text:style-name property of <list> element + OUString msListStyleName; + + rtl::Reference<XMLTextListBlockContext> mxParentListBlock; + + sal_Int16 mnLevel; + bool mbRestartNumbering; + bool mbSetDefaults; + + // text:id property of <list> element, only valid for root <list> element + OUString msListId; + // text:continue-list property of <list> element, only valid for root <list> element + OUString msContinueListId; + +public: + + + // add optional parameter <bRestartNumberingAtSubList> + XMLTextListBlockContext( + SvXMLImport& rImport, + XMLTextImportHelper& rTxtImp, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + const bool bRestartNumberingAtSubList = false ); + virtual ~XMLTextListBlockContext() override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + sal_Int16 GetLevel() const { return mnLevel; } + bool IsRestartNumbering() const { return mbRestartNumbering; } + void ResetRestartNumbering() { mbRestartNumbering = false; } + + /// does this list have (possibly inherited from parent) list-style-name? + bool HasListStyleName() { return !msListStyleName.isEmpty(); } + const css::uno::Reference < css::container::XIndexReplace >& GetNumRules() const + { return mxNumRules; } + + const OUString& GetListId() const { return msListId;} + const OUString& GetContinueListId() const { return msContinueListId;} +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextListItemContext.cxx b/xmloff/source/text/XMLTextListItemContext.cxx new file mode 100644 index 0000000000..1ef6736fa8 --- /dev/null +++ b/xmloff/source/text/XMLTextListItemContext.cxx @@ -0,0 +1,152 @@ +/* -*- 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/xmlimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include "txtparai.hxx" +#include <txtlists.hxx> +#include "XMLTextListBlockContext.hxx" +#include <xmloff/txtimp.hxx> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <xmloff/xmlnumi.hxx> +#include <xmloff/ProgressBarHelper.hxx> +#include "XMLTextListItemContext.hxx" +#include <sal/log.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + + +XMLTextListItemContext::XMLTextListItemContext( + SvXMLImport& rImport, + XMLTextImportHelper& rTxtImp, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + const bool bIsHeader ) + : SvXMLImportContext( rImport ), + rTxtImport( rTxtImp ), + nStartValue( -1 ), + mnSubListCount( 0 ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( !bIsHeader && aIter.getToken() == XML_ELEMENT(TEXT, XML_START_VALUE) ) + { + sal_Int32 nTmp = aIter.toInt32(); + if( nTmp >= 0 && nTmp <= SHRT_MAX ) + nStartValue = static_cast<sal_Int16>(nTmp); + } + else if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_OVERRIDE) ) + { + OUString sListStyleOverrideName = aIter.toString(); + if ( !sListStyleOverrideName.isEmpty() ) + { + OUString sDisplayStyleName( + GetImport().GetStyleDisplayName( XmlStyleFamily::TEXT_LIST, + sListStyleOverrideName ) ); + const Reference < container::XNameContainer >& rNumStyles = + rTxtImp.GetNumberingStyles(); + if( rNumStyles.is() && rNumStyles->hasByName( sDisplayStyleName ) ) + { + Reference < style::XStyle > xStyle; + Any aAny = rNumStyles->getByName( sDisplayStyleName ); + aAny >>= xStyle; + + uno::Reference< beans::XPropertySet > xPropSet( xStyle, UNO_QUERY ); + aAny = xPropSet->getPropertyValue("NumberingRules"); + aAny >>= mxNumRulesOverride; + } + else + { + const SvxXMLListStyleContext* pListStyle = + rTxtImp.FindAutoListStyle( sListStyleOverrideName ); + if( pListStyle ) + { + mxNumRulesOverride = pListStyle->GetNumRules(); + if( !mxNumRulesOverride.is() ) + { + pListStyle->CreateAndInsertAuto(); + mxNumRulesOverride = pListStyle->GetNumRules(); + } + } + } + } + } + else if ( aIter.getToken() == XML_ELEMENT(XML, XML_ID) ) + { +//FIXME: there is no UNO API for list items + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + + // If this is a <text:list-item> element, then remember it as a sign + // that a bullet has to be generated. + if( !bIsHeader ) { + rTxtImport.GetTextListHelper().SetListItem( this ); + } + +} + +XMLTextListItemContext::~XMLTextListItemContext() +{ +} + +void XMLTextListItemContext::endFastElement(sal_Int32 ) +{ + // finish current list item + rTxtImport.GetTextListHelper().SetListItem( nullptr ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextListItemContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContext *pContext = nullptr; + + switch( nElement ) + { + case XML_ELEMENT(TEXT, XML_H): + case XML_ELEMENT(TEXT, XML_P): + case XML_ELEMENT(LO_EXT, XML_P): + pContext = new XMLParaContext( GetImport(), nElement, + xAttrList ); + if (rTxtImport.IsProgress()) + GetImport().GetProgressBarHelper()->Increment(); + + break; + case XML_ELEMENT(TEXT, XML_LIST): + ++mnSubListCount; + pContext = new XMLTextListBlockContext( GetImport(), rTxtImport, + xAttrList, + (mnSubListCount > 1) ); + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + + return pContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextListItemContext.hxx b/xmloff/source/text/XMLTextListItemContext.hxx new file mode 100644 index 0000000000..de43d90f9b --- /dev/null +++ b/xmloff/source/text/XMLTextListItemContext.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 <com/sun/star/container/XIndexReplace.hpp> + +#include <xmloff/xmlictxt.hxx> + +class XMLTextImportHelper; + +class XMLTextListItemContext : public SvXMLImportContext +{ + XMLTextImportHelper& rTxtImport; + + sal_Int16 nStartValue; + + // quantity of <text:list> child elements + sal_Int16 mnSubListCount; + // list style instance for text::style-override property + css::uno::Reference< css::container::XIndexReplace > mxNumRulesOverride; + +public: + + + XMLTextListItemContext( + SvXMLImport& rImport, + XMLTextImportHelper& rTxtImp, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + const bool bIsHeader ); + virtual ~XMLTextListItemContext() override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + bool HasStartValue() const { return -1 != nStartValue; } + sal_Int16 GetStartValue() const { return nStartValue; } + + bool HasNumRulesOverride() const + { + return mxNumRulesOverride.is(); + } + const css::uno::Reference < css::container::XIndexReplace >& GetNumRulesOverride() const + { + return mxNumRulesOverride; + } +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextMarkImportContext.cxx b/xmloff/source/text/XMLTextMarkImportContext.cxx new file mode 100644 index 0000000000..96a694cf1d --- /dev/null +++ b/xmloff/source/text/XMLTextMarkImportContext.cxx @@ -0,0 +1,585 @@ +/* -*- 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 "XMLTextMarkImportContext.hxx" + + +#include <rtl/ustring.hxx> +#include <sal/log.hxx> +#include <osl/diagnose.h> +#include <sax/tools/converter.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/odffields.hxx> +#include <xmloff/xmlement.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/text/ControlCharacter.hpp> +#include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/text/XTextRangeCompare.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/rdf/XMetadatable.hpp> + +#include <com/sun/star/text/XFormField.hpp> +#include <comphelper/diagnose_ex.hxx> + +#include <RDFaImportHelper.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + + +XMLFieldParamImportContext::XMLFieldParamImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp ) : + SvXMLImportContext(rImport), + rHelper(rHlp) +{ +} + + +void XMLFieldParamImportContext::startFastElement(sal_Int32 /*nElement*/, const css::uno::Reference< css::xml::sax::XFastAttributeList> & xAttrList) +{ + OUString sName; + OUString sValue; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(FIELD, XML_NAME): + sName = aIter.toString(); + break; + case XML_ELEMENT(FIELD, XML_VALUE): + sValue = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + if (rHelper.hasCurrentFieldCtx() && !sName.isEmpty()) { + rHelper.addFieldParam(sName, sValue); + } +} + + +XMLTextMarkImportContext::XMLTextMarkImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp, + uno::Reference<uno::XInterface> & io_rxCrossRefHeadingBookmark ) + : SvXMLImportContext(rImport) + , m_rHelper(rHlp) + , m_rxCrossRefHeadingBookmark(io_rxCrossRefHeadingBookmark) + , m_isHidden(false) + , m_bHaveAbout(false) +{ +} + +namespace { + +enum lcl_MarkType { TypeReference, TypeReferenceStart, TypeReferenceEnd, + TypeBookmark, TypeBookmarkStart, TypeBookmarkEnd, + TypeFieldmark, TypeFieldmarkStart, TypeFieldmarkSeparator, TypeFieldmarkEnd + }; + +} + +SvXMLEnumMapEntry<lcl_MarkType> const lcl_aMarkTypeMap[] = +{ + { XML_REFERENCE_MARK, TypeReference }, + { XML_REFERENCE_MARK_START, TypeReferenceStart }, + { XML_REFERENCE_MARK_END, TypeReferenceEnd }, + { XML_BOOKMARK, TypeBookmark }, + { XML_BOOKMARK_START, TypeBookmarkStart }, + { XML_BOOKMARK_END, TypeBookmarkEnd }, + { XML_FIELDMARK, TypeFieldmark }, + { XML_FIELDMARK_START, TypeFieldmarkStart }, + { XML_FIELDMARK_SEPARATOR, TypeFieldmarkSeparator }, + { XML_FIELDMARK_END, TypeFieldmarkEnd }, + { XML_TOKEN_INVALID, lcl_MarkType(0) }, +}; + + +static OUString lcl_getFormFieldmarkName(std::u16string_view name) +{ + if (name == ODF_FORMCHECKBOX || + name == u"msoffice.field.FORMCHECKBOX" || + name == u"ecma.office-open-xml.field.FORMCHECKBOX") + return ODF_FORMCHECKBOX; + else if (name == ODF_FORMDROPDOWN || + name == u"ecma.office-open-xml.field.FORMDROPDOWN") + return ODF_FORMDROPDOWN; + else + return OUString(); +} + +static OUString lcl_getFieldmarkName(OUString const& name) +{ + if (name == "msoffice.field.FORMTEXT" || + name == "ecma.office-open-xml.field.FORMTEXT") + return ODF_FORMTEXT; + else + return name; +} + + +void XMLTextMarkImportContext::startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if (!FindName(xAttrList)) + { + m_sBookmarkName.clear(); + } + + if ((nElement & TOKEN_MASK) == XML_FIELDMARK_START || + (nElement & TOKEN_MASK) == XML_FIELDMARK) + { + if (m_sBookmarkName.isEmpty()) + { + m_sBookmarkName = "Unknown"; + } + m_rHelper.pushFieldCtx( m_sBookmarkName, m_sFieldName ); + } + + if ((nElement & TOKEN_MASK) == XML_BOOKMARK_START) + { + m_rHelper.setBookmarkAttributes(m_sBookmarkName, m_isHidden, m_sCondition); + } +} + +static auto InsertFieldmark(SvXMLImport & rImport, + XMLTextImportHelper & rHelper, bool const isFieldmarkSeparatorMissing) -> void +{ + assert(rHelper.hasCurrentFieldCtx()); // was set up in StartElement() + + // fdo#86795 check if it's actually a checkbox first + auto const [ name, type ] = rHelper.getCurrentFieldType(); + OUString const fieldmarkTypeName = lcl_getFieldmarkName(type); + if (fieldmarkTypeName == ODF_FORMCHECKBOX || + fieldmarkTypeName == ODF_FORMDROPDOWN) + { // sw can't handle checkbox with start+end + SAL_INFO("xmloff.text", "invalid fieldmark-start/fieldmark-end ignored"); + return; + } + + uno::Reference<text::XTextRange> const xStartRange(rHelper.getCurrentFieldStart()); + uno::Reference<text::XTextCursor> const xCursor( + rHelper.GetText()->createTextCursorByRange(xStartRange)); + uno::Reference<text::XTextRangeCompare> const xCompare(rHelper.GetText(), uno::UNO_QUERY); + if (xCompare->compareRegionStarts(xStartRange, rHelper.GetCursorAsRange()) < 0) + { + SAL_WARN("xmloff.text", "invalid field mark positions"); + assert(false); + } + xCursor->gotoRange(rHelper.GetCursorAsRange(), true); + + Reference<XTextContent> const xContent = XMLTextMarkImportContext::CreateAndInsertMark( + rImport, "com.sun.star.text.Fieldmark", name, xCursor, + OUString(), isFieldmarkSeparatorMissing); + + if (!xContent.is()) + return; + + // setup fieldmark... + Reference<text::XFormField> const xFormField(xContent, UNO_QUERY); + assert(xFormField.is()); + try { + xFormField->setFieldType(fieldmarkTypeName); + } catch (uno::RuntimeException const&) { + // tdf#140437 somehow old documents had the field code in the type + // attribute instead of field:param + SAL_INFO("xmloff.text", "invalid fieldmark type, converting to param"); + // add without checking: FieldParamImporter::Import() catches ElementExistException + rHelper.addFieldParam(ODF_CODE_PARAM, fieldmarkTypeName); + xFormField->setFieldType(ODF_UNHANDLED); + } + rHelper.setCurrentFieldParamsTo(xFormField); + // move cursor after setFieldType as that may delete/re-insert + rHelper.GetCursor()->gotoRange(xContent->getAnchor()->getEnd(), false); + rHelper.GetCursor()->goLeft(1, false); // move before CH_TXT_ATR_FIELDEND + // tdf#129520: AppendTextNode() ignores the content index! + // plan B: insert a spurious paragraph break now and join + // it in PopFieldmark()! + rHelper.GetText()->insertControlCharacter(rHelper.GetCursor(), + text::ControlCharacter::PARAGRAPH_BREAK, false); + rHelper.GetCursor()->goLeft(1, false); // back to previous paragraph +} + +static auto PopFieldmark(XMLTextImportHelper & rHelper) -> void +{ + // can't verify name because it's not written as an attribute... + uno::Reference<text::XTextContent> const xField(rHelper.popFieldCtx(), + uno::UNO_QUERY); + if (!xField.is()) + return; + + if (rHelper.GetText() == xField->getAnchor()->getText()) + { + try + { // skip CH_TXT_ATR_FIELDEND + rHelper.GetCursor()->goRight(1, true); + rHelper.GetCursor()->setString(OUString()); // undo AppendTextNode from InsertFieldmark + rHelper.GetCursor()->gotoRange(xField->getAnchor()->getEnd(), false); + } + catch (uno::Exception const&) + { + assert(false); // must succeed + } + } + else + { + SAL_INFO("xmloff.text", "fieldmark has invalid positions"); + // could either dispose it or leave it to end at the end of the document? + xField->dispose(); + } +} + +void XMLTextMarkImportContext::endFastElement(sal_Int32 nElement) +{ + static constexpr OUString sAPI_bookmark = u"com.sun.star.text.Bookmark"_ustr; + + lcl_MarkType nTmp{}; + if (!SvXMLUnitConverter::convertEnum(nTmp, SvXMLImport::getNameFromToken(nElement), lcl_aMarkTypeMap)) + return; + + if (m_sBookmarkName.isEmpty() && TypeFieldmarkEnd != nTmp && TypeFieldmarkSeparator != nTmp) + return; + + switch (nTmp) + { + case TypeReference: + // export point reference mark + CreateAndInsertMark(GetImport(), + "com.sun.star.text.ReferenceMark", + m_sBookmarkName, + m_rHelper.GetCursorAsRange()->getStart()); + break; + + case TypeBookmark: + { + // tdf#94804: detect duplicate heading cross reference bookmarks + if (m_sBookmarkName.startsWith("__RefHeading__")) + { + if (m_rxCrossRefHeadingBookmark.is()) + { + uno::Reference<container::XNamed> const xNamed( + m_rxCrossRefHeadingBookmark, uno::UNO_QUERY); + m_rHelper.AddCrossRefHeadingMapping( + m_sBookmarkName, xNamed->getName()); + break; // don't insert + } + } + } + [[fallthrough]]; + case TypeFieldmark: + { + const OUString formFieldmarkName=lcl_getFormFieldmarkName(m_sFieldName); + bool bImportAsField = (nTmp==TypeFieldmark && !formFieldmarkName.isEmpty()); //@TODO handle abbreviation cases... + // export point bookmark + const Reference<XInterface> xContent( + CreateAndInsertMark(GetImport(), + (bImportAsField ? OUString("com.sun.star.text.FormFieldmark") : sAPI_bookmark), + m_sBookmarkName, + m_rHelper.GetCursorAsRange()->getStart(), + m_sXmlId) ); + if (nTmp==TypeFieldmark) { + if (xContent.is() && bImportAsField) { + // setup fieldmark... + Reference< css::text::XFormField> xFormField(xContent, UNO_QUERY); + xFormField->setFieldType(formFieldmarkName); + if (xFormField.is() && m_rHelper.hasCurrentFieldCtx()) { + m_rHelper.setCurrentFieldParamsTo(xFormField); + } + } + m_rHelper.popFieldCtx(); + } + if (TypeBookmark == nTmp + && m_sBookmarkName.startsWith("__RefHeading__")) + { + assert(xContent.is()); + m_rxCrossRefHeadingBookmark = xContent; + } + } + break; + + case TypeBookmarkStart: + // save XTextRange for later construction of bookmark + { + std::shared_ptr< ::xmloff::ParsedRDFaAttributes > + xRDFaAttributes; + if (m_bHaveAbout && TypeBookmarkStart == nTmp) + { + xRDFaAttributes = + GetImport().GetRDFaImportHelper().ParseRDFa( + m_sAbout, m_sProperty, + m_sContent, m_sDatatype); + } + m_rHelper.InsertBookmarkStartRange( + m_sBookmarkName, + m_rHelper.GetCursorAsRange()->getStart(), + m_sXmlId, xRDFaAttributes); + } + break; + + case TypeBookmarkEnd: + { + // tdf#94804: detect duplicate heading cross reference bookmarks + if (m_sBookmarkName.startsWith("__RefHeading__")) + { + if (m_rxCrossRefHeadingBookmark.is()) + { + uno::Reference<container::XNamed> const xNamed( + m_rxCrossRefHeadingBookmark, uno::UNO_QUERY); + m_rHelper.AddCrossRefHeadingMapping( + m_sBookmarkName, xNamed->getName()); + break; // don't insert + } + } + + // get old range, and construct + Reference<XTextRange> xStartRange; + std::shared_ptr< ::xmloff::ParsedRDFaAttributes > + xRDFaAttributes; + if (m_rHelper.FindAndRemoveBookmarkStartRange( + m_sBookmarkName, xStartRange, + m_sXmlId, xRDFaAttributes)) + { + Reference<XTextRange> xEndRange( + m_rHelper.GetCursorAsRange()->getStart()); + + // check if beginning and end are in same XText + if (xStartRange.is() && xEndRange.is() && xStartRange->getText() == xEndRange->getText()) + { + // create range for insertion + Reference<XTextCursor> xInsertionCursor = + m_rHelper.GetText()->createTextCursorByRange( + xEndRange); + try { + xInsertionCursor->gotoRange(xStartRange, true); + } catch (uno::Exception&) { + TOOLS_WARN_EXCEPTION("xmloff.text", + "cannot go to end position of bookmark"); + } + + //DBG_ASSERT(! xInsertionCursor->isCollapsed(), + // "we want no point mark"); + // can't assert, because someone could + // create a file with subsequence + // start/end elements + + Reference<XInterface> xContent; + // insert reference + xContent = CreateAndInsertMark(GetImport(), + sAPI_bookmark, + m_sBookmarkName, + xInsertionCursor, + m_sXmlId); + if (xRDFaAttributes) + { + const Reference<rdf::XMetadatable> + xMeta(xContent, UNO_QUERY); + GetImport().GetRDFaImportHelper().AddRDFa( + xMeta, xRDFaAttributes); + } + const Reference<XPropertySet> xPropertySet(xContent, UNO_QUERY); + if (xPropertySet.is()) + { + xPropertySet->setPropertyValue("BookmarkHidden", uno::Any(m_rHelper.getBookmarkHidden(m_sBookmarkName))); + xPropertySet->setPropertyValue("BookmarkCondition", uno::Any(m_rHelper.getBookmarkCondition(m_sBookmarkName))); + } + if (m_sBookmarkName.startsWith("__RefHeading__")) + { + assert(xContent.is()); + m_rxCrossRefHeadingBookmark = xContent; + } + } + // else: beginning/end in different XText -> ignore! + } + // else: no start found -> ignore! + break; + } + case TypeFieldmarkStart: + { + break; + } + case TypeFieldmarkSeparator: + { + InsertFieldmark(GetImport(), m_rHelper, false); + break; + } + case TypeFieldmarkEnd: + { + if (m_rHelper.hasCurrentFieldCtx() && !m_rHelper.hasCurrentFieldSeparator()) + { // backward compat for old files without separator + InsertFieldmark(GetImport(), m_rHelper, true); + } + PopFieldmark(m_rHelper); + break; + } + case TypeReferenceStart: + case TypeReferenceEnd: + OSL_FAIL("reference start/end are handled in txtparai !"); + break; + + default: + OSL_FAIL("unknown mark type"); + break; + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextMarkImportContext::createFastChildContext( + sal_Int32 , + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + return new XMLFieldParamImportContext(GetImport(), m_rHelper); +} + + +Reference<XTextContent> XMLTextMarkImportContext::CreateAndInsertMark( + SvXMLImport& rImport, + const OUString& sServiceName, + const OUString& sMarkName, + const Reference<XTextRange> & rRange, + const OUString& i_rXmlId, + bool const isFieldmarkSeparatorMissing) +{ + // create mark + const Reference<XMultiServiceFactory> xFactory(rImport.GetModel(), + UNO_QUERY); + Reference<XInterface> xIfc; + + if (xFactory.is()) + { + xIfc = xFactory->createInstance(sServiceName); + + if (!xIfc.is()) + { + OSL_FAIL("CreateAndInsertMark: cannot create service?"); + return nullptr; + } + + // set name (unless there is no name (text:meta)) + const Reference<XNamed> xNamed(xIfc, UNO_QUERY); + if (xNamed.is()) + { + xNamed->setName(sMarkName); + } + else + { + if (!sMarkName.isEmpty()) + { + OSL_FAIL("name given, but XNamed not supported?"); + return nullptr; + } + } + + if (isFieldmarkSeparatorMissing) + { + uno::Reference<beans::XPropertySet> const xProps(xIfc, uno::UNO_QUERY_THROW); + xProps->setPropertyValue("PrivateSeparatorAtStart", uno::Any(true)); + } + + // cast to XTextContent and attach to document + const Reference<XTextContent> xTextContent(xIfc, UNO_QUERY); + if (xTextContent.is()) + { + try + { + // if inserting marks, bAbsorb==sal_False will cause + // collapsing of the given XTextRange. + rImport.GetTextImport()->GetText()->insertTextContent(rRange, + xTextContent, true); + + // xml:id for RDF metadata -- after insertion! + rImport.SetXmlId(xIfc, i_rXmlId); + + return xTextContent; + } + catch (css::lang::IllegalArgumentException &) + { + OSL_FAIL("CreateAndInsertMark: cannot insert?"); + return nullptr; + } + } + } + return nullptr; +} + +bool XMLTextMarkImportContext::FindName( + const Reference<XFastAttributeList> & xAttrList) +{ + bool bNameOK = false; + + // find name attribute first + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + OUString sValue = aIter.toString(); + switch(aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_NAME): + m_sBookmarkName = sValue; + bNameOK = true; + break; + case XML_ELEMENT(XML, XML_ID): + m_sXmlId = sValue; + break; + // RDFa + case XML_ELEMENT(XHTML, XML_ABOUT): + m_sAbout = sValue; + m_bHaveAbout = true; + break; + case XML_ELEMENT(XHTML, XML_PROPERTY): + m_sProperty = sValue; + break; + case XML_ELEMENT(XHTML, XML_CONTENT): + m_sContent = sValue; + break; + case XML_ELEMENT(XHTML, XML_DATATYPE): + m_sDatatype = sValue; + break; + case XML_ELEMENT(FIELD, XML_TYPE): + m_sFieldName = sValue; + break; + case XML_ELEMENT(LO_EXT, XML_HIDDEN): + ::sax::Converter::convertBool(m_isHidden, sValue); + break; + case XML_ELEMENT(LO_EXT, XML_CONDITION): + m_sCondition = sValue; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + return bNameOK; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextMarkImportContext.hxx b/xmloff/source/text/XMLTextMarkImportContext.hxx new file mode 100644 index 0000000000..da05f52408 --- /dev/null +++ b/xmloff/source/text/XMLTextMarkImportContext.hxx @@ -0,0 +1,106 @@ +/* -*- 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 <com/sun/star/uno/Reference.h> + + +namespace com::sun::star { + namespace text { + class XTextRange; + class XTextContent; + } + namespace xml::sax { + class XAttributeList; + } +} +class XMLTextImportHelper; + +class XMLFieldParamImportContext : public SvXMLImportContext +{ + XMLTextImportHelper& rHelper; +public: + XMLFieldParamImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp ); + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList) override; +}; + + +/** + * import bookmarks and reference marks + * ( <bookmark>, <bookmark-start>, <bookmark-end>, + * <reference>, <reference-start>, <reference-end> ) + * + * All elements are handled by the same class due to their similarities. + */ +class XMLTextMarkImportContext final : public SvXMLImportContext +{ +private: + XMLTextImportHelper & m_rHelper; + + css::uno::Reference<css::uno::XInterface> & m_rxCrossRefHeadingBookmark; + + OUString m_sBookmarkName; + OUString m_sFieldName; + bool m_isHidden; + OUString m_sCondition; + OUString m_sXmlId; + // RDFa + bool m_bHaveAbout; + OUString m_sAbout; + OUString m_sProperty; + OUString m_sContent; + OUString m_sDatatype; + +public: + + XMLTextMarkImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp, + css::uno::Reference<css::uno::XInterface> & io_rxCrossRefHeadingBookmark ); + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + +public: + static css::uno::Reference< css::text::XTextContent > CreateAndInsertMark( + SvXMLImport& rImport, + const OUString& sServiceName, + const OUString& sMarkName, + const css::uno::Reference<css::text::XTextRange> & rRange, + const OUString& i_rXmlId = OUString(), + bool const isFieldmarkSeparatorMissing = false); + + bool FindName( + const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextMasterPageContext.cxx b/xmloff/source/text/XMLTextMasterPageContext.cxx new file mode 100644 index 0000000000..71e5f67701 --- /dev/null +++ b/xmloff/source/text/XMLTextMasterPageContext.cxx @@ -0,0 +1,301 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/beans/XMultiPropertyStates.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <o3tl/any.hxx> +#include <sal/log.hxx> +#include <osl/diagnose.h> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/prstylei.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/XMLTextMasterPageContext.hxx> +#include <XMLTextHeaderFooterContext.hxx> +#include <PageMasterImportContext.hxx> +#include <xmloff/xmlimp.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::xmloff::token; + +Reference < XStyle > XMLTextMasterPageContext::Create() +{ + Reference < XStyle > xNewStyle; + + Reference< XMultiServiceFactory > xFactory( GetImport().GetModel(), + UNO_QUERY ); + if( xFactory.is() ) + { + Reference < XInterface > xIfc = + xFactory->createInstance("com.sun.star.style.PageStyle"); + if( xIfc.is() ) + xNewStyle.set( xIfc, UNO_QUERY ); + } + + return xNewStyle; +} + +constexpr OUString gsFollowStyle( u"FollowStyle"_ustr ); + +XMLTextMasterPageContext::XMLTextMasterPageContext( SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< XFastAttributeList > & xAttrList, + bool bOverwrite ) +: SvXMLStyleContext( rImport, XmlStyleFamily::MASTER_PAGE ) +, m_bInsertHeader( false ) +, m_bInsertFooter( false ) +, m_bInsertHeaderLeft( false ) +, m_bInsertFooterLeft( false ) +, m_bInsertHeaderFirst( false ) +, m_bInsertFooterFirst( false ) +, m_bHeaderInserted( false ) +, m_bFooterInserted( false ) +{ + OUString sName, sDisplayName; + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + const OUString aValue = aIter.toString(); + switch (aIter.getToken()) + { + case XML_ELEMENT(STYLE, XML_NAME): + sName = aValue; + break; + case XML_ELEMENT(STYLE, XML_DISPLAY_NAME): + sDisplayName = aValue; + break; + case XML_ELEMENT(STYLE, XML_NEXT_STYLE_NAME): + m_sFollow = aValue; + break; + case XML_ELEMENT(STYLE, XML_PAGE_LAYOUT_NAME): + m_sPageMasterName = aValue; + break; + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + m_sDrawingPageStyle = aValue; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( !sDisplayName.isEmpty() ) + { + rImport.AddStyleDisplayName( XmlStyleFamily::MASTER_PAGE, sName, + sDisplayName ); + } + else + { + sDisplayName = sName; + } + + if( sDisplayName.isEmpty() ) + return; + + Reference < XNameContainer > xPageStyles = + GetImport().GetTextImport()->GetPageStyles(); + if( !xPageStyles.is() ) + return; + + Any aAny; + bool bNew = false; + if( xPageStyles->hasByName( sDisplayName ) ) + { + aAny = xPageStyles->getByName( sDisplayName ); + aAny >>= m_xStyle; + } + else + { + m_xStyle = Create(); + if( !m_xStyle.is() ) + return; + + xPageStyles->insertByName( sDisplayName, Any(m_xStyle) ); + bNew = true; + } + + Reference < XPropertySet > xPropSet( m_xStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + OUString sIsPhysical( "IsPhysical" ); + if( !bNew && xPropSetInfo->hasPropertyByName( sIsPhysical ) ) + { + aAny = xPropSet->getPropertyValue( sIsPhysical ); + bNew = !*o3tl::doAccess<bool>(aAny); + } + SetNew( bNew ); + + if( !(bOverwrite || bNew) ) + return; + + Reference < XMultiPropertyStates > xMultiStates( xPropSet, + UNO_QUERY ); + OSL_ENSURE( xMultiStates.is(), + "text page style does not support multi property set" ); + if( xMultiStates.is() ) + xMultiStates->setAllPropertiesToDefault(); + + if ( xPropSetInfo->hasPropertyByName( "GridDisplay" ) ) + xPropSet->setPropertyValue( "GridDisplay", Any(false) ); + + if ( xPropSetInfo->hasPropertyByName( "GridPrint" ) ) + xPropSet->setPropertyValue( "GridPrint", Any(false) ); + + m_bInsertHeader = m_bInsertFooter = true; + m_bInsertHeaderLeft = m_bInsertFooterLeft = true; + m_bInsertHeaderFirst = m_bInsertFooterFirst = true; +} + +XMLTextMasterPageContext::~XMLTextMasterPageContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextMasterPageContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContextRef xContext; + + bool bInsert = false, bFooter = false, bLeft = false, bFirst = false; + switch( nElement ) + { + case XML_ELEMENT(STYLE, XML_HEADER): + if( m_bInsertHeader && !m_bHeaderInserted ) + { + bInsert = true; + m_bHeaderInserted = true; + } + break; + case XML_ELEMENT(STYLE, XML_FOOTER): + if( m_bInsertFooter && !m_bFooterInserted ) + { + bInsert = bFooter = true; + m_bFooterInserted = true; + } + break; + case XML_ELEMENT(STYLE, XML_HEADER_LEFT): + if( m_bInsertHeaderLeft && m_bHeaderInserted ) + bInsert = bLeft = true; + break; + case XML_ELEMENT(STYLE, XML_FOOTER_LEFT): + if( m_bInsertFooterLeft && m_bFooterInserted ) + bInsert = bFooter = bLeft = true; + break; + case XML_ELEMENT(LO_EXT, XML_HEADER_FIRST): + case XML_ELEMENT(STYLE, XML_HEADER_FIRST): + if( m_bInsertHeaderFirst && m_bHeaderInserted ) + bInsert = bFirst = true; + break; + case XML_ELEMENT(LO_EXT, XML_FOOTER_FIRST): + case XML_ELEMENT(STYLE, XML_FOOTER_FIRST): + if( m_bInsertFooterFirst && m_bFooterInserted ) + bInsert = bFooter = bFirst = true; + break; + } + + if( bInsert && m_xStyle.is() ) + { + xContext = CreateHeaderFooterContext( nElement, xAttrList, + bFooter, bLeft, bFirst ); + } + + return xContext; +} + +SvXMLImportContext *XMLTextMasterPageContext::CreateHeaderFooterContext( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*xAttrList*/, + const bool bFooter, + const bool bLeft, + const bool bFirst ) +{ + Reference < XPropertySet > xPropSet( m_xStyle, UNO_QUERY ); + return new XMLTextHeaderFooterContext( GetImport(), xPropSet, bFooter, bLeft, bFirst ); +} + +void XMLTextMasterPageContext::Finish( bool bOverwrite ) +{ + if( !(m_xStyle.is() && (IsNew() || bOverwrite)) ) + return; + + Reference < XPropertySet > xPropSet( m_xStyle, UNO_QUERY ); + XMLPropStyleContext * pDrawingPageStyle(nullptr); + if (!m_sDrawingPageStyle.isEmpty()) + { + pDrawingPageStyle = GetImport().GetTextImport()->FindDrawingPage(m_sDrawingPageStyle); + } + PageStyleContext * pPageLayout(nullptr); + if( !m_sPageMasterName.isEmpty() ) + { + pPageLayout = static_cast<PageStyleContext *>(GetImport().GetTextImport()->FindPageMaster(m_sPageMasterName)); + } + if (pPageLayout) + { + pPageLayout->FillPropertySet_PageStyle(xPropSet, pDrawingPageStyle); + } + else if (pDrawingPageStyle) + { + // don't need to care about old background attributes in this case + pDrawingPageStyle->FillPropertySet(xPropSet); + } + + Reference < XNameContainer > xPageStyles = + GetImport().GetTextImport()->GetPageStyles(); + if( !xPageStyles.is() ) + return; + + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + if( xPropSetInfo->hasPropertyByName( gsFollowStyle ) ) + { + OUString sDisplayFollow( + GetImport().GetStyleDisplayName( + XmlStyleFamily::MASTER_PAGE, m_sFollow ) ); + if( sDisplayFollow.isEmpty() || + !xPageStyles->hasByName( sDisplayFollow ) ) + sDisplayFollow = m_xStyle->getName(); + + Any aAny = xPropSet->getPropertyValue( gsFollowStyle ); + OUString sCurrFollow; + aAny >>= sCurrFollow; + if( sCurrFollow != sDisplayFollow ) + { + xPropSet->setPropertyValue( gsFollowStyle, Any(sDisplayFollow) ); + } + } + + if ( xPropSetInfo->hasPropertyByName( "Hidden" ) ) + { + xPropSet->setPropertyValue( "Hidden", uno::Any( IsHidden( ) ) ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextMasterPageExport.cxx b/xmloff/source/text/XMLTextMasterPageExport.cxx new file mode 100644 index 0000000000..7be7be7aff --- /dev/null +++ b/xmloff/source/text/XMLTextMasterPageExport.cxx @@ -0,0 +1,237 @@ +/* -*- 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/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <xmloff/xmlexp.hxx> +#include <xmloff/XMLTextMasterPageExport.hxx> +#include <sal/log.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + +constexpr OUStringLiteral gsHeaderText( u"HeaderText" ); +constexpr OUStringLiteral gsHeaderOn( u"HeaderIsOn" ); +constexpr OUStringLiteral gsHeaderShareContent( u"HeaderIsShared" ); +constexpr OUStringLiteral gsHeaderTextFirst( u"HeaderTextFirst" ); +constexpr OUStringLiteral gsHeaderTextLeft( u"HeaderTextLeft" ); +constexpr OUString gsFirstShareContent( u"FirstIsShared"_ustr ); +constexpr OUStringLiteral gsFooterText( u"FooterText" ); +constexpr OUStringLiteral gsFooterOn( u"FooterIsOn" ); +constexpr OUStringLiteral gsFooterShareContent( u"FooterIsShared" ); +constexpr OUStringLiteral gsFooterTextFirst( u"FooterTextFirst" ); +constexpr OUStringLiteral gsFooterTextLeft( u"FooterTextLeft" ); + +XMLTextMasterPageExport::XMLTextMasterPageExport( SvXMLExport& rExp ) : + XMLPageExport( rExp ) +{ +} + +XMLTextMasterPageExport::~XMLTextMasterPageExport() +{ +} + + +void XMLTextMasterPageExport::exportHeaderFooterContent( + const Reference< XText >& rText, + bool bAutoStyles, bool bExportParagraph ) +{ + SAL_WARN_IF( !rText.is(), "xmloff", "There is the text" ); + + // tracked changes (autostyles + changes list) + GetExport().GetTextParagraphExport()->recordTrackedChangesForXText(rText); + GetExport().GetTextParagraphExport()->exportTrackedChanges(rText, + bAutoStyles); + if( bAutoStyles ) + GetExport().GetTextParagraphExport() + ->collectTextAutoStyles( rText, true, bExportParagraph ); + else + { + GetExport().GetTextParagraphExport()->exportTextDeclarations( rText ); + GetExport().GetTextParagraphExport()->exportText( rText, true, bExportParagraph ); + } + + // tracked changes (end of XText) + GetExport().GetTextParagraphExport()->recordTrackedChangesNoXText(); +} + +void XMLTextMasterPageExport::exportMasterPageContent( + const Reference < XPropertySet > & rPropSet, + bool bAutoStyles ) +{ + Any aAny; + + Reference < XText > xHeaderText; + aAny = rPropSet->getPropertyValue( gsHeaderText ); + aAny >>= xHeaderText; + + Reference < XText > xHeaderTextFirst; + aAny = rPropSet->getPropertyValue( gsHeaderTextFirst ); + aAny >>= xHeaderTextFirst; + + Reference < XText > xHeaderTextLeft; + aAny = rPropSet->getPropertyValue( gsHeaderTextLeft ); + aAny >>= xHeaderTextLeft; + + Reference < XText > xFooterText; + aAny = rPropSet->getPropertyValue( gsFooterText ); + aAny >>= xFooterText; + + Reference < XText > xFooterTextFirst; + aAny = rPropSet->getPropertyValue( gsFooterTextFirst ); + aAny >>= xFooterTextFirst; + + Reference < XText > xFooterTextLeft; + aAny = rPropSet->getPropertyValue( gsFooterTextLeft ); + aAny >>= xFooterTextLeft; + + if( bAutoStyles ) + { + if( xHeaderText.is() ) + exportHeaderFooterContent( xHeaderText, true ); + if( xHeaderTextFirst.is() && xHeaderTextFirst != xHeaderText ) + exportHeaderFooterContent( xHeaderTextFirst, true ); + if( xHeaderTextLeft.is() && xHeaderTextLeft != xHeaderText ) + exportHeaderFooterContent( xHeaderTextLeft, true ); + if( xFooterText.is() ) + exportHeaderFooterContent( xFooterText, true ); + if( xFooterTextFirst.is() && xFooterTextFirst != xFooterText ) + exportHeaderFooterContent( xFooterTextFirst, true ); + if( xFooterTextLeft.is() && xFooterTextLeft != xFooterText ) + exportHeaderFooterContent( xFooterTextLeft, true ); + } + else + { + auto const nVersion(GetExport().getSaneDefaultVersion()); + + aAny = rPropSet->getPropertyValue( gsHeaderOn ); + bool bHeader = false; + aAny >>= bHeader; + + bool bHeaderFirstShared = false; + if( bHeader ) + { + aAny = rPropSet->getPropertyValue( gsFirstShareContent ); + aAny >>= bHeaderFirstShared; + } + + bool bHeaderLeftShared = false; + if( bHeader ) + { + aAny = rPropSet->getPropertyValue( gsHeaderShareContent ); + aAny >>= bHeaderLeftShared; + } + + if( xHeaderText.is() ) + { + if( !bHeader ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DISPLAY, XML_FALSE ); + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, + XML_HEADER, true, true ); + exportHeaderFooterContent( xHeaderText, false ); + } + + if( xHeaderTextLeft.is() && xHeaderTextLeft != xHeaderText ) + { + if (bHeaderLeftShared) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DISPLAY, XML_FALSE ); + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, + XML_HEADER_LEFT, true, true ); + exportHeaderFooterContent( xHeaderTextLeft, false ); + } + + if (xHeaderTextFirst.is() && xHeaderTextFirst != xHeaderText + && SvtSaveOptions::ODFSVER_012 < nVersion) + { + if (bHeaderFirstShared) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DISPLAY, XML_FALSE ); + // ODF 1.3 OFFICE-3789 + SvXMLElementExport aElem( GetExport(), + SvtSaveOptions::ODFSVER_013 <= nVersion + ? XML_NAMESPACE_STYLE + : XML_NAMESPACE_LO_EXT, + XML_HEADER_FIRST, true, true ); + exportHeaderFooterContent( xHeaderTextFirst, false ); + } + + aAny = rPropSet->getPropertyValue( gsFooterOn ); + bool bFooter = false; + aAny >>= bFooter; + + bool bFooterFirstShared = false; + if( bFooter ) + { + aAny = rPropSet->getPropertyValue( gsFirstShareContent ); + aAny >>= bFooterFirstShared; + } + + bool bFooterLeftShared = false; + if( bFooter ) + { + aAny = rPropSet->getPropertyValue( gsFooterShareContent ); + aAny >>= bFooterLeftShared; + } + + if( xFooterText.is() ) + { + if( !bFooter ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DISPLAY, XML_FALSE ); + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, + XML_FOOTER, true, true ); + exportHeaderFooterContent( xFooterText, false ); + } + + if( xFooterTextLeft.is() && xFooterTextLeft != xFooterText ) + { + if (bFooterLeftShared) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DISPLAY, XML_FALSE ); + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, + XML_FOOTER_LEFT, true, true ); + exportHeaderFooterContent( xFooterTextLeft, false ); + } + + if (xFooterTextFirst.is() && xFooterTextFirst != xFooterText + && SvtSaveOptions::ODFSVER_012 < nVersion) + { + if (bFooterFirstShared) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DISPLAY, XML_FALSE ); + // ODF 1.3 OFFICE-3789 + SvXMLElementExport aElem( GetExport(), + SvtSaveOptions::ODFSVER_013 <= nVersion + ? XML_NAMESPACE_STYLE + : XML_NAMESPACE_LO_EXT, + XML_FOOTER_FIRST, true, true ); + exportHeaderFooterContent( xFooterTextFirst, false ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextMasterStylesContext.cxx b/xmloff/source/text/XMLTextMasterStylesContext.cxx new file mode 100644 index 0000000000..608cc63077 --- /dev/null +++ b/xmloff/source/text/XMLTextMasterStylesContext.cxx @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> + +#include <xmloff/XMLTextMasterPageContext.hxx> +#include <xmloff/XMLTextMasterStylesContext.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; + +using ::xmloff::token::XML_MASTER_PAGE; + + +bool XMLTextMasterStylesContext::InsertStyleFamily( XmlStyleFamily ) const +{ + return true; +} + +XMLTextMasterStylesContext::XMLTextMasterStylesContext( + SvXMLImport& rImport ) : + SvXMLStylesContext( rImport ) +{ +} + +XMLTextMasterStylesContext::~XMLTextMasterStylesContext() +{ +} + +SvXMLStyleContext *XMLTextMasterStylesContext::CreateStyleChildContext( + sal_Int32 nElement, + const Reference< XFastAttributeList > & xAttrList ) +{ + SvXMLStyleContext *pContext = nullptr; + + if( nElement == XML_ELEMENT(STYLE, XML_MASTER_PAGE) && + InsertStyleFamily( XmlStyleFamily::MASTER_PAGE ) ) + pContext = new XMLTextMasterPageContext( + GetImport(), nElement, + xAttrList, + !GetImport().GetTextImport()->IsInsertMode() ); + + // any other style will be ignored here! + + return pContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextNumRuleInfo.cxx b/xmloff/source/text/XMLTextNumRuleInfo.cxx new file mode 100644 index 0000000000..5f9a5e2b7a --- /dev/null +++ b/xmloff/source/text/XMLTextNumRuleInfo.cxx @@ -0,0 +1,222 @@ +/* -*- 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 <osl/diagnose.h> +#include <sal/log.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/style/NumberingType.hpp> +#include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include "XMLTextNumRuleInfo.hxx" +#include <xmloff/XMLTextListAutoStylePool.hxx> + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::style; + +// Complete refactoring of the class and enhancement of the class for lists. +XMLTextNumRuleInfo::XMLTextNumRuleInfo() + : mbListIdIsDefault(false) + , mnListStartValue( -1 ) + , mnListLevel( 0 ) + , mbIsNumbered( false ) + , mbIsRestart( false ) + , mnListLevelStartValue( -1 ) + , mbOutlineStyleAsNormalListStyle( false ) +{ + Reset(); +} + +// Written OpenDocument file format doesn't fit to the created text document (#i69627#) +void XMLTextNumRuleInfo::Set( + const css::uno::Reference < css::text::XTextContent > & xTextContent, + const bool bOutlineStyleAsNormalListStyle, + const XMLTextListAutoStylePool& rListAutoPool, + const bool bExportTextNumberElement, + const bool bListIdIsDefault ) +{ + Reset(); + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + mbOutlineStyleAsNormalListStyle = bOutlineStyleAsNormalListStyle; + + Reference< XPropertySet > xPropSet( xTextContent, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo(); + + // check if this paragraph supports a numbering + if( !xPropSetInfo->hasPropertyByName( "NumberingLevel" ) ) + return; + + if( xPropSet->getPropertyValue( "NumberingLevel" ) >>= mnListLevel ) + { + if( xPropSetInfo->hasPropertyByName( "NumberingRules" ) ) + { + xPropSet->getPropertyValue( "NumberingRules" ) >>= mxNumRules; + } + } + else + { + // in applications using the outliner we always have a numbering rule, + // so a void property no numbering + mnListLevel = 0; + } + + // Assertion saving writer document (#i97312#) + if ( mxNumRules.is() && mxNumRules->getCount() < 1 ) + { + SAL_WARN("xmloff", + "<XMLTextNumRuleInfo::Set(..)> - numbering rules instance does not contain any numbering rule" ); + Reset(); + return; + } + + if ( mnListLevel < 0 ) + { + SAL_WARN("xmloff", + "<XMLTextNumRuleInfo::Set(..)> - unexpected numbering level" ); + Reset(); + return; + } + + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + bool bSuppressListStyle( false ); + if ( mxNumRules.is() ) + { + if ( !mbOutlineStyleAsNormalListStyle ) + { + Reference<XPropertySet> xNumRulesProps(mxNumRules, UNO_QUERY); + if ( xNumRulesProps.is() && + xNumRulesProps->getPropertySetInfo()-> + hasPropertyByName( "NumberingIsOutline" ) ) + { + bool bIsOutline = false; + xNumRulesProps->getPropertyValue( "NumberingIsOutline" ) >>= bIsOutline; + bSuppressListStyle = bIsOutline; + } + } + } + + if( mxNumRules.is() && !bSuppressListStyle ) + { + // First try to find the numbering rules in the list auto style pool. + // If not found, the numbering rules instance has to be named. + msNumRulesName = rListAutoPool.Find( mxNumRules ); + if ( msNumRulesName.isEmpty() ) + { + Reference < XNamed > xNamed( mxNumRules, UNO_QUERY ); + SAL_WARN_IF( !xNamed.is(), "xmloff", + "<XMLTextNumRuleInfo::Set(..)> - numbering rules instance have to be named. Serious defect." ); + if( xNamed.is() ) + { + msNumRulesName = xNamed->getName(); + } + } + SAL_WARN_IF( msNumRulesName.isEmpty(), "xmloff", + "<XMLTextNumRuleInfo::Set(..)> - no name found for numbering rules instance. Serious defect." ); + + if( xPropSetInfo->hasPropertyByName( "ListId" ) ) + { + xPropSet->getPropertyValue( "ListId" ) >>= msListId; + } + + mbListIdIsDefault = bListIdIsDefault; + + mbContinueingPreviousSubTree = false; + if( xPropSetInfo->hasPropertyByName( "ContinueingPreviousSubTree" ) ) + { + xPropSet->getPropertyValue( "ContinueingPreviousSubTree" ) >>= mbContinueingPreviousSubTree; + } + + mbIsNumbered = true; + if( xPropSetInfo->hasPropertyByName( "NumberingIsNumber" ) ) + { + if( !(xPropSet->getPropertyValue( "NumberingIsNumber" ) >>= mbIsNumbered ) ) + { + OSL_FAIL( "numbered paragraph without number info" ); + mbIsNumbered = false; + } + } + + if( mbIsNumbered ) + { + if( xPropSetInfo->hasPropertyByName( "ParaIsNumberingRestart" ) ) + { + xPropSet->getPropertyValue( "ParaIsNumberingRestart" ) >>= mbIsRestart; + } + if( xPropSetInfo->hasPropertyByName( "NumberingStartValue" ) ) + { + xPropSet->getPropertyValue( "NumberingStartValue" ) >>= mnListStartValue; + } + } + + OSL_ENSURE( mnListLevel < mxNumRules->getCount(), "wrong num rule level" ); + if( mnListLevel >= mxNumRules->getCount() ) + { + Reset(); + return; + } + + Sequence<PropertyValue> aProps; + mxNumRules->getByIndex( mnListLevel ) >>= aProps; + + auto pProp = std::find_if(std::cbegin(aProps), std::cend(aProps), + [](const PropertyValue& rProp) { return rProp.Name == "StartWith"; }); + if (pProp != std::cend(aProps)) + { + pProp->Value >>= mnListLevelStartValue; + } + + msListLabelString.clear(); + if ( bExportTextNumberElement && + xPropSetInfo->hasPropertyByName( "ListLabelString" ) ) + { + xPropSet->getPropertyValue( "ListLabelString" ) >>= msListLabelString; + } + + // paragraph's list level range is [0..9] representing list levels [1..10] + ++mnListLevel; + } + else + { + mnListLevel = 0; + } +} + +bool XMLTextNumRuleInfo::BelongsToSameList( const XMLTextNumRuleInfo& rCmp ) const +{ + bool bRet( true ); + // Currently only the text documents support <ListId>. + if ( !rCmp.msListId.isEmpty() || !msListId.isEmpty() ) + { + bRet = rCmp.msListId == msListId; + } + else + { + bRet = rCmp.msNumRulesName == msNumRulesName; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextNumRuleInfo.hxx b/xmloff/source/text/XMLTextNumRuleInfo.hxx new file mode 100644 index 0000000000..7cbc3cf8d4 --- /dev/null +++ b/xmloff/source/text/XMLTextNumRuleInfo.hxx @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <sal/types.h> + +namespace com::sun::star { + namespace text { class XTextContent; } +} + +class XMLTextListAutoStylePool; + +/** information about list and list style for a certain paragraph + + OD 2008-04-24 #refactorlists# + Complete refactoring of the class and enhancement of the class for lists. + These changes are considered by method <XMLTextParagraphExport::exportListChange(..)> +*/ +class XMLTextNumRuleInfo +{ + // numbering rules instance and its name + css::uno::Reference < css::container::XIndexReplace > mxNumRules; + OUString msNumRulesName; + + // paragraph's list attributes + OUString msListId; + /// msListId won't be referenced by later lists. + bool mbListIdIsDefault; + sal_Int16 mnListStartValue; + sal_Int16 mnListLevel; + bool mbIsNumbered; + bool mbIsRestart; + + // numbering rules' attributes + sal_Int16 mnListLevelStartValue; + + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + bool mbOutlineStyleAsNormalListStyle; + + bool mbContinueingPreviousSubTree; + OUString msListLabelString; + +public: + + XMLTextNumRuleInfo(); + + inline XMLTextNumRuleInfo& operator=( const XMLTextNumRuleInfo& rInfo ); + + void Set( const css::uno::Reference < css::text::XTextContent > & rTextContent, + bool bOutlineStyleAsNormalListStyle, + const XMLTextListAutoStylePool& rListAutoPool, + bool bExportTextNumberElement, + bool bListIdIsDefault ); + inline void Reset(); + + const OUString& GetNumRulesName() const + { + return msNumRulesName; + } + sal_Int16 GetListLevelStartValue() const + { + return mnListLevelStartValue; + } + + const OUString& GetListId() const + { + return msListId; + } + + bool IsListIdDefault() const { return mbListIdIsDefault; } + + sal_Int16 GetLevel() const + { + return mnListLevel; + } + + bool HasStartValue() const + { + return mnListStartValue != -1; + } + sal_uInt32 GetStartValue() const + { + return mnListStartValue; + } + + bool IsNumbered() const + { + return mbIsNumbered; + } + bool IsRestart() const + { + return mbIsRestart; + } + + bool BelongsToSameList( const XMLTextNumRuleInfo& rCmp ) const; + + bool IsContinueingPreviousSubTree() const + { + return mbContinueingPreviousSubTree; + } + const OUString& ListLabelString() const + { + return msListLabelString; + } +}; + +inline XMLTextNumRuleInfo& XMLTextNumRuleInfo::operator=( + const XMLTextNumRuleInfo& rInfo ) +{ + msNumRulesName = rInfo.msNumRulesName; + mxNumRules = rInfo.mxNumRules; + msListId = rInfo.msListId; + mnListStartValue = rInfo.mnListStartValue; + mnListLevel = rInfo.mnListLevel; + mbIsNumbered = rInfo.mbIsNumbered; + mbIsRestart = rInfo.mbIsRestart; + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + mbOutlineStyleAsNormalListStyle = rInfo.mbOutlineStyleAsNormalListStyle; + mbContinueingPreviousSubTree = rInfo.mbContinueingPreviousSubTree; + msListLabelString = rInfo.msListLabelString; + + return *this; +} + +inline void XMLTextNumRuleInfo::Reset() +{ + mxNumRules = nullptr; + msNumRulesName.clear(); + msListId.clear(); + mnListStartValue = -1; + mnListLevel = 0; + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + mbIsNumbered = mbIsRestart = + mbOutlineStyleAsNormalListStyle = false; + mbContinueingPreviousSubTree = false; + msListLabelString.clear(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextPropertySetContext.cxx b/xmloff/source/text/XMLTextPropertySetContext.cxx new file mode 100644 index 0000000000..472001287e --- /dev/null +++ b/xmloff/source/text/XMLTextPropertySetContext.cxx @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <tools/debug.hxx> +#include "XMLTextPropertySetContext.hxx" +#include <XMLTextColumnsContext.hxx> +#include <xmloff/XMLComplexColorContext.hxx> +#include <XMLBackgroundImageContext.hxx> +#include "XMLSectionFootnoteConfigImport.hxx" + +#include <xmloff/xmlimppr.hxx> +#include <xmloff/txtprmap.hxx> +#include <xmltabi.hxx> +#include "txtdropi.hxx" + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + +XMLTextPropertySetContext::XMLTextPropertySetContext( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + sal_uInt32 nFamily, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap, + OUString& rDCTextStyleName ) : + SvXMLPropertySetContext( rImport, nElement, xAttrList, nFamily, + rProps, rMap ), + rDropCapTextStyleName( rDCTextStyleName ) +{ +} + +XMLTextPropertySetContext::~XMLTextPropertySetContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextPropertySetContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) +{ + switch( mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex ) ) + { + case CTF_TABSTOP: + return new SvxXMLTabStopImportContext( GetImport(), nElement, + rProp, + rProperties ); + break; + case CTF_TEXTCOLUMNS: + return new XMLTextColumnsContext( GetImport(), nElement, + xAttrList, rProp, + rProperties ); + break; + + case CTF_COMPLEX_COLOR: + return new XMLPropertyComplexColorContext(GetImport(), nElement, xAttrList, rProp, rProperties); + break; + + case CTF_DROPCAPFORMAT: + { + DBG_ASSERT( rProp.mnIndex >= 2 && + CTF_DROPCAPWHOLEWORD == mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex-2 ), + "invalid property map!"); + XMLTextDropCapImportContext *pDCContext = + new XMLTextDropCapImportContext( GetImport(), nElement, + xAttrList, + rProp, + rProp.mnIndex-2, + rProperties ); + rDropCapTextStyleName = pDCContext->GetStyleName(); + return pDCContext; + } + break; + + case CTF_BACKGROUND_URL: + { + DBG_ASSERT( rProp.mnIndex >= 2 && + CTF_BACKGROUND_POS == mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex-2 ) && + CTF_BACKGROUND_FILTER == mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex-1 ), + "invalid property map!"); + + // #99657# Transparency might be there as well... but doesn't have + // to. Thus, this is checked with an if, rather than with an assertion. + sal_Int32 nTranspIndex = -1; + if( (rProp.mnIndex >= 3) && + ( CTF_BACKGROUND_TRANSPARENCY == + mxMapper->getPropertySetMapper()->GetEntryContextId( + rProp.mnIndex-3 ) ) ) + nTranspIndex = rProp.mnIndex-3; + + return + new XMLBackgroundImageContext( GetImport(), nElement, + xAttrList, + rProp, + rProp.mnIndex-2, + rProp.mnIndex-1, + nTranspIndex, + -1, + rProperties ); + } + break; + case CTF_SECTION_FOOTNOTE_END: + case CTF_SECTION_ENDNOTE_END: + return new XMLSectionFootnoteConfigImport( + GetImport(), nElement, rProperties, + mxMapper->getPropertySetMapper()); + break; + } + + return SvXMLPropertySetContext::createFastChildContext( nElement, + xAttrList, + rProperties, rProp ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextPropertySetContext.hxx b/xmloff/source/text/XMLTextPropertySetContext.hxx new file mode 100644 index 0000000000..2286e773ff --- /dev/null +++ b/xmloff/source/text/XMLTextPropertySetContext.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <xmloff/xmlprcon.hxx> + + +class XMLTextPropertySetContext : public SvXMLPropertySetContext +{ +// SvXMLImportContextRef xTabStop; +// SvXMLImportContextRef xBackground; +// SvXMLImportContextRef xDropCap; + OUString& rDropCapTextStyleName; + +public: + XMLTextPropertySetContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList >& xAttrList, + sal_uInt32 nFamily, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap, + OUString& rDopCapTextStyleName ); + + virtual ~XMLTextPropertySetContext() override; + + using SvXMLPropertySetContext::createFastChildContext; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) override; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextShapeImportHelper.cxx b/xmloff/source/text/XMLTextShapeImportHelper.cxx new file mode 100644 index 0000000000..aba039095a --- /dev/null +++ b/xmloff/source/text/XMLTextShapeImportHelper.cxx @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> + +#include <sax/tools/converter.hxx> + +#include <xmloff/xmlimp.hxx> +#include <xmloff/txtimp.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include "XMLAnchorTypePropHdl.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <xmloff/XMLTextShapeImportHelper.hxx> + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +constexpr OUStringLiteral gsAnchorType(u"AnchorType"); +constexpr OUStringLiteral gsAnchorPageNo(u"AnchorPageNo"); +constexpr OUStringLiteral gsVertOrientPosition(u"VertOrientPosition"); + +XMLTextShapeImportHelper::XMLTextShapeImportHelper( + SvXMLImport& rImp ) : + XMLShapeImportHelper( rImp, rImp.GetModel(), + XMLTextImportHelper::CreateShapeExtPropMapper(rImp) ), + m_rImport( rImp ) +{ + Reference < XDrawPageSupplier > xDPS( rImp.GetModel(), UNO_QUERY ); + if( xDPS.is() ) + { + Reference < XShapes > xShapes = xDPS->getDrawPage(); + pushGroupForPostProcessing( xShapes ); + } + +} + +XMLTextShapeImportHelper::~XMLTextShapeImportHelper() +{ + popGroupAndPostProcess(); +} + +void XMLTextShapeImportHelper::addShape( + Reference< XShape >& rShape, + const Reference< XFastAttributeList >& xAttrList, + Reference< XShapes >& rShapes ) +{ + if( rShapes.is() ) + { + // It's a group shape or 3DScene , so we have to call the base class method. + XMLShapeImportHelper::addShape( rShape, xAttrList, rShapes ); + return; + } + + TextContentAnchorType eAnchorType = TextContentAnchorType_AT_PARAGRAPH; + sal_Int16 nPage = 0; + sal_Int32 nY = 0; + + rtl::Reference < XMLTextImportHelper > xTxtImport = + m_rImport.GetTextImport(); + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(TEXT, XML_ANCHOR_TYPE): + { + TextContentAnchorType eNew; + // OD 2004-06-01 #i26791# - allow all anchor types + if ( XMLAnchorTypePropHdl::convert( aIter.toView(), eNew ) ) + { + eAnchorType = eNew; + } + } + break; + case XML_ELEMENT(TEXT, XML_ANCHOR_PAGE_NUMBER): + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber(nTmp, aIter.toView(), 1, SHRT_MAX)) + nPage = static_cast<sal_Int16>(nTmp); + } + break; + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + m_rImport.GetMM100UnitConverter().convertMeasureToCore( nY, aIter.toView() ); + break; + } + } + + Reference < XPropertySet > xPropSet( rShape, UNO_QUERY ); + + // anchor type + xPropSet->setPropertyValue( gsAnchorType, Any(eAnchorType) ); + + // page number must be set before the frame is inserted + switch( eAnchorType ) + { + case TextContentAnchorType_AT_PAGE: + // only set positive page numbers + if ( nPage > 0 ) + { + xPropSet->setPropertyValue( gsAnchorPageNo, Any(nPage) ); + } + break; + default: + break; + } + + Reference < XTextContent > xTxtCntnt( rShape, UNO_QUERY ); + xTxtImport->InsertTextContent( xTxtCntnt ); + + switch( eAnchorType ) + { + case TextContentAnchorType_AS_CHARACTER: + xPropSet->setPropertyValue( gsVertOrientPosition, Any(nY) ); + break; + default: + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextShapeStyleContext.cxx b/xmloff/source/text/XMLTextShapeStyleContext.cxx new file mode 100644 index 0000000000..5ce5fafe4f --- /dev/null +++ b/xmloff/source/text/XMLTextShapeStyleContext.cxx @@ -0,0 +1,219 @@ +/* -*- 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 <tools/debug.hxx> +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/XMLEventsImportContext.hxx> +#include <XMLShapePropertySetContext.hxx> +#include <XMLTextColumnsContext.hxx> +#include <XMLBackgroundImageContext.hxx> +#include <xmloff/XMLComplexColorContext.hxx> +#include <xmloff/txtprmap.hxx> +#include <xmloff/xmltypes.hxx> +#include <xmloff/maptype.hxx> +#include <xmloff/xmlimppr.hxx> + +#include <xmloff/XMLTextShapeStyleContext.hxx> + +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + +namespace { + +class XMLTextShapePropertySetContext_Impl : public XMLShapePropertySetContext +{ +public: + XMLTextShapePropertySetContext_Impl( SvXMLImport& rImport, sal_Int32 nElement, + const Reference< XFastAttributeList >& xAttrList, + sal_uInt32 nFamily, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap ); + + using SvXMLPropertySetContext::createFastChildContext; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) override; +}; + +} + +XMLTextShapePropertySetContext_Impl::XMLTextShapePropertySetContext_Impl( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< XFastAttributeList > & xAttrList, + sal_uInt32 nFamily, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap ) : + XMLShapePropertySetContext( rImport, nElement, xAttrList, nFamily, + rProps, rMap ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextShapePropertySetContext_Impl::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) +{ + switch( mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex ) ) + { + case CTF_TEXTCOLUMNS: + return new XMLTextColumnsContext( GetImport(), nElement, + xAttrList, rProp, + rProperties ); + break; + + case CTF_COMPLEX_COLOR: + return new XMLPropertyComplexColorContext(GetImport(), nElement, xAttrList, rProp, rProperties); + + case CTF_BACKGROUND_URL: + DBG_ASSERT( rProp.mnIndex >= 3 && + CTF_BACKGROUND_TRANSPARENCY == + mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex-3 ) && + CTF_BACKGROUND_POS == mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex-2 ) && + CTF_BACKGROUND_FILTER == mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex-1 ), + "invalid property map!"); + return + new XMLBackgroundImageContext( GetImport(), nElement, + xAttrList, + rProp, + rProp.mnIndex-2, + rProp.mnIndex-1, + rProp.mnIndex-3, + -1, + rProperties ); + break; + } + + return XMLShapePropertySetContext::createFastChildContext( + nElement, xAttrList, rProperties, rProp ); +} + +void XMLTextShapeStyleContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_AUTO_UPDATE) ) + { + if( IsXMLToken( rValue, XML_TRUE ) ) + m_bAutoUpdate = true; + } + else + { + XMLShapeStyleContext::SetAttribute( nElement, rValue ); + } +} + + +constexpr OUString gsIsAutoUpdate( u"IsAutoUpdate"_ustr ); + +XMLTextShapeStyleContext::XMLTextShapeStyleContext( SvXMLImport& rImport, + SvXMLStylesContext& rStyles, XmlStyleFamily nFamily ) : + XMLShapeStyleContext( rImport, rStyles, nFamily ), + m_bAutoUpdate( false ) +{ +} + +XMLTextShapeStyleContext::~XMLTextShapeStyleContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextShapeStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( IsTokenInNamespace(nElement, XML_NAMESPACE_STYLE) || + IsTokenInNamespace(nElement, XML_NAMESPACE_LO_EXT) ) + { + sal_Int32 nLocalName = nElement & TOKEN_MASK; + sal_uInt32 nFamily = 0; + if( nLocalName == XML_TEXT_PROPERTIES ) + nFamily = XML_TYPE_PROP_TEXT; + else if( nLocalName == XML_PARAGRAPH_PROPERTIES ) + nFamily = XML_TYPE_PROP_PARAGRAPH; + else if( nLocalName == XML_GRAPHIC_PROPERTIES ) + nFamily = XML_TYPE_PROP_GRAPHIC; + if( nFamily ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + { + return new XMLTextShapePropertySetContext_Impl( + GetImport(), nElement, xAttrList, nFamily, + GetProperties(), xImpPrMap ); + } + } + } + else if ( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + // create and remember events import context + // (for delayed processing of events) + m_xEventContext = new XMLEventsImportContext( GetImport() ); + return m_xEventContext; + } + + return XMLShapeStyleContext::createFastChildContext( nElement, xAttrList ); +} + +void XMLTextShapeStyleContext::CreateAndInsert( bool bOverwrite ) +{ + XMLShapeStyleContext::CreateAndInsert( bOverwrite ); + Reference < XStyle > xStyle = GetStyle(); + if( !xStyle.is() || !(bOverwrite || IsNew()) ) + return; + + Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + if( xPropSetInfo->hasPropertyByName( gsIsAutoUpdate ) ) + { + bool bTmp = m_bAutoUpdate; + xPropSet->setPropertyValue( gsIsAutoUpdate, Any(bTmp) ); + } + + // tell the style about it's events (if applicable) + if( m_xEventContext.is() ) + { + // set event supplier and release reference to context + Reference<XEventsSupplier> xEventsSupplier(xStyle, UNO_QUERY); + m_xEventContext->SetEvents(xEventsSupplier); + m_xEventContext = nullptr; + } +} + +void XMLTextShapeStyleContext::Finish( bool bOverwrite ) +{ + XMLPropStyleContext::Finish( bOverwrite ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextTableContext.cxx b/xmloff/source/text/XMLTextTableContext.cxx new file mode 100644 index 0000000000..2a56c0e60b --- /dev/null +++ b/xmloff/source/text/XMLTextTableContext.cxx @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <xmloff/XMLTextTableContext.hxx> + + +using namespace ::com::sun::star::uno; + + +XMLTextTableContext::XMLTextTableContext( SvXMLImport& rImport ) : + SvXMLImportContext( rImport ) +{ +} + +XMLTextTableContext::~XMLTextTableContext() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTrackedChangesImportContext.cxx b/xmloff/source/text/XMLTrackedChangesImportContext.cxx new file mode 100644 index 0000000000..57a71e0dbf --- /dev/null +++ b/xmloff/source/text/XMLTrackedChangesImportContext.cxx @@ -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 . + */ + +#include "XMLTrackedChangesImportContext.hxx" +#include "XMLChangedRegionImportContext.hxx" +#include <com/sun/star/uno/Reference.h> +#include <sal/log.hxx> +#include <sax/tools/converter.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmltoken.hxx> + + +using ::com::sun::star::uno::Reference; +using namespace ::xmloff::token; + + +XMLTrackedChangesImportContext::XMLTrackedChangesImportContext( + SvXMLImport& rImport) : + SvXMLImportContext(rImport) +{ +} + +XMLTrackedChangesImportContext::~XMLTrackedChangesImportContext() +{ +} + +void XMLTrackedChangesImportContext::startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + bool bTrackChanges = true; + + // scan for text:track-changes and text:protection-key attributes + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if (aIter.getToken() == XML_ELEMENT(TEXT, XML_TRACK_CHANGES) ) + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bTrackChanges = bTmp; + } + break; + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + + // set tracked changes + GetImport().GetTextImport()->SetRecordChanges( bTrackChanges ); +} + + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTrackedChangesImportContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_CHANGED_REGION) ) + { + return new XMLChangedRegionImportContext(GetImport()); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTrackedChangesImportContext.hxx b/xmloff/source/text/XMLTrackedChangesImportContext.hxx new file mode 100644 index 0000000000..6ae3c4a552 --- /dev/null +++ b/xmloff/source/text/XMLTrackedChangesImportContext.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <com/sun/star/uno/Reference.h> + +namespace com::sun::star { + namespace xml::sax { + class XAttributeList; + } +} + +class XMLTrackedChangesImportContext : public SvXMLImportContext +{ +public: + + XMLTrackedChangesImportContext(SvXMLImport& rImport); + + virtual ~XMLTrackedChangesImportContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtdrope.cxx b/xmloff/source/text/txtdrope.cxx new file mode 100644 index 0000000000..5013d422c2 --- /dev/null +++ b/xmloff/source/text/txtdrope.cxx @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/style/DropCapFormat.hpp> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlnamespace.hxx> +#include "txtdrope.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::uno; + +using namespace ::xmloff::token; + + +XMLTextDropCapExport::XMLTextDropCapExport( SvXMLExport& rExp ) : + rExport(rExp) +{ +} + +void XMLTextDropCapExport::exportXML( const Any& rAny, + bool bWholeWord, + const OUString& rStyleName ) +{ + DropCapFormat aFormat; + rAny >>= aFormat; + if( aFormat.Lines > 1 ) + { + SvXMLUnitConverter& rUnitConv = rExport.GetMM100UnitConverter(); + + // style:lines + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LINES, + OUString::number( aFormat.Lines ) ); + + // style:length + OUString sValue; + if( bWholeWord ) + { + sValue = GetXMLToken(XML_WORD); + } + else if( aFormat.Count > 1 ) + { + sValue = OUString::number(aFormat.Count); + } + if( !sValue.isEmpty() ) + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LENGTH, sValue ); + + // style:distance + if( aFormat.Distance > 0 ) + { + OUStringBuffer sBuffer; + rUnitConv.convertMeasureToXML( sBuffer, aFormat.Distance ); + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_DISTANCE, + sBuffer.makeStringAndClear() ); + } + + // style:style-name + if( !rStyleName.isEmpty() ) + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_STYLE_NAME, + rExport.EncodeStyleName( rStyleName ) ); + } + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE, XML_DROP_CAP, + false, false ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtdrope.hxx b/xmloff/source/text/txtdrope.hxx new file mode 100644 index 0000000000..6e6b05a0be --- /dev/null +++ b/xmloff/source/text/txtdrope.hxx @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + + +#include <rtl/ustring.hxx> + +class SvXMLExport; +namespace com::sun::star::uno { class Any; } + +class XMLTextDropCapExport +{ + SvXMLExport& rExport; + +public: + + explicit XMLTextDropCapExport( SvXMLExport& rExport ); + + void exportXML( const css::uno::Any& rAny, + bool bWholeWord, + const OUString& rStyleName ); +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtdropi.cxx b/xmloff/source/text/txtdropi.cxx new file mode 100644 index 0000000000..66b219884b --- /dev/null +++ b/xmloff/source/text/txtdropi.cxx @@ -0,0 +1,122 @@ +/* -*- 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 "txtdropi.hxx" + +#include <com/sun/star/style/DropCapFormat.hpp> + +#include <sal/log.hxx> +#include <sax/tools/converter.hxx> + +#include <xmloff/xmltkmap.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmltoken.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::xmloff::token; + +void XMLTextDropCapImportContext::ProcessAttrs( + const Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + DropCapFormat aFormat; + bool bWholeWord = false; + + sal_Int32 nTmp; + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(STYLE, XML_LINES): + if (::sax::Converter::convertNumber( nTmp, aIter.toView(), 0, 255 )) + { + aFormat.Lines = nTmp < 2 ? 0 : static_cast<sal_Int8>(nTmp); + } + break; + + case XML_ELEMENT(STYLE, XML_LENGTH): + if( IsXMLToken( aIter, XML_WORD ) ) + { + bWholeWord = true; + } + else if (::sax::Converter::convertNumber( nTmp, aIter.toView(), 1, 255 )) + { + bWholeWord = false; + aFormat.Count = static_cast<sal_Int8>(nTmp); + } + break; + + case XML_ELEMENT(STYLE, XML_DISTANCE): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore( + nTmp, aIter.toView(), 0 )) + { + aFormat.Distance = static_cast<sal_uInt16>(nTmp); + } + break; + + case XML_ELEMENT(STYLE, XML_STYLE_NAME): + sStyleName = aIter.toString(); + break; + + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( aFormat.Lines > 1 && aFormat.Count < 1 ) + aFormat.Count = 1; + + aProp.maValue <<= aFormat; + + aWholeWordProp.maValue <<= bWholeWord; +} + +XMLTextDropCapImportContext::XMLTextDropCapImportContext( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + const XMLPropertyState& rProp, + sal_Int32 nWholeWordIdx, + ::std::vector< XMLPropertyState > &rProps ) : + XMLElementPropertyContext( rImport, nElement, rProp, rProps ), + aWholeWordProp( nWholeWordIdx ) +{ + ProcessAttrs( xAttrList ); +} + +XMLTextDropCapImportContext::~XMLTextDropCapImportContext() +{ +} + +void XMLTextDropCapImportContext::endFastElement(sal_Int32 nElement) +{ + SetInsert( true ); + XMLElementPropertyContext::endFastElement(nElement); + + if( -1 != aWholeWordProp.mnIndex ) + rProperties.push_back( aWholeWordProp ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtdropi.hxx b/xmloff/source/text/txtdropi.hxx new file mode 100644 index 0000000000..832761c95d --- /dev/null +++ b/xmloff/source/text/txtdropi.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <xmloff/XMLElementPropertyContext.hxx> + +class XMLTextDropCapImportContext : public XMLElementPropertyContext +{ + XMLPropertyState aWholeWordProp; + OUString sStyleName; + +private: + void ProcessAttrs(const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList); + +public: + XMLTextDropCapImportContext( + SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList, + const XMLPropertyState& rProp, sal_Int32 nWholeWOrdIdx, + ::std::vector<XMLPropertyState>& rProps); + + virtual ~XMLTextDropCapImportContext() override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + const OUString& GetStyleName() const { return sStyleName; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtexppr.cxx b/xmloff/source/text/txtexppr.cxx new file mode 100644 index 0000000000..f49084d9cb --- /dev/null +++ b/xmloff/source/text/txtexppr.cxx @@ -0,0 +1,1206 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/table/BorderLine2.hpp> + +#include "txtexppr.hxx" + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/text/SizeType.hpp> +#include <com/sun/star/text/WrapTextMode.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <com/sun/star/awt/FontUnderline.hpp> +#include <com/sun/star/text/XChapterNumberingSupplier.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <o3tl/any.hxx> +#include <sal/log.hxx> +#include <tools/color.hxx> +#include <xmloff/txtprmap.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/maptype.hxx> +#include <xmloff/namespacemap.hxx> +#include "XMLSectionFootnoteConfigExport.hxx" +#include <xmlsdtypes.hxx> +#include <XMLNumberWithAutoForVoidPropHdl.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::text; + +void XMLTextExportPropertySetMapper::handleElementItem( + SvXMLExport& rExp, + const XMLPropertyState& rProperty, + SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const +{ + XMLTextExportPropertySetMapper *pThis = + const_cast<XMLTextExportPropertySetMapper*>(this); + + switch( getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex ) ) + { + case CTF_DROPCAPFORMAT: + pThis->maDropCapExport.exportXML( rProperty.maValue, bDropWholeWord, + sDropCharStyle ); + pThis->bDropWholeWord = false; + pThis->sDropCharStyle.clear(); + break; + + case CTF_TABSTOP: + pThis->maTabStopExport.Export( rProperty.maValue ); + break; + + case CTF_TEXTCOLUMNS: + pThis->maTextColumnsExport.exportXML( rProperty.maValue ); + break; + + case CTF_COMPLEX_COLOR: + pThis->maComplexColorExport.exportXML(rProperty.maValue, + getPropertySetMapper()->GetEntryNameSpace(rProperty.mnIndex), + getPropertySetMapper()->GetEntryXMLName(rProperty.mnIndex)); + break; + + case CTF_BACKGROUND_URL: + { + const Any *pPos = nullptr, *pFilter = nullptr, *pTrans = nullptr; + sal_uInt32 nPropIndex = rProperty.mnIndex; + + // these are all optional, so have to check them in order + // note: this index order dependency is a steaming pile of manure + if (nIdx) + { + const XMLPropertyState& rFilter = (*pProperties)[nIdx - 1]; + if (CTF_BACKGROUND_FILTER == getPropertySetMapper() + ->GetEntryContextId(rFilter.mnIndex)) + { + pFilter = &rFilter.maValue; + --nIdx; + } + } + + if (nIdx) + { + const XMLPropertyState& rPos = (*pProperties)[nIdx - 1]; + if (CTF_BACKGROUND_POS == getPropertySetMapper() + ->GetEntryContextId(rPos.mnIndex)) + { + pPos = &rPos.maValue; + --nIdx; + } + } + + if (nIdx) + { + const XMLPropertyState& rTrans = (*pProperties)[nIdx - 1]; + // #99657# transparency may be there, but doesn't have to be. + // If it's there, it must be in the right position. + if( CTF_BACKGROUND_TRANSPARENCY == getPropertySetMapper() + ->GetEntryContextId( rTrans.mnIndex ) ) + pTrans = &rTrans.maValue; + } + + pThis->maBackgroundImageExport.exportXML( + rProperty.maValue, pPos, pFilter, pTrans, + getPropertySetMapper()->GetEntryNameSpace( nPropIndex ), + getPropertySetMapper()->GetEntryXMLName( nPropIndex ) ); + } + break; + + case CTF_SECTION_FOOTNOTE_END: + XMLSectionFootnoteConfigExport::exportXML(rExp, false, + pProperties, nIdx, + getPropertySetMapper()); + break; + + case CTF_SECTION_ENDNOTE_END: + XMLSectionFootnoteConfigExport::exportXML(rExp, true, + pProperties, nIdx, + getPropertySetMapper()); + break; + + default: + SvXMLExportPropertyMapper::handleElementItem( rExp, rProperty, nFlags, pProperties, nIdx ); + break; + } +} + +void XMLTextExportPropertySetMapper::handleSpecialItem( + comphelper::AttributeList& rAttrList, + const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const +{ + XMLTextExportPropertySetMapper *pThis = + const_cast<XMLTextExportPropertySetMapper*>(this); + + switch( getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex ) ) + { + case CTF_PAGENUMBEROFFSET: + { + OUString value; + XMLNumberWithAutoForVoidPropHdl const handler; + handler.exportXML(value, rProperty.maValue, rUnitConverter); + if (GetExport().getSaneDefaultVersion() < SvtSaveOptions::ODFSVER_013 + && value == "0") // tdf#91306 ODF 1.3 OFFICE-3923 + { + value = "auto"; + } + OUString const name = rNamespaceMap.GetQNameByKey( + getPropertySetMapper()->GetEntryNameSpace(rProperty.mnIndex), + getPropertySetMapper()->GetEntryXMLName(rProperty.mnIndex)); + rAttrList.AddAttribute(name, value); + } + break; + case CTF_DROPCAPWHOLEWORD: + SAL_WARN_IF( !!bDropWholeWord, "xmloff", "drop whole word is set already!" ); + pThis->bDropWholeWord = *o3tl::doAccess<bool>(rProperty.maValue); + break; + case CTF_DROPCAPCHARSTYLE: + SAL_WARN_IF( !sDropCharStyle.isEmpty(), "xmloff", "drop char style is set already!" ); + rProperty.maValue >>= pThis->sDropCharStyle; + break; + case CTF_NUMBERINGSTYLENAME: + case CTF_PAGEDESCNAME: + case CTF_OLDTEXTBACKGROUND: + case CTF_BACKGROUND_POS: + case CTF_BACKGROUND_FILTER: + case CTF_BACKGROUND_TRANSPARENCY: + case CTF_SECTION_FOOTNOTE_NUM_OWN: + case CTF_SECTION_FOOTNOTE_NUM_RESTART: + case CTF_SECTION_FOOTNOTE_NUM_RESTART_AT: + case CTF_SECTION_FOOTNOTE_NUM_TYPE: + case CTF_SECTION_FOOTNOTE_NUM_PREFIX: + case CTF_SECTION_FOOTNOTE_NUM_SUFFIX: + case CTF_SECTION_ENDNOTE_NUM_OWN: + case CTF_SECTION_ENDNOTE_NUM_RESTART: + case CTF_SECTION_ENDNOTE_NUM_RESTART_AT: + case CTF_SECTION_ENDNOTE_NUM_TYPE: + case CTF_SECTION_ENDNOTE_NUM_PREFIX: + case CTF_SECTION_ENDNOTE_NUM_SUFFIX: + case CTF_DEFAULT_OUTLINE_LEVEL: + case CTF_OLD_FLOW_WITH_TEXT: + // There's nothing to do here! + break; + default: + SvXMLExportPropertyMapper::handleSpecialItem(rAttrList, rProperty, rUnitConverter, rNamespaceMap, pProperties, nIdx ); + break; + } +} + +XMLTextExportPropertySetMapper::XMLTextExportPropertySetMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLExport& rExp ) : + SvXMLExportPropertyMapper( rMapper ), + rExport( rExp ), + bDropWholeWord( false ), + maDropCapExport( rExp ), + maTabStopExport( rExp ), + maTextColumnsExport( rExp ), + maComplexColorExport(rExp), + maBackgroundImageExport( rExp ) +{ +} + +XMLTextExportPropertySetMapper::~XMLTextExportPropertySetMapper() +{ +} + +void XMLTextExportPropertySetMapper::ContextFontFilter( + bool bEnableFoFontFamily, + XMLPropertyState *pFontNameState, + XMLPropertyState *pFontFamilyNameState, + XMLPropertyState *pFontStyleNameState, + XMLPropertyState *pFontFamilyState, + XMLPropertyState *pFontPitchState, + XMLPropertyState *pFontCharsetState ) const +{ + OUString sFamilyName; + OUString sStyleName; + FontFamily nFamily = FAMILY_DONTKNOW; + FontPitch nPitch = PITCH_DONTKNOW; + rtl_TextEncoding eEnc = RTL_TEXTENCODING_DONTKNOW; + + OUString sTmp; + if( pFontFamilyNameState && (pFontFamilyNameState->maValue >>= sTmp ) ) + sFamilyName = sTmp; + if( pFontStyleNameState && (pFontStyleNameState->maValue >>= sTmp ) ) + sStyleName = sTmp; + + sal_Int16 nTmp = sal_Int16(); + if( pFontFamilyState && (pFontFamilyState->maValue >>= nTmp ) ) + nFamily = static_cast< FontFamily >( nTmp ); + if( pFontPitchState && (pFontPitchState->maValue >>= nTmp ) ) + nPitch = static_cast< FontPitch >( nTmp ); + if( pFontCharsetState && (pFontCharsetState->maValue >>= nTmp ) ) + eEnc = static_cast<rtl_TextEncoding>(nTmp); + + //Resolves: fdo#67665 The purpose here appears to be to replace + //FontFamilyName and FontStyleName etc with a single FontName property. The + //problem is that repeated calls to here will first set + //pFontFamilyNameState->mnIndex to -1 to indicate it is disabled, so the + //next time pFontFamilyNameState is not passed here at all, which gives an + //empty sFamilyName resulting in disabling pFontNameState->mnIndex to -1. + //That doesn't seem right to me. + + //So assuming that the main purpose is just to convert the properties in + //the main when we can, and to leave them alone when we can't. And with a + //secondary purpose to filter out empty font properties, then is would + //appear to make sense to base attempting the conversion if we have + //both of the major facts of the font description + + //An alternative solution is to *not* fill the FontAutoStylePool with + //every font in the document, but to partition the fonts into the + //hard-attribute fonts which go into that pool and the style-attribute + //fonts which go into some additional pool which get merged just for + //the purposes of writing the embedded fonts but are not queried by + //"Find" which restores the original logic. + if (pFontFamilyNameState || pFontStyleNameState) + { + OUString sName( const_cast<SvXMLExport&>(GetExport()).GetFontAutoStylePool()->Find( + sFamilyName, sStyleName, nFamily, nPitch, eEnc ) ); + if (!sName.isEmpty()) + { + pFontNameState->maValue <<= sName; + //Resolves: fdo#68431 style:font-name unrecognized by LibreOffice + //<= 4.1 in styles (but recognized in autostyles) so add + //fo:font-family, etc + if (!bEnableFoFontFamily) + { + if( pFontFamilyNameState ) + pFontFamilyNameState->mnIndex = -1; + if( pFontStyleNameState ) + pFontStyleNameState->mnIndex = -1; + if( pFontFamilyState ) + pFontFamilyState->mnIndex = -1; + if( pFontPitchState ) + pFontPitchState->mnIndex = -1; + if( pFontCharsetState ) + pFontCharsetState->mnIndex = -1; + } + } + else + { + pFontNameState->mnIndex = -1; + } + } + + if( pFontFamilyNameState && sFamilyName.isEmpty() ) + { + pFontFamilyNameState->mnIndex = -1; + } + + if( pFontStyleNameState && sStyleName.isEmpty() ) + { + pFontStyleNameState->mnIndex = -1; + } +} + +void XMLTextExportPropertySetMapper::ContextFontHeightFilter( + XMLPropertyState* pCharHeightState, + XMLPropertyState* pCharPropHeightState, + XMLPropertyState* pCharDiffHeightState ) +{ + if( pCharPropHeightState ) + { + sal_Int32 nTemp = 0; + pCharPropHeightState->maValue >>= nTemp; + if( nTemp == 100 ) + { + pCharPropHeightState->mnIndex = -1; + pCharPropHeightState->maValue.clear(); + } + else + { + pCharHeightState->mnIndex = -1; + pCharHeightState->maValue.clear(); + } + } + if( !pCharDiffHeightState ) + return; + + float nTemp = 0; + pCharDiffHeightState->maValue >>= nTemp; + if( nTemp == 0. ) + { + pCharDiffHeightState->mnIndex = -1; + pCharDiffHeightState->maValue.clear(); + } + else + { + pCharHeightState->mnIndex = -1; + pCharHeightState->maValue.clear(); + } + +} + +namespace { + +// helper method; implementation below +bool lcl_IsOutlineStyle(const SvXMLExport&, std::u16string_view); + +void +lcl_checkMultiProperty(XMLPropertyState *const pState, + XMLPropertyState *const pRelState) +{ + if (!(pState && pRelState)) + return; + + sal_Int32 nTemp = 0; + pRelState->maValue >>= nTemp; + if (100 == nTemp) + { + pRelState->mnIndex = -1; + pRelState->maValue.clear(); + } + else + { + pState->mnIndex = -1; + pState->maValue.clear(); + } +} + +/** + * Filter context of paragraph and character borders. + * Compress border attributes. If one of groupable attributes (border type, border width, padding) + * is equal for all four side then just one general attribute will be exported. +**/ +void lcl_FilterBorders( + XMLPropertyState* pAllBorderWidthState, XMLPropertyState* pLeftBorderWidthState, + XMLPropertyState* pRightBorderWidthState, XMLPropertyState* pTopBorderWidthState, + XMLPropertyState* pBottomBorderWidthState, XMLPropertyState* pAllBorderDistanceState, + XMLPropertyState* pLeftBorderDistanceState, XMLPropertyState* pRightBorderDistanceState, + XMLPropertyState* pTopBorderDistanceState, XMLPropertyState* pBottomBorderDistanceState, + XMLPropertyState* pAllBorderState, XMLPropertyState* pLeftBorderState, + XMLPropertyState* pRightBorderState,XMLPropertyState* pTopBorderState, + XMLPropertyState* pBottomBorderState ) +{ + if( pAllBorderWidthState ) + { + if( pLeftBorderWidthState && pRightBorderWidthState && pTopBorderWidthState && pBottomBorderWidthState ) + { + table::BorderLine2 aLeft, aRight, aTop, aBottom; + + pLeftBorderWidthState->maValue >>= aLeft; + pRightBorderWidthState->maValue >>= aRight; + pTopBorderWidthState->maValue >>= aTop; + pBottomBorderWidthState->maValue >>= aBottom; + if( aLeft.Color == aRight.Color && aLeft.InnerLineWidth == aRight.InnerLineWidth && + aLeft.OuterLineWidth == aRight.OuterLineWidth && aLeft.LineDistance == aRight.LineDistance && + aLeft.LineStyle == aRight.LineStyle && + aLeft.LineWidth == aRight.LineWidth && + aLeft.Color == aTop.Color && aLeft.InnerLineWidth == aTop.InnerLineWidth && + aLeft.OuterLineWidth == aTop.OuterLineWidth && aLeft.LineDistance == aTop.LineDistance && + aLeft.LineStyle == aTop.LineStyle && + aLeft.LineWidth == aTop.LineWidth && + aLeft.Color == aBottom.Color && aLeft.InnerLineWidth == aBottom.InnerLineWidth && + aLeft.OuterLineWidth == aBottom.OuterLineWidth && aLeft.LineDistance == aBottom.LineDistance && + aLeft.LineStyle == aBottom.LineStyle && + aLeft.LineWidth == aBottom.LineWidth ) + { + pLeftBorderWidthState->mnIndex = -1; + pLeftBorderWidthState->maValue.clear(); + pRightBorderWidthState->mnIndex = -1; + pRightBorderWidthState->maValue.clear(); + pTopBorderWidthState->mnIndex = -1; + pTopBorderWidthState->maValue.clear(); + pBottomBorderWidthState->mnIndex = -1; + pBottomBorderWidthState->maValue.clear(); + } + else + { + pAllBorderWidthState->mnIndex = -1; + pAllBorderWidthState->maValue.clear(); + } + } + else + { + pAllBorderWidthState->mnIndex = -1; + pAllBorderWidthState->maValue.clear(); + } + } + + if( pAllBorderDistanceState ) + { + if( pLeftBorderDistanceState && pRightBorderDistanceState && pTopBorderDistanceState && pBottomBorderDistanceState ) + { + sal_Int32 aLeft = 0, aRight = 0, aTop = 0, aBottom = 0; + + pLeftBorderDistanceState->maValue >>= aLeft; + pRightBorderDistanceState->maValue >>= aRight; + pTopBorderDistanceState->maValue >>= aTop; + pBottomBorderDistanceState->maValue >>= aBottom; + if( aLeft == aRight && aLeft == aTop && aLeft == aBottom ) + { + pLeftBorderDistanceState->mnIndex = -1; + pLeftBorderDistanceState->maValue.clear(); + pRightBorderDistanceState->mnIndex = -1; + pRightBorderDistanceState->maValue.clear(); + pTopBorderDistanceState->mnIndex = -1; + pTopBorderDistanceState->maValue.clear(); + pBottomBorderDistanceState->mnIndex = -1; + pBottomBorderDistanceState->maValue.clear(); + } + else + { + pAllBorderDistanceState->mnIndex = -1; + pAllBorderDistanceState->maValue.clear(); + } + } + else + { + pAllBorderDistanceState->mnIndex = -1; + pAllBorderDistanceState->maValue.clear(); + } + } + + if( !pAllBorderState ) + return; + + if( pLeftBorderState && pRightBorderState && pTopBorderState && pBottomBorderState ) + { + table::BorderLine2 aLeft, aRight, aTop, aBottom; + + pLeftBorderState->maValue >>= aLeft; + pRightBorderState->maValue >>= aRight; + pTopBorderState->maValue >>= aTop; + pBottomBorderState->maValue >>= aBottom; + if( aLeft.Color == aRight.Color && aLeft.InnerLineWidth == aRight.InnerLineWidth && + aLeft.OuterLineWidth == aRight.OuterLineWidth && aLeft.LineDistance == aRight.LineDistance && + aLeft.LineStyle == aRight.LineStyle && + aLeft.LineWidth == aRight.LineWidth && + aLeft.Color == aTop.Color && aLeft.InnerLineWidth == aTop.InnerLineWidth && + aLeft.OuterLineWidth == aTop.OuterLineWidth && aLeft.LineDistance == aTop.LineDistance && + aLeft.LineStyle == aTop.LineStyle && + aLeft.LineWidth == aTop.LineWidth && + aLeft.Color == aBottom.Color && aLeft.InnerLineWidth == aBottom.InnerLineWidth && + aLeft.OuterLineWidth == aBottom.OuterLineWidth && aLeft.LineDistance == aBottom.LineDistance && + aLeft.LineWidth == aBottom.LineWidth && + aLeft.LineStyle == aBottom.LineStyle ) + { + pLeftBorderState->mnIndex = -1; + pLeftBorderState->maValue.clear(); + pRightBorderState->mnIndex = -1; + pRightBorderState->maValue.clear(); + pTopBorderState->mnIndex = -1; + pTopBorderState->maValue.clear(); + pBottomBorderState->mnIndex = -1; + pBottomBorderState->maValue.clear(); + } + else + { + pAllBorderState->mnIndex = -1; + pAllBorderState->maValue.clear(); + } + } + else + { + pAllBorderState->mnIndex = -1; + pAllBorderState->maValue.clear(); + } +} + +} + +void XMLTextExportPropertySetMapper::ContextFilter( + bool bEnableFoFontFamily, + ::std::vector< XMLPropertyState >& rProperties, + const Reference< XPropertySet >& rPropSet ) const +{ + // filter font + XMLPropertyState *pFontNameState = nullptr; + XMLPropertyState *pFontFamilyNameState = nullptr; + XMLPropertyState *pFontStyleNameState = nullptr; + XMLPropertyState *pFontFamilyState = nullptr; + XMLPropertyState *pFontPitchState = nullptr; + XMLPropertyState *pFontCharsetState = nullptr; + XMLPropertyState *pFontNameCJKState = nullptr; + XMLPropertyState *pFontFamilyNameCJKState = nullptr; + XMLPropertyState *pFontStyleNameCJKState = nullptr; + XMLPropertyState *pFontFamilyCJKState = nullptr; + XMLPropertyState *pFontPitchCJKState = nullptr; + XMLPropertyState *pFontCharsetCJKState = nullptr; + XMLPropertyState *pFontNameCTLState = nullptr; + XMLPropertyState *pFontFamilyNameCTLState = nullptr; + XMLPropertyState *pFontStyleNameCTLState = nullptr; + XMLPropertyState *pFontFamilyCTLState = nullptr; + XMLPropertyState *pFontPitchCTLState = nullptr; + XMLPropertyState *pFontCharsetCTLState = nullptr; + + // filter char height point/percent + XMLPropertyState* pCharHeightState = nullptr; + XMLPropertyState* pCharPropHeightState = nullptr; + XMLPropertyState* pCharDiffHeightState = nullptr; + XMLPropertyState* pCharHeightCJKState = nullptr; + XMLPropertyState* pCharPropHeightCJKState = nullptr; + XMLPropertyState* pCharDiffHeightCJKState = nullptr; + XMLPropertyState* pCharHeightCTLState = nullptr; + XMLPropertyState* pCharPropHeightCTLState = nullptr; + XMLPropertyState* pCharDiffHeightCTLState = nullptr; + + // filter left margin measure/percent + XMLPropertyState* pParaLeftMarginState = nullptr; + XMLPropertyState* pParaLeftMarginRelState = nullptr; + + // filter right margin measure/percent + XMLPropertyState* pParaRightMarginState = nullptr; + XMLPropertyState* pParaRightMarginRelState = nullptr; + + // filter first line indent measure/percent + XMLPropertyState* pParaFirstLineState = nullptr; + XMLPropertyState* pParaFirstLineRelState = nullptr; + + // filter ParaTopMargin/Relative + XMLPropertyState* pParaTopMarginState = nullptr; + XMLPropertyState* pParaTopMarginRelState = nullptr; + + // filter ParaTopMargin/Relative + XMLPropertyState* pParaBottomMarginState = nullptr; + XMLPropertyState* pParaBottomMarginRelState = nullptr; + + // filter (Left|Right|Top|Bottom|)BorderWidth + XMLPropertyState* pAllBorderWidthState = nullptr; + XMLPropertyState* pLeftBorderWidthState = nullptr; + XMLPropertyState* pRightBorderWidthState = nullptr; + XMLPropertyState* pTopBorderWidthState = nullptr; + XMLPropertyState* pBottomBorderWidthState = nullptr; + + // filter (Left|Right|Top|)BorderDistance + XMLPropertyState* pAllBorderDistanceState = nullptr; + XMLPropertyState* pLeftBorderDistanceState = nullptr; + XMLPropertyState* pRightBorderDistanceState = nullptr; + XMLPropertyState* pTopBorderDistanceState = nullptr; + XMLPropertyState* pBottomBorderDistanceState = nullptr; + + // filter (Left|Right|Top|Bottom|)Border + XMLPropertyState* pAllBorderState = nullptr; + XMLPropertyState* pLeftBorderState = nullptr; + XMLPropertyState* pRightBorderState = nullptr; + XMLPropertyState* pTopBorderState = nullptr; + XMLPropertyState* pBottomBorderState = nullptr; + + // filter Char(Left|Right|Top|Bottom|)BorderWidth + XMLPropertyState* pCharAllBorderWidthState = nullptr; + XMLPropertyState* pCharLeftBorderWidthState = nullptr; + XMLPropertyState* pCharRightBorderWidthState = nullptr; + XMLPropertyState* pCharTopBorderWidthState = nullptr; + XMLPropertyState* pCharBottomBorderWidthState = nullptr; + + // filter Char(Left|Right|Top|)BorderDistance + XMLPropertyState* pCharAllBorderDistanceState = nullptr; + XMLPropertyState* pCharLeftBorderDistanceState = nullptr; + XMLPropertyState* pCharRightBorderDistanceState = nullptr; + XMLPropertyState* pCharTopBorderDistanceState = nullptr; + XMLPropertyState* pCharBottomBorderDistanceState = nullptr; + + // filter Char(Left|Right|Top|Bottom|)Border + XMLPropertyState* pCharAllBorderState = nullptr; + XMLPropertyState* pCharLeftBorderState = nullptr; + XMLPropertyState* pCharRightBorderState = nullptr; + XMLPropertyState* pCharTopBorderState = nullptr; + XMLPropertyState* pCharBottomBorderState = nullptr; + + // filter height properties + XMLPropertyState* pHeightMinAbsState = nullptr; + XMLPropertyState* pHeightMinRelState = nullptr; + XMLPropertyState* pHeightAbsState = nullptr; + XMLPropertyState* pHeightRelState = nullptr; + XMLPropertyState* pSizeTypeState = nullptr; + + // filter width properties + XMLPropertyState* pWidthMinAbsState = nullptr; + XMLPropertyState* pWidthMinRelState = nullptr; + XMLPropertyState* pWidthAbsState = nullptr; + XMLPropertyState* pWidthRelState = nullptr; + XMLPropertyState* pWidthTypeState = nullptr; + + // wrap + XMLPropertyState* pWrapState = nullptr; + XMLPropertyState* pWrapContourState = nullptr; + XMLPropertyState* pWrapContourModeState = nullptr; + XMLPropertyState* pWrapParagraphOnlyState = nullptr; + + // anchor + XMLPropertyState* pAnchorTypeState = nullptr; + + // horizontal position and relation + XMLPropertyState* pHoriOrientState = nullptr; + XMLPropertyState* pHoriOrientMirroredState = nullptr; + XMLPropertyState* pHoriOrientRelState = nullptr; + XMLPropertyState* pHoriOrientRelFrameState = nullptr; + XMLPropertyState* pHoriOrientMirrorState = nullptr; + // Horizontal position and relation for shapes (#i28749#) + XMLPropertyState* pShapeHoriOrientState = nullptr; + XMLPropertyState* pShapeHoriOrientMirroredState = nullptr; + XMLPropertyState* pShapeHoriOrientRelState = nullptr; + XMLPropertyState* pShapeHoriOrientRelFrameState = nullptr; + XMLPropertyState* pShapeHoriOrientMirrorState = nullptr; + + // vertical position and relation + XMLPropertyState* pVertOrientState = nullptr; + XMLPropertyState* pVertOrientAtCharState = nullptr; + XMLPropertyState* pVertOrientRelState = nullptr; + XMLPropertyState* pVertOrientRelPageState = nullptr; + XMLPropertyState* pVertOrientRelFrameState = nullptr; + XMLPropertyState* pVertOrientRelAsCharState = nullptr; + XMLPropertyState* pRelWidthRel = nullptr; + XMLPropertyState* pRelHeightRel = nullptr; + + // Vertical position and relation for shapes (#i28749#) + XMLPropertyState* pShapeVertOrientState = nullptr; + XMLPropertyState* pShapeVertOrientAtCharState = nullptr; + XMLPropertyState* pShapeVertOrientRelState = nullptr; + XMLPropertyState* pShapeVertOrientRelPageState = nullptr; + XMLPropertyState* pShapeVertOrientRelFrameState = nullptr; + + // filter underline color + XMLPropertyState* pUnderlineState = nullptr; + XMLPropertyState* pUnderlineColorState = nullptr; + XMLPropertyState* pUnderlineHasColorState = nullptr; + + // filter list style name + XMLPropertyState* pListStyleName = nullptr; + + // filter fo:clip + XMLPropertyState* pClip11State = nullptr; + XMLPropertyState* pClipState = nullptr; + + // filter fo:margin + XMLPropertyState* pAllParaMarginRel = nullptr; + XMLPropertyState* pAllParaMargin = nullptr; + XMLPropertyState* pAllMargin = nullptr; + + XMLPropertyState* pRepeatOffsetX = nullptr; + XMLPropertyState* pRepeatOffsetY = nullptr; + + // character background and highlight + XMLPropertyState* pCharBackground = nullptr; + XMLPropertyState* pCharBackgroundTransparency = nullptr; + XMLPropertyState* pCharHighlight = nullptr; + + bool bNeedsAnchor = false; + + for( auto& rPropertyState : rProperties ) + { + XMLPropertyState *propertyState = &rPropertyState; + if( propertyState->mnIndex == -1 ) + continue; + + switch( getPropertySetMapper()->GetEntryContextId( propertyState->mnIndex ) ) + { + case CTF_CHARHEIGHT: pCharHeightState = propertyState; break; + case CTF_CHARHEIGHT_REL: pCharPropHeightState = propertyState; break; + case CTF_CHARHEIGHT_DIFF: pCharDiffHeightState = propertyState; break; + case CTF_CHARHEIGHT_CJK: pCharHeightCJKState = propertyState; break; + case CTF_CHARHEIGHT_REL_CJK: pCharPropHeightCJKState = propertyState; break; + case CTF_CHARHEIGHT_DIFF_CJK: pCharDiffHeightCJKState = propertyState; break; + case CTF_CHARHEIGHT_CTL: pCharHeightCTLState = propertyState; break; + case CTF_CHARHEIGHT_REL_CTL: pCharPropHeightCTLState = propertyState; break; + case CTF_CHARHEIGHT_DIFF_CTL: pCharDiffHeightCTLState = propertyState; break; + case CTF_PARALEFTMARGIN: pParaLeftMarginState = propertyState; break; + case CTF_PARALEFTMARGIN_REL: pParaLeftMarginRelState = propertyState; break; + case CTF_PARARIGHTMARGIN: pParaRightMarginState = propertyState; break; + case CTF_PARARIGHTMARGIN_REL: pParaRightMarginRelState = propertyState; break; + case CTF_PARAFIRSTLINE: pParaFirstLineState = propertyState; break; + case CTF_PARAFIRSTLINE_REL: pParaFirstLineRelState = propertyState; break; + case CTF_PARATOPMARGIN: pParaTopMarginState = propertyState; break; + case CTF_PARATOPMARGIN_REL: pParaTopMarginRelState = propertyState; break; + case CTF_PARABOTTOMMARGIN: pParaBottomMarginState = propertyState; break; + case CTF_PARABOTTOMMARGIN_REL: pParaBottomMarginRelState = propertyState; break; + + case CTF_ALLBORDERWIDTH: pAllBorderWidthState = propertyState; break; + case CTF_LEFTBORDERWIDTH: pLeftBorderWidthState = propertyState; break; + case CTF_RIGHTBORDERWIDTH: pRightBorderWidthState = propertyState; break; + case CTF_TOPBORDERWIDTH: pTopBorderWidthState = propertyState; break; + case CTF_BOTTOMBORDERWIDTH: pBottomBorderWidthState = propertyState; break; + case CTF_ALLBORDERDISTANCE: pAllBorderDistanceState = propertyState; break; + case CTF_LEFTBORDERDISTANCE: pLeftBorderDistanceState = propertyState; break; + case CTF_RIGHTBORDERDISTANCE: pRightBorderDistanceState = propertyState; break; + case CTF_TOPBORDERDISTANCE: pTopBorderDistanceState = propertyState; break; + case CTF_BOTTOMBORDERDISTANCE: pBottomBorderDistanceState = propertyState; break; + case CTF_ALLBORDER: pAllBorderState = propertyState; break; + case CTF_LEFTBORDER: pLeftBorderState = propertyState; break; + case CTF_RIGHTBORDER: pRightBorderState = propertyState; break; + case CTF_TOPBORDER: pTopBorderState = propertyState; break; + case CTF_BOTTOMBORDER: pBottomBorderState = propertyState; break; + + case CTF_CHARALLBORDERWIDTH: pCharAllBorderWidthState = propertyState; break; + case CTF_CHARLEFTBORDERWIDTH: pCharLeftBorderWidthState = propertyState; break; + case CTF_CHARRIGHTBORDERWIDTH: pCharRightBorderWidthState = propertyState; break; + case CTF_CHARTOPBORDERWIDTH: pCharTopBorderWidthState = propertyState; break; + case CTF_CHARBOTTOMBORDERWIDTH: pCharBottomBorderWidthState = propertyState; break; + case CTF_CHARALLBORDERDISTANCE: pCharAllBorderDistanceState = propertyState; break; + case CTF_CHARLEFTBORDERDISTANCE: pCharLeftBorderDistanceState = propertyState; break; + case CTF_CHARRIGHTBORDERDISTANCE: pCharRightBorderDistanceState = propertyState; break; + case CTF_CHARTOPBORDERDISTANCE: pCharTopBorderDistanceState = propertyState; break; + case CTF_CHARBOTTOMBORDERDISTANCE: pCharBottomBorderDistanceState = propertyState; break; + case CTF_CHARALLBORDER: pCharAllBorderState = propertyState; break; + case CTF_CHARLEFTBORDER: pCharLeftBorderState = propertyState; break; + case CTF_CHARRIGHTBORDER: pCharRightBorderState = propertyState; break; + case CTF_CHARTOPBORDER: pCharTopBorderState = propertyState; break; + case CTF_CHARBOTTOMBORDER: pCharBottomBorderState = propertyState; break; + + case CTF_FRAMEHEIGHT_MIN_ABS: pHeightMinAbsState = propertyState; break; + case CTF_FRAMEHEIGHT_MIN_REL: pHeightMinRelState = propertyState; break; + case CTF_FRAMEHEIGHT_ABS: pHeightAbsState = propertyState; break; + case CTF_FRAMEHEIGHT_REL: pHeightRelState = propertyState; break; + case CTF_SIZETYPE: pSizeTypeState = propertyState; break; + + case CTF_FRAMEWIDTH_MIN_ABS: pWidthMinAbsState = propertyState; break; + case CTF_FRAMEWIDTH_MIN_REL: pWidthMinRelState = propertyState; break; + case CTF_FRAMEWIDTH_ABS: pWidthAbsState = propertyState; break; + case CTF_FRAMEWIDTH_REL: pWidthRelState = propertyState; break; + case CTF_FRAMEWIDTH_TYPE: pWidthTypeState = propertyState; break; + + case CTF_WRAP: pWrapState = propertyState; break; + case CTF_WRAP_CONTOUR: pWrapContourState = propertyState; break; + case CTF_WRAP_CONTOUR_MODE: pWrapContourModeState = propertyState; break; + case CTF_WRAP_PARAGRAPH_ONLY: pWrapParagraphOnlyState = propertyState; break; + case CTF_ANCHORTYPE: pAnchorTypeState = propertyState; break; + + case CTF_HORIZONTALPOS: pHoriOrientState = propertyState; bNeedsAnchor = true; break; + case CTF_HORIZONTALPOS_MIRRORED: pHoriOrientMirroredState = propertyState; bNeedsAnchor = true; break; + case CTF_HORIZONTALREL: pHoriOrientRelState = propertyState; bNeedsAnchor = true; break; + case CTF_HORIZONTALREL_FRAME: pHoriOrientRelFrameState = propertyState; bNeedsAnchor = true; break; + case CTF_HORIZONTALMIRROR: pHoriOrientMirrorState = propertyState; bNeedsAnchor = true; break; + case CTF_RELWIDTHREL: pRelWidthRel = propertyState; break; + case CTF_VERTICALPOS: pVertOrientState = propertyState; bNeedsAnchor = true; break; + case CTF_VERTICALPOS_ATCHAR: pVertOrientAtCharState = propertyState; bNeedsAnchor = true; break; + case CTF_VERTICALREL: pVertOrientRelState = propertyState; bNeedsAnchor = true; break; + case CTF_VERTICALREL_PAGE: pVertOrientRelPageState = propertyState; bNeedsAnchor = true; break; + case CTF_VERTICALREL_FRAME: pVertOrientRelFrameState = propertyState; bNeedsAnchor = true; break; + case CTF_VERTICALREL_ASCHAR: pVertOrientRelAsCharState = propertyState; bNeedsAnchor = true; break; + case CTF_RELHEIGHTREL: pRelHeightRel = propertyState; break; + + // Handle new CTFs for shape positioning properties (#i28749#) + case CTF_SHAPE_HORIZONTALPOS: pShapeHoriOrientState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_HORIZONTALPOS_MIRRORED: pShapeHoriOrientMirroredState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_HORIZONTALREL: pShapeHoriOrientRelState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_HORIZONTALREL_FRAME: pShapeHoriOrientRelFrameState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_HORIZONTALMIRROR: pShapeHoriOrientMirrorState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_VERTICALPOS: pShapeVertOrientState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_VERTICALPOS_ATCHAR: pShapeVertOrientAtCharState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_VERTICALREL: pShapeVertOrientRelState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_VERTICALREL_PAGE: pShapeVertOrientRelPageState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_VERTICALREL_FRAME: pShapeVertOrientRelFrameState = propertyState; bNeedsAnchor = true; break; + case CTF_FONTNAME: pFontNameState = propertyState; break; + case CTF_FONTFAMILYNAME: pFontFamilyNameState = propertyState; break; + case CTF_FONTSTYLENAME: pFontStyleNameState = propertyState; break; + case CTF_FONTFAMILY: pFontFamilyState = propertyState; break; + case CTF_FONTPITCH: pFontPitchState = propertyState; break; + case CTF_FONTCHARSET: pFontCharsetState = propertyState; break; + + case CTF_FONTNAME_CJK: pFontNameCJKState = propertyState; break; + case CTF_FONTFAMILYNAME_CJK: pFontFamilyNameCJKState = propertyState; break; + case CTF_FONTSTYLENAME_CJK: pFontStyleNameCJKState = propertyState; break; + case CTF_FONTFAMILY_CJK: pFontFamilyCJKState = propertyState; break; + case CTF_FONTPITCH_CJK: pFontPitchCJKState = propertyState; break; + case CTF_FONTCHARSET_CJK: pFontCharsetCJKState = propertyState; break; + + case CTF_FONTNAME_CTL: pFontNameCTLState = propertyState; break; + case CTF_FONTFAMILYNAME_CTL: pFontFamilyNameCTLState = propertyState; break; + case CTF_FONTSTYLENAME_CTL: pFontStyleNameCTLState = propertyState; break; + case CTF_FONTFAMILY_CTL: pFontFamilyCTLState = propertyState; break; + case CTF_FONTPITCH_CTL: pFontPitchCTLState = propertyState; break; + case CTF_FONTCHARSET_CTL: pFontCharsetCTLState = propertyState; break; + case CTF_UNDERLINE: pUnderlineState = propertyState; break; + case CTF_UNDERLINE_COLOR: pUnderlineColorState = propertyState; break; + case CTF_UNDERLINE_HASCOLOR: pUnderlineHasColorState = propertyState; break; + case CTF_NUMBERINGSTYLENAME: pListStyleName = propertyState; break; + case CTF_TEXT_CLIP11: pClip11State = propertyState; break; + case CTF_TEXT_CLIP: pClipState = propertyState; break; + case CTF_PARAMARGINALL_REL: pAllParaMarginRel = propertyState; break; + case CTF_PARAMARGINALL: pAllParaMargin = propertyState; break; + case CTF_MARGINALL: pAllMargin = propertyState; break; + + case CTF_REPEAT_OFFSET_X: + pRepeatOffsetX = propertyState; + break; + + case CTF_REPEAT_OFFSET_Y: + pRepeatOffsetY = propertyState; + break; + + case CTF_FILLGRADIENTNAME: + case CTF_FILLHATCHNAME: + case CTF_FILLBITMAPNAME: + case CTF_FILLTRANSNAME: + { + OUString aStr; + if( (propertyState->maValue >>= aStr) && 0 == aStr.getLength() ) + propertyState->mnIndex = -1; + } + break; + + case CTF_CHAR_BACKGROUND: pCharBackground = propertyState; break; + case CTF_CHAR_BACKGROUND_TRANSPARENCY: pCharBackgroundTransparency = propertyState; break; + case CTF_CHAR_HIGHLIGHT: pCharHighlight = propertyState; break; + } + } + + if( pRepeatOffsetX && pRepeatOffsetY ) + { + sal_Int32 nOffset = 0; + if( ( pRepeatOffsetX->maValue >>= nOffset ) && ( nOffset == 0 ) ) + pRepeatOffsetX->mnIndex = -1; + else + pRepeatOffsetY->mnIndex = -1; + } + + if( pFontNameState ) + ContextFontFilter( bEnableFoFontFamily, pFontNameState, pFontFamilyNameState, + pFontStyleNameState, pFontFamilyState, + pFontPitchState, pFontCharsetState ); + if( pFontNameCJKState ) + ContextFontFilter( bEnableFoFontFamily, pFontNameCJKState, pFontFamilyNameCJKState, + pFontStyleNameCJKState, pFontFamilyCJKState, + pFontPitchCJKState, pFontCharsetCJKState ); + if( pFontNameCTLState ) + ContextFontFilter( bEnableFoFontFamily, pFontNameCTLState, pFontFamilyNameCTLState, + pFontStyleNameCTLState, pFontFamilyCTLState, + pFontPitchCTLState, pFontCharsetCTLState ); + + if( pCharHeightState && (pCharPropHeightState || pCharDiffHeightState ) ) + ContextFontHeightFilter( pCharHeightState, pCharPropHeightState, + pCharDiffHeightState ); + if( pCharHeightCJKState && + (pCharPropHeightCJKState || pCharDiffHeightCJKState ) ) + ContextFontHeightFilter( pCharHeightCJKState, pCharPropHeightCJKState, + pCharDiffHeightCJKState ); + if( pCharHeightCTLState && + (pCharPropHeightCTLState || pCharDiffHeightCTLState ) ) + ContextFontHeightFilter( pCharHeightCTLState, pCharPropHeightCTLState, + pCharDiffHeightCTLState ); + if( pUnderlineColorState || pUnderlineHasColorState ) + { + bool bClear = !pUnderlineState; + if( !bClear ) + { + sal_Int16 nUnderline = 0; + pUnderlineState->maValue >>= nUnderline; + bClear = awt::FontUnderline::NONE == nUnderline; + } + if( bClear ) + { + if( pUnderlineColorState ) + pUnderlineColorState->mnIndex = -1; + if( pUnderlineHasColorState ) + pUnderlineHasColorState->mnIndex = -1; + } + } + + lcl_checkMultiProperty(pParaLeftMarginState, pParaLeftMarginRelState); + lcl_checkMultiProperty(pParaRightMarginState, pParaRightMarginRelState); + lcl_checkMultiProperty(pParaTopMarginState, pParaTopMarginRelState); + lcl_checkMultiProperty(pParaBottomMarginState, pParaBottomMarginRelState); + lcl_checkMultiProperty(pParaFirstLineState, pParaFirstLineRelState); + + if (pAllParaMarginRel) + { // because older OOo/LO versions can't read fo:margin: + pAllParaMarginRel->mnIndex = -1; // just export individual attributes... + pAllParaMarginRel->maValue.clear(); + } + if (pAllParaMargin) + { + pAllParaMargin->mnIndex = -1; // just export individual attributes... + pAllParaMargin->maValue.clear(); + } + if (pAllMargin) + { + pAllMargin->mnIndex = -1; // just export individual attributes... + pAllMargin->maValue.clear(); + } + + lcl_FilterBorders( + pAllBorderWidthState, pLeftBorderWidthState, pRightBorderWidthState, + pTopBorderWidthState, pBottomBorderWidthState, pAllBorderDistanceState, + pLeftBorderDistanceState, pRightBorderDistanceState, pTopBorderDistanceState, + pBottomBorderDistanceState, pAllBorderState, pLeftBorderState, + pRightBorderState, pTopBorderState, pBottomBorderState); + + lcl_FilterBorders( + pCharAllBorderWidthState, pCharLeftBorderWidthState, pCharRightBorderWidthState, + pCharTopBorderWidthState, pCharBottomBorderWidthState, pCharAllBorderDistanceState, + pCharLeftBorderDistanceState, pCharRightBorderDistanceState, pCharTopBorderDistanceState, + pCharBottomBorderDistanceState, pCharAllBorderState, pCharLeftBorderState, + pCharRightBorderState, pCharTopBorderState, pCharBottomBorderState); + + sal_Int16 nSizeType = SizeType::FIX; + if( pSizeTypeState ) + { + pSizeTypeState->maValue >>= nSizeType; + pSizeTypeState->mnIndex = -1; + } + + if( pHeightMinAbsState ) + { + sal_Int16 nRel = sal_Int16(); + if( (SizeType::FIX == nSizeType) || + ( pHeightMinRelState && + ( !(pHeightMinRelState->maValue >>= nRel) || nRel > 0 ) ) ) + { + pHeightMinAbsState->mnIndex = -1; + } + + // export SizeType::VARIABLE as min-width="0" + if( SizeType::VARIABLE == nSizeType ) + pHeightMinAbsState->maValue <<= static_cast<sal_Int32>( 0 ); + } + if( pHeightMinRelState && SizeType::MIN != nSizeType) + pHeightMinRelState->mnIndex = -1; + if( pHeightAbsState && pHeightMinAbsState && + -1 != pHeightMinAbsState->mnIndex ) + pHeightAbsState->mnIndex = -1; + if( pHeightRelState && SizeType::FIX != nSizeType) + pHeightRelState->mnIndex = -1; + + // frame width + nSizeType = SizeType::FIX; + if( pWidthTypeState ) + { + pWidthTypeState->maValue >>= nSizeType; + pWidthTypeState->mnIndex = -1; + } + if( pWidthMinAbsState ) + { + sal_Int16 nRel = sal_Int16(); + if( (SizeType::FIX == nSizeType) || + ( pWidthMinRelState && + ( !(pWidthMinRelState->maValue >>= nRel) || nRel > 0 ) ) ) + { + pWidthMinAbsState->mnIndex = -1; + } + + // export SizeType::VARIABLE as min-width="0" + if( SizeType::VARIABLE == nSizeType ) + pWidthMinAbsState->maValue <<= static_cast<sal_Int32>( 0 ); + } + if( pWidthMinRelState && SizeType::MIN != nSizeType) + pWidthMinRelState->mnIndex = -1; + if( pWidthAbsState && pWidthMinAbsState && + -1 != pWidthMinAbsState->mnIndex ) + pWidthAbsState->mnIndex = -1; + if( pWidthRelState && SizeType::FIX != nSizeType) + pWidthRelState->mnIndex = -1; + + if( pWrapState ) + { + WrapTextMode eVal; + pWrapState->maValue >>= eVal; + switch( eVal ) + { + case WrapTextMode_NONE: + // no wrapping: disable para-only and contour + if( pWrapParagraphOnlyState ) + pWrapParagraphOnlyState->mnIndex = -1; + [[fallthrough]]; + case WrapTextMode_THROUGH: + // wrap through: disable only contour + if( pWrapContourState ) + pWrapContourState->mnIndex = -1; + break; + default: + break; + } + if( pWrapContourModeState && + (!pWrapContourState || + !*o3tl::doAccess<bool>(pWrapContourState ->maValue) ) ) + pWrapContourModeState->mnIndex = -1; + } + + TextContentAnchorType eAnchor = TextContentAnchorType_AT_PARAGRAPH; + if( pAnchorTypeState ) + pAnchorTypeState->maValue >>= eAnchor; + else if( bNeedsAnchor ) + { + Any aAny = rPropSet->getPropertyValue("AnchorType"); + aAny >>= eAnchor; + } + + // states for frame positioning attributes + { + if( pHoriOrientState && pHoriOrientMirroredState ) + { + if( pHoriOrientMirrorState && + *o3tl::doAccess<bool>(pHoriOrientMirrorState->maValue) ) + pHoriOrientState->mnIndex = -1; + else + pHoriOrientMirroredState->mnIndex = -1; + } + if( pHoriOrientMirrorState ) + pHoriOrientMirrorState->mnIndex = -1; + + if( pHoriOrientRelState && TextContentAnchorType_AT_FRAME == eAnchor ) + pHoriOrientRelState->mnIndex = -1; + if( pHoriOrientRelFrameState && TextContentAnchorType_AT_FRAME != eAnchor ) + pHoriOrientRelFrameState->mnIndex = -1; + if (pRelWidthRel) + { + sal_Int16 nRelWidth = 0; + rPropSet->getPropertyValue("RelativeWidth") >>= nRelWidth; + if (!nRelWidth) + pRelWidthRel->mnIndex = -1; + } + + if( pVertOrientState && TextContentAnchorType_AT_CHARACTER == eAnchor ) + pVertOrientState->mnIndex = -1; + if( pVertOrientAtCharState && TextContentAnchorType_AT_CHARACTER != eAnchor ) + pVertOrientAtCharState->mnIndex = -1; + if( pVertOrientRelState && TextContentAnchorType_AT_PARAGRAPH != eAnchor && + TextContentAnchorType_AT_CHARACTER != eAnchor ) + pVertOrientRelState->mnIndex = -1; + if( pVertOrientRelPageState && TextContentAnchorType_AT_PAGE != eAnchor ) + pVertOrientRelPageState->mnIndex = -1; + if( pVertOrientRelFrameState && TextContentAnchorType_AT_FRAME != eAnchor ) + pVertOrientRelFrameState->mnIndex = -1; + if( pVertOrientRelAsCharState && TextContentAnchorType_AS_CHARACTER != eAnchor ) + pVertOrientRelAsCharState->mnIndex = -1; + if (pRelHeightRel) + { + sal_Int16 nRelHeight = 0; + rPropSet->getPropertyValue("RelativeHeight") >>= nRelHeight; + if (!nRelHeight) + pRelHeightRel->mnIndex = -1; + } + } + + // States for shape positioning properties (#i28749#) + if ( eAnchor != TextContentAnchorType_AS_CHARACTER && + !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) ) + { + // no export of shape positioning properties, + // if shape isn't anchored as-character and + // destination file format is OpenOffice.org file format + if ( pShapeHoriOrientState ) + pShapeHoriOrientState->mnIndex = -1; + if ( pShapeHoriOrientMirroredState ) + pShapeHoriOrientMirroredState->mnIndex = -1; + if ( pShapeHoriOrientRelState ) + pShapeHoriOrientRelState->mnIndex = -1; + if ( pShapeHoriOrientRelFrameState ) + pShapeHoriOrientRelFrameState->mnIndex = -1; + if ( pShapeHoriOrientMirrorState ) + pShapeHoriOrientMirrorState->mnIndex = -1; + if ( pShapeVertOrientState ) + pShapeVertOrientState->mnIndex = -1; + if ( pShapeVertOrientAtCharState ) + pShapeVertOrientAtCharState->mnIndex = -1; + if ( pShapeVertOrientRelState ) + pShapeVertOrientRelState->mnIndex = -1; + if ( pShapeVertOrientRelPageState ) + pShapeVertOrientRelPageState->mnIndex = -1; + if ( pShapeVertOrientRelFrameState ) + pShapeVertOrientRelFrameState->mnIndex = -1; + } + else + { + // handling of shape positioning property states as for frames - see above + if( pShapeHoriOrientState && pShapeHoriOrientMirroredState ) + { + if( pShapeHoriOrientMirrorState && + *o3tl::doAccess<bool>(pShapeHoriOrientMirrorState->maValue) ) + pShapeHoriOrientState->mnIndex = -1; + else + pShapeHoriOrientMirroredState->mnIndex = -1; + } + if( pShapeHoriOrientMirrorState ) + pShapeHoriOrientMirrorState->mnIndex = -1; + + if( pShapeHoriOrientRelState && TextContentAnchorType_AT_FRAME == eAnchor ) + pShapeHoriOrientRelState->mnIndex = -1; + if( pShapeHoriOrientRelFrameState && TextContentAnchorType_AT_FRAME != eAnchor ) + pShapeHoriOrientRelFrameState->mnIndex = -1; + + if( pShapeVertOrientState && TextContentAnchorType_AT_CHARACTER == eAnchor ) + pShapeVertOrientState->mnIndex = -1; + if( pShapeVertOrientAtCharState && TextContentAnchorType_AT_CHARACTER != eAnchor ) + pShapeVertOrientAtCharState->mnIndex = -1; + if( pShapeVertOrientRelState && TextContentAnchorType_AT_PARAGRAPH != eAnchor && + TextContentAnchorType_AT_CHARACTER != eAnchor ) + pShapeVertOrientRelState->mnIndex = -1; + if( pShapeVertOrientRelPageState && TextContentAnchorType_AT_PAGE != eAnchor ) + pShapeVertOrientRelPageState->mnIndex = -1; + if( pShapeVertOrientRelFrameState && TextContentAnchorType_AT_FRAME != eAnchor ) + pShapeVertOrientRelFrameState->mnIndex = -1; + } + + // list style name: remove list style if it is the default outline style + if( pListStyleName != nullptr ) + { + OUString sListStyleName; + pListStyleName->maValue >>= sListStyleName; + if( lcl_IsOutlineStyle( GetExport(), sListStyleName ) ) + pListStyleName->mnIndex = -1; + } + + if( pClipState != nullptr && pClip11State != nullptr ) + pClip11State->mnIndex = -1; + + // When both background attributes are available export the visible one + if (pCharHighlight) + { + Color nColor = COL_TRANSPARENT; + pCharHighlight->maValue >>= nColor; + if( nColor == COL_TRANSPARENT ) + { + // actually this would not be exported as transparent anyway + // and we'd need another property CharHighlightTransparent for that + pCharHighlight->mnIndex = -1; + } + // When both background attributes are available export the visible one + else if(pCharBackground) + { + assert(pCharBackgroundTransparency); // always together + pCharBackground->mnIndex = -1; + pCharBackgroundTransparency->mnIndex = -1; + } + } + + SvXMLExportPropertyMapper::ContextFilter(bEnableFoFontFamily, rProperties, rPropSet); +} + +namespace { + +bool lcl_IsOutlineStyle(const SvXMLExport &rExport, std::u16string_view rName) +{ + Reference< XChapterNumberingSupplier > + xCNSupplier(rExport.GetModel(), UNO_QUERY); + + OUString sOutlineName; + + if (xCNSupplier.is()) + { + Reference<XPropertySet> xNumRule( + xCNSupplier->getChapterNumberingRules(), UNO_QUERY ); + SAL_WARN_IF( !xNumRule.is(), "xmloff", "no chapter numbering rules" ); + if (xNumRule.is()) + { + xNumRule->getPropertyValue("Name") >>= sOutlineName; + } + } + + return rName == sOutlineName; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtexppr.hxx b/xmloff/source/text/txtexppr.hxx new file mode 100644 index 0000000000..46af0cb2bf --- /dev/null +++ b/xmloff/source/text/txtexppr.hxx @@ -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 . + */ +#pragma once + + +#include <xmloff/xmlexppr.hxx> +#include "txtdrope.hxx" +#include <xmltabe.hxx> +#include <XMLTextColumnsExport.hxx> +#include <XMLBackgroundImageExport.hxx> +#include <xmloff/XMLComplexColorExport.hxx> + +class SvXMLExport; +class XMLTextExportPropertySetMapper: public SvXMLExportPropertyMapper +{ + SvXMLExport& rExport; + + OUString sDropCharStyle; + bool bDropWholeWord; + + void ContextFontFilter( + bool bEnableFoFontFamily, + XMLPropertyState *pFontNameState, + XMLPropertyState *pFontFamilyNameState, + XMLPropertyState *pFontStyleNameState, + XMLPropertyState *pFontFamilyState, + XMLPropertyState *pFontPitchState, + XMLPropertyState *pFontCharsetState ) const; + static void ContextFontHeightFilter( + XMLPropertyState* pCharHeightState, + XMLPropertyState* pCharPropHeightState, + XMLPropertyState* pCharDiffHeightState ); + +private: +// SvXMLUnitConverter& mrUnitConverter; +// const Reference< xml::sax::XDocumentHandler > & mrHandler; + XMLTextDropCapExport maDropCapExport; + SvxXMLTabStopExport maTabStopExport; + XMLTextColumnsExport maTextColumnsExport; + XMLComplexColorExport maComplexColorExport; + XMLBackgroundImageExport maBackgroundImageExport; + + /** Application-specific filter. By default do nothing. */ + virtual void ContextFilter( + bool bEnableFoFontFamily, + ::std::vector< XMLPropertyState >& rProperties, + const css::uno::Reference< css::beans::XPropertySet >& rPropSet ) const override; + const SvXMLExport& GetExport() const { return rExport; } + +public: + + XMLTextExportPropertySetMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLExport& rExt ); + virtual ~XMLTextExportPropertySetMapper() override; + + virtual void handleElementItem( + SvXMLExport& rExport, + const XMLPropertyState& rProperty, + SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const override; + + virtual void handleSpecialItem( + comphelper::AttributeList& rAttrList, + const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const override; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtflde.cxx b/xmloff/source/text/txtflde.cxx new file mode 100644 index 0000000000..2c054d57e3 --- /dev/null +++ b/xmloff/source/text/txtflde.cxx @@ -0,0 +1,3616 @@ +/* -*- 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 . + */ + + +/** @#file + * + * export of all text fields + */ +#include <comphelper/propertyvalue.hxx> +#include <txtflde.hxx> +#include <xmloff/XMLEventExport.hxx> +#include <xmloff/families.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/numehelp.hxx> +#include <xmloff/xmlement.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/maptype.hxx> + +#include "XMLTextCharStyleNamesElementExport.hxx" +#include <sax/tools/converter.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/text/UserDataPart.hpp> +#include <com/sun/star/text/PageNumberType.hpp> +#include <com/sun/star/style/NumberingType.hpp> +#include <com/sun/star/text/ReferenceFieldPart.hpp> +#include <com/sun/star/text/ReferenceFieldSource.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/text/XTextField.hpp> +#include <com/sun/star/text/XDependentTextField.hpp> +#include <com/sun/star/text/XTextFieldsSupplier.hpp> + +#include <com/sun/star/text/SetVariableType.hpp> +#include <com/sun/star/text/PlaceholderType.hpp> +#include <com/sun/star/text/FilenameDisplayFormat.hpp> +#include <com/sun/star/text/ChapterFormat.hpp> +#include <com/sun/star/text/TemplateDisplayFormat.hpp> +#include <com/sun/star/container/XNameReplace.hpp> +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/text/BibliographyDataType.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/rdf/XMetadatable.hpp> +#include <comphelper/sequence.hxx> +#include <o3tl/any.hxx> +#include <o3tl/safeint.hxx> +#include <rtl/ustrbuf.hxx> +#include <tools/debug.hxx> +#include <rtl/math.hxx> +#include <sal/log.hxx> + +#include <vector> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::container; +using namespace ::xmloff::token; + + +char const FIELD_SERVICE_SENDER[] = "ExtendedUser"; +char const FIELD_SERVICE_AUTHOR[] = "Author"; +char const FIELD_SERVICE_JUMPEDIT[] = "JumpEdit"; +char const FIELD_SERVICE_GETEXP[] = "GetExpression"; +char const FIELD_SERVICE_SETEXP[] = "SetExpression"; +char const FIELD_SERVICE_USER[] = "User"; +char const FIELD_SERVICE_INPUT[] = "Input"; +char const FIELD_SERVICE_USERINPUT[] = "InputUser"; +char const FIELD_SERVICE_DATETIME[] = "DateTime"; +char const FIELD_SERVICE_PAGENUMBER[] = "PageNumber"; +char const FIELD_SERVICE_DB_NEXT[] = "DatabaseNextSet"; +char const FIELD_SERVICE_DB_SELECT[] = "DatabaseNumberOfSet"; +char const FIELD_SERVICE_DB_NUMBER[] = "DatabaseSetNumber"; +char const FIELD_SERVICE_DB_DISPLAY[] = "Database"; +char const FIELD_SERVICE_DB_NAME[] = "DatabaseName"; +char const FIELD_SERVICE_CONDITIONAL_TEXT[] = "ConditionalText"; +char const FIELD_SERVICE_HIDDEN_TEXT[] = "HiddenText"; +char const FIELD_SERVICE_HIDDEN_PARAGRAPH[] = "HiddenParagraph"; +char const FIELD_SERVICE_DOC_INFO_CHANGE_AUTHOR[] = "DocInfo.ChangeAuthor"; +char const FIELD_SERVICE_DOC_INFO_CHANGE_AUTHOR2[] = "docinfo.ChangeAuthor"; +char const FIELD_SERVICE_DOC_INFO_CHANGE_DATE_TIME[] = "DocInfo.ChangeDateTime"; +char const FIELD_SERVICE_DOC_INFO_CHANGE_DATE_TIME2[] = "docinfo.ChangeDateTime"; +char const FIELD_SERVICE_DOC_INFO_EDIT_TIME[] = "DocInfo.EditTime"; +char const FIELD_SERVICE_DOC_INFO_EDIT_TIME2[] = "docinfo.EditTime"; +char const FIELD_SERVICE_DOC_INFO_DESCRIPTION[] = "DocInfo.Description"; +char const FIELD_SERVICE_DOC_INFO_DESCRIPTION2[] = "docinfo.Description"; +char const FIELD_SERVICE_DOC_INFO_CREATE_AUTHOR[] = "DocInfo.CreateAuthor"; +char const FIELD_SERVICE_DOC_INFO_CREATE_AUTHOR2[] = "docinfo.CreateAuthor"; +char const FIELD_SERVICE_DOC_INFO_CREATE_DATE_TIME[] = "DocInfo.CreateDateTime"; +char const FIELD_SERVICE_DOC_INFO_CREATE_DATE_TIME2[] = "docinfo.CreateDateTime"; +char const FIELD_SERVICE_DOC_INFO_CUSTOM[] = "DocInfo.Custom"; +char const FIELD_SERVICE_DOC_INFO_CUSTOM2[] = "docinfo.Custom"; +char const FIELD_SERVICE_DOC_INFO_PRINT_AUTHOR[] = "DocInfo.PrintAuthor"; +char const FIELD_SERVICE_DOC_INFO_PRINT_AUTHOR2[] = "docinfo.PrintAuthor"; +char const FIELD_SERVICE_DOC_INFO_PRINT_DATE_TIME[] = "DocInfo.PrintDateTime"; +char const FIELD_SERVICE_DOC_INFO_PRINT_DATE_TIME2[] = "docinfo.PrintDateTime"; +char const FIELD_SERVICE_DOC_INFO_KEY_WORDS[] = "DocInfo.KeyWords"; +char const FIELD_SERVICE_DOC_INFO_KEY_WORDS2[] = "docinfo.KeyWords"; +char const FIELD_SERVICE_DOC_INFO_SUBJECT[] = "DocInfo.Subject"; +char const FIELD_SERVICE_DOC_INFO_SUBJECT2[] = "docinfo.Subject"; +char const FIELD_SERVICE_DOC_INFO_TITLE[] = "DocInfo.Title"; +char const FIELD_SERVICE_DOC_INFO_TITLE2[] = "docinfo.Title"; +char const FIELD_SERVICE_DOC_INFO_REVISION[] = "DocInfo.Revision"; +char const FIELD_SERVICE_DOC_INFO_REVISION2[] = "docinfo.Revision"; +char const FIELD_SERVICE_FILE_NAME[] = "FileName"; +char const FIELD_SERVICE_CHAPTER[] = "Chapter"; +char const FIELD_SERVICE_TEMPLATE_NAME[] = "TemplateName"; +char const FIELD_SERVICE_PAGE_COUNT[] = "PageCount"; +char const FIELD_SERVICE_PARAGRAPH_COUNT[] = "ParagraphCount"; +char const FIELD_SERVICE_WORD_COUNT[] = "WordCount"; +char const FIELD_SERVICE_CHARACTER_COUNT[] = "CharacterCount"; +char const FIELD_SERVICE_TABLE_COUNT[] = "TableCount"; +char const FIELD_SERVICE_GRAPHIC_COUNT[] = "GraphicObjectCount"; +char const FIELD_SERVICE_OBJECT_COUNT[] = "EmbeddedObjectCount"; +char const FIELD_SERVICE_REFERENCE_PAGE_SET[] = "ReferencePageSet"; +char const FIELD_SERVICE_REFERENCE_PAGE_GET[] = "ReferencePageGet"; +char const FIELD_SERVICE_SHEET_NAME[] = "SheetName"; +char const FIELD_SERVICE_PAGE_NAME[] = "PageName"; +char const FIELD_SERVICE_MACRO[] = "Macro"; +char const FIELD_SERVICE_GET_REFERENCE[] = "GetReference"; +char const FIELD_SERVICE_DDE[] = "DDE"; +char const FIELD_SERVICE_URL[] = "URL"; +char const FIELD_SERVICE_BIBLIOGRAPHY[] = "Bibliography"; +char const FIELD_SERVICE_SCRIPT[] = "Script"; +char const FIELD_SERVICE_ANNOTATION[] = "Annotation"; +char const FIELD_SERVICE_COMBINED_CHARACTERS[] = "CombinedCharacters"; +char const FIELD_SERVICE_META[] = "MetadataField"; +char const FIELD_SERVICE_MEASURE[] = "Measure"; +char const FIELD_SERVICE_TABLE_FORMULA[] = "TableFormula"; +char const FIELD_SERVICE_DROP_DOWN[] = "DropDown"; + +namespace +{ +/// Walks up the parent chain of xText and returns the topmost text. +uno::Reference<text::XText> GetToplevelText(const uno::Reference<text::XText>& xText) +{ + uno::Reference<text::XText> xRet = xText; + while (true) + { + uno::Reference<beans::XPropertySet> xPropertySet(xRet, uno::UNO_QUERY); + if (!xPropertySet.is()) + return xRet; + + if (!xPropertySet->getPropertySetInfo()->hasPropertyByName("ParentText")) + return xRet; + + uno::Reference<text::XText> xParent; + if (xPropertySet->getPropertyValue("ParentText") >>= xParent) + xRet = xParent; + else + return xRet; + } + return xRet; +} +} + +SvXMLEnumStringMapEntry<FieldIdEnum> const aFieldServiceNameMapping[] = +{ + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_SENDER, FIELD_ID_SENDER ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_AUTHOR, FIELD_ID_AUTHOR ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_JUMPEDIT, FIELD_ID_PLACEHOLDER ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_GETEXP, FIELD_ID_VARIABLE_GET ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_SETEXP, FIELD_ID_VARIABLE_SET ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_USER, FIELD_ID_USER_GET ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_INPUT, FIELD_ID_TEXT_INPUT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_USERINPUT, FIELD_ID_USER_INPUT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DATETIME, FIELD_ID_TIME ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_PAGENUMBER, FIELD_ID_PAGENUMBER ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_REFERENCE_PAGE_SET, FIELD_ID_REFPAGE_SET ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_REFERENCE_PAGE_GET, FIELD_ID_REFPAGE_GET ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DB_NEXT, FIELD_ID_DATABASE_NEXT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DB_SELECT, FIELD_ID_DATABASE_SELECT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DB_NUMBER, FIELD_ID_DATABASE_NUMBER ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DB_DISPLAY, FIELD_ID_DATABASE_DISPLAY ), + // workaround for #no-bug#: Database/DataBase + ENUM_STRING_MAP_ENTRY( "DataBase", FIELD_ID_DATABASE_DISPLAY ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DB_NAME, FIELD_ID_DATABASE_NAME ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CREATE_AUTHOR, FIELD_ID_DOCINFO_CREATION_AUTHOR ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CREATE_AUTHOR2, FIELD_ID_DOCINFO_CREATION_AUTHOR ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CREATE_DATE_TIME, FIELD_ID_DOCINFO_CREATION_TIME), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CREATE_DATE_TIME2, FIELD_ID_DOCINFO_CREATION_TIME), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CHANGE_AUTHOR, FIELD_ID_DOCINFO_SAVE_AUTHOR ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CHANGE_AUTHOR2, FIELD_ID_DOCINFO_SAVE_AUTHOR ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CHANGE_DATE_TIME, FIELD_ID_DOCINFO_SAVE_TIME ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CHANGE_DATE_TIME2, FIELD_ID_DOCINFO_SAVE_TIME ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_EDIT_TIME, FIELD_ID_DOCINFO_EDIT_DURATION ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_EDIT_TIME2, FIELD_ID_DOCINFO_EDIT_DURATION ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_DESCRIPTION, FIELD_ID_DOCINFO_DESCRIPTION ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_DESCRIPTION2, FIELD_ID_DOCINFO_DESCRIPTION ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CUSTOM, FIELD_ID_DOCINFO_CUSTOM ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CUSTOM2, FIELD_ID_DOCINFO_CUSTOM ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_PRINT_AUTHOR, FIELD_ID_DOCINFO_PRINT_AUTHOR ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_PRINT_AUTHOR2, FIELD_ID_DOCINFO_PRINT_AUTHOR ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_PRINT_DATE_TIME, FIELD_ID_DOCINFO_PRINT_TIME ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_PRINT_DATE_TIME2, FIELD_ID_DOCINFO_PRINT_TIME ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_KEY_WORDS, FIELD_ID_DOCINFO_KEYWORDS ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_KEY_WORDS2, FIELD_ID_DOCINFO_KEYWORDS ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_SUBJECT, FIELD_ID_DOCINFO_SUBJECT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_SUBJECT2, FIELD_ID_DOCINFO_SUBJECT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_TITLE, FIELD_ID_DOCINFO_TITLE ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_TITLE2, FIELD_ID_DOCINFO_TITLE ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_REVISION, FIELD_ID_DOCINFO_REVISION ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_REVISION2, FIELD_ID_DOCINFO_REVISION ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_CONDITIONAL_TEXT, FIELD_ID_CONDITIONAL_TEXT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_HIDDEN_TEXT, FIELD_ID_HIDDEN_TEXT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_HIDDEN_PARAGRAPH, FIELD_ID_HIDDEN_PARAGRAPH ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_FILE_NAME, FIELD_ID_FILE_NAME ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_CHAPTER, FIELD_ID_CHAPTER ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_TEMPLATE_NAME, FIELD_ID_TEMPLATE_NAME ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_PAGE_COUNT, FIELD_ID_COUNT_PAGES ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_PARAGRAPH_COUNT, FIELD_ID_COUNT_PARAGRAPHS ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_WORD_COUNT, FIELD_ID_COUNT_WORDS ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_CHARACTER_COUNT, FIELD_ID_COUNT_CHARACTERS ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_TABLE_COUNT, FIELD_ID_COUNT_TABLES ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_GRAPHIC_COUNT, FIELD_ID_COUNT_GRAPHICS ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_OBJECT_COUNT, FIELD_ID_COUNT_OBJECTS ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_MACRO, FIELD_ID_MACRO ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_GET_REFERENCE, FIELD_ID_REF_REFERENCE ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DDE, FIELD_ID_DDE ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_BIBLIOGRAPHY, FIELD_ID_BIBLIOGRAPHY ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_SCRIPT, FIELD_ID_SCRIPT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_ANNOTATION, FIELD_ID_ANNOTATION ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_COMBINED_CHARACTERS, FIELD_ID_COMBINED_CHARACTERS ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_META, FIELD_ID_META ), + + // non-writer fields + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_SHEET_NAME, FIELD_ID_SHEET_NAME ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_PAGE_NAME, FIELD_ID_PAGENAME ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_URL, FIELD_ID_URL ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_MEASURE, FIELD_ID_MEASURE ), + + // deprecated fields + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_TABLE_FORMULA, FIELD_ID_TABLE_FORMULA ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DROP_DOWN, FIELD_ID_DROP_DOWN ), + + { nullptr, 0, FieldIdEnum(0) } +}; + + +// property accessor helper functions +static bool GetBoolProperty(const OUString&, + const Reference<XPropertySet> &); +static bool GetOptionalBoolProperty(const OUString&, + const Reference<XPropertySet> &, + const Reference<XPropertySetInfo> &, + bool bDefault); +static double GetDoubleProperty(const OUString&, + const Reference<XPropertySet> &); +static OUString GetStringProperty(const OUString&, + const Reference<XPropertySet> &); +static sal_Int32 GetIntProperty(const OUString&, + const Reference<XPropertySet> &); +static sal_Int16 GetInt16Property(const OUString&, + const Reference<XPropertySet> &); +static sal_Int8 GetInt8Property(const OUString&, + const Reference<XPropertySet> &); +static util::DateTime GetDateTimeProperty( const OUString& sPropName, + const Reference<XPropertySet> & xPropSet); +static Sequence<OUString> GetStringSequenceProperty( + const OUString& sPropName, + const Reference<XPropertySet> & xPropSet); + + + // service names +constexpr OUString gsServicePrefix(u"com.sun.star.text.textfield."_ustr); +constexpr OUStringLiteral gsFieldMasterPrefix(u"com.sun.star.text.FieldMaster."); +constexpr OUString gsPresentationServicePrefix(u"com.sun.star.presentation.TextField."_ustr); + + // property names +constexpr OUString gsPropertyAdjust(u"Adjust"_ustr); +constexpr OUStringLiteral gsPropertyAuthor(u"Author"); +constexpr OUStringLiteral gsPropertyChapterFormat(u"ChapterFormat"); +constexpr OUStringLiteral gsPropertyChapterNumberingLevel(u"ChapterNumberingLevel"); +constexpr OUStringLiteral gsPropertyCharStyleNames(u"CharStyleNames"); +constexpr OUString gsPropertyCondition(u"Condition"_ustr); +constexpr OUString gsPropertyContent(u"Content"_ustr); +constexpr OUStringLiteral gsPropertyDataBaseName(u"DataBaseName"); +constexpr OUString gsPropertyDataBaseURL(u"DataBaseURL"_ustr); +constexpr OUStringLiteral gsPropertyDataColumnName(u"DataColumnName"); +constexpr OUString gsPropertyDataCommandType(u"DataCommandType"_ustr); +constexpr OUString gsPropertyDataTableName(u"DataTableName"_ustr); +constexpr OUString gsPropertyDateTime(u"DateTime"_ustr); +constexpr OUString gsPropertyDateTimeValue(u"DateTimeValue"_ustr); +constexpr OUStringLiteral gsPropertyDDECommandElement(u"DDECommandElement"); +constexpr OUStringLiteral gsPropertyDDECommandFile(u"DDECommandFile"); +constexpr OUStringLiteral gsPropertyDDECommandType(u"DDECommandType"); +constexpr OUStringLiteral gsPropertyDependentTextFields(u"DependentTextFields"); +constexpr OUStringLiteral gsPropertyFalseContent(u"FalseContent"); +constexpr OUStringLiteral gsPropertyFields(u"Fields"); +constexpr OUStringLiteral gsPropertyFieldSubType(u"UserDataType"); +constexpr OUString gsPropertyFileFormat(u"FileFormat"_ustr); +constexpr OUStringLiteral gsPropertyFullName(u"FullName"); +constexpr OUString gsPropertyHint(u"Hint"_ustr); +constexpr OUStringLiteral gsPropertyInitials(u"Initials"); +constexpr OUStringLiteral gsPropertyInstanceName(u"InstanceName"); +constexpr OUStringLiteral gsPropertyIsAutomaticUpdate(u"IsAutomaticUpdate"); +constexpr OUStringLiteral gsPropertyIsConditionTrue(u"IsConditionTrue"); +constexpr OUString gsPropertyIsDataBaseFormat(u"DataBaseFormat"_ustr); +constexpr OUString gsPropertyIsDate(u"IsDate"_ustr); +constexpr OUString gsPropertyIsExpression(u"IsExpression"_ustr); +constexpr OUString gsPropertyIsFixed(u"IsFixed"_ustr); +constexpr OUString gsPropertyIsFixedLanguage(u"IsFixedLanguage"_ustr); +constexpr OUString gsPropertyIsHidden(u"IsHidden"_ustr); +constexpr OUStringLiteral gsPropertyIsInput(u"Input"); +constexpr OUString gsPropertyIsShowFormula(u"IsShowFormula"_ustr); +constexpr OUString gsPropertyIsVisible(u"IsVisible"_ustr); +constexpr OUStringLiteral gsPropertyItems(u"Items"); +constexpr OUStringLiteral gsPropertyLevel(u"Level"); +constexpr OUStringLiteral gsPropertyMeasureKind(u"Kind"); +constexpr OUString gsPropertyName(u"Name"_ustr); +constexpr OUStringLiteral gsPropertyParentName(u"ParentName"); +constexpr OUString gsPropertyNumberFormat(u"NumberFormat"_ustr); +constexpr OUStringLiteral gsPropertyNumberingSeparator(u"NumberingSeparator"); +constexpr OUString gsPropertyNumberingType(u"NumberingType"_ustr); +constexpr OUString gsPropertyOffset(u"Offset"_ustr); +constexpr OUStringLiteral gsPropertyOn(u"On"); +constexpr OUStringLiteral gsPropertyPlaceholderType(u"PlaceHolderType"); +constexpr OUString gsPropertyReferenceFieldFlags(u"ReferenceFieldFlags"_ustr); +constexpr OUString gsPropertyReferenceFieldPart(u"ReferenceFieldPart"_ustr); +constexpr OUString gsPropertyReferenceFieldSource(u"ReferenceFieldSource"_ustr); +constexpr OUString gsPropertyReferenceFieldLanguage(u"ReferenceFieldLanguage"_ustr); +constexpr OUStringLiteral gsPropertyScriptType(u"ScriptType"); +constexpr OUStringLiteral gsPropertySelectedItem(u"SelectedItem"); +constexpr OUString gsPropertySequenceNumber(u"SequenceNumber"_ustr); +constexpr OUStringLiteral gsPropertySequenceValue(u"SequenceValue"); +constexpr OUString gsPropertySetNumber(u"SetNumber"_ustr); +constexpr OUString gsPropertySourceName(u"SourceName"_ustr); +constexpr OUString gsPropertySubType(u"SubType"_ustr); +constexpr OUStringLiteral gsPropertyTargetFrame(u"TargetFrame"); +constexpr OUStringLiteral gsPropertyTrueContent(u"TrueContent"); +constexpr OUStringLiteral gsPropertyURL(u"URL"); +constexpr OUStringLiteral gsPropertyURLContent(u"URLContent"); +constexpr OUStringLiteral gsPropertyUserText(u"UserText"); +constexpr OUString gsPropertyValue(u"Value"_ustr); +constexpr OUString gsPropertyVariableName(u"VariableName"_ustr); +constexpr OUString gsPropertyHelp(u"Help"_ustr); +constexpr OUString gsPropertyTooltip(u"Tooltip"_ustr); +constexpr OUStringLiteral gsPropertyTextRange(u"TextRange"); + +XMLTextFieldExport::XMLTextFieldExport( SvXMLExport& rExp, + std::unique_ptr<XMLPropertyState> pCombinedCharState) + : rExport(rExp), + pCombinedCharactersPropertyState(std::move(pCombinedCharState)) +{ + SetExportOnlyUsedFieldDeclarations(); +} + +XMLTextFieldExport::~XMLTextFieldExport() +{ +} + +/// get the field ID (as in FieldIDEnum) from XTextField +enum FieldIdEnum XMLTextFieldExport::GetFieldID( + const Reference<XTextField> & rTextField, + const Reference<XPropertySet> & xPropSet) +{ + // get service names for rTextField (via XServiceInfo service) + Reference<XServiceInfo> xService(rTextField, UNO_QUERY); + const Sequence<OUString> aServices = xService->getSupportedServiceNames(); + + OUString sFieldName; // service name postfix of current field + + // search for TextField service name + const OUString* pNames = std::find_if(aServices.begin(), aServices.end(), + [](const OUString& rName) { return rName.matchIgnoreAsciiCase(gsServicePrefix); }); + if (pNames != aServices.end()) + { + // TextField found => postfix is field type! + sFieldName = pNames->copy(gsServicePrefix.getLength()); + } + + // if this is not a normal text field, check if it's a presentation text field + if( sFieldName.isEmpty() ) + { + // search for TextField service name + pNames = std::find_if(aServices.begin(), aServices.end(), + [](const OUString& rName) { return rName.startsWith(gsPresentationServicePrefix); }); + if (pNames != aServices.end()) + { + // TextField found => postfix is field type! + sFieldName = pNames->copy(gsPresentationServicePrefix.getLength()); + } + + if( !sFieldName.isEmpty() ) + { + if( sFieldName == "Header" ) + { + return FIELD_ID_DRAW_HEADER; + } + else if( sFieldName == "Footer" ) + { + return FIELD_ID_DRAW_FOOTER; + } + else if( sFieldName == "DateTime" ) + { + return FIELD_ID_DRAW_DATE_TIME; + } + } + } + + // map postfix of service name to field ID + DBG_ASSERT(!sFieldName.isEmpty(), "no TextField service found!"); + return MapFieldName(sFieldName, xPropSet); +} + +enum FieldIdEnum XMLTextFieldExport::MapFieldName( + std::u16string_view sFieldName, // field (master) name + const Reference<XPropertySet> & xPropSet) // for subtype +{ + // we'll proceed in 2 steps: + // a) map service name to preliminary FIELD_ID + // b) map those prelim. FIELD_IDs that correspond to several field types + // (in our (XML) world) to final FIELD IDs + + + // a) find prelim. FIELD_ID via aFieldServiceMapping + + // check for non-empty service name + DBG_ASSERT(!sFieldName.empty(), "no valid service name!"); + enum FieldIdEnum nToken = FIELD_ID_UNKNOWN; + if (!sFieldName.empty()) + { + // map name to prelim. ID + bool bRet = SvXMLUnitConverter::convertEnum( + nToken, sFieldName, aFieldServiceNameMapping); + + // check return + DBG_ASSERT(bRet, "Unknown field service name encountered!"); + } + + // b) map prelim. to final FIELD_IDs + switch (nToken) { + case FIELD_ID_VARIABLE_SET: + if (GetBoolProperty(gsPropertyIsInput, xPropSet)) + { + nToken = FIELD_ID_VARIABLE_INPUT; + } + else + { + switch (GetIntProperty(gsPropertySubType, xPropSet)) + { + case SetVariableType::STRING: // text field + case SetVariableType::VAR: // num field + nToken = FIELD_ID_VARIABLE_SET; + break; + case SetVariableType::SEQUENCE: + nToken = FIELD_ID_SEQUENCE; + break; + case SetVariableType::FORMULA: + default: + nToken = FIELD_ID_UNKNOWN; + break; + } + } + break; + + case FIELD_ID_VARIABLE_GET: + switch (GetIntProperty(gsPropertySubType, xPropSet)) + { + case SetVariableType::STRING: // text field + case SetVariableType::VAR: // num field + nToken = FIELD_ID_VARIABLE_GET; + break; + case SetVariableType::FORMULA: + nToken = FIELD_ID_EXPRESSION; + break; + case SetVariableType::SEQUENCE: + default: + nToken = FIELD_ID_UNKNOWN; + break; + } + break; + + case FIELD_ID_TIME: + if (GetBoolProperty(gsPropertyIsDate, xPropSet)) + { + nToken = FIELD_ID_DATE; + } + break; + + case FIELD_ID_PAGENUMBER: + // NumberingType not available in non-Writer apps + if (xPropSet->getPropertySetInfo()-> + hasPropertyByName(gsPropertyNumberingType)) + { + if (NumberingType::CHAR_SPECIAL == GetIntProperty( + gsPropertyNumberingType, xPropSet)) + { + nToken = FIELD_ID_PAGESTRING; + } + } + break; + + case FIELD_ID_DOCINFO_CREATION_TIME: + if (GetBoolProperty(gsPropertyIsDate, xPropSet)) + { + nToken = FIELD_ID_DOCINFO_CREATION_DATE; + } + break; + + case FIELD_ID_DOCINFO_PRINT_TIME: + if (GetBoolProperty(gsPropertyIsDate, xPropSet)) + { + nToken = FIELD_ID_DOCINFO_PRINT_DATE; + } + break; + + case FIELD_ID_DOCINFO_SAVE_TIME: + if (GetBoolProperty(gsPropertyIsDate, xPropSet)) + { + nToken = FIELD_ID_DOCINFO_SAVE_DATE; + } + break; + + case FIELD_ID_REF_REFERENCE: + switch (GetInt16Property(gsPropertyReferenceFieldSource, xPropSet)) + { + case ReferenceFieldSource::REFERENCE_MARK: + nToken = FIELD_ID_REF_REFERENCE; + break; + case ReferenceFieldSource::SEQUENCE_FIELD: + nToken = FIELD_ID_REF_SEQUENCE; + break; + case ReferenceFieldSource::BOOKMARK: + nToken = FIELD_ID_REF_BOOKMARK; + break; + case ReferenceFieldSource::FOOTNOTE: + nToken = FIELD_ID_REF_FOOTNOTE; + break; + case ReferenceFieldSource::ENDNOTE: + nToken = FIELD_ID_REF_ENDNOTE; + break; + case ReferenceFieldSource::STYLE: + nToken = FIELD_ID_REF_STYLE; + break; + default: + nToken = FIELD_ID_UNKNOWN; + break; + } + break; + + case FIELD_ID_COMBINED_CHARACTERS: + case FIELD_ID_SCRIPT: + case FIELD_ID_ANNOTATION: + case FIELD_ID_BIBLIOGRAPHY: + case FIELD_ID_DDE: + case FIELD_ID_MACRO: + case FIELD_ID_REFPAGE_SET: + case FIELD_ID_REFPAGE_GET: + case FIELD_ID_COUNT_PAGES: + case FIELD_ID_COUNT_PARAGRAPHS: + case FIELD_ID_COUNT_WORDS: + case FIELD_ID_COUNT_CHARACTERS: + case FIELD_ID_COUNT_TABLES: + case FIELD_ID_COUNT_GRAPHICS: + case FIELD_ID_COUNT_OBJECTS: + case FIELD_ID_CONDITIONAL_TEXT: + case FIELD_ID_HIDDEN_TEXT: + case FIELD_ID_HIDDEN_PARAGRAPH: + case FIELD_ID_DOCINFO_CREATION_AUTHOR: + case FIELD_ID_DOCINFO_DESCRIPTION: + case FIELD_ID_DOCINFO_CUSTOM: + case FIELD_ID_DOCINFO_PRINT_AUTHOR: + case FIELD_ID_DOCINFO_TITLE: + case FIELD_ID_DOCINFO_SUBJECT: + case FIELD_ID_DOCINFO_KEYWORDS: + case FIELD_ID_DOCINFO_REVISION: + case FIELD_ID_DOCINFO_EDIT_DURATION: + case FIELD_ID_DOCINFO_SAVE_AUTHOR: + case FIELD_ID_TEXT_INPUT: + case FIELD_ID_USER_INPUT: + case FIELD_ID_AUTHOR: + case FIELD_ID_SENDER: + case FIELD_ID_PLACEHOLDER: + case FIELD_ID_USER_GET: + case FIELD_ID_DATABASE_NEXT: + case FIELD_ID_DATABASE_SELECT: + case FIELD_ID_DATABASE_DISPLAY: + case FIELD_ID_DATABASE_NAME: + case FIELD_ID_DATABASE_NUMBER: + case FIELD_ID_TEMPLATE_NAME: + case FIELD_ID_CHAPTER: + case FIELD_ID_FILE_NAME: + case FIELD_ID_META: + case FIELD_ID_SHEET_NAME: + case FIELD_ID_PAGENAME: + case FIELD_ID_MEASURE: + case FIELD_ID_URL: + case FIELD_ID_TABLE_FORMULA: + case FIELD_ID_DROP_DOWN: + ; // these field IDs are final + break; + + default: + nToken = FIELD_ID_UNKNOWN; + } + + // ... and return final FIELD_ID + return nToken; +} + +// is string or numeric field? +bool XMLTextFieldExport::IsStringField( + FieldIdEnum nFieldType, + const Reference<XPropertySet> & xPropSet) +{ + switch (nFieldType) { + + case FIELD_ID_VARIABLE_GET: + case FIELD_ID_VARIABLE_SET: + case FIELD_ID_VARIABLE_INPUT: + { + // depends on field sub type + return ( GetIntProperty(gsPropertySubType, xPropSet) == + SetVariableType::STRING ); + } + + case FIELD_ID_USER_GET: + case FIELD_ID_USER_INPUT: + { + Reference<XTextField> xTextField(xPropSet, UNO_QUERY); + DBG_ASSERT(xTextField.is(), "field is no XTextField!"); + bool bRet = GetBoolProperty(gsPropertyIsExpression, + GetMasterPropertySet(xTextField)); + return !bRet; + } + + case FIELD_ID_META: + return 0 > GetIntProperty(gsPropertyNumberFormat, xPropSet); + + case FIELD_ID_DATABASE_DISPLAY: + // TODO: depends on... ??? + // workaround #no-bug#: no data type + return 5100 == GetIntProperty(gsPropertyNumberFormat, xPropSet); + + case FIELD_ID_TABLE_FORMULA: + // legacy field: always a number field (because it always has + // a number format) + return false; + + case FIELD_ID_COUNT_PAGES: + case FIELD_ID_COUNT_PARAGRAPHS: + case FIELD_ID_COUNT_WORDS: + case FIELD_ID_COUNT_CHARACTERS: + case FIELD_ID_COUNT_TABLES: + case FIELD_ID_COUNT_GRAPHICS: + case FIELD_ID_COUNT_OBJECTS: + case FIELD_ID_DOCINFO_SAVE_TIME: + case FIELD_ID_DOCINFO_SAVE_DATE: + case FIELD_ID_DOCINFO_CREATION_DATE: + case FIELD_ID_DOCINFO_CREATION_TIME: + case FIELD_ID_DOCINFO_PRINT_TIME: + case FIELD_ID_DOCINFO_PRINT_DATE: + case FIELD_ID_DOCINFO_EDIT_DURATION: + case FIELD_ID_DOCINFO_REVISION: + case FIELD_ID_DATABASE_NUMBER: + case FIELD_ID_EXPRESSION: + case FIELD_ID_SEQUENCE: + case FIELD_ID_DATE: + case FIELD_ID_TIME: + case FIELD_ID_PAGENUMBER: + case FIELD_ID_REFPAGE_SET: + case FIELD_ID_REFPAGE_GET: + case FIELD_ID_DOCINFO_CUSTOM: + // always number + return false; + + case FIELD_ID_COMBINED_CHARACTERS: + case FIELD_ID_BIBLIOGRAPHY: + case FIELD_ID_DDE: + case FIELD_ID_REF_REFERENCE: + case FIELD_ID_REF_SEQUENCE: + case FIELD_ID_REF_BOOKMARK: + case FIELD_ID_REF_FOOTNOTE: + case FIELD_ID_REF_ENDNOTE: + case FIELD_ID_REF_STYLE: + case FIELD_ID_MACRO: + case FIELD_ID_TEMPLATE_NAME: + case FIELD_ID_CHAPTER: + case FIELD_ID_FILE_NAME: + case FIELD_ID_CONDITIONAL_TEXT: + case FIELD_ID_HIDDEN_TEXT: + case FIELD_ID_HIDDEN_PARAGRAPH: + case FIELD_ID_DOCINFO_CREATION_AUTHOR: + case FIELD_ID_DOCINFO_DESCRIPTION: + case FIELD_ID_DOCINFO_PRINT_AUTHOR: + case FIELD_ID_DOCINFO_TITLE: + case FIELD_ID_DOCINFO_SUBJECT: + case FIELD_ID_DOCINFO_KEYWORDS: + case FIELD_ID_DOCINFO_SAVE_AUTHOR: + case FIELD_ID_DATABASE_NAME: + case FIELD_ID_TEXT_INPUT: + case FIELD_ID_SENDER: + case FIELD_ID_AUTHOR: + case FIELD_ID_PAGENAME: + case FIELD_ID_PAGESTRING: + case FIELD_ID_SHEET_NAME: + case FIELD_ID_MEASURE: + case FIELD_ID_URL: + case FIELD_ID_DROP_DOWN: + // always string: + return true; + + case FIELD_ID_SCRIPT: + case FIELD_ID_ANNOTATION: + case FIELD_ID_DATABASE_NEXT: + case FIELD_ID_DATABASE_SELECT: + case FIELD_ID_PLACEHOLDER: + case FIELD_ID_UNKNOWN: + case FIELD_ID_DRAW_HEADER: + case FIELD_ID_DRAW_FOOTER: + case FIELD_ID_DRAW_DATE_TIME: + default: + OSL_FAIL("unknown field type/field has no content"); + return true; // invalid info; string in case of doubt + } +} + +/// export the styles needed by the given field. Called on first pass +/// through document +void XMLTextFieldExport::ExportFieldAutoStyle( + const Reference<XTextField> & rTextField, const bool bProgress, + const bool bRecursive ) +{ + // get property set + Reference<XPropertySet> xPropSet(rTextField, UNO_QUERY); + + // add field master to list of used field masters (if desired) + if (nullptr != pUsedMasters) + { + Reference<XDependentTextField> xDepField(rTextField, UNO_QUERY); + if (xDepField.is()) + { + // The direct parent may be just the table cell, while we want the topmost parent, e.g. + // a header text. + Reference<XText> xOurText = GetToplevelText(rTextField->getAnchor()->getText()); + + std::map<Reference<XText>, std::set<OUString> >::iterator aMapIter = + pUsedMasters->find(xOurText); + + // insert a list for our XText (if necessary) + if (aMapIter == pUsedMasters->end()) + { + std::set<OUString> aSet; + (*pUsedMasters)[xOurText] = aSet; + aMapIter = pUsedMasters->find(xOurText); + } + + // insert this text field master + OUString sFieldMasterName = GetStringProperty( + gsPropertyInstanceName, xDepField->getTextFieldMaster()); + if (!sFieldMasterName.isEmpty()) + aMapIter->second.insert( sFieldMasterName ); + } + // else: no dependent field -> no master -> ignore + } + + // get Field ID + FieldIdEnum nToken = GetFieldID(rTextField, xPropSet); + + // export the character style for all fields + // with one exception: combined character fields export their own + // text style below + Reference <XPropertySet> xRangePropSet(rTextField->getAnchor(), UNO_QUERY); + if (FIELD_ID_COMBINED_CHARACTERS != nToken) + { + GetExport().GetTextParagraphExport()->Add( + XmlStyleFamily::TEXT_TEXT, xRangePropSet); + } + + // process special styles for each field (e.g. data styles) + switch (nToken) { + + case FIELD_ID_DATABASE_DISPLAY: + { + sal_Int32 nFormat = GetIntProperty(gsPropertyNumberFormat, xPropSet); + // workaround: #no-bug#; see IsStringField(...) + if ( (5100 != nFormat) && + !GetBoolProperty(gsPropertyIsDataBaseFormat, xPropSet) ) + { + GetExport().addDataStyle(nFormat); + } + break; + } + + case FIELD_ID_DATE: + case FIELD_ID_TIME: + { + // date and time fields are always number fields, but the + // NumberFormat property is optional (e.g. Calc doesn't + // support it) + Reference<XPropertySetInfo> xPropSetInfo( + xPropSet->getPropertySetInfo() ); + if ( xPropSetInfo->hasPropertyByName( gsPropertyNumberFormat ) ) + { + sal_Int32 nFormat = + GetIntProperty(gsPropertyNumberFormat, xPropSet); + + // nFormat may be -1 for numeric fields that display their + // variable name. (Maybe this should be a field type, then?) + if (nFormat != -1) + { + if( ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + xPropSet, xPropSetInfo, false ) ) + { + nFormat = + GetExport().dataStyleForceSystemLanguage(nFormat); + } + + GetExport().addDataStyle( nFormat, + nToken == FIELD_ID_TIME ); + } + } + } + break; + + case FIELD_ID_META: + // recurse into content (does not export element, so can be done first) + if (bRecursive) + { + bool dummy_for_autostyles(true); + ExportMetaField(xPropSet, true, bProgress, dummy_for_autostyles); + } + [[fallthrough]]; + case FIELD_ID_DOCINFO_PRINT_TIME: + case FIELD_ID_DOCINFO_PRINT_DATE: + case FIELD_ID_DOCINFO_CREATION_DATE: + case FIELD_ID_DOCINFO_CREATION_TIME: + case FIELD_ID_DOCINFO_SAVE_TIME: + case FIELD_ID_DOCINFO_SAVE_DATE: + case FIELD_ID_DOCINFO_EDIT_DURATION: + case FIELD_ID_VARIABLE_SET: + case FIELD_ID_VARIABLE_GET: + case FIELD_ID_VARIABLE_INPUT: + case FIELD_ID_USER_GET: + case FIELD_ID_EXPRESSION: + case FIELD_ID_TABLE_FORMULA: + case FIELD_ID_DOCINFO_CUSTOM: + // register number format, if this is a numeric field + if (! IsStringField(nToken, xPropSet)) { + + sal_Int32 nFormat = + GetIntProperty(gsPropertyNumberFormat, xPropSet); + + // nFormat may be -1 for numeric fields that display their + // variable name. (Maybe this should be a field type, then?) + if (nFormat != -1) + { + // handle formats for fixed language fields + // for all these fields (except table formula) + if( ( nToken != FIELD_ID_TABLE_FORMULA ) && + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + xPropSet, xPropSet->getPropertySetInfo(), + false ) ) + { + nFormat = + GetExport().dataStyleForceSystemLanguage(nFormat); + } + + GetExport().addDataStyle(nFormat); + } + } + break; + + case FIELD_ID_COMBINED_CHARACTERS: + { + // export text style with the addition of the combined characters + DBG_ASSERT(nullptr != pCombinedCharactersPropertyState, + "need proper PropertyState for combined characters"); + std::span<XMLPropertyState> aStates( pCombinedCharactersPropertyState.get(), 1 ); + GetExport().GetTextParagraphExport()->Add( + XmlStyleFamily::TEXT_TEXT, xRangePropSet, + aStates); + break; + } + + case FIELD_ID_SCRIPT: + case FIELD_ID_ANNOTATION: + case FIELD_ID_BIBLIOGRAPHY: + case FIELD_ID_DDE: + case FIELD_ID_REF_REFERENCE: + case FIELD_ID_REF_SEQUENCE: + case FIELD_ID_REF_BOOKMARK: + case FIELD_ID_REF_FOOTNOTE: + case FIELD_ID_REF_ENDNOTE: + case FIELD_ID_REF_STYLE: + case FIELD_ID_MACRO: + case FIELD_ID_REFPAGE_SET: + case FIELD_ID_REFPAGE_GET: + case FIELD_ID_COUNT_PAGES: + case FIELD_ID_COUNT_PARAGRAPHS: + case FIELD_ID_COUNT_WORDS: + case FIELD_ID_COUNT_CHARACTERS: + case FIELD_ID_COUNT_TABLES: + case FIELD_ID_COUNT_GRAPHICS: + case FIELD_ID_COUNT_OBJECTS: + case FIELD_ID_CONDITIONAL_TEXT: + case FIELD_ID_HIDDEN_TEXT: + case FIELD_ID_HIDDEN_PARAGRAPH: + case FIELD_ID_DOCINFO_CREATION_AUTHOR: + case FIELD_ID_DOCINFO_DESCRIPTION: + case FIELD_ID_DOCINFO_PRINT_AUTHOR: + case FIELD_ID_DOCINFO_TITLE: + case FIELD_ID_DOCINFO_SUBJECT: + case FIELD_ID_DOCINFO_KEYWORDS: + case FIELD_ID_DOCINFO_REVISION: + case FIELD_ID_DOCINFO_SAVE_AUTHOR: + case FIELD_ID_SEQUENCE: + case FIELD_ID_PAGENAME: + case FIELD_ID_PAGENUMBER: + case FIELD_ID_PAGESTRING: + case FIELD_ID_AUTHOR: + case FIELD_ID_SENDER: + case FIELD_ID_PLACEHOLDER: + case FIELD_ID_USER_INPUT: + case FIELD_ID_TEXT_INPUT: + case FIELD_ID_DATABASE_NEXT: + case FIELD_ID_DATABASE_SELECT: + case FIELD_ID_DATABASE_NAME: + case FIELD_ID_DATABASE_NUMBER: + case FIELD_ID_TEMPLATE_NAME: + case FIELD_ID_CHAPTER: + case FIELD_ID_FILE_NAME: + case FIELD_ID_SHEET_NAME: + case FIELD_ID_MEASURE: + case FIELD_ID_URL: + case FIELD_ID_DROP_DOWN: + case FIELD_ID_DRAW_DATE_TIME: + case FIELD_ID_DRAW_FOOTER: + case FIELD_ID_DRAW_HEADER: + ; // no formats for these fields! + break; + + case FIELD_ID_UNKNOWN: + default: + OSL_FAIL("unknown field type!"); + // ignore -> no format for unknown + break; + } +} + +/// export the given field to XML. Called on second pass through document +void XMLTextFieldExport::ExportField( + const Reference<XTextField> & rTextField, bool bProgress, + bool & rPrevCharIsSpace) +{ + // get property set + Reference<XPropertySet> xPropSet(rTextField, UNO_QUERY); + + // get property set of range (for the attributes) + Reference <XPropertySet> xRangePropSet(rTextField->getAnchor(), UNO_QUERY); + + // get Field ID + enum FieldIdEnum nToken = GetFieldID(rTextField, xPropSet); + + // special treatment for combined characters field, because it is + // exported as a style + const XMLPropertyState* aStates[] = { pCombinedCharactersPropertyState.get(), nullptr }; + const XMLPropertyState **pStates = + FIELD_ID_COMBINED_CHARACTERS == nToken + ? aStates + : nullptr; + + // find out whether we need to set the style + bool bIsUICharStyle; + bool bHasAutoStyle; + OUString sStyle = GetExport().GetTextParagraphExport()-> + FindTextStyle( xRangePropSet, bIsUICharStyle, bHasAutoStyle, pStates ); + bool bHasStyle = !sStyle.isEmpty(); + + { + Reference<XPropertySetInfo> xRangePropSetInfo; + XMLTextCharStyleNamesElementExport aCharStylesExport( + GetExport(), bIsUICharStyle && + GetExport().GetTextParagraphExport() + ->GetCharStyleNamesPropInfoCache().hasProperty( + xRangePropSet, xRangePropSetInfo ), bHasAutoStyle, + xRangePropSet, gsPropertyCharStyleNames ); + + // export span with style (if necessary) + // (except for combined characters field) + if( bHasStyle ) + { + // export <text:span> element + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sStyle ) ); + } + SvXMLElementExport aSpan( GetExport(), bHasStyle, + XML_NAMESPACE_TEXT, XML_SPAN, + false, false); + + // finally, export the field itself + ExportFieldHelper( rTextField, xPropSet, xRangePropSet, nToken, + bProgress, rPrevCharIsSpace); + } +} + +/// export the given field to XML. Called on second pass through document +void XMLTextFieldExport::ExportFieldHelper( + const Reference<XTextField> & rTextField, + const Reference<XPropertySet> & rPropSet, + const Reference<XPropertySet> &, + enum FieldIdEnum nToken, + bool bProgress, + bool & rPrevCharIsSpace) +{ + // get property set info (because some attributes are not support + // in all implementations) + Reference<XPropertySetInfo> xPropSetInfo(rPropSet->getPropertySetInfo()); + + OUString sPresentation = rTextField->getPresentation(false); + + // process each field type + switch (nToken) { + case FIELD_ID_AUTHOR: + // author field: fixed, field (sub-)type + if (xPropSetInfo->hasPropertyByName(gsPropertyIsFixed)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_FIXED, + (GetBoolProperty(gsPropertyIsFixed, rPropSet) ? XML_TRUE : XML_FALSE) ); + } + ExportElement(MapAuthorFieldName(rPropSet), sPresentation); + break; + + case FIELD_ID_SENDER: + // sender field: fixed, field (sub-)type + ProcessBoolean(XML_FIXED, + GetBoolProperty(gsPropertyIsFixed, rPropSet), true); + ExportElement(MapSenderFieldName(rPropSet), sPresentation); + break; + + case FIELD_ID_PLACEHOLDER: + // placeholder field: type, name, description + ProcessString(XML_PLACEHOLDER_TYPE, + MapPlaceholderType( + GetInt16Property(gsPropertyPlaceholderType, rPropSet))); + ProcessString(XML_DESCRIPTION, + GetStringProperty(gsPropertyHint,rPropSet), true); + ExportElement(XML_PLACEHOLDER, sPresentation); + break; + + case FIELD_ID_VARIABLE_SET: + { + // variable set field: name, visible, format&value + ProcessString(XML_NAME, + GetStringProperty(gsPropertyVariableName, rPropSet)); + ProcessDisplay(GetBoolProperty(gsPropertyIsVisible, rPropSet), + false); + ProcessString(XML_FORMULA, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyContent, rPropSet), + sPresentation); + ProcessValueAndType(IsStringField(nToken, rPropSet), + GetIntProperty(gsPropertyNumberFormat, rPropSet), + GetStringProperty(gsPropertyContent, rPropSet), + sPresentation, + GetDoubleProperty(gsPropertyValue, rPropSet), + true, true, true, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false ) ); + ExportElement(XML_VARIABLE_SET, sPresentation); + break; + } + case FIELD_ID_VARIABLE_GET: + { + // variable get field: name, format&value + ProcessString(XML_NAME, + GetStringProperty(gsPropertyContent, rPropSet)); + bool bCmd = GetBoolProperty(gsPropertyIsShowFormula, rPropSet); + ProcessDisplay(true, bCmd); + // show style, unless name will be shown + ProcessValueAndType(IsStringField(nToken, rPropSet), + GetIntProperty(gsPropertyNumberFormat, rPropSet), + "", u"", 0.0, // values not used + false, + false, + !bCmd, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false ) ); + ExportElement(XML_VARIABLE_GET, sPresentation); + break; + } + case FIELD_ID_VARIABLE_INPUT: + // variable input field: name, description, format&value + ProcessString(XML_NAME, + GetStringProperty(gsPropertyVariableName, rPropSet)); + ProcessString(XML_DESCRIPTION, + GetStringProperty(gsPropertyHint , rPropSet)); + ProcessDisplay(GetBoolProperty(gsPropertyIsVisible, rPropSet), + false); + ProcessString(XML_FORMULA, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyContent, rPropSet), + sPresentation); + ProcessValueAndType(IsStringField(nToken, rPropSet), + GetIntProperty(gsPropertyNumberFormat, rPropSet), + GetStringProperty(gsPropertyContent, rPropSet), + sPresentation, + GetDoubleProperty(gsPropertyValue, rPropSet), + true, true, true, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false ) ); + ExportElement(XML_VARIABLE_INPUT, sPresentation); + break; + + case FIELD_ID_USER_GET: + // user field: name, hidden, style + { + bool bCmd = GetBoolProperty(gsPropertyIsShowFormula, rPropSet); + ProcessDisplay(GetBoolProperty(gsPropertyIsVisible, rPropSet), + bCmd); + ProcessValueAndType(IsStringField(nToken, rPropSet), + GetIntProperty(gsPropertyNumberFormat, rPropSet), + "", u"", 0.0, // values not used + false, false, !bCmd, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false ) ); + + // name from FieldMaster + ProcessString(XML_NAME, + GetStringProperty(gsPropertyName, + GetMasterPropertySet(rTextField))); + ExportElement(XML_USER_FIELD_GET, sPresentation); + break; + } + + case FIELD_ID_USER_INPUT: + // user input field: name (from FieldMaster), description +// ProcessString(XML_NAME, +// GetStringProperty(sPropertyName, +// GetMasterPropertySet(rTextField))); + ProcessString(XML_NAME, + GetStringProperty(gsPropertyContent, rPropSet)); + ProcessString(XML_DESCRIPTION, + GetStringProperty(gsPropertyHint, rPropSet)); + ExportElement(XML_USER_FIELD_INPUT, sPresentation); + break; + + case FIELD_ID_SEQUENCE: + { + // sequence field: name, formula, seq-format + OUString sName = GetStringProperty(gsPropertyVariableName, rPropSet); + // TODO: use reference name only if actually being referenced. + ProcessString(XML_REF_NAME, + MakeSequenceRefName( + GetInt16Property(gsPropertySequenceValue, rPropSet), + sName)); + ProcessString(XML_NAME, sName); + ProcessString(XML_FORMULA, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyContent, rPropSet), + sPresentation); + ProcessNumberingType(GetInt16Property(gsPropertyNumberingType, + rPropSet)); + ExportElement(XML_SEQUENCE, sPresentation); + break; + } + + case FIELD_ID_EXPRESSION: + { + // formula field: formula, format&value + bool bCmd = GetBoolProperty(gsPropertyIsShowFormula, rPropSet); + ProcessString(XML_FORMULA, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyContent, rPropSet), + sPresentation); + ProcessDisplay(true, bCmd); + ProcessValueAndType(IsStringField(nToken, rPropSet), + GetIntProperty(gsPropertyNumberFormat, rPropSet), + GetStringProperty(gsPropertyContent, rPropSet), + sPresentation, + GetDoubleProperty(gsPropertyValue, rPropSet), + !bCmd, !bCmd, !bCmd, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false ) ); + ExportElement(XML_EXPRESSION, sPresentation); + break; + } + + case FIELD_ID_TEXT_INPUT: + // text input field: description and string-value + ProcessString(XML_DESCRIPTION, + GetStringProperty(gsPropertyHint, rPropSet)); + ProcessString(XML_HELP, + GetStringProperty(gsPropertyHelp, rPropSet), true); + ProcessString(XML_HINT, + GetStringProperty(gsPropertyTooltip, rPropSet), true); + ExportElement(XML_TEXT_INPUT, sPresentation); + break; + + case FIELD_ID_TIME: + // all properties (except IsDate) are optional! + if (xPropSetInfo->hasPropertyByName(gsPropertyNumberFormat)) + { + ProcessValueAndType(false, + GetIntProperty(gsPropertyNumberFormat,rPropSet), + "", u"", 0.0, // not used + false, false, true, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false ), + true); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyDateTimeValue)) + { + // no value -> current time + ProcessTimeOrDateTime(XML_TIME_VALUE, + GetDateTimeProperty(gsPropertyDateTimeValue, + rPropSet)); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyDateTime)) + { + // no value -> current time + ProcessTimeOrDateTime(XML_TIME_VALUE, + GetDateTimeProperty(gsPropertyDateTime,rPropSet)); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyIsFixed)) + { + ProcessBoolean(XML_FIXED, + GetBoolProperty(gsPropertyIsFixed, rPropSet), + false); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyAdjust)) + { + // adjust value given as integer in minutes + ProcessDateTime(XML_TIME_ADJUST, + GetIntProperty(gsPropertyAdjust, rPropSet), + false, true); + } + ExportElement(XML_TIME, sPresentation); + break; + + case FIELD_ID_DATE: + // all properties (except IsDate) are optional! + if (xPropSetInfo->hasPropertyByName(gsPropertyNumberFormat)) + { + ProcessValueAndType(false, + GetIntProperty(gsPropertyNumberFormat,rPropSet), + "", u"", 0.0, // not used + false, false, true, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false ) ); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyDateTimeValue)) + { + // no value -> current date + ProcessDateTime(XML_DATE_VALUE, + GetDateTimeProperty(gsPropertyDateTimeValue, + rPropSet)); + } + // TODO: remove double-handling after SRC614 + else if (xPropSetInfo->hasPropertyByName(gsPropertyDateTime)) + { + ProcessDateTime(XML_DATE_VALUE, + GetDateTimeProperty(gsPropertyDateTime,rPropSet)); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyIsFixed)) + { + ProcessBoolean(XML_FIXED, + GetBoolProperty(gsPropertyIsFixed, rPropSet), + false); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyAdjust)) + { + // adjust value given as number of days + ProcessDateTime(XML_DATE_ADJUST, + GetIntProperty(gsPropertyAdjust, rPropSet), + true, true); + } + ExportElement(XML_DATE, sPresentation); + break; + + case FIELD_ID_PAGENUMBER: + // all properties are optional + if (xPropSetInfo->hasPropertyByName(gsPropertyNumberingType)) + { + ProcessNumberingType(GetInt16Property(gsPropertyNumberingType, + rPropSet)); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyOffset)) + { + sal_Int32 nAdjust = GetIntProperty(gsPropertyOffset, rPropSet); + + if (xPropSetInfo->hasPropertyByName(gsPropertySubType)) + { + // property SubType used in MapPageNumberName + ProcessString(XML_SELECT_PAGE, + MapPageNumberName(rPropSet, nAdjust)); + } + ProcessIntegerDef(XML_PAGE_ADJUST, nAdjust, 0); + } + ExportElement(XML_PAGE_NUMBER, sPresentation); + break; + + case FIELD_ID_PAGESTRING: + { + ProcessString(XML_STRING_VALUE, + GetStringProperty(gsPropertyUserText, rPropSet), + sPresentation); + sal_Int32 nDummy = 0; // MapPageNumberName need int + ProcessString(XML_SELECT_PAGE, MapPageNumberName(rPropSet, nDummy)); + ExportElement(XML_PAGE_CONTINUATION, sPresentation); + break; + } + + case FIELD_ID_DATABASE_NAME: + ProcessString(XML_TABLE_NAME, + GetStringProperty(gsPropertyDataTableName, rPropSet)); + ProcessCommandType(GetIntProperty(gsPropertyDataCommandType, rPropSet)); + ProcessDisplay(GetBoolProperty(gsPropertyIsVisible, rPropSet), + false); + ExportDataBaseElement(XML_DATABASE_NAME, sPresentation, + rPropSet, xPropSetInfo); + break; + + case FIELD_ID_DATABASE_NUMBER: + ProcessString(XML_TABLE_NAME, + GetStringProperty(gsPropertyDataTableName, rPropSet)); + ProcessCommandType(GetIntProperty(gsPropertyDataCommandType, rPropSet)); + ProcessNumberingType( + GetInt16Property(gsPropertyNumberingType,rPropSet)); + ProcessInteger(XML_VALUE, + GetIntProperty(gsPropertySetNumber, rPropSet)); + ProcessDisplay(GetBoolProperty(gsPropertyIsVisible, rPropSet), + false); + ExportDataBaseElement(XML_DATABASE_ROW_NUMBER, sPresentation, + rPropSet, xPropSetInfo); + break; + + case FIELD_ID_DATABASE_NEXT: + ProcessString(XML_TABLE_NAME, + GetStringProperty(gsPropertyDataTableName, rPropSet)); + ProcessCommandType(GetIntProperty(gsPropertyDataCommandType, rPropSet)); + ProcessString(XML_CONDITION, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyCondition, rPropSet)); + DBG_ASSERT(sPresentation.isEmpty(), + "Unexpected presentation for database next field"); + ExportDataBaseElement(XML_DATABASE_NEXT, OUString(), + rPropSet, xPropSetInfo); + break; + + case FIELD_ID_DATABASE_SELECT: + ProcessString(XML_TABLE_NAME, + GetStringProperty(gsPropertyDataTableName, rPropSet)); + ProcessCommandType(GetIntProperty(gsPropertyDataCommandType, rPropSet)); + ProcessString(XML_CONDITION, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyCondition, rPropSet)); + ProcessInteger(XML_ROW_NUMBER, + GetIntProperty(gsPropertySetNumber, rPropSet)); + DBG_ASSERT(sPresentation.isEmpty(), + "Unexpected presentation for database select field"); + ExportDataBaseElement(XML_DATABASE_ROW_SELECT, OUString(), + rPropSet, xPropSetInfo); + break; + + case FIELD_ID_DATABASE_DISPLAY: + { + // get database, table and column name from field master + const Reference<XPropertySet> & xMaster = GetMasterPropertySet(rTextField); + ProcessString(XML_TABLE_NAME, + GetStringProperty(gsPropertyDataTableName, xMaster)); + ProcessCommandType(GetIntProperty(gsPropertyDataCommandType, xMaster)); + ProcessString(XML_COLUMN_NAME, + GetStringProperty(gsPropertyDataColumnName, xMaster)); + // export number format if available (happens only for numbers!) + if (!GetBoolProperty(gsPropertyIsDataBaseFormat, rPropSet)) + { + ProcessValueAndType(false, // doesn't happen for text + GetIntProperty(gsPropertyNumberFormat,rPropSet), + "", u"", 0.0, // not used + false, false, true, false); + } + ProcessDisplay(GetBoolProperty(gsPropertyIsVisible, rPropSet), + false); + ExportDataBaseElement(XML_DATABASE_DISPLAY, sPresentation, + xMaster, xMaster->getPropertySetInfo()); + break; + } + + case FIELD_ID_DOCINFO_REVISION: + ProcessBoolean(XML_FIXED, + GetBoolProperty(gsPropertyIsFixed, rPropSet), false); + ExportElement(MapDocInfoFieldName(nToken), sPresentation); + break; + + case FIELD_ID_DOCINFO_EDIT_DURATION: + case FIELD_ID_DOCINFO_SAVE_TIME: + case FIELD_ID_DOCINFO_CREATION_TIME: + case FIELD_ID_DOCINFO_PRINT_TIME: + case FIELD_ID_DOCINFO_SAVE_DATE: + case FIELD_ID_DOCINFO_CREATION_DATE: + case FIELD_ID_DOCINFO_PRINT_DATE: + ProcessValueAndType(false, + GetIntProperty(gsPropertyNumberFormat, rPropSet), + "", u"", 0.0, + false, false, true, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false ) ); + + // todo: export date/time value, but values not available -> core bug + ProcessBoolean(XML_FIXED, + GetBoolProperty(gsPropertyIsFixed, rPropSet), false); + ExportElement(MapDocInfoFieldName(nToken), sPresentation); + break; + + case FIELD_ID_DOCINFO_CREATION_AUTHOR: + case FIELD_ID_DOCINFO_DESCRIPTION: + case FIELD_ID_DOCINFO_PRINT_AUTHOR: + case FIELD_ID_DOCINFO_TITLE: + case FIELD_ID_DOCINFO_SUBJECT: + case FIELD_ID_DOCINFO_KEYWORDS: + case FIELD_ID_DOCINFO_SAVE_AUTHOR: + if (xPropSetInfo->hasPropertyByName(gsPropertyIsFixed)) + { + ProcessBoolean(XML_FIXED, + GetBoolProperty(gsPropertyIsFixed, rPropSet), false); + } + ExportElement(MapDocInfoFieldName(nToken), sPresentation); + break; + + case FIELD_ID_DOCINFO_CUSTOM: + { + ProcessValueAndType(false, // doesn't happen for text + GetIntProperty(gsPropertyNumberFormat,rPropSet), + "", u"", 0.0, // not used + false, false, true, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false )); + uno::Any aAny = rPropSet->getPropertyValue( gsPropertyName ); + OUString sName; + aAny >>= sName; + ProcessString(XML_NAME, sName); + ProcessBoolean(XML_FIXED, GetBoolProperty(gsPropertyIsFixed, rPropSet), false); + ExportElement(XML_USER_DEFINED, sPresentation); + break; + } + + case FIELD_ID_COUNT_PAGES: + case FIELD_ID_COUNT_PARAGRAPHS: + case FIELD_ID_COUNT_WORDS: + case FIELD_ID_COUNT_CHARACTERS: + case FIELD_ID_COUNT_TABLES: + case FIELD_ID_COUNT_GRAPHICS: + case FIELD_ID_COUNT_OBJECTS: + // all properties optional (applies to pages only, but I'll do + // it for all for sake of common implementation) + if (xPropSetInfo->hasPropertyByName(gsPropertyNumberingType)) + { + ProcessNumberingType(GetInt16Property(gsPropertyNumberingType, + rPropSet)); + } + ExportElement(MapCountFieldName(nToken), sPresentation); + break; + + case FIELD_ID_CONDITIONAL_TEXT: + ProcessString(XML_CONDITION, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyCondition, rPropSet)); + ProcessString(XML_STRING_VALUE_IF_TRUE, + GetStringProperty(gsPropertyTrueContent, rPropSet)); + ProcessString(XML_STRING_VALUE_IF_FALSE, + GetStringProperty(gsPropertyFalseContent, rPropSet)); + ProcessBoolean(XML_CURRENT_VALUE, + GetBoolProperty(gsPropertyIsConditionTrue, rPropSet), + false); + ExportElement(XML_CONDITIONAL_TEXT, sPresentation); + break; + + case FIELD_ID_HIDDEN_TEXT: + ProcessString(XML_CONDITION, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyCondition, rPropSet)); + ProcessString(XML_STRING_VALUE, + GetStringProperty(gsPropertyContent, rPropSet)); + ProcessBoolean(XML_IS_HIDDEN, + GetBoolProperty(gsPropertyIsHidden, rPropSet), + false); + ExportElement(XML_HIDDEN_TEXT, sPresentation); + break; + + case FIELD_ID_HIDDEN_PARAGRAPH: + ProcessString(XML_CONDITION, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyCondition, rPropSet)); + ProcessBoolean(XML_IS_HIDDEN, + GetBoolProperty(gsPropertyIsHidden, rPropSet), + false); + DBG_ASSERT(sPresentation.isEmpty(), + "Unexpected presentation for hidden paragraph field"); + ExportElement(XML_HIDDEN_PARAGRAPH); + break; + + case FIELD_ID_TEMPLATE_NAME: + ProcessString(XML_DISPLAY, + MapTemplateDisplayFormat( + GetInt16Property(gsPropertyFileFormat, rPropSet))); + ExportElement(XML_TEMPLATE_NAME, sPresentation); + break; + + case FIELD_ID_CHAPTER: + ProcessString(XML_DISPLAY, + MapChapterDisplayFormat( + GetInt16Property(gsPropertyChapterFormat, rPropSet))); + // API numbers 0..9, we number 1..10 + ProcessInteger(XML_OUTLINE_LEVEL, + GetInt8Property(gsPropertyLevel, rPropSet) + 1); + ExportElement(XML_CHAPTER, sPresentation); + break; + + case FIELD_ID_FILE_NAME: + // all properties are optional + if (xPropSetInfo->hasPropertyByName(gsPropertyFileFormat)) + { + ProcessString(XML_DISPLAY, + MapFilenameDisplayFormat( + GetInt16Property(gsPropertyFileFormat, rPropSet))); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyIsFixed)) + { + ProcessBoolean(XML_FIXED, + GetBoolProperty(gsPropertyIsFixed, rPropSet), + false); + } + ExportElement(XML_FILE_NAME, sPresentation); + break; + + case FIELD_ID_REFPAGE_SET: + ProcessBoolean(XML_ACTIVE, + GetBoolProperty(gsPropertyOn, rPropSet), true); + ProcessIntegerDef(XML_PAGE_ADJUST, + GetInt16Property(gsPropertyOffset, rPropSet), 0); + DBG_ASSERT(sPresentation.isEmpty(), + "Unexpected presentation page variable field"); + ExportElement(XML_PAGE_VARIABLE_SET); + break; + + case FIELD_ID_REFPAGE_GET: + ProcessNumberingType( + GetInt16Property(gsPropertyNumberingType, rPropSet)); + ExportElement(XML_PAGE_VARIABLE_GET, sPresentation); + break; + + case FIELD_ID_MACRO: + ExportMacro( rPropSet, sPresentation ); + break; + + case FIELD_ID_REF_SEQUENCE: + // reference to sequence: format, name, find value (and element) + // was: if (nSeqNumber != -1) ... + ProcessString(XML_REFERENCE_FORMAT, + MapReferenceType(GetInt16Property( + gsPropertyReferenceFieldPart, rPropSet)), + XML_TEMPLATE); + ProcessString(XML_REF_NAME, + MakeSequenceRefName( + GetInt16Property(gsPropertySequenceNumber, rPropSet), + GetStringProperty(gsPropertySourceName, rPropSet) ) ); + if (xPropSetInfo->hasPropertyByName(gsPropertyReferenceFieldLanguage) && + GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + // export text:reference-language attribute, if not empty + ProcessString(XML_REFERENCE_LANGUAGE, + GetStringProperty(gsPropertyReferenceFieldLanguage, rPropSet), true, XML_NAMESPACE_LO_EXT); + } + ExportElement( + MapReferenceSource( + GetInt16Property(gsPropertyReferenceFieldSource, rPropSet)), + sPresentation); + break; + + case FIELD_ID_REF_REFERENCE: + case FIELD_ID_REF_BOOKMARK: + // reference to bookmarks, references: format, name (and element) + ProcessString(XML_REFERENCE_FORMAT, + MapReferenceType(GetInt16Property( + gsPropertyReferenceFieldPart, rPropSet)), + XML_TEMPLATE); + ProcessString(XML_REF_NAME, + GetStringProperty(gsPropertySourceName, rPropSet)); + if (xPropSetInfo->hasPropertyByName(gsPropertyReferenceFieldLanguage) && + GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + // export text:reference-language attribute, if not empty + ProcessString(XML_REFERENCE_LANGUAGE, + GetStringProperty(gsPropertyReferenceFieldLanguage, rPropSet), true, XML_NAMESPACE_LO_EXT); + } + ExportElement( + MapReferenceSource(GetInt16Property( + gsPropertyReferenceFieldSource, rPropSet)), + sPresentation); + break; + + case FIELD_ID_REF_FOOTNOTE: + case FIELD_ID_REF_ENDNOTE: + // reference to end-/footnote: format, generate name, (and element) + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_NOTE_CLASS, + FIELD_ID_REF_ENDNOTE==nToken ? XML_ENDNOTE : XML_FOOTNOTE ); + ProcessString(XML_REFERENCE_FORMAT, + MapReferenceType(GetInt16Property( + gsPropertyReferenceFieldPart, rPropSet)), + XML_TEMPLATE); + ProcessString(XML_REF_NAME, + MakeFootnoteRefName(GetInt16Property( + gsPropertySequenceNumber, rPropSet))); + if (xPropSetInfo->hasPropertyByName(gsPropertyReferenceFieldLanguage) && + GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + // export text:reference-language attribute, if not empty + ProcessString(XML_REFERENCE_LANGUAGE, + GetStringProperty(gsPropertyReferenceFieldLanguage, rPropSet), true, XML_NAMESPACE_LO_EXT); + } + ExportElement( + MapReferenceSource(GetInt16Property( + gsPropertyReferenceFieldSource, rPropSet)), + sPresentation); + break; + + case FIELD_ID_REF_STYLE: + { + ProcessString(XML_REFERENCE_FORMAT, + MapReferenceType(GetInt16Property(gsPropertyReferenceFieldPart, rPropSet)), + XML_TEMPLATE); + ProcessString(XML_REF_NAME, GetStringProperty(gsPropertySourceName, rPropSet)); + + sal_uInt16 referenceFieldFlags = GetIntProperty(gsPropertyReferenceFieldFlags, rPropSet); + // In reality gsPropertyReferenceFieldFlags is a uInt16... but there is no GetUInt16Property + + bool fromBottom = (referenceFieldFlags & REFFLDFLAG_STYLE_FROM_BOTTOM) == REFFLDFLAG_STYLE_FROM_BOTTOM; + bool hideNonNumerical = (referenceFieldFlags & REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL) == REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL; + + ProcessBoolean(XML_REFERENCE_FROM_BOTTOM, fromBottom, false, XML_NAMESPACE_LO_EXT); + ProcessBoolean(XML_REFERENCE_HIDE_NON_NUMERICAL, hideNonNumerical, false, XML_NAMESPACE_LO_EXT); + + if (xPropSetInfo->hasPropertyByName(gsPropertyReferenceFieldLanguage) + && GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + // export text:reference-language attribute, if not empty + ProcessString(XML_REFERENCE_LANGUAGE, + GetStringProperty(gsPropertyReferenceFieldLanguage, rPropSet), true, + XML_NAMESPACE_LO_EXT); + } + SvXMLElementExport aElem( + GetExport(), + XML_NAMESPACE_LO_EXT, + MapReferenceSource(GetInt16Property(gsPropertyReferenceFieldSource, rPropSet)), + false, + false); + GetExport().Characters(sPresentation); + break; + } + + case FIELD_ID_DDE: + // name from field master + ProcessString(XML_CONNECTION_NAME, + + GetStringProperty(gsPropertyName, + GetMasterPropertySet(rTextField))); + ExportElement(XML_DDE_CONNECTION, sPresentation); + break; + + case FIELD_ID_SHEET_NAME: + // name of spreadsheet (Calc only) + ExportElement(XML_SHEET_NAME, sPresentation); + break; + + case FIELD_ID_PAGENAME: + { + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_LO_EXT, XML_PAGE_NAME, false, false ); + GetExport().Characters( sPresentation ); + } + break; + } + + case FIELD_ID_URL: + { + // this field is a special case because it gets mapped onto a + // hyperlink, rather than one of the regular text field. + ProcessString(XML_HREF, GetExport().GetRelativeReference(GetStringProperty(gsPropertyURL, rPropSet)), + false, XML_NAMESPACE_XLINK); + ProcessString(XML_TARGET_FRAME_NAME, + GetStringProperty(gsPropertyTargetFrame,rPropSet), + true, XML_NAMESPACE_OFFICE); + GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + SvXMLElementExport aUrlField(rExport, XML_NAMESPACE_TEXT, XML_A, + false, false); + GetExport().Characters(sPresentation); + break; + } + + case FIELD_ID_BIBLIOGRAPHY: + { + ProcessBibliographyData(rPropSet); + ExportElement(XML_BIBLIOGRAPHY_MARK, sPresentation); + break; + } + + case FIELD_ID_SCRIPT: + ProcessString(XML_LANGUAGE, + GetStringProperty(gsPropertyScriptType, rPropSet), + true, XML_NAMESPACE_SCRIPT); + DBG_ASSERT(sPresentation.isEmpty(), + "Unexpected presentation for script field"); + if (GetBoolProperty(gsPropertyURLContent, rPropSet)) + { + ProcessString(XML_HREF, + GetExport().GetRelativeReference(GetStringProperty(gsPropertyContent, rPropSet)), + false, XML_NAMESPACE_XLINK); + ExportElement(XML_SCRIPT); + } + else + { + ExportElement(XML_SCRIPT, + GetStringProperty(gsPropertyContent, rPropSet)); + } + break; + + case FIELD_ID_ANNOTATION: + { + // check for empty presentation (just in case) + DBG_ASSERT(sPresentation.isEmpty(), + "Unexpected presentation for annotation field"); + + bool bRemovePersonalInfo = SvtSecurityOptions::IsOptionSet( + SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo ) && !SvtSecurityOptions::IsOptionSet( + SvtSecurityOptions::EOption::DocWarnKeepNoteAuthorDateInfo); + + // annotation element + content + OUString aName; + rPropSet->getPropertyValue(gsPropertyName) >>= aName; + if (!aName.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_OFFICE, XML_NAME, aName); + } + + OUString aParentName; + rPropSet->getPropertyValue(gsPropertyParentName) >>= aParentName; + if (!aParentName.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_PARENT_NAME, aParentName); + } + + SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); + if (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) + { + bool b = GetBoolProperty("Resolved", rPropSet); + OUString aResolvedText; + OUStringBuffer aResolvedTextBuffer; + ::sax::Converter::convertBool(aResolvedTextBuffer, b); + aResolvedText = aResolvedTextBuffer.makeStringAndClear(); + + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_RESOLVED, aResolvedText); + } + SvXMLElementExport aElem(GetExport(), XML_NAMESPACE_OFFICE, + XML_ANNOTATION, false, true); + + // author + OUString aAuthor( GetStringProperty(gsPropertyAuthor, rPropSet) ); + if( !aAuthor.isEmpty() ) + { + SvXMLElementExport aCreatorElem( GetExport(), XML_NAMESPACE_DC, + XML_CREATOR, true, + false ); + GetExport().Characters( bRemovePersonalInfo + ? "Author" + OUString::number( rExport.GetInfoID(aAuthor) ) + : aAuthor ); + } + + // date time + util::DateTime aDate( GetDateTimeProperty(gsPropertyDateTimeValue, rPropSet) ); + if ( !bRemovePersonalInfo ) + { + OUStringBuffer aBuffer; + ::sax::Converter::convertDateTime(aBuffer, aDate, nullptr, true); + SvXMLElementExport aDateElem( GetExport(), XML_NAMESPACE_DC, + XML_DATE, true, + false ); + GetExport().Characters(aBuffer.makeStringAndClear()); + } + + if (GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012) + { + // initials + OUString aInitials( GetStringProperty(gsPropertyInitials, rPropSet) ); + if( !aInitials.isEmpty() ) + { + // ODF 1.3 OFFICE-3776 export meta:creator-initials for ODF 1.3 + SvXMLElementExport aCreatorElem( GetExport(), + (SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion()) + ? XML_NAMESPACE_META + : XML_NAMESPACE_LO_EXT, + + (SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion()) + ? XML_CREATOR_INITIALS + : XML_SENDER_INITIALS, + true, false ); + GetExport().Characters( bRemovePersonalInfo + ? OUString::number( rExport.GetInfoID(aInitials) ) + : aInitials); + } + } + + css::uno::Reference < css::text::XText > xText; + try + { + css::uno::Any aRet = rPropSet->getPropertyValue(gsPropertyTextRange); + aRet >>= xText; + } + catch ( css::uno::Exception& ) + {} + + if ( xText.is() ) + GetExport().GetTextParagraphExport()->exportText( xText ); + else + ProcessParagraphSequence(GetStringProperty(gsPropertyContent,rPropSet)); + break; + } + + case FIELD_ID_COMBINED_CHARACTERS: + { + // The style with the combined characters attribute has + // already been handled in the ExportField method. So all that + // is left to do now is to export the characters. + GetExport().Characters(sPresentation); + break; + } + + case FIELD_ID_META: + { + ExportMetaField(rPropSet, false, bProgress, rPrevCharIsSpace); + break; + } + + case FIELD_ID_MEASURE: + { + ProcessString(XML_KIND, MapMeasureKind(GetInt16Property(gsPropertyMeasureKind, rPropSet))); + ExportElement( XML_MEASURE, sPresentation ); + break; + } + + case FIELD_ID_TABLE_FORMULA: + ProcessString( XML_FORMULA, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyContent, rPropSet) ); + ProcessDisplay( true, + GetBoolProperty(gsPropertyIsShowFormula, rPropSet) ); + ProcessValueAndType( false, + GetIntProperty(gsPropertyNumberFormat, rPropSet), + "", u"", 0.0f, + false, false, true, + false ); + ExportElement( XML_TABLE_FORMULA, sPresentation ); + break; + + case FIELD_ID_DROP_DOWN: + { + // tdf#133555 don't export in strict ODF versions that don't have it + if (GetExport().getSaneDefaultVersion() <= SvtSaveOptions::ODFSVER_012) + { + break; + } + ProcessString(XML_NAME, GetStringProperty(gsPropertyName, rPropSet)); + ProcessString(XML_HELP, + GetStringProperty(gsPropertyHelp, rPropSet), true); + ProcessString(XML_HINT, + GetStringProperty(gsPropertyTooltip, rPropSet), true); + SvXMLElementExport aElem( GetExport(), + XML_NAMESPACE_TEXT, XML_DROP_DOWN, + false, false ); + ProcessStringSequence + (GetStringSequenceProperty( gsPropertyItems, rPropSet ), + GetStringProperty( gsPropertySelectedItem, rPropSet ) ); + + GetExport().Characters( sPresentation ); + } + break; + + case FIELD_ID_DRAW_HEADER: + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_PRESENTATION, XML_HEADER, false, false ); + } + break; + + case FIELD_ID_DRAW_FOOTER: + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_PRESENTATION, XML_FOOTER, false, false ); + } + break; + + case FIELD_ID_DRAW_DATE_TIME: + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_PRESENTATION, XML_DATE_TIME, false, false ); + } + break; + + + case FIELD_ID_UNKNOWN: + default: + OSL_FAIL("unknown field type encountered!"); + // always export content + GetExport().Characters(sPresentation); + } +} + + +/// export field declarations / field masters +void XMLTextFieldExport::ExportFieldDeclarations() +{ + Reference<XText> xEmptyText; + ExportFieldDeclarations(xEmptyText); +} + +/// export field declarations / field masters +void XMLTextFieldExport::ExportFieldDeclarations( + const Reference<XText> & rText ) +{ + // store lists for decl elements + std::vector<OUString> aVarName; + std::vector<OUString> aUserName; + std::vector<OUString> aSeqName; + std::vector<OUString> aDdeName; + + // get text fields supplier and field master name access + Reference<XTextFieldsSupplier> xTextFieldsSupp(GetExport().GetModel(), + UNO_QUERY); + if( !xTextFieldsSupp.is() ) + return; + + Reference<container::XNameAccess> xFieldMasterNameAccess = + xTextFieldsSupp->getTextFieldMasters(); + + // where to get the text field masters from? + // a) we get a specific XText: then use pUsedMasters + // b) the XText is empty: then export all text fields + Sequence<OUString> aFieldMasters; + if (rText.is()) + { + // export only used masters + DBG_ASSERT(nullptr != pUsedMasters, + "field masters must be recorded in order to be " + "written out separately" ); + if (nullptr != pUsedMasters) + { + std::map<Reference<XText>, std::set<OUString> > ::iterator aMapIter = + pUsedMasters->find(rText); + if (aMapIter != pUsedMasters->end()) + { + // found the set of used field masters + aFieldMasters = comphelper::containerToSequence(aMapIter->second); + pUsedMasters->erase(rText); + } + // else: XText not found -> ignore + } + // else: no field masters have been recorded -> ignore + } + else + { + // no XText: export all! + aFieldMasters = xFieldMasterNameAccess->getElementNames(); + } + + for(const OUString& sFieldMaster : std::as_const(aFieldMasters)) { + + // workaround for #no-bug# + if ( sFieldMaster.startsWithIgnoreAsciiCase( + "com.sun.star.text.FieldMaster.DataBase.") ) + { + continue; + } + + + OUString sFieldMasterType; + OUString sVarName; + ExplodeFieldMasterName(sFieldMaster, sFieldMasterType, sVarName); + + // get XPropertySet of this field master + Reference<XPropertySet> xPropSet; + Any aAny = xFieldMasterNameAccess->getByName(sFieldMaster); + aAny >>= xPropSet; + + // save interesting field masters + if (sFieldMasterType == FIELD_SERVICE_SETEXP) + { + sal_Int32 nType = GetIntProperty(gsPropertySubType, xPropSet); + + // sequence or variable? + if ( SetVariableType::SEQUENCE == nType ) + { + aSeqName.push_back( sFieldMaster ); + } + else + { + aVarName.push_back( sFieldMaster ); + } + } + else if (sFieldMasterType == FIELD_SERVICE_USER) + { + aUserName.push_back( sFieldMaster ); + } + else if (sFieldMasterType == FIELD_SERVICE_DDE) + { + aDdeName.push_back( sFieldMaster ); + } + else + { + ; // ignore + } + } + + // now process fields: + + // variable field masters: + if ( !aVarName.empty() ) + { + SvXMLElementExport aElem( GetExport(), + XML_NAMESPACE_TEXT, + XML_VARIABLE_DECLS, + true, true ); + + for (const auto& sName : aVarName) + { + // get field master property set + Reference<XPropertySet> xPropSet; + Any aAny = xFieldMasterNameAccess->getByName(sName); + aAny >>= xPropSet; + + // field name and type + OUString sFieldMasterType; + OUString sVarName; + ExplodeFieldMasterName(sName, sFieldMasterType, sVarName); + + // determine string/numeric field + bool bIsString = ( GetIntProperty(gsPropertySubType, xPropSet) + == SetVariableType::STRING ); + + // get dependent field property set + Reference<XPropertySet> xFieldPropSet; + if (GetDependentFieldPropertySet(xPropSet, xFieldPropSet)) + { + // process value and type. + ProcessValueAndType( + bIsString, + GetIntProperty(gsPropertyNumberFormat, xFieldPropSet), + "", u"", 0.0, + false, true, false, false); + } + else + { + // If no dependent field is found, only string and + // float types can be supported + + // number format: 0 is default number format for 1st + // language. should be: getDefaultNumberFormat(Locale) + // from NumberFormats + ProcessValueAndType( + bIsString, + 0, "", u"", 0.0, + false, true, false, false); + } + + ProcessString(XML_NAME, sVarName); + ExportElement(XML_VARIABLE_DECL, true); + } + } + // else: no declarations element + + // sequence field masters: + if ( !aSeqName.empty() ) + { + SvXMLElementExport aElem( GetExport(), + XML_NAMESPACE_TEXT, + XML_SEQUENCE_DECLS, + true, true ); + + for (const auto& sName : aSeqName) + { + // get field master property set + Reference<XPropertySet> xPropSet; + Any aAny = xFieldMasterNameAccess->getByName(sName); + aAny >>= xPropSet; + + // field name and type + OUString sFieldMasterType; + OUString sVarName; + ExplodeFieldMasterName(sName, sFieldMasterType, sVarName); + + // outline level + sal_Int32 nLevel = 1 + GetIntProperty( + gsPropertyChapterNumberingLevel, xPropSet); + DBG_ASSERT(nLevel >= 0, "illegal outline level"); + DBG_ASSERT(nLevel < 127, "possible illegal outline level"); + ProcessInteger(XML_DISPLAY_OUTLINE_LEVEL, nLevel); + + // separation character + if (nLevel > 0) { + ProcessString(XML_SEPARATION_CHARACTER, GetStringProperty( + gsPropertyNumberingSeparator, xPropSet)); + } + ProcessString(XML_NAME, sVarName); + ExportElement(XML_SEQUENCE_DECL, true); + } + } + // else: no declarations element + + // user field masters: + if ( !aUserName.empty() ) + { + SvXMLElementExport aElem( GetExport(), + XML_NAMESPACE_TEXT, + XML_USER_FIELD_DECLS, + true, true ); + + for (const auto& sName : aUserName) + { + // get field master property set + Reference<XPropertySet> xPropSet; + Any aAny = xFieldMasterNameAccess->getByName(sName); + aAny >>= xPropSet; + + // field name and type + OUString sFieldMasterType; + OUString sVarName; + ExplodeFieldMasterName(sName, sFieldMasterType, sVarName); + + if (GetBoolProperty(gsPropertyIsExpression, xPropSet)) + { + // expression: + ProcessValueAndType( + false, + 0, "", u"", + GetDoubleProperty(gsPropertyValue, xPropSet), + true, + true, + false, + false); + } + else + { + // string: write regardless of default + ProcessString(XML_VALUE_TYPE, XML_STRING, + XML_NAMESPACE_OFFICE); + ProcessString(XML_STRING_VALUE, + GetStringProperty(gsPropertyContent, xPropSet), + false, XML_NAMESPACE_OFFICE ); + } + ProcessString(XML_NAME, sVarName); + ExportElement(XML_USER_FIELD_DECL, true); + } + } + // else: no declarations element + + // DDE field masters: + if ( aDdeName.empty() ) + return; + + SvXMLElementExport aElem( GetExport(), + XML_NAMESPACE_TEXT, + XML_DDE_CONNECTION_DECLS, + true, true ); + + for (const auto& sName : aDdeName) + { + // get field master property set + Reference<XPropertySet> xPropSet; + Any aAny = xFieldMasterNameAccess->getByName(sName); + aAny >>= xPropSet; + + // check if this connection is being used by a field + Reference<XPropertySet> xDummy; + if (GetDependentFieldPropertySet(xPropSet, xDummy)) + { + + ProcessString(XML_NAME, + GetStringProperty(gsPropertyName, xPropSet), + false, XML_NAMESPACE_OFFICE); + + // export elements; can't use ProcessString because + // elements are in office namespace + ProcessString(XML_DDE_APPLICATION, + GetStringProperty(gsPropertyDDECommandType, + xPropSet), + false, XML_NAMESPACE_OFFICE); + ProcessString(XML_DDE_TOPIC, + GetStringProperty(gsPropertyDDECommandFile, + xPropSet), + false, XML_NAMESPACE_OFFICE); + ProcessString(XML_DDE_ITEM, + GetStringProperty(gsPropertyDDECommandElement, + xPropSet), + false, XML_NAMESPACE_OFFICE); + bool bIsAutomaticUpdate = GetBoolProperty( + gsPropertyIsAutomaticUpdate, xPropSet); + if (bIsAutomaticUpdate) + { + GetExport().AddAttribute(XML_NAMESPACE_OFFICE, + XML_AUTOMATIC_UPDATE, + XML_TRUE); + } + + ExportElement(XML_DDE_CONNECTION_DECL, true); + } + // else: no dependent field -> no export of field declaration + } + // else: no declarations element +} + +void XMLTextFieldExport::SetExportOnlyUsedFieldDeclarations( + bool bExportOnlyUsed) +{ + pUsedMasters.reset(); + + // create used masters set (if none is used) + if (bExportOnlyUsed) + pUsedMasters.reset( new std::map<Reference<XText>, std::set<OUString> > ); +} + +void XMLTextFieldExport::ExportElement(enum XMLTokenEnum eElementName, + bool bAddSpace) +{ + // can't call ExportElement(eElementName, const OUString&) with empty + // string because xmlprinter only uses empty tags if no content + // (not even empty content) was written. + + DBG_ASSERT(XML_TOKEN_INVALID != eElementName, "invalid element name!"); + if (XML_TOKEN_INVALID != eElementName) + { + // Element + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + eElementName, bAddSpace, bAddSpace ); + } // else: ignore +} + +void XMLTextFieldExport::ExportElement(enum XMLTokenEnum eElementName, + const OUString& sContent) +{ + DBG_ASSERT(eElementName != XML_TOKEN_INVALID, "invalid element name!"); + if (eElementName != XML_TOKEN_INVALID) + { + // Element + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + eElementName, false, false ); + // export content + GetExport().Characters(sContent); + } else { + // always export content + GetExport().Characters(sContent); + } +} + +void XMLTextFieldExport::ExportMacro( + const Reference<XPropertySet> & rPropSet, + const OUString& rContent ) +{ + // some strings we'll need + OUString sEventType( "EventType" ); + + + // the description attribute + ProcessString(XML_DESCRIPTION, + GetStringProperty(gsPropertyHint, rPropSet), + rContent); + + // the element + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + XML_EXECUTE_MACRO, false, false ); + + // the <office:events>-macro: + + // 1) build sequence of PropertyValues + Sequence<PropertyValue> aSeq; + OUString sName; + rPropSet->getPropertyValue("ScriptURL") >>= sName; + + // if the ScriptURL property is not empty then this is a Scripting + // Framework URL, otherwise treat it as a Basic Macro + if (!sName.isEmpty()) + { + OUString sScript( "Script" ); + aSeq = Sequence<PropertyValue> + { + comphelper::makePropertyValue(sEventType, sScript), + comphelper::makePropertyValue(sScript, sName) + }; + } + else + { + aSeq = Sequence<PropertyValue> + { + comphelper::makePropertyValue(sEventType, OUString("StarBasic")), + comphelper::makePropertyValue("Library", rPropSet->getPropertyValue( "MacroLibrary" )), + comphelper::makePropertyValue("MacroName", rPropSet->getPropertyValue( "MacroName" )) + }; + } + + // 2) export the sequence + GetExport().GetEventExport().ExportSingleEvent( aSeq, "OnClick", false ); + + // and finally, the field presentation + GetExport().Characters(rContent); +} + +void XMLTextFieldExport::ExportMetaField( + const Reference<XPropertySet> & i_xMeta, + bool i_bAutoStyles, bool i_bProgress, + bool & rPrevCharIsSpace) +{ + bool doExport(!i_bAutoStyles); // do not export element if autostyles + // check version >= 1.2 + switch (GetExport().getSaneDefaultVersion()) { + case SvtSaveOptions::ODFSVER_011: // fall through + case SvtSaveOptions::ODFSVER_010: doExport = false; break; + default: break; + } + + const Reference < XEnumerationAccess > xEA( i_xMeta, UNO_QUERY_THROW ); + const Reference < XEnumeration > xTextEnum( xEA->createEnumeration() ); + + if (doExport) + { + const Reference<rdf::XMetadatable> xMeta( i_xMeta, UNO_QUERY_THROW ); + + // style:data-style-name + ProcessValueAndType(false, + GetIntProperty(gsPropertyNumberFormat, i_xMeta), + "", u"", 0.0, false, false, true, + false ); + + // text:meta-field without xml:id is invalid + xMeta->ensureMetadataReference(); + + // xml:id for RDF metadata + GetExport().AddAttributeXmlId(xMeta); + } + + SvXMLElementExport aElem( GetExport(), doExport, + XML_NAMESPACE_TEXT, XML_META_FIELD, false, false ); + + // recurse to export content + GetExport().GetTextParagraphExport()-> + exportTextRangeEnumeration(xTextEnum, i_bAutoStyles, i_bProgress, rPrevCharIsSpace); +} + +/// export all data-style related attributes +void XMLTextFieldExport::ProcessValueAndType( + bool bIsString, /// do we process a string or a number? + sal_Int32 nFormatKey, /// format key for NumberFormatter; inv. if string + const OUString& sContent, /// string content; possibly invalid + std::u16string_view sDefault, /// default string + double fValue, /// float content; possibly invalid + bool bExportValue, /// export value attribute? + bool bExportValueType, /// export value-type attribute? + bool bExportStyle, /// export style-attribute? + bool bForceSystemLanguage, /// export language attributes? + bool bTimeStyle) // exporting a time style? +{ + // String or number? + if (bIsString) + { + + // string: attributes value-type=string, string-value=... + + if (bExportValue || bExportValueType) + { + XMLNumberFormatAttributesExportHelper::SetNumberFormatAttributes( + GetExport(), sContent, sDefault, bExportValue); + } + + } + else + { + + // number: value-type=..., value...=..., data-style-name=... + + DBG_ASSERT(bExportValueType || !bExportValue, "value w/o value type not supported!"); + + // take care of illegal formats + // (shouldn't happen, but does if document is corrupted) + if (-1 != nFormatKey) + { + if (bExportValue || bExportValueType) + { + XMLNumberFormatAttributesExportHelper:: + SetNumberFormatAttributes( + GetExport(), nFormatKey, fValue, bExportValue); + } + + if (bExportStyle) + { + // don't export language (if desired) + if( bForceSystemLanguage ) + nFormatKey = + GetExport().dataStyleForceSystemLanguage( nFormatKey ); + + OUString sDataStyleName = + GetExport().getDataStyleName(nFormatKey, bTimeStyle); + if( !sDataStyleName.isEmpty() ) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DATA_STYLE_NAME, + sDataStyleName ); + } // else: ignore (no valid number format) + } // else: ignore (no number format) + } + } +} + + +/// process display related properties +void XMLTextFieldExport::ProcessDisplay(bool bIsVisible, + bool bIsCommand) +{ + enum XMLTokenEnum eValue; + + if (bIsVisible) + { + eValue = bIsCommand ? XML_FORMULA : XML_VALUE; + } + else + { + eValue = XML_NONE; + } + + // omit attribute if default + if (eValue != XML_VALUE) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_DISPLAY, eValue); + } +} + + +void XMLTextFieldExport::ProcessBoolean(enum XMLTokenEnum eName, + bool bBool, bool bDefault) +{ + ProcessBoolean(eName, bBool, bDefault, XML_NAMESPACE_TEXT); +} + +/// export boolean property +void XMLTextFieldExport::ProcessBoolean(enum XMLTokenEnum eName, + bool bBool, bool bDefault, sal_uInt16 nPrefix) +{ + SAL_WARN_IF( eName == XML_TOKEN_INVALID, "xmloff.text", "invalid element token"); + if ( XML_TOKEN_INVALID == eName ) + return; + + // write attribute (if different than default) + // negate to force 0/1 values (and make sal_Bool comparable) + if ((!bBool) != (!bDefault)) { + GetExport().AddAttribute(nPrefix, eName, + (bBool ? XML_TRUE : XML_FALSE) ); + } +} + +/// export string attribute +void XMLTextFieldExport::ProcessString(enum XMLTokenEnum eName, + const OUString& sValue, + bool bOmitEmpty, + sal_uInt16 nPrefix) +{ + SAL_WARN_IF( eName == XML_TOKEN_INVALID, "xmloff.text", "invalid element token"); + if ( XML_TOKEN_INVALID == eName ) + return; + + // check for empty string, if applicable + if ( bOmitEmpty && sValue.isEmpty() ) + return; + + // write attribute + GetExport().AddAttribute(nPrefix, eName, sValue); +} + +void XMLTextFieldExport::ProcessString(enum XMLTokenEnum eName, + sal_uInt16 nValuePrefix, + const OUString& sValue) +{ + OUString sQValue = + GetExport().GetNamespaceMap().GetQNameByKey( nValuePrefix, sValue, false ); + ProcessString( eName, sQValue ); +} + +/// export a string attribute +void XMLTextFieldExport::ProcessString(enum XMLTokenEnum eName, + const OUString& sValue, + std::u16string_view sDefault) +{ + if (sValue != sDefault) + { + ProcessString(eName, sValue); + } +} + +/// export a string attribute +void XMLTextFieldExport::ProcessString(enum XMLTokenEnum eName, + sal_uInt16 nValuePrefix, + const OUString& sValue, + std::u16string_view sDefault) +{ + if (sValue != sDefault) + { + ProcessString(eName, nValuePrefix, sValue); + } +} + + +/// export string attribute +void XMLTextFieldExport::ProcessString( + enum XMLTokenEnum eName, + enum XMLTokenEnum eValue, + sal_uInt16 nPrefix) +{ + SAL_WARN_IF( eName == XML_TOKEN_INVALID, "xmloff.text", "invalid element token" ); + SAL_WARN_IF( eValue == XML_TOKEN_INVALID, "xmloff.text", "invalid value token" ); + if ( XML_TOKEN_INVALID == eName ) + return; + + GetExport().AddAttribute(nPrefix, eName, eValue); +} + +/// export a string attribute +void XMLTextFieldExport::ProcessString( + enum XMLTokenEnum eName, + enum XMLTokenEnum eValue, + enum XMLTokenEnum eDefault) +{ + if ( eValue != eDefault ) + ProcessString( eName, eValue); +} + + +/// export a string as a sequence of paragraphs +void XMLTextFieldExport::ProcessParagraphSequence( + std::u16string_view sParagraphSequence) +{ + // iterate over all string-pieces separated by return (0x0a) and + // put each inside a paragraph element. + SvXMLTokenEnumerator aEnumerator(sParagraphSequence, char(0x0a)); + std::u16string_view aSubString; + while (aEnumerator.getNextToken(aSubString)) + { + SvXMLElementExport aParagraph( + GetExport(), XML_NAMESPACE_TEXT, XML_P, true, false); + GetExport().Characters(OUString(aSubString)); + } +} + +// export an integer attribute +void XMLTextFieldExport::ProcessInteger(enum XMLTokenEnum eName, + sal_Int32 nNum) +{ + SAL_WARN_IF( eName == XML_TOKEN_INVALID, "xmloff.text", "invalid element token"); + if ( XML_TOKEN_INVALID == eName ) + return; + + GetExport().AddAttribute(XML_NAMESPACE_TEXT, eName, + OUString::number(nNum)); +} + +/// export an integer attribute, omit if default +void XMLTextFieldExport::ProcessIntegerDef(enum XMLTokenEnum eName, + sal_Int32 nNum, sal_Int32 nDefault) +{ + if (nNum != nDefault) + ProcessInteger(eName, nNum); +} + + +/// export a numbering type +void XMLTextFieldExport::ProcessNumberingType(sal_Int16 nNumberingType) +{ + // process only if real format (not: like page descriptor) + if (NumberingType::PAGE_DESCRIPTOR == nNumberingType) + return; + + OUStringBuffer sTmp( 10 ); + // number type: num format + GetExport().GetMM100UnitConverter().convertNumFormat( sTmp, + nNumberingType ); + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_NUM_FORMAT, + sTmp.makeStringAndClear() ); + // and letter sync, if applicable + SvXMLUnitConverter::convertNumLetterSync( sTmp, nNumberingType ); + + if (!sTmp.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_NUM_LETTER_SYNC, + sTmp.makeStringAndClear() ); + } + // else: like page descriptor => ignore +} + + +/// export a date, time, or duration +void XMLTextFieldExport::ProcessDateTime(enum XMLTokenEnum eName, + double dValue, + bool bIsDate, + bool bIsDuration, + bool bOmitDurationIfZero, + sal_uInt16 nPrefix) +{ + // truncate for date granularity + if (bIsDate) + { + dValue = ::rtl::math::approxFloor(dValue); + } + + OUStringBuffer aBuffer; + if (bIsDuration) + { + // date/time duration handle bOmitDurationIfZero + if (!bOmitDurationIfZero || dValue != 0.0) + { + ::sax::Converter::convertDuration(aBuffer, dValue); + } + } + else + { + // date/time value + rExport.GetMM100UnitConverter().convertDateTime(aBuffer, dValue); + } + + // output attribute + ProcessString(eName, aBuffer.makeStringAndClear(), true, nPrefix); +} + +/// export a date or time +void XMLTextFieldExport::ProcessDateTime(enum XMLTokenEnum eName, + const util::DateTime& rTime) +{ + OUStringBuffer aBuffer; + + util::DateTime aDateTime(rTime); + + // date/time value + ::sax::Converter::convertDateTime(aBuffer, aDateTime, nullptr); + + // output attribute + ProcessString(eName, aBuffer.makeStringAndClear(), true); +} + +/// export a date, time, or duration +void XMLTextFieldExport::ProcessDateTime(enum XMLTokenEnum eName, + sal_Int32 nMinutes, + bool bIsDate, + bool bIsDuration) +{ + // handle bOmitDurationIfZero here, because we can precisely compare ints + if (!(bIsDuration && (nMinutes==0))) + { + ProcessDateTime(eName, static_cast<double>(nMinutes) / double(24*60), + bIsDate, bIsDuration); + } +} + +/// export a time or dateTime +void XMLTextFieldExport::ProcessTimeOrDateTime(enum XMLTokenEnum eName, + const util::DateTime& rTime) +{ + OUStringBuffer aBuffer; + + // date/time value + ::sax::Converter::convertTimeOrDateTime(aBuffer, rTime); + + // output attribute + ProcessString(eName, aBuffer.makeStringAndClear(), true); +} + + +SvXMLEnumMapEntry<sal_Int16> const aBibliographyDataTypeMap[] = +{ + { XML_ARTICLE, BibliographyDataType::ARTICLE }, + { XML_BOOK, BibliographyDataType::BOOK }, + { XML_BOOKLET, BibliographyDataType::BOOKLET }, + { XML_CONFERENCE, BibliographyDataType::CONFERENCE }, + { XML_CUSTOM1, BibliographyDataType::CUSTOM1 }, + { XML_CUSTOM2, BibliographyDataType::CUSTOM2 }, + { XML_CUSTOM3, BibliographyDataType::CUSTOM3 }, + { XML_CUSTOM4, BibliographyDataType::CUSTOM4 }, + { XML_CUSTOM5, BibliographyDataType::CUSTOM5 }, + { XML_EMAIL, BibliographyDataType::EMAIL }, + { XML_INBOOK, BibliographyDataType::INBOOK }, + { XML_INCOLLECTION, BibliographyDataType::INCOLLECTION }, + { XML_INPROCEEDINGS, BibliographyDataType::INPROCEEDINGS }, + { XML_JOURNAL, BibliographyDataType::JOURNAL }, + { XML_MANUAL, BibliographyDataType::MANUAL }, + { XML_MASTERSTHESIS, BibliographyDataType::MASTERSTHESIS }, + { XML_MISC, BibliographyDataType::MISC }, + { XML_PHDTHESIS, BibliographyDataType::PHDTHESIS }, + { XML_PROCEEDINGS, BibliographyDataType::PROCEEDINGS }, + { XML_TECHREPORT, BibliographyDataType::TECHREPORT }, + { XML_UNPUBLISHED, BibliographyDataType::UNPUBLISHED }, + { XML_WWW, BibliographyDataType::WWW }, + { XML_TOKEN_INVALID, 0 } +}; + + +void XMLTextFieldExport::ProcessBibliographyData( + const Reference<XPropertySet>& rPropSet) +{ + // get the values + Any aAny = rPropSet->getPropertyValue(gsPropertyFields); + Sequence<PropertyValue> aValues; + aAny >>= aValues; + + // one attribute per value (unless empty) + for (const auto& rProp : std::as_const(aValues)) + { + if( rProp.Name == "BibiliographicType" ) + { + sal_Int16 nTypeId = 0; + rProp.Value >>= nTypeId; + OUStringBuffer sBuf; + + if (SvXMLUnitConverter::convertEnum(sBuf, nTypeId, + aBibliographyDataTypeMap)) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, + XML_BIBLIOGRAPHY_TYPE, + sBuf.makeStringAndClear()); + } + // else: ignore this argument + } + else + { + OUString sStr; + rProp.Value >>= sStr; + + if (!sStr.isEmpty()) + { + XMLTokenEnum eElement = MapBibliographyFieldName(rProp.Name); + if (eElement == XML_URL || eElement == XML_LOCAL_URL || eElement == XML_TARGET_URL) + { + sStr = GetExport().GetRelativeReference(sStr); + } + sal_uInt16 nPrefix = XML_NAMESPACE_TEXT; + if (eElement == XML_LOCAL_URL || eElement == XML_TARGET_TYPE + || eElement == XML_TARGET_URL) + { + nPrefix = XML_NAMESPACE_LO_EXT; + } + rExport.AddAttribute(nPrefix, eElement, sStr); + } + } + } +} + +/// export CommandTypeAttribute +void XMLTextFieldExport::ProcessCommandType( + sal_Int32 nCommandType) +{ + enum XMLTokenEnum eToken = XML_TOKEN_INVALID; + switch( nCommandType ) + { + case sdb::CommandType::TABLE: eToken = XML_TABLE; break; + case sdb::CommandType::QUERY: eToken = XML_QUERY; break; + case sdb::CommandType::COMMAND: eToken = XML_COMMAND; break; + } + + if( eToken != XML_TOKEN_INVALID ) + rExport.AddAttribute( XML_NAMESPACE_TEXT, XML_TABLE_TYPE, eToken ); +} + + +void XMLTextFieldExport::ProcessStringSequence( + const Sequence<OUString>& rSequence, + const OUString& sSelected ) +{ + // find selected element + sal_Int32 nSelected = comphelper::findValue(rSequence, sSelected); + + // delegate to ProcessStringSequence(OUString,sal_Int32) + ProcessStringSequence( rSequence, nSelected ); +} + +void XMLTextFieldExport::ProcessStringSequence( + const Sequence<OUString>& rSequence, + sal_Int32 nSelected ) +{ + sal_Int32 nLength = rSequence.getLength(); + const OUString* pSequence = rSequence.getConstArray(); + for( sal_Int32 i = 0; i < nLength; i++ ) + { + if( i == nSelected ) + rExport.AddAttribute( XML_NAMESPACE_TEXT, + XML_CURRENT_SELECTED, XML_TRUE ); + rExport.AddAttribute( XML_NAMESPACE_TEXT, XML_VALUE, pSequence[i] ); + SvXMLElementExport aElement( rExport, XML_NAMESPACE_TEXT, XML_LABEL, + false, false ); + } +} + +void XMLTextFieldExport::ExportDataBaseElement( + enum XMLTokenEnum eElementName, + const OUString& sPresentation, + const Reference<XPropertySet>& rPropertySet, + const Reference<XPropertySetInfo>& rPropertySetInfo ) +{ + SAL_WARN_IF( eElementName == XML_TOKEN_INVALID, "xmloff.text", "need token" ); + SAL_WARN_IF( !rPropertySet.is(), "xmloff.text", "need property set" ); + SAL_WARN_IF( !rPropertySetInfo.is(), "xmloff.text", "need property set info" ); + + // get database properties + OUString sDataBaseName; + OUString sDataBaseURL; + OUString sStr; + if( ( rPropertySet->getPropertyValue( gsPropertyDataBaseName ) >>= sStr ) + && !sStr.isEmpty() ) + { + sDataBaseName = sStr; + } + else if( rPropertySetInfo->hasPropertyByName( gsPropertyDataBaseURL ) && + (rPropertySet->getPropertyValue( gsPropertyDataBaseURL ) >>= sStr) && + !sStr.isEmpty() ) + { + sDataBaseURL = sStr; + } + + // add database name property (if present) + if( !sDataBaseName.isEmpty() ) + rExport.AddAttribute( XML_NAMESPACE_TEXT, XML_DATABASE_NAME, + sDataBaseName ); + SvXMLElementExport aDataBaseElement( GetExport(), + XML_NAMESPACE_TEXT, eElementName, + false, false ); + + // write URL as children + if( !sDataBaseURL.isEmpty() ) + { + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sDataBaseURL ); + SvXMLElementExport aDataSourceElement( + GetExport(), XML_NAMESPACE_FORM, XML_CONNECTION_RESOURCE, + false, false ); + } + + // write presentation + rExport.Characters( sPresentation ); +} + + +// explode a field master name into field type and field name +void XMLTextFieldExport::ExplodeFieldMasterName( + std::u16string_view sMasterName, OUString& sFieldType, OUString& sVarName) +{ + sal_Int32 nLength = gsFieldMasterPrefix.getLength(); + size_t nSeparator = sMasterName.find('.', nLength); + + // '.' found? + if (nSeparator == o3tl::make_unsigned(nLength) || nSeparator == std::u16string_view::npos) { + SAL_WARN("xmloff.text", "no field var name!"); + } + else + { + sFieldType = sMasterName.substr(nLength, nSeparator-nLength); + sVarName = sMasterName.substr(nSeparator+1); + } +} + + +// for XDependentTextFields, get PropertySet of FieldMaster +Reference<XPropertySet> XMLTextFieldExport::GetMasterPropertySet( + const Reference<XTextField> & rTextField) +{ + // name, value => get Property set of TextFieldMaster + Reference<XDependentTextField> xDep(rTextField, UNO_QUERY); + return xDep->getTextFieldMaster(); +} + +// get PropertySet of (any; the first) dependent field +bool XMLTextFieldExport::GetDependentFieldPropertySet( + const Reference<XPropertySet> & xMaster, + Reference<XPropertySet> & xField) +{ + Any aAny; + Sequence<Reference<XDependentTextField> > aFields; + aAny = xMaster->getPropertyValue(gsPropertyDependentTextFields); + aAny >>= aFields; + + // any fields? + if (aFields.hasElements()) + { + // get first one and return + Reference<XDependentTextField> xTField = aFields[0]; + xField.set(xTField, UNO_QUERY); + DBG_ASSERT(xField.is(), + "Surprisingly, this TextField refuses to be a PropertySet!"); + return true; + } + else + { + return false; + } +} + + +/// map placeholder type +enum XMLTokenEnum XMLTextFieldExport::MapPlaceholderType(sal_uInt16 nType) +{ + enum XMLTokenEnum eType = XML_TEXT; + + switch (nType) + { + case PlaceholderType::TEXT: + eType = XML_TEXT; + break; + + case PlaceholderType::TABLE: + eType = XML_TABLE; + break; + + case PlaceholderType::TEXTFRAME: + eType = XML_TEXT_BOX; + break; + + case PlaceholderType::GRAPHIC: + eType = XML_IMAGE; + break; + + case PlaceholderType::OBJECT: + eType = XML_OBJECT; + break; + + default: + // unknown placeholder: XML_TEXT + OSL_FAIL("unknown placeholder type"); + } + + return eType; +} + + +/// element name for author fields +enum XMLTokenEnum XMLTextFieldExport::MapAuthorFieldName( + const Reference<XPropertySet> & xPropSet) +{ + // Initials or full name? + return GetBoolProperty(gsPropertyFullName, xPropSet) + ? XML_AUTHOR_NAME : XML_AUTHOR_INITIALS; +} + +enum XMLTokenEnum XMLTextFieldExport::MapPageNumberName( + const Reference<XPropertySet> & xPropSet, + sal_Int32& nOffset) +{ + enum XMLTokenEnum eName = XML_TOKEN_INVALID; + PageNumberType ePage; + Any aAny = xPropSet->getPropertyValue(gsPropertySubType); + ePage = *o3tl::doAccess<PageNumberType>(aAny); + + switch (ePage) + { + case PageNumberType_PREV: + eName = XML_PREVIOUS; + nOffset += 1; + break; + case PageNumberType_CURRENT: + eName = XML_CURRENT; + break; + case PageNumberType_NEXT: + eName = XML_NEXT; + nOffset -= 1; + break; + default: + OSL_FAIL("unknown page number type"); + eName = XML_TOKEN_INVALID; + break; + } + + return eName; +} + +/// map TemplateDisplayFormat to XML +enum XMLTokenEnum XMLTextFieldExport::MapTemplateDisplayFormat(sal_Int16 nFormat) +{ + enum XMLTokenEnum eName = XML_TOKEN_INVALID; + + switch (nFormat) + { + case TemplateDisplayFormat::FULL: + eName = XML_FULL; + break; + case TemplateDisplayFormat::PATH: + eName = XML_PATH; + break; + case TemplateDisplayFormat::NAME: + eName = XML_NAME; + break; + case TemplateDisplayFormat::NAME_AND_EXT: + eName = XML_NAME_AND_EXTENSION; + break; + case TemplateDisplayFormat::AREA: + eName = XML_AREA; + break; + case TemplateDisplayFormat::TITLE: + eName = XML_TITLE; + break; + default: + OSL_FAIL("unknown template display format"); + eName = XML_TOKEN_INVALID; + break; + } + + return eName; +} + +/// map count/statistics field token to XML name +enum XMLTokenEnum XMLTextFieldExport::MapCountFieldName(FieldIdEnum nToken) +{ + enum XMLTokenEnum eElement = XML_TOKEN_INVALID; + + switch (nToken) + { + case FIELD_ID_COUNT_PAGES: + eElement = XML_PAGE_COUNT; + break; + case FIELD_ID_COUNT_PARAGRAPHS: + eElement = XML_PARAGRAPH_COUNT; + break; + case FIELD_ID_COUNT_WORDS: + eElement = XML_WORD_COUNT; + break; + case FIELD_ID_COUNT_CHARACTERS: + eElement = XML_CHARACTER_COUNT; + break; + case FIELD_ID_COUNT_TABLES: + eElement = XML_TABLE_COUNT; + break; + case FIELD_ID_COUNT_GRAPHICS: + eElement = XML_IMAGE_COUNT; + break; + case FIELD_ID_COUNT_OBJECTS: + eElement = XML_OBJECT_COUNT; + break; + default: + OSL_FAIL("no count field token"); + eElement = XML_TOKEN_INVALID; + break; + } + + return eElement; +} + +/// map ChapterDisplayFormat to XML string +enum XMLTokenEnum XMLTextFieldExport::MapChapterDisplayFormat(sal_Int16 nFormat) +{ + enum XMLTokenEnum eName = XML_TOKEN_INVALID; + + switch (nFormat) + { + case ChapterFormat::NAME: + eName = XML_NAME; + break; + case ChapterFormat::NUMBER: + eName = XML_NUMBER; + break; + case ChapterFormat::NAME_NUMBER: + eName = XML_NUMBER_AND_NAME; + break; + case ChapterFormat::NO_PREFIX_SUFFIX: + eName = XML_PLAIN_NUMBER_AND_NAME; + break; + case ChapterFormat::DIGIT: + eName = XML_PLAIN_NUMBER; + break; + default: + OSL_FAIL("unknown chapter display format"); + eName = XML_TOKEN_INVALID; + break; + } + + return eName; +} + + +/// map FilenameDisplayFormat to XML attribute names +enum XMLTokenEnum XMLTextFieldExport::MapFilenameDisplayFormat(sal_Int16 nFormat) +{ + enum XMLTokenEnum eName = XML_TOKEN_INVALID; + + switch (nFormat) + { + case FilenameDisplayFormat::FULL: + eName = XML_FULL; + break; + case FilenameDisplayFormat::PATH: + eName = XML_PATH; + break; + case FilenameDisplayFormat::NAME: + eName = XML_NAME; + break; + case FilenameDisplayFormat::NAME_AND_EXT: + eName = XML_NAME_AND_EXTENSION; + break; + default: + OSL_FAIL("unknown filename display format"); + } + + return eName; +} + + +/// map ReferenceFieldPart to XML string +enum XMLTokenEnum XMLTextFieldExport::MapReferenceType(sal_Int16 nType) +{ + enum XMLTokenEnum eElement = XML_TOKEN_INVALID; + + switch (nType) + { + case ReferenceFieldPart::PAGE: + eElement = XML_PAGE; + break; + case ReferenceFieldPart::CHAPTER: + eElement = XML_CHAPTER; + break; + case ReferenceFieldPart::TEXT: + eElement = XML_TEXT; + break; + case ReferenceFieldPart::UP_DOWN: + eElement = XML_DIRECTION; + break; + case ReferenceFieldPart::CATEGORY_AND_NUMBER: + eElement = XML_CATEGORY_AND_VALUE; + break; + case ReferenceFieldPart::ONLY_CAPTION: + eElement = XML_CAPTION; + break; + case ReferenceFieldPart::ONLY_SEQUENCE_NUMBER: + eElement = XML_VALUE; + break; + case ReferenceFieldPart::PAGE_DESC: + // small hack: this value never gets written, because + // XML_TEMPLATE is default + eElement = XML_TEMPLATE; + break; + // Core implementation for direct cross-references (#i81002#) + case ReferenceFieldPart::NUMBER: + eElement = XML_NUMBER; + break; + case ReferenceFieldPart::NUMBER_NO_CONTEXT: + eElement = XML_NUMBER_NO_SUPERIOR; + break; + case ReferenceFieldPart::NUMBER_FULL_CONTEXT: + eElement = XML_NUMBER_ALL_SUPERIOR; + break; + default: + OSL_FAIL("unknown reference type"); + eElement = XML_TEMPLATE; + break; + } + + return eElement; +} + +/// map ReferenceFieldPart to XML string +enum XMLTokenEnum XMLTextFieldExport::MapReferenceSource(sal_Int16 nType) +{ + enum XMLTokenEnum eElement = XML_TOKEN_INVALID; + + switch (nType) + { + case ReferenceFieldSource::REFERENCE_MARK: + eElement = XML_REFERENCE_REF; + break; + case ReferenceFieldSource::SEQUENCE_FIELD: + eElement = XML_SEQUENCE_REF; + break; + case ReferenceFieldSource::BOOKMARK: + eElement = XML_BOOKMARK_REF; + break; + case ReferenceFieldSource::FOOTNOTE: + case ReferenceFieldSource::ENDNOTE: + eElement = XML_NOTE_REF; + break; + case ReferenceFieldSource::STYLE: + eElement = XML_STYLE_REF; + break; + default: + OSL_FAIL("unknown reference source"); + break; + } + + return eElement; +} + + +/// element name for sender fields +enum XMLTokenEnum XMLTextFieldExport::MapSenderFieldName( + const Reference<XPropertySet> & xPropSet) +{ + enum XMLTokenEnum eName = XML_TOKEN_INVALID; + + // sub-field type + switch (GetInt16Property(gsPropertyFieldSubType, xPropSet)) + { + case UserDataPart::COMPANY : + eName = XML_SENDER_COMPANY; + break; + case UserDataPart::FIRSTNAME : + eName = XML_SENDER_FIRSTNAME; + break; + case UserDataPart::NAME : + eName = XML_SENDER_LASTNAME; + break; + case UserDataPart::SHORTCUT : + eName = XML_SENDER_INITIALS; + break; + case UserDataPart::STREET : + eName = XML_SENDER_STREET; + break; + case UserDataPart::COUNTRY : + eName = XML_SENDER_COUNTRY; + break; + case UserDataPart::ZIP : + eName = XML_SENDER_POSTAL_CODE; + break; + case UserDataPart::CITY : + eName = XML_SENDER_CITY; + break; + case UserDataPart::TITLE : + eName = XML_SENDER_TITLE; + break; + case UserDataPart::POSITION : + eName = XML_SENDER_POSITION; + break; + case UserDataPart::PHONE_PRIVATE : + eName = XML_SENDER_PHONE_PRIVATE; + break; + case UserDataPart::PHONE_COMPANY : + eName = XML_SENDER_PHONE_WORK; + break; + case UserDataPart::FAX : + eName = XML_SENDER_FAX; + break; + case UserDataPart::EMAIL : + eName = XML_SENDER_EMAIL; + break; + case UserDataPart::STATE : + eName = XML_SENDER_STATE_OR_PROVINCE; + break; + default: + SAL_WARN("xmloff.text", "unknown sender type"); + eName = XML_TOKEN_INVALID; + break; + } + + return eName; +} + +enum XMLTokenEnum XMLTextFieldExport::MapDocInfoFieldName( + enum FieldIdEnum nToken) +{ + enum XMLTokenEnum eElement = XML_TOKEN_INVALID; + + switch (nToken) + { + case FIELD_ID_DOCINFO_CREATION_AUTHOR: + eElement = XML_INITIAL_CREATOR; + break; + case FIELD_ID_DOCINFO_CREATION_DATE: + eElement = XML_CREATION_DATE; + break; + case FIELD_ID_DOCINFO_CREATION_TIME: + eElement = XML_CREATION_TIME; + break; + case FIELD_ID_DOCINFO_DESCRIPTION: + eElement = XML_DESCRIPTION; + break; + case FIELD_ID_DOCINFO_PRINT_TIME: + eElement = XML_PRINT_TIME; + break; + case FIELD_ID_DOCINFO_PRINT_DATE: + eElement = XML_PRINT_DATE; + break; + case FIELD_ID_DOCINFO_PRINT_AUTHOR: + eElement = XML_PRINTED_BY; + break; + case FIELD_ID_DOCINFO_TITLE: + eElement = XML_TITLE; + break; + case FIELD_ID_DOCINFO_SUBJECT: + eElement = XML_SUBJECT; + break; + case FIELD_ID_DOCINFO_KEYWORDS: + eElement = XML_KEYWORDS; + break; + case FIELD_ID_DOCINFO_REVISION: + eElement = XML_EDITING_CYCLES; + break; + case FIELD_ID_DOCINFO_EDIT_DURATION: + eElement = XML_EDITING_DURATION; + break; + case FIELD_ID_DOCINFO_SAVE_TIME: + eElement = XML_MODIFICATION_TIME; + break; + case FIELD_ID_DOCINFO_SAVE_DATE: + eElement = XML_MODIFICATION_DATE; + break; + case FIELD_ID_DOCINFO_SAVE_AUTHOR: + eElement = XML_CREATOR; + break; + default: + SAL_WARN("xmloff.text", "unknown docinfo field type!"); + eElement = XML_TOKEN_INVALID; + break; + } + + return eElement; +} + +enum XMLTokenEnum XMLTextFieldExport::MapBibliographyFieldName(std::u16string_view sName) +{ + enum XMLTokenEnum eName = XML_TOKEN_INVALID; + + if( sName == u"Identifier" ) + { + eName = XML_IDENTIFIER; + } + else if( sName == u"BibiliographicType" ) + { + eName = XML_BIBLIOGRAPHY_TYPE; + } + else if( sName == u"Address" ) + { + eName = XML_ADDRESS; + } + else if( sName == u"Annote" ) + { + eName = XML_ANNOTE; + } + else if( sName == u"Author" ) + { + eName = XML_AUTHOR; + } + else if( sName == u"Booktitle" ) + { + eName = XML_BOOKTITLE; + } + else if( sName == u"Chapter" ) + { + eName = XML_CHAPTER; + } + else if( sName == u"Edition" ) + { + eName = XML_EDITION; + } + else if( sName == u"Editor" ) + { + eName = XML_EDITOR; + } + else if( sName == u"Howpublished" ) + { + eName = XML_HOWPUBLISHED; + } + else if( sName == u"Institution" ) + { + eName = XML_INSTITUTION; + } + else if( sName == u"Journal" ) + { + eName = XML_JOURNAL; + } + else if( sName == u"Month" ) + { + eName = XML_MONTH; + } + else if( sName == u"Note" ) + { + eName = XML_NOTE; + } + else if( sName == u"Number" ) + { + eName = XML_NUMBER; + } + else if( sName == u"Organizations" ) + { + eName = XML_ORGANIZATIONS; + } + else if( sName == u"Pages" ) + { + eName = XML_PAGES; + } + else if( sName == u"Publisher" ) + { + eName = XML_PUBLISHER; + } + else if( sName == u"School" ) + { + eName = XML_SCHOOL; + } + else if( sName == u"Series" ) + { + eName = XML_SERIES; + } + else if( sName == u"Title" ) + { + eName = XML_TITLE; + } + else if( sName == u"Report_Type" ) + { + eName = XML_REPORT_TYPE; + } + else if( sName == u"Volume" ) + { + eName = XML_VOLUME; + } + else if( sName == u"Year" ) + { + eName = XML_YEAR; + } + else if( sName == u"URL" ) + { + eName = XML_URL; + } + else if( sName == u"Custom1" ) + { + eName = XML_CUSTOM1; + } + else if( sName == u"Custom2" ) + { + eName = XML_CUSTOM2; + } + else if( sName == u"Custom3" ) + { + eName = XML_CUSTOM3; + } + else if( sName == u"Custom4" ) + { + eName = XML_CUSTOM4; + } + else if( sName == u"Custom5" ) + { + eName = XML_CUSTOM5; + } + else if( sName == u"ISBN" ) + { + eName = XML_ISBN; + } + else if (sName == u"LocalURL") + { + eName = XML_LOCAL_URL; + } + else if (sName == u"TargetType") + { + eName = XML_TARGET_TYPE; + } + else if (sName == u"TargetURL") + { + eName = XML_TARGET_URL; + } + else + { + SAL_WARN("xmloff.text", "Unknown bibliography info data"); + eName = XML_TOKEN_INVALID; + } + + return eName; +} + +enum XMLTokenEnum XMLTextFieldExport::MapMeasureKind(sal_Int16 nKind) +{ + switch( nKind ) + { + case 0: + return XML_VALUE; + case 1: + return XML_UNIT; + } + return XML_GAP; +} + +OUString XMLTextFieldExport::MakeFootnoteRefName( + sal_Int16 nSeqNo) +{ + // generate foot-/endnote ID + return "ftn" + OUString::number(static_cast<sal_Int32>(nSeqNo)); +} + +OUString XMLTextFieldExport::MakeSequenceRefName( + sal_Int16 nSeqNo, + std::u16string_view rSeqName) +{ + // generate foot-/endnote ID + return OUString::Concat("ref") +rSeqName + OUString::number(static_cast<sal_Int32>(nSeqNo)); +} + + +// Property accessor helper functions + + +// to be relegated (does that word exist?) to a more appropriate place + + +bool GetBoolProperty( + const OUString& sPropName, + const Reference<XPropertySet> & xPropSet) +{ + Any aAny = xPropSet->getPropertyValue(sPropName); + bool bBool = *o3tl::doAccess<bool>(aAny); + return bBool; +} + +bool GetOptionalBoolProperty( + const OUString& sPropName, + const Reference<XPropertySet> & xPropSet, + const Reference<XPropertySetInfo> & xPropSetInfo, + bool bDefault) +{ + return xPropSetInfo->hasPropertyByName( sPropName ) + ? GetBoolProperty( sPropName, xPropSet ) : bDefault; +} + +double GetDoubleProperty( + const OUString& sPropName, + const Reference<XPropertySet> & xPropSet) +{ + Any aAny = xPropSet->getPropertyValue(sPropName); + double fDouble = 0.0; + aAny >>= fDouble; + return fDouble; +} + +OUString GetStringProperty( + const OUString& sPropName, + const Reference<XPropertySet> & xPropSet) +{ + Any aAny = xPropSet->getPropertyValue(sPropName); + OUString sString; + aAny >>= sString; + return sString; +} + +sal_Int32 GetIntProperty( + const OUString& sPropName, + const Reference<XPropertySet> & xPropSet) +{ + Any aAny = xPropSet->getPropertyValue(sPropName); + sal_Int32 nInt = 0; + aAny >>= nInt; + return nInt; +} + +sal_Int16 GetInt16Property( + const OUString& sPropName, + const Reference<XPropertySet> & xPropSet) +{ + Any aAny = xPropSet->getPropertyValue(sPropName); + sal_Int16 nInt = 0; + aAny >>= nInt; + return nInt; +} + +sal_Int8 GetInt8Property( + const OUString& sPropName, + const Reference<XPropertySet> & xPropSet) +{ + Any aAny = xPropSet->getPropertyValue(sPropName); + sal_Int8 nInt = 0; + aAny >>= nInt; + return nInt; +} + +util::DateTime GetDateTimeProperty( + const OUString& sPropName, + const Reference<XPropertySet> & xPropSet) +{ + Any aAny = xPropSet->getPropertyValue(sPropName); + util::DateTime aTime; + aAny >>= aTime; + return aTime; +} + +Sequence<OUString> GetStringSequenceProperty( + const OUString& sPropName, + const Reference<XPropertySet> & xPropSet) +{ + Any aAny = xPropSet->getPropertyValue(sPropName); + Sequence<OUString> aSequence; + aAny >>= aSequence; + return aSequence; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtfldi.cxx b/xmloff/source/text/txtfldi.cxx new file mode 100644 index 0000000000..1228e232d3 --- /dev/null +++ b/xmloff/source/text/txtfldi.cxx @@ -0,0 +1,3661 @@ +/* -*- 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 . + */ + + +/** @#file + * + * Import of all text fields except those from txtvfldi.cxx + * (variable related text fields and database display fields) + */ + +#include <o3tl/safeint.hxx> +#include <sal/config.h> + +#include <cassert> + +#include <txtfldi.hxx> +#include <txtvfldi.hxx> +#include <utility> +#include <xmloff/xmlimp.hxx> +#include <xmloff/txtimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> +#include <XMLStringBufferImportContext.hxx> +#include <xmloff/XMLEventsImportContext.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/text/UserDataPart.hpp> +#include <com/sun/star/style/NumberingType.hpp> +#include <com/sun/star/text/PlaceholderType.hpp> +#include <com/sun/star/text/ReferenceFieldPart.hpp> +#include <com/sun/star/text/ReferenceFieldSource.hpp> +#include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/text/XTextFieldsSupplier.hpp> +#include <com/sun/star/text/XDependentTextField.hpp> +#include <com/sun/star/text/FilenameDisplayFormat.hpp> +#include <com/sun/star/text/ChapterFormat.hpp> +#include <com/sun/star/text/TemplateDisplayFormat.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/text/BibliographyDataType.hpp> +#include <com/sun/star/util/XUpdatable.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> + +#include <sax/tools/converter.hxx> + +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <rtl/math.hxx> +#include <tools/debug.hxx> +#include <osl/diagnose.h> +#include <comphelper/diagnose_ex.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + + +// SO API string constants + + +// service prefix and service names +constexpr OUString sAPI_textfield_prefix = u"com.sun.star.text.TextField."_ustr; +constexpr char16_t sAPI_fieldmaster_prefix[] = u"com.sun.star.text.FieldMaster."; +constexpr OUString sAPI_presentation_prefix = u"com.sun.star.presentation.TextField."_ustr; + +constexpr OUString sAPI_date_time = u"DateTime"_ustr; +constexpr OUString sAPI_page_number = u"PageNumber"_ustr; +constexpr OUString sAPI_docinfo_change_date_time = u"DocInfo.ChangeDateTime"_ustr; +constexpr OUString sAPI_docinfo_create_date_time = u"DocInfo.CreateDateTime"_ustr; +constexpr OUString sAPI_docinfo_custom = u"DocInfo.Custom"_ustr; +constexpr OUString sAPI_docinfo_print_date_time = u"DocInfo.PrintDateTime"_ustr; +constexpr OUString sAPI_dde = u"DDE"_ustr; +constexpr OUString sAPI_url = u"URL"_ustr; + +// property names +constexpr OUString sAPI_is_fixed = u"IsFixed"_ustr; +constexpr OUString sAPI_content = u"Content"_ustr; +constexpr OUString sAPI_author = u"Author"_ustr; +constexpr OUString sAPI_hint = u"Hint"_ustr; +constexpr OUString sAPI_name = u"Name"_ustr; +constexpr OUStringLiteral sAPI_parent_name = u"ParentName"; +constexpr OUString sAPI_sub_type = u"SubType"_ustr; +constexpr OUString sAPI_date_time_value = u"DateTimeValue"_ustr; +constexpr OUString sAPI_number_format = u"NumberFormat"_ustr; +constexpr OUString sAPI_numbering_type = u"NumberingType"_ustr; +constexpr OUString sAPI_offset = u"Offset"_ustr; +constexpr OUString sAPI_condition = u"Condition"_ustr; +constexpr OUString sAPI_set_number = u"SetNumber"_ustr; +constexpr OUString sAPI_file_format = u"FileFormat"_ustr; +constexpr OUString sAPI_is_date = u"IsDate"_ustr; +constexpr OUString sAPI_current_presentation = u"CurrentPresentation"_ustr; +constexpr OUString sAPI_is_hidden = u"IsHidden"_ustr; +constexpr OUString sAPI_is_fixed_language = u"IsFixedLanguage"_ustr; + +constexpr OUString sAPI_true = u"TRUE"_ustr; + + +XMLTextFieldImportContext::XMLTextFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + OUString aService) +: SvXMLImportContext( rImport ) +, sServiceName(std::move(aService)) +, rTextImportHelper(rHlp) +, sServicePrefix(sAPI_textfield_prefix) +, bValid(false) +{ +} + +void XMLTextFieldImportContext::startFastElement( + sal_Int32 /*nElement*/, + const Reference<XFastAttributeList> & xAttrList) +{ + // process attributes + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + ProcessAttribute(aIter.getToken(), aIter.toView() ); +} + +OUString const & XMLTextFieldImportContext::GetContent() +{ + if (sContent.isEmpty()) + { + sContent = sContentBuffer.makeStringAndClear(); + } + + return sContent; +} + +void XMLTextFieldImportContext::endFastElement(sal_Int32 ) +{ + if (bValid) + { + + // create field/Service + Reference<XPropertySet> xPropSet; + if (CreateField(xPropSet, sServicePrefix + GetServiceName())) + { + // set field properties + PrepareField(xPropSet); + + // attach field to document + Reference<XTextContent> xTextContent(xPropSet, UNO_QUERY); + + // workaround for #80606# + try + { + rTextImportHelper.InsertTextContent(xTextContent); + } + catch (const lang::IllegalArgumentException&) + { + // ignore + } + return; + } + } + + // in case of error: write element content + rTextImportHelper.InsertString(GetContent()); +} + +void XMLTextFieldImportContext::characters(const OUString& rContent) +{ + sContentBuffer.append(rContent); +} + +bool XMLTextFieldImportContext::CreateField( + Reference<XPropertySet> & xField, + const OUString& rServiceName) +{ + // instantiate new XTextField: + // ask import for model, model is factory, ask factory to create service + + Reference<XMultiServiceFactory> xFactory(GetImport().GetModel(),UNO_QUERY); + if( xFactory.is() ) + { + Reference<XInterface> xIfc = xFactory->createInstance(rServiceName); + if( xIfc.is() ) + { + Reference<XPropertySet> xTmp( xIfc, UNO_QUERY ); + + xField = xTmp; + } else { + return false; // can't create instance + } + } else { + return false; // can't get MultiServiceFactory + } + + return true; +} + +/// create the appropriate field context from +XMLTextFieldImportContext* +XMLTextFieldImportContext::CreateTextFieldImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp, + sal_Int32 nToken) +{ + XMLTextFieldImportContext* pContext = nullptr; + + switch (nToken) + { + case XML_ELEMENT(TEXT, XML_SENDER_FIRSTNAME): + case XML_ELEMENT(TEXT, XML_SENDER_LASTNAME): + case XML_ELEMENT(LO_EXT, XML_SENDER_INITIALS): + case XML_ELEMENT(TEXT, XML_SENDER_INITIALS): + case XML_ELEMENT(TEXT, XML_SENDER_TITLE): + case XML_ELEMENT(TEXT, XML_SENDER_POSITION): + case XML_ELEMENT(TEXT, XML_SENDER_EMAIL): + case XML_ELEMENT(TEXT, XML_SENDER_PHONE_PRIVATE): + + case XML_ELEMENT(TEXT, XML_SENDER_FAX): + case XML_ELEMENT(TEXT, XML_SENDER_COMPANY): + case XML_ELEMENT(TEXT, XML_SENDER_PHONE_WORK): + case XML_ELEMENT(TEXT, XML_SENDER_STREET): + case XML_ELEMENT(TEXT, XML_SENDER_CITY): + case XML_ELEMENT(TEXT, XML_SENDER_POSTAL_CODE): + case XML_ELEMENT(TEXT, XML_SENDER_COUNTRY): + case XML_ELEMENT(TEXT, XML_SENDER_STATE_OR_PROVINCE): + pContext = + new XMLSenderFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_AUTHOR_NAME): + case XML_ELEMENT(TEXT, XML_AUTHOR_INITIALS): + pContext = + new XMLAuthorFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_PLACEHOLDER): + pContext = + new XMLPlaceholderFieldImportContext( rImport, rHlp); + break; + case XML_ELEMENT(TEXT, XML_SEQUENCE): + pContext = + new XMLSequenceFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_TEXT_INPUT): + pContext = + new XMLTextInputFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_EXPRESSION): + pContext = + new XMLExpressionFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_VARIABLE_SET): + pContext = + new XMLVariableSetFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_VARIABLE_INPUT): + pContext = + new XMLVariableInputFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_VARIABLE_GET): + pContext = + new XMLVariableGetFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_USER_FIELD_GET): + pContext = new XMLUserFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_USER_FIELD_INPUT): + pContext = new XMLUserFieldInputImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_TIME): + pContext = new XMLTimeFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_PAGE_CONTINUATION_STRING): + case XML_ELEMENT(TEXT, XML_PAGE_CONTINUATION): + pContext = new XMLPageContinuationImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_PAGE_NUMBER): + pContext = new XMLPageNumberImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_DATE): + pContext = new XMLDateFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_DATABASE_NAME): + pContext = new XMLDatabaseNameImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_DATABASE_NEXT): + pContext = new XMLDatabaseNextImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_DATABASE_ROW_SELECT): + pContext = new XMLDatabaseSelectImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_DATABASE_ROW_NUMBER): + pContext = new XMLDatabaseNumberImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_DATABASE_DISPLAY): + pContext = new XMLDatabaseDisplayImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_CONDITIONAL_TEXT): + pContext = new XMLConditionalTextImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_HIDDEN_TEXT): + pContext = new XMLHiddenTextImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_HIDDEN_PARAGRAPH): + pContext = new XMLHiddenParagraphImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_DESCRIPTION): + case XML_ELEMENT(TEXT, XML_TITLE): + case XML_ELEMENT(TEXT, XML_SUBJECT): + case XML_ELEMENT(TEXT, XML_KEYWORDS): + pContext = new XMLSimpleDocInfoImportContext( rImport, rHlp, + nToken, true, + false ); + break; + case XML_ELEMENT(TEXT, XML_INITIAL_CREATOR): + case XML_ELEMENT(TEXT, XML_PRINTED_BY): + case XML_ELEMENT(TEXT, XML_CREATOR): + pContext = new XMLSimpleDocInfoImportContext( rImport, rHlp, + nToken, false, + true ); + break; + + case XML_ELEMENT(TEXT, XML_CREATION_DATE): + case XML_ELEMENT(TEXT, XML_CREATION_TIME): + case XML_ELEMENT(TEXT, XML_PRINT_DATE): + case XML_ELEMENT(TEXT, XML_PRINT_TIME): + case XML_ELEMENT(TEXT, XML_MODIFICATION_DATE): + case XML_ELEMENT(TEXT, XML_MODIFICATION_TIME): + case XML_ELEMENT(TEXT, XML_EDITING_DURATION): + pContext = new XMLDateTimeDocInfoImportContext( rImport, rHlp, + nToken ); + break; + + case XML_ELEMENT(TEXT, XML_EDITING_CYCLES): + pContext = new XMLRevisionDocInfoImportContext( rImport, rHlp, + nToken ); + break; + + case XML_ELEMENT(TEXT, XML_USER_DEFINED): + pContext = new XMLUserDocInfoImportContext( rImport, rHlp, + nToken ); + break; + + case XML_ELEMENT(TEXT, XML_FILE_NAME): + pContext = new XMLFileNameImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_CHAPTER): + pContext = new XMLChapterImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_TEMPLATE_NAME): + pContext = new XMLTemplateNameImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_WORD_COUNT): + case XML_ELEMENT(TEXT, XML_PARAGRAPH_COUNT): + case XML_ELEMENT(TEXT, XML_TABLE_COUNT): + case XML_ELEMENT(TEXT, XML_CHARACTER_COUNT): + case XML_ELEMENT(TEXT, XML_IMAGE_COUNT): + case XML_ELEMENT(TEXT, XML_OBJECT_COUNT): + case XML_ELEMENT(TEXT, XML_PAGE_COUNT): + pContext = new XMLCountFieldImportContext( rImport, rHlp, nToken); + break; + + case XML_ELEMENT(TEXT, XML_PAGE_VARIABLE_GET): + pContext = new XMLPageVarGetFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_PAGE_VARIABLE_SET): + pContext = new XMLPageVarSetFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_EXECUTE_MACRO): + pContext = new XMLMacroFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_DDE_CONNECTION): + pContext = new XMLDdeFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_REFERENCE_REF): + case XML_ELEMENT(TEXT, XML_BOOKMARK_REF): + case XML_ELEMENT(TEXT, XML_NOTE_REF): + case XML_ELEMENT(TEXT, XML_SEQUENCE_REF): + case XML_ELEMENT(TEXT, XML_STYLE_REF): + case XML_ELEMENT(LO_EXT, XML_STYLE_REF): + pContext = new XMLReferenceFieldImportContext( rImport, rHlp, nToken ); + break; + + case XML_ELEMENT(TEXT, XML_SHEET_NAME): + pContext = new XMLSheetNameImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_PAGE_NAME): + case XML_ELEMENT(LO_EXT, XML_PAGE_NAME): + pContext = new XMLPageNameFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_BIBLIOGRAPHY_MARK): + pContext = new XMLBibliographyFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(OFFICE, XML_ANNOTATION): + case XML_ELEMENT(OFFICE, XML_ANNOTATION_END): + pContext = new XMLAnnotationImportContext( rImport, rHlp, nToken); + break; + + case XML_ELEMENT(TEXT, XML_SCRIPT): + pContext = new XMLScriptImportContext( rImport, rHlp); + break; + + case XML_ELEMENT(TEXT, XML_MEASURE): + pContext = new XMLMeasureFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_TABLE_FORMULA): + pContext = new XMLTableFormulaImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_DROP_DOWN): + pContext = new XMLDropDownFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(PRESENTATION, XML_HEADER): + pContext = new XMLHeaderFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(PRESENTATION, XML_FOOTER): + pContext = new XMLFooterFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(PRESENTATION, XML_DATE_TIME): + pContext = new XMLDateTimeFieldImportContext( rImport, rHlp ); + break; + + default: + // ignore! May not even be a textfield. + // (Reminder: This method is called inside default:-branch) + pContext = nullptr; + break; + } + + return pContext; +} + + +void XMLTextFieldImportContext::ForceUpdate( + const Reference<XPropertySet> & rPropertySet) +{ + // force update + Reference<XUpdatable> xUpdate(rPropertySet, UNO_QUERY); + if (xUpdate.is()) + { + xUpdate->update(); + } + else + { + OSL_FAIL("Expected XUpdatable support!"); + } +} + + +// XMLSenderFieldImportContext + + +constexpr OUStringLiteral gsPropertyFieldSubType(u"UserDataType"); + +XMLSenderFieldImportContext::XMLSenderFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) + : XMLTextFieldImportContext(rImport, rHlp, "ExtendedUser") + , nSubType(0) + , sPropertyFixed(sAPI_is_fixed) + , sPropertyContent(sAPI_content) + , bFixed(true) +{ +} + +void XMLSenderFieldImportContext::startFastElement( + sal_Int32 nElement, + const Reference<XFastAttributeList> & xAttrList) +{ + bValid = true; + switch (nElement) { + case XML_ELEMENT(TEXT, XML_SENDER_FIRSTNAME): + nSubType = UserDataPart::FIRSTNAME; + break; + case XML_ELEMENT(TEXT, XML_SENDER_LASTNAME): + nSubType = UserDataPart::NAME; + break; + case XML_ELEMENT(LO_EXT, XML_SENDER_INITIALS): + case XML_ELEMENT(TEXT, XML_SENDER_INITIALS): + nSubType = UserDataPart::SHORTCUT; + break; + case XML_ELEMENT(TEXT, XML_SENDER_TITLE): + nSubType = UserDataPart::TITLE; + break; + case XML_ELEMENT(TEXT, XML_SENDER_POSITION): + nSubType = UserDataPart::POSITION; + break; + case XML_ELEMENT(TEXT, XML_SENDER_EMAIL): + nSubType = UserDataPart::EMAIL; + break; + case XML_ELEMENT(TEXT, XML_SENDER_PHONE_PRIVATE): + nSubType = UserDataPart::PHONE_PRIVATE; + break; + case XML_ELEMENT(TEXT, XML_SENDER_FAX): + nSubType = UserDataPart::FAX; + break; + case XML_ELEMENT(TEXT, XML_SENDER_COMPANY): + nSubType = UserDataPart::COMPANY; + break; + case XML_ELEMENT(TEXT, XML_SENDER_PHONE_WORK): + nSubType = UserDataPart::PHONE_COMPANY; + break; + case XML_ELEMENT(TEXT, XML_SENDER_STREET): + nSubType = UserDataPart::STREET; + break; + case XML_ELEMENT(TEXT, XML_SENDER_CITY): + nSubType = UserDataPart::CITY; + break; + case XML_ELEMENT(TEXT, XML_SENDER_POSTAL_CODE): + nSubType = UserDataPart::ZIP; + break; + case XML_ELEMENT(TEXT, XML_SENDER_COUNTRY): + nSubType = UserDataPart::COUNTRY; + break; + case XML_ELEMENT(TEXT, XML_SENDER_STATE_OR_PROVINCE): + nSubType = UserDataPart::STATE; + break; + default: + bValid = false; + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + break; + } + + // process Attributes + XMLTextFieldImportContext::startFastElement(nElement, xAttrList); +} + +void XMLSenderFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue) +{ + if (XML_ELEMENT(TEXT, XML_FIXED) == nAttrToken) { + + // set bVal + bool bVal(false); + bool const bRet = ::sax::Converter::convertBool(bVal, sAttrValue); + + // set bFixed if successful + if (bRet) { + bFixed = bVal; + } + } + else + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +void XMLSenderFieldImportContext::PrepareField( + const Reference<XPropertySet> & rPropSet) +{ + // set members + rPropSet->setPropertyValue(gsPropertyFieldSubType, Any(nSubType)); + + // set fixed + rPropSet->setPropertyValue(sPropertyFixed, Any(bFixed)); + + // set content if fixed + if (!bFixed) + return; + + // in organizer or styles-only mode: force update + if (GetImport().GetTextImport()->IsOrganizerMode() || + GetImport().GetTextImport()->IsStylesOnlyMode() ) + { + ForceUpdate(rPropSet); + } + else + { + rPropSet->setPropertyValue(sPropertyContent, Any(GetContent())); + } +} + + +// XMLAuthorFieldImportContext + +constexpr OUStringLiteral gsPropertyAuthorFullName(u"FullName"); + +XMLAuthorFieldImportContext::XMLAuthorFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) +: XMLSenderFieldImportContext(rImport, rHlp) +, bAuthorFullName(true) +, sPropertyFixed(sAPI_is_fixed) +, sPropertyContent(sAPI_content) +{ + // overwrite service name from XMLSenderFieldImportContext + SetServiceName(sAPI_author); +} + +void XMLAuthorFieldImportContext::startFastElement( + sal_Int32 nElement, + const Reference<XFastAttributeList> & xAttrList) +{ + bAuthorFullName = ( XML_ELEMENT(TEXT, XML_AUTHOR_INITIALS) != nElement); + bValid = true; + + // process Attributes + XMLTextFieldImportContext::startFastElement(nElement, xAttrList); +} + +void XMLAuthorFieldImportContext::ProcessAttribute(sal_Int32 nAttrToken, std::string_view sAttrValue) +{ + if(nAttrToken == XML_ELEMENT(TEXT, XML_FIXED)) + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sAttrValue)) + bFixed = bTmp; + } + else + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +void XMLAuthorFieldImportContext::PrepareField( + const Reference<XPropertySet> & rPropSet) +{ + // set members + Any aAny; + rPropSet->setPropertyValue(gsPropertyAuthorFullName, Any(bAuthorFullName)); + + rPropSet->setPropertyValue(sPropertyFixed, Any(bFixed)); + + // set content if fixed + if (!bFixed) + return; + + // organizer or styles-only mode: force update + if (GetImport().GetTextImport()->IsOrganizerMode() || + GetImport().GetTextImport()->IsStylesOnlyMode() ) + { + ForceUpdate(rPropSet); + } + else + { + aAny <<= GetContent(); + rPropSet->setPropertyValue(sPropertyContent, aAny); + } +} + + +// page continuation string + + +SvXMLEnumMapEntry<PageNumberType> const lcl_aSelectPageAttrMap[] = +{ + { XML_PREVIOUS, PageNumberType_PREV }, + { XML_CURRENT, PageNumberType_CURRENT }, + { XML_NEXT, PageNumberType_NEXT }, + { XML_TOKEN_INVALID, PageNumberType(0) }, +}; + +constexpr OUStringLiteral gsPropertyUserText(u"UserText"); + +XMLPageContinuationImportContext::XMLPageContinuationImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) +: XMLTextFieldImportContext(rImport, rHlp, sAPI_page_number) +, sPropertySubType(sAPI_sub_type) +, sPropertyNumberingType(sAPI_numbering_type) +, eSelectPage(PageNumberType_CURRENT) +, sStringOK(false) +{ + bValid = true; +} + +void XMLPageContinuationImportContext::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + switch(nAttrToken) + { + case XML_ELEMENT(TEXT, XML_SELECT_PAGE): + { + PageNumberType nTmp; + if (SvXMLUnitConverter::convertEnum(nTmp, sAttrValue, + lcl_aSelectPageAttrMap) + && (PageNumberType_CURRENT != nTmp) ) + { + eSelectPage = nTmp; + } + break; + } + case XML_ELEMENT(TEXT, XML_STRING_VALUE): + case XML_ELEMENT(OFFICE, XML_STRING_VALUE): + sString = OUString::fromUtf8(sAttrValue); + sStringOK = true; + break; + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +void XMLPageContinuationImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + Any aAny; + + xPropertySet->setPropertyValue(sPropertySubType, Any(eSelectPage)); + + aAny <<= (sStringOK ? sString : GetContent()); + xPropertySet->setPropertyValue(gsPropertyUserText, aAny); + + aAny <<= style::NumberingType::CHAR_SPECIAL; + xPropertySet->setPropertyValue(sPropertyNumberingType, aAny); +} + + +// page number field + + +XMLPageNumberImportContext::XMLPageNumberImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) +: XMLTextFieldImportContext(rImport, rHlp, sAPI_page_number) +, sPropertySubType(sAPI_sub_type) +, sPropertyNumberingType(sAPI_numbering_type) +, sPropertyOffset(sAPI_offset) +, sNumberSync(GetXMLToken(XML_FALSE)) +, nPageAdjust(0) +, eSelectPage(PageNumberType_CURRENT) +, sNumberFormatOK(false) +{ + bValid = true; +} + +void XMLPageNumberImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + sNumberFormat = OUString::fromUtf8(sAttrValue); + sNumberFormatOK = true; + break; + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + sNumberSync = OUString::fromUtf8(sAttrValue); + break; + case XML_ELEMENT(TEXT, XML_SELECT_PAGE): + SvXMLUnitConverter::convertEnum(eSelectPage, sAttrValue, + lcl_aSelectPageAttrMap); + break; + case XML_ELEMENT(TEXT, XML_PAGE_ADJUST): + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber(nTmp, sAttrValue)) + { + nPageAdjust = static_cast<sal_Int16>(nTmp); + } + break; + } + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +void XMLPageNumberImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + // all properties are optional + Reference<XPropertySetInfo> xPropertySetInfo( + xPropertySet->getPropertySetInfo()); + + if (xPropertySetInfo->hasPropertyByName(sPropertyNumberingType)) + { + sal_Int16 nNumType; + if( sNumberFormatOK ) + { + nNumType= style::NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, + sNumberFormat, + sNumberSync ); + } + else + nNumType = style::NumberingType::PAGE_DESCRIPTOR; + + xPropertySet->setPropertyValue(sPropertyNumberingType, Any(nNumType)); + } + + if (xPropertySetInfo->hasPropertyByName(sPropertyOffset)) + { + // adjust offset + switch (eSelectPage) + { + case PageNumberType_PREV: + nPageAdjust--; + break; + case PageNumberType_CURRENT: + break; + case PageNumberType_NEXT: + nPageAdjust++; + break; + default: + SAL_WARN("xmloff.text", "unknown page number type"); + } + xPropertySet->setPropertyValue(sPropertyOffset, Any(nPageAdjust)); + } + + if (xPropertySetInfo->hasPropertyByName(sPropertySubType)) + { + xPropertySet->setPropertyValue(sPropertySubType, Any(eSelectPage)); + } +} + + +// Placeholder + + +constexpr OUStringLiteral gsPropertyPlaceholderType(u"PlaceHolderType"); +constexpr OUStringLiteral gsPropertyPlaceholder(u"PlaceHolder"); + +XMLPlaceholderFieldImportContext::XMLPlaceholderFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) +: XMLTextFieldImportContext(rImport, rHlp, "JumpEdit") +, sPropertyHint(sAPI_hint) +, nPlaceholderType(PlaceholderType::TEXT) +{ +} + +/// process attribute values +void XMLPlaceholderFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + switch (nAttrToken) { + case XML_ELEMENT(TEXT, XML_DESCRIPTION): + sDescription = OUString::fromUtf8(sAttrValue); + break; + + case XML_ELEMENT(TEXT, XML_PLACEHOLDER_TYPE): + bValid = true; + if (IsXMLToken(sAttrValue, XML_TABLE)) + { + nPlaceholderType = PlaceholderType::TABLE; + } + else if (IsXMLToken(sAttrValue, XML_TEXT)) + { + nPlaceholderType = PlaceholderType::TEXT; + } + else if (IsXMLToken(sAttrValue, XML_TEXT_BOX)) + { + nPlaceholderType = PlaceholderType::TEXTFRAME; + } + else if (IsXMLToken(sAttrValue, XML_IMAGE)) + { + nPlaceholderType = PlaceholderType::GRAPHIC; + } + else if (IsXMLToken(sAttrValue, XML_OBJECT)) + { + nPlaceholderType = PlaceholderType::OBJECT; + } + else + { + bValid = false; + } + break; + + default: + // ignore + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +void XMLPlaceholderFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) { + + Any aAny; + xPropertySet->setPropertyValue(sPropertyHint, Any(sDescription)); + + // remove <...> around content (if present) + OUString aContent = GetContent(); + sal_Int32 nStart = 0; + sal_Int32 nLength = aContent.getLength(); + if (aContent.startsWith("<")) + { + --nLength; + ++nStart; + } + if (aContent.endsWith(">")) + { + --nLength; + } + aAny <<= aContent.copy(nStart, nLength); + xPropertySet->setPropertyValue(gsPropertyPlaceholder, aAny); + + xPropertySet->setPropertyValue(gsPropertyPlaceholderType, Any(nPlaceholderType)); +} + + +// time field + +constexpr OUString gsPropertyAdjust(u"Adjust"_ustr); + +XMLTimeFieldImportContext::XMLTimeFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) +: XMLTextFieldImportContext(rImport, rHlp, sAPI_date_time) +, sPropertyNumberFormat(sAPI_number_format) +, sPropertyFixed(sAPI_is_fixed) +, sPropertyDateTimeValue(sAPI_date_time_value) +, sPropertyDateTime(sAPI_date_time) +, sPropertyIsDate(sAPI_is_date) +, sPropertyIsFixedLanguage(sAPI_is_fixed_language) +, nAdjust(0) +, nFormatKey(0) +, bTimeOK(false) +, bFormatOK(false) +, bFixed(false) +, bIsDate(false) +, bIsDefaultLanguage( true ) +{ + bValid = true; // always valid! +} + +void XMLTimeFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_TIME_VALUE): + case XML_ELEMENT(OFFICE, XML_TIME_VALUE): + { + if (::sax::Converter::parseTimeOrDateTime(aDateTimeValue, sAttrValue)) + { + bTimeOK = true; + } + break; + } + case XML_ELEMENT(TEXT, XML_FIXED): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sAttrValue)) + { + bFixed = bTmp; + } + break; + } + case XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME): + { + sal_Int32 nKey = GetImportHelper().GetDataStyleKey( + OUString::fromUtf8(sAttrValue), &bIsDefaultLanguage); + if (-1 != nKey) + { + nFormatKey = nKey; + bFormatOK = true; + } + break; + } + case XML_ELEMENT(TEXT, XML_TIME_ADJUST): + { + double fTmp; + + if (::sax::Converter::convertDuration(fTmp, sAttrValue)) + { + // convert to minutes + nAdjust = static_cast<sal_Int32>(::rtl::math::approxFloor(fTmp * 60 * 24)); + } + break; + } + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +void XMLTimeFieldImportContext::PrepareField( + const Reference<XPropertySet> & rPropertySet) +{ + // all properties are optional (except IsDate) + Reference<XPropertySetInfo> xPropertySetInfo( + rPropertySet->getPropertySetInfo()); + + if (xPropertySetInfo->hasPropertyByName(sPropertyFixed)) + { + rPropertySet->setPropertyValue(sPropertyFixed, Any(bFixed)); + } + + rPropertySet->setPropertyValue(sPropertyIsDate, Any(bIsDate)); + + if (xPropertySetInfo->hasPropertyByName(gsPropertyAdjust)) + { + rPropertySet->setPropertyValue(gsPropertyAdjust, Any(nAdjust)); + } + + // set value + if (bFixed) + { + // organizer or styles-only mode: force update + if (GetImport().GetTextImport()->IsOrganizerMode() || + GetImport().GetTextImport()->IsStylesOnlyMode() ) + { + ForceUpdate(rPropertySet); + } + else + { + // normal mode: set value (if present) + if (bTimeOK) + { + if (xPropertySetInfo->hasPropertyByName(sPropertyDateTimeValue)) + { + rPropertySet->setPropertyValue(sPropertyDateTimeValue, Any(aDateTimeValue)); + } + else if (xPropertySetInfo->hasPropertyByName(sPropertyDateTime)) + { + rPropertySet->setPropertyValue(sPropertyDateTime, Any(aDateTimeValue)); + } + } + } + } + + if (bFormatOK && + xPropertySetInfo->hasPropertyByName(sPropertyNumberFormat)) + { + rPropertySet->setPropertyValue(sPropertyNumberFormat, Any(nFormatKey)); + + if( xPropertySetInfo->hasPropertyByName( sPropertyIsFixedLanguage ) ) + { + bool bIsFixedLanguage = ! bIsDefaultLanguage; + rPropertySet->setPropertyValue( sPropertyIsFixedLanguage, Any(bIsFixedLanguage) ); + } + } +} + + +// date field + + +XMLDateFieldImportContext::XMLDateFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTimeFieldImportContext(rImport, rHlp) +{ + bIsDate = true; // always a date! +} + +void XMLDateFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_DATE_VALUE): + case XML_ELEMENT(OFFICE, XML_DATE_VALUE): + { + if (::sax::Converter::parseDateTime(aDateTimeValue, sAttrValue)) + { + bTimeOK = true; + } + break; + } + case XML_ELEMENT(TEXT, XML_DATE_ADJUST): + // delegate to superclass, pretending it was a time-adjust attr. + XMLTimeFieldImportContext::ProcessAttribute( + XML_ELEMENT(TEXT, XML_TIME_ADJUST), + sAttrValue); + break; + case XML_ELEMENT(TEXT, XML_TIME_VALUE): + case XML_ELEMENT(OFFICE, XML_TIME_VALUE): + case XML_ELEMENT(TEXT, XML_TIME_ADJUST): + ; // ignore time-adjust and time-value attributes + break; + default: + // all others: delegate to super-class + return XMLTimeFieldImportContext::ProcessAttribute(nAttrToken, + sAttrValue); + break; + } +} + + +// database field superclass + + +constexpr OUStringLiteral gsPropertyDataBaseName(u"DataBaseName"); +constexpr OUStringLiteral gsPropertyDataBaseURL(u"DataBaseURL"); +constexpr OUStringLiteral gsPropertyTableName(u"DataTableName"); +constexpr OUStringLiteral gsPropertyDataCommandType(u"DataCommandType"); +constexpr OUStringLiteral gsPropertyIsVisible(u"IsVisible"); + +XMLDatabaseFieldImportContext::XMLDatabaseFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + const OUString& pServiceName, bool bUseDisplay) +: XMLTextFieldImportContext(rImport, rHlp, pServiceName) +, m_nCommandType( sdb::CommandType::TABLE ) +, m_bCommandTypeOK(false) +, m_bDisplay( true ) +, m_bDisplayOK( false ) +, m_bUseDisplay( bUseDisplay ) +, m_bDatabaseOK(false) +, m_bDatabaseNameOK(false) +, m_bDatabaseURLOK(false) +, m_bTableOK(false) +{ +} + +void XMLDatabaseFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_DATABASE_NAME): + m_sDatabaseName = OUString::fromUtf8(sAttrValue); + m_bDatabaseOK = true; + m_bDatabaseNameOK = true; + break; + case XML_ELEMENT(TEXT, XML_TABLE_NAME): + m_sTableName = OUString::fromUtf8(sAttrValue); + m_bTableOK = true; + break; + case XML_ELEMENT(TEXT, XML_TABLE_TYPE): + if( IsXMLToken( sAttrValue, XML_TABLE ) ) + { + m_nCommandType = sdb::CommandType::TABLE; + m_bCommandTypeOK = true; + } + else if( IsXMLToken( sAttrValue, XML_QUERY ) ) + { + m_nCommandType = sdb::CommandType::QUERY; + m_bCommandTypeOK = true; + } + else if( IsXMLToken( sAttrValue, XML_COMMAND ) ) + { + m_nCommandType = sdb::CommandType::COMMAND; + m_bCommandTypeOK = true; + } + break; + case XML_ELEMENT(TEXT, XML_DISPLAY): + if( IsXMLToken( sAttrValue, XML_NONE ) ) + { + m_bDisplay = false; + m_bDisplayOK = true; + } + else if( IsXMLToken( sAttrValue, XML_VALUE ) ) + { + m_bDisplay = true; + m_bDisplayOK = true; + } + break; + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLDatabaseFieldImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if (nElement == XML_ELEMENT(FORM, XML_CONNECTION_RESOURCE) ) + { + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(XLINK, XML_HREF): + { + m_sDatabaseURL = aIter.toString(); + m_bDatabaseOK = true; + m_bDatabaseURLOK = true; + } + break; + default:; + } + } + + // we call ProcessAttribute in order to set bValid appropriately + ProcessAttribute( XML_TOKEN_INVALID, "" ); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + + +void XMLDatabaseFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + xPropertySet->setPropertyValue(gsPropertyTableName, Any(m_sTableName)); + + if( m_bDatabaseNameOK ) + { + xPropertySet->setPropertyValue(gsPropertyDataBaseName, Any(m_sDatabaseName)); + } + else if( m_bDatabaseURLOK ) + { + xPropertySet->setPropertyValue(gsPropertyDataBaseURL, Any(m_sDatabaseURL)); + } + + // #99980# load/save command type for all fields; also load + // old documents without command type + if( m_bCommandTypeOK ) + { + xPropertySet->setPropertyValue( gsPropertyDataCommandType, Any(m_nCommandType) ); + } + + if( m_bUseDisplay && m_bDisplayOK ) + { + xPropertySet->setPropertyValue( gsPropertyIsVisible, Any(m_bDisplay) ); + } +} + + +// database name field + + +XMLDatabaseNameImportContext::XMLDatabaseNameImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLDatabaseFieldImportContext(rImport, rHlp, "DatabaseName", true) +{ +} + +void XMLDatabaseNameImportContext::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + // delegate to superclass and check for success + XMLDatabaseFieldImportContext::ProcessAttribute(nAttrToken, sAttrValue); + bValid = m_bDatabaseOK && m_bTableOK; +} + + +// database next field + + +XMLDatabaseNextImportContext::XMLDatabaseNextImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + const OUString& pServiceName) : + XMLDatabaseFieldImportContext(rImport, rHlp, pServiceName, false), + sPropertyCondition(sAPI_condition), + sTrue(sAPI_true), + bConditionOK(false) +{ +} + +XMLDatabaseNextImportContext::XMLDatabaseNextImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) +: XMLDatabaseFieldImportContext(rImport, rHlp, "DatabaseNextSet", false) +, sPropertyCondition(sAPI_condition) +, sTrue(sAPI_true) +, bConditionOK(false) +{ +} + +void XMLDatabaseNextImportContext::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + if (XML_ELEMENT(TEXT, XML_CONDITION) == nAttrToken) + { + OUString sTmp; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrValueQName( + OUString::fromUtf8(sAttrValue), &sTmp ); + if( XML_NAMESPACE_OOOW == nPrefix ) + { + sCondition = sTmp; + bConditionOK = true; + } + else + sCondition = OUString::fromUtf8(sAttrValue); + } + else + { + XMLDatabaseFieldImportContext::ProcessAttribute(nAttrToken, + sAttrValue); + } + + bValid = m_bDatabaseOK && m_bTableOK; +} + +void XMLDatabaseNextImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + Any aAny; + + aAny <<= bConditionOK ? sCondition : sTrue; + xPropertySet->setPropertyValue(sPropertyCondition, aAny); + + XMLDatabaseFieldImportContext::PrepareField(xPropertySet); +} + + +// database select field + + +XMLDatabaseSelectImportContext::XMLDatabaseSelectImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLDatabaseNextImportContext(rImport, rHlp, "DatabaseNumberOfSet"), + sPropertySetNumber(sAPI_set_number), + nNumber(0), + bNumberOK(false) +{ +} + +void XMLDatabaseSelectImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + if (XML_ELEMENT(TEXT, XML_ROW_NUMBER) == nAttrToken) + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber( nTmp, sAttrValue + /* , nMin, nMax ??? */ )) + { + nNumber = nTmp; + bNumberOK = true; + } + } + else + { + XMLDatabaseNextImportContext::ProcessAttribute(nAttrToken, sAttrValue); + } + + bValid = m_bTableOK && m_bDatabaseOK && bNumberOK; +} + +void XMLDatabaseSelectImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + xPropertySet->setPropertyValue(sPropertySetNumber, Any(nNumber)); + + XMLDatabaseNextImportContext::PrepareField(xPropertySet); +} + + +// database display row number field + + +XMLDatabaseNumberImportContext::XMLDatabaseNumberImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLDatabaseFieldImportContext(rImport, rHlp, "DatabaseSetNumber", true), + sPropertyNumberingType( + sAPI_numbering_type), + sPropertySetNumber(sAPI_set_number), + sNumberFormat("1"), + sNumberSync(GetXMLToken(XML_FALSE)), + nValue(0), + bValueOK(false) +{ +} + +void XMLDatabaseNumberImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + sNumberFormat = OUString::fromUtf8(sAttrValue); + break; + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + sNumberSync = OUString::fromUtf8(sAttrValue); + break; + case XML_ELEMENT(TEXT, XML_VALUE_TYPE): + case XML_ELEMENT(OFFICE, XML_VALUE_TYPE): + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber( nTmp, sAttrValue )) + { + nValue = nTmp; + bValueOK = true; + } + break; + } + default: + XMLDatabaseFieldImportContext::ProcessAttribute(nAttrToken, + sAttrValue); + break; + } + + bValid = m_bTableOK && m_bDatabaseOK; +} + +void XMLDatabaseNumberImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + sal_Int16 nNumType = style::NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, + sNumberFormat, + sNumberSync ); + xPropertySet->setPropertyValue(sPropertyNumberingType, Any(nNumType)); + + if (bValueOK) + { + xPropertySet->setPropertyValue(sPropertySetNumber, Any(nValue)); + } + + XMLDatabaseFieldImportContext::PrepareField(xPropertySet); +} + + +// Simple doc info fields + + +XMLSimpleDocInfoImportContext::XMLSimpleDocInfoImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + sal_Int32 nElementToken, + bool bContent, bool bAuthor) +: XMLTextFieldImportContext(rImport, rHlp, MapTokenToServiceName(nElementToken) ) +, sPropertyFixed(sAPI_is_fixed) +, sPropertyContent(sAPI_content) +, sPropertyAuthor(sAPI_author) +, sPropertyCurrentPresentation(sAPI_current_presentation) +, bFixed(false) +, bHasAuthor(bAuthor) +, bHasContent(bContent) +{ + bValid = true; +} + +void XMLSimpleDocInfoImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + if (XML_ELEMENT(TEXT, XML_FIXED) == nAttrToken) + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sAttrValue)) + { + bFixed = bTmp; + } + } + else + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +void XMLSimpleDocInfoImportContext::PrepareField( + const Reference<XPropertySet> & rPropertySet) +{ + // title field in Calc has no Fixed property + Reference<XPropertySetInfo> xPropertySetInfo(rPropertySet->getPropertySetInfo()); + if (!xPropertySetInfo->hasPropertyByName(sPropertyFixed)) + return; + + Any aAny; + rPropertySet->setPropertyValue(sPropertyFixed, Any(bFixed)); + + // set Content and CurrentPresentation (if fixed) + if (!bFixed) + return; + + // in organizer-mode or styles-only-mode, only force update + if (GetImport().GetTextImport()->IsOrganizerMode() || + GetImport().GetTextImport()->IsStylesOnlyMode() ) + { + ForceUpdate(rPropertySet); + } + else + { + // set content (author, if that's the name) and current + // presentation + aAny <<= GetContent(); + + if (bFixed && bHasAuthor) + { + rPropertySet->setPropertyValue(sPropertyAuthor, aAny); + } + + if (bFixed && bHasContent) + { + rPropertySet->setPropertyValue(sPropertyContent, aAny); + } + + rPropertySet->setPropertyValue(sPropertyCurrentPresentation, aAny); + } +} + +OUString XMLSimpleDocInfoImportContext::MapTokenToServiceName( + sal_Int32 nElementToken) +{ + OUString pServiceName; + + switch(nElementToken) + { + case XML_ELEMENT(TEXT, XML_INITIAL_CREATOR): + pServiceName = "DocInfo.CreateAuthor"; + break; + case XML_ELEMENT(TEXT, XML_CREATION_DATE): + pServiceName = sAPI_docinfo_create_date_time; + break; + case XML_ELEMENT(TEXT, XML_CREATION_TIME): + pServiceName = sAPI_docinfo_create_date_time; + break; + case XML_ELEMENT(TEXT, XML_DESCRIPTION): + pServiceName = "DocInfo.Description"; + break; + case XML_ELEMENT(TEXT, XML_EDITING_DURATION): + pServiceName = "DocInfo.EditTime"; + break; + case XML_ELEMENT(TEXT, XML_USER_DEFINED): + pServiceName = sAPI_docinfo_custom; + break; + case XML_ELEMENT(TEXT, XML_PRINTED_BY): + pServiceName = "DocInfo.PrintAuthor"; + break; + case XML_ELEMENT(TEXT, XML_PRINT_DATE): + pServiceName = sAPI_docinfo_print_date_time; + break; + case XML_ELEMENT(TEXT, XML_PRINT_TIME): + pServiceName = sAPI_docinfo_print_date_time; + break; + case XML_ELEMENT(TEXT, XML_KEYWORDS): + pServiceName = "DocInfo.KeyWords"; + break; + case XML_ELEMENT(TEXT, XML_SUBJECT): + pServiceName = "DocInfo.Subject"; + break; + case XML_ELEMENT(TEXT, XML_EDITING_CYCLES): + pServiceName = "DocInfo.Revision"; + break; + case XML_ELEMENT(TEXT, XML_CREATOR): + pServiceName = "DocInfo.ChangeAuthor"; + break; + case XML_ELEMENT(TEXT, XML_MODIFICATION_DATE): + pServiceName = sAPI_docinfo_change_date_time; + break; + case XML_ELEMENT(TEXT, XML_MODIFICATION_TIME): + pServiceName = sAPI_docinfo_change_date_time; + break; + case XML_ELEMENT(TEXT, XML_TITLE): + pServiceName = "DocInfo.Title"; + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElementToken); + assert(false); + } + + return pServiceName; +} + + +// revision field + +constexpr OUStringLiteral sPropertyRevision(u"Revision"); + +XMLRevisionDocInfoImportContext::XMLRevisionDocInfoImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, sal_Int32 nElement) : + XMLSimpleDocInfoImportContext(rImport, rHlp, nElement, false, false) +{ + bValid = true; +} + +void XMLRevisionDocInfoImportContext::PrepareField( + const Reference<XPropertySet> & rPropertySet) +{ + XMLSimpleDocInfoImportContext::PrepareField(rPropertySet); + + // set revision number + // if fixed, if not in organizer-mode, if not in styles-only-mode + if (!bFixed) + return; + + if ( GetImport().GetTextImport()->IsOrganizerMode() || + GetImport().GetTextImport()->IsStylesOnlyMode() ) + { + ForceUpdate(rPropertySet); + } + else + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber(nTmp, GetContent())) + { + rPropertySet->setPropertyValue(sPropertyRevision, Any(nTmp)); + } + } +} + + +// DocInfo fields with date/time attributes + + +XMLDateTimeDocInfoImportContext::XMLDateTimeDocInfoImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, sal_Int32 nElement) + : XMLSimpleDocInfoImportContext(rImport, rHlp, nElement, false, false) + , sPropertyNumberFormat(sAPI_number_format) + , sPropertyIsDate(sAPI_is_date) + , sPropertyIsFixedLanguage(sAPI_is_fixed_language) + , nFormat(0) + , bFormatOK(false) + , bIsDate(false) + , bHasDateTime(false) + , bIsDefaultLanguage(true) +{ + // we allow processing of EDIT_DURATION here, because import of actual + // is not supported anyway. If it was, we'd need an extra import class + // because times and time durations are presented differently! + + bValid = true; + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_CREATION_DATE): + case XML_ELEMENT(TEXT, XML_PRINT_DATE): + case XML_ELEMENT(TEXT, XML_MODIFICATION_DATE): + bIsDate = true; + bHasDateTime = true; + break; + case XML_ELEMENT(TEXT, XML_CREATION_TIME): + case XML_ELEMENT(TEXT, XML_PRINT_TIME): + case XML_ELEMENT(TEXT, XML_MODIFICATION_TIME): + bIsDate = false; + bHasDateTime = true; + break; + case XML_ELEMENT(TEXT, XML_EDITING_DURATION): + bIsDate = false; + bHasDateTime = false; + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + OSL_FAIL("XMLDateTimeDocInfoImportContext needs date/time doc. fields"); + bValid = false; + break; + } +} + +void XMLDateTimeDocInfoImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME): + { + sal_Int32 nKey = GetImportHelper().GetDataStyleKey( + OUString::fromUtf8(sAttrValue), &bIsDefaultLanguage); + if (-1 != nKey) + { + nFormat = nKey; + bFormatOK = true; + } + break; + } + case XML_ELEMENT(TEXT, XML_FIXED): + XMLSimpleDocInfoImportContext::ProcessAttribute(nAttrToken, + sAttrValue); + break; + default: + // ignore -> we can't set date/time value anyway! + break; + } +} + +void XMLDateTimeDocInfoImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + // process fixed and presentation + XMLSimpleDocInfoImportContext::PrepareField(xPropertySet); + + if (bHasDateTime) + { + xPropertySet->setPropertyValue(sPropertyIsDate, Any(bIsDate)); + } + + if (bFormatOK) + { + xPropertySet->setPropertyValue(sPropertyNumberFormat, Any(nFormat)); + + if( xPropertySet->getPropertySetInfo()-> + hasPropertyByName( sPropertyIsFixedLanguage ) ) + { + bool bIsFixedLanguage = ! bIsDefaultLanguage; + xPropertySet->setPropertyValue( sPropertyIsFixedLanguage, Any(bIsFixedLanguage) ); + } + } + + // can't set date/time/duration value! Sorry. +} + + +// user defined docinfo fields + + +XMLUserDocInfoImportContext::XMLUserDocInfoImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + sal_Int32 nElement) : + XMLSimpleDocInfoImportContext(rImport, rHlp, nElement, false, false) + , sPropertyName(sAPI_name) + , sPropertyNumberFormat(sAPI_number_format) + , sPropertyIsFixedLanguage(sAPI_is_fixed_language) + , nFormat(0) + , bFormatOK(false) + , bIsDefaultLanguage( true ) +{ + bValid = false; +} + +void XMLUserDocInfoImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME): + { + sal_Int32 nKey = GetImportHelper().GetDataStyleKey( + OUString::fromUtf8(sAttrValue), &bIsDefaultLanguage); + if (-1 != nKey) + { + nFormat = nKey; + bFormatOK = true; + } + break; + } + case XML_ELEMENT(TEXT, XML_NAME): + { + if (!bValid) + { + SetServiceName(sAPI_docinfo_custom ); + aName = OUString::fromUtf8(sAttrValue); + bValid = true; + } + break; + } + + default: + XMLSimpleDocInfoImportContext::ProcessAttribute(nAttrToken, + sAttrValue); + break; + } +} + +void XMLUserDocInfoImportContext::PrepareField( + const css::uno::Reference<css::beans::XPropertySet> & xPropertySet) +{ + if ( !aName.isEmpty() ) + { + xPropertySet->setPropertyValue(sPropertyName, Any(aName)); + } + Reference<XPropertySetInfo> xPropertySetInfo( + xPropertySet->getPropertySetInfo()); + if (bFormatOK && + xPropertySetInfo->hasPropertyByName(sPropertyNumberFormat)) + { + xPropertySet->setPropertyValue(sPropertyNumberFormat, Any(nFormat)); + + if( xPropertySetInfo->hasPropertyByName( sPropertyIsFixedLanguage ) ) + { + bool bIsFixedLanguage = ! bIsDefaultLanguage; + xPropertySet->setPropertyValue( sPropertyIsFixedLanguage, Any(bIsFixedLanguage) ); + } + } + + // call superclass to handle "fixed" + XMLSimpleDocInfoImportContext::PrepareField(xPropertySet); +} + + +// import hidden paragraph fields + + +XMLHiddenParagraphImportContext::XMLHiddenParagraphImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "HiddenParagraph"), + sPropertyCondition(sAPI_condition), + sPropertyIsHidden(sAPI_is_hidden), + bIsHidden(false) +{ +} + +void XMLHiddenParagraphImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + if ( XML_ELEMENT(TEXT, XML_CONDITION) == nAttrToken) + { + OUString sTmp; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrValueQName( + OUString::fromUtf8(sAttrValue), &sTmp ); + if( XML_NAMESPACE_OOOW == nPrefix ) + { + sCondition = sTmp; + bValid = true; + } + else + sCondition = OUString::fromUtf8(sAttrValue); + } + else if ( XML_ELEMENT(TEXT, XML_IS_HIDDEN) == nAttrToken) + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sAttrValue)) + { + bIsHidden = bTmp; + } + } + else + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +void XMLHiddenParagraphImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + xPropertySet->setPropertyValue(sPropertyCondition, Any(sCondition)); + xPropertySet->setPropertyValue(sPropertyIsHidden, Any(bIsHidden)); +} + + +// import conditional text (<text:conditional-text>) + +constexpr OUStringLiteral gsPropertyTrueContent(u"TrueContent"); +constexpr OUStringLiteral gsPropertyFalseContent(u"FalseContent"); +constexpr OUStringLiteral gsPropertyIsConditionTrue(u"IsConditionTrue"); + +XMLConditionalTextImportContext::XMLConditionalTextImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "ConditionalText"), + sPropertyCondition(sAPI_condition), + sPropertyCurrentPresentation(sAPI_current_presentation), + bConditionOK(false), + bTrueOK(false), + bFalseOK(false), + bCurrentValue(false) +{ +} + +void XMLConditionalTextImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_CONDITION): + { + OUString sTmp; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap(). + GetKeyByAttrValueQName(OUString::fromUtf8(sAttrValue), &sTmp); + if( XML_NAMESPACE_OOOW == nPrefix ) + { + sCondition = sTmp; + bConditionOK = true; + } + else + sCondition = OUString::fromUtf8(sAttrValue); + } + break; + case XML_ELEMENT(TEXT, XML_STRING_VALUE_IF_FALSE): + sFalseContent = OUString::fromUtf8(sAttrValue); + bFalseOK = true; + break; + case XML_ELEMENT(TEXT, XML_STRING_VALUE_IF_TRUE): + sTrueContent = OUString::fromUtf8(sAttrValue); + bTrueOK = true; + break; + case XML_ELEMENT(TEXT, XML_CURRENT_VALUE): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sAttrValue)) + { + bCurrentValue = bTmp; + } + break; + } + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } + + bValid = bConditionOK && bFalseOK && bTrueOK; +} + +void XMLConditionalTextImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + xPropertySet->setPropertyValue(sPropertyCondition, Any(sCondition)); + xPropertySet->setPropertyValue(gsPropertyFalseContent, Any(sFalseContent)); + xPropertySet->setPropertyValue(gsPropertyTrueContent, Any(sTrueContent)); + xPropertySet->setPropertyValue(gsPropertyIsConditionTrue, Any(bCurrentValue)); + xPropertySet->setPropertyValue(sPropertyCurrentPresentation, Any(GetContent())); +} + + +// hidden text + + +XMLHiddenTextImportContext::XMLHiddenTextImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "HiddenText"), + sPropertyCondition(sAPI_condition), + sPropertyContent(sAPI_content), + sPropertyIsHidden(sAPI_is_hidden), + bConditionOK(false), + bStringOK(false), + bIsHidden(false) +{ +} + +void XMLHiddenTextImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_CONDITION): + { + OUString sTmp; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap(). + GetKeyByAttrValueQName(OUString::fromUtf8(sAttrValue), &sTmp); + if( XML_NAMESPACE_OOOW == nPrefix ) + { + sCondition = sTmp; + bConditionOK = true; + } + else + sCondition = OUString::fromUtf8(sAttrValue); + } + break; + case XML_ELEMENT(TEXT, XML_STRING_VALUE): + case XML_ELEMENT(OFFICE, XML_STRING_VALUE): + sString = OUString::fromUtf8(sAttrValue); + bStringOK = true; + break; + case XML_ELEMENT(TEXT, XML_IS_HIDDEN): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sAttrValue)) + { + bIsHidden = bTmp; + } + break; + } + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } + + bValid = bConditionOK && bStringOK; +} + +void XMLHiddenTextImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + xPropertySet->setPropertyValue(sPropertyCondition, Any(sCondition)); + xPropertySet->setPropertyValue(sPropertyContent, Any(sString)); + xPropertySet->setPropertyValue(sPropertyIsHidden, Any(bIsHidden)); +} + + +// file name fields + + +const SvXMLEnumMapEntry<sal_uInt16> aFilenameDisplayMap[] = +{ + { XML_PATH, FilenameDisplayFormat::PATH }, + { XML_NAME, FilenameDisplayFormat::NAME }, + { XML_NAME_AND_EXTENSION, FilenameDisplayFormat::NAME_AND_EXT }, + { XML_FULL, FilenameDisplayFormat::FULL }, + { XML_TOKEN_INVALID, 0 } +}; + +XMLFileNameImportContext::XMLFileNameImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "FileName"), + sPropertyFixed(sAPI_is_fixed), + sPropertyFileFormat(sAPI_file_format), + sPropertyCurrentPresentation( + sAPI_current_presentation), + nFormat(FilenameDisplayFormat::FULL), + bFixed(false) +{ + bValid = true; +} + +void XMLFileNameImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_FIXED): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sAttrValue)) + { + bFixed = bTmp; + } + break; + } + case XML_ELEMENT(TEXT, XML_DISPLAY): + { + sal_uInt16 nTmp; + if (SvXMLUnitConverter::convertEnum(nTmp, sAttrValue, + aFilenameDisplayMap)) + { + nFormat = nTmp; + } + break; + } + default: + // unknown attribute: ignore + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + break; + } +} + +void XMLFileNameImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + // properties are optional + Reference<XPropertySetInfo> xPropertySetInfo( + xPropertySet->getPropertySetInfo()); + + if (xPropertySetInfo->hasPropertyByName(sPropertyFixed)) + { + xPropertySet->setPropertyValue(sPropertyFixed, Any(bFixed)); + } + + if (xPropertySetInfo->hasPropertyByName(sPropertyFileFormat)) + { + xPropertySet->setPropertyValue(sPropertyFileFormat, Any(nFormat)); + } + + if (xPropertySetInfo->hasPropertyByName(sPropertyCurrentPresentation)) + { + xPropertySet->setPropertyValue(sPropertyCurrentPresentation, Any(GetContent())); + } +} + + +// template name field + + +const SvXMLEnumMapEntry<sal_uInt16> aTemplateDisplayMap[] = +{ + { XML_FULL, TemplateDisplayFormat::FULL }, + { XML_PATH, TemplateDisplayFormat::PATH }, + { XML_NAME, TemplateDisplayFormat::NAME }, + { XML_NAME_AND_EXTENSION, TemplateDisplayFormat::NAME_AND_EXT }, + { XML_AREA, TemplateDisplayFormat::AREA }, + { XML_TITLE, TemplateDisplayFormat::TITLE }, + { XML_TOKEN_INVALID, 0 } +}; + + +XMLTemplateNameImportContext::XMLTemplateNameImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "TemplateName"), + sPropertyFileFormat(sAPI_file_format), + nFormat(TemplateDisplayFormat::FULL) +{ + bValid = true; +} + +void XMLTemplateNameImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_DISPLAY): + { + sal_uInt16 nTmp; + if (SvXMLUnitConverter::convertEnum(nTmp, sAttrValue, + aTemplateDisplayMap)) + { + nFormat = nTmp; + } + break; + } + default: + // unknown attribute: ignore + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + break; + } +} + +void XMLTemplateNameImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + xPropertySet->setPropertyValue(sPropertyFileFormat, Any(nFormat)); +} + + +// import chapter fields + + +const SvXMLEnumMapEntry<sal_uInt16> aChapterDisplayMap[] = +{ + { XML_NAME, ChapterFormat::NAME }, + { XML_NUMBER, ChapterFormat::NUMBER }, + { XML_NUMBER_AND_NAME, ChapterFormat::NAME_NUMBER }, + { XML_PLAIN_NUMBER_AND_NAME, ChapterFormat::NO_PREFIX_SUFFIX }, + { XML_PLAIN_NUMBER, ChapterFormat::DIGIT }, + { XML_TOKEN_INVALID, 0 } +}; + +constexpr OUStringLiteral gsPropertyChapterFormat(u"ChapterFormat"); +constexpr OUStringLiteral gsPropertyLevel(u"Level"); + +XMLChapterImportContext::XMLChapterImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "Chapter"), + nFormat(ChapterFormat::NAME_NUMBER), + nLevel(0) +{ + bValid = true; +} + +void XMLChapterImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_DISPLAY): + { + sal_uInt16 nTmp; + if (SvXMLUnitConverter::convertEnum(nTmp, sAttrValue, + aChapterDisplayMap)) + { + nFormat = static_cast<sal_Int16>(nTmp); + } + break; + } + case XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL): + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber( + nTmp, sAttrValue, 1, + GetImport().GetTextImport()->GetChapterNumbering()->getCount() + )) + { + // API numbers 0..9, we number 1..10 + nLevel = static_cast<sal_Int8>(nTmp); + nLevel--; + } + break; + } + default: + // unknown attribute: ignore + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + break; + } +} + +void XMLChapterImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + xPropertySet->setPropertyValue(gsPropertyChapterFormat, Any(nFormat)); + xPropertySet->setPropertyValue(gsPropertyLevel, Any(nLevel)); +} + + +// counting fields + + +XMLCountFieldImportContext::XMLCountFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + sal_Int32 nElement) : + XMLTextFieldImportContext(rImport, rHlp, MapTokenToServiceName(nElement)), + sPropertyNumberingType( + sAPI_numbering_type), + bNumberFormatOK(false) +{ + bValid = true; +} + +void XMLCountFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + sNumberFormat = OUString::fromUtf8(sAttrValue); + bNumberFormatOK = true; + break; + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + sLetterSync = OUString::fromUtf8(sAttrValue); + break; + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +void XMLCountFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + // properties optional + // (only page count, but do for all to save common implementation) + + if (!xPropertySet->getPropertySetInfo()-> + hasPropertyByName(sPropertyNumberingType)) + return; + + sal_Int16 nNumType; + if( bNumberFormatOK ) + { + nNumType= style::NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, + sNumberFormat, + sLetterSync ); + } + else + nNumType = style::NumberingType::PAGE_DESCRIPTOR; + xPropertySet->setPropertyValue(sPropertyNumberingType, Any(nNumType)); +} + +OUString XMLCountFieldImportContext::MapTokenToServiceName( + sal_Int32 nElement) +{ + OUString pServiceName; + + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_WORD_COUNT): + pServiceName = "WordCount"; + break; + case XML_ELEMENT(TEXT, XML_PARAGRAPH_COUNT): + pServiceName = "ParagraphCount"; + break; + case XML_ELEMENT(TEXT, XML_TABLE_COUNT): + pServiceName = "TableCount"; + break; + case XML_ELEMENT(TEXT, XML_CHARACTER_COUNT): + pServiceName = "CharacterCount"; + break; + case XML_ELEMENT(TEXT, XML_IMAGE_COUNT): + pServiceName = "GraphicObjectCount"; + break; + case XML_ELEMENT(TEXT, XML_OBJECT_COUNT): + pServiceName = "EmbeddedObjectCount"; + break; + case XML_ELEMENT(TEXT, XML_PAGE_COUNT): + pServiceName = "PageCount"; + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + assert(false); + } + + return pServiceName; +} + + +// page variable import + + +XMLPageVarGetFieldImportContext::XMLPageVarGetFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "ReferencePageGet"), + bNumberFormatOK(false) +{ + bValid = true; +} + +void XMLPageVarGetFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + sNumberFormat = OUString::fromUtf8(sAttrValue); + bNumberFormatOK = true; + break; + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + sLetterSync = OUString::fromUtf8(sAttrValue); + break; + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +void XMLPageVarGetFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + sal_Int16 nNumType; + if( bNumberFormatOK ) + { + nNumType= style::NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, + sNumberFormat, + sLetterSync ); + } + else + nNumType = style::NumberingType::PAGE_DESCRIPTOR; + xPropertySet->setPropertyValue(sAPI_numbering_type, Any(nNumType)); + + // display old content (#96657#) + xPropertySet->setPropertyValue( sAPI_current_presentation, Any(GetContent()) ); +} + + +// page variable set fields + + +XMLPageVarSetFieldImportContext::XMLPageVarSetFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "ReferencePageSet"), + nAdjust(0), + bActive(true) +{ + bValid = true; +} + +void XMLPageVarSetFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_ACTIVE): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sAttrValue)) + { + bActive = bTmp; + } + break; + } + case XML_ELEMENT(TEXT, XML_PAGE_ADJUST): + { + sal_Int32 nTmp(0); + if (::sax::Converter::convertNumber(nTmp, sAttrValue)) + { + nAdjust = static_cast<sal_Int16>(nTmp); + } + break; + } + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + break; + } +} + +void XMLPageVarSetFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + xPropertySet->setPropertyValue("On", Any(bActive)); + xPropertySet->setPropertyValue(sAPI_offset, Any(nAdjust)); +} + + +// macro fields + + +XMLMacroFieldImportContext::XMLMacroFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "Macro"), + bDescriptionOK(false) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLMacroFieldImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if ( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + // create events context and remember it! + xEventContext = new XMLEventsImportContext( GetImport() ); + bValid = true; + return xEventContext; + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + +void XMLMacroFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_DESCRIPTION): + sDescription = OUString::fromUtf8(sAttrValue); + bDescriptionOK = true; + break; + case XML_ELEMENT(TEXT, XML_NAME): + sMacro = OUString::fromUtf8(sAttrValue); + bValid = true; + break; + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +void XMLMacroFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + Any aAny; + aAny <<= (bDescriptionOK ? sDescription : GetContent()); + xPropertySet->setPropertyValue(sAPI_hint, aAny); + + // if we have an events child element, we'll look for the OnClick + // event if not, it may be an old (pre-638i) document. Then, we'll + // have to look at the name attribute. + OUString sMacroName; + OUString sLibraryName; + OUString sScriptURL; + + if ( xEventContext.is() ) + { + // get event sequence + XMLEventsImportContext* pEvents = xEventContext.get(); + Sequence<PropertyValue> aValues; + pEvents->GetEventSequence( "OnClick", aValues ); + + for( const auto& rValue : std::as_const(aValues) ) + { + if ( rValue.Name == "ScriptType" ) + { + // ignore ScriptType + } + else if ( rValue.Name == "Library" ) + { + rValue.Value >>= sLibraryName; + } + else if ( rValue.Name == "MacroName" ) + { + rValue.Value >>= sMacroName; + } + if ( rValue.Name == "Script" ) + { + rValue.Value >>= sScriptURL; + } + } + } + else + { + // disassemble old-style macro-name: Everything before the + // third-last dot is the library + sal_Int32 nPos = sMacro.getLength() + 1; // the loop starts with nPos-- + const sal_Unicode* pBuf = sMacro.getStr(); + for( sal_Int32 i = 0; (i < 3) && (nPos > 0); i++ ) + { + nPos--; + while ( (pBuf[nPos] != '.') && (nPos > 0) ) + nPos--; + } + + if (nPos > 0) + { + sLibraryName = sMacro.copy(0, nPos); + sMacroName = sMacro.copy(nPos+1); + } + else + sMacroName = sMacro; + } + + xPropertySet->setPropertyValue("ScriptURL", Any(sScriptURL)); + xPropertySet->setPropertyValue("MacroName", Any(sMacroName)); + xPropertySet->setPropertyValue("MacroLibrary", Any(sLibraryName)); +} + + +// reference field import + + +XMLReferenceFieldImportContext::XMLReferenceFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + sal_Int32 nToken) +: XMLTextFieldImportContext(rImport, rHlp, "GetReference") +, nElementToken(nToken) +, nSource(0) +, nType(ReferenceFieldPart::PAGE_DESC) +, nFlags(0) +, bNameOK(false) +, bTypeOK(false) +{ +} + +SvXMLEnumMapEntry<sal_uInt16> const lcl_aReferenceTypeTokenMap[] = +{ + { XML_PAGE, ReferenceFieldPart::PAGE}, + { XML_CHAPTER, ReferenceFieldPart::CHAPTER }, + { XML_TEXT, ReferenceFieldPart::TEXT }, + { XML_DIRECTION, ReferenceFieldPart::UP_DOWN }, + { XML_CATEGORY_AND_VALUE, ReferenceFieldPart::CATEGORY_AND_NUMBER }, + { XML_CAPTION, ReferenceFieldPart::ONLY_CAPTION }, + { XML_VALUE, ReferenceFieldPart::ONLY_SEQUENCE_NUMBER }, + // Core implementation for direct cross-references (#i81002#) + { XML_NUMBER, ReferenceFieldPart::NUMBER }, + { XML_NUMBER_NO_SUPERIOR, ReferenceFieldPart::NUMBER_NO_CONTEXT }, + { XML_NUMBER_ALL_SUPERIOR, ReferenceFieldPart::NUMBER_FULL_CONTEXT }, + { XML_TOKEN_INVALID, 0 } +}; + +void XMLReferenceFieldImportContext::startFastElement( + sal_Int32 nElement, + const Reference<XFastAttributeList> & xAttrList) +{ + bTypeOK = true; + switch (nElementToken) + { + case XML_ELEMENT(TEXT, XML_REFERENCE_REF): + nSource = ReferenceFieldSource::REFERENCE_MARK; + break; + case XML_ELEMENT(TEXT, XML_BOOKMARK_REF): + nSource = ReferenceFieldSource::BOOKMARK; + break; + case XML_ELEMENT(TEXT, XML_NOTE_REF): + nSource = ReferenceFieldSource::FOOTNOTE; + break; + case XML_ELEMENT(TEXT, XML_SEQUENCE_REF): + nSource = ReferenceFieldSource::SEQUENCE_FIELD; + break; + case XML_ELEMENT(TEXT, XML_STYLE_REF): + case XML_ELEMENT(LO_EXT, XML_STYLE_REF): + nSource = ReferenceFieldSource::STYLE; + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElementToken); + bTypeOK = false; + break; + } + + XMLTextFieldImportContext::startFastElement(nElement, xAttrList); +} + + +void XMLReferenceFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_NOTE_CLASS): + if( IsXMLToken( sAttrValue, XML_ENDNOTE ) ) + nSource = ReferenceFieldSource::ENDNOTE; + break; + case XML_ELEMENT(TEXT, XML_REF_NAME): + sName = OUString::fromUtf8(sAttrValue); + bNameOK = true; + break; + case XML_ELEMENT(TEXT, XML_REFERENCE_FORMAT): + { + sal_uInt16 nToken; + if (SvXMLUnitConverter::convertEnum(nToken, sAttrValue, + lcl_aReferenceTypeTokenMap)) + { + nType = nToken; + } + + // check for sequence-only-attributes + if ( (XML_ELEMENT(TEXT, XML_SEQUENCE_REF) != nElementToken) && + ( (nType == ReferenceFieldPart::CATEGORY_AND_NUMBER) || + (nType == ReferenceFieldPart::ONLY_CAPTION) || + (nType == ReferenceFieldPart::ONLY_SEQUENCE_NUMBER) ) ) + { + nType = ReferenceFieldPart::PAGE_DESC; + } + + break; + } + case XML_ELEMENT(LO_EXT, XML_REFERENCE_LANGUAGE): + case XML_ELEMENT(TEXT, XML_REFERENCE_LANGUAGE): + sLanguage = OUString::fromUtf8(sAttrValue); + break; + case XML_ELEMENT(LO_EXT, XML_REFERENCE_HIDE_NON_NUMERICAL): + case XML_ELEMENT(TEXT, XML_REFERENCE_HIDE_NON_NUMERICAL): + if (OUString::fromUtf8(sAttrValue).toBoolean()) + nFlags |= REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL; + break; + case XML_ELEMENT(LO_EXT, XML_REFERENCE_FROM_BOTTOM): + case XML_ELEMENT(TEXT, XML_REFERENCE_FROM_BOTTOM): + if (OUString::fromUtf8(sAttrValue).toBoolean()) + nFlags |= REFFLDFLAG_STYLE_FROM_BOTTOM; + break; + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } + + // bValid: we need proper element type and name + bValid = bTypeOK && bNameOK; +} + +void XMLReferenceFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + xPropertySet->setPropertyValue("ReferenceFieldPart", Any(nType)); + + xPropertySet->setPropertyValue("ReferenceFieldSource", Any(nSource)); + + xPropertySet->setPropertyValue("ReferenceFieldLanguage", Any(sLanguage)); + switch (nElementToken) + { + case XML_ELEMENT(TEXT, XML_REFERENCE_REF): + case XML_ELEMENT(TEXT, XML_BOOKMARK_REF): + case XML_ELEMENT(TEXT, XML_STYLE_REF): + case XML_ELEMENT(LO_EXT, XML_STYLE_REF): + xPropertySet->setPropertyValue("SourceName", Any(sName)); + xPropertySet->setPropertyValue("ReferenceFieldFlags", Any(nFlags)); + break; + + case XML_ELEMENT(TEXT, XML_NOTE_REF): + GetImportHelper().ProcessFootnoteReference(sName, xPropertySet); + break; + + case XML_ELEMENT(TEXT, XML_SEQUENCE_REF): + GetImportHelper().ProcessSequenceReference(sName, xPropertySet); + break; + } + + xPropertySet->setPropertyValue(sAPI_current_presentation, Any(GetContent())); +} + + +// field declarations container + +XMLDdeFieldDeclsImportContext::XMLDdeFieldDeclsImportContext(SvXMLImport& rImport) : + SvXMLImportContext(rImport) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLDdeFieldDeclsImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_DDE_CONNECTION_DECL) ) + { + return new XMLDdeFieldDeclImportContext(GetImport()); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + + +// import dde field declaration + + +XMLDdeFieldDeclImportContext::XMLDdeFieldDeclImportContext(SvXMLImport& rImport) +: SvXMLImportContext(rImport) +{ +} + +void XMLDdeFieldDeclImportContext::startFastElement( + sal_Int32 /*nElement*/, + const Reference<XFastAttributeList> & xAttrList) +{ + OUString sName; + OUString sCommandApplication; + OUString sCommandTopic; + OUString sCommandItem; + + bool bUpdate = false; + bool bNameOK = false; + bool bCommandApplicationOK = false; + bool bCommandTopicOK = false; + bool bCommandItemOK = false; + + // process attributes + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(OFFICE, XML_NAME): + sName = aIter.toString(); + bNameOK = true; + break; + case XML_ELEMENT(OFFICE, XML_DDE_APPLICATION): + sCommandApplication = aIter.toString(); + bCommandApplicationOK = true; + break; + case XML_ELEMENT(OFFICE, XML_DDE_TOPIC): + sCommandTopic = aIter.toString(); + bCommandTopicOK = true; + break; + case XML_ELEMENT(OFFICE, XML_DDE_ITEM): + sCommandItem = aIter.toString(); + bCommandItemOK = true; + break; + case XML_ELEMENT(OFFICE, XML_AUTOMATIC_UPDATE): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView()) ) + { + bUpdate = bTmp; + } + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // valid data? + if (!(bNameOK && bCommandApplicationOK && bCommandTopicOK && bCommandItemOK)) + return; + + // create DDE TextFieldMaster + Reference<XMultiServiceFactory> xFactory(GetImport().GetModel(), + UNO_QUERY); + if( !xFactory.is() ) + return; + + /* #i6432# There might be multiple occurrences of one DDE + declaration if it is used in more than one of + header/footer/body. createInstance will throw an exception if we + try to create the second, third, etc. instance of such a + declaration. Thus we ignore the exception. Otherwise this will + lead to an unloadable document. */ + try + { + Reference<XInterface> xIfc = + xFactory->createInstance(OUString::Concat(sAPI_fieldmaster_prefix) + sAPI_dde); + if( xIfc.is() ) + { + Reference<XPropertySet> xPropSet( xIfc, UNO_QUERY ); + if (xPropSet.is() && + xPropSet->getPropertySetInfo()->hasPropertyByName( + "DDECommandType")) + { + xPropSet->setPropertyValue(sAPI_name, Any(sName)); + + xPropSet->setPropertyValue("DDECommandType", Any(sCommandApplication)); + + xPropSet->setPropertyValue("DDECommandFile", Any(sCommandTopic)); + + xPropSet->setPropertyValue("DDECommandElement", + Any(sCommandItem)); + + xPropSet->setPropertyValue("IsAutomaticUpdate", + Any(bUpdate)); + } + // else: ignore (can't get XPropertySet, or DDE + // properties are not supported) + } + // else: ignore + } + catch (const Exception&) + { + //ignore + } + // else: ignore + // else: ignore +} + + +// DDE field import + + +XMLDdeFieldImportContext::XMLDdeFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, sAPI_dde), + sPropertyContent(sAPI_content) +{ +} + +void XMLDdeFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + if ( XML_ELEMENT(TEXT, XML_CONNECTION_NAME) == nAttrToken) + { + sName = OUString::fromUtf8(sAttrValue); + bValid = true; + } + else + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + + +void XMLDdeFieldImportContext::endFastElement(sal_Int32 ) +{ + if (!bValid) + return; + + // find master + OUString sMasterName = OUString::Concat(sAPI_fieldmaster_prefix) + sAPI_dde + "." + sName; + + Reference<XTextFieldsSupplier> xTextFieldsSupp(GetImport().GetModel(), + UNO_QUERY); + Reference<container::XNameAccess> xFieldMasterNameAccess = + xTextFieldsSupp->getTextFieldMasters(); + + if (!xFieldMasterNameAccess->hasByName(sMasterName)) + return; + + Reference<XPropertySet> xMaster; + Any aAny = xFieldMasterNameAccess->getByName(sMasterName); + aAny >>= xMaster; + //apply the content to the master + xMaster->setPropertyValue( sPropertyContent, uno::Any( GetContent())); + // master exists: create text field and attach + Reference<XPropertySet> xField; + OUString sFieldName = OUString::Concat(sAPI_textfield_prefix) + sAPI_dde; + if (!CreateField(xField, sFieldName)) + return; + + Reference<XDependentTextField> xDepTextField(xField,UNO_QUERY); + xDepTextField->attachTextFieldMaster(xMaster); + + // attach field to document + Reference<XTextContent> xTextContent(xField, UNO_QUERY); + if (xTextContent.is()) + { + GetImportHelper().InsertTextContent(xTextContent); + + // we're lucky. nothing else to prepare. + } + // else: fail, because text content could not be created + // else: fail, because field could not be created + // else: fail, because no master was found (faulty document?!) + // not valid: ignore +} + +void XMLDdeFieldImportContext::PrepareField( + const Reference<XPropertySet> &) +{ + // empty, since not needed. +} + + +// sheet name fields + + +XMLSheetNameImportContext::XMLSheetNameImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "SheetName") +{ + bValid = true; // always valid! +} + +void XMLSheetNameImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue) +{ + // no attributes -> nothing to be done + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +void XMLSheetNameImportContext::PrepareField( + const Reference<XPropertySet> &) +{ + // no attributes -> nothing to be done +} + +/** import page|slide name fields (<text:page-name>) */ + +XMLPageNameFieldImportContext::XMLPageNameFieldImportContext( + SvXMLImport& rImport, /// XML Import + XMLTextImportHelper& rHlp) /// Text import helper +: XMLTextFieldImportContext(rImport, rHlp, "PageName" ) +{ + bValid = true; +} + +/// process attribute values +void XMLPageNameFieldImportContext::ProcessAttribute( sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +/// prepare XTextField for insertion into document +void XMLPageNameFieldImportContext::PrepareField( + const css::uno::Reference<css::beans::XPropertySet> &) +{ +} + + +// URL fields (Calc, Impress, Draw) + + +XMLUrlFieldImportContext::XMLUrlFieldImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, sAPI_url), + bFrameOK(false) +{ +} + +void XMLUrlFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(XLINK, XML_HREF): + sURL = GetImport().GetAbsoluteReference( OUString::fromUtf8(sAttrValue) ); + bValid = true; + break; + case XML_ELEMENT(OFFICE, XML_TARGET_FRAME_NAME): + sFrame = OUString::fromUtf8(sAttrValue); + bFrameOK = true; + break; + default: + // ignore + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + break; + } +} + +void XMLUrlFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + xPropertySet->setPropertyValue(sAPI_url, Any(sURL)); + + if (bFrameOK) + { + xPropertySet->setPropertyValue("TargetFrame", Any(sFrame)); + } + + xPropertySet->setPropertyValue("Representation", Any(GetContent())); +} + + +XMLBibliographyFieldImportContext::XMLBibliographyFieldImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "Bibliography") +{ + bValid = true; +} + +// TODO: this is the same map as is used in the text field export +SvXMLEnumMapEntry<sal_uInt16> const aBibliographyDataTypeMap[] = +{ + { XML_ARTICLE, BibliographyDataType::ARTICLE }, + { XML_BOOK, BibliographyDataType::BOOK }, + { XML_BOOKLET, BibliographyDataType::BOOKLET }, + { XML_CONFERENCE, BibliographyDataType::CONFERENCE }, + { XML_CUSTOM1, BibliographyDataType::CUSTOM1 }, + { XML_CUSTOM2, BibliographyDataType::CUSTOM2 }, + { XML_CUSTOM3, BibliographyDataType::CUSTOM3 }, + { XML_CUSTOM4, BibliographyDataType::CUSTOM4 }, + { XML_CUSTOM5, BibliographyDataType::CUSTOM5 }, + { XML_EMAIL, BibliographyDataType::EMAIL }, + { XML_INBOOK, BibliographyDataType::INBOOK }, + { XML_INCOLLECTION, BibliographyDataType::INCOLLECTION }, + { XML_INPROCEEDINGS, BibliographyDataType::INPROCEEDINGS }, + { XML_JOURNAL, BibliographyDataType::JOURNAL }, + { XML_MANUAL, BibliographyDataType::MANUAL }, + { XML_MASTERSTHESIS, BibliographyDataType::MASTERSTHESIS }, + { XML_MISC, BibliographyDataType::MISC }, + { XML_PHDTHESIS, BibliographyDataType::PHDTHESIS }, + { XML_PROCEEDINGS, BibliographyDataType::PROCEEDINGS }, + { XML_TECHREPORT, BibliographyDataType::TECHREPORT }, + { XML_UNPUBLISHED, BibliographyDataType::UNPUBLISHED }, + { XML_WWW, BibliographyDataType::WWW }, + { XML_TOKEN_INVALID, 0 } +}; + + +// we'll process attributes on our own and for fit the standard +// textfield mechanism, because our attributes have zero overlap with +// all the other textfields. +void XMLBibliographyFieldImportContext::startFastElement( + sal_Int32 /*nElement*/, + const Reference<XFastAttributeList> & xAttrList) +{ + // iterate over attributes + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + { + if (IsTokenInNamespace(aIter.getToken(), XML_NAMESPACE_TEXT) + || IsTokenInNamespace(aIter.getToken(), XML_NAMESPACE_LO_EXT)) + { + auto nToken = aIter.getToken() & TOKEN_MASK; + PropertyValue aValue; + aValue.Name = OUString::createFromAscii( + MapBibliographyFieldName(nToken)); + Any aAny; + + // special treatment for bibliography type + // biblio vs bibilio: #96658#; also read old documents + if (nToken == XML_BIBILIOGRAPHIC_TYPE || + nToken == XML_BIBLIOGRAPHY_TYPE ) + { + sal_uInt16 nTmp; + if (SvXMLUnitConverter::convertEnum( + nTmp, aIter.toView(), + aBibliographyDataTypeMap)) + { + aAny <<= static_cast<sal_Int16>(nTmp); + aValue.Value = aAny; + + aValues.push_back(aValue); + } + } + else + { + OUString aStringValue = aIter.toString(); + if (nToken == XML_URL || nToken == XML_LOCAL_URL || nToken == XML_TARGET_URL) + { + aStringValue = GetImport().GetAbsoluteReference(aStringValue); + } + aAny <<= aStringValue; + aValue.Value = aAny; + + aValues.push_back(aValue); + } + } + // else: unknown namespace -> ignore + } +} + +void XMLBibliographyFieldImportContext::ProcessAttribute( + sal_Int32 , + std::string_view ) +{ + // attributes are handled in StartElement + assert(false && "This should not have happened."); +} + + +void XMLBibliographyFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + // convert vector into sequence + sal_Int32 nCount = aValues.size(); + Sequence<PropertyValue> aValueSequence(nCount); + auto aValueSequenceRange = asNonConstRange(aValueSequence); + for(sal_Int32 i = 0; i < nCount; i++) + { + aValueSequenceRange[i] = aValues[i]; + } + + // set sequence + xPropertySet->setPropertyValue("Fields", Any(aValueSequence)); +} + +const char* XMLBibliographyFieldImportContext::MapBibliographyFieldName( + sal_Int32 nElement) +{ + const char* pName = nullptr; + + switch (nElement & TOKEN_MASK) + { + case XML_IDENTIFIER: + pName = "Identifier"; + break; + case XML_BIBILIOGRAPHIC_TYPE: + case XML_BIBLIOGRAPHY_TYPE: + // biblio... vs bibilio...: #96658#: also read old documents + pName = "BibiliographicType"; + break; + case XML_ADDRESS: + pName = "Address"; + break; + case XML_ANNOTE: + pName = "Annote"; + break; + case XML_AUTHOR: + pName = "Author"; + break; + case XML_BOOKTITLE: + pName = "Booktitle"; + break; + case XML_CHAPTER: + pName = "Chapter"; + break; + case XML_EDITION: + pName = "Edition"; + break; + case XML_EDITOR: + pName = "Editor"; + break; + case XML_HOWPUBLISHED: + pName = "Howpublished"; + break; + case XML_INSTITUTION: + pName = "Institution"; + break; + case XML_JOURNAL: + pName = "Journal"; + break; + case XML_MONTH: + pName = "Month"; + break; + case XML_NOTE: + pName = "Note"; + break; + case XML_NUMBER: + pName = "Number"; + break; + case XML_ORGANIZATIONS: + pName = "Organizations"; + break; + case XML_PAGES: + pName = "Pages"; + break; + case XML_PUBLISHER: + pName = "Publisher"; + break; + case XML_SCHOOL: + pName = "School"; + break; + case XML_SERIES: + pName = "Series"; + break; + case XML_TITLE: + pName = "Title"; + break; + case XML_REPORT_TYPE: + pName = "Report_Type"; + break; + case XML_VOLUME: + pName = "Volume"; + break; + case XML_YEAR: + pName = "Year"; + break; + case XML_URL: + pName = "URL"; + break; + case XML_CUSTOM1: + pName = "Custom1"; + break; + case XML_CUSTOM2: + pName = "Custom2"; + break; + case XML_CUSTOM3: + pName = "Custom3"; + break; + case XML_CUSTOM4: + pName = "Custom4"; + break; + case XML_CUSTOM5: + pName = "Custom5"; + break; + case XML_ISBN: + pName = "ISBN"; + break; + case XML_LOCAL_URL: + pName = "LocalURL"; + break; + case XML_TARGET_TYPE: + pName = "TargetType"; + break; + case XML_TARGET_URL: + pName = "TargetURL"; + break; + default: + assert(false && "Unknown bibliography info data"); + pName = nullptr; + } + return pName; +} + +// Annotation Field + + +XMLAnnotationImportContext::XMLAnnotationImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp, + sal_Int32 nElement) : + XMLTextFieldImportContext(rImport, rHlp, "Annotation"), + mnElement(nElement) +{ + bValid = true; + + // remember old list item and block (#91964#) and reset them + // for the text frame + // do this in the constructor, not in CreateChildContext (#i93392#) + GetImport().GetTextImport()->PushListContext(); +} + +void XMLAnnotationImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + if (nAttrToken == XML_ELEMENT(OFFICE, XML_NAME)) + aName = OUString::fromUtf8(sAttrValue); + else if (nAttrToken == XML_ELEMENT(LO_EXT, XML_RESOLVED)) + aResolved = OUString::fromUtf8(sAttrValue); + else if (nAttrToken == XML_ELEMENT(LO_EXT, XML_PARENT_NAME)) + aParentName = OUString::fromUtf8(sAttrValue); + else + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLAnnotationImportContext::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + if( nElement == XML_ELEMENT(DC, XML_CREATOR) ) + return new XMLStringBufferImportContext(GetImport(), aAuthorBuffer); + else if( nElement == XML_ELEMENT(DC, XML_DATE) ) + return new XMLStringBufferImportContext(GetImport(), aDateBuffer); + else if (nElement == XML_ELEMENT(TEXT,XML_SENDER_INITIALS) || + nElement == XML_ELEMENT(LO_EXT, XML_SENDER_INITIALS) || + nElement == XML_ELEMENT(META, XML_CREATOR_INITIALS)) + return new XMLStringBufferImportContext(GetImport(), aInitialsBuffer); + + try + { + bool bOK = true; + if ( !mxField.is() ) + bOK = CreateField( mxField, sServicePrefix + GetServiceName() ); + if (bOK) + { + Any aAny = mxField->getPropertyValue( "TextRange" ); + Reference< XText > xText; + aAny >>= xText; + if( xText.is() ) + { + rtl::Reference < XMLTextImportHelper > xTxtImport = GetImport().GetTextImport(); + if( !mxCursor.is() ) + { + mxOldCursor = xTxtImport->GetCursor(); + mxCursor = xText->createTextCursor(); + } + + if( mxCursor.is() ) + { + xTxtImport->SetCursor( mxCursor ); + return xTxtImport->CreateTextChildContext( GetImport(), nElement, xAttrList ); + } + } + } + } + catch (const Exception&) + { + } + + return new XMLStringBufferImportContext(GetImport(), aTextBuffer); +} + +void XMLAnnotationImportContext::endFastElement(sal_Int32 /*nElement*/) +{ + DBG_ASSERT(!GetServiceName().isEmpty(), "no service name for element!"); + if( mxCursor.is() ) + { + // delete addition newline + mxCursor->gotoEnd( false ); + mxCursor->goLeft( 1, true ); + mxCursor->setString( "" ); + + // reset cursor + GetImport().GetTextImport()->ResetCursor(); + } + + if( mxOldCursor.is() ) + GetImport().GetTextImport()->SetCursor( mxOldCursor ); + + // reinstall old list item #91964# + GetImport().GetTextImport()->PopListContext(); + + if ( bValid ) + { + if ( mnElement == XML_ELEMENT(OFFICE, XML_ANNOTATION_END) ) + { + // Search for a previous annotation with the same name. + uno::Reference< text::XTextContent > xPrevField; + { + Reference<XTextFieldsSupplier> xTextFieldsSupplier(GetImport().GetModel(), UNO_QUERY); + uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields()); + uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration()); + while (xFields->hasMoreElements()) + { + uno::Reference<beans::XPropertySet> xCurrField(xFields->nextElement(), uno::UNO_QUERY); + uno::Reference<beans::XPropertySetInfo> const xInfo( + xCurrField->getPropertySetInfo()); + if (xInfo->hasPropertyByName(sAPI_name)) + { + OUString aFieldName; + xCurrField->getPropertyValue(sAPI_name) >>= aFieldName; + if (aFieldName == aName) + { + xPrevField.set( xCurrField, uno::UNO_QUERY ); + break; + } + } + } + } + if ( xPrevField.is() ) + { + // So we are ending a previous annotation, + // let's create a text range covering the old and the current position. + uno::Reference<text::XText> xText = GetImportHelper().GetText(); + uno::Reference<text::XTextCursor> xCursor = + xText->createTextCursorByRange(GetImportHelper().GetCursorAsRange()); + try + { + xCursor->gotoRange(xPrevField->getAnchor(), true); + } + catch (const uno::RuntimeException&) + { + // Losing the start of the anchor is better than not opening the document at + // all. + TOOLS_WARN_EXCEPTION( + "xmloff.text", + "XMLAnnotationImportContext::endFastElement: gotoRange() failed: "); + } + + xText->insertTextContent(xCursor, xPrevField, !xCursor->isCollapsed()); + } + } + else + { + if ( mxField.is() || CreateField( mxField, sServicePrefix + GetServiceName() ) ) + { + // set field properties + PrepareField( mxField ); + + // attach field to document + Reference < XTextContent > xTextContent( mxField, UNO_QUERY ); + + // workaround for #80606# + try + { + GetImportHelper().InsertTextContent( xTextContent ); + } + catch (const lang::IllegalArgumentException&) + { + // ignore + } + } + } + } + else + GetImportHelper().InsertString(GetContent()); +} + +void XMLAnnotationImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet ) +{ + // import (possibly empty) author + OUString sAuthor( aAuthorBuffer.makeStringAndClear() ); + xPropertySet->setPropertyValue(sAPI_author, Any(sAuthor)); + + // import (possibly empty) initials + OUString sInitials( aInitialsBuffer.makeStringAndClear() ); + xPropertySet->setPropertyValue("Initials", Any(sInitials)); + + //import resolved flag + bool bTmp(false); + (void)::sax::Converter::convertBool(bTmp, aResolved); + xPropertySet->setPropertyValue("Resolved", Any(bTmp)); + + util::DateTime aDateTime; + if (::sax::Converter::parseDateTime(aDateTime, aDateBuffer)) + { + /* + Date aDate; + aDate.Year = aDateTime.Year; + aDate.Month = aDateTime.Month; + aDate.Day = aDateTime.Day; + xPropertySet->setPropertyValue(sPropertyDate, makeAny(aDate)); + */ + // why is there no UNO_NAME_DATE_TIME, but only UNO_NAME_DATE_TIME_VALUE? + xPropertySet->setPropertyValue(sAPI_date_time_value, Any(aDateTime)); + } + aDateBuffer.setLength(0); + + if ( aTextBuffer.getLength() ) + { + // delete last paragraph mark (if necessary) + if (char(0x0a) == aTextBuffer[aTextBuffer.getLength()-1]) + aTextBuffer.setLength(aTextBuffer.getLength()-1); + xPropertySet->setPropertyValue(sAPI_content, Any(aTextBuffer.makeStringAndClear())); + } + + if (!aName.isEmpty()) + xPropertySet->setPropertyValue(sAPI_name, Any(aName)); + + if (!aParentName.isEmpty()) + xPropertySet->setPropertyValue(sAPI_parent_name, Any(aParentName)); +} + + +// script field + + +XMLScriptImportContext::XMLScriptImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp) +: XMLTextFieldImportContext(rImport, rHlp, "Script") +, bContentOK(false) +{ +} + +void XMLScriptImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(XLINK, XML_HREF): + sContent = GetImport().GetAbsoluteReference( OUString::fromUtf8(sAttrValue) ); + bContentOK = true; + break; + + case XML_ELEMENT(SCRIPT, XML_LANGUAGE): + sScriptType = OUString::fromUtf8(sAttrValue); + break; + + default: + // ignore + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + break; + } + + // always valid (even without ScriptType; cf- #96531#) + bValid = true; +} + +void XMLScriptImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + // if href attribute was present, we use it. Else we use element content + if (! bContentOK) + { + sContent = GetContent(); + } + xPropertySet->setPropertyValue(sAPI_content, Any(sContent)); + + // URL or script text? We use URL if we have an href-attribute + xPropertySet->setPropertyValue("URLContent", Any(bContentOK)); + + xPropertySet->setPropertyValue("ScriptType", Any(sScriptType)); +} + + +// measure field + + +XMLMeasureFieldImportContext::XMLMeasureFieldImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "Measure"), + mnKind( 0 ) +{ +} + +void XMLMeasureFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_KIND): + if( IsXMLToken( sAttrValue, XML_VALUE ) ) + { + mnKind = 0; bValid = true; + } + else if( IsXMLToken( sAttrValue, XML_UNIT ) ) + { + mnKind = 1; bValid = true; + } + else if( IsXMLToken( sAttrValue, XML_GAP ) ) + { + mnKind = 2; bValid = true; + } + break; + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +void XMLMeasureFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + xPropertySet->setPropertyValue("Kind", Any(mnKind)); +} + + +// dropdown field + + +XMLDropDownFieldImportContext::XMLDropDownFieldImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext( rImport, rHlp, "DropDown" ), + nSelected( -1 ), + bNameOK( false ), + bHelpOK(false), + bHintOK(false) +{ + bValid = true; +} + +static bool lcl_ProcessLabel( + const Reference<XFastAttributeList>& xAttrList, + OUString& rLabel, + bool& rIsSelected ) +{ + bool bValid = false; + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_VALUE): + { + rLabel = aIter.toString(); + bValid = true; + break; + } + case XML_ELEMENT(TEXT, XML_CURRENT_SELECTED): + { + bool bTmp(false); + if (::sax::Converter::convertBool( bTmp, aIter.toView() )) + rIsSelected = bTmp; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + return bValid; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLDropDownFieldImportContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(TEXT, XML_LABEL) ) + { + OUString sLabel; + bool bIsSelected = false; + if( lcl_ProcessLabel( xAttrList, sLabel, bIsSelected ) ) + { + if( bIsSelected ) + nSelected = static_cast<sal_Int32>( aLabels.size() ); + aLabels.push_back( sLabel ); + } + } + return new SvXMLImportContext( GetImport() ); +} + +void XMLDropDownFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + if( nAttrToken == XML_ELEMENT(TEXT, XML_NAME)) + { + sName = OUString::fromUtf8(sAttrValue); + bNameOK = true; + } + else if (nAttrToken == XML_ELEMENT(TEXT, XML_HELP)) + { + sHelp = OUString::fromUtf8(sAttrValue); + bHelpOK = true; + } + else if (nAttrToken == XML_ELEMENT(TEXT, XML_HINT)) + { + sHint = OUString::fromUtf8(sAttrValue); + bHintOK = true; + } + else + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +void XMLDropDownFieldImportContext::PrepareField( + const Reference<XPropertySet>& xPropertySet) +{ + // create sequence + sal_Int32 nLength = static_cast<sal_Int32>( aLabels.size() ); + Sequence<OUString> aSequence( nLength ); + OUString* pSequence = aSequence.getArray(); + for( sal_Int32 n = 0; n < nLength; n++ ) + pSequence[n] = aLabels[n]; + + // now set values: + + xPropertySet->setPropertyValue( "Items", Any(aSequence) ); + + if( nSelected >= 0 && nSelected < nLength ) + { + xPropertySet->setPropertyValue( "SelectedItem", Any(pSequence[nSelected]) ); + } + + // set name + if( bNameOK ) + { + xPropertySet->setPropertyValue( "Name", Any(sName) ); + } + // set help + if( bHelpOK ) + { + xPropertySet->setPropertyValue( "Help", Any(sHelp) ); + } + // set hint + if( bHintOK ) + { + xPropertySet->setPropertyValue( "Tooltip", Any(sHint) ); + } + +} + +/** import header fields (<draw:header>) */ + +XMLHeaderFieldImportContext::XMLHeaderFieldImportContext( + SvXMLImport& rImport, /// XML Import + XMLTextImportHelper& rHlp) /// Text import helper +: XMLTextFieldImportContext(rImport, rHlp, "Header" ) +{ + sServicePrefix = sAPI_presentation_prefix; + bValid = true; +} + +/// process attribute values +void XMLHeaderFieldImportContext::ProcessAttribute( sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +/// prepare XTextField for insertion into document +void XMLHeaderFieldImportContext::PrepareField(const Reference<XPropertySet> &) +{ +} + +/** import footer fields (<draw:footer>) */ + +XMLFooterFieldImportContext::XMLFooterFieldImportContext( + SvXMLImport& rImport, /// XML Import + XMLTextImportHelper& rHlp) /// Text import helper +: XMLTextFieldImportContext(rImport, rHlp, "Footer" ) +{ + sServicePrefix = sAPI_presentation_prefix; + bValid = true; +} + +/// process attribute values +void XMLFooterFieldImportContext::ProcessAttribute( sal_Int32 nAttrToken, std::string_view sAttrValue) +{ + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +/// prepare XTextField for insertion into document +void XMLFooterFieldImportContext::PrepareField(const Reference<XPropertySet> &) +{ +} + + +/** import footer fields (<draw:date-and-time>) */ + +XMLDateTimeFieldImportContext::XMLDateTimeFieldImportContext( + SvXMLImport& rImport, /// XML Import + XMLTextImportHelper& rHlp) /// Text import helper +: XMLTextFieldImportContext(rImport, rHlp, "DateTime" ) +{ + sServicePrefix = sAPI_presentation_prefix; + bValid = true; +} + +/// process attribute values +void XMLDateTimeFieldImportContext::ProcessAttribute( sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +/// prepare XTextField for insertion into document +void XMLDateTimeFieldImportContext::PrepareField( + const css::uno::Reference< + css::beans::XPropertySet> &) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtftne.cxx b/xmloff/source/text/txtftne.cxx new file mode 100644 index 0000000000..9673b15745 --- /dev/null +++ b/xmloff/source/text/txtftne.cxx @@ -0,0 +1,344 @@ +/* -*- 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 . + */ + + +/** @#file + * + * This file implements XMLTextParagraphExport methods to export + * - footnotes + * - endnotes + * - footnote configuration elements + * - endnote configuration elements + */ + +#include <sal/config.h> +#include <sal/log.hxx> + +#include <o3tl/any.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/text/XFootnote.hpp> +#include <com/sun/star/text/XFootnotesSupplier.hpp> +#include <com/sun/star/text/XEndnotesSupplier.hpp> +#include <com/sun/star/text/FootnoteNumbering.hpp> +#include <com/sun/star/container/XNameReplace.hpp> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/families.hxx> +#include "XMLTextCharStyleNamesElementExport.hxx" +#include <xmloff/XMLEventExport.hxx> +#include <xmloff/txtparae.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::container; +using namespace ::xmloff::token; + + +void XMLTextParagraphExport::exportTextFootnote( + const Reference<XPropertySet> & rPropSet, + const OUString& rText, + bool bAutoStyles, bool bIsProgress ) +{ + // get footnote and associated text + Any aAny = rPropSet->getPropertyValue(gsFootnote); + Reference<XFootnote> xFootnote; + aAny >>= xFootnote; + Reference<XText> xText(xFootnote, UNO_QUERY); + + // are we an endnote? + Reference<XServiceInfo> xServiceInfo( xFootnote, UNO_QUERY ); + bool bIsEndnote = xServiceInfo->supportsService(gsTextEndnoteService); + + if (bAutoStyles) + { + // handle formatting of citation mark + Add( XmlStyleFamily::TEXT_TEXT, rPropSet ); + + // handle formatting within footnote + exportTextFootnoteHelper(xFootnote, xText, rText, + bAutoStyles, bIsEndnote, bIsProgress ); + } + else + { + // create span (for citation mark) if necessary; footnote content + // will be handled via exportTextFootnoteHelper, exportText + bool bIsUICharStyle = false; + bool bHasAutoStyle = false; + + OUString sStyle = FindTextStyle( rPropSet, bIsUICharStyle, bHasAutoStyle ); + + { + XMLTextCharStyleNamesElementExport aCharStylesExport( + GetExport(), bIsUICharStyle && + m_aCharStyleNamesPropInfoCache.hasProperty( + rPropSet ), bHasAutoStyle, + rPropSet, gsCharStyleNames ); + if( !sStyle.isEmpty() ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sStyle ) ); + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + XML_SPAN, false, false ); + exportTextFootnoteHelper(xFootnote, xText, rText, + bAutoStyles, bIsEndnote, bIsProgress ); + } + else + { + exportTextFootnoteHelper(xFootnote, xText, rText, + bAutoStyles, bIsEndnote, bIsProgress ); + } + } + } +} + + +void XMLTextParagraphExport::exportTextFootnoteHelper( + const Reference<XFootnote> & rFootnote, + const Reference<XText> & rText, + const OUString& rTextString, + bool bAutoStyles, + bool bIsEndnote, + bool bIsProgress ) +{ + if (bAutoStyles) + { + exportText(rText, bAutoStyles, bIsProgress, true ); + } + else + { + // export reference Id (for reference fields) + Reference<XPropertySet> xPropSet(rFootnote, UNO_QUERY); + Any aAny = xPropSet->getPropertyValue(gsReferenceId); + sal_Int32 nNumber = 0; + aAny >>= nNumber; + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_ID, + "ftn" + OUString::number(nNumber)); + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NOTE_CLASS, + GetXMLToken( bIsEndnote ? XML_ENDNOTE + : XML_FOOTNOTE ) ); + + SvXMLElementExport aNote(GetExport(), XML_NAMESPACE_TEXT, + XML_NOTE, false, false); + { + // handle label vs. automatic numbering + OUString sLabel = rFootnote->getLabel(); + if (!sLabel.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_LABEL, + sLabel); + } + // else: automatic numbering -> no attribute + + SvXMLElementExport aCite(GetExport(), XML_NAMESPACE_TEXT, + XML_NOTE_CITATION, false, false); + GetExport().Characters(rTextString); + } + + { + SvXMLElementExport aBody(GetExport(), XML_NAMESPACE_TEXT, + XML_NOTE_BODY, false, false); + exportText(rText, bAutoStyles, bIsProgress, true ); + } + } +} + + +void XMLTextParagraphExport::exportTextFootnoteConfiguration() +{ + // footnote settings + Reference<XFootnotesSupplier> aFootnotesSupplier(GetExport().GetModel(), + UNO_QUERY); + Reference<XPropertySet> aFootnoteConfiguration( + aFootnotesSupplier->getFootnoteSettings()); + exportTextFootnoteConfigurationHelper(aFootnoteConfiguration, false); + + // endnote settings + Reference<XEndnotesSupplier> aEndnotesSupplier(GetExport().GetModel(), + UNO_QUERY); + Reference<XPropertySet> aEndnoteConfiguration( + aEndnotesSupplier->getEndnoteSettings()); + exportTextFootnoteConfigurationHelper(aEndnoteConfiguration, true); +} + + +static void lcl_exportString( + SvXMLExport& rExport, + const Reference<XPropertySet> & rPropSet, + const OUString& sProperty, + sal_uInt16 nPrefix, + enum XMLTokenEnum eElement, + bool bEncodeName) +{ + SAL_WARN_IF( eElement == XML_TOKEN_INVALID, "xmloff", "need element token"); + + Any aAny = rPropSet->getPropertyValue(sProperty); + OUString sTmp; + aAny >>= sTmp; + if (!sTmp.isEmpty()) + { + if( bEncodeName ) + sTmp = rExport.EncodeStyleName( sTmp ); + rExport.AddAttribute(nPrefix, eElement, sTmp); + } +} + +void XMLTextParagraphExport::exportTextFootnoteConfigurationHelper( + const Reference<XPropertySet> & rFootnoteConfig, + bool bIsEndnote) +{ + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NOTE_CLASS, + GetXMLToken( bIsEndnote ? XML_ENDNOTE + : XML_FOOTNOTE ) ); + // default/paragraph style + lcl_exportString( GetExport(), rFootnoteConfig, + gsParaStyleName, + XML_NAMESPACE_TEXT, XML_DEFAULT_STYLE_NAME, + true); + + // citation style + lcl_exportString( GetExport(), rFootnoteConfig, + gsCharStyleName, + XML_NAMESPACE_TEXT, XML_CITATION_STYLE_NAME, + true); + + // citation body style + lcl_exportString( GetExport(), rFootnoteConfig, + gsAnchorCharStyleName, + XML_NAMESPACE_TEXT, XML_CITATION_BODY_STYLE_NAME, + true); + + // page style + lcl_exportString( GetExport(), rFootnoteConfig, + gsPageStyleName, + XML_NAMESPACE_TEXT, XML_MASTER_PAGE_NAME, + true ); + + // prefix + lcl_exportString( GetExport(), rFootnoteConfig, gsPrefix, + XML_NAMESPACE_STYLE, XML_NUM_PREFIX, false); + + // suffix + lcl_exportString( GetExport(), rFootnoteConfig, gsSuffix, + XML_NAMESPACE_STYLE, XML_NUM_SUFFIX, false); + + + Any aAny; + + // numbering style + OUStringBuffer sBuffer; + aAny = rFootnoteConfig->getPropertyValue(gsNumberingType); + sal_Int16 nNumbering = 0; + aAny >>= nNumbering; + GetExport().GetMM100UnitConverter().convertNumFormat( sBuffer, nNumbering); + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_NUM_FORMAT, + sBuffer.makeStringAndClear() ); + SvXMLUnitConverter::convertNumLetterSync( sBuffer, nNumbering); + if (!sBuffer.isEmpty() ) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_NUM_LETTER_SYNC, + sBuffer.makeStringAndClear()); + } + + // StartAt / start-value + aAny = rFootnoteConfig->getPropertyValue(gsStartAt); + sal_Int16 nOffset = 0; + aAny >>= nOffset; + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_START_VALUE, + OUString::number(nOffset)); + + // some properties are for footnotes only + if (!bIsEndnote) + { + // footnotes position + aAny = rFootnoteConfig->getPropertyValue( + gsPositionEndOfDoc); + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_FOOTNOTES_POSITION, + ( (*o3tl::doAccess<bool>(aAny)) ? + XML_DOCUMENT : XML_PAGE ) ); + + aAny = rFootnoteConfig->getPropertyValue(gsFootnoteCounting); + sal_Int16 nTmp = 0; + aAny >>= nTmp; + enum XMLTokenEnum eElement; + switch (nTmp) + { + case FootnoteNumbering::PER_PAGE: + eElement = XML_PAGE; + break; + case FootnoteNumbering::PER_CHAPTER: + eElement = XML_CHAPTER; + break; + case FootnoteNumbering::PER_DOCUMENT: + default: + eElement = XML_DOCUMENT; + break; + } + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_START_NUMBERING_AT, eElement); + } + + // element + SvXMLElementExport aFootnoteConfigElement( + GetExport(), XML_NAMESPACE_TEXT, + XML_NOTES_CONFIGURATION, + true, true); + + // two element for footnote content + if (bIsEndnote) + return; + + OUString sTmp; + + // end notice / quo vadis + aAny = rFootnoteConfig->getPropertyValue(gsEndNotice); + aAny >>= sTmp; + + if (!sTmp.isEmpty()) + { + SvXMLElementExport aElem(GetExport(), XML_NAMESPACE_TEXT, + XML_FOOTNOTE_CONTINUATION_NOTICE_FORWARD, + true, false); + GetExport().Characters(sTmp); + } + + // begin notice / ergo sum + aAny = rFootnoteConfig->getPropertyValue(gsBeginNotice); + aAny >>= sTmp; + + if (!sTmp.isEmpty()) + { + SvXMLElementExport aElem(GetExport(), XML_NAMESPACE_TEXT, + XML_FOOTNOTE_CONTINUATION_NOTICE_BACKWARD, + true, false); + GetExport().Characters(sTmp); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtimp.cxx b/xmloff/source/text/txtimp.cxx new file mode 100644 index 0000000000..ac0e894742 --- /dev/null +++ b/xmloff/source/text/txtimp.cxx @@ -0,0 +1,2521 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <memory> +#include <optional> +#include <tuple> +#include <vector> + +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/text/ReferenceFieldSource.hpp> +#include <com/sun/star/text/XChapterNumberingSupplier.hpp> +#include <com/sun/star/text/XTextFrame.hpp> +#include <com/sun/star/text/XTextFieldsSupplier.hpp> +#include <com/sun/star/text/XTextFramesSupplier.hpp> +#include <com/sun/star/text/XTextGraphicObjectsSupplier.hpp> +#include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp> +#include <com/sun/star/text/XFormField.hpp> +#include <com/sun/star/ucb/XAnyCompareFactory.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/txtstyli.hxx> +#include <xmloff/xmlnumi.hxx> +#include <xmloff/maptype.hxx> + +#include <sal/log.hxx> +#include "txtparai.hxx" +#include <xmloff/txtprmap.hxx> +#include <xmloff/txtimppr.hxx> +#include <xmloff/xmlimp.hxx> +#include <txtvfldi.hxx> +#include <xmloff/i18nmap.hxx> +#include "XMLTextListItemContext.hxx" +#include "XMLTextListBlockContext.hxx" +#include "XMLTextFrameContext.hxx" +#include "XMLTextFrameHyperlinkContext.hxx" +#include "XMLSectionImportContext.hxx" +#include "XMLIndexTOCContext.hxx" +#include <xmloff/XMLEventsImportContext.hxx> +#include "XMLTrackedChangesImportContext.hxx" +#include "XMLChangeImportContext.hxx" +#include "XMLAutoMarkFileContext.hxx" +#include <xmloff/ProgressBarHelper.hxx> + +#include "XMLCalculationSettingsContext.hxx" +#include <XMLNumberStylesImport.hxx> +#include <PageMasterStyleMap.hxx> +#include <PageMasterPropHdlFactory.hxx> +#include <PageMasterPropMapper.hxx> +// XML import: reconstruction of assignment of paragraph style to outline levels (#i69629#) +#include <com/sun/star/beans/XPropertyState.hpp> +#include <txtlists.hxx> +#include <xmloff/odffields.hxx> +#include <comphelper/attributelist.hxx> + +using ::com::sun::star::ucb::XAnyCompare; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::lang; +using namespace ::xmloff::token; +using namespace ::com::sun::star::ucb; + + +// maximum allowed length of combined characters field +#define MAX_COMBINED_CHARACTERS 6 + +struct XMLTextImportHelper::Impl +{ + std::optional< std::vector<OUString> > m_xPrevFrmNames; + std::optional< std::vector<OUString> > m_xNextFrmNames; + std::unique_ptr<XMLTextListsHelper> m_xTextListsHelper; + + rtl::Reference<SvXMLStylesContext> m_xAutoStyles; + + rtl::Reference< SvXMLImportPropertyMapper > m_xParaImpPrMap; + rtl::Reference< SvXMLImportPropertyMapper > m_xTextImpPrMap; + rtl::Reference< SvXMLImportPropertyMapper > m_xFrameImpPrMap; + rtl::Reference< SvXMLImportPropertyMapper > m_xSectionImpPrMap; + rtl::Reference< SvXMLImportPropertyMapper > m_xRubyImpPrMap; + + std::unique_ptr<SvI18NMap> m_xRenameMap; + + /* Change and extend data structure: + - data structure contains candidates of paragraph styles, which + will be assigned to the outline style + - data structure contains more than one candidate for each list level + of the outline style (#i69629#) + */ + std::unique_ptr< std::vector< OUString > []> + m_xOutlineStylesCandidates; + + // start range, xml:id, RDFa stuff + typedef std::tuple< + uno::Reference<text::XTextRange>, OUString, + std::shared_ptr< ::xmloff::ParsedRDFaAttributes > > + BookmarkMapEntry_t; + /// start ranges for open bookmarks + std::map< OUString, BookmarkMapEntry_t > m_BookmarkStartRanges; + + std::vector< OUString > m_BookmarkVector; + + /// name of the last 'open' redline that started between paragraphs + OUString m_sOpenRedlineIdentifier; + + // Used for frame deduplication, the name of the last frame imported directly before the current one + OUString msLastImportedFrameName; + + std::map< OUString, bool > m_bBookmarkHidden; + std::map< OUString, OUString > m_sBookmarkCondition; + + uno::Reference<text::XText> m_xText; + uno::Reference<text::XTextCursor> m_xCursor; + uno::Reference<text::XTextRange> m_xCursorAsRange; + uno::Reference<container::XNameContainer> m_xParaStyles; + uno::Reference<container::XNameContainer> m_xTextStyles; + uno::Reference<container::XNameContainer> m_xNumStyles; + uno::Reference<container::XNameContainer> m_xFrameStyles; + uno::Reference<container::XNameContainer> m_xPageStyles; + uno::Reference<container::XNameContainer> m_xCellStyles; + uno::Reference<container::XIndexReplace> m_xChapterNumbering; + uno::Reference<container::XNameAccess> m_xTextFrames; + uno::Reference<container::XNameAccess> m_xGraphics; + uno::Reference<container::XNameAccess> m_xObjects; + uno::Reference<lang::XMultiServiceFactory> m_xServiceFactory; + + SvXMLImport & m_rSvXMLImport; + + bool m_bInsertMode : 1; + bool m_bStylesOnlyMode : 1; + bool m_bBlockMode : 1; + bool m_bProgress : 1; + bool m_bOrganizerMode : 1; + bool m_bBodyContentStarted : 1; + + /// Are we inside a <text:deletion> element (deleted redline section) + bool m_bInsideDeleteContext : 1; + + typedef ::std::pair< OUString, OUString> field_name_type_t; + typedef ::std::pair< OUString, OUString > field_param_t; + typedef ::std::vector< field_param_t > field_params_t; + typedef ::std::tuple<field_name_type_t, field_params_t, uno::Reference<text::XFormField>, uno::Reference<text::XTextRange>> field_stack_item_t; + typedef ::std::stack< field_stack_item_t > field_stack_t; + + field_stack_t m_FieldStack; + + OUString m_sCellParaStyleDefault; + + std::optional<std::map<OUString, OUString>> m_xCrossRefHeadingBookmarkMap; + + Impl( uno::Reference<frame::XModel> const& rModel, + SvXMLImport & rImport, + bool const bInsertMode, bool const bStylesOnlyMode, + bool const bProgress, bool const bBlockMode, + bool const bOrganizerMode) + : m_xTextListsHelper( new XMLTextListsHelper() ) + // XML import: reconstruction of assignment of paragraph style to outline levels (#i69629#) + , m_xServiceFactory( rModel, UNO_QUERY ) + , m_rSvXMLImport( rImport ) + , m_bInsertMode( bInsertMode ) + , m_bStylesOnlyMode( bStylesOnlyMode ) + , m_bBlockMode( bBlockMode ) + , m_bProgress( bProgress ) + , m_bOrganizerMode( bOrganizerMode ) + , m_bBodyContentStarted( true ) + , m_bInsideDeleteContext( false ) + { + } + Impl(const Impl&) = delete; + Impl& operator=(const Impl&) = delete; + + void InitOutlineStylesCandidates() + { + if (!m_xOutlineStylesCandidates) + { + size_t const size(m_xChapterNumbering->getCount()); + m_xOutlineStylesCandidates.reset( + new ::std::vector< OUString >[size] ); + } + } + +}; + + +uno::Reference< text::XText > & XMLTextImportHelper::GetText() +{ + return m_xImpl->m_xText; +} + +uno::Reference< text::XTextCursor > & XMLTextImportHelper::GetCursor() +{ + return m_xImpl->m_xCursor; +} + +uno::Reference< text::XTextRange > & XMLTextImportHelper::GetCursorAsRange() +{ + return m_xImpl->m_xCursorAsRange; +} + +bool XMLTextImportHelper::IsInsertMode() const +{ + return m_xImpl->m_bInsertMode; +} + +bool XMLTextImportHelper::IsStylesOnlyMode() const +{ + return m_xImpl->m_bStylesOnlyMode; +} + +bool XMLTextImportHelper::IsBlockMode() const +{ + return m_xImpl->m_bBlockMode; +} + +bool XMLTextImportHelper::IsOrganizerMode() const +{ + return m_xImpl->m_bOrganizerMode; +} + +bool XMLTextImportHelper::IsProgress() const +{ + return m_xImpl->m_bProgress; +} + +uno::Reference<container::XNameContainer> const& +XMLTextImportHelper::GetParaStyles() const +{ + return m_xImpl->m_xParaStyles; +} + +uno::Reference<container::XNameContainer> const& +XMLTextImportHelper::GetTextStyles() const +{ + return m_xImpl->m_xTextStyles; +} + +uno::Reference<container::XNameContainer> const& +XMLTextImportHelper::GetNumberingStyles() const +{ + return m_xImpl->m_xNumStyles; +} + +uno::Reference<container::XNameContainer> const& +XMLTextImportHelper::GetFrameStyles() const +{ + return m_xImpl->m_xFrameStyles; +} + +uno::Reference<container::XNameContainer> const& +XMLTextImportHelper::GetPageStyles() const +{ + return m_xImpl->m_xPageStyles; +} + +uno::Reference<container::XNameContainer> const& +XMLTextImportHelper::GetCellStyles() const +{ + return m_xImpl->m_xCellStyles; +} + +uno::Reference<container::XIndexReplace> const& +XMLTextImportHelper::GetChapterNumbering() const +{ + return m_xImpl->m_xChapterNumbering; +} + +rtl::Reference< SvXMLImportPropertyMapper > const& +XMLTextImportHelper::GetParaImportPropertySetMapper() const +{ + return m_xImpl->m_xParaImpPrMap; +} + +rtl::Reference< SvXMLImportPropertyMapper > const& +XMLTextImportHelper::GetTextImportPropertySetMapper() const +{ + return m_xImpl->m_xTextImpPrMap; +} + +rtl::Reference< SvXMLImportPropertyMapper > const& +XMLTextImportHelper::GetSectionImportPropertySetMapper() const +{ + return m_xImpl->m_xSectionImpPrMap; +} + +rtl::Reference< SvXMLImportPropertyMapper > const& +XMLTextImportHelper::GetRubyImportPropertySetMapper() const +{ + return m_xImpl->m_xRubyImpPrMap; +} + +void XMLTextImportHelper::SetInsideDeleteContext(bool const bNew) +{ + m_xImpl->m_bInsideDeleteContext = bNew; +} + +bool XMLTextImportHelper::IsInsideDeleteContext() const +{ + return m_xImpl->m_bInsideDeleteContext; +} + +SvXMLImport & XMLTextImportHelper::GetXMLImport() +{ + return m_xImpl->m_rSvXMLImport; +} + +XMLTextListsHelper & XMLTextImportHelper::GetTextListHelper() +{ + return *m_xImpl->m_xTextListsHelper; +} + +namespace +{ + class FieldParamImporter + { + public: + typedef std::pair<OUString,OUString> field_param_t; + typedef std::vector<field_param_t> field_params_t; + FieldParamImporter(const field_params_t* const pInParams, Reference<XNameContainer> const & xOutParams) + : m_pInParams(pInParams) + , m_xOutParams(xOutParams) + { }; + void Import(); + + private: + const field_params_t* const m_pInParams; + Reference<XNameContainer> m_xOutParams; + }; + + void FieldParamImporter::Import() + { + ::std::vector<OUString> vListEntries; + ::std::map<OUString, Any> vOutParams; + for(const auto& rCurrent : *m_pInParams) + { + if(rCurrent.first == ODF_FORMDROPDOWN_RESULT) + { + // sal_Int32 + vOutParams[rCurrent.first] <<= rCurrent.second.toInt32(); + } + else if(rCurrent.first == ODF_FORMCHECKBOX_RESULT) + { + // bool + vOutParams[rCurrent.first] <<= rCurrent.second.toBoolean(); + } + else if(rCurrent.first == ODF_FORMDROPDOWN_LISTENTRY) + { + // sequence + vListEntries.push_back(rCurrent.second); + } + else + vOutParams[rCurrent.first] <<= rCurrent.second; + } + if(!vListEntries.empty()) + { + Sequence<OUString> vListEntriesSeq(vListEntries.size()); + copy(vListEntries.begin(), vListEntries.end(), vListEntriesSeq.getArray()); + vOutParams[ODF_FORMDROPDOWN_LISTENTRY] <<= vListEntriesSeq; + } + for(const auto& rCurrent : vOutParams) + { + try + { + m_xOutParams->insertByName(rCurrent.first, rCurrent.second); + } + catch(const ElementExistException&) + { + SAL_INFO("xmloff.text", "duplicate fieldmark param"); + } + } + } +} + +XMLTextImportHelper::XMLTextImportHelper( + uno::Reference<frame::XModel> const& rModel, + SvXMLImport& rImport, + bool const bInsertMode, bool const bStylesOnlyMode, + bool const bProgress, bool const bBlockMode, + bool const bOrganizerMode) + : m_xImpl( new Impl(rModel, rImport, bInsertMode, bStylesOnlyMode, + bProgress, bBlockMode, bOrganizerMode) ) + , m_xBackpatcherImpl( MakeBackpatcherImpl() ) +{ + static constexpr OUString s_PropNameDefaultListId = u"DefaultListId"_ustr; + + Reference< XChapterNumberingSupplier > xCNSupplier( rModel, UNO_QUERY ); + + if (xCNSupplier.is()) + { + // note: m_xChapterNumbering is accessed to import some fields + m_xImpl->m_xChapterNumbering = xCNSupplier->getChapterNumberingRules(); + // the AutoCorrect document doesn't have a proper outline numbering + if (!IsBlockMode() && m_xImpl->m_xChapterNumbering.is()) + { + Reference< XPropertySet > const xNumRuleProps( + m_xImpl->m_xChapterNumbering, UNO_QUERY); + if ( xNumRuleProps.is() ) + { + Reference< XPropertySetInfo > xNumRulePropSetInfo( + xNumRuleProps->getPropertySetInfo()); + if (xNumRulePropSetInfo.is() && + xNumRulePropSetInfo->hasPropertyByName( + s_PropNameDefaultListId)) + { + OUString sListId; + xNumRuleProps->getPropertyValue(s_PropNameDefaultListId) + >>= sListId; + assert( !sListId.isEmpty() && + "no default list id found at chapter numbering rules instance. Serious defect." ); + if ( !sListId.isEmpty() ) + { + Reference< XNamed > const xChapterNumNamed( + m_xImpl->m_xChapterNumbering, UNO_QUERY); + if ( xChapterNumNamed.is() ) + { + m_xImpl->m_xTextListsHelper->KeepListAsProcessed( + sListId, + xChapterNumNamed->getName(), + OUString() ); + } + } + } + } + } + } + + Reference< XStyleFamiliesSupplier > xFamiliesSupp( rModel, UNO_QUERY ); +// SAL_WARN_IF( !xFamiliesSupp.is(), "xmloff", "no chapter numbering supplier" ); for clipboard there may be documents without styles + + if( xFamiliesSupp.is() ) + { + Reference< XNameAccess > xFamilies(xFamiliesSupp->getStyleFamilies()); + + static constexpr OUString aParaStyles(u"ParagraphStyles"_ustr); + if( xFamilies->hasByName( aParaStyles ) ) + { + m_xImpl->m_xParaStyles.set(xFamilies->getByName(aParaStyles), + UNO_QUERY); + } + + static constexpr OUString aCharStyles(u"CharacterStyles"_ustr); + if( xFamilies->hasByName( aCharStyles ) ) + { + m_xImpl->m_xTextStyles.set(xFamilies->getByName(aCharStyles), + UNO_QUERY); + } + + static constexpr OUString aNumStyles(u"NumberingStyles"_ustr); + if( xFamilies->hasByName( aNumStyles ) ) + { + m_xImpl->m_xNumStyles.set(xFamilies->getByName(aNumStyles), + UNO_QUERY); + } + + static constexpr OUString aFrameStyles(u"FrameStyles"_ustr); + if( xFamilies->hasByName( aFrameStyles ) ) + { + m_xImpl->m_xFrameStyles.set(xFamilies->getByName(aFrameStyles), + UNO_QUERY); + } + + static constexpr OUString aPageStyles(u"PageStyles"_ustr); + if( xFamilies->hasByName( aPageStyles ) ) + { + m_xImpl->m_xPageStyles.set(xFamilies->getByName(aPageStyles), + UNO_QUERY); + } + + static constexpr OUString aCellStyles(u"CellStyles"_ustr); + if( xFamilies->hasByName( aCellStyles ) ) + { + m_xImpl->m_xCellStyles.set(xFamilies->getByName(aCellStyles), + UNO_QUERY); + } + } + + Reference < XTextFramesSupplier > xTFS( rModel, UNO_QUERY ); + if( xTFS.is() ) + { + m_xImpl->m_xTextFrames.set(xTFS->getTextFrames()); + } + + Reference < XTextGraphicObjectsSupplier > xTGOS( rModel, UNO_QUERY ); + if( xTGOS.is() ) + { + m_xImpl->m_xGraphics.set(xTGOS->getGraphicObjects()); + } + + Reference < XTextEmbeddedObjectsSupplier > xTEOS( rModel, UNO_QUERY ); + if( xTEOS.is() ) + { + m_xImpl->m_xObjects.set(xTEOS->getEmbeddedObjects()); + } + + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::PARA, false ); + m_xImpl->m_xParaImpPrMap = + new XMLTextImportPropertyMapper( pPropMapper, rImport ); + + pPropMapper = new XMLTextPropertySetMapper( TextPropMap::TEXT, false ); + m_xImpl->m_xTextImpPrMap = + new XMLTextImportPropertyMapper( pPropMapper, rImport ); + + pPropMapper = new XMLTextPropertySetMapper( TextPropMap::FRAME, false ); + m_xImpl->m_xFrameImpPrMap = + new XMLTextImportPropertyMapper( pPropMapper, rImport ); + + pPropMapper = new XMLTextPropertySetMapper( TextPropMap::SECTION, false ); + m_xImpl->m_xSectionImpPrMap = + new XMLTextImportPropertyMapper( pPropMapper, rImport ); + + pPropMapper = new XMLTextPropertySetMapper( TextPropMap::RUBY, false ); + m_xImpl->m_xRubyImpPrMap = + new SvXMLImportPropertyMapper( pPropMapper, rImport ); +} + +XMLTextImportHelper::~XMLTextImportHelper() +{ +} + +void XMLTextImportHelper::dispose() +{ + if (m_xImpl->m_xAutoStyles) + m_xImpl->m_xAutoStyles->dispose(); +} + +SvXMLImportPropertyMapper *XMLTextImportHelper::CreateShapeExtPropMapper(SvXMLImport& rImport) +{ + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::FRAME, false ); + return new XMLTextImportPropertyMapper( pPropMapper, rImport ); +} + +SvXMLImportPropertyMapper *XMLTextImportHelper::CreateParaExtPropMapper(SvXMLImport& rImport) +{ + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::SHAPE_PARA, false ); + return new XMLTextImportPropertyMapper( pPropMapper, rImport ); +} + +SvXMLImportPropertyMapper *XMLTextImportHelper::CreateParaDefaultExtPropMapper(SvXMLImport& rImport) +{ + XMLPropertySetMapper* pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::SHAPE_PARA, false ); + SvXMLImportPropertyMapper* pImportMapper = new XMLTextImportPropertyMapper( pPropMapper, rImport ); + + pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::TEXT_ADDITIONAL_DEFAULTS, false ); + pImportMapper->ChainImportMapper( new XMLTextImportPropertyMapper( pPropMapper, rImport ) ); + + return pImportMapper; +} + +SvXMLImportPropertyMapper* + XMLTextImportHelper::CreateTableDefaultExtPropMapper( + SvXMLImport& rImport ) +{ + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::TABLE_DEFAULTS, false ); + return new SvXMLImportPropertyMapper( pPropMapper, rImport ); +} + +SvXMLImportPropertyMapper* + XMLTextImportHelper::CreateTableRowDefaultExtPropMapper( + SvXMLImport& rImport ) +{ + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::TABLE_ROW_DEFAULTS, false ); + return new SvXMLImportPropertyMapper( pPropMapper, rImport ); +} + +SvXMLImportPropertyMapper* + XMLTextImportHelper::CreateTableCellExtPropMapper( + SvXMLImport& rImport ) +{ + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::CELL, false ); + return new XMLTextImportPropertyMapper( pPropMapper, rImport ); +} + +SvXMLImportPropertyMapper* +XMLTextImportHelper::CreateDrawingPageExtPropMapper(SvXMLImport& rImport) +{ + rtl::Reference<XMLPropertyHandlerFactory> const pFactory(new XMLPageMasterPropHdlFactory); + XMLPropertySetMapper *const pPropMapper( + new XMLPropertySetMapper(g_XMLPageMasterDrawingPageStyleMap, pFactory, false)); + return new SvXMLImportPropertyMapper(pPropMapper, rImport); +} + +void XMLTextImportHelper::SetCursor( const Reference < XTextCursor > & rCursor ) +{ + m_xImpl->m_xCursor.set(rCursor); + m_xImpl->m_xText.set(rCursor->getText()); + m_xImpl->m_xCursorAsRange = rCursor; +} + +void XMLTextImportHelper::ResetCursor() +{ + m_xImpl->m_xCursor.clear(); + m_xImpl->m_xText.clear(); + m_xImpl->m_xCursorAsRange.clear(); +} + + +bool XMLTextImportHelper::HasFrameByName( const OUString& rName ) const +{ + return (m_xImpl->m_xTextFrames.is() && + m_xImpl->m_xTextFrames->hasByName(rName)) + || (m_xImpl->m_xGraphics.is() && + m_xImpl->m_xGraphics->hasByName(rName)) + || (m_xImpl->m_xObjects.is() && + m_xImpl->m_xObjects->hasByName(rName)); +} + +bool XMLTextImportHelper::IsDuplicateFrame(const OUString& sName, sal_Int32 nX, sal_Int32 nY, sal_Int32 nWidth, sal_Int32 nHeight) const +{ + if (HasFrameByName(sName)) + { + uno::Reference<beans::XPropertySet> xOtherFrame; + if(m_xImpl->m_xTextFrames.is() && m_xImpl->m_xTextFrames->hasByName(sName)) + xOtherFrame.set(m_xImpl->m_xTextFrames->getByName(sName), uno::UNO_QUERY); + else if(m_xImpl->m_xGraphics.is() && m_xImpl->m_xGraphics->hasByName(sName)) + xOtherFrame.set(m_xImpl->m_xGraphics->getByName(sName), uno::UNO_QUERY); + else if (m_xImpl->m_xObjects.is() && m_xImpl->m_xObjects->hasByName(sName)) + xOtherFrame.set(m_xImpl->m_xObjects->getByName(sName), uno::UNO_QUERY); + + Reference< XPropertySetInfo > xPropSetInfo = xOtherFrame->getPropertySetInfo(); + if(xPropSetInfo->hasPropertyByName("Width")) + { + sal_Int32 nOtherWidth = 0; + xOtherFrame->getPropertyValue("Width") >>= nOtherWidth; + if(nWidth != nOtherWidth) + return false; + } + + if (xPropSetInfo->hasPropertyByName("Height")) + { + sal_Int32 nOtherHeight = 0; + xOtherFrame->getPropertyValue("Height") >>= nOtherHeight; + if (nHeight != nOtherHeight) + return false; + } + + if (xPropSetInfo->hasPropertyByName("HoriOrientPosition")) + { + sal_Int32 nOtherX = 0; + xOtherFrame->getPropertyValue("HoriOrientPosition") >>= nOtherX; + if (nX != nOtherX) + return false; + } + + if (xPropSetInfo->hasPropertyByName("VertOrientPosition")) + { + sal_Int32 nOtherY = 0; + xOtherFrame->getPropertyValue("VertOrientPosition") >>= nOtherY; + if (nY != nOtherY) + return false; + } + + // In some case, position is not defined for frames, so check whether the two frames follow each other (are anchored to the same position) + return m_xImpl->msLastImportedFrameName == sName; + } + return false; +} + +void XMLTextImportHelper::StoreLastImportedFrameName(const OUString& rName) +{ + m_xImpl->msLastImportedFrameName = rName; +} + +void XMLTextImportHelper::ClearLastImportedTextFrameName() +{ + m_xImpl->msLastImportedFrameName.clear(); +} + +void XMLTextImportHelper::InsertString( const OUString& rChars ) +{ + assert(m_xImpl->m_xText.is()); + assert(m_xImpl->m_xCursorAsRange.is()); + if (m_xImpl->m_xText.is()) + { + m_xImpl->m_xText->insertString(m_xImpl->m_xCursorAsRange, + rChars, false); + } +} + +void XMLTextImportHelper::InsertString( std::u16string_view rChars, + bool& rIgnoreLeadingSpace ) +{ + assert(m_xImpl->m_xText.is()); + assert(m_xImpl->m_xCursorAsRange.is()); + if (!m_xImpl->m_xText.is()) + return; + + sal_Int32 nLen = rChars.size(); + OUStringBuffer sChars( nLen ); + + for( sal_Int32 i=0; i < nLen; i++ ) + { + sal_Unicode c = rChars[i]; + switch( c ) + { + case 0x20: + case 0x09: + case 0x0a: + case 0x0d: + if( !rIgnoreLeadingSpace ) + sChars.append( u' ' ); + rIgnoreLeadingSpace = true; + break; + default: + rIgnoreLeadingSpace = false; + sChars.append( c ); + break; + } + } + m_xImpl->m_xText->insertString(m_xImpl->m_xCursorAsRange, + sChars.makeStringAndClear(), false); +} + +void XMLTextImportHelper::InsertControlCharacter( sal_Int16 nControl ) +{ + assert(m_xImpl->m_xText.is()); + assert(m_xImpl->m_xCursorAsRange.is()); + if (m_xImpl->m_xText.is()) + { + m_xImpl->m_xText->insertControlCharacter( + m_xImpl->m_xCursorAsRange, nControl, false); + } +} + +void XMLTextImportHelper::InsertTextContent( + Reference < XTextContent > const & xContent ) +{ + assert(m_xImpl->m_xText.is()); + assert(m_xImpl->m_xCursorAsRange.is()); + if (m_xImpl->m_xText.is()) + { + // note: this may throw IllegalArgumentException and callers handle it + m_xImpl->m_xText->insertTextContent( m_xImpl->m_xCursorAsRange, xContent, false); + } +} + +void XMLTextImportHelper::DeleteParagraph() +{ + assert(m_xImpl->m_xText.is()); + assert(m_xImpl->m_xCursor.is()); + assert(m_xImpl->m_xCursorAsRange.is()); + + bool bDelete = true; + Reference < XEnumerationAccess > const xEnumAccess( + m_xImpl->m_xCursor, UNO_QUERY); + if( xEnumAccess.is() ) + { + Reference < XEnumeration > xEnum(xEnumAccess->createEnumeration()); + SAL_WARN_IF(!xEnum->hasMoreElements(), "xmloff.text", + "empty text enumeration"); + if( xEnum->hasMoreElements() ) + { + Reference < XComponent > xComp( xEnum->nextElement(), UNO_QUERY ); + assert(xComp.is()); + if( xComp.is() ) + { + xComp->dispose(); + bDelete = false; + } + } + } + if( bDelete ) + { + if (m_xImpl->m_xCursor->goLeft( 1, true )) + { + m_xImpl->m_xText->insertString(m_xImpl->m_xCursorAsRange, + "", true); + } + } +} + +OUString XMLTextImportHelper::ConvertStarFonts( const OUString& rChars, + const OUString& rStyleName, + sal_uInt8& rFlags, + bool bPara, + SvXMLImport& rImport ) const +{ + OUStringBuffer sChars( rChars ); + bool bConverted = false; + for( sal_Int32 j=0; j<rChars.getLength(); j++ ) + { + sal_Unicode c = rChars[j]; + if( c >= 0xf000 && c <= 0xf0ff ) + { + if( (rFlags & CONV_STAR_FONT_FLAGS_VALID) == 0 ) + { + XMLTextStyleContext *pStyle = nullptr; + XmlStyleFamily nFamily = bPara ? XmlStyleFamily::TEXT_PARAGRAPH + : XmlStyleFamily::TEXT_TEXT; + if (!rStyleName.isEmpty() && m_xImpl->m_xAutoStyles.is()) + { + const SvXMLStyleContext* pTempStyle = + m_xImpl->m_xAutoStyles-> + FindStyleChildContext( nFamily, rStyleName, + true ); + pStyle = const_cast<XMLTextStyleContext*>( dynamic_cast< const XMLTextStyleContext* >(pTempStyle)); + } + + if( pStyle ) + { + sal_Int32 nCount = pStyle->GetProperties_().size(); + if( nCount ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + m_xImpl->m_xAutoStyles->GetImportPropertyMapper(nFamily); + if( xImpPrMap.is() ) + { + rtl::Reference<XMLPropertySetMapper> rPropMapper = + xImpPrMap->getPropertySetMapper(); + for( sal_Int32 i=0; i < nCount; i++ ) + { + const XMLPropertyState& rProp = pStyle->GetProperties_()[i]; + sal_Int32 nIdx = rProp.mnIndex; + sal_uInt32 nContextId = rPropMapper->GetEntryContextId(nIdx); + if( CTF_FONTFAMILYNAME == nContextId ) + { + rFlags &= ~(CONV_FROM_STAR_BATS|CONV_FROM_STAR_MATH); + OUString sFontName; + rProp.maValue >>= sFontName; + if( sFontName.equalsIgnoreAsciiCase( "StarBats" ) ) + rFlags |= CONV_FROM_STAR_BATS; + else if( sFontName.equalsIgnoreAsciiCase( "StarMath" ) ) + rFlags |= CONV_FROM_STAR_MATH; + break; + } + } + } + } + + } + + rFlags |= CONV_STAR_FONT_FLAGS_VALID; + } + if( (rFlags & CONV_FROM_STAR_BATS ) != 0 ) + { + sChars[j] = rImport.ConvStarBatsCharToStarSymbol( c ); + bConverted = true; + } + else if( (rFlags & CONV_FROM_STAR_MATH ) != 0 ) + { + sChars[j] = rImport.ConvStarMathCharToStarSymbol( c ); + bConverted = true; + } + } + } + + return bConverted ? sChars.makeStringAndClear() : rChars; +} + +/* Helper method to determine, if a paragraph style has a list style (inclusive + an empty one) inherits a list style (inclusive an empty one) from one of its parents (#i69629#) +*/ +/* Apply special case, that found list style equals the chapter numbering, also + to the found list styles of the parent styles. (#i73973#) +*/ +static bool lcl_HasListStyle( const OUString& sStyleName, + const Reference < XNameContainer >& xParaStyles, + SvXMLImport const & rImport, + const OUString& sNumberingStyleName, + std::u16string_view sOutlineStyleName ) +{ + bool bRet( false ); + + if ( !xParaStyles->hasByName( sStyleName ) ) + { + // error case + return true; + } + + Reference< XPropertyState > xPropState( xParaStyles->getByName( sStyleName ), + UNO_QUERY ); + if ( !xPropState.is() ) + { + // error case + return false; + } + + if ( xPropState->getPropertyState( sNumberingStyleName ) == PropertyState_DIRECT_VALUE ) + { + // list style found + bRet = true; + // special case: the set list style equals the chapter numbering + Reference< XPropertySet > xPropSet( xPropState, UNO_QUERY ); + if ( xPropSet.is() ) + { + OUString sListStyle; + xPropSet->getPropertyValue( sNumberingStyleName ) >>= sListStyle; + if ( !sListStyle.isEmpty() && + sListStyle == sOutlineStyleName ) + { + bRet = false; + } + } + } + else + { + // Tools.Outline settings lost on Save (#i77708#) + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + // Don't use UPD for versioning: xmloff/source/text/txtstyli.cxx and txtimp.cxx (#i86058#) + const bool bBuildIdFound = rImport.getBuildIds( nUPD, nBuild ); + // search list style at parent + Reference<XStyle> xStyle( xPropState, UNO_QUERY ); + while ( xStyle.is() ) + { + OUString aParentStyle( xStyle->getParentStyle() ); + if ( !aParentStyle.isEmpty() ) + { + aParentStyle = + rImport.GetStyleDisplayName( XmlStyleFamily::TEXT_PARAGRAPH, + aParentStyle ); + } + if ( aParentStyle.isEmpty() || !xParaStyles->hasByName( aParentStyle ) ) + { + // no list style found + break; + } + else + { + xPropState.set( xParaStyles->getByName( aParentStyle ), + UNO_QUERY ); + if ( !xPropState.is() ) + { + // error case + return true; + } + if ( xPropState->getPropertyState( sNumberingStyleName ) == PropertyState_DIRECT_VALUE ) + { + // list style found + bRet = true; + // Special case: the found list style equals the chapter numbering (#i73973#) + Reference< XPropertySet > xPropSet( xPropState, UNO_QUERY ); + if ( xPropSet.is() ) + { + OUString sListStyle; + xPropSet->getPropertyValue( sNumberingStyleName ) >>= sListStyle; + if ( !sListStyle.isEmpty() && + sListStyle == sOutlineStyleName ) + { + bRet = false; + } + // Special handling for text documents from OOo version prior OOo 2.4 (#i77708#) + /* Check explicitly on certain versions and on import of + text documents in OpenOffice.org file format (#i86058#) + */ + else if ( sListStyle.isEmpty() && + ( rImport.IsTextDocInOOoFileFormat() || + ( bBuildIdFound && + ( ( nUPD == 641 ) || ( nUPD == 645 ) || // prior OOo 2.0 + ( nUPD == 680 && nBuild <= 9238 ) ) ) ) ) // OOo 2.0 - OOo 2.3.1 + { + bRet = false; + } + } + break; + } + else + { + // search list style at parent + Reference<XStyle> xParentStyle(xPropState, UNO_QUERY); + if (xStyle == xParentStyle) + { + // error case + return true; + } + xStyle = xParentStyle; + } + } + } + } + + return bRet; +} + +namespace { + +auto IsPropertySet(uno::Reference<container::XNameContainer> const& rxParaStyles, + uno::Reference<beans::XPropertySet> const& rxPropSet, + OUString const& rProperty) +{ + uno::Reference<beans::XPropertyState> const xPropState(rxPropSet, uno::UNO_QUERY); + // note: this is true only if it is set in automatic style + if (xPropState->getPropertyState(rProperty) == beans::PropertyState_DIRECT_VALUE) + { + return true; + } + // check if it is set by any parent common style + OUString style; + rxPropSet->getPropertyValue("ParaStyleName") >>= style; + while (!style.isEmpty() && rxParaStyles.is() && rxParaStyles->hasByName(style)) + { + uno::Reference<style::XStyle> const xStyle(rxParaStyles->getByName(style), uno::UNO_QUERY); + assert(xStyle.is()); + uno::Reference<beans::XPropertyState> const xStyleProps(xStyle, uno::UNO_QUERY); + if (xStyleProps->getPropertyState(rProperty) == beans::PropertyState_DIRECT_VALUE) + { + return true; + } + style = xStyle->getParentStyle(); + } + return false; +}; + +} // namespace + +OUString XMLTextImportHelper::SetStyleAndAttrs( + SvXMLImport & rImport, + const Reference < XTextCursor >& rCursor, + const OUString& rStyleName, + bool bPara, + bool bOutlineLevelAttrFound, + sal_Int8 nOutlineLevel, + // Numberings/Bullets in table not visible after save/reload (#i80724#) + bool bSetListAttrs, + bool bOutlineContentVisible) +{ + static constexpr OUString s_NumberingRules = u"NumberingRules"_ustr; + static constexpr OUString s_NumberingIsNumber = u"NumberingIsNumber"_ustr; + static constexpr OUString s_NumberingLevel = u"NumberingLevel"_ustr; + static constexpr OUString s_ParaIsNumberingRestart = u"ParaIsNumberingRestart"_ustr; + static constexpr OUString s_NumberingStartValue = u"NumberingStartValue"_ustr; + static constexpr OUString s_PropNameListId = u"ListId"_ustr; + static constexpr OUString s_PageDescName = u"PageDescName"_ustr; + static constexpr OUString s_OutlineLevel = u"OutlineLevel"_ustr; + + const XmlStyleFamily nFamily = bPara ? XmlStyleFamily::TEXT_PARAGRAPH + : XmlStyleFamily::TEXT_TEXT; + XMLTextStyleContext *pStyle = nullptr; + OUString sStyleName( rStyleName ); + if (!sStyleName.isEmpty() && m_xImpl->m_xAutoStyles.is()) + { + const SvXMLStyleContext* pTempStyle = + m_xImpl->m_xAutoStyles->FindStyleChildContext( nFamily, sStyleName, true ); + pStyle = const_cast<XMLTextStyleContext*>(dynamic_cast< const XMLTextStyleContext* >(pTempStyle)); + } + if( pStyle ) + sStyleName = pStyle->GetParentName(); + + Reference < XPropertySet > xPropSet( rCursor, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo( + xPropSet->getPropertySetInfo()); + + // style + if( !sStyleName.isEmpty() ) + { + sStyleName = rImport.GetStyleDisplayName( nFamily, sStyleName ); + const OUString rPropName = bPara ? OUString("ParaStyleName") : OUString("CharStyleName"); + const Reference < XNameContainer > & rStyles = bPara + ? m_xImpl->m_xParaStyles + : m_xImpl->m_xTextStyles; + if( rStyles.is() && + xPropSetInfo->hasPropertyByName( rPropName ) && + rStyles->hasByName( sStyleName ) ) + { + xPropSet->setPropertyValue( rPropName, Any(sStyleName) ); + } + else + sStyleName.clear(); + } + + /* The outline level needs to be only applied as list level, if the heading + is not inside a list and if it by default applies the outline style. (#i70748#) + */ + bool bApplyOutlineLevelAsListLevel( false ); + // Numberings/Bullets in table not visible after save/reload (#i80724#) + if (bSetListAttrs && bPara + && xPropSetInfo->hasPropertyByName( s_NumberingRules)) + { + // Set numbering rules + Reference< XIndexReplace > const xNumRules( + xPropSet->getPropertyValue(s_NumberingRules), UNO_QUERY); + + XMLTextListBlockContext * pListBlock(nullptr); + XMLTextListItemContext * pListItem(nullptr); + XMLNumberedParaContext * pNumberedParagraph(nullptr); + GetTextListHelper().ListContextTop( + pListBlock, pListItem, pNumberedParagraph); + + assert(!(pListBlock && pNumberedParagraph) && "XMLTextImportHelper::" + "SetStyleAndAttrs: both list and numbered-paragraph???"); + + Reference < XIndexReplace > xNewNumRules; + sal_Int8 nLevel(-1); + OUString sListId; + sal_Int16 nStartValue(-1); + bool bNumberingIsNumber(true); + // Assure that list style of automatic paragraph style is applied at paragraph. (#i101349#) + bool bApplyNumRules(pStyle && pStyle->IsListStyleSet()); + bool bApplyNumRulesFix(false); + + if (pListBlock) { + // the xNumRules is always created, even without a list-style-name + if (!bApplyNumRules + && (pListBlock->HasListStyleName() + || (pListItem != nullptr && pListItem->HasNumRulesOverride()))) + { + bApplyNumRules = true; // tdf#114287 + bApplyNumRulesFix = rImport.isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_76); + } + + if (!pListItem) { + bNumberingIsNumber = false; // list-header + } + + // consider text:style-override property of <text:list-item> + xNewNumRules.set( + (pListItem != nullptr && pListItem->HasNumRulesOverride()) + ? pListItem->GetNumRulesOverride() + : pListBlock->GetNumRules() ); + nLevel = static_cast<sal_Int8>(pListBlock->GetLevel()); + + if ( pListItem && pListItem->HasStartValue() ) { + nStartValue = pListItem->GetStartValue(); + } + + // Inconsistent behavior regarding lists (#i92811#) + sListId = m_xImpl->m_xTextListsHelper->GetListIdForListBlock( + *pListBlock); + } + else if (pNumberedParagraph) + { + xNewNumRules.set(pNumberedParagraph->GetNumRules()); + nLevel = static_cast<sal_Int8>(pNumberedParagraph->GetLevel()); + sListId = pNumberedParagraph->GetListId(); + nStartValue = pNumberedParagraph->GetStartValue(); + } + + + if (pListBlock || pNumberedParagraph) + { + if (!bApplyNumRules || bApplyNumRulesFix) + { + bool bSameNumRules = xNewNumRules == xNumRules; + if( !bSameNumRules && xNewNumRules.is() && xNumRules.is() ) + { + // If the interface pointers are different, then this does + // not mean that the num rules are different. Further tests + // are required then. However, if only one num rule is + // set, no tests are required of course. + Reference< XNamed > xNewNamed( xNewNumRules, UNO_QUERY ); + Reference< XNamed > xNamed( xNumRules, UNO_QUERY ); + if( xNewNamed.is() && xNamed.is() ) + { + bSameNumRules = xNewNamed->getName() == xNamed->getName(); + } + else + { + Reference< XAnyCompare > xNumRuleCompare( xNumRules, UNO_QUERY ); + if( xNumRuleCompare.is() ) + { + bSameNumRules = (xNumRuleCompare->compare( Any(xNumRules), Any(xNewNumRules) ) == 0); + } + } + } + if (!bApplyNumRules) + { + bApplyNumRules = !bSameNumRules; + } + if (!bSameNumRules) + { + bApplyNumRulesFix = false; + } + } + + if ( bApplyNumRules ) + { + // #102607# This may except when xNewNumRules contains + // a Writer-NumRule-Implementation bug gets applied to + // a shape. Since this may occur inside a document + // (e.g. when edited), this must be handled + // gracefully. + try + { + xPropSet->setPropertyValue( + s_NumberingRules, Any(xNewNumRules) ); + if (bApplyNumRulesFix) + { // tdf#156146 override list margins for bug compatibility + if (IsPropertySet(m_xImpl->m_xParaStyles, xPropSet, "ParaLeftMargin")) + { + uno::Any const left(xPropSet->getPropertyValue("ParaLeftMargin")); + xPropSet->setPropertyValue("ParaLeftMargin", left); + } + if (IsPropertySet(m_xImpl->m_xParaStyles, xPropSet, "ParaFirstLineIndent")) + { + uno::Any const first(xPropSet->getPropertyValue("ParaFirstLineIndent")); + xPropSet->setPropertyValue("ParaFirstLineIndent", first); + } + } + } + catch(const Exception&) + { + ; // I would really like to use a warning here, + // but I can't access the XMLErrorHandler from + // here. + } + } + + if (!bNumberingIsNumber && + xPropSetInfo->hasPropertyByName(s_NumberingIsNumber)) + { + xPropSet->setPropertyValue(s_NumberingIsNumber, Any(false)); + } + + xPropSet->setPropertyValue( s_NumberingLevel, Any(nLevel) ); + + if( pListBlock && pListBlock->IsRestartNumbering() ) + { + // TODO: property missing + if (xPropSetInfo->hasPropertyByName(s_ParaIsNumberingRestart)) + { + xPropSet->setPropertyValue(s_ParaIsNumberingRestart, + Any(true) ); + } + pListBlock->ResetRestartNumbering(); + } + + if ( 0 <= nStartValue && + xPropSetInfo->hasPropertyByName(s_NumberingStartValue)) + { + xPropSet->setPropertyValue(s_NumberingStartValue, + Any(nStartValue)); + } + + if (xPropSetInfo->hasPropertyByName(s_PropNameListId)) + { + if (!sListId.isEmpty()) { + xPropSet->setPropertyValue(s_PropNameListId, + Any(sListId) ); + } + } + + GetTextListHelper().SetListItem( nullptr ); + } + else + { + /* If the paragraph is not in a list but its style, remove it from + the list. Do not remove it, if the list of the style is + the chapter numbering rule. + */ + if( xNumRules.is() ) + { + bool bRemove( true ); + // Special handling for document from OOo 2.x (#i70748#) + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + const bool bBuildIdFound = rImport.getBuildIds( nUPD, nBuild ); + if ( ( bBuildIdFound && nUPD == 680 ) || + !pStyle || !pStyle->IsListStyleSet() ) + { + if (m_xImpl->m_xChapterNumbering.is()) + { + Reference< XNamed > xNumNamed( xNumRules, UNO_QUERY ); + Reference< XNamed > const xChapterNumNamed ( + m_xImpl->m_xChapterNumbering, UNO_QUERY); + if ( xNumNamed.is() && xChapterNumNamed.is() && + xNumNamed->getName() == xChapterNumNamed->getName() ) + { + bRemove = false; + // RFE: inserting headings into text documents (#i70748#) + bApplyOutlineLevelAsListLevel = true; + } + } + } + else + { + SAL_INFO_IF(!pStyle->GetListStyle().isEmpty(), + "xmloff.text", + "automatic paragraph style with list style name, but paragraph not in list???"); + } + if ( bRemove ) + { + xPropSet->setPropertyValue( s_NumberingRules, Any() ); + } + } + } + } + + // hard paragraph properties + if( pStyle ) + { + pStyle->FillPropertySet( xPropSet ); + if( bPara && pStyle->HasMasterPageName() && + xPropSetInfo->hasPropertyByName(s_PageDescName)) + { + OUString sDisplayName( + rImport.GetStyleDisplayName( + XmlStyleFamily::MASTER_PAGE, + pStyle->GetMasterPageName()) ); + if( sDisplayName.isEmpty() || + (m_xImpl->m_xPageStyles.is() && + m_xImpl->m_xPageStyles->hasByName( sDisplayName))) + { + xPropSet->setPropertyValue(s_PageDescName, + Any(sDisplayName)); + } + } + if( bPara && !pStyle->GetDropCapStyleName().isEmpty() && + m_xImpl->m_xTextStyles.is()) + { + OUString sDisplayName( + rImport.GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, + pStyle->GetDropCapStyleName()) ); + if (m_xImpl->m_xTextStyles->hasByName(sDisplayName) && + xPropSetInfo->hasPropertyByName("DropCapCharStyleName")) + { + xPropSet->setPropertyValue("DropCapCharStyleName", Any(sDisplayName)); + } + } + + // combined characters special treatment + if (!bPara && pStyle->HasCombinedCharactersLetter()) + { + // insert combined characters text field + if (m_xImpl->m_xServiceFactory.is()) + { + uno::Reference<beans::XPropertySet> const xTmp( + m_xImpl->m_xServiceFactory->createInstance( + "com.sun.star.text.TextField.CombinedCharacters"), UNO_QUERY); + if( xTmp.is() ) + { + // fix cursor if larger than possible for + // combined characters field + if (rCursor->getString().getLength() > + MAX_COMBINED_CHARACTERS) + { + rCursor->gotoRange(rCursor->getStart(), false); + rCursor->goRight(MAX_COMBINED_CHARACTERS, true); + } + + // set field value (the combined character string) + xTmp->setPropertyValue("Content", + Any(rCursor->getString())); + + // insert the field over it's original text + Reference<XTextContent> xTextContent(xTmp, UNO_QUERY); + if (m_xImpl->m_xText.is() && rCursor.is()) + { + // #i107225# the combined characters need to be inserted first + // the selected text has to be removed afterwards + m_xImpl->m_xText->insertTextContent( rCursor->getStart(), xTextContent, true ); + + if( !rCursor->getString().isEmpty() ) + { + try + { + uno::Reference< text::XTextCursor > xCrsr = rCursor->getText()->createTextCursorByRange( rCursor->getStart() ); + xCrsr->goLeft( 1, true ); + uno::Reference< beans::XPropertySet> xCrsrProperties( xCrsr, uno::UNO_QUERY_THROW ); + //the hard properties of the removed text need to be applied to the combined characters field + pStyle->FillPropertySet( xCrsrProperties ); + xCrsr->collapseToEnd(); + xCrsr->gotoRange( rCursor->getEnd(), true ); + xCrsr->setString( OUString() ); + } + catch(const uno::Exception&) + { + } + } + } + } + } + } + } + + // outline level; set after list style has been set + // Complete re-worked and corrected: (#i53198#) + // - set outline level at paragraph + // - set numbering level at paragraph, if none is already set + // - assure that style is marked as an outline style for the corresponding + // outline level. + // - DO NOT set type of numbering rule to outline. + // - DO NOT set numbering rule directly at the paragraph. + + // Some minor rework and adjust access to paragraph styles (#i70748#) + if ( bPara ) + { + // Headings not numbered anymore in 3.1 (#i103817#) + sal_Int16 nCurrentOutlineLevelInheritedFromParagraphStyle = 0; + const bool bHasOutlineLevelProp( + xPropSetInfo->hasPropertyByName(s_OutlineLevel)); + if ( bHasOutlineLevelProp ) + { + xPropSet->getPropertyValue(s_OutlineLevel) + >>= nCurrentOutlineLevelInheritedFromParagraphStyle; + } + if ( nOutlineLevel > 0 ) + { + if ( bHasOutlineLevelProp ) + { + // In case that the value equals the value of its paragraph style + // attribute outline level, the paragraph attribute value is left unset + if ( nCurrentOutlineLevelInheritedFromParagraphStyle != nOutlineLevel ) + { + xPropSet->setPropertyValue( s_OutlineLevel, + Any( static_cast<sal_Int16>(nOutlineLevel) ) ); + } + } + if (!bOutlineContentVisible) + { + uno::Sequence<beans::PropertyValue> aGrabBag; + xPropSet->getPropertyValue("ParaInteropGrabBag") >>= aGrabBag; + sal_Int32 length = aGrabBag.getLength(); + aGrabBag.realloc(length + 1); + auto pGrabBag = aGrabBag.getArray(); + pGrabBag[length].Name = "OutlineContentVisibleAttr"; + pGrabBag[length].Value <<= bool(bOutlineContentVisible); + xPropSet->setPropertyValue("ParaInteropGrabBag", uno::Any(aGrabBag)); + } + // RFE: inserting headings into text documents (#i70748#) + if ( bApplyOutlineLevelAsListLevel ) + { + sal_Int16 nNumLevel = -1; + xPropSet->getPropertyValue( s_NumberingLevel ) >>= nNumLevel; + if ( nNumLevel == -1 || + nNumLevel != (nOutlineLevel - 1) ) + { + xPropSet->setPropertyValue( s_NumberingLevel, + Any( static_cast<sal_Int8>(nOutlineLevel - 1) ) ); + } + } + /* Correction: (#i69629#) + - for text document from version OOo 2.0.4/SO 8 PU4 and earlier + the paragraph style of a heading should be assigned to the + corresponding list level of the outline style. + - for other text documents the paragraph style of a heading is only + a candidate for an assignment to the list level of the outline + style, if it has no direct list style property and (if exists) the + automatic paragraph style has also no direct list style set. + */ + if (m_xImpl->m_xParaStyles.is() && m_xImpl->m_xParaStyles->hasByName(sStyleName)) + { + bool bOutlineStyleCandidate( false ); + + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + const bool bBuildIdFound = rImport.getBuildIds( nUPD, nBuild ); + // Lost outline numbering in master document (#i73509#) + // Check explicitly on certain versions (#i86058#) + if ( rImport.IsTextDocInOOoFileFormat() || + ( bBuildIdFound && + ( nUPD == 645 || nUPD == 641 ) ) ) + { + bOutlineStyleCandidate = true; + } + else if ( nUPD == 680 && nBuild <= 9073 ) /* BuildId of OOo 2.0.4/SO8 PU4 */ + { + bOutlineStyleCandidate = bOutlineLevelAttrFound; + } + if ( bOutlineStyleCandidate ) + { + AddOutlineStyleCandidate( nOutlineLevel, sStyleName ); + } + // Assure that heading applies the outline style (#i103817#) + if ( ( !pStyle || !pStyle->IsListStyleSet() ) && + !bOutlineStyleCandidate && + m_xImpl->m_xChapterNumbering.is()) + { + if ( !lcl_HasListStyle( sStyleName, + m_xImpl->m_xParaStyles, GetXMLImport(), + u"NumberingStyleName"_ustr, + u"" ) ) + { + // heading not in a list --> apply outline style + xPropSet->setPropertyValue( s_NumberingRules, + Any(m_xImpl->m_xChapterNumbering) ); + xPropSet->setPropertyValue( s_NumberingLevel, + Any(static_cast<sal_Int8>(nOutlineLevel - 1))); + } + } + } + } + //handle for text:p,if the paragraphstyle outlinelevel is set to[1~10] + else if( bHasOutlineLevelProp ) + { + if ( nCurrentOutlineLevelInheritedFromParagraphStyle != 0 ) + { + xPropSet->setPropertyValue(s_OutlineLevel, + Any( sal_Int16(0) )); + } + } + } + + return sStyleName; +} + +void XMLTextImportHelper::FindOutlineStyleName( OUString& rStyleName, + sal_Int8 nOutlineLevel ) +{ + // style name empty? + if( !rStyleName.isEmpty() ) + return; + + // Empty? Then we need o do stuff. Let's do error checking first. + if (m_xImpl->m_xChapterNumbering.is() && + ( nOutlineLevel > 0 ) && + (nOutlineLevel <= m_xImpl->m_xChapterNumbering->getCount())) + { + nOutlineLevel--; // for the remainder, the level's are 0-based + + // empty style name: look-up previously used name + + // if we don't have a previously used name, we'll use the default + m_xImpl->InitOutlineStylesCandidates(); + if (m_xImpl->m_xOutlineStylesCandidates[nOutlineLevel].empty()) + { + // no other name used previously? Then use default + + // iterate over property value sequence to find the style name + Sequence<PropertyValue> aProperties; + m_xImpl->m_xChapterNumbering->getByIndex( nOutlineLevel ) + >>= aProperties; + auto pProp = std::find_if(std::cbegin(aProperties), std::cend(aProperties), + [](const PropertyValue& rProp) { return rProp.Name == "HeadingStyleName"; }); + if (pProp != std::cend(aProperties)) + { + OUString aOutlineStyle; + pProp->Value >>= aOutlineStyle; + m_xImpl->m_xOutlineStylesCandidates[nOutlineLevel] + .push_back( aOutlineStyle ); + } + } + + // finally, we'll use the previously used style name for this + // format (or the default we've just put into that style) + // take last added one (#i71249#) + rStyleName = + m_xImpl->m_xOutlineStylesCandidates[nOutlineLevel].back(); + } + // else: nothing we can do, so we'll leave it empty + // else: we already had a style name, so we let it pass. +} + +void XMLTextImportHelper::AddOutlineStyleCandidate( const sal_Int8 nOutlineLevel, + const OUString& rStyleName ) +{ + if (!rStyleName.isEmpty() + && m_xImpl->m_xChapterNumbering.is() + && (nOutlineLevel > 0) + && (nOutlineLevel <= m_xImpl->m_xChapterNumbering->getCount())) + { + m_xImpl->InitOutlineStylesCandidates(); + m_xImpl->m_xOutlineStylesCandidates[nOutlineLevel-1].push_back( + rStyleName); + } +} + +void XMLTextImportHelper::SetOutlineStyles( bool bSetEmptyLevels ) +{ + if (!(m_xImpl->m_xOutlineStylesCandidates != nullptr || bSetEmptyLevels) || + !m_xImpl->m_xChapterNumbering.is() || + IsInsertMode()) + return; + + bool bChooseLastOne( false ); + { + if ( GetXMLImport().IsTextDocInOOoFileFormat() ) + { + bChooseLastOne = true; + } + else + { + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + if ( GetXMLImport().getBuildIds( nUPD, nBuild ) ) + { + // check explicitly on certain versions + bChooseLastOne = ( nUPD == 641 ) || ( nUPD == 645 ) || // prior OOo 2.0 + ( nUPD == 680 && nBuild <= 9073 ); // OOo 2.0 - OOo 2.0.4 + } + } + } + + OUString sOutlineStyleName; + { + Reference<XPropertySet> xChapterNumRule( + m_xImpl->m_xChapterNumbering, UNO_QUERY); + xChapterNumRule->getPropertyValue("Name") >>= sOutlineStyleName; + } + + const sal_Int32 nCount = m_xImpl->m_xChapterNumbering->getCount(); + /* First collect all paragraph styles chosen for assignment to each + list level of the outline style, then perform the intrinsic assignment. + Reason: The assignment of a certain paragraph style to a list level + of the outline style causes side effects on the children + paragraph styles in Writer. (#i106218#) + */ + ::std::vector<OUString> sChosenStyles(nCount); + for( sal_Int32 i=0; i < nCount; ++i ) + { + if ( bSetEmptyLevels || + (m_xImpl->m_xOutlineStylesCandidates && + !m_xImpl->m_xOutlineStylesCandidates[i].empty())) + { + // determine, which candidate is one to be assigned to the list + // level of the outline style + if (m_xImpl->m_xOutlineStylesCandidates && + !m_xImpl->m_xOutlineStylesCandidates[i].empty()) + { + if ( bChooseLastOne ) + { + sChosenStyles[i] = + m_xImpl->m_xOutlineStylesCandidates[i].back(); + } + else + { + for (size_t j = 0; + j < m_xImpl->m_xOutlineStylesCandidates[i].size(); + ++j) + { + if (!lcl_HasListStyle( + m_xImpl->m_xOutlineStylesCandidates[i][j], + m_xImpl->m_xParaStyles, + GetXMLImport(), + "NumberingStyleName", + sOutlineStyleName)) + { + sChosenStyles[i] = + m_xImpl->m_xOutlineStylesCandidates[i][j]; + break; + } + } + } + } + } + } + // Trashed outline numbering in ODF 1.1 text document created by OOo 3.x (#i106218#) + Sequence < PropertyValue > aProps( 1 ); + PropertyValue *pProps = aProps.getArray(); + pProps->Name = "HeadingStyleName"; + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + // Paragraph style assignments in Outline of template lost from second level on (#i107610#) + if ( bSetEmptyLevels || !sChosenStyles[i].isEmpty() ) + { + pProps->Value <<= sChosenStyles[i]; + m_xImpl->m_xChapterNumbering->replaceByIndex(i, + Any( aProps )); + } + } + +} + +void XMLTextImportHelper::SetHyperlink( + SvXMLImport const & rImport, + const Reference < XTextCursor >& rCursor, + const OUString& rHRef, + const OUString& rName, + const OUString& rTargetFrameName, + const OUString& rStyleName, + const OUString& rVisitedStyleName, + XMLEventsImportContext* pEvents) +{ + static constexpr OUString s_HyperLinkURL = u"HyperLinkURL"_ustr; + static constexpr OUString s_HyperLinkName = u"HyperLinkName"_ustr; + static constexpr OUString s_HyperLinkTarget = u"HyperLinkTarget"_ustr; + static constexpr OUString s_UnvisitedCharStyleName = u"UnvisitedCharStyleName"_ustr; + static constexpr OUString s_VisitedCharStyleName = u"VisitedCharStyleName"_ustr; + static constexpr OUString s_HyperLinkEvents = u"HyperLinkEvents"_ustr; + + Reference < XPropertySet > xPropSet( rCursor, UNO_QUERY ); + Reference < XPropertySetInfo > xPropSetInfo( + xPropSet->getPropertySetInfo()); + if (!xPropSetInfo.is() || !xPropSetInfo->hasPropertyByName(s_HyperLinkURL)) + return; + + xPropSet->setPropertyValue(s_HyperLinkURL, Any(rHRef)); + + if (xPropSetInfo->hasPropertyByName(s_HyperLinkName)) + { + xPropSet->setPropertyValue(s_HyperLinkName, Any(rName)); + } + + if (xPropSetInfo->hasPropertyByName(s_HyperLinkTarget)) + { + xPropSet->setPropertyValue(s_HyperLinkTarget, + Any(rTargetFrameName)); + } + + if ( (pEvents != nullptr) && + xPropSetInfo->hasPropertyByName(s_HyperLinkEvents)) + { + // The API treats events at hyperlinks differently from most + // other properties: You have to set a name replace with the + // events in it. The easiest way to do this is to 1) get + // events, 2) set new ones, and 3) then put events back. + uno::Reference<XNameReplace> const xReplace( + xPropSet->getPropertyValue(s_HyperLinkEvents), UNO_QUERY); + if (xReplace.is()) + { + // set events + pEvents->SetEvents(xReplace); + + // put events + xPropSet->setPropertyValue(s_HyperLinkEvents, Any(xReplace)); + } + } + + if (!m_xImpl->m_xTextStyles.is()) + return; + + OUString sDisplayName( + rImport.GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, rStyleName ) ); + if( !sDisplayName.isEmpty() && + xPropSetInfo->hasPropertyByName(s_UnvisitedCharStyleName) && + m_xImpl->m_xTextStyles->hasByName(sDisplayName)) + { + xPropSet->setPropertyValue(s_UnvisitedCharStyleName, + Any(sDisplayName)); + } + + sDisplayName = + rImport.GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, rVisitedStyleName ); + if( !sDisplayName.isEmpty() && + xPropSetInfo->hasPropertyByName(s_VisitedCharStyleName) && + m_xImpl->m_xTextStyles->hasByName(sDisplayName)) + { + xPropSet->setPropertyValue(s_VisitedCharStyleName, + Any(sDisplayName)); + } +} + +void XMLTextImportHelper::SetRuby( + SvXMLImport const & rImport, + const Reference < XTextCursor >& rCursor, + const OUString& rStyleName, + const OUString& rTextStyleName, + const OUString& rText ) +{ + Reference<XPropertySet> xPropSet(rCursor, UNO_QUERY); + + OUString sRubyText("RubyText"); + + // if we have one Ruby property, we assume all of them are present + if (!xPropSet.is() || + !xPropSet->getPropertySetInfo()->hasPropertyByName( sRubyText )) + return; + + // the ruby text + xPropSet->setPropertyValue(sRubyText, Any(rText)); + + // the ruby style (ruby-adjust) + if (!rStyleName.isEmpty() && m_xImpl->m_xAutoStyles.is()) + { + const SvXMLStyleContext* pTempStyle = + m_xImpl->m_xAutoStyles->FindStyleChildContext( XmlStyleFamily::TEXT_RUBY, + rStyleName, true ); + XMLPropStyleContext *pStyle = const_cast<XMLPropStyleContext*>(dynamic_cast< const XMLPropStyleContext* >(pTempStyle)); + + if (nullptr != pStyle) + pStyle->FillPropertySet( xPropSet ); + } + + // the ruby text character style + if (m_xImpl->m_xTextStyles.is()) + { + OUString sDisplayName( + rImport.GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, rTextStyleName ) ); + if( (!sDisplayName.isEmpty()) && + m_xImpl->m_xTextStyles->hasByName( sDisplayName )) + { + xPropSet->setPropertyValue("RubyCharStyleName", Any(sDisplayName)); + } + } +} + +void XMLTextImportHelper::SetAutoStyles( SvXMLStylesContext *pStyles ) +{ + m_xImpl->m_xAutoStyles = pStyles; +} + +SvXMLImportContext *XMLTextImportHelper::CreateTextChildContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< XFastAttributeList > & xAttrList, + XMLTextType eType ) +{ + SvXMLImportContext *pContext = nullptr; + + bool bContent = true; + switch( nElement ) + { + case XML_ELEMENT(TEXT, XML_H): + case XML_ELEMENT(TEXT, XML_P): + case XML_ELEMENT(LO_EXT, XML_P): + pContext = new XMLParaContext( rImport, + nElement, + xAttrList ); + if (m_xImpl->m_bProgress && XMLTextType::Shape != eType) + { + rImport.GetProgressBarHelper()->Increment(); + } + break; + // #i52127# + case XML_ELEMENT(TEXT, XML_NUMBERED_PARAGRAPH): + pContext = new XMLNumberedParaContext( + rImport, nElement, xAttrList ); + break; + case XML_ELEMENT(TEXT, XML_LIST): + pContext = new XMLTextListBlockContext( rImport, *this, + xAttrList ); + break; + case XML_ELEMENT(TABLE,XML_TABLE): + case XML_ELEMENT(LO_EXT, XML_TABLE): + if( XMLTextType::Body == eType || + XMLTextType::TextBox == eType || + XMLTextType::Section == eType || + XMLTextType::HeaderFooter == eType || + XMLTextType::ChangedRegion == eType || + XMLTextType::Cell == eType ) + pContext = CreateTableChildContext( rImport, nElement, xAttrList ); + break; + case XML_ELEMENT(TEXT, XML_SEQUENCE_DECLS): + if ((XMLTextType::Body == eType && m_xImpl->m_bBodyContentStarted) || + XMLTextType::HeaderFooter == eType ) + { + pContext = new XMLVariableDeclsImportContext( + rImport, *this, VarTypeSequence); + bContent = false; + } + break; + case XML_ELEMENT(TEXT, XML_VARIABLE_DECLS): + if ((XMLTextType::Body == eType && m_xImpl->m_bBodyContentStarted) || + XMLTextType::HeaderFooter == eType ) + { + pContext = new XMLVariableDeclsImportContext( + rImport, *this, VarTypeSimple); + bContent = false; + } + break; + case XML_ELEMENT(TEXT, XML_USER_FIELD_DECLS): + if ((XMLTextType::Body == eType && m_xImpl->m_bBodyContentStarted)|| + XMLTextType::HeaderFooter == eType ) + { + pContext = new XMLVariableDeclsImportContext( + rImport, *this, VarTypeUserField); + bContent = false; + } + break; + case XML_ELEMENT(TEXT, XML_DDE_CONNECTION_DECLS): + if ((XMLTextType::Body == eType && m_xImpl->m_bBodyContentStarted) || + XMLTextType::HeaderFooter == eType ) + { + pContext = new XMLDdeFieldDeclsImportContext(rImport); + bContent = false; + } + break; + case XML_ELEMENT(DRAW, XML_FRAME): + if ((XMLTextType::Body == eType && m_xImpl->m_bBodyContentStarted) || + XMLTextType::TextBox == eType || + XMLTextType::ChangedRegion == eType ) + { + TextContentAnchorType eAnchorType = + XMLTextType::TextBox == eType ? TextContentAnchorType_AT_FRAME + : TextContentAnchorType_AT_PAGE; + pContext = new XMLTextFrameContext( rImport, xAttrList, + eAnchorType ); + bContent = false; + } + break; + case XML_ELEMENT(DRAW, XML_A): + if ((XMLTextType::Body == eType && m_xImpl->m_bBodyContentStarted) || + XMLTextType::TextBox == eType || + XMLTextType::ChangedRegion == eType) + { + TextContentAnchorType eAnchorType = + XMLTextType::TextBox == eType ? TextContentAnchorType_AT_FRAME + : TextContentAnchorType_AT_PAGE; + pContext = new XMLTextFrameHyperlinkContext( rImport, nElement, + xAttrList, + eAnchorType ); + bContent = false; + } + break; + case XML_ELEMENT(TEXT, XML_INDEX_TITLE): + case XML_ELEMENT(TEXT, XML_SECTION): + pContext = new XMLSectionImportContext( rImport ); + break; + case XML_ELEMENT(TEXT, XML_TABLE_OF_CONTENT): + case XML_ELEMENT(TEXT, XML_OBJECT_INDEX): + case XML_ELEMENT(TEXT, XML_TABLE_INDEX): + case XML_ELEMENT(TEXT, XML_ILLUSTRATION_INDEX): + case XML_ELEMENT(TEXT, XML_USER_INDEX): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX): + case XML_ELEMENT(TEXT, XML_BIBLIOGRAPHY): + if( XMLTextType::Shape != eType ) + pContext = new XMLIndexTOCContext( rImport, nElement ); + break; + case XML_ELEMENT(TEXT, XML_TRACKED_CHANGES): + pContext = new XMLTrackedChangesImportContext( rImport ); + bContent = false; + break; + case XML_ELEMENT(TEXT, XML_CHANGE): + case XML_ELEMENT(TEXT, XML_CHANGE_START): + case XML_ELEMENT(TEXT, XML_CHANGE_END): + pContext = new XMLChangeImportContext( + rImport, + ((nElement == XML_ELEMENT(TEXT, XML_CHANGE_END)) + ? XMLChangeImportContext::Element::END + : (nElement == XML_ELEMENT(TEXT, XML_CHANGE_START)) + ? XMLChangeImportContext::Element::START + : XMLChangeImportContext::Element::POINT), + true); + break; + case XML_ELEMENT(OFFICE, XML_FORMS): + pContext = xmloff::OFormLayerXMLImport::createOfficeFormsContext(rImport); + bContent = false; + break; + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_AUTO_MARK_FILE): + if( XMLTextType::Body == eType ) + { + pContext = new XMLAutoMarkFileContext(rImport); + } + bContent = false; + break; + case XML_ELEMENT(TABLE, XML_CALCULATION_SETTINGS): + pContext = new XMLCalculationSettingsContext ( rImport, nElement, xAttrList); + bContent = false; + break; + + default: + if ((XMLTextType::Body == eType && m_xImpl->m_bBodyContentStarted) || + XMLTextType::TextBox == eType || + XMLTextType::ChangedRegion == eType ) + { + Reference < XShapes > xShapes; + pContext = XMLShapeImportHelper::CreateGroupChildContext( + rImport, nElement, xAttrList, xShapes ); + bContent = false; + } + } + + // handle open redlines + if ( (XML_ELEMENT(TEXT, XML_CHANGE) != nElement) && + (XML_ELEMENT(TEXT, XML_CHANGE_END) != nElement) && + (XML_ELEMENT(TEXT, XML_CHANGE_START) != nElement) ) + { +// ResetOpenRedlineId(); + } + + if( XMLTextType::Body == eType && bContent ) + { + m_xImpl->m_bBodyContentStarted = false; + } + + if( nElement != XML_ELEMENT(DRAW, XML_FRAME) ) + ClearLastImportedTextFrameName(); + + if (!pContext) + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return pContext; +} + +SvXMLImportContext *XMLTextImportHelper::CreateTableChildContext( + SvXMLImport&, + sal_Int32 /*nElement*/, + const Reference< XFastAttributeList > & ) +{ + return nullptr; +} + +/// get data style key for use with NumberFormat property +sal_Int32 XMLTextImportHelper::GetDataStyleKey(const OUString& sStyleName, + bool* pIsSystemLanguage ) +{ + if (!m_xImpl->m_xAutoStyles.is()) + return -1; + + const SvXMLStyleContext* pStyle = + m_xImpl->m_xAutoStyles->FindStyleChildContext( XmlStyleFamily::DATA_STYLE, + sStyleName, true ); + + // get appropriate context + + + // first check if it's an Impress and draw only number format + // this is needed since it's also a SvXMLNumFormatContext, + // that was needed to support them for controls in impress/draw also + const SdXMLNumberFormatImportContext* pSdNumStyle = dynamic_cast<const SdXMLNumberFormatImportContext*>( pStyle ); + if( pSdNumStyle ) + { + return pSdNumStyle->GetDrawKey(); + } + else + { + SvXMLNumFormatContext* pNumStyle = const_cast<SvXMLNumFormatContext*>(dynamic_cast<const SvXMLNumFormatContext*>( pStyle ) ); + if( pNumStyle ) + { + if( pIsSystemLanguage != nullptr ) + *pIsSystemLanguage = pNumStyle->IsSystemLanguage(); + + // return key + return pNumStyle->GetKey(); + } + } + return -1; +} + +const SvxXMLListStyleContext *XMLTextImportHelper::FindAutoListStyle( const OUString& rName ) const +{ + const SvxXMLListStyleContext *pStyle = nullptr; + if (m_xImpl->m_xAutoStyles.is()) + { + const SvXMLStyleContext* pTempStyle = + m_xImpl->m_xAutoStyles->FindStyleChildContext( XmlStyleFamily::TEXT_LIST, rName, + true ); + pStyle = dynamic_cast< const SvxXMLListStyleContext* >(pTempStyle); + } + + return pStyle; +} + +XMLPropStyleContext *XMLTextImportHelper::FindAutoFrameStyle( const OUString& rName ) const +{ + XMLPropStyleContext *pStyle = nullptr; + if (m_xImpl->m_xAutoStyles.is()) + { + const SvXMLStyleContext* pTempStyle = + m_xImpl->m_xAutoStyles->FindStyleChildContext( XmlStyleFamily::SD_GRAPHICS_ID, rName, + true ); + pStyle = const_cast<XMLPropStyleContext*>(dynamic_cast< const XMLPropStyleContext* >(pTempStyle)); + } + + return pStyle; +} + +XMLPropStyleContext* XMLTextImportHelper::FindSectionStyle( + const OUString& rName ) const +{ + XMLPropStyleContext* pStyle = nullptr; + if (m_xImpl->m_xAutoStyles.is()) + { + const SvXMLStyleContext* pTempStyle = + m_xImpl->m_xAutoStyles->FindStyleChildContext( + XmlStyleFamily::TEXT_SECTION, + rName, true ); + pStyle = const_cast<XMLPropStyleContext*>(dynamic_cast< const XMLPropStyleContext* >(pTempStyle)); + } + + return pStyle; +} + +XMLPropStyleContext* XMLTextImportHelper::FindPageMaster( + const OUString& rName ) const +{ + XMLPropStyleContext* pStyle = nullptr; + if (m_xImpl->m_xAutoStyles.is()) + { + const SvXMLStyleContext* pTempStyle = + m_xImpl->m_xAutoStyles->FindStyleChildContext( + XmlStyleFamily::PAGE_MASTER, + rName, true ); + pStyle = const_cast<XMLPropStyleContext*>(dynamic_cast< const XMLPropStyleContext* >(pTempStyle)); + } + + return pStyle; +} + +XMLPropStyleContext* XMLTextImportHelper::FindAutoCharStyle(const OUString& rName) const +{ + if (!m_xImpl->m_xAutoStyles) + return nullptr; + auto pStyle + = m_xImpl->m_xAutoStyles->FindStyleChildContext(XmlStyleFamily::TEXT_TEXT, rName, true); + return dynamic_cast<XMLPropStyleContext*>(const_cast<SvXMLStyleContext*>(pStyle)); +} + +XMLPropStyleContext * XMLTextImportHelper::FindDrawingPage(OUString const& rName) const +{ + if (!m_xImpl->m_xAutoStyles.is()) + { + return nullptr; + } + SvXMLStyleContext const* pStyle( + m_xImpl->m_xAutoStyles->FindStyleChildContext( + XmlStyleFamily::SD_DRAWINGPAGE_ID, rName, true)); + assert(pStyle == nullptr || dynamic_cast<XMLPropStyleContext const*>(pStyle) != nullptr); + return const_cast<XMLPropStyleContext*>(static_cast<XMLPropStyleContext const*>(pStyle)); +} + +void XMLTextImportHelper::PushListContext() +{ + GetTextListHelper().PushListContext(static_cast<XMLTextListBlockContext*>(nullptr)); +} + +void XMLTextImportHelper::PopListContext() +{ + GetTextListHelper().PopListContext(); +} + + +SvI18NMap& XMLTextImportHelper::GetRenameMap() +{ + if (!m_xImpl->m_xRenameMap) + { + m_xImpl->m_xRenameMap.reset( new SvI18NMap ); + } + return *m_xImpl->m_xRenameMap; +} + +void XMLTextImportHelper::InsertBookmarkStartRange( + const OUString & sName, + const Reference<XTextRange> & rRange, + OUString const& i_rXmlId, + std::shared_ptr< ::xmloff::ParsedRDFaAttributes > & i_rpRDFaAttributes) +{ + m_xImpl->m_BookmarkStartRanges[sName] = + std::make_tuple(rRange, i_rXmlId, i_rpRDFaAttributes); + m_xImpl->m_BookmarkVector.push_back(sName); +} + +bool XMLTextImportHelper::FindAndRemoveBookmarkStartRange( + const OUString & sName, + Reference<XTextRange> & o_rRange, + OUString & o_rXmlId, + std::shared_ptr< ::xmloff::ParsedRDFaAttributes > & o_rpRDFaAttributes) +{ + if (m_xImpl->m_BookmarkStartRanges.count(sName)) + { + Impl::BookmarkMapEntry_t & rEntry = + (*m_xImpl->m_BookmarkStartRanges.find(sName)).second; + o_rRange.set(std::get<0>(rEntry)); + o_rXmlId = std::get<1>(rEntry); + o_rpRDFaAttributes = std::get<2>(rEntry); + m_xImpl->m_BookmarkStartRanges.erase(sName); + auto it = std::find(m_xImpl->m_BookmarkVector.begin(), m_xImpl->m_BookmarkVector.end(), sName); + if (it!=m_xImpl->m_BookmarkVector.end()) + { + m_xImpl->m_BookmarkVector.erase(it); + } + return true; + } + else + { + return false; + } +} + +void XMLTextImportHelper::pushFieldCtx( const OUString& name, const OUString& type ) +{ + m_xImpl->m_FieldStack.push(Impl::field_stack_item_t( + Impl::field_name_type_t(name, type), Impl::field_params_t(), uno::Reference<text::XFormField>{}, GetCursor()->getStart())); +} + +uno::Reference<text::XFormField> +XMLTextImportHelper::popFieldCtx() +{ + uno::Reference<text::XFormField> xRet; + if ( !m_xImpl->m_FieldStack.empty() ) + { + xRet = std::get<2>(m_xImpl->m_FieldStack.top()); + m_xImpl->m_FieldStack.pop(); + } + else + { + SAL_INFO("xmloff.text", "unexpected fieldmark end"); + } + return xRet; +} + +void XMLTextImportHelper::addFieldParam( const OUString& name, const OUString& value ) +{ + assert(!m_xImpl->m_FieldStack.empty()); + Impl::field_stack_item_t & FieldStackItem(m_xImpl->m_FieldStack.top()); + std::get<1>(FieldStackItem).emplace_back( name, value ); +} + +::std::pair<OUString, OUString> XMLTextImportHelper::getCurrentFieldType() const +{ + assert(!m_xImpl->m_FieldStack.empty()); + return std::get<0>(m_xImpl->m_FieldStack.top()); +} + +uno::Reference<text::XTextRange> XMLTextImportHelper::getCurrentFieldStart() const +{ + assert(!m_xImpl->m_FieldStack.empty()); + return std::get<3>(m_xImpl->m_FieldStack.top()); +} + +bool XMLTextImportHelper::hasCurrentFieldSeparator() const +{ + assert(!m_xImpl->m_FieldStack.empty()); + return std::get<2>(m_xImpl->m_FieldStack.top()).is(); +} + +bool XMLTextImportHelper::hasCurrentFieldCtx() const +{ + return !m_xImpl->m_FieldStack.empty(); +} + +void XMLTextImportHelper::setCurrentFieldParamsTo(css::uno::Reference< css::text::XFormField> const &xFormField) +{ + assert(!m_xImpl->m_FieldStack.empty()); + if (xFormField.is()) + { + FieldParamImporter(&std::get<1>(m_xImpl->m_FieldStack.top()), + xFormField->getParameters()).Import(); + std::get<2>(m_xImpl->m_FieldStack.top()) = xFormField; + } +} + + +void XMLTextImportHelper::ConnectFrameChains( + const OUString& rFrmName, + const OUString& rNextFrmName, + const Reference < XPropertySet >& rFrmPropSet ) +{ + if( rFrmName.isEmpty() ) + return; + + if( !rNextFrmName.isEmpty() ) + { + OUString sNextFrmName(GetRenameMap().Get( XML_TEXT_RENAME_TYPE_FRAME, + rNextFrmName )); + if (m_xImpl->m_xTextFrames.is() + && m_xImpl->m_xTextFrames->hasByName(sNextFrmName)) + { + rFrmPropSet->setPropertyValue("ChainNextName", + Any(sNextFrmName)); + } + else + { + if (!m_xImpl->m_xPrevFrmNames) + { + m_xImpl->m_xPrevFrmNames.emplace(); + m_xImpl->m_xNextFrmNames.emplace(); + } + m_xImpl->m_xPrevFrmNames->push_back(rFrmName); + m_xImpl->m_xNextFrmNames->push_back(sNextFrmName); + } + } + if (!m_xImpl->m_xPrevFrmNames || m_xImpl->m_xPrevFrmNames->empty()) + return; + + for(std::vector<OUString>::iterator i = m_xImpl->m_xPrevFrmNames->begin(), j = m_xImpl->m_xNextFrmNames->begin(); i != m_xImpl->m_xPrevFrmNames->end() && j != m_xImpl->m_xNextFrmNames->end(); ++i, ++j) + { + if((*j) == rFrmName) + { + // The previous frame must exist, because it existing than + // inserting the entry + rFrmPropSet->setPropertyValue("ChainPrevName", Any(*i)); + + i = m_xImpl->m_xPrevFrmNames->erase(i); + j = m_xImpl->m_xNextFrmNames->erase(j); + + // There cannot be more than one previous frames + break; + } + } +} + +bool XMLTextImportHelper::IsInFrame() const +{ + static constexpr OUString s_TextFrame = u"TextFrame"_ustr; + + bool bIsInFrame = false; + + // are we currently in a text frame? yes, if the cursor has a + // TextFrame property and it's non-NULL + Reference<XPropertySet> xPropSet(const_cast<XMLTextImportHelper*>(this)->GetCursor(), UNO_QUERY); + if (xPropSet.is()) + { + if (xPropSet->getPropertySetInfo()->hasPropertyByName(s_TextFrame)) + { + uno::Reference<XTextFrame> const xFrame( + xPropSet->getPropertyValue(s_TextFrame), UNO_QUERY); + + if (xFrame.is()) + { + bIsInFrame = true; + } + } + } + + return bIsInFrame; +} + +bool XMLTextImportHelper::IsInHeaderFooter() const +{ + return false; +} + +Reference< XPropertySet> XMLTextImportHelper::createAndInsertOLEObject( + SvXMLImport&, + const OUString& /*rHRef*/, + const OUString& /*rStyleName*/, + const OUString& /*rTblName*/, + sal_Int32 /*nWidth*/, sal_Int32 /*nHeight*/ ) +{ + Reference< XPropertySet> xPropSet; + return xPropSet; +} + +Reference< XPropertySet> XMLTextImportHelper::createAndInsertOOoLink( + SvXMLImport&, + const OUString& /*rHRef*/, + const OUString& /*rStyleName*/, + const OUString& /*rTblName*/, + sal_Int32 /*nWidth*/, sal_Int32 /*nHeight*/ ) +{ + Reference< XPropertySet> xPropSet; + return xPropSet; +} + +Reference< XPropertySet> XMLTextImportHelper::createAndInsertApplet( + const OUString& /*rCode*/, + const OUString& /*rName*/, + bool /*bMayScript*/, + const OUString& /*rHRef*/, + sal_Int32 /*nWidth*/, sal_Int32 /*nHeight*/ ) +{ + Reference< XPropertySet> xPropSet; + return xPropSet; +} +Reference< XPropertySet> XMLTextImportHelper::createAndInsertPlugin( + const OUString& /*rMimeType*/, + const OUString& /*rHRef*/, + sal_Int32 /*nWidth*/, sal_Int32 /*nHeight*/ ) +{ + Reference< XPropertySet> xPropSet; + return xPropSet; +} +Reference< XPropertySet> XMLTextImportHelper::createAndInsertFloatingFrame( + const OUString& /*rName*/, + const OUString& /*rHRef*/, + const OUString& /*rStyleName*/, + sal_Int32 /*nWidth*/, sal_Int32 /*nHeight*/ ) +{ + Reference< XPropertySet> xPropSet; + return xPropSet; +} + +void XMLTextImportHelper::endAppletOrPlugin( + const Reference < XPropertySet> &, + std::map < const OUString, OUString > &) +{ +} +// redline helper: dummy implementation to be overridden in sw/filter/xml +void XMLTextImportHelper::RedlineAdd( const OUString& /*rType*/, + const OUString& /*rId*/, + const OUString& /*rAuthor*/, + const OUString& /*rComment*/, + const util::DateTime& /*rDateTime*/, + const OUString& /*rMovedID*/, + bool /*bMergeLastPara*/) +{ + // dummy implementation: do nothing +} + +Reference<XTextCursor> XMLTextImportHelper::RedlineCreateText( + Reference<XTextCursor> & /*rOldCursor*/, + const OUString& /*rId*/) +{ + // dummy implementation: do nothing + Reference<XTextCursor> xRet; + return xRet; +} + +void XMLTextImportHelper::RedlineSetCursor( + const OUString& /*rId*/, + bool /*bStart*/, + bool /*bIsOutsideOfParagraph*/) +{ + // dummy implementation: do nothing +} + +void XMLTextImportHelper::RedlineAdjustStartNodeCursor() +{ + // dummy implementation: do nothing +} + +void XMLTextImportHelper::SetShowChanges( bool ) +{ + // dummy implementation: do nothing +} + +void XMLTextImportHelper::SetRecordChanges( bool ) +{ + // dummy implementation: do nothing +} +void XMLTextImportHelper::SetChangesProtectionKey(const Sequence<sal_Int8> &) +{ + // dummy implementation: do nothing +} + + +OUString const & XMLTextImportHelper::GetOpenRedlineId() const +{ + return m_xImpl->m_sOpenRedlineIdentifier; +} + +void XMLTextImportHelper::SetOpenRedlineId( OUString const & rId) +{ + m_xImpl->m_sOpenRedlineIdentifier = rId; +} + +void XMLTextImportHelper::ResetOpenRedlineId() +{ + SetOpenRedlineId(""); +} + +void +XMLTextImportHelper::SetCellParaStyleDefault(OUString const& rNewValue) +{ + m_xImpl->m_sCellParaStyleDefault = rNewValue; +} + +OUString const& XMLTextImportHelper::GetCellParaStyleDefault() const +{ + return m_xImpl->m_sCellParaStyleDefault; +} + +void XMLTextImportHelper::AddCrossRefHeadingMapping(OUString const& rFrom, OUString const& rTo) +{ + if (!m_xImpl->m_xCrossRefHeadingBookmarkMap) + { + m_xImpl->m_xCrossRefHeadingBookmarkMap.emplace(); + } + m_xImpl->m_xCrossRefHeadingBookmarkMap->insert(std::make_pair(rFrom, rTo)); +} + +// tdf#94804: hack to map cross reference fields that reference duplicate marks +// note that we can't really check meta:generator for this since the file might +// be round-tripped by different versions preserving duplicates => always map +void XMLTextImportHelper::MapCrossRefHeadingFieldsHorribly() +{ + if (!m_xImpl->m_xCrossRefHeadingBookmarkMap) + { + return; + } + + uno::Reference<text::XTextFieldsSupplier> const xFieldsSupplier( + m_xImpl->m_rSvXMLImport.GetModel(), uno::UNO_QUERY); + if (!xFieldsSupplier.is()) + { + return; + } + uno::Reference<container::XEnumerationAccess> const xFieldsEA( + xFieldsSupplier->getTextFields()); + uno::Reference<container::XEnumeration> const xFields( + xFieldsEA->createEnumeration()); + while (xFields->hasMoreElements()) + { + uno::Reference<lang::XServiceInfo> const xFieldInfo( + xFields->nextElement(), uno::UNO_QUERY); + if (!xFieldInfo->supportsService("com.sun.star.text.textfield.GetReference")) + { + continue; + } + uno::Reference<beans::XPropertySet> const xField( + xFieldInfo, uno::UNO_QUERY); + sal_uInt16 nType(0); + xField->getPropertyValue("ReferenceFieldSource") >>= nType; + if (text::ReferenceFieldSource::BOOKMARK != nType) + { + continue; + } + OUString name; + xField->getPropertyValue("SourceName") >>= name; + auto const iter(m_xImpl->m_xCrossRefHeadingBookmarkMap->find(name)); + if (iter == m_xImpl->m_xCrossRefHeadingBookmarkMap->end()) + { + continue; + } + xField->setPropertyValue("SourceName", uno::Any(iter->second)); + } +} + +void XMLTextImportHelper::setBookmarkAttributes(OUString const& bookmark, bool hidden, OUString const& condition) +{ + m_xImpl->m_bBookmarkHidden[bookmark] = hidden; + m_xImpl->m_sBookmarkCondition[bookmark] = condition; +} + +bool XMLTextImportHelper::getBookmarkHidden(OUString const& bookmark) const +{ + return m_xImpl->m_bBookmarkHidden[bookmark]; +} + +const OUString& XMLTextImportHelper::getBookmarkCondition(OUString const& bookmark) const +{ + return m_xImpl->m_sBookmarkCondition[bookmark]; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtimppr.cxx b/xmloff/source/text/txtimppr.cxx new file mode 100644 index 0000000000..e1da4578a1 --- /dev/null +++ b/xmloff/source/text/txtimppr.cxx @@ -0,0 +1,848 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <memory> +#include <sal/config.h> + +#include <o3tl/any.hxx> +#include <osl/thread.h> +#include <com/sun/star/awt/FontFamily.hpp> +#include <com/sun/star/awt/FontPitch.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/table/BorderLine2.hpp> +#include <com/sun/star/text/VertOrientation.hpp> +#include <com/sun/star/text/SizeType.hpp> +#include <xmloff/XMLFontStylesContext.hxx> +#include <xmloff/txtprmap.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/txtimppr.hxx> +#include <xmloff/maptype.hxx> + +#define XML_LINE_LEFT 0 +#define XML_LINE_RIGHT 1 +#define XML_LINE_TOP 2 +#define XML_LINE_BOTTOM 3 + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::text; + +bool XMLTextImportPropertyMapper::handleSpecialItem( + XMLPropertyState& rProperty, + ::std::vector< XMLPropertyState >& rProperties, + const OUString& rValue, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap ) const +{ + bool bRet = false; + sal_Int32 nIndex = rProperty.mnIndex; + switch( getPropertySetMapper()->GetEntryContextId( nIndex ) ) + { + case CTF_FONTNAME: + case CTF_FONTNAME_CJK: + case CTF_FONTNAME_CTL: + if( GetImport().GetFontDecls() != nullptr ) + { + assert(( + ( CTF_FONTFAMILYNAME == + getPropertySetMapper()->GetEntryContextId(nIndex+1) && + CTF_FONTSTYLENAME == + getPropertySetMapper()->GetEntryContextId(nIndex+2) && + CTF_FONTFAMILY == + getPropertySetMapper()->GetEntryContextId(nIndex+3) && + CTF_FONTPITCH == + getPropertySetMapper()->GetEntryContextId(nIndex+4) && + CTF_FONTCHARSET == + getPropertySetMapper()->GetEntryContextId(nIndex+5) ) || + ( CTF_FONTFAMILYNAME_CJK == + getPropertySetMapper()->GetEntryContextId(nIndex+1) && + CTF_FONTSTYLENAME_CJK == + getPropertySetMapper()->GetEntryContextId(nIndex+2) && + CTF_FONTFAMILY_CJK == + getPropertySetMapper()->GetEntryContextId(nIndex+3) && + CTF_FONTPITCH_CJK == + getPropertySetMapper()->GetEntryContextId(nIndex+4) && + CTF_FONTCHARSET_CJK == + getPropertySetMapper()->GetEntryContextId(nIndex+5) ) || + ( CTF_FONTFAMILYNAME_CTL == + getPropertySetMapper()->GetEntryContextId(nIndex+1) && + CTF_FONTSTYLENAME_CTL == + getPropertySetMapper()->GetEntryContextId(nIndex+2) && + CTF_FONTFAMILY_CTL == + getPropertySetMapper()->GetEntryContextId(nIndex+3) && + CTF_FONTPITCH_CTL == + getPropertySetMapper()->GetEntryContextId(nIndex+4) && + CTF_FONTCHARSET_CTL == + getPropertySetMapper()->GetEntryContextId(nIndex+5) ) + ) && "illegal property map" ); + + GetImport().GetFontDecls()->FillProperties( + rValue, rProperties, + rProperty.mnIndex+1, rProperty.mnIndex+2, + rProperty.mnIndex+3, rProperty.mnIndex+4, + rProperty.mnIndex+5 ); + bRet = false; // the property hasn't been filled + } + break; + + // If we want to do StarMath/StarSymbol font conversion, then we'll + // want these special items to be treated just like regular ones... + // For the Writer, we'll catch and convert them in _FillPropertySet; + // the other apps probably don't care. For the other apps, we just + // imitate the default non-special-item mechanism. + case CTF_FONTFAMILYNAME: + case CTF_FONTFAMILYNAME_CJK: + case CTF_FONTFAMILYNAME_CTL: + bRet = getPropertySetMapper()->importXML( rValue, rProperty, + rUnitConverter ); + break; + + case CTF_TEXT_DISPLAY: + bRet = getPropertySetMapper()->importXML( rValue, rProperty, + rUnitConverter ); + if( SvXMLImport::OOo_2x == GetImport().getGeneratorVersion() ) + { + bool bHidden = false; + rProperty.maValue >>= bHidden; + bHidden = !bHidden; + rProperty.maValue <<= bHidden; + } + break; + default: + bRet = SvXMLImportPropertyMapper::handleSpecialItem( rProperty, + rProperties, rValue, rUnitConverter, rNamespaceMap ); + break; + } + + return bRet; +} + +XMLTextImportPropertyMapper::XMLTextImportPropertyMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLImport& rImp ) : + SvXMLImportPropertyMapper( rMapper, rImp ), + m_nSizeTypeIndex( -2 ), + m_nWidthTypeIndex( -2 ) +{ +} + +XMLTextImportPropertyMapper::~XMLTextImportPropertyMapper() +{ +} + +void XMLTextImportPropertyMapper::FontFinished( + XMLPropertyState *pFontFamilyNameState, + XMLPropertyState *pFontStyleNameState, + XMLPropertyState *pFontFamilyState, + XMLPropertyState *pFontPitchState, + XMLPropertyState *pFontCharsetState ) +{ + if( pFontFamilyNameState && pFontFamilyNameState->mnIndex != -1 ) + { + OUString sName; + pFontFamilyNameState->maValue >>= sName; + if( sName.isEmpty() ) + pFontFamilyNameState->mnIndex = -1; + } + if( !pFontFamilyNameState || pFontFamilyNameState->mnIndex == -1 ) + { + if( pFontStyleNameState ) + pFontStyleNameState->mnIndex = -1; + if( pFontFamilyState ) + pFontFamilyState->mnIndex = -1; + if( pFontPitchState ) + pFontPitchState->mnIndex = -1; + if( pFontCharsetState ) + pFontCharsetState->mnIndex = -1; + } +} + +/** since the properties "CharFontFamilyName", "CharFontStyleName", "CharFontFamily", + "CharFontPitch" and "CharFontSet" and their CJK and CTL counterparts are only + usable as a union, we add defaults to all values that are not set as long as we + have an "CharFontFamilyName" + + #99928# CL */ +void XMLTextImportPropertyMapper::FontDefaultsCheck( + XMLPropertyState const * pFontFamilyName, + XMLPropertyState const * pFontStyleName, + XMLPropertyState const * pFontFamily, + XMLPropertyState const * pFontPitch, + XMLPropertyState const * pFontCharSet, + std::optional<XMLPropertyState>* ppNewFontStyleName, + std::optional<XMLPropertyState>* ppNewFontFamily, + std::optional<XMLPropertyState>* ppNewFontPitch, + std::optional<XMLPropertyState>* ppNewFontCharSet ) const +{ + if( pFontFamilyName ) + { + Any aAny; + + if( !pFontStyleName ) + { + aAny <<= OUString(); + #if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + sal_Int16 nTmp = getPropertySetMapper()->GetEntryContextId( + pFontFamilyName->mnIndex + 1 ); + assert(nTmp == CTF_FONTSTYLENAME || nTmp == CTF_FONTSTYLENAME_CJK || nTmp == CTF_FONTSTYLENAME_CTL); + #endif + ppNewFontStyleName->emplace( pFontFamilyName->mnIndex + 1, aAny ); + } + + if( !pFontFamily ) + { + aAny <<= sal_Int16(css::awt::FontFamily::DONTKNOW); + + #if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + sal_Int16 nTmp = getPropertySetMapper()->GetEntryContextId( + pFontFamilyName->mnIndex + 2 ); + assert(nTmp == CTF_FONTFAMILY || nTmp == CTF_FONTFAMILY_CJK || nTmp == CTF_FONTFAMILY_CTL); + #endif + ppNewFontFamily->emplace( pFontFamilyName->mnIndex + 2, aAny ); + } + + if( !pFontPitch ) + { + aAny <<= sal_Int16(css::awt::FontPitch::DONTKNOW); + #if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + sal_Int16 nTmp = getPropertySetMapper()->GetEntryContextId( + pFontFamilyName->mnIndex + 3 ); + assert(nTmp == CTF_FONTPITCH || nTmp == CTF_FONTPITCH_CJK || nTmp == CTF_FONTPITCH_CTL); + #endif + ppNewFontPitch->emplace( pFontFamilyName->mnIndex + 3, aAny ); + } + + if( !pFontCharSet ) + { + aAny <<= static_cast<sal_Int16>(osl_getThreadTextEncoding()); + #if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + sal_Int16 nTmp = getPropertySetMapper()->GetEntryContextId( + pFontFamilyName->mnIndex + 4 ); + assert(nTmp == CTF_FONTCHARSET || nTmp == CTF_FONTCHARSET_CJK || nTmp == CTF_FONTCHARSET_CTL); + #endif + ppNewFontCharSet->emplace( pFontFamilyName->mnIndex + 4, aAny ); + } + } + + (void) this; // avoid loplugin:staticmethods +} + +namespace { +//fdo#58730 The [UL|LR]Space class has a deficiency where "100%" also serves as +//a flag that the value is an absolute value so we can't truly handle an +//up/lower space property which wants to specify its 200% upper but 100% lower +//of its parent (try typing 100% vs 200% into the edit style dialog and revisit +//your style). So on xml load that ends up meaning 200%, 0 lower. This is a +//crock. + +//On import clear 100% all-margins relative sizes. +bool +isNotDefaultRelSize(const XMLPropertyState* pRelState, const rtl::Reference<XMLPropertySetMapper>& rPrMap) +{ + if (rPrMap->GetEntryContextId(pRelState->mnIndex) == CTF_PARAMARGINALL_REL) + { + sal_Int32 nTemp = 0; + pRelState->maValue >>= nTemp; + return nTemp != 100; + } + return true; +} + +/** + * Separate compressed border attributes. + * During export, border attributes are compressed if there are equal to all four side. + * Since Writer hasn't the same compressed attributes, but has distinct ones for all + * four side, we have to duplicate the compressed attribute during import. +**/ +void lcl_SeparateBorder( + sal_uInt16 nIndex, XMLPropertyState const * pAllBorderDistance, + XMLPropertyState* pBorderDistances[4], XMLPropertyState* pNewBorderDistances[4], + XMLPropertyState const * pAllBorder, XMLPropertyState* pBorders[4], + XMLPropertyState* pNewBorders[4], XMLPropertyState* pAllBorderWidth, + XMLPropertyState* pBorderWidths[4] +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + , const rtl::Reference< XMLPropertySetMapper >& rMapper +#endif +) +{ + if( pAllBorderDistance && !pBorderDistances[nIndex] ) + { +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + sal_Int16 nTmp = rMapper->GetEntryContextId( + pAllBorderDistance->mnIndex + nIndex + 1 ); + if (CTF_CHARALLBORDERDISTANCE == + rMapper->GetEntryContextId(pAllBorderDistance->mnIndex)) + { + assert(nTmp >= CTF_CHARLEFTBORDERDISTANCE && + nTmp <= CTF_CHARBOTTOMBORDERDISTANCE); + } + else + { + assert(nTmp >= CTF_LEFTBORDERDISTANCE && + nTmp <= CTF_BOTTOMBORDERDISTANCE); + } +#endif + pNewBorderDistances[nIndex] = + new XMLPropertyState( pAllBorderDistance->mnIndex + nIndex + 1, + pAllBorderDistance->maValue ); + pBorderDistances[nIndex] = pNewBorderDistances[nIndex]; + } + if( pAllBorder && !pBorders[nIndex] ) + { +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + sal_Int16 nTmp = rMapper->GetEntryContextId( + pAllBorder->mnIndex + nIndex + 1 ); + if (CTF_CHARALLBORDER == + rMapper->GetEntryContextId(pAllBorder->mnIndex)) + { + assert(nTmp >= CTF_CHARLEFTBORDER && nTmp <= CTF_CHARBOTTOMBORDER); + } + else + { + assert(nTmp >= CTF_LEFTBORDER && nTmp <= CTF_BOTTOMBORDER); + } +#endif + pNewBorders[nIndex] = new XMLPropertyState( pAllBorder->mnIndex + nIndex + 1, + pAllBorder->maValue ); + pBorders[nIndex] = pNewBorders[nIndex]; + } + if( !pBorderWidths[nIndex] ) + pBorderWidths[nIndex] = pAllBorderWidth; + else + pBorderWidths[nIndex]->mnIndex = -1; + + if( !(pBorders[nIndex] && pBorderWidths[nIndex]) ) + return; + + table::BorderLine2 aBorderLine; + pBorders[nIndex]->maValue >>= aBorderLine; + + table::BorderLine2 aBorderLineWidth; + pBorderWidths[nIndex]->maValue >>= aBorderLineWidth; + + aBorderLine.OuterLineWidth = aBorderLineWidth.OuterLineWidth; + aBorderLine.InnerLineWidth = aBorderLineWidth.InnerLineWidth; + aBorderLine.LineDistance = aBorderLineWidth.LineDistance; + aBorderLine.LineWidth = aBorderLineWidth.LineWidth; + + pBorders[nIndex]->maValue <<= aBorderLine; +} + +} + +void XMLTextImportPropertyMapper::finished( + ::std::vector< XMLPropertyState >& rProperties, + sal_Int32 /*nStartIndex*/, sal_Int32 /*nEndIndex*/ ) const +{ + bool bHasAnyHeight = false; + bool bHasAnyMinHeight = false; + bool bHasAnyWidth = false; + bool bHasAnyMinWidth = false; + + XMLPropertyState* pFontFamilyName = nullptr; + XMLPropertyState* pFontStyleName = nullptr; + XMLPropertyState* pFontFamily = nullptr; + XMLPropertyState* pFontPitch = nullptr; + XMLPropertyState* pFontCharSet = nullptr; + std::optional<XMLPropertyState> pNewFontStyleName; + std::optional<XMLPropertyState> pNewFontFamily; + std::optional<XMLPropertyState> pNewFontPitch; + std::optional<XMLPropertyState> pNewFontCharSet; + XMLPropertyState* pFontFamilyNameCJK = nullptr; + XMLPropertyState* pFontStyleNameCJK = nullptr; + XMLPropertyState* pFontFamilyCJK = nullptr; + XMLPropertyState* pFontPitchCJK = nullptr; + XMLPropertyState* pFontCharSetCJK = nullptr; + std::optional<XMLPropertyState> pNewFontStyleNameCJK; + std::optional<XMLPropertyState> pNewFontFamilyCJK; + std::optional<XMLPropertyState> pNewFontPitchCJK; + std::optional<XMLPropertyState> pNewFontCharSetCJK; + XMLPropertyState* pFontFamilyNameCTL = nullptr; + XMLPropertyState* pFontStyleNameCTL = nullptr; + XMLPropertyState* pFontFamilyCTL = nullptr; + XMLPropertyState* pFontPitchCTL = nullptr; + XMLPropertyState* pFontCharSetCTL = nullptr; + std::optional<XMLPropertyState> pNewFontStyleNameCTL; + std::optional<XMLPropertyState> pNewFontFamilyCTL; + std::optional<XMLPropertyState> pNewFontPitchCTL; + std::optional<XMLPropertyState> pNewFontCharSetCTL; + XMLPropertyState* pAllBorderDistance = nullptr; + XMLPropertyState* pBorderDistances[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pNewBorderDistances[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllBorder = nullptr; + XMLPropertyState* pBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pNewBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllBorderWidth = nullptr; + XMLPropertyState* pBorderWidths[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pCharAllBorderDistance = nullptr; + XMLPropertyState* pCharBorderDistances[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pCharNewBorderDistances[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pCharAllBorder = nullptr; + XMLPropertyState* pCharBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pCharNewBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pCharAllBorderWidth = nullptr; + XMLPropertyState* pCharBorderWidths[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pVertOrient = nullptr; + XMLPropertyState* pVertOrientRelAsChar = nullptr; + XMLPropertyState* pBackTransparency = nullptr; // transparency in % + XMLPropertyState* pBackTransparent = nullptr; // transparency as boolean + XMLPropertyState* pAllParaMargin = nullptr; + XMLPropertyState* pParaMargins[4] = { nullptr, nullptr, nullptr, nullptr }; + ::std::optional<XMLPropertyState> pNewParaMargins[4]; + XMLPropertyState* pAllMargin = nullptr; + XMLPropertyState* pMargins[4] = { nullptr, nullptr, nullptr, nullptr }; + ::std::optional<XMLPropertyState> pNewMargins[4]; + XMLPropertyState* pFillStyle(nullptr); + XMLPropertyState* pFillColor(nullptr); + + for( auto& rProperty : rProperties ) + { + XMLPropertyState* property = &rProperty; + if( -1 == property->mnIndex ) + continue; + + switch( getPropertySetMapper()->GetEntryContextId( property->mnIndex ) ) + { + case CTF_FONTFAMILYNAME: pFontFamilyName = property; break; + case CTF_FONTSTYLENAME: pFontStyleName = property; break; + case CTF_FONTFAMILY: pFontFamily = property; break; + case CTF_FONTPITCH: pFontPitch = property; break; + case CTF_FONTCHARSET: pFontCharSet = property; break; + + case CTF_FONTFAMILYNAME_CJK: pFontFamilyNameCJK = property; break; + case CTF_FONTSTYLENAME_CJK: pFontStyleNameCJK = property; break; + case CTF_FONTFAMILY_CJK: pFontFamilyCJK = property; break; + case CTF_FONTPITCH_CJK: pFontPitchCJK = property; break; + case CTF_FONTCHARSET_CJK: pFontCharSetCJK = property; break; + + case CTF_FONTFAMILYNAME_CTL: pFontFamilyNameCTL = property; break; + case CTF_FONTSTYLENAME_CTL: pFontStyleNameCTL = property; break; + case CTF_FONTFAMILY_CTL: pFontFamilyCTL = property; break; + case CTF_FONTPITCH_CTL: pFontPitchCTL = property; break; + case CTF_FONTCHARSET_CTL: pFontCharSetCTL = property; break; + + case CTF_ALLBORDERDISTANCE: pAllBorderDistance = property; break; + case CTF_LEFTBORDERDISTANCE: pBorderDistances[XML_LINE_LEFT] = property; break; + case CTF_RIGHTBORDERDISTANCE: pBorderDistances[XML_LINE_RIGHT] = property; break; + case CTF_TOPBORDERDISTANCE: pBorderDistances[XML_LINE_TOP] = property; break; + case CTF_BOTTOMBORDERDISTANCE: pBorderDistances[XML_LINE_BOTTOM] = property; break; + case CTF_ALLBORDER: pAllBorder = property; break; + case CTF_LEFTBORDER: pBorders[XML_LINE_LEFT] = property; break; + case CTF_RIGHTBORDER: pBorders[XML_LINE_RIGHT] = property; break; + case CTF_TOPBORDER: pBorders[XML_LINE_TOP] = property; break; + case CTF_BOTTOMBORDER: pBorders[XML_LINE_BOTTOM] = property; break; + case CTF_ALLBORDERWIDTH: pAllBorderWidth = property; break; + case CTF_LEFTBORDERWIDTH: pBorderWidths[XML_LINE_LEFT] = property; break; + case CTF_RIGHTBORDERWIDTH: pBorderWidths[XML_LINE_RIGHT] = property; break; + case CTF_TOPBORDERWIDTH: pBorderWidths[XML_LINE_TOP] = property; break; + case CTF_BOTTOMBORDERWIDTH: pBorderWidths[XML_LINE_BOTTOM] = property; break; + + case CTF_CHARALLBORDERDISTANCE: pCharAllBorderDistance = property; break; + case CTF_CHARLEFTBORDERDISTANCE: pCharBorderDistances[XML_LINE_LEFT] = property; break; + case CTF_CHARRIGHTBORDERDISTANCE: pCharBorderDistances[XML_LINE_RIGHT] = property; break; + case CTF_CHARTOPBORDERDISTANCE: pCharBorderDistances[XML_LINE_TOP] = property; break; + case CTF_CHARBOTTOMBORDERDISTANCE: pCharBorderDistances[XML_LINE_BOTTOM] = property; break; + case CTF_CHARALLBORDER: pCharAllBorder = property; break; + case CTF_CHARLEFTBORDER: pCharBorders[XML_LINE_LEFT] = property; break; + case CTF_CHARRIGHTBORDER: pCharBorders[XML_LINE_RIGHT] = property; break; + case CTF_CHARTOPBORDER: pCharBorders[XML_LINE_TOP] = property; break; + case CTF_CHARBOTTOMBORDER: pCharBorders[XML_LINE_BOTTOM] = property; break; + case CTF_CHARALLBORDERWIDTH: pCharAllBorderWidth = property; break; + case CTF_CHARLEFTBORDERWIDTH: pCharBorderWidths[XML_LINE_LEFT] = property; break; + case CTF_CHARRIGHTBORDERWIDTH: pCharBorderWidths[XML_LINE_RIGHT] = property; break; + case CTF_CHARTOPBORDERWIDTH: pCharBorderWidths[XML_LINE_TOP] = property; break; + case CTF_CHARBOTTOMBORDERWIDTH: pCharBorderWidths[XML_LINE_BOTTOM] = property; break; + + case CTF_ANCHORTYPE: break; + case CTF_VERTICALPOS: pVertOrient = property; break; + case CTF_VERTICALREL_ASCHAR: pVertOrientRelAsChar = property; break; + + case CTF_FRAMEHEIGHT_MIN_ABS: + case CTF_FRAMEHEIGHT_MIN_REL: +// case CTF_SYNCHEIGHT_MIN: + bHasAnyMinHeight = true; + [[fallthrough]]; + case CTF_FRAMEHEIGHT_ABS: + case CTF_FRAMEHEIGHT_REL: +// case CTF_SYNCHEIGHT: + bHasAnyHeight = true; break; + case CTF_FRAMEWIDTH_MIN_ABS: + case CTF_FRAMEWIDTH_MIN_REL: + bHasAnyMinWidth = true; + [[fallthrough]]; + case CTF_FRAMEWIDTH_ABS: + case CTF_FRAMEWIDTH_REL: + bHasAnyWidth = true; break; + case CTF_BACKGROUND_TRANSPARENCY: pBackTransparency = property; break; + case CTF_BACKGROUND_TRANSPARENT: pBackTransparent = property; break; + case CTF_FILLSTYLE: pFillStyle = property; break; + case CTF_FILLCOLOR: pFillColor = property; break; + case CTF_PARAMARGINALL: + case CTF_PARAMARGINALL_REL: + pAllParaMargin = property; break; + case CTF_PARALEFTMARGIN: + case CTF_PARALEFTMARGIN_REL: + pParaMargins[XML_LINE_LEFT] = property; break; + case CTF_PARARIGHTMARGIN: + case CTF_PARARIGHTMARGIN_REL: + pParaMargins[XML_LINE_RIGHT] = property; break; + case CTF_PARATOPMARGIN: + case CTF_PARATOPMARGIN_REL: + pParaMargins[XML_LINE_TOP] = property; break; + case CTF_PARABOTTOMMARGIN: + case CTF_PARABOTTOMMARGIN_REL: + pParaMargins[XML_LINE_BOTTOM] = property; break; + case CTF_MARGINALL: + pAllMargin = property; break; + case CTF_MARGINLEFT: + pMargins[XML_LINE_LEFT] = property; break; + case CTF_MARGINRIGHT: + pMargins[XML_LINE_RIGHT] = property; break; + case CTF_MARGINTOP: + pMargins[XML_LINE_TOP] = property; break; + case CTF_MARGINBOTTOM: + pMargins[XML_LINE_BOTTOM] = property; break; + } + } + + if( pFontFamilyName || pFontStyleName || pFontFamily || + pFontPitch || pFontCharSet ) + FontFinished( pFontFamilyName, pFontStyleName, pFontFamily, + pFontPitch, pFontCharSet ); + if( pFontFamilyNameCJK || pFontStyleNameCJK || pFontFamilyCJK || + pFontPitchCJK || pFontCharSetCJK ) + FontFinished( pFontFamilyNameCJK, pFontStyleNameCJK, pFontFamilyCJK, + pFontPitchCJK, pFontCharSetCJK ); + if( pFontFamilyNameCTL || pFontStyleNameCTL || pFontFamilyCTL || + pFontPitchCTL || pFontCharSetCTL ) + FontFinished( pFontFamilyNameCTL, pFontStyleNameCTL, pFontFamilyCTL, + pFontPitchCTL, pFontCharSetCTL ); + + for (sal_uInt16 i = 0; i < 4; i++) + { + if (pAllParaMargin && !pParaMargins[i] + && isNotDefaultRelSize(pAllParaMargin, getPropertySetMapper())) + { +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + sal_Int16 nTmp = getPropertySetMapper()->GetEntryContextId( + pAllParaMargin->mnIndex + (2*i) + 2 ); + assert(nTmp >= CTF_PARALEFTMARGIN && + nTmp <= CTF_PARABOTTOMMARGIN_REL); +#endif + pNewParaMargins[i].emplace( + pAllParaMargin->mnIndex + (2*i) + 2, pAllParaMargin->maValue); + } + if (pAllMargin && !pMargins[i]) + { +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + sal_Int16 nTmp = getPropertySetMapper()->GetEntryContextId( + pAllMargin->mnIndex + i + 1 ); + assert(nTmp >= CTF_MARGINLEFT && nTmp <= CTF_MARGINBOTTOM); +#endif + pNewMargins[i].emplace( + pAllMargin->mnIndex + i + 1, pAllMargin->maValue); + } + + lcl_SeparateBorder( + i, pAllBorderDistance, pBorderDistances, pNewBorderDistances, + pAllBorder, pBorders, pNewBorders, + pAllBorderWidth, pBorderWidths +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + , getPropertySetMapper() +#endif + ); + + lcl_SeparateBorder( + i, pCharAllBorderDistance, pCharBorderDistances, + pCharNewBorderDistances, pCharAllBorder, pCharBorders, + pCharNewBorders, pCharAllBorderWidth, pCharBorderWidths +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + , getPropertySetMapper() +#endif + ); + } + + if (pAllParaMargin) + { + pAllParaMargin->mnIndex = -1; + } + if (pAllMargin) + { + pAllMargin->mnIndex = -1; + } + + if( pAllBorderDistance ) + pAllBorderDistance->mnIndex = -1; + + if( pAllBorder ) + pAllBorder->mnIndex = -1; + + if( pAllBorderWidth ) + pAllBorderWidth->mnIndex = -1; + + if( pCharAllBorderDistance ) + pCharAllBorderDistance->mnIndex = -1; + + if( pCharAllBorder ) + pCharAllBorder->mnIndex = -1; + + if( pCharAllBorderWidth ) + pCharAllBorderWidth->mnIndex = -1; + + if( pVertOrient && pVertOrientRelAsChar ) + { + sal_Int16 nVertOrient; + pVertOrient->maValue >>= nVertOrient; + sal_Int16 nVertOrientRel = 0; + pVertOrientRelAsChar->maValue >>= nVertOrientRel; + switch( nVertOrient ) + { + case VertOrientation::TOP: + nVertOrient = nVertOrientRel; + break; + case VertOrientation::CENTER: + switch( nVertOrientRel ) + { + case VertOrientation::CHAR_TOP: + nVertOrient = VertOrientation::CHAR_CENTER; + break; + case VertOrientation::LINE_TOP: + nVertOrient = VertOrientation::LINE_CENTER; + break; + } + break; + case VertOrientation::BOTTOM: + switch( nVertOrientRel ) + { + case VertOrientation::CHAR_TOP: + nVertOrient = VertOrientation::CHAR_BOTTOM; + break; + case VertOrientation::LINE_TOP: + nVertOrient = VertOrientation::LINE_BOTTOM; + break; + } + break; + } + pVertOrient->maValue <<= nVertOrient; + pVertOrientRelAsChar->mnIndex = -1; + } + + FontDefaultsCheck( pFontFamilyName, + pFontStyleName, pFontFamily, pFontPitch, pFontCharSet, + &pNewFontStyleName, &pNewFontFamily, &pNewFontPitch, &pNewFontCharSet ); + + FontDefaultsCheck( pFontFamilyNameCJK, + pFontStyleNameCJK, pFontFamilyCJK, pFontPitchCJK, pFontCharSetCJK, + &pNewFontStyleNameCJK, &pNewFontFamilyCJK, &pNewFontPitchCJK, &pNewFontCharSetCJK ); + + FontDefaultsCheck( pFontFamilyNameCTL, + pFontStyleNameCTL, pFontFamilyCTL, pFontPitchCTL, pFontCharSetCTL, + &pNewFontStyleNameCTL, &pNewFontFamilyCTL, &pNewFontPitchCTL, &pNewFontCharSetCTL ); + + if (pFillStyle && !pFillColor && pBackTransparent + && drawing::FillStyle_SOLID == pFillStyle->maValue.get<drawing::FillStyle>() + && pBackTransparent->maValue.get<bool>()) + { + // fo:background="transparent", draw:fill="solid" without draw:fill-color + // prevent getSvxBrushItemFromSourceSet from adding bogus default color + pFillStyle->mnIndex = -1; + } + + // #i5775# don't overwrite %transparency with binary transparency + if( ( pBackTransparency != nullptr ) && ( pBackTransparent != nullptr ) ) + { + if( ! *o3tl::doAccess<bool>(pBackTransparent->maValue) ) + pBackTransparent->mnIndex = -1; + } + + + // insert newly created properties. This invalidates all iterators! + // Most of the pXXX variables in this method are iterators and will be + // invalidated!!! + + if( pNewFontStyleName ) + { + rProperties.push_back( *pNewFontStyleName ); + pNewFontStyleName.reset(); + } + + if( pNewFontFamily ) + { + rProperties.push_back( *pNewFontFamily ); + pNewFontFamily.reset(); + } + + if( pNewFontPitch ) + { + rProperties.push_back( *pNewFontPitch ); + pNewFontPitch.reset(); + } + + if( pNewFontCharSet ) + { + rProperties.push_back( *pNewFontCharSet ); + pNewFontCharSet.reset(); + } + + if( pNewFontStyleNameCJK ) + { + rProperties.push_back( *pNewFontStyleNameCJK ); + pNewFontStyleNameCJK.reset(); + } + + if( pNewFontFamilyCJK ) + { + rProperties.push_back( *pNewFontFamilyCJK ); + pNewFontFamilyCJK.reset(); + } + + if( pNewFontPitchCJK ) + { + rProperties.push_back( *pNewFontPitchCJK ); + pNewFontPitchCJK.reset(); + } + + if( pNewFontCharSetCJK ) + { + rProperties.push_back( *pNewFontCharSetCJK ); + pNewFontCharSetCJK.reset(); + } + + if( pNewFontStyleNameCTL) + { + rProperties.push_back( *pNewFontStyleNameCTL ); + pNewFontStyleNameCTL.reset(); + } + + if( pNewFontFamilyCTL ) + { + rProperties.push_back( *pNewFontFamilyCTL ); + pNewFontFamilyCTL.reset(); + } + + if( pNewFontPitchCTL ) + { + rProperties.push_back( *pNewFontPitchCTL ); + pNewFontPitchCTL.reset(); + } + + if( pNewFontCharSetCTL ) + { + rProperties.push_back( *pNewFontCharSetCTL ); + pNewFontCharSetCTL.reset(); + } + + for (sal_uInt16 i=0; i<4; i++) + { + if (pNewParaMargins[i]) + { + rProperties.push_back(*pNewParaMargins[i]); + } + if (pNewMargins[i]) + { + rProperties.push_back(*pNewMargins[i]); + } + if( pNewBorderDistances[i] ) + { + rProperties.push_back( *pNewBorderDistances[i] ); + delete pNewBorderDistances[i]; + } + if( pNewBorders[i] ) + { + rProperties.push_back( *pNewBorders[i] ); + delete pNewBorders[i]; + } + if( pCharNewBorderDistances[i] ) + { + rProperties.push_back( *pCharNewBorderDistances[i] ); + delete pCharNewBorderDistances[i]; + } + if( pCharNewBorders[i] ) + { + rProperties.push_back( *pCharNewBorders[i] ); + delete pCharNewBorders[i]; + } + } + + if( bHasAnyHeight ) + { + if( m_nSizeTypeIndex == -2 ) + { + const_cast < XMLTextImportPropertyMapper * > ( this ) + ->m_nSizeTypeIndex = -1; + sal_Int32 nPropCount = getPropertySetMapper()->GetEntryCount(); + for( sal_Int32 j=0; j < nPropCount; j++ ) + { + if( CTF_SIZETYPE == getPropertySetMapper() + ->GetEntryContextId( j ) ) + { + const_cast < XMLTextImportPropertyMapper * > ( this ) + ->m_nSizeTypeIndex = j; + break; + } + } + } + if( m_nSizeTypeIndex != -1 ) + { + XMLPropertyState aSizeTypeState( m_nSizeTypeIndex ); + aSizeTypeState.maValue <<= static_cast<sal_Int16>( bHasAnyMinHeight + ? SizeType::MIN + : SizeType::FIX); + rProperties.push_back( aSizeTypeState ); + } + } + + if( !bHasAnyWidth ) + return; + + if( m_nWidthTypeIndex == -2 ) + { + const_cast < XMLTextImportPropertyMapper * > ( this ) + ->m_nWidthTypeIndex = -1; + sal_Int32 nCount = getPropertySetMapper()->GetEntryCount(); + for( sal_Int32 j=0; j < nCount; j++ ) + { + if( CTF_FRAMEWIDTH_TYPE == getPropertySetMapper() + ->GetEntryContextId( j ) ) + { + const_cast < XMLTextImportPropertyMapper * > ( this ) + ->m_nWidthTypeIndex = j; + break; + } + } + } + if( m_nWidthTypeIndex != -1 ) + { + XMLPropertyState aSizeTypeState( m_nWidthTypeIndex ); + aSizeTypeState.maValue <<= static_cast<sal_Int16>( bHasAnyMinWidth + ? SizeType::MIN + : SizeType::FIX); + rProperties.push_back( aSizeTypeState ); + } + + // DO NOT USE ITERATORS/POINTERS INTO THE rProperties-VECTOR AFTER + // THIS LINE. All iterators into the rProperties-vector, especially all + // pXXX-type variables set in the first switch statement of this method, + // may have been invalidated by the above push_back() calls! +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtlists.cxx b/xmloff/source/text/txtlists.cxx new file mode 100644 index 0000000000..9b3b46f175 --- /dev/null +++ b/xmloff/source/text/txtlists.cxx @@ -0,0 +1,499 @@ +/* -*- 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 <txtlists.hxx> +#include <comphelper/random.hxx> + +#include <o3tl/safeint.hxx> +#include <tools/datetime.hxx> +#include <tools/long.hxx> +#include <sal/log.hxx> + +#include <xmloff/txtimp.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnumi.hxx> + +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include "XMLTextListItemContext.hxx" +#include "XMLTextListBlockContext.hxx" +#include "txtparai.hxx" + + +using namespace ::com::sun::star; + + +XMLTextListsHelper::XMLTextListsHelper() + // Inconsistent behavior regarding lists (#i92811#) +{ +} + +void XMLTextListsHelper::PushListContext( + XMLTextListBlockContext *i_pListBlock) +{ + mListStack.emplace(i_pListBlock, + static_cast<XMLTextListItemContext*>(nullptr), + static_cast<XMLNumberedParaContext*>(nullptr)); +} + +void XMLTextListsHelper::PushListContext( + XMLNumberedParaContext *i_pNumberedParagraph) +{ + mListStack.emplace( + static_cast<XMLTextListBlockContext*>(nullptr), + static_cast<XMLTextListItemContext*>(nullptr), i_pNumberedParagraph); +} + +void XMLTextListsHelper::PopListContext() +{ + assert(mListStack.size()); + if ( !mListStack.empty()) + mListStack.pop(); +} + +void XMLTextListsHelper::ListContextTop( + XMLTextListBlockContext*& o_pListBlockContext, + XMLTextListItemContext*& o_pListItemContext, + XMLNumberedParaContext*& o_pNumberedParagraphContext ) +{ + if ( !mListStack.empty() ) { + o_pListBlockContext = + static_cast<XMLTextListBlockContext*>(std::get<0>(mListStack.top()).get()); + o_pListItemContext = + static_cast<XMLTextListItemContext *>(std::get<1>(mListStack.top()).get()); + o_pNumberedParagraphContext = + static_cast<XMLNumberedParaContext *>(std::get<2>(mListStack.top()).get()); + } +} + +void XMLTextListsHelper::SetListItem( XMLTextListItemContext *i_pListItem ) +{ + // may be cleared by ListBlockContext for upper list... + if (i_pListItem) { + assert(mListStack.size()); + assert(std::get<0>(mListStack.top()).is() && + "internal error: SetListItem: mListStack has no ListBlock"); + assert(!std::get<1>(mListStack.top()).is() && + "error: SetListItem: list item already exists"); + } + if ( !mListStack.empty() ) { + std::get<1>(mListStack.top()) = i_pListItem; + } +} + +// Handling for parameter <sListStyleDefaultListId> (#i92811#) +void XMLTextListsHelper::KeepListAsProcessed( const OUString& sListId, + const OUString& sListStyleName, + const OUString& sContinueListId, + const OUString& sListStyleDefaultListId ) +{ + if ( IsListProcessed( sListId ) ) + { + assert(false && + "<XMLTextListsHelper::KeepListAsProcessed(..)> - list id already added" ); + return; + } + + if ( !mpProcessedLists ) + { + mpProcessedLists = std::make_unique<tMapForLists>(); + } + + ::std::pair< OUString, OUString > + aListData( sListStyleName, sContinueListId ); + (*mpProcessedLists)[ sListId ] = aListData; + + msLastProcessedListId = sListId; + msListStyleOfLastProcessedList = sListStyleName; + + // Remember what is the last list id of this list style. + if (!mpStyleNameLastListIds) + { + mpStyleNameLastListIds = std::make_unique<std::map<OUString, OUString>>(); + } + (*mpStyleNameLastListIds)[sListStyleName] = sListId; + + // Inconsistent behavior regarding lists (#i92811#) + if ( sListStyleDefaultListId.isEmpty()) + return; + + if ( !mpMapListIdToListStyleDefaultListId ) + { + mpMapListIdToListStyleDefaultListId = std::make_unique<tMapForLists>(); + } + + if ( mpMapListIdToListStyleDefaultListId->find( sListStyleName ) == + mpMapListIdToListStyleDefaultListId->end() ) + { + ::std::pair< OUString, OUString > + aListIdMapData( sListId, sListStyleDefaultListId ); + (*mpMapListIdToListStyleDefaultListId)[ sListStyleName ] = + aListIdMapData; + } +} + +bool XMLTextListsHelper::IsListProcessed( const OUString& sListId ) const +{ + if ( !mpProcessedLists ) + { + return false; + } + + return mpProcessedLists->find( sListId ) != mpProcessedLists->end(); +} + +OUString XMLTextListsHelper::GetListStyleOfProcessedList( + const OUString& sListId ) const +{ + if ( mpProcessedLists ) + { + tMapForLists::const_iterator aIter = mpProcessedLists->find( sListId ); + if ( aIter != mpProcessedLists->end() ) + { + return (*aIter).second.first; + } + } + + return OUString(); +} + +OUString XMLTextListsHelper::GetContinueListIdOfProcessedList( + const OUString& sListId ) const +{ + if ( mpProcessedLists ) + { + tMapForLists::const_iterator aIter = mpProcessedLists->find( sListId ); + if ( aIter != mpProcessedLists->end() ) + { + return (*aIter).second.second; + } + } + + return OUString(); +} + + +OUString XMLTextListsHelper::GenerateNewListId() const +{ + static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr); + OUString sTmpStr( "list" ); + + if (bHack) + { + static sal_Int64 nIdCounter = SAL_CONST_INT64(5000000000); + sTmpStr += OUString::number(nIdCounter++); + } + else + { + // Value of xml:id in element <text:list> has to be a valid ID type (#i92478#) + DateTime aDateTime( DateTime::SYSTEM ); + sal_Int64 n = aDateTime.GetTime(); + n += aDateTime.GetDateUnsigned(); + n += comphelper::rng::uniform_int_distribution(0, std::numeric_limits<int>::max()); + // Value of xml:id in element <text:list> has to be a valid ID type (#i92478#) + sTmpStr += OUString::number( n ); + } + + OUString sNewListId( sTmpStr ); + if ( mpProcessedLists ) + { + tools::Long nHitCount = 0; + while ( mpProcessedLists->find( sNewListId ) != mpProcessedLists->end() ) + { + ++nHitCount; + sNewListId = sTmpStr + OUString::number( nHitCount ); + } + } + + return sNewListId; +} + +// Provide list id for a certain list block for import (#i92811#) +OUString XMLTextListsHelper::GetListIdForListBlock( XMLTextListBlockContext const & rListBlock ) +{ + OUString sListBlockListId( rListBlock.GetContinueListId() ); + if ( sListBlockListId.isEmpty() ) + { + sListBlockListId = rListBlock.GetListId(); + } + + if ( mpMapListIdToListStyleDefaultListId ) + { + if ( !sListBlockListId.isEmpty() ) + { + const OUString sListStyleName = + GetListStyleOfProcessedList( sListBlockListId ); + + tMapForLists::const_iterator aIter = + mpMapListIdToListStyleDefaultListId->find( sListStyleName ); + if ( aIter != mpMapListIdToListStyleDefaultListId->end() ) + { + if ( (*aIter).second.first == sListBlockListId ) + { + sListBlockListId = (*aIter).second.second; + } + } + } + } + + return sListBlockListId; +} + +void XMLTextListsHelper::StoreLastContinuingList( const OUString& sListId, + const OUString& sContinuingListId ) +{ + if ( !mpContinuingLists ) + { + mpContinuingLists = std::make_unique<tMapForContinuingLists>(); + } + + (*mpContinuingLists)[ sListId ] = sContinuingListId; +} + +OUString XMLTextListsHelper::GetLastContinuingListId( + const OUString& sListId ) const +{ + if ( mpContinuingLists ) + { + tMapForContinuingLists::const_iterator aIter = + mpContinuingLists->find( sListId ); + if ( aIter != mpContinuingLists->end() ) + { + return (*aIter).second; + } + } + + return sListId; +} + +void XMLTextListsHelper::PushListOnStack( const OUString& sListId, + const OUString& sListStyleName ) +{ + if ( !mpListStack ) + { + mpListStack = std::make_unique<tStackForLists>(); + } + ::std::pair< OUString, OUString > + aListData( sListId, sListStyleName ); + mpListStack->push_back( aListData ); +} +void XMLTextListsHelper::PopListFromStack() +{ + if ( mpListStack && + !mpListStack->empty() ) + { + mpListStack->pop_back(); + } +} + +bool XMLTextListsHelper::EqualsToTopListStyleOnStack( std::u16string_view sListId ) const +{ + return mpListStack && sListId == mpListStack->back().second; +} + +OUString +XMLTextListsHelper::GetNumberedParagraphListId( + const sal_uInt16 i_Level, + std::u16string_view i_StyleName) +{ + if (i_StyleName.empty()) { + SAL_INFO("xmloff.text", "invalid numbered-paragraph: no style-name"); + } + if (!i_StyleName.empty() + && (i_Level < mLastNumberedParagraphs.size()) + && (mLastNumberedParagraphs[i_Level].first == i_StyleName) ) + { + assert(!mLastNumberedParagraphs[i_Level].second.isEmpty() && + "internal error: numbered-paragraph style-name but no list-id?"); + return mLastNumberedParagraphs[i_Level].second; + } else { + return GenerateNewListId(); + } +} + +static void +ClampLevel(uno::Reference<container::XIndexReplace> const& i_xNumRules, + sal_Int16 & io_rLevel) +{ + assert(i_xNumRules.is()); + if (i_xNumRules.is()) { + const sal_Int32 nLevelCount( i_xNumRules->getCount() ); + if ( io_rLevel >= nLevelCount ) { + io_rLevel = sal::static_int_cast< sal_Int16 >(nLevelCount-1); + } + } +} + +uno::Reference<container::XIndexReplace> +XMLTextListsHelper::EnsureNumberedParagraph( + SvXMLImport & i_rImport, + const OUString& i_ListId, + sal_Int16 & io_rLevel, const OUString& i_StyleName) +{ + assert(!i_ListId.isEmpty()); + assert(io_rLevel >= 0); + NumParaList_t & rNPList( mNPLists[i_ListId] ); + const OUString none; // default + if ( rNPList.empty() ) { + // create default list style for top level + sal_Int16 lev(0); + rNPList.emplace_back(none, + MakeNumRule(i_rImport, nullptr, none, none, lev) ); + } + // create num rule first because this might clamp the level... + uno::Reference<container::XIndexReplace> xNumRules; + if ((0 == io_rLevel) || rNPList.empty() || !i_StyleName.isEmpty()) { + // no parent to inherit from, or explicit style given => new numrules! + // index of parent: level - 1, but maybe that does not exist + const size_t parent( std::min(static_cast<size_t>(io_rLevel), + rNPList.size()) - 1 ); + xNumRules = MakeNumRule(i_rImport, + io_rLevel > 0 ? rNPList[parent].second : nullptr, + io_rLevel > 0 ? rNPList[parent].first : none, + i_StyleName, io_rLevel); + } else { + // no style given, but has a parent => reuse parent numrules! + ClampLevel(rNPList.back().second, io_rLevel); + } + if (static_cast<sal_uInt16>(io_rLevel) + 1U > rNPList.size()) { + // new level: need to enlarge + for (size_t i = rNPList.size(); + i < o3tl::make_unsigned(io_rLevel); ++i) + { + NumParaList_t::value_type const rule(rNPList.back()); + rNPList.push_back(rule); + } + NumParaList_t::value_type const rule(rNPList.back()); + rNPList.push_back(xNumRules.is() + ? ::std::make_pair(i_StyleName, xNumRules) + : rule); + } else { + // old level: no need to enlarge; possibly shrink + if (xNumRules.is()) { + rNPList[io_rLevel] = std::make_pair(i_StyleName, xNumRules); + } + if (static_cast<sal_uInt16>(io_rLevel) + 1U < rNPList.size()) { + rNPList.erase(rNPList.begin() + io_rLevel + 1, rNPList.end()); + } + } + // remember the list id + if (mLastNumberedParagraphs.size() <= o3tl::make_unsigned(io_rLevel)) { + mLastNumberedParagraphs.resize(io_rLevel+1); + } + mLastNumberedParagraphs[io_rLevel] = std::make_pair(i_StyleName, i_ListId); + return rNPList.back().second; +} + +/** extracted from the XMLTextListBlockContext constructor */ +uno::Reference<container::XIndexReplace> +XMLTextListsHelper::MakeNumRule( + SvXMLImport & i_rImport, + const uno::Reference<container::XIndexReplace>& i_rNumRule, + std::u16string_view i_ParentStyleName, + const OUString& i_StyleName, + sal_Int16 & io_rLevel, + bool* o_pRestartNumbering, + bool* io_pSetDefaults) +{ + uno::Reference<container::XIndexReplace> xNumRules(i_rNumRule); + if ( !i_StyleName.isEmpty() && i_StyleName != i_ParentStyleName ) + { + const OUString sDisplayStyleName( + i_rImport.GetStyleDisplayName( XmlStyleFamily::TEXT_LIST, + i_StyleName) ); + const uno::Reference < container::XNameContainer >& rNumStyles( + i_rImport.GetTextImport()->GetNumberingStyles() ); + if( rNumStyles.is() && rNumStyles->hasByName( sDisplayStyleName ) ) + { + uno::Reference < style::XStyle > xStyle; + uno::Any any = rNumStyles->getByName( sDisplayStyleName ); + any >>= xStyle; + + uno::Reference< beans::XPropertySet > xPropSet( xStyle, + uno::UNO_QUERY ); + any = xPropSet->getPropertyValue("NumberingRules"); + any >>= xNumRules; + } + else + { + const SvxXMLListStyleContext *pListStyle( + i_rImport.GetTextImport()->FindAutoListStyle( i_StyleName ) ); + if( pListStyle ) + { + xNumRules = pListStyle->GetNumRules(); + if( !xNumRules.is() ) + { + pListStyle->CreateAndInsertAuto(); + xNumRules = pListStyle->GetNumRules(); + } + } + } + } + + bool bSetDefaults(io_pSetDefaults && *io_pSetDefaults); + if ( !xNumRules.is() ) + { + // If no style name has been specified for this style and for any + // parent or if no num rule with the specified name exists, + // create a new one. + + xNumRules = + SvxXMLListStyleContext::CreateNumRule( i_rImport.GetModel() ); + SAL_INFO_IF(xNumRules.is(), "xmloff.core", "cannot create numrules"); + if ( !xNumRules.is() ) + return xNumRules; + + // Because it is a new num rule, numbering must not be restarted. + if (o_pRestartNumbering) *o_pRestartNumbering = false; + bSetDefaults = true; + if (io_pSetDefaults) *io_pSetDefaults = bSetDefaults; + } + + ClampLevel(xNumRules, io_rLevel); + + if ( bSetDefaults ) + { + // Because there is no list style sheet for this style, a default + // format must be set for any level of this num rule. + SvxXMLListStyleContext::SetDefaultStyle( xNumRules, io_rLevel, + false ); + } + + return xNumRules; +} + +OUString XMLTextListsHelper::GetLastIdOfStyleName(const OUString& sListStyleName) const +{ + if (!mpStyleNameLastListIds) + { + return {}; + } + + auto it = mpStyleNameLastListIds->find(sListStyleName); + if (it == mpStyleNameLastListIds->end()) + { + return {}; + } + + return it->second; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtparae.cxx b/xmloff/source/text/txtparae.cxx new file mode 100644 index 0000000000..f55ee10558 --- /dev/null +++ b/xmloff/source/text/txtparae.cxx @@ -0,0 +1,4351 @@ +/* -*- 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 <o3tl/any.hxx> +#include <xmloff/unointerfacetouniqueidentifiermapper.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/types.h> +#include <sal/log.hxx> +#include <osl/diagnose.h> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/text/XTextSectionsSupplier.hpp> +#include <com/sun/star/text/XTextTablesSupplier.hpp> +#include <com/sun/star/text/XNumberingRulesSupplier.hpp> +#include <com/sun/star/text/XChapterNumberingSupplier.hpp> +#include <com/sun/star/text/XTextTable.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/text/XTextField.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/container/XContentEnumerationAccess.hpp> +#include <com/sun/star/text/XTextFrame.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/text/SizeType.hpp> +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/text/VertOrientation.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <com/sun/star/text/XTextFramesSupplier.hpp> +#include <com/sun/star/text/XTextGraphicObjectsSupplier.hpp> +#include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/document/XEmbeddedObjectSupplier.hpp> +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/document/XRedlinesSupplier.hpp> +#include <com/sun/star/text/XFormField.hpp> +#include <com/sun/star/text/XTextSection.hpp> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/style/XAutoStylesSupplier.hpp> +#include <com/sun/star/style/XAutoStyleFamily.hpp> +#include <com/sun/star/text/XTextFieldsSupplier.hpp> +#include <com/sun/star/drawing/XControlShape.hpp> +#include <com/sun/star/util/DateTime.hpp> + +#include <sax/tools/converter.hxx> + +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlaustp.hxx> +#include <xmloff/families.hxx> +#include "txtexppr.hxx" +#include <xmloff/xmluconv.hxx> +#include "XMLAnchorTypePropHdl.hxx" +#include <xexptran.hxx> +#include <xmloff/ProgressBarHelper.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlexp.hxx> +#include <txtflde.hxx> +#include <xmloff/txtprmap.hxx> +#include <XMLImageMapExport.hxx> +#include "XMLTextNumRuleInfo.hxx" +#include <xmloff/XMLTextListAutoStylePool.hxx> +#include <xmloff/txtparae.hxx> +#include "XMLSectionExport.hxx" +#include "XMLIndexMarkExport.hxx" +#include <xmloff/XMLEventExport.hxx> +#include "XMLRedlineExport.hxx" +#include <MultiPropertySetHelper.hxx> +#include <xmloff/formlayerexport.hxx> +#include "XMLTextCharStyleNamesElementExport.hxx" +#include <xmloff/odffields.hxx> +#include <xmloff/maptype.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/document/XStorageBasedDocument.hpp> +#include <txtlists.hxx> +#include <com/sun/star/rdf/XMetadatable.hpp> +#include <list> +#include <unordered_map> +#include <memory> +#include <vector> +#include <algorithm> +#include <iterator> +#include <officecfg/Office/Common.hxx> +#include <o3tl/safeint.hxx> +#include <comphelper/scopeguard.hxx> +#include <comphelper/sequenceashashmap.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::graphic; +using namespace ::xmloff; +using namespace ::xmloff::token; + +// Implement Title/Description Elements UI (#i73249#) +constexpr OUString gsTitle(u"Title"_ustr); +constexpr OUString gsDescription(u"Description"_ustr); +constexpr OUStringLiteral gsAnchorPageNo(u"AnchorPageNo"); +constexpr OUStringLiteral gsAnchorType(u"AnchorType"); +constexpr OUString gsBookmark(u"Bookmark"_ustr); +constexpr OUString gsChainNextName(u"ChainNextName"_ustr); +constexpr OUString gsContourPolyPolygon(u"ContourPolyPolygon"_ustr); +constexpr OUStringLiteral gsDocumentIndexMark(u"DocumentIndexMark"); +constexpr OUStringLiteral gsFrame(u"Frame"); +constexpr OUStringLiteral gsGraphicFilter(u"GraphicFilter"); +constexpr OUStringLiteral gsGraphicRotation(u"GraphicRotation"); +constexpr OUString gsHeight(u"Height"_ustr); +constexpr OUStringLiteral gsHoriOrient(u"HoriOrient"); +constexpr OUStringLiteral gsHoriOrientPosition(u"HoriOrientPosition"); +constexpr OUString gsHyperLinkName(u"HyperLinkName"_ustr); +constexpr OUString gsHyperLinkTarget(u"HyperLinkTarget"_ustr); +constexpr OUString gsHyperLinkURL(u"HyperLinkURL"_ustr); +constexpr OUString gsIsAutomaticContour(u"IsAutomaticContour"_ustr); +constexpr OUString gsIsCollapsed(u"IsCollapsed"_ustr); +constexpr OUString gsIsPixelContour(u"IsPixelContour"_ustr); +constexpr OUString gsIsStart(u"IsStart"_ustr); +constexpr OUString gsIsSyncHeightToWidth(u"IsSyncHeightToWidth"_ustr); +constexpr OUString gsIsSyncWidthToHeight(u"IsSyncWidthToHeight"_ustr); +constexpr OUString gsNumberingRules(u"NumberingRules"_ustr); +constexpr OUString gsParaConditionalStyleName(u"ParaConditionalStyleName"_ustr); +constexpr OUStringLiteral gsParagraphService(u"com.sun.star.text.Paragraph"); +constexpr OUStringLiteral gsRedline(u"Redline"); +constexpr OUString gsReferenceMark(u"ReferenceMark"_ustr); +constexpr OUString gsRelativeHeight(u"RelativeHeight"_ustr); +constexpr OUString gsRelativeWidth(u"RelativeWidth"_ustr); +constexpr OUStringLiteral gsRuby(u"Ruby"); +constexpr OUStringLiteral gsRubyCharStyleName(u"RubyCharStyleName"); +constexpr OUStringLiteral gsRubyText(u"RubyText"); +constexpr OUString gsServerMap(u"ServerMap"_ustr); +constexpr OUString gsShapeService(u"com.sun.star.drawing.Shape"_ustr); +constexpr OUString gsSizeType(u"SizeType"_ustr); +constexpr OUStringLiteral gsSoftPageBreak( u"SoftPageBreak" ); +constexpr OUStringLiteral gsTableService(u"com.sun.star.text.TextTable"); +constexpr OUStringLiteral gsText(u"Text"); +constexpr OUString gsTextContentService(u"com.sun.star.text.TextContent"_ustr); +constexpr OUStringLiteral gsTextEmbeddedService(u"com.sun.star.text.TextEmbeddedObject"); +constexpr OUString gsTextField(u"TextField"_ustr); +constexpr OUStringLiteral gsTextFieldService(u"com.sun.star.text.TextField"); +constexpr OUStringLiteral gsTextFrameService(u"com.sun.star.text.TextFrame"); +constexpr OUStringLiteral gsTextGraphicService(u"com.sun.star.text.TextGraphicObject"); +constexpr OUString gsTextPortionType(u"TextPortionType"_ustr); +constexpr OUString gsUnvisitedCharStyleName(u"UnvisitedCharStyleName"_ustr); +constexpr OUStringLiteral gsVertOrient(u"VertOrient"); +constexpr OUStringLiteral gsVertOrientPosition(u"VertOrientPosition"); +constexpr OUString gsVisitedCharStyleName(u"VisitedCharStyleName"_ustr); +constexpr OUString gsWidth(u"Width"_ustr); +constexpr OUString gsWidthType( u"WidthType"_ustr ); +constexpr OUStringLiteral gsTextFieldStart( u"TextFieldStart" ); +constexpr OUStringLiteral gsTextFieldSep(u"TextFieldSeparator"); +constexpr OUStringLiteral gsTextFieldEnd( u"TextFieldEnd" ); +constexpr OUStringLiteral gsTextFieldStartEnd( u"TextFieldStartEnd" ); + +namespace +{ + class TextContentSet + { + public: + typedef std::list<Reference<XTextContent>> contents_t; + typedef std::back_insert_iterator<contents_t> inserter_t; + typedef contents_t::const_iterator const_iterator_t; + + inserter_t getInserter() + { return std::back_insert_iterator<contents_t>(m_vTextContents); }; + const_iterator_t getBegin() const + { return m_vTextContents.begin(); }; + const_iterator_t getEnd() const + { return m_vTextContents.end(); }; + + private: + contents_t m_vTextContents; + }; + + struct FrameRefHash + { + size_t operator()(const Reference<XTextFrame>& rFrame) const + { return sal::static_int_cast<size_t>(reinterpret_cast<sal_uIntPtr>(rFrame.get())); } + }; + + bool lcl_TextContentsUnfiltered(const Reference<XTextContent>&) + { return true; }; + + bool lcl_ShapeFilter(const Reference<XTextContent>& xTxtContent) + { + Reference<XShape> xShape(xTxtContent, UNO_QUERY); + if(!xShape.is()) + return false; + Reference<XServiceInfo> xServiceInfo(xTxtContent, UNO_QUERY); + return !xServiceInfo->supportsService("com.sun.star.text.TextFrame") && + !xServiceInfo->supportsService("com.sun.star.text.TextGraphicObject") && + !xServiceInfo->supportsService("com.sun.star.text.TextEmbeddedObject"); + }; + + class BoundFrames + { + public: + typedef bool (*filter_t)(const Reference<XTextContent>&); + BoundFrames( + const Reference<XEnumerationAccess>& rEnumAccess, + const filter_t& rFilter) + : m_xEnumAccess(rEnumAccess) + { + Fill(rFilter); + }; + BoundFrames() + {}; + const TextContentSet& GetPageBoundContents() const + { return m_vPageBounds; }; + const TextContentSet* GetFrameBoundContents(const Reference<XTextFrame>& rParentFrame) const + { + framebound_map_t::const_iterator it = m_vFrameBoundsOf.find(rParentFrame); + if(it == m_vFrameBoundsOf.end()) + return nullptr; + return &(it->second); + }; + Reference<XEnumeration> createEnumeration() const + { + if(!m_xEnumAccess.is()) + return Reference<XEnumeration>(); + return m_xEnumAccess->createEnumeration(); + }; + + private: + typedef std::unordered_map< + Reference<XTextFrame>, + TextContentSet, + FrameRefHash> framebound_map_t; + TextContentSet m_vPageBounds; + framebound_map_t m_vFrameBoundsOf; + const Reference<XEnumerationAccess> m_xEnumAccess; + void Fill(const filter_t& rFilter); + }; + + class FieldParamExporter + { + public: + FieldParamExporter(SvXMLExport* const pExport, Reference<XNameContainer> const & xFieldParams) + : m_pExport(pExport) + , m_xFieldParams(xFieldParams) + { }; + void Export(); + + private: + SvXMLExport* const m_pExport; + const Reference<XNameContainer> m_xFieldParams; + + void ExportParameter(const OUString& sKey, const OUString& sValue); + }; + + struct HyperlinkData + { + OUString href, name, targetFrame, ustyleName, vstyleName; + bool serverMap = false; + css::uno::Reference<css::container::XNameReplace> events; + + HyperlinkData() = default; + HyperlinkData(const css::uno::Reference<css::beans::XPropertySet>& rPropSet); + + bool operator==(const HyperlinkData&); + bool operator!=(const HyperlinkData& rOther) { return !operator==(rOther); } + + bool addHyperlinkAttributes(SvXMLExport& rExport); + void exportEvents(SvXMLExport& rExport); + }; + + HyperlinkData::HyperlinkData(const css::uno::Reference<css::beans::XPropertySet>& rPropSet) + { + const css::uno::Reference<css::beans::XPropertyState> xPropState(rPropSet, UNO_QUERY); + const auto xPropSetInfo(rPropSet->getPropertySetInfo()); + if (xPropSetInfo->hasPropertyByName(gsHyperLinkURL) + && (!xPropState.is() + || PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsHyperLinkURL))) + { + rPropSet->getPropertyValue(gsHyperLinkURL) >>= href; + } + + if (href.isEmpty()) + return; + + if (xPropSetInfo->hasPropertyByName(gsHyperLinkName) + && (!xPropState.is() + || PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsHyperLinkName))) + { + rPropSet->getPropertyValue(gsHyperLinkName) >>= name; + } + + if (xPropSetInfo->hasPropertyByName(gsHyperLinkTarget) + && (!xPropState.is() + || PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsHyperLinkTarget))) + { + rPropSet->getPropertyValue(gsHyperLinkTarget) >>= targetFrame; + } + + if (xPropSetInfo->hasPropertyByName(gsServerMap) + && (!xPropState.is() + || PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsServerMap))) + { + serverMap = *o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsServerMap)); + } + + if (xPropSetInfo->hasPropertyByName(gsUnvisitedCharStyleName) + && (!xPropState.is() + || PropertyState_DIRECT_VALUE + == xPropState->getPropertyState(gsUnvisitedCharStyleName))) + { + rPropSet->getPropertyValue(gsUnvisitedCharStyleName) >>= ustyleName; + } + + if (xPropSetInfo->hasPropertyByName(gsVisitedCharStyleName) + && (!xPropState.is() + || PropertyState_DIRECT_VALUE + == xPropState->getPropertyState(gsVisitedCharStyleName))) + { + rPropSet->getPropertyValue(gsVisitedCharStyleName) >>= vstyleName; + } + + static constexpr OUString sHyperLinkEvents(u"HyperLinkEvents"_ustr); + if (xPropSetInfo->hasPropertyByName(sHyperLinkEvents)) + { + events.set(rPropSet->getPropertyValue(sHyperLinkEvents), uno::UNO_QUERY); + } + } + + bool HyperlinkData::operator==(const HyperlinkData& rOther) + { + if (href != rOther.href || name != rOther.name || targetFrame != rOther.targetFrame + || ustyleName != rOther.ustyleName || vstyleName != rOther.vstyleName + || serverMap != rOther.serverMap) + return false; + + if (events == rOther.events) + return true; + if (!events || !rOther.events) + return false; + + const css::uno::Sequence<OUString> aNames = events->getElementNames(); + if (aNames != rOther.events->getElementNames()) + return false; + for (const auto& rName : aNames) + { + const css::uno::Any aAny = events->getByName(rName); + const css::uno::Any aOtherAny = rOther.events->getByName(rName); + if (aAny != aOtherAny) + return false; + } + return true; + } + + bool HyperlinkData::addHyperlinkAttributes(SvXMLExport& rExport) + { + if (href.isEmpty()) + { + // hyperlink without a URL does not make sense + OSL_ENSURE(false, "hyperlink without a URL --> no export to ODF"); + return false; + } + + rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE); + rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, rExport.GetRelativeReference(href)); + + if (!name.isEmpty()) + rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_NAME, name); + + if (!targetFrame.isEmpty()) + { + rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_TARGET_FRAME_NAME, targetFrame); + enum XMLTokenEnum eTok = targetFrame == "_blank" ? XML_NEW : XML_REPLACE; + rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, eTok); + } + + if (serverMap) + rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_SERVER_MAP, XML_TRUE); + + if (!ustyleName.isEmpty()) + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME, + rExport.EncodeStyleName(ustyleName)); + + if (!vstyleName.isEmpty()) + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_VISITED_STYLE_NAME, + rExport.EncodeStyleName(vstyleName)); + + return true; + } + + void HyperlinkData::exportEvents(SvXMLExport& rExport) + { + // export events (if supported) + if (events) + rExport.GetEventExport().Export(events, false); + } +} + +namespace xmloff +{ + class BoundFrameSets + { + public: + explicit BoundFrameSets(const Reference<XInterface>& rModel); + const BoundFrames* GetTexts() const + { return m_pTexts.get(); }; + const BoundFrames* GetGraphics() const + { return m_pGraphics.get(); }; + const BoundFrames* GetEmbeddeds() const + { return m_pEmbeddeds.get(); }; + const BoundFrames* GetShapes() const + { return m_pShapes.get(); }; + private: + std::unique_ptr<BoundFrames> m_pTexts; + std::unique_ptr<BoundFrames> m_pGraphics; + std::unique_ptr<BoundFrames> m_pEmbeddeds; + std::unique_ptr<BoundFrames> m_pShapes; + }; +} + +#ifdef DBG_UTIL +static bool txtparae_bContainsIllegalCharacters = false; +#endif + +// The following map shows which property values are required: + +// property auto style pass export + +// ParaStyleName if style exists always +// ParaConditionalStyleName if style exists always +// NumberingRules if style exists always +// TextSection always always +// ParaChapterNumberingLevel never always +// NumberingIsNumber never always + +// The conclusion is that for auto styles the first three properties +// should be queried using a multi property set if, and only if, an +// auto style needs to be exported. TextSection should be queried by +// an individual call to getPropertyvalue, because this seems to be +// less expensive than querying the first three properties if they aren't +// required. + +// For the export pass all properties can be queried using a multi property +// set. + +static const char* aParagraphPropertyNamesAuto[] = +{ + "NumberingRules", + "ParaConditionalStyleName", + "ParaStyleName", + nullptr +}; + +namespace { + +enum eParagraphPropertyNamesEnumAuto +{ + NUMBERING_RULES_AUTO = 0, + PARA_CONDITIONAL_STYLE_NAME_AUTO = 1, + PARA_STYLE_NAME_AUTO = 2 +}; + +} + +static const char* aParagraphPropertyNames[] = +{ + "NumberingIsNumber", + "NumberingStyleName", + "OutlineLevel", + "ParaConditionalStyleName", + "ParaStyleName", + "TextSection", + "OutlineContentVisible", + nullptr +}; + +namespace { + +enum eParagraphPropertyNamesEnum +{ + NUMBERING_IS_NUMBER = 0, + PARA_NUMBERING_STYLENAME = 1, + PARA_OUTLINE_LEVEL=2, + PARA_CONDITIONAL_STYLE_NAME = 3, + PARA_STYLE_NAME = 4, + TEXT_SECTION = 5, + PARA_OUTLINE_CONTENT_VISIBLE = 6 +}; + +} + +void BoundFrames::Fill(const filter_t& rFilter) +{ + if(!m_xEnumAccess.is()) + return; + const Reference< XEnumeration > xEnum = m_xEnumAccess->createEnumeration(); + if(!xEnum.is()) + return; + static constexpr OUStringLiteral our_sAnchorType(u"AnchorType"); + static constexpr OUStringLiteral our_sAnchorFrame(u"AnchorFrame"); + while(xEnum->hasMoreElements()) + { + Reference<XPropertySet> xPropSet(xEnum->nextElement(), UNO_QUERY); + Reference<XTextContent> xTextContent(xPropSet, UNO_QUERY); + if(!xPropSet.is() || !xTextContent.is()) + continue; + TextContentAnchorType eAnchor; + xPropSet->getPropertyValue(our_sAnchorType) >>= eAnchor; + if(TextContentAnchorType_AT_PAGE != eAnchor && TextContentAnchorType_AT_FRAME != eAnchor) + continue; + if(!rFilter(xTextContent)) + continue; + + TextContentSet::inserter_t pInserter = m_vPageBounds.getInserter(); + if(TextContentAnchorType_AT_FRAME == eAnchor) + { + Reference<XTextFrame> xAnchorTxtFrame( + xPropSet->getPropertyValue(our_sAnchorFrame), + uno::UNO_QUERY); + pInserter = m_vFrameBoundsOf[xAnchorTxtFrame].getInserter(); + } + *pInserter++ = xTextContent; + } +} + +BoundFrameSets::BoundFrameSets(const Reference<XInterface>& rModel) + : m_pTexts(new BoundFrames()) + , m_pGraphics(new BoundFrames()) + , m_pEmbeddeds(new BoundFrames()) + , m_pShapes(new BoundFrames()) +{ + const Reference<XTextFramesSupplier> xTFS(rModel, UNO_QUERY); + const Reference<XTextGraphicObjectsSupplier> xGOS(rModel, UNO_QUERY); + const Reference<XTextEmbeddedObjectsSupplier> xEOS(rModel, UNO_QUERY); + const Reference<XDrawPageSupplier> xDPS(rModel, UNO_QUERY); + if(xTFS.is()) + m_pTexts.reset(new BoundFrames( + Reference<XEnumerationAccess>(xTFS->getTextFrames(), UNO_QUERY), + &lcl_TextContentsUnfiltered)); + if(xGOS.is()) + m_pGraphics.reset(new BoundFrames( + Reference<XEnumerationAccess>(xGOS->getGraphicObjects(), UNO_QUERY), + &lcl_TextContentsUnfiltered)); + if(xEOS.is()) + m_pEmbeddeds.reset(new BoundFrames( + Reference<XEnumerationAccess>(xEOS->getEmbeddedObjects(), UNO_QUERY), + &lcl_TextContentsUnfiltered)); + if(xDPS.is()) + m_pShapes.reset(new BoundFrames( + Reference<XEnumerationAccess>(xDPS->getDrawPage(), UNO_QUERY), + &lcl_ShapeFilter)); +}; + +void FieldParamExporter::Export() +{ + const Type aStringType = ::cppu::UnoType<OUString>::get(); + const Type aBoolType = cppu::UnoType<sal_Bool>::get(); + const Type aSeqType = cppu::UnoType<Sequence<OUString>>::get(); + const Type aIntType = ::cppu::UnoType<sal_Int32>::get(); + const Sequence<OUString> vParameters(m_xFieldParams->getElementNames()); + for(const auto & rParameter : vParameters) + { + const Any aValue = m_xFieldParams->getByName(rParameter); + const Type& aValueType = aValue.getValueType(); + if(aValueType == aStringType) + { + OUString sValue; + aValue >>= sValue; + ExportParameter(rParameter,sValue); + + if ( rParameter == ODF_OLE_PARAM ) + { + // Save the OLE object + Reference< embed::XStorage > xTargetStg = m_pExport->GetTargetStorage(); + if (xTargetStg.is()) { + Reference< embed::XStorage > xDstStg = xTargetStg->openStorageElement( + "OLELinks", embed::ElementModes::WRITE ); + + if ( !xDstStg->hasByName( sValue ) ) { + Reference< XStorageBasedDocument > xStgDoc ( + m_pExport->GetModel( ), UNO_QUERY ); + Reference< embed::XStorage > xDocStg = xStgDoc->getDocumentStorage(); + Reference< embed::XStorage > xOleStg = xDocStg->openStorageElement( + "OLELinks", embed::ElementModes::READ ); + + xOleStg->copyElementTo( sValue, xDstStg, sValue ); + Reference< embed::XTransactedObject > xTransact( xDstStg, UNO_QUERY ); + if ( xTransact.is( ) ) + xTransact->commit( ); + } + } else { + SAL_WARN("xmloff", "no target storage"); + } + } + } + else if(aValueType == aBoolType) + { + bool bValue = false; + aValue >>= bValue; + ExportParameter(rParameter, OUString::boolean(bValue) ); + } + else if(aValueType == aSeqType) + { + Sequence<OUString> vValue; + aValue >>= vValue; + for(const OUString & i : std::as_const(vValue)) + { + ExportParameter(rParameter, i); + } + } + else if(aValueType == aIntType) + { + sal_Int32 nValue = 0; + aValue >>= nValue; + ExportParameter(rParameter, OUString::number(nValue)); + } + } +} + +void FieldParamExporter::ExportParameter(const OUString& sKey, const OUString& sValue) +{ + m_pExport->AddAttribute(XML_NAMESPACE_FIELD, XML_NAME, sKey); + m_pExport->AddAttribute(XML_NAMESPACE_FIELD, XML_VALUE, sValue); + m_pExport->StartElement(XML_NAMESPACE_FIELD, XML_PARAM, false); + m_pExport->EndElement(XML_NAMESPACE_FIELD, XML_PARAM, false); +} + +void XMLTextParagraphExport::Add( XmlStyleFamily nFamily, + const Reference < XPropertySet > & rPropSet, + const std::span<const XMLPropertyState> aAddStates, + bool bDontSeek ) +{ + rtl::Reference < SvXMLExportPropertyMapper > xPropMapper; + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + xPropMapper = GetParaPropMapper(); + break; + case XmlStyleFamily::TEXT_TEXT: + xPropMapper = GetTextPropMapper(); + break; + case XmlStyleFamily::TEXT_FRAME: + xPropMapper = GetAutoFramePropMapper(); + break; + case XmlStyleFamily::TEXT_SECTION: + xPropMapper = GetSectionPropMapper(); + break; + case XmlStyleFamily::TEXT_RUBY: + xPropMapper = GetRubyPropMapper(); + break; + default: break; + } + SAL_WARN_IF( !xPropMapper.is(), "xmloff", "There is the property mapper?" ); + + std::vector< XMLPropertyState > aPropStates = + xPropMapper->Filter(GetExport(), rPropSet); + + aPropStates.insert( aPropStates.end(), aAddStates.begin(), aAddStates.end() ); + + if( aPropStates.empty() ) + return; + + Reference< XPropertySetInfo > xPropSetInfo(rPropSet->getPropertySetInfo()); + OUString sParent, sCondParent; + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + if( xPropSetInfo->hasPropertyByName( gsParaStyleName ) ) + { + rPropSet->getPropertyValue( gsParaStyleName ) >>= sParent; + } + if( xPropSetInfo->hasPropertyByName( gsParaConditionalStyleName ) ) + { + rPropSet->getPropertyValue( gsParaConditionalStyleName ) >>= sCondParent; + } + if( xPropSetInfo->hasPropertyByName( gsNumberingRules ) ) + { + Reference < XIndexReplace > xNumRule(rPropSet->getPropertyValue( gsNumberingRules ), uno::UNO_QUERY); + if( xNumRule.is() && xNumRule->getCount() ) + { + Reference < XNamed > xNamed( xNumRule, UNO_QUERY ); + OUString sName; + if( xNamed.is() ) + sName = xNamed->getName(); + bool bAdd = sName.isEmpty(); + if( !bAdd ) + { + Reference < XPropertySet > xNumPropSet( xNumRule, + UNO_QUERY ); + if( xNumPropSet.is() && + xNumPropSet->getPropertySetInfo() + ->hasPropertyByName( "IsAutomatic" ) ) + { + bAdd = *o3tl::doAccess<bool>(xNumPropSet->getPropertyValue( "IsAutomatic" )); + // Check on outline style (#i73361#) + if ( bAdd && + xNumPropSet->getPropertySetInfo() + ->hasPropertyByName( "NumberingIsOutline" ) ) + { + bAdd = !(*o3tl::doAccess<bool>(xNumPropSet->getPropertyValue( "NumberingIsOutline" ))); + } + } + else + { + bAdd = true; + } + } + if( bAdd ) + maListAutoPool.Add( xNumRule ); + } + } + break; + case XmlStyleFamily::TEXT_TEXT: + { + // Get parent and remove hyperlinks (they aren't of interest) + rtl::Reference< XMLPropertySetMapper > xPM(xPropMapper->getPropertySetMapper()); + sal_uInt16 nIgnoreProps = 0; + for( ::std::vector< XMLPropertyState >::iterator i(aPropStates.begin()); + nIgnoreProps < 2 && i != aPropStates.end(); ) + { + if( i->mnIndex == -1 ) + { + ++i; + continue; + } + + switch( xPM->GetEntryContextId(i->mnIndex) ) + { + case CTF_CHAR_STYLE_NAME: + case CTF_HYPERLINK_URL: + i->mnIndex = -1; + nIgnoreProps++; + i = aPropStates.erase( i ); + break; + default: + ++i; + break; + } + } + } + break; + case XmlStyleFamily::TEXT_FRAME: + if( xPropSetInfo->hasPropertyByName( gsFrameStyleName ) ) + { + rPropSet->getPropertyValue( gsFrameStyleName ) >>= sParent; + } + break; + case XmlStyleFamily::TEXT_SECTION: + case XmlStyleFamily::TEXT_RUBY: + ; // section styles have no parents + break; + default: break; + } + if (aPropStates.size()) // could change after the previous check + { + GetAutoStylePool().Add( nFamily, sParent, std::vector(aPropStates), bDontSeek ); + if( !sCondParent.isEmpty() && sParent != sCondParent ) + GetAutoStylePool().Add( nFamily, sCondParent, std::move(aPropStates) ); + } +} + +static bool lcl_validPropState( const XMLPropertyState& rState ) +{ + return rState.mnIndex != -1; +} + +void XMLTextParagraphExport::Add( XmlStyleFamily nFamily, + MultiPropertySetHelper& rPropSetHelper, + const Reference < XPropertySet > & rPropSet) +{ + rtl::Reference < SvXMLExportPropertyMapper > xPropMapper; + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + xPropMapper = GetParaPropMapper(); + break; + default: break; + } + SAL_WARN_IF( !xPropMapper.is(), "xmloff", "There is the property mapper?" ); + + std::vector<XMLPropertyState> aPropStates(xPropMapper->Filter(GetExport(), rPropSet)); + + if( rPropSetHelper.hasProperty( NUMBERING_RULES_AUTO ) ) + { + Reference < XIndexReplace > xNumRule(rPropSetHelper.getValue( NUMBERING_RULES_AUTO, + rPropSet, true ), uno::UNO_QUERY); + if( xNumRule.is() && xNumRule->getCount() ) + { + Reference < XNamed > xNamed( xNumRule, UNO_QUERY ); + OUString sName; + if( xNamed.is() ) + sName = xNamed->getName(); + bool bAdd = sName.isEmpty(); + if( !bAdd ) + { + Reference < XPropertySet > xNumPropSet( xNumRule, + UNO_QUERY ); + if( xNumPropSet.is() && + xNumPropSet->getPropertySetInfo() + ->hasPropertyByName( "IsAutomatic" ) ) + { + bAdd = *o3tl::doAccess<bool>(xNumPropSet->getPropertyValue( "IsAutomatic" )); + // Check on outline style (#i73361#) + if ( bAdd && + xNumPropSet->getPropertySetInfo() + ->hasPropertyByName( "NumberingIsOutline" ) ) + { + bAdd = !(*o3tl::doAccess<bool>(xNumPropSet->getPropertyValue( "NumberingIsOutline" ))); + } + } + else + { + bAdd = true; + } + } + if( bAdd ) + maListAutoPool.Add( xNumRule ); + } + } + + if( aPropStates.empty() ) + return; + + OUString sParent, sCondParent; + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + if( rPropSetHelper.hasProperty( PARA_STYLE_NAME_AUTO ) ) + { + rPropSetHelper.getValue( PARA_STYLE_NAME_AUTO, rPropSet, + true ) >>= sParent; + } + if( rPropSetHelper.hasProperty( PARA_CONDITIONAL_STYLE_NAME_AUTO ) ) + { + rPropSetHelper.getValue( PARA_CONDITIONAL_STYLE_NAME_AUTO, + rPropSet, true ) >>= sCondParent; + } + + break; + default: break; + } + + if( std::any_of( aPropStates.begin(), aPropStates.end(), lcl_validPropState ) ) + { + GetAutoStylePool().Add( nFamily, sParent, std::vector(aPropStates) ); + if( !sCondParent.isEmpty() && sParent != sCondParent ) + GetAutoStylePool().Add( nFamily, sCondParent, std::move(aPropStates) ); + } +} + +OUString XMLTextParagraphExport::Find( + XmlStyleFamily nFamily, + const Reference < XPropertySet > & rPropSet, + const OUString& rParent, + const std::span<const XMLPropertyState> aAddStates) const +{ + OUString sName( rParent ); + rtl::Reference < SvXMLExportPropertyMapper > xPropMapper; + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + xPropMapper = GetParaPropMapper(); + break; + case XmlStyleFamily::TEXT_FRAME: + xPropMapper = GetAutoFramePropMapper(); + break; + case XmlStyleFamily::TEXT_SECTION: + xPropMapper = GetSectionPropMapper(); + break; + case XmlStyleFamily::TEXT_RUBY: + xPropMapper = GetRubyPropMapper(); + break; + default: break; + } + SAL_WARN_IF( !xPropMapper.is(), "xmloff", "There is the property mapper?" ); + if( !xPropMapper.is() ) + return sName; + std::vector<XMLPropertyState> aPropStates(xPropMapper->Filter(GetExport(), rPropSet)); + aPropStates.insert( aPropStates.end(), aAddStates.begin(), aAddStates.end() ); + if( std::any_of( aPropStates.begin(), aPropStates.end(), lcl_validPropState ) ) + sName = GetAutoStylePool().Find( nFamily, sName, aPropStates ); + + return sName; +} + +OUString XMLTextParagraphExport::FindTextStyle( + const Reference < XPropertySet > & rPropSet, + bool& rbHasCharStyle, + bool& rbHasAutoStyle, + const XMLPropertyState** ppAddStates ) const +{ + rtl::Reference < SvXMLExportPropertyMapper > xPropMapper(GetTextPropMapper()); + std::vector<XMLPropertyState> aPropStates(xPropMapper->Filter(GetExport(), rPropSet)); + + // Get parent and remove hyperlinks (they aren't of interest) + OUString sName; + rbHasCharStyle = rbHasAutoStyle = false; + sal_uInt16 nIgnoreProps = 0; + rtl::Reference< XMLPropertySetMapper > xPM(xPropMapper->getPropertySetMapper()); + ::std::vector< XMLPropertyState >::iterator aFirstDel = aPropStates.end(); + ::std::vector< XMLPropertyState >::iterator aSecondDel = aPropStates.end(); + + for( ::std::vector< XMLPropertyState >::iterator + i = aPropStates.begin(); + nIgnoreProps < 2 && i != aPropStates.end(); + ++i ) + { + if( i->mnIndex == -1 ) + continue; + + switch( xPM->GetEntryContextId(i->mnIndex) ) + { + case CTF_CHAR_STYLE_NAME: + i->maValue >>= sName; + i->mnIndex = -1; + rbHasCharStyle = !sName.isEmpty(); + if( nIgnoreProps ) + aSecondDel = i; + else + aFirstDel = i; + nIgnoreProps++; + break; + case CTF_HYPERLINK_URL: + i->mnIndex = -1; + if( nIgnoreProps ) + aSecondDel = i; + else + aFirstDel = i; + nIgnoreProps++; + break; + } + } + if( ppAddStates ) + { + while( *ppAddStates ) + { + aPropStates.push_back( **ppAddStates ); + ppAddStates++; + } + } + if (aPropStates.size() - nIgnoreProps) + { + // erase the character style, otherwise the autostyle cannot be found! + // erase the hyperlink, otherwise the autostyle cannot be found! + if ( nIgnoreProps ) + { + // If two elements of a vector have to be deleted, + // we should delete the second one first. + if( --nIgnoreProps ) + aPropStates.erase( aSecondDel ); + aPropStates.erase( aFirstDel ); + } + sName = GetAutoStylePool().Find( + XmlStyleFamily::TEXT_TEXT, + OUString(), // AutoStyles should not have parents! + aPropStates ); + rbHasAutoStyle = true; + } + + return sName; +} + +// adjustments to support lists independent from list style +void XMLTextParagraphExport::exportListChange( + const XMLTextNumRuleInfo& rPrevInfo, + const XMLTextNumRuleInfo& rNextInfo ) +{ + // end a list + if ( rPrevInfo.GetLevel() > 0 ) + { + sal_uInt32 nListLevelsToBeClosed = 0; // unsigned larger type to safely multiply and compare + if ( !rNextInfo.BelongsToSameList( rPrevInfo ) || + rNextInfo.GetLevel() <= 0 ) + { + // close complete previous list + nListLevelsToBeClosed = rPrevInfo.GetLevel(); + } + else if ( rPrevInfo.GetLevel() > rNextInfo.GetLevel() ) + { + // close corresponding sub lists + nListLevelsToBeClosed = rPrevInfo.GetLevel() - rNextInfo.GetLevel(); + } + + if ( nListLevelsToBeClosed > 0 && + maListElements.size() >= 2 * nListLevelsToBeClosed ) + { + do { + for(size_t j = 0; j < 2; ++j) + { + OUString aElem(maListElements.back()); + maListElements.pop_back(); + GetExport().EndElement(aElem, true); + } + + // remove closed list from list stack + mpTextListsHelper->PopListFromStack(); + + --nListLevelsToBeClosed; + } while ( nListLevelsToBeClosed > 0 ); + } + } + + // start a new list + if ( rNextInfo.GetLevel() > 0 ) + { + bool bRootListToBeStarted = false; + sal_Int16 nListLevelsToBeOpened = 0; + if ( !rPrevInfo.BelongsToSameList( rNextInfo ) || + rPrevInfo.GetLevel() <= 0 ) + { + // new root list + bRootListToBeStarted = true; + nListLevelsToBeOpened = rNextInfo.GetLevel(); + } + else if ( rNextInfo.GetLevel() > rPrevInfo.GetLevel() ) + { + // open corresponding sub lists + nListLevelsToBeOpened = rNextInfo.GetLevel() - rPrevInfo.GetLevel(); + } + + if ( nListLevelsToBeOpened > 0 ) + { + const OUString& sListStyleName( rNextInfo.GetNumRulesName() ); + // Currently only the text documents support <ListId>. + // Thus, for other document types <sListId> is empty. + const OUString& sListId( rNextInfo.GetListId() ); + bool bExportListStyle( true ); + bool bRestartNumberingAtContinuedList( false ); + sal_Int32 nRestartValueForContinuedList( -1 ); + bool bContinueingPreviousSubList = !bRootListToBeStarted && + rNextInfo.IsContinueingPreviousSubTree(); + do { + GetExport().CheckAttrList(); + + if ( bRootListToBeStarted ) + { + if ( !mpTextListsHelper->IsListProcessed( sListId ) ) + { + if ( ExportListId() && + !sListId.isEmpty() && !rNextInfo.IsListIdDefault() ) + { + /* Property text:id at element <text:list> has to be + replaced by property xml:id (#i92221#) + */ + GetExport().AddAttribute( XML_NAMESPACE_XML, + XML_ID, + sListId ); + } + mpTextListsHelper->KeepListAsProcessed( sListId, + sListStyleName, + OUString() ); + } + else + { + const OUString sNewListId( + mpTextListsHelper->GenerateNewListId() ); + if ( ExportListId() && + !sListId.isEmpty() && !rNextInfo.IsListIdDefault() ) + { + /* Property text:id at element <text:list> has to be + replaced by property xml:id (#i92221#) + */ + GetExport().AddAttribute( XML_NAMESPACE_XML, + XML_ID, + sNewListId ); + } + + const OUString sContinueListId = + mpTextListsHelper->GetLastContinuingListId( sListId ); + // store that list with list id <sNewListId> is last list, + // which has continued list with list id <sListId> + mpTextListsHelper->StoreLastContinuingList( sListId, + sNewListId ); + if ( sListStyleName == + mpTextListsHelper->GetListStyleOfLastProcessedList() && + // Inconsistent behavior regarding lists (#i92811#) + sContinueListId == + mpTextListsHelper->GetLastProcessedListId() ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_CONTINUE_NUMBERING, + XML_TRUE ); + } + else + { + if ( ExportListId() && + !sListId.isEmpty() ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_CONTINUE_LIST, + sContinueListId ); + } + } + + if ( rNextInfo.IsRestart() && + ( nListLevelsToBeOpened != 1 || + !rNextInfo.HasStartValue() ) ) + { + bRestartNumberingAtContinuedList = true; + nRestartValueForContinuedList = + rNextInfo.GetListLevelStartValue(); + } + + mpTextListsHelper->KeepListAsProcessed( sNewListId, + sListStyleName, + sContinueListId ); + } + + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sListStyleName ) ); + bExportListStyle = false; + + bRootListToBeStarted = false; + } + else if ( bExportListStyle && + !mpTextListsHelper->EqualsToTopListStyleOnStack( sListStyleName ) ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sListStyleName ) ); + bExportListStyle = false; + + } + else + { + // rhbz#746174: also export list restart for non root list + if (rNextInfo.IsRestart() && !rNextInfo.HasStartValue()) + { + bRestartNumberingAtContinuedList = true; + nRestartValueForContinuedList = + rNextInfo.GetListLevelStartValue(); + } + } + + if ( bContinueingPreviousSubList ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_CONTINUE_NUMBERING, XML_TRUE ); + bContinueingPreviousSubList = false; + } + + enum XMLTokenEnum eLName = XML_LIST; + + OUString aElem(GetExport().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, + GetXMLToken(eLName) ) ); + GetExport().IgnorableWhitespace(); + GetExport().StartElement(aElem, false); + + maListElements.push_back(aElem); + + mpTextListsHelper->PushListOnStack( sListId, + sListStyleName ); + + // <text:list-header> or <text:list-item> + GetExport().CheckAttrList(); + + /* Export start value at correct list item (#i97309#) */ + if ( nListLevelsToBeOpened == 1 ) + { + if ( rNextInfo.HasStartValue() ) + { + OUString aTmp = OUString::number( static_cast<sal_Int32>(rNextInfo.GetStartValue()) ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE, + aTmp ); + } + else if (bRestartNumberingAtContinuedList) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_START_VALUE, + OUString::number(nRestartValueForContinuedList) ); + bRestartNumberingAtContinuedList = false; + } + } + + eLName = ( rNextInfo.IsNumbered() || nListLevelsToBeOpened > 1 ) + ? XML_LIST_ITEM + : XML_LIST_HEADER; + aElem = GetExport().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, + GetXMLToken(eLName) ); + GetExport().IgnorableWhitespace(); + GetExport().StartElement(aElem, false); + maListElements.push_back(aElem); + + // export of <text:number> element for last opened <text:list-item>, if requested + if ( GetExport().exportTextNumberElement() && + eLName == XML_LIST_ITEM && nListLevelsToBeOpened == 1 && // last iteration --> last opened <text:list-item> + !rNextInfo.ListLabelString().isEmpty() ) + { + const OUString aTextNumberElem = + GetExport().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, + GetXMLToken(XML_NUMBER) ); + GetExport().IgnorableWhitespace(); + GetExport().StartElement( aTextNumberElem, false ); + GetExport().Characters( rNextInfo.ListLabelString() ); + GetExport().EndElement( aTextNumberElem, true ); + } + --nListLevelsToBeOpened; + } while ( nListLevelsToBeOpened > 0 ); + } + } + + bool bEndElement = false; + + if ( rNextInfo.GetLevel() > 0 && + rNextInfo.IsNumbered() && + rPrevInfo.BelongsToSameList( rNextInfo ) && + rPrevInfo.GetLevel() >= rNextInfo.GetLevel() ) + { + assert(maListElements.size() >= 2 && "list elements missing"); + bEndElement = maListElements.size() >= 2; + } + + if (!bEndElement) + return; + + // close previous list-item + GetExport().EndElement(maListElements.back(), true ); + maListElements.pop_back(); + + // Only for sub lists (#i103745#) + if ( rNextInfo.IsRestart() && !rNextInfo.HasStartValue() && + rNextInfo.GetLevel() != 1 ) + { + // start new sub list respectively list on same list level + GetExport().EndElement(maListElements.back(), true ); + GetExport().IgnorableWhitespace(); + GetExport().StartElement(maListElements.back(), false); + } + + // open new list-item + GetExport().CheckAttrList(); + if( rNextInfo.HasStartValue() ) + { + OUString aTmp = OUString::number( static_cast<sal_Int32>(rNextInfo.GetStartValue()) ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE, aTmp ); + } + // Handle restart without start value on list level 1 (#i103745#) + else if ( rNextInfo.IsRestart() && /*!rNextInfo.HasStartValue() &&*/ + rNextInfo.GetLevel() == 1 ) + { + OUString aTmp = OUString::number( static_cast<sal_Int32>(rNextInfo.GetListLevelStartValue()) ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE, aTmp ); + } + if ( ( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) && + GetExport().getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + { + const OUString& sListStyleName( rNextInfo.GetNumRulesName() ); + if ( !mpTextListsHelper->EqualsToTopListStyleOnStack( sListStyleName ) ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_STYLE_OVERRIDE, + GetExport().EncodeStyleName( sListStyleName ) ); + } + } + OUString aElem( GetExport().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, + GetXMLToken(XML_LIST_ITEM) ) ); + GetExport().IgnorableWhitespace(); + GetExport().StartElement(aElem, false ); + maListElements.push_back(aElem); + + // export of <text:number> element for <text:list-item>, if requested + if ( GetExport().exportTextNumberElement() && + !rNextInfo.ListLabelString().isEmpty() ) + { + const OUString aTextNumberElem = + GetExport().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, + GetXMLToken(XML_NUMBER) ); + GetExport().IgnorableWhitespace(); + GetExport().StartElement( aTextNumberElem, false ); + GetExport().Characters( rNextInfo.ListLabelString() ); + GetExport().EndElement( aTextNumberElem, true ); + } + +} + +struct XMLTextParagraphExport::Impl +{ + typedef ::std::map<Reference<XFormField>, sal_Int32> FieldMarkMap_t; + FieldMarkMap_t m_FieldMarkMap; + + explicit Impl() {} + sal_Int32 AddFieldMarkStart(Reference<XFormField> const& i_xFieldMark) + { + assert(m_FieldMarkMap.find(i_xFieldMark) == m_FieldMarkMap.end()); + sal_Int32 const ret(m_FieldMarkMap.size()); + m_FieldMarkMap.insert(::std::make_pair(i_xFieldMark, ret)); + return ret; + } + sal_Int32 GetFieldMarkIndex(Reference<XFormField> const& i_xFieldMark) + { + FieldMarkMap_t::const_iterator const it( + m_FieldMarkMap.find(i_xFieldMark)); + // rely on SwXFieldmark::CreateXFieldmark returning the same instance + // because the Reference in m_FieldMarkMap will keep it alive + assert(it != m_FieldMarkMap.end()); + return it->second; + } +}; + +struct XMLTextParagraphExport::DocumentListNodes +{ + struct NodeData + { + sal_Int32 index; // see SwNode::GetIndex and SwNodeOffset + sal_uInt64 style_id; // actually a pointer to NumRule + OUString list_id; + }; + std::vector<NodeData> docListNodes; + DocumentListNodes(const css::uno::Reference<css::frame::XModel>& xModel) + { + // Sequence of nodes, each of them represented by three-element sequence, + // corresponding to NodeData members + css::uno::Sequence<css::uno::Sequence<css::uno::Any>> nodes; + if (auto xPropSet = xModel.query<css::beans::XPropertySet>()) + { + try + { + // See SwXTextDocument::getPropertyValue + xPropSet->getPropertyValue("ODFExport_ListNodes") >>= nodes; + } + catch (css::beans::UnknownPropertyException&) + { + // That's absolutely fine! + } + } + + docListNodes.reserve(nodes.getLength()); + for (const auto& node : nodes) + { + assert(node.getLength() == 3); + docListNodes.push_back({ node[0].get<sal_Int32>(), node[1].get<sal_uInt64>(), + node[2].get<OUString>() }); + } + + std::sort(docListNodes.begin(), docListNodes.end(), + [](const NodeData& lhs, const NodeData& rhs) { return lhs.index < rhs.index; }); + } + bool ShouldSkipListId(const Reference<XTextContent>& xTextContent) const + { + if (docListNodes.empty()) + return false; + + if (auto xPropSet = xTextContent.query<css::beans::XPropertySet>()) + { + sal_Int32 index = 0; + try + { + // See SwXParagraph::Impl::GetPropertyValues_Impl + xPropSet->getPropertyValue("ODFExport_NodeIndex") >>= index; + } + catch (css::beans::UnknownPropertyException&) + { + // That's absolutely fine! + return false; + } + + auto it = std::lower_bound(docListNodes.begin(), docListNodes.end(), index, + [](const NodeData& lhs, sal_Int32 rhs) + { return lhs.index < rhs; }); + if (it == docListNodes.end() || it->index != index) + return false; + + // We need to write the id, when there will be continuation of the list either with + // a different list style, or after another list. + + for (auto next = it + 1; next != docListNodes.end(); ++next) + { + if (it->list_id != next->list_id) + { + // List changed. We will have to refer to this id, only if there will + // appear a continuation of this list + return std::find_if(next + 1, docListNodes.end(), + [list_id = it->list_id](const NodeData& data) + { return data.list_id == list_id; }) + == docListNodes.end(); + } + + if (it->style_id != next->style_id) + { + // Same list, new style -> this "next" will refer to the id, no skipping + return false; + } + if (it->index + 1 != next->index) + { + // we have a gap before the next node with the same list and style, + // with no other lists in between. There will be a continuation with a + // simple 'text:continue-numbering="true"'. + return true; + } + it = next; // walk through adjacent nodes of the same list + } + // all nodes were adjacent and of the same list and style -> no continuation, skip id + return true; + } + + return false; + } +}; + +XMLTextParagraphExport::XMLTextParagraphExport( + SvXMLExport& rExp, + SvXMLAutoStylePoolP & rASP + ) : + XMLStyleExport( rExp, &rASP ), + m_xImpl(new Impl), + m_rAutoStylePool( rASP ), + m_pBoundFrameSets(new BoundFrameSets(GetExport().GetModel())), + maListAutoPool( GetExport() ), + m_bProgress( false ), + m_bBlock( false ), + m_bOpenRuby( false ), + mpTextListsHelper( nullptr ), + mbCollected(false), + m_aCharStyleNamesPropInfoCache( gsCharStyleNames ) +{ + rtl::Reference < XMLPropertySetMapper > xPropMapper(new XMLTextPropertySetMapper( TextPropMap::PARA, true )); + m_xParaPropMapper = new XMLTextExportPropertySetMapper( xPropMapper, + GetExport() ); + + OUString sFamily( GetXMLToken(XML_PARAGRAPH) ); + OUString aPrefix(u'P'); + m_rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_PARAGRAPH, sFamily, + m_xParaPropMapper, aPrefix ); + + xPropMapper = new XMLTextPropertySetMapper( TextPropMap::TEXT, true ); + m_xTextPropMapper = new XMLTextExportPropertySetMapper( xPropMapper, + GetExport() ); + sFamily = GetXMLToken(XML_TEXT); + aPrefix = "T"; + m_rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_TEXT, sFamily, + m_xTextPropMapper, aPrefix ); + + xPropMapper = new XMLTextPropertySetMapper( TextPropMap::AUTO_FRAME, true ); + m_xAutoFramePropMapper = new XMLTextExportPropertySetMapper( xPropMapper, + GetExport() ); + sFamily = XML_STYLE_FAMILY_SD_GRAPHICS_NAME; + aPrefix = "fr"; + m_rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_FRAME, sFamily, + m_xAutoFramePropMapper, aPrefix ); + + xPropMapper = new XMLTextPropertySetMapper( TextPropMap::SECTION, true ); + m_xSectionPropMapper = new XMLTextExportPropertySetMapper( xPropMapper, + GetExport() ); + sFamily = GetXMLToken( XML_SECTION ); + aPrefix = "Sect" ; + m_rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_SECTION, sFamily, + m_xSectionPropMapper, aPrefix ); + + xPropMapper = new XMLTextPropertySetMapper( TextPropMap::RUBY, true ); + m_xRubyPropMapper = new SvXMLExportPropertyMapper( xPropMapper ); + sFamily = GetXMLToken( XML_RUBY ); + aPrefix = "Ru"; + m_rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_RUBY, sFamily, + m_xRubyPropMapper, aPrefix ); + + xPropMapper = new XMLTextPropertySetMapper( TextPropMap::FRAME, true ); + m_xFramePropMapper = new XMLTextExportPropertySetMapper( xPropMapper, + GetExport() ); + + m_pSectionExport.reset( new XMLSectionExport( rExp, *this ) ); + m_pIndexMarkExport.reset( new XMLIndexMarkExport( rExp ) ); + + if( ! IsBlockMode() && + Reference<XRedlinesSupplier>( GetExport().GetModel(), UNO_QUERY ).is()) + m_pRedlineExport.reset( new XMLRedlineExport( rExp ) ); + + // The text field helper needs a pre-constructed XMLPropertyState + // to export the combined characters field. We construct that + // here, because we need the text property mapper to do it. + + // construct Any value, then find index + sal_Int32 nIndex = m_xTextPropMapper->getPropertySetMapper()->FindEntryIndex( + "", XML_NAMESPACE_STYLE, + GetXMLToken(XML_TEXT_COMBINE)); + m_pFieldExport.reset( new XMLTextFieldExport( rExp, std::make_unique<XMLPropertyState>( nIndex, uno::Any(true) ) ) ); + PushNewTextListsHelper(); +} + +XMLTextParagraphExport::~XMLTextParagraphExport() +{ + m_pRedlineExport.reset(); + m_pIndexMarkExport.reset(); + m_pSectionExport.reset(); + m_pFieldExport.reset(); +#ifdef DBG_UTIL + txtparae_bContainsIllegalCharacters = false; +#endif + PopTextListsHelper(); + SAL_WARN_IF( !maTextListsHelperStack.empty(), "xmloff", + "misusage of text lists helper stack - it is not empty. Serious defect" ); +} + +SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateShapeExtPropMapper( + SvXMLExport& rExport ) +{ + rtl::Reference < XMLPropertySetMapper > xPropMapper = + new XMLTextPropertySetMapper( TextPropMap::SHAPE, true ); + return new XMLTextExportPropertySetMapper( xPropMapper, rExport ); +} + +SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateCharExtPropMapper( + SvXMLExport& rExport) +{ + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::TEXT, true ); + return new XMLTextExportPropertySetMapper( pPropMapper, rExport ); +} + +SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateParaExtPropMapper( + SvXMLExport& rExport) +{ + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::SHAPE_PARA, true ); + return new XMLTextExportPropertySetMapper( pPropMapper, rExport ); +} + +SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateParaDefaultExtPropMapper( + SvXMLExport& rExport) +{ + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::TEXT_ADDITIONAL_DEFAULTS, true ); + return new XMLTextExportPropertySetMapper( pPropMapper, rExport ); +} + +void XMLTextParagraphExport::exportPageFrames( bool bIsProgress ) +{ + const TextContentSet& rTexts = m_pBoundFrameSets->GetTexts()->GetPageBoundContents(); + const TextContentSet& rGraphics = m_pBoundFrameSets->GetGraphics()->GetPageBoundContents(); + const TextContentSet& rEmbeddeds = m_pBoundFrameSets->GetEmbeddeds()->GetPageBoundContents(); + const TextContentSet& rShapes = m_pBoundFrameSets->GetShapes()->GetPageBoundContents(); + for(TextContentSet::const_iterator_t it = rTexts.getBegin(); + it != rTexts.getEnd(); + ++it) + exportTextFrame(*it, false/*bAutoStyles*/, bIsProgress, true); + for(TextContentSet::const_iterator_t it = rGraphics.getBegin(); + it != rGraphics.getEnd(); + ++it) + exportTextGraphic(*it, false/*bAutoStyles*/); + for(TextContentSet::const_iterator_t it = rEmbeddeds.getBegin(); + it != rEmbeddeds.getEnd(); + ++it) + exportTextEmbedded(*it, false/*bAutoStyles*/); + for(TextContentSet::const_iterator_t it = rShapes.getBegin(); + it != rShapes.getEnd(); + ++it) + exportShape(*it, false/*bAutoStyles*/); +} + +void XMLTextParagraphExport::exportFrameFrames( + bool bAutoStyles, + bool bIsProgress, + const Reference < XTextFrame >& rParentTxtFrame ) +{ + const TextContentSet* const pTexts = m_pBoundFrameSets->GetTexts()->GetFrameBoundContents(rParentTxtFrame); + if(pTexts) + for(TextContentSet::const_iterator_t it = pTexts->getBegin(); + it != pTexts->getEnd(); + ++it) + exportTextFrame(*it, bAutoStyles, bIsProgress, true); + const TextContentSet* const pGraphics = m_pBoundFrameSets->GetGraphics()->GetFrameBoundContents(rParentTxtFrame); + if(pGraphics) + for(TextContentSet::const_iterator_t it = pGraphics->getBegin(); + it != pGraphics->getEnd(); + ++it) + exportTextGraphic(*it, bAutoStyles); + const TextContentSet* const pEmbeddeds = m_pBoundFrameSets->GetEmbeddeds()->GetFrameBoundContents(rParentTxtFrame); + if(pEmbeddeds) + for(TextContentSet::const_iterator_t it = pEmbeddeds->getBegin(); + it != pEmbeddeds->getEnd(); + ++it) + exportTextEmbedded(*it, bAutoStyles); + const TextContentSet* const pShapes = m_pBoundFrameSets->GetShapes()->GetFrameBoundContents(rParentTxtFrame); + if(pShapes) + for(TextContentSet::const_iterator_t it = pShapes->getBegin(); + it != pShapes->getEnd(); + ++it) + exportShape(*it, bAutoStyles); +} + +// bookmarks, reference marks (and TOC marks) are the same except for the +// element names. We use the same method for export and it an array with +// the proper element names +const enum XMLTokenEnum lcl_XmlReferenceElements[] = { + XML_REFERENCE_MARK, XML_REFERENCE_MARK_START, XML_REFERENCE_MARK_END }; +const enum XMLTokenEnum lcl_XmlBookmarkElements[] = { + XML_BOOKMARK, XML_BOOKMARK_START, XML_BOOKMARK_END }; + +// This function replaces the text portion iteration during auto style +// collection. +void XMLTextParagraphExport::collectTextAutoStylesOptimized( bool bIsProgress ) +{ + GetExport().GetShapeExport(); // make sure the graphics styles family is added + + if (mbCollected) + return; + + const bool bAutoStyles = true; + const bool bExportContent = false; + + // Export AutoStyles: + Reference< XAutoStylesSupplier > xAutoStylesSupp( GetExport().GetModel(), UNO_QUERY ); + if ( xAutoStylesSupp.is() ) + { + Reference< XAutoStyles > xAutoStyleFamilies = xAutoStylesSupp->getAutoStyles(); + const auto collectFamily = [this, &xAutoStyleFamilies](const OUString& sName, + XmlStyleFamily nFamily) { + Any aAny = xAutoStyleFamilies->getByName( sName ); + Reference< XAutoStyleFamily > xAutoStyles = *o3tl::doAccess<Reference<XAutoStyleFamily>>(aAny); + Reference < XEnumeration > xAutoStylesEnum( xAutoStyles->createEnumeration() ); + + while ( xAutoStylesEnum->hasMoreElements() ) + { + aAny = xAutoStylesEnum->nextElement(); + Reference< XAutoStyle > xAutoStyle = *o3tl::doAccess<Reference<XAutoStyle>>(aAny); + Reference < XPropertySet > xPSet( xAutoStyle, uno::UNO_QUERY ); + Add( nFamily, xPSet, {}, true ); + } + }; + collectFamily("CharacterStyles", XmlStyleFamily::TEXT_TEXT); + collectFamily("RubyStyles", XmlStyleFamily::TEXT_RUBY); + collectFamily("ParagraphStyles", XmlStyleFamily::TEXT_PARAGRAPH); + } + + // Export Field AutoStyles: + Reference< XTextFieldsSupplier > xTextFieldsSupp( GetExport().GetModel(), UNO_QUERY ); + if ( xTextFieldsSupp.is() ) + { + Reference< XEnumerationAccess > xTextFields = xTextFieldsSupp->getTextFields(); + Reference < XEnumeration > xTextFieldsEnum( xTextFields->createEnumeration() ); + + while ( xTextFieldsEnum->hasMoreElements() ) + { + Any aAny = xTextFieldsEnum->nextElement(); + Reference< XTextField > xTextField = *o3tl::doAccess<Reference<XTextField>>(aAny); + exportTextField( xTextField, bAutoStyles, bIsProgress, + !xAutoStylesSupp.is(), nullptr ); + try + { + Reference < XPropertySet > xSet( xTextField, UNO_QUERY ); + Reference < XText > xText; + Any a = xSet->getPropertyValue("TextRange"); + a >>= xText; + if ( xText.is() ) + { + exportText( xText, true, bIsProgress, bExportContent ); + GetExport().GetTextParagraphExport() + ->collectTextAutoStyles( xText ); + } + } + catch (Exception&) + { + } + } + } + + // Export text frames: + Reference<XEnumeration> xTextFramesEnum = m_pBoundFrameSets->GetTexts()->createEnumeration(); + if(xTextFramesEnum.is()) + while(xTextFramesEnum->hasMoreElements()) + { + Reference<XTextContent> xTxtCntnt(xTextFramesEnum->nextElement(), UNO_QUERY); + if(xTxtCntnt.is()) + exportTextFrame(xTxtCntnt, bAutoStyles, bIsProgress, bExportContent); + } + + // Export graphic objects: + Reference<XEnumeration> xGraphicsEnum = m_pBoundFrameSets->GetGraphics()->createEnumeration(); + if(xGraphicsEnum.is()) + while(xGraphicsEnum->hasMoreElements()) + { + Reference<XTextContent> xTxtCntnt(xGraphicsEnum->nextElement(), UNO_QUERY); + if(xTxtCntnt.is()) + exportTextGraphic(xTxtCntnt, true); + } + + // Export embedded objects: + Reference<XEnumeration> xEmbeddedsEnum = m_pBoundFrameSets->GetEmbeddeds()->createEnumeration(); + if(xEmbeddedsEnum.is()) + while(xEmbeddedsEnum->hasMoreElements()) + { + Reference<XTextContent> xTxtCntnt(xEmbeddedsEnum->nextElement(), UNO_QUERY); + if(xTxtCntnt.is()) + exportTextEmbedded(xTxtCntnt, true); + } + + // Export shapes: + Reference<XEnumeration> xShapesEnum = m_pBoundFrameSets->GetShapes()->createEnumeration(); + if(xShapesEnum.is()) + while(xShapesEnum->hasMoreElements()) + { + Reference<XTextContent> xTxtCntnt(xShapesEnum->nextElement(), UNO_QUERY); + if(xTxtCntnt.is()) + { + Reference<XServiceInfo> xServiceInfo(xTxtCntnt, UNO_QUERY); + if( xServiceInfo->supportsService(gsShapeService)) + exportShape(xTxtCntnt, true); + } + } + + sal_Int32 nCount; + // AutoStyles for sections + Reference< XTextSectionsSupplier > xSectionsSupp( GetExport().GetModel(), UNO_QUERY ); + if ( xSectionsSupp.is() ) + { + Reference< XIndexAccess > xSections( xSectionsSupp->getTextSections(), UNO_QUERY ); + if ( xSections.is() ) + { + nCount = xSections->getCount(); + for( sal_Int32 i = 0; i < nCount; ++i ) + { + Any aAny = xSections->getByIndex( i ); + Reference< XTextSection > xSection = *o3tl::doAccess<Reference<XTextSection>>(aAny); + Reference < XPropertySet > xPSet( xSection, uno::UNO_QUERY ); + Add( XmlStyleFamily::TEXT_SECTION, xPSet ); + } + } + } + + // AutoStyles for tables (Note: suppress autostyle collection for paragraphs in exportTable) + Reference< XTextTablesSupplier > xTablesSupp( GetExport().GetModel(), UNO_QUERY ); + if ( xTablesSupp.is() ) + { + Reference< XIndexAccess > xTables( xTablesSupp->getTextTables(), UNO_QUERY ); + if ( xTables.is() ) + { + nCount = xTables->getCount(); + for( sal_Int32 i = 0; i < nCount; ++i ) + { + Any aAny = xTables->getByIndex( i ); + Reference< XTextTable > xTable = *o3tl::doAccess<Reference<XTextTable>>(aAny); + exportTable( xTable, true, true ); + } + } + } + + Reference< XNumberingRulesSupplier > xNumberingRulesSupp( GetExport().GetModel(), UNO_QUERY ); + if ( xNumberingRulesSupp.is() ) + { + Reference< XIndexAccess > xNumberingRules = xNumberingRulesSupp->getNumberingRules(); + nCount = xNumberingRules->getCount(); + // Custom outline assignment lost after re-importing sxw (#i73361#) + for( sal_Int32 i = 0; i < nCount; ++i ) + { + Reference< XIndexReplace > xNumRule( xNumberingRules->getByIndex( i ), UNO_QUERY ); + if( xNumRule.is() && xNumRule->getCount() ) + { + Reference < XNamed > xNamed( xNumRule, UNO_QUERY ); + OUString sName; + if( xNamed.is() ) + sName = xNamed->getName(); + bool bAdd = sName.isEmpty(); + if( !bAdd ) + { + Reference < XPropertySet > xNumPropSet( xNumRule, + UNO_QUERY ); + if( xNumPropSet.is() && + xNumPropSet->getPropertySetInfo() + ->hasPropertyByName( "IsAutomatic" ) ) + { + bAdd = *o3tl::doAccess<bool>(xNumPropSet->getPropertyValue( "IsAutomatic" )); + // Check on outline style (#i73361#) + if ( bAdd && + xNumPropSet->getPropertySetInfo() + ->hasPropertyByName( "NumberingIsOutline" ) ) + { + bAdd = !(*o3tl::doAccess<bool>(xNumPropSet->getPropertyValue( "NumberingIsOutline" ))); + } + } + else + { + bAdd = true; + } + } + if( bAdd ) + maListAutoPool.Add( xNumRule ); + } + } + } + mbCollected = true; +} + +void XMLTextParagraphExport::exportText( + const Reference < XText > & rText, + bool bAutoStyles, + bool bIsProgress, + bool bExportParagraph, + TextPNS eExtensionNS) +{ + if( bAutoStyles ) + GetExport().GetShapeExport(); // make sure the graphics styles family + // is added + Reference < XEnumerationAccess > xEA( rText, UNO_QUERY ); + if( ! xEA.is() ) + return; + + Reference < XEnumeration > xParaEnum(xEA->createEnumeration()); + Reference < XPropertySet > xPropertySet( rText, UNO_QUERY ); + Reference < XTextSection > xBaseSection; + + // #97718# footnotes don't supply paragraph enumerations in some cases + // This is always a bug, but at least we don't want to crash. + SAL_WARN_IF( !xParaEnum.is(), "xmloff", "We need a paragraph enumeration" ); + if( ! xParaEnum.is() ) + return; + + if (xPropertySet.is()) + { + Reference < XPropertySetInfo > xInfo ( xPropertySet->getPropertySetInfo() ); + + if( xInfo.is() ) + { + if (xInfo->hasPropertyByName( gsTextSection )) + { + xPropertySet->getPropertyValue(gsTextSection) >>= xBaseSection ; + } + } + } + + // #96530# Export redlines at start & end of XText before & after + // exporting the text content enumeration + if( !bAutoStyles && (m_pRedlineExport != nullptr) ) + m_pRedlineExport->ExportStartOrEndRedline( xPropertySet, true ); + exportTextContentEnumeration( xParaEnum, bAutoStyles, xBaseSection, + bIsProgress, bExportParagraph, nullptr, eExtensionNS ); + if( !bAutoStyles && (m_pRedlineExport != nullptr) ) + m_pRedlineExport->ExportStartOrEndRedline( xPropertySet, false ); +} + +void XMLTextParagraphExport::exportText( + const Reference < XText > & rText, + const Reference < XTextSection > & rBaseSection, + bool bAutoStyles, + bool bIsProgress, + bool bExportParagraph) +{ + if( bAutoStyles ) + GetExport().GetShapeExport(); // make sure the graphics styles family + // is added + Reference < XEnumerationAccess > xEA( rText, UNO_QUERY ); + Reference < XEnumeration > xParaEnum(xEA->createEnumeration()); + + // #98165# don't continue without a paragraph enumeration + if( ! xParaEnum.is() ) + return; + + // #96530# Export redlines at start & end of XText before & after + // exporting the text content enumeration + Reference<XPropertySet> xPropertySet; + if( !bAutoStyles && (m_pRedlineExport != nullptr) ) + { + xPropertySet.set(rText, uno::UNO_QUERY ); + m_pRedlineExport->ExportStartOrEndRedline( xPropertySet, true ); + } + exportTextContentEnumeration( xParaEnum, bAutoStyles, rBaseSection, + bIsProgress, bExportParagraph ); + if( !bAutoStyles && (m_pRedlineExport != nullptr) ) + m_pRedlineExport->ExportStartOrEndRedline( xPropertySet, false ); +} + +bool XMLTextParagraphExport::ExportListId() const +{ + return (GetExport().getExportFlags() & SvXMLExportFlags::OASIS) + && GetExport().getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012; +} + +bool XMLTextParagraphExport::ShouldSkipListId(const Reference<XTextContent>& xTextContent) +{ + if (!mpDocumentListNodes) + { + if (ExportListId()) + mpDocumentListNodes.reset(new DocumentListNodes(GetExport().GetModel())); + else + mpDocumentListNodes.reset(new DocumentListNodes({})); + } + + return mpDocumentListNodes->ShouldSkipListId(xTextContent); +} + +void XMLTextParagraphExport::exportTextContentEnumeration( + const Reference < XEnumeration > & rContEnum, + bool bAutoStyles, + const Reference < XTextSection > & rBaseSection, + bool bIsProgress, + bool bExportParagraph, + const Reference < XPropertySet > *pRangePropSet, + TextPNS eExtensionNS ) +{ + SAL_WARN_IF( !rContEnum.is(), "xmloff", "No enumeration to export!" ); + bool bHasMoreElements = rContEnum->hasMoreElements(); + if( !bHasMoreElements ) + return; + + XMLTextNumRuleInfo aPrevNumInfo; + XMLTextNumRuleInfo aNextNumInfo; + + bool bHasContent = false; + Reference<XTextSection> xCurrentTextSection(rBaseSection); + + MultiPropertySetHelper aPropSetHelper( + bAutoStyles ? aParagraphPropertyNamesAuto : + aParagraphPropertyNames ); + + bool bHoldElement = false; + Reference < XTextContent > xTxtCntnt; + while( bHoldElement || bHasMoreElements ) + { + if (bHoldElement) + { + bHoldElement = false; + } + else + { + xTxtCntnt.set(rContEnum->nextElement(), uno::UNO_QUERY); + + aPropSetHelper.resetValues(); + + } + + Reference<XServiceInfo> xServiceInfo( xTxtCntnt, UNO_QUERY ); + if( xServiceInfo->supportsService( gsParagraphService ) ) + { + if( bAutoStyles ) + { + exportListAndSectionChange( xCurrentTextSection, xTxtCntnt, + aPrevNumInfo, aNextNumInfo, + bAutoStyles ); + } + else + { + /* Pass list auto style pool to <XMLTextNumRuleInfo> instance + Pass info about request to export <text:number> element + to <XMLTextNumRuleInfo> instance (#i69627#) + */ + aNextNumInfo.Set( xTxtCntnt, + GetExport().writeOutlineStyleAsNormalListStyle(), + GetListAutoStylePool(), + GetExport().exportTextNumberElement(), + ShouldSkipListId(xTxtCntnt) ); + + exportListAndSectionChange( xCurrentTextSection, aPropSetHelper, + TEXT_SECTION, xTxtCntnt, + aPrevNumInfo, aNextNumInfo, + bAutoStyles ); + } + + // if we found a mute section: skip all section content + if (m_pSectionExport->IsMuteSection(xCurrentTextSection)) + { + // Make sure headings are exported anyway. + if( !bAutoStyles ) + m_pSectionExport->ExportMasterDocHeadingDummies(); + + while (rContEnum->hasMoreElements() && + XMLSectionExport::IsInSection( xCurrentTextSection, + xTxtCntnt, true )) + { + xTxtCntnt.set(rContEnum->nextElement(), uno::UNO_QUERY); + aPropSetHelper.resetValues(); + aNextNumInfo.Reset(); + } + // the first non-mute element still needs to be processed + bHoldElement = + ! XMLSectionExport::IsInSection( xCurrentTextSection, + xTxtCntnt, false ); + } + else + exportParagraph( xTxtCntnt, bAutoStyles, bIsProgress, + bExportParagraph, aPropSetHelper, eExtensionNS ); + bHasContent = true; + } + else if( xServiceInfo->supportsService( gsTableService ) ) + { + if( !bAutoStyles ) + { + aNextNumInfo.Reset(); + } + + exportListAndSectionChange( xCurrentTextSection, xTxtCntnt, + aPrevNumInfo, aNextNumInfo, + bAutoStyles ); + + if (! m_pSectionExport->IsMuteSection(xCurrentTextSection)) + { + // export start + end redlines (for wholly redlined tables) + if ((! bAutoStyles) && (nullptr != m_pRedlineExport)) + m_pRedlineExport->ExportStartOrEndRedline(xTxtCntnt, true); + + exportTable( xTxtCntnt, bAutoStyles, bIsProgress ); + + if ((! bAutoStyles) && (nullptr != m_pRedlineExport)) + m_pRedlineExport->ExportStartOrEndRedline(xTxtCntnt, false); + } + else if( !bAutoStyles ) + { + // Make sure headings are exported anyway. + m_pSectionExport->ExportMasterDocHeadingDummies(); + } + + bHasContent = true; + } + else if( xServiceInfo->supportsService( gsTextFrameService ) ) + { + exportTextFrame( xTxtCntnt, bAutoStyles, bIsProgress, true, pRangePropSet ); + } + else if( xServiceInfo->supportsService( gsTextGraphicService ) ) + { + exportTextGraphic( xTxtCntnt, bAutoStyles, pRangePropSet ); + } + else if( xServiceInfo->supportsService( gsTextEmbeddedService ) ) + { + exportTextEmbedded( xTxtCntnt, bAutoStyles, pRangePropSet ); + } + else if( xServiceInfo->supportsService( gsShapeService ) ) + { + exportShape( xTxtCntnt, bAutoStyles, pRangePropSet ); + } + else + { + SAL_WARN_IF( xTxtCntnt.is(), "xmloff", "unknown text content" ); + } + + if( !bAutoStyles ) + { + aPrevNumInfo = aNextNumInfo; + } + + bHasMoreElements = rContEnum->hasMoreElements(); + } + + if( bHasContent && !bAutoStyles ) + { + aNextNumInfo.Reset(); + + // close open lists and sections; no new styles + exportListAndSectionChange( xCurrentTextSection, rBaseSection, + aPrevNumInfo, aNextNumInfo, + bAutoStyles ); + } +} + +void XMLTextParagraphExport::exportParagraph( + const Reference < XTextContent > & rTextContent, + bool bAutoStyles, bool bIsProgress, bool bExportParagraph, + MultiPropertySetHelper& rPropSetHelper, TextPNS eExtensionNS) +{ + sal_Int16 nOutlineLevel = -1; + + if( bIsProgress ) + { + ProgressBarHelper *pProgress = GetExport().GetProgressBarHelper(); + pProgress->SetValue( pProgress->GetValue()+1 ); + } + + // get property set or multi property set and initialize helper + Reference<XMultiPropertySet> xMultiPropSet( rTextContent, UNO_QUERY ); + Reference<XPropertySet> xPropSet( rTextContent, UNO_QUERY ); + + // check for supported properties + if( !rPropSetHelper.checkedProperties() ) + rPropSetHelper.hasProperties( xPropSet->getPropertySetInfo() ); + +// if( xMultiPropSet.is() ) +// rPropSetHelper.getValues( xMultiPropSet ); +// else +// rPropSetHelper.getValues( xPropSet ); + + if( bExportParagraph ) + { + if( bAutoStyles ) + { + Add( XmlStyleFamily::TEXT_PARAGRAPH, rPropSetHelper, xPropSet ); + } + else + { + // xml:id for RDF metadata + GetExport().AddAttributeXmlId(rTextContent); + GetExport().AddAttributesRDFa(rTextContent); + + OUString sStyle; + if( rPropSetHelper.hasProperty( PARA_STYLE_NAME ) ) + { + if( xMultiPropSet.is() ) + rPropSetHelper.getValue( PARA_STYLE_NAME, + xMultiPropSet ) >>= sStyle; + else + rPropSetHelper.getValue( PARA_STYLE_NAME, + xPropSet ) >>= sStyle; + } + + if( rTextContent.is() ) + { + const OUString& rIdentifier = GetExport().getInterfaceToIdentifierMapper().getIdentifier( rTextContent ); + if( !rIdentifier.isEmpty() ) + { + // FIXME: this is just temporary until EditEngine + // paragraphs implement XMetadatable. + // then that must be used and not the mapper, because + // when both can be used we get two xml:id! + uno::Reference<rdf::XMetadatable> const xMeta(rTextContent, + uno::UNO_QUERY); + OSL_ENSURE(!xMeta.is(), "paragraph that implements " + "XMetadatable used in interfaceToIdentifierMapper?"); + GetExport().AddAttributeIdLegacy(XML_NAMESPACE_TEXT, + rIdentifier); + } + } + + OUString sAutoStyle = Find( XmlStyleFamily::TEXT_PARAGRAPH, xPropSet, sStyle ); + if ( sAutoStyle.isEmpty() ) + sAutoStyle = sStyle; + if( !sAutoStyle.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sAutoStyle ) ); + + if( rPropSetHelper.hasProperty( PARA_CONDITIONAL_STYLE_NAME ) ) + { + OUString sCondStyle; + if( xMultiPropSet.is() ) + rPropSetHelper.getValue( PARA_CONDITIONAL_STYLE_NAME, + xMultiPropSet ) >>= sCondStyle; + else + rPropSetHelper.getValue( PARA_CONDITIONAL_STYLE_NAME, + xPropSet ) >>= sCondStyle; + if( sCondStyle != sStyle ) + { + sCondStyle = Find( XmlStyleFamily::TEXT_PARAGRAPH, xPropSet, + sCondStyle ); + if( !sCondStyle.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_COND_STYLE_NAME, + GetExport().EncodeStyleName( sCondStyle ) ); + } + } + + if( rPropSetHelper.hasProperty( PARA_OUTLINE_LEVEL ) ) + { + if( xMultiPropSet.is() ) + rPropSetHelper.getValue( PARA_OUTLINE_LEVEL, + xMultiPropSet ) >>= nOutlineLevel; + else + rPropSetHelper.getValue( PARA_OUTLINE_LEVEL, + xPropSet ) >>= nOutlineLevel; + + if( 0 < nOutlineLevel ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_OUTLINE_LEVEL, + OUString::number( sal_Int32( nOutlineLevel) ) ); + + if ( rPropSetHelper.hasProperty( PARA_OUTLINE_CONTENT_VISIBLE ) ) + { + uno::Sequence<beans::PropertyValue> propList; + bool bIsOutlineContentVisible = true; + if( xMultiPropSet.is() ) + rPropSetHelper.getValue( + PARA_OUTLINE_CONTENT_VISIBLE, xMultiPropSet ) >>= propList; + else + rPropSetHelper.getValue( + PARA_OUTLINE_CONTENT_VISIBLE, xPropSet ) >>= propList; + for (const auto& rProp : std::as_const(propList)) + { + OUString propName = rProp.Name; + if (propName == "OutlineContentVisibleAttr") + { + rProp.Value >>= bIsOutlineContentVisible; + break; + } + } + if (!bIsOutlineContentVisible) + { + GetExport().AddAttribute( XML_NAMESPACE_LO_EXT, + XML_OUTLINE_CONTENT_VISIBLE, + XML_FALSE); + } + } + + if( rPropSetHelper.hasProperty( NUMBERING_IS_NUMBER ) ) + { + bool bIsNumber = false; + if( xMultiPropSet.is() ) + rPropSetHelper.getValue( + NUMBERING_IS_NUMBER, xMultiPropSet ) >>= bIsNumber; + else + rPropSetHelper.getValue( + NUMBERING_IS_NUMBER, xPropSet ) >>= bIsNumber; + + OUString sListStyleName; + if( xMultiPropSet.is() ) + rPropSetHelper.getValue( + PARA_NUMBERING_STYLENAME, xMultiPropSet ) >>= sListStyleName; + else + rPropSetHelper.getValue( + PARA_NUMBERING_STYLENAME, xPropSet ) >>= sListStyleName; + + bool bAssignedtoOutlineStyle = false; + { + Reference< XChapterNumberingSupplier > xCNSupplier( GetExport().GetModel(), UNO_QUERY ); + + if (xCNSupplier.is()) + { + Reference< XIndexReplace > xNumRule ( xCNSupplier->getChapterNumberingRules() ); + SAL_WARN_IF( !xNumRule.is(), "xmloff", "no chapter numbering rules" ); + + if (xNumRule.is()) + { + Reference< XPropertySet > xNumRulePropSet( xNumRule, UNO_QUERY ); + OUString sOutlineName; + xNumRulePropSet->getPropertyValue( + "Name" ) >>= sOutlineName; + bAssignedtoOutlineStyle = ( sListStyleName == sOutlineName ); + } + } + } + + if( ! bIsNumber && bAssignedtoOutlineStyle ) + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_IS_LIST_HEADER, + XML_TRUE ); + } + + { + bool bIsRestartNumbering = false; + + Reference< XPropertySetInfo > + xPropSetInfo(xMultiPropSet.is() ? + xMultiPropSet->getPropertySetInfo(): + xPropSet->getPropertySetInfo()); + + if (xPropSetInfo-> + hasPropertyByName("ParaIsNumberingRestart")) + { + xPropSet->getPropertyValue("ParaIsNumberingRestart") + >>= bIsRestartNumbering; + } + + if (bIsRestartNumbering) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_RESTART_NUMBERING, + XML_TRUE); + + if (xPropSetInfo-> + hasPropertyByName("NumberingStartValue")) + { + sal_Int32 nStartValue = 0; + + xPropSet->getPropertyValue("NumberingStartValue") + >>= nStartValue; + + GetExport(). + AddAttribute(XML_NAMESPACE_TEXT, + XML_START_VALUE, + OUString::number(nStartValue)); + } + } + } + } + } + } + + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + try + { + // ParaMarkerAutoStyleSpan is a hidden property, just to pass the autostyle here + // See SwXParagraph::Impl::GetPropertyValues_Impl + css::uno::Any aVal = xPropSet->getPropertyValue("ParaMarkerAutoStyleSpan"); + if (auto xFakeSpan = aVal.query<css::beans::XPropertySet>()) + { + if (bAutoStyles) + { + Add(XmlStyleFamily::TEXT_TEXT, xFakeSpan); + } + else + { + bool bIsUICharStyle, bHasAutoStyle; + OUString sStyle = FindTextStyle(xFakeSpan, bIsUICharStyle, bHasAutoStyle); + if (!sStyle.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_MARKER_STYLE_NAME, + sStyle); + } + } + } + } + catch (const css::beans::UnknownPropertyException&) + { + // No problem + } + } + } + + Reference < XEnumerationAccess > xEA( rTextContent, UNO_QUERY ); + Reference < XEnumeration > xTextEnum = xEA->createEnumeration(); + const bool bHasPortions = xTextEnum.is(); + + Reference < XEnumeration> xContentEnum; + Reference < XContentEnumerationAccess > xCEA( rTextContent, UNO_QUERY ); + if( xCEA.is() ) + xContentEnum.set(xCEA->createContentEnumeration( gsTextContentService )); + const bool bHasContentEnum = xContentEnum.is() && + xContentEnum->hasMoreElements(); + + Reference < XTextSection > xSection; + if( bHasContentEnum ) + { + // For the auto styles, the multi property set helper is only used + // if hard attributes are existing. Therefore, it seems to be a better + // strategy to have the TextSection property separate, because otherwise + // we always retrieve the style names even if they are not required. + if( bAutoStyles ) + { + if( xPropSet->getPropertySetInfo()->hasPropertyByName( gsTextSection ) ) + { + xSection.set(xPropSet->getPropertyValue( gsTextSection ), uno::UNO_QUERY); + } + } + else + { + if( rPropSetHelper.hasProperty( TEXT_SECTION ) ) + { + xSection.set(rPropSetHelper.getValue( TEXT_SECTION ), uno::UNO_QUERY); + } + } + } + + bool bPrevCharIsSpace(true); // true because whitespace at start is ignored + + if( bAutoStyles ) + { + if( bHasContentEnum ) + exportTextContentEnumeration( + xContentEnum, bAutoStyles, xSection, + bIsProgress ); + if ( bHasPortions ) + { + exportTextRangeEnumeration(xTextEnum, bAutoStyles, bIsProgress, bPrevCharIsSpace); + } + } + else + { + enum XMLTokenEnum eElem = + 0 < nOutlineLevel ? XML_H : XML_P; + SvXMLElementExport aElem( GetExport(), eExtensionNS == TextPNS::EXTENSION ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_TEXT, eElem, + true, false ); + if( bHasContentEnum ) + { + exportTextContentEnumeration( + xContentEnum, bAutoStyles, xSection, + bIsProgress ); + } + exportTextRangeEnumeration(xTextEnum, bAutoStyles, bIsProgress, bPrevCharIsSpace); + } +} + +void XMLTextParagraphExport::exportTextRangeEnumeration( + const Reference < XEnumeration > & rTextEnum, + bool bAutoStyles, bool bIsProgress, + bool & rPrevCharIsSpace) +{ + static const char sFieldMarkName[] = "__FieldMark_"; + + /* This is used for exporting to strict OpenDocument 1.2, in which case traditional + * bookmarks are used instead of fieldmarks. */ + FieldmarkType openFieldMark = NONE; + + std::optional<SvXMLElementExport> oTextA; + HyperlinkData aHyperlinkData; + + while( rTextEnum->hasMoreElements() ) + { + Reference<XPropertySet> xPropSet(rTextEnum->nextElement(), UNO_QUERY); + Reference < XTextRange > xTxtRange(xPropSet, uno::UNO_QUERY); + Reference<XPropertySetInfo> xPropInfo(xPropSet->getPropertySetInfo()); + + if (!bAutoStyles) + { + if (HyperlinkData aNewHyperlinkData(xPropSet); aNewHyperlinkData != aHyperlinkData) + { + aHyperlinkData = aNewHyperlinkData; + oTextA.reset(); + if (aHyperlinkData.addHyperlinkAttributes(GetExport())) + { + oTextA.emplace(GetExport(), true, XML_NAMESPACE_TEXT, XML_A, false, false); + aHyperlinkData.exportEvents(GetExport()); + } + } + } + + if (xPropInfo->hasPropertyByName(gsTextPortionType)) + { + OUString sType; + xPropSet->getPropertyValue(gsTextPortionType) >>= sType; + + if( sType == gsText) + { + exportTextRange( xTxtRange, bAutoStyles, + rPrevCharIsSpace, openFieldMark); + } + else if( sType == gsTextField) + { + exportTextField(xTxtRange, bAutoStyles, bIsProgress, &rPrevCharIsSpace); + } + else if ( sType == "Annotation" ) + { + exportTextField(xTxtRange, bAutoStyles, bIsProgress, &rPrevCharIsSpace); + } + else if ( sType == "AnnotationEnd" ) + { + if (!bAutoStyles) + { + Reference<XNamed> xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY); + const OUString& rName = xBookmark->getName(); + if (!rName.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_OFFICE, XML_NAME, rName); + } + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_OFFICE, XML_ANNOTATION_END, false, false ); + } + } + else if( sType == gsFrame ) + { + Reference < XEnumeration> xContentEnum; + Reference < XContentEnumerationAccess > xCEA( xTxtRange, + UNO_QUERY ); + if( xCEA.is() ) + xContentEnum.set(xCEA->createContentEnumeration( + gsTextContentService )); + // frames are never in sections + Reference<XTextSection> xSection; + if( xContentEnum.is() ) + exportTextContentEnumeration( xContentEnum, + bAutoStyles, + xSection, bIsProgress, true, + &xPropSet ); + + } + else if (sType == gsFootnote) + { + exportTextFootnote(xPropSet, + xTxtRange->getString(), + bAutoStyles, bIsProgress ); + } + else if (sType == gsBookmark) + { + exportTextMark(xPropSet, + gsBookmark, + lcl_XmlBookmarkElements, + bAutoStyles); + } + else if (sType == gsReferenceMark) + { + exportTextMark(xPropSet, + gsReferenceMark, + lcl_XmlReferenceElements, + bAutoStyles); + } + else if (sType == gsDocumentIndexMark) + { + m_pIndexMarkExport->ExportIndexMark(xPropSet, bAutoStyles); + } + else if (sType == gsRedline) + { + if (nullptr != m_pRedlineExport) + m_pRedlineExport->ExportChange(xPropSet, bAutoStyles); + } + else if (sType == gsRuby) + { + exportRuby(xPropSet, bAutoStyles); + } + else if (sType == "InContentMetadata") + { + exportMeta(xPropSet, bAutoStyles, bIsProgress, rPrevCharIsSpace); + } + else if (sType == "ContentControl") + { + ExportContentControl(xPropSet, bAutoStyles, bIsProgress, rPrevCharIsSpace); + } + else if (sType == gsTextFieldStart) + { + Reference< css::text::XFormField > xFormField(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY); + + /* As of now, textmarks are a proposed extension to the OpenDocument standard. */ + if (!bAutoStyles) + { + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + Reference<XNamed> xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY); + if (xBookmark.is()) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, xBookmark->getName()); + } + + if (xFormField.is()) + { + GetExport().AddAttribute(XML_NAMESPACE_FIELD, XML_TYPE, xFormField->getFieldType()); + } + + GetExport().StartElement(XML_NAMESPACE_FIELD, XML_FIELDMARK_START, false); + if (xFormField.is()) + { + FieldParamExporter(&GetExport(), xFormField->getParameters()).Export(); + } + GetExport().EndElement(XML_NAMESPACE_FIELD, XML_FIELDMARK_START, false); + } + /* The OpenDocument standard does not include support for TextMarks for now, so use bookmarks instead. */ + else + { + if (xFormField.is()) + { + OUString sName; + Reference< css::container::XNameAccess > xParameters = xFormField->getParameters(); + if (xParameters.is() && xParameters->hasByName("Name")) + { + const Any aValue = xParameters->getByName("Name"); + aValue >>= sName; + } + if (sName.isEmpty()) + { // name attribute is mandatory, so have to pull a + // rabbit out of the hat here + sName = sFieldMarkName + OUString::number( + m_xImpl->AddFieldMarkStart(xFormField)); + } + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, + sName); + SvXMLElementExport aElem( GetExport(), !bAutoStyles, + XML_NAMESPACE_TEXT, XML_BOOKMARK_START, + false, false ); + const OUString sFieldType = xFormField->getFieldType(); + if (sFieldType == ODF_FORMTEXT) + { + openFieldMark = TEXT; + } + else if (sFieldType == ODF_FORMCHECKBOX) + { + openFieldMark = CHECK; + } + else + { + openFieldMark = NONE; + } + } + } + } + } + else if (sType == gsTextFieldSep) + { + if (!bAutoStyles) + { + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + SvXMLElementExport aElem( GetExport(), !bAutoStyles, + XML_NAMESPACE_FIELD, XML_FIELDMARK_SEPARATOR, + false, false ); + } + } + } + else if (sType == gsTextFieldEnd) + { + if (!bAutoStyles) + { + Reference< css::text::XFormField > xFormField(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY); + + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + SvXMLElementExport aElem( GetExport(), !bAutoStyles, + XML_NAMESPACE_FIELD, XML_FIELDMARK_END, + false, false ); + } + else + { + if (xFormField.is()) + { + OUString sName; + Reference< css::container::XNameAccess > xParameters = xFormField->getParameters(); + if (xParameters.is() && xParameters->hasByName("Name")) + { + const Any aValue = xParameters->getByName("Name"); + aValue >>= sName; + } + if (sName.isEmpty()) + { // name attribute is mandatory, so have to pull a + // rabbit out of the hat here + sName = sFieldMarkName + OUString::number( + m_xImpl->GetFieldMarkIndex(xFormField)); + } + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, + sName); + SvXMLElementExport aElem( GetExport(), !bAutoStyles, + XML_NAMESPACE_TEXT, XML_BOOKMARK_END, + false, false ); + } + } + } + } + else if (sType == gsTextFieldStartEnd) + { + if (!bAutoStyles) + { + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + Reference<XNamed> xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY); + if (xBookmark.is()) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, xBookmark->getName()); + } + Reference< css::text::XFormField > xFormField(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY); + if (xFormField.is()) + { + GetExport().AddAttribute(XML_NAMESPACE_FIELD, XML_TYPE, xFormField->getFieldType()); + } + GetExport().StartElement(XML_NAMESPACE_FIELD, XML_FIELDMARK, false); + if (xFormField.is()) + { + FieldParamExporter(&GetExport(), xFormField->getParameters()).Export(); + } + GetExport().EndElement(XML_NAMESPACE_FIELD, XML_FIELDMARK, false); + } + else + { + Reference<XNamed> xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY); + if (xBookmark.is()) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, xBookmark->getName()); + SvXMLElementExport aElem( GetExport(), !bAutoStyles, + XML_NAMESPACE_TEXT, XML_BOOKMARK, + false, false ); + } + } + } + } + else if (sType == gsSoftPageBreak) + { + if (!bAutoStyles) + exportSoftPageBreak(); + } + else if (sType == "LineBreak") + { + if (!bAutoStyles) + exportTextLineBreak(xPropSet); + } + else { + OSL_FAIL("unknown text portion type"); + } + } + else + { + Reference<XServiceInfo> xServiceInfo( xTxtRange, UNO_QUERY ); + if( xServiceInfo->supportsService( gsTextFieldService ) ) + { + exportTextField(xTxtRange, bAutoStyles, bIsProgress, &rPrevCharIsSpace); + } + else + { + // no TextPortionType property -> non-Writer app -> text + exportTextRange(xTxtRange, bAutoStyles, rPrevCharIsSpace, openFieldMark); + } + } + } + +// now that there are nested enumerations for meta(-field), this may be valid! +// SAL_WARN_IF( bOpenRuby, "xmloff", "Red Alert: Ruby still open!" ); +} + +void XMLTextParagraphExport::exportTable( + const Reference < XTextContent > &, + bool /*bAutoStyles*/, bool /*bIsProgress*/ ) +{ +} + +void XMLTextParagraphExport::exportTextField( + const Reference < XTextRange > & rTextRange, + bool bAutoStyles, bool bIsProgress, bool *const pPrevCharIsSpace) +{ + Reference < XPropertySet > xPropSet( rTextRange, UNO_QUERY ); + // non-Writer apps need not support Property TextField, so test first + if (!xPropSet->getPropertySetInfo()->hasPropertyByName( gsTextField )) + return; + + Reference < XTextField > xTxtFld(xPropSet->getPropertyValue( gsTextField ), uno::UNO_QUERY); + SAL_WARN_IF( !xTxtFld.is(), "xmloff", "text field missing" ); + if( xTxtFld.is() ) + { + exportTextField(xTxtFld, bAutoStyles, bIsProgress, true, pPrevCharIsSpace); + } + else + { + // write only characters + GetExport().Characters(rTextRange->getString()); + } +} + +void XMLTextParagraphExport::exportTextField( + const Reference < XTextField > & xTextField, + const bool bAutoStyles, const bool bIsProgress, + const bool bRecursive, bool *const pPrevCharIsSpace) +{ + if ( bAutoStyles ) + { + m_pFieldExport->ExportFieldAutoStyle( xTextField, bIsProgress, + bRecursive ); + } + else + { + assert(pPrevCharIsSpace); + m_pFieldExport->ExportField(xTextField, bIsProgress, *pPrevCharIsSpace); + } +} + +void XMLTextParagraphExport::exportSoftPageBreak() +{ + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + XML_SOFT_PAGE_BREAK, false, + false ); +} + +void XMLTextParagraphExport::exportTextLineBreak( + const uno::Reference<beans::XPropertySet>& xPropSet) +{ + static const XMLTokenEnum aLineBreakClears[] = { + XML_NONE, + XML_LEFT, + XML_RIGHT, + XML_ALL, + }; + + uno::Reference<text::XTextContent> xLineBreak; + xPropSet->getPropertyValue("LineBreak") >>= xLineBreak; + if (!xLineBreak.is()) + { + return; + } + + uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY); + if (!xLineBreakProps.is()) + { + return; + } + + sal_Int16 eClear{}; + xLineBreakProps->getPropertyValue("Clear") >>= eClear; + if (eClear >= 0 && o3tl::make_unsigned(eClear) < SAL_N_ELEMENTS(aLineBreakClears)) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CLEAR, + GetXMLToken(aLineBreakClears[eClear])); + } + SvXMLElementExport aElem(GetExport(), XML_NAMESPACE_TEXT, XML_LINE_BREAK, + /*bIgnWSOutside=*/false, /*bIgnWSInside=*/false); +} + +void XMLTextParagraphExport::exportTextMark( + const Reference<XPropertySet> & rPropSet, + const OUString& rProperty, + const ::xmloff::token::XMLTokenEnum pElements[], + bool bAutoStyles) +{ + // mib said: "Hau wech!" + + // (Originally, I'd export a span element in case the (book|reference)mark + // was formatted. This actually makes a difference in case some pervert + // sets a point reference mark in the document and, say, formats it bold. + // This basically meaningless formatting will now been thrown away + // (aka cleaned up), since mib said: ... dvo + + if (bAutoStyles) + return; + + // name element + Reference<XNamed> xName(rPropSet->getPropertyValue(rProperty), UNO_QUERY); + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, + xName->getName()); + + // start, end, or point-reference? + sal_Int8 nElement; + if( *o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsIsCollapsed)) ) + { + nElement = 0; + } + else + { + nElement = *o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsIsStart)) ? 1 : 2; + } + + // bookmark, bookmark-start: xml:id and RDFa for RDF metadata + if( nElement < 2 ) { + GetExport().AddAttributeXmlId(xName); + const uno::Reference<text::XTextContent> xTextContent( + xName, uno::UNO_QUERY_THROW); + GetExport().AddAttributesRDFa(xTextContent); + } + + // bookmark-start: add attributes hidden and condition + if (nElement == 1) + { + Reference<XPropertySet> bkmkProps(rPropSet->getPropertyValue(rProperty), UNO_QUERY); + Reference<XPropertySetInfo> bkmkPropInfo = bkmkProps->getPropertySetInfo(); + OUString sHidden("BookmarkHidden"); + if (bkmkPropInfo->hasPropertyByName(sHidden)) + { + bool bHidden = false; + bkmkProps->getPropertyValue(sHidden) >>= bHidden; + if (bHidden) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, "hidden", "true"); + OUString sCondition("BookmarkCondition"); + if (bkmkPropInfo->hasPropertyByName(sCondition)) + { + OUString sBookmarkCondition; + bkmkProps->getPropertyValue(sCondition) >>= sBookmarkCondition; + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, "condition", sBookmarkCondition); + } + } + } + } + + // export element + assert(pElements != nullptr); + assert(0 <= nElement && nElement <= 2); + SvXMLElementExport aElem(GetExport(), + XML_NAMESPACE_TEXT, pElements[nElement], + false, false); + // else: no styles. (see above) +} + +static bool lcl_txtpara_isBoundAsChar( + const Reference < XPropertySet > & rPropSet, + const Reference < XPropertySetInfo > & rPropSetInfo ) +{ + bool bIsBoundAsChar = false; + OUString sAnchorType( "AnchorType" ); + if( rPropSetInfo->hasPropertyByName( sAnchorType ) ) + { + TextContentAnchorType eAnchor; + rPropSet->getPropertyValue( sAnchorType ) >>= eAnchor; + bIsBoundAsChar = TextContentAnchorType_AS_CHARACTER == eAnchor; + } + + return bIsBoundAsChar; +} + +XMLShapeExportFlags XMLTextParagraphExport::addTextFrameAttributes( + const Reference < XPropertySet >& rPropSet, + bool bShape, + basegfx::B2DPoint* pCenter, + OUString* pMinHeightValue, + OUString* pMinWidthValue) +{ + XMLShapeExportFlags nShapeFeatures = SEF_DEFAULT; + + // draw:name (#97662#: not for shapes, since those names will be + // treated in the shape export) + if( !bShape ) + { + Reference < XNamed > xNamed( rPropSet, UNO_QUERY ); + if( xNamed.is() ) + { + OUString sName( xNamed->getName() ); + if( !sName.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, + xNamed->getName() ); + } + } + + OUStringBuffer sValue; + + // text:anchor-type + TextContentAnchorType eAnchor = TextContentAnchorType_AT_PARAGRAPH; + rPropSet->getPropertyValue( gsAnchorType ) >>= eAnchor; + { + XMLAnchorTypePropHdl aAnchorTypeHdl; + OUString sTmp; + aAnchorTypeHdl.exportXML( sTmp, uno::Any(eAnchor), + GetExport().GetMM100UnitConverter() ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_ANCHOR_TYPE, sTmp ); + } + + // text:anchor-page-number + if( TextContentAnchorType_AT_PAGE == eAnchor ) + { + sal_Int16 nPage = 0; + rPropSet->getPropertyValue( gsAnchorPageNo ) >>= nPage; + SAL_WARN_IF(nPage <= 0, "xmloff", + "ERROR: writing invalid anchor-page-number 0"); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_ANCHOR_PAGE_NUMBER, + OUString::number( nPage ) ); + } + else + { + nShapeFeatures |= XMLShapeExportFlags::NO_WS; + } + + // OD 2004-06-01 #i27691# - correction: no export of svg:x, if object + // is anchored as-character. + if ( !bShape && + eAnchor != TextContentAnchorType_AS_CHARACTER ) + { + // svg:x + sal_Int16 nHoriOrient = HoriOrientation::NONE; + rPropSet->getPropertyValue( gsHoriOrient ) >>= nHoriOrient; + if( HoriOrientation::NONE == nHoriOrient ) + { + sal_Int32 nPos = 0; + rPropSet->getPropertyValue( gsHoriOrientPosition ) >>= nPos; + GetExport().GetMM100UnitConverter().convertMeasureToXML( + sValue, nPos ); + GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_X, + sValue.makeStringAndClear() ); + if(nullptr != pCenter) + { + // add left edge to Center + pCenter->setX(pCenter->getX() + nPos); + } + } + } + else if( TextContentAnchorType_AS_CHARACTER == eAnchor ) + nShapeFeatures = (nShapeFeatures & ~XMLShapeExportFlags::X); + + if( !bShape || TextContentAnchorType_AS_CHARACTER == eAnchor ) + { + // svg:y + sal_Int16 nVertOrient = VertOrientation::NONE; + rPropSet->getPropertyValue( gsVertOrient ) >>= nVertOrient; + if( VertOrientation::NONE == nVertOrient ) + { + sal_Int32 nPos = 0; + rPropSet->getPropertyValue( gsVertOrientPosition ) >>= nPos; + GetExport().GetMM100UnitConverter().convertMeasureToXML( + sValue, nPos ); + GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_Y, + sValue.makeStringAndClear() ); + if(nullptr != pCenter) + { + // add top edge to Center + pCenter->setY(pCenter->getY() + nPos); + } + } + if( bShape ) + nShapeFeatures = (nShapeFeatures & ~XMLShapeExportFlags::Y); + } + + Reference< XPropertySetInfo > xPropSetInfo(rPropSet->getPropertySetInfo()); + + bool bSyncWidth = false; + if (xPropSetInfo->hasPropertyByName(gsIsSyncWidthToHeight)) + { + bSyncWidth = *o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsIsSyncWidthToHeight)); + } + sal_Int16 nRelWidth = 0; + if (!bSyncWidth && xPropSetInfo->hasPropertyByName(gsRelativeWidth)) + { + rPropSet->getPropertyValue(gsRelativeWidth) >>= nRelWidth; + } + bool bSyncHeight = false; + if (xPropSetInfo->hasPropertyByName(gsIsSyncHeightToWidth)) + { + bSyncHeight = *o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsIsSyncHeightToWidth)); + } + sal_Int16 nRelHeight = 0; + if (!bSyncHeight && xPropSetInfo->hasPropertyByName(gsRelativeHeight)) + { + rPropSet->getPropertyValue(gsRelativeHeight) >>= nRelHeight; + } + awt::Size aLayoutSize; + if ((nRelWidth > 0 || nRelHeight > 0) && xPropSetInfo->hasPropertyByName("LayoutSize")) + { + rPropSet->getPropertyValue("LayoutSize") >>= aLayoutSize; + } + + bool bUseLayoutSize = true; + if (bSyncWidth && bSyncHeight) + { + // This is broken, width depends on height and height depends on width. Don't use the + // invalid layout size we got. + bUseLayoutSize = false; + } + if (aLayoutSize.Width <= 0 || aLayoutSize.Height <= 0) + { + // This is broken, Writer frames have a minimal size, see MINFLY. + bUseLayoutSize = false; + } + + // svg:width + sal_Int16 nWidthType = SizeType::FIX; + if( xPropSetInfo->hasPropertyByName( gsWidthType ) ) + { + rPropSet->getPropertyValue( gsWidthType ) >>= nWidthType; + } + if( xPropSetInfo->hasPropertyByName( gsWidth ) ) + { + sal_Int32 nWidth = 0; + // VAR size will be written as zero min-size + if( SizeType::VARIABLE != nWidthType ) + { + rPropSet->getPropertyValue( gsWidth ) >>= nWidth; + } + GetExport().GetMM100UnitConverter().convertMeasureToXML(sValue, nWidth); + if( SizeType::FIX != nWidthType ) + { + assert(pMinWidthValue); + if (pMinWidthValue) + { + *pMinWidthValue = sValue.makeStringAndClear(); + } + } + else + { + if ((nRelWidth > 0 || bSyncWidth) && bUseLayoutSize) + { + // Relative width: write the layout size for the fallback width. + sValue.setLength(0); + GetExport().GetMM100UnitConverter().convertMeasureToXML(sValue, aLayoutSize.Width); + } + + GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_WIDTH, + sValue.makeStringAndClear() ); + if(nullptr != pCenter) + { + // add half width to Center + pCenter->setX(pCenter->getX() + (0.5 * nWidth)); + } + } + } + if( xPropSetInfo->hasPropertyByName( gsIsSyncWidthToHeight ) ) + { + if( bSyncWidth ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_WIDTH, + XML_SCALE ); + } + if( !bSyncWidth && xPropSetInfo->hasPropertyByName( gsRelativeWidth ) ) + { + SAL_WARN_IF( nRelWidth < 0 || nRelWidth > 254, "xmloff", + "Got illegal relative width from API" ); + if( nRelWidth > 0 ) + { + ::sax::Converter::convertPercent( sValue, nRelWidth ); + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_WIDTH, + sValue.makeStringAndClear() ); + } + } + + // svg:height, fo:min-height or style:rel-height + sal_Int16 nSizeType = SizeType::FIX; + if( xPropSetInfo->hasPropertyByName( gsSizeType ) ) + { + rPropSet->getPropertyValue( gsSizeType ) >>= nSizeType; + } + if( xPropSetInfo->hasPropertyByName( gsHeight ) ) + { + sal_Int32 nHeight = 0; + if( SizeType::VARIABLE != nSizeType ) + { + rPropSet->getPropertyValue( gsHeight ) >>= nHeight; + } + GetExport().GetMM100UnitConverter().convertMeasureToXML( sValue, + nHeight ); + if( SizeType::FIX != nSizeType && 0==nRelHeight && !bSyncHeight && + pMinHeightValue ) + { + *pMinHeightValue = sValue.makeStringAndClear(); + } + else + { + if ((nRelHeight > 0 || bSyncHeight) && bUseLayoutSize) + { + // Relative height: write the layout size for the fallback height. + sValue.setLength(0); + GetExport().GetMM100UnitConverter().convertMeasureToXML(sValue, aLayoutSize.Height); + } + + GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_HEIGHT, + sValue.makeStringAndClear() ); + if(nullptr != pCenter) + { + // add half height to Center + pCenter->setY(pCenter->getY() + (0.5 * nHeight)); + } + } + } + if( bSyncHeight ) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_HEIGHT, + SizeType::MIN == nSizeType ? XML_SCALE_MIN : XML_SCALE ); + + } + else if( nRelHeight > 0 ) + { + ::sax::Converter::convertPercent( sValue, nRelHeight ); + if( SizeType::MIN == nSizeType ) + { + assert(pMinHeightValue); + if (pMinHeightValue) + { + *pMinHeightValue = sValue.makeStringAndClear(); + } + } + else + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_HEIGHT, + sValue.makeStringAndClear() ); + } + + OUString sZOrder( "ZOrder" ); + if( xPropSetInfo->hasPropertyByName( sZOrder ) ) + { + sal_Int32 nZIndex = 0; + rPropSet->getPropertyValue( sZOrder ) >>= nZIndex; + if( -1 != nZIndex ) + { + GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_ZINDEX, + OUString::number( nZIndex ) ); + } + } + + if (xPropSetInfo->hasPropertyByName("IsSplitAllowed") + && rPropSet->getPropertyValue("IsSplitAllowed").get<bool>()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_MAY_BREAK_BETWEEN_PAGES, XML_TRUE); + } + + return nShapeFeatures; +} + +void XMLTextParagraphExport::exportAnyTextFrame( + const Reference < XTextContent > & rTxtCntnt, + FrameType eType, + bool bAutoStyles, + bool bIsProgress, + bool bExportContent, + const Reference < XPropertySet > *pRangePropSet) +{ + Reference < XPropertySet > xPropSet( rTxtCntnt, UNO_QUERY ); + + if( bAutoStyles ) + { + if( FrameType::Embedded == eType ) + _collectTextEmbeddedAutoStyles( xPropSet ); + // No text frame style for shapes (#i28745#) + else if ( FrameType::Shape != eType ) + Add( XmlStyleFamily::TEXT_FRAME, xPropSet ); + + if( pRangePropSet && lcl_txtpara_isBoundAsChar( xPropSet, + xPropSet->getPropertySetInfo() ) ) + Add( XmlStyleFamily::TEXT_TEXT, *pRangePropSet ); + + switch( eType ) + { + case FrameType::Text: + { + // frame bound frames + if ( bExportContent ) + { + Reference < XTextFrame > xTxtFrame( rTxtCntnt, UNO_QUERY ); + bool bAlreadySeen = !maFrameRecurseGuard.insert(xTxtFrame).second; + if (bAlreadySeen) + { + SAL_WARN("xmloff", "loop in frame export, ditching"); + } + else + { + comphelper::ScopeGuard const g([this, xTxtFrame]() { + maFrameRecurseGuard.erase(xTxtFrame); + }); + Reference < XText > xTxt(xTxtFrame->getText()); + exportFrameFrames( true, bIsProgress, xTxtFrame ); + exportText( xTxt, bAutoStyles, bIsProgress, true ); + } + } + } + break; + case FrameType::Shape: + { + Reference < XShape > xShape( rTxtCntnt, UNO_QUERY ); + bool bAlreadySeen = !maShapeRecurseGuard.insert(xShape).second; + if (bAlreadySeen) + { + SAL_WARN("xmloff", "loop in shape export, ditching"); + } + else + { + comphelper::ScopeGuard const g([this, xShape]() { + maShapeRecurseGuard.erase(xShape); + }); + GetExport().GetShapeExport()->collectShapeAutoStyles( xShape ); + } + } + break; + default: + break; + } + } + else + { + Reference< XPropertySetInfo > xPropSetInfo(xPropSet->getPropertySetInfo()); + { + bool bAddCharStyles = pRangePropSet && + lcl_txtpara_isBoundAsChar( xPropSet, xPropSetInfo ); + + bool bIsUICharStyle; + bool bHasAutoStyle = false; + + OUString sStyle; + + if( bAddCharStyles ) + sStyle = FindTextStyle( *pRangePropSet, bIsUICharStyle, bHasAutoStyle ); + else + bIsUICharStyle = false; + + bool bDoSomething = bIsUICharStyle + && m_aCharStyleNamesPropInfoCache.hasProperty( *pRangePropSet ); + XMLTextCharStyleNamesElementExport aCharStylesExport( + GetExport(), bDoSomething, bHasAutoStyle, + bDoSomething ? *pRangePropSet : Reference<XPropertySet>(), + gsCharStyleNames ); + + if( !sStyle.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sStyle ) ); + { + SvXMLElementExport aElem( GetExport(), !sStyle.isEmpty(), + XML_NAMESPACE_TEXT, XML_SPAN, false, false ); + { + SvXMLElementExport aElement( GetExport(), + FrameType::Shape != eType && + HyperlinkData(xPropSet).addHyperlinkAttributes(GetExport()), + XML_NAMESPACE_DRAW, XML_A, false, false ); + switch( eType ) + { + case FrameType::Text: + _exportTextFrame( xPropSet, xPropSetInfo, bIsProgress ); + break; + case FrameType::Graphic: + _exportTextGraphic( xPropSet, xPropSetInfo ); + break; + case FrameType::Embedded: + _exportTextEmbedded( xPropSet, xPropSetInfo ); + break; + case FrameType::Shape: + { + Reference < XShape > xShape( rTxtCntnt, UNO_QUERY ); + XMLShapeExportFlags nFeatures = + addTextFrameAttributes( xPropSet, true ); + GetExport().GetShapeExport() + ->exportShape( xShape, nFeatures ); + } + break; + } + } + } + } + } +} + +void XMLTextParagraphExport::_exportTextFrame( + const Reference < XPropertySet > & rPropSet, + const Reference < XPropertySetInfo > & rPropSetInfo, + bool bIsProgress ) +{ + Reference < XTextFrame > xTxtFrame( rPropSet, UNO_QUERY ); + Reference < XText > xTxt(xTxtFrame->getText()); + + OUString sStyle; + if( rPropSetInfo->hasPropertyByName( gsFrameStyleName ) ) + { + rPropSet->getPropertyValue( gsFrameStyleName ) >>= sStyle; + } + + OUString aMinHeightValue; + OUString sMinWidthValue; + OUString sAutoStyle = Find( XmlStyleFamily::TEXT_FRAME, rPropSet, sStyle ); + if ( sAutoStyle.isEmpty() ) + sAutoStyle = sStyle; + if( !sAutoStyle.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE_NAME, + GetExport().EncodeStyleName( sAutoStyle ) ); + addTextFrameAttributes(rPropSet, false, nullptr, &aMinHeightValue, &sMinWidthValue); + + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW, + XML_FRAME, false, true ); + + if( !aMinHeightValue.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_MIN_HEIGHT, + aMinHeightValue ); + + if (!sMinWidthValue.isEmpty()) + { + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_MIN_WIDTH, + sMinWidthValue ); + } + + // draw:chain-next-name + if( rPropSetInfo->hasPropertyByName( gsChainNextName ) ) + { + OUString sNext; + if( (rPropSet->getPropertyValue( gsChainNextName ) >>= sNext) && !sNext.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_DRAW, + XML_CHAIN_NEXT_NAME, + sNext ); + } + + { + SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_DRAW, + XML_TEXT_BOX, true, true ); + + // frames bound to frame + exportFrameFrames( false, bIsProgress, xTxtFrame ); + + exportText( xTxt, false, bIsProgress, true ); + } + + // script:events + Reference<XEventsSupplier> xEventsSupp( xTxtFrame, UNO_QUERY ); + GetExport().GetEventExport().Export(xEventsSupp); + + // image map + GetExport().GetImageMapExport().Export( rPropSet ); + + // svg:title and svg:desc (#i73249#) + exportTitleAndDescription( rPropSet, rPropSetInfo ); +} + +void XMLTextParagraphExport::exportContour( + const Reference < XPropertySet > & rPropSet, + const Reference < XPropertySetInfo > & rPropSetInfo ) +{ + if( !rPropSetInfo->hasPropertyByName( gsContourPolyPolygon ) ) + { + return; + } + + PointSequenceSequence aSourcePolyPolygon; + rPropSet->getPropertyValue( gsContourPolyPolygon ) >>= aSourcePolyPolygon; + const basegfx::B2DPolyPolygon aPolyPolygon( + basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon( + aSourcePolyPolygon)); + const sal_uInt32 nPolygonCount(aPolyPolygon.count()); + + if(!nPolygonCount) + { + return; + } + + const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange()); + bool bPixel(false); + + if( rPropSetInfo->hasPropertyByName( gsIsPixelContour ) ) + { + bPixel = *o3tl::doAccess<bool>(rPropSet->getPropertyValue( gsIsPixelContour )); + } + + // svg: width + OUStringBuffer aStringBuffer( 10 ); + + if(bPixel) + { + ::sax::Converter::convertMeasurePx(aStringBuffer, basegfx::fround(aPolyPolygonRange.getWidth())); + } + else + { + GetExport().GetMM100UnitConverter().convertMeasureToXML(aStringBuffer, basegfx::fround(aPolyPolygonRange.getWidth())); + } + + GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, aStringBuffer.makeStringAndClear()); + + // svg: height + if(bPixel) + { + ::sax::Converter::convertMeasurePx(aStringBuffer, basegfx::fround(aPolyPolygonRange.getHeight())); + } + else + { + GetExport().GetMM100UnitConverter().convertMeasureToXML(aStringBuffer, basegfx::fround(aPolyPolygonRange.getHeight())); + } + + GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, aStringBuffer.makeStringAndClear()); + + // svg:viewbox + SdXMLImExViewBox aViewBox(0.0, 0.0, aPolyPolygonRange.getWidth(), aPolyPolygonRange.getHeight()); + GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString()); + enum XMLTokenEnum eElem = XML_TOKEN_INVALID; + + if(1 == nPolygonCount ) + { + // simple polygon shape, can be written as svg:points sequence + const OUString aPointString( + basegfx::utils::exportToSvgPoints( + aPolyPolygon.getB2DPolygon(0))); + + // write point array + GetExport().AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString); + eElem = XML_CONTOUR_POLYGON; + } + else + { + // polypolygon, needs to be written as a svg:path sequence + const OUString aPolygonString( + basegfx::utils::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible + + // write point array + GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_D, aPolygonString); + eElem = XML_CONTOUR_PATH; + } + + if( rPropSetInfo->hasPropertyByName( gsIsAutomaticContour ) ) + { + bool bTmp = *o3tl::doAccess<bool>(rPropSet->getPropertyValue( + gsIsAutomaticContour )); + GetExport().AddAttribute( XML_NAMESPACE_DRAW, + XML_RECREATE_ON_EDIT, bTmp ? XML_TRUE : XML_FALSE ); + } + + // write object now + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW, eElem, + true, true ); +} + +void XMLTextParagraphExport::_exportTextGraphic( + const Reference < XPropertySet > & rPropSet, + const Reference < XPropertySetInfo > & rPropSetInfo ) +{ + OUString sStyle; + if( rPropSetInfo->hasPropertyByName( gsFrameStyleName ) ) + { + rPropSet->getPropertyValue( gsFrameStyleName ) >>= sStyle; + } + + OUString sAutoStyle = Find( XmlStyleFamily::TEXT_FRAME, rPropSet, sStyle ); + if ( sAutoStyle.isEmpty() ) + sAutoStyle = sStyle; + if( !sAutoStyle.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE_NAME, + GetExport().EncodeStyleName( sAutoStyle ) ); + + // check if we need to use svg:transform + sal_Int16 nRotation(0); + rPropSet->getPropertyValue( gsGraphicRotation ) >>= nRotation; + const bool bUseRotation(0 != nRotation); + basegfx::B2DPoint aCenter(0.0, 0.0); + + // add TextFrame attributes like svg:x/y/width/height, also get back + // object's center point if rotation is used and has to be exported + addTextFrameAttributes(rPropSet, false, bUseRotation ? &aCenter : nullptr); + + // svg:transform + if(bUseRotation) + { + // RotateFlyFrameFix: im/export full 'draw:transform' using existing tooling. + // Currently only rotation is used, but combinations with 'draw:transform' + // may be necessary in the future, so that svg:x/svg:y/svg:width/svg:height + // may be extended/replaced with 'draw:transform' (see draw objects) + SdXMLImExTransform2D aSdXMLImExTransform2D; + + // Convert from 10th degree integer to deg. + // CAUTION: internal rotation is classically mathematically 'wrong' defined by ignoring that + // we have a right-handed coordinate system, so need to correct this by mirroring + // the rotation to get the correct transformation. See also case XML_TOK_TEXT_FRAME_TRANSFORM + // in XMLTextFrameContext_Impl::XMLTextFrameContext_Impl and #i78696# + // CAUTION-II: due to tdf#115782 it is better for current ODF to indeed write it with the wrong + // orientation as in all other cases - ARGH! We will need to correct this in future ODF ASAP! + const double fRotate(basegfx::deg2rad<10>(nRotation)); + + // transform to rotation center which is the object's center + aSdXMLImExTransform2D.AddTranslate(-aCenter); + + // add rotation itself + // tdf#115529 but correct value modulo 2PI to have it positive and in the range of [0.0 .. 2PI[ + aSdXMLImExTransform2D.AddRotate(basegfx::normalizeToRange(fRotate, 2 * M_PI)); + + // back-transform after rotation + aSdXMLImExTransform2D.AddTranslate(aCenter); + + // Note: using GetTwipUnitConverter instead of GetMM100UnitConverter may be needed, + // but is not generally available (as it should be, a 'current' UnitConverter should + // be available at GetExport() - and maybe was once). May have to be addressed as soon + // as translate transformations are used here. + GetExport().AddAttribute( + XML_NAMESPACE_DRAW, + XML_TRANSFORM, + aSdXMLImExTransform2D.GetExportString(GetExport().GetMM100UnitConverter())); + } + + // original content + SvXMLElementExport aElem(GetExport(), XML_NAMESPACE_DRAW, XML_FRAME, false, true); + + { + // xlink:href + uno::Reference<graphic::XGraphic> xGraphic; + rPropSet->getPropertyValue("Graphic") >>= xGraphic; + + OUString sInternalURL; + OUString sOutMimeType; + + if (xGraphic.is()) + { + sInternalURL = GetExport().AddEmbeddedXGraphic(xGraphic, sOutMimeType); + } + + // If there still is no url, then graphic is empty + if (!sInternalURL.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD); + } + + // draw:filter-name + OUString sGrfFilter; + rPropSet->getPropertyValue( gsGraphicFilter ) >>= sGrfFilter; + if( !sGrfFilter.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_FILTER_NAME, + sGrfFilter ); + + if (GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012) + { + if (sOutMimeType.isEmpty()) + { + GetExport().GetGraphicMimeTypeFromStream(xGraphic, sOutMimeType); + } + if (!sOutMimeType.isEmpty()) + { // ODF 1.3 OFFICE-3943 + GetExport().AddAttribute( + SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion() + ? XML_NAMESPACE_DRAW + : XML_NAMESPACE_LO_EXT, + "mime-type", sOutMimeType); + } + } + + + // optional office:binary-data + if (xGraphic.is()) + { + SvXMLElementExport aElement(GetExport(), XML_NAMESPACE_DRAW, XML_IMAGE, false, true ); + GetExport().AddEmbeddedXGraphicAsBase64(xGraphic); + } + } + + const bool bAddReplacementImages = officecfg::Office::Common::Save::Graphic::AddReplacementImages::get(); + if (bAddReplacementImages) + { + // replacement graphic for backwards compatibility, but + // only for SVG and metafiles currently + uno::Reference<graphic::XGraphic> xReplacementGraphic; + rPropSet->getPropertyValue("ReplacementGraphic") >>= xReplacementGraphic; + + OUString sInternalURL; + OUString sOutMimeType; + + //Resolves: fdo#62461 put preferred image first above, followed by + //fallback here + if (xReplacementGraphic.is()) + { + sInternalURL = GetExport().AddEmbeddedXGraphic(xReplacementGraphic, sOutMimeType); + } + + // If there is no url, then graphic is empty + if (!sInternalURL.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD); + } + + if (GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012) + { + if (sOutMimeType.isEmpty()) + { + GetExport().GetGraphicMimeTypeFromStream(xReplacementGraphic, sOutMimeType); + } + if (!sOutMimeType.isEmpty()) + { // ODF 1.3 OFFICE-3943 + GetExport().AddAttribute( + SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion() + ? XML_NAMESPACE_DRAW + : XML_NAMESPACE_LO_EXT, + "mime-type", sOutMimeType); + } + } + + + // optional office:binary-data + if (xReplacementGraphic.is()) + { + SvXMLElementExport aElement(GetExport(), XML_NAMESPACE_DRAW, XML_IMAGE, true, true); + GetExport().AddEmbeddedXGraphicAsBase64(xReplacementGraphic); + } + } + + // script:events + Reference<XEventsSupplier> xEventsSupp( rPropSet, UNO_QUERY ); + GetExport().GetEventExport().Export(xEventsSupp); + + // image map + GetExport().GetImageMapExport().Export( rPropSet ); + + // svg:title and svg:desc (#i73249#) + exportTitleAndDescription( rPropSet, rPropSetInfo ); + + // draw:contour + exportContour( rPropSet, rPropSetInfo ); +} + +void XMLTextParagraphExport::_collectTextEmbeddedAutoStyles(const Reference < XPropertySet > & ) +{ + SAL_WARN( "xmloff", "no API implementation available" ); +} + +void XMLTextParagraphExport::_exportTextEmbedded( + const Reference < XPropertySet > &, + const Reference < XPropertySetInfo > & ) +{ + SAL_WARN( "xmloff", "no API implementation available" ); +} + +void XMLTextParagraphExport::exportEvents( const Reference < XPropertySet > & rPropSet ) +{ + // script:events + Reference<XEventsSupplier> xEventsSupp( rPropSet, UNO_QUERY ); + GetExport().GetEventExport().Export(xEventsSupp); + + // image map + if (rPropSet->getPropertySetInfo()->hasPropertyByName("ImageMap")) + GetExport().GetImageMapExport().Export( rPropSet ); +} + +// Implement Title/Description Elements UI (#i73249#) +void XMLTextParagraphExport::exportTitleAndDescription( + const Reference < XPropertySet > & rPropSet, + const Reference < XPropertySetInfo > & rPropSetInfo ) +{ + // svg:title + if( rPropSetInfo->hasPropertyByName( gsTitle ) ) + { + OUString sObjTitle; + rPropSet->getPropertyValue( gsTitle ) >>= sObjTitle; + if( !sObjTitle.isEmpty() ) + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_SVG, + XML_TITLE, true, false ); + GetExport().Characters( sObjTitle ); + } + } + + // svg:description + if( rPropSetInfo->hasPropertyByName( gsDescription ) ) + { + OUString sObjDesc; + rPropSet->getPropertyValue( gsDescription ) >>= sObjDesc; + if( !sObjDesc.isEmpty() ) + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_SVG, + XML_DESC, true, false ); + GetExport().Characters( sObjDesc ); + } + } +} + +void XMLTextParagraphExport::exportTextRangeSpan( + const css::uno::Reference< css::text::XTextRange > & rTextRange, + Reference< XPropertySet > const & xPropSet, + Reference < XPropertySetInfo > & xPropSetInfo, + const bool bIsUICharStyle, + const bool bHasAutoStyle, + const OUString& sStyle, + bool& rPrevCharIsSpace, + FieldmarkType& openFieldMark ) +{ + XMLTextCharStyleNamesElementExport aCharStylesExport( + GetExport(), + bIsUICharStyle && m_aCharStyleNamesPropInfoCache.hasProperty( xPropSet, xPropSetInfo ), + bHasAutoStyle, + xPropSet, + gsCharStyleNames ); + + if ( !sStyle.isEmpty() ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, GetExport().EncodeStyleName( sStyle ) ); + } + { + SvXMLElementExport aElement( GetExport(), !sStyle.isEmpty(), XML_NAMESPACE_TEXT, XML_SPAN, false, false ); + const OUString aText( rTextRange->getString() ); + SvXMLElementExport aElem2( GetExport(), TEXT == openFieldMark, + XML_NAMESPACE_TEXT, XML_TEXT_INPUT, + false, false ); + exportCharacterData(aText, rPrevCharIsSpace); + openFieldMark = NONE; + } +} + +void XMLTextParagraphExport::exportTextRange( + const Reference< XTextRange > & rTextRange, + bool bAutoStyles, + bool& rPrevCharIsSpace, + FieldmarkType& openFieldMark ) +{ + Reference< XPropertySet > xPropSet( rTextRange, UNO_QUERY ); + if ( bAutoStyles ) + { + Add( XmlStyleFamily::TEXT_TEXT, xPropSet ); + } + else + { + bool bIsUICharStyle = false; + bool bHasAutoStyle = false; + const OUString sStyle( + FindTextStyle( xPropSet, bIsUICharStyle, bHasAutoStyle ) ); + + Reference < XPropertySetInfo > xPropSetInfo; + exportTextRangeSpan( rTextRange, xPropSet, xPropSetInfo, bIsUICharStyle, bHasAutoStyle, sStyle, rPrevCharIsSpace, openFieldMark ); + } +} + +void XMLTextParagraphExport::exportCharacterData(const OUString& rText, + bool& rPrevCharIsSpace ) +{ + sal_Int32 nExpStartPos = 0; + sal_Int32 nEndPos = rText.getLength(); + sal_Int32 nSpaceChars = 0; + for( sal_Int32 nPos = 0; nPos < nEndPos; nPos++ ) + { + sal_Unicode cChar = rText[nPos]; + bool bExpCharAsText = true; + bool bExpCharAsElement = false; + bool bCurrCharIsSpace = false; + switch( cChar ) + { + case 0x0009: // Tab + case 0x000A: // LF + // These characters are exported as text. + bExpCharAsElement = true; + bExpCharAsText = false; + break; + case 0x000D: + break; // legal character + case 0x0020: // Blank + if( rPrevCharIsSpace ) + { + // If the previous character is a space character, + // too, export a special space element. + bExpCharAsText = false; + } + bCurrCharIsSpace = true; + break; + default: + if( cChar < 0x0020 ) + { +#ifdef DBG_UTIL + OSL_ENSURE( txtparae_bContainsIllegalCharacters || + cChar >= 0x0020, + "illegal character in text content" ); + txtparae_bContainsIllegalCharacters = true; +#endif + bExpCharAsText = false; + } + break; + } + + // If the current character is not exported as text + // the text that has not been exported by now has to be exported now. + if( nPos > nExpStartPos && !bExpCharAsText ) + { + SAL_WARN_IF( 0 != nSpaceChars, "xmloff", "pending spaces" ); + OUString sExp( rText.copy( nExpStartPos, nPos - nExpStartPos ) ); + GetExport().Characters( sExp ); + nExpStartPos = nPos; + } + + // If there are spaces left that have not been exported and the + // current character is not a space , the pending spaces have to be + // exported now. + if( nSpaceChars > 0 && !bCurrCharIsSpace ) + { + SAL_WARN_IF( nExpStartPos != nPos, "xmloff", " pending characters" ); + + if( nSpaceChars > 1 ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_C, + OUString::number(nSpaceChars) ); + } + + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + XML_S, false, false ); + + nSpaceChars = 0; + } + + // If the current character has to be exported as a special + // element, the element will be exported now. + if( bExpCharAsElement ) + { + switch( cChar ) + { + case 0x0009: // Tab + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + XML_TAB, false, + false ); + } + break; + case 0x000A: // LF + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + XML_LINE_BREAK, false, + false ); + } + break; + } + } + + // If the current character is a space, and the previous one + // is a space, too, the number of pending spaces is incremented + // only. + if( bCurrCharIsSpace && rPrevCharIsSpace ) + nSpaceChars++; + rPrevCharIsSpace = bCurrCharIsSpace; + + // If the current character is not exported as text, the start + // position for text is the position behind the current position. + if( !bExpCharAsText ) + { + SAL_WARN_IF( nExpStartPos != nPos, "xmloff", "wrong export start pos" ); + nExpStartPos = nPos+1; + } + } + + if( nExpStartPos < nEndPos ) + { + SAL_WARN_IF( 0 != nSpaceChars, "xmloff", " pending spaces " ); + OUString sExp( rText.copy( nExpStartPos, nEndPos - nExpStartPos ) ); + GetExport().Characters( sExp ); + } + + // If there are some spaces left, they have to be exported now. + if( nSpaceChars > 0 ) + { + if( nSpaceChars > 1 ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_C, + OUString::number(nSpaceChars) ); + } + + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, XML_S, + false, false ); + } +} + +void XMLTextParagraphExport::exportTextDeclarations() +{ + m_pFieldExport->ExportFieldDeclarations(); + + // get XPropertySet from the document and ask for AutoMarkFileURL. + // If it exists, export the auto-mark-file element. + Reference<XPropertySet> xPropertySet( GetExport().GetModel(), UNO_QUERY ); + if (!xPropertySet.is()) + return; + + OUString sUrl; + OUString sIndexAutoMarkFileURL( + "IndexAutoMarkFileURL"); + if (!xPropertySet->getPropertySetInfo()->hasPropertyByName( + sIndexAutoMarkFileURL)) + return; + + xPropertySet->getPropertyValue(sIndexAutoMarkFileURL) >>= sUrl; + if (!sUrl.isEmpty()) + { + GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, + GetExport().GetRelativeReference(sUrl) ); + SvXMLElementExport aAutoMarkElement( + GetExport(), XML_NAMESPACE_TEXT, + XML_ALPHABETICAL_INDEX_AUTO_MARK_FILE, + true, true ); + } +} + +void XMLTextParagraphExport::exportTextDeclarations( + const Reference<XText> & rText ) +{ + m_pFieldExport->ExportFieldDeclarations(rText); +} + +void XMLTextParagraphExport::exportUsedDeclarations() +{ + m_pFieldExport->SetExportOnlyUsedFieldDeclarations( false/*bOnlyUsed*/ ); +} + +void XMLTextParagraphExport::exportTrackedChanges(bool bAutoStyles) +{ + if (nullptr != m_pRedlineExport) + m_pRedlineExport->ExportChangesList( bAutoStyles ); +} + +void XMLTextParagraphExport::exportTrackedChanges( + const Reference<XText> & rText, + bool bAutoStyle) +{ + if (nullptr != m_pRedlineExport) + m_pRedlineExport->ExportChangesList(rText, bAutoStyle); +} + +void XMLTextParagraphExport::recordTrackedChangesForXText( + const Reference<XText> & rText ) +{ + if (nullptr != m_pRedlineExport) + m_pRedlineExport->SetCurrentXText(rText); +} + +void XMLTextParagraphExport::recordTrackedChangesNoXText() +{ + if (nullptr != m_pRedlineExport) + m_pRedlineExport->SetCurrentXText(); +} + +void XMLTextParagraphExport::exportTableAutoStyles() {} + +void XMLTextParagraphExport::exportTextAutoStyles() +{ + // tdf#135942: do not collect styles during their export: this may modify iterated containers + mbCollected = true; + exportTableAutoStyles(); + + GetAutoStylePool().exportXML( XmlStyleFamily::TEXT_PARAGRAPH ); + + GetAutoStylePool().exportXML( XmlStyleFamily::TEXT_TEXT ); + + GetAutoStylePool().exportXML( XmlStyleFamily::TEXT_FRAME ); + + GetAutoStylePool().exportXML( XmlStyleFamily::TEXT_SECTION ); + + GetAutoStylePool().exportXML( XmlStyleFamily::TEXT_RUBY ); + + maListAutoPool.exportXML(); +} + +void XMLTextParagraphExport::exportRuby( + const Reference<XPropertySet> & rPropSet, + bool bAutoStyles ) +{ + // early out: a collapsed ruby makes no sense + if (*o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsIsCollapsed))) + return; + + // start value ? + bool bStart = *o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsIsStart)); + + if (bAutoStyles) + { + // ruby auto styles + if (bStart) + Add( XmlStyleFamily::TEXT_RUBY, rPropSet ); + } + else + { + if (bStart) + { + // ruby start + + // we can only start a ruby if none is open + assert(!m_bOpenRuby && "Can't open a ruby inside of ruby!"); + if( m_bOpenRuby ) + return; + + // save ruby text + ruby char style + rPropSet->getPropertyValue(gsRubyText) >>= m_sOpenRubyText; + rPropSet->getPropertyValue(gsRubyCharStyleName) >>= m_sOpenRubyCharStyle; + + // ruby style + GetExport().CheckAttrList(); + OUString sStyleName(Find(XmlStyleFamily::TEXT_RUBY, rPropSet, "")); + SAL_WARN_IF(sStyleName.isEmpty(), "xmloff", "Can't find ruby style!"); + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_STYLE_NAME, sStyleName); + + // export <text:ruby> and <text:ruby-base> start elements + GetExport().StartElement( XML_NAMESPACE_TEXT, XML_RUBY, false); + GetExport().ClearAttrList(); + GetExport().StartElement( XML_NAMESPACE_TEXT, XML_RUBY_BASE, + false ); + m_bOpenRuby = true; + } + else + { + // ruby end + + // check for an open ruby + assert(m_bOpenRuby && "Can't close a ruby if none is open!"); + if( !m_bOpenRuby ) + return; + + // close <text:ruby-base> + GetExport().EndElement(XML_NAMESPACE_TEXT, XML_RUBY_BASE, + false); + + // write the ruby text (with char style) + { + if (!m_sOpenRubyCharStyle.isEmpty()) + GetExport().AddAttribute( + XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( m_sOpenRubyCharStyle) ); + + SvXMLElementExport aRubyElement( + GetExport(), XML_NAMESPACE_TEXT, XML_RUBY_TEXT, + false, false); + + GetExport().Characters(m_sOpenRubyText); + } + + // and finally, close the ruby + GetExport().EndElement(XML_NAMESPACE_TEXT, XML_RUBY, false); + m_bOpenRuby = false; + } + } +} + +void XMLTextParagraphExport::exportMeta( + const Reference<XPropertySet> & i_xPortion, + bool i_bAutoStyles, bool i_isProgress, bool & rPrevCharIsSpace) +{ + bool doExport(!i_bAutoStyles); // do not export element if autostyles + // check version >= 1.2 + switch (GetExport().getSaneDefaultVersion()) { + case SvtSaveOptions::ODFSVER_011: // fall through + case SvtSaveOptions::ODFSVER_010: doExport = false; break; + default: break; + } + + const Reference< XTextContent > xTextContent( + i_xPortion->getPropertyValue("InContentMetadata"), UNO_QUERY_THROW); + const Reference< XEnumerationAccess > xEA( xTextContent, UNO_QUERY_THROW ); + const Reference< XEnumeration > xTextEnum( xEA->createEnumeration() ); + + if (doExport) + { + const Reference<rdf::XMetadatable> xMeta(xTextContent, UNO_QUERY_THROW); + + // text:meta with neither xml:id nor RDFa is invalid + xMeta->ensureMetadataReference(); + + // xml:id and RDFa for RDF metadata + GetExport().AddAttributeXmlId(xMeta); + GetExport().AddAttributesRDFa(xTextContent); + } + + SvXMLElementExport aElem( GetExport(), doExport, + XML_NAMESPACE_TEXT, XML_META, false, false ); + + // recurse to export content + exportTextRangeEnumeration(xTextEnum, i_bAutoStyles, i_isProgress, rPrevCharIsSpace); +} + +void XMLTextParagraphExport::ExportContentControl( + const uno::Reference<beans::XPropertySet>& xPortion, bool bAutoStyles, bool isProgress, + bool& rPrevCharIsSpace) +{ + // Do not export the element in the autostyle case. + bool bExport = !bAutoStyles; + if (!(GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)) + { + bExport = false; + } + + uno::Reference<text::XTextContent> xTextContent(xPortion->getPropertyValue("ContentControl"), + uno::UNO_QUERY_THROW); + uno::Reference<container::XEnumerationAccess> xEA(xTextContent, uno::UNO_QUERY_THROW); + uno::Reference<container::XEnumeration> xTextEnum = xEA->createEnumeration(); + + uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY_THROW); + if (bExport) + { + bool bShowingPlaceHolder = false; + xPropertySet->getPropertyValue("ShowingPlaceHolder") >>= bShowingPlaceHolder; + if (bShowingPlaceHolder) + { + OUStringBuffer aBuffer; + sax::Converter::convertBool(aBuffer, bShowingPlaceHolder); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_SHOWING_PLACE_HOLDER, + aBuffer.makeStringAndClear()); + } + + bool bCheckbox = false; + xPropertySet->getPropertyValue("Checkbox") >>= bCheckbox; + if (bCheckbox) + { + OUStringBuffer aBuffer; + sax::Converter::convertBool(aBuffer, bCheckbox); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CHECKBOX, aBuffer.makeStringAndClear()); + } + + bool bChecked = false; + xPropertySet->getPropertyValue("Checked") >>= bChecked; + if (bChecked) + { + OUStringBuffer aBuffer; + sax::Converter::convertBool(aBuffer, bChecked); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CHECKED, aBuffer.makeStringAndClear()); + } + + OUString aCheckedState; + xPropertySet->getPropertyValue("CheckedState") >>= aCheckedState; + if (!aCheckedState.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CHECKED_STATE, aCheckedState); + } + + OUString aUncheckedState; + xPropertySet->getPropertyValue("UncheckedState") >>= aUncheckedState; + if (!aUncheckedState.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_UNCHECKED_STATE, aUncheckedState); + } + + bool bPicture = false; + xPropertySet->getPropertyValue("Picture") >>= bPicture; + if (bPicture) + { + OUStringBuffer aBuffer; + sax::Converter::convertBool(aBuffer, bPicture); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_PICTURE, + aBuffer.makeStringAndClear()); + } + + bool bDate = false; + xPropertySet->getPropertyValue("Date") >>= bDate; + if (bDate) + { + OUStringBuffer aBuffer; + sax::Converter::convertBool(aBuffer, bDate); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATE, aBuffer.makeStringAndClear()); + } + + OUString aDateFormat; + xPropertySet->getPropertyValue("DateFormat") >>= aDateFormat; + if (!aDateFormat.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATE_FORMAT, aDateFormat); + } + + OUString aDateLanguage; + xPropertySet->getPropertyValue("DateLanguage") >>= aDateLanguage; + if (!aDateLanguage.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATE_RFC_LANGUAGE_TAG, aDateLanguage); + } + OUString aCurrentDate; + xPropertySet->getPropertyValue("CurrentDate") >>= aCurrentDate; + if (!aCurrentDate.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CURRENT_DATE, aCurrentDate); + } + + bool bPlainText = false; + xPropertySet->getPropertyValue("PlainText") >>= bPlainText; + if (bPlainText) + { + OUStringBuffer aBuffer; + sax::Converter::convertBool(aBuffer, bPlainText); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_PLAIN_TEXT, aBuffer.makeStringAndClear()); + } + + bool bComboBox = false; + xPropertySet->getPropertyValue("ComboBox") >>= bComboBox; + if (bComboBox) + { + OUStringBuffer aBuffer; + sax::Converter::convertBool(aBuffer, bComboBox); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_COMBOBOX, aBuffer.makeStringAndClear()); + } + + bool bDropDown = false; + xPropertySet->getPropertyValue("DropDown") >>= bDropDown; + if (bDropDown) + { + OUStringBuffer aBuffer; + sax::Converter::convertBool(aBuffer, bDropDown); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_DROPDOWN, aBuffer.makeStringAndClear()); + } + + OUString aAlias; + xPropertySet->getPropertyValue("Alias") >>= aAlias; + if (!aAlias.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_ALIAS, aAlias); + } + + OUString aTag; + xPropertySet->getPropertyValue("Tag") >>= aTag; + if (!aTag.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_TAG, aTag); + } + + sal_Int32 nId = 0; + xPropertySet->getPropertyValue("Id") >>= nId; + if (nId) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_ID, OUString::number(nId)); + } + + sal_uInt32 nTabIndex = 0; + if ((xPropertySet->getPropertyValue("TabIndex") >>= nTabIndex) && nTabIndex) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_TAB_INDEX, + OUString::number(nTabIndex)); + } + + OUString aLock; + xPropertySet->getPropertyValue("Lock") >>= aLock; + if (!aLock.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_LOCK, aLock); + } + } + + SvXMLElementExport aElem(GetExport(), bExport, XML_NAMESPACE_LO_EXT, XML_CONTENT_CONTROL, false, + false); + + if (bExport) + { + // Export list items of dropdowns. + uno::Sequence<beans::PropertyValues> aListItems; + xPropertySet->getPropertyValue("ListItems") >>= aListItems; + for (const auto& rListItem : aListItems) + { + comphelper::SequenceAsHashMap aMap(rListItem); + auto it = aMap.find("DisplayText"); + OUString aValue; + if (it != aMap.end() && (it->second >>= aValue) && !aValue.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_DISPLAY_TEXT, aValue); + } + + it = aMap.find("Value"); + if (it != aMap.end() && (it->second >>= aValue)) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_VALUE, aValue); + } + + SvXMLElementExport aItem(GetExport(), bExport, XML_NAMESPACE_LO_EXT, XML_LIST_ITEM, false, + false); + } + } + + // Recurse to export content. + exportTextRangeEnumeration(xTextEnum, bAutoStyles, isProgress, rPrevCharIsSpace); +} + +void XMLTextParagraphExport::PreventExportOfControlsInMuteSections( + const Reference<XIndexAccess> & rShapes, + const rtl::Reference<xmloff::OFormLayerXMLExport>& xFormExport ) +{ + // check parameters ad pre-conditions + if( ( ! rShapes.is() ) || ( ! xFormExport.is() ) ) + { + // if we don't have shapes or a form export, there's nothing to do + return; + } + SAL_WARN_IF( m_pSectionExport == nullptr, "xmloff", "We need the section export." ); + + Reference<XEnumeration> xShapesEnum = m_pBoundFrameSets->GetShapes()->createEnumeration(); + if(!xShapesEnum.is()) + return; + while( xShapesEnum->hasMoreElements() ) + { + // now we need to check + // 1) if this is a control shape, and + // 2) if it's in a mute section + // if both answers are 'yes', notify the form layer export + + // we join accessing the shape and testing for control + Reference<XControlShape> xControlShape(xShapesEnum->nextElement(), UNO_QUERY); + if( xControlShape.is() ) + { + // Reference<XPropertySet> xPropSet( xControlShape, UNO_QUERY ); + // Reference<XTextContent> xTextContent; + // xPropSet->getPropertyValue("TextRange") >>= xTextContent; + + Reference<XTextContent> xTextContent( xControlShape, UNO_QUERY ); + if( xTextContent.is() ) + { + if( m_pSectionExport->IsMuteSection( xTextContent, false ) ) + { + // Ah, we've found a shape that + // 1) is a control shape + // 2) is anchored in a mute section + // so: don't export it! + xFormExport->excludeFromExport( + xControlShape->getControl() ); + } + // else: not in mute section -> should be exported -> nothing + // to do + } + // else: no anchor -> ignore + } + // else: no control shape -> nothing to do + } +} + +void XMLTextParagraphExport::PushNewTextListsHelper() +{ + maTextListsHelperStack.emplace_back( new XMLTextListsHelper() ); + mpTextListsHelper = maTextListsHelperStack.back().get(); +} + +void XMLTextParagraphExport::PopTextListsHelper() +{ + mpTextListsHelper = nullptr; + maTextListsHelperStack.pop_back(); + if ( !maTextListsHelperStack.empty() ) + { + mpTextListsHelper = maTextListsHelperStack.back().get(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtparai.cxx b/xmloff/source/text/txtparai.cxx new file mode 100644 index 0000000000..c777fa0c29 --- /dev/null +++ b/xmloff/source/text/txtparai.cxx @@ -0,0 +1,2147 @@ +/* -*- 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/unointerfacetouniqueidentifiermapper.hxx> + +#include <memory> +#include <string_view> +#include <vector> + +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/text/XTextFrame.hpp> +#include <com/sun/star/text/XTextCursor.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/text/ControlCharacter.hpp> +#include <com/sun/star/text/XTextRangeCompare.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/rdf/XMetadatable.hpp> + +#include <sax/tools/converter.hxx> + +#include <xmloff/prstylei.hxx> +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/txtimp.hxx> +#include "txtparai.hxx" +#include <txtfldi.hxx> +#include "XMLFootnoteImportContext.hxx" +#include "XMLTextMarkImportContext.hxx" +#include "XMLTextFrameContext.hxx" +#include <xmloff/XMLCharContext.hxx> +#include "XMLTextFrameHyperlinkContext.hxx" +#include <xmloff/XMLEventsImportContext.hxx> +#include "XMLChangeImportContext.hxx" +#include <txtlists.hxx> + +#include "txtparaimphint.hxx" +#include "xmllinebreakcontext.hxx" +#include "xmlcontentcontrolcontext.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; +using ::com::sun::star::container::XEnumerationAccess; +using ::com::sun::star::container::XEnumeration; + +class XMLHints_Impl +{ +private: + + std::vector<std::unique_ptr<XMLHint_Impl>> m_Hints; + std::unordered_map<OUString, XMLIndexMarkHint_Impl*> m_IndexHintsById; + uno::Reference<uno::XInterface> m_xCrossRefHeadingBookmark; + +public: + void push_back(std::unique_ptr<XMLHint_Impl> pHint) + { + m_Hints.push_back(std::move(pHint)); + } + + void push_back(std::unique_ptr<XMLIndexMarkHint_Impl> pHint) + { + m_IndexHintsById.emplace(pHint->GetID(), pHint.get()); + m_Hints.push_back(std::move(pHint)); + } + + std::vector<std::unique_ptr<XMLHint_Impl>> const& GetHints() const + { + return m_Hints; + } + + XMLIndexMarkHint_Impl* GetIndexHintById(const OUString& sID) + { + auto it = m_IndexHintsById.find(sID); + return it == m_IndexHintsById.end() ? nullptr : it->second; + } + + uno::Reference<uno::XInterface> & GetCrossRefHeadingBookmark() + { + return m_xCrossRefHeadingBookmark; + } +}; + + +XMLCharContext::XMLCharContext( + SvXMLImport& rImport, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + sal_Unicode c, + bool bCount ) : + SvXMLImportContext( rImport ) + ,m_nControl(0) + ,m_nCount(1) + ,m_c(c) +{ + if( !bCount ) + return; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if( aIter.getToken() == XML_ELEMENT(TEXT, XML_C) ) + { + sal_Int32 nTmp = aIter.toInt32(); + if( nTmp > 0 ) + { + if( nTmp > SAL_MAX_UINT16 ) + m_nCount = SAL_MAX_UINT16; + else + m_nCount = static_cast<sal_uInt16>(nTmp); + } + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +XMLCharContext::XMLCharContext( + SvXMLImport& rImp, + sal_Int16 nControl ) : + SvXMLImportContext( rImp ) + ,m_nControl(nControl) + ,m_nCount(0) + ,m_c(0) +{ +} + +XMLCharContext::~XMLCharContext() +{ +} +void XMLCharContext::endFastElement(sal_Int32 ) +{ + if ( !m_nCount ) + InsertControlCharacter( m_nControl ); + else + { + if( 1U == m_nCount ) + { + OUString sBuff( &m_c, 1 ); + InsertString(sBuff); + } + else + { + OUStringBuffer sBuff(static_cast<int>(m_nCount)); + while( m_nCount-- ) + sBuff.append( &m_c, 1 ); + + InsertString(sBuff.makeStringAndClear() ); + } + } +} +void XMLCharContext::InsertControlCharacter(sal_Int16 _nControl) +{ + GetImport().GetTextImport()->InsertControlCharacter( _nControl ); +} +void XMLCharContext::InsertString(const OUString& _sString) +{ + GetImport().GetTextImport()->InsertString( _sString ); +} + +namespace { + +/** import start of reference (<text:reference-start>) */ +class XMLStartReferenceContext_Impl : public SvXMLImportContext +{ +public: + + // Do everything in constructor. Well ... + XMLStartReferenceContext_Impl ( + SvXMLImport& rImport, + XMLHints_Impl& rHints, + const Reference<xml::sax::XFastAttributeList> & xAttrList); + + static bool FindName( + const Reference<xml::sax::XFastAttributeList> & xAttrList, + OUString& rName); +}; + +} + +XMLStartReferenceContext_Impl::XMLStartReferenceContext_Impl( + SvXMLImport& rImport, + XMLHints_Impl& rHints, + const Reference<xml::sax::XFastAttributeList> & xAttrList) : + SvXMLImportContext(rImport) +{ + OUString sName; + + if (FindName(xAttrList, sName)) + { + std::unique_ptr<XMLHint_Impl> pHint(new XMLReferenceHint_Impl( + sName, rImport.GetTextImport()->GetCursor()->getStart())); + + // degenerates to point reference, if no end is found! + pHint->SetEnd(rImport.GetTextImport()->GetCursor()->getStart() ); + + rHints.push_back(std::move(pHint)); + } +} + +bool XMLStartReferenceContext_Impl::FindName( + const Reference<xml::sax::XFastAttributeList> & xAttrList, + OUString& rName) +{ + bool bNameOK( false ); + + // find name attribute first + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_NAME) ) + { + rName = aIter.toString(); + bNameOK = true; + break; + } + } + + return bNameOK; +} + +namespace { + +/** import end of reference (<text:reference-end>) */ +class XMLEndReferenceContext_Impl : public SvXMLImportContext +{ +public: + + // Do everything in constructor. Well ... + XMLEndReferenceContext_Impl( + SvXMLImport& rImport, + const XMLHints_Impl& rHints, + const Reference<xml::sax::XFastAttributeList> & xAttrList); +}; + +} + +XMLEndReferenceContext_Impl::XMLEndReferenceContext_Impl( + SvXMLImport& rImport, + const XMLHints_Impl& rHints, + const Reference<xml::sax::XFastAttributeList> & xAttrList) : + SvXMLImportContext(rImport) +{ + OUString sName; + + // borrow from XMLStartReferenceContext_Impl + if (!XMLStartReferenceContext_Impl::FindName(xAttrList, sName)) + return; + + // search for reference start + for (const auto& rHintPtr : rHints.GetHints()) + { + XMLHint_Impl *const pHint = rHintPtr.get(); + if ( pHint->IsReference() && + sName == static_cast<XMLReferenceHint_Impl *>(pHint)->GetRefName() ) + { + // set end and stop searching + pHint->SetEnd(GetImport().GetTextImport()-> + GetCursor()->getStart() ); + break; + } + } + // else: no start (in this paragraph) -> ignore +} + +namespace { + +class XMLImpHyperlinkContext_Impl : public SvXMLImportContext +{ + XMLHints_Impl& m_rHints; + XMLHyperlinkHint_Impl *mpHint; + + bool& mrbIgnoreLeadingSpace; + +public: + + + XMLImpHyperlinkContext_Impl( + SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace ); + + virtual ~XMLImpHyperlinkContext_Impl() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL characters( const OUString& rChars ) override; +}; + +} + +XMLImpHyperlinkContext_Impl::XMLImpHyperlinkContext_Impl( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace ) + : SvXMLImportContext( rImport ) + , m_rHints( rHints ) + , mpHint( new XMLHyperlinkHint_Impl( GetImport().GetTextImport()->GetCursorAsRange()->getStart() ) ) + , mrbIgnoreLeadingSpace( rIgnLeadSpace ) +{ + OUString sShow; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + OUString sValue = aIter.toString(); + switch (aIter.getToken()) + { + case XML_ELEMENT(XLINK, XML_HREF): + mpHint->SetHRef( GetImport().GetAbsoluteReference( sValue ) ); + break; + case XML_ELEMENT(OFFICE, XML_NAME): + mpHint->SetName( sValue ); + break; + case XML_ELEMENT(OFFICE, XML_TARGET_FRAME_NAME): + mpHint->SetTargetFrameName( sValue ); + break; + case XML_ELEMENT(XLINK, XML_SHOW): + sShow = sValue; + break; + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + mpHint->SetStyleName( sValue ); + break; + case XML_ELEMENT(TEXT, XML_VISITED_STYLE_NAME): + mpHint->SetVisitedStyleName( sValue ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( !sShow.isEmpty() && mpHint->GetTargetFrameName().isEmpty() ) + { + if( IsXMLToken( sShow, XML_NEW ) ) + mpHint->SetTargetFrameName( + "_blank" ); + else if( IsXMLToken( sShow, XML_REPLACE ) ) + mpHint->SetTargetFrameName( + "_self" ); + } + + if ( mpHint->GetHRef().isEmpty() ) + { + // hyperlink without a URL is not imported. + delete mpHint; + mpHint = nullptr; + } + else + { + m_rHints.push_back(std::unique_ptr<XMLHyperlinkHint_Impl>(mpHint)); + } +} + +XMLImpHyperlinkContext_Impl::~XMLImpHyperlinkContext_Impl() +{ + if (mpHint) + mpHint->SetEnd( GetImport().GetTextImport() + ->GetCursorAsRange()->getStart() ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImpHyperlinkContext_Impl::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + if ( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + XMLEventsImportContext* pCtxt = new XMLEventsImportContext(GetImport()); + if (mpHint) + mpHint->SetEventsContext(pCtxt); + return pCtxt; + } + else + { + return XMLImpSpanContext_Impl::CreateSpanContext( + GetImport(), nElement, xAttrList, + m_rHints, mrbIgnoreLeadingSpace ); + } +} + +void XMLImpHyperlinkContext_Impl::characters( const OUString& rChars ) +{ + GetImport().GetTextImport()->InsertString( rChars, mrbIgnoreLeadingSpace ); +} + +namespace { + +class XMLImpRubyBaseContext_Impl : public SvXMLImportContext +{ + XMLHints_Impl& m_rHints; + + bool& rIgnoreLeadingSpace; + +public: + + + XMLImpRubyBaseContext_Impl( + SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL characters( const OUString& rChars ) override; +}; + +} + +XMLImpRubyBaseContext_Impl::XMLImpRubyBaseContext_Impl( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< xml::sax::XFastAttributeList > &, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace ) + : SvXMLImportContext( rImport ) + , m_rHints( rHints ) + , rIgnoreLeadingSpace( rIgnLeadSpace ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImpRubyBaseContext_Impl::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + return XMLImpSpanContext_Impl::CreateSpanContext( GetImport(), nElement, xAttrList, + m_rHints, rIgnoreLeadingSpace ); +} + +void XMLImpRubyBaseContext_Impl::characters( const OUString& rChars ) +{ + GetImport().GetTextImport()->InsertString( rChars, rIgnoreLeadingSpace ); +} + +namespace { + +class XMLImpRubyContext_Impl : public SvXMLImportContext +{ + XMLHints_Impl& m_rHints; + + bool& rIgnoreLeadingSpace; + + Reference < XTextRange > m_xStart; + OUString m_sStyleName; + OUString m_sTextStyleName; + OUString m_sText; + +public: + + + XMLImpRubyContext_Impl( + SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace ); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + void SetTextStyleName( const OUString& s ) { m_sTextStyleName = s; } + void AppendText( std::u16string_view s ) { m_sText += s; } +}; + +class XMLImpRubyTextContext_Impl : public SvXMLImportContext +{ + XMLImpRubyContext_Impl & m_rRubyContext; + +public: + + + XMLImpRubyTextContext_Impl( + SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLImpRubyContext_Impl & rParent ); + + virtual void SAL_CALL characters( const OUString& rChars ) override; +}; + +} + +XMLImpRubyTextContext_Impl::XMLImpRubyTextContext_Impl( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLImpRubyContext_Impl & rParent ) + : SvXMLImportContext( rImport ) + , m_rRubyContext( rParent ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME) ) + { + m_rRubyContext.SetTextStyleName( aIter.toString() ); + break; + } + } +} + +void XMLImpRubyTextContext_Impl::characters( const OUString& rChars ) +{ + m_rRubyContext.AppendText( rChars ); +} + + +XMLImpRubyContext_Impl::XMLImpRubyContext_Impl( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace ) + : SvXMLImportContext( rImport ) + , m_rHints( rHints ) + , rIgnoreLeadingSpace( rIgnLeadSpace ) + , m_xStart( GetImport().GetTextImport()->GetCursorAsRange()->getStart() ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME) ) + { + m_sStyleName = aIter.toString(); + break; + } + } +} + +void XMLImpRubyContext_Impl::endFastElement(sal_Int32 ) +{ + const rtl::Reference < XMLTextImportHelper > xTextImport( + GetImport().GetTextImport()); + const Reference < XTextCursor > xAttrCursor( + xTextImport->GetText()->createTextCursorByRange( m_xStart )); + if (!xAttrCursor.is()) + { + SAL_WARN("xmloff.text", "cannot insert ruby"); + return; + } + xAttrCursor->gotoRange(xTextImport->GetCursorAsRange()->getStart(), + true); + xTextImport->SetRuby( GetImport(), xAttrCursor, + m_sStyleName, m_sTextStyleName, m_sText ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImpRubyContext_Impl::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + if( nElement == XML_ELEMENT(TEXT, XML_RUBY_BASE) ) + return new XMLImpRubyBaseContext_Impl( GetImport(), nElement, + xAttrList, + m_rHints, + rIgnoreLeadingSpace ); + else if( nElement == XML_ELEMENT(TEXT, XML_RUBY_TEXT) ) + return new XMLImpRubyTextContext_Impl( GetImport(), nElement, + xAttrList, + *this ); + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + +namespace { + +/** for text:meta and text:meta-field + */ +class XMLMetaImportContextBase : public SvXMLImportContext +{ + XMLHints_Impl& m_rHints; + + bool& m_rIgnoreLeadingSpace; + + /// start position + Reference<XTextRange> m_xStart; + +protected: + OUString m_XmlId; + +public: + + XMLMetaImportContextBase( + SvXMLImport& i_rImport, + const sal_Int32 nElement, + XMLHints_Impl& i_rHints, + bool & i_rIgnoreLeadingSpace ); + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const Reference<xml::sax::XFastAttributeList> & i_xAttrList) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL characters( const OUString& i_rChars ) override; + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter); + + virtual void InsertMeta(const Reference<XTextRange> & i_xInsertionRange) + = 0; +}; + +} + +XMLMetaImportContextBase::XMLMetaImportContextBase( + SvXMLImport& i_rImport, + const sal_Int32 /*i_nElement*/, + XMLHints_Impl& i_rHints, + bool & i_rIgnoreLeadingSpace ) + : SvXMLImportContext( i_rImport ) + , m_rHints( i_rHints ) + , m_rIgnoreLeadingSpace( i_rIgnoreLeadingSpace ) + , m_xStart( GetImport().GetTextImport()->GetCursorAsRange()->getStart() ) +{ +} + +void XMLMetaImportContextBase::startFastElement( + sal_Int32 /*nElement*/, + const Reference<xml::sax::XFastAttributeList> & xAttrList) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + ProcessAttribute(aIter); +} + +void XMLMetaImportContextBase::endFastElement(sal_Int32 ) +{ + SAL_WARN_IF(!m_xStart.is(), "xmloff.text", "no mxStart?"); + if (!m_xStart.is()) return; + + const Reference<XTextRange> xEndRange( + GetImport().GetTextImport()->GetCursorAsRange()->getStart() ); + + // create range for insertion + const Reference<XTextCursor> xInsertionCursor( + GetImport().GetTextImport()->GetText()->createTextCursorByRange( + xEndRange) ); + xInsertionCursor->gotoRange(m_xStart, true); + + InsertMeta(xInsertionCursor); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLMetaImportContextBase::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + return XMLImpSpanContext_Impl::CreateSpanContext( GetImport(), nElement, + xAttrList, m_rHints, m_rIgnoreLeadingSpace ); +} + +void XMLMetaImportContextBase::characters( const OUString& i_rChars ) +{ + GetImport().GetTextImport()->InsertString(i_rChars, m_rIgnoreLeadingSpace); +} + +void XMLMetaImportContextBase::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + if ( aIter.getToken() == XML_ELEMENT(XML, XML_ID) ) + m_XmlId = aIter.toString(); + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); +} + +namespace { + +/** text:meta */ +class XMLMetaImportContext : public XMLMetaImportContextBase +{ + // RDFa + bool m_bHaveAbout; + OUString m_sAbout; + OUString m_sProperty; + OUString m_sContent; + OUString m_sDatatype; + +public: + + XMLMetaImportContext( + SvXMLImport& i_rImport, + sal_Int32 nElement, + XMLHints_Impl& i_rHints, + bool & i_rIgnoreLeadingSpace ); + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override; + + virtual void InsertMeta(const Reference<XTextRange> & i_xInsertionRange) override; +}; + +} + +XMLMetaImportContext::XMLMetaImportContext( + SvXMLImport& i_rImport, + sal_Int32 nElement, + XMLHints_Impl& i_rHints, + bool & i_rIgnoreLeadingSpace ) + : XMLMetaImportContextBase( i_rImport, nElement, + i_rHints, i_rIgnoreLeadingSpace ) + , m_bHaveAbout(false) +{ +} + +void XMLMetaImportContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + switch (aIter.getToken()) + { + // RDFa + case XML_ELEMENT(XHTML, XML_ABOUT): + m_sAbout = aIter.toString(); + m_bHaveAbout = true; + break; + case XML_ELEMENT(XHTML, XML_PROPERTY): + m_sProperty = aIter.toString(); + break; + case XML_ELEMENT(XHTML, XML_CONTENT): + m_sContent = aIter.toString(); + break; + case XML_ELEMENT(XHTML, XML_DATATYPE): + m_sDatatype = aIter.toString(); + break; + default: + XMLMetaImportContextBase::ProcessAttribute(aIter); + } +} + +void XMLMetaImportContext::InsertMeta( + const Reference<XTextRange> & i_xInsertionRange) +{ + SAL_WARN_IF(m_bHaveAbout == m_sProperty.isEmpty(), "xmloff.text", "XMLMetaImportContext::InsertMeta: invalid RDFa?"); + if (!m_XmlId.isEmpty() || (m_bHaveAbout && !m_sProperty.isEmpty())) + { + // insert mark + const uno::Reference<rdf::XMetadatable> xMeta( + XMLTextMarkImportContext::CreateAndInsertMark( + GetImport(), + "com.sun.star.text.InContentMetadata", + OUString(), + i_xInsertionRange, m_XmlId), + uno::UNO_QUERY); + SAL_WARN_IF(!xMeta.is(), "xmloff.text", "cannot insert Meta?"); + + if (xMeta.is() && m_bHaveAbout) + { + GetImport().AddRDFa(xMeta, + m_sAbout, m_sProperty, m_sContent, m_sDatatype); + } + } + else + { + SAL_INFO("xmloff.text", "invalid <text:meta>: no xml:id, no valid RDFa"); + } +} + +namespace { + +/** text:meta-field */ +class XMLMetaFieldImportContext : public XMLMetaImportContextBase +{ + OUString m_DataStyleName; + +public: + + XMLMetaFieldImportContext( + SvXMLImport& i_rImport, + sal_Int32 nElement, + XMLHints_Impl& i_rHints, + bool & i_rIgnoreLeadingSpace ); + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override; + + virtual void InsertMeta(const Reference<XTextRange> & i_xInsertionRange) override; +}; + +} + +XMLMetaFieldImportContext::XMLMetaFieldImportContext( + SvXMLImport& i_rImport, + sal_Int32 nElement, + XMLHints_Impl& i_rHints, + bool & i_rIgnoreLeadingSpace ) + : XMLMetaImportContextBase( i_rImport, nElement, + i_rHints, i_rIgnoreLeadingSpace ) +{ +} + +void XMLMetaFieldImportContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME): + m_DataStyleName = aIter.toString(); + break; + default: + XMLMetaImportContextBase::ProcessAttribute(aIter); + } +} + +void XMLMetaFieldImportContext::InsertMeta( + const Reference<XTextRange> & i_xInsertionRange) +{ + if (!m_XmlId.isEmpty()) // valid? + { + // insert mark + const Reference<XPropertySet> xPropertySet( + XMLTextMarkImportContext::CreateAndInsertMark( + GetImport(), + "com.sun.star.text.textfield.MetadataField", + OUString(), + i_xInsertionRange, m_XmlId), + UNO_QUERY); + SAL_WARN_IF(!xPropertySet.is(), "xmloff.text", "cannot insert MetaField?"); + if (!xPropertySet.is()) return; + + if (!m_DataStyleName.isEmpty()) + { + bool isDefaultLanguage(true); + + const sal_Int32 nKey( GetImport().GetTextImport()->GetDataStyleKey( + m_DataStyleName, & isDefaultLanguage) ); + + if (-1 != nKey) + { + OUString sPropertyIsFixedLanguage("IsFixedLanguage"); + xPropertySet->setPropertyValue("NumberFormat", Any(nKey)); + if ( xPropertySet->getPropertySetInfo()-> + hasPropertyByName( sPropertyIsFixedLanguage ) ) + { + xPropertySet->setPropertyValue( sPropertyIsFixedLanguage, + Any(!isDefaultLanguage) ); + } + } + } + } + else + { + SAL_INFO("xmloff.text", "invalid <text:meta-field>: no xml:id"); + } +} + +namespace { + +/** + * Process index marks. + * + * All *-mark-end index marks should instantiate *this* class (because + * it doesn't process attributes other than ID), while the *-mark and + * *-mark-start classes should instantiate the appropriate subclasses. + */ +class XMLIndexMarkImportContext_Impl : public SvXMLImportContext +{ + XMLHints_Impl& m_rHints; + OUString sID; + +public: + + XMLIndexMarkImportContext_Impl( + SvXMLImport& rImport, + XMLHints_Impl& rHints); + + void SAL_CALL startFastElement(sal_Int32 nElement, const Reference<xml::sax::XFastAttributeList> & xAttrList) override; + +protected: + + /// process all attributes + void ProcessAttributes(sal_Int32 nElement, const Reference<xml::sax::XFastAttributeList> & xAttrList, + Reference<beans::XPropertySet>& rPropSet); + + /** + * All marks can be created immediately. Since we don't care about + * the element content, ProcessAttribute should set the properties + * immediately. + * + * This method tolerates an empty PropertySet; subclasses however + * are not expected to. + */ + virtual void ProcessAttribute(sal_Int32 nElement, + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter, + Reference<beans::XPropertySet>& rPropSet); + + static void GetServiceName(OUString& sServiceName, + sal_Int32 nElement); + + bool CreateMark(Reference<beans::XPropertySet>& rPropSet, + const OUString& rServiceName); +}; + +} + +XMLIndexMarkImportContext_Impl::XMLIndexMarkImportContext_Impl( + SvXMLImport& rImport, + XMLHints_Impl& rHints) + : SvXMLImportContext(rImport) + , m_rHints(rHints) +{ +} + +void XMLIndexMarkImportContext_Impl::startFastElement( + sal_Int32 nElement, + const Reference<xml::sax::XFastAttributeList> & xAttrList) +{ + // get Cursor position (needed for all cases) + Reference<XTextRange> xPos( + GetImport().GetTextImport()->GetCursor()->getStart()); + Reference<beans::XPropertySet> xMark; + + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_TOC_MARK): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK): + { + // single mark: create mark and insert + OUString sService; + GetServiceName(sService, nElement); + if (CreateMark(xMark, sService)) + { + ProcessAttributes(nElement, xAttrList, xMark); + m_rHints.push_back( + std::make_unique<XMLIndexMarkHint_Impl>(xMark, xPos)); + } + // else: can't create mark -> ignore + break; + } + + case XML_ELEMENT(TEXT, XML_TOC_MARK_START): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_START): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_START): + { + // start: create mark and insert (if ID is found) + OUString sService; + GetServiceName(sService, nElement); + if (CreateMark(xMark, sService)) + { + ProcessAttributes(nElement, xAttrList, xMark); + if (!sID.isEmpty()) + { + // process only if we find an ID + m_rHints.push_back( + std::make_unique<XMLIndexMarkHint_Impl>(xMark, xPos, sID)); + } + // else: no ID -> we'll never find the end -> ignore + } + // else: can't create mark -> ignore + break; + } + + case XML_ELEMENT(TEXT, XML_TOC_MARK_END): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_END): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_END): + { + // end: search for ID and set end of mark + + // call process attributes with empty XPropertySet: + ProcessAttributes(nElement, xAttrList, xMark); + if (!sID.isEmpty()) + { + // if we have an ID, find the hint and set the end position + XMLIndexMarkHint_Impl *const pHint = m_rHints.GetIndexHintById(sID); + if (pHint) + // set end and stop searching + pHint->SetEnd(xPos); + } + // else: no ID -> ignore + break; + } + + default: + SAL_WARN("xmloff.text", "unknown index mark type!"); + break; + } +} + +void XMLIndexMarkImportContext_Impl::ProcessAttributes( + sal_Int32 nElement, + const Reference<xml::sax::XFastAttributeList> & xAttrList, + Reference<beans::XPropertySet>& rPropSet) +{ + // process attributes + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + ProcessAttribute(nElement, aIter, rPropSet); + } +} + +void XMLIndexMarkImportContext_Impl::ProcessAttribute( + sal_Int32 nElement, + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter, + Reference<beans::XPropertySet>& rPropSet) +{ + // we only know ID + string-value attribute; + // (former: marks, latter: -start + -end-marks) + // the remainder is handled in sub-classes + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_TOC_MARK): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK): + if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_STRING_VALUE) ) + { + rPropSet->setPropertyValue("AlternativeText", uno::Any(aIter.toString())); + } + // else: ignore! + break; + + case XML_ELEMENT(TEXT, XML_TOC_MARK_START): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_START): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_START): + case XML_ELEMENT(TEXT, XML_TOC_MARK_END): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_END): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_END): + if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_ID) ) + { + sID = aIter.toString(); + } + // else: ignore + break; + + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + break; + } +} + + +void XMLIndexMarkImportContext_Impl::GetServiceName( + OUString& sServiceName, + sal_Int32 nElement) +{ + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_TOC_MARK): + case XML_ELEMENT(TEXT, XML_TOC_MARK_START): + case XML_ELEMENT(TEXT, XML_TOC_MARK_END): + { + sServiceName = "com.sun.star.text.ContentIndexMark"; + break; + } + + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_START): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_END): + { + sServiceName = "com.sun.star.text.UserIndexMark"; + break; + } + + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_START): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_END): + { + sServiceName = "com.sun.star.text.DocumentIndexMark"; + break; + } + + default: + { + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + sServiceName.clear(); + break; + } + } +} + +bool XMLIndexMarkImportContext_Impl::CreateMark( + Reference<beans::XPropertySet>& rPropSet, + const OUString& rServiceName) +{ + Reference<lang::XMultiServiceFactory> + xFactory(GetImport().GetModel(), UNO_QUERY); + + if( xFactory.is() ) + { + Reference<beans::XPropertySet> xPropSet( xFactory->createInstance(rServiceName), UNO_QUERY ); + if (xPropSet.is()) + rPropSet = xPropSet; + return true; + } + + return false; +} + +namespace { + +class XMLTOCMarkImportContext_Impl : public XMLIndexMarkImportContext_Impl +{ +public: + + XMLTOCMarkImportContext_Impl( + SvXMLImport& rImport, + XMLHints_Impl& rHints); + +protected: + + /** process outline level */ + virtual void ProcessAttribute(sal_Int32 nElement, + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter, + Reference<beans::XPropertySet>& rPropSet) override; +}; + +} + +XMLTOCMarkImportContext_Impl::XMLTOCMarkImportContext_Impl( + SvXMLImport& rImport, XMLHints_Impl& rHints) : + XMLIndexMarkImportContext_Impl(rImport, rHints) +{ +} + +void XMLTOCMarkImportContext_Impl::ProcessAttribute( + sal_Int32 nElement, + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter, + Reference<beans::XPropertySet>& rPropSet) +{ + SAL_WARN_IF(!rPropSet.is(), "xmloff.text", "need PropertySet"); + + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL): + { + // outline level: set Level property + sal_Int32 nTmp; + if (::sax::Converter::convertNumber( nTmp, aIter.toView() ) + && nTmp >= 1 + && nTmp < GetImport().GetTextImport()-> + GetChapterNumbering()->getCount() ) + { + rPropSet->setPropertyValue("Level", uno::Any(static_cast<sal_Int16>(nTmp - 1))); + } + // else: value out of range -> ignore + break; + } + default: + // else: delegate to superclass + XMLIndexMarkImportContext_Impl::ProcessAttribute( + nElement, aIter, rPropSet); + } +} + +namespace { + +class XMLUserIndexMarkImportContext_Impl : public XMLIndexMarkImportContext_Impl +{ +public: + + XMLUserIndexMarkImportContext_Impl( + SvXMLImport& rImport, + XMLHints_Impl& rHints); + +protected: + + /** process index name */ + virtual void ProcessAttribute(sal_Int32 nElement, + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter, + Reference<beans::XPropertySet>& rPropSet) override; +}; + +} + +XMLUserIndexMarkImportContext_Impl::XMLUserIndexMarkImportContext_Impl( + SvXMLImport& rImport, XMLHints_Impl& rHints) : + XMLIndexMarkImportContext_Impl(rImport, rHints) +{ +} + +void XMLUserIndexMarkImportContext_Impl::ProcessAttribute( + sal_Int32 nElement, + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter, + Reference<beans::XPropertySet>& rPropSet) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_INDEX_NAME): + rPropSet->setPropertyValue("UserIndexName", uno::Any(aIter.toString())); + break; + case XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL): + { + // outline level: set Level property + sal_Int32 nTmp; + if (::sax::Converter::convertNumber( + nTmp, aIter.toView(), 0, + GetImport().GetTextImport()->GetChapterNumbering()->getCount())) + { + rPropSet->setPropertyValue("Level", uno::Any(static_cast<sal_Int16>(nTmp - 1))); + } + // else: value out of range -> ignore + break; + } + default: + // else: unknown text property: delegate to super class + XMLIndexMarkImportContext_Impl::ProcessAttribute( + nElement, aIter, rPropSet); + } +} + +namespace { + +class XMLAlphaIndexMarkImportContext_Impl : public XMLIndexMarkImportContext_Impl +{ +public: + + XMLAlphaIndexMarkImportContext_Impl( + SvXMLImport& rImport, + XMLHints_Impl& rHints); + +protected: + + /** process primary + secondary keys */ + virtual void ProcessAttribute(sal_Int32 nElement, + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter, + Reference<beans::XPropertySet>& rPropSet) override; +}; + +} + +XMLAlphaIndexMarkImportContext_Impl::XMLAlphaIndexMarkImportContext_Impl( + SvXMLImport& rImport, XMLHints_Impl& rHints) : + XMLIndexMarkImportContext_Impl(rImport, rHints) +{ +} + +void XMLAlphaIndexMarkImportContext_Impl::ProcessAttribute( + sal_Int32 nElement, + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter, + Reference<beans::XPropertySet>& rPropSet) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_KEY1): + rPropSet->setPropertyValue("PrimaryKey", uno::Any(aIter.toString())); + break; + case XML_ELEMENT(TEXT, XML_KEY2): + rPropSet->setPropertyValue("SecondaryKey", uno::Any(aIter.toString())); + break; + case XML_ELEMENT(TEXT, XML_KEY1_PHONETIC): + rPropSet->setPropertyValue("PrimaryKeyReading", uno::Any(aIter.toString())); + break; + case XML_ELEMENT(TEXT, XML_KEY2_PHONETIC): + rPropSet->setPropertyValue("SecondaryKeyReading", uno::Any(aIter.toString())); + break; + case XML_ELEMENT(TEXT, XML_STRING_VALUE_PHONETIC): + rPropSet->setPropertyValue("TextReading", uno::Any(aIter.toString())); + break; + case XML_ELEMENT(TEXT, XML_MAIN_ENTRY): + { + bool bMainEntry = false; + bool bTmp(false); + + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + bMainEntry = bTmp; + + rPropSet->setPropertyValue("IsMainEntry", uno::Any(bMainEntry)); + break; + } + default: + XMLIndexMarkImportContext_Impl::ProcessAttribute( + nElement, aIter, rPropSet); + } +} + + +XMLImpSpanContext_Impl::XMLImpSpanContext_Impl( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace, + sal_uInt8 nSFConvFlags) +: SvXMLImportContext( rImport ) +, m_rHints( rHints ) +, pHint( nullptr ) +, rIgnoreLeadingSpace( rIgnLeadSpace ) +, nStarFontsConvFlags( nSFConvFlags & (CONV_FROM_STAR_BATS|CONV_FROM_STAR_MATH) ) +{ + OUString aStyleName; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME) ) + { + aStyleName = aIter.toString(); + break; + } + } + + if( !aStyleName.isEmpty() ) + { + pHint = new XMLStyleHint_Impl( aStyleName, + GetImport().GetTextImport()->GetCursorAsRange()->getStart() ); + m_rHints.push_back(std::unique_ptr<XMLStyleHint_Impl>(pHint)); + } +} + +void XMLImpSpanContext_Impl::endFastElement(sal_Int32 ) +{ + if (!pHint) + return; + + Reference<XTextRange> xCrsrRange(GetImport().GetTextImport()->GetCursorAsRange()); + if (!xCrsrRange.is()) + return; // Robust (defective file) + + pHint->SetEnd(xCrsrRange->getStart()); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImpSpanContext_Impl::CreateSpanContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnoreLeadingSpace, + sal_uInt8 nStarFontsConvFlags + ) +{ + SvXMLImportContext *pContext = nullptr; + + switch( nElement ) + { + case XML_ELEMENT(TEXT, XML_SPAN): + pContext = new XMLImpSpanContext_Impl( rImport, nElement, + xAttrList, + rHints, + rIgnoreLeadingSpace + ,nStarFontsConvFlags + ); + break; + + case XML_ELEMENT(TEXT, XML_TAB): + pContext = new XMLCharContext( rImport, xAttrList, + 0x0009, false ); + rIgnoreLeadingSpace = false; + break; + + case XML_ELEMENT(TEXT, XML_LINE_BREAK): + if (xAttrList->hasAttribute(XML_ELEMENT(LO_EXT, XML_CLEAR))) + { + pContext = new SvXMLLineBreakContext(rImport, *rImport.GetTextImport()); + } + else + { + pContext = new XMLCharContext(rImport, ControlCharacter::LINE_BREAK); + } + rIgnoreLeadingSpace = false; + break; + + case XML_ELEMENT(TEXT, XML_S): + pContext = new XMLCharContext( rImport, xAttrList, 0x0020, true ); + rIgnoreLeadingSpace = false; + break; + + case XML_ELEMENT(TEXT, XML_A): + { + // test for HyperLinkURL property. If present, insert link as + // text property (StarWriter), else try to insert as text + // field (StarCalc, StarDraw, ...) + Reference< beans::XPropertySet > xPropSet( rImport.GetTextImport()->GetCursor(), UNO_QUERY ); + + if ( xPropSet->getPropertySetInfo()->hasPropertyByName( "HyperLinkURL" ) ) + { + pContext = new XMLImpHyperlinkContext_Impl( + rImport, + nElement, + xAttrList, + rHints, + rIgnoreLeadingSpace ); + } + else + { + pContext = new XMLUrlFieldImportContext(rImport, *rImport.GetTextImport()); + //whitespace handling like other fields + rIgnoreLeadingSpace = false; + + } + break; + } + + case XML_ELEMENT(TEXT, XML_RUBY): + pContext = new XMLImpRubyContext_Impl( rImport, nElement, + xAttrList, + rHints, + rIgnoreLeadingSpace ); + break; + + case XML_ELEMENT(TEXT, XML_NOTE): + if (rImport.GetTextImport()->IsInFrame()) + { + // we must not insert footnotes into text frames + pContext = new SvXMLImportContext( rImport ); + } + else + { + pContext = new XMLFootnoteImportContext(rImport, *rImport.GetTextImport()); + } + rIgnoreLeadingSpace = false; + break; + + case XML_ELEMENT(TEXT, XML_REFERENCE_MARK): + case XML_ELEMENT(TEXT, XML_BOOKMARK): + case XML_ELEMENT(TEXT, XML_BOOKMARK_START): + case XML_ELEMENT(TEXT, XML_BOOKMARK_END): + pContext = new XMLTextMarkImportContext(rImport, *rImport.GetTextImport(), + rHints.GetCrossRefHeadingBookmark()); + break; + + case XML_ELEMENT(FIELD, XML_FIELDMARK): + case XML_ELEMENT(FIELD, XML_FIELDMARK_START): + case XML_ELEMENT(FIELD, XML_FIELDMARK_SEPARATOR): + case XML_ELEMENT(FIELD, XML_FIELDMARK_END): + pContext = new XMLTextMarkImportContext(rImport, *rImport.GetTextImport(), + rHints.GetCrossRefHeadingBookmark()); + break; + + case XML_ELEMENT(TEXT, XML_REFERENCE_MARK_START): + pContext = new XMLStartReferenceContext_Impl( rImport, + rHints, xAttrList ); + break; + + case XML_ELEMENT(TEXT, XML_REFERENCE_MARK_END): + pContext = new XMLEndReferenceContext_Impl( rImport, + rHints, xAttrList ); + break; + + case XML_ELEMENT(DRAW, XML_FRAME): + { + Reference < XTextRange > xAnchorPos = + rImport.GetTextImport()->GetCursor()->getStart(); + XMLTextFrameContext *pTextFrameContext = + new XMLTextFrameContext(rImport, + xAttrList, + TextContentAnchorType_AS_CHARACTER ); + // Remove check for text content. (#i33242#) + // Check for text content is done on the processing of the hint + if( TextContentAnchorType_AT_CHARACTER == + pTextFrameContext->GetAnchorType() ) + { + rHints.push_back(std::make_unique<XMLTextFrameHint_Impl>( + pTextFrameContext, xAnchorPos)); + } + pContext = pTextFrameContext; + rIgnoreLeadingSpace = false; + } + break; + case XML_ELEMENT(DRAW, XML_A): + { + Reference < XTextRange > xAnchorPos(rImport.GetTextImport()->GetCursor()->getStart()); + pContext = + new XMLTextFrameHyperlinkContext( rImport, nElement, + xAttrList, + TextContentAnchorType_AS_CHARACTER ); + rHints.push_back( + std::make_unique<XMLTextFrameHint_Impl>(pContext, xAnchorPos)); + } + break; + + case XML_ELEMENT(TEXT, XML_TOC_MARK): + case XML_ELEMENT(TEXT, XML_TOC_MARK_START): + pContext = new XMLTOCMarkImportContext_Impl( + rImport, rHints); + break; + + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_START): + pContext = new XMLUserIndexMarkImportContext_Impl( + rImport, rHints); + break; + + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_START): + pContext = new XMLAlphaIndexMarkImportContext_Impl( + rImport, rHints); + break; + + case XML_ELEMENT(TEXT, XML_TOC_MARK_END): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_END): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_END): + pContext = new XMLIndexMarkImportContext_Impl( + rImport, rHints); + break; + + case XML_ELEMENT(TEXT, XML_CHANGE_START): + case XML_ELEMENT(TEXT, XML_CHANGE_END): + case XML_ELEMENT(TEXT, XML_CHANGE): + pContext = new XMLChangeImportContext( + rImport, + ((nElement == XML_ELEMENT(TEXT, XML_CHANGE_END)) + ? XMLChangeImportContext::Element::END + : (nElement == XML_ELEMENT(TEXT, XML_CHANGE_START)) + ? XMLChangeImportContext::Element::START + : XMLChangeImportContext::Element::POINT), + false); + break; + + case XML_ELEMENT(TEXT, XML_META): + pContext = new XMLMetaImportContext(rImport, nElement, + rHints, rIgnoreLeadingSpace ); + break; + + case XML_ELEMENT(TEXT, XML_META_FIELD): + pContext = new XMLMetaFieldImportContext(rImport, nElement, + rHints, rIgnoreLeadingSpace ); + break; + + case XML_ELEMENT(LO_EXT, XML_CONTENT_CONTROL): + pContext = new XMLContentControlContext(rImport, nElement, rHints, rIgnoreLeadingSpace); + break; + + default: + // none of the above? then it's probably a text field! + pContext = XMLTextFieldImportContext::CreateTextFieldImportContext( + rImport, *rImport.GetTextImport(), nElement); + // #108784# import draw elements (except control shapes in headers) + if( pContext == nullptr && + !( rImport.GetTextImport()->IsInHeaderFooter() && + nElement == XML_ELEMENT(DRAW, XML_CONTROL ) ) ) + { + Reference < XShapes > xShapes; + SvXMLShapeContext* pShapeContext = XMLShapeImportHelper::CreateGroupChildContext( + rImport, nElement, xAttrList, xShapes ); + pContext = pShapeContext; + // OD 2004-04-20 #i26791# - keep shape in a text frame hint to + // adjust its anchor position, if it's at-character anchored + Reference < XTextRange > xAnchorPos = + rImport.GetTextImport()->GetCursor()->getStart(); + rHints.push_back( + std::make_unique<XMLDrawHint_Impl>(pShapeContext, xAnchorPos)); + } + // Behind fields, shapes and any unknown content blanks aren't ignored + rIgnoreLeadingSpace = false; + } + + if (!pContext) + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return pContext; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImpSpanContext_Impl::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + return CreateSpanContext( GetImport(), nElement, xAttrList, + m_rHints, rIgnoreLeadingSpace + ,nStarFontsConvFlags + ); +} + +void XMLImpSpanContext_Impl::characters( const OUString& rChars ) +{ + OUString sStyleName; + if( pHint ) + sStyleName = pHint->GetStyleName(); + OUString sChars = + GetImport().GetTextImport()->ConvertStarFonts( rChars, sStyleName, + nStarFontsConvFlags, + false, GetImport() ); + GetImport().GetTextImport()->InsertString( sChars, rIgnoreLeadingSpace ); +} + + +XMLParaContext::XMLParaContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList ) : + SvXMLImportContext( rImport ), + xStart( rImport.GetTextImport()->GetCursorAsRange()->getStart() ), + m_bHaveAbout(false), + nOutlineLevel( (nElement & TOKEN_MASK) == XML_H ? 1 : -1 ), + // Lost outline numbering in master document (#i73509#) + mbOutlineLevelAttrFound( false ), + mbOutlineContentVisible(true), + bIgnoreLeadingSpace( true ), + bHeading( (nElement & TOKEN_MASK) == XML_H ), + bIsListHeader( false ), + bIsRestart (false), + nStartValue(0), + nStarFontsConvFlags( 0 ) +{ + bool bHaveXmlId( false ); + OUString aCondStyleName; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(XML, XML_ID): + m_sXmlId = aIter.toString(); + bHaveXmlId = true; + break; + case XML_ELEMENT(XHTML, XML_ABOUT): + m_sAbout = aIter.toString(); + m_bHaveAbout = true; + break; + case XML_ELEMENT(XHTML, XML_PROPERTY): + m_sProperty = aIter.toString(); + break; + case XML_ELEMENT(XHTML, XML_CONTENT): + m_sContent = aIter.toString(); + break; + case XML_ELEMENT(XHTML, XML_DATATYPE): + m_sDatatype = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_ID): + if (!bHaveXmlId) { m_sXmlId = aIter.toString(); } + break; + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + sStyleName = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_COND_STYLE_NAME): + aCondStyleName = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL): + { + sal_Int32 nTmp = aIter.toInt32(); + if( nTmp > 0 ) + { + if( nTmp > 127 ) + nTmp = 127; + nOutlineLevel = static_cast<sal_Int8>(nTmp); + } + // Lost outline numbering in master document (#i73509#) + mbOutlineLevelAttrFound = true; + } + break; + case XML_ELEMENT(LO_EXT, XML_OUTLINE_CONTENT_VISIBLE): + { + bool bBool(false); + if (::sax::Converter::convertBool(bBool, aIter.toView())) + mbOutlineContentVisible = bBool; + } + break; + case XML_ELEMENT(TEXT, XML_IS_LIST_HEADER): + { + bool bBool(false); + if (::sax::Converter::convertBool(bBool, aIter.toView())) + bIsListHeader = bBool; + } + break; + case XML_ELEMENT(TEXT, XML_RESTART_NUMBERING): + { + bool bBool(false); + if (::sax::Converter::convertBool(bBool, aIter.toView())) + bIsRestart = bBool; + } + break; + case XML_ELEMENT(TEXT, XML_START_VALUE): + { + nStartValue = sal::static_int_cast< sal_Int16 >(aIter.toInt32()); + } + break; + case XML_ELEMENT(LO_EXT, XML_MARKER_STYLE_NAME): + if (auto pStyle = rImport.GetTextImport()->FindAutoCharStyle(aIter.toString())) + m_aMarkerStyleName = pStyle->GetAutoName(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( !aCondStyleName.isEmpty() ) + sStyleName = aCondStyleName; +} + +void XMLParaContext::endFastElement(sal_Int32 ) +{ + rtl::Reference < XMLTextImportHelper > xTxtImport( + GetImport().GetTextImport()); + Reference<XTextRange> xEnd; + try + { + Reference<XTextRange> const xCrsrRange(xTxtImport->GetCursorAsRange()); + if (!xCrsrRange.is()) + return; // Robust (defective file) + xEnd = xCrsrRange->getStart(); + } + catch (uno::Exception const&) + { + SAL_INFO("xmloff.text", "XMLParaContext: cursor disposed?"); + return; + } + + // if we have an id set for this paragraph, get a cursor for this + // paragraph and register it with the given identifier + // FIXME: this is just temporary, and should be removed when + // EditEngine paragraphs implement XMetadatable! + if (!m_sXmlId.isEmpty()) + { + Reference < XTextCursor > xIdCursor( xTxtImport->GetText()->createTextCursorByRange( xStart ) ); + if( xIdCursor.is() ) + { + xIdCursor->gotoRange( xEnd, true ); + GetImport().getInterfaceToIdentifierMapper().registerReference( + m_sXmlId, Reference<XInterface>( xIdCursor, UNO_QUERY )); + } + } + + // insert a paragraph break + xTxtImport->InsertControlCharacter( ControlCharacter::APPEND_PARAGRAPH ); + + // create a cursor that select the whole last paragraph + Reference < XTextCursor > xAttrCursor; + try { + xAttrCursor = xTxtImport->GetText()->createTextCursorByRange( xStart ); + if( !xAttrCursor.is() ) + return; // Robust (defective file) + } catch (const uno::Exception &) { + // createTextCursorByRange() likes to throw runtime exception, even + // though it just means 'we were unable to create the cursor' + return; + } + xAttrCursor->gotoRange( xEnd, true ); + + // xml:id for RDF metadata + if (!m_sXmlId.isEmpty() || m_bHaveAbout || !m_sProperty.isEmpty()) + { + try { + const uno::Reference<container::XEnumerationAccess> xEA + (xAttrCursor, uno::UNO_QUERY_THROW); + const uno::Reference<container::XEnumeration> xEnum( + xEA->createEnumeration(), uno::UNO_SET_THROW); + SAL_WARN_IF(!xEnum->hasMoreElements(), "xmloff.text", "xml:id: no paragraph?"); + if (xEnum->hasMoreElements()) { + uno::Reference<rdf::XMetadatable> xMeta; + xEnum->nextElement() >>= xMeta; + SAL_WARN_IF(!xMeta.is(), "xmloff.text", "xml:id: not XMetadatable"); + GetImport().SetXmlId(xMeta, m_sXmlId); + if (m_bHaveAbout) + { + GetImport().AddRDFa(xMeta, + m_sAbout, m_sProperty, m_sContent, m_sDatatype); + } + SAL_WARN_IF(xEnum->hasMoreElements(), "xmloff.text", "xml:id: > 1 paragraph?"); + } + } catch (const uno::Exception &) { + SAL_INFO("xmloff.text", "XMLParaContext::~XMLParaContext: exception"); + } + } + + OUString const sCellParaStyleName(xTxtImport->GetCellParaStyleDefault()); + if( !sCellParaStyleName.isEmpty() ) + { + /* Suppress handling of outline and list attributes, + because of side effects of method <SetStyleAndAttrs(..)> (#i80724#) + */ + xTxtImport->SetStyleAndAttrs( GetImport(), xAttrCursor, + sCellParaStyleName, + true, + false, -1, // suppress outline handling + false ); // suppress list attributes handling + } + + // #103445# for headings without style name, find the proper style + if( bHeading && sStyleName.isEmpty() ) + xTxtImport->FindOutlineStyleName( sStyleName, nOutlineLevel ); + + // set style and hard attributes at the previous paragraph + // Add parameter <mbOutlineLevelAttrFound> (#i73509#) + sStyleName = xTxtImport->SetStyleAndAttrs( GetImport(), xAttrCursor, + sStyleName, + true, + mbOutlineLevelAttrFound, + bHeading ? nOutlineLevel : -1, + true, + mbOutlineContentVisible); + + if (m_aMarkerStyleName.hasValue()) + { + if (auto xPropSet = xStart.query<css::beans::XPropertySet>()) + { + try + { + xPropSet->setPropertyValue("ListAutoFormat", m_aMarkerStyleName); + } + catch (const css::beans::UnknownPropertyException&) + { + // no problem + } + } + } + + // handle list style header + if (bHeading && (bIsListHeader || bIsRestart)) + { + Reference<XPropertySet> xPropSet( xAttrCursor, UNO_QUERY ); + + if (xPropSet.is()) + { + if (bIsListHeader) + { + OUString sNumberingIsNumber + ("NumberingIsNumber"); + if(xPropSet->getPropertySetInfo()-> + hasPropertyByName(sNumberingIsNumber)) + { + xPropSet->setPropertyValue + (sNumberingIsNumber, Any( false ) ); + } + } + if (bIsRestart) + { + OUString sParaIsNumberingRestart + ("ParaIsNumberingRestart"); + OUString sNumberingStartValue + ("NumberingStartValue"); + if (xPropSet->getPropertySetInfo()-> + hasPropertyByName(sParaIsNumberingRestart)) + { + xPropSet->setPropertyValue + (sParaIsNumberingRestart, Any(true)); + } + + if (xPropSet->getPropertySetInfo()-> + hasPropertyByName(sNumberingStartValue)) + { + xPropSet->setPropertyValue + (sNumberingStartValue, Any(nStartValue)); + } + } + + } + } + + if (m_xHints) + { + bool bSetNoFormatAttr = false; + uno::Reference<beans::XPropertySet> xCursorProps(xAttrCursor, uno::UNO_QUERY); + int nEmptyHints = 0; + uno::Reference<text::XTextRangeCompare> xCompare(xTxtImport->GetText(), uno::UNO_QUERY); + if (xCompare.is()) + { + try + { + for (const auto& pHint : m_xHints->GetHints()) + { + if (xCompare->compareRegionStarts(pHint->GetStart(), pHint->GetEnd()) == 0) + { + ++nEmptyHints; + } + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.text", ""); + } + } + if (nEmptyHints > 0 || m_aMarkerStyleName.hasValue()) + { + // We have at least one empty hint, then make try to ask the cursor to not upgrade our character + // attributes to paragraph-level formatting, which would lead to incorrect rendering. + uno::Reference<beans::XPropertySetInfo> xCursorPropsInfo = xCursorProps->getPropertySetInfo(); + bSetNoFormatAttr = xCursorPropsInfo->hasPropertyByName("NoFormatAttr"); + } + if (bSetNoFormatAttr) + { + xCursorProps->setPropertyValue("NoFormatAttr", uno::Any(true)); + } + for (const auto & i : m_xHints->GetHints()) + { + XMLHint_Impl *const pHint = i.get(); + xAttrCursor->gotoRange( pHint->GetStart(), false ); + xAttrCursor->gotoRange( pHint->GetEnd(), true ); + switch( pHint->GetType() ) + { + case XMLHintType::XML_HINT_STYLE: + { + const OUString& rStyleName = + static_cast<XMLStyleHint_Impl *>(pHint)->GetStyleName(); + if( !rStyleName.isEmpty() ) + xTxtImport->SetStyleAndAttrs( GetImport(), + xAttrCursor, rStyleName, + false ); + } + break; + case XMLHintType::XML_HINT_REFERENCE: + { + const OUString& rRefName = + static_cast<XMLReferenceHint_Impl *>(pHint)->GetRefName(); + if( !rRefName.isEmpty() ) + { + if( !pHint->GetEnd().is() ) + pHint->SetEnd(xEnd); + + // reference name uses rStyleName member + // borrow from XMLTextMarkImportContext + XMLTextMarkImportContext::CreateAndInsertMark( + GetImport(), + "com.sun.star.text.ReferenceMark", + rRefName, + xAttrCursor); + } + } + break; + case XMLHintType::XML_HINT_HYPERLINK: + { + const XMLHyperlinkHint_Impl *pHHint = + static_cast<const XMLHyperlinkHint_Impl *>(pHint); + xTxtImport->SetHyperlink( GetImport(), + xAttrCursor, + pHHint->GetHRef(), + pHHint->GetName(), + pHHint->GetTargetFrameName(), + pHHint->GetStyleName(), + pHHint->GetVisitedStyleName(), + pHHint->GetEventsContext() ); + } + break; + case XMLHintType::XML_HINT_INDEX_MARK: + { + Reference<beans::XPropertySet> xMark( + static_cast<const XMLIndexMarkHint_Impl *>(pHint)->GetMark()); + Reference<XTextContent> xContent(xMark, UNO_QUERY); + try + { + xTxtImport->GetText()->insertTextContent( + xAttrCursor, xContent, true ); + } + catch (uno::RuntimeException const&) + { + TOOLS_INFO_EXCEPTION("xmloff.text", "could not insert index mark, presumably in editengine text"); + } + } + break; + case XMLHintType::XML_HINT_TEXT_FRAME: + { + const XMLTextFrameHint_Impl *pFHint = + static_cast<const XMLTextFrameHint_Impl *>(pHint); + // Check for text content (#i33242#) + Reference < XTextContent > xTextContent = + pFHint->GetTextContent(); + if ( xTextContent.is() ) + { + /* Core impl. of the unification of drawing objects and + Writer fly frames (#i26791#) + */ + if ( pFHint->IsBoundAtChar() ) + { + xTextContent->attach( xAttrCursor ); + } + } + /* Consider, that hint can also contain a shape - + e.g. drawing object of type 'Text'. (#i33242#) + */ + else + { + Reference < XShape > xShape = pFHint->GetShape(); + if ( xShape.is() ) + { + // determine anchor type + Reference < XPropertySet > xPropSet( xShape, UNO_QUERY ); + TextContentAnchorType eAnchorType = + TextContentAnchorType_AT_PARAGRAPH; + { + Any aAny = xPropSet->getPropertyValue( "AnchorType" ); + aAny >>= eAnchorType; + } + if ( TextContentAnchorType_AT_CHARACTER == eAnchorType ) + { + // set anchor position for at-character anchored objects + xPropSet->setPropertyValue("TextRange", Any(xAttrCursor)); + } + } + } + } + break; + /* Core impl. of the unification of drawing objects and + Writer fly frames (#i26791#) + */ + case XMLHintType::XML_HINT_DRAW: + { + const XMLDrawHint_Impl *pDHint = + static_cast<const XMLDrawHint_Impl*>(pHint); + // Improvement: hint directly provides the shape. (#i33242#) + const Reference < XShape >& xShape = pDHint->GetShape(); + if ( xShape.is() ) + { + // determine anchor type + Reference < XPropertySet > xPropSet( xShape, UNO_QUERY ); + TextContentAnchorType eAnchorType = TextContentAnchorType_AT_PARAGRAPH; + { + Any aAny = xPropSet->getPropertyValue( "AnchorType" ); + aAny >>= eAnchorType; + } + if ( TextContentAnchorType_AT_CHARACTER == eAnchorType ) + { + // set anchor position for at-character anchored objects + xPropSet->setPropertyValue("TextRange", Any(xAttrCursor)); + } + } + } + break; + default: + SAL_WARN( "xmloff.text", "What's this" ); + break; + } + } + if (bSetNoFormatAttr) + { + xCursorProps->setPropertyValue("NoFormatAttr", uno::Any(false)); + } + } + m_xHints.reset(); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLParaContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if (!m_xHints) + m_xHints.reset(new XMLHints_Impl); + return XMLImpSpanContext_Impl::CreateSpanContext( + GetImport(), nElement, xAttrList, + *m_xHints, bIgnoreLeadingSpace, + nStarFontsConvFlags); +} + +void XMLParaContext::characters( const OUString& rChars ) +{ + OUString sChars = + GetImport().GetTextImport()->ConvertStarFonts( rChars, sStyleName, + nStarFontsConvFlags, + true, GetImport() ); + GetImport().GetTextImport()->InsertString( sChars, bIgnoreLeadingSpace ); +} + + +XMLNumberedParaContext::XMLNumberedParaContext( + SvXMLImport& i_rImport, + sal_Int32 /*nElement*/, + const Reference< xml::sax::XFastAttributeList > & xAttrList ) : + SvXMLImportContext( i_rImport ), + m_Level(0), + m_StartValue(-1) +{ + OUString StyleName; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(XML, XML_ID): +//FIXME: there is no UNO API for lists + break; + case XML_ELEMENT(TEXT, XML_LIST_ID): + m_ListId = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_LEVEL): + { + sal_Int32 nTmp = aIter.toInt32(); + if ( nTmp >= 1 && nTmp <= SHRT_MAX ) { + m_Level = static_cast<sal_uInt16>(nTmp) - 1; + } + } + break; + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + StyleName = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_CONTINUE_NUMBERING): + // this attribute is deprecated +// ContinueNumbering = IsXMLToken(sValue, XML_TRUE); + break; + case XML_ELEMENT(TEXT, XML_START_VALUE): + { + sal_Int32 nTmp = aIter.toInt32(); + if ( nTmp >= 0 && nTmp <= SHRT_MAX ) { + m_StartValue = static_cast<sal_Int16>(nTmp); + } + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + XMLTextListsHelper& rTextListsHelper( + i_rImport.GetTextImport()->GetTextListHelper() ); + if (m_ListId.isEmpty()) + { + SAL_WARN_IF(0 <= i_rImport.GetODFVersion().compareTo(u"1.2"), "xmloff.text", "invalid numbered-paragraph: no list-id (1.2)"); + m_ListId = rTextListsHelper.GetNumberedParagraphListId(m_Level, + StyleName); + SAL_WARN_IF(m_ListId.isEmpty(), "xmloff.text", "numbered-paragraph: no ListId"); + if (m_ListId.isEmpty()) { + return; + } + } + m_xNumRules = rTextListsHelper.EnsureNumberedParagraph( i_rImport, + m_ListId, m_Level, StyleName); + + SAL_WARN_IF(!m_xNumRules.is(), "xmloff.text", "numbered-paragraph: no NumRules"); + + i_rImport.GetTextImport()->GetTextListHelper().PushListContext( this ); +} + +void XMLNumberedParaContext::endFastElement(sal_Int32 ) +{ + if (!m_ListId.isEmpty()) { + GetImport().GetTextImport()->PopListContext(); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLNumberedParaContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_H): + case XML_ELEMENT(LO_EXT, XML_H): + case XML_ELEMENT(TEXT, XML_P): + case XML_ELEMENT(LO_EXT, XML_P): + return new XMLParaContext( GetImport(), nElement, xAttrList ); + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtparai.hxx b/xmloff/source/text/txtparai.hxx new file mode 100644 index 0000000000..fed2690cb4 --- /dev/null +++ b/xmloff/source/text/txtparai.hxx @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + + +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/uno/Reference.h> +#include <xmloff/xmlictxt.hxx> + +class XMLHints_Impl; +namespace com::sun::star { + namespace text { class XTextRange; } + namespace xml::sax { class XAttributeList; } +} + +#define CONV_FROM_STAR_BATS 1 +#define CONV_FROM_STAR_MATH 2 +#define CONV_STAR_FONT_FLAGS_VALID 4 + +class XMLParaContext : public SvXMLImportContext +{ + css::uno::Reference < css::text::XTextRange > xStart; + OUString sStyleName; + OUString m_sXmlId; + OUString m_sAbout; + OUString m_sProperty; + OUString m_sContent; + OUString m_sDatatype; + css::uno::Any m_aMarkerStyleName; + bool m_bHaveAbout; + sal_Int8 nOutlineLevel; + std::unique_ptr<XMLHints_Impl> m_xHints; + // Lost outline numbering in master document (#i73509#) + bool mbOutlineLevelAttrFound; + bool mbOutlineContentVisible; + bool bIgnoreLeadingSpace; + bool bHeading; + bool bIsListHeader; + bool bIsRestart; + sal_Int16 nStartValue; + sal_uInt8 nStarFontsConvFlags; + +public: + + + XMLParaContext( SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL characters( const OUString& rChars ) override; + +}; + +class XMLNumberedParaContext : public SvXMLImportContext +{ + /// text:list-level MINUS 1 + sal_Int16 m_Level; + /// text:start-value + sal_Int16 m_StartValue; + /// text:list-id + OUString m_ListId; + /// text:style-name + css::uno::Reference< css::container::XIndexReplace > m_xNumRules; + +public: + + + XMLNumberedParaContext( SvXMLImport& i_rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & i_xAttrList ); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + sal_Int16 GetLevel() const { return m_Level; } + const css::uno::Reference< css::container::XIndexReplace >& GetNumRules() const + { return m_xNumRules; } + const OUString& GetListId() const { return m_ListId; } + sal_Int16 GetStartValue() const { return m_StartValue; } + +}; + +class XMLHints_Impl; +class XMLStyleHint_Impl; + +class XMLImpSpanContext_Impl : public SvXMLImportContext +{ + XMLHints_Impl& m_rHints; + XMLStyleHint_Impl *pHint; + + bool& rIgnoreLeadingSpace; + + sal_uInt8 nStarFontsConvFlags; + +public: + + + XMLImpSpanContext_Impl( + SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace, + sal_uInt8 nSFConvFlags + ); + + static css::uno::Reference< css::xml::sax::XFastContextHandler > CreateSpanContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace, + sal_uInt8 nStarFontsConvFlags = 0 + ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override; + virtual void SAL_CALL characters( const OUString& rChars ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtparaimphint.hxx b/xmloff/source/text/txtparaimphint.hxx new file mode 100644 index 0000000000..f244eb5719 --- /dev/null +++ b/xmloff/source/text/txtparaimphint.hxx @@ -0,0 +1,241 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include <rtl/ustring.hxx> +#include "XMLTextFrameContext.hxx" +#include "XMLTextFrameHyperlinkContext.hxx" +#include <utility> +#include <xmloff/XMLEventsImportContext.hxx> + +enum class XMLHintType +{ + XML_HINT_STYLE = 1, + XML_HINT_REFERENCE = 2, + XML_HINT_HYPERLINK = 3, + // There is no 4 defined here + XML_HINT_INDEX_MARK = 5, + XML_HINT_TEXT_FRAME = 6, + // Core impl. of the unification of drawing objects and Writer fly frames (#i26791#) + XML_HINT_DRAW = 7 +}; + +class XMLHint_Impl +{ + css::uno::Reference < css::text::XTextRange > xStart; + css::uno::Reference < css::text::XTextRange > xEnd; + + XMLHintType nType; + +public: + + XMLHint_Impl( XMLHintType nTyp, + css::uno::Reference < css::text::XTextRange > xS, + css::uno::Reference < css::text::XTextRange > xE ) : + xStart(std::move( xS )), + xEnd(std::move( xE )), + nType( nTyp ) + { + } + + virtual ~XMLHint_Impl() {} + + const css::uno::Reference < css::text::XTextRange > & GetStart() const { return xStart; } + const css::uno::Reference < css::text::XTextRange > & GetEnd() const { return xEnd; } + void SetEnd( const css::uno::Reference < css::text::XTextRange > & rPos ) { xEnd = rPos; } + + // We don't use virtual methods to differ between the sub classes, + // because this seems to be too expensive if compared to inline methods. + XMLHintType GetType() const { return nType; } + bool IsReference() const { return XMLHintType::XML_HINT_REFERENCE==nType; } +}; + +class XMLStyleHint_Impl : public XMLHint_Impl +{ + OUString sStyleName; + +public: + + XMLStyleHint_Impl( OUString aStyleName, + const css::uno::Reference < css::text::XTextRange > & rPos ) : + XMLHint_Impl( XMLHintType::XML_HINT_STYLE, rPos, rPos ), + sStyleName(std::move( aStyleName )) + { + } + + const OUString& GetStyleName() const { return sStyleName; } +}; + +class XMLReferenceHint_Impl : public XMLHint_Impl +{ + OUString sRefName; + +public: + + XMLReferenceHint_Impl( OUString aRefName, + const css::uno::Reference < css::text::XTextRange > & rPos ) : + XMLHint_Impl( XMLHintType::XML_HINT_REFERENCE, rPos, rPos ), + sRefName(std::move( aRefName )) + { + } + + const OUString& GetRefName() const { return sRefName; } +}; + +class XMLHyperlinkHint_Impl : public XMLHint_Impl +{ + OUString sHRef; + OUString sName; + OUString sTargetFrameName; + OUString sStyleName; + OUString sVisitedStyleName; + rtl::Reference<XMLEventsImportContext> mxEvents; + +public: + + XMLHyperlinkHint_Impl( const css::uno::Reference < css::text::XTextRange > & rPos ) : + XMLHint_Impl( XMLHintType::XML_HINT_HYPERLINK, rPos, rPos ) + { + } + + void SetHRef( const OUString& s ) { sHRef = s; } + const OUString& GetHRef() const { return sHRef; } + void SetName( const OUString& s ) { sName = s; } + const OUString& GetName() const { return sName; } + void SetTargetFrameName( const OUString& s ) { sTargetFrameName = s; } + const OUString& GetTargetFrameName() const { return sTargetFrameName; } + void SetStyleName( const OUString& s ) { sStyleName = s; } + const OUString& GetStyleName() const { return sStyleName; } + void SetVisitedStyleName( const OUString& s ) { sVisitedStyleName = s; } + const OUString& GetVisitedStyleName() const { return sVisitedStyleName; } + XMLEventsImportContext* GetEventsContext() const + { + return mxEvents.get(); + } + void SetEventsContext( XMLEventsImportContext* pCtxt ) + { + mxEvents.set(pCtxt); + } +}; + +class XMLIndexMarkHint_Impl : public XMLHint_Impl +{ + const css::uno::Reference<css::beans::XPropertySet> xIndexMarkPropSet; + + const OUString sID; + +public: + + XMLIndexMarkHint_Impl( css::uno::Reference < css::beans::XPropertySet > xPropSet, + const css::uno::Reference < css::text::XTextRange > & rPos ) : + XMLHint_Impl( XMLHintType::XML_HINT_INDEX_MARK, rPos, rPos ), + xIndexMarkPropSet(std::move( xPropSet )), + sID() + { + } + + XMLIndexMarkHint_Impl( css::uno::Reference < css::beans::XPropertySet > xPropSet, + const css::uno::Reference < css::text::XTextRange > & rPos, + OUString sIDString) : + XMLHint_Impl( XMLHintType::XML_HINT_INDEX_MARK, rPos, rPos ), + xIndexMarkPropSet(std::move( xPropSet )), + sID(std::move(sIDString)) + { + } + + const css::uno::Reference<css::beans::XPropertySet> & GetMark() const + { return xIndexMarkPropSet; } + const OUString& GetID() const { return sID; } +}; + +class XMLTextFrameHint_Impl : public XMLHint_Impl +{ + // OD 2004-04-20 #i26791# + SvXMLImportContextRef xContext; + +public: + + XMLTextFrameHint_Impl( SvXMLImportContext* pContext, + const css::uno::Reference < css::text::XTextRange > & rPos ) : + XMLHint_Impl( XMLHintType::XML_HINT_TEXT_FRAME, rPos, rPos ), + xContext( pContext ) + { + } + + css::uno::Reference < css::text::XTextContent > GetTextContent() const + { + css::uno::Reference < css::text::XTextContent > xTxt; + SvXMLImportContext *pContext = xContext.get(); + if (XMLTextFrameContext *pFrameContext = dynamic_cast<XMLTextFrameContext*>(pContext)) + xTxt = pFrameContext->GetTextContent(); + else if (XMLTextFrameHyperlinkContext *pLinkContext = dynamic_cast<XMLTextFrameHyperlinkContext*>(pContext)) + xTxt = pLinkContext->GetTextContent(); + + return xTxt; + } + + // Frame "to character": anchor moves from first to last char after saving (#i33242#) + css::uno::Reference < css::drawing::XShape > GetShape() const + { + css::uno::Reference < css::drawing::XShape > xShape; + SvXMLImportContext *pContext = xContext.get(); + if (XMLTextFrameContext *pFrameContext = dynamic_cast<XMLTextFrameContext*>(pContext)) + xShape = pFrameContext->GetShape(); + else if(XMLTextFrameHyperlinkContext *pLinkContext = dynamic_cast<XMLTextFrameHyperlinkContext*>(pContext)) + xShape = pLinkContext->GetShape(); + + return xShape; + } + + bool IsBoundAtChar() const + { + bool bRet = false; + SvXMLImportContext *pContext = xContext.get(); + if (XMLTextFrameContext *pFrameContext = dynamic_cast<XMLTextFrameContext*>(pContext)) + bRet = css::text::TextContentAnchorType_AT_CHARACTER == + pFrameContext->GetAnchorType(); + else if (XMLTextFrameHyperlinkContext *pLinkContext = dynamic_cast<XMLTextFrameHyperlinkContext*>(pContext)) + bRet = css::text::TextContentAnchorType_AT_CHARACTER == + pLinkContext->GetAnchorType(); + return bRet; + } +}; + +// Core impl. of the unification of drawing objects and Writer fly frames (#i26791#) +class XMLDrawHint_Impl : public XMLHint_Impl +{ + rtl::Reference<SvXMLShapeContext> xContext; + +public: + + XMLDrawHint_Impl( SvXMLShapeContext* pContext, + const css::uno::Reference < css::text::XTextRange > & rPos ) : + XMLHint_Impl( XMLHintType::XML_HINT_DRAW, rPos, rPos ), + xContext( pContext ) + { + } + + // Frame "to character": anchor moves from first to last char after saving (#i33242#) + css::uno::Reference < css::drawing::XShape > const & GetShape() const + { + return xContext->getShape(); + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtprhdl.cxx b/xmloff/source/text/txtprhdl.cxx new file mode 100644 index 0000000000..f7c3a9790d --- /dev/null +++ b/xmloff/source/text/txtprhdl.cxx @@ -0,0 +1,1451 @@ +/* -*- 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 <o3tl/any.hxx> +#include <osl/diagnose.h> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/style/DropCapFormat.hpp> +#include <com/sun/star/text/FontRelief.hpp> +#include <com/sun/star/text/WrapTextMode.hpp> +#include <com/sun/star/text/XTextColumns.hpp> +#include <com/sun/star/text/TextColumn.hpp> +#include <com/sun/star/text/RelOrientation.hpp> +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/text/VertOrientation.hpp> +#include <com/sun/star/text/RubyAdjust.hpp> +#include <com/sun/star/text/RubyPosition.hpp> +#include <com/sun/star/text/FontEmphasis.hpp> +#include <com/sun/star/text/ParagraphVertAlign.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <sax/tools/converter.hxx> +#include <xmloff/xmltypes.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlement.hxx> +#include "XMLAnchorTypePropHdl.hxx" +#include <enummaps.hxx> +#include <xmloff/XMLConstantsPropertyHandler.hxx> +#include <XMLClipPropertyHandler.hxx> +#include <XMLTextColumnsPropertyHandler.hxx> +#include <xmloff/NamedBoolPropertyHdl.hxx> +#include "txtprhdl.hxx" +#include <com/sun/star/text/WrapInfluenceOnPosition.hpp> +#include <com/sun/star/drawing/TextVerticalAdjust.hpp> +#include <xmloff/EnumPropertyHdl.hxx> +#include <XMLFillBitmapSizePropertyHandler.hxx> +#include <XMLBitmapLogicalSizePropertyHandler.hxx> +#include <XMLBitmapRepeatOffsetPropertyHandler.hxx> +#include <xmloff/XMLComplexColorHandler.hxx> +#include <vcl/graph.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; +using namespace ::com::sun::star::drawing; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_HoriPos_Enum[] = +{ + { XML_FROM_LEFT, HoriOrientation::NONE }, + { XML_FROM_INSIDE, HoriOrientation::NONE }, // import only + { XML_LEFT, HoriOrientation::LEFT }, + { XML_INSIDE, HoriOrientation::LEFT }, // import only + { XML_CENTER, HoriOrientation::CENTER }, + { XML_RIGHT, HoriOrientation::RIGHT }, + { XML_OUTSIDE, HoriOrientation::RIGHT }, // import only + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_HoriPosMirrored_Enum[] = +{ + { XML_FROM_INSIDE, HoriOrientation::NONE }, + { XML_INSIDE, HoriOrientation::LEFT }, + { XML_CENTER, HoriOrientation::CENTER }, + { XML_OUTSIDE, HoriOrientation::RIGHT }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_HoriRel_Enum[] = +{ + { XML_PARAGRAPH, RelOrientation::FRAME }, + { XML_PARAGRAPH_CONTENT, RelOrientation::PRINT_AREA }, + { XML_PAGE, RelOrientation::PAGE_FRAME }, + { XML_PAGE_CONTENT, RelOrientation::PAGE_PRINT_AREA }, + { XML_PARAGRAPH_START_MARGIN, RelOrientation::FRAME_LEFT }, + { XML_PARAGRAPH_END_MARGIN, RelOrientation::FRAME_RIGHT }, + { XML_PAGE_START_MARGIN, RelOrientation::PAGE_LEFT }, + { XML_PAGE_END_MARGIN, RelOrientation::PAGE_RIGHT }, + { XML_CHAR, RelOrientation::CHAR }, + { XML_FRAME, RelOrientation::FRAME }, // import only + { XML_FRAME_CONTENT, RelOrientation::PRINT_AREA }, // import only + { XML_FRAME_START_MARGIN, RelOrientation::FRAME_LEFT }, // import only + { XML_FRAME_END_MARGIN, RelOrientation::FRAME_RIGHT }, // import only + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_HoriRelFrame_Enum[] = +{ + { XML_FRAME, RelOrientation::FRAME }, + { XML_FRAME_CONTENT, RelOrientation::PRINT_AREA }, + { XML_PAGE, RelOrientation::PAGE_FRAME }, + { XML_PAGE_CONTENT, RelOrientation::PAGE_PRINT_AREA }, + { XML_FRAME_START_MARGIN, RelOrientation::FRAME_LEFT }, + { XML_FRAME_END_MARGIN, RelOrientation::FRAME_RIGHT }, + { XML_PAGE_START_MARGIN, RelOrientation::PAGE_LEFT }, + { XML_PAGE_END_MARGIN, RelOrientation::PAGE_RIGHT }, + { XML_CHAR, RelOrientation::CHAR }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<bool> const pXML_HoriMirror_Enum[] = +{ + { XML_FROM_LEFT, false }, + { XML_FROM_INSIDE, true }, + { XML_LEFT, false }, + { XML_INSIDE, true }, + { XML_CENTER, false }, + { XML_RIGHT, false }, + { XML_OUTSIDE, true }, + { XML_TOKEN_INVALID, false } +}; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_VertPosAtChar_Enum[] = +{ + { XML_FROM_TOP, VertOrientation::NONE }, + { XML_TOP, VertOrientation::TOP }, + { XML_TOP, VertOrientation::CHAR_TOP }, // export only + { XML_TOP, VertOrientation::LINE_TOP }, // export only + { XML_MIDDLE, VertOrientation::CENTER }, + { XML_MIDDLE, VertOrientation::CHAR_CENTER }, // export only + { XML_MIDDLE, VertOrientation::LINE_CENTER }, // export only + { XML_BOTTOM, VertOrientation::BOTTOM }, + { XML_BELOW, VertOrientation::CHAR_BOTTOM }, // export only + { XML_BOTTOM, VertOrientation::LINE_BOTTOM }, // export only + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_VertRel_Enum[] = +{ + { XML_PARAGRAPH, RelOrientation::FRAME }, + { XML_PARAGRAPH_CONTENT, RelOrientation::PRINT_AREA }, + { XML_CHAR, RelOrientation::CHAR }, + // DVO, OD 17.09.2003 #i18732# - allow vertical alignment at page + { XML_PAGE, RelOrientation::PAGE_FRAME }, + { XML_PAGE_CONTENT, RelOrientation::PAGE_PRINT_AREA }, + { XML_PAGE_CONTENT_TOP, RelOrientation::PAGE_PRINT_AREA_TOP }, + { XML_PAGE_CONTENT_BOTTOM, RelOrientation::PAGE_PRINT_AREA_BOTTOM }, + { XML_FRAME, RelOrientation::FRAME }, // import only + { XML_FRAME_CONTENT, RelOrientation::PRINT_AREA }, // import only + // OD 13.11.2003 #i22341# - new vertical alignment at top of line + { XML_LINE, RelOrientation::TEXT_LINE }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_VertRelPage_Enum[] = +{ + { XML_PAGE, RelOrientation::FRAME }, + { XML_PAGE_CONTENT, RelOrientation::PRINT_AREA }, + { XML_PAGE, RelOrientation::PAGE_FRAME }, + { XML_PAGE_CONTENT, RelOrientation::PAGE_PRINT_AREA }, + { XML_PAGE_CONTENT_TOP, RelOrientation::PAGE_PRINT_AREA_TOP }, + { XML_PAGE_CONTENT_BOTTOM, RelOrientation::PAGE_PRINT_AREA_BOTTOM }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_VertRelFrame_Enum[] = +{ + { XML_FRAME, RelOrientation::FRAME }, + { XML_FRAME_CONTENT, RelOrientation::PRINT_AREA }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_VertRelAsChar_Enum[] = +{ + { XML_BASELINE, VertOrientation::TOP }, + { XML_BASELINE, VertOrientation::CENTER }, // export only + { XML_BASELINE, VertOrientation::BOTTOM }, // export only + { XML_TEXT, VertOrientation::CHAR_TOP }, + { XML_TEXT, VertOrientation::CHAR_CENTER }, // export only + { XML_TEXT, VertOrientation::CHAR_BOTTOM }, // export only + { XML_LINE, VertOrientation::LINE_TOP }, + { XML_LINE, VertOrientation::LINE_CENTER }, // export only + { XML_LINE, VertOrientation::LINE_BOTTOM }, // export only + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<RubyAdjust> const pXML_RubyAdjust_Enum[] = +{ + { XML_LEFT, RubyAdjust_LEFT }, + { XML_CENTER, RubyAdjust_CENTER }, + { XML_RIGHT, RubyAdjust_RIGHT }, + { XML_DISTRIBUTE_LETTER, RubyAdjust_BLOCK }, + { XML_DISTRIBUTE_SPACE, RubyAdjust_INDENT_BLOCK }, + { XML_TOKEN_INVALID, RubyAdjust(0) } +}; + +SvXMLEnumMapEntry<sal_Int16> const pXML_RubyPosition_Enum[] = +{ + { XML_ABOVE, RubyPosition::ABOVE}, + { XML_BELOW, RubyPosition::BELOW}, + { XML_INTER_CHARACTER, RubyPosition::INTER_CHARACTER}, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_FontRelief_Enum[] = +{ + { XML_NONE, FontRelief::NONE }, + { XML_ENGRAVED, FontRelief::ENGRAVED }, + { XML_EMBOSSED, FontRelief::EMBOSSED }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_ParaVerticalAlign_Enum[] = +{ + { XML_TOP, ParagraphVertAlign::TOP }, + { XML_MIDDLE, ParagraphVertAlign::CENTER }, + { XML_BOTTOM, ParagraphVertAlign::BOTTOM }, + { XML_BASELINE, ParagraphVertAlign::BASELINE }, + { XML_AUTO, ParagraphVertAlign::AUTOMATIC }, + { XML_TOKEN_INVALID, 0 } +}; + +// OD 2004-05-05 #i28701# +SvXMLEnumMapEntry<sal_uInt16> const pXML_WrapInfluenceOnPosition_Enum[] = +{ + // Tokens have been renamed and <XML_ITERATIVE> has been added (#i35017#) + { XML_ONCE_SUCCESSIVE, WrapInfluenceOnPosition::ONCE_SUCCESSIVE }, + { XML_ONCE_CONCURRENT, WrapInfluenceOnPosition::ONCE_CONCURRENT }, + { XML_ITERATIVE, WrapInfluenceOnPosition::ITERATIVE }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<drawing::TextVerticalAdjust> const pXML_VerticalAlign_Enum[] = +{ + { XML_TOP, drawing::TextVerticalAdjust_TOP }, + { XML_MIDDLE, drawing::TextVerticalAdjust_CENTER }, + { XML_BOTTOM, drawing::TextVerticalAdjust_BOTTOM }, + { XML_JUSTIFY, drawing::TextVerticalAdjust_BLOCK }, + { XML_TOKEN_INVALID, drawing::TextVerticalAdjust(0) } +}; + +namespace { + +class XMLDropCapPropHdl_Impl : public XMLPropertyHandler +{ +public: + virtual bool equals( + const css::uno::Any& r1, + const css::uno::Any& r2 ) const override; + + /// TabStops will be imported/exported as XML-Elements. So the Import/Export-work must be done at another place. + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLDropCapPropHdl_Impl::equals( + const Any& r1, + const Any& r2 ) const +{ + DropCapFormat aFormat1, aFormat2; + r1 >>= aFormat1; + r2 >>= aFormat2; + + return (aFormat1.Lines <=1 && aFormat2.Lines <=1) || + (aFormat1.Lines == aFormat2.Lines && + aFormat1.Count == aFormat2.Count && + aFormat1.Distance == aFormat2.Distance); +} + +bool XMLDropCapPropHdl_Impl::importXML( + const OUString&, + Any&, + const SvXMLUnitConverter& ) const +{ + SAL_WARN( "xmloff", "drop caps are an element import property" ); + return false; +} + +bool XMLDropCapPropHdl_Impl::exportXML( + OUString&, + const Any&, + const SvXMLUnitConverter& ) const +{ + SAL_WARN( "xmloff", "drop caps are an element export property" ); + return false; +} + +namespace { + +class XMLOpaquePropHdl_Impl : public XMLPropertyHandler +{ +public: + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLOpaquePropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = true; + bool bVal = false; + if( IsXMLToken( rStrImpValue, XML_FOREGROUND ) ) + bVal = true; + else if( !IsXMLToken( rStrImpValue, XML_BACKGROUND ) ) + bRet = false; + + if( bRet ) + rValue <<= bVal; + + return bRet; +} + +bool XMLOpaquePropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + if( *o3tl::doAccess<bool>(rValue) ) + rStrExpValue = GetXMLToken( XML_FOREGROUND ); + else + rStrExpValue = GetXMLToken( XML_BACKGROUND ); + + return true; +} + +namespace { + +class XMLContourModePropHdl_Impl : public XMLPropertyHandler +{ +public: + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLContourModePropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = true; + bool bVal = false; + if( IsXMLToken( rStrImpValue, XML_OUTSIDE ) ) + bVal = true; + else if( ! IsXMLToken( rStrImpValue, XML_FULL ) ) + bRet = false; + + if( bRet ) + rValue <<= bVal; + + return bRet; +} + +bool XMLContourModePropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + if( *o3tl::doAccess<bool>(rValue) ) + rStrExpValue = GetXMLToken( XML_OUTSIDE ); + else + rStrExpValue = GetXMLToken( XML_FULL ); + + return true; +} + +namespace { + +class XMLParagraphOnlyPropHdl_Impl : public XMLPropertyHandler +{ +public: + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLParagraphOnlyPropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = true; + bool bVal = false; + + if( ! IsXMLToken( rStrImpValue, XML_NO_LIMIT ) ) + { + sal_Int32 nValue = 0; + bRet = ::sax::Converter::convertNumber( nValue, rStrImpValue ); + bVal = 1 == nValue; + } + + if( bRet ) + rValue <<= bVal; + + return bRet; +} + +bool XMLParagraphOnlyPropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + if( *o3tl::doAccess<bool>(rValue) ) + rStrExpValue = GetXMLToken( XML_1 ); + else + rStrExpValue = GetXMLToken( XML_NO_LIMIT ); + + return true; +} + +SvXMLEnumMapEntry<WrapTextMode> const pXML_Wrap_Enum[] = +{ + { XML_NONE, WrapTextMode_NONE }, + { XML_RUN_THROUGH, WrapTextMode_THROUGH }, + { XML_PARALLEL, WrapTextMode_PARALLEL }, + { XML_DYNAMIC, WrapTextMode_DYNAMIC }, + { XML_LEFT, WrapTextMode_LEFT }, + { XML_RIGHT, WrapTextMode_RIGHT }, + { XML_TOKEN_INVALID, WrapTextMode(0) } +}; + +namespace { + +class XMLWrapPropHdl_Impl : public XMLPropertyHandler +{ +public: + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLWrapPropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + WrapTextMode nWrap; + bool bRet = SvXMLUnitConverter::convertEnum( nWrap, rStrImpValue, + pXML_Wrap_Enum ); + + if( bRet ) + rValue <<= nWrap; + + return bRet; +} + +bool XMLWrapPropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + OUStringBuffer aOut; + WrapTextMode eVal; + + rValue >>= eVal; + + bool bRet = SvXMLUnitConverter::convertEnum( aOut, eVal, pXML_Wrap_Enum, XML_NONE ); + + rStrExpValue = aOut.makeStringAndClear(); + + return bRet; +} + +namespace { + +class XMLFrameProtectPropHdl_Impl : public XMLPropertyHandler +{ + const OUString sVal; +public: + explicit XMLFrameProtectPropHdl_Impl( enum XMLTokenEnum eVal ) : + sVal( GetXMLToken(eVal) ) {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLFrameProtectPropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = true; + bool bVal = false; + if( ! IsXMLToken( rStrImpValue, XML_NONE ) ) + { + bRet = false; + SvXMLTokenEnumerator aTokenEnum( rStrImpValue ); + std::u16string_view aToken; + while( aTokenEnum.getNextToken( aToken ) ) + { + bRet = true; + if( aToken == sVal ) + { + bVal = true; + break; + } + } + } + + if( bRet ) + rValue <<= bVal; + + return bRet; +} + +bool XMLFrameProtectPropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + if( *o3tl::doAccess<bool>(rValue) ) + { + if( rStrExpValue.isEmpty() || + IsXMLToken( rStrExpValue, XML_NONE ) ) + { + rStrExpValue = sVal; + } + else + { + rStrExpValue += " " + sVal; + } + } + else if( rStrExpValue.isEmpty() ) + { + rStrExpValue = GetXMLToken( XML_NONE ); + } + + return true; +} + +SvXMLEnumMapEntry<TextContentAnchorType> const pXML_Anchor_Enum[] = +{ + { XML_CHAR, TextContentAnchorType_AT_CHARACTER }, + { XML_PAGE, TextContentAnchorType_AT_PAGE }, + { XML_FRAME, TextContentAnchorType_AT_FRAME }, + { XML_PARAGRAPH, TextContentAnchorType_AT_PARAGRAPH }, + { XML_AS_CHAR, TextContentAnchorType_AS_CHARACTER }, + { XML_TOKEN_INVALID, TextContentAnchorType(0) } +}; + +bool XMLAnchorTypePropHdl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + TextContentAnchorType nAnchor; + bool bRet = SvXMLUnitConverter::convertEnum( nAnchor, rStrImpValue, + pXML_Anchor_Enum ); + + if( bRet ) + rValue <<= nAnchor; + + return bRet; +} + +bool XMLAnchorTypePropHdl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + OUStringBuffer aOut; + TextContentAnchorType eVal; + + rValue >>= eVal; + + bool bRet = SvXMLUnitConverter::convertEnum( aOut, eVal, pXML_Anchor_Enum, XML_PARAGRAPH ); + + rStrExpValue = aOut.makeStringAndClear(); + + return bRet; +} + +XMLAnchorTypePropHdl::~XMLAnchorTypePropHdl() +{ +} + +bool XMLAnchorTypePropHdl::convert( std::string_view rStrImpValue, + TextContentAnchorType& rType ) +{ + TextContentAnchorType nAnchor; + bool bRet = SvXMLUnitConverter::convertEnum( nAnchor, rStrImpValue, + pXML_Anchor_Enum ); + if( bRet ) + rType = nAnchor; + return bRet; +} + +XMLTextColumnsPropertyHandler::~XMLTextColumnsPropertyHandler () +{ +} + +bool XMLTextColumnsPropertyHandler::equals( + const Any& r1, + const Any& r2 ) const +{ + Reference < XTextColumns > xColumns1; + r1 >>= xColumns1; + + Reference < XTextColumns > xColumns2; + r2 >>= xColumns2; + + if (!xColumns1 || !xColumns2) + return (!xColumns1 && !xColumns2); + + if( xColumns1->getColumnCount() != xColumns2->getColumnCount() || + xColumns1->getReferenceValue() != xColumns2->getReferenceValue() ) + return false; + + const Sequence < TextColumn > aColumns1 = xColumns1->getColumns(); + const Sequence < TextColumn > aColumns2 = xColumns2->getColumns(); + + return std::equal(aColumns1.begin(), aColumns1.end(), aColumns2.begin(), aColumns2.end(), + [](const TextColumn& a, const TextColumn& b) { + return a.Width == b.Width + && a.LeftMargin == b.LeftMargin + && a.RightMargin == b.RightMargin; + }); +} + +bool XMLTextColumnsPropertyHandler::importXML( + const OUString&, + Any&, + const SvXMLUnitConverter& ) const +{ + SAL_WARN( "xmloff", "columns are an element import property" ); + return false; +} + +bool XMLTextColumnsPropertyHandler::exportXML( + OUString&, + const Any&, + const SvXMLUnitConverter& ) const +{ + SAL_WARN( "xmloff", "columns are an element export property" ); + return false; +} + +namespace { + +class XMLHoriMirrorPropHdl_Impl : public XMLPropertyHandler +{ +public: + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLHoriMirrorPropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool nHoriMirror; + bool bRet = SvXMLUnitConverter::convertEnum( nHoriMirror, rStrImpValue, + pXML_HoriMirror_Enum ); + + if( bRet ) + { + rValue <<= nHoriMirror; + } + + return bRet; +} + +bool XMLHoriMirrorPropHdl_Impl::exportXML( + OUString&, + const Any&, + const SvXMLUnitConverter& ) const +{ + SAL_WARN( "xmloff", "HorMirror property shouldn't be exported" ); + + return false; +} + +namespace { + +class XMLGrfMirrorPropHdl_Impl : public XMLPropertyHandler +{ + const OUString sVal; + bool bHori; + +public: + XMLGrfMirrorPropHdl_Impl( enum XMLTokenEnum eVal, bool bH ) : + sVal( GetXMLToken( eVal ) ), + bHori( bH ) {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLGrfMirrorPropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = true; + bool bVal = false; + if( ! IsXMLToken( rStrImpValue, XML_NONE ) ) + { + bRet = false; + SvXMLTokenEnumerator aTokenEnum( rStrImpValue ); + std::u16string_view aToken; + while( aTokenEnum.getNextToken( aToken ) ) + { + bRet = true; + if( aToken == sVal || + (bHori && IsXMLToken( aToken, XML_HORIZONTAL ) ) ) + { + bVal = true; + break; + } + } + } + + if( bRet ) + rValue <<= bVal; + + return bRet; +} + +bool XMLGrfMirrorPropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + if( *o3tl::doAccess<bool>(rValue) ) + { + if( rStrExpValue.isEmpty() || + IsXMLToken( rStrExpValue, XML_NONE ) ) + { + rStrExpValue = sVal; + } + else if( bHori && + /* XML_HORIZONTAL_ON_LEFT_PAGES and XML_HORIZONTAL_ON_RIGHT_PAGES + are replaced by XML_HORIZONTAL_ON_EVEN and XML_HORIZONTAL_ON_ODD. + (#i49139#) + */ + ( IsXMLToken( rStrExpValue, XML_HORIZONTAL_ON_EVEN ) || + IsXMLToken( rStrExpValue, XML_HORIZONTAL_ON_ODD ) )) + { + rStrExpValue = GetXMLToken( XML_HORIZONTAL ); + } + else + { + rStrExpValue += " " + sVal; + } + } + else if( rStrExpValue.isEmpty() ) + { + rStrExpValue = GetXMLToken( XML_NONE ); + } + + return true; +} + +SvXMLEnumMapEntry<sal_uInt16> const pXML_Emphasize_Enum[] = +{ + { XML_NONE, FontEmphasis::NONE }, + { XML_DOT, FontEmphasis::DOT_ABOVE }, + { XML_CIRCLE, FontEmphasis::CIRCLE_ABOVE }, + { XML_DISC, FontEmphasis::DISK_ABOVE }, + { XML_ACCENT, FontEmphasis::ACCENT_ABOVE }, + { XML_TOKEN_INVALID, 0 } +}; + +namespace { + +class XMLTextEmphasizePropHdl_Impl : public XMLPropertyHandler +{ +public: + XMLTextEmphasizePropHdl_Impl() {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLTextEmphasizePropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = true; + sal_uInt16 nVal = FontEmphasis::NONE; + bool bBelow = false; + bool bHasPos = false, bHasType = false; + std::u16string_view aToken; + + SvXMLTokenEnumerator aTokenEnum( rStrImpValue ); + while( aTokenEnum.getNextToken( aToken ) ) + { + if( !bHasPos && IsXMLToken( aToken, XML_ABOVE ) ) + { + bBelow = false; + bHasPos = true; + } + else if( !bHasPos && IsXMLToken( aToken, XML_BELOW ) ) + { + bBelow = true; + bHasPos = true; + } + else if( !bHasType && + SvXMLUnitConverter::convertEnum( nVal, aToken, + pXML_Emphasize_Enum )) + { + bHasType = true; + } + else + { + bRet = false; + break; + } + } + + if( bRet ) + { + if( FontEmphasis::NONE != nVal && bBelow ) + nVal += 10; + rValue <<= static_cast<sal_Int16>(nVal); + } + + return bRet; +} + +bool XMLTextEmphasizePropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + OUStringBuffer aOut( 15 ); + bool bRet = true; + sal_uInt16 nType = sal_uInt16(); + if( rValue >>= nType ) + { + bool bBelow = false; + if( nType > 10 ) + { + bBelow = true; + nType -= 10; + } + bRet = SvXMLUnitConverter::convertEnum( aOut, nType, + pXML_Emphasize_Enum, + XML_DOT ); + if( bRet ) + { + if( nType != 0 ) + { + enum XMLTokenEnum ePos = bBelow ? XML_BELOW : XML_ABOVE; + aOut.append( " " + GetXMLToken(ePos) ); + } + rStrExpValue = aOut.makeStringAndClear(); + } + } + + return bRet; +} + +namespace { + +class XMLTextCombineCharPropHdl_Impl : public XMLPropertyHandler +{ +public: + XMLTextCombineCharPropHdl_Impl() {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLTextCombineCharPropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + if( !rStrImpValue.isEmpty() ) + rValue <<= rStrImpValue.copy( 0, 1 ); + else + rValue <<= rStrImpValue; + + return true; +} + +bool XMLTextCombineCharPropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + rValue >>= rStrExpValue; + + // #i114107# attribute of type "character": export only if length is 1 + return (1 == rStrExpValue.getLength()); +} + +namespace { + +class XMLTextRelWidthHeightPropHdl_Impl : public XMLPropertyHandler +{ +public: + XMLTextRelWidthHeightPropHdl_Impl() {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLTextRelWidthHeightPropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue; + bool const bRet = ::sax::Converter::convertPercent( nValue, rStrImpValue ); + if( bRet ) + rValue <<= static_cast<sal_Int16>(nValue); + + return bRet; +} + +bool XMLTextRelWidthHeightPropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int16 nValue = sal_Int16(); + if( (rValue >>= nValue) && nValue > 0 ) + { + OUStringBuffer aOut; + ::sax::Converter::convertPercent( aOut, nValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + +namespace { + +class XMLTextSyncWidthHeightPropHdl_Impl : public XMLPropertyHandler +{ + const OUString sValue; + +public: + explicit XMLTextSyncWidthHeightPropHdl_Impl( enum XMLTokenEnum eValue ) : + sValue( GetXMLToken(eValue) ) {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLTextSyncWidthHeightPropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + rValue <<= (rStrImpValue == sValue); + + return true; +} + +bool XMLTextSyncWidthHeightPropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + if( *o3tl::doAccess<bool>(rValue) ) + { + rStrExpValue = sValue; + bRet = true; + } + + return bRet; +} + +namespace { + +class XMLTextRotationAnglePropHdl_Impl : public XMLPropertyHandler +{ + +public: + XMLTextRotationAnglePropHdl_Impl() {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLTextRotationAnglePropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue; + bool const bRet = ::sax::Converter::convertNumber( nValue, rStrImpValue ); + if( bRet ) + { + nValue = (nValue % 360 ); + if( nValue < 0 ) + nValue = 360 + nValue; + sal_Int16 nAngle; + if( nValue < 45 || nValue > 315 ) + nAngle = 0; + else if( nValue < 180 ) + nAngle = 900; + else /* if nValue <= 315 ) */ + nAngle = 2700; + rValue <<= nAngle; + } + + return bRet; +} + +bool XMLTextRotationAnglePropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int16 nAngle = sal_Int16(); + bool bRet = ( rValue >>= nAngle ); + if( bRet ) + { + rStrExpValue = OUString::number( nAngle / 10 ); + } + OSL_ENSURE( bRet, "illegal rotation angle" ); + + return bRet; +} + +namespace { + +class XMLNumber8OneBasedHdl : public XMLPropertyHandler +{ + +public: + XMLNumber8OneBasedHdl() {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLNumber8OneBasedHdl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + bool const bRet = ::sax::Converter::convertNumber(nValue, rStrImpValue); + if( bRet ) + rValue <<= static_cast<sal_Int8>( nValue - 1 ); + return bRet; +} + +bool XMLNumber8OneBasedHdl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int8 nValue = sal_Int8(); + bool bRet = ( rValue >>= nValue ); + if( bRet ) + { + rStrExpValue = OUString::number( nValue + 1 ); + } + return bRet; +} + +namespace { + +class XMLGraphicPropertyHandler : public XMLPropertyHandler +{ +public: + XMLGraphicPropertyHandler() {} + + virtual bool importXML(const OUString& , uno::Any& , const SvXMLUnitConverter& ) const override + { + SAL_WARN( "xmloff", "drop caps are an element import property" ); + return false; + } + + virtual bool exportXML(OUString& , const uno::Any& , const SvXMLUnitConverter& ) const override + { + SAL_WARN( "xmloff", "drop caps are an element import property" ); + return false; + } + + virtual bool equals(const css::uno::Any& rAny1, const css::uno::Any& rAny2) const override; +}; + +} + +bool XMLGraphicPropertyHandler::equals(const Any& rAny1, const Any& rAny2) const +{ + uno::Reference<graphic::XGraphic> xGraphic1; + uno::Reference<graphic::XGraphic> xGraphic2; + rAny1 >>= xGraphic1; + rAny2 >>= xGraphic2; + Graphic aGraphic1(xGraphic1); + Graphic aGraphic2(xGraphic2); + + return aGraphic1 == aGraphic2; +} + +static const XMLPropertyHandler *GetPropertyHandler + ( sal_Int32 nType ) +{ + const XMLPropertyHandler* pHdl = nullptr; + switch( nType ) + { + case XML_TYPE_TEXT_DROPCAP: + pHdl = new XMLDropCapPropHdl_Impl; + break; + case XML_TYPE_TEXT_WRAP: + pHdl = new XMLWrapPropHdl_Impl; + break; + case XML_TYPE_TEXT_PARAGRAPH_ONLY: + pHdl = new XMLParagraphOnlyPropHdl_Impl; + break; + case XML_TYPE_TEXT_WRAP_OUTSIDE: + pHdl = new XMLContourModePropHdl_Impl; + break; + case XML_TYPE_TEXT_OPAQUE: + pHdl = new XMLOpaquePropHdl_Impl; + break; + case XML_TYPE_TEXT_PROTECT_CONTENT: + pHdl = new XMLFrameProtectPropHdl_Impl( XML_CONTENT ); + break; + case XML_TYPE_TEXT_PROTECT_SIZE: + pHdl = new XMLFrameProtectPropHdl_Impl( XML_SIZE ); + break; + case XML_TYPE_TEXT_PROTECT_POSITION: + pHdl = new XMLFrameProtectPropHdl_Impl( XML_POSITION ); + break; + case XML_TYPE_TEXT_ANCHOR_TYPE: + pHdl = new XMLAnchorTypePropHdl; + break; + case XML_TYPE_TEXT_COLUMNS: + pHdl = new XMLTextColumnsPropertyHandler; + break; + case XML_TYPE_TEXT_HORIZONTAL_POS: + pHdl = new XMLConstantsPropertyHandler( pXML_HoriPos_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_HORIZONTAL_POS_MIRRORED: + pHdl = new XMLConstantsPropertyHandler( pXML_HoriPosMirrored_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_HORIZONTAL_REL: + pHdl = new XMLConstantsPropertyHandler( pXML_HoriRel_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_HORIZONTAL_REL_FRAME: + pHdl = new XMLConstantsPropertyHandler( pXML_HoriRelFrame_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_HORIZONTAL_MIRROR: + pHdl = new XMLHoriMirrorPropHdl_Impl; + break; + case XML_TYPE_TEXT_VERTICAL_POS_AT_CHAR: + pHdl = new XMLConstantsPropertyHandler( pXML_VertPosAtChar_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_VERTICAL_REL: + pHdl = new XMLConstantsPropertyHandler( pXML_VertRel_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_VERTICAL_REL_PAGE: + pHdl = new XMLConstantsPropertyHandler( pXML_VertRelPage_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_VERTICAL_REL_FRAME: + pHdl = new XMLConstantsPropertyHandler( pXML_VertRelFrame_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_VERTICAL_REL_AS_CHAR: + pHdl = new XMLConstantsPropertyHandler( pXML_VertRelAsChar_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_MIRROR_VERTICAL: + pHdl = new XMLGrfMirrorPropHdl_Impl( XML_VERTICAL, false ); + break; + case XML_TYPE_TEXT_MIRROR_HORIZONTAL_LEFT: + // XML_HORIZONTAL_ON_LEFT_PAGES is replaced by XML_HORIZONTAL_ON_EVEN. (#i49139#) + pHdl = new XMLGrfMirrorPropHdl_Impl( XML_HORIZONTAL_ON_EVEN, true ); + break; + case XML_TYPE_TEXT_MIRROR_HORIZONTAL_RIGHT: + // XML_HORIZONTAL_ON_RIGHT_PAGES is replaced by XML_HORIZONTAL_ON_ODD. (#i49139#) + pHdl = new XMLGrfMirrorPropHdl_Impl( XML_HORIZONTAL_ON_ODD, true ); + break; + case XML_TYPE_TEXT_CLIP: + pHdl = new XMLClipPropertyHandler( false ); + break; + case XML_TYPE_TEXT_CLIP11: + pHdl = new XMLClipPropertyHandler( true ); + break; + case XML_TYPE_TEXT_EMPHASIZE: + pHdl = new XMLTextEmphasizePropHdl_Impl; + break; + case XML_TYPE_TEXT_COMBINE: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken( XML_LINES ), + GetXMLToken( XML_NONE ) ); + break; + case XML_TYPE_TEXT_COMBINE_CHARACTERS: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken( XML_LETTERS ), + GetXMLToken( XML_NONE ) ); + break; + case XML_TYPE_TEXT_COMBINECHAR: + pHdl = new XMLTextCombineCharPropHdl_Impl; + break; + case XML_TYPE_TEXT_AUTOSPACE: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken( XML_IDEOGRAPH_ALPHA ), + GetXMLToken( XML_NONE ) ); + break; + case XML_TYPE_TEXT_PUNCTUATION_WRAP: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken( XML_HANGING ), + GetXMLToken( XML_SIMPLE ) ); + break; + case XML_TYPE_TEXT_LINE_BREAK: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken( XML_STRICT ), + GetXMLToken( XML_NORMAL ) ); + break; + case XML_TYPE_TEXT_REL_WIDTH_HEIGHT: + pHdl = new XMLTextRelWidthHeightPropHdl_Impl; + break; + case XML_TYPE_TEXT_SYNC_WIDTH_HEIGHT: + pHdl = new XMLTextSyncWidthHeightPropHdl_Impl( XML_SCALE ); + break; + case XML_TYPE_TEXT_SYNC_WIDTH_HEIGHT_MIN: + pHdl = new XMLTextSyncWidthHeightPropHdl_Impl( XML_SCALE_MIN ); + break; + case XML_TYPE_TEXT_RUBY_ADJUST: + pHdl = new XMLConstantsPropertyHandler( pXML_RubyAdjust_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_FONT_RELIEF: + pHdl = new XMLConstantsPropertyHandler( pXML_FontRelief_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_ROTATION_ANGLE: + pHdl = new XMLTextRotationAnglePropHdl_Impl; + break; + case XML_TYPE_TEXT_ROTATION_SCALE: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken( XML_FIXED ), + GetXMLToken( XML_LINE_HEIGHT ) ); + break; + case XML_TYPE_TEXT_VERTICAL_ALIGN: + pHdl = new XMLConstantsPropertyHandler( pXML_ParaVerticalAlign_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_RUBY_POSITION: + pHdl = new XMLConstantsPropertyHandler( pXML_RubyPosition_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_RUBY_IS_ABOVE: + pHdl = new XMLNamedBoolPropertyHdl(::xmloff::token::XML_ABOVE, ::xmloff::token::XML_BELOW); + break; + // OD 2004-05-05 #i28701# + case XML_TYPE_WRAP_INFLUENCE_ON_POSITION: + pHdl = new XMLConstantsPropertyHandler( pXML_WrapInfluenceOnPosition_Enum, + XML_TOKEN_INVALID ); + break; + case XML_TYPE_BORDER_MODEL: + pHdl = new XMLNamedBoolPropertyHdl( xmloff::token::XML_COLLAPSING, + xmloff::token::XML_SEPARATING ); + break; + case XML_TYPE_TEXT_LINE_MODE: + pHdl = new XMLNamedBoolPropertyHdl( + ::xmloff::token::XML_SKIP_WHITE_SPACE, + ::xmloff::token::XML_CONTINUOUS); + break; + case XML_TYPE_TEXT_KEEP: + pHdl = new XMLNamedBoolPropertyHdl( + ::xmloff::token::XML_ALWAYS, + ::xmloff::token::XML_AUTO); + break; + case XML_TYPE_TEXT_NKEEP: + pHdl = new XMLNamedBoolPropertyHdl( + ::xmloff::token::XML_AUTO, + ::xmloff::token::XML_ALWAYS); + break; + case XML_TYPE_TEXT_NUMBER8_ONE_BASED: + pHdl = new XMLNumber8OneBasedHdl(); + break; + case XML_TYPE_VERTICAL_ALIGN: + pHdl = new XMLConstantsPropertyHandler( pXML_VerticalAlign_Enum, XML_TOKEN_INVALID ); + break; + + case XML_SW_TYPE_FILLSTYLE: + pHdl = new XMLEnumPropertyHdl( aXML_FillStyle_EnumMap); + break; + case XML_SW_TYPE_FILLBITMAPSIZE: + pHdl = new XMLFillBitmapSizePropertyHandler(); + break; + case XML_SW_TYPE_LOGICAL_SIZE: + pHdl = new XMLBitmapLogicalSizePropertyHandler(); + break; + case XML_SW_TYPE_BITMAP_REFPOINT: + pHdl = new XMLEnumPropertyHdl( aXML_RefPoint_EnumMap); + break; + case XML_SW_TYPE_BITMAP_MODE: + pHdl = new XMLEnumPropertyHdl( aXML_BitmapMode_EnumMap); + break; + case XML_SW_TYPE_BITMAPREPOFFSETX: + case XML_SW_TYPE_BITMAPREPOFFSETY: + pHdl = new XMLBitmapRepeatOffsetPropertyHandler(XML_SW_TYPE_BITMAPREPOFFSETX == nType); + break; + case XML_TYPE_GRAPHIC: + pHdl = new XMLGraphicPropertyHandler; + break; + case XML_TYPE_COMPLEX_COLOR: + pHdl = new XMLComplexColorHandler; + break; + default: + { + OSL_ENSURE(false, "XMLPropertyHandler missing (!)"); + break; + } + } + + return pHdl; +} + +XMLTextPropertyHandlerFactory::XMLTextPropertyHandlerFactory() +{ +} + +const XMLPropertyHandler *XMLTextPropertyHandlerFactory::GetPropertyHandler( + sal_Int32 nType ) const +{ + const XMLPropertyHandler *pHdl = + XMLPropertyHandlerFactory::GetPropertyHandler( nType ); + + if( !pHdl ) + { + const XMLPropertyHandler *pNewHdl = ::GetPropertyHandler( nType ); + + if( pNewHdl ) + PutHdlCache( nType, pNewHdl ); + + pHdl = pNewHdl; + } + + return pHdl; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtprhdl.hxx b/xmloff/source/text/txtprhdl.hxx new file mode 100644 index 0000000000..632d4fe88d --- /dev/null +++ b/xmloff/source/text/txtprhdl.hxx @@ -0,0 +1,31 @@ +/* -*- 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/prhdlfac.hxx> + +class XMLTextPropertyHandlerFactory : public XMLPropertyHandlerFactory +{ +public: + XMLTextPropertyHandlerFactory(); + + virtual const XMLPropertyHandler* GetPropertyHandler(sal_Int32 nType) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtprmap.cxx b/xmloff/source/text/txtprmap.cxx new file mode 100644 index 0000000000..cf6adc9a19 --- /dev/null +++ b/xmloff/source/text/txtprmap.cxx @@ -0,0 +1,1159 @@ +/* -*- 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/txtprmap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/maptype.hxx> +#include <xmloff/xmltypes.hxx> +#include "txtprhdl.hxx" +#include <xmlsdtypes.hxx> +#include <sal/log.hxx> +#include <rtl/ref.hxx> +#include <xmlprop.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +#define M_E_( a, p, l, t, c ) \ + { a, p, l, t, c, SvtSaveOptions::ODFSVER_010, false } + +#define M_EV_( a, p, l, t, c, v ) \ + { a, p, l, t, c, v, false } + +#define M_ED_( a, p, l, t, c ) \ + { a, p, l, (t) | MID_FLAG_DEFAULT_ITEM_EXPORT, c, SvtSaveOptions::ODFSVER_010, false } + +// text properties +#define MT_E( a, p, l, t, c ) \ + M_E_( a, p, l, (t|XML_TYPE_PROP_TEXT), c ) +#define MT_ED( a, p, l, t, c ) \ + M_ED_( a, p, l, (t|XML_TYPE_PROP_TEXT), c ) + +// paragraph properties +#define MP_E( a, p, l, t, c ) \ + M_E_( a, p, l, (t|XML_TYPE_PROP_PARAGRAPH), c ) +#define MP_ED( a, p, l, t, c ) \ + M_ED_( a, p, l, (t|XML_TYPE_PROP_PARAGRAPH), c ) + +// graphic properties +#define MG_E( a, p, l, t, c ) \ + M_E_( a, p, l, (t|XML_TYPE_PROP_GRAPHIC), c ) +#define MG_ED( a, p, l, t, c ) \ + M_ED_( a, p, l, (t|XML_TYPE_PROP_GRAPHIC), c ) +#define MG_EV( a, p, l, t, c, v ) \ + M_EV_( a, p, l, (t|XML_TYPE_PROP_GRAPHIC), c, v ) + +// section properties +#define MS_E( a, p, l, t, c ) \ + M_E_( a, p, l, (t|XML_TYPE_PROP_SECTION), c ) + +// ruby properties +#define MR_E( a, p, l, t, c ) \ + M_E_( a, p, l, (t|XML_TYPE_PROP_RUBY), c ) +#define MR_EV( a, p, l, t, c, v ) \ + M_EV_( a, p, l, (t|XML_TYPE_PROP_RUBY), c, v ) + +// cell properties +#define MC_E( a, p, l, t, c ) \ + M_E_( a, p, l, (t|XML_TYPE_PROP_TABLE_CELL), c ) + +#define MAP_ODF13(name,prefix,token,type,context) { name, prefix, token, type, context, SvtSaveOptions::ODFSVER_013, false } + +// extensions import/export +#define MAP_EXT(name,prefix,token,type,context) { name, prefix, token, type, context, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, false } +// extensions import only +#define MAP_EXT_I(name,prefix,token,type,context) { name, prefix, token, type, context, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, true } + +#define M_END() { nullptr } + +#define MAP_(name,prefix,token,type,context) { name, prefix, token, type, context, SvtSaveOptions::ODFSVER_010, false } +#define GMAP(name,prefix,token,type,context) MAP_(name,prefix,token,static_cast<sal_Int32>(type|XML_TYPE_PROP_GRAPHIC),context) + +XMLPropertyMapEntry constexpr aXMLParaPropMap[] = +{ + // RES_UNKNOWNATR_CONTAINER + MP_E( PROP_ParaUserDefinedAttributes, XML_NAMESPACE_TEXT, XML_XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ), + + // fill attributes for paragraph backgrounds + // #i125045# moved to the front to be able to exclude these in lcl_txtprmap_getMap + // for TextPropMap::SHAPE_PARA to not have these double for Shapes (which already have these) + GMAP( PROP_FillStyle, XML_NAMESPACE_DRAW, XML_FILL, XML_SW_TYPE_FILLSTYLE, 0 ), + GMAP( PROP_FillColor, XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( PROP_FillColor2, XML_NAMESPACE_DRAW, XML_SECONDARY_FILL_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( PROP_FillGradientName, XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLGRADIENTNAME ), + GMAP( PROP_FillGradientStepCount, XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_TYPE_NUMBER16, 0 ), + GMAP( PROP_FillHatchName, XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLHATCHNAME ), + GMAP( PROP_FillBackground, XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL, 0 ), + GMAP( PROP_FillBitmapName, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLBITMAPNAME ), + GMAP( PROP_FillTransparence, XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + GMAP( PROP_FillTransparenceGradientName, XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLTRANSNAME ), + GMAP( PROP_FillBitmapSizeX, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_FillBitmapLogicalSize, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_FillBitmapSizeY, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_FillBitmapLogicalSize, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_FillBitmapMode, XML_NAMESPACE_STYLE,XML_REPEAT, XML_SW_TYPE_BITMAP_MODE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_FillBitmapPositionOffsetX, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_TYPE_PERCENT, 0 ), + GMAP( PROP_FillBitmapPositionOffsetY, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_TYPE_PERCENT, 0 ), + GMAP( PROP_FillBitmapRectanglePoint, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_SW_TYPE_BITMAP_REFPOINT, 0 ), + GMAP( PROP_FillBitmapOffsetX, XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETX|MID_FLAG_MULTI_PROPERTY, CTF_REPEAT_OFFSET_X ), + GMAP( PROP_FillBitmapOffsetY, XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETY|MID_FLAG_MULTI_PROPERTY, CTF_REPEAT_OFFSET_Y ), + + // RES_LR_SPACE + // !!! DO NOT REORDER THE MARGINS !!! + MP_E( PROP_ParaLeftMargin, XML_NAMESPACE_FO, XML_MARGIN, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_PARAMARGINALL ), + MP_E( PROP_ParaLeftMarginRelative, XML_NAMESPACE_FO, XML_MARGIN, XML_TYPE_PERCENT16, CTF_PARAMARGINALL_REL ), + MP_E( PROP_ParaLeftMargin, XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_PARALEFTMARGIN ), + MP_E( PROP_ParaLeftMarginRelative, XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_TYPE_PERCENT16, CTF_PARALEFTMARGIN_REL ), + MP_E( PROP_ParaRightMargin, XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_PARARIGHTMARGIN ), + MP_E( PROP_ParaRightMarginRelative, XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_TYPE_PERCENT16, CTF_PARARIGHTMARGIN_REL ), + // RES_UL_SPACE + MP_E( PROP_ParaTopMargin, XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_PARATOPMARGIN ), + MP_E( PROP_ParaTopMarginRelative, XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_TYPE_PERCENT16, CTF_PARATOPMARGIN_REL ), + MP_E( PROP_ParaBottomMargin, XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_PARABOTTOMMARGIN ), + MP_E( PROP_ParaBottomMarginRelative, XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_TYPE_PERCENT16, CTF_PARABOTTOMMARGIN_REL ), + MAP_ODF13( PROP_ParaContextMargin, XML_NAMESPACE_STYLE, XML_CONTEXTUAL_SPACING, XML_TYPE_BOOL|XML_TYPE_PROP_PARAGRAPH, 0 ), // ODF 1.3 OFFICE-3767 and was written by LO<=4.2 + MAP_ODF13( PROP_ParaContextMargin, XML_NAMESPACE_LO_EXT, XML_CONTEXTUAL_SPACING, XML_TYPE_BOOL|XML_TYPE_PROP_PARAGRAPH, 0 ), // extension namespace + // RES_CHRATR_CASEMAP + MT_E( PROP_CharCaseMap, XML_NAMESPACE_FO, XML_FONT_VARIANT, XML_TYPE_TEXT_CASEMAP_VAR, 0 ), + MT_E( PROP_CharCaseMap, XML_NAMESPACE_FO, XML_TEXT_TRANSFORM, XML_TYPE_TEXT_CASEMAP, 0 ), + // RES_CHRATR_COLOR + MT_ED( PROP_CharColor, XML_NAMESPACE_FO, XML_COLOR, XML_TYPE_COLORAUTO|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharColor, XML_NAMESPACE_STYLE, XML_USE_WINDOW_FONT_COLOR, XML_TYPE_ISAUTOCOLOR|MID_FLAG_MERGE_PROPERTY, 0 ), + MAP_EXT_I( PROP_CharTransparence, XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16 | XML_TYPE_PROP_TEXT, 0 ), + MAP_EXT( PROP_CharTransparence, XML_NAMESPACE_LO_EXT, XML_OPACITY, XML_TYPE_NEG_PERCENT16 | XML_TYPE_PROP_TEXT, 0 ), + MAP_EXT( PROP_CharComplexColor, XML_NAMESPACE_LO_EXT, XML_CHAR_COMPLEX_COLOR, XML_TYPE_COMPLEX_COLOR|XML_TYPE_PROP_TEXT|MID_FLAG_ELEMENT_ITEM, CTF_COMPLEX_COLOR ), + // RES_CHRATR_CONTOUR + MT_E( PROP_CharContoured, XML_NAMESPACE_STYLE, XML_TEXT_OUTLINE, XML_TYPE_BOOL, 0 ), + // RES_CHRATR_CROSSEDOUT + MT_E( PROP_CharStrikeout, XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_STYLE, XML_TYPE_TEXT_CROSSEDOUT_STYLE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharStrikeout, XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TYPE, XML_TYPE_TEXT_CROSSEDOUT_TYPE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharStrikeout, XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_WIDTH, XML_TYPE_TEXT_CROSSEDOUT_WIDTH|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharStrikeout, XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TEXT, XML_TYPE_TEXT_CROSSEDOUT_TEXT|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_ESCAPEMENT + MT_E( PROP_CharEscapement, XML_NAMESPACE_STYLE, XML_TEXT_POSITION, XML_TYPE_TEXT_ESCAPEMENT|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( PROP_CharEscapementHeight, XML_NAMESPACE_STYLE, XML_TEXT_POSITION, XML_TYPE_TEXT_ESCAPEMENT_HEIGHT|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + // RES_CHRATR_FONT + MT_ED( PROP_CharFontName, XML_NAMESPACE_STYLE, XML_FONT_NAME, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME ), + MT_ED( PROP_CharFontName, XML_NAMESPACE_FO, XML_FONT_FAMILY, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME ), + MT_ED( PROP_CharFontStyleName, XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME, XML_TYPE_STRING, CTF_FONTSTYLENAME ), + MT_ED( PROP_CharFontFamily, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC, XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY ), + MT_ED( PROP_CharFontPitch, XML_NAMESPACE_STYLE, XML_FONT_PITCH, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH ), + MT_ED( PROP_CharFontCharSet, XML_NAMESPACE_STYLE, XML_FONT_CHARSET, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET ), + // RES_CHRATR_FONTSIZE + MT_ED( PROP_CharHeight, XML_NAMESPACE_FO, XML_FONT_SIZE, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT ), + MT_ED( PROP_CharPropHeight, XML_NAMESPACE_FO, XML_FONT_SIZE, XML_TYPE_CHAR_HEIGHT_PROP|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_REL ), + MT_ED( PROP_CharDiffHeight, XML_NAMESPACE_STYLE, XML_FONT_SIZE_REL, XML_TYPE_CHAR_HEIGHT_DIFF, CTF_CHARHEIGHT_DIFF ), + // RES_CHRATR_KERNING + MT_E( PROP_CharKerning, XML_NAMESPACE_FO, XML_LETTER_SPACING, XML_TYPE_TEXT_KERNING, 0 ), + // RES_CHRATR_LANGUAGE + MT_ED( PROP_CharLocale, XML_NAMESPACE_STYLE, XML_RFC_LANGUAGE_TAG, XML_TYPE_CHAR_RFC_LANGUAGE_TAG|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocale, XML_NAMESPACE_FO, XML_LANGUAGE, XML_TYPE_CHAR_LANGUAGE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocale, XML_NAMESPACE_FO, XML_SCRIPT, XML_TYPE_CHAR_SCRIPT|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocale, XML_NAMESPACE_FO, XML_COUNTRY, XML_TYPE_CHAR_COUNTRY|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_POSTURE + MT_E( PROP_CharPosture, XML_NAMESPACE_FO, XML_FONT_STYLE, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_UNUSED1 + // RES_CHRATR_SHADOWED + MT_E( PROP_CharShadowed, XML_NAMESPACE_FO, XML_TEXT_SHADOW, XML_TYPE_TEXT_SHADOWED, 0 ), + // RES_CHRATR_UNDERLINE + MT_E( PROP_CharUnderline, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_STYLE, XML_TYPE_TEXT_UNDERLINE_STYLE|MID_FLAG_MERGE_PROPERTY, CTF_UNDERLINE ), + MT_E( PROP_CharUnderline, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_TYPE, XML_TYPE_TEXT_UNDERLINE_TYPE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharUnderline, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_WIDTH, XML_TYPE_TEXT_UNDERLINE_WIDTH|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharUnderlineColor, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_COLOR|MID_FLAG_MULTI_PROPERTY, CTF_UNDERLINE_COLOR ), + MT_E( PROP_CharUnderlineHasColor, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_HASCOLOR|MID_FLAG_MERGE_ATTRIBUTE, CTF_UNDERLINE_HASCOLOR ), + // RES_CHRATR_WEIGHT + MT_E( PROP_CharWeight, XML_NAMESPACE_FO, XML_FONT_WEIGHT, XML_TYPE_TEXT_WEIGHT, 0 ), + // RES_CHRATR_RSID + { PROP_Rsid, XML_NAMESPACE_OFFICE_EXT, XML_RSID, XML_TYPE_HEX|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, false }, + // RES_PARATR_RSID + { PROP_ParRsid, XML_NAMESPACE_OFFICE_EXT, XML_PARRSID, XML_TYPE_HEX|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, false }, + // RES_CHRATR_WORDLINEMODE + MT_E( PROP_CharWordMode, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharWordMode, XML_NAMESPACE_STYLE, XML_TEXT_OVERLINE_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharWordMode, XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_AUTOKERN + MT_E( PROP_CharAutoKerning, XML_NAMESPACE_STYLE, XML_LETTER_KERNING, XML_TYPE_BOOL, 0 ), + // RES_CHRATR_BLINK + MT_E( PROP_CharFlash, XML_NAMESPACE_STYLE, XML_TEXT_BLINKING, XML_TYPE_BOOL, 0 ), + // RES_CHRATR_NOHYPHEN + // TODO: not used? + // RES_CHRATR_UNUSED2 + // RES_CHRATR_BACKGROUND + MT_E( PROP_CharBackColor, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_MULTI_PROPERTY, CTF_CHAR_BACKGROUND ), + MT_E( PROP_CharBackTransparent, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_ISTRANSPARENT|MID_FLAG_MERGE_ATTRIBUTE, CTF_CHAR_BACKGROUND_TRANSPARENCY), + MT_E( PROP_CharBackColor, XML_NAMESPACE_FO, XML_TEXT_BACKGROUND_COLOR, XML_TYPE_COLOR|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_OLDTEXTBACKGROUND ), + // RES_CHRATR_CJK_FONT + MT_ED( PROP_CharFontNameAsian, XML_NAMESPACE_STYLE, XML_FONT_NAME_ASIAN, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME_CJK ), + MT_ED( PROP_CharFontNameAsian, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_ASIAN, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME_CJK ), + MT_ED( PROP_CharFontStyleNameAsian, XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME_ASIAN, XML_TYPE_STRING, CTF_FONTSTYLENAME_CJK ), + MT_ED( PROP_CharFontFamilyAsian, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC_ASIAN, XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY_CJK ), + MT_ED( PROP_CharFontPitchAsian, XML_NAMESPACE_STYLE, XML_FONT_PITCH_ASIAN, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH_CJK ), + MT_ED( PROP_CharFontCharSetAsian, XML_NAMESPACE_STYLE, XML_FONT_CHARSET_ASIAN, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET_CJK ), + // RES_CHRATR_CJK_FONTSIZE + MT_ED( PROP_CharHeightAsian, XML_NAMESPACE_STYLE, XML_FONT_SIZE_ASIAN, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_CJK ), + MT_ED( PROP_CharPropHeightAsian, XML_NAMESPACE_STYLE, XML_FONT_SIZE_ASIAN, XML_TYPE_CHAR_HEIGHT_PROP|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_REL_CJK ), + MT_ED( PROP_CharDiffHeightAsian, XML_NAMESPACE_STYLE, XML_FONT_SIZE_REL_ASIAN, XML_TYPE_CHAR_HEIGHT_DIFF, CTF_CHARHEIGHT_DIFF_CJK ), + // RES_CHRATR_CJK_LANGUAGE + MT_ED( PROP_CharLocaleAsian, XML_NAMESPACE_STYLE, XML_RFC_LANGUAGE_TAG_ASIAN, XML_TYPE_CHAR_RFC_LANGUAGE_TAG|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocaleAsian, XML_NAMESPACE_STYLE, XML_LANGUAGE_ASIAN, XML_TYPE_CHAR_LANGUAGE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocaleAsian, XML_NAMESPACE_STYLE, XML_SCRIPT_ASIAN, XML_TYPE_CHAR_SCRIPT|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocaleAsian, XML_NAMESPACE_STYLE, XML_COUNTRY_ASIAN, XML_TYPE_CHAR_COUNTRY|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_CJK_POSTURE + MT_E( PROP_CharPostureAsian, XML_NAMESPACE_STYLE, XML_FONT_STYLE_ASIAN, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_CJK_WEIGHT + MT_E( PROP_CharWeightAsian, XML_NAMESPACE_STYLE, XML_FONT_WEIGHT_ASIAN, XML_TYPE_TEXT_WEIGHT, 0 ), + // RES_CHRATR_CTL_FONT + MT_ED( PROP_CharFontNameComplex, XML_NAMESPACE_STYLE, XML_FONT_NAME_COMPLEX, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME_CTL ), + MT_ED( PROP_CharFontNameComplex, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_COMPLEX, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME_CTL ), + MT_ED( PROP_CharFontStyleNameComplex, XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME_COMPLEX, XML_TYPE_STRING, CTF_FONTSTYLENAME_CTL ), + MT_ED( PROP_CharFontFamilyComplex, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC_COMPLEX, XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY_CTL ), + MT_ED( PROP_CharFontPitchComplex, XML_NAMESPACE_STYLE, XML_FONT_PITCH_COMPLEX, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH_CTL ), + MT_ED( PROP_CharFontCharSetComplex, XML_NAMESPACE_STYLE, XML_FONT_CHARSET_COMPLEX, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET_CTL ), + // RES_CHRATR_CTL_FONTSIZE + MT_ED( PROP_CharHeightComplex, XML_NAMESPACE_STYLE, XML_FONT_SIZE_COMPLEX, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_CTL ), + MT_ED( PROP_CharPropHeightComplex, XML_NAMESPACE_STYLE, XML_FONT_SIZE_COMPLEX, XML_TYPE_CHAR_HEIGHT_PROP|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_REL_CTL ), + MT_ED( PROP_CharDiffHeightComplex, XML_NAMESPACE_STYLE, XML_FONT_SIZE_REL_COMPLEX, XML_TYPE_CHAR_HEIGHT_DIFF, CTF_CHARHEIGHT_DIFF_CTL ), + // RES_CHRATR_CTL_LANGUAGE + MT_ED( PROP_CharLocaleComplex, XML_NAMESPACE_STYLE, XML_RFC_LANGUAGE_TAG_COMPLEX, XML_TYPE_CHAR_RFC_LANGUAGE_TAG|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocaleComplex, XML_NAMESPACE_STYLE, XML_LANGUAGE_COMPLEX, XML_TYPE_CHAR_LANGUAGE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocaleComplex, XML_NAMESPACE_STYLE, XML_SCRIPT_COMPLEX, XML_TYPE_CHAR_SCRIPT|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocaleComplex, XML_NAMESPACE_STYLE, XML_COUNTRY_COMPLEX, XML_TYPE_CHAR_COUNTRY|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_CTL_POSTURE + MT_E( PROP_CharPostureComplex, XML_NAMESPACE_STYLE, XML_FONT_STYLE_COMPLEX, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_CTL_WEIGHT + MT_E( PROP_CharWeightComplex, XML_NAMESPACE_STYLE, XML_FONT_WEIGHT_COMPLEX, XML_TYPE_TEXT_WEIGHT, 0 ), + // RES_CHRATR_ROTATE + MT_E( PROP_CharRotation, XML_NAMESPACE_STYLE, XML_TEXT_ROTATION_ANGLE, XML_TYPE_TEXT_ROTATION_ANGLE, 0 ), + MT_E( PROP_CharRotationIsFitToLine, XML_NAMESPACE_STYLE, XML_TEXT_ROTATION_SCALE, XML_TYPE_TEXT_ROTATION_SCALE, 0 ), + // RES_CHRATR_EMPHASIS_MARK + MT_E( PROP_CharEmphasis, XML_NAMESPACE_STYLE, XML_TEXT_EMPHASIZE, XML_TYPE_TEXT_EMPHASIZE, 0 ), + // RES_CHRATR_TWO_LINES + MT_E( PROP_CharCombineIsOn, XML_NAMESPACE_STYLE, XML_TEXT_COMBINE, XML_TYPE_TEXT_COMBINE, 0 ), + MT_E( PROP_CharCombinePrefix, XML_NAMESPACE_STYLE, XML_TEXT_COMBINE_START_CHAR, XML_TYPE_TEXT_COMBINECHAR, 0 ), + MT_E( PROP_CharCombineSuffix, XML_NAMESPACE_STYLE, XML_TEXT_COMBINE_END_CHAR, XML_TYPE_TEXT_COMBINECHAR, 0 ), + // RES_CHRATR_SCALEW + MT_E( PROP_CharScaleWidth, XML_NAMESPACE_STYLE, XML_TEXT_SCALE, XML_TYPE_PERCENT16, 0 ), + //RES_CHRATR_RELIEF + MT_E( PROP_CharRelief, XML_NAMESPACE_STYLE, XML_FONT_RELIEF, XML_TYPE_TEXT_FONT_RELIEF, 0 ), + // RES_CHRATR_HIDDEN + MT_E( PROP_CharHidden, XML_NAMESPACE_TEXT, XML_DISPLAY, XML_TYPE_TEXT_HIDDEN_AS_DISPLAY|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_TEXT_DISPLAY ), + // RES_CHRATR_OVERLINE + MT_E( PROP_CharOverline, XML_NAMESPACE_STYLE, XML_TEXT_OVERLINE_STYLE, XML_TYPE_TEXT_OVERLINE_STYLE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharOverline, XML_NAMESPACE_STYLE, XML_TEXT_OVERLINE_TYPE, XML_TYPE_TEXT_OVERLINE_TYPE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharOverline, XML_NAMESPACE_STYLE, XML_TEXT_OVERLINE_WIDTH, XML_TYPE_TEXT_OVERLINE_WIDTH|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharOverlineColor, XML_NAMESPACE_STYLE, XML_TEXT_OVERLINE_COLOR, XML_TYPE_TEXT_OVERLINE_COLOR|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( PROP_CharOverlineHasColor, XML_NAMESPACE_STYLE, XML_TEXT_OVERLINE_COLOR, XML_TYPE_TEXT_OVERLINE_HASCOLOR|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + // RES_CHRATR_BOX + MAP_EXT( PROP_CharLeftBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDERWIDTH ), + MAP_EXT( PROP_CharLeftBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDERWIDTH ), + MAP_EXT( PROP_CharRightBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDERWIDTH ), + MAP_EXT( PROP_CharTopBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDERWIDTH ), + MAP_EXT( PROP_CharBottomBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDERWIDTH ), + MAP_EXT_I( PROP_CharLeftBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDERWIDTH ), + MAP_EXT_I( PROP_CharLeftBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDERWIDTH ), + MAP_EXT_I( PROP_CharRightBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDERWIDTH ), + MAP_EXT_I( PROP_CharTopBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDERWIDTH ), + MAP_EXT_I( PROP_CharBottomBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDERWIDTH ), + + MAP_EXT( PROP_CharLeftBorderDistance, XML_NAMESPACE_LO_EXT, XML_PADDING, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDERDISTANCE ), + MAP_EXT( PROP_CharLeftBorderDistance, XML_NAMESPACE_LO_EXT, XML_PADDING_LEFT, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDERDISTANCE ), + MAP_EXT( PROP_CharRightBorderDistance, XML_NAMESPACE_LO_EXT, XML_PADDING_RIGHT, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDERDISTANCE ), + MAP_EXT( PROP_CharTopBorderDistance, XML_NAMESPACE_LO_EXT, XML_PADDING_TOP, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDERDISTANCE ), + MAP_EXT( PROP_CharBottomBorderDistance, XML_NAMESPACE_LO_EXT, XML_PADDING_BOTTOM, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDERDISTANCE ), + MAP_EXT_I( PROP_CharLeftBorderDistance, XML_NAMESPACE_FO, XML_PADDING, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDERDISTANCE ), + MAP_EXT_I( PROP_CharLeftBorderDistance, XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDERDISTANCE ), + MAP_EXT_I( PROP_CharRightBorderDistance, XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDERDISTANCE ), + MAP_EXT_I( PROP_CharTopBorderDistance, XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDERDISTANCE ), + MAP_EXT_I( PROP_CharBottomBorderDistance, XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDERDISTANCE ), + + MAP_EXT( PROP_CharLeftBorder, XML_NAMESPACE_LO_EXT, XML_BORDER, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDER ), + MAP_EXT( PROP_CharLeftBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_LEFT, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDER ), + MAP_EXT( PROP_CharRightBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_RIGHT, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDER ), + MAP_EXT( PROP_CharTopBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_TOP, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDER ), + MAP_EXT( PROP_CharBottomBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_BOTTOM, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDER ), + MAP_EXT_I( PROP_CharLeftBorder, XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDER ), + MAP_EXT_I( PROP_CharLeftBorder, XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDER ), + MAP_EXT_I( PROP_CharRightBorder, XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDER ), + MAP_EXT_I( PROP_CharTopBorder, XML_NAMESPACE_FO, XML_BORDER_TOP, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDER ), + MAP_EXT_I( PROP_CharBottomBorder, XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDER ), + // RES_CHRATR_SHADOW + MAP_EXT( PROP_CharShadowFormat, XML_NAMESPACE_LO_EXT, XML_SHADOW, XML_TYPE_TEXT_SHADOW|XML_TYPE_PROP_TEXT, 0 ), + MAP_EXT_I( PROP_CharShadowFormat, XML_NAMESPACE_STYLE, XML_SHADOW, XML_TYPE_TEXT_SHADOW|XML_TYPE_PROP_TEXT, 0 ), + // RES_CHRATR_HIGHLIGHT + MT_E( PROP_CharHighlight, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_MULTI_PROPERTY| MID_FLAG_NO_PROPERTY_IMPORT, CTF_CHAR_HIGHLIGHT ), + // RES_TXTATR_INETFMT + // TODO + // RES_TXTATR_REFMARK + // TODO + // RES_TXTATR_TOXMARK + // TODO + // RES_TXTATR_CHARFMT +// M_E_SI( TEXT, style_name, RES_TXTATR_CHARFMT, 0 ), + // RES_TXTATR_CJK_RUBY + // TODO + // RES_TXTATR_FIELD + // TODO + // RES_TXTATR_FLYCNT + // TODO + // RES_TXTATR_FTN + // TODO + // RES_TXTATR_SOFTHYPH + // TODO + // RES_TXTATR_HARDBLANK + // TODO + + // RES_PARATR_LINESPACING + MP_E( PROP_ParaLineSpacing, XML_NAMESPACE_FO, XML_LINE_HEIGHT, XML_TYPE_LINE_SPACE_FIXED, 0 ), + MP_E( PROP_ParaLineSpacing, XML_NAMESPACE_STYLE, XML_LINE_HEIGHT_AT_LEAST, XML_TYPE_LINE_SPACE_MINIMUM, 0 ), + MP_E( PROP_ParaLineSpacing, XML_NAMESPACE_STYLE, XML_LINE_SPACING, XML_TYPE_LINE_SPACE_DISTANCE, 0 ), + // RES_PARATR_ADJUST + MP_E( PROP_ParaAdjust, XML_NAMESPACE_FO, XML_TEXT_ALIGN, XML_TYPE_TEXT_ADJUST, CTF_SD_SHAPE_PARA_ADJUST ), + MP_E( PROP_ParaLastLineAdjust, XML_NAMESPACE_FO, XML_TEXT_ALIGN_LAST, XML_TYPE_TEXT_ADJUSTLAST, CTF_PARA_ADJUSTLAST ), + MP_E( PROP_ParaExpandSingleWord, XML_NAMESPACE_STYLE, XML_JUSTIFY_SINGLE_WORD, XML_TYPE_BOOL, 0 ), + // RES_PARATR_SPLIT + MP_E( PROP_ParaSplit, XML_NAMESPACE_FO, XML_KEEP_TOGETHER, XML_TYPE_TEXT_SPLIT, 0 ), + // RES_PARATR_ORPHANS + MP_E( PROP_ParaOrphans, XML_NAMESPACE_FO, XML_ORPHANS, XML_TYPE_NUMBER8, 0 ), + // RES_PARATR_WIDOWS + MP_E( PROP_ParaWidows, XML_NAMESPACE_FO, XML_WIDOWS, XML_TYPE_NUMBER8, 0 ), + // RES_PARATR_TABSTOP + MP_ED( PROP_ParaTabStops, XML_NAMESPACE_STYLE, XML_TAB_STOPS, MID_FLAG_ELEMENT_ITEM|XML_TYPE_TEXT_TABSTOP, CTF_TABSTOP ), // this is not really a string! + // RES_PARATR_HYPHENZONE + MT_E( PROP_ParaIsHyphenation, XML_NAMESPACE_FO, XML_HYPHENATE, XML_TYPE_BOOL, 0 ), + MT_E( PROP_ParaHyphenationMaxLeadingChars, XML_NAMESPACE_FO, XML_HYPHENATION_REMAIN_CHAR_COUNT, XML_TYPE_NUMBER16_NO_ZERO, 0 ), + MT_E( PROP_ParaHyphenationMaxTrailingChars, XML_NAMESPACE_FO, XML_HYPHENATION_PUSH_CHAR_COUNT, XML_TYPE_NUMBER16_NO_ZERO, 0 ), + MP_E( PROP_ParaHyphenationMaxHyphens, XML_NAMESPACE_FO, XML_HYPHENATION_LADDER_COUNT, XML_TYPE_NUMBER16_NONE, 0 ), + MAP_EXT( PROP_ParaHyphenationNoCaps, XML_NAMESPACE_LO_EXT, XML_HYPHENATION_NO_CAPS, XML_TYPE_BOOL|XML_TYPE_PROP_TEXT, 0 ), + MAP_EXT( PROP_ParaHyphenationNoLastWord, XML_NAMESPACE_LO_EXT, XML_HYPHENATION_NO_LAST_WORD, XML_TYPE_BOOL|XML_TYPE_PROP_TEXT, 0 ), + MAP_EXT( PROP_ParaHyphenationMinWordLength, XML_NAMESPACE_LO_EXT, XML_HYPHENATION_WORD_CHAR_COUNT, XML_TYPE_NUMBER16_NONE|XML_TYPE_PROP_TEXT, 0 ), + MAP_EXT( PROP_ParaHyphenationZone, XML_NAMESPACE_LO_EXT, XML_HYPHENATION_ZONE, XML_TYPE_NUMBER16_NONE|XML_TYPE_PROP_TEXT, 0 ), + // RES_PARATR_DROP + MP_E( PROP_DropCapWholeWord, XML_NAMESPACE_STYLE, XML_LENGTH, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BOOL, CTF_DROPCAPWHOLEWORD ), + MP_E( PROP_DropCapCharStyleName, XML_NAMESPACE_STYLE, XML_STYLE_NAME, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_DROPCAPCHARSTYLE ), + MP_E( PROP_DropCapFormat, XML_NAMESPACE_STYLE, XML_DROP_CAP, MID_FLAG_ELEMENT_ITEM|XML_TYPE_TEXT_DROPCAP, CTF_DROPCAPFORMAT ), + // RES_PARATR_REGISTER + MP_E( PROP_ParaRegisterModeActive, XML_NAMESPACE_STYLE, XML_REGISTER_TRUE, XML_TYPE_BOOL, 0 ), + // RES_PARATR_NUMRULE + MP_E( PROP_NumberingStyleName, XML_NAMESPACE_STYLE, XML_LIST_STYLE_NAME, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STYLENAME, CTF_NUMBERINGSTYLENAME ), + + // RES_FILL_ORDER + // not required + // RES_FRM_SIZE + // not required + // RES_PAPER_BIN + // not required + // RES_LR_SPACE + + MP_E( PROP_ParaFirstLineIndent, XML_NAMESPACE_FO, XML_TEXT_INDENT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_PARAFIRSTLINE ), + MP_E( PROP_ParaFirstLineIndentRelative, XML_NAMESPACE_FO, XML_TEXT_INDENT, XML_TYPE_PERCENT, CTF_PARAFIRSTLINE_REL ), + MP_E( PROP_ParaIsAutoFirstLineIndent, XML_NAMESPACE_STYLE, XML_AUTO_TEXT_INDENT, XML_TYPE_BOOL, 0 ), + // RES_PAGEDESC + MP_E( PROP_PageDescName, XML_NAMESPACE_STYLE, XML_MASTER_PAGE_NAME, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STYLENAME, CTF_PAGEDESCNAME ), + MP_E( PROP_PageNumberOffset, XML_NAMESPACE_STYLE, XML_PAGE_NUMBER, XML_TYPE_NUMBER16_AUTO|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_PAGENUMBEROFFSET ), + // RES_BREAK : TODO: does this work? + MP_E( PROP_BreakType, XML_NAMESPACE_FO, XML_BREAK_BEFORE, XML_TYPE_TEXT_BREAKBEFORE|MID_FLAG_MULTI_PROPERTY, 0 ), + MP_E( PROP_BreakType, XML_NAMESPACE_FO, XML_BREAK_AFTER, XML_TYPE_TEXT_BREAKAFTER, 0 ), + // RES_CNTNT + // not required + // RES_HEADER + // not required + // RES_FOOTER + // not required + // RES_PRINT + // not required + // RES_OPAQUE + // not required + // RES_PROTECT + // not required + // RES_SURROUND + // not required + // RES_VERT_ORIENT + // not required + // RES_HORI_ORIENT + // not required + // RES_ANCHOR + // not required + // RES_BACKGROUND + // DO NOT REORDER these! + MP_E( PROP_ParaBackColor, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_MULTI_PROPERTY, 0 ), + MP_E( PROP_ParaBackTransparent, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_ISTRANSPARENT|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + MP_E( PROP_ParaBackGraphicLocation, XML_NAMESPACE_STYLE, XML_POSITION, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BUILDIN_CMP_ONLY, CTF_BACKGROUND_POS ), + MP_E( PROP_ParaBackGraphicFilter, XML_NAMESPACE_STYLE, XML_FILTER_NAME, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_BACKGROUND_FILTER ), + MP_E( PROP_ParaBackGraphic, XML_NAMESPACE_STYLE, XML_BACKGROUND_IMAGE, MID_FLAG_ELEMENT_ITEM|XML_TYPE_GRAPHIC, CTF_BACKGROUND_URL ), + + // RES_BOX + MP_E( PROP_LeftBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH, CTF_ALLBORDERWIDTH ), + MP_E( PROP_LeftBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH, CTF_LEFTBORDERWIDTH ), + MP_E( PROP_RightBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH, CTF_RIGHTBORDERWIDTH ), + MP_E( PROP_TopBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH, CTF_TOPBORDERWIDTH ), + MP_E( PROP_BottomBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH, CTF_BOTTOMBORDERWIDTH ), + + MP_E( PROP_LeftBorderDistance, XML_NAMESPACE_FO, XML_PADDING, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_ALLBORDERDISTANCE ), // need special import filtering + MP_E( PROP_LeftBorderDistance, XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_LEFTBORDERDISTANCE ), + MP_E( PROP_RightBorderDistance, XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_RIGHTBORDERDISTANCE ), + MP_E( PROP_TopBorderDistance, XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_TOPBORDERDISTANCE ), + MP_E( PROP_BottomBorderDistance, XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_BOTTOMBORDERDISTANCE ), + + MP_E( PROP_LeftBorder, XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_BORDER, CTF_ALLBORDER ), + MP_E( PROP_LeftBorder, XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_TYPE_BORDER, CTF_LEFTBORDER ), + MP_E( PROP_RightBorder, XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_TYPE_BORDER, CTF_RIGHTBORDER ), + MP_E( PROP_TopBorder, XML_NAMESPACE_FO, XML_BORDER_TOP, XML_TYPE_BORDER, CTF_TOPBORDER ), + MP_E( PROP_BottomBorder, XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_TYPE_BORDER, CTF_BOTTOMBORDER ), + // RES_SHADOW + MP_E( PROP_ParaShadowFormat, XML_NAMESPACE_STYLE, XML_SHADOW, XML_TYPE_TEXT_SHADOW, 0 ), + // RES_FRMMACRO + // not required + // RES_COL + // not required + // RES_KEEP + MP_E( PROP_ParaKeepTogether, XML_NAMESPACE_FO, XML_KEEP_WITH_NEXT, XML_TYPE_TEXT_KEEP, 0 ), + // RES_URL + // not required + // RES_EDIT_IN_READONLY + // not required + // RES_LAYOUT_SPLIT + // not required + // RES_CHAIN + // not required + + // RES_LINENUMBER + MP_E( PROP_ParaLineNumberCount, XML_NAMESPACE_TEXT, XML_NUMBER_LINES, XML_TYPE_BOOL, 0 ), + MP_E( PROP_ParaLineNumberStartValue, XML_NAMESPACE_TEXT, XML_LINE_NUMBER, XML_TYPE_NUMBER, 0 ), + + // RES_FTN_AT_TXTEND + // not required + // RES_END_AT_TXTEND + // not required + MP_ED( PROP_ParaIsCharacterDistance, XML_NAMESPACE_STYLE, XML_TEXT_AUTOSPACE, XML_TYPE_TEXT_AUTOSPACE, 0 ), + MP_ED( PROP_ParaIsHangingPunctuation, XML_NAMESPACE_STYLE, XML_PUNCTUATION_WRAP, XML_TYPE_TEXT_PUNCTUATION_WRAP, 0 ), + MP_ED( PROP_ParaIsForbiddenRules, XML_NAMESPACE_STYLE, XML_LINE_BREAK, XML_TYPE_TEXT_LINE_BREAK, 0 ), + MP_E( PROP_TabStopDistance, XML_NAMESPACE_STYLE, XML_TAB_STOP_DISTANCE, XML_TYPE_MEASURE, 0 ), + MAP_EXT_I( PROP_ParaTabStopDefaultDistance, XML_NAMESPACE_STYLE, XML_TAB_STOP_DISTANCE, XML_TYPE_MEASURE|XML_TYPE_PROP_PARAGRAPH, 0 ), + MAP_EXT( PROP_ParaTabStopDefaultDistance, XML_NAMESPACE_LO_EXT, XML_TAB_STOP_DISTANCE, XML_TYPE_MEASURE|XML_TYPE_PROP_PARAGRAPH, 0 ), + + // RES_PARATR_VERTALIGN + MP_E( PROP_ParaVertAlignment, XML_NAMESPACE_STYLE, XML_VERTICAL_ALIGN, XML_TYPE_TEXT_VERTICAL_ALIGN, 0 ), + + // RES_PARATR_SNAPTOGRID + MP_E( PROP_SnapToGrid, XML_NAMESPACE_STYLE, XML_SNAP_TO_LAYOUT_GRID, XML_TYPE_BOOL, 0 ), + + MP_ED( PROP_WritingMode, XML_NAMESPACE_STYLE, XML_WRITING_MODE, XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT, CTF_TEXTWRITINGMODE ), + + MP_E( PROP_ParaIsConnectBorder, XML_NAMESPACE_STYLE, XML_JOIN_BORDER, XML_TYPE_BOOL, 0 ), + + MP_E( PROP_DefaultOutlineLevel, XML_NAMESPACE_STYLE, XML_DEFAULT_OUTLINE_LEVEL, XML_TYPE_TEXT_NUMBER8_ONE_BASED|MID_FLAG_SPECIAL_ITEM_EXPORT|MID_FLAG_NO_PROPERTY_IMPORT, CTF_DEFAULT_OUTLINE_LEVEL ), + + MP_ED( PROP_FontIndependentLineSpacing, XML_NAMESPACE_STYLE, XML_FONT_INDEPENDENT_LINE_SPACING, XML_TYPE_BOOL, 0 ), + + MAP_EXT( PROP_ListAutoFormat, XML_NAMESPACE_LO_EXT, XML_MARKER_STYLE_NAME, XML_TYPE_STYLENAME|XML_TYPE_PROP_PARAGRAPH, 0 ), + + M_END() +}; + + +XMLPropertyMapEntry constexpr aXMLAdditionalTextDefaultsMap[] = +{ + // RES_FOLLOW_TEXT_FLOW - DVO #i18732# + MG_ED( PROP_IsFollowingTextFlow, XML_NAMESPACE_STYLE, XML_FLOW_WITH_TEXT, XML_TYPE_BOOL, 0 ), + + // #i28701# - RES_WRAP_INFLUENCE_ON_OBJPOS + MG_ED( PROP_WrapInfluenceOnPosition, XML_NAMESPACE_DRAW, XML_WRAP_INFLUENCE_ON_POSITION, XML_TYPE_WRAP_INFLUENCE_ON_POSITION, 0 ), + + M_END() +}; + +XMLPropertyMapEntry constexpr aXMLTextPropMap[] = +{ + // RES_CHRATR_CASEMAP + MT_E( PROP_CharCaseMap, XML_NAMESPACE_FO, XML_FONT_VARIANT, XML_TYPE_TEXT_CASEMAP_VAR, 0 ), + MT_E( PROP_CharCaseMap, XML_NAMESPACE_FO, XML_TEXT_TRANSFORM, XML_TYPE_TEXT_CASEMAP, 0 ), + // RES_CHRATR_COLOR + MT_ED( PROP_CharColor, XML_NAMESPACE_FO, XML_COLOR, XML_TYPE_COLORAUTO|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharColor, XML_NAMESPACE_STYLE, XML_USE_WINDOW_FONT_COLOR, XML_TYPE_ISAUTOCOLOR|MID_FLAG_MERGE_PROPERTY, 0 ), + MAP_EXT_I( PROP_CharTransparence, XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16 | XML_TYPE_PROP_TEXT, 0 ), + MAP_EXT( PROP_CharTransparence, XML_NAMESPACE_LO_EXT, XML_OPACITY, XML_TYPE_NEG_PERCENT16 | XML_TYPE_PROP_TEXT, 0 ), + MAP_EXT( PROP_CharComplexColor, XML_NAMESPACE_LO_EXT, XML_CHAR_COMPLEX_COLOR, XML_TYPE_COMPLEX_COLOR|XML_TYPE_PROP_TEXT|MID_FLAG_ELEMENT_ITEM, CTF_COMPLEX_COLOR ), + // RES_CHRATR_CONTOUR + MT_E( PROP_CharContoured, XML_NAMESPACE_STYLE, XML_TEXT_OUTLINE, XML_TYPE_BOOL, 0 ), + // RES_CHRATR_CROSSEDOUT + MT_E( PROP_CharStrikeout, XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_STYLE, XML_TYPE_TEXT_CROSSEDOUT_STYLE|MID_FLAG_MERGE_PROPERTY, 0), + MT_E( PROP_CharStrikeout, XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TYPE, XML_TYPE_TEXT_CROSSEDOUT_TYPE|MID_FLAG_MERGE_PROPERTY, 0), + MT_E( PROP_CharStrikeout, XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_WIDTH, XML_TYPE_TEXT_CROSSEDOUT_WIDTH|MID_FLAG_MERGE_PROPERTY, 0), + MT_E( PROP_CharStrikeout, XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TEXT, XML_TYPE_TEXT_CROSSEDOUT_TEXT|MID_FLAG_MERGE_PROPERTY, 0), + // RES_CHRATR_ESCAPEMENT + MT_E( PROP_CharEscapement, XML_NAMESPACE_STYLE, XML_TEXT_POSITION, XML_TYPE_TEXT_ESCAPEMENT|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( PROP_CharEscapementHeight, XML_NAMESPACE_STYLE, XML_TEXT_POSITION, XML_TYPE_TEXT_ESCAPEMENT_HEIGHT|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + // RES_CHRATR_FONT + MT_ED( PROP_CharFontName, XML_NAMESPACE_STYLE, XML_FONT_NAME, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME ), + MT_ED( PROP_CharFontName, XML_NAMESPACE_FO, XML_FONT_FAMILY, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME ), + MT_ED( PROP_CharFontStyleName, XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME, XML_TYPE_STRING, CTF_FONTSTYLENAME ), + MT_ED( PROP_CharFontFamily, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC, XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY ), + MT_ED( PROP_CharFontPitch, XML_NAMESPACE_STYLE, XML_FONT_PITCH, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH ), + MT_ED( PROP_CharFontCharSet, XML_NAMESPACE_STYLE, XML_FONT_CHARSET, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET ), + // RES_CHRATR_FONTSIZE + MT_ED( PROP_CharHeight, XML_NAMESPACE_FO, XML_FONT_SIZE, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT ), + MT_ED( PROP_CharPropHeight, XML_NAMESPACE_FO, XML_FONT_SIZE, XML_TYPE_CHAR_HEIGHT_PROP|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_REL ), + MT_ED( PROP_CharDiffHeight, XML_NAMESPACE_STYLE, XML_FONT_SIZE_REL, XML_TYPE_CHAR_HEIGHT_DIFF, CTF_CHARHEIGHT_DIFF ), + // RES_CHRATR_KERNING + MT_E( PROP_CharKerning, XML_NAMESPACE_FO, XML_LETTER_SPACING, XML_TYPE_TEXT_KERNING, 0 ), + // RES_CHRATR_LANGUAGE + MT_ED( PROP_CharLocale, XML_NAMESPACE_STYLE, XML_RFC_LANGUAGE_TAG, XML_TYPE_CHAR_RFC_LANGUAGE_TAG|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocale, XML_NAMESPACE_FO, XML_LANGUAGE, XML_TYPE_CHAR_LANGUAGE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocale, XML_NAMESPACE_FO, XML_SCRIPT, XML_TYPE_CHAR_SCRIPT|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocale, XML_NAMESPACE_FO, XML_COUNTRY, XML_TYPE_CHAR_COUNTRY|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_POSTURE + MT_E( PROP_CharPosture, XML_NAMESPACE_FO, XML_FONT_STYLE, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_UNUSED1 + // RES_CHRATR_SHADOWED + MT_E( PROP_CharShadowed, XML_NAMESPACE_FO, XML_TEXT_SHADOW, XML_TYPE_TEXT_SHADOWED, 0 ), + // VALIDATED UP TO THIS LINE + // RES_CHRATR_UNDERLINE + MT_E( PROP_CharUnderline, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_STYLE, XML_TYPE_TEXT_UNDERLINE_STYLE|MID_FLAG_MERGE_PROPERTY, CTF_UNDERLINE ), + MT_E( PROP_CharUnderline, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_TYPE, XML_TYPE_TEXT_UNDERLINE_TYPE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharUnderline, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_WIDTH, XML_TYPE_TEXT_UNDERLINE_WIDTH|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharUnderlineColor, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_COLOR|MID_FLAG_MULTI_PROPERTY, CTF_UNDERLINE_COLOR ), + MT_E( PROP_CharUnderlineHasColor, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_HASCOLOR|MID_FLAG_MERGE_ATTRIBUTE, CTF_UNDERLINE_HASCOLOR ), + // RES_CHRATR_WEIGHT + MT_E( PROP_CharWeight, XML_NAMESPACE_FO, XML_FONT_WEIGHT, XML_TYPE_TEXT_WEIGHT, 0 ), + // RES_CHRATR_RSID + { PROP_Rsid, XML_NAMESPACE_OFFICE_EXT, XML_RSID, XML_TYPE_HEX|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, false }, + // RES_PARATR_RSID + { PROP_ParRsid, XML_NAMESPACE_OFFICE_EXT, XML_PARRSID, XML_TYPE_HEX|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, false }, + // RES_CHRATR_WORDLINEMODE + MT_E( PROP_CharWordMode, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharWordMode, XML_NAMESPACE_STYLE, XML_TEXT_OVERLINE_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharWordMode, XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_AUTOKERN + MT_E( PROP_CharAutoKerning, XML_NAMESPACE_STYLE, XML_LETTER_KERNING, XML_TYPE_BOOL, 0 ), + // RES_CHRATR_BLINK + MT_E( PROP_CharFlash, XML_NAMESPACE_STYLE, XML_TEXT_BLINKING, XML_TYPE_BOOL, 0 ), + // RES_CHRATR_NOHYPHEN + // TODO: not used? + // RES_CHRATR_UNUSED2 + // RES_CHRATR_BACKGROUND + MT_E( PROP_CharBackColor, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_MULTI_PROPERTY, CTF_CHAR_BACKGROUND ), + MT_E( PROP_CharBackTransparent, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_ISTRANSPARENT|MID_FLAG_MERGE_ATTRIBUTE, CTF_CHAR_BACKGROUND_TRANSPARENCY), + { PROP_CharShadingValue, XML_NAMESPACE_LO_EXT, XML_CHAR_SHADING_VALUE, XML_TYPE_NUMBER|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, false }, + MT_E( PROP_CharBackColor, XML_NAMESPACE_FO, XML_TEXT_BACKGROUND_COLOR, XML_TYPE_COLOR|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_OLDTEXTBACKGROUND ), + // RES_CHRATR_CJK_FONT + MT_ED( PROP_CharFontNameAsian, XML_NAMESPACE_STYLE, XML_FONT_NAME_ASIAN, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME_CJK ), + MT_ED( PROP_CharFontNameAsian, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_ASIAN, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME_CJK ), + MT_ED( PROP_CharFontStyleNameAsian, XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME_ASIAN, XML_TYPE_STRING, CTF_FONTSTYLENAME_CJK ), + MT_ED( PROP_CharFontFamilyAsian, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC_ASIAN, XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY_CJK ), + MT_ED( PROP_CharFontPitchAsian, XML_NAMESPACE_STYLE, XML_FONT_PITCH_ASIAN, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH_CJK ), + MT_ED( PROP_CharFontCharSetAsian, XML_NAMESPACE_STYLE, XML_FONT_CHARSET_ASIAN, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET_CJK ), + // RES_CHRATR_CJK_FONTSIZE + MT_ED( PROP_CharHeightAsian, XML_NAMESPACE_STYLE, XML_FONT_SIZE_ASIAN, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_CJK ), + MT_ED( PROP_CharPropHeightAsian, XML_NAMESPACE_STYLE, XML_FONT_SIZE_ASIAN, XML_TYPE_CHAR_HEIGHT_PROP|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_REL_CJK ), + MT_ED( PROP_CharDiffHeightAsian, XML_NAMESPACE_STYLE, XML_FONT_SIZE_REL_ASIAN, XML_TYPE_CHAR_HEIGHT_DIFF, CTF_CHARHEIGHT_DIFF_CJK ), + // RES_CHRATR_CJK_LANGUAGE + MT_ED( PROP_CharLocaleAsian, XML_NAMESPACE_STYLE, XML_RFC_LANGUAGE_TAG_ASIAN, XML_TYPE_CHAR_RFC_LANGUAGE_TAG|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocaleAsian, XML_NAMESPACE_STYLE, XML_LANGUAGE_ASIAN, XML_TYPE_CHAR_LANGUAGE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocaleAsian, XML_NAMESPACE_STYLE, XML_SCRIPT_ASIAN, XML_TYPE_CHAR_SCRIPT|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocaleAsian, XML_NAMESPACE_STYLE, XML_COUNTRY_ASIAN, XML_TYPE_CHAR_COUNTRY|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_CJK_POSTURE + MT_E( PROP_CharPostureAsian, XML_NAMESPACE_STYLE, XML_FONT_STYLE_ASIAN, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_CJK_WEIGHT + MT_E( PROP_CharWeightAsian, XML_NAMESPACE_STYLE, XML_FONT_WEIGHT_ASIAN, XML_TYPE_TEXT_WEIGHT, 0 ), + // RES_CHRATR_CTL_FONT + MT_ED( PROP_CharFontNameComplex, XML_NAMESPACE_STYLE, XML_FONT_NAME_COMPLEX, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME_CTL ), + MT_ED( PROP_CharFontNameComplex, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_COMPLEX, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME_CTL ), + MT_ED( PROP_CharFontStyleNameComplex, XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME_COMPLEX, XML_TYPE_STRING, CTF_FONTSTYLENAME_CTL ), + MT_ED( PROP_CharFontFamilyComplex, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC_COMPLEX, XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY_CTL ), + MT_ED( PROP_CharFontPitchComplex, XML_NAMESPACE_STYLE, XML_FONT_PITCH_COMPLEX, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH_CTL ), + MT_ED( PROP_CharFontCharSetComplex, XML_NAMESPACE_STYLE, XML_FONT_CHARSET_COMPLEX, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET_CTL ), + // RES_CHRATR_CTL_FONTSIZE + MT_ED( PROP_CharHeightComplex, XML_NAMESPACE_STYLE, XML_FONT_SIZE_COMPLEX, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_CTL ), + MT_ED( PROP_CharPropHeightComplex, XML_NAMESPACE_STYLE, XML_FONT_SIZE_COMPLEX, XML_TYPE_CHAR_HEIGHT_PROP|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_REL_CTL ), + MT_ED( PROP_CharDiffHeightComplex, XML_NAMESPACE_STYLE, XML_FONT_SIZE_REL_COMPLEX, XML_TYPE_CHAR_HEIGHT_DIFF, CTF_CHARHEIGHT_DIFF_CTL ), + // RES_CHRATR_CTL_LANGUAGE + MT_ED( PROP_CharLocaleComplex, XML_NAMESPACE_STYLE, XML_RFC_LANGUAGE_TAG_COMPLEX, XML_TYPE_CHAR_RFC_LANGUAGE_TAG|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocaleComplex, XML_NAMESPACE_STYLE, XML_LANGUAGE_COMPLEX, XML_TYPE_CHAR_LANGUAGE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocaleComplex, XML_NAMESPACE_STYLE, XML_SCRIPT_COMPLEX, XML_TYPE_CHAR_SCRIPT|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharLocaleComplex, XML_NAMESPACE_STYLE, XML_COUNTRY_COMPLEX, XML_TYPE_CHAR_COUNTRY|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_CTL_POSTURE + MT_E( PROP_CharPostureComplex, XML_NAMESPACE_STYLE, XML_FONT_STYLE_COMPLEX, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_CTL_WEIGHT + MT_E( PROP_CharWeightComplex, XML_NAMESPACE_STYLE, XML_FONT_WEIGHT_COMPLEX, XML_TYPE_TEXT_WEIGHT, 0 ), + // RES_CHRATR_ROTATE + MT_E( PROP_CharRotation, XML_NAMESPACE_STYLE, XML_TEXT_ROTATION_ANGLE, XML_TYPE_TEXT_ROTATION_ANGLE, 0 ), + MT_E( PROP_CharRotationIsFitToLine, XML_NAMESPACE_STYLE, XML_TEXT_ROTATION_SCALE, XML_TYPE_TEXT_ROTATION_SCALE, 0 ), + // RES_CHRATR_EMPHASIS_MARK + MT_E( PROP_CharEmphasis, XML_NAMESPACE_STYLE, XML_TEXT_EMPHASIZE, XML_TYPE_TEXT_EMPHASIZE, 0 ), + // RES_CHRATR_TWO_LINES + MT_E( PROP_CharCombineIsOn, XML_NAMESPACE_STYLE, XML_TEXT_COMBINE, XML_TYPE_TEXT_COMBINE|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( PROP_CharCombinePrefix, XML_NAMESPACE_STYLE, XML_TEXT_COMBINE_START_CHAR, XML_TYPE_TEXT_COMBINECHAR, 0 ), + MT_E( PROP_CharCombineSuffix, XML_NAMESPACE_STYLE, XML_TEXT_COMBINE_END_CHAR, XML_TYPE_TEXT_COMBINECHAR, 0 ), + // RES_CHRATR_SCALEW + MT_E( PROP_CharScaleWidth, XML_NAMESPACE_STYLE, XML_TEXT_SCALE, XML_TYPE_PERCENT16, 0 ), + // combined characters field, does not correspond to a property + MT_E( PROP_, XML_NAMESPACE_STYLE, XML_TEXT_COMBINE, XML_TYPE_TEXT_COMBINE_CHARACTERS|MID_FLAG_NO_PROPERTY, CTF_COMBINED_CHARACTERS_FIELD ), + //RES_CHRATR_RELIEF + MT_E( PROP_CharRelief, XML_NAMESPACE_STYLE, XML_FONT_RELIEF, XML_TYPE_TEXT_FONT_RELIEF, 0 ), + // RES_CHRATR_HIDDEN + MT_E( PROP_CharHidden, XML_NAMESPACE_TEXT, XML_DISPLAY, XML_TYPE_TEXT_HIDDEN_AS_DISPLAY|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_TEXT_DISPLAY ), + // RES_CHRATR_OVERLINE + MT_E( PROP_CharOverline, XML_NAMESPACE_STYLE, XML_TEXT_OVERLINE_STYLE, XML_TYPE_TEXT_OVERLINE_STYLE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharOverline, XML_NAMESPACE_STYLE, XML_TEXT_OVERLINE_TYPE, XML_TYPE_TEXT_OVERLINE_TYPE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharOverline, XML_NAMESPACE_STYLE, XML_TEXT_OVERLINE_WIDTH, XML_TYPE_TEXT_OVERLINE_WIDTH|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharOverlineColor, XML_NAMESPACE_STYLE, XML_TEXT_OVERLINE_COLOR, XML_TYPE_TEXT_OVERLINE_COLOR|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( PROP_CharOverlineHasColor, XML_NAMESPACE_STYLE, XML_TEXT_OVERLINE_COLOR, XML_TYPE_TEXT_OVERLINE_HASCOLOR|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + // RES_CHRATR_BOX + MAP_EXT( PROP_CharLeftBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDERWIDTH ), + MAP_EXT( PROP_CharLeftBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDERWIDTH ), + MAP_EXT( PROP_CharRightBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDERWIDTH ), + MAP_EXT( PROP_CharTopBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDERWIDTH ), + MAP_EXT( PROP_CharBottomBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDERWIDTH ), + MAP_EXT_I( PROP_CharLeftBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDERWIDTH ), + MAP_EXT_I( PROP_CharLeftBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDERWIDTH ), + MAP_EXT_I( PROP_CharRightBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDERWIDTH ), + MAP_EXT_I( PROP_CharTopBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDERWIDTH ), + MAP_EXT_I( PROP_CharBottomBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDERWIDTH ), + + MAP_EXT( PROP_CharLeftBorderDistance, XML_NAMESPACE_LO_EXT, XML_PADDING, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDERDISTANCE ), + MAP_EXT( PROP_CharLeftBorderDistance, XML_NAMESPACE_LO_EXT, XML_PADDING_LEFT, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDERDISTANCE ), + MAP_EXT( PROP_CharRightBorderDistance, XML_NAMESPACE_LO_EXT, XML_PADDING_RIGHT, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDERDISTANCE ), + MAP_EXT( PROP_CharTopBorderDistance, XML_NAMESPACE_LO_EXT, XML_PADDING_TOP, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDERDISTANCE ), + MAP_EXT( PROP_CharBottomBorderDistance, XML_NAMESPACE_LO_EXT, XML_PADDING_BOTTOM, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDERDISTANCE ), + MAP_EXT_I( PROP_CharLeftBorderDistance, XML_NAMESPACE_FO, XML_PADDING, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDERDISTANCE ), + MAP_EXT_I( PROP_CharLeftBorderDistance, XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDERDISTANCE ), + MAP_EXT_I( PROP_CharRightBorderDistance, XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDERDISTANCE ), + MAP_EXT_I( PROP_CharTopBorderDistance, XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDERDISTANCE ), + MAP_EXT_I( PROP_CharBottomBorderDistance, XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDERDISTANCE ), + + MAP_EXT( PROP_CharLeftBorder, XML_NAMESPACE_LO_EXT, XML_BORDER, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDER ), + MAP_EXT( PROP_CharLeftBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_LEFT, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDER ), + MAP_EXT( PROP_CharRightBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_RIGHT, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDER ), + MAP_EXT( PROP_CharTopBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_TOP, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDER ), + MAP_EXT( PROP_CharBottomBorder, XML_NAMESPACE_LO_EXT, XML_BORDER_BOTTOM, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDER ), + MAP_EXT_I( PROP_CharLeftBorder, XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDER ), + MAP_EXT_I( PROP_CharLeftBorder, XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDER ), + MAP_EXT_I( PROP_CharRightBorder, XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDER ), + MAP_EXT_I( PROP_CharTopBorder, XML_NAMESPACE_FO, XML_BORDER_TOP, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDER ), + MAP_EXT_I( PROP_CharBottomBorder, XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDER ), + // RES_CHRATR_SHADOW + MAP_EXT( PROP_CharShadowFormat, XML_NAMESPACE_LO_EXT, XML_SHADOW, XML_TYPE_TEXT_SHADOW|XML_TYPE_PROP_TEXT, 0 ), + MAP_EXT_I( PROP_CharShadowFormat, XML_NAMESPACE_STYLE, XML_SHADOW, XML_TYPE_TEXT_SHADOW|XML_TYPE_PROP_TEXT, 0 ), + // RES_CHRATR_HIGHLIGHT + MT_E( PROP_CharHighlight, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY_IMPORT, CTF_CHAR_HIGHLIGHT ), + // RES_TXTATR_INETFMT + MT_E( PROP_HyperLinkURL, XML_NAMESPACE_TEXT, XML_XMLNS, XML_TYPE_STRING|MID_FLAG_NO_PROPERTY_IMPORT, CTF_HYPERLINK_URL ), + // RES_TXTATR_REFMARK + // TODO + // RES_TXTATR_TOXMARK + // TODO + // RES_TXTATR_CHARFMT + MT_E( PROP_CharStyleName, XML_NAMESPACE_TEXT, XML_STYLE_NAME, XML_TYPE_STRING|MID_FLAG_NO_PROPERTY_IMPORT, CTF_CHAR_STYLE_NAME ), + // RES_TXTATR_CJK_RUBY + // TODO + // RES_TXTATR_FIELD + // TODO + // RES_TXTATR_FLYCNT + // TODO + // RES_TXTATR_FTN + // TODO + // RES_TXTATR_SOFTHYPH + // TODO + // RES_TXTATR_HARDBLANK + // TODO + // RES_UNKNOWNATR_CONTAINER + MT_E( PROP_TextUserDefinedAttributes, XML_NAMESPACE_TEXT, XML_XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ), + MT_ED( PROP_ParaIsCharacterDistance, XML_NAMESPACE_STYLE, XML_TEXT_AUTOSPACE, XML_TYPE_TEXT_AUTOSPACE, 0 ), + MT_ED( PROP_ParaIsHangingPunctuation, XML_NAMESPACE_STYLE, XML_PUNCTUATION_WRAP, XML_TYPE_TEXT_PUNCTUATION_WRAP, 0 ), + MT_ED( PROP_ParaIsForbiddenRules, XML_NAMESPACE_STYLE, XML_LINE_BREAK, XML_TYPE_TEXT_LINE_BREAK, 0 ), + MT_E( PROP_TabStopDistance, XML_NAMESPACE_STYLE, XML_TAB_STOP_DISTANCE, XML_TYPE_MEASURE, 0 ), + + M_END() +}; + +XMLPropertyMapEntry constexpr aXMLFramePropMap[] = +{ + // RES_FILL_ORDER + // TODO: not required??? + // RES_FRM_SIZE + MG_ED( PROP_Width, XML_NAMESPACE_SVG, XML_WIDTH, XML_TYPE_MEASURE, CTF_FRAMEWIDTH_ABS ), + MG_ED( PROP_Width, XML_NAMESPACE_FO, XML_MIN_WIDTH, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_FRAMEWIDTH_MIN_ABS ), + MG_ED( PROP_RelativeWidth, XML_NAMESPACE_FO, XML_MIN_WIDTH, XML_TYPE_TEXT_REL_WIDTH_HEIGHT, CTF_FRAMEWIDTH_MIN_REL ), + MG_ED( PROP_RelativeWidth, XML_NAMESPACE_STYLE, XML_REL_WIDTH, XML_TYPE_TEXT_REL_WIDTH_HEIGHT, CTF_FRAMEWIDTH_REL ), + MG_ED( PROP_WidthType, XML_NAMESPACE_FO, XML_TEXT_BOX, XML_TYPE_NUMBER16|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FRAMEWIDTH_TYPE ), +// M_ED( "RelativeWidth", XML_NAMESPACE_STYLE, XML_REL_WIDTH, XML_TYPE_TEXT_REL_WIDTH_HEIGHT|MID_FLAG_MULTI_PROPERTY, 0 ), +// M_ED( "IsSyncWidthToHeight", XML_NAMESPACE_STYLE, XML_REL_WIDTH, XML_TYPE_TEXT_SYNC_WIDTH_HEIGHT|MID_FLAG_MULTI_PROPERTY, 0 ), + + MG_ED( PROP_Height, XML_NAMESPACE_SVG, XML_HEIGHT, XML_TYPE_MEASURE, CTF_FRAMEHEIGHT_ABS ), + MG_ED( PROP_Height, XML_NAMESPACE_FO, XML_MIN_HEIGHT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_FRAMEHEIGHT_MIN_ABS ), + MG_ED( PROP_RelativeHeight, XML_NAMESPACE_FO, XML_MIN_HEIGHT, XML_TYPE_TEXT_REL_WIDTH_HEIGHT, CTF_FRAMEHEIGHT_MIN_REL ), + MG_ED( PROP_RelativeHeight, XML_NAMESPACE_STYLE, XML_REL_HEIGHT, XML_TYPE_TEXT_REL_WIDTH_HEIGHT, CTF_FRAMEHEIGHT_REL ), +// M_ED( "RelativeHeight", XML_NAMESPACE_STYLE, XML_REL_HEIGHT, XML_TYPE_TEXT_REL_WIDTH_HEIGHT|MID_FLAG_MULTI_PROPERTY, CTF_FRAMEHEIGHT_REL ), +// M_ED( "IsSyncHeightToWidth", XML_NAMESPACE_STYLE, XML_REL_HEIGHT, XML_TYPE_TEXT_SYNC_WIDTH_HEIGHT|MID_FLAG_MULTI_PROPERTY, CTF_SYNCHEIGHT ), +// M_ED( "IsSyncHeightToWidth", XML_NAMESPACE_STYLE, XML_REL_HEIGHT, XML_TYPE_TEXT_SYNC_WIDTH_HEIGHT_MIN, CTF_SYNCHEIGHT_MIN ), + MG_ED( PROP_SizeType, XML_NAMESPACE_FO, XML_TEXT_BOX, XML_TYPE_NUMBER16|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_SIZETYPE ), + // RES_PAPER_BIN + // not required + // RES_ANCHOR + // moved to here because it is not used for automatic styles + MG_ED( PROP_AnchorType, XML_NAMESPACE_TEXT, XML_ANCHOR_TYPE, XML_TYPE_TEXT_ANCHOR_TYPE, CTF_ANCHORTYPE ), + // AnchorPage number is not required for styles! + MG_ED( PROP_HoriOrientPosition, XML_NAMESPACE_SVG, XML_X, XML_TYPE_MEASURE, 0 ), + MG_ED( PROP_VertOrientPosition, XML_NAMESPACE_SVG, XML_Y, XML_TYPE_MEASURE, 0 ), + // ***** The map for automatic styles starts here ***** + // RES_LR_SPACE + MG_E( PROP_LeftMargin, XML_NAMESPACE_FO, XML_MARGIN, XML_TYPE_MEASURE, CTF_MARGINALL ), + MG_E( PROP_LeftMargin, XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_TYPE_MEASURE, CTF_MARGINLEFT ), + MG_E( PROP_RightMargin, XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_TYPE_MEASURE, CTF_MARGINRIGHT ), + // RES_UL_SPACE + MG_E( PROP_TopMargin, XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_TYPE_MEASURE, CTF_MARGINTOP ), + MG_E( PROP_BottomMargin, XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_TYPE_MEASURE, CTF_MARGINBOTTOM ), + // RES_PAGEDESC + // not required + // RES_BREAK + // not required + // RES_CNTNT + // not required (accessed using API) + // RES_HEADER + // not required + // RES_FOOTER + // not required + // RES_PRINT + MG_E( PROP_Print, XML_NAMESPACE_STYLE, XML_PRINT_CONTENT, XML_TYPE_BOOL, 0 ), + // RES_OPAQUE + MG_ED( PROP_Opaque, XML_NAMESPACE_STYLE, XML_RUN_THROUGH, XML_TYPE_TEXT_OPAQUE, 0 ), + // RES_PROTECT + MG_E( PROP_ContentProtected, XML_NAMESPACE_STYLE, XML_PROTECT, XML_TYPE_TEXT_PROTECT_CONTENT|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + MG_E( PROP_SizeProtected, XML_NAMESPACE_STYLE, XML_PROTECT, XML_TYPE_TEXT_PROTECT_SIZE|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + MG_E( PROP_PositionProtected, XML_NAMESPACE_STYLE, XML_PROTECT, XML_TYPE_TEXT_PROTECT_POSITION|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + // RES_SURROUND + MG_ED( PROP_TextWrap, XML_NAMESPACE_STYLE, XML_WRAP, XML_TYPE_TEXT_WRAP, CTF_WRAP ), + MG_ED( PROP_SurroundAnchorOnly, XML_NAMESPACE_STYLE, XML_NUMBER_WRAPPED_PARAGRAPHS, XML_TYPE_TEXT_PARAGRAPH_ONLY, CTF_WRAP_PARAGRAPH_ONLY ), + MG_E( PROP_SurroundContour, XML_NAMESPACE_STYLE, XML_WRAP_CONTOUR, XML_TYPE_BOOL, CTF_WRAP_CONTOUR ), + MG_E( PROP_ContourOutside, XML_NAMESPACE_STYLE, XML_WRAP_CONTOUR_MODE, XML_TYPE_TEXT_WRAP_OUTSIDE, CTF_WRAP_CONTOUR_MODE ), + // RES_VERT_ORIENT + MG_ED( PROP_VertOrient, XML_NAMESPACE_STYLE, XML_VERTICAL_POS, XML_TYPE_TEXT_VERTICAL_POS, CTF_VERTICALPOS ), + MG_ED( PROP_VertOrient, XML_NAMESPACE_STYLE, XML_VERTICAL_POS, XML_TYPE_TEXT_VERTICAL_POS_AT_CHAR, CTF_VERTICALPOS_ATCHAR ), + MG_ED( PROP_VertOrient, XML_NAMESPACE_STYLE, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_AS_CHAR|MID_FLAG_MULTI_PROPERTY, CTF_VERTICALREL_ASCHAR ), + MG_ED( PROP_VertOrientRelation, XML_NAMESPACE_STYLE, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL, CTF_VERTICALREL ), + MG_ED( PROP_VertOrientRelation, XML_NAMESPACE_STYLE, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_PAGE|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_VERTICALREL_PAGE ), + MG_ED( PROP_VertOrientRelation, XML_NAMESPACE_STYLE, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_FRAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_VERTICALREL_FRAME ), + MAP_EXT_I( PROP_VertOrientRelation, XML_NAMESPACE_LO_EXT, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL|XML_TYPE_PROP_GRAPHIC|MID_FLAG_DEFAULT_ITEM_EXPORT, CTF_VERTICALREL ), + MAP_EXT_I( PROP_VertOrientRelation, XML_NAMESPACE_LO_EXT, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_PAGE|MID_FLAG_SPECIAL_ITEM_IMPORT|XML_TYPE_PROP_GRAPHIC|MID_FLAG_DEFAULT_ITEM_EXPORT, CTF_VERTICALREL_PAGE ), + MAP_EXT_I( PROP_VertOrientRelation, XML_NAMESPACE_LO_EXT, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_FRAME|MID_FLAG_SPECIAL_ITEM_IMPORT|XML_TYPE_PROP_GRAPHIC|MID_FLAG_DEFAULT_ITEM_EXPORT, CTF_VERTICALREL_FRAME ), + // RES_HORI_ORIENT + MG_ED( PROP_HoriOrient, XML_NAMESPACE_STYLE, XML_HORIZONTAL_POS, XML_TYPE_TEXT_HORIZONTAL_POS|MID_FLAG_MULTI_PROPERTY, CTF_HORIZONTALPOS ), + MG_ED( PROP_PageToggle, XML_NAMESPACE_STYLE, XML_HORIZONTAL_POS, XML_TYPE_TEXT_HORIZONTAL_MIRROR, CTF_HORIZONTALMIRROR ), + MG_ED( PROP_HoriOrient, XML_NAMESPACE_STYLE, XML_HORIZONTAL_POS, XML_TYPE_TEXT_HORIZONTAL_POS_MIRRORED|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_HORIZONTALPOS_MIRRORED ), + MG_ED( PROP_HoriOrientRelation, XML_NAMESPACE_STYLE, XML_HORIZONTAL_REL, XML_TYPE_TEXT_HORIZONTAL_REL, CTF_HORIZONTALREL ), + MG_ED( PROP_HoriOrientRelation, XML_NAMESPACE_STYLE, XML_HORIZONTAL_REL, XML_TYPE_TEXT_HORIZONTAL_REL_FRAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_HORIZONTALREL_FRAME ), + // RES_ANCHOR + // see above + // RES_BACKGROUND + // DO NOT REORDER these! + MG_ED( PROP_BackColorRGB, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_MULTI_PROPERTY, 0 ), + MG_ED( PROP_BackTransparent, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_ISTRANSPARENT|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, CTF_BACKGROUND_TRANSPARENT ), + MG_ED( PROP_BackColorTransparency, XML_NAMESPACE_STYLE, XML_BACKGROUND_TRANSPARENCY, XML_TYPE_PERCENT8, CTF_BACKGROUND_TRANSPARENCY ), + + MG_E( PROP_BackGraphicTransparency, XML_NAMESPACE_STYLE, XML_BACKGROUND_IMAGE_TRANSPARENCY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_PERCENT8, CTF_BACKGROUND_TRANSPARENCY ), + MG_E( PROP_BackGraphicLocation, XML_NAMESPACE_STYLE, XML_POSITION, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BUILDIN_CMP_ONLY, CTF_BACKGROUND_POS ), + MG_E( PROP_BackGraphicFilter, XML_NAMESPACE_STYLE, XML_FILTER_NAME, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_BACKGROUND_FILTER ), + MG_E( PROP_BackGraphic, XML_NAMESPACE_STYLE, XML_BACKGROUND_IMAGE, MID_FLAG_ELEMENT_ITEM|XML_TYPE_GRAPHIC, CTF_BACKGROUND_URL ), + + // fill attributes + GMAP( PROP_FillStyle, XML_NAMESPACE_DRAW, XML_FILL, XML_SW_TYPE_FILLSTYLE, 0 ), + GMAP( PROP_FillColor, XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( PROP_FillColor2, XML_NAMESPACE_DRAW, XML_SECONDARY_FILL_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( PROP_FillGradientName, XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLGRADIENTNAME ), + GMAP( PROP_FillGradientStepCount, XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_TYPE_NUMBER16, 0 ), + GMAP( PROP_FillHatchName, XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLHATCHNAME ), + GMAP( PROP_FillBackground, XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL, 0 ), + GMAP( PROP_FillBitmapName, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLBITMAPNAME ), + GMAP( PROP_FillTransparence, XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + GMAP( PROP_FillTransparenceGradientName, XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLTRANSNAME ), + GMAP( PROP_FillBitmapSizeX, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_FillBitmapLogicalSize, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_FillBitmapSizeY, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_FillBitmapLogicalSize, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_FillBitmapMode, XML_NAMESPACE_STYLE, XML_REPEAT, XML_SW_TYPE_BITMAP_MODE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_FillBitmapPositionOffsetX, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_TYPE_PERCENT, 0 ), + GMAP( PROP_FillBitmapPositionOffsetY, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_TYPE_PERCENT, 0 ), + GMAP( PROP_FillBitmapRectanglePoint, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_SW_TYPE_BITMAP_REFPOINT, 0 ), + GMAP( PROP_FillBitmapOffsetX, XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETX|MID_FLAG_MULTI_PROPERTY, CTF_REPEAT_OFFSET_X ), + GMAP( PROP_FillBitmapOffsetY, XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETY|MID_FLAG_MULTI_PROPERTY, CTF_REPEAT_OFFSET_Y ), + + // RES_BOX + MG_ED( PROP_LeftBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH, CTF_ALLBORDERWIDTH ), + MG_ED( PROP_LeftBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH, CTF_LEFTBORDERWIDTH ), + MG_ED( PROP_RightBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH, CTF_RIGHTBORDERWIDTH ), + MG_ED( PROP_TopBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH, CTF_TOPBORDERWIDTH ), + MG_ED( PROP_BottomBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH, CTF_BOTTOMBORDERWIDTH ), + + MG_ED( PROP_LeftBorderDistance, XML_NAMESPACE_FO, XML_PADDING, XML_TYPE_MEASURE, CTF_ALLBORDERDISTANCE ), // need special import filtering + MG_ED( PROP_LeftBorderDistance, XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE, CTF_LEFTBORDERDISTANCE ), + MG_ED( PROP_RightBorderDistance, XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE, CTF_RIGHTBORDERDISTANCE ), + MG_ED( PROP_TopBorderDistance, XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE, CTF_TOPBORDERDISTANCE ), + MG_ED( PROP_BottomBorderDistance, XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE, CTF_BOTTOMBORDERDISTANCE ), + + // There is an additional property for controls! + MG_ED( PROP_LeftBorder, XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_BORDER|MID_FLAG_MULTI_PROPERTY, CTF_ALLBORDER ), + MG_ED( PROP_LeftBorder, XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_TYPE_BORDER, CTF_LEFTBORDER ), + MG_ED( PROP_RightBorder, XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_TYPE_BORDER, CTF_RIGHTBORDER ), + MG_ED( PROP_TopBorder, XML_NAMESPACE_FO, XML_BORDER_TOP, XML_TYPE_BORDER, CTF_TOPBORDER ), + MG_ED( PROP_BottomBorder, XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_TYPE_BORDER, CTF_BOTTOMBORDER ), + // RES_SHADOW + MG_E( PROP_ShadowFormat, XML_NAMESPACE_STYLE, XML_SHADOW, XML_TYPE_TEXT_SHADOW, 0 ), + MG_E( PROP_ShadowTransparence, XML_NAMESPACE_DRAW, XML_SHADOW_OPACITY, XML_TYPE_NEG_PERCENT, 0 ), + // RES_FRMMACRO + // TODO + // RES_COL + MG_E( PROP_TextColumns, XML_NAMESPACE_STYLE, XML_COLUMNS, MID_FLAG_ELEMENT_ITEM|XML_TYPE_TEXT_COLUMNS, CTF_TEXTCOLUMNS ), + // RES_KEEP + // not required + // RES_URL + // not required (exported as draw:a element) + // RES_EDIT_IN_READONLY + MG_ED( PROP_EditInReadonly, XML_NAMESPACE_STYLE, XML_EDITABLE, XML_TYPE_BOOL, 0 ), + // RES_LAYOUT_SPLIT + // not required + // RES_CHAIN + // not required (exported at text:text-box element) + // RES_LINENUMBER + // not required + // RES_FTN_AT_TXTEND + // not required + // RES_END_AT_TXTEND + // not required + // RES_COLUMNBALANCE + // TODO + // RES_UNKNOWNATR_CONTAINER +// M_E_SE( TEXT, xmlns, RES_UNKNOWNATR_CONTAINER, 0 ), + // RES_GRFATR_MIRRORGRF (vertical MUST be processed after horizontal!) + MG_E( PROP_HoriMirroredOnEvenPages, XML_NAMESPACE_STYLE, XML_MIRROR, XML_TYPE_TEXT_MIRROR_HORIZONTAL_LEFT|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + MG_E( PROP_HoriMirroredOnOddPages, XML_NAMESPACE_STYLE, XML_MIRROR, XML_TYPE_TEXT_MIRROR_HORIZONTAL_RIGHT|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + MG_E( PROP_VertMirrored, XML_NAMESPACE_STYLE, XML_MIRROR, XML_TYPE_TEXT_MIRROR_VERTICAL|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + // RES_GRFATR_CROPGRF + MG_EV( PROP_GraphicCrop, XML_NAMESPACE_FO, XML_CLIP, XML_TYPE_TEXT_CLIP, CTF_TEXT_CLIP, SvtSaveOptions::ODFSVER_012 ), + MG_E( PROP_GraphicCrop, XML_NAMESPACE_FO, XML_CLIP, XML_TYPE_TEXT_CLIP11, CTF_TEXT_CLIP11 ), + // RES_GRFATR_ROTATION + // not required (exported as svg:transform attribute) + // RES_GRFATR_LUMINANCE + MG_E( PROP_AdjustLuminance, XML_NAMESPACE_DRAW, XML_LUMINANCE, XML_TYPE_PERCENT16, 0 ), // signed? + // RES_GRFATR_CONTRAST + MG_E( PROP_AdjustContrast, XML_NAMESPACE_DRAW, XML_CONTRAST, XML_TYPE_PERCENT16, 0 ), // signed? + // RES_GRFATR_CHANNELR + MG_E( PROP_AdjustRed, XML_NAMESPACE_DRAW, XML_RED, XML_TYPE_PERCENT16, 0 ), // signed? + // RES_GRFATR_CHANNELG + MG_E( PROP_AdjustGreen, XML_NAMESPACE_DRAW, XML_GREEN, XML_TYPE_PERCENT16, 0 ), // signed? + // RES_GRFATR_CHANNELB + MG_E( PROP_AdjustBlue, XML_NAMESPACE_DRAW, XML_BLUE, XML_TYPE_PERCENT16, 0 ), // signed? + // RES_GRFATR_GAMMA + MG_E( PROP_Gamma, XML_NAMESPACE_DRAW, XML_GAMMA, XML_TYPE_DOUBLE_PERCENT, 0 ), // signed? + // RES_GRFATR_INVERT + MG_E( PROP_GraphicIsInverted, XML_NAMESPACE_DRAW, XML_COLOR_INVERSION, XML_TYPE_BOOL, 0 ), + // RES_GRFATR_TRANSPARENCY + MG_E( PROP_Transparency, XML_NAMESPACE_DRAW, XML_IMAGE_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, 0 ), // #i25616# + // RES_GRFATR_DRAWMODE + MG_E( PROP_GraphicColorMode, XML_NAMESPACE_DRAW, XML_COLOR_MODE, XML_TYPE_COLOR_MODE, 0 ), + MG_E( PROP_WritingMode, XML_NAMESPACE_STYLE, XML_WRITING_MODE, XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT, 0 ), + MAP_EXT_I( PROP_WritingMode, XML_NAMESPACE_LO_EXT, XML_WRITING_MODE, XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT|XML_TYPE_PROP_GRAPHIC, 0), + // RES_FOLLOW_TEXT_FLOW - DVO #i18732# + MG_E( PROP_IsFollowingTextFlow, XML_NAMESPACE_DRAW, XML_FLOW_WITH_TEXT, XML_TYPE_BOOL|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_OLD_FLOW_WITH_TEXT ), + MG_E( PROP_IsFollowingTextFlow, XML_NAMESPACE_STYLE, XML_FLOW_WITH_TEXT, XML_TYPE_BOOL, 0 ), + // #i28701# - RES_WRAP_INFLUENCE_ON_OBJPOS + MG_E( PROP_WrapInfluenceOnPosition, XML_NAMESPACE_DRAW, XML_WRAP_INFLUENCE_ON_POSITION, XML_TYPE_WRAP_INFLUENCE_ON_POSITION, 0 ), + MAP_EXT( PROP_AllowOverlap, XML_NAMESPACE_LO_EXT, XML_ALLOW_OVERLAP, XML_TYPE_BOOL|XML_TYPE_PROP_GRAPHIC, 0 ), + MAP_EXT( PROP_WrapTextAtFlyStart, XML_NAMESPACE_LO_EXT, XML_WRAP_TEXT_AT_FRAME_START, XML_TYPE_BOOL|XML_TYPE_PROP_GRAPHIC, 0 ), + + // special entries for floating frames + MG_E( PROP_, XML_NAMESPACE_DRAW, XML_FRAME_DISPLAY_SCROLLBAR, XML_TYPE_BOOL|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_FRAME_DISPLAY_SCROLLBAR ), + MG_E( PROP_, XML_NAMESPACE_DRAW, XML_FRAME_DISPLAY_BORDER, XML_TYPE_BOOL|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_FRAME_DISPLAY_BORDER ), + MG_E( PROP_, XML_NAMESPACE_DRAW, XML_FRAME_MARGIN_HORIZONTAL, XML_TYPE_MEASURE_PX|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_FRAME_MARGIN_HORI ), + MG_E( PROP_, XML_NAMESPACE_DRAW, XML_FRAME_MARGIN_VERTICAL, XML_TYPE_MEASURE_PX|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_FRAME_MARGIN_VERT ), + MG_E( PROP_, XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_LEFT, XML_TYPE_MEASURE|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_OLE_VIS_AREA_LEFT ), + MG_E( PROP_, XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_TOP, XML_TYPE_MEASURE|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_OLE_VIS_AREA_TOP ), + MG_E( PROP_, XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_WIDTH, XML_TYPE_MEASURE|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_OLE_VIS_AREA_WIDTH ), + MG_E( PROP_, XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_HEIGHT, XML_TYPE_MEASURE|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_OLE_VIS_AREA_HEIGHT ), + MG_E( PROP_, XML_NAMESPACE_DRAW, XML_DRAW_ASPECT, XML_TYPE_TEXT_DRAW_ASPECT|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_OLE_DRAW_ASPECT ), + + MG_E( PROP_UserDefinedAttributes, XML_NAMESPACE_TEXT, XML_XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ), + MAP_EXT( PROP_RelativeWidthRelation, XML_NAMESPACE_LO_EXT, XML_REL_WIDTH_REL, XML_TYPE_TEXT_HORIZONTAL_REL|XML_TYPE_PROP_GRAPHIC, CTF_RELWIDTHREL), + MAP_EXT( PROP_RelativeHeightRelation, XML_NAMESPACE_LO_EXT, XML_REL_HEIGHT_REL, XML_TYPE_TEXT_VERTICAL_REL|XML_TYPE_PROP_GRAPHIC, CTF_RELHEIGHTREL), + MG_E(PROP_TextVerticalAdjust, XML_NAMESPACE_DRAW, XML_TEXTAREA_VERTICAL_ALIGN, XML_TYPE_VERTICAL_ALIGN, 0), + MAP_EXT(PROP_Decorative, XML_NAMESPACE_LO_EXT, XML_DECORATIVE, XML_TYPE_BOOL|XML_TYPE_PROP_GRAPHIC, 0), + + M_END() +}; + +XMLPropertyMapEntry constexpr aXMLShapePropMap[] = +{ + // RES_LR_SPACE + MG_E( PROP_LeftMargin, XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_TYPE_MEASURE, 0), + MG_E( PROP_RightMargin, XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_TYPE_MEASURE, 0 ), + // RES_UL_SPACE + MG_E( PROP_TopMargin, XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_TYPE_MEASURE, 0 ), + MG_E( PROP_BottomMargin, XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_TYPE_MEASURE, 0 ), + // RES_OPAQUE + MG_ED( PROP_Opaque, XML_NAMESPACE_STYLE, XML_RUN_THROUGH, XML_TYPE_TEXT_OPAQUE, 0 ), + // RES_SURROUND + MG_E( PROP_TextWrap, XML_NAMESPACE_STYLE, XML_WRAP, XML_TYPE_TEXT_WRAP, CTF_WRAP ), + MG_E( PROP_SurroundAnchorOnly, XML_NAMESPACE_STYLE, XML_NUMBER_WRAPPED_PARAGRAPHS, XML_TYPE_TEXT_PARAGRAPH_ONLY, CTF_WRAP_PARAGRAPH_ONLY ), + MG_E( PROP_SurroundContour, XML_NAMESPACE_STYLE, XML_WRAP_CONTOUR, XML_TYPE_BOOL, CTF_WRAP_CONTOUR ), + MG_E( PROP_ContourOutside, XML_NAMESPACE_STYLE, XML_WRAP_CONTOUR_MODE, XML_TYPE_TEXT_WRAP_OUTSIDE, CTF_WRAP_CONTOUR_MODE ), + // Use own CTF ids for positioning attributes (#i28749#) + // RES_VERT_ORIENT + MG_E( PROP_VertOrient, XML_NAMESPACE_STYLE, XML_VERTICAL_POS, XML_TYPE_TEXT_VERTICAL_POS, CTF_SHAPE_VERTICALPOS ), + // Add property for at-character anchored shapes (#i26791#) + MG_E( PROP_VertOrient, XML_NAMESPACE_STYLE, XML_VERTICAL_POS, XML_TYPE_TEXT_VERTICAL_POS_AT_CHAR, CTF_SHAPE_VERTICALPOS_ATCHAR ), + MG_E( PROP_VertOrient, XML_NAMESPACE_STYLE, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_AS_CHAR|MID_FLAG_MULTI_PROPERTY, CTF_VERTICALREL_ASCHAR ), + MG_E( PROP_VertOrientRelation, XML_NAMESPACE_STYLE, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL, CTF_SHAPE_VERTICALREL ), + MG_E( PROP_VertOrientRelation, XML_NAMESPACE_STYLE, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_PAGE|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_SHAPE_VERTICALREL_PAGE ), + MG_E( PROP_VertOrientRelation, XML_NAMESPACE_STYLE, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_FRAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_SHAPE_VERTICALREL_FRAME ), + MAP_EXT_I( PROP_VertOrientRelation, XML_NAMESPACE_LO_EXT, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL|XML_TYPE_PROP_GRAPHIC, CTF_VERTICALREL ), + MAP_EXT_I( PROP_VertOrientRelation, XML_NAMESPACE_LO_EXT, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_PAGE|MID_FLAG_SPECIAL_ITEM_IMPORT|XML_TYPE_PROP_GRAPHIC, CTF_VERTICALREL_PAGE ), + MAP_EXT_I( PROP_VertOrientRelation, XML_NAMESPACE_LO_EXT, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_FRAME|MID_FLAG_SPECIAL_ITEM_IMPORT|XML_TYPE_PROP_GRAPHIC, CTF_VERTICALREL_FRAME ), + // RES_HORI_ORIENT + MG_E( PROP_HoriOrient, XML_NAMESPACE_STYLE, XML_HORIZONTAL_POS, XML_TYPE_TEXT_HORIZONTAL_POS|MID_FLAG_MULTI_PROPERTY, CTF_SHAPE_HORIZONTALPOS ), + MG_E( PROP_PageToggle, XML_NAMESPACE_STYLE, XML_HORIZONTAL_POS, XML_TYPE_TEXT_HORIZONTAL_MIRROR, CTF_SHAPE_HORIZONTALMIRROR ), + MG_E( PROP_HoriOrient, XML_NAMESPACE_STYLE, XML_HORIZONTAL_POS, XML_TYPE_TEXT_HORIZONTAL_POS_MIRRORED|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_SHAPE_HORIZONTALPOS_MIRRORED ), + MG_E( PROP_HoriOrientRelation, XML_NAMESPACE_STYLE, XML_HORIZONTAL_REL, XML_TYPE_TEXT_HORIZONTAL_REL, CTF_SHAPE_HORIZONTALREL ), + MG_E( PROP_HoriOrientRelation, XML_NAMESPACE_STYLE, XML_HORIZONTAL_REL, XML_TYPE_TEXT_HORIZONTAL_REL_FRAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_SHAPE_HORIZONTALREL_FRAME ), + // RES_WRAP_INFLUENCE_ON_OBJPOS (#i28701#) + MG_ED( PROP_WrapInfluenceOnPosition, XML_NAMESPACE_DRAW, XML_WRAP_INFLUENCE_ON_POSITION, XML_TYPE_WRAP_INFLUENCE_ON_POSITION, 0 ), + MAP_EXT( PROP_AllowOverlap, XML_NAMESPACE_LO_EXT, XML_ALLOW_OVERLAP, XML_TYPE_BOOL|XML_TYPE_PROP_GRAPHIC, 0 ), + // UserDefinedAttributes is already contained in the map this one is + // chained to. + + // RES_FOLLOW_TEXT_FLOW (#i26791#) + MG_ED( PROP_IsFollowingTextFlow, XML_NAMESPACE_STYLE, XML_FLOW_WITH_TEXT, XML_TYPE_BOOL, 0 ), + + // RES_FRM_SIZE + MAP_EXT( PROP_RelativeWidthRelation, XML_NAMESPACE_LO_EXT, XML_REL_WIDTH_REL, XML_TYPE_TEXT_HORIZONTAL_REL|XML_TYPE_PROP_GRAPHIC, CTF_RELWIDTHREL ), + MAP_EXT( PROP_RelativeHeightRelation, XML_NAMESPACE_LO_EXT, XML_REL_HEIGHT_REL, XML_TYPE_TEXT_VERTICAL_REL|XML_TYPE_PROP_GRAPHIC, CTF_RELHEIGHTREL ), + + M_END() +}; + +XMLPropertyMapEntry constexpr aXMLSectionPropMap[] = +{ + // RES_COL + MS_E( PROP_TextColumns, XML_NAMESPACE_STYLE, XML_COLUMNS, MID_FLAG_ELEMENT_ITEM|XML_TYPE_TEXT_COLUMNS, CTF_TEXTCOLUMNS ), + + // RES_BACKGROUND + // DO NOT REORDER these! + MS_E( PROP_BackColor, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_MULTI_PROPERTY, 0 ), + MS_E( PROP_BackTransparent, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_ISTRANSPARENT|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + MS_E( PROP_BackGraphicLocation, XML_NAMESPACE_STYLE, XML_POSITION, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BUILDIN_CMP_ONLY, CTF_BACKGROUND_POS ), + MS_E( PROP_BackGraphicFilter, XML_NAMESPACE_STYLE, XML_FILTER_NAME, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_BACKGROUND_FILTER ), + MS_E( PROP_BackGraphic, XML_NAMESPACE_STYLE, XML_BACKGROUND_IMAGE, MID_FLAG_ELEMENT_ITEM|XML_TYPE_GRAPHIC, CTF_BACKGROUND_URL ), + + // move protect-flag into section element +// M_E( "IsProtected", STYLE, PROTECT, XML_TYPE_BOOL, 0 ), + + MS_E( PROP_DontBalanceTextColumns, XML_NAMESPACE_TEXT, XML_DONT_BALANCE_TEXT_COLUMNS, XML_TYPE_BOOL, 0 ), + + MS_E( PROP_WritingMode, XML_NAMESPACE_STYLE, XML_WRITING_MODE, XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT, 0 ), + + MS_E( PROP_SectionLeftMargin, XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_TYPE_MEASURE, 0 ), + MS_E( PROP_SectionRightMargin, XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_TYPE_MEASURE, 0 ), + + // section footnote settings + MS_E( PROP_FootnoteIsOwnNumbering, XML_NAMESPACE_TEXT, XML__EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BOOL, CTF_SECTION_FOOTNOTE_NUM_OWN ), + MS_E( PROP_FootnoteIsRestartNumbering, XML_NAMESPACE_TEXT, XML__EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BOOL, CTF_SECTION_FOOTNOTE_NUM_RESTART ), + MS_E( PROP_FootnoteRestartNumberingAt, XML_NAMESPACE_TEXT, XML__EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_NUMBER16, CTF_SECTION_FOOTNOTE_NUM_RESTART_AT ), + MS_E( PROP_FootnoteNumberingType, XML_NAMESPACE_TEXT, XML__EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_NUMBER16, CTF_SECTION_FOOTNOTE_NUM_TYPE ), + MS_E( PROP_FootnoteNumberingPrefix, XML_NAMESPACE_TEXT, XML__EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_SECTION_FOOTNOTE_NUM_PREFIX ), + MS_E( PROP_FootnoteNumberingSuffix, XML_NAMESPACE_TEXT, XML__EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_SECTION_FOOTNOTE_NUM_SUFFIX ), + MS_E( PROP_FootnoteIsCollectAtTextEnd, XML_NAMESPACE_TEXT, XML_NOTES_CONFIGURATION, MID_FLAG_ELEMENT_ITEM|XML_TYPE_BOOL, CTF_SECTION_FOOTNOTE_END ), + + // section footnote settings + MS_E( PROP_EndnoteIsOwnNumbering, XML_NAMESPACE_TEXT, XML__EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BOOL, CTF_SECTION_ENDNOTE_NUM_OWN ), + MS_E( PROP_EndnoteIsRestartNumbering, XML_NAMESPACE_TEXT, XML__EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BOOL, CTF_SECTION_ENDNOTE_NUM_RESTART ), + MS_E( PROP_EndnoteRestartNumberingAt, XML_NAMESPACE_TEXT, XML__EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_NUMBER16, CTF_SECTION_ENDNOTE_NUM_RESTART_AT ), + MS_E( PROP_EndnoteNumberingType, XML_NAMESPACE_TEXT, XML__EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_NUMBER16, CTF_SECTION_ENDNOTE_NUM_TYPE ), + MS_E( PROP_EndnoteNumberingPrefix, XML_NAMESPACE_TEXT, XML__EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_SECTION_ENDNOTE_NUM_PREFIX ), + MS_E( PROP_EndnoteNumberingSuffix, XML_NAMESPACE_TEXT, XML__EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_SECTION_ENDNOTE_NUM_SUFFIX ), + MS_E( PROP_EndnoteIsCollectAtTextEnd, XML_NAMESPACE_TEXT, XML_NOTES_CONFIGURATION, MID_FLAG_ELEMENT_ITEM|XML_TYPE_BOOL, CTF_SECTION_ENDNOTE_END ), + MS_E( PROP_UserDefinedAttributes, XML_NAMESPACE_TEXT, XML_XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ), + // RES_EDIT_IN_READONLY + MS_E( PROP_EditInReadonly, XML_NAMESPACE_STYLE, XML_EDITABLE, XML_TYPE_BOOL, 0 ), + M_END() +}; + +XMLPropertyMapEntry constexpr aXMLRubyPropMap[] = +{ + MR_E( PROP_RubyAdjust, XML_NAMESPACE_STYLE, XML_RUBY_ALIGN, XML_TYPE_TEXT_RUBY_ADJUST, 0 ), + MR_E( PROP_RubyIsAbove, XML_NAMESPACE_STYLE, XML_RUBY_POSITION, XML_TYPE_TEXT_RUBY_IS_ABOVE, 0 ), + MR_EV( PROP_RubyPosition, XML_NAMESPACE_LO_EXT, XML_RUBY_POSITION, XML_TYPE_TEXT_RUBY_POSITION, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + M_END() +}; + + +XMLPropertyMapEntry constexpr aXMLTableDefaultsMap[] = +{ + // RES_COLLAPSING_BORDERS: only occurs in tables, but we need to + // read/write the default for this item + M_ED_( PROP_CollapsingBorders, XML_NAMESPACE_TABLE, XML_BORDER_MODEL, XML_TYPE_PROP_TABLE | XML_TYPE_BORDER_MODEL | MID_FLAG_NO_PROPERTY_IMPORT, CTF_BORDER_MODEL ), + + M_END() +}; + +XMLPropertyMapEntry constexpr aXMLTableRowDefaultsMap[] = +{ + // RES_ROW_SPLIT: only occurs in table rows, but we need to + // read/write the default for this item + M_ED_( PROP_IsSplitAllowed, XML_NAMESPACE_FO, XML_KEEP_TOGETHER, XML_TYPE_PROP_TABLE_ROW | XML_TYPE_TEXT_NKEEP | MID_FLAG_NO_PROPERTY_IMPORT, CTF_KEEP_TOGETHER ), + + M_END() +}; + +XMLPropertyMapEntry constexpr aXMLCellPropMap[] = +{ + MC_E( PROP_BackColor, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_MULTI_PROPERTY, 0 ), + MC_E( PROP_LeftBorder, XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_TYPE_BORDER, 0 ), + MC_E( PROP_RightBorder, XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_TYPE_BORDER, 0 ), + MC_E( PROP_TopBorder, XML_NAMESPACE_FO, XML_BORDER_TOP, XML_TYPE_BORDER, 0 ), + MC_E( PROP_BottomBorder, XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_TYPE_BORDER, 0 ), + MC_E( PROP_BorderDistance, XML_NAMESPACE_FO, XML_PADDING, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), + MC_E( PROP_LeftBorderDistance, XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), + MC_E( PROP_RightBorderDistance, XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), + MC_E( PROP_TopBorderDistance, XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), + MC_E( PROP_BottomBorderDistance, XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), + MC_E( PROP_VertOrient, XML_NAMESPACE_STYLE, XML_VERTICAL_ALIGN, XML_TYPE_TEXT_VERTICAL_POS, 0 ), + MC_E( PROP_WritingMode, XML_NAMESPACE_STYLE, XML_WRITING_MODE, XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT, 0 ), + MC_E( PROP_NumberFormat, XML_NAMESPACE_STYLE, XML_DATA_STYLE_NAME, XML_TYPE_NUMBER|MID_FLAG_SPECIAL_ITEM_EXPORT, 0 ), + // paragraph properties + MP_E( PROP_ParaAdjust, XML_NAMESPACE_FO, XML_TEXT_ALIGN, XML_TYPE_TEXT_ADJUST, 0 ), + // text properties + MT_ED( PROP_CharColor, XML_NAMESPACE_FO, XML_COLOR, XML_TYPE_COLORAUTO|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( PROP_CharColor, XML_NAMESPACE_STYLE, XML_USE_WINDOW_FONT_COLOR, XML_TYPE_ISAUTOCOLOR|MID_FLAG_MERGE_PROPERTY, 0 ), + MAP_EXT( PROP_CharComplexColor, XML_NAMESPACE_LO_EXT, XML_CHAR_COMPLEX_COLOR, XML_TYPE_COMPLEX_COLOR|XML_TYPE_PROP_TEXT|MID_FLAG_ELEMENT_ITEM, CTF_COMPLEX_COLOR), + MT_E( PROP_CharShadowed, XML_NAMESPACE_FO, XML_TEXT_SHADOW, XML_TYPE_TEXT_SHADOWED, 0 ), + MT_E( PROP_CharContoured, XML_NAMESPACE_STYLE, XML_TEXT_OUTLINE, XML_TYPE_BOOL, 0 ), + MT_E( PROP_CharStrikeout, XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_STYLE, XML_TYPE_TEXT_CROSSEDOUT_STYLE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharStrikeout, XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TYPE, XML_TYPE_TEXT_CROSSEDOUT_TYPE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharStrikeout, XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_WIDTH, XML_TYPE_TEXT_CROSSEDOUT_WIDTH|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharStrikeout, XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TEXT, XML_TYPE_TEXT_CROSSEDOUT_TEXT|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharUnderline, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_STYLE, XML_TYPE_TEXT_UNDERLINE_STYLE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharUnderline, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_TYPE, XML_TYPE_TEXT_UNDERLINE_TYPE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharUnderline, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_WIDTH, XML_TYPE_TEXT_UNDERLINE_WIDTH|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( PROP_CharUnderlineColor, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_COLOR|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( PROP_CharUnderlineHasColor, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_HASCOLOR|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + // STANDARD FONT + MT_ED( PROP_CharHeight, XML_NAMESPACE_FO, XML_FONT_SIZE, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( PROP_CharWeight, XML_NAMESPACE_FO, XML_FONT_WEIGHT, XML_TYPE_TEXT_WEIGHT, 0 ), + MT_E( PROP_CharPosture, XML_NAMESPACE_FO, XML_FONT_STYLE, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_FONT + MT_ED( PROP_CharFontName, XML_NAMESPACE_STYLE, XML_FONT_NAME, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME ), + MT_ED( PROP_CharFontName, XML_NAMESPACE_FO, XML_FONT_FAMILY, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME ), + MT_ED( PROP_CharFontStyleName, XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME, XML_TYPE_STRING, CTF_FONTSTYLENAME ), + MT_ED( PROP_CharFontFamily, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC, XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY ), + MT_ED( PROP_CharFontPitch, XML_NAMESPACE_STYLE, XML_FONT_PITCH, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH ), + MT_ED( PROP_CharFontCharSet, XML_NAMESPACE_STYLE, XML_FONT_CHARSET, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET ), + // CJK FONT + MT_ED( PROP_CharHeightAsian, XML_NAMESPACE_STYLE, XML_FONT_SIZE_ASIAN, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( PROP_CharWeightAsian, XML_NAMESPACE_STYLE, XML_FONT_WEIGHT_ASIAN, XML_TYPE_TEXT_WEIGHT, 0 ), + MT_E( PROP_CharPostureAsian, XML_NAMESPACE_STYLE, XML_FONT_STYLE_ASIAN, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_CJK_FONT + MT_ED( PROP_CharFontNameAsian, XML_NAMESPACE_STYLE, XML_FONT_NAME_ASIAN, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME_CJK ), + MT_ED( PROP_CharFontNameAsian, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_ASIAN, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME_CJK ), + MT_ED( PROP_CharFontStyleNameAsian, XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME_ASIAN, XML_TYPE_STRING, CTF_FONTSTYLENAME_CJK ), + MT_ED( PROP_CharFontFamilyAsian, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC_ASIAN, XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY_CJK ), + MT_ED( PROP_CharFontPitchAsian, XML_NAMESPACE_STYLE, XML_FONT_PITCH_ASIAN, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH_CJK ), + MT_ED( PROP_CharFontCharSetAsian, XML_NAMESPACE_STYLE, XML_FONT_CHARSET_ASIAN, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET_CJK ), + // CTL FONT + MT_ED( PROP_CharHeightComplex, XML_NAMESPACE_STYLE, XML_FONT_SIZE_COMPLEX, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, 0), + MT_E( PROP_CharWeightComplex, XML_NAMESPACE_STYLE, XML_FONT_WEIGHT_COMPLEX, XML_TYPE_TEXT_WEIGHT, 0), + MT_E( PROP_CharPostureComplex, XML_NAMESPACE_STYLE, XML_FONT_STYLE_COMPLEX, XML_TYPE_TEXT_POSTURE, 0), + // RES_CHRATR_CTL_FONT + MT_ED( PROP_CharFontNameComplex, XML_NAMESPACE_STYLE, XML_FONT_NAME_COMPLEX, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME_CTL), + MT_ED( PROP_CharFontNameComplex, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_COMPLEX, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME_CTL), + MT_ED( PROP_CharFontStyleNameComplex, XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME_COMPLEX, XML_TYPE_STRING, CTF_FONTSTYLENAME_CTL), + MT_ED( PROP_CharFontFamilyComplex, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC_COMPLEX, XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY_CTL), + MT_ED( PROP_CharFontPitchComplex, XML_NAMESPACE_STYLE, XML_FONT_PITCH_COMPLEX, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH_CTL), + MT_ED( PROP_CharFontCharSetComplex, XML_NAMESPACE_STYLE, XML_FONT_CHARSET_COMPLEX, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET_CTL), + + M_END() +}; + +static XMLPropertyMapEntry const *lcl_txtprmap_getMap( TextPropMap nType ) +{ + XMLPropertyMapEntry const *pMap = nullptr; + switch( nType ) + { + case TextPropMap::TEXT: + pMap = aXMLTextPropMap; + break; + case TextPropMap::SHAPE_PARA: + // #i125045# use [21] instead of [1] for text props for Shapes, indices + // [1..20] contain the DrawingLayer FillStyle attributes corresponding to + // [XATTR_FILL_FIRST .. XATTR_FILL_LAST] and would be double since Shapes + // already contain these (usually in aXMLSDProperties) + pMap = &(aXMLParaPropMap[21]); + assert( pMap->meXMLName == XML_MARGIN && " shape para map changed" ); + break; + case TextPropMap::PARA: + pMap = aXMLParaPropMap; + break; + case TextPropMap::FRAME: + pMap = aXMLFramePropMap; + break; + case TextPropMap::AUTO_FRAME: + pMap = &(aXMLFramePropMap[13]); + assert( pMap->meXMLName == XML_MARGIN && " frame map changed" ); + break; + case TextPropMap::SHAPE: + pMap = aXMLShapePropMap; + break; + case TextPropMap::SECTION: + pMap = aXMLSectionPropMap; + break; + case TextPropMap::RUBY: + pMap = aXMLRubyPropMap; + break; + case TextPropMap::TEXT_ADDITIONAL_DEFAULTS: + pMap = aXMLAdditionalTextDefaultsMap; + break; + case TextPropMap::TABLE_DEFAULTS: + pMap = aXMLTableDefaultsMap; + break; + case TextPropMap::TABLE_ROW_DEFAULTS: + pMap = aXMLTableRowDefaultsMap; + break; + case TextPropMap::CELL: + pMap = aXMLCellPropMap; + break; + } + SAL_WARN_IF( !pMap, "xmloff", "illegal map type" ); + return pMap; +} + +const XMLPropertyMapEntry* XMLTextPropertySetMapper::getPropertyMapForType( TextPropMap _nType ) +{ + return lcl_txtprmap_getMap( _nType ); +} + +XMLTextPropertySetMapper::XMLTextPropertySetMapper( TextPropMap nType, bool bForExport ) : + XMLPropertySetMapper( lcl_txtprmap_getMap( nType ), + new XMLTextPropertyHandlerFactory, bForExport ) +{ +} + +XMLTextPropertySetMapper::~XMLTextPropertySetMapper() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtsecte.cxx b/xmloff/source/text/txtsecte.cxx new file mode 100644 index 0000000000..14589b961d --- /dev/null +++ b/xmloff/source/text/txtsecte.cxx @@ -0,0 +1,203 @@ +/* -*- 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/txtparae.hxx> + +#include <vector> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/text/XTextSection.hpp> +#include "XMLTextNumRuleInfo.hxx" +#include "XMLSectionExport.hxx" +#include "XMLRedlineExport.hxx" +#include <MultiPropertySetHelper.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::uno; + +using ::com::sun::star::beans::XPropertySet; + +void XMLTextParagraphExport::exportListAndSectionChange( + Reference<XTextSection> & rPrevSection, + const Reference<XTextContent> & rNextSectionContent, + const XMLTextNumRuleInfo& rPrevRule, + const XMLTextNumRuleInfo& rNextRule, + bool bAutoStyles) +{ + Reference<XTextSection> xNextSection; + + // first: get current XTextSection + Reference<XPropertySet> xPropSet(rNextSectionContent, UNO_QUERY); + if (xPropSet.is()) + { + if (xPropSet->getPropertySetInfo()->hasPropertyByName(gsTextSection)) + { + xPropSet->getPropertyValue(gsTextSection) >>= xNextSection; + } + // else: no current section + } + + exportListAndSectionChange(rPrevSection, xNextSection, + rPrevRule, rNextRule, bAutoStyles); +} + +void XMLTextParagraphExport::exportListAndSectionChange( + Reference<XTextSection> & rPrevSection, + MultiPropertySetHelper& rPropSetHelper, + sal_Int16 nTextSectionId, + const Reference<XTextContent> & rNextSectionContent, + const XMLTextNumRuleInfo& rPrevRule, + const XMLTextNumRuleInfo& rNextRule, + bool bAutoStyles) +{ + Reference<XTextSection> xNextSection; + + // first: get current XTextSection + Reference<XPropertySet> xPropSet(rNextSectionContent, UNO_QUERY); + if (xPropSet.is()) + { + if( !rPropSetHelper.checkedProperties() ) + rPropSetHelper.hasProperties( xPropSet->getPropertySetInfo() ); + if( rPropSetHelper.hasProperty( nTextSectionId )) + { + xNextSection.set(rPropSetHelper.getValue( nTextSectionId , xPropSet, + true ), uno::UNO_QUERY); + } + // else: no current section + } + + exportListAndSectionChange(rPrevSection, xNextSection, + rPrevRule, rNextRule, bAutoStyles); +} + +void XMLTextParagraphExport::exportListAndSectionChange( + Reference<XTextSection> & rPrevSection, + const Reference<XTextSection> & rNextSection, + const XMLTextNumRuleInfo& rPrevRule, + const XMLTextNumRuleInfo& rNextRule, + bool bAutoStyles) +{ + // old != new? -> maybe we have to start or end a new section + if (rPrevSection != rNextSection) + { + // a new section started, or an old one gets closed! + + // close old list + XMLTextNumRuleInfo aEmptyNumRuleInfo; + if ( !bAutoStyles ) + exportListChange(rPrevRule, aEmptyNumRuleInfo); + + // Build stacks of old and new sections + // Sections on top of mute sections should not be on the stack + std::vector< Reference<XTextSection> > aOldStack; + Reference<XTextSection> aCurrent(rPrevSection); + while(aCurrent.is()) + { + // if we have a mute section, ignore all its children + // (all previous ones) + if (m_pSectionExport->IsMuteSection(aCurrent)) + aOldStack.clear(); + + aOldStack.push_back(aCurrent); + aCurrent.set(aCurrent->getParentSection()); + } + + std::vector< Reference<XTextSection> > aNewStack; + aCurrent.set(rNextSection); + bool bMute = false; + while(aCurrent.is()) + { + // if we have a mute section, ignore all its children + // (all previous ones) + if (m_pSectionExport->IsMuteSection(aCurrent)) + { + aNewStack.clear(); + bMute = true; + } + + aNewStack.push_back(aCurrent); + aCurrent.set(aCurrent->getParentSection()); + } + + // compare the two stacks + std::vector<Reference<XTextSection> > ::reverse_iterator aOld = + aOldStack.rbegin(); + std::vector<Reference<XTextSection> > ::reverse_iterator aNew = + aNewStack.rbegin(); + // compare bottom sections and skip equal section + while ( (aOld != aOldStack.rend()) && + (aNew != aNewStack.rend()) && + (*aOld) == (*aNew) ) + { + ++aOld; + ++aNew; + } + + // close all elements of aOld ... + // (order: newest to oldest) + if (aOld != aOldStack.rend()) + { + std::vector<Reference<XTextSection> > ::iterator aOldForward( + aOldStack.begin()); + while ((aOldForward != aOldStack.end()) && + (*aOldForward != *aOld)) + { + if ( !bAutoStyles && (nullptr != m_pRedlineExport) ) + m_pRedlineExport->ExportStartOrEndRedline(*aOldForward, + false); + m_pSectionExport->ExportSectionEnd(*aOldForward, bAutoStyles); + ++aOldForward; + } + if (aOldForward != aOldStack.end()) + { + if ( !bAutoStyles && (nullptr != m_pRedlineExport) ) + m_pRedlineExport->ExportStartOrEndRedline(*aOldForward, + false); + m_pSectionExport->ExportSectionEnd(*aOldForward, bAutoStyles); + } + } + + // ...then open all of aNew + // (order: oldest to newest) + while (aNew != aNewStack.rend()) + { + if ( !bAutoStyles && (nullptr != m_pRedlineExport) ) + m_pRedlineExport->ExportStartOrEndRedline(*aNew, true); + m_pSectionExport->ExportSectionStart(*aNew, bAutoStyles); + ++aNew; + } + + // start new list + if ( !bAutoStyles && !bMute ) + exportListChange(aEmptyNumRuleInfo, rNextRule); + } + else + { + // list change, if sections have not changed + if ( !bAutoStyles ) + exportListChange(rPrevRule, rNextRule); + } + + // save old section (old numRule gets saved in calling method) + rPrevSection.set(rNextSection); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtstyle.cxx b/xmloff/source/text/txtstyle.cxx new file mode 100644 index 0000000000..552e688338 --- /dev/null +++ b/xmloff/source/text/txtstyle.cxx @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/style/ParagraphStyleCategory.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/families.hxx> +#include <xmloff/txtparae.hxx> +#include <xmloff/xmlnume.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/ProgressBarHelper.hxx> +#include "XMLSectionExport.hxx" +#include "XMLLineNumberingExport.hxx" +#include "txtexppr.hxx" +#include <xmloff/txtprmap.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + +void XMLTextParagraphExport::exportStyleAttributes( + const css::uno::Reference< css::style::XStyle > & rStyle ) +{ + Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo( + xPropSet->getPropertySetInfo()); + if( xPropSetInfo->hasPropertyByName( gsCategory ) ) + { + sal_Int16 nCategory = 0; + xPropSet->getPropertyValue( gsCategory ) >>= nCategory; + enum XMLTokenEnum eValue = XML_TOKEN_INVALID; + if( -1 != nCategory ) + { + switch( nCategory ) + { + case ParagraphStyleCategory::TEXT: + eValue = XML_TEXT; + break; + case ParagraphStyleCategory::CHAPTER: + eValue = XML_CHAPTER; + break; + case ParagraphStyleCategory::LIST: + eValue = XML_LIST; + break; + case ParagraphStyleCategory::INDEX: + eValue = XML_INDEX; + break; + case ParagraphStyleCategory::EXTRA: + eValue = XML_EXTRA; + break; + case ParagraphStyleCategory::HTML: + eValue = XML_HTML; + break; + } + } + if( eValue != XML_TOKEN_INVALID ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_CLASS, eValue); + } + if( xPropSetInfo->hasPropertyByName( gsPageDescName ) ) + { + Reference< XPropertyState > xPropState( xPropSet, uno::UNO_QUERY ); + if( PropertyState_DIRECT_VALUE == + xPropState->getPropertyState( gsPageDescName ) ) + { + OUString sName; + xPropSet->getPropertyValue( gsPageDescName ) >>= sName; + // fix for #i5551# if( sName.getLength() > 0 ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_MASTER_PAGE_NAME, + GetExport().EncodeStyleName( sName ) ); + } + } + if( m_bProgress ) + { + ProgressBarHelper *pProgress = GetExport().GetProgressBarHelper(); + pProgress->SetValue( pProgress->GetValue()+2 ); + } +} + +void XMLTextParagraphExport::exportNumStyles( bool bUsed ) +{ + SvxXMLNumRuleExport aNumRuleExport( GetExport() ); + aNumRuleExport.exportStyles(bUsed, !IsBlockMode()); +} + +void XMLTextParagraphExport::exportTextStyles( bool bUsed, bool bProg ) +{ + bool bOldProg = m_bProgress; + m_bProgress = bProg; + + Reference < lang::XMultiServiceFactory > xFactory (GetExport().GetModel(), UNO_QUERY); + if (xFactory.is()) + { + Reference < XPropertySet > xPropSet (xFactory->createInstance ( "com.sun.star.text.Defaults" ), UNO_QUERY); + if (xPropSet.is()) + { + exportDefaultStyle( xPropSet, GetXMLToken(XML_PARAGRAPH), GetParaPropMapper()); + + exportDefaultStyle( + xPropSet, + GetXMLToken(XML_TABLE), + new XMLTextExportPropertySetMapper( + new XMLTextPropertySetMapper( + TextPropMap::TABLE_DEFAULTS, true ), + GetExport() ) ); + + exportDefaultStyle( + xPropSet, + GetXMLToken(XML_TABLE_ROW), + new XMLTextExportPropertySetMapper( + new XMLTextPropertySetMapper( + TextPropMap::TABLE_ROW_DEFAULTS, true ), + GetExport() ) ); + } + } + exportStyleFamily( "ParagraphStyles", GetXMLToken(XML_PARAGRAPH), GetParaPropMapper(), + bUsed, XmlStyleFamily::TEXT_PARAGRAPH); + exportStyleFamily( "CharacterStyles", GetXMLToken(XML_TEXT), GetTextPropMapper(), + bUsed, XmlStyleFamily::TEXT_TEXT ); + // get shape export to make sure the frame family is added correctly. + GetExport().GetShapeExport(); + exportStyleFamily( "FrameStyles", XML_STYLE_FAMILY_SD_GRAPHICS_NAME, m_xFramePropMapper, + bUsed, XmlStyleFamily::TEXT_FRAME); + exportNumStyles( bUsed ); + if( !IsBlockMode() ) + { + exportTextFootnoteConfiguration(); + XMLSectionExport::ExportBibliographyConfiguration(GetExport()); + XMLLineNumberingExport aLineNumberingExport(GetExport()); + aLineNumberingExport.Export(); + } + + m_bProgress = bOldProg; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtstyli.cxx b/xmloff/source/text/txtstyli.cxx new file mode 100644 index 0000000000..bf4893479d --- /dev/null +++ b/xmloff/source/text/txtstyli.cxx @@ -0,0 +1,633 @@ +/* -*- 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 "XMLTextPropertySetContext.hxx" +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/XMLEventsImportContext.hxx> +#include <xmloff/families.hxx> +#include <xmloff/txtprmap.hxx> +#include <xmloff/txtstyli.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/maptype.hxx> +#include <xmloff/xmlimppr.hxx> +#include <xmloff/xmlement.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/style/ParagraphStyleCategory.hpp> +#include <com/sun/star/style/XStyle.hpp> + +#include <o3tl/any.hxx> + +#include <sax/tools/converter.hxx> + +#include <tools/debug.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <sal/log.hxx> + +#include <vector> + +#include <xmlsdtypes.hxx> +#include <xmloff/xmlerror.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::xmloff::token; + +const SvXMLEnumMapEntry<sal_uInt16> aCategoryMap[] = +{ + { XML_TEXT, ParagraphStyleCategory::TEXT }, + { XML_CHAPTER, ParagraphStyleCategory::CHAPTER }, + { XML_LIST, ParagraphStyleCategory::LIST }, + { XML_INDEX, ParagraphStyleCategory::INDEX }, + { XML_EXTRA, ParagraphStyleCategory::EXTRA }, + { XML_HTML, ParagraphStyleCategory::HTML }, + { XML_TOKEN_INVALID, 0 } +}; + +void XMLTextStyleContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + switch (nElement) + { + case XML_ELEMENT(STYLE, XML_AUTO_UPDATE): + { + if( IsXMLToken( rValue, XML_TRUE ) ) + m_isAutoUpdate = true; + break; + } + case XML_ELEMENT(STYLE, XML_LIST_STYLE_NAME): + { + m_sListStyleName = rValue; + // Inherited paragraph style lost information about unset numbering (#i69523#) + m_bListStyleSet = true; + break; + } + case XML_ELEMENT(STYLE, XML_MASTER_PAGE_NAME): + { + m_sMasterPageName = rValue; + m_bHasMasterPageName = true; + break; + } + case XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME): + m_sDataStyleName = rValue; + break; + case XML_ELEMENT(STYLE, XML_CLASS): + m_sCategoryVal = rValue; + break; + case XML_ELEMENT(STYLE, XML_DEFAULT_OUTLINE_LEVEL): + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber( nTmp, rValue ) && + 0 <= nTmp && nTmp <= 10 ) + { + m_nOutlineLevel = static_cast<sal_Int8>(nTmp); + } + break; + } + case XML_ELEMENT(STYLE, XML_LIST_LEVEL): + { + sal_Int32 nTmp; + // The spec is positiveInteger (1-based), but the implementation is 0-based. + if (sax::Converter::convertNumber(nTmp, rValue) && nTmp > 0 && nTmp <= 10) + { + m_aListLevel.emplace(--nTmp); + } + break; + } + default: + XMLPropStyleContext::SetAttribute( nElement, rValue ); + } +} + +XMLTextStyleContext::XMLTextStyleContext( SvXMLImport& rImport, + SvXMLStylesContext& rStyles, XmlStyleFamily nFamily, + bool bDefaultStyle ) +: XMLPropStyleContext( rImport, rStyles, nFamily, bDefaultStyle ) +, m_nOutlineLevel( -1 ) +, m_isAutoUpdate( false ) +, m_bHasMasterPageName( false ) +, m_bHasCombinedCharactersLetter( false ) +// Inherited paragraph style lost information about unset numbering (#i69523#) +, m_bListStyleSet( false ) +{ +} + +XMLTextStyleContext::~XMLTextStyleContext() +{} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( IsTokenInNamespace(nElement, XML_NAMESPACE_STYLE) ) + { + sal_Int32 nLocalName = nElement & TOKEN_MASK; + sal_uInt32 nFamily = 0; + if( nLocalName == XML_TEXT_PROPERTIES ) + nFamily = XML_TYPE_PROP_TEXT; + else if( nLocalName == XML_PARAGRAPH_PROPERTIES ) + nFamily = XML_TYPE_PROP_PARAGRAPH; + else if( nLocalName == XML_SECTION_PROPERTIES ) + nFamily = XML_TYPE_PROP_SECTION; + else if( IsDefaultStyle() && nLocalName == XML_TABLE_PROPERTIES ) + nFamily = XML_TYPE_PROP_TABLE; + else if( IsDefaultStyle() && nLocalName == XML_TABLE_ROW_PROPERTIES ) + nFamily = XML_TYPE_PROP_TABLE_ROW; + if( nFamily ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + return new XMLTextPropertySetContext( GetImport(), nElement, xAttrList, + nFamily, + GetProperties(), + xImpPrMap, + m_sDropCapTextStyleName); + } + } + else if ( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + // create and remember events import context + // (for delayed processing of events) + m_xEventContext.set(new XMLEventsImportContext( GetImport() )); + return m_xEventContext; + } + + return XMLPropStyleContext::createFastChildContext( nElement, xAttrList ); +} + +void XMLTextStyleContext::CreateAndInsert( bool bOverwrite ) +{ + XMLPropStyleContext::CreateAndInsert( bOverwrite ); + Reference < XStyle > xStyle = GetStyle(); + if( !xStyle.is() || !(bOverwrite || IsNew()) ) + return; + + Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + + static constexpr OUString sIsAutoUpdate(u"IsAutoUpdate"_ustr); + if( xPropSetInfo->hasPropertyByName( sIsAutoUpdate ) ) + { + xPropSet->setPropertyValue( sIsAutoUpdate, Any(m_isAutoUpdate) ); + } + + sal_uInt16 nCategory = ParagraphStyleCategory::TEXT; + if( XmlStyleFamily::TEXT_PARAGRAPH == GetFamily() && + !m_sCategoryVal.isEmpty() && xStyle->isUserDefined() && + xPropSetInfo->hasPropertyByName("Category") && + SvXMLUnitConverter::convertEnum( nCategory, m_sCategoryVal, aCategoryMap)) + { + xPropSet->setPropertyValue("Category", Any(static_cast<sal_Int16>(nCategory))); + } + + // tell the style about it's events (if applicable) + if (m_xEventContext.is()) + { + // pass events into event supplier + Reference<document::XEventsSupplier> xEventsSupplier(xStyle,UNO_QUERY); + m_xEventContext->SetEvents(xEventsSupplier); + m_xEventContext.clear(); + } + + // XML import: reconstruction of assignment of paragraph style to outline levels (#i69629#) + if (m_nOutlineLevel > 0) + { + GetImport().GetTextImport()->AddOutlineStyleCandidate(m_nOutlineLevel, + GetDisplayName() ); + } +} + +void XMLTextStyleContext::SetDefaults( ) +{ + if( ( GetFamily() == XmlStyleFamily::TEXT_PARAGRAPH ) || + ( GetFamily() == XmlStyleFamily::TABLE_TABLE ) || + ( GetFamily() == XmlStyleFamily::TABLE_ROW ) ) + { + Reference < XMultiServiceFactory > xFactory ( GetImport().GetModel(), UNO_QUERY); + if (xFactory.is()) + { + Reference < XInterface > xInt = xFactory->createInstance( "com.sun.star.text.Defaults" ); + Reference < XPropertySet > xProperties ( xInt, UNO_QUERY ); + if ( xProperties.is() ) + FillPropertySet ( xProperties ); + } + } +} + +void XMLTextStyleContext::Finish( bool bOverwrite ) +{ + XMLPropStyleContext::Finish( bOverwrite ); + + Reference < XStyle > xStyle = GetStyle(); + // Consider set empty list style (#i69523#) + if ( !( m_bListStyleSet || + m_nOutlineLevel >= 0 || + !m_sDropCapTextStyleName.isEmpty() || + m_bHasMasterPageName ) || + !xStyle.is() || + !( bOverwrite || IsNew() ) ) + return; + + Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + + static constexpr OUString sOutlineLevel(u"OutlineLevel"_ustr); + if( xPropSetInfo->hasPropertyByName( sOutlineLevel )) + { + if (m_nOutlineLevel >= 0) + { + xPropSet->setPropertyValue( sOutlineLevel, Any(m_nOutlineLevel) ); + } + } + + // Consider set empty list style (#i69523#) + static constexpr OUString sNumberingStyleName(u"NumberingStyleName"_ustr); + if (m_bListStyleSet && + xPropSetInfo->hasPropertyByName( sNumberingStyleName ) ) + { + /* Only for text document from version prior OOo 2.1 resp. SO 8 PU5: + - Do not apply list style, if paragraph style has a default outline + level > 0 and thus, will be assigned to the corresponding list + level of the outline style. (#i70223#) + */ + bool bApplyListStyle( true ); + if (m_nOutlineLevel > 0) + { + if ( GetImport().IsTextDocInOOoFileFormat() ) + { + bApplyListStyle = false; + } + else + { + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + // Check explicitly on certain versions (#i86058#) + if ( GetImport().getBuildIds( nUPD, nBuild ) && + ( ( nUPD == 641 ) || ( nUPD == 645 ) || // prior OOo 2.0 + ( nUPD == 680 && nBuild <= 9073 ) ) ) // OOo 2.0 - OOo 2.0.4 + { + bApplyListStyle = false; + } + } + } + + if ( bApplyListStyle ) + { + if (m_sListStyleName.isEmpty()) + { + xPropSet->setPropertyValue(sNumberingStyleName, Any(m_sListStyleName)); /* empty string */ + } + else + { + // change list style name to display name + OUString sDisplayListStyleName( + GetImport().GetStyleDisplayName(XmlStyleFamily::TEXT_LIST, + m_sListStyleName)); + // The families container must exist + const Reference < XNameContainer >& rNumStyles = + GetImport().GetTextImport()->GetNumberingStyles(); + // if( rNumStyles.is() && rNumStyles->hasByName( sDisplayListStyleName ) && + // xPropSetInfo->hasPropertyByName( sNumberingStyleName ) ) + if ( rNumStyles.is() && + rNumStyles->hasByName( sDisplayListStyleName ) ) + { + xPropSet->setPropertyValue( sNumberingStyleName, Any(sDisplayListStyleName) ); + } + } + + if (m_aListLevel.has_value()) + { + xPropSet->setPropertyValue("NumberingLevel", uno::Any(*m_aListLevel)); + } + } + } + + if (!m_sDropCapTextStyleName.isEmpty()) + { + // change list style name to display name + OUString sDisplayDropCapTextStyleName( + GetImport().GetStyleDisplayName( XmlStyleFamily::TEXT_TEXT, + m_sDropCapTextStyleName)); + // The families container must exist + const Reference < XNameContainer >& rTextStyles = + GetImport().GetTextImport()->GetTextStyles(); + if( rTextStyles.is() && + rTextStyles->hasByName( sDisplayDropCapTextStyleName ) && + xPropSetInfo->hasPropertyByName("DropCapCharStyleName")) + { + xPropSet->setPropertyValue("DropCapCharStyleName", Any(sDisplayDropCapTextStyleName)); + } + } + + if (!m_bHasMasterPageName) + return; + + OUString sDisplayName( + GetImport().GetStyleDisplayName( + XmlStyleFamily::MASTER_PAGE, m_sMasterPageName)); + // The families container must exist + const Reference < XNameContainer >& rPageStyles = + GetImport().GetTextImport()->GetPageStyles(); + + static constexpr OUString sPageDescName(u"PageDescName"_ustr); + if( ( sDisplayName.isEmpty() || + (rPageStyles.is() && + rPageStyles->hasByName( sDisplayName )) ) && + xPropSetInfo->hasPropertyByName( sPageDescName ) ) + { + xPropSet->setPropertyValue( sPageDescName, Any(sDisplayName) ); + } +} + +void XMLTextStyleContext::FillPropertySet( + const Reference<XPropertySet > & rPropSet ) +{ + // imitate the FillPropertySet of the super class, so we get a chance to + // catch the combined characters attribute + + // imitate XMLPropStyleContext::FillPropertySet(...) + SvXMLStylesContext* pSvXMLStylesContext = GetStyles(); + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = pSvXMLStylesContext->GetImportPropertyMapper(GetFamily()); + DBG_ASSERT(xImpPrMap.is(),"Where is the import prop mapper?"); + + if(!xImpPrMap.is()) + return; + + // imitate SvXMLImportPropertyMapper::FillPropertySet(...) + // The reason for this is that we have no other way to + // efficiently intercept the value of combined characters. To + // get that value, we could iterate through the map once more, + // but instead we chose to insert the code into this + // iteration. I haven't been able to come up with a much more + // intelligent solution. + struct ContextID_Index_Pair aContextIDs[] = + { + { CTF_COMBINED_CHARACTERS_FIELD, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_KEEP_TOGETHER, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_BORDER_MODEL, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_TEXT_DISPLAY, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_FONTFAMILYNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_FONTFAMILYNAME_CJK, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_FONTFAMILYNAME_CTL, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + + //UUU need special handling for DrawingLayer FillStyle names + { CTF_FILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT }, + { CTF_FILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_FILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH }, + { CTF_FILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP }, + + { -1, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE } + }; + + // the style families associated with the same index modulo 4 + static const XmlStyleFamily aFamilies[] = + { + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_HATCH_ID, + XmlStyleFamily::SD_FILL_IMAGE_ID + }; + + // get property set info + Reference< XPropertySetInfo > xInfo; + rtl::Reference< XMLPropertySetMapper > rPropMapper; + bool bAutomatic = false; + + if(pSvXMLStylesContext->IsAutomaticStyle() && + (XmlStyleFamily::TEXT_TEXT == GetFamily() || XmlStyleFamily::TEXT_PARAGRAPH == GetFamily())) + { + bAutomatic = true; + + if( GetAutoName().hasValue() ) + { + OUString sAutoProp = ( GetFamily() == XmlStyleFamily::TEXT_TEXT ) ? + OUString( "CharAutoStyleName" ): + OUString( "ParaAutoStyleName" ); + + try + { + if(!xInfo.is()) + { + xInfo = rPropSet->getPropertySetInfo(); + } + + if ( xInfo->hasPropertyByName( sAutoProp ) ) + { + rPropSet->setPropertyValue( sAutoProp, GetAutoName() ); + } + else + { + bAutomatic = false; + } + } + catch( const RuntimeException& ) { throw; } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.text"); + bAutomatic = false; + } + } + } + + if( bAutomatic ) + { + xImpPrMap->CheckSpecialContext( GetProperties(), rPropSet, aContextIDs ); + } + else + { + xImpPrMap->FillPropertySet( GetProperties(), rPropSet, aContextIDs ); + } + + sal_Int32 nIndex = aContextIDs[0].nIndex; + + // have we found a combined characters + if ( nIndex != -1 ) + { + Any& rAny = GetProperties()[nIndex].maValue; + bool bVal = *o3tl::doAccess<bool>(rAny); + m_bHasCombinedCharactersLetter = bVal; + } + + // keep-together: the application default is different from + // the file format default. Hence, if we always set this + // value; if we didn't find one, we'll set to false, the file + // format default. + // border-model: same + if(IsDefaultStyle() && XmlStyleFamily::TABLE_ROW == GetFamily()) + { + OUString sIsSplitAllowed("IsSplitAllowed"); + SAL_WARN_IF( !rPropSet->getPropertySetInfo()->hasPropertyByName( sIsSplitAllowed ), "xmloff", "property missing?" ); + rPropSet->setPropertyValue( + sIsSplitAllowed, + (aContextIDs[1].nIndex == -1) ? Any( false ) : GetProperties()[aContextIDs[1].nIndex].maValue ); + } + + if(IsDefaultStyle() && XmlStyleFamily::TABLE_TABLE == GetFamily()) + { + OUString sCollapsingBorders("CollapsingBorders"); + SAL_WARN_IF( !rPropSet->getPropertySetInfo()->hasPropertyByName( sCollapsingBorders ), "xmloff", "property missing?" ); + rPropSet->setPropertyValue( + sCollapsingBorders, + (aContextIDs[2].nIndex == -1) + ? Any( false ) + : GetProperties()[aContextIDs[2].nIndex].maValue ); + } + + + // iterate over aContextIDs entries, start with 3, prev ones are already used above + for(sal_uInt16 i(3); aContextIDs[i].nContextID != -1; i++) + { + nIndex = aContextIDs[i].nIndex; + + if ( nIndex != -1 ) + { + // Found! + struct XMLPropertyState& rState = GetProperties()[nIndex]; + + switch(aContextIDs[i].nContextID) + { + case CTF_FILLGRADIENTNAME: + case CTF_FILLTRANSNAME: + case CTF_FILLHATCHNAME: + case CTF_FILLBITMAPNAME: + { + // DrawingLayer FillStyle name needs to be mapped to DisplayName + OUString sStyleName; + rState.maValue >>= sStyleName; + + // translate the used name from ODF intern to the name used in the Model + sStyleName = GetImport().GetStyleDisplayName(aFamilies[i - 7], sStyleName); + + if(bAutomatic) + { + // in this case the rPropSet got not really filled since above the call to + // CheckSpecialContext was used and not FillPropertySet, thus the below call to + // setPropertyValue can fail/will not be useful (e.g. when the rPropSet + // is a SwXTextCursor). + // This happens for AutoStyles which are already filled in XMLPropStyleContext::CreateAndInsert, + // thus the whole mechanism based on _ContextID_Index_Pair will not work + // in that case. Thus the slots which need to be converted already get + // converted there (it's called first) and not here (see + // translateNameBasedDrawingLayerFillStyleDefinitionsToStyleDisplayNames) + // For convenience, still Write back the corrected value to the XMLPropertyState entry + rState.maValue <<= sStyleName; + break; + } + + if (::xmloff::IsIgnoreFillStyleNamedItem(rPropSet, aContextIDs[i].nExpectedFillStyle)) + { + SAL_INFO("xmloff.style", "XMLTextStyleContext: dropping fill named item: " << sStyleName); + break; // ignore it, it's not used + } + + // Still needed if it's not an AutomaticStyle (!) + try + { + if(!rPropMapper.is()) + { + rPropMapper = xImpPrMap->getPropertySetMapper(); + } + + // set property + const OUString& rPropertyName = rPropMapper->GetEntryAPIName(rState.mnIndex); + + if(!xInfo.is()) + { + xInfo = rPropSet->getPropertySetInfo(); + } + + if(xInfo->hasPropertyByName(rPropertyName)) + { + rPropSet->setPropertyValue(rPropertyName,Any(sStyleName)); + } + } + catch(css::lang::IllegalArgumentException& e) + { + Sequence<OUString> aSeq { sStyleName }; + GetImport().SetError(XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_WARNING, aSeq, e.Message, nullptr); + } + break; + } + default: + { + // check for StarBats and StarMath fonts + Any rAny = rState.maValue; + sal_Int32 nMapperIndex = rState.mnIndex; + + // Now check for font name in rState and set corrected value, + // if necessary. + OUString sFontName; + rAny >>= sFontName; + + if ( !sFontName.isEmpty() ) + { + if ( sFontName.equalsIgnoreAsciiCase( "StarBats" ) || + sFontName.equalsIgnoreAsciiCase( "StarMath" ) ) + { + // construct new value + sFontName = "StarSymbol"; + Any aAny(rAny); + aAny <<= sFontName; + + if(!rPropMapper.is()) + { + rPropMapper = xImpPrMap->getPropertySetMapper(); + } + + // set property + OUString rPropertyName(rPropMapper->GetEntryAPIName(nMapperIndex)); + + if(!xInfo.is()) + { + xInfo = rPropSet->getPropertySetInfo(); + } + + if(xInfo->hasPropertyByName(rPropertyName)) + { + rPropSet->setPropertyValue(rPropertyName,aAny); + } + } + // else: "normal" style name -> no correction is necessary + } + // else: no style name found -> illegal value -> ignore + } + } + } + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtvfldi.cxx b/xmloff/source/text/txtvfldi.cxx new file mode 100644 index 0000000000..7855a2c5be --- /dev/null +++ b/xmloff/source/text/txtvfldi.cxx @@ -0,0 +1,1247 @@ +/* -*- 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 . + */ + + +/** @#file + * + * export of all variable related text fields (and database display field) + */ +#include <txtvfldi.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/txtimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/i18nmap.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/text/SetVariableType.hpp> +#include <com/sun/star/text/XDependentTextField.hpp> +#include <com/sun/star/text/XTextFieldsSupplier.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/style/NumberingType.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> + +#include <sax/tools/converter.hxx> + +#include <rtl/ustring.hxx> +#include <osl/diagnose.h> +#include <sal/log.hxx> + +#include <tools/debug.hxx> +#include <comphelper/diagnose_ex.hxx> + + +// service names +constexpr char16_t sAPI_fieldmaster_prefix[] = u"com.sun.star.text.FieldMaster."; +constexpr OUString sAPI_get_expression = u"GetExpression"_ustr; +constexpr OUString sAPI_set_expression = u"SetExpression"_ustr; +constexpr OUString sAPI_user = u"User"_ustr; +constexpr OUString sAPI_database = u"com.sun.star.text.TextField.Database"_ustr; + +// property names +constexpr OUString sAPI_content = u"Content"_ustr; +constexpr OUString sAPI_sub_type = u"SubType"_ustr; +constexpr OUString sAPI_number_format = u"NumberFormat"_ustr; +constexpr OUString sAPI_is_visible = u"IsVisible"_ustr; +constexpr OUString sAPI_current_presentation = u"CurrentPresentation"_ustr; + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::style; +using namespace ::xmloff::token; + + +// XMLVarFieldImportContext: superclass for all variable related fields + + +XMLVarFieldImportContext::XMLVarFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + const OUString& pServiceName, + bool bFormula, bool bFormulaDefault, + bool bDescription, bool bHelp, bool bHint, bool bVisible, + bool bIsDisplayFormula, + bool bType, bool bStyle, bool bValue, + bool bPresentation) : + XMLTextFieldImportContext(rImport, rHlp, pServiceName), + aValueHelper(rImport, rHlp, bType, bStyle, bValue, false), + bDisplayFormula(false), + bDisplayNone(false), + bFormulaOK(false), + bDescriptionOK(false), + bHelpOK(false), + bHintOK(false), + bDisplayOK(false), + bSetFormula(bFormula), + bSetFormulaDefault(bFormulaDefault), + bSetDescription(bDescription), + bSetHelp(bHelp), + bSetHint(bHint), + bSetVisible(bVisible), + bSetDisplayFormula(bIsDisplayFormula), + bSetPresentation(bPresentation) +{ +} + +void XMLVarFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_NAME): + sName = OUString::fromUtf8(sAttrValue); + bValid = true; // we assume: field with name is valid! + break; + case XML_ELEMENT(TEXT, XML_DESCRIPTION): + sDescription = OUString::fromUtf8(sAttrValue); + bDescriptionOK = true; + break; + case XML_ELEMENT(TEXT, XML_HELP): + sHelp = OUString::fromUtf8(sAttrValue); + bHelpOK = true; + break; + case XML_ELEMENT(TEXT, XML_HINT): + sHint = OUString::fromUtf8(sAttrValue); + bHintOK = true; + break; + case XML_ELEMENT(TEXT, XML_FORMULA): + { + OUString sTmp; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap(). + GetKeyByAttrValueQName(OUString::fromUtf8(sAttrValue), &sTmp); + if( XML_NAMESPACE_OOOW == nPrefix ) + { + sFormula = sTmp; + bFormulaOK = true; + } + else + sFormula = OUString::fromUtf8(sAttrValue); + } + break; + case XML_ELEMENT(TEXT, XML_DISPLAY): + if (IsXMLToken(sAttrValue, XML_FORMULA)) + { + bDisplayFormula = true; + bDisplayNone = false; + bDisplayOK = true; + } + else if (IsXMLToken(sAttrValue, XML_VALUE)) + { + bDisplayFormula = false; + bDisplayNone = false; + bDisplayOK = true; + } + else if (IsXMLToken(sAttrValue, XML_NONE)) + { + bDisplayFormula = false; + bDisplayNone = true; + bDisplayOK = true; + } // else: no change + DBG_ASSERT(!(bDisplayFormula && bDisplayNone), + "illegal display values"); + break; + default: + // delegate all others to value helper + aValueHelper.ProcessAttribute(nAttrToken, sAttrValue); + break; + } +} + +void XMLVarFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + // bSetName: not implemented + + if (bSetFormula) + { + if (!bFormulaOK && bSetFormulaDefault) + { + sFormula = GetContent(); + bFormulaOK = true; + } + + if (bFormulaOK) + { + xPropertySet->setPropertyValue(sAPI_content, Any(sFormula)); + } + } + + if (bSetDescription && bDescriptionOK) + { + xPropertySet->setPropertyValue("Hint", Any(sDescription)); + } + + if (bSetHelp && bHelpOK) + { + xPropertySet->setPropertyValue("Help", Any(sHelp)); + } + + if (bSetHint && bHintOK) + { + xPropertySet->setPropertyValue("Tooltip", Any(sHint)); + } + + if (bSetVisible && bDisplayOK) + { + bool bTmp = !bDisplayNone; + xPropertySet->setPropertyValue(sAPI_is_visible, Any(bTmp)); + } + + // workaround for #no-bug#: display formula by default + if (xPropertySet->getPropertySetInfo()-> + hasPropertyByName("IsShowFormula") && + !bSetDisplayFormula) + { + bDisplayFormula = false; + bSetDisplayFormula = true; + } + + + if (bSetDisplayFormula) + { + bool bTmp = bDisplayFormula && bDisplayOK; + xPropertySet->setPropertyValue("IsShowFormula", Any(bTmp)); + } + + // delegate to value helper + aValueHelper.SetDefault(GetContent()); + aValueHelper.PrepareField(xPropertySet); + + // finally, set the current presentation + if (bSetPresentation) + { + Any aAny; + aAny <<= GetContent(); + xPropertySet->setPropertyValue(sAPI_current_presentation, aAny); + } +} + + +// variable set fields + + +XMLSetVarFieldImportContext::XMLSetVarFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + const OUString& pServiceName, VarType eVarType, + bool bFormula, bool bFormulaDefault, + bool bDescription, bool bHelp, bool bHint, bool bVisible, bool bIsDisplayFormula, + bool bType, bool bStyle, bool bValue, bool bPresentation) : + XMLVarFieldImportContext(rImport, rHlp, pServiceName, + bFormula, bFormulaDefault, + bDescription, bHelp, bHint, bVisible, bIsDisplayFormula, + bType, bStyle, bValue, bPresentation), + eFieldType(eVarType) +{ +} + +void XMLSetVarFieldImportContext::endFastElement(sal_Int32 ) +{ + // should we call PrepareField on the field, or rather on it's master? + // currently: call on field (just like superclass) + // possible alternatives: call on master + // call field or master depending on variable + // PrepareMaster() in addition to PrepareField() + + DBG_ASSERT(!GetServiceName().isEmpty(), "no service name for element!"); + + if (bValid) + { + DBG_ASSERT(!GetName().isEmpty(), "variable name needed!"); + + // find field master + Reference<XPropertySet> xMaster; + if (FindFieldMaster(xMaster)) + { + // create field/Service + Reference<XPropertySet> xPropSet; + if (CreateField(xPropSet, "com.sun.star.text.TextField." + GetServiceName())) + { + Reference<XDependentTextField> xDepTextField(xPropSet, UNO_QUERY); + if (xDepTextField.is()) + { + // attach field to field master + xDepTextField->attachTextFieldMaster(xMaster); + + // attach field to document + Reference<XTextContent> xTextContent(xPropSet, UNO_QUERY); + if (xTextContent.is()) + { + try { + // insert, set field properties and exit! + GetImportHelper().InsertTextContent(xTextContent); + PrepareField(xPropSet); + } catch (lang::IllegalArgumentException & /*e*/) + { + // ignore e: #i54023# + }; + return; + } + } + } + } + } + + // above: exit on success; so for all error cases we end up here! + // write element content + GetImportHelper().InsertString(GetContent()); +} + +bool XMLSetVarFieldImportContext::FindFieldMaster( + Reference<XPropertySet> & xMaster) +{ + // currently: delegate to XMLVariableDeclImportContext; + // should eventually go here + return XMLVariableDeclImportContext::FindFieldMaster(xMaster, + GetImport(), + GetImportHelper(), + GetName(), + eFieldType); +} + + +// sequence field + + +XMLSequenceFieldImportContext::XMLSequenceFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLSetVarFieldImportContext(rImport, rHlp, sAPI_set_expression, + VarTypeSequence, + // formula + true, true, + false, false, false, false, + false, + false, false, false, true), + + sNumFormat(OUString('1')), + sNumFormatSync(GetXMLToken(XML_FALSE)), + bRefNameOK(false) +{ +} + +void XMLSequenceFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + sNumFormat = OUString::fromUtf8(sAttrValue); + break; + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + sNumFormatSync = OUString::fromUtf8(sAttrValue); + break; + case XML_ELEMENT(TEXT, XML_REF_NAME): + sRefName = OUString::fromUtf8(sAttrValue); + bRefNameOK = true; + break; + default: + // delegate to super class (name, formula) + XMLSetVarFieldImportContext::ProcessAttribute(nAttrToken, + sAttrValue); + break; + } // switch +} + +void XMLSequenceFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + // delegate to super class (formula) + XMLSetVarFieldImportContext::PrepareField(xPropertySet); + + // set format + sal_Int16 nNumType = NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, sNumFormat, sNumFormatSync ); + xPropertySet->setPropertyValue(sAPI_number_format, Any(nNumType)); + + // handle reference name + if (bRefNameOK) + { + Any aAny = xPropertySet->getPropertyValue("SequenceValue"); + sal_Int16 nValue = 0; + aAny >>= nValue; + GetImportHelper().InsertSequenceID(sRefName, GetName(), nValue); + } +} + + +// variable set field + + +XMLVariableSetFieldImportContext::XMLVariableSetFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLSetVarFieldImportContext(rImport, rHlp, sAPI_set_expression, + VarTypeSimple, + // formula, value&type, style, + // display none + true, true, + false, false, false, + true, false, + true, true, true, + true) +{ +} + +void XMLVariableSetFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + // set type + Any aAny; + aAny <<= (IsStringValue()? SetVariableType::STRING : SetVariableType::VAR); + xPropertySet->setPropertyValue(sAPI_sub_type, aAny); + + // the remainder is handled by super class + XMLSetVarFieldImportContext::PrepareField(xPropertySet); +} + + +// variable input field + + +XMLVariableInputFieldImportContext::XMLVariableInputFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLSetVarFieldImportContext(rImport, rHlp, sAPI_set_expression, + VarTypeSimple, + // description, display none/formula, + // value&type, style, formula + true, true, + true, true, true, + true, false, + true, true, true, + true) +{ +} + +void XMLVariableInputFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + // set type (input field) + Any aAny; + xPropertySet->setPropertyValue("Input", Any(true)); + + // set type + aAny <<= (IsStringValue()? SetVariableType::STRING : SetVariableType::VAR); + xPropertySet->setPropertyValue(sAPI_sub_type, aAny); + + // the remainder is handled by super class + XMLSetVarFieldImportContext::PrepareField(xPropertySet); +} + + +// user field + + +XMLUserFieldImportContext::XMLUserFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLSetVarFieldImportContext(rImport, rHlp, sAPI_user, + VarTypeUserField, + // display none/formula, style + false, false, + false, false, false, true, + true, + false, true, false, + false) +{ +} + + +// user input field + + +// bug: doesn't work (SO API lacking) +XMLUserFieldInputImportContext::XMLUserFieldInputImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLVarFieldImportContext(rImport, rHlp, "InputUser", + // description, style + false, false, + true, false, false, + false, false, + false /*???*/, true, false, + false) +{ +} + +void XMLUserFieldInputImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + xPropertySet->setPropertyValue(sAPI_content, Any(GetName())); + + // delegate to super class + XMLVarFieldImportContext::PrepareField(xPropertySet); +} + + +// variable get field + + +XMLVariableGetFieldImportContext::XMLVariableGetFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLVarFieldImportContext(rImport, rHlp, sAPI_get_expression, + // style, display formula + false, false, + false, false, false, + false, true, + true, true, false, + true) +{ +} + +void XMLVariableGetFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + // set name + xPropertySet->setPropertyValue(sAPI_content, Any(GetName())); + + // the remainder is handled by super class + XMLVarFieldImportContext::PrepareField(xPropertySet); +} + + +// expression field + + +XMLExpressionFieldImportContext::XMLExpressionFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLVarFieldImportContext(rImport, rHlp, sAPI_get_expression, + // formula, type, style, display formula + true, true, + false, false, false, + false, true, + true, true, false, + true) +{ + bValid = true; // always valid +} + + +void XMLExpressionFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + xPropertySet->setPropertyValue(sAPI_sub_type, Any(sal_Int16(SetVariableType::FORMULA))); + + // delegate to super class + XMLVarFieldImportContext::PrepareField(xPropertySet); +} + + +// text input field + + +XMLTextInputFieldImportContext::XMLTextInputFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLVarFieldImportContext(rImport, rHlp, "Input", + // description + false, false, + true, true, true, + false, false, + false, false, false, + false) +{ + bValid = true; // always valid +} + +void XMLTextInputFieldImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + XMLVarFieldImportContext::PrepareField(xPropertySet); + + xPropertySet->setPropertyValue(sAPI_content, Any(GetContent())); +} + + +// table formula field + + +XMLTableFormulaImportContext::XMLTableFormulaImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "TableFormula"), + aValueHelper(rImport, rHlp, false, true, false, true), + bIsShowFormula(false) +{ +} + +void XMLTableFormulaImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_FORMULA): + aValueHelper.ProcessAttribute( nAttrToken, sAttrValue ); + bValid = true; // we need a formula! + break; + + case XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME): + aValueHelper.ProcessAttribute( nAttrToken, sAttrValue ); + break; + case XML_ELEMENT(TEXT, XML_DISPLAY): + if ( sAttrValue == "formula" ) + bIsShowFormula = true; + break; + default: + // unknown attribute -> ignore + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + break; + } +} + +void XMLTableFormulaImportContext::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + // set format and formula + aValueHelper.PrepareField( xPropertySet ); + + Any aAny; + + // set 'show formula' and presentation + xPropertySet->setPropertyValue( "IsShowFormula", Any(bIsShowFormula) ); + + aAny <<= GetContent(); + xPropertySet->setPropertyValue( "CurrentPresentation", aAny ); +} + + +// variable declarations + +// Should be adapted to XMLVarField-/XMLSetVarFieldImportContext scheme! + + +// declaration container import (<variable/user-field/sequence-decls>) + + +XMLVariableDeclsImportContext::XMLVariableDeclsImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, enum VarType eVarType) : + SvXMLImportContext(rImport), + eVarDeclsContextType(eVarType), + rImportHelper(rHlp) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLVariableDeclsImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( IsTokenInNamespace(nElement, XML_NAMESPACE_TEXT) ) + { + enum XMLTokenEnum eElementName; + switch (eVarDeclsContextType) + { + case VarTypeSequence: + eElementName = XML_SEQUENCE_DECL; + break; + case VarTypeSimple: + eElementName = XML_VARIABLE_DECL; + break; + case VarTypeUserField: + eElementName = XML_USER_FIELD_DECL; + break; + default: + OSL_FAIL("unknown field type!"); + eElementName = XML_SEQUENCE_DECL; + break; + } + + if( nElement == XML_ELEMENT(TEXT, eElementName) ) + { + return new XMLVariableDeclImportContext( + GetImport(), rImportHelper, nElement, xAttrList, + eVarDeclsContextType); + } + } + + // if no context was created, use default context + return nullptr; +} + + +// declaration import (<variable/user-field/sequence-decl> elements) + + +XMLVariableDeclImportContext::XMLVariableDeclImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + sal_Int32 nElement, + const Reference<xml::sax::XFastAttributeList> & xAttrList, + enum VarType eVarType) : + SvXMLImportContext(rImport) +{ + // bug?? which properties for userfield/userfieldmaster + XMLValueImportHelper aValueHelper(rImport, rHlp, true, false, true, false); + sal_Unicode cSeparationChar('.'); + + sal_Int8 nNumLevel(-1); + OUString sName; + + if (nElement != XML_ELEMENT(TEXT, XML_SEQUENCE_DECL) && + nElement != XML_ELEMENT(TEXT, XML_VARIABLE_DECL) && + nElement != XML_ELEMENT(TEXT, XML_USER_FIELD_DECL) ) + return; + + // TODO: check validity (need name!) + + // parse attributes + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_NAME): + sName = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_DISPLAY_OUTLINE_LEVEL): + { + sal_Int32 nLevel; + bool const bRet = ::sax::Converter::convertNumber( + nLevel, aIter.toView(), 0, + GetImport().GetTextImport()->GetChapterNumbering()-> + getCount()); + if (bRet) + { + nNumLevel = static_cast< sal_Int8 >( nLevel-1 ); // API numbers -1..9 + } + break; + } + case XML_ELEMENT(TEXT, XML_SEPARATION_CHARACTER): + cSeparationChar = + static_cast<char>(aIter.toString().toChar()); + break; + + default: + // delegate to value helper + aValueHelper.ProcessAttribute(aIter.getToken(), aIter.toView()); + break; + } + } + + Reference<XPropertySet> xFieldMaster; + if (!FindFieldMaster(xFieldMaster, GetImport(), rHlp, + sName, eVarType)) + return; + + // now we have a field master: process attributes! + Any aAny; + + switch (eVarType) + { + case VarTypeSequence: + xFieldMaster->setPropertyValue("ChapterNumberingLevel", Any(nNumLevel)); + + if (nNumLevel >= 0) + { + OUString sStr(&cSeparationChar, 1); + xFieldMaster->setPropertyValue( + "NumberingSeparator", Any(sStr)); + } + break; + case VarTypeSimple: + { + // set string or non-string SubType (#93192#) + // The SubType was already set in the FindFieldMaster + // method, but it needs to be adjusted if it's a string. + aAny <<= aValueHelper.IsStringValue() + ? SetVariableType::STRING : SetVariableType::VAR; + xFieldMaster->setPropertyValue(sAPI_sub_type, aAny); + } + break; + case VarTypeUserField: + { + bool bTmp = !aValueHelper.IsStringValue(); + xFieldMaster->setPropertyValue("IsExpression", Any(bTmp)); + aValueHelper.PrepareField(xFieldMaster); + break; + } + default: + OSL_FAIL("unknown varfield type"); + } // switch +} + + +bool XMLVariableDeclImportContext::FindFieldMaster( + Reference<XPropertySet> & xMaster, SvXMLImport& rImport, + XMLTextImportHelper& rImportHelper, + const OUString& sVarName, enum VarType eVarType) +{ + static sal_Int32 nCollisionCount = 0; + + // rename field + // currently: no family in use! Use 0. + OUString sName = rImportHelper.GetRenameMap().Get( + sal::static_int_cast< sal_uInt16 >(eVarType), sVarName); + + // get text fields supplier and field masters + Reference<XTextFieldsSupplier> xTextFieldsSupp(rImport.GetModel(), + UNO_QUERY); + Reference<container::XNameAccess> xFieldMasterNameAccess = + xTextFieldsSupp->getTextFieldMasters(); + + OUString sVarServiceName = + OUString::Concat(sAPI_fieldmaster_prefix) + + sAPI_set_expression + + "." + + sName; + + OUString sUserServiceName = + OUString::Concat(sAPI_fieldmaster_prefix) + + sAPI_user + + "." + + sName; + + if (xFieldMasterNameAccess->hasByName(sVarServiceName)) { + // variable field master already in document + + Any aAny = xFieldMasterNameAccess->getByName(sVarServiceName); + aAny >>= xMaster; + + aAny = xMaster->getPropertyValue(sAPI_sub_type); + sal_Int16 nType = 0; + aAny >>= nType; + + enum VarType eFMVarType = + (SetVariableType::SEQUENCE == nType) ? + VarTypeSequence : VarTypeSimple; + + if (eFMVarType != eVarType) + { + ++nCollisionCount; + OUString sNew(sName + "_renamed_" + OUString::number(nCollisionCount)); + + // FIXME! can't find if name is taken already!!!! + + rImportHelper.GetRenameMap().Add( + sal::static_int_cast< sal_uInt16 >(eVarType), sName, sNew); + + // call FindFieldMaster recursively to create new master + return FindFieldMaster(xMaster, rImport, rImportHelper, + sNew, eVarType); + } + } else if (xFieldMasterNameAccess->hasByName(sUserServiceName)) { + // user field: get field master + Any aAny = xFieldMasterNameAccess->getByName(sUserServiceName); + aAny >>= xMaster; + + if (VarTypeUserField != eVarType) { + ++nCollisionCount; + // find new name that is not taken + OUString sNew(sName + "_renamed_" + OUString::number(nCollisionCount)); + + // FIXME! can't find if name is taken already!!!! + + rImportHelper.GetRenameMap().Add( + sal::static_int_cast< sal_uInt16 >(eVarType), sName, sNew); + + // call FindFieldMaster recursively to create new master + return FindFieldMaster(xMaster, rImport, rImportHelper, + sNew, eVarType); + } + } else { + // field name not used: create field master + + // import -> model is MultiServiceFactory -> createInstance + Reference<lang::XMultiServiceFactory> + xFactory(rImport.GetModel(),UNO_QUERY); + if( xFactory.is() ) { + + OUString sService = sAPI_fieldmaster_prefix + + ((eVarType==VarTypeUserField) ? + sAPI_user : sAPI_set_expression); + Reference<XInterface> xIfc = + xFactory->createInstance( sService ); + if (xIfc.is()) { + Reference<XPropertySet> xTmp( xIfc, UNO_QUERY ); + xMaster = xTmp; + + // set name + xMaster->setPropertyValue("Name", Any(sName)); + + if (eVarType != VarTypeUserField) { + // set subtype for setexp field + Any aAny; + aAny <<= ((eVarType == VarTypeSimple) ? + SetVariableType::VAR : + SetVariableType::SEQUENCE); + xMaster->setPropertyValue(sAPI_sub_type, aAny); + } // else : user field: no subtype + + } else { + return false; + } + } else { + return false; + } + } + + DBG_ASSERT(xMaster.is(), "no field master found!?!"); + return true; +} + + +// Database Display field import + + +XMLDatabaseDisplayImportContext::XMLDatabaseDisplayImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLDatabaseFieldImportContext(rImport, rHlp, sAPI_database, false), + aValueHelper(rImport, rHlp, false, true, false, false), + bColumnOK(false), + bDisplay( true ), + bDisplayOK( false ) +{ +} + +void XMLDatabaseDisplayImportContext::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_COLUMN_NAME): + sColumnName = OUString::fromUtf8(sAttrValue); + bColumnOK = true; + break; + case XML_ELEMENT(TEXT, XML_DISPLAY): + { + bool bNone = IsXMLToken( sAttrValue, XML_NONE ); + bool bValue = IsXMLToken( sAttrValue, XML_VALUE ); + bDisplay = bValue; + bDisplayOK = bNone || bValue; + } + break; + case XML_ELEMENT(TEXT, XML_DATABASE_NAME): + case XML_ELEMENT(TEXT, XML_TABLE_NAME): + case XML_ELEMENT(TEXT, XML_TABLE_TYPE): + // handled by super class + XMLDatabaseFieldImportContext::ProcessAttribute(nAttrToken, + sAttrValue); + break; + default: + // remainder handled by value helper + aValueHelper.ProcessAttribute(nAttrToken, sAttrValue); + break; + } + + bValid = m_bTableOK && m_bDatabaseOK && bColumnOK; +} + +void XMLDatabaseDisplayImportContext::endFastElement(sal_Int32 ) +{ + // we have an EndElement of our own, because database fields need + // to be attached to a field master before they can be inserted into + // the document. Database stuff (database, table, column) all goes + // to the field master, value & style go to the field. + + if (bValid) + { + + // so here goes: we start with the master + Reference<XPropertySet> xMaster; + + // create and prepare field master first + if (CreateField(xMaster, + "com.sun.star.text.FieldMaster.Database")) + { + Any aAny; + xMaster->setPropertyValue("DataColumnName", Any(sColumnName)); + + // fieldmaster takes database, table and column name + XMLDatabaseFieldImportContext::PrepareField(xMaster); + + // create field + Reference<XPropertySet> xField; + if (CreateField(xField, + sAPI_database)) + { + // attach field master + Reference<XDependentTextField> xDepField(xField, UNO_QUERY); + if (xDepField.is()) + { + // attach field to field master + xDepField->attachTextFieldMaster(xMaster); + + // attach field to document + Reference<XTextContent> xTextContent(xField, UNO_QUERY); + if (xTextContent.is()) + { + // insert, set field properties and exit! + try + { + GetImportHelper().InsertTextContent(xTextContent); + + // prepare field: format from database? + bool bTmp = !aValueHelper.IsFormatOK(); + xField->setPropertyValue("DataBaseFormat", Any(bTmp)); + + // value, value-type and format done by value helper + aValueHelper.PrepareField(xField); + + // visibility + if( bDisplayOK ) + { + xField->setPropertyValue(sAPI_is_visible, Any(bDisplay)); + } + + // set presentation + aAny <<= GetContent(); + xField->setPropertyValue(sAPI_current_presentation, aAny); + + // success! + return; + } + catch (const lang::IllegalArgumentException&) + { + TOOLS_WARN_EXCEPTION("xmloff.text", "Failed to insert text content"); + } + } + } + } + } + } + + // above: exit on success; so for all error cases we end up here! + // write element content + GetImportHelper().InsertString(GetContent()); +} + + +// value import helper + +namespace { + +enum ValueType +{ + XML_VALUE_TYPE_STRING, + XML_VALUE_TYPE_FLOAT, + XML_VALUE_TYPE_CURRENCY, + XML_VALUE_TYPE_PERCENTAGE, + XML_VALUE_TYPE_DATE, + XML_VALUE_TYPE_TIME, + XML_VALUE_TYPE_BOOLEAN +}; + +} + +SvXMLEnumMapEntry<ValueType> const aValueTypeMap[] = +{ + { XML_FLOAT, XML_VALUE_TYPE_FLOAT }, + { XML_CURRENCY, XML_VALUE_TYPE_CURRENCY }, + { XML_PERCENTAGE, XML_VALUE_TYPE_PERCENTAGE }, + { XML_DATE, XML_VALUE_TYPE_DATE }, + { XML_TIME, XML_VALUE_TYPE_TIME }, + { XML_BOOLEAN, XML_VALUE_TYPE_BOOLEAN }, + { XML_STRING, XML_VALUE_TYPE_STRING }, + { XML_TOKEN_INVALID, ValueType(0) } +}; + +XMLValueImportHelper::XMLValueImportHelper( + SvXMLImport& rImprt, + XMLTextImportHelper& rHlp, + bool bType, bool bStyle, bool bValue, bool bFormula) : + + rImport(rImprt), + rHelper(rHlp), + + fValue(0.0), + nFormatKey(0), + bIsDefaultLanguage(true), + + bStringType(false), + bFormatOK(false), + bStringValueOK(false), + bFormulaOK(false), + + bSetType(bType), + bSetValue(bValue), + bSetStyle(bStyle), + bSetFormula(bFormula) +{ +} + +void XMLValueImportHelper::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_VALUE_TYPE): // #i32362#: src680m48++ saves text:value-type + case XML_ELEMENT(OFFICE, XML_VALUE_TYPE): + { + // convert enum + ValueType eValueType = XML_VALUE_TYPE_STRING; + bool bRet = SvXMLUnitConverter::convertEnum( + eValueType, sAttrValue, aValueTypeMap); + + if (bRet) { + switch (eValueType) + { + case XML_VALUE_TYPE_STRING: + bStringType = true; + break; + case XML_VALUE_TYPE_FLOAT: + case XML_VALUE_TYPE_CURRENCY: + case XML_VALUE_TYPE_PERCENTAGE: + case XML_VALUE_TYPE_DATE: + case XML_VALUE_TYPE_TIME: + case XML_VALUE_TYPE_BOOLEAN: + bStringType = false; + break; + + default: + OSL_FAIL("unknown value type"); + } + } + break; + } + + case XML_ELEMENT(TEXT, XML_VALUE): + case XML_ELEMENT(OFFICE, XML_VALUE): + { + double fTmp; + bool const bRet = ::sax::Converter::convertDouble(fTmp,sAttrValue); + if (bRet) { + fValue = fTmp; + } + break; + } + + case XML_ELEMENT(TEXT, XML_TIME_VALUE): + case XML_ELEMENT(OFFICE, XML_TIME_VALUE): + { + double fTmp; + bool const bRet = + ::sax::Converter::convertDuration(fTmp, sAttrValue); + if (bRet) { + fValue = fTmp; + } + break; + } + + case XML_ELEMENT(TEXT, XML_DATE_VALUE): + case XML_ELEMENT(OFFICE, XML_DATE_VALUE): + { + double fTmp; + bool bRet = rImport.GetMM100UnitConverter(). + convertDateTime(fTmp,sAttrValue); + if (bRet) { + fValue = fTmp; + } + break; + } + + case XML_ELEMENT(OFFICE, XML_BOOLEAN_VALUE): + { + bool bTmp(false); + bool bRet = ::sax::Converter::convertBool(bTmp, sAttrValue); + if (bRet) { + fValue = (bTmp ? 1.0 : 0.0); + } + else + { + double fTmp; + bRet = ::sax::Converter::convertDouble(fTmp, sAttrValue); + if (bRet) { + fValue = fTmp; + } + } + break; + } + + case XML_ELEMENT(TEXT, XML_STRING_VALUE): + case XML_ELEMENT(OFFICE, XML_STRING_VALUE): + sValue = OUString::fromUtf8(sAttrValue); + bStringValueOK = true; + break; + + case XML_ELEMENT(TEXT, XML_FORMULA): + { + OUString sTmp; + sal_uInt16 nPrefix = rImport.GetNamespaceMap(). + GetKeyByAttrValueQName(OUString::fromUtf8(sAttrValue), &sTmp); + if( XML_NAMESPACE_OOOW == nPrefix ) + { + sFormula = sTmp; + bFormulaOK = true; + } + else + sFormula = OUString::fromUtf8(sAttrValue); + } + break; + + case XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME): + { + sal_Int32 nKey = rHelper.GetDataStyleKey( + OUString::fromUtf8(sAttrValue), &bIsDefaultLanguage); + if (-1 != nKey) + { + nFormatKey = nKey; + bFormatOK = true; + } + break; + } + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } // switch +} + +void XMLValueImportHelper::PrepareField( + const Reference<XPropertySet> & xPropertySet) +{ + Any aAny; + + if (bSetType) + { + // ??? how to set type? + } + + if (bSetFormula) + { + aAny <<= !bFormulaOK ? sDefault : sFormula; + xPropertySet->setPropertyValue(sAPI_content, aAny); + } + + // format/style + if (bSetStyle && bFormatOK) + { + xPropertySet->setPropertyValue(sAPI_number_format, Any(nFormatKey)); + + if( xPropertySet->getPropertySetInfo()-> + hasPropertyByName( "IsFixedLanguage" ) ) + { + bool bIsFixedLanguage = ! bIsDefaultLanguage; + xPropertySet->setPropertyValue( "IsFixedLanguage", Any(bIsFixedLanguage) ); + } + } + + // value: string or float + if (bSetValue) + { + if (bStringType) + { + aAny <<= !bStringValueOK ? sDefault : sValue; + xPropertySet->setPropertyValue(sAPI_content, aAny); + } + else + { + xPropertySet->setPropertyValue("Value", Any(fValue)); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/xmlcontentcontrolcontext.cxx b/xmloff/source/text/xmlcontentcontrolcontext.cxx new file mode 100644 index 0000000000..2a7ef5b2ee --- /dev/null +++ b/xmloff/source/text/xmlcontentcontrolcontext.cxx @@ -0,0 +1,369 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "xmlcontentcontrolcontext.hxx" + +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <sax/tools/converter.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/sequence.hxx> + +#include "XMLTextMarkImportContext.hxx" +#include "txtparai.hxx" + +using namespace com::sun::star; +using namespace xmloff::token; + +XMLContentControlContext::XMLContentControlContext(SvXMLImport& rImport, sal_Int32 /*nElement*/, + XMLHints_Impl& rHints, bool& rIgnoreLeadingSpace) + : SvXMLImportContext(rImport) + , m_rHints(rHints) + , m_rIgnoreLeadingSpace(rIgnoreLeadingSpace) + , m_xStart(GetImport().GetTextImport()->GetCursorAsRange()->getStart()) +{ +} + +void XMLContentControlContext::startFastElement( + sal_Int32 /*nElement*/, const uno::Reference<xml::sax::XFastAttributeList>& xAttrList) +{ + for (auto& rIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + bool bTmp = false; + sal_Int32 nTmp = 0; + + switch (rIter.getToken()) + { + case XML_ELEMENT(LO_EXT, XML_SHOWING_PLACE_HOLDER): + { + if (sax::Converter::convertBool(bTmp, rIter.toView())) + { + m_bShowingPlaceHolder = bTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_CHECKBOX): + { + if (sax::Converter::convertBool(bTmp, rIter.toView())) + { + m_bCheckbox = bTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_CHECKED): + { + if (sax::Converter::convertBool(bTmp, rIter.toView())) + { + m_bChecked = bTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_CHECKED_STATE): + { + m_aCheckedState = rIter.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_UNCHECKED_STATE): + { + m_aUncheckedState = rIter.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_PICTURE): + { + if (sax::Converter::convertBool(bTmp, rIter.toView())) + { + m_bPicture = bTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_DATE): + { + if (sax::Converter::convertBool(bTmp, rIter.toView())) + { + m_bDate = bTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_DATE_FORMAT): + { + m_aDateFormat = rIter.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_DATE_RFC_LANGUAGE_TAG): + { + m_aDateLanguage = rIter.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_CURRENT_DATE): + { + m_aCurrentDate = rIter.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_PLAIN_TEXT): + { + if (sax::Converter::convertBool(bTmp, rIter.toView())) + { + m_bPlainText = bTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_COMBOBOX): + { + if (sax::Converter::convertBool(bTmp, rIter.toView())) + { + m_bComboBox = bTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_DROPDOWN): + { + if (sax::Converter::convertBool(bTmp, rIter.toView())) + { + m_bDropDown = bTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_ALIAS): + { + m_aAlias = rIter.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_TAG): + { + m_aTag = rIter.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_ID): + { + if (sax::Converter::convertNumber(nTmp, rIter.toView())) + { + m_nId = nTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_TAB_INDEX): + { + if (sax::Converter::convertNumber(nTmp, rIter.toView())) + { + m_nTabIndex = nTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_LOCK): + { + m_aLock = rIter.toString(); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", rIter); + } + } +} + +void XMLContentControlContext::endFastElement(sal_Int32) +{ + if (!m_xStart.is()) + { + SAL_WARN("xmloff.text", "XMLContentControlContext::endFastElement: no m_xStart"); + return; + } + + uno::Reference<text::XTextRange> xEndRange + = GetImport().GetTextImport()->GetCursorAsRange()->getStart(); + + // Create range for insertion. + uno::Reference<text::XTextCursor> xInsertionCursor + = GetImport().GetTextImport()->GetText()->createTextCursorByRange(xEndRange); + xInsertionCursor->gotoRange(m_xStart, /*bExpand=*/true); + + uno::Reference<text::XTextContent> xContentControl + = XMLTextMarkImportContext::CreateAndInsertMark( + GetImport(), "com.sun.star.text.ContentControl", OUString(), xInsertionCursor); + if (!xContentControl.is()) + { + SAL_WARN("xmloff.text", "cannot insert content control"); + return; + } + + uno::Reference<beans::XPropertySet> xPropertySet(xContentControl, uno::UNO_QUERY); + if (!xPropertySet.is()) + { + return; + } + + if (m_bShowingPlaceHolder) + { + xPropertySet->setPropertyValue("ShowingPlaceHolder", uno::Any(m_bShowingPlaceHolder)); + } + + if (m_bCheckbox) + { + xPropertySet->setPropertyValue("Checkbox", uno::Any(m_bCheckbox)); + } + if (m_bChecked) + { + xPropertySet->setPropertyValue("Checked", uno::Any(m_bChecked)); + } + if (!m_aCheckedState.isEmpty()) + { + xPropertySet->setPropertyValue("CheckedState", uno::Any(m_aCheckedState)); + } + if (!m_aUncheckedState.isEmpty()) + { + xPropertySet->setPropertyValue("UncheckedState", uno::Any(m_aUncheckedState)); + } + if (!m_aListItems.empty()) + { + xPropertySet->setPropertyValue("ListItems", + uno::Any(comphelper::containerToSequence(m_aListItems))); + } + + if (m_bPicture) + { + xPropertySet->setPropertyValue("Picture", uno::Any(m_bPicture)); + } + + if (m_bDate) + { + xPropertySet->setPropertyValue("Date", uno::Any(m_bDate)); + } + if (!m_aDateFormat.isEmpty()) + { + xPropertySet->setPropertyValue("DateFormat", uno::Any(m_aDateFormat)); + } + if (!m_aDateLanguage.isEmpty()) + { + xPropertySet->setPropertyValue("DateLanguage", uno::Any(m_aDateLanguage)); + } + if (!m_aCurrentDate.isEmpty()) + { + xPropertySet->setPropertyValue("CurrentDate", uno::Any(m_aCurrentDate)); + } + + if (m_bPlainText) + { + xPropertySet->setPropertyValue("PlainText", uno::Any(m_bPlainText)); + } + + if (m_bComboBox) + { + xPropertySet->setPropertyValue("ComboBox", uno::Any(m_bComboBox)); + } + + if (m_bDropDown) + { + xPropertySet->setPropertyValue("DropDown", uno::Any(m_bDropDown)); + } + + if (!m_aAlias.isEmpty()) + { + xPropertySet->setPropertyValue("Alias", uno::Any(m_aAlias)); + } + + if (!m_aTag.isEmpty()) + { + xPropertySet->setPropertyValue("Tag", uno::Any(m_aTag)); + } + + if (m_nId) + { + xPropertySet->setPropertyValue("Id", uno::Any(m_nId)); + } + + if (m_nTabIndex) + { + xPropertySet->setPropertyValue("TabIndex", uno::Any(m_nTabIndex)); + } + + if (!m_aLock.isEmpty()) + { + xPropertySet->setPropertyValue("Lock", uno::Any(m_aLock)); + } +} + +css::uno::Reference<css::xml::sax::XFastContextHandler> +XMLContentControlContext::createFastChildContext( + sal_Int32 nElement, const uno::Reference<xml::sax::XFastAttributeList>& xAttrList) +{ + switch (nElement) + { + case XML_ELEMENT(LO_EXT, XML_LIST_ITEM): + return new XMLListItemContext(GetImport(), *this); + break; + default: + break; + } + + return XMLImpSpanContext_Impl::CreateSpanContext(GetImport(), nElement, xAttrList, m_rHints, + m_rIgnoreLeadingSpace); +} + +void XMLContentControlContext::characters(const OUString& rChars) +{ + GetImport().GetTextImport()->InsertString(rChars, m_rIgnoreLeadingSpace); +} + +void XMLContentControlContext::AppendListItem(const css::beans::PropertyValues& rListItem) +{ + m_aListItems.push_back(rListItem); +} + +XMLListItemContext::XMLListItemContext(SvXMLImport& rImport, + XMLContentControlContext& rContentControl) + : SvXMLImportContext(rImport) + , m_rContentControl(rContentControl) +{ +} + +void XMLListItemContext::startFastElement( + sal_Int32 /*nElement*/, const uno::Reference<xml::sax::XFastAttributeList>& xAttrList) +{ + OUString aDisplayText; + OUString aValue; + + for (auto& rIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch (rIter.getToken()) + { + case XML_ELEMENT(LO_EXT, XML_DISPLAY_TEXT): + { + aDisplayText = rIter.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_VALUE): + { + aValue = rIter.toString(); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", rIter); + } + } + + uno::Sequence<beans::PropertyValue> aListItem = { + comphelper::makePropertyValue("DisplayText", uno::Any(aDisplayText)), + comphelper::makePropertyValue("Value", uno::Any(aValue)), + }; + m_rContentControl.AppendListItem(aListItem); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/xmlcontentcontrolcontext.hxx b/xmloff/source/text/xmlcontentcontrolcontext.hxx new file mode 100644 index 0000000000..13c1e50f23 --- /dev/null +++ b/xmloff/source/text/xmlcontentcontrolcontext.hxx @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include <xmloff/xmlictxt.hxx> + +#include <vector> + +#include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/beans/PropertyValues.hpp> + +class XMLHints_Impl; + +/// Imports <loext:content-control>. +class XMLContentControlContext : public SvXMLImportContext +{ + XMLHints_Impl& m_rHints; + + bool& m_rIgnoreLeadingSpace; + + css::uno::Reference<css::text::XTextRange> m_xStart; + + bool m_bShowingPlaceHolder = false; + + bool m_bCheckbox = false; + bool m_bChecked = false; + OUString m_aCheckedState; + OUString m_aUncheckedState; + std::vector<css::beans::PropertyValues> m_aListItems; + bool m_bPicture = false; + bool m_bDate = false; + OUString m_aDateFormat; + OUString m_aDateLanguage; + OUString m_aCurrentDate; + bool m_bPlainText = false; + bool m_bComboBox = false; + bool m_bDropDown = false; + OUString m_aAlias; + OUString m_aTag; + sal_Int32 m_nId = 0; + sal_uInt32 m_nTabIndex = 0; + OUString m_aLock; + +public: + XMLContentControlContext(SvXMLImport& rImport, sal_Int32 nElement, XMLHints_Impl& rHints, + bool& rIgnoreLeadingSpace); + + void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) override; + + void SAL_CALL endFastElement(sal_Int32 nElement) override; + + css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& rAttrList) override; + + void SAL_CALL characters(const OUString& rChars) override; + + void AppendListItem(const css::beans::PropertyValues& rListItem); +}; + +/// Imports <loext:list-item> inside <loext:content-control>. +class XMLListItemContext : public SvXMLImportContext +{ + XMLContentControlContext& m_rContentControl; + +public: + XMLListItemContext(SvXMLImport& rImport, XMLContentControlContext& rContentControl); + + void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/xmllinebreakcontext.cxx b/xmloff/source/text/xmllinebreakcontext.cxx new file mode 100644 index 0000000000..67b56c2d32 --- /dev/null +++ b/xmloff/source/text/xmllinebreakcontext.cxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "xmllinebreakcontext.hxx" + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/text/XTextContent.hpp> + +#include <xmloff/xmlement.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmluconv.hxx> + +using namespace com::sun::star; +using namespace xmloff::token; + +namespace +{ +const SvXMLEnumMapEntry<sal_Int16> pXML_LineBreakClear_Enum[] = { + { XML_NONE, 0 }, { XML_LEFT, 1 }, { XML_RIGHT, 2 }, { XML_ALL, 3 }, { XML_TOKEN_INVALID, 0 } +}; +} + +SvXMLLineBreakContext::SvXMLLineBreakContext(SvXMLImport& rImport, XMLTextImportHelper& rHelper) + : SvXMLImportContext(rImport) + , m_rHelper(rHelper) +{ +} + +void SvXMLLineBreakContext::startFastElement( + sal_Int32 /*nElement*/, const uno::Reference<xml::sax::XFastAttributeList>& xAttrList) +{ + const uno::Reference<frame::XModel>& xModel = GetImport().GetModel(); + uno::Reference<lang::XMultiServiceFactory> xFactory(xModel, uno::UNO_QUERY); + if (!xFactory.is()) + return; + + uno::Reference<text::XTextContent> xLineBreak( + xFactory->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY); + + sal_Int16 eClear = 0; + OUString aClear = xAttrList->getValue(XML_ELEMENT(LO_EXT, XML_CLEAR)); + if (SvXMLUnitConverter::convertEnum(eClear, aClear, pXML_LineBreakClear_Enum)) + { + uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY); + xLineBreakProps->setPropertyValue("Clear", uno::Any(eClear)); + } + + m_rHelper.InsertTextContent(xLineBreak); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/xmllinebreakcontext.hxx b/xmloff/source/text/xmllinebreakcontext.hxx new file mode 100644 index 0000000000..ef1f744bb4 --- /dev/null +++ b/xmloff/source/text/xmllinebreakcontext.hxx @@ -0,0 +1,31 @@ +/* -*- 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/. + */ + +#pragma once + +#include <xmloff/dllapi.h> +#include <xmloff/xmlictxt.hxx> + +class XMLTextImportHelper; + +/// Handles <text:line-break loext:clear="..."> when the attribute is present. +class XMLOFF_DLLPUBLIC SvXMLLineBreakContext : public SvXMLImportContext +{ + XMLTextImportHelper& m_rHelper; + +public: + SvXMLLineBreakContext(SvXMLImport& rImport, XMLTextImportHelper& rHelper); + +protected: + void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |