summaryrefslogtreecommitdiffstats
path: root/forms/source/runtime
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /forms/source/runtime
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--forms/source/runtime/formoperations.cxx1767
-rw-r--r--forms/source/runtime/formoperations.hxx381
2 files changed, 2148 insertions, 0 deletions
diff --git a/forms/source/runtime/formoperations.cxx b/forms/source/runtime/formoperations.cxx
new file mode 100644
index 000000000..11207991d
--- /dev/null
+++ b/forms/source/runtime/formoperations.cxx
@@ -0,0 +1,1767 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+#include <config_fuzzers.h>
+
+#include "formoperations.hxx"
+#include <frm_strings.hxx>
+#include <frm_resource.hxx>
+#include <strings.hrc>
+
+#include <com/sun/star/ucb/AlreadyInitializedException.hpp>
+#include <com/sun/star/util/XModifyBroadcaster.hpp>
+#include <com/sun/star/form/runtime/FormFeature.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/form/XGrid.hpp>
+#include <com/sun/star/form/XBoundControl.hpp>
+#include <com/sun/star/form/XBoundComponent.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/form/XConfirmDeleteListener.hpp>
+#include <com/sun/star/sdb/RowChangeEvent.hpp>
+#include <com/sun/star/sdb/RowChangeAction.hpp>
+#include <com/sun/star/sdb/OrderDialog.hpp>
+#include <com/sun/star/sdb/FilterDialog.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/form/XReset.hpp>
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/util/XRefreshable.hpp>
+
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/stdtext.hxx>
+#include <vcl/weld.hxx>
+#include <tools/diagnose_ex.h>
+#include <comphelper/container.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <osl/mutex.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+
+
+namespace frm
+{
+
+
+ using ::dbtools::SQLExceptionInfo;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::sdbc::XRowSet;
+ using ::com::sun::star::sdbc::XResultSetUpdate;
+ using ::com::sun::star::form::runtime::XFormController;
+ using ::com::sun::star::form::runtime::XFormOperations;
+ using ::com::sun::star::form::runtime::XFeatureInvalidation;
+ using ::com::sun::star::form::runtime::FeatureState;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::sdbc::SQLException;
+ using namespace ::com::sun::star::sdbc;
+ using ::com::sun::star::form::XForm;
+ using ::com::sun::star::ucb::AlreadyInitializedException;
+ using ::com::sun::star::util::XModifyBroadcaster;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::beans::PropertyChangeEvent;
+ using ::com::sun::star::lang::XMultiServiceFactory;
+ using ::com::sun::star::lang::DisposedException;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::awt::XControl;
+ using ::com::sun::star::form::XGrid;
+ using ::com::sun::star::container::XIndexAccess;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::form::XBoundControl;
+ using ::com::sun::star::form::XBoundComponent;
+ using ::com::sun::star::sdbcx::XRowLocate;
+ using ::com::sun::star::form::XConfirmDeleteListener;
+ using ::com::sun::star::sdb::RowChangeEvent;
+ using namespace ::com::sun::star::sdb;
+ using ::com::sun::star::form::XReset;
+ using ::com::sun::star::beans::XMultiPropertySet;
+ using ::com::sun::star::lang::WrappedTargetException;
+ using ::com::sun::star::ui::dialogs::XExecutableDialog;
+ using ::com::sun::star::beans::NamedValue;
+ using ::com::sun::star::util::XRefreshable;
+ using ::com::sun::star::awt::XControlModel;
+
+ namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
+ namespace RowChangeAction = ::com::sun::star::sdb::RowChangeAction;
+
+ FormOperations::FormOperations( const Reference< XComponentContext >& _rxContext )
+ :FormOperations_Base( m_aMutex )
+ ,m_xContext( _rxContext )
+ ,m_bInitializedParser( false )
+ ,m_bActiveControlModified( false )
+ ,m_bConstructed( false )
+ #ifdef DBG_UTIL
+ ,m_nMethodNestingLevel( 0 )
+ #endif
+ {
+ }
+
+ FormOperations::~FormOperations()
+ {
+ }
+
+ void SAL_CALL FormOperations::initialize( const Sequence< Any >& _arguments )
+ {
+ if ( m_bConstructed )
+ throw AlreadyInitializedException();
+
+ if ( _arguments.getLength() == 1 )
+ {
+ Reference< XFormController > xController;
+ Reference< XForm > xForm;
+ if ( _arguments[0] >>= xController )
+ createWithFormController( xController );
+ else if ( _arguments[0] >>= xForm )
+ createWithForm( xForm );
+ else
+ throw IllegalArgumentException( OUString(), *this, 1 );
+ return;
+ }
+
+ throw IllegalArgumentException( OUString(), *this, 0 );
+ }
+
+ OUString SAL_CALL FormOperations::getImplementationName( )
+ {
+ return "com.sun.star.comp.forms.FormOperations";
+ }
+
+ sal_Bool SAL_CALL FormOperations::supportsService( const OUString& ServiceName )
+ {
+ return cppu::supportsService(this, ServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL FormOperations::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.form.runtime.FormOperations" };
+ }
+
+ Reference< XRowSet > SAL_CALL FormOperations::getCursor()
+ {
+ MethodGuard aGuard( *this );
+ return m_xCursor;
+ }
+
+ Reference< XResultSetUpdate > SAL_CALL FormOperations::getUpdateCursor()
+ {
+ MethodGuard aGuard( *this );
+ return m_xUpdateCursor;
+ }
+
+
+ Reference< XFormController > SAL_CALL FormOperations::getController()
+ {
+ MethodGuard aGuard( *this );
+ return m_xController;
+ }
+
+
+ Reference< XFeatureInvalidation > SAL_CALL FormOperations::getFeatureInvalidation()
+ {
+ MethodGuard aGuard( *this );
+ return m_xFeatureInvalidation;
+ }
+
+
+ void SAL_CALL FormOperations::setFeatureInvalidation( const Reference< XFeatureInvalidation > & _rxFeatureInvalidation )
+ {
+ MethodGuard aGuard( *this );
+ m_xFeatureInvalidation = _rxFeatureInvalidation;
+ }
+
+
+ FeatureState SAL_CALL FormOperations::getState( ::sal_Int16 _nFeature )
+ {
+ MethodGuard aGuard( *this );
+
+ FeatureState aState;
+ aState.Enabled = false;
+
+ try
+ {
+ // some checks for basic pre-requisites
+ if ( !m_xLoadableForm.is()
+ || !m_xLoadableForm->isLoaded()
+ || !m_xCursorProperties.is()
+ )
+ {
+ return aState;
+ }
+
+ switch ( _nFeature )
+ {
+ case FormFeature::MoveToFirst:
+ case FormFeature::MoveToPrevious:
+ aState.Enabled = impl_canMoveLeft_throw( );
+ break;
+
+ case FormFeature::MoveToNext:
+ aState.Enabled = impl_canMoveRight_throw();
+ break;
+
+ case FormFeature::MoveToLast:
+ aState.Enabled = impl_getRowCount_throw() && ( !m_xCursor->isLast() || impl_isInsertionRow_throw() );
+ break;
+
+ case FormFeature::DeleteRecord:
+ // already deleted ?
+ if ( m_xCursor->rowDeleted() )
+ aState.Enabled = false;
+ else
+ {
+ // allowed to delete the row ?
+ aState.Enabled = !impl_isInsertionRow_throw() && ::dbtools::canDelete( m_xCursorProperties );
+ }
+ break;
+
+ case FormFeature::MoveToInsertRow:
+ // if we are inserting we can move to the next row if the current record or control is modified
+ aState.Enabled = impl_isInsertionRow_throw()
+ ? impl_isModifiedRow_throw() || m_bActiveControlModified
+ : ::dbtools::canInsert( m_xCursorProperties );
+ break;
+
+ case FormFeature::ReloadForm:
+ {
+ // there must be an active connection
+ aState.Enabled = ::dbtools::getConnection( m_xCursor ).is();
+
+ // and an active command
+ OUString sActiveCommand;
+ m_xCursorProperties->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sActiveCommand;
+ aState.Enabled = aState.Enabled && !sActiveCommand.isEmpty();
+ }
+ break;
+
+ case FormFeature::RefreshCurrentControl:
+ {
+ Reference< XRefreshable > xControlModelRefresh( impl_getCurrentControlModel_throw(), UNO_QUERY );
+ aState.Enabled = xControlModelRefresh.is();
+ }
+ break;
+
+ case FormFeature::SaveRecordChanges:
+ case FormFeature::UndoRecordChanges:
+ aState.Enabled = impl_isModifiedRow_throw() || m_bActiveControlModified;
+ break;
+
+ case FormFeature::RemoveFilterAndSort:
+ if ( impl_isParseable_throw() && impl_hasFilterOrOrder_throw() )
+ aState.Enabled = !impl_isInsertOnlyForm_throw();
+ break;
+
+ case FormFeature::SortAscending:
+ case FormFeature::SortDescending:
+ case FormFeature::AutoFilter:
+ if ( m_xController.is() && impl_isParseable_throw() )
+ {
+ bool bIsDeleted = m_xCursor->rowDeleted();
+
+ if ( !bIsDeleted && !impl_isInsertOnlyForm_throw() )
+ {
+ Reference< XPropertySet > xBoundField = impl_getCurrentBoundField_nothrow( );
+ if ( xBoundField.is() )
+ xBoundField->getPropertyValue( PROPERTY_SEARCHABLE ) >>= aState.Enabled;
+ }
+ }
+ break;
+
+ case FormFeature::InteractiveSort:
+ case FormFeature::InteractiveFilter:
+ if ( impl_isParseable_throw() )
+ aState.Enabled = !impl_isInsertOnlyForm_throw();
+ break;
+
+ case FormFeature::ToggleApplyFilter:
+ {
+ OUString sFilter;
+ OUString sHaving;
+ m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
+ m_xCursorProperties->getPropertyValue( PROPERTY_HAVINGCLAUSE ) >>= sHaving;
+ if ( ! (sFilter.isEmpty() && sHaving.isEmpty()) )
+ {
+ aState.State = m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER );
+ aState.Enabled = !impl_isInsertOnlyForm_throw();
+ }
+ else
+ aState.State <<= false;
+ }
+ break;
+
+ case FormFeature::MoveAbsolute:
+ {
+ sal_Int32 nPosition = m_xCursor->getRow();
+ bool bIsNew = impl_isInsertionRow_throw();
+ sal_Int32 nCount = impl_getRowCount_throw();
+ bool bFinalCount = impl_isRowCountFinal_throw();
+
+ if ( ( nPosition >= 0 ) || bIsNew )
+ {
+ if ( bFinalCount )
+ {
+ // special case: there are no records at all, and we
+ // can't insert records -> disabled
+ if ( !nCount && !::dbtools::canInsert( m_xCursorProperties ) )
+ {
+ aState.Enabled = false;
+ }
+ else
+ {
+ if ( bIsNew )
+ nPosition = ++nCount;
+ aState.State <<= nPosition;
+ aState.Enabled = true;
+ }
+ }
+ else
+ {
+ aState.State <<= nPosition;
+ aState.Enabled = true;
+ }
+ }
+ }
+ break;
+
+ case FormFeature::TotalRecords:
+ {
+ bool bIsNew = impl_isInsertionRow_throw();
+ sal_Int32 nCount = impl_getRowCount_throw();
+ bool bFinalCount = impl_isRowCountFinal_throw();
+
+ if ( bIsNew )
+ ++nCount;
+
+ OUString sValue = OUString::number( nCount );
+ if ( !bFinalCount )
+ sValue += " *";
+
+ aState.State <<= sValue;
+ aState.Enabled = true;
+ }
+ break;
+
+ default:
+ OSL_FAIL( "FormOperations::getState: unknown feature id!" );
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::getState" );
+ }
+
+ return aState;
+ }
+
+
+ sal_Bool SAL_CALL FormOperations::isEnabled( ::sal_Int16 _nFeature )
+ {
+ MethodGuard aGuard( *this );
+
+ FeatureState aState( getState( _nFeature ) );
+ return aState.Enabled;
+ }
+
+
+ namespace
+ {
+ bool lcl_needConfirmCommit( sal_Int32 _nFeature )
+ {
+ return ( ( _nFeature == FormFeature::ReloadForm )
+ || ( _nFeature == FormFeature::RemoveFilterAndSort )
+ || ( _nFeature == FormFeature::ToggleApplyFilter )
+ || ( _nFeature == FormFeature::SortAscending )
+ || ( _nFeature == FormFeature::SortDescending )
+ || ( _nFeature == FormFeature::AutoFilter )
+ || ( _nFeature == FormFeature::InteractiveSort )
+ || ( _nFeature == FormFeature::InteractiveFilter )
+ );
+ }
+ bool lcl_requiresArguments( sal_Int32 _nFeature )
+ {
+ return ( _nFeature == FormFeature::MoveAbsolute );
+ }
+ bool lcl_isExecutableFeature( sal_Int32 _nFeature )
+ {
+ return ( _nFeature != FormFeature::TotalRecords );
+ }
+
+ template < typename TYPE >
+ TYPE lcl_safeGetPropertyValue_throw( const Reference< XPropertySet >& _rxProperties, const OUString& _rPropertyName, TYPE Default )
+ {
+ TYPE value( Default );
+ OSL_PRECOND( _rxProperties.is(), "FormOperations::<foo>: no cursor (already disposed?)!" );
+ if ( _rxProperties.is() )
+ OSL_VERIFY( _rxProperties->getPropertyValue( _rPropertyName ) >>= value );
+ return value;
+ }
+
+ // returns false if parent should *abort* (user pressed cancel)
+ bool checkConfirmation(bool &needConfirmation, bool &shouldCommit)
+ {
+ if(!needConfirmation)
+ return true;
+ // TODO: shouldn't this be done with an interaction handler?
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Question, VclButtonsType::YesNo,
+ ResourceManager::loadString(RID_STR_QUERY_SAVE_MODIFIED_ROW)));
+ xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
+ xQueryBox->set_default_response(RET_YES);
+
+ switch (xQueryBox->run())
+ {
+ case RET_NO:
+ shouldCommit = false;
+ [[fallthrough]]; // don't ask again!
+ case RET_YES:
+ needConfirmation = false;
+ return true;
+ case RET_CANCEL:
+ return false;
+ }
+ return true;
+ }
+
+ bool commit1Form(const Reference< XFormController >& xCntrl, bool &needConfirmation, bool &shouldCommit)
+ {
+ Reference< XFormOperations > xFrmOps(xCntrl->getFormOperations());
+ if (!xFrmOps->commitCurrentControl())
+ return false;
+
+ if(xFrmOps->isModifiedRow())
+ {
+ if(!checkConfirmation(needConfirmation, shouldCommit))
+ return false;
+ sal_Bool bTmp;
+ if (shouldCommit && !xFrmOps->commitCurrentRecord(bTmp))
+ return false;
+ }
+ return true;
+ }
+
+ bool commitFormAndSubforms(const Reference< XFormController >& xCntrl, bool needConfirmation)
+ {
+ bool shouldCommit(true);
+ assert(xCntrl.is());
+ if(xCntrl.is())
+ {
+ const sal_Int32 cnt = xCntrl->getCount();
+ for(int i=0; i < cnt; ++i)
+ {
+ Reference< XFormController > xSubForm(xCntrl->getByIndex(i), UNO_QUERY);
+ assert(xSubForm.is());
+ if (xSubForm.is())
+ {
+ if (!commit1Form(xSubForm, needConfirmation, shouldCommit))
+ return false;
+ }
+ }
+ }
+
+ return commit1Form(xCntrl, needConfirmation, shouldCommit);
+ }
+
+ bool commit1Form(const Reference< XForm >& xFrm, bool &needConfirmation, bool &shouldCommit)
+ {
+ Reference< XPropertySet > xProps(xFrm, UNO_QUERY_THROW);
+ // nothing to do if the record is not modified
+ if(!lcl_safeGetPropertyValue_throw( xProps, PROPERTY_ISMODIFIED, false ))
+ return true;
+
+ if(!checkConfirmation(needConfirmation, shouldCommit))
+ return false;
+ if(shouldCommit)
+ {
+ Reference< XResultSetUpdate > xUpd(xFrm, UNO_QUERY_THROW);
+ // insert respectively update the row
+ if ( lcl_safeGetPropertyValue_throw( xProps, PROPERTY_ISNEW, false ) )
+ xUpd->insertRow();
+ else
+ xUpd->updateRow();
+ }
+ return true;
+ }
+
+ bool commitFormAndSubforms(const Reference< XForm >& xFrm, bool needConfirmation)
+ {
+ // No control... do what we can with the models
+ bool shouldCommit(true);
+ Reference< XIndexAccess > xFormComps(xFrm, UNO_QUERY_THROW);
+
+ const sal_Int32 cnt = xFormComps->getCount();
+ for(int i=0; i < cnt; ++i)
+ {
+ Reference< XForm > xSubForm(xFormComps->getByIndex(i), UNO_QUERY);
+ if(xSubForm.is())
+ {
+ if(!commit1Form(xSubForm, needConfirmation, shouldCommit))
+ return false;
+ }
+ }
+
+ return commit1Form(xFrm, needConfirmation, shouldCommit);
+ }
+ }
+
+ void SAL_CALL FormOperations::execute( ::sal_Int16 _nFeature )
+ {
+ SolarMutexGuard aSolarGuard;
+ MethodGuard aGuard( *this );
+
+ if ( ( _nFeature != FormFeature::DeleteRecord ) && ( _nFeature != FormFeature::UndoRecordChanges ) )
+ {
+
+
+ if(m_xController.is())
+ {
+ if(!commitFormAndSubforms(m_xController, lcl_needConfirmCommit( _nFeature )))
+ return;
+ }
+ else if(m_xCursor.is())
+ {
+ Reference< XForm > xForm(m_xCursor, UNO_QUERY);
+ assert(xForm.is());
+ if(!commitFormAndSubforms(xForm, lcl_needConfirmCommit( _nFeature )))
+ return;
+ }
+ else
+ {
+ SAL_WARN( "forms.runtime", "No cursor, but trying to execute form operation " << _nFeature );
+ }
+ }
+
+ try
+ {
+ switch ( _nFeature )
+ {
+ case FormFeature::MoveToFirst:
+ m_xCursor->first();
+ break;
+
+ case FormFeature::MoveToNext:
+ impl_moveRight_throw( );
+ break;
+
+ case FormFeature::MoveToPrevious:
+ impl_moveLeft_throw( );
+ break;
+
+ case FormFeature::MoveToLast:
+ {
+/*
+ // TODO: re-implement this...
+ // run in an own thread if...
+ // ... the data source is thread safe...
+ sal_Bool bAllowOwnThread = sal_False;
+ if ( ::comphelper::hasProperty( PROPERTY_THREADSAFE, m_xCursorProperties ) )
+ m_xCursorProperties->getPropertyValue( PROPERTY_THREADSAFE ) >>= bAllowOwnThread;
+
+ // ... the record count is unknown
+ sal_Bool bNeedOwnThread sal_False;
+ if ( ::comphelper::hasProperty( PROPERTY_ROWCOUNTFINAL, m_xCursorProperties ) )
+ m_xCursorProperties->getPropertyValue( PROPERTY_ROWCOUNTFINAL ) >>= bNeedOwnThread;
+
+ if ( bNeedOwnThread && bAllowOwnThread )
+ ;
+ else
+*/
+ m_xCursor->last();
+ }
+ break;
+
+ case FormFeature::ReloadForm:
+ if ( m_xLoadableForm.is() )
+ {
+ weld::WaitObject aWO(Application::GetFrameWeld(GetDialogParent()));
+ m_xLoadableForm->reload();
+
+ // refresh all controls in the form (and sub forms) which can be refreshed
+ // #i90914#
+ ::comphelper::IndexAccessIterator aIter( m_xLoadableForm );
+ Reference< XInterface > xElement( aIter.Next() );
+ while ( xElement.is() )
+ {
+ Reference< XRefreshable > xRefresh( xElement, UNO_QUERY );
+ if ( xRefresh.is() )
+ xRefresh->refresh();
+ xElement = aIter.Next();
+ }
+ }
+ break;
+
+ case FormFeature::RefreshCurrentControl:
+ {
+ Reference< XRefreshable > xControlModelRefresh( impl_getCurrentControlModel_throw(), UNO_QUERY );
+ OSL_ENSURE( xControlModelRefresh.is(), "FormOperations::execute: how did you reach this?" );
+ if ( xControlModelRefresh.is() )
+ xControlModelRefresh->refresh();
+ }
+ break;
+
+ case FormFeature::DeleteRecord:
+ {
+ sal_uInt32 nCount = impl_getRowCount_throw();
+
+ // next position
+ bool bLeft = m_xCursor->isLast() && ( nCount > 1 );
+ bool bRight= !m_xCursor->isLast();
+ bool bSuccess = false;
+ try
+ {
+ // ask for confirmation
+ Reference< XConfirmDeleteListener > xConfirmDelete( m_xController, UNO_QUERY );
+
+ if ( xConfirmDelete.is() )
+ {
+ RowChangeEvent aEvent;
+ aEvent.Source.set( 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 = false;
+ }
+
+ if ( bSuccess )
+ {
+ if ( bLeft || bRight )
+ m_xCursor->relative( bRight ? 1 : -1 );
+ else
+ {
+ bool bCanInsert = ::dbtools::canInsert( m_xCursorProperties );
+ // is it possible to insert another record?
+ if ( bCanInsert )
+ m_xUpdateCursor->moveToInsertRow();
+ else
+ // move record to update status
+ m_xCursor->first();
+ }
+ }
+ }
+ break;
+
+ case FormFeature::SaveRecordChanges:
+ case FormFeature::UndoRecordChanges:
+ {
+ bool bInserting = impl_isInsertionRow_throw();
+
+ if ( FormFeature::UndoRecordChanges == _nFeature )
+ {
+ if ( !bInserting )
+ m_xUpdateCursor->cancelRowUpdates();
+
+ // reset all controls for this form
+ impl_resetAllControls_nothrow( );
+
+ 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 FormFeature::MoveToInsertRow:
+ // move to the last row before moving to the insert row
+ m_xCursor->last();
+ m_xUpdateCursor->moveToInsertRow();
+ break;
+
+ case FormFeature::RemoveFilterAndSort:
+ {
+ // simultaneously reset Filter and Order property
+ Reference< XMultiPropertySet > xProperties( m_xCursorProperties, UNO_QUERY );
+ OSL_ENSURE( xProperties.is(), "FormOperations::execute: no multi property access!" );
+ if ( xProperties.is() )
+ {
+ Sequence< OUString > aNames{ PROPERTY_FILTER, PROPERTY_HAVINGCLAUSE,
+ PROPERTY_SORT };
+
+ Sequence< Any> aValues{ Any(OUString()), Any(OUString()), Any(OUString()) };
+
+ weld::WaitObject aWO(Application::GetFrameWeld(GetDialogParent()));
+ xProperties->setPropertyValues( aNames, aValues );
+
+ if ( m_xLoadableForm.is() )
+ m_xLoadableForm->reload();
+ }
+ }
+ break;
+
+ case FormFeature::ToggleApplyFilter:
+ if ( impl_commitCurrentControl_throw() && impl_commitCurrentRecord_throw() )
+ {
+ // simply toggle the value
+ bool bApplied = false;
+ m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER ) >>= bApplied;
+ m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, Any( !bApplied ) );
+
+ // and reload
+ weld::WaitObject aWO(Application::GetFrameWeld(GetDialogParent()));
+ m_xLoadableForm->reload();
+ }
+ break;
+
+ case FormFeature::SortAscending:
+ impl_executeAutoSort_throw( true );
+ break;
+
+ case FormFeature::SortDescending:
+ impl_executeAutoSort_throw( false );
+ break;
+
+ case FormFeature::AutoFilter:
+ impl_executeAutoFilter_throw();
+ break;
+
+ case FormFeature::InteractiveSort:
+ impl_executeFilterOrSort_throw( false );
+ break;
+
+ case FormFeature::InteractiveFilter:
+ impl_executeFilterOrSort_throw( true );
+ break;
+
+ default:
+ {
+ TranslateId pErrorResourceId = RID_STR_FEATURE_UNKNOWN;
+ if ( lcl_requiresArguments( _nFeature ) )
+ pErrorResourceId = RID_STR_FEATURE_REQUIRES_PARAMETERS;
+ else if ( !lcl_isExecutableFeature( _nFeature ) )
+ pErrorResourceId = RID_STR_FEATURE_NOT_EXECUTABLE;
+ throw IllegalArgumentException( ResourceManager::loadString(pErrorResourceId), *this, 1 );
+ }
+ } // switch
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const SQLException& ) { throw; }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
+ }
+
+ impl_invalidateAllSupportedFeatures_nothrow( aGuard );
+ }
+
+
+ void SAL_CALL FormOperations::executeWithArguments( ::sal_Int16 _nFeature, const Sequence< NamedValue >& _rArguments )
+ {
+ if ( !lcl_requiresArguments( _nFeature ) )
+ {
+ execute( _nFeature );
+ return;
+ }
+
+ SolarMutexGuard aSolarGuard;
+ MethodGuard aGuard( *this );
+
+ // at the moment we have only one feature which supports execution parameters
+ if ( !lcl_isExecutableFeature( _nFeature ) )
+ throw IllegalArgumentException( ResourceManager::loadString(RID_STR_FEATURE_NOT_EXECUTABLE), *this, 1 );
+
+ switch ( _nFeature )
+ {
+ case FormFeature::MoveAbsolute:
+ {
+ sal_Int32 nPosition = -1;
+
+ ::comphelper::NamedValueCollection aArguments( _rArguments );
+ aArguments.get_ensureType( "Position", nPosition );
+
+ if ( nPosition < 1 )
+ nPosition = 1;
+
+ try
+ {
+ // commit before doing anything else
+ if ( m_xController.is() && !impl_commitCurrentControl_throw() )
+ return;
+ if ( !impl_commitCurrentRecord_throw() )
+ return;
+
+ sal_Int32 nCount = impl_getRowCount_throw();
+ bool bFinalCount = impl_isRowCountFinal_throw();
+
+ if ( bFinalCount && ( nPosition > nCount ) )
+ nPosition = nCount;
+
+ m_xCursor->absolute( nPosition );
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const SQLException& ) { throw; }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
+ }
+ }
+ break;
+ default:
+ throw IllegalArgumentException( ResourceManager::loadString(RID_STR_FEATURE_UNKNOWN), *this, 1 );
+ } // switch
+ }
+
+
+ sal_Bool SAL_CALL FormOperations::commitCurrentRecord( sal_Bool& _out_rRecordInserted )
+ {
+ MethodGuard aGuard( *this );
+ _out_rRecordInserted = false;
+
+ return impl_commitCurrentRecord_throw( &_out_rRecordInserted );
+ }
+
+
+ bool FormOperations::impl_commitCurrentRecord_throw( sal_Bool* _pRecordInserted ) const
+ {
+#ifdef DBG_UTIL
+ DBG_ASSERT( m_nMethodNestingLevel, "FormOperations::impl_commitCurrentRecord_throw: to be called within a MethodGuard'ed section only!" );
+#endif
+
+ if ( !impl_hasCursor_nothrow() )
+ return false;
+
+ // nothing to do if the record is not modified
+ bool bResult = !impl_isModifiedRow_throw();
+ if ( !bResult )
+ {
+ // insert respectively update the row
+ if ( impl_isInsertionRow_throw() )
+ {
+ m_xUpdateCursor->insertRow();
+ if ( _pRecordInserted )
+ *_pRecordInserted = true;
+ }
+ else
+ m_xUpdateCursor->updateRow();
+ bResult = true;
+ }
+ return bResult;
+ }
+
+
+ sal_Bool SAL_CALL FormOperations::commitCurrentControl()
+ {
+ MethodGuard aGuard( *this );
+ return impl_commitCurrentControl_throw();
+ }
+
+
+ bool FormOperations::impl_commitCurrentControl_throw() const
+ {
+#ifdef DBG_UTIL
+ DBG_ASSERT( m_nMethodNestingLevel, "FormOperations::impl_commitCurrentControl_throw: to be called within a MethodGuard'ed section only!" );
+#endif
+ OSL_PRECOND( m_xController.is(), "FormOperations::commitCurrentControl: no controller!" );
+ if ( !m_xController.is() )
+ return false;
+
+ bool bSuccess = false;
+ try
+ {
+ Reference< XControl > xCurrentControl( m_xController->getCurrentControl() );
+
+ // check whether the control is locked
+ Reference< XBoundControl > xCheckLock( xCurrentControl, UNO_QUERY );
+ bool bControlIsLocked = xCheckLock.is() && xCheckLock->getLock();
+
+ // commit if necessary
+ bSuccess = true;
+ if ( xCurrentControl.is() && !bControlIsLocked )
+ {
+ // both the control and its model can be committable, so try both
+ Reference< XBoundComponent > xBound( xCurrentControl, UNO_QUERY );
+ if ( !xBound.is() )
+ xBound.set(xCurrentControl->getModel(), css::uno::UNO_QUERY);
+ // and now really commit
+ if ( xBound.is() )
+ bSuccess = xBound->commit();
+ }
+
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const SQLException& ) { throw; }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("forms.runtime");
+ bSuccess = false;
+ }
+
+ return bSuccess;
+ }
+
+
+ sal_Bool SAL_CALL FormOperations::isInsertionRow()
+ {
+ bool bIs = false;
+ try
+ {
+ bIs = impl_isInsertionRow_throw();
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
+ }
+ return bIs;
+ }
+
+
+ sal_Bool SAL_CALL FormOperations::isModifiedRow()
+ {
+ bool bIs = false;
+ try
+ {
+ bIs = impl_isModifiedRow_throw();
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
+ }
+ return bIs;
+ }
+
+
+ void SAL_CALL FormOperations::cursorMoved( const EventObject& /*_Event*/ )
+ {
+ MethodGuard aGuard( *this );
+ m_bActiveControlModified = false;
+
+ impl_invalidateAllSupportedFeatures_nothrow( aGuard );
+ }
+
+
+ void SAL_CALL FormOperations::rowChanged( const EventObject& /*_Event*/ )
+ {
+ // not interested in
+ }
+
+
+ void SAL_CALL FormOperations::rowSetChanged( const EventObject& /*_Event*/ )
+ {
+ // not interested in
+ }
+
+
+ void SAL_CALL FormOperations::modified( const EventObject& /*_Source*/ )
+ {
+ MethodGuard aGuard( *this );
+
+ OSL_ENSURE( m_xCursor.is(), "FormOperations::modified: already disposed!" );
+ if ( !m_bActiveControlModified )
+ {
+ m_bActiveControlModified = true;
+ impl_invalidateModifyDependentFeatures_nothrow( aGuard );
+ }
+ }
+
+
+ void SAL_CALL FormOperations::propertyChange( const PropertyChangeEvent& _rEvent )
+ {
+ MethodGuard aGuard( *this );
+
+ if ( m_xCursor.is() && ( m_xCursor == _rEvent.Source ) )
+ {
+ if ( ( _rEvent.PropertyName == PROPERTY_ISMODIFIED )
+ || ( _rEvent.PropertyName == PROPERTY_ISNEW )
+ )
+ {
+ bool bIs = false;
+ if ( ( _rEvent.NewValue >>= bIs ) && !bIs )
+ m_bActiveControlModified = false;
+ }
+ impl_invalidateAllSupportedFeatures_nothrow( aGuard );
+ }
+
+ if ( !(m_xParser.is() && ( m_xCursor == _rEvent.Source )) )
+ return;
+
+ try
+ {
+ OUString sNewValue;
+ _rEvent.NewValue >>= sNewValue;
+ if ( _rEvent.PropertyName == PROPERTY_ACTIVECOMMAND )
+ {
+ m_xParser->setElementaryQuery( sNewValue );
+ }
+ else if ( _rEvent.PropertyName == PROPERTY_FILTER )
+ {
+ if ( m_xParser->getFilter() != sNewValue )
+ m_xParser->setFilter( sNewValue );
+ }
+ else if ( _rEvent.PropertyName == PROPERTY_HAVINGCLAUSE )
+ {
+ if ( m_xParser->getHavingClause() != sNewValue )
+ m_xParser->setHavingClause( sNewValue );
+ }
+ else if ( _rEvent.PropertyName == PROPERTY_SORT )
+ {
+ _rEvent.NewValue >>= sNewValue;
+ if ( m_xParser->getOrder() != sNewValue )
+ m_xParser->setOrder( sNewValue );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::propertyChange: caught an exception while updating the parser!" );
+ }
+ impl_invalidateAllSupportedFeatures_nothrow( aGuard );
+ }
+
+
+ void SAL_CALL FormOperations::disposing( const EventObject& /*_Source*/ )
+ {
+ // TODO: should we react on this? Or is this the responsibility of our owner to dispose us?
+ }
+
+
+ void SAL_CALL FormOperations::disposing()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ impl_disposeParser_nothrow();
+
+ try
+ {
+ // revoke various listeners
+ if ( m_xCursor.is() )
+ m_xCursor->removeRowSetListener( this );
+
+ if ( m_xCursorProperties.is() )
+ {
+ m_xCursorProperties->removePropertyChangeListener( PROPERTY_ISMODIFIED,this );
+ m_xCursorProperties->removePropertyChangeListener( PROPERTY_ISNEW, this );
+ }
+
+ if ( m_xController.is() )
+ m_xController->removeModifyListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("forms.runtime");
+ }
+
+ m_xController.clear();
+ m_xCursor.clear();
+ m_xUpdateCursor.clear();
+ m_xCursorProperties.clear();
+ m_xLoadableForm.clear();
+ m_xFeatureInvalidation.clear();
+
+ m_bActiveControlModified = true;
+ }
+
+
+ void FormOperations::impl_checkDisposed_throw() const
+ {
+ if ( !m_xCursor.is() )
+ throw DisposedException( OUString(), *const_cast< FormOperations* >( this ) );
+ }
+
+
+ void FormOperations::impl_initFromController_throw()
+ {
+ OSL_PRECOND( m_xController.is(), "FormOperations::impl_initFromController_throw: invalid controller!" );
+ m_xCursor.set(m_xController->getModel(), css::uno::UNO_QUERY);
+ if ( !m_xCursor.is() )
+ throw IllegalArgumentException( OUString(), *this, 0 );
+
+ impl_initFromForm_throw();
+
+ if ( m_xController.is() )
+ m_xController->addModifyListener( this );
+ }
+
+
+ void FormOperations::impl_initFromForm_throw()
+ {
+ OSL_PRECOND( m_xCursor.is(), "FormOperations::impl_initFromForm_throw: invalid form!" );
+ m_xCursorProperties.set(m_xCursor, css::uno::UNO_QUERY);
+ m_xUpdateCursor.set(m_xCursor, css::uno::UNO_QUERY);
+ m_xLoadableForm.set(m_xCursor, css::uno::UNO_QUERY);
+
+ if ( !m_xCursor.is() || !m_xCursorProperties.is() || !m_xLoadableForm.is() )
+ throw IllegalArgumentException( OUString(), *this, 0 );
+
+ m_xCursor->addRowSetListener( this );
+ m_xCursorProperties->addPropertyChangeListener( PROPERTY_ISMODIFIED,this );
+ m_xCursorProperties->addPropertyChangeListener( PROPERTY_ISNEW, this );
+ }
+
+
+ void FormOperations::createWithFormController( const Reference< XFormController >& _rxController )
+ {
+ m_xController = _rxController;
+ if ( !m_xController.is() )
+ throw IllegalArgumentException( OUString(), *this, 0 );
+
+ impl_initFromController_throw();
+
+ m_bConstructed = true;
+ }
+
+
+ void FormOperations::createWithForm( const Reference< XForm >& _rxForm )
+ {
+ m_xCursor.set(_rxForm, css::uno::UNO_QUERY);
+ if ( !m_xCursor.is() )
+ throw IllegalArgumentException( OUString(), *this, 0 );
+
+ impl_initFromForm_throw();
+
+ m_bConstructed = true;
+ }
+
+
+ void FormOperations::impl_invalidateAllSupportedFeatures_nothrow( MethodGuard& _rClearForCallback ) const
+ {
+ if ( !m_xFeatureInvalidation.is() )
+ // nobody's interested in ...
+ return;
+
+ Reference< XFeatureInvalidation > xInvalidation = m_xFeatureInvalidation;
+ _rClearForCallback.clear();
+ xInvalidation->invalidateAllFeatures();
+ }
+
+
+ void FormOperations::impl_invalidateModifyDependentFeatures_nothrow( MethodGuard& _rClearForCallback ) const
+ {
+ if ( !m_xFeatureInvalidation.is() )
+ // nobody's interested in ...
+ return;
+
+ static Sequence< sal_Int16 > const s_aModifyDependentFeatures
+ {
+ FormFeature::MoveToNext,
+ FormFeature::MoveToInsertRow,
+ FormFeature::SaveRecordChanges,
+ FormFeature::UndoRecordChanges
+ };
+
+ Reference< XFeatureInvalidation > xInvalidation = m_xFeatureInvalidation;
+ _rClearForCallback.clear();
+
+ xInvalidation->invalidateFeatures( s_aModifyDependentFeatures );
+ }
+
+
+ void FormOperations::impl_ensureInitializedParser_nothrow()
+ {
+ OSL_PRECOND( m_xCursorProperties.is(), "FormOperations::impl_ensureInitializedParser_nothrow: we're disposed!" );
+ if ( m_bInitializedParser )
+ return;
+
+ try
+ {
+ bool bUseEscapeProcessing = false;
+ m_xCursorProperties->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bUseEscapeProcessing;
+ if ( bUseEscapeProcessing )
+ {
+ Reference< XMultiServiceFactory > xFactory( ::dbtools::getConnection( m_xCursor ), UNO_QUERY );
+ if ( xFactory.is() )
+ {
+ m_xParser.set( xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"), UNO_QUERY );
+ OSL_ENSURE( m_xParser.is(), "FormOperations::impl_ensureInitializedParser_nothrow: factory did not create a parser for us!" );
+ }
+ }
+
+ if ( m_xParser.is() )
+ {
+ if ( m_xLoadableForm.is() && m_xLoadableForm->isLoaded() )
+ {
+ OUString sStatement;
+ OUString sFilter;
+ OUString sHaving;
+ OUString sSort;
+
+ m_xCursorProperties->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sStatement;
+ m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
+ m_xCursorProperties->getPropertyValue( PROPERTY_HAVINGCLAUSE ) >>= sHaving;
+ m_xCursorProperties->getPropertyValue( PROPERTY_SORT ) >>= sSort;
+
+ m_xParser->setElementaryQuery( sStatement );
+ m_xParser->setFilter ( sFilter );
+ m_xParser->setHavingClause ( sHaving );
+ m_xParser->setOrder ( sSort );
+ }
+
+ // start listening at the order/sort properties at the form, so
+ // we can keep our parser in sync
+ m_xCursorProperties->addPropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
+ m_xCursorProperties->addPropertyChangeListener( PROPERTY_FILTER, this );
+ m_xCursorProperties->addPropertyChangeListener( PROPERTY_HAVINGCLAUSE, this );
+ m_xCursorProperties->addPropertyChangeListener( PROPERTY_SORT, this );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::impl_ensureInitializedParser_nothrow" );
+ }
+
+ m_bInitializedParser = true;
+ }
+
+
+ void FormOperations::impl_disposeParser_nothrow()
+ {
+ 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( PROPERTY_FILTER, this );
+ m_xCursorProperties->removePropertyChangeListener( PROPERTY_HAVINGCLAUSE, this );
+ m_xCursorProperties->removePropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
+ m_xCursorProperties->removePropertyChangeListener( PROPERTY_SORT, this );
+ }
+
+ Reference< XComponent > xParserComp( m_xParser, UNO_QUERY );
+ if ( xParserComp.is() )
+ xParserComp->dispose();
+ m_xParser.clear();
+
+ m_bInitializedParser = false;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::impl_disposeParser_nothrow" );
+ }
+ }
+
+
+ bool FormOperations::impl_canMoveLeft_throw( ) const
+ {
+ if ( !impl_hasCursor_nothrow() )
+ return false;
+
+ return impl_getRowCount_throw() && ( !m_xCursor->isFirst() || impl_isInsertionRow_throw() );
+ }
+
+
+ bool FormOperations::impl_canMoveRight_throw( ) const
+ {
+ if ( !impl_hasCursor_nothrow() )
+ return false;
+
+ bool bIsNew = impl_isInsertionRow_throw();
+
+ if ( impl_getRowCount_throw() && !m_xCursor->isLast() && !bIsNew )
+ return true;
+
+ if ( ::dbtools::canInsert( m_xCursorProperties ) )
+ if ( !bIsNew || impl_isModifiedRow_throw() )
+ return true;
+
+ if ( bIsNew && m_bActiveControlModified )
+ return true;
+
+ return false;
+ }
+
+
+ bool FormOperations::impl_isInsertionRow_throw() const
+ {
+ return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ISNEW, false );
+ }
+
+
+ sal_Int32 FormOperations::impl_getRowCount_throw() const
+ {
+ return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ROWCOUNT, sal_Int32(0) );
+ }
+
+ bool FormOperations::impl_isRowCountFinal_throw() const
+ {
+ return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ROWCOUNTFINAL, false );
+ }
+
+
+ bool FormOperations::impl_isModifiedRow_throw() const
+ {
+ return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ISMODIFIED, false );
+ }
+
+
+ bool FormOperations::impl_isParseable_throw() const
+ {
+ const_cast< FormOperations* >( this )->impl_ensureInitializedParser_nothrow();
+ return m_xParser.is() && !m_xParser->getQuery().isEmpty();
+ }
+
+
+ bool FormOperations::impl_hasFilterOrOrder_throw() const
+ {
+ return impl_isParseable_throw() && ( !m_xParser->getFilter().isEmpty() ||
+ !m_xParser->getHavingClause().isEmpty() ||
+ !m_xParser->getOrder().isEmpty() );
+ }
+
+
+ bool FormOperations::impl_isInsertOnlyForm_throw() const
+ {
+ return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_INSERTONLY, true );
+ }
+
+
+ Reference< XControlModel > FormOperations::impl_getCurrentControlModel_throw() const
+ {
+ Reference< XControl > xControl( m_xController->getCurrentControl() );
+
+ // special handling for grid controls
+ Reference< XGrid > xGrid( xControl, UNO_QUERY );
+ Reference< XControlModel > xControlModel;
+
+ if ( xGrid.is() )
+ {
+ Reference< XIndexAccess > xColumns( xControl->getModel(), UNO_QUERY_THROW );
+ sal_Int32 nCurrentPos = impl_gridView2ModelPos_nothrow( xColumns, xGrid->getCurrentColumnPosition() );
+
+ if ( nCurrentPos != -1 )
+ xColumns->getByIndex( nCurrentPos ) >>= xControlModel;
+ }
+ else if ( xControl.is() )
+ {
+ xControlModel = xControl->getModel();
+ }
+ return xControlModel;
+ }
+
+
+ Reference< XPropertySet > FormOperations::impl_getCurrentBoundField_nothrow( ) const
+ {
+ OSL_PRECOND( m_xController.is(), "FormOperations::impl_getCurrentBoundField_nothrow: no controller -> no control!" );
+ if ( !m_xController.is() )
+ return nullptr;
+
+ Reference< XPropertySet > xField;
+ try
+ {
+ Reference< XPropertySet > xControlModel( impl_getCurrentControlModel_throw(), UNO_QUERY );
+
+ if ( xControlModel.is() && ::comphelper::hasProperty( PROPERTY_BOUNDFIELD, xControlModel ) )
+ xControlModel->getPropertyValue( PROPERTY_BOUNDFIELD ) >>= xField;
+
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("forms.runtime");
+ }
+
+ return xField;
+ }
+
+
+ sal_Int32 FormOperations::impl_gridView2ModelPos_nothrow( const Reference< XIndexAccess >& _rxColumns, sal_Int16 _nViewPos )
+ {
+ OSL_PRECOND( _rxColumns.is(), "FormOperations::impl_gridView2ModelPos_nothrow: invalid columns container!" );
+ try
+ {
+ // loop through all columns
+ sal_Int32 col = 0;
+ Reference< XPropertySet > xCol;
+ bool bHidden( false );
+ for ( col = 0; col < _rxColumns->getCount(); ++col )
+ {
+ _rxColumns->getByIndex( col ) >>= xCol;
+ OSL_VERIFY( xCol->getPropertyValue( PROPERTY_HIDDEN ) >>= bHidden );
+ if ( bHidden )
+ continue;
+
+ // for every visible col : if nViewPos is greater zero, decrement it, else we
+ // have found the model position
+ if ( !_nViewPos )
+ break;
+ else
+ --_nViewPos;
+ }
+ if ( col < _rxColumns->getCount() )
+ return col;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("forms.runtime");
+ }
+ return -1;
+ }
+
+
+ void FormOperations::impl_moveLeft_throw( ) const
+ {
+ OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_moveLeft_throw: no cursor!" );
+ if ( !impl_hasCursor_nothrow() )
+ return;
+
+ sal_Bool bRecordInserted = false;
+ bool bSuccess = impl_commitCurrentRecord_throw( &bRecordInserted );
+
+ if ( !bSuccess )
+ return;
+
+ if ( bRecordInserted )
+ {
+ // retrieve the bookmark of the new record and move to the record preceding this bookmark
+ Reference< XRowLocate > xLocate( m_xCursor, UNO_QUERY );
+ OSL_ENSURE( xLocate.is(), "FormOperations::impl_moveLeft_throw: no XRowLocate!" );
+ if ( xLocate.is() )
+ xLocate->moveRelativeToBookmark( xLocate->getBookmark(), -1 );
+ }
+ else
+ {
+ if ( impl_isInsertionRow_throw() )
+ {
+ // we assume that the inserted record is now the last record in the
+ // result set
+ m_xCursor->last();
+ }
+ else
+ m_xCursor->previous();
+ }
+ }
+
+
+ void FormOperations::impl_moveRight_throw( ) const
+ {
+ OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_moveRight_throw: no cursor!" );
+ if ( !impl_hasCursor_nothrow() )
+ return;
+
+ sal_Bool bRecordInserted = false;
+ bool bSuccess = impl_commitCurrentRecord_throw( &bRecordInserted );
+
+ if ( !bSuccess )
+ return;
+
+ if ( bRecordInserted )
+ {
+ // go to insert row
+ m_xUpdateCursor->moveToInsertRow();
+ }
+ else
+ {
+ if ( m_xCursor->isLast() )
+ m_xUpdateCursor->moveToInsertRow();
+ else
+ (void)m_xCursor->next();
+ }
+ }
+
+
+ void FormOperations::impl_resetAllControls_nothrow() const
+ {
+ Reference< XIndexAccess > xContainer( m_xCursor, UNO_QUERY );
+ if ( !xContainer.is() )
+ return;
+
+ try
+ {
+ Reference< XReset > xReset;
+ sal_Int32 nCount( xContainer->getCount() );
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ if ( xContainer->getByIndex( i ) >>= xReset )
+ {
+ // no resets on sub forms
+ Reference< XForm > xAsForm( xReset, UNO_QUERY );
+ if ( !xAsForm.is() )
+ xReset->reset();
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("forms.runtime");
+ }
+ }
+
+
+ void FormOperations::impl_executeAutoSort_throw( bool _bUp ) const
+ {
+ OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeAutoSort_throw: need a controller for this!" );
+ OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeAutoSort_throw: need a cursor for this!" );
+ OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeAutoSort_throw: need a parseable statement for this!" );
+ if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
+ return;
+
+ try
+ {
+ Reference< XControl > xControl = m_xController->getCurrentControl();
+ if ( !xControl.is() || !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
+ return;
+
+ Reference< XPropertySet > xBoundField( impl_getCurrentBoundField_nothrow() );
+ if ( !xBoundField.is() )
+ return;
+
+ OUString sOriginalSort;
+ m_xCursorProperties->getPropertyValue( PROPERTY_SORT ) >>= sOriginalSort;
+
+ // automatic sort by field is expected to always resets the previous sort order
+ m_xParser->setOrder( OUString() );
+
+ impl_appendOrderByColumn_throw aAction(this, xBoundField, _bUp);
+ impl_doActionInSQLContext_throw(std::move(aAction), RID_STR_COULD_NOT_SET_ORDER );
+
+ weld::WaitObject aWO(Application::GetFrameWeld(GetDialogParent()));
+ try
+ {
+ m_xCursorProperties->setPropertyValue( PROPERTY_SORT, Any( m_xParser->getOrder() ) );
+ m_xLoadableForm->reload();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::impl_executeAutoSort_throw: 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( PROPERTY_SORT, Any( m_xParser->getOrder() ) );
+ m_xLoadableForm->reload();
+ }
+ catch( const Exception& )
+ {
+ OSL_FAIL( "FormOperations::impl_executeAutoSort_throw: could not reset the form to its original state!" );
+ }
+
+ }
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const SQLException& ) { throw; }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException( OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
+ }
+ }
+
+
+ void FormOperations::impl_executeAutoFilter_throw( ) const
+ {
+ OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeAutoFilter_throw: need a controller for this!" );
+ OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeAutoFilter_throw: need a cursor for this!" );
+ OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeAutoFilter_throw: need a parseable statement for this!" );
+ if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
+ return;
+
+ try
+ {
+ Reference< XControl > xControl = m_xController->getCurrentControl();
+ if ( !xControl.is() || !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
+ return;
+
+ Reference< XPropertySet > xBoundField( impl_getCurrentBoundField_nothrow() );
+ if ( !xBoundField.is() )
+ return;
+
+ OUString sOriginalFilter;
+ OUString sOriginalHaving;
+ m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sOriginalFilter;
+ m_xCursorProperties->getPropertyValue( PROPERTY_HAVINGCLAUSE ) >>= sOriginalHaving;
+ bool bApplied = true;
+ m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER ) >>= bApplied;
+
+ // if we have a filter, but it's not applied, then we have to overwrite it, else append one
+ if ( !bApplied )
+ {
+ m_xParser->setFilter( OUString() );
+ m_xParser->setHavingClause( OUString() );
+ }
+
+ impl_appendFilterByColumn_throw aAction(this, m_xParser, xBoundField);
+ impl_doActionInSQLContext_throw( std::move(aAction), RID_STR_COULD_NOT_SET_FILTER );
+
+ weld::WaitObject aWO(Application::GetFrameWeld(GetDialogParent()));
+ try
+ {
+ m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, Any( m_xParser->getFilter() ) );
+ m_xCursorProperties->setPropertyValue( PROPERTY_HAVINGCLAUSE, Any( m_xParser->getHavingClause() ) );
+ m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, Any( true ) );
+
+ m_xLoadableForm->reload();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::impl_executeAutoFilter_throw: caught an exception while setting the parser properties!" );
+ }
+
+
+ if ( !m_xLoadableForm->isLoaded() )
+ { // something went wrong -> restore the original state
+ try
+ {
+ m_xParser->setFilter ( sOriginalFilter );
+ m_xParser->setHavingClause( sOriginalHaving );
+ m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, Any( bApplied ) );
+ m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, Any( m_xParser->getFilter() ) );
+ m_xCursorProperties->setPropertyValue( PROPERTY_HAVINGCLAUSE, Any( m_xParser->getHavingClause() ) );
+ m_xLoadableForm->reload();
+ }
+ catch( const Exception& )
+ {
+ OSL_FAIL( "FormOperations::impl_executeAutoFilter_throw: could not reset the form to its original state!" );
+ }
+
+ }
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const SQLException& ) { throw; }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException( OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
+ }
+ }
+
+ css::uno::Reference<css::awt::XWindow> FormOperations::GetDialogParent() const
+ {
+ css::uno::Reference<css::awt::XWindow> xDialogParent;
+
+ //tdf#122152 extract parent for dialog
+ if (m_xController.is())
+ {
+ css::uno::Reference<css::awt::XControl> xContainerControl(m_xController->getContainer(), css::uno::UNO_QUERY);
+ if (xContainerControl.is())
+ {
+ css::uno::Reference<css::awt::XWindowPeer> xContainerPeer = xContainerControl->getPeer();
+ xDialogParent = css::uno::Reference<css::awt::XWindow>(xContainerPeer, css::uno::UNO_QUERY);
+ }
+ }
+
+ return xDialogParent;
+ }
+
+ void FormOperations::impl_executeFilterOrSort_throw( bool _bFilter ) const
+ {
+ OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeFilterOrSort_throw: need a controller for this!" );
+ OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeFilterOrSort_throw: need a cursor for this!" );
+ OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeFilterOrSort_throw: need a parseable statement for this!" );
+ if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
+ return;
+
+ if ( !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
+ return;
+ try
+ {
+ css::uno::Reference<css::awt::XWindow> xDialogParent(GetDialogParent());
+
+ Reference< XExecutableDialog> xDialog;
+ if ( _bFilter )
+ {
+ xDialog = css::sdb::FilterDialog::createWithQuery(m_xContext, m_xParser, m_xCursor,
+ xDialogParent);
+ }
+ else
+ {
+ xDialog = css::sdb::OrderDialog::createWithQuery(m_xContext, m_xParser, m_xCursorProperties,
+ xDialogParent);
+ }
+
+ if ( RET_OK == xDialog->execute() )
+ {
+ weld::WaitObject aWO(Application::GetFrameWeld(xDialogParent));
+ if ( _bFilter )
+ {
+ m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, Any( m_xParser->getFilter() ) );
+ m_xCursorProperties->setPropertyValue( PROPERTY_HAVINGCLAUSE, Any( m_xParser->getHavingClause() ) );
+ }
+ else
+ m_xCursorProperties->setPropertyValue( PROPERTY_SORT, Any( m_xParser->getOrder() ) );
+ m_xLoadableForm->reload();
+ }
+
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const SQLException& ) { throw; }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException( OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
+ }
+ }
+
+
+ template < typename FunctObj >
+ void FormOperations::impl_doActionInSQLContext_throw( FunctObj f, TranslateId pErrorResourceId ) const
+ {
+ try
+ {
+ f();
+ }
+#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
+ catch( const SQLException& )
+ {
+ if (!pErrorResourceId) // no information to prepend
+ throw;
+
+ SQLExceptionInfo aInfo( ::cppu::getCaughtException() );
+ OUString sAdditionalError( ResourceManager::loadString(pErrorResourceId) );
+ aInfo.prepend( sAdditionalError );
+ aInfo.doThrow();
+ }
+#endif
+ catch( const RuntimeException& ) { throw; }
+ catch( const Exception& )
+ {
+ OUString sAdditionalError( ResourceManager::loadString(pErrorResourceId) );
+ throw WrappedTargetException( sAdditionalError, *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
+ }
+ }
+
+
+} // namespace frm
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_forms_FormOperations_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new frm::FormOperations(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/runtime/formoperations.hxx b/forms/source/runtime/formoperations.hxx
new file mode 100644
index 000000000..182b0a7e0
--- /dev/null
+++ b/forms/source/runtime/formoperations.hxx
@@ -0,0 +1,381 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/form/runtime/XFormOperations.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/form/XLoadable.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/util/XModifyListener.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <connectivity/dbtools.hxx>
+#include <tools/long.hxx>
+#include <unotools/resmgr.hxx>
+
+namespace frm
+{
+
+
+ //= FormOperations
+
+ typedef ::cppu::WeakComponentImplHelper < css::form::runtime::XFormOperations
+ , css::lang::XInitialization
+ , css::lang::XServiceInfo
+ , css::beans::XPropertyChangeListener
+ , css::util::XModifyListener
+ , css::sdbc::XRowSetListener
+ > FormOperations_Base;
+
+ class FormOperations :public ::cppu::BaseMutex
+ ,public FormOperations_Base
+ {
+ public:
+ class MethodGuard;
+
+ private:
+ css::uno::Reference<css::uno::XComponentContext> m_xContext;
+ css::uno::Reference< css::form::runtime::XFormController > m_xController;
+ css::uno::Reference< css::sdbc::XRowSet > m_xCursor;
+ css::uno::Reference< css::sdbc::XResultSetUpdate > m_xUpdateCursor;
+ css::uno::Reference< css::beans::XPropertySet > m_xCursorProperties;
+ css::uno::Reference< css::form::XLoadable > m_xLoadableForm;
+ css::uno::Reference< css::form::runtime::XFeatureInvalidation > m_xFeatureInvalidation;
+ mutable css::uno::Reference< css::sdb::XSingleSelectQueryComposer > m_xParser;
+
+ bool m_bInitializedParser;
+ bool m_bActiveControlModified;
+ bool m_bConstructed;
+ #ifdef DBG_UTIL
+ mutable tools::Long
+ m_nMethodNestingLevel;
+ #endif
+
+ public:
+ explicit FormOperations( const css::uno::Reference< css::uno::XComponentContext >& _rxContext );
+
+ struct MethodAccess { friend class MethodGuard; private: MethodAccess() { } };
+
+ void enterMethod( MethodAccess ) const
+ {
+ m_aMutex.acquire();
+ impl_checkDisposed_throw();
+ #ifdef DBG_UTIL
+ ++m_nMethodNestingLevel;
+ #endif
+ }
+
+ void leaveMethod( MethodAccess ) const
+ {
+ m_aMutex.release();
+ #ifdef DBG_UTIL
+ --m_nMethodNestingLevel;
+ #endif
+ }
+
+ protected:
+ virtual ~FormOperations() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XFormOperations
+ virtual css::uno::Reference< css::sdbc::XRowSet > SAL_CALL getCursor() override;
+ virtual css::uno::Reference< css::sdbc::XResultSetUpdate > SAL_CALL getUpdateCursor() override;
+ virtual css::uno::Reference< css::form::runtime::XFormController > SAL_CALL getController() override;
+ virtual css::uno::Reference< css::form::runtime::XFeatureInvalidation > SAL_CALL getFeatureInvalidation() override;
+ virtual void SAL_CALL setFeatureInvalidation(const css::uno::Reference< css::form::runtime::XFeatureInvalidation > & the_value) override;
+ virtual css::form::runtime::FeatureState SAL_CALL getState(::sal_Int16 Feature) override;
+ virtual sal_Bool SAL_CALL isEnabled(::sal_Int16 Feature) override;
+ virtual void SAL_CALL execute(::sal_Int16 Feature) override;
+ virtual void SAL_CALL executeWithArguments(::sal_Int16 Feature, const css::uno::Sequence< css::beans::NamedValue >& Arguments) override;
+ virtual sal_Bool SAL_CALL commitCurrentRecord(sal_Bool & RecordInserted) override;
+ virtual sal_Bool SAL_CALL commitCurrentControl() override;
+ virtual sal_Bool SAL_CALL isInsertionRow() override;
+ virtual sal_Bool SAL_CALL isModifiedRow() override;
+
+ // XRowSetListener
+ virtual void SAL_CALL cursorMoved( const css::lang::EventObject& event ) override;
+ virtual void SAL_CALL rowChanged( const css::lang::EventObject& event ) override;
+ virtual void SAL_CALL rowSetChanged( const css::lang::EventObject& event ) override;
+
+ // XModifyListener
+ virtual void SAL_CALL modified( const css::lang::EventObject& _rSource ) override;
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XComponent/OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ private:
+ // service constructors
+ void createWithFormController( const css::uno::Reference< css::form::runtime::XFormController >& _rxController );
+ void createWithForm( const css::uno::Reference< css::form::XForm >& _rxForm );
+
+ /** checks whether the instance is already disposed, and throws an exception if so
+ */
+ void impl_checkDisposed_throw() const;
+
+ /** initializes the instance after m_xController has been set
+ @precond
+ m_xController is not <NULL/>
+ */
+ void impl_initFromController_throw();
+
+ /** initializes the instance after m_xCursor has been set
+ @precond
+ m_xCursor is not <NULL/>
+ */
+ void impl_initFromForm_throw();
+
+ /// invalidate the full palette of features which we know
+ void impl_invalidateAllSupportedFeatures_nothrow( MethodGuard& _rClearForCallback ) const;
+
+ /** invalidate the features which depend on the "modified" state of the current control
+ of our controller
+ */
+ void impl_invalidateModifyDependentFeatures_nothrow( MethodGuard& _rClearForCallback ) const;
+
+ /** ensures that our parse is initialized, or at least that we attempted to do so
+ @precond
+ we're not disposed
+ */
+ void impl_ensureInitializedParser_nothrow();
+
+ /// disposes our parser, if we have one
+ void impl_disposeParser_nothrow();
+
+ /** determines whether our cursor can be moved left
+ @precond hasCursor()
+ */
+ bool impl_canMoveLeft_throw() const;
+
+ /** determines whether our cursor can be moved right
+ @precond hasCursor()
+ */
+ bool impl_canMoveRight_throw() const;
+
+ /// determines whether we're positioned on the insertion row
+ bool impl_isInsertionRow_throw() const;
+
+ /// retrieves the RowCount property of the form
+ sal_Int32 impl_getRowCount_throw() const;
+
+ /// retrieves the RowCountFinal property of the form
+ bool impl_isRowCountFinal_throw() const;
+
+ /// retrieves the IsModified property of the form
+ bool impl_isModifiedRow_throw() const;
+
+ /// determines whether we can parse the query of our form
+ bool impl_isParseable_throw() const;
+
+ /// determines if we have an active filter or order condition
+ bool impl_hasFilterOrOrder_throw() const;
+
+ /// determines whether our form is in "insert-only" mode
+ bool impl_isInsertOnlyForm_throw() const;
+
+ /** retrieves the column to which the current control of our controller is bound
+ @precond
+ m_xController.is()
+ */
+ css::uno::Reference< css::beans::XPropertySet >
+ impl_getCurrentBoundField_nothrow( ) const;
+
+ /** returns the control model of the current control
+
+ If the current control is a grid control, then the returned model is the
+ model of the current <em>column</em> in the grid.
+
+ @precond
+ m_xController.is()
+ */
+ css::uno::Reference< css::awt::XControlModel >
+ impl_getCurrentControlModel_throw() const;
+
+ /// determines if we have a valid cursor
+ bool impl_hasCursor_nothrow() const { return m_xCursorProperties.is(); }
+
+ /** determines the model position from a grid control column's view position
+
+ A grid control can have columns which are currently hidden, so the index of a
+ column in the view is not necessarily the same as its index in the model.
+ */
+ static sal_Int32 impl_gridView2ModelPos_nothrow( const css::uno::Reference< css::container::XIndexAccess >& _rxColumns, sal_Int16 _nViewPos );
+
+ /** moves our cursor one position to the left, caring for different possible
+ cursor states.
+
+ Before the movement is done, the current row is saved, if necessary.
+
+ @precond
+ canMoveLeft()
+ */
+ void impl_moveLeft_throw() const;
+
+ /** moves our cursor one position to the right, caring for different possible
+ cursor states.
+
+ Before the movement is done, the current row is saved, if necessary.
+
+ @precond
+ canMoveRight()
+ */
+ void impl_moveRight_throw( ) const;
+
+ /** impl-version of commitCurrentRecord, which can be called without caring for
+ an output parameter, and within const-contexts
+
+ @precond
+ our mutex is locked
+ */
+ bool impl_commitCurrentRecord_throw( sal_Bool* _pRecordInserted = nullptr ) const;
+
+ /** impl-version of commitCurrentControl, which can be called in const-contexts
+
+ @precond
+ our mutex is locked
+ */
+ bool impl_commitCurrentControl_throw() const;
+
+ /// resets all control models in our own form
+ void impl_resetAllControls_nothrow() const;
+
+ /// executes the "auto sort ascending" and "auto sort descending" features
+ void impl_executeAutoSort_throw( bool _bUp ) const;
+
+ /// executes the "auto filter" feature
+ void impl_executeAutoFilter_throw( ) const;
+
+ /// executes the interactive sort resp. filter feature
+ void impl_executeFilterOrSort_throw( bool _bFilter ) const;
+
+ private:
+ /** calls a (member) function, catches SQLExceptions, extends them with additional context information,
+ and rethrows them
+
+ @param f
+ a functionoid with no arguments to do the work
+ @param pErrorResourceId
+ the id of the resources string to use as error message
+ */
+ template < typename FunctObj >
+ void impl_doActionInSQLContext_throw( FunctObj f, TranslateId pErrorResourceId ) const;
+
+ // functionoid to call appendOrderByColumn
+ class impl_appendOrderByColumn_throw
+ {
+ public:
+ impl_appendOrderByColumn_throw(const FormOperations *pFO,
+ css::uno::Reference< css::beans::XPropertySet > const & xField,
+ bool bUp)
+ : m_pFO(pFO)
+ , m_xField(xField)
+ , m_bUp(bUp)
+ {};
+
+ void operator()() { m_pFO->m_xParser->appendOrderByColumn(m_xField, m_bUp); }
+ private:
+ const FormOperations *m_pFO;
+ css::uno::Reference< css::beans::XPropertySet > m_xField;
+ bool m_bUp;
+ };
+
+ // functionoid to call appendFilterByColumn
+ class impl_appendFilterByColumn_throw
+ {
+ public:
+ impl_appendFilterByColumn_throw(const FormOperations *pFO,
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer > const & xParser,
+ css::uno::Reference< css::beans::XPropertySet > const & xField)
+ : m_pFO(pFO)
+ , m_xParser(xParser)
+ , m_xField(xField)
+ {};
+
+ void operator()() {
+ if (dbtools::isAggregateColumn( m_xParser, m_xField ))
+ m_pFO->m_xParser->appendHavingClauseByColumn( m_xField, true, css::sdb::SQLFilterOperator::EQUAL );
+ else
+ m_pFO->m_xParser->appendFilterByColumn( m_xField, true, css::sdb::SQLFilterOperator::EQUAL );
+ }
+ private:
+ const FormOperations *m_pFO;
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer > m_xParser;
+ css::uno::Reference< css::beans::XPropertySet > m_xField;
+ };
+
+ private:
+ FormOperations( const FormOperations& ) = delete;
+ FormOperations& operator=( const FormOperations& ) = delete;
+
+ public:
+
+ css::uno::Reference<css::awt::XWindow> GetDialogParent() const;
+
+ class MethodGuard
+ {
+ FormOperations& m_rOwner;
+ bool m_bCleared;
+
+ public:
+ explicit MethodGuard( FormOperations& _rOwner )
+ :m_rOwner( _rOwner )
+ ,m_bCleared( false )
+ {
+ m_rOwner.enterMethod( FormOperations::MethodAccess() );
+ }
+
+ ~MethodGuard()
+ {
+ clear();
+ }
+
+ void clear()
+ {
+ if ( !m_bCleared )
+ m_rOwner.leaveMethod( FormOperations::MethodAccess() );
+ m_bCleared = true;
+ }
+ };
+ };
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */