4279 lines
148 KiB
C++
4279 lines
148 KiB
C++
/* -*- 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 "fmcontrolbordermanager.hxx"
|
|
#include "fmcontrollayout.hxx"
|
|
#include "formcontroller.hxx"
|
|
#include "formfeaturedispatcher.hxx"
|
|
#include "fmdocumentclassification.hxx"
|
|
#include "formcontrolling.hxx"
|
|
#include "fmprop.hrc"
|
|
#include "svx/dialmgr.hxx"
|
|
#include "svx/fmresids.hrc"
|
|
#include "fmservs.hxx"
|
|
#include "svx/fmtools.hxx"
|
|
#include "fmurl.hxx"
|
|
|
|
#include <com/sun/star/awt/FocusChangeReason.hpp>
|
|
#include <com/sun/star/awt/XCheckBox.hpp>
|
|
#include <com/sun/star/awt/XComboBox.hpp>
|
|
#include <com/sun/star/awt/XListBox.hpp>
|
|
#include <com/sun/star/awt/XVclWindowPeer.hpp>
|
|
#include <com/sun/star/awt/TabController.hpp>
|
|
#include <com/sun/star/beans/NamedValue.hpp>
|
|
#include <com/sun/star/beans/PropertyAttribute.hpp>
|
|
#include <com/sun/star/container/XIdentifierReplace.hpp>
|
|
#include <com/sun/star/form/TabulatorCycle.hpp>
|
|
#include <com/sun/star/form/validation/XValidatableFormComponent.hpp>
|
|
#include <com/sun/star/form/XBoundComponent.hpp>
|
|
#include <com/sun/star/form/XBoundControl.hpp>
|
|
#include <com/sun/star/form/XGridControl.hpp>
|
|
#include <com/sun/star/form/XLoadable.hpp>
|
|
#include <com/sun/star/form/XReset.hpp>
|
|
#include <com/sun/star/form/control/FilterControl.hpp>
|
|
#include <com/sun/star/frame/XController.hpp>
|
|
#include <com/sun/star/sdb/ParametersRequest.hpp>
|
|
#include <com/sun/star/sdb/RowChangeAction.hpp>
|
|
#include <com/sun/star/sdb/XInteractionSupplyParameters.hpp>
|
|
#include <com/sun/star/sdbc/ColumnValue.hpp>
|
|
#include <com/sun/star/sdbc/DataType.hpp>
|
|
#include <com/sun/star/task/InteractionHandler.hpp>
|
|
#include <com/sun/star/util/XURLTransformer.hpp>
|
|
#include <com/sun/star/form/runtime/FormOperations.hpp>
|
|
#include <com/sun/star/form/runtime/FormFeature.hpp>
|
|
#include <com/sun/star/container/XContainer.hpp>
|
|
#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
|
|
#include <com/sun/star/util/NumberFormatter.hpp>
|
|
#include <com/sun/star/sdb/SQLContext.hpp>
|
|
#include <com/sun/star/sdb/XColumn.hpp>
|
|
|
|
#include <comphelper/enumhelper.hxx>
|
|
#include <comphelper/interaction.hxx>
|
|
#include <comphelper/namedvaluecollection.hxx>
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <comphelper/propagg.hxx>
|
|
#include <comphelper/property.hxx>
|
|
#include <comphelper/sequence.hxx>
|
|
#include <comphelper/uno3.hxx>
|
|
#include <comphelper/flagguard.hxx>
|
|
#include <cppuhelper/queryinterface.hxx>
|
|
#include <cppuhelper/supportsservice.hxx>
|
|
#include <cppuhelper/typeprovider.hxx>
|
|
#include <connectivity/IParseContext.hxx>
|
|
#include <toolkit/controls/unocontrol.hxx>
|
|
#include <toolkit/helper/vclunohelper.hxx>
|
|
#include <tools/debug.hxx>
|
|
#include <tools/diagnose_ex.h>
|
|
#include <vcl/msgbox.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <osl/mutex.hxx>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <o3tl/compat_functional.hxx>
|
|
|
|
using namespace ::com::sun::star;
|
|
using namespace ::comphelper;
|
|
using namespace ::connectivity;
|
|
using namespace ::connectivity::simple;
|
|
|
|
|
|
::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL
|
|
FormController_NewInstance_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & _rxORB )
|
|
throw (css::uno::Exception)
|
|
{
|
|
return *( new ::svxform::FormController( comphelper::getComponentContext(_rxORB) ) );
|
|
}
|
|
|
|
namespace svxform
|
|
{
|
|
|
|
using ::com::sun::star::sdb::XColumn;
|
|
using ::com::sun::star::awt::XControl;
|
|
using ::com::sun::star::awt::XTabController;
|
|
using ::com::sun::star::awt::TabController;
|
|
using ::com::sun::star::awt::XToolkit;
|
|
using ::com::sun::star::awt::XWindowPeer;
|
|
using ::com::sun::star::form::XGrid;
|
|
using ::com::sun::star::beans::XPropertySet;
|
|
using ::com::sun::star::uno::UNO_SET_THROW;
|
|
using ::com::sun::star::uno::UNO_QUERY_THROW;
|
|
using ::com::sun::star::container::XIndexAccess;
|
|
using ::com::sun::star::uno::Exception;
|
|
using ::com::sun::star::uno::XInterface;
|
|
using ::com::sun::star::uno::UNO_QUERY;
|
|
using ::com::sun::star::uno::Sequence;
|
|
using ::com::sun::star::uno::Reference;
|
|
using ::com::sun::star::beans::XPropertySetInfo;
|
|
using ::com::sun::star::beans::PropertyValue;
|
|
using ::com::sun::star::uno::RuntimeException;
|
|
using ::com::sun::star::lang::IndexOutOfBoundsException;
|
|
using ::com::sun::star::sdb::XInteractionSupplyParameters;
|
|
using ::com::sun::star::awt::XTextComponent;
|
|
using ::com::sun::star::awt::XTextListener;
|
|
using ::com::sun::star::uno::Any;
|
|
using ::com::sun::star::frame::XDispatch;
|
|
using ::com::sun::star::lang::XMultiServiceFactory;
|
|
using ::com::sun::star::uno::XAggregation;
|
|
using ::com::sun::star::uno::Type;
|
|
using ::com::sun::star::lang::IllegalArgumentException;
|
|
using ::com::sun::star::sdbc::XConnection;
|
|
using ::com::sun::star::sdbc::XRowSet;
|
|
using ::com::sun::star::sdbc::XDatabaseMetaData;
|
|
using ::com::sun::star::util::XNumberFormatsSupplier;
|
|
using ::com::sun::star::util::NumberFormatter;
|
|
using ::com::sun::star::util::XNumberFormatter;
|
|
using ::com::sun::star::sdbcx::XColumnsSupplier;
|
|
using ::com::sun::star::container::XNameAccess;
|
|
using ::com::sun::star::lang::EventObject;
|
|
using ::com::sun::star::beans::Property;
|
|
using ::com::sun::star::container::XEnumeration;
|
|
using ::com::sun::star::form::XFormComponent;
|
|
using ::com::sun::star::form::runtime::XFormOperations;
|
|
using ::com::sun::star::form::runtime::FilterEvent;
|
|
using ::com::sun::star::form::runtime::XFilterControllerListener;
|
|
using ::com::sun::star::awt::XControlContainer;
|
|
using ::com::sun::star::container::XIdentifierReplace;
|
|
using ::com::sun::star::lang::WrappedTargetException;
|
|
using ::com::sun::star::form::XFormControllerListener;
|
|
using ::com::sun::star::awt::XWindow;
|
|
using ::com::sun::star::sdbc::XResultSet;
|
|
using ::com::sun::star::awt::XControlModel;
|
|
using ::com::sun::star::awt::XTabControllerModel;
|
|
using ::com::sun::star::beans::PropertyChangeEvent;
|
|
using ::com::sun::star::form::validation::XValidatableFormComponent;
|
|
using ::com::sun::star::form::XLoadable;
|
|
using ::com::sun::star::script::XEventAttacherManager;
|
|
using ::com::sun::star::form::XBoundControl;
|
|
using ::com::sun::star::beans::XPropertyChangeListener;
|
|
using ::com::sun::star::awt::TextEvent;
|
|
using ::com::sun::star::form::XBoundComponent;
|
|
using ::com::sun::star::awt::XCheckBox;
|
|
using ::com::sun::star::awt::XComboBox;
|
|
using ::com::sun::star::awt::XListBox;
|
|
using ::com::sun::star::awt::ItemEvent;
|
|
using ::com::sun::star::util::XModifyListener;
|
|
using ::com::sun::star::form::XReset;
|
|
using ::com::sun::star::frame::XDispatchProviderInterception;
|
|
using ::com::sun::star::form::XGridControl;
|
|
using ::com::sun::star::awt::XVclWindowPeer;
|
|
using ::com::sun::star::form::validation::XValidator;
|
|
using ::com::sun::star::awt::FocusEvent;
|
|
using ::com::sun::star::sdb::SQLContext;
|
|
using ::com::sun::star::container::XChild;
|
|
using ::com::sun::star::form::TabulatorCycle_RECORDS;
|
|
using ::com::sun::star::container::ContainerEvent;
|
|
using ::com::sun::star::lang::DisposedException;
|
|
using ::com::sun::star::lang::Locale;
|
|
using ::com::sun::star::beans::NamedValue;
|
|
using ::com::sun::star::lang::NoSupportException;
|
|
using ::com::sun::star::sdb::RowChangeEvent;
|
|
using ::com::sun::star::frame::XStatusListener;
|
|
using ::com::sun::star::frame::XDispatchProviderInterceptor;
|
|
using ::com::sun::star::sdb::SQLErrorEvent;
|
|
using ::com::sun::star::form::DatabaseParameterEvent;
|
|
using ::com::sun::star::sdb::ParametersRequest;
|
|
using ::com::sun::star::task::XInteractionRequest;
|
|
using ::com::sun::star::util::URL;
|
|
using ::com::sun::star::frame::FeatureStateEvent;
|
|
using ::com::sun::star::form::runtime::XFormControllerContext;
|
|
using ::com::sun::star::task::InteractionHandler;
|
|
using ::com::sun::star::task::XInteractionHandler;
|
|
using ::com::sun::star::form::runtime::FormOperations;
|
|
using ::com::sun::star::container::XContainer;
|
|
using ::com::sun::star::sdbc::SQLWarning;
|
|
|
|
namespace ColumnValue = ::com::sun::star::sdbc::ColumnValue;
|
|
namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
|
|
namespace FocusChangeReason = ::com::sun::star::awt::FocusChangeReason;
|
|
namespace RowChangeAction = ::com::sun::star::sdb::RowChangeAction;
|
|
namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
|
|
namespace DataType = ::com::sun::star::sdbc::DataType;
|
|
|
|
struct ColumnInfo
|
|
{
|
|
// information about the column itself
|
|
Reference< XColumn > xColumn;
|
|
sal_Int32 nNullable;
|
|
bool bAutoIncrement;
|
|
bool bReadOnly;
|
|
OUString sName;
|
|
|
|
// information about the control(s) bound to this column
|
|
|
|
/// the first control which is bound to the given column, and which requires input
|
|
Reference< XControl > xFirstControlWithInputRequired;
|
|
/** the first grid control which contains a column which is bound to the given database column, and requires
|
|
input
|
|
*/
|
|
Reference< XGrid > xFirstGridWithInputRequiredColumn;
|
|
/** if xFirstControlWithInputRequired is a grid control, then nRequiredGridColumn specifies the position
|
|
of the grid column which is actually bound
|
|
*/
|
|
sal_Int32 nRequiredGridColumn;
|
|
|
|
ColumnInfo()
|
|
:xColumn()
|
|
,nNullable( ColumnValue::NULLABLE_UNKNOWN )
|
|
,bAutoIncrement( false )
|
|
,bReadOnly( false )
|
|
,sName()
|
|
,xFirstControlWithInputRequired()
|
|
,xFirstGridWithInputRequiredColumn()
|
|
,nRequiredGridColumn( -1 )
|
|
{
|
|
}
|
|
};
|
|
|
|
class ColumnInfoCache
|
|
{
|
|
public:
|
|
ColumnInfoCache( const Reference< XColumnsSupplier >& _rxColSupplier );
|
|
|
|
size_t getColumnCount() const { return m_aColumns.size(); }
|
|
const ColumnInfo& getColumnInfo( size_t _pos );
|
|
|
|
bool controlsInitialized() const { return m_bControlsInitialized; }
|
|
void initializeControls( const Sequence< Reference< XControl > >& _rControls );
|
|
void deinitializeControls();
|
|
|
|
private:
|
|
typedef ::std::vector< ColumnInfo > ColumnInfos;
|
|
ColumnInfos m_aColumns;
|
|
bool m_bControlsInitialized;
|
|
};
|
|
|
|
|
|
ColumnInfoCache::ColumnInfoCache( const Reference< XColumnsSupplier >& _rxColSupplier )
|
|
:m_aColumns()
|
|
,m_bControlsInitialized( false )
|
|
{
|
|
try
|
|
{
|
|
m_aColumns.clear();
|
|
|
|
Reference< XIndexAccess > xColumns( _rxColSupplier->getColumns(), UNO_QUERY_THROW );
|
|
sal_Int32 nColumnCount = xColumns->getCount();
|
|
m_aColumns.reserve( nColumnCount );
|
|
|
|
Reference< XPropertySet > xColumnProps;
|
|
for ( sal_Int32 i = 0; i < nColumnCount; ++i )
|
|
{
|
|
ColumnInfo aColInfo;
|
|
aColInfo.xColumn.set( xColumns->getByIndex(i), UNO_QUERY_THROW );
|
|
|
|
xColumnProps.set( aColInfo.xColumn, UNO_QUERY_THROW );
|
|
OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_ISNULLABLE ) >>= aColInfo.nNullable );
|
|
OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_AUTOINCREMENT ) >>= aColInfo.bAutoIncrement );
|
|
OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_NAME ) >>= aColInfo.sName );
|
|
OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_ISREADONLY ) >>= aColInfo.bReadOnly );
|
|
|
|
m_aColumns.push_back( aColInfo );
|
|
}
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
}
|
|
|
|
|
|
namespace
|
|
{
|
|
bool lcl_isBoundTo( const Reference< XPropertySet >& _rxControlModel, const Reference< XInterface >& _rxNormDBField )
|
|
{
|
|
Reference< XInterface > xNormBoundField( _rxControlModel->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY );
|
|
return ( xNormBoundField == _rxNormDBField );
|
|
}
|
|
|
|
bool lcl_isInputRequired( const Reference< XPropertySet >& _rxControlModel )
|
|
{
|
|
bool bInputRequired = true;
|
|
OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_INPUT_REQUIRED ) >>= bInputRequired );
|
|
return bInputRequired;
|
|
}
|
|
|
|
void lcl_resetColumnControlInfo( ColumnInfo& _rColInfo )
|
|
{
|
|
_rColInfo.xFirstControlWithInputRequired.clear();
|
|
_rColInfo.xFirstGridWithInputRequiredColumn.clear();
|
|
_rColInfo.nRequiredGridColumn = -1;
|
|
}
|
|
}
|
|
|
|
|
|
void ColumnInfoCache::deinitializeControls()
|
|
{
|
|
for ( ColumnInfos::iterator col = m_aColumns.begin();
|
|
col != m_aColumns.end();
|
|
++col
|
|
)
|
|
{
|
|
lcl_resetColumnControlInfo( *col );
|
|
}
|
|
}
|
|
|
|
|
|
void ColumnInfoCache::initializeControls( const Sequence< Reference< XControl > >& _rControls )
|
|
{
|
|
try
|
|
{
|
|
// for every of our known columns, find the controls which are bound to this column
|
|
for ( ColumnInfos::iterator col = m_aColumns.begin();
|
|
col != m_aColumns.end();
|
|
++col
|
|
)
|
|
{
|
|
OSL_ENSURE( !col->xFirstControlWithInputRequired.is() && !col->xFirstGridWithInputRequiredColumn.is()
|
|
&& ( col->nRequiredGridColumn == -1 ), "ColumnInfoCache::initializeControls: called me twice?" );
|
|
|
|
lcl_resetColumnControlInfo( *col );
|
|
|
|
Reference< XInterface > xNormColumn( col->xColumn, UNO_QUERY_THROW );
|
|
|
|
const Reference< XControl >* pControl( _rControls.getConstArray() );
|
|
const Reference< XControl >* pControlEnd( pControl + _rControls.getLength() );
|
|
for ( ; pControl != pControlEnd; ++pControl )
|
|
{
|
|
if ( !pControl->is() )
|
|
continue;
|
|
|
|
Reference< XPropertySet > xModel( (*pControl)->getModel(), UNO_QUERY_THROW );
|
|
Reference< XPropertySetInfo > xModelPSI( xModel->getPropertySetInfo(), UNO_SET_THROW );
|
|
|
|
// special handling for grid controls
|
|
Reference< XGrid > xGrid( *pControl, UNO_QUERY );
|
|
if ( xGrid.is() )
|
|
{
|
|
Reference< XIndexAccess > xGridColAccess( xModel, UNO_QUERY_THROW );
|
|
sal_Int32 gridColCount = xGridColAccess->getCount();
|
|
sal_Int32 gridCol = 0;
|
|
for ( gridCol = 0; gridCol < gridColCount; ++gridCol )
|
|
{
|
|
Reference< XPropertySet > xGridColumnModel( xGridColAccess->getByIndex( gridCol ), UNO_QUERY_THROW );
|
|
|
|
if ( !lcl_isBoundTo( xGridColumnModel, xNormColumn )
|
|
|| !lcl_isInputRequired( xGridColumnModel )
|
|
)
|
|
continue; // with next grid column
|
|
|
|
break;
|
|
}
|
|
|
|
if ( gridCol < gridColCount )
|
|
{
|
|
// found a grid column which is bound to the given
|
|
col->xFirstGridWithInputRequiredColumn = xGrid;
|
|
col->nRequiredGridColumn = gridCol;
|
|
break;
|
|
}
|
|
|
|
continue; // with next control
|
|
}
|
|
|
|
if ( !xModelPSI->hasPropertyByName( FM_PROP_BOUNDFIELD )
|
|
|| !lcl_isBoundTo( xModel, xNormColumn )
|
|
|| !lcl_isInputRequired( xModel )
|
|
)
|
|
continue; // with next control
|
|
|
|
break;
|
|
}
|
|
|
|
if ( pControl == pControlEnd )
|
|
// did not find a control which is bound to this particular column, and for which the input is required
|
|
continue; // with next DB column
|
|
|
|
col->xFirstControlWithInputRequired = *pControl;
|
|
}
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
|
|
m_bControlsInitialized = true;
|
|
}
|
|
|
|
|
|
const ColumnInfo& ColumnInfoCache::getColumnInfo( size_t _pos )
|
|
{
|
|
if ( _pos >= m_aColumns.size() )
|
|
throw IndexOutOfBoundsException();
|
|
|
|
return m_aColumns[ _pos ];
|
|
}
|
|
|
|
class OParameterContinuation : public OInteraction< XInteractionSupplyParameters >
|
|
{
|
|
Sequence< PropertyValue > m_aValues;
|
|
|
|
public:
|
|
OParameterContinuation() { }
|
|
|
|
Sequence< PropertyValue > getValues() const { return m_aValues; }
|
|
|
|
// XInteractionSupplyParameters
|
|
virtual void SAL_CALL setParameters( const Sequence< PropertyValue >& _rValues ) throw(RuntimeException, std::exception) SAL_OVERRIDE;
|
|
};
|
|
|
|
|
|
void SAL_CALL OParameterContinuation::setParameters( const Sequence< PropertyValue >& _rValues ) throw(RuntimeException, std::exception)
|
|
{
|
|
m_aValues = _rValues;
|
|
}
|
|
|
|
|
|
// FmXAutoControl
|
|
|
|
struct FmFieldInfo
|
|
{
|
|
OUString aFieldName;
|
|
Reference< XPropertySet > xField;
|
|
Reference< XTextComponent > xText;
|
|
|
|
FmFieldInfo(const Reference< XPropertySet >& _xField, const Reference< XTextComponent >& _xText)
|
|
:xField(_xField)
|
|
,xText(_xText)
|
|
{xField->getPropertyValue(FM_PROP_NAME) >>= aFieldName;}
|
|
};
|
|
|
|
class FmXAutoControl: public UnoControl
|
|
|
|
{
|
|
public:
|
|
FmXAutoControl() :UnoControl()
|
|
{
|
|
}
|
|
|
|
virtual OUString GetComponentServiceName() SAL_OVERRIDE {return OUString("Edit");}
|
|
virtual void SAL_CALL createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) throw( RuntimeException, std::exception ) SAL_OVERRIDE;
|
|
|
|
protected:
|
|
virtual void ImplSetPeerProperty( const OUString& rPropName, const Any& rVal ) SAL_OVERRIDE;
|
|
};
|
|
|
|
|
|
void FmXAutoControl::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) throw( RuntimeException, std::exception )
|
|
{
|
|
UnoControl::createPeer( rxToolkit, rParentPeer );
|
|
|
|
Reference< XTextComponent > xText(getPeer() , UNO_QUERY);
|
|
if (xText.is())
|
|
{
|
|
xText->setText(SVX_RESSTR(RID_STR_AUTOFIELD));
|
|
xText->setEditable(sal_False);
|
|
}
|
|
}
|
|
|
|
|
|
void FmXAutoControl::ImplSetPeerProperty( const OUString& rPropName, const Any& rVal )
|
|
{
|
|
// these properties are ignored
|
|
if (rPropName == FM_PROP_TEXT)
|
|
return;
|
|
|
|
UnoControl::ImplSetPeerProperty( rPropName, rVal );
|
|
}
|
|
|
|
|
|
IMPL_LINK( FormController, OnActivateTabOrder, void*, /*EMPTYTAG*/ )
|
|
{
|
|
activateTabOrder();
|
|
return 1;
|
|
}
|
|
|
|
|
|
struct UpdateAllListeners : public ::std::unary_function< Reference< XDispatch >, bool >
|
|
{
|
|
bool operator()( const Reference< XDispatch >& _rxDispatcher ) const
|
|
{
|
|
static_cast< ::svx::OSingleFeatureDispatcher* >( _rxDispatcher.get() )->updateAllListeners();
|
|
// the return is a dummy only so we can use this struct in a o3tl::compose1 call
|
|
return true;
|
|
}
|
|
};
|
|
|
|
IMPL_LINK( FormController, OnInvalidateFeatures, void*, /*_pNotInterestedInThisParam*/ )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
for ( ::std::set< sal_Int16 >::const_iterator aLoop = m_aInvalidFeatures.begin();
|
|
aLoop != m_aInvalidFeatures.end();
|
|
++aLoop
|
|
)
|
|
{
|
|
DispatcherContainer::const_iterator aDispatcherPos = m_aFeatureDispatchers.find( *aLoop );
|
|
if ( aDispatcherPos != m_aFeatureDispatchers.end() )
|
|
{
|
|
// TODO: for the real and actual listener notifications, we should release
|
|
// our mutex
|
|
UpdateAllListeners( )( aDispatcherPos->second );
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
FormController::FormController(const Reference< css::uno::XComponentContext > & _rxORB )
|
|
:FormController_BASE( m_aMutex )
|
|
,OPropertySetHelper( FormController_BASE::rBHelper )
|
|
,OSQLParserClient( _rxORB )
|
|
,m_xComponentContext( _rxORB )
|
|
,m_aActivateListeners(m_aMutex)
|
|
,m_aModifyListeners(m_aMutex)
|
|
,m_aErrorListeners(m_aMutex)
|
|
,m_aDeleteListeners(m_aMutex)
|
|
,m_aRowSetApproveListeners(m_aMutex)
|
|
,m_aParameterListeners(m_aMutex)
|
|
,m_aFilterListeners(m_aMutex)
|
|
,m_pControlBorderManager( new ::svxform::ControlBorderManager )
|
|
,m_xFormOperations()
|
|
,m_aMode( OUString( "DataMode" ) )
|
|
,m_aLoadEvent( LINK( this, FormController, OnLoad ) )
|
|
,m_aToggleEvent( LINK( this, FormController, OnToggleAutoFields ) )
|
|
,m_aActivationEvent( LINK( this, FormController, OnActivated ) )
|
|
,m_aDeactivationEvent( LINK( this, FormController, OnDeactivated ) )
|
|
,m_nCurrentFilterPosition(-1)
|
|
,m_bCurrentRecordModified(false)
|
|
,m_bCurrentRecordNew(false)
|
|
,m_bLocked(false)
|
|
,m_bDBConnection(false)
|
|
,m_bCycle(false)
|
|
,m_bCanInsert(false)
|
|
,m_bCanUpdate(false)
|
|
,m_bCommitLock(false)
|
|
,m_bModified(false)
|
|
,m_bControlsSorted(false)
|
|
,m_bFiltering(false)
|
|
,m_bAttachEvents(true)
|
|
,m_bDetachEvents(true)
|
|
,m_bAttemptedHandlerCreation( false )
|
|
,m_bSuspendFilterTextListening( false )
|
|
{
|
|
|
|
::comphelper::increment(m_refCount);
|
|
{
|
|
m_xTabController = TabController::create( m_xComponentContext );
|
|
m_xAggregate = Reference< XAggregation >( m_xTabController, UNO_QUERY_THROW );
|
|
m_xAggregate->setDelegator( *this );
|
|
}
|
|
::comphelper::decrement(m_refCount);
|
|
|
|
m_aTabActivationIdle.SetPriority( SchedulerPriority::LOWEST );
|
|
m_aTabActivationIdle.SetIdleHdl( LINK( this, FormController, OnActivateTabOrder ) );
|
|
|
|
m_aFeatureInvalidationTimer.SetTimeout( 200 );
|
|
m_aFeatureInvalidationTimer.SetTimeoutHdl( LINK( this, FormController, OnInvalidateFeatures ) );
|
|
}
|
|
|
|
|
|
FormController::~FormController()
|
|
{
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
|
|
m_aLoadEvent.CancelPendingCall();
|
|
m_aToggleEvent.CancelPendingCall();
|
|
m_aActivationEvent.CancelPendingCall();
|
|
m_aDeactivationEvent.CancelPendingCall();
|
|
|
|
if ( m_aTabActivationIdle.IsActive() )
|
|
m_aTabActivationIdle.Stop();
|
|
}
|
|
|
|
if ( m_aFeatureInvalidationTimer.IsActive() )
|
|
m_aFeatureInvalidationTimer.Stop();
|
|
|
|
disposeAllFeaturesAndDispatchers();
|
|
|
|
if ( m_xFormOperations.is() )
|
|
m_xFormOperations->dispose();
|
|
m_xFormOperations.clear();
|
|
|
|
// Freigeben der Aggregation
|
|
if ( m_xAggregate.is() )
|
|
{
|
|
m_xAggregate->setDelegator( NULL );
|
|
m_xAggregate.clear();
|
|
}
|
|
|
|
DELETEZ( m_pControlBorderManager );
|
|
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::acquire() throw ()
|
|
{
|
|
FormController_BASE::acquire();
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::release() throw ()
|
|
{
|
|
FormController_BASE::release();
|
|
}
|
|
|
|
|
|
Any SAL_CALL FormController::queryInterface( const Type& _rType ) throw(RuntimeException, std::exception)
|
|
{
|
|
Any aRet = FormController_BASE::queryInterface( _rType );
|
|
if ( !aRet.hasValue() )
|
|
aRet = OPropertySetHelper::queryInterface( _rType );
|
|
if ( !aRet.hasValue() )
|
|
aRet = m_xAggregate->queryAggregation( _rType );
|
|
return aRet;
|
|
}
|
|
|
|
|
|
Sequence< sal_Int8 > SAL_CALL FormController::getImplementationId() throw( RuntimeException, std::exception )
|
|
{
|
|
return css::uno::Sequence<sal_Int8>();
|
|
}
|
|
|
|
Sequence< Type > SAL_CALL FormController::getTypes( ) throw(RuntimeException, std::exception)
|
|
{
|
|
return comphelper::concatSequences(
|
|
FormController_BASE::getTypes(),
|
|
::cppu::OPropertySetHelper::getTypes()
|
|
);
|
|
}
|
|
|
|
// XServiceInfo
|
|
sal_Bool SAL_CALL FormController::supportsService(const OUString& ServiceName) throw( RuntimeException, std::exception )
|
|
{
|
|
return cppu::supportsService(this, ServiceName);
|
|
}
|
|
|
|
OUString SAL_CALL FormController::getImplementationName() throw( RuntimeException, std::exception )
|
|
{
|
|
return OUString("org.openoffice.comp.svx.FormController");
|
|
}
|
|
|
|
Sequence< OUString> SAL_CALL FormController::getSupportedServiceNames(void) throw( RuntimeException, std::exception )
|
|
{
|
|
// service names which are supported only, but cannot be used to created an
|
|
// instance at a service factory
|
|
Sequence< OUString > aNonCreatableServiceNames( 1 );
|
|
aNonCreatableServiceNames[ 0 ] = "com.sun.star.form.FormControllerDispatcher";
|
|
|
|
// services which can be used to created an instance at a service factory
|
|
Sequence< OUString > aCreatableServiceNames( getSupportedServiceNames_Static() );
|
|
return ::comphelper::concatSequences( aCreatableServiceNames, aNonCreatableServiceNames );
|
|
}
|
|
|
|
|
|
sal_Bool SAL_CALL FormController::approveReset(const EventObject& /*rEvent*/) throw( RuntimeException, std::exception )
|
|
{
|
|
return sal_True;
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::resetted(const EventObject& rEvent) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard(m_aMutex);
|
|
if (getCurrentControl().is() && (getCurrentControl()->getModel() == rEvent.Source))
|
|
m_bModified = false;
|
|
}
|
|
|
|
|
|
Sequence< OUString> FormController::getSupportedServiceNames_Static(void)
|
|
{
|
|
static Sequence< OUString> aServices;
|
|
if (!aServices.getLength())
|
|
{
|
|
aServices.realloc(2);
|
|
aServices.getArray()[0] = "com.sun.star.form.runtime.FormController";
|
|
aServices.getArray()[1] = "com.sun.star.awt.control.TabController";
|
|
}
|
|
return aServices;
|
|
}
|
|
|
|
|
|
namespace
|
|
{
|
|
struct ResetComponentText : public ::std::unary_function< Reference< XTextComponent >, void >
|
|
{
|
|
void operator()( const Reference< XTextComponent >& _rxText )
|
|
{
|
|
_rxText->setText( OUString() );
|
|
}
|
|
};
|
|
|
|
struct RemoveComponentTextListener : public ::std::unary_function< Reference< XTextComponent >, void >
|
|
{
|
|
RemoveComponentTextListener( const Reference< XTextListener >& _rxListener )
|
|
:m_xListener( _rxListener )
|
|
{
|
|
}
|
|
|
|
void operator()( const Reference< XTextComponent >& _rxText )
|
|
{
|
|
_rxText->removeTextListener( m_xListener );
|
|
}
|
|
|
|
private:
|
|
Reference< XTextListener > m_xListener;
|
|
};
|
|
}
|
|
|
|
|
|
void FormController::impl_setTextOnAllFilter_throw()
|
|
{
|
|
m_bSuspendFilterTextListening = true;
|
|
::comphelper::FlagGuard aResetFlag( m_bSuspendFilterTextListening );
|
|
|
|
// reset the text for all controls
|
|
::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), ResetComponentText() );
|
|
|
|
if ( m_aFilterRows.empty() )
|
|
// nothing to do anymore
|
|
return;
|
|
|
|
if ( m_nCurrentFilterPosition < 0 )
|
|
return;
|
|
|
|
// set the text for all filters
|
|
OSL_ENSURE( m_aFilterRows.size() > (size_t)m_nCurrentFilterPosition,
|
|
"FormController::impl_setTextOnAllFilter_throw: m_nCurrentFilterPosition too big" );
|
|
|
|
if ( (size_t)m_nCurrentFilterPosition < m_aFilterRows.size() )
|
|
{
|
|
FmFilterRow& rRow = m_aFilterRows[ m_nCurrentFilterPosition ];
|
|
for ( FmFilterRow::const_iterator iter2 = rRow.begin();
|
|
iter2 != rRow.end();
|
|
++iter2
|
|
)
|
|
{
|
|
iter2->first->setText( iter2->second );
|
|
}
|
|
}
|
|
}
|
|
// OPropertySetHelper
|
|
|
|
sal_Bool FormController::convertFastPropertyValue( Any & /*rConvertedValue*/, Any & /*rOldValue*/,
|
|
sal_Int32 /*nHandle*/, const Any& /*rValue*/ )
|
|
throw( IllegalArgumentException )
|
|
{
|
|
return sal_False;
|
|
}
|
|
|
|
|
|
void FormController::setFastPropertyValue_NoBroadcast( sal_Int32 /*nHandle*/, const Any& /*rValue*/ )
|
|
throw( Exception, std::exception )
|
|
{
|
|
}
|
|
|
|
|
|
void FormController::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
|
|
{
|
|
switch (nHandle)
|
|
{
|
|
case FM_ATTR_FILTER:
|
|
{
|
|
OUStringBuffer aFilter;
|
|
OStaticDataAccessTools aStaticTools;
|
|
Reference<XConnection> xConnection(aStaticTools.getRowSetConnection(Reference< XRowSet>(m_xModelAsIndex, UNO_QUERY)));
|
|
if (xConnection.is())
|
|
{
|
|
Reference< XDatabaseMetaData> xMetaData(xConnection->getMetaData());
|
|
Reference< XNumberFormatsSupplier> xFormatSupplier( aStaticTools.getNumberFormats( xConnection, true ) );
|
|
Reference< XNumberFormatter> xFormatter = NumberFormatter::create(m_xComponentContext);
|
|
xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
|
|
|
|
Reference< XColumnsSupplier> xSupplyCols(m_xModelAsIndex, UNO_QUERY);
|
|
Reference< XNameAccess> xFields(xSupplyCols->getColumns(), UNO_QUERY);
|
|
|
|
// now add the filter rows
|
|
try
|
|
{
|
|
for ( FmFilterRows::const_iterator row = m_aFilterRows.begin(); row != m_aFilterRows.end(); ++row )
|
|
{
|
|
const FmFilterRow& rRow = *row;
|
|
|
|
if ( rRow.empty() )
|
|
continue;
|
|
|
|
OUStringBuffer aRowFilter;
|
|
for ( FmFilterRow::const_iterator condition = rRow.begin(); condition != rRow.end(); ++condition )
|
|
{
|
|
// get the field of the controls map
|
|
Reference< XControl > xControl( condition->first, UNO_QUERY_THROW );
|
|
Reference< XPropertySet > xModelProps( xControl->getModel(), UNO_QUERY_THROW );
|
|
Reference< XPropertySet > xField( xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY_THROW );
|
|
|
|
OUString sFilterValue( condition->second );
|
|
|
|
OUString sErrorMsg, sCriteria;
|
|
const ::rtl::Reference< ISQLParseNode > xParseNode =
|
|
predicateTree( sErrorMsg, sFilterValue, xFormatter, xField );
|
|
OSL_ENSURE( xParseNode.is(), "FormController::getFastPropertyValue: could not parse the field value predicate!" );
|
|
if ( xParseNode.is() )
|
|
{
|
|
// don't use a parse context here, we need it unlocalized
|
|
xParseNode->parseNodeToStr( sCriteria, xConnection, NULL );
|
|
if ( condition != rRow.begin() )
|
|
aRowFilter.appendAscii( " AND " );
|
|
aRowFilter.append( sCriteria );
|
|
}
|
|
}
|
|
if ( !aRowFilter.isEmpty() )
|
|
{
|
|
if ( !aFilter.isEmpty() )
|
|
aFilter.appendAscii( " OR " );
|
|
|
|
aFilter.appendAscii( "( " );
|
|
aFilter.append( aRowFilter.makeStringAndClear() );
|
|
aFilter.appendAscii( " )" );
|
|
}
|
|
}
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
aFilter.setLength(0);
|
|
}
|
|
}
|
|
rValue <<= aFilter.makeStringAndClear();
|
|
}
|
|
break;
|
|
|
|
case FM_ATTR_FORM_OPERATIONS:
|
|
rValue <<= m_xFormOperations;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
Reference< XPropertySetInfo > FormController::getPropertySetInfo() throw( RuntimeException, std::exception )
|
|
{
|
|
static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
|
|
return xInfo;
|
|
}
|
|
|
|
|
|
void FormController::fillProperties(
|
|
Sequence< Property >& /* [out] */ _rProps,
|
|
Sequence< Property >& /* [out] */ /*_rAggregateProps*/
|
|
) const
|
|
{
|
|
_rProps.realloc(2);
|
|
sal_Int32 nPos = 0;
|
|
Property* pDesc = _rProps.getArray();
|
|
|
|
pDesc[nPos++] = Property(FM_PROP_FILTER, FM_ATTR_FILTER,
|
|
cppu::UnoType<OUString>::get(),
|
|
PropertyAttribute::READONLY);
|
|
pDesc[nPos++] = Property(FM_PROP_FORM_OPERATIONS, FM_ATTR_FORM_OPERATIONS,
|
|
cppu::UnoType<XFormOperations>::get(),
|
|
PropertyAttribute::READONLY);
|
|
}
|
|
|
|
|
|
::cppu::IPropertyArrayHelper& FormController::getInfoHelper()
|
|
{
|
|
return *getArrayHelper();
|
|
}
|
|
|
|
// XFilterController
|
|
|
|
void SAL_CALL FormController::addFilterControllerListener( const Reference< XFilterControllerListener >& _Listener ) throw( RuntimeException, std::exception )
|
|
{
|
|
m_aFilterListeners.addInterface( _Listener );
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::removeFilterControllerListener( const Reference< XFilterControllerListener >& _Listener ) throw( RuntimeException, std::exception )
|
|
{
|
|
m_aFilterListeners.removeInterface( _Listener );
|
|
}
|
|
|
|
|
|
::sal_Int32 SAL_CALL FormController::getFilterComponents() throw( ::com::sun::star::uno::RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
return m_aFilterComponents.size();
|
|
}
|
|
|
|
|
|
::sal_Int32 SAL_CALL FormController::getDisjunctiveTerms() throw( ::com::sun::star::uno::RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
return m_aFilterRows.size();
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::setPredicateExpression( ::sal_Int32 _Component, ::sal_Int32 _Term, const OUString& _PredicateExpression ) throw( RuntimeException, IndexOutOfBoundsException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
if ( ( _Component < 0 ) || ( _Component >= getFilterComponents() ) || ( _Term < 0 ) || ( _Term >= getDisjunctiveTerms() ) )
|
|
throw IndexOutOfBoundsException( OUString(), *this );
|
|
|
|
Reference< XTextComponent > xText( m_aFilterComponents[ _Component ] );
|
|
xText->setText( _PredicateExpression );
|
|
|
|
FmFilterRow& rFilterRow = m_aFilterRows[ _Term ];
|
|
if ( !_PredicateExpression.isEmpty() )
|
|
rFilterRow[ xText ] = _PredicateExpression;
|
|
else
|
|
rFilterRow.erase( xText );
|
|
}
|
|
|
|
|
|
Reference< XControl > FormController::getFilterComponent( ::sal_Int32 _Component ) throw( RuntimeException, IndexOutOfBoundsException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
if ( ( _Component < 0 ) || ( _Component >= getFilterComponents() ) )
|
|
throw IndexOutOfBoundsException( OUString(), *this );
|
|
|
|
return Reference< XControl >( m_aFilterComponents[ _Component ], UNO_QUERY );
|
|
}
|
|
|
|
|
|
Sequence< Sequence< OUString > > FormController::getPredicateExpressions() throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
Sequence< Sequence< OUString > > aExpressions( m_aFilterRows.size() );
|
|
sal_Int32 termIndex = 0;
|
|
for ( FmFilterRows::const_iterator row = m_aFilterRows.begin();
|
|
row != m_aFilterRows.end();
|
|
++row, ++termIndex
|
|
)
|
|
{
|
|
const FmFilterRow& rRow( *row );
|
|
|
|
Sequence< OUString > aConjunction( m_aFilterComponents.size() );
|
|
sal_Int32 componentIndex = 0;
|
|
for ( FilterComponents::const_iterator comp = m_aFilterComponents.begin();
|
|
comp != m_aFilterComponents.end();
|
|
++comp, ++componentIndex
|
|
)
|
|
{
|
|
FmFilterRow::const_iterator predicate = rRow.find( *comp );
|
|
if ( predicate != rRow.end() )
|
|
aConjunction[ componentIndex ] = predicate->second;
|
|
}
|
|
|
|
aExpressions[ termIndex ] = aConjunction;
|
|
}
|
|
|
|
return aExpressions;
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::removeDisjunctiveTerm( ::sal_Int32 _Term ) throw (IndexOutOfBoundsException, RuntimeException, std::exception)
|
|
{
|
|
// SYNCHRONIZED -->
|
|
::osl::ClearableMutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
if ( ( _Term < 0 ) || ( _Term >= getDisjunctiveTerms() ) )
|
|
throw IndexOutOfBoundsException( OUString(), *this );
|
|
|
|
// if the to-be-deleted row is our current row, we need to shift
|
|
if ( _Term == m_nCurrentFilterPosition )
|
|
{
|
|
if ( m_nCurrentFilterPosition < sal_Int32( m_aFilterRows.size() - 1 ) )
|
|
++m_nCurrentFilterPosition;
|
|
else
|
|
--m_nCurrentFilterPosition;
|
|
}
|
|
|
|
FmFilterRows::iterator pos = m_aFilterRows.begin() + _Term;
|
|
m_aFilterRows.erase( pos );
|
|
|
|
// adjust m_nCurrentFilterPosition if the removed row preceded it
|
|
if ( _Term < m_nCurrentFilterPosition )
|
|
--m_nCurrentFilterPosition;
|
|
|
|
SAL_WARN_IF( !( ( m_nCurrentFilterPosition < 0 ) != ( m_aFilterRows.empty() ) ),
|
|
"svx.form", "FormController::removeDisjunctiveTerm: inconsistency!" );
|
|
|
|
// update the texts in the filter controls
|
|
impl_setTextOnAllFilter_throw();
|
|
|
|
FilterEvent aEvent;
|
|
aEvent.Source = *this;
|
|
aEvent.DisjunctiveTerm = _Term;
|
|
aGuard.clear();
|
|
// <-- SYNCHRONIZED
|
|
|
|
m_aFilterListeners.notifyEach( &XFilterControllerListener::disjunctiveTermRemoved, aEvent );
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::appendEmptyDisjunctiveTerm() throw (RuntimeException, std::exception)
|
|
{
|
|
// SYNCHRONIZED -->
|
|
::osl::ClearableMutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
impl_appendEmptyFilterRow( aGuard );
|
|
// <-- SYNCHRONIZED
|
|
}
|
|
|
|
|
|
::sal_Int32 SAL_CALL FormController::getActiveTerm() throw (RuntimeException, std::exception)
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
return m_nCurrentFilterPosition;
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::setActiveTerm( ::sal_Int32 _ActiveTerm ) throw (IndexOutOfBoundsException, RuntimeException, std::exception)
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
if ( ( _ActiveTerm < 0 ) || ( _ActiveTerm >= getDisjunctiveTerms() ) )
|
|
throw IndexOutOfBoundsException( OUString(), *this );
|
|
|
|
if ( _ActiveTerm == getActiveTerm() )
|
|
return;
|
|
|
|
m_nCurrentFilterPosition = _ActiveTerm;
|
|
impl_setTextOnAllFilter_throw();
|
|
}
|
|
|
|
// XElementAccess
|
|
|
|
sal_Bool SAL_CALL FormController::hasElements(void) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
return !m_aChildren.empty();
|
|
}
|
|
|
|
|
|
Type SAL_CALL FormController::getElementType(void) throw( RuntimeException, std::exception )
|
|
{
|
|
return cppu::UnoType<XFormController>::get();
|
|
|
|
}
|
|
|
|
// XEnumerationAccess
|
|
|
|
Reference< XEnumeration > SAL_CALL FormController::createEnumeration(void) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
return new ::comphelper::OEnumerationByIndex(this);
|
|
}
|
|
|
|
// XIndexAccess
|
|
|
|
sal_Int32 SAL_CALL FormController::getCount(void) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
return m_aChildren.size();
|
|
}
|
|
|
|
|
|
Any SAL_CALL FormController::getByIndex(sal_Int32 Index) throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
if (Index < 0 ||
|
|
Index >= (sal_Int32)m_aChildren.size())
|
|
throw IndexOutOfBoundsException();
|
|
|
|
return makeAny( m_aChildren[ Index ] );
|
|
}
|
|
|
|
// EventListener
|
|
|
|
void SAL_CALL FormController::disposing(const EventObject& e) throw( RuntimeException, std::exception )
|
|
{
|
|
// Ist der Container disposed worden
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
Reference< XControlContainer > xContainer(e.Source, UNO_QUERY);
|
|
if (xContainer.is())
|
|
{
|
|
setContainer(Reference< XControlContainer > ());
|
|
}
|
|
else
|
|
{
|
|
// ist ein Control disposed worden
|
|
Reference< XControl > xControl(e.Source, UNO_QUERY);
|
|
if (xControl.is())
|
|
{
|
|
if (getContainer().is())
|
|
removeControl(xControl);
|
|
}
|
|
}
|
|
}
|
|
|
|
// OComponentHelper
|
|
|
|
void FormController::disposeAllFeaturesAndDispatchers()
|
|
{
|
|
for ( DispatcherContainer::iterator aDispatcher = m_aFeatureDispatchers.begin();
|
|
aDispatcher != m_aFeatureDispatchers.end();
|
|
++aDispatcher
|
|
)
|
|
{
|
|
try
|
|
{
|
|
::comphelper::disposeComponent( aDispatcher->second );
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
}
|
|
m_aFeatureDispatchers.clear();
|
|
}
|
|
|
|
|
|
void FormController::disposing(void)
|
|
{
|
|
EventObject aEvt( *this );
|
|
|
|
// if we're still active, simulate a "deactivated" event
|
|
if ( m_xActiveControl.is() )
|
|
m_aActivateListeners.notifyEach( &XFormControllerListener::formDeactivated, aEvt );
|
|
|
|
// notify all our listeners
|
|
m_aActivateListeners.disposeAndClear(aEvt);
|
|
m_aModifyListeners.disposeAndClear(aEvt);
|
|
m_aErrorListeners.disposeAndClear(aEvt);
|
|
m_aDeleteListeners.disposeAndClear(aEvt);
|
|
m_aRowSetApproveListeners.disposeAndClear(aEvt);
|
|
m_aParameterListeners.disposeAndClear(aEvt);
|
|
m_aFilterListeners.disposeAndClear(aEvt);
|
|
|
|
removeBoundFieldListener();
|
|
stopFiltering();
|
|
|
|
m_pControlBorderManager->restoreAll();
|
|
|
|
m_aFilterRows.clear();
|
|
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
m_xActiveControl = NULL;
|
|
implSetCurrentControl( NULL );
|
|
|
|
// clean up our children
|
|
for (FmFormControllers::const_iterator i = m_aChildren.begin();
|
|
i != m_aChildren.end(); ++i)
|
|
{
|
|
// search the position of the model within the form
|
|
Reference< XFormComponent > xForm((*i)->getModel(), UNO_QUERY);
|
|
sal_uInt32 nPos = m_xModelAsIndex->getCount();
|
|
Reference< XFormComponent > xTemp;
|
|
for( ; nPos; )
|
|
{
|
|
|
|
m_xModelAsIndex->getByIndex( --nPos ) >>= xTemp;
|
|
if ( xForm.get() == xTemp.get() )
|
|
{
|
|
Reference< XInterface > xIfc( *i, UNO_QUERY );
|
|
m_xModelAsManager->detach( nPos, xIfc );
|
|
break;
|
|
}
|
|
}
|
|
|
|
Reference< XComponent > (*i, UNO_QUERY)->dispose();
|
|
}
|
|
m_aChildren.clear();
|
|
|
|
disposeAllFeaturesAndDispatchers();
|
|
|
|
if ( m_xFormOperations.is() )
|
|
m_xFormOperations->dispose();
|
|
m_xFormOperations.clear();
|
|
|
|
if (m_bDBConnection)
|
|
unload();
|
|
|
|
setContainer( NULL );
|
|
setModel( NULL );
|
|
setParent( NULL );
|
|
|
|
::comphelper::disposeComponent( m_xComposer );
|
|
|
|
m_bDBConnection = false;
|
|
}
|
|
|
|
|
|
namespace
|
|
{
|
|
static bool lcl_shouldUseDynamicControlBorder( const Reference< XInterface >& _rxForm, const Any& _rDynamicColorProp )
|
|
{
|
|
bool bDoUse = false;
|
|
if ( !( _rDynamicColorProp >>= bDoUse ) )
|
|
{
|
|
DocumentType eDocType = DocumentClassification::classifyHostDocument( _rxForm );
|
|
return ControlLayouter::useDynamicBorderColor( eDocType );
|
|
}
|
|
return bDoUse;
|
|
}
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::propertyChange(const PropertyChangeEvent& evt) throw( RuntimeException, std::exception )
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
if ( evt.PropertyName == FM_PROP_BOUNDFIELD )
|
|
{
|
|
Reference<XPropertySet> xOldBound;
|
|
evt.OldValue >>= xOldBound;
|
|
if ( !xOldBound.is() && evt.NewValue.hasValue() )
|
|
{
|
|
Reference< XControlModel > xControlModel(evt.Source,UNO_QUERY);
|
|
Reference< XControl > xControl = findControl(m_aControls,xControlModel,false,false);
|
|
if ( xControl.is() )
|
|
{
|
|
startControlModifyListening( xControl );
|
|
Reference<XPropertySet> xProp(xControlModel,UNO_QUERY);
|
|
if ( xProp.is() )
|
|
xProp->removePropertyChangeListener(FM_PROP_BOUNDFIELD, this);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool bModifiedChanged = (evt.PropertyName == FM_PROP_ISMODIFIED);
|
|
bool bNewChanged = (evt.PropertyName == FM_PROP_ISNEW);
|
|
if (bModifiedChanged || bNewChanged)
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
if (bModifiedChanged)
|
|
m_bCurrentRecordModified = ::comphelper::getBOOL(evt.NewValue);
|
|
else
|
|
m_bCurrentRecordNew = ::comphelper::getBOOL(evt.NewValue);
|
|
|
|
// toggle the locking
|
|
if (m_bLocked != determineLockState())
|
|
{
|
|
m_bLocked = !m_bLocked;
|
|
setLocks();
|
|
if (isListeningForChanges())
|
|
startListening();
|
|
else
|
|
stopListening();
|
|
}
|
|
|
|
if ( bNewChanged )
|
|
m_aToggleEvent.Call();
|
|
|
|
if (!m_bCurrentRecordModified)
|
|
m_bModified = false;
|
|
}
|
|
else if ( evt.PropertyName == FM_PROP_DYNAMIC_CONTROL_BORDER )
|
|
{
|
|
bool bEnable = lcl_shouldUseDynamicControlBorder( evt.Source, evt.NewValue );
|
|
if ( bEnable )
|
|
{
|
|
m_pControlBorderManager->enableDynamicBorderColor();
|
|
if ( m_xActiveControl.is() )
|
|
m_pControlBorderManager->focusGained( m_xActiveControl.get() );
|
|
}
|
|
else
|
|
{
|
|
m_pControlBorderManager->disableDynamicBorderColor();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool FormController::replaceControl( const Reference< XControl >& _rxExistentControl, const Reference< XControl >& _rxNewControl )
|
|
{
|
|
bool bSuccess = false;
|
|
try
|
|
{
|
|
Reference< XIdentifierReplace > xContainer( getContainer(), UNO_QUERY );
|
|
DBG_ASSERT( xContainer.is(), "FormController::replaceControl: yes, it's not required by the service description, but XItentifierReplaces would be nice!" );
|
|
if ( xContainer.is() )
|
|
{
|
|
// look up the ID of _rxExistentControl
|
|
Sequence< sal_Int32 > aIdentifiers( xContainer->getIdentifiers() );
|
|
const sal_Int32* pIdentifiers = aIdentifiers.getConstArray();
|
|
const sal_Int32* pIdentifiersEnd = aIdentifiers.getConstArray() + aIdentifiers.getLength();
|
|
for ( ; pIdentifiers != pIdentifiersEnd; ++pIdentifiers )
|
|
{
|
|
Reference< XControl > xCheck( xContainer->getByIdentifier( *pIdentifiers ), UNO_QUERY );
|
|
if ( xCheck == _rxExistentControl )
|
|
break;
|
|
}
|
|
DBG_ASSERT( pIdentifiers != pIdentifiersEnd, "FormController::replaceControl: did not find the control in the container!" );
|
|
if ( pIdentifiers != pIdentifiersEnd )
|
|
{
|
|
bool bReplacedWasActive = ( m_xActiveControl.get() == _rxExistentControl.get() );
|
|
bool bReplacedWasCurrent = ( m_xCurrentControl.get() == _rxExistentControl.get() );
|
|
|
|
if ( bReplacedWasActive )
|
|
{
|
|
m_xActiveControl = NULL;
|
|
implSetCurrentControl( NULL );
|
|
}
|
|
else if ( bReplacedWasCurrent )
|
|
{
|
|
implSetCurrentControl( _rxNewControl );
|
|
}
|
|
|
|
// carry over the model
|
|
_rxNewControl->setModel( _rxExistentControl->getModel() );
|
|
|
|
xContainer->replaceByIdentifer( *pIdentifiers, makeAny( _rxNewControl ) );
|
|
bSuccess = true;
|
|
|
|
if ( bReplacedWasActive )
|
|
{
|
|
Reference< XWindow > xControlWindow( _rxNewControl, UNO_QUERY );
|
|
if ( xControlWindow.is() )
|
|
xControlWindow->setFocus();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
|
|
Reference< XControl > xDisposeIt( bSuccess ? _rxExistentControl : _rxNewControl );
|
|
::comphelper::disposeComponent( xDisposeIt );
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
void FormController::toggleAutoFields(bool bAutoFields)
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
|
|
|
|
Sequence< Reference< XControl > > aControlsCopy( m_aControls );
|
|
const Reference< XControl >* pControls = aControlsCopy.getConstArray();
|
|
sal_Int32 nControls = aControlsCopy.getLength();
|
|
|
|
if (bAutoFields)
|
|
{
|
|
// as we don't want new controls to be attached to the scripting environment
|
|
// we change attach flags
|
|
m_bAttachEvents = false;
|
|
for (sal_Int32 i = nControls; i > 0;)
|
|
{
|
|
Reference< XControl > xControl = pControls[--i];
|
|
if (xControl.is())
|
|
{
|
|
Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
|
|
if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
|
|
{
|
|
// does the model use a bound field ?
|
|
Reference< XPropertySet > xField;
|
|
xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
|
|
|
|
// is it a autofield?
|
|
if ( xField.is()
|
|
&& ::comphelper::hasProperty( FM_PROP_AUTOINCREMENT, xField )
|
|
&& ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_AUTOINCREMENT ) )
|
|
)
|
|
{
|
|
replaceControl( xControl, new FmXAutoControl() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
m_bAttachEvents = true;
|
|
}
|
|
else
|
|
{
|
|
m_bDetachEvents = false;
|
|
for (sal_Int32 i = nControls; i > 0;)
|
|
{
|
|
Reference< XControl > xControl = pControls[--i];
|
|
if (xControl.is())
|
|
{
|
|
Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
|
|
if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
|
|
{
|
|
// does the model use a bound field ?
|
|
Reference< XPropertySet > xField;
|
|
xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
|
|
|
|
// is it a autofield?
|
|
if ( xField.is()
|
|
&& ::comphelper::hasProperty( FM_PROP_AUTOINCREMENT, xField )
|
|
&& ::comphelper::getBOOL( xField->getPropertyValue(FM_PROP_AUTOINCREMENT ) )
|
|
)
|
|
{
|
|
OUString sServiceName;
|
|
OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DEFAULTCONTROL ) >>= sServiceName );
|
|
Reference< XControl > xNewControl( m_xComponentContext->getServiceManager()->createInstanceWithContext( sServiceName, m_xComponentContext ), UNO_QUERY );
|
|
replaceControl( xControl, xNewControl );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
m_bDetachEvents = true;
|
|
}
|
|
}
|
|
|
|
|
|
IMPL_LINK_NOARG(FormController, OnToggleAutoFields)
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
|
|
toggleAutoFields(m_bCurrentRecordNew);
|
|
return 1L;
|
|
}
|
|
|
|
// XTextListener
|
|
|
|
void SAL_CALL FormController::textChanged(const TextEvent& e) throw( RuntimeException, std::exception )
|
|
{
|
|
// SYNCHRONIZED -->
|
|
::osl::ClearableMutexGuard aGuard( m_aMutex );
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
if ( !m_bFiltering )
|
|
{
|
|
impl_onModify();
|
|
return;
|
|
}
|
|
|
|
if ( m_bSuspendFilterTextListening )
|
|
return;
|
|
|
|
Reference< XTextComponent > xText(e.Source,UNO_QUERY);
|
|
OUString aText = xText->getText();
|
|
|
|
if ( m_aFilterRows.empty() )
|
|
appendEmptyDisjunctiveTerm();
|
|
|
|
// Suchen der aktuellen Row
|
|
if ( ( (size_t)m_nCurrentFilterPosition >= m_aFilterRows.size() ) || ( m_nCurrentFilterPosition < 0 ) )
|
|
{
|
|
OSL_ENSURE( false, "FormController::textChanged: m_nCurrentFilterPosition is wrong!" );
|
|
return;
|
|
}
|
|
|
|
FmFilterRow& rRow = m_aFilterRows[ m_nCurrentFilterPosition ];
|
|
|
|
// do we have a new filter
|
|
if (!aText.isEmpty())
|
|
rRow[xText] = aText;
|
|
else
|
|
{
|
|
// do we have the control in the row
|
|
FmFilterRow::iterator iter = rRow.find(xText);
|
|
// erase the entry out of the row
|
|
if (iter != rRow.end())
|
|
rRow.erase(iter);
|
|
}
|
|
|
|
// multiplex the event to our FilterControllerListeners
|
|
FilterEvent aEvent;
|
|
aEvent.Source = *this;
|
|
aEvent.FilterComponent = ::std::find( m_aFilterComponents.begin(), m_aFilterComponents.end(), xText ) - m_aFilterComponents.begin();
|
|
aEvent.DisjunctiveTerm = getActiveTerm();
|
|
aEvent.PredicateExpression = aText;
|
|
|
|
aGuard.clear();
|
|
// <-- SYNCHRONIZED
|
|
|
|
// notify the changed filter expression
|
|
m_aFilterListeners.notifyEach( &XFilterControllerListener::predicateExpressionChanged, aEvent );
|
|
}
|
|
|
|
// XItemListener
|
|
|
|
void SAL_CALL FormController::itemStateChanged(const ItemEvent& /*rEvent*/) throw( RuntimeException, std::exception )
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
impl_onModify();
|
|
}
|
|
|
|
// XModificationBroadcaster
|
|
|
|
void SAL_CALL FormController::addModifyListener(const Reference< XModifyListener > & l) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
m_aModifyListeners.addInterface( l );
|
|
}
|
|
|
|
|
|
void FormController::removeModifyListener(const Reference< XModifyListener > & l) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
m_aModifyListeners.removeInterface( l );
|
|
}
|
|
|
|
// XModificationListener
|
|
|
|
void FormController::modified( const EventObject& _rEvent ) throw( RuntimeException, std::exception )
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
|
|
try
|
|
{
|
|
if ( _rEvent.Source != m_xActiveControl )
|
|
{ // let this control grab the focus
|
|
// (this case may happen if somebody moves the scroll wheel of the mouse over a control
|
|
// which does not have the focus)
|
|
// 85511 - 29.05.2001 - frank.schoenheit@germany.sun.com
|
|
|
|
// also, it happens when an image control gets a new image by double-clicking it
|
|
// #i88458# / 2009-01-12 / frank.schoenheit@sun.com
|
|
Reference< XWindow > xControlWindow( _rEvent.Source, UNO_QUERY_THROW );
|
|
xControlWindow->setFocus();
|
|
}
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
|
|
impl_onModify();
|
|
}
|
|
|
|
|
|
void FormController::impl_checkDisposed_throw() const
|
|
{
|
|
if ( impl_isDisposed_nofail() )
|
|
throw DisposedException( OUString(), *const_cast< FormController* >( this ) );
|
|
}
|
|
|
|
|
|
void FormController::impl_onModify()
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
if ( !m_bModified )
|
|
m_bModified = true;
|
|
}
|
|
|
|
EventObject aEvt(static_cast<cppu::OWeakObject*>(this));
|
|
m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvt );
|
|
}
|
|
|
|
|
|
void FormController::impl_addFilterRow( const FmFilterRow& _row )
|
|
{
|
|
m_aFilterRows.push_back( _row );
|
|
|
|
if ( m_aFilterRows.size() == 1 )
|
|
{ // that's the first row ever
|
|
OSL_ENSURE( m_nCurrentFilterPosition == -1, "FormController::impl_addFilterRow: inconsistency!" );
|
|
m_nCurrentFilterPosition = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void FormController::impl_appendEmptyFilterRow( ::osl::ClearableMutexGuard& _rClearBeforeNotify )
|
|
{
|
|
// SYNCHRONIZED -->
|
|
impl_addFilterRow( FmFilterRow() );
|
|
|
|
// notify the listeners
|
|
FilterEvent aEvent;
|
|
aEvent.Source = *this;
|
|
aEvent.DisjunctiveTerm = (sal_Int32)m_aFilterRows.size() - 1;
|
|
_rClearBeforeNotify.clear();
|
|
// <-- SYNCHRONIZED
|
|
m_aFilterListeners.notifyEach( &XFilterControllerListener::disjunctiveTermAdded, aEvent );
|
|
}
|
|
|
|
|
|
bool FormController::determineLockState() const
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
// a.) in filter mode we are always locked
|
|
// b.) if we have no valid model or our model (a result set) is not alive -> we're locked
|
|
// c.) if we are inserting everything is OK and we are not locked
|
|
// d.) if are not updatable or on invalid position
|
|
Reference< XResultSet > xResultSet(m_xModelAsIndex, UNO_QUERY);
|
|
if (m_bFiltering || !xResultSet.is() || !isRowSetAlive(xResultSet))
|
|
return true;
|
|
else
|
|
return (m_bCanInsert && m_bCurrentRecordNew) ? sal_False
|
|
: xResultSet->isBeforeFirst() || xResultSet->isAfterLast() || xResultSet->rowDeleted() || !m_bCanUpdate;
|
|
}
|
|
|
|
// FocusListener
|
|
|
|
void FormController::focusGained(const FocusEvent& e) throw( RuntimeException, std::exception )
|
|
{
|
|
// SYNCHRONIZED -->
|
|
::osl::ClearableMutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
m_pControlBorderManager->focusGained( e.Source );
|
|
|
|
Reference< XControl > xControl(e.Source, UNO_QUERY);
|
|
if (m_bDBConnection)
|
|
{
|
|
// do we need to keep the locking of the commit
|
|
// we hold the lock as long as the control differs from the current
|
|
// otherwise we disabled the lock
|
|
m_bCommitLock = m_bCommitLock && (XControl*)xControl.get() != (XControl*)m_xCurrentControl.get();
|
|
if (m_bCommitLock)
|
|
return;
|
|
|
|
// when do we have to commit a value to form or a filter
|
|
// a.) if the current value is modified
|
|
// b.) there must be a current control
|
|
// c.) and it must be different from the new focus owning control or
|
|
// d.) the focus is moving around (so we have only one control)
|
|
|
|
if ( ( m_bModified || m_bFiltering )
|
|
&& m_xCurrentControl.is()
|
|
&& ( ( xControl.get() != m_xCurrentControl.get() )
|
|
|| ( ( e.FocusFlags & FocusChangeReason::AROUND )
|
|
&& ( m_bCycle || m_bFiltering )
|
|
)
|
|
)
|
|
)
|
|
{
|
|
// check the old control if the content is ok
|
|
#if OSL_DEBUG_LEVEL > 1
|
|
Reference< XBoundControl > xLockingTest(m_xCurrentControl, UNO_QUERY);
|
|
sal_Bool bControlIsLocked = xLockingTest.is() && xLockingTest->getLock();
|
|
OSL_ENSURE(!bControlIsLocked, "FormController::Gained: I'm modified and the current control is locked ? How this ?");
|
|
// normalerweise sollte ein gelocktes Control nicht modified sein, also muss wohl mein bModified aus einem anderen Kontext
|
|
// gesetzt worden sein, was ich nicht verstehen wuerde ...
|
|
#endif
|
|
DBG_ASSERT(m_xCurrentControl.is(), "kein CurrentControl gesetzt");
|
|
// zunaechst das Control fragen ob es das IFace unterstuetzt
|
|
Reference< XBoundComponent > xBound(m_xCurrentControl, UNO_QUERY);
|
|
if (!xBound.is() && m_xCurrentControl.is())
|
|
xBound = Reference< XBoundComponent > (m_xCurrentControl->getModel(), UNO_QUERY);
|
|
|
|
// lock if we lose the focus during commit
|
|
m_bCommitLock = true;
|
|
|
|
// Commit nicht erfolgreich, Focus zuruecksetzen
|
|
if (xBound.is() && !xBound->commit())
|
|
{
|
|
// the commit failed and we don't commit again until the current control
|
|
// which couldn't be commit gains the focus again
|
|
Reference< XWindow > xWindow(m_xCurrentControl, UNO_QUERY);
|
|
if (xWindow.is())
|
|
xWindow->setFocus();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
m_bModified = false;
|
|
m_bCommitLock = false;
|
|
}
|
|
}
|
|
|
|
if (!m_bFiltering && m_bCycle && (e.FocusFlags & FocusChangeReason::AROUND) && m_xCurrentControl.is())
|
|
{
|
|
SQLErrorEvent aErrorEvent;
|
|
OSL_ENSURE( m_xFormOperations.is(), "FormController::focusGained: hmm?" );
|
|
// should have been created in setModel
|
|
try
|
|
{
|
|
if ( e.FocusFlags & FocusChangeReason::FORWARD )
|
|
{
|
|
if ( m_xFormOperations.is() && m_xFormOperations->isEnabled( FormFeature::MoveToNext ) )
|
|
m_xFormOperations->execute( FormFeature::MoveToNext );
|
|
}
|
|
else // backward
|
|
{
|
|
if ( m_xFormOperations.is() && m_xFormOperations->isEnabled( FormFeature::MoveToPrevious ) )
|
|
m_xFormOperations->execute( FormFeature::MoveToPrevious );
|
|
}
|
|
}
|
|
catch ( const Exception& )
|
|
{
|
|
// don't handle this any further. That's an ... admissible error.
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Immer noch ein und dasselbe Control
|
|
if ( ( m_xActiveControl == xControl )
|
|
&& ( xControl == m_xCurrentControl )
|
|
)
|
|
{
|
|
DBG_ASSERT(m_xCurrentControl.is(), "Kein CurrentControl selektiert");
|
|
return;
|
|
}
|
|
|
|
bool bActivated = !m_xActiveControl.is() && xControl.is();
|
|
|
|
m_xActiveControl = xControl;
|
|
|
|
implSetCurrentControl( xControl );
|
|
SAL_WARN_IF( !m_xCurrentControl.is(), "svx.form", "implSetCurrentControl did nonsense!" );
|
|
|
|
if ( bActivated )
|
|
{
|
|
// (asynchronously) call activation handlers
|
|
m_aActivationEvent.Call();
|
|
|
|
// call modify listeners
|
|
if ( m_bModified )
|
|
m_aModifyListeners.notifyEach( &XModifyListener::modified, EventObject( *this ) );
|
|
}
|
|
|
|
// invalidate all features which depend on the currently focused control
|
|
if ( m_bDBConnection && !m_bFiltering )
|
|
implInvalidateCurrentControlDependentFeatures();
|
|
|
|
if ( !m_xCurrentControl.is() )
|
|
return;
|
|
|
|
// Control erhaelt Focus, dann eventuell in den sichtbaren Bereich
|
|
Reference< XFormControllerContext > xContext( m_xFormControllerContext );
|
|
Reference< XControl > xCurrentControl( m_xCurrentControl );
|
|
aGuard.clear();
|
|
// <-- SYNCHRONIZED
|
|
|
|
if ( xContext.is() )
|
|
xContext->makeVisible( xCurrentControl );
|
|
}
|
|
|
|
|
|
IMPL_LINK( FormController, OnActivated, void*, /**/ )
|
|
{
|
|
EventObject aEvent;
|
|
aEvent.Source = *this;
|
|
m_aActivateListeners.notifyEach( &XFormControllerListener::formActivated, aEvent );
|
|
|
|
return 0L;
|
|
}
|
|
|
|
|
|
IMPL_LINK( FormController, OnDeactivated, void*, /**/ )
|
|
{
|
|
EventObject aEvent;
|
|
aEvent.Source = *this;
|
|
m_aActivateListeners.notifyEach( &XFormControllerListener::formDeactivated, aEvent );
|
|
|
|
return 0L;
|
|
}
|
|
|
|
|
|
void FormController::focusLost(const FocusEvent& e) throw( RuntimeException, std::exception )
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
|
|
m_pControlBorderManager->focusLost( e.Source );
|
|
|
|
Reference< XControl > xControl(e.Source, UNO_QUERY);
|
|
Reference< XWindowPeer > xNext(e.NextFocus, UNO_QUERY);
|
|
Reference< XControl > xNextControl = isInList(xNext);
|
|
if (!xNextControl.is())
|
|
{
|
|
m_xActiveControl = NULL;
|
|
m_aDeactivationEvent.Call();
|
|
}
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::mousePressed( const awt::MouseEvent& /*_rEvent*/ ) throw (RuntimeException, std::exception)
|
|
{
|
|
// not interested in
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::mouseReleased( const awt::MouseEvent& /*_rEvent*/ ) throw (RuntimeException, std::exception)
|
|
{
|
|
// not interested in
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::mouseEntered( const awt::MouseEvent& _rEvent ) throw (RuntimeException, std::exception)
|
|
{
|
|
m_pControlBorderManager->mouseEntered( _rEvent.Source );
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::mouseExited( const awt::MouseEvent& _rEvent ) throw (RuntimeException, std::exception)
|
|
{
|
|
m_pControlBorderManager->mouseExited( _rEvent.Source );
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::componentValidityChanged( const EventObject& _rSource ) throw (RuntimeException, std::exception)
|
|
{
|
|
Reference< XControl > xControl( findControl( m_aControls, Reference< XControlModel >( _rSource.Source, UNO_QUERY ), false, false ) );
|
|
Reference< XValidatableFormComponent > xValidatable( _rSource.Source, UNO_QUERY );
|
|
|
|
OSL_ENSURE( xControl.is() && xValidatable.is(), "FormController::componentValidityChanged: huh?" );
|
|
|
|
if ( xControl.is() && xValidatable.is() )
|
|
m_pControlBorderManager->validityChanged( xControl, xValidatable );
|
|
}
|
|
|
|
|
|
void FormController::setModel(const Reference< XTabControllerModel > & Model) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
DBG_ASSERT(m_xTabController.is(), "FormController::setModel : invalid aggregate !");
|
|
|
|
try
|
|
{
|
|
// disconnect from the old model
|
|
if (m_xModelAsIndex.is())
|
|
{
|
|
if (m_bDBConnection)
|
|
{
|
|
// we are currently working on the model
|
|
EventObject aEvt(m_xModelAsIndex);
|
|
unloaded(aEvt);
|
|
}
|
|
|
|
Reference< XLoadable > xForm(m_xModelAsIndex, UNO_QUERY);
|
|
if (xForm.is())
|
|
xForm->removeLoadListener(this);
|
|
|
|
Reference< XSQLErrorBroadcaster > xBroadcaster(m_xModelAsIndex, UNO_QUERY);
|
|
if (xBroadcaster.is())
|
|
xBroadcaster->removeSQLErrorListener(this);
|
|
|
|
Reference< XDatabaseParameterBroadcaster > xParamBroadcaster(m_xModelAsIndex, UNO_QUERY);
|
|
if (xParamBroadcaster.is())
|
|
xParamBroadcaster->removeParameterListener(this);
|
|
|
|
}
|
|
|
|
disposeAllFeaturesAndDispatchers();
|
|
|
|
if ( m_xFormOperations.is() )
|
|
m_xFormOperations->dispose();
|
|
m_xFormOperations.clear();
|
|
|
|
// set the new model wait for the load event
|
|
if (m_xTabController.is())
|
|
m_xTabController->setModel(Model);
|
|
m_xModelAsIndex = Reference< XIndexAccess > (Model, UNO_QUERY);
|
|
m_xModelAsManager = Reference< XEventAttacherManager > (Model, UNO_QUERY);
|
|
|
|
// only if both ifaces exit, the controller will work successful
|
|
if (!m_xModelAsIndex.is() || !m_xModelAsManager.is())
|
|
{
|
|
m_xModelAsManager = NULL;
|
|
m_xModelAsIndex = NULL;
|
|
}
|
|
|
|
if (m_xModelAsIndex.is())
|
|
{
|
|
// re-create m_xFormOperations
|
|
m_xFormOperations = FormOperations::createWithFormController( m_xComponentContext, this );
|
|
m_xFormOperations->setFeatureInvalidation( this );
|
|
|
|
// adding load and ui interaction listeners
|
|
Reference< XLoadable > xForm(Model, UNO_QUERY);
|
|
if (xForm.is())
|
|
xForm->addLoadListener(this);
|
|
|
|
Reference< XSQLErrorBroadcaster > xBroadcaster(Model, UNO_QUERY);
|
|
if (xBroadcaster.is())
|
|
xBroadcaster->addSQLErrorListener(this);
|
|
|
|
Reference< XDatabaseParameterBroadcaster > xParamBroadcaster(Model, UNO_QUERY);
|
|
if (xParamBroadcaster.is())
|
|
xParamBroadcaster->addParameterListener(this);
|
|
|
|
// well, is the database already loaded?
|
|
// then we have to simulate a load event
|
|
Reference< XLoadable > xCursor(m_xModelAsIndex, UNO_QUERY);
|
|
if (xCursor.is() && xCursor->isLoaded())
|
|
{
|
|
EventObject aEvt(xCursor);
|
|
loaded(aEvt);
|
|
}
|
|
|
|
Reference< XPropertySet > xModelProps( m_xModelAsIndex, UNO_QUERY );
|
|
Reference< XPropertySetInfo > xPropInfo( xModelProps->getPropertySetInfo() );
|
|
if ( xPropInfo.is()
|
|
&& xPropInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER )
|
|
&& xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_FOCUS )
|
|
&& xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_MOUSE )
|
|
&& xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_INVALID )
|
|
)
|
|
{
|
|
bool bEnableDynamicControlBorder = lcl_shouldUseDynamicControlBorder(
|
|
xModelProps.get(), xModelProps->getPropertyValue( FM_PROP_DYNAMIC_CONTROL_BORDER ) );
|
|
if ( bEnableDynamicControlBorder )
|
|
m_pControlBorderManager->enableDynamicBorderColor();
|
|
else
|
|
m_pControlBorderManager->disableDynamicBorderColor();
|
|
|
|
sal_Int32 nColor = 0;
|
|
if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_FOCUS ) >>= nColor )
|
|
m_pControlBorderManager->setStatusColor( CONTROL_STATUS_FOCUSED, nColor );
|
|
if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_MOUSE ) >>= nColor )
|
|
m_pControlBorderManager->setStatusColor( CONTROL_STATUS_MOUSE_HOVER, nColor );
|
|
if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_INVALID ) >>= nColor )
|
|
m_pControlBorderManager->setStatusColor( CONTROL_STATUS_INVALID, nColor );
|
|
}
|
|
}
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
}
|
|
|
|
|
|
Reference< XTabControllerModel > FormController::getModel() throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
DBG_ASSERT(m_xTabController.is(), "FormController::getModel : invalid aggregate !");
|
|
if (!m_xTabController.is())
|
|
return Reference< XTabControllerModel > ();
|
|
return m_xTabController->getModel();
|
|
}
|
|
|
|
|
|
void FormController::addToEventAttacher(const Reference< XControl > & xControl)
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
OSL_ENSURE( xControl.is(), "FormController::addToEventAttacher: invalid control - how did you reach this?" );
|
|
if ( !xControl.is() )
|
|
return; /* throw IllegalArgumentException(); */
|
|
|
|
// anmelden beim Eventattacher
|
|
Reference< XFormComponent > xComp(xControl->getModel(), UNO_QUERY);
|
|
if (xComp.is() && m_xModelAsIndex.is())
|
|
{
|
|
// Und die Position des ControlModel darin suchen
|
|
sal_uInt32 nPos = m_xModelAsIndex->getCount();
|
|
Reference< XFormComponent > xTemp;
|
|
for( ; nPos; )
|
|
{
|
|
m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
|
|
if ((XFormComponent*)xComp.get() == (XFormComponent*)xTemp.get())
|
|
{
|
|
m_xModelAsManager->attach( nPos, Reference<XInterface>( xControl, UNO_QUERY ), makeAny(xControl) );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void FormController::removeFromEventAttacher(const Reference< XControl > & xControl)
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
OSL_ENSURE( xControl.is(), "FormController::removeFromEventAttacher: invalid control - how did you reach this?" );
|
|
if ( !xControl.is() )
|
|
return; /* throw IllegalArgumentException(); */
|
|
|
|
// abmelden beim Eventattacher
|
|
Reference< XFormComponent > xComp(xControl->getModel(), UNO_QUERY);
|
|
if ( xComp.is() && m_xModelAsIndex.is() )
|
|
{
|
|
// Und die Position des ControlModel darin suchen
|
|
sal_uInt32 nPos = m_xModelAsIndex->getCount();
|
|
Reference< XFormComponent > xTemp;
|
|
for( ; nPos; )
|
|
{
|
|
m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
|
|
if ((XFormComponent*)xComp.get() == (XFormComponent*)xTemp.get())
|
|
{
|
|
m_xModelAsManager->detach( nPos, Reference<XInterface>( xControl, UNO_QUERY ) );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void FormController::setContainer(const Reference< XControlContainer > & xContainer) throw( RuntimeException, std::exception )
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
Reference< XTabControllerModel > xTabModel(getModel());
|
|
DBG_ASSERT(xTabModel.is() || !xContainer.is(), "No Model defined");
|
|
// if we have a new container we need a model
|
|
DBG_ASSERT(m_xTabController.is(), "FormController::setContainer : invalid aggregate !");
|
|
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
Reference< XContainer > xCurrentContainer;
|
|
if (m_xTabController.is())
|
|
xCurrentContainer = Reference< XContainer > (m_xTabController->getContainer(), UNO_QUERY);
|
|
if (xCurrentContainer.is())
|
|
{
|
|
xCurrentContainer->removeContainerListener(this);
|
|
|
|
if ( m_aTabActivationIdle.IsActive() )
|
|
m_aTabActivationIdle.Stop();
|
|
|
|
// clear the filter map
|
|
::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), RemoveComponentTextListener( this ) );
|
|
m_aFilterComponents.clear();
|
|
|
|
// einsammeln der Controls
|
|
const Reference< XControl >* pControls = m_aControls.getConstArray();
|
|
const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
|
|
while ( pControls != pControlsEnd )
|
|
implControlRemoved( *pControls++, true );
|
|
|
|
// Datenbank spezifische Dinge vornehmen
|
|
if (m_bDBConnection && isListeningForChanges())
|
|
stopListening();
|
|
|
|
m_aControls.realloc( 0 );
|
|
}
|
|
|
|
if (m_xTabController.is())
|
|
m_xTabController->setContainer(xContainer);
|
|
|
|
// Welche Controls gehoeren zum Container ?
|
|
if (xContainer.is() && xTabModel.is())
|
|
{
|
|
Sequence< Reference< XControlModel > > aModels = xTabModel->getControlModels();
|
|
const Reference< XControlModel > * pModels = aModels.getConstArray();
|
|
Sequence< Reference< XControl > > aAllControls = xContainer->getControls();
|
|
|
|
sal_Int32 nCount = aModels.getLength();
|
|
m_aControls = Sequence< Reference< XControl > >( nCount );
|
|
Reference< XControl > * pControls = m_aControls.getArray();
|
|
|
|
// einsammeln der Controls
|
|
sal_Int32 i, j;
|
|
for (i = 0, j = 0; i < nCount; ++i, ++pModels )
|
|
{
|
|
Reference< XControl > xControl = findControl( aAllControls, *pModels, false, true );
|
|
if ( xControl.is() )
|
|
{
|
|
pControls[j++] = xControl;
|
|
implControlInserted( xControl, true );
|
|
}
|
|
}
|
|
|
|
// not every model had an associated control
|
|
if (j != i)
|
|
m_aControls.realloc(j);
|
|
|
|
// am Container horchen
|
|
Reference< XContainer > xNewContainer(xContainer, UNO_QUERY);
|
|
if (xNewContainer.is())
|
|
xNewContainer->addContainerListener(this);
|
|
|
|
// Datenbank spezifische Dinge vornehmen
|
|
if (m_bDBConnection)
|
|
{
|
|
m_bLocked = determineLockState();
|
|
setLocks();
|
|
if (!isLocked())
|
|
startListening();
|
|
}
|
|
}
|
|
// befinden sich die Controls in der richtigen Reihenfolge
|
|
m_bControlsSorted = true;
|
|
}
|
|
|
|
|
|
Reference< XControlContainer > FormController::getContainer() throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
DBG_ASSERT(m_xTabController.is(), "FormController::getContainer : invalid aggregate !");
|
|
if (!m_xTabController.is())
|
|
return Reference< XControlContainer > ();
|
|
return m_xTabController->getContainer();
|
|
}
|
|
|
|
|
|
Sequence< Reference< XControl > > FormController::getControls(void) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
if (!m_bControlsSorted)
|
|
{
|
|
Reference< XTabControllerModel > xModel = getModel();
|
|
if (!xModel.is())
|
|
return m_aControls;
|
|
|
|
Sequence< Reference< XControlModel > > aControlModels = xModel->getControlModels();
|
|
const Reference< XControlModel > * pModels = aControlModels.getConstArray();
|
|
sal_Int32 nModels = aControlModels.getLength();
|
|
|
|
Sequence< Reference< XControl > > aNewControls(nModels);
|
|
|
|
Reference< XControl > * pControls = aNewControls.getArray();
|
|
Reference< XControl > xControl;
|
|
|
|
// Umsortieren der Controls entsprechend der TabReihenfolge
|
|
sal_Int32 j = 0;
|
|
for (sal_Int32 i = 0; i < nModels; ++i, ++pModels )
|
|
{
|
|
xControl = findControl( m_aControls, *pModels, true, true );
|
|
if ( xControl.is() )
|
|
pControls[j++] = xControl;
|
|
}
|
|
|
|
// not every model had an associated control
|
|
if ( j != nModels )
|
|
aNewControls.realloc( j );
|
|
|
|
m_aControls = aNewControls;
|
|
m_bControlsSorted = true;
|
|
}
|
|
return m_aControls;
|
|
}
|
|
|
|
|
|
void FormController::autoTabOrder() throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
DBG_ASSERT(m_xTabController.is(), "FormController::autoTabOrder : invalid aggregate !");
|
|
if (m_xTabController.is())
|
|
m_xTabController->autoTabOrder();
|
|
}
|
|
|
|
|
|
void FormController::activateTabOrder() throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
DBG_ASSERT(m_xTabController.is(), "FormController::activateTabOrder : invalid aggregate !");
|
|
if (m_xTabController.is())
|
|
m_xTabController->activateTabOrder();
|
|
}
|
|
|
|
|
|
void FormController::setControlLock(const Reference< XControl > & xControl)
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
bool bLocked = isLocked();
|
|
|
|
// es wird gelockt
|
|
// a.) wenn der ganze Datensatz gesperrt ist
|
|
// b.) wenn das zugehoerige Feld gespeert ist
|
|
Reference< XBoundControl > xBound(xControl, UNO_QUERY);
|
|
if (xBound.is() && (( (bLocked && (bLocked ? 1 : 0) != xBound->getLock()) ||
|
|
!bLocked))) // beim entlocken immer einzelne Felder ueberprüfen
|
|
{
|
|
// gibt es eine Datenquelle
|
|
Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
|
|
if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
|
|
{
|
|
// wie sieht mit den Properties ReadOnly und Enable aus
|
|
bool bTouch = true;
|
|
if (::comphelper::hasProperty(FM_PROP_ENABLED, xSet))
|
|
bTouch = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ENABLED));
|
|
if (::comphelper::hasProperty(FM_PROP_READONLY, xSet))
|
|
bTouch = !::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_READONLY));
|
|
|
|
if (bTouch)
|
|
{
|
|
Reference< XPropertySet > xField;
|
|
xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
|
|
if (xField.is())
|
|
{
|
|
if (bLocked)
|
|
xBound->setLock(bLocked);
|
|
else
|
|
{
|
|
try
|
|
{
|
|
Any aVal = xField->getPropertyValue(FM_PROP_ISREADONLY);
|
|
if (aVal.hasValue() && ::comphelper::getBOOL(aVal))
|
|
xBound->setLock(sal_True);
|
|
else
|
|
xBound->setLock(bLocked);
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void FormController::setLocks()
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
// alle Controls, die mit einer Datenquelle verbunden sind locken/unlocken
|
|
const Reference< XControl >* pControls = m_aControls.getConstArray();
|
|
const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
|
|
while ( pControls != pControlsEnd )
|
|
setControlLock( *pControls++ );
|
|
}
|
|
|
|
|
|
namespace
|
|
{
|
|
bool lcl_shouldListenForModifications( const Reference< XControl >& _rxControl, const Reference< XPropertyChangeListener >& _rxBoundFieldListener )
|
|
{
|
|
bool bShould = false;
|
|
|
|
Reference< XBoundComponent > xBound( _rxControl, UNO_QUERY );
|
|
if ( xBound.is() )
|
|
{
|
|
bShould = true;
|
|
}
|
|
else if ( _rxControl.is() )
|
|
{
|
|
Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY );
|
|
if ( xModelProps.is() && ::comphelper::hasProperty( FM_PROP_BOUNDFIELD, xModelProps ) )
|
|
{
|
|
Reference< XPropertySet > xField;
|
|
xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField;
|
|
bShould = xField.is();
|
|
|
|
if ( !bShould && _rxBoundFieldListener.is() )
|
|
xModelProps->addPropertyChangeListener( FM_PROP_BOUNDFIELD, _rxBoundFieldListener );
|
|
}
|
|
}
|
|
|
|
return bShould;
|
|
}
|
|
}
|
|
|
|
|
|
void FormController::startControlModifyListening(const Reference< XControl > & xControl)
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
|
|
bool bModifyListening = lcl_shouldListenForModifications( xControl, this );
|
|
|
|
// artificial while
|
|
while ( bModifyListening )
|
|
{
|
|
Reference< XModifyBroadcaster > xMod(xControl, UNO_QUERY);
|
|
if (xMod.is())
|
|
{
|
|
xMod->addModifyListener(this);
|
|
break;
|
|
}
|
|
|
|
// alle die Text um vorzeitig ein modified zu erkennen
|
|
Reference< XTextComponent > xText(xControl, UNO_QUERY);
|
|
if (xText.is())
|
|
{
|
|
xText->addTextListener(this);
|
|
break;
|
|
}
|
|
|
|
Reference< XCheckBox > xBox(xControl, UNO_QUERY);
|
|
if (xBox.is())
|
|
{
|
|
xBox->addItemListener(this);
|
|
break;
|
|
}
|
|
|
|
Reference< XComboBox > xCbBox(xControl, UNO_QUERY);
|
|
if (xCbBox.is())
|
|
{
|
|
xCbBox->addItemListener(this);
|
|
break;
|
|
}
|
|
|
|
Reference< XListBox > xListBox(xControl, UNO_QUERY);
|
|
if (xListBox.is())
|
|
{
|
|
xListBox->addItemListener(this);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void FormController::stopControlModifyListening(const Reference< XControl > & xControl)
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
|
|
bool bModifyListening = lcl_shouldListenForModifications( xControl, NULL );
|
|
|
|
// kuenstliches while
|
|
while (bModifyListening)
|
|
{
|
|
Reference< XModifyBroadcaster > xMod(xControl, UNO_QUERY);
|
|
if (xMod.is())
|
|
{
|
|
xMod->removeModifyListener(this);
|
|
break;
|
|
}
|
|
// alle die Text um vorzeitig ein modified zu erkennen
|
|
Reference< XTextComponent > xText(xControl, UNO_QUERY);
|
|
if (xText.is())
|
|
{
|
|
xText->removeTextListener(this);
|
|
break;
|
|
}
|
|
|
|
Reference< XCheckBox > xBox(xControl, UNO_QUERY);
|
|
if (xBox.is())
|
|
{
|
|
xBox->removeItemListener(this);
|
|
break;
|
|
}
|
|
|
|
Reference< XComboBox > xCbBox(xControl, UNO_QUERY);
|
|
if (xCbBox.is())
|
|
{
|
|
xCbBox->removeItemListener(this);
|
|
break;
|
|
}
|
|
|
|
Reference< XListBox > xListBox(xControl, UNO_QUERY);
|
|
if (xListBox.is())
|
|
{
|
|
xListBox->removeItemListener(this);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void FormController::startListening()
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
m_bModified = false;
|
|
|
|
// jetzt anmelden bei gebundenen feldern
|
|
const Reference< XControl >* pControls = m_aControls.getConstArray();
|
|
const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
|
|
while ( pControls != pControlsEnd )
|
|
startControlModifyListening( *pControls++ );
|
|
}
|
|
|
|
|
|
void FormController::stopListening()
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
m_bModified = false;
|
|
|
|
// jetzt anmelden bei gebundenen feldern
|
|
const Reference< XControl >* pControls = m_aControls.getConstArray();
|
|
const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
|
|
while ( pControls != pControlsEnd )
|
|
stopControlModifyListening( *pControls++ );
|
|
}
|
|
|
|
|
|
|
|
Reference< XControl > FormController::findControl(Sequence< Reference< XControl > >& _rControls, const Reference< XControlModel > & xCtrlModel ,bool _bRemove,bool _bOverWrite) const
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
DBG_ASSERT( xCtrlModel.is(), "findControl - welches ?!" );
|
|
|
|
Reference< XControl >* pControls = _rControls.getArray();
|
|
Reference< XControlModel > xModel;
|
|
for ( sal_Int32 i = 0, nCount = _rControls.getLength(); i < nCount; ++i, ++pControls )
|
|
{
|
|
if ( pControls->is() )
|
|
{
|
|
xModel = (*pControls)->getModel();
|
|
if ( xModel.get() == xCtrlModel.get() )
|
|
{
|
|
Reference< XControl > xControl( *pControls );
|
|
if ( _bRemove )
|
|
::comphelper::removeElementAt( _rControls, i );
|
|
else if ( _bOverWrite )
|
|
pControls->clear();
|
|
return xControl;
|
|
}
|
|
}
|
|
}
|
|
return Reference< XControl > ();
|
|
}
|
|
|
|
|
|
void FormController::implControlInserted( const Reference< XControl>& _rxControl, bool _bAddToEventAttacher )
|
|
{
|
|
Reference< XWindow > xWindow( _rxControl, UNO_QUERY );
|
|
if ( xWindow.is() )
|
|
{
|
|
xWindow->addFocusListener( this );
|
|
xWindow->addMouseListener( this );
|
|
|
|
if ( _bAddToEventAttacher )
|
|
addToEventAttacher( _rxControl );
|
|
}
|
|
|
|
// add a dispatch interceptor to the control (if supported)
|
|
Reference< XDispatchProviderInterception > xInterception( _rxControl, UNO_QUERY );
|
|
if ( xInterception.is() )
|
|
createInterceptor( xInterception );
|
|
|
|
if ( _rxControl.is() )
|
|
{
|
|
Reference< XControlModel > xModel( _rxControl->getModel() );
|
|
|
|
// we want to know about the reset of the model of our controls
|
|
// (for correctly resetting m_bModified)
|
|
Reference< XReset > xReset( xModel, UNO_QUERY );
|
|
if ( xReset.is() )
|
|
xReset->addResetListener( this );
|
|
|
|
// and we want to know about the validity, to visually indicate it
|
|
Reference< XValidatableFormComponent > xValidatable( xModel, UNO_QUERY );
|
|
if ( xValidatable.is() )
|
|
{
|
|
xValidatable->addFormComponentValidityListener( this );
|
|
m_pControlBorderManager->validityChanged( _rxControl, xValidatable );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void FormController::implControlRemoved( const Reference< XControl>& _rxControl, bool _bRemoveFromEventAttacher )
|
|
{
|
|
Reference< XWindow > xWindow( _rxControl, UNO_QUERY );
|
|
if ( xWindow.is() )
|
|
{
|
|
xWindow->removeFocusListener( this );
|
|
xWindow->removeMouseListener( this );
|
|
|
|
if ( _bRemoveFromEventAttacher )
|
|
removeFromEventAttacher( _rxControl );
|
|
}
|
|
|
|
Reference< XDispatchProviderInterception > xInterception( _rxControl, UNO_QUERY);
|
|
if ( xInterception.is() )
|
|
deleteInterceptor( xInterception );
|
|
|
|
if ( _rxControl.is() )
|
|
{
|
|
Reference< XControlModel > xModel( _rxControl->getModel() );
|
|
|
|
Reference< XReset > xReset( xModel, UNO_QUERY );
|
|
if ( xReset.is() )
|
|
xReset->removeResetListener( this );
|
|
|
|
Reference< XValidatableFormComponent > xValidatable( xModel, UNO_QUERY );
|
|
if ( xValidatable.is() )
|
|
xValidatable->removeFormComponentValidityListener( this );
|
|
}
|
|
}
|
|
|
|
|
|
void FormController::implSetCurrentControl( const Reference< XControl >& _rxControl )
|
|
{
|
|
if ( m_xCurrentControl.get() == _rxControl.get() )
|
|
return;
|
|
|
|
Reference< XGridControl > xGridControl( m_xCurrentControl, UNO_QUERY );
|
|
if ( xGridControl.is() )
|
|
xGridControl->removeGridControlListener( this );
|
|
|
|
m_xCurrentControl = _rxControl;
|
|
|
|
xGridControl.set( m_xCurrentControl, UNO_QUERY );
|
|
if ( xGridControl.is() )
|
|
xGridControl->addGridControlListener( this );
|
|
}
|
|
|
|
|
|
void FormController::insertControl(const Reference< XControl > & xControl)
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
m_bControlsSorted = false;
|
|
m_aControls.realloc(m_aControls.getLength() + 1);
|
|
m_aControls.getArray()[m_aControls.getLength() - 1] = xControl;
|
|
|
|
if ( m_pColumnInfoCache.get() )
|
|
m_pColumnInfoCache->deinitializeControls();
|
|
|
|
implControlInserted( xControl, m_bAttachEvents );
|
|
|
|
if (m_bDBConnection && !m_bFiltering)
|
|
setControlLock(xControl);
|
|
|
|
if (isListeningForChanges() && m_bAttachEvents)
|
|
startControlModifyListening( xControl );
|
|
}
|
|
|
|
|
|
void FormController::removeControl(const Reference< XControl > & xControl)
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
const Reference< XControl >* pControls = m_aControls.getConstArray();
|
|
const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
|
|
while ( pControls != pControlsEnd )
|
|
{
|
|
if ( xControl.get() == (*pControls++).get() )
|
|
{
|
|
::comphelper::removeElementAt( m_aControls, pControls - m_aControls.getConstArray() - 1 );
|
|
break;
|
|
}
|
|
}
|
|
|
|
FilterComponents::iterator componentPos = ::std::find( m_aFilterComponents.begin(), m_aFilterComponents.end(), xControl );
|
|
if ( componentPos != m_aFilterComponents.end() )
|
|
m_aFilterComponents.erase( componentPos );
|
|
|
|
implControlRemoved( xControl, m_bDetachEvents );
|
|
|
|
if ( isListeningForChanges() && m_bDetachEvents )
|
|
stopControlModifyListening( xControl );
|
|
}
|
|
|
|
// XLoadListener
|
|
|
|
void FormController::loaded(const EventObject& rEvent) throw( RuntimeException, std::exception )
|
|
{
|
|
OSL_ENSURE( rEvent.Source == m_xModelAsIndex, "FormController::loaded: where did this come from?" );
|
|
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
Reference< XRowSet > xForm(rEvent.Source, UNO_QUERY);
|
|
// do we have a connected data source
|
|
OStaticDataAccessTools aStaticTools;
|
|
if (xForm.is() && aStaticTools.getRowSetConnection(xForm).is())
|
|
{
|
|
Reference< XPropertySet > xSet(xForm, UNO_QUERY);
|
|
if (xSet.is())
|
|
{
|
|
Any aVal = xSet->getPropertyValue(FM_PROP_CYCLE);
|
|
sal_Int32 aVal2 = 0;
|
|
::cppu::enum2int(aVal2,aVal);
|
|
m_bCycle = !aVal.hasValue() || aVal2 == TabulatorCycle_RECORDS;
|
|
m_bCanUpdate = aStaticTools.canUpdate(xSet);
|
|
m_bCanInsert = aStaticTools.canInsert(xSet);
|
|
m_bCurrentRecordModified = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED));
|
|
m_bCurrentRecordNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
|
|
|
|
startFormListening( xSet, false );
|
|
|
|
// set the locks for the current controls
|
|
if (getContainer().is())
|
|
{
|
|
m_aLoadEvent.Call();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_bCanInsert = m_bCanUpdate = m_bCycle = false;
|
|
m_bCurrentRecordModified = false;
|
|
m_bCurrentRecordNew = false;
|
|
m_bLocked = false;
|
|
}
|
|
m_bDBConnection = true;
|
|
}
|
|
else
|
|
{
|
|
m_bDBConnection = false;
|
|
m_bCanInsert = m_bCanUpdate = m_bCycle = false;
|
|
m_bCurrentRecordModified = false;
|
|
m_bCurrentRecordNew = false;
|
|
m_bLocked = false;
|
|
}
|
|
|
|
Reference< XColumnsSupplier > xFormColumns( xForm, UNO_QUERY );
|
|
m_pColumnInfoCache.reset( xFormColumns.is() ? new ColumnInfoCache( xFormColumns ) : NULL );
|
|
|
|
updateAllDispatchers();
|
|
}
|
|
|
|
|
|
void FormController::updateAllDispatchers() const
|
|
{
|
|
::std::for_each(
|
|
m_aFeatureDispatchers.begin(),
|
|
m_aFeatureDispatchers.end(),
|
|
::o3tl::compose1(
|
|
UpdateAllListeners(),
|
|
::o3tl::select2nd< DispatcherContainer::value_type >()
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
IMPL_LINK_NOARG(FormController, OnLoad)
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
m_bLocked = determineLockState();
|
|
|
|
setLocks();
|
|
|
|
if (!m_bLocked)
|
|
startListening();
|
|
|
|
// just one exception toggle the auto values
|
|
if (m_bCurrentRecordNew)
|
|
toggleAutoFields(true);
|
|
|
|
return 1L;
|
|
}
|
|
|
|
|
|
void FormController::unloaded(const EventObject& /*rEvent*/) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
updateAllDispatchers();
|
|
}
|
|
|
|
|
|
void FormController::reloading(const EventObject& /*aEvent*/) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
// do the same like in unloading
|
|
// just one exception toggle the auto values
|
|
m_aToggleEvent.CancelPendingCall();
|
|
unload();
|
|
}
|
|
|
|
|
|
void FormController::reloaded(const EventObject& aEvent) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
loaded(aEvent);
|
|
}
|
|
|
|
|
|
void FormController::unloading(const EventObject& /*aEvent*/) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
unload();
|
|
}
|
|
|
|
|
|
void FormController::unload() throw( RuntimeException )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
m_aLoadEvent.CancelPendingCall();
|
|
|
|
// be sure not to have autofields
|
|
if (m_bCurrentRecordNew)
|
|
toggleAutoFields(false);
|
|
|
|
// remove bound field listing again
|
|
removeBoundFieldListener();
|
|
|
|
if (m_bDBConnection && isListeningForChanges())
|
|
stopListening();
|
|
|
|
Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
|
|
if ( m_bDBConnection && xSet.is() )
|
|
stopFormListening( xSet, false );
|
|
|
|
m_bDBConnection = false;
|
|
m_bCanInsert = m_bCanUpdate = m_bCycle = false;
|
|
m_bCurrentRecordModified = m_bCurrentRecordNew = m_bLocked = false;
|
|
|
|
m_pColumnInfoCache.reset();
|
|
}
|
|
|
|
|
|
void FormController::removeBoundFieldListener()
|
|
{
|
|
const Reference< XControl >* pControls = m_aControls.getConstArray();
|
|
const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength();
|
|
while ( pControls != pControlsEnd )
|
|
{
|
|
Reference< XPropertySet > xProp( *pControls++, UNO_QUERY );
|
|
if ( xProp.is() )
|
|
xProp->removePropertyChangeListener( FM_PROP_BOUNDFIELD, this );
|
|
}
|
|
}
|
|
|
|
|
|
void FormController::startFormListening( const Reference< XPropertySet >& _rxForm, bool _bPropertiesOnly )
|
|
{
|
|
try
|
|
{
|
|
if ( m_bCanInsert || m_bCanUpdate ) // form can be modified
|
|
{
|
|
_rxForm->addPropertyChangeListener( FM_PROP_ISNEW, this );
|
|
_rxForm->addPropertyChangeListener( FM_PROP_ISMODIFIED, this );
|
|
|
|
if ( !_bPropertiesOnly )
|
|
{
|
|
// set the Listener for UI interaction
|
|
Reference< XRowSetApproveBroadcaster > xApprove( _rxForm, UNO_QUERY );
|
|
if ( xApprove.is() )
|
|
xApprove->addRowSetApproveListener( this );
|
|
|
|
// listener for row set changes
|
|
Reference< XRowSet > xRowSet( _rxForm, UNO_QUERY );
|
|
if ( xRowSet.is() )
|
|
xRowSet->addRowSetListener( this );
|
|
}
|
|
}
|
|
|
|
Reference< XPropertySetInfo > xInfo = _rxForm->getPropertySetInfo();
|
|
if ( xInfo.is() && xInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) )
|
|
_rxForm->addPropertyChangeListener( FM_PROP_DYNAMIC_CONTROL_BORDER, this );
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
}
|
|
|
|
|
|
void FormController::stopFormListening( const Reference< XPropertySet >& _rxForm, bool _bPropertiesOnly )
|
|
{
|
|
try
|
|
{
|
|
if ( m_bCanInsert || m_bCanUpdate )
|
|
{
|
|
_rxForm->removePropertyChangeListener( FM_PROP_ISNEW, this );
|
|
_rxForm->removePropertyChangeListener( FM_PROP_ISMODIFIED, this );
|
|
|
|
if ( !_bPropertiesOnly )
|
|
{
|
|
Reference< XRowSetApproveBroadcaster > xApprove( _rxForm, UNO_QUERY );
|
|
if (xApprove.is())
|
|
xApprove->removeRowSetApproveListener(this);
|
|
|
|
Reference< XRowSet > xRowSet( _rxForm, UNO_QUERY );
|
|
if ( xRowSet.is() )
|
|
xRowSet->removeRowSetListener( this );
|
|
}
|
|
}
|
|
|
|
Reference< XPropertySetInfo > xInfo = _rxForm->getPropertySetInfo();
|
|
if ( xInfo.is() && xInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) )
|
|
_rxForm->removePropertyChangeListener( FM_PROP_DYNAMIC_CONTROL_BORDER, this );
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
}
|
|
|
|
// com::sun::star::sdbc::XRowSetListener
|
|
|
|
void FormController::cursorMoved(const EventObject& /*event*/) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
// toggle the locking ?
|
|
if (m_bLocked != determineLockState())
|
|
{
|
|
m_bLocked = !m_bLocked;
|
|
setLocks();
|
|
if (isListeningForChanges())
|
|
startListening();
|
|
else
|
|
stopListening();
|
|
}
|
|
|
|
// neither the current control nor the current record are modified anymore
|
|
m_bCurrentRecordModified = m_bModified = false;
|
|
}
|
|
|
|
|
|
void FormController::rowChanged(const EventObject& /*event*/) throw( RuntimeException, std::exception )
|
|
{
|
|
// not interested in ...
|
|
}
|
|
|
|
void FormController::rowSetChanged(const EventObject& /*event*/) throw( RuntimeException, std::exception )
|
|
{
|
|
// not interested in ...
|
|
}
|
|
|
|
|
|
// XContainerListener
|
|
|
|
void SAL_CALL FormController::elementInserted(const ContainerEvent& evt) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
Reference< XControl > xControl( evt.Element, UNO_QUERY );
|
|
if ( !xControl.is() )
|
|
return;
|
|
|
|
Reference< XFormComponent > xModel(xControl->getModel(), UNO_QUERY);
|
|
if (xModel.is() && m_xModelAsIndex == xModel->getParent())
|
|
{
|
|
insertControl(xControl);
|
|
|
|
if ( m_aTabActivationIdle.IsActive() )
|
|
m_aTabActivationIdle.Stop();
|
|
|
|
m_aTabActivationIdle.Start();
|
|
}
|
|
// are we in filtermode and a XModeSelector has inserted an element
|
|
else if (m_bFiltering && Reference< XModeSelector > (evt.Source, UNO_QUERY).is())
|
|
{
|
|
xModel = Reference< XFormComponent > (evt.Source, UNO_QUERY);
|
|
if (xModel.is() && m_xModelAsIndex == xModel->getParent())
|
|
{
|
|
Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
|
|
if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
|
|
{
|
|
// does the model use a bound field ?
|
|
Reference< XPropertySet > xField;
|
|
xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
|
|
|
|
Reference< XTextComponent > xText(xControl, UNO_QUERY);
|
|
// may we filter the field?
|
|
if (xText.is() && xField.is() && ::comphelper::hasProperty(FM_PROP_SEARCHABLE, xField) &&
|
|
::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_SEARCHABLE)))
|
|
{
|
|
m_aFilterComponents.push_back( xText );
|
|
xText->addTextListener( this );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::elementReplaced(const ContainerEvent& evt) throw( RuntimeException, std::exception )
|
|
{
|
|
// simulate an elementRemoved
|
|
ContainerEvent aRemoveEvent( evt );
|
|
aRemoveEvent.Element = evt.ReplacedElement;
|
|
aRemoveEvent.ReplacedElement = Any();
|
|
elementRemoved( aRemoveEvent );
|
|
|
|
// simulate an elementInserted
|
|
ContainerEvent aInsertEvent( evt );
|
|
aInsertEvent.ReplacedElement = Any();
|
|
elementInserted( aInsertEvent );
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::elementRemoved(const ContainerEvent& evt) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
Reference< XControl > xControl;
|
|
evt.Element >>= xControl;
|
|
if (!xControl.is())
|
|
return;
|
|
|
|
Reference< XFormComponent > xModel(xControl->getModel(), UNO_QUERY);
|
|
if (xModel.is() && m_xModelAsIndex == xModel->getParent())
|
|
{
|
|
removeControl(xControl);
|
|
// TabOrder nicht neu berechnen, da das intern schon funktionieren muss!
|
|
}
|
|
// are we in filtermode and a XModeSelector has inserted an element
|
|
else if (m_bFiltering && Reference< XModeSelector > (evt.Source, UNO_QUERY).is())
|
|
{
|
|
FilterComponents::iterator componentPos = ::std::find(
|
|
m_aFilterComponents.begin(), m_aFilterComponents.end(), xControl );
|
|
if ( componentPos != m_aFilterComponents.end() )
|
|
m_aFilterComponents.erase( componentPos );
|
|
}
|
|
}
|
|
|
|
|
|
Reference< XControl > FormController::isInList(const Reference< XWindowPeer > & xPeer) const
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
const Reference< XControl >* pControls = m_aControls.getConstArray();
|
|
|
|
sal_uInt32 nCtrls = m_aControls.getLength();
|
|
for ( sal_uInt32 n = 0; n < nCtrls && xPeer.is(); ++n, ++pControls )
|
|
{
|
|
if ( pControls->is() )
|
|
{
|
|
Reference< XVclWindowPeer > xCtrlPeer( (*pControls)->getPeer(), UNO_QUERY);
|
|
if ( ( xCtrlPeer.get() == xPeer.get() ) || xCtrlPeer->isChild( xPeer ) )
|
|
return *pControls;
|
|
}
|
|
}
|
|
return Reference< XControl > ();
|
|
}
|
|
|
|
|
|
void FormController::activateFirst() throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
DBG_ASSERT(m_xTabController.is(), "FormController::activateFirst : invalid aggregate !");
|
|
if (m_xTabController.is())
|
|
m_xTabController->activateFirst();
|
|
}
|
|
|
|
|
|
void FormController::activateLast() throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
DBG_ASSERT(m_xTabController.is(), "FormController::activateLast : invalid aggregate !");
|
|
if (m_xTabController.is())
|
|
m_xTabController->activateLast();
|
|
}
|
|
|
|
// XFormController
|
|
|
|
Reference< XFormOperations > SAL_CALL FormController::getFormOperations() throw (RuntimeException, std::exception)
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
return m_xFormOperations;
|
|
}
|
|
|
|
|
|
Reference< XControl> SAL_CALL FormController::getCurrentControl(void) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
return m_xCurrentControl;
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::addActivateListener(const Reference< XFormControllerListener > & l) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
m_aActivateListeners.addInterface(l);
|
|
}
|
|
|
|
void SAL_CALL FormController::removeActivateListener(const Reference< XFormControllerListener > & l) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
m_aActivateListeners.removeInterface(l);
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::addChildController( const Reference< XFormController >& _ChildController ) throw( RuntimeException, IllegalArgumentException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
if ( !_ChildController.is() )
|
|
throw IllegalArgumentException( OUString(), *this, 1 );
|
|
// TODO: (localized) error message
|
|
|
|
// the parent of our (to-be-)child must be our own model
|
|
Reference< XFormComponent > xFormOfChild( _ChildController->getModel(), UNO_QUERY );
|
|
if ( !xFormOfChild.is() )
|
|
throw IllegalArgumentException( OUString(), *this, 1 );
|
|
// TODO: (localized) error message
|
|
|
|
if ( xFormOfChild->getParent() != m_xModelAsIndex )
|
|
throw IllegalArgumentException( OUString(), *this, 1 );
|
|
// TODO: (localized) error message
|
|
|
|
m_aChildren.push_back( _ChildController );
|
|
_ChildController->setParent( *this );
|
|
|
|
// search the position of the model within the form
|
|
sal_uInt32 nPos = m_xModelAsIndex->getCount();
|
|
Reference< XFormComponent > xTemp;
|
|
for( ; nPos; )
|
|
{
|
|
m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
|
|
if ( xFormOfChild == xTemp )
|
|
{
|
|
m_xModelAsManager->attach( nPos, Reference<XInterface>( _ChildController, UNO_QUERY ), makeAny( _ChildController) );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Reference< XFormControllerContext > SAL_CALL FormController::getContext() throw (RuntimeException, std::exception)
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
return m_xFormControllerContext;
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::setContext( const Reference< XFormControllerContext >& _context ) throw (RuntimeException, std::exception)
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
m_xFormControllerContext = _context;
|
|
}
|
|
|
|
|
|
Reference< XInteractionHandler > SAL_CALL FormController::getInteractionHandler() throw (RuntimeException, std::exception)
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
return m_xInteractionHandler;
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::setInteractionHandler( const Reference< XInteractionHandler >& _interactionHandler ) throw (RuntimeException, std::exception)
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
m_xInteractionHandler = _interactionHandler;
|
|
}
|
|
|
|
|
|
void FormController::setFilter(::std::vector<FmFieldInfo>& rFieldInfos)
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
// create the composer
|
|
Reference< XRowSet > xForm(m_xModelAsIndex, UNO_QUERY);
|
|
Reference< XConnection > xConnection(OStaticDataAccessTools().getRowSetConnection(xForm));
|
|
if (xForm.is())
|
|
{
|
|
try
|
|
{
|
|
Reference< XMultiServiceFactory > xFactory( xConnection, UNO_QUERY_THROW );
|
|
m_xComposer.set(
|
|
xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"),
|
|
UNO_QUERY_THROW );
|
|
|
|
Reference< XPropertySet > xSet( xForm, UNO_QUERY );
|
|
OUString sStatement = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_ACTIVECOMMAND ) );
|
|
OUString sFilter = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_FILTER ) );
|
|
m_xComposer->setElementaryQuery( sStatement );
|
|
m_xComposer->setFilter( sFilter );
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
}
|
|
|
|
if (m_xComposer.is())
|
|
{
|
|
Sequence< Sequence < PropertyValue > > aFilterRows = m_xComposer->getStructuredFilter();
|
|
|
|
// ok, we receive the list of filters as sequence of fieldnames, value
|
|
// now we have to transform the fieldname into UI names, that could be a label of the field or
|
|
// a aliasname or the fieldname itself
|
|
|
|
// first adjust the field names if necessary
|
|
Reference< XNameAccess > xQueryColumns =
|
|
Reference< XColumnsSupplier >( m_xComposer, UNO_QUERY_THROW )->getColumns();
|
|
|
|
for (::std::vector<FmFieldInfo>::iterator iter = rFieldInfos.begin();
|
|
iter != rFieldInfos.end(); ++iter)
|
|
{
|
|
if ( xQueryColumns->hasByName((*iter).aFieldName) )
|
|
{
|
|
if ( (xQueryColumns->getByName((*iter).aFieldName) >>= (*iter).xField) && (*iter).xField.is() )
|
|
(*iter).xField->getPropertyValue(FM_PROP_REALNAME) >>= (*iter).aFieldName;
|
|
}
|
|
}
|
|
|
|
Reference< XDatabaseMetaData> xMetaData(xConnection->getMetaData());
|
|
// now transfer the filters into Value/TextComponent pairs
|
|
::comphelper::UStringMixEqual aCompare(xMetaData->storesMixedCaseQuotedIdentifiers());
|
|
|
|
// need to parse criteria localized
|
|
OStaticDataAccessTools aStaticTools;
|
|
Reference< XNumberFormatsSupplier> xFormatSupplier( aStaticTools.getNumberFormats(xConnection, true));
|
|
Reference< XNumberFormatter> xFormatter = NumberFormatter::create(m_xComponentContext);
|
|
xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
|
|
Locale aAppLocale = Application::GetSettings().GetUILanguageTag().getLocale();
|
|
const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetUILocaleDataWrapper() );
|
|
/* FIXME: casting this to sal_Char is plain wrong and of course only
|
|
* works for ASCII separators, but
|
|
* xParseNode->parseNodeToPredicateStr() expects a sal_Char. Fix it
|
|
* there. */
|
|
sal_Char cDecimalSeparator = (sal_Char)rLocaleWrapper.getNumDecimalSep()[0];
|
|
SAL_WARN_IF( (sal_Unicode)cDecimalSeparator != rLocaleWrapper.getNumDecimalSep()[0],
|
|
"svx.form", "FormController::setFilter: wrong cast of decimal separator to sal_Char!");
|
|
|
|
// retrieving the filter
|
|
const Sequence < PropertyValue >* pRow = aFilterRows.getConstArray();
|
|
for (sal_Int32 i = 0, nLen = aFilterRows.getLength(); i < nLen; ++i)
|
|
{
|
|
FmFilterRow aRow;
|
|
|
|
// search a field for the given name
|
|
const PropertyValue* pRefValues = pRow[i].getConstArray();
|
|
for (sal_Int32 j = 0, nLen1 = pRow[i].getLength(); j < nLen1; j++)
|
|
{
|
|
// look for the text component
|
|
Reference< XPropertySet > xField;
|
|
try
|
|
{
|
|
Reference< XPropertySet > xSet;
|
|
OUString aRealName;
|
|
|
|
// first look with the given name
|
|
if (xQueryColumns->hasByName(pRefValues[j].Name))
|
|
{
|
|
xQueryColumns->getByName(pRefValues[j].Name) >>= xSet;
|
|
|
|
// get the RealName
|
|
xSet->getPropertyValue("RealName") >>= aRealName;
|
|
|
|
// compare the condition field name and the RealName
|
|
if (aCompare(aRealName, pRefValues[j].Name))
|
|
xField = xSet;
|
|
}
|
|
if (!xField.is())
|
|
{
|
|
// no we have to check every column to find the realname
|
|
Reference< XIndexAccess > xColumnsByIndex(xQueryColumns, UNO_QUERY);
|
|
for (sal_Int32 n = 0, nCount = xColumnsByIndex->getCount(); n < nCount; n++)
|
|
{
|
|
xColumnsByIndex->getByIndex(n) >>= xSet;
|
|
xSet->getPropertyValue("RealName") >>= aRealName;
|
|
if (aCompare(aRealName, pRefValues[j].Name))
|
|
{
|
|
// get the column by its alias
|
|
xField = xSet;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!xField.is())
|
|
continue;
|
|
}
|
|
catch (const Exception&)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// find the text component
|
|
for (::std::vector<FmFieldInfo>::iterator iter = rFieldInfos.begin();
|
|
iter != rFieldInfos.end(); ++iter)
|
|
{
|
|
// we found the field so insert a new entry to the filter row
|
|
if ((*iter).xField == xField)
|
|
{
|
|
// do we already have the control ?
|
|
if (aRow.find((*iter).xText) != aRow.end())
|
|
{
|
|
OUString aCompText = aRow[(*iter).xText];
|
|
aCompText += " ";
|
|
OString aVal = m_xParser->getContext().getIntlKeywordAscii(IParseContext::KEY_AND);
|
|
aCompText += OUString(aVal.getStr(),aVal.getLength(),RTL_TEXTENCODING_ASCII_US);
|
|
aCompText += " ";
|
|
aCompText += ::comphelper::getString(pRefValues[j].Value);
|
|
aRow[(*iter).xText] = aCompText;
|
|
}
|
|
else
|
|
{
|
|
OUString sPredicate,sErrorMsg;
|
|
pRefValues[j].Value >>= sPredicate;
|
|
::rtl::Reference< ISQLParseNode > xParseNode = predicateTree(sErrorMsg, sPredicate, xFormatter, xField);
|
|
if ( xParseNode.is() )
|
|
{
|
|
OUString sCriteria;
|
|
xParseNode->parseNodeToPredicateStr( sCriteria
|
|
,xConnection
|
|
,xFormatter
|
|
,xField
|
|
,OUString()
|
|
,aAppLocale
|
|
,cDecimalSeparator
|
|
,getParseContext());
|
|
aRow[(*iter).xText] = sCriteria;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (aRow.empty())
|
|
continue;
|
|
|
|
impl_addFilterRow( aRow );
|
|
}
|
|
}
|
|
|
|
// now set the filter controls
|
|
for ( ::std::vector<FmFieldInfo>::iterator field = rFieldInfos.begin();
|
|
field != rFieldInfos.end();
|
|
++field
|
|
)
|
|
{
|
|
m_aFilterComponents.push_back( field->xText );
|
|
}
|
|
}
|
|
|
|
|
|
void FormController::startFiltering()
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
|
|
OStaticDataAccessTools aStaticTools;
|
|
Reference< XConnection > xConnection( aStaticTools.getRowSetConnection( Reference< XRowSet >( m_xModelAsIndex, UNO_QUERY ) ) );
|
|
if ( !xConnection.is() )
|
|
// nothing to do - can't filter a form which is not connected
|
|
return;
|
|
|
|
// stop listening for controls
|
|
if (isListeningForChanges())
|
|
stopListening();
|
|
|
|
m_bFiltering = true;
|
|
|
|
// as we don't want new controls to be attached to the scripting environment
|
|
// we change attach flags
|
|
m_bAttachEvents = false;
|
|
|
|
// Austauschen der Kontrols fuer das aktuelle Formular
|
|
Sequence< Reference< XControl > > aControlsCopy( m_aControls );
|
|
const Reference< XControl >* pControls = aControlsCopy.getConstArray();
|
|
sal_Int32 nControlCount = aControlsCopy.getLength();
|
|
|
|
// the control we have to activate after replacement
|
|
Reference< XDatabaseMetaData > xMetaData(xConnection->getMetaData());
|
|
Reference< XNumberFormatsSupplier > xFormatSupplier = aStaticTools.getNumberFormats(xConnection, true);
|
|
Reference< XNumberFormatter > xFormatter = NumberFormatter::create(m_xComponentContext);
|
|
xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
|
|
|
|
// structure for storing the field info
|
|
::std::vector<FmFieldInfo> aFieldInfos;
|
|
|
|
for (sal_Int32 i = nControlCount; i > 0;)
|
|
{
|
|
Reference< XControl > xControl = pControls[--i];
|
|
if (xControl.is())
|
|
{
|
|
// no events for the control anymore
|
|
removeFromEventAttacher(xControl);
|
|
|
|
// do we have a mode selector
|
|
Reference< XModeSelector > xSelector(xControl, UNO_QUERY);
|
|
if (xSelector.is())
|
|
{
|
|
xSelector->setMode( OUString( "FilterMode" ) );
|
|
|
|
// listening for new controls of the selector
|
|
Reference< XContainer > xContainer(xSelector, UNO_QUERY);
|
|
if (xContainer.is())
|
|
xContainer->addContainerListener(this);
|
|
|
|
Reference< XEnumerationAccess > xElementAccess(xSelector, UNO_QUERY);
|
|
if (xElementAccess.is())
|
|
{
|
|
Reference< XEnumeration > xEnumeration(xElementAccess->createEnumeration());
|
|
Reference< XControl > xSubControl;
|
|
while (xEnumeration->hasMoreElements())
|
|
{
|
|
xEnumeration->nextElement() >>= xSubControl;
|
|
if (xSubControl.is())
|
|
{
|
|
Reference< XPropertySet > xSet(xSubControl->getModel(), UNO_QUERY);
|
|
if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
|
|
{
|
|
// does the model use a bound field ?
|
|
Reference< XPropertySet > xField;
|
|
xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
|
|
|
|
Reference< XTextComponent > xText(xSubControl, UNO_QUERY);
|
|
// may we filter the field?
|
|
if (xText.is() && xField.is() && ::comphelper::hasProperty(FM_PROP_SEARCHABLE, xField) &&
|
|
::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_SEARCHABLE)))
|
|
{
|
|
aFieldInfos.push_back(FmFieldInfo(xField, xText));
|
|
xText->addTextListener(this);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
Reference< XPropertySet > xModel( xControl->getModel(), UNO_QUERY );
|
|
if (xModel.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xModel))
|
|
{
|
|
// does the model use a bound field ?
|
|
Any aVal = xModel->getPropertyValue(FM_PROP_BOUNDFIELD);
|
|
Reference< XPropertySet > xField;
|
|
aVal >>= xField;
|
|
|
|
// may we filter the field?
|
|
|
|
if ( xField.is()
|
|
&& ::comphelper::hasProperty( FM_PROP_SEARCHABLE, xField )
|
|
&& ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_SEARCHABLE ) )
|
|
)
|
|
{
|
|
// create a filter control
|
|
Reference< XControl > xFilterControl = form::control::FilterControl::createWithFormat(
|
|
m_xComponentContext,
|
|
VCLUnoHelper::GetInterface( getDialogParentWindow() ),
|
|
xFormatter,
|
|
xModel);
|
|
|
|
if ( replaceControl( xControl, xFilterControl ) )
|
|
{
|
|
Reference< XTextComponent > xFilterText( xFilterControl, UNO_QUERY );
|
|
aFieldInfos.push_back( FmFieldInfo( xField, xFilterText ) );
|
|
xFilterText->addTextListener(this);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// abmelden vom EventManager
|
|
}
|
|
}
|
|
}
|
|
|
|
// we have all filter controls now, so the next step is to read the filters from the form
|
|
// resolve all aliases and set the current filter to the according structure
|
|
setFilter(aFieldInfos);
|
|
|
|
Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
|
|
if ( xSet.is() )
|
|
stopFormListening( xSet, true );
|
|
|
|
impl_setTextOnAllFilter_throw();
|
|
|
|
// lock all controls which are not used for filtering
|
|
m_bLocked = determineLockState();
|
|
setLocks();
|
|
m_bAttachEvents = true;
|
|
}
|
|
|
|
|
|
void FormController::stopFiltering()
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
if ( !m_bFiltering ) // #104693# OJ
|
|
{ // nothing to do
|
|
return;
|
|
}
|
|
|
|
m_bFiltering = false;
|
|
m_bDetachEvents = false;
|
|
|
|
::comphelper::disposeComponent(m_xComposer);
|
|
|
|
// Austauschen der Kontrols fuer das aktuelle Formular
|
|
Sequence< Reference< XControl > > aControlsCopy( m_aControls );
|
|
const Reference< XControl > * pControls = aControlsCopy.getConstArray();
|
|
sal_Int32 nControlCount = aControlsCopy.getLength();
|
|
|
|
// clear the filter control map
|
|
::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), RemoveComponentTextListener( this ) );
|
|
m_aFilterComponents.clear();
|
|
|
|
for ( sal_Int32 i = nControlCount; i > 0; )
|
|
{
|
|
Reference< XControl > xControl = pControls[--i];
|
|
if (xControl.is())
|
|
{
|
|
// now enable eventhandling again
|
|
addToEventAttacher(xControl);
|
|
|
|
Reference< XModeSelector > xSelector(xControl, UNO_QUERY);
|
|
if (xSelector.is())
|
|
{
|
|
xSelector->setMode( OUString( "DataMode" ) );
|
|
|
|
// listening for new controls of the selector
|
|
Reference< XContainer > xContainer(xSelector, UNO_QUERY);
|
|
if (xContainer.is())
|
|
xContainer->removeContainerListener(this);
|
|
continue;
|
|
}
|
|
|
|
Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
|
|
if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
|
|
{
|
|
// does the model use a bound field ?
|
|
Reference< XPropertySet > xField;
|
|
xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
|
|
|
|
// may we filter the field?
|
|
if ( xField.is()
|
|
&& ::comphelper::hasProperty( FM_PROP_SEARCHABLE, xField )
|
|
&& ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_SEARCHABLE ) )
|
|
)
|
|
{
|
|
OUString sServiceName;
|
|
OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DEFAULTCONTROL ) >>= sServiceName );
|
|
Reference< XControl > xNewControl( m_xComponentContext->getServiceManager()->createInstanceWithContext( sServiceName, m_xComponentContext ), UNO_QUERY );
|
|
replaceControl( xControl, xNewControl );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
|
|
if ( xSet.is() )
|
|
startFormListening( xSet, true );
|
|
|
|
m_bDetachEvents = true;
|
|
|
|
m_aFilterRows.clear();
|
|
m_nCurrentFilterPosition = -1;
|
|
|
|
// release the locks if possible
|
|
// lock all controls which are not used for filtering
|
|
m_bLocked = determineLockState();
|
|
setLocks();
|
|
|
|
// restart listening for control modifications
|
|
if (isListeningForChanges())
|
|
startListening();
|
|
}
|
|
|
|
// XModeSelector
|
|
|
|
void FormController::setMode(const OUString& Mode) throw( NoSupportException, RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
if (!supportsMode(Mode))
|
|
throw NoSupportException();
|
|
|
|
if (Mode == m_aMode)
|
|
return;
|
|
|
|
m_aMode = Mode;
|
|
|
|
if ( Mode == "FilterMode" )
|
|
startFiltering();
|
|
else
|
|
stopFiltering();
|
|
|
|
for (FmFormControllers::const_iterator i = m_aChildren.begin();
|
|
i != m_aChildren.end(); ++i)
|
|
{
|
|
Reference< XModeSelector > xMode(*i, UNO_QUERY);
|
|
if ( xMode.is() )
|
|
xMode->setMode(Mode);
|
|
}
|
|
}
|
|
|
|
|
|
OUString SAL_CALL FormController::getMode(void) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
return m_aMode;
|
|
}
|
|
|
|
|
|
Sequence< OUString > SAL_CALL FormController::getSupportedModes(void) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
static Sequence< OUString > aModes;
|
|
if (!aModes.getLength())
|
|
{
|
|
aModes.realloc(2);
|
|
aModes[0] = "DataMode";
|
|
aModes[1] = "FilterMode";
|
|
}
|
|
return aModes;
|
|
}
|
|
|
|
|
|
sal_Bool SAL_CALL FormController::supportsMode(const OUString& Mode) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
Sequence< OUString > aModes(getSupportedModes());
|
|
const OUString* pModes = aModes.getConstArray();
|
|
for (sal_Int32 i = aModes.getLength(); i > 0; )
|
|
{
|
|
if (pModes[--i] == Mode)
|
|
return sal_True;
|
|
}
|
|
return sal_False;
|
|
}
|
|
|
|
|
|
vcl::Window* FormController::getDialogParentWindow()
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
vcl::Window* pParentWindow = NULL;
|
|
try
|
|
{
|
|
Reference< XControl > xContainerControl( getContainer(), UNO_QUERY_THROW );
|
|
Reference< XWindowPeer > xContainerPeer( xContainerControl->getPeer(), UNO_QUERY_THROW );
|
|
pParentWindow = VCLUnoHelper::GetWindow( xContainerPeer );
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
return pParentWindow;
|
|
}
|
|
|
|
bool FormController::checkFormComponentValidity( OUString& /* [out] */ _rFirstInvalidityExplanation, Reference< XControlModel >& /* [out] */ _rxFirstInvalidModel )
|
|
{
|
|
try
|
|
{
|
|
Reference< XEnumerationAccess > xControlEnumAcc( getModel(), UNO_QUERY );
|
|
Reference< XEnumeration > xControlEnumeration;
|
|
if ( xControlEnumAcc.is() )
|
|
xControlEnumeration = xControlEnumAcc->createEnumeration();
|
|
OSL_ENSURE( xControlEnumeration.is(), "FormController::checkFormComponentValidity: cannot enumerate the controls!" );
|
|
if ( !xControlEnumeration.is() )
|
|
// assume all valid
|
|
return true;
|
|
|
|
Reference< XValidatableFormComponent > xValidatable;
|
|
while ( xControlEnumeration->hasMoreElements() )
|
|
{
|
|
if ( !( xControlEnumeration->nextElement() >>= xValidatable ) )
|
|
// control does not support validation
|
|
continue;
|
|
|
|
if ( xValidatable->isValid() )
|
|
continue;
|
|
|
|
Reference< XValidator > xValidator( xValidatable->getValidator() );
|
|
OSL_ENSURE( xValidator.is(), "FormController::checkFormComponentValidity: invalid, but no validator?" );
|
|
if ( !xValidator.is() )
|
|
// this violates the interface definition of css.form.validation.XValidatableFormComponent ...
|
|
continue;
|
|
|
|
_rFirstInvalidityExplanation = xValidator->explainInvalid( xValidatable->getCurrentValue() );
|
|
_rxFirstInvalidModel.set(xValidatable, css::uno::UNO_QUERY);
|
|
return false;
|
|
}
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
Reference< XControl > FormController::locateControl( const Reference< XControlModel >& _rxModel )
|
|
{
|
|
try
|
|
{
|
|
Sequence< Reference< XControl > > aControls( getControls() );
|
|
const Reference< XControl >* pControls = aControls.getConstArray();
|
|
const Reference< XControl >* pControlsEnd = aControls.getConstArray() + aControls.getLength();
|
|
|
|
for ( ; pControls != pControlsEnd; ++pControls )
|
|
{
|
|
OSL_ENSURE( pControls->is(), "FormController::locateControl: NULL-control?" );
|
|
if ( pControls->is() )
|
|
{
|
|
if ( ( *pControls)->getModel() == _rxModel )
|
|
return *pControls;
|
|
}
|
|
}
|
|
OSL_FAIL( "FormController::locateControl: did not find a control for this model!" );
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
namespace
|
|
{
|
|
void displayErrorSetFocus( const OUString& _rMessage, const Reference< XControl >& _rxFocusControl, vcl::Window* _pDialogParent )
|
|
{
|
|
SQLContext aError;
|
|
aError.Message = SVX_RESSTR(RID_STR_WRITEERROR);
|
|
aError.Details = _rMessage;
|
|
displayException( aError, _pDialogParent );
|
|
|
|
if ( _rxFocusControl.is() )
|
|
{
|
|
Reference< XWindow > xControlWindow( _rxFocusControl, UNO_QUERY );
|
|
OSL_ENSURE( xControlWindow.is(), "displayErrorSetFocus: invalid control!" );
|
|
if ( xControlWindow.is() )
|
|
xControlWindow->setFocus();
|
|
}
|
|
}
|
|
|
|
bool lcl_shouldValidateRequiredFields_nothrow( const Reference< XInterface >& _rxForm )
|
|
{
|
|
try
|
|
{
|
|
static const char s_sFormsCheckRequiredFields[] = "FormsCheckRequiredFields";
|
|
|
|
// first, check whether the form has a property telling us the answer
|
|
// this allows people to use the XPropertyContainer interface of a form to control
|
|
// the behaviour on a per-form basis.
|
|
Reference< XPropertySet > xFormProps( _rxForm, UNO_QUERY_THROW );
|
|
Reference< XPropertySetInfo > xPSI( xFormProps->getPropertySetInfo() );
|
|
if ( xPSI->hasPropertyByName( s_sFormsCheckRequiredFields ) )
|
|
{
|
|
bool bShouldValidate = true;
|
|
OSL_VERIFY( xFormProps->getPropertyValue( s_sFormsCheckRequiredFields ) >>= bShouldValidate );
|
|
return bShouldValidate;
|
|
}
|
|
|
|
// next, check the data source which created the connection
|
|
Reference< XChild > xConnectionAsChild( xFormProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ), UNO_QUERY_THROW );
|
|
Reference< XPropertySet > xDataSource( xConnectionAsChild->getParent(), UNO_QUERY );
|
|
if ( !xDataSource.is() )
|
|
// seldom (but possible): this is not a connection created by a data source
|
|
return true;
|
|
|
|
Reference< XPropertySet > xDataSourceSettings(
|
|
xDataSource->getPropertyValue("Settings"),
|
|
UNO_QUERY_THROW );
|
|
|
|
bool bShouldValidate = true;
|
|
OSL_VERIFY( xDataSourceSettings->getPropertyValue( s_sFormsCheckRequiredFields ) >>= bShouldValidate );
|
|
return bShouldValidate;
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// XRowSetApproveListener
|
|
|
|
sal_Bool SAL_CALL FormController::approveRowChange(const RowChangeEvent& _rEvent) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::ClearableMutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
|
|
bool bValid = true;
|
|
if (aIter.hasMoreElements())
|
|
{
|
|
RowChangeEvent aEvt( _rEvent );
|
|
aEvt.Source = *this;
|
|
bValid = static_cast<XRowSetApproveListener*>(aIter.next())->approveRowChange(aEvt);
|
|
}
|
|
|
|
if ( !bValid )
|
|
return bValid;
|
|
|
|
if ( ( _rEvent.Action != RowChangeAction::INSERT )
|
|
&& ( _rEvent.Action != RowChangeAction::UPDATE )
|
|
)
|
|
return bValid;
|
|
|
|
// if some of the control models are bound to validators, check them
|
|
OUString sInvalidityExplanation;
|
|
Reference< XControlModel > xInvalidModel;
|
|
if ( !checkFormComponentValidity( sInvalidityExplanation, xInvalidModel ) )
|
|
{
|
|
Reference< XControl > xControl( locateControl( xInvalidModel ) );
|
|
aGuard.clear();
|
|
displayErrorSetFocus( sInvalidityExplanation, xControl, getDialogParentWindow() );
|
|
return false;
|
|
}
|
|
|
|
// check values on NULL and required flag
|
|
if ( !lcl_shouldValidateRequiredFields_nothrow( _rEvent.Source ) )
|
|
return sal_True;
|
|
|
|
OSL_ENSURE( m_pColumnInfoCache.get(), "FormController::approveRowChange: no column infos!" );
|
|
if ( !m_pColumnInfoCache.get() )
|
|
return sal_True;
|
|
|
|
try
|
|
{
|
|
if ( !m_pColumnInfoCache->controlsInitialized() )
|
|
m_pColumnInfoCache->initializeControls( getControls() );
|
|
|
|
size_t colCount = m_pColumnInfoCache->getColumnCount();
|
|
for ( size_t col = 0; col < colCount; ++col )
|
|
{
|
|
const ColumnInfo& rColInfo = m_pColumnInfoCache->getColumnInfo( col );
|
|
if ( rColInfo.nNullable != ColumnValue::NO_NULLS )
|
|
continue;
|
|
|
|
if ( rColInfo.bAutoIncrement )
|
|
continue;
|
|
|
|
if ( rColInfo.bReadOnly )
|
|
continue;
|
|
|
|
if ( !rColInfo.xFirstControlWithInputRequired.is() && !rColInfo.xFirstGridWithInputRequiredColumn.is() )
|
|
continue;
|
|
|
|
// TODO: in case of binary fields, this "getString" below is extremely expensive
|
|
if ( !rColInfo.xColumn->getString().isEmpty() || !rColInfo.xColumn->wasNull() )
|
|
continue;
|
|
|
|
OUString sMessage( SVX_RESSTR( RID_ERR_FIELDREQUIRED ) );
|
|
sMessage = sMessage.replaceFirst( "#", rColInfo.sName );
|
|
|
|
// the control to focus
|
|
Reference< XControl > xControl( rColInfo.xFirstControlWithInputRequired );
|
|
if ( !xControl.is() )
|
|
xControl.set( rColInfo.xFirstGridWithInputRequiredColumn, UNO_QUERY );
|
|
|
|
aGuard.clear();
|
|
displayErrorSetFocus( sMessage, rColInfo.xFirstControlWithInputRequired, getDialogParentWindow() );
|
|
return sal_False;
|
|
}
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
sal_Bool SAL_CALL FormController::approveCursorMove(const EventObject& event) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
|
|
if (aIter.hasMoreElements())
|
|
{
|
|
EventObject aEvt(event);
|
|
aEvt.Source = *this;
|
|
return static_cast<XRowSetApproveListener*>(aIter.next())->approveCursorMove(aEvt);
|
|
}
|
|
|
|
return sal_True;
|
|
}
|
|
|
|
|
|
sal_Bool SAL_CALL FormController::approveRowSetChange(const EventObject& event) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners);
|
|
if (aIter.hasMoreElements())
|
|
{
|
|
EventObject aEvt(event);
|
|
aEvt.Source = *this;
|
|
return static_cast<XRowSetApproveListener*>(aIter.next())->approveRowSetChange(aEvt);
|
|
}
|
|
|
|
return sal_True;
|
|
}
|
|
|
|
// XRowSetApproveBroadcaster
|
|
|
|
void SAL_CALL FormController::addRowSetApproveListener(const Reference< XRowSetApproveListener > & _rxListener) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
m_aRowSetApproveListeners.addInterface(_rxListener);
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::removeRowSetApproveListener(const Reference< XRowSetApproveListener > & _rxListener) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
m_aRowSetApproveListeners.removeInterface(_rxListener);
|
|
}
|
|
|
|
// XErrorListener
|
|
|
|
void SAL_CALL FormController::errorOccured(const SQLErrorEvent& aEvent) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::ClearableMutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
::cppu::OInterfaceIteratorHelper aIter(m_aErrorListeners);
|
|
if (aIter.hasMoreElements())
|
|
{
|
|
SQLErrorEvent aEvt(aEvent);
|
|
aEvt.Source = *this;
|
|
static_cast<XSQLErrorListener*>(aIter.next())->errorOccured(aEvt);
|
|
}
|
|
else
|
|
{
|
|
aGuard.clear();
|
|
displayException( aEvent );
|
|
}
|
|
}
|
|
|
|
// XErrorBroadcaster
|
|
|
|
void SAL_CALL FormController::addSQLErrorListener(const Reference< XSQLErrorListener > & aListener) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
m_aErrorListeners.addInterface(aListener);
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::removeSQLErrorListener(const Reference< XSQLErrorListener > & aListener) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
m_aErrorListeners.removeInterface(aListener);
|
|
}
|
|
|
|
// XDatabaseParameterBroadcaster2
|
|
|
|
void SAL_CALL FormController::addDatabaseParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
m_aParameterListeners.addInterface(aListener);
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::removeDatabaseParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
m_aParameterListeners.removeInterface(aListener);
|
|
}
|
|
|
|
// XDatabaseParameterBroadcaster
|
|
|
|
void SAL_CALL FormController::addParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException, std::exception )
|
|
{
|
|
FormController::addDatabaseParameterListener( aListener );
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::removeParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException, std::exception )
|
|
{
|
|
FormController::removeDatabaseParameterListener( aListener );
|
|
}
|
|
|
|
// XDatabaseParameterListener
|
|
|
|
sal_Bool SAL_CALL FormController::approveParameter(const DatabaseParameterEvent& aEvent) throw( RuntimeException, std::exception )
|
|
{
|
|
SolarMutexGuard aSolarGuard;
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
::cppu::OInterfaceIteratorHelper aIter(m_aParameterListeners);
|
|
if (aIter.hasMoreElements())
|
|
{
|
|
DatabaseParameterEvent aEvt(aEvent);
|
|
aEvt.Source = *this;
|
|
return static_cast<XDatabaseParameterListener*>(aIter.next())->approveParameter(aEvt);
|
|
}
|
|
else
|
|
{
|
|
// default handling: instantiate an interaction handler and let it handle the parameter request
|
|
try
|
|
{
|
|
if ( !ensureInteractionHandler() )
|
|
return sal_False;
|
|
|
|
// two continuations allowed: OK and Cancel
|
|
OParameterContinuation* pParamValues = new OParameterContinuation;
|
|
OInteractionAbort* pAbort = new OInteractionAbort;
|
|
// the request
|
|
ParametersRequest aRequest;
|
|
aRequest.Parameters = aEvent.Parameters;
|
|
aRequest.Connection = OStaticDataAccessTools().getRowSetConnection(Reference< XRowSet >(aEvent.Source, UNO_QUERY));
|
|
OInteractionRequest* pParamRequest = new OInteractionRequest(makeAny(aRequest));
|
|
Reference< XInteractionRequest > xParamRequest(pParamRequest);
|
|
// some knittings
|
|
pParamRequest->addContinuation(pParamValues);
|
|
pParamRequest->addContinuation(pAbort);
|
|
|
|
// handle the request
|
|
m_xInteractionHandler->handle(xParamRequest);
|
|
|
|
if (!pParamValues->wasSelected())
|
|
// canceled
|
|
return sal_False;
|
|
|
|
// transfer the values into the parameter supplier
|
|
Sequence< PropertyValue > aFinalValues = pParamValues->getValues();
|
|
if (aFinalValues.getLength() != aRequest.Parameters->getCount())
|
|
{
|
|
OSL_FAIL("FormController::approveParameter: the InteractionHandler returned nonsense!");
|
|
return sal_False;
|
|
}
|
|
const PropertyValue* pFinalValues = aFinalValues.getConstArray();
|
|
for (sal_Int32 i=0; i<aFinalValues.getLength(); ++i, ++pFinalValues)
|
|
{
|
|
Reference< XPropertySet > xParam(
|
|
aRequest.Parameters->getByIndex(i), css::uno::UNO_QUERY);
|
|
if (xParam.is())
|
|
{
|
|
#ifdef DBG_UTIL
|
|
OUString sName;
|
|
xParam->getPropertyValue(FM_PROP_NAME) >>= sName;
|
|
DBG_ASSERT(sName.equals(pFinalValues->Name), "FormController::approveParameter: suspicious value names!");
|
|
#endif
|
|
try { xParam->setPropertyValue(FM_PROP_VALUE, pFinalValues->Value); }
|
|
catch(Exception&)
|
|
{
|
|
OSL_FAIL("FormController::approveParameter: setting one of the properties failed!");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch(Exception&)
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
}
|
|
return sal_True;
|
|
}
|
|
|
|
// XConfirmDeleteBroadcaster
|
|
|
|
void SAL_CALL FormController::addConfirmDeleteListener(const Reference< XConfirmDeleteListener > & aListener) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
m_aDeleteListeners.addInterface(aListener);
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::removeConfirmDeleteListener(const Reference< XConfirmDeleteListener > & aListener) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
m_aDeleteListeners.removeInterface(aListener);
|
|
}
|
|
|
|
// XConfirmDeleteListener
|
|
|
|
sal_Bool SAL_CALL FormController::confirmDelete(const RowChangeEvent& aEvent) throw( RuntimeException, std::exception )
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
impl_checkDisposed_throw();
|
|
|
|
::cppu::OInterfaceIteratorHelper aIter(m_aDeleteListeners);
|
|
if (aIter.hasMoreElements())
|
|
{
|
|
RowChangeEvent aEvt(aEvent);
|
|
aEvt.Source = *this;
|
|
return static_cast<XConfirmDeleteListener*>(aIter.next())->confirmDelete(aEvt);
|
|
}
|
|
// default handling: instantiate an interaction handler and let it handle the request
|
|
|
|
OUString sTitle;
|
|
sal_Int32 nLength = aEvent.Rows;
|
|
if ( nLength > 1 )
|
|
{
|
|
sTitle = SVX_RESSTR( RID_STR_DELETECONFIRM_RECORDS );
|
|
sTitle = sTitle.replaceFirst( "#", OUString::number(nLength) );
|
|
}
|
|
else
|
|
sTitle = SVX_RESSTR( RID_STR_DELETECONFIRM_RECORD );
|
|
|
|
try
|
|
{
|
|
if ( !ensureInteractionHandler() )
|
|
return sal_False;
|
|
|
|
// two continuations allowed: Yes and No
|
|
OInteractionApprove* pApprove = new OInteractionApprove;
|
|
OInteractionDisapprove* pDisapprove = new OInteractionDisapprove;
|
|
|
|
// the request
|
|
SQLWarning aWarning;
|
|
aWarning.Message = sTitle;
|
|
SQLWarning aDetails;
|
|
aDetails.Message = SVX_RESSTR(RID_STR_DELETECONFIRM);
|
|
aWarning.NextException <<= aDetails;
|
|
|
|
OInteractionRequest* pRequest = new OInteractionRequest( makeAny( aWarning ) );
|
|
Reference< XInteractionRequest > xRequest( pRequest );
|
|
|
|
// some knittings
|
|
pRequest->addContinuation( pApprove );
|
|
pRequest->addContinuation( pDisapprove );
|
|
|
|
// handle the request
|
|
m_xInteractionHandler->handle( xRequest );
|
|
|
|
if ( pApprove->wasSelected() )
|
|
return sal_True;
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION();
|
|
}
|
|
|
|
return sal_False;
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::invalidateFeatures( const Sequence< ::sal_Int16 >& _Features ) throw (RuntimeException, std::exception)
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
// for now, just copy the ids of the features, because ....
|
|
::std::copy( _Features.getConstArray(), _Features.getConstArray() + _Features.getLength(),
|
|
::std::insert_iterator< ::std::set< sal_Int16 > >( m_aInvalidFeatures, m_aInvalidFeatures.begin() )
|
|
);
|
|
|
|
// ... we will do the real invalidation asynchronously
|
|
if ( !m_aFeatureInvalidationTimer.IsActive() )
|
|
m_aFeatureInvalidationTimer.Start();
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::invalidateAllFeatures( ) throw (RuntimeException, std::exception)
|
|
{
|
|
::osl::ClearableMutexGuard aGuard( m_aMutex );
|
|
|
|
Sequence< sal_Int16 > aInterceptedFeatures( m_aFeatureDispatchers.size() );
|
|
::std::transform(
|
|
m_aFeatureDispatchers.begin(),
|
|
m_aFeatureDispatchers.end(),
|
|
aInterceptedFeatures.getArray(),
|
|
::o3tl::select1st< DispatcherContainer::value_type >()
|
|
);
|
|
|
|
aGuard.clear();
|
|
if ( aInterceptedFeatures.getLength() )
|
|
invalidateFeatures( aInterceptedFeatures );
|
|
}
|
|
|
|
|
|
Reference< XDispatch >
|
|
FormController::interceptedQueryDispatch( const URL& aURL,
|
|
const OUString& /*aTargetFrameName*/, sal_Int32 /*nSearchFlags*/)
|
|
throw( RuntimeException )
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
Reference< XDispatch > xReturn;
|
|
// dispatches handled by ourself
|
|
if ( ( aURL.Complete == FMURL_CONFIRM_DELETION )
|
|
|| ( ( aURL.Complete == "private:/InteractionHandler" )
|
|
&& ensureInteractionHandler()
|
|
)
|
|
)
|
|
xReturn = static_cast< XDispatch* >( this );
|
|
|
|
// dispatches of FormSlot-URLs we have to translate
|
|
if ( !xReturn.is() && m_xFormOperations.is() )
|
|
{
|
|
// find the slot id which corresponds to the URL
|
|
sal_Int32 nFeatureSlotId = ::svx::FeatureSlotTranslation::getControllerFeatureSlotIdForURL( aURL.Main );
|
|
sal_Int16 nFormFeature = ( nFeatureSlotId != -1 ) ? ::svx::FeatureSlotTranslation::getFormFeatureForSlotId( nFeatureSlotId ) : -1;
|
|
if ( nFormFeature > 0 )
|
|
{
|
|
// get the dispatcher for this feature, create if necessary
|
|
DispatcherContainer::const_iterator aDispatcherPos = m_aFeatureDispatchers.find( nFormFeature );
|
|
if ( aDispatcherPos == m_aFeatureDispatchers.end() )
|
|
{
|
|
aDispatcherPos = m_aFeatureDispatchers.insert(
|
|
DispatcherContainer::value_type( nFormFeature, new ::svx::OSingleFeatureDispatcher( aURL, nFormFeature, m_xFormOperations, m_aMutex ) )
|
|
).first;
|
|
}
|
|
|
|
OSL_ENSURE( aDispatcherPos->second.is(), "FormController::interceptedQueryDispatch: should have a dispatcher by now!" );
|
|
return aDispatcherPos->second;
|
|
}
|
|
}
|
|
|
|
// no more to offer
|
|
return xReturn;
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::dispatch( const URL& _rURL, const Sequence< PropertyValue >& _rArgs ) throw (RuntimeException, std::exception)
|
|
{
|
|
if ( _rArgs.getLength() != 1 )
|
|
{
|
|
OSL_FAIL( "FormController::dispatch: no arguments -> no dispatch!" );
|
|
return;
|
|
}
|
|
|
|
if ( _rURL.Complete == "private:/InteractionHandler" )
|
|
{
|
|
Reference< XInteractionRequest > xRequest;
|
|
OSL_VERIFY( _rArgs[0].Value >>= xRequest );
|
|
if ( xRequest.is() )
|
|
handle( xRequest );
|
|
return;
|
|
}
|
|
|
|
if ( _rURL.Complete == FMURL_CONFIRM_DELETION )
|
|
{
|
|
OSL_FAIL( "FormController::dispatch: How do you expect me to return something via this call?" );
|
|
// confirmDelete has a return value - dispatch hasn't
|
|
return;
|
|
}
|
|
|
|
OSL_FAIL( "FormController::dispatch: unknown URL!" );
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::addStatusListener( const Reference< XStatusListener >& _rxListener, const URL& _rURL ) throw (RuntimeException, std::exception)
|
|
{
|
|
if (_rURL.Complete == FMURL_CONFIRM_DELETION)
|
|
{
|
|
if (_rxListener.is())
|
|
{ // send an initial statusChanged event
|
|
FeatureStateEvent aEvent;
|
|
aEvent.FeatureURL = _rURL;
|
|
aEvent.IsEnabled = sal_True;
|
|
_rxListener->statusChanged(aEvent);
|
|
// and don't add the listener at all (the status will never change)
|
|
}
|
|
}
|
|
else
|
|
OSL_FAIL("FormController::addStatusListener: invalid (unsupported) URL!");
|
|
}
|
|
|
|
|
|
Reference< XInterface > SAL_CALL FormController::getParent() throw( RuntimeException, std::exception )
|
|
{
|
|
return m_xParent;
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::setParent( const Reference< XInterface >& Parent) throw( NoSupportException, RuntimeException, std::exception )
|
|
{
|
|
m_xParent = Parent;
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::removeStatusListener( const Reference< XStatusListener >& /*_rxListener*/, const URL& _rURL ) throw (RuntimeException, std::exception)
|
|
{
|
|
(void)_rURL;
|
|
OSL_ENSURE(_rURL.Complete == FMURL_CONFIRM_DELETION, "FormController::removeStatusListener: invalid (unsupported) URL!");
|
|
// we never really added the listener, so we don't need to remove it
|
|
}
|
|
|
|
|
|
Reference< XDispatchProviderInterceptor > FormController::createInterceptor(const Reference< XDispatchProviderInterception > & _xInterception)
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
#ifdef DBG_UTIL
|
|
// check if we already have a interceptor for the given object
|
|
for ( Interceptors::const_iterator aIter = m_aControlDispatchInterceptors.begin();
|
|
aIter != m_aControlDispatchInterceptors.end();
|
|
++aIter
|
|
)
|
|
{
|
|
if ((*aIter)->getIntercepted() == _xInterception)
|
|
OSL_FAIL("FormController::createInterceptor : we already do intercept this objects dispatches !");
|
|
}
|
|
#endif
|
|
|
|
DispatchInterceptionMultiplexer* pInterceptor = new DispatchInterceptionMultiplexer( _xInterception, this );
|
|
pInterceptor->acquire();
|
|
m_aControlDispatchInterceptors.insert( m_aControlDispatchInterceptors.end(), pInterceptor );
|
|
|
|
return pInterceptor;
|
|
}
|
|
|
|
|
|
bool FormController::ensureInteractionHandler()
|
|
{
|
|
if ( m_xInteractionHandler.is() )
|
|
return true;
|
|
if ( m_bAttemptedHandlerCreation )
|
|
return false;
|
|
m_bAttemptedHandlerCreation = true;
|
|
|
|
m_xInteractionHandler = InteractionHandler::createWithParent(m_xComponentContext, 0);
|
|
return m_xInteractionHandler.is();
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::handle( const Reference< XInteractionRequest >& _rRequest ) throw (RuntimeException, std::exception)
|
|
{
|
|
if ( !ensureInteractionHandler() )
|
|
return;
|
|
m_xInteractionHandler->handle( _rRequest );
|
|
}
|
|
|
|
|
|
void FormController::deleteInterceptor(const Reference< XDispatchProviderInterception > & _xInterception)
|
|
{
|
|
OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
|
|
// search the interceptor responsible for the given object
|
|
Interceptors::iterator aIter;
|
|
for ( aIter = m_aControlDispatchInterceptors.begin();
|
|
aIter != m_aControlDispatchInterceptors.end();
|
|
++aIter
|
|
)
|
|
{
|
|
if ((*aIter)->getIntercepted() == _xInterception)
|
|
break;
|
|
}
|
|
if (aIter == m_aControlDispatchInterceptors.end())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// log off the interception from it's interception object
|
|
DispatchInterceptionMultiplexer* pInterceptorImpl = *aIter;
|
|
pInterceptorImpl->dispose();
|
|
pInterceptorImpl->release();
|
|
|
|
// remove the interceptor from our array
|
|
m_aControlDispatchInterceptors.erase(aIter);
|
|
}
|
|
|
|
|
|
void FormController::implInvalidateCurrentControlDependentFeatures()
|
|
{
|
|
Sequence< sal_Int16 > aCurrentControlDependentFeatures(4);
|
|
|
|
aCurrentControlDependentFeatures[0] = FormFeature::SortAscending;
|
|
aCurrentControlDependentFeatures[1] = FormFeature::SortDescending;
|
|
aCurrentControlDependentFeatures[2] = FormFeature::AutoFilter;
|
|
aCurrentControlDependentFeatures[3] = FormFeature::RefreshCurrentControl;
|
|
|
|
invalidateFeatures( aCurrentControlDependentFeatures );
|
|
}
|
|
|
|
|
|
void SAL_CALL FormController::columnChanged( const EventObject& /*_event*/ ) throw (RuntimeException, std::exception)
|
|
{
|
|
implInvalidateCurrentControlDependentFeatures();
|
|
}
|
|
|
|
} // namespace svxform
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|