summaryrefslogtreecommitdiffstats
path: root/forms/source/xforms/datatypes.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'forms/source/xforms/datatypes.cxx')
-rw-r--r--forms/source/xforms/datatypes.cxx976
1 files changed, 976 insertions, 0 deletions
diff --git a/forms/source/xforms/datatypes.cxx b/forms/source/xforms/datatypes.cxx
new file mode 100644
index 000000000..d4578013c
--- /dev/null
+++ b/forms/source/xforms/datatypes.cxx
@@ -0,0 +1,976 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include "datatypes.hxx"
+#include "resourcehelper.hxx"
+#include <frm_strings.hxx>
+#include <property.hxx>
+#include <strings.hrc>
+#include "convert.hxx"
+
+#include <com/sun/star/xsd/DataTypeClass.hpp>
+#include <com/sun/star/xsd/WhiteSpaceTreatment.hpp>
+#include <tools/datetime.hxx>
+#include <rtl/math.hxx>
+#include <sal/log.hxx>
+
+
+namespace xforms
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::util::Date;
+ using ::com::sun::star::util::Time;
+ using ::com::sun::star::util::DateTime;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::beans::XPropertyChangeListener;
+ using ::com::sun::star::beans::XVetoableChangeListener;
+
+ using ::com::sun::star::beans::PropertyAttribute::BOUND;
+ using ::com::sun::star::beans::PropertyAttribute::READONLY;
+
+ using namespace ::com::sun::star::xsd;
+ using namespace ::frm;
+ U_NAMESPACE_USE
+
+ OXSDDataType::OXSDDataType( const OUString& _rName, sal_Int16 _nTypeClass )
+ :OXSDDataType_PBase( m_aBHelper )
+ ,m_bIsBasic( true )
+ ,m_nTypeClass( _nTypeClass )
+ ,m_sName( _rName )
+ ,m_nWST( WhiteSpaceTreatment::Preserve )
+ ,m_bPatternMatcherDirty( true )
+ {
+ }
+
+
+ OXSDDataType::~OXSDDataType()
+ {
+ }
+
+
+ void OXSDDataType::registerProperties()
+ {
+ registerProperty( PROPERTY_NAME, PROPERTY_ID_NAME, BOUND, &m_sName, cppu::UnoType<decltype(m_sName)>::get() );
+ registerProperty( PROPERTY_XSD_WHITESPACE, PROPERTY_ID_XSD_WHITESPACE, BOUND, &m_nWST, cppu::UnoType<cppu::UnoUnsignedShortType>::get() );
+ registerProperty( PROPERTY_XSD_PATTERN, PROPERTY_ID_XSD_PATTERN, BOUND, &m_sPattern, cppu::UnoType<decltype(m_sPattern)>::get() );
+
+ registerProperty( PROPERTY_XSD_IS_BASIC, PROPERTY_ID_XSD_IS_BASIC, READONLY, &m_bIsBasic, cppu::UnoType<decltype(m_bIsBasic)>::get() );
+ registerProperty( PROPERTY_XSD_TYPE_CLASS, PROPERTY_ID_XSD_TYPE_CLASS, READONLY, &m_nTypeClass, cppu::UnoType<decltype(m_nTypeClass)>::get() );
+ }
+
+
+ void OXSDDataType::initializeClone( const OXSDDataType& _rCloneSource )
+ {
+ m_bIsBasic = false;
+ m_nTypeClass = _rCloneSource.m_nTypeClass;
+ m_sPattern = _rCloneSource.m_sPattern;
+ m_nWST = _rCloneSource.m_nWST;
+ }
+
+
+ rtl::Reference<OXSDDataType> OXSDDataType::clone( const OUString& _rNewName ) const
+ {
+ rtl::Reference<OXSDDataType> pClone = createClone( _rNewName );
+ pClone->initializeClone( *this );
+ return pClone;
+ }
+
+
+ IMPLEMENT_FORWARD_XINTERFACE2( OXSDDataType, OXSDDataType_Base, ::comphelper::OPropertyContainer )
+
+
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2( OXSDDataType, OXSDDataType_Base, ::comphelper::OPropertyContainer )
+
+ OUString SAL_CALL OXSDDataType::getName( )
+ {
+ return m_sName;
+ }
+
+
+ void SAL_CALL OXSDDataType::setName( const OUString& aName )
+ {
+ // TODO: check the name for conflicts in the repository
+ setFastPropertyValue( PROPERTY_ID_NAME, Any(aName) );
+ SAL_WARN_IF( m_sName != aName, "forms.misc", "OXSDDataType::setName: inconsistency!" );
+ }
+
+
+ OUString SAL_CALL OXSDDataType::getPattern()
+ {
+ return m_sPattern;
+ }
+
+
+ void SAL_CALL OXSDDataType::setPattern( const OUString& _pattern )
+ {
+ setFastPropertyValue( PROPERTY_ID_XSD_PATTERN, Any(_pattern) );
+ SAL_WARN_IF( m_sPattern != _pattern, "forms.misc", "OXSDDataType::setPattern: inconsistency!" );
+ }
+
+
+ sal_Int16 SAL_CALL OXSDDataType::getWhiteSpaceTreatment()
+ {
+ return m_nWST;
+ }
+
+
+ void SAL_CALL OXSDDataType::setWhiteSpaceTreatment( sal_Int16 _whitespacetreatment )
+ {
+ setFastPropertyValue( PROPERTY_ID_XSD_WHITESPACE, Any(_whitespacetreatment) );
+ SAL_WARN_IF( m_nWST != _whitespacetreatment, "forms.misc", "OXSDDataType::setWhiteSpaceTreatment: inconsistency!" );
+ }
+
+
+ sal_Bool SAL_CALL OXSDDataType::getIsBasic()
+ {
+ return m_bIsBasic;
+ }
+
+
+ sal_Int16 SAL_CALL OXSDDataType::getTypeClass()
+ {
+ return m_nTypeClass;
+ }
+
+
+ sal_Bool OXSDDataType::validate( const OUString& sValue )
+ {
+ return bool(_validate( sValue ));
+ }
+
+
+ OUString OXSDDataType::explainInvalid( const OUString& sValue )
+ {
+ // get reason
+ TranslateId pReason = _validate( sValue );
+
+ // get resource and return localized string
+ return (!pReason)
+ ? OUString()
+ : getResource( pReason, sValue,
+ _explainInvalid( pReason ) );
+ }
+
+ OUString OXSDDataType::_explainInvalid(TranslateId rReason)
+ {
+ if ( RID_STR_XFORMS_PATTERN_DOESNT_MATCH == rReason )
+ {
+ OSL_ENSURE( !m_sPattern.isEmpty(), "OXSDDataType::_explainInvalid: how can this error occur without a regular expression?" );
+ return m_sPattern;
+ }
+ return OUString();
+ }
+
+ namespace
+ {
+ void lcl_initializePatternMatcher( ::std::unique_ptr< RegexMatcher >& _rpMatcher, const OUString& _rPattern )
+ {
+ UErrorCode nMatchStatus = U_ZERO_ERROR;
+ UnicodeString aIcuPattern( reinterpret_cast<const UChar *>(_rPattern.getStr()), _rPattern.getLength() );
+ _rpMatcher.reset( new RegexMatcher( aIcuPattern, 0, nMatchStatus ) );
+ OSL_ENSURE( U_SUCCESS( nMatchStatus ), "lcl_initializePatternMatcher: invalid pattern property!" );
+ // if asserts, then something changed our pattern without going to convertFastPropertyValue/checkPropertySanity
+ }
+
+ bool lcl_matchString( RegexMatcher& _rMatcher, const OUString& _rText )
+ {
+ UErrorCode nMatchStatus = U_ZERO_ERROR;
+ UnicodeString aInput( reinterpret_cast<const UChar *>(_rText.getStr()), _rText.getLength() );
+ _rMatcher.reset( aInput );
+ if ( _rMatcher.matches( nMatchStatus ) )
+ {
+ int32_t nStart = _rMatcher.start( nMatchStatus );
+ int32_t nEnd = _rMatcher.end ( nMatchStatus );
+ if ( ( nStart == 0 ) && ( nEnd == _rText.getLength() ) )
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ TranslateId OXSDDataType::_validate( const OUString& _rValue )
+ {
+ // care for the regular expression
+ if ( !m_sPattern.isEmpty() )
+ {
+ // ensure our pattern matcher is up to date
+ if ( m_bPatternMatcherDirty )
+ {
+ lcl_initializePatternMatcher( m_pPatternMatcher, m_sPattern );
+ m_bPatternMatcherDirty = false;
+ }
+
+ // let it match the string
+ if (!lcl_matchString(*m_pPatternMatcher, _rValue))
+ return RID_STR_XFORMS_PATTERN_DOESNT_MATCH;
+ }
+
+ return {};
+ }
+
+
+ sal_Bool OXSDDataType::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue )
+ {
+ // let the base class do the conversion
+ if ( !OXSDDataType_PBase::convertFastPropertyValue( _rConvertedValue, _rOldValue, _nHandle, _rValue ) )
+ return false;
+
+ // sanity checks
+ OUString sErrorMessage;
+ if ( !checkPropertySanity( _nHandle, _rConvertedValue, sErrorMessage ) )
+ {
+ IllegalArgumentException aException;
+ aException.Message = sErrorMessage;
+ aException.Context = *this;
+ throw aException;
+ }
+
+ return true;
+ }
+
+
+ void SAL_CALL OXSDDataType::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue )
+ {
+ OXSDDataType_PBase::setFastPropertyValue_NoBroadcast( _nHandle, _rValue );
+ if ( _nHandle == PROPERTY_ID_XSD_PATTERN )
+ m_bPatternMatcherDirty = true;
+ }
+
+
+ bool OXSDDataType::checkPropertySanity( sal_Int32 _nHandle, const css::uno::Any& _rNewValue, OUString& _rErrorMessage )
+ {
+ if ( _nHandle == PROPERTY_ID_XSD_PATTERN )
+ {
+ OUString sPattern;
+ OSL_VERIFY( _rNewValue >>= sPattern );
+
+ UnicodeString aIcuPattern( reinterpret_cast<const UChar *>(sPattern.getStr()), sPattern.getLength() );
+ UErrorCode nMatchStatus = U_ZERO_ERROR;
+ RegexMatcher aMatcher( aIcuPattern, 0, nMatchStatus );
+ if ( U_FAILURE( nMatchStatus ) )
+ {
+ _rErrorMessage = "This is no valid pattern.";
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ void SAL_CALL OXSDDataType::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
+ {
+ OXSDDataType_PBase::setPropertyValue( aPropertyName, aValue );
+ }
+
+
+ Any SAL_CALL OXSDDataType::getPropertyValue( const OUString& PropertyName )
+ {
+ return OXSDDataType_PBase::getPropertyValue( PropertyName );
+ }
+
+
+ void SAL_CALL OXSDDataType::addPropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener )
+ {
+ OXSDDataType_PBase::addPropertyChangeListener( aPropertyName, xListener );
+ }
+
+
+ void SAL_CALL OXSDDataType::removePropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& aListener )
+ {
+ OXSDDataType_PBase::removePropertyChangeListener( aPropertyName, aListener );
+ }
+
+
+ void SAL_CALL OXSDDataType::addVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener )
+ {
+ OXSDDataType_PBase::addVetoableChangeListener( PropertyName, aListener );
+ }
+
+
+ void SAL_CALL OXSDDataType::removeVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener )
+ {
+ OXSDDataType_PBase::removeVetoableChangeListener( PropertyName, aListener );
+ }
+
+ OValueLimitedType_Base::OValueLimitedType_Base( const OUString& _rName, sal_Int16 _nTypeClass )
+ :OXSDDataType( _rName, _nTypeClass )
+ ,m_fCachedMaxInclusive( 0 )
+ ,m_fCachedMaxExclusive( 0 )
+ ,m_fCachedMinInclusive( 0 )
+ ,m_fCachedMinExclusive( 0 )
+ {
+ }
+
+
+ void OValueLimitedType_Base::initializeClone( const OXSDDataType& _rCloneSource )
+ {
+ OXSDDataType::initializeClone( _rCloneSource );
+ initializeTypedClone( static_cast< const OValueLimitedType_Base& >( _rCloneSource ) );
+ }
+
+
+ void OValueLimitedType_Base::initializeTypedClone( const OValueLimitedType_Base& _rCloneSource )
+ {
+ m_aMaxInclusive = _rCloneSource.m_aMaxInclusive;
+ m_aMaxExclusive = _rCloneSource.m_aMaxExclusive;
+ m_aMinInclusive = _rCloneSource.m_aMinInclusive;
+ m_aMinExclusive = _rCloneSource.m_aMinExclusive;
+ m_fCachedMaxInclusive = _rCloneSource.m_fCachedMaxInclusive;
+ m_fCachedMaxExclusive = _rCloneSource.m_fCachedMaxExclusive;
+ m_fCachedMinInclusive = _rCloneSource.m_fCachedMinInclusive;
+ m_fCachedMinExclusive = _rCloneSource.m_fCachedMinExclusive;
+ }
+
+
+ void SAL_CALL OValueLimitedType_Base::setFastPropertyValue_NoBroadcast(
+ sal_Int32 _nHandle, const css::uno::Any& _rValue )
+ {
+ OXSDDataType::setFastPropertyValue_NoBroadcast( _nHandle, _rValue );
+
+ // if one of our limit properties has been set, translate it into a double
+ // value, for later efficient validation
+ switch ( _nHandle )
+ {
+ case PROPERTY_ID_XSD_MAX_INCLUSIVE_INT:
+ case PROPERTY_ID_XSD_MAX_INCLUSIVE_DOUBLE:
+ case PROPERTY_ID_XSD_MAX_INCLUSIVE_DATE:
+ case PROPERTY_ID_XSD_MAX_INCLUSIVE_TIME:
+ case PROPERTY_ID_XSD_MAX_INCLUSIVE_DATE_TIME:
+ if ( m_aMaxInclusive.hasValue() )
+ normalizeValue( m_aMaxInclusive, m_fCachedMaxInclusive );
+ else
+ m_fCachedMaxInclusive = 0;
+ break;
+ case PROPERTY_ID_XSD_MAX_EXCLUSIVE_INT:
+ case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DOUBLE:
+ case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DATE:
+ case PROPERTY_ID_XSD_MAX_EXCLUSIVE_TIME:
+ case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DATE_TIME:
+ if ( m_aMaxExclusive.hasValue() )
+ normalizeValue( m_aMaxExclusive, m_fCachedMaxExclusive );
+ else
+ m_fCachedMaxExclusive = 0;
+ break;
+ case PROPERTY_ID_XSD_MIN_INCLUSIVE_INT:
+ case PROPERTY_ID_XSD_MIN_INCLUSIVE_DOUBLE:
+ case PROPERTY_ID_XSD_MIN_INCLUSIVE_DATE:
+ case PROPERTY_ID_XSD_MIN_INCLUSIVE_TIME:
+ case PROPERTY_ID_XSD_MIN_INCLUSIVE_DATE_TIME:
+ if ( m_aMinInclusive.hasValue() )
+ normalizeValue( m_aMinInclusive, m_fCachedMinInclusive );
+ else
+ m_fCachedMinInclusive = 0;
+ break;
+ case PROPERTY_ID_XSD_MIN_EXCLUSIVE_INT:
+ case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DOUBLE:
+ case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DATE:
+ case PROPERTY_ID_XSD_MIN_EXCLUSIVE_TIME:
+ case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DATE_TIME:
+ if ( m_aMinExclusive.hasValue() )
+ normalizeValue( m_aMinExclusive, m_fCachedMinExclusive );
+ else
+ m_fCachedMinExclusive = 0;
+ break;
+ }
+ }
+
+
+ bool OValueLimitedType_Base::_getValue( const OUString& rValue, double& fValue )
+ {
+ // convert to double
+ rtl_math_ConversionStatus eStatus;
+ sal_Int32 nEnd;
+ double f = ::rtl::math::stringToDouble(
+ rValue, '.', u'\0', &eStatus, &nEnd );
+
+ // error checking...
+ bool bReturn = false;
+ if( eStatus == rtl_math_ConversionStatus_Ok
+ && nEnd == rValue.getLength() )
+ {
+ bReturn = true;
+ fValue = f;
+ }
+ return bReturn;
+ }
+
+ TranslateId OValueLimitedType_Base::_validate( const OUString& rValue )
+ {
+ TranslateId pReason = OXSDDataType::_validate( rValue );
+ if (!pReason)
+ {
+
+ // convert value and check format
+ double f;
+ if( ! _getValue( rValue, f ) )
+ pReason = RID_STR_XFORMS_VALUE_IS_NOT_A;
+
+ // check range
+ else if( ( m_aMaxInclusive.hasValue() ) && f > m_fCachedMaxInclusive )
+ pReason = RID_STR_XFORMS_VALUE_MAX_INCL;
+ else if( ( m_aMaxExclusive.hasValue() ) && f >= m_fCachedMaxExclusive )
+ pReason = RID_STR_XFORMS_VALUE_MAX_EXCL;
+ else if( ( m_aMinInclusive.hasValue() ) && f < m_fCachedMinInclusive )
+ pReason = RID_STR_XFORMS_VALUE_MIN_INCL;
+ else if( ( m_aMinExclusive.hasValue() ) && f <= m_fCachedMinExclusive )
+ pReason = RID_STR_XFORMS_VALUE_MIN_EXCL;
+ }
+ return pReason;
+ }
+
+ OUString OValueLimitedType_Base::_explainInvalid(TranslateId rReason)
+ {
+ OUStringBuffer sInfo;
+ if (rReason == RID_STR_XFORMS_VALUE_IS_NOT_A)
+ sInfo.append( getName() );
+ else if (rReason == RID_STR_XFORMS_VALUE_MAX_INCL)
+ sInfo.append( typedValueAsHumanReadableString( m_aMaxInclusive ) );
+ else if (rReason == RID_STR_XFORMS_VALUE_MAX_EXCL)
+ sInfo.append( typedValueAsHumanReadableString( m_aMaxExclusive ) );
+ else if (rReason == RID_STR_XFORMS_VALUE_MIN_INCL)
+ sInfo.append( typedValueAsHumanReadableString( m_aMinInclusive ) );
+ else if (rReason == RID_STR_XFORMS_VALUE_MIN_EXCL)
+ sInfo.append( typedValueAsHumanReadableString( m_aMinExclusive ) );
+ return sInfo.makeStringAndClear();
+ }
+
+ OStringType::OStringType( const OUString& _rName, sal_Int16 _nTypeClass )
+ :OStringType_Base( _rName, _nTypeClass )
+ {
+ }
+
+
+ void OStringType::registerProperties()
+ {
+ OStringType_Base::registerProperties();
+
+ registerMayBeVoidProperty( PROPERTY_XSD_LENGTH, PROPERTY_ID_XSD_LENGTH, css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEVOID,
+ &m_aLength, cppu::UnoType<sal_Int32>::get() );
+
+ registerMayBeVoidProperty( PROPERTY_XSD_MIN_LENGTH, PROPERTY_ID_XSD_MIN_LENGTH, css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEVOID,
+ &m_aMinLength, cppu::UnoType<sal_Int32>::get() );
+
+ registerMayBeVoidProperty( PROPERTY_XSD_MAX_LENGTH, PROPERTY_ID_XSD_MAX_LENGTH, css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEVOID,
+ &m_aMaxLength, cppu::UnoType<sal_Int32>::get() );
+ }
+
+
+ rtl::Reference<OXSDDataType> OStringType::createClone( const OUString& _rName ) const
+ {
+ return new OStringType( _rName, getTypeClass() );
+ }
+ void OStringType::initializeClone( const OXSDDataType& _rCloneSource )
+ {
+ OStringType_Base::initializeClone( _rCloneSource );
+ initializeTypedClone( static_cast< const OStringType& >( _rCloneSource ) );
+ }
+
+
+
+ void OStringType::initializeTypedClone( const OStringType& _rCloneSource )
+ {
+ m_aLength = _rCloneSource.m_aLength;
+ m_aMinLength = _rCloneSource.m_aMinLength;
+ m_aMaxLength = _rCloneSource.m_aMaxLength;
+ }
+
+
+ bool OStringType::checkPropertySanity( sal_Int32 _nHandle, const Any& _rNewValue, OUString& _rErrorMessage )
+ {
+ // let the base class do the conversion
+ if ( !OStringType_Base::checkPropertySanity( _nHandle, _rNewValue, _rErrorMessage ) )
+ return false;
+
+ _rErrorMessage.clear();
+ switch ( _nHandle )
+ {
+ case PROPERTY_ID_XSD_LENGTH:
+ case PROPERTY_ID_XSD_MIN_LENGTH:
+ case PROPERTY_ID_XSD_MAX_LENGTH:
+ {
+ sal_Int32 nValue( 0 );
+ OSL_VERIFY( _rNewValue >>= nValue );
+ if ( nValue <= 0 )
+ _rErrorMessage = "Length limits must denote positive integer values.";
+ // TODO/eforms: localize the error message
+ }
+ break;
+ }
+
+ return _rErrorMessage.isEmpty();
+ }
+
+
+ TranslateId OStringType::_validate( const OUString& rValue )
+ {
+ // check regexp, whitespace etc. in parent class
+ TranslateId pReason = OStringType_Base::_validate( rValue );
+
+ if (!pReason)
+ {
+ // check string constraints
+ sal_Int32 nLength = rValue.getLength();
+ sal_Int32 nLimit = 0;
+ if ( m_aLength >>= nLimit )
+ {
+ if ( nLimit != nLength )
+ pReason = RID_STR_XFORMS_VALUE_LENGTH;
+ }
+ else
+ {
+ if ( ( m_aMaxLength >>= nLimit ) && ( nLength > nLimit ) )
+ pReason = RID_STR_XFORMS_VALUE_MAX_LENGTH;
+ else if ( ( m_aMinLength >>= nLimit ) && ( nLength < nLimit ) )
+ pReason = RID_STR_XFORMS_VALUE_MIN_LENGTH;
+ }
+ }
+ return pReason;
+ }
+
+ OUString OStringType::_explainInvalid(TranslateId rReason)
+ {
+ sal_Int32 nValue = 0;
+ OUStringBuffer sInfo;
+ if (rReason == RID_STR_XFORMS_VALUE_LENGTH)
+ {
+ if( m_aLength >>= nValue )
+ sInfo.append( nValue );
+ }
+ else if (rReason == RID_STR_XFORMS_VALUE_MAX_LENGTH)
+ {
+ if( m_aMaxLength >>= nValue )
+ sInfo.append( nValue );
+ }
+ else if (rReason == RID_STR_XFORMS_VALUE_MIN_LENGTH)
+ {
+ if( m_aMinLength >>= nValue )
+ sInfo.append( nValue );
+ }
+ else if (rReason)
+ {
+ sInfo.append(OStringType_Base::_explainInvalid(rReason));
+ }
+ return sInfo.makeStringAndClear();
+ }
+
+ OBooleanType::OBooleanType( const OUString& _rName )
+ :OBooleanType_Base( _rName, DataTypeClass::BOOLEAN )
+ {
+ }
+
+ rtl::Reference<OXSDDataType> OBooleanType::createClone( const OUString& _rName ) const
+ {
+ return new OBooleanType( _rName );
+ }
+
+ void OBooleanType::initializeClone( const OXSDDataType& _rCloneSource )
+ {
+ OBooleanType_Base::initializeClone( _rCloneSource );
+ }
+
+ TranslateId OBooleanType::_validate( const OUString& sValue )
+ {
+ TranslateId pInvalidityReason = OBooleanType_Base::_validate( sValue );
+ if ( pInvalidityReason )
+ return pInvalidityReason;
+
+ bool bValid = sValue == "0" || sValue == "1" || sValue == "true" || sValue == "false";
+ return bValid ? TranslateId() : RID_STR_XFORMS_INVALID_VALUE;
+ }
+
+ OUString OBooleanType::_explainInvalid(TranslateId rReason)
+ {
+ return !rReason ? OUString() : getName();
+ }
+
+ ODecimalType::ODecimalType( const OUString& _rName, sal_Int16 _nTypeClass )
+ :ODecimalType_Base( _rName, _nTypeClass )
+ {
+ }
+
+ rtl::Reference<OXSDDataType> ODecimalType::createClone( const OUString& _rName ) const
+ {
+ return new ODecimalType( _rName, getTypeClass() );
+ }
+ void ODecimalType::initializeClone( const OXSDDataType& _rCloneSource )
+ {
+ ODecimalType_Base::initializeClone( _rCloneSource );
+ initializeTypedClone( static_cast< const ODecimalType& >( _rCloneSource ) );
+ }
+
+ void ODecimalType::initializeTypedClone( const ODecimalType& _rCloneSource )
+ {
+ m_aTotalDigits = _rCloneSource.m_aTotalDigits;
+ m_aFractionDigits = _rCloneSource.m_aFractionDigits;
+ }
+
+
+ void ODecimalType::registerProperties()
+ {
+ ODecimalType_Base::registerProperties();
+
+ registerMayBeVoidProperty( PROPERTY_XSD_TOTAL_DIGITS, PROPERTY_ID_XSD_TOTAL_DIGITS, css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEVOID,
+ &m_aTotalDigits, cppu::UnoType<sal_Int32>::get() );
+
+ registerMayBeVoidProperty( PROPERTY_XSD_FRACTION_DIGITS, PROPERTY_ID_XSD_FRACTION_DIGITS, css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEVOID,
+ &m_aFractionDigits, cppu::UnoType<sal_Int32>::get() );
+ }
+
+
+ // validate decimals and return code for which facets failed
+ // to be used by: ODecimalType::validate and ODecimalType::explainInvalid
+ TranslateId ODecimalType::_validate( const OUString& rValue )
+ {
+ TranslateId pReason = ODecimalType_Base::_validate( rValue );
+
+ // check digits (if no other cause is available so far)
+ if (!pReason)
+ {
+ sal_Int32 nLength = rValue.getLength();
+ sal_Int32 n = 0;
+ sal_Int32 nTotalDigits = 0;
+ sal_Int32 nFractionDigits = 0;
+ const sal_Unicode* pValue = rValue.getStr();
+ for( ; n < nLength && pValue[n] != '.'; n++ )
+ if( pValue[n] >= '0'
+ && pValue[n] <= '9')
+ nTotalDigits++;
+ for( ; n < nLength; n++ )
+ if( pValue[n] >= '0'
+ && pValue[n] <= '9')
+ nFractionDigits++;
+ nTotalDigits += nFractionDigits;
+
+ sal_Int32 nValue = 0;
+ if( ( m_aTotalDigits >>= nValue ) && nTotalDigits > nValue )
+ pReason = RID_STR_XFORMS_VALUE_TOTAL_DIGITS;
+ else if( ( m_aFractionDigits >>= nValue ) &&
+ ( nFractionDigits > nValue ) )
+ pReason = RID_STR_XFORMS_VALUE_FRACTION_DIGITS;
+ }
+
+ return pReason;
+ }
+
+ OUString ODecimalType::_explainInvalid(TranslateId rReason)
+ {
+ sal_Int32 nValue = 0;
+ OUStringBuffer sInfo;
+ if (rReason == RID_STR_XFORMS_VALUE_TOTAL_DIGITS)
+ {
+ if( m_aTotalDigits >>= nValue )
+ sInfo.append( nValue );
+ }
+ else if (rReason == RID_STR_XFORMS_VALUE_FRACTION_DIGITS)
+ {
+ if( m_aFractionDigits >>= nValue )
+ sInfo.append( nValue );
+ }
+ else
+ {
+ sInfo.append(ODecimalType_Base::_explainInvalid(rReason));
+ }
+ return sInfo.makeStringAndClear();
+ }
+
+ OUString ODecimalType::typedValueAsHumanReadableString( const Any& _rValue ) const
+ {
+ double fValue( 0 );
+ normalizeValue( _rValue, fValue );
+ return OUString::number( fValue );
+ }
+
+
+ void ODecimalType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
+ {
+ OSL_VERIFY( _rValue >>= _rDoubleValue );
+ }
+
+
+ ODateType::ODateType(const OUString& _rName)
+ :ODateType_Base(_rName, DataTypeClass::DATE)
+ {
+ }
+ rtl::Reference<OXSDDataType> ODateType::createClone(const OUString& _rName) const
+ {
+ return new ODateType(_rName);
+ }
+ void ODateType::initializeClone( const OXSDDataType& _rCloneSource )
+ {
+ ODateType_Base::initializeClone(_rCloneSource);
+ initializeTypedClone(static_cast< const ODateType& >(_rCloneSource));
+ }
+
+ TranslateId ODateType::_validate( const OUString& _rValue )
+ {
+ return ODateType_Base::_validate( _rValue );
+ }
+
+ bool ODateType::_getValue( const OUString& value, double& fValue )
+ {
+ Any aTypeValue = Convert::get().toAny( value, getCppuType() );
+
+ Date aValue;
+ if ( !( aTypeValue >>= aValue ) )
+ return false;
+
+ ::Date aToolsDate( aValue.Day, aValue.Month, aValue.Year );
+ fValue = aToolsDate.GetDate();
+ return true;
+ }
+
+
+ OUString ODateType::typedValueAsHumanReadableString( const Any& _rValue ) const
+ {
+ OSL_PRECOND( _rValue.getValueType().equals( getCppuType() ), "ODateType::typedValueAsHumanReadableString: unexpected type" );
+ return Convert::get().toXSD( _rValue );
+ }
+
+
+ void ODateType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
+ {
+ Date aValue;
+ OSL_VERIFY( _rValue >>= aValue );
+ ::Date aToolsDate( aValue.Day, aValue.Month, aValue.Year );
+ _rDoubleValue = aToolsDate.GetDate();
+ }
+
+
+ OTimeType::OTimeType(const OUString& _rName)
+ :OTimeType_Base(_rName, DataTypeClass::TIME)
+ {
+ }
+ rtl::Reference<OXSDDataType> OTimeType::createClone(const OUString& _rName) const
+ {
+ return new OTimeType(_rName);
+ }
+ void OTimeType::initializeClone( const OXSDDataType& _rCloneSource )
+ {
+ OTimeType_Base::initializeClone(_rCloneSource);
+ initializeTypedClone(static_cast< const OTimeType& >(_rCloneSource));
+ }
+
+ TranslateId OTimeType::_validate( const OUString& _rValue )
+ {
+ return OTimeType_Base::_validate( _rValue );
+ }
+
+ bool OTimeType::_getValue( const OUString& value, double& fValue )
+ {
+ Any aTypedValue = Convert::get().toAny( value, getCppuType() );
+
+ css::util::Time aValue;
+ if ( !( aTypedValue >>= aValue ) )
+ return false;
+
+ ::tools::Time aToolsTime( aValue );
+ // no loss/rounding; IEEE 754 double-precision floating-point
+ // has a mantissa of 53 bits; we need at the very most 50 bits:
+ // format of aToolsTime.GetTime() is (in decimal) hhmmssnnnnnnnnn
+ // and 999999999999999 = 0x38D7EA4C67FFF
+ // in reality I doubt we need (much) more than
+ // 240000000000000 = 0x0DA475ABF0000
+ // that is 48 bits
+ fValue = aToolsTime.GetTime();
+ return true;
+ }
+
+
+ OUString OTimeType::typedValueAsHumanReadableString( const Any& _rValue ) const
+ {
+ OSL_PRECOND( _rValue.getValueType().equals( getCppuType() ), "OTimeType::typedValueAsHumanReadableString: unexpected type" );
+ return Convert::get().toXSD( _rValue );
+ }
+
+
+ void OTimeType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
+ {
+ css::util::Time aValue;
+ OSL_VERIFY( _rValue >>= aValue );
+ ::tools::Time aToolsTime( aValue );
+ _rDoubleValue = aToolsTime.GetTime();
+ }
+
+
+ ODateTimeType::ODateTimeType(const OUString& _rName)
+ :ODateTimeType_Base(_rName, DataTypeClass::DATETIME)
+ {
+ }
+ rtl::Reference<OXSDDataType> ODateTimeType::createClone(const OUString& _rName) const
+ {
+ return new ODateTimeType(_rName);
+ }
+ void ODateTimeType::initializeClone( const OXSDDataType& _rCloneSource )
+ {
+ ODateTimeType_Base::initializeClone(_rCloneSource);
+ initializeTypedClone(static_cast< const ODateTimeType& >(_rCloneSource));
+ }
+
+ TranslateId ODateTimeType::_validate( const OUString& _rValue )
+ {
+ return ODateTimeType_Base::_validate( _rValue );
+ }
+
+ namespace
+ {
+ double lcl_normalizeDateTime( const DateTime& _rValue )
+ {
+ ::DateTime aToolsValue(_rValue);
+
+ double fValue = 0;
+ // days since 1.1.1900 (which is relatively arbitrary but fixed date)
+ fValue += ::Date( aToolsValue ) - ::Date( 1, 1, 1900 );
+ // time
+ fValue += aToolsValue.GetTimeInDays();
+ return fValue;
+ }
+ }
+
+
+ bool ODateTimeType::_getValue( const OUString& value, double& fValue )
+ {
+ Any aTypedValue = Convert::get().toAny( value, getCppuType() );
+
+ DateTime aValue;
+ if ( !( aTypedValue >>= aValue ) )
+ return false;
+
+ fValue = lcl_normalizeDateTime( aValue );
+ return true;
+ }
+
+
+ OUString ODateTimeType::typedValueAsHumanReadableString( const Any& _rValue ) const
+ {
+ OSL_PRECOND( _rValue.getValueType().equals( getCppuType() ), "OTimeType::typedValueAsHumanReadableString: unexpected type" );
+ OUString sString = Convert::get().toXSD( _rValue );
+
+ // ISO 8601 notation has a "T" to separate between date and time. Our only concession
+ // to the "human readable" in the method name is to replace this T with a whitespace.
+ OSL_ENSURE( sString.indexOf( 'T' ) != -1, "ODateTimeType::typedValueAsHumanReadableString: hmm - no ISO notation?" );
+ return sString.replace( 'T', ' ' );
+ }
+
+
+ void ODateTimeType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
+ {
+ DateTime aValue;
+ OSL_VERIFY( _rValue >>= aValue );
+ _rDoubleValue = lcl_normalizeDateTime( aValue );
+ }
+
+ OShortIntegerType::OShortIntegerType( const OUString& _rName, sal_Int16 _nTypeClass )
+ :OShortIntegerType_Base( _rName, _nTypeClass )
+ {
+ }
+
+ rtl::Reference<OXSDDataType> OShortIntegerType::createClone( const OUString& _rName ) const
+ {
+ return new OShortIntegerType( _rName, getTypeClass() );
+ }
+ void OShortIntegerType::initializeClone( const OXSDDataType& _rCloneSource )
+ {
+ OShortIntegerType_Base::initializeClone( _rCloneSource );
+ initializeTypedClone( static_cast< const OShortIntegerType& >( _rCloneSource ) );
+ }
+
+ bool OShortIntegerType::_getValue( const OUString& value, double& fValue )
+ {
+ fValue = static_cast<double>(static_cast<sal_Int16>(value.toInt32()));
+ // TODO/eforms
+ // this does not care for values which do not fit into a sal_Int16, but simply
+ // cuts them down. A better implementation here should probably return <FALSE/>
+ // for those values.
+ // Else, we may have a situation where the UI claims an input to be valid
+ // (say "12345678"), while internally, and at submission time, this is cut to
+ // some smaller value.
+
+ // Additionally, this of course does not care for strings which are no numbers...
+ return true;
+ }
+
+
+ OUString OShortIntegerType::typedValueAsHumanReadableString( const Any& _rValue ) const
+ {
+ sal_Int16 nValue( 0 );
+ OSL_VERIFY( _rValue >>= nValue );
+ return OUString::number( nValue );
+ }
+
+
+ void OShortIntegerType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
+ {
+ sal_Int16 nValue( 0 );
+ OSL_VERIFY( _rValue >>= nValue );
+ _rDoubleValue = nValue;
+ }
+
+
+template< typename CONCRETE_DATA_TYPE_IMPL, typename SUPERCLASS >
+ODerivedDataType< CONCRETE_DATA_TYPE_IMPL, SUPERCLASS >::ODerivedDataType( const OUString& _rName, sal_Int16 _nTypeClass )
+ :SUPERCLASS( _rName, _nTypeClass )
+ ,m_bPropertiesRegistered( false )
+{
+}
+
+
+template< typename CONCRETE_DATA_TYPE_IMPL, typename SUPERCLASS >
+::cppu::IPropertyArrayHelper* ODerivedDataType< CONCRETE_DATA_TYPE_IMPL, SUPERCLASS >::createArrayHelper( ) const
+{
+ css::uno::Sequence< css::beans::Property > aProps;
+ ODerivedDataType< CONCRETE_DATA_TYPE_IMPL, SUPERCLASS >::describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper( aProps );
+}
+
+
+template< typename CONCRETE_DATA_TYPE_IMPL, typename SUPERCLASS >
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL ODerivedDataType< CONCRETE_DATA_TYPE_IMPL, SUPERCLASS >::getPropertySetInfo()
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() );
+}
+
+
+template< typename CONCRETE_DATA_TYPE_IMPL, typename SUPERCLASS >
+::cppu::IPropertyArrayHelper& SAL_CALL ODerivedDataType< CONCRETE_DATA_TYPE_IMPL, SUPERCLASS >::getInfoHelper()
+{
+ if ( !m_bPropertiesRegistered )
+ {
+ this->registerProperties();
+ m_bPropertiesRegistered = true;
+ }
+
+ return *ODerivedDataType< CONCRETE_DATA_TYPE_IMPL, SUPERCLASS >::getArrayHelper();
+}
+
+
+template< typename VALUE_TYPE >
+OValueLimitedType< VALUE_TYPE >::OValueLimitedType( const OUString& _rName, sal_Int16 _nTypeClass )
+ :OValueLimitedType_Base( _rName, _nTypeClass )
+{
+}
+
+} // namespace xforms
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */