1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include "model_helper.hxx"
24 #include "evaluationcontext.hxx"
25 #include "unohelper.hxx"
26 #include "submission/serialization_app_xml.hxx"
27 #include "resourcehelper.hxx"
28 #include "xmlhelper.hxx"
29 #include "convert.hxx"
31 #include <rtl/ustring.hxx>
32 #include <rtl/ustrbuf.hxx>
33 #include <tools/debug.hxx>
34 #include <comphelper/processfactory.hxx>
37 #include <com/sun/star/xml/dom/XNode.hpp>
38 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
39 #include <com/sun/star/xml/dom/XDocumentFragment.hpp>
40 #include <com/sun/star/xml/dom/XNamedNodeMap.hpp>
41 #include <com/sun/star/xml/xpath/XXPathObject.hpp>
42 #include <com/sun/star/xml/xpath/XPathObjectType.hpp>
43 #include <com/sun/star/beans/PropertyValue.hpp>
44 #include <com/sun/star/io/XInputStream.hpp>
45 #include <com/sun/star/io/XActiveDataSink.hpp>
46 #include <com/sun/star/io/TextInputStream.hpp>
47 #include <com/sun/star/container/XEnumeration.hpp>
48 #include <com/sun/star/container/XNameContainer.hpp>
49 #include <com/sun/star/frame/XModel.hpp>
50 #include <com/sun/star/xforms/XFormsSupplier.hpp>
51 #include <com/sun/star/xforms/XDataTypeRepository.hpp>
52 #include <com/sun/star/xsd/XDataType.hpp>
53 #include <com/sun/star/xsd/DataTypeClass.hpp>
56 using com::sun::star::beans::PropertyValue
;
57 using com::sun::star::io::XInputStream
;
58 using com::sun::star::io::XActiveDataSink
;
59 using com::sun::star::io::TextInputStream
;
60 using com::sun::star::io::XTextInputStream2
;
61 using com::sun::star::container::XEnumeration
;
62 using com::sun::star::container::XNameContainer
;
63 using com::sun::star::xforms::XFormsSupplier
;
65 using namespace xforms
;
66 using namespace com::sun::star::uno
;
67 using namespace com::sun::star::xml::dom
;
68 using namespace com::sun::star::xml::xpath
;
73 // implement XFormsUIHelper1
76 OUString
Model::getDefaultServiceNameForNode( const XNode_t
& xNode
)
77 throw( RuntimeException
, std::exception
)
79 // determine service for control. string/text field is default.
80 OUString sService
= "com.sun.star.form.component.TextField";
82 // query repository for suitable type
83 OSL_ENSURE( mxDataTypes
.is(), "no type repository?" );
84 OUString sTypeName
= queryMIP( xNode
).getTypeName();
85 if( mxDataTypes
->hasByName( sTypeName
) )
87 OSL_ENSURE( mxDataTypes
->getDataType( sTypeName
).is(),
90 switch( mxDataTypes
->getDataType( sTypeName
)->getTypeClass() )
92 case com::sun::star::xsd::DataTypeClass::BOOLEAN
:
93 sService
= "com.sun.star.form.component.CheckBox";
95 case com::sun::star::xsd::DataTypeClass::DOUBLE
:
96 case com::sun::star::xsd::DataTypeClass::DECIMAL
:
97 case com::sun::star::xsd::DataTypeClass::FLOAT
:
98 sService
= "com.sun.star.form.component.NumericField";
101 case com::sun::star::xsd::DataTypeClass::STRING
:
102 case com::sun::star::xsd::DataTypeClass::DURATION
:
103 case com::sun::star::xsd::DataTypeClass::DATETIME
:
104 case com::sun::star::xsd::DataTypeClass::TIME
:
105 case com::sun::star::xsd::DataTypeClass::DATE
:
106 case com::sun::star::xsd::DataTypeClass::gYearMonth
:
107 case com::sun::star::xsd::DataTypeClass::gYear
:
108 case com::sun::star::xsd::DataTypeClass::gMonthDay
:
109 case com::sun::star::xsd::DataTypeClass::gDay
:
110 case com::sun::star::xsd::DataTypeClass::gMonth
:
111 case com::sun::star::xsd::DataTypeClass::hexBinary
:
112 case com::sun::star::xsd::DataTypeClass::base64Binary
:
113 case com::sun::star::xsd::DataTypeClass::anyURI
:
114 case com::sun::star::xsd::DataTypeClass::QName
:
115 case com::sun::star::xsd::DataTypeClass::NOTATION
:
126 static void lcl_OutPosition( OUStringBuffer
& rBuffer
,
127 const Reference
<XNode
>& xNode
)
129 OSL_ENSURE( xNode
->getParentNode().is(), "need parent" );
131 // count # of occurrences of this node
132 sal_Int32 nFound
= 0;
133 sal_Int32 nPosition
= -1;
134 if( xNode
->getParentNode().is() )
136 for( Reference
<XNode
> xIter
= xNode
->getParentNode()->getFirstChild();
138 xIter
= xIter
->getNextSibling() )
140 if( xIter
->getNodeType() == xNode
->getNodeType() &&
141 xIter
->getNodeName() == xNode
->getNodeName() &&
142 xIter
->getNamespaceURI() == xNode
->getNamespaceURI() )
150 OSL_ENSURE( nFound
> 0 && nPosition
> 0, "node not found???" );
152 // output position (if necessary)
155 rBuffer
.insert( 0, ']' );
156 rBuffer
.insert( 0, nPosition
);
157 rBuffer
.insert( 0, '[' );
161 static void lcl_OutName( OUStringBuffer
& rBuffer
,
162 const Reference
<XNode
>& xNode
)
164 rBuffer
.insert( 0, xNode
->getNodeName() );
165 OUString sPrefix
= xNode
->getPrefix();
166 if( !sPrefix
.isEmpty() )
168 rBuffer
.insert( 0, ':' );
169 rBuffer
.insert( 0, sPrefix
);
173 static void lcl_OutInstance( OUStringBuffer
& rBuffer
,
174 const Reference
<XNode
>& xNode
,
177 Reference
<XDocument
> xDoc
= xNode
->getOwnerDocument();
179 if( xDoc
!= pModel
->getDefaultInstance() )
181 rBuffer
.insert( 0, "')" );
183 // iterate over instances, and find the right one
184 OUString sInstanceName
;
185 Reference
<XEnumeration
> xEnum
=
186 pModel
->getInstances()->createEnumeration();
187 while( sInstanceName
.isEmpty() && xEnum
->hasMoreElements() )
189 Sequence
<PropertyValue
> aValues
;
190 xEnum
->nextElement() >>= aValues
;
192 // get ID and instance
194 Reference
<XDocument
> xInstance
;
195 getInstanceData( aValues
, &sId
, &xInstance
, NULL
, NULL
);
197 // now check whether this was our instance:
198 if( xInstance
== xDoc
)
202 rBuffer
.insert( 0, sInstanceName
);
203 rBuffer
.insert( 0, "instance('" );
207 OUString
Model::getDefaultBindingExpressionForNode(
208 const XNode_t
& xNode
,
209 const EvaluationContext
& rContext
)
211 OSL_ENSURE( xNode
.is(), "need node" );
213 // iterate upwards and put sections into the expression buffer.
214 // Stop iteration either at context node (relative expression) or
215 // at document root, whichever occurs first.
216 OUStringBuffer aBuffer
;
217 for( Reference
<XNode
> xCurrent
= xNode
;
218 xCurrent
.is() && xCurrent
!= rContext
.mxContextNode
;
219 xCurrent
= xCurrent
->getParentNode() )
221 // insert a '/' for every step except the first
222 if( !aBuffer
.isEmpty() )
223 aBuffer
.insert( 0, '/' );
225 switch( xCurrent
->getNodeType() )
227 case NodeType_ELEMENT_NODE
:
228 lcl_OutPosition( aBuffer
, xCurrent
);
229 lcl_OutName( aBuffer
, xCurrent
);
232 case NodeType_TEXT_NODE
:
233 lcl_OutPosition( aBuffer
, xCurrent
);
234 aBuffer
.insert( 0, "text()" );
237 case NodeType_ATTRIBUTE_NODE
:
238 lcl_OutName( aBuffer
, xCurrent
);
239 aBuffer
.insert( 0, '@' );
242 case NodeType_DOCUMENT_NODE
:
243 // check for which instance we have
244 lcl_OutInstance( aBuffer
, xCurrent
, this );
248 // unknown type? fail!
249 OSL_FAIL( "unknown node type!" );
250 xCurrent
.set( NULL
);
251 aBuffer
.makeStringAndClear();
252 // we'll remove the slash below
253 aBuffer
.insert( 0, '/' );
258 return aBuffer
.makeStringAndClear();
263 OUString
Model::getDefaultBindingExpressionForNode( const XNode_t
& xNode
)
264 throw( RuntimeException
, std::exception
)
266 return getDefaultBindingExpressionForNode( xNode
, getEvaluationContext() );
269 static bool lcl_isWhitespace( const OUString
& rString
)
271 sal_Int32 nLength
= rString
.getLength();
272 const sal_Unicode
* pStr
= rString
.getStr();
274 bool bWhitespace
= true;
275 for( sal_Int32 i
= 0; bWhitespace
&& ( i
< nLength
); i
++ )
277 sal_Unicode c
= pStr
[i
];
278 bWhitespace
= ( c
== sal_Unicode(0x09) ||
279 c
== sal_Unicode(0x0A) ||
280 c
== sal_Unicode(0x0D) ||
281 c
== sal_Unicode(0x20) );
286 OUString
Model::getNodeDisplayName( const XNode_t
& xNode
,
288 throw( RuntimeException
, std::exception
)
290 OUStringBuffer aBuffer
;
292 switch( xNode
->getNodeType() )
294 case NodeType_ELEMENT_NODE
:
295 lcl_OutName( aBuffer
, xNode
);
298 case NodeType_TEXT_NODE
:
300 OUString sContent
= xNode
->getNodeValue();
301 if( bDetail
|| ! lcl_isWhitespace( sContent
) )
303 aBuffer
= aBuffer
+ "\"" + Convert::collapseWhitespace( sContent
) + "\"";
308 case NodeType_ATTRIBUTE_NODE
:
309 lcl_OutName( aBuffer
, xNode
);
310 aBuffer
.insert( 0, '@' );
313 case NodeType_DOCUMENT_NODE
:
314 if( xNode
== getDefaultInstance() )
315 aBuffer
.append( '/' );
317 lcl_OutInstance( aBuffer
, xNode
, this );
321 // unknown type? fail!
322 OSL_FAIL( "unknown node type!" );
326 return aBuffer
.makeStringAndClear();
329 OUString
Model::getNodeName( const XNode_t
& xNode
)
330 throw( RuntimeException
, std::exception
)
332 OUStringBuffer aBuffer
;
334 switch( xNode
->getNodeType() )
336 case NodeType_ELEMENT_NODE
:
337 case NodeType_ATTRIBUTE_NODE
:
338 lcl_OutName( aBuffer
, xNode
);
341 case NodeType_TEXT_NODE
:
342 case NodeType_DOCUMENT_NODE
:
344 // unknown type? fail!
345 OSL_FAIL( "no name for this node type!" );
349 return aBuffer
.makeStringAndClear();
352 OUString
Model::getBindingName( const XPropertySet_t
& xBinding
,
353 sal_Bool
/*bDetail*/ )
354 throw( RuntimeException
, std::exception
)
357 xBinding
->getPropertyValue( "BindingID" ) >>= sID
;
358 OUString sExpression
;
359 xBinding
->getPropertyValue( "BindingExpression" ) >>= sExpression
;
364 sRet
= sID
+ " (" + sExpression
+ ") ";
372 OUString
Model::getSubmissionName( const XPropertySet_t
& xSubmission
,
373 sal_Bool
/*bDetail*/ )
374 throw( RuntimeException
, std::exception
)
377 xSubmission
->getPropertyValue( "ID" ) >>= sID
;
381 Model::XPropertySet_t
Model::cloneBindingAsGhost( const XPropertySet_t
&xBinding
)
382 throw( RuntimeException
, std::exception
)
384 // Create a new binding instance first...
385 Binding
*pBinding
= new Binding();
387 // ...and bump up the "defered notification counter"
388 // to prevent this binding from contributing to the
390 pBinding
->deferNotifications(true);
392 // Copy the propertyset and return result...
393 XPropertySet_t
xNewBinding(pBinding
);
394 copy( xBinding
, xNewBinding
);
398 void Model::removeBindingIfUseless( const XPropertySet_t
& xBinding
)
399 throw( RuntimeException
, std::exception
)
401 Binding
* pBinding
= Binding::getBinding( xBinding
);
402 if( pBinding
!= NULL
)
404 if( ! pBinding
->isUseful() )
405 mpBindings
->removeItem( pBinding
);
409 Model::XDocument_t
Model::newInstance( const OUString
& sName
,
410 const OUString
& sURL
,
412 throw( RuntimeException
, std::exception
)
414 // create a default instance with <instanceData> element
415 XDocument_t xInstance
= getDocumentBuilder()->newDocument();
416 DBG_ASSERT( xInstance
.is(), "failed to create DOM instance" );
418 Reference
<XNode
>( xInstance
, UNO_QUERY_THROW
)->appendChild(
419 Reference
<XNode
>( xInstance
->createElement( "instanceData" ),
422 Sequence
<PropertyValue
> aSequence
;
423 bool bOnce
= bURLOnce
; // bool, so we can take address in setInstanceData
424 setInstanceData( aSequence
, &sName
, &xInstance
, &sURL
, &bOnce
);
425 sal_Int32 nInstance
= mpInstances
->addItem( aSequence
);
426 loadInstance( nInstance
);
431 static sal_Int32
lcl_findProp( const PropertyValue
* pValues
,
433 const OUString
& rName
)
437 for( ; !bFound
&& n
< nLength
; n
++ )
439 bFound
= ( pValues
[n
].Name
== rName
);
441 return bFound
? ( n
- 1) : -1;
444 sal_Int32
xforms::lcl_findInstance( const InstanceCollection
* pInstances
,
445 const OUString
& rName
)
447 sal_Int32 nLength
= pInstances
->countItems();
450 for( ; !bFound
&& n
< nLength
; n
++ )
453 getInstanceData( pInstances
->getItem( n
), &sName
, NULL
, NULL
, NULL
);
454 bFound
= ( sName
== rName
);
456 return bFound
? ( n
- 1 ) : -1;
459 void Model::renameInstance( const OUString
& sFrom
,
461 const OUString
& sURL
,
463 throw( RuntimeException
, std::exception
)
465 sal_Int32 nPos
= lcl_findInstance( mpInstances
, sFrom
);
468 Sequence
<PropertyValue
> aSeq
= mpInstances
->getItem( nPos
);
469 PropertyValue
* pSeq
= aSeq
.getArray();
470 sal_Int32 nLength
= aSeq
.getLength();
472 sal_Int32 nProp
= lcl_findProp( pSeq
, nLength
, "ID" );
476 aSeq
.realloc( nLength
+ 1 );
477 pSeq
= aSeq
.getArray();
478 pSeq
[ nLength
].Name
= "ID";
483 pSeq
[ nProp
].Value
<<= sTo
;
486 nProp
= lcl_findProp( pSeq
, nLength
, "URL" );
488 pSeq
[ nProp
].Value
<<= sURL
;
491 nProp
= lcl_findProp( pSeq
, nLength
, "URLOnce" );
493 pSeq
[ nProp
].Value
<<= bURLOnce
;
496 mpInstances
->setItem( nPos
, aSeq
);
500 void Model::removeInstance( const OUString
& sName
)
501 throw( RuntimeException
, std::exception
)
503 sal_Int32 nPos
= lcl_findInstance( mpInstances
, sName
);
505 mpInstances
->removeItem( mpInstances
->getItem( nPos
) );
508 static Reference
<XNameContainer
> lcl_getModels(
509 const Reference
<com::sun::star::frame::XModel
>& xComponent
)
511 Reference
<XNameContainer
> xRet
;
512 Reference
<XFormsSupplier
> xSupplier( xComponent
, UNO_QUERY
);
515 xRet
= xSupplier
->getXForms();
520 Model::XModel_t
Model::newModel( const Reference
<com::sun::star::frame::XModel
>& xCmp
,
521 const OUString
& sName
)
522 throw( RuntimeException
, std::exception
)
524 Model::XModel_t xModel
;
525 Reference
<XNameContainer
> xModels
= lcl_getModels( xCmp
);
527 && ! xModels
->hasByName( sName
) )
529 Model
* pModel
= new Model();
530 xModel
.set( pModel
);
532 pModel
->setID( sName
);
533 pModel
->newInstance( OUString(), OUString(), sal_False
);
534 pModel
->initialize();
535 xModels
->insertByName( sName
, makeAny( xModel
) );
541 void Model::renameModel( const Reference
<com::sun::star::frame::XModel
>& xCmp
,
542 const OUString
& sFrom
,
543 const OUString
& sTo
)
544 throw( RuntimeException
, std::exception
)
546 Reference
<XNameContainer
> xModels
= lcl_getModels( xCmp
);
548 && xModels
->hasByName( sFrom
)
549 && ! xModels
->hasByName( sTo
) )
551 Reference
<XModel
> xModel( xModels
->getByName( sFrom
), UNO_QUERY
);
552 xModel
->setID( sTo
);
553 xModels
->insertByName( sTo
, makeAny( xModel
) );
554 xModels
->removeByName( sFrom
);
558 void Model::removeModel( const Reference
<com::sun::star::frame::XModel
>& xCmp
,
559 const OUString
& sName
)
560 throw( RuntimeException
, std::exception
)
562 Reference
<XNameContainer
> xModels
= lcl_getModels( xCmp
);
564 && xModels
->hasByName( sName
) )
566 xModels
->removeByName( sName
);
570 Model::XNode_t
Model::createElement( const XNode_t
& xParent
,
571 const OUString
& sName
)
572 throw( RuntimeException
, std::exception
)
574 Reference
<XNode
> xNode
;
576 && isValidXMLName( sName
) )
578 // TODO: implement proper namespace handling
579 xNode
.set( xParent
->getOwnerDocument()->createElement( sName
),
585 Model::XNode_t
Model::createAttribute( const XNode_t
& xParent
,
586 const OUString
& sName
)
587 throw( RuntimeException
, std::exception
)
589 Reference
<XNode
> xNode
;
590 Reference
<XElement
> xElement( xParent
, UNO_QUERY
);
593 && isValidXMLName( sName
) )
595 // handle case where attribute already exists
596 sal_Int32 nCount
= 0;
597 OUString sUniqueName
= sName
;
598 while( xElement
->hasAttribute( sUniqueName
) )
601 sUniqueName
= sName
+ OUString::number( nCount
);
604 // TODO: implement proper namespace handling
605 xNode
.set( xParent
->getOwnerDocument()->createAttribute( sUniqueName
),
611 Model::XNode_t
Model::renameNode( const XNode_t
& xNode
,
612 const OUString
& sName
)
613 throw( RuntimeException
, std::exception
)
615 // early out if we don't have to change the name
616 if( xNode
->getNodeName() == sName
)
619 // refuse to change name if its an attribute, and the name is already used
620 if( xNode
->getNodeType() == NodeType_ATTRIBUTE_NODE
621 && xNode
->getParentNode().is()
622 && Reference
<XElement
>(xNode
->getParentNode(), UNO_QUERY_THROW
)->hasAttribute( sName
) )
625 // note old binding expression so we can adjust bindings below
626 OUString sOldDefaultBindingExpression
=
627 getDefaultBindingExpressionForNode( xNode
);
629 Reference
<XDocument
> xDoc
= xNode
->getOwnerDocument();
630 Reference
<XNode
> xNew
;
631 if( xNode
->getNodeType() == NodeType_ELEMENT_NODE
)
633 Reference
<XElement
> xElem
= xDoc
->createElement( sName
);
634 xNew
.set( xElem
, UNO_QUERY
);
636 // iterate over all attributes and append them to the new element
637 Reference
<XElement
> xOldElem( xNode
, UNO_QUERY
);
638 OSL_ENSURE( xNode
.is(), "no element?" );
640 Reference
<XNamedNodeMap
> xMap
= xNode
->getAttributes();
641 sal_Int32 nLength
= xMap
.is() ? xMap
->getLength() : 0;
642 for( sal_Int32 n
= 0; n
< nLength
; n
++ )
644 Reference
<XAttr
> xAttr( xMap
->item(n
), UNO_QUERY
);
645 xElem
->setAttributeNode( xOldElem
->removeAttributeNode( xAttr
) );
648 // iterate over all children and append them to the new element
649 for( Reference
<XNode
> xCurrent
= xNode
->getFirstChild();
651 xCurrent
= xNode
->getFirstChild() )
653 xNew
->appendChild( xNode
->removeChild( xCurrent
) );
656 xNode
->getParentNode()->replaceChild( xNew
, xNode
);
658 else if( xNode
->getNodeType() == NodeType_ATTRIBUTE_NODE
)
660 // create new attribute
661 Reference
<XAttr
> xAttr
= xDoc
->createAttribute( sName
);
662 xAttr
->setValue( xNode
->getNodeValue() );
665 Reference
<XNode
> xParent
= xNode
->getParentNode();
666 xParent
->removeChild( xNode
);
667 xNew
= xParent
->appendChild( xAttr
);
671 OSL_FAIL( "can't rename this node type" );
674 // adjust bindings (if necessary):
677 // iterate over bindings and replace default expressions
678 OUString sNewDefaultBindingExpression
=
679 getDefaultBindingExpressionForNode( xNew
);
680 for( sal_Int32 n
= 0; n
< mpBindings
->countItems(); n
++ )
682 Binding
* pBinding
= Binding::getBinding(
683 mpBindings
->Collection
<XPropertySet_t
>::getItem( n
) );
685 if( pBinding
->getBindingExpression()
686 == sOldDefaultBindingExpression
)
687 pBinding
->setBindingExpression( sNewDefaultBindingExpression
);
691 // return node; return old node if renaming failed
692 return xNew
.is() ? xNew
: xNode
;
695 Model::XPropertySet_t
Model::getBindingForNode( const XNode_t
& xNode
,
697 throw( RuntimeException
, std::exception
)
699 OSL_ENSURE( xNode
.is(), "no node?" );
701 // We will iterate over all bindings and determine the
702 // appropriateness of the respective binding for this node. The
703 // best one will be used. If we don't find any and bCreate is set,
704 // then we will create a suitable binding.
705 Binding
* pBestBinding
= NULL
;
706 sal_Int32 nBestScore
= 0;
708 for( sal_Int32 n
= 0; n
< mpBindings
->countItems(); n
++ )
710 Binding
* pBinding
= Binding::getBinding(
711 mpBindings
->Collection
<XPropertySet_t
>::getItem( n
) );
713 OSL_ENSURE( pBinding
!= NULL
, "no binding?" );
714 Reference
<XNodeList
> xNodeList
= pBinding
->getXNodeList();
716 sal_Int32 nNodes
= xNodeList
.is() ? xNodeList
->getLength() : 0;
717 if( nNodes
> 0 && xNodeList
->item( 0 ) == xNode
)
719 // allright, we found a suitable node. Let's determine how
720 // well it fits. Score:
721 // - bind to exactly this node is better than whole nodeset
722 // - simple binding expressions is better than complex ones
723 sal_Int32 nScore
= 0;
726 if( pBinding
->isSimpleBindingExpression() )
729 // if we found a better binding, remember it
730 if( nScore
> nBestScore
)
732 pBestBinding
= pBinding
;
738 // create binding, if none was found and bCreate is set
739 OSL_ENSURE( ( nBestScore
== 0 ) == ( pBestBinding
== NULL
),
740 "score != binding?" );
741 if( bCreate
&& pBestBinding
== NULL
)
743 pBestBinding
= new Binding();
744 pBestBinding
->setBindingExpression(
745 getDefaultBindingExpressionForNode( xNode
) );
746 mpBindings
->addItem( pBestBinding
);
752 void Model::removeBindingForNode( const XNode_t
& )
753 throw( RuntimeException
, std::exception
)
755 // determine whether suitable binding is still used
758 static OUString
lcl_serializeForDisplay( const Reference
< XAttr
>& _rxAttrNode
)
761 OSL_ENSURE( _rxAttrNode
.is(), "lcl_serializeForDisplay( attr ): invalid argument!" );
762 if ( _rxAttrNode
.is() )
764 OUString sValue
= _rxAttrNode
->getValue();
765 sal_Unicode nQuote
= '"';
766 if ( sValue
.indexOf( nQuote
) >= 0 )
769 sResult
= _rxAttrNode
->getName() + "=" + OUString(nQuote
) + sValue
+ OUString(nQuote
) + " ";
774 static OUString
lcl_serializeForDisplay( const Reference
<XNodeList
>& xNodes
)
778 // create document fragment
779 Reference
<XDocument
> xDocument( getDocumentBuilder()->newDocument() );
780 Reference
<XDocumentFragment
> xFragment(
781 xDocument
->createDocumentFragment() );
782 OSL_ENSURE( xFragment
.is(), "xFragment" );
784 sal_Int32 nAttributeNodes
= 0;
786 // attach nodelist to fragment
787 sal_Int32 nLength
= xNodes
->getLength();
788 for( sal_Int32 i
= 0; i
< nLength
; i
++ )
790 Reference
<XNode
> xCurrent
= xNodes
->item( i
);
792 switch ( xCurrent
->getNodeType() )
794 case NodeType_DOCUMENT_NODE
:
795 // special-case documents: use top-level element instead
796 xCurrent
= xCurrent
->getFirstChild();
798 case NodeType_ATTRIBUTE_NODE
:
800 Reference
< XAttr
> xAttr( xCurrent
, UNO_QUERY
);
803 sResult
+= lcl_serializeForDisplay( xAttr
);
814 xFragment
->appendChild( xDocument
->importNode( xCurrent
, sal_True
) );
816 OSL_ENSURE( ( nAttributeNodes
== 0 ) || ( nAttributeNodes
== nLength
),
817 "lcl_serializeForDisplay: mixed attribute and non-attribute nodes?" );
818 if ( nAttributeNodes
)
819 // had only attribute nodes
822 // serialize fragment
823 CSerializationAppXML aSerialization
;
824 aSerialization
.setSource( xFragment
);
825 aSerialization
.serialize();
827 // copy stream into buffer
828 Reference
<XTextInputStream2
> xTextInputStream
= TextInputStream::create( comphelper::getProcessComponentContext() );
829 xTextInputStream
->setInputStream( aSerialization
.getInputStream() );
831 /* WORK AROUND for problem in serialization: currently, multiple
832 XML delarations (<?xml...?>) are being written out and we don't
833 want them. When this is fixed, the code below is nice and
834 simple. The current code filters out the declarations.
835 OUString sResult = xTextInputStream->readString( Sequence<sal_Unicode>(),
839 // well, the serialization prepends XML header(s) that we need to
841 OUStringBuffer aBuffer
;
842 while( ! xTextInputStream
->isEOF() )
844 OUString sLine
= xTextInputStream
->readLine();
846 && !sLine
.startsWith( "<?xml" ) )
848 aBuffer
.append( sLine
);
849 aBuffer
.append( '\n' );
852 sResult
= aBuffer
.makeStringAndClear();
857 static OUString
lcl_serializeForDisplay( const Reference
<XXPathObject
>& xResult
)
859 // error handling first
861 return getResource( RID_STR_XFORMS_CANT_EVALUATE
);
865 OUStringBuffer aBuffer
;
867 switch( xResult
->getObjectType() )
869 case XPathObjectType_XPATH_BOOLEAN
:
870 aBuffer
.append( xResult
->getBoolean()
872 : OUString("false") );
875 case XPathObjectType_XPATH_STRING
:
876 aBuffer
= aBuffer
+ "\"" + xResult
->getString() + "\"";
879 case XPathObjectType_XPATH_NODESET
:
880 aBuffer
.append( lcl_serializeForDisplay( xResult
->getNodeList() ) );
883 case XPathObjectType_XPATH_NUMBER
:
884 aBuffer
.append( xResult
->getDouble() );
887 case XPathObjectType_XPATH_UNDEFINED
:
888 case XPathObjectType_XPATH_POINT
:
889 case XPathObjectType_XPATH_RANGE
:
890 case XPathObjectType_XPATH_LOCATIONSET
:
891 case XPathObjectType_XPATH_USERS
:
892 case XPathObjectType_XPATH_XSLT_TREE
:
894 // TODO: localized error message?
898 return aBuffer
.makeStringAndClear();
901 OUString
Model::getResultForExpression(
902 const XPropertySet_t
& xBinding
,
903 sal_Bool bIsBindingExpression
,
904 const OUString
& sExpression
)
905 throw( RuntimeException
, std::exception
)
907 Binding
* pBinding
= Binding::getBinding( xBinding
);
908 if( pBinding
== NULL
)
909 throw RuntimeException();
911 // prepare & evaluate expression
912 OUStringBuffer aBuffer
;
913 ComputedExpression aExpression
;
914 aExpression
.setExpression( sExpression
);
915 if( bIsBindingExpression
)
917 // binding: use binding context and evaluation
918 aExpression
.evaluate( pBinding
->getEvaluationContext() );
919 aBuffer
.append( lcl_serializeForDisplay( aExpression
.getXPath() ) );
923 // MIP (not binding): iterate over bindings contexts
924 std::vector
<EvaluationContext
> aContext
=
925 pBinding
->getMIPEvaluationContexts();
926 for( std::vector
<EvaluationContext
>::iterator aIter
= aContext
.begin();
927 aIter
!= aContext
.end();
930 aExpression
.evaluate( *aIter
);
931 aBuffer
.append( lcl_serializeForDisplay(aExpression
.getXPath()) );
932 aBuffer
.append( '\n' );
935 return aBuffer
.makeStringAndClear();
938 sal_Bool
Model::isValidXMLName( const OUString
& sName
)
939 throw( RuntimeException
, std::exception
)
941 return isValidQName( sName
, NULL
);
944 sal_Bool
Model::isValidPrefixName( const OUString
& sName
)
945 throw( RuntimeException
, std::exception
)
947 return ::isValidPrefixName( sName
, NULL
);
950 void Model::setNodeValue(
951 const XNode_t
& xNode
,
952 const OUString
& sValue
)
953 throw( RuntimeException
, std::exception
)
955 setSimpleContent( xNode
, sValue
);
960 // helper functions from model_helper.hxx
963 void xforms::getInstanceData(
964 const Sequence
<PropertyValue
>& aValues
,
966 Reference
<XDocument
>* pInstance
,
970 sal_Int32 nValues
= aValues
.getLength();
971 const PropertyValue
* pValues
= aValues
.getConstArray();
972 for( sal_Int32 n
= 0; n
< nValues
; n
++ )
974 const PropertyValue
& rValue
= pValues
[n
];
976 if( p##NAME != NULL && \
977 rValue.Name == #NAME ) \
978 rValue.Value >>= (*p##NAME)
987 void xforms::setInstanceData(
988 Sequence
<PropertyValue
>& aSequence
,
989 const OUString
* _pID
,
990 const Reference
<XDocument
>* _pInstance
,
991 const OUString
* _pURL
,
992 const bool* _pURLOnce
)
994 // get old instance data
996 Reference
<XDocument
> xInstance
;
998 bool bURLOnce
= false;
999 getInstanceData( aSequence
, &sID
, &xInstance
, &sURL
, &bURLOnce
);
1000 const OUString
* pID
= !sID
.isEmpty() ? &sID
: NULL
;
1001 const Reference
<XDocument
>* pInstance
= xInstance
.is() ? &xInstance
: NULL
;
1002 const OUString
* pURL
= !sURL
.isEmpty() ? &sURL
: NULL
;
1003 const bool* pURLOnce
= ( bURLOnce
&& pURL
!= NULL
) ? &bURLOnce
: NULL
;
1005 // determine new instance data
1006 #define PROP(NAME) if( _p##NAME != NULL ) p##NAME = _p##NAME
1013 // count # of values we want to set
1014 sal_Int32 nCount
= 0;
1015 #define PROP(NAME) if( p##NAME != NULL ) nCount++
1022 // realloc sequence and enter values;
1023 aSequence
.realloc( nCount
);
1024 PropertyValue
* pSequence
= aSequence
.getArray();
1025 sal_Int32 nIndex
= 0;
1026 #define PROP(NAME) \
1027 if( p##NAME != NULL ) \
1029 pSequence[ nIndex ].Name = #NAME; \
1030 pSequence[ nIndex ].Value <<= *p##NAME; \
1040 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */