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 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 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 : SAL_WARN_IF( member != value, "forms.misc", "OXSDDataType::setFoo: inconsistency!" );
115 :
116 :
117 0 : OUString SAL_CALL OXSDDataType::getName( ) throw (RuntimeException, std::exception)
118 : {
119 0 : return m_sName;
120 : }
121 :
122 :
123 0 : void SAL_CALL OXSDDataType::setName( const OUString& aName ) throw (RuntimeException, VetoException, std::exception)
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 : OUString SAL_CALL OXSDDataType::getPattern() throw (RuntimeException, std::exception)
131 : {
132 0 : return m_sPattern;
133 : }
134 :
135 :
136 0 : void SAL_CALL OXSDDataType::setPattern( const OUString& _pattern ) throw (RuntimeException, std::exception)
137 : {
138 0 : SET_PROPERTY( XSD_PATTERN, _pattern, m_sPattern );
139 0 : }
140 :
141 :
142 0 : sal_Int16 SAL_CALL OXSDDataType::getWhiteSpaceTreatment() throw (RuntimeException, std::exception)
143 : {
144 0 : return m_nWST;
145 : }
146 :
147 :
148 0 : void SAL_CALL OXSDDataType::setWhiteSpaceTreatment( sal_Int16 _whitespacetreatment ) throw (RuntimeException, IllegalArgumentException, std::exception)
149 : {
150 0 : SET_PROPERTY( XSD_WHITESPACE, _whitespacetreatment, m_nWST );
151 0 : }
152 :
153 :
154 0 : sal_Bool SAL_CALL OXSDDataType::getIsBasic() throw (RuntimeException, std::exception)
155 : {
156 0 : return m_bIsBasic;
157 : }
158 :
159 :
160 :
161 0 : sal_Int16 SAL_CALL OXSDDataType::getTypeClass() throw (RuntimeException, std::exception)
162 : {
163 0 : return m_nTypeClass;
164 : }
165 :
166 :
167 0 : sal_Bool OXSDDataType::validate( const OUString& sValue ) throw( RuntimeException, std::exception )
168 : {
169 0 : return ( _validate( sValue ) == 0 );
170 : }
171 :
172 :
173 0 : OUString OXSDDataType::explainInvalid( const OUString& sValue ) throw( RuntimeException, std::exception )
174 : {
175 : // get reason
176 0 : sal_uInt16 nReason = _validate( sValue );
177 :
178 : // get resource and return localized string
179 : return ( nReason == 0 )
180 : ? OUString()
181 : : getResource( nReason, sValue,
182 0 : _explainInvalid( nReason ) );
183 : }
184 :
185 :
186 0 : 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 OUString();
194 : }
195 :
196 :
197 : namespace
198 : {
199 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
200 0 : static void lcl_initializePatternMatcher( ::std::auto_ptr< RegexMatcher >& _rpMatcher, const 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 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 OUString& _rValue )
229 : {
230 : // care for the regular expression
231 0 : if ( !m_sPattern.isEmpty() )
232 : {
233 : // ensure our pattern matcher is up to date
234 0 : if ( m_bPatternMatcherDirty )
235 : {
236 0 : lcl_initializePatternMatcher( m_pPatternMatcher, m_sPattern );
237 0 : m_bPatternMatcherDirty = false;
238 : }
239 :
240 : // let it match the string
241 0 : if ( !lcl_matchString( *m_pPatternMatcher.get(), _rValue ) )
242 0 : return RID_STR_XFORMS_PATTERN_DOESNT_MATCH;
243 : }
244 :
245 0 : return 0;
246 : }
247 :
248 :
249 0 : sal_Bool OXSDDataType::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) throw(IllegalArgumentException)
250 : {
251 : // let the base class do the conversion
252 0 : if ( !OXSDDataType_PBase::convertFastPropertyValue( _rConvertedValue, _rOldValue, _nHandle, _rValue ) )
253 0 : return sal_False;
254 :
255 : // sanity checks
256 0 : OUString sErrorMessage;
257 0 : if ( !checkPropertySanity( _nHandle, _rConvertedValue, sErrorMessage ) )
258 : {
259 0 : IllegalArgumentException aException;
260 0 : aException.Message = sErrorMessage;
261 0 : aException.Context = *this;
262 0 : throw IllegalArgumentException( aException );
263 : }
264 :
265 0 : return sal_True;
266 : }
267 :
268 :
269 0 : void SAL_CALL OXSDDataType::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw (Exception, std::exception)
270 : {
271 0 : OXSDDataType_PBase::setFastPropertyValue_NoBroadcast( _nHandle, _rValue );
272 0 : if ( _nHandle == PROPERTY_ID_XSD_PATTERN )
273 0 : m_bPatternMatcherDirty = true;
274 0 : }
275 :
276 :
277 0 : bool OXSDDataType::checkPropertySanity( sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rNewValue, OUString& _rErrorMessage )
278 : {
279 0 : if ( _nHandle == PROPERTY_ID_XSD_PATTERN )
280 : {
281 0 : OUString sPattern;
282 0 : OSL_VERIFY( _rNewValue >>= sPattern );
283 :
284 0 : UnicodeString aIcuPattern( reinterpret_cast<const UChar *>(sPattern.getStr()), sPattern.getLength() ); // UChar != sal_Unicode in MinGW
285 0 : UErrorCode nMatchStatus = U_ZERO_ERROR;
286 0 : RegexMatcher aMatcher( aIcuPattern, 0, nMatchStatus );
287 0 : if ( U_FAILURE( nMatchStatus ) )
288 : {
289 0 : _rErrorMessage = "This is no valid pattern.";
290 0 : return false;
291 0 : }
292 : }
293 0 : return true;
294 : }
295 :
296 :
297 0 : void SAL_CALL OXSDDataType::setPropertyValue( const OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException, std::exception)
298 : {
299 0 : OXSDDataType_PBase::setPropertyValue( aPropertyName, aValue );
300 0 : }
301 :
302 :
303 0 : Any SAL_CALL OXSDDataType::getPropertyValue( const OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException, std::exception)
304 : {
305 0 : return OXSDDataType_PBase::getPropertyValue( PropertyName );
306 : }
307 :
308 :
309 0 : void SAL_CALL OXSDDataType::addPropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException, std::exception)
310 : {
311 0 : OXSDDataType_PBase::addPropertyChangeListener( aPropertyName, xListener );
312 0 : }
313 :
314 :
315 0 : void SAL_CALL OXSDDataType::removePropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException, std::exception)
316 : {
317 0 : OXSDDataType_PBase::removePropertyChangeListener( aPropertyName, aListener );
318 0 : }
319 :
320 :
321 0 : void SAL_CALL OXSDDataType::addVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException, std::exception)
322 : {
323 0 : OXSDDataType_PBase::addVetoableChangeListener( PropertyName, aListener );
324 0 : }
325 :
326 :
327 0 : void SAL_CALL OXSDDataType::removeVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException, std::exception)
328 : {
329 0 : OXSDDataType_PBase::removeVetoableChangeListener( PropertyName, aListener );
330 0 : }
331 :
332 :
333 : //= OValueLimitedType_Base
334 :
335 0 : OValueLimitedType_Base::OValueLimitedType_Base( const OUString& _rName, sal_Int16 _nTypeClass )
336 : :OXSDDataType( _rName, _nTypeClass )
337 : ,m_fCachedMaxInclusive( 0 )
338 : ,m_fCachedMaxExclusive( 0 )
339 : ,m_fCachedMinInclusive( 0 )
340 0 : ,m_fCachedMinExclusive( 0 )
341 : {
342 0 : }
343 :
344 :
345 0 : void OValueLimitedType_Base::initializeClone( const OXSDDataType& _rCloneSource )
346 : {
347 0 : OXSDDataType::initializeClone( _rCloneSource );
348 0 : initializeTypedClone( static_cast< const OValueLimitedType_Base& >( _rCloneSource ) );
349 0 : }
350 :
351 :
352 0 : void OValueLimitedType_Base::initializeTypedClone( const OValueLimitedType_Base& _rCloneSource )
353 : {
354 0 : m_aMaxInclusive = _rCloneSource.m_aMaxInclusive;
355 0 : m_aMaxExclusive = _rCloneSource.m_aMaxExclusive;
356 0 : m_aMinInclusive = _rCloneSource.m_aMinInclusive;
357 0 : m_aMinExclusive = _rCloneSource.m_aMinExclusive;
358 0 : m_fCachedMaxInclusive = _rCloneSource.m_fCachedMaxInclusive;
359 0 : m_fCachedMaxExclusive = _rCloneSource.m_fCachedMaxExclusive;
360 0 : m_fCachedMinInclusive = _rCloneSource.m_fCachedMinInclusive;
361 0 : m_fCachedMinExclusive = _rCloneSource.m_fCachedMinExclusive;
362 0 : }
363 :
364 :
365 0 : void SAL_CALL OValueLimitedType_Base::setFastPropertyValue_NoBroadcast(
366 : sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rValue ) throw (::com::sun::star::uno::Exception, std::exception)
367 : {
368 0 : OXSDDataType::setFastPropertyValue_NoBroadcast( _nHandle, _rValue );
369 :
370 : // if one of our limit properties has been set, translate it into a double
371 : // value, for later efficient validation
372 0 : switch ( _nHandle )
373 : {
374 : case PROPERTY_ID_XSD_MAX_INCLUSIVE_INT:
375 : case PROPERTY_ID_XSD_MAX_INCLUSIVE_DOUBLE:
376 : case PROPERTY_ID_XSD_MAX_INCLUSIVE_DATE:
377 : case PROPERTY_ID_XSD_MAX_INCLUSIVE_TIME:
378 : case PROPERTY_ID_XSD_MAX_INCLUSIVE_DATE_TIME:
379 0 : if ( m_aMaxInclusive.hasValue() )
380 0 : normalizeValue( m_aMaxInclusive, m_fCachedMaxInclusive );
381 : else
382 0 : m_fCachedMaxInclusive = 0;
383 0 : break;
384 : case PROPERTY_ID_XSD_MAX_EXCLUSIVE_INT:
385 : case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DOUBLE:
386 : case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DATE:
387 : case PROPERTY_ID_XSD_MAX_EXCLUSIVE_TIME:
388 : case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DATE_TIME:
389 0 : if ( m_aMaxExclusive.hasValue() )
390 0 : normalizeValue( m_aMaxExclusive, m_fCachedMaxExclusive );
391 : else
392 0 : m_fCachedMaxExclusive = 0;
393 0 : break;
394 : case PROPERTY_ID_XSD_MIN_INCLUSIVE_INT:
395 : case PROPERTY_ID_XSD_MIN_INCLUSIVE_DOUBLE:
396 : case PROPERTY_ID_XSD_MIN_INCLUSIVE_DATE:
397 : case PROPERTY_ID_XSD_MIN_INCLUSIVE_TIME:
398 : case PROPERTY_ID_XSD_MIN_INCLUSIVE_DATE_TIME:
399 0 : if ( m_aMinInclusive.hasValue() )
400 0 : normalizeValue( m_aMinInclusive, m_fCachedMinInclusive );
401 : else
402 0 : m_fCachedMinInclusive = 0;
403 0 : break;
404 : case PROPERTY_ID_XSD_MIN_EXCLUSIVE_INT:
405 : case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DOUBLE:
406 : case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DATE:
407 : case PROPERTY_ID_XSD_MIN_EXCLUSIVE_TIME:
408 : case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DATE_TIME:
409 0 : if ( m_aMinExclusive.hasValue() )
410 0 : normalizeValue( m_aMinExclusive, m_fCachedMinExclusive );
411 : else
412 0 : m_fCachedMinExclusive = 0;
413 0 : break;
414 : }
415 0 : }
416 :
417 :
418 0 : bool OValueLimitedType_Base::_getValue( const OUString& rValue, double& fValue )
419 : {
420 : // convert to double
421 : rtl_math_ConversionStatus eStatus;
422 : sal_Int32 nEnd;
423 : double f = ::rtl::math::stringToDouble(
424 0 : rValue, '.', sal_Unicode(0), &eStatus, &nEnd );
425 :
426 : // error checking...
427 0 : bool bReturn = false;
428 0 : if( eStatus == rtl_math_ConversionStatus_Ok
429 0 : && nEnd == rValue.getLength() )
430 : {
431 0 : bReturn = true;
432 0 : fValue = f;
433 : }
434 0 : return bReturn;
435 : }
436 :
437 :
438 0 : sal_uInt16 OValueLimitedType_Base::_validate( const OUString& rValue )
439 : {
440 0 : sal_uInt16 nReason = OXSDDataType::_validate( rValue );
441 0 : if( nReason == 0 )
442 : {
443 :
444 : // convert value and check format
445 : double f;
446 0 : if( ! _getValue( rValue, f ) )
447 0 : nReason = RID_STR_XFORMS_VALUE_IS_NOT_A;
448 :
449 : // check range
450 0 : else if( ( m_aMaxInclusive.hasValue() ) && f > m_fCachedMaxInclusive )
451 0 : nReason = RID_STR_XFORMS_VALUE_MAX_INCL;
452 0 : else if( ( m_aMaxExclusive.hasValue() ) && f >= m_fCachedMaxExclusive )
453 0 : nReason = RID_STR_XFORMS_VALUE_MAX_EXCL;
454 0 : else if( ( m_aMinInclusive.hasValue() ) && f < m_fCachedMinInclusive )
455 0 : nReason = RID_STR_XFORMS_VALUE_MIN_INCL;
456 0 : else if( ( m_aMinExclusive.hasValue() ) && f <= m_fCachedMinExclusive )
457 0 : nReason = RID_STR_XFORMS_VALUE_MIN_EXCL;
458 : }
459 0 : return nReason;
460 : }
461 :
462 :
463 0 : OUString OValueLimitedType_Base::_explainInvalid( sal_uInt16 nReason )
464 : {
465 0 : OUStringBuffer sInfo;
466 0 : switch( nReason )
467 : {
468 : case 0:
469 : // nothing to do!
470 0 : break;
471 :
472 : case RID_STR_XFORMS_VALUE_IS_NOT_A:
473 0 : sInfo.append( getName() );
474 0 : break;
475 :
476 : case RID_STR_XFORMS_VALUE_MAX_INCL:
477 0 : sInfo.append( typedValueAsHumanReadableString( m_aMaxInclusive ) );
478 0 : break;
479 :
480 : case RID_STR_XFORMS_VALUE_MAX_EXCL:
481 0 : sInfo.append( typedValueAsHumanReadableString( m_aMaxExclusive ) );
482 0 : break;
483 :
484 : case RID_STR_XFORMS_VALUE_MIN_INCL:
485 0 : sInfo.append( typedValueAsHumanReadableString( m_aMinInclusive ) );
486 0 : break;
487 :
488 : case RID_STR_XFORMS_VALUE_MIN_EXCL:
489 0 : sInfo.append( typedValueAsHumanReadableString( m_aMinExclusive ) );
490 0 : break;
491 :
492 : default:
493 : OSL_FAIL( "OValueLimitedType::_explainInvalid: unknown reason!" );
494 0 : break;
495 : }
496 :
497 0 : return sInfo.makeStringAndClear();
498 : }
499 :
500 :
501 : //= OStringType
502 :
503 :
504 0 : OStringType::OStringType( const OUString& _rName, sal_Int16 _nTypeClass )
505 0 : :OStringType_Base( _rName, _nTypeClass )
506 : {
507 0 : }
508 :
509 :
510 0 : void OStringType::registerProperties()
511 : {
512 0 : OStringType_Base::registerProperties();
513 :
514 0 : REGISTER_VOID_PROP( XSD_LENGTH, m_aLength, sal_Int32 );
515 0 : REGISTER_VOID_PROP( XSD_MIN_LENGTH, m_aMinLength, sal_Int32 );
516 0 : REGISTER_VOID_PROP( XSD_MAX_LENGTH, m_aMaxLength, sal_Int32 );
517 0 : }
518 :
519 :
520 0 : IMPLEMENT_DEFAULT_TYPED_CLONING( OStringType, OStringType_Base )
521 :
522 :
523 0 : void OStringType::initializeTypedClone( const OStringType& _rCloneSource )
524 : {
525 0 : m_aLength = _rCloneSource.m_aLength;
526 0 : m_aMinLength = _rCloneSource.m_aMinLength;
527 0 : m_aMaxLength = _rCloneSource.m_aMaxLength;
528 0 : }
529 :
530 :
531 0 : bool OStringType::checkPropertySanity( sal_Int32 _nHandle, const Any& _rNewValue, OUString& _rErrorMessage )
532 : {
533 : // let the base class do the conversion
534 0 : if ( !OStringType_Base::checkPropertySanity( _nHandle, _rNewValue, _rErrorMessage ) )
535 0 : return false;
536 :
537 0 : _rErrorMessage = OUString();
538 0 : switch ( _nHandle )
539 : {
540 : case PROPERTY_ID_XSD_LENGTH:
541 : case PROPERTY_ID_XSD_MIN_LENGTH:
542 : case PROPERTY_ID_XSD_MAX_LENGTH:
543 : {
544 0 : sal_Int32 nValue( 0 );
545 0 : OSL_VERIFY( _rNewValue >>= nValue );
546 0 : if ( nValue <= 0 )
547 0 : _rErrorMessage = "Length limits must denote positive integer values.";
548 : // TODO/eforms: localize the error message
549 : }
550 0 : break;
551 : }
552 :
553 0 : return _rErrorMessage.isEmpty();
554 : }
555 :
556 :
557 0 : sal_uInt16 OStringType::_validate( const OUString& rValue )
558 : {
559 : // check regexp, whitespace etc. in parent class
560 0 : sal_uInt16 nReason = OStringType_Base::_validate( rValue );
561 :
562 0 : if( nReason == 0 )
563 : {
564 : // check string constraints
565 0 : sal_Int32 nLength = rValue.getLength();
566 0 : sal_Int32 nLimit = 0;
567 0 : if ( m_aLength >>= nLimit )
568 : {
569 0 : if ( nLimit != nLength )
570 0 : nReason = RID_STR_XFORMS_VALUE_LENGTH;
571 : }
572 : else
573 : {
574 0 : if ( ( m_aMaxLength >>= nLimit ) && ( nLength > nLimit ) )
575 0 : nReason = RID_STR_XFORMS_VALUE_MAX_LENGTH;
576 0 : else if ( ( m_aMinLength >>= nLimit ) && ( nLength < nLimit ) )
577 0 : nReason = RID_STR_XFORMS_VALUE_MIN_LENGTH;
578 : }
579 : }
580 0 : return nReason;
581 : }
582 :
583 :
584 0 : OUString OStringType::_explainInvalid( sal_uInt16 nReason )
585 : {
586 0 : sal_Int32 nValue = 0;
587 0 : OUStringBuffer sInfo;
588 0 : switch( nReason )
589 : {
590 : case 0:
591 : // nothing to do!
592 0 : break;
593 :
594 : case RID_STR_XFORMS_VALUE_LENGTH:
595 0 : if( m_aLength >>= nValue )
596 0 : sInfo.append( nValue );
597 0 : break;
598 :
599 : case RID_STR_XFORMS_VALUE_MAX_LENGTH:
600 0 : if( m_aMaxLength >>= nValue )
601 0 : sInfo.append( nValue );
602 0 : break;
603 :
604 : case RID_STR_XFORMS_VALUE_MIN_LENGTH:
605 0 : if( m_aMinLength >>= nValue )
606 0 : sInfo.append( nValue );
607 0 : break;
608 :
609 : default:
610 0 : sInfo.append( OStringType_Base::_explainInvalid( nReason ) );
611 0 : break;
612 : }
613 0 : return sInfo.makeStringAndClear();
614 : }
615 :
616 :
617 : //= OBooleanType
618 :
619 :
620 0 : OBooleanType::OBooleanType( const OUString& _rName )
621 0 : :OBooleanType_Base( _rName, DataTypeClass::BOOLEAN )
622 : {
623 0 : }
624 :
625 :
626 0 : IMPLEMENT_DEFAULT_CLONING( OBooleanType, OBooleanType_Base )
627 :
628 :
629 0 : void OBooleanType::initializeTypedClone( const OBooleanType& /*_rCloneSource*/ )
630 : {
631 0 : }
632 :
633 :
634 0 : sal_uInt16 OBooleanType::_validate( const OUString& sValue )
635 : {
636 0 : sal_uInt16 nInvalidityReason = OBooleanType_Base::_validate( sValue );
637 0 : if ( nInvalidityReason )
638 0 : return nInvalidityReason;
639 :
640 0 : bool bValid = sValue == "0" || sValue == "1" || sValue == "true" || sValue == "false";
641 0 : return bValid ? 0 : RID_STR_XFORMS_INVALID_VALUE;
642 : }
643 :
644 :
645 0 : OUString OBooleanType::_explainInvalid( sal_uInt16 nReason )
646 : {
647 0 : return ( nReason == 0 ) ? OUString() : getName();
648 : }
649 :
650 :
651 : //= ODecimalType
652 :
653 :
654 0 : ODecimalType::ODecimalType( const OUString& _rName, sal_Int16 _nTypeClass )
655 0 : :ODecimalType_Base( _rName, _nTypeClass )
656 : {
657 0 : }
658 :
659 :
660 0 : IMPLEMENT_DEFAULT_TYPED_CLONING( ODecimalType, ODecimalType_Base )
661 :
662 :
663 0 : void ODecimalType::initializeTypedClone( const ODecimalType& _rCloneSource )
664 : {
665 0 : m_aTotalDigits = _rCloneSource.m_aTotalDigits;
666 0 : m_aFractionDigits = _rCloneSource.m_aFractionDigits;
667 0 : }
668 :
669 :
670 0 : void ODecimalType::registerProperties()
671 : {
672 0 : ODecimalType_Base::registerProperties();
673 :
674 0 : REGISTER_VOID_PROP( XSD_TOTAL_DIGITS, m_aTotalDigits, sal_Int32 );
675 0 : REGISTER_VOID_PROP( XSD_FRACTION_DIGITS, m_aFractionDigits, sal_Int32 );
676 0 : }
677 :
678 :
679 :
680 : // validate decimals and return code for which facets failed
681 : // to be used by: ODecimalType::validate and ODecimalType::explainInvalid
682 0 : sal_uInt16 ODecimalType::_validate( const OUString& rValue )
683 : {
684 0 : sal_Int16 nReason = ODecimalType_Base::_validate( rValue );
685 :
686 : // check digits (if no other cause is available so far)
687 0 : if( nReason == 0 )
688 : {
689 0 : sal_Int32 nLength = rValue.getLength();
690 0 : sal_Int32 n = 0;
691 0 : sal_Int32 nTotalDigits = 0;
692 0 : sal_Int32 nFractionDigits = 0;
693 0 : const sal_Unicode* pValue = rValue.getStr();
694 0 : for( ; n < nLength && pValue[n] != '.'; n++ )
695 0 : if( pValue[n] >= '0'
696 0 : && pValue[n] <= '9')
697 0 : nTotalDigits++;
698 0 : for( ; n < nLength; n++ )
699 0 : if( pValue[n] >= '0'
700 0 : && pValue[n] <= '9')
701 0 : nFractionDigits++;
702 0 : nTotalDigits += nFractionDigits;
703 :
704 0 : sal_Int32 nValue = 0;
705 0 : if( ( m_aTotalDigits >>= nValue ) && nTotalDigits > nValue )
706 0 : nReason = RID_STR_XFORMS_VALUE_TOTAL_DIGITS;
707 0 : else if( ( m_aFractionDigits >>= nValue ) &&
708 0 : ( nFractionDigits > nValue ) )
709 0 : nReason = RID_STR_XFORMS_VALUE_FRACTION_DIGITS;
710 : }
711 :
712 0 : return nReason;
713 : }
714 :
715 :
716 0 : OUString ODecimalType::_explainInvalid( sal_uInt16 nReason )
717 : {
718 0 : sal_Int32 nValue = 0;
719 0 : OUStringBuffer sInfo;
720 0 : switch( nReason )
721 : {
722 : case RID_STR_XFORMS_VALUE_TOTAL_DIGITS:
723 0 : if( m_aTotalDigits >>= nValue )
724 0 : sInfo.append( nValue );
725 0 : break;
726 :
727 : case RID_STR_XFORMS_VALUE_FRACTION_DIGITS:
728 0 : if( m_aFractionDigits >>= nValue )
729 0 : sInfo.append( nValue );
730 0 : break;
731 :
732 : default:
733 0 : sInfo.append( ODecimalType_Base::_explainInvalid( nReason ) );
734 0 : break;
735 : }
736 0 : return sInfo.makeStringAndClear();
737 : }
738 :
739 :
740 0 : OUString ODecimalType::typedValueAsHumanReadableString( const Any& _rValue ) const
741 : {
742 0 : double fValue( 0 );
743 0 : normalizeValue( _rValue, fValue );
744 0 : return OUString::number( fValue );
745 : }
746 :
747 :
748 0 : void ODecimalType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
749 : {
750 0 : OSL_VERIFY( _rValue >>= _rDoubleValue );
751 0 : }
752 :
753 :
754 : //=
755 :
756 : #define DEFAULT_IMPLEMNENT_SUBTYPE( classname, typeclass ) \
757 : classname::classname( const OUString& _rName ) \
758 : :classname##_Base( _rName, DataTypeClass::typeclass ) \
759 : { \
760 : } \
761 : \
762 : IMPLEMENT_DEFAULT_CLONING( classname, classname##_Base ) \
763 : \
764 : void classname::initializeTypedClone( const classname& /*_rCloneSource*/ ) \
765 : { \
766 : } \
767 :
768 :
769 :
770 : //= ODateType
771 :
772 :
773 0 : DEFAULT_IMPLEMNENT_SUBTYPE( ODateType, DATE )
774 :
775 :
776 0 : sal_uInt16 ODateType::_validate( const OUString& _rValue )
777 : {
778 0 : return ODateType_Base::_validate( _rValue );
779 : }
780 :
781 :
782 0 : bool ODateType::_getValue( const OUString& value, double& fValue )
783 : {
784 0 : Any aTypeValue = Convert::get().toAny( value, getCppuType() );
785 :
786 0 : Date aValue;
787 0 : if ( !( aTypeValue >>= aValue ) )
788 0 : return false;
789 :
790 0 : ::Date aToolsDate( aValue.Day, aValue.Month, aValue.Year );
791 0 : fValue = aToolsDate.GetDate();
792 0 : return true;
793 : }
794 :
795 :
796 0 : OUString ODateType::typedValueAsHumanReadableString( const Any& _rValue ) const
797 : {
798 : OSL_PRECOND( _rValue.getValueType().equals( getCppuType() ), "ODateType::typedValueAsHumanReadableString: unexpected type" );
799 0 : return Convert::get().toXSD( _rValue );
800 : }
801 :
802 :
803 0 : void ODateType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
804 : {
805 0 : Date aValue;
806 0 : OSL_VERIFY( _rValue >>= aValue );
807 0 : ::Date aToolsDate( aValue.Day, aValue.Month, aValue.Year );
808 0 : _rDoubleValue = aToolsDate.GetDate();
809 0 : }
810 :
811 :
812 : //= OTimeType
813 :
814 :
815 0 : DEFAULT_IMPLEMNENT_SUBTYPE( OTimeType, TIME )
816 :
817 :
818 0 : sal_uInt16 OTimeType::_validate( const OUString& _rValue )
819 : {
820 0 : return OTimeType_Base::_validate( _rValue );
821 : }
822 :
823 :
824 0 : bool OTimeType::_getValue( const OUString& value, double& fValue )
825 : {
826 0 : Any aTypedValue = Convert::get().toAny( value, getCppuType() );
827 :
828 0 : Time aValue;
829 0 : if ( !( aTypedValue >>= aValue ) )
830 0 : return false;
831 :
832 0 : ::Time aToolsTime( aValue.Hours, aValue.Minutes, aValue.Seconds, aValue.NanoSeconds );
833 : // no loss/rounding; IEEE 754 double-precision floating-point
834 : // has a mantissa of 53 bits; we need at the very most 50 bits:
835 : // format of aToolsTime.GetTime() is (in decimal) hhmmssnnnnnnnnn
836 : // and 999999999999999 = 0x38D7EA4C67FFF
837 : // in reality I doubt we need (much) more than
838 : // 240000000000000 = 0x0DA475ABF0000
839 : // that is 48 bits
840 0 : fValue = aToolsTime.GetTime();
841 0 : return true;
842 : }
843 :
844 :
845 0 : OUString OTimeType::typedValueAsHumanReadableString( const Any& _rValue ) const
846 : {
847 : OSL_PRECOND( _rValue.getValueType().equals( getCppuType() ), "OTimeType::typedValueAsHumanReadableString: unexpected type" );
848 0 : return Convert::get().toXSD( _rValue );
849 : }
850 :
851 :
852 0 : void OTimeType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
853 : {
854 0 : Time aValue;
855 0 : OSL_VERIFY( _rValue >>= aValue );
856 0 : ::Time aToolsTime( aValue.Hours, aValue.Minutes, aValue.Seconds, aValue.NanoSeconds );
857 0 : _rDoubleValue = aToolsTime.GetTime();
858 0 : }
859 :
860 :
861 : //= ODateTimeType
862 :
863 :
864 0 : DEFAULT_IMPLEMNENT_SUBTYPE( ODateTimeType, DATETIME )
865 :
866 :
867 0 : sal_uInt16 ODateTimeType::_validate( const OUString& _rValue )
868 : {
869 0 : return ODateTimeType_Base::_validate( _rValue );
870 : }
871 :
872 :
873 : namespace
874 : {
875 0 : double lcl_normalizeDateTime( const DateTime& _rValue )
876 : {
877 : ::DateTime aToolsValue(
878 : ::Date( _rValue.Day, _rValue.Month, _rValue.Year ),
879 : ::Time( _rValue.Hours, _rValue.Minutes, _rValue.Seconds, _rValue.NanoSeconds )
880 0 : );
881 :
882 0 : double fValue = 0;
883 : // days since 1.1.1900 (which is relatively arbitrary but fixed date)
884 0 : fValue += ::Date( aToolsValue ) - ::Date( 1, 1, 1900 );
885 : // time
886 0 : fValue += aToolsValue.GetTimeInDays();
887 0 : return fValue;
888 : }
889 : }
890 :
891 :
892 0 : bool ODateTimeType::_getValue( const OUString& value, double& fValue )
893 : {
894 0 : Any aTypedValue = Convert::get().toAny( value, getCppuType() );
895 :
896 0 : DateTime aValue;
897 0 : if ( !( aTypedValue >>= aValue ) )
898 0 : return false;
899 :
900 0 : fValue = lcl_normalizeDateTime( aValue );
901 0 : return true;
902 : }
903 :
904 :
905 0 : OUString ODateTimeType::typedValueAsHumanReadableString( const Any& _rValue ) const
906 : {
907 : OSL_PRECOND( _rValue.getValueType().equals( getCppuType() ), "OTimeType::typedValueAsHumanReadableString: unexpected type" );
908 0 : OUString sString = Convert::get().toXSD( _rValue );
909 :
910 : // ISO 8601 notation has a "T" to separate between date and time. Our only concession
911 : // to the "human readable" in the method name is to replace this T with a whitespace.
912 : OSL_ENSURE( sString.indexOf( 'T' ) != -1, "ODateTimeType::typedValueAsHumanReadableString: hmm - no ISO notation?" );
913 0 : return sString.replace( 'T', ' ' );
914 : }
915 :
916 :
917 0 : void ODateTimeType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
918 : {
919 0 : DateTime aValue;
920 0 : OSL_VERIFY( _rValue >>= aValue );
921 0 : _rDoubleValue = lcl_normalizeDateTime( aValue );
922 0 : }
923 :
924 :
925 : //= OShortIntegerType
926 :
927 :
928 0 : OShortIntegerType::OShortIntegerType( const OUString& _rName, sal_Int16 _nTypeClass )
929 0 : :OShortIntegerType_Base( _rName, _nTypeClass )
930 : {
931 0 : }
932 :
933 :
934 0 : IMPLEMENT_DEFAULT_TYPED_CLONING( OShortIntegerType, OShortIntegerType_Base )
935 :
936 :
937 0 : void OShortIntegerType::initializeTypedClone( const OShortIntegerType& /*_rCloneSource*/ )
938 : {
939 0 : }
940 :
941 :
942 0 : bool OShortIntegerType::_getValue( const OUString& value, double& fValue )
943 : {
944 0 : fValue = (double)(sal_Int16)value.toInt32();
945 : // TODO/eforms
946 : // this does not care for values which do not fit into a sal_Int16, but simply
947 : // cuts them down. A better implementation here should probably return <FALSE/>
948 : // for those values.
949 : // Else, we may have a situation where the UI claims an input to be valid
950 : // (say "12345678"), while internally, and at submission time, this is cut to
951 : // some smaller value.
952 :
953 : // Additionally, this of course does not care for strings which are no numers ...
954 0 : return true;
955 : }
956 :
957 :
958 0 : OUString OShortIntegerType::typedValueAsHumanReadableString( const Any& _rValue ) const
959 : {
960 0 : sal_Int16 nValue( 0 );
961 0 : OSL_VERIFY( _rValue >>= nValue );
962 0 : return OUString::number( nValue );
963 : }
964 :
965 :
966 0 : void OShortIntegerType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const
967 : {
968 0 : sal_Int16 nValue( 0 );
969 0 : OSL_VERIFY( _rValue >>= nValue );
970 0 : _rDoubleValue = nValue;
971 0 : }
972 :
973 :
974 :
975 : #define DATATYPES_INCLUDED_BY_MASTER_HEADER
976 : #include "datatypes_impl.hxx"
977 : #undef DATATYPES_INCLUDED_BY_MASTER_HEADER
978 :
979 :
980 : } // namespace xforms
981 :
982 :
983 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|