fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / svx / source / form / formcontroller.cxx
blob861c33ff264957ff83091d396afd90afd98a5fc4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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.hrc"
28 #include "svx/dialmgr.hxx"
29 #include "svx/fmresids.hrc"
30 #include "fmservs.hxx"
31 #include "svx/fmtools.hxx"
32 #include "fmurl.hxx"
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/NamedValue.hpp>
41 #include <com/sun/star/beans/PropertyAttribute.hpp>
42 #include <com/sun/star/container/XIdentifierReplace.hpp>
43 #include <com/sun/star/form/TabulatorCycle.hpp>
44 #include <com/sun/star/form/validation/XValidatableFormComponent.hpp>
45 #include <com/sun/star/form/XBoundComponent.hpp>
46 #include <com/sun/star/form/XBoundControl.hpp>
47 #include <com/sun/star/form/XGridControl.hpp>
48 #include <com/sun/star/form/XLoadable.hpp>
49 #include <com/sun/star/form/XReset.hpp>
50 #include <com/sun/star/form/control/FilterControl.hpp>
51 #include <com/sun/star/frame/XController.hpp>
52 #include <com/sun/star/sdb/ParametersRequest.hpp>
53 #include <com/sun/star/sdb/RowChangeAction.hpp>
54 #include <com/sun/star/sdb/XInteractionSupplyParameters.hpp>
55 #include <com/sun/star/sdbc/ColumnValue.hpp>
56 #include <com/sun/star/sdbc/DataType.hpp>
57 #include <com/sun/star/task/InteractionHandler.hpp>
58 #include <com/sun/star/util/XURLTransformer.hpp>
59 #include <com/sun/star/form/runtime/FormOperations.hpp>
60 #include <com/sun/star/form/runtime/FormFeature.hpp>
61 #include <com/sun/star/container/XContainer.hpp>
62 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
63 #include <com/sun/star/util/NumberFormatter.hpp>
64 #include <com/sun/star/sdb/SQLContext.hpp>
65 #include <com/sun/star/sdb/XColumn.hpp>
67 #include <comphelper/enumhelper.hxx>
68 #include <comphelper/interaction.hxx>
69 #include <comphelper/namedvaluecollection.hxx>
70 #include <comphelper/processfactory.hxx>
71 #include <comphelper/propagg.hxx>
72 #include <comphelper/property.hxx>
73 #include <comphelper/sequence.hxx>
74 #include <comphelper/flagguard.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/msgbox.hxx>
86 #include <vcl/svapp.hxx>
87 #include <vcl/settings.hxx>
88 #include <osl/mutex.hxx>
90 #include <algorithm>
92 #include <o3tl/compat_functional.hxx>
94 using namespace ::com::sun::star;
95 using namespace ::comphelper;
96 using namespace ::connectivity;
97 using namespace ::dbtools;
100 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL
101 FormController_NewInstance_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & _rxORB )
102 throw (css::uno::Exception)
104 return *( new ::svxform::FormController( comphelper::getComponentContext(_rxORB) ) );
107 namespace svxform
110 using ::com::sun::star::sdb::XColumn;
111 using ::com::sun::star::awt::XControl;
112 using ::com::sun::star::awt::XTabController;
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::XAggregation;
137 using ::com::sun::star::uno::Type;
138 using ::com::sun::star::lang::IllegalArgumentException;
139 using ::com::sun::star::sdbc::XConnection;
140 using ::com::sun::star::sdbc::XRowSet;
141 using ::com::sun::star::sdbc::XDatabaseMetaData;
142 using ::com::sun::star::util::XNumberFormatsSupplier;
143 using ::com::sun::star::util::NumberFormatter;
144 using ::com::sun::star::util::XNumberFormatter;
145 using ::com::sun::star::sdbcx::XColumnsSupplier;
146 using ::com::sun::star::container::XNameAccess;
147 using ::com::sun::star::lang::EventObject;
148 using ::com::sun::star::beans::Property;
149 using ::com::sun::star::container::XEnumeration;
150 using ::com::sun::star::form::XFormComponent;
151 using ::com::sun::star::form::runtime::XFormOperations;
152 using ::com::sun::star::form::runtime::FilterEvent;
153 using ::com::sun::star::form::runtime::XFilterControllerListener;
154 using ::com::sun::star::awt::XControlContainer;
155 using ::com::sun::star::container::XIdentifierReplace;
156 using ::com::sun::star::lang::WrappedTargetException;
157 using ::com::sun::star::form::XFormControllerListener;
158 using ::com::sun::star::awt::XWindow;
159 using ::com::sun::star::sdbc::XResultSet;
160 using ::com::sun::star::awt::XControlModel;
161 using ::com::sun::star::awt::XTabControllerModel;
162 using ::com::sun::star::beans::PropertyChangeEvent;
163 using ::com::sun::star::form::validation::XValidatableFormComponent;
164 using ::com::sun::star::form::XLoadable;
165 using ::com::sun::star::script::XEventAttacherManager;
166 using ::com::sun::star::form::XBoundControl;
167 using ::com::sun::star::beans::XPropertyChangeListener;
168 using ::com::sun::star::awt::TextEvent;
169 using ::com::sun::star::form::XBoundComponent;
170 using ::com::sun::star::awt::XCheckBox;
171 using ::com::sun::star::awt::XComboBox;
172 using ::com::sun::star::awt::XListBox;
173 using ::com::sun::star::awt::ItemEvent;
174 using ::com::sun::star::util::XModifyListener;
175 using ::com::sun::star::form::XReset;
176 using ::com::sun::star::frame::XDispatchProviderInterception;
177 using ::com::sun::star::form::XGridControl;
178 using ::com::sun::star::awt::XVclWindowPeer;
179 using ::com::sun::star::form::validation::XValidator;
180 using ::com::sun::star::awt::FocusEvent;
181 using ::com::sun::star::sdb::SQLContext;
182 using ::com::sun::star::container::XChild;
183 using ::com::sun::star::form::TabulatorCycle_RECORDS;
184 using ::com::sun::star::container::ContainerEvent;
185 using ::com::sun::star::lang::DisposedException;
186 using ::com::sun::star::lang::Locale;
187 using ::com::sun::star::beans::NamedValue;
188 using ::com::sun::star::lang::NoSupportException;
189 using ::com::sun::star::sdb::RowChangeEvent;
190 using ::com::sun::star::frame::XStatusListener;
191 using ::com::sun::star::frame::XDispatchProviderInterceptor;
192 using ::com::sun::star::sdb::SQLErrorEvent;
193 using ::com::sun::star::form::DatabaseParameterEvent;
194 using ::com::sun::star::sdb::ParametersRequest;
195 using ::com::sun::star::task::XInteractionRequest;
196 using ::com::sun::star::util::URL;
197 using ::com::sun::star::frame::FeatureStateEvent;
198 using ::com::sun::star::form::runtime::XFormControllerContext;
199 using ::com::sun::star::task::InteractionHandler;
200 using ::com::sun::star::task::XInteractionHandler;
201 using ::com::sun::star::form::runtime::FormOperations;
202 using ::com::sun::star::container::XContainer;
203 using ::com::sun::star::sdbc::SQLWarning;
205 namespace ColumnValue = ::com::sun::star::sdbc::ColumnValue;
206 namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
207 namespace FocusChangeReason = ::com::sun::star::awt::FocusChangeReason;
208 namespace RowChangeAction = ::com::sun::star::sdb::RowChangeAction;
209 namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
210 namespace DataType = ::com::sun::star::sdbc::DataType;
212 struct ColumnInfo
214 // information about the column itself
215 Reference< XColumn > xColumn;
216 sal_Int32 nNullable;
217 bool bAutoIncrement;
218 bool bReadOnly;
219 OUString sName;
221 // information about the control(s) bound to this column
223 /// the first control which is bound to the given column, and which requires input
224 Reference< XControl > xFirstControlWithInputRequired;
225 /** the first grid control which contains a column which is bound to the given database column, and requires
226 input
228 Reference< XGrid > xFirstGridWithInputRequiredColumn;
229 /** if xFirstControlWithInputRequired is a grid control, then nRequiredGridColumn specifies the position
230 of the grid column which is actually bound
232 sal_Int32 nRequiredGridColumn;
234 ColumnInfo()
235 :xColumn()
236 ,nNullable( ColumnValue::NULLABLE_UNKNOWN )
237 ,bAutoIncrement( false )
238 ,bReadOnly( false )
239 ,sName()
240 ,xFirstControlWithInputRequired()
241 ,xFirstGridWithInputRequiredColumn()
242 ,nRequiredGridColumn( -1 )
247 class ColumnInfoCache
249 public:
250 ColumnInfoCache( const Reference< XColumnsSupplier >& _rxColSupplier );
252 size_t getColumnCount() const { return m_aColumns.size(); }
253 const ColumnInfo& getColumnInfo( size_t _pos );
255 bool controlsInitialized() const { return m_bControlsInitialized; }
256 void initializeControls( const Sequence< Reference< XControl > >& _rControls );
257 void deinitializeControls();
259 private:
260 typedef ::std::vector< ColumnInfo > ColumnInfos;
261 ColumnInfos m_aColumns;
262 bool m_bControlsInitialized;
266 ColumnInfoCache::ColumnInfoCache( const Reference< XColumnsSupplier >& _rxColSupplier )
267 :m_aColumns()
268 ,m_bControlsInitialized( false )
272 m_aColumns.clear();
274 Reference< XIndexAccess > xColumns( _rxColSupplier->getColumns(), UNO_QUERY_THROW );
275 sal_Int32 nColumnCount = xColumns->getCount();
276 m_aColumns.reserve( nColumnCount );
278 Reference< XPropertySet > xColumnProps;
279 for ( sal_Int32 i = 0; i < nColumnCount; ++i )
281 ColumnInfo aColInfo;
282 aColInfo.xColumn.set( xColumns->getByIndex(i), UNO_QUERY_THROW );
284 xColumnProps.set( aColInfo.xColumn, UNO_QUERY_THROW );
285 OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_ISNULLABLE ) >>= aColInfo.nNullable );
286 OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_AUTOINCREMENT ) >>= aColInfo.bAutoIncrement );
287 OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_NAME ) >>= aColInfo.sName );
288 OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_ISREADONLY ) >>= aColInfo.bReadOnly );
290 m_aColumns.push_back( aColInfo );
293 catch( const Exception& )
295 DBG_UNHANDLED_EXCEPTION();
300 namespace
302 bool lcl_isBoundTo( const Reference< XPropertySet >& _rxControlModel, const Reference< XInterface >& _rxNormDBField )
304 Reference< XInterface > xNormBoundField( _rxControlModel->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY );
305 return ( xNormBoundField == _rxNormDBField );
308 bool lcl_isInputRequired( const Reference< XPropertySet >& _rxControlModel )
310 bool bInputRequired = true;
311 OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_INPUT_REQUIRED ) >>= bInputRequired );
312 return bInputRequired;
315 void lcl_resetColumnControlInfo( ColumnInfo& _rColInfo )
317 _rColInfo.xFirstControlWithInputRequired.clear();
318 _rColInfo.xFirstGridWithInputRequiredColumn.clear();
319 _rColInfo.nRequiredGridColumn = -1;
324 void ColumnInfoCache::deinitializeControls()
326 for ( ColumnInfos::iterator col = m_aColumns.begin();
327 col != m_aColumns.end();
328 ++col
331 lcl_resetColumnControlInfo( *col );
336 void ColumnInfoCache::initializeControls( const Sequence< Reference< XControl > >& _rControls )
340 // for every of our known columns, find the controls which are bound to this column
341 for ( ColumnInfos::iterator col = m_aColumns.begin();
342 col != m_aColumns.end();
343 ++col
346 OSL_ENSURE( !col->xFirstControlWithInputRequired.is() && !col->xFirstGridWithInputRequiredColumn.is()
347 && ( col->nRequiredGridColumn == -1 ), "ColumnInfoCache::initializeControls: called me twice?" );
349 lcl_resetColumnControlInfo( *col );
351 Reference< XInterface > xNormColumn( col->xColumn, UNO_QUERY_THROW );
353 const Reference< XControl >* pControl( _rControls.getConstArray() );
354 const Reference< XControl >* pControlEnd( pControl + _rControls.getLength() );
355 for ( ; pControl != pControlEnd; ++pControl )
357 if ( !pControl->is() )
358 continue;
360 Reference< XPropertySet > xModel( (*pControl)->getModel(), UNO_QUERY_THROW );
361 Reference< XPropertySetInfo > xModelPSI( xModel->getPropertySetInfo(), UNO_SET_THROW );
363 // special handling for grid controls
364 Reference< XGrid > xGrid( *pControl, UNO_QUERY );
365 if ( xGrid.is() )
367 Reference< XIndexAccess > xGridColAccess( xModel, UNO_QUERY_THROW );
368 sal_Int32 gridColCount = xGridColAccess->getCount();
369 sal_Int32 gridCol = 0;
370 for ( gridCol = 0; gridCol < gridColCount; ++gridCol )
372 Reference< XPropertySet > xGridColumnModel( xGridColAccess->getByIndex( gridCol ), UNO_QUERY_THROW );
374 if ( !lcl_isBoundTo( xGridColumnModel, xNormColumn )
375 || !lcl_isInputRequired( xGridColumnModel )
377 continue; // with next grid column
379 break;
382 if ( gridCol < gridColCount )
384 // found a grid column which is bound to the given
385 col->xFirstGridWithInputRequiredColumn = xGrid;
386 col->nRequiredGridColumn = gridCol;
387 break;
390 continue; // with next control
393 if ( !xModelPSI->hasPropertyByName( FM_PROP_BOUNDFIELD )
394 || !lcl_isBoundTo( xModel, xNormColumn )
395 || !lcl_isInputRequired( xModel )
397 continue; // with next control
399 break;
402 if ( pControl == pControlEnd )
403 // did not find a control which is bound to this particular column, and for which the input is required
404 continue; // with next DB column
406 col->xFirstControlWithInputRequired = *pControl;
409 catch( const Exception& )
411 DBG_UNHANDLED_EXCEPTION();
414 m_bControlsInitialized = true;
418 const ColumnInfo& ColumnInfoCache::getColumnInfo( size_t _pos )
420 if ( _pos >= m_aColumns.size() )
421 throw IndexOutOfBoundsException();
423 return m_aColumns[ _pos ];
426 class OParameterContinuation : public OInteraction< XInteractionSupplyParameters >
428 Sequence< PropertyValue > m_aValues;
430 public:
431 OParameterContinuation() { }
433 Sequence< PropertyValue > getValues() const { return m_aValues; }
435 // XInteractionSupplyParameters
436 virtual void SAL_CALL setParameters( const Sequence< PropertyValue >& _rValues ) throw(RuntimeException, std::exception) SAL_OVERRIDE;
440 void SAL_CALL OParameterContinuation::setParameters( const Sequence< PropertyValue >& _rValues ) throw(RuntimeException, std::exception)
442 m_aValues = _rValues;
446 // FmXAutoControl
448 struct FmFieldInfo
450 OUString aFieldName;
451 Reference< XPropertySet > xField;
452 Reference< XTextComponent > xText;
454 FmFieldInfo(const Reference< XPropertySet >& _xField, const Reference< XTextComponent >& _xText)
455 :xField(_xField)
456 ,xText(_xText)
457 {xField->getPropertyValue(FM_PROP_NAME) >>= aFieldName;}
460 class FmXAutoControl: public UnoControl
463 public:
464 FmXAutoControl() :UnoControl()
468 virtual OUString GetComponentServiceName() SAL_OVERRIDE {return OUString("Edit");}
469 virtual void SAL_CALL createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) throw( RuntimeException, std::exception ) SAL_OVERRIDE;
471 protected:
472 virtual void ImplSetPeerProperty( const OUString& rPropName, const Any& rVal ) SAL_OVERRIDE;
476 void FmXAutoControl::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) throw( RuntimeException, std::exception )
478 UnoControl::createPeer( rxToolkit, rParentPeer );
480 Reference< XTextComponent > xText(getPeer() , UNO_QUERY);
481 if (xText.is())
483 xText->setText(SVX_RESSTR(RID_STR_AUTOFIELD));
484 xText->setEditable(sal_False);
489 void FmXAutoControl::ImplSetPeerProperty( const OUString& rPropName, const Any& rVal )
491 // these properties are ignored
492 if (rPropName == FM_PROP_TEXT)
493 return;
495 UnoControl::ImplSetPeerProperty( rPropName, rVal );
499 IMPL_LINK_NOARG_TYPED( FormController, OnActivateTabOrder, Idle*, void )
501 activateTabOrder();
505 struct UpdateAllListeners : public ::std::unary_function< Reference< XDispatch >, bool >
507 bool operator()( const Reference< XDispatch >& _rxDispatcher ) const
509 static_cast< svx::OSingleFeatureDispatcher* >( _rxDispatcher.get() )->updateAllListeners();
510 // the return is a dummy only so we can use this struct in a o3tl::compose1 call
511 return true;
515 IMPL_LINK_NOARG_TYPED( FormController, OnInvalidateFeatures, Timer*, void )
517 ::osl::MutexGuard aGuard( m_aMutex );
518 for ( ::std::set< sal_Int16 >::const_iterator aLoop = m_aInvalidFeatures.begin();
519 aLoop != m_aInvalidFeatures.end();
520 ++aLoop
523 DispatcherContainer::const_iterator aDispatcherPos = m_aFeatureDispatchers.find( *aLoop );
524 if ( aDispatcherPos != m_aFeatureDispatchers.end() )
526 // TODO: for the real and actual listener notifications, we should release
527 // our mutex
528 UpdateAllListeners( )( aDispatcherPos->second );
533 FormController::FormController(const Reference< css::uno::XComponentContext > & _rxORB )
534 :FormController_BASE( m_aMutex )
535 ,OPropertySetHelper( FormController_BASE::rBHelper )
536 ,OSQLParserClient( _rxORB )
537 ,m_xComponentContext( _rxORB )
538 ,m_aActivateListeners(m_aMutex)
539 ,m_aModifyListeners(m_aMutex)
540 ,m_aErrorListeners(m_aMutex)
541 ,m_aDeleteListeners(m_aMutex)
542 ,m_aRowSetApproveListeners(m_aMutex)
543 ,m_aParameterListeners(m_aMutex)
544 ,m_aFilterListeners(m_aMutex)
545 ,m_pControlBorderManager( new ::svxform::ControlBorderManager )
546 ,m_xFormOperations()
547 ,m_aMode( OUString( "DataMode" ) )
548 ,m_aLoadEvent( LINK( this, FormController, OnLoad ) )
549 ,m_aToggleEvent( LINK( this, FormController, OnToggleAutoFields ) )
550 ,m_aActivationEvent( LINK( this, FormController, OnActivated ) )
551 ,m_aDeactivationEvent( LINK( this, FormController, OnDeactivated ) )
552 ,m_nCurrentFilterPosition(-1)
553 ,m_bCurrentRecordModified(false)
554 ,m_bCurrentRecordNew(false)
555 ,m_bLocked(false)
556 ,m_bDBConnection(false)
557 ,m_bCycle(false)
558 ,m_bCanInsert(false)
559 ,m_bCanUpdate(false)
560 ,m_bCommitLock(false)
561 ,m_bModified(false)
562 ,m_bControlsSorted(false)
563 ,m_bFiltering(false)
564 ,m_bAttachEvents(true)
565 ,m_bDetachEvents(true)
566 ,m_bAttemptedHandlerCreation( false )
567 ,m_bSuspendFilterTextListening( false )
570 osl_atomic_increment(&m_refCount);
572 m_xTabController = TabController::create( m_xComponentContext );
573 m_xAggregate = Reference< XAggregation >( m_xTabController, UNO_QUERY_THROW );
574 m_xAggregate->setDelegator( *this );
576 osl_atomic_decrement(&m_refCount);
578 m_aTabActivationIdle.SetPriority( SchedulerPriority::LOWEST );
579 m_aTabActivationIdle.SetIdleHdl( LINK( this, FormController, OnActivateTabOrder ) );
581 m_aFeatureInvalidationTimer.SetTimeout( 200 );
582 m_aFeatureInvalidationTimer.SetTimeoutHdl( LINK( this, FormController, OnInvalidateFeatures ) );
586 FormController::~FormController()
589 ::osl::MutexGuard aGuard( m_aMutex );
591 m_aLoadEvent.CancelPendingCall();
592 m_aToggleEvent.CancelPendingCall();
593 m_aActivationEvent.CancelPendingCall();
594 m_aDeactivationEvent.CancelPendingCall();
596 if ( m_aTabActivationIdle.IsActive() )
597 m_aTabActivationIdle.Stop();
600 if ( m_aFeatureInvalidationTimer.IsActive() )
601 m_aFeatureInvalidationTimer.Stop();
603 disposeAllFeaturesAndDispatchers();
605 if ( m_xFormOperations.is() )
606 m_xFormOperations->dispose();
607 m_xFormOperations.clear();
609 // Freigeben der Aggregation
610 if ( m_xAggregate.is() )
612 m_xAggregate->setDelegator( NULL );
613 m_xAggregate.clear();
616 DELETEZ( m_pControlBorderManager );
621 void SAL_CALL FormController::acquire() throw ()
623 FormController_BASE::acquire();
627 void SAL_CALL FormController::release() throw ()
629 FormController_BASE::release();
633 Any SAL_CALL FormController::queryInterface( const Type& _rType ) throw(RuntimeException, std::exception)
635 Any aRet = FormController_BASE::queryInterface( _rType );
636 if ( !aRet.hasValue() )
637 aRet = OPropertySetHelper::queryInterface( _rType );
638 if ( !aRet.hasValue() )
639 aRet = m_xAggregate->queryAggregation( _rType );
640 return aRet;
644 Sequence< sal_Int8 > SAL_CALL FormController::getImplementationId() throw( RuntimeException, std::exception )
646 return css::uno::Sequence<sal_Int8>();
649 Sequence< Type > SAL_CALL FormController::getTypes( ) throw(RuntimeException, std::exception)
651 return comphelper::concatSequences(
652 FormController_BASE::getTypes(),
653 ::cppu::OPropertySetHelper::getTypes()
657 // XServiceInfo
658 sal_Bool SAL_CALL FormController::supportsService(const OUString& ServiceName) throw( RuntimeException, std::exception )
660 return cppu::supportsService(this, ServiceName);
663 OUString SAL_CALL FormController::getImplementationName() throw( RuntimeException, std::exception )
665 return OUString("org.openoffice.comp.svx.FormController");
668 Sequence< OUString> SAL_CALL FormController::getSupportedServiceNames() throw( RuntimeException, std::exception )
670 // service names which are supported only, but cannot be used to created an
671 // instance at a service factory
672 Sequence< OUString > aNonCreatableServiceNames( 1 );
673 aNonCreatableServiceNames[ 0 ] = "com.sun.star.form.FormControllerDispatcher";
675 // services which can be used to created an instance at a service factory
676 Sequence< OUString > aCreatableServiceNames( getSupportedServiceNames_Static() );
677 return ::comphelper::concatSequences( aCreatableServiceNames, aNonCreatableServiceNames );
681 sal_Bool SAL_CALL FormController::approveReset(const EventObject& /*rEvent*/) throw( RuntimeException, std::exception )
683 return sal_True;
687 void SAL_CALL FormController::resetted(const EventObject& rEvent) throw( RuntimeException, std::exception )
689 ::osl::MutexGuard aGuard(m_aMutex);
690 if (getCurrentControl().is() && (getCurrentControl()->getModel() == rEvent.Source))
691 m_bModified = false;
695 Sequence< OUString> FormController::getSupportedServiceNames_Static()
697 static Sequence< OUString> aServices;
698 if (!aServices.getLength())
700 aServices.realloc(2);
701 aServices.getArray()[0] = "com.sun.star.form.runtime.FormController";
702 aServices.getArray()[1] = "com.sun.star.awt.control.TabController";
704 return aServices;
708 namespace
710 struct ResetComponentText : public ::std::unary_function< Reference< XTextComponent >, void >
712 void operator()( const Reference< XTextComponent >& _rxText )
714 _rxText->setText( OUString() );
718 struct RemoveComponentTextListener : public ::std::unary_function< Reference< XTextComponent >, void >
720 RemoveComponentTextListener( const Reference< XTextListener >& _rxListener )
721 :m_xListener( _rxListener )
725 void operator()( const Reference< XTextComponent >& _rxText )
727 _rxText->removeTextListener( m_xListener );
730 private:
731 Reference< XTextListener > m_xListener;
736 void FormController::impl_setTextOnAllFilter_throw()
738 m_bSuspendFilterTextListening = true;
739 ::comphelper::FlagGuard aResetFlag( m_bSuspendFilterTextListening );
741 // reset the text for all controls
742 ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), ResetComponentText() );
744 if ( m_aFilterRows.empty() )
745 // nothing to do anymore
746 return;
748 if ( m_nCurrentFilterPosition < 0 )
749 return;
751 // set the text for all filters
752 OSL_ENSURE( m_aFilterRows.size() > (size_t)m_nCurrentFilterPosition,
753 "FormController::impl_setTextOnAllFilter_throw: m_nCurrentFilterPosition too big" );
755 if ( (size_t)m_nCurrentFilterPosition < m_aFilterRows.size() )
757 FmFilterRow& rRow = m_aFilterRows[ m_nCurrentFilterPosition ];
758 for ( FmFilterRow::const_iterator iter2 = rRow.begin();
759 iter2 != rRow.end();
760 ++iter2
763 iter2->first->setText( iter2->second );
767 // OPropertySetHelper
769 sal_Bool FormController::convertFastPropertyValue( Any & /*rConvertedValue*/, Any & /*rOldValue*/,
770 sal_Int32 /*nHandle*/, const Any& /*rValue*/ )
771 throw( IllegalArgumentException )
773 return sal_False;
777 void FormController::setFastPropertyValue_NoBroadcast( sal_Int32 /*nHandle*/, const Any& /*rValue*/ )
778 throw( Exception, std::exception )
783 void FormController::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
785 switch (nHandle)
787 case FM_ATTR_FILTER:
789 OUStringBuffer aFilter;
790 Reference<XConnection> xConnection(getConnection(Reference< XRowSet>(m_xModelAsIndex, UNO_QUERY)));
791 if (xConnection.is())
793 Reference< XDatabaseMetaData> xMetaData(xConnection->getMetaData());
794 Reference< XNumberFormatsSupplier> xFormatSupplier( getNumberFormats( xConnection, true ) );
795 Reference< XNumberFormatter> xFormatter = NumberFormatter::create(m_xComponentContext);
796 xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
798 Reference< XColumnsSupplier> xSupplyCols(m_xModelAsIndex, UNO_QUERY);
799 Reference< XNameAccess> xFields(xSupplyCols->getColumns(), UNO_QUERY);
801 // now add the filter rows
804 for ( FmFilterRows::const_iterator row = m_aFilterRows.begin(); row != m_aFilterRows.end(); ++row )
806 const FmFilterRow& rRow = *row;
808 if ( rRow.empty() )
809 continue;
811 OUStringBuffer aRowFilter;
812 for ( FmFilterRow::const_iterator condition = rRow.begin(); condition != rRow.end(); ++condition )
814 // get the field of the controls map
815 Reference< XControl > xControl( condition->first, UNO_QUERY_THROW );
816 Reference< XPropertySet > xModelProps( xControl->getModel(), UNO_QUERY_THROW );
817 Reference< XPropertySet > xField( xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY_THROW );
819 OUString sFilterValue( condition->second );
821 OUString sErrorMsg, sCriteria;
822 const std::shared_ptr< OSQLParseNode > pParseNode =
823 predicateTree( sErrorMsg, sFilterValue, xFormatter, xField );
824 OSL_ENSURE( pParseNode != nullptr, "FormController::getFastPropertyValue: could not parse the field value predicate!" );
825 if ( pParseNode != nullptr )
827 // don't use a parse context here, we need it unlocalized
828 pParseNode->parseNodeToStr( sCriteria, xConnection, NULL );
829 if ( condition != rRow.begin() )
830 aRowFilter.appendAscii( " AND " );
831 aRowFilter.append( sCriteria );
834 if ( !aRowFilter.isEmpty() )
836 if ( !aFilter.isEmpty() )
837 aFilter.appendAscii( " OR " );
839 aFilter.appendAscii( "( " );
840 aFilter.append( aRowFilter.makeStringAndClear() );
841 aFilter.appendAscii( " )" );
845 catch( const Exception& )
847 DBG_UNHANDLED_EXCEPTION();
848 aFilter.setLength(0);
851 rValue <<= aFilter.makeStringAndClear();
853 break;
855 case FM_ATTR_FORM_OPERATIONS:
856 rValue <<= m_xFormOperations;
857 break;
862 Reference< XPropertySetInfo > FormController::getPropertySetInfo() throw( RuntimeException, std::exception )
864 static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
865 return xInfo;
869 void FormController::fillProperties(
870 Sequence< Property >& /* [out] */ _rProps,
871 Sequence< Property >& /* [out] */ /*_rAggregateProps*/
872 ) const
874 _rProps.realloc(2);
875 sal_Int32 nPos = 0;
876 Property* pDesc = _rProps.getArray();
878 pDesc[nPos++] = Property(FM_PROP_FILTER, FM_ATTR_FILTER,
879 cppu::UnoType<OUString>::get(),
880 PropertyAttribute::READONLY);
881 pDesc[nPos++] = Property(FM_PROP_FORM_OPERATIONS, FM_ATTR_FORM_OPERATIONS,
882 cppu::UnoType<XFormOperations>::get(),
883 PropertyAttribute::READONLY);
887 ::cppu::IPropertyArrayHelper& FormController::getInfoHelper()
889 return *getArrayHelper();
892 // XFilterController
894 void SAL_CALL FormController::addFilterControllerListener( const Reference< XFilterControllerListener >& _Listener ) throw( RuntimeException, std::exception )
896 m_aFilterListeners.addInterface( _Listener );
900 void SAL_CALL FormController::removeFilterControllerListener( const Reference< XFilterControllerListener >& _Listener ) throw( RuntimeException, std::exception )
902 m_aFilterListeners.removeInterface( _Listener );
906 ::sal_Int32 SAL_CALL FormController::getFilterComponents() throw( ::com::sun::star::uno::RuntimeException, std::exception )
908 ::osl::MutexGuard aGuard( m_aMutex );
909 impl_checkDisposed_throw();
911 return m_aFilterComponents.size();
915 ::sal_Int32 SAL_CALL FormController::getDisjunctiveTerms() throw( ::com::sun::star::uno::RuntimeException, std::exception )
917 ::osl::MutexGuard aGuard( m_aMutex );
918 impl_checkDisposed_throw();
920 return m_aFilterRows.size();
924 void SAL_CALL FormController::setPredicateExpression( ::sal_Int32 _Component, ::sal_Int32 _Term, const OUString& _PredicateExpression ) throw( RuntimeException, IndexOutOfBoundsException, std::exception )
926 ::osl::MutexGuard aGuard( m_aMutex );
927 impl_checkDisposed_throw();
929 if ( ( _Component < 0 ) || ( _Component >= getFilterComponents() ) || ( _Term < 0 ) || ( _Term >= getDisjunctiveTerms() ) )
930 throw IndexOutOfBoundsException( OUString(), *this );
932 Reference< XTextComponent > xText( m_aFilterComponents[ _Component ] );
933 xText->setText( _PredicateExpression );
935 FmFilterRow& rFilterRow = m_aFilterRows[ _Term ];
936 if ( !_PredicateExpression.isEmpty() )
937 rFilterRow[ xText ] = _PredicateExpression;
938 else
939 rFilterRow.erase( xText );
943 Reference< XControl > FormController::getFilterComponent( ::sal_Int32 _Component ) throw( RuntimeException, IndexOutOfBoundsException, std::exception )
945 ::osl::MutexGuard aGuard( m_aMutex );
946 impl_checkDisposed_throw();
948 if ( ( _Component < 0 ) || ( _Component >= getFilterComponents() ) )
949 throw IndexOutOfBoundsException( OUString(), *this );
951 return Reference< XControl >( m_aFilterComponents[ _Component ], UNO_QUERY );
955 Sequence< Sequence< OUString > > FormController::getPredicateExpressions() throw( RuntimeException, std::exception )
957 ::osl::MutexGuard aGuard( m_aMutex );
958 impl_checkDisposed_throw();
960 Sequence< Sequence< OUString > > aExpressions( m_aFilterRows.size() );
961 sal_Int32 termIndex = 0;
962 for ( FmFilterRows::const_iterator row = m_aFilterRows.begin();
963 row != m_aFilterRows.end();
964 ++row, ++termIndex
967 const FmFilterRow& rRow( *row );
969 Sequence< OUString > aConjunction( m_aFilterComponents.size() );
970 sal_Int32 componentIndex = 0;
971 for ( FilterComponents::const_iterator comp = m_aFilterComponents.begin();
972 comp != m_aFilterComponents.end();
973 ++comp, ++componentIndex
976 FmFilterRow::const_iterator predicate = rRow.find( *comp );
977 if ( predicate != rRow.end() )
978 aConjunction[ componentIndex ] = predicate->second;
981 aExpressions[ termIndex ] = aConjunction;
984 return aExpressions;
988 void SAL_CALL FormController::removeDisjunctiveTerm( ::sal_Int32 _Term ) throw (IndexOutOfBoundsException, RuntimeException, std::exception)
990 // SYNCHRONIZED -->
991 ::osl::ClearableMutexGuard aGuard( m_aMutex );
992 impl_checkDisposed_throw();
994 if ( ( _Term < 0 ) || ( _Term >= getDisjunctiveTerms() ) )
995 throw IndexOutOfBoundsException( OUString(), *this );
997 // if the to-be-deleted row is our current row, we need to shift
998 if ( _Term == m_nCurrentFilterPosition )
1000 if ( m_nCurrentFilterPosition < sal_Int32( m_aFilterRows.size() - 1 ) )
1001 ++m_nCurrentFilterPosition;
1002 else
1003 --m_nCurrentFilterPosition;
1006 FmFilterRows::iterator pos = m_aFilterRows.begin() + _Term;
1007 m_aFilterRows.erase( pos );
1009 // adjust m_nCurrentFilterPosition if the removed row preceded it
1010 if ( _Term < m_nCurrentFilterPosition )
1011 --m_nCurrentFilterPosition;
1013 SAL_WARN_IF( !( ( m_nCurrentFilterPosition < 0 ) != ( m_aFilterRows.empty() ) ),
1014 "svx.form", "FormController::removeDisjunctiveTerm: inconsistency!" );
1016 // update the texts in the filter controls
1017 impl_setTextOnAllFilter_throw();
1019 FilterEvent aEvent;
1020 aEvent.Source = *this;
1021 aEvent.DisjunctiveTerm = _Term;
1022 aGuard.clear();
1023 // <-- SYNCHRONIZED
1025 m_aFilterListeners.notifyEach( &XFilterControllerListener::disjunctiveTermRemoved, aEvent );
1029 void SAL_CALL FormController::appendEmptyDisjunctiveTerm() throw (RuntimeException, std::exception)
1031 // SYNCHRONIZED -->
1032 ::osl::ClearableMutexGuard aGuard( m_aMutex );
1033 impl_checkDisposed_throw();
1035 impl_appendEmptyFilterRow( aGuard );
1036 // <-- SYNCHRONIZED
1040 ::sal_Int32 SAL_CALL FormController::getActiveTerm() throw (RuntimeException, std::exception)
1042 ::osl::MutexGuard aGuard( m_aMutex );
1043 impl_checkDisposed_throw();
1045 return m_nCurrentFilterPosition;
1049 void SAL_CALL FormController::setActiveTerm( ::sal_Int32 _ActiveTerm ) throw (IndexOutOfBoundsException, RuntimeException, std::exception)
1051 ::osl::MutexGuard aGuard( m_aMutex );
1052 impl_checkDisposed_throw();
1054 if ( ( _ActiveTerm < 0 ) || ( _ActiveTerm >= getDisjunctiveTerms() ) )
1055 throw IndexOutOfBoundsException( OUString(), *this );
1057 if ( _ActiveTerm == getActiveTerm() )
1058 return;
1060 m_nCurrentFilterPosition = _ActiveTerm;
1061 impl_setTextOnAllFilter_throw();
1064 // XElementAccess
1066 sal_Bool SAL_CALL FormController::hasElements() throw( RuntimeException, std::exception )
1068 ::osl::MutexGuard aGuard( m_aMutex );
1069 return !m_aChildren.empty();
1073 Type SAL_CALL FormController::getElementType() throw( RuntimeException, std::exception )
1075 return cppu::UnoType<XFormController>::get();
1079 // XEnumerationAccess
1081 Reference< XEnumeration > SAL_CALL FormController::createEnumeration() throw( RuntimeException, std::exception )
1083 ::osl::MutexGuard aGuard( m_aMutex );
1084 return new ::comphelper::OEnumerationByIndex(this);
1087 // XIndexAccess
1089 sal_Int32 SAL_CALL FormController::getCount() throw( RuntimeException, std::exception )
1091 ::osl::MutexGuard aGuard( m_aMutex );
1092 return m_aChildren.size();
1096 Any SAL_CALL FormController::getByIndex(sal_Int32 Index) throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException, std::exception )
1098 ::osl::MutexGuard aGuard( m_aMutex );
1099 if (Index < 0 ||
1100 Index >= (sal_Int32)m_aChildren.size())
1101 throw IndexOutOfBoundsException();
1103 return makeAny( m_aChildren[ Index ] );
1106 // EventListener
1108 void SAL_CALL FormController::disposing(const EventObject& e) throw( RuntimeException, std::exception )
1110 // Ist der Container disposed worden
1111 ::osl::MutexGuard aGuard( m_aMutex );
1112 Reference< XControlContainer > xContainer(e.Source, UNO_QUERY);
1113 if (xContainer.is())
1115 setContainer(Reference< XControlContainer > ());
1117 else
1119 // ist ein Control disposed worden
1120 Reference< XControl > xControl(e.Source, UNO_QUERY);
1121 if (xControl.is())
1123 if (getContainer().is())
1124 removeControl(xControl);
1129 // OComponentHelper
1131 void FormController::disposeAllFeaturesAndDispatchers()
1133 for ( DispatcherContainer::iterator aDispatcher = m_aFeatureDispatchers.begin();
1134 aDispatcher != m_aFeatureDispatchers.end();
1135 ++aDispatcher
1140 ::comphelper::disposeComponent( aDispatcher->second );
1142 catch( const Exception& )
1144 DBG_UNHANDLED_EXCEPTION();
1147 m_aFeatureDispatchers.clear();
1151 void FormController::disposing()
1153 EventObject aEvt( *this );
1155 // if we're still active, simulate a "deactivated" event
1156 if ( m_xActiveControl.is() )
1157 m_aActivateListeners.notifyEach( &XFormControllerListener::formDeactivated, aEvt );
1159 // notify all our listeners
1160 m_aActivateListeners.disposeAndClear(aEvt);
1161 m_aModifyListeners.disposeAndClear(aEvt);
1162 m_aErrorListeners.disposeAndClear(aEvt);
1163 m_aDeleteListeners.disposeAndClear(aEvt);
1164 m_aRowSetApproveListeners.disposeAndClear(aEvt);
1165 m_aParameterListeners.disposeAndClear(aEvt);
1166 m_aFilterListeners.disposeAndClear(aEvt);
1168 removeBoundFieldListener();
1169 stopFiltering();
1171 m_pControlBorderManager->restoreAll();
1173 m_aFilterRows.clear();
1175 ::osl::MutexGuard aGuard( m_aMutex );
1176 m_xActiveControl = NULL;
1177 implSetCurrentControl( NULL );
1179 // clean up our children
1180 for (FmFormControllers::const_iterator i = m_aChildren.begin();
1181 i != m_aChildren.end(); ++i)
1183 // search the position of the model within the form
1184 Reference< XFormComponent > xForm((*i)->getModel(), UNO_QUERY);
1185 sal_uInt32 nPos = m_xModelAsIndex->getCount();
1186 Reference< XFormComponent > xTemp;
1187 for( ; nPos; )
1190 m_xModelAsIndex->getByIndex( --nPos ) >>= xTemp;
1191 if ( xForm.get() == xTemp.get() )
1193 Reference< XInterface > xIfc( *i, UNO_QUERY );
1194 m_xModelAsManager->detach( nPos, xIfc );
1195 break;
1199 Reference< XComponent > (*i, UNO_QUERY)->dispose();
1201 m_aChildren.clear();
1203 disposeAllFeaturesAndDispatchers();
1205 if ( m_xFormOperations.is() )
1206 m_xFormOperations->dispose();
1207 m_xFormOperations.clear();
1209 if (m_bDBConnection)
1210 unload();
1212 setContainer( NULL );
1213 setModel( NULL );
1214 setParent( NULL );
1216 ::comphelper::disposeComponent( m_xComposer );
1218 m_bDBConnection = false;
1222 namespace
1224 static bool lcl_shouldUseDynamicControlBorder( const Reference< XInterface >& _rxForm, const Any& _rDynamicColorProp )
1226 bool bDoUse = false;
1227 if ( !( _rDynamicColorProp >>= bDoUse ) )
1229 DocumentType eDocType = DocumentClassification::classifyHostDocument( _rxForm );
1230 return ControlLayouter::useDynamicBorderColor( eDocType );
1232 return bDoUse;
1237 void SAL_CALL FormController::propertyChange(const PropertyChangeEvent& evt) throw( RuntimeException, std::exception )
1239 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1240 if ( evt.PropertyName == FM_PROP_BOUNDFIELD )
1242 Reference<XPropertySet> xOldBound;
1243 evt.OldValue >>= xOldBound;
1244 if ( !xOldBound.is() && evt.NewValue.hasValue() )
1246 Reference< XControlModel > xControlModel(evt.Source,UNO_QUERY);
1247 Reference< XControl > xControl = findControl(m_aControls,xControlModel,false,false);
1248 if ( xControl.is() )
1250 startControlModifyListening( xControl );
1251 Reference<XPropertySet> xProp(xControlModel,UNO_QUERY);
1252 if ( xProp.is() )
1253 xProp->removePropertyChangeListener(FM_PROP_BOUNDFIELD, this);
1257 else
1259 bool bModifiedChanged = (evt.PropertyName == FM_PROP_ISMODIFIED);
1260 bool bNewChanged = (evt.PropertyName == FM_PROP_ISNEW);
1261 if (bModifiedChanged || bNewChanged)
1263 ::osl::MutexGuard aGuard( m_aMutex );
1264 if (bModifiedChanged)
1265 m_bCurrentRecordModified = ::comphelper::getBOOL(evt.NewValue);
1266 else
1267 m_bCurrentRecordNew = ::comphelper::getBOOL(evt.NewValue);
1269 // toggle the locking
1270 if (m_bLocked != determineLockState())
1272 m_bLocked = !m_bLocked;
1273 setLocks();
1274 if (isListeningForChanges())
1275 startListening();
1276 else
1277 stopListening();
1280 if ( bNewChanged )
1281 m_aToggleEvent.Call();
1283 if (!m_bCurrentRecordModified)
1284 m_bModified = false;
1286 else if ( evt.PropertyName == FM_PROP_DYNAMIC_CONTROL_BORDER )
1288 bool bEnable = lcl_shouldUseDynamicControlBorder( evt.Source, evt.NewValue );
1289 if ( bEnable )
1291 m_pControlBorderManager->enableDynamicBorderColor();
1292 if ( m_xActiveControl.is() )
1293 m_pControlBorderManager->focusGained( m_xActiveControl.get() );
1295 else
1297 m_pControlBorderManager->disableDynamicBorderColor();
1304 bool FormController::replaceControl( const Reference< XControl >& _rxExistentControl, const Reference< XControl >& _rxNewControl )
1306 bool bSuccess = false;
1309 Reference< XIdentifierReplace > xContainer( getContainer(), UNO_QUERY );
1310 DBG_ASSERT( xContainer.is(), "FormController::replaceControl: yes, it's not required by the service description, but XItentifierReplaces would be nice!" );
1311 if ( xContainer.is() )
1313 // look up the ID of _rxExistentControl
1314 Sequence< sal_Int32 > aIdentifiers( xContainer->getIdentifiers() );
1315 const sal_Int32* pIdentifiers = aIdentifiers.getConstArray();
1316 const sal_Int32* pIdentifiersEnd = aIdentifiers.getConstArray() + aIdentifiers.getLength();
1317 for ( ; pIdentifiers != pIdentifiersEnd; ++pIdentifiers )
1319 Reference< XControl > xCheck( xContainer->getByIdentifier( *pIdentifiers ), UNO_QUERY );
1320 if ( xCheck == _rxExistentControl )
1321 break;
1323 DBG_ASSERT( pIdentifiers != pIdentifiersEnd, "FormController::replaceControl: did not find the control in the container!" );
1324 if ( pIdentifiers != pIdentifiersEnd )
1326 bool bReplacedWasActive = ( m_xActiveControl.get() == _rxExistentControl.get() );
1327 bool bReplacedWasCurrent = ( m_xCurrentControl.get() == _rxExistentControl.get() );
1329 if ( bReplacedWasActive )
1331 m_xActiveControl = NULL;
1332 implSetCurrentControl( NULL );
1334 else if ( bReplacedWasCurrent )
1336 implSetCurrentControl( _rxNewControl );
1339 // carry over the model
1340 _rxNewControl->setModel( _rxExistentControl->getModel() );
1342 xContainer->replaceByIdentifer( *pIdentifiers, makeAny( _rxNewControl ) );
1343 bSuccess = true;
1345 if ( bReplacedWasActive )
1347 Reference< XWindow > xControlWindow( _rxNewControl, UNO_QUERY );
1348 if ( xControlWindow.is() )
1349 xControlWindow->setFocus();
1354 catch( const Exception& )
1356 DBG_UNHANDLED_EXCEPTION();
1359 Reference< XControl > xDisposeIt( bSuccess ? _rxExistentControl : _rxNewControl );
1360 ::comphelper::disposeComponent( xDisposeIt );
1361 return bSuccess;
1365 void FormController::toggleAutoFields(bool bAutoFields)
1367 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1370 Sequence< Reference< XControl > > aControlsCopy( m_aControls );
1371 const Reference< XControl >* pControls = aControlsCopy.getConstArray();
1372 sal_Int32 nControls = aControlsCopy.getLength();
1374 if (bAutoFields)
1376 // as we don't want new controls to be attached to the scripting environment
1377 // we change attach flags
1378 m_bAttachEvents = false;
1379 for (sal_Int32 i = nControls; i > 0;)
1381 Reference< XControl > xControl = pControls[--i];
1382 if (xControl.is())
1384 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
1385 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
1387 // does the model use a bound field ?
1388 Reference< XPropertySet > xField;
1389 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
1391 // is it a autofield?
1392 if ( xField.is()
1393 && ::comphelper::hasProperty( FM_PROP_AUTOINCREMENT, xField )
1394 && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_AUTOINCREMENT ) )
1397 replaceControl( xControl, new FmXAutoControl() );
1402 m_bAttachEvents = true;
1404 else
1406 m_bDetachEvents = false;
1407 for (sal_Int32 i = nControls; i > 0;)
1409 Reference< XControl > xControl = pControls[--i];
1410 if (xControl.is())
1412 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
1413 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
1415 // does the model use a bound field ?
1416 Reference< XPropertySet > xField;
1417 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
1419 // is it a autofield?
1420 if ( xField.is()
1421 && ::comphelper::hasProperty( FM_PROP_AUTOINCREMENT, xField )
1422 && ::comphelper::getBOOL( xField->getPropertyValue(FM_PROP_AUTOINCREMENT ) )
1425 OUString sServiceName;
1426 OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DEFAULTCONTROL ) >>= sServiceName );
1427 Reference< XControl > xNewControl( m_xComponentContext->getServiceManager()->createInstanceWithContext( sServiceName, m_xComponentContext ), UNO_QUERY );
1428 replaceControl( xControl, xNewControl );
1433 m_bDetachEvents = true;
1438 IMPL_LINK_NOARG(FormController, OnToggleAutoFields)
1440 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1442 toggleAutoFields(m_bCurrentRecordNew);
1443 return 1L;
1446 // XTextListener
1448 void SAL_CALL FormController::textChanged(const TextEvent& e) throw( RuntimeException, std::exception )
1450 // SYNCHRONIZED -->
1451 ::osl::ClearableMutexGuard aGuard( m_aMutex );
1452 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1453 if ( !m_bFiltering )
1455 impl_onModify();
1456 return;
1459 if ( m_bSuspendFilterTextListening )
1460 return;
1462 Reference< XTextComponent > xText(e.Source,UNO_QUERY);
1463 OUString aText = xText->getText();
1465 if ( m_aFilterRows.empty() )
1466 appendEmptyDisjunctiveTerm();
1468 // Suchen der aktuellen Row
1469 if ( ( (size_t)m_nCurrentFilterPosition >= m_aFilterRows.size() ) || ( m_nCurrentFilterPosition < 0 ) )
1471 OSL_ENSURE( false, "FormController::textChanged: m_nCurrentFilterPosition is wrong!" );
1472 return;
1475 FmFilterRow& rRow = m_aFilterRows[ m_nCurrentFilterPosition ];
1477 // do we have a new filter
1478 if (!aText.isEmpty())
1479 rRow[xText] = aText;
1480 else
1482 // do we have the control in the row
1483 FmFilterRow::iterator iter = rRow.find(xText);
1484 // erase the entry out of the row
1485 if (iter != rRow.end())
1486 rRow.erase(iter);
1489 // multiplex the event to our FilterControllerListeners
1490 FilterEvent aEvent;
1491 aEvent.Source = *this;
1492 aEvent.FilterComponent = ::std::find( m_aFilterComponents.begin(), m_aFilterComponents.end(), xText ) - m_aFilterComponents.begin();
1493 aEvent.DisjunctiveTerm = getActiveTerm();
1494 aEvent.PredicateExpression = aText;
1496 aGuard.clear();
1497 // <-- SYNCHRONIZED
1499 // notify the changed filter expression
1500 m_aFilterListeners.notifyEach( &XFilterControllerListener::predicateExpressionChanged, aEvent );
1503 // XItemListener
1505 void SAL_CALL FormController::itemStateChanged(const ItemEvent& /*rEvent*/) throw( RuntimeException, std::exception )
1507 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1508 impl_onModify();
1511 // XModificationBroadcaster
1513 void SAL_CALL FormController::addModifyListener(const Reference< XModifyListener > & l) throw( RuntimeException, std::exception )
1515 ::osl::MutexGuard aGuard( m_aMutex );
1516 impl_checkDisposed_throw();
1517 m_aModifyListeners.addInterface( l );
1521 void FormController::removeModifyListener(const Reference< XModifyListener > & l) throw( RuntimeException, std::exception )
1523 ::osl::MutexGuard aGuard( m_aMutex );
1524 impl_checkDisposed_throw();
1525 m_aModifyListeners.removeInterface( l );
1528 // XModificationListener
1530 void FormController::modified( const EventObject& _rEvent ) throw( RuntimeException, std::exception )
1532 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1536 if ( _rEvent.Source != m_xActiveControl )
1537 { // let this control grab the focus
1538 // (this case may happen if somebody moves the scroll wheel of the mouse over a control
1539 // which does not have the focus)
1540 // 85511 - 29.05.2001 - frank.schoenheit@germany.sun.com
1542 // also, it happens when an image control gets a new image by double-clicking it
1543 // #i88458# / 2009-01-12 / frank.schoenheit@sun.com
1544 Reference< XWindow > xControlWindow( _rEvent.Source, UNO_QUERY_THROW );
1545 xControlWindow->setFocus();
1548 catch( const Exception& )
1550 DBG_UNHANDLED_EXCEPTION();
1553 impl_onModify();
1557 void FormController::impl_checkDisposed_throw() const
1559 if ( impl_isDisposed_nofail() )
1560 throw DisposedException( OUString(), *const_cast< FormController* >( this ) );
1564 void FormController::impl_onModify()
1566 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1569 ::osl::MutexGuard aGuard( m_aMutex );
1570 if ( !m_bModified )
1571 m_bModified = true;
1574 EventObject aEvt(static_cast<cppu::OWeakObject*>(this));
1575 m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvt );
1579 void FormController::impl_addFilterRow( const FmFilterRow& _row )
1581 m_aFilterRows.push_back( _row );
1583 if ( m_aFilterRows.size() == 1 )
1584 { // that's the first row ever
1585 OSL_ENSURE( m_nCurrentFilterPosition == -1, "FormController::impl_addFilterRow: inconsistency!" );
1586 m_nCurrentFilterPosition = 0;
1591 void FormController::impl_appendEmptyFilterRow( ::osl::ClearableMutexGuard& _rClearBeforeNotify )
1593 // SYNCHRONIZED -->
1594 impl_addFilterRow( FmFilterRow() );
1596 // notify the listeners
1597 FilterEvent aEvent;
1598 aEvent.Source = *this;
1599 aEvent.DisjunctiveTerm = (sal_Int32)m_aFilterRows.size() - 1;
1600 _rClearBeforeNotify.clear();
1601 // <-- SYNCHRONIZED
1602 m_aFilterListeners.notifyEach( &XFilterControllerListener::disjunctiveTermAdded, aEvent );
1606 bool FormController::determineLockState() const
1608 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1609 // a.) in filter mode we are always locked
1610 // b.) if we have no valid model or our model (a result set) is not alive -> we're locked
1611 // c.) if we are inserting everything is OK and we are not locked
1612 // d.) if are not updatable or on invalid position
1613 Reference< XResultSet > xResultSet(m_xModelAsIndex, UNO_QUERY);
1614 if (m_bFiltering || !xResultSet.is() || !isRowSetAlive(xResultSet))
1615 return true;
1616 else
1617 return !(m_bCanInsert && m_bCurrentRecordNew)
1618 && (xResultSet->isBeforeFirst() || xResultSet->isAfterLast() || xResultSet->rowDeleted() || !m_bCanUpdate);
1621 // FocusListener
1623 void FormController::focusGained(const FocusEvent& e) throw( RuntimeException, std::exception )
1625 // SYNCHRONIZED -->
1626 ::osl::ClearableMutexGuard aGuard( m_aMutex );
1627 impl_checkDisposed_throw();
1629 m_pControlBorderManager->focusGained( e.Source );
1631 Reference< XControl > xControl(e.Source, UNO_QUERY);
1632 if (m_bDBConnection)
1634 // do we need to keep the locking of the commit
1635 // we hold the lock as long as the control differs from the current
1636 // otherwise we disabled the lock
1637 m_bCommitLock = m_bCommitLock && (XControl*)xControl.get() != (XControl*)m_xCurrentControl.get();
1638 if (m_bCommitLock)
1639 return;
1641 // when do we have to commit a value to form or a filter
1642 // a.) if the current value is modified
1643 // b.) there must be a current control
1644 // c.) and it must be different from the new focus owning control or
1645 // d.) the focus is moving around (so we have only one control)
1647 if ( ( m_bModified || m_bFiltering )
1648 && m_xCurrentControl.is()
1649 && ( ( xControl.get() != m_xCurrentControl.get() )
1650 || ( ( e.FocusFlags & FocusChangeReason::AROUND )
1651 && ( m_bCycle || m_bFiltering )
1656 // check the old control if the content is ok
1657 #if OSL_DEBUG_LEVEL > 1
1658 Reference< XBoundControl > xLockingTest(m_xCurrentControl, UNO_QUERY);
1659 sal_Bool bControlIsLocked = xLockingTest.is() && xLockingTest->getLock();
1660 OSL_ENSURE(!bControlIsLocked, "FormController::Gained: I'm modified and the current control is locked ? How this ?");
1661 // normalerweise sollte ein gelocktes Control nicht modified sein, also muss wohl mein bModified aus einem anderen Kontext
1662 // gesetzt worden sein, was ich nicht verstehen wuerde ...
1663 #endif
1664 DBG_ASSERT(m_xCurrentControl.is(), "kein CurrentControl gesetzt");
1665 // zunaechst das Control fragen ob es das IFace unterstuetzt
1666 Reference< XBoundComponent > xBound(m_xCurrentControl, UNO_QUERY);
1667 if (!xBound.is() && m_xCurrentControl.is())
1668 xBound = Reference< XBoundComponent > (m_xCurrentControl->getModel(), UNO_QUERY);
1670 // lock if we lose the focus during commit
1671 m_bCommitLock = true;
1673 // Commit nicht erfolgreich, Focus zuruecksetzen
1674 if (xBound.is() && !xBound->commit())
1676 // the commit failed and we don't commit again until the current control
1677 // which couldn't be commit gains the focus again
1678 Reference< XWindow > xWindow(m_xCurrentControl, UNO_QUERY);
1679 if (xWindow.is())
1680 xWindow->setFocus();
1681 return;
1683 else
1685 m_bModified = false;
1686 m_bCommitLock = false;
1690 if (!m_bFiltering && m_bCycle && (e.FocusFlags & FocusChangeReason::AROUND) && m_xCurrentControl.is())
1692 SQLErrorEvent aErrorEvent;
1693 OSL_ENSURE( m_xFormOperations.is(), "FormController::focusGained: hmm?" );
1694 // should have been created in setModel
1697 if ( e.FocusFlags & FocusChangeReason::FORWARD )
1699 if ( m_xFormOperations.is() && m_xFormOperations->isEnabled( FormFeature::MoveToNext ) )
1700 m_xFormOperations->execute( FormFeature::MoveToNext );
1702 else // backward
1704 if ( m_xFormOperations.is() && m_xFormOperations->isEnabled( FormFeature::MoveToPrevious ) )
1705 m_xFormOperations->execute( FormFeature::MoveToPrevious );
1708 catch ( const Exception& )
1710 // don't handle this any further. That's an ... admissible error.
1711 DBG_UNHANDLED_EXCEPTION();
1716 // Immer noch ein und dasselbe Control
1717 if ( ( m_xActiveControl == xControl )
1718 && ( xControl == m_xCurrentControl )
1721 DBG_ASSERT(m_xCurrentControl.is(), "Kein CurrentControl selektiert");
1722 return;
1725 bool bActivated = !m_xActiveControl.is() && xControl.is();
1727 m_xActiveControl = xControl;
1729 implSetCurrentControl( xControl );
1730 SAL_WARN_IF( !m_xCurrentControl.is(), "svx.form", "implSetCurrentControl did nonsense!" );
1732 if ( bActivated )
1734 // (asynchronously) call activation handlers
1735 m_aActivationEvent.Call();
1737 // call modify listeners
1738 if ( m_bModified )
1739 m_aModifyListeners.notifyEach( &XModifyListener::modified, EventObject( *this ) );
1742 // invalidate all features which depend on the currently focused control
1743 if ( m_bDBConnection && !m_bFiltering )
1744 implInvalidateCurrentControlDependentFeatures();
1746 if ( !m_xCurrentControl.is() )
1747 return;
1749 // Control erhaelt Focus, dann eventuell in den sichtbaren Bereich
1750 Reference< XFormControllerContext > xContext( m_xFormControllerContext );
1751 Reference< XControl > xCurrentControl( m_xCurrentControl );
1752 aGuard.clear();
1753 // <-- SYNCHRONIZED
1755 if ( xContext.is() )
1756 xContext->makeVisible( xCurrentControl );
1760 IMPL_LINK_NOARG( FormController, OnActivated )
1762 EventObject aEvent;
1763 aEvent.Source = *this;
1764 m_aActivateListeners.notifyEach( &XFormControllerListener::formActivated, aEvent );
1766 return 0L;
1770 IMPL_LINK_NOARG( FormController, OnDeactivated )
1772 EventObject aEvent;
1773 aEvent.Source = *this;
1774 m_aActivateListeners.notifyEach( &XFormControllerListener::formDeactivated, aEvent );
1776 return 0L;
1780 void FormController::focusLost(const FocusEvent& e) throw( RuntimeException, std::exception )
1782 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1784 m_pControlBorderManager->focusLost( e.Source );
1786 Reference< XControl > xControl(e.Source, UNO_QUERY);
1787 Reference< XWindowPeer > xNext(e.NextFocus, UNO_QUERY);
1788 Reference< XControl > xNextControl = isInList(xNext);
1789 if (!xNextControl.is())
1791 m_xActiveControl = NULL;
1792 m_aDeactivationEvent.Call();
1797 void SAL_CALL FormController::mousePressed( const awt::MouseEvent& /*_rEvent*/ ) throw (RuntimeException, std::exception)
1799 // not interested in
1803 void SAL_CALL FormController::mouseReleased( const awt::MouseEvent& /*_rEvent*/ ) throw (RuntimeException, std::exception)
1805 // not interested in
1809 void SAL_CALL FormController::mouseEntered( const awt::MouseEvent& _rEvent ) throw (RuntimeException, std::exception)
1811 m_pControlBorderManager->mouseEntered( _rEvent.Source );
1815 void SAL_CALL FormController::mouseExited( const awt::MouseEvent& _rEvent ) throw (RuntimeException, std::exception)
1817 m_pControlBorderManager->mouseExited( _rEvent.Source );
1821 void SAL_CALL FormController::componentValidityChanged( const EventObject& _rSource ) throw (RuntimeException, std::exception)
1823 Reference< XControl > xControl( findControl( m_aControls, Reference< XControlModel >( _rSource.Source, UNO_QUERY ), false, false ) );
1824 Reference< XValidatableFormComponent > xValidatable( _rSource.Source, UNO_QUERY );
1826 OSL_ENSURE( xControl.is() && xValidatable.is(), "FormController::componentValidityChanged: huh?" );
1828 if ( xControl.is() && xValidatable.is() )
1829 m_pControlBorderManager->validityChanged( xControl, xValidatable );
1833 void FormController::setModel(const Reference< XTabControllerModel > & Model) throw( RuntimeException, std::exception )
1835 ::osl::MutexGuard aGuard( m_aMutex );
1836 impl_checkDisposed_throw();
1838 DBG_ASSERT(m_xTabController.is(), "FormController::setModel : invalid aggregate !");
1842 // disconnect from the old model
1843 if (m_xModelAsIndex.is())
1845 if (m_bDBConnection)
1847 // we are currently working on the model
1848 EventObject aEvt(m_xModelAsIndex);
1849 unloaded(aEvt);
1852 Reference< XLoadable > xForm(m_xModelAsIndex, UNO_QUERY);
1853 if (xForm.is())
1854 xForm->removeLoadListener(this);
1856 Reference< XSQLErrorBroadcaster > xBroadcaster(m_xModelAsIndex, UNO_QUERY);
1857 if (xBroadcaster.is())
1858 xBroadcaster->removeSQLErrorListener(this);
1860 Reference< XDatabaseParameterBroadcaster > xParamBroadcaster(m_xModelAsIndex, UNO_QUERY);
1861 if (xParamBroadcaster.is())
1862 xParamBroadcaster->removeParameterListener(this);
1866 disposeAllFeaturesAndDispatchers();
1868 if ( m_xFormOperations.is() )
1869 m_xFormOperations->dispose();
1870 m_xFormOperations.clear();
1872 // set the new model wait for the load event
1873 if (m_xTabController.is())
1874 m_xTabController->setModel(Model);
1875 m_xModelAsIndex = Reference< XIndexAccess > (Model, UNO_QUERY);
1876 m_xModelAsManager = Reference< XEventAttacherManager > (Model, UNO_QUERY);
1878 // only if both ifaces exit, the controller will work successful
1879 if (!m_xModelAsIndex.is() || !m_xModelAsManager.is())
1881 m_xModelAsManager = NULL;
1882 m_xModelAsIndex = NULL;
1885 if (m_xModelAsIndex.is())
1887 // re-create m_xFormOperations
1888 m_xFormOperations = FormOperations::createWithFormController( m_xComponentContext, this );
1889 m_xFormOperations->setFeatureInvalidation( this );
1891 // adding load and ui interaction listeners
1892 Reference< XLoadable > xForm(Model, UNO_QUERY);
1893 if (xForm.is())
1894 xForm->addLoadListener(this);
1896 Reference< XSQLErrorBroadcaster > xBroadcaster(Model, UNO_QUERY);
1897 if (xBroadcaster.is())
1898 xBroadcaster->addSQLErrorListener(this);
1900 Reference< XDatabaseParameterBroadcaster > xParamBroadcaster(Model, UNO_QUERY);
1901 if (xParamBroadcaster.is())
1902 xParamBroadcaster->addParameterListener(this);
1904 // well, is the database already loaded?
1905 // then we have to simulate a load event
1906 Reference< XLoadable > xCursor(m_xModelAsIndex, UNO_QUERY);
1907 if (xCursor.is() && xCursor->isLoaded())
1909 EventObject aEvt(xCursor);
1910 loaded(aEvt);
1913 Reference< XPropertySet > xModelProps( m_xModelAsIndex, UNO_QUERY );
1914 Reference< XPropertySetInfo > xPropInfo( xModelProps->getPropertySetInfo() );
1915 if ( xPropInfo.is()
1916 && xPropInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER )
1917 && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_FOCUS )
1918 && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_MOUSE )
1919 && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_INVALID )
1922 bool bEnableDynamicControlBorder = lcl_shouldUseDynamicControlBorder(
1923 xModelProps.get(), xModelProps->getPropertyValue( FM_PROP_DYNAMIC_CONTROL_BORDER ) );
1924 if ( bEnableDynamicControlBorder )
1925 m_pControlBorderManager->enableDynamicBorderColor();
1926 else
1927 m_pControlBorderManager->disableDynamicBorderColor();
1929 sal_Int32 nColor = 0;
1930 if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_FOCUS ) >>= nColor )
1931 m_pControlBorderManager->setStatusColor( CONTROL_STATUS_FOCUSED, nColor );
1932 if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_MOUSE ) >>= nColor )
1933 m_pControlBorderManager->setStatusColor( CONTROL_STATUS_MOUSE_HOVER, nColor );
1934 if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_INVALID ) >>= nColor )
1935 m_pControlBorderManager->setStatusColor( CONTROL_STATUS_INVALID, nColor );
1939 catch( const Exception& )
1941 DBG_UNHANDLED_EXCEPTION();
1946 Reference< XTabControllerModel > FormController::getModel() throw( RuntimeException, std::exception )
1948 ::osl::MutexGuard aGuard( m_aMutex );
1949 impl_checkDisposed_throw();
1951 DBG_ASSERT(m_xTabController.is(), "FormController::getModel : invalid aggregate !");
1952 if (!m_xTabController.is())
1953 return Reference< XTabControllerModel > ();
1954 return m_xTabController->getModel();
1958 void FormController::addToEventAttacher(const Reference< XControl > & xControl)
1960 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1961 OSL_ENSURE( xControl.is(), "FormController::addToEventAttacher: invalid control - how did you reach this?" );
1962 if ( !xControl.is() )
1963 return; /* throw IllegalArgumentException(); */
1965 // anmelden beim Eventattacher
1966 Reference< XFormComponent > xComp(xControl->getModel(), UNO_QUERY);
1967 if (xComp.is() && m_xModelAsIndex.is())
1969 // Und die Position des ControlModel darin suchen
1970 sal_uInt32 nPos = m_xModelAsIndex->getCount();
1971 Reference< XFormComponent > xTemp;
1972 for( ; nPos; )
1974 m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
1975 if ((XFormComponent*)xComp.get() == (XFormComponent*)xTemp.get())
1977 m_xModelAsManager->attach( nPos, Reference<XInterface>( xControl, UNO_QUERY ), makeAny(xControl) );
1978 break;
1985 void FormController::removeFromEventAttacher(const Reference< XControl > & xControl)
1987 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1988 OSL_ENSURE( xControl.is(), "FormController::removeFromEventAttacher: invalid control - how did you reach this?" );
1989 if ( !xControl.is() )
1990 return; /* throw IllegalArgumentException(); */
1992 // abmelden beim Eventattacher
1993 Reference< XFormComponent > xComp(xControl->getModel(), UNO_QUERY);
1994 if ( xComp.is() && m_xModelAsIndex.is() )
1996 // Und die Position des ControlModel darin suchen
1997 sal_uInt32 nPos = m_xModelAsIndex->getCount();
1998 Reference< XFormComponent > xTemp;
1999 for( ; nPos; )
2001 m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
2002 if ((XFormComponent*)xComp.get() == (XFormComponent*)xTemp.get())
2004 m_xModelAsManager->detach( nPos, Reference<XInterface>( xControl, UNO_QUERY ) );
2005 break;
2012 void FormController::setContainer(const Reference< XControlContainer > & xContainer) throw( RuntimeException, std::exception )
2014 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2015 Reference< XTabControllerModel > xTabModel(getModel());
2016 DBG_ASSERT(xTabModel.is() || !xContainer.is(), "No Model defined");
2017 // if we have a new container we need a model
2018 DBG_ASSERT(m_xTabController.is(), "FormController::setContainer : invalid aggregate !");
2020 ::osl::MutexGuard aGuard( m_aMutex );
2021 Reference< XContainer > xCurrentContainer;
2022 if (m_xTabController.is())
2023 xCurrentContainer = Reference< XContainer > (m_xTabController->getContainer(), UNO_QUERY);
2024 if (xCurrentContainer.is())
2026 xCurrentContainer->removeContainerListener(this);
2028 if ( m_aTabActivationIdle.IsActive() )
2029 m_aTabActivationIdle.Stop();
2031 // clear the filter map
2032 ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), RemoveComponentTextListener( this ) );
2033 m_aFilterComponents.clear();
2035 // einsammeln der Controls
2036 const Reference< XControl >* pControls = m_aControls.getConstArray();
2037 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2038 while ( pControls != pControlsEnd )
2039 implControlRemoved( *pControls++, true );
2041 // Datenbank spezifische Dinge vornehmen
2042 if (m_bDBConnection && isListeningForChanges())
2043 stopListening();
2045 m_aControls.realloc( 0 );
2048 if (m_xTabController.is())
2049 m_xTabController->setContainer(xContainer);
2051 // Welche Controls gehoeren zum Container ?
2052 if (xContainer.is() && xTabModel.is())
2054 Sequence< Reference< XControlModel > > aModels = xTabModel->getControlModels();
2055 const Reference< XControlModel > * pModels = aModels.getConstArray();
2056 Sequence< Reference< XControl > > aAllControls = xContainer->getControls();
2058 sal_Int32 nCount = aModels.getLength();
2059 m_aControls = Sequence< Reference< XControl > >( nCount );
2060 Reference< XControl > * pControls = m_aControls.getArray();
2062 // einsammeln der Controls
2063 sal_Int32 i, j;
2064 for (i = 0, j = 0; i < nCount; ++i, ++pModels )
2066 Reference< XControl > xControl = findControl( aAllControls, *pModels, false, true );
2067 if ( xControl.is() )
2069 pControls[j++] = xControl;
2070 implControlInserted( xControl, true );
2074 // not every model had an associated control
2075 if (j != i)
2076 m_aControls.realloc(j);
2078 // am Container horchen
2079 Reference< XContainer > xNewContainer(xContainer, UNO_QUERY);
2080 if (xNewContainer.is())
2081 xNewContainer->addContainerListener(this);
2083 // Datenbank spezifische Dinge vornehmen
2084 if (m_bDBConnection)
2086 m_bLocked = determineLockState();
2087 setLocks();
2088 if (!isLocked())
2089 startListening();
2092 // befinden sich die Controls in der richtigen Reihenfolge
2093 m_bControlsSorted = true;
2097 Reference< XControlContainer > FormController::getContainer() throw( RuntimeException, std::exception )
2099 ::osl::MutexGuard aGuard( m_aMutex );
2100 impl_checkDisposed_throw();
2102 DBG_ASSERT(m_xTabController.is(), "FormController::getContainer : invalid aggregate !");
2103 if (!m_xTabController.is())
2104 return Reference< XControlContainer > ();
2105 return m_xTabController->getContainer();
2109 Sequence< Reference< XControl > > FormController::getControls() throw( RuntimeException, std::exception )
2111 ::osl::MutexGuard aGuard( m_aMutex );
2112 impl_checkDisposed_throw();
2114 if (!m_bControlsSorted)
2116 Reference< XTabControllerModel > xModel = getModel();
2117 if (!xModel.is())
2118 return m_aControls;
2120 Sequence< Reference< XControlModel > > aControlModels = xModel->getControlModels();
2121 const Reference< XControlModel > * pModels = aControlModels.getConstArray();
2122 sal_Int32 nModels = aControlModels.getLength();
2124 Sequence< Reference< XControl > > aNewControls(nModels);
2126 Reference< XControl > * pControls = aNewControls.getArray();
2127 Reference< XControl > xControl;
2129 // Umsortieren der Controls entsprechend der TabReihenfolge
2130 sal_Int32 j = 0;
2131 for (sal_Int32 i = 0; i < nModels; ++i, ++pModels )
2133 xControl = findControl( m_aControls, *pModels, true, true );
2134 if ( xControl.is() )
2135 pControls[j++] = xControl;
2138 // not every model had an associated control
2139 if ( j != nModels )
2140 aNewControls.realloc( j );
2142 m_aControls = aNewControls;
2143 m_bControlsSorted = true;
2145 return m_aControls;
2149 void FormController::autoTabOrder() throw( RuntimeException, std::exception )
2151 ::osl::MutexGuard aGuard( m_aMutex );
2152 impl_checkDisposed_throw();
2154 DBG_ASSERT(m_xTabController.is(), "FormController::autoTabOrder : invalid aggregate !");
2155 if (m_xTabController.is())
2156 m_xTabController->autoTabOrder();
2160 void FormController::activateTabOrder() throw( RuntimeException, std::exception )
2162 ::osl::MutexGuard aGuard( m_aMutex );
2163 impl_checkDisposed_throw();
2165 DBG_ASSERT(m_xTabController.is(), "FormController::activateTabOrder : invalid aggregate !");
2166 if (m_xTabController.is())
2167 m_xTabController->activateTabOrder();
2171 void FormController::setControlLock(const Reference< XControl > & xControl)
2173 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2174 bool bLocked = isLocked();
2176 // es wird gelockt
2177 // a.) wenn der ganze Datensatz gesperrt ist
2178 // b.) wenn das zugehoerige Feld gespeert ist
2179 Reference< XBoundControl > xBound(xControl, UNO_QUERY);
2180 if (xBound.is() && (( (bLocked && bLocked != bool(xBound->getLock())) ||
2181 !bLocked))) // beim entlocken immer einzelne Felder ueberprüfen
2183 // gibt es eine Datenquelle
2184 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
2185 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
2187 // wie sieht mit den Properties ReadOnly und Enable aus
2188 bool bTouch = true;
2189 if (::comphelper::hasProperty(FM_PROP_ENABLED, xSet))
2190 bTouch = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ENABLED));
2191 if (::comphelper::hasProperty(FM_PROP_READONLY, xSet))
2192 bTouch = !::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_READONLY));
2194 if (bTouch)
2196 Reference< XPropertySet > xField;
2197 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
2198 if (xField.is())
2200 if (bLocked)
2201 xBound->setLock(bLocked);
2202 else
2206 Any aVal = xField->getPropertyValue(FM_PROP_ISREADONLY);
2207 if (aVal.hasValue() && ::comphelper::getBOOL(aVal))
2208 xBound->setLock(sal_True);
2209 else
2210 xBound->setLock(bLocked);
2212 catch( const Exception& )
2214 DBG_UNHANDLED_EXCEPTION();
2225 void FormController::setLocks()
2227 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2228 // alle Controls, die mit einer Datenquelle verbunden sind locken/unlocken
2229 const Reference< XControl >* pControls = m_aControls.getConstArray();
2230 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2231 while ( pControls != pControlsEnd )
2232 setControlLock( *pControls++ );
2236 namespace
2238 bool lcl_shouldListenForModifications( const Reference< XControl >& _rxControl, const Reference< XPropertyChangeListener >& _rxBoundFieldListener )
2240 bool bShould = false;
2242 Reference< XBoundComponent > xBound( _rxControl, UNO_QUERY );
2243 if ( xBound.is() )
2245 bShould = true;
2247 else if ( _rxControl.is() )
2249 Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY );
2250 if ( xModelProps.is() && ::comphelper::hasProperty( FM_PROP_BOUNDFIELD, xModelProps ) )
2252 Reference< XPropertySet > xField;
2253 xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField;
2254 bShould = xField.is();
2256 if ( !bShould && _rxBoundFieldListener.is() )
2257 xModelProps->addPropertyChangeListener( FM_PROP_BOUNDFIELD, _rxBoundFieldListener );
2261 return bShould;
2266 void FormController::startControlModifyListening(const Reference< XControl > & xControl)
2268 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2270 bool bModifyListening = lcl_shouldListenForModifications( xControl, this );
2272 // artificial while
2273 while ( bModifyListening )
2275 Reference< XModifyBroadcaster > xMod(xControl, UNO_QUERY);
2276 if (xMod.is())
2278 xMod->addModifyListener(this);
2279 break;
2282 // alle die Text um vorzeitig ein modified zu erkennen
2283 Reference< XTextComponent > xText(xControl, UNO_QUERY);
2284 if (xText.is())
2286 xText->addTextListener(this);
2287 break;
2290 Reference< XCheckBox > xBox(xControl, UNO_QUERY);
2291 if (xBox.is())
2293 xBox->addItemListener(this);
2294 break;
2297 Reference< XComboBox > xCbBox(xControl, UNO_QUERY);
2298 if (xCbBox.is())
2300 xCbBox->addItemListener(this);
2301 break;
2304 Reference< XListBox > xListBox(xControl, UNO_QUERY);
2305 if (xListBox.is())
2307 xListBox->addItemListener(this);
2308 break;
2310 break;
2315 void FormController::stopControlModifyListening(const Reference< XControl > & xControl)
2317 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2319 bool bModifyListening = lcl_shouldListenForModifications( xControl, NULL );
2321 // kuenstliches while
2322 while (bModifyListening)
2324 Reference< XModifyBroadcaster > xMod(xControl, UNO_QUERY);
2325 if (xMod.is())
2327 xMod->removeModifyListener(this);
2328 break;
2330 // alle die Text um vorzeitig ein modified zu erkennen
2331 Reference< XTextComponent > xText(xControl, UNO_QUERY);
2332 if (xText.is())
2334 xText->removeTextListener(this);
2335 break;
2338 Reference< XCheckBox > xBox(xControl, UNO_QUERY);
2339 if (xBox.is())
2341 xBox->removeItemListener(this);
2342 break;
2345 Reference< XComboBox > xCbBox(xControl, UNO_QUERY);
2346 if (xCbBox.is())
2348 xCbBox->removeItemListener(this);
2349 break;
2352 Reference< XListBox > xListBox(xControl, UNO_QUERY);
2353 if (xListBox.is())
2355 xListBox->removeItemListener(this);
2356 break;
2358 break;
2363 void FormController::startListening()
2365 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2366 m_bModified = false;
2368 // jetzt anmelden bei gebundenen feldern
2369 const Reference< XControl >* pControls = m_aControls.getConstArray();
2370 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2371 while ( pControls != pControlsEnd )
2372 startControlModifyListening( *pControls++ );
2376 void FormController::stopListening()
2378 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2379 m_bModified = false;
2381 // jetzt anmelden bei gebundenen feldern
2382 const Reference< XControl >* pControls = m_aControls.getConstArray();
2383 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2384 while ( pControls != pControlsEnd )
2385 stopControlModifyListening( *pControls++ );
2390 Reference< XControl > FormController::findControl(Sequence< Reference< XControl > >& _rControls, const Reference< XControlModel > & xCtrlModel ,bool _bRemove,bool _bOverWrite) const
2392 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2393 DBG_ASSERT( xCtrlModel.is(), "findControl - welches ?!" );
2395 Reference< XControl >* pControls = _rControls.getArray();
2396 Reference< XControlModel > xModel;
2397 for ( sal_Int32 i = 0, nCount = _rControls.getLength(); i < nCount; ++i, ++pControls )
2399 if ( pControls->is() )
2401 xModel = (*pControls)->getModel();
2402 if ( xModel.get() == xCtrlModel.get() )
2404 Reference< XControl > xControl( *pControls );
2405 if ( _bRemove )
2406 ::comphelper::removeElementAt( _rControls, i );
2407 else if ( _bOverWrite )
2408 pControls->clear();
2409 return xControl;
2413 return Reference< XControl > ();
2417 void FormController::implControlInserted( const Reference< XControl>& _rxControl, bool _bAddToEventAttacher )
2419 Reference< XWindow > xWindow( _rxControl, UNO_QUERY );
2420 if ( xWindow.is() )
2422 xWindow->addFocusListener( this );
2423 xWindow->addMouseListener( this );
2425 if ( _bAddToEventAttacher )
2426 addToEventAttacher( _rxControl );
2429 // add a dispatch interceptor to the control (if supported)
2430 Reference< XDispatchProviderInterception > xInterception( _rxControl, UNO_QUERY );
2431 if ( xInterception.is() )
2432 createInterceptor( xInterception );
2434 if ( _rxControl.is() )
2436 Reference< XControlModel > xModel( _rxControl->getModel() );
2438 // we want to know about the reset of the model of our controls
2439 // (for correctly resetting m_bModified)
2440 Reference< XReset > xReset( xModel, UNO_QUERY );
2441 if ( xReset.is() )
2442 xReset->addResetListener( this );
2444 // and we want to know about the validity, to visually indicate it
2445 Reference< XValidatableFormComponent > xValidatable( xModel, UNO_QUERY );
2446 if ( xValidatable.is() )
2448 xValidatable->addFormComponentValidityListener( this );
2449 m_pControlBorderManager->validityChanged( _rxControl, xValidatable );
2456 void FormController::implControlRemoved( const Reference< XControl>& _rxControl, bool _bRemoveFromEventAttacher )
2458 Reference< XWindow > xWindow( _rxControl, UNO_QUERY );
2459 if ( xWindow.is() )
2461 xWindow->removeFocusListener( this );
2462 xWindow->removeMouseListener( this );
2464 if ( _bRemoveFromEventAttacher )
2465 removeFromEventAttacher( _rxControl );
2468 Reference< XDispatchProviderInterception > xInterception( _rxControl, UNO_QUERY);
2469 if ( xInterception.is() )
2470 deleteInterceptor( xInterception );
2472 if ( _rxControl.is() )
2474 Reference< XControlModel > xModel( _rxControl->getModel() );
2476 Reference< XReset > xReset( xModel, UNO_QUERY );
2477 if ( xReset.is() )
2478 xReset->removeResetListener( this );
2480 Reference< XValidatableFormComponent > xValidatable( xModel, UNO_QUERY );
2481 if ( xValidatable.is() )
2482 xValidatable->removeFormComponentValidityListener( this );
2487 void FormController::implSetCurrentControl( const Reference< XControl >& _rxControl )
2489 if ( m_xCurrentControl.get() == _rxControl.get() )
2490 return;
2492 Reference< XGridControl > xGridControl( m_xCurrentControl, UNO_QUERY );
2493 if ( xGridControl.is() )
2494 xGridControl->removeGridControlListener( this );
2496 m_xCurrentControl = _rxControl;
2498 xGridControl.set( m_xCurrentControl, UNO_QUERY );
2499 if ( xGridControl.is() )
2500 xGridControl->addGridControlListener( this );
2504 void FormController::insertControl(const Reference< XControl > & xControl)
2506 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2507 m_bControlsSorted = false;
2508 m_aControls.realloc(m_aControls.getLength() + 1);
2509 m_aControls.getArray()[m_aControls.getLength() - 1] = xControl;
2511 if ( m_pColumnInfoCache.get() )
2512 m_pColumnInfoCache->deinitializeControls();
2514 implControlInserted( xControl, m_bAttachEvents );
2516 if (m_bDBConnection && !m_bFiltering)
2517 setControlLock(xControl);
2519 if (isListeningForChanges() && m_bAttachEvents)
2520 startControlModifyListening( xControl );
2524 void FormController::removeControl(const Reference< XControl > & xControl)
2526 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2527 const Reference< XControl >* pControls = m_aControls.getConstArray();
2528 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2529 while ( pControls != pControlsEnd )
2531 if ( xControl.get() == (*pControls++).get() )
2533 ::comphelper::removeElementAt( m_aControls, pControls - m_aControls.getConstArray() - 1 );
2534 break;
2538 FilterComponents::iterator componentPos = ::std::find( m_aFilterComponents.begin(), m_aFilterComponents.end(), xControl );
2539 if ( componentPos != m_aFilterComponents.end() )
2540 m_aFilterComponents.erase( componentPos );
2542 implControlRemoved( xControl, m_bDetachEvents );
2544 if ( isListeningForChanges() && m_bDetachEvents )
2545 stopControlModifyListening( xControl );
2548 // XLoadListener
2550 void FormController::loaded(const EventObject& rEvent) throw( RuntimeException, std::exception )
2552 OSL_ENSURE( rEvent.Source == m_xModelAsIndex, "FormController::loaded: where did this come from?" );
2554 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2555 ::osl::MutexGuard aGuard( m_aMutex );
2556 Reference< XRowSet > xForm(rEvent.Source, UNO_QUERY);
2557 // do we have a connected data source
2558 if (xForm.is() && getConnection(xForm).is())
2560 Reference< XPropertySet > xSet(xForm, UNO_QUERY);
2561 if (xSet.is())
2563 Any aVal = xSet->getPropertyValue(FM_PROP_CYCLE);
2564 sal_Int32 aVal2 = 0;
2565 ::cppu::enum2int(aVal2,aVal);
2566 m_bCycle = !aVal.hasValue() || aVal2 == TabulatorCycle_RECORDS;
2567 m_bCanUpdate = canUpdate(xSet);
2568 m_bCanInsert = canInsert(xSet);
2569 m_bCurrentRecordModified = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED));
2570 m_bCurrentRecordNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
2572 startFormListening( xSet, false );
2574 // set the locks for the current controls
2575 if (getContainer().is())
2577 m_aLoadEvent.Call();
2580 else
2582 m_bCanInsert = m_bCanUpdate = m_bCycle = false;
2583 m_bCurrentRecordModified = false;
2584 m_bCurrentRecordNew = false;
2585 m_bLocked = false;
2587 m_bDBConnection = true;
2589 else
2591 m_bDBConnection = false;
2592 m_bCanInsert = m_bCanUpdate = m_bCycle = false;
2593 m_bCurrentRecordModified = false;
2594 m_bCurrentRecordNew = false;
2595 m_bLocked = false;
2598 Reference< XColumnsSupplier > xFormColumns( xForm, UNO_QUERY );
2599 m_pColumnInfoCache.reset( xFormColumns.is() ? new ColumnInfoCache( xFormColumns ) : NULL );
2601 updateAllDispatchers();
2605 void FormController::updateAllDispatchers() const
2607 ::std::for_each(
2608 m_aFeatureDispatchers.begin(),
2609 m_aFeatureDispatchers.end(),
2610 ::o3tl::compose1(
2611 UpdateAllListeners(),
2612 ::o3tl::select2nd< DispatcherContainer::value_type >()
2618 IMPL_LINK_NOARG(FormController, OnLoad)
2620 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2621 m_bLocked = determineLockState();
2623 setLocks();
2625 if (!m_bLocked)
2626 startListening();
2628 // just one exception toggle the auto values
2629 if (m_bCurrentRecordNew)
2630 toggleAutoFields(true);
2632 return 1L;
2636 void FormController::unloaded(const EventObject& /*rEvent*/) throw( RuntimeException, std::exception )
2638 ::osl::MutexGuard aGuard( m_aMutex );
2639 impl_checkDisposed_throw();
2641 updateAllDispatchers();
2645 void FormController::reloading(const EventObject& /*aEvent*/) throw( RuntimeException, std::exception )
2647 ::osl::MutexGuard aGuard( m_aMutex );
2648 impl_checkDisposed_throw();
2650 // do the same like in unloading
2651 // just one exception toggle the auto values
2652 m_aToggleEvent.CancelPendingCall();
2653 unload();
2657 void FormController::reloaded(const EventObject& aEvent) throw( RuntimeException, std::exception )
2659 ::osl::MutexGuard aGuard( m_aMutex );
2660 impl_checkDisposed_throw();
2662 loaded(aEvent);
2666 void FormController::unloading(const EventObject& /*aEvent*/) throw( RuntimeException, std::exception )
2668 ::osl::MutexGuard aGuard( m_aMutex );
2669 impl_checkDisposed_throw();
2671 unload();
2675 void FormController::unload() throw( RuntimeException )
2677 ::osl::MutexGuard aGuard( m_aMutex );
2678 impl_checkDisposed_throw();
2680 m_aLoadEvent.CancelPendingCall();
2682 // be sure not to have autofields
2683 if (m_bCurrentRecordNew)
2684 toggleAutoFields(false);
2686 // remove bound field listing again
2687 removeBoundFieldListener();
2689 if (m_bDBConnection && isListeningForChanges())
2690 stopListening();
2692 Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
2693 if ( m_bDBConnection && xSet.is() )
2694 stopFormListening( xSet, false );
2696 m_bDBConnection = false;
2697 m_bCanInsert = m_bCanUpdate = m_bCycle = false;
2698 m_bCurrentRecordModified = m_bCurrentRecordNew = m_bLocked = false;
2700 m_pColumnInfoCache.reset();
2704 void FormController::removeBoundFieldListener()
2706 const Reference< XControl >* pControls = m_aControls.getConstArray();
2707 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2708 while ( pControls != pControlsEnd )
2710 Reference< XPropertySet > xProp( *pControls++, UNO_QUERY );
2711 if ( xProp.is() )
2712 xProp->removePropertyChangeListener( FM_PROP_BOUNDFIELD, this );
2717 void FormController::startFormListening( const Reference< XPropertySet >& _rxForm, bool _bPropertiesOnly )
2721 if ( m_bCanInsert || m_bCanUpdate ) // form can be modified
2723 _rxForm->addPropertyChangeListener( FM_PROP_ISNEW, this );
2724 _rxForm->addPropertyChangeListener( FM_PROP_ISMODIFIED, this );
2726 if ( !_bPropertiesOnly )
2728 // set the Listener for UI interaction
2729 Reference< XRowSetApproveBroadcaster > xApprove( _rxForm, UNO_QUERY );
2730 if ( xApprove.is() )
2731 xApprove->addRowSetApproveListener( this );
2733 // listener for row set changes
2734 Reference< XRowSet > xRowSet( _rxForm, UNO_QUERY );
2735 if ( xRowSet.is() )
2736 xRowSet->addRowSetListener( this );
2740 Reference< XPropertySetInfo > xInfo = _rxForm->getPropertySetInfo();
2741 if ( xInfo.is() && xInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) )
2742 _rxForm->addPropertyChangeListener( FM_PROP_DYNAMIC_CONTROL_BORDER, this );
2744 catch( const Exception& )
2746 DBG_UNHANDLED_EXCEPTION();
2751 void FormController::stopFormListening( const Reference< XPropertySet >& _rxForm, bool _bPropertiesOnly )
2755 if ( m_bCanInsert || m_bCanUpdate )
2757 _rxForm->removePropertyChangeListener( FM_PROP_ISNEW, this );
2758 _rxForm->removePropertyChangeListener( FM_PROP_ISMODIFIED, this );
2760 if ( !_bPropertiesOnly )
2762 Reference< XRowSetApproveBroadcaster > xApprove( _rxForm, UNO_QUERY );
2763 if (xApprove.is())
2764 xApprove->removeRowSetApproveListener(this);
2766 Reference< XRowSet > xRowSet( _rxForm, UNO_QUERY );
2767 if ( xRowSet.is() )
2768 xRowSet->removeRowSetListener( this );
2772 Reference< XPropertySetInfo > xInfo = _rxForm->getPropertySetInfo();
2773 if ( xInfo.is() && xInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) )
2774 _rxForm->removePropertyChangeListener( FM_PROP_DYNAMIC_CONTROL_BORDER, this );
2776 catch( const Exception& )
2778 DBG_UNHANDLED_EXCEPTION();
2782 // com::sun::star::sdbc::XRowSetListener
2784 void FormController::cursorMoved(const EventObject& /*event*/) throw( RuntimeException, std::exception )
2786 ::osl::MutexGuard aGuard( m_aMutex );
2787 impl_checkDisposed_throw();
2789 // toggle the locking ?
2790 if (m_bLocked != determineLockState())
2792 m_bLocked = !m_bLocked;
2793 setLocks();
2794 if (isListeningForChanges())
2795 startListening();
2796 else
2797 stopListening();
2800 // neither the current control nor the current record are modified anymore
2801 m_bCurrentRecordModified = m_bModified = false;
2805 void FormController::rowChanged(const EventObject& /*event*/) throw( RuntimeException, std::exception )
2807 // not interested in ...
2810 void FormController::rowSetChanged(const EventObject& /*event*/) throw( RuntimeException, std::exception )
2812 // not interested in ...
2816 // XContainerListener
2818 void SAL_CALL FormController::elementInserted(const ContainerEvent& evt) throw( RuntimeException, std::exception )
2820 ::osl::MutexGuard aGuard( m_aMutex );
2821 impl_checkDisposed_throw();
2823 Reference< XControl > xControl( evt.Element, UNO_QUERY );
2824 if ( !xControl.is() )
2825 return;
2827 Reference< XFormComponent > xModel(xControl->getModel(), UNO_QUERY);
2828 if (xModel.is() && m_xModelAsIndex == xModel->getParent())
2830 insertControl(xControl);
2832 if ( m_aTabActivationIdle.IsActive() )
2833 m_aTabActivationIdle.Stop();
2835 m_aTabActivationIdle.Start();
2837 // are we in filtermode and a XModeSelector has inserted an element
2838 else if (m_bFiltering && Reference< XModeSelector > (evt.Source, UNO_QUERY).is())
2840 xModel = Reference< XFormComponent > (evt.Source, UNO_QUERY);
2841 if (xModel.is() && m_xModelAsIndex == xModel->getParent())
2843 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
2844 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
2846 // does the model use a bound field ?
2847 Reference< XPropertySet > xField;
2848 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
2850 Reference< XTextComponent > xText(xControl, UNO_QUERY);
2851 // may we filter the field?
2852 if (xText.is() && xField.is() && ::comphelper::hasProperty(FM_PROP_SEARCHABLE, xField) &&
2853 ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_SEARCHABLE)))
2855 m_aFilterComponents.push_back( xText );
2856 xText->addTextListener( this );
2864 void SAL_CALL FormController::elementReplaced(const ContainerEvent& evt) throw( RuntimeException, std::exception )
2866 // simulate an elementRemoved
2867 ContainerEvent aRemoveEvent( evt );
2868 aRemoveEvent.Element = evt.ReplacedElement;
2869 aRemoveEvent.ReplacedElement = Any();
2870 elementRemoved( aRemoveEvent );
2872 // simulate an elementInserted
2873 ContainerEvent aInsertEvent( evt );
2874 aInsertEvent.ReplacedElement = Any();
2875 elementInserted( aInsertEvent );
2879 void SAL_CALL FormController::elementRemoved(const ContainerEvent& evt) throw( RuntimeException, std::exception )
2881 ::osl::MutexGuard aGuard( m_aMutex );
2882 impl_checkDisposed_throw();
2884 Reference< XControl > xControl;
2885 evt.Element >>= xControl;
2886 if (!xControl.is())
2887 return;
2889 Reference< XFormComponent > xModel(xControl->getModel(), UNO_QUERY);
2890 if (xModel.is() && m_xModelAsIndex == xModel->getParent())
2892 removeControl(xControl);
2893 // TabOrder nicht neu berechnen, da das intern schon funktionieren muss!
2895 // are we in filtermode and a XModeSelector has inserted an element
2896 else if (m_bFiltering && Reference< XModeSelector > (evt.Source, UNO_QUERY).is())
2898 FilterComponents::iterator componentPos = ::std::find(
2899 m_aFilterComponents.begin(), m_aFilterComponents.end(), xControl );
2900 if ( componentPos != m_aFilterComponents.end() )
2901 m_aFilterComponents.erase( componentPos );
2906 Reference< XControl > FormController::isInList(const Reference< XWindowPeer > & xPeer) const
2908 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2909 const Reference< XControl >* pControls = m_aControls.getConstArray();
2911 sal_uInt32 nCtrls = m_aControls.getLength();
2912 for ( sal_uInt32 n = 0; n < nCtrls && xPeer.is(); ++n, ++pControls )
2914 if ( pControls->is() )
2916 Reference< XVclWindowPeer > xCtrlPeer( (*pControls)->getPeer(), UNO_QUERY);
2917 if ( ( xCtrlPeer.get() == xPeer.get() ) || xCtrlPeer->isChild( xPeer ) )
2918 return *pControls;
2921 return Reference< XControl > ();
2925 void FormController::activateFirst() throw( RuntimeException, std::exception )
2927 ::osl::MutexGuard aGuard( m_aMutex );
2928 impl_checkDisposed_throw();
2930 DBG_ASSERT(m_xTabController.is(), "FormController::activateFirst : invalid aggregate !");
2931 if (m_xTabController.is())
2932 m_xTabController->activateFirst();
2936 void FormController::activateLast() throw( RuntimeException, std::exception )
2938 ::osl::MutexGuard aGuard( m_aMutex );
2939 impl_checkDisposed_throw();
2941 DBG_ASSERT(m_xTabController.is(), "FormController::activateLast : invalid aggregate !");
2942 if (m_xTabController.is())
2943 m_xTabController->activateLast();
2946 // XFormController
2948 Reference< XFormOperations > SAL_CALL FormController::getFormOperations() throw (RuntimeException, std::exception)
2950 ::osl::MutexGuard aGuard( m_aMutex );
2951 impl_checkDisposed_throw();
2953 return m_xFormOperations;
2957 Reference< XControl> SAL_CALL FormController::getCurrentControl() throw( RuntimeException, std::exception )
2959 ::osl::MutexGuard aGuard( m_aMutex );
2960 impl_checkDisposed_throw();
2961 return m_xCurrentControl;
2965 void SAL_CALL FormController::addActivateListener(const Reference< XFormControllerListener > & l) throw( RuntimeException, std::exception )
2967 ::osl::MutexGuard aGuard( m_aMutex );
2968 impl_checkDisposed_throw();
2969 m_aActivateListeners.addInterface(l);
2972 void SAL_CALL FormController::removeActivateListener(const Reference< XFormControllerListener > & l) throw( RuntimeException, std::exception )
2974 ::osl::MutexGuard aGuard( m_aMutex );
2975 impl_checkDisposed_throw();
2976 m_aActivateListeners.removeInterface(l);
2980 void SAL_CALL FormController::addChildController( const Reference< XFormController >& _ChildController ) throw( RuntimeException, IllegalArgumentException, std::exception )
2982 ::osl::MutexGuard aGuard( m_aMutex );
2983 impl_checkDisposed_throw();
2985 if ( !_ChildController.is() )
2986 throw IllegalArgumentException( OUString(), *this, 1 );
2987 // TODO: (localized) error message
2989 // the parent of our (to-be-)child must be our own model
2990 Reference< XFormComponent > xFormOfChild( _ChildController->getModel(), UNO_QUERY );
2991 if ( !xFormOfChild.is() )
2992 throw IllegalArgumentException( OUString(), *this, 1 );
2993 // TODO: (localized) error message
2995 if ( xFormOfChild->getParent() != m_xModelAsIndex )
2996 throw IllegalArgumentException( OUString(), *this, 1 );
2997 // TODO: (localized) error message
2999 m_aChildren.push_back( _ChildController );
3000 _ChildController->setParent( *this );
3002 // search the position of the model within the form
3003 sal_uInt32 nPos = m_xModelAsIndex->getCount();
3004 Reference< XFormComponent > xTemp;
3005 for( ; nPos; )
3007 m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
3008 if ( xFormOfChild == xTemp )
3010 m_xModelAsManager->attach( nPos, Reference<XInterface>( _ChildController, UNO_QUERY ), makeAny( _ChildController) );
3011 break;
3017 Reference< XFormControllerContext > SAL_CALL FormController::getContext() throw (RuntimeException, std::exception)
3019 ::osl::MutexGuard aGuard( m_aMutex );
3020 impl_checkDisposed_throw();
3021 return m_xFormControllerContext;
3025 void SAL_CALL FormController::setContext( const Reference< XFormControllerContext >& _context ) throw (RuntimeException, std::exception)
3027 ::osl::MutexGuard aGuard( m_aMutex );
3028 impl_checkDisposed_throw();
3029 m_xFormControllerContext = _context;
3033 Reference< XInteractionHandler > SAL_CALL FormController::getInteractionHandler() throw (RuntimeException, std::exception)
3035 ::osl::MutexGuard aGuard( m_aMutex );
3036 impl_checkDisposed_throw();
3037 return m_xInteractionHandler;
3041 void SAL_CALL FormController::setInteractionHandler( const Reference< XInteractionHandler >& _interactionHandler ) throw (RuntimeException, std::exception)
3043 ::osl::MutexGuard aGuard( m_aMutex );
3044 impl_checkDisposed_throw();
3045 m_xInteractionHandler = _interactionHandler;
3049 void FormController::setFilter(::std::vector<FmFieldInfo>& rFieldInfos)
3051 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3052 // create the composer
3053 Reference< XRowSet > xForm(m_xModelAsIndex, UNO_QUERY);
3054 Reference< XConnection > xConnection(getConnection(xForm));
3055 if (xForm.is())
3059 Reference< XMultiServiceFactory > xFactory( xConnection, UNO_QUERY_THROW );
3060 m_xComposer.set(
3061 xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"),
3062 UNO_QUERY_THROW );
3064 Reference< XPropertySet > xSet( xForm, UNO_QUERY );
3065 OUString sStatement = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_ACTIVECOMMAND ) );
3066 OUString sFilter = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_FILTER ) );
3067 m_xComposer->setElementaryQuery( sStatement );
3068 m_xComposer->setFilter( sFilter );
3070 catch( const Exception& )
3072 DBG_UNHANDLED_EXCEPTION();
3076 if (m_xComposer.is())
3078 Sequence< Sequence < PropertyValue > > aFilterRows = m_xComposer->getStructuredFilter();
3080 // ok, we receive the list of filters as sequence of fieldnames, value
3081 // now we have to transform the fieldname into UI names, that could be a label of the field or
3082 // a aliasname or the fieldname itself
3084 // first adjust the field names if necessary
3085 Reference< XNameAccess > xQueryColumns =
3086 Reference< XColumnsSupplier >( m_xComposer, UNO_QUERY_THROW )->getColumns();
3088 for (::std::vector<FmFieldInfo>::iterator iter = rFieldInfos.begin();
3089 iter != rFieldInfos.end(); ++iter)
3091 if ( xQueryColumns->hasByName((*iter).aFieldName) )
3093 if ( (xQueryColumns->getByName((*iter).aFieldName) >>= (*iter).xField) && (*iter).xField.is() )
3094 (*iter).xField->getPropertyValue(FM_PROP_REALNAME) >>= (*iter).aFieldName;
3098 Reference< XDatabaseMetaData> xMetaData(xConnection->getMetaData());
3099 // now transfer the filters into Value/TextComponent pairs
3100 ::comphelper::UStringMixEqual aCompare(xMetaData->storesMixedCaseQuotedIdentifiers());
3102 // need to parse criteria localized
3103 Reference< XNumberFormatsSupplier> xFormatSupplier( getNumberFormats(xConnection, true));
3104 Reference< XNumberFormatter> xFormatter = NumberFormatter::create(m_xComponentContext);
3105 xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
3106 Locale aAppLocale = Application::GetSettings().GetUILanguageTag().getLocale();
3107 const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetUILocaleDataWrapper() );
3108 /* FIXME: casting this to sal_Char is plain wrong and of course only
3109 * works for ASCII separators, but
3110 * pParseNode->parseNodeToPredicateStr() expects a sal_Char. Fix it
3111 * there. */
3112 sal_Char cDecimalSeparator = (sal_Char)rLocaleWrapper.getNumDecimalSep()[0];
3113 SAL_WARN_IF( (sal_Unicode)cDecimalSeparator != rLocaleWrapper.getNumDecimalSep()[0],
3114 "svx.form", "FormController::setFilter: wrong cast of decimal separator to sal_Char!");
3116 // retrieving the filter
3117 const Sequence < PropertyValue >* pRow = aFilterRows.getConstArray();
3118 for (sal_Int32 i = 0, nLen = aFilterRows.getLength(); i < nLen; ++i)
3120 FmFilterRow aRow;
3122 // search a field for the given name
3123 const PropertyValue* pRefValues = pRow[i].getConstArray();
3124 for (sal_Int32 j = 0, nLen1 = pRow[i].getLength(); j < nLen1; j++)
3126 // look for the text component
3127 Reference< XPropertySet > xField;
3130 Reference< XPropertySet > xSet;
3131 OUString aRealName;
3133 // first look with the given name
3134 if (xQueryColumns->hasByName(pRefValues[j].Name))
3136 xQueryColumns->getByName(pRefValues[j].Name) >>= xSet;
3138 // get the RealName
3139 xSet->getPropertyValue("RealName") >>= aRealName;
3141 // compare the condition field name and the RealName
3142 if (aCompare(aRealName, pRefValues[j].Name))
3143 xField = xSet;
3145 if (!xField.is())
3147 // no we have to check every column to find the realname
3148 Reference< XIndexAccess > xColumnsByIndex(xQueryColumns, UNO_QUERY);
3149 for (sal_Int32 n = 0, nCount = xColumnsByIndex->getCount(); n < nCount; n++)
3151 xColumnsByIndex->getByIndex(n) >>= xSet;
3152 xSet->getPropertyValue("RealName") >>= aRealName;
3153 if (aCompare(aRealName, pRefValues[j].Name))
3155 // get the column by its alias
3156 xField = xSet;
3157 break;
3161 if (!xField.is())
3162 continue;
3164 catch (const Exception&)
3166 continue;
3169 // find the text component
3170 for (::std::vector<FmFieldInfo>::iterator iter = rFieldInfos.begin();
3171 iter != rFieldInfos.end(); ++iter)
3173 // we found the field so insert a new entry to the filter row
3174 if ((*iter).xField == xField)
3176 // do we already have the control ?
3177 if (aRow.find((*iter).xText) != aRow.end())
3179 OUString aCompText = aRow[(*iter).xText];
3180 aCompText += " ";
3181 OString aVal = m_pParser->getContext().getIntlKeywordAscii(IParseContext::KEY_AND);
3182 aCompText += OUString(aVal.getStr(),aVal.getLength(),RTL_TEXTENCODING_ASCII_US);
3183 aCompText += " ";
3184 aCompText += ::comphelper::getString(pRefValues[j].Value);
3185 aRow[(*iter).xText] = aCompText;
3187 else
3189 OUString sPredicate,sErrorMsg;
3190 pRefValues[j].Value >>= sPredicate;
3191 std::shared_ptr< OSQLParseNode > pParseNode = predicateTree(sErrorMsg, sPredicate, xFormatter, xField);
3192 if ( pParseNode != nullptr )
3194 OUString sCriteria;
3195 pParseNode->parseNodeToPredicateStr( sCriteria
3196 ,xConnection
3197 ,xFormatter
3198 ,xField
3199 ,OUString()
3200 ,aAppLocale
3201 ,cDecimalSeparator
3202 ,getParseContext());
3203 aRow[(*iter).xText] = sCriteria;
3210 if (aRow.empty())
3211 continue;
3213 impl_addFilterRow( aRow );
3217 // now set the filter controls
3218 for ( ::std::vector<FmFieldInfo>::iterator field = rFieldInfos.begin();
3219 field != rFieldInfos.end();
3220 ++field
3223 m_aFilterComponents.push_back( field->xText );
3228 void FormController::startFiltering()
3230 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3232 Reference< XConnection > xConnection( getConnection( Reference< XRowSet >( m_xModelAsIndex, UNO_QUERY ) ) );
3233 if ( !xConnection.is() )
3234 // nothing to do - can't filter a form which is not connected
3235 return;
3237 // stop listening for controls
3238 if (isListeningForChanges())
3239 stopListening();
3241 m_bFiltering = true;
3243 // as we don't want new controls to be attached to the scripting environment
3244 // we change attach flags
3245 m_bAttachEvents = false;
3247 // Austauschen der Kontrols fuer das aktuelle Formular
3248 Sequence< Reference< XControl > > aControlsCopy( m_aControls );
3249 const Reference< XControl >* pControls = aControlsCopy.getConstArray();
3250 sal_Int32 nControlCount = aControlsCopy.getLength();
3252 // the control we have to activate after replacement
3253 Reference< XDatabaseMetaData > xMetaData(xConnection->getMetaData());
3254 Reference< XNumberFormatsSupplier > xFormatSupplier = getNumberFormats(xConnection, true);
3255 Reference< XNumberFormatter > xFormatter = NumberFormatter::create(m_xComponentContext);
3256 xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
3258 // structure for storing the field info
3259 ::std::vector<FmFieldInfo> aFieldInfos;
3261 for (sal_Int32 i = nControlCount; i > 0;)
3263 Reference< XControl > xControl = pControls[--i];
3264 if (xControl.is())
3266 // no events for the control anymore
3267 removeFromEventAttacher(xControl);
3269 // do we have a mode selector
3270 Reference< XModeSelector > xSelector(xControl, UNO_QUERY);
3271 if (xSelector.is())
3273 xSelector->setMode( OUString( "FilterMode" ) );
3275 // listening for new controls of the selector
3276 Reference< XContainer > xContainer(xSelector, UNO_QUERY);
3277 if (xContainer.is())
3278 xContainer->addContainerListener(this);
3280 Reference< XEnumerationAccess > xElementAccess(xSelector, UNO_QUERY);
3281 if (xElementAccess.is())
3283 Reference< XEnumeration > xEnumeration(xElementAccess->createEnumeration());
3284 Reference< XControl > xSubControl;
3285 while (xEnumeration->hasMoreElements())
3287 xEnumeration->nextElement() >>= xSubControl;
3288 if (xSubControl.is())
3290 Reference< XPropertySet > xSet(xSubControl->getModel(), UNO_QUERY);
3291 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
3293 // does the model use a bound field ?
3294 Reference< XPropertySet > xField;
3295 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
3297 Reference< XTextComponent > xText(xSubControl, UNO_QUERY);
3298 // may we filter the field?
3299 if (xText.is() && xField.is() && ::comphelper::hasProperty(FM_PROP_SEARCHABLE, xField) &&
3300 ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_SEARCHABLE)))
3302 aFieldInfos.push_back(FmFieldInfo(xField, xText));
3303 xText->addTextListener(this);
3309 continue;
3312 Reference< XPropertySet > xModel( xControl->getModel(), UNO_QUERY );
3313 if (xModel.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xModel))
3315 // does the model use a bound field ?
3316 Any aVal = xModel->getPropertyValue(FM_PROP_BOUNDFIELD);
3317 Reference< XPropertySet > xField;
3318 aVal >>= xField;
3320 // may we filter the field?
3322 if ( xField.is()
3323 && ::comphelper::hasProperty( FM_PROP_SEARCHABLE, xField )
3324 && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_SEARCHABLE ) )
3327 // create a filter control
3328 Reference< XControl > xFilterControl = form::control::FilterControl::createWithFormat(
3329 m_xComponentContext,
3330 VCLUnoHelper::GetInterface( getDialogParentWindow() ),
3331 xFormatter,
3332 xModel);
3334 if ( replaceControl( xControl, xFilterControl ) )
3336 Reference< XTextComponent > xFilterText( xFilterControl, UNO_QUERY );
3337 aFieldInfos.push_back( FmFieldInfo( xField, xFilterText ) );
3338 xFilterText->addTextListener(this);
3342 else
3344 // abmelden vom EventManager
3349 // we have all filter controls now, so the next step is to read the filters from the form
3350 // resolve all aliases and set the current filter to the according structure
3351 setFilter(aFieldInfos);
3353 Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
3354 if ( xSet.is() )
3355 stopFormListening( xSet, true );
3357 impl_setTextOnAllFilter_throw();
3359 // lock all controls which are not used for filtering
3360 m_bLocked = determineLockState();
3361 setLocks();
3362 m_bAttachEvents = true;
3366 void FormController::stopFiltering()
3368 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3369 if ( !m_bFiltering ) // #104693# OJ
3370 { // nothing to do
3371 return;
3374 m_bFiltering = false;
3375 m_bDetachEvents = false;
3377 ::comphelper::disposeComponent(m_xComposer);
3379 // Austauschen der Kontrols fuer das aktuelle Formular
3380 Sequence< Reference< XControl > > aControlsCopy( m_aControls );
3381 const Reference< XControl > * pControls = aControlsCopy.getConstArray();
3382 sal_Int32 nControlCount = aControlsCopy.getLength();
3384 // clear the filter control map
3385 ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), RemoveComponentTextListener( this ) );
3386 m_aFilterComponents.clear();
3388 for ( sal_Int32 i = nControlCount; i > 0; )
3390 Reference< XControl > xControl = pControls[--i];
3391 if (xControl.is())
3393 // now enable eventhandling again
3394 addToEventAttacher(xControl);
3396 Reference< XModeSelector > xSelector(xControl, UNO_QUERY);
3397 if (xSelector.is())
3399 xSelector->setMode( OUString( "DataMode" ) );
3401 // listening for new controls of the selector
3402 Reference< XContainer > xContainer(xSelector, UNO_QUERY);
3403 if (xContainer.is())
3404 xContainer->removeContainerListener(this);
3405 continue;
3408 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
3409 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
3411 // does the model use a bound field ?
3412 Reference< XPropertySet > xField;
3413 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
3415 // may we filter the field?
3416 if ( xField.is()
3417 && ::comphelper::hasProperty( FM_PROP_SEARCHABLE, xField )
3418 && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_SEARCHABLE ) )
3421 OUString sServiceName;
3422 OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DEFAULTCONTROL ) >>= sServiceName );
3423 Reference< XControl > xNewControl( m_xComponentContext->getServiceManager()->createInstanceWithContext( sServiceName, m_xComponentContext ), UNO_QUERY );
3424 replaceControl( xControl, xNewControl );
3430 Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
3431 if ( xSet.is() )
3432 startFormListening( xSet, true );
3434 m_bDetachEvents = true;
3436 m_aFilterRows.clear();
3437 m_nCurrentFilterPosition = -1;
3439 // release the locks if possible
3440 // lock all controls which are not used for filtering
3441 m_bLocked = determineLockState();
3442 setLocks();
3444 // restart listening for control modifications
3445 if (isListeningForChanges())
3446 startListening();
3449 // XModeSelector
3451 void FormController::setMode(const OUString& Mode) throw( NoSupportException, RuntimeException, std::exception )
3453 ::osl::MutexGuard aGuard( m_aMutex );
3454 impl_checkDisposed_throw();
3456 if (!supportsMode(Mode))
3457 throw NoSupportException();
3459 if (Mode == m_aMode)
3460 return;
3462 m_aMode = Mode;
3464 if ( Mode == "FilterMode" )
3465 startFiltering();
3466 else
3467 stopFiltering();
3469 for (FmFormControllers::const_iterator i = m_aChildren.begin();
3470 i != m_aChildren.end(); ++i)
3472 Reference< XModeSelector > xMode(*i, UNO_QUERY);
3473 if ( xMode.is() )
3474 xMode->setMode(Mode);
3479 OUString SAL_CALL FormController::getMode() throw( RuntimeException, std::exception )
3481 ::osl::MutexGuard aGuard( m_aMutex );
3482 impl_checkDisposed_throw();
3484 return m_aMode;
3488 Sequence< OUString > SAL_CALL FormController::getSupportedModes() throw( RuntimeException, std::exception )
3490 ::osl::MutexGuard aGuard( m_aMutex );
3491 impl_checkDisposed_throw();
3493 static Sequence< OUString > aModes;
3494 if (!aModes.getLength())
3496 aModes.realloc(2);
3497 aModes[0] = "DataMode";
3498 aModes[1] = "FilterMode";
3500 return aModes;
3504 sal_Bool SAL_CALL FormController::supportsMode(const OUString& Mode) throw( RuntimeException, std::exception )
3506 ::osl::MutexGuard aGuard( m_aMutex );
3507 impl_checkDisposed_throw();
3509 Sequence< OUString > aModes(getSupportedModes());
3510 const OUString* pModes = aModes.getConstArray();
3511 for (sal_Int32 i = aModes.getLength(); i > 0; )
3513 if (pModes[--i] == Mode)
3514 return sal_True;
3516 return sal_False;
3520 vcl::Window* FormController::getDialogParentWindow()
3522 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3523 vcl::Window* pParentWindow = NULL;
3526 Reference< XControl > xContainerControl( getContainer(), UNO_QUERY_THROW );
3527 Reference< XWindowPeer > xContainerPeer( xContainerControl->getPeer(), UNO_QUERY_THROW );
3528 pParentWindow = VCLUnoHelper::GetWindow( xContainerPeer );
3530 catch( const Exception& )
3532 DBG_UNHANDLED_EXCEPTION();
3534 return pParentWindow;
3537 bool FormController::checkFormComponentValidity( OUString& /* [out] */ _rFirstInvalidityExplanation, Reference< XControlModel >& /* [out] */ _rxFirstInvalidModel )
3541 Reference< XEnumerationAccess > xControlEnumAcc( getModel(), UNO_QUERY );
3542 Reference< XEnumeration > xControlEnumeration;
3543 if ( xControlEnumAcc.is() )
3544 xControlEnumeration = xControlEnumAcc->createEnumeration();
3545 OSL_ENSURE( xControlEnumeration.is(), "FormController::checkFormComponentValidity: cannot enumerate the controls!" );
3546 if ( !xControlEnumeration.is() )
3547 // assume all valid
3548 return true;
3550 Reference< XValidatableFormComponent > xValidatable;
3551 while ( xControlEnumeration->hasMoreElements() )
3553 if ( !( xControlEnumeration->nextElement() >>= xValidatable ) )
3554 // control does not support validation
3555 continue;
3557 if ( xValidatable->isValid() )
3558 continue;
3560 Reference< XValidator > xValidator( xValidatable->getValidator() );
3561 OSL_ENSURE( xValidator.is(), "FormController::checkFormComponentValidity: invalid, but no validator?" );
3562 if ( !xValidator.is() )
3563 // this violates the interface definition of css.form.validation.XValidatableFormComponent ...
3564 continue;
3566 _rFirstInvalidityExplanation = xValidator->explainInvalid( xValidatable->getCurrentValue() );
3567 _rxFirstInvalidModel.set(xValidatable, css::uno::UNO_QUERY);
3568 return false;
3571 catch( const Exception& )
3573 DBG_UNHANDLED_EXCEPTION();
3575 return true;
3579 Reference< XControl > FormController::locateControl( const Reference< XControlModel >& _rxModel )
3583 Sequence< Reference< XControl > > aControls( getControls() );
3584 const Reference< XControl >* pControls = aControls.getConstArray();
3585 const Reference< XControl >* pControlsEnd = aControls.getConstArray() + aControls.getLength();
3587 for ( ; pControls != pControlsEnd; ++pControls )
3589 OSL_ENSURE( pControls->is(), "FormController::locateControl: NULL-control?" );
3590 if ( pControls->is() )
3592 if ( ( *pControls)->getModel() == _rxModel )
3593 return *pControls;
3596 OSL_FAIL( "FormController::locateControl: did not find a control for this model!" );
3598 catch( const Exception& )
3600 DBG_UNHANDLED_EXCEPTION();
3602 return NULL;
3606 namespace
3608 void displayErrorSetFocus( const OUString& _rMessage, const Reference< XControl >& _rxFocusControl, vcl::Window* _pDialogParent )
3610 SQLContext aError;
3611 aError.Message = SVX_RESSTR(RID_STR_WRITEERROR);
3612 aError.Details = _rMessage;
3613 displayException( aError, _pDialogParent );
3615 if ( _rxFocusControl.is() )
3617 Reference< XWindow > xControlWindow( _rxFocusControl, UNO_QUERY );
3618 OSL_ENSURE( xControlWindow.is(), "displayErrorSetFocus: invalid control!" );
3619 if ( xControlWindow.is() )
3620 xControlWindow->setFocus();
3624 bool lcl_shouldValidateRequiredFields_nothrow( const Reference< XInterface >& _rxForm )
3628 static const char s_sFormsCheckRequiredFields[] = "FormsCheckRequiredFields";
3630 // first, check whether the form has a property telling us the answer
3631 // this allows people to use the XPropertyContainer interface of a form to control
3632 // the behaviour on a per-form basis.
3633 Reference< XPropertySet > xFormProps( _rxForm, UNO_QUERY_THROW );
3634 Reference< XPropertySetInfo > xPSI( xFormProps->getPropertySetInfo() );
3635 if ( xPSI->hasPropertyByName( s_sFormsCheckRequiredFields ) )
3637 bool bShouldValidate = true;
3638 OSL_VERIFY( xFormProps->getPropertyValue( s_sFormsCheckRequiredFields ) >>= bShouldValidate );
3639 return bShouldValidate;
3642 // next, check the data source which created the connection
3643 Reference< XChild > xConnectionAsChild( xFormProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ), UNO_QUERY_THROW );
3644 Reference< XPropertySet > xDataSource( xConnectionAsChild->getParent(), UNO_QUERY );
3645 if ( !xDataSource.is() )
3646 // seldom (but possible): this is not a connection created by a data source
3647 return true;
3649 Reference< XPropertySet > xDataSourceSettings(
3650 xDataSource->getPropertyValue("Settings"),
3651 UNO_QUERY_THROW );
3653 bool bShouldValidate = true;
3654 OSL_VERIFY( xDataSourceSettings->getPropertyValue( s_sFormsCheckRequiredFields ) >>= bShouldValidate );
3655 return bShouldValidate;
3657 catch( const Exception& )
3659 DBG_UNHANDLED_EXCEPTION();
3662 return true;
3666 // XRowSetApproveListener
3668 sal_Bool SAL_CALL FormController::approveRowChange(const RowChangeEvent& _rEvent) throw( RuntimeException, std::exception )
3670 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3671 impl_checkDisposed_throw();
3673 ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
3674 bool bValid = true;
3675 if (aIter.hasMoreElements())
3677 RowChangeEvent aEvt( _rEvent );
3678 aEvt.Source = *this;
3679 bValid = static_cast<XRowSetApproveListener*>(aIter.next())->approveRowChange(aEvt);
3682 if ( !bValid )
3683 return bValid;
3685 if ( ( _rEvent.Action != RowChangeAction::INSERT )
3686 && ( _rEvent.Action != RowChangeAction::UPDATE )
3688 return bValid;
3690 // if some of the control models are bound to validators, check them
3691 OUString sInvalidityExplanation;
3692 Reference< XControlModel > xInvalidModel;
3693 if ( !checkFormComponentValidity( sInvalidityExplanation, xInvalidModel ) )
3695 Reference< XControl > xControl( locateControl( xInvalidModel ) );
3696 aGuard.clear();
3697 displayErrorSetFocus( sInvalidityExplanation, xControl, getDialogParentWindow() );
3698 return false;
3701 // check values on NULL and required flag
3702 if ( !lcl_shouldValidateRequiredFields_nothrow( _rEvent.Source ) )
3703 return sal_True;
3705 OSL_ENSURE( m_pColumnInfoCache.get(), "FormController::approveRowChange: no column infos!" );
3706 if ( !m_pColumnInfoCache.get() )
3707 return sal_True;
3711 if ( !m_pColumnInfoCache->controlsInitialized() )
3712 m_pColumnInfoCache->initializeControls( getControls() );
3714 size_t colCount = m_pColumnInfoCache->getColumnCount();
3715 for ( size_t col = 0; col < colCount; ++col )
3717 const ColumnInfo& rColInfo = m_pColumnInfoCache->getColumnInfo( col );
3718 if ( rColInfo.nNullable != ColumnValue::NO_NULLS )
3719 continue;
3721 if ( rColInfo.bAutoIncrement )
3722 continue;
3724 if ( rColInfo.bReadOnly )
3725 continue;
3727 if ( !rColInfo.xFirstControlWithInputRequired.is() && !rColInfo.xFirstGridWithInputRequiredColumn.is() )
3728 continue;
3730 // TODO: in case of binary fields, this "getString" below is extremely expensive
3731 if ( !rColInfo.xColumn->getString().isEmpty() || !rColInfo.xColumn->wasNull() )
3732 continue;
3734 OUString sMessage( SVX_RESSTR( RID_ERR_FIELDREQUIRED ) );
3735 sMessage = sMessage.replaceFirst( "#", rColInfo.sName );
3737 // the control to focus
3738 Reference< XControl > xControl( rColInfo.xFirstControlWithInputRequired );
3739 if ( !xControl.is() )
3740 xControl.set( rColInfo.xFirstGridWithInputRequiredColumn, UNO_QUERY );
3742 aGuard.clear();
3743 displayErrorSetFocus( sMessage, rColInfo.xFirstControlWithInputRequired, getDialogParentWindow() );
3744 return sal_False;
3747 catch( const Exception& )
3749 DBG_UNHANDLED_EXCEPTION();
3752 return true;
3756 sal_Bool SAL_CALL FormController::approveCursorMove(const EventObject& event) throw( RuntimeException, std::exception )
3758 ::osl::MutexGuard aGuard( m_aMutex );
3759 impl_checkDisposed_throw();
3761 ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
3762 if (aIter.hasMoreElements())
3764 EventObject aEvt(event);
3765 aEvt.Source = *this;
3766 return static_cast<XRowSetApproveListener*>(aIter.next())->approveCursorMove(aEvt);
3769 return sal_True;
3773 sal_Bool SAL_CALL FormController::approveRowSetChange(const EventObject& event) throw( RuntimeException, std::exception )
3775 ::osl::MutexGuard aGuard( m_aMutex );
3776 impl_checkDisposed_throw();
3778 ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
3779 if (aIter.hasMoreElements())
3781 EventObject aEvt(event);
3782 aEvt.Source = *this;
3783 return static_cast<XRowSetApproveListener*>(aIter.next())->approveRowSetChange(aEvt);
3786 return sal_True;
3789 // XRowSetApproveBroadcaster
3791 void SAL_CALL FormController::addRowSetApproveListener(const Reference< XRowSetApproveListener > & _rxListener) throw( RuntimeException, std::exception )
3793 ::osl::MutexGuard aGuard( m_aMutex );
3794 impl_checkDisposed_throw();
3796 m_aRowSetApproveListeners.addInterface(_rxListener);
3800 void SAL_CALL FormController::removeRowSetApproveListener(const Reference< XRowSetApproveListener > & _rxListener) throw( RuntimeException, std::exception )
3802 ::osl::MutexGuard aGuard( m_aMutex );
3803 impl_checkDisposed_throw();
3805 m_aRowSetApproveListeners.removeInterface(_rxListener);
3808 // XErrorListener
3810 void SAL_CALL FormController::errorOccured(const SQLErrorEvent& aEvent) throw( RuntimeException, std::exception )
3812 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3813 impl_checkDisposed_throw();
3815 ::cppu::OInterfaceIteratorHelper aIter(m_aErrorListeners);
3816 if (aIter.hasMoreElements())
3818 SQLErrorEvent aEvt(aEvent);
3819 aEvt.Source = *this;
3820 static_cast<XSQLErrorListener*>(aIter.next())->errorOccured(aEvt);
3822 else
3824 aGuard.clear();
3825 displayException( aEvent );
3829 // XErrorBroadcaster
3831 void SAL_CALL FormController::addSQLErrorListener(const Reference< XSQLErrorListener > & aListener) throw( RuntimeException, std::exception )
3833 ::osl::MutexGuard aGuard( m_aMutex );
3834 impl_checkDisposed_throw();
3836 m_aErrorListeners.addInterface(aListener);
3840 void SAL_CALL FormController::removeSQLErrorListener(const Reference< XSQLErrorListener > & aListener) throw( RuntimeException, std::exception )
3842 ::osl::MutexGuard aGuard( m_aMutex );
3843 impl_checkDisposed_throw();
3845 m_aErrorListeners.removeInterface(aListener);
3848 // XDatabaseParameterBroadcaster2
3850 void SAL_CALL FormController::addDatabaseParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException, std::exception )
3852 ::osl::MutexGuard aGuard( m_aMutex );
3853 impl_checkDisposed_throw();
3855 m_aParameterListeners.addInterface(aListener);
3859 void SAL_CALL FormController::removeDatabaseParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException, std::exception )
3861 ::osl::MutexGuard aGuard( m_aMutex );
3862 impl_checkDisposed_throw();
3864 m_aParameterListeners.removeInterface(aListener);
3867 // XDatabaseParameterBroadcaster
3869 void SAL_CALL FormController::addParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException, std::exception )
3871 FormController::addDatabaseParameterListener( aListener );
3875 void SAL_CALL FormController::removeParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException, std::exception )
3877 FormController::removeDatabaseParameterListener( aListener );
3880 // XDatabaseParameterListener
3882 sal_Bool SAL_CALL FormController::approveParameter(const DatabaseParameterEvent& aEvent) throw( RuntimeException, std::exception )
3884 SolarMutexGuard aSolarGuard;
3885 ::osl::MutexGuard aGuard( m_aMutex );
3886 impl_checkDisposed_throw();
3888 ::cppu::OInterfaceIteratorHelper aIter(m_aParameterListeners);
3889 if (aIter.hasMoreElements())
3891 DatabaseParameterEvent aEvt(aEvent);
3892 aEvt.Source = *this;
3893 return static_cast<XDatabaseParameterListener*>(aIter.next())->approveParameter(aEvt);
3895 else
3897 // default handling: instantiate an interaction handler and let it handle the parameter request
3900 if ( !ensureInteractionHandler() )
3901 return sal_False;
3903 // two continuations allowed: OK and Cancel
3904 OParameterContinuation* pParamValues = new OParameterContinuation;
3905 OInteractionAbort* pAbort = new OInteractionAbort;
3906 // the request
3907 ParametersRequest aRequest;
3908 aRequest.Parameters = aEvent.Parameters;
3909 aRequest.Connection = getConnection(Reference< XRowSet >(aEvent.Source, UNO_QUERY));
3910 OInteractionRequest* pParamRequest = new OInteractionRequest(makeAny(aRequest));
3911 Reference< XInteractionRequest > xParamRequest(pParamRequest);
3912 // some knittings
3913 pParamRequest->addContinuation(pParamValues);
3914 pParamRequest->addContinuation(pAbort);
3916 // handle the request
3917 m_xInteractionHandler->handle(xParamRequest);
3919 if (!pParamValues->wasSelected())
3920 // canceled
3921 return sal_False;
3923 // transfer the values into the parameter supplier
3924 Sequence< PropertyValue > aFinalValues = pParamValues->getValues();
3925 if (aFinalValues.getLength() != aRequest.Parameters->getCount())
3927 OSL_FAIL("FormController::approveParameter: the InteractionHandler returned nonsense!");
3928 return sal_False;
3930 const PropertyValue* pFinalValues = aFinalValues.getConstArray();
3931 for (sal_Int32 i=0; i<aFinalValues.getLength(); ++i, ++pFinalValues)
3933 Reference< XPropertySet > xParam(
3934 aRequest.Parameters->getByIndex(i), css::uno::UNO_QUERY);
3935 if (xParam.is())
3937 #ifdef DBG_UTIL
3938 OUString sName;
3939 xParam->getPropertyValue(FM_PROP_NAME) >>= sName;
3940 DBG_ASSERT(sName.equals(pFinalValues->Name), "FormController::approveParameter: suspicious value names!");
3941 #endif
3942 try { xParam->setPropertyValue(FM_PROP_VALUE, pFinalValues->Value); }
3943 catch(Exception&)
3945 OSL_FAIL("FormController::approveParameter: setting one of the properties failed!");
3950 catch(Exception&)
3952 DBG_UNHANDLED_EXCEPTION();
3955 return sal_True;
3958 // XConfirmDeleteBroadcaster
3960 void SAL_CALL FormController::addConfirmDeleteListener(const Reference< XConfirmDeleteListener > & aListener) throw( RuntimeException, std::exception )
3962 ::osl::MutexGuard aGuard( m_aMutex );
3963 impl_checkDisposed_throw();
3965 m_aDeleteListeners.addInterface(aListener);
3969 void SAL_CALL FormController::removeConfirmDeleteListener(const Reference< XConfirmDeleteListener > & aListener) throw( RuntimeException, std::exception )
3971 ::osl::MutexGuard aGuard( m_aMutex );
3972 impl_checkDisposed_throw();
3974 m_aDeleteListeners.removeInterface(aListener);
3977 // XConfirmDeleteListener
3979 sal_Bool SAL_CALL FormController::confirmDelete(const RowChangeEvent& aEvent) throw( RuntimeException, std::exception )
3981 ::osl::MutexGuard aGuard( m_aMutex );
3982 impl_checkDisposed_throw();
3984 ::cppu::OInterfaceIteratorHelper aIter(m_aDeleteListeners);
3985 if (aIter.hasMoreElements())
3987 RowChangeEvent aEvt(aEvent);
3988 aEvt.Source = *this;
3989 return static_cast<XConfirmDeleteListener*>(aIter.next())->confirmDelete(aEvt);
3991 // default handling: instantiate an interaction handler and let it handle the request
3993 OUString sTitle;
3994 sal_Int32 nLength = aEvent.Rows;
3995 if ( nLength > 1 )
3997 sTitle = SVX_RESSTR( RID_STR_DELETECONFIRM_RECORDS );
3998 sTitle = sTitle.replaceFirst( "#", OUString::number(nLength) );
4000 else
4001 sTitle = SVX_RESSTR( RID_STR_DELETECONFIRM_RECORD );
4005 if ( !ensureInteractionHandler() )
4006 return sal_False;
4008 // two continuations allowed: Yes and No
4009 OInteractionApprove* pApprove = new OInteractionApprove;
4010 OInteractionDisapprove* pDisapprove = new OInteractionDisapprove;
4012 // the request
4013 SQLWarning aWarning;
4014 aWarning.Message = sTitle;
4015 SQLWarning aDetails;
4016 aDetails.Message = SVX_RESSTR(RID_STR_DELETECONFIRM);
4017 aWarning.NextException <<= aDetails;
4019 OInteractionRequest* pRequest = new OInteractionRequest( makeAny( aWarning ) );
4020 Reference< XInteractionRequest > xRequest( pRequest );
4022 // some knittings
4023 pRequest->addContinuation( pApprove );
4024 pRequest->addContinuation( pDisapprove );
4026 // handle the request
4027 m_xInteractionHandler->handle( xRequest );
4029 if ( pApprove->wasSelected() )
4030 return sal_True;
4032 catch( const Exception& )
4034 DBG_UNHANDLED_EXCEPTION();
4037 return sal_False;
4041 void SAL_CALL FormController::invalidateFeatures( const Sequence< ::sal_Int16 >& _Features ) throw (RuntimeException, std::exception)
4043 ::osl::MutexGuard aGuard( m_aMutex );
4044 // for now, just copy the ids of the features, because ....
4045 ::std::copy( _Features.getConstArray(), _Features.getConstArray() + _Features.getLength(),
4046 ::std::insert_iterator< ::std::set< sal_Int16 > >( m_aInvalidFeatures, m_aInvalidFeatures.begin() )
4049 // ... we will do the real invalidation asynchronously
4050 if ( !m_aFeatureInvalidationTimer.IsActive() )
4051 m_aFeatureInvalidationTimer.Start();
4055 void SAL_CALL FormController::invalidateAllFeatures( ) throw (RuntimeException, std::exception)
4057 ::osl::ClearableMutexGuard aGuard( m_aMutex );
4059 Sequence< sal_Int16 > aInterceptedFeatures( m_aFeatureDispatchers.size() );
4060 ::std::transform(
4061 m_aFeatureDispatchers.begin(),
4062 m_aFeatureDispatchers.end(),
4063 aInterceptedFeatures.getArray(),
4064 ::o3tl::select1st< DispatcherContainer::value_type >()
4067 aGuard.clear();
4068 if ( aInterceptedFeatures.getLength() )
4069 invalidateFeatures( aInterceptedFeatures );
4073 Reference< XDispatch >
4074 FormController::interceptedQueryDispatch( const URL& aURL,
4075 const OUString& /*aTargetFrameName*/, sal_Int32 /*nSearchFlags*/)
4076 throw( RuntimeException )
4078 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
4079 Reference< XDispatch > xReturn;
4080 // dispatches handled by ourself
4081 if ( ( aURL.Complete == FMURL_CONFIRM_DELETION )
4082 || ( ( aURL.Complete == "private:/InteractionHandler" )
4083 && ensureInteractionHandler()
4086 xReturn = static_cast< XDispatch* >( this );
4088 // dispatches of FormSlot-URLs we have to translate
4089 if ( !xReturn.is() && m_xFormOperations.is() )
4091 // find the slot id which corresponds to the URL
4092 sal_Int32 nFeatureSlotId = svx::FeatureSlotTranslation::getControllerFeatureSlotIdForURL( aURL.Main );
4093 sal_Int16 nFormFeature = ( nFeatureSlotId != -1 ) ? svx::FeatureSlotTranslation::getFormFeatureForSlotId( nFeatureSlotId ) : -1;
4094 if ( nFormFeature > 0 )
4096 // get the dispatcher for this feature, create if necessary
4097 DispatcherContainer::const_iterator aDispatcherPos = m_aFeatureDispatchers.find( nFormFeature );
4098 if ( aDispatcherPos == m_aFeatureDispatchers.end() )
4100 aDispatcherPos = m_aFeatureDispatchers.insert(
4101 DispatcherContainer::value_type( nFormFeature, new svx::OSingleFeatureDispatcher( aURL, nFormFeature, m_xFormOperations, m_aMutex ) )
4102 ).first;
4105 OSL_ENSURE( aDispatcherPos->second.is(), "FormController::interceptedQueryDispatch: should have a dispatcher by now!" );
4106 return aDispatcherPos->second;
4110 // no more to offer
4111 return xReturn;
4115 void SAL_CALL FormController::dispatch( const URL& _rURL, const Sequence< PropertyValue >& _rArgs ) throw (RuntimeException, std::exception)
4117 if ( _rArgs.getLength() != 1 )
4119 OSL_FAIL( "FormController::dispatch: no arguments -> no dispatch!" );
4120 return;
4123 if ( _rURL.Complete == "private:/InteractionHandler" )
4125 Reference< XInteractionRequest > xRequest;
4126 OSL_VERIFY( _rArgs[0].Value >>= xRequest );
4127 if ( xRequest.is() )
4128 handle( xRequest );
4129 return;
4132 if ( _rURL.Complete == FMURL_CONFIRM_DELETION )
4134 OSL_FAIL( "FormController::dispatch: How do you expect me to return something via this call?" );
4135 // confirmDelete has a return value - dispatch hasn't
4136 return;
4139 OSL_FAIL( "FormController::dispatch: unknown URL!" );
4143 void SAL_CALL FormController::addStatusListener( const Reference< XStatusListener >& _rxListener, const URL& _rURL ) throw (RuntimeException, std::exception)
4145 if (_rURL.Complete == FMURL_CONFIRM_DELETION)
4147 if (_rxListener.is())
4148 { // send an initial statusChanged event
4149 FeatureStateEvent aEvent;
4150 aEvent.FeatureURL = _rURL;
4151 aEvent.IsEnabled = sal_True;
4152 _rxListener->statusChanged(aEvent);
4153 // and don't add the listener at all (the status will never change)
4156 else
4157 OSL_FAIL("FormController::addStatusListener: invalid (unsupported) URL!");
4161 Reference< XInterface > SAL_CALL FormController::getParent() throw( RuntimeException, std::exception )
4163 return m_xParent;
4167 void SAL_CALL FormController::setParent( const Reference< XInterface >& Parent) throw( NoSupportException, RuntimeException, std::exception )
4169 m_xParent = Parent;
4173 void SAL_CALL FormController::removeStatusListener( const Reference< XStatusListener >& /*_rxListener*/, const URL& _rURL ) throw (RuntimeException, std::exception)
4175 (void)_rURL;
4176 OSL_ENSURE(_rURL.Complete == FMURL_CONFIRM_DELETION, "FormController::removeStatusListener: invalid (unsupported) URL!");
4177 // we never really added the listener, so we don't need to remove it
4181 Reference< XDispatchProviderInterceptor > FormController::createInterceptor(const Reference< XDispatchProviderInterception > & _xInterception)
4183 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
4184 #ifdef DBG_UTIL
4185 // check if we already have a interceptor for the given object
4186 for ( Interceptors::const_iterator aIter = m_aControlDispatchInterceptors.begin();
4187 aIter != m_aControlDispatchInterceptors.end();
4188 ++aIter
4191 if ((*aIter)->getIntercepted() == _xInterception)
4192 OSL_FAIL("FormController::createInterceptor : we already do intercept this objects dispatches !");
4194 #endif
4196 DispatchInterceptionMultiplexer* pInterceptor = new DispatchInterceptionMultiplexer( _xInterception, this );
4197 pInterceptor->acquire();
4198 m_aControlDispatchInterceptors.insert( m_aControlDispatchInterceptors.end(), pInterceptor );
4200 return pInterceptor;
4204 bool FormController::ensureInteractionHandler()
4206 if ( m_xInteractionHandler.is() )
4207 return true;
4208 if ( m_bAttemptedHandlerCreation )
4209 return false;
4210 m_bAttemptedHandlerCreation = true;
4212 m_xInteractionHandler = InteractionHandler::createWithParent(m_xComponentContext, 0);
4213 return m_xInteractionHandler.is();
4217 void SAL_CALL FormController::handle( const Reference< XInteractionRequest >& _rRequest ) throw (RuntimeException, std::exception)
4219 if ( !ensureInteractionHandler() )
4220 return;
4221 m_xInteractionHandler->handle( _rRequest );
4225 void FormController::deleteInterceptor(const Reference< XDispatchProviderInterception > & _xInterception)
4227 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
4228 // search the interceptor responsible for the given object
4229 Interceptors::iterator aIter;
4230 for ( aIter = m_aControlDispatchInterceptors.begin();
4231 aIter != m_aControlDispatchInterceptors.end();
4232 ++aIter
4235 if ((*aIter)->getIntercepted() == _xInterception)
4236 break;
4238 if (aIter == m_aControlDispatchInterceptors.end())
4240 return;
4243 // log off the interception from it's interception object
4244 DispatchInterceptionMultiplexer* pInterceptorImpl = *aIter;
4245 pInterceptorImpl->dispose();
4246 pInterceptorImpl->release();
4248 // remove the interceptor from our array
4249 m_aControlDispatchInterceptors.erase(aIter);
4253 void FormController::implInvalidateCurrentControlDependentFeatures()
4255 Sequence< sal_Int16 > aCurrentControlDependentFeatures(4);
4257 aCurrentControlDependentFeatures[0] = FormFeature::SortAscending;
4258 aCurrentControlDependentFeatures[1] = FormFeature::SortDescending;
4259 aCurrentControlDependentFeatures[2] = FormFeature::AutoFilter;
4260 aCurrentControlDependentFeatures[3] = FormFeature::RefreshCurrentControl;
4262 invalidateFeatures( aCurrentControlDependentFeatures );
4266 void SAL_CALL FormController::columnChanged( const EventObject& /*_event*/ ) throw (RuntimeException, std::exception)
4268 implInvalidateCurrentControlDependentFeatures();
4273 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */