diff options
author | Jens-Heiner Rechtien <hr@openoffice.org> | 2004-04-13 10:00:14 +0000 |
---|---|---|
committer | Jens-Heiner Rechtien <hr@openoffice.org> | 2004-04-13 10:00:14 +0000 |
commit | 693b5dd88c6a5d32df543dd908260fcb414ba5e1 (patch) | |
tree | 586cb5d1d07509b4b00960dc2b40b5f8630ad475 /svx/source/form | |
parent | 11bc713852092c730ccf7f3e55eb9e39d3a30bf1 (diff) |
INTEGRATION: CWS frmcontrols02 (1.1.2); FILE ADDED
2004/03/30 07:17:18 fs 1.1.2.4: #100000#
2004/03/29 07:30:02 fs 1.1.2.3: #100000
2004/02/02 07:52:12 fs 1.1.2.2: #i24409#
2004/01/22 10:35:20 fs 1.1.2.1: helper class for form controller related functionality
Diffstat (limited to 'svx/source/form')
-rw-r--r-- | svx/source/form/formcontrolling.cxx | 1778 |
1 files changed, 1778 insertions, 0 deletions
diff --git a/svx/source/form/formcontrolling.cxx b/svx/source/form/formcontrolling.cxx new file mode 100644 index 000000000000..77b3cc14e869 --- /dev/null +++ b/svx/source/form/formcontrolling.cxx @@ -0,0 +1,1778 @@ +/************************************************************************* + * + * $RCSfile: formcontrolling.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: hr $ $Date: 2004-04-13 11:00:14 $ + * + * 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 EXPRESS 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): _______________________________________ + * + * + ************************************************************************/ + +#ifndef SVX_FORMCONTROLLING_HXX +#include "formcontrolling.hxx" +#endif + +#ifndef _OSL_DIAGNOSE_H_ +#include <osl/diagnose.h> +#endif +#ifndef _CPPUHELPER_IMPLBASE1_HXX_ +#include <cppuhelper/implbase1.hxx> +#endif +#ifndef _COMPHELPER_PROPERTY_HXX_ +#include <comphelper/property.hxx> +#endif +#ifndef _COMPHELPER_PROCESSFACTORY_HXX_ +#include <comphelper/processfactory.hxx> +#endif +#ifndef _SV_WAITOBJ_HXX +#include <vcl/waitobj.hxx> +#endif +#ifndef _SV_MSGBOX_HXX +#include <vcl/msgbox.hxx> +#endif +#ifndef _VCL_STDTEXT_HXX +#include <vcl/stdtext.hxx> +#endif + +#ifndef _SVX_FMPROP_HRC +#include "fmprop.hrc" +#endif +#ifndef _SVX_SVXIDS_HRC +#include "svxids.hrc" +#endif +#ifndef _SVX_FMRESIDS_HRC +#include "fmresids.hrc" +#endif +#ifndef _SVX_DIALMGR_HXX +#include "dialmgr.hxx" +#endif +#ifndef _SVX_FMTOOLS_HXX +#include "fmtools.hxx" +#endif +#ifndef _SVX_FMURL_HXX +#include "fmurl.hxx" +#endif + +#ifndef _COM_SUN_STAR_SDBC_XROWSET_HPP_ +#include <com/sun/star/sdbc/XRowSet.hpp> +#endif +#ifndef _COM_SUN_STAR_AWT_XCONTROL_HPP_ +#include <com/sun/star/awt/XControl.hpp> +#endif +#ifndef _COM_SUN_STAR_FORM_XBOUNDCONTROL_HPP_ +#include <com/sun/star/form/XBoundControl.hpp> +#endif +#ifndef _COM_SUN_STAR_FORM_XCONFIRMDELETELISTENER_HPP_ +#include <com/sun/star/form/XConfirmDeleteListener.hpp> +#endif +#ifndef _COM_SUN_STAR_FORM_XBOUNDCOMPONENT_HPP_ +#include <com/sun/star/form/XBoundComponent.hpp> +#endif +#ifndef _COM_SUN_STAR_SDBCX_XROWLOCATE_HPP_ +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#endif +#ifndef _COM_SUN_STAR_SDB_ROWCHANGEEVENT_HPP_ +#include <com/sun/star/sdb/RowChangeEvent.hpp> +#endif +#ifndef _COM_SUN_STAR_SDB_ROWCHANGEACTION_HPP_ +#include <com/sun/star/sdb/RowChangeAction.hpp> +#endif +#ifndef _COM_SUN_STAR_SDB_XSQLQUERYCOMPOSERFACTORY_HPP_ +#include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp> +#endif +#ifndef _COM_SUN_STAR_SDB_SQLCONTEXT_HPP_ +#include <com/sun/star/sdb/SQLContext.hpp> +#endif +#ifndef _COM_SUN_STAR_CONTAINER_XINDEXACCESS_HPP_ +#include <com/sun/star/container/XIndexAccess.hpp> +#endif +#ifndef _COM_SUN_STAR_FORM_XRESET_HPP_ +#include <com/sun/star/form/XReset.hpp> +#endif +#ifndef _COM_SUN_STAR_BEANS_XMULTIPROPERTYSET_HPP_ +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#endif +#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_ +#include <com/sun/star/lang/XComponent.hpp> +#endif +#ifndef _COM_SUN_STAR_FORM_XGRID_HPP_ +#include <com/sun/star/form/XGrid.hpp> +#endif +#ifndef _COM_SUN_STAR_UI_DIALOGS_XEXECUTABLEDIALOG_HPP_ +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#endif +#ifndef _COM_SUN_STAR_UTIL_XMODIFYBROADCASTER_HPP_ +#include <com/sun/star/util/XModifyBroadcaster.hpp> +#endif + +//........................................................................ +namespace svx +{ +//........................................................................ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::util; + 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::ui::dialogs; + using namespace ::svxform; + + //==================================================================== + //= FeatureSlotTranslation + //==================================================================== + namespace + { + //................................................................ + void getTranslationTables( ::rtl::OUString const** _ppURLs, ::rtl::OUString const** _ppURLsEnd, + sal_Int32 const** _ppIds, sal_Int32 const** _ppIdsEnd ) + { + static const ::rtl::OUString aURLs[] = + { + FMURL_FORM_POSITION, + FMURL_FORM_RECORDCOUNT, + FMURL_RECORD_MOVEFIRST, + FMURL_RECORD_MOVEPREV, + FMURL_RECORD_MOVENEXT, + FMURL_RECORD_MOVELAST, + FMURL_RECORD_MOVETONEW, + FMURL_RECORD_SAVE, + FMURL_RECORD_DELETE, + FMURL_FORM_REFRESH, + FMURL_RECORD_UNDO, + FMURL_FORM_SORT_UP, + FMURL_FORM_SORT_DOWN, + FMURL_FORM_SORT, + FMURL_FORM_AUTO_FILTER, + FMURL_FORM_FILTER, + FMURL_FORM_APPLY_FILTER, + FMURL_FORM_REMOVE_FILTER + }; + static const sal_Int32 aSlots[] = + { + SID_FM_RECORD_ABSOLUTE, + SID_FM_RECORD_TOTAL, + SID_FM_RECORD_FIRST, + SID_FM_RECORD_PREV, + SID_FM_RECORD_NEXT, + SID_FM_RECORD_LAST, + SID_FM_RECORD_NEW, + SID_FM_RECORD_SAVE, + SID_FM_RECORD_DELETE, + SID_FM_REFRESH, + SID_FM_RECORD_UNDO, + SID_FM_SORTUP, + SID_FM_SORTDOWN, + SID_FM_ORDERCRIT, + SID_FM_AUTOFILTER, + SID_FM_FILTERCRIT, + SID_FM_FORM_FILTERED, + SID_FM_REMOVE_FILTER_SORT + }; + if ( _ppURLs ) *_ppURLs = aURLs; + if ( _ppURLsEnd ) *_ppURLsEnd = aURLs + ( sizeof( aURLs ) / sizeof( aURLs[0] ) ); + if ( _ppIds ) *_ppIds = aSlots; + if ( _ppIdsEnd ) *_ppIdsEnd = aSlots + ( sizeof( aSlots ) / sizeof( aSlots[0] ) ); + + OSL_ENSURE( ( sizeof( aURLs ) / sizeof( aURLs[0] ) ) == ( sizeof( aSlots ) / sizeof( aSlots[0] ) ), + "FeatureSlotTranslation::getTranslationTables: inconsistence!" ); + } + } + + //-------------------------------------------------------------------- + sal_Int32 FeatureSlotTranslation::getControllerFeatureIdForURL( const ::rtl::OUString& _rMainURL ) + { + const ::rtl::OUString* pURLs = NULL; + const ::rtl::OUString* pURLsEnd = NULL; + const sal_Int32* pIds = NULL; + getTranslationTables( &pURLs, &pURLsEnd, &pIds, NULL ); + + for ( ; pURLs < pURLsEnd; ++pURLs, ++pIds ) + { + if ( _rMainURL.equals( *pURLs ) ) + return *pIds; + } + return -1; + } + + //-------------------------------------------------------------------- + ::rtl::OUString FeatureSlotTranslation::getControllerFeatureURLForId( sal_Int32 _nId ) + { + const ::rtl::OUString* pURLs = NULL; + const sal_Int32* pIds = NULL; + const sal_Int32* pIdsEnd = NULL; + getTranslationTables( &pURLs, NULL, &pIds, &pIdsEnd ); + + for ( ; pIds < pIdsEnd; ++pURLs, ++pIds ) + { + if ( _nId == *pIds ) + return *pURLs; + } + return ::rtl::OUString(); + } + + //-------------------------------------------------------------------- + sal_Bool FeatureSlotTranslation::isFeatureURL( const ::rtl::OUString& _rMainURL ) + { + return ( _rMainURL.indexOf( FMURL_FORMSLOTS_PREFIX ) == 0 ); + } + + //==================================================================== + //= ControllerFeatures + //==================================================================== + //-------------------------------------------------------------------- + ControllerFeatures::ControllerFeatures( const Reference< XMultiServiceFactory >& _rxORB, IControllerFeatureInvalidation* _pInvalidationCallback ) + :m_xORB( _rxORB ) + ,m_pImpl( NULL ) + ,m_pInvalidationCallback( _pInvalidationCallback ) + { + } + + //-------------------------------------------------------------------- + ControllerFeatures::ControllerFeatures( const Reference< XMultiServiceFactory >& _rxORB, + const Reference< XFormController >& _rxController, IControllerFeatureInvalidation* _pInvalidationCallback ) + :m_xORB( _rxORB ) + ,m_pImpl( NULL ) + ,m_pInvalidationCallback( _pInvalidationCallback ) + { + assign( _rxController ); + } + + //-------------------------------------------------------------------- + ControllerFeatures::ControllerFeatures( const Reference< XMultiServiceFactory >& _rxORB, + const Reference< XForm >& _rxForm, IControllerFeatureInvalidation* _pInvalidationCallback ) + :m_xORB( _rxORB ) + ,m_pImpl( NULL ) + ,m_pInvalidationCallback( _pInvalidationCallback ) + { + assign( _rxForm ); + } + + //-------------------------------------------------------------------- + void ControllerFeatures::assign( const Reference< XFormController >& _rxController ) + { + dispose(); + m_pImpl = new FormControllerHelper( m_xORB, _rxController, m_pInvalidationCallback ); + m_pImpl->acquire(); + } + + //-------------------------------------------------------------------- + void ControllerFeatures::assign( const Reference< XForm >& _rxForm ) + { + dispose(); + m_pImpl = new FormControllerHelper( m_xORB, _rxForm, m_pInvalidationCallback ); + m_pImpl->acquire(); + } + + //-------------------------------------------------------------------- + ControllerFeatures::~ControllerFeatures() + { + dispose(); + } + + //-------------------------------------------------------------------- + void ControllerFeatures::dispose() + { + if ( m_pImpl ) + { + m_pImpl->dispose(); + m_pImpl->release(); + m_pImpl = NULL; + } + } + + //==================================================================== + //= FormControllerHelper + //==================================================================== + //-------------------------------------------------------------------- + FormControllerHelper::FormControllerHelper( const Reference< XMultiServiceFactory >& _rxORB, + const Reference< XFormController >& _rxController, IControllerFeatureInvalidation* _pInvalidationCallback ) + :m_xORB( _rxORB ) + ,m_bInitializedParser( sal_False ) + ,m_bActiveControlModified( sal_False ) + ,m_pInvalidationCallback( _pInvalidationCallback ) + { + OSL_ENSURE( m_xORB.is(), "FormControllerHelper::FormControllerHelper: gimme a service factory!" ); + + initController( _rxController ); + + // TODO: add as dispose listener to the controller/form + // Or should we define that this is the responsibility of our owner? + + m_pDbTools = new ::svxform::OStaticDataAccessTools; + } + + //-------------------------------------------------------------------- + FormControllerHelper::FormControllerHelper( const Reference< XMultiServiceFactory >& _rxORB, + const Reference< XForm >& _rxForm, IControllerFeatureInvalidation* _pInvalidationCallback ) + :m_xORB( _rxORB ) + ,m_bInitializedParser( sal_False ) + ,m_bActiveControlModified( sal_False ) + ,m_pInvalidationCallback( _pInvalidationCallback ) + { + OSL_ENSURE( m_xORB.is(), "FormControllerHelper::FormControllerHelper: gimme a service factory!" ); + + initCursor( _rxForm.get() ); + + // TODO: add as dispose listener to the form + // Or should we define that this is the responsibility of our owner? + + m_pDbTools = new ::svxform::OStaticDataAccessTools; + } + + //-------------------------------------------------------------------- + FormControllerHelper::~FormControllerHelper( ) + { + if ( m_xController.is() || hasCursor() ) + { // not yet disposed + acquire(); + dispose(); + } + + if ( m_pDbTools ) + { + delete m_pDbTools; + m_pDbTools = NULL; + } + } + + //------------------------------------------------------------------------------ + void SAL_CALL FormControllerHelper::cursorMoved(const EventObject& event) throw( RuntimeException ) + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + OSL_ENSURE( m_xCursor.is(), "FormControllerHelper::cursorMoved: already disposed!" ); + m_bActiveControlModified = sal_False; + + invalidateAllSupportedFeatures( aGuard ); + } + + //-------------------------------------------------------------------- + void SAL_CALL FormControllerHelper::rowChanged( const EventObject& event ) throw (RuntimeException) + { + // not interested in + } + + //-------------------------------------------------------------------- + void SAL_CALL FormControllerHelper::rowSetChanged( const EventObject& event ) throw (RuntimeException) + { + // not interested in + } + + //-------------------------------------------------------------------- + void SAL_CALL FormControllerHelper::modified( const EventObject& _rSource ) throw( RuntimeException ) + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + + OSL_ENSURE( m_xCursor.is(), "FormControllerHelper::modified: already disposed!" ); + if ( !m_bActiveControlModified ) + { + m_bActiveControlModified = sal_True; + invalidateModifyDependentFeatures( aGuard ); + } + } + + //-------------------------------------------------------------------- + void SAL_CALL FormControllerHelper::propertyChange( const PropertyChangeEvent& _rEvent ) throw (RuntimeException) + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + + if ( m_xCursor.is() && ( m_xCursor == _rEvent.Source ) ) + { + sal_Bool bIs = sal_False; + if ( ( _rEvent.PropertyName == FM_PROP_ISMODIFIED ) + || ( _rEvent.PropertyName == FM_PROP_ISNEW ) + ) + { + if ( ( _rEvent.NewValue >>= bIs ) && !bIs ) + m_bActiveControlModified = sal_False; + } + invalidateAllSupportedFeatures( aGuard ); + } + if ( m_xParser.is() && ( m_xCursor == _rEvent.Source ) ) + { + try + { + ::rtl::OUString sNewValue; + _rEvent.NewValue >>= sNewValue; + if ( _rEvent.PropertyName == FM_PROP_ACTIVECOMMAND ) + { + m_xParser->setQuery( sNewValue ); + } + else if ( _rEvent.PropertyName == FM_PROP_FILTER_CRITERIA ) + { + if ( m_xParser->getFilter() != sNewValue ) + m_xParser->setFilter( sNewValue ); + } + else if ( _rEvent.PropertyName == FM_PROP_SORT ) + { + _rEvent.NewValue >>= sNewValue; + if ( m_xParser->getOrder() != sNewValue ) + m_xParser->setOrder( sNewValue ); + } + + invalidateAllSupportedFeatures( aGuard ); + } + catch( Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::propertyChange: caught an exception while updating the parser!" ); + } + + } + } + + //-------------------------------------------------------------------- + void SAL_CALL FormControllerHelper::disposing( const EventObject& _rSource ) throw (RuntimeException) + { + // not interested in + } + + //-------------------------------------------------------------------- + void FormControllerHelper::dispose() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + disposeParser(); + + // + // revoke various listeners + if ( m_xCursor.is() ) + m_xCursor->removeRowSetListener( this ); + + if ( m_xCursorProperties.is() ) + { + m_xCursorProperties->removePropertyChangeListener( FM_PROP_ISMODIFIED,this ); + m_xCursorProperties->removePropertyChangeListener( FM_PROP_ISNEW, this ); + } + + Reference< XModifyBroadcaster > xBroadcaster( m_xController, UNO_QUERY ); + if ( xBroadcaster.is() ) + xBroadcaster->removeModifyListener( this ); + + // + m_xController.clear(); + m_xCursor.clear(); + m_xUpdateCursor.clear(); + m_xCursorProperties.clear(); + m_xLoadableForm.clear(); + + m_bActiveControlModified = sal_True; + } + + //-------------------------------------------------------------------- + void FormControllerHelper::initController( const Reference< XFormController >& _rxController ) + { + m_xController = _rxController; + OSL_ENSURE( m_xController.is(), "FormControllerHelper::initController: invalid controller!" ); + if ( m_xController.is() ) + initCursor( m_xController->getModel().get() ); + + Reference< XModifyBroadcaster > xBroadcaster( m_xController, UNO_QUERY ); + if ( xBroadcaster.is() ) + xBroadcaster->addModifyListener( this ); + } + + //-------------------------------------------------------------------- + void FormControllerHelper::initCursor( const Reference< XInterface >& _rxForm ) + { + m_xCursor = m_xCursor.query ( _rxForm ); + m_xCursorProperties = m_xCursorProperties.query ( m_xCursor ); + m_xUpdateCursor = m_xUpdateCursor.query ( m_xCursor ); + m_xLoadableForm = m_xLoadableForm.query ( m_xCursor ); + + OSL_ENSURE( m_xCursor.is() && m_xCursorProperties.is() && m_xLoadableForm.is(), + "FormControllerHelper::initCursor: could not obtain necessary cursor interfaces!" ); + + if ( m_xCursorProperties.is() ) + { + m_xCursorProperties->addPropertyChangeListener( FM_PROP_ISMODIFIED,this ); + m_xCursorProperties->addPropertyChangeListener( FM_PROP_ISNEW, this ); + } + + if ( m_xCursor.is() ) + m_xCursor->addRowSetListener( this ); + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::getSimpleState( sal_Int32 _nFeatureId ) const + { + ControllerFeatureState aState; + getState( _nFeatureId, aState ); + return aState.bEnabled; + } + + //-------------------------------------------------------------------- + void FormControllerHelper::getState( sal_Int32 _nFeatureId, ControllerFeatureState& _rState ) const + { + _rState.aState.clear(); + _rState.bEnabled = sal_False; + + ::osl::MutexGuard aGuard( m_aMutex ); + try + { + // some checks for basic pre-requisites + if ( !m_xLoadableForm.is() + || !m_xLoadableForm->isLoaded() + || !m_xCursorProperties.is() + ) + { + return; + } + + switch ( _nFeatureId ) + { + case SID_FM_RECORD_FIRST: + case SID_FM_RECORD_PREV: + _rState.bEnabled = canMoveLeft( ); + break; + + case SID_FM_RECORD_NEXT: + if ( isNewRecord() && m_bActiveControlModified ) + // if the form is on the insert row, and the current + // control is modified, then the slot is enabled, too + _rState.bEnabled = sal_True; + else + _rState.bEnabled = canMoveRight(); + break; + + case SID_FM_RECORD_LAST: + _rState.bEnabled = getRecordCount() && ( !m_xCursor->isLast() || isNewRecord() ); + break; + + case SID_FM_RECORD_DELETE: + // already deleted ? + if ( m_xCursor->rowDeleted() ) + _rState.bEnabled = sal_False; + else + { + // allowed to delete the row ? + _rState.bEnabled = !isNewRecord() && m_pDbTools->canDelete( m_xCursorProperties ); + } + break; + + case SID_FM_RECORD_NEW: + // if we are inserting we can move to the next row if the current record or control is modified + _rState.bEnabled = isNewRecord() + ? isModifiedRecord() || m_bActiveControlModified + : m_pDbTools->canInsert( m_xCursorProperties ); + break; + + case SID_FM_REFRESH: + { + // there must be an active connection + Reference< XRowSet > xCursorRowSet( m_xCursor, UNO_QUERY ); + _rState.bEnabled = m_pDbTools->getRowSetConnection( xCursorRowSet ).is(); + + // and an active command + ::rtl::OUString sActiveCommand; + m_xCursorProperties->getPropertyValue( FM_PROP_ACTIVECOMMAND ) >>= sActiveCommand; + _rState.bEnabled &= sActiveCommand.getLength() > 0; + } + break; + + case SID_FM_RECORD_SAVE: + case SID_FM_RECORD_UNDO: + _rState.bEnabled = isModifiedRecord() || m_bActiveControlModified; + break; + + case SID_FM_REMOVE_FILTER_SORT: + if ( isParsable() && hasFilterOrOrder() ) + { + _rState.bEnabled = !isInsertOnlyForm(); + } + break; + + case SID_FM_SORTUP: + case SID_FM_SORTDOWN: + case SID_FM_AUTOFILTER: + if ( m_xController.is() && isParsable() ) + { + sal_Bool bIsDeleted = m_xCursor->rowDeleted(); + + if ( !bIsDeleted && !isInsertOnlyForm() ) + { + Reference< XPropertySet > xBoundField = getCurrentBoundField( ); + if ( xBoundField.is() ) + xBoundField->getPropertyValue( FM_PROP_SEARCHABLE ) >>= _rState.bEnabled; + } + } + break; + + case SID_FM_ORDERCRIT: + case SID_FM_FILTERCRIT: + if ( isParsable() ) + { + _rState.bEnabled = !isInsertOnlyForm(); + } + break; + + case SID_FM_FORM_FILTERED: + { + ::rtl::OUString sFilter; + m_xCursorProperties->getPropertyValue( FM_PROP_FILTER_CRITERIA ) >>= sFilter; + if ( sFilter.getLength() ) + { + _rState.aState = m_xCursorProperties->getPropertyValue( FM_PROP_APPLYFILTER ); + _rState.bEnabled = !isInsertOnlyForm(); + } + else + _rState.aState <<= (sal_Bool)sal_False; + } + break; + + case SID_FM_RECORD_ABSOLUTE: + { + sal_Int32 nPosition = m_xCursor->getRow(); + sal_Bool bIsNew = isNewRecord(); + sal_Int32 nCount = getRecordCount(); + sal_Bool bFinalCount = isRecordCountFinal(); + + if ( ( nPosition >= 0 ) || bIsNew ) + { + if ( bFinalCount ) + { + // special case: there are no records at all, and we + // can't insert records -> disabled + if ( !nCount && !m_pDbTools->canInsert( m_xCursorProperties ) ) + { + _rState.bEnabled = sal_False; + } + else + { + if ( bIsNew ) + nPosition = ++nCount; + _rState.aState <<= (sal_Int32)nPosition; + _rState.bEnabled = sal_True; + } + } + else + { + _rState.aState <<= (sal_Int32)nPosition; + _rState.bEnabled = sal_True; + } + } + } + break; + + case SID_FM_RECORD_TOTAL: + { + sal_Bool bIsNew = isNewRecord(); + sal_Int32 nCount = getRecordCount(); + sal_Bool bFinalCount = isRecordCountFinal(); + + if ( bIsNew ) + ++nCount; + + ::rtl::OUString sValue = ::rtl::OUString::valueOf( sal_Int32( nCount ) ); + if ( !bFinalCount ) + sValue += String::CreateFromAscii(" *"); + + _rState.aState <<= sValue; + _rState.bEnabled = sal_True; + } + break; + + default: + OSL_ENSURE( sal_False, "FormControllerHelper::getState: unknown feature id!" ); + break; + } + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::getState: caught an exception!" ); + } + } + + //------------------------------------------------------------------------------ + void FormControllerHelper::appendOrderByColumn( const void* _pActionParam ) const + { + const param_appendOrderByColumn* pParam = static_cast< const param_appendOrderByColumn* >( _pActionParam ); + m_xParser->appendOrderByColumn( pParam->xField, pParam->bUp ); + } + + //------------------------------------------------------------------------------ + void FormControllerHelper::appendFilterByColumn( const void* _pActionParam ) const + { + const param_appendFilterByColumn* pParam = static_cast< const param_appendFilterByColumn* >( _pActionParam ); + m_xParser->appendFilterByColumn( pParam->xField ); + } + + //------------------------------------------------------------------------------ + sal_Bool FormControllerHelper::doActionReportError( Action _pAction, const void* _pParam, sal_uInt16 _nErrorResourceId ) const + { + sal_Bool bSuccess = sal_False; + try + { + (this->*_pAction)( _pParam ); + bSuccess = sal_True; + } + catch( SQLException e ) + { + if ( _nErrorResourceId ) + { + String aAdditionalError( SVX_RES( _nErrorResourceId ) ); + SQLContext aExtendedInfo( m_pDbTools->prependContextInfo( e, NULL, aAdditionalError, ::rtl::OUString() ) ); + + displayException( aExtendedInfo ); + } + else + displayException( e ); + } + catch( Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::doActionReportError: caught a non-SQL exception!" ); + } + + return bSuccess; + } + + //------------------------------------------------------------------------------ + void FormControllerHelper::executeAutoSort( sal_Bool _bUp ) const + { + OSL_PRECOND( m_xController.is(), "FormControllerHelper::executeAutoSort: need a controller for this!" ); + OSL_PRECOND( hasCursor(), "FormControllerHelper::executeAutoSort: need a cursor for this!" ); + OSL_PRECOND( isParsable(), "FormControllerHelper::executeAutoSort: need a parseable statement for this!" ); + if ( !m_xController.is() || !hasCursor() || !isParsable() ) + return; + + Reference< XControl > xControl = m_xController->getCurrentControl(); + if ( xControl.is() && commitCurrentControl() && commitCurrentRecord() ) + { + Reference< XPropertySet > xBoundField( getCurrentBoundField() ); + if ( xBoundField.is() ) + { + ::rtl::OUString sOriginalSort; + m_xCursorProperties->getPropertyValue( FM_PROP_SORT ) >>= sOriginalSort; + + // automatic sort by field always resets the previous sort order + try + { + m_xParser->setOrder( ::rtl::OUString() ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::executeAutoFilter: could not reset the parser's order!" ); + } + + sal_Bool bParserSuccess = sal_True; + + param_appendOrderByColumn aParam; + aParam.xField = xBoundField; + aParam.bUp = _bUp; + if ( doActionReportError( (Action)&FormControllerHelper::appendOrderByColumn, static_cast< const void* >( &aParam ), (sal_uInt16)RID_STR_COULDNOTSETORDER ) ) + { + WaitObject aWO( NULL ); + try + { + m_xCursorProperties->setPropertyValue( FM_PROP_SORT, makeAny( m_xParser->getOrder() ) ); + m_xLoadableForm->reload(); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::executeAutoSort: caught an exception while setting the parser properties!" ); + } + + + if ( !m_xLoadableForm->isLoaded() ) + { // something went wrong -> restore the original state + try + { + m_xParser->setOrder( sOriginalSort ); + m_xCursorProperties->setPropertyValue( FM_PROP_SORT, makeAny( m_xParser->getOrder() ) ); + m_xLoadableForm->reload(); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::executeAutoSort: could not reset the form to it's original state!" ); + } + + } + } + } + } + } + + //------------------------------------------------------------------------------ + void FormControllerHelper::executeAutoFilter( ) const + { + OSL_PRECOND( m_xController.is(), "FormControllerHelper::executeAutoFilter: need a controller for this!" ); + OSL_PRECOND( hasCursor(), "FormControllerHelper::executeAutoFilter: need a cursor for this!" ); + OSL_PRECOND( isParsable(), "FormControllerHelper::executeAutoFilter: need a parseable statement for this!" ); + if ( !m_xController.is() || !hasCursor() || !isParsable() ) + return; + + Reference< XControl > xControl = m_xController->getCurrentControl(); + if ( xControl.is() && commitCurrentControl() && commitCurrentRecord() ) + { + Reference< XPropertySet > xBoundField( getCurrentBoundField() ); + if ( xBoundField.is() ) + { + ::rtl::OUString sOriginalFilter; + m_xCursorProperties->getPropertyValue( FM_PROP_FILTER_CRITERIA ) >>= sOriginalFilter; + sal_Bool bApplied = sal_True; + m_xCursorProperties->getPropertyValue( FM_PROP_APPLYFILTER ) >>= bApplied; + + // if we have a filter, but it's not applied, then we have to overwrite it, else append one + if ( !bApplied ) + { + try + { + m_xParser->setFilter( ::rtl::OUString() ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::executeAutoFilter: could not reset the parser's filter!" ); + } + } + + param_appendFilterByColumn aParam; + aParam.xField = xBoundField; + if ( doActionReportError( (Action)&FormControllerHelper::appendFilterByColumn, static_cast< const void* >( &aParam ), (sal_uInt16)RID_STR_COULDNOTSETFILTER ) ) + { + WaitObject aWO( NULL ); + try + { + m_xCursorProperties->setPropertyValue( FM_PROP_FILTER_CRITERIA, makeAny( m_xParser->getFilter() ) ); + m_xCursorProperties->setPropertyValue( FM_PROP_APPLYFILTER, makeAny( (sal_Bool)sal_True ) ); + + m_xLoadableForm->reload(); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::executeAutoFilter: caught an exception while setting the parser properties!" ); + } + + + if ( !m_xLoadableForm->isLoaded() ) + { // something went wrong -> restore the original state + try + { + m_xParser->setOrder( sOriginalFilter ); + m_xCursorProperties->setPropertyValue( FM_PROP_APPLYFILTER, makeAny( (sal_Bool)bApplied ) ); + m_xCursorProperties->setPropertyValue( FM_PROP_FILTER_CRITERIA, makeAny( m_xParser->getFilter() ) ); + m_xLoadableForm->reload(); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::executeAutoFilter: could not reset the form to it's original state!" ); + } + + } + } + } + } + } + + //------------------------------------------------------------------------------ + Reference< XPropertySet > FormControllerHelper::getCurrentBoundField( ) const + { + OSL_PRECOND( m_xController.is(), "FormControllerHelper::getCurrentBoundField: no controller -> no control!" ); + if ( !m_xController.is() ) + return NULL; + + Reference< XControl > xControl( m_xController->getCurrentControl() ); + + // special handling for grid controls + Reference< XGrid > xGrid( xControl, UNO_QUERY ); + Reference< XPropertySet > xControlModel; + + if ( xGrid.is() ) + { + Reference< XIndexAccess > xColumns( xControl->getModel(), UNO_QUERY ); + sal_Int16 nCurrentPos = xGrid->getCurrentColumnPosition(); + nCurrentPos = GridView2ModelPos( xColumns, nCurrentPos ); + + if ( nCurrentPos != (sal_Int16)-1 ) + xColumns->getByIndex( nCurrentPos ) >>= xControlModel; + } + else if ( xControl.is() ) + { + xControlModel = xControlModel.query( xControl->getModel() ); + } + + Reference< XPropertySet > xField; + if ( xControlModel.is() && ::comphelper::hasProperty( FM_PROP_BOUNDFIELD, xControlModel ) ) + xControlModel->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField; + + return xField; + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::commitCurrentControl( ) const + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + OSL_PRECOND( m_xController.is(), "FormControllerHelper::commitCurrentControl: no controller!" ); + if ( !m_xController.is() ) + return sal_False; + + Reference< XControl > xCurrentControl( m_xController->getCurrentControl() ); + + // check whether the control is locked + Reference< XBoundControl > xCheckLock( xCurrentControl, UNO_QUERY ); + sal_Bool bControlIsLocked = xCheckLock.is() && xCheckLock->getLock(); + + // commit if necessary + sal_Bool bSuccess = sal_True; + if ( xCurrentControl.is() && !bControlIsLocked ) + { + // both the control and it's model can be committable, so try both + Reference< XBoundComponent > xBound( xCurrentControl, UNO_QUERY ); + if ( !xBound.is() ) + xBound = xBound.query( xCurrentControl->getModel() ); + // and now really commit + if ( xBound.is() ) + { + try + { + aGuard.clear(); + bSuccess = xBound->commit(); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::commitCurrentControl: caught an exception!" ); + } + } + } + return bSuccess; + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::commitCurrentRecord( sal_Bool* _pRecordInserted ) const + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + if ( _pRecordInserted ) + *_pRecordInserted = sal_False; + + if ( !hasCursor() ) + return sal_False; + + // nothing to do if the record is not modified + sal_Bool bResult = !isModifiedRecord(); + if ( !bResult ) + { + bResult = sal_False; + try + { + // clear our mutex before calling into a foreign component + Reference< XResultSetUpdate > xUpdate( m_xUpdateCursor ); + aGuard.clear(); + + // insert respectively update the row + if ( isNewRecord() ) + { + xUpdate->insertRow(); + if ( _pRecordInserted ) + *_pRecordInserted = sal_True; + } + else + xUpdate->updateRow(); + bResult = sal_True; + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::commitCurrentRecord: caught an exception!" ); + } + } + return bResult; + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::moveRight( ) const + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + OSL_PRECOND( hasCursor(), "FormControllerHelper::moveRight: no cursor!" ); + if ( !hasCursor() ) + return sal_False; + + sal_Bool bRecordInserted = sal_False; + sal_Bool bSuccess = commitCurrentRecord( &bRecordInserted ); + + if ( bSuccess ) + { + try + { + // clear our mutex before calling into a foreign component + Reference< XRowSet > xCursor( m_xCursor ); + Reference< XResultSetUpdate > xUpdate( m_xUpdateCursor ); + aGuard.clear(); + + if ( bRecordInserted ) + { + // go to insert row + xUpdate->moveToInsertRow(); + } + else + { + if ( xCursor->isLast() ) + xUpdate->moveToInsertRow(); + else + xCursor->next(); + } + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::moveRight: caught an exception!"); + bSuccess = sal_False; + } + + } + return bSuccess; + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::moveLeft( ) const + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + OSL_PRECOND( hasCursor(), "FormControllerHelper::moveLeft: no cursor!" ); + if ( !hasCursor() ) + return sal_False; + + sal_Bool bRecordInserted = sal_False; + sal_Bool bSuccess = commitCurrentRecord( &bRecordInserted ); + + if ( bSuccess ) + { + try + { + if ( bRecordInserted ) + { + // retrieve the bookmark of the new record and move previous to that bookmark + Reference< XRowLocate > xLocate( m_xCursor, UNO_QUERY ); + OSL_ENSURE( xLocate.is(), "FormControllerHelper::moveLeft: no XRowLocate!" ); + aGuard.clear(); + + if ( xLocate.is() ) + xLocate->moveRelativeToBookmark( xLocate->getBookmark(), -1 ); + } + else + { + // clear our mutex before calling into a foreign component + Reference< XRowSet > xCursor( m_xCursor ); + aGuard.clear(); + + if ( isNewRecord() ) + { + // we assume that the inserted record is now the last record in the + // result set + xCursor->last(); + } + else + xCursor->previous(); + } + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::moveLeft: caught an exception!" ); + bSuccess = sal_False; + } + + } + return bSuccess; + } + + //-------------------------------------------------------------------- + void FormControllerHelper::execute( sal_Int32 _nFeatureId, const ::rtl::OUString& _rParamName, + const Any& _rParamValue ) const + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + OSL_ENSURE( hasCursor(), "FormControllerHelper::execute: no cursor!" ); + if ( !hasCursor() ) + return; + + // at the moment we have only one feature which supports execution parameters + OSL_ENSURE( _nFeatureId == SID_FM_RECORD_ABSOLUTE, "FormControllerHelper::execute: wrong id!" ); + if ( _nFeatureId == SID_FM_RECORD_ABSOLUTE ) + { + sal_Int32 nPosition = -1; + + OSL_ENSURE( _rParamName.equalsAscii( "Position" ), "FormControllerHelper::execute: invalid parameter!" ); + if ( _rParamName.equalsAscii( "Position" ) ) + { + _rParamValue >>= nPosition; + if ( nPosition < 1 ) + nPosition = 1; + } + + if ( nPosition != -1 ) + { + try + { + // commit before doing anything else + if ( m_xController.is() && !commitCurrentControl() ) + return; + if ( !commitCurrentRecord() ) + return; + + sal_Int32 nCount = getRecordCount(); + sal_Bool bFinalCount = isRecordCountFinal(); + + if ( bFinalCount && ( (sal_Int32)nPosition > nCount ) ) + nPosition = nCount; + + m_xCursor->absolute( nPosition ); + } + catch( const SQLException& ) + { + // no need to assert. See the similar block in the other + // execute method for an explanation + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::execute: caught an exception!" ); + } + } + } + } + + //-------------------------------------------------------------------- + namespace + { + static bool needConfirmCommit( sal_Int32 _nFeatureId ) + { + return ( ( _nFeatureId == SID_FM_REFRESH ) + || ( _nFeatureId == SID_FM_REMOVE_FILTER_SORT ) + || ( _nFeatureId == SID_FM_FORM_FILTERED ) + || ( _nFeatureId == SID_FM_SORTUP ) + || ( _nFeatureId == SID_FM_SORTDOWN ) + || ( _nFeatureId == SID_FM_AUTOFILTER ) + || ( _nFeatureId == SID_FM_ORDERCRIT ) + || ( _nFeatureId == SID_FM_FILTERCRIT ) + ); + } + } + + //-------------------------------------------------------------------- + void FormControllerHelper::execute( sal_Int32 _nFeatureId ) const + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + OSL_ENSURE( hasCursor(), "FormControllerHelper::execute: no cursor!" ); + if ( !hasCursor() ) + return; + + if ( ( _nFeatureId != SID_FM_RECORD_DELETE ) && ( _nFeatureId != SID_FM_RECORD_UNDO ) ) + { + // if we have a controller, commit the current control + if ( m_xController.is() ) + if ( !commitCurrentControl() ) + return; + + // commit the current record + bool bCommitCurrentRecord = true; + // (but before, let the user confirm if necessary) + if ( isModifiedRecord() ) + { + if ( needConfirmCommit( _nFeatureId ) ) + { + QueryBox aQuery( NULL, SVX_RES( RID_QRY_SAVEMODIFIED ) ); + switch ( aQuery.Execute() ) + { + case RET_NO: bCommitCurrentRecord = false; break; + case RET_CANCEL: return; + } + } + } + if ( bCommitCurrentRecord && !commitCurrentRecord() ) + return; + } + + try + { + switch ( _nFeatureId ) + { + case SID_FM_RECORD_FIRST: + // move + m_xCursor->first(); + break; + + case SID_FM_RECORD_NEXT: + case SID_FM_RECORD_PREV: + if ( SID_FM_RECORD_PREV == _nFeatureId ) + moveLeft( ); + else + moveRight( ); + // note that moveXXX also does a commitCurrentControl + break; + + case SID_FM_RECORD_LAST: + { +/* + // TODO: re-implement this ..... + // run in an own thread if ... + // ... the data source is thread safe ... + sal_Bool bAllowOwnThread = sal_False; + if ( ::comphelper::hasProperty( FM_PROP_THREADSAFE, m_xCursorProperties ) ) + m_xCursorProperties->getPropertyValue( FM_PROP_THREADSAFE ) >>= bAllowOwnThread; + + // ... the record count is unknown + sal_Bool bNeedOwnThread sal_False; + if ( ::comphelper::hasProperty( FM_PROP_ROWCOUNTFINAL, m_xCursorProperties ) ) + m_xCursorProperties->getPropertyValue( FM_PROP_ROWCOUNTFINAL ) >>= bNeedOwnThread; + + if ( bNeedOwnThread && bAllowOwnThread ) + TODO + else +*/ + m_xCursor->last(); + } + break; + + case SID_FM_REFRESH: + if ( m_xLoadableForm.is() ) + { + WaitObject aWO( NULL ); + m_xLoadableForm->reload(); + } + break; + + case SID_FM_RECORD_DELETE: + { + sal_uInt32 nCount = getRecordCount(); + + // next position + sal_Bool bLeft = m_xCursor->isLast() && ( nCount > 1 ); + sal_Bool bRight= !m_xCursor->isLast(); + sal_Bool bSuccess = sal_False; + try + { + // ask for confirmation + Reference< XConfirmDeleteListener > xConfirmDelete( m_xController, UNO_QUERY ); + + if ( xConfirmDelete.is() ) + { + RowChangeEvent aEvent; + aEvent.Source = Reference< XInterface >( m_xCursor, UNO_QUERY ); + aEvent.Action = RowChangeAction::DELETE; + aEvent.Rows = 1; + bSuccess = xConfirmDelete->confirmDelete( aEvent ); + } + + // delete it + if ( bSuccess ) + m_xUpdateCursor->deleteRow(); + } + catch( const Exception& ) + { + bSuccess = sal_False; + } + + if ( bSuccess ) + { + if ( bLeft || bRight ) + m_xCursor->relative( bRight ? 1 : -1 ); + else + { + sal_Bool bCanInsert = m_pDbTools->canInsert( m_xCursorProperties ); + // is it possible to insert another record? + if ( bCanInsert ) + m_xUpdateCursor->moveToInsertRow(); + else + // move record to update stati + m_xCursor->first(); + } + } + } + + case SID_FM_RECORD_SAVE: + case SID_FM_RECORD_UNDO: + { + sal_Bool bInserting = isNewRecord(); + + if ( SID_FM_RECORD_UNDO == _nFeatureId ) + { + if ( !bInserting ) + m_xUpdateCursor->cancelRowUpdates(); + + // reset all controls for this form + resetAllControls( ); + + if ( bInserting ) // back to insertion mode for this form + m_xUpdateCursor->moveToInsertRow(); + } + else + { + if ( bInserting ) + { + m_xUpdateCursor->insertRow(); + m_xCursor->last(); + } + else + m_xUpdateCursor->updateRow(); + } + } + break; + + case SID_FM_RECORD_NEW: + // move to the last row before moving to the insert row + // 21.01.2002 - 96480 - fs@openoffice.org + m_xCursor->last(); + m_xUpdateCursor->moveToInsertRow(); + break; + + case SID_FM_REMOVE_FILTER_SORT: + { + // simultaneously reset Filter and Order property + Reference< XMultiPropertySet > xProperties( m_xCursorProperties, UNO_QUERY ); + OSL_ENSURE( xProperties.is(), "FormControllerHelper::execute: no multi property access!" ); + if ( xProperties.is() ) + { + Sequence< ::rtl::OUString > aNames( 2 ); + aNames[0] = FM_PROP_FILTER_CRITERIA; + aNames[1] = FM_PROP_SORT; + + Sequence< Any> aValues( 2 ); + aValues[0] <<= ::rtl::OUString(); + aValues[1] <<= ::rtl::OUString(); + + WaitObject aWO( NULL ); + xProperties->setPropertyValues( aNames, aValues ); + + if ( m_xLoadableForm.is() ) + m_xLoadableForm->reload(); + } + } + break; + + case SID_FM_FORM_FILTERED: + if ( commitCurrentControl() && commitCurrentRecord() ) + { + // simply toggle the value + sal_Bool bApplied = sal_False; + m_xCursorProperties->getPropertyValue( FM_PROP_APPLYFILTER ) >>= bApplied; + m_xCursorProperties->setPropertyValue( FM_PROP_APPLYFILTER, makeAny( (sal_Bool)!bApplied ) ); + + // and reload + WaitObject aWO( NULL ); + m_xLoadableForm->reload(); + } + break; + + case SID_FM_SORTUP: + executeAutoSort( sal_True ); + break; + + case SID_FM_SORTDOWN: + executeAutoSort( sal_False ); + break; + + case SID_FM_AUTOFILTER: + executeAutoFilter(); + break; + + case SID_FM_ORDERCRIT: + executeFilterOrSort( false ); + break; + + case SID_FM_FILTERCRIT: + executeFilterOrSort( true ); + break; + } + } + catch( const SQLException& ) + { + // silent this. SQL exceptions, when they happen, are to be reported + // to all XSQLErrorListeners of the form. One of these listeners is + // the form controller, which displays an error message. + // So there's no reason that we assert here. + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::execute: caught an exception!" ); + } + + invalidateAllSupportedFeatures( aGuard ); + } + + //-------------------------------------------------------------------- + void FormControllerHelper::executeFilterOrSort( bool _bFilter ) const + { + OSL_PRECOND( m_xController.is(), "FormControllerHelper::executeFilterOrSort: need a controller for this!" ); + OSL_PRECOND( hasCursor(), "FormControllerHelper::executeFilterOrSort: need a cursor for this!" ); + OSL_PRECOND( isParsable(), "FormControllerHelper::executeFilterOrSort: need a parseable statement for this!" ); + if ( !m_xController.is() || !hasCursor() || !isParsable() ) + return; + + if ( commitCurrentControl() && commitCurrentRecord() && m_xORB.is() ) + { + try + { + PropertyValue aFirst; + aFirst.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "QueryComposer" ) ); + aFirst.Value <<= m_xParser; + + PropertyValue aSecond; + aSecond.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RowSet" ) ); + aSecond.Value <<= m_xCursorProperties; + + Sequence<Any> aInit(2); + aInit[0] <<= aFirst; + aInit[1] <<= aSecond; + + ::rtl::OUString sDialogServiceName; + if ( _bFilter ) + sDialogServiceName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdb.FilterDialog" ) ); + else + sDialogServiceName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdb.OrderDialog" ) ); + + Reference< XExecutableDialog> xDialog( + m_xORB->createInstanceWithArguments( sDialogServiceName, aInit ), UNO_QUERY + ); + + if ( !xDialog.is() ) + { + ShowServiceNotAvailableError( NULL, sDialogServiceName, sal_True ); + return; + } + + if ( RET_OK == xDialog->execute() ) + { + WaitObject aWO( NULL ); + if ( _bFilter ) + m_xCursorProperties->setPropertyValue( FM_PROP_FILTER_CRITERIA, makeAny( m_xParser->getFilter() ) ); + else + m_xCursorProperties->setPropertyValue( FM_PROP_SORT, makeAny( m_xParser->getOrder() ) ); + m_xLoadableForm->reload(); + } + + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::executeFilterOrSort: caught an exception!" ); + } + } + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::canMoveRight( ) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( hasCursor() ) + { + sal_Bool bIsNew = isNewRecord(); + + if ( getRecordCount() && !m_xCursor->isLast() && !bIsNew ) + return sal_True; + + if ( m_pDbTools->canInsert( m_xCursorProperties ) ) + if ( !bIsNew || isModifiedRecord() ) + return sal_True; + } + + return sal_False; + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::canMoveLeft( ) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( hasCursor() ) + { + return getRecordCount() && ( !m_xCursor->isFirst() || isNewRecord() ); + } + return sal_False; + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::isNewRecord() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + OSL_PRECOND( m_xCursorProperties.is(), "FormControllerHelper::isNewRecord: no cursor (already disposed?)!" ); + sal_Bool bIsNew = sal_False; + if ( m_xCursorProperties.is() ) + m_xCursorProperties->getPropertyValue( FM_PROP_ISNEW ) >>= bIsNew; + return bIsNew; + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::isModifiedRecord() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + OSL_PRECOND( m_xCursorProperties.is(), "FormControllerHelper::isModifiedRecord: no cursor (already disposed?)!" ); + sal_Bool bIsModified = sal_False; + if ( m_xCursorProperties.is() ) + m_xCursorProperties->getPropertyValue( FM_PROP_ISMODIFIED ) >>= bIsModified; + return bIsModified; + } + + //-------------------------------------------------------------------- + sal_Int32 FormControllerHelper::getRecordCount() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + OSL_PRECOND( m_xCursorProperties.is(), "FormControllerHelper::getRecordCount: no cursor (already disposed?)!" ); + sal_Int32 nRecordCount = 0; + if ( m_xCursorProperties.is() ) + m_xCursorProperties->getPropertyValue( FM_PROP_ROWCOUNT ) >>= nRecordCount; + return nRecordCount; + } + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::isRecordCountFinal() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + OSL_PRECOND( m_xCursorProperties.is(), "FormControllerHelper::isRecordCountFinal: no cursor (already disposed?)!" ); + sal_Bool bIsFinal = sal_False; + if ( m_xCursorProperties.is() ) + m_xCursorProperties->getPropertyValue( FM_PROP_ROWCOUNTFINAL ) >>= bIsFinal; + return bIsFinal; + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::isInsertOnlyForm() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + OSL_PRECOND( m_xCursorProperties.is(), "FormControllerHelper::isInsertOnlyForm: no cursor (already disposed?)!" ); + sal_Bool bInsertOnly = sal_True; + if ( m_xCursorProperties.is() ) + m_xCursorProperties->getPropertyValue( FM_PROP_INSERTONLY ) >>= bInsertOnly; + return bInsertOnly; + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::isParsable() const + { + const_cast< FormControllerHelper* >( this )->ensureInitializedParser(); + return m_xParser.is() && m_xParser->getQuery().getLength(); + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::hasFilterOrOrder() const + { + return isParsable() && ( m_xParser->getFilter().getLength() || m_xParser->getOrder().getLength() ); + } + + //-------------------------------------------------------------------- + void FormControllerHelper::disposeParser() + { + try + { + // if we have a parser (and a cursor), then we're listening at the cursor's + // properties to keep the parser in sync with the cursor + if ( m_xParser.is() && m_xCursorProperties.is() ) + { + m_xCursorProperties->removePropertyChangeListener( FM_PROP_FILTER_CRITERIA, this ); + m_xCursorProperties->removePropertyChangeListener( FM_PROP_ACTIVECOMMAND, this ); + m_xCursorProperties->removePropertyChangeListener( FM_PROP_SORT, this ); + } + + Reference< XComponent > xParserComp( m_xParser, UNO_QUERY ); + if ( xParserComp.is() ) + xParserComp->dispose(); + m_xParser.clear(); + + m_bInitializedParser = sal_False; + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::disposeParser: caught an exception!" ); + } + } + + //-------------------------------------------------------------------- + void FormControllerHelper::ensureInitializedParser() + { + if ( m_bInitializedParser ) + return; + + try + { + sal_Bool bUseEscapeProcessing = sal_False; + m_xCursorProperties->getPropertyValue( FM_PROP_ESCAPE_PROCESSING ) >>= bUseEscapeProcessing; + if ( bUseEscapeProcessing ) + { + Reference< XRowSet > xCursorRowSet( m_xCursor, UNO_QUERY ); + Reference< XSQLQueryComposerFactory > xFactory( m_pDbTools->getRowSetConnection( xCursorRowSet ), UNO_QUERY ); + if ( xFactory.is() ) + m_xParser = xFactory->createQueryComposer(); + } + + if ( m_xParser.is() ) + { + if ( m_xLoadableForm.is() && m_xLoadableForm->isLoaded() ) + { + ::rtl::OUString sStatement; + ::rtl::OUString sFilter; + ::rtl::OUString sSort; + + m_xCursorProperties->getPropertyValue( FM_PROP_ACTIVECOMMAND ) >>= sStatement; + m_xCursorProperties->getPropertyValue( FM_PROP_FILTER_CRITERIA ) >>= sFilter; + m_xCursorProperties->getPropertyValue( FM_PROP_SORT ) >>= sSort; + + m_xParser->setQuery ( sStatement ); + m_xParser->setFilter( sFilter ); + m_xParser->setOrder ( sSort ); + } + + // start listening at the properties order/sort properties at the form, so + // we can keep our parser in sync + m_xCursorProperties->addPropertyChangeListener( FM_PROP_ACTIVECOMMAND, this ); + m_xCursorProperties->addPropertyChangeListener( FM_PROP_FILTER_CRITERIA, this ); + m_xCursorProperties->addPropertyChangeListener( FM_PROP_SORT, this ); + } + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormControllerHelper::ensureInitializedParser: caught an exception!" ); + } + + m_bInitializedParser = sal_True; + } + + //-------------------------------------------------------------------- + void FormControllerHelper::resetAllControls( ) const + { + resetAllControls( Reference< XForm >( m_xCursor, UNO_QUERY ) ); + } + + //-------------------------------------------------------------------- + void FormControllerHelper::resetAllControls( const Reference< XForm >& _rxForm ) + { + Reference< XIndexAccess > xContainer( _rxForm, UNO_QUERY ); + if ( xContainer.is() ) + { + Reference< XReset > xReset; + for ( sal_Int32 i = 0; i < xContainer->getCount(); ++i ) + { + if ( ( xContainer->getByIndex( i ) >>= xReset ) && xReset.is() ) + { + // no resets on sub forms + Reference< XForm > xAsForm( xReset, UNO_QUERY ); + if ( !xAsForm.is() ) + xReset->reset(); + } + } + } + + } + + //------------------------------------------------------------------------------ + void FormControllerHelper::invalidateAllSupportedFeatures( ::osl::ClearableMutexGuard& _rClearForCallback ) const + { + if ( !m_pInvalidationCallback ) + // nobody's interested in ... + return; + + // actually, it's a little bit more than the supported features, + // but on the medium term, we are to support everything listed + // here + static ::std::vector< sal_Int32 > aSupportedFeatures; + if ( aSupportedFeatures.empty() ) + { + sal_Int32 pSupportedFeatures[] = + { + SID_FM_RECORD_FIRST, + SID_FM_RECORD_NEXT, + SID_FM_RECORD_PREV, + SID_FM_RECORD_LAST, + SID_FM_RECORD_NEW, + SID_FM_RECORD_DELETE, + SID_FM_RECORD_ABSOLUTE, + SID_FM_RECORD_TOTAL, + SID_FM_RECORD_SAVE, + SID_FM_RECORD_UNDO, + SID_FM_REMOVE_FILTER_SORT, + SID_FM_SORTUP, + SID_FM_SORTDOWN, + SID_FM_ORDERCRIT, + SID_FM_AUTOFILTER, + SID_FM_FILTERCRIT, + SID_FM_FORM_FILTERED, + SID_FM_REFRESH, + SID_FM_SEARCH, + SID_FM_FILTER_START, + SID_FM_VIEW_AS_GRID + }; + sal_Int32 nFeatureCount = sizeof( pSupportedFeatures ) / sizeof( pSupportedFeatures[ 0 ] ); + aSupportedFeatures.resize( nFeatureCount ); + ::std::copy( pSupportedFeatures, pSupportedFeatures + nFeatureCount, aSupportedFeatures.begin() ); + } + + IControllerFeatureInvalidation* pCallback = m_pInvalidationCallback; + _rClearForCallback.clear(); + + pCallback->invalidateFeatures( aSupportedFeatures ); + } + + //------------------------------------------------------------------------------ + void FormControllerHelper::invalidateModifyDependentFeatures( ::osl::ClearableMutexGuard& _rClearForCallback ) const + { + if ( !m_pInvalidationCallback ) + // nobody's interested in ... + return; + + static ::std::vector< sal_Int32 > aModifyDependentFeatures; + if ( aModifyDependentFeatures.empty() ) + { + sal_uInt16 pModifyDependentFeatures[] = // slots des Controllers + { + SID_FM_RECORD_NEXT, + SID_FM_RECORD_NEW, + SID_FM_RECORD_SAVE, + SID_FM_RECORD_UNDO + }; + sal_Int32 nFeatureCount = sizeof( pModifyDependentFeatures ) / sizeof( pModifyDependentFeatures[ 0 ] ); + aModifyDependentFeatures.resize( nFeatureCount ); + ::std::copy( pModifyDependentFeatures, pModifyDependentFeatures + nFeatureCount, aModifyDependentFeatures.begin() ); + } + + IControllerFeatureInvalidation* pCallback = m_pInvalidationCallback; + _rClearForCallback.clear(); + + pCallback->invalidateFeatures( aModifyDependentFeatures ); + } + +//........................................................................ +} // namespace svx +//........................................................................ |