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