1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_extensions.hxx"
26 #include "xsdvalidationhelper.hxx"
27 #include "xsddatatypes.hxx"
28 #include "formstrings.hxx"
29 
30 /** === begin UNO includes === **/
31 #include <com/sun/star/lang/XServiceInfo.hpp>
32 #include <com/sun/star/xsd/DataTypeClass.hpp>
33 #include <com/sun/star/util/NumberFormat.hpp>
34 #include <com/sun/star/util/XNumberFormatTypes.hpp>
35 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
36 #include <com/sun/star/xforms/XDataTypeRepository.hpp>
37 /** === end UNO includes === **/
38 #include <unotools/syslocale.hxx>
39 #include <tools/diagnose_ex.h>
40 
41 //........................................................................
42 namespace pcr
43 {
44 //........................................................................
45 
46     using namespace ::com::sun::star;
47     using namespace ::com::sun::star::uno;
48     using namespace ::com::sun::star::beans;
49     using namespace ::com::sun::star::xsd;
50     using namespace ::com::sun::star::util;
51     using namespace ::com::sun::star::lang;
52     using namespace ::com::sun::star::xforms;
53 
54     namespace NumberFormat = ::com::sun::star::util::NumberFormat;
55 
56     //====================================================================
57 	//= XSDValidationHelper
58 	//====================================================================
59 	//--------------------------------------------------------------------
XSDValidationHelper(::osl::Mutex & _rMutex,const Reference<XPropertySet> & _rxIntrospectee,const Reference<frame::XModel> & _rxContextDocument)60     XSDValidationHelper::XSDValidationHelper( ::osl::Mutex& _rMutex, const Reference< XPropertySet >& _rxIntrospectee, const Reference< frame::XModel >& _rxContextDocument )
61         :EFormsHelper( _rMutex, _rxIntrospectee, _rxContextDocument )
62         ,m_bInspectingFormattedField( false )
63     {
64         try
65         {
66             Reference< XPropertySetInfo > xPSI;
67             Reference< XServiceInfo >     xSI( _rxIntrospectee, UNO_QUERY );
68             if ( m_xControlModel.is() )
69                 xPSI = m_xControlModel->getPropertySetInfo();
70             if  (   xPSI.is()
71                 &&  xPSI->hasPropertyByName( PROPERTY_FORMATKEY )
72                 &&  xPSI->hasPropertyByName( PROPERTY_FORMATSSUPPLIER )
73                 &&  xSI.is()
74                 &&  xSI->supportsService( SERVICE_COMPONENT_FORMATTEDFIELD )
75                 )
76                 m_bInspectingFormattedField = true;
77         }
78         catch( const Exception& )
79         {
80             OSL_ENSURE( sal_False, "XSDValidationHelper::XSDValidationHelper: caught an exception while examining the introspectee!" );
81         }
82     }
83 
84     //--------------------------------------------------------------------
getAvailableDataTypeNames(::std::vector<::rtl::OUString> & _rNames) const85     void XSDValidationHelper::getAvailableDataTypeNames( ::std::vector< ::rtl::OUString >& /* [out] */ _rNames ) const SAL_THROW(())
86     {
87         _rNames.resize( 0 );
88 
89         try
90         {
91             Reference< XDataTypeRepository > xRepository = getDataTypeRepository();
92             Sequence< ::rtl::OUString > aElements;
93             if ( xRepository.is() )
94                 aElements = xRepository->getElementNames();
95 
96             _rNames.resize( aElements.getLength() );
97             ::std::copy( aElements.getConstArray(), aElements.getConstArray() + aElements.getLength(), _rNames.begin() );
98         }
99         catch( const Exception& )
100         {
101         	OSL_ENSURE( sal_False, "XSDValidationHelper::getAvailableDataTypeNames: caught an exception!" );
102         }
103     }
104 
105 	//--------------------------------------------------------------------
getDataTypeRepository() const106     Reference< XDataTypeRepository > XSDValidationHelper::getDataTypeRepository() const SAL_THROW((Exception))
107     {
108         Reference< XDataTypeRepository > xRepository;
109 
110         Reference< xforms::XModel > xModel( getCurrentFormModel( ) );
111         if ( xModel.is() )
112             xRepository = xModel->getDataTypeRepository();
113 
114         return xRepository;
115     }
116 
117 	//--------------------------------------------------------------------
getDataTypeRepository(const::rtl::OUString & _rModelName) const118     Reference< XDataTypeRepository > XSDValidationHelper::getDataTypeRepository( const ::rtl::OUString& _rModelName ) const SAL_THROW((Exception))
119     {
120         Reference< XDataTypeRepository > xRepository;
121 
122         Reference< xforms::XModel > xModel( getFormModelByName( _rModelName ) );
123         if ( xModel.is() )
124             xRepository = xModel->getDataTypeRepository();
125 
126         return xRepository;
127     }
128 
129 	//--------------------------------------------------------------------
getDataType(const::rtl::OUString & _rName) const130     Reference< XDataType > XSDValidationHelper::getDataType( const ::rtl::OUString& _rName ) const SAL_THROW((Exception))
131     {
132         Reference< XDataType > xDataType;
133 
134         if ( _rName.getLength() )
135         {
136             Reference< XDataTypeRepository > xRepository = getDataTypeRepository();
137             if ( xRepository.is() )
138                 xDataType = xRepository->getDataType( _rName );
139         }
140         return xDataType;
141     }
142 
143 	//--------------------------------------------------------------------
getValidatingDataTypeName() const144     ::rtl::OUString XSDValidationHelper::getValidatingDataTypeName( ) const SAL_THROW(())
145     {
146         ::rtl::OUString sDataTypeName;
147         try
148         {
149             Reference< XPropertySet > xBinding( getCurrentBinding() );
150             // it's allowed here to not (yet) have a binding
151             if ( xBinding.is() )
152             {
153                 OSL_VERIFY( xBinding->getPropertyValue( PROPERTY_XSD_DATA_TYPE ) >>= sDataTypeName );
154             }
155         }
156         catch( const Exception& )
157         {
158         	OSL_ENSURE( sal_False, "XSDValidationHelper::getValidatingDataTypeName: caught an exception!" );
159         }
160         return sDataTypeName;
161     }
162 
163     //--------------------------------------------------------------------
getDataTypeByName(const::rtl::OUString & _rName) const164     ::rtl::Reference< XSDDataType > XSDValidationHelper::getDataTypeByName( const ::rtl::OUString& _rName ) const SAL_THROW(())
165     {
166         ::rtl::Reference< XSDDataType > pReturn;
167 
168         try
169         {
170             Reference< XDataType > xValidatedAgainst;
171 
172             if ( _rName.getLength() )
173                 xValidatedAgainst = getDataType( _rName );
174 
175             if ( xValidatedAgainst.is() )
176                 pReturn = new XSDDataType( xValidatedAgainst );
177         }
178         catch( const Exception& )
179         {
180         	OSL_ENSURE( sal_False, "XSDValidationHelper::getDataTypeByName: caught an exception!" );
181         }
182 
183         return pReturn;
184     }
185 
186     //--------------------------------------------------------------------
getValidatingDataType() const187     ::rtl::Reference< XSDDataType > XSDValidationHelper::getValidatingDataType( ) const SAL_THROW(())
188     {
189         return getDataTypeByName( getValidatingDataTypeName() );
190     }
191 
192 	//--------------------------------------------------------------------
cloneDataType(const::rtl::Reference<XSDDataType> & _pDataType,const::rtl::OUString & _rNewName) const193     bool XSDValidationHelper::cloneDataType( const ::rtl::Reference< XSDDataType >& _pDataType, const ::rtl::OUString& _rNewName ) const SAL_THROW(())
194     {
195         OSL_ENSURE( _pDataType.is(), "XSDValidationHelper::removeDataTypeFromRepository: invalid data type!" );
196         if ( !_pDataType.is() )
197             return false;
198 
199         try
200         {
201             Reference< XDataTypeRepository > xRepository( getDataTypeRepository() );
202             OSL_ENSURE( xRepository.is(), "XSDValidationHelper::removeDataTypeFromRepository: invalid data type repository!" );
203             if ( !xRepository.is() )
204                 return false;
205 
206             Reference< XDataType > xDataType( _pDataType->getUnoDataType() );
207             OSL_ENSURE( xDataType.is(), "XSDValidationHelper::removeDataTypeFromRepository: invalid data type (II)!" );
208             if ( !xDataType.is() )
209                 return false;
210 
211             xRepository->cloneDataType( xDataType->getName(), _rNewName );
212         }
213         catch( const Exception& )
214         {
215         	OSL_ENSURE( sal_False, "XSDValidationHelper::cloneDataType: caught an exception!" );
216         }
217         return true;
218     }
219 
220 	//--------------------------------------------------------------------
removeDataTypeFromRepository(const::rtl::OUString & _rName) const221     bool XSDValidationHelper::removeDataTypeFromRepository( const ::rtl::OUString& _rName ) const SAL_THROW(())
222     {
223         try
224         {
225             Reference< XDataTypeRepository > xRepository( getDataTypeRepository() );
226             OSL_ENSURE( xRepository.is(), "XSDValidationHelper::removeDataTypeFromRepository: invalid data type repository!" );
227             if ( !xRepository.is() )
228                 return false;
229 
230             if ( !xRepository->hasByName( _rName ) )
231             {
232                 OSL_ENSURE( sal_False, "XSDValidationHelper::removeDataTypeFromRepository: invalid repository and/or data type!" );
233                 return false;
234             }
235 
236             xRepository->revokeDataType( _rName );
237         }
238         catch( const Exception& )
239         {
240         	OSL_ENSURE( sal_False, "XSDValidationHelper::removeDataTypeFromRepository: caught an exception!" );
241             return false;
242         }
243         return true;
244     }
245 
246 	//--------------------------------------------------------------------
setValidatingDataTypeByName(const::rtl::OUString & _rName) const247     void XSDValidationHelper::setValidatingDataTypeByName( const ::rtl::OUString& _rName ) const SAL_THROW(())
248     {
249         try
250         {
251             Reference< XPropertySet > xBinding( getCurrentBinding() );
252             OSL_ENSURE( xBinding.is(), "XSDValidationHelper::setValidatingDataTypeByName: no active binding - how this?" );
253 
254             if ( xBinding.is() )
255             {
256                 // get the old data type - this is necessary for notifying property changes
257                 ::rtl::OUString sOldDataTypeName;
258                 OSL_VERIFY( xBinding->getPropertyValue( PROPERTY_XSD_DATA_TYPE ) >>= sOldDataTypeName );
259                 Reference< XPropertySet > xOldType;
260                 try { xOldType = xOldType.query( getDataType( sOldDataTypeName ) ); } catch( const Exception& ) { }
261 
262                 // set the new data type name
263                 xBinding->setPropertyValue( PROPERTY_XSD_DATA_TYPE, makeAny( _rName ) );
264 
265                 // retrieve the new data type object
266                 Reference< XPropertySet > xNewType( getDataType( _rName ), UNO_QUERY );
267 
268                 // fire any changes in the properties which result from this new type
269                 std::set< ::rtl::OUString > aFilter; aFilter.insert( PROPERTY_NAME );
270                 firePropertyChanges( xOldType, xNewType, aFilter );
271 
272                 // fire the change in the Data Type property
273                 ::rtl::OUString sNewDataTypeName;
274                 OSL_VERIFY( xBinding->getPropertyValue( PROPERTY_XSD_DATA_TYPE ) >>= sNewDataTypeName );
275                 firePropertyChange( PROPERTY_XSD_DATA_TYPE, makeAny( sOldDataTypeName ), makeAny( sNewDataTypeName ) );
276             }
277         }
278         catch( const Exception& )
279         {
280             DBG_UNHANDLED_EXCEPTION();
281         }
282     }
283 
284 	//--------------------------------------------------------------------
copyDataType(const::rtl::OUString & _rFromModel,const::rtl::OUString & _rToModel,const::rtl::OUString & _rDataTypeName) const285     void XSDValidationHelper::copyDataType( const ::rtl::OUString& _rFromModel, const ::rtl::OUString& _rToModel,
286                 const ::rtl::OUString& _rDataTypeName ) const SAL_THROW(())
287     {
288         if ( _rFromModel == _rToModel )
289             // nothing to do (me thinks)
290             return;
291 
292         try
293         {
294             Reference< XDataTypeRepository > xFromRepository, xToRepository;
295             if ( _rFromModel.getLength() )
296                 xFromRepository = getDataTypeRepository( _rFromModel );
297             if ( _rToModel.getLength() )
298                 xToRepository = getDataTypeRepository( _rToModel );
299 
300             if ( !xFromRepository.is() || !xToRepository.is() )
301                 return;
302 
303             if ( !xFromRepository->hasByName( _rDataTypeName ) || xToRepository->hasByName( _rDataTypeName ) )
304                 // not existent in the source, or already existent (by name) in the destination
305                 return;
306 
307             // determine the built-in type belonging to the source type
308             ::rtl::Reference< XSDDataType > pSourceType = new XSDDataType( xFromRepository->getDataType( _rDataTypeName ) );
309             ::rtl::OUString sTargetBaseType = getBasicTypeNameForClass( pSourceType->classify(), xToRepository );
310 
311             // create the target type
312             Reference< XDataType > xTargetType = xToRepository->cloneDataType( sTargetBaseType, _rDataTypeName );
313             ::rtl::Reference< XSDDataType > pTargetType = new XSDDataType( xTargetType );
314 
315             // copy the facets
316             pTargetType->copyFacetsFrom( pSourceType );
317         }
318         catch( const Exception& )
319         {
320         	OSL_ENSURE( sal_False, "XSDValidationHelper::copyDataType: caught an exception!" );
321         }
322     }
323 
324     //--------------------------------------------------------------------
findDefaultFormatForIntrospectee()325     void XSDValidationHelper::findDefaultFormatForIntrospectee() SAL_THROW(())
326     {
327         try
328         {
329             ::rtl::Reference< XSDDataType > xDataType = getValidatingDataType();
330             if ( xDataType.is() )
331             {
332                 // find a NumberFormat type corresponding to the DataTypeClass
333                 sal_Int16 nNumberFormatType = NumberFormat::NUMBER;
334                 switch ( xDataType->classify() )
335                 {
336                 case DataTypeClass::DATETIME:
337                     nNumberFormatType = NumberFormat::DATETIME;
338                     break;
339                 case DataTypeClass::DATE:
340                     nNumberFormatType = NumberFormat::DATE;
341                     break;
342                 case DataTypeClass::TIME:
343                     nNumberFormatType = NumberFormat::TIME;
344                     break;
345                 case DataTypeClass::STRING:
346                 case DataTypeClass::anyURI:
347                 case DataTypeClass::QName:
348                 case DataTypeClass::NOTATION:
349                     nNumberFormatType = NumberFormat::TEXT;
350                     break;
351                 }
352 
353                 // get the number formatter from the introspectee
354                 Reference< XNumberFormatsSupplier > xSupplier;
355                 Reference< XNumberFormatTypes > xFormatTypes;
356                 OSL_VERIFY( m_xControlModel->getPropertyValue( PROPERTY_FORMATSSUPPLIER ) >>= xSupplier );
357                 if ( xSupplier.is() )
358                     xFormatTypes = xFormatTypes.query( xSupplier->getNumberFormats() );
359                 OSL_ENSURE( xFormatTypes.is(), "XSDValidationHelper::findDefaultFormatForIntrospectee: no number formats for the introspectee!" );
360                 if ( !xFormatTypes.is() )
361                     return;
362 
363                 // and the standard format for the given NumberFormat type
364                 sal_Int32 nDesiredFormat = xFormatTypes->getStandardFormat( nNumberFormatType, SvtSysLocale().GetLocaleData().getLocale() );
365 
366                 // set this at the introspectee
367                 m_xControlModel->setPropertyValue( PROPERTY_FORMATKEY, makeAny( nDesiredFormat ) );
368             }
369         }
370         catch( const Exception& )
371         {
372         	OSL_ENSURE( sal_False, "XSDValidationHelper::findDefaultFormatForIntrospectee: caught an exception!" );
373         }
374     }
375 
376 	//--------------------------------------------------------------------
getBasicTypeNameForClass(sal_Int16 _nClass) const377     ::rtl::OUString XSDValidationHelper::getBasicTypeNameForClass( sal_Int16 _nClass ) const SAL_THROW(())
378     {
379         return getBasicTypeNameForClass( _nClass, getDataTypeRepository() );
380     }
381 
382 	//--------------------------------------------------------------------
getBasicTypeNameForClass(sal_Int16 _nClass,Reference<XDataTypeRepository> _rxRepository) const383     ::rtl::OUString XSDValidationHelper::getBasicTypeNameForClass( sal_Int16 _nClass, Reference< XDataTypeRepository > _rxRepository ) const SAL_THROW(())
384     {
385         ::rtl::OUString sReturn;
386         OSL_ENSURE( _rxRepository.is(), "XSDValidationHelper::getBasicTypeNameForClass: invalid repository!" );
387         if ( !_rxRepository.is() )
388             return sReturn;
389 
390         try
391         {
392             Reference< XDataType > xDataType = _rxRepository->getBasicDataType( _nClass );
393             OSL_ENSURE( xDataType.is(), "XSDValidationHelper::getBasicTypeNameForClass: invalid data type returned!" );
394             if ( xDataType.is() )
395                 sReturn = xDataType->getName();
396         }
397         catch( const Exception& )
398         {
399         	OSL_ENSURE( sal_False, "XSDValidationHelper::getBasicTypeNameForClass: caught an exception!" );
400         }
401 
402         return sReturn;
403     }
404 
405 //........................................................................
406 } // namespace pcr
407 //........................................................................
408 
409