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