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 :
35 : // UNO classes
36 : #include <com/sun/star/xml/dom/XNode.hpp>
37 : #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
38 : #include <com/sun/star/xml/dom/XDocumentFragment.hpp>
39 : #include <com/sun/star/xml/dom/XNamedNodeMap.hpp>
40 : #include <com/sun/star/xml/xpath/XXPathObject.hpp>
41 : #include <com/sun/star/xml/xpath/XPathObjectType.hpp>
42 : #include <com/sun/star/beans/PropertyValue.hpp>
43 : #include <com/sun/star/io/XInputStream.hpp>
44 : #include <com/sun/star/io/XActiveDataSink.hpp>
45 : #include <com/sun/star/io/XTextInputStream.hpp>
46 : #include <com/sun/star/container/XEnumeration.hpp>
47 : #include <com/sun/star/container/XNameContainer.hpp>
48 : #include <com/sun/star/frame/XModel.hpp>
49 : #include <com/sun/star/xforms/XFormsSupplier.hpp>
50 : #include <com/sun/star/xforms/XDataTypeRepository.hpp>
51 : #include <com/sun/star/xsd/XDataType.hpp>
52 : #include <com/sun/star/xsd/DataTypeClass.hpp>
53 :
54 :
55 : using rtl::OUString;
56 : using rtl::OUStringBuffer;
57 : using com::sun::star::beans::PropertyValue;
58 : using com::sun::star::io::XInputStream;
59 : using com::sun::star::io::XActiveDataSink;
60 : using com::sun::star::io::XTextInputStream;
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 )
78 : {
79 : // determine service for control. string/text field is default.
80 0 : OUString sService = OUSTRING("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 = OUSTRING("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 = OUSTRING("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 0 : 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, sal_Unicode(']') );
156 0 : rBuffer.insert( 0, nPosition );
157 0 : rBuffer.insert( 0, sal_Unicode('[') );
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, sal_Unicode(':') );
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, OUSTRING("')") );
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, OUSTRING("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.getLength() > 0 )
223 0 : aBuffer.insert( 0, sal_Unicode('/') );
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, OUSTRING("text()") );
235 0 : break;
236 :
237 : case NodeType_ATTRIBUTE_NODE:
238 0 : lcl_OutName( aBuffer, xCurrent );
239 0 : aBuffer.insert( 0, sal_Unicode('@') );
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, sal_Unicode('/') );
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 )
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 : bWhitespace = ( c == sal_Unicode(0x09) ||
279 : c == sal_Unicode(0x0A) ||
280 : 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 )
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.append( sal_Unicode('"') );
304 0 : aBuffer.append( Convert::collapseWhitespace( sContent ) );
305 0 : aBuffer.append( sal_Unicode('"') );
306 0 : }
307 : }
308 0 : break;
309 :
310 : case NodeType_ATTRIBUTE_NODE:
311 0 : lcl_OutName( aBuffer, xNode );
312 0 : aBuffer.insert( 0, sal_Unicode('@') );
313 0 : break;
314 :
315 : case NodeType_DOCUMENT_NODE:
316 0 : if( xNode == getDefaultInstance() )
317 0 : aBuffer.append( sal_Unicode('/') );
318 : else
319 0 : lcl_OutInstance( aBuffer, xNode, this );
320 0 : break;
321 :
322 : default:
323 : // unknown type? fail!
324 : OSL_FAIL( "unknown node type!" );
325 0 : break;
326 : }
327 :
328 0 : return aBuffer.makeStringAndClear();
329 : }
330 :
331 0 : OUString Model::getNodeName( const XNode_t& xNode )
332 : throw( RuntimeException )
333 : {
334 0 : OUStringBuffer aBuffer;
335 :
336 0 : switch( xNode->getNodeType() )
337 : {
338 : case NodeType_ELEMENT_NODE:
339 : case NodeType_ATTRIBUTE_NODE:
340 0 : lcl_OutName( aBuffer, xNode );
341 0 : break;
342 :
343 : case NodeType_TEXT_NODE:
344 : case NodeType_DOCUMENT_NODE:
345 : default:
346 : // unknown type? fail!
347 : OSL_FAIL( "no name for this node type!" );
348 0 : break;
349 : }
350 :
351 0 : return aBuffer.makeStringAndClear();
352 : }
353 :
354 0 : OUString Model::getBindingName( const XPropertySet_t& xBinding,
355 : sal_Bool /*bDetail*/ )
356 : throw( RuntimeException )
357 : {
358 0 : OUString sID;
359 0 : xBinding->getPropertyValue( OUSTRING("BindingID" ) ) >>= sID;
360 0 : OUString sExpression;
361 0 : xBinding->getPropertyValue( OUSTRING("BindingExpression" ) ) >>= sExpression;
362 :
363 0 : OUStringBuffer aBuffer;
364 0 : if( !sID.isEmpty() )
365 : {
366 0 : aBuffer.append( sID );
367 0 : aBuffer.append( OUSTRING(" (" ));
368 0 : aBuffer.append( sExpression );
369 0 : aBuffer.append( OUSTRING(")" ));
370 : }
371 : else
372 0 : aBuffer.append( sExpression );
373 :
374 0 : return aBuffer.makeStringAndClear();
375 : }
376 :
377 0 : OUString Model::getSubmissionName( const XPropertySet_t& xSubmission,
378 : sal_Bool /*bDetail*/ )
379 : throw( RuntimeException )
380 : {
381 0 : OUString sID;
382 0 : xSubmission->getPropertyValue( OUSTRING("ID") ) >>= sID;
383 0 : return sID;
384 : }
385 :
386 0 : Model::XPropertySet_t Model::cloneBindingAsGhost( const XPropertySet_t &xBinding )
387 : throw( RuntimeException )
388 : {
389 : // Create a new binding instance first...
390 0 : Binding *pBinding = new Binding();
391 :
392 : // ...and bump up the "defered notification counter"
393 : // to prevent this binding from contributing to the
394 : // MIPs table...
395 0 : pBinding->deferNotifications(true);
396 :
397 : // Copy the propertyset and return result...
398 0 : XPropertySet_t xNewBinding(pBinding);
399 0 : copy( xBinding, xNewBinding );
400 0 : return xNewBinding;
401 : }
402 :
403 0 : void Model::removeBindingIfUseless( const XPropertySet_t& xBinding )
404 : throw( RuntimeException )
405 : {
406 0 : Binding* pBinding = Binding::getBinding( xBinding );
407 0 : if( pBinding != NULL )
408 : {
409 0 : if( ! pBinding->isUseful() )
410 0 : mpBindings->removeItem( pBinding );
411 : }
412 0 : }
413 :
414 0 : Model::XDocument_t Model::newInstance( const rtl::OUString& sName,
415 : const rtl::OUString& sURL,
416 : sal_Bool bURLOnce )
417 : throw( RuntimeException )
418 : {
419 : // create a default instance with <instanceData> element
420 0 : XDocument_t xInstance = getDocumentBuilder()->newDocument();
421 : DBG_ASSERT( xInstance.is(), "failed to create DOM instance" );
422 :
423 0 : Reference<XNode>( xInstance, UNO_QUERY_THROW )->appendChild(
424 0 : Reference<XNode>( xInstance->createElement( OUSTRING("instanceData") ),
425 0 : UNO_QUERY_THROW ) );
426 :
427 0 : Sequence<PropertyValue> aSequence;
428 0 : bool bOnce = bURLOnce; // bool, so we can take address in setInstanceData
429 0 : setInstanceData( aSequence, &sName, &xInstance, &sURL, &bOnce );
430 0 : sal_Int32 nInstance = mpInstances->addItem( aSequence );
431 0 : loadInstance( nInstance );
432 :
433 0 : return xInstance;
434 : }
435 :
436 0 : static sal_Int32 lcl_findProp( const PropertyValue* pValues,
437 : sal_Int32 nLength,
438 : const rtl::OUString& rName )
439 : {
440 0 : bool bFound = false;
441 0 : sal_Int32 n = 0;
442 0 : for( ; !bFound && n < nLength; n++ )
443 : {
444 0 : bFound = ( pValues[n].Name == rName );
445 : }
446 0 : return bFound ? ( n - 1) : -1;
447 : }
448 :
449 0 : sal_Int32 xforms::lcl_findInstance( const InstanceCollection* pInstances,
450 : const rtl::OUString& rName )
451 : {
452 0 : sal_Int32 nLength = pInstances->countItems();
453 0 : sal_Int32 n = 0;
454 0 : bool bFound = false;
455 0 : for( ; !bFound && n < nLength; n++ )
456 : {
457 0 : OUString sName;
458 0 : getInstanceData( pInstances->getItem( n ), &sName, NULL, NULL, NULL );
459 0 : bFound = ( sName == rName );
460 0 : }
461 0 : return bFound ? ( n - 1 ) : -1;
462 : }
463 :
464 0 : void Model::renameInstance( const rtl::OUString& sFrom,
465 : const rtl::OUString& sTo,
466 : const rtl::OUString& sURL,
467 : sal_Bool bURLOnce )
468 : throw( RuntimeException )
469 : {
470 0 : sal_Int32 nPos = lcl_findInstance( mpInstances, sFrom );
471 0 : if( nPos != -1 )
472 : {
473 0 : Sequence<PropertyValue> aSeq = mpInstances->getItem( nPos );
474 0 : PropertyValue* pSeq = aSeq.getArray();
475 0 : sal_Int32 nLength = aSeq.getLength();
476 :
477 0 : sal_Int32 nProp = lcl_findProp( pSeq, nLength, OUSTRING("ID") );
478 0 : if( nProp == -1 )
479 : {
480 : // add name property
481 0 : aSeq.realloc( nLength + 1 );
482 0 : pSeq = aSeq.getArray();
483 0 : pSeq[ nLength ].Name = OUSTRING("ID");
484 0 : nProp = nLength;
485 : }
486 :
487 : // change name
488 0 : pSeq[ nProp ].Value <<= sTo;
489 :
490 : // change url
491 0 : nProp = lcl_findProp( pSeq, nLength, OUSTRING("URL") );
492 0 : if(nProp != -1)
493 0 : pSeq[ nProp ].Value <<= sURL;
494 :
495 : // change urlonce
496 0 : nProp = lcl_findProp( pSeq, nLength, OUSTRING("URLOnce") );
497 0 : if(nProp != -1)
498 0 : pSeq[ nProp ].Value <<= bURLOnce;
499 :
500 : // set instance
501 0 : mpInstances->setItem( nPos, aSeq );
502 : }
503 0 : }
504 :
505 0 : void Model::removeInstance( const rtl::OUString& sName )
506 : throw( RuntimeException )
507 : {
508 0 : sal_Int32 nPos = lcl_findInstance( mpInstances, sName );
509 0 : if( nPos != -1 )
510 0 : mpInstances->removeItem( mpInstances->getItem( nPos ) );
511 0 : }
512 :
513 0 : static Reference<XNameContainer> lcl_getModels(
514 : const Reference<com::sun::star::frame::XModel>& xComponent )
515 : {
516 0 : Reference<XNameContainer> xRet;
517 0 : Reference<XFormsSupplier> xSupplier( xComponent, UNO_QUERY );
518 0 : if( xSupplier.is() )
519 : {
520 0 : xRet = xSupplier->getXForms();
521 : }
522 0 : return xRet;
523 : }
524 :
525 0 : Model::XModel_t Model::newModel( const Reference<com::sun::star::frame::XModel>& xCmp,
526 : const OUString& sName )
527 : throw( RuntimeException )
528 : {
529 0 : Model::XModel_t xModel;
530 0 : Reference<XNameContainer> xModels = lcl_getModels( xCmp );
531 0 : if( xModels.is()
532 0 : && ! xModels->hasByName( sName ) )
533 : {
534 0 : Model* pModel = new Model();
535 0 : xModel.set( pModel );
536 :
537 0 : pModel->setID( sName );
538 0 : pModel->newInstance( OUString(), OUString(), sal_False );
539 0 : pModel->initialize();
540 0 : xModels->insertByName( sName, makeAny( xModel ) );
541 : }
542 :
543 0 : return xModel;
544 : }
545 :
546 0 : void Model::renameModel( const Reference<com::sun::star::frame::XModel>& xCmp,
547 : const OUString& sFrom,
548 : const OUString& sTo )
549 : throw( RuntimeException )
550 : {
551 0 : Reference<XNameContainer> xModels = lcl_getModels( xCmp );
552 0 : if( xModels.is()
553 0 : && xModels->hasByName( sFrom )
554 0 : && ! xModels->hasByName( sTo ) )
555 : {
556 0 : Reference<XModel> xModel( xModels->getByName( sFrom ), UNO_QUERY );
557 0 : xModel->setID( sTo );
558 0 : xModels->insertByName( sTo, makeAny( xModel ) );
559 0 : xModels->removeByName( sFrom );
560 0 : }
561 0 : }
562 :
563 0 : void Model::removeModel( const Reference<com::sun::star::frame::XModel>& xCmp,
564 : const OUString& sName )
565 : throw( RuntimeException )
566 : {
567 0 : Reference<XNameContainer> xModels = lcl_getModels( xCmp );
568 0 : if( xModels.is()
569 0 : && xModels->hasByName( sName ) )
570 : {
571 0 : xModels->removeByName( sName );
572 0 : }
573 0 : }
574 :
575 0 : Model::XNode_t Model::createElement( const XNode_t& xParent,
576 : const OUString& sName )
577 : throw( RuntimeException )
578 : {
579 0 : Reference<XNode> xNode;
580 0 : if( xParent.is()
581 0 : && isValidXMLName( sName ) )
582 : {
583 : // TODO: implement proper namespace handling
584 0 : xNode.set( xParent->getOwnerDocument()->createElement( sName ),
585 0 : UNO_QUERY );
586 : }
587 0 : return xNode;
588 : }
589 :
590 0 : Model::XNode_t Model::createAttribute( const XNode_t& xParent,
591 : const OUString& sName )
592 : throw( RuntimeException )
593 : {
594 0 : Reference<XNode> xNode;
595 0 : Reference<XElement> xElement( xParent, UNO_QUERY );
596 0 : if( xParent.is()
597 0 : && xElement.is()
598 0 : && isValidXMLName( sName ) )
599 : {
600 : // handle case where attribute already exists
601 0 : sal_Int32 nCount = 0;
602 0 : OUString sUniqueName = sName;
603 0 : while( xElement->hasAttribute( sUniqueName ) )
604 : {
605 0 : nCount++;
606 0 : sUniqueName = sName + OUString::valueOf( nCount );
607 : }
608 :
609 : // TODO: implement proper namespace handling
610 0 : xNode.set( xParent->getOwnerDocument()->createAttribute( sUniqueName ),
611 0 : UNO_QUERY );
612 : }
613 0 : return xNode;
614 : }
615 :
616 0 : Model::XNode_t Model::renameNode( const XNode_t& xNode,
617 : const rtl::OUString& sName )
618 : throw( RuntimeException )
619 : {
620 : // early out if we don't have to change the name
621 0 : if( xNode->getNodeName() == sName )
622 0 : return xNode;
623 :
624 : // refuse to change name if its an attribute, and the name is already used
625 0 : if( xNode->getNodeType() == NodeType_ATTRIBUTE_NODE
626 0 : && xNode->getParentNode().is()
627 0 : && Reference<XElement>(xNode->getParentNode(), UNO_QUERY_THROW)->hasAttribute( sName ) )
628 0 : return xNode;
629 :
630 : // note old binding expression so we can adjust bindings below
631 : OUString sOldDefaultBindingExpression =
632 0 : getDefaultBindingExpressionForNode( xNode );
633 :
634 0 : Reference<XDocument> xDoc = xNode->getOwnerDocument();
635 0 : Reference<XNode> xNew;
636 0 : if( xNode->getNodeType() == NodeType_ELEMENT_NODE )
637 : {
638 0 : Reference<XElement> xElem = xDoc->createElement( sName );
639 0 : xNew.set( xElem, UNO_QUERY );
640 :
641 : // iterate over all attributes and append them to the new element
642 0 : Reference<XElement> xOldElem( xNode, UNO_QUERY );
643 : OSL_ENSURE( xNode.is(), "no element?" );
644 :
645 0 : Reference<XNamedNodeMap> xMap = xNode->getAttributes();
646 0 : sal_Int32 nLength = xMap.is() ? xMap->getLength() : 0;
647 0 : for( sal_Int32 n = 0; n < nLength; n++ )
648 : {
649 0 : Reference<XAttr> xAttr( xMap->item(n), UNO_QUERY );
650 0 : xElem->setAttributeNode( xOldElem->removeAttributeNode( xAttr ) );
651 0 : }
652 :
653 : // iterate over all children and append them to the new element
654 0 : for( Reference<XNode> xCurrent = xNode->getFirstChild();
655 0 : xCurrent.is();
656 0 : xCurrent = xNode->getFirstChild() )
657 : {
658 0 : xNew->appendChild( xNode->removeChild( xCurrent ) );
659 0 : }
660 :
661 0 : xNode->getParentNode()->replaceChild( xNew, xNode );
662 : }
663 0 : else if( xNode->getNodeType() == NodeType_ATTRIBUTE_NODE )
664 : {
665 : // create new attribute
666 0 : Reference<XAttr> xAttr = xDoc->createAttribute( sName );
667 0 : xAttr->setValue( xNode->getNodeValue() );
668 :
669 : // replace node
670 0 : Reference<XNode> xParent = xNode->getParentNode();
671 0 : xParent->removeChild( xNode );
672 0 : xNew = xParent->appendChild( Reference<XNode>( xAttr, UNO_QUERY ) );
673 : }
674 : else
675 : {
676 : OSL_FAIL( "can't rename this node type" );
677 : }
678 :
679 : // adjust bindings (if necessary):
680 0 : if( xNew.is() )
681 : {
682 : // iterate over bindings and replace default expressions
683 : OUString sNewDefaultBindingExpression =
684 0 : getDefaultBindingExpressionForNode( xNew );
685 0 : for( sal_Int32 n = 0; n < mpBindings->countItems(); n++ )
686 : {
687 : Binding* pBinding = Binding::getBinding(
688 0 : mpBindings->Collection<XPropertySet_t>::getItem( n ) );
689 :
690 0 : if( pBinding->getBindingExpression()
691 0 : == sOldDefaultBindingExpression )
692 0 : pBinding->setBindingExpression( sNewDefaultBindingExpression );
693 0 : }
694 : }
695 :
696 : // return node; return old node if renaming failed
697 0 : return xNew.is() ? xNew : xNode;
698 : }
699 :
700 0 : Model::XPropertySet_t Model::getBindingForNode( const XNode_t& xNode,
701 : sal_Bool bCreate )
702 : throw( RuntimeException )
703 : {
704 : OSL_ENSURE( xNode.is(), "no node?" );
705 :
706 : // We will iterate over all bindings and determine the
707 : // appropriateness of the respective binding for this node. The
708 : // best one will be used. If we don't find any and bCreate is set,
709 : // then we will create a suitable binding.
710 0 : Binding* pBestBinding = NULL;
711 0 : sal_Int32 nBestScore = 0;
712 :
713 0 : for( sal_Int32 n = 0; n < mpBindings->countItems(); n++ )
714 : {
715 : Binding* pBinding = Binding::getBinding(
716 0 : mpBindings->Collection<XPropertySet_t>::getItem( n ) );
717 :
718 : OSL_ENSURE( pBinding != NULL, "no binding?" );
719 0 : Reference<XNodeList> xNodeList = pBinding->getXNodeList();
720 :
721 0 : sal_Int32 nNodes = xNodeList.is() ? xNodeList->getLength() : 0;
722 0 : if( nNodes > 0 && xNodeList->item( 0 ) == xNode )
723 : {
724 : // allright, we found a suitable node. Let's determine how
725 : // well it fits. Score:
726 : // - bind to exactly this node is better than whole nodeset
727 : // - simple binding expressions is better than complex ones
728 0 : sal_Int32 nScore = 0;
729 0 : if( nNodes == 1 )
730 0 : nScore ++;
731 0 : if( pBinding->isSimpleBindingExpression() )
732 0 : nScore ++;
733 :
734 : // if we found a better binding, remember it
735 0 : if( nScore > nBestScore )
736 : {
737 0 : pBestBinding = pBinding;
738 0 : nBestScore = nScore;
739 : }
740 : }
741 0 : }
742 :
743 : // create binding, if none was found and bCreate is set
744 : OSL_ENSURE( ( nBestScore == 0 ) == ( pBestBinding == NULL ),
745 : "score != binding?" );
746 0 : if( bCreate && pBestBinding == NULL )
747 : {
748 0 : pBestBinding = new Binding();
749 : pBestBinding->setBindingExpression(
750 0 : getDefaultBindingExpressionForNode( xNode ) );
751 0 : mpBindings->addItem( pBestBinding );
752 : }
753 :
754 0 : return pBestBinding;
755 : }
756 :
757 0 : void Model::removeBindingForNode( const XNode_t& )
758 : throw( RuntimeException )
759 : {
760 : // determine whether suitable binding is still used
761 0 : }
762 :
763 0 : static OUString lcl_serializeForDisplay( const Reference< XAttr >& _rxAttrNode )
764 : {
765 0 : ::rtl::OUString sResult;
766 : OSL_ENSURE( _rxAttrNode.is(), "lcl_serializeForDisplay( attr ): invalid argument!" );
767 0 : if ( _rxAttrNode.is() )
768 : {
769 0 : ::rtl::OUStringBuffer aBuffer;
770 0 : aBuffer.append( _rxAttrNode->getName() );
771 0 : aBuffer.appendAscii( "=" );
772 0 : ::rtl::OUString sValue = _rxAttrNode->getValue();
773 0 : sal_Unicode nQuote = '"';
774 0 : if ( sValue.indexOf( nQuote ) >= 0 )
775 0 : nQuote = '\'';
776 0 : aBuffer.append( nQuote );
777 0 : aBuffer.append( sValue );
778 0 : aBuffer.append( nQuote );
779 0 : aBuffer.append( (sal_Unicode)' ' );
780 0 : sResult = aBuffer.makeStringAndClear();
781 : }
782 0 : return sResult;
783 : }
784 :
785 0 : static OUString lcl_serializeForDisplay( const Reference<XNodeList>& xNodes )
786 : {
787 0 : ::rtl::OUString sResult;
788 :
789 : // create document fragment
790 0 : Reference<XDocument> xDocument( getDocumentBuilder()->newDocument() );
791 : Reference<XDocumentFragment> xFragment(
792 0 : xDocument->createDocumentFragment() );
793 0 : Reference<XNode> xNode( xFragment, UNO_QUERY );
794 : OSL_ENSURE( xFragment.is(), "xFragment" );
795 : OSL_ENSURE( xNode.is(), "xNode" );
796 :
797 0 : sal_Int32 nAttributeNodes = 0;
798 :
799 : // attach nodelist to fragment
800 0 : sal_Int32 nLength = xNodes->getLength();
801 0 : for( sal_Int32 i = 0; i < nLength; i++ )
802 : {
803 0 : Reference<XNode> xCurrent = xNodes->item( i );
804 :
805 0 : switch ( xCurrent->getNodeType() )
806 : {
807 : case NodeType_DOCUMENT_NODE:
808 : // special-case documents: use top-level element instead
809 0 : xCurrent = xCurrent->getFirstChild();
810 0 : break;
811 : case NodeType_ATTRIBUTE_NODE:
812 : {
813 0 : Reference< XAttr > xAttr( xCurrent, UNO_QUERY );
814 0 : if ( xAttr.is() )
815 : {
816 0 : sResult += lcl_serializeForDisplay( xAttr );
817 0 : ++nAttributeNodes;
818 0 : }
819 : }
820 0 : continue;
821 :
822 : default:
823 0 : break;
824 : }
825 :
826 : // append node
827 0 : xNode->appendChild( xDocument->importNode( xCurrent, sal_True ) );
828 0 : }
829 : OSL_ENSURE( ( nAttributeNodes == 0 ) || ( nAttributeNodes == nLength ),
830 : "lcl_serializeForDisplay: mixed attribute and non-attribute nodes?" );
831 0 : if ( nAttributeNodes )
832 : // had only attribute nodes
833 : return sResult;
834 :
835 : // serialize fragment
836 0 : CSerializationAppXML aSerialization;
837 0 : aSerialization.setSource( xFragment );
838 0 : aSerialization.serialize();
839 :
840 : // copy stream into buffer
841 : Reference<XTextInputStream> xTextInputStream(
842 : createInstance( OUSTRING("com.sun.star.io.TextInputStream") ),
843 0 : UNO_QUERY );
844 : Reference<XActiveDataSink>( xTextInputStream, UNO_QUERY_THROW )
845 0 : ->setInputStream( aSerialization.getInputStream() );
846 :
847 : /* WORK AROUND for problem in serialization: currently, multiple
848 : XML delarations (<?xml...?>) are being written out and we don't
849 : want them. When this is fixed, the code below is nice and
850 : simple. The current code filters out the declarations.
851 : OUString sResult = xTextInputStream->readString( Sequence<sal_Unicode>(),
852 : sal_True );
853 : */
854 :
855 : // well, the serialization prepends XML header(s) that we need to
856 : // remove first.
857 0 : OUStringBuffer aBuffer;
858 0 : while( ! xTextInputStream->isEOF() )
859 : {
860 0 : OUString sLine = xTextInputStream->readLine();
861 0 : if( !sLine.isEmpty()
862 0 : && sLine.compareToAscii( "<?xml", 5 ) != 0 )
863 : {
864 0 : aBuffer.append( sLine );
865 0 : aBuffer.append( sal_Unicode('\n') );
866 : }
867 0 : }
868 0 : sResult = aBuffer.makeStringAndClear();
869 :
870 0 : return sResult;
871 : }
872 :
873 0 : static OUString lcl_serializeForDisplay( const Reference<XXPathObject>& xResult )
874 : {
875 : // error handling first
876 0 : if( ! xResult.is() )
877 0 : return getResource( RID_STR_XFORMS_CANT_EVALUATE );
878 :
879 :
880 : // TODO: localize
881 0 : OUStringBuffer aBuffer;
882 :
883 0 : switch( xResult->getObjectType() )
884 : {
885 : case XPathObjectType_XPATH_BOOLEAN:
886 0 : aBuffer.append( xResult->getBoolean()
887 : ? OUSTRING("true")
888 0 : : OUSTRING("false") );
889 0 : break;
890 :
891 : case XPathObjectType_XPATH_STRING:
892 0 : aBuffer.append( sal_Unicode('"') );
893 0 : aBuffer.append( xResult->getString() );
894 0 : aBuffer.append( sal_Unicode('"') );
895 0 : break;
896 :
897 : case XPathObjectType_XPATH_NODESET:
898 0 : aBuffer.append( lcl_serializeForDisplay( xResult->getNodeList() ) );
899 0 : break;
900 :
901 : case XPathObjectType_XPATH_NUMBER:
902 0 : aBuffer.append( xResult->getDouble() );
903 0 : break;
904 :
905 : case XPathObjectType_XPATH_UNDEFINED:
906 : case XPathObjectType_XPATH_POINT:
907 : case XPathObjectType_XPATH_RANGE:
908 : case XPathObjectType_XPATH_LOCATIONSET:
909 : case XPathObjectType_XPATH_USERS:
910 : case XPathObjectType_XPATH_XSLT_TREE:
911 : default:
912 : // TODO: localized error message?
913 0 : break;
914 : }
915 :
916 0 : return aBuffer.makeStringAndClear();
917 : }
918 :
919 0 : OUString Model::getResultForExpression(
920 : const XPropertySet_t& xBinding,
921 : sal_Bool bIsBindingExpression,
922 : const OUString& sExpression )
923 : throw( RuntimeException )
924 : {
925 0 : Binding* pBinding = Binding::getBinding( xBinding );
926 0 : if( pBinding == NULL )
927 0 : throw RuntimeException();
928 :
929 : // prepare & evaluate expression
930 0 : OUStringBuffer aBuffer;
931 0 : ComputedExpression aExpression;
932 0 : aExpression.setExpression( sExpression );
933 0 : if( bIsBindingExpression )
934 : {
935 : // binding: use binding context and evaluation
936 0 : aExpression.evaluate( pBinding->getEvaluationContext() );
937 0 : aBuffer.append( lcl_serializeForDisplay( aExpression.getXPath() ) );
938 : }
939 : else
940 : {
941 : // MIP (not binding): iterate over bindings contexts
942 : std::vector<EvaluationContext> aContext =
943 0 : pBinding->getMIPEvaluationContexts();
944 0 : for( std::vector<EvaluationContext>::iterator aIter = aContext.begin();
945 0 : aIter != aContext.end();
946 : ++aIter )
947 : {
948 0 : aExpression.evaluate( *aIter );
949 0 : aBuffer.append( lcl_serializeForDisplay(aExpression.getXPath()) );
950 0 : aBuffer.append( sal_Unicode('\n') );
951 0 : }
952 : }
953 0 : return aBuffer.makeStringAndClear();
954 : }
955 :
956 0 : sal_Bool Model::isValidXMLName( const OUString& sName )
957 : throw( RuntimeException )
958 : {
959 0 : return isValidQName( sName, NULL );
960 : }
961 :
962 0 : sal_Bool Model::isValidPrefixName( const OUString& sName )
963 : throw( RuntimeException )
964 : {
965 0 : return ::isValidPrefixName( sName, NULL );
966 : }
967 :
968 0 : void Model::setNodeValue(
969 : const XNode_t& xNode,
970 : const rtl::OUString& sValue )
971 : throw( RuntimeException )
972 : {
973 0 : setSimpleContent( xNode, sValue );
974 0 : }
975 :
976 :
977 : //
978 : // helper functions from model_helper.hxx
979 : //
980 :
981 0 : void xforms::getInstanceData(
982 : const Sequence<PropertyValue>& aValues,
983 : OUString* pID,
984 : Reference<XDocument>* pInstance,
985 : OUString* pURL,
986 : bool* pURLOnce )
987 : {
988 0 : sal_Int32 nValues = aValues.getLength();
989 0 : const PropertyValue* pValues = aValues.getConstArray();
990 0 : for( sal_Int32 n = 0; n < nValues; n++ )
991 : {
992 0 : const PropertyValue& rValue = pValues[n];
993 : #define PROP(NAME) \
994 : if( p##NAME != NULL && \
995 : rValue.Name == #NAME ) \
996 : rValue.Value >>= (*p##NAME)
997 0 : PROP(ID);
998 0 : PROP(Instance);
999 0 : PROP(URL);
1000 0 : PROP(URLOnce);
1001 : #undef PROP
1002 : }
1003 0 : }
1004 :
1005 0 : void xforms::setInstanceData(
1006 : Sequence<PropertyValue>& aSequence,
1007 : const OUString* _pID,
1008 : const Reference<XDocument>* _pInstance,
1009 : const OUString* _pURL,
1010 : const bool* _pURLOnce )
1011 : {
1012 : // get old instance data
1013 0 : OUString sID;
1014 0 : Reference<XDocument> xInstance;
1015 0 : OUString sURL;
1016 0 : bool bURLOnce = false;
1017 0 : getInstanceData( aSequence, &sID, &xInstance, &sURL, &bURLOnce );
1018 0 : const OUString* pID = !sID.isEmpty() ? &sID : NULL;
1019 0 : const Reference<XDocument>* pInstance = xInstance.is() ? &xInstance : NULL;
1020 0 : const OUString* pURL = !sURL.isEmpty() ? &sURL : NULL;
1021 0 : const bool* pURLOnce = ( bURLOnce && pURL != NULL ) ? &bURLOnce : NULL;
1022 :
1023 : // determine new instance data
1024 : #define PROP(NAME) if( _p##NAME != NULL ) p##NAME = _p##NAME
1025 0 : PROP(ID);
1026 0 : PROP(Instance);
1027 0 : PROP(URL);
1028 0 : PROP(URLOnce);
1029 : #undef PROP
1030 :
1031 : // count # of values we want to set
1032 0 : sal_Int32 nCount = 0;
1033 : #define PROP(NAME) if( p##NAME != NULL ) nCount++
1034 0 : PROP(ID);
1035 0 : PROP(Instance);
1036 0 : PROP(URL);
1037 0 : PROP(URLOnce);
1038 : #undef PROP
1039 :
1040 : // realloc sequence and enter values;
1041 0 : aSequence.realloc( nCount );
1042 0 : PropertyValue* pSequence = aSequence.getArray();
1043 0 : sal_Int32 nIndex = 0;
1044 : #define PROP(NAME) \
1045 : if( p##NAME != NULL ) \
1046 : { \
1047 : pSequence[ nIndex ].Name = OUSTRING(#NAME); \
1048 : pSequence[ nIndex ].Value <<= *p##NAME; \
1049 : nIndex++; \
1050 : }
1051 0 : PROP(ID);
1052 0 : PROP(Instance);
1053 0 : PROP(URL);
1054 0 : PROP(URLOnce);
1055 : #undef PROP
1056 0 : }
1057 :
1058 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|