Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / svx / source / form / formcontroller.cxx
blob374bb29b54d3aa82ac61f1fe441ffa6f2a30f209
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include "fmcontrolbordermanager.hxx"
31 #include "fmcontrollayout.hxx"
32 #include "formcontroller.hxx"
33 #include "formfeaturedispatcher.hxx"
34 #include "fmdocumentclassification.hxx"
35 #include "formcontrolling.hxx"
36 #include "fmprop.hrc"
37 #include "svx/dialmgr.hxx"
38 #include "svx/fmresids.hrc"
39 #include "fmservs.hxx"
40 #include "svx/fmtools.hxx"
41 #include "fmurl.hxx"
43 /** === begin UNO includes === **/
44 #include <com/sun/star/awt/FocusChangeReason.hpp>
45 #include <com/sun/star/awt/XCheckBox.hpp>
46 #include <com/sun/star/awt/XComboBox.hpp>
47 #include <com/sun/star/awt/XListBox.hpp>
48 #include <com/sun/star/awt/XVclWindowPeer.hpp>
49 #include <com/sun/star/beans/NamedValue.hpp>
50 #include <com/sun/star/beans/PropertyAttribute.hpp>
51 #include <com/sun/star/container/XIdentifierReplace.hpp>
52 #include <com/sun/star/form/TabulatorCycle.hpp>
53 #include <com/sun/star/form/validation/XValidatableFormComponent.hpp>
54 #include <com/sun/star/form/XBoundComponent.hpp>
55 #include <com/sun/star/form/XBoundControl.hpp>
56 #include <com/sun/star/form/XGridControl.hpp>
57 #include <com/sun/star/form/XLoadable.hpp>
58 #include <com/sun/star/form/XReset.hpp>
59 #include <com/sun/star/frame/XController.hpp>
60 #include <com/sun/star/sdb/ParametersRequest.hpp>
61 #include <com/sun/star/sdb/RowChangeAction.hpp>
62 #include <com/sun/star/sdb/XInteractionSupplyParameters.hpp>
63 #include <com/sun/star/sdbc/ColumnValue.hpp>
64 #include <com/sun/star/sdbc/DataType.hpp>
65 #include <com/sun/star/util/XURLTransformer.hpp>
66 #include <com/sun/star/form/runtime/FormOperations.hpp>
67 #include <com/sun/star/form/runtime/FormFeature.hpp>
68 #include <com/sun/star/container/XContainer.hpp>
69 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
70 #include <com/sun/star/util/XNumberFormatter.hpp>
71 #include <com/sun/star/sdb/SQLContext.hpp>
72 #include <com/sun/star/sdb/XColumn.hpp>
73 /** === end UNO includes === **/
75 #include <comphelper/enumhelper.hxx>
76 #include <comphelper/extract.hxx>
77 #include <comphelper/interaction.hxx>
78 #include <comphelper/namedvaluecollection.hxx>
79 #include <comphelper/propagg.hxx>
80 #include <comphelper/property.hxx>
81 #include <comphelper/sequence.hxx>
82 #include <comphelper/uno3.hxx>
83 #include <comphelper/flagguard.hxx>
84 #include <cppuhelper/queryinterface.hxx>
85 #include <cppuhelper/typeprovider.hxx>
86 #include <toolkit/controls/unocontrol.hxx>
87 #include <toolkit/helper/vclunohelper.hxx>
88 #include <tools/debug.hxx>
89 #include <tools/diagnose_ex.h>
90 #include <tools/shl.hxx>
91 #include <vcl/msgbox.hxx>
92 #include <vcl/svapp.hxx>
93 #include <osl/mutex.hxx>
94 #include <rtl/logfile.hxx>
96 #include <algorithm>
98 #include <o3tl/compat_functional.hxx>
100 using namespace ::com::sun::star;
101 using namespace ::comphelper;
102 using namespace ::connectivity;
103 using namespace ::connectivity::simple;
105 //------------------------------------------------------------------
106 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL
107 FormController_NewInstance_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & _rxORB )
109 return *( new ::svxform::FormController( _rxORB ) );
112 namespace svxform
115 /** === begin UNO using === **/
116 using ::com::sun::star::sdb::XColumn;
117 using ::com::sun::star::awt::XControl;
118 using ::com::sun::star::awt::XTabController;
119 using ::com::sun::star::awt::XToolkit;
120 using ::com::sun::star::awt::XWindowPeer;
121 using ::com::sun::star::form::XGrid;
122 using ::com::sun::star::beans::XPropertySet;
123 using ::com::sun::star::uno::UNO_SET_THROW;
124 using ::com::sun::star::uno::UNO_QUERY_THROW;
125 using ::com::sun::star::container::XIndexAccess;
126 using ::com::sun::star::uno::Exception;
127 using ::com::sun::star::uno::XInterface;
128 using ::com::sun::star::uno::UNO_QUERY;
129 using ::com::sun::star::uno::Sequence;
130 using ::com::sun::star::uno::Reference;
131 using ::com::sun::star::beans::XPropertySetInfo;
132 using ::com::sun::star::beans::PropertyValue;
133 using ::com::sun::star::uno::RuntimeException;
134 using ::com::sun::star::lang::IndexOutOfBoundsException;
135 using ::com::sun::star::sdb::XInteractionSupplyParameters;
136 using ::com::sun::star::awt::XTextComponent;
137 using ::com::sun::star::awt::XTextListener;
138 using ::com::sun::star::uno::Any;
139 using ::com::sun::star::frame::XDispatch;
140 using ::com::sun::star::lang::XMultiServiceFactory;
141 using ::com::sun::star::uno::XAggregation;
142 using ::com::sun::star::uno::Type;
143 using ::com::sun::star::lang::IllegalArgumentException;
144 using ::com::sun::star::sdbc::XConnection;
145 using ::com::sun::star::sdbc::XRowSet;
146 using ::com::sun::star::sdbc::XDatabaseMetaData;
147 using ::com::sun::star::util::XNumberFormatsSupplier;
148 using ::com::sun::star::util::XNumberFormatter;
149 using ::com::sun::star::sdbcx::XColumnsSupplier;
150 using ::com::sun::star::container::XNameAccess;
151 using ::com::sun::star::lang::EventObject;
152 using ::com::sun::star::beans::Property;
153 using ::com::sun::star::container::XEnumeration;
154 using ::com::sun::star::form::XFormComponent;
155 using ::com::sun::star::form::runtime::XFormOperations;
156 using ::com::sun::star::form::runtime::FilterEvent;
157 using ::com::sun::star::form::runtime::XFilterControllerListener;
158 using ::com::sun::star::awt::XControlContainer;
159 using ::com::sun::star::container::XIdentifierReplace;
160 using ::com::sun::star::lang::WrappedTargetException;
161 using ::com::sun::star::form::XFormControllerListener;
162 using ::com::sun::star::awt::XWindow;
163 using ::com::sun::star::sdbc::XResultSet;
164 using ::com::sun::star::awt::XControlModel;
165 using ::com::sun::star::awt::XTabControllerModel;
166 using ::com::sun::star::beans::PropertyChangeEvent;
167 using ::com::sun::star::form::validation::XValidatableFormComponent;
168 using ::com::sun::star::form::XLoadable;
169 using ::com::sun::star::script::XEventAttacherManager;
170 using ::com::sun::star::form::XBoundControl;
171 using ::com::sun::star::beans::XPropertyChangeListener;
172 using ::com::sun::star::awt::TextEvent;
173 using ::com::sun::star::form::XBoundComponent;
174 using ::com::sun::star::awt::XCheckBox;
175 using ::com::sun::star::awt::XComboBox;
176 using ::com::sun::star::awt::XListBox;
177 using ::com::sun::star::awt::ItemEvent;
178 using ::com::sun::star::util::XModifyListener;
179 using ::com::sun::star::form::XReset;
180 using ::com::sun::star::frame::XDispatchProviderInterception;
181 using ::com::sun::star::form::XGridControl;
182 using ::com::sun::star::awt::XVclWindowPeer;
183 using ::com::sun::star::form::validation::XValidator;
184 using ::com::sun::star::awt::FocusEvent;
185 using ::com::sun::star::sdb::SQLContext;
186 using ::com::sun::star::container::XChild;
187 using ::com::sun::star::form::TabulatorCycle_RECORDS;
188 using ::com::sun::star::container::ContainerEvent;
189 using ::com::sun::star::lang::DisposedException;
190 using ::com::sun::star::lang::Locale;
191 using ::com::sun::star::beans::NamedValue;
192 using ::com::sun::star::lang::NoSupportException;
193 using ::com::sun::star::sdb::RowChangeEvent;
194 using ::com::sun::star::frame::XStatusListener;
195 using ::com::sun::star::frame::XDispatchProviderInterceptor;
196 using ::com::sun::star::sdb::SQLErrorEvent;
197 using ::com::sun::star::form::DatabaseParameterEvent;
198 using ::com::sun::star::sdb::ParametersRequest;
199 using ::com::sun::star::task::XInteractionRequest;
200 using ::com::sun::star::util::URL;
201 using ::com::sun::star::frame::FeatureStateEvent;
202 using ::com::sun::star::form::runtime::XFormControllerContext;
203 using ::com::sun::star::task::XInteractionHandler;
204 using ::com::sun::star::form::runtime::FormOperations;
205 using ::com::sun::star::container::XContainer;
206 using ::com::sun::star::sdbc::SQLWarning;
207 /** === end UNO using === **/
208 namespace ColumnValue = ::com::sun::star::sdbc::ColumnValue;
209 namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
210 namespace FocusChangeReason = ::com::sun::star::awt::FocusChangeReason;
211 namespace RowChangeAction = ::com::sun::star::sdb::RowChangeAction;
212 namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
213 namespace DataType = ::com::sun::star::sdbc::DataType;
215 //==============================================================================
216 // ColumnInfo
217 //==============================================================================
218 struct ColumnInfo
220 // information about the column itself
221 Reference< XColumn > xColumn;
222 sal_Int32 nNullable;
223 sal_Bool bAutoIncrement;
224 sal_Bool bReadOnly;
225 ::rtl::OUString sName;
227 // information about the control(s) bound to this column
229 /// the first control which is bound to the given column, and which requires input
230 Reference< XControl > xFirstControlWithInputRequired;
231 /** the first grid control which contains a column which is bound to the given database column, and requires
232 input
234 Reference< XGrid > xFirstGridWithInputRequiredColumn;
235 /** if xFirstControlWithInputRequired is a grid control, then nRequiredGridColumn specifies the position
236 of the grid column which is actually bound
238 sal_Int32 nRequiredGridColumn;
240 ColumnInfo()
241 :xColumn()
242 ,nNullable( ColumnValue::NULLABLE_UNKNOWN )
243 ,bAutoIncrement( sal_False )
244 ,bReadOnly( sal_False )
245 ,sName()
246 ,xFirstControlWithInputRequired()
247 ,xFirstGridWithInputRequiredColumn()
248 ,nRequiredGridColumn( -1 )
253 //==============================================================================
254 //= ColumnInfoCache
255 //==============================================================================
256 class ColumnInfoCache
258 public:
259 ColumnInfoCache( const Reference< XColumnsSupplier >& _rxColSupplier );
261 size_t getColumnCount() const { return m_aColumns.size(); }
262 const ColumnInfo& getColumnInfo( size_t _pos );
264 bool controlsInitialized() const { return m_bControlsInitialized; }
265 void initializeControls( const Sequence< Reference< XControl > >& _rControls );
266 void deinitializeControls();
268 private:
269 typedef ::std::vector< ColumnInfo > ColumnInfos;
270 ColumnInfos m_aColumns;
271 bool m_bControlsInitialized;
274 //------------------------------------------------------------------------------
275 ColumnInfoCache::ColumnInfoCache( const Reference< XColumnsSupplier >& _rxColSupplier )
276 :m_aColumns()
277 ,m_bControlsInitialized( false )
281 m_aColumns.clear();
283 Reference< XColumnsSupplier > xSupplyCols( _rxColSupplier, UNO_SET_THROW );
284 Reference< XIndexAccess > xColumns( xSupplyCols->getColumns(), UNO_QUERY_THROW );
285 sal_Int32 nColumnCount = xColumns->getCount();
286 m_aColumns.reserve( nColumnCount );
288 Reference< XPropertySet > xColumnProps;
289 for ( sal_Int32 i = 0; i < nColumnCount; ++i )
291 ColumnInfo aColInfo;
292 aColInfo.xColumn.set( xColumns->getByIndex(i), UNO_QUERY_THROW );
294 xColumnProps.set( aColInfo.xColumn, UNO_QUERY_THROW );
295 OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_ISNULLABLE ) >>= aColInfo.nNullable );
296 OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_AUTOINCREMENT ) >>= aColInfo.bAutoIncrement );
297 OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_NAME ) >>= aColInfo.sName );
298 OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_ISREADONLY ) >>= aColInfo.bReadOnly );
300 m_aColumns.push_back( aColInfo );
303 catch( const Exception& )
305 DBG_UNHANDLED_EXCEPTION();
309 //------------------------------------------------------------------------------
310 namespace
312 bool lcl_isBoundTo( const Reference< XPropertySet >& _rxControlModel, const Reference< XInterface >& _rxNormDBField )
314 Reference< XInterface > xNormBoundField( _rxControlModel->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY );
315 return ( xNormBoundField.get() == _rxNormDBField.get() );
318 bool lcl_isInputRequired( const Reference< XPropertySet >& _rxControlModel )
320 sal_Bool bInputRequired = sal_True;
321 OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_INPUT_REQUIRED ) >>= bInputRequired );
322 return ( bInputRequired != sal_False );
325 void lcl_resetColumnControlInfo( ColumnInfo& _rColInfo )
327 _rColInfo.xFirstControlWithInputRequired.clear();
328 _rColInfo.xFirstGridWithInputRequiredColumn.clear();
329 _rColInfo.nRequiredGridColumn = -1;
333 //------------------------------------------------------------------------------
334 void ColumnInfoCache::deinitializeControls()
336 for ( ColumnInfos::iterator col = m_aColumns.begin();
337 col != m_aColumns.end();
338 ++col
341 lcl_resetColumnControlInfo( *col );
345 //------------------------------------------------------------------------------
346 void ColumnInfoCache::initializeControls( const Sequence< Reference< XControl > >& _rControls )
350 // for every of our known columns, find the controls which are bound to this column
351 for ( ColumnInfos::iterator col = m_aColumns.begin();
352 col != m_aColumns.end();
353 ++col
356 OSL_ENSURE( !col->xFirstControlWithInputRequired.is() && !col->xFirstGridWithInputRequiredColumn.is()
357 && ( col->nRequiredGridColumn == -1 ), "ColumnInfoCache::initializeControls: called me twice?" );
359 lcl_resetColumnControlInfo( *col );
361 Reference< XInterface > xNormColumn( col->xColumn, UNO_QUERY_THROW );
363 const Reference< XControl >* pControl( _rControls.getConstArray() );
364 const Reference< XControl >* pControlEnd( pControl + _rControls.getLength() );
365 for ( ; pControl != pControlEnd; ++pControl )
367 if ( !pControl->is() )
368 continue;
370 Reference< XPropertySet > xModel( (*pControl)->getModel(), UNO_QUERY_THROW );
371 Reference< XPropertySetInfo > xModelPSI( xModel->getPropertySetInfo(), UNO_SET_THROW );
373 // special handling for grid controls
374 Reference< XGrid > xGrid( *pControl, UNO_QUERY );
375 if ( xGrid.is() )
377 Reference< XIndexAccess > xGridColAccess( xModel, UNO_QUERY_THROW );
378 sal_Int32 gridColCount = xGridColAccess->getCount();
379 sal_Int32 gridCol = 0;
380 for ( gridCol = 0; gridCol < gridColCount; ++gridCol )
382 Reference< XPropertySet > xGridColumnModel( xGridColAccess->getByIndex( gridCol ), UNO_QUERY_THROW );
384 if ( !lcl_isBoundTo( xGridColumnModel, xNormColumn )
385 || !lcl_isInputRequired( xGridColumnModel )
387 continue; // with next grid column
389 break;
392 if ( gridCol < gridColCount )
394 // found a grid column which is bound to the given
395 col->xFirstGridWithInputRequiredColumn = xGrid;
396 col->nRequiredGridColumn = gridCol;
397 break;
400 continue; // with next control
403 if ( !xModelPSI->hasPropertyByName( FM_PROP_BOUNDFIELD )
404 || !lcl_isBoundTo( xModel, xNormColumn )
405 || !lcl_isInputRequired( xModel )
407 continue; // with next control
409 break;
412 if ( pControl == pControlEnd )
413 // did not find a control which is bound to this particular column, and for which the input is required
414 continue; // with next DB column
416 col->xFirstControlWithInputRequired = *pControl;
419 catch( const Exception& )
421 DBG_UNHANDLED_EXCEPTION();
424 m_bControlsInitialized = true;
427 //------------------------------------------------------------------------------
428 const ColumnInfo& ColumnInfoCache::getColumnInfo( size_t _pos )
430 if ( _pos >= m_aColumns.size() )
431 throw IndexOutOfBoundsException();
433 return m_aColumns[ _pos ];
436 //==================================================================
437 // OParameterContinuation
438 //==================================================================
439 class OParameterContinuation : public OInteraction< XInteractionSupplyParameters >
441 Sequence< PropertyValue > m_aValues;
443 public:
444 OParameterContinuation() { }
446 Sequence< PropertyValue > getValues() const { return m_aValues; }
448 // XInteractionSupplyParameters
449 virtual void SAL_CALL setParameters( const Sequence< PropertyValue >& _rValues ) throw(RuntimeException);
452 //------------------------------------------------------------------
453 void SAL_CALL OParameterContinuation::setParameters( const Sequence< PropertyValue >& _rValues ) throw(RuntimeException)
455 m_aValues = _rValues;
458 //==================================================================
459 // FmXAutoControl
460 //==================================================================
461 struct FmFieldInfo
463 rtl::OUString aFieldName;
464 Reference< XPropertySet > xField;
465 Reference< XTextComponent > xText;
467 FmFieldInfo(const Reference< XPropertySet >& _xField, const Reference< XTextComponent >& _xText)
468 :xField(_xField)
469 ,xText(_xText)
470 {xField->getPropertyValue(FM_PROP_NAME) >>= aFieldName;}
473 //==================================================================
474 // FmXAutoControl
475 //==================================================================
476 class FmXAutoControl: public UnoControl
479 friend Reference< XInterface > SAL_CALL FmXAutoControl_NewInstance_Impl();
481 public:
482 FmXAutoControl( const ::comphelper::ComponentContext& i_context )
483 :UnoControl( i_context.getLegacyServiceFactory() )
487 virtual ::rtl::OUString GetComponentServiceName() {return ::rtl::OUString("Edit");}
488 virtual void SAL_CALL createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) throw( RuntimeException );
490 protected:
491 virtual void ImplSetPeerProperty( const ::rtl::OUString& rPropName, const Any& rVal );
494 //------------------------------------------------------------------------------
495 void FmXAutoControl::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) throw( RuntimeException )
497 UnoControl::createPeer( rxToolkit, rParentPeer );
499 Reference< XTextComponent > xText(getPeer() , UNO_QUERY);
500 if (xText.is())
502 xText->setText(::rtl::OUString(String(SVX_RES(RID_STR_AUTOFIELD))));
503 xText->setEditable(sal_False);
507 //------------------------------------------------------------------------------
508 void FmXAutoControl::ImplSetPeerProperty( const ::rtl::OUString& rPropName, const Any& rVal )
510 // these properties are ignored
511 if (rPropName == FM_PROP_TEXT)
512 return;
514 UnoControl::ImplSetPeerProperty( rPropName, rVal );
517 //------------------------------------------------------------------------------
518 IMPL_LINK( FormController, OnActivateTabOrder, void*, /*EMPTYTAG*/ )
520 activateTabOrder();
521 return 1;
524 //------------------------------------------------------------------------------
525 struct UpdateAllListeners : public ::std::unary_function< Reference< XDispatch >, bool >
527 bool operator()( const Reference< XDispatch >& _rxDispatcher ) const
529 static_cast< ::svx::OSingleFeatureDispatcher* >( _rxDispatcher.get() )->updateAllListeners();
530 // the return is a dummy only so we can use this struct in a o3tl::compose1 call
531 return true;
534 //..............................................................................
535 IMPL_LINK( FormController, OnInvalidateFeatures, void*, /*_pNotInterestedInThisParam*/ )
537 ::osl::MutexGuard aGuard( m_aMutex );
538 for ( ::std::set< sal_Int16 >::const_iterator aLoop = m_aInvalidFeatures.begin();
539 aLoop != m_aInvalidFeatures.end();
540 ++aLoop
543 DispatcherContainer::const_iterator aDispatcherPos = m_aFeatureDispatchers.find( *aLoop );
544 if ( aDispatcherPos != m_aFeatureDispatchers.end() )
546 // TODO: for the real and actual listener notifications, we should release
547 // our mutex
548 UpdateAllListeners( )( aDispatcherPos->second );
551 return 1;
554 /*************************************************************************/
556 DBG_NAME( FormController )
557 //------------------------------------------------------------------
558 FormController::FormController(const Reference< XMultiServiceFactory > & _rxORB )
559 :FormController_BASE( m_aMutex )
560 ,OPropertySetHelper( FormController_BASE::rBHelper )
561 ,OSQLParserClient( _rxORB )
562 ,m_aContext( _rxORB )
563 ,m_aActivateListeners(m_aMutex)
564 ,m_aModifyListeners(m_aMutex)
565 ,m_aErrorListeners(m_aMutex)
566 ,m_aDeleteListeners(m_aMutex)
567 ,m_aRowSetApproveListeners(m_aMutex)
568 ,m_aParameterListeners(m_aMutex)
569 ,m_aFilterListeners(m_aMutex)
570 ,m_pControlBorderManager( new ::svxform::ControlBorderManager )
571 ,m_xFormOperations()
572 ,m_aMode( ::rtl::OUString( "DataMode" ) )
573 ,m_aLoadEvent( LINK( this, FormController, OnLoad ) )
574 ,m_aToggleEvent( LINK( this, FormController, OnToggleAutoFields ) )
575 ,m_aActivationEvent( LINK( this, FormController, OnActivated ) )
576 ,m_aDeactivationEvent( LINK( this, FormController, OnDeactivated ) )
577 ,m_nCurrentFilterPosition(-1)
578 ,m_bCurrentRecordModified(sal_False)
579 ,m_bCurrentRecordNew(sal_False)
580 ,m_bLocked(sal_False)
581 ,m_bDBConnection(sal_False)
582 ,m_bCycle(sal_False)
583 ,m_bCanInsert(sal_False)
584 ,m_bCanUpdate(sal_False)
585 ,m_bCommitLock(sal_False)
586 ,m_bModified(sal_False)
587 ,m_bControlsSorted(sal_False)
588 ,m_bFiltering(sal_False)
589 ,m_bAttachEvents(sal_True)
590 ,m_bDetachEvents(sal_True)
591 ,m_bAttemptedHandlerCreation( false )
592 ,m_bSuspendFilterTextListening( false )
594 DBG_CTOR( FormController, NULL );
596 ::comphelper::increment(m_refCount);
599 m_xAggregate = Reference< XAggregation >(
600 m_aContext.createComponent( "com.sun.star.awt.TabController" ),
601 UNO_QUERY
603 DBG_ASSERT( m_xAggregate.is(), "FormController::FormController : could not create my aggregate !" );
604 m_xTabController = Reference< XTabController >( m_xAggregate, UNO_QUERY );
607 if ( m_xAggregate.is() )
608 m_xAggregate->setDelegator( *this );
610 ::comphelper::decrement(m_refCount);
612 m_aTabActivationTimer.SetTimeout( 500 );
613 m_aTabActivationTimer.SetTimeoutHdl( LINK( this, FormController, OnActivateTabOrder ) );
615 m_aFeatureInvalidationTimer.SetTimeout( 200 );
616 m_aFeatureInvalidationTimer.SetTimeoutHdl( LINK( this, FormController, OnInvalidateFeatures ) );
619 //------------------------------------------------------------------
620 FormController::~FormController()
623 ::osl::MutexGuard aGuard( m_aMutex );
625 m_aLoadEvent.CancelPendingCall();
626 m_aToggleEvent.CancelPendingCall();
627 m_aActivationEvent.CancelPendingCall();
628 m_aDeactivationEvent.CancelPendingCall();
630 if ( m_aTabActivationTimer.IsActive() )
631 m_aTabActivationTimer.Stop();
634 if ( m_aFeatureInvalidationTimer.IsActive() )
635 m_aFeatureInvalidationTimer.Stop();
637 disposeAllFeaturesAndDispatchers();
639 if ( m_xFormOperations.is() )
640 m_xFormOperations->dispose();
641 m_xFormOperations.clear();
643 // Freigeben der Aggregation
644 if ( m_xAggregate.is() )
646 m_xAggregate->setDelegator( NULL );
647 m_xAggregate.clear();
650 DELETEZ( m_pControlBorderManager );
652 DBG_DTOR( FormController, NULL );
655 // -----------------------------------------------------------------------------
656 void SAL_CALL FormController::acquire() throw ()
658 FormController_BASE::acquire();
661 // -----------------------------------------------------------------------------
662 void SAL_CALL FormController::release() throw ()
664 FormController_BASE::release();
667 //------------------------------------------------------------------
668 Any SAL_CALL FormController::queryInterface( const Type& _rType ) throw(RuntimeException)
670 Any aRet = FormController_BASE::queryInterface( _rType );
671 if ( !aRet.hasValue() )
672 aRet = OPropertySetHelper::queryInterface( _rType );
673 if ( !aRet.hasValue() )
674 aRet = m_xAggregate->queryAggregation( _rType );
675 return aRet;
678 //------------------------------------------------------------------------------
679 Sequence< sal_Int8 > SAL_CALL FormController::getImplementationId() throw( RuntimeException )
681 static ::cppu::OImplementationId* pId = NULL;
682 if ( !pId )
684 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
685 if ( !pId )
687 static ::cppu::OImplementationId aId;
688 pId = &aId;
691 return pId->getImplementationId();
694 //------------------------------------------------------------------------------
695 Sequence< Type > SAL_CALL FormController::getTypes( ) throw(RuntimeException)
697 return comphelper::concatSequences(
698 FormController_BASE::getTypes(),
699 ::cppu::OPropertySetHelper::getTypes()
703 // XServiceInfo
704 //------------------------------------------------------------------------------
705 sal_Bool SAL_CALL FormController::supportsService(const ::rtl::OUString& ServiceName) throw( RuntimeException )
707 Sequence< ::rtl::OUString> aSNL(getSupportedServiceNames());
708 const ::rtl::OUString * pArray = aSNL.getConstArray();
709 for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
710 if( pArray[i] == ServiceName )
711 return sal_True;
712 return sal_False;
715 //------------------------------------------------------------------------------
716 ::rtl::OUString SAL_CALL FormController::getImplementationName() throw( RuntimeException )
718 return ::rtl::OUString("org.openoffice.comp.svx.FormController");
721 //------------------------------------------------------------------------------
722 Sequence< ::rtl::OUString> SAL_CALL FormController::getSupportedServiceNames(void) throw( RuntimeException )
724 // service names which are supported only, but cannot be used to created an
725 // instance at a service factory
726 Sequence< ::rtl::OUString > aNonCreatableServiceNames( 1 );
727 aNonCreatableServiceNames[ 0 ] = ::rtl::OUString( "com.sun.star.form.FormControllerDispatcher" );
729 // services which can be used to created an instance at a service factory
730 Sequence< ::rtl::OUString > aCreatableServiceNames( getSupportedServiceNames_Static() );
731 return ::comphelper::concatSequences( aCreatableServiceNames, aNonCreatableServiceNames );
734 //------------------------------------------------------------------------------
735 sal_Bool SAL_CALL FormController::approveReset(const EventObject& /*rEvent*/) throw( RuntimeException )
737 return sal_True;
740 //------------------------------------------------------------------------------
741 void SAL_CALL FormController::resetted(const EventObject& rEvent) throw( RuntimeException )
743 ::osl::MutexGuard aGuard(m_aMutex);
744 if (getCurrentControl().is() && (getCurrentControl()->getModel() == rEvent.Source))
745 m_bModified = sal_False;
748 //------------------------------------------------------------------------------
749 Sequence< ::rtl::OUString> FormController::getSupportedServiceNames_Static(void)
751 static Sequence< ::rtl::OUString> aServices;
752 if (!aServices.getLength())
754 aServices.realloc(2);
755 aServices.getArray()[0] = FM_FORM_CONTROLLER;
756 aServices.getArray()[1] = ::rtl::OUString("com.sun.star.awt.control.TabController");
758 return aServices;
761 // -----------------------------------------------------------------------------
762 namespace
764 struct ResetComponentText : public ::std::unary_function< Reference< XTextComponent >, void >
766 void operator()( const Reference< XTextComponent >& _rxText )
768 _rxText->setText( ::rtl::OUString() );
772 struct RemoveComponentTextListener : public ::std::unary_function< Reference< XTextComponent >, void >
774 RemoveComponentTextListener( const Reference< XTextListener >& _rxListener )
775 :m_xListener( _rxListener )
779 void operator()( const Reference< XTextComponent >& _rxText )
781 _rxText->removeTextListener( m_xListener );
784 private:
785 Reference< XTextListener > m_xListener;
789 // -----------------------------------------------------------------------------
790 void FormController::impl_setTextOnAllFilter_throw()
792 m_bSuspendFilterTextListening = true;
793 ::comphelper::FlagGuard aResetFlag( m_bSuspendFilterTextListening );
795 // reset the text for all controls
796 ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), ResetComponentText() );
798 if ( m_aFilterRows.empty() )
799 // nothing to do anymore
800 return;
802 if ( m_nCurrentFilterPosition < 0 )
803 return;
805 // set the text for all filters
806 OSL_ENSURE( m_aFilterRows.size() > (size_t)m_nCurrentFilterPosition,
807 "FormController::impl_setTextOnAllFilter_throw: m_nCurrentFilterPosition too big" );
809 if ( (size_t)m_nCurrentFilterPosition < m_aFilterRows.size() )
811 FmFilterRow& rRow = m_aFilterRows[ m_nCurrentFilterPosition ];
812 for ( FmFilterRow::const_iterator iter2 = rRow.begin();
813 iter2 != rRow.end();
814 ++iter2
817 iter2->first->setText( iter2->second );
821 // OPropertySetHelper
822 //------------------------------------------------------------------------------
823 sal_Bool FormController::convertFastPropertyValue( Any & /*rConvertedValue*/, Any & /*rOldValue*/,
824 sal_Int32 /*nHandle*/, const Any& /*rValue*/ )
825 throw( IllegalArgumentException )
827 return sal_False;
830 //------------------------------------------------------------------------------
831 void FormController::setFastPropertyValue_NoBroadcast( sal_Int32 /*nHandle*/, const Any& /*rValue*/ )
832 throw( Exception )
836 //------------------------------------------------------------------------------
837 void FormController::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
839 switch (nHandle)
841 case FM_ATTR_FILTER:
843 ::rtl::OUStringBuffer aFilter;
844 OStaticDataAccessTools aStaticTools;
845 Reference<XConnection> xConnection(aStaticTools.getRowSetConnection(Reference< XRowSet>(m_xModelAsIndex, UNO_QUERY)));
846 if (xConnection.is())
848 Reference< XDatabaseMetaData> xMetaData(xConnection->getMetaData());
849 Reference< XNumberFormatsSupplier> xFormatSupplier( aStaticTools.getNumberFormats( xConnection, sal_True ) );
850 Reference< XNumberFormatter> xFormatter( m_aContext.createComponent( "com.sun.star.util.NumberFormatter" ), UNO_QUERY_THROW );
851 xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
853 Reference< XColumnsSupplier> xSupplyCols(m_xModelAsIndex, UNO_QUERY);
854 Reference< XNameAccess> xFields(xSupplyCols->getColumns(), UNO_QUERY);
856 ::rtl::OUString aQuote( xMetaData->getIdentifierQuoteString() );
858 // now add the filter rows
861 for ( FmFilterRows::const_iterator row = m_aFilterRows.begin(); row != m_aFilterRows.end(); ++row )
863 const FmFilterRow& rRow = *row;
865 if ( rRow.empty() )
866 continue;
868 ::rtl::OUStringBuffer aRowFilter;
869 for ( FmFilterRow::const_iterator condition = rRow.begin(); condition != rRow.end(); ++condition )
871 // get the field of the controls map
872 Reference< XControl > xControl( condition->first, UNO_QUERY_THROW );
873 Reference< XPropertySet > xModelProps( xControl->getModel(), UNO_QUERY_THROW );
874 Reference< XPropertySet > xField( xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY_THROW );
876 ::rtl::OUString sFilterValue( condition->second );
878 ::rtl::OUString sErrorMsg, sCriteria;
879 const ::rtl::Reference< ISQLParseNode > xParseNode =
880 predicateTree( sErrorMsg, sFilterValue, xFormatter, xField );
881 OSL_ENSURE( xParseNode.is(), "FormController::getFastPropertyValue: could not parse the field value predicate!" );
882 if ( xParseNode.is() )
884 // don't use a parse context here, we need it unlocalized
885 xParseNode->parseNodeToStr( sCriteria, xConnection, NULL );
886 if ( condition != rRow.begin() )
887 aRowFilter.appendAscii( " AND " );
888 aRowFilter.append( sCriteria );
891 if ( aRowFilter.getLength() > 0 )
893 if ( aFilter.getLength() )
894 aFilter.appendAscii( " OR " );
896 aFilter.appendAscii( "( " );
897 aFilter.append( aRowFilter.makeStringAndClear() );
898 aFilter.appendAscii( " )" );
902 catch( const Exception& )
904 DBG_UNHANDLED_EXCEPTION();
905 aFilter.setLength(0);
908 rValue <<= aFilter.makeStringAndClear();
910 break;
912 case FM_ATTR_FORM_OPERATIONS:
913 rValue <<= m_xFormOperations;
914 break;
918 //------------------------------------------------------------------------------
919 Reference< XPropertySetInfo > FormController::getPropertySetInfo() throw( RuntimeException )
921 static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
922 return xInfo;
925 //------------------------------------------------------------------------------
926 #define DECL_PROP_CORE(varname, type) \
927 pDesc[nPos++] = Property(FM_PROP_##varname, FM_ATTR_##varname, ::getCppuType((const type*)0),
930 #define DECL_PROP1(varname, type, attrib1) \
931 DECL_PROP_CORE(varname, type) PropertyAttribute::attrib1)
933 //------------------------------------------------------------------------------
934 void FormController::fillProperties(
935 Sequence< Property >& /* [out] */ _rProps,
936 Sequence< Property >& /* [out] */ /*_rAggregateProps*/
937 ) const
939 _rProps.realloc(2);
940 sal_Int32 nPos = 0;
941 Property* pDesc = _rProps.getArray();
942 DECL_PROP1(FILTER, rtl::OUString, READONLY);
943 DECL_PROP1(FORM_OPERATIONS, Reference< XFormOperations >, READONLY);
946 //------------------------------------------------------------------------------
947 ::cppu::IPropertyArrayHelper& FormController::getInfoHelper()
949 return *getArrayHelper();
952 // XFilterController
953 //------------------------------------------------------------------------------
954 void SAL_CALL FormController::addFilterControllerListener( const Reference< XFilterControllerListener >& _Listener ) throw( RuntimeException )
956 m_aFilterListeners.addInterface( _Listener );
959 //------------------------------------------------------------------------------
960 void SAL_CALL FormController::removeFilterControllerListener( const Reference< XFilterControllerListener >& _Listener ) throw( RuntimeException )
962 m_aFilterListeners.removeInterface( _Listener );
965 //------------------------------------------------------------------------------
966 ::sal_Int32 SAL_CALL FormController::getFilterComponents() throw( ::com::sun::star::uno::RuntimeException )
968 ::osl::MutexGuard aGuard( m_aMutex );
969 impl_checkDisposed_throw();
971 return m_aFilterComponents.size();
974 //------------------------------------------------------------------------------
975 ::sal_Int32 SAL_CALL FormController::getDisjunctiveTerms() throw( ::com::sun::star::uno::RuntimeException )
977 ::osl::MutexGuard aGuard( m_aMutex );
978 impl_checkDisposed_throw();
980 return m_aFilterRows.size();
983 //------------------------------------------------------------------------------
984 void SAL_CALL FormController::setPredicateExpression( ::sal_Int32 _Component, ::sal_Int32 _Term, const ::rtl::OUString& _PredicateExpression ) throw( RuntimeException, IndexOutOfBoundsException )
986 ::osl::MutexGuard aGuard( m_aMutex );
987 impl_checkDisposed_throw();
989 if ( ( _Component < 0 ) || ( _Component >= getFilterComponents() ) || ( _Term < 0 ) || ( _Term >= getDisjunctiveTerms() ) )
990 throw IndexOutOfBoundsException( ::rtl::OUString(), *this );
992 Reference< XTextComponent > xText( m_aFilterComponents[ _Component ] );
993 xText->setText( _PredicateExpression );
995 FmFilterRow& rFilterRow = m_aFilterRows[ _Term ];
996 if ( !_PredicateExpression.isEmpty() )
997 rFilterRow[ xText ] = _PredicateExpression;
998 else
999 rFilterRow.erase( xText );
1002 //------------------------------------------------------------------------------
1003 Reference< XControl > FormController::getFilterComponent( ::sal_Int32 _Component ) throw( RuntimeException, IndexOutOfBoundsException )
1005 ::osl::MutexGuard aGuard( m_aMutex );
1006 impl_checkDisposed_throw();
1008 if ( ( _Component < 0 ) || ( _Component >= getFilterComponents() ) )
1009 throw IndexOutOfBoundsException( ::rtl::OUString(), *this );
1011 return Reference< XControl >( m_aFilterComponents[ _Component ], UNO_QUERY );
1014 //------------------------------------------------------------------------------
1015 Sequence< Sequence< ::rtl::OUString > > FormController::getPredicateExpressions() throw( RuntimeException )
1017 ::osl::MutexGuard aGuard( m_aMutex );
1018 impl_checkDisposed_throw();
1020 Sequence< Sequence< ::rtl::OUString > > aExpressions( m_aFilterRows.size() );
1021 sal_Int32 termIndex = 0;
1022 for ( FmFilterRows::const_iterator row = m_aFilterRows.begin();
1023 row != m_aFilterRows.end();
1024 ++row, ++termIndex
1027 const FmFilterRow& rRow( *row );
1029 Sequence< ::rtl::OUString > aConjunction( m_aFilterComponents.size() );
1030 sal_Int32 componentIndex = 0;
1031 for ( FilterComponents::const_iterator comp = m_aFilterComponents.begin();
1032 comp != m_aFilterComponents.end();
1033 ++comp, ++componentIndex
1036 FmFilterRow::const_iterator predicate = rRow.find( *comp );
1037 if ( predicate != rRow.end() )
1038 aConjunction[ componentIndex ] = predicate->second;
1041 aExpressions[ termIndex ] = aConjunction;
1044 return aExpressions;
1047 //------------------------------------------------------------------------------
1048 void SAL_CALL FormController::removeDisjunctiveTerm( ::sal_Int32 _Term ) throw (IndexOutOfBoundsException, RuntimeException)
1050 // SYNCHRONIZED -->
1051 ::osl::ClearableMutexGuard aGuard( m_aMutex );
1052 impl_checkDisposed_throw();
1054 if ( ( _Term < 0 ) || ( _Term >= getDisjunctiveTerms() ) )
1055 throw IndexOutOfBoundsException( ::rtl::OUString(), *this );
1057 // if the to-be-deleted row is our current row, we need to shift
1058 if ( _Term == m_nCurrentFilterPosition )
1060 if ( m_nCurrentFilterPosition < sal_Int32( m_aFilterRows.size() - 1 ) )
1061 ++m_nCurrentFilterPosition;
1062 else
1063 --m_nCurrentFilterPosition;
1066 FmFilterRows::iterator pos = m_aFilterRows.begin() + _Term;
1067 m_aFilterRows.erase( pos );
1069 // adjust m_nCurrentFilterPosition if the removed row preceeded it
1070 if ( _Term < m_nCurrentFilterPosition )
1071 --m_nCurrentFilterPosition;
1073 OSL_POSTCOND( ( m_nCurrentFilterPosition < 0 ) == ( m_aFilterRows.empty() ),
1074 "FormController::removeDisjunctiveTerm: inconsistency!" );
1076 // update the texts in the filter controls
1077 impl_setTextOnAllFilter_throw();
1079 FilterEvent aEvent;
1080 aEvent.Source = *this;
1081 aEvent.DisjunctiveTerm = _Term;
1082 aGuard.clear();
1083 // <-- SYNCHRONIZED
1085 m_aFilterListeners.notifyEach( &XFilterControllerListener::disjunctiveTermRemoved, aEvent );
1088 //------------------------------------------------------------------------------
1089 void SAL_CALL FormController::appendEmptyDisjunctiveTerm() throw (RuntimeException)
1091 // SYNCHRONIZED -->
1092 ::osl::ClearableMutexGuard aGuard( m_aMutex );
1093 impl_checkDisposed_throw();
1095 impl_appendEmptyFilterRow( aGuard );
1096 // <-- SYNCHRONIZED
1099 //------------------------------------------------------------------------------
1100 ::sal_Int32 SAL_CALL FormController::getActiveTerm() throw (RuntimeException)
1102 ::osl::MutexGuard aGuard( m_aMutex );
1103 impl_checkDisposed_throw();
1105 return m_nCurrentFilterPosition;
1108 //------------------------------------------------------------------------------
1109 void SAL_CALL FormController::setActiveTerm( ::sal_Int32 _ActiveTerm ) throw (IndexOutOfBoundsException, RuntimeException)
1111 ::osl::MutexGuard aGuard( m_aMutex );
1112 impl_checkDisposed_throw();
1114 if ( ( _ActiveTerm < 0 ) || ( _ActiveTerm >= getDisjunctiveTerms() ) )
1115 throw IndexOutOfBoundsException( ::rtl::OUString(), *this );
1117 if ( _ActiveTerm == getActiveTerm() )
1118 return;
1120 m_nCurrentFilterPosition = _ActiveTerm;
1121 impl_setTextOnAllFilter_throw();
1124 // XElementAccess
1125 //------------------------------------------------------------------------------
1126 sal_Bool SAL_CALL FormController::hasElements(void) throw( RuntimeException )
1128 ::osl::MutexGuard aGuard( m_aMutex );
1129 return !m_aChildren.empty();
1132 //------------------------------------------------------------------------------
1133 Type SAL_CALL FormController::getElementType(void) throw( RuntimeException )
1135 return ::getCppuType((const Reference< XFormController>*)0);
1139 // XEnumerationAccess
1140 //------------------------------------------------------------------------------
1141 Reference< XEnumeration > SAL_CALL FormController::createEnumeration(void) throw( RuntimeException )
1143 ::osl::MutexGuard aGuard( m_aMutex );
1144 return new ::comphelper::OEnumerationByIndex(this);
1147 // XIndexAccess
1148 //------------------------------------------------------------------------------
1149 sal_Int32 SAL_CALL FormController::getCount(void) throw( RuntimeException )
1151 ::osl::MutexGuard aGuard( m_aMutex );
1152 return m_aChildren.size();
1155 //------------------------------------------------------------------------------
1156 Any SAL_CALL FormController::getByIndex(sal_Int32 Index) throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException )
1158 ::osl::MutexGuard aGuard( m_aMutex );
1159 if (Index < 0 ||
1160 Index >= (sal_Int32)m_aChildren.size())
1161 throw IndexOutOfBoundsException();
1163 return makeAny( m_aChildren[ Index ] );
1166 // EventListener
1167 //------------------------------------------------------------------------------
1168 void SAL_CALL FormController::disposing(const EventObject& e) throw( RuntimeException )
1170 // Ist der Container disposed worden
1171 ::osl::MutexGuard aGuard( m_aMutex );
1172 Reference< XControlContainer > xContainer(e.Source, UNO_QUERY);
1173 if (xContainer.is())
1175 setContainer(Reference< XControlContainer > ());
1177 else
1179 // ist ein Control disposed worden
1180 Reference< XControl > xControl(e.Source, UNO_QUERY);
1181 if (xControl.is())
1183 if (getContainer().is())
1184 removeControl(xControl);
1189 // OComponentHelper
1190 //-----------------------------------------------------------------------------
1191 void FormController::disposeAllFeaturesAndDispatchers() SAL_THROW(())
1193 for ( DispatcherContainer::iterator aDispatcher = m_aFeatureDispatchers.begin();
1194 aDispatcher != m_aFeatureDispatchers.end();
1195 ++aDispatcher
1200 ::comphelper::disposeComponent( aDispatcher->second );
1202 catch( const Exception& )
1204 DBG_UNHANDLED_EXCEPTION();
1207 m_aFeatureDispatchers.clear();
1210 //-----------------------------------------------------------------------------
1211 void FormController::disposing(void)
1213 EventObject aEvt( *this );
1215 // if we're still active, simulate a "deactivated" event
1216 if ( m_xActiveControl.is() )
1217 m_aActivateListeners.notifyEach( &XFormControllerListener::formDeactivated, aEvt );
1219 // notify all our listeners
1220 m_aActivateListeners.disposeAndClear(aEvt);
1221 m_aModifyListeners.disposeAndClear(aEvt);
1222 m_aErrorListeners.disposeAndClear(aEvt);
1223 m_aDeleteListeners.disposeAndClear(aEvt);
1224 m_aRowSetApproveListeners.disposeAndClear(aEvt);
1225 m_aParameterListeners.disposeAndClear(aEvt);
1226 m_aFilterListeners.disposeAndClear(aEvt);
1228 removeBoundFieldListener();
1229 stopFiltering();
1231 m_pControlBorderManager->restoreAll();
1233 m_aFilterRows.clear();
1235 ::osl::MutexGuard aGuard( m_aMutex );
1236 m_xActiveControl = NULL;
1237 implSetCurrentControl( NULL );
1239 // clean up our children
1240 for (FmFormControllers::const_iterator i = m_aChildren.begin();
1241 i != m_aChildren.end(); ++i)
1243 // search the position of the model within the form
1244 Reference< XFormComponent > xForm((*i)->getModel(), UNO_QUERY);
1245 sal_uInt32 nPos = m_xModelAsIndex->getCount();
1246 Reference< XFormComponent > xTemp;
1247 for( ; nPos; )
1250 m_xModelAsIndex->getByIndex( --nPos ) >>= xTemp;
1251 if ( xForm.get() == xTemp.get() )
1253 Reference< XInterface > xIfc( *i, UNO_QUERY );
1254 m_xModelAsManager->detach( nPos, xIfc );
1255 break;
1259 Reference< XComponent > (*i, UNO_QUERY)->dispose();
1261 m_aChildren.clear();
1263 disposeAllFeaturesAndDispatchers();
1265 if ( m_xFormOperations.is() )
1266 m_xFormOperations->dispose();
1267 m_xFormOperations.clear();
1269 if (m_bDBConnection)
1270 unload();
1272 setContainer( NULL );
1273 setModel( NULL );
1274 setParent( NULL );
1276 ::comphelper::disposeComponent( m_xComposer );
1278 m_bDBConnection = sal_False;
1281 //------------------------------------------------------------------------------
1282 namespace
1284 static bool lcl_shouldUseDynamicControlBorder( const Reference< XInterface >& _rxForm, const Any& _rDynamicColorProp )
1286 bool bDoUse = false;
1287 if ( !( _rDynamicColorProp >>= bDoUse ) )
1289 DocumentType eDocType = DocumentClassification::classifyHostDocument( _rxForm );
1290 return ControlLayouter::useDynamicBorderColor( eDocType );
1292 return bDoUse;
1296 //------------------------------------------------------------------------------
1297 void SAL_CALL FormController::propertyChange(const PropertyChangeEvent& evt) throw( RuntimeException )
1299 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1300 if ( evt.PropertyName == FM_PROP_BOUNDFIELD )
1302 Reference<XPropertySet> xOldBound;
1303 evt.OldValue >>= xOldBound;
1304 if ( !xOldBound.is() && evt.NewValue.hasValue() )
1306 Reference< XControlModel > xControlModel(evt.Source,UNO_QUERY);
1307 Reference< XControl > xControl = findControl(m_aControls,xControlModel,sal_False,sal_False);
1308 if ( xControl.is() )
1310 startControlModifyListening( xControl );
1311 Reference<XPropertySet> xProp(xControlModel,UNO_QUERY);
1312 if ( xProp.is() )
1313 xProp->removePropertyChangeListener(FM_PROP_BOUNDFIELD, this);
1317 else
1319 sal_Bool bModifiedChanged = (evt.PropertyName == FM_PROP_ISMODIFIED);
1320 sal_Bool bNewChanged = (evt.PropertyName == FM_PROP_ISNEW);
1321 if (bModifiedChanged || bNewChanged)
1323 ::osl::MutexGuard aGuard( m_aMutex );
1324 if (bModifiedChanged)
1325 m_bCurrentRecordModified = ::comphelper::getBOOL(evt.NewValue);
1326 else
1327 m_bCurrentRecordNew = ::comphelper::getBOOL(evt.NewValue);
1329 // toggle the locking
1330 if (m_bLocked != determineLockState())
1332 m_bLocked = !m_bLocked;
1333 setLocks();
1334 if (isListeningForChanges())
1335 startListening();
1336 else
1337 stopListening();
1340 if ( bNewChanged )
1341 m_aToggleEvent.Call();
1343 if (!m_bCurrentRecordModified)
1344 m_bModified = sal_False;
1346 else if ( evt.PropertyName == FM_PROP_DYNAMIC_CONTROL_BORDER )
1348 bool bEnable = lcl_shouldUseDynamicControlBorder( evt.Source, evt.NewValue );
1349 if ( bEnable )
1351 m_pControlBorderManager->enableDynamicBorderColor();
1352 if ( m_xActiveControl.is() )
1353 m_pControlBorderManager->focusGained( m_xActiveControl.get() );
1355 else
1357 m_pControlBorderManager->disableDynamicBorderColor();
1363 //------------------------------------------------------------------------------
1364 bool FormController::replaceControl( const Reference< XControl >& _rxExistentControl, const Reference< XControl >& _rxNewControl )
1366 bool bSuccess = false;
1369 Reference< XIdentifierReplace > xContainer( getContainer(), UNO_QUERY );
1370 DBG_ASSERT( xContainer.is(), "FormController::replaceControl: yes, it's not required by the service description, but XItentifierReplaces would be nice!" );
1371 if ( xContainer.is() )
1373 // look up the ID of _rxExistentControl
1374 Sequence< sal_Int32 > aIdentifiers( xContainer->getIdentifiers() );
1375 const sal_Int32* pIdentifiers = aIdentifiers.getConstArray();
1376 const sal_Int32* pIdentifiersEnd = aIdentifiers.getConstArray() + aIdentifiers.getLength();
1377 for ( ; pIdentifiers != pIdentifiersEnd; ++pIdentifiers )
1379 Reference< XControl > xCheck( xContainer->getByIdentifier( *pIdentifiers ), UNO_QUERY );
1380 if ( xCheck == _rxExistentControl )
1381 break;
1383 DBG_ASSERT( pIdentifiers != pIdentifiersEnd, "FormController::replaceControl: did not find the control in the container!" );
1384 if ( pIdentifiers != pIdentifiersEnd )
1386 bool bReplacedWasActive = ( m_xActiveControl.get() == _rxExistentControl.get() );
1387 bool bReplacedWasCurrent = ( m_xCurrentControl.get() == _rxExistentControl.get() );
1389 if ( bReplacedWasActive )
1391 m_xActiveControl = NULL;
1392 implSetCurrentControl( NULL );
1394 else if ( bReplacedWasCurrent )
1396 implSetCurrentControl( _rxNewControl );
1399 // carry over the model
1400 _rxNewControl->setModel( _rxExistentControl->getModel() );
1402 xContainer->replaceByIdentifer( *pIdentifiers, makeAny( _rxNewControl ) );
1403 bSuccess = true;
1405 if ( bReplacedWasActive )
1407 Reference< XWindow > xControlWindow( _rxNewControl, UNO_QUERY );
1408 if ( xControlWindow.is() )
1409 xControlWindow->setFocus();
1414 catch( const Exception& )
1416 DBG_UNHANDLED_EXCEPTION();
1419 Reference< XControl > xDisposeIt( bSuccess ? _rxExistentControl : _rxNewControl );
1420 ::comphelper::disposeComponent( xDisposeIt );
1421 return bSuccess;
1424 //------------------------------------------------------------------------------
1425 void FormController::toggleAutoFields(sal_Bool bAutoFields)
1427 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1430 Sequence< Reference< XControl > > aControlsCopy( m_aControls );
1431 const Reference< XControl >* pControls = aControlsCopy.getConstArray();
1432 sal_Int32 nControls = aControlsCopy.getLength();
1434 if (bAutoFields)
1436 // as we don't want new controls to be attached to the scripting environment
1437 // we change attach flags
1438 m_bAttachEvents = sal_False;
1439 for (sal_Int32 i = nControls; i > 0;)
1441 Reference< XControl > xControl = pControls[--i];
1442 if (xControl.is())
1444 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
1445 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
1447 // does the model use a bound field ?
1448 Reference< XPropertySet > xField;
1449 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
1451 // is it a autofield?
1452 if ( xField.is()
1453 && ::comphelper::hasProperty( FM_PROP_AUTOINCREMENT, xField )
1454 && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_AUTOINCREMENT ) )
1457 replaceControl( xControl, new FmXAutoControl( m_aContext ) );
1462 m_bAttachEvents = sal_True;
1464 else
1466 m_bDetachEvents = sal_False;
1467 for (sal_Int32 i = nControls; i > 0;)
1469 Reference< XControl > xControl = pControls[--i];
1470 if (xControl.is())
1472 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
1473 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
1475 // does the model use a bound field ?
1476 Reference< XPropertySet > xField;
1477 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
1479 // is it a autofield?
1480 if ( xField.is()
1481 && ::comphelper::hasProperty( FM_PROP_AUTOINCREMENT, xField )
1482 && ::comphelper::getBOOL( xField->getPropertyValue(FM_PROP_AUTOINCREMENT ) )
1485 ::rtl::OUString sServiceName;
1486 OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DEFAULTCONTROL ) >>= sServiceName );
1487 Reference< XControl > xNewControl( m_aContext.createComponent( sServiceName ), UNO_QUERY );
1488 replaceControl( xControl, xNewControl );
1493 m_bDetachEvents = sal_True;
1497 //------------------------------------------------------------------------------
1498 IMPL_LINK_NOARG(FormController, OnToggleAutoFields)
1500 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1502 toggleAutoFields(m_bCurrentRecordNew);
1503 return 1L;
1506 // XTextListener
1507 //------------------------------------------------------------------------------
1508 void SAL_CALL FormController::textChanged(const TextEvent& e) throw( RuntimeException )
1510 // SYNCHRONIZED -->
1511 ::osl::ClearableMutexGuard aGuard( m_aMutex );
1512 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1513 if ( !m_bFiltering )
1515 impl_onModify();
1516 return;
1519 if ( m_bSuspendFilterTextListening )
1520 return;
1522 Reference< XTextComponent > xText(e.Source,UNO_QUERY);
1523 ::rtl::OUString aText = xText->getText();
1525 if ( m_aFilterRows.empty() )
1526 appendEmptyDisjunctiveTerm();
1528 // Suchen der aktuellen Row
1529 if ( ( (size_t)m_nCurrentFilterPosition >= m_aFilterRows.size() ) || ( m_nCurrentFilterPosition < 0 ) )
1531 OSL_ENSURE( false, "FormController::textChanged: m_nCurrentFilterPosition is wrong!" );
1532 return;
1535 FmFilterRow& rRow = m_aFilterRows[ m_nCurrentFilterPosition ];
1537 // do we have a new filter
1538 if (!aText.isEmpty())
1539 rRow[xText] = aText;
1540 else
1542 // do we have the control in the row
1543 FmFilterRow::iterator iter = rRow.find(xText);
1544 // erase the entry out of the row
1545 if (iter != rRow.end())
1546 rRow.erase(iter);
1549 // multiplex the event to our FilterControllerListeners
1550 FilterEvent aEvent;
1551 aEvent.Source = *this;
1552 aEvent.FilterComponent = ::std::find( m_aFilterComponents.begin(), m_aFilterComponents.end(), xText ) - m_aFilterComponents.begin();
1553 aEvent.DisjunctiveTerm = getActiveTerm();
1554 aEvent.PredicateExpression = aText;
1556 aGuard.clear();
1557 // <-- SYNCHRONIZED
1559 // notify the changed filter expression
1560 m_aFilterListeners.notifyEach( &XFilterControllerListener::predicateExpressionChanged, aEvent );
1563 // XItemListener
1564 //------------------------------------------------------------------------------
1565 void SAL_CALL FormController::itemStateChanged(const ItemEvent& /*rEvent*/) throw( RuntimeException )
1567 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1568 impl_onModify();
1571 // XModificationBroadcaster
1572 //------------------------------------------------------------------------------
1573 void SAL_CALL FormController::addModifyListener(const Reference< XModifyListener > & l) throw( RuntimeException )
1575 ::osl::MutexGuard aGuard( m_aMutex );
1576 impl_checkDisposed_throw();
1577 m_aModifyListeners.addInterface( l );
1580 //------------------------------------------------------------------------------
1581 void FormController::removeModifyListener(const Reference< XModifyListener > & l) throw( RuntimeException )
1583 ::osl::MutexGuard aGuard( m_aMutex );
1584 impl_checkDisposed_throw();
1585 m_aModifyListeners.removeInterface( l );
1588 // XModificationListener
1589 //------------------------------------------------------------------------------
1590 void FormController::modified( const EventObject& _rEvent ) throw( RuntimeException )
1592 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1596 if ( _rEvent.Source != m_xActiveControl )
1597 { // let this control grab the focus
1598 // (this case may happen if somebody moves the scroll wheel of the mouse over a control
1599 // which does not have the focus)
1600 // 85511 - 29.05.2001 - frank.schoenheit@germany.sun.com
1602 // also, it happens when an image control gets a new image by double-clicking it
1603 // #i88458# / 2009-01-12 / frank.schoenheit@sun.com
1604 Reference< XWindow > xControlWindow( _rEvent.Source, UNO_QUERY_THROW );
1605 xControlWindow->setFocus();
1608 catch( const Exception& )
1610 DBG_UNHANDLED_EXCEPTION();
1613 impl_onModify();
1616 //------------------------------------------------------------------------------
1617 void FormController::impl_checkDisposed_throw() const
1619 if ( impl_isDisposed_nofail() )
1620 throw DisposedException( ::rtl::OUString(), *const_cast< FormController* >( this ) );
1623 //------------------------------------------------------------------------------
1624 void FormController::impl_onModify()
1626 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1629 ::osl::MutexGuard aGuard( m_aMutex );
1630 if ( !m_bModified )
1631 m_bModified = sal_True;
1634 EventObject aEvt(static_cast<cppu::OWeakObject*>(this));
1635 m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvt );
1638 //------------------------------------------------------------------------------
1639 void FormController::impl_addFilterRow( const FmFilterRow& _row )
1641 m_aFilterRows.push_back( _row );
1643 if ( m_aFilterRows.size() == 1 )
1644 { // that's the first row ever
1645 OSL_ENSURE( m_nCurrentFilterPosition == -1, "FormController::impl_addFilterRow: inconsistency!" );
1646 m_nCurrentFilterPosition = 0;
1650 //------------------------------------------------------------------------------
1651 void FormController::impl_appendEmptyFilterRow( ::osl::ClearableMutexGuard& _rClearBeforeNotify )
1653 // SYNCHRONIZED -->
1654 impl_addFilterRow( FmFilterRow() );
1656 // notify the listeners
1657 FilterEvent aEvent;
1658 aEvent.Source = *this;
1659 aEvent.DisjunctiveTerm = (sal_Int32)m_aFilterRows.size() - 1;
1660 _rClearBeforeNotify.clear();
1661 // <-- SYNCHRONIZED
1662 m_aFilterListeners.notifyEach( &XFilterControllerListener::disjunctiveTermAdded, aEvent );
1665 //------------------------------------------------------------------------------
1666 sal_Bool FormController::determineLockState() const
1668 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1669 // a.) in filter mode we are always locked
1670 // b.) if we have no valid model or our model (a result set) is not alive -> we're locked
1671 // c.) if we are inserting everything is OK and we are not locked
1672 // d.) if are not updatable or on invalid position
1673 Reference< XResultSet > xResultSet(m_xModelAsIndex, UNO_QUERY);
1674 if (m_bFiltering || !xResultSet.is() || !isRowSetAlive(xResultSet))
1675 return sal_True;
1676 else
1677 return (m_bCanInsert && m_bCurrentRecordNew) ? sal_False
1678 : xResultSet->isBeforeFirst() || xResultSet->isAfterLast() || xResultSet->rowDeleted() || !m_bCanUpdate;
1681 // FocusListener
1682 //------------------------------------------------------------------------------
1683 void FormController::focusGained(const FocusEvent& e) throw( RuntimeException )
1685 // SYNCHRONIZED -->
1686 ::osl::ClearableMutexGuard aGuard( m_aMutex );
1687 impl_checkDisposed_throw();
1689 m_pControlBorderManager->focusGained( e.Source );
1691 Reference< XControl > xControl(e.Source, UNO_QUERY);
1692 if (m_bDBConnection)
1694 // do we need to keep the locking of the commit
1695 // we hold the lock as long as the control differs from the current
1696 // otherwhise we disabled the lock
1697 m_bCommitLock = m_bCommitLock && (XControl*)xControl.get() != (XControl*)m_xCurrentControl.get();
1698 if (m_bCommitLock)
1699 return;
1701 // when do we have to commit a value to form or a filter
1702 // a.) if the current value is modified
1703 // b.) there must be a current control
1704 // c.) and it must be different from the new focus owning control or
1705 // d.) the focus is moving around (so we have only one control)
1707 if ( ( m_bModified || m_bFiltering )
1708 && m_xCurrentControl.is()
1709 && ( ( xControl.get() != m_xCurrentControl.get() )
1710 || ( ( e.FocusFlags & FocusChangeReason::AROUND )
1711 && ( m_bCycle || m_bFiltering )
1716 // check the old control if the content is ok
1717 #if OSL_DEBUG_LEVEL > 1
1718 Reference< XBoundControl > xLockingTest(m_xCurrentControl, UNO_QUERY);
1719 sal_Bool bControlIsLocked = xLockingTest.is() && xLockingTest->getLock();
1720 OSL_ENSURE(!bControlIsLocked, "FormController::Gained: I'm modified and the current control is locked ? How this ?");
1721 // normalerweise sollte ein gelocktes Control nicht modified sein, also muss wohl mein bModified aus einem anderen Kontext
1722 // gesetzt worden sein, was ich nicht verstehen wuerde ...
1723 #endif
1724 DBG_ASSERT(m_xCurrentControl.is(), "kein CurrentControl gesetzt");
1725 // zunaechst das Control fragen ob es das IFace unterstuetzt
1726 Reference< XBoundComponent > xBound(m_xCurrentControl, UNO_QUERY);
1727 if (!xBound.is() && m_xCurrentControl.is())
1728 xBound = Reference< XBoundComponent > (m_xCurrentControl->getModel(), UNO_QUERY);
1730 // lock if we lose the focus during commit
1731 m_bCommitLock = sal_True;
1733 // Commit nicht erfolgreich, Focus zuruecksetzen
1734 if (xBound.is() && !xBound->commit())
1736 // the commit failed and we don't commit again until the current control
1737 // which couldn't be commit gains the focus again
1738 Reference< XWindow > xWindow(m_xCurrentControl, UNO_QUERY);
1739 if (xWindow.is())
1740 xWindow->setFocus();
1741 return;
1743 else
1745 m_bModified = sal_False;
1746 m_bCommitLock = sal_False;
1750 if (!m_bFiltering && m_bCycle && (e.FocusFlags & FocusChangeReason::AROUND) && m_xCurrentControl.is())
1752 SQLErrorEvent aErrorEvent;
1753 OSL_ENSURE( m_xFormOperations.is(), "FormController::focusGained: hmm?" );
1754 // should have been created in setModel
1757 if ( e.FocusFlags & FocusChangeReason::FORWARD )
1759 if ( m_xFormOperations.is() && m_xFormOperations->isEnabled( FormFeature::MoveToNext ) )
1760 m_xFormOperations->execute( FormFeature::MoveToNext );
1762 else // backward
1764 if ( m_xFormOperations.is() && m_xFormOperations->isEnabled( FormFeature::MoveToPrevious ) )
1765 m_xFormOperations->execute( FormFeature::MoveToPrevious );
1768 catch ( const Exception& )
1770 // don't handle this any further. That's an ... admissible error.
1771 DBG_UNHANDLED_EXCEPTION();
1776 // Immer noch ein und dasselbe Control
1777 if ( ( m_xActiveControl == xControl )
1778 && ( xControl == m_xCurrentControl )
1781 DBG_ASSERT(m_xCurrentControl.is(), "Kein CurrentControl selektiert");
1782 return;
1785 sal_Bool bActivated = !m_xActiveControl.is() && xControl.is();
1787 m_xActiveControl = xControl;
1789 implSetCurrentControl( xControl );
1790 OSL_POSTCOND( m_xCurrentControl.is(), "implSetCurrentControl did nonsense!" );
1792 if ( bActivated )
1794 // (asynchronously) call activation handlers
1795 m_aActivationEvent.Call();
1797 // call modify listeners
1798 if ( m_bModified )
1799 m_aModifyListeners.notifyEach( &XModifyListener::modified, EventObject( *this ) );
1802 // invalidate all features which depend on the currently focused control
1803 if ( m_bDBConnection && !m_bFiltering )
1804 implInvalidateCurrentControlDependentFeatures();
1806 if ( !m_xCurrentControl.is() )
1807 return;
1809 // Control erhaelt Focus, dann eventuell in den sichtbaren Bereich
1810 Reference< XFormControllerContext > xContext( m_xContext );
1811 Reference< XControl > xCurrentControl( m_xCurrentControl );
1812 aGuard.clear();
1813 // <-- SYNCHRONIZED
1815 if ( xContext.is() )
1816 xContext->makeVisible( xCurrentControl );
1819 //------------------------------------------------------------------------------
1820 IMPL_LINK( FormController, OnActivated, void*, /**/ )
1822 EventObject aEvent;
1823 aEvent.Source = *this;
1824 m_aActivateListeners.notifyEach( &XFormControllerListener::formActivated, aEvent );
1826 return 0L;
1829 //------------------------------------------------------------------------------
1830 IMPL_LINK( FormController, OnDeactivated, void*, /**/ )
1832 EventObject aEvent;
1833 aEvent.Source = *this;
1834 m_aActivateListeners.notifyEach( &XFormControllerListener::formDeactivated, aEvent );
1836 return 0L;
1839 //------------------------------------------------------------------------------
1840 void FormController::focusLost(const FocusEvent& e) throw( RuntimeException )
1842 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1844 m_pControlBorderManager->focusLost( e.Source );
1846 Reference< XControl > xControl(e.Source, UNO_QUERY);
1847 Reference< XWindowPeer > xNext(e.NextFocus, UNO_QUERY);
1848 Reference< XControl > xNextControl = isInList(xNext);
1849 if (!xNextControl.is())
1851 m_xActiveControl = NULL;
1852 m_aDeactivationEvent.Call();
1856 //--------------------------------------------------------------------
1857 void SAL_CALL FormController::mousePressed( const awt::MouseEvent& /*_rEvent*/ ) throw (RuntimeException)
1859 // not interested in
1862 //--------------------------------------------------------------------
1863 void SAL_CALL FormController::mouseReleased( const awt::MouseEvent& /*_rEvent*/ ) throw (RuntimeException)
1865 // not interested in
1868 //--------------------------------------------------------------------
1869 void SAL_CALL FormController::mouseEntered( const awt::MouseEvent& _rEvent ) throw (RuntimeException)
1871 m_pControlBorderManager->mouseEntered( _rEvent.Source );
1874 //--------------------------------------------------------------------
1875 void SAL_CALL FormController::mouseExited( const awt::MouseEvent& _rEvent ) throw (RuntimeException)
1877 m_pControlBorderManager->mouseExited( _rEvent.Source );
1880 //--------------------------------------------------------------------
1881 void SAL_CALL FormController::componentValidityChanged( const EventObject& _rSource ) throw (RuntimeException)
1883 Reference< XControl > xControl( findControl( m_aControls, Reference< XControlModel >( _rSource.Source, UNO_QUERY ), sal_False, sal_False ) );
1884 Reference< XValidatableFormComponent > xValidatable( _rSource.Source, UNO_QUERY );
1886 OSL_ENSURE( xControl.is() && xValidatable.is(), "FormController::componentValidityChanged: huh?" );
1888 if ( xControl.is() && xValidatable.is() )
1889 m_pControlBorderManager->validityChanged( xControl, xValidatable );
1892 //--------------------------------------------------------------------
1893 void FormController::setModel(const Reference< XTabControllerModel > & Model) throw( RuntimeException )
1895 ::osl::MutexGuard aGuard( m_aMutex );
1896 impl_checkDisposed_throw();
1898 DBG_ASSERT(m_xTabController.is(), "FormController::setModel : invalid aggregate !");
1902 // disconnect from the old model
1903 if (m_xModelAsIndex.is())
1905 if (m_bDBConnection)
1907 // we are currently working on the model
1908 EventObject aEvt(m_xModelAsIndex);
1909 unloaded(aEvt);
1912 Reference< XLoadable > xForm(m_xModelAsIndex, UNO_QUERY);
1913 if (xForm.is())
1914 xForm->removeLoadListener(this);
1916 Reference< XSQLErrorBroadcaster > xBroadcaster(m_xModelAsIndex, UNO_QUERY);
1917 if (xBroadcaster.is())
1918 xBroadcaster->removeSQLErrorListener(this);
1920 Reference< XDatabaseParameterBroadcaster > xParamBroadcaster(m_xModelAsIndex, UNO_QUERY);
1921 if (xParamBroadcaster.is())
1922 xParamBroadcaster->removeParameterListener(this);
1926 disposeAllFeaturesAndDispatchers();
1928 if ( m_xFormOperations.is() )
1929 m_xFormOperations->dispose();
1930 m_xFormOperations.clear();
1932 // set the new model wait for the load event
1933 if (m_xTabController.is())
1934 m_xTabController->setModel(Model);
1935 m_xModelAsIndex = Reference< XIndexAccess > (Model, UNO_QUERY);
1936 m_xModelAsManager = Reference< XEventAttacherManager > (Model, UNO_QUERY);
1938 // only if both ifaces exit, the controller will work successful
1939 if (!m_xModelAsIndex.is() || !m_xModelAsManager.is())
1941 m_xModelAsManager = NULL;
1942 m_xModelAsIndex = NULL;
1945 if (m_xModelAsIndex.is())
1947 // re-create m_xFormOperations
1948 m_xFormOperations.set( FormOperations::createWithFormController( m_aContext.getUNOContext(), this ), UNO_SET_THROW );
1949 m_xFormOperations->setFeatureInvalidation( this );
1951 // adding load and ui interaction listeners
1952 Reference< XLoadable > xForm(Model, UNO_QUERY);
1953 if (xForm.is())
1954 xForm->addLoadListener(this);
1956 Reference< XSQLErrorBroadcaster > xBroadcaster(Model, UNO_QUERY);
1957 if (xBroadcaster.is())
1958 xBroadcaster->addSQLErrorListener(this);
1960 Reference< XDatabaseParameterBroadcaster > xParamBroadcaster(Model, UNO_QUERY);
1961 if (xParamBroadcaster.is())
1962 xParamBroadcaster->addParameterListener(this);
1964 // well, is the database already loaded?
1965 // then we have to simulate a load event
1966 Reference< XLoadable > xCursor(m_xModelAsIndex, UNO_QUERY);
1967 if (xCursor.is() && xCursor->isLoaded())
1969 EventObject aEvt(xCursor);
1970 loaded(aEvt);
1973 Reference< XPropertySet > xModelProps( m_xModelAsIndex, UNO_QUERY );
1974 Reference< XPropertySetInfo > xPropInfo( xModelProps->getPropertySetInfo() );
1975 if ( xPropInfo.is()
1976 && xPropInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER )
1977 && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_FOCUS )
1978 && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_MOUSE )
1979 && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_INVALID )
1982 bool bEnableDynamicControlBorder = lcl_shouldUseDynamicControlBorder(
1983 xModelProps.get(), xModelProps->getPropertyValue( FM_PROP_DYNAMIC_CONTROL_BORDER ) );
1984 if ( bEnableDynamicControlBorder )
1985 m_pControlBorderManager->enableDynamicBorderColor();
1986 else
1987 m_pControlBorderManager->disableDynamicBorderColor();
1989 sal_Int32 nColor = 0;
1990 if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_FOCUS ) >>= nColor )
1991 m_pControlBorderManager->setStatusColor( CONTROL_STATUS_FOCUSED, nColor );
1992 if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_MOUSE ) >>= nColor )
1993 m_pControlBorderManager->setStatusColor( CONTROL_STATUS_MOUSE_HOVER, nColor );
1994 if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_INVALID ) >>= nColor )
1995 m_pControlBorderManager->setStatusColor( CONTROL_STATUS_INVALID, nColor );
1999 catch( const Exception& )
2001 DBG_UNHANDLED_EXCEPTION();
2005 //------------------------------------------------------------------------------
2006 Reference< XTabControllerModel > FormController::getModel() throw( RuntimeException )
2008 ::osl::MutexGuard aGuard( m_aMutex );
2009 impl_checkDisposed_throw();
2011 DBG_ASSERT(m_xTabController.is(), "FormController::getModel : invalid aggregate !");
2012 if (!m_xTabController.is())
2013 return Reference< XTabControllerModel > ();
2014 return m_xTabController->getModel();
2017 //------------------------------------------------------------------------------
2018 void FormController::addToEventAttacher(const Reference< XControl > & xControl)
2020 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2021 OSL_ENSURE( xControl.is(), "FormController::addToEventAttacher: invalid control - how did you reach this?" );
2022 if ( !xControl.is() )
2023 return; /* throw IllegalArgumentException(); */
2025 // anmelden beim Eventattacher
2026 Reference< XFormComponent > xComp(xControl->getModel(), UNO_QUERY);
2027 if (xComp.is() && m_xModelAsIndex.is())
2029 // Und die Position des ControlModel darin suchen
2030 sal_uInt32 nPos = m_xModelAsIndex->getCount();
2031 Reference< XFormComponent > xTemp;
2032 for( ; nPos; )
2034 m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
2035 if ((XFormComponent*)xComp.get() == (XFormComponent*)xTemp.get())
2037 Reference< XInterface > xIfc(xControl, UNO_QUERY);
2038 m_xModelAsManager->attach( nPos, xIfc, makeAny(xControl) );
2039 break;
2045 //------------------------------------------------------------------------------
2046 void FormController::removeFromEventAttacher(const Reference< XControl > & xControl)
2048 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2049 OSL_ENSURE( xControl.is(), "FormController::removeFromEventAttacher: invalid control - how did you reach this?" );
2050 if ( !xControl.is() )
2051 return; /* throw IllegalArgumentException(); */
2053 // abmelden beim Eventattacher
2054 Reference< XFormComponent > xComp(xControl->getModel(), UNO_QUERY);
2055 if ( xComp.is() && m_xModelAsIndex.is() )
2057 // Und die Position des ControlModel darin suchen
2058 sal_uInt32 nPos = m_xModelAsIndex->getCount();
2059 Reference< XFormComponent > xTemp;
2060 for( ; nPos; )
2062 m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
2063 if ((XFormComponent*)xComp.get() == (XFormComponent*)xTemp.get())
2065 Reference< XInterface > xIfc(xControl, UNO_QUERY);
2066 m_xModelAsManager->detach( nPos, xIfc );
2067 break;
2073 //------------------------------------------------------------------------------
2074 void FormController::setContainer(const Reference< XControlContainer > & xContainer) throw( RuntimeException )
2076 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2077 Reference< XTabControllerModel > xTabModel(getModel());
2078 DBG_ASSERT(xTabModel.is() || !xContainer.is(), "No Model defined");
2079 // if we have a new container we need a model
2080 DBG_ASSERT(m_xTabController.is(), "FormController::setContainer : invalid aggregate !");
2082 ::osl::MutexGuard aGuard( m_aMutex );
2083 Reference< XContainer > xCurrentContainer;
2084 if (m_xTabController.is())
2085 xCurrentContainer = Reference< XContainer > (m_xTabController->getContainer(), UNO_QUERY);
2086 if (xCurrentContainer.is())
2088 xCurrentContainer->removeContainerListener(this);
2090 if ( m_aTabActivationTimer.IsActive() )
2091 m_aTabActivationTimer.Stop();
2093 // clear the filter map
2094 ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), RemoveComponentTextListener( this ) );
2095 m_aFilterComponents.clear();
2097 // einsammeln der Controls
2098 const Reference< XControl >* pControls = m_aControls.getConstArray();
2099 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2100 while ( pControls != pControlsEnd )
2101 implControlRemoved( *pControls++, true );
2103 // Datenbank spezifische Dinge vornehmen
2104 if (m_bDBConnection && isListeningForChanges())
2105 stopListening();
2107 m_aControls.realloc( 0 );
2110 if (m_xTabController.is())
2111 m_xTabController->setContainer(xContainer);
2113 // Welche Controls gehoeren zum Container ?
2114 if (xContainer.is() && xTabModel.is())
2116 Sequence< Reference< XControlModel > > aModels = xTabModel->getControlModels();
2117 const Reference< XControlModel > * pModels = aModels.getConstArray();
2118 Sequence< Reference< XControl > > aAllControls = xContainer->getControls();
2120 sal_Int32 nCount = aModels.getLength();
2121 m_aControls = Sequence< Reference< XControl > >( nCount );
2122 Reference< XControl > * pControls = m_aControls.getArray();
2124 // einsammeln der Controls
2125 sal_Int32 i, j;
2126 for (i = 0, j = 0; i < nCount; ++i, ++pModels )
2128 Reference< XControl > xControl = findControl( aAllControls, *pModels, sal_False, sal_True );
2129 if ( xControl.is() )
2131 pControls[j++] = xControl;
2132 implControlInserted( xControl, true );
2136 // not every model had an associated control
2137 if (j != i)
2138 m_aControls.realloc(j);
2140 // am Container horchen
2141 Reference< XContainer > xNewContainer(xContainer, UNO_QUERY);
2142 if (xNewContainer.is())
2143 xNewContainer->addContainerListener(this);
2145 // Datenbank spezifische Dinge vornehmen
2146 if (m_bDBConnection)
2148 m_bLocked = determineLockState();
2149 setLocks();
2150 if (!isLocked())
2151 startListening();
2154 // befinden sich die Controls in der richtigen Reihenfolge
2155 m_bControlsSorted = sal_True;
2158 //------------------------------------------------------------------------------
2159 Reference< XControlContainer > FormController::getContainer() throw( RuntimeException )
2161 ::osl::MutexGuard aGuard( m_aMutex );
2162 impl_checkDisposed_throw();
2164 DBG_ASSERT(m_xTabController.is(), "FormController::getContainer : invalid aggregate !");
2165 if (!m_xTabController.is())
2166 return Reference< XControlContainer > ();
2167 return m_xTabController->getContainer();
2170 //------------------------------------------------------------------------------
2171 Sequence< Reference< XControl > > FormController::getControls(void) throw( RuntimeException )
2173 ::osl::MutexGuard aGuard( m_aMutex );
2174 impl_checkDisposed_throw();
2176 if (!m_bControlsSorted)
2178 Reference< XTabControllerModel > xModel = getModel();
2179 if (!xModel.is())
2180 return m_aControls;
2182 Sequence< Reference< XControlModel > > aControlModels = xModel->getControlModels();
2183 const Reference< XControlModel > * pModels = aControlModels.getConstArray();
2184 sal_Int32 nModels = aControlModels.getLength();
2186 Sequence< Reference< XControl > > aNewControls(nModels);
2188 Reference< XControl > * pControls = aNewControls.getArray();
2189 Reference< XControl > xControl;
2191 // Umsortieren der Controls entsprechend der TabReihenfolge
2192 sal_Int32 j = 0;
2193 for (sal_Int32 i = 0; i < nModels; ++i, ++pModels )
2195 xControl = findControl( m_aControls, *pModels, sal_True, sal_True );
2196 if ( xControl.is() )
2197 pControls[j++] = xControl;
2200 // not every model had an associated control
2201 if ( j != nModels )
2202 aNewControls.realloc( j );
2204 m_aControls = aNewControls;
2205 m_bControlsSorted = sal_True;
2207 return m_aControls;
2210 //------------------------------------------------------------------------------
2211 void FormController::autoTabOrder() throw( RuntimeException )
2213 ::osl::MutexGuard aGuard( m_aMutex );
2214 impl_checkDisposed_throw();
2216 DBG_ASSERT(m_xTabController.is(), "FormController::autoTabOrder : invalid aggregate !");
2217 if (m_xTabController.is())
2218 m_xTabController->autoTabOrder();
2221 //------------------------------------------------------------------------------
2222 void FormController::activateTabOrder() throw( RuntimeException )
2224 ::osl::MutexGuard aGuard( m_aMutex );
2225 impl_checkDisposed_throw();
2227 DBG_ASSERT(m_xTabController.is(), "FormController::activateTabOrder : invalid aggregate !");
2228 if (m_xTabController.is())
2229 m_xTabController->activateTabOrder();
2232 //------------------------------------------------------------------------------
2233 void FormController::setControlLock(const Reference< XControl > & xControl)
2235 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2236 sal_Bool bLocked = isLocked();
2238 // es wird gelockt
2239 // a.) wenn der ganze Datensatz gesperrt ist
2240 // b.) wenn das zugehoerige Feld gespeert ist
2241 Reference< XBoundControl > xBound(xControl, UNO_QUERY);
2242 if (xBound.is() && (( (bLocked && bLocked != xBound->getLock()) ||
2243 !bLocked))) // beim entlocken immer einzelne Felder ueberpr�fen
2245 // gibt es eine Datenquelle
2246 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
2247 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
2249 // wie sieht mit den Properties ReadOnly und Enable aus
2250 sal_Bool bTouch = sal_True;
2251 if (::comphelper::hasProperty(FM_PROP_ENABLED, xSet))
2252 bTouch = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ENABLED));
2253 if (::comphelper::hasProperty(FM_PROP_READONLY, xSet))
2254 bTouch = !::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_READONLY));
2256 if (bTouch)
2258 Reference< XPropertySet > xField;
2259 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
2260 if (xField.is())
2262 if (bLocked)
2263 xBound->setLock(bLocked);
2264 else
2268 Any aVal = xField->getPropertyValue(FM_PROP_ISREADONLY);
2269 if (aVal.hasValue() && ::comphelper::getBOOL(aVal))
2270 xBound->setLock(sal_True);
2271 else
2272 xBound->setLock(bLocked);
2274 catch( const Exception& )
2276 DBG_UNHANDLED_EXCEPTION();
2286 //------------------------------------------------------------------------------
2287 void FormController::setLocks()
2289 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2290 // alle Controls, die mit einer Datenquelle verbunden sind locken/unlocken
2291 const Reference< XControl >* pControls = m_aControls.getConstArray();
2292 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2293 while ( pControls != pControlsEnd )
2294 setControlLock( *pControls++ );
2297 //------------------------------------------------------------------------------
2298 namespace
2300 bool lcl_shouldListenForModifications( const Reference< XControl >& _rxControl, const Reference< XPropertyChangeListener >& _rxBoundFieldListener )
2302 bool bShould = false;
2304 Reference< XBoundComponent > xBound( _rxControl, UNO_QUERY );
2305 if ( xBound.is() )
2307 bShould = true;
2309 else if ( _rxControl.is() )
2311 Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY );
2312 if ( xModelProps.is() && ::comphelper::hasProperty( FM_PROP_BOUNDFIELD, xModelProps ) )
2314 Reference< XPropertySet > xField;
2315 xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField;
2316 bShould = xField.is();
2318 if ( !bShould && _rxBoundFieldListener.is() )
2319 xModelProps->addPropertyChangeListener( FM_PROP_BOUNDFIELD, _rxBoundFieldListener );
2323 return bShould;
2327 //------------------------------------------------------------------------------
2328 void FormController::startControlModifyListening(const Reference< XControl > & xControl)
2330 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2332 bool bModifyListening = lcl_shouldListenForModifications( xControl, this );
2334 // artificial while
2335 while ( bModifyListening )
2337 Reference< XModifyBroadcaster > xMod(xControl, UNO_QUERY);
2338 if (xMod.is())
2340 xMod->addModifyListener(this);
2341 break;
2344 // alle die Text um vorzeitig ein modified zu erkennen
2345 Reference< XTextComponent > xText(xControl, UNO_QUERY);
2346 if (xText.is())
2348 xText->addTextListener(this);
2349 break;
2352 Reference< XCheckBox > xBox(xControl, UNO_QUERY);
2353 if (xBox.is())
2355 xBox->addItemListener(this);
2356 break;
2359 Reference< XComboBox > xCbBox(xControl, UNO_QUERY);
2360 if (xCbBox.is())
2362 xCbBox->addItemListener(this);
2363 break;
2366 Reference< XListBox > xListBox(xControl, UNO_QUERY);
2367 if (xListBox.is())
2369 xListBox->addItemListener(this);
2370 break;
2372 break;
2376 //------------------------------------------------------------------------------
2377 void FormController::stopControlModifyListening(const Reference< XControl > & xControl)
2379 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2381 bool bModifyListening = lcl_shouldListenForModifications( xControl, NULL );
2383 // kuenstliches while
2384 while (bModifyListening)
2386 Reference< XModifyBroadcaster > xMod(xControl, UNO_QUERY);
2387 if (xMod.is())
2389 xMod->removeModifyListener(this);
2390 break;
2392 // alle die Text um vorzeitig ein modified zu erkennen
2393 Reference< XTextComponent > xText(xControl, UNO_QUERY);
2394 if (xText.is())
2396 xText->removeTextListener(this);
2397 break;
2400 Reference< XCheckBox > xBox(xControl, UNO_QUERY);
2401 if (xBox.is())
2403 xBox->removeItemListener(this);
2404 break;
2407 Reference< XComboBox > xCbBox(xControl, UNO_QUERY);
2408 if (xCbBox.is())
2410 xCbBox->removeItemListener(this);
2411 break;
2414 Reference< XListBox > xListBox(xControl, UNO_QUERY);
2415 if (xListBox.is())
2417 xListBox->removeItemListener(this);
2418 break;
2420 break;
2424 //------------------------------------------------------------------------------
2425 void FormController::startListening()
2427 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2428 m_bModified = sal_False;
2430 // jetzt anmelden bei gebundenen feldern
2431 const Reference< XControl >* pControls = m_aControls.getConstArray();
2432 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2433 while ( pControls != pControlsEnd )
2434 startControlModifyListening( *pControls++ );
2437 //------------------------------------------------------------------------------
2438 void FormController::stopListening()
2440 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2441 m_bModified = sal_False;
2443 // jetzt anmelden bei gebundenen feldern
2444 const Reference< XControl >* pControls = m_aControls.getConstArray();
2445 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2446 while ( pControls != pControlsEnd )
2447 stopControlModifyListening( *pControls++ );
2451 //------------------------------------------------------------------------------
2452 Reference< XControl > FormController::findControl(Sequence< Reference< XControl > >& _rControls, const Reference< XControlModel > & xCtrlModel ,sal_Bool _bRemove,sal_Bool _bOverWrite) const
2454 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2455 DBG_ASSERT( xCtrlModel.is(), "findControl - welches ?!" );
2457 Reference< XControl >* pControls = _rControls.getArray();
2458 Reference< XControlModel > xModel;
2459 for ( sal_Int32 i = 0, nCount = _rControls.getLength(); i < nCount; ++i, ++pControls )
2461 if ( pControls->is() )
2463 xModel = (*pControls)->getModel();
2464 if ( xModel.get() == xCtrlModel.get() )
2466 Reference< XControl > xControl( *pControls );
2467 if ( _bRemove )
2468 ::comphelper::removeElementAt( _rControls, i );
2469 else if ( _bOverWrite )
2470 *pControls = Reference< XControl >();
2471 return xControl;
2475 return Reference< XControl > ();
2478 //------------------------------------------------------------------------------
2479 void FormController::implControlInserted( const Reference< XControl>& _rxControl, bool _bAddToEventAttacher )
2481 Reference< XWindow > xWindow( _rxControl, UNO_QUERY );
2482 if ( xWindow.is() )
2484 xWindow->addFocusListener( this );
2485 xWindow->addMouseListener( this );
2487 if ( _bAddToEventAttacher )
2488 addToEventAttacher( _rxControl );
2491 // add a dispatch interceptor to the control (if supported)
2492 Reference< XDispatchProviderInterception > xInterception( _rxControl, UNO_QUERY );
2493 if ( xInterception.is() )
2494 createInterceptor( xInterception );
2496 if ( _rxControl.is() )
2498 Reference< XControlModel > xModel( _rxControl->getModel() );
2500 // we want to know about the reset of the the model of our controls
2501 // (for correctly resetting m_bModified)
2502 Reference< XReset > xReset( xModel, UNO_QUERY );
2503 if ( xReset.is() )
2504 xReset->addResetListener( this );
2506 // and we want to know about the validity, to visually indicate it
2507 Reference< XValidatableFormComponent > xValidatable( xModel, UNO_QUERY );
2508 if ( xValidatable.is() )
2510 xValidatable->addFormComponentValidityListener( this );
2511 m_pControlBorderManager->validityChanged( _rxControl, xValidatable );
2517 //------------------------------------------------------------------------------
2518 void FormController::implControlRemoved( const Reference< XControl>& _rxControl, bool _bRemoveFromEventAttacher )
2520 Reference< XWindow > xWindow( _rxControl, UNO_QUERY );
2521 if ( xWindow.is() )
2523 xWindow->removeFocusListener( this );
2524 xWindow->removeMouseListener( this );
2526 if ( _bRemoveFromEventAttacher )
2527 removeFromEventAttacher( _rxControl );
2530 Reference< XDispatchProviderInterception > xInterception( _rxControl, UNO_QUERY);
2531 if ( xInterception.is() )
2532 deleteInterceptor( xInterception );
2534 if ( _rxControl.is() )
2536 Reference< XControlModel > xModel( _rxControl->getModel() );
2538 Reference< XReset > xReset( xModel, UNO_QUERY );
2539 if ( xReset.is() )
2540 xReset->removeResetListener( this );
2542 Reference< XValidatableFormComponent > xValidatable( xModel, UNO_QUERY );
2543 if ( xValidatable.is() )
2544 xValidatable->removeFormComponentValidityListener( this );
2548 //------------------------------------------------------------------------------
2549 void FormController::implSetCurrentControl( const Reference< XControl >& _rxControl )
2551 if ( m_xCurrentControl.get() == _rxControl.get() )
2552 return;
2554 Reference< XGridControl > xGridControl( m_xCurrentControl, UNO_QUERY );
2555 if ( xGridControl.is() )
2556 xGridControl->removeGridControlListener( this );
2558 m_xCurrentControl = _rxControl;
2560 xGridControl.set( m_xCurrentControl, UNO_QUERY );
2561 if ( xGridControl.is() )
2562 xGridControl->addGridControlListener( this );
2565 //------------------------------------------------------------------------------
2566 void FormController::insertControl(const Reference< XControl > & xControl)
2568 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2569 m_bControlsSorted = sal_False;
2570 m_aControls.realloc(m_aControls.getLength() + 1);
2571 m_aControls.getArray()[m_aControls.getLength() - 1] = xControl;
2573 if ( m_pColumnInfoCache.get() )
2574 m_pColumnInfoCache->deinitializeControls();
2576 implControlInserted( xControl, m_bAttachEvents );
2578 if (m_bDBConnection && !m_bFiltering)
2579 setControlLock(xControl);
2581 if (isListeningForChanges() && m_bAttachEvents)
2582 startControlModifyListening( xControl );
2585 //------------------------------------------------------------------------------
2586 void FormController::removeControl(const Reference< XControl > & xControl)
2588 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2589 const Reference< XControl >* pControls = m_aControls.getConstArray();
2590 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2591 while ( pControls != pControlsEnd )
2593 if ( xControl.get() == (*pControls++).get() )
2595 ::comphelper::removeElementAt( m_aControls, pControls - m_aControls.getConstArray() - 1 );
2596 break;
2600 FilterComponents::iterator componentPos = ::std::find( m_aFilterComponents.begin(), m_aFilterComponents.end(), xControl );
2601 if ( componentPos != m_aFilterComponents.end() )
2602 m_aFilterComponents.erase( componentPos );
2604 implControlRemoved( xControl, m_bDetachEvents );
2606 if ( isListeningForChanges() && m_bDetachEvents )
2607 stopControlModifyListening( xControl );
2610 // XLoadListener
2611 //------------------------------------------------------------------------------
2612 void FormController::loaded(const EventObject& rEvent) throw( RuntimeException )
2614 OSL_ENSURE( rEvent.Source == m_xModelAsIndex, "FormController::loaded: where did this come from?" );
2616 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2617 ::osl::MutexGuard aGuard( m_aMutex );
2618 Reference< XRowSet > xForm(rEvent.Source, UNO_QUERY);
2619 // do we have a connected data source
2620 OStaticDataAccessTools aStaticTools;
2621 if (xForm.is() && aStaticTools.getRowSetConnection(xForm).is())
2623 Reference< XPropertySet > xSet(xForm, UNO_QUERY);
2624 if (xSet.is())
2626 Any aVal = xSet->getPropertyValue(FM_PROP_CYCLE);
2627 sal_Int32 aVal2 = 0;
2628 ::cppu::enum2int(aVal2,aVal);
2629 m_bCycle = !aVal.hasValue() || aVal2 == TabulatorCycle_RECORDS;
2630 m_bCanUpdate = aStaticTools.canUpdate(xSet);
2631 m_bCanInsert = aStaticTools.canInsert(xSet);
2632 m_bCurrentRecordModified = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED));
2633 m_bCurrentRecordNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
2635 startFormListening( xSet, sal_False );
2637 // set the locks for the current controls
2638 if (getContainer().is())
2640 m_aLoadEvent.Call();
2643 else
2645 m_bCanInsert = m_bCanUpdate = m_bCycle = sal_False;
2646 m_bCurrentRecordModified = sal_False;
2647 m_bCurrentRecordNew = sal_False;
2648 m_bLocked = sal_False;
2650 m_bDBConnection = sal_True;
2652 else
2654 m_bDBConnection = sal_False;
2655 m_bCanInsert = m_bCanUpdate = m_bCycle = sal_False;
2656 m_bCurrentRecordModified = sal_False;
2657 m_bCurrentRecordNew = sal_False;
2658 m_bLocked = sal_False;
2661 Reference< XColumnsSupplier > xFormColumns( xForm, UNO_QUERY );
2662 m_pColumnInfoCache.reset( xFormColumns.is() ? new ColumnInfoCache( xFormColumns ) : NULL );
2664 updateAllDispatchers();
2667 //------------------------------------------------------------------------------
2668 void FormController::updateAllDispatchers() const
2670 ::std::for_each(
2671 m_aFeatureDispatchers.begin(),
2672 m_aFeatureDispatchers.end(),
2673 ::o3tl::compose1(
2674 UpdateAllListeners(),
2675 ::o3tl::select2nd< DispatcherContainer::value_type >()
2680 //------------------------------------------------------------------------------
2681 IMPL_LINK_NOARG(FormController, OnLoad)
2683 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2684 m_bLocked = determineLockState();
2686 setLocks();
2688 if (!m_bLocked)
2689 startListening();
2691 // just one exception toggle the auto values
2692 if (m_bCurrentRecordNew)
2693 toggleAutoFields(sal_True);
2695 return 1L;
2698 //------------------------------------------------------------------------------
2699 void FormController::unloaded(const EventObject& /*rEvent*/) throw( RuntimeException )
2701 ::osl::MutexGuard aGuard( m_aMutex );
2702 impl_checkDisposed_throw();
2704 updateAllDispatchers();
2707 //------------------------------------------------------------------------------
2708 void FormController::reloading(const EventObject& /*aEvent*/) throw( RuntimeException )
2710 ::osl::MutexGuard aGuard( m_aMutex );
2711 impl_checkDisposed_throw();
2713 // do the same like in unloading
2714 // just one exception toggle the auto values
2715 m_aToggleEvent.CancelPendingCall();
2716 unload();
2719 //------------------------------------------------------------------------------
2720 void FormController::reloaded(const EventObject& aEvent) throw( RuntimeException )
2722 ::osl::MutexGuard aGuard( m_aMutex );
2723 impl_checkDisposed_throw();
2725 loaded(aEvent);
2728 //------------------------------------------------------------------------------
2729 void FormController::unloading(const EventObject& /*aEvent*/) throw( RuntimeException )
2731 ::osl::MutexGuard aGuard( m_aMutex );
2732 impl_checkDisposed_throw();
2734 unload();
2737 //------------------------------------------------------------------------------
2738 void FormController::unload() throw( RuntimeException )
2740 ::osl::MutexGuard aGuard( m_aMutex );
2741 impl_checkDisposed_throw();
2743 m_aLoadEvent.CancelPendingCall();
2745 // be sure not to have autofields
2746 if (m_bCurrentRecordNew)
2747 toggleAutoFields(sal_False);
2749 // remove bound field listing again
2750 removeBoundFieldListener();
2752 if (m_bDBConnection && isListeningForChanges())
2753 stopListening();
2755 Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
2756 if ( m_bDBConnection && xSet.is() )
2757 stopFormListening( xSet, sal_False );
2759 m_bDBConnection = sal_False;
2760 m_bCanInsert = m_bCanUpdate = m_bCycle = sal_False;
2761 m_bCurrentRecordModified = m_bCurrentRecordNew = m_bLocked = sal_False;
2763 m_pColumnInfoCache.reset( NULL );
2766 // -----------------------------------------------------------------------------
2767 void FormController::removeBoundFieldListener()
2769 const Reference< XControl >* pControls = m_aControls.getConstArray();
2770 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2771 while ( pControls != pControlsEnd )
2773 Reference< XPropertySet > xProp( *pControls++, UNO_QUERY );
2774 if ( xProp.is() )
2775 xProp->removePropertyChangeListener( FM_PROP_BOUNDFIELD, this );
2779 //------------------------------------------------------------------------------
2780 void FormController::startFormListening( const Reference< XPropertySet >& _rxForm, sal_Bool _bPropertiesOnly )
2784 if ( m_bCanInsert || m_bCanUpdate ) // form can be modified
2786 _rxForm->addPropertyChangeListener( FM_PROP_ISNEW, this );
2787 _rxForm->addPropertyChangeListener( FM_PROP_ISMODIFIED, this );
2789 if ( !_bPropertiesOnly )
2791 // set the Listener for UI interaction
2792 Reference< XRowSetApproveBroadcaster > xApprove( _rxForm, UNO_QUERY );
2793 if ( xApprove.is() )
2794 xApprove->addRowSetApproveListener( this );
2796 // listener for row set changes
2797 Reference< XRowSet > xRowSet( _rxForm, UNO_QUERY );
2798 if ( xRowSet.is() )
2799 xRowSet->addRowSetListener( this );
2803 Reference< XPropertySetInfo > xInfo = _rxForm->getPropertySetInfo();
2804 if ( xInfo.is() && xInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) )
2805 _rxForm->addPropertyChangeListener( FM_PROP_DYNAMIC_CONTROL_BORDER, this );
2807 catch( const Exception& )
2809 DBG_UNHANDLED_EXCEPTION();
2813 //------------------------------------------------------------------------------
2814 void FormController::stopFormListening( const Reference< XPropertySet >& _rxForm, sal_Bool _bPropertiesOnly )
2818 if ( m_bCanInsert || m_bCanUpdate )
2820 _rxForm->removePropertyChangeListener( FM_PROP_ISNEW, this );
2821 _rxForm->removePropertyChangeListener( FM_PROP_ISMODIFIED, this );
2823 if ( !_bPropertiesOnly )
2825 Reference< XRowSetApproveBroadcaster > xApprove( _rxForm, UNO_QUERY );
2826 if (xApprove.is())
2827 xApprove->removeRowSetApproveListener(this);
2829 Reference< XRowSet > xRowSet( _rxForm, UNO_QUERY );
2830 if ( xRowSet.is() )
2831 xRowSet->removeRowSetListener( this );
2835 Reference< XPropertySetInfo > xInfo = _rxForm->getPropertySetInfo();
2836 if ( xInfo.is() && xInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) )
2837 _rxForm->removePropertyChangeListener( FM_PROP_DYNAMIC_CONTROL_BORDER, this );
2839 catch( const Exception& )
2841 DBG_UNHANDLED_EXCEPTION();
2845 // com::sun::star::sdbc::XRowSetListener
2846 //------------------------------------------------------------------------------
2847 void FormController::cursorMoved(const EventObject& /*event*/) throw( RuntimeException )
2849 ::osl::MutexGuard aGuard( m_aMutex );
2850 impl_checkDisposed_throw();
2852 // toggle the locking ?
2853 if (m_bLocked != determineLockState())
2855 m_bLocked = !m_bLocked;
2856 setLocks();
2857 if (isListeningForChanges())
2858 startListening();
2859 else
2860 stopListening();
2863 // neither the current control nor the current record are modified anymore
2864 m_bCurrentRecordModified = m_bModified = sal_False;
2867 //------------------------------------------------------------------------------
2868 void FormController::rowChanged(const EventObject& /*event*/) throw( RuntimeException )
2870 // not interested in ...
2872 //------------------------------------------------------------------------------
2873 void FormController::rowSetChanged(const EventObject& /*event*/) throw( RuntimeException )
2875 // not interested in ...
2879 // XContainerListener
2880 //------------------------------------------------------------------------------
2881 void SAL_CALL FormController::elementInserted(const ContainerEvent& evt) throw( RuntimeException )
2883 ::osl::MutexGuard aGuard( m_aMutex );
2884 impl_checkDisposed_throw();
2886 Reference< XControl > xControl( evt.Element, UNO_QUERY );
2887 if ( !xControl.is() )
2888 return;
2890 Reference< XFormComponent > xModel(xControl->getModel(), UNO_QUERY);
2891 if (xModel.is() && m_xModelAsIndex == xModel->getParent())
2893 insertControl(xControl);
2895 if ( m_aTabActivationTimer.IsActive() )
2896 m_aTabActivationTimer.Stop();
2898 m_aTabActivationTimer.Start();
2900 // are we in filtermode and a XModeSelector has inserted an element
2901 else if (m_bFiltering && Reference< XModeSelector > (evt.Source, UNO_QUERY).is())
2903 xModel = Reference< XFormComponent > (evt.Source, UNO_QUERY);
2904 if (xModel.is() && m_xModelAsIndex == xModel->getParent())
2906 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
2907 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
2909 // does the model use a bound field ?
2910 Reference< XPropertySet > xField;
2911 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
2913 Reference< XTextComponent > xText(xControl, UNO_QUERY);
2914 // may we filter the field?
2915 if (xText.is() && xField.is() && ::comphelper::hasProperty(FM_PROP_SEARCHABLE, xField) &&
2916 ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_SEARCHABLE)))
2918 m_aFilterComponents.push_back( xText );
2919 xText->addTextListener( this );
2926 //------------------------------------------------------------------------------
2927 void SAL_CALL FormController::elementReplaced(const ContainerEvent& evt) throw( RuntimeException )
2929 // simulate an elementRemoved
2930 ContainerEvent aRemoveEvent( evt );
2931 aRemoveEvent.Element = evt.ReplacedElement;
2932 aRemoveEvent.ReplacedElement = Any();
2933 elementRemoved( aRemoveEvent );
2935 // simulate an elementInserted
2936 ContainerEvent aInsertEvent( evt );
2937 aInsertEvent.ReplacedElement = Any();
2938 elementInserted( aInsertEvent );
2941 //------------------------------------------------------------------------------
2942 void SAL_CALL FormController::elementRemoved(const ContainerEvent& evt) throw( RuntimeException )
2944 ::osl::MutexGuard aGuard( m_aMutex );
2945 impl_checkDisposed_throw();
2947 Reference< XControl > xControl;
2948 evt.Element >>= xControl;
2949 if (!xControl.is())
2950 return;
2952 Reference< XFormComponent > xModel(xControl->getModel(), UNO_QUERY);
2953 if (xModel.is() && m_xModelAsIndex == xModel->getParent())
2955 removeControl(xControl);
2956 // TabOrder nicht neu berechnen, da das intern schon funktionieren mu�!
2958 // are we in filtermode and a XModeSelector has inserted an element
2959 else if (m_bFiltering && Reference< XModeSelector > (evt.Source, UNO_QUERY).is())
2961 FilterComponents::iterator componentPos = ::std::find(
2962 m_aFilterComponents.begin(), m_aFilterComponents.end(), xControl );
2963 if ( componentPos != m_aFilterComponents.end() )
2964 m_aFilterComponents.erase( componentPos );
2968 //------------------------------------------------------------------------------
2969 Reference< XControl > FormController::isInList(const Reference< XWindowPeer > & xPeer) const
2971 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2972 const Reference< XControl >* pControls = m_aControls.getConstArray();
2974 sal_uInt32 nCtrls = m_aControls.getLength();
2975 for ( sal_uInt32 n = 0; n < nCtrls && xPeer.is(); ++n, ++pControls )
2977 if ( pControls->is() )
2979 Reference< XVclWindowPeer > xCtrlPeer( (*pControls)->getPeer(), UNO_QUERY);
2980 if ( ( xCtrlPeer.get() == xPeer.get() ) || xCtrlPeer->isChild( xPeer ) )
2981 return *pControls;
2984 return Reference< XControl > ();
2987 //------------------------------------------------------------------------------
2988 void FormController::activateFirst() throw( RuntimeException )
2990 ::osl::MutexGuard aGuard( m_aMutex );
2991 impl_checkDisposed_throw();
2993 DBG_ASSERT(m_xTabController.is(), "FormController::activateFirst : invalid aggregate !");
2994 if (m_xTabController.is())
2995 m_xTabController->activateFirst();
2998 //------------------------------------------------------------------------------
2999 void FormController::activateLast() throw( RuntimeException )
3001 ::osl::MutexGuard aGuard( m_aMutex );
3002 impl_checkDisposed_throw();
3004 DBG_ASSERT(m_xTabController.is(), "FormController::activateLast : invalid aggregate !");
3005 if (m_xTabController.is())
3006 m_xTabController->activateLast();
3009 // XFormController
3010 //------------------------------------------------------------------------------
3011 Reference< XFormOperations > SAL_CALL FormController::getFormOperations() throw (RuntimeException)
3013 ::osl::MutexGuard aGuard( m_aMutex );
3014 impl_checkDisposed_throw();
3016 return m_xFormOperations;
3019 //------------------------------------------------------------------------------
3020 Reference< XControl> SAL_CALL FormController::getCurrentControl(void) throw( RuntimeException )
3022 ::osl::MutexGuard aGuard( m_aMutex );
3023 impl_checkDisposed_throw();
3024 return m_xCurrentControl;
3027 //------------------------------------------------------------------------------
3028 void SAL_CALL FormController::addActivateListener(const Reference< XFormControllerListener > & l) throw( RuntimeException )
3030 ::osl::MutexGuard aGuard( m_aMutex );
3031 impl_checkDisposed_throw();
3032 m_aActivateListeners.addInterface(l);
3034 //------------------------------------------------------------------------------
3035 void SAL_CALL FormController::removeActivateListener(const Reference< XFormControllerListener > & l) throw( RuntimeException )
3037 ::osl::MutexGuard aGuard( m_aMutex );
3038 impl_checkDisposed_throw();
3039 m_aActivateListeners.removeInterface(l);
3042 //------------------------------------------------------------------------------
3043 void SAL_CALL FormController::addChildController( const Reference< XFormController >& _ChildController ) throw( RuntimeException, IllegalArgumentException )
3045 ::osl::MutexGuard aGuard( m_aMutex );
3046 impl_checkDisposed_throw();
3048 if ( !_ChildController.is() )
3049 throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
3050 // TODO: (localized) error message
3052 // the parent of our (to-be-)child must be our own model
3053 Reference< XFormComponent > xFormOfChild( _ChildController->getModel(), UNO_QUERY );
3054 if ( !xFormOfChild.is() )
3055 throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
3056 // TODO: (localized) error message
3058 if ( xFormOfChild->getParent() != m_xModelAsIndex )
3059 throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
3060 // TODO: (localized) error message
3062 m_aChildren.push_back( _ChildController );
3063 _ChildController->setParent( *this );
3065 // search the position of the model within the form
3066 sal_uInt32 nPos = m_xModelAsIndex->getCount();
3067 Reference< XFormComponent > xTemp;
3068 for( ; nPos; )
3070 m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
3071 if ( xFormOfChild == xTemp )
3073 Reference< XInterface > xIfc( _ChildController, UNO_QUERY );
3074 m_xModelAsManager->attach( nPos, xIfc, makeAny( _ChildController) );
3075 break;
3080 //------------------------------------------------------------------------------
3081 Reference< XFormControllerContext > SAL_CALL FormController::getContext() throw (RuntimeException)
3083 ::osl::MutexGuard aGuard( m_aMutex );
3084 impl_checkDisposed_throw();
3085 return m_xContext;
3088 //------------------------------------------------------------------------------
3089 void SAL_CALL FormController::setContext( const Reference< XFormControllerContext >& _context ) throw (RuntimeException)
3091 ::osl::MutexGuard aGuard( m_aMutex );
3092 impl_checkDisposed_throw();
3093 m_xContext = _context;
3096 //------------------------------------------------------------------------------
3097 Reference< XInteractionHandler > SAL_CALL FormController::getInteractionHandler() throw (RuntimeException)
3099 ::osl::MutexGuard aGuard( m_aMutex );
3100 impl_checkDisposed_throw();
3101 return m_xInteractionHandler;
3104 //------------------------------------------------------------------------------
3105 void SAL_CALL FormController::setInteractionHandler( const Reference< XInteractionHandler >& _interactionHandler ) throw (RuntimeException)
3107 ::osl::MutexGuard aGuard( m_aMutex );
3108 impl_checkDisposed_throw();
3109 m_xInteractionHandler = _interactionHandler;
3112 //------------------------------------------------------------------------------
3113 void FormController::setFilter(::std::vector<FmFieldInfo>& rFieldInfos)
3115 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3116 // create the composer
3117 Reference< XRowSet > xForm(m_xModelAsIndex, UNO_QUERY);
3118 Reference< XConnection > xConnection(OStaticDataAccessTools().getRowSetConnection(xForm));
3119 if (xForm.is())
3123 Reference< XMultiServiceFactory > xFactory( xConnection, UNO_QUERY_THROW );
3124 m_xComposer.set(
3125 xFactory->createInstance( ::rtl::OUString( "com.sun.star.sdb.SingleSelectQueryComposer" ) ),
3126 UNO_QUERY_THROW );
3128 Reference< XPropertySet > xSet( xForm, UNO_QUERY );
3129 ::rtl::OUString sStatement = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_ACTIVECOMMAND ) );
3130 ::rtl::OUString sFilter = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_FILTER ) );
3131 m_xComposer->setElementaryQuery( sStatement );
3132 m_xComposer->setFilter( sFilter );
3134 catch( const Exception& )
3136 DBG_UNHANDLED_EXCEPTION();
3140 if (m_xComposer.is())
3142 Sequence < PropertyValue> aLevel;
3143 Sequence< Sequence < PropertyValue > > aFilterRows = m_xComposer->getStructuredFilter();
3145 // ok, we recieve the list of filters as sequence of fieldnames, value
3146 // now we have to transform the fieldname into UI names, that could be a label of the field or
3147 // a aliasname or the fieldname itself
3149 // first adjust the field names if necessary
3150 Reference< XNameAccess > xQueryColumns =
3151 Reference< XColumnsSupplier >( m_xComposer, UNO_QUERY_THROW )->getColumns();
3153 for (::std::vector<FmFieldInfo>::iterator iter = rFieldInfos.begin();
3154 iter != rFieldInfos.end(); ++iter)
3156 if ( xQueryColumns->hasByName((*iter).aFieldName) )
3158 if ( (xQueryColumns->getByName((*iter).aFieldName) >>= (*iter).xField) && (*iter).xField.is() )
3159 (*iter).xField->getPropertyValue(FM_PROP_REALNAME) >>= (*iter).aFieldName;
3163 Reference< XDatabaseMetaData> xMetaData(xConnection->getMetaData());
3164 // now transfer the filters into Value/TextComponent pairs
3165 ::comphelper::UStringMixEqual aCompare(xMetaData->storesMixedCaseQuotedIdentifiers());
3167 // need to parse criteria localized
3168 OStaticDataAccessTools aStaticTools;
3169 Reference< XNumberFormatsSupplier> xFormatSupplier( aStaticTools.getNumberFormats(xConnection, sal_True));
3170 Reference< XNumberFormatter> xFormatter( m_aContext.createComponent( "com.sun.star.util.NumberFormatter" ), UNO_QUERY );
3171 xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
3172 Locale aAppLocale = Application::GetSettings().GetUILocale();
3173 LocaleDataWrapper aLocaleWrapper( m_aContext.getLegacyServiceFactory(), aAppLocale );
3175 // retrieving the filter
3176 const Sequence < PropertyValue >* pRow = aFilterRows.getConstArray();
3177 for (sal_Int32 i = 0, nLen = aFilterRows.getLength(); i < nLen; ++i)
3179 FmFilterRow aRow;
3181 // search a field for the given name
3182 const PropertyValue* pRefValues = pRow[i].getConstArray();
3183 for (sal_Int32 j = 0, nLen1 = pRow[i].getLength(); j < nLen1; j++)
3185 // look for the text component
3186 Reference< XPropertySet > xField;
3189 Reference< XPropertySet > xSet;
3190 ::rtl::OUString aRealName;
3192 // first look with the given name
3193 if (xQueryColumns->hasByName(pRefValues[j].Name))
3195 xQueryColumns->getByName(pRefValues[j].Name) >>= xSet;
3197 // get the RealName
3198 xSet->getPropertyValue(::rtl::OUString("RealName")) >>= aRealName;
3200 // compare the condition field name and the RealName
3201 if (aCompare(aRealName, pRefValues[j].Name))
3202 xField = xSet;
3204 if (!xField.is())
3206 // no we have to check every column to find the realname
3207 Reference< XIndexAccess > xColumnsByIndex(xQueryColumns, UNO_QUERY);
3208 for (sal_Int32 n = 0, nCount = xColumnsByIndex->getCount(); n < nCount; n++)
3210 xColumnsByIndex->getByIndex(n) >>= xSet;
3211 xSet->getPropertyValue(::rtl::OUString("RealName")) >>= aRealName;
3212 if (aCompare(aRealName, pRefValues[j].Name))
3214 // get the column by its alias
3215 xField = xSet;
3216 break;
3220 if (!xField.is())
3221 continue;
3223 catch (const Exception&)
3225 continue;
3228 // find the text component
3229 for (::std::vector<FmFieldInfo>::iterator iter = rFieldInfos.begin();
3230 iter != rFieldInfos.end(); ++iter)
3232 // we found the field so insert a new entry to the filter row
3233 if ((*iter).xField == xField)
3235 // do we already have the control ?
3236 if (aRow.find((*iter).xText) != aRow.end())
3238 ::rtl::OUString aCompText = aRow[(*iter).xText];
3239 aCompText += ::rtl::OUString(" ");
3240 ::rtl::OString aVal = m_xParser->getContext().getIntlKeywordAscii(OParseContext::KEY_AND);
3241 aCompText += ::rtl::OUString(aVal.getStr(),aVal.getLength(),RTL_TEXTENCODING_ASCII_US);
3242 aCompText += ::rtl::OUString(" ");
3243 aCompText += ::comphelper::getString(pRefValues[j].Value);
3244 aRow[(*iter).xText] = aCompText;
3246 else
3248 ::rtl::OUString sPredicate,sErrorMsg;
3249 pRefValues[j].Value >>= sPredicate;
3250 ::rtl::Reference< ISQLParseNode > xParseNode = predicateTree(sErrorMsg, sPredicate, xFormatter, xField);
3251 if ( xParseNode.is() )
3253 ::rtl::OUString sCriteria;
3254 xParseNode->parseNodeToPredicateStr( sCriteria
3255 ,xConnection
3256 ,xFormatter
3257 ,xField
3258 ,aAppLocale
3259 ,(sal_Char)aLocaleWrapper.getNumDecimalSep().GetChar(0)
3260 ,getParseContext());
3261 aRow[(*iter).xText] = sCriteria;
3268 if (aRow.empty())
3269 continue;
3271 impl_addFilterRow( aRow );
3275 // now set the filter controls
3276 for ( ::std::vector<FmFieldInfo>::iterator field = rFieldInfos.begin();
3277 field != rFieldInfos.end();
3278 ++field
3281 m_aFilterComponents.push_back( field->xText );
3285 //------------------------------------------------------------------------------
3286 void FormController::startFiltering()
3288 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3290 OStaticDataAccessTools aStaticTools;
3291 Reference< XConnection > xConnection( aStaticTools.getRowSetConnection( Reference< XRowSet >( m_xModelAsIndex, UNO_QUERY ) ) );
3292 if ( !xConnection.is() )
3293 // nothing to do - can't filter a form which is not connected
3294 return;
3296 // stop listening for controls
3297 if (isListeningForChanges())
3298 stopListening();
3300 m_bFiltering = sal_True;
3302 // as we don't want new controls to be attached to the scripting environment
3303 // we change attach flags
3304 m_bAttachEvents = sal_False;
3306 // Austauschen der Kontrols fuer das aktuelle Formular
3307 Sequence< Reference< XControl > > aControlsCopy( m_aControls );
3308 const Reference< XControl >* pControls = aControlsCopy.getConstArray();
3309 sal_Int32 nControlCount = aControlsCopy.getLength();
3311 // the control we have to activate after replacement
3312 Reference< XDatabaseMetaData > xMetaData(xConnection->getMetaData());
3313 Reference< XNumberFormatsSupplier > xFormatSupplier = aStaticTools.getNumberFormats(xConnection, sal_True);
3314 Reference< XNumberFormatter > xFormatter( m_aContext.createComponent( "com.sun.star.util.NumberFormatter" ), UNO_QUERY );
3315 xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
3317 // structure for storing the field info
3318 ::std::vector<FmFieldInfo> aFieldInfos;
3320 for (sal_Int32 i = nControlCount; i > 0;)
3322 Reference< XControl > xControl = pControls[--i];
3323 if (xControl.is())
3325 // no events for the control anymore
3326 removeFromEventAttacher(xControl);
3328 // do we have a mode selector
3329 Reference< XModeSelector > xSelector(xControl, UNO_QUERY);
3330 if (xSelector.is())
3332 xSelector->setMode( ::rtl::OUString( "FilterMode" ) );
3334 // listening for new controls of the selector
3335 Reference< XContainer > xContainer(xSelector, UNO_QUERY);
3336 if (xContainer.is())
3337 xContainer->addContainerListener(this);
3339 Reference< XEnumerationAccess > xElementAccess(xSelector, UNO_QUERY);
3340 if (xElementAccess.is())
3342 Reference< XEnumeration > xEnumeration(xElementAccess->createEnumeration());
3343 Reference< XControl > xSubControl;
3344 while (xEnumeration->hasMoreElements())
3346 xEnumeration->nextElement() >>= xSubControl;
3347 if (xSubControl.is())
3349 Reference< XPropertySet > xSet(xSubControl->getModel(), UNO_QUERY);
3350 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
3352 // does the model use a bound field ?
3353 Reference< XPropertySet > xField;
3354 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
3356 Reference< XTextComponent > xText(xSubControl, UNO_QUERY);
3357 // may we filter the field?
3358 if (xText.is() && xField.is() && ::comphelper::hasProperty(FM_PROP_SEARCHABLE, xField) &&
3359 ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_SEARCHABLE)))
3361 aFieldInfos.push_back(FmFieldInfo(xField, xText));
3362 xText->addTextListener(this);
3368 continue;
3371 Reference< XPropertySet > xModel( xControl->getModel(), UNO_QUERY );
3372 if (xModel.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xModel))
3374 // does the model use a bound field ?
3375 Any aVal = xModel->getPropertyValue(FM_PROP_BOUNDFIELD);
3376 Reference< XPropertySet > xField;
3377 aVal >>= xField;
3379 // may we filter the field?
3381 if ( xField.is()
3382 && ::comphelper::hasProperty( FM_PROP_SEARCHABLE, xField )
3383 && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_SEARCHABLE ) )
3386 // create a filter control
3387 Sequence< Any > aCreationArgs( 3 );
3388 aCreationArgs[ 0 ] <<= NamedValue( ::rtl::OUString("MessageParent"), makeAny( VCLUnoHelper::GetInterface( getDialogParentWindow() ) ) );
3389 aCreationArgs[ 1 ] <<= NamedValue( ::rtl::OUString("NumberFormatter"), makeAny( xFormatter ) );
3390 aCreationArgs[ 2 ] <<= NamedValue( ::rtl::OUString("ControlModel"), makeAny( xModel ) );
3391 Reference< XControl > xFilterControl(
3392 m_aContext.createComponentWithArguments( "com.sun.star.form.control.FilterControl", aCreationArgs ),
3393 UNO_QUERY
3395 DBG_ASSERT( xFilterControl.is(), "FormController::startFiltering: could not create a filter control!" );
3397 if ( replaceControl( xControl, xFilterControl ) )
3399 Reference< XTextComponent > xFilterText( xFilterControl, UNO_QUERY );
3400 aFieldInfos.push_back( FmFieldInfo( xField, xFilterText ) );
3401 xFilterText->addTextListener(this);
3405 else
3407 // abmelden vom EventManager
3412 // we have all filter controls now, so the next step is to read the filters from the form
3413 // resolve all aliases and set the current filter to the according structure
3414 setFilter(aFieldInfos);
3416 Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
3417 if ( xSet.is() )
3418 stopFormListening( xSet, sal_True );
3420 impl_setTextOnAllFilter_throw();
3422 // lock all controls which are not used for filtering
3423 m_bLocked = determineLockState();
3424 setLocks();
3425 m_bAttachEvents = sal_True;
3428 //------------------------------------------------------------------------------
3429 void FormController::stopFiltering()
3431 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3432 if ( !m_bFiltering ) // #104693# OJ
3433 { // nothing to do
3434 return;
3437 m_bFiltering = sal_False;
3438 m_bDetachEvents = sal_False;
3440 ::comphelper::disposeComponent(m_xComposer);
3442 // Austauschen der Kontrols fuer das aktuelle Formular
3443 Sequence< Reference< XControl > > aControlsCopy( m_aControls );
3444 const Reference< XControl > * pControls = aControlsCopy.getConstArray();
3445 sal_Int32 nControlCount = aControlsCopy.getLength();
3447 // clear the filter control map
3448 ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), RemoveComponentTextListener( this ) );
3449 m_aFilterComponents.clear();
3451 for ( sal_Int32 i = nControlCount; i > 0; )
3453 Reference< XControl > xControl = pControls[--i];
3454 if (xControl.is())
3456 // now enable eventhandling again
3457 addToEventAttacher(xControl);
3459 Reference< XModeSelector > xSelector(xControl, UNO_QUERY);
3460 if (xSelector.is())
3462 xSelector->setMode( ::rtl::OUString( "DataMode" ) );
3464 // listening for new controls of the selector
3465 Reference< XContainer > xContainer(xSelector, UNO_QUERY);
3466 if (xContainer.is())
3467 xContainer->removeContainerListener(this);
3468 continue;
3471 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
3472 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
3474 // does the model use a bound field ?
3475 Reference< XPropertySet > xField;
3476 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
3478 // may we filter the field?
3479 if ( xField.is()
3480 && ::comphelper::hasProperty( FM_PROP_SEARCHABLE, xField )
3481 && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_SEARCHABLE ) )
3484 ::rtl::OUString sServiceName;
3485 OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DEFAULTCONTROL ) >>= sServiceName );
3486 Reference< XControl > xNewControl( m_aContext.createComponent( sServiceName ), UNO_QUERY );
3487 replaceControl( xControl, xNewControl );
3493 Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
3494 if ( xSet.is() )
3495 startFormListening( xSet, sal_True );
3497 m_bDetachEvents = sal_True;
3499 m_aFilterRows.clear();
3500 m_nCurrentFilterPosition = -1;
3502 // release the locks if possible
3503 // lock all controls which are not used for filtering
3504 m_bLocked = determineLockState();
3505 setLocks();
3507 // restart listening for control modifications
3508 if (isListeningForChanges())
3509 startListening();
3512 // XModeSelector
3513 //------------------------------------------------------------------------------
3514 void FormController::setMode(const ::rtl::OUString& Mode) throw( NoSupportException, RuntimeException )
3516 ::osl::MutexGuard aGuard( m_aMutex );
3517 impl_checkDisposed_throw();
3519 if (!supportsMode(Mode))
3520 throw NoSupportException();
3522 if (Mode == m_aMode)
3523 return;
3525 m_aMode = Mode;
3527 if ( Mode == "FilterMode" )
3528 startFiltering();
3529 else
3530 stopFiltering();
3532 for (FmFormControllers::const_iterator i = m_aChildren.begin();
3533 i != m_aChildren.end(); ++i)
3535 Reference< XModeSelector > xMode(*i, UNO_QUERY);
3536 if ( xMode.is() )
3537 xMode->setMode(Mode);
3541 //------------------------------------------------------------------------------
3542 ::rtl::OUString SAL_CALL FormController::getMode(void) throw( RuntimeException )
3544 ::osl::MutexGuard aGuard( m_aMutex );
3545 impl_checkDisposed_throw();
3547 return m_aMode;
3550 //------------------------------------------------------------------------------
3551 Sequence< ::rtl::OUString > SAL_CALL FormController::getSupportedModes(void) throw( RuntimeException )
3553 ::osl::MutexGuard aGuard( m_aMutex );
3554 impl_checkDisposed_throw();
3556 static Sequence< ::rtl::OUString > aModes;
3557 if (!aModes.getLength())
3559 aModes.realloc(2);
3560 ::rtl::OUString* pModes = aModes.getArray();
3561 pModes[0] = ::rtl::OUString( "DataMode" );
3562 pModes[1] = ::rtl::OUString( "FilterMode" );
3564 return aModes;
3567 //------------------------------------------------------------------------------
3568 sal_Bool SAL_CALL FormController::supportsMode(const ::rtl::OUString& Mode) throw( RuntimeException )
3570 ::osl::MutexGuard aGuard( m_aMutex );
3571 impl_checkDisposed_throw();
3573 Sequence< ::rtl::OUString > aModes(getSupportedModes());
3574 const ::rtl::OUString* pModes = aModes.getConstArray();
3575 for (sal_Int32 i = aModes.getLength(); i > 0; )
3577 if (pModes[--i] == Mode)
3578 return sal_True;
3580 return sal_False;
3583 //------------------------------------------------------------------------------
3584 Window* FormController::getDialogParentWindow()
3586 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3587 Window* pParentWindow = NULL;
3590 Reference< XControl > xContainerControl( getContainer(), UNO_QUERY_THROW );
3591 Reference< XWindowPeer > xContainerPeer( xContainerControl->getPeer(), UNO_QUERY_THROW );
3592 pParentWindow = VCLUnoHelper::GetWindow( xContainerPeer );
3594 catch( const Exception& )
3596 DBG_UNHANDLED_EXCEPTION();
3598 return pParentWindow;
3600 //------------------------------------------------------------------------------
3601 bool FormController::checkFormComponentValidity( ::rtl::OUString& /* [out] */ _rFirstInvalidityExplanation, Reference< XControlModel >& /* [out] */ _rxFirstInvalidModel ) SAL_THROW(())
3605 Reference< XEnumerationAccess > xControlEnumAcc( getModel(), UNO_QUERY );
3606 Reference< XEnumeration > xControlEnumeration;
3607 if ( xControlEnumAcc.is() )
3608 xControlEnumeration = xControlEnumAcc->createEnumeration();
3609 OSL_ENSURE( xControlEnumeration.is(), "FormController::checkFormComponentValidity: cannot enumerate the controls!" );
3610 if ( !xControlEnumeration.is() )
3611 // assume all valid
3612 return true;
3614 Reference< XValidatableFormComponent > xValidatable;
3615 while ( xControlEnumeration->hasMoreElements() )
3617 if ( !( xControlEnumeration->nextElement() >>= xValidatable ) )
3618 // control does not support validation
3619 continue;
3621 if ( xValidatable->isValid() )
3622 continue;
3624 Reference< XValidator > xValidator( xValidatable->getValidator() );
3625 OSL_ENSURE( xValidator.is(), "FormController::checkFormComponentValidity: invalid, but no validator?" );
3626 if ( !xValidator.is() )
3627 // this violates the interface definition of css.form.validation.XValidatableFormComponent ...
3628 continue;
3630 _rFirstInvalidityExplanation = xValidator->explainInvalid( xValidatable->getCurrentValue() );
3631 _rxFirstInvalidModel = _rxFirstInvalidModel.query( xValidatable );
3632 return false;
3635 catch( const Exception& )
3637 DBG_UNHANDLED_EXCEPTION();
3639 return true;
3642 //------------------------------------------------------------------------------
3643 Reference< XControl > FormController::locateControl( const Reference< XControlModel >& _rxModel ) SAL_THROW(())
3647 Sequence< Reference< XControl > > aControls( getControls() );
3648 const Reference< XControl >* pControls = aControls.getConstArray();
3649 const Reference< XControl >* pControlsEnd = aControls.getConstArray() + aControls.getLength();
3651 for ( ; pControls != pControlsEnd; ++pControls )
3653 OSL_ENSURE( pControls->is(), "FormController::locateControl: NULL-control?" );
3654 if ( pControls->is() )
3656 if ( ( *pControls)->getModel() == _rxModel )
3657 return *pControls;
3660 OSL_FAIL( "FormController::locateControl: did not find a control for this model!" );
3662 catch( const Exception& )
3664 DBG_UNHANDLED_EXCEPTION();
3666 return NULL;
3669 //------------------------------------------------------------------------------
3670 namespace
3672 void displayErrorSetFocus( const String& _rMessage, const Reference< XControl >& _rxFocusControl, Window* _pDialogParent )
3674 SQLContext aError;
3675 aError.Message = String( SVX_RES( RID_STR_WRITEERROR ) );
3676 aError.Details = _rMessage;
3677 displayException( aError, _pDialogParent );
3679 if ( _rxFocusControl.is() )
3681 Reference< XWindow > xControlWindow( _rxFocusControl, UNO_QUERY );
3682 OSL_ENSURE( xControlWindow.is(), "displayErrorSetFocus: invalid control!" );
3683 if ( xControlWindow.is() )
3684 xControlWindow->setFocus();
3688 sal_Bool lcl_shouldValidateRequiredFields_nothrow( const Reference< XInterface >& _rxForm )
3692 static ::rtl::OUString s_sFormsCheckRequiredFields( "FormsCheckRequiredFields" );
3694 // first, check whether the form has a property telling us the answer
3695 // this allows people to use the XPropertyContainer interface of a form to control
3696 // the behaviour on a per-form basis.
3697 Reference< XPropertySet > xFormProps( _rxForm, UNO_QUERY_THROW );
3698 Reference< XPropertySetInfo > xPSI( xFormProps->getPropertySetInfo() );
3699 if ( xPSI->hasPropertyByName( s_sFormsCheckRequiredFields ) )
3701 sal_Bool bShouldValidate = true;
3702 OSL_VERIFY( xFormProps->getPropertyValue( s_sFormsCheckRequiredFields ) >>= bShouldValidate );
3703 return bShouldValidate;
3706 // next, check the data source which created the connection
3707 Reference< XChild > xConnectionAsChild( xFormProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ), UNO_QUERY_THROW );
3708 Reference< XPropertySet > xDataSource( xConnectionAsChild->getParent(), UNO_QUERY );
3709 if ( !xDataSource.is() )
3710 // seldom (but possible): this is not a connection created by a data source
3711 return sal_True;
3713 Reference< XPropertySet > xDataSourceSettings(
3714 xDataSource->getPropertyValue( ::rtl::OUString( "Settings" ) ),
3715 UNO_QUERY_THROW );
3717 sal_Bool bShouldValidate = true;
3718 OSL_VERIFY( xDataSourceSettings->getPropertyValue( s_sFormsCheckRequiredFields ) >>= bShouldValidate );
3719 return bShouldValidate;
3721 catch( const Exception& )
3723 DBG_UNHANDLED_EXCEPTION();
3726 return sal_True;
3730 // XRowSetApproveListener
3731 //------------------------------------------------------------------------------
3732 sal_Bool SAL_CALL FormController::approveRowChange(const RowChangeEvent& _rEvent) throw( RuntimeException )
3734 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3735 impl_checkDisposed_throw();
3737 ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
3738 sal_Bool bValid = sal_True;
3739 if (aIter.hasMoreElements())
3741 RowChangeEvent aEvt( _rEvent );
3742 aEvt.Source = *this;
3743 bValid = ((XRowSetApproveListener*)aIter.next())->approveRowChange(aEvt);
3746 if ( !bValid )
3747 return bValid;
3749 if ( ( _rEvent.Action != RowChangeAction::INSERT )
3750 && ( _rEvent.Action != RowChangeAction::UPDATE )
3752 return bValid;
3754 // if some of the control models are bound to validators, check them
3755 ::rtl::OUString sInvalidityExplanation;
3756 Reference< XControlModel > xInvalidModel;
3757 if ( !checkFormComponentValidity( sInvalidityExplanation, xInvalidModel ) )
3759 Reference< XControl > xControl( locateControl( xInvalidModel ) );
3760 aGuard.clear();
3761 displayErrorSetFocus( sInvalidityExplanation, xControl, getDialogParentWindow() );
3762 return false;
3765 // check values on NULL and required flag
3766 if ( !lcl_shouldValidateRequiredFields_nothrow( _rEvent.Source ) )
3767 return sal_True;
3769 OSL_ENSURE( m_pColumnInfoCache.get(), "FormController::approveRowChange: no column infos!" );
3770 if ( !m_pColumnInfoCache.get() )
3771 return sal_True;
3775 if ( !m_pColumnInfoCache->controlsInitialized() )
3776 m_pColumnInfoCache->initializeControls( getControls() );
3778 size_t colCount = m_pColumnInfoCache->getColumnCount();
3779 for ( size_t col = 0; col < colCount; ++col )
3781 const ColumnInfo& rColInfo = m_pColumnInfoCache->getColumnInfo( col );
3782 if ( rColInfo.nNullable != ColumnValue::NO_NULLS )
3783 continue;
3785 if ( rColInfo.bAutoIncrement )
3786 continue;
3788 if ( rColInfo.bReadOnly )
3789 continue;
3791 if ( !rColInfo.xFirstControlWithInputRequired.is() && !rColInfo.xFirstGridWithInputRequiredColumn.is() )
3792 continue;
3794 // TODO: in case of binary fields, this "getString" below is extremely expensive
3795 if ( !rColInfo.xColumn->getString().isEmpty() || !rColInfo.xColumn->wasNull() )
3796 continue;
3798 String sMessage( SVX_RES( RID_ERR_FIELDREQUIRED ) );
3799 sMessage.SearchAndReplace( '#', rColInfo.sName );
3801 // the control to focus
3802 Reference< XControl > xControl( rColInfo.xFirstControlWithInputRequired );
3803 if ( !xControl.is() )
3804 xControl.set( rColInfo.xFirstGridWithInputRequiredColumn, UNO_QUERY );
3806 aGuard.clear();
3807 displayErrorSetFocus( sMessage, rColInfo.xFirstControlWithInputRequired, getDialogParentWindow() );
3808 return sal_False;
3811 catch( const Exception& )
3813 DBG_UNHANDLED_EXCEPTION();
3816 return true;
3819 //------------------------------------------------------------------------------
3820 sal_Bool SAL_CALL FormController::approveCursorMove(const EventObject& event) throw( RuntimeException )
3822 ::osl::MutexGuard aGuard( m_aMutex );
3823 impl_checkDisposed_throw();
3825 ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
3826 if (aIter.hasMoreElements())
3828 EventObject aEvt(event);
3829 aEvt.Source = *this;
3830 return ((XRowSetApproveListener*)aIter.next())->approveCursorMove(aEvt);
3833 return sal_True;
3836 //------------------------------------------------------------------------------
3837 sal_Bool SAL_CALL FormController::approveRowSetChange(const EventObject& event) throw( RuntimeException )
3839 ::osl::MutexGuard aGuard( m_aMutex );
3840 impl_checkDisposed_throw();
3842 ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
3843 if (aIter.hasMoreElements())
3845 EventObject aEvt(event);
3846 aEvt.Source = *this;
3847 return ((XRowSetApproveListener*)aIter.next())->approveRowSetChange(aEvt);
3850 return sal_True;
3853 // XRowSetApproveBroadcaster
3854 //------------------------------------------------------------------------------
3855 void SAL_CALL FormController::addRowSetApproveListener(const Reference< XRowSetApproveListener > & _rxListener) throw( RuntimeException )
3857 ::osl::MutexGuard aGuard( m_aMutex );
3858 impl_checkDisposed_throw();
3860 m_aRowSetApproveListeners.addInterface(_rxListener);
3863 //------------------------------------------------------------------------------
3864 void SAL_CALL FormController::removeRowSetApproveListener(const Reference< XRowSetApproveListener > & _rxListener) throw( RuntimeException )
3866 ::osl::MutexGuard aGuard( m_aMutex );
3867 impl_checkDisposed_throw();
3869 m_aRowSetApproveListeners.removeInterface(_rxListener);
3872 // XErrorListener
3873 //------------------------------------------------------------------------------
3874 void SAL_CALL FormController::errorOccured(const SQLErrorEvent& aEvent) throw( RuntimeException )
3876 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3877 impl_checkDisposed_throw();
3879 ::cppu::OInterfaceIteratorHelper aIter(m_aErrorListeners);
3880 if (aIter.hasMoreElements())
3882 SQLErrorEvent aEvt(aEvent);
3883 aEvt.Source = *this;
3884 ((XSQLErrorListener*)aIter.next())->errorOccured(aEvt);
3886 else
3888 aGuard.clear();
3889 displayException( aEvent );
3893 // XErrorBroadcaster
3894 //------------------------------------------------------------------------------
3895 void SAL_CALL FormController::addSQLErrorListener(const Reference< XSQLErrorListener > & aListener) throw( RuntimeException )
3897 ::osl::MutexGuard aGuard( m_aMutex );
3898 impl_checkDisposed_throw();
3900 m_aErrorListeners.addInterface(aListener);
3903 //------------------------------------------------------------------------------
3904 void SAL_CALL FormController::removeSQLErrorListener(const Reference< XSQLErrorListener > & aListener) throw( RuntimeException )
3906 ::osl::MutexGuard aGuard( m_aMutex );
3907 impl_checkDisposed_throw();
3909 m_aErrorListeners.removeInterface(aListener);
3912 // XDatabaseParameterBroadcaster2
3913 //------------------------------------------------------------------------------
3914 void SAL_CALL FormController::addDatabaseParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException )
3916 ::osl::MutexGuard aGuard( m_aMutex );
3917 impl_checkDisposed_throw();
3919 m_aParameterListeners.addInterface(aListener);
3922 //------------------------------------------------------------------------------
3923 void SAL_CALL FormController::removeDatabaseParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException )
3925 ::osl::MutexGuard aGuard( m_aMutex );
3926 impl_checkDisposed_throw();
3928 m_aParameterListeners.removeInterface(aListener);
3931 // XDatabaseParameterBroadcaster
3932 //------------------------------------------------------------------------------
3933 void SAL_CALL FormController::addParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException )
3935 FormController::addDatabaseParameterListener( aListener );
3938 //------------------------------------------------------------------------------
3939 void SAL_CALL FormController::removeParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException )
3941 FormController::removeDatabaseParameterListener( aListener );
3944 // XDatabaseParameterListener
3945 //------------------------------------------------------------------------------
3946 sal_Bool SAL_CALL FormController::approveParameter(const DatabaseParameterEvent& aEvent) throw( RuntimeException )
3948 SolarMutexGuard aSolarGuard;
3949 ::osl::MutexGuard aGuard( m_aMutex );
3950 impl_checkDisposed_throw();
3952 ::cppu::OInterfaceIteratorHelper aIter(m_aParameterListeners);
3953 if (aIter.hasMoreElements())
3955 DatabaseParameterEvent aEvt(aEvent);
3956 aEvt.Source = *this;
3957 return ((XDatabaseParameterListener*)aIter.next())->approveParameter(aEvt);
3959 else
3961 // default handling: instantiate an interaction handler and let it handle the parameter request
3964 if ( !ensureInteractionHandler() )
3965 return sal_False;
3967 // two continuations allowed: OK and Cancel
3968 OParameterContinuation* pParamValues = new OParameterContinuation;
3969 OInteractionAbort* pAbort = new OInteractionAbort;
3970 // the request
3971 ParametersRequest aRequest;
3972 aRequest.Parameters = aEvent.Parameters;
3973 aRequest.Connection = OStaticDataAccessTools().getRowSetConnection(Reference< XRowSet >(aEvent.Source, UNO_QUERY));
3974 OInteractionRequest* pParamRequest = new OInteractionRequest(makeAny(aRequest));
3975 Reference< XInteractionRequest > xParamRequest(pParamRequest);
3976 // some knittings
3977 pParamRequest->addContinuation(pParamValues);
3978 pParamRequest->addContinuation(pAbort);
3980 // handle the request
3981 m_xInteractionHandler->handle(xParamRequest);
3983 if (!pParamValues->wasSelected())
3984 // canceled
3985 return sal_False;
3987 // transfer the values into the parameter supplier
3988 Sequence< PropertyValue > aFinalValues = pParamValues->getValues();
3989 if (aFinalValues.getLength() != aRequest.Parameters->getCount())
3991 OSL_FAIL("FormController::approveParameter: the InteractionHandler returned nonsense!");
3992 return sal_False;
3994 const PropertyValue* pFinalValues = aFinalValues.getConstArray();
3995 for (sal_Int32 i=0; i<aFinalValues.getLength(); ++i, ++pFinalValues)
3997 Reference< XPropertySet > xParam;
3998 ::cppu::extractInterface(xParam, aRequest.Parameters->getByIndex(i));
3999 if (xParam.is())
4001 #ifdef DBG_UTIL
4002 ::rtl::OUString sName;
4003 xParam->getPropertyValue(FM_PROP_NAME) >>= sName;
4004 DBG_ASSERT(sName.equals(pFinalValues->Name), "FormController::approveParameter: suspicious value names!");
4005 #endif
4006 try { xParam->setPropertyValue(FM_PROP_VALUE, pFinalValues->Value); }
4007 catch(Exception&)
4009 OSL_FAIL("FormController::approveParameter: setting one of the properties failed!");
4014 catch(Exception&)
4016 DBG_UNHANDLED_EXCEPTION();
4019 return sal_True;
4022 // XConfirmDeleteBroadcaster
4023 //------------------------------------------------------------------------------
4024 void SAL_CALL FormController::addConfirmDeleteListener(const Reference< XConfirmDeleteListener > & aListener) throw( RuntimeException )
4026 ::osl::MutexGuard aGuard( m_aMutex );
4027 impl_checkDisposed_throw();
4029 m_aDeleteListeners.addInterface(aListener);
4032 //------------------------------------------------------------------------------
4033 void SAL_CALL FormController::removeConfirmDeleteListener(const Reference< XConfirmDeleteListener > & aListener) throw( RuntimeException )
4035 ::osl::MutexGuard aGuard( m_aMutex );
4036 impl_checkDisposed_throw();
4038 m_aDeleteListeners.removeInterface(aListener);
4041 // XConfirmDeleteListener
4042 //------------------------------------------------------------------------------
4043 sal_Bool SAL_CALL FormController::confirmDelete(const RowChangeEvent& aEvent) throw( RuntimeException )
4045 ::osl::MutexGuard aGuard( m_aMutex );
4046 impl_checkDisposed_throw();
4048 ::cppu::OInterfaceIteratorHelper aIter(m_aDeleteListeners);
4049 if (aIter.hasMoreElements())
4051 RowChangeEvent aEvt(aEvent);
4052 aEvt.Source = *this;
4053 return ((XConfirmDeleteListener*)aIter.next())->confirmDelete(aEvt);
4055 // default handling: instantiate an interaction handler and let it handle the request
4057 String sTitle;
4058 sal_Int32 nLength = aEvent.Rows;
4059 if ( nLength > 1 )
4061 sTitle = SVX_RESSTR( RID_STR_DELETECONFIRM_RECORDS );
4062 sTitle.SearchAndReplace( '#', String::CreateFromInt32( nLength ) );
4064 else
4065 sTitle = SVX_RESSTR( RID_STR_DELETECONFIRM_RECORD );
4069 if ( !ensureInteractionHandler() )
4070 return sal_False;
4072 // two continuations allowed: Yes and No
4073 OInteractionApprove* pApprove = new OInteractionApprove;
4074 OInteractionDisapprove* pDisapprove = new OInteractionDisapprove;
4076 // the request
4077 SQLWarning aWarning;
4078 aWarning.Message = sTitle;
4079 SQLWarning aDetails;
4080 aDetails.Message = String( SVX_RES( RID_STR_DELETECONFIRM ) );
4081 aWarning.NextException <<= aDetails;
4083 OInteractionRequest* pRequest = new OInteractionRequest( makeAny( aWarning ) );
4084 Reference< XInteractionRequest > xRequest( pRequest );
4086 // some knittings
4087 pRequest->addContinuation( pApprove );
4088 pRequest->addContinuation( pDisapprove );
4090 // handle the request
4091 m_xInteractionHandler->handle( xRequest );
4093 if ( pApprove->wasSelected() )
4094 return sal_True;
4096 catch( const Exception& )
4098 DBG_UNHANDLED_EXCEPTION();
4101 return sal_False;
4104 //------------------------------------------------------------------------------
4105 void SAL_CALL FormController::invalidateFeatures( const Sequence< ::sal_Int16 >& _Features ) throw (RuntimeException)
4107 ::osl::MutexGuard aGuard( m_aMutex );
4108 // for now, just copy the ids of the features, because ....
4109 ::std::copy( _Features.getConstArray(), _Features.getConstArray() + _Features.getLength(),
4110 ::std::insert_iterator< ::std::set< sal_Int16 > >( m_aInvalidFeatures, m_aInvalidFeatures.begin() )
4113 // ... we will do the real invalidation asynchronously
4114 if ( !m_aFeatureInvalidationTimer.IsActive() )
4115 m_aFeatureInvalidationTimer.Start();
4118 //------------------------------------------------------------------------------
4119 void SAL_CALL FormController::invalidateAllFeatures( ) throw (RuntimeException)
4121 ::osl::ClearableMutexGuard aGuard( m_aMutex );
4123 Sequence< sal_Int16 > aInterceptedFeatures( m_aFeatureDispatchers.size() );
4124 ::std::transform(
4125 m_aFeatureDispatchers.begin(),
4126 m_aFeatureDispatchers.end(),
4127 aInterceptedFeatures.getArray(),
4128 ::o3tl::select1st< DispatcherContainer::value_type >()
4131 aGuard.clear();
4132 if ( aInterceptedFeatures.getLength() )
4133 invalidateFeatures( aInterceptedFeatures );
4136 //------------------------------------------------------------------------------
4137 Reference< XDispatch >
4138 FormController::interceptedQueryDispatch( const URL& aURL,
4139 const ::rtl::OUString& /*aTargetFrameName*/, sal_Int32 /*nSearchFlags*/)
4140 throw( RuntimeException )
4142 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
4143 Reference< XDispatch > xReturn;
4144 // dispatches handled by ourself
4145 if ( ( aURL.Complete == FMURL_CONFIRM_DELETION )
4146 || ( ( aURL.Complete.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "private:/InteractionHandler" ) ) )
4147 && ensureInteractionHandler()
4150 xReturn = static_cast< XDispatch* >( this );
4152 // dispatches of FormSlot-URLs we have to translate
4153 if ( !xReturn.is() && m_xFormOperations.is() )
4155 // find the slot id which corresponds to the URL
4156 sal_Int32 nFeatureSlotId = ::svx::FeatureSlotTranslation::getControllerFeatureSlotIdForURL( aURL.Main );
4157 sal_Int16 nFormFeature = ( nFeatureSlotId != -1 ) ? ::svx::FeatureSlotTranslation::getFormFeatureForSlotId( nFeatureSlotId ) : -1;
4158 if ( nFormFeature > 0 )
4160 // get the dispatcher for this feature, create if necessary
4161 DispatcherContainer::const_iterator aDispatcherPos = m_aFeatureDispatchers.find( nFormFeature );
4162 if ( aDispatcherPos == m_aFeatureDispatchers.end() )
4164 aDispatcherPos = m_aFeatureDispatchers.insert(
4165 DispatcherContainer::value_type( nFormFeature, new ::svx::OSingleFeatureDispatcher( aURL, nFormFeature, m_xFormOperations, m_aMutex ) )
4166 ).first;
4169 OSL_ENSURE( aDispatcherPos->second.is(), "FormController::interceptedQueryDispatch: should have a dispatcher by now!" );
4170 return aDispatcherPos->second;
4174 // no more to offer
4175 return xReturn;
4178 //------------------------------------------------------------------------------
4179 void SAL_CALL FormController::dispatch( const URL& _rURL, const Sequence< PropertyValue >& _rArgs ) throw (RuntimeException)
4181 if ( _rArgs.getLength() != 1 )
4183 OSL_FAIL( "FormController::dispatch: no arguments -> no dispatch!" );
4184 return;
4187 if ( _rURL.Complete == "private:/InteractionHandler" )
4189 Reference< XInteractionRequest > xRequest;
4190 OSL_VERIFY( _rArgs[0].Value >>= xRequest );
4191 if ( xRequest.is() )
4192 handle( xRequest );
4193 return;
4196 if ( _rURL.Complete == FMURL_CONFIRM_DELETION )
4198 OSL_FAIL( "FormController::dispatch: How do you expect me to return something via this call?" );
4199 // confirmDelete has a return value - dispatch hasn't
4200 return;
4203 OSL_FAIL( "FormController::dispatch: unknown URL!" );
4206 //------------------------------------------------------------------------------
4207 void SAL_CALL FormController::addStatusListener( const Reference< XStatusListener >& _rxListener, const URL& _rURL ) throw (RuntimeException)
4209 if (_rURL.Complete == FMURL_CONFIRM_DELETION)
4211 if (_rxListener.is())
4212 { // send an initial statusChanged event
4213 FeatureStateEvent aEvent;
4214 aEvent.FeatureURL = _rURL;
4215 aEvent.IsEnabled = sal_True;
4216 _rxListener->statusChanged(aEvent);
4217 // and don't add the listener at all (the status will never change)
4220 else
4221 OSL_FAIL("FormController::addStatusListener: invalid (unsupported) URL!");
4224 //------------------------------------------------------------------------------
4225 Reference< XInterface > SAL_CALL FormController::getParent() throw( RuntimeException )
4227 return m_xParent;
4230 //------------------------------------------------------------------------------
4231 void SAL_CALL FormController::setParent( const Reference< XInterface >& Parent) throw( NoSupportException, RuntimeException )
4233 m_xParent = Parent;
4236 //------------------------------------------------------------------------------
4237 void SAL_CALL FormController::removeStatusListener( const Reference< XStatusListener >& /*_rxListener*/, const URL& _rURL ) throw (RuntimeException)
4239 (void)_rURL;
4240 OSL_ENSURE(_rURL.Complete == FMURL_CONFIRM_DELETION, "FormController::removeStatusListener: invalid (unsupported) URL!");
4241 // we never really added the listener, so we don't need to remove it
4244 //------------------------------------------------------------------------------
4245 Reference< XDispatchProviderInterceptor > FormController::createInterceptor(const Reference< XDispatchProviderInterception > & _xInterception)
4247 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
4248 #ifdef DBG_UTIL
4249 // check if we already have a interceptor for the given object
4250 for ( ConstInterceptorsIterator aIter = m_aControlDispatchInterceptors.begin();
4251 aIter != m_aControlDispatchInterceptors.end();
4252 ++aIter
4255 if ((*aIter)->getIntercepted() == _xInterception)
4256 OSL_FAIL("FormController::createInterceptor : we already do intercept this objects dispatches !");
4258 #endif
4260 DispatchInterceptionMultiplexer* pInterceptor = new DispatchInterceptionMultiplexer( _xInterception, this );
4261 pInterceptor->acquire();
4262 m_aControlDispatchInterceptors.insert( m_aControlDispatchInterceptors.end(), pInterceptor );
4264 return pInterceptor;
4267 //------------------------------------------------------------------------------
4268 bool FormController::ensureInteractionHandler()
4270 if ( m_xInteractionHandler.is() )
4271 return true;
4272 if ( m_bAttemptedHandlerCreation )
4273 return false;
4274 m_bAttemptedHandlerCreation = true;
4276 m_xInteractionHandler.set( m_aContext.createComponent( ::rtl::OUString( "com.sun.star.task.InteractionHandler" ) ), UNO_QUERY );
4277 OSL_ENSURE( m_xInteractionHandler.is(), "FormController::ensureInteractionHandler: could not create an interaction handler!" );
4278 return m_xInteractionHandler.is();
4281 //------------------------------------------------------------------------------
4282 void SAL_CALL FormController::handle( const Reference< XInteractionRequest >& _rRequest ) throw (RuntimeException)
4284 if ( !ensureInteractionHandler() )
4285 return;
4286 m_xInteractionHandler->handle( _rRequest );
4289 //------------------------------------------------------------------------------
4290 void FormController::deleteInterceptor(const Reference< XDispatchProviderInterception > & _xInterception)
4292 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
4293 // search the interceptor responsible for the given object
4294 InterceptorsIterator aIter;
4295 for ( aIter = m_aControlDispatchInterceptors.begin();
4296 aIter != m_aControlDispatchInterceptors.end();
4297 ++aIter
4300 if ((*aIter)->getIntercepted() == _xInterception)
4301 break;
4303 if (aIter == m_aControlDispatchInterceptors.end())
4305 return;
4308 // log off the interception from it's interception object
4309 DispatchInterceptionMultiplexer* pInterceptorImpl = *aIter;
4310 pInterceptorImpl->dispose();
4311 pInterceptorImpl->release();
4313 // remove the interceptor from our array
4314 m_aControlDispatchInterceptors.erase(aIter);
4317 //--------------------------------------------------------------------
4318 void FormController::implInvalidateCurrentControlDependentFeatures()
4320 Sequence< sal_Int16 > aCurrentControlDependentFeatures(4);
4322 aCurrentControlDependentFeatures[0] = FormFeature::SortAscending;
4323 aCurrentControlDependentFeatures[1] = FormFeature::SortDescending;
4324 aCurrentControlDependentFeatures[2] = FormFeature::AutoFilter;
4325 aCurrentControlDependentFeatures[3] = FormFeature::RefreshCurrentControl;
4327 invalidateFeatures( aCurrentControlDependentFeatures );
4330 //--------------------------------------------------------------------
4331 void SAL_CALL FormController::columnChanged( const EventObject& /*_event*/ ) throw (RuntimeException)
4333 implInvalidateCurrentControlDependentFeatures();
4336 } // namespace svxform
4338 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */