nss: upgrade to release 3.73
[LibreOffice.git] / forms / source / component / DatabaseForm.cxx
blob3b1f8f6de5f8568debfebf63473480a793199f92
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <componenttools.hxx>
22 #include "DatabaseForm.hxx"
23 #include "EventThread.hxx"
24 #include <strings.hrc>
25 #include <frm_resource.hxx>
26 #include "GroupManager.hxx"
27 #include <property.hxx>
28 #include <services.hxx>
30 #include <com/sun/star/awt/XControlContainer.hpp>
31 #include <com/sun/star/awt/XTextComponent.hpp>
32 #include <com/sun/star/form/DataSelectionType.hpp>
33 #include <com/sun/star/form/FormComponentType.hpp>
34 #include <com/sun/star/form/TabulatorCycle.hpp>
35 #include <com/sun/star/frame/FrameSearchFlag.hpp>
36 #include <com/sun/star/frame/XDispatch.hpp>
37 #include <com/sun/star/frame/XDispatchProvider.hpp>
38 #include <com/sun/star/frame/XModel.hpp>
39 #include <com/sun/star/io/XObjectInputStream.hpp>
40 #include <com/sun/star/io/XObjectOutputStream.hpp>
41 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
42 #include <com/sun/star/sdb/CommandType.hpp>
43 #include <com/sun/star/sdb/RowSetVetoException.hpp>
44 #include <com/sun/star/sdb/XColumnUpdate.hpp>
45 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
46 #include <com/sun/star/sdbc/ResultSetType.hpp>
47 #include <com/sun/star/sdbc/XRowSet.hpp>
48 #include <com/sun/star/sdbcx/Privilege.hpp>
49 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
50 #include <com/sun/star/util/URLTransformer.hpp>
51 #include <com/sun/star/util/XURLTransformer.hpp>
52 #include <com/sun/star/util/XModifiable2.hpp>
54 #include <comphelper/basicio.hxx>
55 #include <comphelper/property.hxx>
56 #include <comphelper/seqstream.hxx>
57 #include <comphelper/sequence.hxx>
58 #include <connectivity/dbtools.hxx>
59 #include <cppuhelper/exc_hlp.hxx>
60 #include <cppuhelper/supportsservice.hxx>
61 #include <comphelper/types.hxx>
62 #include <rtl/math.hxx>
63 #include <rtl/tencinfo.h>
64 #include <svl/inettype.hxx>
65 #include <tools/datetime.hxx>
66 #include <tools/debug.hxx>
67 #include <tools/diagnose_ex.h>
68 #include <tools/inetmsg.hxx>
69 #include <tools/inetstrm.hxx>
70 #include <tools/urlobj.hxx>
71 #include <unotools/ucbstreamhelper.hxx>
72 #include <vcl/svapp.hxx>
73 #include <vcl/timer.hxx>
74 #include <osl/mutex.hxx>
76 using namespace ::dbtools;
77 using namespace ::comphelper;
78 using namespace ::com::sun::star::uno;
79 using namespace ::com::sun::star::sdb;
80 using namespace ::com::sun::star::sdbc;
81 using namespace ::com::sun::star::sdbcx;
82 using namespace ::com::sun::star::beans;
83 using namespace ::com::sun::star::container;
84 using namespace ::com::sun::star::task;
85 using namespace ::com::sun::star::frame;
86 using namespace ::com::sun::star::form;
87 using namespace ::com::sun::star::awt;
88 using namespace ::com::sun::star::io;
89 using namespace ::com::sun::star::lang;
90 using namespace ::com::sun::star::util;
93 namespace frm
96 namespace {
98 class DocumentModifyGuard
100 public:
101 explicit DocumentModifyGuard( const Reference< XInterface >& _rxFormComponent )
102 :m_xDocumentModify( getXModel( _rxFormComponent ), UNO_QUERY )
104 impl_changeModifiableFlag_nothrow( false );
106 ~DocumentModifyGuard()
108 impl_changeModifiableFlag_nothrow( true );
111 private:
112 void impl_changeModifiableFlag_nothrow( const bool _enable )
116 if ( m_xDocumentModify.is() )
117 _enable ? m_xDocumentModify->enableSetModified() : m_xDocumentModify->disableSetModified();
119 catch(const Exception&)
121 DBG_UNHANDLED_EXCEPTION("forms.component");
125 private:
126 Reference< XModifiable2 > m_xDocumentModify;
131 // submitting and resetting html-forms asynchronously
132 class OFormSubmitResetThread: public OComponentEventThread
134 protected:
136 // process an event. while processing the mutex isn't locked, and pCompImpl
137 // is made sure to remain valid
138 virtual void processEvent( ::cppu::OComponentHelper* _pCompImpl,
139 const EventObject* _pEvt,
140 const Reference<XControl>& _rControl,
141 bool _bSubmit) override;
143 public:
145 explicit OFormSubmitResetThread(ODatabaseForm* pControl) : OComponentEventThread(pControl) { }
149 void OFormSubmitResetThread::processEvent(
150 ::cppu::OComponentHelper* pCompImpl,
151 const EventObject *_pEvt,
152 const Reference<XControl>& _rControl,
153 bool _bSubmit)
155 if (_bSubmit)
156 static_cast<ODatabaseForm *>(pCompImpl)->submit_impl(_rControl, *static_cast<const css::awt::MouseEvent*>(_pEvt));
157 else
158 static_cast<ODatabaseForm *>(pCompImpl)->reset_impl(true);
162 //= ODatabaseForm
164 Sequence<sal_Int8> SAL_CALL ODatabaseForm::getImplementationId()
166 return css::uno::Sequence<sal_Int8>();
170 Sequence<Type> SAL_CALL ODatabaseForm::getTypes()
172 // ask the aggregate
173 Sequence<Type> aAggregateTypes;
174 Reference<XTypeProvider> xAggregateTypes;
175 if (query_aggregation(m_xAggregate, xAggregateTypes))
176 aAggregateTypes = xAggregateTypes->getTypes();
178 Sequence< Type > aRet = concatSequences(
179 aAggregateTypes, ODatabaseForm_BASE1::getTypes(), OFormComponents::getTypes()
181 aRet = concatSequences( aRet, ODatabaseForm_BASE2::getTypes(), ODatabaseForm_BASE3::getTypes() );
182 return concatSequences( aRet, OPropertySetAggregationHelper::getTypes() );
186 Any SAL_CALL ODatabaseForm::queryAggregation(const Type& _rType)
188 Any aReturn = ODatabaseForm_BASE1::queryInterface(_rType);
189 // our own interfaces
190 if (!aReturn.hasValue())
192 aReturn = ODatabaseForm_BASE2::queryInterface(_rType);
193 // property set related interfaces
194 if (!aReturn.hasValue())
196 aReturn = OPropertySetAggregationHelper::queryInterface(_rType);
198 // form component collection related interfaces
199 if (!aReturn.hasValue())
201 aReturn = OFormComponents::queryAggregation(_rType);
203 // interfaces already present in the aggregate which we want to reroute
204 // only available if we could create the aggregate
205 if (!aReturn.hasValue() && m_xAggregateAsRowSet.is())
206 aReturn = ODatabaseForm_BASE3::queryInterface(_rType);
208 // aggregate interfaces
209 // (ask the aggregated object _after_ the OComponentHelper (base of OFormComponents),
210 // so calls to the XComponent interface reach us and not the aggregation)
211 if (!aReturn.hasValue() && m_xAggregate.is())
212 aReturn = m_xAggregate->queryAggregation(_rType);
217 return aReturn;
221 ODatabaseForm::ODatabaseForm(const Reference<XComponentContext>& _rxContext)
222 :OFormComponents(_rxContext)
223 ,OPropertySetAggregationHelper(OComponentHelper::rBHelper)
224 ,OPropertyChangeListener(m_aMutex)
225 ,m_aLoadListeners(m_aMutex)
226 ,m_aRowSetApproveListeners(m_aMutex)
227 ,m_aSubmitListeners(m_aMutex)
228 ,m_aErrorListeners(m_aMutex)
229 ,m_aResetListeners( *this, m_aMutex )
230 ,m_aPropertyBagHelper( *this )
231 ,m_aParameterManager( m_aMutex, _rxContext )
232 ,m_aFilterManager()
233 ,m_nResetsPending(0)
234 ,m_nPrivileges(0)
235 ,m_bInsertOnly( false )
236 ,m_eSubmitMethod(FormSubmitMethod_GET)
237 ,m_eSubmitEncoding(FormSubmitEncoding_URL)
238 ,m_eNavigation(NavigationBarMode_CURRENT)
239 ,m_bAllowInsert(true)
240 ,m_bAllowUpdate(true)
241 ,m_bAllowDelete(true)
242 ,m_bLoaded(false)
243 ,m_bSubForm(false)
244 ,m_bForwardingConnection(false)
245 ,m_bSharingConnection( false )
247 impl_construct();
251 ODatabaseForm::ODatabaseForm( const ODatabaseForm& _cloneSource )
252 :OFormComponents( _cloneSource )
253 ,OPropertySetAggregationHelper( OComponentHelper::rBHelper )
254 ,OPropertyChangeListener( m_aMutex )
255 ,ODatabaseForm_BASE1()
256 ,ODatabaseForm_BASE2()
257 ,ODatabaseForm_BASE3()
258 ,IPropertyBagHelperContext()
259 ,m_aLoadListeners( m_aMutex )
260 ,m_aRowSetApproveListeners( m_aMutex )
261 ,m_aSubmitListeners( m_aMutex )
262 ,m_aErrorListeners( m_aMutex )
263 ,m_aResetListeners( *this, m_aMutex )
264 ,m_aPropertyBagHelper( *this )
265 ,m_aParameterManager( m_aMutex, _cloneSource.m_xContext )
266 ,m_aFilterManager()
267 ,m_nResetsPending( 0 )
268 ,m_nPrivileges( 0 )
269 ,m_bInsertOnly( _cloneSource.m_bInsertOnly )
270 ,m_aControlBorderColorFocus( _cloneSource.m_aControlBorderColorFocus )
271 ,m_aControlBorderColorMouse( _cloneSource.m_aControlBorderColorMouse )
272 ,m_aControlBorderColorInvalid( _cloneSource.m_aControlBorderColorInvalid )
273 ,m_aDynamicControlBorder( _cloneSource.m_aDynamicControlBorder )
274 ,m_sName( _cloneSource.m_sName )
275 ,m_aTargetURL( _cloneSource.m_aTargetURL )
276 ,m_aTargetFrame( _cloneSource.m_aTargetFrame )
277 ,m_eSubmitMethod( _cloneSource.m_eSubmitMethod )
278 ,m_eSubmitEncoding( _cloneSource.m_eSubmitEncoding )
279 ,m_eNavigation( _cloneSource.m_eNavigation )
280 ,m_bAllowInsert( _cloneSource.m_bAllowInsert )
281 ,m_bAllowUpdate( _cloneSource.m_bAllowUpdate )
282 ,m_bAllowDelete( _cloneSource.m_bAllowDelete )
283 ,m_bLoaded( false )
284 ,m_bSubForm( false )
285 ,m_bForwardingConnection( false )
286 ,m_bSharingConnection( false )
289 impl_construct();
291 osl_atomic_increment( &m_refCount );
293 // our aggregated rowset itself is not cloneable, so simply copy the properties
294 ::comphelper::copyProperties( _cloneSource.m_xAggregateSet, m_xAggregateSet );
296 // also care for the dynamic properties: If the clone source has properties which we do not have,
297 // then add them
300 Reference< XPropertySet > xSourceProps( const_cast< ODatabaseForm& >( _cloneSource ).queryAggregation(
301 cppu::UnoType<XPropertySet>::get() ), UNO_QUERY_THROW );
302 Reference< XPropertySetInfo > xSourcePSI( xSourceProps->getPropertySetInfo(), UNO_SET_THROW );
303 Reference< XPropertyState > xSourcePropState( xSourceProps, UNO_QUERY );
305 Reference< XPropertySetInfo > xDestPSI( getPropertySetInfo(), UNO_SET_THROW );
307 const Sequence< Property > aSourceProperties( xSourcePSI->getProperties() );
308 for ( auto const & sourceProperty : aSourceProperties )
310 if ( xDestPSI->hasPropertyByName( sourceProperty.Name ) )
311 continue;
313 // the initial value passed to XPropertyContainer is also used as default, usually. So, try
314 // to retrieve the default of the source property
315 Any aInitialValue;
316 if ( xSourcePropState.is() )
318 aInitialValue = xSourcePropState->getPropertyDefault( sourceProperty.Name );
320 else
322 aInitialValue = xSourceProps->getPropertyValue( sourceProperty.Name );
324 addProperty( sourceProperty.Name, sourceProperty.Attributes, aInitialValue );
325 setPropertyValue( sourceProperty.Name, xSourceProps->getPropertyValue( sourceProperty.Name ) );
328 catch(const RuntimeException&)
330 throw;
332 catch(const Exception&)
334 css::uno::Any a(cppu::getCaughtException());
335 throw WrappedTargetRuntimeException(
336 "Could not clone the given database form.",
337 *const_cast< ODatabaseForm* >( &_cloneSource ),
342 osl_atomic_decrement( &m_refCount );
345 void ODatabaseForm::impl_construct()
347 // aggregate a row set
348 osl_atomic_increment(&m_refCount);
350 m_xAggregate.set( m_xContext->getServiceManager()->createInstanceWithContext(SRV_SDB_ROWSET, m_xContext), UNO_QUERY_THROW );
351 m_xAggregateAsRowSet.set( m_xAggregate, UNO_QUERY_THROW );
352 setAggregation( m_xAggregate );
355 // listen for the properties, important for Parameters
356 if ( m_xAggregateSet.is() )
358 m_xAggregatePropertyMultiplexer = new OPropertyChangeMultiplexer(this, m_xAggregateSet, false);
359 m_xAggregatePropertyMultiplexer->addProperty(PROPERTY_COMMAND);
360 m_xAggregatePropertyMultiplexer->addProperty(PROPERTY_ACTIVE_CONNECTION);
364 Reference< XWarningsSupplier > xRowSetWarnings( m_xAggregate, UNO_QUERY );
365 m_aWarnings.setExternalWarnings( xRowSetWarnings );
368 if ( m_xAggregate.is() )
370 m_xAggregate->setDelegator( static_cast< XWeak* >( this ) );
374 m_aFilterManager.initialize( m_xAggregateSet );
375 m_aParameterManager.initialize( this, m_xAggregate );
377 declareForwardedProperty( PROPERTY_ID_ACTIVE_CONNECTION );
379 osl_atomic_decrement( &m_refCount );
381 m_pGroupManager = new OGroupManager( this );
385 ODatabaseForm::~ODatabaseForm()
387 m_pGroupManager.clear();
389 if (m_xAggregate.is())
390 m_xAggregate->setDelegator( nullptr );
392 m_aWarnings.setExternalWarnings( nullptr );
394 if (m_xAggregatePropertyMultiplexer.is())
396 m_xAggregatePropertyMultiplexer->dispose();
397 m_xAggregatePropertyMultiplexer.clear();
402 // html tools
404 OUString ODatabaseForm::GetDataEncoded(bool _bURLEncoded,const Reference<XControl>& SubmitButton, const css::awt::MouseEvent& MouseEvt)
406 // Fill List of successful Controls
407 HtmlSuccessfulObjList aSuccObjList;
408 FillSuccessfulList( aSuccObjList, SubmitButton, MouseEvt );
411 // Aggregate the list to OUString
412 OUStringBuffer aResult;
413 OUString aName;
414 OUString aValue;
416 for ( HtmlSuccessfulObjList::iterator pSuccObj = aSuccObjList.begin();
417 pSuccObj < aSuccObjList.end();
418 ++pSuccObj
421 aName = pSuccObj->aName;
422 aValue = pSuccObj->aValue;
423 if( pSuccObj->nRepresentation == SUCCESSFUL_REPRESENT_FILE && !aValue.isEmpty() )
425 // For File URLs we transfer the file name and not a URL, because Netscape does it like that
426 INetURLObject aURL;
427 aURL.SetSmartProtocol(INetProtocol::File);
428 aURL.SetSmartURL(aValue);
429 if( INetProtocol::File == aURL.GetProtocol() )
430 aValue = INetURLObject::decode(aURL.PathToFileName(), INetURLObject::DecodeMechanism::Unambiguous);
432 Encode( aName );
433 Encode( aValue );
435 aResult.append(aName);
436 aResult.append('=');
437 aResult.append(aValue);
439 if (pSuccObj < aSuccObjList.end() - 1)
441 if ( _bURLEncoded )
442 aResult.append('&');
443 else
444 aResult.append("\r\n");
449 aSuccObjList.clear();
451 return aResult.makeStringAndClear();
455 // html tools
457 Sequence<sal_Int8> ODatabaseForm::GetDataMultiPartEncoded(const Reference<XControl>& SubmitButton, const css::awt::MouseEvent& MouseEvt, OUString& rContentType)
460 // Create Parent
461 INetMIMEMessage aParent;
462 aParent.EnableAttachMultipartFormDataChild();
465 // Fill List of successful Controls
466 HtmlSuccessfulObjList aSuccObjList;
467 FillSuccessfulList( aSuccObjList, SubmitButton, MouseEvt );
470 // Aggregate List to OUString
471 for (auto const& succObj : aSuccObjList)
473 if( succObj.nRepresentation == SUCCESSFUL_REPRESENT_TEXT )
474 InsertTextPart( aParent, succObj.aName, succObj.aValue );
475 else if( succObj.nRepresentation == SUCCESSFUL_REPRESENT_FILE )
476 InsertFilePart( aParent, succObj.aName, succObj.aValue );
480 // Delete List
481 aSuccObjList.clear();
483 // Create MessageStream for parent
484 INetMIMEMessageStream aMessStream(&aParent, true);
486 // Copy MessageStream to SvStream
487 SvMemoryStream aMemStream;
488 std::unique_ptr<char[]> pBuf(new char[1025]);
489 int nRead;
490 while( (nRead = aMessStream.Read(pBuf.get(), 1024)) > 0 )
492 aMemStream.WriteBytes(pBuf.get(), nRead);
494 pBuf.reset();
496 aMemStream.Flush();
497 aMemStream.Seek( 0 );
498 void const * pData = aMemStream.GetData();
499 sal_Int32 nLen = aMemStream.TellEnd();
501 rContentType = aParent.GetContentType();
502 return Sequence<sal_Int8>(static_cast<sal_Int8 const *>(pData), nLen);
506 namespace
508 void appendDigits( sal_Int32 _nNumber, sal_Int8 nDigits, OUStringBuffer& _rOut )
510 sal_Int32 nCurLen = _rOut.getLength();
511 _rOut.append( _nNumber );
512 while ( _rOut.getLength() - nCurLen < nDigits )
513 _rOut.insert( nCurLen, '0' );
518 void ODatabaseForm::AppendComponent(HtmlSuccessfulObjList& rList, const Reference<XPropertySet>& xComponentSet, const OUString& rNamePrefix,
519 const Reference<XControl>& rxSubmitButton, const css::awt::MouseEvent& MouseEvt)
521 if (!xComponentSet.is())
522 return;
524 // TODO: Catch nested Forms; or would we need to submit them?
525 if (!hasProperty(PROPERTY_CLASSID, xComponentSet))
526 return;
528 // Get names
529 if (!hasProperty(PROPERTY_NAME, xComponentSet))
530 return;
532 sal_Int16 nClassId = 0;
533 xComponentSet->getPropertyValue(PROPERTY_CLASSID) >>= nClassId;
534 OUString aName;
535 xComponentSet->getPropertyValue( PROPERTY_NAME ) >>= aName;
536 if( aName.isEmpty() && nClassId != FormComponentType::IMAGEBUTTON)
537 return;
538 else // Extend name with the prefix
539 aName = rNamePrefix + aName;
541 switch( nClassId )
543 // Buttons
544 case FormComponentType::COMMANDBUTTON:
546 // We only evaluate the pressed Submit button
547 // If one is passed at all
548 if( rxSubmitButton.is() )
550 Reference<XPropertySet> xSubmitButtonComponent(rxSubmitButton->getModel(), UNO_QUERY);
551 if (xSubmitButtonComponent == xComponentSet && hasProperty(PROPERTY_LABEL, xComponentSet))
553 // <name>=<label>
554 OUString aLabel;
555 xComponentSet->getPropertyValue( PROPERTY_LABEL ) >>= aLabel;
556 rList.emplace_back(aName, aLabel );
559 } break;
561 // ImageButtons
562 case FormComponentType::IMAGEBUTTON:
564 // We only evaluate the pressed Submit button
565 // If one is passed at all
566 if( rxSubmitButton.is() )
568 Reference<XPropertySet> xSubmitButtonComponent(rxSubmitButton->getModel(), UNO_QUERY);
569 if (xSubmitButtonComponent == xComponentSet)
571 // <name>.x=<pos.X>&<name>.y=<pos.Y>
572 OUString aRhs = OUString::number( MouseEvt.X );
574 // Only if a name is available we have a name.x
575 OUStringBuffer aLhs(aName);
576 if (!aName.isEmpty())
577 aLhs.append(".x");
578 else
579 aLhs.append("x");
580 rList.emplace_back(aLhs.makeStringAndClear(), aRhs );
582 aLhs.append(aName);
583 aRhs = OUString::number( MouseEvt.Y );
584 if (!aName.isEmpty())
585 aLhs.append(".y");
586 else
587 aLhs.append("y");
588 rList.emplace_back(aLhs.makeStringAndClear(), aRhs );
591 } break;
593 // CheckBoxes/RadioButtons
594 case FormComponentType::CHECKBOX:
595 case FormComponentType::RADIOBUTTON:
597 // <name>=<refValue>
598 if( !hasProperty(PROPERTY_STATE, xComponentSet) )
599 break;
600 sal_Int16 nChecked = 0;
601 xComponentSet->getPropertyValue( PROPERTY_STATE ) >>= nChecked;
602 if( nChecked != 1 )
603 break;
605 OUString aStrValue;
606 if( hasProperty(PROPERTY_REFVALUE, xComponentSet) )
607 xComponentSet->getPropertyValue( PROPERTY_REFVALUE ) >>= aStrValue;
609 rList.emplace_back(aName, aStrValue );
610 } break;
612 // Edit
613 case FormComponentType::TEXTFIELD:
615 // <name>=<text>
616 if( !hasProperty(PROPERTY_TEXT, xComponentSet) )
617 break;
619 // Special treatment for multiline edit only if we have a control for it
620 Any aTmp = xComponentSet->getPropertyValue( PROPERTY_MULTILINE );
621 bool bMulti = rxSubmitButton.is()
622 && (aTmp.getValueType().getTypeClass() == TypeClass_BOOLEAN)
623 && getBOOL(aTmp);
624 OUString sText;
625 if ( bMulti ) // For multiline edit, get the text at the control
628 Reference<XControlContainer> xControlContainer(rxSubmitButton->getContext(), UNO_QUERY);
629 if( !xControlContainer.is() ) break;
631 // Find the right control
632 bool bFound = false;
633 const Sequence<Reference<XControl>> aControls = xControlContainer->getControls();
634 for( auto const& xControl : aControls )
636 Reference<XPropertySet> xModel(xControl->getModel(), UNO_QUERY);
637 if ((bFound = xModel == xComponentSet))
639 Reference<XTextComponent> xTextComponent(xControl, UNO_QUERY);
640 if( xTextComponent.is() )
641 sText = xTextComponent->getText();
642 break;
645 // Couldn't find control or it does not exist (edit in the grid)
646 if (!bFound)
647 xComponentSet->getPropertyValue( PROPERTY_TEXT ) >>= sText;
649 else
650 xComponentSet->getPropertyValue( PROPERTY_TEXT ) >>= sText;
652 rList.emplace_back(aName, sText );
653 } break;
655 // ComboBox, Patternfield
656 case FormComponentType::COMBOBOX:
657 case FormComponentType::PATTERNFIELD:
659 // <name>=<text>
660 if( hasProperty(PROPERTY_TEXT, xComponentSet) )
662 OUString aText;
663 xComponentSet->getPropertyValue( PROPERTY_TEXT ) >>= aText;
664 rList.emplace_back(aName, aText );
666 } break;
667 case FormComponentType::CURRENCYFIELD:
668 case FormComponentType::NUMERICFIELD:
670 // <name>=<value> // Value is a double with dot as decimal delimiter
671 // no value (NULL) means empty value
672 if( hasProperty(PROPERTY_VALUE, xComponentSet) )
674 OUString aText;
675 Any aVal = xComponentSet->getPropertyValue( PROPERTY_VALUE );
677 double aDoubleVal = 0;
678 if (aVal >>= aDoubleVal)
680 sal_Int16 nScale = 0;
681 xComponentSet->getPropertyValue( PROPERTY_DECIMAL_ACCURACY ) >>= nScale;
682 aText = ::rtl::math::doubleToUString(aDoubleVal, rtl_math_StringFormat_F, nScale, '.', true);
684 rList.emplace_back(aName, aText );
686 } break;
687 case FormComponentType::DATEFIELD:
689 // <name>=<value> // Value is a Date with the format MM-DD-YYYY
690 // no value (NULL) means empty value
691 if( hasProperty(PROPERTY_DATE, xComponentSet) )
693 OUString aText;
694 Any aVal = xComponentSet->getPropertyValue( PROPERTY_DATE );
695 sal_Int32 nInt32Val = 0;
696 if (aVal >>= nInt32Val)
698 ::Date aDate( nInt32Val );
699 OUStringBuffer aBuffer;
700 appendDigits( aDate.GetMonth(), 2, aBuffer );
701 aBuffer.append( '-' );
702 appendDigits( aDate.GetDay(), 2, aBuffer );
703 aBuffer.append( '-' );
704 appendDigits( aDate.GetYear(), 4, aBuffer );
705 aText = aBuffer.makeStringAndClear();
707 rList.emplace_back(aName, aText );
709 } break;
710 case FormComponentType::TIMEFIELD:
712 // <name>=<value> // Value is a Time with the format HH:MM:SS
713 // no value (NULL) means empty value
714 if( hasProperty(PROPERTY_TIME, xComponentSet) )
716 OUString aText;
717 Any aVal = xComponentSet->getPropertyValue( PROPERTY_TIME );
718 sal_Int32 nInt32Val = 0;
719 if (aVal >>= nInt32Val)
721 ::tools::Time aTime(nInt32Val);
722 OUStringBuffer aBuffer;
723 appendDigits( aTime.GetHour(), 2, aBuffer );
724 aBuffer.append( '-' );
725 appendDigits( aTime.GetMin(), 2, aBuffer );
726 aBuffer.append( '-' );
727 appendDigits( aTime.GetSec(), 2, aBuffer );
728 aText = aBuffer.makeStringAndClear();
730 rList.emplace_back(aName, aText );
732 } break;
734 // starform
735 case FormComponentType::HIDDENCONTROL:
738 // <name>=<value>
739 if( hasProperty(PROPERTY_HIDDEN_VALUE, xComponentSet) )
741 OUString aText;
742 xComponentSet->getPropertyValue( PROPERTY_HIDDEN_VALUE ) >>= aText;
743 rList.emplace_back(aName, aText );
745 } break;
747 // starform
748 case FormComponentType::FILECONTROL:
750 // <name>=<text>
751 if( hasProperty(PROPERTY_TEXT, xComponentSet) )
754 OUString aText;
755 xComponentSet->getPropertyValue( PROPERTY_TEXT ) >>= aText;
756 rList.emplace_back(aName, aText, SUCCESSFUL_REPRESENT_FILE );
758 } break;
760 // starform
761 case FormComponentType::LISTBOX:
764 // <name>=<Token0>&<name>=<Token1>&...&<name>=<TokenN> (multiple selection)
765 if (!hasProperty(PROPERTY_SELECT_SEQ, xComponentSet) ||
766 !hasProperty(PROPERTY_STRINGITEMLIST, xComponentSet))
767 break;
769 // Displayed values
770 Sequence< OUString > aVisibleList;
771 xComponentSet->getPropertyValue( PROPERTY_STRINGITEMLIST ) >>= aVisibleList;
772 sal_Int32 nStringCnt = aVisibleList.getLength();
773 const OUString* pStrings = aVisibleList.getConstArray();
775 // Value list
776 Sequence< OUString > aValueList;
777 xComponentSet->getPropertyValue( PROPERTY_VALUE_SEQ ) >>= aValueList;
778 sal_Int32 nValCnt = aValueList.getLength();
779 const OUString* pVals = aValueList.getConstArray();
781 // Selection
782 Sequence<sal_Int16> aSelectList;
783 xComponentSet->getPropertyValue( PROPERTY_SELECT_SEQ ) >>= aSelectList;
784 sal_Int32 nSelCount = aSelectList.getLength();
785 const sal_Int16* pSels = aSelectList.getConstArray();
787 // Simple or multiple selection
788 // For simple selections MT only accounts for the list's first entry.
789 if (nSelCount > 1 && !getBOOL(xComponentSet->getPropertyValue(PROPERTY_MULTISELECTION)))
790 nSelCount = 1;
792 // The indices in the selection list can also be invalid, so we first have to
793 // find the valid ones to determine the length of the new list.
794 sal_Int32 nCurCnt = 0;
795 sal_Int32 i;
796 for( i=0; i<nSelCount; ++i )
798 if( pSels[i] < nStringCnt )
799 ++nCurCnt;
802 OUString aSubValue;
803 for(i=0; i<nCurCnt; ++i )
805 sal_Int16 nSelPos = pSels[i];
806 if (nSelPos < nValCnt && !pVals[nSelPos].isEmpty())
808 aSubValue = pVals[nSelPos];
810 else
812 aSubValue = pStrings[nSelPos];
814 rList.emplace_back(aName, aSubValue );
816 } break;
817 case FormComponentType::GRIDCONTROL:
819 // Each of the column values is sent;
820 // the name is extended by the grid's prefix.
821 Reference<XIndexAccess> xContainer(xComponentSet, UNO_QUERY);
822 if (!xContainer.is())
823 break;
825 aName += ".";
827 Reference<XPropertySet> xSet;
828 sal_Int32 nCount = xContainer->getCount();
829 // we know already how many objects should be appended,
830 // so why not allocate the space for them
831 rList.reserve( nCount + rList.capacity() ); // not size()
832 for (sal_Int32 i = 0; i < nCount; ++i)
834 xContainer->getByIndex(i) >>= xSet;
835 if (xSet.is())
836 AppendComponent(rList, xSet, aName, rxSubmitButton, MouseEvt);
843 void ODatabaseForm::FillSuccessfulList( HtmlSuccessfulObjList& rList,
844 const Reference<XControl>& rxSubmitButton, const css::awt::MouseEvent& MouseEvt )
846 // Delete list
847 rList.clear();
848 // Iterate over Components
849 Reference<XPropertySet> xComponentSet;
851 // we know already how many objects should be appended,
852 // so why not allocate the space for them
853 rList.reserve( getCount() );
854 for( sal_Int32 nIndex=0; nIndex < getCount(); nIndex++ )
856 getByIndex( nIndex ) >>= xComponentSet;
857 AppendComponent(rList, xComponentSet, OUString(), rxSubmitButton, MouseEvt);
862 void ODatabaseForm::Encode( OUString& rString )
864 OUStringBuffer aResult;
866 // Line endings are represented as CR
867 rString = convertLineEnd(rString, LINEEND_CR);
869 // Check each character
870 sal_Int32 nStrLen = rString.getLength();
871 sal_Unicode nCharCode;
872 for( sal_Int32 nCurPos=0; nCurPos < nStrLen; ++nCurPos )
874 nCharCode = rString[nCurPos];
876 // Handle chars, which are not an alphanumeric character and character codes > 127
877 if( (!rtl::isAsciiAlphanumeric(nCharCode) && nCharCode != ' ')
878 || nCharCode > 127 )
880 switch( nCharCode )
882 case 13: // CR
883 aResult.append("%0D%0A"); // CR LF in hex
884 break;
887 // Special treatment for Netscape
888 case 42: // '*'
889 case 45: // '-'
890 case 46: // '.'
891 case 64: // '@'
892 case 95: // '_'
893 aResult.append(nCharCode);
894 break;
896 default:
898 // Convert to hex
899 short nHi = static_cast<sal_Int16>(nCharCode) / 16;
900 short nLo = static_cast<sal_Int16>(nCharCode) - (nHi*16);
901 if( nHi > 9 ) nHi += int('A')-10; else nHi += int('0');
902 if( nLo > 9 ) nLo += int('A')-10; else nLo += int('0');
903 aResult.append('%');
904 aResult.append(static_cast<sal_Unicode>(nHi));
905 aResult.append(static_cast<sal_Unicode>(nLo));
909 else
910 aResult.append(nCharCode);
913 // Replace spaces with '+'
914 rString = aResult.makeStringAndClear().replace(' ', '+');
918 void ODatabaseForm::InsertTextPart( INetMIMEMessage& rParent, const OUString& rName,
919 const OUString& rData )
921 // Create part as MessageChild
922 std::unique_ptr<INetMIMEMessage> pChild(new INetMIMEMessage);
924 // Header
925 //TODO: Encode rName into a properly formatted Content-Disposition header
926 // field as per RFC 2231:
927 OUString aContentDisp = "form-data; name=\"" + rName + "\"";
928 pChild->SetContentDisposition(aContentDisp);
930 rtl_TextEncoding eSystemEncoding = osl_getThreadTextEncoding();
931 const char* pBestMatchingEncoding = rtl_getBestMimeCharsetFromTextEncoding( eSystemEncoding );
932 OUString aBestMatchingEncoding = OUString::createFromAscii(pBestMatchingEncoding);
933 pChild->SetContentType(
934 "text/plain; charset=\"" + aBestMatchingEncoding + "\"");
935 pChild->SetContentTransferEncoding("8bit");
937 // Body
938 SvMemoryStream* pStream = new SvMemoryStream;
939 pStream->WriteLine( OUStringToOString(rData, rtl_getTextEncodingFromMimeCharset(pBestMatchingEncoding)) );
940 pStream->Flush();
941 pStream->Seek( 0 );
942 pChild->SetDocumentLB( new SvLockBytes(pStream, true) );
943 rParent.AttachChild( std::move(pChild) );
947 void ODatabaseForm::InsertFilePart( INetMIMEMessage& rParent, const OUString& rName,
948 const OUString& rFileName )
950 OUString aFileName(rFileName);
951 OUString aContentType(CONTENT_TYPE_STR_TEXT_PLAIN);
952 std::unique_ptr<SvStream> pStream;
954 if (!aFileName.isEmpty())
956 // We can only process File URLs yet
957 INetURLObject aURL;
958 aURL.SetSmartProtocol(INetProtocol::File);
959 aURL.SetSmartURL(rFileName);
960 if( INetProtocol::File == aURL.GetProtocol() )
962 aFileName = INetURLObject::decode(aURL.PathToFileName(), INetURLObject::DecodeMechanism::Unambiguous);
963 pStream = ::utl::UcbStreamHelper::CreateStream(aFileName, StreamMode::READ);
964 if (!pStream || (pStream->GetError() != ERRCODE_NONE))
966 pStream.reset();
968 sal_Int32 nSepInd = aFileName.lastIndexOf('.');
969 OUString aExtension = aFileName.copy( nSepInd + 1 );
970 INetContentType eContentType = INetContentTypes::GetContentType4Extension( aExtension );
971 if (eContentType != CONTENT_TYPE_UNKNOWN)
972 aContentType = INetContentTypes::GetContentType(eContentType);
976 // If something didn't work, we create an empty MemoryStream
977 if( !pStream )
978 pStream.reset( new SvMemoryStream );
981 // Create part as MessageChild
982 std::unique_ptr<INetMIMEMessage> pChild(new INetMIMEMessage);
985 // Header
986 //TODO: Encode rName and aFileName into a properly formatted
987 // Content-Disposition header field as per RFC 2231:
988 OUString aContentDisp =
989 "form-data; name=\"" +
990 rName +
991 "\""
992 "; filename=\"" +
993 aFileName +
994 "\"";
995 pChild->SetContentDisposition(aContentDisp);
996 pChild->SetContentType( aContentType );
997 pChild->SetContentTransferEncoding("8bit");
1000 // Body
1001 pChild->SetDocumentLB( new SvLockBytes(pStream.release(), true) );
1002 rParent.AttachChild( std::move(pChild) );
1006 // internals
1008 void ODatabaseForm::onError( const SQLErrorEvent& _rEvent )
1010 m_aErrorListeners.notifyEach( &XSQLErrorListener::errorOccured, _rEvent );
1014 void ODatabaseForm::onError( const SQLException& _rException, const OUString& _rContextDescription )
1016 if ( !m_aErrorListeners.getLength() )
1017 return;
1019 SQLErrorEvent aEvent( *this, makeAny( prependErrorInfo( _rException, *this, _rContextDescription ) ) );
1020 onError( aEvent );
1024 void ODatabaseForm::updateParameterInfo()
1026 m_aParameterManager.updateParameterInfo( m_aFilterManager );
1030 bool ODatabaseForm::hasValidParent() const
1032 // do we have to fill the parameters again?
1033 if (m_bSubForm)
1035 Reference<XResultSet> xResultSet(m_xParent, UNO_QUERY);
1036 if (!xResultSet.is())
1038 OSL_FAIL("ODatabaseForm::hasValidParent() : no parent resultset !");
1039 return false;
1043 Reference< XPropertySet > xSet( m_xParent, UNO_QUERY );
1044 Reference< XLoadable > xLoad( m_xParent, UNO_QUERY );
1045 if ( xLoad->isLoaded()
1046 && ( xResultSet->isBeforeFirst()
1047 || xResultSet->isAfterLast()
1048 || getBOOL( xSet->getPropertyValue( PROPERTY_ISNEW ) )
1051 // the parent form is loaded and on a "virtual" row -> not valid
1052 return false;
1054 catch(const Exception&)
1056 // parent could be forwardonly?
1057 return false;
1060 return true;
1064 bool ODatabaseForm::fillParameters( ::osl::ResettableMutexGuard& _rClearForNotifies, const Reference< XInteractionHandler >& _rxCompletionHandler )
1066 // do we have to fill the parameters again?
1067 if ( !m_aParameterManager.isUpToDate() )
1068 updateParameterInfo();
1070 // is there a valid parent?
1071 if ( m_bSubForm && !hasValidParent() )
1072 return true;
1074 // ensure we're connected
1075 if ( !implEnsureConnection() )
1076 return false;
1078 if ( m_aParameterManager.isUpToDate() )
1079 return m_aParameterManager.fillParameterValues( _rxCompletionHandler, _rClearForNotifies );
1081 return true;
1085 void ODatabaseForm::saveInsertOnlyState( )
1087 OSL_ENSURE( !m_aIgnoreResult.hasValue(), "ODatabaseForm::saveInsertOnlyState: overriding old value!" );
1088 m_aIgnoreResult = m_xAggregateSet->getPropertyValue( PROPERTY_INSERTONLY );
1092 void ODatabaseForm::restoreInsertOnlyState( )
1094 if ( m_aIgnoreResult.hasValue() )
1096 m_xAggregateSet->setPropertyValue( PROPERTY_INSERTONLY, m_aIgnoreResult );
1097 m_aIgnoreResult = Any();
1102 bool ODatabaseForm::executeRowSet(::osl::ResettableMutexGuard& _rClearForNotifies, bool bMoveToFirst, const Reference< XInteractionHandler >& _rxCompletionHandler)
1104 if (!m_xAggregateAsRowSet.is())
1105 return false;
1107 if (!fillParameters(_rClearForNotifies, _rxCompletionHandler))
1108 return false;
1110 restoreInsertOnlyState( );
1112 // ensure the aggregated row set has the correct properties
1113 sal_Int32 nConcurrency = ResultSetConcurrency::READ_ONLY;
1115 // if we have a parent, who is not positioned on a valid row
1116 // we can't be updatable!
1117 if (m_bSubForm && !hasValidParent())
1119 nConcurrency = ResultSetConcurrency::READ_ONLY;
1121 // don't use any parameters if we don't have a valid parent
1122 m_aParameterManager.setAllParametersNull();
1124 // switch to "insert only" mode
1125 saveInsertOnlyState( );
1126 m_xAggregateSet->setPropertyValue( PROPERTY_INSERTONLY, makeAny( true ) );
1128 else if (m_bAllowInsert || m_bAllowUpdate || m_bAllowDelete)
1129 nConcurrency = ResultSetConcurrency::UPDATABLE;
1130 else
1131 nConcurrency = ResultSetConcurrency::READ_ONLY;
1133 m_xAggregateSet->setPropertyValue( PROPERTY_RESULTSET_CONCURRENCY, makeAny( nConcurrency ) );
1134 m_xAggregateSet->setPropertyValue( PROPERTY_RESULTSET_TYPE, makeAny( sal_Int32(ResultSetType::SCROLL_SENSITIVE) ) );
1136 bool bSuccess = false;
1139 m_xAggregateAsRowSet->execute();
1140 bSuccess = true;
1142 catch(const RowSetVetoException&)
1145 catch(const SQLException& eDb)
1147 _rClearForNotifies.clear();
1148 if (!m_sCurrentErrorContext.isEmpty())
1149 onError(eDb, m_sCurrentErrorContext);
1150 else
1151 onError(eDb, FRM_RES_STRING(RID_STR_READERROR));
1152 _rClearForNotifies.reset();
1154 restoreInsertOnlyState( );
1157 if (bSuccess)
1159 // adjust the privilege property
1160 // m_nPrivileges;
1161 m_xAggregateSet->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
1162 if (!m_bAllowInsert)
1163 m_nPrivileges &= ~Privilege::INSERT;
1164 if (!m_bAllowUpdate)
1165 m_nPrivileges &= ~Privilege::UPDATE;
1166 if (!m_bAllowDelete)
1167 m_nPrivileges &= ~Privilege::DELETE;
1169 if (bMoveToFirst)
1171 // the row set is positioned _before_ the first row (per definitionem), so move the set ...
1174 // if we have an insert only rowset we move to the insert row
1175 next();
1176 if (((m_nPrivileges & Privilege::INSERT) == Privilege::INSERT)
1177 && isAfterLast())
1179 // move on the insert row of set
1180 // resetting must be done later, after the load events have been posted
1181 // see: moveToInsertRow and load , reload
1182 Reference<XResultSetUpdate> xUpdate;
1183 if (query_aggregation( m_xAggregate, xUpdate))
1184 xUpdate->moveToInsertRow();
1187 catch(const SQLException& eDB)
1189 _rClearForNotifies.clear();
1190 if (!m_sCurrentErrorContext.isEmpty())
1191 onError(eDB, m_sCurrentErrorContext);
1192 else
1193 onError(eDB, FRM_RES_STRING(RID_STR_READERROR));
1194 _rClearForNotifies.reset();
1195 bSuccess = false;
1199 return bSuccess;
1203 void ODatabaseForm::disposing()
1205 if (m_xAggregatePropertyMultiplexer.is())
1206 m_xAggregatePropertyMultiplexer->dispose();
1208 if (m_bLoaded)
1209 unload();
1211 // cancel the submit/reset-thread
1213 ::osl::MutexGuard aGuard( m_aMutex );
1214 m_pThread.clear();
1217 EventObject aEvt(static_cast<XWeak*>(this));
1218 m_aLoadListeners.disposeAndClear(aEvt);
1219 m_aRowSetApproveListeners.disposeAndClear(aEvt);
1220 m_aResetListeners.disposing();
1221 m_aSubmitListeners.disposeAndClear(aEvt);
1222 m_aErrorListeners.disposeAndClear(aEvt);
1224 m_aParameterManager.dispose(); // To free any references it may have to be me
1225 m_aFilterManager.dispose(); // (ditto)
1227 OFormComponents::disposing();
1228 OPropertySetAggregationHelper::disposing();
1230 // stop listening on the aggregate
1231 if (m_xAggregateAsRowSet.is())
1232 m_xAggregateAsRowSet->removeRowSetListener(this);
1234 // dispose the active connection
1235 Reference<XComponent> xAggregationComponent;
1236 if (query_aggregation(m_xAggregate, xAggregationComponent))
1237 xAggregationComponent->dispose();
1239 m_aPropertyBagHelper.dispose();
1243 Reference< XConnection > ODatabaseForm::getConnection()
1245 Reference< XConnection > xConn;
1246 m_xAggregateSet->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConn;
1247 return xConn;
1251 ::osl::Mutex& ODatabaseForm::getMutex()
1253 return m_aMutex;
1257 // property handling
1259 void ODatabaseForm::describeFixedAndAggregateProperties(
1260 Sequence< Property >& _rProps,
1261 Sequence< Property >& _rAggregateProps ) const
1263 _rProps.realloc( 23 );
1264 css::beans::Property* pProperties = _rProps.getArray();
1266 if (m_xAggregateSet.is())
1267 _rAggregateProps = m_xAggregateSet->getPropertySetInfo()->getProperties();
1270 // we want to "override" the privileges, since we have additional "AllowInsert" etc. properties
1271 RemoveProperty( _rAggregateProps, PROPERTY_PRIVILEGES );
1273 // InsertOnly is also to be overridden, since we sometimes change it ourself
1274 RemoveProperty( _rAggregateProps, PROPERTY_INSERTONLY );
1276 // we remove and re-declare the DataSourceName property, 'cause we want it to be constrained, and the
1277 // original property of our aggregate isn't
1278 RemoveProperty( _rAggregateProps, PROPERTY_DATASOURCE );
1280 // for connection sharing, we need to override the ActiveConnection property, too
1281 RemoveProperty( _rAggregateProps, PROPERTY_ACTIVE_CONNECTION );
1283 // the Filter property is also overwritten, since we have some implicit filters
1284 // (e.g. the ones which result from linking master fields to detail fields
1285 // via column names instead of parameters)
1286 RemoveProperty( _rAggregateProps, PROPERTY_FILTER );
1287 RemoveProperty( _rAggregateProps, PROPERTY_HAVINGCLAUSE );
1288 RemoveProperty( _rAggregateProps, PROPERTY_APPLYFILTER );
1290 DECL_IFACE_PROP4( ACTIVE_CONNECTION,XConnection, BOUND, TRANSIENT, MAYBEVOID, CONSTRAINED);
1291 DECL_BOOL_PROP2 ( APPLYFILTER, BOUND, MAYBEDEFAULT );
1292 DECL_PROP1 ( NAME, OUString, BOUND );
1293 DECL_PROP1 ( MASTERFIELDS, Sequence< OUString >, BOUND );
1294 DECL_PROP1 ( DETAILFIELDS, Sequence< OUString >, BOUND );
1295 DECL_PROP2 ( DATASOURCE, OUString, BOUND, CONSTRAINED );
1296 DECL_PROP3 ( CYCLE, TabulatorCycle, BOUND, MAYBEVOID, MAYBEDEFAULT );
1297 DECL_PROP2 ( FILTER, OUString, BOUND, MAYBEDEFAULT );
1298 DECL_PROP2 ( HAVINGCLAUSE, OUString, BOUND, MAYBEDEFAULT );
1299 DECL_BOOL_PROP2 ( INSERTONLY, BOUND, MAYBEDEFAULT );
1300 DECL_PROP1 ( NAVIGATION, NavigationBarMode, BOUND );
1301 DECL_BOOL_PROP1 ( ALLOWADDITIONS, BOUND );
1302 DECL_BOOL_PROP1 ( ALLOWEDITS, BOUND );
1303 DECL_BOOL_PROP1 ( ALLOWDELETIONS, BOUND );
1304 DECL_PROP2 ( PRIVILEGES, sal_Int32, TRANSIENT, READONLY );
1305 DECL_PROP1 ( TARGET_URL, OUString, BOUND );
1306 DECL_PROP1 ( TARGET_FRAME, OUString, BOUND );
1307 DECL_PROP1 ( SUBMIT_METHOD, FormSubmitMethod, BOUND );
1308 DECL_PROP1 ( SUBMIT_ENCODING, FormSubmitEncoding, BOUND );
1309 DECL_BOOL_PROP3 ( DYNAMIC_CONTROL_BORDER, BOUND, MAYBEVOID, MAYBEDEFAULT );
1310 DECL_PROP3 ( CONTROL_BORDER_COLOR_FOCUS, sal_Int32, BOUND, MAYBEVOID, MAYBEDEFAULT );
1311 DECL_PROP3 ( CONTROL_BORDER_COLOR_MOUSE, sal_Int32, BOUND, MAYBEVOID, MAYBEDEFAULT );
1312 DECL_PROP3 ( CONTROL_BORDER_COLOR_INVALID, sal_Int32, BOUND, MAYBEVOID, MAYBEDEFAULT );
1313 END_DESCRIBE_PROPERTIES();
1317 Reference< XMultiPropertySet > ODatabaseForm::getPropertiesInterface()
1319 return Reference< XMultiPropertySet >( *this, UNO_QUERY );
1323 ::cppu::IPropertyArrayHelper& ODatabaseForm::getInfoHelper()
1325 return m_aPropertyBagHelper.getInfoHelper();
1329 Reference< XPropertySetInfo > ODatabaseForm::getPropertySetInfo()
1331 return createPropertySetInfo( getInfoHelper() );
1335 void SAL_CALL ODatabaseForm::addProperty( const OUString& _rName, ::sal_Int16 _nAttributes, const Any& _rInitialValue )
1337 m_aPropertyBagHelper.addProperty( _rName, _nAttributes, _rInitialValue );
1341 void SAL_CALL ODatabaseForm::removeProperty( const OUString& _rName )
1343 m_aPropertyBagHelper.removeProperty( _rName );
1347 Sequence< PropertyValue > SAL_CALL ODatabaseForm::getPropertyValues()
1349 return m_aPropertyBagHelper.getPropertyValues();
1353 void SAL_CALL ODatabaseForm::setPropertyValues( const Sequence< PropertyValue >& _rProps )
1355 m_aPropertyBagHelper.setPropertyValues( _rProps );
1359 Any SAL_CALL ODatabaseForm::getWarnings( )
1361 return m_aWarnings.getWarnings();
1365 void SAL_CALL ODatabaseForm::clearWarnings( )
1367 m_aWarnings.clearWarnings();
1371 Reference< XCloneable > SAL_CALL ODatabaseForm::createClone( )
1373 ODatabaseForm* pClone = new ODatabaseForm( *this );
1374 osl_atomic_increment( &pClone->m_refCount );
1375 pClone->clonedFrom( *this );
1376 osl_atomic_decrement( &pClone->m_refCount );
1377 return pClone;
1381 void ODatabaseForm::fire( sal_Int32* pnHandles, const Any* pNewValues, const Any* pOldValues, sal_Int32 nCount )
1383 // same as in getFastPropertyValue(sal_Int32) : if we're resetting currently don't fire any changes of the
1384 // IsModified property from sal_False to sal_True, as this is only temporary 'til the reset is done
1385 if (m_nResetsPending > 0)
1387 // look for the PROPERTY_ID_ISMODIFIED
1388 sal_Int32 nPos = 0;
1389 for (nPos=0; nPos<nCount; ++nPos)
1390 if (pnHandles[nPos] == PROPERTY_ID_ISMODIFIED)
1391 break;
1393 if ((nPos < nCount) && (pNewValues[nPos].getValueType().getTypeClass() == TypeClass_BOOLEAN) && getBOOL(pNewValues[nPos]))
1394 { // yeah, we found it, and it changed to TRUE
1395 if (nPos == 0)
1396 { // just cut the first element
1397 ++pnHandles;
1398 ++pNewValues;
1399 ++pOldValues;
1400 --nCount;
1402 else if (nPos == nCount - 1)
1403 // just cut the last element
1404 --nCount;
1405 else
1406 { // split into two base class calls
1407 OPropertySetAggregationHelper::fire(pnHandles, pNewValues, pOldValues, nPos, false/*bVetoable*/);
1408 ++nPos;
1409 OPropertySetAggregationHelper::fire(pnHandles + nPos, pNewValues + nPos, pOldValues + nPos, nCount - nPos, false/*bVetoable*/);
1410 return;
1415 OPropertySetAggregationHelper::fire(pnHandles, pNewValues, pOldValues, nCount, false/*bVetoable*/);
1419 Any SAL_CALL ODatabaseForm::getFastPropertyValue( sal_Int32 nHandle )
1421 if ((nHandle == PROPERTY_ID_ISMODIFIED) && (m_nResetsPending > 0))
1422 return css::uno::Any(false);
1423 // don't allow the aggregate which is currently being reset to return a (temporary) "yes"
1424 else
1425 return OPropertySetAggregationHelper::getFastPropertyValue(nHandle);
1429 void ODatabaseForm::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
1431 switch (nHandle)
1433 case PROPERTY_ID_INSERTONLY:
1434 rValue <<= m_bInsertOnly;
1435 break;
1437 case PROPERTY_ID_FILTER:
1438 rValue <<= m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicFilter );
1439 break;
1441 case PROPERTY_ID_HAVINGCLAUSE:
1442 rValue <<= m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicHaving );
1443 break;
1445 case PROPERTY_ID_APPLYFILTER:
1446 rValue <<= m_aFilterManager.isApplyPublicFilter();
1447 break;
1449 case PROPERTY_ID_DATASOURCE:
1450 rValue = m_xAggregateSet->getPropertyValue( PROPERTY_DATASOURCE );
1451 break;
1453 case PROPERTY_ID_TARGET_URL:
1454 rValue <<= m_aTargetURL;
1455 break;
1456 case PROPERTY_ID_TARGET_FRAME:
1457 rValue <<= m_aTargetFrame;
1458 break;
1459 case PROPERTY_ID_SUBMIT_METHOD:
1460 rValue <<= m_eSubmitMethod;
1461 break;
1462 case PROPERTY_ID_SUBMIT_ENCODING:
1463 rValue <<= m_eSubmitEncoding;
1464 break;
1465 case PROPERTY_ID_NAME:
1466 rValue <<= m_sName;
1467 break;
1468 case PROPERTY_ID_MASTERFIELDS:
1469 rValue <<= m_aMasterFields;
1470 break;
1471 case PROPERTY_ID_DETAILFIELDS:
1472 rValue <<= m_aDetailFields;
1473 break;
1474 case PROPERTY_ID_CYCLE:
1475 rValue = m_aCycle;
1476 break;
1477 case PROPERTY_ID_NAVIGATION:
1478 rValue <<= m_eNavigation;
1479 break;
1480 case PROPERTY_ID_ALLOWADDITIONS:
1481 rValue <<= m_bAllowInsert;
1482 break;
1483 case PROPERTY_ID_ALLOWEDITS:
1484 rValue <<= m_bAllowUpdate;
1485 break;
1486 case PROPERTY_ID_ALLOWDELETIONS:
1487 rValue <<= m_bAllowDelete;
1488 break;
1489 case PROPERTY_ID_PRIVILEGES:
1490 rValue <<= m_nPrivileges;
1491 break;
1492 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1493 rValue = m_aDynamicControlBorder;
1494 break;
1495 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1496 rValue = m_aControlBorderColorFocus;
1497 break;
1498 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1499 rValue = m_aControlBorderColorMouse;
1500 break;
1501 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1502 rValue = m_aControlBorderColorInvalid;
1503 break;
1504 default:
1505 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( nHandle ) )
1506 m_aPropertyBagHelper.getDynamicFastPropertyValue( nHandle, rValue );
1507 else
1508 OPropertySetAggregationHelper::getFastPropertyValue( rValue, nHandle );
1509 break;
1513 sal_Bool ODatabaseForm::convertFastPropertyValue( Any& rConvertedValue, Any& rOldValue,
1514 sal_Int32 nHandle, const Any& rValue )
1516 bool bModified(false);
1517 switch (nHandle)
1519 case PROPERTY_ID_INSERTONLY:
1520 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_bInsertOnly );
1521 break;
1523 case PROPERTY_ID_FILTER:
1524 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicFilter ) );
1525 break;
1527 case PROPERTY_ID_HAVINGCLAUSE:
1528 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicHaving ) );
1529 break;
1531 case PROPERTY_ID_APPLYFILTER:
1532 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aFilterManager.isApplyPublicFilter() );
1533 break;
1535 case PROPERTY_ID_DATASOURCE:
1537 Any aAggregateProperty;
1538 getFastPropertyValue(aAggregateProperty, PROPERTY_ID_DATASOURCE);
1539 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, aAggregateProperty, cppu::UnoType<OUString>::get());
1541 break;
1542 case PROPERTY_ID_TARGET_URL:
1543 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aTargetURL);
1544 break;
1545 case PROPERTY_ID_TARGET_FRAME:
1546 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aTargetFrame);
1547 break;
1548 case PROPERTY_ID_SUBMIT_METHOD:
1549 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_eSubmitMethod);
1550 break;
1551 case PROPERTY_ID_SUBMIT_ENCODING:
1552 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_eSubmitEncoding);
1553 break;
1554 case PROPERTY_ID_NAME:
1555 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_sName);
1556 break;
1557 case PROPERTY_ID_MASTERFIELDS:
1558 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aMasterFields);
1559 break;
1560 case PROPERTY_ID_DETAILFIELDS:
1561 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aDetailFields);
1562 break;
1563 case PROPERTY_ID_CYCLE:
1564 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aCycle, cppu::UnoType<TabulatorCycle>::get());
1565 break;
1566 case PROPERTY_ID_NAVIGATION:
1567 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_eNavigation);
1568 break;
1569 case PROPERTY_ID_ALLOWADDITIONS:
1570 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAllowInsert);
1571 break;
1572 case PROPERTY_ID_ALLOWEDITS:
1573 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAllowUpdate);
1574 break;
1575 case PROPERTY_ID_ALLOWDELETIONS:
1576 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAllowDelete);
1577 break;
1578 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1579 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aDynamicControlBorder, cppu::UnoType<bool>::get() );
1580 break;
1581 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1582 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aControlBorderColorFocus, cppu::UnoType<sal_Int32>::get() );
1583 break;
1584 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1585 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aControlBorderColorMouse, cppu::UnoType<sal_Int32>::get() );
1586 break;
1587 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1588 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aControlBorderColorInvalid, cppu::UnoType<sal_Int32>::get() );
1589 break;
1590 default:
1591 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle ( nHandle ) )
1592 bModified = m_aPropertyBagHelper.convertDynamicFastPropertyValue( nHandle, rValue, rConvertedValue, rOldValue );
1593 else
1594 bModified = OPropertySetAggregationHelper::convertFastPropertyValue( rConvertedValue, rOldValue, nHandle, rValue );
1595 break;
1597 return bModified;
1600 void ODatabaseForm::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
1602 switch (nHandle)
1604 case PROPERTY_ID_INSERTONLY:
1605 rValue >>= m_bInsertOnly;
1606 if ( m_aIgnoreResult.hasValue() )
1607 m_aIgnoreResult <<= m_bInsertOnly;
1608 else
1609 m_xAggregateSet->setPropertyValue( PROPERTY_INSERTONLY, makeAny( m_bInsertOnly ) );
1610 break;
1612 case PROPERTY_ID_FILTER:
1614 OUString sNewFilter;
1615 rValue >>= sNewFilter;
1616 m_aFilterManager.setFilterComponent( FilterManager::FilterComponent::PublicFilter, sNewFilter );
1618 break;
1620 case PROPERTY_ID_HAVINGCLAUSE:
1622 OUString sNewFilter;
1623 rValue >>= sNewFilter;
1624 m_aFilterManager.setFilterComponent( FilterManager::FilterComponent::PublicHaving, sNewFilter );
1626 break;
1628 case PROPERTY_ID_APPLYFILTER:
1630 bool bApply = true;
1631 rValue >>= bApply;
1632 m_aFilterManager.setApplyPublicFilter( bApply );
1634 break;
1636 case PROPERTY_ID_DATASOURCE:
1638 Reference< XConnection > xSomeConnection;
1639 if ( ::dbtools::isEmbeddedInDatabase( getParent(), xSomeConnection ) )
1640 throw PropertyVetoException();
1644 m_xAggregateSet->setPropertyValue(PROPERTY_DATASOURCE, rValue);
1646 catch(const Exception&)
1650 break;
1651 case PROPERTY_ID_TARGET_URL:
1652 rValue >>= m_aTargetURL;
1653 break;
1654 case PROPERTY_ID_TARGET_FRAME:
1655 rValue >>= m_aTargetFrame;
1656 break;
1657 case PROPERTY_ID_SUBMIT_METHOD:
1658 rValue >>= m_eSubmitMethod;
1659 break;
1660 case PROPERTY_ID_SUBMIT_ENCODING:
1661 rValue >>= m_eSubmitEncoding;
1662 break;
1663 case PROPERTY_ID_NAME:
1664 rValue >>= m_sName;
1665 break;
1666 case PROPERTY_ID_MASTERFIELDS:
1667 rValue >>= m_aMasterFields;
1668 invalidateParameters();
1669 break;
1670 case PROPERTY_ID_DETAILFIELDS:
1671 rValue >>= m_aDetailFields;
1672 invalidateParameters();
1673 break;
1674 case PROPERTY_ID_CYCLE:
1675 m_aCycle = rValue;
1676 break;
1677 case PROPERTY_ID_NAVIGATION:
1678 rValue >>= m_eNavigation;
1679 break;
1680 case PROPERTY_ID_ALLOWADDITIONS:
1681 m_bAllowInsert = getBOOL(rValue);
1682 break;
1683 case PROPERTY_ID_ALLOWEDITS:
1684 m_bAllowUpdate = getBOOL(rValue);
1685 break;
1686 case PROPERTY_ID_ALLOWDELETIONS:
1687 m_bAllowDelete = getBOOL(rValue);
1688 break;
1689 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1690 m_aDynamicControlBorder = rValue;
1691 break;
1692 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1693 m_aControlBorderColorFocus = rValue;
1694 break;
1695 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1696 m_aControlBorderColorMouse = rValue;
1697 break;
1698 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1699 m_aControlBorderColorInvalid = rValue;
1700 break;
1702 case PROPERTY_ID_ACTIVE_CONNECTION:
1704 Reference< XConnection > xOuterConnection;
1705 if ( ::dbtools::isEmbeddedInDatabase( getParent(), xOuterConnection ) )
1707 if ( xOuterConnection != Reference< XConnection >( rValue, UNO_QUERY ) )
1708 // somebody's trying to set a connection which is not equal the connection
1709 // implied by the database we're embedded in
1710 throw PropertyVetoException();
1712 OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( nHandle, rValue );
1713 break;
1716 default:
1717 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( nHandle ) )
1718 m_aPropertyBagHelper.setDynamicFastPropertyValue( nHandle, rValue );
1719 else
1720 OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( nHandle, rValue );
1721 break;
1726 void ODatabaseForm::forwardingPropertyValue( sal_Int32 _nHandle )
1728 OSL_ENSURE( _nHandle == PROPERTY_ID_ACTIVE_CONNECTION, "ODatabaseForm::forwardingPropertyValue: unexpected property!" );
1729 if ( _nHandle == PROPERTY_ID_ACTIVE_CONNECTION )
1731 if ( m_bSharingConnection )
1732 stopSharingConnection( );
1733 m_bForwardingConnection = true;
1738 void ODatabaseForm::forwardedPropertyValue( sal_Int32 _nHandle )
1740 OSL_ENSURE( _nHandle == PROPERTY_ID_ACTIVE_CONNECTION, "ODatabaseForm::forwardedPropertyValue: unexpected property!" );
1741 if ( _nHandle == PROPERTY_ID_ACTIVE_CONNECTION )
1743 m_bForwardingConnection = false;
1748 // css::beans::XPropertyState
1750 PropertyState ODatabaseForm::getPropertyStateByHandle(sal_Int32 nHandle)
1752 PropertyState eState;
1753 switch (nHandle)
1755 case PROPERTY_ID_NAVIGATION:
1756 return (NavigationBarMode_CURRENT == m_eNavigation) ? PropertyState_DEFAULT_VALUE : PropertyState_DIRECT_VALUE;
1758 case PROPERTY_ID_CYCLE:
1759 eState = m_aCycle.hasValue() ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1760 break;
1762 case PROPERTY_ID_INSERTONLY:
1763 eState = m_bInsertOnly ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1764 break;
1766 case PROPERTY_ID_FILTER:
1767 if ( m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicFilter ).isEmpty() )
1768 eState = PropertyState_DEFAULT_VALUE;
1769 else
1770 eState = PropertyState_DIRECT_VALUE;
1771 break;
1773 case PROPERTY_ID_HAVINGCLAUSE:
1774 if ( m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicHaving ).isEmpty() )
1775 eState = PropertyState_DEFAULT_VALUE;
1776 else
1777 eState = PropertyState_DIRECT_VALUE;
1778 break;
1780 case PROPERTY_ID_APPLYFILTER:
1781 eState = m_aFilterManager.isApplyPublicFilter() ? PropertyState_DEFAULT_VALUE : PropertyState_DIRECT_VALUE;
1782 break;
1784 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1785 eState = m_aDynamicControlBorder.hasValue() ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1786 break;
1788 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1789 eState = m_aControlBorderColorFocus.hasValue() ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1790 break;
1792 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1793 eState = m_aControlBorderColorMouse.hasValue() ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1794 break;
1796 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1797 eState = m_aControlBorderColorInvalid.hasValue() ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1798 break;
1800 default:
1801 eState = OPropertySetAggregationHelper::getPropertyStateByHandle(nHandle);
1803 return eState;
1807 void ODatabaseForm::setPropertyToDefaultByHandle(sal_Int32 nHandle)
1809 switch (nHandle)
1811 case PROPERTY_ID_INSERTONLY:
1812 case PROPERTY_ID_FILTER:
1813 case PROPERTY_ID_HAVINGCLAUSE:
1814 case PROPERTY_ID_APPLYFILTER:
1815 case PROPERTY_ID_NAVIGATION:
1816 case PROPERTY_ID_CYCLE:
1817 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1818 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1819 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1820 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1821 setFastPropertyValue( nHandle, getPropertyDefaultByHandle( nHandle ) );
1822 break;
1824 default:
1825 OPropertySetAggregationHelper::setPropertyToDefaultByHandle(nHandle);
1830 Any ODatabaseForm::getPropertyDefaultByHandle( sal_Int32 nHandle ) const
1832 Any aReturn;
1833 switch (nHandle)
1835 case PROPERTY_ID_INSERTONLY:
1836 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1837 aReturn <<= false;
1838 break;
1840 case PROPERTY_ID_FILTER:
1841 aReturn <<= OUString();
1842 break;
1844 case PROPERTY_ID_HAVINGCLAUSE:
1845 aReturn <<= OUString();
1846 break;
1848 case PROPERTY_ID_APPLYFILTER:
1849 aReturn <<= true;
1850 break;
1852 case PROPERTY_ID_NAVIGATION:
1853 aReturn <<= NavigationBarMode_CURRENT;
1854 break;
1856 case PROPERTY_ID_CYCLE:
1857 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1858 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1859 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1860 break;
1862 default:
1863 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( nHandle ) )
1864 m_aPropertyBagHelper.getDynamicPropertyDefaultByHandle( nHandle, aReturn );
1865 else
1866 aReturn = OPropertySetAggregationHelper::getPropertyDefaultByHandle( nHandle );
1867 break;
1869 return aReturn;
1873 // css::form::XReset
1875 void SAL_CALL ODatabaseForm::reset()
1877 osl::ClearableMutexGuard aGuard(m_aMutex);
1879 if (isLoaded())
1881 ::osl::MutexGuard aResetGuard(m_aResetSafety);
1882 ++m_nResetsPending;
1883 reset_impl(true);
1884 return;
1887 if ( !m_aResetListeners.empty() )
1889 ::osl::MutexGuard aResetGuard(m_aResetSafety);
1890 ++m_nResetsPending;
1891 // create an own thread if we have (approve-)reset-listeners (so the listeners can't do that much damage
1892 // to this thread which is probably the main one)
1893 if (!m_pThread.is())
1895 m_pThread = new OFormSubmitResetThread(this);
1896 m_pThread->create();
1898 m_pThread->addEvent(std::make_unique<EventObject>());
1900 else
1902 // direct call without any approving by the listeners
1903 aGuard.clear();
1905 ::osl::MutexGuard aResetGuard(m_aResetSafety);
1906 ++m_nResetsPending;
1907 reset_impl(false);
1912 void ODatabaseForm::reset_impl(bool _bApproveByListeners)
1914 if ( _bApproveByListeners )
1915 if ( !m_aResetListeners.approveReset() )
1916 return;
1918 ::osl::ResettableMutexGuard aResetGuard(m_aResetSafety);
1919 // do we have a database connected form and stay on the insert row
1920 bool bInsertRow = false;
1921 if (m_xAggregateSet.is())
1922 bInsertRow = getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_ISNEW));
1923 if (bInsertRow)
1927 // Iterate through all columns and set the default value
1928 Reference< XColumnsSupplier > xColsSuppl( m_xAggregateSet, UNO_QUERY );
1929 Reference< XIndexAccess > xIndexCols( xColsSuppl->getColumns(), UNO_QUERY );
1930 for (sal_Int32 i = 0; i < xIndexCols->getCount(); ++i)
1932 Reference< XPropertySet > xColProps;
1933 xIndexCols->getByIndex(i) >>= xColProps;
1935 Reference< XColumnUpdate > xColUpdate( xColProps, UNO_QUERY );
1936 if ( !xColUpdate.is() )
1937 continue;
1939 Reference< XPropertySetInfo > xPSI;
1940 if ( xColProps.is() )
1941 xPSI = xColProps->getPropertySetInfo( );
1943 static const char PROPERTY_CONTROLDEFAULT[] = "ControlDefault";
1944 if ( xPSI.is() && xPSI->hasPropertyByName( PROPERTY_CONTROLDEFAULT ) )
1946 Any aDefault = xColProps->getPropertyValue( PROPERTY_CONTROLDEFAULT );
1948 bool bReadOnly = false;
1949 if ( xPSI->hasPropertyByName( PROPERTY_ISREADONLY ) )
1950 xColProps->getPropertyValue( PROPERTY_ISREADONLY ) >>= bReadOnly;
1952 if ( !bReadOnly )
1956 if ( aDefault.hasValue() )
1957 xColUpdate->updateObject( aDefault );
1959 catch(const Exception&)
1961 DBG_UNHANDLED_EXCEPTION("forms.component");
1967 catch(const Exception&)
1971 if (m_bSubForm)
1973 Reference< XColumnsSupplier > xParentColSupp( m_xParent, UNO_QUERY );
1974 Reference< XNameAccess > xParentCols;
1975 if ( xParentColSupp.is() )
1976 xParentCols = xParentColSupp->getColumns();
1978 if ( xParentCols.is() && xParentCols->hasElements() && m_aMasterFields.hasElements() )
1982 // analyze our parameters
1983 if ( !m_aParameterManager.isUpToDate() )
1984 updateParameterInfo();
1986 m_aParameterManager.resetParameterValues( );
1988 catch(const Exception&)
1990 OSL_FAIL("ODatabaseForm::reset_impl: could not initialize the master-detail-driven parameters!");
1996 aResetGuard.clear();
1997 // iterate through all components. don't use an XIndexAccess as this will cause massive
1998 // problems with the count.
1999 Reference<XEnumeration> xIter = createEnumeration();
2000 while (xIter->hasMoreElements())
2002 Reference<XReset> xReset;
2003 xIter->nextElement() >>= xReset;
2004 if (xReset.is())
2006 // TODO: all reset-methods have to be thread-safe
2007 xReset->reset();
2011 aResetGuard.reset();
2012 // ensure that the row isn't modified
2013 // (do this _before_ the listeners are notified ! their reaction (maybe asynchronous) may depend
2014 // on the modified state of the row)
2015 if (bInsertRow)
2016 m_xAggregateSet->setPropertyValue(PROPERTY_ISMODIFIED, css::uno::Any(false));
2018 aResetGuard.clear();
2020 m_aResetListeners.resetted();
2023 aResetGuard.reset();
2024 // and again : ensure the row isn't modified
2025 // we already did this after we (and maybe our dependents) reset the values, but the listeners may have changed the row, too
2026 if (bInsertRow)
2027 m_xAggregateSet->setPropertyValue(PROPERTY_ISMODIFIED, css::uno::Any(false));
2029 --m_nResetsPending;
2033 void SAL_CALL ODatabaseForm::addResetListener(const Reference<XResetListener>& _rListener)
2035 m_aResetListeners.addTypedListener( _rListener );
2039 void SAL_CALL ODatabaseForm::removeResetListener(const Reference<XResetListener>& _rListener)
2041 m_aResetListeners.removeTypedListener( _rListener );
2045 // css::form::XSubmit
2047 void SAL_CALL ODatabaseForm::submit( const Reference<XControl>& Control,
2048 const css::awt::MouseEvent& MouseEvt )
2051 ::osl::MutexGuard aGuard(m_aMutex);
2052 // Do we have controls and a Submit URL?
2053 if( !getCount() || m_aTargetURL.isEmpty() )
2054 return;
2057 ::osl::ClearableMutexGuard aGuard(m_aMutex);
2058 if (m_aSubmitListeners.getLength())
2060 // create an own thread if we have (approve-)submit-listeners (so the listeners can't do that much damage
2061 // to this thread which is probably the main one)
2062 if (!m_pThread.is())
2064 m_pThread = new OFormSubmitResetThread(this);
2065 m_pThread->create();
2067 m_pThread->addEvent(std::make_unique<css::awt::MouseEvent>(MouseEvt), Control, true);
2069 else
2071 // direct call without any approving by the listeners
2072 aGuard.clear();
2073 submit_impl( Control, MouseEvt );
2077 static void lcl_dispatch(const Reference< XFrame >& xFrame,const Reference<XURLTransformer>& xTransformer,const OUString& aURLStr,const OUString& aReferer,const OUString& aTargetName
2078 ,const OUString& aData,rtl_TextEncoding _eEncoding)
2080 URL aURL;
2081 aURL.Complete = aURLStr;
2082 xTransformer->parseStrict(aURL);
2084 Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY_THROW)->queryDispatch(aURL, aTargetName,
2085 FrameSearchFlag::SELF | FrameSearchFlag::PARENT | FrameSearchFlag::CHILDREN |
2086 FrameSearchFlag::SIBLINGS | FrameSearchFlag::CREATE | FrameSearchFlag::TASKS);
2088 if (!xDisp.is())
2089 return;
2091 Sequence<PropertyValue> aArgs(2);
2092 aArgs.getArray()[0].Name = "Referer";
2093 aArgs.getArray()[0].Value <<= aReferer;
2095 // build a sequence from the to-be-submitted string
2096 OString a8BitData(OUStringToOString(aData, _eEncoding));
2097 // always ANSI #58641
2098 Sequence< sal_Int8 > aPostData(reinterpret_cast<const sal_Int8*>(a8BitData.getStr()), a8BitData.getLength());
2099 Reference< XInputStream > xPostData = new SequenceInputStream(aPostData);
2101 aArgs.getArray()[1].Name = "PostData";
2102 aArgs.getArray()[1].Value <<= xPostData;
2104 xDisp->dispatch(aURL, aArgs);
2107 void ODatabaseForm::submit_impl(const Reference<XControl>& Control, const css::awt::MouseEvent& MouseEvt)
2110 ::comphelper::OInterfaceIteratorHelper2 aIter(m_aSubmitListeners);
2111 EventObject aEvt(static_cast<XWeak*>(this));
2112 bool bCanceled = false;
2113 while (aIter.hasMoreElements() && !bCanceled)
2115 if (!static_cast<XSubmitListener*>(aIter.next())->approveSubmit(aEvt))
2116 bCanceled = true;
2119 if (bCanceled)
2120 return;
2122 FormSubmitEncoding eSubmitEncoding;
2123 FormSubmitMethod eSubmitMethod;
2124 OUString aURLStr;
2125 OUString aReferer;
2126 OUString aTargetName;
2127 Reference< XModel > xModel;
2129 SolarMutexGuard aGuard;
2130 // starform->Forms
2132 Reference<XChild> xParent(m_xParent, UNO_QUERY);
2134 if (xParent.is())
2135 xModel = getXModel(xParent->getParent());
2137 if (xModel.is())
2138 aReferer = xModel->getURL();
2140 // TargetItem
2141 aTargetName = m_aTargetFrame;
2143 eSubmitEncoding = m_eSubmitEncoding;
2144 eSubmitMethod = m_eSubmitMethod;
2145 aURLStr = m_aTargetURL;
2148 if (!xModel.is())
2149 return;
2150 Reference< XFrame > xFrame = xModel->getCurrentController()->getFrame();
2151 if (!xFrame.is())
2152 return;
2154 Reference<XURLTransformer> xTransformer(URLTransformer::create(m_xContext));
2156 // URL encoding
2157 if( eSubmitEncoding == FormSubmitEncoding_URL )
2159 OUString aData;
2161 SolarMutexGuard aGuard;
2162 aData = GetDataEncoded(true, Control, MouseEvt);
2165 URL aURL;
2166 // FormMethod GET
2167 if( eSubmitMethod == FormSubmitMethod_GET )
2169 INetURLObject aUrlObj( aURLStr, INetURLObject::EncodeMechanism::WasEncoded );
2170 aUrlObj.SetParam( aData, INetURLObject::EncodeMechanism::All );
2171 aURL.Complete = aUrlObj.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
2172 if (xTransformer.is())
2173 xTransformer->parseStrict(aURL);
2175 Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY_THROW)->queryDispatch(aURL, aTargetName,
2176 FrameSearchFlag::SELF | FrameSearchFlag::PARENT | FrameSearchFlag::CHILDREN |
2177 FrameSearchFlag::SIBLINGS | FrameSearchFlag::CREATE | FrameSearchFlag::TASKS);
2179 if (xDisp.is())
2181 Sequence<PropertyValue> aArgs(1);
2182 aArgs.getArray()->Name = "Referer";
2183 aArgs.getArray()->Value <<= aReferer;
2184 xDisp->dispatch(aURL, aArgs);
2187 // FormMethod POST
2188 else if( eSubmitMethod == FormSubmitMethod_POST )
2190 lcl_dispatch(xFrame,xTransformer,aURLStr,aReferer,aTargetName,aData,RTL_TEXTENCODING_MS_1252);
2193 else if( eSubmitEncoding == FormSubmitEncoding_MULTIPART )
2195 URL aURL;
2196 aURL.Complete = aURLStr;
2197 xTransformer->parseStrict(aURL);
2199 Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY_THROW)->queryDispatch(aURL, aTargetName,
2200 FrameSearchFlag::SELF | FrameSearchFlag::PARENT | FrameSearchFlag::CHILDREN |
2201 FrameSearchFlag::SIBLINGS | FrameSearchFlag::CREATE | FrameSearchFlag::TASKS);
2203 if (xDisp.is())
2205 OUString aContentType;
2206 Sequence<sal_Int8> aData;
2208 SolarMutexGuard aGuard;
2209 aData = GetDataMultiPartEncoded(Control, MouseEvt, aContentType);
2211 if (!aData.hasElements())
2212 return;
2214 Sequence<PropertyValue> aArgs(3);
2215 aArgs.getArray()[0].Name = "Referer";
2216 aArgs.getArray()[0].Value <<= aReferer;
2217 aArgs.getArray()[1].Name = "ContentType";
2218 aArgs.getArray()[1].Value <<= aContentType;
2220 // build a sequence from the to-be-submitted string
2221 Reference< XInputStream > xPostData = new SequenceInputStream(aData);
2223 aArgs.getArray()[2].Name = "PostData";
2224 aArgs.getArray()[2].Value <<= xPostData;
2226 xDisp->dispatch(aURL, aArgs);
2229 else if( eSubmitEncoding == FormSubmitEncoding_TEXT )
2231 OUString aData;
2233 SolarMutexGuard aGuard;
2234 aData = GetDataEncoded(false, Reference<XControl> (), MouseEvt);
2237 lcl_dispatch(xFrame,xTransformer,aURLStr,aReferer,aTargetName,aData,osl_getThreadTextEncoding());
2239 else {
2240 OSL_FAIL("ODatabaseForm::submit_Impl : wrong encoding !");
2245 // XSubmit
2247 void SAL_CALL ODatabaseForm::addSubmitListener(const Reference<XSubmitListener>& _rListener)
2249 m_aSubmitListeners.addInterface(_rListener);
2253 void SAL_CALL ODatabaseForm::removeSubmitListener(const Reference<XSubmitListener>& _rListener)
2255 m_aSubmitListeners.removeInterface(_rListener);
2259 // css::sdbc::XSQLErrorBroadcaster
2261 void SAL_CALL ODatabaseForm::addSQLErrorListener(const Reference<XSQLErrorListener>& _rListener)
2263 m_aErrorListeners.addInterface(_rListener);
2267 void SAL_CALL ODatabaseForm::removeSQLErrorListener(const Reference<XSQLErrorListener>& _rListener)
2269 m_aErrorListeners.removeInterface(_rListener);
2273 void ODatabaseForm::invalidateParameters()
2275 ::osl::MutexGuard aGuard(m_aMutex);
2276 m_aParameterManager.clearAllParameterInformation();
2280 // OChangeListener
2282 void ODatabaseForm::_propertyChanged(const PropertyChangeEvent& evt)
2284 if (evt.PropertyName == PROPERTY_ACTIVE_CONNECTION && !m_bForwardingConnection)
2286 // the rowset changed its active connection itself (without interaction from our side), so
2287 // we need to fire this event, too
2288 sal_Int32 nHandle = PROPERTY_ID_ACTIVE_CONNECTION;
2289 fire(&nHandle, &evt.NewValue, &evt.OldValue, 1);
2291 else // it was one of the statement relevant props
2293 // if the statement has changed we have to delete the parameter info
2294 invalidateParameters();
2299 // smartXChild
2301 void SAL_CALL ODatabaseForm::setParent(const css::uno::Reference<css::uno::XInterface>& Parent)
2303 // SYNCHRONIZED ----->
2304 osl::ClearableMutexGuard aGuard(m_aMutex);
2306 Reference<XForm> xParentForm(getParent(), UNO_QUERY);
2307 if (xParentForm.is())
2311 Reference< XRowSetApproveBroadcaster > xParentApprBroadcast( xParentForm, UNO_QUERY_THROW );
2312 xParentApprBroadcast->removeRowSetApproveListener( this );
2314 Reference< XLoadable > xParentLoadable( xParentForm, UNO_QUERY_THROW );
2315 xParentLoadable->removeLoadListener( this );
2317 Reference< XPropertySet > xParentProperties( xParentForm, UNO_QUERY_THROW );
2318 xParentProperties->removePropertyChangeListener( PROPERTY_ISNEW, this );
2320 catch(const Exception&)
2322 DBG_UNHANDLED_EXCEPTION("forms.component");
2326 OFormComponents::setParent(Parent);
2328 xParentForm.set(getParent(), UNO_QUERY);
2329 if ( xParentForm.is() )
2333 Reference< XRowSetApproveBroadcaster > xParentApprBroadcast( xParentForm, UNO_QUERY_THROW );
2334 xParentApprBroadcast->addRowSetApproveListener( this );
2336 Reference< XLoadable > xParentLoadable( xParentForm, UNO_QUERY_THROW );
2337 xParentLoadable->addLoadListener( this );
2339 Reference< XPropertySet > xParentProperties( xParentForm, UNO_QUERY_THROW );
2340 xParentProperties->addPropertyChangeListener( PROPERTY_ISNEW, this );
2342 catch(const Exception&)
2344 DBG_UNHANDLED_EXCEPTION("forms.component");
2348 Reference< XPropertySet > xAggregateProperties( m_xAggregateSet );
2349 aGuard.clear();
2350 // <----- SYNCHRONIZED
2352 Reference< XConnection > xOuterConnection;
2353 bool bIsEmbedded = ::dbtools::isEmbeddedInDatabase( Parent, xOuterConnection );
2355 if ( bIsEmbedded )
2356 xAggregateProperties->setPropertyValue( PROPERTY_DATASOURCE, makeAny( OUString() ) );
2360 // smartXTabControllerModel
2362 sal_Bool SAL_CALL ODatabaseForm::getGroupControl()
2364 osl::MutexGuard aGuard(m_aMutex);
2366 // Should controls be combined into a TabOrder group?
2367 if (m_aCycle.hasValue())
2369 sal_Int32 nCycle = 0;
2370 ::cppu::enum2int(nCycle, m_aCycle);
2371 return static_cast<TabulatorCycle>(nCycle) != TabulatorCycle_PAGE;
2374 if (isLoaded() && getConnection().is())
2375 return true;
2377 return false;
2381 void SAL_CALL ODatabaseForm::setControlModels(const Sequence<Reference<XControlModel> >& rControls)
2383 osl::MutexGuard aGuard(m_aMutex);
2385 // Set TabIndex in the order of the sequence
2386 sal_Int32 nCount = getCount();
2388 // HiddenControls and forms are not listed
2389 if (rControls.getLength() > nCount)
2390 return;
2392 sal_Int16 nTabIndex = 1;
2393 for (auto const& rControl : rControls)
2395 Reference<XFormComponent> xComp(rControl, UNO_QUERY);
2396 if (xComp.is())
2398 // Find component in the list
2399 for (sal_Int32 j = 0; j < nCount; ++j)
2401 Reference<XFormComponent> xElement(
2402 getByIndex(j), css::uno::UNO_QUERY);
2403 if (xComp == xElement)
2405 Reference<XPropertySet> xSet(xComp, UNO_QUERY);
2406 if (xSet.is() && hasProperty(PROPERTY_TABINDEX, xSet))
2407 xSet->setPropertyValue( PROPERTY_TABINDEX, makeAny(nTabIndex++) );
2408 break;
2416 Sequence<Reference<XControlModel> > SAL_CALL ODatabaseForm::getControlModels()
2418 ::osl::MutexGuard aGuard(m_aMutex);
2419 return m_pGroupManager->getControlModels();
2423 void SAL_CALL ODatabaseForm::setGroup( const Sequence<Reference<XControlModel> >& _rGroup, const OUString& Name )
2425 ::osl::MutexGuard aGuard(m_aMutex);
2427 // The controls are grouped by adjusting their names to the name of the
2428 // first control of the sequence
2429 Reference< XPropertySet > xSet;
2430 OUString sGroupName( Name );
2432 for( auto const& rControl : _rGroup )
2434 xSet.set(rControl, css::uno::UNO_QUERY);
2435 if ( !xSet.is() )
2437 // can't throw an exception other than a RuntimeException (which would not be appropriate),
2438 // so we ignore (and only assert) this
2439 OSL_FAIL( "ODatabaseForm::setGroup: invalid arguments!" );
2440 continue;
2443 if (sGroupName.isEmpty())
2444 xSet->getPropertyValue(PROPERTY_NAME) >>= sGroupName;
2445 else
2446 xSet->setPropertyValue(PROPERTY_NAME, makeAny(sGroupName));
2451 sal_Int32 SAL_CALL ODatabaseForm::getGroupCount()
2453 ::osl::MutexGuard aGuard(m_aMutex);
2454 return m_pGroupManager->getGroupCount();
2458 void SAL_CALL ODatabaseForm::getGroup( sal_Int32 nGroup, Sequence<Reference<XControlModel> >& _rGroup, OUString& _rName )
2460 ::osl::MutexGuard aGuard(m_aMutex);
2461 _rGroup.realloc(0);
2462 _rName.clear();
2464 if ((nGroup < 0) || (nGroup >= m_pGroupManager->getGroupCount()))
2465 return;
2466 m_pGroupManager->getGroup( nGroup, _rGroup, _rName );
2470 void SAL_CALL ODatabaseForm::getGroupByName(const OUString& Name, Sequence< Reference<XControlModel> >& _rGroup)
2472 ::osl::MutexGuard aGuard(m_aMutex);
2473 _rGroup.realloc(0);
2474 m_pGroupManager->getGroupByName( Name, _rGroup );
2478 // css::lang::XEventListener
2480 void SAL_CALL ODatabaseForm::disposing(const EventObject& Source)
2482 // does the call come from the connection which we are sharing with our parent?
2483 if ( isSharingConnection() )
2485 Reference< XConnection > xConnSource( Source.Source, UNO_QUERY );
2486 if ( xConnSource.is() )
2488 #if OSL_DEBUG_LEVEL > 0
2489 Reference< XConnection > xActiveConn;
2490 m_xAggregateSet->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xActiveConn;
2491 OSL_ENSURE( xActiveConn.get() == xConnSource.get(), "ODatabaseForm::disposing: where did this come from?" );
2492 // there should be exactly one XConnection object we're listening at - our aggregate connection
2493 #endif
2494 disposingSharedConnection( xConnSource );
2498 OInterfaceContainer::disposing(Source);
2500 // does the disposing come from the aggregate ?
2501 if (m_xAggregate.is())
2502 { // no -> forward it
2503 css::uno::Reference<css::lang::XEventListener> xListener;
2504 if (query_aggregation(m_xAggregate, xListener))
2505 xListener->disposing(Source);
2510 void ODatabaseForm::impl_createLoadTimer()
2512 OSL_PRECOND( m_pLoadTimer == nullptr, "ODatabaseForm::impl_createLoadTimer: timer already exists!" );
2513 m_pLoadTimer.reset(new Timer("DatabaseFormLoadTimer"));
2514 m_pLoadTimer->SetTimeout(100);
2515 m_pLoadTimer->SetInvokeHandler(LINK(this,ODatabaseForm,OnTimeout));
2519 // css::form::XLoadListener
2521 void SAL_CALL ODatabaseForm::loaded(const EventObject& /*aEvent*/)
2524 ::osl::MutexGuard aGuard( m_aMutex );
2525 Reference< XRowSet > xParentRowSet( m_xParent, UNO_QUERY_THROW );
2526 xParentRowSet->addRowSetListener( this );
2528 impl_createLoadTimer();
2531 load_impl( true );
2535 void SAL_CALL ODatabaseForm::unloading(const EventObject& /*aEvent*/)
2538 // now stop the rowset listening if we are a subform
2539 ::osl::MutexGuard aGuard( m_aMutex );
2541 if ( m_pLoadTimer && m_pLoadTimer->IsActive() )
2542 m_pLoadTimer->Stop();
2543 m_pLoadTimer.reset();
2545 Reference< XRowSet > xParentRowSet( m_xParent, UNO_QUERY_THROW );
2546 xParentRowSet->removeRowSetListener( this );
2549 unload();
2553 void SAL_CALL ODatabaseForm::unloaded(const EventObject& /*aEvent*/)
2555 // nothing to do
2559 void SAL_CALL ODatabaseForm::reloading(const EventObject& /*aEvent*/)
2561 // now stop the rowset listening if we are a subform
2562 ::osl::MutexGuard aGuard(m_aMutex);
2563 Reference<XRowSet> xParentRowSet(m_xParent, UNO_QUERY);
2564 if (xParentRowSet.is())
2565 xParentRowSet->removeRowSetListener(this);
2567 if (m_pLoadTimer && m_pLoadTimer->IsActive())
2568 m_pLoadTimer->Stop();
2572 void SAL_CALL ODatabaseForm::reloaded(const EventObject& /*aEvent*/)
2574 reload_impl(true);
2576 ::osl::MutexGuard aGuard(m_aMutex);
2577 Reference<XRowSet> xParentRowSet(m_xParent, UNO_QUERY);
2578 if (xParentRowSet.is())
2579 xParentRowSet->addRowSetListener(this);
2584 IMPL_LINK_NOARG(ODatabaseForm, OnTimeout, Timer *, void)
2586 reload_impl(true);
2590 // css::form::XLoadable
2592 void SAL_CALL ODatabaseForm::load()
2594 load_impl(false);
2598 bool ODatabaseForm::canShareConnection( const Reference< XPropertySet >& _rxParentProps )
2600 // our own data source
2601 OUString sOwnDatasource;
2602 m_xAggregateSet->getPropertyValue( PROPERTY_DATASOURCE ) >>= sOwnDatasource;
2604 // our parents data source
2605 OUString sParentDataSource;
2606 OSL_ENSURE( _rxParentProps.is() && _rxParentProps->getPropertySetInfo().is() && _rxParentProps->getPropertySetInfo()->hasPropertyByName( PROPERTY_DATASOURCE ),
2607 "ODatabaseForm::doShareConnection: invalid parent form!" );
2608 if ( _rxParentProps.is() )
2609 _rxParentProps->getPropertyValue( PROPERTY_DATASOURCE ) >>= sParentDataSource;
2611 bool bCanShareConnection = false;
2613 // both rowsets share are connected to the same data source
2614 if ( sParentDataSource == sOwnDatasource )
2616 if ( !sParentDataSource.isEmpty() )
2617 // and it's really a data source name (not empty)
2618 bCanShareConnection = true;
2619 else
2620 { // the data source name is empty
2621 // -> ok for the URL
2622 OUString sParentURL;
2623 OUString sMyURL;
2624 _rxParentProps->getPropertyValue( PROPERTY_URL ) >>= sParentURL;
2625 m_xAggregateSet->getPropertyValue( PROPERTY_URL ) >>= sMyURL;
2627 bCanShareConnection = (sParentURL == sMyURL);
2631 if ( bCanShareConnection )
2633 // check for the user/password
2635 // take the user property on the rowset (if any) into account
2636 OUString sParentUser, sParentPwd;
2637 _rxParentProps->getPropertyValue( PROPERTY_USER ) >>= sParentUser;
2638 _rxParentProps->getPropertyValue( PROPERTY_PASSWORD ) >>= sParentPwd;
2640 OUString sMyUser, sMyPwd;
2641 m_xAggregateSet->getPropertyValue( PROPERTY_USER ) >>= sMyUser;
2642 m_xAggregateSet->getPropertyValue( PROPERTY_PASSWORD ) >>= sMyPwd;
2644 bCanShareConnection =
2645 ( sParentUser == sMyUser )
2646 && ( sParentPwd == sMyPwd );
2649 return bCanShareConnection;
2653 void ODatabaseForm::doShareConnection( const Reference< XPropertySet >& _rxParentProps )
2655 // get the connection of the parent
2656 Reference< XConnection > xParentConn;
2657 _rxParentProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xParentConn;
2658 OSL_ENSURE( xParentConn.is(), "ODatabaseForm::doShareConnection: we're a valid sub-form, but the parent has no connection?!" );
2660 if ( xParentConn.is() )
2662 // add as dispose listener to the connection
2663 Reference< XComponent > xParentConnComp( xParentConn, UNO_QUERY );
2664 OSL_ENSURE( xParentConnComp.is(), "ODatabaseForm::doShareConnection: invalid connection!" );
2665 xParentConnComp->addEventListener( static_cast< XLoadListener* >( this ) );
2667 // forward the connection to our own aggregate
2668 m_bForwardingConnection = true;
2669 m_xAggregateSet->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, makeAny( xParentConn ) );
2670 m_bForwardingConnection = false;
2672 m_bSharingConnection = true;
2674 else
2675 m_bSharingConnection = false;
2679 void ODatabaseForm::disposingSharedConnection( const Reference< XConnection >& /*_rxConn*/ )
2681 stopSharingConnection();
2683 // TODO: we could think about whether or not to re-connect.
2684 unload( );
2688 void ODatabaseForm::stopSharingConnection( )
2690 OSL_ENSURE( m_bSharingConnection, "ODatabaseForm::stopSharingConnection: invalid call!" );
2692 if ( !m_bSharingConnection )
2693 return;
2695 // get the connection
2696 Reference< XConnection > xSharedConn;
2697 m_xAggregateSet->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xSharedConn;
2698 OSL_ENSURE( xSharedConn.is(), "ODatabaseForm::stopSharingConnection: there's no conn!" );
2700 // remove ourself as event listener
2701 Reference< XComponent > xSharedConnComp( xSharedConn, UNO_QUERY );
2702 if ( xSharedConnComp.is() )
2703 xSharedConnComp->removeEventListener( static_cast< XLoadListener* >( this ) );
2705 // no need to dispose the conn: we're not the owner, this is our parent
2706 // (in addition, this method may be called if the connection is being disposed while we use it)
2708 // reset the property
2709 xSharedConn.clear();
2710 m_bForwardingConnection = true;
2711 m_xAggregateSet->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, makeAny( xSharedConn ) );
2712 m_bForwardingConnection = false;
2714 // reset the flag
2715 m_bSharingConnection = false;
2718 namespace
2720 Reference<css::awt::XWindow> GetDialogParentWindow(const Reference<XModel>& rModel)
2722 if (!rModel.is())
2723 return nullptr;
2724 Reference<XController> xController(rModel->getCurrentController());
2725 if (!xController.is())
2726 return nullptr;
2727 Reference<XFrame> xFrame(xController->getFrame());
2728 if (!xFrame.is())
2729 return nullptr;
2730 return xFrame->getContainerWindow();
2734 bool ODatabaseForm::implEnsureConnection()
2738 if ( getConnection( ).is() )
2739 // if our aggregate already has a connection, nothing needs to be done about it
2740 return true;
2742 // see whether we're an embedded form
2743 Reference< XConnection > xOuterConnection;
2744 if ( ::dbtools::isEmbeddedInDatabase( getParent(), xOuterConnection ) )
2746 m_xAggregateSet->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, makeAny( xOuterConnection ) );
2747 return xOuterConnection.is();
2750 m_bSharingConnection = false;
2752 // if we're a sub form, we try to re-use the connection of our parent
2753 if (m_bSubForm)
2755 OSL_ENSURE( Reference< XForm >( getParent(), UNO_QUERY ).is(),
2756 "ODatabaseForm::implEnsureConnection: m_bSubForm is TRUE, but the parent is no form?" );
2758 Reference< XPropertySet > xParentProps( getParent(), UNO_QUERY );
2760 // can we re-use (aka share) the connection of the parent?
2761 if ( canShareConnection( xParentProps ) )
2763 // yep -> do it
2764 doShareConnection( xParentProps );
2765 // success?
2766 if ( m_bSharingConnection )
2767 // yes -> outta here
2768 return true;
2772 if (m_xAggregateSet.is())
2774 //Dig out a suitable parent for any warning dialogs
2775 Reference<css::awt::XWindow> m_xDialogParent;
2776 Reference<XChild> xParent(m_xParent, UNO_QUERY);
2777 if (xParent.is())
2778 m_xDialogParent = GetDialogParentWindow(getXModel(xParent->getParent()));
2780 Reference< XConnection > xConnection = connectRowset(
2781 Reference<XRowSet> (m_xAggregate, UNO_QUERY),
2782 m_xContext, m_xDialogParent
2784 return xConnection.is();
2787 catch(const SQLException& eDB)
2789 onError(eDB, FRM_RES_STRING(RID_STR_CONNECTERROR));
2791 catch(const Exception&)
2793 DBG_UNHANDLED_EXCEPTION("forms.component");
2796 return false;
2800 void ODatabaseForm::load_impl(bool bCausedByParentForm, bool bMoveToFirst, const Reference< XInteractionHandler >& _rxCompletionHandler )
2802 ::osl::ResettableMutexGuard aGuard(m_aMutex);
2804 // are we already loaded?
2805 if (isLoaded())
2806 return;
2808 m_bSubForm = bCausedByParentForm;
2810 // if we don't have a connection, we are not intended to be a database form or the aggregate was not able
2811 // to establish a connection
2812 bool bConnected = implEnsureConnection();
2814 // we don't have to execute if we do not have a command to execute
2815 bool bExecute = bConnected && m_xAggregateSet.is() && !getString(m_xAggregateSet->getPropertyValue(PROPERTY_COMMAND)).isEmpty();
2817 // a database form always uses caching
2818 // we use starting fetchsize with at least 10 rows
2819 if (bConnected)
2820 m_xAggregateSet->setPropertyValue(PROPERTY_FETCHSIZE, makeAny(sal_Int32(40)));
2822 // if we're loaded as sub form we got a "rowSetChanged" from the parent rowset _before_ we got the "loaded"
2823 // so we don't need to execute the statement again, this was already done
2824 // (and there were no relevant changes between these two listener calls, the "load" of a form is quite an
2825 // atomic operation.)
2827 bool bSuccess = false;
2828 if (bExecute)
2830 m_sCurrentErrorContext = FRM_RES_STRING(RID_ERR_LOADING_FORM);
2831 bSuccess = executeRowSet(aGuard, bMoveToFirst, _rxCompletionHandler);
2834 if (bSuccess)
2836 m_bLoaded = true;
2837 aGuard.clear();
2838 EventObject aEvt(static_cast<XWeak*>(this));
2839 m_aLoadListeners.notifyEach( &XLoadListener::loaded, aEvt );
2841 // if we are on the insert row, we have to reset all controls
2842 // to set the default values
2843 if (bExecute && getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_ISNEW)))
2844 reset();
2849 void SAL_CALL ODatabaseForm::unload()
2851 ::osl::ResettableMutexGuard aGuard(m_aMutex);
2852 if (!isLoaded())
2853 return;
2855 m_pLoadTimer.reset();
2857 aGuard.clear();
2858 EventObject aEvt(static_cast<XWeak*>(this));
2859 m_aLoadListeners.notifyEach( &XLoadListener::unloading, aEvt );
2861 if (m_xAggregateAsRowSet.is())
2863 // we may have reset the InsertOnly property on the aggregate - restore it
2864 restoreInsertOnlyState( );
2866 // clear the parameters if there are any
2867 invalidateParameters();
2871 // close the aggregate
2872 Reference<XCloseable> xCloseable;
2873 query_aggregation( m_xAggregate, xCloseable);
2874 if (xCloseable.is())
2875 xCloseable->close();
2877 catch(const SQLException&)
2882 aGuard.reset();
2883 m_bLoaded = false;
2885 // if the connection we used while we were loaded is only shared with our parent, we
2886 // reset it
2887 if ( isSharingConnection() )
2888 stopSharingConnection();
2890 aGuard.clear();
2891 m_aLoadListeners.notifyEach( &XLoadListener::unloaded, aEvt );
2895 void SAL_CALL ODatabaseForm::reload()
2897 reload_impl(true);
2901 void ODatabaseForm::reload_impl(bool bMoveToFirst, const Reference< XInteractionHandler >& _rxCompletionHandler )
2903 ::osl::ResettableMutexGuard aGuard(m_aMutex);
2904 if (!isLoaded())
2905 return;
2907 DocumentModifyGuard aModifyGuard( *this );
2908 // ensures the document is not marked as "modified" just because we change some control's content during
2909 // reloading...
2911 EventObject aEvent(static_cast<XWeak*>(this));
2913 // only if there is no approve listener we can post the event at this time
2914 // otherwise see approveRowsetChange
2915 // the approval is done by the aggregate
2916 if (!m_aRowSetApproveListeners.getLength())
2918 ::comphelper::OInterfaceIteratorHelper2 aIter(m_aLoadListeners);
2919 aGuard.clear();
2921 while (aIter.hasMoreElements())
2922 static_cast<XLoadListener*>(aIter.next())->reloading(aEvent);
2924 aGuard.reset();
2928 bool bSuccess = true;
2931 m_sCurrentErrorContext = FRM_RES_STRING(RID_ERR_REFRESHING_FORM);
2932 bSuccess = executeRowSet(aGuard, bMoveToFirst, _rxCompletionHandler);
2934 catch(const SQLException&)
2936 OSL_FAIL("ODatabaseForm::reload_impl : shouldn't executeRowSet catch this exception?");
2939 if (bSuccess)
2941 ::comphelper::OInterfaceIteratorHelper2 aIter(m_aLoadListeners);
2942 aGuard.clear();
2943 while (aIter.hasMoreElements())
2944 static_cast<XLoadListener*>(aIter.next())->reloaded(aEvent);
2946 // if we are on the insert row, we have to reset all controls
2947 // to set the default values
2948 if (getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_ISNEW)))
2949 reset();
2951 else
2952 m_bLoaded = false;
2956 sal_Bool SAL_CALL ODatabaseForm::isLoaded()
2958 return m_bLoaded;
2962 void SAL_CALL ODatabaseForm::addLoadListener(const Reference<XLoadListener>& aListener)
2964 m_aLoadListeners.addInterface(aListener);
2968 void SAL_CALL ODatabaseForm::removeLoadListener(const Reference<XLoadListener>& aListener)
2970 m_aLoadListeners.removeInterface(aListener);
2974 // css::sdbc::XCloseable
2975 void SAL_CALL ODatabaseForm::close()
2977 // unload will close the aggregate
2978 unload();
2982 // css::sdbc::XRowSetListener
2984 void SAL_CALL ODatabaseForm::cursorMoved(const EventObject& /*event*/)
2986 // reload the subform with the new parameters of the parent
2987 // do this handling delayed to provide of execute too many SQL Statements
2988 osl::MutexGuard aGuard(m_aMutex);
2990 DBG_ASSERT( m_pLoadTimer, "ODatabaseForm::cursorMoved: how can this happen?!" );
2991 if ( !m_pLoadTimer )
2992 impl_createLoadTimer();
2994 if ( m_pLoadTimer->IsActive() )
2995 m_pLoadTimer->Stop();
2997 // and start the timer again
2998 m_pLoadTimer->Start();
3002 void SAL_CALL ODatabaseForm::rowChanged(const EventObject& /*event*/)
3004 // ignore it
3008 void SAL_CALL ODatabaseForm::rowSetChanged(const EventObject& /*event*/)
3010 // not interested in :
3011 // if our parent is an ODatabaseForm, too, then after this rowSetChanged we'll get a "reloaded"
3012 // or a "loaded" event.
3013 // If somebody gave us another parent which is an XRowSet but doesn't handle an execute as
3014 // "load" respectively "reload"... can't do anything...
3018 bool ODatabaseForm::impl_approveRowChange_throw( const EventObject& _rEvent, const bool _bAllowSQLException,
3019 ::osl::ClearableMutexGuard& _rGuard )
3021 ::comphelper::OInterfaceIteratorHelper2 aIter( m_aRowSetApproveListeners );
3022 _rGuard.clear();
3023 while ( aIter.hasMoreElements() )
3025 Reference< XRowSetApproveListener > xListener( static_cast< XRowSetApproveListener* >( aIter.next() ) );
3026 if ( !xListener.is() )
3027 continue;
3031 if ( !xListener->approveRowSetChange( _rEvent ) )
3032 return false;
3034 catch (const DisposedException& e)
3036 if ( e.Context == xListener )
3037 aIter.remove();
3039 catch (const RuntimeException&)
3041 throw;
3043 catch (const SQLException&)
3045 DBG_UNHANDLED_EXCEPTION("forms.component");
3046 if ( _bAllowSQLException )
3047 throw;
3049 catch (const Exception&)
3051 DBG_UNHANDLED_EXCEPTION("forms.component");
3054 return true;
3058 sal_Bool SAL_CALL ODatabaseForm::approveCursorMove(const EventObject& event)
3060 // is our aggregate calling?
3061 if (event.Source == css::uno::Reference<css::uno::XInterface>(static_cast<XWeak*>(this)))
3063 // Our aggregate doesn't have any ApproveRowSetListeners (expect ourself), as we re-routed the queryInterface
3064 // for XRowSetApproveBroadcaster-interface.
3065 // So we have to multiplex this approve request.
3066 ::comphelper::OInterfaceIteratorHelper2 aIter( m_aRowSetApproveListeners );
3067 while ( aIter.hasMoreElements() )
3069 Reference< XRowSetApproveListener > xListener( static_cast< XRowSetApproveListener* >( aIter.next() ) );
3070 if ( !xListener.is() )
3071 continue;
3075 if ( !xListener->approveCursorMove( event ) )
3076 return false;
3078 catch (const DisposedException& e)
3080 if ( e.Context == xListener )
3081 aIter.remove();
3083 catch (const RuntimeException&)
3085 throw;
3087 catch (const Exception&)
3089 DBG_UNHANDLED_EXCEPTION("forms.component");
3092 return true;
3094 else
3096 // this is a call from our parent ...
3097 // a parent's cursor move will result in a re-execute of our own row-set, so we have to
3098 // ask our own RowSetChangesListeners, too
3099 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3100 if ( !impl_approveRowChange_throw( event, false, aGuard ) )
3101 return false;
3103 return true;
3107 sal_Bool SAL_CALL ODatabaseForm::approveRowChange(const RowChangeEvent& event)
3109 // is our aggregate calling?
3110 if (event.Source == css::uno::Reference<css::uno::XInterface>(static_cast<XWeak*>(this)))
3112 // Our aggregate doesn't have any ApproveRowSetListeners (expect ourself), as we re-routed the queryInterface
3113 // for XRowSetApproveBroadcaster-interface.
3114 // So we have to multiplex this approve request.
3115 ::comphelper::OInterfaceIteratorHelper2 aIter( m_aRowSetApproveListeners );
3116 while ( aIter.hasMoreElements() )
3118 Reference< XRowSetApproveListener > xListener( static_cast< XRowSetApproveListener* >( aIter.next() ) );
3119 if ( !xListener.is() )
3120 continue;
3124 if ( !xListener->approveRowChange( event ) )
3125 return false;
3127 catch (const DisposedException& e)
3129 if ( e.Context == xListener )
3130 aIter.remove();
3132 catch (const RuntimeException&)
3134 throw;
3136 catch (const Exception&)
3138 DBG_UNHANDLED_EXCEPTION("forms.component");
3141 return true;
3143 return true;
3147 sal_Bool SAL_CALL ODatabaseForm::approveRowSetChange(const EventObject& event)
3149 if (event.Source == css::uno::Reference<css::uno::XInterface>(static_cast<XWeak*>(this))) // ignore our aggregate as we handle this approve ourself
3151 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3152 bool bWasLoaded = isLoaded();
3153 if ( !impl_approveRowChange_throw( event, false, aGuard ) )
3154 return false;
3156 if ( bWasLoaded )
3158 m_aLoadListeners.notifyEach( &XLoadListener::reloading, event );
3161 else
3163 // this is a call from our parent ...
3164 // a parent's cursor move will result in a re-execute of our own row-set, so we have to
3165 // ask our own RowSetChangesListeners, too
3166 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3167 if ( !impl_approveRowChange_throw( event, false, aGuard ) )
3168 return false;
3170 return true;
3174 // css::sdb::XRowSetApproveBroadcaster
3176 void SAL_CALL ODatabaseForm::addRowSetApproveListener(const Reference<XRowSetApproveListener>& _rListener)
3178 osl::MutexGuard aGuard(m_aMutex);
3179 m_aRowSetApproveListeners.addInterface(_rListener);
3181 // do we have to multiplex ?
3182 if (m_aRowSetApproveListeners.getLength() == 1)
3184 Reference<XRowSetApproveBroadcaster> xBroadcaster;
3185 if (query_aggregation( m_xAggregate, xBroadcaster))
3187 Reference<XRowSetApproveListener> xListener(static_cast<XRowSetApproveListener*>(this));
3188 xBroadcaster->addRowSetApproveListener(xListener);
3194 void SAL_CALL ODatabaseForm::removeRowSetApproveListener(const Reference<XRowSetApproveListener>& _rListener)
3196 osl::MutexGuard aGuard(m_aMutex);
3197 // do we have to remove the multiplex ?
3198 m_aRowSetApproveListeners.removeInterface(_rListener);
3199 if ( m_aRowSetApproveListeners.getLength() == 0 )
3201 Reference<XRowSetApproveBroadcaster> xBroadcaster;
3202 if (query_aggregation( m_xAggregate, xBroadcaster))
3204 Reference<XRowSetApproveListener> xListener(static_cast<XRowSetApproveListener*>(this));
3205 xBroadcaster->removeRowSetApproveListener(xListener);
3211 // com::sun:star::form::XDatabaseParameterBroadcaster
3213 void SAL_CALL ODatabaseForm::addDatabaseParameterListener(const Reference<XDatabaseParameterListener>& _rListener)
3215 m_aParameterManager.addParameterListener( _rListener );
3218 void SAL_CALL ODatabaseForm::removeDatabaseParameterListener(const Reference<XDatabaseParameterListener>& _rListener)
3220 m_aParameterManager.removeParameterListener( _rListener );
3224 void SAL_CALL ODatabaseForm::addParameterListener(const Reference<XDatabaseParameterListener>& _rListener)
3226 ODatabaseForm::addDatabaseParameterListener( _rListener );
3230 void SAL_CALL ODatabaseForm::removeParameterListener(const Reference<XDatabaseParameterListener>& _rListener)
3232 ODatabaseForm::removeDatabaseParameterListener( _rListener );
3236 // css::sdb::XCompletedExecution
3238 void SAL_CALL ODatabaseForm::executeWithCompletion( const Reference< XInteractionHandler >& _rxHandler )
3240 ::osl::ClearableMutexGuard aGuard(m_aMutex);
3241 // the difference between execute and load is, that we position on the first row in case of load
3242 // after execute we remain before the first row
3243 if (!isLoaded())
3245 aGuard.clear();
3246 load_impl(false, false, _rxHandler);
3248 else
3250 EventObject event(static_cast< XWeak* >(this));
3251 if ( !impl_approveRowChange_throw( event, true, aGuard ) )
3252 return;
3254 // we're loaded and somebody wants to execute ourself -> this means a reload
3255 reload_impl(false, _rxHandler);
3260 // css::sdbc::XRowSet
3262 void SAL_CALL ODatabaseForm::execute()
3264 osl::ClearableMutexGuard aGuard(m_aMutex);
3265 // if somebody calls an execute and we're not loaded we reroute this call to our load method.
3267 // the difference between execute and load is, that we position on the first row in case of load
3268 // after execute we remain before the first row
3269 if (!isLoaded())
3271 aGuard.clear();
3272 load_impl(false, false);
3274 else
3276 EventObject event(static_cast< XWeak* >(this));
3277 if ( !impl_approveRowChange_throw( event, true, aGuard ) )
3278 return;
3280 // we're loaded and somebody wants to execute ourself -> this means a reload
3281 reload_impl(false);
3286 void SAL_CALL ODatabaseForm::addRowSetListener(const Reference<XRowSetListener>& _rListener)
3288 if (m_xAggregateAsRowSet.is())
3289 m_xAggregateAsRowSet->addRowSetListener(_rListener);
3293 void SAL_CALL ODatabaseForm::removeRowSetListener(const Reference<XRowSetListener>& _rListener)
3295 if (m_xAggregateAsRowSet.is())
3296 m_xAggregateAsRowSet->removeRowSetListener(_rListener);
3300 // css::sdbc::XResultSet
3302 sal_Bool SAL_CALL ODatabaseForm::next()
3304 return m_xAggregateAsRowSet->next();
3308 sal_Bool SAL_CALL ODatabaseForm::isBeforeFirst()
3310 return m_xAggregateAsRowSet->isBeforeFirst();
3314 sal_Bool SAL_CALL ODatabaseForm::isAfterLast()
3316 return m_xAggregateAsRowSet->isAfterLast();
3320 sal_Bool SAL_CALL ODatabaseForm::isFirst()
3322 return m_xAggregateAsRowSet->isFirst();
3326 sal_Bool SAL_CALL ODatabaseForm::isLast()
3328 return m_xAggregateAsRowSet->isLast();
3332 void SAL_CALL ODatabaseForm::beforeFirst()
3334 m_xAggregateAsRowSet->beforeFirst();
3338 void SAL_CALL ODatabaseForm::afterLast()
3340 m_xAggregateAsRowSet->afterLast();
3344 sal_Bool SAL_CALL ODatabaseForm::first()
3346 return m_xAggregateAsRowSet->first();
3350 sal_Bool SAL_CALL ODatabaseForm::last()
3352 return m_xAggregateAsRowSet->last();
3356 sal_Int32 SAL_CALL ODatabaseForm::getRow()
3358 return m_xAggregateAsRowSet->getRow();
3362 sal_Bool SAL_CALL ODatabaseForm::absolute(sal_Int32 row)
3364 return m_xAggregateAsRowSet->absolute(row);
3368 sal_Bool SAL_CALL ODatabaseForm::relative(sal_Int32 rows)
3370 return m_xAggregateAsRowSet->relative(rows);
3374 sal_Bool SAL_CALL ODatabaseForm::previous()
3376 return m_xAggregateAsRowSet->previous();
3380 void SAL_CALL ODatabaseForm::refreshRow()
3382 m_xAggregateAsRowSet->refreshRow();
3386 sal_Bool SAL_CALL ODatabaseForm::rowUpdated()
3388 return m_xAggregateAsRowSet->rowUpdated();
3392 sal_Bool SAL_CALL ODatabaseForm::rowInserted()
3394 return m_xAggregateAsRowSet->rowInserted();
3398 sal_Bool SAL_CALL ODatabaseForm::rowDeleted()
3400 return m_xAggregateAsRowSet->rowDeleted();
3404 css::uno::Reference<css::uno::XInterface> SAL_CALL ODatabaseForm::getStatement()
3406 return m_xAggregateAsRowSet->getStatement();
3409 // css::sdbc::XResultSetUpdate
3410 // exceptions during insert update and delete will be forwarded to the errorlistener
3412 void SAL_CALL ODatabaseForm::insertRow()
3416 Reference<XResultSetUpdate> xUpdate;
3417 if (query_aggregation( m_xAggregate, xUpdate))
3418 xUpdate->insertRow();
3420 catch(const RowSetVetoException&)
3422 throw;
3424 catch(const SQLException& eDb)
3426 onError(eDb, FRM_RES_STRING(RID_STR_ERR_INSERTRECORD));
3427 throw;
3432 void SAL_CALL ODatabaseForm::updateRow()
3436 Reference<XResultSetUpdate> xUpdate;
3437 if (query_aggregation( m_xAggregate, xUpdate))
3438 xUpdate->updateRow();
3440 catch(const RowSetVetoException&)
3442 throw;
3444 catch(const SQLException& eDb)
3446 onError(eDb, FRM_RES_STRING(RID_STR_ERR_UPDATERECORD));
3447 throw;
3452 void SAL_CALL ODatabaseForm::deleteRow()
3456 Reference<XResultSetUpdate> xUpdate;
3457 if (query_aggregation( m_xAggregate, xUpdate))
3458 xUpdate->deleteRow();
3460 catch(const RowSetVetoException&)
3462 throw;
3464 catch(const SQLException& eDb)
3466 onError(eDb, FRM_RES_STRING(RID_STR_ERR_DELETERECORD));
3467 throw;
3472 void SAL_CALL ODatabaseForm::cancelRowUpdates()
3476 Reference<XResultSetUpdate> xUpdate;
3477 if (query_aggregation( m_xAggregate, xUpdate))
3478 xUpdate->cancelRowUpdates();
3480 catch(const RowSetVetoException&)
3482 throw;
3484 catch(const SQLException& eDb)
3486 onError(eDb, FRM_RES_STRING(RID_STR_ERR_INSERTRECORD));
3487 throw;
3492 void SAL_CALL ODatabaseForm::moveToInsertRow()
3494 Reference<XResultSetUpdate> xUpdate;
3495 if (!query_aggregation( m_xAggregate, xUpdate))
3496 return;
3498 // _always_ move to the insert row
3500 // Formerly, the following line was conditioned with a "not is new", means we did not move the aggregate
3501 // to the insert row if it was already positioned there.
3503 // This prevented the RowSet implementation from resetting its column values. We, ourself, formerly
3504 // did this reset of columns in reset_impl, where we set every column to the ControlDefault, or, if this
3505 // was not present, to NULL. However, the problem with setting to NULL was #88888#, the problem with
3506 // _not_ setting to NULL (which was the original fix for #88888#) was #97955#.
3508 // So now we
3509 // * move our aggregate to the insert row
3510 // * in reset_impl
3511 // - set the control defaults into the columns if not void
3512 // - do _not_ set the columns to NULL if no control default is set
3514 // Still, there is #72756#. During fixing this bug, DG introduced not calling the aggregate here. So
3515 // in theory, we re-introduced #72756#. But the bug described therein does not happen anymore, as the
3516 // preliminaries for it changed (no display of guessed values for new records with autoinc fields)
3518 // BTW: the public Issuezilla bug is #i2815#
3520 xUpdate->moveToInsertRow();
3522 // then set the default values and the parameters given from the parent
3523 reset();
3527 void SAL_CALL ODatabaseForm::moveToCurrentRow()
3529 Reference<XResultSetUpdate> xUpdate;
3530 if (query_aggregation( m_xAggregate, xUpdate))
3531 xUpdate->moveToCurrentRow();
3534 // css::sdbcx::XDeleteRows
3536 Sequence<sal_Int32> SAL_CALL ODatabaseForm::deleteRows(const Sequence<Any>& rows)
3540 Reference<XDeleteRows> xDelete;
3541 if (query_aggregation( m_xAggregate, xDelete))
3542 return xDelete->deleteRows(rows);
3544 catch(const RowSetVetoException&)
3546 throw;
3548 catch(const SQLException& eDb)
3550 onError(eDb, FRM_RES_STRING(RID_STR_ERR_DELETERECORDS));
3551 throw;
3554 return Sequence< sal_Int32 >();
3557 // css::sdbc::XParameters
3559 void SAL_CALL ODatabaseForm::setNull(sal_Int32 parameterIndex, sal_Int32 sqlType)
3561 m_aParameterManager.setNull(parameterIndex, sqlType);
3565 void SAL_CALL ODatabaseForm::setObjectNull(sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName)
3567 m_aParameterManager.setObjectNull(parameterIndex, sqlType, typeName);
3571 void SAL_CALL ODatabaseForm::setBoolean(sal_Int32 parameterIndex, sal_Bool x)
3573 m_aParameterManager.setBoolean(parameterIndex, x);
3577 void SAL_CALL ODatabaseForm::setByte(sal_Int32 parameterIndex, sal_Int8 x)
3579 m_aParameterManager.setByte(parameterIndex, x);
3583 void SAL_CALL ODatabaseForm::setShort(sal_Int32 parameterIndex, sal_Int16 x)
3585 m_aParameterManager.setShort(parameterIndex, x);
3589 void SAL_CALL ODatabaseForm::setInt(sal_Int32 parameterIndex, sal_Int32 x)
3591 m_aParameterManager.setInt(parameterIndex, x);
3595 void SAL_CALL ODatabaseForm::setLong(sal_Int32 parameterIndex, sal_Int64 x)
3597 m_aParameterManager.setLong(parameterIndex, x);
3601 void SAL_CALL ODatabaseForm::setFloat(sal_Int32 parameterIndex, float x)
3603 m_aParameterManager.setFloat(parameterIndex, x);
3607 void SAL_CALL ODatabaseForm::setDouble(sal_Int32 parameterIndex, double x)
3609 m_aParameterManager.setDouble(parameterIndex, x);
3613 void SAL_CALL ODatabaseForm::setString(sal_Int32 parameterIndex, const OUString& x)
3615 m_aParameterManager.setString(parameterIndex, x);
3619 void SAL_CALL ODatabaseForm::setBytes(sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x)
3621 m_aParameterManager.setBytes(parameterIndex, x);
3625 void SAL_CALL ODatabaseForm::setDate(sal_Int32 parameterIndex, const css::util::Date& x)
3627 m_aParameterManager.setDate(parameterIndex, x);
3631 void SAL_CALL ODatabaseForm::setTime(sal_Int32 parameterIndex, const css::util::Time& x)
3633 m_aParameterManager.setTime(parameterIndex, x);
3637 void SAL_CALL ODatabaseForm::setTimestamp(sal_Int32 parameterIndex, const css::util::DateTime& x)
3639 m_aParameterManager.setTimestamp(parameterIndex, x);
3643 void SAL_CALL ODatabaseForm::setBinaryStream(sal_Int32 parameterIndex, const Reference<XInputStream>& x, sal_Int32 length)
3645 m_aParameterManager.setBinaryStream(parameterIndex, x, length);
3649 void SAL_CALL ODatabaseForm::setCharacterStream(sal_Int32 parameterIndex, const Reference<XInputStream>& x, sal_Int32 length)
3651 m_aParameterManager.setCharacterStream(parameterIndex, x, length);
3655 void SAL_CALL ODatabaseForm::setObjectWithInfo(sal_Int32 parameterIndex, const Any& x, sal_Int32 targetSqlType, sal_Int32 scale)
3657 m_aParameterManager.setObjectWithInfo(parameterIndex, x, targetSqlType, scale);
3661 void SAL_CALL ODatabaseForm::setObject(sal_Int32 parameterIndex, const Any& x)
3663 m_aParameterManager.setObject(parameterIndex, x);
3667 void SAL_CALL ODatabaseForm::setRef(sal_Int32 parameterIndex, const Reference<XRef>& x)
3669 m_aParameterManager.setRef(parameterIndex, x);
3673 void SAL_CALL ODatabaseForm::setBlob(sal_Int32 parameterIndex, const Reference<XBlob>& x)
3675 m_aParameterManager.setBlob(parameterIndex, x);
3679 void SAL_CALL ODatabaseForm::setClob(sal_Int32 parameterIndex, const Reference<XClob>& x)
3681 m_aParameterManager.setClob(parameterIndex, x);
3685 void SAL_CALL ODatabaseForm::setArray(sal_Int32 parameterIndex, const Reference<XArray>& x)
3687 m_aParameterManager.setArray(parameterIndex, x);
3691 void SAL_CALL ODatabaseForm::clearParameters()
3693 m_aParameterManager.clearParameters();
3697 void SAL_CALL ODatabaseForm::propertyChange( const PropertyChangeEvent& evt )
3699 if ( evt.Source == m_xParent )
3701 if ( evt.PropertyName == PROPERTY_ISNEW )
3703 bool bCurrentIsNew( false );
3704 OSL_VERIFY( evt.NewValue >>= bCurrentIsNew );
3705 if ( !bCurrentIsNew )
3706 reload_impl( true );
3708 return;
3710 OFormComponents::propertyChange( evt );
3713 // css::lang::XServiceInfo
3715 OUString SAL_CALL ODatabaseForm::getImplementationName()
3717 return "com.sun.star.comp.forms.ODatabaseForm";
3721 Sequence< OUString > SAL_CALL ODatabaseForm::getSupportedServiceNames()
3723 // the services of our aggregate
3724 Sequence< OUString > aServices;
3725 Reference< XServiceInfo > xInfo;
3726 if (query_aggregation(m_xAggregate, xInfo))
3727 aServices = xInfo->getSupportedServiceNames();
3729 // concat without own services
3730 return ::comphelper::concatSequences(
3731 css::uno::Sequence<OUString> {
3732 FRM_SUN_FORMCOMPONENT, "com.sun.star.form.FormComponents",
3733 FRM_SUN_COMPONENT_FORM, FRM_SUN_COMPONENT_HTMLFORM,
3734 FRM_SUN_COMPONENT_DATAFORM, FRM_COMPONENT_FORM },
3735 aServices
3739 sal_Bool SAL_CALL ODatabaseForm::supportsService(const OUString& ServiceName)
3741 return cppu::supportsService(this, ServiceName);
3744 // css::io::XPersistObject
3745 const sal_uInt16 CYCLE = 0x0001;
3746 const sal_uInt16 DONTAPPLYFILTER = 0x0002;
3748 OUString ODatabaseForm::getServiceName()
3750 return FRM_COMPONENT_FORM; // old (non-sun) name for compatibility !
3753 void SAL_CALL ODatabaseForm::write(const Reference<XObjectOutputStream>& _rxOutStream)
3755 DBG_ASSERT(m_xAggregateSet.is(), "ODatabaseForm::write : only to be called if the aggregate exists !");
3757 // all children
3758 OFormComponents::write(_rxOutStream);
3760 // version
3761 _rxOutStream->writeShort(0x0005);
3763 // Name
3764 _rxOutStream << m_sName;
3766 OUString sDataSource;
3767 if (m_xAggregateSet.is())
3768 m_xAggregateSet->getPropertyValue(PROPERTY_DATASOURCE) >>= sDataSource;
3769 _rxOutStream << sDataSource;
3771 // former CursorSource
3772 OUString sCommand;
3773 if (m_xAggregateSet.is())
3774 m_xAggregateSet->getPropertyValue(PROPERTY_COMMAND) >>= sCommand;
3775 _rxOutStream << sCommand;
3777 // former MasterFields
3778 _rxOutStream << m_aMasterFields;
3779 // former DetailFields
3780 _rxOutStream << m_aDetailFields;
3782 // former DataSelectionType
3783 DataSelectionType eTranslated = DataSelectionType_TABLE;
3784 if (m_xAggregateSet.is())
3786 sal_Int32 nCommandType = 0;
3787 m_xAggregateSet->getPropertyValue(PROPERTY_COMMANDTYPE) >>= nCommandType;
3788 switch (nCommandType)
3790 case CommandType::TABLE : eTranslated = DataSelectionType_TABLE; break;
3791 case CommandType::QUERY : eTranslated = DataSelectionType_QUERY; break;
3792 case CommandType::COMMAND:
3794 bool bEscapeProcessing = getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_ESCAPE_PROCESSING));
3795 eTranslated = bEscapeProcessing ? DataSelectionType_SQL : DataSelectionType_SQLPASSTHROUGH;
3797 break;
3798 default : OSL_FAIL("ODatabaseForm::write : wrong CommandType !");
3801 _rxOutStream->writeShort(static_cast<sal_Int16>(eTranslated)); // former DataSelectionType
3803 // very old versions expect a CursorType here
3804 _rxOutStream->writeShort(2); // DatabaseCursorType_KEYSET
3806 _rxOutStream->writeBoolean(m_eNavigation != NavigationBarMode_NONE);
3808 // former DataEntry
3809 if (m_xAggregateSet.is())
3810 _rxOutStream->writeBoolean(getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_INSERTONLY)));
3811 else
3812 _rxOutStream->writeBoolean(false);
3814 _rxOutStream->writeBoolean(m_bAllowInsert);
3815 _rxOutStream->writeBoolean(m_bAllowUpdate);
3816 _rxOutStream->writeBoolean(m_bAllowDelete);
3818 // html form stuff
3819 OUString sTmp = INetURLObject::decode( m_aTargetURL, INetURLObject::DecodeMechanism::Unambiguous);
3820 _rxOutStream << sTmp;
3821 _rxOutStream->writeShort( static_cast<sal_Int16>(m_eSubmitMethod) );
3822 _rxOutStream->writeShort( static_cast<sal_Int16>(m_eSubmitEncoding) );
3823 _rxOutStream << m_aTargetFrame;
3825 // version 2 didn't know some options and the "default" state
3826 sal_Int32 nCycle = sal_Int32(TabulatorCycle_RECORDS);
3827 if (m_aCycle.hasValue())
3829 ::cppu::enum2int(nCycle, m_aCycle);
3830 if (m_aCycle == TabulatorCycle_PAGE)
3831 // unknown in earlier versions
3832 nCycle = sal_Int32(TabulatorCycle_RECORDS);
3834 _rxOutStream->writeShort(static_cast<sal_Int16>(nCycle));
3836 _rxOutStream->writeShort(static_cast<sal_Int16>(m_eNavigation));
3838 OUString sFilter;
3839 OUString sSort;
3840 if (m_xAggregateSet.is())
3842 m_xAggregateSet->getPropertyValue(PROPERTY_FILTER) >>= sFilter;
3843 // version 4
3844 m_xAggregateSet->getPropertyValue(PROPERTY_SORT) >>= sSort;
3846 _rxOutStream << sFilter;
3847 _rxOutStream << sSort;
3849 // version 3
3850 sal_uInt16 nAnyMask = 0;
3851 if (m_aCycle.hasValue())
3852 nAnyMask |= CYCLE;
3854 if (m_xAggregateSet.is() && !getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_APPLYFILTER)))
3855 nAnyMask |= DONTAPPLYFILTER;
3857 _rxOutStream->writeShort(nAnyMask);
3859 if (nAnyMask & CYCLE)
3861 sal_Int32 nRealCycle = 0;
3862 ::cppu::enum2int(nRealCycle, m_aCycle);
3863 _rxOutStream->writeShort(static_cast<sal_Int16>(nRealCycle));
3866 // version 5
3867 OUString sHaving;
3868 if (m_xAggregateSet.is())
3869 m_xAggregateSet->getPropertyValue(PROPERTY_HAVINGCLAUSE) >>= sHaving;
3870 _rxOutStream << sHaving;
3874 void SAL_CALL ODatabaseForm::read(const Reference<XObjectInputStream>& _rxInStream)
3876 DBG_ASSERT(m_xAggregateSet.is(), "ODatabaseForm::read : only to be called if the aggregate exists !");
3878 OFormComponents::read(_rxInStream);
3880 // version
3881 sal_uInt16 nVersion = _rxInStream->readShort();
3883 _rxInStream >> m_sName;
3885 OUString sAggregateProp;
3886 _rxInStream >> sAggregateProp;
3887 if (m_xAggregateSet.is())
3888 m_xAggregateSet->setPropertyValue(PROPERTY_DATASOURCE, makeAny(sAggregateProp));
3889 _rxInStream >> sAggregateProp;
3890 if (m_xAggregateSet.is())
3891 m_xAggregateSet->setPropertyValue(PROPERTY_COMMAND, makeAny(sAggregateProp));
3893 _rxInStream >> m_aMasterFields;
3894 _rxInStream >> m_aDetailFields;
3896 sal_Int16 nCursorSourceType = _rxInStream->readShort();
3897 sal_Int32 nCommandType = 0;
3898 switch (static_cast<DataSelectionType>(nCursorSourceType))
3900 case DataSelectionType_TABLE : nCommandType = CommandType::TABLE; break;
3901 case DataSelectionType_QUERY : nCommandType = CommandType::QUERY; break;
3902 case DataSelectionType_SQL:
3903 case DataSelectionType_SQLPASSTHROUGH:
3905 nCommandType = CommandType::COMMAND;
3906 bool bEscapeProcessing = static_cast<DataSelectionType>(nCursorSourceType) != DataSelectionType_SQLPASSTHROUGH;
3907 m_xAggregateSet->setPropertyValue(PROPERTY_ESCAPE_PROCESSING, makeAny(bEscapeProcessing));
3909 break;
3910 default : OSL_FAIL("ODatabaseForm::read : wrong CommandType !");
3912 if (m_xAggregateSet.is())
3913 m_xAggregateSet->setPropertyValue(PROPERTY_COMMANDTYPE, makeAny(nCommandType));
3915 // obsolete
3916 _rxInStream->readShort();
3918 // navigation mode was a boolean in version 1
3919 // was a sal_Bool in version 1
3920 bool bNavigation = _rxInStream->readBoolean();
3921 if (nVersion == 1)
3922 m_eNavigation = bNavigation ? NavigationBarMode_CURRENT : NavigationBarMode_NONE;
3924 bool bInsertOnly = _rxInStream->readBoolean();
3925 if (m_xAggregateSet.is())
3926 m_xAggregateSet->setPropertyValue(PROPERTY_INSERTONLY, makeAny(bInsertOnly));
3928 m_bAllowInsert = _rxInStream->readBoolean();
3929 m_bAllowUpdate = _rxInStream->readBoolean();
3930 m_bAllowDelete = _rxInStream->readBoolean();
3932 // html stuff
3933 OUString sTmp;
3934 _rxInStream >> sTmp;
3935 m_aTargetURL = INetURLObject::decode( sTmp, INetURLObject::DecodeMechanism::Unambiguous);
3936 m_eSubmitMethod = static_cast<FormSubmitMethod>(_rxInStream->readShort());
3937 m_eSubmitEncoding = static_cast<FormSubmitEncoding>(_rxInStream->readShort());
3938 _rxInStream >> m_aTargetFrame;
3940 if (nVersion > 1)
3942 sal_Int32 nCycle = _rxInStream->readShort();
3943 m_aCycle <<= TabulatorCycle(nCycle);
3944 m_eNavigation = static_cast<NavigationBarMode>(_rxInStream->readShort());
3946 _rxInStream >> sAggregateProp;
3947 if (m_xAggregateSet.is())
3948 m_xAggregateSet->setPropertyValue(PROPERTY_FILTER, makeAny(sAggregateProp));
3949 if(nVersion > 3)
3951 _rxInStream >> sAggregateProp;
3952 if (m_xAggregateSet.is())
3953 m_xAggregateSet->setPropertyValue(PROPERTY_SORT, makeAny(sAggregateProp));
3957 sal_uInt16 nAnyMask = 0;
3958 if (nVersion > 2)
3960 nAnyMask = _rxInStream->readShort();
3961 if (nAnyMask & CYCLE)
3963 sal_Int32 nCycle = _rxInStream->readShort();
3964 m_aCycle <<= TabulatorCycle(nCycle);
3966 else
3967 m_aCycle.clear();
3969 if (m_xAggregateSet.is())
3970 m_xAggregateSet->setPropertyValue(PROPERTY_APPLYFILTER, makeAny((nAnyMask & DONTAPPLYFILTER) == 0));
3972 if(nVersion > 4)
3974 _rxInStream >> sAggregateProp;
3975 if (m_xAggregateSet.is())
3976 m_xAggregateSet->setPropertyValue(PROPERTY_HAVINGCLAUSE, makeAny(sAggregateProp));
3981 void ODatabaseForm::implInserted( const ElementDescription* _pElement )
3983 OFormComponents::implInserted( _pElement );
3985 Reference< XSQLErrorBroadcaster > xBroadcaster( _pElement->xInterface, UNO_QUERY );
3986 Reference< XForm > xForm ( _pElement->xInterface, UNO_QUERY );
3988 if ( xBroadcaster.is() && !xForm.is() )
3989 { // the object is an error broadcaster, but no form itself -> add ourself as listener
3990 xBroadcaster->addSQLErrorListener( this );
3995 void ODatabaseForm::implRemoved(const css::uno::Reference<css::uno::XInterface>& _rxObject)
3997 OFormComponents::implRemoved( _rxObject );
3999 Reference<XSQLErrorBroadcaster> xBroadcaster(_rxObject, UNO_QUERY);
4000 Reference<XForm> xForm(_rxObject, UNO_QUERY);
4001 if (xBroadcaster.is() && !xForm.is())
4002 { // the object is an error broadcaster, but no form itself -> remove ourself as listener
4003 xBroadcaster->removeSQLErrorListener(this);
4007 void SAL_CALL ODatabaseForm::errorOccured(const SQLErrorEvent& _rEvent)
4009 // give it to my own error listener
4010 onError(_rEvent);
4011 // TODO: think about extending the chain with an SQLContext object saying
4012 // "this was an error of one of my children"
4015 // css::container::XNamed
4016 OUString SAL_CALL ODatabaseForm::getName()
4018 OUString sReturn;
4021 OPropertySetHelper::getFastPropertyValue(PROPERTY_ID_NAME) >>= sReturn;
4023 catch (const css::beans::UnknownPropertyException&)
4025 throw WrappedTargetRuntimeException(
4026 "ODatabaseForm::getName",
4027 *this,
4028 ::cppu::getCaughtException()
4031 return sReturn;
4034 void SAL_CALL ODatabaseForm::setName(const OUString& aName)
4036 setFastPropertyValue(PROPERTY_ID_NAME, makeAny(aName));
4039 } // namespace frm
4041 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
4042 com_sun_star_comp_forms_ODatabaseForm_get_implementation(css::uno::XComponentContext* context,
4043 css::uno::Sequence<css::uno::Any> const &)
4045 return cppu::acquire(new frm::ODatabaseForm(context));
4048 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */