Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / svx / source / form / formcontroller.cxx
blob0d4457cb9a31906e0f64b011e595d3081f88f8e9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "fmcontrolbordermanager.hxx"
22 #include "fmcontrollayout.hxx"
23 #include "formcontroller.hxx"
24 #include "formfeaturedispatcher.hxx"
25 #include "fmdocumentclassification.hxx"
26 #include "formcontrolling.hxx"
27 #include "fmprop.hrc"
28 #include "svx/dialmgr.hxx"
29 #include "svx/fmresids.hrc"
30 #include "fmservs.hxx"
31 #include "svx/fmtools.hxx"
32 #include "fmurl.hxx"
34 #include <com/sun/star/awt/FocusChangeReason.hpp>
35 #include <com/sun/star/awt/XCheckBox.hpp>
36 #include <com/sun/star/awt/XComboBox.hpp>
37 #include <com/sun/star/awt/XListBox.hpp>
38 #include <com/sun/star/awt/XVclWindowPeer.hpp>
39 #include <com/sun/star/awt/TabController.hpp>
40 #include <com/sun/star/beans/NamedValue.hpp>
41 #include <com/sun/star/beans/PropertyAttribute.hpp>
42 #include <com/sun/star/container/XIdentifierReplace.hpp>
43 #include <com/sun/star/form/TabulatorCycle.hpp>
44 #include <com/sun/star/form/validation/XValidatableFormComponent.hpp>
45 #include <com/sun/star/form/XBoundComponent.hpp>
46 #include <com/sun/star/form/XBoundControl.hpp>
47 #include <com/sun/star/form/XGridControl.hpp>
48 #include <com/sun/star/form/XLoadable.hpp>
49 #include <com/sun/star/form/XReset.hpp>
50 #include <com/sun/star/form/control/FilterControl.hpp>
51 #include <com/sun/star/frame/XController.hpp>
52 #include <com/sun/star/sdb/ParametersRequest.hpp>
53 #include <com/sun/star/sdb/RowChangeAction.hpp>
54 #include <com/sun/star/sdb/XInteractionSupplyParameters.hpp>
55 #include <com/sun/star/sdbc/ColumnValue.hpp>
56 #include <com/sun/star/sdbc/DataType.hpp>
57 #include <com/sun/star/task/InteractionHandler.hpp>
58 #include <com/sun/star/util/XURLTransformer.hpp>
59 #include <com/sun/star/form/runtime/FormOperations.hpp>
60 #include <com/sun/star/form/runtime/FormFeature.hpp>
61 #include <com/sun/star/container/XContainer.hpp>
62 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
63 #include <com/sun/star/util/NumberFormatter.hpp>
64 #include <com/sun/star/sdb/SQLContext.hpp>
65 #include <com/sun/star/sdb/XColumn.hpp>
67 #include <comphelper/enumhelper.hxx>
68 #include <comphelper/interaction.hxx>
69 #include <comphelper/namedvaluecollection.hxx>
70 #include <comphelper/processfactory.hxx>
71 #include <comphelper/propagg.hxx>
72 #include <comphelper/property.hxx>
73 #include <comphelper/sequence.hxx>
74 #include <comphelper/uno3.hxx>
75 #include <comphelper/flagguard.hxx>
76 #include <cppuhelper/queryinterface.hxx>
77 #include <cppuhelper/supportsservice.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 <vcl/settings.hxx>
88 #include <osl/mutex.hxx>
90 #include <algorithm>
92 #include <o3tl/compat_functional.hxx>
94 using namespace ::com::sun::star;
95 using namespace ::comphelper;
96 using namespace ::connectivity;
97 using namespace ::connectivity::simple;
100 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL
101 FormController_NewInstance_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & _rxORB )
102 throw (css::uno::Exception)
104 return *( new ::svxform::FormController( comphelper::getComponentContext(_rxORB) ) );
107 namespace svxform
110 using ::com::sun::star::sdb::XColumn;
111 using ::com::sun::star::awt::XControl;
112 using ::com::sun::star::awt::XTabController;
113 using ::com::sun::star::awt::TabController;
114 using ::com::sun::star::awt::XToolkit;
115 using ::com::sun::star::awt::XWindowPeer;
116 using ::com::sun::star::form::XGrid;
117 using ::com::sun::star::beans::XPropertySet;
118 using ::com::sun::star::uno::UNO_SET_THROW;
119 using ::com::sun::star::uno::UNO_QUERY_THROW;
120 using ::com::sun::star::container::XIndexAccess;
121 using ::com::sun::star::uno::Exception;
122 using ::com::sun::star::uno::XInterface;
123 using ::com::sun::star::uno::UNO_QUERY;
124 using ::com::sun::star::uno::Sequence;
125 using ::com::sun::star::uno::Reference;
126 using ::com::sun::star::beans::XPropertySetInfo;
127 using ::com::sun::star::beans::PropertyValue;
128 using ::com::sun::star::uno::RuntimeException;
129 using ::com::sun::star::lang::IndexOutOfBoundsException;
130 using ::com::sun::star::sdb::XInteractionSupplyParameters;
131 using ::com::sun::star::awt::XTextComponent;
132 using ::com::sun::star::awt::XTextListener;
133 using ::com::sun::star::uno::Any;
134 using ::com::sun::star::frame::XDispatch;
135 using ::com::sun::star::lang::XMultiServiceFactory;
136 using ::com::sun::star::uno::XAggregation;
137 using ::com::sun::star::uno::Type;
138 using ::com::sun::star::lang::IllegalArgumentException;
139 using ::com::sun::star::sdbc::XConnection;
140 using ::com::sun::star::sdbc::XRowSet;
141 using ::com::sun::star::sdbc::XDatabaseMetaData;
142 using ::com::sun::star::util::XNumberFormatsSupplier;
143 using ::com::sun::star::util::NumberFormatter;
144 using ::com::sun::star::util::XNumberFormatter;
145 using ::com::sun::star::sdbcx::XColumnsSupplier;
146 using ::com::sun::star::container::XNameAccess;
147 using ::com::sun::star::lang::EventObject;
148 using ::com::sun::star::beans::Property;
149 using ::com::sun::star::container::XEnumeration;
150 using ::com::sun::star::form::XFormComponent;
151 using ::com::sun::star::form::runtime::XFormOperations;
152 using ::com::sun::star::form::runtime::FilterEvent;
153 using ::com::sun::star::form::runtime::XFilterControllerListener;
154 using ::com::sun::star::awt::XControlContainer;
155 using ::com::sun::star::container::XIdentifierReplace;
156 using ::com::sun::star::lang::WrappedTargetException;
157 using ::com::sun::star::form::XFormControllerListener;
158 using ::com::sun::star::awt::XWindow;
159 using ::com::sun::star::sdbc::XResultSet;
160 using ::com::sun::star::awt::XControlModel;
161 using ::com::sun::star::awt::XTabControllerModel;
162 using ::com::sun::star::beans::PropertyChangeEvent;
163 using ::com::sun::star::form::validation::XValidatableFormComponent;
164 using ::com::sun::star::form::XLoadable;
165 using ::com::sun::star::script::XEventAttacherManager;
166 using ::com::sun::star::form::XBoundControl;
167 using ::com::sun::star::beans::XPropertyChangeListener;
168 using ::com::sun::star::awt::TextEvent;
169 using ::com::sun::star::form::XBoundComponent;
170 using ::com::sun::star::awt::XCheckBox;
171 using ::com::sun::star::awt::XComboBox;
172 using ::com::sun::star::awt::XListBox;
173 using ::com::sun::star::awt::ItemEvent;
174 using ::com::sun::star::util::XModifyListener;
175 using ::com::sun::star::form::XReset;
176 using ::com::sun::star::frame::XDispatchProviderInterception;
177 using ::com::sun::star::form::XGridControl;
178 using ::com::sun::star::awt::XVclWindowPeer;
179 using ::com::sun::star::form::validation::XValidator;
180 using ::com::sun::star::awt::FocusEvent;
181 using ::com::sun::star::sdb::SQLContext;
182 using ::com::sun::star::container::XChild;
183 using ::com::sun::star::form::TabulatorCycle_RECORDS;
184 using ::com::sun::star::container::ContainerEvent;
185 using ::com::sun::star::lang::DisposedException;
186 using ::com::sun::star::lang::Locale;
187 using ::com::sun::star::beans::NamedValue;
188 using ::com::sun::star::lang::NoSupportException;
189 using ::com::sun::star::sdb::RowChangeEvent;
190 using ::com::sun::star::frame::XStatusListener;
191 using ::com::sun::star::frame::XDispatchProviderInterceptor;
192 using ::com::sun::star::sdb::SQLErrorEvent;
193 using ::com::sun::star::form::DatabaseParameterEvent;
194 using ::com::sun::star::sdb::ParametersRequest;
195 using ::com::sun::star::task::XInteractionRequest;
196 using ::com::sun::star::util::URL;
197 using ::com::sun::star::frame::FeatureStateEvent;
198 using ::com::sun::star::form::runtime::XFormControllerContext;
199 using ::com::sun::star::task::InteractionHandler;
200 using ::com::sun::star::task::XInteractionHandler;
201 using ::com::sun::star::form::runtime::FormOperations;
202 using ::com::sun::star::container::XContainer;
203 using ::com::sun::star::sdbc::SQLWarning;
205 namespace ColumnValue = ::com::sun::star::sdbc::ColumnValue;
206 namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
207 namespace FocusChangeReason = ::com::sun::star::awt::FocusChangeReason;
208 namespace RowChangeAction = ::com::sun::star::sdb::RowChangeAction;
209 namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
210 namespace DataType = ::com::sun::star::sdbc::DataType;
213 // ColumnInfo
215 struct ColumnInfo
217 // information about the column itself
218 Reference< XColumn > xColumn;
219 sal_Int32 nNullable;
220 bool bAutoIncrement;
221 bool bReadOnly;
222 OUString sName;
224 // information about the control(s) bound to this column
226 /// the first control which is bound to the given column, and which requires input
227 Reference< XControl > xFirstControlWithInputRequired;
228 /** the first grid control which contains a column which is bound to the given database column, and requires
229 input
231 Reference< XGrid > xFirstGridWithInputRequiredColumn;
232 /** if xFirstControlWithInputRequired is a grid control, then nRequiredGridColumn specifies the position
233 of the grid column which is actually bound
235 sal_Int32 nRequiredGridColumn;
237 ColumnInfo()
238 :xColumn()
239 ,nNullable( ColumnValue::NULLABLE_UNKNOWN )
240 ,bAutoIncrement( false )
241 ,bReadOnly( false )
242 ,sName()
243 ,xFirstControlWithInputRequired()
244 ,xFirstGridWithInputRequiredColumn()
245 ,nRequiredGridColumn( -1 )
251 //= ColumnInfoCache
253 class ColumnInfoCache
255 public:
256 ColumnInfoCache( const Reference< XColumnsSupplier >& _rxColSupplier );
258 size_t getColumnCount() const { return m_aColumns.size(); }
259 const ColumnInfo& getColumnInfo( size_t _pos );
261 bool controlsInitialized() const { return m_bControlsInitialized; }
262 void initializeControls( const Sequence< Reference< XControl > >& _rControls );
263 void deinitializeControls();
265 private:
266 typedef ::std::vector< ColumnInfo > ColumnInfos;
267 ColumnInfos m_aColumns;
268 bool m_bControlsInitialized;
272 ColumnInfoCache::ColumnInfoCache( const Reference< XColumnsSupplier >& _rxColSupplier )
273 :m_aColumns()
274 ,m_bControlsInitialized( false )
278 m_aColumns.clear();
280 Reference< XIndexAccess > xColumns( _rxColSupplier->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();
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 bool bInputRequired = true;
317 OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_INPUT_REQUIRED ) >>= bInputRequired );
318 return bInputRequired;
321 void lcl_resetColumnControlInfo( ColumnInfo& _rColInfo )
323 _rColInfo.xFirstControlWithInputRequired.clear();
324 _rColInfo.xFirstGridWithInputRequiredColumn.clear();
325 _rColInfo.nRequiredGridColumn = -1;
330 void ColumnInfoCache::deinitializeControls()
332 for ( ColumnInfos::iterator col = m_aColumns.begin();
333 col != m_aColumns.end();
334 ++col
337 lcl_resetColumnControlInfo( *col );
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 const Reference< XControl >* pControl( _rControls.getConstArray() );
358 const Reference< XControl >* pControlEnd( pControl + _rControls.getLength() );
359 for ( ; pControl != pControlEnd; ++pControl )
361 if ( !pControl->is() )
362 continue;
364 Reference< XPropertySet > xModel( (*pControl)->getModel(), UNO_QUERY_THROW );
365 Reference< XPropertySetInfo > xModelPSI( xModel->getPropertySetInfo(), UNO_SET_THROW );
367 // special handling for grid controls
368 Reference< XGrid > xGrid( *pControl, UNO_QUERY );
369 if ( xGrid.is() )
371 Reference< XIndexAccess > xGridColAccess( xModel, UNO_QUERY_THROW );
372 sal_Int32 gridColCount = xGridColAccess->getCount();
373 sal_Int32 gridCol = 0;
374 for ( gridCol = 0; gridCol < gridColCount; ++gridCol )
376 Reference< XPropertySet > xGridColumnModel( xGridColAccess->getByIndex( gridCol ), UNO_QUERY_THROW );
378 if ( !lcl_isBoundTo( xGridColumnModel, col->xColumn )
379 || !lcl_isInputRequired( xGridColumnModel )
381 continue; // with next grid column
383 break;
386 if ( gridCol < gridColCount )
388 // found a grid column which is bound to the given
389 col->xFirstGridWithInputRequiredColumn = xGrid;
390 col->nRequiredGridColumn = gridCol;
391 break;
394 continue; // with next control
397 if ( !xModelPSI->hasPropertyByName( FM_PROP_BOUNDFIELD )
398 || !lcl_isBoundTo( xModel, col->xColumn )
399 || !lcl_isInputRequired( xModel )
401 continue; // with next control
403 break;
406 if ( pControl == pControlEnd )
407 // did not find a control which is bound to this particular column, and for which the input is required
408 continue; // with next DB column
410 col->xFirstControlWithInputRequired = *pControl;
413 catch( const Exception& )
415 DBG_UNHANDLED_EXCEPTION();
418 m_bControlsInitialized = true;
422 const ColumnInfo& ColumnInfoCache::getColumnInfo( size_t _pos )
424 if ( _pos >= m_aColumns.size() )
425 throw IndexOutOfBoundsException();
427 return m_aColumns[ _pos ];
431 // OParameterContinuation
433 class OParameterContinuation : public OInteraction< XInteractionSupplyParameters >
435 Sequence< PropertyValue > m_aValues;
437 public:
438 OParameterContinuation() { }
440 Sequence< PropertyValue > getValues() const { return m_aValues; }
442 // XInteractionSupplyParameters
443 virtual void SAL_CALL setParameters( const Sequence< PropertyValue >& _rValues ) throw(RuntimeException, std::exception) SAL_OVERRIDE;
447 void SAL_CALL OParameterContinuation::setParameters( const Sequence< PropertyValue >& _rValues ) throw(RuntimeException, std::exception)
449 m_aValues = _rValues;
453 // FmXAutoControl
455 struct FmFieldInfo
457 OUString aFieldName;
458 Reference< XPropertySet > xField;
459 Reference< XTextComponent > xText;
461 FmFieldInfo(const Reference< XPropertySet >& _xField, const Reference< XTextComponent >& _xText)
462 :xField(_xField)
463 ,xText(_xText)
464 {xField->getPropertyValue(FM_PROP_NAME) >>= aFieldName;}
468 // FmXAutoControl
470 class FmXAutoControl: public UnoControl
473 public:
474 FmXAutoControl() :UnoControl()
478 virtual OUString GetComponentServiceName() SAL_OVERRIDE {return OUString("Edit");}
479 virtual void SAL_CALL createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) throw( RuntimeException, std::exception ) SAL_OVERRIDE;
481 protected:
482 virtual void ImplSetPeerProperty( const OUString& rPropName, const Any& rVal ) SAL_OVERRIDE;
486 void FmXAutoControl::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) throw( RuntimeException, std::exception )
488 UnoControl::createPeer( rxToolkit, rParentPeer );
490 Reference< XTextComponent > xText(getPeer() , UNO_QUERY);
491 if (xText.is())
493 xText->setText(SVX_RESSTR(RID_STR_AUTOFIELD));
494 xText->setEditable(sal_False);
499 void FmXAutoControl::ImplSetPeerProperty( const OUString& rPropName, const Any& rVal )
501 // these properties are ignored
502 if (rPropName == FM_PROP_TEXT)
503 return;
505 UnoControl::ImplSetPeerProperty( rPropName, rVal );
509 IMPL_LINK( FormController, OnActivateTabOrder, void*, /*EMPTYTAG*/ )
511 activateTabOrder();
512 return 1;
516 struct UpdateAllListeners : public ::std::unary_function< Reference< XDispatch >, bool >
518 bool operator()( const Reference< XDispatch >& _rxDispatcher ) const
520 static_cast< ::svx::OSingleFeatureDispatcher* >( _rxDispatcher.get() )->updateAllListeners();
521 // the return is a dummy only so we can use this struct in a o3tl::compose1 call
522 return true;
526 IMPL_LINK( FormController, OnInvalidateFeatures, void*, /*_pNotInterestedInThisParam*/ )
528 ::osl::MutexGuard aGuard( m_aMutex );
529 for ( ::std::set< sal_Int16 >::const_iterator aLoop = m_aInvalidFeatures.begin();
530 aLoop != m_aInvalidFeatures.end();
531 ++aLoop
534 DispatcherContainer::const_iterator aDispatcherPos = m_aFeatureDispatchers.find( *aLoop );
535 if ( aDispatcherPos != m_aFeatureDispatchers.end() )
537 // TODO: for the real and actual listener notifications, we should release
538 // our mutex
539 UpdateAllListeners( )( aDispatcherPos->second );
542 return 1;
545 /*************************************************************************/
548 FormController::FormController(const Reference< css::uno::XComponentContext > & _rxORB )
549 :FormController_BASE( m_aMutex )
550 ,OPropertySetHelper( FormController_BASE::rBHelper )
551 ,OSQLParserClient( _rxORB )
552 ,m_xComponentContext( _rxORB )
553 ,m_aActivateListeners(m_aMutex)
554 ,m_aModifyListeners(m_aMutex)
555 ,m_aErrorListeners(m_aMutex)
556 ,m_aDeleteListeners(m_aMutex)
557 ,m_aRowSetApproveListeners(m_aMutex)
558 ,m_aParameterListeners(m_aMutex)
559 ,m_aFilterListeners(m_aMutex)
560 ,m_pControlBorderManager( new ::svxform::ControlBorderManager )
561 ,m_xFormOperations()
562 ,m_aMode( OUString( "DataMode" ) )
563 ,m_aLoadEvent( LINK( this, FormController, OnLoad ) )
564 ,m_aToggleEvent( LINK( this, FormController, OnToggleAutoFields ) )
565 ,m_aActivationEvent( LINK( this, FormController, OnActivated ) )
566 ,m_aDeactivationEvent( LINK( this, FormController, OnDeactivated ) )
567 ,m_nCurrentFilterPosition(-1)
568 ,m_bCurrentRecordModified(false)
569 ,m_bCurrentRecordNew(false)
570 ,m_bLocked(false)
571 ,m_bDBConnection(false)
572 ,m_bCycle(false)
573 ,m_bCanInsert(false)
574 ,m_bCanUpdate(false)
575 ,m_bCommitLock(false)
576 ,m_bModified(false)
577 ,m_bControlsSorted(false)
578 ,m_bFiltering(false)
579 ,m_bAttachEvents(true)
580 ,m_bDetachEvents(true)
581 ,m_bAttemptedHandlerCreation( false )
582 ,m_bSuspendFilterTextListening( false )
585 ::comphelper::increment(m_refCount);
587 m_xTabController = TabController::create( m_xComponentContext );
588 m_xAggregate = Reference< XAggregation >( m_xTabController, UNO_QUERY_THROW );
589 m_xAggregate->setDelegator( *this );
591 ::comphelper::decrement(m_refCount);
593 m_aTabActivationTimer.SetTimeout( 500 );
594 m_aTabActivationTimer.SetTimeoutHdl( LINK( this, FormController, OnActivateTabOrder ) );
596 m_aFeatureInvalidationTimer.SetTimeout( 200 );
597 m_aFeatureInvalidationTimer.SetTimeoutHdl( LINK( this, FormController, OnInvalidateFeatures ) );
601 FormController::~FormController()
604 ::osl::MutexGuard aGuard( m_aMutex );
606 m_aLoadEvent.CancelPendingCall();
607 m_aToggleEvent.CancelPendingCall();
608 m_aActivationEvent.CancelPendingCall();
609 m_aDeactivationEvent.CancelPendingCall();
611 if ( m_aTabActivationTimer.IsActive() )
612 m_aTabActivationTimer.Stop();
615 if ( m_aFeatureInvalidationTimer.IsActive() )
616 m_aFeatureInvalidationTimer.Stop();
618 disposeAllFeaturesAndDispatchers();
620 if ( m_xFormOperations.is() )
621 m_xFormOperations->dispose();
622 m_xFormOperations.clear();
624 // Freigeben der Aggregation
625 if ( m_xAggregate.is() )
627 m_xAggregate->setDelegator( NULL );
628 m_xAggregate.clear();
631 DELETEZ( m_pControlBorderManager );
636 void SAL_CALL FormController::acquire() throw ()
638 FormController_BASE::acquire();
642 void SAL_CALL FormController::release() throw ()
644 FormController_BASE::release();
648 Any SAL_CALL FormController::queryInterface( const Type& _rType ) throw(RuntimeException, std::exception)
650 Any aRet = FormController_BASE::queryInterface( _rType );
651 if ( !aRet.hasValue() )
652 aRet = OPropertySetHelper::queryInterface( _rType );
653 if ( !aRet.hasValue() )
654 aRet = m_xAggregate->queryAggregation( _rType );
655 return aRet;
659 Sequence< sal_Int8 > SAL_CALL FormController::getImplementationId() throw( RuntimeException, std::exception )
661 return css::uno::Sequence<sal_Int8>();
664 Sequence< Type > SAL_CALL FormController::getTypes( ) throw(RuntimeException, std::exception)
666 return comphelper::concatSequences(
667 FormController_BASE::getTypes(),
668 ::cppu::OPropertySetHelper::getTypes()
672 // XServiceInfo
673 sal_Bool SAL_CALL FormController::supportsService(const OUString& ServiceName) throw( RuntimeException, std::exception )
675 return cppu::supportsService(this, ServiceName);
678 OUString SAL_CALL FormController::getImplementationName() throw( RuntimeException, std::exception )
680 return OUString("org.openoffice.comp.svx.FormController");
683 Sequence< OUString> SAL_CALL FormController::getSupportedServiceNames(void) throw( RuntimeException, std::exception )
685 // service names which are supported only, but cannot be used to created an
686 // instance at a service factory
687 Sequence< OUString > aNonCreatableServiceNames( 1 );
688 aNonCreatableServiceNames[ 0 ] = "com.sun.star.form.FormControllerDispatcher";
690 // services which can be used to created an instance at a service factory
691 Sequence< OUString > aCreatableServiceNames( getSupportedServiceNames_Static() );
692 return ::comphelper::concatSequences( aCreatableServiceNames, aNonCreatableServiceNames );
696 sal_Bool SAL_CALL FormController::approveReset(const EventObject& /*rEvent*/) throw( RuntimeException, std::exception )
698 return sal_True;
702 void SAL_CALL FormController::resetted(const EventObject& rEvent) throw( RuntimeException, std::exception )
704 ::osl::MutexGuard aGuard(m_aMutex);
705 if (getCurrentControl().is() && (getCurrentControl()->getModel() == rEvent.Source))
706 m_bModified = false;
710 Sequence< OUString> FormController::getSupportedServiceNames_Static(void)
712 static Sequence< OUString> aServices;
713 if (!aServices.getLength())
715 aServices.realloc(2);
716 aServices.getArray()[0] = "com.sun.star.form.runtime.FormController";
717 aServices.getArray()[1] = "com.sun.star.awt.control.TabController";
719 return aServices;
723 namespace
725 struct ResetComponentText : public ::std::unary_function< Reference< XTextComponent >, void >
727 void operator()( const Reference< XTextComponent >& _rxText )
729 _rxText->setText( OUString() );
733 struct RemoveComponentTextListener : public ::std::unary_function< Reference< XTextComponent >, void >
735 RemoveComponentTextListener( const Reference< XTextListener >& _rxListener )
736 :m_xListener( _rxListener )
740 void operator()( const Reference< XTextComponent >& _rxText )
742 _rxText->removeTextListener( m_xListener );
745 private:
746 Reference< XTextListener > m_xListener;
751 void FormController::impl_setTextOnAllFilter_throw()
753 m_bSuspendFilterTextListening = true;
754 ::comphelper::FlagGuard aResetFlag( m_bSuspendFilterTextListening );
756 // reset the text for all controls
757 ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), ResetComponentText() );
759 if ( m_aFilterRows.empty() )
760 // nothing to do anymore
761 return;
763 if ( m_nCurrentFilterPosition < 0 )
764 return;
766 // set the text for all filters
767 OSL_ENSURE( m_aFilterRows.size() > (size_t)m_nCurrentFilterPosition,
768 "FormController::impl_setTextOnAllFilter_throw: m_nCurrentFilterPosition too big" );
770 if ( (size_t)m_nCurrentFilterPosition < m_aFilterRows.size() )
772 FmFilterRow& rRow = m_aFilterRows[ m_nCurrentFilterPosition ];
773 for ( FmFilterRow::const_iterator iter2 = rRow.begin();
774 iter2 != rRow.end();
775 ++iter2
778 iter2->first->setText( iter2->second );
782 // OPropertySetHelper
784 sal_Bool FormController::convertFastPropertyValue( Any & /*rConvertedValue*/, Any & /*rOldValue*/,
785 sal_Int32 /*nHandle*/, const Any& /*rValue*/ )
786 throw( IllegalArgumentException )
788 return sal_False;
792 void FormController::setFastPropertyValue_NoBroadcast( sal_Int32 /*nHandle*/, const Any& /*rValue*/ )
793 throw( Exception, std::exception )
798 void FormController::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
800 switch (nHandle)
802 case FM_ATTR_FILTER:
804 OUStringBuffer aFilter;
805 OStaticDataAccessTools aStaticTools;
806 Reference<XConnection> xConnection(aStaticTools.getRowSetConnection(Reference< XRowSet>(m_xModelAsIndex, UNO_QUERY)));
807 if (xConnection.is())
809 Reference< XDatabaseMetaData> xMetaData(xConnection->getMetaData());
810 Reference< XNumberFormatsSupplier> xFormatSupplier( aStaticTools.getNumberFormats( xConnection, true ) );
811 Reference< XNumberFormatter> xFormatter = NumberFormatter::create(m_xComponentContext);
812 xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
814 Reference< XColumnsSupplier> xSupplyCols(m_xModelAsIndex, UNO_QUERY);
815 Reference< XNameAccess> xFields(xSupplyCols->getColumns(), UNO_QUERY);
817 // now add the filter rows
820 for ( FmFilterRows::const_iterator row = m_aFilterRows.begin(); row != m_aFilterRows.end(); ++row )
822 const FmFilterRow& rRow = *row;
824 if ( rRow.empty() )
825 continue;
827 OUStringBuffer aRowFilter;
828 for ( FmFilterRow::const_iterator condition = rRow.begin(); condition != rRow.end(); ++condition )
830 // get the field of the controls map
831 Reference< XControl > xControl( condition->first, UNO_QUERY_THROW );
832 Reference< XPropertySet > xModelProps( xControl->getModel(), UNO_QUERY_THROW );
833 Reference< XPropertySet > xField( xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY_THROW );
835 OUString sFilterValue( condition->second );
837 OUString sErrorMsg, sCriteria;
838 const ::rtl::Reference< ISQLParseNode > xParseNode =
839 predicateTree( sErrorMsg, sFilterValue, xFormatter, xField );
840 OSL_ENSURE( xParseNode.is(), "FormController::getFastPropertyValue: could not parse the field value predicate!" );
841 if ( xParseNode.is() )
843 // don't use a parse context here, we need it unlocalized
844 xParseNode->parseNodeToStr( sCriteria, xConnection, NULL );
845 if ( condition != rRow.begin() )
846 aRowFilter.appendAscii( " AND " );
847 aRowFilter.append( sCriteria );
850 if ( !aRowFilter.isEmpty() )
852 if ( !aFilter.isEmpty() )
853 aFilter.appendAscii( " OR " );
855 aFilter.appendAscii( "( " );
856 aFilter.append( aRowFilter.makeStringAndClear() );
857 aFilter.appendAscii( " )" );
861 catch( const Exception& )
863 DBG_UNHANDLED_EXCEPTION();
864 aFilter.setLength(0);
867 rValue <<= aFilter.makeStringAndClear();
869 break;
871 case FM_ATTR_FORM_OPERATIONS:
872 rValue <<= m_xFormOperations;
873 break;
878 Reference< XPropertySetInfo > FormController::getPropertySetInfo() throw( RuntimeException, std::exception )
880 static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
881 return xInfo;
885 #define DECL_PROP_CORE(varname, type) \
886 pDesc[nPos++] = Property(FM_PROP_##varname, FM_ATTR_##varname, ::getCppuType((const type*)0),
889 #define DECL_PROP1(varname, type, attrib1) \
890 DECL_PROP_CORE(varname, type) PropertyAttribute::attrib1)
893 void FormController::fillProperties(
894 Sequence< Property >& /* [out] */ _rProps,
895 Sequence< Property >& /* [out] */ /*_rAggregateProps*/
896 ) const
898 _rProps.realloc(2);
899 sal_Int32 nPos = 0;
900 Property* pDesc = _rProps.getArray();
901 DECL_PROP1(FILTER, OUString, READONLY);
902 DECL_PROP1(FORM_OPERATIONS, Reference< XFormOperations >, READONLY);
906 ::cppu::IPropertyArrayHelper& FormController::getInfoHelper()
908 return *getArrayHelper();
911 // XFilterController
913 void SAL_CALL FormController::addFilterControllerListener( const Reference< XFilterControllerListener >& _Listener ) throw( RuntimeException, std::exception )
915 m_aFilterListeners.addInterface( _Listener );
919 void SAL_CALL FormController::removeFilterControllerListener( const Reference< XFilterControllerListener >& _Listener ) throw( RuntimeException, std::exception )
921 m_aFilterListeners.removeInterface( _Listener );
925 ::sal_Int32 SAL_CALL FormController::getFilterComponents() throw( ::com::sun::star::uno::RuntimeException, std::exception )
927 ::osl::MutexGuard aGuard( m_aMutex );
928 impl_checkDisposed_throw();
930 return m_aFilterComponents.size();
934 ::sal_Int32 SAL_CALL FormController::getDisjunctiveTerms() throw( ::com::sun::star::uno::RuntimeException, std::exception )
936 ::osl::MutexGuard aGuard( m_aMutex );
937 impl_checkDisposed_throw();
939 return m_aFilterRows.size();
943 void SAL_CALL FormController::setPredicateExpression( ::sal_Int32 _Component, ::sal_Int32 _Term, const OUString& _PredicateExpression ) throw( RuntimeException, IndexOutOfBoundsException, std::exception )
945 ::osl::MutexGuard aGuard( m_aMutex );
946 impl_checkDisposed_throw();
948 if ( ( _Component < 0 ) || ( _Component >= getFilterComponents() ) || ( _Term < 0 ) || ( _Term >= getDisjunctiveTerms() ) )
949 throw IndexOutOfBoundsException( OUString(), *this );
951 Reference< XTextComponent > xText( m_aFilterComponents[ _Component ] );
952 xText->setText( _PredicateExpression );
954 FmFilterRow& rFilterRow = m_aFilterRows[ _Term ];
955 if ( !_PredicateExpression.isEmpty() )
956 rFilterRow[ xText ] = _PredicateExpression;
957 else
958 rFilterRow.erase( xText );
962 Reference< XControl > FormController::getFilterComponent( ::sal_Int32 _Component ) throw( RuntimeException, IndexOutOfBoundsException, std::exception )
964 ::osl::MutexGuard aGuard( m_aMutex );
965 impl_checkDisposed_throw();
967 if ( ( _Component < 0 ) || ( _Component >= getFilterComponents() ) )
968 throw IndexOutOfBoundsException( OUString(), *this );
970 return Reference< XControl >( m_aFilterComponents[ _Component ], UNO_QUERY );
974 Sequence< Sequence< OUString > > FormController::getPredicateExpressions() throw( RuntimeException, std::exception )
976 ::osl::MutexGuard aGuard( m_aMutex );
977 impl_checkDisposed_throw();
979 Sequence< Sequence< OUString > > aExpressions( m_aFilterRows.size() );
980 sal_Int32 termIndex = 0;
981 for ( FmFilterRows::const_iterator row = m_aFilterRows.begin();
982 row != m_aFilterRows.end();
983 ++row, ++termIndex
986 const FmFilterRow& rRow( *row );
988 Sequence< OUString > aConjunction( m_aFilterComponents.size() );
989 sal_Int32 componentIndex = 0;
990 for ( FilterComponents::const_iterator comp = m_aFilterComponents.begin();
991 comp != m_aFilterComponents.end();
992 ++comp, ++componentIndex
995 FmFilterRow::const_iterator predicate = rRow.find( *comp );
996 if ( predicate != rRow.end() )
997 aConjunction[ componentIndex ] = predicate->second;
1000 aExpressions[ termIndex ] = aConjunction;
1003 return aExpressions;
1007 void SAL_CALL FormController::removeDisjunctiveTerm( ::sal_Int32 _Term ) throw (IndexOutOfBoundsException, RuntimeException, std::exception)
1009 // SYNCHRONIZED -->
1010 ::osl::ClearableMutexGuard aGuard( m_aMutex );
1011 impl_checkDisposed_throw();
1013 if ( ( _Term < 0 ) || ( _Term >= getDisjunctiveTerms() ) )
1014 throw IndexOutOfBoundsException( OUString(), *this );
1016 // if the to-be-deleted row is our current row, we need to shift
1017 if ( _Term == m_nCurrentFilterPosition )
1019 if ( m_nCurrentFilterPosition < sal_Int32( m_aFilterRows.size() - 1 ) )
1020 ++m_nCurrentFilterPosition;
1021 else
1022 --m_nCurrentFilterPosition;
1025 FmFilterRows::iterator pos = m_aFilterRows.begin() + _Term;
1026 m_aFilterRows.erase( pos );
1028 // adjust m_nCurrentFilterPosition if the removed row preceded it
1029 if ( _Term < m_nCurrentFilterPosition )
1030 --m_nCurrentFilterPosition;
1032 SAL_WARN_IF( !( ( m_nCurrentFilterPosition < 0 ) != ( m_aFilterRows.empty() ) ),
1033 "svx.form", "FormController::removeDisjunctiveTerm: inconsistency!" );
1035 // update the texts in the filter controls
1036 impl_setTextOnAllFilter_throw();
1038 FilterEvent aEvent;
1039 aEvent.Source = *this;
1040 aEvent.DisjunctiveTerm = _Term;
1041 aGuard.clear();
1042 // <-- SYNCHRONIZED
1044 m_aFilterListeners.notifyEach( &XFilterControllerListener::disjunctiveTermRemoved, aEvent );
1048 void SAL_CALL FormController::appendEmptyDisjunctiveTerm() throw (RuntimeException, std::exception)
1050 // SYNCHRONIZED -->
1051 ::osl::ClearableMutexGuard aGuard( m_aMutex );
1052 impl_checkDisposed_throw();
1054 impl_appendEmptyFilterRow( aGuard );
1055 // <-- SYNCHRONIZED
1059 ::sal_Int32 SAL_CALL FormController::getActiveTerm() throw (RuntimeException, std::exception)
1061 ::osl::MutexGuard aGuard( m_aMutex );
1062 impl_checkDisposed_throw();
1064 return m_nCurrentFilterPosition;
1068 void SAL_CALL FormController::setActiveTerm( ::sal_Int32 _ActiveTerm ) throw (IndexOutOfBoundsException, RuntimeException, std::exception)
1070 ::osl::MutexGuard aGuard( m_aMutex );
1071 impl_checkDisposed_throw();
1073 if ( ( _ActiveTerm < 0 ) || ( _ActiveTerm >= getDisjunctiveTerms() ) )
1074 throw IndexOutOfBoundsException( OUString(), *this );
1076 if ( _ActiveTerm == getActiveTerm() )
1077 return;
1079 m_nCurrentFilterPosition = _ActiveTerm;
1080 impl_setTextOnAllFilter_throw();
1083 // XElementAccess
1085 sal_Bool SAL_CALL FormController::hasElements(void) throw( RuntimeException, std::exception )
1087 ::osl::MutexGuard aGuard( m_aMutex );
1088 return !m_aChildren.empty();
1092 Type SAL_CALL FormController::getElementType(void) throw( RuntimeException, std::exception )
1094 return cppu::UnoType<XFormController>::get();
1098 // XEnumerationAccess
1100 Reference< XEnumeration > SAL_CALL FormController::createEnumeration(void) throw( RuntimeException, std::exception )
1102 ::osl::MutexGuard aGuard( m_aMutex );
1103 return new ::comphelper::OEnumerationByIndex(this);
1106 // XIndexAccess
1108 sal_Int32 SAL_CALL FormController::getCount(void) throw( RuntimeException, std::exception )
1110 ::osl::MutexGuard aGuard( m_aMutex );
1111 return m_aChildren.size();
1115 Any SAL_CALL FormController::getByIndex(sal_Int32 Index) throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException, std::exception )
1117 ::osl::MutexGuard aGuard( m_aMutex );
1118 if (Index < 0 ||
1119 Index >= (sal_Int32)m_aChildren.size())
1120 throw IndexOutOfBoundsException();
1122 return makeAny( m_aChildren[ Index ] );
1125 // EventListener
1127 void SAL_CALL FormController::disposing(const EventObject& e) throw( RuntimeException, std::exception )
1129 // Ist der Container disposed worden
1130 ::osl::MutexGuard aGuard( m_aMutex );
1131 Reference< XControlContainer > xContainer(e.Source, UNO_QUERY);
1132 if (xContainer.is())
1134 setContainer(Reference< XControlContainer > ());
1136 else
1138 // ist ein Control disposed worden
1139 Reference< XControl > xControl(e.Source, UNO_QUERY);
1140 if (xControl.is())
1142 if (getContainer().is())
1143 removeControl(xControl);
1148 // OComponentHelper
1150 void FormController::disposeAllFeaturesAndDispatchers() SAL_THROW(())
1152 for ( DispatcherContainer::iterator aDispatcher = m_aFeatureDispatchers.begin();
1153 aDispatcher != m_aFeatureDispatchers.end();
1154 ++aDispatcher
1159 ::comphelper::disposeComponent( aDispatcher->second );
1161 catch( const Exception& )
1163 DBG_UNHANDLED_EXCEPTION();
1166 m_aFeatureDispatchers.clear();
1170 void FormController::disposing(void)
1172 EventObject aEvt( *this );
1174 // if we're still active, simulate a "deactivated" event
1175 if ( m_xActiveControl.is() )
1176 m_aActivateListeners.notifyEach( &XFormControllerListener::formDeactivated, aEvt );
1178 // notify all our listeners
1179 m_aActivateListeners.disposeAndClear(aEvt);
1180 m_aModifyListeners.disposeAndClear(aEvt);
1181 m_aErrorListeners.disposeAndClear(aEvt);
1182 m_aDeleteListeners.disposeAndClear(aEvt);
1183 m_aRowSetApproveListeners.disposeAndClear(aEvt);
1184 m_aParameterListeners.disposeAndClear(aEvt);
1185 m_aFilterListeners.disposeAndClear(aEvt);
1187 removeBoundFieldListener();
1188 stopFiltering();
1190 m_pControlBorderManager->restoreAll();
1192 m_aFilterRows.clear();
1194 ::osl::MutexGuard aGuard( m_aMutex );
1195 m_xActiveControl = NULL;
1196 implSetCurrentControl( NULL );
1198 // clean up our children
1199 for (FmFormControllers::const_iterator i = m_aChildren.begin();
1200 i != m_aChildren.end(); ++i)
1202 // search the position of the model within the form
1203 Reference< XFormComponent > xForm((*i)->getModel(), UNO_QUERY);
1204 sal_uInt32 nPos = m_xModelAsIndex->getCount();
1205 Reference< XFormComponent > xTemp;
1206 for( ; nPos; )
1209 m_xModelAsIndex->getByIndex( --nPos ) >>= xTemp;
1210 if ( xForm.get() == xTemp.get() )
1212 Reference< XInterface > xIfc( *i, UNO_QUERY );
1213 m_xModelAsManager->detach( nPos, xIfc );
1214 break;
1218 Reference< XComponent > (*i, UNO_QUERY)->dispose();
1220 m_aChildren.clear();
1222 disposeAllFeaturesAndDispatchers();
1224 if ( m_xFormOperations.is() )
1225 m_xFormOperations->dispose();
1226 m_xFormOperations.clear();
1228 if (m_bDBConnection)
1229 unload();
1231 setContainer( NULL );
1232 setModel( NULL );
1233 setParent( NULL );
1235 ::comphelper::disposeComponent( m_xComposer );
1237 m_bDBConnection = false;
1241 namespace
1243 static bool lcl_shouldUseDynamicControlBorder( const Reference< XInterface >& _rxForm, const Any& _rDynamicColorProp )
1245 bool bDoUse = false;
1246 if ( !( _rDynamicColorProp >>= bDoUse ) )
1248 DocumentType eDocType = DocumentClassification::classifyHostDocument( _rxForm );
1249 return ControlLayouter::useDynamicBorderColor( eDocType );
1251 return bDoUse;
1256 void SAL_CALL FormController::propertyChange(const PropertyChangeEvent& evt) throw( RuntimeException, std::exception )
1258 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1259 if ( evt.PropertyName == FM_PROP_BOUNDFIELD )
1261 Reference<XPropertySet> xOldBound;
1262 evt.OldValue >>= xOldBound;
1263 if ( !xOldBound.is() && evt.NewValue.hasValue() )
1265 Reference< XControlModel > xControlModel(evt.Source,UNO_QUERY);
1266 Reference< XControl > xControl = findControl(m_aControls,xControlModel,false,false);
1267 if ( xControl.is() )
1269 startControlModifyListening( xControl );
1270 Reference<XPropertySet> xProp(xControlModel,UNO_QUERY);
1271 if ( xProp.is() )
1272 xProp->removePropertyChangeListener(FM_PROP_BOUNDFIELD, this);
1276 else
1278 bool bModifiedChanged = (evt.PropertyName == FM_PROP_ISMODIFIED);
1279 bool bNewChanged = (evt.PropertyName == FM_PROP_ISNEW);
1280 if (bModifiedChanged || bNewChanged)
1282 ::osl::MutexGuard aGuard( m_aMutex );
1283 if (bModifiedChanged)
1284 m_bCurrentRecordModified = ::comphelper::getBOOL(evt.NewValue);
1285 else
1286 m_bCurrentRecordNew = ::comphelper::getBOOL(evt.NewValue);
1288 // toggle the locking
1289 if (m_bLocked != determineLockState())
1291 m_bLocked = !m_bLocked;
1292 setLocks();
1293 if (isListeningForChanges())
1294 startListening();
1295 else
1296 stopListening();
1299 if ( bNewChanged )
1300 m_aToggleEvent.Call();
1302 if (!m_bCurrentRecordModified)
1303 m_bModified = false;
1305 else if ( evt.PropertyName == FM_PROP_DYNAMIC_CONTROL_BORDER )
1307 bool bEnable = lcl_shouldUseDynamicControlBorder( evt.Source, evt.NewValue );
1308 if ( bEnable )
1310 m_pControlBorderManager->enableDynamicBorderColor();
1311 if ( m_xActiveControl.is() )
1312 m_pControlBorderManager->focusGained( m_xActiveControl.get() );
1314 else
1316 m_pControlBorderManager->disableDynamicBorderColor();
1323 bool FormController::replaceControl( const Reference< XControl >& _rxExistentControl, const Reference< XControl >& _rxNewControl )
1325 bool bSuccess = false;
1328 Reference< XIdentifierReplace > xContainer( getContainer(), UNO_QUERY );
1329 DBG_ASSERT( xContainer.is(), "FormController::replaceControl: yes, it's not required by the service description, but XItentifierReplaces would be nice!" );
1330 if ( xContainer.is() )
1332 // look up the ID of _rxExistentControl
1333 Sequence< sal_Int32 > aIdentifiers( xContainer->getIdentifiers() );
1334 const sal_Int32* pIdentifiers = aIdentifiers.getConstArray();
1335 const sal_Int32* pIdentifiersEnd = aIdentifiers.getConstArray() + aIdentifiers.getLength();
1336 for ( ; pIdentifiers != pIdentifiersEnd; ++pIdentifiers )
1338 Reference< XControl > xCheck( xContainer->getByIdentifier( *pIdentifiers ), UNO_QUERY );
1339 if ( xCheck == _rxExistentControl )
1340 break;
1342 DBG_ASSERT( pIdentifiers != pIdentifiersEnd, "FormController::replaceControl: did not find the control in the container!" );
1343 if ( pIdentifiers != pIdentifiersEnd )
1345 bool bReplacedWasActive = ( m_xActiveControl.get() == _rxExistentControl.get() );
1346 bool bReplacedWasCurrent = ( m_xCurrentControl.get() == _rxExistentControl.get() );
1348 if ( bReplacedWasActive )
1350 m_xActiveControl = NULL;
1351 implSetCurrentControl( NULL );
1353 else if ( bReplacedWasCurrent )
1355 implSetCurrentControl( _rxNewControl );
1358 // carry over the model
1359 _rxNewControl->setModel( _rxExistentControl->getModel() );
1361 xContainer->replaceByIdentifer( *pIdentifiers, makeAny( _rxNewControl ) );
1362 bSuccess = true;
1364 if ( bReplacedWasActive )
1366 Reference< XWindow > xControlWindow( _rxNewControl, UNO_QUERY );
1367 if ( xControlWindow.is() )
1368 xControlWindow->setFocus();
1373 catch( const Exception& )
1375 DBG_UNHANDLED_EXCEPTION();
1378 Reference< XControl > xDisposeIt( bSuccess ? _rxExistentControl : _rxNewControl );
1379 ::comphelper::disposeComponent( xDisposeIt );
1380 return bSuccess;
1384 void FormController::toggleAutoFields(bool bAutoFields)
1386 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1389 Sequence< Reference< XControl > > aControlsCopy( m_aControls );
1390 const Reference< XControl >* pControls = aControlsCopy.getConstArray();
1391 sal_Int32 nControls = aControlsCopy.getLength();
1393 if (bAutoFields)
1395 // as we don't want new controls to be attached to the scripting environment
1396 // we change attach flags
1397 m_bAttachEvents = false;
1398 for (sal_Int32 i = nControls; i > 0;)
1400 Reference< XControl > xControl = pControls[--i];
1401 if (xControl.is())
1403 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
1404 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
1406 // does the model use a bound field ?
1407 Reference< XPropertySet > xField;
1408 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
1410 // is it a autofield?
1411 if ( xField.is()
1412 && ::comphelper::hasProperty( FM_PROP_AUTOINCREMENT, xField )
1413 && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_AUTOINCREMENT ) )
1416 replaceControl( xControl, new FmXAutoControl() );
1421 m_bAttachEvents = true;
1423 else
1425 m_bDetachEvents = false;
1426 for (sal_Int32 i = nControls; i > 0;)
1428 Reference< XControl > xControl = pControls[--i];
1429 if (xControl.is())
1431 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
1432 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
1434 // does the model use a bound field ?
1435 Reference< XPropertySet > xField;
1436 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
1438 // is it a autofield?
1439 if ( xField.is()
1440 && ::comphelper::hasProperty( FM_PROP_AUTOINCREMENT, xField )
1441 && ::comphelper::getBOOL( xField->getPropertyValue(FM_PROP_AUTOINCREMENT ) )
1444 OUString sServiceName;
1445 OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DEFAULTCONTROL ) >>= sServiceName );
1446 Reference< XControl > xNewControl( m_xComponentContext->getServiceManager()->createInstanceWithContext( sServiceName, m_xComponentContext ), UNO_QUERY );
1447 replaceControl( xControl, xNewControl );
1452 m_bDetachEvents = true;
1457 IMPL_LINK_NOARG(FormController, OnToggleAutoFields)
1459 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1461 toggleAutoFields(m_bCurrentRecordNew);
1462 return 1L;
1465 // XTextListener
1467 void SAL_CALL FormController::textChanged(const TextEvent& e) throw( RuntimeException, std::exception )
1469 // SYNCHRONIZED -->
1470 ::osl::ClearableMutexGuard aGuard( m_aMutex );
1471 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1472 if ( !m_bFiltering )
1474 impl_onModify();
1475 return;
1478 if ( m_bSuspendFilterTextListening )
1479 return;
1481 Reference< XTextComponent > xText(e.Source,UNO_QUERY);
1482 OUString aText = xText->getText();
1484 if ( m_aFilterRows.empty() )
1485 appendEmptyDisjunctiveTerm();
1487 // Suchen der aktuellen Row
1488 if ( ( (size_t)m_nCurrentFilterPosition >= m_aFilterRows.size() ) || ( m_nCurrentFilterPosition < 0 ) )
1490 OSL_ENSURE( false, "FormController::textChanged: m_nCurrentFilterPosition is wrong!" );
1491 return;
1494 FmFilterRow& rRow = m_aFilterRows[ m_nCurrentFilterPosition ];
1496 // do we have a new filter
1497 if (!aText.isEmpty())
1498 rRow[xText] = aText;
1499 else
1501 // do we have the control in the row
1502 FmFilterRow::iterator iter = rRow.find(xText);
1503 // erase the entry out of the row
1504 if (iter != rRow.end())
1505 rRow.erase(iter);
1508 // multiplex the event to our FilterControllerListeners
1509 FilterEvent aEvent;
1510 aEvent.Source = *this;
1511 aEvent.FilterComponent = ::std::find( m_aFilterComponents.begin(), m_aFilterComponents.end(), xText ) - m_aFilterComponents.begin();
1512 aEvent.DisjunctiveTerm = getActiveTerm();
1513 aEvent.PredicateExpression = aText;
1515 aGuard.clear();
1516 // <-- SYNCHRONIZED
1518 // notify the changed filter expression
1519 m_aFilterListeners.notifyEach( &XFilterControllerListener::predicateExpressionChanged, aEvent );
1522 // XItemListener
1524 void SAL_CALL FormController::itemStateChanged(const ItemEvent& /*rEvent*/) throw( RuntimeException, std::exception )
1526 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1527 impl_onModify();
1530 // XModificationBroadcaster
1532 void SAL_CALL FormController::addModifyListener(const Reference< XModifyListener > & l) throw( RuntimeException, std::exception )
1534 ::osl::MutexGuard aGuard( m_aMutex );
1535 impl_checkDisposed_throw();
1536 m_aModifyListeners.addInterface( l );
1540 void FormController::removeModifyListener(const Reference< XModifyListener > & l) throw( RuntimeException, std::exception )
1542 ::osl::MutexGuard aGuard( m_aMutex );
1543 impl_checkDisposed_throw();
1544 m_aModifyListeners.removeInterface( l );
1547 // XModificationListener
1549 void FormController::modified( const EventObject& _rEvent ) throw( RuntimeException, std::exception )
1551 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1555 if ( _rEvent.Source != m_xActiveControl )
1556 { // let this control grab the focus
1557 // (this case may happen if somebody moves the scroll wheel of the mouse over a control
1558 // which does not have the focus)
1559 // 85511 - 29.05.2001 - frank.schoenheit@germany.sun.com
1561 // also, it happens when an image control gets a new image by double-clicking it
1562 // #i88458# / 2009-01-12 / frank.schoenheit@sun.com
1563 Reference< XWindow > xControlWindow( _rEvent.Source, UNO_QUERY_THROW );
1564 xControlWindow->setFocus();
1567 catch( const Exception& )
1569 DBG_UNHANDLED_EXCEPTION();
1572 impl_onModify();
1576 void FormController::impl_checkDisposed_throw() const
1578 if ( impl_isDisposed_nofail() )
1579 throw DisposedException( OUString(), *const_cast< FormController* >( this ) );
1583 void FormController::impl_onModify()
1585 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1588 ::osl::MutexGuard aGuard( m_aMutex );
1589 if ( !m_bModified )
1590 m_bModified = true;
1593 EventObject aEvt(static_cast<cppu::OWeakObject*>(this));
1594 m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvt );
1598 void FormController::impl_addFilterRow( const FmFilterRow& _row )
1600 m_aFilterRows.push_back( _row );
1602 if ( m_aFilterRows.size() == 1 )
1603 { // that's the first row ever
1604 OSL_ENSURE( m_nCurrentFilterPosition == -1, "FormController::impl_addFilterRow: inconsistency!" );
1605 m_nCurrentFilterPosition = 0;
1610 void FormController::impl_appendEmptyFilterRow( ::osl::ClearableMutexGuard& _rClearBeforeNotify )
1612 // SYNCHRONIZED -->
1613 impl_addFilterRow( FmFilterRow() );
1615 // notify the listeners
1616 FilterEvent aEvent;
1617 aEvent.Source = *this;
1618 aEvent.DisjunctiveTerm = (sal_Int32)m_aFilterRows.size() - 1;
1619 _rClearBeforeNotify.clear();
1620 // <-- SYNCHRONIZED
1621 m_aFilterListeners.notifyEach( &XFilterControllerListener::disjunctiveTermAdded, aEvent );
1625 bool FormController::determineLockState() const
1627 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1628 // a.) in filter mode we are always locked
1629 // b.) if we have no valid model or our model (a result set) is not alive -> we're locked
1630 // c.) if we are inserting everything is OK and we are not locked
1631 // d.) if are not updatable or on invalid position
1632 Reference< XResultSet > xResultSet(m_xModelAsIndex, UNO_QUERY);
1633 if (m_bFiltering || !xResultSet.is() || !isRowSetAlive(xResultSet))
1634 return true;
1635 else
1636 return (m_bCanInsert && m_bCurrentRecordNew) ? sal_False
1637 : xResultSet->isBeforeFirst() || xResultSet->isAfterLast() || xResultSet->rowDeleted() || !m_bCanUpdate;
1640 // FocusListener
1642 void FormController::focusGained(const FocusEvent& e) throw( RuntimeException, std::exception )
1644 // SYNCHRONIZED -->
1645 ::osl::ClearableMutexGuard aGuard( m_aMutex );
1646 impl_checkDisposed_throw();
1648 m_pControlBorderManager->focusGained( e.Source );
1650 Reference< XControl > xControl(e.Source, UNO_QUERY);
1651 if (m_bDBConnection)
1653 // do we need to keep the locking of the commit
1654 // we hold the lock as long as the control differs from the current
1655 // otherwise we disabled the lock
1656 m_bCommitLock = m_bCommitLock && (XControl*)xControl.get() != (XControl*)m_xCurrentControl.get();
1657 if (m_bCommitLock)
1658 return;
1660 // when do we have to commit a value to form or a filter
1661 // a.) if the current value is modified
1662 // b.) there must be a current control
1663 // c.) and it must be different from the new focus owning control or
1664 // d.) the focus is moving around (so we have only one control)
1666 if ( ( m_bModified || m_bFiltering )
1667 && m_xCurrentControl.is()
1668 && ( ( xControl.get() != m_xCurrentControl.get() )
1669 || ( ( e.FocusFlags & FocusChangeReason::AROUND )
1670 && ( m_bCycle || m_bFiltering )
1675 // check the old control if the content is ok
1676 #if OSL_DEBUG_LEVEL > 1
1677 Reference< XBoundControl > xLockingTest(m_xCurrentControl, UNO_QUERY);
1678 sal_Bool bControlIsLocked = xLockingTest.is() && xLockingTest->getLock();
1679 OSL_ENSURE(!bControlIsLocked, "FormController::Gained: I'm modified and the current control is locked ? How this ?");
1680 // normalerweise sollte ein gelocktes Control nicht modified sein, also muss wohl mein bModified aus einem anderen Kontext
1681 // gesetzt worden sein, was ich nicht verstehen wuerde ...
1682 #endif
1683 DBG_ASSERT(m_xCurrentControl.is(), "kein CurrentControl gesetzt");
1684 // zunaechst das Control fragen ob es das IFace unterstuetzt
1685 Reference< XBoundComponent > xBound(m_xCurrentControl, UNO_QUERY);
1686 if (!xBound.is() && m_xCurrentControl.is())
1687 xBound = Reference< XBoundComponent > (m_xCurrentControl->getModel(), UNO_QUERY);
1689 // lock if we lose the focus during commit
1690 m_bCommitLock = true;
1692 // Commit nicht erfolgreich, Focus zuruecksetzen
1693 if (xBound.is() && !xBound->commit())
1695 // the commit failed and we don't commit again until the current control
1696 // which couldn't be commit gains the focus again
1697 Reference< XWindow > xWindow(m_xCurrentControl, UNO_QUERY);
1698 if (xWindow.is())
1699 xWindow->setFocus();
1700 return;
1702 else
1704 m_bModified = false;
1705 m_bCommitLock = false;
1709 if (!m_bFiltering && m_bCycle && (e.FocusFlags & FocusChangeReason::AROUND) && m_xCurrentControl.is())
1711 SQLErrorEvent aErrorEvent;
1712 OSL_ENSURE( m_xFormOperations.is(), "FormController::focusGained: hmm?" );
1713 // should have been created in setModel
1716 if ( e.FocusFlags & FocusChangeReason::FORWARD )
1718 if ( m_xFormOperations.is() && m_xFormOperations->isEnabled( FormFeature::MoveToNext ) )
1719 m_xFormOperations->execute( FormFeature::MoveToNext );
1721 else // backward
1723 if ( m_xFormOperations.is() && m_xFormOperations->isEnabled( FormFeature::MoveToPrevious ) )
1724 m_xFormOperations->execute( FormFeature::MoveToPrevious );
1727 catch ( const Exception& )
1729 // don't handle this any further. That's an ... admissible error.
1730 DBG_UNHANDLED_EXCEPTION();
1735 // Immer noch ein und dasselbe Control
1736 if ( ( m_xActiveControl == xControl )
1737 && ( xControl == m_xCurrentControl )
1740 DBG_ASSERT(m_xCurrentControl.is(), "Kein CurrentControl selektiert");
1741 return;
1744 bool bActivated = !m_xActiveControl.is() && xControl.is();
1746 m_xActiveControl = xControl;
1748 implSetCurrentControl( xControl );
1749 SAL_WARN_IF( !m_xCurrentControl.is(), "svx.form", "implSetCurrentControl did nonsense!" );
1751 if ( bActivated )
1753 // (asynchronously) call activation handlers
1754 m_aActivationEvent.Call();
1756 // call modify listeners
1757 if ( m_bModified )
1758 m_aModifyListeners.notifyEach( &XModifyListener::modified, EventObject( *this ) );
1761 // invalidate all features which depend on the currently focused control
1762 if ( m_bDBConnection && !m_bFiltering )
1763 implInvalidateCurrentControlDependentFeatures();
1765 if ( !m_xCurrentControl.is() )
1766 return;
1768 // Control erhaelt Focus, dann eventuell in den sichtbaren Bereich
1769 Reference< XFormControllerContext > xContext( m_xFormControllerContext );
1770 Reference< XControl > xCurrentControl( m_xCurrentControl );
1771 aGuard.clear();
1772 // <-- SYNCHRONIZED
1774 if ( xContext.is() )
1775 xContext->makeVisible( xCurrentControl );
1779 IMPL_LINK( FormController, OnActivated, void*, /**/ )
1781 EventObject aEvent;
1782 aEvent.Source = *this;
1783 m_aActivateListeners.notifyEach( &XFormControllerListener::formActivated, aEvent );
1785 return 0L;
1789 IMPL_LINK( FormController, OnDeactivated, void*, /**/ )
1791 EventObject aEvent;
1792 aEvent.Source = *this;
1793 m_aActivateListeners.notifyEach( &XFormControllerListener::formDeactivated, aEvent );
1795 return 0L;
1799 void FormController::focusLost(const FocusEvent& e) throw( RuntimeException, std::exception )
1801 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1803 m_pControlBorderManager->focusLost( e.Source );
1805 Reference< XControl > xControl(e.Source, UNO_QUERY);
1806 Reference< XWindowPeer > xNext(e.NextFocus, UNO_QUERY);
1807 Reference< XControl > xNextControl = isInList(xNext);
1808 if (!xNextControl.is())
1810 m_xActiveControl = NULL;
1811 m_aDeactivationEvent.Call();
1816 void SAL_CALL FormController::mousePressed( const awt::MouseEvent& /*_rEvent*/ ) throw (RuntimeException, std::exception)
1818 // not interested in
1822 void SAL_CALL FormController::mouseReleased( const awt::MouseEvent& /*_rEvent*/ ) throw (RuntimeException, std::exception)
1824 // not interested in
1828 void SAL_CALL FormController::mouseEntered( const awt::MouseEvent& _rEvent ) throw (RuntimeException, std::exception)
1830 m_pControlBorderManager->mouseEntered( _rEvent.Source );
1834 void SAL_CALL FormController::mouseExited( const awt::MouseEvent& _rEvent ) throw (RuntimeException, std::exception)
1836 m_pControlBorderManager->mouseExited( _rEvent.Source );
1840 void SAL_CALL FormController::componentValidityChanged( const EventObject& _rSource ) throw (RuntimeException, std::exception)
1842 Reference< XControl > xControl( findControl( m_aControls, Reference< XControlModel >( _rSource.Source, UNO_QUERY ), false, false ) );
1843 Reference< XValidatableFormComponent > xValidatable( _rSource.Source, UNO_QUERY );
1845 OSL_ENSURE( xControl.is() && xValidatable.is(), "FormController::componentValidityChanged: huh?" );
1847 if ( xControl.is() && xValidatable.is() )
1848 m_pControlBorderManager->validityChanged( xControl, xValidatable );
1852 void FormController::setModel(const Reference< XTabControllerModel > & Model) throw( RuntimeException, std::exception )
1854 ::osl::MutexGuard aGuard( m_aMutex );
1855 impl_checkDisposed_throw();
1857 DBG_ASSERT(m_xTabController.is(), "FormController::setModel : invalid aggregate !");
1861 // disconnect from the old model
1862 if (m_xModelAsIndex.is())
1864 if (m_bDBConnection)
1866 // we are currently working on the model
1867 EventObject aEvt(m_xModelAsIndex);
1868 unloaded(aEvt);
1871 Reference< XLoadable > xForm(m_xModelAsIndex, UNO_QUERY);
1872 if (xForm.is())
1873 xForm->removeLoadListener(this);
1875 Reference< XSQLErrorBroadcaster > xBroadcaster(m_xModelAsIndex, UNO_QUERY);
1876 if (xBroadcaster.is())
1877 xBroadcaster->removeSQLErrorListener(this);
1879 Reference< XDatabaseParameterBroadcaster > xParamBroadcaster(m_xModelAsIndex, UNO_QUERY);
1880 if (xParamBroadcaster.is())
1881 xParamBroadcaster->removeParameterListener(this);
1885 disposeAllFeaturesAndDispatchers();
1887 if ( m_xFormOperations.is() )
1888 m_xFormOperations->dispose();
1889 m_xFormOperations.clear();
1891 // set the new model wait for the load event
1892 if (m_xTabController.is())
1893 m_xTabController->setModel(Model);
1894 m_xModelAsIndex = Reference< XIndexAccess > (Model, UNO_QUERY);
1895 m_xModelAsManager = Reference< XEventAttacherManager > (Model, UNO_QUERY);
1897 // only if both ifaces exit, the controller will work successful
1898 if (!m_xModelAsIndex.is() || !m_xModelAsManager.is())
1900 m_xModelAsManager = NULL;
1901 m_xModelAsIndex = NULL;
1904 if (m_xModelAsIndex.is())
1906 // re-create m_xFormOperations
1907 m_xFormOperations = FormOperations::createWithFormController( m_xComponentContext, this );
1908 m_xFormOperations->setFeatureInvalidation( this );
1910 // adding load and ui interaction listeners
1911 Reference< XLoadable > xForm(Model, UNO_QUERY);
1912 if (xForm.is())
1913 xForm->addLoadListener(this);
1915 Reference< XSQLErrorBroadcaster > xBroadcaster(Model, UNO_QUERY);
1916 if (xBroadcaster.is())
1917 xBroadcaster->addSQLErrorListener(this);
1919 Reference< XDatabaseParameterBroadcaster > xParamBroadcaster(Model, UNO_QUERY);
1920 if (xParamBroadcaster.is())
1921 xParamBroadcaster->addParameterListener(this);
1923 // well, is the database already loaded?
1924 // then we have to simulate a load event
1925 Reference< XLoadable > xCursor(m_xModelAsIndex, UNO_QUERY);
1926 if (xCursor.is() && xCursor->isLoaded())
1928 EventObject aEvt(xCursor);
1929 loaded(aEvt);
1932 Reference< XPropertySet > xModelProps( m_xModelAsIndex, UNO_QUERY );
1933 Reference< XPropertySetInfo > xPropInfo( xModelProps->getPropertySetInfo() );
1934 if ( xPropInfo.is()
1935 && xPropInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER )
1936 && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_FOCUS )
1937 && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_MOUSE )
1938 && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_INVALID )
1941 bool bEnableDynamicControlBorder = lcl_shouldUseDynamicControlBorder(
1942 xModelProps.get(), xModelProps->getPropertyValue( FM_PROP_DYNAMIC_CONTROL_BORDER ) );
1943 if ( bEnableDynamicControlBorder )
1944 m_pControlBorderManager->enableDynamicBorderColor();
1945 else
1946 m_pControlBorderManager->disableDynamicBorderColor();
1948 sal_Int32 nColor = 0;
1949 if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_FOCUS ) >>= nColor )
1950 m_pControlBorderManager->setStatusColor( CONTROL_STATUS_FOCUSED, nColor );
1951 if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_MOUSE ) >>= nColor )
1952 m_pControlBorderManager->setStatusColor( CONTROL_STATUS_MOUSE_HOVER, nColor );
1953 if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_INVALID ) >>= nColor )
1954 m_pControlBorderManager->setStatusColor( CONTROL_STATUS_INVALID, nColor );
1958 catch( const Exception& )
1960 DBG_UNHANDLED_EXCEPTION();
1965 Reference< XTabControllerModel > FormController::getModel() throw( RuntimeException, std::exception )
1967 ::osl::MutexGuard aGuard( m_aMutex );
1968 impl_checkDisposed_throw();
1970 DBG_ASSERT(m_xTabController.is(), "FormController::getModel : invalid aggregate !");
1971 if (!m_xTabController.is())
1972 return Reference< XTabControllerModel > ();
1973 return m_xTabController->getModel();
1977 void FormController::addToEventAttacher(const Reference< XControl > & xControl)
1979 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
1980 OSL_ENSURE( xControl.is(), "FormController::addToEventAttacher: invalid control - how did you reach this?" );
1981 if ( !xControl.is() )
1982 return; /* throw IllegalArgumentException(); */
1984 // anmelden beim Eventattacher
1985 Reference< XFormComponent > xComp(xControl->getModel(), UNO_QUERY);
1986 if (xComp.is() && m_xModelAsIndex.is())
1988 // Und die Position des ControlModel darin suchen
1989 sal_uInt32 nPos = m_xModelAsIndex->getCount();
1990 Reference< XFormComponent > xTemp;
1991 for( ; nPos; )
1993 m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
1994 if ((XFormComponent*)xComp.get() == (XFormComponent*)xTemp.get())
1996 m_xModelAsManager->attach( nPos, xControl, makeAny(xControl) );
1997 break;
2004 void FormController::removeFromEventAttacher(const Reference< XControl > & xControl)
2006 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2007 OSL_ENSURE( xControl.is(), "FormController::removeFromEventAttacher: invalid control - how did you reach this?" );
2008 if ( !xControl.is() )
2009 return; /* throw IllegalArgumentException(); */
2011 // abmelden beim Eventattacher
2012 Reference< XFormComponent > xComp(xControl->getModel(), UNO_QUERY);
2013 if ( xComp.is() && m_xModelAsIndex.is() )
2015 // Und die Position des ControlModel darin suchen
2016 sal_uInt32 nPos = m_xModelAsIndex->getCount();
2017 Reference< XFormComponent > xTemp;
2018 for( ; nPos; )
2020 m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
2021 if ((XFormComponent*)xComp.get() == (XFormComponent*)xTemp.get())
2023 m_xModelAsManager->detach( nPos, xControl );
2024 break;
2031 void FormController::setContainer(const Reference< XControlContainer > & xContainer) throw( RuntimeException, std::exception )
2033 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2034 Reference< XTabControllerModel > xTabModel(getModel());
2035 DBG_ASSERT(xTabModel.is() || !xContainer.is(), "No Model defined");
2036 // if we have a new container we need a model
2037 DBG_ASSERT(m_xTabController.is(), "FormController::setContainer : invalid aggregate !");
2039 ::osl::MutexGuard aGuard( m_aMutex );
2040 Reference< XContainer > xCurrentContainer;
2041 if (m_xTabController.is())
2042 xCurrentContainer = Reference< XContainer > (m_xTabController->getContainer(), UNO_QUERY);
2043 if (xCurrentContainer.is())
2045 xCurrentContainer->removeContainerListener(this);
2047 if ( m_aTabActivationTimer.IsActive() )
2048 m_aTabActivationTimer.Stop();
2050 // clear the filter map
2051 ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), RemoveComponentTextListener( this ) );
2052 m_aFilterComponents.clear();
2054 // einsammeln der Controls
2055 const Reference< XControl >* pControls = m_aControls.getConstArray();
2056 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2057 while ( pControls != pControlsEnd )
2058 implControlRemoved( *pControls++, true );
2060 // Datenbank spezifische Dinge vornehmen
2061 if (m_bDBConnection && isListeningForChanges())
2062 stopListening();
2064 m_aControls.realloc( 0 );
2067 if (m_xTabController.is())
2068 m_xTabController->setContainer(xContainer);
2070 // Welche Controls gehoeren zum Container ?
2071 if (xContainer.is() && xTabModel.is())
2073 Sequence< Reference< XControlModel > > aModels = xTabModel->getControlModels();
2074 const Reference< XControlModel > * pModels = aModels.getConstArray();
2075 Sequence< Reference< XControl > > aAllControls = xContainer->getControls();
2077 sal_Int32 nCount = aModels.getLength();
2078 m_aControls = Sequence< Reference< XControl > >( nCount );
2079 Reference< XControl > * pControls = m_aControls.getArray();
2081 // einsammeln der Controls
2082 sal_Int32 i, j;
2083 for (i = 0, j = 0; i < nCount; ++i, ++pModels )
2085 Reference< XControl > xControl = findControl( aAllControls, *pModels, false, true );
2086 if ( xControl.is() )
2088 pControls[j++] = xControl;
2089 implControlInserted( xControl, true );
2093 // not every model had an associated control
2094 if (j != i)
2095 m_aControls.realloc(j);
2097 // am Container horchen
2098 Reference< XContainer > xNewContainer(xContainer, UNO_QUERY);
2099 if (xNewContainer.is())
2100 xNewContainer->addContainerListener(this);
2102 // Datenbank spezifische Dinge vornehmen
2103 if (m_bDBConnection)
2105 m_bLocked = determineLockState();
2106 setLocks();
2107 if (!isLocked())
2108 startListening();
2111 // befinden sich die Controls in der richtigen Reihenfolge
2112 m_bControlsSorted = true;
2116 Reference< XControlContainer > FormController::getContainer() throw( RuntimeException, std::exception )
2118 ::osl::MutexGuard aGuard( m_aMutex );
2119 impl_checkDisposed_throw();
2121 DBG_ASSERT(m_xTabController.is(), "FormController::getContainer : invalid aggregate !");
2122 if (!m_xTabController.is())
2123 return Reference< XControlContainer > ();
2124 return m_xTabController->getContainer();
2128 Sequence< Reference< XControl > > FormController::getControls(void) throw( RuntimeException, std::exception )
2130 ::osl::MutexGuard aGuard( m_aMutex );
2131 impl_checkDisposed_throw();
2133 if (!m_bControlsSorted)
2135 Reference< XTabControllerModel > xModel = getModel();
2136 if (!xModel.is())
2137 return m_aControls;
2139 Sequence< Reference< XControlModel > > aControlModels = xModel->getControlModels();
2140 const Reference< XControlModel > * pModels = aControlModels.getConstArray();
2141 sal_Int32 nModels = aControlModels.getLength();
2143 Sequence< Reference< XControl > > aNewControls(nModels);
2145 Reference< XControl > * pControls = aNewControls.getArray();
2146 Reference< XControl > xControl;
2148 // Umsortieren der Controls entsprechend der TabReihenfolge
2149 sal_Int32 j = 0;
2150 for (sal_Int32 i = 0; i < nModels; ++i, ++pModels )
2152 xControl = findControl( m_aControls, *pModels, true, true );
2153 if ( xControl.is() )
2154 pControls[j++] = xControl;
2157 // not every model had an associated control
2158 if ( j != nModels )
2159 aNewControls.realloc( j );
2161 m_aControls = aNewControls;
2162 m_bControlsSorted = true;
2164 return m_aControls;
2168 void FormController::autoTabOrder() throw( RuntimeException, std::exception )
2170 ::osl::MutexGuard aGuard( m_aMutex );
2171 impl_checkDisposed_throw();
2173 DBG_ASSERT(m_xTabController.is(), "FormController::autoTabOrder : invalid aggregate !");
2174 if (m_xTabController.is())
2175 m_xTabController->autoTabOrder();
2179 void FormController::activateTabOrder() throw( RuntimeException, std::exception )
2181 ::osl::MutexGuard aGuard( m_aMutex );
2182 impl_checkDisposed_throw();
2184 DBG_ASSERT(m_xTabController.is(), "FormController::activateTabOrder : invalid aggregate !");
2185 if (m_xTabController.is())
2186 m_xTabController->activateTabOrder();
2190 void FormController::setControlLock(const Reference< XControl > & xControl)
2192 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2193 bool bLocked = isLocked();
2195 // es wird gelockt
2196 // a.) wenn der ganze Datensatz gesperrt ist
2197 // b.) wenn das zugehoerige Feld gespeert ist
2198 Reference< XBoundControl > xBound(xControl, UNO_QUERY);
2199 if (xBound.is() && (( (bLocked && (bLocked ? 1 : 0) != xBound->getLock()) ||
2200 !bLocked))) // beim entlocken immer einzelne Felder ueberprüfen
2202 // gibt es eine Datenquelle
2203 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
2204 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
2206 // wie sieht mit den Properties ReadOnly und Enable aus
2207 bool bTouch = true;
2208 if (::comphelper::hasProperty(FM_PROP_ENABLED, xSet))
2209 bTouch = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ENABLED));
2210 if (::comphelper::hasProperty(FM_PROP_READONLY, xSet))
2211 bTouch = !::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_READONLY));
2213 if (bTouch)
2215 Reference< XPropertySet > xField;
2216 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
2217 if (xField.is())
2219 if (bLocked)
2220 xBound->setLock(bLocked);
2221 else
2225 Any aVal = xField->getPropertyValue(FM_PROP_ISREADONLY);
2226 if (aVal.hasValue() && ::comphelper::getBOOL(aVal))
2227 xBound->setLock(sal_True);
2228 else
2229 xBound->setLock(bLocked);
2231 catch( const Exception& )
2233 DBG_UNHANDLED_EXCEPTION();
2244 void FormController::setLocks()
2246 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2247 // alle Controls, die mit einer Datenquelle verbunden sind locken/unlocken
2248 const Reference< XControl >* pControls = m_aControls.getConstArray();
2249 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2250 while ( pControls != pControlsEnd )
2251 setControlLock( *pControls++ );
2255 namespace
2257 bool lcl_shouldListenForModifications( const Reference< XControl >& _rxControl, const Reference< XPropertyChangeListener >& _rxBoundFieldListener )
2259 bool bShould = false;
2261 Reference< XBoundComponent > xBound( _rxControl, UNO_QUERY );
2262 if ( xBound.is() )
2264 bShould = true;
2266 else if ( _rxControl.is() )
2268 Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY );
2269 if ( xModelProps.is() && ::comphelper::hasProperty( FM_PROP_BOUNDFIELD, xModelProps ) )
2271 Reference< XPropertySet > xField;
2272 xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField;
2273 bShould = xField.is();
2275 if ( !bShould && _rxBoundFieldListener.is() )
2276 xModelProps->addPropertyChangeListener( FM_PROP_BOUNDFIELD, _rxBoundFieldListener );
2280 return bShould;
2285 void FormController::startControlModifyListening(const Reference< XControl > & xControl)
2287 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2289 bool bModifyListening = lcl_shouldListenForModifications( xControl, this );
2291 // artificial while
2292 while ( bModifyListening )
2294 Reference< XModifyBroadcaster > xMod(xControl, UNO_QUERY);
2295 if (xMod.is())
2297 xMod->addModifyListener(this);
2298 break;
2301 // alle die Text um vorzeitig ein modified zu erkennen
2302 Reference< XTextComponent > xText(xControl, UNO_QUERY);
2303 if (xText.is())
2305 xText->addTextListener(this);
2306 break;
2309 Reference< XCheckBox > xBox(xControl, UNO_QUERY);
2310 if (xBox.is())
2312 xBox->addItemListener(this);
2313 break;
2316 Reference< XComboBox > xCbBox(xControl, UNO_QUERY);
2317 if (xCbBox.is())
2319 xCbBox->addItemListener(this);
2320 break;
2323 Reference< XListBox > xListBox(xControl, UNO_QUERY);
2324 if (xListBox.is())
2326 xListBox->addItemListener(this);
2327 break;
2329 break;
2334 void FormController::stopControlModifyListening(const Reference< XControl > & xControl)
2336 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2338 bool bModifyListening = lcl_shouldListenForModifications( xControl, NULL );
2340 // kuenstliches while
2341 while (bModifyListening)
2343 Reference< XModifyBroadcaster > xMod(xControl, UNO_QUERY);
2344 if (xMod.is())
2346 xMod->removeModifyListener(this);
2347 break;
2349 // alle die Text um vorzeitig ein modified zu erkennen
2350 Reference< XTextComponent > xText(xControl, UNO_QUERY);
2351 if (xText.is())
2353 xText->removeTextListener(this);
2354 break;
2357 Reference< XCheckBox > xBox(xControl, UNO_QUERY);
2358 if (xBox.is())
2360 xBox->removeItemListener(this);
2361 break;
2364 Reference< XComboBox > xCbBox(xControl, UNO_QUERY);
2365 if (xCbBox.is())
2367 xCbBox->removeItemListener(this);
2368 break;
2371 Reference< XListBox > xListBox(xControl, UNO_QUERY);
2372 if (xListBox.is())
2374 xListBox->removeItemListener(this);
2375 break;
2377 break;
2382 void FormController::startListening()
2384 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2385 m_bModified = false;
2387 // jetzt anmelden bei gebundenen feldern
2388 const Reference< XControl >* pControls = m_aControls.getConstArray();
2389 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2390 while ( pControls != pControlsEnd )
2391 startControlModifyListening( *pControls++ );
2395 void FormController::stopListening()
2397 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2398 m_bModified = false;
2400 // jetzt anmelden bei gebundenen feldern
2401 const Reference< XControl >* pControls = m_aControls.getConstArray();
2402 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2403 while ( pControls != pControlsEnd )
2404 stopControlModifyListening( *pControls++ );
2409 Reference< XControl > FormController::findControl(Sequence< Reference< XControl > >& _rControls, const Reference< XControlModel > & xCtrlModel ,bool _bRemove,bool _bOverWrite) const
2411 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2412 DBG_ASSERT( xCtrlModel.is(), "findControl - welches ?!" );
2414 Reference< XControl >* pControls = _rControls.getArray();
2415 Reference< XControlModel > xModel;
2416 for ( sal_Int32 i = 0, nCount = _rControls.getLength(); i < nCount; ++i, ++pControls )
2418 if ( pControls->is() )
2420 xModel = (*pControls)->getModel();
2421 if ( xModel.get() == xCtrlModel.get() )
2423 Reference< XControl > xControl( *pControls );
2424 if ( _bRemove )
2425 ::comphelper::removeElementAt( _rControls, i );
2426 else if ( _bOverWrite )
2427 pControls->clear();
2428 return xControl;
2432 return Reference< XControl > ();
2436 void FormController::implControlInserted( const Reference< XControl>& _rxControl, bool _bAddToEventAttacher )
2438 Reference< XWindow > xWindow( _rxControl, UNO_QUERY );
2439 if ( xWindow.is() )
2441 xWindow->addFocusListener( this );
2442 xWindow->addMouseListener( this );
2444 if ( _bAddToEventAttacher )
2445 addToEventAttacher( _rxControl );
2448 // add a dispatch interceptor to the control (if supported)
2449 Reference< XDispatchProviderInterception > xInterception( _rxControl, UNO_QUERY );
2450 if ( xInterception.is() )
2451 createInterceptor( xInterception );
2453 if ( _rxControl.is() )
2455 Reference< XControlModel > xModel( _rxControl->getModel() );
2457 // we want to know about the reset of the model of our controls
2458 // (for correctly resetting m_bModified)
2459 Reference< XReset > xReset( xModel, UNO_QUERY );
2460 if ( xReset.is() )
2461 xReset->addResetListener( this );
2463 // and we want to know about the validity, to visually indicate it
2464 Reference< XValidatableFormComponent > xValidatable( xModel, UNO_QUERY );
2465 if ( xValidatable.is() )
2467 xValidatable->addFormComponentValidityListener( this );
2468 m_pControlBorderManager->validityChanged( _rxControl, xValidatable );
2475 void FormController::implControlRemoved( const Reference< XControl>& _rxControl, bool _bRemoveFromEventAttacher )
2477 Reference< XWindow > xWindow( _rxControl, UNO_QUERY );
2478 if ( xWindow.is() )
2480 xWindow->removeFocusListener( this );
2481 xWindow->removeMouseListener( this );
2483 if ( _bRemoveFromEventAttacher )
2484 removeFromEventAttacher( _rxControl );
2487 Reference< XDispatchProviderInterception > xInterception( _rxControl, UNO_QUERY);
2488 if ( xInterception.is() )
2489 deleteInterceptor( xInterception );
2491 if ( _rxControl.is() )
2493 Reference< XControlModel > xModel( _rxControl->getModel() );
2495 Reference< XReset > xReset( xModel, UNO_QUERY );
2496 if ( xReset.is() )
2497 xReset->removeResetListener( this );
2499 Reference< XValidatableFormComponent > xValidatable( xModel, UNO_QUERY );
2500 if ( xValidatable.is() )
2501 xValidatable->removeFormComponentValidityListener( this );
2506 void FormController::implSetCurrentControl( const Reference< XControl >& _rxControl )
2508 if ( m_xCurrentControl.get() == _rxControl.get() )
2509 return;
2511 Reference< XGridControl > xGridControl( m_xCurrentControl, UNO_QUERY );
2512 if ( xGridControl.is() )
2513 xGridControl->removeGridControlListener( this );
2515 m_xCurrentControl = _rxControl;
2517 xGridControl.set( m_xCurrentControl, UNO_QUERY );
2518 if ( xGridControl.is() )
2519 xGridControl->addGridControlListener( this );
2523 void FormController::insertControl(const Reference< XControl > & xControl)
2525 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2526 m_bControlsSorted = false;
2527 m_aControls.realloc(m_aControls.getLength() + 1);
2528 m_aControls.getArray()[m_aControls.getLength() - 1] = xControl;
2530 if ( m_pColumnInfoCache.get() )
2531 m_pColumnInfoCache->deinitializeControls();
2533 implControlInserted( xControl, m_bAttachEvents );
2535 if (m_bDBConnection && !m_bFiltering)
2536 setControlLock(xControl);
2538 if (isListeningForChanges() && m_bAttachEvents)
2539 startControlModifyListening( xControl );
2543 void FormController::removeControl(const Reference< XControl > & xControl)
2545 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2546 const Reference< XControl >* pControls = m_aControls.getConstArray();
2547 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2548 while ( pControls != pControlsEnd )
2550 if ( xControl.get() == (*pControls++).get() )
2552 ::comphelper::removeElementAt( m_aControls, pControls - m_aControls.getConstArray() - 1 );
2553 break;
2557 FilterComponents::iterator componentPos = ::std::find( m_aFilterComponents.begin(), m_aFilterComponents.end(), xControl );
2558 if ( componentPos != m_aFilterComponents.end() )
2559 m_aFilterComponents.erase( componentPos );
2561 implControlRemoved( xControl, m_bDetachEvents );
2563 if ( isListeningForChanges() && m_bDetachEvents )
2564 stopControlModifyListening( xControl );
2567 // XLoadListener
2569 void FormController::loaded(const EventObject& rEvent) throw( RuntimeException, std::exception )
2571 OSL_ENSURE( rEvent.Source == m_xModelAsIndex, "FormController::loaded: where did this come from?" );
2573 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2574 ::osl::MutexGuard aGuard( m_aMutex );
2575 Reference< XRowSet > xForm(rEvent.Source, UNO_QUERY);
2576 // do we have a connected data source
2577 OStaticDataAccessTools aStaticTools;
2578 if (xForm.is() && aStaticTools.getRowSetConnection(xForm).is())
2580 Reference< XPropertySet > xSet(xForm, UNO_QUERY);
2581 if (xSet.is())
2583 Any aVal = xSet->getPropertyValue(FM_PROP_CYCLE);
2584 sal_Int32 aVal2 = 0;
2585 ::cppu::enum2int(aVal2,aVal);
2586 m_bCycle = !aVal.hasValue() || aVal2 == TabulatorCycle_RECORDS;
2587 m_bCanUpdate = aStaticTools.canUpdate(xSet);
2588 m_bCanInsert = aStaticTools.canInsert(xSet);
2589 m_bCurrentRecordModified = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED));
2590 m_bCurrentRecordNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
2592 startFormListening( xSet, false );
2594 // set the locks for the current controls
2595 if (getContainer().is())
2597 m_aLoadEvent.Call();
2600 else
2602 m_bCanInsert = m_bCanUpdate = m_bCycle = false;
2603 m_bCurrentRecordModified = false;
2604 m_bCurrentRecordNew = false;
2605 m_bLocked = false;
2607 m_bDBConnection = true;
2609 else
2611 m_bDBConnection = false;
2612 m_bCanInsert = m_bCanUpdate = m_bCycle = false;
2613 m_bCurrentRecordModified = false;
2614 m_bCurrentRecordNew = false;
2615 m_bLocked = false;
2618 Reference< XColumnsSupplier > xFormColumns( xForm, UNO_QUERY );
2619 m_pColumnInfoCache.reset( xFormColumns.is() ? new ColumnInfoCache( xFormColumns ) : NULL );
2621 updateAllDispatchers();
2625 void FormController::updateAllDispatchers() const
2627 ::std::for_each(
2628 m_aFeatureDispatchers.begin(),
2629 m_aFeatureDispatchers.end(),
2630 ::o3tl::compose1(
2631 UpdateAllListeners(),
2632 ::o3tl::select2nd< DispatcherContainer::value_type >()
2638 IMPL_LINK_NOARG(FormController, OnLoad)
2640 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2641 m_bLocked = determineLockState();
2643 setLocks();
2645 if (!m_bLocked)
2646 startListening();
2648 // just one exception toggle the auto values
2649 if (m_bCurrentRecordNew)
2650 toggleAutoFields(true);
2652 return 1L;
2656 void FormController::unloaded(const EventObject& /*rEvent*/) throw( RuntimeException, std::exception )
2658 ::osl::MutexGuard aGuard( m_aMutex );
2659 impl_checkDisposed_throw();
2661 updateAllDispatchers();
2665 void FormController::reloading(const EventObject& /*aEvent*/) throw( RuntimeException, std::exception )
2667 ::osl::MutexGuard aGuard( m_aMutex );
2668 impl_checkDisposed_throw();
2670 // do the same like in unloading
2671 // just one exception toggle the auto values
2672 m_aToggleEvent.CancelPendingCall();
2673 unload();
2677 void FormController::reloaded(const EventObject& aEvent) throw( RuntimeException, std::exception )
2679 ::osl::MutexGuard aGuard( m_aMutex );
2680 impl_checkDisposed_throw();
2682 loaded(aEvent);
2686 void FormController::unloading(const EventObject& /*aEvent*/) throw( RuntimeException, std::exception )
2688 ::osl::MutexGuard aGuard( m_aMutex );
2689 impl_checkDisposed_throw();
2691 unload();
2695 void FormController::unload() throw( RuntimeException )
2697 ::osl::MutexGuard aGuard( m_aMutex );
2698 impl_checkDisposed_throw();
2700 m_aLoadEvent.CancelPendingCall();
2702 // be sure not to have autofields
2703 if (m_bCurrentRecordNew)
2704 toggleAutoFields(false);
2706 // remove bound field listing again
2707 removeBoundFieldListener();
2709 if (m_bDBConnection && isListeningForChanges())
2710 stopListening();
2712 Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
2713 if ( m_bDBConnection && xSet.is() )
2714 stopFormListening( xSet, false );
2716 m_bDBConnection = false;
2717 m_bCanInsert = m_bCanUpdate = m_bCycle = false;
2718 m_bCurrentRecordModified = m_bCurrentRecordNew = m_bLocked = false;
2720 m_pColumnInfoCache.reset();
2724 void FormController::removeBoundFieldListener()
2726 const Reference< XControl >* pControls = m_aControls.getConstArray();
2727 const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
2728 while ( pControls != pControlsEnd )
2730 Reference< XPropertySet > xProp( *pControls++, UNO_QUERY );
2731 if ( xProp.is() )
2732 xProp->removePropertyChangeListener( FM_PROP_BOUNDFIELD, this );
2737 void FormController::startFormListening( const Reference< XPropertySet >& _rxForm, bool _bPropertiesOnly )
2741 if ( m_bCanInsert || m_bCanUpdate ) // form can be modified
2743 _rxForm->addPropertyChangeListener( FM_PROP_ISNEW, this );
2744 _rxForm->addPropertyChangeListener( FM_PROP_ISMODIFIED, this );
2746 if ( !_bPropertiesOnly )
2748 // set the Listener for UI interaction
2749 Reference< XRowSetApproveBroadcaster > xApprove( _rxForm, UNO_QUERY );
2750 if ( xApprove.is() )
2751 xApprove->addRowSetApproveListener( this );
2753 // listener for row set changes
2754 Reference< XRowSet > xRowSet( _rxForm, UNO_QUERY );
2755 if ( xRowSet.is() )
2756 xRowSet->addRowSetListener( this );
2760 Reference< XPropertySetInfo > xInfo = _rxForm->getPropertySetInfo();
2761 if ( xInfo.is() && xInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) )
2762 _rxForm->addPropertyChangeListener( FM_PROP_DYNAMIC_CONTROL_BORDER, this );
2764 catch( const Exception& )
2766 DBG_UNHANDLED_EXCEPTION();
2771 void FormController::stopFormListening( const Reference< XPropertySet >& _rxForm, bool _bPropertiesOnly )
2775 if ( m_bCanInsert || m_bCanUpdate )
2777 _rxForm->removePropertyChangeListener( FM_PROP_ISNEW, this );
2778 _rxForm->removePropertyChangeListener( FM_PROP_ISMODIFIED, this );
2780 if ( !_bPropertiesOnly )
2782 Reference< XRowSetApproveBroadcaster > xApprove( _rxForm, UNO_QUERY );
2783 if (xApprove.is())
2784 xApprove->removeRowSetApproveListener(this);
2786 Reference< XRowSet > xRowSet( _rxForm, UNO_QUERY );
2787 if ( xRowSet.is() )
2788 xRowSet->removeRowSetListener( this );
2792 Reference< XPropertySetInfo > xInfo = _rxForm->getPropertySetInfo();
2793 if ( xInfo.is() && xInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) )
2794 _rxForm->removePropertyChangeListener( FM_PROP_DYNAMIC_CONTROL_BORDER, this );
2796 catch( const Exception& )
2798 DBG_UNHANDLED_EXCEPTION();
2802 // com::sun::star::sdbc::XRowSetListener
2804 void FormController::cursorMoved(const EventObject& /*event*/) throw( RuntimeException, std::exception )
2806 ::osl::MutexGuard aGuard( m_aMutex );
2807 impl_checkDisposed_throw();
2809 // toggle the locking ?
2810 if (m_bLocked != determineLockState())
2812 m_bLocked = !m_bLocked;
2813 setLocks();
2814 if (isListeningForChanges())
2815 startListening();
2816 else
2817 stopListening();
2820 // neither the current control nor the current record are modified anymore
2821 m_bCurrentRecordModified = m_bModified = false;
2825 void FormController::rowChanged(const EventObject& /*event*/) throw( RuntimeException, std::exception )
2827 // not interested in ...
2830 void FormController::rowSetChanged(const EventObject& /*event*/) throw( RuntimeException, std::exception )
2832 // not interested in ...
2836 // XContainerListener
2838 void SAL_CALL FormController::elementInserted(const ContainerEvent& evt) throw( RuntimeException, std::exception )
2840 ::osl::MutexGuard aGuard( m_aMutex );
2841 impl_checkDisposed_throw();
2843 Reference< XControl > xControl( evt.Element, UNO_QUERY );
2844 if ( !xControl.is() )
2845 return;
2847 Reference< XFormComponent > xModel(xControl->getModel(), UNO_QUERY);
2848 if (xModel.is() && m_xModelAsIndex == xModel->getParent())
2850 insertControl(xControl);
2852 if ( m_aTabActivationTimer.IsActive() )
2853 m_aTabActivationTimer.Stop();
2855 m_aTabActivationTimer.Start();
2857 // are we in filtermode and a XModeSelector has inserted an element
2858 else if (m_bFiltering && Reference< XModeSelector > (evt.Source, UNO_QUERY).is())
2860 xModel = Reference< XFormComponent > (evt.Source, UNO_QUERY);
2861 if (xModel.is() && m_xModelAsIndex == xModel->getParent())
2863 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
2864 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
2866 // does the model use a bound field ?
2867 Reference< XPropertySet > xField;
2868 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
2870 Reference< XTextComponent > xText(xControl, UNO_QUERY);
2871 // may we filter the field?
2872 if (xText.is() && xField.is() && ::comphelper::hasProperty(FM_PROP_SEARCHABLE, xField) &&
2873 ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_SEARCHABLE)))
2875 m_aFilterComponents.push_back( xText );
2876 xText->addTextListener( this );
2884 void SAL_CALL FormController::elementReplaced(const ContainerEvent& evt) throw( RuntimeException, std::exception )
2886 // simulate an elementRemoved
2887 ContainerEvent aRemoveEvent( evt );
2888 aRemoveEvent.Element = evt.ReplacedElement;
2889 aRemoveEvent.ReplacedElement = Any();
2890 elementRemoved( aRemoveEvent );
2892 // simulate an elementInserted
2893 ContainerEvent aInsertEvent( evt );
2894 aInsertEvent.ReplacedElement = Any();
2895 elementInserted( aInsertEvent );
2899 void SAL_CALL FormController::elementRemoved(const ContainerEvent& evt) throw( RuntimeException, std::exception )
2901 ::osl::MutexGuard aGuard( m_aMutex );
2902 impl_checkDisposed_throw();
2904 Reference< XControl > xControl;
2905 evt.Element >>= xControl;
2906 if (!xControl.is())
2907 return;
2909 Reference< XFormComponent > xModel(xControl->getModel(), UNO_QUERY);
2910 if (xModel.is() && m_xModelAsIndex == xModel->getParent())
2912 removeControl(xControl);
2913 // TabOrder nicht neu berechnen, da das intern schon funktionieren muss!
2915 // are we in filtermode and a XModeSelector has inserted an element
2916 else if (m_bFiltering && Reference< XModeSelector > (evt.Source, UNO_QUERY).is())
2918 FilterComponents::iterator componentPos = ::std::find(
2919 m_aFilterComponents.begin(), m_aFilterComponents.end(), xControl );
2920 if ( componentPos != m_aFilterComponents.end() )
2921 m_aFilterComponents.erase( componentPos );
2926 Reference< XControl > FormController::isInList(const Reference< XWindowPeer > & xPeer) const
2928 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
2929 const Reference< XControl >* pControls = m_aControls.getConstArray();
2931 sal_uInt32 nCtrls = m_aControls.getLength();
2932 for ( sal_uInt32 n = 0; n < nCtrls && xPeer.is(); ++n, ++pControls )
2934 if ( pControls->is() )
2936 Reference< XVclWindowPeer > xCtrlPeer( (*pControls)->getPeer(), UNO_QUERY);
2937 if ( ( xCtrlPeer.get() == xPeer.get() ) || xCtrlPeer->isChild( xPeer ) )
2938 return *pControls;
2941 return Reference< XControl > ();
2945 void FormController::activateFirst() throw( RuntimeException, std::exception )
2947 ::osl::MutexGuard aGuard( m_aMutex );
2948 impl_checkDisposed_throw();
2950 DBG_ASSERT(m_xTabController.is(), "FormController::activateFirst : invalid aggregate !");
2951 if (m_xTabController.is())
2952 m_xTabController->activateFirst();
2956 void FormController::activateLast() throw( RuntimeException, std::exception )
2958 ::osl::MutexGuard aGuard( m_aMutex );
2959 impl_checkDisposed_throw();
2961 DBG_ASSERT(m_xTabController.is(), "FormController::activateLast : invalid aggregate !");
2962 if (m_xTabController.is())
2963 m_xTabController->activateLast();
2966 // XFormController
2968 Reference< XFormOperations > SAL_CALL FormController::getFormOperations() throw (RuntimeException, std::exception)
2970 ::osl::MutexGuard aGuard( m_aMutex );
2971 impl_checkDisposed_throw();
2973 return m_xFormOperations;
2977 Reference< XControl> SAL_CALL FormController::getCurrentControl(void) throw( RuntimeException, std::exception )
2979 ::osl::MutexGuard aGuard( m_aMutex );
2980 impl_checkDisposed_throw();
2981 return m_xCurrentControl;
2985 void SAL_CALL FormController::addActivateListener(const Reference< XFormControllerListener > & l) throw( RuntimeException, std::exception )
2987 ::osl::MutexGuard aGuard( m_aMutex );
2988 impl_checkDisposed_throw();
2989 m_aActivateListeners.addInterface(l);
2992 void SAL_CALL FormController::removeActivateListener(const Reference< XFormControllerListener > & l) throw( RuntimeException, std::exception )
2994 ::osl::MutexGuard aGuard( m_aMutex );
2995 impl_checkDisposed_throw();
2996 m_aActivateListeners.removeInterface(l);
3000 void SAL_CALL FormController::addChildController( const Reference< XFormController >& _ChildController ) throw( RuntimeException, IllegalArgumentException, std::exception )
3002 ::osl::MutexGuard aGuard( m_aMutex );
3003 impl_checkDisposed_throw();
3005 if ( !_ChildController.is() )
3006 throw IllegalArgumentException( OUString(), *this, 1 );
3007 // TODO: (localized) error message
3009 // the parent of our (to-be-)child must be our own model
3010 Reference< XFormComponent > xFormOfChild( _ChildController->getModel(), UNO_QUERY );
3011 if ( !xFormOfChild.is() )
3012 throw IllegalArgumentException( OUString(), *this, 1 );
3013 // TODO: (localized) error message
3015 if ( xFormOfChild->getParent() != m_xModelAsIndex )
3016 throw IllegalArgumentException( OUString(), *this, 1 );
3017 // TODO: (localized) error message
3019 m_aChildren.push_back( _ChildController );
3020 _ChildController->setParent( *this );
3022 // search the position of the model within the form
3023 sal_uInt32 nPos = m_xModelAsIndex->getCount();
3024 Reference< XFormComponent > xTemp;
3025 for( ; nPos; )
3027 m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
3028 if ( xFormOfChild == xTemp )
3030 m_xModelAsManager->attach( nPos, _ChildController, makeAny( _ChildController) );
3031 break;
3037 Reference< XFormControllerContext > SAL_CALL FormController::getContext() throw (RuntimeException, std::exception)
3039 ::osl::MutexGuard aGuard( m_aMutex );
3040 impl_checkDisposed_throw();
3041 return m_xFormControllerContext;
3045 void SAL_CALL FormController::setContext( const Reference< XFormControllerContext >& _context ) throw (RuntimeException, std::exception)
3047 ::osl::MutexGuard aGuard( m_aMutex );
3048 impl_checkDisposed_throw();
3049 m_xFormControllerContext = _context;
3053 Reference< XInteractionHandler > SAL_CALL FormController::getInteractionHandler() throw (RuntimeException, std::exception)
3055 ::osl::MutexGuard aGuard( m_aMutex );
3056 impl_checkDisposed_throw();
3057 return m_xInteractionHandler;
3061 void SAL_CALL FormController::setInteractionHandler( const Reference< XInteractionHandler >& _interactionHandler ) throw (RuntimeException, std::exception)
3063 ::osl::MutexGuard aGuard( m_aMutex );
3064 impl_checkDisposed_throw();
3065 m_xInteractionHandler = _interactionHandler;
3069 void FormController::setFilter(::std::vector<FmFieldInfo>& rFieldInfos)
3071 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3072 // create the composer
3073 Reference< XRowSet > xForm(m_xModelAsIndex, UNO_QUERY);
3074 Reference< XConnection > xConnection(OStaticDataAccessTools().getRowSetConnection(xForm));
3075 if (xForm.is())
3079 Reference< XMultiServiceFactory > xFactory( xConnection, UNO_QUERY_THROW );
3080 m_xComposer.set(
3081 xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"),
3082 UNO_QUERY_THROW );
3084 Reference< XPropertySet > xSet( xForm, UNO_QUERY );
3085 OUString sStatement = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_ACTIVECOMMAND ) );
3086 OUString sFilter = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_FILTER ) );
3087 m_xComposer->setElementaryQuery( sStatement );
3088 m_xComposer->setFilter( sFilter );
3090 catch( const Exception& )
3092 DBG_UNHANDLED_EXCEPTION();
3096 if (m_xComposer.is())
3098 Sequence< Sequence < PropertyValue > > aFilterRows = m_xComposer->getStructuredFilter();
3100 // ok, we receive the list of filters as sequence of fieldnames, value
3101 // now we have to transform the fieldname into UI names, that could be a label of the field or
3102 // a aliasname or the fieldname itself
3104 // first adjust the field names if necessary
3105 Reference< XNameAccess > xQueryColumns =
3106 Reference< XColumnsSupplier >( m_xComposer, UNO_QUERY_THROW )->getColumns();
3108 for (::std::vector<FmFieldInfo>::iterator iter = rFieldInfos.begin();
3109 iter != rFieldInfos.end(); ++iter)
3111 if ( xQueryColumns->hasByName((*iter).aFieldName) )
3113 if ( (xQueryColumns->getByName((*iter).aFieldName) >>= (*iter).xField) && (*iter).xField.is() )
3114 (*iter).xField->getPropertyValue(FM_PROP_REALNAME) >>= (*iter).aFieldName;
3118 Reference< XDatabaseMetaData> xMetaData(xConnection->getMetaData());
3119 // now transfer the filters into Value/TextComponent pairs
3120 ::comphelper::UStringMixEqual aCompare(xMetaData->storesMixedCaseQuotedIdentifiers());
3122 // need to parse criteria localized
3123 OStaticDataAccessTools aStaticTools;
3124 Reference< XNumberFormatsSupplier> xFormatSupplier( aStaticTools.getNumberFormats(xConnection, true));
3125 Reference< XNumberFormatter> xFormatter = NumberFormatter::create(m_xComponentContext);
3126 xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
3127 Locale aAppLocale = Application::GetSettings().GetUILanguageTag().getLocale();
3128 const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetUILocaleDataWrapper() );
3129 /* FIXME: casting this to sal_Char is plain wrong and of course only
3130 * works for ASCII separators, but
3131 * xParseNode->parseNodeToPredicateStr() expects a sal_Char. Fix it
3132 * there. */
3133 sal_Char cDecimalSeparator = (sal_Char)rLocaleWrapper.getNumDecimalSep()[0];
3134 SAL_WARN_IF( (sal_Unicode)cDecimalSeparator != rLocaleWrapper.getNumDecimalSep()[0],
3135 "svx.form", "FormController::setFilter: wrong cast of decimal separator to sal_Char!");
3137 // retrieving the filter
3138 const Sequence < PropertyValue >* pRow = aFilterRows.getConstArray();
3139 for (sal_Int32 i = 0, nLen = aFilterRows.getLength(); i < nLen; ++i)
3141 FmFilterRow aRow;
3143 // search a field for the given name
3144 const PropertyValue* pRefValues = pRow[i].getConstArray();
3145 for (sal_Int32 j = 0, nLen1 = pRow[i].getLength(); j < nLen1; j++)
3147 // look for the text component
3148 Reference< XPropertySet > xField;
3151 Reference< XPropertySet > xSet;
3152 OUString aRealName;
3154 // first look with the given name
3155 if (xQueryColumns->hasByName(pRefValues[j].Name))
3157 xQueryColumns->getByName(pRefValues[j].Name) >>= xSet;
3159 // get the RealName
3160 xSet->getPropertyValue("RealName") >>= aRealName;
3162 // compare the condition field name and the RealName
3163 if (aCompare(aRealName, pRefValues[j].Name))
3164 xField = xSet;
3166 if (!xField.is())
3168 // no we have to check every column to find the realname
3169 Reference< XIndexAccess > xColumnsByIndex(xQueryColumns, UNO_QUERY);
3170 for (sal_Int32 n = 0, nCount = xColumnsByIndex->getCount(); n < nCount; n++)
3172 xColumnsByIndex->getByIndex(n) >>= xSet;
3173 xSet->getPropertyValue("RealName") >>= aRealName;
3174 if (aCompare(aRealName, pRefValues[j].Name))
3176 // get the column by its alias
3177 xField = xSet;
3178 break;
3182 if (!xField.is())
3183 continue;
3185 catch (const Exception&)
3187 continue;
3190 // find the text component
3191 for (::std::vector<FmFieldInfo>::iterator iter = rFieldInfos.begin();
3192 iter != rFieldInfos.end(); ++iter)
3194 // we found the field so insert a new entry to the filter row
3195 if ((*iter).xField == xField)
3197 // do we already have the control ?
3198 if (aRow.find((*iter).xText) != aRow.end())
3200 OUString aCompText = aRow[(*iter).xText];
3201 aCompText += " ";
3202 OString aVal = m_xParser->getContext().getIntlKeywordAscii(IParseContext::KEY_AND);
3203 aCompText += OUString(aVal.getStr(),aVal.getLength(),RTL_TEXTENCODING_ASCII_US);
3204 aCompText += " ";
3205 aCompText += ::comphelper::getString(pRefValues[j].Value);
3206 aRow[(*iter).xText] = aCompText;
3208 else
3210 OUString sPredicate,sErrorMsg;
3211 pRefValues[j].Value >>= sPredicate;
3212 ::rtl::Reference< ISQLParseNode > xParseNode = predicateTree(sErrorMsg, sPredicate, xFormatter, xField);
3213 if ( xParseNode.is() )
3215 OUString sCriteria;
3216 xParseNode->parseNodeToPredicateStr( sCriteria
3217 ,xConnection
3218 ,xFormatter
3219 ,xField
3220 ,OUString()
3221 ,aAppLocale
3222 ,cDecimalSeparator
3223 ,getParseContext());
3224 aRow[(*iter).xText] = sCriteria;
3231 if (aRow.empty())
3232 continue;
3234 impl_addFilterRow( aRow );
3238 // now set the filter controls
3239 for ( ::std::vector<FmFieldInfo>::iterator field = rFieldInfos.begin();
3240 field != rFieldInfos.end();
3241 ++field
3244 m_aFilterComponents.push_back( field->xText );
3249 void FormController::startFiltering()
3251 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3253 OStaticDataAccessTools aStaticTools;
3254 Reference< XConnection > xConnection( aStaticTools.getRowSetConnection( Reference< XRowSet >( m_xModelAsIndex, UNO_QUERY ) ) );
3255 if ( !xConnection.is() )
3256 // nothing to do - can't filter a form which is not connected
3257 return;
3259 // stop listening for controls
3260 if (isListeningForChanges())
3261 stopListening();
3263 m_bFiltering = true;
3265 // as we don't want new controls to be attached to the scripting environment
3266 // we change attach flags
3267 m_bAttachEvents = false;
3269 // Austauschen der Kontrols fuer das aktuelle Formular
3270 Sequence< Reference< XControl > > aControlsCopy( m_aControls );
3271 const Reference< XControl >* pControls = aControlsCopy.getConstArray();
3272 sal_Int32 nControlCount = aControlsCopy.getLength();
3274 // the control we have to activate after replacement
3275 Reference< XDatabaseMetaData > xMetaData(xConnection->getMetaData());
3276 Reference< XNumberFormatsSupplier > xFormatSupplier = aStaticTools.getNumberFormats(xConnection, true);
3277 Reference< XNumberFormatter > xFormatter = NumberFormatter::create(m_xComponentContext);
3278 xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
3280 // structure for storing the field info
3281 ::std::vector<FmFieldInfo> aFieldInfos;
3283 for (sal_Int32 i = nControlCount; i > 0;)
3285 Reference< XControl > xControl = pControls[--i];
3286 if (xControl.is())
3288 // no events for the control anymore
3289 removeFromEventAttacher(xControl);
3291 // do we have a mode selector
3292 Reference< XModeSelector > xSelector(xControl, UNO_QUERY);
3293 if (xSelector.is())
3295 xSelector->setMode( OUString( "FilterMode" ) );
3297 // listening for new controls of the selector
3298 Reference< XContainer > xContainer(xSelector, UNO_QUERY);
3299 if (xContainer.is())
3300 xContainer->addContainerListener(this);
3302 Reference< XEnumerationAccess > xElementAccess(xSelector, UNO_QUERY);
3303 if (xElementAccess.is())
3305 Reference< XEnumeration > xEnumeration(xElementAccess->createEnumeration());
3306 Reference< XControl > xSubControl;
3307 while (xEnumeration->hasMoreElements())
3309 xEnumeration->nextElement() >>= xSubControl;
3310 if (xSubControl.is())
3312 Reference< XPropertySet > xSet(xSubControl->getModel(), UNO_QUERY);
3313 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
3315 // does the model use a bound field ?
3316 Reference< XPropertySet > xField;
3317 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
3319 Reference< XTextComponent > xText(xSubControl, UNO_QUERY);
3320 // may we filter the field?
3321 if (xText.is() && xField.is() && ::comphelper::hasProperty(FM_PROP_SEARCHABLE, xField) &&
3322 ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_SEARCHABLE)))
3324 aFieldInfos.push_back(FmFieldInfo(xField, xText));
3325 xText->addTextListener(this);
3331 continue;
3334 Reference< XPropertySet > xModel( xControl->getModel(), UNO_QUERY );
3335 if (xModel.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xModel))
3337 // does the model use a bound field ?
3338 Any aVal = xModel->getPropertyValue(FM_PROP_BOUNDFIELD);
3339 Reference< XPropertySet > xField;
3340 aVal >>= xField;
3342 // may we filter the field?
3344 if ( xField.is()
3345 && ::comphelper::hasProperty( FM_PROP_SEARCHABLE, xField )
3346 && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_SEARCHABLE ) )
3349 // create a filter control
3350 Reference< XControl > xFilterControl = form::control::FilterControl::createWithFormat(
3351 m_xComponentContext,
3352 VCLUnoHelper::GetInterface( getDialogParentWindow() ),
3353 xFormatter,
3354 xModel);
3356 if ( replaceControl( xControl, xFilterControl ) )
3358 Reference< XTextComponent > xFilterText( xFilterControl, UNO_QUERY );
3359 aFieldInfos.push_back( FmFieldInfo( xField, xFilterText ) );
3360 xFilterText->addTextListener(this);
3364 else
3366 // abmelden vom EventManager
3371 // we have all filter controls now, so the next step is to read the filters from the form
3372 // resolve all aliases and set the current filter to the according structure
3373 setFilter(aFieldInfos);
3375 Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
3376 if ( xSet.is() )
3377 stopFormListening( xSet, true );
3379 impl_setTextOnAllFilter_throw();
3381 // lock all controls which are not used for filtering
3382 m_bLocked = determineLockState();
3383 setLocks();
3384 m_bAttachEvents = true;
3388 void FormController::stopFiltering()
3390 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3391 if ( !m_bFiltering ) // #104693# OJ
3392 { // nothing to do
3393 return;
3396 m_bFiltering = false;
3397 m_bDetachEvents = false;
3399 ::comphelper::disposeComponent(m_xComposer);
3401 // Austauschen der Kontrols fuer das aktuelle Formular
3402 Sequence< Reference< XControl > > aControlsCopy( m_aControls );
3403 const Reference< XControl > * pControls = aControlsCopy.getConstArray();
3404 sal_Int32 nControlCount = aControlsCopy.getLength();
3406 // clear the filter control map
3407 ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), RemoveComponentTextListener( this ) );
3408 m_aFilterComponents.clear();
3410 for ( sal_Int32 i = nControlCount; i > 0; )
3412 Reference< XControl > xControl = pControls[--i];
3413 if (xControl.is())
3415 // now enable eventhandling again
3416 addToEventAttacher(xControl);
3418 Reference< XModeSelector > xSelector(xControl, UNO_QUERY);
3419 if (xSelector.is())
3421 xSelector->setMode( OUString( "DataMode" ) );
3423 // listening for new controls of the selector
3424 Reference< XContainer > xContainer(xSelector, UNO_QUERY);
3425 if (xContainer.is())
3426 xContainer->removeContainerListener(this);
3427 continue;
3430 Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
3431 if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
3433 // does the model use a bound field ?
3434 Reference< XPropertySet > xField;
3435 xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
3437 // may we filter the field?
3438 if ( xField.is()
3439 && ::comphelper::hasProperty( FM_PROP_SEARCHABLE, xField )
3440 && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_SEARCHABLE ) )
3443 OUString sServiceName;
3444 OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DEFAULTCONTROL ) >>= sServiceName );
3445 Reference< XControl > xNewControl( m_xComponentContext->getServiceManager()->createInstanceWithContext( sServiceName, m_xComponentContext ), UNO_QUERY );
3446 replaceControl( xControl, xNewControl );
3452 Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
3453 if ( xSet.is() )
3454 startFormListening( xSet, true );
3456 m_bDetachEvents = true;
3458 m_aFilterRows.clear();
3459 m_nCurrentFilterPosition = -1;
3461 // release the locks if possible
3462 // lock all controls which are not used for filtering
3463 m_bLocked = determineLockState();
3464 setLocks();
3466 // restart listening for control modifications
3467 if (isListeningForChanges())
3468 startListening();
3471 // XModeSelector
3473 void FormController::setMode(const OUString& Mode) throw( NoSupportException, RuntimeException, std::exception )
3475 ::osl::MutexGuard aGuard( m_aMutex );
3476 impl_checkDisposed_throw();
3478 if (!supportsMode(Mode))
3479 throw NoSupportException();
3481 if (Mode == m_aMode)
3482 return;
3484 m_aMode = Mode;
3486 if ( Mode == "FilterMode" )
3487 startFiltering();
3488 else
3489 stopFiltering();
3491 for (FmFormControllers::const_iterator i = m_aChildren.begin();
3492 i != m_aChildren.end(); ++i)
3494 Reference< XModeSelector > xMode(*i, UNO_QUERY);
3495 if ( xMode.is() )
3496 xMode->setMode(Mode);
3501 OUString SAL_CALL FormController::getMode(void) throw( RuntimeException, std::exception )
3503 ::osl::MutexGuard aGuard( m_aMutex );
3504 impl_checkDisposed_throw();
3506 return m_aMode;
3510 Sequence< OUString > SAL_CALL FormController::getSupportedModes(void) throw( RuntimeException, std::exception )
3512 ::osl::MutexGuard aGuard( m_aMutex );
3513 impl_checkDisposed_throw();
3515 static Sequence< OUString > aModes;
3516 if (!aModes.getLength())
3518 aModes.realloc(2);
3519 aModes[0] = "DataMode";
3520 aModes[1] = "FilterMode";
3522 return aModes;
3526 sal_Bool SAL_CALL FormController::supportsMode(const OUString& Mode) throw( RuntimeException, std::exception )
3528 ::osl::MutexGuard aGuard( m_aMutex );
3529 impl_checkDisposed_throw();
3531 Sequence< OUString > aModes(getSupportedModes());
3532 const OUString* pModes = aModes.getConstArray();
3533 for (sal_Int32 i = aModes.getLength(); i > 0; )
3535 if (pModes[--i] == Mode)
3536 return sal_True;
3538 return sal_False;
3542 Window* FormController::getDialogParentWindow()
3544 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
3545 Window* pParentWindow = NULL;
3548 Reference< XControl > xContainerControl( getContainer(), UNO_QUERY_THROW );
3549 Reference< XWindowPeer > xContainerPeer( xContainerControl->getPeer(), UNO_QUERY_THROW );
3550 pParentWindow = VCLUnoHelper::GetWindow( xContainerPeer );
3552 catch( const Exception& )
3554 DBG_UNHANDLED_EXCEPTION();
3556 return pParentWindow;
3559 bool FormController::checkFormComponentValidity( OUString& /* [out] */ _rFirstInvalidityExplanation, Reference< XControlModel >& /* [out] */ _rxFirstInvalidModel ) SAL_THROW(())
3563 Reference< XEnumerationAccess > xControlEnumAcc( getModel(), UNO_QUERY );
3564 Reference< XEnumeration > xControlEnumeration;
3565 if ( xControlEnumAcc.is() )
3566 xControlEnumeration = xControlEnumAcc->createEnumeration();
3567 OSL_ENSURE( xControlEnumeration.is(), "FormController::checkFormComponentValidity: cannot enumerate the controls!" );
3568 if ( !xControlEnumeration.is() )
3569 // assume all valid
3570 return true;
3572 Reference< XValidatableFormComponent > xValidatable;
3573 while ( xControlEnumeration->hasMoreElements() )
3575 if ( !( xControlEnumeration->nextElement() >>= xValidatable ) )
3576 // control does not support validation
3577 continue;
3579 if ( xValidatable->isValid() )
3580 continue;
3582 Reference< XValidator > xValidator( xValidatable->getValidator() );
3583 OSL_ENSURE( xValidator.is(), "FormController::checkFormComponentValidity: invalid, but no validator?" );
3584 if ( !xValidator.is() )
3585 // this violates the interface definition of css.form.validation.XValidatableFormComponent ...
3586 continue;
3588 _rFirstInvalidityExplanation = xValidator->explainInvalid( xValidatable->getCurrentValue() );
3589 _rxFirstInvalidModel = _rxFirstInvalidModel.query( xValidatable );
3590 return false;
3593 catch( const Exception& )
3595 DBG_UNHANDLED_EXCEPTION();
3597 return true;
3601 Reference< XControl > FormController::locateControl( const Reference< XControlModel >& _rxModel ) SAL_THROW(())
3605 Sequence< Reference< XControl > > aControls( getControls() );
3606 const Reference< XControl >* pControls = aControls.getConstArray();
3607 const Reference< XControl >* pControlsEnd = aControls.getConstArray() + aControls.getLength();
3609 for ( ; pControls != pControlsEnd; ++pControls )
3611 OSL_ENSURE( pControls->is(), "FormController::locateControl: NULL-control?" );
3612 if ( pControls->is() )
3614 if ( ( *pControls)->getModel() == _rxModel )
3615 return *pControls;
3618 OSL_FAIL( "FormController::locateControl: did not find a control for this model!" );
3620 catch( const Exception& )
3622 DBG_UNHANDLED_EXCEPTION();
3624 return NULL;
3628 namespace
3630 void displayErrorSetFocus( const OUString& _rMessage, const Reference< XControl >& _rxFocusControl, Window* _pDialogParent )
3632 SQLContext aError;
3633 aError.Message = SVX_RESSTR(RID_STR_WRITEERROR);
3634 aError.Details = _rMessage;
3635 displayException( aError, _pDialogParent );
3637 if ( _rxFocusControl.is() )
3639 Reference< XWindow > xControlWindow( _rxFocusControl, UNO_QUERY );
3640 OSL_ENSURE( xControlWindow.is(), "displayErrorSetFocus: invalid control!" );
3641 if ( xControlWindow.is() )
3642 xControlWindow->setFocus();
3646 bool lcl_shouldValidateRequiredFields_nothrow( const Reference< XInterface >& _rxForm )
3650 static OUString s_sFormsCheckRequiredFields( "FormsCheckRequiredFields" );
3652 // first, check whether the form has a property telling us the answer
3653 // this allows people to use the XPropertyContainer interface of a form to control
3654 // the behaviour on a per-form basis.
3655 Reference< XPropertySet > xFormProps( _rxForm, UNO_QUERY_THROW );
3656 Reference< XPropertySetInfo > xPSI( xFormProps->getPropertySetInfo() );
3657 if ( xPSI->hasPropertyByName( s_sFormsCheckRequiredFields ) )
3659 bool bShouldValidate = true;
3660 OSL_VERIFY( xFormProps->getPropertyValue( s_sFormsCheckRequiredFields ) >>= bShouldValidate );
3661 return bShouldValidate;
3664 // next, check the data source which created the connection
3665 Reference< XChild > xConnectionAsChild( xFormProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ), UNO_QUERY_THROW );
3666 Reference< XPropertySet > xDataSource( xConnectionAsChild->getParent(), UNO_QUERY );
3667 if ( !xDataSource.is() )
3668 // seldom (but possible): this is not a connection created by a data source
3669 return true;
3671 Reference< XPropertySet > xDataSourceSettings(
3672 xDataSource->getPropertyValue("Settings"),
3673 UNO_QUERY_THROW );
3675 bool bShouldValidate = true;
3676 OSL_VERIFY( xDataSourceSettings->getPropertyValue( s_sFormsCheckRequiredFields ) >>= bShouldValidate );
3677 return bShouldValidate;
3679 catch( const Exception& )
3681 DBG_UNHANDLED_EXCEPTION();
3684 return true;
3688 // XRowSetApproveListener
3690 sal_Bool SAL_CALL FormController::approveRowChange(const RowChangeEvent& _rEvent) throw( RuntimeException, std::exception )
3692 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3693 impl_checkDisposed_throw();
3695 ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
3696 bool bValid = true;
3697 if (aIter.hasMoreElements())
3699 RowChangeEvent aEvt( _rEvent );
3700 aEvt.Source = *this;
3701 bValid = ((XRowSetApproveListener*)aIter.next())->approveRowChange(aEvt);
3704 if ( !bValid )
3705 return bValid;
3707 if ( ( _rEvent.Action != RowChangeAction::INSERT )
3708 && ( _rEvent.Action != RowChangeAction::UPDATE )
3710 return bValid;
3712 // if some of the control models are bound to validators, check them
3713 OUString sInvalidityExplanation;
3714 Reference< XControlModel > xInvalidModel;
3715 if ( !checkFormComponentValidity( sInvalidityExplanation, xInvalidModel ) )
3717 Reference< XControl > xControl( locateControl( xInvalidModel ) );
3718 aGuard.clear();
3719 displayErrorSetFocus( sInvalidityExplanation, xControl, getDialogParentWindow() );
3720 return false;
3723 // check values on NULL and required flag
3724 if ( !lcl_shouldValidateRequiredFields_nothrow( _rEvent.Source ) )
3725 return sal_True;
3727 OSL_ENSURE( m_pColumnInfoCache.get(), "FormController::approveRowChange: no column infos!" );
3728 if ( !m_pColumnInfoCache.get() )
3729 return sal_True;
3733 if ( !m_pColumnInfoCache->controlsInitialized() )
3734 m_pColumnInfoCache->initializeControls( getControls() );
3736 size_t colCount = m_pColumnInfoCache->getColumnCount();
3737 for ( size_t col = 0; col < colCount; ++col )
3739 const ColumnInfo& rColInfo = m_pColumnInfoCache->getColumnInfo( col );
3740 if ( rColInfo.nNullable != ColumnValue::NO_NULLS )
3741 continue;
3743 if ( rColInfo.bAutoIncrement )
3744 continue;
3746 if ( rColInfo.bReadOnly )
3747 continue;
3749 if ( !rColInfo.xFirstControlWithInputRequired.is() && !rColInfo.xFirstGridWithInputRequiredColumn.is() )
3750 continue;
3752 // TODO: in case of binary fields, this "getString" below is extremely expensive
3753 if ( !rColInfo.xColumn->getString().isEmpty() || !rColInfo.xColumn->wasNull() )
3754 continue;
3756 OUString sMessage( SVX_RESSTR( RID_ERR_FIELDREQUIRED ) );
3757 sMessage = sMessage.replaceFirst( "#", rColInfo.sName );
3759 // the control to focus
3760 Reference< XControl > xControl( rColInfo.xFirstControlWithInputRequired );
3761 if ( !xControl.is() )
3762 xControl.set( rColInfo.xFirstGridWithInputRequiredColumn, UNO_QUERY );
3764 aGuard.clear();
3765 displayErrorSetFocus( sMessage, rColInfo.xFirstControlWithInputRequired, getDialogParentWindow() );
3766 return sal_False;
3769 catch( const Exception& )
3771 DBG_UNHANDLED_EXCEPTION();
3774 return true;
3778 sal_Bool SAL_CALL FormController::approveCursorMove(const EventObject& event) throw( RuntimeException, std::exception )
3780 ::osl::MutexGuard aGuard( m_aMutex );
3781 impl_checkDisposed_throw();
3783 ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
3784 if (aIter.hasMoreElements())
3786 EventObject aEvt(event);
3787 aEvt.Source = *this;
3788 return ((XRowSetApproveListener*)aIter.next())->approveCursorMove(aEvt);
3791 return sal_True;
3795 sal_Bool SAL_CALL FormController::approveRowSetChange(const EventObject& event) throw( RuntimeException, std::exception )
3797 ::osl::MutexGuard aGuard( m_aMutex );
3798 impl_checkDisposed_throw();
3800 ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
3801 if (aIter.hasMoreElements())
3803 EventObject aEvt(event);
3804 aEvt.Source = *this;
3805 return ((XRowSetApproveListener*)aIter.next())->approveRowSetChange(aEvt);
3808 return sal_True;
3811 // XRowSetApproveBroadcaster
3813 void SAL_CALL FormController::addRowSetApproveListener(const Reference< XRowSetApproveListener > & _rxListener) throw( RuntimeException, std::exception )
3815 ::osl::MutexGuard aGuard( m_aMutex );
3816 impl_checkDisposed_throw();
3818 m_aRowSetApproveListeners.addInterface(_rxListener);
3822 void SAL_CALL FormController::removeRowSetApproveListener(const Reference< XRowSetApproveListener > & _rxListener) throw( RuntimeException, std::exception )
3824 ::osl::MutexGuard aGuard( m_aMutex );
3825 impl_checkDisposed_throw();
3827 m_aRowSetApproveListeners.removeInterface(_rxListener);
3830 // XErrorListener
3832 void SAL_CALL FormController::errorOccured(const SQLErrorEvent& aEvent) throw( RuntimeException, std::exception )
3834 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3835 impl_checkDisposed_throw();
3837 ::cppu::OInterfaceIteratorHelper aIter(m_aErrorListeners);
3838 if (aIter.hasMoreElements())
3840 SQLErrorEvent aEvt(aEvent);
3841 aEvt.Source = *this;
3842 ((XSQLErrorListener*)aIter.next())->errorOccured(aEvt);
3844 else
3846 aGuard.clear();
3847 displayException( aEvent );
3851 // XErrorBroadcaster
3853 void SAL_CALL FormController::addSQLErrorListener(const Reference< XSQLErrorListener > & aListener) throw( RuntimeException, std::exception )
3855 ::osl::MutexGuard aGuard( m_aMutex );
3856 impl_checkDisposed_throw();
3858 m_aErrorListeners.addInterface(aListener);
3862 void SAL_CALL FormController::removeSQLErrorListener(const Reference< XSQLErrorListener > & aListener) throw( RuntimeException, std::exception )
3864 ::osl::MutexGuard aGuard( m_aMutex );
3865 impl_checkDisposed_throw();
3867 m_aErrorListeners.removeInterface(aListener);
3870 // XDatabaseParameterBroadcaster2
3872 void SAL_CALL FormController::addDatabaseParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException, std::exception )
3874 ::osl::MutexGuard aGuard( m_aMutex );
3875 impl_checkDisposed_throw();
3877 m_aParameterListeners.addInterface(aListener);
3881 void SAL_CALL FormController::removeDatabaseParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException, std::exception )
3883 ::osl::MutexGuard aGuard( m_aMutex );
3884 impl_checkDisposed_throw();
3886 m_aParameterListeners.removeInterface(aListener);
3889 // XDatabaseParameterBroadcaster
3891 void SAL_CALL FormController::addParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException, std::exception )
3893 FormController::addDatabaseParameterListener( aListener );
3897 void SAL_CALL FormController::removeParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException, std::exception )
3899 FormController::removeDatabaseParameterListener( aListener );
3902 // XDatabaseParameterListener
3904 sal_Bool SAL_CALL FormController::approveParameter(const DatabaseParameterEvent& aEvent) throw( RuntimeException, std::exception )
3906 SolarMutexGuard aSolarGuard;
3907 ::osl::MutexGuard aGuard( m_aMutex );
3908 impl_checkDisposed_throw();
3910 ::cppu::OInterfaceIteratorHelper aIter(m_aParameterListeners);
3911 if (aIter.hasMoreElements())
3913 DatabaseParameterEvent aEvt(aEvent);
3914 aEvt.Source = *this;
3915 return ((XDatabaseParameterListener*)aIter.next())->approveParameter(aEvt);
3917 else
3919 // default handling: instantiate an interaction handler and let it handle the parameter request
3922 if ( !ensureInteractionHandler() )
3923 return sal_False;
3925 // two continuations allowed: OK and Cancel
3926 OParameterContinuation* pParamValues = new OParameterContinuation;
3927 OInteractionAbort* pAbort = new OInteractionAbort;
3928 // the request
3929 ParametersRequest aRequest;
3930 aRequest.Parameters = aEvent.Parameters;
3931 aRequest.Connection = OStaticDataAccessTools().getRowSetConnection(Reference< XRowSet >(aEvent.Source, UNO_QUERY));
3932 OInteractionRequest* pParamRequest = new OInteractionRequest(makeAny(aRequest));
3933 Reference< XInteractionRequest > xParamRequest(pParamRequest);
3934 // some knittings
3935 pParamRequest->addContinuation(pParamValues);
3936 pParamRequest->addContinuation(pAbort);
3938 // handle the request
3939 m_xInteractionHandler->handle(xParamRequest);
3941 if (!pParamValues->wasSelected())
3942 // canceled
3943 return sal_False;
3945 // transfer the values into the parameter supplier
3946 Sequence< PropertyValue > aFinalValues = pParamValues->getValues();
3947 if (aFinalValues.getLength() != aRequest.Parameters->getCount())
3949 OSL_FAIL("FormController::approveParameter: the InteractionHandler returned nonsense!");
3950 return sal_False;
3952 const PropertyValue* pFinalValues = aFinalValues.getConstArray();
3953 for (sal_Int32 i=0; i<aFinalValues.getLength(); ++i, ++pFinalValues)
3955 Reference< XPropertySet > xParam(
3956 aRequest.Parameters->getByIndex(i), css::uno::UNO_QUERY);
3957 if (xParam.is())
3959 #ifdef DBG_UTIL
3960 OUString sName;
3961 xParam->getPropertyValue(FM_PROP_NAME) >>= sName;
3962 DBG_ASSERT(sName.equals(pFinalValues->Name), "FormController::approveParameter: suspicious value names!");
3963 #endif
3964 try { xParam->setPropertyValue(FM_PROP_VALUE, pFinalValues->Value); }
3965 catch(Exception&)
3967 OSL_FAIL("FormController::approveParameter: setting one of the properties failed!");
3972 catch(Exception&)
3974 DBG_UNHANDLED_EXCEPTION();
3977 return sal_True;
3980 // XConfirmDeleteBroadcaster
3982 void SAL_CALL FormController::addConfirmDeleteListener(const Reference< XConfirmDeleteListener > & aListener) throw( RuntimeException, std::exception )
3984 ::osl::MutexGuard aGuard( m_aMutex );
3985 impl_checkDisposed_throw();
3987 m_aDeleteListeners.addInterface(aListener);
3991 void SAL_CALL FormController::removeConfirmDeleteListener(const Reference< XConfirmDeleteListener > & aListener) throw( RuntimeException, std::exception )
3993 ::osl::MutexGuard aGuard( m_aMutex );
3994 impl_checkDisposed_throw();
3996 m_aDeleteListeners.removeInterface(aListener);
3999 // XConfirmDeleteListener
4001 sal_Bool SAL_CALL FormController::confirmDelete(const RowChangeEvent& aEvent) throw( RuntimeException, std::exception )
4003 ::osl::MutexGuard aGuard( m_aMutex );
4004 impl_checkDisposed_throw();
4006 ::cppu::OInterfaceIteratorHelper aIter(m_aDeleteListeners);
4007 if (aIter.hasMoreElements())
4009 RowChangeEvent aEvt(aEvent);
4010 aEvt.Source = *this;
4011 return ((XConfirmDeleteListener*)aIter.next())->confirmDelete(aEvt);
4013 // default handling: instantiate an interaction handler and let it handle the request
4015 OUString sTitle;
4016 sal_Int32 nLength = aEvent.Rows;
4017 if ( nLength > 1 )
4019 sTitle = SVX_RESSTR( RID_STR_DELETECONFIRM_RECORDS );
4020 sTitle = sTitle.replaceFirst( "#", OUString::number(nLength) );
4022 else
4023 sTitle = SVX_RESSTR( RID_STR_DELETECONFIRM_RECORD );
4027 if ( !ensureInteractionHandler() )
4028 return sal_False;
4030 // two continuations allowed: Yes and No
4031 OInteractionApprove* pApprove = new OInteractionApprove;
4032 OInteractionDisapprove* pDisapprove = new OInteractionDisapprove;
4034 // the request
4035 SQLWarning aWarning;
4036 aWarning.Message = sTitle;
4037 SQLWarning aDetails;
4038 aDetails.Message = SVX_RESSTR(RID_STR_DELETECONFIRM);
4039 aWarning.NextException <<= aDetails;
4041 OInteractionRequest* pRequest = new OInteractionRequest( makeAny( aWarning ) );
4042 Reference< XInteractionRequest > xRequest( pRequest );
4044 // some knittings
4045 pRequest->addContinuation( pApprove );
4046 pRequest->addContinuation( pDisapprove );
4048 // handle the request
4049 m_xInteractionHandler->handle( xRequest );
4051 if ( pApprove->wasSelected() )
4052 return sal_True;
4054 catch( const Exception& )
4056 DBG_UNHANDLED_EXCEPTION();
4059 return sal_False;
4063 void SAL_CALL FormController::invalidateFeatures( const Sequence< ::sal_Int16 >& _Features ) throw (RuntimeException, std::exception)
4065 ::osl::MutexGuard aGuard( m_aMutex );
4066 // for now, just copy the ids of the features, because ....
4067 ::std::copy( _Features.getConstArray(), _Features.getConstArray() + _Features.getLength(),
4068 ::std::insert_iterator< ::std::set< sal_Int16 > >( m_aInvalidFeatures, m_aInvalidFeatures.begin() )
4071 // ... we will do the real invalidation asynchronously
4072 if ( !m_aFeatureInvalidationTimer.IsActive() )
4073 m_aFeatureInvalidationTimer.Start();
4077 void SAL_CALL FormController::invalidateAllFeatures( ) throw (RuntimeException, std::exception)
4079 ::osl::ClearableMutexGuard aGuard( m_aMutex );
4081 Sequence< sal_Int16 > aInterceptedFeatures( m_aFeatureDispatchers.size() );
4082 ::std::transform(
4083 m_aFeatureDispatchers.begin(),
4084 m_aFeatureDispatchers.end(),
4085 aInterceptedFeatures.getArray(),
4086 ::o3tl::select1st< DispatcherContainer::value_type >()
4089 aGuard.clear();
4090 if ( aInterceptedFeatures.getLength() )
4091 invalidateFeatures( aInterceptedFeatures );
4095 Reference< XDispatch >
4096 FormController::interceptedQueryDispatch( const URL& aURL,
4097 const OUString& /*aTargetFrameName*/, sal_Int32 /*nSearchFlags*/)
4098 throw( RuntimeException )
4100 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
4101 Reference< XDispatch > xReturn;
4102 // dispatches handled by ourself
4103 if ( ( aURL.Complete == FMURL_CONFIRM_DELETION )
4104 || ( ( aURL.Complete == "private:/InteractionHandler" )
4105 && ensureInteractionHandler()
4108 xReturn = static_cast< XDispatch* >( this );
4110 // dispatches of FormSlot-URLs we have to translate
4111 if ( !xReturn.is() && m_xFormOperations.is() )
4113 // find the slot id which corresponds to the URL
4114 sal_Int32 nFeatureSlotId = ::svx::FeatureSlotTranslation::getControllerFeatureSlotIdForURL( aURL.Main );
4115 sal_Int16 nFormFeature = ( nFeatureSlotId != -1 ) ? ::svx::FeatureSlotTranslation::getFormFeatureForSlotId( nFeatureSlotId ) : -1;
4116 if ( nFormFeature > 0 )
4118 // get the dispatcher for this feature, create if necessary
4119 DispatcherContainer::const_iterator aDispatcherPos = m_aFeatureDispatchers.find( nFormFeature );
4120 if ( aDispatcherPos == m_aFeatureDispatchers.end() )
4122 aDispatcherPos = m_aFeatureDispatchers.insert(
4123 DispatcherContainer::value_type( nFormFeature, new ::svx::OSingleFeatureDispatcher( aURL, nFormFeature, m_xFormOperations, m_aMutex ) )
4124 ).first;
4127 OSL_ENSURE( aDispatcherPos->second.is(), "FormController::interceptedQueryDispatch: should have a dispatcher by now!" );
4128 return aDispatcherPos->second;
4132 // no more to offer
4133 return xReturn;
4137 void SAL_CALL FormController::dispatch( const URL& _rURL, const Sequence< PropertyValue >& _rArgs ) throw (RuntimeException, std::exception)
4139 if ( _rArgs.getLength() != 1 )
4141 OSL_FAIL( "FormController::dispatch: no arguments -> no dispatch!" );
4142 return;
4145 if ( _rURL.Complete == "private:/InteractionHandler" )
4147 Reference< XInteractionRequest > xRequest;
4148 OSL_VERIFY( _rArgs[0].Value >>= xRequest );
4149 if ( xRequest.is() )
4150 handle( xRequest );
4151 return;
4154 if ( _rURL.Complete == FMURL_CONFIRM_DELETION )
4156 OSL_FAIL( "FormController::dispatch: How do you expect me to return something via this call?" );
4157 // confirmDelete has a return value - dispatch hasn't
4158 return;
4161 OSL_FAIL( "FormController::dispatch: unknown URL!" );
4165 void SAL_CALL FormController::addStatusListener( const Reference< XStatusListener >& _rxListener, const URL& _rURL ) throw (RuntimeException, std::exception)
4167 if (_rURL.Complete == FMURL_CONFIRM_DELETION)
4169 if (_rxListener.is())
4170 { // send an initial statusChanged event
4171 FeatureStateEvent aEvent;
4172 aEvent.FeatureURL = _rURL;
4173 aEvent.IsEnabled = sal_True;
4174 _rxListener->statusChanged(aEvent);
4175 // and don't add the listener at all (the status will never change)
4178 else
4179 OSL_FAIL("FormController::addStatusListener: invalid (unsupported) URL!");
4183 Reference< XInterface > SAL_CALL FormController::getParent() throw( RuntimeException, std::exception )
4185 return m_xParent;
4189 void SAL_CALL FormController::setParent( const Reference< XInterface >& Parent) throw( NoSupportException, RuntimeException, std::exception )
4191 m_xParent = Parent;
4195 void SAL_CALL FormController::removeStatusListener( const Reference< XStatusListener >& /*_rxListener*/, const URL& _rURL ) throw (RuntimeException, std::exception)
4197 (void)_rURL;
4198 OSL_ENSURE(_rURL.Complete == FMURL_CONFIRM_DELETION, "FormController::removeStatusListener: invalid (unsupported) URL!");
4199 // we never really added the listener, so we don't need to remove it
4203 Reference< XDispatchProviderInterceptor > FormController::createInterceptor(const Reference< XDispatchProviderInterception > & _xInterception)
4205 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
4206 #ifdef DBG_UTIL
4207 // check if we already have a interceptor for the given object
4208 for ( Interceptors::const_iterator aIter = m_aControlDispatchInterceptors.begin();
4209 aIter != m_aControlDispatchInterceptors.end();
4210 ++aIter
4213 if ((*aIter)->getIntercepted() == _xInterception)
4214 OSL_FAIL("FormController::createInterceptor : we already do intercept this objects dispatches !");
4216 #endif
4218 DispatchInterceptionMultiplexer* pInterceptor = new DispatchInterceptionMultiplexer( _xInterception, this );
4219 pInterceptor->acquire();
4220 m_aControlDispatchInterceptors.insert( m_aControlDispatchInterceptors.end(), pInterceptor );
4222 return pInterceptor;
4226 bool FormController::ensureInteractionHandler()
4228 if ( m_xInteractionHandler.is() )
4229 return true;
4230 if ( m_bAttemptedHandlerCreation )
4231 return false;
4232 m_bAttemptedHandlerCreation = true;
4234 m_xInteractionHandler = InteractionHandler::createWithParent(m_xComponentContext, 0);
4235 return m_xInteractionHandler.is();
4239 void SAL_CALL FormController::handle( const Reference< XInteractionRequest >& _rRequest ) throw (RuntimeException, std::exception)
4241 if ( !ensureInteractionHandler() )
4242 return;
4243 m_xInteractionHandler->handle( _rRequest );
4247 void FormController::deleteInterceptor(const Reference< XDispatchProviderInterception > & _xInterception)
4249 OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
4250 // search the interceptor responsible for the given object
4251 Interceptors::iterator aIter;
4252 for ( aIter = m_aControlDispatchInterceptors.begin();
4253 aIter != m_aControlDispatchInterceptors.end();
4254 ++aIter
4257 if ((*aIter)->getIntercepted() == _xInterception)
4258 break;
4260 if (aIter == m_aControlDispatchInterceptors.end())
4262 return;
4265 // log off the interception from it's interception object
4266 DispatchInterceptionMultiplexer* pInterceptorImpl = *aIter;
4267 pInterceptorImpl->dispose();
4268 pInterceptorImpl->release();
4270 // remove the interceptor from our array
4271 m_aControlDispatchInterceptors.erase(aIter);
4275 void FormController::implInvalidateCurrentControlDependentFeatures()
4277 Sequence< sal_Int16 > aCurrentControlDependentFeatures(4);
4279 aCurrentControlDependentFeatures[0] = FormFeature::SortAscending;
4280 aCurrentControlDependentFeatures[1] = FormFeature::SortDescending;
4281 aCurrentControlDependentFeatures[2] = FormFeature::AutoFilter;
4282 aCurrentControlDependentFeatures[3] = FormFeature::RefreshCurrentControl;
4284 invalidateFeatures( aCurrentControlDependentFeatures );
4288 void SAL_CALL FormController::columnChanged( const EventObject& /*_event*/ ) throw (RuntimeException, std::exception)
4290 implInvalidateCurrentControlDependentFeatures();
4293 } // namespace svxform
4295 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */