summaryrefslogtreecommitdiff
path: root/svx/source/form
diff options
context:
space:
mode:
authorJens-Heiner Rechtien <hr@openoffice.org>2004-04-13 10:00:14 +0000
committerJens-Heiner Rechtien <hr@openoffice.org>2004-04-13 10:00:14 +0000
commit693b5dd88c6a5d32df543dd908260fcb414ba5e1 (patch)
tree586cb5d1d07509b4b00960dc2b40b5f8630ad475 /svx/source/form
parent11bc713852092c730ccf7f3e55eb9e39d3a30bf1 (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.cxx1778
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
+//........................................................................