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 <cppuhelper/weakref.hxx> 22 #include <cppuhelper/implementationentry.hxx> 23 #include <cppuhelper/factory.hxx> 24 #include <cppuhelper/exc_hlp.hxx> 25 #include <cppuhelper/implbase.hxx> 26 #include <cppuhelper/supportsservice.hxx> 27 #include <unotools/mediadescriptor.hxx> 28 29 #include <com/sun/star/lang/XMultiComponentFactory.hpp> 30 #include <com/sun/star/frame/XModel.hpp> 31 #include <com/sun/star/reflection/ProxyFactory.hpp> 32 33 #include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp> 34 #include <com/sun/star/script/browse/BrowseNodeFactoryViewTypes.hpp> 35 #include <com/sun/star/script/browse/BrowseNodeTypes.hpp> 36 #include <com/sun/star/document/XScriptInvocationContext.hpp> 37 38 #include <tools/diagnose_ex.h> 39 #include <sal/log.hxx> 40 41 #include "BrowseNodeFactoryImpl.hxx" 42 #include "MasterScriptProvider.hxx" 43 #include "ActiveMSPList.hxx" 44 #include <util/MiscUtils.hxx> 45 46 #include <vector> 47 #include <algorithm> 48 #include <memory> 49 50 using namespace ::com::sun::star; 51 using namespace ::com::sun::star::uno; 52 using namespace ::com::sun::star::script; 53 using namespace ::sf_misc; 54 55 namespace browsenodefactory 56 { 57 class BrowseNodeAggregator : 58 public ::cppu::WeakImplHelper< browse::XBrowseNode > 59 { 60 private: 61 OUString m_Name; 62 std::vector< Reference< browse::XBrowseNode > > m_Nodes; 63 64 public: 65 66 explicit BrowseNodeAggregator( const Reference< browse::XBrowseNode >& node ) 67 { 68 m_Name = node->getName(); 69 m_Nodes.resize( 1 ); 70 m_Nodes[ 0 ] = node; 71 } 72 73 void addBrowseNode( const Reference< browse::XBrowseNode>& node ) 74 { 75 m_Nodes.push_back( node ); 76 } 77 78 virtual OUString 79 SAL_CALL getName() override 80 { 81 return m_Name; 82 } 83 84 virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL 85 getChildNodes() override 86 { 87 std::vector< Sequence< Reference < browse::XBrowseNode > > > seqs; 88 seqs.reserve( m_Nodes.size() ); 89 90 sal_Int32 numChildren = 0; 91 92 for (Reference<XBrowseNode> & xNode : m_Nodes) 93 { 94 Sequence< Reference < browse::XBrowseNode > > children; 95 try 96 { 97 children = xNode->getChildNodes(); 98 seqs.push_back( children ); 99 numChildren += children.getLength(); 100 } 101 catch ( Exception& ) 102 { 103 // some form of exception getting child nodes so they 104 // won't be displayed 105 } 106 } 107 108 std::vector< Sequence< Reference < browse::XBrowseNode > > >::const_iterator it = seqs.begin(); 109 std::vector< Sequence< Reference < browse::XBrowseNode > > >::const_iterator it_end = seqs.end(); 110 111 Sequence< Reference < browse::XBrowseNode > > result( numChildren ); 112 for ( sal_Int32 index = 0; it != it_end && index < numChildren ; ++it ) 113 { 114 Sequence< Reference < browse::XBrowseNode > > children = *it; 115 for ( sal_Int32 j = 0; j < children.getLength(); j++ ) 116 { 117 result[ index++ ] = children[ j ]; 118 } 119 } 120 return result; 121 } 122 123 virtual sal_Bool SAL_CALL 124 hasChildNodes() override 125 { 126 if ( !m_Nodes.empty() ) 127 { 128 for (Reference<XBrowseNode> & xNode : m_Nodes) 129 { 130 try 131 { 132 if ( xNode->hasChildNodes() ) 133 { 134 return true; 135 } 136 } 137 catch ( Exception& ) 138 { 139 // some form of exception getting child nodes so move 140 // on to the next one 141 } 142 } 143 } 144 145 return false; 146 } 147 148 virtual sal_Int16 SAL_CALL getType() override 149 { 150 return browse::BrowseNodeTypes::CONTAINER; 151 } 152 }; 153 154 struct alphaSort 155 { 156 bool operator()( const OUString& a, const OUString& b ) 157 { 158 return a.compareTo( b ) < 0; 159 } 160 }; 161 class LocationBrowseNode : 162 public ::cppu::WeakImplHelper< browse::XBrowseNode > 163 { 164 private: 165 std::unique_ptr<std::unordered_map< OUString, Reference< browse::XBrowseNode > >> m_hBNA; 166 std::vector< OUString > m_vStr; 167 OUString m_sNodeName; 168 Reference< browse::XBrowseNode > m_origNode; 169 170 public: 171 172 explicit LocationBrowseNode( const Reference< browse::XBrowseNode >& node ) 173 { 174 m_sNodeName = node->getName(); 175 m_hBNA = nullptr; 176 m_origNode.set( node ); 177 } 178 179 180 // XBrowseNode 181 182 virtual OUString SAL_CALL getName() override 183 { 184 return m_sNodeName; 185 } 186 187 virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL 188 getChildNodes() override 189 { 190 if ( m_hBNA == nullptr ) 191 { 192 loadChildNodes(); 193 } 194 195 Sequence< Reference< browse::XBrowseNode > > children( m_hBNA->size() ); 196 sal_Int32 index = 0; 197 198 for ( auto& str : m_vStr ) 199 { 200 children[ index ].set( m_hBNA->find( str )->second ); 201 ++index; 202 } 203 204 return children; 205 } 206 207 virtual sal_Bool SAL_CALL hasChildNodes() override 208 { 209 return true; 210 } 211 212 virtual sal_Int16 SAL_CALL getType() override 213 { 214 return browse::BrowseNodeTypes::CONTAINER; 215 } 216 217 private: 218 219 void loadChildNodes() 220 { 221 m_hBNA.reset( new std::unordered_map< OUString, Reference< browse::XBrowseNode > > ); 222 223 Sequence< Reference< browse::XBrowseNode > > langNodes = 224 m_origNode->getChildNodes(); 225 226 for ( sal_Int32 i = 0; i < langNodes.getLength(); i++ ) 227 { 228 Reference< browse::XBrowseNode > xbn; 229 if ( langNodes[ i ]->getName() == "uno_packages" ) 230 { 231 xbn.set( new LocationBrowseNode( langNodes[ i ] ) ); 232 } 233 else 234 { 235 xbn.set( langNodes[ i ] ); 236 } 237 238 Sequence< Reference< browse::XBrowseNode > > grandchildren = 239 xbn->getChildNodes(); 240 241 for ( sal_Int32 j = 0; j < grandchildren.getLength(); j++ ) 242 { 243 Reference< browse::XBrowseNode > grandchild(grandchildren[j]); 244 245 auto h_it = 246 m_hBNA->find( grandchild->getName() ); 247 248 if ( h_it != m_hBNA->end() ) 249 { 250 BrowseNodeAggregator* bna = static_cast< BrowseNodeAggregator* >( h_it->second.get() ); 251 bna->addBrowseNode( grandchild ); 252 } 253 else 254 { 255 Reference< browse::XBrowseNode > bna( 256 new BrowseNodeAggregator( grandchild ) ); 257 (*m_hBNA)[ grandchild->getName() ].set( bna ); 258 m_vStr.push_back( grandchild->getName() ); 259 } 260 } 261 } 262 // sort children alphabetically 263 ::std::sort( m_vStr.begin(), m_vStr.end(), alphaSort() ); 264 } 265 }; 266 267 namespace 268 { 269 270 std::vector< Reference< browse::XBrowseNode > > getAllBrowseNodes( const Reference< XComponentContext >& xCtx ) 271 { 272 Sequence< OUString > openDocs = 273 MiscUtils::allOpenTDocUrls( xCtx ); 274 275 Reference< provider::XScriptProviderFactory > xFac; 276 sal_Int32 initialSize = openDocs.getLength() + 2; 277 sal_Int32 mspIndex = 0; 278 279 std::vector< Reference < browse::XBrowseNode > > locnBNs( initialSize ); 280 try 281 { 282 xFac = provider::theMasterScriptProviderFactory::get( xCtx ); 283 284 locnBNs[ mspIndex++ ].set( xFac->createScriptProvider( makeAny( OUString("user") ) ), UNO_QUERY_THROW ); 285 locnBNs[ mspIndex++ ].set( xFac->createScriptProvider( makeAny( OUString("share") ) ), UNO_QUERY_THROW ); 286 } 287 // TODO proper exception handling, should throw 288 catch( const Exception& e ) 289 { 290 SAL_WARN("scripting", "Caught " << e ); 291 locnBNs.resize( mspIndex ); 292 return locnBNs; 293 } 294 295 for ( sal_Int32 i = 0; i < openDocs.getLength(); i++ ) 296 { 297 try 298 { 299 Reference< frame::XModel > model( MiscUtils::tDocUrlToModel( openDocs[ i ] ), UNO_QUERY_THROW ); 300 301 // #i44599 Check if it's a real document or something special like Hidden/Preview 302 css::uno::Reference< css::frame::XController > xCurrentController = model->getCurrentController(); 303 if( xCurrentController.is() ) 304 { 305 utl::MediaDescriptor aMD( model->getArgs() ); 306 bool bDefault = false; 307 bool bHidden = aMD.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_HIDDEN(), bDefault ); 308 bool bPreview = aMD.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_PREVIEW(), bDefault ); 309 if( !bHidden && !bPreview ) 310 { 311 Reference< document::XEmbeddedScripts > xScripts( model, UNO_QUERY ); 312 if ( xScripts.is() ) 313 locnBNs[ mspIndex++ ].set( xFac->createScriptProvider( makeAny( model ) ), UNO_QUERY_THROW ); 314 } 315 } 316 } 317 catch( const Exception& ) 318 { 319 DBG_UNHANDLED_EXCEPTION("scripting"); 320 } 321 322 } 323 324 std::vector< Reference < browse::XBrowseNode > > locnBNs_Return( mspIndex ); 325 for ( sal_Int32 j = 0; j < mspIndex; j++ ) 326 locnBNs_Return[j] = locnBNs[j]; 327 328 return locnBNs_Return; 329 } 330 331 } // namespace 332 333 typedef ::std::vector< Reference< browse::XBrowseNode > > vXBrowseNodes; 334 335 struct alphaSortForBNodes 336 { 337 bool operator()( const Reference< browse::XBrowseNode >& a, const Reference< browse::XBrowseNode >& b ) 338 { 339 return a->getName().compareTo( b->getName() ) < 0; 340 } 341 }; 342 343 typedef ::cppu::WeakImplHelper< browse::XBrowseNode > t_BrowseNodeBase; 344 class DefaultBrowseNode : 345 public t_BrowseNodeBase 346 { 347 348 private: 349 Reference< browse::XBrowseNode > m_xWrappedBrowseNode; 350 Reference< lang::XTypeProvider > m_xWrappedTypeProv; 351 Reference< XAggregation > m_xAggProxy; 352 Reference< XComponentContext > m_xCtx; 353 354 public: 355 DefaultBrowseNode( const Reference< XComponentContext >& xCtx, const Reference< browse::XBrowseNode>& xNode ) : m_xWrappedBrowseNode( xNode ), m_xWrappedTypeProv( xNode, UNO_QUERY ), m_xCtx( xCtx ) 356 { 357 OSL_ENSURE( m_xWrappedBrowseNode.is(), "DefaultBrowseNode::DefaultBrowseNode(): No BrowseNode to wrap" ); 358 OSL_ENSURE( m_xWrappedTypeProv.is(), "DefaultBrowseNode::DefaultBrowseNode(): No BrowseNode to wrap" ); 359 OSL_ENSURE( m_xCtx.is(), "DefaultBrowseNode::DefaultBrowseNode(): No ComponentContext" ); 360 // Use proxy factory service to create aggregatable proxy. 361 try 362 { 363 Reference< reflection::XProxyFactory > xProxyFac = 364 reflection::ProxyFactory::create( m_xCtx ); 365 m_xAggProxy = xProxyFac->createProxy( m_xWrappedBrowseNode ); 366 } 367 catch( uno::Exception& ) 368 { 369 OSL_FAIL( "DefaultBrowseNode::DefaultBrowseNode: Caught exception!" ); 370 } 371 OSL_ENSURE( m_xAggProxy.is(), 372 "DefaultBrowseNode::DefaultBrowseNode: Wrapped BrowseNode cannot be aggregated!" ); 373 374 if ( m_xAggProxy.is() ) 375 { 376 osl_atomic_increment( &m_refCount ); 377 378 /* i35609 - Fix crash on Solaris. The setDelegator call needs 379 to be in its own block to ensure that all temporary Reference 380 instances that are acquired during the call are released 381 before m_refCount is decremented again */ 382 { 383 m_xAggProxy->setDelegator( 384 static_cast< cppu::OWeakObject * >( this ) ); 385 } 386 387 osl_atomic_decrement( &m_refCount ); 388 } 389 } 390 391 virtual ~DefaultBrowseNode() override 392 { 393 if ( m_xAggProxy.is() ) 394 { 395 m_xAggProxy->setDelegator( uno::Reference< uno::XInterface >() ); 396 } 397 } 398 399 virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL 400 getChildNodes() override 401 { 402 if ( hasChildNodes() ) 403 { 404 vXBrowseNodes aVNodes; 405 Sequence < Reference< browse::XBrowseNode > > nodes = 406 m_xWrappedBrowseNode->getChildNodes(); 407 for ( sal_Int32 i=0; i<nodes.getLength(); i++ ) 408 { 409 Reference< browse::XBrowseNode > xBrowseNode = nodes[ i ]; 410 OSL_ENSURE( xBrowseNode.is(), "DefaultBrowseNode::getChildNodes(): Invalid BrowseNode" ); 411 if( xBrowseNode.is() ) 412 aVNodes.push_back( new DefaultBrowseNode( m_xCtx, xBrowseNode ) ); 413 } 414 415 ::std::sort( aVNodes.begin(), aVNodes.end(), alphaSortForBNodes() ); 416 Sequence < Reference< browse::XBrowseNode > > children( aVNodes.size() ); 417 vXBrowseNodes::const_iterator it = aVNodes.begin(); 418 for ( sal_Int32 i=0; it != aVNodes.end() && i<children.getLength(); i++, ++it ) 419 { 420 children[ i ].set( *it ); 421 } 422 return children; 423 } 424 else 425 { 426 // no nodes 427 428 Sequence < Reference< browse::XBrowseNode > > none; 429 return none; 430 } 431 } 432 433 virtual sal_Int16 SAL_CALL getType() override 434 { 435 return m_xWrappedBrowseNode->getType(); 436 } 437 438 virtual OUString 439 SAL_CALL getName() override 440 { 441 return m_xWrappedBrowseNode->getName(); 442 } 443 444 virtual sal_Bool SAL_CALL 445 hasChildNodes() override 446 { 447 return m_xWrappedBrowseNode->hasChildNodes(); 448 } 449 450 // XInterface 451 virtual Any SAL_CALL queryInterface( const Type& aType ) override 452 { 453 Any aRet = t_BrowseNodeBase::queryInterface( aType ); 454 if ( aRet.hasValue() ) 455 { 456 return aRet; 457 } 458 if ( m_xAggProxy.is() ) 459 { 460 return m_xAggProxy->queryAggregation( aType ); 461 } 462 else 463 { 464 return Any(); 465 } 466 } 467 468 // XTypeProvider (implemnented by base, but needs to be overridden for 469 // delegating to aggregate) 470 virtual Sequence< Type > SAL_CALL getTypes() override 471 { 472 return m_xWrappedTypeProv->getTypes(); 473 } 474 virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override 475 { 476 return css::uno::Sequence<sal_Int8>(); 477 } 478 }; 479 480 class DefaultRootBrowseNode : 481 public ::cppu::WeakImplHelper< browse::XBrowseNode > 482 { 483 484 private: 485 vXBrowseNodes m_vNodes; 486 OUString m_Name; 487 488 public: 489 explicit DefaultRootBrowseNode( const Reference< XComponentContext >& xCtx ) 490 { 491 std::vector< Reference< browse::XBrowseNode > > nodes = 492 getAllBrowseNodes( xCtx ); 493 494 for (Reference< browse::XBrowseNode > & xNode : nodes) 495 { 496 m_vNodes.push_back( new DefaultBrowseNode( xCtx, xNode ) ); 497 } 498 m_Name = "Root"; 499 } 500 501 virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL 502 getChildNodes() override 503 { 504 // no need to sort user, share, doc1...docN 505 //::std::sort( m_vNodes.begin(), m_vNodes.end(), alphaSortForBNodes() ); 506 Sequence < Reference< browse::XBrowseNode > > children( m_vNodes.size() ); 507 vXBrowseNodes::const_iterator it = m_vNodes.begin(); 508 for ( sal_Int32 i=0; it != m_vNodes.end() && i<children.getLength(); i++, ++it ) 509 { 510 children[ i ].set( *it ); 511 } 512 return children; 513 } 514 515 virtual sal_Int16 SAL_CALL getType() override 516 { 517 return browse::BrowseNodeTypes::ROOT; 518 } 519 520 virtual OUString 521 SAL_CALL getName() override 522 { 523 return m_Name; 524 } 525 526 virtual sal_Bool SAL_CALL 527 hasChildNodes() override 528 { 529 bool result = true; 530 if ( m_vNodes.empty() ) 531 { 532 result = false; 533 } 534 return result; 535 } 536 }; 537 538 539 class SelectorBrowseNode : 540 public ::cppu::WeakImplHelper< browse::XBrowseNode > 541 { 542 private: 543 Reference< XComponentContext > m_xComponentContext; 544 545 public: 546 explicit SelectorBrowseNode( const Reference< XComponentContext >& xContext ) 547 : m_xComponentContext( xContext ) 548 { 549 } 550 551 virtual OUString SAL_CALL getName() override 552 { 553 return OUString("Root"); 554 } 555 556 virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL 557 getChildNodes() override 558 { 559 560 std::vector< Reference < browse::XBrowseNode > > locnBNs = getAllBrowseNodes( m_xComponentContext ); 561 562 Sequence< Reference< browse::XBrowseNode > > children( 563 locnBNs.size() ); 564 565 for ( size_t j = 0; j < locnBNs.size(); j++ ) 566 { 567 children[j] = new LocationBrowseNode( locnBNs[j] ); 568 } 569 570 return children; 571 } 572 573 virtual sal_Bool SAL_CALL hasChildNodes() override 574 { 575 return true; // will always be user and share 576 } 577 578 virtual sal_Int16 SAL_CALL getType() override 579 { 580 return browse::BrowseNodeTypes::CONTAINER; 581 } 582 }; 583 584 BrowseNodeFactoryImpl::BrowseNodeFactoryImpl( 585 Reference< XComponentContext > const & xComponentContext ) 586 : m_xComponentContext( xComponentContext ) 587 { 588 } 589 590 BrowseNodeFactoryImpl::~BrowseNodeFactoryImpl() 591 { 592 } 593 594 595 // Implementation of XBrowseNodeFactory 596 597 598 /* 599 * The selector hierarchy is the standard hierarchy for organizers with the 600 * language nodes removed. 601 */ 602 Reference< browse::XBrowseNode > SAL_CALL 603 BrowseNodeFactoryImpl::createView( sal_Int16 viewType ) 604 { 605 switch( viewType ) 606 { 607 case browse::BrowseNodeFactoryViewTypes::MACROSELECTOR: 608 return new SelectorBrowseNode( m_xComponentContext ); 609 case browse::BrowseNodeFactoryViewTypes::MACROORGANIZER: 610 return getOrganizerHierarchy(); 611 default: 612 throw RuntimeException( "Unknown view type" ); 613 } 614 } 615 616 Reference< browse::XBrowseNode > 617 BrowseNodeFactoryImpl::getOrganizerHierarchy() 618 { 619 Reference< browse::XBrowseNode > xRet = new DefaultRootBrowseNode( m_xComponentContext ); 620 return xRet; 621 } 622 623 // Helper methods 624 625 626 // Namespace global methods for setting up BrowseNodeFactory service 627 628 629 Sequence< OUString > 630 bnf_getSupportedServiceNames( ) 631 { 632 OUString str_name( 633 "com.sun.star.script.browse.BrowseNodeFactory"); 634 635 return Sequence< OUString >( &str_name, 1 ); 636 } 637 638 OUString 639 bnf_getImplementationName( ) 640 { 641 return OUString( 642 "com.sun.star.script.browse.BrowseNodeFactory" ); 643 } 644 645 Reference< XInterface > 646 bnf_create( Reference< XComponentContext > const & xComponentContext ) 647 { 648 return static_cast< ::cppu::OWeakObject * >( 649 new BrowseNodeFactoryImpl( xComponentContext ) ); 650 } 651 652 653 // Implementation of XServiceInfo 654 655 656 OUString SAL_CALL 657 BrowseNodeFactoryImpl::getImplementationName() 658 { 659 return bnf_getImplementationName(); 660 } 661 662 Sequence< OUString > SAL_CALL 663 BrowseNodeFactoryImpl::getSupportedServiceNames() 664 { 665 return bnf_getSupportedServiceNames(); 666 } 667 668 sal_Bool BrowseNodeFactoryImpl::supportsService(OUString const & serviceName ) 669 { 670 return cppu::supportsService(this, serviceName); 671 } 672 673 } // namespace browsenodefactory 674 675 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 676
