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