diff options
Diffstat (limited to 'forms/source/xforms')
62 files changed, 13555 insertions, 0 deletions
diff --git a/forms/source/xforms/NameContainer.hxx b/forms/source/xforms/NameContainer.hxx new file mode 100644 index 000000000000..3cab033f605e --- /dev/null +++ b/forms/source/xforms/NameContainer.hxx @@ -0,0 +1,221 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _NAMECONTAINER_HXX +#define _NAMECONTAINER_HXX + +#include <cppuhelper/implbase1.hxx> +#include <map> + +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/container/NoSuchElementException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/WrappedTargetException.hpp> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/uno/Type.hxx> + +typedef cppu::WeakImplHelper1< + com::sun::star::container::XNameContainer +> NameContainer_t; + +template<class T> +class NameContainer : public NameContainer_t +{ +protected: + typedef std::map<rtl::OUString,T> map_t; + map_t maItems; + + + bool hasItems() + { + return ! maItems.empty(); + } + + typename map_t::const_iterator findItem( const rtl::OUString& rName ) + { + return maItems.find( rName ); + } + + bool hasItem( const rtl::OUString& rName ) + { + return findItem( rName ) != maItems.end(); + } + + T getItem( const rtl::OUString& rName ) + { + OSL_ENSURE( hasItem( rName ), "can't get non-existant item" ); + return maItems[ rName ]; + } + + + void replace( const rtl::OUString& rName, + const T& aElement ) + { + OSL_ENSURE( hasItem( rName ), "unknown item" ); + maItems[ rName ] = aElement; + } + + void insert( const rtl::OUString& rName, + const T& aElement ) + { + OSL_ENSURE( ! hasItem( rName ), "item already in set" ); + maItems[ rName ] = aElement; + } + + void remove( const rtl::OUString& rName ) + { + OSL_ENSURE( hasItem( rName ), "item not in set" ); + maItems.erase( rName ); + } + + +public: + + NameContainer() {} + virtual ~NameContainer() {} + + // + // methods for XElementAccess + // + + virtual com::sun::star::uno::Type SAL_CALL getElementType() + throw( com::sun::star::uno::RuntimeException ) + { + return getCppuType( static_cast<T*>( NULL ) ); + } + + virtual sal_Bool SAL_CALL hasElements() + throw( com::sun::star::uno::RuntimeException ) + { + return hasItems(); + } + + + // + // methods for XNameAccess (inherits XElementAccess) + // + + virtual com::sun::star::uno::Any SAL_CALL getByName( + const rtl::OUString& rName ) + throw( com::sun::star::container::NoSuchElementException, + com::sun::star::lang::WrappedTargetException, + com::sun::star::uno::RuntimeException ) + { + typename map_t::const_iterator aIter = findItem( rName ); + if( aIter == maItems.end() ) + throw com::sun::star::container::NoSuchElementException(); + else + return com::sun::star::uno::makeAny( aIter->second ); + } + + virtual com::sun::star::uno::Sequence<rtl::OUString> SAL_CALL getElementNames() + throw( com::sun::star::uno::RuntimeException ) + { + com::sun::star::uno::Sequence<rtl::OUString> aSequence( maItems.size() ); + typename map_t::const_iterator aIter = maItems.begin(); + rtl::OUString* pStrings = aSequence.getArray(); + while( aIter != maItems.end() ) + { + *pStrings = aIter->first; + ++aIter; + ++pStrings; + } + OSL_ENSURE( pStrings == aSequence.getArray() + aSequence.getLength(), + "sequence not of right size; possible buffer overflow" ); + return aSequence; + } + + virtual sal_Bool SAL_CALL hasByName( + const rtl::OUString& rName ) + throw( com::sun::star::uno::RuntimeException ) + { + return hasItem( rName ); + } + + + // + // methods for XNameReplace (inherits XNameAccess) + // + + virtual void SAL_CALL replaceByName( + const rtl::OUString& rName, + const com::sun::star::uno::Any& aElement ) + throw( com::sun::star::lang::IllegalArgumentException, + com::sun::star::container::NoSuchElementException, + com::sun::star::lang::WrappedTargetException, + com::sun::star::uno::RuntimeException) + { + T aItem; + if( aElement >>= aItem ) + if( hasByName( rName ) ) + replace( rName, aItem ); + else + throw com::sun::star::container::NoSuchElementException(); + else + throw com::sun::star::lang::IllegalArgumentException(); + } + + + // + // methods for XNameContainer (inherits XNameReplace) + // + + virtual void SAL_CALL insertByName( + const rtl::OUString& rName, + const com::sun::star::uno::Any& aElement ) + throw( com::sun::star::lang::IllegalArgumentException, + com::sun::star::container::ElementExistException, + com::sun::star::lang::WrappedTargetException, + com::sun::star::uno::RuntimeException ) + { + T aItem; + if( aElement >>= aItem ) + if( ! hasByName( rName ) ) + insert( rName, aItem ); + else + throw com::sun::star::container::ElementExistException(); + else + throw com::sun::star::lang::IllegalArgumentException(); + } + + virtual void SAL_CALL removeByName( + const rtl::OUString& rName ) + throw( com::sun::star::container::NoSuchElementException, + com::sun::star::lang::WrappedTargetException, + com::sun::star::uno::RuntimeException) + { + if( hasByName( rName ) ) + remove( rName ); + else + throw com::sun::star::container::NoSuchElementException(); + } + +}; + +#endif diff --git a/forms/source/xforms/binding.cxx b/forms/source/xforms/binding.cxx new file mode 100644 index 000000000000..3df2385796f0 --- /dev/null +++ b/forms/source/xforms/binding.cxx @@ -0,0 +1,1409 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include "binding.hxx" + +#include "model.hxx" +#include "unohelper.hxx" +#include "NameContainer.hxx" +#include "evaluationcontext.hxx" +#include "convert.hxx" +#include "resourcehelper.hxx" +#include "xmlhelper.hxx" +#include "xformsevent.hxx" + +#include <rtl/ustrbuf.hxx> +#include <osl/diagnose.h> + +#include <tools/diagnose_ex.h> + +#include <algorithm> +#include <functional> + +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/xml/dom/XNodeList.hpp> +#include <com/sun/star/xml/dom/XNode.hpp> +#include <com/sun/star/xml/dom/XDocument.hpp> +#include <com/sun/star/xml/dom/XElement.hpp> +#include <com/sun/star/xml/dom/NodeType.hpp> +#include <com/sun/star/xml/dom/events/XEventTarget.hpp> +#include <com/sun/star/xml/dom/events/XEventListener.hpp> +#include <com/sun/star/xml/dom/events/XDocumentEvent.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/container/XSet.hpp> +#include <com/sun/star/container/XNameContainer.hpp> + +#include <comphelper/propertysetinfo.hxx> +#include <unotools/textsearch.hxx> +#include <cppuhelper/typeprovider.hxx> + +using namespace com::sun::star::xml::xpath; +using namespace com::sun::star::xml::dom::events; + +using rtl::OUString; +using rtl::OUStringBuffer; +using std::vector; +using xforms::Binding; +using xforms::MIP; +using xforms::Model; +using xforms::getResource; +using xforms::EvaluationContext; +using com::sun::star::beans::PropertyVetoException; +using com::sun::star::beans::UnknownPropertyException; +using com::sun::star::beans::XPropertySet; +using com::sun::star::container::XSet; +using com::sun::star::container::XNameAccess; +using com::sun::star::form::binding::IncompatibleTypesException; +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::IllegalArgumentException; +using com::sun::star::lang::IndexOutOfBoundsException; +using com::sun::star::lang::NoSupportException; +using com::sun::star::lang::NullPointerException; +using com::sun::star::lang::WrappedTargetException; +using com::sun::star::lang::XUnoTunnel; +using com::sun::star::uno::Any; +using com::sun::star::uno::Reference; +using com::sun::star::uno::RuntimeException; +using com::sun::star::uno::Sequence; +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; +using com::sun::star::xml::dom::NodeType_TEXT_NODE; +using com::sun::star::xml::dom::XNode; +using com::sun::star::xml::dom::XNodeList; +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) OUSTRING(msg),static_cast<XValueBinding*>(this) + +#define HANDLE_BindingID 0 +#define HANDLE_BindingExpression 1 +#define HANDLE_Model 2 +#define HANDLE_ModelID 3 +#define HANDLE_BindingNamespaces 4 +#define HANDLE_ReadonlyExpression 5 +#define HANDLE_RelevantExpression 6 +#define HANDLE_RequiredExpression 7 +#define HANDLE_ConstraintExpression 8 +#define HANDLE_CalculateExpression 9 +#define HANDLE_Type 10 +#define HANDLE_ReadOnly 11 // from com.sun.star.form.binding.ValueBinding, for interaction with a bound form control +#define HANDLE_Relevant 12 // from com.sun.star.form.binding.ValueBinding, for interaction with a bound form control +#define HANDLE_ModelNamespaces 13 +#define HANDLE_ExternalData 14 + + +Binding::Binding() : + mxModel(), + msBindingID(), + maBindingExpression(), + maReadonly(), + mxNamespaces( new NameContainer<OUString>() ), + mbInCalculate( false ), + mnDeferModifyNotifications( 0 ), + mbValueModified( false ), + mbBindingModified( false ) + +{ + initializePropertySet(); +} + +Binding::~Binding() throw() +{ + _setModel(NULL); +} + + +Binding::Model_t Binding::getModel() const +{ + return mxModel; +} + +void Binding::_setModel( const Model_t& xModel ) +{ + PropertyChangeNotifier aNotifyModelChange( *this, HANDLE_Model ); + PropertyChangeNotifier aNotifyModelIDChange( *this, HANDLE_ModelID ); + + // prepare binding for removal of old model + clear(); // remove all cached data (e.g. XPath evaluation results) + XNameContainer_t xNamespaces = getModelNamespaces(); // save namespaces + + mxModel = xModel; + + // set namespaces (and move to model, if appropriate) + setBindingNamespaces( xNamespaces ); + _checkBindingID(); + + notifyAndCachePropertyValue( HANDLE_ExternalData ); +} + + +OUString Binding::getModelID() const +{ + Model* pModel = getModelImpl(); + return ( pModel == NULL ) ? OUString() : pModel->getID(); +} + + +Binding::XNodeList_t Binding::getXNodeList() +{ + // first make sure we are bound + if( ! maBindingExpression.hasValue() ) + bind( sal_False ); + + return maBindingExpression.getXNodeList(); +} + +bool Binding::isSimpleBinding() const +{ + return maBindingExpression.isSimpleExpression() + && maReadonly.isSimpleExpression() + && maRelevant.isSimpleExpression() + && maRequired.isSimpleExpression() + && maConstraint.isSimpleExpression() + && maCalculate.isSimpleExpression(); +} + +bool Binding::isSimpleBindingExpression() const +{ + return maBindingExpression.isSimpleExpression(); +} + +void Binding::update() +{ + // clear all expressions (to remove cached node references) + maBindingExpression.clear(); + maReadonly.clear(); + maRelevant.clear(); + maRequired.clear(); + maConstraint.clear(); + maCalculate.clear(); + + // let's just pretend the binding has been modified -> full rebind() + bindingModified(); +} + +void Binding::deferNotifications( bool bDefer ) +{ + mnDeferModifyNotifications += ( bDefer ? 1 : -1 ); + OSL_ENSURE( mnDeferModifyNotifications >= 0, "you're deferring too much" ); + + if( mnDeferModifyNotifications == 0 ) + { + if( mbBindingModified ) + bindingModified(); + if( mbValueModified ) + valueModified(); + } + + OSL_ENSURE( ( mnDeferModifyNotifications > 0 ) + || ( ! mbBindingModified && ! mbValueModified ), + "deferred modifications not delivered?" ); +} + +bool Binding::isValid() +{ + // TODO: determine whether node is suitable, not just whether it exists + return maBindingExpression.getNode().is() && + isValid_DataType() && + maMIP.isConstraint() && + ( ! maMIP.isRequired() || + ( maBindingExpression.hasValue() && + maBindingExpression.getString().getLength() > 0 ) ); +} + +bool Binding::isUseful() +{ + // we are useful, if + // 0) we don't have a model + // (at least, in this case we shouldn't be removed from the model) + // 1) we have a proper name + // 2) we have some MIPs, + // 3) we are bound to some control + // (this can be assumed if some listeners are set) + bool bUseful = + getModelImpl() == NULL +// || msBindingID.getLength() > 0 + || msTypeName.getLength() > 0 + || ! maReadonly.isEmptyExpression() + || ! maRelevant.isEmptyExpression() + || ! maRequired.isEmptyExpression() + || ! maConstraint.isEmptyExpression() + || ! maCalculate.isEmptyExpression() + || ! maModifyListeners.empty() + || ! maListEntryListeners.empty() + || ! maValidityListeners.empty(); + + return bUseful; +} + +OUString Binding::explainInvalid() +{ + OUString sReason; + if( ! maBindingExpression.getNode().is() ) + { + sReason = ( maBindingExpression.getExpression().getLength() == 0 ) + ? getResource( RID_STR_XFORMS_NO_BINDING_EXPRESSION ) + : getResource( RID_STR_XFORMS_INVALID_BINDING_EXPRESSION ); + } + else if( ! isValid_DataType() ) + { + sReason = explainInvalid_DataType(); + if( sReason.getLength() == 0 ) + { + // no explanation given by data type? Then give generic message + sReason = getResource( RID_STR_XFORMS_INVALID_VALUE, + maMIP.getTypeName() ); + } + } + else if( ! maMIP.isConstraint() ) + { + sReason = maMIP.getConstraintExplanation(); + } + else if( maMIP.isRequired() && maBindingExpression.hasValue() && + ( maBindingExpression.getString().getLength() == 0 ) ) + { + sReason = getResource( RID_STR_XFORMS_REQUIRED ); + } + // else: no explanation given; should only happen if data is valid + + OSL_ENSURE( ( sReason.getLength() == 0 ) == isValid(), + "invalid data should have an explanation!" ); + + return sReason; +} + + + +EvaluationContext Binding::getEvaluationContext() const +{ + OSL_ENSURE( getModelImpl() != NULL, "need model impl" ); + EvaluationContext aContext = getModelImpl()->getEvaluationContext(); + aContext.mxNamespaces = getBindingNamespaces(); + return aContext; +} + +::std::vector<EvaluationContext> Binding::getMIPEvaluationContexts() +{ + OSL_ENSURE( getModelImpl() != NULL, "need model impl" ); + + // bind (in case we were not bound before) + bind( sal_False ); + return _getMIPEvaluationContexts(); +} + + +Binding::IntSequence_t Binding::getUnoTunnelID() +{ + static cppu::OImplementationId aImplementationId; + return aImplementationId.getImplementationId(); +} + +Binding* SAL_CALL Binding::getBinding( const Reference<XPropertySet>& xPropertySet ) +{ + Reference<XUnoTunnel> xTunnel( xPropertySet, UNO_QUERY ); + return xTunnel.is() + ? reinterpret_cast<Binding*>( xTunnel->getSomething(getUnoTunnelID())) + : NULL; +} + + + + +OUString Binding::getBindingID() const +{ + return msBindingID; +} + +void Binding::setBindingID( const OUString& sBindingID ) +{ + msBindingID = sBindingID; +} + +OUString Binding::getBindingExpression() const +{ + return maBindingExpression.getExpression(); +} + +void Binding::setBindingExpression( const OUString& sBindingExpression) +{ + maBindingExpression.setExpression( sBindingExpression ); + bindingModified(); +} + +OUString Binding::getReadonlyExpression() const +{ + return maReadonly.getExpression(); +} + +void Binding::setReadonlyExpression( const OUString& sReadonly) +{ + maReadonly.setExpression( sReadonly ); + bindingModified(); +} + +OUString Binding::getRelevantExpression() const +{ + return maRelevant.getExpression(); +} + +void Binding::setRelevantExpression( const OUString& sRelevant ) +{ + maRelevant.setExpression( sRelevant ); + bindingModified(); +} + +OUString Binding::getRequiredExpression() const +{ + return maRequired.getExpression(); +} + +void Binding::setRequiredExpression( const OUString& sRequired ) +{ + maRequired.setExpression( sRequired ); + bindingModified(); +} + +OUString Binding::getConstraintExpression() const +{ + return maConstraint.getExpression(); +} + +void Binding::setConstraintExpression( const OUString& sConstraint ) +{ + maConstraint.setExpression( sConstraint ); + msExplainConstraint = getResource( RID_STR_XFORMS_INVALID_CONSTRAINT, + sConstraint ); + + // TODO: This should only re-evaluate the constraint, and notify + // the validity constraint listeners; instead we currently pretend + // the entire binding was notified, which does a little too much. + bindingModified(); +} + +OUString Binding::getCalculateExpression() const +{ + return maCalculate.getExpression(); +} + +void Binding::setCalculateExpression( const OUString& sCalculate ) +{ + maCalculate.setExpression( sCalculate ); + bindingModified(); +} + +OUString Binding::getType() const +{ + return msTypeName; +} + +void Binding::setType( const OUString& sTypeName ) +{ + msTypeName = sTypeName; + bindingModified(); +} + +Binding::XNameContainer_t Binding::getBindingNamespaces() const +{ + // return _getNamespaces(); + return mxNamespaces; +} + +void Binding::setBindingNamespaces( const XNameContainer_t& rNamespaces ) +{ + _setNamespaces( rNamespaces, true ); +} + +Binding::XNameContainer_t Binding::getModelNamespaces() const +{ + return _getNamespaces(); +} + +void Binding::setModelNamespaces( const XNameContainer_t& rNamespaces ) +{ + _setNamespaces( rNamespaces, false ); +} + +bool Binding::getReadOnly() const +{ + return maMIP.isReadonly(); +} + +bool Binding::getRelevant() const +{ + return maMIP.isRelevant(); +} + +bool Binding::getExternalData() const +{ + bool bExternalData = true; + if ( !mxModel.is() ) + return bExternalData; + + try + { + Reference< XPropertySet > xModelProps( mxModel, UNO_QUERY_THROW ); + OSL_VERIFY( + xModelProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ExternalData" ) ) ) >>= bExternalData ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return bExternalData; +} + + +void Binding::checkLive() + throw( RuntimeException ) +{ + if( ! isLive() ) + throw RuntimeException( EXCEPT("Binding not initialized") ); +} + +void Binding::checkModel() + throw( RuntimeException ) +{ + if( ! mxModel.is() ) + throw RuntimeException( EXCEPT("Binding has no Model") ); +} + +bool Binding::isLive() const +{ + const Model* pModel = getModelImpl(); + return ( pModel != NULL ) ? pModel->isInitialized() : false; +} + +Model* Binding::getModelImpl() const +{ + return getModelImpl( mxModel ); +} + +Model* Binding::getModelImpl( const Model_t& xModel ) const +{ + Reference<XUnoTunnel> xTunnel( xModel, UNO_QUERY ); + Model* pModel = xTunnel.is() + ? reinterpret_cast<Model*>( + xTunnel->getSomething( Model::getUnoTunnelID() ) ) + : NULL; + return pModel; +} + +void lcl_addListenerToNode( Reference<XNode> xNode, + Reference<XEventListener> xListener ) +{ + Reference<XEventTarget> xTarget( xNode, UNO_QUERY ); + if( xTarget.is() ) + { + xTarget->addEventListener( OUSTRING("DOMCharacterDataModified"), + xListener, false ); + xTarget->addEventListener( OUSTRING("DOMCharacterDataModified"), + xListener, true ); + xTarget->addEventListener( OUSTRING("DOMAttrModified"), + xListener, false ); + xTarget->addEventListener( OUSTRING("DOMAttrModified"), + xListener, true ); + xTarget->addEventListener( OUSTRING("DOMAttrModified"), + xListener, true ); + xTarget->addEventListener( OUSTRING("xforms-generic"), + xListener, true ); + } +} + +void lcl_removeListenerFromNode( Reference<XNode> xNode, + Reference<XEventListener> xListener ) +{ + Reference<XEventTarget> xTarget( xNode, UNO_QUERY ); + if( xTarget.is() ) + { + xTarget->removeEventListener( OUSTRING("DOMCharacterDataModified"), + xListener, false ); + xTarget->removeEventListener( OUSTRING("DOMCharacterDataModified"), + xListener, true ); + xTarget->removeEventListener( OUSTRING("DOMAttrModified"), + xListener, false ); + xTarget->removeEventListener( OUSTRING("DOMAttrModified"), + xListener, true ); + xTarget->removeEventListener( OUSTRING("xforms-generic"), + xListener, true ); + } +} + +::std::vector<EvaluationContext> Binding::_getMIPEvaluationContexts() const +{ + OSL_ENSURE( getModelImpl() != NULL, "need model impl" ); + + // iterate over nodes of bind expression and create + // EvaluationContext for each + PathExpression::NodeVector_t aNodes = maBindingExpression.getNodeList(); + ::std::vector<EvaluationContext> aVector; + sal_Int32 nCount = 0; // count nodes for context position + for( PathExpression::NodeVector_t::iterator aIter = aNodes.begin(); + aIter != aNodes.end(); + aIter++, nCount++ ) + { + OSL_ENSURE( aIter->is(), "no node?" ); + + // create proper evaluation context for this MIP + aVector.push_back( EvaluationContext( *aIter, getModel(), + getBindingNamespaces(), + nCount, aNodes.size() ) ); + } + return aVector; +} + +void Binding::bind( bool bForceRebind ) +{ + checkModel(); + + // bind() will evaluate this binding as follows: + // 1) evaluate the binding expression + // 1b) if necessary, create node according to 'lazy author' rules + // 2) register suitable listeners on the instance (and remove old ones) + // 3) remove old MIPs defined by this binding + // 4) for every node in the binding nodeset do: + // 1) create proper evaluation context for this MIP + // 2) evaluate calculate expression (and push value into instance) + // 3) evaluate remaining MIPs + // 4) evaluate the locally defined MIPs, and push them to the model + + + // 1) evaluate the binding expression + EvaluationContext aContext = getEvaluationContext(); + maBindingExpression.evaluate( aContext ); + if( ! maBindingExpression.getNode().is() ) + { + // 1b) create node (if valid element name) + if( isValidQName( maBindingExpression.getExpression(), + aContext.mxNamespaces ) ) + { + aContext.mxContextNode->appendChild( + Reference<XNode>( + aContext.mxContextNode->getOwnerDocument()->createElement( + maBindingExpression.getExpression() ), + UNO_QUERY ) ); + maBindingExpression.evaluate( aContext ); + OSL_ENSURE( maBindingExpression.getNode().is(), + "we should bind to the newly inserted node!" ); + } + } + PathExpression::NodeVector_t aNodes = maBindingExpression.getNodeList(); + + // 2) register suitable listeners on the instance (and remove old ones) + if( maEventNodes.empty() || bForceRebind ) + { + for( XNodes_t::iterator aIter = maEventNodes.begin(); + aIter != maEventNodes.end(); + aIter ++ ) + lcl_removeListenerFromNode( *aIter, this ); + maEventNodes.clear(); + if( isSimpleBinding() ) + for( PathExpression::NodeVector_t::iterator aIter = aNodes.begin(); + aIter != aNodes.end(); + aIter++ ) + maEventNodes.push_back( *aIter ); + else + maEventNodes.push_back( + Reference<XNode>( aContext.mxContextNode->getOwnerDocument(), + UNO_QUERY_THROW ) ); + for( PathExpression::NodeVector_t::iterator aIter2 = maEventNodes.begin(); + aIter2 != maEventNodes.end(); + aIter2 ++ ) + lcl_addListenerToNode( *aIter2, this ); + } + + // 3) remove old MIPs defined by this binding + Model* pModel = getModelImpl(); + OSL_ENSURE( pModel != NULL, "need model" ); + pModel->removeMIPs( this ); + + // 4) calculate all MIPs + ::std::vector<EvaluationContext> aMIPContexts = _getMIPEvaluationContexts(); + for( ::std::vector<EvaluationContext>::iterator aIter = aMIPContexts.begin(); + aIter != aMIPContexts.end(); + aIter++ ) + { + EvaluationContext& rContext = *aIter; + + // evaluate calculate expression (and push value into instance) + // (prevent recursion using mbInCalculate + if( ! maCalculate.isEmptyExpression() ) + { + if( ! mbInCalculate ) + { + mbInCalculate = true; + maCalculate.evaluate( rContext ); + pModel->setSimpleContent( rContext.mxContextNode, + maCalculate.getString() ); + mbInCalculate = false; + } + } + + // now evaluate remaining MIPs in the apropriate context + maReadonly.evaluate( rContext ); + maRelevant.evaluate( rContext ); + maRequired.evaluate( rContext ); + maConstraint.evaluate( rContext ); + // type is static; does not need updating + + // evaluate the locally defined MIPs, and push them to the model + pModel->addMIP( this, rContext.mxContextNode, getLocalMIP() ); + } +} + + +// helper for Binding::valueModified +void lcl_modified( const Binding::XModifyListener_t xListener, + const Reference<XInterface> xSource ) +{ + OSL_ENSURE( xListener.is(), "no listener?" ); + xListener->modified( EventObject( xSource ) ); +} + +// helper for Binding::valueModified +void lcl_listentry( const Binding::XListEntryListener_t xListener, + const Reference<XInterface> xSource ) +{ + OSL_ENSURE( xListener.is(), "no listener?" ); + // TODO: send fine granular events + xListener->allEntriesChanged( EventObject( xSource ) ); +} + +// helper for Binding::valueModified +void lcl_validate( const Binding::XValidityConstraintListener_t xListener, + const Reference<XInterface> xSource ) +{ + OSL_ENSURE( xListener.is(), "no listener?" ); + xListener->validityConstraintChanged( EventObject( xSource ) ); +} + + +void Binding::valueModified() +{ + // defer notifications, if so desired + if( mnDeferModifyNotifications > 0 ) + { + mbValueModified = true; + return; + } + mbValueModified = false; + + // query MIP used by our first node (also note validity) + Reference<XNode> xNode = maBindingExpression.getNode(); + maMIP = getModelImpl()->queryMIP( xNode ); + + // distribute MIPs _used_ by this binding + if( xNode.is() ) + { + notifyAndCachePropertyValue( HANDLE_ReadOnly ); + notifyAndCachePropertyValue( HANDLE_Relevant ); + } + + // iterate over _value_ listeners and send each a modified signal, + // using this object as source (will also update validity, because + // control will query once the value has changed) + Reference<XInterface> xSource = static_cast<XPropertySet*>( this ); + ::std::for_each( maModifyListeners.begin(), + maModifyListeners.end(), + ::std::bind2nd( ::std::ptr_fun( lcl_modified ), xSource ) ); + ::std::for_each( maListEntryListeners.begin(), + maListEntryListeners.end(), + ::std::bind2nd( ::std::ptr_fun( lcl_listentry ), xSource ) ); + ::std::for_each( maValidityListeners.begin(), + maValidityListeners.end(), + ::std::bind2nd( ::std::ptr_fun( lcl_validate ), xSource ) ); + + // now distribute MIPs to childs + if( xNode.is() ) + distributeMIP( xNode->getFirstChild() ); +} + +void Binding::distributeMIP( const XNode_t & rxNode ) { + + typedef com::sun::star::xforms::XFormsEventConcrete XFormsEvent_t; + OUString sEventName( RTL_CONSTASCII_USTRINGPARAM("xforms-generic") ); + XFormsEvent_t *pEvent = new XFormsEvent_t; + pEvent->initXFormsEvent(sEventName, sal_True, sal_False); + Reference<XEvent> xEvent(pEvent); + + // naive depth-first traversal + XNode_t xNode( rxNode ); + while(xNode.is()) { + + // notifications should be triggered at the + // leaf nodes first, bubbling upwards the hierarchy. + XNode_t child(xNode->getFirstChild()); + if(child.is()) + distributeMIP(child); + + // we're standing at a particular node somewhere + // below the one which changed a property (MIP). + // bindings which are listening at this node will receive + // a notification message about what exactly happened. + Reference< XEventTarget > target(xNode,UNO_QUERY); + target->dispatchEvent(xEvent); + + xNode = xNode->getNextSibling(); + }; +} + +void Binding::bindingModified() +{ + // defer notifications, if so desired + if( mnDeferModifyNotifications > 0 ) + { + mbBindingModified = true; + return; + } + mbBindingModified = false; + + // rebind (if live); then call valueModified + // A binding should be inert until its model is fully constructed. + if( isLive() ) + { + bind( true ); + valueModified(); + } +} + + +MIP Binding::getLocalMIP() const +{ + MIP aMIP; + + if( maReadonly.hasValue() ) + aMIP.setReadonly( maReadonly.getBool( false ) ); + if( maRelevant.hasValue() ) + aMIP.setRelevant( maRelevant.getBool( true ) ); + if( maRequired.hasValue() ) + aMIP.setRequired( maRequired.getBool( false ) ); + if( maConstraint.hasValue() ) + { + aMIP.setConstraint( maConstraint.getBool( true ) ); + if( ! aMIP.isConstraint() ) + aMIP.setConstraintExplanation( msExplainConstraint ); + } + if( msTypeName.getLength() > 0 ) + aMIP.setTypeName( msTypeName ); + + // calculate: only handle presence of calculate; value set elsewhere + aMIP.setHasCalculate( !maCalculate.isEmptyExpression() ); + + return aMIP; +} + +Binding::XDataType_t Binding::getDataType() +{ + OSL_ENSURE( getModel().is(), "need model" ); + OSL_ENSURE( getModel()->getDataTypeRepository().is(), "need types" ); + + Reference<XDataTypeRepository> xRepository( + getModel()->getDataTypeRepository(), UNO_QUERY ); + OUString sTypeName = maMIP.getTypeName(); + + return ( xRepository.is() && xRepository->hasByName( sTypeName ) ) + ? Reference<XDataType>( xRepository->getByName( sTypeName ), UNO_QUERY) + : Reference<XDataType>( NULL ); +} + +bool Binding::isValid_DataType() +{ + Reference<XDataType> xDataType = getDataType(); + return xDataType.is() + ? xDataType->validate( maBindingExpression.getString() ) + : true; +} + +rtl::OUString Binding::explainInvalid_DataType() +{ + Reference<XDataType> xDataType = getDataType(); + return xDataType.is() + ? xDataType->explainInvalid( maBindingExpression.getString() ) + : OUString(); +} + +void Binding::clear() +{ + // remove MIPs contributed by this binding + Model* pModel = getModelImpl(); + if( pModel != NULL ) + pModel->removeMIPs( this ); + + // remove all references + for( XNodes_t::iterator aIter = maEventNodes.begin(); + aIter != maEventNodes.end(); + aIter ++ ) + lcl_removeListenerFromNode( *aIter, this ); + maEventNodes.clear(); + + // clear expressions + maBindingExpression.clear(); + maReadonly.clear(); + maRelevant.clear(); + maRequired.clear(); + maConstraint.clear(); + maCalculate.clear(); + + // TODO: what about our listeners? +} + + +void lcl_removeOtherNamespaces( const Binding::XNameContainer_t& xFrom, + Binding::XNameContainer_t& xTo ) +{ + OSL_ENSURE( xFrom.is(), "no source" ); + OSL_ENSURE( xTo.is(), "no target" ); + + // iterate over name in source + Sequence<OUString> aNames = xTo->getElementNames(); + sal_Int32 nNames = aNames.getLength(); + const OUString* pNames = aNames.getConstArray(); + for( sal_Int32 i = 0; i < nNames; i++ ) + { + const OUString& rName = pNames[i]; + + if( ! xFrom->hasByName( rName ) ) + xTo->removeByName( rName ); + } +} + +/** copy namespaces from one namespace container into another + * @param bOverwrite true: overwrite namespaces in target + * false: do not overwrite namespaces in target + * @param bMove true: move namespaces (i.e., delete in source) + * false: copy namespaces (do not modify source) + * @param bFromSource true: use elements from source + * false: use only elements from target + */ +void lcl_copyNamespaces( const Binding::XNameContainer_t& xFrom, + Binding::XNameContainer_t& xTo, + bool bOverwrite ) +{ + OSL_ENSURE( xFrom.is(), "no source" ); + OSL_ENSURE( xTo.is(), "no target" ); + + // iterate over name in source + Sequence<OUString> aNames = xFrom->getElementNames(); + sal_Int32 nNames = aNames.getLength(); + const OUString* pNames = aNames.getConstArray(); + for( sal_Int32 i = 0; i < nNames; i++ ) + { + const OUString& rName = pNames[i]; + + // determine whether to copy the value, and whether to delete + // it in the source: + + bool bInTarget = xTo->hasByName( rName ); + + // we copy: if property is in target, and + // if bOverwrite is set, or when the namespace prefix is free + bool bCopy = bOverwrite || ! bInTarget; + + // and now... ACTION! + if( bCopy ) + { + if( bInTarget ) + xTo->replaceByName( rName, xFrom->getByName( rName ) ); + else + xTo->insertByName( rName, xFrom->getByName( rName ) ); + } + } +} + +// implement get*Namespaces() +// (identical for both variants) +Binding::XNameContainer_t Binding::_getNamespaces() const +{ + XNameContainer_t xNamespaces = new NameContainer<OUString>(); + lcl_copyNamespaces( mxNamespaces, xNamespaces, true ); + + // merge model's with binding's own namespaces + Model* pModel = getModelImpl(); + if( pModel != NULL ) + lcl_copyNamespaces( pModel->getNamespaces(), xNamespaces, false ); + + return xNamespaces; +} + +// implement set*Namespaces() +// bBinding = true: setBindingNamespaces, otherwise: setModelNamespaces +void Binding::_setNamespaces( const XNameContainer_t& rNamespaces, + bool bBinding ) +{ + Model* pModel = getModelImpl(); + XNameContainer_t xModelNamespaces = ( pModel != NULL ) + ? pModel->getNamespaces() + : NULL; + OSL_ENSURE( ( pModel != NULL ) == xModelNamespaces.is(), "no model nmsp?"); + + // remove deleted namespaces + lcl_removeOtherNamespaces( rNamespaces, mxNamespaces ); + if( !bBinding && xModelNamespaces.is() ) + lcl_removeOtherNamespaces( rNamespaces, xModelNamespaces ); + + // copy namespaces as appropriate + Sequence<OUString> aNames = rNamespaces->getElementNames(); + sal_Int32 nNames = aNames.getLength(); + const OUString* pNames = aNames.getConstArray(); + for( sal_Int32 i = 0; i < nNames; i++ ) + { + const OUString& rName = pNames[i]; + Any aValue = rNamespaces->getByName( rName ); + + // determine whether the namespace should go into model's or + // into binding's namespaces + bool bLocal = + ! xModelNamespaces.is() + || mxNamespaces->hasByName( rName ) + || ( bBinding + && xModelNamespaces.is() + && xModelNamespaces->hasByName( rName ) ); + + // write namespace into the appropriate namespace container + XNameContainer_t& rWhich = bLocal ? mxNamespaces : xModelNamespaces; + OSL_ENSURE( rWhich.is(), "whoops" ); + if( rWhich->hasByName( rName ) ) + rWhich->replaceByName( rName, aValue ); + else + rWhich->insertByName( rName, aValue ); + + // always 'promote' namespaces from binding to model, if equal + if( xModelNamespaces.is() + && xModelNamespaces->hasByName( rName ) + && mxNamespaces->hasByName( rName ) + && xModelNamespaces->getByName( rName ) == mxNamespaces->getByName( rName ) ) + { + mxNamespaces->removeByName( rName ); + } + } + + // ... done. But we modified the binding! + bindingModified(); +} + +void Binding::_checkBindingID() +{ + if( getModel().is() ) + { + Reference<XNameAccess> xBindings( getModel()->getBindings(), UNO_QUERY_THROW ); + if( msBindingID.getLength() == 0 ) + { + // no binding ID? then make one up! + OUString sIDPrefix = getResource( RID_STR_XFORMS_BINDING_UI_NAME ); + sIDPrefix += String::CreateFromAscii( " " ); + sal_Int32 nNumber = 0; + OUString sName; + do + { + nNumber++; + sName = sIDPrefix + OUString::valueOf( nNumber ); + } + while( xBindings->hasByName( sName ) ); + setBindingID( sName ); + } + } +} + + + + +// +// XValueBinding +// + +Binding::Sequence_Type_t Binding::getSupportedValueTypes() + throw( RuntimeException ) +{ + return Convert::get().getTypes(); +} + +sal_Bool Binding::supportsType( const Type_t& rType ) + throw( RuntimeException ) +{ + return Convert::get().hasType( rType ); +} + +Binding::Any_t Binding::getValue( const Type_t& rType ) + throw( IncompatibleTypesException, + RuntimeException ) +{ + // first, check for model + checkLive(); + + // second, check for type + if( ! supportsType( rType ) ) + throw IncompatibleTypesException( EXCEPT( "type unsupported" ) ); + + // return string value (if present; else return empty Any) + Binding::Any_t result = Any(); + if(maBindingExpression.hasValue()) { + rtl::OUString pathExpr(maBindingExpression.getString()); + Convert &rConvert = Convert::get(); + result = rConvert.toAny(pathExpr,rType); + } + +// return maBindingExpression.hasValue() + // ? Convert::get().toAny( maBindingExpression.getString(), rType ) + // : Any(); + + return result; +} + +void Binding::setValue( const Any_t& aValue ) + throw( IncompatibleTypesException, + InvalidBindingStateException, + NoSupportException, + RuntimeException ) +{ + // first, check for model + checkLive(); + + // check for supported type + if( ! supportsType( aValue.getValueType() ) ) + throw IncompatibleTypesException( EXCEPT( "type unsupported" ) ); + + if( maBindingExpression.hasValue() ) + { + Binding::XNode_t xNode = maBindingExpression.getNode(); + if( xNode.is() ) + { + OUString sValue = Convert::get().toXSD( aValue ); + bool bSuccess = getModelImpl()->setSimpleContent( xNode, sValue ); + if( ! bSuccess ) + throw InvalidBindingStateException( EXCEPT( "can't set value" ) ); + } + else + throw InvalidBindingStateException( EXCEPT( "no suitable node found" ) ); + } + else + throw InvalidBindingStateException( EXCEPT( "no suitable node found" ) ); +} + + +// +// XListEntry Source +// + +sal_Int32 Binding::getListEntryCount() + throw( RuntimeException ) +{ + // first, check for model + checkLive(); + + // return size of node list + return maBindingExpression.getNodeList().size(); +} + +void lcl_getString( const Reference<XNode>& xNode, OUStringBuffer& rBuffer ) +{ + if( xNode->getNodeType() == NodeType_TEXT_NODE + || xNode->getNodeType() == NodeType_ATTRIBUTE_NODE ) + { + rBuffer.append( xNode->getNodeValue() ); + } + else + { + for( Reference<XNode> xChild = xNode->getFirstChild(); + xChild.is(); + xChild = xChild->getNextSibling() ) + { + lcl_getString( xChild, rBuffer ); + } + } +} + +OUString lcl_getString( const Reference<XNode>& xNode ) +{ + OUStringBuffer aBuffer; + lcl_getString( xNode, aBuffer ); + return aBuffer.makeStringAndClear(); +} + +OUString Binding::getListEntry( sal_Int32 nPosition ) + throw( IndexOutOfBoundsException, + RuntimeException ) +{ + // first, check for model + checkLive(); + + // 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("") ); + return lcl_getString( aNodes[ nPosition ] ); +} + +Sequence<OUString> Binding::getAllListEntries() + throw( RuntimeException ) +{ + // first, check for model + checkLive(); + + // create sequence of string values + PathExpression::NodeVector_t aNodes = maBindingExpression.getNodeList(); + Sequence<OUString> aSequence( aNodes.size() ); + OUString* pSequence = aSequence.getArray(); + for( sal_Int32 n = 0; n < aSequence.getLength(); n++ ) + { + pSequence[n] = lcl_getString( aNodes[n] ); + } + + return aSequence; +} + +void Binding::addListEntryListener( const XListEntryListener_t& xListener ) + throw( NullPointerException, + RuntimeException ) +{ + OSL_ENSURE( xListener.is(), "need listener!" ); + if( ::std::find( maListEntryListeners.begin(), + maListEntryListeners.end(), + xListener) + == maListEntryListeners.end() ) + maListEntryListeners.push_back( xListener ); +} + +void Binding::removeListEntryListener( const XListEntryListener_t& xListener ) + throw( NullPointerException, + RuntimeException ) +{ + XListEntryListeners_t::iterator aIter = + ::std::find( maListEntryListeners.begin(), maListEntryListeners.end(), + xListener ); + if( aIter != maListEntryListeners.end() ) + maListEntryListeners.erase( aIter ); +} + + +// +// XValidator +// + +sal_Bool Binding::isValid( const Any_t& ) + throw( RuntimeException ) +{ + // first, check for model + checkLive(); + + // ignore value; determine validate only on current data + return isValid(); +} + +rtl::OUString Binding::explainInvalid( + const Any_t& /*Value*/ ) + throw( RuntimeException ) +{ + // first, check for model + checkLive(); + + // ignore value; determine explanation only on current data + return explainInvalid(); +} + +void Binding::addValidityConstraintListener( + const XValidityConstraintListener_t& xListener ) + throw( NullPointerException, + RuntimeException ) +{ + OSL_ENSURE( xListener.is(), "need listener!" ); + if( ::std::find(maValidityListeners.begin(), maValidityListeners.end(), xListener) + == maValidityListeners.end() ) + maValidityListeners.push_back( xListener ); +} + +void Binding::removeValidityConstraintListener( + const XValidityConstraintListener_t& xListener ) + throw( NullPointerException, + RuntimeException ) +{ + XValidityConstraintListeners_t::iterator aIter = + ::std::find( maValidityListeners.begin(), maValidityListeners.end(), + xListener ); + if( aIter != maValidityListeners.end() ) + maValidityListeners.erase( aIter ); +} + + + +// +// xml::dom::event::XEventListener +// + +void Binding::handleEvent( const XEvent_t& xEvent ) + throw( RuntimeException ) +{ + OUString sType(xEvent->getType()); + //OUString sEventMIPChanged(RTL_CONSTASCII_USTRINGPARAM("xforms-generic")); + //if(sType.equals(sEventMIPChanged)) { + if(!sType.compareToAscii("xforms-generic")) { + + // the modification of the 'mnDeferModifyNotifications'-member + // is necessary to prevent infinite notication looping. + // This can happend in case the binding which caused + // the notification chain is listening to those events + // as well... + bool bPreserveValueModified = mbValueModified; + mnDeferModifyNotifications++; + valueModified(); + --mnDeferModifyNotifications; + mbValueModified = bPreserveValueModified; + return; + } + + // if we're a dynamic binding, we better re-bind, too! + bind( false ); + + // our value was maybe modified + valueModified(); +} + + +// +// lang::XUnoTunnel +// + +sal_Int64 Binding::getSomething( const IntSequence_t& xId ) + throw( RuntimeException ) +{ + return reinterpret_cast<sal_Int64>( ( xId == getUnoTunnelID() ) ? this : NULL ); +} + +// +// XCloneable +// + +Binding::XCloneable_t SAL_CALL Binding::createClone() + throw( RuntimeException ) +{ + Reference< XPropertySet > xClone; + + Model* pModel = getModelImpl(); + if ( pModel ) + xClone = pModel->cloneBinding( this ); + else + { + xClone = new Binding; + copy( this, xClone ); + } + return XCloneable_t( xClone, UNO_QUERY ); +} + +// +// property set implementations +// + +#define REGISTER_PROPERTY( property, type ) \ + registerProperty( PROPERTY( property, type ), \ + new DirectPropertyAccessor< Binding, type >( this, &Binding::set##property, &Binding::get##property ) ); + +#define REGISTER_PROPERTY_RO( property, type ) \ + registerProperty( PROPERTY_RO( property, type ), \ + new DirectPropertyAccessor< Binding, type >( this, NULL, &Binding::get##property ) ); + +#define REGISTER_BOOL_PROPERTY_RO( property ) \ + registerProperty( PROPERTY_RO( property, sal_Bool ), \ + new BooleanPropertyAccessor< Binding, bool >( this, NULL, &Binding::get##property ) ); + +void Binding::initializePropertySet() +{ + REGISTER_PROPERTY ( BindingID, OUString ); + REGISTER_PROPERTY ( BindingExpression, OUString ); + REGISTER_PROPERTY_RO ( Model, Model_t ); + REGISTER_PROPERTY ( BindingNamespaces, XNameContainer_t ); + REGISTER_PROPERTY ( ModelNamespaces, XNameContainer_t ); + 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 ); + + initializePropertyValueCache( HANDLE_ReadOnly ); + initializePropertyValueCache( HANDLE_Relevant ); + initializePropertyValueCache( HANDLE_ExternalData ); +} + +void Binding::addModifyListener( + const XModifyListener_t& xListener ) + throw( RuntimeException ) +{ + OSL_ENSURE( xListener.is(), "need listener!" ); + if( ::std::find( maModifyListeners.begin(), maModifyListeners.end(), xListener ) + == maModifyListeners.end() ) + maModifyListeners.push_back( xListener ); + + // HACK: currently, we have to 'push' some MIPs to the control + // (read-only, relevant, etc.) To enable this, we need to update + // the control at least once when it registers here. + valueModified(); +} + +void Binding::removeModifyListener( + const XModifyListener_t& xListener ) + throw( RuntimeException ) +{ + ModifyListeners_t::iterator aIter = + ::std::find( maModifyListeners.begin(), maModifyListeners.end(), xListener ); + if( aIter != maModifyListeners.end() ) + maModifyListeners.erase( aIter ); +} + + + + +rtl::OUString Binding::getName() + throw( RuntimeException ) +{ + return getBindingID(); +} + +void SAL_CALL Binding::setName( const rtl::OUString& rName ) + throw( RuntimeException ) +{ + // use the XPropertySet methods, so the change in the name is notified to the + // property listeners + setFastPropertyValue( HANDLE_BindingID, makeAny( rName ) ); +} diff --git a/forms/source/xforms/binding.hxx b/forms/source/xforms/binding.hxx new file mode 100644 index 000000000000..7a69b1547418 --- /dev/null +++ b/forms/source/xforms/binding.hxx @@ -0,0 +1,527 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _BINDING_HXX +#define _BINDING_HXX + +#include <com/sun/star/uno/Reference.hxx> + +// forward declaractions +namespace xforms +{ + class Model; + class EvaluationContext; +} +namespace com { namespace sun { namespace star { + namespace xml { + namespace xpath { class XXPathAPI; } + namespace dom + { + class XNode; + class XNodeList; + } + } + namespace container { class XNameContainer; } + namespace xforms { class XModel; } + namespace xsd { class XDataType; } +} } } + +// includes for parent classes +#include <cppuhelper/implbase8.hxx> +#include <propertysetbase.hxx> +#include <com/sun/star/form/binding/XValueBinding.hpp> +#include <com/sun/star/form/binding/XListEntrySource.hpp> +#include <com/sun/star/form/validation/XValidator.hpp> +#include <com/sun/star/util/XModifyBroadcaster.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/xml/dom/events/XEventListener.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/util/XCloneable.hpp> + +// includes for member variables +#include "pathexpression.hxx" +#include "boolexpression.hxx" +#include "mip.hxx" +#include <rtl/ustring.hxx> +#include <vector> +#include <memory> // auto_ptr + + + +namespace xforms +{ + +/** An XForms Binding. Contains: + * # a connection to its model + * # an ID + * # an binding expression + * # model item properties + * # (NOT YET IMPLEMENTED) child bindings (sequence of) + * + * See http://www.w3.org/TR/xforms/ for more information. + */ + +typedef cppu::ImplInheritanceHelper8< + PropertySetBase, + com::sun::star::form::binding::XValueBinding, + com::sun::star::form::binding::XListEntrySource, + com::sun::star::form::validation::XValidator, + com::sun::star::util::XModifyBroadcaster, + com::sun::star::container::XNamed, + com::sun::star::xml::dom::events::XEventListener, + com::sun::star::lang::XUnoTunnel, + com::sun::star::util::XCloneable +> Binding_t; + +class Binding : public Binding_t +{ +public: + typedef com::sun::star::uno::Reference<com::sun::star::xforms::XModel> Model_t; + typedef com::sun::star::uno::Reference<com::sun::star::util::XModifyListener> XModifyListener_t; + typedef std::vector<XModifyListener_t> ModifyListeners_t; + typedef com::sun::star::uno::Reference<com::sun::star::form::validation::XValidityConstraintListener> XValidityConstraintListener_t; + typedef std::vector<XValidityConstraintListener_t> XValidityConstraintListeners_t; + typedef com::sun::star::uno::Reference<com::sun::star::form::binding::XListEntryListener> XListEntryListener_t; + typedef std::vector<XListEntryListener_t> XListEntryListeners_t; + typedef com::sun::star::uno::Reference<com::sun::star::container::XNameContainer> XNameContainer_t; + typedef com::sun::star::uno::Reference<com::sun::star::xml::dom::XNode> XNode_t; + typedef com::sun::star::uno::Reference<com::sun::star::xml::dom::XNodeList> XNodeList_t; + typedef com::sun::star::uno::Reference<com::sun::star::util::XCloneable> XCloneable_t; + typedef com::sun::star::uno::Sequence<sal_Int8> IntSequence_t; + typedef com::sun::star::uno::Sequence<rtl::OUString> StringSequence_t; + typedef std::vector<MIP> MIPs_t; + typedef std::vector<XNode_t> XNodes_t; + + + +private: + + /// the Model to which this Binding belongs; may be NULL + Model_t mxModel; + + /// binding-ID. A document-wide unique ID for this binding element. + rtl::OUString msBindingID; + + /// an XPath-expression to be instantiated on the data instance + PathExpression maBindingExpression; + + /// an XPath-expression to determine read-only status + BoolExpression maReadonly; + + /// an XPath-expression to determine relevance + BoolExpression maRelevant; + + /// an XPath-expression to determine if item is required + BoolExpression maRequired; + + /// an XPath-expression to determine if item is valid + BoolExpression maConstraint; + + /// user-readable explanation of the constraint + rtl::OUString msExplainConstraint; + + /// an XPath-expression to calculate values + ComputedExpression maCalculate; + + /// the XML namespaces used for XML names/XPath-expressions in this binding + XNameContainer_t mxNamespaces; + + /// a type name + rtl::OUString msTypeName; + + /// modify listeners + ModifyListeners_t maModifyListeners; + + /// list entry listener + XListEntryListeners_t maListEntryListeners; + + /// validity listeners; + XValidityConstraintListeners_t maValidityListeners; + + /// nodes on which we are listening for events + XNodes_t maEventNodes; + + /// the current MIP object for the first node we are bound to + MIP maMIP; + + /// flag to detect recursions in calculate + bool mbInCalculate; + + // flags to manage deferred notifications: + /// if >0, valueModified() and bindingModified() will only set flags + sal_Int32 mnDeferModifyNotifications; + bool mbValueModified; /// if true, valueModified needs to be called + bool mbBindingModified; /// if true, bindingModified needs to be called + + + void initializePropertySet(); + + +public: + Binding(); + virtual ~Binding() throw(); + + // + // property methods: get/set value + // + + Model_t getModel() const; /// get XForms model + void _setModel( const Model_t& ); /// set XForms model (only called by Model) + + + rtl::OUString getModelID() const; /// get ID of XForms model + + rtl::OUString getBindingID() const; /// get ID for this binding + void setBindingID( const rtl::OUString& ); /// set ID for this binding + + rtl::OUString getBindingExpression() const; /// get binding expression + void setBindingExpression( const rtl::OUString& ); /// set binding exp. + + // MIPs (model item properties) + + rtl::OUString getReadonlyExpression() const; /// get read-only MIP + void setReadonlyExpression( const rtl::OUString& ); /// set read-only MIP + + rtl::OUString getRelevantExpression() const; /// get relevant MIP + void setRelevantExpression( const rtl::OUString& ); /// set relevant MIP + + rtl::OUString getRequiredExpression() const; /// get required MIP + void setRequiredExpression( const rtl::OUString& ); /// set required MIP + + rtl::OUString getConstraintExpression() const; /// get constraint MIP + void setConstraintExpression( const rtl::OUString& );/// set constraint MIP + + rtl::OUString getCalculateExpression() const; /// get calculate MIP + void setCalculateExpression( const rtl::OUString& ); /// set calculate MIP + + rtl::OUString getType() const; /// get type name MIP (static) + void setType( const rtl::OUString& ); /// set type name MIP (static) + + // a binding expression can only be interpreted with respect to + // suitable namespace declarations. We collect those in the model and in a binding. + + // access to a binding's namespace + // (set-method only changes local namespaces (but may add to model)) + XNameContainer_t getBindingNamespaces() const; /// set binding namespaces + void setBindingNamespaces( const XNameContainer_t& ); /// get binding nmsp. + + // access to the model's namespaces + // (set-method changes model's namespaces (unless a local one is present)) + XNameContainer_t getModelNamespaces() const; /// set model namespaces + void setModelNamespaces( const XNameContainer_t& ); /// get model nmsp. + + + // read-only properties that map MIPs to control data source properties + bool getReadOnly() const; // MIP readonly + bool getRelevant() const; // MIP relevant + bool getExternalData() const; // mapped from model's ExternalData property + + + // missing binding properties: + // - type (static; default: xsd:string) + // - minOccurs/maxOccurs (computed XPath; default: 0/inf) + // - p3ptype (static; no default) + + + + + /// get this binding's context node + xforms::EvaluationContext getEvaluationContext() const; + + /// get evalation contexts for this binding's MIPs + std::vector<xforms::EvaluationContext> getMIPEvaluationContexts(); + + /// get nodeset the bind is bound to + XNodeList_t getXNodeList(); + + /// heuristically determine whether this binding is simple binding + /// (here: simple binding == does not depend on other parts of the + /// instance, it's not a 'dynamic' binding) + bool isSimpleBinding() const; + + /// heuristically determine whether this binding's binding + /// expression is simple + bool isSimpleBindingExpression() const; + + /// update this binding (e.g. called by model for refresh ) + void update(); + + /// prevent change notifications being sent to controls + void deferNotifications( bool ); + + /// is this binding valid? (are constraint, type and required MIPs ok?) + bool isValid(); + + /// determine whether this binding currently performs a useful + /// function, r whether is may be discarded + bool isUseful(); + + /// explain why binding is invalid + rtl::OUString explainInvalid(); + + + // the ID for XUnoTunnel calls + static IntSequence_t getUnoTunnelID(); + static Binding* getBinding( const com::sun::star::uno::Reference<com::sun::star::beans::XPropertySet>& ); + + // + // class-scoped typedef for easy-to-read UNO interfaces + // + + // basic types + typedef com::sun::star::uno::Any Any_t; + typedef com::sun::star::uno::Sequence<com::sun::star::uno::Type> Sequence_Type_t; + typedef com::sun::star::uno::Type Type_t; + + // reference types + typedef com::sun::star::uno::Reference<com::sun::star::beans::XPropertyChangeListener> XPropertyChangeListener_t; + typedef com::sun::star::uno::Reference<com::sun::star::beans::XPropertySetInfo> XPropertySetInfo_t; + typedef com::sun::star::uno::Reference<com::sun::star::beans::XVetoableChangeListener> XVetoableChangeListener_t; + typedef com::sun::star::uno::Reference<com::sun::star::xml::xpath::XXPathAPI> XXPathAPI_t; + typedef com::sun::star::uno::Reference<com::sun::star::xml::dom::events::XEvent> XEvent_t; + typedef com::sun::star::uno::Reference<com::sun::star::xsd::XDataType> XDataType_t; + + // exceptions + typedef com::sun::star::beans::PropertyVetoException PropertyVetoException_t; + typedef com::sun::star::beans::UnknownPropertyException UnknownPropertyException_t; + typedef com::sun::star::lang::IllegalArgumentException IllegalArgumentException_t; + typedef com::sun::star::lang::NoSupportException NoSupportException_t; + typedef com::sun::star::lang::WrappedTargetException WrappedTargetException_t; + typedef com::sun::star::uno::RuntimeException RuntimeException_t; + typedef com::sun::star::form::binding::IncompatibleTypesException IncompatibleTypesException_t; + typedef com::sun::star::form::binding::InvalidBindingStateException InvalidBindingStateException_t; + typedef com::sun::star::lang::NullPointerException NullPointerException_t; + typedef com::sun::star::lang::IndexOutOfBoundsException IndexOutOfBoundsException_t; + + + +private: + /// check whether object is live, and throw suitable exception if not + /// (to be used be API methods before acting on the object) + void checkLive() throw( RuntimeException_t ); + + /// check whether binding has a model, and throw exception if not + /// (to be used be API methods before acting on the object) + void checkModel() throw( RuntimeException_t ); + + /// determine whether object is live + /// live: has model, and model has been initialized + bool isLive() const; + + /// get the model implementation + xforms::Model* getModelImpl() const; + xforms::Model* getModelImpl( const Model_t& xModel ) const; + + /// get MIP evaluation contexts + /// (only valid if control has already been bound) + std::vector<xforms::EvaluationContext> _getMIPEvaluationContexts() const; + + /// bind this binding, and pre-compute the affected nodes + void bind( bool bForceRebind = false ); + + /// the binding value has been changed: + /// trigger a modified event on all modified listeners + void valueModified(); + + /// the binding itself has changed: + /// force rebind, then call valueModified() + void bindingModified(); + + + /// register the event listeners for + void registerListeners(); + + /// set MIPs defined by this binding on MIP item + MIP getLocalMIP() const; + + /// get the data type that applies to this binding + XDataType_t getDataType(); + + /// determine whether binding is valid according to the given data type + bool isValid_DataType(); + + /// explain validity of binding with respect to the given data type + rtl::OUString explainInvalid_DataType(); + + /// 'clear' this binding - remove all listeners, etc. + void clear(); + + /// distribute MIPs from current node recursively to childs + void distributeMIP( const XNode_t &rxNode ); + + /// implement get*Namespaces() + XNameContainer_t _getNamespaces() const; + + /// implement set*Namespaces() + void _setNamespaces( const XNameContainer_t&, bool bBinding ); + + /// set a useful default binding ID (if none is set) + void _checkBindingID(); + +public: + /// for debugging purposes only: get the MIPs defined by this binding + const MIP* _getMIP(); + + + + + + // + // XValueBinding: + // + +public: + + virtual Sequence_Type_t SAL_CALL getSupportedValueTypes() + throw( RuntimeException_t ); + + virtual sal_Bool SAL_CALL supportsType( const Type_t& aType ) + throw( RuntimeException_t ); + + virtual Any_t SAL_CALL getValue( const Type_t& aType ) + throw( IncompatibleTypesException_t, + RuntimeException_t ); + + virtual void SAL_CALL setValue( const Any_t& aValue ) + throw( IncompatibleTypesException_t, + InvalidBindingStateException_t, + NoSupportException_t, + RuntimeException_t ); + + + + // + // XListEntry Source + // + + virtual sal_Int32 SAL_CALL getListEntryCount() + throw( RuntimeException_t ); + + virtual rtl::OUString SAL_CALL getListEntry( sal_Int32 nPosition ) + throw( IndexOutOfBoundsException_t, + RuntimeException_t ); + + virtual StringSequence_t SAL_CALL getAllListEntries() + throw( RuntimeException_t ); + + virtual void SAL_CALL addListEntryListener( const XListEntryListener_t& ) + throw( NullPointerException_t, + RuntimeException_t ); + + virtual void SAL_CALL removeListEntryListener( const XListEntryListener_t&) + throw( NullPointerException_t, + RuntimeException_t ); + + + + // + // XValidator: + // + + virtual sal_Bool SAL_CALL isValid( + const Any_t& ) + throw( RuntimeException_t ); + + virtual rtl::OUString SAL_CALL explainInvalid( + const Any_t& ) + throw( RuntimeException_t ); + + virtual void SAL_CALL addValidityConstraintListener( + const XValidityConstraintListener_t& xListener ) + throw( NullPointerException_t, + RuntimeException_t ); + + virtual void SAL_CALL removeValidityConstraintListener( + const XValidityConstraintListener_t& xListener ) + throw( NullPointerException_t, + RuntimeException_t ); + + + // + // XModifyBroadcaster & friends: + // inform listeners about changes in our values + // + +public: + + virtual void SAL_CALL addModifyListener( + const XModifyListener_t& xListener ) + throw( RuntimeException_t ); + + virtual void SAL_CALL removeModifyListener( + const XModifyListener_t& xListener ) + throw( RuntimeException_t ); + + + + + // + // XNamed: + // get/set name + // + +public: + + virtual rtl::OUString SAL_CALL getName() + throw( RuntimeException_t ); + + virtual void SAL_CALL setName( const rtl::OUString& ) + throw( RuntimeException_t ); + + + + // + // xml::dom::event::XEventListener + // receive an event if our node changed + // + + virtual void SAL_CALL handleEvent( + const XEvent_t& xEvent ) + throw( RuntimeException_t ); + + + + // + // XUnoTunnel + // + + virtual sal_Int64 SAL_CALL getSomething( const IntSequence_t& ) + throw( RuntimeException_t ); + + + // + // XCloneable + // + + virtual XCloneable_t SAL_CALL createClone() + throw( RuntimeException_t ); +}; + + +} // namespace xforms + +#endif diff --git a/forms/source/xforms/boolexpression.cxx b/forms/source/xforms/boolexpression.cxx new file mode 100644 index 000000000000..c8d7572b5f56 --- /dev/null +++ b/forms/source/xforms/boolexpression.cxx @@ -0,0 +1,59 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include "boolexpression.hxx" + + +namespace xforms +{ + +/** BoolExpression represents a computed XPath expression that returns + * a bool value and caches the results. + * + * As this class has no virtual methods, it should never be used + * polymorphically. */ + +BoolExpression::BoolExpression() : ComputedExpression() +{ +} + +BoolExpression::~BoolExpression() +{ +} + +void BoolExpression::setExpression( const rtl::OUString& rExpression ) +{ + ComputedExpression::setExpression( rExpression ); + mbIsSimple = _checkExpression( " *(true)|(false) *\\( *\\) *" ); +} + + +} // namespace xforms + diff --git a/forms/source/xforms/boolexpression.hxx b/forms/source/xforms/boolexpression.hxx new file mode 100644 index 000000000000..2c34a98b4fed --- /dev/null +++ b/forms/source/xforms/boolexpression.hxx @@ -0,0 +1,55 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _BOOLEXPRESSION_HXX +#define _BOOLEXPRESSION_HXX + +// include for parent class +#include "computedexpression.hxx" + +namespace xforms +{ + +/** BoolExpression represents a computed XPath expression that returns + * a bool value and caches the results. + * + * As this class has no virtual methods, it should never be used + * polymorphically. */ +class BoolExpression : public ComputedExpression +{ +public: + BoolExpression(); + ~BoolExpression(); + + /// set the expression string + /// (overridden for new definition of a simple expression) + void setExpression( const rtl::OUString& rExpression ); +}; + +} // namespace xforms + +#endif diff --git a/forms/source/xforms/collection.hxx b/forms/source/xforms/collection.hxx new file mode 100644 index 000000000000..2c083a969306 --- /dev/null +++ b/forms/source/xforms/collection.hxx @@ -0,0 +1,337 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _COLLECTION_HXX +#define _COLLECTION_HXX + +#include "enumeration.hxx" + +#include <cppuhelper/implbase3.hxx> +#include <com/sun/star/container/ElementExistException.hpp> +#include <com/sun/star/container/NoSuchElementException.hpp> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/container/XSet.hpp> +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/container/XContainerListener.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/WrappedTargetException.hpp> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/uno/Type.hxx> +#include <vector> +#include <algorithm> + + +typedef cppu::WeakImplHelper3< + com::sun::star::container::XIndexReplace, + com::sun::star::container::XSet, + com::sun::star::container::XContainer> +Collection_t; + +template<class ELEMENT_TYPE> +class Collection : public Collection_t +{ +public: + typedef ELEMENT_TYPE T; + typedef com::sun::star::uno::Reference<com::sun::star::container::XContainerListener> XContainerListener_t; + typedef std::vector<XContainerListener_t> Listeners_t; + +protected: + std::vector<T> maItems; + Listeners_t maListeners; + +public: + + Collection() {} + virtual ~Collection() {} + + const T& getItem( sal_Int32 n ) const + { + OSL_ENSURE( isValidIndex(n), "invalid index" ); + OSL_ENSURE( isValid( maItems[n] ), "invalid item found" ); + return maItems[n]; + } + + void setItem( sal_Int32 n, const T& t) + { + OSL_ENSURE( isValidIndex(n), "invalid index" ); + OSL_ENSURE( isValid ( t ), "invalid item" ); + + T& aRef = maItems[ n ]; + _elementReplaced( n, t ); + _remove( aRef ); + aRef = t; + _insert( t ); + } + + bool hasItem( const T& t ) const + { + return maItems.end() != std::find( maItems.begin(), maItems.end(), t ); + } + + sal_Int32 addItem( const T& t ) + { + OSL_ENSURE( !hasItem( t ), "item to be added already present" ); + OSL_ENSURE( isValid( t ), "invalid item" ); + + maItems.push_back( t ); + _insert( t ); + _elementInserted( maItems.size() - 1 ); + return ( maItems.size() - 1 ); + } + + void removeItem( const T& t ) + { + OSL_ENSURE( hasItem( t ), "item to be removed not present" ); + OSL_ENSURE( isValid( t ), "an invalid item, funny that!" ); + + _elementRemoved( t ); + _remove( t ); + maItems.erase( std::find( maItems.begin(), maItems.end(), t ) ); + } + + bool hasItems() const + { + return maItems.size() != 0; + } + + sal_Int32 countItems() const + { + return static_cast<sal_Int32>( maItems.size() ); + } + + bool isValidIndex( sal_Int32 n ) const + { + return n >= 0 && n < static_cast<sal_Int32>( maItems.size() ); + } + + + // the following method may be overriden by sub-classes for + // customized behaviour + + /// called before insertion to determine whether item is valid + virtual bool isValid( const T& ) const { return true; } + + +protected: + + // the following methods may be overriden by sub-classes for + // customized behaviour + + /// called after item has been inserted into the collection + virtual void _insert( const T& ) { } + + /// called before item is removed from the collection + virtual void _remove( const T& ) { } + +public: + + typedef com::sun::star::uno::Type Type_t; + typedef com::sun::star::uno::Any Any_t; + typedef com::sun::star::uno::RuntimeException RuntimeException_t; + typedef com::sun::star::lang::IllegalArgumentException IllegalArgumentException_t; + typedef com::sun::star::container::NoSuchElementException NoSuchElementException_t; + typedef com::sun::star::lang::IndexOutOfBoundsException IndexOutOfBoundsException_t; + typedef com::sun::star::uno::Reference<com::sun::star::container::XEnumeration> XEnumeration_t; + typedef com::sun::star::lang::WrappedTargetException WrappedTargetException_t; + typedef com::sun::star::container::ElementExistException ElementExistException_t; + + + // XElementAccess + virtual Type_t SAL_CALL getElementType() + throw( RuntimeException_t ) + { + return getCppuType( static_cast<T*>( NULL ) ); + } + + virtual sal_Bool SAL_CALL hasElements() + throw( RuntimeException_t ) + { + return hasItems(); + } + + // XIndexAccess : XElementAccess + virtual sal_Int32 SAL_CALL getCount() + throw( RuntimeException_t ) + { + return countItems(); + } + + virtual Any_t SAL_CALL getByIndex( sal_Int32 nIndex ) + throw( IndexOutOfBoundsException_t, + WrappedTargetException_t, + RuntimeException_t) + { + if( isValidIndex( nIndex ) ) + return com::sun::star::uno::makeAny( getItem( nIndex ) ); + else + throw IndexOutOfBoundsException_t(); + } + + // XIndexReplace : XIndexAccess + virtual void SAL_CALL replaceByIndex( sal_Int32 nIndex, + const Any_t& aElement ) + throw( IllegalArgumentException_t, + IndexOutOfBoundsException_t, + WrappedTargetException_t, + RuntimeException_t) + { + T t; + if( isValidIndex( nIndex) ) + if( ( aElement >>= t ) && isValid( t ) ) + setItem( nIndex, t ); + else + throw IllegalArgumentException_t(); + else + throw IndexOutOfBoundsException_t(); + } + + // XEnumerationAccess : XElementAccess + virtual XEnumeration_t SAL_CALL createEnumeration() + throw( RuntimeException_t ) + { + return new Enumeration( this ); + } + + + // XSet : XEnumerationAccess + virtual sal_Bool SAL_CALL has( const Any_t& aElement ) + throw( RuntimeException_t ) + { + T t; + return ( aElement >>= t ) ? hasItem( t ) : sal_False; + } + + virtual void SAL_CALL insert( const Any_t& aElement ) + throw( IllegalArgumentException_t, + ElementExistException_t, + RuntimeException_t ) + { + T t; + if( ( aElement >>= t ) && isValid( t ) ) + if( ! hasItem( t ) ) + addItem( t ); + else + throw ElementExistException_t(); + else + throw IllegalArgumentException_t(); + } + + virtual void SAL_CALL remove( const Any_t& aElement ) + throw( IllegalArgumentException_t, + NoSuchElementException_t, + RuntimeException_t ) + { + T t; + if( aElement >>= t ) + if( hasItem( t ) ) + removeItem( t ); + else + throw NoSuchElementException_t(); + else + throw IllegalArgumentException_t(); + } + + + // XContainer + virtual void SAL_CALL addContainerListener( + const XContainerListener_t& xListener ) + throw( RuntimeException_t ) + { + OSL_ENSURE( xListener.is(), "need listener!" ); + if( std::find( maListeners.begin(), maListeners.end(), xListener) + == maListeners.end() ) + maListeners.push_back( xListener ); + } + + virtual void SAL_CALL removeContainerListener( + const XContainerListener_t& xListener ) + throw( RuntimeException_t ) + { + OSL_ENSURE( xListener.is(), "need listener!" ); + Listeners_t::iterator aIter = + std::find( maListeners.begin(), maListeners.end(), xListener ); + if( aIter != maListeners.end() ) + maListeners.erase( aIter ); + } + +protected: + + // call listeners: + void _elementInserted( sal_Int32 nPos ) + { + OSL_ENSURE( isValidIndex(nPos), "invalid index" ); + com::sun::star::container::ContainerEvent aEvent( + static_cast<com::sun::star::container::XIndexReplace*>( this ), + com::sun::star::uno::makeAny( nPos ), + com::sun::star::uno::makeAny( getItem( nPos ) ), + com::sun::star::uno::Any() ); + for( Listeners_t::iterator aIter = maListeners.begin(); + aIter != maListeners.end(); + aIter++ ) + { + (*aIter)->elementInserted( aEvent ); + } + } + + void _elementRemoved( const T& aOld ) + { + com::sun::star::container::ContainerEvent aEvent( + static_cast<com::sun::star::container::XIndexReplace*>( this ), + com::sun::star::uno::Any(), + com::sun::star::uno::makeAny( aOld ), + com::sun::star::uno::Any() ); + for( Listeners_t::iterator aIter = maListeners.begin(); + aIter != maListeners.end(); + aIter++ ) + { + (*aIter)->elementRemoved( aEvent ); + } + } + + void _elementReplaced( const sal_Int32 nPos, const T& aNew ) + { + OSL_ENSURE( isValidIndex(nPos), "invalid index" ); + com::sun::star::container::ContainerEvent aEvent( + static_cast<com::sun::star::container::XIndexReplace*>( this ), + com::sun::star::uno::makeAny( nPos ), + com::sun::star::uno::makeAny( getItem( nPos ) ), + com::sun::star::uno::makeAny( aNew ) ); + for( Listeners_t::iterator aIter = maListeners.begin(); + aIter != maListeners.end(); + aIter++ ) + { + (*aIter)->elementReplaced( aEvent ); + } + } + +}; + +#endif diff --git a/forms/source/xforms/computedexpression.cxx b/forms/source/xforms/computedexpression.cxx new file mode 100644 index 000000000000..540cfd2f6d5b --- /dev/null +++ b/forms/source/xforms/computedexpression.cxx @@ -0,0 +1,246 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include "computedexpression.hxx" +#include "unohelper.hxx" +#include "evaluationcontext.hxx" +#include "NameContainer.hxx" + +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/xml/dom/NodeType.hpp> +#include <com/sun/star/xml/dom/XNode.hpp> +#include <com/sun/star/xml/xpath/XXPathAPI.hpp> +#include <com/sun/star/xml/xpath/XXPathObject.hpp> +#include <com/sun/star/xml/xpath/XXPathExtension.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/util/SearchAlgorithms.hpp> + +#include <unotools/textsearch.hxx> +#include <comphelper/processfactory.hxx> + +using rtl::OUString; +using com::sun::star::beans::NamedValue; +using com::sun::star::uno::Any; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::lang::XInitialization; +using com::sun::star::lang::XMultiServiceFactory; +using com::sun::star::xml::dom::XNode; +using com::sun::star::container::XNameContainer; +using com::sun::star::xml::xpath::XXPathAPI; +using com::sun::star::xml::xpath::XXPathExtension; +using com::sun::star::xml::xpath::XXPathObject; +using com::sun::star::uno::RuntimeException; +using com::sun::star::uno::Exception; +using com::sun::star::uno::UNO_QUERY_THROW; +using com::sun::star::xml::xpath::XPathObjectType_XPATH_UNDEFINED; +using com::sun::star::util::SearchOptions; +using com::sun::star::util::SearchAlgorithms_REGEXP; + + +namespace xforms +{ + +ComputedExpression::ComputedExpression() + : msExpression(), + mbIsEmpty( true ), + mbIsSimple( true ), + mxResult() +{ +} + +ComputedExpression::~ComputedExpression() +{ +} + + +OUString ComputedExpression::getExpression() const +{ + return msExpression; +} + +void ComputedExpression::setExpression( const OUString& rExpression ) +{ + // set new expression, and clear pre-computed results + msExpression = rExpression; + mbIsEmpty = _checkExpression( " *" ); + mbIsSimple = false; + mxResult.clear(); +} + + +bool ComputedExpression::_checkExpression( const sal_Char* pExpression ) const +{ + OSL_ENSURE( pExpression != NULL, "no expression?" ); + + // call RegExp engine + SearchOptions aSearchOptions; + aSearchOptions.algorithmType = SearchAlgorithms_REGEXP; + aSearchOptions.searchString = String( pExpression, RTL_TEXTENCODING_ASCII_US ); + utl::TextSearch aTextSearch( aSearchOptions ); + + xub_StrLen nLength = + static_cast<xub_StrLen>( msExpression.getLength() ); + xub_StrLen nStart = 0; + xub_StrLen nEnd = nLength; + int nSearch = aTextSearch.SearchFrwrd( msExpression, &nStart, &nEnd ); + + // our expression is static only if 1) we found our regexp, and 2) + // the regexp goes from beginning to end. + return ( nLength == 0 || nSearch != 0 ) + && ( nStart == 0 && nEnd == nLength ); +} + +/// do we have an actual expression? +bool ComputedExpression::isEmptyExpression() const +{ + return mbIsEmpty; +} + +bool ComputedExpression::isSimpleExpression() const +{ + // actual work is done by setExpression + return mbIsEmpty || mbIsSimple; +} + + +const OUString ComputedExpression::_getExpressionForEvaluation() const +{ + // the default implementation is to do nothing... + return msExpression; +} + +bool ComputedExpression::_evaluate( + const xforms::EvaluationContext& rContext, + const OUString& sExpression ) +{ + OSL_ENSURE( rContext.mxContextNode.is(), "no context node in context" ); + + // obtain value by evaluating XPath expression + mxResult.clear(); + try + { + mxResult = _getXPathAPI(rContext)->eval( rContext.mxContextNode, + sExpression ); + } + catch( const Exception& ) + { + ; // ignore exception -> mxResult will be empty + } + + return hasValue(); +} + +bool ComputedExpression::evaluate( const EvaluationContext& rContext ) +{ + // for simple expression we don't need to re-evaluate (if we have + // an older result); neither for empty expressions + if( mbIsEmpty || (mxResult.is() && mbIsSimple) ) + return true; + + return _evaluate( rContext, _getExpressionForEvaluation() ); +} + + +bool ComputedExpression::hasValue() const +{ + return mxResult.is() && + mxResult->getObjectType() != XPathObjectType_XPATH_UNDEFINED; +} + +void ComputedExpression::clear() +{ + mxResult.clear(); +} + +Reference<XXPathObject> ComputedExpression::getXPath() +{ + return mxResult; +} + +OUString ComputedExpression::getString( const rtl::OUString& rDefault ) const +{ + return mxResult.is() ? mxResult->getString() : rDefault; +} + +bool ComputedExpression::getBool( bool bDefault ) const +{ + return mxResult.is() ? mxResult->getBoolean() : bDefault; +} + + + + +Reference<XXPathAPI> ComputedExpression::_getXPathAPI(const xforms::EvaluationContext& aContext) +{ + // create XPath API, then register namespaces + Reference<XXPathAPI> xXPath( createInstance( + OUSTRING( "com.sun.star.xml.xpath.XPathAPI" ) ), + UNO_QUERY_THROW ); + OSL_ENSURE( xXPath.is(), "cannot get XPath API" ); + + // register xforms extension# + Sequence< Any > aSequence(2); + NamedValue aValue; + aValue.Name = OUSTRING("Model"); + aValue.Value <<= aContext.mxModel; + aSequence[0] <<= aValue; + aValue.Name = OUSTRING("ContextNode"); + aValue.Value <<= aContext.mxContextNode; + aSequence[1] <<= aValue; + Reference<XMultiServiceFactory> aFactory = comphelper::getProcessServiceFactory(); + Reference< XXPathExtension > aExtension( aFactory->createInstanceWithArguments( + OUSTRING( "com.sun.star.comp.xml.xpath.XFormsExtension"), aSequence), UNO_QUERY_THROW); + xXPath->registerExtensionInstance(aExtension); + + // register namespaces + if( aContext.mxNamespaces.is() ) + { + Sequence<OUString> aPrefixes =aContext.mxNamespaces->getElementNames(); + sal_Int32 nCount = aPrefixes.getLength(); + const OUString* pPrefixes = aPrefixes.getConstArray(); + for( sal_Int32 i = 0; i < nCount; i++ ) + { + const OUString* pNamePrefix = &pPrefixes[i]; + OUString sNameURL; + aContext.mxNamespaces->getByName( *pNamePrefix ) >>= sNameURL; + xXPath->registerNS( *pNamePrefix, sNameURL ); + } + } + + // done, so return xXPath-object + return xXPath; +} + + +} // namespace xforms diff --git a/forms/source/xforms/computedexpression.hxx b/forms/source/xforms/computedexpression.hxx new file mode 100644 index 000000000000..6a1581cc8d0b --- /dev/null +++ b/forms/source/xforms/computedexpression.hxx @@ -0,0 +1,138 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _COMPUTEDEXPRESSION_HXX +#define _COMPUTEDEXPRESSION_HXX + + +// includes for member variables +#include <rtl/ustring.hxx> +#include <com/sun/star/uno/Reference.hxx> + +// forward declaractions +namespace com { namespace sun { namespace star +{ + namespace xml + { + namespace dom { class XNode; } + namespace dom { class XNodeset; } + namespace xpath { class XXPathAPI; } + namespace xpath { class XXPathObject; } + } + namespace container { class XNameContainer; } +} } } +namespace xforms { class EvaluationContext; } + + + +namespace xforms +{ + +/** ComputedExpression represents an XPath Expression and caches results. + * + * As this class has no virtual methods, it should never be used + * polymorphically. */ +class ComputedExpression +{ + /// the expression string + rtl::OUString msExpression; + + /// is msExpression empty? + bool mbIsEmpty; + +protected: + /// is msExpression a simple expression? + bool mbIsSimple; + + /// the result from the last bind + com::sun::star::uno::Reference<com::sun::star::xml::xpath::XXPathObject> mxResult; + + + /// implementation of isSimpleExpression + bool _checkExpression( const sal_Char* pExpression ) const; + + /// allow manipulation of the expression before it is evaluated + const rtl::OUString _getExpressionForEvaluation() const; + + /// obtain a (suitable) XPathAPI implementation + com::sun::star::uno::Reference<com::sun::star::xml::xpath::XXPathAPI> _getXPathAPI(const xforms::EvaluationContext& aContext); + + /// evaluate the expression relative to the content node. + bool _evaluate( const xforms::EvaluationContext& rContext, + const rtl::OUString& sExpression ); + + +public: + ComputedExpression(); + ~ComputedExpression(); + + + /// get the expression string + rtl::OUString getExpression() const; + + /// set a new expression string + void setExpression( const rtl::OUString& rExpression ); + + /// get the namespaces that are used to interpret the expression string + com::sun::star::uno::Reference<com::sun::star::container::XNameContainer> getNamespaces() const; + + /// set the namespaces that are used to interpret the expression string + void setNamespaces( const com::sun::star::uno::Reference<com::sun::star::container::XNameContainer>& ); + + /// do we have an actual expression? + bool isEmptyExpression() const; + + /// heuristically determine whether this expression is 'simple', + /// i.e. whether its value will change depending on the values + /// of other nodes + bool isSimpleExpression() const; + + + /// evaluate the expression relative to the content node. + bool evaluate( const xforms::EvaluationContext& rContext ); + + + /// does this expression have a value? + bool hasValue() const; + + + /// remove value/evaluate results + void clear(); + + + // get the result of this expression as string/bool/... + // (Results will be based on the last call of evaluate(..). The caller + // must call evaluate to ensure current results.) + com::sun::star::uno::Reference<com::sun::star::xml::xpath::XXPathObject> getXPath(); + bool getBool( bool bDefault = false ) const; + rtl::OUString getString( const rtl::OUString& rDefault = rtl::OUString() ) const; + +}; + +} // namespace xforms + +#endif diff --git a/forms/source/xforms/convert.cxx b/forms/source/xforms/convert.cxx new file mode 100644 index 000000000000..7ea6e35a5284 --- /dev/null +++ b/forms/source/xforms/convert.cxx @@ -0,0 +1,627 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include "convert.hxx" + +#include "unohelper.hxx" +#include <memory> +#include <algorithm> +#include <functional> +#include <rtl/math.hxx> +#include <rtl/ustrbuf.hxx> +#include <tools/date.hxx> +#include <com/sun/star/uno/Type.hxx> +#include <com/sun/star/xsd/WhiteSpaceTreatment.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/Time.hpp> + +using xforms::Convert; +using ::rtl::OUString; +using ::rtl::OUStringBuffer; +using com::sun::star::uno::Any; +using com::sun::star::uno::makeAny; +using com::sun::star::util::Time; +using namespace std; + +typedef com::sun::star::util::Date UNODate; +typedef com::sun::star::util::Time UNOTime; +typedef com::sun::star::util::DateTime UNODateTime; + +Convert::Convert() + : maMap() +{ + init(); +} + +#define ADD_ENTRY(XCONVERT,TYPE) XCONVERT->maMap[ getCppuType( static_cast<TYPE*>( NULL ) ) ] = Convert_t( &lcl_toXSD_##TYPE, &lcl_toAny_##TYPE ) + +namespace +{ + // ======================================================================== + struct StringToken + { + private: + ::rtl::OUString m_sString; + sal_Int32 m_nTokenStart; + sal_Int32 m_nTokenEnd; + + public: + StringToken() : m_sString(), m_nTokenStart( 0 ), m_nTokenEnd( 0 ) { } + StringToken( const ::rtl::OUString& _rString, sal_Int32 _nTokenStart, sal_Int32 _nTokenEnd ); + StringToken( const StringToken& ); + StringToken& operator=( const StringToken& ); + + inline bool isEmpty() const { return m_nTokenEnd <= m_nTokenStart; } + inline sal_Int32 getLength() const { return isEmpty() ? 0 : m_nTokenEnd - m_nTokenStart - 1; } + inline const sal_Unicode* begin() const { return m_sString.getStr() + m_nTokenStart; } + inline const sal_Unicode* end() const { return m_sString.getStr() + m_nTokenEnd; } + + bool toInt32( sal_Int32& _rValue ) const; + }; + + // ------------------------------------------------------------------------ + StringToken::StringToken( const ::rtl::OUString& _rString, sal_Int32 _nTokenStart, sal_Int32 _nTokenEnd ) + :m_sString( _rString ) + ,m_nTokenStart( _nTokenStart ) + ,m_nTokenEnd( _nTokenEnd ) + { + OSL_ENSURE( ( m_nTokenStart >= 0 ) && ( m_nTokenStart <= m_sString.getLength() ), "StringToken::StringToken: invalid token start!" ); + OSL_ENSURE( ( m_nTokenEnd >= 0 ) && ( m_nTokenEnd <= m_sString.getLength() ), "StringToken::StringToken: invalid token end!" ); + } + + // ------------------------------------------------------------------------ + StringToken::StringToken( const StringToken& _rRHS ) + { + *this = _rRHS; + } + + // ------------------------------------------------------------------------ + StringToken& StringToken::operator=( const StringToken& _rRHS ) + { + if ( this == &_rRHS ) + return *this; + + m_sString = _rRHS.m_sString; + m_nTokenStart = _rRHS.m_nTokenStart; + m_nTokenEnd = _rRHS.m_nTokenEnd; + + return *this; + } + + // ------------------------------------------------------------------------ + bool StringToken::toInt32( sal_Int32& _rValue ) const + { + if ( isEmpty() ) + return false; + + _rValue = 0; + const sal_Unicode* pStr = begin(); + while ( pStr < end() ) + { + if ( ( *pStr < '0' ) || ( *pStr > '9' ) ) + return false; + + _rValue *= 10; + _rValue += ( *pStr - '0' ); + + ++pStr; + } + + return true; + } + + // ======================================================================== + class StringTokenizer + { + private: + ::rtl::OUString m_sString; + const sal_Unicode m_nTokenSeparator; + sal_Int32 m_nTokenStart; + + public: + /** constructs a tokenizer + @param _rString the string to tokenize + @param _nTokenSeparator the token value. May be 0, in this case the tokenizer + will recognize exactly one token, being the whole string. + This may make sense if you want to apply <type>StringToken</type> + methods to a whole string. + */ + StringTokenizer( const ::rtl::OUString& _rString, sal_Unicode _nTokenSeparator = ';' ); + + /// resets the tokenizer to the beginning of the string + void reset(); + + /// determines whether there is a next token + bool hasNextToken() const; + + /// retrieves the next token + StringToken + getNextToken(); + }; + + // ------------------------------------------------------------------------ + StringTokenizer::StringTokenizer( const ::rtl::OUString& _rString, sal_Unicode _nTokenSeparator ) + :m_sString( _rString ) + ,m_nTokenSeparator( _nTokenSeparator ) + { + reset(); + } + + // ------------------------------------------------------------------------ + void StringTokenizer::reset() + { + m_nTokenStart = 0; + } + + // ------------------------------------------------------------------------ + bool StringTokenizer::hasNextToken() const + { + return ( m_nTokenStart < m_sString.getLength() ); + } + + // ------------------------------------------------------------------------ + StringToken StringTokenizer::getNextToken() + { + OSL_PRECOND( hasNextToken(), "StringTokenizer::getNextToken: there is no next token!" ); + if ( !hasNextToken() ) + return StringToken(); + + // determine the end of the current token + sal_Int32 nTokenEnd = m_nTokenSeparator ? m_sString.indexOf( m_nTokenSeparator, m_nTokenStart ) : m_sString.getLength(); + bool bLastToken = !m_nTokenSeparator || ( nTokenEnd == -1 ); + + // construct a new token + StringToken aToken( m_sString, m_nTokenStart, bLastToken ? m_sString.getLength() : nTokenEnd ); + // advance + m_nTokenStart = bLastToken ? m_sString.getLength() : nTokenEnd + 1; + // outta here + return aToken; + } + + // ======================================================================== + // ------------------------------------------------------------------------ + OUString lcl_toXSD_OUString( const Any& rAny ) + { OUString sStr; rAny >>= sStr; return sStr; } + + // ------------------------------------------------------------------------ + Any lcl_toAny_OUString( const OUString& rStr ) + { Any aAny; aAny <<= rStr; return aAny; } + + // ------------------------------------------------------------------------ + OUString lcl_toXSD_bool( const Any& rAny ) + { bool b = false; rAny >>= b; return b ? OUSTRING("true") : OUSTRING("false"); } + + // ------------------------------------------------------------------------ + Any lcl_toAny_bool( const OUString& rStr ) + { + bool b = ( rStr == OUSTRING("true") || rStr == OUSTRING("1") ); + return makeAny( b ); + } + + // ------------------------------------------------------------------------ + OUString lcl_toXSD_double( const Any& rAny ) + { + double f = 0.0; + rAny >>= f; + + return rtl::math::isFinite( f ) + ? rtl::math::doubleToUString( f, rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, '.', + sal_True ) + : OUString(); + } + + // ------------------------------------------------------------------------ + Any lcl_toAny_double( const OUString& rString ) + { + rtl_math_ConversionStatus eStatus; + double f = rtl::math::stringToDouble( + rString, sal_Unicode('.'), sal_Unicode(','), &eStatus, NULL ); + return ( eStatus == rtl_math_ConversionStatus_Ok ) ? makeAny( f ) : Any(); + } + + // ------------------------------------------------------------------------ + void lcl_appendInt32ToBuffer( const sal_Int32 _nValue, ::rtl::OUStringBuffer& _rBuffer, sal_Int16 _nMinDigits ) + { + if ( ( _nMinDigits >= 4 ) && ( _nValue < 1000 ) ) + _rBuffer.append( (sal_Unicode)'0' ); + if ( ( _nMinDigits >= 3 ) && ( _nValue < 100 ) ) + _rBuffer.append( (sal_Unicode)'0' ); + if ( ( _nMinDigits >= 2 ) && ( _nValue < 10 ) ) + _rBuffer.append( (sal_Unicode)'0' ); + _rBuffer.append( _nValue ); + } + + // ------------------------------------------------------------------------ + OUString lcl_toXSD_UNODate_typed( const UNODate& rDate ) + { + + ::rtl::OUStringBuffer sInfo; + lcl_appendInt32ToBuffer( rDate.Year, sInfo, 4 ); + sInfo.appendAscii( "-" ); + lcl_appendInt32ToBuffer( rDate.Month, sInfo, 2 ); + sInfo.appendAscii( "-" ); + lcl_appendInt32ToBuffer( rDate.Day, sInfo, 2 ); + + return sInfo.makeStringAndClear(); + } + + // ------------------------------------------------------------------------ + OUString lcl_toXSD_UNODate( const Any& rAny ) + { + UNODate aDate; + OSL_VERIFY( rAny >>= aDate ); + return lcl_toXSD_UNODate_typed( aDate ); + } + + // ------------------------------------------------------------------------ + UNODate lcl_toUNODate( const OUString& rString ) + { + bool bWellformed = true; + + UNODate aDate( 1, 1, 1900 ); + + sal_Int32 nToken = 0; + StringTokenizer aTokenizer( rString, '-' ); + while ( aTokenizer.hasNextToken() ) + { + sal_Int32 nTokenValue = 0; + if ( !aTokenizer.getNextToken().toInt32( nTokenValue ) ) + { + bWellformed = false; + break; + } + + if ( nToken == 0 ) + aDate.Year = (sal_uInt16)nTokenValue; + else if ( nToken == 1 ) + aDate.Month = (sal_uInt16)nTokenValue; + else if ( nToken == 2 ) + aDate.Day = (sal_uInt16)nTokenValue; + else + { + bWellformed = false; + break; + } + ++nToken; + } + + // sanity checks + if ( ( aDate.Year > 9999 ) || ( aDate.Month < 1 ) || ( aDate.Month > 12 ) || ( aDate.Day < 1 ) || ( aDate.Day > 31 ) ) + bWellformed = false; + else + { + ::Date aDateCheck( 1, aDate.Month, aDate.Year ); + if ( aDate.Day > aDateCheck.GetDaysInMonth() ) + bWellformed = false; + } + + // all okay? + if ( !bWellformed ) + return UNODate( 1, 1, 1900 ); + + return aDate; + } + + // ------------------------------------------------------------------------ + Any lcl_toAny_UNODate( const OUString& rString ) + { + return makeAny( lcl_toUNODate( rString ) ); + } + + // ------------------------------------------------------------------------ + OUString lcl_toXSD_UNOTime_typed( const UNOTime& rTime ) + { + + ::rtl::OUStringBuffer sInfo; + lcl_appendInt32ToBuffer( rTime.Hours, sInfo, 2 ); + sInfo.appendAscii( ":" ); + lcl_appendInt32ToBuffer( rTime.Minutes, sInfo, 2 ); + sInfo.appendAscii( ":" ); + lcl_appendInt32ToBuffer( rTime.Seconds, sInfo, 2 ); + if ( rTime.HundredthSeconds ) + { + sInfo.appendAscii( "." ); + lcl_appendInt32ToBuffer( rTime.HundredthSeconds, sInfo, 2 ); + } + + return sInfo.makeStringAndClear(); + } + + // ------------------------------------------------------------------------ + OUString lcl_toXSD_UNOTime( const Any& rAny ) + { + UNOTime aTime; + OSL_VERIFY( rAny >>= aTime ); + return lcl_toXSD_UNOTime_typed( aTime ); + } + + // ------------------------------------------------------------------------ + UNOTime lcl_toUNOTime( const OUString& rString ) + { + bool bWellformed = true; + + UNOTime aTime( 0, 0, 0, 0 ); + + ::rtl::OUString sString( rString ); + // see if there's a decimal separator for the seconds, + // and if so, handle it separately + sal_Int32 nDecimalSepPos = rString.indexOf( '.' ); + if ( nDecimalSepPos == -1 ) + // ISO 8601 allows for both a comma and a dot + nDecimalSepPos = rString.indexOf( ',' ); + if ( nDecimalSepPos != -1 ) + { + // handle fractional seconds + ::rtl::OUString sFractional = sString.copy( nDecimalSepPos + 1 ); + if ( sFractional.getLength() > 2 ) + // our precision is HundrethSeconds - it's all a css.util.Time can hold + sFractional = sFractional.copy( 0, 2 ); + sal_Int32 nFractional = 0; + if ( sFractional.getLength() ) + { + if ( StringTokenizer( sFractional, 0 ).getNextToken().toInt32( nFractional ) ) + { + aTime.HundredthSeconds = (sal_uInt16)nFractional; + if ( nFractional < 10 ) + aTime.HundredthSeconds *= 10; + } + else + bWellformed = false; + } + + // strip the fraction before further processing + sString = sString.copy( 0, nDecimalSepPos ); + } + + // split into the tokens which are separated by colon + sal_Int32 nToken = 0; + StringTokenizer aTokenizer( sString, ':' ); + while ( aTokenizer.hasNextToken() ) + { + sal_Int32 nTokenValue = 0; + if ( !aTokenizer.getNextToken().toInt32( nTokenValue ) ) + { + bWellformed = false; + break; + } + + if ( nToken == 0 ) + aTime.Hours = (sal_uInt16)nTokenValue; + else if ( nToken == 1 ) + aTime.Minutes = (sal_uInt16)nTokenValue; + else if ( nToken == 2 ) + aTime.Seconds = (sal_uInt16)nTokenValue; + else + { + bWellformed = false; + break; + } + ++nToken; + } + + // sanity checks + // note that Seconds == 60 denotes leap seconds. Normally, they're not allowed everywhere, + // but we accept them all the time for simplicity reasons + if ( ( aTime.Hours > 24 ) + || ( aTime.Minutes > 59 ) + || ( aTime.Seconds > 60 ) + ) + bWellformed = false; + + if ( bWellformed + && ( aTime.Hours == 24 ) + && ( ( aTime.Minutes != 0 ) + || ( aTime.Seconds != 0 ) + || ( aTime.HundredthSeconds != 0 ) + ) + ) + bWellformed = false; + + // all okay? + if ( !bWellformed ) + return UNOTime( 0, 0, 0, 0 ); + + return aTime; + } + + // ------------------------------------------------------------------------ + Any lcl_toAny_UNOTime( const OUString& rString ) + { + return makeAny( lcl_toUNOTime( rString ) ); + } + + // ------------------------------------------------------------------------ + OUString lcl_toXSD_UNODateTime( const Any& rAny ) + { + UNODateTime aDateTime; + OSL_VERIFY( rAny >>= aDateTime ); + + UNODate aDate( aDateTime.Day, aDateTime.Month, aDateTime.Year ); + ::rtl::OUString sDate = lcl_toXSD_UNODate_typed( aDate ); + + UNOTime aTime( aDateTime.HundredthSeconds, aDateTime.Seconds, aDateTime.Minutes, aDateTime.Hours ); + ::rtl::OUString sTime = lcl_toXSD_UNOTime_typed( aTime ); + + ::rtl::OUStringBuffer sInfo; + sInfo.append( sDate ); + sInfo.append( (sal_Unicode) 'T' ); + sInfo.append( sTime ); + return sInfo.makeStringAndClear(); + } + + // ------------------------------------------------------------------------ + Any lcl_toAny_UNODateTime( const OUString& rString ) + { + // separate the date from the time part + sal_Int32 nDateTimeSep = rString.indexOf( 'T' ); + if ( nDateTimeSep == -1 ) + nDateTimeSep = rString.indexOf( 't' ); + + UNODate aDate; + UNOTime aTime; + if ( nDateTimeSep == -1 ) + { // no time part + aDate = lcl_toUNODate( rString ); + aTime = UNOTime( 0, 0, 0, 0 ); + } + else + { + aDate = lcl_toUNODate( rString.copy( 0, nDateTimeSep ) ); + aTime = lcl_toUNOTime( rString.copy( nDateTimeSep + 1 ) ); + } + UNODateTime aDateTime( + aTime.HundredthSeconds, aTime.Seconds, aTime.Minutes, aTime.Hours, + aDate.Day, aDate.Month, aDate.Year + ); + return makeAny( aDateTime ); + } +} + +// ============================================================================ +void Convert::init() +{ + ADD_ENTRY( this, OUString ); + ADD_ENTRY( this, bool ); + ADD_ENTRY( this, double ); + ADD_ENTRY( this, UNODate ); + ADD_ENTRY( this, UNOTime ); + ADD_ENTRY( this, UNODateTime ); +} + + +Convert& Convert::get() +{ + // create our Singleton instance on demand + static Convert* pConvert = NULL; + if( pConvert == NULL ) + pConvert = new Convert(); + + OSL_ENSURE( pConvert != NULL, "no converter?" ); + return *pConvert; +} + +bool Convert::hasType( const Type_t& rType ) +{ + return maMap.find( rType ) != maMap.end(); +} + +Convert::Types_t Convert::getTypes() +{ + Types_t aTypes( maMap.size() ); + transform( maMap.begin(), maMap.end(), aTypes.getArray(), + select1st<Map_t::value_type>() ); + return aTypes; +} + +rtl::OUString Convert::toXSD( const Any_t& rAny ) +{ + Map_t::iterator aIter = maMap.find( rAny.getValueType() ); + return aIter != maMap.end() ? aIter->second.first( rAny ) : OUString(); +} + +Convert::Any_t Convert::toAny( const rtl::OUString& rValue, + const Type_t& rType ) +{ + Map_t::iterator aIter = maMap.find( rType ); + return aIter != maMap.end() ? aIter->second.second( rValue ) : Any_t(); +} + +//------------------------------------------------------------------------ +::rtl::OUString Convert::convertWhitespace( const ::rtl::OUString& _rString, sal_Int16 _nWhitespaceTreatment ) +{ + ::rtl::OUString sConverted; + switch( _nWhitespaceTreatment ) + { + default: + OSL_ENSURE( sal_False, "Convert::convertWhitespace: invalid whitespace treatment constant!" ); + // NO break + case com::sun::star::xsd::WhiteSpaceTreatment::Preserve: + sConverted = _rString; + break; + case com::sun::star::xsd::WhiteSpaceTreatment::Replace: + sConverted = replaceWhitespace( _rString ); + break; + case com::sun::star::xsd::WhiteSpaceTreatment::Collapse: + sConverted = collapseWhitespace( _rString ); + break; + } + return sConverted; +} + +//------------------------------------------------------------------------ +::rtl::OUString Convert::replaceWhitespace( const ::rtl::OUString& _rString ) +{ + OUStringBuffer aBuffer( _rString ); + sal_Int32 nLength = aBuffer.getLength(); + const sal_Unicode* pBuffer = aBuffer.getStr(); + for( sal_Int32 i = 0; i < nLength; i++ ) + { + sal_Unicode c = pBuffer[i]; + if( c == sal_Unicode(0x08) || + c == sal_Unicode(0x0A) || + c == sal_Unicode(0x0D) ) + aBuffer.setCharAt( i, sal_Unicode(0x20) ); + } + return aBuffer.makeStringAndClear(); +} + +//------------------------------------------------------------------------ +::rtl::OUString Convert::collapseWhitespace( const ::rtl::OUString& _rString ) +{ + sal_Int32 nLength = _rString.getLength(); + OUStringBuffer aBuffer( nLength ); + const sal_Unicode* pStr = _rString.getStr(); + bool bStrip = true; + for( sal_Int32 i = 0; i < nLength; i++ ) + { + sal_Unicode c = pStr[i]; + if( c == sal_Unicode(0x08) || + c == sal_Unicode(0x0A) || + c == sal_Unicode(0x0D) || + c == sal_Unicode(0x20) ) + { + if( ! bStrip ) + { + aBuffer.append( sal_Unicode(0x20) ); + bStrip = true; + } + } + else + { + bStrip = false; + aBuffer.append( c ); + } + } + if( aBuffer[ aBuffer.getLength() - 1 ] == sal_Unicode( 0x20 ) ) + aBuffer.setLength( aBuffer.getLength() - 1 ); + return aBuffer.makeStringAndClear(); +} diff --git a/forms/source/xforms/convert.hxx b/forms/source/xforms/convert.hxx new file mode 100644 index 000000000000..750399879ee0 --- /dev/null +++ b/forms/source/xforms/convert.hxx @@ -0,0 +1,113 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CONVERT_HXX +#define _CONVERT_HXX + +#include <com/sun/star/uno/Sequence.hxx> +#include <map> + +namespace com { namespace sun { namespace star { namespace uno +{ + class Any; + class Type; +} } } } +namespace rtl { class OUString; } +class ConvertImpl; + +namespace xforms +{ + +struct TypeLess +{ + bool operator()( const com::sun::star::uno::Type& rType1, + const com::sun::star::uno::Type& rType2 ) const + { return rType1.getTypeName() < rType2.getTypeName(); } +}; + +class Convert +{ + typedef com::sun::star::uno::Type Type_t; + typedef com::sun::star::uno::Sequence<com::sun::star::uno::Type> Types_t; + typedef com::sun::star::uno::Any Any_t; + + // hold conversion objects + typedef rtl::OUString (*fn_toXSD)( const Any_t& ); + typedef Any_t (*fn_toAny)( const rtl::OUString& ); + typedef std::pair<fn_toXSD,fn_toAny> Convert_t; + typedef std::map<Type_t,Convert_t,TypeLess> Map_t; + Map_t maMap; + + Convert(); + + void init(); + +public: + /** get/create Singleton class */ + static Convert& get(); + + /// can we convert this type? + bool hasType( const Type_t& ); + + /// get list of convertable types + Types_t getTypes(); + + /// convert any to XML representation + rtl::OUString toXSD( const Any_t& rAny ); + + /// convert XML representation to Any of given type + Any_t toAny( const rtl::OUString&, const Type_t& ); + + /** translates the whitespaces in a given string, according + to a given <type scope="com::sun::star::xsd">WhiteSpaceTreatment</type>. + + @param _rString + the string to convert + @param _nWhitespaceTreatment + a constant from the <type scope="com::sun::star::xsd">WhiteSpaceTreatment</type> group, specifying + how to handle whitespaces + @return + the converted string + */ + static ::rtl::OUString convertWhitespace( + const ::rtl::OUString& _rString, + sal_Int16 _nWhitespaceTreatment + ); + + /** replace all occurences 0x08, 0x0A, 0x0D with 0x20 + */ + static ::rtl::OUString replaceWhitespace( const ::rtl::OUString& _rString ); + + /** replace all sequences of 0x08, 0x0A, 0x0D, 0x20 with a single 0x20. + also strip leading/trailing whitespace. + */ + static ::rtl::OUString collapseWhitespace( const ::rtl::OUString& _rString ); +}; + +} // namespace xforms + +#endif diff --git a/forms/source/xforms/datatyperepository.cxx b/forms/source/xforms/datatyperepository.cxx new file mode 100644 index 000000000000..8a9a4847af62 --- /dev/null +++ b/forms/source/xforms/datatyperepository.cxx @@ -0,0 +1,298 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#ifndef FORMS_SOURCE_XFORMS_DATATYPEREPOSITORY_HXX +#include "datatyperepository.hxx" +#endif +#include "datatypes.hxx" +#ifndef _FRM_RESOURCE_HRC_ +#include "frm_resource.hrc" +#endif +#include "frm_resource.hxx" +#include "frm_strings.hxx" +#ifndef _FRM_PROPERTY_HRC_ +#include "property.hrc" +#endif + +/** === begin UNO includes === **/ +/** === end UNO includes === **/ +#include <tools/debug.hxx> +#include <comphelper/enumhelper.hxx> + +#include <functional> +#include <algorithm> + +//........................................................................ +namespace xforms +{ +//........................................................................ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::Type; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::util::VetoException; + using ::com::sun::star::container::NoSuchElementException; + using ::com::sun::star::container::ElementExistException; + using ::com::sun::star::container::XEnumeration; + using ::com::sun::star::lang::WrappedTargetException; + using ::com::sun::star::xsd::XDataType; + using namespace frm; + + //==================================================================== + //= ODataTypeRepository + //==================================================================== + DBG_NAME( ODataTypeRepository ) + //-------------------------------------------------------------------- + ODataTypeRepository::ODataTypeRepository( ) + { + DBG_CTOR( ODataTypeRepository, NULL ); + + // insert some basic types + ::rtl::OUString sName( FRM_RES_STRING( RID_STR_DATATYPE_STRING ) ); + m_aRepository[ sName ] = new OStringType( sName, ::com::sun::star::xsd::DataTypeClass::STRING ); + + sName = FRM_RES_STRING( RID_STR_DATATYPE_URL ); + m_aRepository[ sName ] = new OStringType( sName, ::com::sun::star::xsd::DataTypeClass::anyURI ); + + sName = FRM_RES_STRING( RID_STR_DATATYPE_BOOLEAN ); + m_aRepository[ sName ] = new OBooleanType( sName ); + + sName = FRM_RES_STRING( RID_STR_DATATYPE_DECIMAL ); + m_aRepository[ sName ] = new ODecimalType( sName, ::com::sun::star::xsd::DataTypeClass::DECIMAL ); + + sName = FRM_RES_STRING( RID_STR_DATATYPE_FLOAT ); + m_aRepository[ sName ] = new ODecimalType( sName, ::com::sun::star::xsd::DataTypeClass::FLOAT ); + + sName = FRM_RES_STRING( RID_STR_DATATYPE_DOUBLE ); + m_aRepository[ sName ] = new ODecimalType( sName, ::com::sun::star::xsd::DataTypeClass::DOUBLE ); + + sName = FRM_RES_STRING( RID_STR_DATATYPE_DATE ); + m_aRepository[ sName ] = new ODateType( sName ); + + sName = FRM_RES_STRING( RID_STR_DATATYPE_TIME ); + m_aRepository[ sName ] = new OTimeType( sName ); + + sName = FRM_RES_STRING( RID_STR_DATATYPE_DATETIME ); + m_aRepository[ sName ] = new ODateTimeType( sName ); + + sName = FRM_RES_STRING( RID_STR_DATATYPE_YEAR ); + m_aRepository[ sName ] = new OShortIntegerType( sName, ::com::sun::star::xsd::DataTypeClass::gYear ); + + sName = FRM_RES_STRING( RID_STR_DATATYPE_MONTH ); + m_aRepository[ sName ] = new OShortIntegerType( sName, ::com::sun::star::xsd::DataTypeClass::gMonth ); + + sName = FRM_RES_STRING( RID_STR_DATATYPE_DAY ); + m_aRepository[ sName ] = new OShortIntegerType( sName, ::com::sun::star::xsd::DataTypeClass::gDay ); + } + + //-------------------------------------------------------------------- + ODataTypeRepository::~ODataTypeRepository( ) + { + DBG_DTOR( ODataTypeRepository, NULL ); + } + + //-------------------------------------------------------------------- + ODataTypeRepository::Repository::iterator ODataTypeRepository::implLocate( const ::rtl::OUString& _rName, bool _bAllowMiss ) SAL_THROW( ( NoSuchElementException ) ) + { + Repository::iterator aTypePos = m_aRepository.find( _rName ); + if ( aTypePos == m_aRepository.end() && !_bAllowMiss ) + throw NoSuchElementException( ::rtl::OUString(), *this ); + + return aTypePos; + } + + //-------------------------------------------------------------------- + Reference< XDataType > SAL_CALL ODataTypeRepository::getBasicDataType( sal_Int16 dataTypeClass ) throw (NoSuchElementException, RuntimeException) + { + Reference< XDataType > xReturn; + + for ( Repository::const_iterator lookup = m_aRepository.begin(); + ( lookup != m_aRepository.end() ) && ! xReturn.is(); + ++lookup + ) + { + if ( lookup->second->getIsBasic() && ( lookup->second->getTypeClass() == dataTypeClass ) ) + xReturn = lookup->second.get(); + } + + if ( !xReturn.is() ) + throw NoSuchElementException( ::rtl::OUString(), *this ); + + return xReturn; + } + + //-------------------------------------------------------------------- + Reference< XDataType > SAL_CALL ODataTypeRepository::cloneDataType( const ::rtl::OUString& sourceName, const ::rtl::OUString& newName ) throw (NoSuchElementException, ElementExistException, RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + Repository::iterator aTypePos = implLocate( newName, true ); + if ( aTypePos != m_aRepository.end() ) + throw ElementExistException( ::rtl::OUString(), *this ); + + aTypePos = implLocate( sourceName ); + OXSDDataType* pClone = aTypePos->second->clone( newName ); + m_aRepository[ newName ] = pClone; + + return pClone; + } + + //-------------------------------------------------------------------- + void SAL_CALL ODataTypeRepository::revokeDataType( const ::rtl::OUString& typeName ) throw (NoSuchElementException, VetoException, RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + Repository::iterator aTypePos = implLocate( typeName ); + if ( aTypePos->second->getIsBasic() ) + throw VetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "This is a built-in type and cannot be removed." ) ), *this ); + // TODO: localize this error message + + m_aRepository.erase( aTypePos ); + } + + //-------------------------------------------------------------------- + Reference< XDataType > SAL_CALL ODataTypeRepository::getDataType( const ::rtl::OUString& typeName ) throw (NoSuchElementException, RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return implLocate( typeName, false )->second.get(); + } + + + //-------------------------------------------------------------------- + Reference< XEnumeration > SAL_CALL ODataTypeRepository::createEnumeration( ) throw (RuntimeException) + { + return new ::comphelper::OEnumerationByName( this ); + } + + //-------------------------------------------------------------------- + Any SAL_CALL ODataTypeRepository::getByName( const ::rtl::OUString& aName ) throw (NoSuchElementException, WrappedTargetException, RuntimeException) + { + return makeAny( getDataType( aName ) ); + } + + //-------------------------------------------------------------------- + Sequence< ::rtl::OUString > SAL_CALL ODataTypeRepository::getElementNames( ) throw (RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + Sequence< ::rtl::OUString > aNames( m_aRepository.size() ); + ::std::transform( + m_aRepository.begin(), + m_aRepository.end(), + aNames.getArray(), + ::std::select1st< Repository::value_type >() + ); + return aNames; + } + + //-------------------------------------------------------------------- + sal_Bool SAL_CALL ODataTypeRepository::hasByName( const ::rtl::OUString& aName ) throw (RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return m_aRepository.find( aName ) != m_aRepository.end(); + } + + //-------------------------------------------------------------------- + Type SAL_CALL ODataTypeRepository::getElementType( ) throw (RuntimeException) + { + return ::getCppuType( static_cast< Reference< XDataType >* >( NULL ) ); + } + + //-------------------------------------------------------------------- + sal_Bool SAL_CALL ODataTypeRepository::hasElements( ) throw (RuntimeException) + { + return !m_aRepository.empty(); + } + + //-------------------------------------------------------------------- + // type specific implementation of registerProperties, using explicit + // template instantiations + + template<> + void OValueLimitedType<com::sun::star::util::Date>::registerProperties() + { + OValueLimitedType_Base::registerProperties(); + + REGISTER_VOID_PROP( XSD_MAX_INCLUSIVE_DATE, m_aMaxInclusive, ValueType ); + REGISTER_VOID_PROP( XSD_MAX_EXCLUSIVE_DATE, m_aMaxExclusive, ValueType ); + REGISTER_VOID_PROP( XSD_MIN_INCLUSIVE_DATE, m_aMinInclusive, ValueType ); + REGISTER_VOID_PROP( XSD_MIN_EXCLUSIVE_DATE, m_aMinExclusive, ValueType ); + } + + template<> + void OValueLimitedType<com::sun::star::util::Time>::registerProperties() + { + OValueLimitedType_Base::registerProperties(); + + REGISTER_VOID_PROP( XSD_MAX_INCLUSIVE_TIME, m_aMaxInclusive, ValueType ); + REGISTER_VOID_PROP( XSD_MAX_EXCLUSIVE_TIME, m_aMaxExclusive, ValueType ); + REGISTER_VOID_PROP( XSD_MIN_INCLUSIVE_TIME, m_aMinInclusive, ValueType ); + REGISTER_VOID_PROP( XSD_MIN_EXCLUSIVE_TIME, m_aMinExclusive, ValueType ); + } + + template<> + void OValueLimitedType<com::sun::star::util::DateTime>::registerProperties() + { + OValueLimitedType_Base::registerProperties(); + + REGISTER_VOID_PROP( XSD_MAX_INCLUSIVE_DATE_TIME, m_aMaxInclusive, ValueType ); + REGISTER_VOID_PROP( XSD_MAX_EXCLUSIVE_DATE_TIME, m_aMaxExclusive, ValueType ); + REGISTER_VOID_PROP( XSD_MIN_INCLUSIVE_DATE_TIME, m_aMinInclusive, ValueType ); + REGISTER_VOID_PROP( XSD_MIN_EXCLUSIVE_DATE_TIME, m_aMinExclusive, ValueType ); + } + + template<> + void OValueLimitedType<double>::registerProperties() + { + OValueLimitedType_Base::registerProperties(); + + REGISTER_VOID_PROP( XSD_MAX_INCLUSIVE_DOUBLE, m_aMaxInclusive, ValueType ); + REGISTER_VOID_PROP( XSD_MAX_EXCLUSIVE_DOUBLE, m_aMaxExclusive, ValueType ); + REGISTER_VOID_PROP( XSD_MIN_INCLUSIVE_DOUBLE, m_aMinInclusive, ValueType ); + REGISTER_VOID_PROP( XSD_MIN_EXCLUSIVE_DOUBLE, m_aMinExclusive, ValueType ); + } + + template<> + void OValueLimitedType<sal_Int16>::registerProperties() + { + OValueLimitedType_Base::registerProperties(); + + REGISTER_VOID_PROP( XSD_MAX_INCLUSIVE_INT, m_aMaxInclusive, ValueType ); + REGISTER_VOID_PROP( XSD_MAX_EXCLUSIVE_INT, m_aMaxExclusive, ValueType ); + REGISTER_VOID_PROP( XSD_MIN_INCLUSIVE_INT, m_aMinInclusive, ValueType ); + REGISTER_VOID_PROP( XSD_MIN_EXCLUSIVE_INT, m_aMinExclusive, ValueType ); + } +//........................................................................ +} // namespace xforms +//........................................................................ + diff --git a/forms/source/xforms/datatyperepository.hxx b/forms/source/xforms/datatyperepository.hxx new file mode 100644 index 000000000000..f680079ebf4b --- /dev/null +++ b/forms/source/xforms/datatyperepository.hxx @@ -0,0 +1,98 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef OFFAPI_COM_SUN_STAR_XFORMS_DATATYPEREPOSITORY_HXX +#define OFFAPI_COM_SUN_STAR_XFORMS_DATATYPEREPOSITORY_HXX + +/** === begin UNO includes === **/ +#include <com/sun/star/xforms/XDataTypeRepository.hpp> +/** === end UNO includes === **/ +#include <cppuhelper/implbase1.hxx> +#include <rtl/ref.hxx> + +#include <map> + +//........................................................................ +namespace xforms +{ +//........................................................................ + + class OXSDDataType; + //==================================================================== + //= ODataTypeRepository + //==================================================================== + typedef ::cppu::WeakImplHelper1 < ::com::sun::star::xforms::XDataTypeRepository + > ODataTypeRepository_Base; + class ODataTypeRepository : public ODataTypeRepository_Base + { + private: + typedef ::rtl::Reference< OXSDDataType > DataType; + typedef ::std::map< ::rtl::OUString, DataType > Repository; + + ::osl::Mutex m_aMutex; + Repository m_aRepository; + + public: + ODataTypeRepository( ); + + protected: + ~ODataTypeRepository( ); + + // XDataTypeRepository + virtual ::com::sun::star::uno::Reference< ::com::sun::star::xsd::XDataType > SAL_CALL getBasicDataType( sal_Int16 dataTypeClass ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::xsd::XDataType > SAL_CALL cloneDataType( const ::rtl::OUString& sourceName, const ::rtl::OUString& newName ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::container::ElementExistException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL revokeDataType( const ::rtl::OUString& typeName ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::util::VetoException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::xsd::XDataType > SAL_CALL getDataType( const ::rtl::OUString& typeName ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException); + + // XEnumerationAccess (base of XDataTypeRepository) + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL createEnumeration( ) throw (::com::sun::star::uno::RuntimeException); + + // XNameAccess (base of XDataTypeRepository) + virtual ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) throw (::com::sun::star::uno::RuntimeException); + + // XElementAccess (base of XEnumerationAccess and XNameAccess) + virtual ::com::sun::star::uno::Type SAL_CALL getElementType( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasElements( ) throw (::com::sun::star::uno::RuntimeException); + + private: + ODataTypeRepository( const ODataTypeRepository& ); // never implemented + ODataTypeRepository& operator=( const ODataTypeRepository& ); // never implemented + + private: + /** locates the type with the given name in our repository, or throws an exception if there is no such type + */ + Repository::iterator implLocate( const ::rtl::OUString& _rName, bool _bAllowMiss = false ) SAL_THROW( ( ::com::sun::star::container::NoSuchElementException ) ); + }; + +//........................................................................ +} // namespace xforms +//........................................................................ + +#endif // OFFAPI_COM_SUN_STAR_XFORMS_DATATYPEREPOSITORY_HXX + diff --git a/forms/source/xforms/datatypes.cxx b/forms/source/xforms/datatypes.cxx new file mode 100644 index 000000000000..212b5f721e67 --- /dev/null +++ b/forms/source/xforms/datatypes.cxx @@ -0,0 +1,995 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" +#include "datatypes.hxx" +#include "resourcehelper.hxx" +#ifndef _FRM_PROPERTY_HRC_ +#include "property.hrc" +#endif +#include "convert.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/xsd/WhiteSpaceTreatment.hpp> +/** === end UNO includes === **/ +#include <tools/debug.hxx> +#include <tools/datetime.hxx> +#include <rtl/math.hxx> + +//........................................................................ +namespace xforms +{ +//........................................................................ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::uno::Type; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::util::VetoException; + using ::com::sun::star::util::Date; + using ::com::sun::star::util::Time; + using ::com::sun::star::util::DateTime; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::lang::WrappedTargetException; + using ::com::sun::star::beans::UnknownPropertyException; + using ::com::sun::star::beans::PropertyVetoException; + using ::com::sun::star::beans::XPropertyChangeListener; + using ::com::sun::star::beans::XVetoableChangeListener; + + using ::com::sun::star::beans::PropertyAttribute::BOUND; + using ::com::sun::star::beans::PropertyAttribute::READONLY; + + using namespace ::com::sun::star::xsd; + using namespace ::frm; + U_NAMESPACE_USE + + //==================================================================== + //= OXSDDataType + //==================================================================== + //-------------------------------------------------------------------- + OXSDDataType::OXSDDataType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass ) + :OXSDDataType_PBase( m_aBHelper ) + ,m_bIsBasic( sal_True ) + ,m_nTypeClass( _nTypeClass ) + ,m_sName( _rName ) + ,m_nWST( WhiteSpaceTreatment::Preserve ) + ,m_bPatternMatcherDirty( true ) + { + } + + //-------------------------------------------------------------------- + OXSDDataType::~OXSDDataType() + { + } + + //-------------------------------------------------------------------- + void OXSDDataType::registerProperties() + { + registerProperty( PROPERTY_NAME, PROPERTY_ID_NAME, BOUND, &m_sName, ::getCppuType( &m_sName ) ); + registerProperty( PROPERTY_XSD_WHITESPACE, PROPERTY_ID_XSD_WHITESPACE, BOUND, &m_nWST, ::getCppuType( &m_nWST ) ); + registerProperty( PROPERTY_XSD_PATTERN, PROPERTY_ID_XSD_PATTERN, BOUND, &m_sPattern, ::getCppuType( &m_sPattern ) ); + + registerProperty( PROPERTY_XSD_IS_BASIC, PROPERTY_ID_XSD_IS_BASIC, READONLY, &m_bIsBasic, ::getCppuType( &m_bIsBasic ) ); + registerProperty( PROPERTY_XSD_TYPE_CLASS, PROPERTY_ID_XSD_TYPE_CLASS, READONLY, &m_nTypeClass, ::getCppuType( &m_nTypeClass ) ); + } + + //-------------------------------------------------------------------- + void OXSDDataType::initializeClone( const OXSDDataType& _rCloneSource ) + { + m_bIsBasic = sal_False; + m_nTypeClass = _rCloneSource.m_nTypeClass; + m_sPattern = _rCloneSource.m_sPattern; + m_nWST = _rCloneSource.m_nWST; + } + + //-------------------------------------------------------------------- + OXSDDataType* OXSDDataType::clone( const ::rtl::OUString& _rNewName ) const + { + OXSDDataType* pClone = createClone( _rNewName ); + pClone->initializeClone( *this ); + return pClone; + } + + //-------------------------------------------------------------------- + IMPLEMENT_FORWARD_XINTERFACE2( OXSDDataType, OXSDDataType_Base, ::comphelper::OPropertyContainer ) + + //-------------------------------------------------------------------- + IMPLEMENT_FORWARD_XTYPEPROVIDER2( OXSDDataType, OXSDDataType_Base, ::comphelper::OPropertyContainer ) + +#define SET_PROPERTY( propertyid, value, member ) \ + setFastPropertyValue( PROPERTY_ID_##propertyid, makeAny( value ) ); \ + OSL_POSTCOND( member == value, "OXSDDataType::setFoo: inconsistency!" ); + + //-------------------------------------------------------------------- + ::rtl::OUString SAL_CALL OXSDDataType::getName( ) throw (RuntimeException) + { + return m_sName; + } + + //-------------------------------------------------------------------- + void SAL_CALL OXSDDataType::setName( const ::rtl::OUString& aName ) throw (RuntimeException, VetoException) + { + // TODO: check the name for conflicts in the repository + SET_PROPERTY( NAME, aName, m_sName ); + } + + //-------------------------------------------------------------------- + ::rtl::OUString SAL_CALL OXSDDataType::getPattern() throw (RuntimeException) + { + return m_sPattern; + } + + //-------------------------------------------------------------------- + void SAL_CALL OXSDDataType::setPattern( const ::rtl::OUString& _pattern ) throw (RuntimeException) + { + SET_PROPERTY( XSD_PATTERN, _pattern, m_sPattern ); + } + + //-------------------------------------------------------------------- + sal_Int16 SAL_CALL OXSDDataType::getWhiteSpaceTreatment() throw (RuntimeException) + { + return m_nWST; + } + + //-------------------------------------------------------------------- + void SAL_CALL OXSDDataType::setWhiteSpaceTreatment( sal_Int16 _whitespacetreatment ) throw (RuntimeException, IllegalArgumentException) + { + SET_PROPERTY( XSD_WHITESPACE, _whitespacetreatment, m_nWST ); + } + + //-------------------------------------------------------------------- + sal_Bool SAL_CALL OXSDDataType::getIsBasic() throw (RuntimeException) + { + return m_bIsBasic; + } + + + //-------------------------------------------------------------------- + sal_Int16 SAL_CALL OXSDDataType::getTypeClass() throw (RuntimeException) + { + return m_nTypeClass; + } + + //-------------------------------------------------------------------- + sal_Bool OXSDDataType::validate( const ::rtl::OUString& sValue ) throw( RuntimeException ) + { + return ( _validate( sValue ) == 0 ); + } + + //-------------------------------------------------------------------- + ::rtl::OUString OXSDDataType::explainInvalid( const ::rtl::OUString& sValue ) throw( RuntimeException ) + { + // get reason + sal_uInt16 nReason = _validate( sValue ); + + // get resource and return localized string + return ( nReason == 0 ) + ? ::rtl::OUString() + : getResource( nReason, sValue, + _explainInvalid( nReason ) ); + } + + //-------------------------------------------------------------------- + ::rtl::OUString OXSDDataType::_explainInvalid( sal_uInt16 nReason ) + { + if ( RID_STR_XFORMS_PATTERN_DOESNT_MATCH == nReason ) + { + OSL_ENSURE( m_sPattern.getLength(), "OXSDDataType::_explainInvalid: how can this error occur without a regular expression?" ); + return m_sPattern; + } + return ::rtl::OUString(); + } + + //-------------------------------------------------------------------- + namespace + { + static void lcl_initializePatternMatcher( ::std::auto_ptr< RegexMatcher >& _rpMatcher, const ::rtl::OUString& _rPattern ) + { + UErrorCode nMatchStatus = U_ZERO_ERROR; + UnicodeString aIcuPattern( reinterpret_cast<const UChar *>(_rPattern.getStr()), _rPattern.getLength() ); // UChar != sal_Unicode in MinGW + _rpMatcher.reset( new RegexMatcher( aIcuPattern, 0, nMatchStatus ) ); + OSL_ENSURE( U_SUCCESS( nMatchStatus ), "lcl_initializePatternMatcher: invalid pattern property!" ); + // if asserts, then something changed our pattern without going to convertFastPropertyValue/checkPropertySanity + } + + static bool lcl_matchString( RegexMatcher& _rMatcher, const ::rtl::OUString& _rText ) + { + UErrorCode nMatchStatus = U_ZERO_ERROR; + UnicodeString aInput( reinterpret_cast<const UChar *>(_rText.getStr()), _rText.getLength() ); // UChar != sal_Unicode in MinGW + _rMatcher.reset( aInput ); + if ( _rMatcher.matches( nMatchStatus ) ) + { + int32_t nStart = _rMatcher.start( nMatchStatus ); + int32_t nEnd = _rMatcher.end ( nMatchStatus ); + if ( ( nStart == 0 ) && ( nEnd == _rText.getLength() ) ) + return true; + } + + return false; + } + } + + //-------------------------------------------------------------------- + sal_uInt16 OXSDDataType::_validate( const ::rtl::OUString& _rValue ) + { + // care for the whitespaces + ::rtl::OUString sConverted = Convert::convertWhitespace( _rValue, m_nWST ); + + // care for the regular expression + if ( m_sPattern.getLength() ) + { + // ensure our pattern matcher is up to date + if ( m_bPatternMatcherDirty ) + { + lcl_initializePatternMatcher( m_pPatternMatcher, m_sPattern ); + m_bPatternMatcherDirty = false; + } + + // let it match the string + if ( !lcl_matchString( *m_pPatternMatcher.get(), _rValue ) ) + return RID_STR_XFORMS_PATTERN_DOESNT_MATCH; + } + + return 0; + } + + //-------------------------------------------------------------------- + sal_Bool OXSDDataType::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) throw(IllegalArgumentException) + { + // let the base class do the conversion + if ( !OXSDDataType_PBase::convertFastPropertyValue( _rConvertedValue, _rOldValue, _nHandle, _rValue ) ) + return sal_False; + + // sanity checks + ::rtl::OUString sErrorMessage; + if ( !checkPropertySanity( _nHandle, _rConvertedValue, sErrorMessage ) ) + { + IllegalArgumentException aException; + aException.Message = sErrorMessage; + aException.Context = *this; + throw IllegalArgumentException( aException ); + } + + return sal_True; + } + + //-------------------------------------------------------------------- + void SAL_CALL OXSDDataType::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw (Exception) + { + OXSDDataType_PBase::setFastPropertyValue_NoBroadcast( _nHandle, _rValue ); + if ( _nHandle == PROPERTY_ID_XSD_PATTERN ) + m_bPatternMatcherDirty = true; + } + + //-------------------------------------------------------------------- + bool OXSDDataType::checkPropertySanity( sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rNewValue, ::rtl::OUString& _rErrorMessage ) + { + if ( _nHandle == PROPERTY_ID_XSD_PATTERN ) + { + ::rtl::OUString sPattern; + OSL_VERIFY( _rNewValue >>= sPattern ); + + UnicodeString aIcuPattern( reinterpret_cast<const UChar *>(sPattern.getStr()), sPattern.getLength() ); // UChar != sal_Unicode in MinGW + UErrorCode nMatchStatus = U_ZERO_ERROR; + RegexMatcher aMatcher( aIcuPattern, 0, nMatchStatus ); + if ( U_FAILURE( nMatchStatus ) ) + { + _rErrorMessage = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "This is no valid pattern." ) ); + return false; + } + } + return true; + } + + //-------------------------------------------------------------------- + void SAL_CALL OXSDDataType::setPropertyValue( const ::rtl::OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) + { + OXSDDataType_PBase::setPropertyValue( aPropertyName, aValue ); + } + + //-------------------------------------------------------------------- + Any SAL_CALL OXSDDataType::getPropertyValue( const ::rtl::OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) + { + return OXSDDataType_PBase::getPropertyValue( PropertyName ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OXSDDataType::addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) + { + OXSDDataType_PBase::addPropertyChangeListener( aPropertyName, xListener ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OXSDDataType::removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const Reference< XPropertyChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) + { + OXSDDataType_PBase::removePropertyChangeListener( aPropertyName, aListener ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OXSDDataType::addVetoableChangeListener( const ::rtl::OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) + { + OXSDDataType_PBase::addVetoableChangeListener( PropertyName, aListener ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OXSDDataType::removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) + { + OXSDDataType_PBase::removeVetoableChangeListener( PropertyName, aListener ); + } + + //==================================================================== + //= OValueLimitedType_Base + //==================================================================== + OValueLimitedType_Base::OValueLimitedType_Base( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass ) + :OXSDDataType( _rName, _nTypeClass ) + ,m_fCachedMaxInclusive( 0 ) + ,m_fCachedMaxExclusive( 0 ) + ,m_fCachedMinInclusive( 0 ) + ,m_fCachedMinExclusive( 0 ) + { + } + + //-------------------------------------------------------------------- + void OValueLimitedType_Base::initializeClone( const OXSDDataType& _rCloneSource ) + { + OXSDDataType::initializeClone( _rCloneSource ); + initializeTypedClone( static_cast< const OValueLimitedType_Base& >( _rCloneSource ) ); + } + + //-------------------------------------------------------------------- + void OValueLimitedType_Base::initializeTypedClone( const OValueLimitedType_Base& _rCloneSource ) + { + m_aMaxInclusive = _rCloneSource.m_aMaxInclusive; + m_aMaxExclusive = _rCloneSource.m_aMaxExclusive; + m_aMinInclusive = _rCloneSource.m_aMinInclusive; + m_aMinExclusive = _rCloneSource.m_aMinExclusive; + m_fCachedMaxInclusive = _rCloneSource.m_fCachedMaxInclusive; + m_fCachedMaxExclusive = _rCloneSource.m_fCachedMaxExclusive; + m_fCachedMinInclusive = _rCloneSource.m_fCachedMinInclusive; + m_fCachedMinExclusive = _rCloneSource.m_fCachedMinExclusive; + } + + //-------------------------------------------------------------------- + void SAL_CALL OValueLimitedType_Base::setFastPropertyValue_NoBroadcast( + sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rValue ) throw (::com::sun::star::uno::Exception) + { + OXSDDataType::setFastPropertyValue_NoBroadcast( _nHandle, _rValue ); + + // if one of our limit properties has been set, translate it into a double + // value, for later efficient validation + switch ( _nHandle ) + { + case PROPERTY_ID_XSD_MAX_INCLUSIVE_INT: + case PROPERTY_ID_XSD_MAX_INCLUSIVE_DOUBLE: + case PROPERTY_ID_XSD_MAX_INCLUSIVE_DATE: + case PROPERTY_ID_XSD_MAX_INCLUSIVE_TIME: + case PROPERTY_ID_XSD_MAX_INCLUSIVE_DATE_TIME: + if ( m_aMaxInclusive.hasValue() ) + normalizeValue( m_aMaxInclusive, m_fCachedMaxInclusive ); + else + m_fCachedMaxInclusive = 0; + break; + case PROPERTY_ID_XSD_MAX_EXCLUSIVE_INT: + case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DOUBLE: + case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DATE: + case PROPERTY_ID_XSD_MAX_EXCLUSIVE_TIME: + case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DATE_TIME: + if ( m_aMaxExclusive.hasValue() ) + normalizeValue( m_aMaxExclusive, m_fCachedMaxExclusive ); + else + m_fCachedMaxExclusive = 0; + break; + case PROPERTY_ID_XSD_MIN_INCLUSIVE_INT: + case PROPERTY_ID_XSD_MIN_INCLUSIVE_DOUBLE: + case PROPERTY_ID_XSD_MIN_INCLUSIVE_DATE: + case PROPERTY_ID_XSD_MIN_INCLUSIVE_TIME: + case PROPERTY_ID_XSD_MIN_INCLUSIVE_DATE_TIME: + if ( m_aMinInclusive.hasValue() ) + normalizeValue( m_aMinInclusive, m_fCachedMinInclusive ); + else + m_fCachedMinInclusive = 0; + break; + case PROPERTY_ID_XSD_MIN_EXCLUSIVE_INT: + case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DOUBLE: + case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DATE: + case PROPERTY_ID_XSD_MIN_EXCLUSIVE_TIME: + case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DATE_TIME: + if ( m_aMinExclusive.hasValue() ) + normalizeValue( m_aMinExclusive, m_fCachedMinExclusive ); + else + m_fCachedMinExclusive = 0; + break; + } + } + + //-------------------------------------------------------------------- + bool OValueLimitedType_Base::_getValue( const ::rtl::OUString& rValue, double& fValue ) + { + // convert to double + rtl_math_ConversionStatus eStatus; + sal_Int32 nEnd; + double f = ::rtl::math::stringToDouble( + rValue, sal_Unicode('.'), sal_Unicode(0), &eStatus, &nEnd ); + + // error checking... + bool bReturn = false; + if( eStatus == rtl_math_ConversionStatus_Ok + && nEnd == rValue.getLength() ) + { + bReturn = true; + fValue = f; + } + return bReturn; + } + + //-------------------------------------------------------------------- + sal_uInt16 OValueLimitedType_Base::_validate( const ::rtl::OUString& rValue ) + { + sal_uInt16 nReason = OXSDDataType::_validate( rValue ); + if( nReason == 0 ) + { + + // convert value and check format + double f; + if( ! _getValue( rValue, f ) ) + nReason = RID_STR_XFORMS_VALUE_IS_NOT_A; + + // check range + else if( ( m_aMaxInclusive.hasValue() ) && f > m_fCachedMaxInclusive ) + nReason = RID_STR_XFORMS_VALUE_MAX_INCL; + else if( ( m_aMaxExclusive.hasValue() ) && f >= m_fCachedMaxExclusive ) + nReason = RID_STR_XFORMS_VALUE_MAX_EXCL; + else if( ( m_aMinInclusive.hasValue() ) && f < m_fCachedMinInclusive ) + nReason = RID_STR_XFORMS_VALUE_MIN_INCL; + else if( ( m_aMinExclusive.hasValue() ) && f <= m_fCachedMinExclusive ) + nReason = RID_STR_XFORMS_VALUE_MIN_EXCL; + } + return nReason; + } + + //-------------------------------------------------------------------- + ::rtl::OUString OValueLimitedType_Base::_explainInvalid( sal_uInt16 nReason ) + { + ::rtl::OUStringBuffer sInfo; + switch( nReason ) + { + case 0: + // nothing to do! + break; + + case RID_STR_XFORMS_VALUE_IS_NOT_A: + sInfo.append( getName() ); + break; + + case RID_STR_XFORMS_VALUE_MAX_INCL: + sInfo.append( typedValueAsHumanReadableString( m_aMaxInclusive ) ); + break; + + case RID_STR_XFORMS_VALUE_MAX_EXCL: + sInfo.append( typedValueAsHumanReadableString( m_aMaxExclusive ) ); + break; + + case RID_STR_XFORMS_VALUE_MIN_INCL: + sInfo.append( typedValueAsHumanReadableString( m_aMinInclusive ) ); + break; + + case RID_STR_XFORMS_VALUE_MIN_EXCL: + sInfo.append( typedValueAsHumanReadableString( m_aMinExclusive ) ); + break; + + default: + OSL_ENSURE( false, "OValueLimitedType::_explainInvalid: unknown reason!" ); + break; + } + + return sInfo.makeStringAndClear(); + } + + //==================================================================== + //= OStringType + //==================================================================== + //-------------------------------------------------------------------- + OStringType::OStringType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass ) + :OStringType_Base( _rName, _nTypeClass ) + { + } + + //-------------------------------------------------------------------- + void OStringType::registerProperties() + { + OStringType_Base::registerProperties(); + + REGISTER_VOID_PROP( XSD_LENGTH, m_aLength, sal_Int32 ); + REGISTER_VOID_PROP( XSD_MIN_LENGTH, m_aMinLength, sal_Int32 ); + REGISTER_VOID_PROP( XSD_MAX_LENGTH, m_aMaxLength, sal_Int32 ); + } + + //-------------------------------------------------------------------- + IMPLEMENT_DEFAULT_TYPED_CLONING( OStringType, OStringType_Base ) + + //-------------------------------------------------------------------- + void OStringType::initializeTypedClone( const OStringType& _rCloneSource ) + { + m_aLength = _rCloneSource.m_aLength; + m_aMinLength = _rCloneSource.m_aMinLength; + m_aMaxLength = _rCloneSource.m_aMaxLength; + } + + //-------------------------------------------------------------------- + bool OStringType::checkPropertySanity( sal_Int32 _nHandle, const Any& _rNewValue, ::rtl::OUString& _rErrorMessage ) + { + // let the base class do the conversion + if ( !OStringType_Base::checkPropertySanity( _nHandle, _rNewValue, _rErrorMessage ) ) + return false; + + _rErrorMessage = ::rtl::OUString(); + switch ( _nHandle ) + { + case PROPERTY_ID_XSD_LENGTH: + case PROPERTY_ID_XSD_MIN_LENGTH: + case PROPERTY_ID_XSD_MAX_LENGTH: + { + sal_Int32 nValue( 0 ); + OSL_VERIFY( _rNewValue >>= nValue ); + if ( nValue <= 0 ) + _rErrorMessage = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Length limits must denote positive integer values." ) ); + // TODO/eforms: localize the error message + } + break; + } + + return _rErrorMessage.getLength() == 0; + } + + //-------------------------------------------------------------------- + sal_uInt16 OStringType::_validate( const ::rtl::OUString& rValue ) + { + // check regexp, whitespace etc. in parent class + sal_uInt16 nReason = OStringType_Base::_validate( rValue ); + + if( nReason == 0 ) + { + // check string constraints + sal_Int32 nLength = rValue.getLength(); + sal_Int32 nLimit = 0; + if ( m_aLength >>= nLimit ) + { + if ( nLimit != nLength ) + nReason = RID_STR_XFORMS_VALUE_LENGTH; + } + else + { + if ( ( m_aMaxLength >>= nLimit ) && ( nLength > nLimit ) ) + nReason = RID_STR_XFORMS_VALUE_MAX_LENGTH; + else if ( ( m_aMinLength >>= nLimit ) && ( nLength < nLimit ) ) + nReason = RID_STR_XFORMS_VALUE_MIN_LENGTH; + } + } + return nReason; + } + + //-------------------------------------------------------------------- + ::rtl::OUString OStringType::_explainInvalid( sal_uInt16 nReason ) + { + sal_Int32 nValue = 0; + ::rtl::OUStringBuffer sInfo; + switch( nReason ) + { + case 0: + // nothing to do! + break; + + case RID_STR_XFORMS_VALUE_LENGTH: + if( m_aLength >>= nValue ) + sInfo.append( nValue ); + break; + + case RID_STR_XFORMS_VALUE_MAX_LENGTH: + if( m_aMaxLength >>= nValue ) + sInfo.append( nValue ); + break; + + case RID_STR_XFORMS_VALUE_MIN_LENGTH: + if( m_aMinLength >>= nValue ) + sInfo.append( nValue ); + break; + + default: + sInfo.append( OStringType_Base::_explainInvalid( nReason ) ); + break; + } + return sInfo.makeStringAndClear(); + } + + //==================================================================== + //= OBooleanType + //==================================================================== + //-------------------------------------------------------------------- + OBooleanType::OBooleanType( const ::rtl::OUString& _rName ) + :OBooleanType_Base( _rName, DataTypeClass::BOOLEAN ) + { + } + + //-------------------------------------------------------------------- + IMPLEMENT_DEFAULT_CLONING( OBooleanType, OBooleanType_Base ) + + //-------------------------------------------------------------------- + void OBooleanType::initializeTypedClone( const OBooleanType& /*_rCloneSource*/ ) + { + } + + //-------------------------------------------------------------------- + sal_uInt16 OBooleanType::_validate( const ::rtl::OUString& sValue ) + { + sal_uInt16 nInvalidityReason = OBooleanType_Base::_validate( sValue ); + if ( nInvalidityReason ) + return nInvalidityReason; + + bool bValid = + sValue.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("0")) || + sValue.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("1")) || + sValue.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("true")) || + sValue.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("false")); + return bValid ? 0 : RID_STR_XFORMS_INVALID_VALUE; + } + + //-------------------------------------------------------------------- + ::rtl::OUString OBooleanType::_explainInvalid( sal_uInt16 nReason ) + { + return ( nReason == 0 ) ? ::rtl::OUString() : getName(); + } + + //==================================================================== + //= ODecimalType + //==================================================================== + //-------------------------------------------------------------------- + ODecimalType::ODecimalType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass ) + :ODecimalType_Base( _rName, _nTypeClass ) + { + } + + //-------------------------------------------------------------------- + IMPLEMENT_DEFAULT_TYPED_CLONING( ODecimalType, ODecimalType_Base ) + + //-------------------------------------------------------------------- + void ODecimalType::initializeTypedClone( const ODecimalType& _rCloneSource ) + { + m_aTotalDigits = _rCloneSource.m_aTotalDigits; + m_aFractionDigits = _rCloneSource.m_aFractionDigits; + } + + //-------------------------------------------------------------------- + void ODecimalType::registerProperties() + { + ODecimalType_Base::registerProperties(); + + REGISTER_VOID_PROP( XSD_TOTAL_DIGITS, m_aTotalDigits, sal_Int32 ); + REGISTER_VOID_PROP( XSD_FRACTION_DIGITS, m_aFractionDigits, sal_Int32 ); + } + + //-------------------------------------------------------------------- + + // validate decimals and return code for which facets failed + // to be used by: ODecimalType::validate and ODecimalType::explainInvalid + sal_uInt16 ODecimalType::_validate( const ::rtl::OUString& rValue ) + { + sal_Int16 nReason = ODecimalType_Base::_validate( rValue ); + + // check digits (if no other cause is available so far) + if( nReason == 0 ) + { + sal_Int32 nLength = rValue.getLength(); + sal_Int32 n = 0; + sal_Int32 nTotalDigits = 0; + sal_Int32 nFractionDigits = 0; + const sal_Unicode* pValue = rValue.getStr(); + for( ; pValue[n] != sal_Unicode('.') && n < nLength; n++ ) + if( pValue[n] >= sal_Unicode('0') + && pValue[n] <= sal_Unicode('9')) + nTotalDigits++; + for( ; n < nLength; n++ ) + if( pValue[n] >= sal_Unicode('0') + && pValue[n] <= sal_Unicode('9')) + nFractionDigits++; + nTotalDigits += nFractionDigits; + + sal_Int32 nValue = 0; + if( ( m_aTotalDigits >>= nValue ) && nTotalDigits > nValue ) + nReason = RID_STR_XFORMS_VALUE_TOTAL_DIGITS; + else if( ( m_aFractionDigits >>= nValue ) && + ( nFractionDigits > nValue ) ) + nReason = RID_STR_XFORMS_VALUE_FRACTION_DIGITS; + } + + return nReason; + } + + //-------------------------------------------------------------------- + ::rtl::OUString ODecimalType::_explainInvalid( sal_uInt16 nReason ) + { + sal_Int32 nValue = 0; + ::rtl::OUStringBuffer sInfo; + switch( nReason ) + { + case RID_STR_XFORMS_VALUE_TOTAL_DIGITS: + if( m_aTotalDigits >>= nValue ) + sInfo.append( nValue ); + break; + + case RID_STR_XFORMS_VALUE_FRACTION_DIGITS: + if( m_aFractionDigits >>= nValue ) + sInfo.append( nValue ); + break; + + default: + sInfo.append( ODecimalType_Base::_explainInvalid( nReason ) ); + break; + } + return sInfo.makeStringAndClear(); + } + + //-------------------------------------------------------------------- + ::rtl::OUString ODecimalType::typedValueAsHumanReadableString( const Any& _rValue ) const + { + double fValue( 0 ); + normalizeValue( _rValue, fValue ); + return ::rtl::OUString::valueOf( fValue ); + } + + //-------------------------------------------------------------------- + void ODecimalType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const + { + OSL_VERIFY( _rValue >>= _rDoubleValue ); + } + + //==================================================================== + //= + //==================================================================== +#define DEFAULT_IMPLEMNENT_SUBTYPE( classname, typeclass ) \ + classname::classname( const ::rtl::OUString& _rName ) \ + :classname##_Base( _rName, DataTypeClass::typeclass ) \ + { \ + } \ + \ + IMPLEMENT_DEFAULT_CLONING( classname, classname##_Base ) \ + \ + void classname::initializeTypedClone( const classname& /*_rCloneSource*/ ) \ + { \ + } \ + + + //==================================================================== + //= ODateType + //==================================================================== + //-------------------------------------------------------------------- + DEFAULT_IMPLEMNENT_SUBTYPE( ODateType, DATE ) + + //-------------------------------------------------------------------- + sal_uInt16 ODateType::_validate( const ::rtl::OUString& _rValue ) + { + return ODateType_Base::_validate( _rValue ); + } + + //-------------------------------------------------------------------- + bool ODateType::_getValue( const ::rtl::OUString& value, double& fValue ) + { + Any aTypeValue = Convert::get().toAny( value, getCppuType() ); + + Date aValue; + if ( !( aTypeValue >>= aValue ) ) + return false; + + ::Date aToolsDate( aValue.Day, aValue.Month, aValue.Year ); + fValue = aToolsDate.GetDate(); + return true; + } + + //-------------------------------------------------------------------- + ::rtl::OUString ODateType::typedValueAsHumanReadableString( const Any& _rValue ) const + { + OSL_PRECOND( _rValue.getValueType().equals( getCppuType() ), "ODateType::typedValueAsHumanReadableString: unexpected type" ); + return Convert::get().toXSD( _rValue ); + } + + //-------------------------------------------------------------------- + void ODateType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const + { + Date aValue; + OSL_VERIFY( _rValue >>= aValue ); + ::Date aToolsDate( aValue.Day, aValue.Month, aValue.Year ); + _rDoubleValue = aToolsDate.GetDate(); + } + + //==================================================================== + //= OTimeType + //==================================================================== + //-------------------------------------------------------------------- + DEFAULT_IMPLEMNENT_SUBTYPE( OTimeType, TIME ) + + //-------------------------------------------------------------------- + sal_uInt16 OTimeType::_validate( const ::rtl::OUString& _rValue ) + { + return OTimeType_Base::_validate( _rValue ); + } + + //-------------------------------------------------------------------- + bool OTimeType::_getValue( const ::rtl::OUString& value, double& fValue ) + { + Any aTypedValue = Convert::get().toAny( value, getCppuType() ); + + Time aValue; + if ( !( aTypedValue >>= aValue ) ) + return false; + + ::Time aToolsTime( aValue.Hours, aValue.Minutes, aValue.Seconds, aValue.HundredthSeconds ); + fValue = aToolsTime.GetTime(); + return true; + } + + //-------------------------------------------------------------------- + ::rtl::OUString OTimeType::typedValueAsHumanReadableString( const Any& _rValue ) const + { + OSL_PRECOND( _rValue.getValueType().equals( getCppuType() ), "OTimeType::typedValueAsHumanReadableString: unexpected type" ); + return Convert::get().toXSD( _rValue ); + } + + //-------------------------------------------------------------------- + void OTimeType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const + { + Time aValue; + OSL_VERIFY( _rValue >>= aValue ); + ::Time aToolsTime( aValue.Hours, aValue.Minutes, aValue.Seconds, aValue.HundredthSeconds ); + _rDoubleValue = aToolsTime.GetTime(); + } + + //==================================================================== + //= ODateTimeType + //==================================================================== + //-------------------------------------------------------------------- + DEFAULT_IMPLEMNENT_SUBTYPE( ODateTimeType, DATETIME ) + + //-------------------------------------------------------------------- + sal_uInt16 ODateTimeType::_validate( const ::rtl::OUString& _rValue ) + { + return ODateTimeType_Base::_validate( _rValue ); + } + + //-------------------------------------------------------------------- + namespace + { + double lcl_normalizeDateTime( const DateTime& _rValue ) + { + ::DateTime aToolsValue( + ::Date( _rValue.Day, _rValue.Month, _rValue.Year ), + ::Time( _rValue.Hours, _rValue.Minutes, _rValue.Seconds, _rValue.HundredthSeconds ) + ); + + double fValue = 0; + // days since 1.1.1900 (which is relatively arbitrary but fixed date) + fValue += ::Date( aToolsValue ) - ::Date( 1, 1, 1900 ); + // time + fValue += aToolsValue.GetTimeInDays(); + return fValue; + } + } + + //-------------------------------------------------------------------- + bool ODateTimeType::_getValue( const ::rtl::OUString& value, double& fValue ) + { + Any aTypedValue = Convert::get().toAny( value, getCppuType() ); + + DateTime aValue; + if ( !( aTypedValue >>= aValue ) ) + return false; + + fValue = lcl_normalizeDateTime( aValue ); + return true; + } + + //-------------------------------------------------------------------- + ::rtl::OUString ODateTimeType::typedValueAsHumanReadableString( const Any& _rValue ) const + { + OSL_PRECOND( _rValue.getValueType().equals( getCppuType() ), "OTimeType::typedValueAsHumanReadableString: unexpected type" ); + ::rtl::OUString sString = Convert::get().toXSD( _rValue ); + + // ISO 8601 notation has a "T" to separate between date and time. Our only concession + // to the "human readable" in the method name is to replace this T with a whitespace. + OSL_ENSURE( sString.indexOf( 'T' ) != -1, "ODateTimeType::typedValueAsHumanReadableString: hmm - no ISO notation?" ); + return sString.replace( 'T', ' ' ); + } + + //-------------------------------------------------------------------- + void ODateTimeType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const + { + DateTime aValue; + OSL_VERIFY( _rValue >>= aValue ); + _rDoubleValue = lcl_normalizeDateTime( aValue ); + } + + //==================================================================== + //= OShortIntegerType + //==================================================================== + //-------------------------------------------------------------------- + OShortIntegerType::OShortIntegerType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass ) + :OShortIntegerType_Base( _rName, _nTypeClass ) + { + } + + //-------------------------------------------------------------------- + IMPLEMENT_DEFAULT_TYPED_CLONING( OShortIntegerType, OShortIntegerType_Base ) + + //-------------------------------------------------------------------- + void OShortIntegerType::initializeTypedClone( const OShortIntegerType& /*_rCloneSource*/ ) + { + } + + //-------------------------------------------------------------------- + bool OShortIntegerType::_getValue( const ::rtl::OUString& value, double& fValue ) + { + fValue = (double)(sal_Int16)value.toInt32(); + // TODO/eforms + // this does not care for values which do not fit into a sal_Int16, but simply + // cuts them down. A better implementation here should probably return <FALSE/> + // for those values. + // Else, we may have a situation where the UI claims an input to be valid + // (say "12345678"), while internally, and at submission time, this is cut to + // some smaller value. + // + // Additionally, this of course does not care for strings which are no numers ... + return true; + } + + //-------------------------------------------------------------------- + ::rtl::OUString OShortIntegerType::typedValueAsHumanReadableString( const Any& _rValue ) const + { + sal_Int16 nValue( 0 ); + OSL_VERIFY( _rValue >>= nValue ); + return ::rtl::OUString::valueOf( (sal_Int32)nValue ); + } + + //-------------------------------------------------------------------- + void OShortIntegerType::normalizeValue( const Any& _rValue, double& _rDoubleValue ) const + { + sal_Int16 nValue( 0 ); + OSL_VERIFY( _rValue >>= nValue ); + _rDoubleValue = nValue; + } + //==================================================================== + //==================================================================== + +#define DATATYPES_INCLUDED_BY_MASTER_HEADER +#include "datatypes_impl.hxx" +#undef DATATYPES_INCLUDED_BY_MASTER_HEADER + +//........................................................................ +} // namespace xforms +//........................................................................ + diff --git a/forms/source/xforms/datatypes.hxx b/forms/source/xforms/datatypes.hxx new file mode 100644 index 000000000000..50021f6db5b4 --- /dev/null +++ b/forms/source/xforms/datatypes.hxx @@ -0,0 +1,424 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef FORMS_SOURCE_XFORMS_DATATYPES_HXX +#define FORMS_SOURCE_XFORMS_DATATYPES_HXX + +/** === begin UNO includes === **/ +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/xsd/XDataType.hpp> +#include <com/sun/star/xsd/DataTypeClass.hpp> +/** === end UNO includes === **/ +#include <cppuhelper/implbase1.hxx> +#include <comphelper/uno3.hxx> +#include <comphelper/propertycontainer.hxx> +#include <comphelper/proparrhlp.hxx> +#include <comphelper/broadcasthelper.hxx> +#include "warnings_guard_unicode_regex.h" + +#include <memory> + +//........................................................................ +namespace xforms +{ +//........................................................................ + + //==================================================================== + //= OXSDDataType + //==================================================================== + typedef ::cppu::WeakImplHelper1 < ::com::sun::star::xsd::XDataType + > OXSDDataType_Base; + typedef ::comphelper::OMutexAndBroadcastHelper OXSDDataType_BBase; + typedef ::comphelper::OPropertyContainer OXSDDataType_PBase; + + class OXSDDataType :public OXSDDataType_Base + ,public OXSDDataType_BBase // order matters: OMutexAndBroadcastHelper before + ,public OXSDDataType_PBase // OPropertyContainer + { + private: + // <properties> + sal_Bool m_bIsBasic; + sal_Int16 m_nTypeClass; + ::rtl::OUString m_sName; + ::rtl::OUString m_sPattern; + sal_uInt16 m_nWST; + // </properties> + + ::std::auto_ptr< U_NAMESPACE_QUALIFIER RegexMatcher > + m_pPatternMatcher; + bool m_bPatternMatcherDirty; + + protected: + + sal_Bool isBasic() const { return m_bIsBasic; } + sal_Int16 getTypeClass() const { return m_nTypeClass; } + const ::rtl::OUString& + getName() const { return m_sName; } + + private: + OXSDDataType( ); // never implemented + OXSDDataType( const OXSDDataType& ); // never implemented + OXSDDataType& operator=( const OXSDDataType& ); // never implemented + + protected: + // create basic data type + OXSDDataType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass ); + ~OXSDDataType(); + + public: + DECLARE_XINTERFACE() + DECLARE_XTYPEPROVIDER() + + virtual ::rtl::OUString SAL_CALL getName( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setName( const ::rtl::OUString& aName ) throw (::com::sun::star::uno::RuntimeException, ::com::sun::star::util::VetoException); + virtual ::rtl::OUString SAL_CALL getPattern() throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setPattern( const ::rtl::OUString& _pattern ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int16 SAL_CALL getWhiteSpaceTreatment() throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setWhiteSpaceTreatment( sal_Int16 _whitespacetreatment ) throw (::com::sun::star::uno::RuntimeException, ::com::sun::star::lang::IllegalArgumentException); + virtual sal_Bool SAL_CALL getIsBasic() throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int16 SAL_CALL getTypeClass() throw (::com::sun::star::uno::RuntimeException); + + virtual sal_Bool SAL_CALL validate( const ::rtl::OUString& value ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL explainInvalid( const ::rtl::OUString& value ) throw (::com::sun::star::uno::RuntimeException); + + // XPropertySet - is a base of XDataType and needs to be disambiguated + virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + public: + OXSDDataType* clone( const ::rtl::OUString& _rNewName ) const; + + protected: + // XPropertySet and friends + virtual sal_Bool SAL_CALL convertFastPropertyValue( ::com::sun::star::uno::Any& _rConvertedValue, ::com::sun::star::uno::Any& _rOldValue, sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rValue ) throw(::com::sun::star::lang::IllegalArgumentException); + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const ::com::sun::star::uno::Any& rValue + ) + throw (::com::sun::star::uno::Exception); + + // --- own overridables --- + // helper for implementing cloning of data types + virtual OXSDDataType* createClone( const ::rtl::OUString& _rName ) const = 0; + virtual void initializeClone( const OXSDDataType& _rCloneSource ); + + // helper method for validate and explainInvalid + virtual sal_uInt16 _validate( const ::rtl::OUString& value ); + virtual ::rtl::OUString _explainInvalid( sal_uInt16 nReason ); + + // helper method for checking properties values which are to be set + virtual bool checkPropertySanity( sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rNewValue, ::rtl::OUString& _rErrorMessage ); + + // register properties implemented by this instance - call the base class when overriding + virtual void registerProperties(); + }; + + //==================================================================== + //= helper for deriving from OXSDDataType + //==================================================================== +#define DECLARE_DEFAULT_CLONING( classname ) \ + virtual OXSDDataType* createClone( const ::rtl::OUString& _rName ) const; \ + virtual void initializeClone( const OXSDDataType& _rCloneSource ); \ + void initializeTypedClone( const classname& _rCloneSource ); + +#define IMPLEMENT_DEFAULT_CLONING( classname, baseclass ) \ + OXSDDataType* classname::createClone( const ::rtl::OUString& _rName ) const \ + { \ + return new classname( _rName ); \ + } \ + void classname::initializeClone( const OXSDDataType& _rCloneSource ) \ + { \ + baseclass::initializeClone( _rCloneSource ); \ + initializeTypedClone( static_cast< const classname& >( _rCloneSource ) ); \ + } \ + +#define IMPLEMENT_DEFAULT_TYPED_CLONING( classname, baseclass ) \ + OXSDDataType* classname::createClone( const ::rtl::OUString& _rName ) const \ + { \ + return new classname( _rName, getTypeClass() ); \ + } \ + void classname::initializeClone( const OXSDDataType& _rCloneSource ) \ + { \ + baseclass::initializeClone( _rCloneSource ); \ + initializeTypedClone( static_cast< const classname& >( _rCloneSource ) ); \ + } \ + +#define REGISTER_VOID_PROP( prop, memberAny, type ) \ + registerMayBeVoidProperty( PROPERTY_##prop, PROPERTY_ID_##prop, ::com::sun::star::beans::PropertyAttribute::BOUND | ::com::sun::star::beans::PropertyAttribute::MAYBEVOID, \ + &memberAny, ::getCppuType( static_cast< type* >( NULL ) ) ); + + //==================================================================== + //= OValueLimitedType_Base + //==================================================================== + class OValueLimitedType_Base : public OXSDDataType + { + protected: + ::com::sun::star::uno::Any m_aMaxInclusive; + ::com::sun::star::uno::Any m_aMaxExclusive; + ::com::sun::star::uno::Any m_aMinInclusive; + ::com::sun::star::uno::Any m_aMinExclusive; + + double m_fCachedMaxInclusive; + double m_fCachedMaxExclusive; + double m_fCachedMinInclusive; + double m_fCachedMinExclusive; + + protected: + OValueLimitedType_Base( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass ); + + virtual void initializeClone( const OXSDDataType& _rCloneSource ); + void initializeTypedClone( const OValueLimitedType_Base& _rCloneSource ); + + // XPropertySet and friends + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const ::com::sun::star::uno::Any& rValue + ) + throw (::com::sun::star::uno::Exception); + + // OXSDDataType overridables + virtual bool _getValue( const ::rtl::OUString& value, double& fValue ); + virtual sal_uInt16 _validate( const ::rtl::OUString& value ); + virtual ::rtl::OUString _explainInvalid( sal_uInt16 nReason ); + + // own overridables + /** translate a given value into a human-readable string + + The value is guaranteed to be not <NULL/>, and is of type <member>ValueType</member> + */ + virtual ::rtl::OUString typedValueAsHumanReadableString( const ::com::sun::star::uno::Any& _rValue ) const = 0; + + /** translates a <member>ValueType</member> value into a double value + + The normalization must respect the "<" and "==" relations on the value + space. That is, if two values are equal, their normalizations must be equal, too. + Similarily, if <code>foo</code> is less than <code>bar</code>, the same + must hold for their normalizations. + + @param _rValue + the value to translate. Guranteed to be not <NULL/>, and of type <member>ValueType</member> + @param _rDoubleValue + output parameter to hold the resulting double value + */ + virtual void normalizeValue( const ::com::sun::star::uno::Any& _rValue, double& _rDoubleValue ) const = 0; + }; + + //==================================================================== + //= OValueLimitedType + //==================================================================== + template < typename VALUE_TYPE > + class OValueLimitedType : public OValueLimitedType_Base + { + protected: + typedef VALUE_TYPE ValueType; + inline const ::com::sun::star::uno::Type& + getCppuType() const { return ::getCppuType( static_cast< ValueType* >( NULL ) ); } + + protected: + OValueLimitedType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass ); + + // OXSDDataType overridables + virtual void registerProperties(); + }; + + //==================================================================== + //= ODerivedDataType + //==================================================================== + /** helper class for implementing interfaces derived from XDataType + */ + template< typename CONCRETE_DATA_TYPE_IMPL, typename SUPERCLASS = OXSDDataType > + class ODerivedDataType :public SUPERCLASS + ,::comphelper::OPropertyArrayUsageHelper< CONCRETE_DATA_TYPE_IMPL > + { + private: + bool m_bPropertiesRegistered; + + protected: + ODerivedDataType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass ); + + protected: + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const; + + // XPropertySet + virtual com::sun::star::uno::Reference<com::sun::star::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() throw(com::sun::star::uno::RuntimeException); + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper(); + }; + + //==================================================================== + //= OBooleanType + //==================================================================== + class OBooleanType; + typedef ODerivedDataType< OBooleanType > OBooleanType_Base; + class OBooleanType : public OBooleanType_Base + { + public: + OBooleanType( const ::rtl::OUString& _rName ); + + protected: + DECLARE_DEFAULT_CLONING( OBooleanType ) + + // OXSDDataType overridables + virtual sal_uInt16 _validate( const ::rtl::OUString& value ); + virtual ::rtl::OUString _explainInvalid( sal_uInt16 nReason ); + }; + + //==================================================================== + //= OStringType + //==================================================================== + class OStringType; + typedef ODerivedDataType< OStringType > OStringType_Base; + class OStringType :public OStringType_Base + { + protected: + // <properties> + ::com::sun::star::uno::Any m_aLength; + ::com::sun::star::uno::Any m_aMinLength; + ::com::sun::star::uno::Any m_aMaxLength; + // </properties> + + public: + OStringType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass /* = ::com::sun::star::xsd::DataTypeClass::STRING */ ); + + protected: + DECLARE_DEFAULT_CLONING( OStringType ) + + // OXSDDataType overridables + virtual sal_uInt16 _validate( const ::rtl::OUString& value ); + virtual ::rtl::OUString _explainInvalid( sal_uInt16 nReason ); + virtual bool checkPropertySanity( sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rNewValue, ::rtl::OUString& _rErrorMessage ); + virtual void registerProperties(); + }; + + //==================================================================== + //= ODecimalType + //==================================================================== + class ODecimalType; + typedef ODerivedDataType< ODecimalType, OValueLimitedType< double > > ODecimalType_Base; + class ODecimalType : public ODecimalType_Base + { + protected: + ::com::sun::star::uno::Any m_aTotalDigits; + ::com::sun::star::uno::Any m_aFractionDigits; + + public: + ODecimalType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass /* = ::com::sun::star::xsd::DataTypeClass::DECIMAL */ ); + + protected: + DECLARE_DEFAULT_CLONING( ODecimalType ) + + // OXSDDataType overridables + virtual sal_uInt16 _validate( const ::rtl::OUString& value ); + virtual ::rtl::OUString _explainInvalid( sal_uInt16 nReason ); + virtual void registerProperties(); + + // OValueLimitedType overridables + virtual ::rtl::OUString typedValueAsHumanReadableString( const ::com::sun::star::uno::Any& _rValue ) const; + virtual void normalizeValue( const ::com::sun::star::uno::Any& _rValue, double& _rDoubleValue ) const; + + private: + using ODecimalType_Base::initializeTypedClone; + }; + + //==================================================================== + //= + //==================================================================== +#define DEFAULT_DECLARE_SUBTYPE( classname, valuetype ) \ + class classname; \ + typedef ODerivedDataType< classname, OValueLimitedType< valuetype > > classname##_Base; \ + class classname : public classname##_Base \ + { \ + public: \ + classname( const ::rtl::OUString& _rName ); \ + \ + protected: \ + DECLARE_DEFAULT_CLONING( classname ) \ + \ + /* OXSDDataType overridables */ \ + virtual sal_uInt16 _validate( const ::rtl::OUString& value ); \ + virtual bool _getValue( const ::rtl::OUString& value, double& fValue ); \ + \ + /* OValueLimitedType overridables */ \ + virtual ::rtl::OUString typedValueAsHumanReadableString( const ::com::sun::star::uno::Any& _rValue ) const; \ + virtual void normalizeValue( const ::com::sun::star::uno::Any& _rValue, double& _rDoubleValue ) const; \ + \ + private: \ + using classname##_Base::initializeTypedClone; \ + }; + + //==================================================================== + //= ODateType + //==================================================================== + DEFAULT_DECLARE_SUBTYPE( ODateType, ::com::sun::star::util::Date ) + + //==================================================================== + //= OTimeType + //==================================================================== + DEFAULT_DECLARE_SUBTYPE( OTimeType, ::com::sun::star::util::Time ) + + //==================================================================== + //= ODateTimeType + //==================================================================== + DEFAULT_DECLARE_SUBTYPE( ODateTimeType, ::com::sun::star::util::DateTime ) + + //==================================================================== + //= OShortIntegerType + //==================================================================== + class OShortIntegerType; + typedef ODerivedDataType< OShortIntegerType, OValueLimitedType< sal_Int16 > > OShortIntegerType_Base; + class OShortIntegerType : public OShortIntegerType_Base + { + public: + OShortIntegerType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass ); + + protected: + DECLARE_DEFAULT_CLONING( OShortIntegerType ) + + // OXSDDataType overridables + virtual bool _getValue( const ::rtl::OUString& value, double& fValue ); + + // OValueLimitedType overridables + virtual ::rtl::OUString typedValueAsHumanReadableString( const ::com::sun::star::uno::Any& _rValue ) const; + virtual void normalizeValue( const ::com::sun::star::uno::Any& _rValue, double& _rDoubleValue ) const; + + private: + using OShortIntegerType_Base::initializeTypedClone; + }; + +//........................................................................ +} // namespace xforms +//........................................................................ + +#endif // FORMS_SOURCE_XFORMS_DATATYPES_HXX + diff --git a/forms/source/xforms/datatypes_impl.hxx b/forms/source/xforms/datatypes_impl.hxx new file mode 100644 index 000000000000..d0d0f9606b91 --- /dev/null +++ b/forms/source/xforms/datatypes_impl.hxx @@ -0,0 +1,76 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef DATATYPES_INCLUDED_BY_MASTER_HEADER + #error "not to be included directly!" +#endif + +//-------------------------------------------------------------------- +template< typename CONCRETE_DATA_TYPE_IMPL, typename SUPERCLASS > +ODerivedDataType< CONCRETE_DATA_TYPE_IMPL, SUPERCLASS >::ODerivedDataType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass ) + :SUPERCLASS( _rName, _nTypeClass ) + ,m_bPropertiesRegistered( false ) +{ +} + +//-------------------------------------------------------------------- +template< typename CONCRETE_DATA_TYPE_IMPL, typename SUPERCLASS > +::cppu::IPropertyArrayHelper* ODerivedDataType< CONCRETE_DATA_TYPE_IMPL, SUPERCLASS >::createArrayHelper( ) const +{ + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property > aProps; + ODerivedDataType< CONCRETE_DATA_TYPE_IMPL, SUPERCLASS >::describeProperties( aProps ); + return new ::cppu::OPropertyArrayHelper( aProps ); +} + +//-------------------------------------------------------------------- +template< typename CONCRETE_DATA_TYPE_IMPL, typename SUPERCLASS > +::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL ODerivedDataType< CONCRETE_DATA_TYPE_IMPL, SUPERCLASS >::getPropertySetInfo() throw( ::com::sun::star::uno::RuntimeException ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() ); +} + +//-------------------------------------------------------------------- +template< typename CONCRETE_DATA_TYPE_IMPL, typename SUPERCLASS > +::cppu::IPropertyArrayHelper& SAL_CALL ODerivedDataType< CONCRETE_DATA_TYPE_IMPL, SUPERCLASS >::getInfoHelper() +{ + if ( !m_bPropertiesRegistered ) + { + const_cast< ODerivedDataType* >( this )->registerProperties(); + const_cast< ODerivedDataType* >( this )->m_bPropertiesRegistered = true; + } + + return *ODerivedDataType< CONCRETE_DATA_TYPE_IMPL, SUPERCLASS >::getArrayHelper(); +} + + +//-------------------------------------------------------------------- +template< typename VALUE_TYPE > +OValueLimitedType< VALUE_TYPE >::OValueLimitedType( const ::rtl::OUString& _rName, sal_Int16 _nTypeClass ) + :OValueLimitedType_Base( _rName, _nTypeClass ) +{ +} + diff --git a/forms/source/xforms/enumeration.cxx b/forms/source/xforms/enumeration.cxx new file mode 100644 index 000000000000..270ade4bc4bb --- /dev/null +++ b/forms/source/xforms/enumeration.cxx @@ -0,0 +1,74 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include "enumeration.hxx" + +#include <com/sun/star/container/NoSuchElementException.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/lang/WrappedTargetException.hpp> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/RuntimeException.hpp> + +using com::sun::star::container::NoSuchElementException; +using com::sun::star::container::XIndexAccess; +using com::sun::star::lang::WrappedTargetException; +using com::sun::star::uno::Any; +using com::sun::star::uno::Reference; +using com::sun::star::uno::RuntimeException; + + +Enumeration::Enumeration( XIndexAccess* pContainer ) + : mxContainer( pContainer ), + mnIndex( 0 ) +{ + OSL_ENSURE( mxContainer.is(), "no container?" ); +} + +sal_Bool Enumeration::hasMoreElements() + throw( RuntimeException ) +{ + if( ! mxContainer.is() ) + throw RuntimeException(); + + return mnIndex < mxContainer->getCount(); +} + +Any Enumeration::nextElement() + throw( NoSuchElementException, + WrappedTargetException, + RuntimeException ) +{ + if( ! mxContainer.is() ) + throw RuntimeException(); + if( mnIndex >= mxContainer->getCount() ) + throw NoSuchElementException(); + + return mxContainer->getByIndex( mnIndex++ ); +} diff --git a/forms/source/xforms/enumeration.hxx b/forms/source/xforms/enumeration.hxx new file mode 100644 index 000000000000..8a9b89a09a15 --- /dev/null +++ b/forms/source/xforms/enumeration.hxx @@ -0,0 +1,63 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _ENUMERATION_HXX +#define _ENUMERATION_HXX + + +#include <cppuhelper/implbase1.hxx> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/uno/Reference.hxx> + +namespace com { namespace sun { namespace star { + namespace container { class XIndexAccess; } + namespace uno { class Any; } + namespace container { class NoSuchElementException; } + namespace lang { class WrappedTargetException; } + namespace uno { class RuntimeException; } +} } } + +/** implement XEnumeration based on container::XIndexAccess */ +class Enumeration + : public cppu::WeakImplHelper1<com::sun::star::container::XEnumeration> +{ + com::sun::star::uno::Reference<com::sun::star::container::XIndexAccess> mxContainer; + sal_Int32 mnIndex; + +public: + Enumeration( com::sun::star::container::XIndexAccess* ); + + virtual sal_Bool SAL_CALL hasMoreElements() + throw( com::sun::star::uno::RuntimeException ); + + virtual com::sun::star::uno::Any SAL_CALL nextElement() + throw( com::sun::star::container::NoSuchElementException, + com::sun::star::lang::WrappedTargetException, + com::sun::star::uno::RuntimeException ); +}; + +#endif diff --git a/forms/source/xforms/evaluationcontext.hxx b/forms/source/xforms/evaluationcontext.hxx new file mode 100644 index 000000000000..4affefd34f29 --- /dev/null +++ b/forms/source/xforms/evaluationcontext.hxx @@ -0,0 +1,75 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EVALUATIONCONTEXT_HXX +#define _EVALUATIONCONTEXT_HXX + +#include <com/sun/star/xml/dom/XNode.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/xforms/XModel.hpp> + +namespace xforms +{ + + +/** define the context for the evaluation of an XPath expression */ +class EvaluationContext +{ +public: + EvaluationContext() + : mxContextNode(), + mxModel(), + mxNamespaces(), + mnContextPosition( 0 ), + mnContextSize( 0 ) + { } + + EvaluationContext( + const com::sun::star::uno::Reference<com::sun::star::xml::dom::XNode>& xContextNode, + const com::sun::star::uno::Reference<com::sun::star::xforms::XModel>& xModel, + const com::sun::star::uno::Reference<com::sun::star::container::XNameContainer>& xNamespaces, + sal_Int32 nPosition, + sal_Int32 nSize ) + : mxContextNode( xContextNode ), + mxModel( xModel ), + mxNamespaces( xNamespaces ), + mnContextPosition( nPosition ), + mnContextSize( nSize ) + { } + + com::sun::star::uno::Reference<com::sun::star::xml::dom::XNode> mxContextNode; + com::sun::star::uno::Reference<com::sun::star::xforms::XModel> mxModel; + com::sun::star::uno::Reference<com::sun::star::container::XNameContainer> mxNamespaces; + + sal_Int32 mnContextPosition; + sal_Int32 mnContextSize; +}; + + +} // namespace xforms + +#endif diff --git a/forms/source/xforms/makefile.mk b/forms/source/xforms/makefile.mk new file mode 100644 index 000000000000..10bbf6b49fcd --- /dev/null +++ b/forms/source/xforms/makefile.mk @@ -0,0 +1,66 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=forms +TARGET=xforms + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE: $(PRJ)$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/model.obj \ + $(SLO)$/model_ui.obj \ + $(SLO)$/binding.obj \ + $(SLO)$/xforms_services.obj \ + $(SLO)$/unohelper.obj \ + $(SLO)$/propertysetbase.obj \ + $(SLO)$/pathexpression.obj \ + $(SLO)$/computedexpression.obj \ + $(SLO)$/boolexpression.obj \ + $(SLO)$/mip.obj \ + $(SLO)$/submission.obj \ + $(SLO)$/datatyperepository.obj \ + $(SLO)$/datatypes.obj \ + $(SLO)$/convert.obj \ + $(SLO)$/enumeration.obj \ + $(SLO)$/resourcehelper.obj \ + $(SLO)$/xmlhelper.obj \ + $(SLO)$/xformsevent.obj + + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/forms/source/xforms/mip.cxx b/forms/source/xforms/mip.cxx new file mode 100644 index 000000000000..7f45ff5e9415 --- /dev/null +++ b/forms/source/xforms/mip.cxx @@ -0,0 +1,126 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include "mip.hxx" + + +namespace xforms +{ + + +MIP::MIP() +{ + resetReadonly(); + resetRequired(); + resetRelevant(); + resetConstraint(); + resetCalculate(); + resetTypeName(); +} + +MIP::~MIP() {} + +void MIP::inherit( const MIP& rMip ) +{ + if( ! mbHasReadonly ) + { + mbHasReadonly = rMip.hasReadonly(); + mbReadonly = rMip.isReadonly(); + } + if( ! mbHasRequired ) + { + mbHasRequired = rMip.hasRequired(); + mbRequired = rMip.isRequired(); + } + if( ! mbHasRelevant ) + { + mbHasRelevant = rMip.hasRelevant(); + mbRelevant = rMip.isRelevant(); + } + if( ! mbHasConstraint ) + { + mbHasConstraint = rMip.hasConstraint(); + mbConstraint = rMip.isConstraint(); + msConstraintExplanation = rMip.getConstraintExplanation(); + } + if( ! mbHasCalculate ) + { + mbHasCalculate = rMip.hasCalculate(); + } + if( ! mbHasTypeName ) + { + mbHasTypeName = rMip.hasTypeName(); + msTypeName = rMip.getTypeName(); + } +} + +void MIP::join( const MIP& rMip ) +{ + // TODO: inherit only inheritable MIPs... + inherit( rMip ); +} + +bool MIP::hasReadonly() const { return mbHasReadonly; } +bool MIP::isReadonly() const { return mbHasReadonly ? mbReadonly : mbHasCalculate; } +void MIP::setReadonly( bool b ) { mbHasReadonly = true; mbReadonly = b; } +void MIP::resetReadonly() { mbHasReadonly = false; mbReadonly = false; } + +bool MIP::hasRequired() const { return mbHasRequired; } +bool MIP::isRequired() const { return mbRequired; } +void MIP::setRequired( bool b ) { mbHasRequired = true; mbRequired = b; } +void MIP::resetRequired() { mbHasRequired = false; mbRequired = false; } + +bool MIP::hasRelevant() const { return mbHasRelevant; } +bool MIP::isRelevant() const { return mbRelevant; } +void MIP::setRelevant( bool b ) { mbHasRelevant = true; mbRelevant = b; } +void MIP::resetRelevant() { mbHasRelevant = false; mbRelevant = true; } + +bool MIP::hasConstraint() const { return mbHasConstraint; } +bool MIP::isConstraint() const { return mbConstraint; } +void MIP::setConstraint( bool b ) { mbHasConstraint = true; mbConstraint = b; msConstraintExplanation = rtl::OUString(); } +void MIP::resetConstraint() { mbHasConstraint = false; mbConstraint = true; msConstraintExplanation = rtl::OUString(); } + +void MIP::setConstraintExplanation( const rtl::OUString& s ) { msConstraintExplanation = s; } +rtl::OUString MIP::getConstraintExplanation() const { return msConstraintExplanation; } + + +bool MIP::hasCalculate() const { return mbHasCalculate; } +void MIP::setHasCalculate( bool b ) { mbHasCalculate = b; } +void MIP::resetCalculate() { mbHasCalculate = false; } + +bool MIP::hasTypeName() const { return mbHasTypeName; } + rtl::OUString MIP::getTypeName() const { return msTypeName; } +void MIP::setTypeName( const rtl::OUString& s ) { msTypeName = s; mbHasTypeName = true; } +void MIP::resetTypeName() { msTypeName = rtl::OUString(); mbHasTypeName = false; } + + + + +} // namespace xforms diff --git a/forms/source/xforms/mip.hxx b/forms/source/xforms/mip.hxx new file mode 100644 index 000000000000..fb8b219cf7e1 --- /dev/null +++ b/forms/source/xforms/mip.hxx @@ -0,0 +1,122 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _MIP_HXX +#define _MIP_HXX + +#include <rtl/ustring.hxx> + +namespace xforms +{ + +/** represents the XForms *m*odel *i*tem *p*roperties (MIPs) for a + * given XNode in the instance data at a given point in time. The + * values will not be updated; for updated values new MIP objects have + * to be created/queried. */ +class MIP +{ + bool mbHasReadonly; + bool mbReadonly; + + bool mbHasRequired; + bool mbRequired; + + bool mbHasRelevant; + bool mbRelevant; + + bool mbHasConstraint; + bool mbConstraint; + + bool mbHasCalculate; + + bool mbHasTypeName; + rtl::OUString msTypeName; + + rtl::OUString msConstraintExplanation; + +public: + MIP(); + ~MIP(); + + /// inherit from upper-level MIPs + void inherit( const MIP& ); + + /// join with same-level MIPs + void join( const MIP& ); + + + // - type (static; default: xsd:string) + // (currently default implemented as empty string) + bool hasTypeName() const; + rtl::OUString getTypeName() const; + void setTypeName( const rtl::OUString& ); + void resetTypeName(); + + // - readonly (computed XPath; default: false; true if calculate exists) + bool hasReadonly() const; + bool isReadonly() const; + void setReadonly( bool ); + void resetReadonly(); + + // - required (computed XPath; default: false) + bool hasRequired() const; + bool isRequired() const; + void setRequired( bool ); + void resetRequired(); + + // - relevant (computed XPath; default: true) + bool hasRelevant() const; + bool isRelevant() const; + void setRelevant( bool ); + void resetRelevant(); + + // - constraing (computed XPath; default: true) + bool hasConstraint() const; + bool isConstraint() const; + void setConstraint( bool ); + void resetConstraint(); + + // explain _why_ a constraint failed + void setConstraintExplanation( const rtl::OUString& ); + rtl::OUString getConstraintExplanation() const; + + // - calculate (computed XPath; default: has none (false)) + // (for calculate, we only store whether a calculate MIP is present; + // the actual calculate value is handled my changing the instance + // directly) + bool hasCalculate() const; + void setHasCalculate( bool ); + void resetCalculate(); + + // - minOccurs/maxOccurs (computed XPath; default: 0/inf) + // - p3ptype (static; no default) + +}; + +} // namespace xforms + +#endif diff --git a/forms/source/xforms/model.cxx b/forms/source/xforms/model.cxx new file mode 100644 index 000000000000..0d81c7056bec --- /dev/null +++ b/forms/source/xforms/model.cxx @@ -0,0 +1,808 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include "model.hxx" + +#include "model_helper.hxx" +#include "unohelper.hxx" +#include "binding.hxx" +#include "submission.hxx" +#include "mip.hxx" +#include "evaluationcontext.hxx" +#include "xmlhelper.hxx" +#include "datatyperepository.hxx" +#include "NameContainer.hxx" + +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <tools/debug.hxx> + +#include <comphelper/propertysetinfo.hxx> +#include <cppuhelper/typeprovider.hxx> + +#include <algorithm> + +// UNO classes +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/xml/dom/XDocument.hpp> +#include <com/sun/star/xml/dom/XCharacterData.hpp> +#include <com/sun/star/xml/dom/NodeType.hpp> +#include <com/sun/star/xml/dom/XDocumentBuilder.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <com/sun/star/io/XInputStream.hpp> + + +using com::sun::star::lang::XMultiServiceFactory; +using com::sun::star::lang::XUnoTunnel; +using com::sun::star::beans::XPropertySet; +using com::sun::star::beans::PropertyValue; +using rtl::OUString; +using rtl::OUStringBuffer; +using com::sun::star::beans::PropertyVetoException; +using com::sun::star::beans::UnknownPropertyException; +using com::sun::star::util::VetoException; +using com::sun::star::lang::WrappedTargetException; +using com::sun::star::lang::IllegalArgumentException; +using com::sun::star::ucb::XSimpleFileAccess; +using com::sun::star::io::XInputStream; + +using namespace com::sun::star::uno; +using namespace com::sun::star::xml::dom; +using namespace xforms; + + +#if OSL_DEBUG_LEVEL > 1 +#define DBG_INVARIANT_TYPE(TYPE) class DBG_##TYPE { const TYPE* mpT; void check() { mpT->dbg_assertInvariant(); } public: DBG_##TYPE(const TYPE* pT) : mpT(pT) { check(); } ~DBG_##TYPE() { check(); } } _DBG_##TYPE(this); + +#define DBG_INVARIANT() DBG_INVARIANT_TYPE(Model) +#else +#define DBG_INVARIANT_TYPE(TYPE) +#define DBG_INVARIANT() +#endif + + + +// +// The Model +// + +void Model::ensureAtLeastOneInstance() +{ + if( ! mpInstances->hasItems() ) + { + // create a default instance + newInstance( OUString(), OUString(), true ); + } +} + + + +/** Model default constructor; create empty model */ +Model::Model() : + msID(), + mpBindings( NULL ), + mpSubmissions( NULL ), + mpInstances( new InstanceCollection ), + mxNamespaces( new NameContainer<OUString>() ), + mxBindings( mpBindings ), + mxSubmissions( mpSubmissions ), + mxInstances( mpInstances ), + mbInitialized( false ), + mbExternalData( true ) +{ + initializePropertySet(); + + // initialize bindings collections + // (not in initializer list to avoid use of incomplete 'this') + mpBindings = new BindingCollection( this ); + mxBindings = mpBindings; + + mpSubmissions = new SubmissionCollection( this ); + mxSubmissions = mpSubmissions; + + // invariant only holds after construction + DBG_INVARIANT(); +} + +Model::~Model() throw() +{ + // give up bindings & submissions; the mxBindings/mxSubmissions + // references will then delete them + mpBindings = NULL; + mpSubmissions = NULL; +} + +Model* lcl_getModel( const Reference<XUnoTunnel>& xTunnel ) +{ + Model* pModel = NULL; + if( xTunnel.is() ) + pModel = reinterpret_cast<Model*>( + xTunnel->getSomething( Model::getUnoTunnelID() ) ); + return pModel; +} + +Model* Model::getModel( const Reference<XModel>& xModel ) +{ + return lcl_getModel( Reference<XUnoTunnel>( xModel, UNO_QUERY ) ); +} + +EvaluationContext Model::getEvaluationContext() +{ + // the default context is the top-level element node. A default + // node (instanceData' is inserted when there is no default node + Reference<XDocument> xInstance = getDefaultInstance(); + Reference<XNode> xElement( xInstance->getDocumentElement(), UNO_QUERY ); + + // no element found? Then insert default element 'instanceData' + if( ! xElement.is() ) + { + xElement = Reference<XNode>( + xInstance->createElement( OUSTRING("instanceData") ), + UNO_QUERY_THROW ); + Reference<XNode>( xInstance, UNO_QUERY_THROW)->appendChild( xElement ); + } + + OSL_ENSURE( xElement.is() && + xElement->getNodeType() == NodeType_ELEMENT_NODE, + "no element in evaluation context" ); + + return EvaluationContext( xElement, this, mxNamespaces, 0, 1 ); +} + + +Model::IntSequence_t Model::getUnoTunnelID() +{ + static cppu::OImplementationId aImplementationId; + return aImplementationId.getImplementationId(); +} + +Model::XDocument_t Model::getForeignSchema() const +{ + return mxForeignSchema; +} + +void Model::setForeignSchema( const XDocument_t& rDocument ) +{ + mxForeignSchema = rDocument; +} + +rtl::OUString Model::getSchemaRef() const +{ + return msSchemaRef; +} + +void Model::setSchemaRef( const rtl::OUString& rSchemaRef ) +{ + msSchemaRef = rSchemaRef; +} + +Model::XNameContainer_t Model::getNamespaces() const +{ + return mxNamespaces; +} + +void Model::setNamespaces( const XNameContainer_t& rNamespaces ) +{ + if( rNamespaces.is() ) + mxNamespaces = rNamespaces; +} + +bool Model::getExternalData() const +{ + return mbExternalData; +} + +void Model::setExternalData( bool _bData ) +{ + mbExternalData = _bData; +} + +#if OSL_DEBUG_LEVEL > 1 +void Model::dbg_assertInvariant() const +{ + OSL_ENSURE( mpInstances != NULL, "no instances found" ); + OSL_ENSURE( mxInstances.is(), "No instance container!" ); + // OSL_ENSURE( mxInstances->hasElements(), "no instance!" ); + + OSL_ENSURE( mpBindings != NULL, "no bindings element" ); + OSL_ENSURE( mxBindings.is(), "No Bindings container" ); + + OSL_ENSURE( mpSubmissions != NULL, "no submissions element" ); + OSL_ENSURE( mxSubmissions.is(), "No Submission container" ); + + + + /* + // check bindings, and things that have to do with our binding + std::vector<MIP*> aAllMIPs; // check MIP map + sal_Int32 nCount = mpBindings->countItems(); + for( sal_Int32 i = 0; i < nCount; i++ ) + { + Binding* pBind = Binding::getBinding( + mpBindings->Collection<XPropertySet_t>::getItem( i ) ); + + // examine and check binding + OSL_ENSURE( pBind != NULL, "invalid binding found" ); + + OSL_ENSURE( Model::getModel( pBind->getModel() ) == this, + "our binding doesn't know us."); + // check this binding's MIP against MIP map + MIP* pMIP = const_cast<MIP*>( pBind->_getMIP() ); + sal_Int32 nFound = 0; + if( pMIP != NULL ) + { + aAllMIPs.push_back( pMIP ); + for( MIPs_t::const_iterator aIter = maMIPs.begin(); + aIter != maMIPs.end(); + aIter++ ) + { + if( pMIP == aIter->second ) + nFound++; + } + } + OSL_ENSURE( ( pMIP == NULL ) == ( nFound == 0 ), "MIP-map wrong" ); + } + + // check MIP map for left-over MIPs + for( MIPs_t::const_iterator aIter = maMIPs.begin(); + aIter != maMIPs.end(); + aIter++ ) + { + MIP* pMIP = aIter->second; + std::vector<MIP*>::iterator aFound = + std::find( aAllMIPs.begin(), aAllMIPs.end(), pMIP ); + if( aFound != aAllMIPs.end() ) + aAllMIPs.erase( aFound ); + } + OSL_ENSURE( aAllMIPs.empty(), "lonely MIPs found!" ); + */ +} +#endif + + +// +// MIP managment +// + +void Model::addMIP( void* pTag, const XNode_t& xNode, const MIP& rMIP ) +{ + OSL_ENSURE( pTag != NULL, "empty tag?" ); + OSL_ENSURE( xNode.is(), "no node" ); + + MIPs_t::value_type aValue( xNode, ::std::pair<void*,MIP>( pTag, rMIP ) ); + maMIPs.insert( aValue ); +} + +void Model::removeMIPs( void* pTag ) +{ + OSL_ENSURE( pTag != NULL, "empty tag?" ); + + for( MIPs_t::iterator aIter = maMIPs.begin(); + aIter != maMIPs.end(); ) + { + if( aIter->second.first == pTag ) + { + MIPs_t::iterator next( aIter ); ++next; + maMIPs.erase( aIter ); + aIter = next; + } + else + ++aIter; + } +} + +MIP Model::queryMIP( const XNode_t& xNode ) const +{ + // OSL_ENSURE( xNode.is(), "no node" ); + + // travel up inheritance chain and inherit MIPs + MIP aRet; + for( XNode_t xCurrent = xNode; + xCurrent.is(); + xCurrent = xCurrent->getParentNode() ) + { + // iterate over all MIPs for this node, and join MIPs + MIP aMIP; + MIPs_t::const_iterator aEnd = maMIPs.upper_bound( xCurrent ); + MIPs_t::const_iterator aIter = maMIPs.lower_bound( xCurrent ); + for( ; aIter != aEnd; aIter++ ) + aMIP.join( aIter->second.second ); + + // inherit from current node (or set if we are at the start node) + if( xCurrent == xNode ) + aRet = aMIP; + else + aRet.inherit( aMIP ); + } + + return aRet; +} + + + +void Model::rebind() +{ + OSL_ENSURE( mpBindings != NULL, "bindings?" ); + + // iterate over all bindings and call update + sal_Int32 nCount = mpBindings->countItems(); + for( sal_Int32 i = 0; i < nCount; i++ ) + { + Binding* pBind = Binding::getBinding( mpBindings->Collection<XPropertySet_t>::getItem( i ) ); + OSL_ENSURE( pBind != NULL, "binding?" ); + pBind->update(); + } +} + + + +void Model::deferNotifications( bool bDefer ) +{ + // iterate over all bindings and defer notifications + sal_Int32 nCount = mpBindings->countItems(); + for( sal_Int32 i = 0; i < nCount; i++ ) + { + Binding* pBind = Binding::getBinding( mpBindings->Collection<XPropertySet_t>::getItem( i ) ); + OSL_ENSURE( pBind != NULL, "binding?" ); + pBind->deferNotifications( bDefer ); + } +} + + +bool Model::setSimpleContent( const XNode_t& xConstNode, + const rtl::OUString& sValue ) +{ + OSL_ENSURE( xConstNode.is(), "need node to set data" ); + + bool bRet = false; + if( xConstNode.is() ) + { + // non-const node reference so we can assign children (if necessary) + XNode_t xNode( xConstNode ); + + switch( xNode->getNodeType() ) + { + case NodeType_ELEMENT_NODE: + { + // find first text node child + Reference<XNode> xChild; + for( xChild = xNode->getFirstChild(); + xChild.is() && xChild->getNodeType() != NodeType_TEXT_NODE; + xChild = xChild->getNextSibling() ) + ; // empty loop; only find first text node child + + // create text node, if none is found + if( ! xChild.is() ) + { + xChild = Reference<XNode>( + xNode->getOwnerDocument()->createTextNode( OUString() ), + UNO_QUERY_THROW ); + xNode->appendChild( xChild ); + } + xNode = xChild; + + OSL_ENSURE( xNode.is() && + xNode->getNodeType() == NodeType_TEXT_NODE, + "text node creation failed?" ); + } + // no break; continue as with text node: + + case NodeType_TEXT_NODE: + case NodeType_ATTRIBUTE_NODE: + { + // set the node value (defer notifications) + if( xNode->getNodeValue() != sValue ) + { + deferNotifications( true ); + xNode->setNodeValue( sValue ); + deferNotifications( false ); + } + bRet = true; + } + break; + + default: + { + OSL_ENSURE( false, "bound to unknown node type?" ); + } + break; + + } + } + return bRet; +} + +void Model::loadInstance( sal_Int32 nInstance ) +{ + Sequence<PropertyValue> aSequence = mpInstances->getItem( nInstance ); + + // find URL from instance + OUString sURL; + bool bOnce = false; + getInstanceData( aSequence, NULL, NULL, &sURL, &bOnce ); + + // if we have a URL, load the document and set it into the instance + if( sURL.getLength() > 0 ) + { + try + { + Reference<XInputStream> xInput = + Reference<XSimpleFileAccess>( + createInstance( + OUSTRING("com.sun.star.ucb.SimpleFileAccess") ), + UNO_QUERY_THROW )->openFileRead( sURL ); + if( xInput.is() ) + { + Reference<XDocument> xInstance = + getDocumentBuilder()->parse( xInput ); + if( xInstance.is() ) + { + OUString sEmpty; + setInstanceData( aSequence, NULL, &xInstance, + bOnce ? &sEmpty : &sURL, NULL); + mpInstances->setItem( nInstance, aSequence ); + } + } + } + catch( const Exception& ) + { + // couldn't load the instance -> ignore! + } + } +} + +void Model::loadInstances() +{ + // iterate over instance array to get PropertyValue-Sequence + const sal_Int32 nInstances = mpInstances->countItems(); + for( sal_Int32 nInstance = 0; nInstance < nInstances; nInstance++ ) + { + loadInstance( nInstance ); + } +} + +bool Model::isInitialized() const +{ + return mbInitialized; +} + +bool Model::isValid() const +{ + bool bValid = true; + sal_Int32 nCount = mpBindings->countItems(); + for( sal_Int32 i = 0; bValid && i < nCount; i++ ) + { + Binding* pBind = Binding::getBinding( mpBindings->Collection<XPropertySet_t>::getItem( i ) ); + OSL_ENSURE( pBind != NULL, "binding?" ); + bValid = pBind->isValid(); + } + return bValid; +} + + + +// +// implement xforms::XModel +// + +rtl::OUString Model::getID() + throw( RuntimeException ) +{ + DBG_INVARIANT(); + return msID; +} + +void Model::setID( const rtl::OUString& sID ) + throw( RuntimeException ) +{ + DBG_INVARIANT(); + msID = sID; +} + +void Model::initialize() + throw( RuntimeException ) +{ + DBG_ASSERT( ! mbInitialized, "model already initialized" ); + + // load instances + loadInstances(); + + // let's pretend we're initialized and rebind all bindings + mbInitialized = true; + rebind(); +} + +void Model::rebuild() + throw( RuntimeException ) +{ + if( ! mbInitialized ) + initialize(); + else + rebind(); +} + +void Model::recalculate() + throw( RuntimeException ) +{ + rebind(); +} + +void Model::revalidate() + throw( RuntimeException ) +{ + // do nothing. We don't validate anyways! +} + +void Model::refresh() + throw( RuntimeException ) +{ + rebind(); +} + + +void SAL_CALL Model::submitWithInteraction( + const rtl::OUString& sID, + const XInteractionHandler_t& _rxHandler ) + throw( VetoException, + WrappedTargetException, + RuntimeException ) +{ + DBG_INVARIANT(); + + if( mpSubmissions->hasItem( sID ) ) + { + Submission* pSubmission = + Submission::getSubmission( mpSubmissions->getItem( sID ) ); + OSL_ENSURE( pSubmission != NULL, "no submission?" ); + OSL_ENSURE( pSubmission->getModel() == Reference<XModel>( this ), + "wrong model" ); + + // submit. All exceptions are allowed to leave. + pSubmission->submitWithInteraction( _rxHandler ); + } +} + +void Model::submit( const rtl::OUString& sID ) + throw( VetoException, WrappedTargetException, RuntimeException ) +{ + submitWithInteraction( sID, NULL ); +} + +Model::XDataTypeRepository_t SAL_CALL Model::getDataTypeRepository( ) + throw( RuntimeException ) +{ + if ( !mxDataTypes.is() ) + mxDataTypes = new ODataTypeRepository; + + return mxDataTypes; +} + +// +// instance management +// + +Model::XSet_t Model::getInstances() + throw( RuntimeException ) +{ + return mxInstances; +} + +Model::XDocument_t Model::getInstanceDocument( const rtl::OUString& rName ) + throw( RuntimeException ) +{ + ensureAtLeastOneInstance(); + Reference<XDocument> aInstance; + sal_Int32 nInstance = lcl_findInstance( mpInstances, rName ); + if( nInstance != -1 ) + getInstanceData( mpInstances->getItem( nInstance ), + NULL, &aInstance, NULL, NULL ); + return aInstance; +} + +Model::XDocument_t SAL_CALL Model::getDefaultInstance() + throw( RuntimeException ) +{ + ensureAtLeastOneInstance(); + DBG_ASSERT( mpInstances->countItems() > 0, "no instance?" ); + Reference<XDocument> aInstance; + getInstanceData( mpInstances->getItem( 0 ), NULL, &aInstance, NULL, NULL ); + return aInstance; +} + + + +// +// bindings management +// + +Model::XPropertySet_t SAL_CALL Model::createBinding() + throw( RuntimeException ) +{ + DBG_INVARIANT(); + return new Binding(); +} + +Model::XPropertySet_t Model::cloneBinding( const XPropertySet_t& xBinding ) + throw( RuntimeException ) +{ + DBG_INVARIANT(); + XPropertySet_t xNewBinding = createBinding(); + copy( xBinding, xNewBinding ); + return xNewBinding; +} + +Model::XPropertySet_t Model::getBinding( const rtl::OUString& sId ) + throw( RuntimeException ) +{ + DBG_INVARIANT(); + return mpBindings->hasItem( sId ) ? mpBindings->getItem( sId ) : NULL; +} + +Model::XSet_t Model::getBindings() + throw( RuntimeException ) +{ + DBG_INVARIANT(); + return mxBindings; +} + + + +// +// submission management +// + +Model::XSubmission_t Model::createSubmission() + throw( RuntimeException ) +{ + DBG_INVARIANT(); + return new Submission(); +} + +Model::XSubmission_t Model::cloneSubmission(const XPropertySet_t& xSubmission) + throw( RuntimeException ) +{ + DBG_INVARIANT(); + XSubmission_t xNewSubmission = createSubmission(); + XPropertySet_t xAsPropertySet( xNewSubmission.get() ); + copy( xSubmission.get(), xAsPropertySet ); + return xNewSubmission; +} + +Model::XSubmission_t Model::getSubmission( const rtl::OUString& sId ) + throw( RuntimeException ) +{ + DBG_INVARIANT(); + XSubmission_t xSubmission; + if ( mpSubmissions->hasItem( sId ) ) + xSubmission = xSubmission.query( mpSubmissions->getItem( sId ) ); + return xSubmission; +} + +Model::XSet_t Model::getSubmissions() + throw( RuntimeException ) +{ + DBG_INVARIANT(); + return mxSubmissions; +} + + + +// +// implementation of XFormsUIHelper1 interface +// can be found in file model_ui.cxx +// + + + +// +// implement XPropertySet & friends +// + +#define HANDLE_ID 0 +#define HANDLE_Instance 1 +#define HANDLE_InstanceURL 2 +#define HANDLE_ForeignSchema 3 +#define HANDLE_SchemaRef 4 +#define HANDLE_Namespaces 5 +#define HANDLE_ExternalData 6 + +#define REGISTER_PROPERTY( property, type ) \ + registerProperty( PROPERTY( property, type ), \ + new DirectPropertyAccessor< Model, type >( this, &Model::set##property, &Model::get##property ) ); + +#define REGISTER_PROPERTY_API( property, type ) \ + registerProperty( PROPERTY( property, type ), \ + new APIPropertyAccessor< Model, type >( this, &Model::set##property, &Model::get##property ) ); + +#define REGISTER_BOOL_PROPERTY( property ) \ + registerProperty( PROPERTY( property, sal_Bool ), \ + new BooleanPropertyAccessor< Model, bool >( this, &Model::set##property, &Model::get##property ) ); + +void Model::initializePropertySet() +{ + REGISTER_PROPERTY_API ( ID, OUString ); + REGISTER_PROPERTY ( ForeignSchema, XDocument_t ); + REGISTER_PROPERTY ( SchemaRef, OUString ); + REGISTER_PROPERTY ( Namespaces, XNameContainer_t ); + REGISTER_BOOL_PROPERTY( ExternalData ); +} + +void Model::update() + throw( RuntimeException ) +{ + rebuild(); +} + + +sal_Int64 Model::getSomething( const IntSequence_t& xId ) + throw( RuntimeException ) +{ + return reinterpret_cast<sal_Int64>( ( xId == getUnoTunnelID() ) ? this : NULL ); +} + +Sequence<sal_Int8> Model::getImplementationId() + throw( RuntimeException ) +{ + return getUnoTunnelID(); +} + + +// +// 'shift' operators for getting data into and out of Anys +// + +void operator <<= ( com::sun::star::uno::Any& rAny, + xforms::Model* pModel) +{ + Reference<XPropertySet> xPropSet( static_cast<XPropertySet*>( pModel ) ); + rAny <<= xPropSet; +} + +bool operator >>= ( xforms::Model* pModel, + com::sun::star::uno::Any& rAny ) +{ + bool bRet = false; + + // acquire model pointer through XUnoTunnel + Reference<XUnoTunnel> xTunnel( rAny, UNO_QUERY ); + if( xTunnel.is() ) + { + pModel = reinterpret_cast<xforms::Model*>( + xTunnel->getSomething( xforms::Model::getUnoTunnelID() ) ); + bRet = true; + } + + return bRet; +} diff --git a/forms/source/xforms/model.hxx b/forms/source/xforms/model.hxx new file mode 100644 index 000000000000..be9a5134d1da --- /dev/null +++ b/forms/source/xforms/model.hxx @@ -0,0 +1,435 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _MODEL_HXX +#define _MODEL_HXX + + +// include for parent class(es) +#include <cppuhelper/implbase4.hxx> +#include <propertysetbase.hxx> +#include <com/sun/star/xforms/XModel.hpp> +#include <com/sun/star/xforms/XFormsUIHelper1.hpp> +#include <com/sun/star/util/XUpdatable.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> + + +// includes for member variables +#include <com/sun/star/uno/Reference.hxx> +#include <map> + + +// forward declaractions +namespace com { namespace sun { namespace star +{ + namespace xml { namespace dom { class XDocument; } } + namespace xml { namespace dom { class XNode; } } + namespace uno { template<typename T> class Sequence; } + namespace lang { class IndexOutOfBoundsException; } + namespace lang { class IllegalArgumentException; } + namespace beans { class XPropertySet; } + namespace container { class XSet; } + namespace container { class XNameContainer; } + namespace frame { class XModel; } +} } } +namespace rtl { class OUString; } +namespace xforms +{ + class Binding; + class MIP; + class BindingCollection; + class SubmissionCollection; + class InstanceCollection; + class EvaluationContext; +} + + +namespace xforms +{ + +/** An XForms Model. Contains: + * # (set of) instance data (XML DOM tree) + * # (set of) bindings + * # (set of) submissions + * # (NOT YET IMPLEMENTED) actions (set of) + * + * See http://www.w3.org/TR/xforms/ for more information. + */ +typedef cppu::ImplInheritanceHelper4< + PropertySetBase, + com::sun::star::xforms::XModel, + com::sun::star::xforms::XFormsUIHelper1, + com::sun::star::util::XUpdatable, + com::sun::star::lang::XUnoTunnel +> Model_t; +class Model : public Model_t +{ + // a number of local typedefs, to make the remaining header readable + typedef com::sun::star::uno::Reference<com::sun::star::xml::dom::XDocument> XDocument_t; + typedef com::sun::star::uno::Reference<com::sun::star::xml::dom::XNode> XNode_t; + typedef com::sun::star::lang::IndexOutOfBoundsException IndexOutOfBoundsException_t; + typedef com::sun::star::lang::IllegalArgumentException IllegalArgumentException_t; + typedef com::sun::star::uno::Reference<com::sun::star::beans::XPropertySet> XPropertySet_t; + typedef com::sun::star::uno::Reference<com::sun::star::xforms::XDataTypeRepository> XDataTypeRepository_t; + typedef com::sun::star::uno::Reference<com::sun::star::container::XNameContainer> XNameContainer_t; + typedef com::sun::star::uno::Reference<com::sun::star::xforms::XSubmission> XSubmission_t; + typedef com::sun::star::uno::Reference<com::sun::star::frame::XModel> Frame_XModel_t; + typedef com::sun::star::uno::Reference<com::sun::star::xforms::XModel> XModel_t; + typedef com::sun::star::uno::Reference<com::sun::star::task::XInteractionHandler> XInteractionHandler_t; + + typedef com::sun::star::uno::Reference<com::sun::star::container::XSet> XSet_t; + typedef com::sun::star::beans::PropertyVetoException PropertyVetoException_t; + typedef com::sun::star::beans::UnknownPropertyException UnknownPropertyException_t; + typedef com::sun::star::util::VetoException VetoException_t; + typedef com::sun::star::lang::WrappedTargetException WrappedTargetException_t; + typedef com::sun::star::uno::RuntimeException RuntimeException_t; + typedef com::sun::star::uno::Any Any_t; + typedef com::sun::star::uno::Sequence<sal_Int8> IntSequence_t; + typedef std::multimap<XNode_t,std::pair<void*,MIP> > MIPs_t; + + +private: + + rtl::OUString msID; /// the model ID + BindingCollection* mpBindings; /// the bindings + SubmissionCollection* mpSubmissions; /// the submissions + InstanceCollection* mpInstances; /// the instance(s) + + XDataTypeRepository_t mxDataTypes; /// the XSD data-types used + XDocument_t mxForeignSchema; /// the XSD-schema part we cannot + /// map onto data types + rtl::OUString msSchemaRef; /// xforms:model/@schema attribute + + XNameContainer_t mxNamespaces; /// namespaces for entire model + + + // references to mpBindings/mpSubmissions, for UNO reference counting + XSet_t mxBindings; + XSet_t mxSubmissions; + XSet_t mxInstances; + + MIPs_t maMIPs; /// map nodes to their MIPs + + bool mbInitialized; /// has model been initialized ? + bool mbExternalData; /// is the data of this model to be considered an ingegral part of the document? + + void initializePropertySet(); + + void ensureAtLeastOneInstance(); + + +public: + + /// create a new model with an empty, default instance + Model(); + virtual ~Model() throw(); + + // get Model implementation from API object + static Model* getModel( const com::sun::star::uno::Reference<com::sun::star::xforms::XModel>& ); + + xforms::EvaluationContext getEvaluationContext(); + + + static IntSequence_t getUnoTunnelID(); + + + // get/set that part of the schema, that we can't interpret as data types + XDocument_t getForeignSchema() const; + void setForeignSchema( const XDocument_t& ); + + // get/set the xforms:model/@schema attribute + rtl::OUString getSchemaRef() const; + void setSchemaRef( const rtl::OUString& ); + + // get/set namespaces for entire model + XNameContainer_t getNamespaces() const; + void setNamespaces( const XNameContainer_t& ); + + // get/set the ExternalData property + bool getExternalData() const; + void setExternalData( bool _bData ); + + +#if OSL_DEBUG_LEVEL > 1 + void dbg_assertInvariant() const; +#endif + + + // + // MIP (model item property) management + // + + // register MIPs which apply to a given node; only to be called by bindings + // (The pTag parameter serves only to be able to remove the MIPs + // that were added using the same tag. No functions will be + // performed on it; hence the void* type.) + void addMIP( void* pTag, const XNode_t&, const MIP& ); + void removeMIPs( void* pTag ); + + /// query which MIPs appy to the given node + MIP queryMIP( const XNode_t& xNode ) const; + + /// re-bind all bindings + void rebind(); + + /// call defer notifications on all bindings + void deferNotifications( bool ); + + /// set a data value in the instance + /// (also defers notifications) + bool setSimpleContent( const XNode_t&, const rtl::OUString& ); + + /// load instance data + void loadInstance( sal_Int32 nInstance ); + void loadInstances(); + + /// has model been initialized? + bool isInitialized() const; + + /// is model currently valid (for submission)? + bool isValid() const; + + + + // + // XModel + // implement the xforms::XModel implementation + // + + + virtual rtl::OUString SAL_CALL getID() + throw( RuntimeException_t ); + + virtual void SAL_CALL setID( const rtl::OUString& sID ) + throw( RuntimeException_t ); + + virtual void SAL_CALL initialize() + throw( RuntimeException_t ); + + virtual void SAL_CALL rebuild() + throw( RuntimeException_t ); + + virtual void SAL_CALL recalculate() + throw( RuntimeException_t ); + + virtual void SAL_CALL revalidate() + throw( RuntimeException_t ); + + virtual void SAL_CALL refresh() + throw( RuntimeException_t ); + + virtual void SAL_CALL submit( const rtl::OUString& sID ) + throw( VetoException_t, WrappedTargetException_t, RuntimeException_t ); + + virtual void SAL_CALL submitWithInteraction( const ::rtl::OUString& id, const XInteractionHandler_t& _rxHandler ) + throw( VetoException_t, WrappedTargetException_t, RuntimeException_t ); + + virtual XDataTypeRepository_t SAL_CALL getDataTypeRepository( ) + throw( RuntimeException_t ); + + + // XModel: instance management + + virtual XSet_t SAL_CALL getInstances() + throw( RuntimeException_t ); + + virtual XDocument_t SAL_CALL getInstanceDocument( const rtl::OUString& ) + throw( RuntimeException_t ); + + virtual XDocument_t SAL_CALL getDefaultInstance() + throw( RuntimeException_t ); + + + + // XModel: binding management + + virtual XPropertySet_t SAL_CALL createBinding() + throw( RuntimeException_t ); + + virtual XPropertySet_t SAL_CALL cloneBinding( const XPropertySet_t& ) + throw( RuntimeException_t ); + + virtual XPropertySet_t SAL_CALL getBinding( const rtl::OUString& ) + throw( RuntimeException_t ); + + virtual XSet_t SAL_CALL getBindings() + throw( RuntimeException_t ); + + + // XModel: submission management + + virtual XSubmission_t SAL_CALL createSubmission() + throw( RuntimeException_t ); + + virtual XSubmission_t SAL_CALL cloneSubmission( const XPropertySet_t& ) + throw( RuntimeException_t ); + + virtual XSubmission_t SAL_CALL getSubmission( const rtl::OUString& ) + throw( RuntimeException_t ); + + virtual XSet_t SAL_CALL getSubmissions() + throw( RuntimeException_t ); + + + + // + // XFormsUIHelper1 & friends: + // (implementation in model_ui.cxx) + // + + /// determine a reasonable control service for a given node + /// (based on data type MIP assigned to the node) + virtual rtl::OUString SAL_CALL getDefaultServiceNameForNode( const XNode_t& xNode ) throw (RuntimeException_t); + + /// call getDefaultBindingExpressionForNode with default evaluation context + virtual rtl::OUString SAL_CALL getDefaultBindingExpressionForNode( const XNode_t& xNode ) throw (RuntimeException_t); + + /// determine a reasonable default binding expression for a given node + /// and a given evaluation context + /// @returns expression, or empty string if no expression could be derived + rtl::OUString getDefaultBindingExpressionForNode( + const XNode_t&, + const EvaluationContext& ); + + virtual rtl::OUString SAL_CALL getNodeDisplayName( const XNode_t&, + sal_Bool bDetail ) + throw( RuntimeException_t ); + + virtual rtl::OUString SAL_CALL getNodeName( const XNode_t& ) + throw( RuntimeException_t ); + + virtual rtl::OUString SAL_CALL getBindingName( const XPropertySet_t&, + sal_Bool bDetail ) + throw( RuntimeException_t ); + + virtual rtl::OUString SAL_CALL getSubmissionName( const XPropertySet_t&, + sal_Bool bDetail ) + throw( RuntimeException_t ); + + virtual XPropertySet_t SAL_CALL cloneBindingAsGhost( const XPropertySet_t& ) + throw( RuntimeException_t ); + + virtual void SAL_CALL removeBindingIfUseless( const XPropertySet_t& ) + throw( RuntimeException_t ); + + virtual XDocument_t SAL_CALL newInstance( const rtl::OUString& sName, + const rtl::OUString& sURL, + sal_Bool bURLOnce ) + throw( RuntimeException_t ); + + virtual void SAL_CALL renameInstance( const rtl::OUString& sFrom, + const rtl::OUString& sTo, + const rtl::OUString& sURL, + sal_Bool bURLOnce ) + throw( RuntimeException_t ); + + virtual void SAL_CALL removeInstance( const rtl::OUString& sName ) + throw( RuntimeException_t ); + + + virtual XModel_t SAL_CALL newModel( const Frame_XModel_t& xComponent, + const rtl::OUString& sName ) + throw( RuntimeException_t ); + virtual void SAL_CALL renameModel( const Frame_XModel_t& xComponent, + const rtl::OUString& sFrom, + const rtl::OUString& sTo ) + throw( RuntimeException_t ); + + virtual void SAL_CALL removeModel( const Frame_XModel_t& xComponent, + const rtl::OUString& sName ) + throw( RuntimeException_t ); + + + virtual XNode_t SAL_CALL createElement( const XNode_t& xParent, + const rtl::OUString& sName ) + throw( RuntimeException_t ); + + virtual XNode_t SAL_CALL createAttribute( const XNode_t& xParent, + const rtl::OUString& sName ) + throw( RuntimeException_t ); + + virtual XNode_t SAL_CALL renameNode( const XNode_t& xNode, + const rtl::OUString& sName ) + throw( RuntimeException_t ); + + virtual XPropertySet_t SAL_CALL getBindingForNode( const XNode_t&, + sal_Bool bCreate ) + throw( RuntimeException_t ); + + virtual void SAL_CALL removeBindingForNode( const XNode_t& ) + throw( RuntimeException_t ); + + virtual rtl::OUString SAL_CALL getResultForExpression( + const XPropertySet_t& xBinding, + sal_Bool bIsBindingExpression, + const rtl::OUString& sExpression ) + throw( RuntimeException_t ); + + virtual sal_Bool SAL_CALL isValidXMLName( const rtl::OUString& sName ) + throw( RuntimeException_t ); + + virtual sal_Bool SAL_CALL isValidPrefixName( const rtl::OUString& sName ) + throw( RuntimeException_t ); + + virtual void SAL_CALL setNodeValue( + const XNode_t& xNode, + const rtl::OUString& sValue ) + throw( RuntimeException_t ); + + + // + // XUpdatable + // + +public: + virtual void SAL_CALL update() + throw( RuntimeException_t ); + + // + // XUnoTunnel + // + +public: + virtual sal_Int64 SAL_CALL getSomething( const IntSequence_t& ) + throw( RuntimeException_t ); + + // + // XTypeProvider::getImplementationId + // + +public: + virtual IntSequence_t SAL_CALL getImplementationId() + throw( RuntimeException_t ); + +}; + +// finally, allow 'shifting' of Model objects into/out of Any +void operator <<= ( com::sun::star::uno::Any&, const xforms::Model* ); +bool operator >>= ( xforms::Model*, const com::sun::star::uno::Any& ); + +} // namespace +#endif diff --git a/forms/source/xforms/model_helper.hxx b/forms/source/xforms/model_helper.hxx new file mode 100644 index 000000000000..d67a83c8cdb1 --- /dev/null +++ b/forms/source/xforms/model_helper.hxx @@ -0,0 +1,167 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _MODEL_HELPER_HXX +#define _MODEL_HELPER_HXX + +// +// some helper definitions that must be available for model.cxx and +// model_ui.cxx +// + +#include "namedcollection.hxx" +#include "binding.hxx" +#include "submission.hxx" +#include "unohelper.hxx" + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> + +namespace xforms +{ + class Model; +} + +// +// BindingCollection +// + +namespace xforms +{ + +class BindingCollection : public NamedCollection<com::sun::star::uno::Reference<com::sun::star::beans::XPropertySet> > +{ + Model* mpModel; + +public: + BindingCollection( Model* pModel ) : mpModel( pModel ) {} + virtual ~BindingCollection() {} + + virtual bool isValid( const T& t ) const + { + return Binding::getBinding( t ) != NULL; + } + +protected: + virtual void _insert( const T& t ) + { + OSL_ENSURE( Binding::getBinding( t ) != NULL, "invalid item?" ); + Binding::getBinding( t )->_setModel( Binding::Model_t( mpModel ) ); + } + + virtual void _remove( const T& t ) + { + OSL_ENSURE( Binding::getBinding( t ) != NULL, "invalid item?" ); + Binding::getBinding( t )->_setModel( Binding::Model_t() ); + } +}; + + + +// +// SubmissionCollection +// + +class SubmissionCollection : public NamedCollection<com::sun::star::uno::Reference<com::sun::star::beans::XPropertySet> > +{ + Model* mpModel; + +public: + SubmissionCollection( Model* pModel ) : mpModel( pModel ) {} + virtual ~SubmissionCollection() {} + +public: + virtual bool isValid( const T& t ) const + { + return Submission::getSubmission( t ) != NULL; + } + +protected: + virtual void _insert( const T& t ) + { + OSL_ENSURE( Submission::getSubmission( t ) != NULL, "invalid item?" ); + Submission::getSubmission( t )->setModel( com::sun::star::uno::Reference<com::sun::star::xforms::XModel>( mpModel ) ); + } + + virtual void _remove( const T& t ) + { + OSL_ENSURE( Submission::getSubmission( t ) != NULL, "invalid item?" ); + Submission::getSubmission( t )->setModel( com::sun::star::uno::Reference<com::sun::star::xforms::XModel>( ) ); + } +}; + + +// +// InstanceCollection +// + +class InstanceCollection : public Collection<com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> > +{ +public: + virtual bool isValid( const T& t ) const + { + const com::sun::star::beans::PropertyValue* pValues = t.getConstArray(); + rtl::OUString sInstance( OUSTRING("Instance") ); + sal_Bool bFound = sal_False; + for( sal_Int32 i = 0; ( ! bFound ) && ( i < t.getLength() ); i++ ) + { + bFound |= ( pValues[i].Name == sInstance ); + } + return bFound ? true : false; + } +}; + + +// +// helper functions +// + +sal_Int32 lcl_findInstance( const InstanceCollection*, + const rtl::OUString& ); + + +// get values from Sequence<PropertyValue> describing an Instance +void getInstanceData( + const com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>&, + rtl::OUString* pID, + com::sun::star::uno::Reference<com::sun::star::xml::dom::XDocument>*, + rtl::OUString* pURL, + bool* pURLOnce ); + +// set values on Sequence<PropertyValue> for an Instance +void setInstanceData( + com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>&, + const rtl::OUString* pID, + const com::sun::star::uno::Reference<com::sun::star::xml::dom::XDocument>*, + const rtl::OUString* pURL, + const bool* pURLOnce ); + +} // namespace xforms + +#endif diff --git a/forms/source/xforms/model_ui.cxx b/forms/source/xforms/model_ui.cxx new file mode 100644 index 000000000000..a62ac1fa9ac9 --- /dev/null +++ b/forms/source/xforms/model_ui.cxx @@ -0,0 +1,1066 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include "model.hxx" +#include "model_helper.hxx" +#include "mip.hxx" +#include "evaluationcontext.hxx" +#include "unohelper.hxx" +#include "submission/serialization_app_xml.hxx" +#include "resourcehelper.hxx" +#include "xmlhelper.hxx" +#include "convert.hxx" + +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <tools/debug.hxx> + +// UNO classes +#include <com/sun/star/xml/dom/XNode.hpp> +#include <com/sun/star/xml/dom/XDocumentBuilder.hpp> +#include <com/sun/star/xml/dom/XDocumentFragment.hpp> +#include <com/sun/star/xml/dom/XNamedNodeMap.hpp> +#include <com/sun/star/xml/xpath/XXPathObject.hpp> +#include <com/sun/star/xml/xpath/XPathObjectType.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XTextInputStream.hpp> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/xforms/XFormsSupplier.hpp> +#include <com/sun/star/xforms/XDataTypeRepository.hpp> +#include <com/sun/star/xsd/XDataType.hpp> +#include <com/sun/star/xsd/DataTypeClass.hpp> + + +using rtl::OUString; +using rtl::OUStringBuffer; +using com::sun::star::beans::PropertyValue; +using com::sun::star::io::XInputStream; +using com::sun::star::io::XActiveDataSink; +using com::sun::star::io::XTextInputStream; +using com::sun::star::container::XEnumeration; +using com::sun::star::container::XNameContainer; +using com::sun::star::xforms::XFormsSupplier; + +using namespace xforms; +using namespace com::sun::star::uno; +using namespace com::sun::star::xml::dom; +using namespace com::sun::star::xml::xpath; + + + +// +// implement XFormsUIHelper1 +// + +OUString Model::getDefaultServiceNameForNode( const XNode_t& xNode ) + throw( RuntimeException ) +{ + // determine service for control. string/text field is default. + OUString sService = OUSTRING("com.sun.star.form.component.TextField"); + + // query repository for suitable type + OSL_ENSURE( mxDataTypes.is(), "no type repository?" ); + OUString sTypeName = queryMIP( xNode ).getTypeName(); + if( mxDataTypes->hasByName( sTypeName ) ) + { + OSL_ENSURE( mxDataTypes->getDataType( sTypeName ).is(), + "has or has not?" ); + + switch( mxDataTypes->getDataType( sTypeName )->getTypeClass() ) + { + case com::sun::star::xsd::DataTypeClass::BOOLEAN: + sService = OUSTRING("com.sun.star.form.component.CheckBox"); + break; + case com::sun::star::xsd::DataTypeClass::DOUBLE: + case com::sun::star::xsd::DataTypeClass::DECIMAL: + case com::sun::star::xsd::DataTypeClass::FLOAT: + sService = OUSTRING("com.sun.star.form.component.NumericField"); + break; + + case com::sun::star::xsd::DataTypeClass::STRING: + case com::sun::star::xsd::DataTypeClass::DURATION: + case com::sun::star::xsd::DataTypeClass::DATETIME: + case com::sun::star::xsd::DataTypeClass::TIME: + case com::sun::star::xsd::DataTypeClass::DATE: + case com::sun::star::xsd::DataTypeClass::gYearMonth: + case com::sun::star::xsd::DataTypeClass::gYear: + case com::sun::star::xsd::DataTypeClass::gMonthDay: + case com::sun::star::xsd::DataTypeClass::gDay: + case com::sun::star::xsd::DataTypeClass::gMonth: + case com::sun::star::xsd::DataTypeClass::hexBinary: + case com::sun::star::xsd::DataTypeClass::base64Binary: + case com::sun::star::xsd::DataTypeClass::anyURI: + case com::sun::star::xsd::DataTypeClass::QName: + case com::sun::star::xsd::DataTypeClass::NOTATION: + default: + // keep default + break; + } + } + + return sService; +} + + +void lcl_OutPosition( OUStringBuffer& rBuffer, + const Reference<XNode>& xNode ) +{ + OSL_ENSURE( xNode->getParentNode().is(), "need parent" ); + + // count # of occurences of this node + sal_Int32 nFound = 0; + sal_Int32 nPosition = -1; + if( xNode->getParentNode().is() ) + { + for( Reference<XNode> xIter = xNode->getParentNode()->getFirstChild(); + xIter != NULL; + xIter = xIter->getNextSibling() ) + { + if( xIter->getNodeType() == xNode->getNodeType() && + xIter->getNodeName() == xNode->getNodeName() && + xIter->getNamespaceURI() == xNode->getNamespaceURI() ) + { + nFound++; + if( xIter == xNode ) + nPosition = nFound; + } + } + } + OSL_ENSURE( nFound > 0 && nPosition > 0, "node not found???" ); + + // output position (if necessary) + if( nFound > 1 ) + { + rBuffer.insert( 0, sal_Unicode(']') ); + rBuffer.insert( 0, nPosition ); + rBuffer.insert( 0, sal_Unicode('[') ); + } +} + +void lcl_OutName( OUStringBuffer& rBuffer, + const Reference<XNode>& xNode ) +{ + rBuffer.insert( 0, xNode->getNodeName() ); + OUString sPrefix = xNode->getPrefix(); + if( sPrefix.getLength() > 0 ) + { + rBuffer.insert( 0, sal_Unicode(':') ); + rBuffer.insert( 0, sPrefix ); + } +} + +void lcl_OutInstance( OUStringBuffer& rBuffer, + const Reference<XNode>& xNode, + Model* pModel ) +{ + Reference<XDocument> xDoc = xNode->getOwnerDocument(); + + if( xDoc != pModel->getDefaultInstance() ) + { + rBuffer.insert( 0, OUSTRING("')") ); + + // iterate over instances, and find the right one + OUString sInstanceName; + Reference<XEnumeration> xEnum = + pModel->getInstances()->createEnumeration(); + while( ( sInstanceName.getLength() == 0 ) && xEnum->hasMoreElements() ) + { + Sequence<PropertyValue> aValues; + xEnum->nextElement() >>= aValues; + + // get ID and instance + OUString sId; + Reference<XDocument> xInstance; + getInstanceData( aValues, &sId, &xInstance, NULL, NULL ); + + // now check whether this was our instance: + if( xInstance == xDoc ) + sInstanceName = sId; + } + + rBuffer.insert( 0, sInstanceName ); + rBuffer.insert( 0, OUSTRING("instance('") ); + } +} + +OUString Model::getDefaultBindingExpressionForNode( + const XNode_t& xNode, + const EvaluationContext& rContext) +{ + OSL_ENSURE( xNode.is(), "need node" ); + + // iterate upwards and put sections into the expression buffer. + // Stop iteration either at context node (relative expression) or + // at document root, whichever occurs first. + OUStringBuffer aBuffer; + for( Reference<XNode> xCurrent = xNode; + xCurrent.is() && xCurrent != rContext.mxContextNode; + xCurrent = xCurrent->getParentNode() ) + { + // insert a '/' for every step except the first + if( aBuffer.getLength() > 0 ) + aBuffer.insert( 0, sal_Unicode('/') ); + + switch( xCurrent->getNodeType() ) + { + case NodeType_ELEMENT_NODE: + lcl_OutPosition( aBuffer, xCurrent ); + lcl_OutName( aBuffer, xCurrent ); + break; + + case NodeType_TEXT_NODE: + lcl_OutPosition( aBuffer, xCurrent ); + aBuffer.insert( 0, OUSTRING("text()") ); + break; + + case NodeType_ATTRIBUTE_NODE: + lcl_OutName( aBuffer, xCurrent ); + aBuffer.insert( 0, sal_Unicode('@') ); + break; + + case NodeType_DOCUMENT_NODE: + // check for which instance we have + lcl_OutInstance( aBuffer, xCurrent, this ); + break; + + default: + // unknown type? fail! + OSL_ENSURE( false, "unknown node type!" ); + xCurrent.set( NULL ); + aBuffer.makeStringAndClear(); + // we'll remove the slash below + aBuffer.insert( 0, sal_Unicode('/') ); + break; + } + } + + return aBuffer.makeStringAndClear(); +} + + + +OUString Model::getDefaultBindingExpressionForNode( const XNode_t& xNode ) + throw( RuntimeException ) +{ + return getDefaultBindingExpressionForNode( xNode, getEvaluationContext() ); +} + +bool lcl_isWhitespace( const OUString& rString ) +{ + sal_Int32 nLength = rString.getLength(); + const sal_Unicode* pStr = rString.getStr(); + + bool bWhitespace = true; + for( sal_Int32 i = 0; bWhitespace && ( i < nLength ); i++ ) + { + sal_Unicode c = pStr[i]; + bWhitespace = ( c == sal_Unicode(0x09) || + c == sal_Unicode(0x0A) || + c == sal_Unicode(0x0D) || + c == sal_Unicode(0x20) ); + } + return bWhitespace; +} + +OUString Model::getNodeDisplayName( const XNode_t& xNode, + sal_Bool bDetail ) + throw( RuntimeException ) +{ + OUStringBuffer aBuffer; + + switch( xNode->getNodeType() ) + { + case NodeType_ELEMENT_NODE: + lcl_OutName( aBuffer, xNode ); + break; + + case NodeType_TEXT_NODE: + { + OUString sContent = xNode->getNodeValue(); + if( bDetail || ! lcl_isWhitespace( sContent ) ) + { + aBuffer.append( sal_Unicode('"') ); + aBuffer.append( Convert::collapseWhitespace( sContent ) ); + aBuffer.append( sal_Unicode('"') ); + } + } + break; + + case NodeType_ATTRIBUTE_NODE: + lcl_OutName( aBuffer, xNode ); + aBuffer.insert( 0, sal_Unicode('@') ); + break; + + case NodeType_DOCUMENT_NODE: + if( xNode == getDefaultInstance() ) + aBuffer.append( sal_Unicode('/') ); + else + lcl_OutInstance( aBuffer, xNode, this ); + break; + + default: + // unknown type? fail! + OSL_ENSURE( false, "unknown node type!" ); + break; + } + + return aBuffer.makeStringAndClear(); +} + +OUString Model::getNodeName( const XNode_t& xNode ) + throw( RuntimeException ) +{ + OUStringBuffer aBuffer; + + switch( xNode->getNodeType() ) + { + case NodeType_ELEMENT_NODE: + case NodeType_ATTRIBUTE_NODE: + lcl_OutName( aBuffer, xNode ); + break; + + case NodeType_TEXT_NODE: + case NodeType_DOCUMENT_NODE: + default: + // unknown type? fail! + OSL_ENSURE( false, "no name for this node type!" ); + break; + } + + return aBuffer.makeStringAndClear(); +} + +OUString Model::getBindingName( const XPropertySet_t& xBinding, + sal_Bool /*bDetail*/ ) + throw( RuntimeException ) +{ + OUString sID; + xBinding->getPropertyValue( OUSTRING("BindingID" ) ) >>= sID; + OUString sExpression; + xBinding->getPropertyValue( OUSTRING("BindingExpression" ) ) >>= sExpression; + + OUStringBuffer aBuffer; + if( sID.getLength() > 0 ) + { + aBuffer.append( sID ); + aBuffer.append( OUSTRING(" (" )); + aBuffer.append( sExpression ); + aBuffer.append( OUSTRING(")" )); + } + else + aBuffer.append( sExpression ); + + return aBuffer.makeStringAndClear(); +} + +OUString Model::getSubmissionName( const XPropertySet_t& xSubmission, + sal_Bool /*bDetail*/ ) + throw( RuntimeException ) +{ + OUString sID; + xSubmission->getPropertyValue( OUSTRING("ID") ) >>= sID; + return sID; +} + +Model::XPropertySet_t Model::cloneBindingAsGhost( const XPropertySet_t &xBinding ) + throw( RuntimeException ) +{ + // Create a new binding instance first... + Binding *pBinding = new Binding(); + + // ...and bump up the "defered notification counter" + // to prevent this binding from contributing to the + // MIPs table... + pBinding->deferNotifications(true); + + // Copy the propertyset and return result... + XPropertySet_t xNewBinding(pBinding); + copy( xBinding, xNewBinding ); + return xNewBinding; +} + +void Model::removeBindingIfUseless( const XPropertySet_t& xBinding ) + throw( RuntimeException ) +{ + Binding* pBinding = Binding::getBinding( xBinding ); + if( pBinding != NULL ) + { + if( ! pBinding->isUseful() ) + mpBindings->removeItem( pBinding ); + } +} + +Model::XDocument_t Model::newInstance( const rtl::OUString& sName, + const rtl::OUString& sURL, + sal_Bool bURLOnce ) + throw( RuntimeException ) +{ + // create a default instance with <instanceData> element + XDocument_t xInstance = getDocumentBuilder()->newDocument(); + DBG_ASSERT( xInstance.is(), "failed to create DOM instance" ); + + Reference<XNode>( xInstance, UNO_QUERY_THROW )->appendChild( + Reference<XNode>( xInstance->createElement( OUSTRING("instanceData") ), + UNO_QUERY_THROW ) ); + + Sequence<PropertyValue> aSequence; + bool bOnce = bURLOnce; // bool, so we can take address in setInstanceData + setInstanceData( aSequence, &sName, &xInstance, &sURL, &bOnce ); + sal_Int32 nInstance = mpInstances->addItem( aSequence ); + loadInstance( nInstance ); + + return xInstance; +} + +sal_Int32 lcl_findProp( const PropertyValue* pValues, + sal_Int32 nLength, + const rtl::OUString& rName ) +{ + bool bFound = false; + sal_Int32 n = 0; + for( ; !bFound && n < nLength; n++ ) + { + bFound = ( pValues[n].Name == rName ); + } + return bFound ? ( n - 1) : -1; +} + +sal_Int32 xforms::lcl_findInstance( const InstanceCollection* pInstances, + const rtl::OUString& rName ) +{ + sal_Int32 nLength = pInstances->countItems(); + sal_Int32 n = 0; + bool bFound = false; + for( ; !bFound && n < nLength; n++ ) + { + OUString sName; + getInstanceData( pInstances->getItem( n ), &sName, NULL, NULL, NULL ); + bFound = ( sName == rName ); + } + return bFound ? ( n - 1 ) : -1; +} + +void Model::renameInstance( const rtl::OUString& sFrom, + const rtl::OUString& sTo, + const rtl::OUString& sURL, + sal_Bool bURLOnce ) + throw( RuntimeException ) +{ + sal_Int32 nPos = lcl_findInstance( mpInstances, sFrom ); + if( nPos != -1 ) + { + Sequence<PropertyValue> aSeq = mpInstances->getItem( nPos ); + PropertyValue* pSeq = aSeq.getArray(); + sal_Int32 nLength = aSeq.getLength(); + + sal_Int32 nProp = lcl_findProp( pSeq, nLength, OUSTRING("ID") ); + if( nProp == -1 ) + { + // add name property + aSeq.realloc( nLength + 1 ); + pSeq = aSeq.getArray(); + pSeq[ nLength ].Name = OUSTRING("ID"); + nProp = nLength; + } + + // change name + pSeq[ nProp ].Value <<= sTo; + + // change url + nProp = lcl_findProp( pSeq, nLength, OUSTRING("URL") ); + if(nProp != -1) + pSeq[ nProp ].Value <<= sURL; + + // change urlonce + nProp = lcl_findProp( pSeq, nLength, OUSTRING("URLOnce") ); + if(nProp != -1) + pSeq[ nProp ].Value <<= bURLOnce; + + // set instance + mpInstances->setItem( nPos, aSeq ); + } +} + +void Model::removeInstance( const rtl::OUString& sName ) + throw( RuntimeException ) +{ + sal_Int32 nPos = lcl_findInstance( mpInstances, sName ); + if( nPos != -1 ) + mpInstances->removeItem( mpInstances->getItem( nPos ) ); +} + +Reference<XNameContainer> lcl_getModels( + const Reference<com::sun::star::frame::XModel>& xComponent ) +{ + Reference<XNameContainer> xRet; + Reference<XFormsSupplier> xSupplier( xComponent, UNO_QUERY ); + if( xSupplier.is() ) + { + xRet = xSupplier->getXForms(); + } + return xRet; +} + +Model::XModel_t Model::newModel( const Reference<com::sun::star::frame::XModel>& xCmp, + const OUString& sName ) + throw( RuntimeException ) +{ + Model::XModel_t xModel; + Reference<XNameContainer> xModels = lcl_getModels( xCmp ); + if( xModels.is() + && ! xModels->hasByName( sName ) ) + { + Model* pModel = new Model(); + xModel.set( pModel ); + + pModel->setID( sName ); + pModel->newInstance( OUString(), OUString(), sal_False ); + pModel->initialize(); + xModels->insertByName( sName, makeAny( xModel ) ); + } + + return xModel; +} + +void Model::renameModel( const Reference<com::sun::star::frame::XModel>& xCmp, + const OUString& sFrom, + const OUString& sTo ) + throw( RuntimeException ) +{ + Reference<XNameContainer> xModels = lcl_getModels( xCmp ); + if( xModels.is() + && xModels->hasByName( sFrom ) + && ! xModels->hasByName( sTo ) ) + { + Reference<XModel> xModel( xModels->getByName( sFrom ), UNO_QUERY ); + xModel->setID( sTo ); + xModels->insertByName( sTo, makeAny( xModel ) ); + xModels->removeByName( sFrom ); + } +} + +void Model::removeModel( const Reference<com::sun::star::frame::XModel>& xCmp, + const OUString& sName ) + throw( RuntimeException ) +{ + Reference<XNameContainer> xModels = lcl_getModels( xCmp ); + if( xModels.is() + && xModels->hasByName( sName ) ) + { + xModels->removeByName( sName ); + } +} + +Model::XNode_t Model::createElement( const XNode_t& xParent, + const OUString& sName ) + throw( RuntimeException ) +{ + Reference<XNode> xNode; + if( xParent.is() + && isValidXMLName( sName ) ) + { + // TODO: implement proper namespace handling + xNode.set( xParent->getOwnerDocument()->createElement( sName ), + UNO_QUERY ); + } + return xNode; +} + +Model::XNode_t Model::createAttribute( const XNode_t& xParent, + const OUString& sName ) + throw( RuntimeException ) +{ + Reference<XNode> xNode; + Reference<XElement> xElement( xParent, UNO_QUERY ); + if( xParent.is() + && xElement.is() + && isValidXMLName( sName ) ) + { + // handle case where attribute already exists + sal_Int32 nCount = 0; + OUString sUniqueName = sName; + while( xElement->hasAttribute( sUniqueName ) ) + { + nCount++; + sUniqueName = sName + OUString::valueOf( nCount ); + } + + // TODO: implement proper namespace handling + xNode.set( xParent->getOwnerDocument()->createAttribute( sUniqueName ), + UNO_QUERY ); + } + return xNode; +} + +Model::XNode_t Model::renameNode( const XNode_t& xNode, + const rtl::OUString& sName ) + throw( RuntimeException ) +{ + // early out if we don't have to change the name + if( xNode->getNodeName() == sName ) + return xNode; + + // refuse to change name if its an attribute, and the name is already used + if( xNode->getNodeType() == NodeType_ATTRIBUTE_NODE + && xNode->getParentNode().is() + && Reference<XElement>(xNode->getParentNode(), UNO_QUERY_THROW)->hasAttribute( sName ) ) + return xNode; + + // note old binding expression so we can adjust bindings below + OUString sOldDefaultBindingExpression = + getDefaultBindingExpressionForNode( xNode ); + + Reference<XDocument> xDoc = xNode->getOwnerDocument(); + Reference<XNode> xNew; + if( xNode->getNodeType() == NodeType_ELEMENT_NODE ) + { + Reference<XElement> xElem = xDoc->createElement( sName ); + xNew.set( xElem, UNO_QUERY ); + + // iterate over all attributes and append them to the new element + Reference<XElement> xOldElem( xNode, UNO_QUERY ); + OSL_ENSURE( xNode.is(), "no element?" ); + + Reference<XNamedNodeMap> xMap = xNode->getAttributes(); + sal_Int32 nLength = xMap.is() ? xMap->getLength() : 0; + for( sal_Int32 n = 0; n < nLength; n++ ) + { + Reference<XAttr> xAttr( xMap->item(n), UNO_QUERY ); + xElem->setAttributeNode( xOldElem->removeAttributeNode( xAttr ) ); + } + + // iterate over all children and append them to the new element + for( Reference<XNode> xCurrent = xNode->getFirstChild(); + xCurrent.is(); + xCurrent = xNode->getFirstChild() ) + { + xNew->appendChild( xNode->removeChild( xCurrent ) ); + } + + xNode->getParentNode()->replaceChild( xNew, xNode ); + } + else if( xNode->getNodeType() == NodeType_ATTRIBUTE_NODE ) + { + // create new attribute + Reference<XAttr> xAttr = xDoc->createAttribute( sName ); + xAttr->setValue( xNode->getNodeValue() ); + + // replace node + Reference<XNode> xParent = xNode->getParentNode(); + xParent->removeChild( xNode ); + xNew = xParent->appendChild( Reference<XNode>( xAttr, UNO_QUERY ) ); + } + else + { + OSL_ENSURE( false, "can't rename this node type" ); + } + + // adjust bindings (if necessary): + if( xNew.is() ) + { + // iterate over bindings and replace default expressions + OUString sNewDefaultBindingExpression = + getDefaultBindingExpressionForNode( xNew ); + for( sal_Int32 n = 0; n < mpBindings->countItems(); n++ ) + { + Binding* pBinding = Binding::getBinding( + mpBindings->Collection<XPropertySet_t>::getItem( n ) ); + + if( pBinding->getBindingExpression() + == sOldDefaultBindingExpression ) + pBinding->setBindingExpression( sNewDefaultBindingExpression ); + } + } + + // return node; return old node if renaming failed + return xNew.is() ? xNew : xNode; +} + +Model::XPropertySet_t Model::getBindingForNode( const XNode_t& xNode, + sal_Bool bCreate ) + throw( RuntimeException ) +{ + OSL_ENSURE( xNode.is(), "no node?" ); + + // We will iterate over all bindings and determine the + // appropriateness of the respective binding for this node. The + // best one will be used. If we don't find any and bCreate is set, + // then we will create a suitable binding. + Binding* pBestBinding = NULL; + sal_Int32 nBestScore = 0; + + for( sal_Int32 n = 0; n < mpBindings->countItems(); n++ ) + { + Binding* pBinding = Binding::getBinding( + mpBindings->Collection<XPropertySet_t>::getItem( n ) ); + + OSL_ENSURE( pBinding != NULL, "no binding?" ); + Reference<XNodeList> xNodeList = pBinding->getXNodeList(); + + sal_Int32 nNodes = xNodeList.is() ? xNodeList->getLength() : 0; + if( nNodes > 0 && xNodeList->item( 0 ) == xNode ) + { + // allright, we found a suitable node. Let's determine how + // well it fits. Score: + // - bind to exactly this node is better than whole nodeset + // - simple binding expressions is better than complex ones + sal_Int32 nScore = 0; + if( nNodes == 1 ) + nScore ++; + if( pBinding->isSimpleBindingExpression() ) + nScore ++; + + // if we found a better binding, remember it + if( nScore > nBestScore ) + { + pBestBinding = pBinding; + nBestScore = nScore; + } + } + } + + // create binding, if none was found and bCreate is set + OSL_ENSURE( ( nBestScore == 0 ) == ( pBestBinding == NULL ), + "score != binding?" ); + if( bCreate && pBestBinding == NULL ) + { + pBestBinding = new Binding(); + pBestBinding->setBindingExpression( + getDefaultBindingExpressionForNode( xNode ) ); + mpBindings->addItem( pBestBinding ); + } + + return pBestBinding; +} + +void Model::removeBindingForNode( const XNode_t& ) + throw( RuntimeException ) +{ + // determine whether suitable binding is still used +} + +OUString lcl_serializeForDisplay( const Reference< XAttr >& _rxAttrNode ) +{ + ::rtl::OUString sResult; + OSL_ENSURE( _rxAttrNode.is(), "lcl_serializeForDisplay( attr ): invalid argument!" ); + if ( _rxAttrNode.is() ) + { + ::rtl::OUStringBuffer aBuffer; + aBuffer.append( _rxAttrNode->getName() ); + aBuffer.appendAscii( "=" ); + ::rtl::OUString sValue = _rxAttrNode->getValue(); + sal_Unicode nQuote = '"'; + if ( sValue.indexOf( nQuote ) >= 0 ) + nQuote = '\''; + aBuffer.append( nQuote ); + aBuffer.append( sValue ); + aBuffer.append( nQuote ); + aBuffer.append( (sal_Unicode)' ' ); + sResult = aBuffer.makeStringAndClear(); + } + return sResult; +} + +OUString lcl_serializeForDisplay( const Reference<XNodeList>& xNodes ) +{ + ::rtl::OUString sResult; + + // create document fragment + Reference<XDocument> xDocument( getDocumentBuilder()->newDocument() ); + Reference<XDocumentFragment> xFragment( + xDocument->createDocumentFragment() ); + Reference<XNode> xNode( xFragment, UNO_QUERY ); + OSL_ENSURE( xFragment.is(), "xFragment" ); + OSL_ENSURE( xNode.is(), "xNode" ); + + sal_Int32 nAttributeNodes = 0; + + // attach nodelist to fragment + sal_Int32 nLength = xNodes->getLength(); + for( sal_Int32 i = 0; i < nLength; i++ ) + { + Reference<XNode> xCurrent = xNodes->item( i ); + + switch ( xCurrent->getNodeType() ) + { + case NodeType_DOCUMENT_NODE: + // special-case documents: use top-level element instead + xCurrent = xCurrent->getFirstChild(); + break; + case NodeType_ATTRIBUTE_NODE: + { + Reference< XAttr > xAttr( xCurrent, UNO_QUERY ); + if ( xAttr.is() ) + { + sResult += lcl_serializeForDisplay( xAttr ); + ++nAttributeNodes; + } + } + continue; + + default: + break; + } + + // append node + xNode->appendChild( xDocument->importNode( xCurrent, sal_True ) ); + } + OSL_ENSURE( ( nAttributeNodes == 0 ) || ( nAttributeNodes == nLength ), + "lcl_serializeForDisplay: mixed attribute and non-attribute nodes?" ); + if ( nAttributeNodes ) + // had only attribute nodes + return sResult; + + // serialize fragment + CSerializationAppXML aSerialization; + aSerialization.setSource( xFragment ); + aSerialization.serialize(); + + // copy stream into buffer + Reference<XTextInputStream> xTextInputStream( + createInstance( OUSTRING("com.sun.star.io.TextInputStream") ), + UNO_QUERY ); + Reference<XActiveDataSink>( xTextInputStream, UNO_QUERY_THROW ) + ->setInputStream( aSerialization.getInputStream() ); + + /* WORK AROUND for problem in serialization: currently, multiple + XML delarations (<?xml...?>) are being written out and we don't + want them. When this is fixed, the code below is nice and + simple. The current code filters out the declarations. + OUString sResult = xTextInputStream->readString( Sequence<sal_Unicode>(), + sal_True ); + */ + + // well, the serialization prepends XML header(s) that we need to + // remove first. + OUStringBuffer aBuffer; + while( ! xTextInputStream->isEOF() ) + { + OUString sLine = xTextInputStream->readLine(); + if( sLine.getLength() > 0 + && sLine.compareToAscii( "<?xml", 5 ) != 0 ) + { + aBuffer.append( sLine ); + aBuffer.append( sal_Unicode('\n') ); + } + } + sResult = aBuffer.makeStringAndClear(); + + return sResult; +} + +OUString lcl_serializeForDisplay( const Reference<XXPathObject>& xResult ) +{ + // error handling first + if( ! xResult.is() ) + return getResource( RID_STR_XFORMS_CANT_EVALUATE ); + + + // TODO: localize + OUStringBuffer aBuffer; + + switch( xResult->getObjectType() ) + { + case XPathObjectType_XPATH_BOOLEAN: + aBuffer.append( xResult->getBoolean() + ? OUSTRING("true") + : OUSTRING("false") ); + break; + + case XPathObjectType_XPATH_STRING: + aBuffer.append( sal_Unicode('"') ); + aBuffer.append( xResult->getString() ); + aBuffer.append( sal_Unicode('"') ); + break; + + case XPathObjectType_XPATH_NODESET: + aBuffer.append( lcl_serializeForDisplay( xResult->getNodeList() ) ); + break; + + case XPathObjectType_XPATH_NUMBER: + aBuffer.append( xResult->getDouble() ); + break; + + case XPathObjectType_XPATH_UNDEFINED: + case XPathObjectType_XPATH_POINT: + case XPathObjectType_XPATH_RANGE: + case XPathObjectType_XPATH_LOCATIONSET: + case XPathObjectType_XPATH_USERS: + case XPathObjectType_XPATH_XSLT_TREE: + default: + // TODO: localized error message? + break; + } + + return aBuffer.makeStringAndClear(); +} + +OUString Model::getResultForExpression( + const XPropertySet_t& xBinding, + sal_Bool bIsBindingExpression, + const OUString& sExpression ) + throw( RuntimeException ) +{ + Binding* pBinding = Binding::getBinding( xBinding ); + if( pBinding == NULL ) + throw RuntimeException(); + + // prepare & evaluate expression + OUStringBuffer aBuffer; + ComputedExpression aExpression; + aExpression.setExpression( sExpression ); + if( bIsBindingExpression ) + { + // binding: use binding context and evaluation + aExpression.evaluate( pBinding->getEvaluationContext() ); + aBuffer.append( lcl_serializeForDisplay( aExpression.getXPath() ) ); + } + else + { + // MIP (not binding): iterate over bindings contexts + std::vector<EvaluationContext> aContext = + pBinding->getMIPEvaluationContexts(); + for( std::vector<EvaluationContext>::iterator aIter = aContext.begin(); + aIter != aContext.end(); + aIter ++ ) + { + aExpression.evaluate( *aIter ); + aBuffer.append( lcl_serializeForDisplay(aExpression.getXPath()) ); + aBuffer.append( sal_Unicode('\n') ); + } + } + return aBuffer.makeStringAndClear(); +} + +sal_Bool Model::isValidXMLName( const OUString& sName ) + throw( RuntimeException ) +{ + return isValidQName( sName, NULL ); +} + +sal_Bool Model::isValidPrefixName( const OUString& sName ) + throw( RuntimeException ) +{ + return ::isValidPrefixName( sName, NULL ); +} + +void Model::setNodeValue( + const XNode_t& xNode, + const rtl::OUString& sValue ) + throw( RuntimeException ) +{ + setSimpleContent( xNode, sValue ); +} + + +// +// helper functions from model_helper.hxx +// + +void xforms::getInstanceData( + const Sequence<PropertyValue>& aValues, + OUString* pID, + Reference<XDocument>* pInstance, + OUString* pURL, + bool* pURLOnce ) +{ + sal_Int32 nValues = aValues.getLength(); + const PropertyValue* pValues = aValues.getConstArray(); + for( sal_Int32 n = 0; n < nValues; n++ ) + { + const PropertyValue& rValue = pValues[n]; +#define PROP(NAME) \ + if( p##NAME != NULL && \ + rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(#NAME)) ) \ + rValue.Value >>= (*p##NAME) + PROP(ID); + PROP(Instance); + PROP(URL); + PROP(URLOnce); +#undef PROP + } +} + +void xforms::setInstanceData( + Sequence<PropertyValue>& aSequence, + const OUString* _pID, + const Reference<XDocument>* _pInstance, + const OUString* _pURL, + const bool* _pURLOnce ) +{ + // get old instance data + OUString sID; + Reference<XDocument> xInstance; + OUString sURL; + bool bURLOnce = false; + getInstanceData( aSequence, &sID, &xInstance, &sURL, &bURLOnce ); + const OUString* pID = ( sID.getLength() > 0 ) ? &sID : NULL; + const Reference<XDocument>* pInstance = xInstance.is() ? &xInstance : NULL; + const OUString* pURL = ( sURL.getLength() > 0 ) ? &sURL : NULL; + const bool* pURLOnce = ( bURLOnce && pURL != NULL ) ? &bURLOnce : NULL; + + // determine new instance data +#define PROP(NAME) if( _p##NAME != NULL ) p##NAME = _p##NAME + PROP(ID); + PROP(Instance); + PROP(URL); + PROP(URLOnce); +#undef PROP + + // count # of values we want to set + sal_Int32 nCount = 0; +#define PROP(NAME) if( p##NAME != NULL ) nCount++ + PROP(ID); + PROP(Instance); + PROP(URL); + PROP(URLOnce); +#undef PROP + + // realloc sequence and enter values; + aSequence.realloc( nCount ); + PropertyValue* pSequence = aSequence.getArray(); + sal_Int32 nIndex = 0; +#define PROP(NAME) \ + if( p##NAME != NULL ) \ + { \ + pSequence[ nIndex ].Name = OUSTRING(#NAME); \ + pSequence[ nIndex ].Value <<= *p##NAME; \ + nIndex++; \ + } + PROP(ID); + PROP(Instance); + PROP(URL); + PROP(URLOnce); +#undef PROP +} diff --git a/forms/source/xforms/namedcollection.hxx b/forms/source/xforms/namedcollection.hxx new file mode 100644 index 000000000000..ffae93ed2c90 --- /dev/null +++ b/forms/source/xforms/namedcollection.hxx @@ -0,0 +1,142 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _NAMEDCOLLECTION_HXX +#define _NAMEDCOLLECTION_HXX + +#include <collection.hxx> +#include <cppuhelper/implbase1.hxx> +#include <com/sun/star/container/XNameAccess.hpp> + +#include <algorithm> + +template<class T> +class NamedCollection : public cppu::ImplInheritanceHelper1< + Collection<T>, + com::sun::star::container::XNameAccess> +{ + using Collection<T>::maItems; + using Collection<T>::getItem; + using Collection<T>::hasItem; + +public: + NamedCollection() {} + virtual ~NamedCollection() {} + + const T& getItem( const rtl::OUString& rName ) const + { + OSL_ENSURE( hasItem( rName ), "invalid name" ); + return *findItem( rName ); + } + + bool hasItem( const rtl::OUString& rName ) const + { + return findItem( rName ) != maItems.end(); + } + + typedef com::sun::star::uno::Sequence<rtl::OUString> Names_t; + Names_t getNames() const + { + // iterate over members, and collect all those that have names + std::vector<rtl::OUString> aNames; + for( typename std::vector<T>::const_iterator aIter = maItems.begin(); + aIter != maItems.end(); + aIter++ ) + { + com::sun::star::uno::Reference<com::sun::star::container::XNamed> + xNamed( *aIter, com::sun::star::uno::UNO_QUERY ); + if( xNamed.is() ) + aNames.push_back( xNamed->getName() ); + } + + // copy names to Sequence and return + Names_t aResult( aNames.size() ); + rtl::OUString* pStrings = aResult.getArray(); + std::copy( aNames.begin(), aNames.end(), pStrings ); + + return aResult; + } + +protected: + typename std::vector<T>::const_iterator findItem( const rtl::OUString& rName ) const + { + for( typename std::vector<T>::const_iterator aIter = maItems.begin(); + aIter != maItems.end(); + aIter++ ) + { + com::sun::star::uno::Reference<com::sun::star::container::XNamed> + xNamed( *aIter, com::sun::star::uno::UNO_QUERY ); + if( xNamed.is() && xNamed->getName() == rName ) + return aIter; + } + return maItems.end(); + } + +public: + + // XElementAccess + virtual typename Collection<T>::Type_t SAL_CALL getElementType() + throw( typename Collection<T>::RuntimeException_t ) + { + return Collection<T>::getElementType(); + } + + virtual sal_Bool SAL_CALL hasElements() + throw( typename Collection<T>::RuntimeException_t ) + { + return Collection<T>::hasElements(); + } + + // XNameAccess : XElementAccess + virtual typename Collection<T>::Any_t SAL_CALL getByName( + const rtl::OUString& aName ) + throw( typename Collection<T>::NoSuchElementException_t, + typename Collection<T>::WrappedTargetException_t, + typename Collection<T>::RuntimeException_t ) + { + if( hasItem( aName ) ) + return com::sun::star::uno::makeAny( getItem( aName ) ); + else + throw typename Collection<T>::NoSuchElementException_t(); + + } + + virtual Names_t SAL_CALL getElementNames() + throw( typename Collection<T>::RuntimeException_t ) + { + return getNames(); + } + + virtual sal_Bool SAL_CALL hasByName( + const rtl::OUString& aName ) + throw( typename Collection<T>::RuntimeException_t ) + { + return hasItem( aName ) ? sal_True : sal_False; + } +}; + +#endif diff --git a/forms/source/xforms/pathexpression.cxx b/forms/source/xforms/pathexpression.cxx new file mode 100644 index 000000000000..ef82e87c4d18 --- /dev/null +++ b/forms/source/xforms/pathexpression.cxx @@ -0,0 +1,154 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include "pathexpression.hxx" +#include "unohelper.hxx" +#include "evaluationcontext.hxx" +#include "NameContainer.hxx" + +#include <com/sun/star/xml/dom/XNode.hpp> +#include <com/sun/star/xml/dom/XNodeList.hpp> +#include <com/sun/star/xml/dom/NodeType.hpp> +#include <com/sun/star/xml/dom/events/XEventListener.hpp> +#include <com/sun/star/xml/dom/events/XEventTarget.hpp> +#include <com/sun/star/xml/xpath/XXPathObject.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <rtl/ustrbuf.hxx> + +#include <unotools/textsearch.hxx> + +#include <algorithm> +#include <functional> + + +using rtl::OUString; +using rtl::OUStringBuffer; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::xml::dom::XNode; +using com::sun::star::xml::dom::XNodeList; +using com::sun::star::xml::dom::events::XEventListener; +using com::sun::star::xml::dom::events::XEventTarget; +using com::sun::star::container::XNameContainer; +using com::sun::star::xml::xpath::XXPathObject; +using com::sun::star::uno::RuntimeException; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::UNO_QUERY_THROW; +using com::sun::star::xml::dom::NodeType_TEXT_NODE; +using com::sun::star::xml::xpath::XPathObjectType_XPATH_UNDEFINED; +using namespace std; + + + + +namespace xforms +{ + +PathExpression::PathExpression() + : ComputedExpression(), + maNodes() +{ +} + +PathExpression::~PathExpression() +{ +} + + + +void PathExpression::setExpression( const OUString& rExpression ) +{ + // set new expression, and clear pre-computed results + ComputedExpression::setExpression( rExpression ); + + // check expression against regular expression to determine + // whether it contains only 'simple' (i.e. static) conditions. For + // now, we check whether it only contains number positions. + // (TODO: Only works for names containing only ASCII letters+digits.) + mbIsSimple = + _checkExpression( "( */@?[a-zA-Z0-9:]+( *\\[ *[0-9 ]+ *\\] *)?)+" ); + + maNodes.clear(); +} + +const rtl::OUString PathExpression::_getExpressionForEvaluation() const +{ + OUString sExpr = ComputedExpression::_getExpressionForEvaluation(); + if( sExpr.getLength() == 0 ) + sExpr = OUSTRING("."); + return sExpr; +} + +bool PathExpression::evaluate( const EvaluationContext& rContext ) +{ + // for simple expression we don't need to re-bind (if we were bound before) + // (we will evaluate empty expressions, since they are interpreted as ".") + if( mxResult.is() && isSimpleExpression() ) + return true; + + bool bResult = _evaluate( rContext, _getExpressionForEvaluation() ); + + // clear old result, and copy new + maNodes.clear(); + if( mxResult.is() ) + { + // copy node list + Reference<XNodeList> xNodeList = mxResult->getNodeList(); + OSL_ENSURE( xNodeList.is(), "empty object (instead of empty list)" ); + sal_Int32 nLength = xNodeList.is() ? xNodeList->getLength() : 0; + for( sal_Int32 n = 0; n < nLength; n++ ) + maNodes.push_back( xNodeList->item( n ) ); + } + + return bResult; +} + + +Reference<XNode> PathExpression::getNode() const +{ + Reference<XNode> xResult; + if( ! maNodes.empty() ) + xResult = *maNodes.begin(); + return xResult; +} + +const PathExpression::NodeVector_t PathExpression::getNodeList() const +{ + return maNodes; +} + +Reference<XNodeList> PathExpression::getXNodeList() const +{ + return mxResult.is() ? mxResult->getNodeList() : Reference<XNodeList>(); +} + + +} // namespace xforms diff --git a/forms/source/xforms/pathexpression.hxx b/forms/source/xforms/pathexpression.hxx new file mode 100644 index 000000000000..00f11b56d435 --- /dev/null +++ b/forms/source/xforms/pathexpression.hxx @@ -0,0 +1,91 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _PATHEXPRESSION_HXX +#define _PATHEXPRESSION_HXX + + +// include for parent class +#include "computedexpression.hxx" + +// includes for member variables +#include <vector> + +// forward declaractions +namespace com { namespace sun { namespace star +{ + namespace xml { namespace dom + { + class XNodeList; + namespace events { class XEventListener; } + } } +} } } + + + +namespace xforms +{ + +/** PathExpression represents an XPath Expression and caches results */ +class PathExpression : public ComputedExpression +{ +public: + typedef std::vector<com::sun::star::uno::Reference<com::sun::star::xml::dom::XNode> > NodeVector_t; + +private: + /// the node-list result from the last bind (cached from mxResult) + NodeVector_t maNodes; + +protected: + /// get expression for evaluation + const rtl::OUString _getExpressionForEvaluation() const; + + +public: + PathExpression(); + ~PathExpression(); + + /// set the expression string + /// (overridden to do remove old listeners) + /// (also defines simple expressions) + void setExpression( const rtl::OUString& rExpression ); + + + /// evaluate the expression relative to the content node. + bool evaluate( const xforms::EvaluationContext& rContext ); + + + // get the result of this expression as node/node list/... + com::sun::star::uno::Reference<com::sun::star::xml::dom::XNode> getNode() const; + const NodeVector_t getNodeList() const; + com::sun::star::uno::Reference<com::sun::star::xml::dom::XNodeList> getXNodeList() const; + +}; + +} // namespace xforms + +#endif diff --git a/forms/source/xforms/propertysetbase.cxx b/forms/source/xforms/propertysetbase.cxx new file mode 100644 index 000000000000..131b2aa447b0 --- /dev/null +++ b/forms/source/xforms/propertysetbase.cxx @@ -0,0 +1,192 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include "propertysetbase.hxx" + +#include <cppuhelper/typeprovider.hxx> // for getImplementationId() + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <tools/debug.hxx> + +#include <vector> + +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Exception; +using com::sun::star::uno::RuntimeException; +using com::sun::star::lang::IllegalArgumentException; +using com::sun::star::beans::Property; +using com::sun::star::beans::XPropertySetInfo; + +oslInterlockedCount SAL_CALL PropertyAccessorBase::acquire() +{ + return ++m_refCount; +} + +oslInterlockedCount SAL_CALL PropertyAccessorBase::release() +{ + if ( --m_refCount == 0 ) + { + delete this; + return 0; + } + return m_refCount; +} + +PropertySetBase::PropertySetBase( ) + :m_pProperties( NULL ) +{ +} + +PropertySetBase::~PropertySetBase( ) +{ + DELETEZ( m_pProperties ); +} + +cppu::IPropertyArrayHelper& SAL_CALL PropertySetBase::getInfoHelper() +{ + if ( !m_pProperties ) + { + DBG_ASSERT( !m_aProperties.empty(), "PropertySetBase::getInfoHelper: no registered properties!" ); + m_pProperties = new cppu::OPropertyArrayHelper( &m_aProperties[0], m_aProperties.size(), sal_False ); + } + return *m_pProperties; +} + +Reference< XPropertySetInfo > SAL_CALL PropertySetBase::getPropertySetInfo( ) throw(RuntimeException) +{ + return cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() ); +} + +void PropertySetBase::registerProperty( const Property& rProperty, + const ::rtl::Reference< PropertyAccessorBase >& rAccessor ) +{ + DBG_ASSERT( rAccessor.get(), "PropertySetBase::registerProperty: invalid property accessor, this will crash!" ); + m_aAccessors.insert( PropertyAccessors::value_type( rProperty.Handle, rAccessor ) ); + + DBG_ASSERT( ( rAccessor->isWriteable() == true ) + == ( ( rProperty.Attributes & com::sun::star::beans::PropertyAttribute::READONLY ) == 0 ), + "PropertySetBase::registerProperty: inconsistence!" ); + + m_aProperties.push_back( rProperty ); +} + +void PropertySetBase::notifyAndCachePropertyValue( sal_Int32 nHandle ) +{ + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + + PropertyValueCache::iterator aPos = m_aCache.find( nHandle ); + if ( aPos == m_aCache.end() ) + { // method has never before been invoked for this property + try + { + // determine the type of this property + ::cppu::IPropertyArrayHelper& rPropertyMetaData = getInfoHelper(); + ::rtl::OUString sPropName; + OSL_VERIFY( rPropertyMetaData.fillPropertyMembersByHandle( &sPropName, NULL, nHandle ) ); + Property aProperty = rPropertyMetaData.getPropertyByName( sPropName ); + // default construct a value of this type + Any aEmptyValue( NULL, aProperty.Type ); + // insert into the cache + aPos = m_aCache.insert( PropertyValueCache::value_type( nHandle, aEmptyValue ) ).first; + } + catch( Exception& ) + { + DBG_ERROR( "PropertySetBase::notifyAndCachePropertyValue: this is not expected to fail!" ); + } + } + Any aOldValue = aPos->second; + // determine the current value + Any aNewValue; + getFastPropertyValue( aNewValue, nHandle ); + // remember the old value + aPos->second = aNewValue; + + aGuard.clear(); + if ( aNewValue != aOldValue ) + firePropertyChange( nHandle, aNewValue, aOldValue ); +} + +void PropertySetBase::initializePropertyValueCache( sal_Int32 nHandle ) +{ + Any aCurrentValue; + getFastPropertyValue( aCurrentValue, nHandle ); + +#if OSL_DEBUG_LEVEL > 0 + ::std::pair< PropertyValueCache::iterator, bool > aInsertResult = +#endif + m_aCache.insert( PropertyValueCache::value_type( nHandle, aCurrentValue ) ); + DBG_ASSERT( aInsertResult.second, "PropertySetBase::initializePropertyValueCache: already cached a value for this property!" ); +} + +PropertyAccessorBase& PropertySetBase::locatePropertyHandler( sal_Int32 nHandle ) const +{ + PropertyAccessors::const_iterator aPropertyPos = m_aAccessors.find( nHandle ); + DBG_ASSERT( aPropertyPos != m_aAccessors.end() && aPropertyPos->second.get(), + "PropertySetBase::locatePropertyHandler: accessor map is corrupted!" ); + // neither should this be called for handles where there is no accessor, nor should a + // NULL accssor be in the map + return *aPropertyPos->second; +} + +sal_Bool SAL_CALL PropertySetBase::convertFastPropertyValue( Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, + const Any& rValue ) + throw (IllegalArgumentException) +{ + PropertyAccessorBase& rAccessor = locatePropertyHandler( nHandle ); + if ( !rAccessor.approveValue( rValue ) ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 0 ); + + rAccessor.getValue( rOldValue ); + if ( rOldValue != rValue ) + { + rConvertedValue = rValue; // no conversion at all + return sal_True; + } + return sal_False; +} + +void SAL_CALL PropertySetBase::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) + throw (Exception) +{ + PropertyAccessorBase& rAccessor = locatePropertyHandler( nHandle ); + rAccessor.setValue( rValue ); +} + +void SAL_CALL PropertySetBase::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const +{ + PropertyAccessorBase& rAccessor = locatePropertyHandler( nHandle ); + rAccessor.getValue( rValue ); +} diff --git a/forms/source/xforms/propertysetbase.hxx b/forms/source/xforms/propertysetbase.hxx new file mode 100644 index 000000000000..9e11efe1ebb7 --- /dev/null +++ b/forms/source/xforms/propertysetbase.hxx @@ -0,0 +1,371 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _PROPERTYSETBASE_HXX +#define _PROPERTYSETBASE_HXX + + +// include for parent class +#include <cppuhelper/weak.hxx> +#include <com/sun/star/lang/XTypeProvider.hpp> +#include <comphelper/propstate.hxx> +#include <comphelper/propertysetinfo.hxx> +#include <comphelper/proparrhlp.hxx> +#include <rtl/ref.hxx> + +// include for inlined helper function below +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> + +#include <map> + +// forward declarations for method arguments +namespace com { namespace sun { namespace star { namespace uno { + class Any; + class Type; + class RuntimeException; + template<class T> class Sequence; +} } } } + +/** base class which encapsulates accessing (reading/writing) concrete property values +*/ +class PropertyAccessorBase : public ::rtl::IReference +{ +private: + oslInterlockedCount m_refCount; + +protected: + PropertyAccessorBase() : m_refCount( 0 ) { } + +public: + virtual oslInterlockedCount SAL_CALL acquire(); + virtual oslInterlockedCount SAL_CALL release(); + + virtual bool approveValue( const com::sun::star::uno::Any& rValue ) const = 0; + virtual void setValue( const com::sun::star::uno::Any& rValue ) = 0; + virtual void getValue( com::sun::star::uno::Any& rValue ) const = 0; + virtual bool isWriteable() const = 0; +}; + + +/** helper class for implementing property accessors through public member functions +*/ +template< typename CLASS, typename VALUE, class WRITER, class READER > +class GenericPropertyAccessor : public PropertyAccessorBase +{ +public: + typedef WRITER Writer; + typedef READER Reader; + +private: + CLASS* m_pInstance; + Writer m_pWriter; + Reader m_pReader; + +public: + GenericPropertyAccessor( CLASS* pInstance, Writer pWriter, Reader pReader ) + :m_pInstance( pInstance ) + ,m_pWriter( pWriter ) + ,m_pReader( pReader ) + { + } + + virtual bool approveValue( const com::sun::star::uno::Any& rValue ) const + { + VALUE aVal; + return ( rValue >>= aVal ); + } + + virtual void setValue( const com::sun::star::uno::Any& rValue ) + { + VALUE aTypedVal = VALUE(); + OSL_VERIFY( rValue >>= aTypedVal ); + (m_pInstance->*m_pWriter)( aTypedVal ); + } + + virtual void getValue( com::sun::star::uno::Any& rValue ) const + { + rValue = com::sun::star::uno::makeAny( (m_pInstance->*m_pReader)() ); + } + + virtual bool isWriteable() const + { + return m_pWriter != NULL; + } +}; + +/** helper class for implementing property accessors via non-UNO methods +*/ +template< typename CLASS, typename VALUE > +class DirectPropertyAccessor + :public GenericPropertyAccessor < CLASS + , VALUE + , void (CLASS::*)( const VALUE& ) + , VALUE (CLASS::*)() const + > +{ +protected: + typedef void (CLASS::*Writer)( const VALUE& ); + typedef VALUE (CLASS::*Reader)() const; +public: + DirectPropertyAccessor( CLASS* pInstance, Writer pWriter, Reader pReader ) + :GenericPropertyAccessor< CLASS, VALUE, Writer, Reader >( pInstance, pWriter, pReader ) + { + } +}; + +/** helper class for implementing non-UNO accessors to a boolean property +*/ +template< typename CLASS, typename DUMMY > +class BooleanPropertyAccessor + :public GenericPropertyAccessor < CLASS + , bool + , void (CLASS::*)( bool ) + , bool (CLASS::*)() const + > +{ +protected: + typedef void (CLASS::*Writer)( bool ); + typedef bool (CLASS::*Reader)() const; +public: + BooleanPropertyAccessor( CLASS* pInstance, Writer pWriter, Reader pReader ) + :GenericPropertyAccessor< CLASS, bool, Writer, Reader >( pInstance, pWriter, pReader ) + { + } +}; + +/** helper class for implementing property accessors via UNO methods +*/ +template< typename CLASS, typename VALUE > +class APIPropertyAccessor + :public GenericPropertyAccessor < CLASS + , VALUE + , void (SAL_CALL CLASS::*)( const VALUE& ) + , VALUE (SAL_CALL CLASS::*)() + > +{ +protected: + typedef void (SAL_CALL CLASS::*Writer)( const VALUE& ); + typedef VALUE (SAL_CALL CLASS::*Reader)(); +public: + APIPropertyAccessor( CLASS* pInstance, Writer pWriter, Reader pReader ) + :GenericPropertyAccessor< CLASS, VALUE, Writer, Reader >( pInstance, pWriter, pReader ) + { + } +}; + +/** bridges two XPropertySet helper implementations + + The <type scope="comphelper">OStatefulPropertySet</type> (basically, the + <type scope="cppu">OPropertySetHelper</type>) implements a comprehensive framework + for property sets, including property change notifications. + However, it lacks some easy possibilities to declare the supported properties. + Other helper structs and classes allow for this, but are lacking needed features + such as property change notifications. + + The <type>PropertySetBase</type> bridges various implementations, + so you have the best of both worlds. + */ +class PropertySetBase : public ::comphelper::OStatefulPropertySet +{ +private: + typedef com::sun::star::uno::Any Any_t; + + typedef ::std::map< const sal_Int32, ::rtl::Reference< PropertyAccessorBase > > PropertyAccessors; + typedef ::std::vector< ::com::sun::star::beans::Property > PropertyArray; + typedef ::std::map< const sal_Int32, Any_t > PropertyValueCache; + + PropertyArray m_aProperties; + cppu::IPropertyArrayHelper* m_pProperties; + PropertyAccessors m_aAccessors; + PropertyValueCache m_aCache; + +protected: + PropertySetBase(); + virtual ~PropertySetBase(); + + /** registers a new property to be supported by this instance + @param rProperty + the descriptor for the to-be-supported property + @param rAccessor + an instance which is able to provide read and possibly write access to + the property. + @precond + Must not be called after any of the property set related UNO interfaces + has been used. Usually, you will do a number of <member>registerProperty</member> + calls in the constructor of your class. + */ + void registerProperty( + const com::sun::star::beans::Property& rProperty, + const ::rtl::Reference< PropertyAccessorBase >& rAccessor + ); + + /** notifies a change in a given property value, if necessary + + The necessity of the notification is determined by a cached value for the given + property. Caching happens after notification. + + That is, when you call <member>notifyAndCachePropertyValue</member> for the first time, + a value for the given property is default constructed, and considered to be the "old value". + If this value differs from the current value, then this change is notified to all interested + listeners. Finally, the current value is remembered. + + Subsequent calls to <member>notifyAndCachePropertyValue</member> use the remembered value as + "old value", and from then on behave as the first call. + + @param nHandle + the handle of the property. Must denote a property supported by this instance, i.e. + one previously registered via <member>registerProperty</member>. + + @precond + our ref count must not be 0. The reason is that during this method's execution, + the instance might be acquired and released, which would immediately destroy + the instance if it has a ref count of 0. + + @seealso initializePropertyValueCache + */ + void notifyAndCachePropertyValue( sal_Int32 nHandle ); + + /** initializes the property value cache for the given property, with its current value + + Usually used to initialize the cache with values which are different from default + constructed values. Say you have a boolean property whose initial state + is <TRUE/>. Say you call <member>notifyAndCachePropertyValue</member> the first time: it will + default construct the "old value" for this property as <FALSE/>, and thus <b>not</b> do + any notifications if the "current value" is also <FALSE/> - which might be wrong, since + the guessing of the "old value" differed from the real initial value which was <TRUE/>. + + Too confusing? Okay, than just call this method for every property you have. + + @param nHandle + the handle of the property. Must denote a property supported by this instance, i.e. + one previously registered via <member>registerProperty</member>. + @param rValue + the value to cache + @seealso notifyAndCachePropertyValue + */ + void initializePropertyValueCache( sal_Int32 nHandle ); + + /// OPropertysetHelper methods + virtual sal_Bool SAL_CALL convertFastPropertyValue( Any_t& rConvertedValue, Any_t& rOldValue, sal_Int32 nHandle, const Any_t& rValue ) + throw (::com::sun::star::lang::IllegalArgumentException); + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any_t& rValue ) + throw (::com::sun::star::uno::Exception); + virtual void SAL_CALL getFastPropertyValue( Any_t& rValue, sal_Int32 nHandle ) const; + + virtual cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper(); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw(::com::sun::star::uno::RuntimeException); + +public: + /// helper struct for granting selective access to some notification-related methods + struct NotifierAccess { friend struct PropertyChangeNotifier; private: NotifierAccess() { } }; + /** retrieves the current property value for the given handle + @param nHandle + the handle of the property. Must denote a property supported by this instance, i.e. + one previously registered via <member>registerProperty</member>. + @see registerProperty + */ + inline void getCurrentPropertyValueByHandle( sal_Int32 nHandle, Any_t& /* [out] */ rValue, const NotifierAccess& ) const + { + getFastPropertyValue( rValue, nHandle ); + } + + /** notifies a change in a given property to all interested listeners + */ + inline void notifyPropertyChange( sal_Int32 nHandle, const Any_t& rOldValue, const Any_t& rNewValue, const NotifierAccess& ) const + { + const_cast< PropertySetBase* >( this )->firePropertyChange( nHandle, rNewValue, rOldValue ); + } + + using ::comphelper::OStatefulPropertySet::getFastPropertyValue; + +private: + /** locates a property given by handle + @param nHandle + the handle of the property. Must denote a property supported by this instance, i.e. + one previously registered via <member>registerProperty</member>. + @see registerProperty + */ + PropertyAccessorBase& locatePropertyHandler( sal_Int32 nHandle ) const; +}; + +/** a helper class for notifying property changes in a <type>PropertySetBase</type> instance. + + You can create an instance of this class on the stack of a method which is to programmatically + change the value of a property. In its constructor, the instance will acquire the current property + value, and in its destructor, it will notify the change of this property's value (if necessary). + + You do not need this class if you are modifying property values by using the X(Fast|Multi)PropertSet + methods, since those already care for property notifications. You only need it if you're changing + the internal representation of your property directly. + + Also note that usually, notifications in the UNO world should be done without a locked mutex. So + if you use this class in conjunction with a <type>MutexGuard</type>, ensure that you <b>first</b> + instantiate the <type>PropertyChangeNotifier</type>, and <b>then</b> the <type>MutexGuard</type>, + so your mutex is released before the notification happens. +*/ +struct PropertyChangeNotifier +{ +private: + const PropertySetBase& m_rPropertySet; + sal_Int32 m_nHandle; + com::sun::star::uno::Any m_aOldValue; + +public: + /** constructs a PropertyChangeNotifier + @param rPropertySet + the property set implementation whose property is going to be changed. Note + that this property set implementation must live at least as long as the + PropertyChangeNotifier instance does. + @param nHandle + the handle of the property which is going to be changed. Must be a valid property + handle for the given <arg>rPropertySet</arg> + */ + inline PropertyChangeNotifier( const PropertySetBase& rPropertySet, sal_Int32 nHandle ) + :m_rPropertySet( rPropertySet ) + ,m_nHandle( nHandle ) + { + m_rPropertySet.getCurrentPropertyValueByHandle( m_nHandle, m_aOldValue, PropertySetBase::NotifierAccess() ); + } + inline ~PropertyChangeNotifier() + { + com::sun::star::uno::Any aNewValue; + m_rPropertySet.getCurrentPropertyValueByHandle( m_nHandle, aNewValue, PropertySetBase::NotifierAccess() ); + if ( aNewValue != m_aOldValue ) + { + m_rPropertySet.notifyPropertyChange( m_nHandle, m_aOldValue, aNewValue, PropertySetBase::NotifierAccess() ); + } + } +}; + + +#define PROPERTY_FLAGS( NAME, TYPE, FLAG ) com::sun::star::beans::Property( \ + ::rtl::OUString( #NAME, sizeof( #NAME ) - 1, RTL_TEXTENCODING_ASCII_US ), \ + HANDLE_##NAME, getCppuType( static_cast< TYPE* >( NULL ) ), FLAG ) +#define PROPERTY( NAME, TYPE ) PROPERTY_FLAGS( NAME, TYPE, com::sun::star::beans::PropertyAttribute::BOUND ) +#define PROPERTY_RO( NAME, TYPE ) PROPERTY_FLAGS( NAME, TYPE, com::sun::star::beans::PropertyAttribute::BOUND | com::sun::star::beans::PropertyAttribute::READONLY ) + +#endif diff --git a/forms/source/xforms/resourcehelper.cxx b/forms/source/xforms/resourcehelper.cxx new file mode 100644 index 000000000000..138c64851dce --- /dev/null +++ b/forms/source/xforms/resourcehelper.cxx @@ -0,0 +1,79 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include "resourcehelper.hxx" +#include "frm_resource.hxx" + +#include <rtl/ustring.hxx> +#include <tools/string.hxx> + +using rtl::OUString; + +#define OUSTRING(x) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(x)) + +namespace xforms +{ + +OUString getResource( sal_uInt16 nResourceId ) +{ + return getResource( nResourceId, OUString(), OUString(), OUString() ); +} + +OUString getResource( sal_uInt16 nResourceId, + const OUString& rInfo1 ) +{ + return getResource( nResourceId, rInfo1, OUString(), OUString() ); +} + +OUString getResource( sal_uInt16 nResourceId, + const OUString& rInfo1, + const OUString& rInfo2 ) +{ + return getResource( nResourceId, rInfo1, rInfo2, OUString() ); +} + +OUString getResource( sal_uInt16 nResourceId, + const OUString& rInfo1, + const OUString& rInfo2, + const OUString& rInfo3 ) +{ + OUString sResource = frm::ResourceManager::loadString( nResourceId ); + OSL_ENSURE( sResource.getLength() > 0, "resource not found?" ); + + // use old style String class for search and replace, so we don't have to + // code this again. + String sString( sResource ); + sString.SearchAndReplaceAll( String(OUSTRING("$1")), String(rInfo1) ); + sString.SearchAndReplaceAll( String(OUSTRING("$2")), String(rInfo2) ); + sString.SearchAndReplaceAll( String(OUSTRING("$3")), String(rInfo3) ); + return OUString( sString ); +} + +} // namespace xforms diff --git a/forms/source/xforms/resourcehelper.hxx b/forms/source/xforms/resourcehelper.hxx new file mode 100644 index 000000000000..a312c5749c50 --- /dev/null +++ b/forms/source/xforms/resourcehelper.hxx @@ -0,0 +1,52 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _RESOURCEHELPER_HXX +#define _RESOURCEHELPER_HXX + +// include resource IDs +#include <frm_resource.hrc> + +#include <sal/types.h> + +namespace rtl { class OUString; } + +namespace xforms +{ + /// get a resource string for the current language + rtl::OUString getResource( sal_uInt16 ); + + // overloaded: get a resource string, and substitute parameters + rtl::OUString getResource( sal_uInt16, const rtl::OUString& ); + rtl::OUString getResource( sal_uInt16, const rtl::OUString&, + const rtl::OUString& ); + rtl::OUString getResource( sal_uInt16, const rtl::OUString&, + const rtl::OUString&, + const rtl::OUString& ); + +} // namespace + +#endif diff --git a/forms/source/xforms/submission.cxx b/forms/source/xforms/submission.cxx new file mode 100644 index 000000000000..b61ad498933e --- /dev/null +++ b/forms/source/xforms/submission.cxx @@ -0,0 +1,719 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" +#include "submission.hxx" + +#include "model.hxx" +#include "binding.hxx" +#include "mip.hxx" +#include "evaluationcontext.hxx" +#include "unohelper.hxx" +#include "submission/submission_put.hxx" +#include "submission/submission_post.hxx" +#include "submission/submission_get.hxx" + +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> + +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/xforms/XModel.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/xml/xpath/XXPathObject.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/xml/xpath/XPathObjectType.hpp> +#include <com/sun/star/xml/dom/XNodeList.hpp> +#include <com/sun/star/xml/dom/XDocument.hpp> +#include <com/sun/star/xml/dom/XDocumentBuilder.hpp> +#include <com/sun/star/xml/dom/XDocumentFragment.hpp> +#include <com/sun/star/xml/dom/NodeType.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/task/XInteractionRequest.hpp> +#include <com/sun/star/task/XInteractionContinuation.hpp> +#include <com/sun/star/xforms/InvalidDataOnSubmitException.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <cppuhelper/typeprovider.hxx> +#include <comphelper/propertysetinfo.hxx> +#include <comphelper/interaction.hxx> +#include <unotools/processfactory.hxx> +#include <memory> + + + + +using rtl::OUString; +using rtl::OUStringBuffer; +using com::sun::star::beans::UnknownPropertyException; +using com::sun::star::beans::PropertyVetoException; +using com::sun::star::lang::IllegalArgumentException; +using com::sun::star::util::VetoException; +using com::sun::star::form::submission::XSubmissionVetoListener; +using com::sun::star::lang::WrappedTargetException; +using com::sun::star::lang::NoSupportException; +using com::sun::star::task::XInteractionHandler; +using com::sun::star::task::XInteractionRequest; +using com::sun::star::task::XInteractionContinuation; +using com::sun::star::xforms::XModel; +using com::sun::star::xforms::InvalidDataOnSubmitException; +using com::sun::star::container::XNameAccess; +using com::sun::star::xml::xpath::XXPathObject; +using com::sun::star::xml::xpath::XPathObjectType; +using com::sun::star::frame::XFrame; +using xforms::Submission; +using xforms::Model; +using xforms::MIP; +using std::auto_ptr; + +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::xml::dom; + +Submission::Submission() : + msID(), + msBind(), + maRef(), + msAction(), + msMethod(), + msVersion(), + mbIndent(), + msMediaType(), + msEncoding(), + mbOmitXmlDeclaration(), + mbStandalone(), + msCDataSectionElement(), + msReplace( OUSTRING("none") ), + msSeparator(), + msIncludeNamespacePrefixes(), + m_aFactory(utl::getProcessServiceFactory()) +{ + initializePropertySet(); +} + +Submission::~Submission() throw() +{ +} + +Reference<XModel> Submission::getModel() const +{ + return mxModel; +} + +void Submission::setModel( const Reference<XModel>& xModel ) +{ + mxModel = xModel; +} + +OUString Submission::getID() const +{ + return msID; +} + +void Submission::setID( const OUString& sID ) +{ + msID = sID; +} + +OUString Submission::getBind() const +{ + return msBind; +} + +void Submission::setBind( const OUString& sBind ) +{ + msBind = sBind; +} + +OUString Submission::getRef() const +{ + return maRef.getExpression(); +} + +void Submission::setRef( const OUString& sRef ) +{ + maRef.setExpression( sRef ); +} + +OUString Submission::getAction() const +{ + return msAction; +} + +void Submission::setAction( const OUString& sAction ) +{ + msAction = sAction; +} + +OUString Submission::getMethod() const +{ + return msMethod; +} + +void Submission::setMethod( const OUString& sMethod ) +{ + msMethod = sMethod; +} + +OUString Submission::getVersion() const +{ + return msVersion; +} + +void Submission::setVersion( const OUString& sVersion ) +{ + msVersion = sVersion; +} + +bool Submission::getIndent() const +{ + return mbIndent; +} + +void Submission::setIndent( bool bIndent ) +{ + mbIndent = bIndent; +} + +OUString Submission::getMediaType() const +{ + return msMediaType; +} + +void Submission::setMediaType( const OUString& sMediaType ) +{ + msMediaType = sMediaType; +} + +OUString Submission::getEncoding() const +{ + return msEncoding; +} + +void Submission::setEncoding( const OUString& sEncoding ) +{ + msEncoding = sEncoding; +} + +bool Submission::getOmitXmlDeclaration() const +{ + return mbOmitXmlDeclaration; +} + +void Submission::setOmitXmlDeclaration( bool bOmitXmlDeclaration ) +{ + mbOmitXmlDeclaration = bOmitXmlDeclaration; +} + +bool Submission::getStandalone() const +{ + return mbStandalone; +} + +void Submission::setStandalone( bool bStandalone ) +{ + mbStandalone = bStandalone; +} + +OUString Submission::getCDataSectionElement() const +{ + return msCDataSectionElement; +} + +void Submission::setCDataSectionElement( const OUString& sCDataSectionElement ) +{ + msCDataSectionElement = sCDataSectionElement; +} + +OUString Submission::getReplace() const +{ + return msReplace; +} + +void Submission::setReplace( const OUString& sReplace ) +{ + msReplace = sReplace; +} + +OUString Submission::getSeparator() const +{ + return msSeparator; +} + +void Submission::setSeparator( const OUString& sSeparator ) +{ + msSeparator = sSeparator; +} + +Sequence< OUString > Submission::getIncludeNamespacePrefixes() const +{ + return msIncludeNamespacePrefixes; +} + +void Submission::setIncludeNamespacePrefixes( const Sequence< OUString >& rIncludeNamespacePrefixes ) +{ + msIncludeNamespacePrefixes = rIncludeNamespacePrefixes; +} + +bool Submission::doSubmit( const Reference< XInteractionHandler >& xHandler ) +{ + liveCheck(); + + // construct XXPathObject for submission doc; use bind in preference of ref + EvaluationContext aEvalContext; + ComputedExpression aExpression; + if( msBind.getLength() != 0 ) + { + Binding* pBinding = Binding::getBinding( mxModel->getBinding(msBind) ); + if( pBinding != NULL ) + { + aExpression.setExpression( pBinding->getBindingExpression() ); + aEvalContext = pBinding->getEvaluationContext(); + } + // TODO: else: illegal binding name -> raise error + } + else if( maRef.getExpression().getLength() != 0 ) + { + aExpression.setExpression( maRef.getExpression() ); + aEvalContext = Model::getModel( mxModel )->getEvaluationContext(); + } + else + { + aExpression.setExpression( OUSTRING( "/" ) ); + aEvalContext = Model::getModel( mxModel )->getEvaluationContext(); + } + aExpression.evaluate( aEvalContext ); + Reference<XXPathObject> xResult = aExpression.getXPath(); + OSL_ENSURE( xResult.is(), "no result?" ); + + // early out if we have not obtained any result + if( ! xResult.is() ) + return false; + + + // Reference< XNodeList > aList = xResult->getNodeList(); + OUString aMethod = getMethod(); + + // strip whitespace-only text node for get submission + Reference< XDocumentFragment > aFragment = createSubmissionDocument( + xResult, aMethod.equalsIgnoreAsciiCaseAscii("get")); + + // submit result; set encoding, etc. + auto_ptr<CSubmission> xSubmission; + if (aMethod.equalsIgnoreAsciiCaseAscii("PUT")) + xSubmission = auto_ptr<CSubmission>( + new CSubmissionPut( getAction(), aFragment)); + else if (aMethod.equalsIgnoreAsciiCaseAscii("post")) + xSubmission = auto_ptr<CSubmission>( + new CSubmissionPost( getAction(), aFragment)); + else if (aMethod.equalsIgnoreAsciiCaseAscii("get")) + xSubmission = auto_ptr<CSubmission>( + new CSubmissionGet( getAction(), aFragment)); + else + { + OSL_ENSURE(sal_False, "Unsupported xforms submission method"); + return false; + } + + xSubmission->setEncoding(getEncoding()); + CSubmission::SubmissionResult aResult = xSubmission->submit( xHandler ); + + if (aResult == CSubmission::SUCCESS) + { + Reference< XDocument > aInstanceDoc = getInstanceDocument(xResult); + aResult = xSubmission->replace(getReplace(), aInstanceDoc, Reference< XFrame >()); + } + + return ( aResult == CSubmission::SUCCESS ); +} + +Sequence<sal_Int8> Submission::getUnoTunnelID() +{ + static cppu::OImplementationId aImplementationId; + return aImplementationId.getImplementationId(); +} + +Submission* Submission::getSubmission( + const Reference<XPropertySet>& xPropertySet ) +{ + Reference<XUnoTunnel> xTunnel( xPropertySet, UNO_QUERY ); + return xTunnel.is() + ? reinterpret_cast<Submission*>( + xTunnel->getSomething( getUnoTunnelID() ) ) + : NULL; +} + + + + + + +void Submission::liveCheck() + throw( RuntimeException ) +{ + bool bValid = mxModel.is(); + + if( ! bValid ) + throw RuntimeException(); +} + +Model* Submission::getModelImpl() const +{ + Model* pModel = NULL; + if( mxModel.is() ) + pModel = Model::getModel( mxModel ); + return pModel; +} + + +// +// Property-Set implementation +// + +#define HANDLE_ID 0 +#define HANDLE_Bind 1 +#define HANDLE_Ref 2 +#define HANDLE_Action 3 +#define HANDLE_Method 4 +#define HANDLE_Version 5 +#define HANDLE_Indent 6 +#define HANDLE_MediaType 7 +#define HANDLE_Encoding 8 +#define HANDLE_OmitXmlDeclaration 9 +#define HANDLE_Standalone 10 +#define HANDLE_CDataSectionElement 11 +#define HANDLE_Replace 12 +#define HANDLE_Separator 13 +#define HANDLE_IncludeNamespacePrefixes 14 +#define HANDLE_Model 15 + +#define REGISTER_PROPERTY( property, type ) \ + registerProperty( PROPERTY( property, type ), \ + new DirectPropertyAccessor< Submission, type >( this, &Submission::set##property, &Submission::get##property ) ); + +#define REGISTER_PROPERTY_BOOL( property ) \ + registerProperty( PROPERTY( property, bool ), \ + new BooleanPropertyAccessor< Submission, bool >( this, &Submission::set##property, &Submission::get##property ) ); + +void Submission::initializePropertySet() +{ + REGISTER_PROPERTY ( ID, OUString ); + REGISTER_PROPERTY ( Bind, OUString ); + REGISTER_PROPERTY ( Ref, OUString ); + REGISTER_PROPERTY ( Action, OUString ); + REGISTER_PROPERTY ( Method, OUString ); + REGISTER_PROPERTY ( Version, OUString ); + REGISTER_PROPERTY_BOOL( Indent ); + REGISTER_PROPERTY ( MediaType, OUString ); + REGISTER_PROPERTY ( Encoding, OUString ); + REGISTER_PROPERTY_BOOL( OmitXmlDeclaration ); + REGISTER_PROPERTY_BOOL( Standalone ); + REGISTER_PROPERTY ( CDataSectionElement, OUString ); + REGISTER_PROPERTY ( Replace, OUString ); + REGISTER_PROPERTY ( Separator, OUString ); + REGISTER_PROPERTY ( IncludeNamespacePrefixes, Sequence< OUString > ); + REGISTER_PROPERTY ( Model, Reference<XModel> ); + + initializePropertyValueCache( HANDLE_Indent ); + initializePropertyValueCache( HANDLE_OmitXmlDeclaration ); + initializePropertyValueCache( HANDLE_Standalone ); +} + +sal_Bool SAL_CALL Submission::convertFastPropertyValue( + Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue ) + throw ( IllegalArgumentException ) +{ + if ( nHandle == HANDLE_IncludeNamespacePrefixes ) + { + // for convinience reasons (????), we accept a string which contains + // a comma-separated list of namespace prefixes + ::rtl::OUString sTokenList; + if ( rValue >>= sTokenList ) + { + std::vector< OUString > aPrefixes; + sal_Int32 p = 0; + while ( p >= 0 ) + aPrefixes.push_back( sTokenList.getToken( 0, ',', p ) ); + + Sequence< ::rtl::OUString > aConvertedPrefixes( &aPrefixes[0], aPrefixes.size() ); + return PropertySetBase::convertFastPropertyValue( rConvertedValue, rOldValue, nHandle, makeAny( aConvertedPrefixes ) ); + } + } + + return PropertySetBase::convertFastPropertyValue( rConvertedValue, rOldValue, nHandle, rValue ); +} + +OUString SAL_CALL Submission::getName() + throw( RuntimeException ) +{ + return getID(); +} + +void SAL_CALL Submission::setName( const OUString& sID ) + throw( RuntimeException ) +{ + setID( sID ); +} + + + +sal_Int64 SAL_CALL Submission::getSomething( + const Sequence<sal_Int8>& aId ) + throw( RuntimeException ) +{ + return ( aId == getUnoTunnelID() ) ? reinterpret_cast<sal_Int64>(this) : 0; +} + + +OUString lcl_message( const OUString& rID, const OUString& rText ) +{ + OUStringBuffer aMessage; + aMessage.append( OUSTRING("XForms submission '") ); + aMessage.append( rID ); + aMessage.append( OUSTRING("' failed") ); + aMessage.append( rText ); + aMessage.append( OUSTRING(".") ); + return aMessage.makeStringAndClear(); +} + +void SAL_CALL Submission::submitWithInteraction( + const Reference<XInteractionHandler>& _rxHandler ) + throw ( VetoException, + WrappedTargetException, + RuntimeException ) +{ + // as long as this class is not really threadsafe, we need to copy + // the members we're interested in + Reference< XModel > xModel( mxModel ); + ::rtl::OUString sID( msID ); + + if ( !xModel.is() || !msID.getLength() ) + throw RuntimeException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "This is not a valid submission object." ) ), + *this + ); + + Model* pModel = Model::getModel( xModel ); + OSL_ENSURE( pModel != NULL, "illegal model?" ); + + // #i36765# #i47248# warning on submission of illegal data + // check for validity (and query user if invalid) + bool bValid = pModel->isValid(); + if( ! bValid ) + { + InvalidDataOnSubmitException aInvalidDataException( + lcl_message(sID, OUSTRING(" due to invalid data") ), *this ); + + if( _rxHandler.is() ) + { + // labouriously create interaction request + comphelper::OInteractionRequest* pRequest + = new comphelper::OInteractionRequest( + makeAny( aInvalidDataException ) ); + Reference<XInteractionRequest> xRequest = pRequest; + + comphelper::OInteractionApprove* pContinue + = new comphelper::OInteractionApprove(); + Reference<XInteractionContinuation> xContinue = pContinue; + pRequest->addContinuation( xContinue ); + + comphelper::OInteractionDisapprove* pCancel + = new comphelper::OInteractionDisapprove(); + Reference<XInteractionContinuation> xCancel = pCancel; + pRequest->addContinuation( xCancel ); + + // ask the handler... + _rxHandler->handle( xRequest ); + OSL_ENSURE( pContinue->wasSelected() || pCancel->wasSelected(), + "handler didn't select" ); + + // and continue, if user chose 'continue' + if( pContinue->wasSelected() ) + bValid = true; + } + + // abort if invalid (and user didn't tell us to continue) + if( ! bValid ) + throw aInvalidDataException; + } + + // attempt submission + bool bResult = false; + try + { + bResult = doSubmit( _rxHandler ); + } + catch( const VetoException& ) + { + OSL_ENSURE( sal_False, "Model::submit: Hmm. How can a single submission have a veto right?" ); + // allowed to leave + throw; + } + catch( const Exception& e ) + { + // exception caught: re-throw as wrapped target exception + throw WrappedTargetException( + lcl_message( sID, OUSTRING(" due to exception being thrown") ), + *this, makeAny( e ) ); + } + + if( bResult ) + { + mxModel->rebuild(); + } + else + { + // other failure: throw wrapped target exception, too. + throw WrappedTargetException( + lcl_message( sID, OUString() ), *this, Any() ); + } +} + +void SAL_CALL Submission::submit( ) throw ( VetoException, WrappedTargetException, RuntimeException ) +{ + submitWithInteraction( NULL ); +} + +void SAL_CALL Submission::addSubmissionVetoListener( const Reference< XSubmissionVetoListener >& /*listener*/ ) throw (NoSupportException, RuntimeException) +{ + // TODO + throw NoSupportException(); +} + +void SAL_CALL Submission::removeSubmissionVetoListener( const Reference< XSubmissionVetoListener >& /*listener*/ ) throw (NoSupportException, RuntimeException) +{ + // TODO + throw NoSupportException(); +} + +static sal_Bool _isIgnorable(const Reference< XNode >& aNode) +{ + // ignore whitespace-only textnodes + if (aNode->getNodeType() == NodeType_TEXT_NODE) + { + OUString aTrimmedValue = aNode->getNodeValue().trim(); + if (aTrimmedValue.getLength() == 0) return sal_True; + } + + return sal_False; +} + +// recursively copy relevant nodes from A to B +static void _cloneNodes(Model& aModel, const Reference< XNode >& dstParent, const Reference< XNode >& source, sal_Bool bRemoveWSNodes) +{ + if (!source.is()) return; + + Reference< XNode > cur = source; + Reference< XDocument > dstDoc = dstParent->getOwnerDocument(); + Reference< XNode > imported; + + if (cur.is()) + { + // is this node relevant? + MIP mip = aModel.queryMIP(cur); + if(mip.isRelevant() && !(bRemoveWSNodes && _isIgnorable(cur))) + { + imported = dstDoc->importNode(cur, sal_False); + imported = dstParent->appendChild(imported); + // append source children to new imported parent + for( cur = cur->getFirstChild(); cur.is(); cur = cur->getNextSibling() ) + _cloneNodes(aModel, imported, cur, bRemoveWSNodes); + } + } +} +Reference< XDocument > Submission::getInstanceDocument(const Reference< XXPathObject >& aObj) +{ + using namespace com::sun::star::xml::xpath; + // result + Reference< XDocument > aDocument; + + if (aObj->getObjectType() == XPathObjectType_XPATH_NODESET) + { + Reference< XNodeList > aList = aObj->getNodeList(); + if (aList->getLength() > 0) + aDocument = aList->item(0)->getOwnerDocument(); + } + return aDocument; +} + +Reference< XDocumentFragment > Submission::createSubmissionDocument(const Reference< XXPathObject >& aObj, sal_Bool bRemoveWSNodes) +{ + using namespace com::sun::star::xml::xpath; + Reference< XDocumentBuilder > aDocBuilder(m_aFactory->createInstance( + OUString::createFromAscii("com.sun.star.xml.dom.DocumentBuilder")), UNO_QUERY); + Reference< XDocument > aDocument = aDocBuilder->newDocument(); + Reference< XDocumentFragment > aFragment = aDocument->createDocumentFragment(); + + // + if (aObj->getObjectType() == XPathObjectType_XPATH_NODESET) + { + Reference< XNodeList > aList = aObj->getNodeList(); + Reference< XNode > aListItem; + for (sal_Int32 i=0; i < aList->getLength(); i++) + { + aListItem = aList->item(i); + if (aListItem->getNodeType()==NodeType_DOCUMENT_NODE) + aListItem = Reference< XNode >( + (Reference< XDocument >(aListItem, UNO_QUERY))->getDocumentElement(), UNO_QUERY); + // copy relevant nodes from instance into fragment + _cloneNodes(*getModelImpl(), Reference< XNode >(aFragment, UNO_QUERY), aListItem, bRemoveWSNodes); + } + } + return aFragment; +} + +// some forwarding: XPropertySet is implemented in our base class, +// but also available as base of XSubmission +Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL Submission::getPropertySetInfo( ) throw(RuntimeException) +{ + return PropertySetBase::getPropertySetInfo(); +} +void SAL_CALL Submission::setPropertyValue( const ::rtl::OUString& aPropertyName, const Any& aValue ) throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + PropertySetBase::setPropertyValue( aPropertyName, aValue ); +} +Any SAL_CALL Submission::getPropertyValue( const ::rtl::OUString& PropertyName ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + return PropertySetBase::getPropertyValue( PropertyName ); +} +void SAL_CALL Submission::addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + PropertySetBase::addPropertyChangeListener( aPropertyName, xListener ); +} +void SAL_CALL Submission::removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + PropertySetBase::removePropertyChangeListener( aPropertyName, aListener ); +} +void SAL_CALL Submission::addVetoableChangeListener( const ::rtl::OUString& PropertyName, const Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + PropertySetBase::addVetoableChangeListener( PropertyName, aListener ); +} +void SAL_CALL Submission::removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + PropertySetBase::removeVetoableChangeListener( PropertyName, aListener ); +} + diff --git a/forms/source/xforms/submission.hxx b/forms/source/xforms/submission.hxx new file mode 100644 index 000000000000..36a687a3d5e5 --- /dev/null +++ b/forms/source/xforms/submission.hxx @@ -0,0 +1,276 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _SUBMISSION_HXX +#define _SUBMISSION_HXX + + +// includes for parent classes +#include <cppuhelper/implbase2.hxx> +#include <propertysetbase.hxx> +#include <com/sun/star/util/XModifyBroadcaster.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/xml/dom/events/XEventListener.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/xml/dom/XNode.hpp> +#include <com/sun/star/xml/dom/XDocument.hpp> +#include <com/sun/star/xml/dom/XDocumentFragment.hpp> +#include <com/sun/star/xml/xpath/XXPathObject.hpp> +#include <com/sun/star/xforms/XSubmission.hpp> + +// includes for member variables +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <computedexpression.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +// forward declaractions +namespace com { namespace sun { namespace star { + namespace xforms { class XModel; } + namespace uno { class Any; } + namespace beans { class UnknownPropertyException; + class PropertyVetoException; } + namespace lang { class IllegalArgumentException; + class WrappedTargetException; } +} } } +namespace xforms { class Model; } + + +namespace xforms +{ + +/** An XForms submission. + * + * See http://www.w3.org/TR/xforms/ for more information. + */ +typedef cppu::ImplInheritanceHelper2< + PropertySetBase, + com::sun::star::lang::XUnoTunnel, + com::sun::star::xforms::XSubmission +> Submission_t; + +class Submission : public Submission_t +{ + // submission properties + rtl::OUString msID; + rtl::OUString msBind; + ComputedExpression maRef; + rtl::OUString msAction; + rtl::OUString msMethod; + rtl::OUString msVersion; + bool mbIndent; + rtl::OUString msMediaType; + rtl::OUString msEncoding; + bool mbOmitXmlDeclaration; + bool mbStandalone; + rtl::OUString msCDataSectionElement; + rtl::OUString msReplace; + rtl::OUString msSeparator; + com::sun::star::uno::Sequence< rtl::OUString > msIncludeNamespacePrefixes; + +private: + + /// the Model to which this Submission belongs; may be NULL + com::sun::star::uno::Reference<com::sun::star::xforms::XModel> mxModel; + + // this will extract the document from the model that will be submitted + com::sun::star::uno::Reference< com::sun::star::xml::dom::XDocumentFragment > + createSubmissionDocument(const com::sun::star::uno::Reference< com::sun::star::xml::xpath::XXPathObject >& aObject, + sal_Bool bRemoveWSNodes = sal_False); + com::sun::star::uno::Reference< com::sun::star::xml::dom::XDocument > + getInstanceDocument(const com::sun::star::uno::Reference< com::sun::star::xml::xpath::XXPathObject >& aObject); + + com::sun::star::uno::Reference<com::sun::star::lang::XMultiServiceFactory > m_aFactory; +public: + Submission(); + virtual ~Submission() throw(); + + // + // property methods: get/set value + // + + /// get XForms model + com::sun::star::uno::Reference<com::sun::star::xforms::XModel> + getModel() const; + + /// set XForms model + void setModel( + const com::sun::star::uno::Reference<com::sun::star::xforms::XModel>& ); + + rtl::OUString getID() const; /// get ID for this submission + void setID( const rtl::OUString& ); /// set ID for this submission + + rtl::OUString getBind() const; + void setBind( const rtl::OUString& ); + + rtl::OUString getRef() const; + void setRef( const rtl::OUString& ); + + rtl::OUString getAction() const; + void setAction( const rtl::OUString& ); + + rtl::OUString getMethod() const; + void setMethod( const rtl::OUString& ); + + rtl::OUString getVersion() const; + void setVersion( const rtl::OUString& ); + + bool getIndent() const; + void setIndent( bool ); + + rtl::OUString getMediaType() const; + void setMediaType( const rtl::OUString& ); + + rtl::OUString getEncoding() const; + void setEncoding( const rtl::OUString& ); + + bool getOmitXmlDeclaration() const; + void setOmitXmlDeclaration( bool ); + + bool getStandalone() const; + void setStandalone( bool ); + + rtl::OUString getCDataSectionElement() const; + void setCDataSectionElement( const rtl::OUString& ); + + rtl::OUString getReplace() const; + void setReplace( const rtl::OUString& ); + + rtl::OUString getSeparator() const; + void setSeparator( const rtl::OUString& ); + + com::sun::star::uno::Sequence< rtl::OUString > getIncludeNamespacePrefixes() const; + void setIncludeNamespacePrefixes( const com::sun::star::uno::Sequence< rtl::OUString >& ); + + + /** perform the submission + * @returns if submission was successful */ + bool doSubmit( const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& aHandler ); + + + /// release the model (note: Binding is unusable without model) + void releaseModel(); + + + // helpers for UNO tunnel + static com::sun::star::uno::Sequence<sal_Int8> getUnoTunnelID(); + static Submission* getSubmission( const com::sun::star::uno::Reference<com::sun::star::beans::XPropertySet>& ); + + + +private: + + /// check whether object is live, and throw suitable exception if not + /// (to be used be API methods before acting on the object) + void liveCheck() + throw( com::sun::star::uno::RuntimeException ); + + /// get the model implementation + xforms::Model* getModelImpl() const; + xforms::Model* getModelImpl( const com::sun::star::uno::Reference<com::sun::star::xforms::XModel>& xModel ) const; + + + +protected: + + // + // XPropertySet & friends: + // implement abstract methods from PropertySetHelper + // + + virtual sal_Bool SAL_CALL convertFastPropertyValue( + com::sun::star::uno::Any& rConvertedValue, + com::sun::star::uno::Any& rOldValue, + sal_Int32 nHandle, + const com::sun::star::uno::Any& rValue ) + throw ( com::sun::star::lang::IllegalArgumentException ); + +private: + void initializePropertySet(); + + +public: + + // + // XNamed: + // get/set name + // + + virtual rtl::OUString SAL_CALL getName() + throw( com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL setName( const rtl::OUString& ) + throw( com::sun::star::uno::RuntimeException ); + + + + // + // XUnoTunnel + // + + virtual sal_Int64 SAL_CALL getSomething( + const com::sun::star::uno::Sequence<sal_Int8>& ) + throw( com::sun::star::uno::RuntimeException ); + + + // + // XSubmission + // + + virtual void SAL_CALL submit( ) + throw ( com::sun::star::util::VetoException, + com::sun::star::lang::WrappedTargetException, + com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL submitWithInteraction( + const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& aHandler ) + throw ( com::sun::star::util::VetoException, + com::sun::star::lang::WrappedTargetException, + com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL addSubmissionVetoListener( + const ::com::sun::star::uno::Reference< ::com::sun::star::form::submission::XSubmissionVetoListener >& listener ) + throw (::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeSubmissionVetoListener( + const ::com::sun::star::uno::Reference< ::com::sun::star::form::submission::XSubmissionVetoListener >& listener ) + throw (::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + + // + // XPropertySet + // (need to disambiguate this) + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw(::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); +}; + + +} // namespace xforms + +#endif diff --git a/forms/source/xforms/submission/makefile.mk b/forms/source/xforms/submission/makefile.mk new file mode 100644 index 000000000000..20590cab880b --- /dev/null +++ b/forms/source/xforms/submission/makefile.mk @@ -0,0 +1,57 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=forms +TARGET=xformssubmit + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE: $(PRJ)$/makefile.pmk + +.IF "$(SYSTEM_LIBXML)" == "YES" +CFLAGS+=-DSYSTEM_LIBXML $(LIBXML_CFLAGS) +.ENDIF + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/serialization_app_xml.obj \ + $(SLO)$/serialization_urlencoded.obj \ + $(SLO)$/submission_post.obj \ + $(SLO)$/submission_put.obj \ + $(SLO)$/submission_get.obj \ + $(SLO)$/replace.obj + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/forms/source/xforms/submission/replace.cxx b/forms/source/xforms/submission/replace.cxx new file mode 100644 index 000000000000..fa8ca6f383b5 --- /dev/null +++ b/forms/source/xforms/submission/replace.cxx @@ -0,0 +1,145 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" +#include <memory> +#include "submission.hxx" +#include "serialization_app_xml.hxx" + +#include <rtl/ustring.hxx> +#include <rtl/string.hxx> + +#include <unotools/processfactory.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/xml/dom/XDocument.hpp> +#include <com/sun/star/xml/dom/XDocumentBuilder.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <ucbhelper/content.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::ucb; +using namespace com::sun::star::frame; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::task; +using namespace com::sun::star::xml::dom; + +CSubmission::SubmissionResult CSubmission::replace(const ::rtl::OUString& aReplace, const Reference<XDocument>& aDocument, const Reference<XFrame>& aFrame) +{ + if (!m_aResultStream.is()) + return CSubmission::UNKNOWN_ERROR; + + try { + Reference< XMultiServiceFactory > xFactory = utl::getProcessServiceFactory(); + if (aReplace.equalsIgnoreAsciiCaseAscii("all") || aReplace.equalsIgnoreAsciiCaseAscii("document")) { + Reference< XComponentLoader > xLoader; + if (aFrame.is()) + xLoader = Reference< XComponentLoader >(aFrame, UNO_QUERY); + + if (!xLoader.is()) + xLoader = Reference< XComponentLoader >(xFactory->createInstance( + ::rtl::OUString::createFromAscii("com.sun.star.frame.Desktop")), UNO_QUERY_THROW); + + // open the stream from the result... + // build media descriptor + Sequence< PropertyValue > descriptor(2); + descriptor[0] = PropertyValue(::rtl::OUString::createFromAscii( + "InputStream"), -1, makeAny(m_aResultStream), PropertyState_DIRECT_VALUE); + descriptor[1] = PropertyValue(::rtl::OUString::createFromAscii( + "ReadOnly"), -1, makeAny(sal_True), PropertyState_DIRECT_VALUE); + + //::rtl::OUString aURL = ::rtl::OUString::createFromAscii("private:stream"); + ::rtl::OUString aURL = m_aURLObj.GetMainURL(INetURLObject::NO_DECODE); + ::rtl::OUString aTarget = ::rtl::OUString::createFromAscii("_default"); + xLoader->loadComponentFromURL(aURL, aTarget, FrameSearchFlag::ALL, descriptor); + + return CSubmission::SUCCESS; + + } else if (aReplace.equalsIgnoreAsciiCaseAscii("instance")) { + if (aDocument.is()) { + // parse the result stream into a new document + Reference< XDocumentBuilder > xBuilder(xFactory->createInstance( + ::rtl::OUString::createFromAscii("com.sun.star.xml.dom.DocumentBuilder")), UNO_QUERY_THROW); + Reference< XDocument > aNewDocument = xBuilder->parse(m_aResultStream); + + if (aNewDocument.is()) { + // and replace the content of the current instance + Reference< XElement > oldRoot = aDocument->getDocumentElement(); + Reference< XElement > newRoot = aNewDocument->getDocumentElement(); + + // aDocument->removeChild(Reference< XNode >(oldRoot, UNO_QUERY_THROW)); + Reference< XNode > aImportedNode = aDocument->importNode(Reference< XNode >(newRoot, UNO_QUERY_THROW), sal_True); + Reference< XNode >(aDocument, UNO_QUERY_THROW)->replaceChild(aImportedNode, Reference< XNode >(oldRoot, UNO_QUERY_THROW)); + return CSubmission::SUCCESS; + } else { + return CSubmission::UNKNOWN_ERROR; + } + } else { + // nothing to replace + return CSubmission::UNKNOWN_ERROR; + } + } else if (aReplace.equalsIgnoreAsciiCaseAscii("none")) { + // do nothing \o/ + return CSubmission::SUCCESS; + } + } catch (Exception& e) { + ::rtl::OString aMsg("Exception during replace:\n"); + aMsg += OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8); + OSL_ENSURE(sal_False, aMsg.getStr()); + } + return CSubmission::UNKNOWN_ERROR; +} +::std::auto_ptr< CSerialization > CSubmission::createSerialization(const Reference< XInteractionHandler >& _xHandler,Reference<XCommandEnvironment>& _rOutEnv) +{ + // PUT always uses application/xml + ::std::auto_ptr< CSerialization > apSerialization(new CSerializationAppXML()); + apSerialization->setSource(m_aFragment); + apSerialization->serialize(); + + // create a commandEnvironment and use the default interaction handler + CCommandEnvironmentHelper *pHelper = new CCommandEnvironmentHelper; + if( _xHandler.is() ) + pHelper->m_aInteractionHandler = _xHandler; + else + pHelper->m_aInteractionHandler = CSS::uno::Reference< XInteractionHandler >(m_aFactory->createInstance( + ::rtl::OUString::createFromAscii("com.sun.star.task.InteractionHandler")), UNO_QUERY); + OSL_ENSURE(pHelper->m_aInteractionHandler.is(), "failed to create IntreractionHandler"); + + CProgressHandlerHelper *pProgressHelper = new CProgressHandlerHelper; + pHelper->m_aProgressHandler = Reference< XProgressHandler >(pProgressHelper); + + // UCB has ownership of environment... + _rOutEnv = pHelper; + return apSerialization; +} + + + diff --git a/forms/source/xforms/submission/serialization.hxx b/forms/source/xforms/submission/serialization.hxx new file mode 100644 index 000000000000..a3e369bc19b2 --- /dev/null +++ b/forms/source/xforms/submission/serialization.hxx @@ -0,0 +1,98 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef __SERIALIZATION_HXX +#define __SERIALIZATION_HXX + +#include <map> + +#include <sal/types.h> +#include <rtl/ustring.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/xml/xpath/XXPathObject.hpp> +#include <com/sun/star/xml/dom/XDocumentFragment.hpp> + +namespace CSS = com::sun::star; + +/** +Serialize an XObject +*/ + +typedef std::map<rtl::OUString, rtl::OUString> PropMap; + +class CSerialization +{ +protected: + CSS::uno::Reference< CSS::xml::dom::XDocumentFragment > m_aFragment; + PropMap m_properties; + +public: + virtual ~CSerialization() {} + + /** + sets the XObject that is to serialized + */ + virtual void setSource(const CSS::uno::Reference< CSS::xml::dom::XDocumentFragment >& aFragment) + { + m_aFragment = aFragment; + } + + /** + set the properties from the submission element + that control aspects of the serialization + eachs serialization may support individual properties + */ + void setProperties(const CSS::uno::Sequence< CSS::beans::NamedValue >& props) + { + m_properties.clear(); + rtl::OUString aValue; + for (sal_Int32 i=0; i<props.getLength(); i++) + { + if (props[i].Value >>= aValue) + m_properties.insert(PropMap::value_type(props[i].Name, aValue)); + } + } + + /** + start the serialization process + */ + virtual void serialize()=0; + + /** + get the serialized bytes. + reads up to buffer->getLength() bytes and returns the number of + bytes read. + returns -1 on error + */ + virtual CSS::uno::Reference< CSS::io::XInputStream > getInputStream() = 0; + +}; + +#endif diff --git a/forms/source/xforms/submission/serialization_app_xml.cxx b/forms/source/xforms/submission/serialization_app_xml.cxx new file mode 100644 index 000000000000..85cf066d6343 --- /dev/null +++ b/forms/source/xforms/submission/serialization_app_xml.cxx @@ -0,0 +1,121 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include "serialization.hxx" +#include "serialization_app_xml.hxx" + +#include <unotools/processfactory.hxx> +#include <com/sun/star/xml/dom/XNode.hpp> +#include <com/sun/star/xml/dom/XDocument.hpp> +#include <com/sun/star/xml/dom/XNodeList.hpp> +#include <com/sun/star/xml/dom/NodeType.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/xml/xpath/XPathObjectType.hpp> + +#include <libxml/tree.h> + +CSerializationAppXML::CSerializationAppXML() + : m_aFactory(utl::getProcessServiceFactory()) + , m_aPipe(CSS::uno::Reference< CSS::io::XOutputStream > (m_aFactory->createInstance( + rtl::OUString::createFromAscii("com.sun.star.io.Pipe")), CSS::uno::UNO_QUERY)) +{ + OSL_ENSURE(m_aPipe.is(), "cannot create Pipe"); +} + +CSS::uno::Reference< CSS::io::XInputStream > +CSerializationAppXML::getInputStream() +{ + // The pipes output is provided through it's + // XOutputStream interface aspect + return CSS::uno::Reference< CSS::io::XInputStream >(m_aPipe, CSS::uno::UNO_QUERY); +} + +void +CSerializationAppXML::serialize_node(const CSS::uno::Reference< CSS::xml::dom::XNode >& rNode) +{ + CSS::uno::Reference< CSS::xml::dom::XNode > aNode = rNode; + if (aNode->getNodeType() == CSS::xml::dom::NodeType_DOCUMENT_NODE) + { + CSS::uno::Reference< CSS::xml::dom::XDocument > aDoc(rNode, CSS::uno::UNO_QUERY_THROW); + aNode = CSS::uno::Reference< CSS::xml::dom::XNode >(aDoc->getDocumentElement(), CSS::uno::UNO_QUERY_THROW); + } + if (aNode->getNodeType() != CSS::xml::dom::NodeType_ELEMENT_NODE) + return; + + // clone the node to a new document and serialize that document + CSS::uno::Reference< CSS::lang::XUnoTunnel > aTunnel(aNode, CSS::uno::UNO_QUERY); + if (aTunnel.is()) + { + xmlNodePtr aNodePtr = reinterpret_cast< xmlNodePtr >( aTunnel->getSomething(CSS::uno::Sequence< sal_Int8 >()) ); + xmlDocPtr aDocPtr = xmlNewDoc((xmlChar*)"1.0"); + xmlNodePtr aDocNodePtr = xmlDocCopyNode(aNodePtr, aDocPtr, 1); + if (aDocNodePtr != NULL) { + xmlAddChild((xmlNodePtr)aDocPtr, aDocNodePtr); + xmlChar *buffer = NULL; + sal_Int32 size = 0; + xmlDocDumpMemory(aDocPtr, &buffer, (int*)&size); + + // write the xml into the pipe through it's XOutputStream interface + m_aPipe->writeBytes(CSS::uno::Sequence< sal_Int8 >((sal_Int8*)buffer, size)); + xmlFree(buffer); + } + + } else { + // can't get tunnel to native backend + // logic for generic implementation could be implemented here... + OSL_ENSURE(sal_False, "unkown dom implementation, cannot serialize"); + return; + } +} + +/* +void +CSerializationAppXML::serialize_nodeset() +{ + CSS::uno::Reference< CSS::xml::dom::XNodeList > aNodeList = m_aXPathObject->getNodeList(); + for (sal_Int32 i=0; i<aNodeList->getLength(); i++) + serialize_node(aNodeList->item(i)); + m_aPipe->closeOutput(); +} +*/ + +void +CSerializationAppXML::serialize() +{ + if (!m_aFragment.is()) return; + + CSS::uno::Reference< CSS::xml::dom::XNode > cur = m_aFragment->getFirstChild(); + while (cur.is()) + { + serialize_node(cur); + cur = cur->getNextSibling(); + } + m_aPipe->closeOutput(); +} diff --git a/forms/source/xforms/submission/serialization_app_xml.hxx b/forms/source/xforms/submission/serialization_app_xml.hxx new file mode 100644 index 000000000000..338df6aea083 --- /dev/null +++ b/forms/source/xforms/submission/serialization_app_xml.hxx @@ -0,0 +1,55 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef __SERIALIZATION_APP_XML_HXX +#define __SERIALIZATION_APP_XML_HXX + +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#include "serialization.hxx" + + +class CSerializationAppXML : public CSerialization +{ +private: + CSS::uno::Reference< CSS::lang::XMultiServiceFactory > m_aFactory; + CSS::uno::Reference< CSS::io::XOutputStream > m_aPipe; + + void serialize_node(const CSS::uno::Reference< CSS::xml::dom::XNode >& aNode); + void serialize_nodeset(); + +public: + CSerializationAppXML(); + + virtual void serialize(); + // virtual void setSource(const CSS::uno::Reference< CSS::xml::xpath::XXPathObject >& object); + // virtual void setProperties(const CSS::uno::Sequence< CSS::beans::NamedValue >& props); + virtual CSS::uno::Reference< CSS::io::XInputStream > getInputStream(); +}; + +#endif diff --git a/forms/source/xforms/submission/serialization_urlencoded.cxx b/forms/source/xforms/submission/serialization_urlencoded.cxx new file mode 100644 index 000000000000..307d9d90aed7 --- /dev/null +++ b/forms/source/xforms/submission/serialization_urlencoded.cxx @@ -0,0 +1,210 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include <com/sun/star/xml/xpath/XPathObjectType.hpp> +#include <com/sun/star/xml/dom/XNode.hpp> +#include <com/sun/star/xml/dom/XText.hpp> +#include <com/sun/star/xml/dom/XNodeList.hpp> +#include <com/sun/star/xml/dom/NodeType.hpp> + +#include <rtl/ustrbuf.hxx> +#include <rtl/strbuf.hxx> +#include <unotools/processfactory.hxx> + +#include <stdio.h> + +#include "serialization_urlencoded.hxx" + +using namespace utl; +using namespace CSS::uno; +using namespace CSS::io; +using namespace CSS::xml::xpath; +using namespace CSS::xml::dom; + +CSerializationURLEncoded::CSerializationURLEncoded() + : m_aFactory(getProcessServiceFactory()) + , m_aPipe(Reference< XOutputStream > (m_aFactory->createInstance( + ::rtl::OUString::createFromAscii("com.sun.star.io.Pipe")), UNO_QUERY)) +{ +} + + +/* + rfc2396 + reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | + "$" | "," + mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" + unreserved = alphanum | mark +*/ +sal_Bool CSerializationURLEncoded::is_unreserved(sal_Char c) +{ + //digit? + if (c >= '0' && c <= '9') return sal_True; + if (c >= 'A' && c <= 'Z') return sal_True; + if (c >= 'a' && c <= 'z') return sal_True; + switch (c) { + case '-': + case '_': + case '.': + case '!': + case '~': + case '*': + case '\'': + case '(': + case ')': + return sal_True; + } + return sal_False; +} +void CSerializationURLEncoded::encode_and_append(const ::rtl::OUString& aString, ::rtl::OStringBuffer& aBuffer) +{ + ::rtl::OString utf8String = OUStringToOString(aString, RTL_TEXTENCODING_UTF8); + const sal_uInt8 *pString = reinterpret_cast< const sal_uInt8 * >( utf8String.getStr() ); + sal_Char tmpChar[4]; tmpChar[3] = 0; + + while( *pString != 0) + { + if( *pString < 0x80 ) + { + if ( is_unreserved(*pString) ) { + aBuffer.append(*pString); + } else if (*pString == 0x20) { + aBuffer.append('+'); + } else if (*pString == 0x0d && *(pString+1) == 0x0a) { + aBuffer.append("%0D%0A"); + pString++; + } else if (*pString == 0x0a) { + aBuffer.append("%0D%0A"); + } else { + snprintf(tmpChar, 3, "%%%X", *pString % 0x100); + aBuffer.append(tmpChar); + } + } else { + snprintf(tmpChar, 3, "%%%X", *pString % 0x100); + aBuffer.append(tmpChar); + while (*pString >= 0x80) { + // continuation... + pString++; + snprintf(tmpChar, 3, "%%%X", *pString % 0x100); + aBuffer.append(tmpChar); + } + } + pString++; + } +} + +void CSerializationURLEncoded::serialize_node(const Reference< XNode >& aNode) +{ + // serialize recursive + // every element node E that has a text child T will be serialized in document order + // <E1>T1<E2>T2</E2></E1><E3>T3</E3> -> E1=T2&E2=T2&E3=T3 (En := local name) + + // this node + Reference< XNodeList > aChildList = aNode->getChildNodes(); + Reference< XNode > aChild; + // is this an element node? + if (aNode->getNodeType() == NodeType_ELEMENT_NODE) + { + ::rtl::OUString aName = aNode->getNodeName(); + // find any text children + ::rtl::OUStringBuffer aValue; + Reference< XText > aText; + for(sal_Int32 i=0; i < aChildList->getLength(); i++) + { + aChild = aChildList->item(i); + if (aChild->getNodeType() == NodeType_TEXT_NODE) + { + aText = Reference< XText >(aChild, UNO_QUERY); + aValue.append(aText->getData()); + } + } + + // found anything? + if (aValue.getLength() > 0) + { + ::rtl::OUString aUnencValue = aValue.makeStringAndClear(); + ::rtl::OStringBuffer aEncodedBuffer; + encode_and_append(aName, aEncodedBuffer); + aEncodedBuffer.append("="); + encode_and_append(aUnencValue, aEncodedBuffer); + aEncodedBuffer.append("&"); + sal_Int8 *pData = (sal_Int8*)aEncodedBuffer.getStr(); + Sequence< sal_Int8 > sData(pData, aEncodedBuffer.getLength()); + m_aPipe->writeBytes(sData); + } + } + + // element children... + for(sal_Int32 i=0; i < aChildList->getLength(); i++) + { + aChild = aChildList->item(i); + // if this is an element node, it might be a candidate for serialization + if (aChild.is() && aChild->getNodeType() == NodeType_ELEMENT_NODE) + serialize_node(aChild); + } + + // siblings... +// Reference< XNode > aSibling = aNode->getNextSibling(); +// if (aSibling.is()) +// serialize_node(aSibling); + +} + +/* +void CSerializationURLEncoded::serialize_nodeset() +{ + Reference< XNodeList > aNodeList = m_aXPathObject->getNodeList(); + for (sal_Int32 i=0; i<aNodeList->getLength(); i++) + serialize_node(aNodeList->item(i)); + m_aPipe->closeOutput(); +} +*/ + +void CSerializationURLEncoded::serialize() +{ + + // output stream to the pipe buffer + Reference< XOutputStream > out(m_aPipe, UNO_QUERY); + + CSS::uno::Reference< CSS::xml::dom::XNode > cur = m_aFragment->getFirstChild(); + while (cur.is()) + { + serialize_node(cur); + cur = cur->getNextSibling(); + } + m_aPipe->closeOutput(); +} + +Reference< XInputStream > CSerializationURLEncoded::getInputStream() +{ + return Reference< XInputStream >(m_aPipe, UNO_QUERY); +} + + diff --git a/forms/source/xforms/submission/serialization_urlencoded.hxx b/forms/source/xforms/submission/serialization_urlencoded.hxx new file mode 100644 index 000000000000..a3c41e7e4d5c --- /dev/null +++ b/forms/source/xforms/submission/serialization_urlencoded.hxx @@ -0,0 +1,56 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef __SERIALIZATION_URLENCODED_HXX +#define __SERIALIZATION_URLENCODED_HXX + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> + +#include <rtl/strbuf.hxx> + +#include "serialization.hxx" + +class CSerializationURLEncoded : public CSerialization +{ +private: + CSS::uno::Reference< CSS::lang::XMultiServiceFactory > m_aFactory; + CSS::uno::Reference< CSS::io::XOutputStream > m_aPipe; + + sal_Bool is_unreserved(sal_Char); + void encode_and_append(const rtl::OUString& aString, rtl::OStringBuffer& aBuffer); + void serialize_node(const CSS::uno::Reference< CSS::xml::dom::XNode >& aNode); + void serialize_nodeset(); + +public: + CSerializationURLEncoded(); + virtual void serialize(); + virtual CSS::uno::Reference< CSS::io::XInputStream > getInputStream(); +}; + +#endif diff --git a/forms/source/xforms/submission/submission.hxx b/forms/source/xforms/submission/submission.hxx new file mode 100644 index 000000000000..53e37b4cd131 --- /dev/null +++ b/forms/source/xforms/submission/submission.hxx @@ -0,0 +1,160 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef __SUBMISSION_HXX +#define __SUBMISSION_HXX + +#include <tools/urlobj.hxx> +#include <rtl/ustring.h> +#include <osl/conditn.hxx> +#include <osl/mutex.hxx> +#include <unotools/processfactory.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/xml/xpath/XXPathObject.hpp> +#include <com/sun/star/xml/dom/XDocumentFragment.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/ucb/XProgressHandler.hpp> + +#include <com/sun/star/task/XInteractionHandler.hpp> + +#include <com/sun/star/frame/XFrame.hpp> + +#include <cppuhelper/implbase1.hxx> +#include <cppuhelper/implbase2.hxx> +#include <cppuhelper/implbase3.hxx> + +#include "serialization.hxx" + +namespace CSS = com::sun::star; + +class CSubmissionPut; +class CSubmissionPost; +class CSubmissionGet; + +class CCommandEnvironmentHelper : public cppu::WeakImplHelper1< CSS::ucb::XCommandEnvironment > +{ + friend class CSubmissionPut; + friend class CSubmissionPost; + friend class CSubmissionGet; + friend class CSubmission; + +protected: + CSS::uno::Reference< CSS::task::XInteractionHandler > m_aInteractionHandler; + CSS::uno::Reference< CSS::ucb::XProgressHandler > m_aProgressHandler; + +public: + virtual CSS::uno::Reference< CSS::task::XInteractionHandler > SAL_CALL getInteractionHandler() throw (CSS::uno::RuntimeException) + { + return m_aInteractionHandler; + } + virtual CSS::uno::Reference< CSS::ucb::XProgressHandler > SAL_CALL getProgressHandler() throw (CSS::uno::RuntimeException) + { + return m_aProgressHandler; + } +}; + +class CProgressHandlerHelper : public cppu::WeakImplHelper1< CSS::ucb::XProgressHandler > +{ + friend class CSubmissionPut; + friend class CSubmissionPost; + friend class CSubmissionGet; +protected: + osl::Condition m_cFinished; + osl::Mutex m_mLock; + sal_Int32 m_count; +public: + CProgressHandlerHelper() + : m_count(0) + {} + virtual void SAL_CALL push( const com::sun::star::uno::Any& /*aStatus*/) throw(com::sun::star::uno::RuntimeException) + { + m_mLock.acquire(); + m_count++; + m_mLock.release(); + } + virtual void SAL_CALL update(const com::sun::star::uno::Any& /*aStatus*/) throw(com::sun::star::uno::RuntimeException) + { + } + virtual void SAL_CALL pop() throw(com::sun::star::uno::RuntimeException) + { + m_mLock.acquire(); + m_count--; + if (m_count == 0) + m_cFinished.set(); + m_mLock.release(); + } +}; + +class CSubmission +{ + +protected: + INetURLObject m_aURLObj; + CSS::uno::Reference< CSS::xml::xpath::XXPathObject > m_aXPathObject; + CSS::uno::Reference< CSS::xml::dom::XDocumentFragment > m_aFragment; + CSS::uno::Reference< CSS::io::XInputStream > m_aResultStream; + CSS::uno::Reference< CSS::lang::XMultiServiceFactory > m_aFactory; + rtl::OUString m_aEncoding; + + ::std::auto_ptr< CSerialization > createSerialization(const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& aHandler + ,com::sun::star::uno::Reference<com::sun::star::ucb::XCommandEnvironment>& _rOutEnv); + +public: + enum SubmissionResult { + SUCCESS, + INVALID_METHOD, + INVALID_URL, + INVALID_ENCODING, + E_TRANSMISSION, + UNKNOWN_ERROR + }; + + CSubmission(const rtl::OUString& aURL, const CSS::uno::Reference< CSS::xml::dom::XDocumentFragment >& aFragment) + : m_aURLObj(aURL) + , m_aFragment(aFragment) + , m_aFactory(::utl::getProcessServiceFactory()) + {} + + virtual ~CSubmission() {} + + // virtual CSS::uno::Sequence< rtl::OUString > getSupportedEncodings() = 0; + virtual void setEncoding(const rtl::OUString& aEncoding) + { + m_aEncoding = aEncoding; + } + virtual SubmissionResult submit(const CSS::uno::Reference< CSS::task::XInteractionHandler >& ) = 0; + + virtual SubmissionResult replace(const rtl::OUString&, const CSS::uno::Reference< CSS::xml::dom::XDocument >&, const CSS::uno::Reference< CSS::frame::XFrame>&); + +}; + +#endif diff --git a/forms/source/xforms/submission/submission_get.cxx b/forms/source/xforms/submission/submission_get.cxx new file mode 100644 index 000000000000..57adeda664c7 --- /dev/null +++ b/forms/source/xforms/submission/submission_get.cxx @@ -0,0 +1,117 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include <memory> + +#include "submission_get.hxx" +#include "serialization_app_xml.hxx" +#include "serialization_urlencoded.hxx" + +#include <rtl/strbuf.hxx> +#include <rtl/string.hxx> +#include <osl/file.hxx> +#include <unotools/processfactory.hxx> +#include <ucbhelper/content.hxx> + +using namespace CSS::uno; +using namespace CSS::ucb; +using namespace CSS::task; +using namespace CSS::io; +using namespace rtl; +using namespace osl; +using namespace ucbhelper; +using namespace std; + + +CSubmissionGet::CSubmissionGet(const rtl::OUString& aURL, const CSS::uno::Reference< CSS::xml::dom::XDocumentFragment >& aFragment) + : CSubmission(aURL, aFragment) +{ +} + +CSubmission::SubmissionResult CSubmissionGet::submit(const CSS::uno::Reference< CSS::task::XInteractionHandler >& aInteractionHandler) +{ + // GET always uses apllicatin/x-www-formurlencoded + auto_ptr< CSerialization > apSerialization(new CSerializationURLEncoded()); + apSerialization->setSource(m_aFragment); + apSerialization->serialize(); + + CSS::uno::Reference< XInputStream > aInStream = apSerialization->getInputStream(); + + // create a commandEnvironment and use the default interaction handler + CCommandEnvironmentHelper *pHelper = new CCommandEnvironmentHelper; + if( aInteractionHandler.is() ) + pHelper->m_aInteractionHandler = aInteractionHandler; + else + pHelper->m_aInteractionHandler = CSS::uno::Reference< XInteractionHandler >(m_aFactory->createInstance( + OUString::createFromAscii("com.sun.star.task.InteractionHandler")), UNO_QUERY); + OSL_ENSURE(pHelper->m_aInteractionHandler.is(), "failed to create IntreractionHandler"); + CProgressHandlerHelper *pProgressHelper = new CProgressHandlerHelper; + pHelper->m_aProgressHandler = CSS::uno::Reference< XProgressHandler >(pProgressHelper); + + // UCB has ownership of environment... + CSS::uno::Reference< XCommandEnvironment > aEnvironment(pHelper); + + // append query string to the URL + try { + OStringBuffer aUTF8QueryURL(OUStringToOString(m_aURLObj.GetMainURL(INetURLObject::NO_DECODE), + RTL_TEXTENCODING_UTF8)); + OStringBuffer aQueryString; + + const sal_Int32 size = 1024; + sal_Int32 n = 0; + Sequence< sal_Int8 > aByteBuffer(size); + while ((n = aInStream->readSomeBytes(aByteBuffer, size-1)) != 0) + aQueryString.append((sal_Char*)aByteBuffer.getArray(), n); + if (aQueryString.getLength() > 0 && m_aURLObj.GetProtocol() != INET_PROT_FILE) + { + aUTF8QueryURL.append('?'); + aUTF8QueryURL.append(aQueryString.makeStringAndClear()); + } + OUString aQueryURL = OStringToOUString(aUTF8QueryURL.makeStringAndClear(), RTL_TEXTENCODING_UTF8); + ucbhelper::Content aContent(aQueryURL, aEnvironment); + CSS::uno::Reference< XOutputStream > aPipe(m_aFactory->createInstance( + OUString::createFromAscii("com.sun.star.io.Pipe")), UNO_QUERY_THROW); + aContent.openStream(aPipe); + // get reply + try { + m_aResultStream = aContent.openStream(); + } catch (Exception&) { + OSL_ENSURE(sal_False, "Cannot open reply stream from content"); + } + } catch (Exception&) + { + // XXX + OSL_ENSURE(sal_False, "Exception during UCB operatration."); + return UNKNOWN_ERROR; + } + + return SUCCESS; +} + diff --git a/forms/source/xforms/submission/submission_get.hxx b/forms/source/xforms/submission/submission_get.hxx new file mode 100644 index 000000000000..931ecb514fc4 --- /dev/null +++ b/forms/source/xforms/submission/submission_get.hxx @@ -0,0 +1,44 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef __SUBMISSION_GET_HXX +#define __SUBMISSION_GET_HXX + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#include "submission.hxx" + +class CSubmissionGet : public CSubmission +{ +private: + CSS::uno::Reference< CSS::lang::XMultiServiceFactory > m_aFactory; +public: + CSubmissionGet(const rtl::OUString& aURL, const CSS::uno::Reference< CSS::xml::dom::XDocumentFragment >& aFragment); + virtual SubmissionResult submit(const CSS::uno::Reference< CSS::task::XInteractionHandler >& aInteractionHandler); + +}; +#endif diff --git a/forms/source/xforms/submission/submission_post.cxx b/forms/source/xforms/submission/submission_post.cxx new file mode 100644 index 000000000000..fa3f2180b0b0 --- /dev/null +++ b/forms/source/xforms/submission/submission_post.cxx @@ -0,0 +1,105 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include <memory> + +#include "submission_post.hxx" +#include "serialization_app_xml.hxx" +#include "serialization_urlencoded.hxx" + +#include <osl/file.hxx> +#include <unotools/processfactory.hxx> +#include <ucbhelper/content.hxx> +#include <ucbhelper/activedatasink.hxx> +#include <com/sun/star/ucb/PostCommandArgument2.hpp> + +using namespace CSS::uno; +using namespace CSS::ucb; +using namespace CSS::task; +using namespace CSS::io; +using namespace rtl; +using namespace osl; +using namespace ucbhelper; +using namespace std; + + +CSubmissionPost::CSubmissionPost(const rtl::OUString& aURL, const CSS::uno::Reference< CSS::xml::dom::XDocumentFragment >& aFragment) + : CSubmission(aURL, aFragment) +{ +} + +CSubmission::SubmissionResult CSubmissionPost::submit(const CSS::uno::Reference< CSS::task::XInteractionHandler >& aInteractionHandler) +{ + // PUT always uses application/xml + CSS::uno::Reference< XCommandEnvironment > aEnvironment; + auto_ptr< CSerialization > apSerialization(createSerialization(aInteractionHandler,aEnvironment)); + + try { + ucbhelper::Content aContent(m_aURLObj.GetMainURL(INetURLObject::NO_DECODE), aEnvironment); + + // use post command + + OUString aCommandName = OUString::createFromAscii("post"); + PostCommandArgument2 aPostArgument; + aPostArgument.Source = apSerialization->getInputStream(); + //CSS::uno::Reference< XInterface > aSink( m_aFactory->createInstance( + // OUString::createFromAscii("com.sun.star.io.Pipe")), UNO_QUERY_THROW); + CSS::uno::Reference< XActiveDataSink > aSink(new ucbhelper::ActiveDataSink); + // OUString::createFromAscii("com.sun.star.io.Pipe")), UNO_QUERY_THROW); + aPostArgument.Sink = aSink; + aPostArgument.MediaType = OUString::createFromAscii("application/xml"); + aPostArgument.Referer = OUString(); + Any aCommandArgument; + aCommandArgument <<= aPostArgument; + aContent.executeCommand( aCommandName, aCommandArgument); + + // wait for command to finish + // pProgressHelper->m_cFinished.wait(); + + // CSS::uno::Reference< XOutputStream > xOut(aSink, UNO_QUERY_THROW); + // xOut->closeOutput(); + + try { + // m_aResultStream = CSS::uno::Reference< XInputStream >(aSink, UNO_QUERY_THROW); + m_aResultStream = aSink->getInputStream(); + } catch (Exception&) { + OSL_ENSURE(sal_False, "Cannot open reply stream from content"); + } + } catch (Exception&) + { + // XXX + OSL_ENSURE(sal_False, "Exception during UCB operatration."); + return UNKNOWN_ERROR; + } + + + return SUCCESS; +} + diff --git a/forms/source/xforms/submission/submission_post.hxx b/forms/source/xforms/submission/submission_post.hxx new file mode 100644 index 000000000000..1c0c86d6490f --- /dev/null +++ b/forms/source/xforms/submission/submission_post.hxx @@ -0,0 +1,40 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef __SUBMISSION_POST_HXX +#define __SUBMISSION_POST_HXX + +#include "submission.hxx" + +class CSubmissionPost : public CSubmission +{ +public: + CSubmissionPost(const rtl::OUString& aURL, const CSS::uno::Reference< CSS::xml::dom::XDocumentFragment >& aFragment); + virtual SubmissionResult submit(const CSS::uno::Reference< CSS::task::XInteractionHandler >& aInteractionHandler); + +}; +#endif diff --git a/forms/source/xforms/submission/submission_put.cxx b/forms/source/xforms/submission/submission_put.cxx new file mode 100644 index 000000000000..9ed37470ba93 --- /dev/null +++ b/forms/source/xforms/submission/submission_put.cxx @@ -0,0 +1,81 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include <memory> + +#include "submission_put.hxx" +#include "serialization_app_xml.hxx" +#include "serialization_urlencoded.hxx" + +#include <osl/file.hxx> +#include <unotools/processfactory.hxx> +#include <ucbhelper/content.hxx> + +using namespace CSS::uno; +using namespace CSS::ucb; +using namespace CSS::task; +using namespace CSS::io; +using namespace rtl; +using namespace osl; +using namespace ucbhelper; +using namespace std; + + +CSubmissionPut::CSubmissionPut(const rtl::OUString& aURL, const CSS::uno::Reference< CSS::xml::dom::XDocumentFragment >& aFragment) + : CSubmission(aURL, aFragment) +{ +} + +CSubmission::SubmissionResult CSubmissionPut::submit(const CSS::uno::Reference< CSS::task::XInteractionHandler >& aInteractionHandler) +{ + CSS::uno::Reference< XCommandEnvironment > aEnvironment; + auto_ptr< CSerialization > apSerialization(createSerialization(aInteractionHandler,aEnvironment)); + + try { + ucbhelper::Content aContent(m_aURLObj.GetMainURL(INetURLObject::NO_DECODE), aEnvironment); + + // insert serialized data to content -> PUT + CSS::uno::Reference< XInputStream > aInStream = apSerialization->getInputStream(); + aContent.writeStream(aInStream, sal_True); + //aContent.closeStream(); + + // no content as a result of put... + + } catch (Exception&) + { + // XXX + OSL_ENSURE(sal_False, "Exception during UCB operatration."); + return UNKNOWN_ERROR; + } + + + return SUCCESS; +} + diff --git a/forms/source/xforms/submission/submission_put.hxx b/forms/source/xforms/submission/submission_put.hxx new file mode 100644 index 000000000000..10e4fa44007d --- /dev/null +++ b/forms/source/xforms/submission/submission_put.hxx @@ -0,0 +1,44 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef __SUBMISSION_PUT_HXX +#define __SUBMISSION_PUT_HXX + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/frame/XFrame.hpp> + +#include "submission.hxx" + +class CSubmissionPut : public CSubmission +{ +public: + CSubmissionPut(const rtl::OUString& aURL, const CSS::uno::Reference< CSS::xml::dom::XDocumentFragment >& aFragment); + virtual SubmissionResult submit(const CSS::uno::Reference< CSS::task::XInteractionHandler >& aInteractionHandler); + +}; +#endif + diff --git a/forms/source/xforms/unohelper.cxx b/forms/source/xforms/unohelper.cxx new file mode 100644 index 000000000000..738ad4f40a1a --- /dev/null +++ b/forms/source/xforms/unohelper.cxx @@ -0,0 +1,103 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include "unohelper.hxx" + +#include <osl/diagnose.h> + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <unotools/processfactory.hxx> + + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Exception; +using com::sun::star::uno::XInterface; +using com::sun::star::lang::XMultiServiceFactory; +using com::sun::star::beans::Property; +using com::sun::star::beans::XPropertySet; +using com::sun::star::beans::XPropertySetInfo; +using com::sun::star::beans::PropertyAttribute::READONLY; +using rtl::OUString; + + +Reference<XInterface> xforms::createInstance( const OUString& sServiceName ) +{ + Reference<XMultiServiceFactory> xFactory = utl::getProcessServiceFactory(); + OSL_ENSURE( xFactory.is(), "can't get service factory" ); + + Reference<XInterface> xInstance = xFactory->createInstance( sServiceName ); + OSL_ENSURE( xInstance.is(), "failed to create instance" ); + + return xInstance; +} + +void xforms::copy( const Reference<XPropertySet>& xFrom, + Reference<XPropertySet>& xTo ) +{ + OSL_ENSURE( xFrom.is(), "no source" ); + OSL_ENSURE( xTo.is(), "no target" ); + + // get property names & infos, and iterate over target properties + Sequence<Property> aProperties = + xTo->getPropertySetInfo()->getProperties(); + sal_Int32 nProperties = aProperties.getLength(); + const Property* pProperties = aProperties.getConstArray(); + Reference<XPropertySetInfo> xFromInfo = xFrom->getPropertySetInfo(); + for( sal_Int32 n = 0; n < nProperties; n++ ) + { + const OUString& rName = pProperties[n].Name; + + // if both set have the property, copy the value + // (catch and ignore exceptions, if any) + if( xFromInfo->hasPropertyByName( rName ) ) + { + try + { + Property aProperty = xFromInfo->getPropertyByName( rName ); + if ( ( aProperty.Attributes & READONLY ) == 0 ) + xTo->setPropertyValue(rName, xFrom->getPropertyValue( rName )); + } + catch( const Exception& ) + { + // ignore any errors; we'll copy as good as we can + } + } + // else: no property? then ignore. + } +} diff --git a/forms/source/xforms/unohelper.hxx b/forms/source/xforms/unohelper.hxx new file mode 100644 index 000000000000..d6cb46fcbc40 --- /dev/null +++ b/forms/source/xforms/unohelper.hxx @@ -0,0 +1,57 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _UNOHELPER_HXX +#define _UNOHELPER_HXX + +#include <sal/types.h> + +// forward declarations +namespace rtl { class OUString; } +namespace com { namespace sun { namespace star { + namespace uno { + class XInterface; + template<class T> class Reference; + } + namespace beans { class XPropertySet; } +} } } + + +#define OUSTRING(msg) rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( msg ) ) + +namespace xforms +{ + +/** instantiate a UNO service using the process global service factory */ +com::sun::star::uno::Reference<com::sun::star::uno::XInterface> + createInstance( const rtl::OUString& sServiceName ); + +/** copy the properties from one PropertySet into the next */ +void copy( const com::sun::star::uno::Reference<com::sun::star::beans::XPropertySet>& , com::sun::star::uno::Reference<com::sun::star::beans::XPropertySet>& ); + +} // namespace + +#endif diff --git a/forms/source/xforms/warnings_guard_unicode_regex.h b/forms/source/xforms/warnings_guard_unicode_regex.h new file mode 100644 index 000000000000..2d7605cb9524 --- /dev/null +++ b/forms/source/xforms/warnings_guard_unicode_regex.h @@ -0,0 +1,48 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_WARNINGS_GUARD_UNICODE_REGEX_H +#define INCLUDED_WARNINGS_GUARD_UNICODE_REGEX_H + +// Because the GCC system_header mechanism doesn't work in .c/.cxx compilation +// units and more important affects the rest of the current include file, the +// warnings guard is separated into this header file on its own. + +// External unicode includes (from icu) cause warning C4668 on Windows. +// We want to minimize the patches to external headers, so the warnings are +// disabled here instead of in the header file itself. +#ifdef _MSC_VER +#pragma warning(push, 1) +#elif defined __GNUC__ +#pragma GCC system_header +#endif +#include <unicode/regex.h> +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif // INCLUDED_WARNINGS_GUARD_UNICODE_REGEX_H diff --git a/forms/source/xforms/xforms_services.cxx b/forms/source/xforms/xforms_services.cxx new file mode 100644 index 000000000000..867a80bd7bbd --- /dev/null +++ b/forms/source/xforms/xforms_services.cxx @@ -0,0 +1,72 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + + +#include "services.hxx" + +#include "binding.hxx" +#include "model.hxx" +#include "NameContainer.hxx" + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/container/XNameContainer.hpp> + +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; +using com::sun::star::lang::XMultiServiceFactory; +using com::sun::star::uno::RuntimeException; +using com::sun::star::form::binding::XValueBinding; +using com::sun::star::beans::XPropertySet; +using com::sun::star::container::XNameContainer; +using rtl::OUString; + + +namespace frm +{ + +Reference<XInterface> Model_CreateInstance( + const Reference<XMultiServiceFactory>& ) + throw( RuntimeException ) +{ + return static_cast<XPropertySet*>( new xforms::Model ); +} + +Reference<XInterface> XForms_CreateInstance( + const Reference<XMultiServiceFactory>& ) + throw( RuntimeException ) +{ + return static_cast<XNameContainer*>( new NameContainer<Reference<XPropertySet> >() ); +} + +} diff --git a/forms/source/xforms/xforms_services.hxx b/forms/source/xforms/xforms_services.hxx new file mode 100644 index 000000000000..e40550bc6550 --- /dev/null +++ b/forms/source/xforms/xforms_services.hxx @@ -0,0 +1,27 @@ + + +namespace com { namespace sun { namespace star { + namespace uno { class XInterface; } + namespace uno { template<class T> class Reference<T>; } + namespace uno { class RuntimeException; } + namespace lang { class XMultiServiceFactory; } +} } } + + +namespace frm +{ + com::sun::star::uno::Reference<com::sun::star::uno::XInterface> + SAL_CALL Binding_CreateInstance( + const com::sun::star::uno::Reference<com::sun::star::lang::XMultiServiceFactory>& _rxFactory) + throw( com::sun::star::uno::RuntimeException ); + + com::sun::star::uno::Reference<com::sun::star::uno::XInterface> + SAL_CALL Model_CreateInstance( + const com::sun::star::uno::Reference<com::sun::star::lang::XMultiServiceFactory>& _rxFactory) + throw( com::sun::star::uno::RuntimeException ); + + com::sun::star::uno::Reference<com::sun::star::uno::XInterface> + SAL_CALL XForms_CreateInstance( + const com::sun::star::uno::Reference<com::sun::star::lang::XMultiServiceFactory>& _rxFactory) + throw( com::sun::star::uno::RuntimeException ); +} diff --git a/forms/source/xforms/xformsevent.cxx b/forms/source/xforms/xformsevent.cxx new file mode 100644 index 000000000000..56f8f2e9ca4a --- /dev/null +++ b/forms/source/xforms/xformsevent.cxx @@ -0,0 +1,100 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" +#include "xformsevent.hxx" + +namespace com { +namespace sun { +namespace star { +namespace xforms { + +using rtl::OUString; +using com::sun::star::uno::RuntimeException; + +void SAL_CALL XFormsEventConcrete::initXFormsEvent(const OUString& typeArg, + sal_Bool canBubbleArg, sal_Bool cancelableArg) + throw (RuntimeException) +{ + initEvent(typeArg, canBubbleArg, cancelableArg); +} + +OUString SAL_CALL XFormsEventConcrete::getType() throw (RuntimeException) +{ + return m_eventType; +} + +XFormsEventConcrete::XEventTarget_t SAL_CALL XFormsEventConcrete::getTarget() throw (RuntimeException) +{ + return m_target; +} + +XFormsEventConcrete::XEventTarget_t SAL_CALL XFormsEventConcrete::getCurrentTarget() throw (RuntimeException) +{ + return m_currentTarget; +} + +XFormsEventConcrete::PhaseType_t SAL_CALL XFormsEventConcrete::getEventPhase() throw (RuntimeException) +{ + return m_phase; +} + +sal_Bool SAL_CALL XFormsEventConcrete::getBubbles() throw (RuntimeException) +{ + return m_bubbles; +} + +sal_Bool SAL_CALL XFormsEventConcrete::getCancelable() throw (RuntimeException) +{ + return m_cancelable; +} + +XFormsEventConcrete::Time_t SAL_CALL XFormsEventConcrete::getTimeStamp() throw (RuntimeException) +{ + return m_time; +} + +void SAL_CALL XFormsEventConcrete::stopPropagation() throw (RuntimeException) +{ + if(m_cancelable) + m_canceled = sal_True; +} +void SAL_CALL XFormsEventConcrete::preventDefault() throw (RuntimeException) +{ +} + +void SAL_CALL XFormsEventConcrete::initEvent(const OUString& eventTypeArg, sal_Bool canBubbleArg, + sal_Bool cancelableArg) throw (RuntimeException) +{ + m_eventType = eventTypeArg; + m_bubbles = canBubbleArg; + m_cancelable = cancelableArg; +} + +} } } } diff --git a/forms/source/xforms/xformsevent.hxx b/forms/source/xforms/xformsevent.hxx new file mode 100644 index 000000000000..c770c0db6d56 --- /dev/null +++ b/forms/source/xforms/xformsevent.hxx @@ -0,0 +1,66 @@ +#ifndef __XFORMSEVENT_HXX +#define __XFORMSEVENT_HXX + +#include <sal/types.h> +#include <cppuhelper/implbase1.hxx> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/xforms/XFormsEvent.hpp> +#include <com/sun/star/xml/dom/events/XEventTarget.hpp> + +namespace com { +namespace sun { +namespace star { +namespace xforms { + +class XFormsEventConcrete : public cppu::WeakImplHelper1< XFormsEvent > { + + public: + + typedef com::sun::star::uno::RuntimeException RuntimeException_t; + typedef com::sun::star::uno::Reference< com::sun::star::xml::dom::events::XEventTarget > XEventTarget_t; + typedef com::sun::star::xml::dom::events::PhaseType PhaseType_t; + typedef com::sun::star::util::Time Time_t; + + inline XFormsEventConcrete( void ) : m_canceled(sal_False) {} + virtual ~XFormsEventConcrete( void ) {} + + virtual rtl::OUString SAL_CALL getType() throw (RuntimeException_t); + virtual XEventTarget_t SAL_CALL getTarget() throw (RuntimeException_t); + virtual XEventTarget_t SAL_CALL getCurrentTarget() throw (RuntimeException_t); + virtual PhaseType_t SAL_CALL getEventPhase() throw (RuntimeException_t); + virtual sal_Bool SAL_CALL getBubbles() throw (RuntimeException_t); + virtual sal_Bool SAL_CALL getCancelable() throw (RuntimeException_t); + virtual Time_t SAL_CALL getTimeStamp() throw (RuntimeException_t); + virtual void SAL_CALL stopPropagation() throw (RuntimeException_t); + virtual void SAL_CALL preventDefault() throw (RuntimeException_t); + + virtual void SAL_CALL initXFormsEvent( + const rtl::OUString& typeArg, + sal_Bool canBubbleArg, + sal_Bool cancelableArg ) + throw (RuntimeException_t); + + virtual void SAL_CALL initEvent( + const rtl::OUString& eventTypeArg, + sal_Bool canBubbleArg, + sal_Bool cancelableArg) + throw (RuntimeException_t); + + private: + + sal_Bool m_canceled; + + protected: + + rtl::OUString m_eventType; + XEventTarget_t m_target; + XEventTarget_t m_currentTarget; + PhaseType_t m_phase; + sal_Bool m_bubbles; + sal_Bool m_cancelable; + Time_t m_time; +}; + +} } } } + +#endif diff --git a/forms/source/xforms/xmlhelper.cxx b/forms/source/xforms/xmlhelper.cxx new file mode 100644 index 000000000000..a8aaa19aea34 --- /dev/null +++ b/forms/source/xforms/xmlhelper.cxx @@ -0,0 +1,148 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" + +#include "xmlhelper.hxx" + +#include "unohelper.hxx" +#include <rtl/ustring.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/xml/dom/XDocumentBuilder.hpp> + +using rtl::OUString; +using com::sun::star::uno::Reference; +using com::sun::star::uno::UNO_QUERY_THROW; +using com::sun::star::container::XNameContainer; +using com::sun::star::xml::dom::XDocumentBuilder; + + +// +// determine valid XML name +// + +// character class: +// 1: NameStartChar +// 2: NameChar +// 4: NCNameStartChar +// 8: NCNameChar +inline sal_uInt8 lcl_getCharClass( sal_Unicode c ) +{ + sal_uInt8 nClass = 0; + + // NameStartChar + if( (c >= 'A' && c <= 'Z') + || c == '_' + || (c >= 'a' && c <= 'z') + || (c >= 0x00C0 && c <= 0x00D6) + || (c >= 0x00D8 && c <= 0x00F6) + || (c >= 0x00F8 && c <= 0x02FF) + || (c >= 0x0370 && c <= 0x037D) + || (c >= 0x037F && c <= 0x1FFF) + || (c >= 0x200C && c <= 0x200D) + || (c >= 0x2070 && c <= 0x218F) + || (c >= 0x2C00 && c <= 0x2FEF) + || (c >= 0x3001 && c <= 0xD7FF) + || (c >= 0xF900 && c <= 0xFDCF) + || (c >= 0xFDF0 && c <= 0xFFFD) + + // surrogates + || (c >= 0xD800 && c <= 0xDBFF) + || (c >= 0xDC00 && c <= 0xDFFF) ) + { + nClass = 15; + } + else if( c == '-' + || c == '.' + || (c >= '0' && c <= '9') + || (c == 0x00B7) + || (c >= 0x0300 && c <= 0x036F) + || (c >= 0x203F && c <= 0x2040) ) + { + nClass = 10; + } + else if( c == ':' ) + { + nClass = 3; + } + + return nClass; +} + +bool isValidQName( const OUString& sName, + const Reference<XNameContainer>& /*xNamespaces*/ ) +{ + sal_Int32 nLength = sName.getLength(); + const sal_Unicode* pName = sName.getStr(); + + bool bRet = false; + sal_Int32 nColon = 0; + if( nLength > 0 ) + { + bRet = ( ( lcl_getCharClass( pName[0] ) & 4 ) != 0 ); + for( sal_Int32 n = 1; n < nLength; n++ ) + { + sal_uInt8 nClass = lcl_getCharClass( pName[n] ); + bRet &= ( ( nClass & 2 ) != 0 ); + if( nClass == 3 ) + nColon++; + } + } + if( nColon > 1 ) + bRet = sal_False; + + return bRet; +} + +bool isValidPrefixName( const OUString& sName, + const Reference<XNameContainer>& /*xNamespaces*/ ) +{ + sal_Int32 nLength = sName.getLength(); + const sal_Unicode* pName = sName.getStr(); + bool bRet = false; + + if( nLength > 0 ) + { + bRet = ( ( lcl_getCharClass( pName[0] ) & 4 ) != 0 ); + for( sal_Int32 n = 1; n < nLength; n++ ) + bRet &= ( ( lcl_getCharClass( pName[n] ) & 8 ) != 0 ); + } + + return bRet; +} + +Reference<XDocumentBuilder> getDocumentBuilder() +{ + Reference<XDocumentBuilder> xBuilder( + xforms::createInstance( + OUSTRING("com.sun.star.xml.dom.DocumentBuilder") ), + UNO_QUERY_THROW ); + OSL_ENSURE( xBuilder.is(), "no document builder?" ); + return xBuilder; +} + diff --git a/forms/source/xforms/xmlhelper.hxx b/forms/source/xforms/xmlhelper.hxx new file mode 100644 index 000000000000..d5822138a306 --- /dev/null +++ b/forms/source/xforms/xmlhelper.hxx @@ -0,0 +1,51 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _XMLHELPER_HXX +#define _XMLHELPER_HXX + +#include <sal/types.h> + + +namespace rtl { class OUString; } +namespace com { namespace sun { namespace star { + namespace uno { template<typename T> class Reference; } + namespace container { class XNameContainer; } + namespace xml { namespace dom { class XDocumentBuilder; } } +} } } + + +bool isValidQName( const rtl::OUString& sName, + const com::sun::star::uno::Reference<com::sun::star::container::XNameContainer>& xNamespaces ); + +bool isValidPrefixName( const rtl::OUString& sName, + const com::sun::star::uno::Reference<com::sun::star::container::XNameContainer>& xNamespaces ); + +com::sun::star::uno::Reference<com::sun::star::xml::dom::XDocumentBuilder> getDocumentBuilder(); + + +#endif diff --git a/forms/source/xforms/xpathlib/extension.cxx b/forms/source/xforms/xpathlib/extension.cxx new file mode 100644 index 000000000000..4c23eac63be0 --- /dev/null +++ b/forms/source/xforms/xpathlib/extension.cxx @@ -0,0 +1,104 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" +#include <stdio.h> +#include <com/sun/star/xml/xpath/Libxml2ExtensionHandle.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include "extension.hxx" +#include "xpathlib.hxx" +#include "frm_module.hxx" + +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::xforms; +using namespace com::sun::star::xml::xpath; +using namespace com::sun::star::beans; +using com::sun::star::xml::dom::XNode; + +Reference< XInterface > SAL_CALL CLibxml2XFormsExtension::Create( + const Reference< XMultiServiceFactory >& /*aFactory*/) +{ + // printf("_create_\n"); + Reference< XInterface > aInstance(static_cast< XXPathExtension* >(new CLibxml2XFormsExtension(/*aFactory*/))); + return aInstance; +} + +::rtl::OUString SAL_CALL CLibxml2XFormsExtension::getImplementationName_Static() +{ + // printf("_implname_\n"); + return ::rtl::OUString::createFromAscii("com.sun.star.comp.xml.xpath.XFormsExtension"); +} + +Sequence< ::rtl::OUString > SAL_CALL CLibxml2XFormsExtension::getSupportedServiceNames_Static() +{ + // printf("_services_\n"); + Sequence< ::rtl::OUString > aSequence(1); + aSequence[0] = ::rtl::OUString::createFromAscii("com.sun.star.xml.xpath.XPathExtension"); + return aSequence; +} + +Libxml2ExtensionHandle SAL_CALL CLibxml2XFormsExtension::getLibxml2ExtensionHandle() throw (RuntimeException) +{ + Libxml2ExtensionHandle aHandle; + aHandle.functionLookupFunction = reinterpret_cast< sal_Int64 >( &xforms_lookupFunc ); + aHandle.functionData = reinterpret_cast< sal_Int64 >( this ); + aHandle.variableLookupFunction = (sal_Int64)0; + aHandle.variableData = (sal_Int64)0; + return aHandle; +} + +void SAL_CALL CLibxml2XFormsExtension::initialize(const Sequence< Any >& aSequence) throw (RuntimeException) +{ + NamedValue aValue; + for (sal_Int32 i = 0; i < aSequence.getLength(); i++) + { + if (! (aSequence[i] >>= aValue)) + throw RuntimeException(); + if (aValue.Name.equalsAscii("Model")) + aValue.Value >>= m_aModel; + else if (aValue.Name.equalsAscii("ContextNode")) + aValue.Value >>= m_aContextNode; + } +} + +Reference< XModel > CLibxml2XFormsExtension::getModel() +{ + return m_aModel; +} + +Reference< XNode > CLibxml2XFormsExtension::getContextNode() +{ + return m_aContextNode; +} + +extern "C" void SAL_CALL createRegistryInfo_CLibxml2XFormsExtension() +{ + static frm::OMultiInstanceAutoRegistration< CLibxml2XFormsExtension > aRegistration; +} diff --git a/forms/source/xforms/xpathlib/extension.hxx b/forms/source/xforms/xpathlib/extension.hxx new file mode 100644 index 000000000000..303b832f9f43 --- /dev/null +++ b/forms/source/xforms/xpathlib/extension.hxx @@ -0,0 +1,39 @@ +#include <rtl/ustring.h> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <cppuhelper/implbase1.hxx> +#include <cppuhelper/implbase2.hxx> + +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/xml/xpath/XXPathExtension.hpp> +#include <com/sun/star/xforms/XModel.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/xml/dom/XNode.hpp> + + + + +class CLibxml2XFormsExtension : public cppu::WeakImplHelper2< + com::sun::star::xml::xpath::XXPathExtension, com::sun::star::lang::XInitialization> +{ +private: + com::sun::star::uno::Reference <com::sun::star::xforms::XModel> m_aModel; + com::sun::star::uno::Reference <com::sun::star::xml::dom::XNode> m_aContextNode; + +public: + static com::sun::star::uno::Reference< com::sun::star::uno::XInterface > SAL_CALL Create( + const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >& aFactory); + static rtl::OUString SAL_CALL getImplementationName_Static(); + static com::sun::star::uno::Sequence< rtl::OUString > SAL_CALL getSupportedServiceNames_Static(); + + com::sun::star::uno::Reference< com::sun::star::xforms::XModel > getModel(); + com::sun::star::uno::Reference< com::sun::star::xml::dom::XNode > getContextNode(); + + virtual com::sun::star::xml::xpath::Libxml2ExtensionHandle SAL_CALL getLibxml2ExtensionHandle() throw (com::sun::star::uno::RuntimeException); + virtual void SAL_CALL initialize(const com::sun::star::uno::Sequence< com::sun::star::uno::Any >& aSequence) throw (com::sun::star::uno::RuntimeException); + +}; diff --git a/forms/source/xforms/xpathlib/makefile.mk b/forms/source/xforms/xpathlib/makefile.mk new file mode 100644 index 000000000000..08e58eb2834c --- /dev/null +++ b/forms/source/xforms/xpathlib/makefile.mk @@ -0,0 +1,56 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=forms +TARGET=xformsxpath + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE: $(PRJ)$/makefile.pmk + +INCPRE+=$(PRJ)$/source$/inc + +.IF "$(SYSTEM_LIBXML)" == "YES" +CFLAGS+=-DSYSTEM_LIBXML $(LIBXML_CFLAGS) +.ENDIF + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/xpathlib.obj \ + $(SLO)$/extension.obj + + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/forms/source/xforms/xpathlib/xpathlib.cxx b/forms/source/xforms/xpathlib/xpathlib.cxx new file mode 100644 index 000000000000..2fd6a93b614a --- /dev/null +++ b/forms/source/xforms/xpathlib/xpathlib.cxx @@ -0,0 +1,567 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" +#include <string.h> +#include <sal/types.h> +#include <rtl/alloc.h> +#include <rtl/ustring.hxx> +#include <rtl/string.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/strbuf.hxx> +#include <tools/date.hxx> +#include <tools/time.hxx> +#include <tools/datetime.hxx> + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/xforms/XModel.hpp> +#include <com/sun/star/xml/dom/XNode.hpp> +#include <com/sun/star/xml/dom/XDocument.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> + +#include "xpathlib.hxx" + +#include "extension.hxx" + +// C interface + +using namespace com::sun::star::uno; +using namespace com::sun::star::xml::dom; +using namespace com::sun::star::xforms; +using namespace com::sun::star::lang; + +xmlXPathFunction xforms_lookupFunc(void *, const xmlChar *xname, const xmlChar *) +{ + + const char *name = (char *)xname; + if (strcmp("boolean-from-string", name)==0) + return xforms_booleanFromStringFunction; + else if ((strcmp("if", name))==0) + return xforms_ifFunction; + else if ((strcmp("avg", name))==0) + return xforms_avgFunction; + else if ((strcmp("min", name))==0) + return xforms_minFunction; + else if ((strcmp("max", name))==0) + return xforms_maxFunction; + else if ((strcmp("count-non-empty", name))==0) + return xforms_countNonEmptyFunction; + else if ((strcmp("index", name))==0) + return xforms_indexFunction; + else if ((strcmp("property", name))==0) + return xforms_propertyFunction; + else if ((strcmp("now", name))==0) + return xforms_nowFunction; + else if ((strcmp("days-from-date", name))==0) + return xforms_daysFromDateFunction; + else if ((strcmp("seconds-from-dateTime", name))==0) + return xforms_secondsFromDateTimeFunction; + else if ((strcmp("seconds", name))==0) + return xforms_secondsFuction; + else if ((strcmp("months", name))==0) + return xforms_monthsFuction; + else if ((strcmp("instance", name))==0) + return xforms_instanceFuction; + else if ((strcmp("current", name))==0) + return xforms_currentFunction; + else + return NULL; +} + +// boolean functions +void xforms_booleanFromStringFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY); + xmlChar *pString = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE); + ::rtl::OUString aString((char*)pString, strlen((char*)pString), RTL_TEXTENCODING_UTF8); + if (aString.equalsIgnoreAsciiCaseAscii("true") || aString.equalsIgnoreAsciiCaseAscii("1")) + xmlXPathReturnTrue(ctxt); + else if (aString.equalsIgnoreAsciiCaseAscii("false") || aString.equalsIgnoreAsciiCaseAscii("0")) + xmlXPathReturnFalse(ctxt); + else + XP_ERROR(XPATH_NUMBER_ERROR); +} + +void xforms_ifFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + if (nargs != 3) XP_ERROR(XPATH_INVALID_ARITY); + xmlChar *s2 = xmlXPathPopString(ctxt); + + if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE); + xmlChar *s1 = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE); + bool aBool = xmlXPathPopBoolean(ctxt); + if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE); + + if (aBool) + xmlXPathReturnString(ctxt, s1); + else + xmlXPathReturnString(ctxt, s2); + +} + +// Number Functions +void xforms_avgFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + // use sum(), div() and count() + if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY); + + // save nodeset + xmlXPathObjectPtr pObject = valuePop(ctxt); + if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE); + //push back a copy + valuePush(ctxt, xmlXPathObjectCopy(pObject)); + // get the Sum + xmlXPathSumFunction(ctxt, 1); + double nSum = xmlXPathPopNumber(ctxt); + // push a copy once more + valuePush(ctxt, xmlXPathObjectCopy(pObject)); + xmlXPathCountFunction(ctxt, 1); + double nCount = xmlXPathPopNumber(ctxt); + // push args for div() + xmlXPathReturnNumber(ctxt, nSum); + xmlXPathReturnNumber(ctxt, nCount); + xmlXPathDivValues(ctxt); + // the result is now on the ctxt stack + xmlXPathFreeObject(pObject); +} + +void xforms_minFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY); + xmlNodeSetPtr pNodeSet = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE); + double nMinimum = 0; + double nNumber = 0; + for (int i = 0; i < xmlXPathNodeSetGetLength(pNodeSet); i++) + { + nNumber = xmlXPathCastNodeToNumber(xmlXPathNodeSetItem(pNodeSet, i)); + if (xmlXPathIsNaN(nNumber)) + { + xmlXPathReturnNumber(ctxt, xmlXPathNAN); + return; + } + if (i == 0) + nMinimum = nNumber; + else if (nNumber < nMinimum) + nMinimum = nNumber; + } + xmlXPathReturnNumber(ctxt, nMinimum); +} + +void xforms_maxFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY); + xmlNodeSetPtr pNodeSet = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE); + double nMaximum = 0; + double nNumber = 0; + for (int i = 0; i < xmlXPathNodeSetGetLength(pNodeSet); i++) + { + nNumber = xmlXPathCastNodeToNumber(xmlXPathNodeSetItem(pNodeSet, i)); + if (xmlXPathIsNaN(nNumber)) + { + xmlXPathReturnNumber(ctxt, xmlXPathNAN); + return; + } + if (i == 0) + nMaximum = nNumber; + else if (nNumber > nMaximum) + nMaximum = nNumber; + } + xmlXPathReturnNumber(ctxt, nMaximum); +} +void xforms_countNonEmptyFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY); + xmlNodeSetPtr pNodeSet = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE); + xmlChar *aString; + sal_Int32 nNotEmpty = 0; + for (int i = 0; i < xmlXPathNodeSetGetLength(pNodeSet); i++) + { + aString = xmlXPathCastNodeToString(xmlXPathNodeSetItem(pNodeSet, i)); + if (strlen((char*)aString) > 0) nNotEmpty++; + } + xmlXPathReturnNumber(ctxt, nNotEmpty); +} +void xforms_indexFunction(xmlXPathParserContextPtr /*ctxt*/, int /*nargs*/) +{ + // function index takes a string argument that is the IDREF of a + // 'repeat' and returns the current 1-based position of the repeat + // index of the identified repeat -- see xforms/9.3.1 + + // doc.getElementByID + // (...) +} + +// String Functions +static const char* _version = "1.0"; +static const char* _conformance = "conformance"; +void xforms_propertyFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY); + xmlChar* pString = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE); + ::rtl::OUString aString((char*)pString, strlen((char*)pString), RTL_TEXTENCODING_UTF8); + if (aString.equalsIgnoreAsciiCaseAscii("version")) + xmlXPathReturnString(ctxt, (xmlChar*)_version); + else if (aString.equalsIgnoreAsciiCaseAscii("conformance-level")) + xmlXPathReturnString(ctxt, (xmlChar*)_conformance); + else + xmlXPathReturnEmptyString(ctxt); +} + +// Date and Time Functions + +static ::rtl::OString makeDateTimeString (const DateTime& aDateTime, sal_Bool bUTC = sal_True) +{ + ::rtl::OStringBuffer aDateTimeString; + aDateTimeString.append((sal_Int32)aDateTime.GetYear()); + aDateTimeString.append("-"); + if (aDateTime.GetMonth()<10) aDateTimeString.append("0"); + aDateTimeString.append((sal_Int32)aDateTime.GetMonth()); + aDateTimeString.append("-"); + if (aDateTime.GetDay()<10) aDateTimeString.append("0"); + aDateTimeString.append((sal_Int32)aDateTime.GetDay()); + aDateTimeString.append("T"); + if (aDateTime.GetHour()<10) aDateTimeString.append("0"); + aDateTimeString.append((sal_Int32)aDateTime.GetHour()); + aDateTimeString.append(":"); + if (aDateTime.GetMin()<10) aDateTimeString.append("0"); + aDateTimeString.append((sal_Int32)aDateTime.GetMin()); + aDateTimeString.append(":"); + if (aDateTime.GetSec()<10) aDateTimeString.append("0"); + aDateTimeString.append((sal_Int32)aDateTime.GetSec()); + if (bUTC) aDateTimeString.append("Z"); + + return aDateTimeString.makeStringAndClear(); +} + +// returns current system date and time in canonical xsd:dateTime +// format +void xforms_nowFunction(xmlXPathParserContextPtr ctxt, int /*nargs*/) +{ + /* + A single lexical representation, which is a subset of the lexical representations + allowed by [ISO 8601], is allowed for dateTime. This lexical representation is the + [ISO 8601] extended format CCYY-MM-DDThh:mm:ss where "CC" represents the century, + "YY" the year, "MM" the month and "DD" the day, preceded by an optional leading "-" + sign to indicate a negative number. If the sign is omitted, "+" is assumed. The letter + "T" is the date/time separator and "hh", "mm", "ss" represent hour, minute and second + respectively. + */ + + /* + 3.2.7.2 Canonical representation + The canonical representation for dateTime is defined by prohibiting certain options + from the Lexical representation (par.3.2.7.1). Specifically, either the time zone must + be omitted or, if present, the time zone must be Coordinated Universal Time (UTC) + indicated by a "Z". + */ + DateTime aDateTime; + ::rtl::OString aDateTimeString = makeDateTimeString(aDateTime); + xmlChar *pString = static_cast<xmlChar*>(xmlMalloc(aDateTimeString.getLength()+1)); + strncpy((char*)pString, (char*)aDateTimeString.getStr(), aDateTimeString.getLength()); + pString[aDateTimeString.getLength()] = 0; + xmlXPathReturnString(ctxt, pString); +} + +static sal_Bool parseDateTime(const ::rtl::OUString& aString, DateTime& aDateTime) +{ + // take apart a canonical literal xsd:dateTime string + //CCYY-MM-DDThh:mm:ss(Z) + + ::rtl::OUString aDateTimeString = aString.trim(); + + // check length + if (aDateTimeString.getLength() < 19 || aDateTimeString.getLength() > 20) + return sal_False; + + sal_Int32 nDateLength = 10; + sal_Int32 nTimeLength = 8; + + ::rtl::OUString aDateTimeSep = ::rtl::OUString::createFromAscii("T"); + ::rtl::OUString aDateSep = ::rtl::OUString::createFromAscii("-"); + ::rtl::OUString aTimeSep = ::rtl::OUString::createFromAscii(":"); + ::rtl::OUString aUTCString = ::rtl::OUString::createFromAscii("Z"); + + ::rtl::OUString aDateString = aDateTimeString.copy(0, nDateLength); + ::rtl::OUString aTimeString = aDateTimeString.copy(nDateLength+1, nTimeLength); + + sal_Int32 nIndex = 0; + sal_Int32 nYear = aDateString.getToken(0, '-', nIndex).toInt32(); + sal_Int32 nMonth = aDateString.getToken(0, '-', nIndex).toInt32(); + sal_Int32 nDay = aDateString.getToken(0, '-', nIndex).toInt32(); + nIndex = 0; + sal_Int32 nHour = aTimeString.getToken(0, ':', nIndex).toInt32(); + sal_Int32 nMinute = aTimeString.getToken(0, ':', nIndex).toInt32(); + sal_Int32 nSecond = aTimeString.getToken(0, ':', nIndex).toInt32(); + + Date tmpDate((USHORT)nDay, (USHORT)nMonth, (USHORT)nYear); + Time tmpTime(nHour, nMinute, nSecond); + DateTime tmpDateTime(tmpDate, tmpTime); + if (aString.indexOf(aUTCString) < 0) + tmpDateTime.ConvertToUTC(); + + aDateTime = tmpDateTime; + + return sal_True; +} + + +void xforms_daysFromDateFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + // number of days from 1970-01-01 to supplied xsd:date(Time) + + if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY); + xmlChar* pString = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE); + ::rtl::OUString aString((char*)pString, strlen((char*)pString), RTL_TEXTENCODING_UTF8); + + DateTime aDateTime; + if (parseDateTime(aString, aDateTime)) + { + Date aReferenceDate(1, 1, 1970); + sal_Int32 nDays = aDateTime - aReferenceDate; + xmlXPathReturnNumber(ctxt, nDays); + } + else + xmlXPathReturnNumber(ctxt, xmlXPathNAN); + + +} + + +void xforms_secondsFromDateTimeFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + // number of seconds from 1970-01-01T00:00:00Z to supplied xsd:date(Time) + + if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY); + xmlChar* pString = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE); + ::rtl::OUString aString((char*)pString, strlen((char*)pString), RTL_TEXTENCODING_UTF8); + + DateTime aDateTime; + + if (parseDateTime(aString, aDateTime)) + { + Date aReferenceDate(1, 1, 1970); + Time aReferenceTime(0, 0, 0); + sal_Int32 nDays = aDateTime - aReferenceDate; + sal_Int32 nSeconds = nDays * 24 * 60 * 60; + nSeconds += aDateTime.GetHour() * 60 * 60; + nSeconds += aDateTime.GetMin() * 60; + nSeconds += aDateTime.GetSec(); + xmlXPathReturnNumber(ctxt, nSeconds); + } + else + xmlXPathReturnNumber(ctxt, xmlXPathNAN); + +} + +static sal_Bool parseDuration(const xmlChar* aString, sal_Bool& bNegative, sal_Int32& nYears, sal_Int32& nMonth, sal_Int32& nDays, + sal_Int32& nHours, sal_Int32& nMinutes, sal_Int32& nSeconds) +{ + sal_Bool bTime = sal_False; // in part after T + sal_Int32 nLength = strlen((char*)aString)+1; + char *pString = (char*)rtl_allocateMemory(nLength); + char *pString0 = pString; + strncpy(pString, (char*)aString, nLength); + + if (pString[0] == '-') { + bNegative = sal_True; + pString++; + } + + if (pString[0] != 'P') + return sal_False; + pString++; + char* pToken = pString; + while(pToken[0] != 0) + { + switch(pToken[0]) { + case 'Y': + pToken[0] = 0; + nYears = atoi(pString); + pString = ++pToken; + break; + case 'M': + pToken[0] = 0; + if (!bTime) + nMonth = atoi(pString); + else + nMinutes = atoi(pString); + pString = ++pToken; + break; + case 'D': + pToken[0] = 0; + nDays = atoi(pString); + pString = ++pToken; + break; + case 'H': + pToken[0] = 0; + nHours = atoi(pString); + pString = ++pToken; + break; + case 'S': + pToken[0] = 0; + nSeconds = atoi(pString); + pString = ++pToken; + break; + case 'T': + bTime = sal_True; + pString = ++pToken; + break; + default: + pToken++; + } + } + rtl_freeMemory(pString0); + return sal_True; +} + +void xforms_secondsFuction(xmlXPathParserContextPtr ctxt, int nargs) +{ + // convert a xsd:duration to seconds + // (-)PnYnMnDTnHnMnS + if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY); + xmlChar* pString = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE); + + sal_Bool bNegative = sal_False; + sal_Int32 nYears = 0; + sal_Int32 nMonths = 0; + sal_Int32 nDays = 0; + sal_Int32 nHours = 0; + sal_Int32 nMinutes = 0; + sal_Int32 nSeconds = 0; + + if (parseDuration(pString, bNegative, nYears, nMonths, nDays, nHours, nMinutes, nSeconds)) + { + nSeconds += nMinutes*60; + nSeconds += nHours*60*60; + nSeconds += nDays*24*60*60; + // year and month are ignored according to spec + if (bNegative) + nSeconds = 0 - nSeconds; + xmlXPathReturnNumber(ctxt, nSeconds); + } + else + xmlXPathReturnNumber(ctxt, xmlXPathNAN); +} + +void xforms_monthsFuction(xmlXPathParserContextPtr ctxt, int nargs) +{ + // convert a xsd:duration to seconds + // (-)PnYnMnDTnHnMnS + if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY); + xmlChar* pString = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE); + + sal_Bool bNegative = sal_False; + sal_Int32 nYears = 0; + sal_Int32 nMonths = 0; + sal_Int32 nDays = 0; + sal_Int32 nHours = 0; + sal_Int32 nMinutes = 0; + sal_Int32 nSeconds = 0; + + if (parseDuration(pString, bNegative, nYears, nMonths, nDays, nHours, nMinutes, nSeconds)) + { + nMonths += nYears*12; + // Days, Houres, Minutes and seconds are ignored, see spec + if (bNegative) + nMonths = 0 - nMonths; + xmlXPathReturnNumber(ctxt, nMonths); + } + else + xmlXPathReturnNumber(ctxt, xmlXPathNAN); + +} + +// Node-set Functions +void xforms_instanceFuction(xmlXPathParserContextPtr ctxt, int nargs) +{ + if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY); + xmlChar *pString = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE); + ::rtl::OUString aString((char*)pString, strlen((char*)pString), RTL_TEXTENCODING_UTF8); + + Reference< XModel > aModel = ((CLibxml2XFormsExtension*)ctxt->context->funcLookupData)->getModel(); + if (aModel.is()) + { + Reference< XDocument > aInstance = aModel->getInstanceDocument(aString); + if (aInstance.is()) + { + try { + // xmlXPathObjectPtr xmlXPathNewNodeSet (xmlNodePtr val); + Reference< XUnoTunnel > aTunnel(aInstance, UNO_QUERY_THROW); + xmlNodePtr pNode = reinterpret_cast< xmlNodePtr >( aTunnel->getSomething(Sequence< sal_Int8 >()) ); + xmlXPathObjectPtr pObject = xmlXPathNewNodeSet(pNode); + xmlXPathReturnNodeSet(ctxt, pObject->nodesetval); + } catch (RuntimeException&) + { + xmlXPathReturnEmptyNodeSet(ctxt); + } + } + else + xmlXPathReturnEmptyNodeSet(ctxt); + } + else + xmlXPathReturnEmptyNodeSet(ctxt); + +} + +// Node-set Functions, XForms 1.1 +void xforms_currentFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + if (nargs != 0) XP_ERROR(XPATH_INVALID_ARITY); + + Reference< XNode > aNode = ((CLibxml2XFormsExtension*)ctxt->context->funcLookupData)->getContextNode(); + + if (aNode.is()) + { + try { + Reference< XUnoTunnel > aTunnel(aNode, UNO_QUERY_THROW); + xmlNodePtr pNode = reinterpret_cast< xmlNodePtr >( aTunnel->getSomething(Sequence< sal_Int8 >()) ); + xmlXPathObjectPtr pObject = xmlXPathNewNodeSet(pNode); + xmlXPathReturnNodeSet(ctxt, pObject->nodesetval); + } + catch (RuntimeException&) + { + xmlXPathReturnEmptyNodeSet(ctxt); + } + } + else + xmlXPathReturnEmptyNodeSet(ctxt); +} diff --git a/forms/source/xforms/xpathlib/xpathlib.hxx b/forms/source/xforms/xpathlib/xpathlib.hxx new file mode 100644 index 000000000000..d9fe96e598ca --- /dev/null +++ b/forms/source/xforms/xpathlib/xpathlib.hxx @@ -0,0 +1,83 @@ + + +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> + +/* + entry functions for libxml xpath engine + +*/ + +/** + * xmlXPathParserContext: + * + * An XPath parser context. It contains pure parsing informations, + * an xmlXPathContext, and the stack of objects. + */ +#if 0 +// for reference from xpath.h +struct _xmlXPathParserContext { + const xmlChar *cur; /* the current char being parsed */ + const xmlChar *base; /* the full expression */ + + int error; /* error code */ + + xmlXPathContextPtr context; /* the evaluation context */ + xmlXPathObjectPtr value; /* the current value */ + int valueNr; /* number of values stacked */ + int valueMax; /* max number of values stacked */ + xmlXPathObjectPtr *valueTab; /* stack of values */ + + xmlXPathCompExprPtr comp; /* the precompiled expression */ + int xptr; /* it this an XPointer expression */ + xmlNodePtr ancestor; /* used for walking preceding axis */ +}; + +#endif + +extern "C" +{ + +// XForms +/* +void xforms_getInstanceDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs); +void xforms_rebuildFunction(xmlXPathParserContextPtr ctxt, int nargs); +void xforms_recalculateFunction(xmlXPathParserContextPtr ctxt, int nargs); +void xforms_revalidateFunction(xmlXPathParserContextPtr ctxt, int nargs); +void xforms_refreshFunction(xmlXPathParserContextPtr ctxt, int nargs); +*/ + +// XForms Core Functions +// boolean functions +void xforms_booleanFromStringFunction(xmlXPathParserContextPtr ctxt, int nargs); +void xforms_ifFunction(xmlXPathParserContextPtr ctxt, int nargs); + +// Number Functions +void xforms_avgFunction(xmlXPathParserContextPtr ctxt, int nargs); +void xforms_minFunction(xmlXPathParserContextPtr ctxt, int nargs); +void xforms_maxFunction(xmlXPathParserContextPtr ctxt, int nargs); +void xforms_countNonEmptyFunction(xmlXPathParserContextPtr ctxt, int nargs); +void xforms_indexFunction(xmlXPathParserContextPtr ctxt, int nargs); + +// String Functions +void xforms_propertyFunction(xmlXPathParserContextPtr ctxt, int nargs); +void xforms_versionFunction(xmlXPathParserContextPtr ctxt, int nargs); + +// Date and Time Functions +void xforms_nowFunction(xmlXPathParserContextPtr ctxt, int nargs); +void xforms_daysFromDateFunction(xmlXPathParserContextPtr ctxt, int nargs); +void xforms_secondsFromDateTimeFunction(xmlXPathParserContextPtr ctxt, int nargs); +void xforms_secondsFuction(xmlXPathParserContextPtr ctxt, int nargs); +void xforms_monthsFuction(xmlXPathParserContextPtr ctxt, int nargs); + +// Node-set Functions +void xforms_instanceFuction(xmlXPathParserContextPtr ctxt, int nargs); + +// Node-set Functions; XForms 1.1 +void xforms_currentFunction(xmlXPathParserContextPtr ctxt, int nargs); + +// --- lookup --- +xmlXPathFunction xforms_lookupFunc(void *ctxt, const xmlChar *name, const xmlChar *ns_uri); + +} |