/*************************************************************************
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* 
* Copyright 2008 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: formcontrolfactory.cxx,v $
*
* $Revision: 1.1.2.3 $
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org.  If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"

#include "dbtoolsclient.hxx"
#include "formcontrolfactory.hxx"
#include "fmcontrollayout.hxx"
#include "fmprop.hrc"
#include "fmresids.hrc"
#include "svx/dialmgr.hxx"
#include "svx/svdouno.hxx"

/** === begin UNO includes === **/
#include <com/sun/star/form/XFormComponent.hpp>
#include <com/sun/star/form/FormComponentType.hpp>
#include <com/sun/star/awt/ScrollBarOrientation.hpp>
#include <com/sun/star/form/XGridColumnFactory.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
#include <com/sun/star/style/VerticalAlignment.hpp>
#include <com/sun/star/awt/LineEndFormat.hpp>
#include <com/sun/star/awt/ImageScaleMode.hpp>
#include <com/sun/star/sdbc/DataType.hpp>
#include <com/sun/star/util/XNumberFormatTypes.hpp>
#include <com/sun/star/sdbc/ColumnValue.hpp>
#include <com/sun/star/text/WritingMode2.hpp>
/** === end UNO includes === **/

#include <comphelper/componentcontext.hxx>
#include <comphelper/numbers.hxx>
#include <svtools/syslocale.hxx>
#include <tools/gen.hxx>
#include <tools/diagnose_ex.h>

#include <set>

//........................................................................
namespace svxform
{
//........................................................................

	/** === begin UNO using === **/
	using ::com::sun::star::uno::Reference;
	using ::com::sun::star::uno::XInterface;
	using ::com::sun::star::uno::UNO_QUERY;
	using ::com::sun::star::uno::UNO_QUERY_THROW;
	using ::com::sun::star::uno::UNO_SET_THROW;
	using ::com::sun::star::uno::Exception;
	using ::com::sun::star::uno::RuntimeException;
	using ::com::sun::star::uno::Any;
	using ::com::sun::star::uno::makeAny;
	using ::com::sun::star::uno::Sequence;
	using ::com::sun::star::uno::Type;
    using ::com::sun::star::beans::XPropertySet;
    using ::com::sun::star::awt::XControlModel;
    using ::com::sun::star::form::XFormComponent;
    using ::com::sun::star::container::XIndexAccess;
    using ::com::sun::star::beans::XPropertySetInfo;
    using ::com::sun::star::beans::PropertyValue;
    using ::com::sun::star::container::XChild;
    using ::com::sun::star::form::XGridColumnFactory;
    using ::com::sun::star::lang::XServiceInfo;
    using ::com::sun::star::style::XStyleFamiliesSupplier;
    using ::com::sun::star::container::XNameAccess;
    using ::com::sun::star::style::VerticalAlignment_MIDDLE;
    using ::com::sun::star::beans::Property;
    using ::com::sun::star::uno::TypeClass_DOUBLE;
    using ::com::sun::star::uno::TypeClass_LONG;
    using ::com::sun::star::util::XNumberFormats;
    using ::com::sun::star::util::XNumberFormatTypes;
	/** === end UNO using === **/
    namespace FormComponentType = ::com::sun::star::form::FormComponentType;
    namespace ScrollBarOrientation = ::com::sun::star::awt::ScrollBarOrientation;
    namespace LineEndFormat = ::com::sun::star::awt::LineEndFormat;
    namespace ImageScaleMode = ::com::sun::star::awt::ImageScaleMode;
    namespace DataType = ::com::sun::star::sdbc::DataType;
    namespace ColumnValue = ::com::sun::star::sdbc::ColumnValue;
    namespace WritingMode2 = ::com::sun::star::text::WritingMode2;

	//====================================================================
	//= FormControlFactory_Data
	//====================================================================
    struct FormControlFactory_Data
    {
        ::comphelper::ComponentContext  m_aContext;

        FormControlFactory_Data( const ::comphelper::ComponentContext& _rContext )
            :m_aContext( _rContext )
        {
        }
    };

	//====================================================================
	//= FormControlFactory
	//====================================================================
	//--------------------------------------------------------------------
    FormControlFactory::FormControlFactory( const ::comphelper::ComponentContext& _rContext )
        :m_pData( new FormControlFactory_Data( _rContext ) )
    {
    }

	//--------------------------------------------------------------------
    FormControlFactory::~FormControlFactory()
    {
    }

	//--------------------------------------------------------------------
    sal_Int16 FormControlFactory::initializeControlModel( const DocumentType _eDocType, const SdrUnoObj& _rObject )
    {
        return initializeControlModel(
            _eDocType,
            Reference< XPropertySet >( _rObject.GetUnoControlModel(), UNO_QUERY ),
            _rObject.GetCurrentBoundRect()
        );
    }

	//--------------------------------------------------------------------
    sal_Int16 FormControlFactory::initializeControlModel( const DocumentType _eDocType, const Reference< XPropertySet >& _rxControlModel )
    {
        return initializeControlModel(
            _eDocType, _rxControlModel, Rectangle()
        );
    }

    // -----------------------------------------------------------------------------
    namespace
    {
        //....................................................................
        static ::rtl::OUString lcl_getUniqueLabel_nothrow( const Reference< XPropertySet >& _rxControlModel, const ::rtl::OUString& _rBaseLabel )
        {
            ::rtl::OUString sLabel( _rBaseLabel );
            try
            {
                typedef ::std::set< ::rtl::OUString > StringBag;
                StringBag aUsedLabels;

                Reference< XFormComponent > xFormComponent( _rxControlModel, UNO_QUERY_THROW );
                Reference< XIndexAccess > xContainer( xFormComponent->getParent(), UNO_QUERY_THROW );
                // loop through all siblings of the control model, and collect their labels
                for ( sal_Int32 index=xContainer->getCount(); index>0; )
                {
                    Reference< XPropertySet > xElement( xContainer->getByIndex( --index ), UNO_QUERY_THROW );
                    if ( xElement == _rxControlModel )
                        continue;

                    Reference< XPropertySetInfo > xPSI( xElement->getPropertySetInfo(), UNO_SET_THROW );
                    if ( !xPSI->hasPropertyByName( FM_PROP_LABEL ) )
                        continue;

                    ::rtl::OUString sElementLabel;
                    OSL_VERIFY( xElement->getPropertyValue( FM_PROP_LABEL ) >>= sElementLabel );
                    aUsedLabels.insert( sElementLabel );
                }

                // now find a free label
                sal_Int32 i=2;
                while ( aUsedLabels.find( sLabel ) != aUsedLabels.end() )
                {
                    ::rtl::OUStringBuffer aBuffer( _rBaseLabel );
                    aBuffer.appendAscii( " " );
                    aBuffer.append( (sal_Int32)i++ );
                    sLabel = aBuffer.makeStringAndClear();
                }
            }
            catch( const Exception& )
            {
            	DBG_UNHANDLED_EXCEPTION();
            }
            return sLabel;
        }

        //....................................................................
        static Sequence< PropertyValue > lcl_getDataSourceIndirectProperties( const Reference< XPropertySet >& _rxControlModel,
            const ::comphelper::ComponentContext& _rContext )
        {
            OSL_PRECOND( _rxControlModel.is(), "lcl_getDataSourceIndirectProperties: invalid model!" );

            Sequence< PropertyValue > aInfo;
            try
            {
                Reference< XChild > xChild( _rxControlModel, UNO_QUERY );
                Reference< XPropertySet > xForm;
                if ( xChild.is() )
                    xForm = xForm.query( xChild->getParent() );

                if ( Reference< XGridColumnFactory >( xForm, UNO_QUERY ).is() )
                {   // hmm. the model is a grid column, in real
                    xChild = xChild.query( xForm );
                    xForm = xForm.query( xChild->getParent() );
                }

                OSL_ENSURE( xForm.is(), "lcl_getDataSourceIndirectProperties: could not determine the form!" );
                if ( !xForm.is() )
                    return aInfo;
                ::rtl::OUString sDataSourceName;
                xForm->getPropertyValue( FM_PROP_DATASOURCE ) >>= sDataSourceName;

                Reference< XPropertySet > xDsProperties;
                if ( sDataSourceName.getLength() )
                    xDsProperties = xDsProperties.query( OStaticDataAccessTools().getDataSource( sDataSourceName, _rContext.getLegacyServiceFactory() ) );
                if ( xDsProperties.is() )
                    xDsProperties->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Info" ) ) ) >>= aInfo;
            }
            catch( const Exception& )
            {
        	    OSL_ENSURE( sal_False, "lcl_getDataSourceIndirectProperties: caught an exception!" );
            }
            return aInfo;
        }
        /*
            ATTENTION!
            Broken for solaris? It seems that the old used template argument TYPE was already
            defined as a macro ... which expand to ... "TYPE "!?
            All platforms are OK - excepting Solaris. There the line "template< class TYPE >"
            was expanded to "template < class TYPE " where the closing ">" was missing.
        */
        #ifdef MYTYPE
            #error "Who defines the macro MYTYPE, which is used as template argument here?"
        #endif

        //....................................................................
        template< class MYTYPE >
        Reference< MYTYPE > getTypedModelNode( const Reference< XInterface >& _rxModelNode )
        {
            Reference< MYTYPE > xTypedNode( _rxModelNode, UNO_QUERY );
            if ( xTypedNode.is() )
                return xTypedNode;
            else
            {
                Reference< XChild > xChild( _rxModelNode, UNO_QUERY );
                if ( xChild.is() )
                    return getTypedModelNode< MYTYPE >( xChild->getParent() );
                else
                    return NULL;
            }
        }

        //....................................................................
        static bool lcl_getDocumentDefaultStyleAndFamily( const Reference< XInterface >& _rxDocument, ::rtl::OUString& _rFamilyName, ::rtl::OUString& _rStyleName ) SAL_THROW(( Exception ))
        {
            bool bSuccess = true;
            Reference< XServiceInfo > xDocumentSI( _rxDocument, UNO_QUERY );
            if ( xDocumentSI.is() )
            {
                if (  xDocumentSI->supportsService( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.text.TextDocument" ) ) )
                   || xDocumentSI->supportsService( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.text.WebDocument" ) ) )
                   )
                {
                    _rFamilyName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ParagraphStyles" ) );
                    _rStyleName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) );
                }
                else if ( xDocumentSI->supportsService( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sheet.SpreadsheetDocument" ) ) ) )
                {
                    _rFamilyName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CellStyles" ) );
                    _rStyleName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Default" ) );
                }
                else if (  xDocumentSI->supportsService( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.DrawingDocument" ) ) )
                        || xDocumentSI->supportsService( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.presentation.PresentationDocument" ) ) )
                        )
                {
                    _rFamilyName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "graphics" ) );
                    _rStyleName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "standard" ) );
                }
                else
                    bSuccess = false;
            }
            return bSuccess;
        }

        //....................................................................
        static const sal_Char* aCharacterAndParagraphProperties[] =
        {
            "CharFontName",
            "CharFontStyleName",
            "CharFontFamily",
            "CharFontCharSet",
            "CharFontPitch",
            "CharColor",
            "CharEscapement",
            "CharHeight",
            "CharUnderline",
            "CharWeight",
            "CharPosture",
            "CharAutoKerning",
            "CharBackColor",
            "CharBackTransparent",
            "CharCaseMap",
            "CharCrossedOut",
            "CharFlash",
            "CharStrikeout",
            "CharWordMode",
            "CharKerning",
            "CharLocale",
            "CharKeepTogether",
            "CharNoLineBreak",
            "CharShadowed",
            "CharFontType",
            "CharStyleName",
            "CharContoured",
            "CharCombineIsOn",
            "CharCombinePrefix",
            "CharCombineSuffix",
            "CharEmphasize",
            "CharRelief",
            "RubyText",
            "RubyAdjust",
            "RubyCharStyleName",
            "RubyIsAbove",
            "CharRotation",
            "CharRotationIsFitToLine",
            "CharScaleWidth",
            "HyperLinkURL",
            "HyperLinkTarget",
            "HyperLinkName",
            "VisitedCharStyleName",
            "UnvisitedCharStyleName",
            "CharEscapementHeight",
            "CharNoHyphenation",
            "CharUnderlineColor",
            "CharUnderlineHasColor",
            "CharStyleNames",
            "CharHeightAsian",
            "CharWeightAsian",
            "CharFontNameAsian",
            "CharFontStyleNameAsian",
            "CharFontFamilyAsian",
            "CharFontCharSetAsian",
            "CharFontPitchAsian",
            "CharPostureAsian",
            "CharLocaleAsian",
            "ParaIsCharacterDistance",
            "ParaIsForbiddenRules",
            "ParaIsHangingPunctuation",
            "CharHeightComplex",
            "CharWeightComplex",
            "CharFontNameComplex",
            "CharFontStyleNameComplex",
            "CharFontFamilyComplex",
            "CharFontCharSetComplex",
            "CharFontPitchComplex",
            "CharPostureComplex",
            "CharLocaleComplex",
            "ParaAdjust",
            "ParaLineSpacing",
            "ParaBackColor",
            "ParaBackTransparent",
            "ParaBackGraphicURL",
            "ParaBackGraphicFilter",
            "ParaBackGraphicLocation",
            "ParaLastLineAdjust",
            "ParaExpandSingleWord",
            "ParaLeftMargin",
            "ParaRightMargin",
            "ParaTopMargin",
            "ParaBottomMargin",
            "ParaLineNumberCount",
            "ParaLineNumberStartValue",
            "PageDescName",
            "PageNumberOffset",
            "ParaRegisterModeActive",
            "ParaTabStops",
            "ParaStyleName",
            "DropCapFormat",
            "DropCapWholeWord",
            "ParaKeepTogether",
            "Setting",
            "ParaSplit",
            "Setting",
            "NumberingLevel",
            "NumberingRules",
            "NumberingStartValue",
            "ParaIsNumberingRestart",
            "NumberingStyleName",
            "ParaOrphans",
            "ParaWidows",
            "ParaShadowFormat",
            "LeftBorder",
            "RightBorder",
            "TopBorder",
            "BottomBorder",
            "BorderDistance",
            "LeftBorderDistance",
            "RightBorderDistance",
            "TopBorderDistance",
            "BottomBorderDistance",
            "BreakType",
            "DropCapCharStyleName",
            "ParaFirstLineIndent",
            "ParaIsAutoFirstLineIndent",
            "ParaIsHyphenation",
            "ParaHyphenationMaxHyphens",
            "ParaHyphenationMaxLeadingChars",
            "ParaHyphenationMaxTrailingChars",
            "ParaVertAlignment",
            "ParaUserDefinedAttributes",
            "NumberingIsNumber",
            "ParaIsConnectBorder",
            NULL
        };

        //....................................................................
        static void lcl_initializeCharacterAttributes( const Reference< XPropertySet >& _rxModel )
        {
            // need to initialize the attributes from the "Default" style of the document we live in

            try
            {
                // the style family collection
                Reference< XStyleFamiliesSupplier > xSuppStyleFamilies = getTypedModelNode< XStyleFamiliesSupplier >( _rxModel.get() );
                Reference< XNameAccess > xStyleFamilies;
                if ( xSuppStyleFamilies.is() )
                    xStyleFamilies = xSuppStyleFamilies->getStyleFamilies();
                OSL_ENSURE( xStyleFamilies.is(), "lcl_initializeCharacterAttributes: could not obtain the style families!" );
                if ( !xStyleFamilies.is() )
                    return;

                // the names of the family, and the style - depends on the document type we live in
                ::rtl::OUString sFamilyName, sStyleName;
                bool bKnownDocumentType = lcl_getDocumentDefaultStyleAndFamily( xSuppStyleFamilies.get(), sFamilyName, sStyleName );
                OSL_ENSURE( bKnownDocumentType, "lcl_initializeCharacterAttributes: Huh? What document type is this?" );
                if ( !bKnownDocumentType )
                    return;

                // the concrete style
                Reference< XNameAccess > xStyleFamily( xStyleFamilies->getByName( sFamilyName ), UNO_QUERY );
                Reference< XPropertySet > xStyle;
                if ( xStyleFamily.is() )
                    xStyleFamily->getByName( sStyleName ) >>= xStyle;
                OSL_ENSURE( xStyle.is(), "lcl_initializeCharacterAttributes: could not retrieve the style!" );
                if ( !xStyle.is() )
                    return;

                // transfer all properties which are described by the com.sun.star.style.
                Reference< XPropertySetInfo > xSourcePropInfo( xStyle->getPropertySetInfo() );
                Reference< XPropertySetInfo > xDestPropInfo( _rxModel->getPropertySetInfo() );
                OSL_ENSURE( xSourcePropInfo.is() && xDestPropInfo.is(), "lcl_initializeCharacterAttributes: no property set info!" );
                if ( !xSourcePropInfo.is() || !xDestPropInfo.is() )
                    return;

                ::rtl::OUString sPropertyName;
                const sal_Char** pCharacterProperty = aCharacterAndParagraphProperties;
                while ( *pCharacterProperty )
                {
                    sPropertyName = ::rtl::OUString::createFromAscii( *pCharacterProperty );

                    if ( xSourcePropInfo->hasPropertyByName( sPropertyName ) && xDestPropInfo->hasPropertyByName( sPropertyName ) )
                        _rxModel->setPropertyValue( sPropertyName, xStyle->getPropertyValue( sPropertyName ) );

                    ++pCharacterProperty;
                }
            }
            catch( const Exception& )
            {
                DBG_UNHANDLED_EXCEPTION();
            }
        }
    }

	//--------------------------------------------------------------------
    sal_Int16 FormControlFactory::initializeControlModel( const DocumentType _eDocType, const Reference< XPropertySet >& _rxControlModel,
        const Rectangle& _rControlBoundRect )
    {
        sal_Int16 nClassId = FormComponentType::CONTROL;

        OSL_ENSURE( _rxControlModel.is(), "FormControlFactory::initializeControlModel: invalid model!" );
        if ( !_rxControlModel.is() )
            return nClassId;

        try
        {
            ControlLayouter::initializeControlLayout( _rxControlModel, _eDocType );

            _rxControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId;
		    Reference< XPropertySetInfo > xPSI( _rxControlModel->getPropertySetInfo(), UNO_SET_THROW );
            switch ( nClassId )
            {
                case FormComponentType::SCROLLBAR:
                    _rxControlModel->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LiveScroll" ) ), makeAny( (sal_Bool)sal_True ) );
                    // NO break!
                case FormComponentType::SPINBUTTON:
                {
                    sal_Int32 eOrientation = ScrollBarOrientation::HORIZONTAL;
                    if ( !_rControlBoundRect.IsEmpty() && ( _rControlBoundRect.GetWidth() < _rControlBoundRect.GetHeight() ) )
                        eOrientation = ScrollBarOrientation::VERTICAL;
                    _rxControlModel->setPropertyValue( FM_PROP_ORIENTATION, makeAny( eOrientation ) );
                }
                break;

                case FormComponentType::LISTBOX:
                case FormComponentType::COMBOBOX:
                {
                    sal_Bool bDropDown = !_rControlBoundRect.IsEmpty() && ( _rControlBoundRect.GetWidth() >= 3 * _rControlBoundRect.GetHeight() );
                    _rxControlModel->setPropertyValue( FM_PROP_DROPDOWN, makeAny( (sal_Bool)bDropDown ) );
                }
                break;

                case FormComponentType::TEXTFIELD:
                {
                    initializeTextFieldLineEnds( _rxControlModel );
                    lcl_initializeCharacterAttributes( _rxControlModel );

                    if  (   !_rControlBoundRect.IsEmpty()
                        &&  !( _rControlBoundRect.GetWidth() > 4 * _rControlBoundRect.GetHeight() )
                        )
                    {
                        if ( xPSI->hasPropertyByName( FM_PROP_MULTILINE ) )
                            _rxControlModel->setPropertyValue( FM_PROP_MULTILINE, makeAny( (sal_Bool)sal_True ) );
                    }
                }
                break;

                case FormComponentType::RADIOBUTTON:
                case FormComponentType::CHECKBOX:
                case FormComponentType::FIXEDTEXT:
                {
                    ::rtl::OUString sVertAlignPropertyName( RTL_CONSTASCII_USTRINGPARAM( "VerticalAlign" ) );
                    if ( xPSI->hasPropertyByName( sVertAlignPropertyName ) )
                        _rxControlModel->setPropertyValue( sVertAlignPropertyName, makeAny( VerticalAlignment_MIDDLE ) );
                }
                break;

                case FormComponentType::IMAGEBUTTON:
                case FormComponentType::IMAGECONTROL:
                {
                    const ::rtl::OUString sScaleModeProperty( RTL_CONSTASCII_USTRINGPARAM( "ScaleMode" ) );
                    if ( xPSI->hasPropertyByName( sScaleModeProperty ) )
                        _rxControlModel->setPropertyValue( sScaleModeProperty, makeAny( ImageScaleMode::Isotropic ) );
                }
                break;
            }

            // initial default label for the control
            if ( xPSI->hasPropertyByName( FM_PROP_LABEL ) )
            {
                ::rtl::OUString sExistingLabel;
                OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_LABEL ) >>= sExistingLabel );
                if ( !sExistingLabel.getLength() )
                {
                    ::rtl::OUString sInitialLabel;
                    OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_NAME ) >>= sInitialLabel );

                    sal_uInt16 nTitleResId = 0;
                    switch ( nClassId )
                    {
                        case FormComponentType::COMMANDBUTTON:  nTitleResId = RID_STR_PROPTITLE_PUSHBUTTON;      break;
                        case FormComponentType::RADIOBUTTON:    nTitleResId = RID_STR_PROPTITLE_RADIOBUTTON;     break;
                        case FormComponentType::CHECKBOX:       nTitleResId = RID_STR_PROPTITLE_CHECKBOX;        break;
                        case FormComponentType::GROUPBOX:       nTitleResId = RID_STR_PROPTITLE_GROUPBOX;        break;
                        case FormComponentType::FIXEDTEXT:      nTitleResId = RID_STR_PROPTITLE_FIXEDTEXT;       break;
                    }

                    if ( nTitleResId )
                        sInitialLabel = String( SVX_RES( nTitleResId ) );

                    _rxControlModel->setPropertyValue(
                        FM_PROP_LABEL,
                        makeAny( lcl_getUniqueLabel_nothrow( _rxControlModel, sInitialLabel ) )
                    );
                }
            }

            // strict format = yes is the default (i93467)
            if ( xPSI->hasPropertyByName( FM_PROP_STRICTFORMAT ) )
	        {
		        _rxControlModel->setPropertyValue( FM_PROP_STRICTFORMAT, makeAny( sal_Bool( sal_True ) ) );
	        }

            if ( xPSI->hasPropertyByName( FM_PROP_WRITING_MODE ) )
                _rxControlModel->setPropertyValue( FM_PROP_WRITING_MODE, makeAny( WritingMode2::CONTEXT ) );
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
        return nClassId;
    }

    //------------------------------------------------------------------------------
    void FormControlFactory::initializeTextFieldLineEnds( const Reference< XPropertySet >& _rxModel )
    {
        OSL_PRECOND( _rxModel.is(), "initializeTextFieldLineEnds: invalid model!" );
        if ( !_rxModel.is() )
            return;

        try
        {
            Reference< XPropertySetInfo > xInfo = _rxModel->getPropertySetInfo();
            if ( !xInfo.is() || !xInfo->hasPropertyByName( FM_PROP_LINEENDFORMAT ) )
                return;

            // let's see if the data source which the form belongs to (if any)
            // has a setting for the preferred line end format
            sal_Bool bDosLineEnds = sal_False;
            Sequence< PropertyValue > aInfo = lcl_getDataSourceIndirectProperties( _rxModel, m_pData->m_aContext );
            const PropertyValue* pInfo = aInfo.getConstArray();
            const PropertyValue* pInfoEnd = pInfo + aInfo.getLength();
            for ( ; pInfo != pInfoEnd; ++pInfo )
            {
                if ( pInfo->Name.equalsAscii( "PreferDosLikeLineEnds" ) )
                {
                    pInfo->Value >>= bDosLineEnds;
                    break;
                }
            }

            sal_Int16 nLineEndFormat = bDosLineEnds ? LineEndFormat::CARRIAGE_RETURN_LINE_FEED : LineEndFormat::LINE_FEED;
            _rxModel->setPropertyValue( FM_PROP_LINEENDFORMAT, makeAny( nLineEndFormat ) );
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
    }

    //------------------------------------------------------------------------------
    void FormControlFactory::initializeFieldDependentProperties( const Reference< XPropertySet >& _rxDatabaseField,
        const Reference< XPropertySet >& _rxControlModel, const Reference< XNumberFormats >& _rxNumberFormats )
    {
        OSL_PRECOND( _rxDatabaseField.is() && _rxControlModel.is(),
            "FormControlFactory::initializeFieldDependentProperties: illegal params!" );
        if ( !_rxDatabaseField.is() || !_rxControlModel.is() )
            return;

        try
        {
            ////////////////////////////////////////////////////////////////////////
            // if the field has a numeric format, and the model has a "Scale" property, sync it
		    Reference< XPropertySetInfo > xFieldPSI( _rxDatabaseField->getPropertySetInfo(), UNO_SET_THROW );
            Reference< XPropertySetInfo > xModelPSI( _rxControlModel->getPropertySetInfo(), UNO_SET_THROW );

            if ( xModelPSI->hasPropertyByName( FM_PROP_DECIMAL_ACCURACY ) )
            {
		        sal_Int32 nFormatKey = 0;
                if ( xFieldPSI->hasPropertyByName( FM_PROP_FORMATKEY ) )
                {
			        _rxDatabaseField->getPropertyValue( FM_PROP_FORMATKEY ) >>= nFormatKey;
                }
                else
                {
                    nFormatKey = OStaticDataAccessTools().getDefaultNumberFormat(
                        _rxDatabaseField,
                        Reference< XNumberFormatTypes >( _rxNumberFormats, UNO_QUERY ),
                        SvtSysLocale().GetLocaleData().getLocale()
                    );
                }

                Any aScaleVal( ::comphelper::getNumberFormatDecimals( _rxNumberFormats, nFormatKey ) );
			    _rxControlModel->setPropertyValue( FM_PROP_DECIMAL_ACCURACY, aScaleVal );
		    }

            ////////////////////////////////////////////////////////////////////////
            // minimum and maximum of the control according to the type of the database field
            sal_Int32 nDataType = DataType::OTHER;
            OSL_VERIFY( _rxDatabaseField->getPropertyValue( FM_PROP_FIELDTYPE ) >>= nDataType );

            if  (   xModelPSI->hasPropertyByName( FM_PROP_VALUEMIN )
                &&  xModelPSI->hasPropertyByName( FM_PROP_VALUEMAX )
                )
            {
		        sal_Int32 nMinValue = -1000000000, nMaxValue = 1000000000;
		        switch ( nDataType )
		        {
			        case DataType::TINYINT	: nMinValue = 0; nMaxValue = 255; break;
			        case DataType::SMALLINT	: nMinValue = -32768; nMaxValue = 32767; break;
			        case DataType::INTEGER	: nMinValue = 0x80000000; nMaxValue = 0x7FFFFFFF; break;
				        // double and singles are ignored
		        }

                Any aValue;

                // both the minimum and the maximum value properties can be either Long or Double
		        Property aProperty = xModelPSI->getPropertyByName( FM_PROP_VALUEMIN );
		        if ( aProperty.Type.getTypeClass() == TypeClass_DOUBLE )
			        aValue <<= (double)nMinValue;
		        else if ( aProperty.Type.getTypeClass() == TypeClass_LONG )
			        aValue <<= (sal_Int32)nMinValue;
		        else
		        {
			        DBG_ERROR( "FormControlFactory::initializeFieldDependentProperties: unexpected property type (MinValue)!" );
		        }
		        _rxControlModel->setPropertyValue( FM_PROP_VALUEMIN, aValue );

                // both the minimum and the maximum value properties can be either Long or Double
		        aProperty = xModelPSI->getPropertyByName( FM_PROP_VALUEMAX );
		        if ( aProperty.Type.getTypeClass() == TypeClass_DOUBLE )
			        aValue <<= (double)nMaxValue;
		        else if ( aProperty.Type.getTypeClass() == TypeClass_LONG )
			        aValue <<= (sal_Int32)nMaxValue;
		        else
		        {
			        DBG_ERROR( "FormControlFactory::initializeFieldDependentProperties: unexpected property type (MaxValue)!" );
		        }
		        _rxControlModel->setPropertyValue( FM_PROP_VALUEMAX, aValue );
            }

            ////////////////////////////////////////////////////////////////////////
            // a check box can be tristate if and only if the column it is bound to is nullable
            sal_Int16 nClassId = FormComponentType::CONTROL;
            OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
            if ( nClassId == FormComponentType::CHECKBOX )
            {
		        sal_Int32 nNullable = ColumnValue::NULLABLE_UNKNOWN;
		        OSL_VERIFY( _rxDatabaseField->getPropertyValue( FM_PROP_ISNULLABLE ) >>= nNullable );
		        _rxControlModel->setPropertyValue( FM_PROP_TRISTATE, makeAny( sal_Bool( ColumnValue::NO_NULLS != nNullable ) ) );
            }
        }
        catch( const Exception& )
        {
        	DBG_UNHANDLED_EXCEPTION();
        }
    }

//........................................................................
} // namespace svxform
//........................................................................
