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