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