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