1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_forms.hxx"
26
27 #include "model.hxx"
28 #include "model_helper.hxx"
29 #include "mip.hxx"
30 #include "evaluationcontext.hxx"
31 #include "unohelper.hxx"
32 #include "submission/serialization_app_xml.hxx"
33 #include "resourcehelper.hxx"
34 #include "xmlhelper.hxx"
35 #include "convert.hxx"
36
37 #include <rtl/ustring.hxx>
38 #include <rtl/ustrbuf.hxx>
39 #include <tools/debug.hxx>
40
41 // UNO classes
42 #include <com/sun/star/xml/dom/XNode.hpp>
43 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
44 #include <com/sun/star/xml/dom/XDocumentFragment.hpp>
45 #include <com/sun/star/xml/dom/XNamedNodeMap.hpp>
46 #include <com/sun/star/xml/xpath/XXPathObject.hpp>
47 #include <com/sun/star/xml/xpath/XPathObjectType.hpp>
48 #include <com/sun/star/beans/PropertyValue.hpp>
49 #include <com/sun/star/io/XInputStream.hpp>
50 #include <com/sun/star/io/XActiveDataSink.hpp>
51 #include <com/sun/star/io/XTextInputStream.hpp>
52 #include <com/sun/star/container/XEnumeration.hpp>
53 #include <com/sun/star/container/XNameContainer.hpp>
54 #include <com/sun/star/frame/XModel.hpp>
55 #include <com/sun/star/xforms/XFormsSupplier.hpp>
56 #include <com/sun/star/xforms/XDataTypeRepository.hpp>
57 #include <com/sun/star/xsd/XDataType.hpp>
58 #include <com/sun/star/xsd/DataTypeClass.hpp>
59
60
61 using rtl::OUString;
62 using rtl::OUStringBuffer;
63 using com::sun::star::beans::PropertyValue;
64 using com::sun::star::io::XInputStream;
65 using com::sun::star::io::XActiveDataSink;
66 using com::sun::star::io::XTextInputStream;
67 using com::sun::star::container::XEnumeration;
68 using com::sun::star::container::XNameContainer;
69 using com::sun::star::xforms::XFormsSupplier;
70
71 using namespace xforms;
72 using namespace com::sun::star::uno;
73 using namespace com::sun::star::xml::dom;
74 using namespace com::sun::star::xml::xpath;
75
76
77
78 //
79 // implement XFormsUIHelper1
80 //
81
getDefaultServiceNameForNode(const XNode_t & xNode)82 OUString Model::getDefaultServiceNameForNode( const XNode_t& xNode )
83 {
84 // determine service for control. string/text field is default.
85 OUString sService = OUSTRING("com.sun.star.form.component.TextField");
86
87 // query repository for suitable type
88 OSL_ENSURE( mxDataTypes.is(), "no type repository?" );
89 OUString sTypeName = queryMIP( xNode ).getTypeName();
90 if( mxDataTypes->hasByName( sTypeName ) )
91 {
92 OSL_ENSURE( mxDataTypes->getDataType( sTypeName ).is(),
93 "has or has not?" );
94
95 switch( mxDataTypes->getDataType( sTypeName )->getTypeClass() )
96 {
97 case com::sun::star::xsd::DataTypeClass::BOOLEAN:
98 sService = OUSTRING("com.sun.star.form.component.CheckBox");
99 break;
100 case com::sun::star::xsd::DataTypeClass::DOUBLE:
101 case com::sun::star::xsd::DataTypeClass::DECIMAL:
102 case com::sun::star::xsd::DataTypeClass::FLOAT:
103 sService = OUSTRING("com.sun.star.form.component.NumericField");
104 break;
105
106 case com::sun::star::xsd::DataTypeClass::STRING:
107 case com::sun::star::xsd::DataTypeClass::DURATION:
108 case com::sun::star::xsd::DataTypeClass::DATETIME:
109 case com::sun::star::xsd::DataTypeClass::TIME:
110 case com::sun::star::xsd::DataTypeClass::DATE:
111 case com::sun::star::xsd::DataTypeClass::gYearMonth:
112 case com::sun::star::xsd::DataTypeClass::gYear:
113 case com::sun::star::xsd::DataTypeClass::gMonthDay:
114 case com::sun::star::xsd::DataTypeClass::gDay:
115 case com::sun::star::xsd::DataTypeClass::gMonth:
116 case com::sun::star::xsd::DataTypeClass::hexBinary:
117 case com::sun::star::xsd::DataTypeClass::base64Binary:
118 case com::sun::star::xsd::DataTypeClass::anyURI:
119 case com::sun::star::xsd::DataTypeClass::QName:
120 case com::sun::star::xsd::DataTypeClass::NOTATION:
121 default:
122 // keep default
123 break;
124 }
125 }
126
127 return sService;
128 }
129
130
lcl_OutPosition(OUStringBuffer & rBuffer,const Reference<XNode> & xNode)131 void lcl_OutPosition( OUStringBuffer& rBuffer,
132 const Reference<XNode>& xNode )
133 {
134 OSL_ENSURE( xNode->getParentNode().is(), "need parent" );
135
136 // count # of occurrences of this node
137 sal_Int32 nFound = 0;
138 sal_Int32 nPosition = -1;
139 if( xNode->getParentNode().is() )
140 {
141 for( Reference<XNode> xIter = xNode->getParentNode()->getFirstChild();
142 xIter != NULL;
143 xIter = xIter->getNextSibling() )
144 {
145 if( xIter->getNodeType() == xNode->getNodeType() &&
146 xIter->getNodeName() == xNode->getNodeName() &&
147 xIter->getNamespaceURI() == xNode->getNamespaceURI() )
148 {
149 nFound++;
150 if( xIter == xNode )
151 nPosition = nFound;
152 }
153 }
154 }
155 OSL_ENSURE( nFound > 0 && nPosition > 0, "node not found???" );
156
157 // output position (if necessary)
158 if( nFound > 1 )
159 {
160 rBuffer.insert( 0, sal_Unicode(']') );
161 rBuffer.insert( 0, nPosition );
162 rBuffer.insert( 0, sal_Unicode('[') );
163 }
164 }
165
lcl_OutName(OUStringBuffer & rBuffer,const Reference<XNode> & xNode)166 void lcl_OutName( OUStringBuffer& rBuffer,
167 const Reference<XNode>& xNode )
168 {
169 rBuffer.insert( 0, xNode->getNodeName() );
170 OUString sPrefix = xNode->getPrefix();
171 if( sPrefix.getLength() > 0 )
172 {
173 rBuffer.insert( 0, sal_Unicode(':') );
174 rBuffer.insert( 0, sPrefix );
175 }
176 }
177
lcl_OutInstance(OUStringBuffer & rBuffer,const Reference<XNode> & xNode,Model * pModel)178 void lcl_OutInstance( OUStringBuffer& rBuffer,
179 const Reference<XNode>& xNode,
180 Model* pModel )
181 {
182 Reference<XDocument> xDoc = xNode->getOwnerDocument();
183
184 if( xDoc != pModel->getDefaultInstance() )
185 {
186 rBuffer.insert( 0, OUSTRING("')") );
187
188 // iterate over instances, and find the right one
189 OUString sInstanceName;
190 Reference<XEnumeration> xEnum =
191 pModel->getInstances()->createEnumeration();
192 while( ( sInstanceName.getLength() == 0 ) && xEnum->hasMoreElements() )
193 {
194 Sequence<PropertyValue> aValues;
195 xEnum->nextElement() >>= aValues;
196
197 // get ID and instance
198 OUString sId;
199 Reference<XDocument> xInstance;
200 getInstanceData( aValues, &sId, &xInstance, NULL, NULL );
201
202 // now check whether this was our instance:
203 if( xInstance == xDoc )
204 sInstanceName = sId;
205 }
206
207 rBuffer.insert( 0, sInstanceName );
208 rBuffer.insert( 0, OUSTRING("instance('") );
209 }
210 }
211
getDefaultBindingExpressionForNode(const XNode_t & xNode,const EvaluationContext & rContext)212 OUString Model::getDefaultBindingExpressionForNode(
213 const XNode_t& xNode,
214 const EvaluationContext& rContext)
215 {
216 OSL_ENSURE( xNode.is(), "need node" );
217
218 // iterate upwards and put sections into the expression buffer.
219 // Stop iteration either at context node (relative expression) or
220 // at document root, whichever occurs first.
221 OUStringBuffer aBuffer;
222 for( Reference<XNode> xCurrent = xNode;
223 xCurrent.is() && xCurrent != rContext.mxContextNode;
224 xCurrent = xCurrent->getParentNode() )
225 {
226 // insert a '/' for every step except the first
227 if( aBuffer.getLength() > 0 )
228 aBuffer.insert( 0, sal_Unicode('/') );
229
230 switch( xCurrent->getNodeType() )
231 {
232 case NodeType_ELEMENT_NODE:
233 lcl_OutPosition( aBuffer, xCurrent );
234 lcl_OutName( aBuffer, xCurrent );
235 break;
236
237 case NodeType_TEXT_NODE:
238 lcl_OutPosition( aBuffer, xCurrent );
239 aBuffer.insert( 0, OUSTRING("text()") );
240 break;
241
242 case NodeType_ATTRIBUTE_NODE:
243 lcl_OutName( aBuffer, xCurrent );
244 aBuffer.insert( 0, sal_Unicode('@') );
245 break;
246
247 case NodeType_DOCUMENT_NODE:
248 // check for which instance we have
249 lcl_OutInstance( aBuffer, xCurrent, this );
250 break;
251
252 default:
253 // unknown type? fail!
254 OSL_ENSURE( false, "unknown node type!" );
255 xCurrent.set( NULL );
256 aBuffer.makeStringAndClear();
257 // we'll remove the slash below
258 aBuffer.insert( 0, sal_Unicode('/') );
259 break;
260 }
261 }
262
263 return aBuffer.makeStringAndClear();
264 }
265
266
267
getDefaultBindingExpressionForNode(const XNode_t & xNode)268 OUString Model::getDefaultBindingExpressionForNode( const XNode_t& xNode )
269 {
270 return getDefaultBindingExpressionForNode( xNode, getEvaluationContext() );
271 }
272
lcl_isWhitespace(const OUString & rString)273 bool lcl_isWhitespace( const OUString& rString )
274 {
275 sal_Int32 nLength = rString.getLength();
276 const sal_Unicode* pStr = rString.getStr();
277
278 bool bWhitespace = true;
279 for( sal_Int32 i = 0; bWhitespace && ( i < nLength ); i++ )
280 {
281 sal_Unicode c = pStr[i];
282 bWhitespace = ( c == sal_Unicode(0x09) ||
283 c == sal_Unicode(0x0A) ||
284 c == sal_Unicode(0x0D) ||
285 c == sal_Unicode(0x20) );
286 }
287 return bWhitespace;
288 }
289
getNodeDisplayName(const XNode_t & xNode,sal_Bool bDetail)290 OUString Model::getNodeDisplayName( const XNode_t& xNode,
291 sal_Bool bDetail )
292 {
293 OUStringBuffer aBuffer;
294
295 switch( xNode->getNodeType() )
296 {
297 case NodeType_ELEMENT_NODE:
298 lcl_OutName( aBuffer, xNode );
299 break;
300
301 case NodeType_TEXT_NODE:
302 {
303 OUString sContent = xNode->getNodeValue();
304 if( bDetail || ! lcl_isWhitespace( sContent ) )
305 {
306 aBuffer.append( sal_Unicode('"') );
307 aBuffer.append( Convert::collapseWhitespace( sContent ) );
308 aBuffer.append( sal_Unicode('"') );
309 }
310 }
311 break;
312
313 case NodeType_ATTRIBUTE_NODE:
314 lcl_OutName( aBuffer, xNode );
315 aBuffer.insert( 0, sal_Unicode('@') );
316 break;
317
318 case NodeType_DOCUMENT_NODE:
319 if( xNode == getDefaultInstance() )
320 aBuffer.append( sal_Unicode('/') );
321 else
322 lcl_OutInstance( aBuffer, xNode, this );
323 break;
324
325 default:
326 // unknown type? fail!
327 OSL_ENSURE( false, "unknown node type!" );
328 break;
329 }
330
331 return aBuffer.makeStringAndClear();
332 }
333
getNodeName(const XNode_t & xNode)334 OUString Model::getNodeName( const XNode_t& xNode )
335 {
336 OUStringBuffer aBuffer;
337
338 switch( xNode->getNodeType() )
339 {
340 case NodeType_ELEMENT_NODE:
341 case NodeType_ATTRIBUTE_NODE:
342 lcl_OutName( aBuffer, xNode );
343 break;
344
345 case NodeType_TEXT_NODE:
346 case NodeType_DOCUMENT_NODE:
347 default:
348 // unknown type? fail!
349 OSL_ENSURE( false, "no name for this node type!" );
350 break;
351 }
352
353 return aBuffer.makeStringAndClear();
354 }
355
getBindingName(const XPropertySet_t & xBinding,sal_Bool)356 OUString Model::getBindingName( const XPropertySet_t& xBinding,
357 sal_Bool /*bDetail*/ )
358 {
359 OUString sID;
360 xBinding->getPropertyValue( OUSTRING("BindingID" ) ) >>= sID;
361 OUString sExpression;
362 xBinding->getPropertyValue( OUSTRING("BindingExpression" ) ) >>= sExpression;
363
364 OUStringBuffer aBuffer;
365 if( sID.getLength() > 0 )
366 {
367 aBuffer.append( sID );
368 aBuffer.append( OUSTRING(" (" ));
369 aBuffer.append( sExpression );
370 aBuffer.append( OUSTRING(")" ));
371 }
372 else
373 aBuffer.append( sExpression );
374
375 return aBuffer.makeStringAndClear();
376 }
377
getSubmissionName(const XPropertySet_t & xSubmission,sal_Bool)378 OUString Model::getSubmissionName( const XPropertySet_t& xSubmission,
379 sal_Bool /*bDetail*/ )
380 {
381 OUString sID;
382 xSubmission->getPropertyValue( OUSTRING("ID") ) >>= sID;
383 return sID;
384 }
385
cloneBindingAsGhost(const XPropertySet_t & xBinding)386 Model::XPropertySet_t Model::cloneBindingAsGhost( const XPropertySet_t &xBinding )
387 {
388 // Create a new binding instance first...
389 Binding *pBinding = new Binding();
390
391 // ...and bump up the "defered notification counter"
392 // to prevent this binding from contributing to the
393 // MIPs table...
394 pBinding->deferNotifications(true);
395
396 // Copy the propertyset and return result...
397 XPropertySet_t xNewBinding(pBinding);
398 copy( xBinding, xNewBinding );
399 return xNewBinding;
400 }
401
removeBindingIfUseless(const XPropertySet_t & xBinding)402 void Model::removeBindingIfUseless( const XPropertySet_t& xBinding )
403 {
404 Binding* pBinding = Binding::getBinding( xBinding );
405 if( pBinding != NULL )
406 {
407 if( ! pBinding->isUseful() )
408 mpBindings->removeItem( pBinding );
409 }
410 }
411
newInstance(const rtl::OUString & sName,const rtl::OUString & sURL,sal_Bool bURLOnce)412 Model::XDocument_t Model::newInstance( const rtl::OUString& sName,
413 const rtl::OUString& sURL,
414 sal_Bool bURLOnce )
415 {
416 // create a default instance with <instanceData> element
417 XDocument_t xInstance = getDocumentBuilder()->newDocument();
418 DBG_ASSERT( xInstance.is(), "failed to create DOM instance" );
419
420 Reference<XNode>( xInstance, UNO_QUERY_THROW )->appendChild(
421 Reference<XNode>( xInstance->createElement( OUSTRING("instanceData") ),
422 UNO_QUERY_THROW ) );
423
424 Sequence<PropertyValue> aSequence;
425 bool bOnce = bURLOnce; // bool, so we can take address in setInstanceData
426 setInstanceData( aSequence, &sName, &xInstance, &sURL, &bOnce );
427 sal_Int32 nInstance = mpInstances->addItem( aSequence );
428 loadInstance( nInstance );
429
430 return xInstance;
431 }
432
lcl_findProp(const PropertyValue * pValues,sal_Int32 nLength,const rtl::OUString & rName)433 sal_Int32 lcl_findProp( const PropertyValue* pValues,
434 sal_Int32 nLength,
435 const rtl::OUString& rName )
436 {
437 bool bFound = false;
438 sal_Int32 n = 0;
439 for( ; !bFound && n < nLength; n++ )
440 {
441 bFound = ( pValues[n].Name == rName );
442 }
443 return bFound ? ( n - 1) : -1;
444 }
445
lcl_findInstance(const InstanceCollection * pInstances,const rtl::OUString & rName)446 sal_Int32 xforms::lcl_findInstance( const InstanceCollection* pInstances,
447 const rtl::OUString& rName )
448 {
449 sal_Int32 nLength = pInstances->countItems();
450 sal_Int32 n = 0;
451 bool bFound = false;
452 for( ; !bFound && n < nLength; n++ )
453 {
454 OUString sName;
455 getInstanceData( pInstances->getItem( n ), &sName, NULL, NULL, NULL );
456 bFound = ( sName == rName );
457 }
458 return bFound ? ( n - 1 ) : -1;
459 }
460
renameInstance(const rtl::OUString & sFrom,const rtl::OUString & sTo,const rtl::OUString & sURL,sal_Bool bURLOnce)461 void Model::renameInstance( const rtl::OUString& sFrom,
462 const rtl::OUString& sTo,
463 const rtl::OUString& sURL,
464 sal_Bool bURLOnce )
465 {
466 sal_Int32 nPos = lcl_findInstance( mpInstances, sFrom );
467 if( nPos != -1 )
468 {
469 Sequence<PropertyValue> aSeq = mpInstances->getItem( nPos );
470 PropertyValue* pSeq = aSeq.getArray();
471 sal_Int32 nLength = aSeq.getLength();
472
473 sal_Int32 nProp = lcl_findProp( pSeq, nLength, OUSTRING("ID") );
474 if( nProp == -1 )
475 {
476 // add name property
477 aSeq.realloc( nLength + 1 );
478 pSeq = aSeq.getArray();
479 pSeq[ nLength ].Name = OUSTRING("ID");
480 nProp = nLength;
481 }
482
483 // change name
484 pSeq[ nProp ].Value <<= sTo;
485
486 // change url
487 nProp = lcl_findProp( pSeq, nLength, OUSTRING("URL") );
488 if(nProp != -1)
489 pSeq[ nProp ].Value <<= sURL;
490
491 // change urlonce
492 nProp = lcl_findProp( pSeq, nLength, OUSTRING("URLOnce") );
493 if(nProp != -1)
494 pSeq[ nProp ].Value <<= bURLOnce;
495
496 // set instance
497 mpInstances->setItem( nPos, aSeq );
498 }
499 }
500
removeInstance(const rtl::OUString & sName)501 void Model::removeInstance( const rtl::OUString& sName )
502 {
503 sal_Int32 nPos = lcl_findInstance( mpInstances, sName );
504 if( nPos != -1 )
505 mpInstances->removeItem( mpInstances->getItem( nPos ) );
506 }
507
lcl_getModels(const Reference<com::sun::star::frame::XModel> & xComponent)508 Reference<XNameContainer> lcl_getModels(
509 const Reference<com::sun::star::frame::XModel>& xComponent )
510 {
511 Reference<XNameContainer> xRet;
512 Reference<XFormsSupplier> xSupplier( xComponent, UNO_QUERY );
513 if( xSupplier.is() )
514 {
515 xRet = xSupplier->getXForms();
516 }
517 return xRet;
518 }
519
newModel(const Reference<com::sun::star::frame::XModel> & xCmp,const OUString & sName)520 Model::XModel_t Model::newModel( const Reference<com::sun::star::frame::XModel>& xCmp,
521 const OUString& sName )
522 {
523 Model::XModel_t xModel;
524 Reference<XNameContainer> xModels = lcl_getModels( xCmp );
525 if( xModels.is()
526 && ! xModels->hasByName( sName ) )
527 {
528 Model* pModel = new Model();
529 xModel.set( pModel );
530
531 pModel->setID( sName );
532 pModel->newInstance( OUString(), OUString(), sal_False );
533 pModel->initialize();
534 xModels->insertByName( sName, makeAny( xModel ) );
535 }
536
537 return xModel;
538 }
539
renameModel(const Reference<com::sun::star::frame::XModel> & xCmp,const OUString & sFrom,const OUString & sTo)540 void Model::renameModel( const Reference<com::sun::star::frame::XModel>& xCmp,
541 const OUString& sFrom,
542 const OUString& sTo )
543 {
544 Reference<XNameContainer> xModels = lcl_getModels( xCmp );
545 if( xModels.is()
546 && xModels->hasByName( sFrom )
547 && ! xModels->hasByName( sTo ) )
548 {
549 Reference<XModel> xModel( xModels->getByName( sFrom ), UNO_QUERY );
550 xModel->setID( sTo );
551 xModels->insertByName( sTo, makeAny( xModel ) );
552 xModels->removeByName( sFrom );
553 }
554 }
555
removeModel(const Reference<com::sun::star::frame::XModel> & xCmp,const OUString & sName)556 void Model::removeModel( const Reference<com::sun::star::frame::XModel>& xCmp,
557 const OUString& sName )
558 {
559 Reference<XNameContainer> xModels = lcl_getModels( xCmp );
560 if( xModels.is()
561 && xModels->hasByName( sName ) )
562 {
563 xModels->removeByName( sName );
564 }
565 }
566
createElement(const XNode_t & xParent,const OUString & sName)567 Model::XNode_t Model::createElement( const XNode_t& xParent,
568 const OUString& sName )
569 {
570 Reference<XNode> xNode;
571 if( xParent.is()
572 && isValidXMLName( sName ) )
573 {
574 // TODO: implement proper namespace handling
575 xNode.set( xParent->getOwnerDocument()->createElement( sName ),
576 UNO_QUERY );
577 }
578 return xNode;
579 }
580
createAttribute(const XNode_t & xParent,const OUString & sName)581 Model::XNode_t Model::createAttribute( const XNode_t& xParent,
582 const OUString& sName )
583 {
584 Reference<XNode> xNode;
585 Reference<XElement> xElement( xParent, UNO_QUERY );
586 if( xParent.is()
587 && xElement.is()
588 && isValidXMLName( sName ) )
589 {
590 // handle case where attribute already exists
591 sal_Int32 nCount = 0;
592 OUString sUniqueName = sName;
593 while( xElement->hasAttribute( sUniqueName ) )
594 {
595 nCount++;
596 sUniqueName = sName + OUString::valueOf( nCount );
597 }
598
599 // TODO: implement proper namespace handling
600 xNode.set( xParent->getOwnerDocument()->createAttribute( sUniqueName ),
601 UNO_QUERY );
602 }
603 return xNode;
604 }
605
renameNode(const XNode_t & xNode,const rtl::OUString & sName)606 Model::XNode_t Model::renameNode( const XNode_t& xNode,
607 const rtl::OUString& sName )
608 {
609 // early out if we don't have to change the name
610 if( xNode->getNodeName() == sName )
611 return xNode;
612
613 // refuse to change name if its an attribute, and the name is already used
614 if( xNode->getNodeType() == NodeType_ATTRIBUTE_NODE
615 && xNode->getParentNode().is()
616 && Reference<XElement>(xNode->getParentNode(), UNO_QUERY_THROW)->hasAttribute( sName ) )
617 return xNode;
618
619 // note old binding expression so we can adjust bindings below
620 OUString sOldDefaultBindingExpression =
621 getDefaultBindingExpressionForNode( xNode );
622
623 Reference<XDocument> xDoc = xNode->getOwnerDocument();
624 Reference<XNode> xNew;
625 if( xNode->getNodeType() == NodeType_ELEMENT_NODE )
626 {
627 Reference<XElement> xElem = xDoc->createElement( sName );
628 xNew.set( xElem, UNO_QUERY );
629
630 // iterate over all attributes and append them to the new element
631 Reference<XElement> xOldElem( xNode, UNO_QUERY );
632 OSL_ENSURE( xNode.is(), "no element?" );
633
634 Reference<XNamedNodeMap> xMap = xNode->getAttributes();
635 sal_Int32 nLength = xMap.is() ? xMap->getLength() : 0;
636 for( sal_Int32 n = 0; n < nLength; n++ )
637 {
638 Reference<XAttr> xAttr( xMap->item(n), UNO_QUERY );
639 xElem->setAttributeNode( xOldElem->removeAttributeNode( xAttr ) );
640 }
641
642 // iterate over all children and append them to the new element
643 for( Reference<XNode> xCurrent = xNode->getFirstChild();
644 xCurrent.is();
645 xCurrent = xNode->getFirstChild() )
646 {
647 xNew->appendChild( xNode->removeChild( xCurrent ) );
648 }
649
650 xNode->getParentNode()->replaceChild( xNew, xNode );
651 }
652 else if( xNode->getNodeType() == NodeType_ATTRIBUTE_NODE )
653 {
654 // create new attribute
655 Reference<XAttr> xAttr = xDoc->createAttribute( sName );
656 xAttr->setValue( xNode->getNodeValue() );
657
658 // replace node
659 Reference<XNode> xParent = xNode->getParentNode();
660 xParent->removeChild( xNode );
661 xNew = xParent->appendChild( Reference<XNode>( xAttr, UNO_QUERY ) );
662 }
663 else
664 {
665 OSL_ENSURE( false, "can't rename this node type" );
666 }
667
668 // adjust bindings (if necessary):
669 if( xNew.is() )
670 {
671 // iterate over bindings and replace default expressions
672 OUString sNewDefaultBindingExpression =
673 getDefaultBindingExpressionForNode( xNew );
674 for( sal_Int32 n = 0; n < mpBindings->countItems(); n++ )
675 {
676 Binding* pBinding = Binding::getBinding(
677 mpBindings->Collection<XPropertySet_t>::getItem( n ) );
678
679 if( pBinding->getBindingExpression()
680 == sOldDefaultBindingExpression )
681 pBinding->setBindingExpression( sNewDefaultBindingExpression );
682 }
683 }
684
685 // return node; return old node if renaming failed
686 return xNew.is() ? xNew : xNode;
687 }
688
getBindingForNode(const XNode_t & xNode,sal_Bool bCreate)689 Model::XPropertySet_t Model::getBindingForNode( const XNode_t& xNode,
690 sal_Bool bCreate )
691 {
692 OSL_ENSURE( xNode.is(), "no node?" );
693
694 // We will iterate over all bindings and determine the
695 // appropriateness of the respective binding for this node. The
696 // best one will be used. If we don't find any and bCreate is set,
697 // then we will create a suitable binding.
698 Binding* pBestBinding = NULL;
699 sal_Int32 nBestScore = 0;
700
701 for( sal_Int32 n = 0; n < mpBindings->countItems(); n++ )
702 {
703 Binding* pBinding = Binding::getBinding(
704 mpBindings->Collection<XPropertySet_t>::getItem( n ) );
705
706 OSL_ENSURE( pBinding != NULL, "no binding?" );
707 Reference<XNodeList> xNodeList = pBinding->getXNodeList();
708
709 sal_Int32 nNodes = xNodeList.is() ? xNodeList->getLength() : 0;
710 if( nNodes > 0 && xNodeList->item( 0 ) == xNode )
711 {
712 // allright, we found a suitable node. Let's determine how
713 // well it fits. Score:
714 // - bind to exactly this node is better than whole nodeset
715 // - simple binding expressions is better than complex ones
716 sal_Int32 nScore = 0;
717 if( nNodes == 1 )
718 nScore ++;
719 if( pBinding->isSimpleBindingExpression() )
720 nScore ++;
721
722 // if we found a better binding, remember it
723 if( nScore > nBestScore )
724 {
725 pBestBinding = pBinding;
726 nBestScore = nScore;
727 }
728 }
729 }
730
731 // create binding, if none was found and bCreate is set
732 OSL_ENSURE( ( nBestScore == 0 ) == ( pBestBinding == NULL ),
733 "score != binding?" );
734 if( bCreate && pBestBinding == NULL )
735 {
736 pBestBinding = new Binding();
737 pBestBinding->setBindingExpression(
738 getDefaultBindingExpressionForNode( xNode ) );
739 mpBindings->addItem( pBestBinding );
740 }
741
742 return pBestBinding;
743 }
744
removeBindingForNode(const XNode_t &)745 void Model::removeBindingForNode( const XNode_t& )
746 {
747 // determine whether suitable binding is still used
748 }
749
lcl_serializeForDisplay(const Reference<XAttr> & _rxAttrNode)750 OUString lcl_serializeForDisplay( const Reference< XAttr >& _rxAttrNode )
751 {
752 ::rtl::OUString sResult;
753 OSL_ENSURE( _rxAttrNode.is(), "lcl_serializeForDisplay( attr ): invalid argument!" );
754 if ( _rxAttrNode.is() )
755 {
756 ::rtl::OUStringBuffer aBuffer;
757 aBuffer.append( _rxAttrNode->getName() );
758 aBuffer.appendAscii( "=" );
759 ::rtl::OUString sValue = _rxAttrNode->getValue();
760 sal_Unicode nQuote = '"';
761 if ( sValue.indexOf( nQuote ) >= 0 )
762 nQuote = '\'';
763 aBuffer.append( nQuote );
764 aBuffer.append( sValue );
765 aBuffer.append( nQuote );
766 aBuffer.append( (sal_Unicode)' ' );
767 sResult = aBuffer.makeStringAndClear();
768 }
769 return sResult;
770 }
771
lcl_serializeForDisplay(const Reference<XNodeList> & xNodes)772 OUString lcl_serializeForDisplay( const Reference<XNodeList>& xNodes )
773 {
774 ::rtl::OUString sResult;
775
776 // create document fragment
777 Reference<XDocument> xDocument( getDocumentBuilder()->newDocument() );
778 Reference<XDocumentFragment> xFragment(
779 xDocument->createDocumentFragment() );
780 Reference<XNode> xNode( xFragment, UNO_QUERY );
781 OSL_ENSURE( xFragment.is(), "xFragment" );
782 OSL_ENSURE( xNode.is(), "xNode" );
783
784 sal_Int32 nAttributeNodes = 0;
785
786 // attach nodelist to fragment
787 sal_Int32 nLength = xNodes->getLength();
788 for( sal_Int32 i = 0; i < nLength; i++ )
789 {
790 Reference<XNode> xCurrent = xNodes->item( i );
791
792 switch ( xCurrent->getNodeType() )
793 {
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:
799 {
800 Reference< XAttr > xAttr( xCurrent, UNO_QUERY );
801 if ( xAttr.is() )
802 {
803 sResult += lcl_serializeForDisplay( xAttr );
804 ++nAttributeNodes;
805 }
806 }
807 continue;
808
809 default:
810 break;
811 }
812
813 // append node
814 xNode->appendChild( xDocument->importNode( xCurrent, sal_True ) );
815 }
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;
821
822 // serialize fragment
823 CSerializationAppXML aSerialization;
824 aSerialization.setSource( xFragment );
825 aSerialization.serialize();
826
827 // copy stream into buffer
828 Reference<XTextInputStream> xTextInputStream(
829 createInstance( OUSTRING("com.sun.star.io.TextInputStream") ),
830 UNO_QUERY );
831 Reference<XActiveDataSink>( xTextInputStream, UNO_QUERY_THROW )
832 ->setInputStream( aSerialization.getInputStream() );
833
834 /* WORK AROUND for problem in serialization: currently, multiple
835 XML delarations (<?xml...?>) are being written out and we don't
836 want them. When this is fixed, the code below is nice and
837 simple. The current code filters out the declarations.
838 OUString sResult = xTextInputStream->readString( Sequence<sal_Unicode>(),
839 sal_True );
840 */
841
842 // well, the serialization prepends XML header(s) that we need to
843 // remove first.
844 OUStringBuffer aBuffer;
845 while( ! xTextInputStream->isEOF() )
846 {
847 OUString sLine = xTextInputStream->readLine();
848 if( sLine.getLength() > 0
849 && sLine.compareToAscii( "<?xml", 5 ) != 0 )
850 {
851 aBuffer.append( sLine );
852 aBuffer.append( sal_Unicode('\n') );
853 }
854 }
855 sResult = aBuffer.makeStringAndClear();
856
857 return sResult;
858 }
859
lcl_serializeForDisplay(const Reference<XXPathObject> & xResult)860 OUString lcl_serializeForDisplay( const Reference<XXPathObject>& xResult )
861 {
862 // error handling first
863 if( ! xResult.is() )
864 return getResource( RID_STR_XFORMS_CANT_EVALUATE );
865
866
867 // TODO: localize
868 OUStringBuffer aBuffer;
869
870 switch( xResult->getObjectType() )
871 {
872 case XPathObjectType_XPATH_BOOLEAN:
873 aBuffer.append( xResult->getBoolean()
874 ? OUSTRING("true")
875 : OUSTRING("false") );
876 break;
877
878 case XPathObjectType_XPATH_STRING:
879 aBuffer.append( sal_Unicode('"') );
880 aBuffer.append( xResult->getString() );
881 aBuffer.append( sal_Unicode('"') );
882 break;
883
884 case XPathObjectType_XPATH_NODESET:
885 aBuffer.append( lcl_serializeForDisplay( xResult->getNodeList() ) );
886 break;
887
888 case XPathObjectType_XPATH_NUMBER:
889 aBuffer.append( xResult->getDouble() );
890 break;
891
892 case XPathObjectType_XPATH_UNDEFINED:
893 case XPathObjectType_XPATH_POINT:
894 case XPathObjectType_XPATH_RANGE:
895 case XPathObjectType_XPATH_LOCATIONSET:
896 case XPathObjectType_XPATH_USERS:
897 case XPathObjectType_XPATH_XSLT_TREE:
898 default:
899 // TODO: localized error message?
900 break;
901 }
902
903 return aBuffer.makeStringAndClear();
904 }
905
getResultForExpression(const XPropertySet_t & xBinding,sal_Bool bIsBindingExpression,const OUString & sExpression)906 OUString Model::getResultForExpression(
907 const XPropertySet_t& xBinding,
908 sal_Bool bIsBindingExpression,
909 const OUString& sExpression )
910 {
911 Binding* pBinding = Binding::getBinding( xBinding );
912 if( pBinding == NULL )
913 throw RuntimeException();
914
915 // prepare & evaluate expression
916 OUStringBuffer aBuffer;
917 ComputedExpression aExpression;
918 aExpression.setExpression( sExpression );
919 if( bIsBindingExpression )
920 {
921 // binding: use binding context and evaluation
922 aExpression.evaluate( pBinding->getEvaluationContext() );
923 aBuffer.append( lcl_serializeForDisplay( aExpression.getXPath() ) );
924 }
925 else
926 {
927 // MIP (not binding): iterate over bindings contexts
928 std::vector<EvaluationContext> aContext =
929 pBinding->getMIPEvaluationContexts();
930 for( std::vector<EvaluationContext>::iterator aIter = aContext.begin();
931 aIter != aContext.end();
932 aIter ++ )
933 {
934 aExpression.evaluate( *aIter );
935 aBuffer.append( lcl_serializeForDisplay(aExpression.getXPath()) );
936 aBuffer.append( sal_Unicode('\n') );
937 }
938 }
939 return aBuffer.makeStringAndClear();
940 }
941
isValidXMLName(const OUString & sName)942 sal_Bool Model::isValidXMLName( const OUString& sName )
943 {
944 return isValidQName( sName, NULL );
945 }
946
isValidPrefixName(const OUString & sName)947 sal_Bool Model::isValidPrefixName( const OUString& sName )
948 {
949 return ::isValidPrefixName( sName, NULL );
950 }
951
setNodeValue(const XNode_t & xNode,const rtl::OUString & sValue)952 void Model::setNodeValue(
953 const XNode_t& xNode,
954 const rtl::OUString& sValue )
955 {
956 setSimpleContent( xNode, sValue );
957 }
958
959
960 //
961 // helper functions from model_helper.hxx
962 //
963
getInstanceData(const Sequence<PropertyValue> & aValues,OUString * pID,Reference<XDocument> * pInstance,OUString * pURL,bool * pURLOnce)964 void xforms::getInstanceData(
965 const Sequence<PropertyValue>& aValues,
966 OUString* pID,
967 Reference<XDocument>* pInstance,
968 OUString* pURL,
969 bool* pURLOnce )
970 {
971 sal_Int32 nValues = aValues.getLength();
972 const PropertyValue* pValues = aValues.getConstArray();
973 for( sal_Int32 n = 0; n < nValues; n++ )
974 {
975 const PropertyValue& rValue = pValues[n];
976 #define PROP(NAME) \
977 if( p##NAME != NULL && \
978 rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(#NAME)) ) \
979 rValue.Value >>= (*p##NAME)
980 PROP(ID);
981 PROP(Instance);
982 PROP(URL);
983 PROP(URLOnce);
984 #undef PROP
985 }
986 }
987
setInstanceData(Sequence<PropertyValue> & aSequence,const OUString * _pID,const Reference<XDocument> * _pInstance,const OUString * _pURL,const bool * _pURLOnce)988 void xforms::setInstanceData(
989 Sequence<PropertyValue>& aSequence,
990 const OUString* _pID,
991 const Reference<XDocument>* _pInstance,
992 const OUString* _pURL,
993 const bool* _pURLOnce )
994 {
995 // get old instance data
996 OUString sID;
997 Reference<XDocument> xInstance;
998 OUString sURL;
999 bool bURLOnce = false;
1000 getInstanceData( aSequence, &sID, &xInstance, &sURL, &bURLOnce );
1001 const OUString* pID = ( sID.getLength() > 0 ) ? &sID : NULL;
1002 const Reference<XDocument>* pInstance = xInstance.is() ? &xInstance : NULL;
1003 const OUString* pURL = ( sURL.getLength() > 0 ) ? &sURL : NULL;
1004 const bool* pURLOnce = ( bURLOnce && pURL != NULL ) ? &bURLOnce : NULL;
1005
1006 // determine new instance data
1007 #define PROP(NAME) if( _p##NAME != NULL ) p##NAME = _p##NAME
1008 PROP(ID);
1009 PROP(Instance);
1010 PROP(URL);
1011 PROP(URLOnce);
1012 #undef PROP
1013
1014 // count # of values we want to set
1015 sal_Int32 nCount = 0;
1016 #define PROP(NAME) if( p##NAME != NULL ) nCount++
1017 PROP(ID);
1018 PROP(Instance);
1019 PROP(URL);
1020 PROP(URLOnce);
1021 #undef PROP
1022
1023 // realloc sequence and enter values;
1024 aSequence.realloc( nCount );
1025 PropertyValue* pSequence = aSequence.getArray();
1026 sal_Int32 nIndex = 0;
1027 #define PROP(NAME) \
1028 if( p##NAME != NULL ) \
1029 { \
1030 pSequence[ nIndex ].Name = OUSTRING(#NAME); \
1031 pSequence[ nIndex ].Value <<= *p##NAME; \
1032 nIndex++; \
1033 }
1034 PROP(ID);
1035 PROP(Instance);
1036 PROP(URL);
1037 PROP(URLOnce);
1038 #undef PROP
1039 }
1040