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::XModel_t xModel
;
543 Reference
<XNameContainer
> xModels
= lcl_getModels( xCmp
);
545 && ! xModels
->hasByName( sName
) )
547 Model
* pModel
= new Model();
548 xModel
.set( pModel
);
550 pModel
->setID( sName
);
551 pModel
->newInstance( OUString(), OUString(), sal_False
);
552 pModel
->initialize();
553 xModels
->insertByName( sName
, makeAny( xModel
) );
559 void Model::renameModel( const Reference
<com::sun::star::frame::XModel
>& xCmp
,
560 const OUString
& sFrom
,
561 const OUString
& sTo
)
562 throw( RuntimeException
)
564 Reference
<XNameContainer
> xModels
= lcl_getModels( xCmp
);
566 && xModels
->hasByName( sFrom
)
567 && ! xModels
->hasByName( sTo
) )
569 Reference
<XModel
> xModel( xModels
->getByName( sFrom
), UNO_QUERY
);
570 xModel
->setID( sTo
);
571 xModels
->insertByName( sTo
, makeAny( xModel
) );
572 xModels
->removeByName( sFrom
);
576 void Model::removeModel( const Reference
<com::sun::star::frame::XModel
>& xCmp
,
577 const OUString
& sName
)
578 throw( RuntimeException
)
580 Reference
<XNameContainer
> xModels
= lcl_getModels( xCmp
);
582 && xModels
->hasByName( sName
) )
584 xModels
->removeByName( sName
);
588 Model::XNode_t
Model::createElement( const XNode_t
& xParent
,
589 const OUString
& sName
)
590 throw( RuntimeException
)
592 Reference
<XNode
> xNode
;
594 && isValidXMLName( sName
) )
596 // TODO: implement proper namespace handling
597 xNode
.set( xParent
->getOwnerDocument()->createElement( sName
),
603 Model::XNode_t
Model::createAttribute( const XNode_t
& xParent
,
604 const OUString
& sName
)
605 throw( RuntimeException
)
607 Reference
<XNode
> xNode
;
608 Reference
<XElement
> xElement( xParent
, UNO_QUERY
);
611 && isValidXMLName( sName
) )
613 // handle case where attribute already exists
614 sal_Int32 nCount
= 0;
615 OUString sUniqueName
= sName
;
616 while( xElement
->hasAttribute( sUniqueName
) )
619 sUniqueName
= sName
+ OUString::valueOf( nCount
);
622 // TODO: implement proper namespace handling
623 xNode
.set( xParent
->getOwnerDocument()->createAttribute( sUniqueName
),
629 Model::XNode_t
Model::renameNode( const XNode_t
& xNode
,
630 const rtl::OUString
& sName
)
631 throw( RuntimeException
)
633 // early out if we don't have to change the name
634 if( xNode
->getNodeName() == sName
)
637 // refuse to change name if its an attribute, and the name is already used
638 if( xNode
->getNodeType() == NodeType_ATTRIBUTE_NODE
639 && xNode
->getParentNode().is()
640 && Reference
<XElement
>(xNode
->getParentNode(), UNO_QUERY_THROW
)->hasAttribute( sName
) )
643 // note old binding expression so we can adjust bindings below
644 OUString sOldDefaultBindingExpression
=
645 getDefaultBindingExpressionForNode( xNode
);
647 Reference
<XDocument
> xDoc
= xNode
->getOwnerDocument();
648 Reference
<XNode
> xNew
;
649 if( xNode
->getNodeType() == NodeType_ELEMENT_NODE
)
651 Reference
<XElement
> xElem
= xDoc
->createElement( sName
);
652 xNew
.set( xElem
, UNO_QUERY
);
654 // iterate over all attributes and append them to the new element
655 Reference
<XElement
> xOldElem( xNode
, UNO_QUERY
);
656 OSL_ENSURE( xNode
.is(), "no element?" );
658 Reference
<XNamedNodeMap
> xMap
= xNode
->getAttributes();
659 sal_Int32 nLength
= xMap
.is() ? xMap
->getLength() : 0;
660 for( sal_Int32 n
= 0; n
< nLength
; n
++ )
662 Reference
<XAttr
> xAttr( xMap
->item(n
), UNO_QUERY
);
663 xElem
->setAttributeNode( xOldElem
->removeAttributeNode( xAttr
) );
666 // iterate over all children and append them to the new element
667 for( Reference
<XNode
> xCurrent
= xNode
->getFirstChild();
669 xCurrent
= xNode
->getFirstChild() )
671 xNew
->appendChild( xNode
->removeChild( xCurrent
) );
674 xNode
->getParentNode()->replaceChild( xNew
, xNode
);
676 else if( xNode
->getNodeType() == NodeType_ATTRIBUTE_NODE
)
678 // create new attribute
679 Reference
<XAttr
> xAttr
= xDoc
->createAttribute( sName
);
680 xAttr
->setValue( xNode
->getNodeValue() );
683 Reference
<XNode
> xParent
= xNode
->getParentNode();
684 xParent
->removeChild( xNode
);
685 xNew
= xParent
->appendChild( Reference
<XNode
>( xAttr
, UNO_QUERY
) );
689 OSL_ENSURE( false, "can't rename this node type" );
692 // adjust bindings (if necessary):
695 // iterate over bindings and replace default expressions
696 OUString sNewDefaultBindingExpression
=
697 getDefaultBindingExpressionForNode( xNew
);
698 for( sal_Int32 n
= 0; n
< mpBindings
->countItems(); n
++ )
700 Binding
* pBinding
= Binding::getBinding(
701 mpBindings
->Collection
<XPropertySet_t
>::getItem( n
) );
703 if( pBinding
->getBindingExpression()
704 == sOldDefaultBindingExpression
)
705 pBinding
->setBindingExpression( sNewDefaultBindingExpression
);
709 // return node; return old node if renaming failed
710 return xNew
.is() ? xNew
: xNode
;
713 Model::XPropertySet_t
Model::getBindingForNode( const XNode_t
& xNode
,
715 throw( RuntimeException
)
717 OSL_ENSURE( xNode
.is(), "no node?" );
719 // We will iterate over all bindings and determine the
720 // appropriateness of the respective binding for this node. The
721 // best one will be used. If we don't find any and bCreate is set,
722 // then we will create a suitable binding.
723 Binding
* pBestBinding
= NULL
;
724 sal_Int32 nBestScore
= 0;
726 for( sal_Int32 n
= 0; n
< mpBindings
->countItems(); n
++ )
728 Binding
* pBinding
= Binding::getBinding(
729 mpBindings
->Collection
<XPropertySet_t
>::getItem( n
) );
731 OSL_ENSURE( pBinding
!= NULL
, "no binding?" );
732 Reference
<XNodeList
> xNodeList
= pBinding
->getXNodeList();
734 sal_Int32 nNodes
= xNodeList
.is() ? xNodeList
->getLength() : 0;
735 if( nNodes
> 0 && xNodeList
->item( 0 ) == xNode
)
737 // allright, we found a suitable node. Let's determine how
738 // well it fits. Score:
739 // - bind to exactly this node is better than whole nodeset
740 // - simple binding expressions is better than complex ones
741 sal_Int32 nScore
= 0;
744 if( pBinding
->isSimpleBindingExpression() )
747 // if we found a better binding, remember it
748 if( nScore
> nBestScore
)
750 pBestBinding
= pBinding
;
756 // create binding, if none was found and bCreate is set
757 OSL_ENSURE( ( nBestScore
== 0 ) == ( pBestBinding
== NULL
),
758 "score != binding?" );
759 if( bCreate
&& pBestBinding
== NULL
)
761 pBestBinding
= new Binding();
762 pBestBinding
->setBindingExpression(
763 getDefaultBindingExpressionForNode( xNode
) );
764 mpBindings
->addItem( pBestBinding
);
770 void Model::removeBindingForNode( const XNode_t
& )
771 throw( RuntimeException
)
773 // determine whether suitable binding is still used
776 OUString
lcl_serializeForDisplay( const Reference
< XAttr
>& _rxAttrNode
)
778 ::rtl::OUString sResult
;
779 OSL_ENSURE( _rxAttrNode
.is(), "lcl_serializeForDisplay( attr ): invalid argument!" );
780 if ( _rxAttrNode
.is() )
782 ::rtl::OUStringBuffer aBuffer
;
783 aBuffer
.append( _rxAttrNode
->getName() );
784 aBuffer
.appendAscii( "=" );
785 ::rtl::OUString sValue
= _rxAttrNode
->getValue();
786 sal_Unicode nQuote
= '"';
787 if ( sValue
.indexOf( nQuote
) >= 0 )
789 aBuffer
.append( nQuote
);
790 aBuffer
.append( sValue
);
791 aBuffer
.append( nQuote
);
792 aBuffer
.append( (sal_Unicode
)' ' );
793 sResult
= aBuffer
.makeStringAndClear();
798 OUString
lcl_serializeForDisplay( const Reference
<XNodeList
>& xNodes
)
800 ::rtl::OUString sResult
;
802 // create document fragment
803 Reference
<XDocument
> xDocument( getDocumentBuilder()->newDocument() );
804 Reference
<XDocumentFragment
> xFragment(
805 xDocument
->createDocumentFragment() );
806 Reference
<XNode
> xNode( xFragment
, UNO_QUERY
);
807 OSL_ENSURE( xFragment
.is(), "xFragment" );
808 OSL_ENSURE( xNode
.is(), "xNode" );
810 sal_Int32 nAttributeNodes
= 0;
812 // attach nodelist to fragment
813 sal_Int32 nLength
= xNodes
->getLength();
814 for( sal_Int32 i
= 0; i
< nLength
; i
++ )
816 Reference
<XNode
> xCurrent
= xNodes
->item( i
);
818 switch ( xCurrent
->getNodeType() )
820 case NodeType_DOCUMENT_NODE
:
821 // special-case documents: use top-level element instead
822 xCurrent
= xCurrent
->getFirstChild();
824 case NodeType_ATTRIBUTE_NODE
:
826 Reference
< XAttr
> xAttr( xCurrent
, UNO_QUERY
);
829 sResult
+= lcl_serializeForDisplay( xAttr
);
840 xNode
->appendChild( xDocument
->importNode( xCurrent
, sal_True
) );
842 OSL_ENSURE( ( nAttributeNodes
== 0 ) || ( nAttributeNodes
== nLength
),
843 "lcl_serializeForDisplay: mixed attribute and non-attribute nodes?" );
844 if ( nAttributeNodes
)
845 // had only attribute nodes
848 // serialize fragment
849 CSerializationAppXML aSerialization
;
850 aSerialization
.setSource( xFragment
);
851 aSerialization
.serialize();
853 // copy stream into buffer
854 Reference
<XTextInputStream
> xTextInputStream(
855 createInstance( OUSTRING("com.sun.star.io.TextInputStream") ),
857 Reference
<XActiveDataSink
>( xTextInputStream
, UNO_QUERY_THROW
)
858 ->setInputStream( aSerialization
.getInputStream() );
860 /* WORK AROUND for problem in serialization: currently, multiple
861 XML delarations (<?xml...?>) are being written out and we don't
862 want them. When this is fixed, the code below is nice and
863 simple. The current code filters out the declarations.
864 OUString sResult = xTextInputStream->readString( Sequence<sal_Unicode>(),
868 // well, the serialization prepends XML header(s) that we need to
870 OUStringBuffer aBuffer
;
871 while( ! xTextInputStream
->isEOF() )
873 OUString sLine
= xTextInputStream
->readLine();
874 if( sLine
.getLength() > 0
875 && sLine
.compareToAscii( "<?xml", 5 ) != 0 )
877 aBuffer
.append( sLine
);
878 aBuffer
.append( sal_Unicode('\n') );
881 sResult
= aBuffer
.makeStringAndClear();
886 OUString
lcl_serializeForDisplay( const Reference
<XXPathObject
>& xResult
)
888 // error handling first
890 return getResource( RID_STR_XFORMS_CANT_EVALUATE
);
894 OUStringBuffer aBuffer
;
896 switch( xResult
->getObjectType() )
898 case XPathObjectType_XPATH_BOOLEAN
:
899 aBuffer
.append( xResult
->getBoolean()
901 : OUSTRING("false") );
904 case XPathObjectType_XPATH_STRING
:
905 aBuffer
.append( sal_Unicode('"') );
906 aBuffer
.append( xResult
->getString() );
907 aBuffer
.append( sal_Unicode('"') );
910 case XPathObjectType_XPATH_NODESET
:
911 aBuffer
.append( lcl_serializeForDisplay( xResult
->getNodeList() ) );
914 case XPathObjectType_XPATH_NUMBER
:
915 aBuffer
.append( xResult
->getDouble() );
918 case XPathObjectType_XPATH_UNDEFINED
:
919 case XPathObjectType_XPATH_POINT
:
920 case XPathObjectType_XPATH_RANGE
:
921 case XPathObjectType_XPATH_LOCATIONSET
:
922 case XPathObjectType_XPATH_USERS
:
923 case XPathObjectType_XPATH_XSLT_TREE
:
925 // TODO: localized error message?
929 return aBuffer
.makeStringAndClear();
932 OUString
Model::getResultForExpression(
933 const XPropertySet_t
& xBinding
,
934 sal_Bool bIsBindingExpression
,
935 const OUString
& sExpression
)
936 throw( RuntimeException
)
938 Binding
* pBinding
= Binding::getBinding( xBinding
);
939 if( pBinding
== NULL
)
940 throw RuntimeException();
942 // prepare & evaluate expression
943 OUStringBuffer aBuffer
;
944 ComputedExpression aExpression
;
945 aExpression
.setExpression( sExpression
);
946 if( bIsBindingExpression
)
948 // binding: use binding context and evaluation
949 aExpression
.evaluate( pBinding
->getEvaluationContext() );
950 aBuffer
.append( lcl_serializeForDisplay( aExpression
.getXPath() ) );
954 // MIP (not binding): iterate over bindings contexts
955 std::vector
<EvaluationContext
> aContext
=
956 pBinding
->getMIPEvaluationContexts();
957 for( std::vector
<EvaluationContext
>::iterator aIter
= aContext
.begin();
958 aIter
!= aContext
.end();
961 aExpression
.evaluate( *aIter
);
962 aBuffer
.append( lcl_serializeForDisplay(aExpression
.getXPath()) );
963 aBuffer
.append( sal_Unicode('\n') );
966 return aBuffer
.makeStringAndClear();
969 sal_Bool
Model::isValidXMLName( const OUString
& sName
)
970 throw( RuntimeException
)
972 return isValidQName( sName
, NULL
);
975 sal_Bool
Model::isValidPrefixName( const OUString
& sName
)
976 throw( RuntimeException
)
978 return ::isValidPrefixName( sName
, NULL
);
981 void Model::setNodeValue(
982 const XNode_t
& xNode
,
983 const rtl::OUString
& sValue
)
984 throw( RuntimeException
)
986 setSimpleContent( xNode
, sValue
);
991 // helper functions from model_helper.hxx
994 void xforms::getInstanceData(
995 const Sequence
<PropertyValue
>& aValues
,
997 Reference
<XDocument
>* pInstance
,
1001 sal_Int32 nValues
= aValues
.getLength();
1002 const PropertyValue
* pValues
= aValues
.getConstArray();
1003 for( sal_Int32 n
= 0; n
< nValues
; n
++ )
1005 const PropertyValue
& rValue
= pValues
[n
];
1006 #define PROP(NAME) \
1007 if( p##NAME != NULL && \
1008 rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(#NAME)) ) \
1009 rValue.Value >>= (*p##NAME)
1018 void xforms::setInstanceData(
1019 Sequence
<PropertyValue
>& aSequence
,
1020 const OUString
* _pID
,
1021 const Reference
<XDocument
>* _pInstance
,
1022 const OUString
* _pURL
,
1023 const bool* _pURLOnce
)
1025 // get old instance data
1027 Reference
<XDocument
> xInstance
;
1029 bool bURLOnce
= false;
1030 getInstanceData( aSequence
, &sID
, &xInstance
, &sURL
, &bURLOnce
);
1031 const OUString
* pID
= ( sID
.getLength() > 0 ) ? &sID
: NULL
;
1032 const Reference
<XDocument
>* pInstance
= xInstance
.is() ? &xInstance
: NULL
;
1033 const OUString
* pURL
= ( sURL
.getLength() > 0 ) ? &sURL
: NULL
;
1034 const bool* pURLOnce
= ( bURLOnce
&& pURL
!= NULL
) ? &bURLOnce
: NULL
;
1036 // determine new instance data
1037 #define PROP(NAME) if( _p##NAME != NULL ) p##NAME = _p##NAME
1044 // count # of values we want to set
1045 sal_Int32 nCount
= 0;
1046 #define PROP(NAME) if( p##NAME != NULL ) nCount++
1053 // realloc sequence and enter values;
1054 aSequence
.realloc( nCount
);
1055 PropertyValue
* pSequence
= aSequence
.getArray();
1056 sal_Int32 nIndex
= 0;
1057 #define PROP(NAME) \
1058 if( p##NAME != NULL ) \
1060 pSequence[ nIndex ].Name = OUSTRING(#NAME); \
1061 pSequence[ nIndex ].Value <<= *p##NAME; \