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