xref: /aoo41x/main/svx/source/form/formcontroller.cxx (revision cdf0e10c)
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_svx.hxx"
30 
31 #include "fmcontrolbordermanager.hxx"
32 #include "fmcontrollayout.hxx"
33 #include "formcontroller.hxx"
34 #include "formfeaturedispatcher.hxx"
35 #include "fmdocumentclassification.hxx"
36 #include "formcontrolling.hxx"
37 #include "fmprop.hrc"
38 #include "svx/dialmgr.hxx"
39 #include "svx/fmresids.hrc"
40 #include "fmservs.hxx"
41 #include "svx/fmtools.hxx"
42 #include "fmurl.hxx"
43 
44 /** === begin UNO includes === **/
45 #include <com/sun/star/awt/FocusChangeReason.hpp>
46 #include <com/sun/star/awt/XCheckBox.hpp>
47 #include <com/sun/star/awt/XComboBox.hpp>
48 #include <com/sun/star/awt/XListBox.hpp>
49 #include <com/sun/star/awt/XVclWindowPeer.hpp>
50 #include <com/sun/star/beans/NamedValue.hpp>
51 #include <com/sun/star/beans/PropertyAttribute.hpp>
52 #include <com/sun/star/container/XIdentifierReplace.hpp>
53 #include <com/sun/star/form/TabulatorCycle.hpp>
54 #include <com/sun/star/form/validation/XValidatableFormComponent.hpp>
55 #include <com/sun/star/form/XBoundComponent.hpp>
56 #include <com/sun/star/form/XBoundControl.hpp>
57 #include <com/sun/star/form/XGridControl.hpp>
58 #include <com/sun/star/form/XLoadable.hpp>
59 #include <com/sun/star/form/XReset.hpp>
60 #include <com/sun/star/frame/XController.hpp>
61 #include <com/sun/star/sdb/ParametersRequest.hpp>
62 #include <com/sun/star/sdb/RowChangeAction.hpp>
63 #include <com/sun/star/sdb/XInteractionSupplyParameters.hpp>
64 #include <com/sun/star/sdbc/ColumnValue.hpp>
65 #include <com/sun/star/sdbc/DataType.hpp>
66 #include <com/sun/star/util/XURLTransformer.hpp>
67 #include <com/sun/star/form/runtime/FormOperations.hpp>
68 #include <com/sun/star/form/runtime/FormFeature.hpp>
69 #include <com/sun/star/container/XContainer.hpp>
70 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
71 #include <com/sun/star/util/XNumberFormatter.hpp>
72 #include <com/sun/star/sdb/SQLContext.hpp>
73 #include <com/sun/star/sdb/XColumn.hpp>
74 /** === end UNO includes === **/
75 
76 #include <comphelper/enumhelper.hxx>
77 #include <comphelper/extract.hxx>
78 #include <comphelper/interaction.hxx>
79 #include <comphelper/namedvaluecollection.hxx>
80 #include <comphelper/propagg.hxx>
81 #include <comphelper/property.hxx>
82 #include <comphelper/sequence.hxx>
83 #include <comphelper/uno3.hxx>
84 #include <comphelper/flagguard.hxx>
85 #include <cppuhelper/queryinterface.hxx>
86 #include <cppuhelper/typeprovider.hxx>
87 #include <toolkit/controls/unocontrol.hxx>
88 #include <toolkit/helper/vclunohelper.hxx>
89 #include <tools/debug.hxx>
90 #include <tools/diagnose_ex.h>
91 #include <tools/shl.hxx>
92 #include <vcl/msgbox.hxx>
93 #include <vcl/svapp.hxx>
94 #include <vos/mutex.hxx>
95 #include <rtl/logfile.hxx>
96 
97 #include <algorithm>
98 #include <functional>
99 
100 using namespace ::com::sun::star;
101 using namespace ::comphelper;
102 using namespace ::connectivity;
103 using namespace ::connectivity::simple;
104 
105 //------------------------------------------------------------------
106 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL
107     FormController_NewInstance_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & _rxORB )
108 {
109     return *( new ::svxform::FormController( _rxORB ) );
110 }
111 
112 namespace svxform
113 {
114 
115     /** === begin UNO using === **/
116     using ::com::sun::star::sdb::XColumn;
117     using ::com::sun::star::awt::XControl;
118     using ::com::sun::star::awt::XTabController;
119     using ::com::sun::star::awt::XToolkit;
120     using ::com::sun::star::awt::XWindowPeer;
121     using ::com::sun::star::form::XGrid;
122     using ::com::sun::star::beans::XPropertySet;
123     using ::com::sun::star::uno::UNO_SET_THROW;
124     using ::com::sun::star::uno::UNO_QUERY_THROW;
125     using ::com::sun::star::container::XIndexAccess;
126     using ::com::sun::star::uno::Exception;
127     using ::com::sun::star::uno::XInterface;
128     using ::com::sun::star::uno::UNO_QUERY;
129     using ::com::sun::star::uno::Sequence;
130     using ::com::sun::star::uno::Reference;
131     using ::com::sun::star::beans::XPropertySetInfo;
132     using ::com::sun::star::beans::PropertyValue;
133     using ::com::sun::star::uno::RuntimeException;
134     using ::com::sun::star::lang::IndexOutOfBoundsException;
135     using ::com::sun::star::sdb::XInteractionSupplyParameters;
136     using ::com::sun::star::awt::XTextComponent;
137     using ::com::sun::star::awt::XTextListener;
138     using ::com::sun::star::uno::Any;
139     using ::com::sun::star::frame::XDispatch;
140     using ::com::sun::star::lang::XMultiServiceFactory;
141     using ::com::sun::star::uno::XAggregation;
142     using ::com::sun::star::uno::Type;
143     using ::com::sun::star::lang::IllegalArgumentException;
144     using ::com::sun::star::sdbc::XConnection;
145     using ::com::sun::star::sdbc::XRowSet;
146     using ::com::sun::star::sdbc::XDatabaseMetaData;
147     using ::com::sun::star::util::XNumberFormatsSupplier;
148     using ::com::sun::star::util::XNumberFormatter;
149     using ::com::sun::star::sdbcx::XColumnsSupplier;
150     using ::com::sun::star::container::XNameAccess;
151     using ::com::sun::star::lang::EventObject;
152     using ::com::sun::star::beans::Property;
153     using ::com::sun::star::container::XEnumeration;
154     using ::com::sun::star::form::XFormComponent;
155     using ::com::sun::star::form::runtime::XFormOperations;
156     using ::com::sun::star::form::runtime::FilterEvent;
157     using ::com::sun::star::form::runtime::XFilterControllerListener;
158     using ::com::sun::star::awt::XControlContainer;
159     using ::com::sun::star::container::XIdentifierReplace;
160     using ::com::sun::star::lang::WrappedTargetException;
161     using ::com::sun::star::form::XFormControllerListener;
162     using ::com::sun::star::awt::XWindow;
163     using ::com::sun::star::sdbc::XResultSet;
164     using ::com::sun::star::awt::XControlModel;
165     using ::com::sun::star::awt::XTabControllerModel;
166     using ::com::sun::star::beans::PropertyChangeEvent;
167     using ::com::sun::star::form::validation::XValidatableFormComponent;
168     using ::com::sun::star::form::XLoadable;
169     using ::com::sun::star::script::XEventAttacherManager;
170     using ::com::sun::star::form::XBoundControl;
171     using ::com::sun::star::beans::XPropertyChangeListener;
172     using ::com::sun::star::awt::TextEvent;
173     using ::com::sun::star::form::XBoundComponent;
174     using ::com::sun::star::awt::XCheckBox;
175     using ::com::sun::star::awt::XComboBox;
176     using ::com::sun::star::awt::XListBox;
177     using ::com::sun::star::awt::ItemEvent;
178     using ::com::sun::star::util::XModifyListener;
179     using ::com::sun::star::form::XReset;
180     using ::com::sun::star::frame::XDispatchProviderInterception;
181     using ::com::sun::star::form::XGridControl;
182     using ::com::sun::star::awt::XVclWindowPeer;
183     using ::com::sun::star::form::validation::XValidator;
184     using ::com::sun::star::awt::FocusEvent;
185     using ::com::sun::star::sdb::SQLContext;
186     using ::com::sun::star::container::XChild;
187     using ::com::sun::star::form::TabulatorCycle_RECORDS;
188     using ::com::sun::star::container::ContainerEvent;
189     using ::com::sun::star::lang::DisposedException;
190     using ::com::sun::star::lang::Locale;
191     using ::com::sun::star::beans::NamedValue;
192     using ::com::sun::star::lang::NoSupportException;
193     using ::com::sun::star::sdb::RowChangeEvent;
194     using ::com::sun::star::frame::XStatusListener;
195     using ::com::sun::star::frame::XDispatchProviderInterceptor;
196     using ::com::sun::star::sdb::SQLErrorEvent;
197     using ::com::sun::star::form::DatabaseParameterEvent;
198     using ::com::sun::star::sdb::ParametersRequest;
199     using ::com::sun::star::task::XInteractionRequest;
200     using ::com::sun::star::util::URL;
201     using ::com::sun::star::frame::FeatureStateEvent;
202     using ::com::sun::star::form::runtime::XFormControllerContext;
203     using ::com::sun::star::task::XInteractionHandler;
204     using ::com::sun::star::form::runtime::FormOperations;
205     using ::com::sun::star::container::XContainer;
206     using ::com::sun::star::sdbc::SQLWarning;
207     /** === end UNO using === **/
208     namespace ColumnValue = ::com::sun::star::sdbc::ColumnValue;
209     namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
210     namespace FocusChangeReason = ::com::sun::star::awt::FocusChangeReason;
211     namespace RowChangeAction = ::com::sun::star::sdb::RowChangeAction;
212     namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
213     namespace DataType = ::com::sun::star::sdbc::DataType;
214 
215 //==============================================================================
216 // ColumnInfo
217 //==============================================================================
218 struct ColumnInfo
219 {
220     // information about the column itself
221     Reference< XColumn >    xColumn;
222     sal_Int32               nNullable;
223     sal_Bool                bAutoIncrement;
224     sal_Bool                bReadOnly;
225     ::rtl::OUString         sName;
226 
227     // information about the control(s) bound to this column
228 
229     /// the first control which is bound to the given column, and which requires input
230     Reference< XControl >   xFirstControlWithInputRequired;
231     /** the first grid control which contains a column which is bound to the given database column, and requires
232         input
233     */
234     Reference< XGrid >      xFirstGridWithInputRequiredColumn;
235     /** if xFirstControlWithInputRequired is a grid control, then nRequiredGridColumn specifies the position
236         of the grid column which is actually bound
237     */
238     sal_Int32               nRequiredGridColumn;
239 
240     ColumnInfo()
241         :xColumn()
242         ,nNullable( ColumnValue::NULLABLE_UNKNOWN )
243         ,bAutoIncrement( sal_False )
244         ,bReadOnly( sal_False )
245         ,sName()
246         ,xFirstControlWithInputRequired()
247         ,xFirstGridWithInputRequiredColumn()
248         ,nRequiredGridColumn( -1 )
249     {
250     }
251 };
252 
253 //==============================================================================
254 //= ColumnInfoCache
255 //==============================================================================
256 class ColumnInfoCache
257 {
258 public:
259     ColumnInfoCache( const Reference< XColumnsSupplier >& _rxColSupplier );
260 
261     size_t        getColumnCount() const { return m_aColumns.size(); }
262     const ColumnInfo&   getColumnInfo( size_t _pos );
263 
264     bool    controlsInitialized() const { return m_bControlsInitialized; }
265     void    initializeControls( const Sequence< Reference< XControl > >& _rControls );
266     void    deinitializeControls();
267 
268 private:
269     typedef ::std::vector< ColumnInfo > ColumnInfos;
270     ColumnInfos                         m_aColumns;
271     bool                                m_bControlsInitialized;
272 };
273 
274 //------------------------------------------------------------------------------
275 ColumnInfoCache::ColumnInfoCache( const Reference< XColumnsSupplier >& _rxColSupplier )
276     :m_aColumns()
277     ,m_bControlsInitialized( false )
278 {
279     try
280     {
281         m_aColumns.clear();
282 
283         Reference< XColumnsSupplier > xSupplyCols( _rxColSupplier, UNO_SET_THROW );
284         Reference< XIndexAccess > xColumns( xSupplyCols->getColumns(), UNO_QUERY_THROW );
285         sal_Int32 nColumnCount = xColumns->getCount();
286         m_aColumns.reserve( nColumnCount );
287 
288         Reference< XPropertySet >   xColumnProps;
289         for ( sal_Int32 i = 0; i < nColumnCount; ++i )
290         {
291             ColumnInfo aColInfo;
292             aColInfo.xColumn.set( xColumns->getByIndex(i), UNO_QUERY_THROW );
293 
294             xColumnProps.set( aColInfo.xColumn, UNO_QUERY_THROW );
295             OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_ISNULLABLE ) >>= aColInfo.nNullable );
296             OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_AUTOINCREMENT ) >>= aColInfo.bAutoIncrement );
297             OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_NAME ) >>= aColInfo.sName );
298             OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_ISREADONLY ) >>= aColInfo.bReadOnly );
299 
300             m_aColumns.push_back( aColInfo );
301         }
302     }
303     catch( const Exception& )
304     {
305     	DBG_UNHANDLED_EXCEPTION();
306     }
307 }
308 
309 //------------------------------------------------------------------------------
310 namespace
311 {
312     bool lcl_isBoundTo( const Reference< XPropertySet >& _rxControlModel, const Reference< XInterface >& _rxNormDBField )
313     {
314         Reference< XInterface > xNormBoundField( _rxControlModel->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY );
315         return ( xNormBoundField.get() == _rxNormDBField.get() );
316     }
317 
318     bool lcl_isInputRequired( const Reference< XPropertySet >& _rxControlModel )
319     {
320         sal_Bool bInputRequired = sal_True;
321         OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_INPUT_REQUIRED ) >>= bInputRequired );
322         return ( bInputRequired != sal_False );
323     }
324 
325     void lcl_resetColumnControlInfo( ColumnInfo& _rColInfo )
326     {
327         _rColInfo.xFirstControlWithInputRequired.clear();
328         _rColInfo.xFirstGridWithInputRequiredColumn.clear();
329         _rColInfo.nRequiredGridColumn = -1;
330     }
331 }
332 
333 //------------------------------------------------------------------------------
334 void ColumnInfoCache::deinitializeControls()
335 {
336     for (   ColumnInfos::iterator col = m_aColumns.begin();
337             col != m_aColumns.end();
338             ++col
339         )
340     {
341         lcl_resetColumnControlInfo( *col );
342     }
343 }
344 
345 //------------------------------------------------------------------------------
346 void ColumnInfoCache::initializeControls( const Sequence< Reference< XControl > >& _rControls )
347 {
348     try
349     {
350         // for every of our known columns, find the controls which are bound to this column
351         for (   ColumnInfos::iterator col = m_aColumns.begin();
352                 col != m_aColumns.end();
353                 ++col
354             )
355         {
356             OSL_ENSURE( !col->xFirstControlWithInputRequired.is() && !col->xFirstGridWithInputRequiredColumn.is()
357                 && ( col->nRequiredGridColumn == -1 ), "ColumnInfoCache::initializeControls: called me twice?" );
358 
359             lcl_resetColumnControlInfo( *col );
360 
361             Reference< XInterface > xNormColumn( col->xColumn, UNO_QUERY_THROW );
362 
363             const Reference< XControl >* pControl( _rControls.getConstArray() );
364             const Reference< XControl >* pControlEnd( pControl + _rControls.getLength() );
365             for ( ; pControl != pControlEnd; ++pControl )
366             {
367                 if ( !pControl->is() )
368                     continue;
369 
370                 Reference< XPropertySet > xModel( (*pControl)->getModel(), UNO_QUERY_THROW );
371                 Reference< XPropertySetInfo > xModelPSI( xModel->getPropertySetInfo(), UNO_SET_THROW );
372 
373                 // special handling for grid controls
374                 Reference< XGrid > xGrid( *pControl, UNO_QUERY );
375                 if ( xGrid.is() )
376                 {
377                     Reference< XIndexAccess > xGridColAccess( xModel, UNO_QUERY_THROW );
378                     sal_Int32 gridColCount = xGridColAccess->getCount();
379                     sal_Int32 gridCol = 0;
380                     for ( gridCol = 0; gridCol < gridColCount; ++gridCol )
381                     {
382                         Reference< XPropertySet > xGridColumnModel( xGridColAccess->getByIndex( gridCol ), UNO_QUERY_THROW );
383 
384                         if  (   !lcl_isBoundTo( xGridColumnModel, xNormColumn )
385                             ||  !lcl_isInputRequired( xGridColumnModel )
386                             )
387                             continue;   // with next grid column
388 
389                         break;
390                     }
391 
392                     if ( gridCol < gridColCount )
393                     {
394                         // found a grid column which is bound to the given
395                         col->xFirstGridWithInputRequiredColumn = xGrid;
396                         col->nRequiredGridColumn = gridCol;
397                         break;
398                     }
399 
400                     continue;   // with next control
401                 }
402 
403                 if  (   !xModelPSI->hasPropertyByName( FM_PROP_BOUNDFIELD )
404                     ||  !lcl_isBoundTo( xModel, xNormColumn )
405                     ||  !lcl_isInputRequired( xModel )
406                     )
407                     continue;   // with next control
408 
409                 break;
410             }
411 
412             if ( pControl == pControlEnd )
413                 // did not find a control which is bound to this particular column, and for which the input is required
414                 continue;   // with next DB column
415 
416             col->xFirstControlWithInputRequired = *pControl;
417         }
418     }
419     catch( const Exception& )
420     {
421     	DBG_UNHANDLED_EXCEPTION();
422     }
423 
424     m_bControlsInitialized = true;
425 }
426 
427 //------------------------------------------------------------------------------
428 const ColumnInfo& ColumnInfoCache::getColumnInfo( size_t _pos )
429 {
430     if ( _pos >= m_aColumns.size() )
431         throw IndexOutOfBoundsException();
432 
433     return m_aColumns[ _pos ];
434 }
435 
436 //==================================================================
437 // OParameterContinuation
438 //==================================================================
439 class OParameterContinuation : public OInteraction< XInteractionSupplyParameters >
440 {
441     Sequence< PropertyValue >       m_aValues;
442 
443 public:
444     OParameterContinuation() { }
445 
446     Sequence< PropertyValue >   getValues() const { return m_aValues; }
447 
448 // XInteractionSupplyParameters
449     virtual void SAL_CALL setParameters( const Sequence< PropertyValue >& _rValues ) throw(RuntimeException);
450 };
451 
452 //------------------------------------------------------------------
453 void SAL_CALL OParameterContinuation::setParameters( const Sequence< PropertyValue >& _rValues ) throw(RuntimeException)
454 {
455     m_aValues = _rValues;
456 }
457 
458 //==================================================================
459 // FmXAutoControl
460 //==================================================================
461 struct FmFieldInfo
462 {
463     rtl::OUString       aFieldName;
464     Reference< XPropertySet >   xField;
465     Reference< XTextComponent >  xText;
466 
467     FmFieldInfo(const Reference< XPropertySet >& _xField, const Reference< XTextComponent >& _xText)
468         :xField(_xField)
469         ,xText(_xText)
470     {xField->getPropertyValue(FM_PROP_NAME) >>= aFieldName;}
471 };
472 
473 //==================================================================
474 // FmXAutoControl
475 //==================================================================
476 class FmXAutoControl: public UnoControl
477 
478 {
479     friend Reference< XInterface > SAL_CALL FmXAutoControl_NewInstance_Impl();
480 
481 public:
482     FmXAutoControl( const ::comphelper::ComponentContext& i_context )
483         :UnoControl( i_context.getLegacyServiceFactory() )
484     {
485     }
486 
487     virtual ::rtl::OUString GetComponentServiceName() {return ::rtl::OUString::createFromAscii("Edit");}
488     virtual void SAL_CALL createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer >  & rParentPeer ) throw( RuntimeException );
489 
490 protected:
491     virtual void ImplSetPeerProperty( const ::rtl::OUString& rPropName, const Any& rVal );
492 };
493 
494 //------------------------------------------------------------------------------
495 void FmXAutoControl::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer >  & rParentPeer ) throw( RuntimeException )
496 {
497     UnoControl::createPeer( rxToolkit, rParentPeer );
498 
499     Reference< XTextComponent >  xText(getPeer() , UNO_QUERY);
500     if (xText.is())
501     {
502         xText->setText(::rtl::OUString(String(SVX_RES(RID_STR_AUTOFIELD))));
503         xText->setEditable(sal_False);
504     }
505 }
506 
507 //------------------------------------------------------------------------------
508 void FmXAutoControl::ImplSetPeerProperty( const ::rtl::OUString& rPropName, const Any& rVal )
509 {
510     // these properties are ignored
511     if (rPropName == FM_PROP_TEXT)
512         return;
513 
514     UnoControl::ImplSetPeerProperty( rPropName, rVal );
515 }
516 
517 //------------------------------------------------------------------------------
518 IMPL_LINK( FormController, OnActivateTabOrder, void*, /*EMPTYTAG*/ )
519 {
520     activateTabOrder();
521     return 1;
522 }
523 
524 //------------------------------------------------------------------------------
525 struct UpdateAllListeners : public ::std::unary_function< Reference< XDispatch >, bool >
526 {
527     bool operator()( const Reference< XDispatch >& _rxDispatcher ) const
528     {
529         static_cast< ::svx::OSingleFeatureDispatcher* >( _rxDispatcher.get() )->updateAllListeners();
530         // the return is a dummy only so we can use this struct in a std::compose1 call
531         return true;
532     }
533 };
534 //..............................................................................
535 IMPL_LINK( FormController, OnInvalidateFeatures, void*, /*_pNotInterestedInThisParam*/ )
536 {
537     ::osl::MutexGuard aGuard( m_aMutex );
538     for ( ::std::set< sal_Int16 >::const_iterator aLoop = m_aInvalidFeatures.begin();
539           aLoop != m_aInvalidFeatures.end();
540           ++aLoop
541         )
542     {
543         DispatcherContainer::const_iterator aDispatcherPos = m_aFeatureDispatchers.find( *aLoop );
544         if ( aDispatcherPos != m_aFeatureDispatchers.end() )
545         {
546             // TODO: for the real and actual listener notifications, we should release
547             // our mutex
548             UpdateAllListeners( )( aDispatcherPos->second );
549         }
550     }
551     return 1;
552 }
553 
554 /*************************************************************************/
555 
556 DBG_NAME( FormController )
557 //------------------------------------------------------------------
558 FormController::FormController(const Reference< XMultiServiceFactory > & _rxORB )
559 				  :FormController_BASE( m_aMutex )
560 				  ,OPropertySetHelper( FormController_BASE::rBHelper )
561                   ,OSQLParserClient( _rxORB )
562 				  ,m_aContext( _rxORB )
563 				  ,m_aActivateListeners(m_aMutex)
564 				  ,m_aModifyListeners(m_aMutex)
565 				  ,m_aErrorListeners(m_aMutex)
566 				  ,m_aDeleteListeners(m_aMutex)
567 				  ,m_aRowSetApproveListeners(m_aMutex)
568 				  ,m_aParameterListeners(m_aMutex)
569                   ,m_aFilterListeners(m_aMutex)
570                   ,m_pControlBorderManager( new ::svxform::ControlBorderManager )
571                   ,m_xFormOperations()
572 				  ,m_aMode( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DataMode" ) ) )
573 				  ,m_aLoadEvent( LINK( this, FormController, OnLoad ) )
574 				  ,m_aToggleEvent( LINK( this, FormController, OnToggleAutoFields ) )
575                   ,m_aActivationEvent( LINK( this, FormController, OnActivated ) )
576                   ,m_aDeactivationEvent( LINK( this, FormController, OnDeactivated ) )
577 				  ,m_nCurrentFilterPosition(-1)
578 				  ,m_bCurrentRecordModified(sal_False)
579 				  ,m_bCurrentRecordNew(sal_False)
580 				  ,m_bLocked(sal_False)
581 				  ,m_bDBConnection(sal_False)
582 				  ,m_bCycle(sal_False)
583 				  ,m_bCanInsert(sal_False)
584 				  ,m_bCanUpdate(sal_False)
585 				  ,m_bCommitLock(sal_False)
586 				  ,m_bModified(sal_False)
587                   ,m_bControlsSorted(sal_False)
588                   ,m_bFiltering(sal_False)
589 				  ,m_bAttachEvents(sal_True)
590 				  ,m_bDetachEvents(sal_True)
591                   ,m_bAttemptedHandlerCreation( false )
592                   ,m_bSuspendFilterTextListening( false )
593 {
594 	DBG_CTOR( FormController, NULL );
595 
596 	::comphelper::increment(m_refCount);
597 	{
598         {
599 		    m_xAggregate = Reference< XAggregation >(
600                 m_aContext.createComponent( "com.sun.star.awt.TabController" ),
601                 UNO_QUERY
602             );
603 		    DBG_ASSERT( m_xAggregate.is(), "FormController::FormController : could not create my aggregate !" );
604 		    m_xTabController = Reference< XTabController >( m_xAggregate, UNO_QUERY );
605         }
606 
607     	if ( m_xAggregate.is() )
608 	        m_xAggregate->setDelegator( *this );
609     }
610     ::comphelper::decrement(m_refCount);
611 
612     m_aTabActivationTimer.SetTimeout( 500 );
613     m_aTabActivationTimer.SetTimeoutHdl( LINK( this, FormController, OnActivateTabOrder ) );
614 
615     m_aFeatureInvalidationTimer.SetTimeout( 200 );
616     m_aFeatureInvalidationTimer.SetTimeoutHdl( LINK( this, FormController, OnInvalidateFeatures ) );
617 }
618 
619 //------------------------------------------------------------------
620 FormController::~FormController()
621 {
622     {
623 	    ::osl::MutexGuard aGuard( m_aMutex );
624 
625         m_aLoadEvent.CancelPendingCall();
626         m_aToggleEvent.CancelPendingCall();
627         m_aActivationEvent.CancelPendingCall();
628         m_aDeactivationEvent.CancelPendingCall();
629 
630         if ( m_aTabActivationTimer.IsActive() )
631             m_aTabActivationTimer.Stop();
632     }
633 
634     if ( m_aFeatureInvalidationTimer.IsActive() )
635         m_aFeatureInvalidationTimer.Stop();
636 
637     disposeAllFeaturesAndDispatchers();
638 
639     if ( m_xFormOperations.is() )
640         m_xFormOperations->dispose();
641     m_xFormOperations.clear();
642 
643     // Freigeben der Aggregation
644     if ( m_xAggregate.is() )
645     {
646         m_xAggregate->setDelegator( NULL );
647         m_xAggregate.clear();
648     }
649 
650     DELETEZ( m_pControlBorderManager );
651 
652 	DBG_DTOR( FormController, NULL );
653 }
654 
655 // -----------------------------------------------------------------------------
656 void SAL_CALL FormController::acquire() throw ()
657 {
658     FormController_BASE::acquire();
659 }
660 
661 // -----------------------------------------------------------------------------
662 void SAL_CALL FormController::release() throw ()
663 {
664     FormController_BASE::release();
665 }
666 
667 //------------------------------------------------------------------
668 Any SAL_CALL FormController::queryInterface( const Type& _rType ) throw(RuntimeException)
669 {
670     Any aRet = FormController_BASE::queryInterface( _rType );
671     if ( !aRet.hasValue() )
672         aRet = OPropertySetHelper::queryInterface( _rType );
673     if ( !aRet.hasValue() )
674         aRet = m_xAggregate->queryAggregation( _rType );
675     return aRet;
676 }
677 
678 //------------------------------------------------------------------------------
679 Sequence< sal_Int8 > SAL_CALL FormController::getImplementationId() throw( RuntimeException )
680 {
681     static ::cppu::OImplementationId* pId = NULL;
682 	if  ( !pId )
683 	{
684         ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
685 		if ( !pId )
686 		{
687 			static ::cppu::OImplementationId aId;
688 			pId = &aId;
689 		}
690 	}
691 	return pId->getImplementationId();
692 }
693 
694 //------------------------------------------------------------------------------
695 Sequence< Type > SAL_CALL FormController::getTypes(  ) throw(RuntimeException)
696 {
697     return comphelper::concatSequences(
698         FormController_BASE::getTypes(),
699         ::cppu::OPropertySetHelper::getTypes()
700     );
701 }
702 
703 // XServiceInfo
704 //------------------------------------------------------------------------------
705 sal_Bool SAL_CALL FormController::supportsService(const ::rtl::OUString& ServiceName) throw( RuntimeException )
706 {
707     Sequence< ::rtl::OUString> aSNL(getSupportedServiceNames());
708     const ::rtl::OUString * pArray = aSNL.getConstArray();
709     for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
710         if( pArray[i] == ServiceName )
711             return sal_True;
712     return sal_False;
713 }
714 
715 //------------------------------------------------------------------------------
716 ::rtl::OUString SAL_CALL FormController::getImplementationName() throw( RuntimeException )
717 {
718     return ::rtl::OUString::createFromAscii( "org.openoffice.comp.svx.FormController" );
719 }
720 
721 //------------------------------------------------------------------------------
722 Sequence< ::rtl::OUString> SAL_CALL FormController::getSupportedServiceNames(void) throw( RuntimeException )
723 {
724     // service names which are supported only, but cannot be used to created an
725     // instance at a service factory
726     Sequence< ::rtl::OUString > aNonCreatableServiceNames( 1 );
727     aNonCreatableServiceNames[ 0 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.FormControllerDispatcher" ) );
728 
729     // services which can be used to created an instance at a service factory
730     Sequence< ::rtl::OUString > aCreatableServiceNames( getSupportedServiceNames_Static() );
731     return ::comphelper::concatSequences( aCreatableServiceNames, aNonCreatableServiceNames );
732 }
733 
734 //------------------------------------------------------------------------------
735 sal_Bool SAL_CALL FormController::approveReset(const EventObject& /*rEvent*/) throw( RuntimeException )
736 {
737     return sal_True;
738 }
739 
740 //------------------------------------------------------------------------------
741 void SAL_CALL FormController::resetted(const EventObject& rEvent) throw( RuntimeException )
742 {
743     ::osl::MutexGuard aGuard(m_aMutex);
744     if (getCurrentControl().is() &&  (getCurrentControl()->getModel() == rEvent.Source))
745         m_bModified = sal_False;
746 }
747 
748 //------------------------------------------------------------------------------
749 Sequence< ::rtl::OUString> FormController::getSupportedServiceNames_Static(void)
750 {
751     static Sequence< ::rtl::OUString> aServices;
752     if (!aServices.getLength())
753     {
754         aServices.realloc(2);
755         aServices.getArray()[0] = FM_FORM_CONTROLLER;
756         aServices.getArray()[1] = ::rtl::OUString::createFromAscii("com.sun.star.awt.control.TabController");
757     }
758     return aServices;
759 }
760 
761 // -----------------------------------------------------------------------------
762 namespace
763 {
764     struct ResetComponentText : public ::std::unary_function< Reference< XTextComponent >, void >
765     {
766         void operator()( const Reference< XTextComponent >& _rxText )
767         {
768             _rxText->setText( ::rtl::OUString() );
769         }
770     };
771 
772     struct RemoveComponentTextListener : public ::std::unary_function< Reference< XTextComponent >, void >
773     {
774         RemoveComponentTextListener( const Reference< XTextListener >& _rxListener )
775             :m_xListener( _rxListener )
776         {
777         }
778 
779         void operator()( const Reference< XTextComponent >& _rxText )
780         {
781             _rxText->removeTextListener( m_xListener );
782         }
783 
784     private:
785         Reference< XTextListener >  m_xListener;
786     };
787 }
788 
789 // -----------------------------------------------------------------------------
790 void FormController::impl_setTextOnAllFilter_throw()
791 {
792     m_bSuspendFilterTextListening = true;
793     ::comphelper::FlagGuard aResetFlag( m_bSuspendFilterTextListening );
794 
795     // reset the text for all controls
796     ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), ResetComponentText() );
797 
798     if ( m_aFilterRows.empty() )
799         // nothing to do anymore
800         return;
801 
802     if ( m_nCurrentFilterPosition < 0 )
803         return;
804 
805     // set the text for all filters
806     OSL_ENSURE( m_aFilterRows.size() > (size_t)m_nCurrentFilterPosition,
807         "FormController::impl_setTextOnAllFilter_throw: m_nCurrentFilterPosition too big" );
808 
809 	if ( (size_t)m_nCurrentFilterPosition < m_aFilterRows.size() )
810 	{
811         FmFilterRow& rRow = m_aFilterRows[ m_nCurrentFilterPosition ];
812         for (   FmFilterRow::const_iterator iter2 = rRow.begin();
813                 iter2 != rRow.end();
814                 ++iter2
815             )
816         {
817             iter2->first->setText( iter2->second );
818         }
819     }
820 }
821 // OPropertySetHelper
822 //------------------------------------------------------------------------------
823 sal_Bool FormController::convertFastPropertyValue( Any & /*rConvertedValue*/, Any & /*rOldValue*/,
824                                             sal_Int32 /*nHandle*/, const Any& /*rValue*/ )
825                 throw( IllegalArgumentException )
826 {
827     return sal_False;
828 }
829 
830 //------------------------------------------------------------------------------
831 void FormController::setFastPropertyValue_NoBroadcast( sal_Int32 /*nHandle*/, const Any& /*rValue*/ )
832                          throw( Exception )
833 {
834 }
835 
836 //------------------------------------------------------------------------------
837 void FormController::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
838 {
839     switch (nHandle)
840     {
841         case FM_ATTR_FILTER:
842         {
843             ::rtl::OUStringBuffer aFilter;
844 			OStaticDataAccessTools aStaticTools;
845             Reference<XConnection> xConnection(aStaticTools.getRowSetConnection(Reference< XRowSet>(m_xModelAsIndex, UNO_QUERY)));
846             if (xConnection.is())
847             {
848                 Reference< XDatabaseMetaData> xMetaData(xConnection->getMetaData());
849                 Reference< XNumberFormatsSupplier> xFormatSupplier( aStaticTools.getNumberFormats( xConnection, sal_True ) );
850                 Reference< XNumberFormatter> xFormatter( m_aContext.createComponent( "com.sun.star.util.NumberFormatter" ), UNO_QUERY_THROW );
851                 xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
852 
853                 Reference< XColumnsSupplier> xSupplyCols(m_xModelAsIndex, UNO_QUERY);
854                 Reference< XNameAccess> xFields(xSupplyCols->getColumns(), UNO_QUERY);
855 
856                 ::rtl::OUString aQuote( xMetaData->getIdentifierQuoteString() );
857 
858                 // now add the filter rows
859                 try
860                 {
861                     for ( FmFilterRows::const_iterator row = m_aFilterRows.begin(); row != m_aFilterRows.end(); ++row )
862                     {
863                         const FmFilterRow& rRow = *row;
864 
865                         if ( rRow.empty() )
866                             continue;
867 
868                         ::rtl::OUStringBuffer aRowFilter;
869                         for ( FmFilterRow::const_iterator condition = rRow.begin(); condition != rRow.end(); ++condition )
870                         {
871                             // get the field of the controls map
872                             Reference< XControl > xControl( condition->first, UNO_QUERY_THROW );
873                             Reference< XPropertySet > xModelProps( xControl->getModel(), UNO_QUERY_THROW );
874                             Reference< XPropertySet > xField( xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY_THROW );
875 
876                             ::rtl::OUString sFilterValue( condition->second );
877 
878                             ::rtl::OUString sErrorMsg, sCriteria;
879                             const ::rtl::Reference< ISQLParseNode > xParseNode =
880                                 predicateTree( sErrorMsg, sFilterValue, xFormatter, xField );
881                             OSL_ENSURE( xParseNode.is(), "FormController::getFastPropertyValue: could not parse the field value predicate!" );
882                             if ( xParseNode.is() )
883                             {
884                                 // don't use a parse context here, we need it unlocalized
885                                 xParseNode->parseNodeToStr( sCriteria, xConnection, NULL );
886                                 if ( condition != rRow.begin() )
887                                     aRowFilter.appendAscii( " AND " );
888                                 aRowFilter.append( sCriteria );
889                             }
890                         }
891                         if ( aRowFilter.getLength() > 0 )
892                         {
893                             if ( aFilter.getLength() )
894                                 aFilter.appendAscii( " OR " );
895 
896                             aFilter.appendAscii( "( " );
897                             aFilter.append( aRowFilter.makeStringAndClear() );
898                             aFilter.appendAscii( " )" );
899                         }
900                     }
901                 }
902                 catch( const Exception& )
903                 {
904                     DBG_UNHANDLED_EXCEPTION();
905                     aFilter.setLength(0);
906                 }
907             }
908             rValue <<= aFilter.makeStringAndClear();
909         }
910         break;
911 
912         case FM_ATTR_FORM_OPERATIONS:
913             rValue <<= m_xFormOperations;
914             break;
915     }
916 }
917 
918 //------------------------------------------------------------------------------
919 Reference< XPropertySetInfo >  FormController::getPropertySetInfo() throw( RuntimeException )
920 {
921     static Reference< XPropertySetInfo >  xInfo( createPropertySetInfo( getInfoHelper() ) );
922     return xInfo;
923 }
924 
925 //------------------------------------------------------------------------------
926 #define DECL_PROP_CORE(varname, type) \
927 pDesc[nPos++] = Property(FM_PROP_##varname, FM_ATTR_##varname, ::getCppuType((const type*)0),
928 
929 
930 #define DECL_PROP1(varname, type, attrib1)  \
931     DECL_PROP_CORE(varname, type) PropertyAttribute::attrib1)
932 
933 //------------------------------------------------------------------------------
934 void FormController::fillProperties(
935         Sequence< Property >& /* [out] */ _rProps,
936         Sequence< Property >& /* [out] */ /*_rAggregateProps*/
937         ) const
938 {
939     _rProps.realloc(2);
940     sal_Int32 nPos = 0;
941     Property* pDesc = _rProps.getArray();
942     DECL_PROP1(FILTER, rtl::OUString, READONLY);
943     DECL_PROP1(FORM_OPERATIONS, Reference< XFormOperations >, READONLY);
944 }
945 
946 //------------------------------------------------------------------------------
947 ::cppu::IPropertyArrayHelper& FormController::getInfoHelper()
948 {
949     return *getArrayHelper();
950 }
951 
952 // XFilterController
953 //------------------------------------------------------------------------------
954 void SAL_CALL FormController::addFilterControllerListener( const Reference< XFilterControllerListener >& _Listener ) throw( RuntimeException )
955 {
956     m_aFilterListeners.addInterface( _Listener );
957 }
958 
959 //------------------------------------------------------------------------------
960 void SAL_CALL FormController::removeFilterControllerListener( const Reference< XFilterControllerListener >& _Listener ) throw( RuntimeException )
961 {
962     m_aFilterListeners.removeInterface( _Listener );
963 }
964 
965 //------------------------------------------------------------------------------
966 ::sal_Int32 SAL_CALL FormController::getFilterComponents() throw( ::com::sun::star::uno::RuntimeException )
967 {
968     ::osl::MutexGuard aGuard( m_aMutex );
969     impl_checkDisposed_throw();
970 
971     return m_aFilterComponents.size();
972 }
973 
974 //------------------------------------------------------------------------------
975 ::sal_Int32 SAL_CALL FormController::getDisjunctiveTerms() throw( ::com::sun::star::uno::RuntimeException )
976 {
977     ::osl::MutexGuard aGuard( m_aMutex );
978     impl_checkDisposed_throw();
979 
980     return m_aFilterRows.size();
981 }
982 
983 //------------------------------------------------------------------------------
984 void SAL_CALL FormController::setPredicateExpression( ::sal_Int32 _Component, ::sal_Int32 _Term, const ::rtl::OUString& _PredicateExpression ) throw( RuntimeException, IndexOutOfBoundsException )
985 {
986     ::osl::MutexGuard aGuard( m_aMutex );
987     impl_checkDisposed_throw();
988 
989     if ( ( _Component < 0 ) || ( _Component >= getFilterComponents() ) || ( _Term < 0 ) || ( _Term >= getDisjunctiveTerms() ) )
990         throw IndexOutOfBoundsException( ::rtl::OUString(), *this );
991 
992     Reference< XTextComponent > xText( m_aFilterComponents[ _Component ] );
993     xText->setText( _PredicateExpression );
994 
995     FmFilterRow& rFilterRow = m_aFilterRows[ _Term ];
996     if ( _PredicateExpression.getLength() )
997         rFilterRow[ xText ] = _PredicateExpression;
998     else
999         rFilterRow.erase( xText );
1000 }
1001 
1002 //------------------------------------------------------------------------------
1003 Reference< XControl > FormController::getFilterComponent( ::sal_Int32 _Component ) throw( RuntimeException, IndexOutOfBoundsException )
1004 {
1005     ::osl::MutexGuard aGuard( m_aMutex );
1006     impl_checkDisposed_throw();
1007 
1008     if ( ( _Component < 0 ) || ( _Component >= getFilterComponents() ) )
1009         throw IndexOutOfBoundsException( ::rtl::OUString(), *this );
1010 
1011     return Reference< XControl >( m_aFilterComponents[ _Component ], UNO_QUERY );
1012 }
1013 
1014 //------------------------------------------------------------------------------
1015 Sequence< Sequence< ::rtl::OUString > > FormController::getPredicateExpressions() throw( RuntimeException )
1016 {
1017     ::osl::MutexGuard aGuard( m_aMutex );
1018     impl_checkDisposed_throw();
1019 
1020     Sequence< Sequence< ::rtl::OUString > > aExpressions( m_aFilterRows.size() );
1021     sal_Int32 termIndex = 0;
1022     for (   FmFilterRows::const_iterator row = m_aFilterRows.begin();
1023             row != m_aFilterRows.end();
1024             ++row, ++termIndex
1025         )
1026     {
1027         const FmFilterRow& rRow( *row );
1028 
1029         Sequence< ::rtl::OUString > aConjunction( m_aFilterComponents.size() );
1030         sal_Int32 componentIndex = 0;
1031         for (   FilterComponents::const_iterator comp = m_aFilterComponents.begin();
1032                 comp != m_aFilterComponents.end();
1033                 ++comp, ++componentIndex
1034             )
1035         {
1036             FmFilterRow::const_iterator predicate = rRow.find( *comp );
1037             if ( predicate != rRow.end() )
1038                 aConjunction[ componentIndex ] = predicate->second;
1039         }
1040 
1041         aExpressions[ termIndex ] = aConjunction;
1042     }
1043 
1044     return aExpressions;
1045 }
1046 
1047 //------------------------------------------------------------------------------
1048 void SAL_CALL FormController::removeDisjunctiveTerm( ::sal_Int32 _Term ) throw (IndexOutOfBoundsException, RuntimeException)
1049 {
1050     // SYNCHRONIZED -->
1051     ::osl::ClearableMutexGuard aGuard( m_aMutex );
1052     impl_checkDisposed_throw();
1053 
1054     if ( ( _Term < 0 ) || ( _Term >= getDisjunctiveTerms() ) )
1055         throw IndexOutOfBoundsException( ::rtl::OUString(), *this );
1056 
1057     // if the to-be-deleted row is our current row, we need to shift
1058     if ( _Term == m_nCurrentFilterPosition )
1059     {
1060         if ( m_nCurrentFilterPosition < sal_Int32( m_aFilterRows.size() - 1 ) )
1061             ++m_nCurrentFilterPosition;
1062         else
1063             --m_nCurrentFilterPosition;
1064     }
1065 
1066     FmFilterRows::iterator pos = m_aFilterRows.begin() + _Term;
1067     m_aFilterRows.erase( pos );
1068 
1069     // adjust m_nCurrentFilterPosition if the removed row preceeded it
1070     if ( _Term < m_nCurrentFilterPosition )
1071         --m_nCurrentFilterPosition;
1072 
1073     OSL_POSTCOND( ( m_nCurrentFilterPosition < 0 ) == ( m_aFilterRows.empty() ),
1074         "FormController::removeDisjunctiveTerm: inconsistency!" );
1075 
1076     // update the texts in the filter controls
1077     impl_setTextOnAllFilter_throw();
1078 
1079     FilterEvent aEvent;
1080     aEvent.Source = *this;
1081     aEvent.DisjunctiveTerm = _Term;
1082     aGuard.clear();
1083     // <-- SYNCHRONIZED
1084 
1085     m_aFilterListeners.notifyEach( &XFilterControllerListener::disjunctiveTermRemoved, aEvent );
1086 }
1087 
1088 //------------------------------------------------------------------------------
1089 void SAL_CALL FormController::appendEmptyDisjunctiveTerm() throw (RuntimeException)
1090 {
1091     // SYNCHRONIZED -->
1092     ::osl::ClearableMutexGuard aGuard( m_aMutex );
1093     impl_checkDisposed_throw();
1094 
1095     impl_appendEmptyFilterRow( aGuard );
1096     // <-- SYNCHRONIZED
1097 }
1098 
1099 //------------------------------------------------------------------------------
1100 ::sal_Int32 SAL_CALL FormController::getActiveTerm() throw (RuntimeException)
1101 {
1102     ::osl::MutexGuard aGuard( m_aMutex );
1103     impl_checkDisposed_throw();
1104 
1105     return m_nCurrentFilterPosition;
1106 }
1107 
1108 //------------------------------------------------------------------------------
1109 void SAL_CALL FormController::setActiveTerm( ::sal_Int32 _ActiveTerm ) throw (IndexOutOfBoundsException, RuntimeException)
1110 {
1111     ::osl::MutexGuard aGuard( m_aMutex );
1112     impl_checkDisposed_throw();
1113 
1114     if ( ( _ActiveTerm < 0 ) || ( _ActiveTerm >= getDisjunctiveTerms() ) )
1115         throw IndexOutOfBoundsException( ::rtl::OUString(), *this );
1116 
1117     if ( _ActiveTerm == getActiveTerm() )
1118         return;
1119 
1120     m_nCurrentFilterPosition = _ActiveTerm;
1121     impl_setTextOnAllFilter_throw();
1122 }
1123 
1124 // XElementAccess
1125 //------------------------------------------------------------------------------
1126 sal_Bool SAL_CALL FormController::hasElements(void) throw( RuntimeException )
1127 {
1128     ::osl::MutexGuard aGuard( m_aMutex );
1129     return !m_aChilds.empty();
1130 }
1131 
1132 //------------------------------------------------------------------------------
1133 Type SAL_CALL  FormController::getElementType(void) throw( RuntimeException )
1134 {
1135     return ::getCppuType((const Reference< XFormController>*)0);
1136 
1137 }
1138 
1139 // XEnumerationAccess
1140 //------------------------------------------------------------------------------
1141 Reference< XEnumeration > SAL_CALL  FormController::createEnumeration(void) throw( RuntimeException )
1142 {
1143     ::osl::MutexGuard aGuard( m_aMutex );
1144     return new ::comphelper::OEnumerationByIndex(this);
1145 }
1146 
1147 // XIndexAccess
1148 //------------------------------------------------------------------------------
1149 sal_Int32 SAL_CALL FormController::getCount(void) throw( RuntimeException )
1150 {
1151 	::osl::MutexGuard aGuard( m_aMutex );
1152     return m_aChilds.size();
1153 }
1154 
1155 //------------------------------------------------------------------------------
1156 Any SAL_CALL FormController::getByIndex(sal_Int32 Index) throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException )
1157 {
1158 	::osl::MutexGuard aGuard( m_aMutex );
1159 	if (Index < 0 ||
1160 		Index >= (sal_Int32)m_aChilds.size())
1161 		throw IndexOutOfBoundsException();
1162 
1163     return makeAny( m_aChilds[ Index ] );
1164 }
1165 
1166 //  EventListener
1167 //------------------------------------------------------------------------------
1168 void SAL_CALL FormController::disposing(const EventObject& e) throw( RuntimeException )
1169 {
1170     // Ist der Container disposed worden
1171 	::osl::MutexGuard aGuard( m_aMutex );
1172     Reference< XControlContainer >  xContainer(e.Source, UNO_QUERY);
1173     if (xContainer.is())
1174     {
1175         setContainer(Reference< XControlContainer > ());
1176     }
1177     else
1178     {
1179         // ist ein Control disposed worden
1180         Reference< XControl >  xControl(e.Source, UNO_QUERY);
1181         if (xControl.is())
1182         {
1183             if (getContainer().is())
1184                 removeControl(xControl);
1185         }
1186     }
1187 }
1188 
1189 // OComponentHelper
1190 //-----------------------------------------------------------------------------
1191 void FormController::disposeAllFeaturesAndDispatchers() SAL_THROW(())
1192 {
1193     for ( DispatcherContainer::iterator aDispatcher = m_aFeatureDispatchers.begin();
1194           aDispatcher != m_aFeatureDispatchers.end();
1195           ++aDispatcher
1196         )
1197     {
1198         try
1199         {
1200             ::comphelper::disposeComponent( aDispatcher->second );
1201         }
1202         catch( const Exception& )
1203         {
1204             DBG_UNHANDLED_EXCEPTION();
1205         }
1206     }
1207     m_aFeatureDispatchers.clear();
1208 }
1209 
1210 //-----------------------------------------------------------------------------
1211 void FormController::disposing(void)
1212 {
1213     EventObject aEvt( *this );
1214 
1215     // if we're still active, simulate a "deactivated" event
1216     if ( m_xActiveControl.is() )
1217         m_aActivateListeners.notifyEach( &XFormControllerListener::formDeactivated, aEvt );
1218 
1219     // notify all our listeners
1220     m_aActivateListeners.disposeAndClear(aEvt);
1221     m_aModifyListeners.disposeAndClear(aEvt);
1222     m_aErrorListeners.disposeAndClear(aEvt);
1223     m_aDeleteListeners.disposeAndClear(aEvt);
1224     m_aRowSetApproveListeners.disposeAndClear(aEvt);
1225     m_aParameterListeners.disposeAndClear(aEvt);
1226     m_aFilterListeners.disposeAndClear(aEvt);
1227 
1228 	removeBoundFieldListener();
1229 	stopFiltering();
1230 
1231     m_pControlBorderManager->restoreAll();
1232 
1233     m_aFilterRows.clear();
1234 
1235     ::osl::MutexGuard aGuard( m_aMutex );
1236     m_xActiveControl = NULL;
1237     implSetCurrentControl( NULL );
1238 
1239     // clean up our children
1240     for (FmFormControllers::const_iterator i = m_aChilds.begin();
1241         i != m_aChilds.end(); i++)
1242     {
1243         // search the position of the model within the form
1244         Reference< XFormComponent >  xForm((*i)->getModel(), UNO_QUERY);
1245         sal_uInt32 nPos = m_xModelAsIndex->getCount();
1246         Reference< XFormComponent > xTemp;
1247         for( ; nPos; )
1248         {
1249 
1250             m_xModelAsIndex->getByIndex( --nPos ) >>= xTemp;
1251             if ( xForm.get() == xTemp.get() )
1252             {
1253                 Reference< XInterface > xIfc( *i, UNO_QUERY );
1254                 m_xModelAsManager->detach( nPos, xIfc );
1255                 break;
1256             }
1257         }
1258 
1259         Reference< XComponent > (*i, UNO_QUERY)->dispose();
1260     }
1261     m_aChilds.clear();
1262 
1263     disposeAllFeaturesAndDispatchers();
1264 
1265     if ( m_xFormOperations.is() )
1266         m_xFormOperations->dispose();
1267     m_xFormOperations.clear();
1268 
1269     if (m_bDBConnection)
1270         unload();
1271 
1272     setContainer( NULL );
1273     setModel( NULL );
1274     setParent( NULL );
1275 
1276     ::comphelper::disposeComponent( m_xComposer );
1277 
1278     m_bDBConnection = sal_False;
1279 }
1280 
1281 //------------------------------------------------------------------------------
1282 namespace
1283 {
1284     static bool lcl_shouldUseDynamicControlBorder( const Reference< XInterface >& _rxForm, const Any& _rDynamicColorProp )
1285     {
1286         bool bDoUse = false;
1287         if ( !( _rDynamicColorProp >>= bDoUse ) )
1288         {
1289             DocumentType eDocType = DocumentClassification::classifyHostDocument( _rxForm );
1290             return ControlLayouter::useDynamicBorderColor( eDocType );
1291         }
1292         return bDoUse;
1293     }
1294 }
1295 
1296 //------------------------------------------------------------------------------
1297 void SAL_CALL FormController::propertyChange(const PropertyChangeEvent& evt) throw( RuntimeException )
1298 {
1299     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1300     if ( evt.PropertyName == FM_PROP_BOUNDFIELD )
1301     {
1302 		Reference<XPropertySet> xOldBound;
1303 		evt.OldValue >>= xOldBound;
1304 		if ( !xOldBound.is() && evt.NewValue.hasValue() )
1305 		{
1306 			Reference< XControlModel > xControlModel(evt.Source,UNO_QUERY);
1307 			Reference< XControl > xControl = findControl(m_aControls,xControlModel,sal_False,sal_False);
1308 			if ( xControl.is() )
1309 			{
1310 				startControlModifyListening( xControl );
1311 				Reference<XPropertySet> xProp(xControlModel,UNO_QUERY);
1312 				if ( xProp.is() )
1313 					xProp->removePropertyChangeListener(FM_PROP_BOUNDFIELD, this);
1314 			}
1315 		}
1316     }
1317     else
1318     {
1319 		sal_Bool bModifiedChanged = (evt.PropertyName == FM_PROP_ISMODIFIED);
1320 		sal_Bool bNewChanged = (evt.PropertyName == FM_PROP_ISNEW);
1321 		if (bModifiedChanged || bNewChanged)
1322 		{
1323 			::osl::MutexGuard aGuard( m_aMutex );
1324 			if (bModifiedChanged)
1325 				m_bCurrentRecordModified = ::comphelper::getBOOL(evt.NewValue);
1326 			else
1327 				m_bCurrentRecordNew = ::comphelper::getBOOL(evt.NewValue);
1328 
1329 			// toggle the locking
1330 			if (m_bLocked != determineLockState())
1331 			{
1332 				m_bLocked = !m_bLocked;
1333 				setLocks();
1334 				if (isListeningForChanges())
1335 					startListening();
1336 				else
1337 					stopListening();
1338 			}
1339 
1340 			if ( bNewChanged )
1341 				m_aToggleEvent.Call();
1342 
1343 			if (!m_bCurrentRecordModified)
1344 				m_bModified = sal_False;
1345 		}
1346         else if ( evt.PropertyName == FM_PROP_DYNAMIC_CONTROL_BORDER )
1347         {
1348             bool bEnable = lcl_shouldUseDynamicControlBorder( evt.Source, evt.NewValue );
1349             if ( bEnable )
1350             {
1351                 m_pControlBorderManager->enableDynamicBorderColor();
1352                 if ( m_xActiveControl.is() )
1353                     m_pControlBorderManager->focusGained( m_xActiveControl.get() );
1354             }
1355             else
1356             {
1357                 m_pControlBorderManager->disableDynamicBorderColor();
1358             }
1359         }
1360 	}
1361 }
1362 
1363 //------------------------------------------------------------------------------
1364 bool FormController::replaceControl( const Reference< XControl >& _rxExistentControl, const Reference< XControl >& _rxNewControl )
1365 {
1366     bool bSuccess = false;
1367     try
1368     {
1369         Reference< XIdentifierReplace > xContainer( getContainer(), UNO_QUERY );
1370         DBG_ASSERT( xContainer.is(), "FormController::replaceControl: yes, it's not required by the service description, but XItentifierReplaces would be nice!" );
1371         if ( xContainer.is() )
1372         {
1373             // look up the ID of _rxExistentControl
1374             Sequence< sal_Int32 > aIdentifiers( xContainer->getIdentifiers() );
1375             const sal_Int32* pIdentifiers = aIdentifiers.getConstArray();
1376             const sal_Int32* pIdentifiersEnd = aIdentifiers.getConstArray() + aIdentifiers.getLength();
1377             for ( ; pIdentifiers != pIdentifiersEnd; ++pIdentifiers )
1378             {
1379                 Reference< XControl > xCheck( xContainer->getByIdentifier( *pIdentifiers ), UNO_QUERY );
1380                 if ( xCheck == _rxExistentControl )
1381                     break;
1382             }
1383             DBG_ASSERT( pIdentifiers != pIdentifiersEnd, "FormController::replaceControl: did not find the control in the container!" );
1384             if ( pIdentifiers != pIdentifiersEnd )
1385             {
1386                 bool bReplacedWasActive = ( m_xActiveControl.get() == _rxExistentControl.get() );
1387                 bool bReplacedWasCurrent = ( m_xCurrentControl.get() == _rxExistentControl.get() );
1388 
1389                 if ( bReplacedWasActive )
1390                 {
1391                     m_xActiveControl = NULL;
1392                     implSetCurrentControl( NULL );
1393                 }
1394                 else if ( bReplacedWasCurrent )
1395                 {
1396                     implSetCurrentControl( _rxNewControl );
1397                 }
1398 
1399                 // carry over the model
1400                 _rxNewControl->setModel( _rxExistentControl->getModel() );
1401 
1402                 xContainer->replaceByIdentifer( *pIdentifiers, makeAny( _rxNewControl ) );
1403                 bSuccess = true;
1404 
1405                 if ( bReplacedWasActive )
1406                 {
1407                     Reference< XWindow > xControlWindow( _rxNewControl, UNO_QUERY );
1408                     if ( xControlWindow.is() )
1409                         xControlWindow->setFocus();
1410                 }
1411             }
1412         }
1413     }
1414     catch( const Exception& )
1415     {
1416         DBG_UNHANDLED_EXCEPTION();
1417     }
1418 
1419     Reference< XControl > xDisposeIt( bSuccess ? _rxExistentControl : _rxNewControl );
1420     ::comphelper::disposeComponent( xDisposeIt );
1421     return bSuccess;
1422 }
1423 
1424 //------------------------------------------------------------------------------
1425 void FormController::toggleAutoFields(sal_Bool bAutoFields)
1426 {
1427     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1428 
1429 
1430     Sequence< Reference< XControl > > aControlsCopy( m_aControls );
1431     const Reference< XControl >* pControls = aControlsCopy.getConstArray();
1432     sal_Int32 nControls = aControlsCopy.getLength();
1433 
1434     if (bAutoFields)
1435     {
1436         // as we don't want new controls to be attached to the scripting environment
1437         // we change attach flags
1438         m_bAttachEvents = sal_False;
1439         for (sal_Int32 i = nControls; i > 0;)
1440         {
1441             Reference< XControl > xControl = pControls[--i];
1442             if (xControl.is())
1443             {
1444                 Reference< XPropertySet >  xSet(xControl->getModel(), UNO_QUERY);
1445                 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
1446                 {
1447                     // does the model use a bound field ?
1448                     Reference< XPropertySet >  xField;
1449                     xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
1450 
1451                     // is it a autofield?
1452                     if  (   xField.is()
1453                         &&  ::comphelper::hasProperty( FM_PROP_AUTOINCREMENT, xField )
1454                         &&  ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_AUTOINCREMENT ) )
1455                         )
1456                     {
1457                         replaceControl( xControl, new FmXAutoControl( m_aContext ) );
1458                     }
1459                 }
1460             }
1461         }
1462         m_bAttachEvents = sal_True;
1463     }
1464     else
1465     {
1466         m_bDetachEvents = sal_False;
1467         for (sal_Int32 i = nControls; i > 0;)
1468         {
1469             Reference< XControl > xControl = pControls[--i];
1470             if (xControl.is())
1471             {
1472                 Reference< XPropertySet >  xSet(xControl->getModel(), UNO_QUERY);
1473                 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
1474                 {
1475                     // does the model use a bound field ?
1476                     Reference< XPropertySet >  xField;
1477                     xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
1478 
1479                     // is it a autofield?
1480                     if  (   xField.is()
1481                         &&  ::comphelper::hasProperty( FM_PROP_AUTOINCREMENT, xField )
1482                         &&  ::comphelper::getBOOL( xField->getPropertyValue(FM_PROP_AUTOINCREMENT ) )
1483                         )
1484                     {
1485                         ::rtl::OUString sServiceName;
1486                         OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DEFAULTCONTROL ) >>= sServiceName );
1487                         Reference< XControl > xNewControl( m_aContext.createComponent( sServiceName ), UNO_QUERY );
1488                         replaceControl( xControl, xNewControl );
1489                     }
1490                 }
1491             }
1492         }
1493         m_bDetachEvents = sal_True;
1494     }
1495 }
1496 
1497 //------------------------------------------------------------------------------
1498 IMPL_LINK(FormController, OnToggleAutoFields, void*, EMPTYARG)
1499 {
1500     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1501 
1502     toggleAutoFields(m_bCurrentRecordNew);
1503     return 1L;
1504 }
1505 
1506 // XTextListener
1507 //------------------------------------------------------------------------------
1508 void SAL_CALL FormController::textChanged(const TextEvent& e) throw( RuntimeException )
1509 {
1510     // SYNCHRONIZED -->
1511     ::osl::ClearableMutexGuard aGuard( m_aMutex );
1512     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1513     if ( !m_bFiltering )
1514     {
1515         impl_onModify();
1516         return;
1517     }
1518 
1519     if ( m_bSuspendFilterTextListening )
1520         return;
1521 
1522     Reference< XTextComponent >  xText(e.Source,UNO_QUERY);
1523     ::rtl::OUString aText = xText->getText();
1524 
1525     if ( m_aFilterRows.empty() )
1526         appendEmptyDisjunctiveTerm();
1527 
1528     // Suchen der aktuellen Row
1529     if ( ( (size_t)m_nCurrentFilterPosition >= m_aFilterRows.size() ) || ( m_nCurrentFilterPosition < 0 ) )
1530     {
1531 	    OSL_ENSURE( false, "FormController::textChanged: m_nCurrentFilterPosition is wrong!" );
1532         return;
1533     }
1534 
1535 	FmFilterRow& rRow = m_aFilterRows[ m_nCurrentFilterPosition ];
1536 
1537 	// do we have a new filter
1538 	if (aText.getLength())
1539 		rRow[xText] = aText;
1540 	else
1541 	{
1542 		// do we have the control in the row
1543 		FmFilterRow::iterator iter = rRow.find(xText);
1544 		// erase the entry out of the row
1545 		if (iter != rRow.end())
1546 			rRow.erase(iter);
1547 	}
1548 
1549     // multiplex the event to our FilterControllerListeners
1550     FilterEvent aEvent;
1551     aEvent.Source = *this;
1552     aEvent.FilterComponent = ::std::find( m_aFilterComponents.begin(), m_aFilterComponents.end(), xText ) - m_aFilterComponents.begin();
1553     aEvent.DisjunctiveTerm = getActiveTerm();
1554     aEvent.PredicateExpression = aText;
1555 
1556     aGuard.clear();
1557     // <-- SYNCHRONIZED
1558 
1559     // notify the changed filter expression
1560     m_aFilterListeners.notifyEach( &XFilterControllerListener::predicateExpressionChanged, aEvent );
1561 }
1562 
1563 // XItemListener
1564 //------------------------------------------------------------------------------
1565 void SAL_CALL FormController::itemStateChanged(const ItemEvent& /*rEvent*/) throw( RuntimeException )
1566 {
1567     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1568     impl_onModify();
1569 }
1570 
1571 // XModificationBroadcaster
1572 //------------------------------------------------------------------------------
1573 void SAL_CALL FormController::addModifyListener(const Reference< XModifyListener > & l) throw( RuntimeException )
1574 {
1575     ::osl::MutexGuard aGuard( m_aMutex );
1576     impl_checkDisposed_throw();
1577     m_aModifyListeners.addInterface( l );
1578 }
1579 
1580 //------------------------------------------------------------------------------
1581 void FormController::removeModifyListener(const Reference< XModifyListener > & l) throw( RuntimeException )
1582 {
1583     ::osl::MutexGuard aGuard( m_aMutex );
1584     impl_checkDisposed_throw();
1585     m_aModifyListeners.removeInterface( l );
1586 }
1587 
1588 // XModificationListener
1589 //------------------------------------------------------------------------------
1590 void FormController::modified( const EventObject& _rEvent ) throw( RuntimeException )
1591 {
1592     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1593 
1594     try
1595     {
1596         if ( _rEvent.Source != m_xActiveControl )
1597         {	// let this control grab the focus
1598             // (this case may happen if somebody moves the scroll wheel of the mouse over a control
1599             // which does not have the focus)
1600             // 85511 - 29.05.2001 - frank.schoenheit@germany.sun.com
1601             //
1602             // also, it happens when an image control gets a new image by double-clicking it
1603             // #i88458# / 2009-01-12 / frank.schoenheit@sun.com
1604             Reference< XWindow > xControlWindow( _rEvent.Source, UNO_QUERY_THROW );
1605             xControlWindow->setFocus();
1606         }
1607     }
1608     catch( const Exception& )
1609     {
1610     	DBG_UNHANDLED_EXCEPTION();
1611     }
1612 
1613     impl_onModify();
1614 }
1615 
1616 //------------------------------------------------------------------------------
1617 void FormController::impl_checkDisposed_throw() const
1618 {
1619     if ( impl_isDisposed_nofail() )
1620         throw DisposedException( ::rtl::OUString(), *const_cast< FormController* >( this ) );
1621 }
1622 
1623 //------------------------------------------------------------------------------
1624 void FormController::impl_onModify()
1625 {
1626     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1627 
1628     {
1629         ::osl::MutexGuard aGuard( m_aMutex );
1630         if ( !m_bModified )
1631             m_bModified = sal_True;
1632     }
1633 
1634 	EventObject aEvt(static_cast<cppu::OWeakObject*>(this));
1635     m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvt );
1636 }
1637 
1638 //------------------------------------------------------------------------------
1639 void FormController::impl_addFilterRow( const FmFilterRow& _row )
1640 {
1641     m_aFilterRows.push_back( _row );
1642 
1643     if ( m_aFilterRows.size() == 1 )
1644     {   // that's the first row ever
1645         OSL_ENSURE( m_nCurrentFilterPosition == -1, "FormController::impl_addFilterRow: inconsistency!" );
1646         m_nCurrentFilterPosition = 0;
1647     }
1648 }
1649 
1650 //------------------------------------------------------------------------------
1651 void FormController::impl_appendEmptyFilterRow( ::osl::ClearableMutexGuard& _rClearBeforeNotify )
1652 {
1653     // SYNCHRONIZED -->
1654     impl_addFilterRow( FmFilterRow() );
1655 
1656     // notify the listeners
1657     FilterEvent aEvent;
1658     aEvent.Source = *this;
1659     aEvent.DisjunctiveTerm = (sal_Int32)m_aFilterRows.size() - 1;
1660     _rClearBeforeNotify.clear();
1661     // <-- SYNCHRONIZED
1662     m_aFilterListeners.notifyEach( &XFilterControllerListener::disjunctiveTermAdded, aEvent );
1663 }
1664 
1665 //------------------------------------------------------------------------------
1666 sal_Bool FormController::determineLockState() const
1667 {
1668     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1669     // a.) in filter mode we are always locked
1670     // b.) if we have no valid model or our model (a result set) is not alive -> we're locked
1671     // c.) if we are inserting everything is OK and we are not locked
1672     // d.) if are not updatable or on invalid position
1673     Reference< XResultSet >  xResultSet(m_xModelAsIndex, UNO_QUERY);
1674     if (m_bFiltering || !xResultSet.is() || !isRowSetAlive(xResultSet))
1675         return sal_True;
1676     else
1677         return (m_bCanInsert && m_bCurrentRecordNew) ? sal_False
1678         :  xResultSet->isBeforeFirst() || xResultSet->isAfterLast() || xResultSet->rowDeleted() || !m_bCanUpdate;
1679 }
1680 
1681 //  FocusListener
1682 //------------------------------------------------------------------------------
1683 void FormController::focusGained(const FocusEvent& e) throw( RuntimeException )
1684 {
1685     // SYNCHRONIZED -->
1686     ::osl::ClearableMutexGuard aGuard( m_aMutex );
1687     impl_checkDisposed_throw();
1688 
1689     m_pControlBorderManager->focusGained( e.Source );
1690 
1691     Reference< XControl >  xControl(e.Source, UNO_QUERY);
1692     if (m_bDBConnection)
1693     {
1694         // do we need to keep the locking of the commit
1695         // we hold the lock as long as the control differs from the current
1696         // otherwhise we disabled the lock
1697         m_bCommitLock = m_bCommitLock && (XControl*)xControl.get() != (XControl*)m_xCurrentControl.get();
1698         if (m_bCommitLock)
1699             return;
1700 
1701         // when do we have to commit a value to form or a filter
1702         // a.) if the current value is modified
1703         // b.) there must be a current control
1704         // c.) and it must be different from the new focus owning control or
1705         // d.) the focus is moving around (so we have only one control)
1706 
1707         if  (   ( m_bModified || m_bFiltering )
1708             &&  m_xCurrentControl.is()
1709             &&  (   ( xControl.get() != m_xCurrentControl.get() )
1710                 ||  (   ( e.FocusFlags & FocusChangeReason::AROUND )
1711                     &&  ( m_bCycle || m_bFiltering )
1712                     )
1713                 )
1714             )
1715         {
1716             // check the old control if the content is ok
1717 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
1718 			Reference< XBoundControl >  xLockingTest(m_xCurrentControl, UNO_QUERY);
1719 			sal_Bool bControlIsLocked = xLockingTest.is() && xLockingTest->getLock();
1720 			OSL_ENSURE(!bControlIsLocked, "FormController::Gained: I'm modified and the current control is locked ? How this ?");
1721 			// normalerweise sollte ein gelocktes Control nicht modified sein, also muss wohl mein bModified aus einem anderen Kontext
1722 			// gesetzt worden sein, was ich nicht verstehen wuerde ...
1723 #endif
1724 			DBG_ASSERT(m_xCurrentControl.is(), "kein CurrentControl gesetzt");
1725 			// zunaechst das Control fragen ob es das IFace unterstuetzt
1726 			Reference< XBoundComponent >  xBound(m_xCurrentControl, UNO_QUERY);
1727 			if (!xBound.is() && m_xCurrentControl.is())
1728 				xBound  = Reference< XBoundComponent > (m_xCurrentControl->getModel(), UNO_QUERY);
1729 
1730 			// lock if we lose the focus during commit
1731 			m_bCommitLock = sal_True;
1732 
1733 			// Commit nicht erfolgreich, Focus zuruecksetzen
1734 			if (xBound.is() && !xBound->commit())
1735 			{
1736 				// the commit failed and we don't commit again until the current control
1737 				// which couldn't be commit gains the focus again
1738 				Reference< XWindow >  xWindow(m_xCurrentControl, UNO_QUERY);
1739 				if (xWindow.is())
1740 					xWindow->setFocus();
1741 				return;
1742 			}
1743 			else
1744 			{
1745 				m_bModified = sal_False;
1746 				m_bCommitLock = sal_False;
1747 			}
1748 		}
1749 
1750 		if (!m_bFiltering && m_bCycle && (e.FocusFlags & FocusChangeReason::AROUND) && m_xCurrentControl.is())
1751 		{
1752             SQLErrorEvent aErrorEvent;
1753             OSL_ENSURE( m_xFormOperations.is(), "FormController::focusGained: hmm?" );
1754                 // should have been created in setModel
1755             try
1756             {
1757 			    if ( e.FocusFlags & FocusChangeReason::FORWARD )
1758 		        {
1759                     if ( m_xFormOperations.is() && m_xFormOperations->isEnabled( FormFeature::MoveToNext ) )
1760                         m_xFormOperations->execute( FormFeature::MoveToNext );
1761                 }
1762 			    else // backward
1763                 {
1764                     if ( m_xFormOperations.is() && m_xFormOperations->isEnabled( FormFeature::MoveToPrevious ) )
1765                         m_xFormOperations->execute( FormFeature::MoveToPrevious );
1766                 }
1767             }
1768             catch ( const Exception& )
1769             {
1770                 // don't handle this any further. That's an ... admissible error.
1771                 DBG_UNHANDLED_EXCEPTION();
1772             }
1773 		}
1774 	}
1775 
1776 	// Immer noch ein und dasselbe Control
1777 	if	(	( m_xActiveControl == xControl )
1778 		&&	( xControl == m_xCurrentControl )
1779 		)
1780 	{
1781 		DBG_ASSERT(m_xCurrentControl.is(), "Kein CurrentControl selektiert");
1782 		return;
1783 	}
1784 
1785 	sal_Bool bActivated = !m_xActiveControl.is() && xControl.is();
1786 
1787 	m_xActiveControl  = xControl;
1788 
1789     implSetCurrentControl( xControl );
1790 	OSL_POSTCOND( m_xCurrentControl.is(), "implSetCurrentControl did nonsense!" );
1791 
1792 	if ( bActivated )
1793     {
1794         // (asynchronously) call activation handlers
1795         m_aActivationEvent.Call();
1796 
1797         // call modify listeners
1798         if ( m_bModified )
1799             m_aModifyListeners.notifyEach( &XModifyListener::modified, EventObject( *this ) );
1800     }
1801 
1802     // invalidate all features which depend on the currently focused control
1803 	if ( m_bDBConnection && !m_bFiltering )
1804         implInvalidateCurrentControlDependentFeatures();
1805 
1806 	if ( !m_xCurrentControl.is() )
1807         return;
1808 
1809 	// Control erhaelt Focus, dann eventuell in den sichtbaren Bereich
1810     Reference< XFormControllerContext > xContext( m_xContext );
1811     Reference< XControl > xCurrentControl( m_xCurrentControl );
1812     aGuard.clear();
1813     // <-- SYNCHRONIZED
1814 
1815     if ( xContext.is() )
1816         xContext->makeVisible( xCurrentControl );
1817 }
1818 
1819 //------------------------------------------------------------------------------
1820 IMPL_LINK( FormController, OnActivated, void*, /**/ )
1821 {
1822     EventObject aEvent;
1823     aEvent.Source = *this;
1824     m_aActivateListeners.notifyEach( &XFormControllerListener::formActivated, aEvent );
1825 
1826     return 0L;
1827 }
1828 
1829 //------------------------------------------------------------------------------
1830 IMPL_LINK( FormController, OnDeactivated, void*, /**/ )
1831 {
1832     EventObject aEvent;
1833     aEvent.Source = *this;
1834     m_aActivateListeners.notifyEach( &XFormControllerListener::formDeactivated, aEvent );
1835 
1836     return 0L;
1837 }
1838 
1839 //------------------------------------------------------------------------------
1840 void FormController::focusLost(const FocusEvent& e) throw( RuntimeException )
1841 {
1842     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1843 
1844     m_pControlBorderManager->focusLost( e.Source );
1845 
1846     Reference< XControl >  xControl(e.Source, UNO_QUERY);
1847     Reference< XWindowPeer >  xNext(e.NextFocus, UNO_QUERY);
1848     Reference< XControl >  xNextControl = isInList(xNext);
1849     if (!xNextControl.is())
1850     {
1851         m_xActiveControl = NULL;
1852         m_aDeactivationEvent.Call();
1853     }
1854 }
1855 
1856 //--------------------------------------------------------------------
1857 void SAL_CALL FormController::mousePressed( const awt::MouseEvent& /*_rEvent*/ ) throw (RuntimeException)
1858 {
1859     // not interested in
1860 }
1861 
1862 //--------------------------------------------------------------------
1863 void SAL_CALL FormController::mouseReleased( const awt::MouseEvent& /*_rEvent*/ ) throw (RuntimeException)
1864 {
1865     // not interested in
1866 }
1867 
1868 //--------------------------------------------------------------------
1869 void SAL_CALL FormController::mouseEntered( const awt::MouseEvent& _rEvent ) throw (RuntimeException)
1870 {
1871     m_pControlBorderManager->mouseEntered( _rEvent.Source );
1872 }
1873 
1874 //--------------------------------------------------------------------
1875 void SAL_CALL FormController::mouseExited( const awt::MouseEvent& _rEvent ) throw (RuntimeException)
1876 {
1877     m_pControlBorderManager->mouseExited( _rEvent.Source );
1878 }
1879 
1880 //--------------------------------------------------------------------
1881 void SAL_CALL FormController::componentValidityChanged( const EventObject& _rSource ) throw (RuntimeException)
1882 {
1883     Reference< XControl > xControl( findControl( m_aControls, Reference< XControlModel >( _rSource.Source, UNO_QUERY ), sal_False, sal_False ) );
1884     Reference< XValidatableFormComponent > xValidatable( _rSource.Source, UNO_QUERY );
1885 
1886     OSL_ENSURE( xControl.is() && xValidatable.is(), "FormController::componentValidityChanged: huh?" );
1887 
1888     if ( xControl.is() && xValidatable.is() )
1889         m_pControlBorderManager->validityChanged( xControl, xValidatable );
1890 }
1891 
1892 //--------------------------------------------------------------------
1893 void FormController::setModel(const Reference< XTabControllerModel > & Model) throw( RuntimeException )
1894 {
1895     ::osl::MutexGuard aGuard( m_aMutex );
1896     impl_checkDisposed_throw();
1897 
1898     DBG_ASSERT(m_xTabController.is(), "FormController::setModel : invalid aggregate !");
1899 
1900     try
1901     {
1902         // disconnect from the old model
1903         if (m_xModelAsIndex.is())
1904         {
1905             if (m_bDBConnection)
1906             {
1907                 // we are currently working on the model
1908                 EventObject aEvt(m_xModelAsIndex);
1909                 unloaded(aEvt);
1910             }
1911 
1912             Reference< XLoadable >  xForm(m_xModelAsIndex, UNO_QUERY);
1913             if (xForm.is())
1914                 xForm->removeLoadListener(this);
1915 
1916             Reference< XSQLErrorBroadcaster >  xBroadcaster(m_xModelAsIndex, UNO_QUERY);
1917             if (xBroadcaster.is())
1918                 xBroadcaster->removeSQLErrorListener(this);
1919 
1920             Reference< XDatabaseParameterBroadcaster >  xParamBroadcaster(m_xModelAsIndex, UNO_QUERY);
1921             if (xParamBroadcaster.is())
1922                 xParamBroadcaster->removeParameterListener(this);
1923 
1924         }
1925 
1926         disposeAllFeaturesAndDispatchers();
1927 
1928         if ( m_xFormOperations.is() )
1929             m_xFormOperations->dispose();
1930         m_xFormOperations.clear();
1931 
1932         // set the new model wait for the load event
1933         if (m_xTabController.is())
1934             m_xTabController->setModel(Model);
1935         m_xModelAsIndex = Reference< XIndexAccess > (Model, UNO_QUERY);
1936         m_xModelAsManager = Reference< XEventAttacherManager > (Model, UNO_QUERY);
1937 
1938         // only if both ifaces exit, the controller will work successful
1939         if (!m_xModelAsIndex.is() || !m_xModelAsManager.is())
1940         {
1941             m_xModelAsManager = NULL;
1942             m_xModelAsIndex = NULL;
1943         }
1944 
1945         if (m_xModelAsIndex.is())
1946         {
1947             // re-create m_xFormOperations
1948             m_xFormOperations.set( FormOperations::createWithFormController( m_aContext.getUNOContext(), this ), UNO_SET_THROW );
1949             m_xFormOperations->setFeatureInvalidation( this );
1950 
1951             // adding load and ui interaction listeners
1952             Reference< XLoadable >  xForm(Model, UNO_QUERY);
1953             if (xForm.is())
1954                 xForm->addLoadListener(this);
1955 
1956             Reference< XSQLErrorBroadcaster >  xBroadcaster(Model, UNO_QUERY);
1957             if (xBroadcaster.is())
1958                 xBroadcaster->addSQLErrorListener(this);
1959 
1960             Reference< XDatabaseParameterBroadcaster >  xParamBroadcaster(Model, UNO_QUERY);
1961             if (xParamBroadcaster.is())
1962                 xParamBroadcaster->addParameterListener(this);
1963 
1964             // well, is the database already loaded?
1965             // then we have to simulate a load event
1966             Reference< XLoadable >  xCursor(m_xModelAsIndex, UNO_QUERY);
1967             if (xCursor.is() && xCursor->isLoaded())
1968             {
1969                 EventObject aEvt(xCursor);
1970                 loaded(aEvt);
1971             }
1972 
1973             Reference< XPropertySet > xModelProps( m_xModelAsIndex, UNO_QUERY );
1974             Reference< XPropertySetInfo > xPropInfo( xModelProps->getPropertySetInfo() );
1975             if (  xPropInfo.is()
1976                && xPropInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER )
1977                && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_FOCUS )
1978                && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_MOUSE )
1979                && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_INVALID )
1980                )
1981             {
1982                 bool bEnableDynamicControlBorder = lcl_shouldUseDynamicControlBorder(
1983                     xModelProps.get(), xModelProps->getPropertyValue( FM_PROP_DYNAMIC_CONTROL_BORDER ) );
1984                 if ( bEnableDynamicControlBorder )
1985                     m_pControlBorderManager->enableDynamicBorderColor();
1986                 else
1987                     m_pControlBorderManager->disableDynamicBorderColor();
1988 
1989                 sal_Int32 nColor = 0;
1990                 if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_FOCUS ) >>= nColor )
1991                     m_pControlBorderManager->setStatusColor( CONTROL_STATUS_FOCUSED, nColor );
1992                 if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_MOUSE ) >>= nColor )
1993                     m_pControlBorderManager->setStatusColor( CONTROL_STATUS_MOUSE_HOVER, nColor );
1994                 if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_INVALID ) >>= nColor )
1995                     m_pControlBorderManager->setStatusColor( CONTROL_STATUS_INVALID, nColor );
1996             }
1997         }
1998     }
1999     catch( const Exception& )
2000     {
2001         DBG_UNHANDLED_EXCEPTION();
2002     }
2003 }
2004 
2005 //------------------------------------------------------------------------------
2006 Reference< XTabControllerModel >  FormController::getModel() throw( RuntimeException )
2007 {
2008     ::osl::MutexGuard aGuard( m_aMutex );
2009     impl_checkDisposed_throw();
2010 
2011     DBG_ASSERT(m_xTabController.is(), "FormController::getModel : invalid aggregate !");
2012     if (!m_xTabController.is())
2013         return Reference< XTabControllerModel > ();
2014     return m_xTabController->getModel();
2015 }
2016 
2017 //------------------------------------------------------------------------------
2018 void FormController::addToEventAttacher(const Reference< XControl > & xControl)
2019 {
2020     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2021     OSL_ENSURE( xControl.is(), "FormController::addToEventAttacher: invalid control - how did you reach this?" );
2022     if ( !xControl.is() )
2023         return; /* throw IllegalArgumentException(); */
2024 
2025     // anmelden beim Eventattacher
2026     Reference< XFormComponent >  xComp(xControl->getModel(), UNO_QUERY);
2027     if (xComp.is() && m_xModelAsIndex.is())
2028     {
2029         // Und die Position des ControlModel darin suchen
2030         sal_uInt32 nPos = m_xModelAsIndex->getCount();
2031         Reference< XFormComponent > xTemp;
2032         for( ; nPos; )
2033         {
2034             m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
2035             if ((XFormComponent*)xComp.get() == (XFormComponent*)xTemp.get())
2036             {
2037                 Reference< XInterface >  xIfc(xControl, UNO_QUERY);
2038                 m_xModelAsManager->attach( nPos, xIfc, makeAny(xControl) );
2039                 break;
2040             }
2041         }
2042     }
2043 }
2044 
2045 //------------------------------------------------------------------------------
2046 void FormController::removeFromEventAttacher(const Reference< XControl > & xControl)
2047 {
2048     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2049     OSL_ENSURE( xControl.is(), "FormController::removeFromEventAttacher: invalid control - how did you reach this?" );
2050     if ( !xControl.is() )
2051         return; /* throw IllegalArgumentException(); */
2052 
2053     // abmelden beim Eventattacher
2054     Reference< XFormComponent >  xComp(xControl->getModel(), UNO_QUERY);
2055     if ( xComp.is() && m_xModelAsIndex.is() )
2056     {
2057         // Und die Position des ControlModel darin suchen
2058         sal_uInt32 nPos = m_xModelAsIndex->getCount();
2059         Reference< XFormComponent > xTemp;
2060         for( ; nPos; )
2061         {
2062             m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
2063             if ((XFormComponent*)xComp.get() == (XFormComponent*)xTemp.get())
2064             {
2065                 Reference< XInterface >  xIfc(xControl, UNO_QUERY);
2066                 m_xModelAsManager->detach( nPos, xIfc );
2067                 break;
2068             }
2069         }
2070     }
2071 }
2072 
2073 //------------------------------------------------------------------------------
2074 void FormController::setContainer(const Reference< XControlContainer > & xContainer) throw( RuntimeException )
2075 {
2076     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2077     Reference< XTabControllerModel >  xTabModel(getModel());
2078     DBG_ASSERT(xTabModel.is() || !xContainer.is(), "No Model defined");
2079         // if we have a new container we need a model
2080     DBG_ASSERT(m_xTabController.is(), "FormController::setContainer : invalid aggregate !");
2081 
2082     ::osl::MutexGuard aGuard( m_aMutex );
2083     Reference< XContainer >  xCurrentContainer;
2084     if (m_xTabController.is())
2085         xCurrentContainer = Reference< XContainer > (m_xTabController->getContainer(), UNO_QUERY);
2086     if (xCurrentContainer.is())
2087     {
2088         xCurrentContainer->removeContainerListener(this);
2089 
2090         if ( m_aTabActivationTimer.IsActive() )
2091             m_aTabActivationTimer.Stop();
2092 
2093         // clear the filter map
2094         ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), RemoveComponentTextListener( this ) );
2095         m_aFilterComponents.clear();
2096 
2097         // einsammeln der Controls
2098         const Reference< XControl >* pControls = m_aControls.getConstArray();
2099         const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2100         while ( pControls != pControlsEnd )
2101             implControlRemoved( *pControls++, true );
2102 
2103         // Datenbank spezifische Dinge vornehmen
2104         if (m_bDBConnection && isListeningForChanges())
2105             stopListening();
2106 
2107         m_aControls.realloc( 0 );
2108     }
2109 
2110     if (m_xTabController.is())
2111         m_xTabController->setContainer(xContainer);
2112 
2113     // Welche Controls gehoeren zum Container ?
2114     if (xContainer.is() && xTabModel.is())
2115     {
2116         Sequence< Reference< XControlModel > > aModels = xTabModel->getControlModels();
2117         const Reference< XControlModel > * pModels = aModels.getConstArray();
2118         Sequence< Reference< XControl > > aAllControls = xContainer->getControls();
2119 
2120         sal_Int32 nCount = aModels.getLength();
2121         m_aControls = Sequence< Reference< XControl > >( nCount );
2122         Reference< XControl > * pControls = m_aControls.getArray();
2123 
2124         // einsammeln der Controls
2125         sal_Int32 i, j;
2126         for (i = 0, j = 0; i < nCount; ++i, ++pModels )
2127         {
2128             Reference< XControl > xControl = findControl( aAllControls, *pModels, sal_False, sal_True );
2129             if ( xControl.is() )
2130             {
2131                 pControls[j++] = xControl;
2132                 implControlInserted( xControl, true );
2133             }
2134         }
2135 
2136         // not every model had an associated control
2137         if (j != i)
2138             m_aControls.realloc(j);
2139 
2140         // am Container horchen
2141         Reference< XContainer >  xNewContainer(xContainer, UNO_QUERY);
2142         if (xNewContainer.is())
2143             xNewContainer->addContainerListener(this);
2144 
2145         // Datenbank spezifische Dinge vornehmen
2146         if (m_bDBConnection)
2147         {
2148             m_bLocked = determineLockState();
2149             setLocks();
2150             if (!isLocked())
2151                 startListening();
2152         }
2153     }
2154     // befinden sich die Controls in der richtigen Reihenfolge
2155     m_bControlsSorted = sal_True;
2156 }
2157 
2158 //------------------------------------------------------------------------------
2159 Reference< XControlContainer >  FormController::getContainer() throw( RuntimeException )
2160 {
2161 	::osl::MutexGuard aGuard( m_aMutex );
2162     impl_checkDisposed_throw();
2163 
2164     DBG_ASSERT(m_xTabController.is(), "FormController::getContainer : invalid aggregate !");
2165     if (!m_xTabController.is())
2166         return Reference< XControlContainer > ();
2167     return m_xTabController->getContainer();
2168 }
2169 
2170 //------------------------------------------------------------------------------
2171 Sequence< Reference< XControl > > FormController::getControls(void) throw( RuntimeException )
2172 {
2173     ::osl::MutexGuard aGuard( m_aMutex );
2174     impl_checkDisposed_throw();
2175 
2176     if (!m_bControlsSorted)
2177     {
2178         Reference< XTabControllerModel >  xModel = getModel();
2179         if (!xModel.is())
2180             return m_aControls;
2181 
2182         Sequence< Reference< XControlModel > > aControlModels = xModel->getControlModels();
2183         const Reference< XControlModel > * pModels = aControlModels.getConstArray();
2184         sal_Int32 nModels = aControlModels.getLength();
2185 
2186         Sequence< Reference< XControl > > aNewControls(nModels);
2187 
2188         Reference< XControl > * pControls = aNewControls.getArray();
2189         Reference< XControl >  xControl;
2190 
2191         // Umsortieren der Controls entsprechend der TabReihenfolge
2192 	    sal_Int32 j = 0;
2193         for (sal_Int32 i = 0; i < nModels; ++i, ++pModels )
2194         {
2195             xControl = findControl( m_aControls, *pModels, sal_True, sal_True );
2196             if ( xControl.is() )
2197                 pControls[j++] = xControl;
2198         }
2199 
2200         // not every model had an associated control
2201         if ( j != nModels )
2202             aNewControls.realloc( j );
2203 
2204         m_aControls = aNewControls;
2205         m_bControlsSorted = sal_True;
2206     }
2207     return m_aControls;
2208 }
2209 
2210 //------------------------------------------------------------------------------
2211 void FormController::autoTabOrder() throw( RuntimeException )
2212 {
2213     ::osl::MutexGuard aGuard( m_aMutex );
2214     impl_checkDisposed_throw();
2215 
2216     DBG_ASSERT(m_xTabController.is(), "FormController::autoTabOrder : invalid aggregate !");
2217     if (m_xTabController.is())
2218         m_xTabController->autoTabOrder();
2219 }
2220 
2221 //------------------------------------------------------------------------------
2222 void FormController::activateTabOrder() throw( RuntimeException )
2223 {
2224     ::osl::MutexGuard aGuard( m_aMutex );
2225     impl_checkDisposed_throw();
2226 
2227     DBG_ASSERT(m_xTabController.is(), "FormController::activateTabOrder : invalid aggregate !");
2228     if (m_xTabController.is())
2229         m_xTabController->activateTabOrder();
2230 }
2231 
2232 //------------------------------------------------------------------------------
2233 void FormController::setControlLock(const Reference< XControl > & xControl)
2234 {
2235     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2236     sal_Bool bLocked = isLocked();
2237 
2238     // es wird gelockt
2239     // a.) wenn der ganze Datensatz gesperrt ist
2240     // b.) wenn das zugehoerige Feld gespeert ist
2241     Reference< XBoundControl >  xBound(xControl, UNO_QUERY);
2242     if (xBound.is() && (( (bLocked && bLocked != xBound->getLock()) ||
2243                          !bLocked)))    // beim entlocken immer einzelne Felder ueberpr�fen
2244     {
2245         // gibt es eine Datenquelle
2246         Reference< XPropertySet >  xSet(xControl->getModel(), UNO_QUERY);
2247         if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
2248         {
2249             // wie sieht mit den Properties ReadOnly und Enable aus
2250             sal_Bool bTouch = sal_True;
2251             if (::comphelper::hasProperty(FM_PROP_ENABLED, xSet))
2252                 bTouch = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ENABLED));
2253             if (::comphelper::hasProperty(FM_PROP_READONLY, xSet))
2254                 bTouch = !::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_READONLY));
2255 
2256             if (bTouch)
2257             {
2258                 Reference< XPropertySet >  xField;
2259                 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
2260                 if (xField.is())
2261                 {
2262                     if (bLocked)
2263                         xBound->setLock(bLocked);
2264                     else
2265                     {
2266                         try
2267                         {
2268                             Any aVal = xField->getPropertyValue(FM_PROP_ISREADONLY);
2269                             if (aVal.hasValue() && ::comphelper::getBOOL(aVal))
2270                                 xBound->setLock(sal_True);
2271                             else
2272                                 xBound->setLock(bLocked);
2273                         }
2274                         catch( const Exception& )
2275                         {
2276                             DBG_UNHANDLED_EXCEPTION();
2277                         }
2278 
2279                     }
2280                 }
2281             }
2282         }
2283     }
2284 }
2285 
2286 //------------------------------------------------------------------------------
2287 void FormController::setLocks()
2288 {
2289     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2290     // alle Controls, die mit einer Datenquelle verbunden sind locken/unlocken
2291     const Reference< XControl >* pControls = m_aControls.getConstArray();
2292     const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2293     while ( pControls != pControlsEnd )
2294         setControlLock( *pControls++ );
2295 }
2296 
2297 //------------------------------------------------------------------------------
2298 namespace
2299 {
2300     bool lcl_shouldListenForModifications( const Reference< XControl >& _rxControl, const Reference< XPropertyChangeListener >& _rxBoundFieldListener )
2301     {
2302         bool bShould = false;
2303 
2304         Reference< XBoundComponent > xBound( _rxControl, UNO_QUERY );
2305         if ( xBound.is() )
2306         {
2307             bShould = true;
2308         }
2309         else if ( _rxControl.is() )
2310         {
2311             Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY );
2312             if ( xModelProps.is() && ::comphelper::hasProperty( FM_PROP_BOUNDFIELD, xModelProps ) )
2313             {
2314                 Reference< XPropertySet > xField;
2315                 xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField;
2316                 bShould = xField.is();
2317 
2318                 if ( !bShould && _rxBoundFieldListener.is() )
2319 				    xModelProps->addPropertyChangeListener( FM_PROP_BOUNDFIELD, _rxBoundFieldListener );
2320             }
2321         }
2322 
2323         return bShould;
2324     }
2325 }
2326 
2327 //------------------------------------------------------------------------------
2328 void FormController::startControlModifyListening(const Reference< XControl > & xControl)
2329 {
2330     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2331 
2332     bool bModifyListening = lcl_shouldListenForModifications( xControl, this );
2333 
2334     // artificial while
2335     while ( bModifyListening )
2336     {
2337         Reference< XModifyBroadcaster >  xMod(xControl, UNO_QUERY);
2338         if (xMod.is())
2339         {
2340             xMod->addModifyListener(this);
2341             break;
2342         }
2343 
2344         // alle die Text um vorzeitig ein modified zu erkennen
2345         Reference< XTextComponent >  xText(xControl, UNO_QUERY);
2346         if (xText.is())
2347         {
2348             xText->addTextListener(this);
2349             break;
2350         }
2351 
2352         Reference< XCheckBox >  xBox(xControl, UNO_QUERY);
2353         if (xBox.is())
2354         {
2355             xBox->addItemListener(this);
2356             break;
2357         }
2358 
2359         Reference< XComboBox >  xCbBox(xControl, UNO_QUERY);
2360         if (xCbBox.is())
2361         {
2362             xCbBox->addItemListener(this);
2363             break;
2364         }
2365 
2366         Reference< XListBox >  xListBox(xControl, UNO_QUERY);
2367         if (xListBox.is())
2368         {
2369             xListBox->addItemListener(this);
2370             break;
2371         }
2372         break;
2373     }
2374 }
2375 
2376 //------------------------------------------------------------------------------
2377 void FormController::stopControlModifyListening(const Reference< XControl > & xControl)
2378 {
2379     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2380 
2381     bool bModifyListening = lcl_shouldListenForModifications( xControl, NULL );
2382 
2383     // kuenstliches while
2384     while (bModifyListening)
2385     {
2386         Reference< XModifyBroadcaster >  xMod(xControl, UNO_QUERY);
2387         if (xMod.is())
2388         {
2389             xMod->removeModifyListener(this);
2390             break;
2391         }
2392         // alle die Text um vorzeitig ein modified zu erkennen
2393         Reference< XTextComponent >  xText(xControl, UNO_QUERY);
2394         if (xText.is())
2395         {
2396             xText->removeTextListener(this);
2397             break;
2398         }
2399 
2400         Reference< XCheckBox >  xBox(xControl, UNO_QUERY);
2401         if (xBox.is())
2402         {
2403             xBox->removeItemListener(this);
2404             break;
2405         }
2406 
2407         Reference< XComboBox >  xCbBox(xControl, UNO_QUERY);
2408         if (xCbBox.is())
2409         {
2410             xCbBox->removeItemListener(this);
2411             break;
2412         }
2413 
2414         Reference< XListBox >  xListBox(xControl, UNO_QUERY);
2415         if (xListBox.is())
2416         {
2417             xListBox->removeItemListener(this);
2418             break;
2419         }
2420         break;
2421     }
2422 }
2423 
2424 //------------------------------------------------------------------------------
2425 void FormController::startListening()
2426 {
2427     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2428     m_bModified  = sal_False;
2429 
2430     // jetzt anmelden bei gebundenen feldern
2431     const Reference< XControl >* pControls = m_aControls.getConstArray();
2432     const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2433     while ( pControls != pControlsEnd )
2434         startControlModifyListening( *pControls++ );
2435 }
2436 
2437 //------------------------------------------------------------------------------
2438 void FormController::stopListening()
2439 {
2440     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2441     m_bModified  = sal_False;
2442 
2443     // jetzt anmelden bei gebundenen feldern
2444     const Reference< XControl >* pControls = m_aControls.getConstArray();
2445     const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2446     while ( pControls != pControlsEnd )
2447         stopControlModifyListening( *pControls++ );
2448 }
2449 
2450 
2451 //------------------------------------------------------------------------------
2452 Reference< XControl >  FormController::findControl(Sequence< Reference< XControl > >& _rControls, const Reference< XControlModel > & xCtrlModel ,sal_Bool _bRemove,sal_Bool _bOverWrite) const
2453 {
2454     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2455     DBG_ASSERT( xCtrlModel.is(), "findControl - welches ?!" );
2456 
2457     Reference< XControl >* pControls = _rControls.getArray();
2458     Reference< XControlModel >  xModel;
2459     for ( sal_Int32 i = 0, nCount = _rControls.getLength(); i < nCount; ++i, ++pControls )
2460     {
2461         if ( pControls->is() )
2462         {
2463             xModel = (*pControls)->getModel();
2464             if ( xModel.get() == xCtrlModel.get() )
2465             {
2466                 Reference< XControl > xControl( *pControls );
2467 				if ( _bRemove )
2468 					::comphelper::removeElementAt( _rControls, i );
2469 				else if ( _bOverWrite )
2470 					*pControls = Reference< XControl >();
2471                 return xControl;
2472             }
2473         }
2474     }
2475     return Reference< XControl > ();
2476 }
2477 
2478 //------------------------------------------------------------------------------
2479 void FormController::implControlInserted( const Reference< XControl>& _rxControl, bool _bAddToEventAttacher )
2480 {
2481     Reference< XWindow > xWindow( _rxControl, UNO_QUERY );
2482     if ( xWindow.is() )
2483     {
2484         xWindow->addFocusListener( this );
2485         xWindow->addMouseListener( this );
2486 
2487         if ( _bAddToEventAttacher )
2488             addToEventAttacher( _rxControl );
2489     }
2490 
2491     // add a dispatch interceptor to the control (if supported)
2492     Reference< XDispatchProviderInterception > xInterception( _rxControl, UNO_QUERY );
2493     if ( xInterception.is() )
2494         createInterceptor( xInterception );
2495 
2496     if ( _rxControl.is() )
2497     {
2498         Reference< XControlModel > xModel( _rxControl->getModel() );
2499 
2500         // we want to know about the reset of the the model of our controls
2501         // (for correctly resetting m_bModified)
2502         Reference< XReset >  xReset( xModel, UNO_QUERY );
2503 		if ( xReset.is() )
2504 			xReset->addResetListener( this );
2505 
2506         // and we want to know about the validity, to visually indicate it
2507         Reference< XValidatableFormComponent > xValidatable( xModel, UNO_QUERY );
2508         if ( xValidatable.is() )
2509         {
2510             xValidatable->addFormComponentValidityListener( this );
2511             m_pControlBorderManager->validityChanged( _rxControl, xValidatable );
2512         }
2513     }
2514 
2515 }
2516 
2517 //------------------------------------------------------------------------------
2518 void FormController::implControlRemoved( const Reference< XControl>& _rxControl, bool _bRemoveFromEventAttacher )
2519 {
2520 	Reference< XWindow > xWindow( _rxControl, UNO_QUERY );
2521 	if ( xWindow.is() )
2522 	{
2523         xWindow->removeFocusListener( this );
2524         xWindow->removeMouseListener( this );
2525 
2526         if ( _bRemoveFromEventAttacher )
2527 			removeFromEventAttacher( _rxControl );
2528 	}
2529 
2530 	Reference< XDispatchProviderInterception > xInterception( _rxControl, UNO_QUERY);
2531 	if ( xInterception.is() )
2532 		deleteInterceptor( xInterception );
2533 
2534 	if ( _rxControl.is() )
2535 	{
2536         Reference< XControlModel > xModel( _rxControl->getModel() );
2537 
2538         Reference< XReset >  xReset( xModel, UNO_QUERY );
2539 		if ( xReset.is() )
2540 			xReset->removeResetListener( this );
2541 
2542         Reference< XValidatableFormComponent > xValidatable( xModel, UNO_QUERY );
2543         if ( xValidatable.is() )
2544             xValidatable->removeFormComponentValidityListener( this );
2545 	}
2546 }
2547 
2548 //------------------------------------------------------------------------------
2549 void FormController::implSetCurrentControl( const Reference< XControl >& _rxControl )
2550 {
2551     if ( m_xCurrentControl.get() == _rxControl.get() )
2552         return;
2553 
2554     Reference< XGridControl > xGridControl( m_xCurrentControl, UNO_QUERY );
2555     if ( xGridControl.is() )
2556         xGridControl->removeGridControlListener( this );
2557 
2558     m_xCurrentControl = _rxControl;
2559 
2560     xGridControl.set( m_xCurrentControl, UNO_QUERY );
2561     if ( xGridControl.is() )
2562         xGridControl->addGridControlListener( this );
2563 }
2564 
2565 //------------------------------------------------------------------------------
2566 void FormController::insertControl(const Reference< XControl > & xControl)
2567 {
2568     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2569     m_bControlsSorted = sal_False;
2570     m_aControls.realloc(m_aControls.getLength() + 1);
2571     m_aControls.getArray()[m_aControls.getLength() - 1] = xControl;
2572 
2573     if ( m_pColumnInfoCache.get() )
2574         m_pColumnInfoCache->deinitializeControls();
2575 
2576     implControlInserted( xControl, m_bAttachEvents );
2577 
2578     if (m_bDBConnection && !m_bFiltering)
2579         setControlLock(xControl);
2580 
2581     if (isListeningForChanges() && m_bAttachEvents)
2582         startControlModifyListening( xControl );
2583 }
2584 
2585 //------------------------------------------------------------------------------
2586 void FormController::removeControl(const Reference< XControl > & xControl)
2587 {
2588 	OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2589 	const Reference< XControl >* pControls = m_aControls.getConstArray();
2590 	const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2591     while ( pControls != pControlsEnd )
2592 	{
2593 		if ( xControl.get() == (*pControls++).get() )
2594 		{
2595 			::comphelper::removeElementAt( m_aControls, pControls - m_aControls.getConstArray() - 1 );
2596 			break;
2597 		}
2598 	}
2599 
2600     FilterComponents::iterator componentPos = ::std::find( m_aFilterComponents.begin(), m_aFilterComponents.end(), xControl );
2601     if ( componentPos != m_aFilterComponents.end() )
2602         m_aFilterComponents.erase( componentPos );
2603 
2604     implControlRemoved( xControl, m_bDetachEvents );
2605 
2606     if ( isListeningForChanges() && m_bDetachEvents )
2607         stopControlModifyListening( xControl );
2608 }
2609 
2610 // XLoadListener
2611 //------------------------------------------------------------------------------
2612 void FormController::loaded(const EventObject& rEvent) throw( RuntimeException )
2613 {
2614 	OSL_ENSURE( rEvent.Source == m_xModelAsIndex, "FormController::loaded: where did this come from?" );
2615 
2616 	OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2617     ::osl::MutexGuard aGuard( m_aMutex );
2618     Reference< XRowSet >  xForm(rEvent.Source, UNO_QUERY);
2619     // do we have a connected data source
2620 	OStaticDataAccessTools aStaticTools;
2621     if (xForm.is() && aStaticTools.getRowSetConnection(xForm).is())
2622     {
2623         Reference< XPropertySet >  xSet(xForm, UNO_QUERY);
2624         if (xSet.is())
2625         {
2626             Any aVal        = xSet->getPropertyValue(FM_PROP_CYCLE);
2627             sal_Int32 aVal2 = 0;
2628             ::cppu::enum2int(aVal2,aVal);
2629             m_bCycle        = !aVal.hasValue() || aVal2 == TabulatorCycle_RECORDS;
2630             m_bCanUpdate    = aStaticTools.canUpdate(xSet);
2631             m_bCanInsert    = aStaticTools.canInsert(xSet);
2632             m_bCurrentRecordModified = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED));
2633             m_bCurrentRecordNew      = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
2634 
2635 			startFormListening( xSet, sal_False );
2636 
2637             // set the locks for the current controls
2638             if (getContainer().is())
2639             {
2640                 m_aLoadEvent.Call();
2641             }
2642         }
2643         else
2644         {
2645             m_bCanInsert = m_bCanUpdate = m_bCycle = sal_False;
2646             m_bCurrentRecordModified = sal_False;
2647             m_bCurrentRecordNew = sal_False;
2648             m_bLocked = sal_False;
2649         }
2650         m_bDBConnection = sal_True;
2651     }
2652     else
2653     {
2654         m_bDBConnection = sal_False;
2655         m_bCanInsert = m_bCanUpdate = m_bCycle = sal_False;
2656         m_bCurrentRecordModified = sal_False;
2657         m_bCurrentRecordNew = sal_False;
2658         m_bLocked = sal_False;
2659     }
2660 
2661     Reference< XColumnsSupplier > xFormColumns( xForm, UNO_QUERY );
2662     m_pColumnInfoCache.reset( xFormColumns.is() ? new ColumnInfoCache( xFormColumns ) : NULL );
2663 
2664     updateAllDispatchers();
2665 }
2666 
2667 //------------------------------------------------------------------------------
2668 void FormController::updateAllDispatchers() const
2669 {
2670     ::std::for_each(
2671         m_aFeatureDispatchers.begin(),
2672         m_aFeatureDispatchers.end(),
2673         ::std::compose1(
2674             UpdateAllListeners(),
2675             ::std::select2nd< DispatcherContainer::value_type >()
2676         )
2677     );
2678 }
2679 
2680 //------------------------------------------------------------------------------
2681 IMPL_LINK(FormController, OnLoad, void*, EMPTYARG)
2682 {
2683     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2684     m_bLocked = determineLockState();
2685 
2686     setLocks();
2687 
2688     if (!m_bLocked)
2689         startListening();
2690 
2691     // just one exception toggle the auto values
2692     if (m_bCurrentRecordNew)
2693         toggleAutoFields(sal_True);
2694 
2695     return 1L;
2696 }
2697 
2698 //------------------------------------------------------------------------------
2699 void FormController::unloaded(const EventObject& /*rEvent*/) throw( RuntimeException )
2700 {
2701     ::osl::MutexGuard aGuard( m_aMutex );
2702     impl_checkDisposed_throw();
2703 
2704     updateAllDispatchers();
2705 }
2706 
2707 //------------------------------------------------------------------------------
2708 void FormController::reloading(const EventObject& /*aEvent*/) throw( RuntimeException )
2709 {
2710     ::osl::MutexGuard aGuard( m_aMutex );
2711     impl_checkDisposed_throw();
2712 
2713     // do the same like in unloading
2714     // just one exception toggle the auto values
2715     m_aToggleEvent.CancelPendingCall();
2716     unload();
2717 }
2718 
2719 //------------------------------------------------------------------------------
2720 void FormController::reloaded(const EventObject& aEvent) throw( RuntimeException )
2721 {
2722     ::osl::MutexGuard aGuard( m_aMutex );
2723     impl_checkDisposed_throw();
2724 
2725     loaded(aEvent);
2726 }
2727 
2728 //------------------------------------------------------------------------------
2729 void FormController::unloading(const EventObject& /*aEvent*/) throw( RuntimeException )
2730 {
2731     ::osl::MutexGuard aGuard( m_aMutex );
2732     impl_checkDisposed_throw();
2733 
2734     unload();
2735 }
2736 
2737 //------------------------------------------------------------------------------
2738 void FormController::unload() throw( RuntimeException )
2739 {
2740     ::osl::MutexGuard aGuard( m_aMutex );
2741     impl_checkDisposed_throw();
2742 
2743     m_aLoadEvent.CancelPendingCall();
2744 
2745     // be sure not to have autofields
2746     if (m_bCurrentRecordNew)
2747         toggleAutoFields(sal_False);
2748 
2749 	// remove bound field listing again
2750 	removeBoundFieldListener();
2751 
2752     if (m_bDBConnection && isListeningForChanges())
2753         stopListening();
2754 
2755     Reference< XPropertySet >  xSet( m_xModelAsIndex, UNO_QUERY );
2756     if ( m_bDBConnection && xSet.is() )
2757 		stopFormListening( xSet, sal_False );
2758 
2759     m_bDBConnection = sal_False;
2760     m_bCanInsert = m_bCanUpdate = m_bCycle = sal_False;
2761     m_bCurrentRecordModified = m_bCurrentRecordNew = m_bLocked = sal_False;
2762 
2763     m_pColumnInfoCache.reset( NULL );
2764 }
2765 
2766 // -----------------------------------------------------------------------------
2767 void FormController::removeBoundFieldListener()
2768 {
2769 	const Reference< XControl >* pControls = m_aControls.getConstArray();
2770 	const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2771     while ( pControls != pControlsEnd )
2772     {
2773 		Reference< XPropertySet > xProp( *pControls++, UNO_QUERY );
2774 		if ( xProp.is() )
2775 			xProp->removePropertyChangeListener( FM_PROP_BOUNDFIELD, this );
2776 	}
2777 }
2778 
2779 //------------------------------------------------------------------------------
2780 void FormController::startFormListening( const Reference< XPropertySet >& _rxForm, sal_Bool _bPropertiesOnly )
2781 {
2782     try
2783     {
2784         if ( m_bCanInsert || m_bCanUpdate )   // form can be modified
2785         {
2786             _rxForm->addPropertyChangeListener( FM_PROP_ISNEW, this );
2787             _rxForm->addPropertyChangeListener( FM_PROP_ISMODIFIED, this );
2788 
2789 		    if ( !_bPropertiesOnly )
2790 		    {
2791 			    // set the Listener for UI interaction
2792 			    Reference< XRowSetApproveBroadcaster > xApprove( _rxForm, UNO_QUERY );
2793 			    if ( xApprove.is() )
2794 				    xApprove->addRowSetApproveListener( this );
2795 
2796 			    // listener for row set changes
2797 			    Reference< XRowSet > xRowSet( _rxForm, UNO_QUERY );
2798 			    if ( xRowSet.is() )
2799 				    xRowSet->addRowSetListener( this );
2800 		    }
2801         }
2802 
2803         Reference< XPropertySetInfo > xInfo = _rxForm->getPropertySetInfo();
2804         if ( xInfo.is() && xInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) )
2805             _rxForm->addPropertyChangeListener( FM_PROP_DYNAMIC_CONTROL_BORDER, this );
2806     }
2807     catch( const Exception& )
2808     {
2809         DBG_UNHANDLED_EXCEPTION();
2810     }
2811 }
2812 
2813 //------------------------------------------------------------------------------
2814 void FormController::stopFormListening( const Reference< XPropertySet >& _rxForm, sal_Bool _bPropertiesOnly )
2815 {
2816     try
2817     {
2818         if ( m_bCanInsert || m_bCanUpdate )
2819         {
2820             _rxForm->removePropertyChangeListener( FM_PROP_ISNEW, this );
2821             _rxForm->removePropertyChangeListener( FM_PROP_ISMODIFIED, this );
2822 
2823 		    if ( !_bPropertiesOnly )
2824 		    {
2825 			    Reference< XRowSetApproveBroadcaster > xApprove( _rxForm, UNO_QUERY );
2826 			    if (xApprove.is())
2827 				    xApprove->removeRowSetApproveListener(this);
2828 
2829 			    Reference< XRowSet > xRowSet( _rxForm, UNO_QUERY );
2830 			    if ( xRowSet.is() )
2831 				    xRowSet->removeRowSetListener( this );
2832 		    }
2833         }
2834 
2835         Reference< XPropertySetInfo > xInfo = _rxForm->getPropertySetInfo();
2836         if ( xInfo.is() && xInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) )
2837             _rxForm->removePropertyChangeListener( FM_PROP_DYNAMIC_CONTROL_BORDER, this );
2838     }
2839     catch( const Exception& )
2840     {
2841         DBG_UNHANDLED_EXCEPTION();
2842     }
2843 }
2844 
2845 // com::sun::star::sdbc::XRowSetListener
2846 //------------------------------------------------------------------------------
2847 void FormController::cursorMoved(const EventObject& /*event*/) throw( RuntimeException )
2848 {
2849     ::osl::MutexGuard aGuard( m_aMutex );
2850     impl_checkDisposed_throw();
2851 
2852     // toggle the locking ?
2853     if (m_bLocked != determineLockState())
2854     {
2855         m_bLocked = !m_bLocked;
2856         setLocks();
2857         if (isListeningForChanges())
2858             startListening();
2859         else
2860             stopListening();
2861     }
2862 
2863 	// neither the current control nor the current record are modified anymore
2864 	m_bCurrentRecordModified = m_bModified = sal_False;
2865 }
2866 
2867 //------------------------------------------------------------------------------
2868 void FormController::rowChanged(const EventObject& /*event*/) throw( RuntimeException )
2869 {
2870     // not interested in ...
2871 }
2872 //------------------------------------------------------------------------------
2873 void FormController::rowSetChanged(const EventObject& /*event*/) throw( RuntimeException )
2874 {
2875     // not interested in ...
2876 }
2877 
2878 
2879 // XContainerListener
2880 //------------------------------------------------------------------------------
2881 void SAL_CALL FormController::elementInserted(const ContainerEvent& evt) throw( RuntimeException )
2882 {
2883     ::osl::MutexGuard aGuard( m_aMutex );
2884     impl_checkDisposed_throw();
2885 
2886     Reference< XControl > xControl( evt.Element, UNO_QUERY );
2887     if ( !xControl.is() )
2888         return;
2889 
2890     Reference< XFormComponent >  xModel(xControl->getModel(), UNO_QUERY);
2891     if (xModel.is() && m_xModelAsIndex == xModel->getParent())
2892     {
2893         insertControl(xControl);
2894 
2895         if ( m_aTabActivationTimer.IsActive() )
2896             m_aTabActivationTimer.Stop();
2897 
2898         m_aTabActivationTimer.Start();
2899     }
2900     // are we in filtermode and a XModeSelector has inserted an element
2901     else if (m_bFiltering && Reference< XModeSelector > (evt.Source, UNO_QUERY).is())
2902     {
2903         xModel = Reference< XFormComponent > (evt.Source, UNO_QUERY);
2904         if (xModel.is() && m_xModelAsIndex == xModel->getParent())
2905         {
2906             Reference< XPropertySet >  xSet(xControl->getModel(), UNO_QUERY);
2907             if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
2908             {
2909                 // does the model use a bound field ?
2910                 Reference< XPropertySet >  xField;
2911                 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
2912 
2913                 Reference< XTextComponent >  xText(xControl, UNO_QUERY);
2914                 // may we filter the field?
2915                 if (xText.is() && xField.is() && ::comphelper::hasProperty(FM_PROP_SEARCHABLE, xField) &&
2916                     ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_SEARCHABLE)))
2917                 {
2918                     m_aFilterComponents.push_back( xText );
2919                     xText->addTextListener( this );
2920                 }
2921             }
2922         }
2923     }
2924 }
2925 
2926 //------------------------------------------------------------------------------
2927 void SAL_CALL FormController::elementReplaced(const ContainerEvent& evt) throw( RuntimeException )
2928 {
2929     // simulate an elementRemoved
2930     ContainerEvent aRemoveEvent( evt );
2931     aRemoveEvent.Element = evt.ReplacedElement;
2932     aRemoveEvent.ReplacedElement = Any();
2933     elementRemoved( aRemoveEvent );
2934 
2935     // simulate an elementInserted
2936     ContainerEvent aInsertEvent( evt );
2937     aInsertEvent.ReplacedElement = Any();
2938     elementInserted( aInsertEvent );
2939 }
2940 
2941 //------------------------------------------------------------------------------
2942 void SAL_CALL FormController::elementRemoved(const ContainerEvent& evt) throw( RuntimeException )
2943 {
2944     ::osl::MutexGuard aGuard( m_aMutex );
2945     impl_checkDisposed_throw();
2946 
2947     Reference< XControl >  xControl;
2948     evt.Element >>= xControl;
2949     if (!xControl.is())
2950         return;
2951 
2952     Reference< XFormComponent >  xModel(xControl->getModel(), UNO_QUERY);
2953     if (xModel.is() && m_xModelAsIndex == xModel->getParent())
2954     {
2955         removeControl(xControl);
2956         // TabOrder nicht neu berechnen, da das intern schon funktionieren mu�!
2957     }
2958     // are we in filtermode and a XModeSelector has inserted an element
2959     else if (m_bFiltering && Reference< XModeSelector > (evt.Source, UNO_QUERY).is())
2960     {
2961         FilterComponents::iterator componentPos = ::std::find(
2962             m_aFilterComponents.begin(), m_aFilterComponents.end(), xControl );
2963         if ( componentPos != m_aFilterComponents.end() )
2964             m_aFilterComponents.erase( componentPos );
2965     }
2966 }
2967 
2968 //------------------------------------------------------------------------------
2969 Reference< XControl >  FormController::isInList(const Reference< XWindowPeer > & xPeer) const
2970 {
2971     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2972     const Reference< XControl >* pControls = m_aControls.getConstArray();
2973 
2974     sal_uInt32 nCtrls = m_aControls.getLength();
2975     for ( sal_uInt32 n = 0; n < nCtrls && xPeer.is(); ++n, ++pControls )
2976     {
2977         if ( pControls->is() )
2978         {
2979             Reference< XVclWindowPeer >  xCtrlPeer( (*pControls)->getPeer(), UNO_QUERY);
2980             if ( ( xCtrlPeer.get() == xPeer.get() ) || xCtrlPeer->isChild( xPeer ) )
2981                 return *pControls;
2982         }
2983     }
2984     return Reference< XControl > ();
2985 }
2986 
2987 //------------------------------------------------------------------------------
2988 void FormController::activateFirst() throw( RuntimeException )
2989 {
2990     ::osl::MutexGuard aGuard( m_aMutex );
2991     impl_checkDisposed_throw();
2992 
2993     DBG_ASSERT(m_xTabController.is(), "FormController::activateFirst : invalid aggregate !");
2994     if (m_xTabController.is())
2995         m_xTabController->activateFirst();
2996 }
2997 
2998 //------------------------------------------------------------------------------
2999 void FormController::activateLast() throw( RuntimeException )
3000 {
3001     ::osl::MutexGuard aGuard( m_aMutex );
3002     impl_checkDisposed_throw();
3003 
3004     DBG_ASSERT(m_xTabController.is(), "FormController::activateLast : invalid aggregate !");
3005     if (m_xTabController.is())
3006         m_xTabController->activateLast();
3007 }
3008 
3009 // XFormController
3010 //------------------------------------------------------------------------------
3011 Reference< XFormOperations > SAL_CALL FormController::getFormOperations() throw (RuntimeException)
3012 {
3013     ::osl::MutexGuard aGuard( m_aMutex );
3014     impl_checkDisposed_throw();
3015 
3016     return m_xFormOperations;
3017 }
3018 
3019 //------------------------------------------------------------------------------
3020 Reference< XControl> SAL_CALL FormController::getCurrentControl(void) throw( RuntimeException )
3021 {
3022 	::osl::MutexGuard aGuard( m_aMutex );
3023     impl_checkDisposed_throw();
3024 	return m_xCurrentControl;
3025 }
3026 
3027 //------------------------------------------------------------------------------
3028 void SAL_CALL FormController::addActivateListener(const Reference< XFormControllerListener > & l) throw( RuntimeException )
3029 {
3030 	::osl::MutexGuard aGuard( m_aMutex );
3031     impl_checkDisposed_throw();
3032 	m_aActivateListeners.addInterface(l);
3033 }
3034 //------------------------------------------------------------------------------
3035 void SAL_CALL FormController::removeActivateListener(const Reference< XFormControllerListener > & l) throw( RuntimeException )
3036 {
3037 	::osl::MutexGuard aGuard( m_aMutex );
3038     impl_checkDisposed_throw();
3039 	m_aActivateListeners.removeInterface(l);
3040 }
3041 
3042 //------------------------------------------------------------------------------
3043 void SAL_CALL FormController::addChildController( const Reference< XFormController >& _ChildController ) throw( RuntimeException, IllegalArgumentException )
3044 {
3045     ::osl::MutexGuard aGuard( m_aMutex );
3046     impl_checkDisposed_throw();
3047 
3048     if ( !_ChildController.is() )
3049         throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
3050         // TODO: (localized) error message
3051 
3052     // the parent of our (to-be-)child must be our own model
3053     Reference< XFormComponent > xFormOfChild( _ChildController->getModel(), UNO_QUERY );
3054     if ( !xFormOfChild.is() )
3055         throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
3056         // TODO: (localized) error message
3057 
3058     if ( xFormOfChild->getParent() != m_xModelAsIndex )
3059         throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
3060         // TODO: (localized) error message
3061 
3062     m_aChilds.push_back( _ChildController );
3063     _ChildController->setParent( *this );
3064 
3065     // search the position of the model within the form
3066     sal_uInt32 nPos = m_xModelAsIndex->getCount();
3067     Reference< XFormComponent > xTemp;
3068     for( ; nPos; )
3069     {
3070         m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
3071         if ( xFormOfChild == xTemp )
3072         {
3073             Reference< XInterface >  xIfc( _ChildController, UNO_QUERY );
3074             m_xModelAsManager->attach( nPos, xIfc, makeAny( _ChildController) );
3075             break;
3076         }
3077     }
3078 }
3079 
3080 //------------------------------------------------------------------------------
3081 Reference< XFormControllerContext > SAL_CALL FormController::getContext() throw (RuntimeException)
3082 {
3083 	::osl::MutexGuard aGuard( m_aMutex );
3084     impl_checkDisposed_throw();
3085     return m_xContext;
3086 }
3087 
3088 //------------------------------------------------------------------------------
3089 void SAL_CALL FormController::setContext( const Reference< XFormControllerContext >& _context ) throw (RuntimeException)
3090 {
3091 	::osl::MutexGuard aGuard( m_aMutex );
3092     impl_checkDisposed_throw();
3093     m_xContext = _context;
3094 }
3095 
3096 //------------------------------------------------------------------------------
3097 Reference< XInteractionHandler > SAL_CALL FormController::getInteractionHandler() throw (RuntimeException)
3098 {
3099 	::osl::MutexGuard aGuard( m_aMutex );
3100     impl_checkDisposed_throw();
3101     return m_xInteractionHandler;
3102 }
3103 
3104 //------------------------------------------------------------------------------
3105 void SAL_CALL FormController::setInteractionHandler( const Reference< XInteractionHandler >& _interactionHandler ) throw (RuntimeException)
3106 {
3107 	::osl::MutexGuard aGuard( m_aMutex );
3108     impl_checkDisposed_throw();
3109     m_xInteractionHandler = _interactionHandler;
3110 }
3111 
3112 //------------------------------------------------------------------------------
3113 void FormController::setFilter(::std::vector<FmFieldInfo>& rFieldInfos)
3114 {
3115 	OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3116 	// create the composer
3117 	Reference< XRowSet > xForm(m_xModelAsIndex, UNO_QUERY);
3118 	Reference< XConnection > xConnection(OStaticDataAccessTools().getRowSetConnection(xForm));
3119 	if (xForm.is())
3120 	{
3121         try
3122         {
3123             Reference< XMultiServiceFactory > xFactory( xConnection, UNO_QUERY_THROW );
3124             m_xComposer.set(
3125                 xFactory->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdb.SingleSelectQueryComposer" ) ) ),
3126                 UNO_QUERY_THROW );
3127 
3128             Reference< XPropertySet > xSet( xForm, UNO_QUERY );
3129 			::rtl::OUString	sStatement	= ::comphelper::getString( xSet->getPropertyValue( FM_PROP_ACTIVECOMMAND ) );
3130 			::rtl::OUString sFilter		= ::comphelper::getString( xSet->getPropertyValue( FM_PROP_FILTER ) );
3131 			m_xComposer->setElementaryQuery( sStatement );
3132 			m_xComposer->setFilter( sFilter );
3133         }
3134         catch( const Exception& )
3135         {
3136         	DBG_UNHANDLED_EXCEPTION();
3137         }
3138 	}
3139 
3140 	if (m_xComposer.is())
3141 	{
3142 		Sequence < PropertyValue> aLevel;
3143 		Sequence< Sequence < PropertyValue > > aFilterRows = m_xComposer->getStructuredFilter();
3144 
3145 		// ok, we recieve the list of filters as sequence of fieldnames, value
3146 		// now we have to transform the fieldname into UI names, that could be a label of the field or
3147 		// a aliasname or the fieldname itself
3148 
3149 		// first adjust the field names if necessary
3150 		Reference< XNameAccess > xQueryColumns =
3151             Reference< XColumnsSupplier >( m_xComposer, UNO_QUERY_THROW )->getColumns();
3152 
3153 		for (::std::vector<FmFieldInfo>::iterator iter = rFieldInfos.begin();
3154 			iter != rFieldInfos.end(); iter++)
3155 		{
3156 			if ( xQueryColumns->hasByName((*iter).aFieldName) )
3157 			{
3158 				if ( (xQueryColumns->getByName((*iter).aFieldName) >>= (*iter).xField) && (*iter).xField.is() )
3159 					(*iter).xField->getPropertyValue(FM_PROP_REALNAME) >>= (*iter).aFieldName;
3160 			}
3161 		}
3162 
3163 		Reference< XDatabaseMetaData> xMetaData(xConnection->getMetaData());
3164 		// now transfer the filters into Value/TextComponent pairs
3165 		::comphelper::UStringMixEqual aCompare(xMetaData->storesMixedCaseQuotedIdentifiers());
3166 
3167 		// need to parse criteria localized
3168 		OStaticDataAccessTools aStaticTools;
3169 		Reference< XNumberFormatsSupplier> xFormatSupplier( aStaticTools.getNumberFormats(xConnection, sal_True));
3170         Reference< XNumberFormatter> xFormatter( m_aContext.createComponent( "com.sun.star.util.NumberFormatter" ), UNO_QUERY );
3171         xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
3172 		Locale aAppLocale = Application::GetSettings().GetUILocale();
3173 		LocaleDataWrapper aLocaleWrapper( m_aContext.getLegacyServiceFactory(), aAppLocale );
3174 
3175 		// retrieving the filter
3176 		const Sequence < PropertyValue >* pRow = aFilterRows.getConstArray();
3177 		for (sal_Int32 i = 0, nLen = aFilterRows.getLength(); i < nLen; ++i)
3178 		{
3179 			FmFilterRow aRow;
3180 
3181 			// search a field for the given name
3182 			const PropertyValue* pRefValues = pRow[i].getConstArray();
3183 			for (sal_Int32 j = 0, nLen1 = pRow[i].getLength(); j < nLen1; j++)
3184 			{
3185 				// look for the text component
3186 				Reference< XPropertySet > xField;
3187 				try
3188 				{
3189 					Reference< XPropertySet > xSet;
3190 					::rtl::OUString aRealName;
3191 
3192 					// first look with the given name
3193 					if (xQueryColumns->hasByName(pRefValues[j].Name))
3194 					{
3195 						xQueryColumns->getByName(pRefValues[j].Name) >>= xSet;
3196 
3197 						// get the RealName
3198 						xSet->getPropertyValue(::rtl::OUString::createFromAscii("RealName")) >>= aRealName;
3199 
3200 						// compare the condition field name and the RealName
3201 						if (aCompare(aRealName, pRefValues[j].Name))
3202 							xField = xSet;
3203 					}
3204 					if (!xField.is())
3205 					{
3206 						// no we have to check every column to find the realname
3207 						Reference< XIndexAccess > xColumnsByIndex(xQueryColumns, UNO_QUERY);
3208 						for (sal_Int32 n = 0, nCount = xColumnsByIndex->getCount(); n < nCount; n++)
3209 						{
3210 							xColumnsByIndex->getByIndex(n) >>= xSet;
3211 							xSet->getPropertyValue(::rtl::OUString::createFromAscii("RealName")) >>= aRealName;
3212 							if (aCompare(aRealName, pRefValues[j].Name))
3213 							{
3214 								// get the column by its alias
3215 								xField = xSet;
3216 								break;
3217 							}
3218 						}
3219 					}
3220 					if (!xField.is())
3221 						continue;
3222 				}
3223 				catch (const Exception&)
3224 				{
3225 					continue;
3226 				}
3227 
3228 				// find the text component
3229 				for (::std::vector<FmFieldInfo>::iterator iter = rFieldInfos.begin();
3230 					iter != rFieldInfos.end(); iter++)
3231 				{
3232 					// we found the field so insert a new entry to the filter row
3233 					if ((*iter).xField == xField)
3234 					{
3235 						// do we already have the control ?
3236 						if (aRow.find((*iter).xText) != aRow.end())
3237 						{
3238 							::rtl::OUString aCompText = aRow[(*iter).xText];
3239 							aCompText += ::rtl::OUString::createFromAscii(" ");
3240 							::rtl::OString aVal = m_xParser->getContext().getIntlKeywordAscii(OParseContext::KEY_AND);
3241 							aCompText += ::rtl::OUString(aVal.getStr(),aVal.getLength(),RTL_TEXTENCODING_ASCII_US);
3242 							aCompText += ::rtl::OUString::createFromAscii(" ");
3243 							aCompText += ::comphelper::getString(pRefValues[j].Value);
3244 							aRow[(*iter).xText] = aCompText;
3245 						}
3246 						else
3247 						{
3248 							::rtl::OUString sPredicate,sErrorMsg;
3249 							pRefValues[j].Value >>= sPredicate;
3250 							::rtl::Reference< ISQLParseNode > xParseNode = predicateTree(sErrorMsg, sPredicate, xFormatter, xField);
3251                             if ( xParseNode.is() )
3252                             {
3253 								::rtl::OUString sCriteria;
3254 								xParseNode->parseNodeToPredicateStr( sCriteria
3255 																	,xConnection
3256 																	,xFormatter
3257 																	,xField
3258 																	,aAppLocale
3259 																	,(sal_Char)aLocaleWrapper.getNumDecimalSep().GetChar(0)
3260 																	,getParseContext());
3261                                 aRow[(*iter).xText] = sCriteria;
3262                             }
3263 						}
3264 					}
3265 				}
3266 			}
3267 
3268 			if (aRow.empty())
3269 				continue;
3270 
3271             impl_addFilterRow( aRow );
3272 		}
3273 	}
3274 
3275 	// now set the filter controls
3276     for (   ::std::vector<FmFieldInfo>::iterator field = rFieldInfos.begin();
3277             field != rFieldInfos.end();
3278             ++field
3279         )
3280     {
3281         m_aFilterComponents.push_back( field->xText );
3282     }
3283 }
3284 
3285 //------------------------------------------------------------------------------
3286 void FormController::startFiltering()
3287 {
3288     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3289 
3290 	OStaticDataAccessTools aStaticTools;
3291     Reference< XConnection >  xConnection( aStaticTools.getRowSetConnection( Reference< XRowSet >( m_xModelAsIndex, UNO_QUERY ) ) );
3292 	if ( !xConnection.is() )
3293 		// nothing to do - can't filter a form which is not connected
3294 		// 98023 - 19.03.2002 - fs@openoffice.org
3295 		return;
3296 
3297     // stop listening for controls
3298     if (isListeningForChanges())
3299         stopListening();
3300 
3301     m_bFiltering = sal_True;
3302 
3303     // as we don't want new controls to be attached to the scripting environment
3304     // we change attach flags
3305     m_bAttachEvents = sal_False;
3306 
3307     // Austauschen der Kontrols fuer das aktuelle Formular
3308     Sequence< Reference< XControl > > aControlsCopy( m_aControls );
3309     const Reference< XControl >* pControls = aControlsCopy.getConstArray();
3310     sal_Int32 nControlCount = aControlsCopy.getLength();
3311 
3312     // the control we have to activate after replacement
3313     Reference< XDatabaseMetaData >  xMetaData(xConnection->getMetaData());
3314     Reference< XNumberFormatsSupplier >  xFormatSupplier = aStaticTools.getNumberFormats(xConnection, sal_True);
3315     Reference< XNumberFormatter >  xFormatter( m_aContext.createComponent( "com.sun.star.util.NumberFormatter" ), UNO_QUERY );
3316     xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
3317 
3318     // structure for storing the field info
3319     ::std::vector<FmFieldInfo> aFieldInfos;
3320 
3321     for (sal_Int32 i = nControlCount; i > 0;)
3322     {
3323         Reference< XControl > xControl = pControls[--i];
3324         if (xControl.is())
3325         {
3326             // no events for the control anymore
3327             removeFromEventAttacher(xControl);
3328 
3329             // do we have a mode selector
3330             Reference< XModeSelector >  xSelector(xControl, UNO_QUERY);
3331             if (xSelector.is())
3332             {
3333                 xSelector->setMode( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterMode" ) ) );
3334 
3335                 // listening for new controls of the selector
3336                 Reference< XContainer >  xContainer(xSelector, UNO_QUERY);
3337                 if (xContainer.is())
3338                     xContainer->addContainerListener(this);
3339 
3340                 Reference< XEnumerationAccess >  xElementAccess(xSelector, UNO_QUERY);
3341                 if (xElementAccess.is())
3342                 {
3343                     Reference< XEnumeration >  xEnumeration(xElementAccess->createEnumeration());
3344                     Reference< XControl >  xSubControl;
3345                     while (xEnumeration->hasMoreElements())
3346                     {
3347                         xEnumeration->nextElement() >>= xSubControl;
3348                         if (xSubControl.is())
3349                         {
3350                             Reference< XPropertySet >  xSet(xSubControl->getModel(), UNO_QUERY);
3351                             if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
3352                             {
3353                                 // does the model use a bound field ?
3354                                 Reference< XPropertySet >  xField;
3355                                 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
3356 
3357                                 Reference< XTextComponent >  xText(xSubControl, UNO_QUERY);
3358                                 // may we filter the field?
3359                                 if (xText.is() && xField.is() && ::comphelper::hasProperty(FM_PROP_SEARCHABLE, xField) &&
3360                                     ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_SEARCHABLE)))
3361                                 {
3362                                     aFieldInfos.push_back(FmFieldInfo(xField, xText));
3363                                     xText->addTextListener(this);
3364                                 }
3365                             }
3366                         }
3367                     }
3368                 }
3369                 continue;
3370             }
3371 
3372             Reference< XPropertySet >  xModel( xControl->getModel(), UNO_QUERY );
3373             if (xModel.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xModel))
3374             {
3375                 // does the model use a bound field ?
3376                 Any aVal = xModel->getPropertyValue(FM_PROP_BOUNDFIELD);
3377                 Reference< XPropertySet >  xField;
3378                 aVal >>= xField;
3379 
3380                 // may we filter the field?
3381 
3382                 if  (   xField.is()
3383                     &&  ::comphelper::hasProperty( FM_PROP_SEARCHABLE, xField )
3384                     && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_SEARCHABLE ) )
3385                     )
3386                 {
3387                     // create a filter control
3388                     Sequence< Any > aCreationArgs( 3 );
3389                     aCreationArgs[ 0 ] <<= NamedValue( ::rtl::OUString::createFromAscii( "MessageParent" ), makeAny( VCLUnoHelper::GetInterface( getDialogParentWindow() ) ) );
3390                     aCreationArgs[ 1 ] <<= NamedValue( ::rtl::OUString::createFromAscii( "NumberFormatter" ), makeAny( xFormatter ) );
3391                     aCreationArgs[ 2 ] <<= NamedValue( ::rtl::OUString::createFromAscii( "ControlModel" ), makeAny( xModel ) );
3392                     Reference< XControl > xFilterControl(
3393                         m_aContext.createComponentWithArguments( "com.sun.star.form.control.FilterControl", aCreationArgs ),
3394                         UNO_QUERY
3395                     );
3396                     DBG_ASSERT( xFilterControl.is(), "FormController::startFiltering: could not create a filter control!" );
3397 
3398                     if ( replaceControl( xControl, xFilterControl ) )
3399                     {
3400                         Reference< XTextComponent > xFilterText( xFilterControl, UNO_QUERY );
3401                         aFieldInfos.push_back( FmFieldInfo( xField, xFilterText ) );
3402                         xFilterText->addTextListener(this);
3403                     }
3404                 }
3405             }
3406             else
3407             {
3408                 // abmelden vom EventManager
3409             }
3410         }
3411     }
3412 
3413     // we have all filter controls now, so the next step is to read the filters from the form
3414     // resolve all aliases and set the current filter to the according structure
3415     setFilter(aFieldInfos);
3416 
3417     Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
3418 	if ( xSet.is() )
3419 		stopFormListening( xSet, sal_True );
3420 
3421     impl_setTextOnAllFilter_throw();
3422 
3423     // lock all controls which are not used for filtering
3424     m_bLocked = determineLockState();
3425     setLocks();
3426     m_bAttachEvents = sal_True;
3427 }
3428 
3429 //------------------------------------------------------------------------------
3430 void FormController::stopFiltering()
3431 {
3432     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3433 	if ( !m_bFiltering ) // #104693# OJ
3434 	{	// nothing to do
3435 		return;
3436 	}
3437 
3438     m_bFiltering = sal_False;
3439     m_bDetachEvents = sal_False;
3440 
3441     ::comphelper::disposeComponent(m_xComposer);
3442 
3443     // Austauschen der Kontrols fuer das aktuelle Formular
3444     Sequence< Reference< XControl > > aControlsCopy( m_aControls );
3445     const Reference< XControl > * pControls = aControlsCopy.getConstArray();
3446     sal_Int32 nControlCount = aControlsCopy.getLength();
3447 
3448     // clear the filter control map
3449     ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), RemoveComponentTextListener( this ) );
3450     m_aFilterComponents.clear();
3451 
3452     for ( sal_Int32 i = nControlCount; i > 0; )
3453     {
3454         Reference< XControl > xControl = pControls[--i];
3455         if (xControl.is())
3456         {
3457             // now enable eventhandling again
3458             addToEventAttacher(xControl);
3459 
3460             Reference< XModeSelector >  xSelector(xControl, UNO_QUERY);
3461             if (xSelector.is())
3462             {
3463                 xSelector->setMode( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DataMode" ) ) );
3464 
3465                 // listening for new controls of the selector
3466                 Reference< XContainer >  xContainer(xSelector, UNO_QUERY);
3467                 if (xContainer.is())
3468                     xContainer->removeContainerListener(this);
3469                 continue;
3470             }
3471 
3472             Reference< XPropertySet >  xSet(xControl->getModel(), UNO_QUERY);
3473             if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
3474             {
3475                 // does the model use a bound field ?
3476                 Reference< XPropertySet >  xField;
3477                 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
3478 
3479                 // may we filter the field?
3480                 if  (   xField.is()
3481                     &&  ::comphelper::hasProperty( FM_PROP_SEARCHABLE, xField )
3482                     &&  ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_SEARCHABLE ) )
3483                     )
3484                 {
3485                     ::rtl::OUString sServiceName;
3486                     OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DEFAULTCONTROL ) >>= sServiceName );
3487                     Reference< XControl > xNewControl( m_aContext.createComponent( sServiceName ), UNO_QUERY );
3488                     replaceControl( xControl, xNewControl );
3489                 }
3490             }
3491         }
3492     }
3493 
3494     Reference< XPropertySet >  xSet( m_xModelAsIndex, UNO_QUERY );
3495     if ( xSet.is() )
3496 		startFormListening( xSet, sal_True );
3497 
3498     m_bDetachEvents = sal_True;
3499 
3500     m_aFilterRows.clear();
3501     m_nCurrentFilterPosition = -1;
3502 
3503     // release the locks if possible
3504     // lock all controls which are not used for filtering
3505     m_bLocked = determineLockState();
3506     setLocks();
3507 
3508     // restart listening for control modifications
3509     if (isListeningForChanges())
3510         startListening();
3511 }
3512 
3513 // XModeSelector
3514 //------------------------------------------------------------------------------
3515 void FormController::setMode(const ::rtl::OUString& Mode) throw( NoSupportException, RuntimeException )
3516 {
3517     ::osl::MutexGuard aGuard( m_aMutex );
3518     impl_checkDisposed_throw();
3519 
3520     if (!supportsMode(Mode))
3521         throw NoSupportException();
3522 
3523     if (Mode == m_aMode)
3524         return;
3525 
3526     m_aMode = Mode;
3527 
3528     if ( Mode.equalsAscii( "FilterMode" ) )
3529         startFiltering();
3530     else
3531         stopFiltering();
3532 
3533     for (FmFormControllers::const_iterator i = m_aChilds.begin();
3534         i != m_aChilds.end(); ++i)
3535     {
3536 		Reference< XModeSelector > xMode(*i, UNO_QUERY);
3537 		if ( xMode.is() )
3538 			xMode->setMode(Mode);
3539     }
3540 }
3541 
3542 //------------------------------------------------------------------------------
3543 ::rtl::OUString SAL_CALL FormController::getMode(void) throw( RuntimeException )
3544 {
3545     ::osl::MutexGuard aGuard( m_aMutex );
3546     impl_checkDisposed_throw();
3547 
3548     return m_aMode;
3549 }
3550 
3551 //------------------------------------------------------------------------------
3552 Sequence< ::rtl::OUString > SAL_CALL FormController::getSupportedModes(void) throw( RuntimeException )
3553 {
3554     ::osl::MutexGuard aGuard( m_aMutex );
3555     impl_checkDisposed_throw();
3556 
3557     static Sequence< ::rtl::OUString > aModes;
3558     if (!aModes.getLength())
3559     {
3560         aModes.realloc(2);
3561         ::rtl::OUString* pModes = aModes.getArray();
3562         pModes[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DataMode" ) );
3563         pModes[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterMode" ) );
3564     }
3565     return aModes;
3566 }
3567 
3568 //------------------------------------------------------------------------------
3569 sal_Bool SAL_CALL FormController::supportsMode(const ::rtl::OUString& Mode) throw( RuntimeException )
3570 {
3571     ::osl::MutexGuard aGuard( m_aMutex );
3572     impl_checkDisposed_throw();
3573 
3574     Sequence< ::rtl::OUString > aModes(getSupportedModes());
3575     const ::rtl::OUString* pModes = aModes.getConstArray();
3576     for (sal_Int32 i = aModes.getLength(); i > 0; )
3577     {
3578         if (pModes[--i] == Mode)
3579             return sal_True;
3580     }
3581     return sal_False;
3582 }
3583 
3584 //------------------------------------------------------------------------------
3585 Window* FormController::getDialogParentWindow()
3586 {
3587     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3588     Window* pParentWindow = NULL;
3589     try
3590     {
3591         Reference< XControl > xContainerControl( getContainer(), UNO_QUERY_THROW );
3592         Reference< XWindowPeer > xContainerPeer( xContainerControl->getPeer(), UNO_QUERY_THROW );
3593         pParentWindow = VCLUnoHelper::GetWindow( xContainerPeer );
3594     }
3595     catch( const Exception& )
3596     {
3597 	    DBG_UNHANDLED_EXCEPTION();
3598     }
3599     return pParentWindow;
3600 }
3601 //------------------------------------------------------------------------------
3602 bool FormController::checkFormComponentValidity( ::rtl::OUString& /* [out] */ _rFirstInvalidityExplanation, Reference< XControlModel >& /* [out] */ _rxFirstInvalidModel ) SAL_THROW(())
3603 {
3604     try
3605     {
3606         Reference< XEnumerationAccess > xControlEnumAcc( getModel(), UNO_QUERY );
3607         Reference< XEnumeration > xControlEnumeration;
3608         if ( xControlEnumAcc.is() )
3609             xControlEnumeration = xControlEnumAcc->createEnumeration();
3610         OSL_ENSURE( xControlEnumeration.is(), "FormController::checkFormComponentValidity: cannot enumerate the controls!" );
3611         if ( !xControlEnumeration.is() )
3612             // assume all valid
3613             return true;
3614 
3615         Reference< XValidatableFormComponent > xValidatable;
3616         while ( xControlEnumeration->hasMoreElements() )
3617         {
3618             if ( !( xControlEnumeration->nextElement() >>= xValidatable ) )
3619                 // control does not support validation
3620                 continue;
3621 
3622             if ( xValidatable->isValid() )
3623                 continue;
3624 
3625             Reference< XValidator > xValidator( xValidatable->getValidator() );
3626             OSL_ENSURE( xValidator.is(), "FormController::checkFormComponentValidity: invalid, but no validator?" );
3627             if ( !xValidator.is() )
3628                 // this violates the interface definition of css.form.validation.XValidatableFormComponent ...
3629                 continue;
3630 
3631             _rFirstInvalidityExplanation = xValidator->explainInvalid( xValidatable->getCurrentValue() );
3632             _rxFirstInvalidModel = _rxFirstInvalidModel.query( xValidatable );
3633             return false;
3634         }
3635     }
3636     catch( const Exception& )
3637     {
3638         DBG_UNHANDLED_EXCEPTION();
3639     }
3640     return true;
3641 }
3642 
3643 //------------------------------------------------------------------------------
3644 Reference< XControl > FormController::locateControl( const Reference< XControlModel >& _rxModel ) SAL_THROW(())
3645 {
3646     try
3647     {
3648         Sequence< Reference< XControl > > aControls( getControls() );
3649         const Reference< XControl >* pControls = aControls.getConstArray();
3650         const Reference< XControl >* pControlsEnd = aControls.getConstArray() + aControls.getLength();
3651 
3652         for ( ; pControls != pControlsEnd; ++pControls )
3653         {
3654             OSL_ENSURE( pControls->is(), "FormController::locateControl: NULL-control?" );
3655             if ( pControls->is() )
3656             {
3657                 if ( ( *pControls)->getModel() == _rxModel )
3658                     return *pControls;
3659             }
3660         }
3661         OSL_ENSURE( sal_False, "FormController::locateControl: did not find a control for this model!" );
3662     }
3663     catch( const Exception& )
3664     {
3665         DBG_UNHANDLED_EXCEPTION();
3666     }
3667     return NULL;
3668 }
3669 
3670 //------------------------------------------------------------------------------
3671 namespace
3672 {
3673     void displayErrorSetFocus( const String& _rMessage, const Reference< XControl >& _rxFocusControl, Window* _pDialogParent )
3674     {
3675 	    SQLContext aError;
3676 	    aError.Message = String( SVX_RES( RID_STR_WRITEERROR ) );
3677 	    aError.Details = _rMessage;
3678 	    displayException( aError, _pDialogParent );
3679 
3680         if ( _rxFocusControl.is() )
3681         {
3682             Reference< XWindow > xControlWindow( _rxFocusControl, UNO_QUERY );
3683             OSL_ENSURE( xControlWindow.is(), "displayErrorSetFocus: invalid control!" );
3684             if ( xControlWindow.is() )
3685                 xControlWindow->setFocus();
3686         }
3687     }
3688 
3689     sal_Bool lcl_shouldValidateRequiredFields_nothrow( const Reference< XInterface >& _rxForm )
3690     {
3691         try
3692         {
3693             static ::rtl::OUString s_sFormsCheckRequiredFields( RTL_CONSTASCII_USTRINGPARAM( "FormsCheckRequiredFields" ) );
3694 
3695             // first, check whether the form has a property telling us the answer
3696             // this allows people to use the XPropertyContainer interface of a form to control
3697             // the behaviour on a per-form basis.
3698             Reference< XPropertySet > xFormProps( _rxForm, UNO_QUERY_THROW );
3699             Reference< XPropertySetInfo > xPSI( xFormProps->getPropertySetInfo() );
3700             if ( xPSI->hasPropertyByName( s_sFormsCheckRequiredFields ) )
3701             {
3702                 sal_Bool bShouldValidate = true;
3703                 OSL_VERIFY( xFormProps->getPropertyValue( s_sFormsCheckRequiredFields ) >>= bShouldValidate );
3704                 return bShouldValidate;
3705             }
3706 
3707             // next, check the data source which created the connection
3708             Reference< XChild > xConnectionAsChild( xFormProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ), UNO_QUERY_THROW );
3709             Reference< XPropertySet > xDataSource( xConnectionAsChild->getParent(), UNO_QUERY );
3710             if ( !xDataSource.is() )
3711                 // seldom (but possible): this is not a connection created by a data source
3712                 return sal_True;
3713 
3714             Reference< XPropertySet > xDataSourceSettings(
3715                 xDataSource->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Settings" ) ) ),
3716                 UNO_QUERY_THROW );
3717 
3718             sal_Bool bShouldValidate = true;
3719             OSL_VERIFY( xDataSourceSettings->getPropertyValue( s_sFormsCheckRequiredFields ) >>= bShouldValidate );
3720             return bShouldValidate;
3721         }
3722         catch( const Exception& )
3723         {
3724         	DBG_UNHANDLED_EXCEPTION();
3725         }
3726 
3727         return sal_True;
3728     }
3729 }
3730 
3731 // XRowSetApproveListener
3732 //------------------------------------------------------------------------------
3733 sal_Bool SAL_CALL FormController::approveRowChange(const RowChangeEvent& _rEvent) throw( RuntimeException )
3734 {
3735     ::osl::ClearableMutexGuard aGuard( m_aMutex );
3736     impl_checkDisposed_throw();
3737 
3738     ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
3739     sal_Bool bValid = sal_True;
3740     if (aIter.hasMoreElements())
3741     {
3742         RowChangeEvent aEvt( _rEvent );
3743         aEvt.Source = *this;
3744         bValid = ((XRowSetApproveListener*)aIter.next())->approveRowChange(aEvt);
3745     }
3746 
3747     if ( !bValid )
3748         return bValid;
3749 
3750     if  (   ( _rEvent.Action != RowChangeAction::INSERT )
3751         &&  ( _rEvent.Action != RowChangeAction::UPDATE )
3752         )
3753         return bValid;
3754 
3755     // if some of the control models are bound to validators, check them
3756     ::rtl::OUString sInvalidityExplanation;
3757     Reference< XControlModel > xInvalidModel;
3758     if ( !checkFormComponentValidity( sInvalidityExplanation, xInvalidModel ) )
3759     {
3760         Reference< XControl > xControl( locateControl( xInvalidModel ) );
3761         aGuard.clear();
3762         displayErrorSetFocus( sInvalidityExplanation, xControl, getDialogParentWindow() );
3763         return false;
3764     }
3765 
3766     // check values on NULL and required flag
3767     if ( !lcl_shouldValidateRequiredFields_nothrow( _rEvent.Source ) )
3768         return sal_True;
3769 
3770     OSL_ENSURE( m_pColumnInfoCache.get(), "FormController::approveRowChange: no column infos!" );
3771     if ( !m_pColumnInfoCache.get() )
3772         return sal_True;
3773 
3774     try
3775     {
3776         if ( !m_pColumnInfoCache->controlsInitialized() )
3777             m_pColumnInfoCache->initializeControls( getControls() );
3778 
3779         size_t colCount = m_pColumnInfoCache->getColumnCount();
3780         for ( size_t col = 0; col < colCount; ++col )
3781         {
3782             const ColumnInfo& rColInfo = m_pColumnInfoCache->getColumnInfo( col );
3783             if ( rColInfo.nNullable != ColumnValue::NO_NULLS )
3784                 continue;
3785 
3786             if ( rColInfo.bAutoIncrement )
3787                 continue;
3788 
3789             if ( rColInfo.bReadOnly )
3790                 continue;
3791 
3792             if ( !rColInfo.xFirstControlWithInputRequired.is() && !rColInfo.xFirstGridWithInputRequiredColumn.is() )
3793                 continue;
3794 
3795             // TODO: in case of binary fields, this "getString" below is extremely expensive
3796             if ( rColInfo.xColumn->getString().getLength() || !rColInfo.xColumn->wasNull() )
3797                 continue;
3798 
3799             String sMessage( SVX_RES( RID_ERR_FIELDREQUIRED ) );
3800             sMessage.SearchAndReplace( '#', rColInfo.sName );
3801 
3802             // the control to focus
3803             Reference< XControl > xControl( rColInfo.xFirstControlWithInputRequired );
3804             if ( !xControl.is() )
3805                 xControl.set( rColInfo.xFirstGridWithInputRequiredColumn, UNO_QUERY );
3806 
3807             aGuard.clear();
3808             displayErrorSetFocus( sMessage, rColInfo.xFirstControlWithInputRequired, getDialogParentWindow() );
3809             return sal_False;
3810         }
3811     }
3812     catch( const Exception& )
3813     {
3814     	DBG_UNHANDLED_EXCEPTION();
3815     }
3816 
3817     return true;
3818 }
3819 
3820 //------------------------------------------------------------------------------
3821 sal_Bool SAL_CALL FormController::approveCursorMove(const EventObject& event) throw( RuntimeException )
3822 {
3823     ::osl::MutexGuard aGuard( m_aMutex );
3824     impl_checkDisposed_throw();
3825 
3826     ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
3827     if (aIter.hasMoreElements())
3828     {
3829         EventObject aEvt(event);
3830         aEvt.Source = *this;
3831         return ((XRowSetApproveListener*)aIter.next())->approveCursorMove(aEvt);
3832     }
3833 
3834     return sal_True;
3835 }
3836 
3837 //------------------------------------------------------------------------------
3838 sal_Bool SAL_CALL FormController::approveRowSetChange(const EventObject& event) throw( RuntimeException )
3839 {
3840     ::osl::MutexGuard aGuard( m_aMutex );
3841     impl_checkDisposed_throw();
3842 
3843     ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
3844     if (aIter.hasMoreElements())
3845     {
3846         EventObject aEvt(event);
3847         aEvt.Source = *this;
3848         return ((XRowSetApproveListener*)aIter.next())->approveRowSetChange(aEvt);
3849     }
3850 
3851     return sal_True;
3852 }
3853 
3854 // XRowSetApproveBroadcaster
3855 //------------------------------------------------------------------------------
3856 void SAL_CALL FormController::addRowSetApproveListener(const Reference< XRowSetApproveListener > & _rxListener) throw( RuntimeException )
3857 {
3858     ::osl::MutexGuard aGuard( m_aMutex );
3859     impl_checkDisposed_throw();
3860 
3861     m_aRowSetApproveListeners.addInterface(_rxListener);
3862 }
3863 
3864 //------------------------------------------------------------------------------
3865 void SAL_CALL FormController::removeRowSetApproveListener(const Reference< XRowSetApproveListener > & _rxListener) throw( RuntimeException )
3866 {
3867     ::osl::MutexGuard aGuard( m_aMutex );
3868     impl_checkDisposed_throw();
3869 
3870     m_aRowSetApproveListeners.removeInterface(_rxListener);
3871 }
3872 
3873 // XErrorListener
3874 //------------------------------------------------------------------------------
3875 void SAL_CALL FormController::errorOccured(const SQLErrorEvent& aEvent) throw( RuntimeException )
3876 {
3877     ::osl::ClearableMutexGuard aGuard( m_aMutex );
3878     impl_checkDisposed_throw();
3879 
3880     ::cppu::OInterfaceIteratorHelper aIter(m_aErrorListeners);
3881     if (aIter.hasMoreElements())
3882     {
3883         SQLErrorEvent aEvt(aEvent);
3884         aEvt.Source = *this;
3885         ((XSQLErrorListener*)aIter.next())->errorOccured(aEvt);
3886     }
3887     else
3888     {
3889         aGuard.clear();
3890         displayException( aEvent );
3891     }
3892 }
3893 
3894 // XErrorBroadcaster
3895 //------------------------------------------------------------------------------
3896 void SAL_CALL FormController::addSQLErrorListener(const Reference< XSQLErrorListener > & aListener) throw( RuntimeException )
3897 {
3898     ::osl::MutexGuard aGuard( m_aMutex );
3899     impl_checkDisposed_throw();
3900 
3901     m_aErrorListeners.addInterface(aListener);
3902 }
3903 
3904 //------------------------------------------------------------------------------
3905 void SAL_CALL FormController::removeSQLErrorListener(const Reference< XSQLErrorListener > & aListener) throw( RuntimeException )
3906 {
3907     ::osl::MutexGuard aGuard( m_aMutex );
3908     impl_checkDisposed_throw();
3909 
3910     m_aErrorListeners.removeInterface(aListener);
3911 }
3912 
3913 // XDatabaseParameterBroadcaster2
3914 //------------------------------------------------------------------------------
3915 void SAL_CALL FormController::addDatabaseParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException )
3916 {
3917     ::osl::MutexGuard aGuard( m_aMutex );
3918     impl_checkDisposed_throw();
3919 
3920     m_aParameterListeners.addInterface(aListener);
3921 }
3922 
3923 //------------------------------------------------------------------------------
3924 void SAL_CALL FormController::removeDatabaseParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException )
3925 {
3926     ::osl::MutexGuard aGuard( m_aMutex );
3927     impl_checkDisposed_throw();
3928 
3929     m_aParameterListeners.removeInterface(aListener);
3930 }
3931 
3932 // XDatabaseParameterBroadcaster
3933 //------------------------------------------------------------------------------
3934 void SAL_CALL FormController::addParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException )
3935 {
3936     FormController::addDatabaseParameterListener( aListener );
3937 }
3938 
3939 //------------------------------------------------------------------------------
3940 void SAL_CALL FormController::removeParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException )
3941 {
3942     FormController::removeDatabaseParameterListener( aListener );
3943 }
3944 
3945 // XDatabaseParameterListener
3946 //------------------------------------------------------------------------------
3947 sal_Bool SAL_CALL FormController::approveParameter(const DatabaseParameterEvent& aEvent) throw( RuntimeException )
3948 {
3949     ::vos::OGuard aSolarGuard(Application::GetSolarMutex());
3950     ::osl::MutexGuard aGuard( m_aMutex );
3951     impl_checkDisposed_throw();
3952 
3953     ::cppu::OInterfaceIteratorHelper aIter(m_aParameterListeners);
3954     if (aIter.hasMoreElements())
3955     {
3956         DatabaseParameterEvent aEvt(aEvent);
3957         aEvt.Source = *this;
3958         return ((XDatabaseParameterListener*)aIter.next())->approveParameter(aEvt);
3959     }
3960     else
3961     {
3962         // default handling: instantiate an interaction handler and let it handle the parameter request
3963         try
3964         {
3965             if ( !ensureInteractionHandler() )
3966                 return sal_False;
3967 
3968             // two continuations allowed: OK and Cancel
3969             OParameterContinuation* pParamValues = new OParameterContinuation;
3970             OInteractionAbort* pAbort = new OInteractionAbort;
3971             // the request
3972             ParametersRequest aRequest;
3973             aRequest.Parameters = aEvent.Parameters;
3974             aRequest.Connection = OStaticDataAccessTools().getRowSetConnection(Reference< XRowSet >(aEvent.Source, UNO_QUERY));
3975             OInteractionRequest* pParamRequest = new OInteractionRequest(makeAny(aRequest));
3976             Reference< XInteractionRequest > xParamRequest(pParamRequest);
3977             // some knittings
3978             pParamRequest->addContinuation(pParamValues);
3979             pParamRequest->addContinuation(pAbort);
3980 
3981             // handle the request
3982             m_xInteractionHandler->handle(xParamRequest);
3983 
3984             if (!pParamValues->wasSelected())
3985                 // canceled
3986                 return sal_False;
3987 
3988             // transfer the values into the parameter supplier
3989             Sequence< PropertyValue > aFinalValues = pParamValues->getValues();
3990             if (aFinalValues.getLength() != aRequest.Parameters->getCount())
3991             {
3992                 DBG_ERROR("FormController::approveParameter: the InteractionHandler returned nonsense!");
3993                 return sal_False;
3994             }
3995             const PropertyValue* pFinalValues = aFinalValues.getConstArray();
3996             for (sal_Int32 i=0; i<aFinalValues.getLength(); ++i, ++pFinalValues)
3997             {
3998                 Reference< XPropertySet > xParam;
3999                 ::cppu::extractInterface(xParam, aRequest.Parameters->getByIndex(i));
4000                 if (xParam.is())
4001                 {
4002 #ifdef DBG_UTIL
4003                     ::rtl::OUString sName;
4004                     xParam->getPropertyValue(FM_PROP_NAME) >>= sName;
4005                     DBG_ASSERT(sName.equals(pFinalValues->Name), "FormController::approveParameter: suspicious value names!");
4006 #endif
4007                     try { xParam->setPropertyValue(FM_PROP_VALUE, pFinalValues->Value); }
4008                     catch(Exception&)
4009                     {
4010                         DBG_ERROR("FormController::approveParameter: setting one of the properties failed!");
4011                     }
4012                 }
4013             }
4014         }
4015         catch(Exception&)
4016         {
4017             DBG_UNHANDLED_EXCEPTION();
4018         }
4019     }
4020     return sal_True;
4021 }
4022 
4023 // XConfirmDeleteBroadcaster
4024 //------------------------------------------------------------------------------
4025 void SAL_CALL FormController::addConfirmDeleteListener(const Reference< XConfirmDeleteListener > & aListener) throw( RuntimeException )
4026 {
4027     ::osl::MutexGuard aGuard( m_aMutex );
4028     impl_checkDisposed_throw();
4029 
4030     m_aDeleteListeners.addInterface(aListener);
4031 }
4032 
4033 //------------------------------------------------------------------------------
4034 void SAL_CALL FormController::removeConfirmDeleteListener(const Reference< XConfirmDeleteListener > & aListener) throw( RuntimeException )
4035 {
4036     ::osl::MutexGuard aGuard( m_aMutex );
4037     impl_checkDisposed_throw();
4038 
4039     m_aDeleteListeners.removeInterface(aListener);
4040 }
4041 
4042 // XConfirmDeleteListener
4043 //------------------------------------------------------------------------------
4044 sal_Bool SAL_CALL FormController::confirmDelete(const RowChangeEvent& aEvent) throw( RuntimeException )
4045 {
4046     ::osl::MutexGuard aGuard( m_aMutex );
4047     impl_checkDisposed_throw();
4048 
4049     ::cppu::OInterfaceIteratorHelper aIter(m_aDeleteListeners);
4050     if (aIter.hasMoreElements())
4051     {
4052         RowChangeEvent aEvt(aEvent);
4053         aEvt.Source = *this;
4054         return ((XConfirmDeleteListener*)aIter.next())->confirmDelete(aEvt);
4055     }
4056     // default handling: instantiate an interaction handler and let it handle the request
4057 
4058     String sTitle;
4059     sal_Int32 nLength = aEvent.Rows;
4060     if ( nLength > 1 )
4061     {
4062         sTitle = SVX_RES( RID_STR_DELETECONFIRM_RECORDS );
4063         sTitle.SearchAndReplace( '#', String::CreateFromInt32( nLength ) );
4064     }
4065     else
4066         sTitle = SVX_RES( RID_STR_DELETECONFIRM_RECORD );
4067 
4068     try
4069     {
4070         if ( !ensureInteractionHandler() )
4071             return sal_False;
4072 
4073         // two continuations allowed: Yes and No
4074         OInteractionApprove* pApprove = new OInteractionApprove;
4075         OInteractionDisapprove* pDisapprove = new OInteractionDisapprove;
4076 
4077         // the request
4078         SQLWarning aWarning;
4079         aWarning.Message = sTitle;
4080         SQLWarning aDetails;
4081         aDetails.Message = String( SVX_RES( RID_STR_DELETECONFIRM ) );
4082         aWarning.NextException <<= aDetails;
4083 
4084         OInteractionRequest* pRequest = new OInteractionRequest( makeAny( aWarning ) );
4085         Reference< XInteractionRequest > xRequest( pRequest );
4086 
4087         // some knittings
4088         pRequest->addContinuation( pApprove );
4089         pRequest->addContinuation( pDisapprove );
4090 
4091         // handle the request
4092         m_xInteractionHandler->handle( xRequest );
4093 
4094         if ( pApprove->wasSelected() )
4095             return sal_True;
4096     }
4097     catch( const Exception& )
4098     {
4099     	DBG_UNHANDLED_EXCEPTION();
4100     }
4101 
4102     return sal_False;
4103 }
4104 
4105 //------------------------------------------------------------------------------
4106 void SAL_CALL FormController::invalidateFeatures( const Sequence< ::sal_Int16 >& _Features ) throw (RuntimeException)
4107 {
4108     ::osl::MutexGuard aGuard( m_aMutex );
4109     // for now, just copy the ids of the features, because ....
4110     ::std::copy( _Features.getConstArray(), _Features.getConstArray() + _Features.getLength(),
4111         ::std::insert_iterator< ::std::set< sal_Int16 > >( m_aInvalidFeatures, m_aInvalidFeatures.begin() )
4112     );
4113 
4114     // ... we will do the real invalidation asynchronously
4115     if ( !m_aFeatureInvalidationTimer.IsActive() )
4116         m_aFeatureInvalidationTimer.Start();
4117 }
4118 
4119 //------------------------------------------------------------------------------
4120 void SAL_CALL FormController::invalidateAllFeatures(  ) throw (RuntimeException)
4121 {
4122     ::osl::ClearableMutexGuard aGuard( m_aMutex );
4123 
4124     Sequence< sal_Int16 > aInterceptedFeatures( m_aFeatureDispatchers.size() );
4125     ::std::transform(
4126         m_aFeatureDispatchers.begin(),
4127         m_aFeatureDispatchers.end(),
4128         aInterceptedFeatures.getArray(),
4129         ::std::select1st< DispatcherContainer::value_type >()
4130     );
4131 
4132     aGuard.clear();
4133     if ( aInterceptedFeatures.getLength() )
4134         invalidateFeatures( aInterceptedFeatures );
4135 }
4136 
4137 //------------------------------------------------------------------------------
4138 Reference< XDispatch >
4139 FormController::interceptedQueryDispatch( const URL& aURL,
4140                                             const ::rtl::OUString& /*aTargetFrameName*/, sal_Int32 /*nSearchFlags*/)
4141                                             throw( RuntimeException )
4142 {
4143     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
4144     Reference< XDispatch >  xReturn;
4145     // dispatches handled by ourself
4146     if  (   ( aURL.Complete == FMURL_CONFIRM_DELETION )
4147         ||  (   ( aURL.Complete.equalsAscii( "private:/InteractionHandler" ) )
4148             &&  ensureInteractionHandler()
4149             )
4150         )
4151 		xReturn = static_cast< XDispatch* >( this );
4152 
4153     // dispatches of FormSlot-URLs we have to translate
4154     if ( !xReturn.is() && m_xFormOperations.is() )
4155     {
4156         // find the slot id which corresponds to the URL
4157         sal_Int32 nFeatureSlotId = ::svx::FeatureSlotTranslation::getControllerFeatureSlotIdForURL( aURL.Main );
4158         sal_Int16 nFormFeature = ( nFeatureSlotId != -1 ) ? ::svx::FeatureSlotTranslation::getFormFeatureForSlotId( nFeatureSlotId ) : -1;
4159         if ( nFormFeature > 0 )
4160         {
4161             // get the dispatcher for this feature, create if necessary
4162             DispatcherContainer::const_iterator aDispatcherPos = m_aFeatureDispatchers.find( nFormFeature );
4163             if ( aDispatcherPos == m_aFeatureDispatchers.end() )
4164             {
4165                 aDispatcherPos = m_aFeatureDispatchers.insert(
4166                     DispatcherContainer::value_type( nFormFeature, new ::svx::OSingleFeatureDispatcher( aURL, nFormFeature, m_xFormOperations, m_aMutex ) )
4167                 ).first;
4168             }
4169 
4170             OSL_ENSURE( aDispatcherPos->second.is(), "FormController::interceptedQueryDispatch: should have a dispatcher by now!" );
4171             return aDispatcherPos->second;
4172         }
4173     }
4174 
4175     // no more to offer
4176     return xReturn;
4177 }
4178 
4179 //------------------------------------------------------------------------------
4180 void SAL_CALL FormController::dispatch( const URL& _rURL, const Sequence< PropertyValue >& _rArgs ) throw (RuntimeException)
4181 {
4182     if ( _rArgs.getLength() != 1 )
4183     {
4184         DBG_ERROR( "FormController::dispatch: no arguments -> no dispatch!" );
4185         return;
4186     }
4187 
4188     if ( _rURL.Complete.equalsAscii( "private:/InteractionHandler" ) )
4189     {
4190         Reference< XInteractionRequest > xRequest;
4191         OSL_VERIFY( _rArgs[0].Value >>= xRequest );
4192         if ( xRequest.is() )
4193             handle( xRequest );
4194         return;
4195     }
4196 
4197     if  ( _rURL.Complete == FMURL_CONFIRM_DELETION )
4198     {
4199         DBG_ERROR( "FormController::dispatch: How do you expect me to return something via this call?" );
4200             // confirmDelete has a return value - dispatch hasn't
4201         return;
4202     }
4203 
4204 	DBG_ERROR( "FormController::dispatch: unknown URL!" );
4205 }
4206 
4207 //------------------------------------------------------------------------------
4208 void SAL_CALL FormController::addStatusListener( const Reference< XStatusListener >& _rxListener, const URL& _rURL ) throw (RuntimeException)
4209 {
4210     if (_rURL.Complete == FMURL_CONFIRM_DELETION)
4211 	{
4212 		if (_rxListener.is())
4213 		{	// send an initial statusChanged event
4214 			FeatureStateEvent aEvent;
4215 			aEvent.FeatureURL = _rURL;
4216 			aEvent.IsEnabled = sal_True;
4217 			_rxListener->statusChanged(aEvent);
4218 			// and don't add the listener at all (the status will never change)
4219 		}
4220 	}
4221 	else
4222 		OSL_ENSURE(sal_False, "FormController::addStatusListener: invalid (unsupported) URL!");
4223 }
4224 
4225 //------------------------------------------------------------------------------
4226 Reference< XInterface > SAL_CALL FormController::getParent() throw( RuntimeException )
4227 {
4228     return m_xParent;
4229 }
4230 
4231 //------------------------------------------------------------------------------
4232 void SAL_CALL FormController::setParent( const Reference< XInterface >& Parent) throw( NoSupportException, RuntimeException )
4233 {
4234     m_xParent = Parent;
4235 }
4236 
4237 //------------------------------------------------------------------------------
4238 void SAL_CALL FormController::removeStatusListener( const Reference< XStatusListener >& /*_rxListener*/, const URL& _rURL ) throw (RuntimeException)
4239 {
4240     (void)_rURL;
4241 	OSL_ENSURE(_rURL.Complete == FMURL_CONFIRM_DELETION, "FormController::removeStatusListener: invalid (unsupported) URL!");
4242 	// we never really added the listener, so we don't need to remove it
4243 }
4244 
4245 //------------------------------------------------------------------------------
4246 Reference< XDispatchProviderInterceptor >  FormController::createInterceptor(const Reference< XDispatchProviderInterception > & _xInterception)
4247 {
4248     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
4249 #ifdef DBG_UTIL
4250     // check if we already have a interceptor for the given object
4251     for (   ConstInterceptorsIterator aIter = m_aControlDispatchInterceptors.begin();
4252             aIter != m_aControlDispatchInterceptors.end();
4253             ++aIter
4254         )
4255     {
4256         if ((*aIter)->getIntercepted() == _xInterception)
4257             DBG_ERROR("FormController::createInterceptor : we already do intercept this objects dispatches !");
4258     }
4259 #endif
4260 
4261     DispatchInterceptionMultiplexer* pInterceptor = new DispatchInterceptionMultiplexer( _xInterception, this );
4262     pInterceptor->acquire();
4263     m_aControlDispatchInterceptors.insert( m_aControlDispatchInterceptors.end(), pInterceptor );
4264 
4265     return pInterceptor;
4266 }
4267 
4268 //------------------------------------------------------------------------------
4269 bool FormController::ensureInteractionHandler()
4270 {
4271     if ( m_xInteractionHandler.is() )
4272         return true;
4273     if ( m_bAttemptedHandlerCreation )
4274         return false;
4275     m_bAttemptedHandlerCreation = true;
4276 
4277     m_xInteractionHandler.set( m_aContext.createComponent( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.task.InteractionHandler" ) ) ), UNO_QUERY );
4278     OSL_ENSURE( m_xInteractionHandler.is(), "FormController::ensureInteractionHandler: could not create an interaction handler!" );
4279     return m_xInteractionHandler.is();
4280 }
4281 
4282 //------------------------------------------------------------------------------
4283 void SAL_CALL FormController::handle( const Reference< XInteractionRequest >& _rRequest ) throw (RuntimeException)
4284 {
4285     if ( !ensureInteractionHandler() )
4286         return;
4287     m_xInteractionHandler->handle( _rRequest );
4288 }
4289 
4290 //------------------------------------------------------------------------------
4291 void FormController::deleteInterceptor(const Reference< XDispatchProviderInterception > & _xInterception)
4292 {
4293     OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
4294     // search the interceptor responsible for the given object
4295     InterceptorsIterator aIter;
4296     for (   aIter = m_aControlDispatchInterceptors.begin();
4297             aIter != m_aControlDispatchInterceptors.end();
4298             ++aIter
4299         )
4300     {
4301         if ((*aIter)->getIntercepted() == _xInterception)
4302             break;
4303     }
4304     if (aIter == m_aControlDispatchInterceptors.end())
4305     {
4306         return;
4307     }
4308 
4309     // log off the interception from it's interception object
4310     DispatchInterceptionMultiplexer* pInterceptorImpl = *aIter;
4311     pInterceptorImpl->dispose();
4312     pInterceptorImpl->release();
4313 
4314     // remove the interceptor from our array
4315     m_aControlDispatchInterceptors.erase(aIter);
4316 }
4317 
4318 //--------------------------------------------------------------------
4319 void FormController::implInvalidateCurrentControlDependentFeatures()
4320 {
4321     Sequence< sal_Int16 > aCurrentControlDependentFeatures(4);
4322 
4323     aCurrentControlDependentFeatures[0] = FormFeature::SortAscending;
4324     aCurrentControlDependentFeatures[1] = FormFeature::SortDescending;
4325     aCurrentControlDependentFeatures[2] = FormFeature::AutoFilter;
4326     aCurrentControlDependentFeatures[3] = FormFeature::RefreshCurrentControl;
4327 
4328     invalidateFeatures( aCurrentControlDependentFeatures );
4329 }
4330 
4331 //--------------------------------------------------------------------
4332 void SAL_CALL FormController::columnChanged( const EventObject& /*_event*/ ) throw (RuntimeException)
4333 {
4334     implInvalidateCurrentControlDependentFeatures();
4335 }
4336 
4337 }   // namespace svxform
4338