1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: model_ui.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_forms.hxx"
35 #include "model_helper.hxx"
37 #include "evaluationcontext.hxx"
38 #include "unohelper.hxx"
39 #include "submission/serialization_app_xml.hxx"
40 #include "resourcehelper.hxx"
41 #include "xmlhelper.hxx"
42 #include "convert.hxx"
44 #include <rtl/ustring.hxx>
45 #include <rtl/ustrbuf.hxx>
46 #include <tools/debug.hxx>
49 #include <com/sun/star/xml/dom/XNode.hpp>
50 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
51 #include <com/sun/star/xml/dom/XDocumentFragment.hpp>
52 #include <com/sun/star/xml/dom/XNamedNodeMap.hpp>
53 #include <com/sun/star/xml/xpath/XXPathObject.hpp>
54 #include <com/sun/star/xml/xpath/XPathObjectType.hpp>
55 #include <com/sun/star/beans/PropertyValue.hpp>
56 #include <com/sun/star/io/XInputStream.hpp>
57 #include <com/sun/star/io/XActiveDataSink.hpp>
58 #include <com/sun/star/io/XTextInputStream.hpp>
59 #include <com/sun/star/container/XEnumeration.hpp>
60 #include <com/sun/star/container/XNameContainer.hpp>
61 #include <com/sun/star/frame/XModel.hpp>
62 #include <com/sun/star/xforms/XFormsSupplier.hpp>
63 #include <com/sun/star/xforms/XDataTypeRepository.hpp>
64 #include <com/sun/star/xsd/XDataType.hpp>
65 #include <com/sun/star/xsd/DataTypeClass.hpp>
69 using rtl::OUStringBuffer
;
70 using com::sun::star::beans::PropertyValue
;
71 using com::sun::star::io::XInputStream
;
72 using com::sun::star::io::XActiveDataSink
;
73 using com::sun::star::io::XTextInputStream
;
74 using com::sun::star::container::XEnumeration
;
75 using com::sun::star::container::XNameContainer
;
76 using com::sun::star::xforms::XFormsSupplier
;
78 using namespace xforms
;
79 using namespace com::sun::star::uno
;
80 using namespace com::sun::star::xml::dom
;
81 using namespace com::sun::star::xml::xpath
;
86 // implement XFormsUIHelper1
89 OUString
Model::getDefaultServiceNameForNode( const XNode_t
& xNode
)
90 throw( RuntimeException
)
92 // determine service for control. string/text field is default.
93 OUString sService
= OUSTRING("com.sun.star.form.component.TextField");
95 // query repository for suitable type
96 OSL_ENSURE( mxDataTypes
.is(), "no type repository?" );
97 OUString sTypeName
= queryMIP( xNode
).getTypeName();
98 if( mxDataTypes
->hasByName( sTypeName
) )
100 OSL_ENSURE( mxDataTypes
->getDataType( sTypeName
).is(),
103 switch( mxDataTypes
->getDataType( sTypeName
)->getTypeClass() )
105 case com::sun::star::xsd::DataTypeClass::BOOLEAN
:
106 sService
= OUSTRING("com.sun.star.form.component.CheckBox");
108 case com::sun::star::xsd::DataTypeClass::DOUBLE
:
109 case com::sun::star::xsd::DataTypeClass::DECIMAL
:
110 case com::sun::star::xsd::DataTypeClass::FLOAT
:
111 sService
= OUSTRING("com.sun.star.form.component.NumericField");
114 case com::sun::star::xsd::DataTypeClass::STRING
:
115 case com::sun::star::xsd::DataTypeClass::DURATION
:
116 case com::sun::star::xsd::DataTypeClass::DATETIME
:
117 case com::sun::star::xsd::DataTypeClass::TIME
:
118 case com::sun::star::xsd::DataTypeClass::DATE
:
119 case com::sun::star::xsd::DataTypeClass::gYearMonth
:
120 case com::sun::star::xsd::DataTypeClass::gYear
:
121 case com::sun::star::xsd::DataTypeClass::gMonthDay
:
122 case com::sun::star::xsd::DataTypeClass::gDay
:
123 case com::sun::star::xsd::DataTypeClass::gMonth
:
124 case com::sun::star::xsd::DataTypeClass::hexBinary
:
125 case com::sun::star::xsd::DataTypeClass::base64Binary
:
126 case com::sun::star::xsd::DataTypeClass::anyURI
:
127 case com::sun::star::xsd::DataTypeClass::QName
:
128 case com::sun::star::xsd::DataTypeClass::NOTATION
:
139 void lcl_OutPosition( OUStringBuffer
& rBuffer
,
140 const Reference
<XNode
>& xNode
)
142 OSL_ENSURE( xNode
->getParentNode().is(), "need parent" );
144 // count # of occurences of this node
145 sal_Int32 nFound
= 0;
146 sal_Int32 nPosition
= -1;
147 if( xNode
->getParentNode().is() )
149 for( Reference
<XNode
> xIter
= xNode
->getParentNode()->getFirstChild();
151 xIter
= xIter
->getNextSibling() )
153 if( xIter
->getNodeType() == xNode
->getNodeType() &&
154 xIter
->getNodeName() == xNode
->getNodeName() &&
155 xIter
->getNamespaceURI() == xNode
->getNamespaceURI() )
163 OSL_ENSURE( nFound
> 0 && nPosition
> 0, "node not found???" );
165 // output position (if necessary)
168 rBuffer
.insert( 0, sal_Unicode(']') );
169 rBuffer
.insert( 0, nPosition
);
170 rBuffer
.insert( 0, sal_Unicode('[') );
174 void lcl_OutName( OUStringBuffer
& rBuffer
,
175 const Reference
<XNode
>& xNode
)
177 rBuffer
.insert( 0, xNode
->getNodeName() );
178 OUString sPrefix
= xNode
->getPrefix();
179 if( sPrefix
.getLength() > 0 )
181 rBuffer
.insert( 0, sal_Unicode(':') );
182 rBuffer
.insert( 0, sPrefix
);
186 void lcl_OutInstance( OUStringBuffer
& rBuffer
,
187 const Reference
<XNode
>& xNode
,
190 Reference
<XDocument
> xDoc
= xNode
->getOwnerDocument();
192 if( xDoc
!= pModel
->getDefaultInstance() )
194 rBuffer
.insert( 0, OUSTRING("')") );
196 // iterate over instances, and find the right one
197 OUString sInstanceName
;
198 Reference
<XEnumeration
> xEnum
=
199 pModel
->getInstances()->createEnumeration();
200 while( ( sInstanceName
.getLength() == 0 ) && xEnum
->hasMoreElements() )
202 Sequence
<PropertyValue
> aValues
;
203 xEnum
->nextElement() >>= aValues
;
205 // get ID and instance
207 Reference
<XDocument
> xInstance
;
208 getInstanceData( aValues
, &sId
, &xInstance
, NULL
, NULL
);
210 // now check whether this was our instance:
211 if( xInstance
== xDoc
)
215 rBuffer
.insert( 0, sInstanceName
);
216 rBuffer
.insert( 0, OUSTRING("instance('") );
220 OUString
Model::getDefaultBindingExpressionForNode(
221 const XNode_t
& xNode
,
222 const EvaluationContext
& rContext
)
224 OSL_ENSURE( xNode
.is(), "need node" );
226 // iterate upwards and put sections into the expression buffer.
227 // Stop iteration either at context node (relative expression) or
228 // at document root, whichever occurs first.
229 OUStringBuffer aBuffer
;
230 for( Reference
<XNode
> xCurrent
= xNode
;
231 xCurrent
.is() && xCurrent
!= rContext
.mxContextNode
;
232 xCurrent
= xCurrent
->getParentNode() )
234 // insert a '/' for every step except the first
235 if( aBuffer
.getLength() > 0 )
236 aBuffer
.insert( 0, sal_Unicode('/') );
238 switch( xCurrent
->getNodeType() )
240 case NodeType_ELEMENT_NODE
:
241 lcl_OutPosition( aBuffer
, xCurrent
);
242 lcl_OutName( aBuffer
, xCurrent
);
245 case NodeType_TEXT_NODE
:
246 lcl_OutPosition( aBuffer
, xCurrent
);
247 aBuffer
.insert( 0, OUSTRING("text()") );
250 case NodeType_ATTRIBUTE_NODE
:
251 lcl_OutName( aBuffer
, xCurrent
);
252 aBuffer
.insert( 0, sal_Unicode('@') );
255 case NodeType_DOCUMENT_NODE
:
256 // check for which instance we have
257 lcl_OutInstance( aBuffer
, xCurrent
, this );
261 // unknown type? fail!
262 OSL_ENSURE( false, "unknown node type!" );
263 xCurrent
.set( NULL
);
264 aBuffer
.makeStringAndClear();
265 // we'll remove the slash below
266 aBuffer
.insert( 0, sal_Unicode('/') );
271 return aBuffer
.makeStringAndClear();
276 OUString
Model::getDefaultBindingExpressionForNode( const XNode_t
& xNode
)
277 throw( RuntimeException
)
279 return getDefaultBindingExpressionForNode( xNode
, getEvaluationContext() );
282 bool lcl_isWhitespace( const OUString
& rString
)
284 sal_Int32 nLength
= rString
.getLength();
285 const sal_Unicode
* pStr
= rString
.getStr();
287 bool bWhitespace
= true;
288 for( sal_Int32 i
= 0; bWhitespace
&& ( i
< nLength
); i
++ )
290 sal_Unicode c
= pStr
[i
];
291 bWhitespace
= ( c
== sal_Unicode(0x09) ||
292 c
== sal_Unicode(0x0A) ||
293 c
== sal_Unicode(0x0D) ||
294 c
== sal_Unicode(0x20) );
299 OUString
Model::getNodeDisplayName( const XNode_t
& xNode
,
301 throw( RuntimeException
)
303 OUStringBuffer aBuffer
;
305 switch( xNode
->getNodeType() )
307 case NodeType_ELEMENT_NODE
:
308 lcl_OutName( aBuffer
, xNode
);
311 case NodeType_TEXT_NODE
:
313 OUString sContent
= xNode
->getNodeValue();
314 if( bDetail
|| ! lcl_isWhitespace( sContent
) )
316 aBuffer
.append( sal_Unicode('"') );
317 aBuffer
.append( Convert::collapseWhitespace( sContent
) );
318 aBuffer
.append( sal_Unicode('"') );
323 case NodeType_ATTRIBUTE_NODE
:
324 lcl_OutName( aBuffer
, xNode
);
325 aBuffer
.insert( 0, sal_Unicode('@') );
328 case NodeType_DOCUMENT_NODE
:
329 if( xNode
== getDefaultInstance() )
330 aBuffer
.append( sal_Unicode('/') );
332 lcl_OutInstance( aBuffer
, xNode
, this );
336 // unknown type? fail!
337 OSL_ENSURE( false, "unknown node type!" );
341 return aBuffer
.makeStringAndClear();
344 OUString
Model::getNodeName( const XNode_t
& xNode
)
345 throw( RuntimeException
)
347 OUStringBuffer aBuffer
;
349 switch( xNode
->getNodeType() )
351 case NodeType_ELEMENT_NODE
:
352 case NodeType_ATTRIBUTE_NODE
:
353 lcl_OutName( aBuffer
, xNode
);
356 case NodeType_TEXT_NODE
:
357 case NodeType_DOCUMENT_NODE
:
359 // unknown type? fail!
360 OSL_ENSURE( false, "no name for this node type!" );
364 return aBuffer
.makeStringAndClear();
367 OUString
Model::getBindingName( const XPropertySet_t
& xBinding
,
368 sal_Bool
/*bDetail*/ )
369 throw( RuntimeException
)
372 xBinding
->getPropertyValue( OUSTRING("BindingID" ) ) >>= sID
;
373 OUString sExpression
;
374 xBinding
->getPropertyValue( OUSTRING("BindingExpression" ) ) >>= sExpression
;
376 OUStringBuffer aBuffer
;
377 if( sID
.getLength() > 0 )
379 aBuffer
.append( sID
);
380 aBuffer
.append( OUSTRING(" (" ));
381 aBuffer
.append( sExpression
);
382 aBuffer
.append( OUSTRING(")" ));
385 aBuffer
.append( sExpression
);
387 return aBuffer
.makeStringAndClear();
390 OUString
Model::getSubmissionName( const XPropertySet_t
& xSubmission
,
391 sal_Bool
/*bDetail*/ )
392 throw( RuntimeException
)
395 xSubmission
->getPropertyValue( OUSTRING("ID") ) >>= sID
;
399 Model::XPropertySet_t
Model::cloneBindingAsGhost( const XPropertySet_t
&xBinding
)
400 throw( RuntimeException
)
402 // Create a new binding instance first...
403 Binding
*pBinding
= new Binding();
405 // ...and bump up the "defered notification counter"
406 // to prevent this binding from contributing to the
408 pBinding
->deferNotifications(true);
410 // Copy the propertyset and return result...
411 XPropertySet_t
xNewBinding(pBinding
);
412 copy( xBinding
, xNewBinding
);
416 void Model::removeBindingIfUseless( const XPropertySet_t
& xBinding
)
417 throw( RuntimeException
)
419 Binding
* pBinding
= Binding::getBinding( xBinding
);
420 if( pBinding
!= NULL
)
422 if( ! pBinding
->isUseful() )
423 mpBindings
->removeItem( pBinding
);
427 Model::XDocument_t
Model::newInstance( const rtl::OUString
& sName
,
428 const rtl::OUString
& sURL
,
430 throw( RuntimeException
)
432 // create a default instance with <instanceData> element
433 XDocument_t xInstance
= getDocumentBuilder()->newDocument();
434 DBG_ASSERT( xInstance
.is(), "failed to create DOM instance" );
436 Reference
<XNode
>( xInstance
, UNO_QUERY_THROW
)->appendChild(
437 Reference
<XNode
>( xInstance
->createElement( OUSTRING("instanceData") ),
440 Sequence
<PropertyValue
> aSequence
;
441 bool bOnce
= bURLOnce
; // bool, so we can take address in setInstanceData
442 setInstanceData( aSequence
, &sName
, &xInstance
, &sURL
, &bOnce
);
443 sal_Int32 nInstance
= mpInstances
->addItem( aSequence
);
444 loadInstance( nInstance
);
449 sal_Int32
lcl_findProp( const PropertyValue
* pValues
,
451 const rtl::OUString
& rName
)
455 for( ; !bFound
&& n
< nLength
; n
++ )
457 bFound
= ( pValues
[n
].Name
== rName
);
459 return bFound
? ( n
- 1) : -1;
462 sal_Int32
xforms::lcl_findInstance( const InstanceCollection
* pInstances
,
463 const rtl::OUString
& rName
)
465 sal_Int32 nLength
= pInstances
->countItems();
468 for( ; !bFound
&& n
< nLength
; n
++ )
471 getInstanceData( pInstances
->getItem( n
), &sName
, NULL
, NULL
, NULL
);
472 bFound
= ( sName
== rName
);
474 return bFound
? ( n
- 1 ) : -1;
477 void Model::renameInstance( const rtl::OUString
& sFrom
,
478 const rtl::OUString
& sTo
,
479 const rtl::OUString
& sURL
,
481 throw( RuntimeException
)
483 sal_Int32 nPos
= lcl_findInstance( mpInstances
, sFrom
);
486 Sequence
<PropertyValue
> aSeq
= mpInstances
->getItem( nPos
);
487 PropertyValue
* pSeq
= aSeq
.getArray();
488 sal_Int32 nLength
= aSeq
.getLength();
490 sal_Int32 nProp
= lcl_findProp( pSeq
, nLength
, OUSTRING("ID") );
494 aSeq
.realloc( nLength
+ 1 );
495 pSeq
= aSeq
.getArray();
496 pSeq
[ nLength
].Name
= OUSTRING("ID");
501 pSeq
[ nProp
].Value
<<= sTo
;
504 nProp
= lcl_findProp( pSeq
, nLength
, OUSTRING("URL") );
506 pSeq
[ nProp
].Value
<<= sURL
;
509 nProp
= lcl_findProp( pSeq
, nLength
, OUSTRING("URLOnce") );
511 pSeq
[ nProp
].Value
<<= bURLOnce
;
514 mpInstances
->setItem( nPos
, aSeq
);
518 void Model::removeInstance( const rtl::OUString
& sName
)
519 throw( RuntimeException
)
521 sal_Int32 nPos
= lcl_findInstance( mpInstances
, sName
);
523 mpInstances
->removeItem( mpInstances
->getItem( nPos
) );
526 Reference
<XNameContainer
> lcl_getModels(
527 const Reference
<com::sun::star::frame::XModel
>& xComponent
)
529 Reference
<XNameContainer
> xRet
;
530 Reference
<XFormsSupplier
> xSupplier( xComponent
, UNO_QUERY
);
533 xRet
= xSupplier
->getXForms();
538 Model::XModel_t
Model::newModel( const Reference
<com::sun::star::frame::XModel
>& xCmp
,
539 const OUString
& sName
)
540 throw( RuntimeException
)
542 Model
* pModel
= NULL
;
543 Reference
<XNameContainer
> xModels
= lcl_getModels( xCmp
);
545 && ! xModels
->hasByName( sName
) )
547 pModel
= new Model();
548 pModel
->setID( sName
);
549 pModel
->newInstance( OUString(), OUString(), sal_False
);
550 xModels
->insertByName( sName
, makeAny( Reference
<XModel
>( pModel
) ) );
556 void Model::renameModel( const Reference
<com::sun::star::frame::XModel
>& xCmp
,
557 const OUString
& sFrom
,
558 const OUString
& sTo
)
559 throw( RuntimeException
)
561 Reference
<XNameContainer
> xModels
= lcl_getModels( xCmp
);
563 && xModels
->hasByName( sFrom
)
564 && ! xModels
->hasByName( sTo
) )
566 Reference
<XModel
> xModel( xModels
->getByName( sFrom
), UNO_QUERY
);
567 xModel
->setID( sTo
);
568 xModels
->insertByName( sTo
, makeAny( xModel
) );
569 xModels
->removeByName( sFrom
);
573 void Model::removeModel( const Reference
<com::sun::star::frame::XModel
>& xCmp
,
574 const OUString
& sName
)
575 throw( RuntimeException
)
577 Reference
<XNameContainer
> xModels
= lcl_getModels( xCmp
);
579 && xModels
->hasByName( sName
) )
581 xModels
->removeByName( sName
);
585 Model::XNode_t
Model::createElement( const XNode_t
& xParent
,
586 const OUString
& sName
)
587 throw( RuntimeException
)
589 Reference
<XNode
> xNode
;
591 && isValidXMLName( sName
) )
593 // TODO: implement proper namespace handling
594 xNode
.set( xParent
->getOwnerDocument()->createElement( sName
),
600 Model::XNode_t
Model::createAttribute( const XNode_t
& xParent
,
601 const OUString
& sName
)
602 throw( RuntimeException
)
604 Reference
<XNode
> xNode
;
605 Reference
<XElement
> xElement( xParent
, UNO_QUERY
);
608 && isValidXMLName( sName
) )
610 // handle case where attribute already exists
611 sal_Int32 nCount
= 0;
612 OUString sUniqueName
= sName
;
613 while( xElement
->hasAttribute( sUniqueName
) )
616 sUniqueName
= sName
+ OUString::valueOf( nCount
);
619 // TODO: implement proper namespace handling
620 xNode
.set( xParent
->getOwnerDocument()->createAttribute( sUniqueName
),
626 Model::XNode_t
Model::renameNode( const XNode_t
& xNode
,
627 const rtl::OUString
& sName
)
628 throw( RuntimeException
)
630 // early out if we don't have to change the name
631 if( xNode
->getNodeName() == sName
)
634 // refuse to change name if its an attribute, and the name is already used
635 if( xNode
->getNodeType() == NodeType_ATTRIBUTE_NODE
636 && xNode
->getParentNode().is()
637 && Reference
<XElement
>(xNode
->getParentNode(), UNO_QUERY_THROW
)->hasAttribute( sName
) )
640 // note old binding expression so we can adjust bindings below
641 OUString sOldDefaultBindingExpression
=
642 getDefaultBindingExpressionForNode( xNode
);
644 Reference
<XDocument
> xDoc
= xNode
->getOwnerDocument();
645 Reference
<XNode
> xNew
;
646 if( xNode
->getNodeType() == NodeType_ELEMENT_NODE
)
648 Reference
<XElement
> xElem
= xDoc
->createElement( sName
);
649 xNew
.set( xElem
, UNO_QUERY
);
651 // iterate over all attributes and append them to the new element
652 Reference
<XElement
> xOldElem( xNode
, UNO_QUERY
);
653 OSL_ENSURE( xNode
.is(), "no element?" );
655 Reference
<XNamedNodeMap
> xMap
= xNode
->getAttributes();
656 sal_Int32 nLength
= xMap
.is() ? xMap
->getLength() : 0;
657 for( sal_Int32 n
= 0; n
< nLength
; n
++ )
659 Reference
<XAttr
> xAttr( xMap
->item(n
), UNO_QUERY
);
660 xElem
->setAttributeNode( xOldElem
->removeAttributeNode( xAttr
) );
663 // iterate over all children and append them to the new element
664 for( Reference
<XNode
> xCurrent
= xNode
->getFirstChild();
666 xCurrent
= xNode
->getFirstChild() )
668 xNew
->appendChild( xNode
->removeChild( xCurrent
) );
671 xNode
->getParentNode()->replaceChild( xNew
, xNode
);
673 else if( xNode
->getNodeType() == NodeType_ATTRIBUTE_NODE
)
675 // create new attribute
676 Reference
<XAttr
> xAttr
= xDoc
->createAttribute( sName
);
677 xAttr
->setValue( xNode
->getNodeValue() );
680 Reference
<XNode
> xParent
= xNode
->getParentNode();
681 xParent
->removeChild( xNode
);
682 xNew
= xParent
->appendChild( Reference
<XNode
>( xAttr
, UNO_QUERY
) );
686 OSL_ENSURE( false, "can't rename this node type" );
689 // adjust bindings (if necessary):
692 // iterate over bindings and replace default expressions
693 OUString sNewDefaultBindingExpression
=
694 getDefaultBindingExpressionForNode( xNew
);
695 for( sal_Int32 n
= 0; n
< mpBindings
->countItems(); n
++ )
697 Binding
* pBinding
= Binding::getBinding(
698 mpBindings
->Collection
<XPropertySet_t
>::getItem( n
) );
700 if( pBinding
->getBindingExpression()
701 == sOldDefaultBindingExpression
)
702 pBinding
->setBindingExpression( sNewDefaultBindingExpression
);
706 // return node; return old node if renaming failed
707 return xNew
.is() ? xNew
: xNode
;
710 Model::XPropertySet_t
Model::getBindingForNode( const XNode_t
& xNode
,
712 throw( RuntimeException
)
714 OSL_ENSURE( xNode
.is(), "no node?" );
716 // We will iterate over all bindings and determine the
717 // appropriateness of the respective binding for this node. The
718 // best one will be used. If we don't find any and bCreate is set,
719 // then we will create a suitable binding.
720 Binding
* pBestBinding
= NULL
;
721 sal_Int32 nBestScore
= 0;
723 for( sal_Int32 n
= 0; n
< mpBindings
->countItems(); n
++ )
725 Binding
* pBinding
= Binding::getBinding(
726 mpBindings
->Collection
<XPropertySet_t
>::getItem( n
) );
728 OSL_ENSURE( pBinding
!= NULL
, "no binding?" );
729 Reference
<XNodeList
> xNodeList
= pBinding
->getXNodeList();
731 sal_Int32 nNodes
= xNodeList
.is() ? xNodeList
->getLength() : 0;
732 if( nNodes
> 0 && xNodeList
->item( 0 ) == xNode
)
734 // allright, we found a suitable node. Let's determine how
735 // well it fits. Score:
736 // - bind to exactly this node is better than whole nodeset
737 // - simple binding expressions is better than complex ones
738 sal_Int32 nScore
= 0;
741 if( pBinding
->isSimpleBindingExpression() )
744 // if we found a better binding, remember it
745 if( nScore
> nBestScore
)
747 pBestBinding
= pBinding
;
753 // create binding, if none was found and bCreate is set
754 OSL_ENSURE( ( nBestScore
== 0 ) == ( pBestBinding
== NULL
),
755 "score != binding?" );
756 if( bCreate
&& pBestBinding
== NULL
)
758 pBestBinding
= new Binding();
759 pBestBinding
->setBindingExpression(
760 getDefaultBindingExpressionForNode( xNode
) );
761 mpBindings
->addItem( pBestBinding
);
767 void Model::removeBindingForNode( const XNode_t
& )
768 throw( RuntimeException
)
770 // determine whether suitable binding is still used
773 OUString
lcl_serializeForDisplay( const Reference
< XAttr
>& _rxAttrNode
)
775 ::rtl::OUString sResult
;
776 OSL_ENSURE( _rxAttrNode
.is(), "lcl_serializeForDisplay( attr ): invalid argument!" );
777 if ( _rxAttrNode
.is() )
779 ::rtl::OUStringBuffer aBuffer
;
780 aBuffer
.append( _rxAttrNode
->getName() );
781 aBuffer
.appendAscii( "=" );
782 ::rtl::OUString sValue
= _rxAttrNode
->getValue();
783 sal_Unicode nQuote
= '"';
784 if ( sValue
.indexOf( nQuote
) >= 0 )
786 aBuffer
.append( nQuote
);
787 aBuffer
.append( sValue
);
788 aBuffer
.append( nQuote
);
789 aBuffer
.append( (sal_Unicode
)' ' );
790 sResult
= aBuffer
.makeStringAndClear();
795 OUString
lcl_serializeForDisplay( const Reference
<XNodeList
>& xNodes
)
797 ::rtl::OUString sResult
;
799 // create document fragment
800 Reference
<XDocument
> xDocument( getDocumentBuilder()->newDocument() );
801 Reference
<XDocumentFragment
> xFragment(
802 xDocument
->createDocumentFragment() );
803 Reference
<XNode
> xNode( xFragment
, UNO_QUERY
);
804 OSL_ENSURE( xFragment
.is(), "xFragment" );
805 OSL_ENSURE( xNode
.is(), "xNode" );
807 sal_Int32 nAttributeNodes
= 0;
809 // attach nodelist to fragment
810 sal_Int32 nLength
= xNodes
->getLength();
811 for( sal_Int32 i
= 0; i
< nLength
; i
++ )
813 Reference
<XNode
> xCurrent
= xNodes
->item( i
);
815 switch ( xCurrent
->getNodeType() )
817 case NodeType_DOCUMENT_NODE
:
818 // special-case documents: use top-level element instead
819 xCurrent
= xCurrent
->getFirstChild();
821 case NodeType_ATTRIBUTE_NODE
:
823 Reference
< XAttr
> xAttr( xCurrent
, UNO_QUERY
);
826 sResult
+= lcl_serializeForDisplay( xAttr
);
837 xNode
->appendChild( xDocument
->importNode( xCurrent
, sal_True
) );
839 OSL_ENSURE( ( nAttributeNodes
== 0 ) || ( nAttributeNodes
== nLength
),
840 "lcl_serializeForDisplay: mixed attribute and non-attribute nodes?" );
841 if ( nAttributeNodes
)
842 // had only attribute nodes
845 // serialize fragment
846 CSerializationAppXML aSerialization
;
847 aSerialization
.setSource( xFragment
);
848 aSerialization
.serialize();
850 // copy stream into buffer
851 Reference
<XTextInputStream
> xTextInputStream(
852 createInstance( OUSTRING("com.sun.star.io.TextInputStream") ),
854 Reference
<XActiveDataSink
>( xTextInputStream
, UNO_QUERY_THROW
)
855 ->setInputStream( aSerialization
.getInputStream() );
857 /* WORK AROUND for problem in serialization: currently, multiple
858 XML delarations (<?xml...?>) are being written out and we don't
859 want them. When this is fixed, the code below is nice and
860 simple. The current code filters out the declarations.
861 OUString sResult = xTextInputStream->readString( Sequence<sal_Unicode>(),
865 // well, the serialization prepends XML header(s) that we need to
867 OUStringBuffer aBuffer
;
868 while( ! xTextInputStream
->isEOF() )
870 OUString sLine
= xTextInputStream
->readLine();
871 if( sLine
.getLength() > 0
872 && sLine
.compareToAscii( "<?xml", 5 ) != 0 )
874 aBuffer
.append( sLine
);
875 aBuffer
.append( sal_Unicode('\n') );
878 sResult
= aBuffer
.makeStringAndClear();
883 OUString
lcl_serializeForDisplay( const Reference
<XXPathObject
>& xResult
)
885 // error handling first
887 return getResource( RID_STR_XFORMS_CANT_EVALUATE
);
891 OUStringBuffer aBuffer
;
893 switch( xResult
->getObjectType() )
895 case XPathObjectType_XPATH_BOOLEAN
:
896 aBuffer
.append( xResult
->getBoolean()
898 : OUSTRING("false") );
901 case XPathObjectType_XPATH_STRING
:
902 aBuffer
.append( sal_Unicode('"') );
903 aBuffer
.append( xResult
->getString() );
904 aBuffer
.append( sal_Unicode('"') );
907 case XPathObjectType_XPATH_NODESET
:
908 aBuffer
.append( lcl_serializeForDisplay( xResult
->getNodeList() ) );
911 case XPathObjectType_XPATH_NUMBER
:
912 aBuffer
.append( xResult
->getDouble() );
915 case XPathObjectType_XPATH_UNDEFINED
:
916 case XPathObjectType_XPATH_POINT
:
917 case XPathObjectType_XPATH_RANGE
:
918 case XPathObjectType_XPATH_LOCATIONSET
:
919 case XPathObjectType_XPATH_USERS
:
920 case XPathObjectType_XPATH_XSLT_TREE
:
922 // TODO: localized error message?
926 return aBuffer
.makeStringAndClear();
929 OUString
Model::getResultForExpression(
930 const XPropertySet_t
& xBinding
,
931 sal_Bool bIsBindingExpression
,
932 const OUString
& sExpression
)
933 throw( RuntimeException
)
935 Binding
* pBinding
= Binding::getBinding( xBinding
);
936 if( pBinding
== NULL
)
937 throw RuntimeException();
939 // prepare & evaluate expression
940 OUStringBuffer aBuffer
;
941 ComputedExpression aExpression
;
942 aExpression
.setExpression( sExpression
);
943 if( bIsBindingExpression
)
945 // binding: use binding context and evaluation
946 aExpression
.evaluate( pBinding
->getEvaluationContext() );
947 aBuffer
.append( lcl_serializeForDisplay( aExpression
.getXPath() ) );
951 // MIP (not binding): iterate over bindings contexts
952 std::vector
<EvaluationContext
> aContext
=
953 pBinding
->getMIPEvaluationContexts();
954 for( std::vector
<EvaluationContext
>::iterator aIter
= aContext
.begin();
955 aIter
!= aContext
.end();
958 aExpression
.evaluate( *aIter
);
959 aBuffer
.append( lcl_serializeForDisplay(aExpression
.getXPath()) );
960 aBuffer
.append( sal_Unicode('\n') );
963 return aBuffer
.makeStringAndClear();
966 sal_Bool
Model::isValidXMLName( const OUString
& sName
)
967 throw( RuntimeException
)
969 return isValidQName( sName
, NULL
);
972 sal_Bool
Model::isValidPrefixName( const OUString
& sName
)
973 throw( RuntimeException
)
975 return ::isValidPrefixName( sName
, NULL
);
978 void Model::setNodeValue(
979 const XNode_t
& xNode
,
980 const rtl::OUString
& sValue
)
981 throw( RuntimeException
)
983 setSimpleContent( xNode
, sValue
);
988 // helper functions from model_helper.hxx
991 void xforms::getInstanceData(
992 const Sequence
<PropertyValue
>& aValues
,
994 Reference
<XDocument
>* pInstance
,
998 sal_Int32 nValues
= aValues
.getLength();
999 const PropertyValue
* pValues
= aValues
.getConstArray();
1000 for( sal_Int32 n
= 0; n
< nValues
; n
++ )
1002 const PropertyValue
& rValue
= pValues
[n
];
1003 #define PROP(NAME) \
1004 if( p##NAME != NULL && \
1005 rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(#NAME)) ) \
1006 rValue.Value >>= (*p##NAME)
1015 void xforms::setInstanceData(
1016 Sequence
<PropertyValue
>& aSequence
,
1017 const OUString
* _pID
,
1018 const Reference
<XDocument
>* _pInstance
,
1019 const OUString
* _pURL
,
1020 const bool* _pURLOnce
)
1022 // get old instance data
1024 Reference
<XDocument
> xInstance
;
1026 bool bURLOnce
= false;
1027 getInstanceData( aSequence
, &sID
, &xInstance
, &sURL
, &bURLOnce
);
1028 const OUString
* pID
= ( sID
.getLength() > 0 ) ? &sID
: NULL
;
1029 const Reference
<XDocument
>* pInstance
= xInstance
.is() ? &xInstance
: NULL
;
1030 const OUString
* pURL
= ( sURL
.getLength() > 0 ) ? &sURL
: NULL
;
1031 const bool* pURLOnce
= ( bURLOnce
&& pURL
!= NULL
) ? &bURLOnce
: NULL
;
1033 // determine new instance data
1034 #define PROP(NAME) if( _p##NAME != NULL ) p##NAME = _p##NAME
1041 // count # of values we want to set
1042 sal_Int32 nCount
= 0;
1043 #define PROP(NAME) if( p##NAME != NULL ) nCount++
1050 // realloc sequence and enter values;
1051 aSequence
.realloc( nCount
);
1052 PropertyValue
* pSequence
= aSequence
.getArray();
1053 sal_Int32 nIndex
= 0;
1054 #define PROP(NAME) \
1055 if( p##NAME != NULL ) \
1057 pSequence[ nIndex ].Name = OUSTRING(#NAME); \
1058 pSequence[ nIndex ].Value <<= *p##NAME; \