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
)
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, sal_Unicode(']') );
156 rBuffer
.insert( 0, nPosition
);
157 rBuffer
.insert( 0, sal_Unicode('[') );
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, sal_Unicode(':') );
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
.getLength() > 0 )
223 aBuffer
.insert( 0, sal_Unicode('/') );
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, sal_Unicode('@') );
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, sal_Unicode('/') );
258 return aBuffer
.makeStringAndClear();
263 OUString
Model::getDefaultBindingExpressionForNode( const XNode_t
& xNode
)
264 throw( RuntimeException
)
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
)
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
.append( sal_Unicode('"') );
304 aBuffer
.append( Convert::collapseWhitespace( sContent
) );
305 aBuffer
.append( sal_Unicode('"') );
310 case NodeType_ATTRIBUTE_NODE
:
311 lcl_OutName( aBuffer
, xNode
);
312 aBuffer
.insert( 0, sal_Unicode('@') );
315 case NodeType_DOCUMENT_NODE
:
316 if( xNode
== getDefaultInstance() )
317 aBuffer
.append( sal_Unicode('/') );
319 lcl_OutInstance( aBuffer
, xNode
, this );
323 // unknown type? fail!
324 OSL_FAIL( "unknown node type!" );
328 return aBuffer
.makeStringAndClear();
331 OUString
Model::getNodeName( const XNode_t
& xNode
)
332 throw( RuntimeException
)
334 OUStringBuffer aBuffer
;
336 switch( xNode
->getNodeType() )
338 case NodeType_ELEMENT_NODE
:
339 case NodeType_ATTRIBUTE_NODE
:
340 lcl_OutName( aBuffer
, xNode
);
343 case NodeType_TEXT_NODE
:
344 case NodeType_DOCUMENT_NODE
:
346 // unknown type? fail!
347 OSL_FAIL( "no name for this node type!" );
351 return aBuffer
.makeStringAndClear();
354 OUString
Model::getBindingName( const XPropertySet_t
& xBinding
,
355 sal_Bool
/*bDetail*/ )
356 throw( RuntimeException
)
359 xBinding
->getPropertyValue( "BindingID" ) >>= sID
;
360 OUString sExpression
;
361 xBinding
->getPropertyValue( "BindingExpression" ) >>= sExpression
;
363 OUStringBuffer aBuffer
;
366 aBuffer
.append( sID
);
367 aBuffer
.append( " (" );
368 aBuffer
.append( sExpression
);
369 aBuffer
.append( ")" );
372 aBuffer
.append( sExpression
);
374 return aBuffer
.makeStringAndClear();
377 OUString
Model::getSubmissionName( const XPropertySet_t
& xSubmission
,
378 sal_Bool
/*bDetail*/ )
379 throw( RuntimeException
)
382 xSubmission
->getPropertyValue( "ID" ) >>= sID
;
386 Model::XPropertySet_t
Model::cloneBindingAsGhost( const XPropertySet_t
&xBinding
)
387 throw( RuntimeException
)
389 // Create a new binding instance first...
390 Binding
*pBinding
= new Binding();
392 // ...and bump up the "defered notification counter"
393 // to prevent this binding from contributing to the
395 pBinding
->deferNotifications(true);
397 // Copy the propertyset and return result...
398 XPropertySet_t
xNewBinding(pBinding
);
399 copy( xBinding
, xNewBinding
);
403 void Model::removeBindingIfUseless( const XPropertySet_t
& xBinding
)
404 throw( RuntimeException
)
406 Binding
* pBinding
= Binding::getBinding( xBinding
);
407 if( pBinding
!= NULL
)
409 if( ! pBinding
->isUseful() )
410 mpBindings
->removeItem( pBinding
);
414 Model::XDocument_t
Model::newInstance( const OUString
& sName
,
415 const OUString
& sURL
,
417 throw( RuntimeException
)
419 // create a default instance with <instanceData> element
420 XDocument_t xInstance
= getDocumentBuilder()->newDocument();
421 DBG_ASSERT( xInstance
.is(), "failed to create DOM instance" );
423 Reference
<XNode
>( xInstance
, UNO_QUERY_THROW
)->appendChild(
424 Reference
<XNode
>( xInstance
->createElement( "instanceData" ),
427 Sequence
<PropertyValue
> aSequence
;
428 bool bOnce
= bURLOnce
; // bool, so we can take address in setInstanceData
429 setInstanceData( aSequence
, &sName
, &xInstance
, &sURL
, &bOnce
);
430 sal_Int32 nInstance
= mpInstances
->addItem( aSequence
);
431 loadInstance( nInstance
);
436 static sal_Int32
lcl_findProp( const PropertyValue
* pValues
,
438 const OUString
& rName
)
442 for( ; !bFound
&& n
< nLength
; n
++ )
444 bFound
= ( pValues
[n
].Name
== rName
);
446 return bFound
? ( n
- 1) : -1;
449 sal_Int32
xforms::lcl_findInstance( const InstanceCollection
* pInstances
,
450 const OUString
& rName
)
452 sal_Int32 nLength
= pInstances
->countItems();
455 for( ; !bFound
&& n
< nLength
; n
++ )
458 getInstanceData( pInstances
->getItem( n
), &sName
, NULL
, NULL
, NULL
);
459 bFound
= ( sName
== rName
);
461 return bFound
? ( n
- 1 ) : -1;
464 void Model::renameInstance( const OUString
& sFrom
,
466 const OUString
& sURL
,
468 throw( RuntimeException
)
470 sal_Int32 nPos
= lcl_findInstance( mpInstances
, sFrom
);
473 Sequence
<PropertyValue
> aSeq
= mpInstances
->getItem( nPos
);
474 PropertyValue
* pSeq
= aSeq
.getArray();
475 sal_Int32 nLength
= aSeq
.getLength();
477 sal_Int32 nProp
= lcl_findProp( pSeq
, nLength
, "ID" );
481 aSeq
.realloc( nLength
+ 1 );
482 pSeq
= aSeq
.getArray();
483 pSeq
[ nLength
].Name
= "ID";
488 pSeq
[ nProp
].Value
<<= sTo
;
491 nProp
= lcl_findProp( pSeq
, nLength
, "URL" );
493 pSeq
[ nProp
].Value
<<= sURL
;
496 nProp
= lcl_findProp( pSeq
, nLength
, "URLOnce" );
498 pSeq
[ nProp
].Value
<<= bURLOnce
;
501 mpInstances
->setItem( nPos
, aSeq
);
505 void Model::removeInstance( const OUString
& sName
)
506 throw( RuntimeException
)
508 sal_Int32 nPos
= lcl_findInstance( mpInstances
, sName
);
510 mpInstances
->removeItem( mpInstances
->getItem( nPos
) );
513 static Reference
<XNameContainer
> lcl_getModels(
514 const Reference
<com::sun::star::frame::XModel
>& xComponent
)
516 Reference
<XNameContainer
> xRet
;
517 Reference
<XFormsSupplier
> xSupplier( xComponent
, UNO_QUERY
);
520 xRet
= xSupplier
->getXForms();
525 Model::XModel_t
Model::newModel( const Reference
<com::sun::star::frame::XModel
>& xCmp
,
526 const OUString
& sName
)
527 throw( RuntimeException
)
529 Model::XModel_t xModel
;
530 Reference
<XNameContainer
> xModels
= lcl_getModels( xCmp
);
532 && ! xModels
->hasByName( sName
) )
534 Model
* pModel
= new Model();
535 xModel
.set( pModel
);
537 pModel
->setID( sName
);
538 pModel
->newInstance( OUString(), OUString(), sal_False
);
539 pModel
->initialize();
540 xModels
->insertByName( sName
, makeAny( xModel
) );
546 void Model::renameModel( const Reference
<com::sun::star::frame::XModel
>& xCmp
,
547 const OUString
& sFrom
,
548 const OUString
& sTo
)
549 throw( RuntimeException
)
551 Reference
<XNameContainer
> xModels
= lcl_getModels( xCmp
);
553 && xModels
->hasByName( sFrom
)
554 && ! xModels
->hasByName( sTo
) )
556 Reference
<XModel
> xModel( xModels
->getByName( sFrom
), UNO_QUERY
);
557 xModel
->setID( sTo
);
558 xModels
->insertByName( sTo
, makeAny( xModel
) );
559 xModels
->removeByName( sFrom
);
563 void Model::removeModel( const Reference
<com::sun::star::frame::XModel
>& xCmp
,
564 const OUString
& sName
)
565 throw( RuntimeException
)
567 Reference
<XNameContainer
> xModels
= lcl_getModels( xCmp
);
569 && xModels
->hasByName( sName
) )
571 xModels
->removeByName( sName
);
575 Model::XNode_t
Model::createElement( const XNode_t
& xParent
,
576 const OUString
& sName
)
577 throw( RuntimeException
)
579 Reference
<XNode
> xNode
;
581 && isValidXMLName( sName
) )
583 // TODO: implement proper namespace handling
584 xNode
.set( xParent
->getOwnerDocument()->createElement( sName
),
590 Model::XNode_t
Model::createAttribute( const XNode_t
& xParent
,
591 const OUString
& sName
)
592 throw( RuntimeException
)
594 Reference
<XNode
> xNode
;
595 Reference
<XElement
> xElement( xParent
, UNO_QUERY
);
598 && isValidXMLName( sName
) )
600 // handle case where attribute already exists
601 sal_Int32 nCount
= 0;
602 OUString sUniqueName
= sName
;
603 while( xElement
->hasAttribute( sUniqueName
) )
606 sUniqueName
= sName
+ OUString::valueOf( nCount
);
609 // TODO: implement proper namespace handling
610 xNode
.set( xParent
->getOwnerDocument()->createAttribute( sUniqueName
),
616 Model::XNode_t
Model::renameNode( const XNode_t
& xNode
,
617 const OUString
& sName
)
618 throw( RuntimeException
)
620 // early out if we don't have to change the name
621 if( xNode
->getNodeName() == sName
)
624 // refuse to change name if its an attribute, and the name is already used
625 if( xNode
->getNodeType() == NodeType_ATTRIBUTE_NODE
626 && xNode
->getParentNode().is()
627 && Reference
<XElement
>(xNode
->getParentNode(), UNO_QUERY_THROW
)->hasAttribute( sName
) )
630 // note old binding expression so we can adjust bindings below
631 OUString sOldDefaultBindingExpression
=
632 getDefaultBindingExpressionForNode( xNode
);
634 Reference
<XDocument
> xDoc
= xNode
->getOwnerDocument();
635 Reference
<XNode
> xNew
;
636 if( xNode
->getNodeType() == NodeType_ELEMENT_NODE
)
638 Reference
<XElement
> xElem
= xDoc
->createElement( sName
);
639 xNew
.set( xElem
, UNO_QUERY
);
641 // iterate over all attributes and append them to the new element
642 Reference
<XElement
> xOldElem( xNode
, UNO_QUERY
);
643 OSL_ENSURE( xNode
.is(), "no element?" );
645 Reference
<XNamedNodeMap
> xMap
= xNode
->getAttributes();
646 sal_Int32 nLength
= xMap
.is() ? xMap
->getLength() : 0;
647 for( sal_Int32 n
= 0; n
< nLength
; n
++ )
649 Reference
<XAttr
> xAttr( xMap
->item(n
), UNO_QUERY
);
650 xElem
->setAttributeNode( xOldElem
->removeAttributeNode( xAttr
) );
653 // iterate over all children and append them to the new element
654 for( Reference
<XNode
> xCurrent
= xNode
->getFirstChild();
656 xCurrent
= xNode
->getFirstChild() )
658 xNew
->appendChild( xNode
->removeChild( xCurrent
) );
661 xNode
->getParentNode()->replaceChild( xNew
, xNode
);
663 else if( xNode
->getNodeType() == NodeType_ATTRIBUTE_NODE
)
665 // create new attribute
666 Reference
<XAttr
> xAttr
= xDoc
->createAttribute( sName
);
667 xAttr
->setValue( xNode
->getNodeValue() );
670 Reference
<XNode
> xParent
= xNode
->getParentNode();
671 xParent
->removeChild( xNode
);
672 xNew
= xParent
->appendChild( Reference
<XNode
>( xAttr
, UNO_QUERY
) );
676 OSL_FAIL( "can't rename this node type" );
679 // adjust bindings (if necessary):
682 // iterate over bindings and replace default expressions
683 OUString sNewDefaultBindingExpression
=
684 getDefaultBindingExpressionForNode( xNew
);
685 for( sal_Int32 n
= 0; n
< mpBindings
->countItems(); n
++ )
687 Binding
* pBinding
= Binding::getBinding(
688 mpBindings
->Collection
<XPropertySet_t
>::getItem( n
) );
690 if( pBinding
->getBindingExpression()
691 == sOldDefaultBindingExpression
)
692 pBinding
->setBindingExpression( sNewDefaultBindingExpression
);
696 // return node; return old node if renaming failed
697 return xNew
.is() ? xNew
: xNode
;
700 Model::XPropertySet_t
Model::getBindingForNode( const XNode_t
& xNode
,
702 throw( RuntimeException
)
704 OSL_ENSURE( xNode
.is(), "no node?" );
706 // We will iterate over all bindings and determine the
707 // appropriateness of the respective binding for this node. The
708 // best one will be used. If we don't find any and bCreate is set,
709 // then we will create a suitable binding.
710 Binding
* pBestBinding
= NULL
;
711 sal_Int32 nBestScore
= 0;
713 for( sal_Int32 n
= 0; n
< mpBindings
->countItems(); n
++ )
715 Binding
* pBinding
= Binding::getBinding(
716 mpBindings
->Collection
<XPropertySet_t
>::getItem( n
) );
718 OSL_ENSURE( pBinding
!= NULL
, "no binding?" );
719 Reference
<XNodeList
> xNodeList
= pBinding
->getXNodeList();
721 sal_Int32 nNodes
= xNodeList
.is() ? xNodeList
->getLength() : 0;
722 if( nNodes
> 0 && xNodeList
->item( 0 ) == xNode
)
724 // allright, we found a suitable node. Let's determine how
725 // well it fits. Score:
726 // - bind to exactly this node is better than whole nodeset
727 // - simple binding expressions is better than complex ones
728 sal_Int32 nScore
= 0;
731 if( pBinding
->isSimpleBindingExpression() )
734 // if we found a better binding, remember it
735 if( nScore
> nBestScore
)
737 pBestBinding
= pBinding
;
743 // create binding, if none was found and bCreate is set
744 OSL_ENSURE( ( nBestScore
== 0 ) == ( pBestBinding
== NULL
),
745 "score != binding?" );
746 if( bCreate
&& pBestBinding
== NULL
)
748 pBestBinding
= new Binding();
749 pBestBinding
->setBindingExpression(
750 getDefaultBindingExpressionForNode( xNode
) );
751 mpBindings
->addItem( pBestBinding
);
757 void Model::removeBindingForNode( const XNode_t
& )
758 throw( RuntimeException
)
760 // determine whether suitable binding is still used
763 static OUString
lcl_serializeForDisplay( const Reference
< XAttr
>& _rxAttrNode
)
766 OSL_ENSURE( _rxAttrNode
.is(), "lcl_serializeForDisplay( attr ): invalid argument!" );
767 if ( _rxAttrNode
.is() )
769 OUStringBuffer aBuffer
;
770 aBuffer
.append( _rxAttrNode
->getName() );
771 aBuffer
.appendAscii( "=" );
772 OUString sValue
= _rxAttrNode
->getValue();
773 sal_Unicode nQuote
= '"';
774 if ( sValue
.indexOf( nQuote
) >= 0 )
776 aBuffer
.append( nQuote
);
777 aBuffer
.append( sValue
);
778 aBuffer
.append( nQuote
);
779 aBuffer
.append( (sal_Unicode
)' ' );
780 sResult
= aBuffer
.makeStringAndClear();
785 static OUString
lcl_serializeForDisplay( const Reference
<XNodeList
>& xNodes
)
789 // create document fragment
790 Reference
<XDocument
> xDocument( getDocumentBuilder()->newDocument() );
791 Reference
<XDocumentFragment
> xFragment(
792 xDocument
->createDocumentFragment() );
793 Reference
<XNode
> xNode( xFragment
, UNO_QUERY
);
794 OSL_ENSURE( xFragment
.is(), "xFragment" );
795 OSL_ENSURE( xNode
.is(), "xNode" );
797 sal_Int32 nAttributeNodes
= 0;
799 // attach nodelist to fragment
800 sal_Int32 nLength
= xNodes
->getLength();
801 for( sal_Int32 i
= 0; i
< nLength
; i
++ )
803 Reference
<XNode
> xCurrent
= xNodes
->item( i
);
805 switch ( xCurrent
->getNodeType() )
807 case NodeType_DOCUMENT_NODE
:
808 // special-case documents: use top-level element instead
809 xCurrent
= xCurrent
->getFirstChild();
811 case NodeType_ATTRIBUTE_NODE
:
813 Reference
< XAttr
> xAttr( xCurrent
, UNO_QUERY
);
816 sResult
+= lcl_serializeForDisplay( xAttr
);
827 xNode
->appendChild( xDocument
->importNode( xCurrent
, sal_True
) );
829 OSL_ENSURE( ( nAttributeNodes
== 0 ) || ( nAttributeNodes
== nLength
),
830 "lcl_serializeForDisplay: mixed attribute and non-attribute nodes?" );
831 if ( nAttributeNodes
)
832 // had only attribute nodes
835 // serialize fragment
836 CSerializationAppXML aSerialization
;
837 aSerialization
.setSource( xFragment
);
838 aSerialization
.serialize();
840 // copy stream into buffer
841 Reference
<XTextInputStream2
> xTextInputStream
= TextInputStream::create( comphelper::getProcessComponentContext() );
842 xTextInputStream
->setInputStream( aSerialization
.getInputStream() );
844 /* WORK AROUND for problem in serialization: currently, multiple
845 XML delarations (<?xml...?>) are being written out and we don't
846 want them. When this is fixed, the code below is nice and
847 simple. The current code filters out the declarations.
848 OUString sResult = xTextInputStream->readString( Sequence<sal_Unicode>(),
852 // well, the serialization prepends XML header(s) that we need to
854 OUStringBuffer aBuffer
;
855 while( ! xTextInputStream
->isEOF() )
857 OUString sLine
= xTextInputStream
->readLine();
859 && !sLine
.startsWith( "<?xml" ) )
861 aBuffer
.append( sLine
);
862 aBuffer
.append( sal_Unicode('\n') );
865 sResult
= aBuffer
.makeStringAndClear();
870 static OUString
lcl_serializeForDisplay( const Reference
<XXPathObject
>& xResult
)
872 // error handling first
874 return getResource( RID_STR_XFORMS_CANT_EVALUATE
);
878 OUStringBuffer aBuffer
;
880 switch( xResult
->getObjectType() )
882 case XPathObjectType_XPATH_BOOLEAN
:
883 aBuffer
.append( xResult
->getBoolean()
885 : OUString("false") );
888 case XPathObjectType_XPATH_STRING
:
889 aBuffer
.append( sal_Unicode('"') );
890 aBuffer
.append( xResult
->getString() );
891 aBuffer
.append( sal_Unicode('"') );
894 case XPathObjectType_XPATH_NODESET
:
895 aBuffer
.append( lcl_serializeForDisplay( xResult
->getNodeList() ) );
898 case XPathObjectType_XPATH_NUMBER
:
899 aBuffer
.append( xResult
->getDouble() );
902 case XPathObjectType_XPATH_UNDEFINED
:
903 case XPathObjectType_XPATH_POINT
:
904 case XPathObjectType_XPATH_RANGE
:
905 case XPathObjectType_XPATH_LOCATIONSET
:
906 case XPathObjectType_XPATH_USERS
:
907 case XPathObjectType_XPATH_XSLT_TREE
:
909 // TODO: localized error message?
913 return aBuffer
.makeStringAndClear();
916 OUString
Model::getResultForExpression(
917 const XPropertySet_t
& xBinding
,
918 sal_Bool bIsBindingExpression
,
919 const OUString
& sExpression
)
920 throw( RuntimeException
)
922 Binding
* pBinding
= Binding::getBinding( xBinding
);
923 if( pBinding
== NULL
)
924 throw RuntimeException();
926 // prepare & evaluate expression
927 OUStringBuffer aBuffer
;
928 ComputedExpression aExpression
;
929 aExpression
.setExpression( sExpression
);
930 if( bIsBindingExpression
)
932 // binding: use binding context and evaluation
933 aExpression
.evaluate( pBinding
->getEvaluationContext() );
934 aBuffer
.append( lcl_serializeForDisplay( aExpression
.getXPath() ) );
938 // MIP (not binding): iterate over bindings contexts
939 std::vector
<EvaluationContext
> aContext
=
940 pBinding
->getMIPEvaluationContexts();
941 for( std::vector
<EvaluationContext
>::iterator aIter
= aContext
.begin();
942 aIter
!= aContext
.end();
945 aExpression
.evaluate( *aIter
);
946 aBuffer
.append( lcl_serializeForDisplay(aExpression
.getXPath()) );
947 aBuffer
.append( sal_Unicode('\n') );
950 return aBuffer
.makeStringAndClear();
953 sal_Bool
Model::isValidXMLName( const OUString
& sName
)
954 throw( RuntimeException
)
956 return isValidQName( sName
, NULL
);
959 sal_Bool
Model::isValidPrefixName( const OUString
& sName
)
960 throw( RuntimeException
)
962 return ::isValidPrefixName( sName
, NULL
);
965 void Model::setNodeValue(
966 const XNode_t
& xNode
,
967 const OUString
& sValue
)
968 throw( RuntimeException
)
970 setSimpleContent( xNode
, sValue
);
975 // helper functions from model_helper.hxx
978 void xforms::getInstanceData(
979 const Sequence
<PropertyValue
>& aValues
,
981 Reference
<XDocument
>* pInstance
,
985 sal_Int32 nValues
= aValues
.getLength();
986 const PropertyValue
* pValues
= aValues
.getConstArray();
987 for( sal_Int32 n
= 0; n
< nValues
; n
++ )
989 const PropertyValue
& rValue
= pValues
[n
];
991 if( p##NAME != NULL && \
992 rValue.Name == #NAME ) \
993 rValue.Value >>= (*p##NAME)
1002 void xforms::setInstanceData(
1003 Sequence
<PropertyValue
>& aSequence
,
1004 const OUString
* _pID
,
1005 const Reference
<XDocument
>* _pInstance
,
1006 const OUString
* _pURL
,
1007 const bool* _pURLOnce
)
1009 // get old instance data
1011 Reference
<XDocument
> xInstance
;
1013 bool bURLOnce
= false;
1014 getInstanceData( aSequence
, &sID
, &xInstance
, &sURL
, &bURLOnce
);
1015 const OUString
* pID
= !sID
.isEmpty() ? &sID
: NULL
;
1016 const Reference
<XDocument
>* pInstance
= xInstance
.is() ? &xInstance
: NULL
;
1017 const OUString
* pURL
= !sURL
.isEmpty() ? &sURL
: NULL
;
1018 const bool* pURLOnce
= ( bURLOnce
&& pURL
!= NULL
) ? &bURLOnce
: NULL
;
1020 // determine new instance data
1021 #define PROP(NAME) if( _p##NAME != NULL ) p##NAME = _p##NAME
1028 // count # of values we want to set
1029 sal_Int32 nCount
= 0;
1030 #define PROP(NAME) if( p##NAME != NULL ) nCount++
1037 // realloc sequence and enter values;
1038 aSequence
.realloc( nCount
);
1039 PropertyValue
* pSequence
= aSequence
.getArray();
1040 sal_Int32 nIndex
= 0;
1041 #define PROP(NAME) \
1042 if( p##NAME != NULL ) \
1044 pSequence[ nIndex ].Name = OUString(#NAME); \
1045 pSequence[ nIndex ].Value <<= *p##NAME; \
1055 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */