/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include "BrowseNodeFactoryImpl.hxx" #include #include #include #include #include #include using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::script; using namespace ::sf_misc; namespace browsenodefactory { namespace { class BrowseNodeAggregator : public ::cppu::WeakImplHelper< browse::XBrowseNode > { private: OUString m_Name; std::vector< Reference< browse::XBrowseNode > > m_Nodes; public: explicit BrowseNodeAggregator( const Reference< browse::XBrowseNode >& node ) : m_Name(node->getName()) { m_Nodes.resize( 1 ); m_Nodes[ 0 ] = node; } void addBrowseNode( const Reference< browse::XBrowseNode>& node ) { m_Nodes.push_back( node ); } virtual OUString SAL_CALL getName() override { return m_Name; } virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL getChildNodes() override { std::vector< Sequence< Reference < browse::XBrowseNode > > > seqs; seqs.reserve( m_Nodes.size() ); sal_Int32 numChildren = 0; for (Reference & xNode : m_Nodes) { Sequence< Reference < browse::XBrowseNode > > children; try { children = xNode->getChildNodes(); seqs.push_back( children ); numChildren += children.getLength(); } catch ( Exception& ) { // some form of exception getting child nodes so they // won't be displayed } } Sequence< Reference < browse::XBrowseNode > > result( numChildren ); sal_Int32 index = 0; for ( const Sequence< Reference < browse::XBrowseNode > >& children : seqs ) { std::copy(children.begin(), children.end(), std::next(result.getArray(), index)); index += children.getLength(); if (index >= numChildren) break; } return result; } virtual sal_Bool SAL_CALL hasChildNodes() override { for (Reference & xNode : m_Nodes) { try { if ( xNode->hasChildNodes() ) { return true; } } catch ( Exception& ) { // some form of exception getting child nodes so move // on to the next one } } return false; } virtual sal_Int16 SAL_CALL getType() override { return browse::BrowseNodeTypes::CONTAINER; } }; struct alphaSort { bool operator()( const OUString& a, std::u16string_view b ) { return a.compareTo( b ) < 0; } }; class LocationBrowseNode : public ::cppu::WeakImplHelper< browse::XBrowseNode > { private: std::optional >> m_hBNA; std::vector< OUString > m_vStr; OUString m_sNodeName; Reference< browse::XBrowseNode > m_origNode; public: explicit LocationBrowseNode( const Reference< browse::XBrowseNode >& node ) : m_sNodeName(node->getName()) { m_origNode.set( node ); } // XBrowseNode virtual OUString SAL_CALL getName() override { return m_sNodeName; } virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL getChildNodes() override { if ( !m_hBNA ) { loadChildNodes(); } Sequence< Reference< browse::XBrowseNode > > children( m_hBNA->size() ); auto childrenRange = asNonConstRange(children); sal_Int32 index = 0; for ( const auto& str : m_vStr ) { childrenRange[ index ].set( m_hBNA->find( str )->second ); ++index; } return children; } virtual sal_Bool SAL_CALL hasChildNodes() override { return true; } virtual sal_Int16 SAL_CALL getType() override { return browse::BrowseNodeTypes::CONTAINER; } private: void loadChildNodes() { m_hBNA.emplace(); const Sequence< Reference< browse::XBrowseNode > > langNodes = m_origNode->getChildNodes(); for ( const auto& rLangNode : langNodes ) { Reference< browse::XBrowseNode > xbn; if ( rLangNode->getName() == "uno_packages" ) { xbn.set( new LocationBrowseNode( rLangNode ) ); } else { xbn.set( rLangNode ); } const Sequence< Reference< browse::XBrowseNode > > grandchildren = xbn->getChildNodes(); for ( const Reference< browse::XBrowseNode >& grandchild : grandchildren ) { auto h_it = m_hBNA->find( grandchild->getName() ); if ( h_it != m_hBNA->end() ) { BrowseNodeAggregator* bna = static_cast< BrowseNodeAggregator* >( h_it->second.get() ); bna->addBrowseNode( grandchild ); } else { Reference< browse::XBrowseNode > bna( new BrowseNodeAggregator( grandchild ) ); (*m_hBNA)[ grandchild->getName() ].set( bna ); m_vStr.push_back( grandchild->getName() ); } } } // sort children alphabetically ::std::sort( m_vStr.begin(), m_vStr.end(), alphaSort() ); } }; std::vector< Reference< browse::XBrowseNode > > getAllBrowseNodes( const Reference< XComponentContext >& xCtx ) { const Sequence< OUString > openDocs = MiscUtils::allOpenTDocUrls( xCtx ); Reference< provider::XScriptProviderFactory > xFac; sal_Int32 initialSize = openDocs.getLength() + 2; sal_Int32 mspIndex = 0; std::vector< Reference < browse::XBrowseNode > > locnBNs( initialSize ); try { xFac = provider::theMasterScriptProviderFactory::get( xCtx ); locnBNs[ mspIndex++ ].set( xFac->createScriptProvider( makeAny( OUString("user") ) ), UNO_QUERY_THROW ); locnBNs[ mspIndex++ ].set( xFac->createScriptProvider( makeAny( OUString("share") ) ), UNO_QUERY_THROW ); } // TODO proper exception handling, should throw catch( const Exception& ) { TOOLS_WARN_EXCEPTION("scripting", "Caught" ); locnBNs.resize( mspIndex ); return locnBNs; } for ( const auto& rDoc : openDocs ) { try { Reference< frame::XModel > model( MiscUtils::tDocUrlToModel( rDoc ), UNO_SET_THROW ); // #i44599 Check if it's a real document or something special like Hidden/Preview css::uno::Reference< css::frame::XController > xCurrentController = model->getCurrentController(); if( xCurrentController.is() ) { utl::MediaDescriptor aMD( model->getArgs() ); bool bDefault = false; bool bHidden = aMD.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_HIDDEN, bDefault ); bool bPreview = aMD.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_PREVIEW, bDefault ); if( !bHidden && !bPreview ) { Reference< document::XEmbeddedScripts > xScripts( model, UNO_QUERY ); if ( xScripts.is() ) locnBNs[ mspIndex++ ].set( xFac->createScriptProvider( makeAny( model ) ), UNO_QUERY_THROW ); } } } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("scripting"); } } std::vector< Reference < browse::XBrowseNode > > locnBNs_Return( mspIndex ); for ( sal_Int32 j = 0; j < mspIndex; j++ ) locnBNs_Return[j] = locnBNs[j]; return locnBNs_Return; } } // namespace typedef ::std::vector< Reference< browse::XBrowseNode > > vXBrowseNodes; namespace { struct alphaSortForBNodes { bool operator()( const Reference< browse::XBrowseNode >& a, const Reference< browse::XBrowseNode >& b ) { return a->getName().compareTo( b->getName() ) < 0; } }; } typedef ::cppu::WeakImplHelper< browse::XBrowseNode > t_BrowseNodeBase; namespace { class DefaultBrowseNode : public t_BrowseNodeBase { private: Reference< browse::XBrowseNode > m_xWrappedBrowseNode; Reference< lang::XTypeProvider > m_xWrappedTypeProv; Reference< XAggregation > m_xAggProxy; Reference< XComponentContext > m_xCtx; public: DefaultBrowseNode( const Reference< XComponentContext >& xCtx, const Reference< browse::XBrowseNode>& xNode ) : m_xWrappedBrowseNode( xNode ), m_xWrappedTypeProv( xNode, UNO_QUERY ), m_xCtx( xCtx ) { OSL_ENSURE( m_xWrappedBrowseNode.is(), "DefaultBrowseNode::DefaultBrowseNode(): No BrowseNode to wrap" ); OSL_ENSURE( m_xWrappedTypeProv.is(), "DefaultBrowseNode::DefaultBrowseNode(): No BrowseNode to wrap" ); OSL_ENSURE( m_xCtx.is(), "DefaultBrowseNode::DefaultBrowseNode(): No ComponentContext" ); // Use proxy factory service to create aggregatable proxy. try { Reference< reflection::XProxyFactory > xProxyFac = reflection::ProxyFactory::create( m_xCtx ); m_xAggProxy = xProxyFac->createProxy( m_xWrappedBrowseNode ); } catch( uno::Exception& ) { TOOLS_WARN_EXCEPTION( "scripting", "DefaultBrowseNode::DefaultBrowseNode" ); } OSL_ENSURE( m_xAggProxy.is(), "DefaultBrowseNode::DefaultBrowseNode: Wrapped BrowseNode cannot be aggregated!" ); if ( !m_xAggProxy.is() ) return; osl_atomic_increment( &m_refCount ); /* i35609 - Fix crash on Solaris. The setDelegator call needs to be in its own block to ensure that all temporary Reference instances that are acquired during the call are released before m_refCount is decremented again */ { m_xAggProxy->setDelegator( static_cast< cppu::OWeakObject * >( this ) ); } osl_atomic_decrement( &m_refCount ); } virtual ~DefaultBrowseNode() override { if ( m_xAggProxy.is() ) { m_xAggProxy->setDelegator( uno::Reference< uno::XInterface >() ); } } virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL getChildNodes() override { if ( hasChildNodes() ) { vXBrowseNodes aVNodes; const Sequence < Reference< browse::XBrowseNode > > nodes = m_xWrappedBrowseNode->getChildNodes(); for ( const Reference< browse::XBrowseNode >& xBrowseNode : nodes ) { OSL_ENSURE( xBrowseNode.is(), "DefaultBrowseNode::getChildNodes(): Invalid BrowseNode" ); if( xBrowseNode.is() ) aVNodes.push_back( new DefaultBrowseNode( m_xCtx, xBrowseNode ) ); } ::std::sort( aVNodes.begin(), aVNodes.end(), alphaSortForBNodes() ); Sequence < Reference< browse::XBrowseNode > > children( aVNodes.size() ); auto childrenRange = asNonConstRange(children); sal_Int32 i = 0; for ( const auto& rxNode : aVNodes ) { childrenRange[ i ].set( rxNode ); i++; } return children; } else { // no nodes Sequence < Reference< browse::XBrowseNode > > none; return none; } } virtual sal_Int16 SAL_CALL getType() override { return m_xWrappedBrowseNode->getType(); } virtual OUString SAL_CALL getName() override { return m_xWrappedBrowseNode->getName(); } virtual sal_Bool SAL_CALL hasChildNodes() override { return m_xWrappedBrowseNode->hasChildNodes(); } // XInterface virtual Any SAL_CALL queryInterface( const Type& aType ) override { Any aRet = t_BrowseNodeBase::queryInterface( aType ); if ( aRet.hasValue() ) { return aRet; } if ( m_xAggProxy.is() ) { return m_xAggProxy->queryAggregation( aType ); } else { return Any(); } } // XTypeProvider (implemented by base, but needs to be overridden for // delegating to aggregate) virtual Sequence< Type > SAL_CALL getTypes() override { return m_xWrappedTypeProv->getTypes(); } virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override { return css::uno::Sequence(); } }; class DefaultRootBrowseNode : public ::cppu::WeakImplHelper< browse::XBrowseNode > { private: vXBrowseNodes m_vNodes; OUString m_Name; public: explicit DefaultRootBrowseNode( const Reference< XComponentContext >& xCtx ) { std::vector< Reference< browse::XBrowseNode > > nodes = getAllBrowseNodes( xCtx ); for (Reference< browse::XBrowseNode > & xNode : nodes) { m_vNodes.push_back( new DefaultBrowseNode( xCtx, xNode ) ); } m_Name = "Root"; } virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL getChildNodes() override { // no need to sort user, share, doc1...docN //::std::sort( m_vNodes.begin(), m_vNodes.end(), alphaSortForBNodes() ); Sequence < Reference< browse::XBrowseNode > > children( m_vNodes.size() ); auto childrenRange = asNonConstRange(children); sal_Int32 i = 0; for ( const auto& rxNode : m_vNodes ) { childrenRange[ i ].set( rxNode ); i++; } return children; } virtual sal_Int16 SAL_CALL getType() override { return browse::BrowseNodeTypes::ROOT; } virtual OUString SAL_CALL getName() override { return m_Name; } virtual sal_Bool SAL_CALL hasChildNodes() override { bool result = true; if ( m_vNodes.empty() ) { result = false; } return result; } }; class SelectorBrowseNode : public ::cppu::WeakImplHelper< browse::XBrowseNode > { private: Reference< XComponentContext > m_xComponentContext; public: explicit SelectorBrowseNode( const Reference< XComponentContext >& xContext ) : m_xComponentContext( xContext ) { } virtual OUString SAL_CALL getName() override { return "Root"; } virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL getChildNodes() override { std::vector< Reference < browse::XBrowseNode > > locnBNs = getAllBrowseNodes( m_xComponentContext ); Sequence< Reference< browse::XBrowseNode > > children( locnBNs.size() ); auto childrenRange = asNonConstRange(children); for ( size_t j = 0; j < locnBNs.size(); j++ ) { childrenRange[j] = new LocationBrowseNode( locnBNs[j] ); } return children; } virtual sal_Bool SAL_CALL hasChildNodes() override { return true; // will always be user and share } virtual sal_Int16 SAL_CALL getType() override { return browse::BrowseNodeTypes::CONTAINER; } }; } BrowseNodeFactoryImpl::BrowseNodeFactoryImpl( Reference< XComponentContext > const & xComponentContext ) : m_xComponentContext( xComponentContext ) { } BrowseNodeFactoryImpl::~BrowseNodeFactoryImpl() { } // Implementation of XBrowseNodeFactory /* * The selector hierarchy is the standard hierarchy for organizers with the * language nodes removed. */ Reference< browse::XBrowseNode > SAL_CALL BrowseNodeFactoryImpl::createView( sal_Int16 viewType ) { switch( viewType ) { case browse::BrowseNodeFactoryViewTypes::MACROSELECTOR: return new SelectorBrowseNode( m_xComponentContext ); case browse::BrowseNodeFactoryViewTypes::MACROORGANIZER: return getOrganizerHierarchy(); default: throw RuntimeException( "Unknown view type" ); } } Reference< browse::XBrowseNode > BrowseNodeFactoryImpl::getOrganizerHierarchy() const { Reference< browse::XBrowseNode > xRet = new DefaultRootBrowseNode( m_xComponentContext ); return xRet; } // Implementation of XServiceInfo OUString SAL_CALL BrowseNodeFactoryImpl::getImplementationName() { return "com.sun.star.script.browse.BrowseNodeFactory"; } Sequence< OUString > SAL_CALL BrowseNodeFactoryImpl::getSupportedServiceNames() { return { "com.sun.star.script.browse.BrowseNodeFactory" }; } sal_Bool BrowseNodeFactoryImpl::supportsService(OUString const & serviceName ) { return cppu::supportsService(this, serviceName); } extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* scripting_BrowseNodeFactoryImpl_get_implementation( css::uno::XComponentContext* context, css::uno::Sequence const&) { return cppu::acquire(new BrowseNodeFactoryImpl(context)); } } // namespace browsenodefactory /* vim:set shiftwidth=4 softtabstop=4 expandtab: */