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