/* -*- 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 #include "datatypes.hxx" #include "resourcehelper.hxx" #include #include #include #include "convert.hxx" #include #include #include #include #include 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::get() ); registerProperty( PROPERTY_XSD_WHITESPACE, PROPERTY_ID_XSD_WHITESPACE, BOUND, &m_nWST, cppu::UnoType::get() ); registerProperty( PROPERTY_XSD_PATTERN, PROPERTY_ID_XSD_PATTERN, BOUND, &m_sPattern, cppu::UnoType::get() ); registerProperty( PROPERTY_XSD_IS_BASIC, PROPERTY_ID_XSD_IS_BASIC, READONLY, &m_bIsBasic, cppu::UnoType::get() ); registerProperty( PROPERTY_XSD_TYPE_CLASS, PROPERTY_ID_XSD_TYPE_CLASS, READONLY, &m_nTypeClass, cppu::UnoType::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::clone( const OUString& _rNewName ) const { rtl::Reference 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(_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(_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(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::get() ); registerMayBeVoidProperty( PROPERTY_XSD_MIN_LENGTH, PROPERTY_ID_XSD_MIN_LENGTH, css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEVOID, &m_aMinLength, cppu::UnoType::get() ); registerMayBeVoidProperty( PROPERTY_XSD_MAX_LENGTH, PROPERTY_ID_XSD_MAX_LENGTH, css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEVOID, &m_aMaxLength, cppu::UnoType::get() ); } rtl::Reference 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 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 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::get() ); registerMayBeVoidProperty( PROPERTY_XSD_FRACTION_DIGITS, PROPERTY_ID_XSD_FRACTION_DIGITS, css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEVOID, &m_aFractionDigits, cppu::UnoType::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 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 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 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 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(static_cast(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 // 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: */