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