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