bump product version to 5.0.4.1
[LibreOffice.git] / forms / source / component / DatabaseForm.cxx
blob2e325405c20e7eed477449233a1ebf930432a596
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "componenttools.hxx"
22 #include "DatabaseForm.hxx"
23 #include "EventThread.hxx"
24 #include "frm_resource.hrc"
25 #include "frm_resource.hxx"
26 #include "GroupManager.hxx"
27 #include "property.hrc"
28 #include "property.hxx"
29 #include "services.hxx"
31 #include <com/sun/star/awt/XControlContainer.hpp>
32 #include <com/sun/star/awt/XTextComponent.hpp>
33 #include <com/sun/star/form/DataSelectionType.hpp>
34 #include <com/sun/star/form/FormComponentType.hpp>
35 #include <com/sun/star/form/TabulatorCycle.hpp>
36 #include <com/sun/star/frame/FrameSearchFlag.hpp>
37 #include <com/sun/star/frame/XDispatch.hpp>
38 #include <com/sun/star/frame/XDispatchProvider.hpp>
39 #include <com/sun/star/frame/XModel.hpp>
40 #include <com/sun/star/io/XObjectInputStream.hpp>
41 #include <com/sun/star/io/XObjectOutputStream.hpp>
42 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
43 #include <com/sun/star/sdb/CommandType.hpp>
44 #include <com/sun/star/sdb/RowSetVetoException.hpp>
45 #include <com/sun/star/sdb/SQLContext.hpp>
46 #include <com/sun/star/sdb/XColumnUpdate.hpp>
47 #include <com/sun/star/sdbc/DataType.hpp>
48 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
49 #include <com/sun/star/sdbc/ResultSetType.hpp>
50 #include <com/sun/star/sdbc/XRowSet.hpp>
51 #include <com/sun/star/sdbcx/Privilege.hpp>
52 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
53 #include <com/sun/star/util/XCancellable.hpp>
54 #include <com/sun/star/util/URLTransformer.hpp>
55 #include <com/sun/star/util/XURLTransformer.hpp>
56 #include <com/sun/star/util/XModifiable2.hpp>
58 #include <comphelper/basicio.hxx>
59 #include <comphelper/container.hxx>
60 #include <comphelper/enumhelper.hxx>
61 #include <comphelper/processfactory.hxx>
62 #include <comphelper/seqstream.hxx>
63 #include <comphelper/sequence.hxx>
64 #include <connectivity/dbtools.hxx>
65 #include <cppuhelper/exc_hlp.hxx>
66 #include <cppuhelper/implbase2.hxx>
67 #include <cppuhelper/supportsservice.hxx>
68 #include <rtl/math.hxx>
69 #include <rtl/tencinfo.h>
70 #include <svl/inettype.hxx>
71 #include <tools/datetime.hxx>
72 #include <tools/debug.hxx>
73 #include <tools/diagnose_ex.h>
74 #include <tools/inetmsg.hxx>
75 #include <tools/inetstrm.hxx>
76 #include <tools/urlobj.hxx>
77 #include <unotools/ucbstreamhelper.hxx>
78 #include <vcl/svapp.hxx>
79 #include <vcl/timer.hxx>
80 #include <osl/mutex.hxx>
82 #include <ctype.h>
83 #include <unordered_map>
85 // compatibility: DatabaseCursorType is dead, but for compatibility reasons we still have to write it ...
86 namespace com {
87 namespace sun {
88 namespace star {
89 namespace data {
91 enum DatabaseCursorType
93 DatabaseCursorType_FORWARD = 0,
94 DatabaseCursorType_SNAPSHOT = 1,
95 DatabaseCursorType_KEYSET = 2,
96 DatabaseCursorType_DYNAMIC = 3,
97 DatabaseCursorType_MAKE_FIXED_SIZE = SAL_MAX_ENUM
100 } } } }
102 using namespace ::dbtools;
103 using namespace ::comphelper;
104 using namespace ::com::sun::star::uno;
105 using namespace ::com::sun::star::sdb;
106 using namespace ::com::sun::star::sdbc;
107 using namespace ::com::sun::star::sdbcx;
108 using namespace ::com::sun::star::beans;
109 using namespace ::com::sun::star::container;
110 using namespace ::com::sun::star::task;
111 using namespace ::com::sun::star::frame;
112 using namespace ::com::sun::star::form;
113 using namespace ::com::sun::star::awt;
114 using namespace ::com::sun::star::io;
115 using namespace ::com::sun::star::lang;
116 using namespace ::com::sun::star::data;
117 using namespace ::com::sun::star::util;
120 namespace frm
123 class DocumentModifyGuard
125 public:
126 DocumentModifyGuard( const Reference< XInterface >& _rxFormComponent )
127 :m_xDocumentModify( getXModel( _rxFormComponent ), UNO_QUERY )
129 impl_changeModifiableFlag_nothrow( false );
131 ~DocumentModifyGuard()
133 impl_changeModifiableFlag_nothrow( true );
136 private:
137 void impl_changeModifiableFlag_nothrow( const bool _enable )
141 if ( m_xDocumentModify.is() )
142 _enable ? m_xDocumentModify->enableSetModified() : m_xDocumentModify->disableSetModified();
144 catch(const Exception&)
146 DBG_UNHANDLED_EXCEPTION();
150 private:
151 Reference< XModifiable2 > m_xDocumentModify;
154 // submitting and resetting html-forms asynchronously
155 class OFormSubmitResetThread: public OComponentEventThread
157 protected:
159 // duplicate an event with respect to it's type
160 virtual EventObject *cloneEvent( const EventObject *pEvt ) const SAL_OVERRIDE;
162 // process an event. while processing the mutex isn't locked, and pCompImpl
163 // is made sure to remain valid
164 virtual void processEvent( ::cppu::OComponentHelper* _pCompImpl,
165 const EventObject* _pEvt,
166 const Reference<XControl>& _rControl,
167 bool _bSubmit) SAL_OVERRIDE;
169 public:
171 OFormSubmitResetThread(ODatabaseForm* pControl) : OComponentEventThread(pControl) { }
175 EventObject* OFormSubmitResetThread::cloneEvent(
176 const EventObject *pEvt ) const
178 return new ::com::sun::star::awt::MouseEvent( *static_cast<const ::com::sun::star::awt::MouseEvent *>(pEvt) );
182 void OFormSubmitResetThread::processEvent(
183 ::cppu::OComponentHelper* pCompImpl,
184 const EventObject *_pEvt,
185 const Reference<XControl>& _rControl,
186 bool _bSubmit)
188 if (_bSubmit)
189 static_cast<ODatabaseForm *>(pCompImpl)->submit_impl(_rControl, *static_cast<const ::com::sun::star::awt::MouseEvent*>(_pEvt), true);
190 else
191 static_cast<ODatabaseForm *>(pCompImpl)->reset_impl(true);
195 //= ODatabaseForm
197 Sequence<sal_Int8> SAL_CALL ODatabaseForm::getImplementationId() throw(RuntimeException, std::exception)
199 return css::uno::Sequence<sal_Int8>();
203 Sequence<Type> SAL_CALL ODatabaseForm::getTypes() throw(RuntimeException, std::exception)
205 // ask the aggregate
206 Sequence<Type> aAggregateTypes;
207 Reference<XTypeProvider> xAggregateTypes;
208 if (query_aggregation(m_xAggregate, xAggregateTypes))
209 aAggregateTypes = xAggregateTypes->getTypes();
211 Sequence< Type > aRet = concatSequences(
212 aAggregateTypes, ODatabaseForm_BASE1::getTypes(), OFormComponents::getTypes()
214 aRet = concatSequences( aRet, ODatabaseForm_BASE2::getTypes(), ODatabaseForm_BASE3::getTypes() );
215 return concatSequences( aRet, OPropertySetAggregationHelper::getTypes() );
219 Any SAL_CALL ODatabaseForm::queryAggregation(const Type& _rType) throw(RuntimeException, std::exception)
221 Any aReturn = ODatabaseForm_BASE1::queryInterface(_rType);
222 // our own interfaces
223 if (!aReturn.hasValue())
225 aReturn = ODatabaseForm_BASE2::queryInterface(_rType);
226 // property set related interfaces
227 if (!aReturn.hasValue())
229 aReturn = OPropertySetAggregationHelper::queryInterface(_rType);
231 // form component collection related interfaces
232 if (!aReturn.hasValue())
234 aReturn = OFormComponents::queryAggregation(_rType);
236 // interfaces already present in the aggregate which we want to reroute
237 // only available if we could create the aggregate
238 if (!aReturn.hasValue() && m_xAggregateAsRowSet.is())
239 aReturn = ODatabaseForm_BASE3::queryInterface(_rType);
241 // aggregate interfaces
242 // (ask the aggregated object _after_ the OComponentHelper (base of OFormComponents),
243 // so calls to the XComponent interface reach us and not the aggregation)
244 if (!aReturn.hasValue() && m_xAggregate.is())
245 aReturn = m_xAggregate->queryAggregation(_rType);
250 return aReturn;
254 ODatabaseForm::ODatabaseForm(const Reference<XComponentContext>& _rxContext)
255 :OFormComponents(_rxContext)
256 ,OPropertySetAggregationHelper(OComponentHelper::rBHelper)
257 ,OPropertyChangeListener(m_aMutex)
258 ,m_aLoadListeners(m_aMutex)
259 ,m_aRowSetApproveListeners(m_aMutex)
260 ,m_aRowSetListeners(m_aMutex)
261 ,m_aSubmitListeners(m_aMutex)
262 ,m_aErrorListeners(m_aMutex)
263 ,m_aResetListeners( *this, m_aMutex )
264 ,m_aPropertyBagHelper( *this )
265 ,m_pAggregatePropertyMultiplexer(NULL)
266 ,m_pGroupManager( NULL )
267 ,m_aParameterManager( m_aMutex, _rxContext )
268 ,m_aFilterManager()
269 ,m_pLoadTimer(NULL)
270 ,m_pThread(NULL)
271 ,m_nResetsPending(0)
272 ,m_nPrivileges(0)
273 ,m_bInsertOnly( false )
274 ,m_eSubmitMethod(FormSubmitMethod_GET)
275 ,m_eSubmitEncoding(FormSubmitEncoding_URL)
276 ,m_eNavigation(NavigationBarMode_CURRENT)
277 ,m_bAllowInsert(true)
278 ,m_bAllowUpdate(true)
279 ,m_bAllowDelete(true)
280 ,m_bLoaded(false)
281 ,m_bSubForm(false)
282 ,m_bForwardingConnection(false)
283 ,m_bSharingConnection( false )
285 impl_construct();
289 ODatabaseForm::ODatabaseForm( const ODatabaseForm& _cloneSource )
290 :OFormComponents( _cloneSource )
291 ,OPropertySetAggregationHelper( OComponentHelper::rBHelper )
292 ,OPropertyChangeListener( m_aMutex )
293 ,ODatabaseForm_BASE1()
294 ,ODatabaseForm_BASE2()
295 ,ODatabaseForm_BASE3()
296 ,IPropertyBagHelperContext()
297 ,m_aLoadListeners( m_aMutex )
298 ,m_aRowSetApproveListeners( m_aMutex )
299 ,m_aRowSetListeners( m_aMutex )
300 ,m_aSubmitListeners( m_aMutex )
301 ,m_aErrorListeners( m_aMutex )
302 ,m_aResetListeners( *this, m_aMutex )
303 ,m_aPropertyBagHelper( *this )
304 ,m_pAggregatePropertyMultiplexer( NULL )
305 ,m_pGroupManager( NULL )
306 ,m_aParameterManager( m_aMutex, _cloneSource.m_xContext )
307 ,m_aFilterManager()
308 ,m_pLoadTimer( NULL )
309 ,m_pThread( NULL )
310 ,m_nResetsPending( 0 )
311 ,m_nPrivileges( 0 )
312 ,m_bInsertOnly( _cloneSource.m_bInsertOnly )
313 ,m_aControlBorderColorFocus( _cloneSource.m_aControlBorderColorFocus )
314 ,m_aControlBorderColorMouse( _cloneSource.m_aControlBorderColorMouse )
315 ,m_aControlBorderColorInvalid( _cloneSource.m_aControlBorderColorInvalid )
316 ,m_aDynamicControlBorder( _cloneSource.m_aDynamicControlBorder )
317 ,m_sName( _cloneSource.m_sName )
318 ,m_aTargetURL( _cloneSource.m_aTargetURL )
319 ,m_aTargetFrame( _cloneSource.m_aTargetFrame )
320 ,m_eSubmitMethod( _cloneSource.m_eSubmitMethod )
321 ,m_eSubmitEncoding( _cloneSource.m_eSubmitEncoding )
322 ,m_eNavigation( _cloneSource.m_eNavigation )
323 ,m_bAllowInsert( _cloneSource.m_bAllowInsert )
324 ,m_bAllowUpdate( _cloneSource.m_bAllowUpdate )
325 ,m_bAllowDelete( _cloneSource.m_bAllowDelete )
326 ,m_bLoaded( false )
327 ,m_bSubForm( false )
328 ,m_bForwardingConnection( false )
329 ,m_bSharingConnection( false )
332 impl_construct();
334 osl_atomic_increment( &m_refCount );
336 // our aggregated rowset itself is not cloneable, so simply copy the properties
337 ::comphelper::copyProperties( _cloneSource.m_xAggregateSet, m_xAggregateSet );
339 // also care for the dynamic properties: If the clone source has properties which we do not have,
340 // then add them
343 Reference< XPropertySet > xSourceProps( const_cast< ODatabaseForm& >( _cloneSource ).queryAggregation(
344 cppu::UnoType<XPropertySet>::get() ), UNO_QUERY_THROW );
345 Reference< XPropertySetInfo > xSourcePSI( xSourceProps->getPropertySetInfo(), UNO_SET_THROW );
346 Reference< XPropertyState > xSourcePropState( xSourceProps, UNO_QUERY );
348 Reference< XPropertySetInfo > xDestPSI( getPropertySetInfo(), UNO_QUERY_THROW );
350 Sequence< Property > aSourceProperties( xSourcePSI->getProperties() );
351 for ( const Property* pSourceProperty = aSourceProperties.getConstArray();
352 pSourceProperty != aSourceProperties.getConstArray() + aSourceProperties.getLength();
353 ++pSourceProperty
356 if ( xDestPSI->hasPropertyByName( pSourceProperty->Name ) )
357 continue;
359 // the initial value passed to XPropertyContainer is also used as default, usually. So, try
360 // to retrieve the default of the source property
361 Any aInitialValue;
362 if ( xSourcePropState.is() )
364 aInitialValue = xSourcePropState->getPropertyDefault( pSourceProperty->Name );
366 else
368 aInitialValue = xSourceProps->getPropertyValue( pSourceProperty->Name );
370 addProperty( pSourceProperty->Name, pSourceProperty->Attributes, aInitialValue );
371 setPropertyValue( pSourceProperty->Name, xSourceProps->getPropertyValue( pSourceProperty->Name ) );
374 catch(const RuntimeException&)
376 throw;
378 catch(const Exception&)
380 css::uno::Any a(cppu::getCaughtException());
381 throw WrappedTargetRuntimeException(
382 "Could not clone the given database form.",
383 *const_cast< ODatabaseForm* >( &_cloneSource ),
388 osl_atomic_decrement( &m_refCount );
391 void ODatabaseForm::impl_construct()
393 // aggregate a row set
394 osl_atomic_increment(&m_refCount);
396 m_xAggregate = Reference< XAggregation >( m_xContext->getServiceManager()->createInstanceWithContext(SRV_SDB_ROWSET, m_xContext), UNO_QUERY_THROW );
397 m_xAggregateAsRowSet.set( m_xAggregate, UNO_QUERY_THROW );
398 setAggregation( m_xAggregate );
401 // listen for the properties, important for Parameters
402 if ( m_xAggregateSet.is() )
404 m_pAggregatePropertyMultiplexer = new OPropertyChangeMultiplexer(this, m_xAggregateSet, false);
405 m_pAggregatePropertyMultiplexer->acquire();
406 m_pAggregatePropertyMultiplexer->addProperty(PROPERTY_COMMAND);
407 m_pAggregatePropertyMultiplexer->addProperty(PROPERTY_ACTIVE_CONNECTION);
411 Reference< XWarningsSupplier > xRowSetWarnings( m_xAggregate, UNO_QUERY );
412 m_aWarnings.setExternalWarnings( xRowSetWarnings );
415 if ( m_xAggregate.is() )
417 m_xAggregate->setDelegator( static_cast< XWeak* >( this ) );
421 m_aFilterManager.initialize( m_xAggregateSet );
422 m_aParameterManager.initialize( this, m_xAggregate );
424 declareForwardedProperty( PROPERTY_ID_ACTIVE_CONNECTION );
426 osl_atomic_decrement( &m_refCount );
428 m_pGroupManager = new OGroupManager( this );
429 m_pGroupManager->acquire();
433 ODatabaseForm::~ODatabaseForm()
436 m_pGroupManager->release();
437 m_pGroupManager = NULL;
439 if (m_xAggregate.is())
440 m_xAggregate->setDelegator( NULL );
442 m_aWarnings.setExternalWarnings( NULL );
444 if (m_pAggregatePropertyMultiplexer)
446 m_pAggregatePropertyMultiplexer->dispose();
447 m_pAggregatePropertyMultiplexer->release();
448 m_pAggregatePropertyMultiplexer = NULL;
453 // html tools
455 OUString ODatabaseForm::GetDataURLEncoded(const Reference<XControl>& SubmitButton, const ::com::sun::star::awt::MouseEvent& MouseEvt)
457 return GetDataEncoded(true,SubmitButton,MouseEvt);
460 OUString ODatabaseForm::GetDataEncoded(bool _bURLEncoded,const Reference<XControl>& SubmitButton, const ::com::sun::star::awt::MouseEvent& MouseEvt)
462 // Fill List of successful Controls
463 HtmlSuccessfulObjList aSuccObjList;
464 FillSuccessfulList( aSuccObjList, SubmitButton, MouseEvt );
467 // Aggregate Liste to OUString
468 OUStringBuffer aResult;
469 OUString aName;
470 OUString aValue;
472 for ( HtmlSuccessfulObjList::iterator pSuccObj = aSuccObjList.begin();
473 pSuccObj < aSuccObjList.end();
474 ++pSuccObj
477 aName = pSuccObj->aName;
478 aValue = pSuccObj->aValue;
479 if( pSuccObj->nRepresentation == SUCCESSFUL_REPRESENT_FILE && !aValue.isEmpty() )
481 // For File URLs we transfer the file name and not a URL, because Netscape does it like that
482 INetURLObject aURL;
483 aURL.SetSmartProtocol(INetProtocol::File);
484 aURL.SetSmartURL(aValue);
485 if( INetProtocol::File == aURL.GetProtocol() )
486 aValue = INetURLObject::decode(aURL.PathToFileName(), INetURLObject::DECODE_UNAMBIGUOUS);
488 Encode( aName );
489 Encode( aValue );
491 aResult.append(aName);
492 aResult.append('=');
493 aResult.append(aValue);
495 if (pSuccObj < aSuccObjList.end() - 1)
497 if ( _bURLEncoded )
498 aResult.append('&');
499 else
500 aResult.appendAscii("\r\n");
505 aSuccObjList.clear();
507 return aResult.makeStringAndClear();
511 // html tools
513 OUString ODatabaseForm::GetDataTextEncoded(const Reference<XControl>& SubmitButton, const ::com::sun::star::awt::MouseEvent& MouseEvt)
515 return GetDataEncoded(false,SubmitButton,MouseEvt);
519 Sequence<sal_Int8> ODatabaseForm::GetDataMultiPartEncoded(const Reference<XControl>& SubmitButton, const ::com::sun::star::awt::MouseEvent& MouseEvt, OUString& rContentType)
522 // Create Parent
523 INetMIMEMessage aParent;
524 aParent.EnableAttachChild( INETMSG_MULTIPART_FORM_DATA );
527 // Fill List of successful Controls
528 HtmlSuccessfulObjList aSuccObjList;
529 FillSuccessfulList( aSuccObjList, SubmitButton, MouseEvt );
532 // Aggregate Liste to OUString
533 for ( HtmlSuccessfulObjList::iterator pSuccObj = aSuccObjList.begin();
534 pSuccObj < aSuccObjList.end();
535 ++pSuccObj
538 if( pSuccObj->nRepresentation == SUCCESSFUL_REPRESENT_TEXT )
539 InsertTextPart( aParent, pSuccObj->aName, pSuccObj->aValue );
540 else if( pSuccObj->nRepresentation == SUCCESSFUL_REPRESENT_FILE )
541 InsertFilePart( aParent, pSuccObj->aName, pSuccObj->aValue );
545 // Delete List
546 aSuccObjList.clear();
548 // Create MessageStream for parent
549 INetMIMEMessageStream aMessStream;
550 aMessStream.SetSourceMessage( &aParent );
551 aMessStream.SetHeaderGenerated();
553 // Copy MessageStream to SvStream
554 SvMemoryStream aMemStream;
555 char* pBuf = new char[1025];
556 int nRead;
557 while( (nRead = aMessStream.Read(pBuf, 1024)) > 0 )
558 aMemStream.Write( pBuf, nRead );
559 delete[] pBuf;
561 aMemStream.Flush();
562 aMemStream.Seek( 0 );
563 void const * pData = aMemStream.GetData();
564 sal_Int32 nLen = aMemStream.Seek(STREAM_SEEK_TO_END);
566 rContentType = aParent.GetContentType();
567 return Sequence<sal_Int8>(static_cast<sal_Int8 const *>(pData), nLen);
571 namespace
573 static void appendDigits( sal_Int32 _nNumber, sal_Int8 nDigits, OUStringBuffer& _rOut )
575 sal_Int32 nCurLen = _rOut.getLength();
576 _rOut.append( _nNumber );
577 while ( _rOut.getLength() - nCurLen < nDigits )
578 _rOut.insert( nCurLen, '0' );
583 void ODatabaseForm::AppendComponent(HtmlSuccessfulObjList& rList, const Reference<XPropertySet>& xComponentSet, const OUString& rNamePrefix,
584 const Reference<XControl>& rxSubmitButton, const ::com::sun::star::awt::MouseEvent& MouseEvt)
586 if (!xComponentSet.is())
587 return;
589 // TODO: Catch nested Forms; or would we need to submit them?
590 if (!hasProperty(PROPERTY_CLASSID, xComponentSet))
591 return;
593 // Get names
594 if (!hasProperty(PROPERTY_NAME, xComponentSet))
595 return;
597 sal_Int16 nClassId = 0;
598 xComponentSet->getPropertyValue(PROPERTY_CLASSID) >>= nClassId;
599 OUString aName;
600 xComponentSet->getPropertyValue( PROPERTY_NAME ) >>= aName;
601 if( aName.isEmpty() && nClassId != FormComponentType::IMAGEBUTTON)
602 return;
603 else // Extend name with the prefix
604 aName = rNamePrefix + aName;
606 switch( nClassId )
608 // Buttons
609 case FormComponentType::COMMANDBUTTON:
611 // We only evaluate the pressed Submit button
612 // If one is passed at all
613 if( rxSubmitButton.is() )
615 Reference<XPropertySet> xSubmitButtonComponent(rxSubmitButton->getModel(), UNO_QUERY);
616 if (xSubmitButtonComponent == xComponentSet && hasProperty(PROPERTY_LABEL, xComponentSet))
618 // <name>=<label>
619 OUString aLabel;
620 xComponentSet->getPropertyValue( PROPERTY_LABEL ) >>= aLabel;
621 rList.push_back( HtmlSuccessfulObj(aName, aLabel) );
624 } break;
626 // ImageButtons
627 case FormComponentType::IMAGEBUTTON:
629 // We only evaluate the pressed Submit button
630 // If one is passed at all
631 if( rxSubmitButton.is() )
633 Reference<XPropertySet> xSubmitButtonComponent(rxSubmitButton->getModel(), UNO_QUERY);
634 if (xSubmitButtonComponent == xComponentSet)
636 // <name>.x=<pos.X>&<name>.y=<pos.Y>
637 OUString aRhs = OUString::number( MouseEvt.X );
639 // Only if a name is available we have a name.x
640 OUStringBuffer aLhs(aName);
641 if (!aName.isEmpty())
642 aLhs.append(".x");
643 else
644 aLhs.append("x");
645 rList.push_back( HtmlSuccessfulObj(aLhs.makeStringAndClear(), aRhs) );
647 aLhs.append(aName);
648 aRhs = OUString::number( MouseEvt.Y );
649 if (!aName.isEmpty())
650 aLhs.append(".y");
651 else
652 aLhs.append("y");
653 rList.push_back( HtmlSuccessfulObj(aLhs.makeStringAndClear(), aRhs) );
656 } break;
658 // CheckBoxes/RadioButtons
659 case FormComponentType::CHECKBOX:
660 case FormComponentType::RADIOBUTTON:
662 // <name>=<refValue>
663 if( !hasProperty(PROPERTY_STATE, xComponentSet) )
664 break;
665 sal_Int16 nChecked = 0;
666 xComponentSet->getPropertyValue( PROPERTY_STATE ) >>= nChecked;
667 if( nChecked != 1 )
668 break;
670 OUString aStrValue;
671 if( hasProperty(PROPERTY_REFVALUE, xComponentSet) )
672 xComponentSet->getPropertyValue( PROPERTY_REFVALUE ) >>= aStrValue;
674 rList.push_back( HtmlSuccessfulObj(aName, aStrValue) );
675 } break;
677 // Edit
678 case FormComponentType::TEXTFIELD:
680 // <name>=<text>
681 if( !hasProperty(PROPERTY_TEXT, xComponentSet) )
682 break;
684 // Special treatment for multiline edit only if we have a control for it
685 Any aTmp = xComponentSet->getPropertyValue( PROPERTY_MULTILINE );
686 bool bMulti = rxSubmitButton.is()
687 && (aTmp.getValueType().getTypeClass() == TypeClass_BOOLEAN)
688 && getBOOL(aTmp);
689 OUString sText;
690 if ( bMulti ) // For multiline edit, get the text at the control
693 Reference<XControlContainer> xControlContainer(rxSubmitButton->getContext(), UNO_QUERY);
694 if( !xControlContainer.is() ) break;
696 Sequence<Reference<XControl> > aControlSeq = xControlContainer->getControls();
697 Reference<XControl> xControl;
698 Reference<XFormComponent> xControlComponent;
700 // Find the right control
701 sal_Int32 i;
702 for( i=0; i<aControlSeq.getLength(); i++ )
704 xControl = aControlSeq.getConstArray()[i];
705 Reference<XPropertySet> xModel(xControl->getModel(), UNO_QUERY);
706 if (xModel == xComponentSet)
708 Reference<XTextComponent> xTextComponent(xControl, UNO_QUERY);
709 if( xTextComponent.is() )
710 sText = xTextComponent->getText();
711 break;
714 // Couldn't find control or it does not exist (edit in the grid)
715 if (i == aControlSeq.getLength())
716 xComponentSet->getPropertyValue( PROPERTY_TEXT ) >>= sText;
718 else
719 xComponentSet->getPropertyValue( PROPERTY_TEXT ) >>= sText;
721 rList.push_back( HtmlSuccessfulObj(aName, sText) );
722 } break;
724 // ComboBox, Patternfield
725 case FormComponentType::COMBOBOX:
726 case FormComponentType::PATTERNFIELD:
728 // <name>=<text>
729 if( hasProperty(PROPERTY_TEXT, xComponentSet) )
731 OUString aText;
732 xComponentSet->getPropertyValue( PROPERTY_TEXT ) >>= aText;
733 rList.push_back( HtmlSuccessfulObj(aName, aText) );
735 } break;
736 case FormComponentType::CURRENCYFIELD:
737 case FormComponentType::NUMERICFIELD:
739 // <name>=<value> // Value is a double with dot as decimal delimiter
740 // no value (NULL) means empty value
741 if( hasProperty(PROPERTY_VALUE, xComponentSet) )
743 OUString aText;
744 Any aVal = xComponentSet->getPropertyValue( PROPERTY_VALUE );
746 double aDoubleVal = 0;
747 if (aVal >>= aDoubleVal)
749 sal_Int16 nScale = 0;
750 xComponentSet->getPropertyValue( PROPERTY_DECIMAL_ACCURACY ) >>= nScale;
751 aText = ::rtl::math::doubleToUString(aDoubleVal, rtl_math_StringFormat_F, nScale, '.', true);
753 rList.push_back( HtmlSuccessfulObj(aName, aText) );
755 } break;
756 case FormComponentType::DATEFIELD:
758 // <name>=<value> // Value is a Date with the format MM-DD-YYYY
759 // no value (NULL) means empty value
760 if( hasProperty(PROPERTY_DATE, xComponentSet) )
762 OUString aText;
763 Any aVal = xComponentSet->getPropertyValue( PROPERTY_DATE );
764 sal_Int32 nInt32Val = 0;
765 if (aVal >>= nInt32Val)
767 ::Date aDate( nInt32Val );
768 OUStringBuffer aBuffer;
769 appendDigits( aDate.GetMonth(), 2, aBuffer );
770 aBuffer.append( '-' );
771 appendDigits( aDate.GetDay(), 2, aBuffer );
772 aBuffer.append( '-' );
773 appendDigits( aDate.GetYear(), 4, aBuffer );
774 aText = aBuffer.makeStringAndClear();
776 rList.push_back( HtmlSuccessfulObj(aName, aText) );
778 } break;
779 case FormComponentType::TIMEFIELD:
781 // <name>=<value> // Value is a Time with the format HH:MM:SS
782 // no value (NULL) means empty value
783 if( hasProperty(PROPERTY_TIME, xComponentSet) )
785 OUString aText;
786 Any aVal = xComponentSet->getPropertyValue( PROPERTY_TIME );
787 sal_Int32 nInt32Val = 0;
788 if (aVal >>= nInt32Val)
790 ::tools::Time aTime(nInt32Val);
791 OUStringBuffer aBuffer;
792 appendDigits( aTime.GetHour(), 2, aBuffer );
793 aBuffer.append( '-' );
794 appendDigits( aTime.GetMin(), 2, aBuffer );
795 aBuffer.append( '-' );
796 appendDigits( aTime.GetSec(), 2, aBuffer );
797 aText = aBuffer.makeStringAndClear();
799 rList.push_back( HtmlSuccessfulObj(aName, aText) );
801 } break;
803 // starform
804 case FormComponentType::HIDDENCONTROL:
807 // <name>=<value>
808 if( hasProperty(PROPERTY_HIDDEN_VALUE, xComponentSet) )
810 OUString aText;
811 xComponentSet->getPropertyValue( PROPERTY_HIDDEN_VALUE ) >>= aText;
812 rList.push_back( HtmlSuccessfulObj(aName, aText) );
814 } break;
816 // starform
817 case FormComponentType::FILECONTROL:
819 // <name>=<text>
820 if( hasProperty(PROPERTY_TEXT, xComponentSet) )
823 OUString aText;
824 xComponentSet->getPropertyValue( PROPERTY_TEXT ) >>= aText;
825 rList.push_back( HtmlSuccessfulObj(aName, aText, SUCCESSFUL_REPRESENT_FILE) );
827 } break;
829 // starform
830 case FormComponentType::LISTBOX:
833 // <name>=<Token0>&<name>=<Token1>&...&<name>=<TokenN> (multiple selection)
834 if (!hasProperty(PROPERTY_SELECT_SEQ, xComponentSet) ||
835 !hasProperty(PROPERTY_STRINGITEMLIST, xComponentSet))
836 break;
838 // Displayed values
839 Sequence< OUString > aVisibleList;
840 xComponentSet->getPropertyValue( PROPERTY_STRINGITEMLIST ) >>= aVisibleList;
841 sal_Int32 nStringCnt = aVisibleList.getLength();
842 const OUString* pStrings = aVisibleList.getConstArray();
844 // Value list
845 Sequence< OUString > aValueList;
846 xComponentSet->getPropertyValue( PROPERTY_VALUE_SEQ ) >>= aValueList;
847 sal_Int32 nValCnt = aValueList.getLength();
848 const OUString* pVals = aValueList.getConstArray();
850 // Selection
851 Sequence<sal_Int16> aSelectList;
852 xComponentSet->getPropertyValue( PROPERTY_SELECT_SEQ ) >>= aSelectList;
853 sal_Int32 nSelCount = aSelectList.getLength();
854 const sal_Int16* pSels = aSelectList.getConstArray();
856 // Simple or multiple selection
857 // For simple selections MT only accounts for the list's first entry.
858 if (nSelCount > 1 && !getBOOL(xComponentSet->getPropertyValue(PROPERTY_MULTISELECTION)))
859 nSelCount = 1;
861 // The indices in the selection list can also be invalid, so we first have to
862 // find the valid ones to determine the length of the new list.
863 sal_Int32 nCurCnt = 0;
864 sal_Int32 i;
865 for( i=0; i<nSelCount; ++i )
867 if( pSels[i] < nStringCnt )
868 ++nCurCnt;
871 OUString aSubValue;
872 for(i=0; i<nCurCnt; ++i )
874 sal_Int16 nSelPos = pSels[i];
875 if (nSelPos < nValCnt && !pVals[nSelPos].isEmpty())
877 aSubValue = pVals[nSelPos];
879 else
881 aSubValue = pStrings[nSelPos];
883 rList.push_back( HtmlSuccessfulObj(aName, aSubValue) );
885 } break;
886 case FormComponentType::GRIDCONTROL:
888 // Each of the column values is sent;
889 // the name is extended by the grid's prefix.
890 Reference<XIndexAccess> xContainer(xComponentSet, UNO_QUERY);
891 if (!xContainer.is())
892 break;
894 aName += ".";
896 Reference<XPropertySet> xSet;
897 sal_Int32 nCount = xContainer->getCount();
898 // we know already how many objects should be appended,
899 // so why not allocate the space for them
900 rList.reserve( nCount + rList.capacity() ); // not size()
901 for (sal_Int32 i = 0; i < nCount; ++i)
903 xContainer->getByIndex(i) >>= xSet;
904 if (xSet.is())
905 AppendComponent(rList, xSet, aName, rxSubmitButton, MouseEvt);
912 void ODatabaseForm::FillSuccessfulList( HtmlSuccessfulObjList& rList,
913 const Reference<XControl>& rxSubmitButton, const ::com::sun::star::awt::MouseEvent& MouseEvt )
915 // Delete list
916 rList.clear();
917 // Iterate over Components
918 Reference<XPropertySet> xComponentSet;
919 OUString aPrefix;
921 // we know already how many objects should be appended,
922 // so why not allocate the space for them
923 rList.reserve( getCount() );
924 for( sal_Int32 nIndex=0; nIndex < getCount(); nIndex++ )
926 getByIndex( nIndex ) >>= xComponentSet;
927 AppendComponent(rList, xComponentSet, aPrefix, rxSubmitButton, MouseEvt);
932 void ODatabaseForm::Encode( OUString& rString )
934 OUStringBuffer aResult;
936 // Line endings are represented as CR
937 rString = convertLineEnd(rString, LINEEND_CR);
939 // Check each character
940 sal_Int32 nStrLen = rString.getLength();
941 sal_Unicode nCharCode;
942 for( sal_Int32 nCurPos=0; nCurPos < nStrLen; ++nCurPos )
944 nCharCode = rString[nCurPos];
946 // Handle chars, which are not an alphanumeric character and character codes > 127
947 if( (!isalnum(nCharCode) && nCharCode != ' ') || nCharCode > 127 )
949 switch( nCharCode )
951 case 13: // CR
952 aResult.append("%0D%0A"); // CR LF in hex
953 break;
956 // Special treatment for Netscape
957 case 42: // '*'
958 case 45: // '-'
959 case 46: // '.'
960 case 64: // '@'
961 case 95: // '_'
962 aResult.append(nCharCode);
963 break;
965 default:
967 // Convert to hex
968 short nHi = ((sal_Int16)nCharCode) / 16;
969 short nLo = ((sal_Int16)nCharCode) - (nHi*16);
970 if( nHi > 9 ) nHi += (int)'A'-10; else nHi += (int)'0';
971 if( nLo > 9 ) nLo += (int)'A'-10; else nLo += (int)'0';
972 aResult.append('%');
973 aResult.append((sal_Unicode)nHi);
974 aResult.append((sal_Unicode)nLo);
978 else
979 aResult.append(nCharCode);
982 // Replace spaces with '+'
983 rString = aResult.makeStringAndClear().replace(' ', '+');
987 void ODatabaseForm::InsertTextPart( INetMIMEMessage& rParent, const OUString& rName,
988 const OUString& rData )
991 // Create part as MessageChild
992 INetMIMEMessage* pChild = new INetMIMEMessage();
995 // Header
996 OUStringBuffer aContentDisp;
997 aContentDisp.append("form-data; name=\"");
998 aContentDisp.append(rName);
999 aContentDisp.append('\"');
1000 pChild->SetContentDisposition(aContentDisp.makeStringAndClear());
1001 pChild->SetContentType(OUString("text/plain"));
1003 rtl_TextEncoding eSystemEncoding = osl_getThreadTextEncoding();
1004 const sal_Char* pBestMatchingEncoding = rtl_getBestMimeCharsetFromTextEncoding( eSystemEncoding );
1005 OUString aBestMatchingEncoding = OUString::createFromAscii(pBestMatchingEncoding);
1006 pChild->SetContentTransferEncoding(aBestMatchingEncoding);
1008 // Body
1009 SvMemoryStream* pStream = new SvMemoryStream;
1010 pStream->WriteLine( OUStringToOString(rData, rtl_getTextEncodingFromMimeCharset(pBestMatchingEncoding)) );
1011 pStream->Flush();
1012 pStream->Seek( 0 );
1013 pChild->SetDocumentLB( new SvLockBytes(pStream, true) );
1014 rParent.AttachChild( *pChild );
1018 bool ODatabaseForm::InsertFilePart( INetMIMEMessage& rParent, const OUString& rName,
1019 const OUString& rFileName )
1021 OUString aFileName(rFileName);
1022 OUString aContentType(CONTENT_TYPE_STR_TEXT_PLAIN);
1023 SvStream *pStream = 0;
1025 if (!aFileName.isEmpty())
1027 // We can only process File URLs yet
1028 INetURLObject aURL;
1029 aURL.SetSmartProtocol(INetProtocol::File);
1030 aURL.SetSmartURL(rFileName);
1031 if( INetProtocol::File == aURL.GetProtocol() )
1033 aFileName = INetURLObject::decode(aURL.PathToFileName(), INetURLObject::DECODE_UNAMBIGUOUS);
1034 pStream = ::utl::UcbStreamHelper::CreateStream(aFileName, StreamMode::READ);
1035 if (!pStream || (pStream->GetError() != ERRCODE_NONE))
1037 delete pStream;
1038 pStream = 0;
1040 sal_Int32 nSepInd = aFileName.lastIndexOf('.');
1041 OUString aExtension = aFileName.copy( nSepInd + 1, aFileName.getLength() - nSepInd - 1 );
1042 INetContentType eContentType = INetContentTypes::GetContentType4Extension( aExtension );
1043 if (eContentType != CONTENT_TYPE_UNKNOWN)
1044 aContentType = INetContentTypes::GetContentType(eContentType);
1048 // If something didn't work, we create an empty MemoryStream
1049 if( !pStream )
1050 pStream = new SvMemoryStream;
1053 // Create part as MessageChild
1054 INetMIMEMessage* pChild = new INetMIMEMessage;
1057 // Header
1058 OUStringBuffer aContentDisp;
1059 aContentDisp.append("form-data; name=\"");
1060 aContentDisp.append(rName);
1061 aContentDisp.append('\"');
1062 aContentDisp.append("; filename=\"");
1063 aContentDisp.append(aFileName);
1064 aContentDisp.append('\"');
1065 pChild->SetContentDisposition(aContentDisp.makeStringAndClear());
1066 pChild->SetContentType( aContentType );
1067 pChild->SetContentTransferEncoding(OUString("8bit"));
1070 // Body
1071 pChild->SetDocumentLB( new SvLockBytes(pStream, true) );
1072 rParent.AttachChild( *pChild );
1074 return true;
1078 // internals
1080 void ODatabaseForm::onError( const SQLErrorEvent& _rEvent )
1082 m_aErrorListeners.notifyEach( &XSQLErrorListener::errorOccured, _rEvent );
1086 void ODatabaseForm::onError( const SQLException& _rException, const OUString& _rContextDescription )
1088 if ( !m_aErrorListeners.getLength() )
1089 return;
1091 SQLErrorEvent aEvent( *this, makeAny( prependErrorInfo( _rException, *this, _rContextDescription ) ) );
1092 onError( aEvent );
1096 void ODatabaseForm::updateParameterInfo()
1098 m_aParameterManager.updateParameterInfo( m_aFilterManager );
1102 bool ODatabaseForm::hasValidParent() const
1104 // do we have to fill the parameters again?
1105 if (m_bSubForm)
1107 Reference<XResultSet> xResultSet(m_xParent, UNO_QUERY);
1108 if (!xResultSet.is())
1110 OSL_FAIL("ODatabaseForm::hasValidParent() : no parent resultset !");
1111 return false;
1115 Reference< XPropertySet > xSet( m_xParent, UNO_QUERY );
1116 Reference< XLoadable > xLoad( m_xParent, UNO_QUERY );
1117 if ( xLoad->isLoaded()
1118 && ( xResultSet->isBeforeFirst()
1119 || xResultSet->isAfterLast()
1120 || getBOOL( xSet->getPropertyValue( PROPERTY_ISNEW ) )
1123 // the parent form is loaded and on a "virtual" row -> not valid
1124 return false;
1126 catch(const Exception&)
1128 // parent could be forwardonly?
1129 return false;
1132 return true;
1136 bool ODatabaseForm::fillParameters( ::osl::ResettableMutexGuard& _rClearForNotifies, const Reference< XInteractionHandler >& _rxCompletionHandler )
1138 // do we have to fill the parameters again?
1139 if ( !m_aParameterManager.isUpToDate() )
1140 updateParameterInfo();
1142 // is there a valid parent?
1143 if ( m_bSubForm && !hasValidParent() )
1144 return true;
1146 // ensure we're connected
1147 if ( !implEnsureConnection() )
1148 return false;
1150 if ( m_aParameterManager.isUpToDate() )
1151 return m_aParameterManager.fillParameterValues( _rxCompletionHandler, _rClearForNotifies );
1153 return true;
1157 void ODatabaseForm::saveInsertOnlyState( )
1159 OSL_ENSURE( !m_aIgnoreResult.hasValue(), "ODatabaseForm::saveInsertOnlyState: overriding old value!" );
1160 m_aIgnoreResult = m_xAggregateSet->getPropertyValue( PROPERTY_INSERTONLY );
1164 void ODatabaseForm::restoreInsertOnlyState( )
1166 if ( m_aIgnoreResult.hasValue() )
1168 m_xAggregateSet->setPropertyValue( PROPERTY_INSERTONLY, m_aIgnoreResult );
1169 m_aIgnoreResult = Any();
1174 bool ODatabaseForm::executeRowSet(::osl::ResettableMutexGuard& _rClearForNotifies, bool bMoveToFirst, const Reference< XInteractionHandler >& _rxCompletionHandler)
1176 if (!m_xAggregateAsRowSet.is())
1177 return false;
1179 if (!fillParameters(_rClearForNotifies, _rxCompletionHandler))
1180 return false;
1182 restoreInsertOnlyState( );
1184 // ensure the aggregated row set has the correct properties
1185 sal_Int32 nConcurrency = ResultSetConcurrency::READ_ONLY;
1187 // if we have a parent, who is not positioned on a valid row
1188 // we can't be updatable!
1189 if (m_bSubForm && !hasValidParent())
1191 nConcurrency = ResultSetConcurrency::READ_ONLY;
1193 // don't use any parameters if we don't have a valid parent
1194 m_aParameterManager.setAllParametersNull();
1196 // switch to "insert only" mode
1197 saveInsertOnlyState( );
1198 m_xAggregateSet->setPropertyValue( PROPERTY_INSERTONLY, makeAny( sal_True ) );
1200 else if (m_bAllowInsert || m_bAllowUpdate || m_bAllowDelete)
1201 nConcurrency = ResultSetConcurrency::UPDATABLE;
1202 else
1203 nConcurrency = ResultSetConcurrency::READ_ONLY;
1205 m_xAggregateSet->setPropertyValue( PROPERTY_RESULTSET_CONCURRENCY, makeAny( (sal_Int32)nConcurrency ) );
1206 m_xAggregateSet->setPropertyValue( PROPERTY_RESULTSET_TYPE, makeAny( (sal_Int32)ResultSetType::SCROLL_SENSITIVE ) );
1208 bool bSuccess = false;
1211 m_xAggregateAsRowSet->execute();
1212 bSuccess = true;
1214 catch(const RowSetVetoException&)
1217 catch(const SQLException& eDb)
1219 _rClearForNotifies.clear();
1220 if (!m_sCurrentErrorContext.isEmpty())
1221 onError(eDb, m_sCurrentErrorContext);
1222 else
1223 onError(eDb, FRM_RES_STRING(RID_STR_READERROR));
1224 _rClearForNotifies.reset();
1226 restoreInsertOnlyState( );
1229 if (bSuccess)
1231 // adjust the privilege property
1232 // m_nPrivileges;
1233 m_xAggregateSet->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
1234 if (!m_bAllowInsert)
1235 m_nPrivileges &= ~Privilege::INSERT;
1236 if (!m_bAllowUpdate)
1237 m_nPrivileges &= ~Privilege::UPDATE;
1238 if (!m_bAllowDelete)
1239 m_nPrivileges &= ~Privilege::DELETE;
1241 if (bMoveToFirst)
1243 // the row set is positioned _before_ the first row (per definitionem), so move the set ...
1246 // if we have an insert only rowset we move to the insert row
1247 next();
1248 if (((m_nPrivileges & Privilege::INSERT) == Privilege::INSERT)
1249 && isAfterLast())
1251 // move on the insert row of set
1252 // resetting must be done later, after the load events have been posted
1253 // see: moveToInsertRow and load , reload
1254 Reference<XResultSetUpdate> xUpdate;
1255 if (query_aggregation( m_xAggregate, xUpdate))
1256 xUpdate->moveToInsertRow();
1259 catch(const SQLException& eDB)
1261 _rClearForNotifies.clear();
1262 if (!m_sCurrentErrorContext.isEmpty())
1263 onError(eDB, m_sCurrentErrorContext);
1264 else
1265 onError(eDB, FRM_RES_STRING(RID_STR_READERROR));
1266 _rClearForNotifies.reset();
1267 bSuccess = false;
1271 return bSuccess;
1275 void ODatabaseForm::disposing()
1277 if (m_pAggregatePropertyMultiplexer)
1278 m_pAggregatePropertyMultiplexer->dispose();
1280 if (m_bLoaded)
1281 unload();
1283 // cancel the submit/reset-thread
1285 ::osl::MutexGuard aGuard( m_aMutex );
1286 if (m_pThread)
1288 m_pThread->release();
1289 m_pThread = NULL;
1293 EventObject aEvt(static_cast<XWeak*>(this));
1294 m_aLoadListeners.disposeAndClear(aEvt);
1295 m_aRowSetApproveListeners.disposeAndClear(aEvt);
1296 m_aResetListeners.disposing();
1297 m_aSubmitListeners.disposeAndClear(aEvt);
1298 m_aErrorListeners.disposeAndClear(aEvt);
1300 m_aParameterManager.dispose(); // To free any references it may have to be me
1301 m_aFilterManager.dispose(); // (dito)
1303 OFormComponents::disposing();
1304 OPropertySetAggregationHelper::disposing();
1306 // stop listening on the aggregate
1307 if (m_xAggregateAsRowSet.is())
1308 m_xAggregateAsRowSet->removeRowSetListener(this);
1310 // dispose the active connection
1311 Reference<XComponent> xAggregationComponent;
1312 if (query_aggregation(m_xAggregate, xAggregationComponent))
1313 xAggregationComponent->dispose();
1315 m_aPropertyBagHelper.dispose();
1319 Reference< XConnection > ODatabaseForm::getConnection()
1321 Reference< XConnection > xConn;
1322 m_xAggregateSet->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConn;
1323 return xConn;
1327 ::osl::Mutex& ODatabaseForm::getMutex()
1329 return m_aMutex;
1333 // property handling
1335 void ODatabaseForm::describeFixedAndAggregateProperties(
1336 Sequence< Property >& _rProps,
1337 Sequence< Property >& _rAggregateProps ) const
1339 BEGIN_DESCRIBE_AGGREGATION_PROPERTIES(22, m_xAggregateSet)
1340 // we want to "override" the privileges, since we have additional "AllowInsert" etc. properties
1341 RemoveProperty( _rAggregateProps, PROPERTY_PRIVILEGES );
1343 // InsertOnly is also to be overridden, since we sometimes change it ourself
1344 RemoveProperty( _rAggregateProps, PROPERTY_INSERTONLY );
1346 // we remove and re-declare the DataSourceName property, 'cause we want it to be constrained, and the
1347 // original property of our aggregate isn't
1348 RemoveProperty( _rAggregateProps, PROPERTY_DATASOURCE );
1350 // for connection sharing, we need to override the ActiveConnection property, too
1351 RemoveProperty( _rAggregateProps, PROPERTY_ACTIVE_CONNECTION );
1353 // the Filter property is also overwritten, since we have some implicit filters
1354 // (e.g. the ones which result from linking master fields to detail fields
1355 // via column names instead of parameters)
1356 RemoveProperty( _rAggregateProps, PROPERTY_FILTER );
1357 RemoveProperty( _rAggregateProps, PROPERTY_APPLYFILTER );
1359 DECL_IFACE_PROP4(ACTIVE_CONNECTION, XConnection, BOUND, TRANSIENT, MAYBEVOID, CONSTRAINED);
1360 DECL_BOOL_PROP2 ( APPLYFILTER, BOUND, MAYBEDEFAULT );
1361 DECL_PROP1 ( NAME, OUString, BOUND );
1362 DECL_PROP1 ( MASTERFIELDS, Sequence< OUString >, BOUND );
1363 DECL_PROP1 ( DETAILFIELDS, Sequence< OUString >, BOUND );
1364 DECL_PROP2 ( DATASOURCE, OUString, BOUND, CONSTRAINED );
1365 DECL_PROP3 ( CYCLE, TabulatorCycle, BOUND, MAYBEVOID, MAYBEDEFAULT );
1366 DECL_PROP2 ( FILTER, OUString, BOUND, MAYBEDEFAULT );
1367 DECL_BOOL_PROP2 ( INSERTONLY, BOUND, MAYBEDEFAULT );
1368 DECL_PROP1 ( NAVIGATION, NavigationBarMode, BOUND );
1369 DECL_BOOL_PROP1 ( ALLOWADDITIONS, BOUND );
1370 DECL_BOOL_PROP1 ( ALLOWEDITS, BOUND );
1371 DECL_BOOL_PROP1 ( ALLOWDELETIONS, BOUND );
1372 DECL_PROP2 ( PRIVILEGES, sal_Int32, TRANSIENT, READONLY );
1373 DECL_PROP1 ( TARGET_URL, OUString, BOUND );
1374 DECL_PROP1 ( TARGET_FRAME, OUString, BOUND );
1375 DECL_PROP1 ( SUBMIT_METHOD, FormSubmitMethod, BOUND );
1376 DECL_PROP1 ( SUBMIT_ENCODING, FormSubmitEncoding, BOUND );
1377 DECL_BOOL_PROP3 ( DYNAMIC_CONTROL_BORDER, BOUND, MAYBEVOID, MAYBEDEFAULT );
1378 DECL_PROP3 ( CONTROL_BORDER_COLOR_FOCUS, sal_Int32, BOUND, MAYBEVOID, MAYBEDEFAULT );
1379 DECL_PROP3 ( CONTROL_BORDER_COLOR_MOUSE, sal_Int32, BOUND, MAYBEVOID, MAYBEDEFAULT );
1380 DECL_PROP3 ( CONTROL_BORDER_COLOR_INVALID, sal_Int32, BOUND, MAYBEVOID, MAYBEDEFAULT );
1381 END_DESCRIBE_PROPERTIES();
1385 Reference< XMultiPropertySet > ODatabaseForm::getPropertiesInterface()
1387 return Reference< XMultiPropertySet >( *this, UNO_QUERY );
1391 ::cppu::IPropertyArrayHelper& ODatabaseForm::getInfoHelper()
1393 return m_aPropertyBagHelper.getInfoHelper();
1397 Reference< XPropertySetInfo > ODatabaseForm::getPropertySetInfo() throw( RuntimeException, std::exception )
1399 return createPropertySetInfo( getInfoHelper() );
1403 void SAL_CALL ODatabaseForm::addProperty( const OUString& _rName, ::sal_Int16 _nAttributes, const Any& _rInitialValue ) throw (PropertyExistException, IllegalTypeException, IllegalArgumentException, RuntimeException, std::exception)
1405 m_aPropertyBagHelper.addProperty( _rName, _nAttributes, _rInitialValue );
1409 void SAL_CALL ODatabaseForm::removeProperty( const OUString& _rName ) throw (UnknownPropertyException, NotRemoveableException, RuntimeException, std::exception)
1411 m_aPropertyBagHelper.removeProperty( _rName );
1415 Sequence< PropertyValue > SAL_CALL ODatabaseForm::getPropertyValues() throw (RuntimeException, std::exception)
1417 return m_aPropertyBagHelper.getPropertyValues();
1421 void SAL_CALL ODatabaseForm::setPropertyValues( const Sequence< PropertyValue >& _rProps ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException, std::exception)
1423 m_aPropertyBagHelper.setPropertyValues( _rProps );
1427 Any SAL_CALL ODatabaseForm::getWarnings( ) throw (SQLException, RuntimeException, std::exception)
1429 return m_aWarnings.getWarnings();
1433 void SAL_CALL ODatabaseForm::clearWarnings( ) throw (SQLException, RuntimeException, std::exception)
1435 m_aWarnings.clearWarnings();
1439 Reference< XCloneable > SAL_CALL ODatabaseForm::createClone( ) throw (RuntimeException, std::exception)
1441 ODatabaseForm* pClone = new ODatabaseForm( *this );
1442 osl_atomic_increment( &pClone->m_refCount );
1443 pClone->clonedFrom( *this );
1444 osl_atomic_decrement( &pClone->m_refCount );
1445 return pClone;
1449 void ODatabaseForm::fire( sal_Int32* pnHandles, const Any* pNewValues, const Any* pOldValues, sal_Int32 nCount, bool bVetoable )
1451 // same as in getFastPropertyValue(sal_Int32) : if we're resetting currently don't fire any changes of the
1452 // IsModified property from sal_False to sal_True, as this is only temporary 'til the reset is done
1453 if (m_nResetsPending > 0)
1455 // look for the PROPERTY_ID_ISMODIFIED
1456 sal_Int32 nPos = 0;
1457 for (nPos=0; nPos<nCount; ++nPos)
1458 if (pnHandles[nPos] == PROPERTY_ID_ISMODIFIED)
1459 break;
1461 if ((nPos < nCount) && (pNewValues[nPos].getValueType().getTypeClass() == TypeClass_BOOLEAN) && getBOOL(pNewValues[nPos]))
1462 { // yeah, we found it, and it changed to TRUE
1463 if (nPos == 0)
1464 { // just cut the first element
1465 ++pnHandles;
1466 ++pNewValues;
1467 ++pOldValues;
1468 --nCount;
1470 else if (nPos == nCount - 1)
1471 // just cut the last element
1472 --nCount;
1473 else
1474 { // split into two base class calls
1475 OPropertySetAggregationHelper::fire(pnHandles, pNewValues, pOldValues, nPos, bVetoable);
1476 ++nPos;
1477 OPropertySetAggregationHelper::fire(pnHandles + nPos, pNewValues + nPos, pOldValues + nPos, nCount - nPos, bVetoable);
1478 return;
1483 OPropertySetAggregationHelper::fire(pnHandles, pNewValues, pOldValues, nCount, bVetoable);
1487 Any SAL_CALL ODatabaseForm::getFastPropertyValue( sal_Int32 nHandle )
1488 throw(UnknownPropertyException, WrappedTargetException, RuntimeException, std::exception)
1490 if ((nHandle == PROPERTY_ID_ISMODIFIED) && (m_nResetsPending > 0))
1491 return css::uno::Any(false);
1492 // don't allow the aggregate which is currently being reset to return a (temporary) "yes"
1493 else
1494 return OPropertySetAggregationHelper::getFastPropertyValue(nHandle);
1498 void ODatabaseForm::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
1500 switch (nHandle)
1502 case PROPERTY_ID_INSERTONLY:
1503 rValue <<= m_bInsertOnly;
1504 break;
1506 case PROPERTY_ID_FILTER:
1507 rValue <<= m_aFilterManager.getFilterComponent( FilterManager::fcPublicFilter );
1508 break;
1510 case PROPERTY_ID_APPLYFILTER:
1511 rValue <<= m_aFilterManager.isApplyPublicFilter();
1512 break;
1514 case PROPERTY_ID_DATASOURCE:
1515 rValue = m_xAggregateSet->getPropertyValue( PROPERTY_DATASOURCE );
1516 break;
1518 case PROPERTY_ID_TARGET_URL:
1519 rValue <<= m_aTargetURL;
1520 break;
1521 case PROPERTY_ID_TARGET_FRAME:
1522 rValue <<= m_aTargetFrame;
1523 break;
1524 case PROPERTY_ID_SUBMIT_METHOD:
1525 rValue <<= m_eSubmitMethod;
1526 break;
1527 case PROPERTY_ID_SUBMIT_ENCODING:
1528 rValue <<= m_eSubmitEncoding;
1529 break;
1530 case PROPERTY_ID_NAME:
1531 rValue <<= m_sName;
1532 break;
1533 case PROPERTY_ID_MASTERFIELDS:
1534 rValue <<= m_aMasterFields;
1535 break;
1536 case PROPERTY_ID_DETAILFIELDS:
1537 rValue <<= m_aDetailFields;
1538 break;
1539 case PROPERTY_ID_CYCLE:
1540 rValue = m_aCycle;
1541 break;
1542 case PROPERTY_ID_NAVIGATION:
1543 rValue <<= m_eNavigation;
1544 break;
1545 case PROPERTY_ID_ALLOWADDITIONS:
1546 rValue <<= m_bAllowInsert;
1547 break;
1548 case PROPERTY_ID_ALLOWEDITS:
1549 rValue <<= m_bAllowUpdate;
1550 break;
1551 case PROPERTY_ID_ALLOWDELETIONS:
1552 rValue <<= m_bAllowDelete;
1553 break;
1554 case PROPERTY_ID_PRIVILEGES:
1555 rValue <<= (sal_Int32)m_nPrivileges;
1556 break;
1557 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1558 rValue = m_aDynamicControlBorder;
1559 break;
1560 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1561 rValue = m_aControlBorderColorFocus;
1562 break;
1563 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1564 rValue = m_aControlBorderColorMouse;
1565 break;
1566 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1567 rValue = m_aControlBorderColorInvalid;
1568 break;
1569 default:
1570 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( nHandle ) )
1571 m_aPropertyBagHelper.getDynamicFastPropertyValue( nHandle, rValue );
1572 else
1573 OPropertySetAggregationHelper::getFastPropertyValue( rValue, nHandle );
1574 break;
1579 sal_Bool ODatabaseForm::convertFastPropertyValue( Any& rConvertedValue, Any& rOldValue,
1580 sal_Int32 nHandle, const Any& rValue ) throw( IllegalArgumentException )
1582 bool bModified(false);
1583 switch (nHandle)
1585 case PROPERTY_ID_INSERTONLY:
1586 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_bInsertOnly );
1587 break;
1589 case PROPERTY_ID_FILTER:
1590 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aFilterManager.getFilterComponent( FilterManager::fcPublicFilter ) );
1591 break;
1593 case PROPERTY_ID_APPLYFILTER:
1594 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aFilterManager.isApplyPublicFilter() );
1595 break;
1597 case PROPERTY_ID_DATASOURCE:
1599 Any aAggregateProperty;
1600 getFastPropertyValue(aAggregateProperty, PROPERTY_ID_DATASOURCE);
1601 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, aAggregateProperty, cppu::UnoType<OUString>::get());
1603 break;
1604 case PROPERTY_ID_TARGET_URL:
1605 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aTargetURL);
1606 break;
1607 case PROPERTY_ID_TARGET_FRAME:
1608 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aTargetFrame);
1609 break;
1610 case PROPERTY_ID_SUBMIT_METHOD:
1611 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_eSubmitMethod);
1612 break;
1613 case PROPERTY_ID_SUBMIT_ENCODING:
1614 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_eSubmitEncoding);
1615 break;
1616 case PROPERTY_ID_NAME:
1617 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_sName);
1618 break;
1619 case PROPERTY_ID_MASTERFIELDS:
1620 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aMasterFields);
1621 break;
1622 case PROPERTY_ID_DETAILFIELDS:
1623 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aDetailFields);
1624 break;
1625 case PROPERTY_ID_CYCLE:
1626 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aCycle, cppu::UnoType<TabulatorCycle>::get());
1627 break;
1628 case PROPERTY_ID_NAVIGATION:
1629 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_eNavigation);
1630 break;
1631 case PROPERTY_ID_ALLOWADDITIONS:
1632 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAllowInsert);
1633 break;
1634 case PROPERTY_ID_ALLOWEDITS:
1635 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAllowUpdate);
1636 break;
1637 case PROPERTY_ID_ALLOWDELETIONS:
1638 bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAllowDelete);
1639 break;
1640 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1641 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aDynamicControlBorder, cppu::UnoType<bool>::get() );
1642 break;
1643 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1644 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aControlBorderColorFocus, cppu::UnoType<sal_Int32>::get() );
1645 break;
1646 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1647 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aControlBorderColorMouse, cppu::UnoType<sal_Int32>::get() );
1648 break;
1649 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1650 bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aControlBorderColorInvalid, cppu::UnoType<sal_Int32>::get() );
1651 break;
1652 default:
1653 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle ( nHandle ) )
1654 bModified = m_aPropertyBagHelper.convertDynamicFastPropertyValue( nHandle, rValue, rConvertedValue, rOldValue );
1655 else
1656 bModified = OPropertySetAggregationHelper::convertFastPropertyValue( rConvertedValue, rOldValue, nHandle, rValue );
1657 break;
1659 return bModified;
1663 void ODatabaseForm::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) throw( Exception, std::exception )
1665 switch (nHandle)
1667 case PROPERTY_ID_INSERTONLY:
1668 rValue >>= m_bInsertOnly;
1669 if ( m_aIgnoreResult.hasValue() )
1670 m_aIgnoreResult <<= m_bInsertOnly;
1671 else
1672 m_xAggregateSet->setPropertyValue( PROPERTY_INSERTONLY, makeAny( m_bInsertOnly ) );
1673 break;
1675 case PROPERTY_ID_FILTER:
1677 OUString sNewFilter;
1678 rValue >>= sNewFilter;
1679 m_aFilterManager.setFilterComponent( FilterManager::fcPublicFilter, sNewFilter );
1681 break;
1683 case PROPERTY_ID_APPLYFILTER:
1685 bool bApply = true;
1686 rValue >>= bApply;
1687 m_aFilterManager.setApplyPublicFilter( bApply );
1689 break;
1691 case PROPERTY_ID_DATASOURCE:
1693 Reference< XConnection > xSomeConnection;
1694 if ( ::dbtools::isEmbeddedInDatabase( getParent(), xSomeConnection ) )
1695 throw PropertyVetoException();
1699 m_xAggregateSet->setPropertyValue(PROPERTY_DATASOURCE, rValue);
1701 catch(const Exception&)
1705 break;
1706 case PROPERTY_ID_TARGET_URL:
1707 rValue >>= m_aTargetURL;
1708 break;
1709 case PROPERTY_ID_TARGET_FRAME:
1710 rValue >>= m_aTargetFrame;
1711 break;
1712 case PROPERTY_ID_SUBMIT_METHOD:
1713 rValue >>= m_eSubmitMethod;
1714 break;
1715 case PROPERTY_ID_SUBMIT_ENCODING:
1716 rValue >>= m_eSubmitEncoding;
1717 break;
1718 case PROPERTY_ID_NAME:
1719 rValue >>= m_sName;
1720 break;
1721 case PROPERTY_ID_MASTERFIELDS:
1722 rValue >>= m_aMasterFields;
1723 invlidateParameters();
1724 break;
1725 case PROPERTY_ID_DETAILFIELDS:
1726 rValue >>= m_aDetailFields;
1727 invlidateParameters();
1728 break;
1729 case PROPERTY_ID_CYCLE:
1730 m_aCycle = rValue;
1731 break;
1732 case PROPERTY_ID_NAVIGATION:
1733 rValue >>= m_eNavigation;
1734 break;
1735 case PROPERTY_ID_ALLOWADDITIONS:
1736 m_bAllowInsert = getBOOL(rValue);
1737 break;
1738 case PROPERTY_ID_ALLOWEDITS:
1739 m_bAllowUpdate = getBOOL(rValue);
1740 break;
1741 case PROPERTY_ID_ALLOWDELETIONS:
1742 m_bAllowDelete = getBOOL(rValue);
1743 break;
1744 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1745 m_aDynamicControlBorder = rValue;
1746 break;
1747 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1748 m_aControlBorderColorFocus = rValue;
1749 break;
1750 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1751 m_aControlBorderColorMouse = rValue;
1752 break;
1753 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1754 m_aControlBorderColorInvalid = rValue;
1755 break;
1757 case PROPERTY_ID_ACTIVE_CONNECTION:
1759 Reference< XConnection > xOuterConnection;
1760 if ( ::dbtools::isEmbeddedInDatabase( getParent(), xOuterConnection ) )
1762 if ( xOuterConnection != Reference< XConnection >( rValue, UNO_QUERY ) )
1763 // somebody's trying to set a connection which is not equal the connection
1764 // implied by the database we're embedded in
1765 throw PropertyVetoException();
1767 OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( nHandle, rValue );
1768 break;
1771 default:
1772 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( nHandle ) )
1773 m_aPropertyBagHelper.setDynamicFastPropertyValue( nHandle, rValue );
1774 else
1775 OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( nHandle, rValue );
1776 break;
1781 void ODatabaseForm::forwardingPropertyValue( sal_Int32 _nHandle )
1783 OSL_ENSURE( _nHandle == PROPERTY_ID_ACTIVE_CONNECTION, "ODatabaseForm::forwardingPropertyValue: unexpected property!" );
1784 if ( _nHandle == PROPERTY_ID_ACTIVE_CONNECTION )
1786 if ( m_bSharingConnection )
1787 stopSharingConnection( );
1788 m_bForwardingConnection = true;
1793 void ODatabaseForm::forwardedPropertyValue( sal_Int32 _nHandle )
1795 OSL_ENSURE( _nHandle == PROPERTY_ID_ACTIVE_CONNECTION, "ODatabaseForm::forwardedPropertyValue: unexpected property!" );
1796 if ( _nHandle == PROPERTY_ID_ACTIVE_CONNECTION )
1798 m_bForwardingConnection = false;
1803 // com::sun::star::beans::XPropertyState
1805 PropertyState ODatabaseForm::getPropertyStateByHandle(sal_Int32 nHandle)
1807 PropertyState eState;
1808 switch (nHandle)
1810 case PROPERTY_ID_NAVIGATION:
1811 return (NavigationBarMode_CURRENT == m_eNavigation) ? PropertyState_DEFAULT_VALUE : PropertyState_DIRECT_VALUE;
1813 case PROPERTY_ID_CYCLE:
1814 eState = m_aCycle.hasValue() ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1815 break;
1817 case PROPERTY_ID_INSERTONLY:
1818 eState = m_bInsertOnly ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1819 break;
1821 case PROPERTY_ID_FILTER:
1822 if ( m_aFilterManager.getFilterComponent( FilterManager::fcPublicFilter ).isEmpty() )
1823 eState = PropertyState_DEFAULT_VALUE;
1824 else
1825 eState = PropertyState_DIRECT_VALUE;
1826 break;
1828 case PROPERTY_ID_APPLYFILTER:
1829 eState = m_aFilterManager.isApplyPublicFilter() ? PropertyState_DEFAULT_VALUE : PropertyState_DIRECT_VALUE;
1830 break;
1832 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1833 eState = m_aDynamicControlBorder.hasValue() ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1834 break;
1836 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1837 eState = m_aControlBorderColorFocus.hasValue() ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1838 break;
1840 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1841 eState = m_aControlBorderColorMouse.hasValue() ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1842 break;
1844 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1845 eState = m_aControlBorderColorInvalid.hasValue() ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1846 break;
1848 default:
1849 eState = OPropertySetAggregationHelper::getPropertyStateByHandle(nHandle);
1851 return eState;
1855 void ODatabaseForm::setPropertyToDefaultByHandle(sal_Int32 nHandle)
1857 switch (nHandle)
1859 case PROPERTY_ID_INSERTONLY:
1860 case PROPERTY_ID_FILTER:
1861 case PROPERTY_ID_APPLYFILTER:
1862 case PROPERTY_ID_NAVIGATION:
1863 case PROPERTY_ID_CYCLE:
1864 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1865 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1866 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1867 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1868 setFastPropertyValue( nHandle, getPropertyDefaultByHandle( nHandle ) );
1869 break;
1871 default:
1872 OPropertySetAggregationHelper::setPropertyToDefaultByHandle(nHandle);
1877 Any ODatabaseForm::getPropertyDefaultByHandle( sal_Int32 nHandle ) const
1879 Any aReturn;
1880 switch (nHandle)
1882 case PROPERTY_ID_INSERTONLY:
1883 case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
1884 aReturn <<= sal_False;
1885 break;
1887 case PROPERTY_ID_FILTER:
1888 aReturn <<= OUString();
1889 break;
1891 case PROPERTY_ID_APPLYFILTER:
1892 aReturn <<= sal_True;
1893 break;
1895 case PROPERTY_ID_NAVIGATION:
1896 aReturn = makeAny(NavigationBarMode_CURRENT);
1897 break;
1899 case PROPERTY_ID_CYCLE:
1900 case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
1901 case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
1902 case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
1903 break;
1905 default:
1906 if ( m_aPropertyBagHelper.hasDynamicPropertyByHandle( nHandle ) )
1907 m_aPropertyBagHelper.getDynamicPropertyDefaultByHandle( nHandle, aReturn );
1908 else
1909 aReturn = OPropertySetAggregationHelper::getPropertyDefaultByHandle( nHandle );
1910 break;
1912 return aReturn;
1916 // com::sun::star::form::XReset
1918 void SAL_CALL ODatabaseForm::reset() throw( RuntimeException, std::exception )
1920 ::osl::ResettableMutexGuard aGuard(m_aMutex);
1922 if (isLoaded())
1924 ::osl::MutexGuard aResetGuard(m_aResetSafety);
1925 ++m_nResetsPending;
1926 reset_impl(true);
1927 return;
1930 if ( !m_aResetListeners.empty() )
1932 ::osl::MutexGuard aResetGuard(m_aResetSafety);
1933 ++m_nResetsPending;
1934 // create an own thread if we have (approve-)reset-listeners (so the listeners can't do that much damage
1935 // to this thread which is probably the main one)
1936 if (!m_pThread)
1938 m_pThread = new OFormSubmitResetThread(this);
1939 m_pThread->acquire();
1940 m_pThread->create();
1942 EventObject aEvt;
1943 m_pThread->addEvent(&aEvt, false);
1945 else
1947 // direct call without any approving by the listeners
1948 aGuard.clear();
1950 ::osl::MutexGuard aResetGuard(m_aResetSafety);
1951 ++m_nResetsPending;
1952 reset_impl(false);
1957 void ODatabaseForm::reset_impl(bool _bAproveByListeners)
1959 if ( _bAproveByListeners )
1960 if ( !m_aResetListeners.approveReset() )
1961 return;
1963 ::osl::ResettableMutexGuard aResetGuard(m_aResetSafety);
1964 // do we have a database connected form and stay on the insert row
1965 bool bInsertRow = false;
1966 if (m_xAggregateSet.is())
1967 bInsertRow = getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_ISNEW));
1968 if (bInsertRow)
1972 // Iterate through all columns and set the default value
1973 Reference< XColumnsSupplier > xColsSuppl( m_xAggregateSet, UNO_QUERY );
1974 Reference< XIndexAccess > xIndexCols( xColsSuppl->getColumns(), UNO_QUERY );
1975 for (sal_Int32 i = 0; i < xIndexCols->getCount(); ++i)
1977 Reference< XPropertySet > xColProps;
1978 xIndexCols->getByIndex(i) >>= xColProps;
1980 Reference< XColumnUpdate > xColUpdate( xColProps, UNO_QUERY );
1981 if ( !xColUpdate.is() )
1982 continue;
1984 Reference< XPropertySetInfo > xPSI;
1985 if ( xColProps.is() )
1986 xPSI = xColProps->getPropertySetInfo( );
1988 static const char PROPERTY_CONTROLDEFAULT[] = "ControlDefault";
1989 if ( xPSI.is() && xPSI->hasPropertyByName( PROPERTY_CONTROLDEFAULT ) )
1991 Any aDefault = xColProps->getPropertyValue( PROPERTY_CONTROLDEFAULT );
1993 bool bReadOnly = false;
1994 if ( xPSI->hasPropertyByName( PROPERTY_ISREADONLY ) )
1995 xColProps->getPropertyValue( PROPERTY_ISREADONLY ) >>= bReadOnly;
1997 if ( !bReadOnly )
2001 if ( aDefault.hasValue() )
2002 xColUpdate->updateObject( aDefault );
2004 catch(const Exception&)
2006 DBG_UNHANDLED_EXCEPTION();
2012 catch(const Exception&)
2016 if (m_bSubForm)
2018 Reference< XColumnsSupplier > xParentColSupp( m_xParent, UNO_QUERY );
2019 Reference< XNameAccess > xParentCols;
2020 if ( xParentColSupp.is() )
2021 xParentCols = xParentColSupp->getColumns();
2023 if ( xParentCols.is() && xParentCols->hasElements() && m_aMasterFields.getLength() )
2027 // analyze our parameters
2028 if ( !m_aParameterManager.isUpToDate() )
2029 updateParameterInfo();
2031 m_aParameterManager.resetParameterValues( );
2033 catch(const Exception&)
2035 OSL_FAIL("ODatabaseForm::reset_impl: could not initialize the master-detail-driven parameters!");
2041 aResetGuard.clear();
2042 // iterate through all components. don't use an XIndexAccess as this will cause massive
2043 // problems with the count.
2044 Reference<XEnumeration> xIter = createEnumeration();
2045 while (xIter->hasMoreElements())
2047 Reference<XReset> xReset;
2048 xIter->nextElement() >>= xReset;
2049 if (xReset.is())
2051 // TODO: all reset-methods have to be thread-safe
2052 xReset->reset();
2056 aResetGuard.reset();
2057 // ensure that the row isn't modified
2058 // (do this _before_ the listeners are notified ! their reaction (maybe asynchronous) may depend
2059 // on the modified state of the row)
2060 if (bInsertRow)
2061 m_xAggregateSet->setPropertyValue(PROPERTY_ISMODIFIED, css::uno::Any(false));
2063 aResetGuard.clear();
2065 m_aResetListeners.resetted();
2068 aResetGuard.reset();
2069 // and again : ensure the row isn't modified
2070 // we already did this after we (and maybe our dependents) resetted the values, but the listeners may have changed the row, too
2071 if (bInsertRow)
2072 m_xAggregateSet->setPropertyValue(PROPERTY_ISMODIFIED, css::uno::Any(false));
2074 --m_nResetsPending;
2078 void SAL_CALL ODatabaseForm::addResetListener(const Reference<XResetListener>& _rListener) throw( RuntimeException, std::exception )
2080 m_aResetListeners.addTypedListener( _rListener );
2084 void SAL_CALL ODatabaseForm::removeResetListener(const Reference<XResetListener>& _rListener) throw( RuntimeException, std::exception )
2086 m_aResetListeners.removeTypedListener( _rListener );
2090 // com::sun::star::form::XSubmit
2092 void SAL_CALL ODatabaseForm::submit( const Reference<XControl>& Control,
2093 const ::com::sun::star::awt::MouseEvent& MouseEvt ) throw( RuntimeException, std::exception )
2096 ::osl::MutexGuard aGuard(m_aMutex);
2097 // Do we have controls and a Submit URL?
2098 if( !getCount() || m_aTargetURL.isEmpty() )
2099 return;
2102 ::osl::ClearableMutexGuard aGuard(m_aMutex);
2103 if (m_aSubmitListeners.getLength())
2105 // create an own thread if we have (approve-)submit-listeners (so the listeners can't do that much damage
2106 // to this thread which is probably the main one)
2107 if (!m_pThread)
2109 m_pThread = new OFormSubmitResetThread(this);
2110 m_pThread->acquire();
2111 m_pThread->create();
2113 m_pThread->addEvent(&MouseEvt, Control, true);
2115 else
2117 // direct call without any approving by the listeners
2118 aGuard.clear();
2119 submit_impl( Control, MouseEvt, true );
2123 void lcl_dispatch(const Reference< XFrame >& xFrame,const Reference<XURLTransformer>& xTransformer,const OUString& aURLStr,const OUString& aReferer,const OUString& aTargetName
2124 ,const OUString& aData,rtl_TextEncoding _eEncoding)
2126 URL aURL;
2127 aURL.Complete = aURLStr;
2128 xTransformer->parseStrict(aURL);
2130 Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY)->queryDispatch(aURL, aTargetName,
2131 FrameSearchFlag::SELF | FrameSearchFlag::PARENT | FrameSearchFlag::CHILDREN |
2132 FrameSearchFlag::SIBLINGS | FrameSearchFlag::CREATE | FrameSearchFlag::TASKS);
2134 if (xDisp.is())
2136 Sequence<PropertyValue> aArgs(2);
2137 aArgs.getArray()[0].Name = "Referer";
2138 aArgs.getArray()[0].Value <<= aReferer;
2140 // build a sequence from the to-be-submitted string
2141 OString a8BitData(OUStringToOString(aData, _eEncoding));
2142 // always ANSI #58641
2143 Sequence< sal_Int8 > aPostData(reinterpret_cast<const sal_Int8*>(a8BitData.getStr()), a8BitData.getLength());
2144 Reference< XInputStream > xPostData = new SequenceInputStream(aPostData);
2146 aArgs.getArray()[1].Name = "PostData";
2147 aArgs.getArray()[1].Value <<= xPostData;
2149 xDisp->dispatch(aURL, aArgs);
2150 } // if (xDisp.is())
2153 void ODatabaseForm::submit_impl(const Reference<XControl>& Control, const ::com::sun::star::awt::MouseEvent& MouseEvt, bool _bAproveByListeners)
2156 if (_bAproveByListeners)
2158 ::cppu::OInterfaceIteratorHelper aIter(m_aSubmitListeners);
2159 EventObject aEvt(static_cast<XWeak*>(this));
2160 bool bCanceled = false;
2161 while (aIter.hasMoreElements() && !bCanceled)
2163 if (!static_cast<XSubmitListener*>(aIter.next())->approveSubmit(aEvt))
2164 bCanceled = true;
2167 if (bCanceled)
2168 return;
2171 FormSubmitEncoding eSubmitEncoding;
2172 FormSubmitMethod eSubmitMethod;
2173 OUString aURLStr;
2174 OUString aReferer;
2175 OUString aTargetName;
2176 Reference< XModel > xModel;
2178 SolarMutexGuard aGuard;
2179 // starform->Forms
2181 Reference<XChild> xParent(m_xParent, UNO_QUERY);
2183 if (xParent.is())
2184 xModel = getXModel(xParent->getParent());
2186 if (xModel.is())
2187 aReferer = xModel->getURL();
2189 // TargetItem
2190 aTargetName = m_aTargetFrame;
2192 eSubmitEncoding = m_eSubmitEncoding;
2193 eSubmitMethod = m_eSubmitMethod;
2194 aURLStr = m_aTargetURL;
2197 if (!xModel.is())
2198 return;
2199 Reference< XFrame > xFrame = xModel->getCurrentController()->getFrame();
2200 if (!xFrame.is())
2201 return;
2203 Reference<XURLTransformer> xTransformer(URLTransformer::create(m_xContext));
2205 // URL encoding
2206 if( eSubmitEncoding == FormSubmitEncoding_URL )
2208 OUString aData;
2210 SolarMutexGuard aGuard;
2211 aData = GetDataURLEncoded( Control, MouseEvt );
2214 URL aURL;
2215 // FormMethod GET
2216 if( eSubmitMethod == FormSubmitMethod_GET )
2218 INetURLObject aUrlObj( aURLStr, INetURLObject::WAS_ENCODED );
2219 aUrlObj.SetParam( aData, INetURLObject::ENCODE_ALL );
2220 aURL.Complete = aUrlObj.GetMainURL( INetURLObject::DECODE_UNAMBIGUOUS );
2221 if (xTransformer.is())
2222 xTransformer->parseStrict(aURL);
2224 Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY)->queryDispatch(aURL, aTargetName,
2225 FrameSearchFlag::SELF | FrameSearchFlag::PARENT | FrameSearchFlag::CHILDREN |
2226 FrameSearchFlag::SIBLINGS | FrameSearchFlag::CREATE | FrameSearchFlag::TASKS);
2228 if (xDisp.is())
2230 Sequence<PropertyValue> aArgs(1);
2231 aArgs.getArray()->Name = "Referer";
2232 aArgs.getArray()->Value <<= aReferer;
2233 xDisp->dispatch(aURL, aArgs);
2236 // FormMethod POST
2237 else if( eSubmitMethod == FormSubmitMethod_POST )
2239 lcl_dispatch(xFrame,xTransformer,aURLStr,aReferer,aTargetName,aData,RTL_TEXTENCODING_MS_1252);
2242 else if( eSubmitEncoding == FormSubmitEncoding_MULTIPART )
2244 URL aURL;
2245 aURL.Complete = aURLStr;
2246 xTransformer->parseStrict(aURL);
2248 Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY)->queryDispatch(aURL, aTargetName,
2249 FrameSearchFlag::SELF | FrameSearchFlag::PARENT | FrameSearchFlag::CHILDREN |
2250 FrameSearchFlag::SIBLINGS | FrameSearchFlag::CREATE | FrameSearchFlag::TASKS);
2252 if (xDisp.is())
2254 OUString aContentType;
2255 Sequence<sal_Int8> aData;
2257 SolarMutexGuard aGuard;
2258 aData = GetDataMultiPartEncoded(Control, MouseEvt, aContentType);
2260 if (!aData.getLength())
2261 return;
2263 Sequence<PropertyValue> aArgs(3);
2264 aArgs.getArray()[0].Name = "Referer";
2265 aArgs.getArray()[0].Value <<= aReferer;
2266 aArgs.getArray()[1].Name = "ContentType";
2267 aArgs.getArray()[1].Value <<= aContentType;
2269 // build a sequence from the to-be-submitted string
2270 Reference< XInputStream > xPostData = new SequenceInputStream(aData);
2272 aArgs.getArray()[2].Name = "PostData";
2273 aArgs.getArray()[2].Value <<= xPostData;
2275 xDisp->dispatch(aURL, aArgs);
2278 else if( eSubmitEncoding == FormSubmitEncoding_TEXT )
2280 OUString aData;
2282 SolarMutexGuard aGuard;
2283 aData = GetDataTextEncoded( Reference<XControl> (), MouseEvt );
2286 lcl_dispatch(xFrame,xTransformer,aURLStr,aReferer,aTargetName,aData,osl_getThreadTextEncoding());
2288 else {
2289 OSL_FAIL("ODatabaseForm::submit_Impl : wrong encoding !");
2294 // XSubmit
2296 void SAL_CALL ODatabaseForm::addSubmitListener(const Reference<XSubmitListener>& _rListener) throw( RuntimeException, std::exception )
2298 m_aSubmitListeners.addInterface(_rListener);
2302 void SAL_CALL ODatabaseForm::removeSubmitListener(const Reference<XSubmitListener>& _rListener) throw( RuntimeException, std::exception )
2304 m_aSubmitListeners.removeInterface(_rListener);
2308 // com::sun::star::sdbc::XSQLErrorBroadcaster
2310 void SAL_CALL ODatabaseForm::addSQLErrorListener(const Reference<XSQLErrorListener>& _rListener) throw( RuntimeException, std::exception )
2312 m_aErrorListeners.addInterface(_rListener);
2316 void SAL_CALL ODatabaseForm::removeSQLErrorListener(const Reference<XSQLErrorListener>& _rListener) throw( RuntimeException, std::exception )
2318 m_aErrorListeners.removeInterface(_rListener);
2322 void ODatabaseForm::invlidateParameters()
2324 ::osl::MutexGuard aGuard(m_aMutex);
2325 m_aParameterManager.clearAllParameterInformation();
2329 // OChangeListener
2331 void ODatabaseForm::_propertyChanged(const PropertyChangeEvent& evt) throw( RuntimeException )
2333 if (evt.PropertyName == PROPERTY_ACTIVE_CONNECTION && !m_bForwardingConnection)
2335 // the rowset changed its active connection itself (without interaction from our side), so
2336 // we need to fire this event, too
2337 sal_Int32 nHandle = PROPERTY_ID_ACTIVE_CONNECTION;
2338 fire(&nHandle, &evt.NewValue, &evt.OldValue, 1, false);
2340 else // it was one of the statement relevant props
2342 // if the statement has changed we have to delete the parameter info
2343 invlidateParameters();
2348 // smartXChild
2350 void SAL_CALL ODatabaseForm::setParent(const InterfaceRef& Parent) throw ( ::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException, std::exception)
2352 // SYNCHRONIZED ----->
2353 ::osl::ResettableMutexGuard aGuard(m_aMutex);
2355 Reference<XForm> xParentForm(getParent(), UNO_QUERY);
2356 if (xParentForm.is())
2360 Reference< XRowSetApproveBroadcaster > xParentApprBroadcast( xParentForm, UNO_QUERY_THROW );
2361 xParentApprBroadcast->removeRowSetApproveListener( this );
2363 Reference< XLoadable > xParentLoadable( xParentForm, UNO_QUERY_THROW );
2364 xParentLoadable->removeLoadListener( this );
2366 Reference< XPropertySet > xParentProperties( xParentForm, UNO_QUERY_THROW );
2367 xParentProperties->removePropertyChangeListener( PROPERTY_ISNEW, this );
2369 catch(const Exception&)
2371 DBG_UNHANDLED_EXCEPTION();
2375 OFormComponents::setParent(Parent);
2377 xParentForm.set(getParent(), UNO_QUERY);
2378 if ( xParentForm.is() )
2382 Reference< XRowSetApproveBroadcaster > xParentApprBroadcast( xParentForm, UNO_QUERY_THROW );
2383 xParentApprBroadcast->addRowSetApproveListener( this );
2385 Reference< XLoadable > xParentLoadable( xParentForm, UNO_QUERY_THROW );
2386 xParentLoadable->addLoadListener( this );
2388 Reference< XPropertySet > xParentProperties( xParentForm, UNO_QUERY_THROW );
2389 xParentProperties->addPropertyChangeListener( PROPERTY_ISNEW, this );
2391 catch(const Exception&)
2393 DBG_UNHANDLED_EXCEPTION();
2397 Reference< XPropertySet > xAggregateProperties( m_xAggregateSet );
2398 aGuard.clear();
2399 // <----- SYNCHRONIZED
2401 Reference< XConnection > xOuterConnection;
2402 bool bIsEmbedded = ::dbtools::isEmbeddedInDatabase( Parent, xOuterConnection );
2404 if ( bIsEmbedded )
2405 xAggregateProperties->setPropertyValue( PROPERTY_DATASOURCE, makeAny( OUString() ) );
2409 // smartXTabControllerModel
2411 sal_Bool SAL_CALL ODatabaseForm::getGroupControl() throw(com::sun::star::uno::RuntimeException, std::exception)
2413 ::osl::ResettableMutexGuard aGuard(m_aMutex);
2415 // Should controls be combined into a TabOrder group?
2416 if (m_aCycle.hasValue())
2418 sal_Int32 nCycle = 0;
2419 ::cppu::enum2int(nCycle, m_aCycle);
2420 return nCycle != TabulatorCycle_PAGE;
2423 if (isLoaded() && getConnection().is())
2424 return sal_True;
2426 return sal_False;
2430 void SAL_CALL ODatabaseForm::setControlModels(const Sequence<Reference<XControlModel> >& rControls) throw( RuntimeException, std::exception )
2432 ::osl::ResettableMutexGuard aGuard(m_aMutex);
2434 // Set TabIndex in the order of the sequence
2435 const Reference<XControlModel>* pControls = rControls.getConstArray();
2436 sal_Int32 nCount = getCount();
2437 sal_Int32 nNewCount = rControls.getLength();
2439 // HiddenControls and forms are not listed
2440 if (nNewCount <= nCount)
2442 sal_Int16 nTabIndex = 1;
2443 for (sal_Int32 i=0; i < nNewCount; ++i, ++pControls)
2445 Reference<XFormComponent> xComp(*pControls, UNO_QUERY);
2446 if (xComp.is())
2448 // Find component in the list
2449 for (sal_Int32 j = 0; j < nCount; ++j)
2451 Reference<XFormComponent> xElement(
2452 getByIndex(j), css::uno::UNO_QUERY);
2453 if (xComp == xElement)
2455 Reference<XPropertySet> xSet(xComp, UNO_QUERY);
2456 if (xSet.is() && hasProperty(PROPERTY_TABINDEX, xSet))
2457 xSet->setPropertyValue( PROPERTY_TABINDEX, makeAny(nTabIndex++) );
2458 break;
2467 Sequence<Reference<XControlModel> > SAL_CALL ODatabaseForm::getControlModels() throw( RuntimeException, std::exception )
2469 ::osl::MutexGuard aGuard(m_aMutex);
2470 return m_pGroupManager->getControlModels();
2474 void SAL_CALL ODatabaseForm::setGroup( const Sequence<Reference<XControlModel> >& _rGroup, const OUString& Name ) throw( RuntimeException, std::exception )
2476 ::osl::MutexGuard aGuard(m_aMutex);
2478 // The controls are grouped by adjusting their names to the name of the
2479 // first control of the sequence
2480 const Reference<XControlModel>* pControls = _rGroup.getConstArray();
2481 Reference< XPropertySet > xSet;
2482 OUString sGroupName( Name );
2484 for( sal_Int32 i=0; i<_rGroup.getLength(); ++i, ++pControls )
2486 xSet.set(*pControls, css::uno::UNO_QUERY);
2487 if ( !xSet.is() )
2489 // can't throw an exception other than a RuntimeException (which would not be appropriate),
2490 // so we ignore (and only assert) this
2491 OSL_FAIL( "ODatabaseForm::setGroup: invalid arguments!" );
2492 continue;
2495 if (sGroupName.isEmpty())
2496 xSet->getPropertyValue(PROPERTY_NAME) >>= sGroupName;
2497 else
2498 xSet->setPropertyValue(PROPERTY_NAME, makeAny(sGroupName));
2503 sal_Int32 SAL_CALL ODatabaseForm::getGroupCount() throw( RuntimeException, std::exception )
2505 ::osl::MutexGuard aGuard(m_aMutex);
2506 return m_pGroupManager->getGroupCount();
2510 void SAL_CALL ODatabaseForm::getGroup( sal_Int32 nGroup, Sequence<Reference<XControlModel> >& _rGroup, OUString& _rName ) throw( RuntimeException, std::exception )
2512 ::osl::MutexGuard aGuard(m_aMutex);
2513 _rGroup.realloc(0);
2514 _rName.clear();
2516 if ((nGroup < 0) || (nGroup >= m_pGroupManager->getGroupCount()))
2517 return;
2518 m_pGroupManager->getGroup( nGroup, _rGroup, _rName );
2522 void SAL_CALL ODatabaseForm::getGroupByName(const OUString& Name, Sequence< Reference<XControlModel> >& _rGroup) throw( RuntimeException, std::exception )
2524 ::osl::MutexGuard aGuard(m_aMutex);
2525 _rGroup.realloc(0);
2526 m_pGroupManager->getGroupByName( Name, _rGroup );
2530 // com::sun::star::lang::XEventListener
2532 void SAL_CALL ODatabaseForm::disposing(const EventObject& Source) throw( RuntimeException, std::exception )
2534 // does the call come from the connection which we are sharing with our parent?
2535 if ( isSharingConnection() )
2537 Reference< XConnection > xConnSource( Source.Source, UNO_QUERY );
2538 if ( xConnSource.is() )
2540 #if OSL_DEBUG_LEVEL > 0
2541 Reference< XConnection > xActiveConn;
2542 m_xAggregateSet->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xActiveConn;
2543 OSL_ENSURE( xActiveConn.get() == xConnSource.get(), "ODatabaseForm::disposing: where did this come from?" );
2544 // there should be exactly one XConnection object we're listening at - our aggregate connection
2545 #endif
2546 disposingSharedConnection( xConnSource );
2550 OInterfaceContainer::disposing(Source);
2552 // does the disposing come from the aggregate ?
2553 if (m_xAggregate.is())
2554 { // no -> forward it
2555 com::sun::star::uno::Reference<com::sun::star::lang::XEventListener> xListener;
2556 if (query_aggregation(m_xAggregate, xListener))
2557 xListener->disposing(Source);
2562 void ODatabaseForm::impl_createLoadTimer()
2564 OSL_PRECOND( m_pLoadTimer == NULL, "ODatabaseForm::impl_createLoadTimer: timer already exists!" );
2565 m_pLoadTimer = new Timer();
2566 m_pLoadTimer->SetTimeout(100);
2567 m_pLoadTimer->SetTimeoutHdl(LINK(this,ODatabaseForm,OnTimeout));
2571 // com::sun::star::form::XLoadListener
2573 void SAL_CALL ODatabaseForm::loaded(const EventObject& /*aEvent*/) throw( RuntimeException, std::exception )
2576 ::osl::MutexGuard aGuard( m_aMutex );
2577 Reference< XRowSet > xParentRowSet( m_xParent, UNO_QUERY_THROW );
2578 xParentRowSet->addRowSetListener( this );
2580 impl_createLoadTimer();
2583 load_impl( true );
2587 void SAL_CALL ODatabaseForm::unloading(const EventObject& /*aEvent*/) throw( RuntimeException, std::exception )
2590 // now stop the rowset listening if we are a subform
2591 ::osl::MutexGuard aGuard( m_aMutex );
2593 if ( m_pLoadTimer && m_pLoadTimer->IsActive() )
2594 m_pLoadTimer->Stop();
2595 DELETEZ( m_pLoadTimer );
2597 Reference< XRowSet > xParentRowSet( m_xParent, UNO_QUERY_THROW );
2598 xParentRowSet->removeRowSetListener( this );
2601 unload();
2605 void SAL_CALL ODatabaseForm::unloaded(const EventObject& /*aEvent*/) throw( RuntimeException, std::exception )
2607 // nothing to do
2611 void SAL_CALL ODatabaseForm::reloading(const EventObject& /*aEvent*/) throw( RuntimeException, std::exception )
2613 // now stop the rowset listening if we are a subform
2614 ::osl::MutexGuard aGuard(m_aMutex);
2615 Reference<XRowSet> xParentRowSet(m_xParent, UNO_QUERY);
2616 if (xParentRowSet.is())
2617 xParentRowSet->removeRowSetListener(this);
2619 if (m_pLoadTimer && m_pLoadTimer->IsActive())
2620 m_pLoadTimer->Stop();
2624 void SAL_CALL ODatabaseForm::reloaded(const EventObject& /*aEvent*/) throw( RuntimeException, std::exception )
2626 reload_impl(true);
2628 ::osl::MutexGuard aGuard(m_aMutex);
2629 Reference<XRowSet> xParentRowSet(m_xParent, UNO_QUERY);
2630 if (xParentRowSet.is())
2631 xParentRowSet->addRowSetListener(this);
2636 IMPL_LINK_NOARG_TYPED(ODatabaseForm, OnTimeout, Timer *, void)
2638 reload_impl(true);
2642 // com::sun::star::form::XLoadable
2644 void SAL_CALL ODatabaseForm::load() throw( RuntimeException, std::exception )
2646 load_impl(false);
2650 bool ODatabaseForm::canShareConnection( const Reference< XPropertySet >& _rxParentProps )
2652 // our own data source
2653 OUString sOwnDatasource;
2654 m_xAggregateSet->getPropertyValue( PROPERTY_DATASOURCE ) >>= sOwnDatasource;
2656 // our parents data source
2657 OUString sParentDataSource;
2658 OSL_ENSURE( _rxParentProps.is() && _rxParentProps->getPropertySetInfo().is() && _rxParentProps->getPropertySetInfo()->hasPropertyByName( PROPERTY_DATASOURCE ),
2659 "ODatabaseForm::doShareConnection: invalid parent form!" );
2660 if ( _rxParentProps.is() )
2661 _rxParentProps->getPropertyValue( PROPERTY_DATASOURCE ) >>= sParentDataSource;
2663 bool bCanShareConnection = false;
2665 // both rowsets share are connected to the same data source
2666 if ( sParentDataSource == sOwnDatasource )
2668 if ( !sParentDataSource.isEmpty() )
2669 // and it's really a data source name (not empty)
2670 bCanShareConnection = true;
2671 else
2672 { // the data source name is empty
2673 // -> ok for the URL
2674 OUString sParentURL;
2675 OUString sMyURL;
2676 _rxParentProps->getPropertyValue( PROPERTY_URL ) >>= sParentURL;
2677 m_xAggregateSet->getPropertyValue( PROPERTY_URL ) >>= sMyURL;
2679 bCanShareConnection = (sParentURL == sMyURL);
2683 if ( bCanShareConnection )
2685 // check for the user/password
2687 // take the user property on the rowset (if any) into account
2688 OUString sParentUser, sParentPwd;
2689 _rxParentProps->getPropertyValue( PROPERTY_USER ) >>= sParentUser;
2690 _rxParentProps->getPropertyValue( PROPERTY_PASSWORD ) >>= sParentPwd;
2692 OUString sMyUser, sMyPwd;
2693 m_xAggregateSet->getPropertyValue( PROPERTY_USER ) >>= sMyUser;
2694 m_xAggregateSet->getPropertyValue( PROPERTY_PASSWORD ) >>= sMyPwd;
2696 bCanShareConnection =
2697 ( sParentUser == sMyUser )
2698 && ( sParentPwd == sMyPwd );
2701 return bCanShareConnection;
2705 void ODatabaseForm::doShareConnection( const Reference< XPropertySet >& _rxParentProps )
2707 // get the conneciton of the parent
2708 Reference< XConnection > xParentConn;
2709 _rxParentProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xParentConn;
2710 OSL_ENSURE( xParentConn.is(), "ODatabaseForm::doShareConnection: we're a valid sub-form, but the parent has no connection?!" );
2712 if ( xParentConn.is() )
2714 // add as dispose listener to the connection
2715 Reference< XComponent > xParentConnComp( xParentConn, UNO_QUERY );
2716 OSL_ENSURE( xParentConnComp.is(), "ODatabaseForm::doShareConnection: invalid connection!" );
2717 xParentConnComp->addEventListener( static_cast< XLoadListener* >( this ) );
2719 // forward the connection to our own aggregate
2720 m_bForwardingConnection = true;
2721 m_xAggregateSet->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, makeAny( xParentConn ) );
2722 m_bForwardingConnection = false;
2724 m_bSharingConnection = true;
2726 else
2727 m_bSharingConnection = false;
2731 void ODatabaseForm::disposingSharedConnection( const Reference< XConnection >& /*_rxConn*/ )
2733 stopSharingConnection();
2735 // TODO: we could think about whether or not to re-connect.
2736 unload( );
2740 void ODatabaseForm::stopSharingConnection( )
2742 OSL_ENSURE( m_bSharingConnection, "ODatabaseForm::stopSharingConnection: invalid call!" );
2744 if ( m_bSharingConnection )
2746 // get the connection
2747 Reference< XConnection > xSharedConn;
2748 m_xAggregateSet->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xSharedConn;
2749 OSL_ENSURE( xSharedConn.is(), "ODatabaseForm::stopSharingConnection: there's no conn!" );
2751 // remove ourself as event listener
2752 Reference< XComponent > xSharedConnComp( xSharedConn, UNO_QUERY );
2753 if ( xSharedConnComp.is() )
2754 xSharedConnComp->removeEventListener( static_cast< XLoadListener* >( this ) );
2756 // no need to dispose the conn: we're not the owner, this is our parent
2757 // (in addition, this method may be called if the connection is being disposed while we use it)
2759 // reset the property
2760 xSharedConn.clear();
2761 m_bForwardingConnection = true;
2762 m_xAggregateSet->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, makeAny( xSharedConn ) );
2763 m_bForwardingConnection = false;
2765 // reset the flag
2766 m_bSharingConnection = false;
2771 bool ODatabaseForm::implEnsureConnection()
2775 if ( getConnection( ).is() )
2776 // if our aggregate already has a connection, nothing needs to be done about it
2777 return true;
2779 // see whether we're an embedded form
2780 Reference< XConnection > xOuterConnection;
2781 if ( ::dbtools::isEmbeddedInDatabase( getParent(), xOuterConnection ) )
2783 m_xAggregateSet->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, makeAny( xOuterConnection ) );
2784 return xOuterConnection.is();
2787 m_bSharingConnection = false;
2789 // if we're a sub form, we try to re-use the connection of our parent
2790 if (m_bSubForm)
2792 OSL_ENSURE( Reference< XForm >( getParent(), UNO_QUERY ).is(),
2793 "ODatabaseForm::implEnsureConnection: m_bSubForm is TRUE, but the parent is no form?" );
2795 Reference< XPropertySet > xParentProps( getParent(), UNO_QUERY );
2797 // can we re-use (aka share) the connection of the parent?
2798 if ( canShareConnection( xParentProps ) )
2800 // yep -> do it
2801 doShareConnection( xParentProps );
2802 // success?
2803 if ( m_bSharingConnection )
2804 // yes -> outta here
2805 return true;
2809 if (m_xAggregateSet.is())
2811 Reference< XConnection > xConnection = connectRowset(
2812 Reference<XRowSet> (m_xAggregate, UNO_QUERY),
2813 m_xContext,
2814 true // set a calculated connection as ActiveConnection
2816 return xConnection.is();
2819 catch(const SQLException& eDB)
2821 onError(eDB, FRM_RES_STRING(RID_STR_CONNECTERROR));
2823 catch(const Exception&)
2825 DBG_UNHANDLED_EXCEPTION();
2828 return false;
2832 void ODatabaseForm::load_impl(bool bCausedByParentForm, bool bMoveToFirst, const Reference< XInteractionHandler >& _rxCompletionHandler ) throw( RuntimeException )
2834 ::osl::ResettableMutexGuard aGuard(m_aMutex);
2836 // are we already loaded?
2837 if (isLoaded())
2838 return;
2840 m_bSubForm = bCausedByParentForm;
2842 // if we don't have a connection, we are not intended to be a database form or the aggregate was not able
2843 // to establish a connection
2844 bool bConnected = implEnsureConnection();
2846 // we don't have to execute if we do not have a command to execute
2847 bool bExecute = bConnected && m_xAggregateSet.is() && !getString(m_xAggregateSet->getPropertyValue(PROPERTY_COMMAND)).isEmpty();
2849 // a database form always uses caching
2850 // we use starting fetchsize with at least 10 rows
2851 if (bConnected)
2852 m_xAggregateSet->setPropertyValue(PROPERTY_FETCHSIZE, makeAny((sal_Int32)40));
2854 // if we're loaded as sub form we got a "rowSetChanged" from the parent rowset _before_ we got the "loaded"
2855 // so we don't need to execute the statement again, this was already done
2856 // (and there were no relevant changes between these two listener calls, the "load" of a form is quite an
2857 // atomic operation.)
2859 bool bSuccess = false;
2860 if (bExecute)
2862 m_sCurrentErrorContext = FRM_RES_STRING(RID_ERR_LOADING_FORM);
2863 bSuccess = executeRowSet(aGuard, bMoveToFirst, _rxCompletionHandler);
2866 if (bSuccess)
2868 m_bLoaded = true;
2869 aGuard.clear();
2870 EventObject aEvt(static_cast<XWeak*>(this));
2871 m_aLoadListeners.notifyEach( &XLoadListener::loaded, aEvt );
2873 // if we are on the insert row, we have to reset all controls
2874 // to set the default values
2875 if (bExecute && getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_ISNEW)))
2876 reset();
2881 void SAL_CALL ODatabaseForm::unload() throw( RuntimeException, std::exception )
2883 ::osl::ResettableMutexGuard aGuard(m_aMutex);
2884 if (!isLoaded())
2885 return;
2887 DELETEZ(m_pLoadTimer);
2889 aGuard.clear();
2890 EventObject aEvt(static_cast<XWeak*>(this));
2891 m_aLoadListeners.notifyEach( &XLoadListener::unloading, aEvt );
2893 if (m_xAggregateAsRowSet.is())
2895 // we may have reset the InsertOnly property on the aggregate - restore it
2896 restoreInsertOnlyState( );
2898 // clear the parameters if there are any
2899 invlidateParameters();
2903 // close the aggregate
2904 Reference<XCloseable> xCloseable;
2905 query_aggregation( m_xAggregate, xCloseable);
2906 aGuard.clear();
2907 if (xCloseable.is())
2908 xCloseable->close();
2910 catch(const SQLException&)
2913 aGuard.reset();
2916 m_bLoaded = false;
2918 // if the connection we used while we were loaded is only shared with our parent, we
2919 // reset it
2920 if ( isSharingConnection() )
2921 stopSharingConnection();
2923 aGuard.clear();
2924 m_aLoadListeners.notifyEach( &XLoadListener::unloaded, aEvt );
2928 void SAL_CALL ODatabaseForm::reload() throw( RuntimeException, std::exception )
2930 reload_impl(true);
2934 void ODatabaseForm::reload_impl(bool bMoveToFirst, const Reference< XInteractionHandler >& _rxCompletionHandler ) throw( RuntimeException )
2936 ::osl::ResettableMutexGuard aGuard(m_aMutex);
2937 if (!isLoaded())
2938 return;
2940 DocumentModifyGuard aModifyGuard( *this );
2941 // ensures the document is not marked as "modified" just because we change some control's content during
2942 // reloading ...
2944 EventObject aEvent(static_cast<XWeak*>(this));
2946 // only if there is no approve listener we can post the event at this time
2947 // otherwise see approveRowsetChange
2948 // the aprrovement is done by the aggregate
2949 if (!m_aRowSetApproveListeners.getLength())
2951 ::cppu::OInterfaceIteratorHelper aIter(m_aLoadListeners);
2952 aGuard.clear();
2954 while (aIter.hasMoreElements())
2955 static_cast<XLoadListener*>(aIter.next())->reloading(aEvent);
2957 aGuard.reset();
2961 bool bSuccess = true;
2964 m_sCurrentErrorContext = FRM_RES_STRING(RID_ERR_REFRESHING_FORM);
2965 bSuccess = executeRowSet(aGuard, bMoveToFirst, _rxCompletionHandler);
2967 catch(const SQLException&)
2969 OSL_FAIL("ODatabaseForm::reload_impl : shouldn't executeRowSet catch this exception?");
2972 if (bSuccess)
2974 ::cppu::OInterfaceIteratorHelper aIter(m_aLoadListeners);
2975 aGuard.clear();
2976 while (aIter.hasMoreElements())
2977 static_cast<XLoadListener*>(aIter.next())->reloaded(aEvent);
2979 // if we are on the insert row, we have to reset all controls
2980 // to set the default values
2981 if (getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_ISNEW)))
2982 reset();
2984 else
2985 m_bLoaded = false;
2989 sal_Bool SAL_CALL ODatabaseForm::isLoaded() throw( RuntimeException, std::exception )
2991 return m_bLoaded;
2995 void SAL_CALL ODatabaseForm::addLoadListener(const Reference<XLoadListener>& aListener) throw( RuntimeException, std::exception )
2997 m_aLoadListeners.addInterface(aListener);
3001 void SAL_CALL ODatabaseForm::removeLoadListener(const Reference<XLoadListener>& aListener) throw( RuntimeException, std::exception )
3003 m_aLoadListeners.removeInterface(aListener);
3007 // com::sun::star::sdbc::XCloseable
3008 void SAL_CALL ODatabaseForm::close() throw( SQLException, RuntimeException, std::exception )
3010 // unload will close the aggregate
3011 unload();
3015 // com::sun::star::sdbc::XRowSetListener
3017 void SAL_CALL ODatabaseForm::cursorMoved(const EventObject& /*event*/) throw( RuntimeException, std::exception )
3019 // reload the subform with the new parameters of the parent
3020 // do this handling delayed to provide of execute too many SQL Statements
3021 ::osl::ResettableMutexGuard aGuard(m_aMutex);
3023 DBG_ASSERT( m_pLoadTimer, "ODatabaseForm::cursorMoved: how can this happen?!" );
3024 if ( !m_pLoadTimer )
3025 impl_createLoadTimer();
3027 if ( m_pLoadTimer->IsActive() )
3028 m_pLoadTimer->Stop();
3030 // and start the timer again
3031 m_pLoadTimer->Start();
3035 void SAL_CALL ODatabaseForm::rowChanged(const EventObject& /*event*/) throw( RuntimeException, std::exception )
3037 // ignore it
3041 void SAL_CALL ODatabaseForm::rowSetChanged(const EventObject& /*event*/) throw( RuntimeException, std::exception )
3043 // not interested in :
3044 // if our parent is an ODatabaseForm, too, then after this rowSetChanged we'll get a "reloaded"
3045 // or a "loaded" event.
3046 // If somebody gave us another parent which is an XRowSet but doesn't handle an execute as
3047 // "load" respectively "reload" ... can't do anything ....
3051 bool ODatabaseForm::impl_approveRowChange_throw( const EventObject& _rEvent, const bool _bAllowSQLException,
3052 ::osl::ClearableMutexGuard& _rGuard )
3054 ::cppu::OInterfaceIteratorHelper aIter( m_aRowSetApproveListeners );
3055 _rGuard.clear();
3056 while ( aIter.hasMoreElements() )
3058 Reference< XRowSetApproveListener > xListener( static_cast< XRowSetApproveListener* >( aIter.next() ) );
3059 if ( !xListener.is() )
3060 continue;
3064 if ( !xListener->approveRowSetChange( _rEvent ) )
3065 return false;
3067 catch (const DisposedException& e)
3069 if ( e.Context == xListener )
3070 aIter.remove();
3072 catch (const RuntimeException&)
3074 throw;
3076 catch (const SQLException&)
3078 if ( _bAllowSQLException )
3079 throw;
3080 DBG_UNHANDLED_EXCEPTION();
3082 catch (const Exception&)
3084 DBG_UNHANDLED_EXCEPTION();
3087 return true;
3091 sal_Bool SAL_CALL ODatabaseForm::approveCursorMove(const EventObject& event) throw( RuntimeException, std::exception )
3093 // is our aggregate calling?
3094 if (event.Source == InterfaceRef(static_cast<XWeak*>(this)))
3096 // Our aggregate doesn't have any ApproveRowSetListeners (expect ourself), as we re-routed the queryInterface
3097 // for XRowSetApproveBroadcaster-interface.
3098 // So we have to multiplex this approve request.
3099 ::cppu::OInterfaceIteratorHelper aIter( m_aRowSetApproveListeners );
3100 while ( aIter.hasMoreElements() )
3102 Reference< XRowSetApproveListener > xListener( static_cast< XRowSetApproveListener* >( aIter.next() ) );
3103 if ( !xListener.is() )
3104 continue;
3108 if ( !xListener->approveCursorMove( event ) )
3109 return sal_False;
3111 catch (const DisposedException& e)
3113 if ( e.Context == xListener )
3114 aIter.remove();
3116 catch (const RuntimeException&)
3118 throw;
3120 catch (const Exception&)
3122 DBG_UNHANDLED_EXCEPTION();
3125 return true;
3127 else
3129 // this is a call from our parent ...
3130 // a parent's cursor move will result in a re-execute of our own row-set, so we have to
3131 // ask our own RowSetChangesListeners, too
3132 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3133 if ( !impl_approveRowChange_throw( event, false, aGuard ) )
3134 return sal_False;
3136 return sal_True;
3140 sal_Bool SAL_CALL ODatabaseForm::approveRowChange(const RowChangeEvent& event) throw( RuntimeException, std::exception )
3142 // is our aggregate calling?
3143 if (event.Source == InterfaceRef(static_cast<XWeak*>(this)))
3145 // Our aggregate doesn't have any ApproveRowSetListeners (expect ourself), as we re-routed the queryInterface
3146 // for XRowSetApproveBroadcaster-interface.
3147 // So we have to multiplex this approve request.
3148 ::cppu::OInterfaceIteratorHelper aIter( m_aRowSetApproveListeners );
3149 while ( aIter.hasMoreElements() )
3151 Reference< XRowSetApproveListener > xListener( static_cast< XRowSetApproveListener* >( aIter.next() ) );
3152 if ( !xListener.is() )
3153 continue;
3157 if ( !xListener->approveRowChange( event ) )
3158 return false;
3160 catch (const DisposedException& e)
3162 if ( e.Context == xListener )
3163 aIter.remove();
3165 catch (const RuntimeException&)
3167 throw;
3169 catch (const Exception&)
3171 DBG_UNHANDLED_EXCEPTION();
3174 return true;
3176 return sal_True;
3180 sal_Bool SAL_CALL ODatabaseForm::approveRowSetChange(const EventObject& event) throw( RuntimeException, std::exception )
3182 if (event.Source == InterfaceRef(static_cast<XWeak*>(this))) // ignore our aggregate as we handle this approve ourself
3184 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3185 bool bWasLoaded = isLoaded();
3186 if ( !impl_approveRowChange_throw( event, false, aGuard ) )
3187 return sal_False;
3189 if ( bWasLoaded )
3191 m_aLoadListeners.notifyEach( &XLoadListener::reloading, event );
3194 else
3196 // this is a call from our parent ...
3197 // a parent's cursor move will result in a re-execute of our own row-set, so we have to
3198 // ask our own RowSetChangesListeners, too
3199 ::osl::ClearableMutexGuard aGuard( m_aMutex );
3200 if ( !impl_approveRowChange_throw( event, false, aGuard ) )
3201 return sal_False;
3203 return sal_True;
3207 // com::sun::star::sdb::XRowSetApproveBroadcaster
3209 void SAL_CALL ODatabaseForm::addRowSetApproveListener(const Reference<XRowSetApproveListener>& _rListener) throw( RuntimeException, std::exception )
3211 ::osl::ResettableMutexGuard aGuard(m_aMutex);
3212 m_aRowSetApproveListeners.addInterface(_rListener);
3214 // do we have to multiplex ?
3215 if (m_aRowSetApproveListeners.getLength() == 1)
3217 Reference<XRowSetApproveBroadcaster> xBroadcaster;
3218 if (query_aggregation( m_xAggregate, xBroadcaster))
3220 Reference<XRowSetApproveListener> xListener((XRowSetApproveListener*)this);
3221 xBroadcaster->addRowSetApproveListener(xListener);
3227 void SAL_CALL ODatabaseForm::removeRowSetApproveListener(const Reference<XRowSetApproveListener>& _rListener) throw( RuntimeException, std::exception )
3229 ::osl::ResettableMutexGuard aGuard(m_aMutex);
3230 // do we have to remove the multiplex ?
3231 m_aRowSetApproveListeners.removeInterface(_rListener);
3232 if ( m_aRowSetApproveListeners.getLength() == 0 )
3234 Reference<XRowSetApproveBroadcaster> xBroadcaster;
3235 if (query_aggregation( m_xAggregate, xBroadcaster))
3237 Reference<XRowSetApproveListener> xListener((XRowSetApproveListener*)this);
3238 xBroadcaster->removeRowSetApproveListener(xListener);
3244 // com::sun:star::form::XDatabaseParameterBroadcaster
3246 void SAL_CALL ODatabaseForm::addDatabaseParameterListener(const Reference<XDatabaseParameterListener>& _rListener) throw( RuntimeException, std::exception )
3248 m_aParameterManager.addParameterListener( _rListener );
3251 void SAL_CALL ODatabaseForm::removeDatabaseParameterListener(const Reference<XDatabaseParameterListener>& _rListener) throw( RuntimeException, std::exception )
3253 m_aParameterManager.removeParameterListener( _rListener );
3257 void SAL_CALL ODatabaseForm::addParameterListener(const Reference<XDatabaseParameterListener>& _rListener) throw( RuntimeException, std::exception )
3259 ODatabaseForm::addDatabaseParameterListener( _rListener );
3263 void SAL_CALL ODatabaseForm::removeParameterListener(const Reference<XDatabaseParameterListener>& _rListener) throw( RuntimeException, std::exception )
3265 ODatabaseForm::removeDatabaseParameterListener( _rListener );
3269 // com::sun::star::sdb::XCompletedExecution
3271 void SAL_CALL ODatabaseForm::executeWithCompletion( const Reference< XInteractionHandler >& _rxHandler ) throw(SQLException, RuntimeException, std::exception)
3273 ::osl::ClearableMutexGuard aGuard(m_aMutex);
3274 // the difference between execute and load is, that we position on the first row in case of load
3275 // after execute we remain before the first row
3276 if (!isLoaded())
3278 aGuard.clear();
3279 load_impl(false, false, _rxHandler);
3281 else
3283 EventObject event(static_cast< XWeak* >(this));
3284 if ( !impl_approveRowChange_throw( event, true, aGuard ) )
3285 return;
3287 // we're loaded and somebody want's to execute ourself -> this means a reload
3288 reload_impl(false, _rxHandler);
3293 // com::sun::star::sdbc::XRowSet
3295 void SAL_CALL ODatabaseForm::execute() throw( SQLException, RuntimeException, std::exception )
3297 ::osl::ResettableMutexGuard aGuard(m_aMutex);
3298 // if somebody calls an execute and we're not loaded we reroute this call to our load method.
3300 // the difference between execute and load is, that we position on the first row in case of load
3301 // after execute we remain before the first row
3302 if (!isLoaded())
3304 aGuard.clear();
3305 load_impl(false, false);
3307 else
3309 EventObject event(static_cast< XWeak* >(this));
3310 if ( !impl_approveRowChange_throw( event, true, aGuard ) )
3311 return;
3313 // we're loaded and somebody want's to execute ourself -> this means a reload
3314 reload_impl(false);
3319 void SAL_CALL ODatabaseForm::addRowSetListener(const Reference<XRowSetListener>& _rListener) throw( RuntimeException, std::exception )
3321 if (m_xAggregateAsRowSet.is())
3322 m_xAggregateAsRowSet->addRowSetListener(_rListener);
3326 void SAL_CALL ODatabaseForm::removeRowSetListener(const Reference<XRowSetListener>& _rListener) throw( RuntimeException, std::exception )
3328 if (m_xAggregateAsRowSet.is())
3329 m_xAggregateAsRowSet->removeRowSetListener(_rListener);
3333 // com::sun::star::sdbc::XResultSet
3335 sal_Bool SAL_CALL ODatabaseForm::next() throw( SQLException, RuntimeException, std::exception )
3337 return m_xAggregateAsRowSet->next();
3341 sal_Bool SAL_CALL ODatabaseForm::isBeforeFirst() throw( SQLException, RuntimeException, std::exception )
3343 return m_xAggregateAsRowSet->isBeforeFirst();
3347 sal_Bool SAL_CALL ODatabaseForm::isAfterLast() throw( SQLException, RuntimeException, std::exception )
3349 return m_xAggregateAsRowSet->isAfterLast();
3353 sal_Bool SAL_CALL ODatabaseForm::isFirst() throw( SQLException, RuntimeException, std::exception )
3355 return m_xAggregateAsRowSet->isFirst();
3359 sal_Bool SAL_CALL ODatabaseForm::isLast() throw( SQLException, RuntimeException, std::exception )
3361 return m_xAggregateAsRowSet->isLast();
3365 void SAL_CALL ODatabaseForm::beforeFirst() throw( SQLException, RuntimeException, std::exception )
3367 m_xAggregateAsRowSet->beforeFirst();
3371 void SAL_CALL ODatabaseForm::afterLast() throw( SQLException, RuntimeException, std::exception )
3373 m_xAggregateAsRowSet->afterLast();
3377 sal_Bool SAL_CALL ODatabaseForm::first() throw( SQLException, RuntimeException, std::exception )
3379 return m_xAggregateAsRowSet->first();
3383 sal_Bool SAL_CALL ODatabaseForm::last() throw( SQLException, RuntimeException, std::exception )
3385 return m_xAggregateAsRowSet->last();
3389 sal_Int32 SAL_CALL ODatabaseForm::getRow() throw( SQLException, RuntimeException, std::exception )
3391 return m_xAggregateAsRowSet->getRow();
3395 sal_Bool SAL_CALL ODatabaseForm::absolute(sal_Int32 row) throw( SQLException, RuntimeException, std::exception )
3397 return m_xAggregateAsRowSet->absolute(row);
3401 sal_Bool SAL_CALL ODatabaseForm::relative(sal_Int32 rows) throw( SQLException, RuntimeException, std::exception )
3403 return m_xAggregateAsRowSet->relative(rows);
3407 sal_Bool SAL_CALL ODatabaseForm::previous() throw( SQLException, RuntimeException, std::exception )
3409 return m_xAggregateAsRowSet->previous();
3413 void SAL_CALL ODatabaseForm::refreshRow() throw( SQLException, RuntimeException, std::exception )
3415 m_xAggregateAsRowSet->refreshRow();
3419 sal_Bool SAL_CALL ODatabaseForm::rowUpdated() throw( SQLException, RuntimeException, std::exception )
3421 return m_xAggregateAsRowSet->rowUpdated();
3425 sal_Bool SAL_CALL ODatabaseForm::rowInserted() throw( SQLException, RuntimeException, std::exception )
3427 return m_xAggregateAsRowSet->rowInserted();
3431 sal_Bool SAL_CALL ODatabaseForm::rowDeleted() throw( SQLException, RuntimeException, std::exception )
3433 return m_xAggregateAsRowSet->rowDeleted();
3437 InterfaceRef SAL_CALL ODatabaseForm::getStatement() throw( SQLException, RuntimeException, std::exception )
3439 return m_xAggregateAsRowSet->getStatement();
3442 // com::sun::star::sdbc::XResultSetUpdate
3443 // exceptions during insert update and delete will be forwarded to the errorlistener
3445 void SAL_CALL ODatabaseForm::insertRow() throw( SQLException, RuntimeException, std::exception )
3449 Reference<XResultSetUpdate> xUpdate;
3450 if (query_aggregation( m_xAggregate, xUpdate))
3451 xUpdate->insertRow();
3453 catch(const RowSetVetoException&)
3455 throw;
3457 catch(const SQLException& eDb)
3459 onError(eDb, FRM_RES_STRING(RID_STR_ERR_INSERTRECORD));
3460 throw;
3465 void SAL_CALL ODatabaseForm::updateRow() throw( SQLException, RuntimeException, std::exception )
3469 Reference<XResultSetUpdate> xUpdate;
3470 if (query_aggregation( m_xAggregate, xUpdate))
3471 xUpdate->updateRow();
3473 catch(const RowSetVetoException&)
3475 throw;
3477 catch(const SQLException& eDb)
3479 onError(eDb, FRM_RES_STRING(RID_STR_ERR_UPDATERECORD));
3480 throw;
3485 void SAL_CALL ODatabaseForm::deleteRow() throw( SQLException, RuntimeException, std::exception )
3489 Reference<XResultSetUpdate> xUpdate;
3490 if (query_aggregation( m_xAggregate, xUpdate))
3491 xUpdate->deleteRow();
3493 catch(const RowSetVetoException&)
3495 throw;
3497 catch(const SQLException& eDb)
3499 onError(eDb, FRM_RES_STRING(RID_STR_ERR_DELETERECORD));
3500 throw;
3505 void SAL_CALL ODatabaseForm::cancelRowUpdates() throw( SQLException, RuntimeException, std::exception )
3509 Reference<XResultSetUpdate> xUpdate;
3510 if (query_aggregation( m_xAggregate, xUpdate))
3511 xUpdate->cancelRowUpdates();
3513 catch(const RowSetVetoException&)
3515 throw;
3517 catch(const SQLException& eDb)
3519 onError(eDb, FRM_RES_STRING(RID_STR_ERR_INSERTRECORD));
3520 throw;
3525 void SAL_CALL ODatabaseForm::moveToInsertRow() throw( SQLException, RuntimeException, std::exception )
3527 Reference<XResultSetUpdate> xUpdate;
3528 if (query_aggregation( m_xAggregate, xUpdate))
3530 // _always_ move to the insert row
3532 // Formerly, the following line was conditioned with a "not is new", means we did not move the aggregate
3533 // to the insert row if it was already positioned there.
3535 // This prevented the RowSet implementation from resetting it's column values. We, ourself, formerly
3536 // did this reset of columns in reset_impl, where we set every column to the ControlDefault, or, if this
3537 // was not present, to NULL. However, the problem with setting to NULL was #88888#, the problem with
3538 // _not_ setting to NULL (which was the original fix for #88888#) was #97955#.
3540 // So now we
3541 // * move our aggregate to the insert row
3542 // * in reset_impl
3543 // - set the control defaults into the columns if not void
3544 // - do _not_ set the columns to NULL if no control default is set
3546 // Still, there is #72756#. During fixing this bug, DG introduced not calling the aggregate here. So
3547 // in theory, we re-introduced #72756#. But the bug described therein does not happen anymore, as the
3548 // preliminaries for it changed (no display of guessed values for new records with autoinc fields)
3550 // BTW: the public Issuezilla bug is #i2815#
3552 xUpdate->moveToInsertRow();
3554 // then set the default values and the parameters given from the parent
3555 reset();
3560 void SAL_CALL ODatabaseForm::moveToCurrentRow() throw( SQLException, RuntimeException, std::exception )
3562 Reference<XResultSetUpdate> xUpdate;
3563 if (query_aggregation( m_xAggregate, xUpdate))
3564 xUpdate->moveToCurrentRow();
3567 // com::sun::star::sdbcx::XDeleteRows
3569 Sequence<sal_Int32> SAL_CALL ODatabaseForm::deleteRows(const Sequence<Any>& rows) throw( SQLException, RuntimeException, std::exception )
3573 Reference<XDeleteRows> xDelete;
3574 if (query_aggregation( m_xAggregate, xDelete))
3575 return xDelete->deleteRows(rows);
3577 catch(const RowSetVetoException&)
3579 throw;
3581 catch(const SQLException& eDb)
3583 onError(eDb, FRM_RES_STRING(RID_STR_ERR_DELETERECORDS));
3584 throw;
3587 return Sequence< sal_Int32 >();
3590 // com::sun::star::sdbc::XParameters
3592 void SAL_CALL ODatabaseForm::setNull(sal_Int32 parameterIndex, sal_Int32 sqlType) throw( SQLException, RuntimeException, std::exception )
3594 m_aParameterManager.setNull(parameterIndex, sqlType);
3598 void SAL_CALL ODatabaseForm::setObjectNull(sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName) throw( SQLException, RuntimeException, std::exception )
3600 m_aParameterManager.setObjectNull(parameterIndex, sqlType, typeName);
3604 void SAL_CALL ODatabaseForm::setBoolean(sal_Int32 parameterIndex, sal_Bool x) throw( SQLException, RuntimeException, std::exception )
3606 m_aParameterManager.setBoolean(parameterIndex, x);
3610 void SAL_CALL ODatabaseForm::setByte(sal_Int32 parameterIndex, sal_Int8 x) throw( SQLException, RuntimeException, std::exception )
3612 m_aParameterManager.setByte(parameterIndex, x);
3616 void SAL_CALL ODatabaseForm::setShort(sal_Int32 parameterIndex, sal_Int16 x) throw( SQLException, RuntimeException, std::exception )
3618 m_aParameterManager.setShort(parameterIndex, x);
3622 void SAL_CALL ODatabaseForm::setInt(sal_Int32 parameterIndex, sal_Int32 x) throw( SQLException, RuntimeException, std::exception )
3624 m_aParameterManager.setInt(parameterIndex, x);
3628 void SAL_CALL ODatabaseForm::setLong(sal_Int32 parameterIndex, sal_Int64 x) throw( SQLException, RuntimeException, std::exception )
3630 m_aParameterManager.setLong(parameterIndex, x);
3634 void SAL_CALL ODatabaseForm::setFloat(sal_Int32 parameterIndex, float x) throw( SQLException, RuntimeException, std::exception )
3636 m_aParameterManager.setFloat(parameterIndex, x);
3640 void SAL_CALL ODatabaseForm::setDouble(sal_Int32 parameterIndex, double x) throw( SQLException, RuntimeException, std::exception )
3642 m_aParameterManager.setDouble(parameterIndex, x);
3646 void SAL_CALL ODatabaseForm::setString(sal_Int32 parameterIndex, const OUString& x) throw( SQLException, RuntimeException, std::exception )
3648 m_aParameterManager.setString(parameterIndex, x);
3652 void SAL_CALL ODatabaseForm::setBytes(sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x) throw( SQLException, RuntimeException, std::exception )
3654 m_aParameterManager.setBytes(parameterIndex, x);
3658 void SAL_CALL ODatabaseForm::setDate(sal_Int32 parameterIndex, const ::com::sun::star::util::Date& x) throw( SQLException, RuntimeException, std::exception )
3660 m_aParameterManager.setDate(parameterIndex, x);
3664 void SAL_CALL ODatabaseForm::setTime(sal_Int32 parameterIndex, const ::com::sun::star::util::Time& x) throw( SQLException, RuntimeException, std::exception )
3666 m_aParameterManager.setTime(parameterIndex, x);
3670 void SAL_CALL ODatabaseForm::setTimestamp(sal_Int32 parameterIndex, const ::com::sun::star::util::DateTime& x) throw( SQLException, RuntimeException, std::exception )
3672 m_aParameterManager.setTimestamp(parameterIndex, x);
3676 void SAL_CALL ODatabaseForm::setBinaryStream(sal_Int32 parameterIndex, const Reference<XInputStream>& x, sal_Int32 length) throw( SQLException, RuntimeException, std::exception )
3678 m_aParameterManager.setBinaryStream(parameterIndex, x, length);
3682 void SAL_CALL ODatabaseForm::setCharacterStream(sal_Int32 parameterIndex, const Reference<XInputStream>& x, sal_Int32 length) throw( SQLException, RuntimeException, std::exception )
3684 m_aParameterManager.setCharacterStream(parameterIndex, x, length);
3688 void SAL_CALL ODatabaseForm::setObjectWithInfo(sal_Int32 parameterIndex, const Any& x, sal_Int32 targetSqlType, sal_Int32 scale) throw( SQLException, RuntimeException, std::exception )
3690 m_aParameterManager.setObjectWithInfo(parameterIndex, x, targetSqlType, scale);
3694 void SAL_CALL ODatabaseForm::setObject(sal_Int32 parameterIndex, const Any& x) throw( SQLException, RuntimeException, std::exception )
3696 m_aParameterManager.setObject(parameterIndex, x);
3700 void SAL_CALL ODatabaseForm::setRef(sal_Int32 parameterIndex, const Reference<XRef>& x) throw( SQLException, RuntimeException, std::exception )
3702 m_aParameterManager.setRef(parameterIndex, x);
3706 void SAL_CALL ODatabaseForm::setBlob(sal_Int32 parameterIndex, const Reference<XBlob>& x) throw( SQLException, RuntimeException, std::exception )
3708 m_aParameterManager.setBlob(parameterIndex, x);
3712 void SAL_CALL ODatabaseForm::setClob(sal_Int32 parameterIndex, const Reference<XClob>& x) throw( SQLException, RuntimeException, std::exception )
3714 m_aParameterManager.setClob(parameterIndex, x);
3718 void SAL_CALL ODatabaseForm::setArray(sal_Int32 parameterIndex, const Reference<XArray>& x) throw( SQLException, RuntimeException, std::exception )
3720 m_aParameterManager.setArray(parameterIndex, x);
3724 void SAL_CALL ODatabaseForm::clearParameters() throw( SQLException, RuntimeException, std::exception )
3726 m_aParameterManager.clearParameters();
3730 void SAL_CALL ODatabaseForm::propertyChange( const PropertyChangeEvent& evt ) throw (RuntimeException, std::exception)
3732 if ( evt.Source == m_xParent )
3734 if ( evt.PropertyName == PROPERTY_ISNEW )
3736 bool bCurrentIsNew( false );
3737 OSL_VERIFY( evt.NewValue >>= bCurrentIsNew );
3738 if ( !bCurrentIsNew )
3739 reload_impl( true );
3741 return;
3743 OFormComponents::propertyChange( evt );
3746 // com::sun::star::lang::XServiceInfo
3748 OUString SAL_CALL ODatabaseForm::getImplementationName_Static()
3750 return OUString( "com.sun.star.comp.forms.ODatabaseForm" );
3753 Sequence< OUString > SAL_CALL ODatabaseForm::getSupportedServiceNames_Static()
3755 return css::uno::Sequence<OUString>{
3756 FRM_SUN_FORMCOMPONENT, "com.sun.star.form.FormComponents",
3757 FRM_SUN_COMPONENT_FORM, FRM_SUN_COMPONENT_HTMLFORM,
3758 FRM_SUN_COMPONENT_DATAFORM, FRM_COMPONENT_FORM};
3762 OUString SAL_CALL ODatabaseForm::getImplementationName() throw( RuntimeException, std::exception )
3764 return getImplementationName_Static();
3768 Sequence< OUString > SAL_CALL ODatabaseForm::getSupportedServiceNames() throw( RuntimeException, std::exception )
3770 // the services of our aggregate
3771 Sequence< OUString > aServices;
3772 Reference< XServiceInfo > xInfo;
3773 if (query_aggregation(m_xAggregate, xInfo))
3774 aServices = xInfo->getSupportedServiceNames();
3776 // concat with out own services
3777 return ::comphelper::concatSequences(
3778 getSupportedServiceNames_Static(),
3779 aServices
3783 sal_Bool SAL_CALL ODatabaseForm::supportsService(const OUString& ServiceName) throw( RuntimeException, std::exception )
3785 return cppu::supportsService(this, ServiceName);
3788 // com::sun::star::io::XPersistObject
3789 const sal_uInt16 CYCLE = 0x0001;
3790 const sal_uInt16 DONTAPPLYFILTER = 0x0002;
3792 OUString ODatabaseForm::getServiceName() throw( RuntimeException, std::exception )
3794 return OUString(FRM_COMPONENT_FORM); // old (non-sun) name for compatibility !
3797 void SAL_CALL ODatabaseForm::write(const Reference<XObjectOutputStream>& _rxOutStream) throw( IOException, RuntimeException, std::exception )
3799 DBG_ASSERT(m_xAggregateSet.is(), "ODatabaseForm::write : only to be called if the aggregate exists !");
3801 // all children
3802 OFormComponents::write(_rxOutStream);
3804 // version
3805 _rxOutStream->writeShort(0x0003);
3807 // Name
3808 _rxOutStream << m_sName;
3810 OUString sDataSource;
3811 if (m_xAggregateSet.is())
3812 m_xAggregateSet->getPropertyValue(PROPERTY_DATASOURCE) >>= sDataSource;
3813 _rxOutStream << sDataSource;
3815 // former CursorSource
3816 OUString sCommand;
3817 if (m_xAggregateSet.is())
3818 m_xAggregateSet->getPropertyValue(PROPERTY_COMMAND) >>= sCommand;
3819 _rxOutStream << sCommand;
3821 // former MasterFields
3822 _rxOutStream << m_aMasterFields;
3823 // former DetailFields
3824 _rxOutStream << m_aDetailFields;
3826 // former DataSelectionType
3827 DataSelectionType eTranslated = DataSelectionType_TABLE;
3828 if (m_xAggregateSet.is())
3830 sal_Int32 nCommandType = 0;
3831 m_xAggregateSet->getPropertyValue(PROPERTY_COMMANDTYPE) >>= nCommandType;
3832 switch (nCommandType)
3834 case CommandType::TABLE : eTranslated = DataSelectionType_TABLE; break;
3835 case CommandType::QUERY : eTranslated = DataSelectionType_QUERY; break;
3836 case CommandType::COMMAND:
3838 bool bEscapeProcessing = getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_ESCAPE_PROCESSING));
3839 eTranslated = bEscapeProcessing ? DataSelectionType_SQL : DataSelectionType_SQLPASSTHROUGH;
3841 break;
3842 default : OSL_FAIL("ODatabaseForm::write : wrong CommandType !");
3845 _rxOutStream->writeShort((sal_Int16)eTranslated); // former DataSelectionType
3847 // very old versions expect a CursorType here
3848 _rxOutStream->writeShort(DatabaseCursorType_KEYSET);
3850 _rxOutStream->writeBoolean(m_eNavigation != NavigationBarMode_NONE);
3852 // former DataEntry
3853 if (m_xAggregateSet.is())
3854 _rxOutStream->writeBoolean(getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_INSERTONLY)));
3855 else
3856 _rxOutStream->writeBoolean(sal_False);
3858 _rxOutStream->writeBoolean(m_bAllowInsert);
3859 _rxOutStream->writeBoolean(m_bAllowUpdate);
3860 _rxOutStream->writeBoolean(m_bAllowDelete);
3862 // html form stuff
3863 OUString sTmp = INetURLObject::decode( m_aTargetURL, INetURLObject::DECODE_UNAMBIGUOUS);
3864 _rxOutStream << sTmp;
3865 _rxOutStream->writeShort( (sal_Int16)m_eSubmitMethod );
3866 _rxOutStream->writeShort( (sal_Int16)m_eSubmitEncoding );
3867 _rxOutStream << m_aTargetFrame;
3869 // version 2 didn't know some options and the "default" state
3870 sal_Int32 nCycle = TabulatorCycle_RECORDS;
3871 if (m_aCycle.hasValue())
3873 ::cppu::enum2int(nCycle, m_aCycle);
3874 if (m_aCycle == TabulatorCycle_PAGE)
3875 // unknown in earlier versions
3876 nCycle = TabulatorCycle_RECORDS;
3878 _rxOutStream->writeShort((sal_Int16) nCycle);
3880 _rxOutStream->writeShort((sal_Int16)m_eNavigation);
3882 OUString sFilter;
3883 OUString sOrder;
3884 if (m_xAggregateSet.is())
3886 m_xAggregateSet->getPropertyValue(PROPERTY_FILTER) >>= sFilter;
3887 m_xAggregateSet->getPropertyValue(PROPERTY_SORT) >>= sOrder;
3889 _rxOutStream << sFilter;
3890 _rxOutStream << sOrder;
3893 // version 3
3894 sal_uInt16 nAnyMask = 0;
3895 if (m_aCycle.hasValue())
3896 nAnyMask |= CYCLE;
3898 if (m_xAggregateSet.is() && !getBOOL(m_xAggregateSet->getPropertyValue(PROPERTY_APPLYFILTER)))
3899 nAnyMask |= DONTAPPLYFILTER;
3901 _rxOutStream->writeShort(nAnyMask);
3903 if (nAnyMask & CYCLE)
3905 sal_Int32 nRealCycle = 0;
3906 ::cppu::enum2int(nRealCycle, m_aCycle);
3907 _rxOutStream->writeShort((sal_Int16)nRealCycle);
3912 void SAL_CALL ODatabaseForm::read(const Reference<XObjectInputStream>& _rxInStream) throw( IOException, RuntimeException, std::exception )
3914 DBG_ASSERT(m_xAggregateSet.is(), "ODatabaseForm::read : only to be called if the aggregate exists !");
3916 OFormComponents::read(_rxInStream);
3918 // version
3919 sal_uInt16 nVersion = _rxInStream->readShort();
3921 _rxInStream >> m_sName;
3923 OUString sAggregateProp;
3924 _rxInStream >> sAggregateProp;
3925 if (m_xAggregateSet.is())
3926 m_xAggregateSet->setPropertyValue(PROPERTY_DATASOURCE, makeAny(sAggregateProp));
3927 _rxInStream >> sAggregateProp;
3928 if (m_xAggregateSet.is())
3929 m_xAggregateSet->setPropertyValue(PROPERTY_COMMAND, makeAny(sAggregateProp));
3931 _rxInStream >> m_aMasterFields;
3932 _rxInStream >> m_aDetailFields;
3934 sal_Int16 nCursorSourceType = _rxInStream->readShort();
3935 sal_Int32 nCommandType = 0;
3936 switch ((DataSelectionType)nCursorSourceType)
3938 case DataSelectionType_TABLE : nCommandType = CommandType::TABLE; break;
3939 case DataSelectionType_QUERY : nCommandType = CommandType::QUERY; break;
3940 case DataSelectionType_SQL:
3941 case DataSelectionType_SQLPASSTHROUGH:
3943 nCommandType = CommandType::COMMAND;
3944 bool bEscapeProcessing = ((DataSelectionType)nCursorSourceType) != DataSelectionType_SQLPASSTHROUGH;
3945 m_xAggregateSet->setPropertyValue(PROPERTY_ESCAPE_PROCESSING, makeAny(bEscapeProcessing));
3947 break;
3948 default : OSL_FAIL("ODatabaseForm::read : wrong CommandType !");
3950 if (m_xAggregateSet.is())
3951 m_xAggregateSet->setPropertyValue(PROPERTY_COMMANDTYPE, makeAny(nCommandType));
3953 // obsolete
3954 _rxInStream->readShort();
3956 // navigation mode was a boolean in version 1
3957 // was a sal_Bool in version 1
3958 bool bNavigation = _rxInStream->readBoolean();
3959 if (nVersion == 1)
3960 m_eNavigation = bNavigation ? NavigationBarMode_CURRENT : NavigationBarMode_NONE;
3962 bool bInsertOnly = _rxInStream->readBoolean();
3963 if (m_xAggregateSet.is())
3964 m_xAggregateSet->setPropertyValue(PROPERTY_INSERTONLY, makeAny(bInsertOnly));
3966 m_bAllowInsert = _rxInStream->readBoolean();
3967 m_bAllowUpdate = _rxInStream->readBoolean();
3968 m_bAllowDelete = _rxInStream->readBoolean();
3970 // html stuff
3971 OUString sTmp;
3972 _rxInStream >> sTmp;
3973 m_aTargetURL = INetURLObject::decode( sTmp, INetURLObject::DECODE_UNAMBIGUOUS);
3974 m_eSubmitMethod = (FormSubmitMethod)_rxInStream->readShort();
3975 m_eSubmitEncoding = (FormSubmitEncoding)_rxInStream->readShort();
3976 _rxInStream >> m_aTargetFrame;
3978 if (nVersion > 1)
3980 sal_Int32 nCycle = _rxInStream->readShort();
3981 m_aCycle = ::cppu::int2enum(nCycle, cppu::UnoType<TabulatorCycle>::get());
3982 m_eNavigation = (NavigationBarMode)_rxInStream->readShort();
3984 _rxInStream >> sAggregateProp;
3985 setPropertyValue(PROPERTY_FILTER, makeAny(sAggregateProp));
3987 _rxInStream >> sAggregateProp;
3988 if (m_xAggregateSet.is())
3989 m_xAggregateSet->setPropertyValue(PROPERTY_SORT, makeAny(sAggregateProp));
3992 sal_uInt16 nAnyMask = 0;
3993 if (nVersion > 2)
3995 nAnyMask = _rxInStream->readShort();
3996 if (nAnyMask & CYCLE)
3998 sal_Int32 nCycle = _rxInStream->readShort();
3999 m_aCycle = ::cppu::int2enum(nCycle, cppu::UnoType<TabulatorCycle>::get());
4001 else
4002 m_aCycle.clear();
4004 if (m_xAggregateSet.is())
4005 m_xAggregateSet->setPropertyValue(PROPERTY_APPLYFILTER, makeAny((nAnyMask & DONTAPPLYFILTER) == 0));
4009 void ODatabaseForm::implInserted( const ElementDescription* _pElement )
4011 OFormComponents::implInserted( _pElement );
4013 Reference< XSQLErrorBroadcaster > xBroadcaster( _pElement->xInterface, UNO_QUERY );
4014 Reference< XForm > xForm ( _pElement->xInterface, UNO_QUERY );
4016 if ( xBroadcaster.is() && !xForm.is() )
4017 { // the object is an error broadcaster, but no form itself -> add ourself as listener
4018 xBroadcaster->addSQLErrorListener( this );
4023 void ODatabaseForm::implRemoved(const InterfaceRef& _rxObject)
4025 OFormComponents::implRemoved( _rxObject );
4027 Reference<XSQLErrorBroadcaster> xBroadcaster(_rxObject, UNO_QUERY);
4028 Reference<XForm> xForm(_rxObject, UNO_QUERY);
4029 if (xBroadcaster.is() && !xForm.is())
4030 { // the object is an error broadcaster, but no form itself -> remove ourself as listener
4031 xBroadcaster->removeSQLErrorListener(this);
4035 void SAL_CALL ODatabaseForm::errorOccured(const SQLErrorEvent& _rEvent) throw( RuntimeException, std::exception )
4037 // give it to my own error listener
4038 onError(_rEvent);
4039 // TODO: think about extending the chain with an SQLContext object saying
4040 // "this was an error of one of my children"
4043 // com::sun::star::container::XNamed
4044 OUString SAL_CALL ODatabaseForm::getName() throw( RuntimeException, std::exception )
4046 OUString sReturn;
4049 OPropertySetHelper::getFastPropertyValue(PROPERTY_ID_NAME) >>= sReturn;
4051 catch (const css::beans::UnknownPropertyException&)
4053 throw WrappedTargetRuntimeException(
4054 "ODatabaseForm::getName",
4055 *const_cast< ODatabaseForm* >( this ),
4056 ::cppu::getCaughtException()
4059 return sReturn;
4062 void SAL_CALL ODatabaseForm::setName(const OUString& aName) throw( RuntimeException, std::exception )
4064 setFastPropertyValue(PROPERTY_ID_NAME, makeAny(aName));
4067 } // namespace frm
4069 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* SAL_CALL
4070 com_sun_star_comp_forms_ODatabaseForm_get_implementation(css::uno::XComponentContext* context,
4071 css::uno::Sequence<css::uno::Any> const &)
4073 return cppu::acquire(new frm::ODatabaseForm(context));
4076 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */