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