/************************************************************************* * * $RCSfile: DatabaseForm.cxx,v $ * * $Revision: 1.66 $ * * last change: $Author: obo $ $Date: 2005-01-05 12:02:29 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses * * - GNU Lesser General Public License Version 2.1 * - Sun Industry Standards Source License Version 1.1 * * Sun Microsystems Inc., October, 2000 * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2000 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * * Sun Industry Standards Source License Version 1.1 * ================================================= * The contents of this file are subject to the Sun Industry Standards * Source License Version 1.1 (the "License"); You may not use this file * except in compliance with the License. You may obtain a copy of the * License at http://www.openoffice.org/license.html. * * Software provided under this License is provided on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. * See the License for the specific provisions governing your rights and * obligations concerning the Software. * * The Initial Developer of the Original Code is: Sun Microsystems, Inc. * * Copyright: 2000 by Sun Microsystems, Inc. * * All Rights Reserved. * * Contributor(s): _______________________________________ * * ************************************************************************/ #include #include #ifndef _FRM_DATABASEFORM_HXX_ #include "DatabaseForm.hxx" #endif #ifndef _FRM_EVENT_THREAD_HXX_ #include "EventThread.hxx" #endif #ifndef _FRM_RESOURCE_HXX_ #include "frm_resource.hxx" #endif #ifndef _FRM_RESOURCE_HRC_ #include "frm_resource.hrc" #endif #ifndef _COM_SUN_STAR_SDB_XCOLUMNUPDATE_HPP_ #include #endif #ifndef _COM_SUN_STAR_UTIL_XCANCELLABLE_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBC_RESULTSETTYPE_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBC_RESULTSETCONCURRENCY_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBC_DATATYPE_HPP_ #include #endif #ifndef _COM_SUN_STAR_IO_XOBJECTINPUTSTREAM_HPP_ #include #endif #ifndef _COM_SUN_STAR_IO_XOBJECTOUTPUTSTREAM_HPP_ #include #endif #ifndef _COM_SUN_STAR_FORM_DATASELECTIONTYPE_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDB_SQLCONTEXT_HPP_ #include #endif #ifndef _COM_SUN_STAR_FORM_FORMCOMPONENTTYPE_HPP_ #include #endif #ifndef _COM_SUN_STAR_FRAME_XDISPATCHPROVIDER_HPP_ #include #endif #ifndef _COM_SUN_STAR_FRAME_FRAMESEARCHFLAG_HPP_ #include #endif #ifndef _COM_SUN_STAR_FRAME_XDISPATCH_HPP_ #include #endif #ifndef _COM_SUN_STAR_FRAME_XMODEL_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDB_COMMANDTYPE_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDB_ROWSETVETOEXCEPTION_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBCX_XCOLUMNSSUPPLIER_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBCX_PRIVILEGE_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBC_XROWSET_HPP_ #include #endif #ifndef _COM_SUN_STAR_FORM_TABULATORCYCLE_HPP_ #include #endif #ifndef _COM_SUN_STAR_AWT_XCONTROLCONTAINER_HPP_ #include #endif #ifndef _COM_SUN_STAR_AWT_XTEXTCOMPONENT_HPP_ #include #endif #ifndef _COM_SUN_STAR_UTIL_XURLTRANSFORMER_HPP_ #include #endif #ifndef _TOOLS_DEBUG_HXX #include #endif #ifndef _SV_TIMER_HXX #include #endif #ifndef _FRM_GROUPMANAGER_HXX_ #include "GroupManager.hxx" #endif #ifndef _FRM_PROPERTY_HRC_ #include "property.hrc" #endif #ifndef _FRM_PROPERTY_HXX_ #include "property.hxx" #endif #ifndef _FRM_SERVICES_HXX_ #include "services.hxx" #endif #ifndef _FRM_IDS_HXX_ #include "ids.hxx" #endif #ifndef _FSYS_HXX #include #endif #ifndef _TOOLS_INETMSG_HXX #include #endif #ifndef _INETSTRM_HXX //autogen #include #endif #ifndef _CPPUHELPER_IMPLBASE2_HXX_ #include #endif #ifndef _COMPHELPER_STLTYPES_HXX_ #include #endif #ifndef _COMPHELPER_SEQUENCE_HXX_ #include #endif #ifndef _COMPHELPER_STLTYPES_HXX_ #include #endif #ifndef _COMPHELPER_UNO3_HXX_ #include #endif #ifndef _COMPHELPER_SEQSTREAM_HXX #include #endif #ifndef _COMPHELPER_ENUMHELPER_HXX_ #include #endif #ifndef _COMPHELPER_CONTAINER_HXX_ #include #endif #ifndef _COMPHELPER_BASIC_IO_HXX_ #include #endif #ifndef _CONNECTIVITY_DBTOOLS_HXX_ #include #endif #ifndef _OSL_MUTEX_HXX_ #include #endif #ifndef _URLOBJ_HXX #include #endif #ifndef INCLUDED_RTL_MATH_HXX #include #endif #ifndef _INETTYPE_HXX #include #endif #ifndef _COMPHELPER_EXTRACT_HXX_ #include #endif #ifndef _VOS_MUTEX_HXX_ #include #endif #ifndef _SV_SVAPP_HXX // because of the solar mutex #include #endif #ifndef _RTL_TENCINFO_H #include #endif #ifndef _UNTOOLS_UCBLOCKBYTES_HXX #include #endif #ifndef _UNTOOLS_UCBSTREAMHELPER_HXX #include #endif #ifndef FRM_MODULE_HXX #include "frm_module.hxx" #endif // compatiblity: DatabaseCursorType is dead, but for compatiblity reasons we still have to write it ... namespace com { namespace sun { namespace star { namespace data { enum DatabaseCursorType { DatabaseCursorType_FORWARD = 0, DatabaseCursorType_SNAPSHOT = 1, DatabaseCursorType_KEYSET = 2, DatabaseCursorType_DYNAMIC = 3, DatabaseCursorType_MAKE_FIXED_SIZE = SAL_MAX_ENUM }; } } } } #define DATABASEFORM_IMPLEMENTATION_NAME ::rtl::OUString::createFromAscii("com.sun.star.comp.forms.ODatabaseForm") using namespace ::dbtools; using namespace ::comphelper; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::sdb; using namespace ::com::sun::star::sdbc; using namespace ::com::sun::star::sdbcx; using namespace ::com::sun::star::beans; using namespace ::com::sun::star::container; using namespace ::com::sun::star::task; using namespace ::com::sun::star::frame; using namespace ::com::sun::star::form; using namespace ::com::sun::star::awt; using namespace ::com::sun::star::io; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::data; using namespace ::com::sun::star::util; //-------------------------------------------------------------------------- extern "C" void SAL_CALL createRegistryInfo_ODatabaseForm() { static ::frm::OMultiInstanceAutoRegistration< ::frm::ODatabaseForm > aAutoRegistration; } //......................................................................... namespace frm { //......................................................................... //--------------------------------------------------------------------- Reference< XModel> getXModel(const Reference< XInterface>& xIface) { Reference< XInterface > xParent = xIface; Reference< XModel > xModel(xParent,UNO_QUERY);; while( xParent.is() && !xModel.is() ) { Reference xChild(xParent,UNO_QUERY); xParent.set(xChild.is() ? xChild->getParent() : Reference< XInterface >(),UNO_QUERY); xModel.set(xParent,UNO_QUERY); } return xModel; } //================================================================== //= OFormSubmitResetThread //=----------------------------------------------------------------- //= submitting and resetting html-forms asynchronously //================================================================== //------------------------------------------------------------------ class OFormSubmitResetThread: public OComponentEventThread { protected: // duplicate an event with respect to it's type virtual EventObject *cloneEvent( const EventObject *pEvt ) const; // process an event. while processing the mutex isn't locked, and pCompImpl // is made sure to remain valid virtual void processEvent( ::cppu::OComponentHelper* _pCompImpl, const EventObject* _pEvt, const Reference& _rControl, sal_Bool _bSubmit); public: OFormSubmitResetThread(ODatabaseForm* pControl) : OComponentEventThread(pControl) { } }; //------------------------------------------------------------------ EventObject* OFormSubmitResetThread::cloneEvent( const EventObject *pEvt ) const { return new ::com::sun::star::awt::MouseEvent( *(::com::sun::star::awt::MouseEvent *)pEvt ); } //------------------------------------------------------------------ void OFormSubmitResetThread::processEvent( ::cppu::OComponentHelper* pCompImpl, const EventObject *_pEvt, const Reference& _rControl, sal_Bool _bSubmit) { if (_bSubmit) ((ODatabaseForm *)pCompImpl)->submit_impl(_rControl, *reinterpret_cast(_pEvt), true); else ((ODatabaseForm *)pCompImpl)->reset_impl(true); } //================================================================== //= ODatabaseForm //================================================================== //------------------------------------------------------------------ Reference< XInterface > SAL_CALL ODatabaseForm::Create( const Reference< XMultiServiceFactory >& _rxFactory ) { return *( new ODatabaseForm( _rxFactory ) ); } //------------------------------------------------------------------------------ Sequence SAL_CALL ODatabaseForm::getImplementationId() throw(RuntimeException) { return OImplementationIds::getImplementationId(getTypes()); } //------------------------------------------------------------------ Sequence SAL_CALL ODatabaseForm::getTypes() throw(RuntimeException) { // ask the aggregate Sequence aAggregateTypes; Reference xAggregateTypes; if (query_aggregation(m_xAggregate, xAggregateTypes)) aAggregateTypes = xAggregateTypes->getTypes(); Sequence< Type > aRet = concatSequences( aAggregateTypes, ODatabaseForm_BASE1::getTypes(), OFormComponents::getTypes() ); aRet = concatSequences( aRet, ODatabaseForm_BASE2::getTypes(), ODatabaseForm_BASE3::getTypes() ); return concatSequences( aRet, OPropertySetAggregationHelper::getTypes() ); } //------------------------------------------------------------------ Any SAL_CALL ODatabaseForm::queryAggregation(const Type& _rType) throw(RuntimeException) { Any aReturn = ODatabaseForm_BASE1::queryInterface(_rType); // our own interfaces if (!aReturn.hasValue()) { aReturn = ODatabaseForm_BASE2::queryInterface(_rType); // property set related interfaces if (!aReturn.hasValue()) { aReturn = OPropertySetAggregationHelper::queryInterface(_rType); // form component collection related interfaces if (!aReturn.hasValue()) { aReturn = OFormComponents::queryAggregation(_rType); // interfaces already present in the aggregate which we want to reroute // only available if we could create the aggregate if (!aReturn.hasValue() && m_xAggregateAsRowSet.is()) aReturn = ODatabaseForm_BASE3::queryInterface(_rType); // aggregate interfaces // (ask the aggregated object _after_ the OComponentHelper (base of OFormComponents), // so calls to the XComponent interface reach us and not the aggreagtion) if (!aReturn.hasValue() && m_xAggregate.is()) aReturn = m_xAggregate->queryAggregation(_rType); } } } return aReturn; } DBG_NAME(ODatabaseForm); //------------------------------------------------------------------ ODatabaseForm::ODatabaseForm(const Reference& _rxFactory) :OFormComponents(_rxFactory) ,OPropertySetAggregationHelper(OComponentHelper::rBHelper) ,OPropertyChangeListener(m_aMutex) ,m_aLoadListeners(m_aMutex) ,m_aRowSetApproveListeners(m_aMutex) ,m_aRowSetListeners(m_aMutex) ,m_aResetListeners( *this, m_aMutex ) ,m_aSubmitListeners(m_aMutex) ,m_aErrorListeners(m_aMutex) ,m_bLoaded(sal_False) ,m_bSubForm(sal_False) ,m_eNavigation(NavigationBarMode_CURRENT) ,m_nPrivileges(0) ,m_aParameterManager( m_aMutex, _rxFactory ) ,m_aFilterManager( _rxFactory ) ,m_pThread(NULL) ,m_eSubmitMethod(FormSubmitMethod_GET) ,m_eSubmitEncoding(FormSubmitEncoding_URL) ,m_bAllowDelete(sal_True) ,m_bAllowUpdate(sal_True) ,m_bAllowInsert(sal_True) ,m_pLoadTimer(NULL) ,m_nResetsPending(0) ,m_bForwardingConnection(sal_False) ,m_pAggregatePropertyMultiplexer(NULL) ,m_bSharingConnection( sal_False ) ,m_bInsertOnly( sal_False ) { DBG_CTOR(ODatabaseForm,NULL); // aggregate a row set increment(m_refCount); { m_xAggregate = Reference(m_xServiceFactory->createInstance(SRV_SDB_ROWSET), UNO_QUERY); // m_xAggregate = Reference(m_xServiceFactory->createInstance(rtl::OUString::createFromAscii("com.sun.star.sdb.dbaccess.ORowSet")), UNO_QUERY); DBG_ASSERT(m_xAggregate.is(), "ODatabaseForm::ODatabaseForm : could not instantiate an SDB rowset !"); m_xAggregateAsRowSet = Reference (m_xAggregate,UNO_QUERY); setAggregation(m_xAggregate); } // listen for the properties, important for Parameters if (m_xAggregateSet.is()) { m_pAggregatePropertyMultiplexer = new OPropertyChangeMultiplexer(this, m_xAggregateSet, sal_False); m_pAggregatePropertyMultiplexer->acquire(); m_pAggregatePropertyMultiplexer->addProperty(PROPERTY_COMMAND); m_pAggregatePropertyMultiplexer->addProperty(PROPERTY_ACTIVE_CONNECTION); } if (m_xAggregate.is()) { m_xAggregate->setDelegator(static_cast(this)); } { m_aFilterManager.initialize( this, m_xAggregateSet ); m_aParameterManager.initialize( this, m_xAggregate ); declareForwardedProperty( PROPERTY_ID_ACTIVE_CONNECTION ); } decrement(m_refCount); m_pGroupManager = new OGroupManager(this); m_pGroupManager->acquire(); } //------------------------------------------------------------------ ODatabaseForm::~ODatabaseForm() { DBG_DTOR(ODatabaseForm,NULL); m_pGroupManager->release(); if (m_xAggregate.is()) m_xAggregate->setDelegator(InterfaceRef()); if (m_pAggregatePropertyMultiplexer) { m_pAggregatePropertyMultiplexer->dispose(); m_pAggregatePropertyMultiplexer->release(); m_pAggregatePropertyMultiplexer = NULL; } } //============================================================================== // html tools //------------------------------------------------------------------------ ::rtl::OUString ODatabaseForm::GetDataURLEncoded(const Reference& SubmitButton, const ::com::sun::star::awt::MouseEvent& MouseEvt) { // Liste von successful Controls fuellen HtmlSuccessfulObjList aSuccObjList; FillSuccessfulList( aSuccObjList, SubmitButton, MouseEvt ); // Liste zu ::rtl::OUString zusammensetzen ::rtl::OUString aResult; ::rtl::OUString aName; ::rtl::OUString aValue; for ( HtmlSuccessfulObjListIterator pSuccObj = aSuccObjList.begin(); pSuccObj < aSuccObjList.end(); ++pSuccObj ) { aName = pSuccObj->aName; aValue = pSuccObj->aValue; if( pSuccObj->nRepresentation == SUCCESSFUL_REPRESENT_FILE && aValue.getLength() ) { // Bei File-URLs wird der Dateiname und keine URL uebertragen, // weil Netscape dies so macht. INetURLObject aURL; aURL.SetSmartProtocol(INET_PROT_FILE); aURL.SetSmartURL(aValue); if( INET_PROT_FILE == aURL.GetProtocol() ) aValue = INetURLObject::decode(aURL.PathToFileName(), '%', INetURLObject::DECODE_UNAMBIGUOUS); } Encode( aName ); Encode( aValue ); aResult += aName; aResult += UniString('='); aResult += aValue; if (pSuccObj < aSuccObjList.end() - 1) aResult += UniString('&'); } aSuccObjList.clear(); return aResult; } //============================================================================== // html tools //------------------------------------------------------------------------ ::rtl::OUString ODatabaseForm::GetDataTextEncoded(const Reference& SubmitButton, const ::com::sun::star::awt::MouseEvent& MouseEvt) { // Liste von successful Controls fuellen HtmlSuccessfulObjList aSuccObjList; FillSuccessfulList( aSuccObjList, SubmitButton, MouseEvt ); // Liste zu ::rtl::OUString zusammensetzen ::rtl::OUString aResult; ::rtl::OUString aName; ::rtl::OUString aValue; for ( HtmlSuccessfulObjListIterator pSuccObj = aSuccObjList.begin(); pSuccObj < aSuccObjList.end(); ++pSuccObj ) { aName = pSuccObj->aName; aValue = pSuccObj->aValue; if (pSuccObj->nRepresentation == SUCCESSFUL_REPRESENT_FILE && aValue.getLength()) { // Bei File-URLs wird der Dateiname und keine URL uebertragen, // weil Netscape dies so macht. INetURLObject aURL; aURL.SetSmartProtocol(INET_PROT_FILE); aURL.SetSmartURL(aValue); if( INET_PROT_FILE == aURL.GetProtocol() ) aValue = INetURLObject::decode(aURL.PathToFileName(), '%', INetURLObject::DECODE_UNAMBIGUOUS); } Encode( aName ); Encode( aValue ); aResult += pSuccObj->aName; aResult += UniString('='); aResult += pSuccObj->aValue; if (pSuccObj < aSuccObjList.end() - 1) aResult += ::rtl::OUString::createFromAscii("\r\n"); } // Liste loeschen aSuccObjList.clear(); return aResult; } //------------------------------------------------------------------------ Sequence ODatabaseForm::GetDataMultiPartEncoded(const Reference& SubmitButton, const ::com::sun::star::awt::MouseEvent& MouseEvt, ::rtl::OUString& rContentType) { // Parent erzeugen INetMIMEMessage aParent; aParent.EnableAttachChild( INETMSG_MULTIPART_FORM_DATA ); // Liste von successful Controls fuellen HtmlSuccessfulObjList aSuccObjList; FillSuccessfulList( aSuccObjList, SubmitButton, MouseEvt ); // Liste zu ::rtl::OUString zusammensetzen ::rtl::OUString aResult; for ( HtmlSuccessfulObjListIterator pSuccObj = aSuccObjList.begin(); pSuccObj < aSuccObjList.end(); ++pSuccObj ) { if( pSuccObj->nRepresentation == SUCCESSFUL_REPRESENT_TEXT ) InsertTextPart( aParent, pSuccObj->aName, pSuccObj->aValue ); else if( pSuccObj->nRepresentation == SUCCESSFUL_REPRESENT_FILE ) InsertFilePart( aParent, pSuccObj->aName, pSuccObj->aValue ); } // Liste loeschen aSuccObjList.clear(); // Fuer Parent MessageStream erzeugen INetMIMEMessageStream aMessStream; aMessStream.SetSourceMessage( &aParent ); aMessStream.GenerateHeader( sal_False ); // MessageStream in SvStream kopieren SvMemoryStream aMemStream; char* pBuf = new char[1025]; int nRead; while( (nRead = aMessStream.Read(pBuf, 1024)) > 0 ) aMemStream.Write( pBuf, nRead ); delete[] pBuf; aMemStream.Flush(); aMemStream.Seek( 0 ); void* pData = (void*)aMemStream.GetData(); sal_Int32 nLen = aMemStream.Seek(STREAM_SEEK_TO_END); rContentType = UniString(aParent.GetContentType()); return Sequence((sal_Int8*)pData, nLen); } //------------------------------------------------------------------------ namespace { static void appendDigits( sal_Int32 _nNumber, sal_Int8 nDigits, ::rtl::OUStringBuffer& _rOut ) { sal_Int32 nCurLen = _rOut.getLength(); _rOut.append( _nNumber ); while ( _rOut.getLength() - nCurLen < nDigits ) _rOut.insert( nCurLen, (sal_Unicode)'0' ); } } //------------------------------------------------------------------------ void ODatabaseForm::AppendComponent(HtmlSuccessfulObjList& rList, const Reference& xComponentSet, const ::rtl::OUString& rNamePrefix, const Reference& rxSubmitButton, const ::com::sun::star::awt::MouseEvent& MouseEvt) { if (!xComponentSet.is()) return; // MIB 25.6.98: Geschachtelte Formulare abfangen ... oder muesste // man sie submitten? if (!hasProperty(PROPERTY_CLASSID, xComponentSet)) return; // Namen ermitteln if (!hasProperty(PROPERTY_NAME, xComponentSet)) return; sal_Int16 nClassId; xComponentSet->getPropertyValue(PROPERTY_CLASSID) >>= nClassId; ::rtl::OUString aName; xComponentSet->getPropertyValue( PROPERTY_NAME ) >>= aName; if( !aName.getLength() && nClassId != FormComponentType::IMAGEBUTTON) return; else // Name um den Prefix erweitern aName = rNamePrefix + aName; switch( nClassId ) { // Buttons case FormComponentType::COMMANDBUTTON: { // Es wird nur der gedrueckte Submit-Button ausgewertet // MIB: Sofern ueberhaupt einer uebergeben wurde if( rxSubmitButton.is() ) { Reference xSubmitButtonComponent(rxSubmitButton->getModel(), UNO_QUERY); if (xSubmitButtonComponent == xComponentSet && hasProperty(PROPERTY_LABEL, xComponentSet)) { // =