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

    /** @#file
     *
     *  export of all variable related text fields (and database display field)
     */
    #include <txtvfldi.hxx>
    #include <xmloff/xmltoken.hxx>
    #include <xmloff/txtimp.hxx>
    #include <xmloff/xmlnumi.hxx>
    #include <xmloff/xmlnmspe.hxx>
    #include <xmloff/nmspmap.hxx>
    #include <xmloff/i18nmap.hxx>
    #include <xmloff/xmlimp.hxx>
    #include <xmloff/xmluconv.hxx>
    #include <xmloff/xmlement.hxx>
    #include <com/sun/star/text/SetVariableType.hpp>
    #include <com/sun/star/text/XTextField.hpp>
    #include <com/sun/star/text/XDependentTextField.hpp>
    #include <com/sun/star/text/XTextFieldsSupplier.hpp>
    #include <com/sun/star/beans/XPropertySet.hpp>
    #include <com/sun/star/beans/XPropertySetInfo.hpp>
    #include <com/sun/star/lang/XMultiServiceFactory.hpp>
    #include <com/sun/star/xml/sax/XAttributeList.hpp>

    #include <sax/tools/converter.hxx>

    #include <rtl/ustring.hxx>
    #include <osl/diagnose.h>

    #include <tools/debug.hxx>

    // service names
    static const sal_Char sAPI_fieldmaster_prefix[] = "com.sun.star.text.FieldMaster.";
    static const sal_Char sAPI_get_expression[]     = "GetExpression";
    static const sal_Char sAPI_set_expression[]     = "SetExpression";
    static const sal_Char sAPI_user[]               = "User";
    static const sal_Char sAPI_database[]           = "com.sun.star.text.TextField.Database";

    // property names
    static const sal_Char sAPI_content[]            = "Content";
    static const sal_Char sAPI_sub_type[]           = "SubType";
    static const sal_Char sAPI_number_format[]      = "NumberFormat";
    static const sal_Char sAPI_is_visible[]         = "IsVisible";
    static const sal_Char sAPI_current_presentation[]   = "CurrentPresentation";

    using namespace ::com::sun::star;
    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::beans;
    using namespace ::com::sun::star::text;
    using namespace ::com::sun::star::style;
    using namespace ::xmloff::token;

    // XMLVarFieldImportContext: superclass for all variable related fields

    XMLVarFieldImportContext::XMLVarFieldImportContext(
        SvXMLImport& rImport, XMLTextImportHelper& rHlp,
        const sal_Char* pServiceName, sal_uInt16 nPrfx,
        const OUString& rLocalName,
        bool bFormula, bool bFormulaDefault,
        bool bDescription, bool bHelp, bool bHint, bool bVisible,
        bool bIsDisplayFormula,
        bool bType, bool bStyle, bool bValue,
        bool bPresentation) :
            XMLTextFieldImportContext(rImport, rHlp, pServiceName, nPrfx, rLocalName),
            aValueHelper(rImport, rHlp, bType, bStyle, bValue, false),
            bDisplayFormula(false),
            bDisplayNone(false),
            bFormulaOK(false),
            bDescriptionOK(false),
            bHelpOK(false),
            bHintOK(false),
            bDisplayOK(false),
            bSetFormula(bFormula),
            bSetFormulaDefault(bFormulaDefault),
            bSetDescription(bDescription),
            bSetHelp(bHelp),
            bSetHint(bHint),
            bSetVisible(bVisible),
            bSetDisplayFormula(bIsDisplayFormula),
            bSetPresentation(bPresentation)
    {
    }

    void XMLVarFieldImportContext::ProcessAttribute(
        sal_uInt16 nAttrToken,
        const OUString& sAttrValue )
    {
        switch (nAttrToken)
            {
            case XML_TOK_TEXTFIELD_NAME:
                sName = sAttrValue;
                bValid = true;      // we assume: field with name is valid!
                break;
            case XML_TOK_TEXTFIELD_DESCRIPTION:
                sDescription = sAttrValue;
                bDescriptionOK = true;
                break;
            case XML_TOK_TEXTFIELD_HELP:
                sHelp = sAttrValue;
                bHelpOK = true;
                break;
            case XML_TOK_TEXTFIELD_HINT:
                sHint = sAttrValue;
                bHintOK = true;
                break;
            case XML_TOK_TEXTFIELD_FORMULA:
                {
                    OUString sTmp;
                    sal_uInt16 nPrefix = GetImport().GetNamespaceMap().
                            GetKeyByAttrName_( sAttrValue, &sTmp );
                    if( XML_NAMESPACE_OOOW == nPrefix )
                    {
                        sFormula = sTmp;
                        bFormulaOK = true;
                    }
                    else
                        sFormula = sAttrValue;
                }
                break;
            case XML_TOK_TEXTFIELD_DISPLAY:
                if (IsXMLToken(sAttrValue, XML_FORMULA))
                {
                    bDisplayFormula = true;
                    bDisplayNone = false;
                    bDisplayOK = true;
                }
                else if (IsXMLToken(sAttrValue, XML_VALUE))
                {
                    bDisplayFormula = false;
                    bDisplayNone = false;
                    bDisplayOK = true;
                }
                else if (IsXMLToken(sAttrValue, XML_NONE))
                {
                    bDisplayFormula = false;
                    bDisplayNone = true;
                    bDisplayOK = true;
                } // else: no change
                DBG_ASSERT(!(bDisplayFormula && bDisplayNone),
                           "illegal display values");
                break;
            default:
                // delegate all others to value helper
                aValueHelper.ProcessAttribute(nAttrToken, sAttrValue);
                break;
            }
    }

    void XMLVarFieldImportContext::PrepareField(
        const Reference<XPropertySet> & xPropertySet)
    {
        // bSetName: not implemented

        if (bSetFormula)
        {
            if (!bFormulaOK && bSetFormulaDefault)
            {
                sFormula = GetContent();
                bFormulaOK = true;
            }

            if (bFormulaOK)
            {
                xPropertySet->setPropertyValue(sAPI_content, Any(sFormula));
            }
        }

        if (bSetDescription && bDescriptionOK)
        {
            xPropertySet->setPropertyValue("Hint", Any(sDescription));
        }

        if (bSetHelp && bHelpOK)
        {
            xPropertySet->setPropertyValue("Help", Any(sHelp));
        }

        if (bSetHint && bHintOK)
        {
            xPropertySet->setPropertyValue("Tooltip", Any(sHint));
        }

        if (bSetVisible && bDisplayOK)
        {
            bool bTmp = ! (bDisplayNone && bDisplayOK);
            xPropertySet->setPropertyValue(sAPI_is_visible, Any(bTmp));
        }

        // workaround for #no-bug#: display formula by default
        if (xPropertySet->getPropertySetInfo()->
                    hasPropertyByName("IsShowFormula") &&
            !bSetDisplayFormula)
        {
            bDisplayFormula = false;
            bSetDisplayFormula = true;
        }

        if (bSetDisplayFormula)
        {
            bool bTmp = bDisplayFormula && bDisplayOK;
            xPropertySet->setPropertyValue("IsShowFormula", Any(bTmp));
        }

        // delegate to value helper
        aValueHelper.SetDefault(GetContent());
        aValueHelper.PrepareField(xPropertySet);

        // finally, set the curren presentation
        if (bSetPresentation)
        {
            Any aAny;
            aAny <<= GetContent();
            xPropertySet->setPropertyValue(sAPI_current_presentation, aAny);
        }
    }

    // variable set fields

    XMLSetVarFieldImportContext::XMLSetVarFieldImportContext(
        SvXMLImport& rImport, XMLTextImportHelper& rHlp,
        const sal_Char* pServiceName, sal_uInt16 nPrfx,
        const OUString& rLocalName, VarType eVarType,
        bool bFormula, bool bFormulaDefault,
        bool bDescription, bool bHelp, bool bHint, bool bVisible, bool bIsDisplayFormula,
        bool bType, bool bStyle, bool bValue, bool bPresentation) :
            XMLVarFieldImportContext(rImport, rHlp, pServiceName,
                                     nPrfx, rLocalName,
                                     bFormula, bFormulaDefault,
                                     bDescription, bHelp, bHint, bVisible, bIsDisplayFormula,
                                     bType, bStyle, bValue, bPresentation),
            eFieldType(eVarType)
    {
    }

    void XMLSetVarFieldImportContext::EndElement()
    {
        // should we call PrepareField on the field, or rather on it's master?
        // currently: call on field (just like superclass)
        // possible alternatives: call on master
        //                        call field or master depending on variable
        //                        PrepareMaster() in addition to PrepareField()

        DBG_ASSERT(!GetServiceName().isEmpty(), "no service name for element!");

        if (bValid)
        {
            DBG_ASSERT(!GetName().isEmpty(), "variable name needed!");

            // find field master
            Reference<XPropertySet> xMaster;
            if (FindFieldMaster(xMaster))
            {
                // create field/Service
                Reference<XPropertySet> xPropSet;
                if (CreateField(xPropSet, "com.sun.star.text.TextField." + GetServiceName()))
                {
                    Reference<XDependentTextField> xDepTextField(xPropSet, UNO_QUERY);
                    if (xDepTextField.is())
                    {
                        // attach field to field master
                        xDepTextField->attachTextFieldMaster(xMaster);

                        // attach field to document
                        Reference<XTextContent> xTextContent(xPropSet, UNO_QUERY);
                        if (xTextContent.is())
                        {
                            try {
                            // insert, set field properties and exit!
                            GetImportHelper().InsertTextContent(xTextContent);
                            PrepareField(xPropSet);
                            } catch (lang::IllegalArgumentException & /*e*/)
                            {
                                // ignore e: #i54023#
                            };
                            return;
                        }
                    }
                }
            }
        }

        // above: exit on success; so for all error cases we end up here!
        // write element content
        GetImportHelper().InsertString(GetContent());
    }

    bool XMLSetVarFieldImportContext::FindFieldMaster(
        Reference<XPropertySet> & xMaster)
    {
        // currently: delegate to XMLVariableDeclImportContext;
        // should eventually go here
        return XMLVariableDeclImportContext::FindFieldMaster(xMaster,
                                                             GetImport(),
                                                             GetImportHelper(),
                                                             GetName(),
                                                             eFieldType);
    }

    // sequence field

    XMLSequenceFieldImportContext::XMLSequenceFieldImportContext(
        SvXMLImport& rImport, XMLTextImportHelper& rHlp,
        sal_uInt16 nPrfx, const OUString& rLocalName) :
            XMLSetVarFieldImportContext(rImport, rHlp, sAPI_set_expression,
                                        nPrfx, rLocalName, VarTypeSequence,
                                        // formula
                                        true, true,
                                        false, false, false, false,
                                        false,
                                        false, false, false, true),

            sNumFormat(OUString('1')),
            sNumFormatSync(GetXMLToken(XML_FALSE)),
            bRefNameOK(false)
    {
    }

    void XMLSequenceFieldImportContext::ProcessAttribute(
        sal_uInt16 nAttrToken, const OUString& sAttrValue )
    {
        switch (nAttrToken)
        {
            case XML_TOK_TEXTFIELD_NUM_FORMAT:
                sNumFormat = sAttrValue;
                break;
            case XML_TOK_TEXTFIELD_NUM_LETTER_SYNC:
                sNumFormatSync = sAttrValue;
                break;
            case XML_TOK_TEXTFIELD_REF_NAME:
                sRefName = sAttrValue;
                bRefNameOK = true;
                break;
            default:
                // delegate to super class (name, formula)
                XMLSetVarFieldImportContext::ProcessAttribute(nAttrToken,
                                                              sAttrValue);
                break;
        } // switch
    }

    void XMLSequenceFieldImportContext::PrepareField(
        const Reference<XPropertySet> & xPropertySet)
    {
        // delegate to super class (formula)
        XMLSetVarFieldImportContext::PrepareField(xPropertySet);

        // set format
        sal_Int16 nNumType = NumberingType::ARABIC;
        GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, sNumFormat, sNumFormatSync );
        xPropertySet->setPropertyValue(sAPI_number_format, Any(nNumType));

        // handle reference name
        if (bRefNameOK)
        {
            Any aAny;
            aAny = xPropertySet->getPropertyValue("SequenceValue");
            sal_Int16 nValue = 0;
            aAny >>= nValue;
            GetImportHelper().InsertSequenceID(sRefName, GetName(), nValue);
        }
    }

    // variable set field

    XMLVariableSetFieldImportContext::XMLVariableSetFieldImportContext(
        SvXMLImport& rImport, XMLTextImportHelper& rHlp,
        sal_uInt16 nPrfx, const OUString& rLocalName) :
            XMLSetVarFieldImportContext(rImport, rHlp, sAPI_set_expression,
                                        nPrfx, rLocalName, VarTypeSimple,
                                        // formula, value&type, style,
                                        // display none
                                        true, true,
                                        false, false, false,
                                        true, false,
                                        true, true, true,
                                        true)
    {
    }

    void XMLVariableSetFieldImportContext::PrepareField(
            const Reference<XPropertySet> & xPropertySet)
    {
        // set type
        Any aAny;
        aAny <<= (IsStringValue()? SetVariableType::STRING : SetVariableType::VAR);
        xPropertySet->setPropertyValue(sAPI_sub_type, aAny);

        // the remainder is handled by super class
        XMLSetVarFieldImportContext::PrepareField(xPropertySet);
    }

    // variable input field

    XMLVariableInputFieldImportContext::XMLVariableInputFieldImportContext(
        SvXMLImport& rImport, XMLTextImportHelper& rHlp, sal_uInt16 nPrfx,
        const OUString& rLocalName) :
            XMLSetVarFieldImportContext(rImport, rHlp, sAPI_set_expression,
                                        nPrfx, rLocalName, VarTypeSimple,
                                        // description, display none/formula,
                                        // value&type, style, formula
                                        true, true,
                                        true, true, true,
                                        true, false,
                                        true, true, true,
                                        true)
    {
    }

    void XMLVariableInputFieldImportContext::PrepareField(
            const Reference<XPropertySet> & xPropertySet)
    {
        // set type (input field)
        Any aAny;
        xPropertySet->setPropertyValue("Input", Any(true));

        // set type
        aAny <<= (IsStringValue()? SetVariableType::STRING : SetVariableType::VAR);
        xPropertySet->setPropertyValue(sAPI_sub_type, aAny);

        // the remainder is handled by super class
        XMLSetVarFieldImportContext::PrepareField(xPropertySet);
    }

    // user field

    XMLUserFieldImportContext::XMLUserFieldImportContext(
        SvXMLImport& rImport, XMLTextImportHelper& rHlp,
        sal_uInt16 nPrfx, const OUString& rLocalName) :
            XMLSetVarFieldImportContext(rImport, rHlp, sAPI_user, nPrfx,
                                        rLocalName, VarTypeUserField,
                                        // display none/formula, style
                                        false, false,
                                        false, false, false, true,
                                        true,
                                        false, true, false,
                                        false)
    {
    }

    // user input field

    // bug: doesn't work (SO API lacking)
    XMLUserFieldInputImportContext::XMLUserFieldInputImportContext(
        SvXMLImport& rImport, XMLTextImportHelper& rHlp, sal_uInt16 nPrfx,
        const OUString& rLocalName) :
            XMLVarFieldImportContext(rImport, rHlp, "InputUser",
                                     nPrfx, rLocalName,
                                     // description, style
                                     false, false,
                                     true, false, false,
                                     false, false,
                                     false /*???*/, true, false,
                                     false)
    {
    }

    void XMLUserFieldInputImportContext::PrepareField(
        const Reference<XPropertySet> & xPropertySet)
    {
        xPropertySet->setPropertyValue(sAPI_content, Any(GetName()));

        // delegate to super class
        XMLVarFieldImportContext::PrepareField(xPropertySet);
    }

    // variable get field

    XMLVariableGetFieldImportContext::XMLVariableGetFieldImportContext(
        SvXMLImport& rImport, XMLTextImportHelper& rHlp,
        sal_uInt16 nPrfx, const OUString& rLocalName) :
            XMLVarFieldImportContext(rImport, rHlp, sAPI_get_expression,
                                     nPrfx, rLocalName,
                                     // style, display formula
                                     false, false,
                                     false, false, false,
                                     false, true,
                                     true, true, false,
                                     true)
    {
    }

    void XMLVariableGetFieldImportContext::PrepareField(
            const Reference<XPropertySet> & xPropertySet)
    {
        // set name
        xPropertySet->setPropertyValue(sAPI_content, Any(GetName()));

        // the remainder is handled by super class
        XMLVarFieldImportContext::PrepareField(xPropertySet);
    }

    // expression field

    XMLExpressionFieldImportContext::XMLExpressionFieldImportContext(
        SvXMLImport& rImport, XMLTextImportHelper& rHlp,
        sal_uInt16 nPrfx, const OUString& rLocalName) :
            XMLVarFieldImportContext(rImport, rHlp, sAPI_get_expression,
                                     nPrfx, rLocalName,
                                     // formula, type, style, display formula
                                     true, true,
                                     false, false, false,
                                     false, true,
                                     true, true, false,
                                     true)
    {
        bValid = true;  // always valid
    }

    void XMLExpressionFieldImportContext::PrepareField(
        const Reference<XPropertySet> & xPropertySet)
    {
        xPropertySet->setPropertyValue(sAPI_sub_type, Any(sal_Int16(SetVariableType::FORMULA)));

        // delegate to super class
        XMLVarFieldImportContext::PrepareField(xPropertySet);
    }

    // text input field

    XMLTextInputFieldImportContext::XMLTextInputFieldImportContext(
        SvXMLImport& rImport, XMLTextImportHelper& rHlp,
        sal_uInt16 nPrfx, const OUString& sLocalName) :
            XMLVarFieldImportContext(rImport, rHlp, "Input",
                                     nPrfx, sLocalName,
                                     // description
                                     false, false,
                                     true, true, true,
                                     false, false,
                                     false, false, false,
                                     false)
    {
        bValid = true;  // always valid
    }

    void XMLTextInputFieldImportContext::PrepareField(
        const Reference<XPropertySet> & xPropertySet)
    {
        XMLVarFieldImportContext::PrepareField(xPropertySet);

        xPropertySet->setPropertyValue(sAPI_content, Any(GetContent()));
    }

    // table formula field

    XMLTableFormulaImportContext::XMLTableFormulaImportContext(
        SvXMLImport& rImport,
        XMLTextImportHelper& rHlp,
        sal_uInt16 nPrfx,
        const OUString& rLocalName) :
            XMLTextFieldImportContext(rImport, rHlp, "TableFormula",
                                      nPrfx, rLocalName),
            aValueHelper(rImport, rHlp, false, true, false, true),
            bIsShowFormula(false)
    {
    }

    void XMLTableFormulaImportContext::ProcessAttribute(
        sal_uInt16 nAttrToken,
        const OUString& sAttrValue )
    {
        switch (nAttrToken)
        {
            case XML_TOK_TEXTFIELD_FORMULA:
                aValueHelper.ProcessAttribute( nAttrToken, sAttrValue );
                bValid = true;  // we need a formula!
                break;

            case XML_TOK_TEXTFIELD_DATA_STYLE_NAME:
                aValueHelper.ProcessAttribute( nAttrToken, sAttrValue );
                break;
            case XML_TOK_TEXTFIELD_DISPLAY:
                if ( sAttrValue == "formula" )
                     bIsShowFormula = true;
                break;
            default:
                // unknown attribute -> ignore
                break;
        }
    }

    void XMLTableFormulaImportContext::PrepareField(
        const Reference<XPropertySet> & xPropertySet)
    {
        // set format and formula
        aValueHelper.PrepareField( xPropertySet );

        Any aAny;

        // set 'show formula' and presentation
        xPropertySet->setPropertyValue( "IsShowFormula", Any(bIsShowFormula) );

        aAny <<= GetContent();
        xPropertySet->setPropertyValue( "CurrentPresentation", aAny );
    }

    // variable declarations

    // Should be adapted to XMLVarField-/XMLSetVarFieldImportContext scheme!

    // declaration container import (<variable/user-field/sequence-decls>)

    XMLVariableDeclsImportContext::XMLVariableDeclsImportContext(
        SvXMLImport& rImport, XMLTextImportHelper& rHlp, sal_uInt16 nPrfx,
        const OUString& rLocalName, enum VarType eVarType) :
            SvXMLImportContext(rImport, nPrfx, rLocalName),
            eVarDeclsContextType(eVarType),
            rImportHelper(rHlp)
    {
    }

    SvXMLImportContextRef XMLVariableDeclsImportContext::CreateChildContext(
        sal_uInt16 nPrefix, const OUString& rLocalName,
        const Reference<xml::sax::XAttributeList> & xAttrList )
    {
        enum XMLTokenEnum eElementName;
        SvXMLImportContextRef xImportContext;

        if( XML_NAMESPACE_TEXT == nPrefix )
        {
            switch (eVarDeclsContextType)
            {
                case VarTypeSequence:
                    eElementName = XML_SEQUENCE_DECL;
                    break;
                case VarTypeSimple:
                    eElementName = XML_VARIABLE_DECL;
                    break;
                case VarTypeUserField:
                    eElementName = XML_USER_FIELD_DECL;
                    break;
                default:
                    OSL_FAIL("unknown field type!");
                    eElementName = XML_SEQUENCE_DECL;
                    break;
            }

            if( IsXMLToken( rLocalName, eElementName ) )
            {
                xImportContext = new XMLVariableDeclImportContext(
                    GetImport(), rImportHelper, nPrefix, rLocalName, xAttrList,
                    eVarDeclsContextType);
            }
        }

        // if no context was created, use default context
        if (!xImportContext) {
            xImportContext = SvXMLImportContext::CreateChildContext(nPrefix,
                                                                    rLocalName,
                                                                    xAttrList);
        }

        return xImportContext;
    }

    // declaration import (<variable/user-field/sequence-decl> elements)

    XMLVariableDeclImportContext::XMLVariableDeclImportContext(
        SvXMLImport& rImport, XMLTextImportHelper& rHlp,
        sal_uInt16 nPrfx, const OUString& rLocalName,
        const Reference<xml::sax::XAttributeList> & xAttrList,
        enum VarType eVarType) :
            SvXMLImportContext(rImport, nPrfx, rLocalName),
            // bug?? which properties for userfield/userfieldmaster
            aValueHelper(rImport, rHlp, true, false, true, false),
            cSeparationChar('.')
    {
        sal_Int8 nNumLevel(-1);
        OUString sName;

        if ( (XML_NAMESPACE_TEXT == nPrfx) &&
             ( ( IsXMLToken( rLocalName, XML_SEQUENCE_DECL )) ||
               ( IsXMLToken( rLocalName, XML_VARIABLE_DECL)) ||
               ( IsXMLToken( rLocalName, XML_USER_FIELD_DECL))    )) {

            // TODO: check validity (need name!)

            // parse attributes
            sal_Int16 nLength = xAttrList->getLength();
            for(sal_Int16 i=0; i<nLength; i++) {

                OUString sLocalName;
                sal_uInt16 nPrefix = GetImport().GetNamespaceMap().
                    GetKeyByAttrName( xAttrList->getNameByIndex(i), &sLocalName );

                sal_uInt16 nToken = rHlp.
                    GetTextFieldAttrTokenMap().Get(nPrefix, sLocalName);

                switch (nToken)
                {
                    case XML_TOK_TEXTFIELD_NAME:
                        sName = xAttrList->getValueByIndex(i);
                        break;
                    case XML_TOK_TEXTFIELD_NUMBERING_LEVEL:
                    {
                        sal_Int32 nLevel;
                        bool const bRet = ::sax::Converter::convertNumber(
                            nLevel, xAttrList->getValueByIndex(i), 0,
                            GetImport().GetTextImport()->GetChapterNumbering()->
                                                                       getCount());
                        if (bRet)
                        {
                            nNumLevel = static_cast< sal_Int8 >( nLevel-1 ); // API numbers -1..9
                        }
                        break;
                    }
                    case XML_TOK_TEXTFIELD_NUMBERING_SEPARATOR:
                        cSeparationChar =
                            static_cast<sal_Char>(xAttrList->getValueByIndex(i).toChar());
                        break;

                    default:
                        // delegate to value helper
                        aValueHelper.ProcessAttribute(nToken,
                                                      xAttrList->getValueByIndex(i));
                        break;
                }
            }

            Reference<XPropertySet> xFieldMaster;
            if (FindFieldMaster(xFieldMaster, GetImport(), rHlp,
                                sName, eVarType))
            {
                // now we have a field master: process attributes!
                Any aAny;

                switch (eVarType)
                {
                case VarTypeSequence:
                    xFieldMaster->setPropertyValue("ChapterNumberingLevel", Any(nNumLevel));

                    if (nNumLevel >= 0)
                    {
                        OUString sStr(&cSeparationChar, 1);
                        xFieldMaster->setPropertyValue(
                            "NumberingSeparator", Any(sStr));
                    }
                    break;
                case VarTypeSimple:
                    {
                        // set string or non-string SubType (#93192#)
                        // The SubType was already set in the FindFieldMaster
                        // method, but it needs to be adjusted if it's a string.
                        aAny <<= aValueHelper.IsStringValue()
                            ? SetVariableType::STRING : SetVariableType::VAR;
                        xFieldMaster->setPropertyValue(sAPI_sub_type, aAny);
                    }
                    break;
                case VarTypeUserField:
                {
                    bool bTmp = !aValueHelper.IsStringValue();
                    xFieldMaster->setPropertyValue("IsExpression", Any(bTmp));
                    aValueHelper.PrepareField(xFieldMaster);
                    break;
                }
                default:
                    OSL_FAIL("unknown varfield type");
                } // switch
            } // else: no field master found/constructed
        } // else: no sequence-decl
    }

    bool XMLVariableDeclImportContext::FindFieldMaster(
        Reference<XPropertySet> & xMaster, SvXMLImport& rImport,
        XMLTextImportHelper& rImportHelper,
        const OUString& sVarName, enum VarType eVarType)
    {
        static sal_Int32 nCollisionCount = 0;

        // rename field
        // currently: no family in use! Use 0.
        OUString sName = rImportHelper.GetRenameMap().Get(
            sal::static_int_cast< sal_uInt16 >(eVarType), sVarName);

        // get text fields supplier and field masters
        Reference<XTextFieldsSupplier> xTextFieldsSupp(rImport.GetModel(),
                                                       UNO_QUERY);
        Reference<container::XNameAccess> xFieldMasterNameAccess(
            xTextFieldsSupp->getTextFieldMasters(), UNO_QUERY);

        OUStringBuffer sBuffer;
        sBuffer.append(sAPI_fieldmaster_prefix);
        sBuffer.append(sAPI_set_expression);
        sBuffer.append(".");
        sBuffer.append(sName);
        OUString sVarServiceName = sBuffer.makeStringAndClear();

        sBuffer.append(sAPI_fieldmaster_prefix);
        sBuffer.append(sAPI_user);
        sBuffer.append(".");
        sBuffer.append(sName);
        OUString sUserServiceName = sBuffer.makeStringAndClear();

        if (xFieldMasterNameAccess->hasByName(sVarServiceName)) {
            // variable field master already in document

            Any aAny = xFieldMasterNameAccess->getByName(sVarServiceName);
            aAny >>= xMaster;

            aAny = xMaster->getPropertyValue(sAPI_sub_type);
            sal_Int16 nType = 0;
            aAny >>= nType;

            enum VarType eFMVarType =
                (SetVariableType::SEQUENCE == nType) ?
                    VarTypeSequence : VarTypeSimple;

            if (eFMVarType != eVarType)
            {
                OUString sNew;

                // FIXME! can't find if name is taken already!!!!

                nCollisionCount++;
                OUStringBuffer aBuf;
                aBuf.append(sName);
                aBuf.append("_renamed_");
                aBuf.append(nCollisionCount);
                sNew = aBuf.makeStringAndClear();

                rImportHelper.GetRenameMap().Add(
                    sal::static_int_cast< sal_uInt16 >(eVarType), sName, sNew);

                // call FindFieldMaster recursively to create new master
                return FindFieldMaster(xMaster, rImport, rImportHelper,
                                       sNew, eVarType);
            }
        } else if (xFieldMasterNameAccess->hasByName(sUserServiceName)) {
            // user field: get field master
            Any aAny = xFieldMasterNameAccess->getByName(sUserServiceName);
            aAny >>= xMaster;

            if (VarTypeUserField != eVarType) {
                // find new name that is not taken
                OUString sNew;

                // FIXME! can't find if name is taken already!!!!

                nCollisionCount++;
                OUStringBuffer aBuf;
                aBuf.append(sName);
                aBuf.append("_renamed_");
                aBuf.append(nCollisionCount);
                sNew = aBuf.makeStringAndClear();

                rImportHelper.GetRenameMap().Add(
                    sal::static_int_cast< sal_uInt16 >(eVarType), sName, sNew);

                // call FindFieldMaster recursively to create new master
                return FindFieldMaster(xMaster, rImport, rImportHelper,
                                       sNew, eVarType);
            }
        } else {
            // field name not used: create field master

            // import -> model is MultiServiceFactory -> createInstance
            Reference<lang::XMultiServiceFactory>
                xFactory(rImport.GetModel(),UNO_QUERY);
            if( xFactory.is() ) {

                OUStringBuffer sService;
                sService.append(sAPI_fieldmaster_prefix);
                sService.appendAscii((eVarType==VarTypeUserField) ?
                                     sAPI_user : sAPI_set_expression);
                Reference<XInterface> xIfc =
                    xFactory->createInstance( sService.makeStringAndClear() );
                if (xIfc.is()) {
                    Reference<XPropertySet> xTmp( xIfc, UNO_QUERY );
                    xMaster = xTmp;

                    // set name
                    xMaster->setPropertyValue("Name", Any(sName));

                    if (eVarType != VarTypeUserField) {
                        // set subtype for setexp field
                        Any aAny;
                        aAny <<= ((eVarType == VarTypeSimple) ?
                                  SetVariableType::VAR :
                                  SetVariableType::SEQUENCE);
                        xMaster->setPropertyValue(sAPI_sub_type, aAny);
                    } // else : user field: no subtype

                } else {
                    return false;
                }
            } else {
                return false;
            }
        }

        DBG_ASSERT(xMaster.is(), "no field master found!?!");
        return true;
    }

    // Database Display field import

    XMLDatabaseDisplayImportContext::XMLDatabaseDisplayImportContext(
        SvXMLImport& rImport, XMLTextImportHelper& rHlp, sal_uInt16 nPrfx,
        const OUString& rLocalName) :
            XMLDatabaseFieldImportContext(rImport, rHlp, sAPI_database,
                                          nPrfx, rLocalName, false),
            aValueHelper(rImport, rHlp, false, true, false, false),
            bColumnOK(false),
            bDisplay( true ),
            bDisplayOK( false )
    {
    }

    void XMLDatabaseDisplayImportContext::ProcessAttribute(
        sal_uInt16 nAttrToken, const OUString& sAttrValue )
    {
        switch (nAttrToken)
        {
            case XML_TOK_TEXTFIELD_COLUMN_NAME:
                sColumnName = sAttrValue;
                bColumnOK = true;
                break;
            case XML_TOK_TEXTFIELD_DISPLAY:
                {
                    bool bNone = IsXMLToken( sAttrValue, XML_NONE );
                    bool bValue = IsXMLToken( sAttrValue, XML_VALUE );
                    bDisplay = bValue;
                    bDisplayOK = bNone || bValue;
                }
                break;
            case XML_TOK_TEXTFIELD_DATABASE_NAME:
            case XML_TOK_TEXTFIELD_TABLE_NAME:
            case XML_TOK_TEXTFIELD_TABLE_TYPE:
                // handled by super class
                XMLDatabaseFieldImportContext::ProcessAttribute(nAttrToken,
                                                                sAttrValue);
                break;
            default:
                // remainder handled by value helper
                aValueHelper.ProcessAttribute(nAttrToken, sAttrValue);
                break;
        }

        bValid = bTableOK && bDatabaseOK && bColumnOK;
    }

    void XMLDatabaseDisplayImportContext::EndElement()
    {
        // we have an EndElement of our own, because database fields need
        // to be attached to a field master before they can be inserted into
        // the document. Database stuff (database, table, column) all goes
        // to the field master, value & style go to the field.

        if (bValid)
        {

            // so here goes: we start with the master
            Reference<XPropertySet> xMaster;

            // create and prepare field master first
            if (CreateField(xMaster,
                            "com.sun.star.text.FieldMaster.Database"))
            {
                Any aAny;
                xMaster->setPropertyValue("DataColumnName", Any(sColumnName));

                // fieldmaster takes database, table and column name
                XMLDatabaseFieldImportContext::PrepareField(xMaster);

                // create field
                Reference<XPropertySet> xField;
                if (CreateField(xField,
                                sAPI_database))
                {
                    // attach field master
                    Reference<XDependentTextField> xDepField(xField, UNO_QUERY);
                    if (xDepField.is())
                    {
                        // attach field to field master
                        xDepField->attachTextFieldMaster(xMaster);

                        // attach field to document
                        Reference<XTextContent> xTextContent(xField, UNO_QUERY);
                        if (xTextContent.is())
                        {
                            // insert, set field properties and exit!
                            GetImportHelper().InsertTextContent(xTextContent);

                            // prepare field: format from database?
                            bool bTmp = !aValueHelper.IsFormatOK();
                            xField->setPropertyValue("DataBaseFormat", Any(bTmp));

                            // value, value-type and format done by value helper
                            aValueHelper.PrepareField(xField);

                            // visibility
                            if( bDisplayOK )
                            {
                                xField->setPropertyValue(sAPI_is_visible, Any(bDisplay));
                            }

                            // set presentation
                            aAny <<= GetContent();
                            xField->setPropertyValue(sAPI_current_presentation, aAny);

                            // success!
                            return;
                        }
                    }
                }
            }
        }

        // above: exit on success; so for all error cases we end up here!
        // write element content
        GetImportHelper().InsertString(GetContent());
    }

    // value import helper

    enum ValueType
    {
        XML_VALUE_TYPE_STRING,
        XML_VALUE_TYPE_FLOAT,
        XML_VALUE_TYPE_CURRENCY,
        XML_VALUE_TYPE_PERCENTAGE,
        XML_VALUE_TYPE_DATE,
        XML_VALUE_TYPE_TIME,
        XML_VALUE_TYPE_BOOLEAN
    };

    static SvXMLEnumMapEntry<ValueType> const aValueTypeMap[] =
    {
        { XML_FLOAT,        XML_VALUE_TYPE_FLOAT },
        { XML_CURRENCY,     XML_VALUE_TYPE_CURRENCY },
        { XML_PERCENTAGE,   XML_VALUE_TYPE_PERCENTAGE },
        { XML_DATE,         XML_VALUE_TYPE_DATE },
        { XML_TIME,         XML_VALUE_TYPE_TIME },
        { XML_BOOLEAN,      XML_VALUE_TYPE_BOOLEAN },
        { XML_STRING,       XML_VALUE_TYPE_STRING },
        { XML_TOKEN_INVALID, ValueType(0) }
    };

    XMLValueImportHelper::XMLValueImportHelper(
        SvXMLImport& rImprt,
        XMLTextImportHelper& rHlp,
        bool bType, bool bStyle, bool bValue, bool bFormula) :

            rImport(rImprt),
            rHelper(rHlp),

            fValue(0.0),
            nFormatKey(0),
            bIsDefaultLanguage(true),

            bStringType(false),
            bFormatOK(false),
            bStringValueOK(false),
            bFormulaOK(false),

            bSetType(bType),
            bSetValue(bValue),
            bSetStyle(bStyle),
            bSetFormula(bFormula)
    {
    }

    void XMLValueImportHelper::ProcessAttribute(
        sal_uInt16 nAttrToken, const OUString& sAttrValue )
    {
        switch (nAttrToken)
        {
            case XML_TOK_TEXTFIELD_VALUE_TYPE:
            {
                // convert enum
                ValueType eValueType = XML_VALUE_TYPE_STRING;
                bool bRet = SvXMLUnitConverter::convertEnum(
                    eValueType, sAttrValue, aValueTypeMap);

                if (bRet) {
                    switch (eValueType)
                    {
                        case XML_VALUE_TYPE_STRING:
                            bStringType = true;
                            break;
                        case XML_VALUE_TYPE_FLOAT:
                        case XML_VALUE_TYPE_CURRENCY:
                        case XML_VALUE_TYPE_PERCENTAGE:
                        case XML_VALUE_TYPE_DATE:
                        case XML_VALUE_TYPE_TIME:
                        case XML_VALUE_TYPE_BOOLEAN:
                            bStringType = false;
                            break;

                        default:
                            OSL_FAIL("unknown value type");
                    }
                }
                break;
            }

            case XML_TOK_TEXTFIELD_VALUE:
            {
                double fTmp;
                bool const bRet = ::sax::Converter::convertDouble(fTmp,sAttrValue);
                if (bRet) {
                    fValue = fTmp;
                }
                break;
            }

            case XML_TOK_TEXTFIELD_TIME_VALUE:
            {
                double fTmp;
                bool const bRet =
                    ::sax::Converter::convertDuration(fTmp, sAttrValue);
                if (bRet) {
                    fValue = fTmp;
                }
                break;
            }

            case XML_TOK_TEXTFIELD_DATE_VALUE:
            {
                double fTmp;
                bool bRet = rImport.GetMM100UnitConverter().
                    convertDateTime(fTmp,sAttrValue);
                if (bRet) {
                    fValue = fTmp;
                }
                break;
            }

            case XML_TOK_TEXTFIELD_BOOL_VALUE:
            {
                bool bTmp(false);
                bool bRet = ::sax::Converter::convertBool(bTmp, sAttrValue);
                if (bRet) {
                    fValue = (bTmp ? 1.0 : 0.0);
                }
                else
                {
                    double fTmp;
                    bRet = ::sax::Converter::convertDouble(fTmp, sAttrValue);
                    if (bRet) {
                        fValue = fTmp;
                    }
                }
                break;
            }

            case XML_TOK_TEXTFIELD_STRING_VALUE:
                sValue = sAttrValue;
                bStringValueOK = true;
                break;

            case XML_TOK_TEXTFIELD_FORMULA:
                {
                    OUString sTmp;
                    sal_uInt16 nPrefix = rImport.GetNamespaceMap().
                            GetKeyByAttrName_( sAttrValue, &sTmp );
                    if( XML_NAMESPACE_OOOW == nPrefix )
                    {
                        sFormula = sTmp;
                        bFormulaOK = true;
                    }
                    else
                        sFormula = sAttrValue;
                }
                break;

            case XML_TOK_TEXTFIELD_DATA_STYLE_NAME:
            {
                sal_Int32 nKey = rHelper.GetDataStyleKey(
                                              sAttrValue, &bIsDefaultLanguage);
                if (-1 != nKey)
                {
                    nFormatKey = nKey;
                    bFormatOK = true;
                }
                break;
            }
        } // switch
    }

    void XMLValueImportHelper::PrepareField(
        const Reference<XPropertySet> & xPropertySet)
    {
        Any aAny;

        if (bSetType)
        {
            // ??? how to set type?
        }

        if (bSetFormula)
        {
            aAny <<= !bFormulaOK ? sDefault : sFormula;
            xPropertySet->setPropertyValue(sAPI_content, aAny);
        }

        // format/style
        if (bSetStyle && bFormatOK)
        {
            xPropertySet->setPropertyValue(sAPI_number_format, Any(nFormatKey));

            if( xPropertySet->getPropertySetInfo()->
                    hasPropertyByName( "IsFixedLanguage" ) )
            {
                bool bIsFixedLanguage = ! bIsDefaultLanguage;
                xPropertySet->setPropertyValue( "IsFixedLanguage", Any(bIsFixedLanguage) );
            }
        }

        // value: string or float
        if (bSetValue)
        {
            if (bStringType)
            {
                aAny <<= !bStringValueOK ? sDefault : sValue;
                xPropertySet->setPropertyValue(sAPI_content, aAny);
            }
            else
            {
                xPropertySet->setPropertyValue("Value", Any(fValue));
            }
        }
    }

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V560 A part of conditional expression is always true: bDisplayOK.

↑ V519 The 'aAny' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 848, 850.