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