LibreOffice Module toolkit (master) 1
treedatamodel.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#include <com/sun/star/awt/tree/XMutableTreeDataModel.hpp>
21#include <com/sun/star/lang/IllegalArgumentException.hpp>
22#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
23#include <com/sun/star/lang/XServiceInfo.hpp>
24#include <com/sun/star/uno/XComponentContext.hpp>
27#include <o3tl/safeint.hxx>
28#include <rtl/ref.hxx>
30#include <mutex>
31#include <utility>
32
33using namespace ::com::sun::star;
34using namespace ::com::sun::star::uno;
35using namespace ::com::sun::star::awt;
36using namespace ::com::sun::star::awt::tree;
37using namespace ::com::sun::star::lang;
38
39namespace {
40
41 enum broadcast_type { nodes_changed, nodes_inserted, nodes_removed, structure_changed };
42
43class MutableTreeNode;
44class MutableTreeDataModel;
45
46typedef std::vector< rtl::Reference< MutableTreeNode > > TreeNodeVector;
47
48class MutableTreeDataModel : public ::cppu::WeakAggImplHelper2< XMutableTreeDataModel, XServiceInfo >
49{
50public:
51 MutableTreeDataModel();
52
53 void broadcast( broadcast_type eType, const Reference< XTreeNode >& xParentNode, const Reference< XTreeNode >& rNode );
54
55 // XMutableTreeDataModel
56 virtual css::uno::Reference< css::awt::tree::XMutableTreeNode > SAL_CALL createNode( const css::uno::Any& DisplayValue, sal_Bool ChildrenOnDemand ) override;
57 virtual void SAL_CALL setRoot( const css::uno::Reference< css::awt::tree::XMutableTreeNode >& RootNode ) override;
58
59 // XTreeDataModel
60 virtual css::uno::Reference< css::awt::tree::XTreeNode > SAL_CALL getRoot( ) override;
61 virtual void SAL_CALL addTreeDataModelListener( const css::uno::Reference< css::awt::tree::XTreeDataModelListener >& Listener ) override;
62 virtual void SAL_CALL removeTreeDataModelListener( const css::uno::Reference< css::awt::tree::XTreeDataModelListener >& Listener ) override;
63
64 // XComponent
65 virtual void SAL_CALL dispose( ) override;
66 virtual void SAL_CALL addEventListener( const Reference< XEventListener >& xListener ) override;
67 virtual void SAL_CALL removeEventListener( const Reference< XEventListener >& aListener ) override;
68
69 // XServiceInfo
70 virtual OUString SAL_CALL getImplementationName( ) override;
71 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
72 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
73
74private:
75 void broadcastImpl( std::unique_lock<std::mutex>& rGuard, broadcast_type eType, const Reference< XTreeNode >& xParentNode, const Reference< XTreeNode >& rNode );
76
77 std::mutex m_aMutex;
80 bool mbDisposed;
81 Reference< XTreeNode > mxRootNode;
82};
83
84class MutableTreeNode: public ::cppu::WeakAggImplHelper2< XMutableTreeNode, XServiceInfo >
85{
86 friend class MutableTreeDataModel;
87
88public:
89 MutableTreeNode( rtl::Reference< MutableTreeDataModel > xModel, Any aValue, bool bChildrenOnDemand );
90 virtual ~MutableTreeNode() override;
91
92 void setParent( MutableTreeNode* pParent );
93 void broadcast_changes();
94 void broadcast_changes(std::unique_lock<std::mutex> & rLock,
95 const Reference< XTreeNode >& xNode, bool bNew);
96
97 // XMutableTreeNode
98 virtual css::uno::Any SAL_CALL getDataValue() override;
99 virtual void SAL_CALL setDataValue( const css::uno::Any& _datavalue ) override;
100 virtual void SAL_CALL appendChild( const css::uno::Reference< css::awt::tree::XMutableTreeNode >& ChildNode ) override;
101 virtual void SAL_CALL insertChildByIndex( ::sal_Int32 Index, const css::uno::Reference< css::awt::tree::XMutableTreeNode >& ChildNode ) override;
102 virtual void SAL_CALL removeChildByIndex( ::sal_Int32 Index ) override;
103 virtual void SAL_CALL setHasChildrenOnDemand( sal_Bool ChildrenOnDemand ) override;
104 virtual void SAL_CALL setDisplayValue( const css::uno::Any& Value ) override;
105 virtual void SAL_CALL setNodeGraphicURL( const OUString& URL ) override;
106 virtual void SAL_CALL setExpandedGraphicURL( const OUString& URL ) override;
107 virtual void SAL_CALL setCollapsedGraphicURL( const OUString& URL ) override;
108
109 // XTreeNode
110 virtual css::uno::Reference< css::awt::tree::XTreeNode > SAL_CALL getChildAt( ::sal_Int32 Index ) override;
111 virtual ::sal_Int32 SAL_CALL getChildCount( ) override;
112 virtual css::uno::Reference< css::awt::tree::XTreeNode > SAL_CALL getParent( ) override;
113 virtual ::sal_Int32 SAL_CALL getIndex( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override;
114 virtual sal_Bool SAL_CALL hasChildrenOnDemand( ) override;
115 virtual css::uno::Any SAL_CALL getDisplayValue( ) override;
116 virtual OUString SAL_CALL getNodeGraphicURL( ) override;
117 virtual OUString SAL_CALL getExpandedGraphicURL( ) override;
118 virtual OUString SAL_CALL getCollapsedGraphicURL( ) override;
119
120 // XServiceInfo
121 virtual OUString SAL_CALL getImplementationName( ) override;
122 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
123 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
124
125private:
126 TreeNodeVector maChildren;
127 Any maDisplayValue;
128 Any maDataValue;
129 bool mbHasChildrenOnDemand;
130 std::mutex maMutex;
131 MutableTreeNode* mpParent;
133 OUString maNodeGraphicURL;
134 OUString maExpandedGraphicURL;
135 OUString maCollapsedGraphicURL;
136 bool mbIsInserted;
137};
138
139MutableTreeDataModel::MutableTreeDataModel()
140: mbDisposed( false )
141{
142}
143
144void MutableTreeDataModel::broadcast( broadcast_type eType, const Reference< XTreeNode >& xParentNode, const Reference< XTreeNode >& rNode )
145{
146 std::unique_lock aGuard(m_aMutex);
147 broadcastImpl(aGuard, eType, xParentNode, rNode);
148}
149
150void MutableTreeDataModel::broadcastImpl( std::unique_lock<std::mutex>& rGuard, broadcast_type eType, const Reference< XTreeNode >& xParentNode, const Reference< XTreeNode >& rNode )
151{
152 if( !maTreeDataModelListeners.getLength(rGuard) )
153 return;
154
155 Reference< XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) );
156 const Sequence< Reference< XTreeNode > > aNodes { rNode };
157 TreeDataModelEvent aEvent( xSource, aNodes, xParentNode );
158
159 comphelper::OInterfaceIteratorHelper4 aListIter(rGuard, maTreeDataModelListeners);
160 rGuard.unlock();
161 while(aListIter.hasMoreElements())
162 {
163 XTreeDataModelListener* pListener = aListIter.next().get();
164 switch( eType )
165 {
166 case nodes_changed: pListener->treeNodesChanged(aEvent); break;
167 case nodes_inserted: pListener->treeNodesInserted(aEvent); break;
168 case nodes_removed: pListener->treeNodesRemoved(aEvent); break;
169 case structure_changed: pListener->treeStructureChanged(aEvent); break;
170 }
171 }
172}
173
174Reference< XMutableTreeNode > SAL_CALL MutableTreeDataModel::createNode( const Any& aValue, sal_Bool bChildrenOnDemand )
175{
176 return new MutableTreeNode( this, aValue, bChildrenOnDemand );
177}
178
179void SAL_CALL MutableTreeDataModel::setRoot( const Reference< XMutableTreeNode >& xNode )
180{
181 if( !xNode.is() )
182 throw IllegalArgumentException();
183
184 std::unique_lock aGuard( m_aMutex );
185 if( xNode == mxRootNode )
186 return;
187
188 if( mxRootNode.is() )
189 {
190 rtl::Reference< MutableTreeNode > xOldImpl( dynamic_cast< MutableTreeNode* >( mxRootNode.get() ) );
191 if( xOldImpl.is() )
192 xOldImpl->mbIsInserted = false;
193 }
194
195 rtl::Reference< MutableTreeNode > xImpl( dynamic_cast< MutableTreeNode* >( xNode.get() ) );
196 if( !xImpl.is() || xImpl->mbIsInserted )
197 throw IllegalArgumentException();
198
199 xImpl->mbIsInserted = true;
200 mxRootNode = xImpl;
201
202 Reference< XTreeNode > xParentNode;
203 broadcastImpl( aGuard, structure_changed, xParentNode, mxRootNode );
204}
205
206Reference< XTreeNode > SAL_CALL MutableTreeDataModel::getRoot( )
207{
208 std::unique_lock aGuard( m_aMutex );
209 return mxRootNode;
210}
211
212void SAL_CALL MutableTreeDataModel::addTreeDataModelListener( const Reference< XTreeDataModelListener >& xListener )
213{
214 std::unique_lock aGuard( m_aMutex );
215 maTreeDataModelListeners.addInterface( aGuard, xListener );
216}
217
218void SAL_CALL MutableTreeDataModel::removeTreeDataModelListener( const Reference< XTreeDataModelListener >& xListener )
219{
220 std::unique_lock aGuard( m_aMutex );
221 maTreeDataModelListeners.removeInterface( aGuard, xListener );
222}
223
224void SAL_CALL MutableTreeDataModel::dispose()
225{
226 std::unique_lock aGuard( m_aMutex );
227
228 if( !mbDisposed )
229 {
230 mbDisposed = true;
231 css::lang::EventObject aEvent;
232 aEvent.Source.set( static_cast< ::cppu::OWeakObject* >( this ) );
233 maTreeDataModelListeners.disposeAndClear( aGuard, aEvent );
234 maEventListeners.disposeAndClear( aGuard, aEvent );
235 }
236}
237
238void SAL_CALL MutableTreeDataModel::addEventListener( const Reference< XEventListener >& xListener )
239{
240 std::unique_lock aGuard( m_aMutex );
241 maEventListeners.addInterface( aGuard, xListener );
242}
243
244void SAL_CALL MutableTreeDataModel::removeEventListener( const Reference< XEventListener >& xListener )
245{
246 std::unique_lock aGuard( m_aMutex );
247 maEventListeners.removeInterface( aGuard, xListener );
248}
249
250OUString SAL_CALL MutableTreeDataModel::getImplementationName( )
251{
252 return "toolkit.MutableTreeDataModel";
253}
254
255sal_Bool SAL_CALL MutableTreeDataModel::supportsService( const OUString& ServiceName )
256{
257 return cppu::supportsService(this, ServiceName);
258}
259
260Sequence< OUString > SAL_CALL MutableTreeDataModel::getSupportedServiceNames( )
261{
262 Sequence<OUString> aSeq { "com.sun.star.awt.tree.MutableTreeDataModel" };
263 return aSeq;
264}
265
266MutableTreeNode::MutableTreeNode( rtl::Reference< MutableTreeDataModel > xModel, Any aValue, bool bChildrenOnDemand )
267: maDisplayValue(std::move( aValue ))
268, mbHasChildrenOnDemand( bChildrenOnDemand )
269, mpParent( nullptr )
270, mxModel(std::move( xModel ))
271, mbIsInserted( false )
272{
273}
274
275MutableTreeNode::~MutableTreeNode()
276{
277 for( auto& rChild : maChildren )
278 rChild->setParent(nullptr);
279}
280
281void MutableTreeNode::setParent( MutableTreeNode* pParent )
282{
283 mpParent = pParent;
284}
285
286void MutableTreeNode::broadcast_changes()
287{
288 if( mxModel.is() )
289 {
290 mxModel->broadcast( nodes_changed, mpParent, this );
291 }
292}
293
294void MutableTreeNode::broadcast_changes(std::unique_lock<std::mutex> & rLock,
295 const Reference< XTreeNode >& xNode, bool const bNew)
296{
297 auto const xModel(mxModel);
298 rLock.unlock();
299 if (xModel.is())
300 {
301 xModel->broadcast(bNew ? nodes_inserted : nodes_removed, this, xNode);
302 }
303}
304
305Any SAL_CALL MutableTreeNode::getDataValue()
306{
307 std::scoped_lock aGuard( maMutex );
308 return maDataValue;
309}
310
311void SAL_CALL MutableTreeNode::setDataValue( const Any& _datavalue )
312{
313 std::scoped_lock aGuard( maMutex );
314 maDataValue = _datavalue;
315}
316
317void SAL_CALL MutableTreeNode::appendChild( const Reference< XMutableTreeNode >& xChildNode )
318{
319 std::unique_lock aGuard( maMutex );
320 rtl::Reference< MutableTreeNode > xImpl( dynamic_cast< MutableTreeNode* >( xChildNode.get() ) );
321
322 if( !xImpl.is() || xImpl->mbIsInserted || (this == xImpl.get()) )
323 throw IllegalArgumentException();
324
325 maChildren.push_back( xImpl );
326 xImpl->setParent(this);
327 xImpl->mbIsInserted = true;
328
329 broadcast_changes(aGuard, xChildNode, true);
330}
331
332void SAL_CALL MutableTreeNode::insertChildByIndex( sal_Int32 nChildIndex, const Reference< XMutableTreeNode >& xChildNode )
333{
334 std::unique_lock aGuard( maMutex );
335
336 if( (nChildIndex < 0) || (o3tl::make_unsigned(nChildIndex) > maChildren.size()) )
337 throw IndexOutOfBoundsException();
338
339 rtl::Reference< MutableTreeNode > xImpl( dynamic_cast< MutableTreeNode* >( xChildNode.get() ) );
340 if( !xImpl.is() || xImpl->mbIsInserted || (this == xImpl.get()) )
341 throw IllegalArgumentException();
342
343 xImpl->mbIsInserted = true;
344
345 TreeNodeVector::iterator aIter( maChildren.begin() );
346 std::advance(aIter, nChildIndex);
347
348 maChildren.insert( aIter, xImpl );
349 xImpl->setParent( this );
350
351 broadcast_changes(aGuard, xChildNode, true);
352}
353
354void SAL_CALL MutableTreeNode::removeChildByIndex( sal_Int32 nChildIndex )
355{
356 std::unique_lock aGuard( maMutex );
357
358 if( (nChildIndex < 0) || (o3tl::make_unsigned(nChildIndex) >= maChildren.size()) )
359 throw IndexOutOfBoundsException();
360
362
363 TreeNodeVector::iterator aIter( maChildren.begin() );
364 std::advance(aIter, nChildIndex);
365
366 xImpl = *aIter;
367 maChildren.erase( aIter );
368
369 if( !xImpl.is() )
370 throw IndexOutOfBoundsException();
371
372 xImpl->setParent(nullptr);
373 xImpl->mbIsInserted = false;
374
375 broadcast_changes(aGuard, xImpl, false);
376}
377
378void SAL_CALL MutableTreeNode::setHasChildrenOnDemand( sal_Bool bChildrenOnDemand )
379{
380 bool bChanged;
381
382 {
383 std::scoped_lock aGuard( maMutex );
384 bChanged = mbHasChildrenOnDemand != bool(bChildrenOnDemand);
385 mbHasChildrenOnDemand = bChildrenOnDemand;
386 }
387
388 if( bChanged )
389 broadcast_changes();
390}
391
392void SAL_CALL MutableTreeNode::setDisplayValue( const Any& aValue )
393{
394 {
395 std::scoped_lock aGuard( maMutex );
396 maDisplayValue = aValue;
397 }
398
399 broadcast_changes();
400}
401
402void SAL_CALL MutableTreeNode::setNodeGraphicURL( const OUString& rURL )
403{
404 bool bChanged;
405
406 {
407 std::scoped_lock aGuard( maMutex );
408 bChanged = maNodeGraphicURL != rURL;
409 maNodeGraphicURL = rURL;
410 }
411
412 if( bChanged )
413 broadcast_changes();
414}
415
416void SAL_CALL MutableTreeNode::setExpandedGraphicURL( const OUString& rURL )
417{
418 bool bChanged;
419
420 {
421 std::scoped_lock aGuard( maMutex );
422 bChanged = maExpandedGraphicURL != rURL;
423 maExpandedGraphicURL = rURL;
424 }
425
426 if( bChanged )
427 broadcast_changes();
428}
429
430void SAL_CALL MutableTreeNode::setCollapsedGraphicURL( const OUString& rURL )
431{
432 bool bChanged;
433
434 {
435 std::scoped_lock aGuard( maMutex );
436 bChanged = maCollapsedGraphicURL != rURL;
437 maCollapsedGraphicURL = rURL;
438 }
439
440 if( bChanged )
441 broadcast_changes();
442}
443
444Reference< XTreeNode > SAL_CALL MutableTreeNode::getChildAt( sal_Int32 nChildIndex )
445{
446 std::scoped_lock aGuard( maMutex );
447
448 if( (nChildIndex < 0) || (o3tl::make_unsigned(nChildIndex) >= maChildren.size()) )
449 throw IndexOutOfBoundsException();
450 return maChildren[nChildIndex];
451}
452
453sal_Int32 SAL_CALL MutableTreeNode::getChildCount( )
454{
455 std::scoped_lock aGuard( maMutex );
456 return static_cast<sal_Int32>(maChildren.size());
457}
458
459Reference< XTreeNode > SAL_CALL MutableTreeNode::getParent( )
460{
461 std::scoped_lock aGuard( maMutex );
462 return mpParent;
463}
464
465sal_Int32 SAL_CALL MutableTreeNode::getIndex( const Reference< XTreeNode >& xNode )
466{
467 std::scoped_lock aGuard( maMutex );
468
469 rtl::Reference< MutableTreeNode > xImpl( dynamic_cast< MutableTreeNode* >( xNode.get() ) );
470 if( xImpl.is() )
471 {
472 sal_Int32 nChildCount = maChildren.size();
473 while( nChildCount-- )
474 {
475 if( maChildren[nChildCount] == xImpl )
476 return nChildCount;
477 }
478 }
479
480 return -1;
481}
482
483sal_Bool SAL_CALL MutableTreeNode::hasChildrenOnDemand( )
484{
485 std::scoped_lock aGuard( maMutex );
486 return mbHasChildrenOnDemand;
487}
488
489Any SAL_CALL MutableTreeNode::getDisplayValue( )
490{
491 std::scoped_lock aGuard( maMutex );
492 return maDisplayValue;
493}
494
495OUString SAL_CALL MutableTreeNode::getNodeGraphicURL( )
496{
497 std::scoped_lock aGuard( maMutex );
498 return maNodeGraphicURL;
499}
500
501OUString SAL_CALL MutableTreeNode::getExpandedGraphicURL( )
502{
503 std::scoped_lock aGuard( maMutex );
504 return maExpandedGraphicURL;
505}
506
507OUString SAL_CALL MutableTreeNode::getCollapsedGraphicURL( )
508{
509 std::scoped_lock aGuard( maMutex );
510 return maCollapsedGraphicURL;
511}
512
513OUString SAL_CALL MutableTreeNode::getImplementationName( )
514{
515 return "toolkit.MutableTreeNode";
516}
517
518sal_Bool SAL_CALL MutableTreeNode::supportsService( const OUString& ServiceName )
519{
520 return cppu::supportsService(this, ServiceName);
521}
522
523Sequence< OUString > SAL_CALL MutableTreeNode::getSupportedServiceNames( )
524{
525 Sequence<OUString> aSeq { "com.sun.star.awt.tree.MutableTreeNode" };
526 return aSeq;
527}
528
529}
530
531extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
533 css::uno::XComponentContext *,
534 css::uno::Sequence<css::uno::Any> const &)
535{
536 return cppu::acquire(new MutableTreeDataModel());
537}
538
539/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
struct _ADOIndex Index
css::uno::Reference< css::frame::XModel2 > mxModel
std::mutex maMutex
std::vector< Reference< XAnimationNode > > maChildren
AnyEventRef aEvent
RegionData_Impl * mpParent
std::mutex m_aMutex
Sequence< sal_Int8 > aSeq
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
void dispose()
uno::Reference< animations::XAnimationNode > mxRootNode
Reference< XModel > xModel
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * stardiv_Toolkit_MutableTreeDataModel_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
unsigned char sal_Bool