Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / forms / source / component / DatabaseForm.cxx
blobfccd2367ea174e615583188bab0bfdb82c4f3f51
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 .
20 #include <sal/config.h>
22 #include <string_view>
24 #include <componenttools.hxx>
25 #include "DatabaseForm.hxx"
26 #include "EventThread.hxx"
27 #include <strings.hrc>
28 #include <frm_resource.hxx>
29 #include "GroupManager.hxx"
30 #include <property.hxx>
31 #include <services.hxx>
32 #include <comphelper/propertyvalue.hxx>
34 #include <com/sun/star/awt/XControlContainer.hpp>
35 #include <com/sun/star/awt/XTextComponent.hpp>
36 #include <com/sun/star/beans/PropertyAttribute.hpp>
37 #include <com/sun/star/form/DataSelectionType.hpp>
38 #include <com/sun/star/form/FormComponentType.hpp>
39 #include <com/sun/star/form/TabulatorCycle.hpp>
40 #include <com/sun/star/frame/FrameSearchFlag.hpp>
41 #include <com/sun/star/frame/XDispatch.hpp>
42 #include <com/sun/star/frame/XDispatchProvider.hpp>
43 #include <com/sun/star/frame/XModel.hpp>
44 #include <com/sun/star/io/XObjectInputStream.hpp>
45 #include <com/sun/star/io/XObjectOutputStream.hpp>
46 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
47 #include <com/sun/star/sdb/CommandType.hpp>
48 #include <com/sun/star/sdb/RowSetVetoException.hpp>
49 #include <com/sun/star/sdb/XColumnUpdate.hpp>
50 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
51 #include <com/sun/star/sdbc/ResultSetType.hpp>
52 #include <com/sun/star/sdbc/XRowSet.hpp>
53 #include <com/sun/star/sdbcx/Privilege.hpp>
54 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
55 #include <com/sun/star/util/URLTransformer.hpp>
56 #include <com/sun/star/util/XURLTransformer.hpp>
57 #include <com/sun/star/util/XModifiable2.hpp>
59 #include <comphelper/basicio.hxx>
60 #include <comphelper/property.hxx>
61 #include <comphelper/seqstream.hxx>
62 #include <comphelper/sequence.hxx>
63 #include <connectivity/dbtools.hxx>
64 #include <cppuhelper/exc_hlp.hxx>
65 #include <cppuhelper/supportsservice.hxx>
66 #include <comphelper/types.hxx>
67 #include <rtl/math.hxx>
68 #include <rtl/tencinfo.h>
69 #include <svl/inettype.hxx>
70 #include <tools/datetime.hxx>
71 #include <tools/debug.hxx>
72 #include <comphelper/diagnose_ex.hxx>
73 #include <tools/inetmsg.hxx>
74 #include <tools/inetstrm.hxx>
75 #include <tools/urlobj.hxx>
76 #include <unotools/ucbstreamhelper.hxx>
77 #include <vcl/svapp.hxx>
78 #include <vcl/timer.hxx>
79 #include <osl/mutex.hxx>
81 using namespace ::dbtools;
82 using namespace ::comphelper;
83 using namespace ::com::sun::star::uno;
84 using namespace ::com::sun::star::sdb;
85 using namespace ::com::sun::star::sdbc;
86 using namespace ::com::sun::star::sdbcx;
87 using namespace ::com::sun::star::beans;
88 using namespace ::com::sun::star::container;
89 using namespace ::com::sun::star::task;
90 using namespace ::com::sun::star::frame;
91 using namespace ::com::sun::star::form;
92 using namespace ::com::sun::star::awt;
93 using namespace ::com::sun::star::io;
94 using namespace ::com::sun::star::lang;
95 using namespace ::com::sun::star::util;
98 namespace frm
101 namespace {
103 class DocumentModifyGuard
105 public:
106 explicit DocumentModifyGuard( const Reference< XInterface >& _rxFormComponent )
107 :m_xDocumentModify( getXModel( _rxFormComponent ), UNO_QUERY )
109 impl_changeModifiableFlag_nothrow( false );
111 ~DocumentModifyGuard()
113 impl_changeModifiableFlag_nothrow( true );
116 private:
117 void impl_changeModifiableFlag_nothrow( const bool _enable )
121 if ( m_xDocumentModify.is() )
122 _enable ? m_xDocumentModify->enableSetModified() : m_xDocumentModify->disableSetModified();
124 catch(const Exception&)
126 DBG_UNHANDLED_EXCEPTION("forms.component");
130 private:
131 Reference< XModifiable2 > m_xDocumentModify;
136 // submitting and resetting html-forms asynchronously
137 class OFormSubmitResetThread: public OComponentEventThread
139 protected:
141 // process an event. while processing the mutex isn't locked, and pCompImpl
142 // is made sure to remain valid
143 virtual void processEvent( ::cppu::OComponentHelper* _pCompImpl,
144 const EventObject* _pEvt,
145 const Reference<XControl>& _rControl,
146 bool _bSubmit) override;
148 public:
150 explicit OFormSubmitResetThread(ODatabaseForm* pControl) : OComponentEventThread(pControl) { }
154 void OFormSubmitResetThread::processEvent(
155 ::cppu::OComponentHelper* pCompImpl,
156 const EventObject *_pEvt,
157 const Reference<XControl>& _rControl,
158 bool _bSubmit)
160 if (_bSubmit)
161 static_cast<ODatabaseForm *>(pCompImpl)->submit_impl(_rControl, *static_cast<const css::awt::MouseEvent*>(_pEvt));
162 else
163 static_cast<ODatabaseForm *>(pCompImpl)->reset_impl(true);
167 //= ODatabaseForm
169 Sequence<sal_Int8> SAL_CALL ODatabaseForm::getImplementationId()
171 return css::uno::Sequence<sal_Int8>();
175 Sequence<Type> SAL_CALL ODatabaseForm::getTypes()
177 // ask the aggregate
178 Sequence<Type> aAggregateTypes;
179 Reference<XTypeProvider> xAggregateTypes;
180 if (query_aggregation(m_xAggregate, xAggregateTypes))
181 aAggregateTypes = xAggregateTypes->getTypes();
183 Sequence< Type > aRet = concatSequences(
184 aAggregateTypes, ODatabaseForm_BASE1::getTypes(), OFormComponents::getTypes()
186 aRet = concatSequences( aRet, ODatabaseForm_BASE2::getTypes(), ODatabaseForm_BASE3::getTypes() );
187 return concatSequences( aRet, OPropertySetAggregationHelper::getTypes() );
191 Any SAL_CALL ODatabaseForm::queryAggregation(const Type& _rType)
193 Any aReturn = ODatabaseForm_BASE1::queryInterface(_rType);
194 // our own interfaces
195 if (!aReturn.hasValue())
197 aReturn = ODatabaseForm_BASE2::queryInterface(_rType);
198 // property set related interfaces
199 if (!aReturn.hasValue())
201 aReturn = OPropertySetAggregationHelper::queryInterface(_rType);
203 // form component collection related interfaces
204 if (!aReturn.hasValue())
206 aReturn = OFormComponents::queryAggregation(_rType);
208 // interfaces already present in the aggregate which we want to reroute
209 // only available if we could create the aggregate
210 if (!aReturn.hasValue() && m_xAggregateAsRowSet.is())
211 aReturn = ODatabaseForm_BASE3::queryInterface(_rType);
213 // aggregate interfaces
214 // (ask the aggregated object _after_ the OComponentHelper (base of OFormComponents),
215 // so calls to the XComponent interface reach us and not the aggregation)
216 if (!aReturn.hasValue() && m_xAggregate.is())
217 aReturn = m_xAggregate->queryAggregation(_rType);
222 return aReturn;
226 ODatabaseForm::ODatabaseForm(const Reference<XComponentContext>& _rxContext)
227 :OFormComponents(_rxContext)
228 ,OPropertySetAggregationHelper(OComponentHelper::rBHelper)
229 ,OPropertyChangeListener(m_aMutex)
230 ,m_aLoadListeners(m_aMutex)
231 ,m_aRowSetApproveListeners(m_aMutex)
232 ,m_aSubmitListeners(m_aMutex)
233 ,m_aErrorListeners(m_aMutex)
234 ,m_aResetListeners(m_aMutex)
235 ,m_aPropertyBagHelper( *this )
236 ,m_aParameterManager( m_aMutex, _rxContext )
237 ,m_aFilterManager()
238 ,m_nResetsPending(0)
239 ,m_nPrivileges(0)
240 ,m_bInsertOnly( false )
241 ,m_eSubmitMethod(FormSubmitMethod_GET)
242 ,m_eSubmitEncoding(FormSubmitEncoding_URL)
243 ,m_eNavigation(NavigationBarMode_CURRENT)
244 ,m_bAllowInsert(true)
245 ,m_bAllowUpdate(true)
246 ,m_bAllowDelete(true)
247 ,m_bLoaded(false)
248 ,m_bSubForm(false)
249 ,m_bForwardingConnection(false)
250 ,m_bSharingConnection( false )
252 impl_construct();
256 ODatabaseForm::ODatabaseForm( const ODatabaseForm& _cloneSource )
257 :OFormComponents( _cloneSource )
258 ,OPropertySetAggregationHelper( OComponentHelper::rBHelper )
259 ,OPropertyChangeListener( m_aMutex )
260 ,ODatabaseForm_BASE1()
261 ,ODatabaseForm_BASE2()
262 ,ODatabaseForm_BASE3()
263 ,IPropertyBagHelperContext()
264 ,m_aLoadListeners( m_aMutex )
265 ,m_aRowSetApproveListeners( m_aMutex )
266 ,m_aSubmitListeners( m_aMutex )
267 ,m_aErrorListeners( m_aMutex )
268 ,m_aResetListeners( m_aMutex )
269 ,m_aPropertyBagHelper( *this )
270 ,m_aParameterManager( m_aMutex, _cloneSource.m_xContext )
271 ,m_aFilterManager()
272 ,m_nResetsPending( 0 )
273 ,m_nPrivileges( 0 )
274 ,m_bInsertOnly( _cloneSource.m_bInsertOnly )
275 ,m_aControlBorderColorFocus( _cloneSource.m_aControlBorderColorFocus )
276 ,m_aControlBorderColorMouse( _cloneSource.m_aControlBorderColorMouse )
277 ,m_aControlBorderColorInvalid( _cloneSource.m_aControlBorderColorInvalid )
278 ,m_aDynamicControlBorder( _cloneSource.m_aDynamicControlBorder )
279 ,m_sName( _cloneSource.m_sName )
280 ,m_aTargetURL( _cloneSource.m_aTargetURL )
281 ,m_aTargetFrame( _cloneSource.m_aTargetFrame )
282 ,m_eSubmitMethod( _cloneSource.m_eSubmitMethod )
283 ,m_eSubmitEncoding( _cloneSource.m_eSubmitEncoding )
284 ,m_eNavigation( _cloneSource.m_eNavigation )
285 ,m_bAllowInsert( _cloneSource.m_bAllowInsert )
286 ,m_bAllowUpdate( _cloneSource.m_bAllowUpdate )
287 ,m_bAllowDelete( _cloneSource.m_bAllowDelete )
288 ,m_bLoaded( false )
289 ,m_bSubForm( false )
290 ,m_bForwardingConnection( false )
291 ,m_bSharingConnection( false )
294 impl_construct();
296 osl_atomic_increment( &m_refCount );
298 // our aggregated rowset itself is not cloneable, so simply copy the properties
299 ::comphelper::copyProperties( _cloneSource.m_xAggregateSet, m_xAggregateSet );
301 // also care for the dynamic properties: If the clone source has properties which we do not have,
302 // then add them
305 Reference< XPropertySet > xSourceProps( const_cast< ODatabaseForm& >( _cloneSource ).queryAggregation(
306 cppu::UnoType<XPropertySet>::get() ), UNO_QUERY_THROW );
307 Reference< XPropertySetInfo > xSourcePSI( xSourceProps->getPropertySetInfo(), UNO_SET_THROW );
308 Reference< XPropertyState > xSourcePropState( xSourceProps, UNO_QUERY );
310 Reference< XPropertySetInfo > xDestPSI( getPropertySetInfo(), UNO_SET_THROW );
312 const Sequence< Property > aSourceProperties( xSourcePSI->getProperties() );
313 for ( auto const & sourceProperty : aSourceProperties )
315 if ( xDestPSI->hasPropertyByName( sourceProperty.Name ) )
316 continue;
318 // the initial value passed to XPropertyContainer is also used as default, usually. So, try
319 // to retrieve the default of the source property
320 Any aInitialValue;
321 if ( xSourcePropState.is() )
323 aInitialValue = xSourcePropState->getPropertyDefault( sourceProperty.Name );
325 else
327 aInitialValue = xSourceProps->getPropertyValue( sourceProperty.Name );
329 addProperty( sourceProperty.Name, sourceProperty.Attributes, aInitialValue );
330 setPropertyValue( sourceProperty.Name, xSourceProps->getPropertyValue( sourceProperty.Name ) );
333 catch(const RuntimeException&)
335 throw;
337 catch(const Exception&)
339 css::uno::Any a(cppu::getCaughtException());
340 throw WrappedTargetRuntimeException(
341 "Could not clone the given database form.",
342 *const_cast< ODatabaseForm* >( &_cloneSource ),
347 osl_atomic_decrement( &m_refCount );
350 void ODatabaseForm::impl_construct()
352 // aggregate a row set
353 osl_atomic_increment(&m_refCount);
355 m_xAggregate.set( m_xContext->getServiceManager()->createInstanceWithContext(SRV_SDB_ROWSET, m_xContext), UNO_QUERY_THROW );
356 m_xAggregateAsRowSet.set( m_xAggregate, UNO_QUERY_THROW );
357 setAggregation( m_xAggregate );
360 // listen for the properties, important for Parameters
361 if ( m_xAggregateSet.is() )
363 m_xAggregatePropertyMultiplexer = new OPropertyChangeMultiplexer(this, m_xAggregateSet, false);
364 m_xAggregatePropertyMultiplexer->addProperty(PROPERTY_COMMAND);
365 m_xAggregatePropertyMultiplexer->addProperty(PROPERTY_ACTIVE_CONNECTION);
369 Reference< XWarningsSupplier > xRowSetWarnings( m_xAggregate, UNO_QUERY );
370 m_aWarnings.setExternalWarnings( xRowSetWarnings );
373 if ( m_xAggregate.is() )
375 m_xAggregate->setDelegator( static_cast< XWeak* >( this ) );
379 m_aFilterManager.initialize( m_xAggregateSet );
380 m_aParameterManager.initialize( this, m_xAggregate );
382 declareForwardedProperty( PROPERTY_ID_ACTIVE_CONNECTION );
384 osl_atomic_decrement( &m_refCount );
386 m_pGroupManager = new OGroupManager( this );
390 ODatabaseForm::~ODatabaseForm()
392 m_pGroupManager.clear();
394 if (m_xAggregate.is())
395 m_xAggregate->setDelegator( nullptr );
397 m_aWarnings.setExternalWarnings( nullptr );
399 if (m_xAggregatePropertyMultiplexer.is())
401 m_xAggregatePropertyMultiplexer->dispose();
402 m_xAggregatePropertyMultiplexer.clear();
407 // html tools
409 OUString ODatabaseForm::GetDataEncoded(bool _bURLEncoded,const Reference<XControl>& SubmitButton, const css::awt::MouseEvent& MouseEvt)
411 // Fill List of successful Controls
412 HtmlSuccessfulObjList aSuccObjList;
413 FillSuccessfulList( aSuccObjList, SubmitButton, MouseEvt );
416 // Aggregate the list to OUString
417 OUStringBuffer aResult;
418 OUString aName;
419 OUString aValue;
421 for ( HtmlSuccessfulObjList::iterator pSuccObj = aSuccObjList.begin();
422 pSuccObj < aSuccObjList.end();
423 ++pSuccObj
426 aName = pSuccObj->aName;
427 aValue = pSuccObj->aValue;
428 if( pSuccObj->nRepresentation == SUCCESSFUL_REPRESENT_FILE && !aValue.isEmpty() )
430 // For File URLs we transfer the file name and not a URL, because Netscape does it like that
431 INetURLObject aURL;
432 aURL.SetSmartProtocol(INetProtocol::File);
433 aURL.SetSmartURL(aValue);
434 if( INetProtocol::File == aURL.GetProtocol() )
435 aValue = INetURLObject::decode(aURL.PathToFileName(), INetURLObject::DecodeMechanism::Unambiguous);
437 Encode( aName );
438 Encode( aValue );
440 aResult.append(aName + "=" + aValue);
442 if (pSuccObj < aSuccObjList.end() - 1)
444 if ( _bURLEncoded )
445 aResult.append('&');
446 else
447 aResult.append("\r\n");
452 aSuccObjList.clear();
454 return aResult.makeStringAndClear();
458 // html tools
460 Sequence<sal_Int8> ODatabaseForm::GetDataMultiPartEncoded(const Reference<XControl>& SubmitButton, const css::awt::MouseEvent& MouseEvt, OUString& rContentType)
463 // Create Parent
464 INetMIMEMessage aParent;
465 aParent.EnableAttachMultipartFormDataChild();
468 // Fill List of successful Controls
469 HtmlSuccessfulObjList aSuccObjList;
470 FillSuccessfulList( aSuccObjList, SubmitButton, MouseEvt );
473 // Aggregate List to OUString
474 for (auto const& succObj : aSuccObjList)
476 if( succObj.nRepresentation == SUCCESSFUL_REPRESENT_TEXT )
477 InsertTextPart( aParent, succObj.aName, succObj.aValue );
478 else if( succObj.nRepresentation == SUCCESSFUL_REPRESENT_FILE )
479 InsertFilePart( aParent, succObj.aName, succObj.aValue );
483 // Delete List
484 aSuccObjList.clear();
486 // Create MessageStream for parent
487 INetMIMEMessageStream aMessStream(&aParent, true);
489 // Copy MessageStream to SvStream
490 SvMemoryStream aMemStream;
491 std::unique_ptr<char[]> pBuf(new char[1025]);
492 int nRead;
493 while( (nRead = aMessStream.Read(pBuf.get(), 1024)) > 0 )
495 aMemStream.WriteBytes(pBuf.get(), nRead);
497 pBuf.reset();
499 aMemStream.FlushBuffer();
500 aMemStream.Seek( 0 );
501 void const * pData = aMemStream.GetData();
502 sal_Int32 nLen = aMemStream.TellEnd();
504 rContentType = aParent.GetContentType();
505 return Sequence<sal_Int8>(static_cast<sal_Int8 const *>(pData), nLen);
509 namespace
511 void appendDigits( sal_Int32 _nNumber, sal_Int8 nDigits, OUStringBuffer& _rOut )
513 sal_Int32 nCurLen = _rOut.getLength();
514 _rOut.append( _nNumber );
515 while ( _rOut.getLength() - nCurLen < nDigits )
516 _rOut.insert( nCurLen, '0' );
521 void ODatabaseForm::AppendComponent(HtmlSuccessfulObjList& rList, const Reference<XPropertySet>& xComponentSet, std::u16string_view rNamePrefix,
522 const Reference<XControl>& rxSubmitButton, const css::awt::MouseEvent& MouseEvt)
524 if (!xComponentSet.is())
525 return;
527 // TODO: Catch nested Forms; or would we need to submit them?
528 if (!hasProperty(PROPERTY_CLASSID, xComponentSet))
529 return;
531 // Get names
532 if (!hasProperty(PROPERTY_NAME, xComponentSet))
533 return;
535 sal_Int16 nClassId = 0;
536 xComponentSet->getPropertyValue(PROPERTY_CLASSID) >>= nClassId;
537 OUString aName;
538 xComponentSet->getPropertyValue( PROPERTY_NAME ) >>= aName;
539 if( aName.isEmpty() && nClassId != FormComponentType::IMAGEBUTTON)
540 return;
541 else // Extend name with the prefix
542 aName = rNamePrefix + aName;
544 switch( nClassId )
546 // Buttons
547 case FormComponentType::COMMANDBUTTON:
549 // We only evaluate the pressed Submit button
550 // If one is passed at all
551 if( rxSubmitButton.is() )
553 Reference<XPropertySet> xSubmitButtonComponent(rxSubmitButton->getModel(), UNO_QUERY);
554 if (xSubmitButtonComponent == xComponentSet && hasProperty(PROPERTY_LABEL, xComponentSet))
556 // <name>=<label>
557 OUString aLabel;
558 xComponentSet->getPropertyValue( PROPERTY_LABEL ) >>= aLabel;
559 rList.emplace_back(aName, aLabel );
562 } break;
564 // ImageButtons
565 case FormComponentType::IMAGEBUTTON:
567 // We only evaluate the pressed Submit button
568 // If one is passed at all
569 if( rxSubmitButton.is() )
571 Reference<XPropertySet> xSubmitButtonComponent(rxSubmitButton->getModel(), UNO_QUERY);
572 if (xSubmitButtonComponent == xComponentSet)
574 // <name>.x=<pos.X>&<name>.y=<pos.Y>
575 OUString aRhs = OUString::number( MouseEvt.X );
577 // Only if a name is available we have a name.x
578 OUStringBuffer aLhs(aName);
579 if (!aName.isEmpty())
580 aLhs.append(".x");
581 else
582 aLhs.append("x");
583 rList.emplace_back(aLhs.makeStringAndClear(), aRhs );
585 aLhs.append(aName);
586 aRhs = OUString::number( MouseEvt.Y );
587 if (!aName.isEmpty())
588 aLhs.append(".y");
589 else
590 aLhs.append("y");
591 rList.emplace_back(aLhs.makeStringAndClear(), aRhs );
594 } break;
596 // CheckBoxes/RadioButtons
597 case FormComponentType::CHECKBOX:
598 case FormComponentType::RADIOBUTTON:
600 // <name>=<refValue>
601 if( !hasProperty(PROPERTY_STATE, xComponentSet) )
602 break;
603 sal_Int16 nChecked = 0;
604 xComponentSet->getPropertyValue( PROPERTY_STATE ) >>= nChecked;
605 if( nChecked != 1 )
606 break;
608 OUString aStrValue;
609 if( hasProperty(PROPERTY_REFVALUE, xComponentSet) )
610 xComponentSet->getPropertyValue( PROPERTY_REFVALUE ) >>= aStrValue;
612 rList.emplace_back(aName, aStrValue );
613 } break;
615 // Edit
616 case FormComponentType::TEXTFIELD:
618 // <name>=<text>
619 if( !hasProperty(PROPERTY_TEXT, xComponentSet) )
620 break;
622 // Special treatment for multiline edit only if we have a control for it
623 Any aTmp = xComponentSet->getPropertyValue( PROPERTY_MULTILINE );
624 bool bMulti = rxSubmitButton.is()
625 && (aTmp.getValueType().getTypeClass() == TypeClass_BOOLEAN)
626 && getBOOL(aTmp);
627 OUString sText;
628 if ( bMulti ) // For multiline edit, get the text at the control
631 Reference<XControlContainer> xControlContainer(rxSubmitButton->getContext(), UNO_QUERY);
632 if( !xControlContainer.is() ) break;
634 // Find the right control
635 bool bFound = false;
636 const Sequence<Reference<XControl>> aControls = xControlContainer->getControls();
637 for( auto const& xControl : aControls )
639 Reference<XPropertySet> xModel(xControl->getModel(), UNO_QUERY);
640 if ((bFound = xModel == xComponentSet))
642 Reference<XTextComponent> xTextComponent(xControl, UNO_QUERY);
643 if( xTextComponent.is() )
644 sText = xTextComponent->getText();
645 break;
648 // Couldn't find control or it does not exist (edit in the grid)
649 if (!bFound)
650 xComponentSet->getPropertyValue( PROPERTY_TEXT ) >>= sText;
652 else
653 xComponentSet->getPropertyValue( PROPERTY_TEXT ) >>= sText;
655 rList.emplace_back(aName, sText );
656 } break;
658 // ComboBox, Patternfield
659 case FormComponentType::COMBOBOX:
660 case FormComponentType::PATTERNFIELD:
662 // <name>=<text>
663 if( hasProperty(PROPERTY_TEXT, xComponentSet) )
665 OUString aText;
666 xComponentSet->getPropertyValue( PROPERTY_TEXT ) >>= aText;
667 rList.emplace_back(aName, aText );
669 } break;
670 case FormComponentType::CURRENCYFIELD:
671 case FormComponentType::NUMERICFIELD:
673 // <name>=<value> // Value is a double with dot as decimal delimiter
674 // no value (NULL) means empty value
675 if( hasProperty(PROPERTY_VALUE, xComponentSet) )
677 OUString aText;
678 Any aVal = xComponentSet->getPropertyValue( PROPERTY_VALUE );
680 double aDoubleVal = 0;
681 if (aVal >>= aDoubleVal)
683 sal_Int16 nScale = 0;
684 xComponentSet->getPropertyValue( PROPERTY_DECIMAL_ACCURACY ) >>= nScale;
685 aText = ::rtl::math::doubleToUString(aDoubleVal, rtl_math_StringFormat_F, nScale, '.', true);
687 rList.emplace_back(aName, aText );
689 } break;
690 case FormComponentType::DATEFIELD:
692 // <name>=<value> // Value is a Date with the format MM-DD-YYYY
693 // no value (NULL) means empty value
694 if( hasProperty(PROPERTY_DATE, xComponentSet) )
696 OUString aText;
697 Any aVal = xComponentSet->getPropertyValue( PROPERTY_DATE );
698 sal_Int32 nInt32Val = 0;
699 if (aVal >>= nInt32Val)
701 ::Date aDate( nInt32Val );
702 OUStringBuffer aBuffer;
703 appendDigits( aDate.GetMonth(), 2, aBuffer );
704 aBuffer.append( '-' );
705 appendDigits( aDate.GetDay(), 2, aBuffer );
706 aBuffer.append( '-' );
707 appendDigits( aDate.GetYear(), 4, aBuffer );
708 aText = aBuffer.makeStringAndClear();
710 rList.emplace_back(aName, aText );
712 } break;
713 case FormComponentType::TIMEFIELD:
715 // <name>=<value> // Value is a Time with the format HH:MM:SS
716 // no value (NULL) means empty value
717 if( hasProperty(PROPERTY_TIME, xComponentSet) )
719 OUString aText;
720 Any aVal = xComponentSet->getPropertyValue( PROPERTY_TIME );
721 sal_Int32 nInt32Val = 0;
722 if (aVal >>= nInt32Val)
724 ::tools::Time aTime(nInt32Val);
725 OUStringBuffer aBuffer;
726 appendDigits( aTime.GetHour(), 2, aBuffer );
727 aBuffer.append( '-' );
728 appendDigits( aTime.GetMin(), 2, aBuffer );
729 aBuffer.append( '-' );
730 appendDigits( aTime.GetSec(), 2, aBuffer );
731 aText = aBuffer.makeStringAndClear();
733 rList.emplace_back(aName, aText );
735 } break;
737 // starform
738 case FormComponentType::HIDDENCONTROL:
741 // <name>=<value>
742 if( hasProperty(PROPERTY_HIDDEN_VALUE, xComponentSet) )
744 OUString aText;
745 xComponentSet->getPropertyValue( PROPERTY_HIDDEN_VALUE ) >>= aText;
746 rList.emplace_back(aName, aText );
748 } break;
750 // starform
751 case FormComponentType::FILECONTROL:
753 // <name>=<text>
754 if( hasProperty(PROPERTY_TEXT, xComponentSet) )
757 OUString aText;
758 xComponentSet->getPropertyValue( PROPERTY_TEXT ) >>= aText;
759 rList.emplace_back(aName, aText, SUCCESSFUL_REPRESENT_FILE );
761 } break;
763 // starform
764 case FormComponentType::LISTBOX:
767 // <name>=<Token0>&<name>=<Token1>&...&<name>=<TokenN> (multiple selection)
768 if (!hasProperty(PROPERTY_SELECT_SEQ, xComponentSet) ||
769 !hasProperty(PROPERTY_STRINGITEMLIST, xComponentSet))
770 break;
772 // Displayed values
773 Sequence< OUString > aVisibleList;
774 xComponentSet->getPropertyValue( PROPERTY_STRINGITEMLIST ) >>= aVisibleList;
775 sal_Int32 nStringCnt = aVisibleList.getLength();
776 const OUString* pStrings = aVisibleList.getConstArray();
778 // Value list
779 Sequence< OUString > aValueList;
780 xComponentSet->getPropertyValue( PROPERTY_VALUE_SEQ ) >>= aValueList;
781 sal_Int32 nValCnt = aValueList.getLength();
782 const OUString* pVals = aValueList.getConstArray();
784 // Selection
785 Sequence<sal_Int16> aSelectList;
786 xComponentSet->getPropertyValue( PROPERTY_SELECT_SEQ ) >>= aSelectList;
787 sal_Int32 nSelCount = aSelectList.getLength();
788 const sal_Int16* pSels = aSelectList.getConstArray();
790 // Simple or multiple selection
791 // For simple selections MT only accounts for the list's first entry.
792 if (nSelCount > 1 && !getBOOL(xComponentSet->getPropertyValue(PROPERTY_MULTISELECTION)))
793 nSelCount = 1;
795 // The indices in the selection list can also be invalid, so we first have to
796 // find the valid ones to determine the length of the new list.
797 sal_Int32 nCurCnt = 0;
798 sal_Int32 i;
799 for( i=0; i<nSelCount; ++i )
801 if( pSels[i] < nStringCnt )
802 ++nCurCnt;
805 OUString aSubValue;
806 for(i=0; i<nCurCnt; ++i )
808 sal_Int16 nSelPos = pSels[i];
809 if (nSelPos < nValCnt && !pVals[nSelPos].isEmpty())
811 aSubValue = pVals[nSelPos];
813 else
815 aSubValue = pStrings[nSelPos];
817 rList.emplace_back(aName, aSubValue );
819 } break;
820 case FormComponentType::GRIDCONTROL:
822 // Each of the column values is sent;
823 // the name is extended by the grid's prefix.
824 Reference<XIndexAccess> xContainer(xComponentSet, UNO_QUERY);
825 if (!xContainer.is())
826 break;
828 aName += ".";
830 Reference<XPropertySet> xSet;
831 sal_Int32 nCount = xContainer->getCount();
832 // we know already how many objects should be appended,
833 // so why not allocate the space for them
834 rList.reserve( nCount + rList.capacity() ); // not size()
835 for (sal_Int32 i = 0; i < nCount; ++i)
837 xContainer->getByIndex(i) >>= xSet;
838 if (xSet.is())
839 AppendComponent(rList, xSet, aName, rxSubmitButton, MouseEvt);
846 void ODatabaseForm::FillSuccessfulList( HtmlSuccessfulObjList& rList,
847 const Reference<XControl>& rxSubmitButton, const css::awt::MouseEvent& MouseEvt )
849 // Delete list
850 rList.clear();
851 // Iterate over Components
852 Reference<XPropertySet> xComponentSet;
854 // we know already how many objects should be appended,
855 // so why not allocate the space for them
856 rList.reserve( getCount() );
857 for( sal_Int32 nIndex=0; nIndex < getCount(); nIndex++ )
859 getByIndex( nIndex ) >>= xComponentSet;
860 AppendComponent(rList, xComponentSet, std::u16string_view(), rxSubmitButton, MouseEvt);
865 void ODatabaseForm::Encode( OUString& rString )
867 OUStringBuffer aResult;
869 // Line endings are represented as CR
870 rString = convertLineEnd(rString, LINEEND_CR);
872 // Check each character
873 sal_Int32 nStrLen = rString.getLength();
874 sal_Unicode nCharCode;
875 for( sal_Int32 nCurPos=0; nCurPos < nStrLen; ++nCurPos )
877 nCharCode = rString[nCurPos];
879 // Handle chars, which are not an alphanumeric character and character codes > 127
880 if( (!rtl::isAsciiAlphanumeric(nCharCode) && nCharCode != ' ')
881 || nCharCode > 127 )
883 switch( nCharCode )
885 case 13: // CR
886 aResult.append("%0D%0A"); // CR LF in hex
887 break;
890 // Special treatment for Netscape
891 case 42: // '*'
892 case 45: // '-'
893 case 46: // '.'
894 case 64: // '@'
895 case 95: // '_'
896 aResult.append(nCharCode);
897 break;
899 default:
901 // Convert to hex
902 short nHi = static_cast<sal_Int16>(nCharCode) / 16;
903 short nLo = static_cast<sal_Int16>(nCharCode) - (nHi*16);
904 if( nHi > 9 ) nHi += int('A')-10; else nHi += int('0');
905 if( nLo > 9 ) nLo += int('A')-10; else nLo += int('0');
906 aResult.append("%"
907 + OUStringChar(static_cast<sal_Unicode>(nHi))
908 + OUStringChar(static_cast<sal_Unicode>(nLo)) );
912 else
913 aResult.append(nCharCode);
916 // Replace spaces with '+'
917 rString = aResult.makeStringAndClear().replace(' ', '+');
921 void ODatabaseForm::InsertTextPart( INetMIMEMessage& rParent, std::u16string_view rName,
922 std::u16string_view rData )
924 // Create part as MessageChild
925 std::unique_ptr<INetMIMEMessage> pChild(new INetMIMEMessage);
927 // Header
928 //TODO: Encode rName into a properly formatted Content-Disposition header
929 // field as per RFC 2231:
930 OUString aContentDisp = OUString::Concat("form-data; name=\"") + rName + "\"";
931 pChild->SetContentDisposition(aContentDisp);
933 rtl_TextEncoding eSystemEncoding = osl_getThreadTextEncoding();
934 const char* pBestMatchingEncoding = rtl_getBestMimeCharsetFromTextEncoding( eSystemEncoding );
935 OUString aBestMatchingEncoding = OUString::createFromAscii(pBestMatchingEncoding);
936 pChild->SetContentType(
937 "text/plain; charset=\"" + aBestMatchingEncoding + "\"");
938 pChild->SetContentTransferEncoding("8bit");
940 // Body
941 SvMemoryStream* pStream = new SvMemoryStream;
942 pStream->WriteLine( OUStringToOString(rData, rtl_getTextEncodingFromMimeCharset(pBestMatchingEncoding)) );
943 pStream->FlushBuffer();
944 pStream->Seek( 0 );
945 pChild->SetDocumentLB( new SvLockBytes(pStream, true) );
946 rParent.AttachChild( std::move(pChild) );
950 void ODatabaseForm::InsertFilePart( INetMIMEMessage& rParent, std::u16string_view rName,
951 const OUString& rFileName )
953 OUString aFileName(rFileName);
954 OUString aContentType(CONTENT_TYPE_STR_TEXT_PLAIN);
955 std::unique_ptr<SvStream> pStream;
957 if (!aFileName.isEmpty())
959 // We can only process File URLs yet
960 INetURLObject aURL;
961 aURL.SetSmartProtocol(INetProtocol::File);
962 aURL.SetSmartURL(rFileName);
963 if( INetProtocol::File == aURL.GetProtocol() )
965 aFileName = INetURLObject::decode(aURL.PathToFileName(), INetURLObject::DecodeMechanism::Unambiguous);
966 pStream = ::utl::UcbStreamHelper::CreateStream(aFileName, StreamMode::READ);
967 if (!pStream || (pStream->GetError() != ERRCODE_NONE))
969 pStream.reset();
971 sal_Int32 nSepInd = aFileName.lastIndexOf('.');
972 OUString aExtension = aFileName.copy( nSepInd + 1 );
973 INetContentType eContentType = INetContentTypes::GetContentType4Extension( aExtension );
974 if (eContentType != CONTENT_TYPE_UNKNOWN)
975 aContentType = INetContentTypes::GetContentType(eContentType);
979 // If something didn't work, we create an empty MemoryStream
980 if( !pStream )
981 pStream.reset( new SvMemoryStream );
984 // Create part as MessageChild
985 std::unique_ptr<INetMIMEMessage> pChild(new INetMIMEMessage);
988 // Header
989 //TODO: Encode rName and aFileName into a properly formatted
990 // Content-Disposition header field as per RFC 2231:
991 OUString aContentDisp =
992 OUString::Concat("form-data; name=\"") +
993 rName +
994 "\""
995 "; filename=\"" +
996 aFileName +
997 "\"";
998 pChild->SetContentDisposition(aContentDisp);
999 pChild->SetContentType( aContentType );
1000 pChild->SetContentTransferEncoding("8bit");
1003 // Body
1004 pChild->SetDocumentLB( new SvLockBytes(pStream.release(), true) );
1005 rParent.AttachChild( std::move(pChild) );
1009 // internals
1011 void ODatabaseForm::onError( const SQLErrorEvent& _rEvent )
1013 m_aErrorListeners.notifyEach( &XSQLErrorListener::errorOccured, _rEvent );
1017 void ODatabaseForm::onError( const SQLException& _rException, const OUString& _rContextDescription )
1019 if ( !m_aErrorListeners.getLength() )
1020 return;
1022 SQLErrorEvent aEvent( *this, Any( prependErrorInfo( _rException, *this, _rContextDescription ) ) );
1023 onError( aEvent );
1027 void ODatabaseForm::updateParameterInfo()
1029 m_aParameterManager.updateParameterInfo( m_aFilterManager );
1033 bool ODatabaseForm::hasValidParent() const
1035 // do we have to fill the parameters again?
1036 if (!m_bSubForm)
1037 return true;
1038 Reference<XResultSet> xResultSet(m_xParent, UNO_QUERY);
1039 if (!xResultSet.is())
1041 OSL_FAIL("ODatabaseForm::hasValidParent() : no parent resultset !");
1042 return false;
1046 Reference< XPropertySet > xSet( m_xParent, UNO_QUERY );
1047 Reference< XLoadable > xLoad( m_xParent, UNO_QUERY );
1048 if ( xLoad->isLoaded()
1049 && ( xResultSet->isBeforeFirst()
1050 || xResultSet->isAfterLast()
1051 || getBOOL( xSet->getPropertyValue( PROPERTY_ISNEW ) )
1054 // the parent form is loaded and on a "virtual" row -> not valid
1055 return false;
1057 catch(const Exception&)
1059 // parent could be forwardonly?
1060 return false;
1062 return true;
1066 bool ODatabaseForm::fillParameters( ::osl::ResettableMutexGuard& _rClearForNotifies, const Reference< XInteractionHandler >& _rxCompletionHandler )
1068 // do we have to fill the parameters again?
1069 if ( !m_aParameterManager.isUpToDate() )
1070 updateParameterInfo();
1072 // is there a valid parent?
1073 if ( m_bSubForm && !hasValidParent() )
1074 return true;
1076 // ensure we're connected
1077 if ( !implEnsureConnection() )
1078 return false;
1080 if ( m_aParameterManager.isUpToDate() )
1081 return m_aParameterManager.fillParameterValues( _rxCompletionHandler, _rClearForNotifies );
1083 return true;
1087 void ODatabaseForm::saveInsertOnlyState( )
1089 OSL_ENSURE( !m_aIgnoreResult.hasValue(), "ODatabaseForm::saveInsertOnlyState: overriding old value!" );
1090 m_aIgnoreResult = m_xAggregateSet->getPropertyValue( PROPERTY_INSERTONLY );
1094 void ODatabaseForm::restoreInsertOnlyState( )
1096 if ( m_aIgnoreResult.hasValue() )
1098 m_xAggregateSet->setPropertyValue( PROPERTY_INSERTONLY, m_aIgnoreResult );
1099 m_aIgnoreResult = Any();
1104 bool ODatabaseForm::executeRowSet(::osl::ResettableMutexGuard& _rClearForNotifies, bool bMoveToFirst, const Reference< XInteractionHandler >& _rxCompletionHandler)
1106 if (!m_xAggregateAsRowSet.is())
1107 return false;
1109 if (!fillParameters(_rClearForNotifies, _rxCompletionHandler))
1110 return false;
1112 restoreInsertOnlyState( );
1114 // ensure the aggregated row set has the correct properties
1115 sal_Int32 nConcurrency = ResultSetConcurrency::READ_ONLY;
1117 // if we have a parent, who is not positioned on a valid row
1118 // we can't be updatable!
1119 if (m_bSubForm && !hasValidParent())
1121 nConcurrency = ResultSetConcurrency::READ_ONLY;
1123 // don't use any parameters if we don't have a valid parent
1124 m_aParameterManager.setAllParametersNull();
1126 // switch to "insert only" mode
1127 saveInsertOnlyState( );
1128 m_xAggregateSet->setPropertyValue( PROPERTY_INSERTONLY, Any( true ) );
1130 else if (m_bAllowInsert || m_bAllowUpdate || m_bAllowDelete)
1131 nConcurrency = ResultSetConcurrency::UPDATABLE;
1132 else
1133 nConcurrency = ResultSetConcurrency::READ_ONLY;
1135 m_xAggregateSet->setPropertyValue( PROPERTY_RESULTSET_CONCURRENCY, Any( nConcurrency ) );
1136 m_xAggregateSet->setPropertyValue( PROPERTY_RESULTSET_TYPE, Any( sal_Int32(ResultSetType::SCROLL_SENSITIVE) ) );
1138 bool bSuccess = false;
1141 m_xAggregateAsRowSet->execute();
1142 bSuccess = true;
1144 catch(const RowSetVetoException&)
1147 catch(const SQLException& eDb)
1149 _rClearForNotifies.clear();
1150 if (!m_sCurrentErrorContext.isEmpty())
1151 onError(eDb, m_sCurrentErrorContext);
1152 else
1153 onError(eDb, ResourceManager::loadString(RID_STR_READERROR));
1154 _rClearForNotifies.reset();
1156 restoreInsertOnlyState( );
1159 if (bSuccess)
1161 // adjust the privilege property
1162 // m_nPrivileges;
1163 m_xAggregateSet->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
1164 if (!m_bAllowInsert)
1165 m_nPrivileges &= ~Privilege::INSERT;
1166 if (!m_bAllowUpdate)
1167 m_nPrivileges &= ~Privilege::UPDATE;
1168 if (!m_bAllowDelete)
1169 m_nPrivileges &= ~Privilege::DELETE;
1171 if (bMoveToFirst)
1173 // the row set is positioned _before_ the first row (per definitionem), so move the set ...
1176 // if we have an insert only rowset we move to the insert row
1177 next();
1178 if (((m_nPrivileges & Privilege::INSERT) == Privilege::INSERT)
1179 && isAfterLast())
1181 // move on the insert row of set
1182 // resetting must be done later, after the load events have been posted
1183 // see: moveToInsertRow and load , reload
1184 Reference<XResultSetUpdate> xUpdate;
1185 if (query_aggregation( m_xAggregate, xUpdate))
1186 xUpdate->moveToInsertRow();
1189 catch(const SQLException& eDB)
1191 _rClearForNotifies.clear();
1192 if (!m_sCurrentErrorContext.isEmpty())
1193 onError(eDB, m_sCurrentErrorContext);
1194 else
1195 onError(eDB, ResourceManager::loadString(RID_STR_READERROR));
1196 _rClearForNotifies.reset();
1197 bSuccess = false;
1201 return bSuccess;
1205 void ODatabaseForm::disposing()
1207 if (m_xAggregatePropertyMultiplexer.is())
1208 m_xAggregatePropertyMultiplexer->dispose();
1210 if (m_bLoaded)
1211 unload();
1213 // cancel the submit/reset-thread
1215 ::osl::MutexGuard aGuard( m_aMutex );
1216 m_pThread.clear();
1219 EventObject aEvt(static_cast<XWeak*>(this));
1220 m_aLoadListeners.disposeAndClear(aEvt);
1221 m_aRowSetApproveListeners.disposeAndClear(aEvt);
1222 m_aResetListeners.disposeAndClear(aEvt);
1223 m_aSubmitListeners.disposeAndClear(aEvt);
1224 m_aErrorListeners.disposeAndClear(aEvt);
1226 m_aParameterManager.dispose(); // To free any references it may have to be me
1227 m_aFilterManager.dispose(); // (ditto)
1229 OFormComponents::disposing();
1230 OPropertySetAggregationHelper::disposing();
1232 // stop listening on the aggregate
1233 if (m_xAggregateAsRowSet.is())
1234 m_xAggregateAsRowSet->removeRowSetListener(this);
1236 // dispose the active connection
1237 Reference<XComponent> xAggregationComponent;
1238 if (query_aggregation(m_xAggregate, xAggregationComponent))
1239 xAggregationComponent->dispose();
1241 m_aPropertyBagHelper.dispose();
1245 Reference< XConnection > ODatabaseForm::getConnection()
1247 Reference< XConnection > xConn;
1248 m_xAggregateSet->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConn;
1249 return xConn;
1253 ::osl::Mutex& ODatabaseForm::getMutex()
1255 return m_aMutex;
1259 // property handling
1261 void ODatabaseForm::describeFixedAndAggregateProperties(
1262 Sequence< Property >& _rProps,
1263 Sequence< Property >& _rAggregateProps ) const
1265 _rProps.realloc( 23 );
1266 css::beans::Property* pProperties = _rProps.getArray();
1268 if (m_xAggregateSet.is())
1269 _rAggregateProps = m_xAggregateSet->getPropertySetInfo()->getProperties();
1272 // we want to "override" the privileges, since we have additional "AllowInsert" etc. properties
1273 RemoveProperty( _rAggregateProps, PROPERTY_PRIVILEGES );
1275 // InsertOnly is also to be overridden, since we sometimes change it ourself
1276 RemoveProperty( _rAggregateProps, PROPERTY_INSERTONLY );
1278 // we remove and re-declare the DataSourceName property, 'cause we want it to be constrained, and the
1279 // original property of our aggregate isn't
1280 RemoveProperty( _rAggregateProps, PROPERTY_DATASOURCE );
1282 // for connection sharing, we need to override the ActiveConnection property, too
1283 RemoveProperty( _rAggregateProps, PROPERTY_ACTIVE_CONNECTION );
1285 // the Filter property is also overwritten, since we have some implicit filters
1286 // (e.g. the ones which result from linking master fields to detail fields
1287 // via column names instead of parameters)
1288 RemoveProperty( _rAggregateProps, PROPERTY_FILTER );
1289 RemoveProperty( _rAggregateProps, PROPERTY_HAVINGCLAUSE );
1290 RemoveProperty( _rAggregateProps, PROPERTY_APPLYFILTER );
1292 *pProperties++ = css::beans::Property(PROPERTY_ACTIVE_CONNECTION, PROPERTY_ID_ACTIVE_CONNECTION, cppu::UnoType<XConnection>::get(),
1293 css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::TRANSIENT |
1294 css::beans::PropertyAttribute::MAYBEVOID | PropertyAttribute::CONSTRAINED);
1295 *pProperties++ = css::beans::Property(PROPERTY_APPLYFILTER, PROPERTY_ID_APPLYFILTER, cppu::UnoType<bool>::get(),
1296 css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEDEFAULT);
1297 *pProperties++ = css::beans::Property(PROPERTY_NAME, PROPERTY_ID_NAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND);
1298 *pProperties++ = css::beans::Property(PROPERTY_MASTERFIELDS, PROPERTY_ID_MASTERFIELDS, cppu::UnoType<Sequence< OUString >>::get(), css::beans::PropertyAttribute::BOUND);
1299 *pProperties++ = css::beans::Property(PROPERTY_DETAILFIELDS, PROPERTY_ID_DETAILFIELDS, cppu::UnoType<Sequence< OUString >>::get(), css::beans::PropertyAttribute::BOUND);
1300 *pProperties++ = css::beans::Property(PROPERTY_DATASOURCE, PROPERTY_ID_DATASOURCE, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::CONSTRAINED);
1301 *pProperties++ = css::beans::Property(PROPERTY_CYCLE, PROPERTY_ID_CYCLE, cppu::UnoType<TabulatorCycle>::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEVOID | css::beans::PropertyAttribute::MAYBEDEFAULT);
1302 *pProperties++ = css::beans::Property(PROPERTY_FILTER, PROPERTY_ID_FILTER, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEDEFAULT);
1303 *pProperties++ = css::beans::Property(PROPERTY_HAVINGCLAUSE, PROPERTY_ID_HAVINGCLAUSE, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEDEFAULT);
1304 *pProperties++ = css::beans::Property(PROPERTY_INSERTONLY, PROPERTY_ID_INSERTONLY, cppu::UnoType<bool>::get(),
1305 css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEDEFAULT);
1306 *pProperties++ = css::beans::Property(PROPERTY_NAVIGATION, PROPERTY_ID_NAVIGATION, cppu::UnoType<NavigationBarMode>::get(), css::beans::PropertyAttribute::BOUND);
1307 *pProperties++ = css::beans::Property(PROPERTY_ALLOWADDITIONS, PROPERTY_ID_ALLOWADDITIONS, cppu::UnoType<bool>::get(),
1308 css::beans::PropertyAttribute::BOUND);
1309 *pProperties++ = css::beans::Property(PROPERTY_ALLOWEDITS, PROPERTY_ID_ALLOWEDITS, cppu::UnoType<bool>::get(),
1310 css::beans::PropertyAttribute::BOUND);
1311 *pProperties++ = css::beans::Property(PROPERTY_ALLOWDELETIONS, PROPERTY_ID_ALLOWDELETIONS, cppu::UnoType<bool>::get(),
1312 css::beans::PropertyAttribute::BOUND);
1313 *pProperties++ = css::beans::Property(PROPERTY_PRIVILEGES, PROPERTY_ID_PRIVILEGES, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::TRANSIENT | css::beans::PropertyAttribute::READONLY);
1314 *pProperties++ = css::beans::Property(PROPERTY_TARGET_URL, PROPERTY_ID_TARGET_URL, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND);
1315 *pProperties++ = css::beans::Property(PROPERTY_TARGET_FRAME, PROPERTY_ID_TARGET_FRAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND);
1316 *pProperties++ = css::beans::Property(PROPERTY_SUBMIT_METHOD, PROPERTY_ID_SUBMIT_METHOD, cppu::UnoType<FormSubmitMethod>::get(), css::beans::PropertyAttribute::BOUND);
1317 *pProperties++ = css::beans::Property(PROPERTY_SUBMIT_ENCODING, PROPERTY_ID_SUBMIT_ENCODING, cppu::UnoType<FormSubmitEncoding>::get(), css::beans::PropertyAttribute::BOUND);
1318 *pProperties++ = css::beans::Property(PROPERTY_DYNAMIC_CONTROL_BORDER, PROPERTY_ID_DYNAMIC_CONTROL_BORDER, cppu::UnoType<bool>::get(),
1319 css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEVOID | css::beans::PropertyAttribute::MAYBEDEFAULT );
1320 *pProperties++ = css::beans::Property(PROPERTY_CONTROL_BORDER_COLOR_FOCUS, PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEVOID | css::beans::PropertyAttribute::MAYBEDEFAULT);
1321 *pProperties++ = css::beans::Property(PROPERTY_CONTROL_BORDER_COLOR_MOUSE, PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEVOID | css::beans::PropertyAttribute::MAYBEDEFAULT);
1322 *pProperties++ = css::beans::Property(PROPERTY_CONTROL_BORDER_COLOR_INVALID, PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEVOID | css::beans::PropertyAttribute::MAYBEDEFAULT);
1323 DBG_ASSERT( pProperties == _rProps.getArray() + _rProps.getLength(), "<...>::describeFixedProperties/getInfoHelper: forgot to adjust the count ?");
1327 Reference< XMultiPropertySet > ODatabaseForm::getPropertiesInterface()
1329 return this;
1333 ::cppu::IPropertyArrayHelper& ODatabaseForm::getInfoHelper()
1335 return m_aPropertyBagHelper.getInfoHelper();
1339 Reference< XPropertySetInfo > ODatabaseForm::getPropertySetInfo()
1341 return createPropertySetInfo( getInfoHelper() );
1345 void SAL_CALL ODatabaseForm::addProperty( const OUString& _rName, ::sal_Int16 _nAttributes, const Any& _rInitialValue )
1347 m_aPropertyBagHelper.addProperty( _rName, _nAttributes, _rInitialValue );
1351 void SAL_CALL ODatabaseForm::removeProperty( const OUString& _rName )
1353 m_aPropertyBagHelper.removeProperty( _rName );
1357 Sequence< PropertyValue > SAL_CALL ODatabaseForm::getPropertyValues()
1359 return m_aPropertyBagHelper.getPropertyValues();
1363 void SAL_CALL ODatabaseForm::setPropertyValues( const Sequence< PropertyValue >& _rProps )
1365 m_aPropertyBagHelper.setPropertyValues( _rProps );
1369 Any SAL_CALL ODatabaseForm::getWarnings( )
1371 return m_aWarnings.getWarnings();
1375 void SAL_CALL ODatabaseForm::clearWarnings( )
1377 m_aWarnings.clearWarnings();
1381 Reference< XCloneable > SAL_CALL ODatabaseForm::createClone( )
1383 rtl::Reference<ODatabaseForm> pClone = new ODatabaseForm( *this );
1384 pClone->clonedFrom( *this );
1385 return pClone;
1389 void ODatabaseForm::fire( sal_Int32* pnHandles, const Any* pNewValues, const Any* pOldValues, sal_Int32 nCount )
1391 // same as in getFastPropertyValue(sal_Int32) : if we're resetting currently don't fire any changes of the
1392 // IsModified property from sal_False to sal_True, as this is only temporary 'til the reset is done
1393 if (m_nResetsPending > 0)
1395 // look for the PROPERTY_ID_ISMODIFIED
1396 sal_Int32 nPos = 0;
1397 for (nPos=0; nPos<nCount; ++nPos)
1398 if (pnHandles[nPos] == PROPERTY_ID_ISMODIFIED)
1399 break;
1401 if ((nPos < nCount) && (pNewValues[nPos].getValueType().getTypeClass() == TypeClass_BOOLEAN) && getBOOL(pNewValues[nPos]))
1402 { // yeah, we found it, and it changed to TRUE
1403 if (nPos == 0)
1404 { // just cut the first element
1405 ++pnHandles;
1406 ++pNewValues;
1407 ++pOldValues;
1408 --nCount;
1410 else if (nPos == nCount - 1)
1411 // just cut the last element
1412 --nCount;
1413 else
1414 { // split into two base class calls
1415 OPropertySetAggregationHelper::fire(pnHandles, pNewValues, pOldValues, nPos, false/*bVetoable*/);
1416 ++nPos;
1417 OPropertySetAggregationHelper::fire(pnHandles + nPos, pNewValues + nPos, pOldValues + nPos, nCount - nPos, false/*bVetoable*/);
1418 return;
1423 OPropertySetAggregationHelper::fire(pnHandles, pNewValues, pOldValues, nCount, false/*bVetoable*/);
1427 Any SAL_CALL ODatabaseForm::getFastPropertyValue( sal_Int32 nHandle )
1429 if ((nHandle == PROPERTY_ID_ISMODIFIED) && (m_nResetsPending > 0))
1430 return css::uno::Any(false);
1431 // don't allow the aggregate which is currently being reset to return a (temporary) "yes"
1432 else
1433 return OPropertySetAggregationHelper::getFastPropertyValue(nHandle);
1437 void ODatabaseForm::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
1439 switch (nHandle)
1441 case PROPERTY_ID_INSERTONLY:
1442 rValue <<= m_bInsertOnly;
1443 break;
1445 case PROPERTY_ID_FILTER:
1446 rValue <<= m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicFilter );
1447 break;
1449 case PROPERTY_ID_HAVINGCLAUSE:
1450 rValue <<= m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicHaving );
1451 break;
1453 case PROPERTY_ID_APPLYFILTER:
1454 rValue <<= m_aFilterManager.isApplyPublicFilter();
1455 break;
1457 case PROPERTY_ID_DATASOURCE:
1458 rValue = m_xAggregateSet->getPropertyValue( PROPERTY_DATASOURCE );
1459 break;
1461 case PROPERTY_ID_TARGET_URL:
1462 rValue <<= m_aTargetURL;
1463 break;
1464 case PROPERTY_ID_TARGET_FRAME:
1465 rValue <<= m_aTargetFrame;
1466 break;
1467 case PROPERTY_ID_SUBMIT_METHOD:
1468 rValue <<= m_eSubmitMethod;
1469 break;
1470 case PROPERTY_ID_SUBMIT_ENCODING:
1471 rValue <<= m_eSubmitEncoding;
1472 break;
1473 case PROPERTY_ID_NAME:
1474 rValue <<= m_sName;
1475 break;
1476 case PROPERTY_ID_MASTERFIELDS:
1477 rValue <<= m_aMasterFields;
1478 break;
1479 case PROPERTY_ID_DETAILFIELDS:
1480 rValue <<= m_aDetailFields;
1481 break;
1482 case PROPERTY_ID_CYCLE:
1483 rValue = m_aCycle;
1484 break;
1485 case PROPERTY_ID_NAVIGATION:
1486 rValue <<= m_eNavigation;
1487 break;
1488 case PROPERTY_ID_ALLOWADDITIONS:
1489 rValue <<= m_bAllowInsert;
1490 break;
1491 case PROPERTY_ID_ALLOWEDITS:
1492 rValue <<= m_bAllowUpdate;
1493 break;
1494 case PROPERTY_ID_ALLOWDELETIONS:
1495 rValue <<= m_bAllowDelete;
1496 break;
1497 case PROPERTY_ID_PRIVILEGES:
1498 rValue <<= m_nPrivileges;
1499 break;
1500 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1501 rValue = m_aDynamicControlBorder;
1502 break;
1503 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1504 rValue = m_aControlBorderColorFocus;
1505 break;
1506 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1507 rValue = m_aControlBorderColorMouse;
1508 break;
1509 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1510 rValue = m_aControlBorderColorInvalid;
1511 break;
1512 default:
1513 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( nHandle ) )
1514 m_aPropertyBagHelper.getDynamicFastPropertyValue( nHandle, rValue );
1515 else
1516 OPropertySetAggregationHelper::getFastPropertyValue( rValue, nHandle );
1517 break;
1521 sal_Bool ODatabaseForm::convertFastPropertyValue( Any& rConvertedValue, Any& rOldValue,
1522 sal_Int32 nHandle, const Any& rValue )
1524 bool bModified(false);
1525 switch (nHandle)
1527 case PROPERTY_ID_INSERTONLY:
1528 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_bInsertOnly );
1529 break;
1531 case PROPERTY_ID_FILTER:
1532 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicFilter ) );
1533 break;
1535 case PROPERTY_ID_HAVINGCLAUSE:
1536 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicHaving ) );
1537 break;
1539 case PROPERTY_ID_APPLYFILTER:
1540 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aFilterManager.isApplyPublicFilter() );
1541 break;
1543 case PROPERTY_ID_DATASOURCE:
1545 Any aAggregateProperty;
1546 getFastPropertyValue(aAggregateProperty, PROPERTY_ID_DATASOURCE);
1547 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, aAggregateProperty, cppu::UnoType<OUString>::get());
1549 break;
1550 case PROPERTY_ID_TARGET_URL:
1551 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aTargetURL);
1552 break;
1553 case PROPERTY_ID_TARGET_FRAME:
1554 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aTargetFrame);
1555 break;
1556 case PROPERTY_ID_SUBMIT_METHOD:
1557 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_eSubmitMethod);
1558 break;
1559 case PROPERTY_ID_SUBMIT_ENCODING:
1560 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_eSubmitEncoding);
1561 break;
1562 case PROPERTY_ID_NAME:
1563 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_sName);
1564 break;
1565 case PROPERTY_ID_MASTERFIELDS:
1566 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aMasterFields);
1567 break;
1568 case PROPERTY_ID_DETAILFIELDS:
1569 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aDetailFields);
1570 break;
1571 case PROPERTY_ID_CYCLE:
1572 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aCycle, cppu::UnoType<TabulatorCycle>::get());
1573 break;
1574 case PROPERTY_ID_NAVIGATION:
1575 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_eNavigation);
1576 break;
1577 case PROPERTY_ID_ALLOWADDITIONS:
1578 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAllowInsert);
1579 break;
1580 case PROPERTY_ID_ALLOWEDITS:
1581 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAllowUpdate);
1582 break;
1583 case PROPERTY_ID_ALLOWDELETIONS:
1584 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAllowDelete);
1585 break;
1586 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1587 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aDynamicControlBorder, cppu::UnoType<bool>::get() );
1588 break;
1589 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1590 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aControlBorderColorFocus, cppu::UnoType<sal_Int32>::get() );
1591 break;
1592 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1593 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aControlBorderColorMouse, cppu::UnoType<sal_Int32>::get() );
1594 break;
1595 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1596 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aControlBorderColorInvalid, cppu::UnoType<sal_Int32>::get() );
1597 break;
1598 default:
1599 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle ( nHandle ) )
1600 bModified = m_aPropertyBagHelper.convertDynamicFastPropertyValue( nHandle, rValue, rConvertedValue, rOldValue );
1601 else
1602 bModified = OPropertySetAggregationHelper::convertFastPropertyValue( rConvertedValue, rOldValue, nHandle, rValue );
1603 break;
1605 return bModified;
1608 void ODatabaseForm::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
1610 switch (nHandle)
1612 case PROPERTY_ID_INSERTONLY:
1613 rValue >>= m_bInsertOnly;
1614 if ( m_aIgnoreResult.hasValue() )
1615 m_aIgnoreResult <<= m_bInsertOnly;
1616 else
1617 m_xAggregateSet->setPropertyValue( PROPERTY_INSERTONLY, Any( m_bInsertOnly ) );
1618 break;
1620 case PROPERTY_ID_FILTER:
1622 OUString sNewFilter;
1623 rValue >>= sNewFilter;
1624 m_aFilterManager.setFilterComponent( FilterManager::FilterComponent::PublicFilter, sNewFilter );
1626 break;
1628 case PROPERTY_ID_HAVINGCLAUSE:
1630 OUString sNewFilter;
1631 rValue >>= sNewFilter;
1632 m_aFilterManager.setFilterComponent( FilterManager::FilterComponent::PublicHaving, sNewFilter );
1634 break;
1636 case PROPERTY_ID_APPLYFILTER:
1638 bool bApply = true;
1639 rValue >>= bApply;
1640 m_aFilterManager.setApplyPublicFilter( bApply );
1642 break;
1644 case PROPERTY_ID_DATASOURCE:
1646 Reference< XConnection > xSomeConnection;
1647 if ( ::dbtools::isEmbeddedInDatabase( getParent(), xSomeConnection ) )
1648 throw PropertyVetoException();
1652 m_xAggregateSet->setPropertyValue(PROPERTY_DATASOURCE, rValue);
1654 catch(const Exception&)
1658 break;
1659 case PROPERTY_ID_TARGET_URL:
1660 rValue >>= m_aTargetURL;
1661 break;
1662 case PROPERTY_ID_TARGET_FRAME:
1663 rValue >>= m_aTargetFrame;
1664 break;
1665 case PROPERTY_ID_SUBMIT_METHOD:
1666 rValue >>= m_eSubmitMethod;
1667 break;
1668 case PROPERTY_ID_SUBMIT_ENCODING:
1669 rValue >>= m_eSubmitEncoding;
1670 break;
1671 case PROPERTY_ID_NAME:
1672 rValue >>= m_sName;
1673 break;
1674 case PROPERTY_ID_MASTERFIELDS:
1675 rValue >>= m_aMasterFields;
1676 invalidateParameters();
1677 break;
1678 case PROPERTY_ID_DETAILFIELDS:
1679 rValue >>= m_aDetailFields;
1680 invalidateParameters();
1681 break;
1682 case PROPERTY_ID_CYCLE:
1683 m_aCycle = rValue;
1684 break;
1685 case PROPERTY_ID_NAVIGATION:
1686 rValue >>= m_eNavigation;
1687 break;
1688 case PROPERTY_ID_ALLOWADDITIONS:
1689 m_bAllowInsert = getBOOL(rValue);
1690 break;
1691 case PROPERTY_ID_ALLOWEDITS:
1692 m_bAllowUpdate = getBOOL(rValue);
1693 break;
1694 case PROPERTY_ID_ALLOWDELETIONS:
1695 m_bAllowDelete = getBOOL(rValue);
1696 break;
1697 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1698 m_aDynamicControlBorder = rValue;
1699 break;
1700 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1701 m_aControlBorderColorFocus = rValue;
1702 break;
1703 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1704 m_aControlBorderColorMouse = rValue;
1705 break;
1706 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1707 m_aControlBorderColorInvalid = rValue;
1708 break;
1710 case PROPERTY_ID_ACTIVE_CONNECTION:
1712 Reference< XConnection > xOuterConnection;
1713 if ( ::dbtools::isEmbeddedInDatabase( getParent(), xOuterConnection ) )
1715 if ( xOuterConnection != Reference< XConnection >( rValue, UNO_QUERY ) )
1716 // somebody's trying to set a connection which is not equal the connection
1717 // implied by the database we're embedded in
1718 throw PropertyVetoException();
1720 OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( nHandle, rValue );
1721 break;
1724 default:
1725 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( nHandle ) )
1726 m_aPropertyBagHelper.setDynamicFastPropertyValue( nHandle, rValue );
1727 else
1728 OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( nHandle, rValue );
1729 break;
1734 void ODatabaseForm::forwardingPropertyValue( sal_Int32 _nHandle )
1736 OSL_ENSURE( _nHandle == PROPERTY_ID_ACTIVE_CONNECTION, "ODatabaseForm::forwardingPropertyValue: unexpected property!" );
1737 if ( _nHandle == PROPERTY_ID_ACTIVE_CONNECTION )
1739 if ( m_bSharingConnection )
1740 stopSharingConnection( );
1741 m_bForwardingConnection = true;
1746 void ODatabaseForm::forwardedPropertyValue( sal_Int32 _nHandle )
1748 OSL_ENSURE( _nHandle == PROPERTY_ID_ACTIVE_CONNECTION, "ODatabaseForm::forwardedPropertyValue: unexpected property!" );
1749 if ( _nHandle == PROPERTY_ID_ACTIVE_CONNECTION )
1751 m_bForwardingConnection = false;
1756 // css::beans::XPropertyState
1758 PropertyState ODatabaseForm::getPropertyStateByHandle(sal_Int32 nHandle)
1760 PropertyState eState;
1761 switch (nHandle)
1763 case PROPERTY_ID_NAVIGATION:
1764 return (NavigationBarMode_CURRENT == m_eNavigation) ? PropertyState_DEFAULT_VALUE : PropertyState_DIRECT_VALUE;
1766 case PROPERTY_ID_CYCLE:
1767 eState = m_aCycle.hasValue() ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1768 break;
1770 case PROPERTY_ID_INSERTONLY:
1771 eState = m_bInsertOnly ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1772 break;
1774 case PROPERTY_ID_FILTER:
1775 if ( m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicFilter ).isEmpty() )
1776 eState = PropertyState_DEFAULT_VALUE;
1777 else
1778 eState = PropertyState_DIRECT_VALUE;
1779 break;
1781 case PROPERTY_ID_HAVINGCLAUSE:
1782 if ( m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicHaving ).isEmpty() )
1783 eState = PropertyState_DEFAULT_VALUE;
1784 else
1785 eState = PropertyState_DIRECT_VALUE;
1786 break;
1788 case PROPERTY_ID_APPLYFILTER:
1789 eState = m_aFilterManager.isApplyPublicFilter() ? PropertyState_DEFAULT_VALUE : PropertyState_DIRECT_VALUE;
1790 break;
1792 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1793 eState = m_aDynamicControlBorder.hasValue() ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1794 break;
1796 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1797 eState = m_aControlBorderColorFocus.hasValue() ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1798 break;
1800 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1801 eState = m_aControlBorderColorMouse.hasValue() ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1802 break;
1804 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1805 eState = m_aControlBorderColorInvalid.hasValue() ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1806 break;
1808 default:
1809 eState = OPropertySetAggregationHelper::getPropertyStateByHandle(nHandle);
1811 return eState;
1815 void ODatabaseForm::setPropertyToDefaultByHandle(sal_Int32 nHandle)
1817 switch (nHandle)
1819 case PROPERTY_ID_INSERTONLY:
1820 case PROPERTY_ID_FILTER:
1821 case PROPERTY_ID_HAVINGCLAUSE:
1822 case PROPERTY_ID_APPLYFILTER:
1823 case PROPERTY_ID_NAVIGATION:
1824 case PROPERTY_ID_CYCLE:
1825 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1826 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1827 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1828 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1829 setFastPropertyValue( nHandle, getPropertyDefaultByHandle( nHandle ) );
1830 break;
1832 default:
1833 OPropertySetAggregationHelper::setPropertyToDefaultByHandle(nHandle);
1838 Any ODatabaseForm::getPropertyDefaultByHandle( sal_Int32 nHandle ) const
1840 Any aReturn;
1841 switch (nHandle)
1843 case PROPERTY_ID_INSERTONLY:
1844 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1845 aReturn <<= false;
1846 break;
1848 case PROPERTY_ID_FILTER:
1849 aReturn <<= OUString();
1850 break;
1852 case PROPERTY_ID_HAVINGCLAUSE:
1853 aReturn <<= OUString();
1854 break;
1856 case PROPERTY_ID_APPLYFILTER:
1857 aReturn <<= true;
1858 break;
1860 case PROPERTY_ID_NAVIGATION:
1861 aReturn <<= NavigationBarMode_CURRENT;
1862 break;
1864 case PROPERTY_ID_CYCLE:
1865 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1866 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1867 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1868 break;
1870 default:
1871 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( nHandle ) )
1872 m_aPropertyBagHelper.getDynamicPropertyDefaultByHandle( nHandle, aReturn );
1873 else
1874 aReturn = OPropertySetAggregationHelper::getPropertyDefaultByHandle( nHandle );
1875 break;
1877 return aReturn;
1881 // css::form::XReset
1883 void SAL_CALL ODatabaseForm::reset()
1885 osl::ClearableMutexGuard aGuard(m_aMutex);
1887 if (isLoaded())
1889 ::osl::MutexGuard aResetGuard(m_aResetSafety);
1890 ++m_nResetsPending;
1891 reset_impl(true);
1892 return;
1895 if ( m_aResetListeners.getLength() )
1897 ::osl::MutexGuard aResetGuard(m_aResetSafety);
1898 ++m_nResetsPending;
1899 // create an own thread if we have (approve-)reset-listeners (so the listeners can't do that much damage
1900 // to this thread which is probably the main one)
1901 if (!m_pThread.is())
1903 m_pThread = new OFormSubmitResetThread(this);
1904 m_pThread->create();
1906 m_pThread->addEvent(std::make_unique<EventObject>());
1908 else
1910 // direct call without any approving by the listeners
1911 aGuard.clear();
1913 ::osl::MutexGuard aResetGuard(m_aResetSafety);
1914 ++m_nResetsPending;
1915 reset_impl(false);
1920 void ODatabaseForm::reset_impl(bool _bApproveByListeners)
1922 if ( _bApproveByListeners )
1924 ::comphelper::OInterfaceIteratorHelper3 aIter(m_aResetListeners);
1925 EventObject aEvent(*this);
1926 while (aIter.hasMoreElements())
1927 if (!aIter.next()->approveReset(aEvent))
1928 return;
1931 ::osl::ResettableMutexGuard aResetGuard(m_aResetSafety);
1932 // do we have a database connected form and stay on the insert row
1933 bool bInsertRow = false;
1934 if (m_xAggregateSet.is())
1935 bInsertRow = getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_ISNEW));
1936 if (bInsertRow)
1940 // Iterate through all columns and set the default value
1941 Reference< XColumnsSupplier > xColsSuppl( m_xAggregateSet, UNO_QUERY );
1942 Reference< XIndexAccess > xIndexCols( xColsSuppl->getColumns(), UNO_QUERY );
1943 for (sal_Int32 i = 0; i < xIndexCols->getCount(); ++i)
1945 Reference< XPropertySet > xColProps;
1946 xIndexCols->getByIndex(i) >>= xColProps;
1948 Reference< XColumnUpdate > xColUpdate( xColProps, UNO_QUERY );
1949 if ( !xColUpdate.is() )
1950 continue;
1952 Reference< XPropertySetInfo > xPSI;
1953 if ( xColProps.is() )
1954 xPSI = xColProps->getPropertySetInfo( );
1956 static constexpr OUStringLiteral PROPERTY_CONTROLDEFAULT = u"ControlDefault";
1957 if ( xPSI.is() && xPSI->hasPropertyByName( PROPERTY_CONTROLDEFAULT ) )
1959 Any aDefault = xColProps->getPropertyValue( PROPERTY_CONTROLDEFAULT );
1961 bool bReadOnly = false;
1962 if ( xPSI->hasPropertyByName( PROPERTY_ISREADONLY ) )
1963 xColProps->getPropertyValue( PROPERTY_ISREADONLY ) >>= bReadOnly;
1965 if ( !bReadOnly )
1969 if ( aDefault.hasValue() )
1970 xColUpdate->updateObject( aDefault );
1972 catch(const Exception&)
1974 DBG_UNHANDLED_EXCEPTION("forms.component");
1980 catch(const Exception&)
1984 if (m_bSubForm)
1986 Reference< XColumnsSupplier > xParentColSupp( m_xParent, UNO_QUERY );
1987 Reference< XNameAccess > xParentCols;
1988 if ( xParentColSupp.is() )
1989 xParentCols = xParentColSupp->getColumns();
1991 if ( xParentCols.is() && xParentCols->hasElements() && m_aMasterFields.hasElements() )
1995 // analyze our parameters
1996 if ( !m_aParameterManager.isUpToDate() )
1997 updateParameterInfo();
1999 m_aParameterManager.resetParameterValues( );
2001 catch(const Exception&)
2003 OSL_FAIL("ODatabaseForm::reset_impl: could not initialize the master-detail-driven parameters!");
2009 aResetGuard.clear();
2010 // iterate through all components. don't use an XIndexAccess as this will cause massive
2011 // problems with the count.
2012 Reference<XEnumeration> xIter = createEnumeration();
2013 while (xIter->hasMoreElements())
2015 Reference<XReset> xReset;
2016 xIter->nextElement() >>= xReset;
2017 if (xReset.is())
2019 // TODO: all reset-methods have to be thread-safe
2020 xReset->reset();
2024 aResetGuard.reset();
2025 // ensure that the row isn't modified
2026 // (do this _before_ the listeners are notified ! their reaction (maybe asynchronous) may depend
2027 // on the modified state of the row)
2028 if (bInsertRow)
2029 m_xAggregateSet->setPropertyValue(PROPERTY_ISMODIFIED, css::uno::Any(false));
2031 aResetGuard.clear();
2033 css::lang::EventObject aEvent( *this );
2034 m_aResetListeners.notifyEach(&css::form::XResetListener::resetted, aEvent);
2037 aResetGuard.reset();
2038 // and again : ensure the row isn't modified
2039 // we already did this after we (and maybe our dependents) reset the values, but the listeners may have changed the row, too
2040 if (bInsertRow)
2041 m_xAggregateSet->setPropertyValue(PROPERTY_ISMODIFIED, css::uno::Any(false));
2043 --m_nResetsPending;
2047 void SAL_CALL ODatabaseForm::addResetListener(const Reference<XResetListener>& _rListener)
2049 m_aResetListeners.addInterface( _rListener );
2053 void SAL_CALL ODatabaseForm::removeResetListener(const Reference<XResetListener>& _rListener)
2055 m_aResetListeners.removeInterface( _rListener );
2059 // css::form::XSubmit
2061 void SAL_CALL ODatabaseForm::submit( const Reference<XControl>& Control,
2062 const css::awt::MouseEvent& MouseEvt )
2065 ::osl::MutexGuard aGuard(m_aMutex);
2066 // Do we have controls and a Submit URL?
2067 if( !getCount() || m_aTargetURL.isEmpty() )
2068 return;
2071 ::osl::ClearableMutexGuard aGuard(m_aMutex);
2072 if (m_aSubmitListeners.getLength())
2074 // create an own thread if we have (approve-)submit-listeners (so the listeners can't do that much damage
2075 // to this thread which is probably the main one)
2076 if (!m_pThread.is())
2078 m_pThread = new OFormSubmitResetThread(this);
2079 m_pThread->create();
2081 m_pThread->addEvent(std::make_unique<css::awt::MouseEvent>(MouseEvt), Control, true);
2083 else
2085 // direct call without any approving by the listeners
2086 aGuard.clear();
2087 submit_impl( Control, MouseEvt );
2091 static void lcl_dispatch(const Reference< XFrame >& xFrame,const Reference<XURLTransformer>& xTransformer,const OUString& aURLStr,const OUString& aReferer,const OUString& aTargetName
2092 ,std::u16string_view aData,rtl_TextEncoding _eEncoding)
2094 URL aURL;
2095 aURL.Complete = aURLStr;
2096 xTransformer->parseStrict(aURL);
2098 Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY_THROW)->queryDispatch(aURL, aTargetName,
2099 FrameSearchFlag::SELF | FrameSearchFlag::PARENT | FrameSearchFlag::CHILDREN |
2100 FrameSearchFlag::SIBLINGS | FrameSearchFlag::CREATE | FrameSearchFlag::TASKS);
2102 if (!xDisp.is())
2103 return;
2106 // build a sequence from the to-be-submitted string
2107 OString a8BitData(OUStringToOString(aData, _eEncoding));
2108 // always ANSI #58641
2109 Sequence< sal_Int8 > aPostData(reinterpret_cast<const sal_Int8*>(a8BitData.getStr()), a8BitData.getLength());
2110 Reference< XInputStream > xPostData = new SequenceInputStream(aPostData);
2112 Sequence<PropertyValue> aArgs
2114 comphelper::makePropertyValue("Referer", aReferer),
2115 comphelper::makePropertyValue("PostData", xPostData)
2118 xDisp->dispatch(aURL, aArgs);
2121 void ODatabaseForm::submit_impl(const Reference<XControl>& Control, const css::awt::MouseEvent& MouseEvt)
2124 ::comphelper::OInterfaceIteratorHelper3 aIter(m_aSubmitListeners);
2125 EventObject aEvt(static_cast<XWeak*>(this));
2126 bool bCanceled = false;
2127 while (aIter.hasMoreElements() && !bCanceled)
2129 if (!aIter.next()->approveSubmit(aEvt))
2130 bCanceled = true;
2133 if (bCanceled)
2134 return;
2136 FormSubmitEncoding eSubmitEncoding;
2137 FormSubmitMethod eSubmitMethod;
2138 OUString aURLStr;
2139 OUString aReferer;
2140 OUString aTargetName;
2141 Reference< XModel > xModel;
2143 SolarMutexGuard aGuard;
2144 // starform->Forms
2146 Reference<XChild> xParent(m_xParent, UNO_QUERY);
2148 if (xParent.is())
2149 xModel = getXModel(xParent->getParent());
2151 if (xModel.is())
2152 aReferer = xModel->getURL();
2154 // TargetItem
2155 aTargetName = m_aTargetFrame;
2157 eSubmitEncoding = m_eSubmitEncoding;
2158 eSubmitMethod = m_eSubmitMethod;
2159 aURLStr = m_aTargetURL;
2162 if (!xModel.is())
2163 return;
2164 Reference< XFrame > xFrame = xModel->getCurrentController()->getFrame();
2165 if (!xFrame.is())
2166 return;
2168 Reference<XURLTransformer> xTransformer(URLTransformer::create(m_xContext));
2170 // URL encoding
2171 if( eSubmitEncoding == FormSubmitEncoding_URL )
2173 OUString aData;
2175 SolarMutexGuard aGuard;
2176 aData = GetDataEncoded(true, Control, MouseEvt);
2179 URL aURL;
2180 // FormMethod GET
2181 if( eSubmitMethod == FormSubmitMethod_GET )
2183 INetURLObject aUrlObj( aURLStr, INetURLObject::EncodeMechanism::WasEncoded );
2184 aUrlObj.SetParam( aData, INetURLObject::EncodeMechanism::All );
2185 aURL.Complete = aUrlObj.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
2186 if (xTransformer.is())
2187 xTransformer->parseStrict(aURL);
2189 Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY_THROW)->queryDispatch(aURL, aTargetName,
2190 FrameSearchFlag::SELF | FrameSearchFlag::PARENT | FrameSearchFlag::CHILDREN |
2191 FrameSearchFlag::SIBLINGS | FrameSearchFlag::CREATE | FrameSearchFlag::TASKS);
2193 if (xDisp.is())
2195 Sequence<PropertyValue> aArgs { comphelper::makePropertyValue("Referer", aReferer) };
2196 xDisp->dispatch(aURL, aArgs);
2199 // FormMethod POST
2200 else if( eSubmitMethod == FormSubmitMethod_POST )
2202 lcl_dispatch(xFrame,xTransformer,aURLStr,aReferer,aTargetName,aData,RTL_TEXTENCODING_MS_1252);
2205 else if( eSubmitEncoding == FormSubmitEncoding_MULTIPART )
2207 URL aURL;
2208 aURL.Complete = aURLStr;
2209 xTransformer->parseStrict(aURL);
2211 Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY_THROW)->queryDispatch(aURL, aTargetName,
2212 FrameSearchFlag::SELF | FrameSearchFlag::PARENT | FrameSearchFlag::CHILDREN |
2213 FrameSearchFlag::SIBLINGS | FrameSearchFlag::CREATE | FrameSearchFlag::TASKS);
2215 if (xDisp.is())
2217 OUString aContentType;
2218 Sequence<sal_Int8> aData;
2220 SolarMutexGuard aGuard;
2221 aData = GetDataMultiPartEncoded(Control, MouseEvt, aContentType);
2223 if (!aData.hasElements())
2224 return;
2226 // build a sequence from the to-be-submitted string
2227 Reference< XInputStream > xPostData = new SequenceInputStream(aData);
2229 Sequence<PropertyValue> aArgs
2231 comphelper::makePropertyValue("Referer", aReferer),
2232 comphelper::makePropertyValue("ContentType", aContentType),
2233 comphelper::makePropertyValue("PostData", xPostData)
2236 xDisp->dispatch(aURL, aArgs);
2239 else if( eSubmitEncoding == FormSubmitEncoding_TEXT )
2241 OUString aData;
2243 SolarMutexGuard aGuard;
2244 aData = GetDataEncoded(false, Reference<XControl> (), MouseEvt);
2247 lcl_dispatch(xFrame,xTransformer,aURLStr,aReferer,aTargetName,aData,osl_getThreadTextEncoding());
2249 else {
2250 OSL_FAIL("ODatabaseForm::submit_Impl : wrong encoding !");
2255 // XSubmit
2257 void SAL_CALL ODatabaseForm::addSubmitListener(const Reference<XSubmitListener>& _rListener)
2259 m_aSubmitListeners.addInterface(_rListener);
2263 void SAL_CALL ODatabaseForm::removeSubmitListener(const Reference<XSubmitListener>& _rListener)
2265 m_aSubmitListeners.removeInterface(_rListener);
2269 // css::sdbc::XSQLErrorBroadcaster
2271 void SAL_CALL ODatabaseForm::addSQLErrorListener(const Reference<XSQLErrorListener>& _rListener)
2273 m_aErrorListeners.addInterface(_rListener);
2277 void SAL_CALL ODatabaseForm::removeSQLErrorListener(const Reference<XSQLErrorListener>& _rListener)
2279 m_aErrorListeners.removeInterface(_rListener);
2283 void ODatabaseForm::invalidateParameters()
2285 ::osl::MutexGuard aGuard(m_aMutex);
2286 m_aParameterManager.clearAllParameterInformation();
2290 // OChangeListener
2292 void ODatabaseForm::_propertyChanged(const PropertyChangeEvent& evt)
2294 if (evt.PropertyName == PROPERTY_ACTIVE_CONNECTION && !m_bForwardingConnection)
2296 // the rowset changed its active connection itself (without interaction from our side), so
2297 // we need to fire this event, too
2298 sal_Int32 nHandle = PROPERTY_ID_ACTIVE_CONNECTION;
2299 fire(&nHandle, &evt.NewValue, &evt.OldValue, 1);
2301 else // it was one of the statement relevant props
2303 // if the statement has changed we have to delete the parameter info
2304 invalidateParameters();
2309 // smartXChild
2311 void SAL_CALL ODatabaseForm::setParent(const css::uno::Reference<css::uno::XInterface>& Parent)
2313 // SYNCHRONIZED ----->
2314 osl::ClearableMutexGuard aGuard(m_aMutex);
2316 Reference<XForm> xParentForm(getParent(), UNO_QUERY);
2317 if (xParentForm.is())
2321 Reference< XRowSetApproveBroadcaster > xParentApprBroadcast( xParentForm, UNO_QUERY_THROW );
2322 xParentApprBroadcast->removeRowSetApproveListener( this );
2324 Reference< XLoadable > xParentLoadable( xParentForm, UNO_QUERY_THROW );
2325 xParentLoadable->removeLoadListener( this );
2327 Reference< XPropertySet > xParentProperties( xParentForm, UNO_QUERY_THROW );
2328 xParentProperties->removePropertyChangeListener( PROPERTY_ISNEW, this );
2330 catch(const Exception&)
2332 DBG_UNHANDLED_EXCEPTION("forms.component");
2336 OFormComponents::setParent(Parent);
2338 xParentForm.set(getParent(), UNO_QUERY);
2339 if ( xParentForm.is() )
2343 Reference< XRowSetApproveBroadcaster > xParentApprBroadcast( xParentForm, UNO_QUERY_THROW );
2344 xParentApprBroadcast->addRowSetApproveListener( this );
2346 Reference< XLoadable > xParentLoadable( xParentForm, UNO_QUERY_THROW );
2347 xParentLoadable->addLoadListener( this );
2349 Reference< XPropertySet > xParentProperties( xParentForm, UNO_QUERY_THROW );
2350 xParentProperties->addPropertyChangeListener( PROPERTY_ISNEW, this );
2352 catch(const Exception&)
2354 DBG_UNHANDLED_EXCEPTION("forms.component");
2358 Reference< XPropertySet > xAggregateProperties( m_xAggregateSet );
2359 aGuard.clear();
2360 // <----- SYNCHRONIZED
2362 Reference< XConnection > xOuterConnection;
2363 bool bIsEmbedded = ::dbtools::isEmbeddedInDatabase( Parent, xOuterConnection );
2365 if ( bIsEmbedded )
2366 xAggregateProperties->setPropertyValue( PROPERTY_DATASOURCE, Any( OUString() ) );
2370 // smartXTabControllerModel
2372 sal_Bool SAL_CALL ODatabaseForm::getGroupControl()
2374 osl::MutexGuard aGuard(m_aMutex);
2376 // Should controls be combined into a TabOrder group?
2377 if (m_aCycle.hasValue())
2379 sal_Int32 nCycle = 0;
2380 ::cppu::enum2int(nCycle, m_aCycle);
2381 return static_cast<TabulatorCycle>(nCycle) != TabulatorCycle_PAGE;
2384 if (isLoaded() && getConnection().is())
2385 return true;
2387 return false;
2391 void SAL_CALL ODatabaseForm::setControlModels(const Sequence<Reference<XControlModel> >& rControls)
2393 osl::MutexGuard aGuard(m_aMutex);
2395 // Set TabIndex in the order of the sequence
2396 sal_Int32 nCount = getCount();
2398 // HiddenControls and forms are not listed
2399 if (rControls.getLength() > nCount)
2400 return;
2402 sal_Int16 nTabIndex = 1;
2403 for (auto const& rControl : rControls)
2405 Reference<XFormComponent> xComp(rControl, UNO_QUERY);
2406 if (xComp.is())
2408 // Find component in the list
2409 for (sal_Int32 j = 0; j < nCount; ++j)
2411 Reference<XFormComponent> xElement(
2412 getByIndex(j), css::uno::UNO_QUERY);
2413 if (xComp == xElement)
2415 Reference<XPropertySet> xSet(xComp, UNO_QUERY);
2416 if (xSet.is() && hasProperty(PROPERTY_TABINDEX, xSet))
2417 xSet->setPropertyValue( PROPERTY_TABINDEX, Any(nTabIndex++) );
2418 break;
2426 Sequence<Reference<XControlModel> > SAL_CALL ODatabaseForm::getControlModels()
2428 ::osl::MutexGuard aGuard(m_aMutex);
2429 return m_pGroupManager->getControlModels();
2433 void SAL_CALL ODatabaseForm::setGroup( const Sequence<Reference<XControlModel> >& _rGroup, const OUString& Name )
2435 ::osl::MutexGuard aGuard(m_aMutex);
2437 // The controls are grouped by adjusting their names to the name of the
2438 // first control of the sequence
2439 Reference< XPropertySet > xSet;
2440 OUString sGroupName( Name );
2442 for( auto const& rControl : _rGroup )
2444 xSet.set(rControl, css::uno::UNO_QUERY);
2445 if ( !xSet.is() )
2447 // can't throw an exception other than a RuntimeException (which would not be appropriate),
2448 // so we ignore (and only assert) this
2449 OSL_FAIL( "ODatabaseForm::setGroup: invalid arguments!" );
2450 continue;
2453 if (sGroupName.isEmpty())
2454 xSet->getPropertyValue(PROPERTY_NAME) >>= sGroupName;
2455 else
2456 xSet->setPropertyValue(PROPERTY_NAME, Any(sGroupName));
2461 sal_Int32 SAL_CALL ODatabaseForm::getGroupCount()
2463 ::osl::MutexGuard aGuard(m_aMutex);
2464 return m_pGroupManager->getGroupCount();
2468 void SAL_CALL ODatabaseForm::getGroup( sal_Int32 nGroup, Sequence<Reference<XControlModel> >& _rGroup, OUString& _rName )
2470 ::osl::MutexGuard aGuard(m_aMutex);
2471 _rGroup.realloc(0);
2472 _rName.clear();
2474 if ((nGroup < 0) || (nGroup >= m_pGroupManager->getGroupCount()))
2475 return;
2476 m_pGroupManager->getGroup( nGroup, _rGroup, _rName );
2480 void SAL_CALL ODatabaseForm::getGroupByName(const OUString& Name, Sequence< Reference<XControlModel> >& _rGroup)
2482 ::osl::MutexGuard aGuard(m_aMutex);
2483 _rGroup.realloc(0);
2484 m_pGroupManager->getGroupByName( Name, _rGroup );
2488 // css::lang::XEventListener
2490 void SAL_CALL ODatabaseForm::disposing(const EventObject& Source)
2492 // does the call come from the connection which we are sharing with our parent?
2493 if ( isSharingConnection() )
2495 Reference< XConnection > xConnSource( Source.Source, UNO_QUERY );
2496 if ( xConnSource.is() )
2498 #if OSL_DEBUG_LEVEL > 0
2499 Reference< XConnection > xActiveConn;
2500 m_xAggregateSet->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xActiveConn;
2501 OSL_ENSURE( xActiveConn.get() == xConnSource.get(), "ODatabaseForm::disposing: where did this come from?" );
2502 // there should be exactly one XConnection object we're listening at - our aggregate connection
2503 #endif
2504 disposingSharedConnection( xConnSource );
2508 OInterfaceContainer::disposing(Source);
2510 // does the disposing come from the aggregate ?
2511 if (m_xAggregate.is())
2512 { // no -> forward it
2513 css::uno::Reference<css::lang::XEventListener> xListener;
2514 if (query_aggregation(m_xAggregate, xListener))
2515 xListener->disposing(Source);
2520 void ODatabaseForm::impl_createLoadTimer()
2522 OSL_PRECOND( m_pLoadTimer == nullptr, "ODatabaseForm::impl_createLoadTimer: timer already exists!" );
2523 m_pLoadTimer.reset(new Timer("DatabaseFormLoadTimer"));
2524 m_pLoadTimer->SetTimeout(100);
2525 m_pLoadTimer->SetInvokeHandler(LINK(this,ODatabaseForm,OnTimeout));
2529 // css::form::XLoadListener
2531 void SAL_CALL ODatabaseForm::loaded(const EventObject& /*aEvent*/)
2534 ::osl::MutexGuard aGuard( m_aMutex );
2535 Reference< XRowSet > xParentRowSet( m_xParent, UNO_QUERY_THROW );
2536 xParentRowSet->addRowSetListener( this );
2538 impl_createLoadTimer();
2541 load_impl( true );
2545 void SAL_CALL ODatabaseForm::unloading(const EventObject& /*aEvent*/)
2548 // now stop the rowset listening if we are a subform
2549 ::osl::MutexGuard aGuard( m_aMutex );
2551 if ( m_pLoadTimer && m_pLoadTimer->IsActive() )
2552 m_pLoadTimer->Stop();
2553 m_pLoadTimer.reset();
2555 Reference< XRowSet > xParentRowSet( m_xParent, UNO_QUERY_THROW );
2556 xParentRowSet->removeRowSetListener( this );
2559 unload();
2563 void SAL_CALL ODatabaseForm::unloaded(const EventObject& /*aEvent*/)
2565 // nothing to do
2569 void SAL_CALL ODatabaseForm::reloading(const EventObject& /*aEvent*/)
2571 // now stop the rowset listening if we are a subform
2572 ::osl::MutexGuard aGuard(m_aMutex);
2573 Reference<XRowSet> xParentRowSet(m_xParent, UNO_QUERY);
2574 if (xParentRowSet.is())
2575 xParentRowSet->removeRowSetListener(this);
2577 if (m_pLoadTimer && m_pLoadTimer->IsActive())
2578 m_pLoadTimer->Stop();
2582 void SAL_CALL ODatabaseForm::reloaded(const EventObject& /*aEvent*/)
2584 reload_impl(true);
2586 ::osl::MutexGuard aGuard(m_aMutex);
2587 Reference<XRowSet> xParentRowSet(m_xParent, UNO_QUERY);
2588 if (xParentRowSet.is())
2589 xParentRowSet->addRowSetListener(this);
2594 IMPL_LINK_NOARG(ODatabaseForm, OnTimeout, Timer *, void)
2596 reload_impl(true);
2600 // css::form::XLoadable
2602 void SAL_CALL ODatabaseForm::load()
2604 load_impl(false);
2608 bool ODatabaseForm::canShareConnection( const Reference< XPropertySet >& _rxParentProps )
2610 // our own data source
2611 OUString sOwnDatasource;
2612 m_xAggregateSet->getPropertyValue( PROPERTY_DATASOURCE ) >>= sOwnDatasource;
2614 // our parents data source
2615 OUString sParentDataSource;
2616 OSL_ENSURE( _rxParentProps.is() && _rxParentProps->getPropertySetInfo().is() && _rxParentProps->getPropertySetInfo()->hasPropertyByName( PROPERTY_DATASOURCE ),
2617 "ODatabaseForm::doShareConnection: invalid parent form!" );
2618 if ( _rxParentProps.is() )
2619 _rxParentProps->getPropertyValue( PROPERTY_DATASOURCE ) >>= sParentDataSource;
2621 bool bCanShareConnection = false;
2623 // both rowsets share are connected to the same data source
2624 if ( sParentDataSource == sOwnDatasource )
2626 if ( !sParentDataSource.isEmpty() )
2627 // and it's really a data source name (not empty)
2628 bCanShareConnection = true;
2629 else
2630 { // the data source name is empty
2631 // -> ok for the URL
2632 OUString sParentURL;
2633 OUString sMyURL;
2634 _rxParentProps->getPropertyValue( PROPERTY_URL ) >>= sParentURL;
2635 m_xAggregateSet->getPropertyValue( PROPERTY_URL ) >>= sMyURL;
2637 bCanShareConnection = (sParentURL == sMyURL);
2641 if ( bCanShareConnection )
2643 // check for the user/password
2645 // take the user property on the rowset (if any) into account
2646 OUString sParentUser, sParentPwd;
2647 _rxParentProps->getPropertyValue( PROPERTY_USER ) >>= sParentUser;
2648 _rxParentProps->getPropertyValue( PROPERTY_PASSWORD ) >>= sParentPwd;
2650 OUString sMyUser, sMyPwd;
2651 m_xAggregateSet->getPropertyValue( PROPERTY_USER ) >>= sMyUser;
2652 m_xAggregateSet->getPropertyValue( PROPERTY_PASSWORD ) >>= sMyPwd;
2654 bCanShareConnection =
2655 ( sParentUser == sMyUser )
2656 && ( sParentPwd == sMyPwd );
2659 return bCanShareConnection;
2663 void ODatabaseForm::doShareConnection( const Reference< XPropertySet >& _rxParentProps )
2665 // get the connection of the parent
2666 Reference< XConnection > xParentConn;
2667 _rxParentProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xParentConn;
2668 OSL_ENSURE( xParentConn.is(), "ODatabaseForm::doShareConnection: we're a valid sub-form, but the parent has no connection?!" );
2670 if ( xParentConn.is() )
2672 // add as dispose listener to the connection
2673 Reference< XComponent > xParentConnComp( xParentConn, UNO_QUERY );
2674 OSL_ENSURE( xParentConnComp.is(), "ODatabaseForm::doShareConnection: invalid connection!" );
2675 xParentConnComp->addEventListener( static_cast< XLoadListener* >( this ) );
2677 // forward the connection to our own aggregate
2678 m_bForwardingConnection = true;
2679 m_xAggregateSet->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, Any( xParentConn ) );
2680 m_bForwardingConnection = false;
2682 m_bSharingConnection = true;
2684 else
2685 m_bSharingConnection = false;
2689 void ODatabaseForm::disposingSharedConnection( const Reference< XConnection >& /*_rxConn*/ )
2691 stopSharingConnection();
2693 // TODO: we could think about whether or not to re-connect.
2694 unload( );
2698 void ODatabaseForm::stopSharingConnection( )
2700 OSL_ENSURE( m_bSharingConnection, "ODatabaseForm::stopSharingConnection: invalid call!" );
2702 if ( !m_bSharingConnection )
2703 return;
2705 // get the connection
2706 Reference< XConnection > xSharedConn;
2707 m_xAggregateSet->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xSharedConn;
2708 OSL_ENSURE( xSharedConn.is(), "ODatabaseForm::stopSharingConnection: there's no conn!" );
2710 // remove ourself as event listener
2711 Reference< XComponent > xSharedConnComp( xSharedConn, UNO_QUERY );
2712 if ( xSharedConnComp.is() )
2713 xSharedConnComp->removeEventListener( static_cast< XLoadListener* >( this ) );
2715 // no need to dispose the conn: we're not the owner, this is our parent
2716 // (in addition, this method may be called if the connection is being disposed while we use it)
2718 // reset the property
2719 xSharedConn.clear();
2720 m_bForwardingConnection = true;
2721 m_xAggregateSet->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, Any( xSharedConn ) );
2722 m_bForwardingConnection = false;
2724 // reset the flag
2725 m_bSharingConnection = false;
2728 namespace
2730 Reference<css::awt::XWindow> GetDialogParentWindow(const Reference<XModel>& rModel)
2732 if (!rModel.is())
2733 return nullptr;
2734 Reference<XController> xController(rModel->getCurrentController());
2735 if (!xController.is())
2736 return nullptr;
2737 Reference<XFrame> xFrame(xController->getFrame());
2738 if (!xFrame.is())
2739 return nullptr;
2740 return xFrame->getContainerWindow();
2744 bool ODatabaseForm::implEnsureConnection()
2748 if ( getConnection( ).is() )
2749 // if our aggregate already has a connection, nothing needs to be done about it
2750 return true;
2752 // see whether we're an embedded form
2753 Reference< XConnection > xOuterConnection;
2754 if ( ::dbtools::isEmbeddedInDatabase( getParent(), xOuterConnection ) )
2756 m_xAggregateSet->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, Any( xOuterConnection ) );
2757 return xOuterConnection.is();
2760 m_bSharingConnection = false;
2762 // if we're a sub form, we try to re-use the connection of our parent
2763 if (m_bSubForm)
2765 OSL_ENSURE( Reference< XForm >( getParent(), UNO_QUERY ).is(),
2766 "ODatabaseForm::implEnsureConnection: m_bSubForm is TRUE, but the parent is no form?" );
2768 Reference< XPropertySet > xParentProps( getParent(), UNO_QUERY );
2770 // can we re-use (aka share) the connection of the parent?
2771 if ( canShareConnection( xParentProps ) )
2773 // yep -> do it
2774 doShareConnection( xParentProps );
2775 // success?
2776 if ( m_bSharingConnection )
2777 // yes -> outta here
2778 return true;
2782 if (m_xAggregateSet.is())
2784 //Dig out a suitable parent for any warning dialogs
2785 Reference<css::awt::XWindow> m_xDialogParent;
2786 Reference<XChild> xParent(m_xParent, UNO_QUERY);
2787 if (xParent.is())
2788 m_xDialogParent = GetDialogParentWindow(getXModel(xParent->getParent()));
2790 Reference< XConnection > xConnection = connectRowset(
2791 Reference<XRowSet> (m_xAggregate, UNO_QUERY),
2792 m_xContext, m_xDialogParent
2794 return xConnection.is();
2797 catch(const SQLException& eDB)
2799 onError(eDB, ResourceManager::loadString(RID_STR_CONNECTERROR));
2801 catch(const Exception&)
2803 DBG_UNHANDLED_EXCEPTION("forms.component");
2806 return false;
2810 void ODatabaseForm::load_impl(bool bCausedByParentForm, bool bMoveToFirst, const Reference< XInteractionHandler >& _rxCompletionHandler )
2812 ::osl::ResettableMutexGuard aGuard(m_aMutex);
2814 // are we already loaded?
2815 if (isLoaded())
2816 return;
2818 m_bSubForm = bCausedByParentForm;
2820 // if we don't have a connection, we are not intended to be a database form or the aggregate was not able
2821 // to establish a connection
2822 bool bConnected = implEnsureConnection();
2824 // we don't have to execute if we do not have a command to execute
2825 bool bExecute = bConnected && m_xAggregateSet.is() && !getString(m_xAggregateSet->getPropertyValue(PROPERTY_COMMAND)).isEmpty();
2827 // a database form always uses caching
2828 // we use starting fetchsize with at least 10 rows
2829 if (bConnected)
2830 m_xAggregateSet->setPropertyValue(PROPERTY_FETCHSIZE, Any(sal_Int32(40)));
2832 // if we're loaded as sub form we got a "rowSetChanged" from the parent rowset _before_ we got the "loaded"
2833 // so we don't need to execute the statement again, this was already done
2834 // (and there were no relevant changes between these two listener calls, the "load" of a form is quite an
2835 // atomic operation.)
2837 bool bSuccess = false;
2838 if (bExecute)
2840 m_sCurrentErrorContext = ResourceManager::loadString(RID_ERR_LOADING_FORM);
2841 bSuccess = executeRowSet(aGuard, bMoveToFirst, _rxCompletionHandler);
2844 if (bSuccess)
2846 m_bLoaded = true;
2847 aGuard.clear();
2848 EventObject aEvt(static_cast<XWeak*>(this));
2849 m_aLoadListeners.notifyEach( &XLoadListener::loaded, aEvt );
2851 // if we are on the insert row, we have to reset all controls
2852 // to set the default values
2853 if (bExecute && getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_ISNEW)))
2854 reset();
2859 void SAL_CALL ODatabaseForm::unload()
2861 ::osl::ResettableMutexGuard aGuard(m_aMutex);
2862 if (!isLoaded())
2863 return;
2865 m_pLoadTimer.reset();
2867 aGuard.clear();
2868 EventObject aEvt(static_cast<XWeak*>(this));
2869 m_aLoadListeners.notifyEach( &XLoadListener::unloading, aEvt );
2871 if (m_xAggregateAsRowSet.is())
2873 // we may have reset the InsertOnly property on the aggregate - restore it
2874 restoreInsertOnlyState( );
2876 // clear the parameters if there are any
2877 invalidateParameters();
2881 // close the aggregate
2882 Reference<XCloseable> xCloseable;
2883 query_aggregation( m_xAggregate, xCloseable);
2884 if (xCloseable.is())
2885 xCloseable->close();
2887 catch(const SQLException&)
2892 aGuard.reset();
2893 m_bLoaded = false;
2895 // if the connection we used while we were loaded is only shared with our parent, we
2896 // reset it
2897 if ( isSharingConnection() )
2898 stopSharingConnection();
2900 aGuard.clear();
2901 m_aLoadListeners.notifyEach( &XLoadListener::unloaded, aEvt );
2905 void SAL_CALL ODatabaseForm::reload()
2907 reload_impl(true);
2911 void ODatabaseForm::reload_impl(bool bMoveToFirst, const Reference< XInteractionHandler >& _rxCompletionHandler )
2913 ::osl::ResettableMutexGuard aGuard(m_aMutex);
2914 if (!isLoaded())
2915 return;
2917 DocumentModifyGuard aModifyGuard( *this );
2918 // ensures the document is not marked as "modified" just because we change some control's content during
2919 // reloading...
2921 EventObject aEvent(static_cast<XWeak*>(this));
2923 // only if there is no approve listener we can post the event at this time
2924 // otherwise see approveRowsetChange
2925 // the approval is done by the aggregate
2926 if (!m_aRowSetApproveListeners.getLength())
2928 aGuard.clear();
2929 m_aLoadListeners.notifyEach( &XLoadListener::reloading, aEvent);
2930 aGuard.reset();
2934 bool bSuccess = true;
2937 m_sCurrentErrorContext = ResourceManager::loadString(RID_ERR_REFRESHING_FORM);
2938 bSuccess = executeRowSet(aGuard, bMoveToFirst, _rxCompletionHandler);
2940 catch(const SQLException&)
2942 TOOLS_WARN_EXCEPTION( "forms.component", "ODatabaseForm::reload_impl : shouldn't executeRowSet catch this exception?");
2945 if (bSuccess)
2947 aGuard.clear();
2948 m_aLoadListeners.notifyEach( &XLoadListener::reloaded, aEvent);
2950 // if we are on the insert row, we have to reset all controls
2951 // to set the default values
2952 if (getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_ISNEW)))
2953 reset();
2955 else
2956 m_bLoaded = false;
2960 sal_Bool SAL_CALL ODatabaseForm::isLoaded()
2962 return m_bLoaded;
2966 void SAL_CALL ODatabaseForm::addLoadListener(const Reference<XLoadListener>& aListener)
2968 m_aLoadListeners.addInterface(aListener);
2972 void SAL_CALL ODatabaseForm::removeLoadListener(const Reference<XLoadListener>& aListener)
2974 m_aLoadListeners.removeInterface(aListener);
2978 // css::sdbc::XCloseable
2979 void SAL_CALL ODatabaseForm::close()
2981 // unload will close the aggregate
2982 unload();
2986 // css::sdbc::XRowSetListener
2988 void SAL_CALL ODatabaseForm::cursorMoved(const EventObject& /*event*/)
2990 // reload the subform with the new parameters of the parent
2991 // do this handling delayed to provide of execute too many SQL Statements
2992 osl::MutexGuard aGuard(m_aMutex);
2994 DBG_ASSERT( m_pLoadTimer, "ODatabaseForm::cursorMoved: how can this happen?!" );
2995 if ( !m_pLoadTimer )
2996 impl_createLoadTimer();
2998 if ( m_pLoadTimer->IsActive() )
2999 m_pLoadTimer->Stop();
3001 // and start the timer again
3002 m_pLoadTimer->Start();
3006 void SAL_CALL ODatabaseForm::rowChanged(const EventObject& /*event*/)
3008 // ignore it
3012 void SAL_CALL ODatabaseForm::rowSetChanged(const EventObject& /*event*/)
3014 // not interested in :
3015 // if our parent is an ODatabaseForm, too, then after this rowSetChanged we'll get a "reloaded"
3016 // or a "loaded" event.
3017 // If somebody gave us another parent which is an XRowSet but doesn't handle an execute as
3018 // "load" respectively "reload"... can't do anything...
3022 bool ODatabaseForm::impl_approveRowChange_throw( const EventObject& _rEvent, const bool _bAllowSQLException,
3023 ::osl::ClearableMutexGuard& _rGuard )
3025 ::comphelper::OInterfaceIteratorHelper3 aIter( m_aRowSetApproveListeners );
3026 _rGuard.clear();
3027 while ( aIter.hasMoreElements() )
3029 Reference< XRowSetApproveListener > xListener( aIter.next() );
3032 if ( !xListener->approveRowSetChange( _rEvent ) )
3033 return false;
3035 catch (const DisposedException& e)
3037 if ( e.Context == xListener )
3038 aIter.remove();
3040 catch (const RuntimeException&)
3042 throw;
3044 catch (const SQLException&)
3046 DBG_UNHANDLED_EXCEPTION("forms.component");
3047 if ( _bAllowSQLException )
3048 throw;
3050 catch (const Exception&)
3052 DBG_UNHANDLED_EXCEPTION("forms.component");
3055 return true;
3059 sal_Bool SAL_CALL ODatabaseForm::approveCursorMove(const EventObject& event)
3061 // is our aggregate calling?
3062 if (event.Source == css::uno::Reference<css::uno::XInterface>(static_cast<XWeak*>(this)))
3064 // Our aggregate doesn't have any ApproveRowSetListeners (expect ourself), as we re-routed the queryInterface
3065 // for XRowSetApproveBroadcaster-interface.
3066 // So we have to multiplex this approve request.
3067 ::comphelper::OInterfaceIteratorHelper3 aIter( m_aRowSetApproveListeners );
3068 while ( aIter.hasMoreElements() )
3070 Reference< XRowSetApproveListener > xListener( aIter.next() );
3073 if ( !xListener->approveCursorMove( event ) )
3074 return false;
3076 catch (const DisposedException& e)
3078 if ( e.Context == xListener )
3079 aIter.remove();
3081 catch (const RuntimeException&)
3083 throw;
3085 catch (const Exception&)
3087 DBG_UNHANDLED_EXCEPTION("forms.component");
3090 return true;
3092 else
3094 // this is a call from our parent ...
3095 // a parent's cursor move will result in a re-execute of our own row-set, so we have to
3096 // ask our own RowSetChangesListeners, too
3097 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3098 if ( !impl_approveRowChange_throw( event, false, aGuard ) )
3099 return false;
3101 return true;
3105 sal_Bool SAL_CALL ODatabaseForm::approveRowChange(const RowChangeEvent& event)
3107 // is our aggregate calling?
3108 if (event.Source != css::uno::Reference<css::uno::XInterface>(static_cast<XWeak*>(this)))
3109 return true;
3111 // Our aggregate doesn't have any ApproveRowSetListeners (expect ourself), as we re-routed the queryInterface
3112 // for XRowSetApproveBroadcaster-interface.
3113 // So we have to multiplex this approve request.
3114 ::comphelper::OInterfaceIteratorHelper3 aIter( m_aRowSetApproveListeners );
3115 while ( aIter.hasMoreElements() )
3117 Reference< XRowSetApproveListener > xListener( aIter.next() );
3120 if ( !xListener->approveRowChange( event ) )
3121 return false;
3123 catch (const DisposedException& e)
3125 if ( e.Context == xListener )
3126 aIter.remove();
3128 catch (const RuntimeException&)
3130 throw;
3132 catch (const Exception&)
3134 DBG_UNHANDLED_EXCEPTION("forms.component");
3137 return true;
3141 sal_Bool SAL_CALL ODatabaseForm::approveRowSetChange(const EventObject& event)
3143 if (event.Source == css::uno::Reference<css::uno::XInterface>(static_cast<XWeak*>(this))) // ignore our aggregate as we handle this approve ourself
3145 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3146 bool bWasLoaded = isLoaded();
3147 if ( !impl_approveRowChange_throw( event, false, aGuard ) )
3148 return false;
3150 if ( bWasLoaded )
3152 m_aLoadListeners.notifyEach( &XLoadListener::reloading, event );
3155 else
3157 // this is a call from our parent ...
3158 // a parent's cursor move will result in a re-execute of our own row-set, so we have to
3159 // ask our own RowSetChangesListeners, too
3160 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3161 if ( !impl_approveRowChange_throw( event, false, aGuard ) )
3162 return false;
3164 return true;
3168 // css::sdb::XRowSetApproveBroadcaster
3170 void SAL_CALL ODatabaseForm::addRowSetApproveListener(const Reference<XRowSetApproveListener>& _rListener)
3172 osl::MutexGuard aGuard(m_aMutex);
3173 m_aRowSetApproveListeners.addInterface(_rListener);
3175 // do we have to multiplex ?
3176 if (m_aRowSetApproveListeners.getLength() == 1)
3178 Reference<XRowSetApproveBroadcaster> xBroadcaster;
3179 if (query_aggregation( m_xAggregate, xBroadcaster))
3181 Reference<XRowSetApproveListener> xListener(static_cast<XRowSetApproveListener*>(this));
3182 xBroadcaster->addRowSetApproveListener(xListener);
3188 void SAL_CALL ODatabaseForm::removeRowSetApproveListener(const Reference<XRowSetApproveListener>& _rListener)
3190 osl::MutexGuard aGuard(m_aMutex);
3191 // do we have to remove the multiplex ?
3192 m_aRowSetApproveListeners.removeInterface(_rListener);
3193 if ( m_aRowSetApproveListeners.getLength() == 0 )
3195 Reference<XRowSetApproveBroadcaster> xBroadcaster;
3196 if (query_aggregation( m_xAggregate, xBroadcaster))
3198 Reference<XRowSetApproveListener> xListener(static_cast<XRowSetApproveListener*>(this));
3199 xBroadcaster->removeRowSetApproveListener(xListener);
3205 // com::sun:star::form::XDatabaseParameterBroadcaster
3207 void SAL_CALL ODatabaseForm::addDatabaseParameterListener(const Reference<XDatabaseParameterListener>& _rListener)
3209 m_aParameterManager.addParameterListener( _rListener );
3212 void SAL_CALL ODatabaseForm::removeDatabaseParameterListener(const Reference<XDatabaseParameterListener>& _rListener)
3214 m_aParameterManager.removeParameterListener( _rListener );
3218 void SAL_CALL ODatabaseForm::addParameterListener(const Reference<XDatabaseParameterListener>& _rListener)
3220 ODatabaseForm::addDatabaseParameterListener( _rListener );
3224 void SAL_CALL ODatabaseForm::removeParameterListener(const Reference<XDatabaseParameterListener>& _rListener)
3226 ODatabaseForm::removeDatabaseParameterListener( _rListener );
3230 // css::sdb::XCompletedExecution
3232 void SAL_CALL ODatabaseForm::executeWithCompletion( const Reference< XInteractionHandler >& _rxHandler )
3234 ::osl::ClearableMutexGuard aGuard(m_aMutex);
3235 // the difference between execute and load is, that we position on the first row in case of load
3236 // after execute we remain before the first row
3237 if (!isLoaded())
3239 aGuard.clear();
3240 load_impl(false, false, _rxHandler);
3242 else
3244 EventObject event(static_cast< XWeak* >(this));
3245 if ( !impl_approveRowChange_throw( event, true, aGuard ) )
3246 return;
3248 // we're loaded and somebody wants to execute ourself -> this means a reload
3249 reload_impl(false, _rxHandler);
3254 // css::sdbc::XRowSet
3256 void SAL_CALL ODatabaseForm::execute()
3258 osl::ClearableMutexGuard aGuard(m_aMutex);
3259 // if somebody calls an execute and we're not loaded we reroute this call to our load method.
3261 // the difference between execute and load is, that we position on the first row in case of load
3262 // after execute we remain before the first row
3263 if (!isLoaded())
3265 aGuard.clear();
3266 load_impl(false, false);
3268 else
3270 EventObject event(static_cast< XWeak* >(this));
3271 if ( !impl_approveRowChange_throw( event, true, aGuard ) )
3272 return;
3274 // we're loaded and somebody wants to execute ourself -> this means a reload
3275 reload_impl(false);
3280 void SAL_CALL ODatabaseForm::addRowSetListener(const Reference<XRowSetListener>& _rListener)
3282 if (m_xAggregateAsRowSet.is())
3283 m_xAggregateAsRowSet->addRowSetListener(_rListener);
3287 void SAL_CALL ODatabaseForm::removeRowSetListener(const Reference<XRowSetListener>& _rListener)
3289 if (m_xAggregateAsRowSet.is())
3290 m_xAggregateAsRowSet->removeRowSetListener(_rListener);
3294 // css::sdbc::XResultSet
3296 sal_Bool SAL_CALL ODatabaseForm::next()
3298 return m_xAggregateAsRowSet->next();
3302 sal_Bool SAL_CALL ODatabaseForm::isBeforeFirst()
3304 return m_xAggregateAsRowSet->isBeforeFirst();
3308 sal_Bool SAL_CALL ODatabaseForm::isAfterLast()
3310 return m_xAggregateAsRowSet->isAfterLast();
3314 sal_Bool SAL_CALL ODatabaseForm::isFirst()
3316 return m_xAggregateAsRowSet->isFirst();
3320 sal_Bool SAL_CALL ODatabaseForm::isLast()
3322 return m_xAggregateAsRowSet->isLast();
3326 void SAL_CALL ODatabaseForm::beforeFirst()
3328 m_xAggregateAsRowSet->beforeFirst();
3332 void SAL_CALL ODatabaseForm::afterLast()
3334 m_xAggregateAsRowSet->afterLast();
3338 sal_Bool SAL_CALL ODatabaseForm::first()
3340 return m_xAggregateAsRowSet->first();
3344 sal_Bool SAL_CALL ODatabaseForm::last()
3346 return m_xAggregateAsRowSet->last();
3350 sal_Int32 SAL_CALL ODatabaseForm::getRow()
3352 return m_xAggregateAsRowSet->getRow();
3356 sal_Bool SAL_CALL ODatabaseForm::absolute(sal_Int32 row)
3358 return m_xAggregateAsRowSet->absolute(row);
3362 sal_Bool SAL_CALL ODatabaseForm::relative(sal_Int32 rows)
3364 return m_xAggregateAsRowSet->relative(rows);
3368 sal_Bool SAL_CALL ODatabaseForm::previous()
3370 return m_xAggregateAsRowSet->previous();
3374 void SAL_CALL ODatabaseForm::refreshRow()
3376 m_xAggregateAsRowSet->refreshRow();
3380 sal_Bool SAL_CALL ODatabaseForm::rowUpdated()
3382 return m_xAggregateAsRowSet->rowUpdated();
3386 sal_Bool SAL_CALL ODatabaseForm::rowInserted()
3388 return m_xAggregateAsRowSet->rowInserted();
3392 sal_Bool SAL_CALL ODatabaseForm::rowDeleted()
3394 return m_xAggregateAsRowSet->rowDeleted();
3398 css::uno::Reference<css::uno::XInterface> SAL_CALL ODatabaseForm::getStatement()
3400 return m_xAggregateAsRowSet->getStatement();
3403 // css::sdbc::XResultSetUpdate
3404 // exceptions during insert update and delete will be forwarded to the errorlistener
3406 void SAL_CALL ODatabaseForm::insertRow()
3410 Reference<XResultSetUpdate> xUpdate;
3411 if (query_aggregation( m_xAggregate, xUpdate))
3412 xUpdate->insertRow();
3414 catch(const RowSetVetoException&)
3416 throw;
3418 catch(const SQLException& eDb)
3420 onError(eDb, ResourceManager::loadString(RID_STR_ERR_INSERTRECORD));
3421 throw;
3426 void SAL_CALL ODatabaseForm::updateRow()
3430 Reference<XResultSetUpdate> xUpdate;
3431 if (query_aggregation( m_xAggregate, xUpdate))
3432 xUpdate->updateRow();
3434 catch(const RowSetVetoException&)
3436 throw;
3438 catch(const SQLException& eDb)
3440 onError(eDb, ResourceManager::loadString(RID_STR_ERR_UPDATERECORD));
3441 throw;
3446 void SAL_CALL ODatabaseForm::deleteRow()
3450 Reference<XResultSetUpdate> xUpdate;
3451 if (query_aggregation( m_xAggregate, xUpdate))
3452 xUpdate->deleteRow();
3454 catch(const RowSetVetoException&)
3456 throw;
3458 catch(const SQLException& eDb)
3460 onError(eDb, ResourceManager::loadString(RID_STR_ERR_DELETERECORD));
3461 throw;
3466 void SAL_CALL ODatabaseForm::cancelRowUpdates()
3470 Reference<XResultSetUpdate> xUpdate;
3471 if (query_aggregation( m_xAggregate, xUpdate))
3472 xUpdate->cancelRowUpdates();
3474 catch(const RowSetVetoException&)
3476 throw;
3478 catch(const SQLException& eDb)
3480 onError(eDb, ResourceManager::loadString(RID_STR_ERR_INSERTRECORD));
3481 throw;
3486 void SAL_CALL ODatabaseForm::moveToInsertRow()
3488 Reference<XResultSetUpdate> xUpdate;
3489 if (!query_aggregation( m_xAggregate, xUpdate))
3490 return;
3492 // _always_ move to the insert row
3494 // Formerly, the following line was conditioned with a "not is new", means we did not move the aggregate
3495 // to the insert row if it was already positioned there.
3497 // This prevented the RowSet implementation from resetting its column values. We, ourself, formerly
3498 // did this reset of columns in reset_impl, where we set every column to the ControlDefault, or, if this
3499 // was not present, to NULL. However, the problem with setting to NULL was #88888#, the problem with
3500 // _not_ setting to NULL (which was the original fix for #88888#) was #97955#.
3502 // So now we
3503 // * move our aggregate to the insert row
3504 // * in reset_impl
3505 // - set the control defaults into the columns if not void
3506 // - do _not_ set the columns to NULL if no control default is set
3508 // Still, there is #72756#. During fixing this bug, DG introduced not calling the aggregate here. So
3509 // in theory, we re-introduced #72756#. But the bug described therein does not happen anymore, as the
3510 // preliminaries for it changed (no display of guessed values for new records with autoinc fields)
3512 // BTW: the public Issuezilla bug is #i2815#
3514 xUpdate->moveToInsertRow();
3516 // then set the default values and the parameters given from the parent
3517 reset();
3521 void SAL_CALL ODatabaseForm::moveToCurrentRow()
3523 Reference<XResultSetUpdate> xUpdate;
3524 if (query_aggregation( m_xAggregate, xUpdate))
3525 xUpdate->moveToCurrentRow();
3528 // css::sdbcx::XDeleteRows
3530 Sequence<sal_Int32> SAL_CALL ODatabaseForm::deleteRows(const Sequence<Any>& rows)
3534 Reference<XDeleteRows> xDelete;
3535 if (query_aggregation( m_xAggregate, xDelete))
3536 return xDelete->deleteRows(rows);
3538 catch(const RowSetVetoException&)
3540 throw;
3542 catch(const SQLException& eDb)
3544 onError(eDb, ResourceManager::loadString(RID_STR_ERR_DELETERECORDS));
3545 throw;
3548 return Sequence< sal_Int32 >();
3551 // css::sdbc::XParameters
3553 void SAL_CALL ODatabaseForm::setNull(sal_Int32 parameterIndex, sal_Int32 sqlType)
3555 m_aParameterManager.setNull(parameterIndex, sqlType);
3559 void SAL_CALL ODatabaseForm::setObjectNull(sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName)
3561 m_aParameterManager.setObjectNull(parameterIndex, sqlType, typeName);
3565 void SAL_CALL ODatabaseForm::setBoolean(sal_Int32 parameterIndex, sal_Bool x)
3567 m_aParameterManager.setBoolean(parameterIndex, x);
3571 void SAL_CALL ODatabaseForm::setByte(sal_Int32 parameterIndex, sal_Int8 x)
3573 m_aParameterManager.setByte(parameterIndex, x);
3577 void SAL_CALL ODatabaseForm::setShort(sal_Int32 parameterIndex, sal_Int16 x)
3579 m_aParameterManager.setShort(parameterIndex, x);
3583 void SAL_CALL ODatabaseForm::setInt(sal_Int32 parameterIndex, sal_Int32 x)
3585 m_aParameterManager.setInt(parameterIndex, x);
3589 void SAL_CALL ODatabaseForm::setLong(sal_Int32 parameterIndex, sal_Int64 x)
3591 m_aParameterManager.setLong(parameterIndex, x);
3595 void SAL_CALL ODatabaseForm::setFloat(sal_Int32 parameterIndex, float x)
3597 m_aParameterManager.setFloat(parameterIndex, x);
3601 void SAL_CALL ODatabaseForm::setDouble(sal_Int32 parameterIndex, double x)
3603 m_aParameterManager.setDouble(parameterIndex, x);
3607 void SAL_CALL ODatabaseForm::setString(sal_Int32 parameterIndex, const OUString& x)
3609 m_aParameterManager.setString(parameterIndex, x);
3613 void SAL_CALL ODatabaseForm::setBytes(sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x)
3615 m_aParameterManager.setBytes(parameterIndex, x);
3619 void SAL_CALL ODatabaseForm::setDate(sal_Int32 parameterIndex, const css::util::Date& x)
3621 m_aParameterManager.setDate(parameterIndex, x);
3625 void SAL_CALL ODatabaseForm::setTime(sal_Int32 parameterIndex, const css::util::Time& x)
3627 m_aParameterManager.setTime(parameterIndex, x);
3631 void SAL_CALL ODatabaseForm::setTimestamp(sal_Int32 parameterIndex, const css::util::DateTime& x)
3633 m_aParameterManager.setTimestamp(parameterIndex, x);
3637 void SAL_CALL ODatabaseForm::setBinaryStream(sal_Int32 parameterIndex, const Reference<XInputStream>& x, sal_Int32 length)
3639 m_aParameterManager.setBinaryStream(parameterIndex, x, length);
3643 void SAL_CALL ODatabaseForm::setCharacterStream(sal_Int32 parameterIndex, const Reference<XInputStream>& x, sal_Int32 length)
3645 m_aParameterManager.setCharacterStream(parameterIndex, x, length);
3649 void SAL_CALL ODatabaseForm::setObjectWithInfo(sal_Int32 parameterIndex, const Any& x, sal_Int32 targetSqlType, sal_Int32 scale)
3651 m_aParameterManager.setObjectWithInfo(parameterIndex, x, targetSqlType, scale);
3655 void SAL_CALL ODatabaseForm::setObject(sal_Int32 parameterIndex, const Any& x)
3657 m_aParameterManager.setObject(parameterIndex, x);
3661 void SAL_CALL ODatabaseForm::setRef(sal_Int32 parameterIndex, const Reference<XRef>& x)
3663 m_aParameterManager.setRef(parameterIndex, x);
3667 void SAL_CALL ODatabaseForm::setBlob(sal_Int32 parameterIndex, const Reference<XBlob>& x)
3669 m_aParameterManager.setBlob(parameterIndex, x);
3673 void SAL_CALL ODatabaseForm::setClob(sal_Int32 parameterIndex, const Reference<XClob>& x)
3675 m_aParameterManager.setClob(parameterIndex, x);
3679 void SAL_CALL ODatabaseForm::setArray(sal_Int32 parameterIndex, const Reference<XArray>& x)
3681 m_aParameterManager.setArray(parameterIndex, x);
3685 void SAL_CALL ODatabaseForm::clearParameters()
3687 m_aParameterManager.clearParameters();
3691 void SAL_CALL ODatabaseForm::propertyChange( const PropertyChangeEvent& evt )
3693 if ( evt.Source == m_xParent )
3695 if ( evt.PropertyName == PROPERTY_ISNEW )
3697 bool bCurrentIsNew( false );
3698 OSL_VERIFY( evt.NewValue >>= bCurrentIsNew );
3699 if ( !bCurrentIsNew )
3700 reload_impl( true );
3702 return;
3704 OFormComponents::propertyChange( evt );
3707 // css::lang::XServiceInfo
3709 OUString SAL_CALL ODatabaseForm::getImplementationName()
3711 return "com.sun.star.comp.forms.ODatabaseForm";
3715 Sequence< OUString > SAL_CALL ODatabaseForm::getSupportedServiceNames()
3717 // the services of our aggregate
3718 Sequence< OUString > aServices;
3719 Reference< XServiceInfo > xInfo;
3720 if (query_aggregation(m_xAggregate, xInfo))
3721 aServices = xInfo->getSupportedServiceNames();
3723 // concat without own services
3724 return ::comphelper::concatSequences(
3725 css::uno::Sequence<OUString> {
3726 FRM_SUN_FORMCOMPONENT, "com.sun.star.form.FormComponents",
3727 FRM_SUN_COMPONENT_FORM, FRM_SUN_COMPONENT_HTMLFORM,
3728 FRM_SUN_COMPONENT_DATAFORM, FRM_COMPONENT_FORM },
3729 aServices
3733 sal_Bool SAL_CALL ODatabaseForm::supportsService(const OUString& ServiceName)
3735 return cppu::supportsService(this, ServiceName);
3738 // css::io::XPersistObject
3739 const sal_uInt16 CYCLE = 0x0001;
3740 const sal_uInt16 DONTAPPLYFILTER = 0x0002;
3742 OUString ODatabaseForm::getServiceName()
3744 return FRM_COMPONENT_FORM; // old (non-sun) name for compatibility !
3747 void SAL_CALL ODatabaseForm::write(const Reference<XObjectOutputStream>& _rxOutStream)
3749 DBG_ASSERT(m_xAggregateSet.is(), "ODatabaseForm::write : only to be called if the aggregate exists !");
3751 // all children
3752 OFormComponents::write(_rxOutStream);
3754 // version
3755 _rxOutStream->writeShort(0x0005);
3757 // Name
3758 _rxOutStream << m_sName;
3760 OUString sDataSource;
3761 if (m_xAggregateSet.is())
3762 m_xAggregateSet->getPropertyValue(PROPERTY_DATASOURCE) >>= sDataSource;
3763 _rxOutStream << sDataSource;
3765 // former CursorSource
3766 OUString sCommand;
3767 if (m_xAggregateSet.is())
3768 m_xAggregateSet->getPropertyValue(PROPERTY_COMMAND) >>= sCommand;
3769 _rxOutStream << sCommand;
3771 // former MasterFields
3772 _rxOutStream << m_aMasterFields;
3773 // former DetailFields
3774 _rxOutStream << m_aDetailFields;
3776 // former DataSelectionType
3777 DataSelectionType eTranslated = DataSelectionType_TABLE;
3778 if (m_xAggregateSet.is())
3780 sal_Int32 nCommandType = 0;
3781 m_xAggregateSet->getPropertyValue(PROPERTY_COMMANDTYPE) >>= nCommandType;
3782 switch (nCommandType)
3784 case CommandType::TABLE : eTranslated = DataSelectionType_TABLE; break;
3785 case CommandType::QUERY : eTranslated = DataSelectionType_QUERY; break;
3786 case CommandType::COMMAND:
3788 bool bEscapeProcessing = getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_ESCAPE_PROCESSING));
3789 eTranslated = bEscapeProcessing ? DataSelectionType_SQL : DataSelectionType_SQLPASSTHROUGH;
3791 break;
3792 default : OSL_FAIL("ODatabaseForm::write : wrong CommandType !");
3795 _rxOutStream->writeShort(static_cast<sal_Int16>(eTranslated)); // former DataSelectionType
3797 // very old versions expect a CursorType here
3798 _rxOutStream->writeShort(2); // DatabaseCursorType_KEYSET
3800 _rxOutStream->writeBoolean(m_eNavigation != NavigationBarMode_NONE);
3802 // former DataEntry
3803 if (m_xAggregateSet.is())
3804 _rxOutStream->writeBoolean(getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_INSERTONLY)));
3805 else
3806 _rxOutStream->writeBoolean(false);
3808 _rxOutStream->writeBoolean(m_bAllowInsert);
3809 _rxOutStream->writeBoolean(m_bAllowUpdate);
3810 _rxOutStream->writeBoolean(m_bAllowDelete);
3812 // html form stuff
3813 OUString sTmp = INetURLObject::decode( m_aTargetURL, INetURLObject::DecodeMechanism::Unambiguous);
3814 _rxOutStream << sTmp;
3815 _rxOutStream->writeShort( static_cast<sal_Int16>(m_eSubmitMethod) );
3816 _rxOutStream->writeShort( static_cast<sal_Int16>(m_eSubmitEncoding) );
3817 _rxOutStream << m_aTargetFrame;
3819 // version 2 didn't know some options and the "default" state
3820 sal_Int32 nCycle = sal_Int32(TabulatorCycle_RECORDS);
3821 if (m_aCycle.hasValue())
3823 ::cppu::enum2int(nCycle, m_aCycle);
3824 if (m_aCycle == TabulatorCycle_PAGE)
3825 // unknown in earlier versions
3826 nCycle = sal_Int32(TabulatorCycle_RECORDS);
3828 _rxOutStream->writeShort(static_cast<sal_Int16>(nCycle));
3830 _rxOutStream->writeShort(static_cast<sal_Int16>(m_eNavigation));
3832 OUString sFilter;
3833 OUString sSort;
3834 if (m_xAggregateSet.is())
3836 m_xAggregateSet->getPropertyValue(PROPERTY_FILTER) >>= sFilter;
3837 // version 4
3838 m_xAggregateSet->getPropertyValue(PROPERTY_SORT) >>= sSort;
3840 _rxOutStream << sFilter;
3841 _rxOutStream << sSort;
3843 // version 3
3844 sal_uInt16 nAnyMask = 0;
3845 if (m_aCycle.hasValue())
3846 nAnyMask |= CYCLE;
3848 if (m_xAggregateSet.is() && !getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_APPLYFILTER)))
3849 nAnyMask |= DONTAPPLYFILTER;
3851 _rxOutStream->writeShort(nAnyMask);
3853 if (nAnyMask & CYCLE)
3855 sal_Int32 nRealCycle = 0;
3856 ::cppu::enum2int(nRealCycle, m_aCycle);
3857 _rxOutStream->writeShort(static_cast<sal_Int16>(nRealCycle));
3860 // version 5
3861 OUString sHaving;
3862 if (m_xAggregateSet.is())
3863 m_xAggregateSet->getPropertyValue(PROPERTY_HAVINGCLAUSE) >>= sHaving;
3864 _rxOutStream << sHaving;
3868 void SAL_CALL ODatabaseForm::read(const Reference<XObjectInputStream>& _rxInStream)
3870 DBG_ASSERT(m_xAggregateSet.is(), "ODatabaseForm::read : only to be called if the aggregate exists !");
3872 OFormComponents::read(_rxInStream);
3874 // version
3875 sal_uInt16 nVersion = _rxInStream->readShort();
3877 _rxInStream >> m_sName;
3879 OUString sAggregateProp;
3880 _rxInStream >> sAggregateProp;
3881 if (m_xAggregateSet.is())
3882 m_xAggregateSet->setPropertyValue(PROPERTY_DATASOURCE, Any(sAggregateProp));
3883 _rxInStream >> sAggregateProp;
3884 if (m_xAggregateSet.is())
3885 m_xAggregateSet->setPropertyValue(PROPERTY_COMMAND, Any(sAggregateProp));
3887 _rxInStream >> m_aMasterFields;
3888 _rxInStream >> m_aDetailFields;
3890 sal_Int16 nCursorSourceType = _rxInStream->readShort();
3891 sal_Int32 nCommandType = 0;
3892 switch (static_cast<DataSelectionType>(nCursorSourceType))
3894 case DataSelectionType_TABLE : nCommandType = CommandType::TABLE; break;
3895 case DataSelectionType_QUERY : nCommandType = CommandType::QUERY; break;
3896 case DataSelectionType_SQL:
3897 case DataSelectionType_SQLPASSTHROUGH:
3899 nCommandType = CommandType::COMMAND;
3900 bool bEscapeProcessing = static_cast<DataSelectionType>(nCursorSourceType) != DataSelectionType_SQLPASSTHROUGH;
3901 m_xAggregateSet->setPropertyValue(PROPERTY_ESCAPE_PROCESSING, Any(bEscapeProcessing));
3903 break;
3904 default : OSL_FAIL("ODatabaseForm::read : wrong CommandType !");
3906 if (m_xAggregateSet.is())
3907 m_xAggregateSet->setPropertyValue(PROPERTY_COMMANDTYPE, Any(nCommandType));
3909 // obsolete
3910 _rxInStream->readShort();
3912 // navigation mode was a boolean in version 1
3913 // was a sal_Bool in version 1
3914 bool bNavigation = _rxInStream->readBoolean();
3915 if (nVersion == 1)
3916 m_eNavigation = bNavigation ? NavigationBarMode_CURRENT : NavigationBarMode_NONE;
3918 bool bInsertOnly = _rxInStream->readBoolean();
3919 if (m_xAggregateSet.is())
3920 m_xAggregateSet->setPropertyValue(PROPERTY_INSERTONLY, Any(bInsertOnly));
3922 m_bAllowInsert = _rxInStream->readBoolean();
3923 m_bAllowUpdate = _rxInStream->readBoolean();
3924 m_bAllowDelete = _rxInStream->readBoolean();
3926 // html stuff
3927 OUString sTmp;
3928 _rxInStream >> sTmp;
3929 m_aTargetURL = INetURLObject::decode( sTmp, INetURLObject::DecodeMechanism::Unambiguous);
3930 m_eSubmitMethod = static_cast<FormSubmitMethod>(_rxInStream->readShort());
3931 m_eSubmitEncoding = static_cast<FormSubmitEncoding>(_rxInStream->readShort());
3932 _rxInStream >> m_aTargetFrame;
3934 if (nVersion > 1)
3936 sal_Int32 nCycle = _rxInStream->readShort();
3937 m_aCycle <<= TabulatorCycle(nCycle);
3938 m_eNavigation = static_cast<NavigationBarMode>(_rxInStream->readShort());
3940 _rxInStream >> sAggregateProp;
3941 if (m_xAggregateSet.is())
3942 m_xAggregateSet->setPropertyValue(PROPERTY_FILTER, Any(sAggregateProp));
3943 if(nVersion > 3)
3945 _rxInStream >> sAggregateProp;
3946 if (m_xAggregateSet.is())
3947 m_xAggregateSet->setPropertyValue(PROPERTY_SORT, Any(sAggregateProp));
3951 sal_uInt16 nAnyMask = 0;
3952 if (nVersion > 2)
3954 nAnyMask = _rxInStream->readShort();
3955 if (nAnyMask & CYCLE)
3957 sal_Int32 nCycle = _rxInStream->readShort();
3958 m_aCycle <<= TabulatorCycle(nCycle);
3960 else
3961 m_aCycle.clear();
3963 if (m_xAggregateSet.is())
3964 m_xAggregateSet->setPropertyValue(PROPERTY_APPLYFILTER, Any((nAnyMask & DONTAPPLYFILTER) == 0));
3966 if(nVersion > 4)
3968 _rxInStream >> sAggregateProp;
3969 if (m_xAggregateSet.is())
3970 m_xAggregateSet->setPropertyValue(PROPERTY_HAVINGCLAUSE, Any(sAggregateProp));
3975 void ODatabaseForm::implInserted( const ElementDescription* _pElement )
3977 OFormComponents::implInserted( _pElement );
3979 Reference< XSQLErrorBroadcaster > xBroadcaster( _pElement->xInterface, UNO_QUERY );
3980 Reference< XForm > xForm ( _pElement->xInterface, UNO_QUERY );
3982 if ( xBroadcaster.is() && !xForm.is() )
3983 { // the object is an error broadcaster, but no form itself -> add ourself as listener
3984 xBroadcaster->addSQLErrorListener( this );
3989 void ODatabaseForm::implRemoved(const css::uno::Reference<css::uno::XInterface>& _rxObject)
3991 OFormComponents::implRemoved( _rxObject );
3993 Reference<XSQLErrorBroadcaster> xBroadcaster(_rxObject, UNO_QUERY);
3994 Reference<XForm> xForm(_rxObject, UNO_QUERY);
3995 if (xBroadcaster.is() && !xForm.is())
3996 { // the object is an error broadcaster, but no form itself -> remove ourself as listener
3997 xBroadcaster->removeSQLErrorListener(this);
4001 void SAL_CALL ODatabaseForm::errorOccured(const SQLErrorEvent& _rEvent)
4003 // give it to my own error listener
4004 onError(_rEvent);
4005 // TODO: think about extending the chain with an SQLContext object saying
4006 // "this was an error of one of my children"
4009 // css::container::XNamed
4010 OUString SAL_CALL ODatabaseForm::getName()
4012 OUString sReturn;
4015 OPropertySetHelper::getFastPropertyValue(PROPERTY_ID_NAME) >>= sReturn;
4017 catch (const css::beans::UnknownPropertyException&)
4019 throw WrappedTargetRuntimeException(
4020 "ODatabaseForm::getName",
4021 *this,
4022 ::cppu::getCaughtException()
4025 return sReturn;
4028 void SAL_CALL ODatabaseForm::setName(const OUString& aName)
4030 setFastPropertyValue(PROPERTY_ID_NAME, Any(aName));
4033 } // namespace frm
4035 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
4036 com_sun_star_comp_forms_ODatabaseForm_get_implementation(css::uno::XComponentContext* context,
4037 css::uno::Sequence<css::uno::Any> const &)
4039 return cppu::acquire(new frm::ODatabaseForm(context));
4042 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */