/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this 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 <sal/config.h>

#include <cassert>

#include <txtfld.hxx>
#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/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 <com/sun/star/container/XUniqueIDAccess.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() )
        {
            xField.set(xIfc, UNO_QUERY);
        } 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):
        case XML_ELEMENT(LO_EXT, XML_PAGE_COUNT_RANGE):
            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, u"ExtendedUser"_ustr)
    , 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, u"JumpEdit"_ustr)
,   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, u"DatabaseName"_ustr, 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, u"DatabaseNextSet"_ustr, 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, u"DatabaseNumberOfSet"_ustr),
        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, u"DatabaseSetNumber"_ustr, true),
        sPropertyNumberingType(
            sAPI_numbering_type),
        sPropertySetNumber(sAPI_set_number),
        sNumberFormat(u"1"_ustr),
        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, u"HiddenParagraph"_ustr),
        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, u"ConditionalText"_ustr),
        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, u"HiddenText"_ustr),
        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, u"FileName"_ustr),
        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, u"TemplateName"_ustr),
        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, u"Chapter"_ustr),
        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;
        case XML_ELEMENT(LO_EXT, XML_PAGE_COUNT_RANGE):
            pServiceName = "PageCountRange";
            break;
        default:
            XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
            assert(false);
    }

    return pServiceName;
}


// page variable import


XMLPageVarGetFieldImportContext::XMLPageVarGetFieldImportContext(
    SvXMLImport& rImport, XMLTextImportHelper& rHlp) :
        XMLTextFieldImportContext(rImport, rHlp, u"ReferencePageGet"_ustr),
        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, u"ReferencePageSet"_ustr),
        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(u"On"_ustr, Any(bActive));
    xPropertySet->setPropertyValue(sAPI_offset, Any(nAdjust));
}


// macro fields


XMLMacroFieldImportContext::XMLMacroFieldImportContext(
    SvXMLImport& rImport, XMLTextImportHelper& rHlp) :
        XMLTextFieldImportContext(rImport, rHlp, u"Macro"_ustr),
        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( u"OnClick"_ustr, aValues );

        for (const auto& rValue : 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(u"ScriptURL"_ustr, Any(sScriptURL));
    xPropertySet->setPropertyValue(u"MacroName"_ustr, Any(sMacroName));
    xPropertySet->setPropertyValue(u"MacroLibrary"_ustr, Any(sLibraryName));
}


// reference field import


XMLReferenceFieldImportContext::XMLReferenceFieldImportContext(
    SvXMLImport& rImport, XMLTextImportHelper& rHlp,
    sal_Int32 nToken)
:   XMLTextFieldImportContext(rImport, rHlp, u"GetReference"_ustr)
,   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(u"ReferenceFieldPart"_ustr, Any(nType));

    xPropertySet->setPropertyValue(u"ReferenceFieldSource"_ustr, Any(nSource));

    xPropertySet->setPropertyValue(u"ReferenceFieldLanguage"_ustr, 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(u"SourceName"_ustr, Any(sName));
            xPropertySet->setPropertyValue(u"ReferenceFieldFlags"_ustr, 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(
                                                                  u"DDECommandType"_ustr))
            {
                xPropSet->setPropertyValue(sAPI_name, Any(sName));

                xPropSet->setPropertyValue(u"DDECommandType"_ustr, Any(sCommandApplication));

                xPropSet->setPropertyValue(u"DDECommandFile"_ustr, Any(sCommandTopic));

                xPropSet->setPropertyValue(u"DDECommandElement"_ustr,
                                           Any(sCommandItem));

                xPropSet->setPropertyValue(u"IsAutomaticUpdate"_ustr,
                                           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, u"SheetName"_ustr)
{
    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, u"PageName"_ustr )
{
    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(u"TargetFrame"_ustr, Any(sFrame));
    }

    xPropertySet->setPropertyValue(u"Representation"_ustr, Any(GetContent()));
}


XMLBibliographyFieldImportContext::XMLBibliographyFieldImportContext(
    SvXMLImport& rImport,
    XMLTextImportHelper& rHlp) :
        XMLTextFieldImportContext(rImport, rHlp, u"Bibliography"_ustr)
{
    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 = MapBibliographyFieldName(nToken);

            // 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))
                {
                    aValue.Value <<= static_cast<sal_Int16>(nTmp);

                    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);
                }
                aValue.Value <<= aStringValue;

                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(u"Fields"_ustr, Any(aValueSequence));
}

OUString XMLBibliographyFieldImportContext::MapBibliographyFieldName(
    sal_Int32 nElement)
{
    OUString pName;

    switch (nElement & TOKEN_MASK)
    {
        case XML_IDENTIFIER:
            pName = u"Identifier"_ustr;
            break;
        case XML_BIBILIOGRAPHIC_TYPE:
        case XML_BIBLIOGRAPHY_TYPE:
            // biblio... vs bibilio...: #96658#: also read old documents
            pName = u"BibiliographicType"_ustr;
            break;
        case XML_ADDRESS:
            pName = u"Address"_ustr;
            break;
        case XML_ANNOTE:
            pName = u"Annote"_ustr;
            break;
        case XML_AUTHOR:
            pName = u"Author"_ustr;
            break;
        case XML_BOOKTITLE:
            pName = u"Booktitle"_ustr;
            break;
        case XML_CHAPTER:
            pName = u"Chapter"_ustr;
            break;
        case XML_EDITION:
            pName = u"Edition"_ustr;
            break;
        case XML_EDITOR:
            pName = u"Editor"_ustr;
            break;
        case XML_HOWPUBLISHED:
            pName = u"Howpublished"_ustr;
            break;
        case XML_INSTITUTION:
            pName = u"Institution"_ustr;
            break;
        case XML_JOURNAL:
            pName = u"Journal"_ustr;
            break;
        case XML_MONTH:
            pName = u"Month"_ustr;
            break;
        case XML_NOTE:
            pName = u"Note"_ustr;
            break;
        case XML_NUMBER:
            pName = u"Number"_ustr;
            break;
        case XML_ORGANIZATIONS:
            pName = u"Organizations"_ustr;
            break;
        case XML_PAGES:
            pName = u"Pages"_ustr;
            break;
        case XML_PUBLISHER:
            pName = u"Publisher"_ustr;
            break;
        case XML_SCHOOL:
            pName = u"School"_ustr;
            break;
        case XML_SERIES:
            pName = u"Series"_ustr;
            break;
        case XML_TITLE:
            pName = u"Title"_ustr;
            break;
        case XML_REPORT_TYPE:
            pName = u"Report_Type"_ustr;
            break;
        case XML_VOLUME:
            pName = u"Volume"_ustr;
            break;
        case XML_YEAR:
            pName = u"Year"_ustr;
            break;
        case XML_URL:
            pName = u"URL"_ustr;
            break;
        case XML_CUSTOM1:
            pName = u"Custom1"_ustr;
            break;
        case XML_CUSTOM2:
            pName = u"Custom2"_ustr;
            break;
        case XML_CUSTOM3:
            pName = u"Custom3"_ustr;
            break;
        case XML_CUSTOM4:
            pName = u"Custom4"_ustr;
            break;
        case XML_CUSTOM5:
            pName = u"Custom5"_ustr;
            break;
        case XML_ISBN:
            pName = u"ISBN"_ustr;
            break;
        case XML_LOCAL_URL:
            pName = u"LocalURL"_ustr;
            break;
        case XML_TARGET_TYPE:
            pName = u"TargetType"_ustr;
            break;
        case XML_TARGET_URL:
            pName = u"TargetURL"_ustr;
            break;
        default:
            assert(false && "Unknown bibliography info data");
    }
    return pName;
}

// Annotation Field


XMLAnnotationImportContext::XMLAnnotationImportContext(
    SvXMLImport& rImport,
    XMLTextImportHelper& rHlp,
    sal_Int32 nElement) :
        XMLTextFieldImportContext(rImport, rHlp, u"Annotation"_ustr),
        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( u"TextRange"_ustr );
            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( u""_ustr );

        // reset cursor
        GetImport().GetTextImport()->ResetCursor();
    }

    if( mxOldCursor.is() )
        GetImport().GetTextImport()->SetCursor( mxOldCursor );

    // reinstall old list item #91964#
    GetImport().GetTextImport()->PopListContext();

    if (!bValid)
    {
        GetImportHelper().InsertString(GetContent());
        return;
    }

    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);
            if (!xTextFieldsSupplier)
                return;
            uno::Reference<container::XUniqueIDAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields(), UNO_QUERY_THROW);
            uno::Any aAny = xFieldsAccess->getByUniqueID(aName);
            aAny >>= xPrevField;
        }
        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());
        }
        return;
    }

    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
        }
    }
}

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(u"Initials"_ustr, Any(sInitials));

    //import resolved flag
    bool bTmp(false);
    (void)::sax::Converter::convertBool(bTmp, aResolved);
    xPropertySet->setPropertyValue(u"Resolved"_ustr, 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, u"Script"_ustr)
,   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(u"URLContent"_ustr, Any(bContentOK));

    xPropertySet->setPropertyValue(u"ScriptType"_ustr, Any(sScriptType));
}


// measure field


XMLMeasureFieldImportContext::XMLMeasureFieldImportContext(
    SvXMLImport& rImport,
    XMLTextImportHelper& rHlp) :
        XMLTextFieldImportContext(rImport, rHlp, u"Measure"_ustr),
        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(u"Kind"_ustr, Any(mnKind));
}


// dropdown field


XMLDropDownFieldImportContext::XMLDropDownFieldImportContext(
        SvXMLImport& rImport,
        XMLTextImportHelper& rHlp) :
    XMLTextFieldImportContext( rImport, rHlp, u"DropDown"_ustr ),
    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( u"Items"_ustr, Any(aSequence) );

    if( nSelected >= 0  &&  nSelected < nLength )
    {
        xPropertySet->setPropertyValue( u"SelectedItem"_ustr, Any(pSequence[nSelected]) );
    }

    // set name
    if( bNameOK )
    {
        xPropertySet->setPropertyValue( u"Name"_ustr, Any(sName) );
    }
    // set help
    if( bHelpOK )
    {
        xPropertySet->setPropertyValue( u"Help"_ustr, Any(sHelp) );
    }
    // set hint
    if( bHintOK )
    {
        xPropertySet->setPropertyValue( u"Tooltip"_ustr, Any(sHint) );
    }

}

/** import header fields (<draw:header>) */

XMLHeaderFieldImportContext::XMLHeaderFieldImportContext(
        SvXMLImport& rImport,                   /// XML Import
        XMLTextImportHelper& rHlp)              /// Text import helper
: XMLTextFieldImportContext(rImport, rHlp, u"Header"_ustr )
{
    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, u"Footer"_ustr )
{
    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, u"DateTime"_ustr )
{
    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: */
