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