diff options
Diffstat (limited to 'forms/source/xforms/binding.cxx')
-rw-r--r-- | forms/source/xforms/binding.cxx | 183 |
1 files changed, 96 insertions, 87 deletions
diff --git a/forms/source/xforms/binding.cxx b/forms/source/xforms/binding.cxx index 6d8735f6366c..c739126642c4 100644 --- a/forms/source/xforms/binding.cxx +++ b/forms/source/xforms/binding.cxx @@ -31,9 +31,10 @@ #include <strings.hrc> #include <rtl/ustrbuf.hxx> +#include <o3tl/safeint.hxx> #include <osl/diagnose.h> -#include <tools/diagnose_ex.h> +#include <comphelper/diagnose_ex.hxx> #include <algorithm> #include <functional> @@ -70,7 +71,6 @@ using com::sun::star::form::binding::InvalidBindingStateException; using com::sun::star::form::binding::XValueBinding; using com::sun::star::lang::EventObject; using com::sun::star::lang::IndexOutOfBoundsException; -using com::sun::star::lang::XUnoTunnel; using com::sun::star::uno::Any; using com::sun::star::uno::Reference; using com::sun::star::uno::RuntimeException; @@ -79,7 +79,6 @@ using com::sun::star::uno::UNO_QUERY; using com::sun::star::uno::UNO_QUERY_THROW; using com::sun::star::uno::XInterface; using com::sun::star::uno::Exception; -using com::sun::star::uno::makeAny; using com::sun::star::util::XModifyListener; using com::sun::star::xforms::XDataTypeRepository; using com::sun::star::xml::dom::NodeType_ATTRIBUTE_NODE; @@ -90,9 +89,6 @@ using com::sun::star::xml::dom::events::XEventListener; using com::sun::star::xml::dom::events::XEventTarget; using com::sun::star::xsd::XDataType; - -#define EXCEPT(msg) msg,static_cast<XValueBinding*>(this) - #define HANDLE_BindingID 0 #define HANDLE_BindingExpression 1 #define HANDLE_Model 2 @@ -125,7 +121,7 @@ Binding::~Binding() _setModel(nullptr); } -void Binding::_setModel( const css::uno::Reference<css::xforms::XModel>& xModel ) +void Binding::_setModel( const rtl::Reference<Model>& xModel ) { PropertyChangeNotifier aNotifyModelChange( *this, HANDLE_Model ); PropertyChangeNotifier aNotifyModelIDChange( *this, HANDLE_ModelID ); @@ -146,8 +142,7 @@ void Binding::_setModel( const css::uno::Reference<css::xforms::XModel>& xModel OUString Binding::getModelID() const { - Model* pModel = getModelImpl(); - return ( pModel == nullptr ) ? OUString() : pModel->getID(); + return ( mxModel == nullptr ) ? OUString() : mxModel->getID(); } @@ -211,7 +206,14 @@ bool Binding::isValid() const { // TODO: determine whether node is suitable, not just whether it exists return maBindingExpression.getNode().is() && - isValid_DataType() && + ( + // tdf#155121, validity rules should be apply when field is required or + // when the field is not required but not empty + // so if the field is not required and empty, do not check validity + (! maMIP.isRequired() && maBindingExpression.hasValue() + && maBindingExpression.getString().isEmpty() ) || + isValid_DataType() + ) && maMIP.isConstraint() && ( ! maMIP.isRequired() || ( maBindingExpression.hasValue() && @@ -228,7 +230,7 @@ bool Binding::isUseful() const // 3) we are bound to some control // (this can be assumed if some listeners are set) bool bUseful = - getModelImpl() == nullptr + mxModel == nullptr // || msBindingID.getLength() > 0 || ! msTypeName.isEmpty() || ! maReadonly.isEmptyExpression() @@ -282,15 +284,15 @@ OUString Binding::explainInvalid() EvaluationContext Binding::getEvaluationContext() const { - OSL_ENSURE( getModelImpl() != nullptr, "need model impl" ); - EvaluationContext aContext = getModelImpl()->getEvaluationContext(); + OSL_ENSURE( mxModel != nullptr, "need model impl" ); + EvaluationContext aContext = mxModel->getEvaluationContext(); aContext.mxNamespaces = getBindingNamespaces(); return aContext; } ::std::vector<EvaluationContext> Binding::getMIPEvaluationContexts() { - OSL_ENSURE( getModelImpl() != nullptr, "need model impl" ); + OSL_ENSURE( mxModel != nullptr, "need model impl" ); // bind (in case we were not bound before) bind(); @@ -422,9 +424,8 @@ bool Binding::getExternalData() const try { - Reference< XPropertySet > xModelProps( mxModel, UNO_QUERY_THROW ); OSL_VERIFY( - xModelProps->getPropertyValue( "ExternalData" ) >>= bExternalData ); + mxModel->getPropertyValue( "ExternalData" ) >>= bExternalData ); } catch( const Exception& ) { @@ -437,19 +438,14 @@ bool Binding::getExternalData() const void Binding::checkLive() { if( ! isLive() ) - throw RuntimeException( EXCEPT("Binding not initialized") ); + throw RuntimeException("Binding not initialized", static_cast<XValueBinding*>(this)); } bool Binding::isLive() const { - const Model* pModel = getModelImpl(); - return pModel && pModel->isInitialized(); + return mxModel && mxModel->isInitialized(); } -Model* Binding::getModelImpl() const -{ - return comphelper::getFromUnoTunnel<Model>( mxModel ); -} static void lcl_addListenerToNode( const Reference<XNode>& xNode, const Reference<XEventListener>& xListener ) @@ -466,8 +462,6 @@ static void lcl_addListenerToNode( const Reference<XNode>& xNode, xListener, false ); xTarget->addEventListener( "DOMAttrModified", xListener, true ); - xTarget->addEventListener( "DOMAttrModified", - xListener, true ); xTarget->addEventListener( "xforms-generic", xListener, true ); } @@ -493,7 +487,7 @@ static void lcl_removeListenerFromNode( const Reference<XNode>& xNode, ::std::vector<EvaluationContext> Binding::_getMIPEvaluationContexts() const { - OSL_ENSURE( getModelImpl() != nullptr, "need model impl" ); + OSL_ENSURE( mxModel != nullptr, "need model impl" ); // iterate over nodes of bind expression and create // EvaluationContext for each @@ -504,7 +498,7 @@ static void lcl_removeListenerFromNode( const Reference<XNode>& xNode, OSL_ENSURE( node.is(), "no node?" ); // create proper evaluation context for this MIP - aVector.emplace_back( node, getModel(), getBindingNamespaces() ); + aVector.emplace_back( node, mxModel, getBindingNamespaces() ); } return aVector; } @@ -512,7 +506,7 @@ static void lcl_removeListenerFromNode( const Reference<XNode>& xNode, void Binding::bind( bool bForceRebind ) { if( ! mxModel.is() ) - throw RuntimeException( EXCEPT("Binding has no Model") ); + throw RuntimeException("Binding has no Model", static_cast<XValueBinding*>(this)); // bind() will evaluate this binding as follows: // 1) evaluate the binding expression @@ -561,9 +555,8 @@ void Binding::bind( bool bForceRebind ) } // 3) remove old MIPs defined by this binding - Model* pModel = getModelImpl(); - OSL_ENSURE( pModel != nullptr, "need model" ); - pModel->removeMIPs( this ); + OSL_ENSURE( mxModel != nullptr, "need model" ); + mxModel->removeMIPs( this ); // 4) calculate all MIPs ::std::vector<EvaluationContext> aMIPContexts = _getMIPEvaluationContexts(); @@ -579,7 +572,7 @@ void Binding::bind( bool bForceRebind ) { mbInCalculate = true; maCalculate.evaluate( rContext ); - pModel->setSimpleContent( rContext.mxContextNode, + mxModel->setSimpleContent( rContext.mxContextNode, maCalculate.getString() ); mbInCalculate = false; } @@ -593,7 +586,7 @@ void Binding::bind( bool bForceRebind ) // type is static; does not need updating // evaluate the locally defined MIPs, and push them to the model - pModel->addMIP( this, rContext.mxContextNode, getLocalMIP() ); + mxModel->addMIP( this, rContext.mxContextNode, getLocalMIP() ); } } @@ -636,7 +629,7 @@ void Binding::valueModified() // query MIP used by our first node (also note validity) Reference<XNode> xNode = maBindingExpression.getNode(); - maMIP = getModelImpl()->queryMIP( xNode ); + maMIP = mxModel->queryMIP( xNode ); // distribute MIPs _used_ by this binding if( xNode.is() ) @@ -737,11 +730,11 @@ MIP Binding::getLocalMIP() const css::uno::Reference<css::xsd::XDataType> Binding::getDataType() const { - OSL_ENSURE( getModel().is(), "need model" ); - OSL_ENSURE( getModel()->getDataTypeRepository().is(), "need types" ); + OSL_ENSURE( mxModel.is(), "need model" ); + OSL_ENSURE( mxModel->getDataTypeRepository().is(), "need types" ); Reference<XDataTypeRepository> xRepository = - getModel()->getDataTypeRepository(); + mxModel->getDataTypeRepository(); OUString sTypeName = maMIP.getTypeName(); return ( xRepository.is() && xRepository->hasByName( sTypeName ) ) @@ -767,9 +760,8 @@ OUString Binding::explainInvalid_DataType() void Binding::clear() { // remove MIPs contributed by this binding - Model* pModel = getModelImpl(); - if( pModel != nullptr ) - pModel->removeMIPs( this ); + if( mxModel != nullptr ) + mxModel->removeMIPs( this ); // remove all references for (auto const& eventNode : maEventNodes) @@ -858,9 +850,8 @@ css::uno::Reference<css::container::XNameContainer> Binding::_getNamespaces() co lcl_copyNamespaces( mxNamespaces, xNamespaces, true ); // merge model's with binding's own namespaces - Model* pModel = getModelImpl(); - if( pModel != nullptr ) - lcl_copyNamespaces( pModel->getNamespaces(), xNamespaces, false ); + if( mxModel != nullptr ) + lcl_copyNamespaces( mxModel->getNamespaces(), xNamespaces, false ); return xNamespaces; } @@ -870,11 +861,10 @@ css::uno::Reference<css::container::XNameContainer> Binding::_getNamespaces() co void Binding::_setNamespaces( const css::uno::Reference<css::container::XNameContainer>& rNamespaces, bool bBinding ) { - Model* pModel = getModelImpl(); - css::uno::Reference<css::container::XNameContainer> xModelNamespaces = ( pModel != nullptr ) - ? pModel->getNamespaces() + css::uno::Reference<css::container::XNameContainer> xModelNamespaces = ( mxModel != nullptr ) + ? mxModel->getNamespaces() : nullptr; - OSL_ENSURE( ( pModel != nullptr ) == xModelNamespaces.is(), "no model nmsp?"); + OSL_ENSURE( ( mxModel != nullptr ) == xModelNamespaces.is(), "no model nmsp?"); // remove deleted namespaces lcl_removeOtherNamespaces( rNamespaces, mxNamespaces ); @@ -923,10 +913,10 @@ void Binding::_setNamespaces( const css::uno::Reference<css::container::XNameCon void Binding::_checkBindingID() { - if( !getModel().is() ) + if( !mxModel.is() ) return; - Reference<XNameAccess> xBindings( getModel()->getBindings(), UNO_QUERY_THROW ); + Reference<XNameAccess> xBindings( mxModel->getBindings(), UNO_QUERY_THROW ); if( !msBindingID.isEmpty() ) return; @@ -964,7 +954,7 @@ css::uno::Any Binding::getValue( const css::uno::Type& rType ) // second, check for type if( ! supportsType( rType ) ) - throw IncompatibleTypesException( EXCEPT( "type unsupported" ) ); + throw IncompatibleTypesException("type unsupported", static_cast<XValueBinding*>(this)); // return string value (if present; else return empty Any) css::uno::Any result; @@ -984,19 +974,19 @@ void Binding::setValue( const css::uno::Any& aValue ) // check for supported type if( ! supportsType( aValue.getValueType() ) ) - throw IncompatibleTypesException( EXCEPT( "type unsupported" ) ); + throw IncompatibleTypesException("type unsupported", static_cast<XValueBinding*>(this)); if( !maBindingExpression.hasValue() ) - throw InvalidBindingStateException( EXCEPT( "no suitable node found" ) ); + throw InvalidBindingStateException("no suitable node found", static_cast<XValueBinding*>(this)); css::uno::Reference<css::xml::dom::XNode> xNode = maBindingExpression.getNode(); if( !xNode.is() ) - throw InvalidBindingStateException( EXCEPT( "no suitable node found" ) ); + throw InvalidBindingStateException("no suitable node found", static_cast<XValueBinding*>(this)); OUString sValue = Convert::get().toXSD( aValue ); - bool bSuccess = getModelImpl()->setSimpleContent( xNode, sValue ); + bool bSuccess = mxModel->setSimpleContent( xNode, sValue ); if( ! bSuccess ) - throw InvalidBindingStateException( EXCEPT( "can't set value" ) ); + throw InvalidBindingStateException("can't set value", static_cast<XValueBinding*>(this)); } @@ -1046,8 +1036,8 @@ OUString Binding::getListEntry( sal_Int32 nPosition ) // check bounds and return proper item PathExpression::NodeVector_t aNodes = maBindingExpression.getNodeList(); - if( nPosition < 0 || nPosition >= static_cast<sal_Int32>( aNodes.size() ) ) - throw IndexOutOfBoundsException( EXCEPT("") ); + if( nPosition < 0 || o3tl::make_unsigned(nPosition) >= aNodes.size() ) + throw IndexOutOfBoundsException("", static_cast<XValueBinding*>(this)); return lcl_getString( aNodes[ nPosition ] ); } @@ -1177,9 +1167,8 @@ css::uno::Reference<css::util::XCloneable> SAL_CALL Binding::createClone() { Reference< XPropertySet > xClone; - Model* pModel = getModelImpl(); - if ( pModel ) - xClone = pModel->cloneBinding( this ); + if ( mxModel ) + xClone = mxModel->cloneBinding( this ); else { xClone = new Binding; @@ -1188,39 +1177,59 @@ css::uno::Reference<css::util::XCloneable> SAL_CALL Binding::createClone() return css::uno::Reference<css::util::XCloneable>( xClone, UNO_QUERY ); } +css::uno::Reference<css::xforms::XModel> Binding::getModel() const +{ + return mxModel; +} // property set implementations +void Binding::initializePropertySet() +{ + registerProperty( css::beans::Property("BindingID", HANDLE_BindingID, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND ), + new DirectPropertyAccessor< Binding, OUString >(this, &Binding::setBindingID, &Binding::getBindingID)); -#define REGISTER_PROPERTY( property, type ) \ - registerProperty( PROPERTY( property, type ), \ - new DirectPropertyAccessor< Binding, type >( this, &Binding::set##property, &Binding::get##property ) ); + registerProperty( css::beans::Property("BindingExpression", HANDLE_BindingExpression, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND ), + new DirectPropertyAccessor< Binding, OUString >(this, &Binding::setBindingExpression, &Binding::getBindingExpression)); -#define REGISTER_PROPERTY_RO( property, type ) \ - registerProperty( PROPERTY_RO( property, type ), \ - new DirectPropertyAccessor< Binding, type >( this, nullptr, &Binding::get##property ) ); + registerProperty( css::beans::Property("Model", HANDLE_Model, cppu::UnoType<css::uno::Reference<css::xforms::XModel>>::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ), + new DirectPropertyAccessor< Binding, css::uno::Reference<css::xforms::XModel> >(this, nullptr, &Binding::getModel)); -#define REGISTER_BOOL_PROPERTY_RO( property ) \ - registerProperty( PROPERTY_RO( property, sal_Bool ), \ - new BooleanPropertyAccessor< Binding >( this, nullptr, &Binding::get##property ) ); + registerProperty( css::beans::Property("BindingNamespaces", HANDLE_BindingNamespaces, cppu::UnoType<css::uno::Reference<css::container::XNameContainer>>::get(), css::beans::PropertyAttribute::BOUND ), + new DirectPropertyAccessor< Binding, css::uno::Reference<css::container::XNameContainer> >(this, &Binding::setBindingNamespaces, &Binding::getBindingNamespaces)); -void Binding::initializePropertySet() -{ - REGISTER_PROPERTY ( BindingID, OUString ); - REGISTER_PROPERTY ( BindingExpression, OUString ); - REGISTER_PROPERTY_RO ( Model, css::uno::Reference<css::xforms::XModel> ); - REGISTER_PROPERTY ( BindingNamespaces, css::uno::Reference<css::container::XNameContainer> ); - REGISTER_PROPERTY ( ModelNamespaces, css::uno::Reference<css::container::XNameContainer> ); - REGISTER_PROPERTY_RO ( ModelID, OUString ); - REGISTER_PROPERTY ( ReadonlyExpression, OUString ); - REGISTER_PROPERTY ( RelevantExpression, OUString ); - REGISTER_PROPERTY ( RequiredExpression, OUString ); - REGISTER_PROPERTY ( ConstraintExpression, OUString ); - REGISTER_PROPERTY ( CalculateExpression, OUString ); - REGISTER_PROPERTY ( Type, OUString ); - REGISTER_PROPERTY_RO ( ReadOnly, bool ); - REGISTER_PROPERTY_RO ( Relevant, bool ); - REGISTER_BOOL_PROPERTY_RO( ExternalData ); + registerProperty( css::beans::Property("ModelNamespaces", HANDLE_ModelNamespaces, cppu::UnoType<css::uno::Reference<css::container::XNameContainer>>::get(), css::beans::PropertyAttribute::BOUND ), + new DirectPropertyAccessor< Binding, css::uno::Reference<css::container::XNameContainer> >(this, &Binding::setModelNamespaces, &Binding::getModelNamespaces)); + + registerProperty( css::beans::Property("ModelID", HANDLE_ModelID, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ), + new DirectPropertyAccessor< Binding, OUString >(this, nullptr, &Binding::getModelID)); + + registerProperty( css::beans::Property("ReadonlyExpression", HANDLE_ReadonlyExpression, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND ), + new DirectPropertyAccessor< Binding, OUString >(this, &Binding::setReadonlyExpression, &Binding::getReadonlyExpression)); + + registerProperty( css::beans::Property("RelevantExpression", HANDLE_RelevantExpression, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND ), + new DirectPropertyAccessor< Binding, OUString >(this, &Binding::setRelevantExpression, &Binding::getRelevantExpression)); + + registerProperty( css::beans::Property("RequiredExpression", HANDLE_RequiredExpression, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND ), + new DirectPropertyAccessor< Binding, OUString >(this, &Binding::setRequiredExpression, &Binding::getRequiredExpression)); + + registerProperty( css::beans::Property("ConstraintExpression", HANDLE_ConstraintExpression, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND ), + new DirectPropertyAccessor< Binding, OUString >(this, &Binding::setConstraintExpression, &Binding::getConstraintExpression)); + + registerProperty( css::beans::Property("CalculateExpression", HANDLE_CalculateExpression, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND ), + new DirectPropertyAccessor< Binding, OUString >(this, &Binding::setCalculateExpression, &Binding::getCalculateExpression)); + + registerProperty( css::beans::Property("Type", HANDLE_Type, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND ), + new DirectPropertyAccessor< Binding, OUString >(this, &Binding::setType, &Binding::getType)); + + registerProperty( css::beans::Property("ReadOnly", HANDLE_ReadOnly, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ), + new DirectPropertyAccessor< Binding, bool >(this, nullptr, &Binding::getReadOnly)); + + registerProperty( css::beans::Property("Relevant", HANDLE_Relevant, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ), + new DirectPropertyAccessor< Binding, bool >(this, nullptr, &Binding::getRelevant)); + + registerProperty( css::beans::Property("ExternalData", HANDLE_ExternalData, cppu::UnoType<sal_Bool>::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ), + new BooleanPropertyAccessor< Binding >(this, nullptr, &Binding::getExternalData)); initializePropertyValueCache( HANDLE_ReadOnly ); initializePropertyValueCache( HANDLE_Relevant ); @@ -1260,7 +1269,7 @@ void SAL_CALL Binding::setName( const OUString& rName ) { // use the XPropertySet methods, so the change in the name is notified to the // property listeners - setFastPropertyValue( HANDLE_BindingID, makeAny( rName ) ); + setFastPropertyValue( HANDLE_BindingID, Any( rName ) ); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |