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 "eformshelper.hxx"
31 #include "formstrings.hxx"
32 #ifndef _EXTENSIONS_FORMCTRLR_PROPRESID_HRC_
33 #include "formresid.hrc"
34 #endif
35 #ifndef _EXTENSIONS_PROPCTRLR_MODULEPRC_HXX_
36 #include "modulepcr.hxx"
37 #endif
38 #include "propeventtranslation.hxx"
39 #include "formbrowsertools.hxx"
40 
41 /** === begin UNO includes === **/
42 #include <com/sun/star/lang/XServiceInfo.hpp>
43 #include <com/sun/star/form/FormComponentType.hpp>
44 #include <com/sun/star/xforms/XFormsUIHelper1.hpp>
45 #include <com/sun/star/xsd/DataTypeClass.hpp>
46 #include <com/sun/star/form/binding/XListEntrySink.hpp>
47 /** === end UNO includes === **/
48 #include <tools/diagnose_ex.h>
49 #include <rtl/ustrbuf.hxx>
50 
51 #include <functional>
52 #include <algorithm>
53 
54 //........................................................................
55 namespace pcr
56 {
57 //........................................................................
58 
59     using namespace ::com::sun::star;
60     using namespace ::com::sun::star::uno;
61     using namespace ::com::sun::star::beans;
62     using namespace ::com::sun::star::container;
63     using namespace ::com::sun::star::form::binding;
64     using namespace ::com::sun::star::xsd;
65     using namespace ::com::sun::star::lang;
66     using namespace ::com::sun::star::form;
67 
68 	//====================================================================
69 	//= file-local helpers
70 	//====================================================================
71     namespace
72     {
73 	    //--------------------------------------------------------------------
74         ::rtl::OUString composeModelElementUIName( const ::rtl::OUString& _rModelName, const ::rtl::OUString& _rElementName )
75         {
76             ::rtl::OUStringBuffer aBuffer;
77             aBuffer.appendAscii( "[" );
78             aBuffer.append( _rModelName );
79             aBuffer.appendAscii( "] " );
80             aBuffer.append( _rElementName );
81             return aBuffer.makeStringAndClear();
82         }
83     }
84 
85 	//====================================================================
86 	//= EFormsHelper
87 	//====================================================================
88 	//--------------------------------------------------------------------
89     EFormsHelper::EFormsHelper( ::osl::Mutex& _rMutex, const Reference< XPropertySet >& _rxControlModel, const Reference< frame::XModel >& _rxContextDocument )
90         :m_xControlModel( _rxControlModel )
91         ,m_aPropertyListeners( _rMutex )
92     {
93         OSL_ENSURE( _rxControlModel.is(), "EFormsHelper::EFormsHelper: invalid control model!" );
94         m_xBindableControl = m_xBindableControl.query( _rxControlModel );
95 
96         m_xDocument = m_xDocument.query( _rxContextDocument );
97         OSL_ENSURE( m_xDocument.is(), "EFormsHelper::EFormsHelper: invalid document!" );
98 
99     }
100 
101 	//--------------------------------------------------------------------
102     bool EFormsHelper::isEForm( const Reference< frame::XModel >& _rxContextDocument )
103     {
104         try
105         {
106             Reference< xforms::XFormsSupplier > xDocument( _rxContextDocument, UNO_QUERY );
107             if ( !xDocument.is() )
108                 return false;
109 
110             return xDocument->getXForms().is();
111         }
112         catch( const Exception& )
113         {
114         	OSL_ENSURE( sal_False, "EFormsHelper::isEForm: caught an exception!" );
115         }
116         return false;
117     }
118 
119 	//--------------------------------------------------------------------
120     bool EFormsHelper::canBindToDataType( sal_Int32 _nDataType ) const SAL_THROW(())
121     {
122         if ( !m_xBindableControl.is() )
123             // cannot bind at all
124             return false;
125 
126         // some types cannot be bound, independent from the control type
127         if (  ( DataTypeClass::hexBinary == _nDataType )
128            || ( DataTypeClass::base64Binary == _nDataType )
129            || ( DataTypeClass::QName == _nDataType )
130            || ( DataTypeClass::NOTATION == _nDataType )
131            )
132            return false;
133 
134         bool bCan = false;
135         try
136         {
137             // classify the control model
138             sal_Int16 nControlType = FormComponentType::CONTROL;
139             OSL_VERIFY( m_xControlModel->getPropertyValue( PROPERTY_CLASSID ) >>= nControlType );
140 
141             // some lists
142             sal_Int16 nNumericCompatibleTypes[] = { DataTypeClass::DECIMAL, DataTypeClass::FLOAT, DataTypeClass::DOUBLE, 0 };
143             sal_Int16 nDateCompatibleTypes[] = { DataTypeClass::DATE, 0 };
144             sal_Int16 nTimeCompatibleTypes[] = { DataTypeClass::TIME, 0 };
145             sal_Int16 nCheckboxCompatibleTypes[] = { DataTypeClass::BOOLEAN, DataTypeClass::STRING, DataTypeClass::anyURI, 0 };
146             sal_Int16 nRadiobuttonCompatibleTypes[] = { DataTypeClass::STRING, DataTypeClass::anyURI, 0 };
147             sal_Int16 nFormattedCompatibleTypes[] = { DataTypeClass::DECIMAL, DataTypeClass::FLOAT, DataTypeClass::DOUBLE, DataTypeClass::DATETIME, DataTypeClass::DATE, DataTypeClass::TIME, 0 };
148 
149             sal_Int16* pCompatibleTypes = NULL;
150             switch ( nControlType )
151             {
152             case FormComponentType::SPINBUTTON:
153             case FormComponentType::NUMERICFIELD:
154                 pCompatibleTypes = nNumericCompatibleTypes;
155                 break;
156             case FormComponentType::DATEFIELD:
157                 pCompatibleTypes = nDateCompatibleTypes;
158                 break;
159             case FormComponentType::TIMEFIELD:
160                 pCompatibleTypes = nTimeCompatibleTypes;
161                 break;
162             case FormComponentType::CHECKBOX:
163                 pCompatibleTypes = nCheckboxCompatibleTypes;
164                 break;
165             case FormComponentType::RADIOBUTTON:
166                 pCompatibleTypes = nRadiobuttonCompatibleTypes;
167                 break;
168 
169             case FormComponentType::TEXTFIELD:
170             {
171                 // both the normal text field, and the formatted field, claim to be a TEXTFIELD
172                 // need to distinguish by service name
173                 Reference< XServiceInfo > xSI( m_xControlModel, UNO_QUERY );
174                 OSL_ENSURE( xSI.is(), "EFormsHelper::canBindToDataType: a control model which has no service info?" );
175                 if ( xSI.is() )
176                 {
177                     if ( xSI->supportsService( SERVICE_COMPONENT_FORMATTEDFIELD ) )
178                     {
179                         pCompatibleTypes = nFormattedCompatibleTypes;
180                         break;
181                     }
182                 }
183                 // NO break here!
184             }
185             case FormComponentType::LISTBOX:
186             case FormComponentType::COMBOBOX:
187                 // edit fields and list/combo boxes can be bound to anything
188                 bCan = true;
189             }
190 
191             if ( !bCan && pCompatibleTypes )
192             {
193                 if ( _nDataType == -1 )
194                 {
195                     // the control can be bound to at least one type, and exactly this is being asked for
196                     bCan = true;
197                 }
198                 else
199                 {
200                     while ( *pCompatibleTypes && !bCan )
201                         bCan = ( *pCompatibleTypes++ == _nDataType );
202                 }
203             }
204         }
205         catch( const Exception& )
206         {
207         	OSL_ENSURE( sal_False, "EFormsHelper::canBindToDataType: caught an exception!" );
208         }
209 
210         return bCan;
211     }
212 
213 	//--------------------------------------------------------------------
214     bool EFormsHelper::isListEntrySink() const SAL_THROW(())
215     {
216         bool bIs = false;
217         try
218         {
219             Reference< XListEntrySink > xAsSink( m_xControlModel, UNO_QUERY );
220             bIs = xAsSink.is();
221         }
222         catch( const Exception& )
223         {
224         	OSL_ENSURE( sal_False, "EFormsHelper::isListEntrySink: caught an exception!" );
225         }
226         return bIs;
227     }
228 
229 	//--------------------------------------------------------------------
230     void EFormsHelper::impl_switchBindingListening_throw( bool _bDoListening, const Reference< XPropertyChangeListener >& _rxListener )
231     {
232         Reference< XPropertySet > xBindingProps;
233         if ( m_xBindableControl.is() )
234             xBindingProps = xBindingProps.query( m_xBindableControl->getValueBinding() );
235         if ( !xBindingProps.is() )
236             return;
237 
238         if ( _bDoListening )
239         {
240             xBindingProps->addPropertyChangeListener( ::rtl::OUString(), _rxListener );
241         }
242         else
243         {
244             xBindingProps->removePropertyChangeListener( ::rtl::OUString(), _rxListener );
245         }
246     }
247 
248 	//--------------------------------------------------------------------
249     void EFormsHelper::registerBindingListener( const Reference< XPropertyChangeListener >& _rxBindingListener )
250     {
251         if ( !_rxBindingListener.is() )
252             return;
253         impl_toggleBindingPropertyListening_throw( true, _rxBindingListener );
254     }
255 
256 	//--------------------------------------------------------------------
257     void EFormsHelper::impl_toggleBindingPropertyListening_throw( bool _bDoListen, const Reference< XPropertyChangeListener >& _rxConcreteListenerOrNull )
258     {
259         if ( !_bDoListen )
260         {
261             ::std::auto_ptr< ::cppu::OInterfaceIteratorHelper > pListenerIterator = m_aPropertyListeners.createIterator();
262             while ( pListenerIterator->hasMoreElements() )
263             {
264                 PropertyEventTranslation* pTranslator = dynamic_cast< PropertyEventTranslation* >( pListenerIterator->next() );
265                 OSL_ENSURE( pTranslator, "EFormsHelper::impl_toggleBindingPropertyListening_throw: invalid listener element in my container!" );
266                 if ( !pTranslator )
267                     continue;
268 
269                 Reference< XPropertyChangeListener > xEventSourceTranslator( pTranslator );
270                 if ( _rxConcreteListenerOrNull.is() )
271                 {
272                     if ( pTranslator->getDelegator() == _rxConcreteListenerOrNull )
273                     {
274                         impl_switchBindingListening_throw( false, xEventSourceTranslator );
275                         m_aPropertyListeners.removeListener( xEventSourceTranslator );
276                         break;
277                     }
278                 }
279                 else
280                 {
281                     impl_switchBindingListening_throw( false, xEventSourceTranslator );
282                 }
283             }
284         }
285         else
286         {
287             if ( _rxConcreteListenerOrNull.is() )
288             {
289                 Reference< XPropertyChangeListener > xEventSourceTranslator( new PropertyEventTranslation( _rxConcreteListenerOrNull, m_xBindableControl ) );
290                 m_aPropertyListeners.addListener( xEventSourceTranslator );
291                 impl_switchBindingListening_throw( true, xEventSourceTranslator );
292             }
293             else
294             {
295                 ::std::auto_ptr< ::cppu::OInterfaceIteratorHelper > pListenerIterator = m_aPropertyListeners.createIterator();
296                 while ( pListenerIterator->hasMoreElements() )
297                 {
298                     Reference< XPropertyChangeListener > xListener( pListenerIterator->next(), UNO_QUERY );
299                     impl_switchBindingListening_throw( true, xListener );
300                 }
301             }
302         }
303     }
304 
305 	//--------------------------------------------------------------------
306     void EFormsHelper::revokeBindingListener( const Reference< XPropertyChangeListener >& _rxBindingListener )
307     {
308         impl_toggleBindingPropertyListening_throw( false, _rxBindingListener );
309     }
310 
311 	//--------------------------------------------------------------------
312     void EFormsHelper::getFormModelNames( ::std::vector< ::rtl::OUString >& /* [out] */ _rModelNames ) const SAL_THROW(())
313     {
314         if ( m_xDocument.is() )
315         {
316             try
317             {
318                 _rModelNames.resize( 0 );
319 
320                 Reference< XNameContainer > xForms( m_xDocument->getXForms() );
321                 OSL_ENSURE( xForms.is(), "EFormsHelper::getFormModelNames: invalid forms container!" );
322                 if ( xForms.is() )
323                 {
324                     Sequence< ::rtl::OUString > aModelNames = xForms->getElementNames();
325                     _rModelNames.resize( aModelNames.getLength() );
326                     ::std::copy( aModelNames.getConstArray(), aModelNames.getConstArray() + aModelNames.getLength(),
327                         _rModelNames.begin()
328                     );
329                 }
330             }
331             catch( const Exception& )
332             {
333                 OSL_ENSURE( sal_False, "EFormsHelper::getFormModelNames: caught an exception!" );
334             }
335         }
336     }
337 
338     //--------------------------------------------------------------------
339     void EFormsHelper::getBindingNames( const ::rtl::OUString& _rModelName, ::std::vector< ::rtl::OUString >& /* [out] */ _rBindingNames ) const SAL_THROW(())
340     {
341         _rBindingNames.resize( 0 );
342         try
343         {
344             Reference< xforms::XModel > xModel( getFormModelByName( _rModelName ) );
345             if ( xModel.is() )
346             {
347                 Reference< XNameAccess > xBindings( xModel->getBindings(), UNO_QUERY );
348                 OSL_ENSURE( xBindings.is(), "EFormsHelper::getBindingNames: invalid bindings container obtained from the model!" );
349                 if ( xBindings.is() )
350                 {
351                     Sequence< ::rtl::OUString > aNames = xBindings->getElementNames();
352                     _rBindingNames.resize( aNames.getLength() );
353                     ::std::copy( aNames.getConstArray(), aNames.getConstArray() + aNames.getLength(), _rBindingNames.begin() );
354                 }
355             }
356         }
357         catch( const Exception& )
358         {
359         	OSL_ENSURE( sal_False, "EFormsHelper::getBindingNames: caught an exception!" );
360         }
361     }
362 
363 	//--------------------------------------------------------------------
364     Reference< xforms::XModel > EFormsHelper::getFormModelByName( const ::rtl::OUString& _rModelName ) const SAL_THROW(())
365     {
366         Reference< xforms::XModel > xReturn;
367         try
368         {
369             Reference< XNameContainer > xForms( m_xDocument->getXForms() );
370             OSL_ENSURE( xForms.is(), "EFormsHelper::getFormModelByName: invalid forms container!" );
371             if ( xForms.is() )
372                 OSL_VERIFY( xForms->getByName( _rModelName ) >>= xReturn );
373         }
374         catch( const Exception& )
375         {
376         	OSL_ENSURE( sal_False, "EFormsHelper::getFormModelByName: caught an exception!" );
377         }
378         return xReturn;
379     }
380 
381 	//--------------------------------------------------------------------
382     Reference< xforms::XModel > EFormsHelper::getCurrentFormModel() const SAL_THROW(())
383     {
384         Reference< xforms::XModel > xModel;
385         try
386         {
387             Reference< XPropertySet > xBinding( getCurrentBinding() );
388             if ( xBinding.is() )
389             {
390                 OSL_VERIFY( xBinding->getPropertyValue( PROPERTY_MODEL ) >>= xModel );
391             }
392         }
393         catch( const Exception& )
394         {
395         	OSL_ENSURE( sal_False, "EFormsHelper::getCurrentFormModel: caught an exception!" );
396         }
397         return xModel;
398     }
399 
400 	//--------------------------------------------------------------------
401     ::rtl::OUString EFormsHelper::getCurrentFormModelName() const SAL_THROW(())
402     {
403         ::rtl::OUString sModelName;
404         try
405         {
406             Reference< xforms::XModel > xFormsModel( getCurrentFormModel() );
407             if ( xFormsModel.is() )
408                 sModelName = xFormsModel->getID();
409         }
410         catch( const Exception& )
411         {
412         	OSL_ENSURE( sal_False, "EFormsHelper::getCurrentFormModel: caught an exception!" );
413         }
414         return sModelName;
415     }
416 
417     //--------------------------------------------------------------------
418     Reference< XPropertySet > EFormsHelper::getCurrentBinding() const SAL_THROW(())
419     {
420         Reference< XPropertySet > xBinding;
421 
422         try
423         {
424             if ( m_xBindableControl.is() )
425                 xBinding = xBinding.query( m_xBindableControl->getValueBinding() );
426         }
427         catch( const Exception& )
428         {
429         	OSL_ENSURE( sal_False, "EFormsHelper::getCurrentBinding: caught an exception!" );
430         }
431 
432         return xBinding;
433     }
434 
435     //--------------------------------------------------------------------
436     ::rtl::OUString EFormsHelper::getCurrentBindingName() const SAL_THROW(())
437     {
438         ::rtl::OUString sBindingName;
439         try
440         {
441             Reference< XPropertySet > xBinding( getCurrentBinding() );
442             if ( xBinding.is() )
443                 xBinding->getPropertyValue( PROPERTY_BINDING_ID ) >>= sBindingName;
444         }
445         catch( const Exception& )
446         {
447             OSL_ENSURE( sal_False, "EFormsHelper::getCurrentBindingName: caught an exception!" );
448         }
449         return sBindingName;
450     }
451 
452     //--------------------------------------------------------------------
453     Reference< XListEntrySource > EFormsHelper::getCurrentListSourceBinding() const SAL_THROW(())
454     {
455         Reference< XListEntrySource > xReturn;
456         try
457         {
458             Reference< XListEntrySink > xAsSink( m_xControlModel, UNO_QUERY );
459             OSL_ENSURE( xAsSink.is(), "EFormsHelper::getCurrentListSourceBinding: you should have used isListEntrySink before!" );
460             if ( xAsSink.is() )
461                 xReturn = xAsSink->getListEntrySource();
462         }
463         catch( const Exception& )
464         {
465         	OSL_ENSURE( sal_False, "EFormsHelper::getCurrentListSourceBinding: caught an exception!" );
466         }
467         return xReturn;
468     }
469 
470     //--------------------------------------------------------------------
471     void EFormsHelper::setListSourceBinding( const Reference< XListEntrySource >& _rxListSource ) SAL_THROW(())
472     {
473         try
474         {
475             Reference< XListEntrySink > xAsSink( m_xControlModel, UNO_QUERY );
476             OSL_ENSURE( xAsSink.is(), "EFormsHelper::setListSourceBinding: you should have used isListEntrySink before!" );
477             if ( xAsSink.is() )
478                 xAsSink->setListEntrySource( _rxListSource );
479         }
480         catch( const Exception& )
481         {
482         	OSL_ENSURE( sal_False, "EFormsHelper::setListSourceBinding: caught an exception!" );
483         }
484     }
485 
486     //--------------------------------------------------------------------
487     void EFormsHelper::setBinding( const Reference< ::com::sun::star::beans::XPropertySet >& _rxBinding ) SAL_THROW(())
488     {
489         if ( !m_xBindableControl.is() )
490             return;
491 
492         try
493         {
494             Reference< XPropertySet > xOldBinding( m_xBindableControl->getValueBinding(), UNO_QUERY );
495 
496             Reference< XValueBinding > xBinding( _rxBinding, UNO_QUERY );
497             OSL_ENSURE( xBinding.is() || !_rxBinding.is(), "EFormsHelper::setBinding: invalid binding!" );
498 
499             impl_toggleBindingPropertyListening_throw( false, NULL );
500             m_xBindableControl->setValueBinding( xBinding );
501             impl_toggleBindingPropertyListening_throw( true, NULL );
502 
503             ::std::set< ::rtl::OUString > aSet;
504             firePropertyChanges( xOldBinding, _rxBinding, aSet );
505         }
506         catch( const Exception& )
507         {
508         	OSL_ENSURE( sal_False, "EFormsHelper::setBinding: caught an exception!" );
509         }
510     }
511 
512     //--------------------------------------------------------------------
513     Reference< XPropertySet > EFormsHelper::getOrCreateBindingForModel( const ::rtl::OUString& _rTargetModel, const ::rtl::OUString& _rBindingName ) const SAL_THROW(())
514     {
515         OSL_ENSURE( _rBindingName.getLength(), "EFormsHelper::getOrCreateBindingForModel: invalid binding name!" );
516         return implGetOrCreateBinding( _rTargetModel, _rBindingName );
517     }
518 
519     //--------------------------------------------------------------------
520     Reference< XPropertySet > EFormsHelper::implGetOrCreateBinding( const ::rtl::OUString& _rTargetModel, const ::rtl::OUString& _rBindingName ) const SAL_THROW(())
521     {
522         OSL_ENSURE( !( !_rTargetModel.getLength() && _rBindingName .getLength() ), "EFormsHelper::implGetOrCreateBinding: no model, but a binding name?" );
523 
524         Reference< XPropertySet > xBinding;
525         try
526         {
527             ::rtl::OUString sTargetModel( _rTargetModel );
528             // determine the model which the binding should belong to
529             if ( !sTargetModel.getLength() )
530             {
531                 ::std::vector< ::rtl::OUString > aModelNames;
532                 getFormModelNames( aModelNames );
533                 if ( !aModelNames.empty() )
534                     sTargetModel = *aModelNames.begin();
535                 OSL_ENSURE( sTargetModel.getLength(), "EFormsHelper::implGetOrCreateBinding: unable to obtain a default model!" );
536             }
537             Reference< xforms::XModel > xModel( getFormModelByName( sTargetModel ) );
538             Reference< XNameAccess > xBindingNames( xModel.is() ? xModel->getBindings() : Reference< XSet >(), UNO_QUERY );
539             if ( xBindingNames.is() )
540             {
541                 // get or create the binding instance
542                 if ( _rBindingName.getLength() )
543                 {
544                     if ( xBindingNames->hasByName( _rBindingName ) )
545                         OSL_VERIFY( xBindingNames->getByName( _rBindingName ) >>= xBinding );
546                     else
547                     {
548                         xBinding = xModel->createBinding( );
549                         if ( xBinding.is() )
550                         {
551                             xBinding->setPropertyValue( PROPERTY_BINDING_ID, makeAny( _rBindingName ) );
552                             xModel->getBindings()->insert( makeAny( xBinding ) );
553                         }
554                     }
555                 }
556                 else
557                 {
558                     xBinding = xModel->createBinding( );
559                     if ( xBinding.is() )
560                     {
561                         // find a nice name for it
562                         String sBaseName( PcrRes( RID_STR_BINDING_UI_NAME ) );
563                         sBaseName += String::CreateFromAscii( " " );
564 			            String sNewName;
565                         sal_Int32 nNumber = 1;
566                         do
567                         {
568                             sNewName = sBaseName + ::rtl::OUString::valueOf( nNumber++ );
569                         }
570                         while ( xBindingNames->hasByName( sNewName ) );
571                         Reference< XNamed > xName( xBinding, UNO_QUERY_THROW );
572                         xName->setName( sNewName );
573                         // and insert into the model
574                         xModel->getBindings()->insert( makeAny( xBinding ) );
575                     }
576                 }
577             }
578         }
579         catch( const Exception& )
580         {
581             DBG_UNHANDLED_EXCEPTION();
582         }
583 
584         return xBinding;
585     }
586 
587     //--------------------------------------------------------------------
588     namespace
589     {
590         //................................................................
591         struct PropertyBagInserter : public ::std::unary_function< Property, void >
592         {
593         private:
594             PropertyBag& m_rProperties;
595 
596         public:
597             PropertyBagInserter( PropertyBag& rProperties ) : m_rProperties( rProperties ) { }
598 
599             void operator()( const Property& _rProp )
600             {
601                 m_rProperties.insert( _rProp );
602             }
603         };
604 
605         //................................................................
606         Reference< XPropertySetInfo > collectPropertiesGetInfo( const Reference< XPropertySet >& _rxProps, PropertyBag& _rBag )
607         {
608             Reference< XPropertySetInfo > xInfo;
609             if ( _rxProps.is() )
610                 xInfo = _rxProps->getPropertySetInfo();
611             if ( xInfo.is() )
612             {
613                 Sequence< Property > aProperties = xInfo->getProperties();
614                 ::std::for_each( aProperties.getConstArray(), aProperties.getConstArray() + aProperties.getLength(),
615                     PropertyBagInserter( _rBag )
616                 );
617             }
618             return xInfo;
619         }
620     }
621 
622 	//--------------------------------------------------------------------
623     ::rtl::OUString EFormsHelper::getModelElementUIName( const EFormsHelper::ModelElementType _eType, const Reference< XPropertySet >& _rxElement ) const SAL_THROW(())
624     {
625         ::rtl::OUString sUIName;
626         try
627         {
628             // determine the model which the element belongs to
629             Reference< xforms::XFormsUIHelper1 > xHelper;
630             if ( _rxElement.is() )
631                 _rxElement->getPropertyValue( PROPERTY_MODEL ) >>= xHelper;
632             OSL_ENSURE( xHelper.is(), "EFormsHelper::getModelElementUIName: invalid element or model!" );
633             if ( xHelper.is() )
634             {
635                 ::rtl::OUString sElementName = ( _eType == Submission ) ? xHelper->getSubmissionName( _rxElement, sal_True ) : xHelper->getBindingName( _rxElement, sal_True );
636                 Reference< xforms::XModel > xModel( xHelper, UNO_QUERY_THROW );
637                 sUIName = composeModelElementUIName( xModel->getID(), sElementName );
638             }
639         }
640         catch( const Exception& )
641         {
642         	OSL_ENSURE( sal_False, "EFormsHelper::getModelElementUIName: caught an exception!" );
643         }
644 
645         return sUIName;
646     }
647 
648 	//--------------------------------------------------------------------
649     Reference< XPropertySet > EFormsHelper::getModelElementFromUIName( const EFormsHelper::ModelElementType _eType, const ::rtl::OUString& _rUIName ) const SAL_THROW(())
650     {
651         const MapStringToPropertySet& rMapUINameToElement( ( _eType == Submission ) ? m_aSubmissionUINames : m_aBindingUINames );
652         MapStringToPropertySet::const_iterator pos = rMapUINameToElement.find( _rUIName );
653         OSL_ENSURE( pos != rMapUINameToElement.end(), "EFormsHelper::getModelElementFromUIName: didn't find it!" );
654 
655         return ( pos != rMapUINameToElement.end() ) ? pos->second : Reference< XPropertySet >();
656     }
657 
658 	//--------------------------------------------------------------------
659     void EFormsHelper::getAllElementUINames( const ModelElementType _eType, ::std::vector< ::rtl::OUString >& /* [out] */ _rElementNames, bool _bPrepentEmptyEntry )
660     {
661         MapStringToPropertySet& rMapUINameToElement( ( _eType == Submission ) ? m_aSubmissionUINames : m_aBindingUINames );
662         rMapUINameToElement.clear();
663         _rElementNames.resize( 0 );
664 
665         if ( _bPrepentEmptyEntry )
666             rMapUINameToElement[ ::rtl::OUString() ] = Reference< XPropertySet >();
667 
668         try
669         {
670             // obtain the model names
671             ::std::vector< ::rtl::OUString > aModels;
672             getFormModelNames( aModels );
673             _rElementNames.reserve( aModels.size() * 2 );    // heuristics
674 
675             // for every model, obtain the element
676             for ( ::std::vector< ::rtl::OUString >::const_iterator pModelName = aModels.begin();
677                   pModelName != aModels.end();
678                   ++pModelName
679                 )
680             {
681                 Reference< xforms::XModel > xModel = getFormModelByName( *pModelName );
682                 OSL_ENSURE( xModel.is(), "EFormsHelper::getAllElementUINames: inconsistency in the models!" );
683                 Reference< xforms::XFormsUIHelper1 > xHelper( xModel, UNO_QUERY );
684 
685                 Reference< XIndexAccess > xElements;
686                 if ( xModel.is() )
687                     xElements = xElements.query( ( _eType == Submission ) ? xModel->getSubmissions() : xModel->getBindings() );
688                 if ( !xElements.is() )
689                     break;
690 
691                 sal_Int32 nElementCount = xElements->getCount();
692                 for ( sal_Int32 i = 0; i < nElementCount; ++i )
693                 {
694                     Reference< XPropertySet > xElement( xElements->getByIndex( i ), UNO_QUERY );
695                     OSL_ENSURE( xElement.is(), "EFormsHelper::getAllElementUINames: empty element!" );
696                     if ( !xElement.is() )
697                         continue;
698 #if OSL_DEBUG_LEVEL > 0
699                     {
700                         Reference< xforms::XModel > xElementsModel;
701                         xElement->getPropertyValue( PROPERTY_MODEL ) >>= xElementsModel;
702                         OSL_ENSURE( xElementsModel == xModel, "EFormsHelper::getAllElementUINames: inconsistency in the model-element relationship!" );
703                         if ( !( xElementsModel == xModel ) )
704                             xElement->setPropertyValue( PROPERTY_MODEL, makeAny( xModel ) );
705                     }
706 #endif
707                     ::rtl::OUString sElementName = ( _eType == Submission ) ? xHelper->getSubmissionName( xElement, sal_True ) : xHelper->getBindingName( xElement, sal_True );
708                     ::rtl::OUString sUIName = composeModelElementUIName( *pModelName, sElementName );
709 
710                     OSL_ENSURE( rMapUINameToElement.find( sUIName ) == rMapUINameToElement.end(), "EFormsHelper::getAllElementUINames: duplicate name!" );
711                     rMapUINameToElement.insert( MapStringToPropertySet::value_type( sUIName, xElement ) );
712                 }
713             }
714         }
715         catch( const Exception& )
716         {
717         	OSL_ENSURE( sal_False, "EFormsHelper::getAllElementUINames: caught an exception!" );
718         }
719 
720         _rElementNames.resize( rMapUINameToElement.size() );
721         ::std::transform( rMapUINameToElement.begin(), rMapUINameToElement.end(), _rElementNames.begin(), ::std::select1st< MapStringToPropertySet::value_type >() );
722     }
723 
724     //--------------------------------------------------------------------
725     void EFormsHelper::firePropertyChange( const ::rtl::OUString& _rName, const Any& _rOldValue, const Any& _rNewValue ) const
726     {
727         if ( m_aPropertyListeners.empty() )
728             return;
729 
730         if ( _rOldValue == _rNewValue )
731             return;
732 
733         try
734         {
735             PropertyChangeEvent aEvent;
736 
737             aEvent.Source = m_xBindableControl.get();
738             aEvent.PropertyName = _rName;
739             aEvent.OldValue = _rOldValue;
740             aEvent.NewValue = _rNewValue;
741 
742             const_cast< EFormsHelper* >( this )->m_aPropertyListeners.notify( aEvent, &XPropertyChangeListener::propertyChange );
743         }
744         catch( const Exception& )
745         {
746             OSL_ENSURE( sal_False, "EFormsHelper::firePropertyChange: caught an exception!" );
747         }
748     }
749 
750     //--------------------------------------------------------------------
751     void EFormsHelper::firePropertyChanges( const Reference< XPropertySet >& _rxOldProps, const Reference< XPropertySet >& _rxNewProps, ::std::set< ::rtl::OUString >& _rFilter ) const
752     {
753         if ( m_aPropertyListeners.empty() )
754             return;
755 
756         try
757         {
758             PropertyBag aProperties;
759             Reference< XPropertySetInfo > xOldInfo = collectPropertiesGetInfo( _rxOldProps, aProperties );
760             Reference< XPropertySetInfo > xNewInfo = collectPropertiesGetInfo( _rxNewProps, aProperties );
761 
762             for ( PropertyBag::const_iterator aProp = aProperties.begin();
763                   aProp != aProperties.end();
764                   ++aProp
765                 )
766             {
767                 if ( _rFilter.find( aProp->Name ) != _rFilter.end() )
768                     continue;
769 
770                 Any aOldValue( NULL, aProp->Type );
771                 if ( xOldInfo.is() && xOldInfo->hasPropertyByName( aProp->Name ) )
772                     aOldValue = _rxOldProps->getPropertyValue( aProp->Name );
773 
774                 Any aNewValue( NULL, aProp->Type );
775                 if ( xNewInfo.is() && xNewInfo->hasPropertyByName( aProp->Name ) )
776                     aNewValue = _rxNewProps->getPropertyValue( aProp->Name );
777 
778                 firePropertyChange( aProp->Name, aOldValue, aNewValue );
779             }
780         }
781         catch( const Exception& )
782         {
783         	OSL_ENSURE( sal_False, "EFormsHelper::firePropertyChanges: caught an exception!" );
784         }
785     }
786 
787 //........................................................................
788 } // namespace pcr
789 //........................................................................
790 
791