bump product version to 4.1.6.2
[LibreOffice.git] / svx / source / form / formcontroller.cxx
blob0fbe0dc9c5d4835d2f01f6130269c0def2b04450
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "fmcontrolbordermanager.hxx"
22 #include "fmcontrollayout.hxx"
23 #include "formcontroller.hxx"
24 #include "formfeaturedispatcher.hxx"
25 #include "fmdocumentclassification.hxx"
26 #include "formcontrolling.hxx"
27 #include "fmprop.hrc"
28 #include "svx/dialmgr.hxx"
29 #include "svx/fmresids.hrc"
30 #include "fmservs.hxx"
31 #include "svx/fmtools.hxx"
32 #include "fmurl.hxx"
34 #include <com/sun/star/awt/FocusChangeReason.hpp>
35 #include <com/sun/star/awt/XCheckBox.hpp>
36 #include <com/sun/star/awt/XComboBox.hpp>
37 #include <com/sun/star/awt/XListBox.hpp>
38 #include <com/sun/star/awt/XVclWindowPeer.hpp>
39 #include <com/sun/star/awt/TabController.hpp>
40 #include <com/sun/star/beans/NamedValue.hpp>
41 #include <com/sun/star/beans/PropertyAttribute.hpp>
42 #include <com/sun/star/container/XIdentifierReplace.hpp>
43 #include <com/sun/star/form/TabulatorCycle.hpp>
44 #include <com/sun/star/form/validation/XValidatableFormComponent.hpp>
45 #include <com/sun/star/form/XBoundComponent.hpp>
46 #include <com/sun/star/form/XBoundControl.hpp>
47 #include <com/sun/star/form/XGridControl.hpp>
48 #include <com/sun/star/form/XLoadable.hpp>
49 #include <com/sun/star/form/XReset.hpp>
50 #include <com/sun/star/form/control/FilterControl.hpp>
51 #include <com/sun/star/frame/XController.hpp>
52 #include <com/sun/star/sdb/ParametersRequest.hpp>
53 #include <com/sun/star/sdb/RowChangeAction.hpp>
54 #include <com/sun/star/sdb/XInteractionSupplyParameters.hpp>
55 #include <com/sun/star/sdbc/ColumnValue.hpp>
56 #include <com/sun/star/sdbc/DataType.hpp>
57 #include <com/sun/star/task/InteractionHandler.hpp>
58 #include <com/sun/star/util/XURLTransformer.hpp>
59 #include <com/sun/star/form/runtime/FormOperations.hpp>
60 #include <com/sun/star/form/runtime/FormFeature.hpp>
61 #include <com/sun/star/container/XContainer.hpp>
62 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
63 #include <com/sun/star/util/NumberFormatter.hpp>
64 #include <com/sun/star/sdb/SQLContext.hpp>
65 #include <com/sun/star/sdb/XColumn.hpp>
67 #include <comphelper/enumhelper.hxx>
68 #include <comphelper/extract.hxx>
69 #include <comphelper/interaction.hxx>
70 #include <comphelper/namedvaluecollection.hxx>
71 #include <comphelper/processfactory.hxx>
72 #include <comphelper/propagg.hxx>
73 #include <comphelper/property.hxx>
74 #include <comphelper/sequence.hxx>
75 #include <comphelper/uno3.hxx>
76 #include <comphelper/flagguard.hxx>
77 #include <cppuhelper/queryinterface.hxx>
78 #include <cppuhelper/typeprovider.hxx>
79 #include <connectivity/IParseContext.hxx>
80 #include <toolkit/controls/unocontrol.hxx>
81 #include <toolkit/helper/vclunohelper.hxx>
82 #include <tools/debug.hxx>
83 #include <tools/diagnose_ex.h>
84 #include <tools/shl.hxx>
85 #include <vcl/msgbox.hxx>
86 #include <vcl/svapp.hxx>
87 #include <osl/mutex.hxx>
88 #include <rtl/logfile.hxx>
90 #include <algorithm>
92 #include <o3tl/compat_functional.hxx>
94 using namespace ::com::sun::star;
95 using namespace ::comphelper;
96 using namespace ::connectivity;
97 using namespace ::connectivity::simple;
99 //------------------------------------------------------------------
100 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL
101 FormController_NewInstance_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & _rxORB )
103 return *( new ::svxform::FormController( _rxORB ) );
106 namespace svxform
109 using ::com::sun::star::sdb::XColumn;
110 using ::com::sun::star::awt::XControl;
111 using ::com::sun::star::awt::XTabController;
112 using ::com::sun::star::awt::TabController;
113 using ::com::sun::star::awt::XToolkit;
114 using ::com::sun::star::awt::XWindowPeer;
115 using ::com::sun::star::form::XGrid;
116 using ::com::sun::star::beans::XPropertySet;
117 using ::com::sun::star::uno::UNO_SET_THROW;
118 using ::com::sun::star::uno::UNO_QUERY_THROW;
119 using ::com::sun::star::container::XIndexAccess;
120 using ::com::sun::star::uno::Exception;
121 using ::com::sun::star::uno::XInterface;
122 using ::com::sun::star::uno::UNO_QUERY;
123 using ::com::sun::star::uno::Sequence;
124 using ::com::sun::star::uno::Reference;
125 using ::com::sun::star::beans::XPropertySetInfo;
126 using ::com::sun::star::beans::PropertyValue;
127 using ::com::sun::star::uno::RuntimeException;
128 using ::com::sun::star::lang::IndexOutOfBoundsException;
129 using ::com::sun::star::sdb::XInteractionSupplyParameters;
130 using ::com::sun::star::awt::XTextComponent;
131 using ::com::sun::star::awt::XTextListener;
132 using ::com::sun::star::uno::Any;
133 using ::com::sun::star::frame::XDispatch;
134 using ::com::sun::star::lang::XMultiServiceFactory;
135 using ::com::sun::star::uno::XAggregation;
136 using ::com::sun::star::uno::Type;
137 using ::com::sun::star::lang::IllegalArgumentException;
138 using ::com::sun::star::sdbc::XConnection;
139 using ::com::sun::star::sdbc::XRowSet;
140 using ::com::sun::star::sdbc::XDatabaseMetaData;
141 using ::com::sun::star::util::XNumberFormatsSupplier;
142 using ::com::sun::star::util::NumberFormatter;
143 using ::com::sun::star::util::XNumberFormatter;
144 using ::com::sun::star::sdbcx::XColumnsSupplier;
145 using ::com::sun::star::container::XNameAccess;
146 using ::com::sun::star::lang::EventObject;
147 using ::com::sun::star::beans::Property;
148 using ::com::sun::star::container::XEnumeration;
149 using ::com::sun::star::form::XFormComponent;
150 using ::com::sun::star::form::runtime::XFormOperations;
151 using ::com::sun::star::form::runtime::FilterEvent;
152 using ::com::sun::star::form::runtime::XFilterControllerListener;
153 using ::com::sun::star::awt::XControlContainer;
154 using ::com::sun::star::container::XIdentifierReplace;
155 using ::com::sun::star::lang::WrappedTargetException;
156 using ::com::sun::star::form::XFormControllerListener;
157 using ::com::sun::star::awt::XWindow;
158 using ::com::sun::star::sdbc::XResultSet;
159 using ::com::sun::star::awt::XControlModel;
160 using ::com::sun::star::awt::XTabControllerModel;
161 using ::com::sun::star::beans::PropertyChangeEvent;
162 using ::com::sun::star::form::validation::XValidatableFormComponent;
163 using ::com::sun::star::form::XLoadable;
164 using ::com::sun::star::script::XEventAttacherManager;
165 using ::com::sun::star::form::XBoundControl;
166 using ::com::sun::star::beans::XPropertyChangeListener;
167 using ::com::sun::star::awt::TextEvent;
168 using ::com::sun::star::form::XBoundComponent;
169 using ::com::sun::star::awt::XCheckBox;
170 using ::com::sun::star::awt::XComboBox;
171 using ::com::sun::star::awt::XListBox;
172 using ::com::sun::star::awt::ItemEvent;
173 using ::com::sun::star::util::XModifyListener;
174 using ::com::sun::star::form::XReset;
175 using ::com::sun::star::frame::XDispatchProviderInterception;
176 using ::com::sun::star::form::XGridControl;
177 using ::com::sun::star::awt::XVclWindowPeer;
178 using ::com::sun::star::form::validation::XValidator;
179 using ::com::sun::star::awt::FocusEvent;
180 using ::com::sun::star::sdb::SQLContext;
181 using ::com::sun::star::container::XChild;
182 using ::com::sun::star::form::TabulatorCycle_RECORDS;
183 using ::com::sun::star::container::ContainerEvent;
184 using ::com::sun::star::lang::DisposedException;
185 using ::com::sun::star::lang::Locale;
186 using ::com::sun::star::beans::NamedValue;
187 using ::com::sun::star::lang::NoSupportException;
188 using ::com::sun::star::sdb::RowChangeEvent;
189 using ::com::sun::star::frame::XStatusListener;
190 using ::com::sun::star::frame::XDispatchProviderInterceptor;
191 using ::com::sun::star::sdb::SQLErrorEvent;
192 using ::com::sun::star::form::DatabaseParameterEvent;
193 using ::com::sun::star::sdb::ParametersRequest;
194 using ::com::sun::star::task::XInteractionRequest;
195 using ::com::sun::star::util::URL;
196 using ::com::sun::star::frame::FeatureStateEvent;
197 using ::com::sun::star::form::runtime::XFormControllerContext;
198 using ::com::sun::star::task::InteractionHandler;
199 using ::com::sun::star::task::XInteractionHandler;
200 using ::com::sun::star::form::runtime::FormOperations;
201 using ::com::sun::star::container::XContainer;
202 using ::com::sun::star::sdbc::SQLWarning;
204 namespace ColumnValue = ::com::sun::star::sdbc::ColumnValue;
205 namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
206 namespace FocusChangeReason = ::com::sun::star::awt::FocusChangeReason;
207 namespace RowChangeAction = ::com::sun::star::sdb::RowChangeAction;
208 namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
209 namespace DataType = ::com::sun::star::sdbc::DataType;
211 //==============================================================================
212 // ColumnInfo
213 //==============================================================================
214 struct ColumnInfo
216 // information about the column itself
217 Reference< XColumn > xColumn;
218 sal_Int32 nNullable;
219 sal_Bool bAutoIncrement;
220 sal_Bool bReadOnly;
221 OUString sName;
223 // information about the control(s) bound to this column
225 /// the first control which is bound to the given column, and which requires input
226 Reference< XControl > xFirstControlWithInputRequired;
227 /** the first grid control which contains a column which is bound to the given database column, and requires
228 input
230 Reference< XGrid > xFirstGridWithInputRequiredColumn;
231 /** if xFirstControlWithInputRequired is a grid control, then nRequiredGridColumn specifies the position
232 of the grid column which is actually bound
234 sal_Int32 nRequiredGridColumn;
236 ColumnInfo()
237 :xColumn()
238 ,nNullable( ColumnValue::NULLABLE_UNKNOWN )
239 ,bAutoIncrement( sal_False )
240 ,bReadOnly( sal_False )
241 ,sName()
242 ,xFirstControlWithInputRequired()
243 ,xFirstGridWithInputRequiredColumn()
244 ,nRequiredGridColumn( -1 )
249 //==============================================================================
250 //= ColumnInfoCache
251 //==============================================================================
252 class ColumnInfoCache
254 public:
255 ColumnInfoCache( const Reference< XColumnsSupplier >& _rxColSupplier );
257 size_t getColumnCount() const { return m_aColumns.size(); }
258 const ColumnInfo& getColumnInfo( size_t _pos );
260 bool controlsInitialized() const { return m_bControlsInitialized; }
261 void initializeControls( const Sequence< Reference< XControl > >& _rControls );
262 void deinitializeControls();
264 private:
265 typedef ::std::vector< ColumnInfo > ColumnInfos;
266 ColumnInfos m_aColumns;
267 bool m_bControlsInitialized;
270 //------------------------------------------------------------------------------
271 ColumnInfoCache::ColumnInfoCache( const Reference< XColumnsSupplier >& _rxColSupplier )
272 :m_aColumns()
273 ,m_bControlsInitialized( false )
277 m_aColumns.clear();
279 Reference< XColumnsSupplier > xSupplyCols( _rxColSupplier, UNO_SET_THROW );
280 Reference< XIndexAccess > xColumns( xSupplyCols->getColumns(), UNO_QUERY_THROW );
281 sal_Int32 nColumnCount = xColumns->getCount();
282 m_aColumns.reserve( nColumnCount );
284 Reference< XPropertySet > xColumnProps;
285 for ( sal_Int32 i = 0; i < nColumnCount; ++i )
287 ColumnInfo aColInfo;
288 aColInfo.xColumn.set( xColumns->getByIndex(i), UNO_QUERY_THROW );
290 xColumnProps.set( aColInfo.xColumn, UNO_QUERY_THROW );
291 OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_ISNULLABLE ) >>= aColInfo.nNullable );
292 OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_AUTOINCREMENT ) >>= aColInfo.bAutoIncrement );
293 OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_NAME ) >>= aColInfo.sName );
294 OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_ISREADONLY ) >>= aColInfo.bReadOnly );
296 m_aColumns.push_back( aColInfo );
299 catch( const Exception& )
301 DBG_UNHANDLED_EXCEPTION();
305 //------------------------------------------------------------------------------
306 namespace
308 bool lcl_isBoundTo( const Reference< XPropertySet >& _rxControlModel, const Reference< XInterface >& _rxNormDBField )
310 Reference< XInterface > xNormBoundField( _rxControlModel->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY );
311 return ( xNormBoundField.get() == _rxNormDBField.get() );
314 bool lcl_isInputRequired( const Reference< XPropertySet >& _rxControlModel )
316 sal_Bool bInputRequired = sal_True;
317 OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_INPUT_REQUIRED ) >>= bInputRequired );
318 return ( bInputRequired != sal_False );
321 void lcl_resetColumnControlInfo( ColumnInfo& _rColInfo )
323 _rColInfo.xFirstControlWithInputRequired.clear();
324 _rColInfo.xFirstGridWithInputRequiredColumn.clear();
325 _rColInfo.nRequiredGridColumn = -1;
329 //------------------------------------------------------------------------------
330 void ColumnInfoCache::deinitializeControls()
332 for ( ColumnInfos::iterator col = m_aColumns.begin();
333 col != m_aColumns.end();
334 ++col
337 lcl_resetColumnControlInfo( *col );
341 //------------------------------------------------------------------------------
342 void ColumnInfoCache::initializeControls( const Sequence< Reference< XControl > >& _rControls )
346 // for every of our known columns, find the controls which are bound to this column
347 for ( ColumnInfos::iterator col = m_aColumns.begin();
348 col != m_aColumns.end();
349 ++col
352 OSL_ENSURE( !col->xFirstControlWithInputRequired.is() && !col->xFirstGridWithInputRequiredColumn.is()
353 && ( col->nRequiredGridColumn == -1 ), "ColumnInfoCache::initializeControls: called me twice?" );
355 lcl_resetColumnControlInfo( *col );
357 Reference< XInterface > xNormColumn( col->xColumn, UNO_QUERY_THROW );
359 const Reference< XControl >* pControl( _rControls.getConstArray() );
360 const Reference< XControl >* pControlEnd( pControl + _rControls.getLength() );
361 for ( ; pControl != pControlEnd; ++pControl )
363 if ( !pControl->is() )
364 continue;
366 Reference< XPropertySet > xModel( (*pControl)->getModel(), UNO_QUERY_THROW );
367 Reference< XPropertySetInfo > xModelPSI( xModel->getPropertySetInfo(), UNO_SET_THROW );
369 // special handling for grid controls
370 Reference< XGrid > xGrid( *pControl, UNO_QUERY );
371 if ( xGrid.is() )
373 Reference< XIndexAccess > xGridColAccess( xModel, UNO_QUERY_THROW );
374 sal_Int32 gridColCount = xGridColAccess->getCount();
375 sal_Int32 gridCol = 0;
376 for ( gridCol = 0; gridCol < gridColCount; ++gridCol )
378 Reference< XPropertySet > xGridColumnModel( xGridColAccess->getByIndex( gridCol ), UNO_QUERY_THROW );
380 if ( !lcl_isBoundTo( xGridColumnModel, xNormColumn )
381 || !lcl_isInputRequired( xGridColumnModel )
383 continue; // with next grid column
385 break;
388 if ( gridCol < gridColCount )
390 // found a grid column which is bound to the given
391 col->xFirstGridWithInputRequiredColumn = xGrid;
392 col->nRequiredGridColumn = gridCol;
393 break;
396 continue; // with next control
399 if ( !xModelPSI->hasPropertyByName( FM_PROP_BOUNDFIELD )
400 || !lcl_isBoundTo( xModel, xNormColumn )
401 || !lcl_isInputRequired( xModel )
403 continue; // with next control
405 break;
408 if ( pControl == pControlEnd )
409 // did not find a control which is bound to this particular column, and for which the input is required
410 continue; // with next DB column
412 col->xFirstControlWithInputRequired = *pControl;
415 catch( const Exception& )
417 DBG_UNHANDLED_EXCEPTION();
420 m_bControlsInitialized = true;
423 //------------------------------------------------------------------------------
424 const ColumnInfo& ColumnInfoCache::getColumnInfo( size_t _pos )
426 if ( _pos >= m_aColumns.size() )
427 throw IndexOutOfBoundsException();
429 return m_aColumns[ _pos ];
432 //==================================================================
433 // OParameterContinuation
434 //==================================================================
435 class OParameterContinuation : public OInteraction< XInteractionSupplyParameters >
437 Sequence< PropertyValue > m_aValues;
439 public:
440 OParameterContinuation() { }
442 Sequence< PropertyValue > getValues() const { return m_aValues; }
444 // XInteractionSupplyParameters
445 virtual void SAL_CALL setParameters( const Sequence< PropertyValue >& _rValues ) throw(RuntimeException);
448 //------------------------------------------------------------------
449 void SAL_CALL OParameterContinuation::setParameters( const Sequence< PropertyValue >& _rValues ) throw(RuntimeException)
451 m_aValues = _rValues;
454 //==================================================================
455 // FmXAutoControl
456 //==================================================================
457 struct FmFieldInfo
459 OUString aFieldName;
460 Reference< XPropertySet > xField;
461 Reference< XTextComponent > xText;
463 FmFieldInfo(const Reference< XPropertySet >& _xField, const Reference< XTextComponent >& _xText)
464 :xField(_xField)
465 ,xText(_xText)
466 {xField->getPropertyValue(FM_PROP_NAME) >>= aFieldName;}
469 //==================================================================
470 // FmXAutoControl
471 //==================================================================
472 class FmXAutoControl: public UnoControl
475 friend Reference< XInterface > SAL_CALL FmXAutoControl_NewInstance_Impl();
477 public:
478 FmXAutoControl() :UnoControl()
482 virtual OUString GetComponentServiceName() {return OUString("Edit");}
483 virtual void SAL_CALL createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) throw( RuntimeException );
485 protected:
486 virtual void ImplSetPeerProperty( const OUString& rPropName, const Any& rVal );
489 //------------------------------------------------------------------------------
490 void FmXAutoControl::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) throw( RuntimeException )
492 UnoControl::createPeer( rxToolkit, rParentPeer );
494 Reference< XTextComponent > xText(getPeer() , UNO_QUERY);
495 if (xText.is())
497 xText->setText(OUString(String(SVX_RES(RID_STR_AUTOFIELD))));
498 xText->setEditable(sal_False);
502 //------------------------------------------------------------------------------
503 void FmXAutoControl::ImplSetPeerProperty( const OUString& rPropName, const Any& rVal )
505 // these properties are ignored
506 if (rPropName == FM_PROP_TEXT)
507 return;
509 UnoControl::ImplSetPeerProperty( rPropName, rVal );
512 //------------------------------------------------------------------------------
513 IMPL_LINK( FormController, OnActivateTabOrder, void*, /*EMPTYTAG*/ )
515 activateTabOrder();
516 return 1;
519 //------------------------------------------------------------------------------
520 struct UpdateAllListeners : public ::std::unary_function< Reference< XDispatch >, bool >
522 bool operator()( const Reference< XDispatch >& _rxDispatcher ) const
524 static_cast< ::svx::OSingleFeatureDispatcher* >( _rxDispatcher.get() )->updateAllListeners();
525 // the return is a dummy only so we can use this struct in a o3tl::compose1 call
526 return true;
529 //..............................................................................
530 IMPL_LINK( FormController, OnInvalidateFeatures, void*, /*_pNotInterestedInThisParam*/ )
532 ::osl::MutexGuard aGuard( m_aMutex );
533 for ( ::std::set< sal_Int16 >::const_iterator aLoop = m_aInvalidFeatures.begin();
534 aLoop != m_aInvalidFeatures.end();
535 ++aLoop
538 DispatcherContainer::const_iterator aDispatcherPos = m_aFeatureDispatchers.find( *aLoop );
539 if ( aDispatcherPos != m_aFeatureDispatchers.end() )
541 // TODO: for the real and actual listener notifications, we should release
542 // our mutex
543 UpdateAllListeners( )( aDispatcherPos->second );
546 return 1;
549 /*************************************************************************/
551 DBG_NAME( FormController )
552 //------------------------------------------------------------------
553 FormController::FormController(const Reference< XMultiServiceFactory > & _rxORB )
554 :FormController_BASE( m_aMutex )
555 ,OPropertySetHelper( FormController_BASE::rBHelper )
556 ,OSQLParserClient( comphelper::getComponentContext(_rxORB) )
557 ,m_aContext( _rxORB )
558 ,m_aActivateListeners(m_aMutex)
559 ,m_aModifyListeners(m_aMutex)
560 ,m_aErrorListeners(m_aMutex)
561 ,m_aDeleteListeners(m_aMutex)
562 ,m_aRowSetApproveListeners(m_aMutex)
563 ,m_aParameterListeners(m_aMutex)
564 ,m_aFilterListeners(m_aMutex)
565 ,m_pControlBorderManager( new ::svxform::ControlBorderManager )
566 ,m_xFormOperations()
567 ,m_aMode( OUString( "DataMode" ) )
568 ,m_aLoadEvent( LINK( this, FormController, OnLoad ) )
569 ,m_aToggleEvent( LINK( this, FormController, OnToggleAutoFields ) )
570 ,m_aActivationEvent( LINK( this, FormController, OnActivated ) )
571 ,m_aDeactivationEvent( LINK( this, FormController, OnDeactivated ) )
572 ,m_nCurrentFilterPosition(-1)
573 ,m_bCurrentRecordModified(sal_False)
574 ,m_bCurrentRecordNew(sal_False)
575 ,m_bLocked(sal_False)
576 ,m_bDBConnection(sal_False)
577 ,m_bCycle(sal_False)
578 ,m_bCanInsert(sal_False)
579 ,m_bCanUpdate(sal_False)
580 ,m_bCommitLock(sal_False)
581 ,m_bModified(sal_False)
582 ,m_bControlsSorted(sal_False)
583 ,m_bFiltering(sal_False)
584 ,m_bAttachEvents(sal_True)
585 ,m_bDetachEvents(sal_True)
586 ,m_bAttemptedHandlerCreation( false )
587 ,m_bSuspendFilterTextListening( false )
589 DBG_CTOR( FormController, NULL );
591 ::comphelper::increment(m_refCount);
593 m_xTabController = TabController::create( m_aContext.getUNOContext() );
594 m_xAggregate = Reference< XAggregation >( m_xTabController, UNO_QUERY_THROW );
595 m_xAggregate->setDelegator( *this );
597 ::comphelper::decrement(m_refCount);
599 m_aTabActivationTimer.SetTimeout( 500 );
600 m_aTabActivationTimer.SetTimeoutHdl( LINK( this, FormController, OnActivateTabOrder ) );
602 m_aFeatureInvalidationTimer.SetTimeout( 200 );
603 m_aFeatureInvalidationTimer.SetTimeoutHdl( LINK( this, FormController, OnInvalidateFeatures ) );
606 //------------------------------------------------------------------
607 FormController::~FormController()
610 ::osl::MutexGuard aGuard( m_aMutex );
612 m_aLoadEvent.CancelPendingCall();
613 m_aToggleEvent.CancelPendingCall();
614 m_aActivationEvent.CancelPendingCall();
615 m_aDeactivationEvent.CancelPendingCall();
617 if ( m_aTabActivationTimer.IsActive() )
618 m_aTabActivationTimer.Stop();
621 if ( m_aFeatureInvalidationTimer.IsActive() )
622 m_aFeatureInvalidationTimer.Stop();
624 disposeAllFeaturesAndDispatchers();
626 if ( m_xFormOperations.is() )
627 m_xFormOperations->dispose();
628 m_xFormOperations.clear();
630 // Freigeben der Aggregation
631 if ( m_xAggregate.is() )
633 m_xAggregate->setDelegator( NULL );
634 m_xAggregate.clear();
637 DELETEZ( m_pControlBorderManager );
639 DBG_DTOR( FormController, NULL );
642 // -----------------------------------------------------------------------------
643 void SAL_CALL FormController::acquire() throw ()
645 FormController_BASE::acquire();
648 // -----------------------------------------------------------------------------
649 void SAL_CALL FormController::release() throw ()
651 FormController_BASE::release();
654 //------------------------------------------------------------------
655 Any SAL_CALL FormController::queryInterface( const Type& _rType ) throw(RuntimeException)
657 Any aRet = FormController_BASE::queryInterface( _rType );
658 if ( !aRet.hasValue() )
659 aRet = OPropertySetHelper::queryInterface( _rType );
660 if ( !aRet.hasValue() )
661 aRet = m_xAggregate->queryAggregation( _rType );
662 return aRet;
665 //------------------------------------------------------------------------------
666 Sequence< sal_Int8 > SAL_CALL FormController::getImplementationId() throw( RuntimeException )
668 static ::cppu::OImplementationId* pId = NULL;
669 if ( !pId )
671 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
672 if ( !pId )
674 static ::cppu::OImplementationId aId;
675 pId = &aId;
678 return pId->getImplementationId();
681 //------------------------------------------------------------------------------
682 Sequence< Type > SAL_CALL FormController::getTypes( ) throw(RuntimeException)
684 return comphelper::concatSequences(
685 FormController_BASE::getTypes(),
686 ::cppu::OPropertySetHelper::getTypes()
690 // XServiceInfo
691 //------------------------------------------------------------------------------
692 sal_Bool SAL_CALL FormController::supportsService(const OUString& ServiceName) throw( RuntimeException )
694 Sequence< OUString> aSNL(getSupportedServiceNames());
695 const OUString * pArray = aSNL.getConstArray();
696 for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
697 if( pArray[i] == ServiceName )
698 return sal_True;
699 return sal_False;
702 //------------------------------------------------------------------------------
703 OUString SAL_CALL FormController::getImplementationName() throw( RuntimeException )
705 return OUString("org.openoffice.comp.svx.FormController");
708 //------------------------------------------------------------------------------
709 Sequence< OUString> SAL_CALL FormController::getSupportedServiceNames(void) throw( RuntimeException )
711 // service names which are supported only, but cannot be used to created an
712 // instance at a service factory
713 Sequence< OUString > aNonCreatableServiceNames( 1 );
714 aNonCreatableServiceNames[ 0 ] = OUString( "com.sun.star.form.FormControllerDispatcher" );
716 // services which can be used to created an instance at a service factory
717 Sequence< OUString > aCreatableServiceNames( getSupportedServiceNames_Static() );
718 return ::comphelper::concatSequences( aCreatableServiceNames, aNonCreatableServiceNames );
721 //------------------------------------------------------------------------------
722 sal_Bool SAL_CALL FormController::approveReset(const EventObject& /*rEvent*/) throw( RuntimeException )
724 return sal_True;
727 //------------------------------------------------------------------------------
728 void SAL_CALL FormController::resetted(const EventObject& rEvent) throw( RuntimeException )
730 ::osl::MutexGuard aGuard(m_aMutex);
731 if (getCurrentControl().is() && (getCurrentControl()->getModel() == rEvent.Source))
732 m_bModified = sal_False;
735 //------------------------------------------------------------------------------
736 Sequence< OUString> FormController::getSupportedServiceNames_Static(void)
738 static Sequence< OUString> aServices;
739 if (!aServices.getLength())
741 aServices.realloc(2);
742 aServices.getArray()[0] = OUString( "com.sun.star.form.runtime.FormController" );
743 aServices.getArray()[1] = OUString("com.sun.star.awt.control.TabController");
745 return aServices;
748 // -----------------------------------------------------------------------------
749 namespace
751 struct ResetComponentText : public ::std::unary_function< Reference< XTextComponent >, void >
753 void operator()( const Reference< XTextComponent >& _rxText )
755 _rxText->setText( OUString() );
759 struct RemoveComponentTextListener : public ::std::unary_function< Reference< XTextComponent >, void >
761 RemoveComponentTextListener( const Reference< XTextListener >& _rxListener )
762 :m_xListener( _rxListener )
766 void operator()( const Reference< XTextComponent >& _rxText )
768 _rxText->removeTextListener( m_xListener );
771 private:
772 Reference< XTextListener > m_xListener;
776 // -----------------------------------------------------------------------------
777 void FormController::impl_setTextOnAllFilter_throw()
779 m_bSuspendFilterTextListening = true;
780 ::comphelper::FlagGuard aResetFlag( m_bSuspendFilterTextListening );
782 // reset the text for all controls
783 ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), ResetComponentText() );
785 if ( m_aFilterRows.empty() )
786 // nothing to do anymore
787 return;
789 if ( m_nCurrentFilterPosition < 0 )
790 return;
792 // set the text for all filters
793 OSL_ENSURE( m_aFilterRows.size() > (size_t)m_nCurrentFilterPosition,
794 "FormController::impl_setTextOnAllFilter_throw: m_nCurrentFilterPosition too big" );
796 if ( (size_t)m_nCurrentFilterPosition < m_aFilterRows.size() )
798 FmFilterRow& rRow = m_aFilterRows[ m_nCurrentFilterPosition ];
799 for ( FmFilterRow::const_iterator iter2 = rRow.begin();
800 iter2 != rRow.end();
801 ++iter2
804 iter2->first->setText( iter2->second );
808 // OPropertySetHelper
809 //------------------------------------------------------------------------------
810 sal_Bool FormController::convertFastPropertyValue( Any & /*rConvertedValue*/, Any & /*rOldValue*/,
811 sal_Int32 /*nHandle*/, const Any& /*rValue*/ )
812 throw( IllegalArgumentException )
814 return sal_False;
817 //------------------------------------------------------------------------------
818 void FormController::setFastPropertyValue_NoBroadcast( sal_Int32 /*nHandle*/, const Any& /*rValue*/ )
819 throw( Exception )
823 //------------------------------------------------------------------------------
824 void FormController::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
826 switch (nHandle)
828 case FM_ATTR_FILTER:
830 OUStringBuffer aFilter;
831 OStaticDataAccessTools aStaticTools;
832 Reference<XConnection> xConnection(aStaticTools.getRowSetConnection(Reference< XRowSet>(m_xModelAsIndex, UNO_QUERY)));
833 if (xConnection.is())
835 Reference< XDatabaseMetaData> xMetaData(xConnection->getMetaData());
836 Reference< XNumberFormatsSupplier> xFormatSupplier( aStaticTools.getNumberFormats( xConnection, sal_True ) );
837 Reference< XNumberFormatter> xFormatter( NumberFormatter::create(m_aContext.getUNOContext()), UNO_QUERY_THROW );
838 xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
840 Reference< XColumnsSupplier> xSupplyCols(m_xModelAsIndex, UNO_QUERY);
841 Reference< XNameAccess> xFields(xSupplyCols->getColumns(), UNO_QUERY);
843 // now add the filter rows
846 for ( FmFilterRows::const_iterator row = m_aFilterRows.begin(); row != m_aFilterRows.end(); ++row )
848 const FmFilterRow& rRow = *row;
850 if ( rRow.empty() )
851 continue;
853 OUStringBuffer aRowFilter;
854 for ( FmFilterRow::const_iterator condition = rRow.begin(); condition != rRow.end(); ++condition )
856 // get the field of the controls map
857 Reference< XControl > xControl( condition->first, UNO_QUERY_THROW );
858 Reference< XPropertySet > xModelProps( xControl->getModel(), UNO_QUERY_THROW );
859 Reference< XPropertySet > xField( xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY_THROW );
861 OUString sFilterValue( condition->second );
863 OUString sErrorMsg, sCriteria;
864 const ::rtl::Reference< ISQLParseNode > xParseNode =
865 predicateTree( sErrorMsg, sFilterValue, xFormatter, xField );
866 OSL_ENSURE( xParseNode.is(), "FormController::getFastPropertyValue: could not parse the field value predicate!" );
867 if ( xParseNode.is() )
869 // don't use a parse context here, we need it unlocalized
870 xParseNode->parseNodeToStr( sCriteria, xConnection, NULL );
871 if ( condition != rRow.begin() )
872 aRowFilter.appendAscii( " AND " );
873 aRowFilter.append( sCriteria );
876 if ( aRowFilter.getLength() > 0 )
878 if ( aFilter.getLength() )
879 aFilter.appendAscii( " OR " );
881 aFilter.appendAscii( "( " );
882 aFilter.append( aRowFilter.makeStringAndClear() );
883 aFilter.appendAscii( " )" );
887 catch( const Exception& )
889 DBG_UNHANDLED_EXCEPTION();
890 aFilter.setLength(0);
893 rValue <<= aFilter.makeStringAndClear();
895 break;
897 case FM_ATTR_FORM_OPERATIONS:
898 rValue <<= m_xFormOperations;
899 break;
903 //------------------------------------------------------------------------------
904 Reference< XPropertySetInfo > FormController::getPropertySetInfo() throw( RuntimeException )
906 static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
907 return xInfo;
910 //------------------------------------------------------------------------------
911 #define DECL_PROP_CORE(varname, type) \
912 pDesc[nPos++] = Property(FM_PROP_##varname, FM_ATTR_##varname, ::getCppuType((const type*)0),
915 #define DECL_PROP1(varname, type, attrib1) \
916 DECL_PROP_CORE(varname, type) PropertyAttribute::attrib1)
918 //------------------------------------------------------------------------------
919 void FormController::fillProperties(
920 Sequence< Property >& /* [out] */ _rProps,
921 Sequence< Property >& /* [out] */ /*_rAggregateProps*/
922 ) const
924 _rProps.realloc(2);
925 sal_Int32 nPos = 0;
926 Property* pDesc = _rProps.getArray();
927 DECL_PROP1(FILTER, OUString, READONLY);
928 DECL_PROP1(FORM_OPERATIONS, Reference< XFormOperations >, READONLY);
931 //------------------------------------------------------------------------------
932 ::cppu::IPropertyArrayHelper& FormController::getInfoHelper()
934 return *getArrayHelper();
937 // XFilterController
938 //------------------------------------------------------------------------------
939 void SAL_CALL FormController::addFilterControllerListener( const Reference< XFilterControllerListener >& _Listener ) throw( RuntimeException )
941 m_aFilterListeners.addInterface( _Listener );
944 //------------------------------------------------------------------------------
945 void SAL_CALL FormController::removeFilterControllerListener( const Reference< XFilterControllerListener >& _Listener ) throw( RuntimeException )
947 m_aFilterListeners.removeInterface( _Listener );
950 //------------------------------------------------------------------------------
951 ::sal_Int32 SAL_CALL FormController::getFilterComponents() throw( ::com::sun::star::uno::RuntimeException )
953 ::osl::MutexGuard aGuard( m_aMutex );
954 impl_checkDisposed_throw();
956 return m_aFilterComponents.size();
959 //------------------------------------------------------------------------------
960 ::sal_Int32 SAL_CALL FormController::getDisjunctiveTerms() throw( ::com::sun::star::uno::RuntimeException )
962 ::osl::MutexGuard aGuard( m_aMutex );
963 impl_checkDisposed_throw();
965 return m_aFilterRows.size();
968 //------------------------------------------------------------------------------
969 void SAL_CALL FormController::setPredicateExpression( ::sal_Int32 _Component, ::sal_Int32 _Term, const OUString& _PredicateExpression ) throw( RuntimeException, IndexOutOfBoundsException )
971 ::osl::MutexGuard aGuard( m_aMutex );
972 impl_checkDisposed_throw();
974 if ( ( _Component < 0 ) || ( _Component >= getFilterComponents() ) || ( _Term < 0 ) || ( _Term >= getDisjunctiveTerms() ) )
975 throw IndexOutOfBoundsException( OUString(), *this );
977 Reference< XTextComponent > xText( m_aFilterComponents[ _Component ] );
978 xText->setText( _PredicateExpression );
980 FmFilterRow& rFilterRow = m_aFilterRows[ _Term ];
981 if ( !_PredicateExpression.isEmpty() )
982 rFilterRow[ xText ] = _PredicateExpression;
983 else
984 rFilterRow.erase( xText );
987 //------------------------------------------------------------------------------
988 Reference< XControl > FormController::getFilterComponent( ::sal_Int32 _Component ) throw( RuntimeException, IndexOutOfBoundsException )
990 ::osl::MutexGuard aGuard( m_aMutex );
991 impl_checkDisposed_throw();
993 if ( ( _Component < 0 ) || ( _Component >= getFilterComponents() ) )
994 throw IndexOutOfBoundsException( OUString(), *this );
996 return Reference< XControl >( m_aFilterComponents[ _Component ], UNO_QUERY );
999 //------------------------------------------------------------------------------
1000 Sequence< Sequence< OUString > > FormController::getPredicateExpressions() throw( RuntimeException )
1002 ::osl::MutexGuard aGuard( m_aMutex );
1003 impl_checkDisposed_throw();
1005 Sequence< Sequence< OUString > > aExpressions( m_aFilterRows.size() );
1006 sal_Int32 termIndex = 0;
1007 for ( FmFilterRows::const_iterator row = m_aFilterRows.begin();
1008 row != m_aFilterRows.end();
1009 ++row, ++termIndex
1012 const FmFilterRow& rRow( *row );
1014 Sequence< OUString > aConjunction( m_aFilterComponents.size() );
1015 sal_Int32 componentIndex = 0;
1016 for ( FilterComponents::const_iterator comp = m_aFilterComponents.begin();
1017 comp != m_aFilterComponents.end();
1018 ++comp, ++componentIndex
1021 FmFilterRow::const_iterator predicate = rRow.find( *comp );
1022 if ( predicate != rRow.end() )
1023 aConjunction[ componentIndex ] = predicate->second;
1026 aExpressions[ termIndex ] = aConjunction;
1029 return aExpressions;
1032 //------------------------------------------------------------------------------
1033 void SAL_CALL FormController::removeDisjunctiveTerm( ::sal_Int32 _Term ) throw (IndexOutOfBoundsException, RuntimeException)
1035 // SYNCHRONIZED -->
1036 ::osl::ClearableMutexGuard aGuard( m_aMutex );
1037 impl_checkDisposed_throw();
1039 if ( ( _Term < 0 ) || ( _Term >= getDisjunctiveTerms() ) )
1040 throw IndexOutOfBoundsException( OUString(), *this );
1042 // if the to-be-deleted row is our current row, we need to shift
1043 if ( _Term == m_nCurrentFilterPosition )
1045 if ( m_nCurrentFilterPosition < sal_Int32( m_aFilterRows.size() - 1 ) )
1046 ++m_nCurrentFilterPosition;
1047 else
1048 --m_nCurrentFilterPosition;
1051 FmFilterRows::iterator pos = m_aFilterRows.begin() + _Term;
1052 m_aFilterRows.erase( pos );
1054 // adjust m_nCurrentFilterPosition if the removed row preceeded it
1055 if ( _Term < m_nCurrentFilterPosition )
1056 --m_nCurrentFilterPosition;
1058 OSL_POSTCOND( ( m_nCurrentFilterPosition < 0 ) == ( m_aFilterRows.empty() ),
1059 "FormController::removeDisjunctiveTerm: inconsistency!" );
1061 // update the texts in the filter controls
1062 impl_setTextOnAllFilter_throw();
1064 FilterEvent aEvent;
1065 aEvent.Source = *this;
1066 aEvent.DisjunctiveTerm = _Term;
1067 aGuard.clear();
1068 // <-- SYNCHRONIZED
1070 m_aFilterListeners.notifyEach( &XFilterControllerListener::disjunctiveTermRemoved, aEvent );
1073 //------------------------------------------------------------------------------
1074 void SAL_CALL FormController::appendEmptyDisjunctiveTerm() throw (RuntimeException)
1076 // SYNCHRONIZED -->
1077 ::osl::ClearableMutexGuard aGuard( m_aMutex );
1078 impl_checkDisposed_throw();
1080 impl_appendEmptyFilterRow( aGuard );
1081 // <-- SYNCHRONIZED
1084 //------------------------------------------------------------------------------
1085 ::sal_Int32 SAL_CALL FormController::getActiveTerm() throw (RuntimeException)
1087 ::osl::MutexGuard aGuard( m_aMutex );
1088 impl_checkDisposed_throw();
1090 return m_nCurrentFilterPosition;
1093 //------------------------------------------------------------------------------
1094 void SAL_CALL FormController::setActiveTerm( ::sal_Int32 _ActiveTerm ) throw (IndexOutOfBoundsException, RuntimeException)
1096 ::osl::MutexGuard aGuard( m_aMutex );
1097 impl_checkDisposed_throw();
1099 if ( ( _ActiveTerm < 0 ) || ( _ActiveTerm >= getDisjunctiveTerms() ) )
1100 throw IndexOutOfBoundsException( OUString(), *this );
1102 if ( _ActiveTerm == getActiveTerm() )
1103 return;
1105 m_nCurrentFilterPosition = _ActiveTerm;
1106 impl_setTextOnAllFilter_throw();
1109 // XElementAccess
1110 //------------------------------------------------------------------------------
1111 sal_Bool SAL_CALL FormController::hasElements(void) throw( RuntimeException )
1113 ::osl::MutexGuard aGuard( m_aMutex );
1114 return !m_aChildren.empty();
1117 //------------------------------------------------------------------------------
1118 Type SAL_CALL FormController::getElementType(void) throw( RuntimeException )
1120 return ::getCppuType((const Reference< XFormController>*)0);
1124 // XEnumerationAccess
1125 //------------------------------------------------------------------------------
1126 Reference< XEnumeration > SAL_CALL FormController::createEnumeration(void) throw( RuntimeException )
1128 ::osl::MutexGuard aGuard( m_aMutex );
1129 return new ::comphelper::OEnumerationByIndex(this);
1132 // XIndexAccess
1133 //------------------------------------------------------------------------------
1134 sal_Int32 SAL_CALL FormController::getCount(void) throw( RuntimeException )
1136 ::osl::MutexGuard aGuard( m_aMutex );
1137 return m_aChildren.size();
1140 //------------------------------------------------------------------------------
1141 Any SAL_CALL FormController::getByIndex(sal_Int32 Index) throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException )
1143 ::osl::MutexGuard aGuard( m_aMutex );
1144 if (Index < 0 ||
1145 Index >= (sal_Int32)m_aChildren.size())
1146 throw IndexOutOfBoundsException();
1148 return makeAny( m_aChildren[ Index ] );
1151 // EventListener
1152 //------------------------------------------------------------------------------
1153 void SAL_CALL FormController::disposing(const EventObject& e) throw( RuntimeException )
1155 // Ist der Container disposed worden
1156 ::osl::MutexGuard aGuard( m_aMutex );
1157 Reference< XControlContainer > xContainer(e.Source, UNO_QUERY);
1158 if (xContainer.is())
1160 setContainer(Reference< XControlContainer > ());
1162 else
1164 // ist ein Control disposed worden
1165 Reference< XControl > xControl(e.Source, UNO_QUERY);
1166 if (xControl.is())
1168 if (getContainer().is())
1169 removeControl(xControl);
1174 // OComponentHelper
1175 //-----------------------------------------------------------------------------
1176 void FormController::disposeAllFeaturesAndDispatchers() SAL_THROW(())
1178 for ( DispatcherContainer::iterator aDispatcher = m_aFeatureDispatchers.begin();
1179 aDispatcher != m_aFeatureDispatchers.end();
1180 ++aDispatcher
1185 ::comphelper::disposeComponent( aDispatcher->second );
1187 catch( const Exception& )
1189 DBG_UNHANDLED_EXCEPTION();
1192 m_aFeatureDispatchers.clear();
1195 //-----------------------------------------------------------------------------
1196 void FormController::disposing(void)
1198 EventObject aEvt( *this );
1200 // if we're still active, simulate a "deactivated" event
1201 if ( m_xActiveControl.is() )
1202 m_aActivateListeners.notifyEach( &XFormControllerListener::formDeactivated, aEvt );
1204 // notify all our listeners
1205 m_aActivateListeners.disposeAndClear(aEvt);
1206 m_aModifyListeners.disposeAndClear(aEvt);
1207 m_aErrorListeners.disposeAndClear(aEvt);
1208 m_aDeleteListeners.disposeAndClear(aEvt);
1209 m_aRowSetApproveListeners.disposeAndClear(aEvt);
1210 m_aParameterListeners.disposeAndClear(aEvt);
1211 m_aFilterListeners.disposeAndClear(aEvt);
1213 removeBoundFieldListener();
1214 stopFiltering();
1216 m_pControlBorderManager->restoreAll();
1218 m_aFilterRows.clear();
1220 ::osl::MutexGuard aGuard( m_aMutex );
1221 m_xActiveControl = NULL;
1222 implSetCurrentControl( NULL );
1224 // clean up our children
1225 for (FmFormControllers::const_iterator i = m_aChildren.begin();
1226 i != m_aChildren.end(); ++i)
1228 // search the position of the model within the form
1229 Reference< XFormComponent > xForm((*i)->getModel(), UNO_QUERY);
1230 sal_uInt32 nPos = m_xModelAsIndex->getCount();
1231 Reference< XFormComponent > xTemp;
1232 for( ; nPos; )
1235 m_xModelAsIndex->getByIndex( --nPos ) >>= xTemp;
1236 if ( xForm.get() == xTemp.get() )
1238 Reference< XInterface > xIfc( *i, UNO_QUERY );
1239 m_xModelAsManager->detach( nPos, xIfc );
1240 break;
1244 Reference< XComponent > (*i, UNO_QUERY)->dispose();
1246 m_aChildren.clear();
1248 disposeAllFeaturesAndDispatchers();
1250 if ( m_xFormOperations.is() )
1251 m_xFormOperations->dispose();
1252 m_xFormOperations.clear();
1254 if (m_bDBConnection)
1255 unload();
1257 setContainer( NULL );
1258 setModel( NULL );
1259 setParent( NULL );
1261 ::comphelper::disposeComponent( m_xComposer );
1263 m_bDBConnection = sal_False;
1266 //------------------------------------------------------------------------------
1267 namespace
1269 static bool lcl_shouldUseDynamicControlBorder( const Reference< XInterface >& _rxForm, const Any& _rDynamicColorProp )
1271 bool bDoUse = false;
1272 if ( !( _rDynamicColorProp >>= bDoUse ) )
1274 DocumentType eDocType = DocumentClassification::classifyHostDocument( _rxForm );
1275 return ControlLayouter::useDynamicBorderColor( eDocType );
1277 return bDoUse;
1281 //------------------------------------------------------------------------------
1282 void SAL_CALL FormController::propertyChange(const PropertyChangeEvent& evt) throw( RuntimeException )
1284 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1285 if ( evt.PropertyName == FM_PROP_BOUNDFIELD )
1287 Reference<XPropertySet> xOldBound;
1288 evt.OldValue >>= xOldBound;
1289 if ( !xOldBound.is() && evt.NewValue.hasValue() )
1291 Reference< XControlModel > xControlModel(evt.Source,UNO_QUERY);
1292 Reference< XControl > xControl = findControl(m_aControls,xControlModel,sal_False,sal_False);
1293 if ( xControl.is() )
1295 startControlModifyListening( xControl );
1296 Reference<XPropertySet> xProp(xControlModel,UNO_QUERY);
1297 if ( xProp.is() )
1298 xProp->removePropertyChangeListener(FM_PROP_BOUNDFIELD, this);
1302 else
1304 sal_Bool bModifiedChanged = (evt.PropertyName == FM_PROP_ISMODIFIED);
1305 sal_Bool bNewChanged = (evt.PropertyName == FM_PROP_ISNEW);
1306 if (bModifiedChanged || bNewChanged)
1308 ::osl::MutexGuard aGuard( m_aMutex );
1309 if (bModifiedChanged)
1310 m_bCurrentRecordModified = ::comphelper::getBOOL(evt.NewValue);
1311 else
1312 m_bCurrentRecordNew = ::comphelper::getBOOL(evt.NewValue);
1314 // toggle the locking
1315 if (m_bLocked != determineLockState())
1317 m_bLocked = !m_bLocked;
1318 setLocks();
1319 if (isListeningForChanges())
1320 startListening();
1321 else
1322 stopListening();
1325 if ( bNewChanged )
1326 m_aToggleEvent.Call();
1328 if (!m_bCurrentRecordModified)
1329 m_bModified = sal_False;
1331 else if ( evt.PropertyName == FM_PROP_DYNAMIC_CONTROL_BORDER )
1333 bool bEnable = lcl_shouldUseDynamicControlBorder( evt.Source, evt.NewValue );
1334 if ( bEnable )
1336 m_pControlBorderManager->enableDynamicBorderColor();
1337 if ( m_xActiveControl.is() )
1338 m_pControlBorderManager->focusGained( m_xActiveControl.get() );
1340 else
1342 m_pControlBorderManager->disableDynamicBorderColor();
1348 //------------------------------------------------------------------------------
1349 bool FormController::replaceControl( const Reference< XControl >& _rxExistentControl, const Reference< XControl >& _rxNewControl )
1351 bool bSuccess = false;
1354 Reference< XIdentifierReplace > xContainer( getContainer(), UNO_QUERY );
1355 DBG_ASSERT( xContainer.is(), "FormController::replaceControl: yes, it's not required by the service description, but XItentifierReplaces would be nice!" );
1356 if ( xContainer.is() )
1358 // look up the ID of _rxExistentControl
1359 Sequence< sal_Int32 > aIdentifiers( xContainer->getIdentifiers() );
1360 const sal_Int32* pIdentifiers = aIdentifiers.getConstArray();
1361 const sal_Int32* pIdentifiersEnd = aIdentifiers.getConstArray() + aIdentifiers.getLength();
1362 for ( ; pIdentifiers != pIdentifiersEnd; ++pIdentifiers )
1364 Reference< XControl > xCheck( xContainer->getByIdentifier( *pIdentifiers ), UNO_QUERY );
1365 if ( xCheck == _rxExistentControl )
1366 break;
1368 DBG_ASSERT( pIdentifiers != pIdentifiersEnd, "FormController::replaceControl: did not find the control in the container!" );
1369 if ( pIdentifiers != pIdentifiersEnd )
1371 bool bReplacedWasActive = ( m_xActiveControl.get() == _rxExistentControl.get() );
1372 bool bReplacedWasCurrent = ( m_xCurrentControl.get() == _rxExistentControl.get() );
1374 if ( bReplacedWasActive )
1376 m_xActiveControl = NULL;
1377 implSetCurrentControl( NULL );
1379 else if ( bReplacedWasCurrent )
1381 implSetCurrentControl( _rxNewControl );
1384 // carry over the model
1385 _rxNewControl->setModel( _rxExistentControl->getModel() );
1387 xContainer->replaceByIdentifer( *pIdentifiers, makeAny( _rxNewControl ) );
1388 bSuccess = true;
1390 if ( bReplacedWasActive )
1392 Reference< XWindow > xControlWindow( _rxNewControl, UNO_QUERY );
1393 if ( xControlWindow.is() )
1394 xControlWindow->setFocus();
1399 catch( const Exception& )
1401 DBG_UNHANDLED_EXCEPTION();
1404 Reference< XControl > xDisposeIt( bSuccess ? _rxExistentControl : _rxNewControl );
1405 ::comphelper::disposeComponent( xDisposeIt );
1406 return bSuccess;
1409 //------------------------------------------------------------------------------
1410 void FormController::toggleAutoFields(sal_Bool bAutoFields)
1412 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1415 Sequence< Reference< XControl > > aControlsCopy( m_aControls );
1416 const Reference< XControl >* pControls = aControlsCopy.getConstArray();
1417 sal_Int32 nControls = aControlsCopy.getLength();
1419 if (bAutoFields)
1421 // as we don't want new controls to be attached to the scripting environment
1422 // we change attach flags
1423 m_bAttachEvents = sal_False;
1424 for (sal_Int32 i = nControls; i > 0;)
1426 Reference< XControl > xControl = pControls[--i];
1427 if (xControl.is())
1429 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
1430 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
1432 // does the model use a bound field ?
1433 Reference< XPropertySet > xField;
1434 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
1436 // is it a autofield?
1437 if ( xField.is()
1438 && ::comphelper::hasProperty( FM_PROP_AUTOINCREMENT, xField )
1439 && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_AUTOINCREMENT ) )
1442 replaceControl( xControl, new FmXAutoControl() );
1447 m_bAttachEvents = sal_True;
1449 else
1451 m_bDetachEvents = sal_False;
1452 for (sal_Int32 i = nControls; i > 0;)
1454 Reference< XControl > xControl = pControls[--i];
1455 if (xControl.is())
1457 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
1458 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
1460 // does the model use a bound field ?
1461 Reference< XPropertySet > xField;
1462 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
1464 // is it a autofield?
1465 if ( xField.is()
1466 && ::comphelper::hasProperty( FM_PROP_AUTOINCREMENT, xField )
1467 && ::comphelper::getBOOL( xField->getPropertyValue(FM_PROP_AUTOINCREMENT ) )
1470 OUString sServiceName;
1471 OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DEFAULTCONTROL ) >>= sServiceName );
1472 Reference< XControl > xNewControl( m_aContext.createComponent( sServiceName ), UNO_QUERY );
1473 replaceControl( xControl, xNewControl );
1478 m_bDetachEvents = sal_True;
1482 //------------------------------------------------------------------------------
1483 IMPL_LINK_NOARG(FormController, OnToggleAutoFields)
1485 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1487 toggleAutoFields(m_bCurrentRecordNew);
1488 return 1L;
1491 // XTextListener
1492 //------------------------------------------------------------------------------
1493 void SAL_CALL FormController::textChanged(const TextEvent& e) throw( RuntimeException )
1495 // SYNCHRONIZED -->
1496 ::osl::ClearableMutexGuard aGuard( m_aMutex );
1497 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1498 if ( !m_bFiltering )
1500 impl_onModify();
1501 return;
1504 if ( m_bSuspendFilterTextListening )
1505 return;
1507 Reference< XTextComponent > xText(e.Source,UNO_QUERY);
1508 OUString aText = xText->getText();
1510 if ( m_aFilterRows.empty() )
1511 appendEmptyDisjunctiveTerm();
1513 // Suchen der aktuellen Row
1514 if ( ( (size_t)m_nCurrentFilterPosition >= m_aFilterRows.size() ) || ( m_nCurrentFilterPosition < 0 ) )
1516 OSL_ENSURE( false, "FormController::textChanged: m_nCurrentFilterPosition is wrong!" );
1517 return;
1520 FmFilterRow& rRow = m_aFilterRows[ m_nCurrentFilterPosition ];
1522 // do we have a new filter
1523 if (!aText.isEmpty())
1524 rRow[xText] = aText;
1525 else
1527 // do we have the control in the row
1528 FmFilterRow::iterator iter = rRow.find(xText);
1529 // erase the entry out of the row
1530 if (iter != rRow.end())
1531 rRow.erase(iter);
1534 // multiplex the event to our FilterControllerListeners
1535 FilterEvent aEvent;
1536 aEvent.Source = *this;
1537 aEvent.FilterComponent = ::std::find( m_aFilterComponents.begin(), m_aFilterComponents.end(), xText ) - m_aFilterComponents.begin();
1538 aEvent.DisjunctiveTerm = getActiveTerm();
1539 aEvent.PredicateExpression = aText;
1541 aGuard.clear();
1542 // <-- SYNCHRONIZED
1544 // notify the changed filter expression
1545 m_aFilterListeners.notifyEach( &XFilterControllerListener::predicateExpressionChanged, aEvent );
1548 // XItemListener
1549 //------------------------------------------------------------------------------
1550 void SAL_CALL FormController::itemStateChanged(const ItemEvent& /*rEvent*/) throw( RuntimeException )
1552 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1553 impl_onModify();
1556 // XModificationBroadcaster
1557 //------------------------------------------------------------------------------
1558 void SAL_CALL FormController::addModifyListener(const Reference< XModifyListener > & l) throw( RuntimeException )
1560 ::osl::MutexGuard aGuard( m_aMutex );
1561 impl_checkDisposed_throw();
1562 m_aModifyListeners.addInterface( l );
1565 //------------------------------------------------------------------------------
1566 void FormController::removeModifyListener(const Reference< XModifyListener > & l) throw( RuntimeException )
1568 ::osl::MutexGuard aGuard( m_aMutex );
1569 impl_checkDisposed_throw();
1570 m_aModifyListeners.removeInterface( l );
1573 // XModificationListener
1574 //------------------------------------------------------------------------------
1575 void FormController::modified( const EventObject& _rEvent ) throw( RuntimeException )
1577 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1581 if ( _rEvent.Source != m_xActiveControl )
1582 { // let this control grab the focus
1583 // (this case may happen if somebody moves the scroll wheel of the mouse over a control
1584 // which does not have the focus)
1585 // 85511 - 29.05.2001 - frank.schoenheit@germany.sun.com
1587 // also, it happens when an image control gets a new image by double-clicking it
1588 // #i88458# / 2009-01-12 / frank.schoenheit@sun.com
1589 Reference< XWindow > xControlWindow( _rEvent.Source, UNO_QUERY_THROW );
1590 xControlWindow->setFocus();
1593 catch( const Exception& )
1595 DBG_UNHANDLED_EXCEPTION();
1598 impl_onModify();
1601 //------------------------------------------------------------------------------
1602 void FormController::impl_checkDisposed_throw() const
1604 if ( impl_isDisposed_nofail() )
1605 throw DisposedException( OUString(), *const_cast< FormController* >( this ) );
1608 //------------------------------------------------------------------------------
1609 void FormController::impl_onModify()
1611 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1614 ::osl::MutexGuard aGuard( m_aMutex );
1615 if ( !m_bModified )
1616 m_bModified = sal_True;
1619 EventObject aEvt(static_cast<cppu::OWeakObject*>(this));
1620 m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvt );
1623 //------------------------------------------------------------------------------
1624 void FormController::impl_addFilterRow( const FmFilterRow& _row )
1626 m_aFilterRows.push_back( _row );
1628 if ( m_aFilterRows.size() == 1 )
1629 { // that's the first row ever
1630 OSL_ENSURE( m_nCurrentFilterPosition == -1, "FormController::impl_addFilterRow: inconsistency!" );
1631 m_nCurrentFilterPosition = 0;
1635 //------------------------------------------------------------------------------
1636 void FormController::impl_appendEmptyFilterRow( ::osl::ClearableMutexGuard& _rClearBeforeNotify )
1638 // SYNCHRONIZED -->
1639 impl_addFilterRow( FmFilterRow() );
1641 // notify the listeners
1642 FilterEvent aEvent;
1643 aEvent.Source = *this;
1644 aEvent.DisjunctiveTerm = (sal_Int32)m_aFilterRows.size() - 1;
1645 _rClearBeforeNotify.clear();
1646 // <-- SYNCHRONIZED
1647 m_aFilterListeners.notifyEach( &XFilterControllerListener::disjunctiveTermAdded, aEvent );
1650 //------------------------------------------------------------------------------
1651 sal_Bool FormController::determineLockState() const
1653 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1654 // a.) in filter mode we are always locked
1655 // b.) if we have no valid model or our model (a result set) is not alive -> we're locked
1656 // c.) if we are inserting everything is OK and we are not locked
1657 // d.) if are not updatable or on invalid position
1658 Reference< XResultSet > xResultSet(m_xModelAsIndex, UNO_QUERY);
1659 if (m_bFiltering || !xResultSet.is() || !isRowSetAlive(xResultSet))
1660 return sal_True;
1661 else
1662 return (m_bCanInsert && m_bCurrentRecordNew) ? sal_False
1663 : xResultSet->isBeforeFirst() || xResultSet->isAfterLast() || xResultSet->rowDeleted() || !m_bCanUpdate;
1666 // FocusListener
1667 //------------------------------------------------------------------------------
1668 void FormController::focusGained(const FocusEvent& e) throw( RuntimeException )
1670 // SYNCHRONIZED -->
1671 ::osl::ClearableMutexGuard aGuard( m_aMutex );
1672 impl_checkDisposed_throw();
1674 m_pControlBorderManager->focusGained( e.Source );
1676 Reference< XControl > xControl(e.Source, UNO_QUERY);
1677 if (m_bDBConnection)
1679 // do we need to keep the locking of the commit
1680 // we hold the lock as long as the control differs from the current
1681 // otherwise we disabled the lock
1682 m_bCommitLock = m_bCommitLock && (XControl*)xControl.get() != (XControl*)m_xCurrentControl.get();
1683 if (m_bCommitLock)
1684 return;
1686 // when do we have to commit a value to form or a filter
1687 // a.) if the current value is modified
1688 // b.) there must be a current control
1689 // c.) and it must be different from the new focus owning control or
1690 // d.) the focus is moving around (so we have only one control)
1692 if ( ( m_bModified || m_bFiltering )
1693 && m_xCurrentControl.is()
1694 && ( ( xControl.get() != m_xCurrentControl.get() )
1695 || ( ( e.FocusFlags & FocusChangeReason::AROUND )
1696 && ( m_bCycle || m_bFiltering )
1701 // check the old control if the content is ok
1702 #if OSL_DEBUG_LEVEL > 1
1703 Reference< XBoundControl > xLockingTest(m_xCurrentControl, UNO_QUERY);
1704 sal_Bool bControlIsLocked = xLockingTest.is() && xLockingTest->getLock();
1705 OSL_ENSURE(!bControlIsLocked, "FormController::Gained: I'm modified and the current control is locked ? How this ?");
1706 // normalerweise sollte ein gelocktes Control nicht modified sein, also muss wohl mein bModified aus einem anderen Kontext
1707 // gesetzt worden sein, was ich nicht verstehen wuerde ...
1708 #endif
1709 DBG_ASSERT(m_xCurrentControl.is(), "kein CurrentControl gesetzt");
1710 // zunaechst das Control fragen ob es das IFace unterstuetzt
1711 Reference< XBoundComponent > xBound(m_xCurrentControl, UNO_QUERY);
1712 if (!xBound.is() && m_xCurrentControl.is())
1713 xBound = Reference< XBoundComponent > (m_xCurrentControl->getModel(), UNO_QUERY);
1715 // lock if we lose the focus during commit
1716 m_bCommitLock = sal_True;
1718 // Commit nicht erfolgreich, Focus zuruecksetzen
1719 if (xBound.is() && !xBound->commit())
1721 // the commit failed and we don't commit again until the current control
1722 // which couldn't be commit gains the focus again
1723 Reference< XWindow > xWindow(m_xCurrentControl, UNO_QUERY);
1724 if (xWindow.is())
1725 xWindow->setFocus();
1726 return;
1728 else
1730 m_bModified = sal_False;
1731 m_bCommitLock = sal_False;
1735 if (!m_bFiltering && m_bCycle && (e.FocusFlags & FocusChangeReason::AROUND) && m_xCurrentControl.is())
1737 SQLErrorEvent aErrorEvent;
1738 OSL_ENSURE( m_xFormOperations.is(), "FormController::focusGained: hmm?" );
1739 // should have been created in setModel
1742 if ( e.FocusFlags & FocusChangeReason::FORWARD )
1744 if ( m_xFormOperations.is() && m_xFormOperations->isEnabled( FormFeature::MoveToNext ) )
1745 m_xFormOperations->execute( FormFeature::MoveToNext );
1747 else // backward
1749 if ( m_xFormOperations.is() && m_xFormOperations->isEnabled( FormFeature::MoveToPrevious ) )
1750 m_xFormOperations->execute( FormFeature::MoveToPrevious );
1753 catch ( const Exception& )
1755 // don't handle this any further. That's an ... admissible error.
1756 DBG_UNHANDLED_EXCEPTION();
1761 // Immer noch ein und dasselbe Control
1762 if ( ( m_xActiveControl == xControl )
1763 && ( xControl == m_xCurrentControl )
1766 DBG_ASSERT(m_xCurrentControl.is(), "Kein CurrentControl selektiert");
1767 return;
1770 sal_Bool bActivated = !m_xActiveControl.is() && xControl.is();
1772 m_xActiveControl = xControl;
1774 implSetCurrentControl( xControl );
1775 OSL_POSTCOND( m_xCurrentControl.is(), "implSetCurrentControl did nonsense!" );
1777 if ( bActivated )
1779 // (asynchronously) call activation handlers
1780 m_aActivationEvent.Call();
1782 // call modify listeners
1783 if ( m_bModified )
1784 m_aModifyListeners.notifyEach( &XModifyListener::modified, EventObject( *this ) );
1787 // invalidate all features which depend on the currently focused control
1788 if ( m_bDBConnection && !m_bFiltering )
1789 implInvalidateCurrentControlDependentFeatures();
1791 if ( !m_xCurrentControl.is() )
1792 return;
1794 // Control erhaelt Focus, dann eventuell in den sichtbaren Bereich
1795 Reference< XFormControllerContext > xContext( m_xContext );
1796 Reference< XControl > xCurrentControl( m_xCurrentControl );
1797 aGuard.clear();
1798 // <-- SYNCHRONIZED
1800 if ( xContext.is() )
1801 xContext->makeVisible( xCurrentControl );
1804 //------------------------------------------------------------------------------
1805 IMPL_LINK( FormController, OnActivated, void*, /**/ )
1807 EventObject aEvent;
1808 aEvent.Source = *this;
1809 m_aActivateListeners.notifyEach( &XFormControllerListener::formActivated, aEvent );
1811 return 0L;
1814 //------------------------------------------------------------------------------
1815 IMPL_LINK( FormController, OnDeactivated, void*, /**/ )
1817 EventObject aEvent;
1818 aEvent.Source = *this;
1819 m_aActivateListeners.notifyEach( &XFormControllerListener::formDeactivated, aEvent );
1821 return 0L;
1824 //------------------------------------------------------------------------------
1825 void FormController::focusLost(const FocusEvent& e) throw( RuntimeException )
1827 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1829 m_pControlBorderManager->focusLost( e.Source );
1831 Reference< XControl > xControl(e.Source, UNO_QUERY);
1832 Reference< XWindowPeer > xNext(e.NextFocus, UNO_QUERY);
1833 Reference< XControl > xNextControl = isInList(xNext);
1834 if (!xNextControl.is())
1836 m_xActiveControl = NULL;
1837 m_aDeactivationEvent.Call();
1841 //--------------------------------------------------------------------
1842 void SAL_CALL FormController::mousePressed( const awt::MouseEvent& /*_rEvent*/ ) throw (RuntimeException)
1844 // not interested in
1847 //--------------------------------------------------------------------
1848 void SAL_CALL FormController::mouseReleased( const awt::MouseEvent& /*_rEvent*/ ) throw (RuntimeException)
1850 // not interested in
1853 //--------------------------------------------------------------------
1854 void SAL_CALL FormController::mouseEntered( const awt::MouseEvent& _rEvent ) throw (RuntimeException)
1856 m_pControlBorderManager->mouseEntered( _rEvent.Source );
1859 //--------------------------------------------------------------------
1860 void SAL_CALL FormController::mouseExited( const awt::MouseEvent& _rEvent ) throw (RuntimeException)
1862 m_pControlBorderManager->mouseExited( _rEvent.Source );
1865 //--------------------------------------------------------------------
1866 void SAL_CALL FormController::componentValidityChanged( const EventObject& _rSource ) throw (RuntimeException)
1868 Reference< XControl > xControl( findControl( m_aControls, Reference< XControlModel >( _rSource.Source, UNO_QUERY ), sal_False, sal_False ) );
1869 Reference< XValidatableFormComponent > xValidatable( _rSource.Source, UNO_QUERY );
1871 OSL_ENSURE( xControl.is() && xValidatable.is(), "FormController::componentValidityChanged: huh?" );
1873 if ( xControl.is() && xValidatable.is() )
1874 m_pControlBorderManager->validityChanged( xControl, xValidatable );
1877 //--------------------------------------------------------------------
1878 void FormController::setModel(const Reference< XTabControllerModel > & Model) throw( RuntimeException )
1880 ::osl::MutexGuard aGuard( m_aMutex );
1881 impl_checkDisposed_throw();
1883 DBG_ASSERT(m_xTabController.is(), "FormController::setModel : invalid aggregate !");
1887 // disconnect from the old model
1888 if (m_xModelAsIndex.is())
1890 if (m_bDBConnection)
1892 // we are currently working on the model
1893 EventObject aEvt(m_xModelAsIndex);
1894 unloaded(aEvt);
1897 Reference< XLoadable > xForm(m_xModelAsIndex, UNO_QUERY);
1898 if (xForm.is())
1899 xForm->removeLoadListener(this);
1901 Reference< XSQLErrorBroadcaster > xBroadcaster(m_xModelAsIndex, UNO_QUERY);
1902 if (xBroadcaster.is())
1903 xBroadcaster->removeSQLErrorListener(this);
1905 Reference< XDatabaseParameterBroadcaster > xParamBroadcaster(m_xModelAsIndex, UNO_QUERY);
1906 if (xParamBroadcaster.is())
1907 xParamBroadcaster->removeParameterListener(this);
1911 disposeAllFeaturesAndDispatchers();
1913 if ( m_xFormOperations.is() )
1914 m_xFormOperations->dispose();
1915 m_xFormOperations.clear();
1917 // set the new model wait for the load event
1918 if (m_xTabController.is())
1919 m_xTabController->setModel(Model);
1920 m_xModelAsIndex = Reference< XIndexAccess > (Model, UNO_QUERY);
1921 m_xModelAsManager = Reference< XEventAttacherManager > (Model, UNO_QUERY);
1923 // only if both ifaces exit, the controller will work successful
1924 if (!m_xModelAsIndex.is() || !m_xModelAsManager.is())
1926 m_xModelAsManager = NULL;
1927 m_xModelAsIndex = NULL;
1930 if (m_xModelAsIndex.is())
1932 // re-create m_xFormOperations
1933 m_xFormOperations.set( FormOperations::createWithFormController( m_aContext.getUNOContext(), this ), UNO_SET_THROW );
1934 m_xFormOperations->setFeatureInvalidation( this );
1936 // adding load and ui interaction listeners
1937 Reference< XLoadable > xForm(Model, UNO_QUERY);
1938 if (xForm.is())
1939 xForm->addLoadListener(this);
1941 Reference< XSQLErrorBroadcaster > xBroadcaster(Model, UNO_QUERY);
1942 if (xBroadcaster.is())
1943 xBroadcaster->addSQLErrorListener(this);
1945 Reference< XDatabaseParameterBroadcaster > xParamBroadcaster(Model, UNO_QUERY);
1946 if (xParamBroadcaster.is())
1947 xParamBroadcaster->addParameterListener(this);
1949 // well, is the database already loaded?
1950 // then we have to simulate a load event
1951 Reference< XLoadable > xCursor(m_xModelAsIndex, UNO_QUERY);
1952 if (xCursor.is() && xCursor->isLoaded())
1954 EventObject aEvt(xCursor);
1955 loaded(aEvt);
1958 Reference< XPropertySet > xModelProps( m_xModelAsIndex, UNO_QUERY );
1959 Reference< XPropertySetInfo > xPropInfo( xModelProps->getPropertySetInfo() );
1960 if ( xPropInfo.is()
1961 && xPropInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER )
1962 && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_FOCUS )
1963 && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_MOUSE )
1964 && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_INVALID )
1967 bool bEnableDynamicControlBorder = lcl_shouldUseDynamicControlBorder(
1968 xModelProps.get(), xModelProps->getPropertyValue( FM_PROP_DYNAMIC_CONTROL_BORDER ) );
1969 if ( bEnableDynamicControlBorder )
1970 m_pControlBorderManager->enableDynamicBorderColor();
1971 else
1972 m_pControlBorderManager->disableDynamicBorderColor();
1974 sal_Int32 nColor = 0;
1975 if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_FOCUS ) >>= nColor )
1976 m_pControlBorderManager->setStatusColor( CONTROL_STATUS_FOCUSED, nColor );
1977 if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_MOUSE ) >>= nColor )
1978 m_pControlBorderManager->setStatusColor( CONTROL_STATUS_MOUSE_HOVER, nColor );
1979 if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_INVALID ) >>= nColor )
1980 m_pControlBorderManager->setStatusColor( CONTROL_STATUS_INVALID, nColor );
1984 catch( const Exception& )
1986 DBG_UNHANDLED_EXCEPTION();
1990 //------------------------------------------------------------------------------
1991 Reference< XTabControllerModel > FormController::getModel() throw( RuntimeException )
1993 ::osl::MutexGuard aGuard( m_aMutex );
1994 impl_checkDisposed_throw();
1996 DBG_ASSERT(m_xTabController.is(), "FormController::getModel : invalid aggregate !");
1997 if (!m_xTabController.is())
1998 return Reference< XTabControllerModel > ();
1999 return m_xTabController->getModel();
2002 //------------------------------------------------------------------------------
2003 void FormController::addToEventAttacher(const Reference< XControl > & xControl)
2005 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2006 OSL_ENSURE( xControl.is(), "FormController::addToEventAttacher: invalid control - how did you reach this?" );
2007 if ( !xControl.is() )
2008 return; /* throw IllegalArgumentException(); */
2010 // anmelden beim Eventattacher
2011 Reference< XFormComponent > xComp(xControl->getModel(), UNO_QUERY);
2012 if (xComp.is() && m_xModelAsIndex.is())
2014 // Und die Position des ControlModel darin suchen
2015 sal_uInt32 nPos = m_xModelAsIndex->getCount();
2016 Reference< XFormComponent > xTemp;
2017 for( ; nPos; )
2019 m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
2020 if ((XFormComponent*)xComp.get() == (XFormComponent*)xTemp.get())
2022 Reference< XInterface > xIfc(xControl, UNO_QUERY);
2023 m_xModelAsManager->attach( nPos, xIfc, makeAny(xControl) );
2024 break;
2030 //------------------------------------------------------------------------------
2031 void FormController::removeFromEventAttacher(const Reference< XControl > & xControl)
2033 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2034 OSL_ENSURE( xControl.is(), "FormController::removeFromEventAttacher: invalid control - how did you reach this?" );
2035 if ( !xControl.is() )
2036 return; /* throw IllegalArgumentException(); */
2038 // abmelden beim Eventattacher
2039 Reference< XFormComponent > xComp(xControl->getModel(), UNO_QUERY);
2040 if ( xComp.is() && m_xModelAsIndex.is() )
2042 // Und die Position des ControlModel darin suchen
2043 sal_uInt32 nPos = m_xModelAsIndex->getCount();
2044 Reference< XFormComponent > xTemp;
2045 for( ; nPos; )
2047 m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
2048 if ((XFormComponent*)xComp.get() == (XFormComponent*)xTemp.get())
2050 Reference< XInterface > xIfc(xControl, UNO_QUERY);
2051 m_xModelAsManager->detach( nPos, xIfc );
2052 break;
2058 //------------------------------------------------------------------------------
2059 void FormController::setContainer(const Reference< XControlContainer > & xContainer) throw( RuntimeException )
2061 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2062 Reference< XTabControllerModel > xTabModel(getModel());
2063 DBG_ASSERT(xTabModel.is() || !xContainer.is(), "No Model defined");
2064 // if we have a new container we need a model
2065 DBG_ASSERT(m_xTabController.is(), "FormController::setContainer : invalid aggregate !");
2067 ::osl::MutexGuard aGuard( m_aMutex );
2068 Reference< XContainer > xCurrentContainer;
2069 if (m_xTabController.is())
2070 xCurrentContainer = Reference< XContainer > (m_xTabController->getContainer(), UNO_QUERY);
2071 if (xCurrentContainer.is())
2073 xCurrentContainer->removeContainerListener(this);
2075 if ( m_aTabActivationTimer.IsActive() )
2076 m_aTabActivationTimer.Stop();
2078 // clear the filter map
2079 ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), RemoveComponentTextListener( this ) );
2080 m_aFilterComponents.clear();
2082 // einsammeln der Controls
2083 const Reference< XControl >* pControls = m_aControls.getConstArray();
2084 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2085 while ( pControls != pControlsEnd )
2086 implControlRemoved( *pControls++, true );
2088 // Datenbank spezifische Dinge vornehmen
2089 if (m_bDBConnection && isListeningForChanges())
2090 stopListening();
2092 m_aControls.realloc( 0 );
2095 if (m_xTabController.is())
2096 m_xTabController->setContainer(xContainer);
2098 // Welche Controls gehoeren zum Container ?
2099 if (xContainer.is() && xTabModel.is())
2101 Sequence< Reference< XControlModel > > aModels = xTabModel->getControlModels();
2102 const Reference< XControlModel > * pModels = aModels.getConstArray();
2103 Sequence< Reference< XControl > > aAllControls = xContainer->getControls();
2105 sal_Int32 nCount = aModels.getLength();
2106 m_aControls = Sequence< Reference< XControl > >( nCount );
2107 Reference< XControl > * pControls = m_aControls.getArray();
2109 // einsammeln der Controls
2110 sal_Int32 i, j;
2111 for (i = 0, j = 0; i < nCount; ++i, ++pModels )
2113 Reference< XControl > xControl = findControl( aAllControls, *pModels, sal_False, sal_True );
2114 if ( xControl.is() )
2116 pControls[j++] = xControl;
2117 implControlInserted( xControl, true );
2121 // not every model had an associated control
2122 if (j != i)
2123 m_aControls.realloc(j);
2125 // am Container horchen
2126 Reference< XContainer > xNewContainer(xContainer, UNO_QUERY);
2127 if (xNewContainer.is())
2128 xNewContainer->addContainerListener(this);
2130 // Datenbank spezifische Dinge vornehmen
2131 if (m_bDBConnection)
2133 m_bLocked = determineLockState();
2134 setLocks();
2135 if (!isLocked())
2136 startListening();
2139 // befinden sich die Controls in der richtigen Reihenfolge
2140 m_bControlsSorted = sal_True;
2143 //------------------------------------------------------------------------------
2144 Reference< XControlContainer > FormController::getContainer() throw( RuntimeException )
2146 ::osl::MutexGuard aGuard( m_aMutex );
2147 impl_checkDisposed_throw();
2149 DBG_ASSERT(m_xTabController.is(), "FormController::getContainer : invalid aggregate !");
2150 if (!m_xTabController.is())
2151 return Reference< XControlContainer > ();
2152 return m_xTabController->getContainer();
2155 //------------------------------------------------------------------------------
2156 Sequence< Reference< XControl > > FormController::getControls(void) throw( RuntimeException )
2158 ::osl::MutexGuard aGuard( m_aMutex );
2159 impl_checkDisposed_throw();
2161 if (!m_bControlsSorted)
2163 Reference< XTabControllerModel > xModel = getModel();
2164 if (!xModel.is())
2165 return m_aControls;
2167 Sequence< Reference< XControlModel > > aControlModels = xModel->getControlModels();
2168 const Reference< XControlModel > * pModels = aControlModels.getConstArray();
2169 sal_Int32 nModels = aControlModels.getLength();
2171 Sequence< Reference< XControl > > aNewControls(nModels);
2173 Reference< XControl > * pControls = aNewControls.getArray();
2174 Reference< XControl > xControl;
2176 // Umsortieren der Controls entsprechend der TabReihenfolge
2177 sal_Int32 j = 0;
2178 for (sal_Int32 i = 0; i < nModels; ++i, ++pModels )
2180 xControl = findControl( m_aControls, *pModels, sal_True, sal_True );
2181 if ( xControl.is() )
2182 pControls[j++] = xControl;
2185 // not every model had an associated control
2186 if ( j != nModels )
2187 aNewControls.realloc( j );
2189 m_aControls = aNewControls;
2190 m_bControlsSorted = sal_True;
2192 return m_aControls;
2195 //------------------------------------------------------------------------------
2196 void FormController::autoTabOrder() throw( RuntimeException )
2198 ::osl::MutexGuard aGuard( m_aMutex );
2199 impl_checkDisposed_throw();
2201 DBG_ASSERT(m_xTabController.is(), "FormController::autoTabOrder : invalid aggregate !");
2202 if (m_xTabController.is())
2203 m_xTabController->autoTabOrder();
2206 //------------------------------------------------------------------------------
2207 void FormController::activateTabOrder() throw( RuntimeException )
2209 ::osl::MutexGuard aGuard( m_aMutex );
2210 impl_checkDisposed_throw();
2212 DBG_ASSERT(m_xTabController.is(), "FormController::activateTabOrder : invalid aggregate !");
2213 if (m_xTabController.is())
2214 m_xTabController->activateTabOrder();
2217 //------------------------------------------------------------------------------
2218 void FormController::setControlLock(const Reference< XControl > & xControl)
2220 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2221 sal_Bool bLocked = isLocked();
2223 // es wird gelockt
2224 // a.) wenn der ganze Datensatz gesperrt ist
2225 // b.) wenn das zugehoerige Feld gespeert ist
2226 Reference< XBoundControl > xBound(xControl, UNO_QUERY);
2227 if (xBound.is() && (( (bLocked && bLocked != xBound->getLock()) ||
2228 !bLocked))) // beim entlocken immer einzelne Felder ueberpr�fen
2230 // gibt es eine Datenquelle
2231 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
2232 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
2234 // wie sieht mit den Properties ReadOnly und Enable aus
2235 sal_Bool bTouch = sal_True;
2236 if (::comphelper::hasProperty(FM_PROP_ENABLED, xSet))
2237 bTouch = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ENABLED));
2238 if (::comphelper::hasProperty(FM_PROP_READONLY, xSet))
2239 bTouch = !::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_READONLY));
2241 if (bTouch)
2243 Reference< XPropertySet > xField;
2244 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
2245 if (xField.is())
2247 if (bLocked)
2248 xBound->setLock(bLocked);
2249 else
2253 Any aVal = xField->getPropertyValue(FM_PROP_ISREADONLY);
2254 if (aVal.hasValue() && ::comphelper::getBOOL(aVal))
2255 xBound->setLock(sal_True);
2256 else
2257 xBound->setLock(bLocked);
2259 catch( const Exception& )
2261 DBG_UNHANDLED_EXCEPTION();
2271 //------------------------------------------------------------------------------
2272 void FormController::setLocks()
2274 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2275 // alle Controls, die mit einer Datenquelle verbunden sind locken/unlocken
2276 const Reference< XControl >* pControls = m_aControls.getConstArray();
2277 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2278 while ( pControls != pControlsEnd )
2279 setControlLock( *pControls++ );
2282 //------------------------------------------------------------------------------
2283 namespace
2285 bool lcl_shouldListenForModifications( const Reference< XControl >& _rxControl, const Reference< XPropertyChangeListener >& _rxBoundFieldListener )
2287 bool bShould = false;
2289 Reference< XBoundComponent > xBound( _rxControl, UNO_QUERY );
2290 if ( xBound.is() )
2292 bShould = true;
2294 else if ( _rxControl.is() )
2296 Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY );
2297 if ( xModelProps.is() && ::comphelper::hasProperty( FM_PROP_BOUNDFIELD, xModelProps ) )
2299 Reference< XPropertySet > xField;
2300 xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField;
2301 bShould = xField.is();
2303 if ( !bShould && _rxBoundFieldListener.is() )
2304 xModelProps->addPropertyChangeListener( FM_PROP_BOUNDFIELD, _rxBoundFieldListener );
2308 return bShould;
2312 //------------------------------------------------------------------------------
2313 void FormController::startControlModifyListening(const Reference< XControl > & xControl)
2315 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2317 bool bModifyListening = lcl_shouldListenForModifications( xControl, this );
2319 // artificial while
2320 while ( bModifyListening )
2322 Reference< XModifyBroadcaster > xMod(xControl, UNO_QUERY);
2323 if (xMod.is())
2325 xMod->addModifyListener(this);
2326 break;
2329 // alle die Text um vorzeitig ein modified zu erkennen
2330 Reference< XTextComponent > xText(xControl, UNO_QUERY);
2331 if (xText.is())
2333 xText->addTextListener(this);
2334 break;
2337 Reference< XCheckBox > xBox(xControl, UNO_QUERY);
2338 if (xBox.is())
2340 xBox->addItemListener(this);
2341 break;
2344 Reference< XComboBox > xCbBox(xControl, UNO_QUERY);
2345 if (xCbBox.is())
2347 xCbBox->addItemListener(this);
2348 break;
2351 Reference< XListBox > xListBox(xControl, UNO_QUERY);
2352 if (xListBox.is())
2354 xListBox->addItemListener(this);
2355 break;
2357 break;
2361 //------------------------------------------------------------------------------
2362 void FormController::stopControlModifyListening(const Reference< XControl > & xControl)
2364 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2366 bool bModifyListening = lcl_shouldListenForModifications( xControl, NULL );
2368 // kuenstliches while
2369 while (bModifyListening)
2371 Reference< XModifyBroadcaster > xMod(xControl, UNO_QUERY);
2372 if (xMod.is())
2374 xMod->removeModifyListener(this);
2375 break;
2377 // alle die Text um vorzeitig ein modified zu erkennen
2378 Reference< XTextComponent > xText(xControl, UNO_QUERY);
2379 if (xText.is())
2381 xText->removeTextListener(this);
2382 break;
2385 Reference< XCheckBox > xBox(xControl, UNO_QUERY);
2386 if (xBox.is())
2388 xBox->removeItemListener(this);
2389 break;
2392 Reference< XComboBox > xCbBox(xControl, UNO_QUERY);
2393 if (xCbBox.is())
2395 xCbBox->removeItemListener(this);
2396 break;
2399 Reference< XListBox > xListBox(xControl, UNO_QUERY);
2400 if (xListBox.is())
2402 xListBox->removeItemListener(this);
2403 break;
2405 break;
2409 //------------------------------------------------------------------------------
2410 void FormController::startListening()
2412 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2413 m_bModified = sal_False;
2415 // jetzt anmelden bei gebundenen feldern
2416 const Reference< XControl >* pControls = m_aControls.getConstArray();
2417 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2418 while ( pControls != pControlsEnd )
2419 startControlModifyListening( *pControls++ );
2422 //------------------------------------------------------------------------------
2423 void FormController::stopListening()
2425 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2426 m_bModified = sal_False;
2428 // jetzt anmelden bei gebundenen feldern
2429 const Reference< XControl >* pControls = m_aControls.getConstArray();
2430 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2431 while ( pControls != pControlsEnd )
2432 stopControlModifyListening( *pControls++ );
2436 //------------------------------------------------------------------------------
2437 Reference< XControl > FormController::findControl(Sequence< Reference< XControl > >& _rControls, const Reference< XControlModel > & xCtrlModel ,sal_Bool _bRemove,sal_Bool _bOverWrite) const
2439 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2440 DBG_ASSERT( xCtrlModel.is(), "findControl - welches ?!" );
2442 Reference< XControl >* pControls = _rControls.getArray();
2443 Reference< XControlModel > xModel;
2444 for ( sal_Int32 i = 0, nCount = _rControls.getLength(); i < nCount; ++i, ++pControls )
2446 if ( pControls->is() )
2448 xModel = (*pControls)->getModel();
2449 if ( xModel.get() == xCtrlModel.get() )
2451 Reference< XControl > xControl( *pControls );
2452 if ( _bRemove )
2453 ::comphelper::removeElementAt( _rControls, i );
2454 else if ( _bOverWrite )
2455 *pControls = Reference< XControl >();
2456 return xControl;
2460 return Reference< XControl > ();
2463 //------------------------------------------------------------------------------
2464 void FormController::implControlInserted( const Reference< XControl>& _rxControl, bool _bAddToEventAttacher )
2466 Reference< XWindow > xWindow( _rxControl, UNO_QUERY );
2467 if ( xWindow.is() )
2469 xWindow->addFocusListener( this );
2470 xWindow->addMouseListener( this );
2472 if ( _bAddToEventAttacher )
2473 addToEventAttacher( _rxControl );
2476 // add a dispatch interceptor to the control (if supported)
2477 Reference< XDispatchProviderInterception > xInterception( _rxControl, UNO_QUERY );
2478 if ( xInterception.is() )
2479 createInterceptor( xInterception );
2481 if ( _rxControl.is() )
2483 Reference< XControlModel > xModel( _rxControl->getModel() );
2485 // we want to know about the reset of the model of our controls
2486 // (for correctly resetting m_bModified)
2487 Reference< XReset > xReset( xModel, UNO_QUERY );
2488 if ( xReset.is() )
2489 xReset->addResetListener( this );
2491 // and we want to know about the validity, to visually indicate it
2492 Reference< XValidatableFormComponent > xValidatable( xModel, UNO_QUERY );
2493 if ( xValidatable.is() )
2495 xValidatable->addFormComponentValidityListener( this );
2496 m_pControlBorderManager->validityChanged( _rxControl, xValidatable );
2502 //------------------------------------------------------------------------------
2503 void FormController::implControlRemoved( const Reference< XControl>& _rxControl, bool _bRemoveFromEventAttacher )
2505 Reference< XWindow > xWindow( _rxControl, UNO_QUERY );
2506 if ( xWindow.is() )
2508 xWindow->removeFocusListener( this );
2509 xWindow->removeMouseListener( this );
2511 if ( _bRemoveFromEventAttacher )
2512 removeFromEventAttacher( _rxControl );
2515 Reference< XDispatchProviderInterception > xInterception( _rxControl, UNO_QUERY);
2516 if ( xInterception.is() )
2517 deleteInterceptor( xInterception );
2519 if ( _rxControl.is() )
2521 Reference< XControlModel > xModel( _rxControl->getModel() );
2523 Reference< XReset > xReset( xModel, UNO_QUERY );
2524 if ( xReset.is() )
2525 xReset->removeResetListener( this );
2527 Reference< XValidatableFormComponent > xValidatable( xModel, UNO_QUERY );
2528 if ( xValidatable.is() )
2529 xValidatable->removeFormComponentValidityListener( this );
2533 //------------------------------------------------------------------------------
2534 void FormController::implSetCurrentControl( const Reference< XControl >& _rxControl )
2536 if ( m_xCurrentControl.get() == _rxControl.get() )
2537 return;
2539 Reference< XGridControl > xGridControl( m_xCurrentControl, UNO_QUERY );
2540 if ( xGridControl.is() )
2541 xGridControl->removeGridControlListener( this );
2543 m_xCurrentControl = _rxControl;
2545 xGridControl.set( m_xCurrentControl, UNO_QUERY );
2546 if ( xGridControl.is() )
2547 xGridControl->addGridControlListener( this );
2550 //------------------------------------------------------------------------------
2551 void FormController::insertControl(const Reference< XControl > & xControl)
2553 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2554 m_bControlsSorted = sal_False;
2555 m_aControls.realloc(m_aControls.getLength() + 1);
2556 m_aControls.getArray()[m_aControls.getLength() - 1] = xControl;
2558 if ( m_pColumnInfoCache.get() )
2559 m_pColumnInfoCache->deinitializeControls();
2561 implControlInserted( xControl, m_bAttachEvents );
2563 if (m_bDBConnection && !m_bFiltering)
2564 setControlLock(xControl);
2566 if (isListeningForChanges() && m_bAttachEvents)
2567 startControlModifyListening( xControl );
2570 //------------------------------------------------------------------------------
2571 void FormController::removeControl(const Reference< XControl > & xControl)
2573 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2574 const Reference< XControl >* pControls = m_aControls.getConstArray();
2575 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2576 while ( pControls != pControlsEnd )
2578 if ( xControl.get() == (*pControls++).get() )
2580 ::comphelper::removeElementAt( m_aControls, pControls - m_aControls.getConstArray() - 1 );
2581 break;
2585 FilterComponents::iterator componentPos = ::std::find( m_aFilterComponents.begin(), m_aFilterComponents.end(), xControl );
2586 if ( componentPos != m_aFilterComponents.end() )
2587 m_aFilterComponents.erase( componentPos );
2589 implControlRemoved( xControl, m_bDetachEvents );
2591 if ( isListeningForChanges() && m_bDetachEvents )
2592 stopControlModifyListening( xControl );
2595 // XLoadListener
2596 //------------------------------------------------------------------------------
2597 void FormController::loaded(const EventObject& rEvent) throw( RuntimeException )
2599 OSL_ENSURE( rEvent.Source == m_xModelAsIndex, "FormController::loaded: where did this come from?" );
2601 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2602 ::osl::MutexGuard aGuard( m_aMutex );
2603 Reference< XRowSet > xForm(rEvent.Source, UNO_QUERY);
2604 // do we have a connected data source
2605 OStaticDataAccessTools aStaticTools;
2606 if (xForm.is() && aStaticTools.getRowSetConnection(xForm).is())
2608 Reference< XPropertySet > xSet(xForm, UNO_QUERY);
2609 if (xSet.is())
2611 Any aVal = xSet->getPropertyValue(FM_PROP_CYCLE);
2612 sal_Int32 aVal2 = 0;
2613 ::cppu::enum2int(aVal2,aVal);
2614 m_bCycle = !aVal.hasValue() || aVal2 == TabulatorCycle_RECORDS;
2615 m_bCanUpdate = aStaticTools.canUpdate(xSet);
2616 m_bCanInsert = aStaticTools.canInsert(xSet);
2617 m_bCurrentRecordModified = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED));
2618 m_bCurrentRecordNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
2620 startFormListening( xSet, sal_False );
2622 // set the locks for the current controls
2623 if (getContainer().is())
2625 m_aLoadEvent.Call();
2628 else
2630 m_bCanInsert = m_bCanUpdate = m_bCycle = sal_False;
2631 m_bCurrentRecordModified = sal_False;
2632 m_bCurrentRecordNew = sal_False;
2633 m_bLocked = sal_False;
2635 m_bDBConnection = sal_True;
2637 else
2639 m_bDBConnection = sal_False;
2640 m_bCanInsert = m_bCanUpdate = m_bCycle = sal_False;
2641 m_bCurrentRecordModified = sal_False;
2642 m_bCurrentRecordNew = sal_False;
2643 m_bLocked = sal_False;
2646 Reference< XColumnsSupplier > xFormColumns( xForm, UNO_QUERY );
2647 m_pColumnInfoCache.reset( xFormColumns.is() ? new ColumnInfoCache( xFormColumns ) : NULL );
2649 updateAllDispatchers();
2652 //------------------------------------------------------------------------------
2653 void FormController::updateAllDispatchers() const
2655 ::std::for_each(
2656 m_aFeatureDispatchers.begin(),
2657 m_aFeatureDispatchers.end(),
2658 ::o3tl::compose1(
2659 UpdateAllListeners(),
2660 ::o3tl::select2nd< DispatcherContainer::value_type >()
2665 //------------------------------------------------------------------------------
2666 IMPL_LINK_NOARG(FormController, OnLoad)
2668 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2669 m_bLocked = determineLockState();
2671 setLocks();
2673 if (!m_bLocked)
2674 startListening();
2676 // just one exception toggle the auto values
2677 if (m_bCurrentRecordNew)
2678 toggleAutoFields(sal_True);
2680 return 1L;
2683 //------------------------------------------------------------------------------
2684 void FormController::unloaded(const EventObject& /*rEvent*/) throw( RuntimeException )
2686 ::osl::MutexGuard aGuard( m_aMutex );
2687 impl_checkDisposed_throw();
2689 updateAllDispatchers();
2692 //------------------------------------------------------------------------------
2693 void FormController::reloading(const EventObject& /*aEvent*/) throw( RuntimeException )
2695 ::osl::MutexGuard aGuard( m_aMutex );
2696 impl_checkDisposed_throw();
2698 // do the same like in unloading
2699 // just one exception toggle the auto values
2700 m_aToggleEvent.CancelPendingCall();
2701 unload();
2704 //------------------------------------------------------------------------------
2705 void FormController::reloaded(const EventObject& aEvent) throw( RuntimeException )
2707 ::osl::MutexGuard aGuard( m_aMutex );
2708 impl_checkDisposed_throw();
2710 loaded(aEvent);
2713 //------------------------------------------------------------------------------
2714 void FormController::unloading(const EventObject& /*aEvent*/) throw( RuntimeException )
2716 ::osl::MutexGuard aGuard( m_aMutex );
2717 impl_checkDisposed_throw();
2719 unload();
2722 //------------------------------------------------------------------------------
2723 void FormController::unload() throw( RuntimeException )
2725 ::osl::MutexGuard aGuard( m_aMutex );
2726 impl_checkDisposed_throw();
2728 m_aLoadEvent.CancelPendingCall();
2730 // be sure not to have autofields
2731 if (m_bCurrentRecordNew)
2732 toggleAutoFields(sal_False);
2734 // remove bound field listing again
2735 removeBoundFieldListener();
2737 if (m_bDBConnection && isListeningForChanges())
2738 stopListening();
2740 Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
2741 if ( m_bDBConnection && xSet.is() )
2742 stopFormListening( xSet, sal_False );
2744 m_bDBConnection = sal_False;
2745 m_bCanInsert = m_bCanUpdate = m_bCycle = sal_False;
2746 m_bCurrentRecordModified = m_bCurrentRecordNew = m_bLocked = sal_False;
2748 m_pColumnInfoCache.reset( NULL );
2751 // -----------------------------------------------------------------------------
2752 void FormController::removeBoundFieldListener()
2754 const Reference< XControl >* pControls = m_aControls.getConstArray();
2755 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2756 while ( pControls != pControlsEnd )
2758 Reference< XPropertySet > xProp( *pControls++, UNO_QUERY );
2759 if ( xProp.is() )
2760 xProp->removePropertyChangeListener( FM_PROP_BOUNDFIELD, this );
2764 //------------------------------------------------------------------------------
2765 void FormController::startFormListening( const Reference< XPropertySet >& _rxForm, sal_Bool _bPropertiesOnly )
2769 if ( m_bCanInsert || m_bCanUpdate ) // form can be modified
2771 _rxForm->addPropertyChangeListener( FM_PROP_ISNEW, this );
2772 _rxForm->addPropertyChangeListener( FM_PROP_ISMODIFIED, this );
2774 if ( !_bPropertiesOnly )
2776 // set the Listener for UI interaction
2777 Reference< XRowSetApproveBroadcaster > xApprove( _rxForm, UNO_QUERY );
2778 if ( xApprove.is() )
2779 xApprove->addRowSetApproveListener( this );
2781 // listener for row set changes
2782 Reference< XRowSet > xRowSet( _rxForm, UNO_QUERY );
2783 if ( xRowSet.is() )
2784 xRowSet->addRowSetListener( this );
2788 Reference< XPropertySetInfo > xInfo = _rxForm->getPropertySetInfo();
2789 if ( xInfo.is() && xInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) )
2790 _rxForm->addPropertyChangeListener( FM_PROP_DYNAMIC_CONTROL_BORDER, this );
2792 catch( const Exception& )
2794 DBG_UNHANDLED_EXCEPTION();
2798 //------------------------------------------------------------------------------
2799 void FormController::stopFormListening( const Reference< XPropertySet >& _rxForm, sal_Bool _bPropertiesOnly )
2803 if ( m_bCanInsert || m_bCanUpdate )
2805 _rxForm->removePropertyChangeListener( FM_PROP_ISNEW, this );
2806 _rxForm->removePropertyChangeListener( FM_PROP_ISMODIFIED, this );
2808 if ( !_bPropertiesOnly )
2810 Reference< XRowSetApproveBroadcaster > xApprove( _rxForm, UNO_QUERY );
2811 if (xApprove.is())
2812 xApprove->removeRowSetApproveListener(this);
2814 Reference< XRowSet > xRowSet( _rxForm, UNO_QUERY );
2815 if ( xRowSet.is() )
2816 xRowSet->removeRowSetListener( this );
2820 Reference< XPropertySetInfo > xInfo = _rxForm->getPropertySetInfo();
2821 if ( xInfo.is() && xInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) )
2822 _rxForm->removePropertyChangeListener( FM_PROP_DYNAMIC_CONTROL_BORDER, this );
2824 catch( const Exception& )
2826 DBG_UNHANDLED_EXCEPTION();
2830 // com::sun::star::sdbc::XRowSetListener
2831 //------------------------------------------------------------------------------
2832 void FormController::cursorMoved(const EventObject& /*event*/) throw( RuntimeException )
2834 ::osl::MutexGuard aGuard( m_aMutex );
2835 impl_checkDisposed_throw();
2837 // toggle the locking ?
2838 if (m_bLocked != determineLockState())
2840 m_bLocked = !m_bLocked;
2841 setLocks();
2842 if (isListeningForChanges())
2843 startListening();
2844 else
2845 stopListening();
2848 // neither the current control nor the current record are modified anymore
2849 m_bCurrentRecordModified = m_bModified = sal_False;
2852 //------------------------------------------------------------------------------
2853 void FormController::rowChanged(const EventObject& /*event*/) throw( RuntimeException )
2855 // not interested in ...
2857 //------------------------------------------------------------------------------
2858 void FormController::rowSetChanged(const EventObject& /*event*/) throw( RuntimeException )
2860 // not interested in ...
2864 // XContainerListener
2865 //------------------------------------------------------------------------------
2866 void SAL_CALL FormController::elementInserted(const ContainerEvent& evt) throw( RuntimeException )
2868 ::osl::MutexGuard aGuard( m_aMutex );
2869 impl_checkDisposed_throw();
2871 Reference< XControl > xControl( evt.Element, UNO_QUERY );
2872 if ( !xControl.is() )
2873 return;
2875 Reference< XFormComponent > xModel(xControl->getModel(), UNO_QUERY);
2876 if (xModel.is() && m_xModelAsIndex == xModel->getParent())
2878 insertControl(xControl);
2880 if ( m_aTabActivationTimer.IsActive() )
2881 m_aTabActivationTimer.Stop();
2883 m_aTabActivationTimer.Start();
2885 // are we in filtermode and a XModeSelector has inserted an element
2886 else if (m_bFiltering && Reference< XModeSelector > (evt.Source, UNO_QUERY).is())
2888 xModel = Reference< XFormComponent > (evt.Source, UNO_QUERY);
2889 if (xModel.is() && m_xModelAsIndex == xModel->getParent())
2891 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
2892 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
2894 // does the model use a bound field ?
2895 Reference< XPropertySet > xField;
2896 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
2898 Reference< XTextComponent > xText(xControl, UNO_QUERY);
2899 // may we filter the field?
2900 if (xText.is() && xField.is() && ::comphelper::hasProperty(FM_PROP_SEARCHABLE, xField) &&
2901 ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_SEARCHABLE)))
2903 m_aFilterComponents.push_back( xText );
2904 xText->addTextListener( this );
2911 //------------------------------------------------------------------------------
2912 void SAL_CALL FormController::elementReplaced(const ContainerEvent& evt) throw( RuntimeException )
2914 // simulate an elementRemoved
2915 ContainerEvent aRemoveEvent( evt );
2916 aRemoveEvent.Element = evt.ReplacedElement;
2917 aRemoveEvent.ReplacedElement = Any();
2918 elementRemoved( aRemoveEvent );
2920 // simulate an elementInserted
2921 ContainerEvent aInsertEvent( evt );
2922 aInsertEvent.ReplacedElement = Any();
2923 elementInserted( aInsertEvent );
2926 //------------------------------------------------------------------------------
2927 void SAL_CALL FormController::elementRemoved(const ContainerEvent& evt) throw( RuntimeException )
2929 ::osl::MutexGuard aGuard( m_aMutex );
2930 impl_checkDisposed_throw();
2932 Reference< XControl > xControl;
2933 evt.Element >>= xControl;
2934 if (!xControl.is())
2935 return;
2937 Reference< XFormComponent > xModel(xControl->getModel(), UNO_QUERY);
2938 if (xModel.is() && m_xModelAsIndex == xModel->getParent())
2940 removeControl(xControl);
2941 // TabOrder nicht neu berechnen, da das intern schon funktionieren mu�!
2943 // are we in filtermode and a XModeSelector has inserted an element
2944 else if (m_bFiltering && Reference< XModeSelector > (evt.Source, UNO_QUERY).is())
2946 FilterComponents::iterator componentPos = ::std::find(
2947 m_aFilterComponents.begin(), m_aFilterComponents.end(), xControl );
2948 if ( componentPos != m_aFilterComponents.end() )
2949 m_aFilterComponents.erase( componentPos );
2953 //------------------------------------------------------------------------------
2954 Reference< XControl > FormController::isInList(const Reference< XWindowPeer > & xPeer) const
2956 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2957 const Reference< XControl >* pControls = m_aControls.getConstArray();
2959 sal_uInt32 nCtrls = m_aControls.getLength();
2960 for ( sal_uInt32 n = 0; n < nCtrls && xPeer.is(); ++n, ++pControls )
2962 if ( pControls->is() )
2964 Reference< XVclWindowPeer > xCtrlPeer( (*pControls)->getPeer(), UNO_QUERY);
2965 if ( ( xCtrlPeer.get() == xPeer.get() ) || xCtrlPeer->isChild( xPeer ) )
2966 return *pControls;
2969 return Reference< XControl > ();
2972 //------------------------------------------------------------------------------
2973 void FormController::activateFirst() throw( RuntimeException )
2975 ::osl::MutexGuard aGuard( m_aMutex );
2976 impl_checkDisposed_throw();
2978 DBG_ASSERT(m_xTabController.is(), "FormController::activateFirst : invalid aggregate !");
2979 if (m_xTabController.is())
2980 m_xTabController->activateFirst();
2983 //------------------------------------------------------------------------------
2984 void FormController::activateLast() throw( RuntimeException )
2986 ::osl::MutexGuard aGuard( m_aMutex );
2987 impl_checkDisposed_throw();
2989 DBG_ASSERT(m_xTabController.is(), "FormController::activateLast : invalid aggregate !");
2990 if (m_xTabController.is())
2991 m_xTabController->activateLast();
2994 // XFormController
2995 //------------------------------------------------------------------------------
2996 Reference< XFormOperations > SAL_CALL FormController::getFormOperations() throw (RuntimeException)
2998 ::osl::MutexGuard aGuard( m_aMutex );
2999 impl_checkDisposed_throw();
3001 return m_xFormOperations;
3004 //------------------------------------------------------------------------------
3005 Reference< XControl> SAL_CALL FormController::getCurrentControl(void) throw( RuntimeException )
3007 ::osl::MutexGuard aGuard( m_aMutex );
3008 impl_checkDisposed_throw();
3009 return m_xCurrentControl;
3012 //------------------------------------------------------------------------------
3013 void SAL_CALL FormController::addActivateListener(const Reference< XFormControllerListener > & l) throw( RuntimeException )
3015 ::osl::MutexGuard aGuard( m_aMutex );
3016 impl_checkDisposed_throw();
3017 m_aActivateListeners.addInterface(l);
3019 //------------------------------------------------------------------------------
3020 void SAL_CALL FormController::removeActivateListener(const Reference< XFormControllerListener > & l) throw( RuntimeException )
3022 ::osl::MutexGuard aGuard( m_aMutex );
3023 impl_checkDisposed_throw();
3024 m_aActivateListeners.removeInterface(l);
3027 //------------------------------------------------------------------------------
3028 void SAL_CALL FormController::addChildController( const Reference< XFormController >& _ChildController ) throw( RuntimeException, IllegalArgumentException )
3030 ::osl::MutexGuard aGuard( m_aMutex );
3031 impl_checkDisposed_throw();
3033 if ( !_ChildController.is() )
3034 throw IllegalArgumentException( OUString(), *this, 1 );
3035 // TODO: (localized) error message
3037 // the parent of our (to-be-)child must be our own model
3038 Reference< XFormComponent > xFormOfChild( _ChildController->getModel(), UNO_QUERY );
3039 if ( !xFormOfChild.is() )
3040 throw IllegalArgumentException( OUString(), *this, 1 );
3041 // TODO: (localized) error message
3043 if ( xFormOfChild->getParent() != m_xModelAsIndex )
3044 throw IllegalArgumentException( OUString(), *this, 1 );
3045 // TODO: (localized) error message
3047 m_aChildren.push_back( _ChildController );
3048 _ChildController->setParent( *this );
3050 // search the position of the model within the form
3051 sal_uInt32 nPos = m_xModelAsIndex->getCount();
3052 Reference< XFormComponent > xTemp;
3053 for( ; nPos; )
3055 m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
3056 if ( xFormOfChild == xTemp )
3058 Reference< XInterface > xIfc( _ChildController, UNO_QUERY );
3059 m_xModelAsManager->attach( nPos, xIfc, makeAny( _ChildController) );
3060 break;
3065 //------------------------------------------------------------------------------
3066 Reference< XFormControllerContext > SAL_CALL FormController::getContext() throw (RuntimeException)
3068 ::osl::MutexGuard aGuard( m_aMutex );
3069 impl_checkDisposed_throw();
3070 return m_xContext;
3073 //------------------------------------------------------------------------------
3074 void SAL_CALL FormController::setContext( const Reference< XFormControllerContext >& _context ) throw (RuntimeException)
3076 ::osl::MutexGuard aGuard( m_aMutex );
3077 impl_checkDisposed_throw();
3078 m_xContext = _context;
3081 //------------------------------------------------------------------------------
3082 Reference< XInteractionHandler > SAL_CALL FormController::getInteractionHandler() throw (RuntimeException)
3084 ::osl::MutexGuard aGuard( m_aMutex );
3085 impl_checkDisposed_throw();
3086 return m_xInteractionHandler;
3089 //------------------------------------------------------------------------------
3090 void SAL_CALL FormController::setInteractionHandler( const Reference< XInteractionHandler >& _interactionHandler ) throw (RuntimeException)
3092 ::osl::MutexGuard aGuard( m_aMutex );
3093 impl_checkDisposed_throw();
3094 m_xInteractionHandler = _interactionHandler;
3097 //------------------------------------------------------------------------------
3098 void FormController::setFilter(::std::vector<FmFieldInfo>& rFieldInfos)
3100 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3101 // create the composer
3102 Reference< XRowSet > xForm(m_xModelAsIndex, UNO_QUERY);
3103 Reference< XConnection > xConnection(OStaticDataAccessTools().getRowSetConnection(xForm));
3104 if (xForm.is())
3108 Reference< XMultiServiceFactory > xFactory( xConnection, UNO_QUERY_THROW );
3109 m_xComposer.set(
3110 xFactory->createInstance( OUString( "com.sun.star.sdb.SingleSelectQueryComposer" ) ),
3111 UNO_QUERY_THROW );
3113 Reference< XPropertySet > xSet( xForm, UNO_QUERY );
3114 OUString sStatement = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_ACTIVECOMMAND ) );
3115 OUString sFilter = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_FILTER ) );
3116 m_xComposer->setElementaryQuery( sStatement );
3117 m_xComposer->setFilter( sFilter );
3119 catch( const Exception& )
3121 DBG_UNHANDLED_EXCEPTION();
3125 if (m_xComposer.is())
3127 Sequence < PropertyValue> aLevel;
3128 Sequence< Sequence < PropertyValue > > aFilterRows = m_xComposer->getStructuredFilter();
3130 // ok, we receive the list of filters as sequence of fieldnames, value
3131 // now we have to transform the fieldname into UI names, that could be a label of the field or
3132 // a aliasname or the fieldname itself
3134 // first adjust the field names if necessary
3135 Reference< XNameAccess > xQueryColumns =
3136 Reference< XColumnsSupplier >( m_xComposer, UNO_QUERY_THROW )->getColumns();
3138 for (::std::vector<FmFieldInfo>::iterator iter = rFieldInfos.begin();
3139 iter != rFieldInfos.end(); ++iter)
3141 if ( xQueryColumns->hasByName((*iter).aFieldName) )
3143 if ( (xQueryColumns->getByName((*iter).aFieldName) >>= (*iter).xField) && (*iter).xField.is() )
3144 (*iter).xField->getPropertyValue(FM_PROP_REALNAME) >>= (*iter).aFieldName;
3148 Reference< XDatabaseMetaData> xMetaData(xConnection->getMetaData());
3149 // now transfer the filters into Value/TextComponent pairs
3150 ::comphelper::UStringMixEqual aCompare(xMetaData->storesMixedCaseQuotedIdentifiers());
3152 // need to parse criteria localized
3153 OStaticDataAccessTools aStaticTools;
3154 Reference< XNumberFormatsSupplier> xFormatSupplier( aStaticTools.getNumberFormats(xConnection, sal_True));
3155 Reference< XNumberFormatter> xFormatter( NumberFormatter::create(m_aContext.getUNOContext()), UNO_QUERY_THROW );
3156 xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
3157 Locale aAppLocale = Application::GetSettings().GetUILanguageTag().getLocale();
3158 const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetUILocaleDataWrapper() );
3159 /* FIXME: casting this to sal_Char is plain wrong and of course only
3160 * works for ASCII separators, but
3161 * xParseNode->parseNodeToPredicateStr() expects a sal_Char. Fix it
3162 * there. */
3163 sal_Char cDecimalSeparator = (sal_Char)rLocaleWrapper.getNumDecimalSep()[0];
3164 SAL_WARN_IF( (sal_Unicode)cDecimalSeparator != rLocaleWrapper.getNumDecimalSep()[0],
3165 "svx.form", "FormController::setFilter: wrong cast of decimal separator to sal_Char!");
3167 // retrieving the filter
3168 const Sequence < PropertyValue >* pRow = aFilterRows.getConstArray();
3169 for (sal_Int32 i = 0, nLen = aFilterRows.getLength(); i < nLen; ++i)
3171 FmFilterRow aRow;
3173 // search a field for the given name
3174 const PropertyValue* pRefValues = pRow[i].getConstArray();
3175 for (sal_Int32 j = 0, nLen1 = pRow[i].getLength(); j < nLen1; j++)
3177 // look for the text component
3178 Reference< XPropertySet > xField;
3181 Reference< XPropertySet > xSet;
3182 OUString aRealName;
3184 // first look with the given name
3185 if (xQueryColumns->hasByName(pRefValues[j].Name))
3187 xQueryColumns->getByName(pRefValues[j].Name) >>= xSet;
3189 // get the RealName
3190 xSet->getPropertyValue(OUString("RealName")) >>= aRealName;
3192 // compare the condition field name and the RealName
3193 if (aCompare(aRealName, pRefValues[j].Name))
3194 xField = xSet;
3196 if (!xField.is())
3198 // no we have to check every column to find the realname
3199 Reference< XIndexAccess > xColumnsByIndex(xQueryColumns, UNO_QUERY);
3200 for (sal_Int32 n = 0, nCount = xColumnsByIndex->getCount(); n < nCount; n++)
3202 xColumnsByIndex->getByIndex(n) >>= xSet;
3203 xSet->getPropertyValue(OUString("RealName")) >>= aRealName;
3204 if (aCompare(aRealName, pRefValues[j].Name))
3206 // get the column by its alias
3207 xField = xSet;
3208 break;
3212 if (!xField.is())
3213 continue;
3215 catch (const Exception&)
3217 continue;
3220 // find the text component
3221 for (::std::vector<FmFieldInfo>::iterator iter = rFieldInfos.begin();
3222 iter != rFieldInfos.end(); ++iter)
3224 // we found the field so insert a new entry to the filter row
3225 if ((*iter).xField == xField)
3227 // do we already have the control ?
3228 if (aRow.find((*iter).xText) != aRow.end())
3230 OUString aCompText = aRow[(*iter).xText];
3231 aCompText += OUString(" ");
3232 OString aVal = m_xParser->getContext().getIntlKeywordAscii(IParseContext::KEY_AND);
3233 aCompText += OUString(aVal.getStr(),aVal.getLength(),RTL_TEXTENCODING_ASCII_US);
3234 aCompText += OUString(" ");
3235 aCompText += ::comphelper::getString(pRefValues[j].Value);
3236 aRow[(*iter).xText] = aCompText;
3238 else
3240 OUString sPredicate,sErrorMsg;
3241 pRefValues[j].Value >>= sPredicate;
3242 ::rtl::Reference< ISQLParseNode > xParseNode = predicateTree(sErrorMsg, sPredicate, xFormatter, xField);
3243 if ( xParseNode.is() )
3245 OUString sCriteria;
3246 xParseNode->parseNodeToPredicateStr( sCriteria
3247 ,xConnection
3248 ,xFormatter
3249 ,xField
3250 ,OUString()
3251 ,aAppLocale
3252 ,cDecimalSeparator
3253 ,getParseContext());
3254 aRow[(*iter).xText] = sCriteria;
3261 if (aRow.empty())
3262 continue;
3264 impl_addFilterRow( aRow );
3268 // now set the filter controls
3269 for ( ::std::vector<FmFieldInfo>::iterator field = rFieldInfos.begin();
3270 field != rFieldInfos.end();
3271 ++field
3274 m_aFilterComponents.push_back( field->xText );
3278 //------------------------------------------------------------------------------
3279 void FormController::startFiltering()
3281 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3283 OStaticDataAccessTools aStaticTools;
3284 Reference< XConnection > xConnection( aStaticTools.getRowSetConnection( Reference< XRowSet >( m_xModelAsIndex, UNO_QUERY ) ) );
3285 if ( !xConnection.is() )
3286 // nothing to do - can't filter a form which is not connected
3287 return;
3289 // stop listening for controls
3290 if (isListeningForChanges())
3291 stopListening();
3293 m_bFiltering = sal_True;
3295 // as we don't want new controls to be attached to the scripting environment
3296 // we change attach flags
3297 m_bAttachEvents = sal_False;
3299 // Austauschen der Kontrols fuer das aktuelle Formular
3300 Sequence< Reference< XControl > > aControlsCopy( m_aControls );
3301 const Reference< XControl >* pControls = aControlsCopy.getConstArray();
3302 sal_Int32 nControlCount = aControlsCopy.getLength();
3304 // the control we have to activate after replacement
3305 Reference< XDatabaseMetaData > xMetaData(xConnection->getMetaData());
3306 Reference< XNumberFormatsSupplier > xFormatSupplier = aStaticTools.getNumberFormats(xConnection, sal_True);
3307 Reference< XNumberFormatter > xFormatter( NumberFormatter::create(m_aContext.getUNOContext()), UNO_QUERY_THROW );
3308 xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
3310 // structure for storing the field info
3311 ::std::vector<FmFieldInfo> aFieldInfos;
3313 for (sal_Int32 i = nControlCount; i > 0;)
3315 Reference< XControl > xControl = pControls[--i];
3316 if (xControl.is())
3318 // no events for the control anymore
3319 removeFromEventAttacher(xControl);
3321 // do we have a mode selector
3322 Reference< XModeSelector > xSelector(xControl, UNO_QUERY);
3323 if (xSelector.is())
3325 xSelector->setMode( OUString( "FilterMode" ) );
3327 // listening for new controls of the selector
3328 Reference< XContainer > xContainer(xSelector, UNO_QUERY);
3329 if (xContainer.is())
3330 xContainer->addContainerListener(this);
3332 Reference< XEnumerationAccess > xElementAccess(xSelector, UNO_QUERY);
3333 if (xElementAccess.is())
3335 Reference< XEnumeration > xEnumeration(xElementAccess->createEnumeration());
3336 Reference< XControl > xSubControl;
3337 while (xEnumeration->hasMoreElements())
3339 xEnumeration->nextElement() >>= xSubControl;
3340 if (xSubControl.is())
3342 Reference< XPropertySet > xSet(xSubControl->getModel(), UNO_QUERY);
3343 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
3345 // does the model use a bound field ?
3346 Reference< XPropertySet > xField;
3347 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
3349 Reference< XTextComponent > xText(xSubControl, UNO_QUERY);
3350 // may we filter the field?
3351 if (xText.is() && xField.is() && ::comphelper::hasProperty(FM_PROP_SEARCHABLE, xField) &&
3352 ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_SEARCHABLE)))
3354 aFieldInfos.push_back(FmFieldInfo(xField, xText));
3355 xText->addTextListener(this);
3361 continue;
3364 Reference< XPropertySet > xModel( xControl->getModel(), UNO_QUERY );
3365 if (xModel.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xModel))
3367 // does the model use a bound field ?
3368 Any aVal = xModel->getPropertyValue(FM_PROP_BOUNDFIELD);
3369 Reference< XPropertySet > xField;
3370 aVal >>= xField;
3372 // may we filter the field?
3374 if ( xField.is()
3375 && ::comphelper::hasProperty( FM_PROP_SEARCHABLE, xField )
3376 && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_SEARCHABLE ) )
3379 // create a filter control
3380 Reference< XControl > xFilterControl = form::control::FilterControl::createWithFormat(
3381 m_aContext.getUNOContext(),
3382 VCLUnoHelper::GetInterface( getDialogParentWindow() ),
3383 xFormatter,
3384 xModel);
3386 if ( replaceControl( xControl, xFilterControl ) )
3388 Reference< XTextComponent > xFilterText( xFilterControl, UNO_QUERY );
3389 aFieldInfos.push_back( FmFieldInfo( xField, xFilterText ) );
3390 xFilterText->addTextListener(this);
3394 else
3396 // abmelden vom EventManager
3401 // we have all filter controls now, so the next step is to read the filters from the form
3402 // resolve all aliases and set the current filter to the according structure
3403 setFilter(aFieldInfos);
3405 Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
3406 if ( xSet.is() )
3407 stopFormListening( xSet, sal_True );
3409 impl_setTextOnAllFilter_throw();
3411 // lock all controls which are not used for filtering
3412 m_bLocked = determineLockState();
3413 setLocks();
3414 m_bAttachEvents = sal_True;
3417 //------------------------------------------------------------------------------
3418 void FormController::stopFiltering()
3420 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3421 if ( !m_bFiltering ) // #104693# OJ
3422 { // nothing to do
3423 return;
3426 m_bFiltering = sal_False;
3427 m_bDetachEvents = sal_False;
3429 ::comphelper::disposeComponent(m_xComposer);
3431 // Austauschen der Kontrols fuer das aktuelle Formular
3432 Sequence< Reference< XControl > > aControlsCopy( m_aControls );
3433 const Reference< XControl > * pControls = aControlsCopy.getConstArray();
3434 sal_Int32 nControlCount = aControlsCopy.getLength();
3436 // clear the filter control map
3437 ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), RemoveComponentTextListener( this ) );
3438 m_aFilterComponents.clear();
3440 for ( sal_Int32 i = nControlCount; i > 0; )
3442 Reference< XControl > xControl = pControls[--i];
3443 if (xControl.is())
3445 // now enable eventhandling again
3446 addToEventAttacher(xControl);
3448 Reference< XModeSelector > xSelector(xControl, UNO_QUERY);
3449 if (xSelector.is())
3451 xSelector->setMode( OUString( "DataMode" ) );
3453 // listening for new controls of the selector
3454 Reference< XContainer > xContainer(xSelector, UNO_QUERY);
3455 if (xContainer.is())
3456 xContainer->removeContainerListener(this);
3457 continue;
3460 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
3461 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
3463 // does the model use a bound field ?
3464 Reference< XPropertySet > xField;
3465 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
3467 // may we filter the field?
3468 if ( xField.is()
3469 && ::comphelper::hasProperty( FM_PROP_SEARCHABLE, xField )
3470 && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_SEARCHABLE ) )
3473 OUString sServiceName;
3474 OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DEFAULTCONTROL ) >>= sServiceName );
3475 Reference< XControl > xNewControl( m_aContext.createComponent( sServiceName ), UNO_QUERY );
3476 replaceControl( xControl, xNewControl );
3482 Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
3483 if ( xSet.is() )
3484 startFormListening( xSet, sal_True );
3486 m_bDetachEvents = sal_True;
3488 m_aFilterRows.clear();
3489 m_nCurrentFilterPosition = -1;
3491 // release the locks if possible
3492 // lock all controls which are not used for filtering
3493 m_bLocked = determineLockState();
3494 setLocks();
3496 // restart listening for control modifications
3497 if (isListeningForChanges())
3498 startListening();
3501 // XModeSelector
3502 //------------------------------------------------------------------------------
3503 void FormController::setMode(const OUString& Mode) throw( NoSupportException, RuntimeException )
3505 ::osl::MutexGuard aGuard( m_aMutex );
3506 impl_checkDisposed_throw();
3508 if (!supportsMode(Mode))
3509 throw NoSupportException();
3511 if (Mode == m_aMode)
3512 return;
3514 m_aMode = Mode;
3516 if ( Mode == "FilterMode" )
3517 startFiltering();
3518 else
3519 stopFiltering();
3521 for (FmFormControllers::const_iterator i = m_aChildren.begin();
3522 i != m_aChildren.end(); ++i)
3524 Reference< XModeSelector > xMode(*i, UNO_QUERY);
3525 if ( xMode.is() )
3526 xMode->setMode(Mode);
3530 //------------------------------------------------------------------------------
3531 OUString SAL_CALL FormController::getMode(void) throw( RuntimeException )
3533 ::osl::MutexGuard aGuard( m_aMutex );
3534 impl_checkDisposed_throw();
3536 return m_aMode;
3539 //------------------------------------------------------------------------------
3540 Sequence< OUString > SAL_CALL FormController::getSupportedModes(void) throw( RuntimeException )
3542 ::osl::MutexGuard aGuard( m_aMutex );
3543 impl_checkDisposed_throw();
3545 static Sequence< OUString > aModes;
3546 if (!aModes.getLength())
3548 aModes.realloc(2);
3549 OUString* pModes = aModes.getArray();
3550 pModes[0] = OUString( "DataMode" );
3551 pModes[1] = OUString( "FilterMode" );
3553 return aModes;
3556 //------------------------------------------------------------------------------
3557 sal_Bool SAL_CALL FormController::supportsMode(const OUString& Mode) throw( RuntimeException )
3559 ::osl::MutexGuard aGuard( m_aMutex );
3560 impl_checkDisposed_throw();
3562 Sequence< OUString > aModes(getSupportedModes());
3563 const OUString* pModes = aModes.getConstArray();
3564 for (sal_Int32 i = aModes.getLength(); i > 0; )
3566 if (pModes[--i] == Mode)
3567 return sal_True;
3569 return sal_False;
3572 //------------------------------------------------------------------------------
3573 Window* FormController::getDialogParentWindow()
3575 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3576 Window* pParentWindow = NULL;
3579 Reference< XControl > xContainerControl( getContainer(), UNO_QUERY_THROW );
3580 Reference< XWindowPeer > xContainerPeer( xContainerControl->getPeer(), UNO_QUERY_THROW );
3581 pParentWindow = VCLUnoHelper::GetWindow( xContainerPeer );
3583 catch( const Exception& )
3585 DBG_UNHANDLED_EXCEPTION();
3587 return pParentWindow;
3589 //------------------------------------------------------------------------------
3590 bool FormController::checkFormComponentValidity( OUString& /* [out] */ _rFirstInvalidityExplanation, Reference< XControlModel >& /* [out] */ _rxFirstInvalidModel ) SAL_THROW(())
3594 Reference< XEnumerationAccess > xControlEnumAcc( getModel(), UNO_QUERY );
3595 Reference< XEnumeration > xControlEnumeration;
3596 if ( xControlEnumAcc.is() )
3597 xControlEnumeration = xControlEnumAcc->createEnumeration();
3598 OSL_ENSURE( xControlEnumeration.is(), "FormController::checkFormComponentValidity: cannot enumerate the controls!" );
3599 if ( !xControlEnumeration.is() )
3600 // assume all valid
3601 return true;
3603 Reference< XValidatableFormComponent > xValidatable;
3604 while ( xControlEnumeration->hasMoreElements() )
3606 if ( !( xControlEnumeration->nextElement() >>= xValidatable ) )
3607 // control does not support validation
3608 continue;
3610 if ( xValidatable->isValid() )
3611 continue;
3613 Reference< XValidator > xValidator( xValidatable->getValidator() );
3614 OSL_ENSURE( xValidator.is(), "FormController::checkFormComponentValidity: invalid, but no validator?" );
3615 if ( !xValidator.is() )
3616 // this violates the interface definition of css.form.validation.XValidatableFormComponent ...
3617 continue;
3619 _rFirstInvalidityExplanation = xValidator->explainInvalid( xValidatable->getCurrentValue() );
3620 _rxFirstInvalidModel = _rxFirstInvalidModel.query( xValidatable );
3621 return false;
3624 catch( const Exception& )
3626 DBG_UNHANDLED_EXCEPTION();
3628 return true;
3631 //------------------------------------------------------------------------------
3632 Reference< XControl > FormController::locateControl( const Reference< XControlModel >& _rxModel ) SAL_THROW(())
3636 Sequence< Reference< XControl > > aControls( getControls() );
3637 const Reference< XControl >* pControls = aControls.getConstArray();
3638 const Reference< XControl >* pControlsEnd = aControls.getConstArray() + aControls.getLength();
3640 for ( ; pControls != pControlsEnd; ++pControls )
3642 OSL_ENSURE( pControls->is(), "FormController::locateControl: NULL-control?" );
3643 if ( pControls->is() )
3645 if ( ( *pControls)->getModel() == _rxModel )
3646 return *pControls;
3649 OSL_FAIL( "FormController::locateControl: did not find a control for this model!" );
3651 catch( const Exception& )
3653 DBG_UNHANDLED_EXCEPTION();
3655 return NULL;
3658 //------------------------------------------------------------------------------
3659 namespace
3661 void displayErrorSetFocus( const String& _rMessage, const Reference< XControl >& _rxFocusControl, Window* _pDialogParent )
3663 SQLContext aError;
3664 aError.Message = String( SVX_RES( RID_STR_WRITEERROR ) );
3665 aError.Details = _rMessage;
3666 displayException( aError, _pDialogParent );
3668 if ( _rxFocusControl.is() )
3670 Reference< XWindow > xControlWindow( _rxFocusControl, UNO_QUERY );
3671 OSL_ENSURE( xControlWindow.is(), "displayErrorSetFocus: invalid control!" );
3672 if ( xControlWindow.is() )
3673 xControlWindow->setFocus();
3677 sal_Bool lcl_shouldValidateRequiredFields_nothrow( const Reference< XInterface >& _rxForm )
3681 static OUString s_sFormsCheckRequiredFields( "FormsCheckRequiredFields" );
3683 // first, check whether the form has a property telling us the answer
3684 // this allows people to use the XPropertyContainer interface of a form to control
3685 // the behaviour on a per-form basis.
3686 Reference< XPropertySet > xFormProps( _rxForm, UNO_QUERY_THROW );
3687 Reference< XPropertySetInfo > xPSI( xFormProps->getPropertySetInfo() );
3688 if ( xPSI->hasPropertyByName( s_sFormsCheckRequiredFields ) )
3690 sal_Bool bShouldValidate = true;
3691 OSL_VERIFY( xFormProps->getPropertyValue( s_sFormsCheckRequiredFields ) >>= bShouldValidate );
3692 return bShouldValidate;
3695 // next, check the data source which created the connection
3696 Reference< XChild > xConnectionAsChild( xFormProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ), UNO_QUERY_THROW );
3697 Reference< XPropertySet > xDataSource( xConnectionAsChild->getParent(), UNO_QUERY );
3698 if ( !xDataSource.is() )
3699 // seldom (but possible): this is not a connection created by a data source
3700 return sal_True;
3702 Reference< XPropertySet > xDataSourceSettings(
3703 xDataSource->getPropertyValue( OUString( "Settings" ) ),
3704 UNO_QUERY_THROW );
3706 sal_Bool bShouldValidate = true;
3707 OSL_VERIFY( xDataSourceSettings->getPropertyValue( s_sFormsCheckRequiredFields ) >>= bShouldValidate );
3708 return bShouldValidate;
3710 catch( const Exception& )
3712 DBG_UNHANDLED_EXCEPTION();
3715 return sal_True;
3719 // XRowSetApproveListener
3720 //------------------------------------------------------------------------------
3721 sal_Bool SAL_CALL FormController::approveRowChange(const RowChangeEvent& _rEvent) throw( RuntimeException )
3723 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3724 impl_checkDisposed_throw();
3726 ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
3727 sal_Bool bValid = sal_True;
3728 if (aIter.hasMoreElements())
3730 RowChangeEvent aEvt( _rEvent );
3731 aEvt.Source = *this;
3732 bValid = ((XRowSetApproveListener*)aIter.next())->approveRowChange(aEvt);
3735 if ( !bValid )
3736 return bValid;
3738 if ( ( _rEvent.Action != RowChangeAction::INSERT )
3739 && ( _rEvent.Action != RowChangeAction::UPDATE )
3741 return bValid;
3743 // if some of the control models are bound to validators, check them
3744 OUString sInvalidityExplanation;
3745 Reference< XControlModel > xInvalidModel;
3746 if ( !checkFormComponentValidity( sInvalidityExplanation, xInvalidModel ) )
3748 Reference< XControl > xControl( locateControl( xInvalidModel ) );
3749 aGuard.clear();
3750 displayErrorSetFocus( sInvalidityExplanation, xControl, getDialogParentWindow() );
3751 return false;
3754 // check values on NULL and required flag
3755 if ( !lcl_shouldValidateRequiredFields_nothrow( _rEvent.Source ) )
3756 return sal_True;
3758 OSL_ENSURE( m_pColumnInfoCache.get(), "FormController::approveRowChange: no column infos!" );
3759 if ( !m_pColumnInfoCache.get() )
3760 return sal_True;
3764 if ( !m_pColumnInfoCache->controlsInitialized() )
3765 m_pColumnInfoCache->initializeControls( getControls() );
3767 size_t colCount = m_pColumnInfoCache->getColumnCount();
3768 for ( size_t col = 0; col < colCount; ++col )
3770 const ColumnInfo& rColInfo = m_pColumnInfoCache->getColumnInfo( col );
3771 if ( rColInfo.nNullable != ColumnValue::NO_NULLS )
3772 continue;
3774 if ( rColInfo.bAutoIncrement )
3775 continue;
3777 if ( rColInfo.bReadOnly )
3778 continue;
3780 if ( !rColInfo.xFirstControlWithInputRequired.is() && !rColInfo.xFirstGridWithInputRequiredColumn.is() )
3781 continue;
3783 // TODO: in case of binary fields, this "getString" below is extremely expensive
3784 if ( !rColInfo.xColumn->getString().isEmpty() || !rColInfo.xColumn->wasNull() )
3785 continue;
3787 String sMessage( SVX_RES( RID_ERR_FIELDREQUIRED ) );
3788 sMessage.SearchAndReplace( OUString('#'), rColInfo.sName );
3790 // the control to focus
3791 Reference< XControl > xControl( rColInfo.xFirstControlWithInputRequired );
3792 if ( !xControl.is() )
3793 xControl.set( rColInfo.xFirstGridWithInputRequiredColumn, UNO_QUERY );
3795 aGuard.clear();
3796 displayErrorSetFocus( sMessage, rColInfo.xFirstControlWithInputRequired, getDialogParentWindow() );
3797 return sal_False;
3800 catch( const Exception& )
3802 DBG_UNHANDLED_EXCEPTION();
3805 return true;
3808 //------------------------------------------------------------------------------
3809 sal_Bool SAL_CALL FormController::approveCursorMove(const EventObject& event) throw( RuntimeException )
3811 ::osl::MutexGuard aGuard( m_aMutex );
3812 impl_checkDisposed_throw();
3814 ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
3815 if (aIter.hasMoreElements())
3817 EventObject aEvt(event);
3818 aEvt.Source = *this;
3819 return ((XRowSetApproveListener*)aIter.next())->approveCursorMove(aEvt);
3822 return sal_True;
3825 //------------------------------------------------------------------------------
3826 sal_Bool SAL_CALL FormController::approveRowSetChange(const EventObject& event) throw( RuntimeException )
3828 ::osl::MutexGuard aGuard( m_aMutex );
3829 impl_checkDisposed_throw();
3831 ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
3832 if (aIter.hasMoreElements())
3834 EventObject aEvt(event);
3835 aEvt.Source = *this;
3836 return ((XRowSetApproveListener*)aIter.next())->approveRowSetChange(aEvt);
3839 return sal_True;
3842 // XRowSetApproveBroadcaster
3843 //------------------------------------------------------------------------------
3844 void SAL_CALL FormController::addRowSetApproveListener(const Reference< XRowSetApproveListener > & _rxListener) throw( RuntimeException )
3846 ::osl::MutexGuard aGuard( m_aMutex );
3847 impl_checkDisposed_throw();
3849 m_aRowSetApproveListeners.addInterface(_rxListener);
3852 //------------------------------------------------------------------------------
3853 void SAL_CALL FormController::removeRowSetApproveListener(const Reference< XRowSetApproveListener > & _rxListener) throw( RuntimeException )
3855 ::osl::MutexGuard aGuard( m_aMutex );
3856 impl_checkDisposed_throw();
3858 m_aRowSetApproveListeners.removeInterface(_rxListener);
3861 // XErrorListener
3862 //------------------------------------------------------------------------------
3863 void SAL_CALL FormController::errorOccured(const SQLErrorEvent& aEvent) throw( RuntimeException )
3865 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3866 impl_checkDisposed_throw();
3868 ::cppu::OInterfaceIteratorHelper aIter(m_aErrorListeners);
3869 if (aIter.hasMoreElements())
3871 SQLErrorEvent aEvt(aEvent);
3872 aEvt.Source = *this;
3873 ((XSQLErrorListener*)aIter.next())->errorOccured(aEvt);
3875 else
3877 aGuard.clear();
3878 displayException( aEvent );
3882 // XErrorBroadcaster
3883 //------------------------------------------------------------------------------
3884 void SAL_CALL FormController::addSQLErrorListener(const Reference< XSQLErrorListener > & aListener) throw( RuntimeException )
3886 ::osl::MutexGuard aGuard( m_aMutex );
3887 impl_checkDisposed_throw();
3889 m_aErrorListeners.addInterface(aListener);
3892 //------------------------------------------------------------------------------
3893 void SAL_CALL FormController::removeSQLErrorListener(const Reference< XSQLErrorListener > & aListener) throw( RuntimeException )
3895 ::osl::MutexGuard aGuard( m_aMutex );
3896 impl_checkDisposed_throw();
3898 m_aErrorListeners.removeInterface(aListener);
3901 // XDatabaseParameterBroadcaster2
3902 //------------------------------------------------------------------------------
3903 void SAL_CALL FormController::addDatabaseParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException )
3905 ::osl::MutexGuard aGuard( m_aMutex );
3906 impl_checkDisposed_throw();
3908 m_aParameterListeners.addInterface(aListener);
3911 //------------------------------------------------------------------------------
3912 void SAL_CALL FormController::removeDatabaseParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException )
3914 ::osl::MutexGuard aGuard( m_aMutex );
3915 impl_checkDisposed_throw();
3917 m_aParameterListeners.removeInterface(aListener);
3920 // XDatabaseParameterBroadcaster
3921 //------------------------------------------------------------------------------
3922 void SAL_CALL FormController::addParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException )
3924 FormController::addDatabaseParameterListener( aListener );
3927 //------------------------------------------------------------------------------
3928 void SAL_CALL FormController::removeParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException )
3930 FormController::removeDatabaseParameterListener( aListener );
3933 // XDatabaseParameterListener
3934 //------------------------------------------------------------------------------
3935 sal_Bool SAL_CALL FormController::approveParameter(const DatabaseParameterEvent& aEvent) throw( RuntimeException )
3937 SolarMutexGuard aSolarGuard;
3938 ::osl::MutexGuard aGuard( m_aMutex );
3939 impl_checkDisposed_throw();
3941 ::cppu::OInterfaceIteratorHelper aIter(m_aParameterListeners);
3942 if (aIter.hasMoreElements())
3944 DatabaseParameterEvent aEvt(aEvent);
3945 aEvt.Source = *this;
3946 return ((XDatabaseParameterListener*)aIter.next())->approveParameter(aEvt);
3948 else
3950 // default handling: instantiate an interaction handler and let it handle the parameter request
3953 if ( !ensureInteractionHandler() )
3954 return sal_False;
3956 // two continuations allowed: OK and Cancel
3957 OParameterContinuation* pParamValues = new OParameterContinuation;
3958 OInteractionAbort* pAbort = new OInteractionAbort;
3959 // the request
3960 ParametersRequest aRequest;
3961 aRequest.Parameters = aEvent.Parameters;
3962 aRequest.Connection = OStaticDataAccessTools().getRowSetConnection(Reference< XRowSet >(aEvent.Source, UNO_QUERY));
3963 OInteractionRequest* pParamRequest = new OInteractionRequest(makeAny(aRequest));
3964 Reference< XInteractionRequest > xParamRequest(pParamRequest);
3965 // some knittings
3966 pParamRequest->addContinuation(pParamValues);
3967 pParamRequest->addContinuation(pAbort);
3969 // handle the request
3970 m_xInteractionHandler->handle(xParamRequest);
3972 if (!pParamValues->wasSelected())
3973 // canceled
3974 return sal_False;
3976 // transfer the values into the parameter supplier
3977 Sequence< PropertyValue > aFinalValues = pParamValues->getValues();
3978 if (aFinalValues.getLength() != aRequest.Parameters->getCount())
3980 OSL_FAIL("FormController::approveParameter: the InteractionHandler returned nonsense!");
3981 return sal_False;
3983 const PropertyValue* pFinalValues = aFinalValues.getConstArray();
3984 for (sal_Int32 i=0; i<aFinalValues.getLength(); ++i, ++pFinalValues)
3986 Reference< XPropertySet > xParam;
3987 ::cppu::extractInterface(xParam, aRequest.Parameters->getByIndex(i));
3988 if (xParam.is())
3990 #ifdef DBG_UTIL
3991 OUString sName;
3992 xParam->getPropertyValue(FM_PROP_NAME) >>= sName;
3993 DBG_ASSERT(sName.equals(pFinalValues->Name), "FormController::approveParameter: suspicious value names!");
3994 #endif
3995 try { xParam->setPropertyValue(FM_PROP_VALUE, pFinalValues->Value); }
3996 catch(Exception&)
3998 OSL_FAIL("FormController::approveParameter: setting one of the properties failed!");
4003 catch(Exception&)
4005 DBG_UNHANDLED_EXCEPTION();
4008 return sal_True;
4011 // XConfirmDeleteBroadcaster
4012 //------------------------------------------------------------------------------
4013 void SAL_CALL FormController::addConfirmDeleteListener(const Reference< XConfirmDeleteListener > & aListener) throw( RuntimeException )
4015 ::osl::MutexGuard aGuard( m_aMutex );
4016 impl_checkDisposed_throw();
4018 m_aDeleteListeners.addInterface(aListener);
4021 //------------------------------------------------------------------------------
4022 void SAL_CALL FormController::removeConfirmDeleteListener(const Reference< XConfirmDeleteListener > & aListener) throw( RuntimeException )
4024 ::osl::MutexGuard aGuard( m_aMutex );
4025 impl_checkDisposed_throw();
4027 m_aDeleteListeners.removeInterface(aListener);
4030 // XConfirmDeleteListener
4031 //------------------------------------------------------------------------------
4032 sal_Bool SAL_CALL FormController::confirmDelete(const RowChangeEvent& aEvent) throw( RuntimeException )
4034 ::osl::MutexGuard aGuard( m_aMutex );
4035 impl_checkDisposed_throw();
4037 ::cppu::OInterfaceIteratorHelper aIter(m_aDeleteListeners);
4038 if (aIter.hasMoreElements())
4040 RowChangeEvent aEvt(aEvent);
4041 aEvt.Source = *this;
4042 return ((XConfirmDeleteListener*)aIter.next())->confirmDelete(aEvt);
4044 // default handling: instantiate an interaction handler and let it handle the request
4046 String sTitle;
4047 sal_Int32 nLength = aEvent.Rows;
4048 if ( nLength > 1 )
4050 sTitle = SVX_RESSTR( RID_STR_DELETECONFIRM_RECORDS );
4051 sTitle.SearchAndReplace( OUString('#'), OUString::valueOf(nLength) );
4053 else
4054 sTitle = SVX_RESSTR( RID_STR_DELETECONFIRM_RECORD );
4058 if ( !ensureInteractionHandler() )
4059 return sal_False;
4061 // two continuations allowed: Yes and No
4062 OInteractionApprove* pApprove = new OInteractionApprove;
4063 OInteractionDisapprove* pDisapprove = new OInteractionDisapprove;
4065 // the request
4066 SQLWarning aWarning;
4067 aWarning.Message = sTitle;
4068 SQLWarning aDetails;
4069 aDetails.Message = String( SVX_RES( RID_STR_DELETECONFIRM ) );
4070 aWarning.NextException <<= aDetails;
4072 OInteractionRequest* pRequest = new OInteractionRequest( makeAny( aWarning ) );
4073 Reference< XInteractionRequest > xRequest( pRequest );
4075 // some knittings
4076 pRequest->addContinuation( pApprove );
4077 pRequest->addContinuation( pDisapprove );
4079 // handle the request
4080 m_xInteractionHandler->handle( xRequest );
4082 if ( pApprove->wasSelected() )
4083 return sal_True;
4085 catch( const Exception& )
4087 DBG_UNHANDLED_EXCEPTION();
4090 return sal_False;
4093 //------------------------------------------------------------------------------
4094 void SAL_CALL FormController::invalidateFeatures( const Sequence< ::sal_Int16 >& _Features ) throw (RuntimeException)
4096 ::osl::MutexGuard aGuard( m_aMutex );
4097 // for now, just copy the ids of the features, because ....
4098 ::std::copy( _Features.getConstArray(), _Features.getConstArray() + _Features.getLength(),
4099 ::std::insert_iterator< ::std::set< sal_Int16 > >( m_aInvalidFeatures, m_aInvalidFeatures.begin() )
4102 // ... we will do the real invalidation asynchronously
4103 if ( !m_aFeatureInvalidationTimer.IsActive() )
4104 m_aFeatureInvalidationTimer.Start();
4107 //------------------------------------------------------------------------------
4108 void SAL_CALL FormController::invalidateAllFeatures( ) throw (RuntimeException)
4110 ::osl::ClearableMutexGuard aGuard( m_aMutex );
4112 Sequence< sal_Int16 > aInterceptedFeatures( m_aFeatureDispatchers.size() );
4113 ::std::transform(
4114 m_aFeatureDispatchers.begin(),
4115 m_aFeatureDispatchers.end(),
4116 aInterceptedFeatures.getArray(),
4117 ::o3tl::select1st< DispatcherContainer::value_type >()
4120 aGuard.clear();
4121 if ( aInterceptedFeatures.getLength() )
4122 invalidateFeatures( aInterceptedFeatures );
4125 //------------------------------------------------------------------------------
4126 Reference< XDispatch >
4127 FormController::interceptedQueryDispatch( const URL& aURL,
4128 const OUString& /*aTargetFrameName*/, sal_Int32 /*nSearchFlags*/)
4129 throw( RuntimeException )
4131 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
4132 Reference< XDispatch > xReturn;
4133 // dispatches handled by ourself
4134 if ( ( aURL.Complete == FMURL_CONFIRM_DELETION )
4135 || ( ( aURL.Complete.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "private:/InteractionHandler" ) ) )
4136 && ensureInteractionHandler()
4139 xReturn = static_cast< XDispatch* >( this );
4141 // dispatches of FormSlot-URLs we have to translate
4142 if ( !xReturn.is() && m_xFormOperations.is() )
4144 // find the slot id which corresponds to the URL
4145 sal_Int32 nFeatureSlotId = ::svx::FeatureSlotTranslation::getControllerFeatureSlotIdForURL( aURL.Main );
4146 sal_Int16 nFormFeature = ( nFeatureSlotId != -1 ) ? ::svx::FeatureSlotTranslation::getFormFeatureForSlotId( nFeatureSlotId ) : -1;
4147 if ( nFormFeature > 0 )
4149 // get the dispatcher for this feature, create if necessary
4150 DispatcherContainer::const_iterator aDispatcherPos = m_aFeatureDispatchers.find( nFormFeature );
4151 if ( aDispatcherPos == m_aFeatureDispatchers.end() )
4153 aDispatcherPos = m_aFeatureDispatchers.insert(
4154 DispatcherContainer::value_type( nFormFeature, new ::svx::OSingleFeatureDispatcher( aURL, nFormFeature, m_xFormOperations, m_aMutex ) )
4155 ).first;
4158 OSL_ENSURE( aDispatcherPos->second.is(), "FormController::interceptedQueryDispatch: should have a dispatcher by now!" );
4159 return aDispatcherPos->second;
4163 // no more to offer
4164 return xReturn;
4167 //------------------------------------------------------------------------------
4168 void SAL_CALL FormController::dispatch( const URL& _rURL, const Sequence< PropertyValue >& _rArgs ) throw (RuntimeException)
4170 if ( _rArgs.getLength() != 1 )
4172 OSL_FAIL( "FormController::dispatch: no arguments -> no dispatch!" );
4173 return;
4176 if ( _rURL.Complete == "private:/InteractionHandler" )
4178 Reference< XInteractionRequest > xRequest;
4179 OSL_VERIFY( _rArgs[0].Value >>= xRequest );
4180 if ( xRequest.is() )
4181 handle( xRequest );
4182 return;
4185 if ( _rURL.Complete == FMURL_CONFIRM_DELETION )
4187 OSL_FAIL( "FormController::dispatch: How do you expect me to return something via this call?" );
4188 // confirmDelete has a return value - dispatch hasn't
4189 return;
4192 OSL_FAIL( "FormController::dispatch: unknown URL!" );
4195 //------------------------------------------------------------------------------
4196 void SAL_CALL FormController::addStatusListener( const Reference< XStatusListener >& _rxListener, const URL& _rURL ) throw (RuntimeException)
4198 if (_rURL.Complete == FMURL_CONFIRM_DELETION)
4200 if (_rxListener.is())
4201 { // send an initial statusChanged event
4202 FeatureStateEvent aEvent;
4203 aEvent.FeatureURL = _rURL;
4204 aEvent.IsEnabled = sal_True;
4205 _rxListener->statusChanged(aEvent);
4206 // and don't add the listener at all (the status will never change)
4209 else
4210 OSL_FAIL("FormController::addStatusListener: invalid (unsupported) URL!");
4213 //------------------------------------------------------------------------------
4214 Reference< XInterface > SAL_CALL FormController::getParent() throw( RuntimeException )
4216 return m_xParent;
4219 //------------------------------------------------------------------------------
4220 void SAL_CALL FormController::setParent( const Reference< XInterface >& Parent) throw( NoSupportException, RuntimeException )
4222 m_xParent = Parent;
4225 //------------------------------------------------------------------------------
4226 void SAL_CALL FormController::removeStatusListener( const Reference< XStatusListener >& /*_rxListener*/, const URL& _rURL ) throw (RuntimeException)
4228 (void)_rURL;
4229 OSL_ENSURE(_rURL.Complete == FMURL_CONFIRM_DELETION, "FormController::removeStatusListener: invalid (unsupported) URL!");
4230 // we never really added the listener, so we don't need to remove it
4233 //------------------------------------------------------------------------------
4234 Reference< XDispatchProviderInterceptor > FormController::createInterceptor(const Reference< XDispatchProviderInterception > & _xInterception)
4236 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
4237 #ifdef DBG_UTIL
4238 // check if we already have a interceptor for the given object
4239 for ( ConstInterceptorsIterator aIter = m_aControlDispatchInterceptors.begin();
4240 aIter != m_aControlDispatchInterceptors.end();
4241 ++aIter
4244 if ((*aIter)->getIntercepted() == _xInterception)
4245 OSL_FAIL("FormController::createInterceptor : we already do intercept this objects dispatches !");
4247 #endif
4249 DispatchInterceptionMultiplexer* pInterceptor = new DispatchInterceptionMultiplexer( _xInterception, this );
4250 pInterceptor->acquire();
4251 m_aControlDispatchInterceptors.insert( m_aControlDispatchInterceptors.end(), pInterceptor );
4253 return pInterceptor;
4256 //------------------------------------------------------------------------------
4257 bool FormController::ensureInteractionHandler()
4259 if ( m_xInteractionHandler.is() )
4260 return true;
4261 if ( m_bAttemptedHandlerCreation )
4262 return false;
4263 m_bAttemptedHandlerCreation = true;
4265 m_xInteractionHandler.set( InteractionHandler::createWithParent(m_aContext.getUNOContext(), 0), UNO_QUERY );
4266 OSL_ENSURE( m_xInteractionHandler.is(), "FormController::ensureInteractionHandler: could not create an interaction handler!" );
4267 return m_xInteractionHandler.is();
4270 //------------------------------------------------------------------------------
4271 void SAL_CALL FormController::handle( const Reference< XInteractionRequest >& _rRequest ) throw (RuntimeException)
4273 if ( !ensureInteractionHandler() )
4274 return;
4275 m_xInteractionHandler->handle( _rRequest );
4278 //------------------------------------------------------------------------------
4279 void FormController::deleteInterceptor(const Reference< XDispatchProviderInterception > & _xInterception)
4281 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
4282 // search the interceptor responsible for the given object
4283 InterceptorsIterator aIter;
4284 for ( aIter = m_aControlDispatchInterceptors.begin();
4285 aIter != m_aControlDispatchInterceptors.end();
4286 ++aIter
4289 if ((*aIter)->getIntercepted() == _xInterception)
4290 break;
4292 if (aIter == m_aControlDispatchInterceptors.end())
4294 return;
4297 // log off the interception from it's interception object
4298 DispatchInterceptionMultiplexer* pInterceptorImpl = *aIter;
4299 pInterceptorImpl->dispose();
4300 pInterceptorImpl->release();
4302 // remove the interceptor from our array
4303 m_aControlDispatchInterceptors.erase(aIter);
4306 //--------------------------------------------------------------------
4307 void FormController::implInvalidateCurrentControlDependentFeatures()
4309 Sequence< sal_Int16 > aCurrentControlDependentFeatures(4);
4311 aCurrentControlDependentFeatures[0] = FormFeature::SortAscending;
4312 aCurrentControlDependentFeatures[1] = FormFeature::SortDescending;
4313 aCurrentControlDependentFeatures[2] = FormFeature::AutoFilter;
4314 aCurrentControlDependentFeatures[3] = FormFeature::RefreshCurrentControl;
4316 invalidateFeatures( aCurrentControlDependentFeatures );
4319 //--------------------------------------------------------------------
4320 void SAL_CALL FormController::columnChanged( const EventObject& /*_event*/ ) throw (RuntimeException)
4322 implInvalidateCurrentControlDependentFeatures();
4325 } // namespace svxform
4327 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */