xref: /aoo41x/main/forms/source/xforms/model.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_forms.hxx"
30 
31 #include "model.hxx"
32 
33 #include "model_helper.hxx"
34 #include "unohelper.hxx"
35 #include "binding.hxx"
36 #include "submission.hxx"
37 #include "mip.hxx"
38 #include "evaluationcontext.hxx"
39 #include "xmlhelper.hxx"
40 #include "datatyperepository.hxx"
41 #include "NameContainer.hxx"
42 
43 #include <rtl/ustring.hxx>
44 #include <rtl/ustrbuf.hxx>
45 #include <tools/debug.hxx>
46 
47 #include <comphelper/propertysetinfo.hxx>
48 #include <cppuhelper/typeprovider.hxx>
49 
50 #include <algorithm>
51 
52 // UNO classes
53 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
54 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
55 #include <com/sun/star/lang/IllegalArgumentException.hpp>
56 #include <com/sun/star/xml/dom/XDocument.hpp>
57 #include <com/sun/star/xml/dom/XCharacterData.hpp>
58 #include <com/sun/star/xml/dom/NodeType.hpp>
59 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
60 #include <com/sun/star/uno/Sequence.hxx>
61 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
62 #include <com/sun/star/beans/PropertyValue.hpp>
63 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
64 #include <com/sun/star/io/XInputStream.hpp>
65 
66 
67 using com::sun::star::lang::XMultiServiceFactory;
68 using com::sun::star::lang::XUnoTunnel;
69 using com::sun::star::beans::XPropertySet;
70 using com::sun::star::beans::PropertyValue;
71 using rtl::OUString;
72 using rtl::OUStringBuffer;
73 using com::sun::star::beans::PropertyVetoException;
74 using com::sun::star::beans::UnknownPropertyException;
75 using com::sun::star::util::VetoException;
76 using com::sun::star::lang::WrappedTargetException;
77 using com::sun::star::lang::IllegalArgumentException;
78 using com::sun::star::ucb::XSimpleFileAccess;
79 using com::sun::star::io::XInputStream;
80 
81 using namespace com::sun::star::uno;
82 using namespace com::sun::star::xml::dom;
83 using namespace xforms;
84 
85 
86 #if OSL_DEBUG_LEVEL > 1
87 #define DBG_INVARIANT_TYPE(TYPE) class DBG_##TYPE { const TYPE* mpT; void check() { mpT->dbg_assertInvariant(); } public: DBG_##TYPE(const TYPE* pT) : mpT(pT) { check(); } ~DBG_##TYPE() { check(); } } _DBG_##TYPE(this);
88 
89 #define DBG_INVARIANT() DBG_INVARIANT_TYPE(Model)
90 #else
91 #define DBG_INVARIANT_TYPE(TYPE)
92 #define DBG_INVARIANT()
93 #endif
94 
95 
96 
97 //
98 // The Model
99 //
100 
101 void Model::ensureAtLeastOneInstance()
102 {
103     if( ! mpInstances->hasItems() )
104     {
105         // create a default instance
106         newInstance( OUString(), OUString(), true );
107     }
108 }
109 
110 
111 
112 /** Model default constructor; create empty model */
113 Model::Model() :
114     msID(),
115     mpBindings( NULL ),
116     mpSubmissions( NULL ),
117     mpInstances( new InstanceCollection ),
118     mxNamespaces( new NameContainer<OUString>() ),
119     mxBindings( mpBindings ),
120     mxSubmissions( mpSubmissions ),
121     mxInstances( mpInstances ),
122     mbInitialized( false ),
123     mbExternalData( true )
124 {
125     initializePropertySet();
126 
127     // initialize bindings collections
128     // (not in initializer list to avoid use of incomplete 'this')
129     mpBindings = new BindingCollection( this );
130     mxBindings = mpBindings;
131 
132     mpSubmissions = new SubmissionCollection( this );
133     mxSubmissions = mpSubmissions;
134 
135     // invariant only holds after construction
136     DBG_INVARIANT();
137 }
138 
139 Model::~Model() throw()
140 {
141     // give up bindings & submissions; the mxBindings/mxSubmissions
142     // references will then delete them
143     mpBindings = NULL;
144     mpSubmissions = NULL;
145 }
146 
147 Model* lcl_getModel( const Reference<XUnoTunnel>& xTunnel )
148 {
149     Model* pModel = NULL;
150     if( xTunnel.is() )
151         pModel = reinterpret_cast<Model*>(
152             xTunnel->getSomething( Model::getUnoTunnelID() ) );
153     return pModel;
154 }
155 
156 Model* Model::getModel( const Reference<XModel>& xModel )
157 {
158     return lcl_getModel( Reference<XUnoTunnel>( xModel, UNO_QUERY ) );
159 }
160 
161 EvaluationContext Model::getEvaluationContext()
162 {
163     // the default context is the top-level element node. A default
164     // node (instanceData' is inserted when there is no default node
165     Reference<XDocument> xInstance = getDefaultInstance();
166     Reference<XNode> xElement( xInstance->getDocumentElement(), UNO_QUERY );
167 
168     // no element found? Then insert default element 'instanceData'
169     if( ! xElement.is() )
170     {
171         xElement = Reference<XNode>(
172                        xInstance->createElement( OUSTRING("instanceData") ),
173                        UNO_QUERY_THROW );
174         Reference<XNode>( xInstance, UNO_QUERY_THROW)->appendChild( xElement );
175     }
176 
177     OSL_ENSURE( xElement.is() &&
178                 xElement->getNodeType() == NodeType_ELEMENT_NODE,
179                 "no element in evaluation context" );
180 
181     return EvaluationContext( xElement, this, mxNamespaces, 0, 1 );
182 }
183 
184 
185 Model::IntSequence_t Model::getUnoTunnelID()
186 {
187     static cppu::OImplementationId aImplementationId;
188     return aImplementationId.getImplementationId();
189 }
190 
191 Model::XDocument_t Model::getForeignSchema() const
192 {
193     return mxForeignSchema;
194 }
195 
196 void Model::setForeignSchema( const XDocument_t& rDocument )
197 {
198     mxForeignSchema = rDocument;
199 }
200 
201 rtl::OUString Model::getSchemaRef() const
202 {
203     return msSchemaRef;
204 }
205 
206 void Model::setSchemaRef( const rtl::OUString& rSchemaRef )
207 {
208     msSchemaRef = rSchemaRef;
209 }
210 
211 Model::XNameContainer_t Model::getNamespaces() const
212 {
213     return mxNamespaces;
214 }
215 
216 void Model::setNamespaces( const XNameContainer_t& rNamespaces )
217 {
218     if( rNamespaces.is() )
219         mxNamespaces = rNamespaces;
220 }
221 
222 bool Model::getExternalData() const
223 {
224     return mbExternalData;
225 }
226 
227 void Model::setExternalData( bool _bData )
228 {
229     mbExternalData = _bData;
230 }
231 
232 #if OSL_DEBUG_LEVEL > 1
233 void Model::dbg_assertInvariant() const
234 {
235     OSL_ENSURE( mpInstances != NULL, "no instances found" );
236     OSL_ENSURE( mxInstances.is(), "No instance container!" );
237     //    OSL_ENSURE( mxInstances->hasElements(), "no instance!" );
238 
239     OSL_ENSURE( mpBindings != NULL, "no bindings element" );
240     OSL_ENSURE( mxBindings.is(), "No Bindings container" );
241 
242     OSL_ENSURE( mpSubmissions != NULL, "no submissions element" );
243     OSL_ENSURE( mxSubmissions.is(), "No Submission container" );
244 
245 
246 
247     /*
248     // check bindings, and things that have to do with our binding
249     std::vector<MIP*> aAllMIPs; // check MIP map
250     sal_Int32 nCount = mpBindings->countItems();
251     for( sal_Int32 i = 0; i < nCount; i++ )
252     {
253         Binding* pBind = Binding::getBinding(
254             mpBindings->Collection<XPropertySet_t>::getItem( i ) );
255 
256         // examine and check binding
257         OSL_ENSURE( pBind != NULL, "invalid binding found" );
258 
259         OSL_ENSURE( Model::getModel( pBind->getModel() ) == this,
260                     "our binding doesn't know us.");
261         // check this binding's MIP against MIP map
262         MIP* pMIP = const_cast<MIP*>( pBind->_getMIP() );
263         sal_Int32 nFound = 0;
264         if( pMIP != NULL )
265         {
266             aAllMIPs.push_back( pMIP );
267             for( MIPs_t::const_iterator aIter = maMIPs.begin();
268                  aIter != maMIPs.end();
269                  aIter++ )
270             {
271                 if( pMIP == aIter->second )
272                     nFound++;
273             }
274         }
275         OSL_ENSURE( ( pMIP == NULL ) == ( nFound == 0 ), "MIP-map wrong" );
276     }
277 
278     // check MIP map for left-over MIPs
279     for( MIPs_t::const_iterator aIter = maMIPs.begin();
280          aIter != maMIPs.end();
281          aIter++ )
282     {
283         MIP* pMIP = aIter->second;
284         std::vector<MIP*>::iterator aFound =
285             std::find( aAllMIPs.begin(), aAllMIPs.end(), pMIP );
286         if( aFound != aAllMIPs.end() )
287             aAllMIPs.erase( aFound );
288     }
289     OSL_ENSURE( aAllMIPs.empty(), "lonely MIPs found!" );
290     */
291 }
292 #endif
293 
294 
295 //
296 // MIP managment
297 //
298 
299 void Model::addMIP( void* pTag, const XNode_t& xNode, const MIP& rMIP )
300 {
301     OSL_ENSURE( pTag != NULL, "empty tag?" );
302     OSL_ENSURE( xNode.is(), "no node" );
303 
304     MIPs_t::value_type aValue( xNode, ::std::pair<void*,MIP>( pTag, rMIP ) );
305     maMIPs.insert( aValue );
306 }
307 
308 void Model::removeMIPs( void* pTag )
309 {
310     OSL_ENSURE( pTag != NULL, "empty tag?" );
311 
312     for( MIPs_t::iterator aIter = maMIPs.begin();
313          aIter != maMIPs.end(); )
314     {
315         if( aIter->second.first == pTag )
316         {
317             MIPs_t::iterator next( aIter ); ++next;
318             maMIPs.erase( aIter );
319             aIter = next;
320         }
321         else
322             ++aIter;
323     }
324 }
325 
326 MIP Model::queryMIP( const XNode_t& xNode ) const
327 {
328     //    OSL_ENSURE( xNode.is(), "no node" );
329 
330     // travel up inheritance chain and inherit MIPs
331     MIP aRet;
332     for( XNode_t xCurrent = xNode;
333          xCurrent.is();
334          xCurrent = xCurrent->getParentNode() )
335     {
336         // iterate over all MIPs for this node, and join MIPs
337         MIP aMIP;
338         MIPs_t::const_iterator aEnd = maMIPs.upper_bound( xCurrent );
339         MIPs_t::const_iterator aIter = maMIPs.lower_bound( xCurrent );
340         for( ; aIter != aEnd; aIter++ )
341           aMIP.join( aIter->second.second );
342 
343         // inherit from current node (or set if we are at the start node)
344         if( xCurrent == xNode )
345             aRet = aMIP;
346         else
347             aRet.inherit( aMIP );
348     }
349 
350     return aRet;
351 }
352 
353 
354 
355 void Model::rebind()
356 {
357     OSL_ENSURE( mpBindings != NULL, "bindings?" );
358 
359     // iterate over all bindings and call update
360     sal_Int32 nCount = mpBindings->countItems();
361     for( sal_Int32 i = 0; i < nCount; i++ )
362     {
363         Binding* pBind = Binding::getBinding( mpBindings->Collection<XPropertySet_t>::getItem( i ) );
364         OSL_ENSURE( pBind != NULL, "binding?" );
365         pBind->update();
366     }
367 }
368 
369 
370 
371 void Model::deferNotifications( bool bDefer )
372 {
373     // iterate over all bindings and defer notifications
374     sal_Int32 nCount = mpBindings->countItems();
375     for( sal_Int32 i = 0; i < nCount; i++ )
376     {
377         Binding* pBind = Binding::getBinding( mpBindings->Collection<XPropertySet_t>::getItem( i ) );
378         OSL_ENSURE( pBind != NULL, "binding?" );
379         pBind->deferNotifications( bDefer );
380     }
381 }
382 
383 
384 bool Model::setSimpleContent( const XNode_t& xConstNode,
385                               const rtl::OUString& sValue )
386 {
387     OSL_ENSURE( xConstNode.is(), "need node to set data" );
388 
389     bool bRet = false;
390     if( xConstNode.is() )
391     {
392         // non-const node reference so we can assign children (if necessary)
393         XNode_t xNode( xConstNode );
394 
395         switch( xNode->getNodeType() )
396         {
397         case NodeType_ELEMENT_NODE:
398         {
399             // find first text node child
400             Reference<XNode> xChild;
401             for( xChild = xNode->getFirstChild();
402                  xChild.is() && xChild->getNodeType() != NodeType_TEXT_NODE;
403                  xChild = xChild->getNextSibling() )
404                 ; // empty loop; only find first text node child
405 
406             // create text node, if none is found
407             if( ! xChild.is() )
408             {
409                 xChild = Reference<XNode>(
410                     xNode->getOwnerDocument()->createTextNode( OUString() ),
411                     UNO_QUERY_THROW );
412                 xNode->appendChild( xChild );
413             }
414             xNode = xChild;
415 
416             OSL_ENSURE( xNode.is() &&
417                         xNode->getNodeType() == NodeType_TEXT_NODE,
418                         "text node creation failed?" );
419         }
420         // no break; continue as with text node:
421 
422         case NodeType_TEXT_NODE:
423         case NodeType_ATTRIBUTE_NODE:
424         {
425             // set the node value (defer notifications)
426             if( xNode->getNodeValue() != sValue )
427             {
428                 deferNotifications( true );
429                 xNode->setNodeValue( sValue );
430                 deferNotifications( false );
431             }
432             bRet = true;
433         }
434         break;
435 
436         default:
437         {
438             OSL_ENSURE( false, "bound to unknown node type?" );
439         }
440         break;
441 
442         }
443     }
444     return bRet;
445 }
446 
447 void Model::loadInstance( sal_Int32 nInstance )
448 {
449     Sequence<PropertyValue> aSequence = mpInstances->getItem( nInstance );
450 
451     // find URL from instance
452     OUString sURL;
453     bool bOnce = false;
454     getInstanceData( aSequence, NULL, NULL, &sURL, &bOnce );
455 
456     // if we have a URL, load the document and set it into the instance
457     if( sURL.getLength() > 0 )
458     {
459         try
460         {
461             Reference<XInputStream> xInput =
462                 Reference<XSimpleFileAccess>(
463                     createInstance(
464                         OUSTRING("com.sun.star.ucb.SimpleFileAccess") ),
465                     UNO_QUERY_THROW )->openFileRead( sURL );
466             if( xInput.is() )
467             {
468                 Reference<XDocument> xInstance =
469                     getDocumentBuilder()->parse( xInput );
470                 if( xInstance.is() )
471                 {
472                     OUString sEmpty;
473                     setInstanceData( aSequence, NULL, &xInstance,
474                                      bOnce ? &sEmpty : &sURL, NULL);
475                     mpInstances->setItem( nInstance, aSequence );
476                 }
477             }
478         }
479         catch( const Exception& )
480         {
481             // couldn't load the instance -> ignore!
482         }
483     }
484 }
485 
486 void Model::loadInstances()
487 {
488     // iterate over instance array to get PropertyValue-Sequence
489     const sal_Int32 nInstances = mpInstances->countItems();
490     for( sal_Int32 nInstance = 0; nInstance < nInstances; nInstance++ )
491     {
492         loadInstance( nInstance );
493     }
494 }
495 
496 bool Model::isInitialized() const
497 {
498     return mbInitialized;
499 }
500 
501 bool Model::isValid() const
502 {
503     bool bValid = true;
504     sal_Int32 nCount = mpBindings->countItems();
505     for( sal_Int32 i = 0; bValid && i < nCount; i++ )
506     {
507         Binding* pBind = Binding::getBinding( mpBindings->Collection<XPropertySet_t>::getItem( i ) );
508         OSL_ENSURE( pBind != NULL, "binding?" );
509         bValid = pBind->isValid();
510     }
511     return bValid;
512 }
513 
514 
515 
516 //
517 // implement xforms::XModel
518 //
519 
520 rtl::OUString Model::getID()
521     throw( RuntimeException )
522 {
523     DBG_INVARIANT();
524     return msID;
525 }
526 
527 void Model::setID( const rtl::OUString& sID )
528     throw( RuntimeException )
529 {
530     DBG_INVARIANT();
531     msID = sID;
532 }
533 
534 void Model::initialize()
535     throw( RuntimeException )
536 {
537     DBG_ASSERT( ! mbInitialized, "model already initialized" );
538 
539     // load instances
540     loadInstances();
541 
542     // let's pretend we're initialized and rebind all bindings
543     mbInitialized = true;
544     rebind();
545 }
546 
547 void Model::rebuild()
548     throw( RuntimeException )
549 {
550     if( ! mbInitialized )
551         initialize();
552     else
553         rebind();
554 }
555 
556 void Model::recalculate()
557     throw( RuntimeException )
558 {
559     rebind();
560 }
561 
562 void Model::revalidate()
563     throw( RuntimeException )
564 {
565     // do nothing. We don't validate anyways!
566 }
567 
568 void Model::refresh()
569     throw( RuntimeException )
570 {
571     rebind();
572 }
573 
574 
575 void SAL_CALL Model::submitWithInteraction(
576     const rtl::OUString& sID,
577     const XInteractionHandler_t& _rxHandler )
578     throw( VetoException,
579            WrappedTargetException,
580            RuntimeException )
581 {
582     DBG_INVARIANT();
583 
584     if( mpSubmissions->hasItem( sID ) )
585     {
586         Submission* pSubmission =
587             Submission::getSubmission( mpSubmissions->getItem( sID ) );
588         OSL_ENSURE( pSubmission != NULL, "no submission?" );
589         OSL_ENSURE( pSubmission->getModel() == Reference<XModel>( this ),
590                     "wrong model" );
591 
592         // submit. All exceptions are allowed to leave.
593         pSubmission->submitWithInteraction( _rxHandler );
594     }
595 }
596 
597 void Model::submit( const rtl::OUString& sID )
598     throw( VetoException, WrappedTargetException, RuntimeException )
599 {
600     submitWithInteraction( sID, NULL );
601 }
602 
603 Model::XDataTypeRepository_t SAL_CALL Model::getDataTypeRepository(  )
604     throw( RuntimeException )
605 {
606     if ( !mxDataTypes.is() )
607         mxDataTypes = new ODataTypeRepository;
608 
609     return mxDataTypes;
610 }
611 
612 //
613 // instance management
614 //
615 
616 Model::XSet_t Model::getInstances()
617     throw( RuntimeException )
618 {
619     return mxInstances;
620 }
621 
622 Model::XDocument_t Model::getInstanceDocument( const rtl::OUString& rName )
623     throw( RuntimeException )
624 {
625     ensureAtLeastOneInstance();
626     Reference<XDocument> aInstance;
627     sal_Int32 nInstance = lcl_findInstance( mpInstances, rName );
628     if( nInstance != -1 )
629         getInstanceData( mpInstances->getItem( nInstance ),
630                          NULL, &aInstance, NULL, NULL );
631     return aInstance;
632 }
633 
634 Model::XDocument_t SAL_CALL Model::getDefaultInstance()
635     throw( RuntimeException )
636 {
637     ensureAtLeastOneInstance();
638     DBG_ASSERT( mpInstances->countItems() > 0, "no instance?" );
639     Reference<XDocument> aInstance;
640     getInstanceData( mpInstances->getItem( 0 ), NULL, &aInstance, NULL, NULL );
641     return aInstance;
642 }
643 
644 
645 
646 //
647 // bindings management
648 //
649 
650 Model::XPropertySet_t SAL_CALL Model::createBinding()
651     throw( RuntimeException )
652 {
653     DBG_INVARIANT();
654     return new Binding();
655 }
656 
657 Model::XPropertySet_t Model::cloneBinding( const XPropertySet_t& xBinding )
658     throw( RuntimeException )
659 {
660     DBG_INVARIANT();
661     XPropertySet_t xNewBinding = createBinding();
662     copy( xBinding, xNewBinding );
663     return xNewBinding;
664 }
665 
666 Model::XPropertySet_t Model::getBinding( const rtl::OUString& sId )
667     throw( RuntimeException )
668 {
669     DBG_INVARIANT();
670     return mpBindings->hasItem( sId ) ? mpBindings->getItem( sId ) : NULL;
671 }
672 
673 Model::XSet_t Model::getBindings()
674     throw( RuntimeException )
675 {
676     DBG_INVARIANT();
677     return mxBindings;
678 }
679 
680 
681 
682 //
683 // submission management
684 //
685 
686 Model::XSubmission_t Model::createSubmission()
687     throw( RuntimeException )
688 {
689     DBG_INVARIANT();
690     return new Submission();
691 }
692 
693 Model::XSubmission_t Model::cloneSubmission(const XPropertySet_t& xSubmission)
694     throw( RuntimeException )
695 {
696     DBG_INVARIANT();
697     XSubmission_t xNewSubmission = createSubmission();
698     XPropertySet_t xAsPropertySet( xNewSubmission.get() );
699     copy( xSubmission.get(), xAsPropertySet );
700     return xNewSubmission;
701 }
702 
703 Model::XSubmission_t Model::getSubmission( const rtl::OUString& sId )
704     throw( RuntimeException )
705 {
706     DBG_INVARIANT();
707     XSubmission_t xSubmission;
708     if ( mpSubmissions->hasItem( sId ) )
709         xSubmission = xSubmission.query( mpSubmissions->getItem( sId ) );
710     return xSubmission;
711 }
712 
713 Model::XSet_t Model::getSubmissions()
714     throw( RuntimeException )
715 {
716     DBG_INVARIANT();
717     return mxSubmissions;
718 }
719 
720 
721 
722 //
723 // implementation of XFormsUIHelper1 interface
724 //   can be found in file model_ui.cxx
725 //
726 
727 
728 
729 //
730 // implement XPropertySet & friends
731 //
732 
733 #define HANDLE_ID 0
734 #define HANDLE_Instance 1
735 #define HANDLE_InstanceURL 2
736 #define HANDLE_ForeignSchema 3
737 #define HANDLE_SchemaRef 4
738 #define HANDLE_Namespaces 5
739 #define HANDLE_ExternalData 6
740 
741 #define REGISTER_PROPERTY( property, type )   \
742     registerProperty( PROPERTY( property, type ), \
743     new DirectPropertyAccessor< Model, type >( this, &Model::set##property, &Model::get##property ) );
744 
745 #define REGISTER_PROPERTY_API( property, type )   \
746     registerProperty( PROPERTY( property, type ), \
747     new APIPropertyAccessor< Model, type >( this, &Model::set##property, &Model::get##property ) );
748 
749 #define REGISTER_BOOL_PROPERTY( property )   \
750     registerProperty( PROPERTY( property, sal_Bool ), \
751     new BooleanPropertyAccessor< Model, bool >( this, &Model::set##property, &Model::get##property ) );
752 
753 void Model::initializePropertySet()
754 {
755     REGISTER_PROPERTY_API ( ID,            OUString );
756     REGISTER_PROPERTY     ( ForeignSchema, XDocument_t );
757     REGISTER_PROPERTY     ( SchemaRef,     OUString );
758     REGISTER_PROPERTY     ( Namespaces,    XNameContainer_t );
759     REGISTER_BOOL_PROPERTY( ExternalData );
760 }
761 
762 void Model::update()
763     throw( RuntimeException )
764 {
765     rebuild();
766 }
767 
768 
769 sal_Int64 Model::getSomething( const IntSequence_t& xId )
770     throw( RuntimeException )
771 {
772     return reinterpret_cast<sal_Int64>( ( xId == getUnoTunnelID() ) ? this : NULL );
773 }
774 
775 Sequence<sal_Int8> Model::getImplementationId()
776     throw( RuntimeException )
777 {
778     return getUnoTunnelID();
779 }
780 
781 
782 //
783 // 'shift' operators for getting data into and out of Anys
784 //
785 
786 void operator <<= ( com::sun::star::uno::Any& rAny,
787                     xforms::Model* pModel)
788 {
789     Reference<XPropertySet> xPropSet( static_cast<XPropertySet*>( pModel ) );
790     rAny <<= xPropSet;
791 }
792 
793 bool operator >>= ( xforms::Model* pModel,
794                     com::sun::star::uno::Any& rAny )
795 {
796     bool bRet = false;
797 
798     // acquire model pointer through XUnoTunnel
799     Reference<XUnoTunnel> xTunnel( rAny, UNO_QUERY );
800     if( xTunnel.is() )
801     {
802         pModel = reinterpret_cast<xforms::Model*>(
803             xTunnel->getSomething( xforms::Model::getUnoTunnelID() ) );
804         bRet = true;
805     }
806 
807     return bRet;
808 }
809