bump product version to 5.0.4.1
[LibreOffice.git] / forms / source / xforms / model_ui.cxx
blob37c122efe3147cadf8dfb2c4c1e03d9eebad0a97
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #include "model.hxx"
22 #include "model_helper.hxx"
23 #include "mip.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>
36 // UNO classes
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(),
88 "has or has not?" );
90 switch( mxDataTypes->getDataType( sTypeName )->getTypeClass() )
92 case com::sun::star::xsd::DataTypeClass::BOOLEAN:
93 sService = "com.sun.star.form.component.CheckBox";
94 break;
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";
99 break;
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:
116 default:
117 // keep default
118 break;
122 return sService;
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();
137 xIter != NULL;
138 xIter = xIter->getNextSibling() )
140 if( xIter->getNodeType() == xNode->getNodeType() &&
141 xIter->getNodeName() == xNode->getNodeName() &&
142 xIter->getNamespaceURI() == xNode->getNamespaceURI() )
144 nFound++;
145 if( xIter == xNode )
146 nPosition = nFound;
150 OSL_ENSURE( nFound > 0 && nPosition > 0, "node not found???" );
152 // output position (if necessary)
153 if( nFound > 1 )
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,
175 Model* pModel )
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
193 OUString sId;
194 Reference<XDocument> xInstance;
195 getInstanceData( aValues, &sId, &xInstance, NULL, NULL );
197 // now check whether this was our instance:
198 if( xInstance == xDoc )
199 sInstanceName = sId;
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 );
230 break;
232 case NodeType_TEXT_NODE:
233 lcl_OutPosition( aBuffer, xCurrent );
234 aBuffer.insert( 0, "text()" );
235 break;
237 case NodeType_ATTRIBUTE_NODE:
238 lcl_OutName( aBuffer, xCurrent );
239 aBuffer.insert( 0, '@' );
240 break;
242 case NodeType_DOCUMENT_NODE:
243 // check for which instance we have
244 lcl_OutInstance( aBuffer, xCurrent, this );
245 break;
247 default:
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, '/' );
254 break;
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) );
283 return bWhitespace;
286 OUString Model::getNodeDisplayName( const XNode_t& xNode,
287 sal_Bool bDetail )
288 throw( RuntimeException, std::exception )
290 OUStringBuffer aBuffer;
292 switch( xNode->getNodeType() )
294 case NodeType_ELEMENT_NODE:
295 lcl_OutName( aBuffer, xNode );
296 break;
298 case NodeType_TEXT_NODE:
300 OUString sContent = xNode->getNodeValue();
301 if( bDetail || ! lcl_isWhitespace( sContent ) )
303 aBuffer = aBuffer + "\"" + Convert::collapseWhitespace( sContent ) + "\"";
306 break;
308 case NodeType_ATTRIBUTE_NODE:
309 lcl_OutName( aBuffer, xNode );
310 aBuffer.insert( 0, '@' );
311 break;
313 case NodeType_DOCUMENT_NODE:
314 if( xNode == getDefaultInstance() )
315 aBuffer.append( '/' );
316 else
317 lcl_OutInstance( aBuffer, xNode, this );
318 break;
320 default:
321 // unknown type? fail!
322 OSL_FAIL( "unknown node type!" );
323 break;
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 );
339 break;
341 case NodeType_TEXT_NODE:
342 case NodeType_DOCUMENT_NODE:
343 default:
344 // unknown type? fail!
345 OSL_FAIL( "no name for this node type!" );
346 break;
349 return aBuffer.makeStringAndClear();
352 OUString Model::getBindingName( const XPropertySet_t& xBinding,
353 sal_Bool /*bDetail*/ )
354 throw( RuntimeException, std::exception )
356 OUString sID;
357 xBinding->getPropertyValue( "BindingID" ) >>= sID;
358 OUString sExpression;
359 xBinding->getPropertyValue( "BindingExpression" ) >>= sExpression;
361 OUString sRet;
362 if( !sID.isEmpty() )
364 sRet = sID + " (" + sExpression + ") ";
366 else
367 sRet = sExpression;
369 return sRet;
372 OUString Model::getSubmissionName( const XPropertySet_t& xSubmission,
373 sal_Bool /*bDetail*/ )
374 throw( RuntimeException, std::exception )
376 OUString sID;
377 xSubmission->getPropertyValue( "ID" ) >>= sID;
378 return 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
389 // MIPs table...
390 pBinding->deferNotifications(true);
392 // Copy the propertyset and return result...
393 XPropertySet_t xNewBinding(pBinding);
394 copy( xBinding, xNewBinding );
395 return 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,
411 sal_Bool bURLOnce )
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" ),
420 UNO_QUERY_THROW ) );
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 );
428 return xInstance;
431 static sal_Int32 lcl_findProp( const PropertyValue* pValues,
432 sal_Int32 nLength,
433 const OUString& rName )
435 bool bFound = false;
436 sal_Int32 n = 0;
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();
448 sal_Int32 n = 0;
449 bool bFound = false;
450 for( ; !bFound && n < nLength; n++ )
452 OUString sName;
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,
460 const OUString& sTo,
461 const OUString& sURL,
462 sal_Bool bURLOnce )
463 throw( RuntimeException, std::exception )
465 sal_Int32 nPos = lcl_findInstance( mpInstances, sFrom );
466 if( nPos != -1 )
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" );
473 if( nProp == -1 )
475 // add name property
476 aSeq.realloc( nLength + 1 );
477 pSeq = aSeq.getArray();
478 pSeq[ nLength ].Name = "ID";
479 nProp = nLength;
482 // change name
483 pSeq[ nProp ].Value <<= sTo;
485 // change url
486 nProp = lcl_findProp( pSeq, nLength, "URL" );
487 if(nProp != -1)
488 pSeq[ nProp ].Value <<= sURL;
490 // change urlonce
491 nProp = lcl_findProp( pSeq, nLength, "URLOnce" );
492 if(nProp != -1)
493 pSeq[ nProp ].Value <<= bURLOnce;
495 // set instance
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 );
504 if( nPos != -1 )
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 );
513 if( xSupplier.is() )
515 xRet = xSupplier->getXForms();
517 return xRet;
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 );
526 if( xModels.is()
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 ) );
538 return 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 );
547 if( xModels.is()
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 );
563 if( xModels.is()
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;
575 if( xParent.is()
576 && isValidXMLName( sName ) )
578 // TODO: implement proper namespace handling
579 xNode.set( xParent->getOwnerDocument()->createElement( sName ),
580 UNO_QUERY );
582 return xNode;
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 );
591 if( xParent.is()
592 && xElement.is()
593 && isValidXMLName( sName ) )
595 // handle case where attribute already exists
596 sal_Int32 nCount = 0;
597 OUString sUniqueName = sName;
598 while( xElement->hasAttribute( sUniqueName ) )
600 nCount++;
601 sUniqueName = sName + OUString::number( nCount );
604 // TODO: implement proper namespace handling
605 xNode.set( xParent->getOwnerDocument()->createAttribute( sUniqueName ),
606 UNO_QUERY );
608 return xNode;
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 )
617 return xNode;
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 ) )
623 return xNode;
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();
650 xCurrent.is();
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() );
664 // replace node
665 Reference<XNode> xParent = xNode->getParentNode();
666 xParent->removeChild( xNode );
667 xNew = xParent->appendChild( xAttr );
669 else
671 OSL_FAIL( "can't rename this node type" );
674 // adjust bindings (if necessary):
675 if( xNew.is() )
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,
696 sal_Bool bCreate )
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;
724 if( nNodes == 1 )
725 nScore ++;
726 if( pBinding->isSimpleBindingExpression() )
727 nScore ++;
729 // if we found a better binding, remember it
730 if( nScore > nBestScore )
732 pBestBinding = pBinding;
733 nBestScore = nScore;
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 );
749 return 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 )
760 OUString sResult;
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 )
767 nQuote = '\'';
769 sResult = _rxAttrNode->getName() + "=" + OUString(nQuote) + sValue + OUString(nQuote) + " ";
771 return sResult;
774 static OUString lcl_serializeForDisplay( const Reference<XNodeList>& xNodes )
776 OUString sResult;
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();
797 break;
798 case NodeType_ATTRIBUTE_NODE:
800 Reference< XAttr > xAttr( xCurrent, UNO_QUERY );
801 if ( xAttr.is() )
803 sResult += lcl_serializeForDisplay( xAttr );
804 ++nAttributeNodes;
807 continue;
809 default:
810 break;
813 // append node
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
820 return sResult;
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>(),
836 sal_True );
839 // well, the serialization prepends XML header(s) that we need to
840 // remove first.
841 OUStringBuffer aBuffer;
842 while( ! xTextInputStream->isEOF() )
844 OUString sLine = xTextInputStream->readLine();
845 if( !sLine.isEmpty()
846 && !sLine.startsWith( "<?xml" ) )
848 aBuffer.append( sLine );
849 aBuffer.append( '\n' );
852 sResult = aBuffer.makeStringAndClear();
854 return sResult;
857 static OUString lcl_serializeForDisplay( const Reference<XXPathObject>& xResult )
859 // error handling first
860 if( ! xResult.is() )
861 return getResource( RID_STR_XFORMS_CANT_EVALUATE );
864 // TODO: localize
865 OUStringBuffer aBuffer;
867 switch( xResult->getObjectType() )
869 case XPathObjectType_XPATH_BOOLEAN:
870 aBuffer.append( xResult->getBoolean()
871 ? OUString("true")
872 : OUString("false") );
873 break;
875 case XPathObjectType_XPATH_STRING:
876 aBuffer = aBuffer + "\"" + xResult->getString() + "\"";
877 break;
879 case XPathObjectType_XPATH_NODESET:
880 aBuffer.append( lcl_serializeForDisplay( xResult->getNodeList() ) );
881 break;
883 case XPathObjectType_XPATH_NUMBER:
884 aBuffer.append( xResult->getDouble() );
885 break;
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:
893 default:
894 // TODO: localized error message?
895 break;
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() ) );
921 else
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();
928 ++aIter )
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,
965 OUString* pID,
966 Reference<XDocument>* pInstance,
967 OUString* pURL,
968 bool* pURLOnce )
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];
975 #define PROP(NAME) \
976 if( p##NAME != NULL && \
977 rValue.Name == #NAME ) \
978 rValue.Value >>= (*p##NAME)
979 PROP(ID);
980 PROP(Instance);
981 PROP(URL);
982 PROP(URLOnce);
983 #undef PROP
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
995 OUString sID;
996 Reference<XDocument> xInstance;
997 OUString sURL;
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
1007 PROP(ID);
1008 PROP(Instance);
1009 PROP(URL);
1010 PROP(URLOnce);
1011 #undef PROP
1013 // count # of values we want to set
1014 sal_Int32 nCount = 0;
1015 #define PROP(NAME) if( p##NAME != NULL ) nCount++
1016 PROP(ID);
1017 PROP(Instance);
1018 PROP(URL);
1019 PROP(URLOnce);
1020 #undef PROP
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; \
1031 nIndex++; \
1033 PROP(ID);
1034 PROP(Instance);
1035 PROP(URL);
1036 PROP(URLOnce);
1037 #undef PROP
1040 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */