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