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