blob: fe539925516846f894f917b0af0dd9bbca51ddeb [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_forms.hxx"
#include "datatypes.hxx"
#include "resourcehelper.hxx"
#ifndef _FRM_PROPERTY_HRC_
#include "property.hrc"
#endif
#include "convert.hxx"
/** === begin UNO includes === **/
#include <com/sun/star/xsd/WhiteSpaceTreatment.hpp>
/** === end UNO includes === **/
#include <tools/debug.hxx>
#include <tools/datetime.hxx>
#include <rtl/math.hxx>
//........................................................................
namespace xforms
{
//........................................................................
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::RuntimeException;
using ::com::sun::star::uno::Any;
using ::com::sun::star::uno::makeAny;
using ::com::sun::star::uno::Type;
using ::com::sun::star::uno::Sequence;
using ::com::sun::star::uno::Exception;
using ::com::sun::star::util::VetoException;
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::lang::WrappedTargetException;
using ::com::sun::star::beans::UnknownPropertyException;
using ::com::sun::star::beans::PropertyVetoException;
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::OXSDDataType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass )
:OXSDDataType_PBase( m_aBHelper )
,m_bIsBasic( sal_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, ::getCppuType( &m_sName ) );
registerProperty( PROPERTY_XSD_WHITESPACE, PROPERTY_ID_XSD_WHITESPACE, BOUND, &m_nWST, ::getCppuType( &m_nWST ) );
registerProperty( PROPERTY_XSD_PATTERN, PROPERTY_ID_XSD_PATTERN, BOUND, &m_sPattern, ::getCppuType( &m_sPattern ) );
registerProperty( PROPERTY_XSD_IS_BASIC, PROPERTY_ID_XSD_IS_BASIC, READONLY, &m_bIsBasic, ::getCppuType( &m_bIsBasic ) );
registerProperty( PROPERTY_XSD_TYPE_CLASS, PROPERTY_ID_XSD_TYPE_CLASS, READONLY, &m_nTypeClass, ::getCppuType( &m_nTypeClass ) );
}
//--------------------------------------------------------------------
void OXSDDataType::initializeClone( const OXSDDataType& _rCloneSource )
{
m_bIsBasic = sal_False;
m_nTypeClass = _rCloneSource.m_nTypeClass;
m_sPattern = _rCloneSource.m_sPattern;
m_nWST = _rCloneSource.m_nWST;
}
//--------------------------------------------------------------------
OXSDDataType* OXSDDataType::clone( const ::rtl::OUString& _rNewName ) const
{
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 )
#define SET_PROPERTY( propertyid, value, member ) \
setFastPropertyValue( PROPERTY_ID_##propertyid, makeAny( value ) ); \
OSL_POSTCOND( member == value, "OXSDDataType::setFoo: inconsistency!" );
//--------------------------------------------------------------------
::rtl::OUString SAL_CALL OXSDDataType::getName( ) throw (RuntimeException)
{
return m_sName;
}
//--------------------------------------------------------------------
void SAL_CALL OXSDDataType::setName( const ::rtl::OUString& aName ) throw (RuntimeException, VetoException)
{
// TODO: check the name for conflicts in the repository
SET_PROPERTY( NAME, aName, m_sName );
}
//--------------------------------------------------------------------
::rtl::OUString SAL_CALL OXSDDataType::getPattern() throw (RuntimeException)
{
return m_sPattern;
}
//--------------------------------------------------------------------
void SAL_CALL OXSDDataType::setPattern( const ::rtl::OUString& _pattern ) throw (RuntimeException)
{
SET_PROPERTY( XSD_PATTERN, _pattern, m_sPattern );
}
//--------------------------------------------------------------------
sal_Int16 SAL_CALL OXSDDataType::getWhiteSpaceTreatment() throw (RuntimeException)
{
return m_nWST;
}
//--------------------------------------------------------------------
void SAL_CALL OXSDDataType::setWhiteSpaceTreatment( sal_Int16 _whitespacetreatment ) throw (RuntimeException, IllegalArgumentException)
{
SET_PROPERTY( XSD_WHITESPACE, _whitespacetreatment, m_nWST );
}
//--------------------------------------------------------------------
sal_Bool SAL_CALL OXSDDataType::getIsBasic() throw (RuntimeException)
{
return m_bIsBasic;
}
//--------------------------------------------------------------------
sal_Int16 SAL_CALL OXSDDataType::getTypeClass() throw (RuntimeException)
{
return m_nTypeClass;
}
//--------------------------------------------------------------------
sal_Bool OXSDDataType::validate( const ::rtl::OUString& sValue ) throw( RuntimeException )
{
return ( _validate( sValue ) == 0 );
}
//--------------------------------------------------------------------
::rtl::OUString OXSDDataType::explainInvalid( const ::rtl::OUString& sValue ) throw( RuntimeException )
{
// get reason
sal_uInt16 nReason = _validate( sValue );
// get resource and return localized string
return ( nReason == 0 )
? ::rtl::OUString()
: getResource( nReason, sValue,
_explainInvalid( nReason ) );
}
//--------------------------------------------------------------------
::rtl::OUString OXSDDataType::_explainInvalid( sal_uInt16 nReason )
{
if ( RID_STR_XFORMS_PATTERN_DOESNT_MATCH == nReason )
{
OSL_ENSURE( m_sPattern.getLength(), "OXSDDataType::_explainInvalid: how can this error occur without a regular expression?" );
return m_sPattern;
}
return ::rtl::OUString();
}
//--------------------------------------------------------------------
namespace
{
static void lcl_initializePatternMatcher( ::std::auto_ptr< RegexMatcher >& _rpMatcher, const ::rtl::OUString& _rPattern )
{
UErrorCode nMatchStatus = U_ZERO_ERROR;
UnicodeString aIcuPattern( reinterpret_cast<const UChar *>(_rPattern.getStr()), _rPattern.getLength() ); // UChar != sal_Unicode in MinGW
_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
}
static bool lcl_matchString( RegexMatcher& _rMatcher, const ::rtl::OUString& _rText )
{
UErrorCode nMatchStatus = U_ZERO_ERROR;
UnicodeString aInput( reinterpret_cast<const UChar *>(_rText.getStr()), _rText.getLength() ); // UChar != sal_Unicode in MinGW
_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;
}
}
//--------------------------------------------------------------------
sal_uInt16 OXSDDataType::_validate( const ::rtl::OUString& _rValue )
{
// care for the whitespaces
::rtl::OUString sConverted = Convert::convertWhitespace( _rValue, m_nWST );
// care for the regular expression
if ( m_sPattern.getLength() )
{
// 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.get(), _rValue ) )
return RID_STR_XFORMS_PATTERN_DOESNT_MATCH;
}
return 0;
}
//--------------------------------------------------------------------
sal_Bool OXSDDataType::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) throw(IllegalArgumentException)
{
// let the base class do the conversion
if ( !OXSDDataType_PBase::convertFastPropertyValue( _rConvertedValue, _rOldValue, _nHandle, _rValue ) )
return sal_False;
// sanity checks
::rtl::OUString sErrorMessage;
if ( !checkPropertySanity( _nHandle, _rConvertedValue, sErrorMessage ) )
{
IllegalArgumentException aException;
aException.Message = sErrorMessage;
aException.Context = *this;
throw IllegalArgumentException( aException );
}
return sal_True;
}
//--------------------------------------------------------------------
void SAL_CALL OXSDDataType::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw (Exception)
{
OXSDDataType_PBase::setFastPropertyValue_NoBroadcast( _nHandle, _rValue );
if ( _nHandle == PROPERTY_ID_XSD_PATTERN )
m_bPatternMatcherDirty = true;
}
//--------------------------------------------------------------------
bool OXSDDataType::checkPropertySanity( sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rNewValue, ::rtl::OUString& _rErrorMessage )
{
if ( _nHandle == PROPERTY_ID_XSD_PATTERN )
{
::rtl::OUString sPattern;
OSL_VERIFY( _rNewValue >>= sPattern );
UnicodeString aIcuPattern( reinterpret_cast<const UChar *>(sPattern.getStr()), sPattern.getLength() ); // UChar != sal_Unicode in MinGW
UErrorCode nMatchStatus = U_ZERO_ERROR;
RegexMatcher aMatcher( aIcuPattern, 0, nMatchStatus );
if ( U_FAILURE( nMatchStatus ) )
{
_rErrorMessage = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "This is no valid pattern." ) );
return false;
}
}
return true;
}
//--------------------------------------------------------------------
void SAL_CALL OXSDDataType::setPropertyValue( const ::rtl::OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
{
OXSDDataType_PBase::setPropertyValue( aPropertyName, aValue );
}
//--------------------------------------------------------------------
Any SAL_CALL OXSDDataType::getPropertyValue( const ::rtl::OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
{
return OXSDDataType_PBase::getPropertyValue( PropertyName );
}
//--------------------------------------------------------------------
void SAL_CALL OXSDDataType::addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
{
OXSDDataType_PBase::addPropertyChangeListener( aPropertyName, xListener );
}
//--------------------------------------------------------------------
void SAL_CALL OXSDDataType::removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const Reference< XPropertyChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
{
OXSDDataType_PBase::removePropertyChangeListener( aPropertyName, aListener );
}
//--------------------------------------------------------------------
void SAL_CALL OXSDDataType::addVetoableChangeListener( const ::rtl::OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
{
OXSDDataType_PBase::addVetoableChangeListener( PropertyName, aListener );
}
//--------------------------------------------------------------------
void SAL_CALL OXSDDataType::removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
{
OXSDDataType_PBase::removeVetoableChangeListener( PropertyName, aListener );
}
//====================================================================
//= OValueLimitedType_Base
//====================================================================
OValueLimitedType_Base::OValueLimitedType_Base( const ::rtl::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 ::com::sun::star::uno::Any& _rValue ) throw (::com::sun::star::uno::Exception)
{
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 ::rtl::OUString& rValue, double& fValue )
{
// convert to double
rtl_math_ConversionStatus eStatus;
sal_Int32 nEnd;
double f = ::rtl::math::stringToDouble(
rValue, sal_Unicode('.'), sal_Unicode(0), &eStatus, &nEnd );
// error checking...
bool bReturn = false;
if( eStatus == rtl_math_ConversionStatus_Ok
&& nEnd == rValue.getLength() )
{
bReturn = true;
fValue = f;
}
return bReturn;
}
//--------------------------------------------------------------------
sal_uInt16 OValueLimitedType_Base::_validate( const ::rtl::OUString& rValue )
{
sal_uInt16 nReason = OXSDDataType::_validate( rValue );
if( nReason == 0 )
{
// convert value and check format
double f;
if( ! _getValue( rValue, f ) )
nReason = RID_STR_XFORMS_VALUE_IS_NOT_A;
// check range
else if( ( m_aMaxInclusive.hasValue() ) && f > m_fCachedMaxInclusive )
nReason = RID_STR_XFORMS_VALUE_MAX_INCL;
else if( ( m_aMaxExclusive.hasValue() ) && f >= m_fCachedMaxExclusive )
nReason = RID_STR_XFORMS_VALUE_MAX_EXCL;
else if( ( m_aMinInclusive.hasValue() ) && f < m_fCachedMinInclusive )
nReason = RID_STR_XFORMS_VALUE_MIN_INCL;
else if( ( m_aMinExclusive.hasValue() ) && f <= m_fCachedMinExclusive )
nReason = RID_STR_XFORMS_VALUE_MIN_EXCL;
}
return nReason;
}
//--------------------------------------------------------------------
::rtl::OUString OValueLimitedType_Base::_explainInvalid( sal_uInt16 nReason )
{
::rtl::OUStringBuffer sInfo;
switch( nReason )
{
case 0:
// nothing to do!
break;
case RID_STR_XFORMS_VALUE_IS_NOT_A:
sInfo.append( getName() );
break;
case RID_STR_XFORMS_VALUE_MAX_INCL:
sInfo.append( typedValueAsHumanReadableString( m_aMaxInclusive ) );
break;
case RID_STR_XFORMS_VALUE_MAX_EXCL:
sInfo.append( typedValueAsHumanReadableString( m_aMaxExclusive ) );
break;
case RID_STR_XFORMS_VALUE_MIN_INCL:
sInfo.append( typedValueAsHumanReadableString( m_aMinInclusive ) );
break;
case RID_STR_XFORMS_VALUE_MIN_EXCL:
sInfo.append( typedValueAsHumanReadableString( m_aMinExclusive ) );
break;
default:
OSL_ENSURE( false, "OValueLimitedType::_explainInvalid: unknown reason!" );
break;
}
return sInfo.makeStringAndClear();
}
//====================================================================
//= OStringType
//====================================================================
//--------------------------------------------------------------------
OStringType::OStringType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass )
:OStringType_Base( _rName, _nTypeClass )
{
}
//--------------------------------------------------------------------
void OStringType::registerProperties()
{
OStringType_Base::registerProperties();
REGISTER_VOID_PROP( XSD_LENGTH, m_aLength, sal_Int32 );
REGISTER_VOID_PROP( XSD_MIN_LENGTH, m_aMinLength, sal_Int32 );
REGISTER_VOID_PROP( XSD_MAX_LENGTH, m_aMaxLength, sal_Int32 );
}
//--------------------------------------------------------------------
IMPLEMENT_DEFAULT_TYPED_CLONING( OStringType, OStringType_Base )
//--------------------------------------------------------------------
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, ::rtl::OUString& _rErrorMessage )
{
// let the base class do the conversion
if ( !OStringType_Base::checkPropertySanity( _nHandle, _rNewValue, _rErrorMessage ) )
return false;
_rErrorMessage = ::rtl::OUString();
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 = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Length limits must denote positive integer values." ) );
// TODO/eforms: localize the error message
}
break;
}
return _rErrorMessage.getLength() == 0;
}
//--------------------------------------------------------------------
sal_uInt16 OStringType::_validate( const ::rtl::OUString& rValue )
{
// check regexp, whitespace etc. in parent class
sal_uInt16 nReason = OStringType_Base::_validate( rValue );
if( nReason == 0 )
{
// check string constraints
sal_Int32 nLength = rValue.getLength();
sal_Int32 nLimit = 0;
if ( m_aLength >>= nLimit )
{
if ( nLimit != nLength )
nReason = RID_STR_XFORMS_VALUE_LENGTH;
}
else
{
if ( ( m_aMaxLength >>= nLimit ) && ( nLength > nLimit ) )
nReason = RID_STR_XFORMS_VALUE_MAX_LENGTH;
else if ( ( m_aMinLength >>= nLimit ) && ( nLength < nLimit ) )
nReason = RID_STR_XFORMS_VALUE_MIN_LENGTH;
}
}
return nReason;
}
//--------------------------------------------------------------------
::rtl::OUString OStringType::_explainInvalid( sal_uInt16 nReason )
{
sal_Int32 nValue = 0;
::rtl::OUStringBuffer sInfo;
switch( nReason )
{
case 0:
// nothing to do!
break;
case RID_STR_XFORMS_VALUE_LENGTH:
if( m_aLength >>= nValue )
sInfo.append( nValue );
break;
case RID_STR_XFORMS_VALUE_MAX_LENGTH:
if( m_aMaxLength >>= nValue )
sInfo.append( nValue );
break;
case RID_STR_XFORMS_VALUE_MIN_LENGTH:
if( m_aMinLength >>= nValue )
sInfo.append( nValue );
break;
default:
sInfo.append( OStringType_Base::_explainInvalid( nReason ) );
break;
}
return sInfo.makeStringAndClear();
}
//====================================================================
//= OBooleanType
//====================================================================
//--------------------------------------------------------------------
OBooleanType::OBooleanType( const ::rtl::OUString& _rName )
:OBooleanType_Base( _rName, DataTypeClass::BOOLEAN )
{
}
//--------------------------------------------------------------------
IMPLEMENT_DEFAULT_CLONING( OBooleanType, OBooleanType_Base )
//--------------------------------------------------------------------
void OBooleanType::initializeTypedClone( const OBooleanType& /*_rCloneSource*/ )
{
}
//--------------------------------------------------------------------
sal_uInt16 OBooleanType::_validate( const ::rtl::OUString& sValue )
{
sal_uInt16 nInvalidityReason = OBooleanType_Base::_validate( sValue );
if ( nInvalidityReason )
return nInvalidityReason;
bool bValid =
sValue.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("0")) ||
sValue.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("1")) ||
sValue.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("true")) ||
sValue.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("false"));
return bValid ? 0 : RID_STR_XFORMS_INVALID_VALUE;
}
//--------------------------------------------------------------------
::rtl::OUString OBooleanType::_explainInvalid( sal_uInt16 nReason )
{
return ( nReason == 0 ) ? ::rtl::OUString() : getName();
}
//====================================================================
//= ODecimalType
//====================================================================
//--------------------------------------------------------------------
ODecimalType::ODecimalType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass )
:ODecimalType_Base( _rName, _nTypeClass )
{
}
//--------------------------------------------------------------------
IMPLEMENT_DEFAULT_TYPED_CLONING( ODecimalType, ODecimalType_Base )
//--------------------------------------------------------------------
void ODecimalType::initializeTypedClone( const ODecimalType& _rCloneSource )
{
m_aTotalDigits = _rCloneSource.m_aTotalDigits;
m_aFractionDigits = _rCloneSource.m_aFractionDigits;
}
//--------------------------------------------------------------------
void ODecimalType::registerProperties()
{
ODecimalType_Base::registerProperties();
REGISTER_VOID_PROP( XSD_TOTAL_DIGITS, m_aTotalDigits, sal_Int32 );
REGISTER_VOID_PROP( XSD_FRACTION_DIGITS, m_aFractionDigits, sal_Int32 );
}
//--------------------------------------------------------------------
// validate decimals and return code for which facets failed
// to be used by: ODecimalType::validate and ODecimalType::explainInvalid
sal_uInt16 ODecimalType::_validate( const ::rtl::OUString& rValue )
{
sal_Int16 nReason = ODecimalType_Base::_validate( rValue );
// check digits (if no other cause is available so far)
if( nReason == 0 )
{
sal_Int32 nLength = rValue.getLength();
sal_Int32 n = 0;
sal_Int32 nTotalDigits = 0;
sal_Int32 nFractionDigits = 0;
const sal_Unicode* pValue = rValue.getStr();
for( ; pValue[n] != sal_Unicode('.') && n < nLength; n++ )
if( pValue[n] >= sal_Unicode('0')
&& pValue[n] <= sal_Unicode('9'))
nTotalDigits++;
for( ; n < nLength; n++ )
if( pValue[n] >= sal_Unicode('0')
&& pValue[n] <= sal_Unicode('9'))
nFractionDigits++;
nTotalDigits += nFractionDigits;
sal_Int32 nValue = 0;
if( ( m_aTotalDigits >>= nValue ) && nTotalDigits > nValue )
nReason = RID_STR_XFORMS_VALUE_TOTAL_DIGITS;
else if( ( m_aFractionDigits >>= nValue ) &&
( nFractionDigits > nValue ) )
nReason = RID_STR_XFORMS_VALUE_FRACTION_DIGITS;
}
return nReason;
}
//--------------------------------------------------------------------
::rtl::OUString ODecimalType::_explainInvalid( sal_uInt16 nReason )
{
sal_Int32 nValue = 0;
::rtl::OUStringBuffer sInfo;
switch( nReason )
{
case RID_STR_XFORMS_VALUE_TOTAL_DIGITS:
if( m_aTotalDigits >>= nValue )
sInfo.append( nValue );
break;
case RID_STR_XFORMS_VALUE_FRACTION_DIGITS:
if( m_aFractionDigits >>= nValue )
sInfo.append( nValue );
break;
default:
sInfo.append( ODecimalType_Base::_explainInvalid( nReason ) );
break;
}
return sInfo.makeStringAndClear();
}
//--------------------------------------------------------------------
::rtl::OUString ODecimalType::typedValueAsHumanReadableString( const Any& _rValue ) const
{
double fValue( 0 );
normalizeValue( _rValue, fValue );
return ::rtl::OUString::valueOf( fValue );
}
//--------------------------------------------------------------------
void ODecimalType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
{
OSL_VERIFY( _rValue >>= _rDoubleValue );
}
//====================================================================
//=
//====================================================================
#define DEFAULT_IMPLEMNENT_SUBTYPE( classname, typeclass ) \
classname::classname( const ::rtl::OUString& _rName ) \
:classname##_Base( _rName, DataTypeClass::typeclass ) \
{ \
} \
\
IMPLEMENT_DEFAULT_CLONING( classname, classname##_Base ) \
\
void classname::initializeTypedClone( const classname& /*_rCloneSource*/ ) \
{ \
} \
//====================================================================
//= ODateType
//====================================================================
//--------------------------------------------------------------------
DEFAULT_IMPLEMNENT_SUBTYPE( ODateType, DATE )
//--------------------------------------------------------------------
sal_uInt16 ODateType::_validate( const ::rtl::OUString& _rValue )
{
return ODateType_Base::_validate( _rValue );
}
//--------------------------------------------------------------------
bool ODateType::_getValue( const ::rtl::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;
}
//--------------------------------------------------------------------
::rtl::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
//====================================================================
//--------------------------------------------------------------------
DEFAULT_IMPLEMNENT_SUBTYPE( OTimeType, TIME )
//--------------------------------------------------------------------
sal_uInt16 OTimeType::_validate( const ::rtl::OUString& _rValue )
{
return OTimeType_Base::_validate( _rValue );
}
//--------------------------------------------------------------------
bool OTimeType::_getValue( const ::rtl::OUString& value, double& fValue )
{
Any aTypedValue = Convert::get().toAny( value, getCppuType() );
Time aValue;
if ( !( aTypedValue >>= aValue ) )
return false;
::Time aToolsTime( aValue.Hours, aValue.Minutes, aValue.Seconds, aValue.HundredthSeconds );
fValue = aToolsTime.GetTime();
return true;
}
//--------------------------------------------------------------------
::rtl::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
{
Time aValue;
OSL_VERIFY( _rValue >>= aValue );
::Time aToolsTime( aValue.Hours, aValue.Minutes, aValue.Seconds, aValue.HundredthSeconds );
_rDoubleValue = aToolsTime.GetTime();
}
//====================================================================
//= ODateTimeType
//====================================================================
//--------------------------------------------------------------------
DEFAULT_IMPLEMNENT_SUBTYPE( ODateTimeType, DATETIME )
//--------------------------------------------------------------------
sal_uInt16 ODateTimeType::_validate( const ::rtl::OUString& _rValue )
{
return ODateTimeType_Base::_validate( _rValue );
}
//--------------------------------------------------------------------
namespace
{
double lcl_normalizeDateTime( const DateTime& _rValue )
{
::DateTime aToolsValue(
::Date( _rValue.Day, _rValue.Month, _rValue.Year ),
::Time( _rValue.Hours, _rValue.Minutes, _rValue.Seconds, _rValue.HundredthSeconds )
);
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 ::rtl::OUString& value, double& fValue )
{
Any aTypedValue = Convert::get().toAny( value, getCppuType() );
DateTime aValue;
if ( !( aTypedValue >>= aValue ) )
return false;
fValue = lcl_normalizeDateTime( aValue );
return true;
}
//--------------------------------------------------------------------
::rtl::OUString ODateTimeType::typedValueAsHumanReadableString( const Any& _rValue ) const
{
OSL_PRECOND( _rValue.getValueType().equals( getCppuType() ), "OTimeType::typedValueAsHumanReadableString: unexpected type" );
::rtl::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::OShortIntegerType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass )
:OShortIntegerType_Base( _rName, _nTypeClass )
{
}
//--------------------------------------------------------------------
IMPLEMENT_DEFAULT_TYPED_CLONING( OShortIntegerType, OShortIntegerType_Base )
//--------------------------------------------------------------------
void OShortIntegerType::initializeTypedClone( const OShortIntegerType& /*_rCloneSource*/ )
{
}
//--------------------------------------------------------------------
bool OShortIntegerType::_getValue( const ::rtl::OUString& value, double& fValue )
{
fValue = (double)(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 numers ...
return true;
}
//--------------------------------------------------------------------
::rtl::OUString OShortIntegerType::typedValueAsHumanReadableString( const Any& _rValue ) const
{
sal_Int16 nValue( 0 );
OSL_VERIFY( _rValue >>= nValue );
return ::rtl::OUString::valueOf( (sal_Int32)nValue );
}
//--------------------------------------------------------------------
void OShortIntegerType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
{
sal_Int16 nValue( 0 );
OSL_VERIFY( _rValue >>= nValue );
_rDoubleValue = nValue;
}
//====================================================================
//====================================================================
#define DATATYPES_INCLUDED_BY_MASTER_HEADER
#include "datatypes_impl.hxx"
#undef DATATYPES_INCLUDED_BY_MASTER_HEADER
//........................................................................
} // namespace xforms
//........................................................................