Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "datatypes.hxx"
21 : #include "resourcehelper.hxx"
22 : #include "property.hrc"
23 : #include "convert.hxx"
24 :
25 : #include <com/sun/star/xsd/WhiteSpaceTreatment.hpp>
26 : #include <tools/datetime.hxx>
27 : #include <rtl/math.hxx>
28 :
29 : //........................................................................
30 : namespace xforms
31 : {
32 : //........................................................................
33 :
34 : using ::com::sun::star::uno::Reference;
35 : using ::com::sun::star::uno::RuntimeException;
36 : using ::com::sun::star::uno::Any;
37 : using ::com::sun::star::uno::makeAny;
38 : using ::com::sun::star::uno::Type;
39 : using ::com::sun::star::uno::Sequence;
40 : using ::com::sun::star::uno::Exception;
41 : using ::com::sun::star::util::VetoException;
42 : using ::com::sun::star::util::Date;
43 : using ::com::sun::star::util::Time;
44 : using ::com::sun::star::util::DateTime;
45 : using ::com::sun::star::lang::IllegalArgumentException;
46 : using ::com::sun::star::lang::WrappedTargetException;
47 : using ::com::sun::star::beans::UnknownPropertyException;
48 : using ::com::sun::star::beans::PropertyVetoException;
49 : using ::com::sun::star::beans::XPropertyChangeListener;
50 : using ::com::sun::star::beans::XVetoableChangeListener;
51 :
52 : using ::com::sun::star::beans::PropertyAttribute::BOUND;
53 : using ::com::sun::star::beans::PropertyAttribute::READONLY;
54 :
55 : using namespace ::com::sun::star::xsd;
56 : using namespace ::frm;
57 : U_NAMESPACE_USE
58 :
59 : //====================================================================
60 : //= OXSDDataType
61 : //====================================================================
62 : //--------------------------------------------------------------------
63 0 : OXSDDataType::OXSDDataType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass )
64 : :OXSDDataType_PBase( m_aBHelper )
65 : ,m_bIsBasic( sal_True )
66 : ,m_nTypeClass( _nTypeClass )
67 : ,m_sName( _rName )
68 : ,m_nWST( WhiteSpaceTreatment::Preserve )
69 0 : ,m_bPatternMatcherDirty( true )
70 : {
71 0 : }
72 :
73 : //--------------------------------------------------------------------
74 0 : OXSDDataType::~OXSDDataType()
75 : {
76 0 : }
77 :
78 : //--------------------------------------------------------------------
79 0 : void OXSDDataType::registerProperties()
80 : {
81 0 : registerProperty( PROPERTY_NAME, PROPERTY_ID_NAME, BOUND, &m_sName, ::getCppuType( &m_sName ) );
82 0 : registerProperty( PROPERTY_XSD_WHITESPACE, PROPERTY_ID_XSD_WHITESPACE, BOUND, &m_nWST, ::getCppuType( &m_nWST ) );
83 0 : registerProperty( PROPERTY_XSD_PATTERN, PROPERTY_ID_XSD_PATTERN, BOUND, &m_sPattern, ::getCppuType( &m_sPattern ) );
84 :
85 0 : registerProperty( PROPERTY_XSD_IS_BASIC, PROPERTY_ID_XSD_IS_BASIC, READONLY, &m_bIsBasic, ::getCppuType( &m_bIsBasic ) );
86 0 : registerProperty( PROPERTY_XSD_TYPE_CLASS, PROPERTY_ID_XSD_TYPE_CLASS, READONLY, &m_nTypeClass, ::getCppuType( &m_nTypeClass ) );
87 0 : }
88 :
89 : //--------------------------------------------------------------------
90 0 : void OXSDDataType::initializeClone( const OXSDDataType& _rCloneSource )
91 : {
92 0 : m_bIsBasic = sal_False;
93 0 : m_nTypeClass = _rCloneSource.m_nTypeClass;
94 0 : m_sPattern = _rCloneSource.m_sPattern;
95 0 : m_nWST = _rCloneSource.m_nWST;
96 0 : }
97 :
98 : //--------------------------------------------------------------------
99 0 : OXSDDataType* OXSDDataType::clone( const ::rtl::OUString& _rNewName ) const
100 : {
101 0 : OXSDDataType* pClone = createClone( _rNewName );
102 0 : pClone->initializeClone( *this );
103 0 : return pClone;
104 : }
105 :
106 : //--------------------------------------------------------------------
107 0 : IMPLEMENT_FORWARD_XINTERFACE2( OXSDDataType, OXSDDataType_Base, ::comphelper::OPropertyContainer )
108 :
109 : //--------------------------------------------------------------------
110 0 : IMPLEMENT_FORWARD_XTYPEPROVIDER2( OXSDDataType, OXSDDataType_Base, ::comphelper::OPropertyContainer )
111 :
112 : #define SET_PROPERTY( propertyid, value, member ) \
113 : setFastPropertyValue( PROPERTY_ID_##propertyid, makeAny( value ) ); \
114 : OSL_POSTCOND( member == value, "OXSDDataType::setFoo: inconsistency!" );
115 :
116 : //--------------------------------------------------------------------
117 0 : ::rtl::OUString SAL_CALL OXSDDataType::getName( ) throw (RuntimeException)
118 : {
119 0 : return m_sName;
120 : }
121 :
122 : //--------------------------------------------------------------------
123 0 : void SAL_CALL OXSDDataType::setName( const ::rtl::OUString& aName ) throw (RuntimeException, VetoException)
124 : {
125 : // TODO: check the name for conflicts in the repository
126 0 : SET_PROPERTY( NAME, aName, m_sName );
127 0 : }
128 :
129 : //--------------------------------------------------------------------
130 0 : ::rtl::OUString SAL_CALL OXSDDataType::getPattern() throw (RuntimeException)
131 : {
132 0 : return m_sPattern;
133 : }
134 :
135 : //--------------------------------------------------------------------
136 0 : void SAL_CALL OXSDDataType::setPattern( const ::rtl::OUString& _pattern ) throw (RuntimeException)
137 : {
138 0 : SET_PROPERTY( XSD_PATTERN, _pattern, m_sPattern );
139 0 : }
140 :
141 : //--------------------------------------------------------------------
142 0 : sal_Int16 SAL_CALL OXSDDataType::getWhiteSpaceTreatment() throw (RuntimeException)
143 : {
144 0 : return m_nWST;
145 : }
146 :
147 : //--------------------------------------------------------------------
148 0 : void SAL_CALL OXSDDataType::setWhiteSpaceTreatment( sal_Int16 _whitespacetreatment ) throw (RuntimeException, IllegalArgumentException)
149 : {
150 0 : SET_PROPERTY( XSD_WHITESPACE, _whitespacetreatment, m_nWST );
151 0 : }
152 :
153 : //--------------------------------------------------------------------
154 0 : sal_Bool SAL_CALL OXSDDataType::getIsBasic() throw (RuntimeException)
155 : {
156 0 : return m_bIsBasic;
157 : }
158 :
159 :
160 : //--------------------------------------------------------------------
161 0 : sal_Int16 SAL_CALL OXSDDataType::getTypeClass() throw (RuntimeException)
162 : {
163 0 : return m_nTypeClass;
164 : }
165 :
166 : //--------------------------------------------------------------------
167 0 : sal_Bool OXSDDataType::validate( const ::rtl::OUString& sValue ) throw( RuntimeException )
168 : {
169 0 : return ( _validate( sValue ) == 0 );
170 : }
171 :
172 : //--------------------------------------------------------------------
173 0 : ::rtl::OUString OXSDDataType::explainInvalid( const ::rtl::OUString& sValue ) throw( RuntimeException )
174 : {
175 : // get reason
176 0 : sal_uInt16 nReason = _validate( sValue );
177 :
178 : // get resource and return localized string
179 : return ( nReason == 0 )
180 : ? ::rtl::OUString()
181 : : getResource( nReason, sValue,
182 0 : _explainInvalid( nReason ) );
183 : }
184 :
185 : //--------------------------------------------------------------------
186 0 : ::rtl::OUString OXSDDataType::_explainInvalid( sal_uInt16 nReason )
187 : {
188 0 : if ( RID_STR_XFORMS_PATTERN_DOESNT_MATCH == nReason )
189 : {
190 : OSL_ENSURE( !m_sPattern.isEmpty(), "OXSDDataType::_explainInvalid: how can this error occur without a regular expression?" );
191 0 : return m_sPattern;
192 : }
193 0 : return ::rtl::OUString();
194 : }
195 :
196 : //--------------------------------------------------------------------
197 : namespace
198 : {
199 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
200 0 : static void lcl_initializePatternMatcher( ::std::auto_ptr< RegexMatcher >& _rpMatcher, const ::rtl::OUString& _rPattern )
201 : {
202 0 : UErrorCode nMatchStatus = U_ZERO_ERROR;
203 0 : UnicodeString aIcuPattern( reinterpret_cast<const UChar *>(_rPattern.getStr()), _rPattern.getLength() ); // UChar != sal_Unicode in MinGW
204 0 : _rpMatcher.reset( new RegexMatcher( aIcuPattern, 0, nMatchStatus ) );
205 0 : OSL_ENSURE( U_SUCCESS( nMatchStatus ), "lcl_initializePatternMatcher: invalid pattern property!" );
206 : // if asserts, then something changed our pattern without going to convertFastPropertyValue/checkPropertySanity
207 0 : }
208 : SAL_WNODEPRECATED_DECLARATIONS_POP
209 :
210 0 : static bool lcl_matchString( RegexMatcher& _rMatcher, const ::rtl::OUString& _rText )
211 : {
212 0 : UErrorCode nMatchStatus = U_ZERO_ERROR;
213 0 : UnicodeString aInput( reinterpret_cast<const UChar *>(_rText.getStr()), _rText.getLength() ); // UChar != sal_Unicode in MinGW
214 0 : _rMatcher.reset( aInput );
215 0 : if ( _rMatcher.matches( nMatchStatus ) )
216 : {
217 0 : int32_t nStart = _rMatcher.start( nMatchStatus );
218 0 : int32_t nEnd = _rMatcher.end ( nMatchStatus );
219 0 : if ( ( nStart == 0 ) && ( nEnd == _rText.getLength() ) )
220 0 : return true;
221 : }
222 :
223 0 : return false;
224 : }
225 : }
226 :
227 : //--------------------------------------------------------------------
228 0 : sal_uInt16 OXSDDataType::_validate( const ::rtl::OUString& _rValue )
229 : {
230 : // care for the whitespaces
231 0 : ::rtl::OUString sConverted = Convert::convertWhitespace( _rValue, m_nWST );
232 :
233 : // care for the regular expression
234 0 : if ( !m_sPattern.isEmpty() )
235 : {
236 : // ensure our pattern matcher is up to date
237 0 : if ( m_bPatternMatcherDirty )
238 : {
239 0 : lcl_initializePatternMatcher( m_pPatternMatcher, m_sPattern );
240 0 : m_bPatternMatcherDirty = false;
241 : }
242 :
243 : // let it match the string
244 0 : if ( !lcl_matchString( *m_pPatternMatcher.get(), _rValue ) )
245 0 : return RID_STR_XFORMS_PATTERN_DOESNT_MATCH;
246 : }
247 :
248 0 : return 0;
249 : }
250 :
251 : //--------------------------------------------------------------------
252 0 : sal_Bool OXSDDataType::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) throw(IllegalArgumentException)
253 : {
254 : // let the base class do the conversion
255 0 : if ( !OXSDDataType_PBase::convertFastPropertyValue( _rConvertedValue, _rOldValue, _nHandle, _rValue ) )
256 0 : return sal_False;
257 :
258 : // sanity checks
259 0 : ::rtl::OUString sErrorMessage;
260 0 : if ( !checkPropertySanity( _nHandle, _rConvertedValue, sErrorMessage ) )
261 : {
262 0 : IllegalArgumentException aException;
263 0 : aException.Message = sErrorMessage;
264 0 : aException.Context = *this;
265 0 : throw IllegalArgumentException( aException );
266 : }
267 :
268 0 : return sal_True;
269 : }
270 :
271 : //--------------------------------------------------------------------
272 0 : void SAL_CALL OXSDDataType::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw (Exception)
273 : {
274 0 : OXSDDataType_PBase::setFastPropertyValue_NoBroadcast( _nHandle, _rValue );
275 0 : if ( _nHandle == PROPERTY_ID_XSD_PATTERN )
276 0 : m_bPatternMatcherDirty = true;
277 0 : }
278 :
279 : //--------------------------------------------------------------------
280 0 : bool OXSDDataType::checkPropertySanity( sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rNewValue, ::rtl::OUString& _rErrorMessage )
281 : {
282 0 : if ( _nHandle == PROPERTY_ID_XSD_PATTERN )
283 : {
284 0 : ::rtl::OUString sPattern;
285 0 : OSL_VERIFY( _rNewValue >>= sPattern );
286 :
287 0 : UnicodeString aIcuPattern( reinterpret_cast<const UChar *>(sPattern.getStr()), sPattern.getLength() ); // UChar != sal_Unicode in MinGW
288 0 : UErrorCode nMatchStatus = U_ZERO_ERROR;
289 0 : RegexMatcher aMatcher( aIcuPattern, 0, nMatchStatus );
290 0 : if ( U_FAILURE( nMatchStatus ) )
291 : {
292 0 : _rErrorMessage = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "This is no valid pattern." ) );
293 0 : return false;
294 0 : }
295 : }
296 0 : return true;
297 : }
298 :
299 : //--------------------------------------------------------------------
300 0 : void SAL_CALL OXSDDataType::setPropertyValue( const ::rtl::OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
301 : {
302 0 : OXSDDataType_PBase::setPropertyValue( aPropertyName, aValue );
303 0 : }
304 :
305 : //--------------------------------------------------------------------
306 0 : Any SAL_CALL OXSDDataType::getPropertyValue( const ::rtl::OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
307 : {
308 0 : return OXSDDataType_PBase::getPropertyValue( PropertyName );
309 : }
310 :
311 : //--------------------------------------------------------------------
312 0 : void SAL_CALL OXSDDataType::addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
313 : {
314 0 : OXSDDataType_PBase::addPropertyChangeListener( aPropertyName, xListener );
315 0 : }
316 :
317 : //--------------------------------------------------------------------
318 0 : void SAL_CALL OXSDDataType::removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const Reference< XPropertyChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
319 : {
320 0 : OXSDDataType_PBase::removePropertyChangeListener( aPropertyName, aListener );
321 0 : }
322 :
323 : //--------------------------------------------------------------------
324 0 : void SAL_CALL OXSDDataType::addVetoableChangeListener( const ::rtl::OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
325 : {
326 0 : OXSDDataType_PBase::addVetoableChangeListener( PropertyName, aListener );
327 0 : }
328 :
329 : //--------------------------------------------------------------------
330 0 : void SAL_CALL OXSDDataType::removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
331 : {
332 0 : OXSDDataType_PBase::removeVetoableChangeListener( PropertyName, aListener );
333 0 : }
334 :
335 : //====================================================================
336 : //= OValueLimitedType_Base
337 : //====================================================================
338 0 : OValueLimitedType_Base::OValueLimitedType_Base( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass )
339 : :OXSDDataType( _rName, _nTypeClass )
340 : ,m_fCachedMaxInclusive( 0 )
341 : ,m_fCachedMaxExclusive( 0 )
342 : ,m_fCachedMinInclusive( 0 )
343 0 : ,m_fCachedMinExclusive( 0 )
344 : {
345 0 : }
346 :
347 : //--------------------------------------------------------------------
348 0 : void OValueLimitedType_Base::initializeClone( const OXSDDataType& _rCloneSource )
349 : {
350 0 : OXSDDataType::initializeClone( _rCloneSource );
351 0 : initializeTypedClone( static_cast< const OValueLimitedType_Base& >( _rCloneSource ) );
352 0 : }
353 :
354 : //--------------------------------------------------------------------
355 0 : void OValueLimitedType_Base::initializeTypedClone( const OValueLimitedType_Base& _rCloneSource )
356 : {
357 0 : m_aMaxInclusive = _rCloneSource.m_aMaxInclusive;
358 0 : m_aMaxExclusive = _rCloneSource.m_aMaxExclusive;
359 0 : m_aMinInclusive = _rCloneSource.m_aMinInclusive;
360 0 : m_aMinExclusive = _rCloneSource.m_aMinExclusive;
361 0 : m_fCachedMaxInclusive = _rCloneSource.m_fCachedMaxInclusive;
362 0 : m_fCachedMaxExclusive = _rCloneSource.m_fCachedMaxExclusive;
363 0 : m_fCachedMinInclusive = _rCloneSource.m_fCachedMinInclusive;
364 0 : m_fCachedMinExclusive = _rCloneSource.m_fCachedMinExclusive;
365 0 : }
366 :
367 : //--------------------------------------------------------------------
368 0 : void SAL_CALL OValueLimitedType_Base::setFastPropertyValue_NoBroadcast(
369 : sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rValue ) throw (::com::sun::star::uno::Exception)
370 : {
371 0 : OXSDDataType::setFastPropertyValue_NoBroadcast( _nHandle, _rValue );
372 :
373 : // if one of our limit properties has been set, translate it into a double
374 : // value, for later efficient validation
375 0 : switch ( _nHandle )
376 : {
377 : case PROPERTY_ID_XSD_MAX_INCLUSIVE_INT:
378 : case PROPERTY_ID_XSD_MAX_INCLUSIVE_DOUBLE:
379 : case PROPERTY_ID_XSD_MAX_INCLUSIVE_DATE:
380 : case PROPERTY_ID_XSD_MAX_INCLUSIVE_TIME:
381 : case PROPERTY_ID_XSD_MAX_INCLUSIVE_DATE_TIME:
382 0 : if ( m_aMaxInclusive.hasValue() )
383 0 : normalizeValue( m_aMaxInclusive, m_fCachedMaxInclusive );
384 : else
385 0 : m_fCachedMaxInclusive = 0;
386 0 : break;
387 : case PROPERTY_ID_XSD_MAX_EXCLUSIVE_INT:
388 : case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DOUBLE:
389 : case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DATE:
390 : case PROPERTY_ID_XSD_MAX_EXCLUSIVE_TIME:
391 : case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DATE_TIME:
392 0 : if ( m_aMaxExclusive.hasValue() )
393 0 : normalizeValue( m_aMaxExclusive, m_fCachedMaxExclusive );
394 : else
395 0 : m_fCachedMaxExclusive = 0;
396 0 : break;
397 : case PROPERTY_ID_XSD_MIN_INCLUSIVE_INT:
398 : case PROPERTY_ID_XSD_MIN_INCLUSIVE_DOUBLE:
399 : case PROPERTY_ID_XSD_MIN_INCLUSIVE_DATE:
400 : case PROPERTY_ID_XSD_MIN_INCLUSIVE_TIME:
401 : case PROPERTY_ID_XSD_MIN_INCLUSIVE_DATE_TIME:
402 0 : if ( m_aMinInclusive.hasValue() )
403 0 : normalizeValue( m_aMinInclusive, m_fCachedMinInclusive );
404 : else
405 0 : m_fCachedMinInclusive = 0;
406 0 : break;
407 : case PROPERTY_ID_XSD_MIN_EXCLUSIVE_INT:
408 : case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DOUBLE:
409 : case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DATE:
410 : case PROPERTY_ID_XSD_MIN_EXCLUSIVE_TIME:
411 : case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DATE_TIME:
412 0 : if ( m_aMinExclusive.hasValue() )
413 0 : normalizeValue( m_aMinExclusive, m_fCachedMinExclusive );
414 : else
415 0 : m_fCachedMinExclusive = 0;
416 0 : break;
417 : }
418 0 : }
419 :
420 : //--------------------------------------------------------------------
421 0 : bool OValueLimitedType_Base::_getValue( const ::rtl::OUString& rValue, double& fValue )
422 : {
423 : // convert to double
424 : rtl_math_ConversionStatus eStatus;
425 : sal_Int32 nEnd;
426 : double f = ::rtl::math::stringToDouble(
427 0 : rValue, sal_Unicode('.'), sal_Unicode(0), &eStatus, &nEnd );
428 :
429 : // error checking...
430 0 : bool bReturn = false;
431 0 : if( eStatus == rtl_math_ConversionStatus_Ok
432 0 : && nEnd == rValue.getLength() )
433 : {
434 0 : bReturn = true;
435 0 : fValue = f;
436 : }
437 0 : return bReturn;
438 : }
439 :
440 : //--------------------------------------------------------------------
441 0 : sal_uInt16 OValueLimitedType_Base::_validate( const ::rtl::OUString& rValue )
442 : {
443 0 : sal_uInt16 nReason = OXSDDataType::_validate( rValue );
444 0 : if( nReason == 0 )
445 : {
446 :
447 : // convert value and check format
448 : double f;
449 0 : if( ! _getValue( rValue, f ) )
450 0 : nReason = RID_STR_XFORMS_VALUE_IS_NOT_A;
451 :
452 : // check range
453 0 : else if( ( m_aMaxInclusive.hasValue() ) && f > m_fCachedMaxInclusive )
454 0 : nReason = RID_STR_XFORMS_VALUE_MAX_INCL;
455 0 : else if( ( m_aMaxExclusive.hasValue() ) && f >= m_fCachedMaxExclusive )
456 0 : nReason = RID_STR_XFORMS_VALUE_MAX_EXCL;
457 0 : else if( ( m_aMinInclusive.hasValue() ) && f < m_fCachedMinInclusive )
458 0 : nReason = RID_STR_XFORMS_VALUE_MIN_INCL;
459 0 : else if( ( m_aMinExclusive.hasValue() ) && f <= m_fCachedMinExclusive )
460 0 : nReason = RID_STR_XFORMS_VALUE_MIN_EXCL;
461 : }
462 0 : return nReason;
463 : }
464 :
465 : //--------------------------------------------------------------------
466 0 : ::rtl::OUString OValueLimitedType_Base::_explainInvalid( sal_uInt16 nReason )
467 : {
468 0 : ::rtl::OUStringBuffer sInfo;
469 0 : switch( nReason )
470 : {
471 : case 0:
472 : // nothing to do!
473 0 : break;
474 :
475 : case RID_STR_XFORMS_VALUE_IS_NOT_A:
476 0 : sInfo.append( getName() );
477 0 : break;
478 :
479 : case RID_STR_XFORMS_VALUE_MAX_INCL:
480 0 : sInfo.append( typedValueAsHumanReadableString( m_aMaxInclusive ) );
481 0 : break;
482 :
483 : case RID_STR_XFORMS_VALUE_MAX_EXCL:
484 0 : sInfo.append( typedValueAsHumanReadableString( m_aMaxExclusive ) );
485 0 : break;
486 :
487 : case RID_STR_XFORMS_VALUE_MIN_INCL:
488 0 : sInfo.append( typedValueAsHumanReadableString( m_aMinInclusive ) );
489 0 : break;
490 :
491 : case RID_STR_XFORMS_VALUE_MIN_EXCL:
492 0 : sInfo.append( typedValueAsHumanReadableString( m_aMinExclusive ) );
493 0 : break;
494 :
495 : default:
496 : OSL_FAIL( "OValueLimitedType::_explainInvalid: unknown reason!" );
497 0 : break;
498 : }
499 :
500 0 : return sInfo.makeStringAndClear();
501 : }
502 :
503 : //====================================================================
504 : //= OStringType
505 : //====================================================================
506 : //--------------------------------------------------------------------
507 0 : OStringType::OStringType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass )
508 0 : :OStringType_Base( _rName, _nTypeClass )
509 : {
510 0 : }
511 :
512 : //--------------------------------------------------------------------
513 0 : void OStringType::registerProperties()
514 : {
515 0 : OStringType_Base::registerProperties();
516 :
517 0 : REGISTER_VOID_PROP( XSD_LENGTH, m_aLength, sal_Int32 );
518 0 : REGISTER_VOID_PROP( XSD_MIN_LENGTH, m_aMinLength, sal_Int32 );
519 0 : REGISTER_VOID_PROP( XSD_MAX_LENGTH, m_aMaxLength, sal_Int32 );
520 0 : }
521 :
522 : //--------------------------------------------------------------------
523 0 : IMPLEMENT_DEFAULT_TYPED_CLONING( OStringType, OStringType_Base )
524 :
525 : //--------------------------------------------------------------------
526 0 : void OStringType::initializeTypedClone( const OStringType& _rCloneSource )
527 : {
528 0 : m_aLength = _rCloneSource.m_aLength;
529 0 : m_aMinLength = _rCloneSource.m_aMinLength;
530 0 : m_aMaxLength = _rCloneSource.m_aMaxLength;
531 0 : }
532 :
533 : //--------------------------------------------------------------------
534 0 : bool OStringType::checkPropertySanity( sal_Int32 _nHandle, const Any& _rNewValue, ::rtl::OUString& _rErrorMessage )
535 : {
536 : // let the base class do the conversion
537 0 : if ( !OStringType_Base::checkPropertySanity( _nHandle, _rNewValue, _rErrorMessage ) )
538 0 : return false;
539 :
540 0 : _rErrorMessage = ::rtl::OUString();
541 0 : switch ( _nHandle )
542 : {
543 : case PROPERTY_ID_XSD_LENGTH:
544 : case PROPERTY_ID_XSD_MIN_LENGTH:
545 : case PROPERTY_ID_XSD_MAX_LENGTH:
546 : {
547 0 : sal_Int32 nValue( 0 );
548 0 : OSL_VERIFY( _rNewValue >>= nValue );
549 0 : if ( nValue <= 0 )
550 0 : _rErrorMessage = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Length limits must denote positive integer values." ) );
551 : // TODO/eforms: localize the error message
552 : }
553 0 : break;
554 : }
555 :
556 0 : return _rErrorMessage.isEmpty();
557 : }
558 :
559 : //--------------------------------------------------------------------
560 0 : sal_uInt16 OStringType::_validate( const ::rtl::OUString& rValue )
561 : {
562 : // check regexp, whitespace etc. in parent class
563 0 : sal_uInt16 nReason = OStringType_Base::_validate( rValue );
564 :
565 0 : if( nReason == 0 )
566 : {
567 : // check string constraints
568 0 : sal_Int32 nLength = rValue.getLength();
569 0 : sal_Int32 nLimit = 0;
570 0 : if ( m_aLength >>= nLimit )
571 : {
572 0 : if ( nLimit != nLength )
573 0 : nReason = RID_STR_XFORMS_VALUE_LENGTH;
574 : }
575 : else
576 : {
577 0 : if ( ( m_aMaxLength >>= nLimit ) && ( nLength > nLimit ) )
578 0 : nReason = RID_STR_XFORMS_VALUE_MAX_LENGTH;
579 0 : else if ( ( m_aMinLength >>= nLimit ) && ( nLength < nLimit ) )
580 0 : nReason = RID_STR_XFORMS_VALUE_MIN_LENGTH;
581 : }
582 : }
583 0 : return nReason;
584 : }
585 :
586 : //--------------------------------------------------------------------
587 0 : ::rtl::OUString OStringType::_explainInvalid( sal_uInt16 nReason )
588 : {
589 0 : sal_Int32 nValue = 0;
590 0 : ::rtl::OUStringBuffer sInfo;
591 0 : switch( nReason )
592 : {
593 : case 0:
594 : // nothing to do!
595 0 : break;
596 :
597 : case RID_STR_XFORMS_VALUE_LENGTH:
598 0 : if( m_aLength >>= nValue )
599 0 : sInfo.append( nValue );
600 0 : break;
601 :
602 : case RID_STR_XFORMS_VALUE_MAX_LENGTH:
603 0 : if( m_aMaxLength >>= nValue )
604 0 : sInfo.append( nValue );
605 0 : break;
606 :
607 : case RID_STR_XFORMS_VALUE_MIN_LENGTH:
608 0 : if( m_aMinLength >>= nValue )
609 0 : sInfo.append( nValue );
610 0 : break;
611 :
612 : default:
613 0 : sInfo.append( OStringType_Base::_explainInvalid( nReason ) );
614 0 : break;
615 : }
616 0 : return sInfo.makeStringAndClear();
617 : }
618 :
619 : //====================================================================
620 : //= OBooleanType
621 : //====================================================================
622 : //--------------------------------------------------------------------
623 0 : OBooleanType::OBooleanType( const ::rtl::OUString& _rName )
624 0 : :OBooleanType_Base( _rName, DataTypeClass::BOOLEAN )
625 : {
626 0 : }
627 :
628 : //--------------------------------------------------------------------
629 0 : IMPLEMENT_DEFAULT_CLONING( OBooleanType, OBooleanType_Base )
630 :
631 : //--------------------------------------------------------------------
632 0 : void OBooleanType::initializeTypedClone( const OBooleanType& /*_rCloneSource*/ )
633 : {
634 0 : }
635 :
636 : //--------------------------------------------------------------------
637 0 : sal_uInt16 OBooleanType::_validate( const ::rtl::OUString& sValue )
638 : {
639 0 : sal_uInt16 nInvalidityReason = OBooleanType_Base::_validate( sValue );
640 0 : if ( nInvalidityReason )
641 0 : return nInvalidityReason;
642 :
643 0 : bool bValid = sValue == "0" || sValue == "1" || sValue == "true" || sValue == "false";
644 0 : return bValid ? 0 : RID_STR_XFORMS_INVALID_VALUE;
645 : }
646 :
647 : //--------------------------------------------------------------------
648 0 : ::rtl::OUString OBooleanType::_explainInvalid( sal_uInt16 nReason )
649 : {
650 0 : return ( nReason == 0 ) ? ::rtl::OUString() : getName();
651 : }
652 :
653 : //====================================================================
654 : //= ODecimalType
655 : //====================================================================
656 : //--------------------------------------------------------------------
657 0 : ODecimalType::ODecimalType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass )
658 0 : :ODecimalType_Base( _rName, _nTypeClass )
659 : {
660 0 : }
661 :
662 : //--------------------------------------------------------------------
663 0 : IMPLEMENT_DEFAULT_TYPED_CLONING( ODecimalType, ODecimalType_Base )
664 :
665 : //--------------------------------------------------------------------
666 0 : void ODecimalType::initializeTypedClone( const ODecimalType& _rCloneSource )
667 : {
668 0 : m_aTotalDigits = _rCloneSource.m_aTotalDigits;
669 0 : m_aFractionDigits = _rCloneSource.m_aFractionDigits;
670 0 : }
671 :
672 : //--------------------------------------------------------------------
673 0 : void ODecimalType::registerProperties()
674 : {
675 0 : ODecimalType_Base::registerProperties();
676 :
677 0 : REGISTER_VOID_PROP( XSD_TOTAL_DIGITS, m_aTotalDigits, sal_Int32 );
678 0 : REGISTER_VOID_PROP( XSD_FRACTION_DIGITS, m_aFractionDigits, sal_Int32 );
679 0 : }
680 :
681 : //--------------------------------------------------------------------
682 :
683 : // validate decimals and return code for which facets failed
684 : // to be used by: ODecimalType::validate and ODecimalType::explainInvalid
685 0 : sal_uInt16 ODecimalType::_validate( const ::rtl::OUString& rValue )
686 : {
687 0 : sal_Int16 nReason = ODecimalType_Base::_validate( rValue );
688 :
689 : // check digits (if no other cause is available so far)
690 0 : if( nReason == 0 )
691 : {
692 0 : sal_Int32 nLength = rValue.getLength();
693 0 : sal_Int32 n = 0;
694 0 : sal_Int32 nTotalDigits = 0;
695 0 : sal_Int32 nFractionDigits = 0;
696 0 : const sal_Unicode* pValue = rValue.getStr();
697 0 : for( ; pValue[n] != sal_Unicode('.') && n < nLength; n++ )
698 0 : if( pValue[n] >= sal_Unicode('0')
699 0 : && pValue[n] <= sal_Unicode('9'))
700 0 : nTotalDigits++;
701 0 : for( ; n < nLength; n++ )
702 0 : if( pValue[n] >= sal_Unicode('0')
703 0 : && pValue[n] <= sal_Unicode('9'))
704 0 : nFractionDigits++;
705 0 : nTotalDigits += nFractionDigits;
706 :
707 0 : sal_Int32 nValue = 0;
708 0 : if( ( m_aTotalDigits >>= nValue ) && nTotalDigits > nValue )
709 0 : nReason = RID_STR_XFORMS_VALUE_TOTAL_DIGITS;
710 0 : else if( ( m_aFractionDigits >>= nValue ) &&
711 : ( nFractionDigits > nValue ) )
712 0 : nReason = RID_STR_XFORMS_VALUE_FRACTION_DIGITS;
713 : }
714 :
715 0 : return nReason;
716 : }
717 :
718 : //--------------------------------------------------------------------
719 0 : ::rtl::OUString ODecimalType::_explainInvalid( sal_uInt16 nReason )
720 : {
721 0 : sal_Int32 nValue = 0;
722 0 : ::rtl::OUStringBuffer sInfo;
723 0 : switch( nReason )
724 : {
725 : case RID_STR_XFORMS_VALUE_TOTAL_DIGITS:
726 0 : if( m_aTotalDigits >>= nValue )
727 0 : sInfo.append( nValue );
728 0 : break;
729 :
730 : case RID_STR_XFORMS_VALUE_FRACTION_DIGITS:
731 0 : if( m_aFractionDigits >>= nValue )
732 0 : sInfo.append( nValue );
733 0 : break;
734 :
735 : default:
736 0 : sInfo.append( ODecimalType_Base::_explainInvalid( nReason ) );
737 0 : break;
738 : }
739 0 : return sInfo.makeStringAndClear();
740 : }
741 :
742 : //--------------------------------------------------------------------
743 0 : ::rtl::OUString ODecimalType::typedValueAsHumanReadableString( const Any& _rValue ) const
744 : {
745 0 : double fValue( 0 );
746 0 : normalizeValue( _rValue, fValue );
747 0 : return ::rtl::OUString::valueOf( fValue );
748 : }
749 :
750 : //--------------------------------------------------------------------
751 0 : void ODecimalType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
752 : {
753 0 : OSL_VERIFY( _rValue >>= _rDoubleValue );
754 0 : }
755 :
756 : //====================================================================
757 : //=
758 : //====================================================================
759 : #define DEFAULT_IMPLEMNENT_SUBTYPE( classname, typeclass ) \
760 : classname::classname( const ::rtl::OUString& _rName ) \
761 : :classname##_Base( _rName, DataTypeClass::typeclass ) \
762 : { \
763 : } \
764 : \
765 : IMPLEMENT_DEFAULT_CLONING( classname, classname##_Base ) \
766 : \
767 : void classname::initializeTypedClone( const classname& /*_rCloneSource*/ ) \
768 : { \
769 : } \
770 :
771 :
772 : //====================================================================
773 : //= ODateType
774 : //====================================================================
775 : //--------------------------------------------------------------------
776 0 : DEFAULT_IMPLEMNENT_SUBTYPE( ODateType, DATE )
777 :
778 : //--------------------------------------------------------------------
779 0 : sal_uInt16 ODateType::_validate( const ::rtl::OUString& _rValue )
780 : {
781 0 : return ODateType_Base::_validate( _rValue );
782 : }
783 :
784 : //--------------------------------------------------------------------
785 0 : bool ODateType::_getValue( const ::rtl::OUString& value, double& fValue )
786 : {
787 0 : Any aTypeValue = Convert::get().toAny( value, getCppuType() );
788 :
789 0 : Date aValue;
790 0 : if ( !( aTypeValue >>= aValue ) )
791 0 : return false;
792 :
793 0 : ::Date aToolsDate( aValue.Day, aValue.Month, aValue.Year );
794 0 : fValue = aToolsDate.GetDate();
795 0 : return true;
796 : }
797 :
798 : //--------------------------------------------------------------------
799 0 : ::rtl::OUString ODateType::typedValueAsHumanReadableString( const Any& _rValue ) const
800 : {
801 : OSL_PRECOND( _rValue.getValueType().equals( getCppuType() ), "ODateType::typedValueAsHumanReadableString: unexpected type" );
802 0 : return Convert::get().toXSD( _rValue );
803 : }
804 :
805 : //--------------------------------------------------------------------
806 0 : void ODateType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
807 : {
808 0 : Date aValue;
809 0 : OSL_VERIFY( _rValue >>= aValue );
810 0 : ::Date aToolsDate( aValue.Day, aValue.Month, aValue.Year );
811 0 : _rDoubleValue = aToolsDate.GetDate();
812 0 : }
813 :
814 : //====================================================================
815 : //= OTimeType
816 : //====================================================================
817 : //--------------------------------------------------------------------
818 0 : DEFAULT_IMPLEMNENT_SUBTYPE( OTimeType, TIME )
819 :
820 : //--------------------------------------------------------------------
821 0 : sal_uInt16 OTimeType::_validate( const ::rtl::OUString& _rValue )
822 : {
823 0 : return OTimeType_Base::_validate( _rValue );
824 : }
825 :
826 : //--------------------------------------------------------------------
827 0 : bool OTimeType::_getValue( const ::rtl::OUString& value, double& fValue )
828 : {
829 0 : Any aTypedValue = Convert::get().toAny( value, getCppuType() );
830 :
831 0 : Time aValue;
832 0 : if ( !( aTypedValue >>= aValue ) )
833 0 : return false;
834 :
835 0 : ::Time aToolsTime( aValue.Hours, aValue.Minutes, aValue.Seconds, aValue.HundredthSeconds );
836 0 : fValue = aToolsTime.GetTime();
837 0 : return true;
838 : }
839 :
840 : //--------------------------------------------------------------------
841 0 : ::rtl::OUString OTimeType::typedValueAsHumanReadableString( const Any& _rValue ) const
842 : {
843 : OSL_PRECOND( _rValue.getValueType().equals( getCppuType() ), "OTimeType::typedValueAsHumanReadableString: unexpected type" );
844 0 : return Convert::get().toXSD( _rValue );
845 : }
846 :
847 : //--------------------------------------------------------------------
848 0 : void OTimeType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
849 : {
850 0 : Time aValue;
851 0 : OSL_VERIFY( _rValue >>= aValue );
852 0 : ::Time aToolsTime( aValue.Hours, aValue.Minutes, aValue.Seconds, aValue.HundredthSeconds );
853 0 : _rDoubleValue = aToolsTime.GetTime();
854 0 : }
855 :
856 : //====================================================================
857 : //= ODateTimeType
858 : //====================================================================
859 : //--------------------------------------------------------------------
860 0 : DEFAULT_IMPLEMNENT_SUBTYPE( ODateTimeType, DATETIME )
861 :
862 : //--------------------------------------------------------------------
863 0 : sal_uInt16 ODateTimeType::_validate( const ::rtl::OUString& _rValue )
864 : {
865 0 : return ODateTimeType_Base::_validate( _rValue );
866 : }
867 :
868 : //--------------------------------------------------------------------
869 : namespace
870 : {
871 0 : double lcl_normalizeDateTime( const DateTime& _rValue )
872 : {
873 : ::DateTime aToolsValue(
874 : ::Date( _rValue.Day, _rValue.Month, _rValue.Year ),
875 : ::Time( _rValue.Hours, _rValue.Minutes, _rValue.Seconds, _rValue.HundredthSeconds )
876 0 : );
877 :
878 0 : double fValue = 0;
879 : // days since 1.1.1900 (which is relatively arbitrary but fixed date)
880 0 : fValue += ::Date( aToolsValue ) - ::Date( 1, 1, 1900 );
881 : // time
882 0 : fValue += aToolsValue.GetTimeInDays();
883 0 : return fValue;
884 : }
885 : }
886 :
887 : //--------------------------------------------------------------------
888 0 : bool ODateTimeType::_getValue( const ::rtl::OUString& value, double& fValue )
889 : {
890 0 : Any aTypedValue = Convert::get().toAny( value, getCppuType() );
891 :
892 0 : DateTime aValue;
893 0 : if ( !( aTypedValue >>= aValue ) )
894 0 : return false;
895 :
896 0 : fValue = lcl_normalizeDateTime( aValue );
897 0 : return true;
898 : }
899 :
900 : //--------------------------------------------------------------------
901 0 : ::rtl::OUString ODateTimeType::typedValueAsHumanReadableString( const Any& _rValue ) const
902 : {
903 : OSL_PRECOND( _rValue.getValueType().equals( getCppuType() ), "OTimeType::typedValueAsHumanReadableString: unexpected type" );
904 0 : ::rtl::OUString sString = Convert::get().toXSD( _rValue );
905 :
906 : // ISO 8601 notation has a "T" to separate between date and time. Our only concession
907 : // to the "human readable" in the method name is to replace this T with a whitespace.
908 : OSL_ENSURE( sString.indexOf( 'T' ) != -1, "ODateTimeType::typedValueAsHumanReadableString: hmm - no ISO notation?" );
909 0 : return sString.replace( 'T', ' ' );
910 : }
911 :
912 : //--------------------------------------------------------------------
913 0 : void ODateTimeType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
914 : {
915 0 : DateTime aValue;
916 0 : OSL_VERIFY( _rValue >>= aValue );
917 0 : _rDoubleValue = lcl_normalizeDateTime( aValue );
918 0 : }
919 :
920 : //====================================================================
921 : //= OShortIntegerType
922 : //====================================================================
923 : //--------------------------------------------------------------------
924 0 : OShortIntegerType::OShortIntegerType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass )
925 0 : :OShortIntegerType_Base( _rName, _nTypeClass )
926 : {
927 0 : }
928 :
929 : //--------------------------------------------------------------------
930 0 : IMPLEMENT_DEFAULT_TYPED_CLONING( OShortIntegerType, OShortIntegerType_Base )
931 :
932 : //--------------------------------------------------------------------
933 0 : void OShortIntegerType::initializeTypedClone( const OShortIntegerType& /*_rCloneSource*/ )
934 : {
935 0 : }
936 :
937 : //--------------------------------------------------------------------
938 0 : bool OShortIntegerType::_getValue( const ::rtl::OUString& value, double& fValue )
939 : {
940 0 : fValue = (double)(sal_Int16)value.toInt32();
941 : // TODO/eforms
942 : // this does not care for values which do not fit into a sal_Int16, but simply
943 : // cuts them down. A better implementation here should probably return <FALSE/>
944 : // for those values.
945 : // Else, we may have a situation where the UI claims an input to be valid
946 : // (say "12345678"), while internally, and at submission time, this is cut to
947 : // some smaller value.
948 : //
949 : // Additionally, this of course does not care for strings which are no numers ...
950 0 : return true;
951 : }
952 :
953 : //--------------------------------------------------------------------
954 0 : ::rtl::OUString OShortIntegerType::typedValueAsHumanReadableString( const Any& _rValue ) const
955 : {
956 0 : sal_Int16 nValue( 0 );
957 0 : OSL_VERIFY( _rValue >>= nValue );
958 0 : return ::rtl::OUString::valueOf( (sal_Int32)nValue );
959 : }
960 :
961 : //--------------------------------------------------------------------
962 0 : void OShortIntegerType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
963 : {
964 0 : sal_Int16 nValue( 0 );
965 0 : OSL_VERIFY( _rValue >>= nValue );
966 0 : _rDoubleValue = nValue;
967 0 : }
968 : //====================================================================
969 : //====================================================================
970 :
971 : #define DATATYPES_INCLUDED_BY_MASTER_HEADER
972 : #include "datatypes_impl.hxx"
973 : #undef DATATYPES_INCLUDED_BY_MASTER_HEADER
974 :
975 : //........................................................................
976 : } // namespace xforms
977 : //........................................................................
978 :
979 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|