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 <memory>
22 #include <com/sun/star/graphic/GraphicProvider.hpp>
23 #include <com/sun/star/lang/DisposedException.hpp>
24 #include <com/sun/star/view/SelectionType.hpp>
25 #include <com/sun/star/util/VetoException.hpp>
26 #include <o3tl/any.hxx>
27 #include <toolkit/helper/property.hxx>
28 #include <toolkit/helper/vclunohelper.hxx>
29 
30 #include <com/sun/star/awt/tree/XMutableTreeNode.hpp>
31 #include "treecontrolpeer.hxx"
32 #include <comphelper/processfactory.hxx>
33 
34 #include <cppuhelper/implbase.hxx>
35 #include <rtl/ref.hxx>
36 #include <vcl/graph.hxx>
37 #include <vcl/svapp.hxx>
38 #include <vcl/treelistbox.hxx>
39 #include <vcl/treelistentry.hxx>
40 #include <vcl/viewdataentry.hxx>
41 #include <vcl/svlbitm.hxx>
42 
43 #include <map>
44 
45 using namespace ::com::sun::star;
46 using namespace css::uno;
47 using namespace css::lang;
48 using namespace css::awt::tree;
49 using namespace css::beans;
50 using namespace css::view;
51 using namespace css::container;
52 using namespace css::util;
53 using namespace css::graphic;
54 
55 struct LockGuard
56 {
57 public:
LockGuardLockGuard58     explicit LockGuard( sal_Int32& rLock )
59     : mrLock( rLock )
60     {
61         rLock++;
62     }
63 
~LockGuardLockGuard64     ~LockGuard()
65     {
66         mrLock--;
67     }
68 
69     sal_Int32& mrLock;
70 };
71 
72 
73 class ImplContextGraphicItem : public SvLBoxContextBmp
74 {
75 public:
ImplContextGraphicItem(Image const & rI1,Image const & rI2,bool bExpanded)76     ImplContextGraphicItem( Image const & rI1, Image const & rI2, bool bExpanded)
77         : SvLBoxContextBmp(rI1, rI2, bExpanded) {}
78 
79     OUString msExpandedGraphicURL;
80     OUString msCollapsedGraphicURL;
81 };
82 
83 
84 class UnoTreeListBoxImpl : public SvTreeListBox
85 {
86 public:
87     UnoTreeListBoxImpl( TreeControlPeer* pPeer, vcl::Window* pParent, WinBits nWinStyle );
88     virtual ~UnoTreeListBoxImpl() override;
89     virtual void dispose() override;
90 
91     void            insert( SvTreeListEntry* pEntry, SvTreeListEntry* pParent, sal_uLong nPos );
92 
93     virtual void    RequestingChildren( SvTreeListEntry* pParent ) override;
94 
95     virtual bool    EditingEntry( SvTreeListEntry* pEntry, Selection& ) override;
96     virtual bool    EditedEntry( SvTreeListEntry* pEntry, const OUString& rNewText ) override;
97 
98     DECL_LINK(OnSelectionChangeHdl, SvTreeListBox*, void);
99     DECL_LINK(OnExpandingHdl, SvTreeListBox*, bool);
100     DECL_LINK(OnExpandedHdl, SvTreeListBox*, void);
101 
102 private:
103     rtl::Reference< TreeControlPeer > mxPeer;
104 };
105 
106 
107 class UnoTreeListItem : public SvLBoxString
108 {
109 public:
110                     UnoTreeListItem();
111 
112     void            InitViewData( SvTreeListBox*,SvTreeListEntry*,SvViewDataItem * = nullptr ) override;
113     void            SetImage( const Image& rImage );
GetGraphicURL() const114     const OUString& GetGraphicURL() const { return maGraphicURL;}
115     void            SetGraphicURL( const OUString& rGraphicURL );
116     virtual void    Paint(const Point& rPos, SvTreeListBox& rOutDev, vcl::RenderContext& rRenderContext,
117                           const SvViewDataEntry* pView, const SvTreeListEntry& rEntry) override;
118     std::unique_ptr<SvLBoxItem> Clone( SvLBoxItem const * pSource ) const override;
119 
120 private:
121     OUString        maGraphicURL;
122     Image           maImage;
123 };
124 
125 
126 class UnoTreeListEntry : public SvTreeListEntry
127 {
128 public:
129     UnoTreeListEntry( const Reference< XTreeNode >& xNode, TreeControlPeer* pPeer );
130     virtual ~UnoTreeListEntry() override;
131 
132     Reference< XTreeNode > mxNode;
133     TreeControlPeer* mpPeer;
134 };
135 
TreeControlPeer()136 TreeControlPeer::TreeControlPeer()
137     : maSelectionListeners( *this )
138     , maTreeExpansionListeners( *this )
139     , maTreeEditListeners( *this )
140     , mbIsRootDisplayed(false)
141     , mpTreeImpl( nullptr )
142     , mnEditLock( 0 )
143 {
144 }
145 
146 
~TreeControlPeer()147 TreeControlPeer::~TreeControlPeer()
148 {
149     if( mpTreeImpl )
150         mpTreeImpl->Clear();
151 }
152 
153 
addEntry(UnoTreeListEntry * pEntry)154 void TreeControlPeer::addEntry( UnoTreeListEntry* pEntry )
155 {
156     if( pEntry && pEntry->mxNode.is() )
157     {
158         if( !mpTreeNodeMap )
159         {
160             mpTreeNodeMap.reset( new TreeNodeMap );
161         }
162 
163         (*mpTreeNodeMap)[ pEntry->mxNode ] = pEntry;
164     }
165 }
166 
167 
removeEntry(UnoTreeListEntry const * pEntry)168 void TreeControlPeer::removeEntry( UnoTreeListEntry const * pEntry )
169 {
170     if( mpTreeNodeMap && pEntry && pEntry->mxNode.is() )
171     {
172         TreeNodeMap::iterator aIter( mpTreeNodeMap->find( pEntry->mxNode ) );
173         if( aIter != mpTreeNodeMap->end() )
174         {
175             mpTreeNodeMap->erase( aIter );
176         }
177     }
178 }
179 
180 
getEntry(const Reference<XTreeNode> & xNode,bool bThrow)181 UnoTreeListEntry* TreeControlPeer::getEntry( const Reference< XTreeNode >& xNode, bool bThrow /* = true */ )
182 {
183     if( mpTreeNodeMap )
184     {
185         TreeNodeMap::iterator aIter( mpTreeNodeMap->find( xNode ) );
186         if( aIter != mpTreeNodeMap->end() )
187             return (*aIter).second;
188     }
189 
190     if( bThrow )
191         throw IllegalArgumentException();
192 
193     return nullptr;
194 }
195 
196 
createVclControl(vcl::Window * pParent,sal_Int64 nWinStyle)197 vcl::Window* TreeControlPeer::createVclControl( vcl::Window* pParent, sal_Int64 nWinStyle )
198 {
199     mpTreeImpl = VclPtr<UnoTreeListBoxImpl>::Create( this, pParent, nWinStyle );
200     return mpTreeImpl;
201 }
202 
203 
204 /** called from the UnoTreeListBoxImpl when it gets deleted */
disposeControl()205 void TreeControlPeer::disposeControl()
206 {
207     mpTreeNodeMap.reset();
208     mpTreeImpl = nullptr;
209 }
210 
211 
createEntry(const Reference<XTreeNode> & xNode,UnoTreeListEntry * pParent,sal_uLong nPos)212 UnoTreeListEntry* TreeControlPeer::createEntry( const Reference< XTreeNode >& xNode, UnoTreeListEntry* pParent, sal_uLong nPos /* = TREELIST_APPEND */ )
213 {
214     UnoTreeListEntry* pEntry = nullptr;
215     if( mpTreeImpl )
216     {
217         Image aImage;
218         pEntry = new UnoTreeListEntry( xNode, this );
219         pEntry->AddItem(std::make_unique<ImplContextGraphicItem>(aImage, aImage, true));
220 
221         std::unique_ptr<UnoTreeListItem> pUnoItem(new UnoTreeListItem);
222 
223         if( !xNode->getNodeGraphicURL().isEmpty() )
224         {
225             pUnoItem->SetGraphicURL( xNode->getNodeGraphicURL() );
226             Image aNodeImage;
227             loadImage( xNode->getNodeGraphicURL(), aNodeImage );
228             pUnoItem->SetImage( aNodeImage );
229             mpTreeImpl->AdjustEntryHeight( aNodeImage );
230         }
231 
232         pEntry->AddItem(std::move(pUnoItem));
233 
234         mpTreeImpl->insert( pEntry, pParent, nPos );
235 
236         if( !msDefaultExpandedGraphicURL.isEmpty() )
237             mpTreeImpl->SetExpandedEntryBmp( pEntry, maDefaultExpandedImage );
238 
239         if( !msDefaultCollapsedGraphicURL.isEmpty() )
240             mpTreeImpl->SetCollapsedEntryBmp( pEntry, maDefaultCollapsedImage );
241 
242         updateEntry( pEntry );
243     }
244     return pEntry;
245 }
246 
247 
updateEntry(UnoTreeListEntry * pEntry)248 void TreeControlPeer::updateEntry( UnoTreeListEntry* pEntry )
249 {
250     bool bChanged = false;
251     if( !(pEntry && pEntry->mxNode.is() && mpTreeImpl) )
252         return;
253 
254     const OUString aValue( getEntryString( pEntry->mxNode->getDisplayValue() ) );
255     UnoTreeListItem* pUnoItem = dynamic_cast< UnoTreeListItem* >( &pEntry->GetItem( 1 ) );
256     if( pUnoItem )
257     {
258         if( aValue != pUnoItem->GetText() )
259         {
260             pUnoItem->SetText( aValue );
261             bChanged = true;
262         }
263 
264         if( pUnoItem->GetGraphicURL() != pEntry->mxNode->getNodeGraphicURL() )
265         {
266             Image aImage;
267             if( loadImage( pEntry->mxNode->getNodeGraphicURL(), aImage ) )
268             {
269                 pUnoItem->SetGraphicURL( pEntry->mxNode->getNodeGraphicURL() );
270                 pUnoItem->SetImage( aImage );
271                 mpTreeImpl->AdjustEntryHeight( aImage );
272                 bChanged = true;
273             }
274         }
275     }
276 
277     if( bool(pEntry->mxNode->hasChildrenOnDemand()) != pEntry->HasChildrenOnDemand() )
278     {
279         pEntry->EnableChildrenOnDemand( pEntry->mxNode->hasChildrenOnDemand() );
280         bChanged = true;
281     }
282 
283     ImplContextGraphicItem* pContextGraphicItem = dynamic_cast< ImplContextGraphicItem* >( &pEntry->GetItem( 0 ) );
284     if( pContextGraphicItem )
285     {
286         if( pContextGraphicItem->msExpandedGraphicURL != pEntry->mxNode->getExpandedGraphicURL() )
287         {
288             Image aImage;
289             if( loadImage( pEntry->mxNode->getExpandedGraphicURL(), aImage ) )
290             {
291                 pContextGraphicItem->msExpandedGraphicURL = pEntry->mxNode->getExpandedGraphicURL();
292                 mpTreeImpl->SetExpandedEntryBmp( pEntry, aImage );
293                 bChanged = true;
294             }
295         }
296         if( pContextGraphicItem->msCollapsedGraphicURL != pEntry->mxNode->getCollapsedGraphicURL() )
297         {
298             Image aImage;
299             if( loadImage( pEntry->mxNode->getCollapsedGraphicURL(), aImage ) )
300             {
301                 pContextGraphicItem->msCollapsedGraphicURL = pEntry->mxNode->getCollapsedGraphicURL();
302                 mpTreeImpl->SetCollapsedEntryBmp( pEntry, aImage );
303                 bChanged = true;
304             }
305         }
306     }
307 
308     if( bChanged )
309         mpTreeImpl->GetModel()->InvalidateEntry( pEntry );
310 }
311 
312 
onSelectionChanged()313 void TreeControlPeer::onSelectionChanged()
314 {
315     Reference< XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) );
316     EventObject aEvent( xSource );
317     maSelectionListeners.selectionChanged( aEvent );
318 }
319 
320 
onRequestChildNodes(const Reference<XTreeNode> & xNode)321 void TreeControlPeer::onRequestChildNodes( const Reference< XTreeNode >& xNode )
322 {
323     try
324     {
325         Reference< XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) );
326         TreeExpansionEvent aEvent( xSource, xNode );
327         maTreeExpansionListeners.requestChildNodes( aEvent );
328     }
329     catch( Exception& )
330     {
331     }
332 }
333 
334 
onExpanding(const Reference<XTreeNode> & xNode,bool bExpanding)335 bool TreeControlPeer::onExpanding( const Reference< XTreeNode >& xNode, bool bExpanding )
336 {
337     try
338     {
339         Reference< XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) );
340         TreeExpansionEvent aEvent( xSource, xNode );
341         if( bExpanding )
342         {
343             maTreeExpansionListeners.treeExpanding( aEvent );
344         }
345         else
346         {
347             maTreeExpansionListeners.treeCollapsing( aEvent );
348         }
349     }
350     catch( Exception& )
351     {
352         return false;
353     }
354     return true;
355 }
356 
357 
onExpanded(const Reference<XTreeNode> & xNode,bool bExpanding)358 void TreeControlPeer::onExpanded( const Reference< XTreeNode >& xNode, bool bExpanding )
359 {
360     try
361     {
362         Reference< XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) );
363         TreeExpansionEvent aEvent( xSource, xNode );
364 
365         if( bExpanding )
366         {
367             maTreeExpansionListeners.treeExpanded( aEvent );
368         }
369         else
370         {
371             maTreeExpansionListeners.treeCollapsed( aEvent );
372         }
373     }
374     catch( Exception& )
375     {
376     }
377 }
378 
379 
fillTree(UnoTreeListBoxImpl & rTree,const Reference<XTreeDataModel> & xDataModel)380 void TreeControlPeer::fillTree( UnoTreeListBoxImpl& rTree, const Reference< XTreeDataModel >& xDataModel )
381 {
382     rTree.Clear();
383 
384     if( !xDataModel.is() )
385         return;
386 
387     Reference< XTreeNode > xRootNode( xDataModel->getRoot() );
388     if( !xRootNode.is() )
389         return;
390 
391     if( mbIsRootDisplayed )
392     {
393         addNode( rTree, xRootNode, nullptr );
394     }
395     else
396     {
397         const sal_Int32 nChildCount = xRootNode->getChildCount();
398         for( sal_Int32 nChild = 0; nChild < nChildCount; nChild++ )
399             addNode( rTree, xRootNode->getChildAt( nChild ), nullptr );
400     }
401 }
402 
403 
addNode(UnoTreeListBoxImpl & rTree,const Reference<XTreeNode> & xNode,UnoTreeListEntry * pParentEntry)404 void TreeControlPeer::addNode( UnoTreeListBoxImpl& rTree, const Reference< XTreeNode >& xNode, UnoTreeListEntry* pParentEntry )
405 {
406     if( xNode.is() )
407     {
408         UnoTreeListEntry* pEntry = createEntry( xNode, pParentEntry, TREELIST_APPEND );
409         const sal_Int32 nChildCount = xNode->getChildCount();
410         for( sal_Int32 nChild = 0; nChild < nChildCount; nChild++ )
411             addNode( rTree, xNode->getChildAt( nChild ), pEntry );
412     }
413 }
414 
415 
getTreeListBoxOrThrow() const416 UnoTreeListBoxImpl& TreeControlPeer::getTreeListBoxOrThrow() const
417 {
418     if( !mpTreeImpl )
419         throw DisposedException();
420     return *mpTreeImpl;
421 }
422 
423 
ChangeNodesSelection(const Any & rSelection,bool bSelect,bool bSetSelection)424 void TreeControlPeer::ChangeNodesSelection( const Any& rSelection, bool bSelect, bool bSetSelection )
425 {
426     SolarMutexGuard aGuard;
427 
428     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
429 
430     Reference< XTreeNode > xTempNode;
431 
432     Sequence<Reference<XTreeNode>> pNodes;
433     sal_Int32 nCount = 0;
434 
435     if( rSelection.hasValue() )
436     {
437         switch( rSelection.getValueTypeClass() )
438         {
439         case TypeClass_INTERFACE:
440             {
441                 rSelection >>= xTempNode;
442                 if( xTempNode.is() )
443                 {
444                     nCount = 1;
445                     pNodes = {xTempNode};
446                 }
447                 break;
448             }
449         case TypeClass_SEQUENCE:
450             {
451                 if( auto rSeq = o3tl::tryAccess<Sequence<Reference<XTreeNode>>>(
452                         rSelection) )
453                 {
454                     nCount = rSeq->getLength();
455                     pNodes = *rSeq;
456                 }
457                 break;
458             }
459         default:
460             break;
461         }
462 
463         if( nCount == 0 )
464             throw IllegalArgumentException();
465     }
466 
467     if( bSetSelection )
468         rTree.SelectAll( false );
469 
470     for( sal_Int32 i = 0; i != nCount; ++i )
471     {
472         UnoTreeListEntry* pEntry = getEntry( pNodes[i] );
473         rTree.Select( pEntry, bSelect );
474     }
475 }
476 
477 
478 // css::view::XSelectionSupplier
479 
480 
select(const Any & rSelection)481 sal_Bool SAL_CALL TreeControlPeer::select( const Any& rSelection )
482 {
483     SolarMutexGuard aGuard;
484     ChangeNodesSelection( rSelection, true, true );
485     return true;
486 }
487 
488 
getSelection()489 Any SAL_CALL TreeControlPeer::getSelection()
490 {
491     SolarMutexGuard aGuard;
492 
493     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
494 
495     Any aRet;
496 
497     sal_uLong nSelectionCount = rTree.GetSelectionCount();
498     if( nSelectionCount == 1 )
499     {
500         UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.FirstSelected() );
501         if( pEntry && pEntry->mxNode.is() )
502             aRet <<= pEntry->mxNode;
503     }
504     else if( nSelectionCount > 1 )
505     {
506         Sequence< Reference< XTreeNode > > aSelection( nSelectionCount );
507         Reference< XTreeNode >* pNodes = aSelection.getArray();
508         UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.FirstSelected() );
509         while( pEntry && nSelectionCount )
510         {
511             *pNodes++ = pEntry->mxNode;
512             pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.NextSelected( pEntry ) );
513             --nSelectionCount;
514         }
515 
516         OSL_ASSERT( (pEntry == nullptr) && (nSelectionCount == 0) );
517         aRet <<= aSelection;
518     }
519 
520     return aRet;
521 }
522 
523 
addSelectionChangeListener(const Reference<XSelectionChangeListener> & xListener)524 void SAL_CALL TreeControlPeer::addSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener )
525 {
526     maSelectionListeners.addInterface( xListener );
527 }
528 
529 
removeSelectionChangeListener(const Reference<XSelectionChangeListener> & xListener)530 void SAL_CALL TreeControlPeer::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener )
531 {
532     maSelectionListeners.addInterface( xListener );
533 }
534 
535 
536 // css::view::XMultiSelectionSupplier
537 
538 
addSelection(const Any & rSelection)539 sal_Bool SAL_CALL TreeControlPeer::addSelection( const Any& rSelection )
540 {
541     ChangeNodesSelection( rSelection, true, false );
542     return true;
543 }
544 
545 
removeSelection(const Any & rSelection)546 void SAL_CALL TreeControlPeer::removeSelection( const Any& rSelection )
547 {
548     ChangeNodesSelection( rSelection, false, false );
549 }
550 
551 
clearSelection()552 void SAL_CALL TreeControlPeer::clearSelection()
553 {
554     SolarMutexGuard aGuard;
555     getTreeListBoxOrThrow().SelectAll( false );
556 }
557 
558 
getSelectionCount()559 sal_Int32 SAL_CALL TreeControlPeer::getSelectionCount()
560 {
561     SolarMutexGuard aGuard;
562     return getTreeListBoxOrThrow().GetSelectionCount();
563 }
564 
565 
566 class TreeSelectionEnumeration : public ::cppu::WeakImplHelper< XEnumeration >
567 {
568 public:
569     explicit TreeSelectionEnumeration( std::list< Any >& rSelection );
570     virtual sal_Bool SAL_CALL hasMoreElements() override;
571     virtual Any SAL_CALL nextElement() override;
572 
573     std::list< Any > maSelection;
574     std::list< Any >::iterator maIter;
575 };
576 
577 
TreeSelectionEnumeration(std::list<Any> & rSelection)578 TreeSelectionEnumeration::TreeSelectionEnumeration( std::list< Any >& rSelection )
579 {
580     maSelection.swap( rSelection );
581     maIter = maSelection.begin();
582 }
583 
584 
hasMoreElements()585 sal_Bool SAL_CALL TreeSelectionEnumeration::hasMoreElements()
586 {
587     return maIter != maSelection.end();
588 }
589 
590 
nextElement()591 Any SAL_CALL TreeSelectionEnumeration::nextElement()
592 {
593     if( maIter == maSelection.end() )
594         throw NoSuchElementException();
595 
596     return (*maIter++);
597 }
598 
599 
createSelectionEnumeration()600 Reference< XEnumeration > SAL_CALL TreeControlPeer::createSelectionEnumeration()
601 {
602     SolarMutexGuard aGuard;
603 
604     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
605 
606     sal_uInt32 nSelectionCount = rTree.GetSelectionCount();
607     std::list< Any > aSelection( nSelectionCount );
608 
609     UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.FirstSelected() );
610     while( pEntry && nSelectionCount )
611     {
612         aSelection.emplace_back( pEntry->mxNode );
613         pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.NextSelected( pEntry ) );
614         --nSelectionCount;
615     }
616 
617     OSL_ASSERT( (pEntry == nullptr) && (nSelectionCount == 0) );
618 
619     return Reference< XEnumeration >( new TreeSelectionEnumeration( aSelection ) );
620 }
621 
622 
createReverseSelectionEnumeration()623 Reference< XEnumeration > SAL_CALL TreeControlPeer::createReverseSelectionEnumeration()
624 {
625     SolarMutexGuard aGuard;
626 
627     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
628 
629     sal_uInt32 nSelectionCount = rTree.GetSelectionCount();
630     std::list< Any > aSelection;
631 
632     UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.FirstSelected() );
633     while( pEntry && nSelectionCount )
634     {
635         aSelection.push_front( Any( pEntry->mxNode ) );
636         pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.NextSelected( pEntry ) );
637         --nSelectionCount;
638     }
639 
640     OSL_ASSERT( (pEntry == nullptr) && (nSelectionCount == 0) );
641 
642     return Reference< XEnumeration >( new TreeSelectionEnumeration( aSelection ) );
643 }
644 
645 
646 // css::awt::XTreeControl
647 
648 
getDefaultExpandedGraphicURL()649 OUString SAL_CALL TreeControlPeer::getDefaultExpandedGraphicURL()
650 {
651     SolarMutexGuard aGuard;
652     return msDefaultExpandedGraphicURL;
653 }
654 
655 
setDefaultExpandedGraphicURL(const OUString & sDefaultExpandedGraphicURL)656 void SAL_CALL TreeControlPeer::setDefaultExpandedGraphicURL( const OUString& sDefaultExpandedGraphicURL )
657 {
658     SolarMutexGuard aGuard;
659     if( msDefaultExpandedGraphicURL == sDefaultExpandedGraphicURL )
660         return;
661 
662     if( !sDefaultExpandedGraphicURL.isEmpty() )
663         loadImage( sDefaultExpandedGraphicURL, maDefaultExpandedImage );
664     else
665         maDefaultExpandedImage = Image();
666 
667     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
668 
669     SvTreeListEntry* pEntry = rTree.First();
670     while( pEntry )
671     {
672         ImplContextGraphicItem* pContextGraphicItem = dynamic_cast< ImplContextGraphicItem* >( &pEntry->GetItem( 0 ) );
673         if( pContextGraphicItem )
674         {
675             if( pContextGraphicItem->msExpandedGraphicURL.isEmpty() )
676                 rTree.SetExpandedEntryBmp( pEntry, maDefaultExpandedImage );
677         }
678         pEntry = rTree.Next( pEntry );
679     }
680 
681     msDefaultExpandedGraphicURL = sDefaultExpandedGraphicURL;
682 }
683 
684 
getDefaultCollapsedGraphicURL()685 OUString SAL_CALL TreeControlPeer::getDefaultCollapsedGraphicURL()
686 {
687     SolarMutexGuard aGuard;
688     return msDefaultCollapsedGraphicURL;
689 }
690 
691 
setDefaultCollapsedGraphicURL(const OUString & sDefaultCollapsedGraphicURL)692 void SAL_CALL TreeControlPeer::setDefaultCollapsedGraphicURL( const OUString& sDefaultCollapsedGraphicURL )
693 {
694     SolarMutexGuard aGuard;
695     if( msDefaultCollapsedGraphicURL == sDefaultCollapsedGraphicURL )
696         return;
697 
698     if( !sDefaultCollapsedGraphicURL.isEmpty() )
699         loadImage( sDefaultCollapsedGraphicURL, maDefaultCollapsedImage );
700     else
701         maDefaultCollapsedImage = Image();
702 
703     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
704 
705     SvTreeListEntry* pEntry = rTree.First();
706     while( pEntry )
707     {
708         ImplContextGraphicItem* pContextGraphicItem = dynamic_cast< ImplContextGraphicItem* >( &pEntry->GetItem( 0 ) );
709         if( pContextGraphicItem )
710         {
711             if( pContextGraphicItem->msCollapsedGraphicURL.isEmpty() )
712                 rTree.SetCollapsedEntryBmp( pEntry, maDefaultCollapsedImage );
713         }
714         pEntry = rTree.Next( pEntry );
715     }
716 
717     msDefaultCollapsedGraphicURL = sDefaultCollapsedGraphicURL;
718 }
719 
720 
isNodeExpanded(const Reference<XTreeNode> & xNode)721 sal_Bool SAL_CALL TreeControlPeer::isNodeExpanded( const Reference< XTreeNode >& xNode )
722 {
723     SolarMutexGuard aGuard;
724 
725     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
726     UnoTreeListEntry* pEntry = getEntry( xNode );
727     return pEntry && rTree.IsExpanded( pEntry );
728 }
729 
730 
isNodeCollapsed(const Reference<XTreeNode> & xNode)731 sal_Bool SAL_CALL TreeControlPeer::isNodeCollapsed( const Reference< XTreeNode >& xNode )
732 {
733     SolarMutexGuard aGuard;
734     return !isNodeExpanded( xNode );
735 }
736 
737 
makeNodeVisible(const Reference<XTreeNode> & xNode)738 void SAL_CALL TreeControlPeer::makeNodeVisible( const Reference< XTreeNode >& xNode )
739 {
740     SolarMutexGuard aGuard;
741 
742     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
743     UnoTreeListEntry* pEntry = getEntry( xNode );
744     if( pEntry )
745         rTree.MakeVisible( pEntry );
746 }
747 
748 
isNodeVisible(const Reference<XTreeNode> & xNode)749 sal_Bool SAL_CALL TreeControlPeer::isNodeVisible( const Reference< XTreeNode >& xNode )
750 {
751     SolarMutexGuard aGuard;
752 
753     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
754     UnoTreeListEntry* pEntry = getEntry( xNode );
755     return pEntry && rTree.IsEntryVisible( pEntry );
756 }
757 
758 
expandNode(const Reference<XTreeNode> & xNode)759 void SAL_CALL TreeControlPeer::expandNode( const Reference< XTreeNode >& xNode )
760 {
761     SolarMutexGuard aGuard;
762 
763     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
764     UnoTreeListEntry* pEntry = getEntry( xNode );
765     if( pEntry )
766         rTree.Expand( pEntry );
767 }
768 
769 
collapseNode(const Reference<XTreeNode> & xNode)770 void SAL_CALL TreeControlPeer::collapseNode( const Reference< XTreeNode >& xNode )
771 {
772     SolarMutexGuard aGuard;
773 
774     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
775     UnoTreeListEntry* pEntry = getEntry( xNode );
776     if( pEntry )
777         rTree.Collapse( pEntry );
778 }
779 
780 
addTreeExpansionListener(const Reference<XTreeExpansionListener> & xListener)781 void SAL_CALL TreeControlPeer::addTreeExpansionListener( const Reference< XTreeExpansionListener >& xListener )
782 {
783     maTreeExpansionListeners.addInterface( xListener );
784 }
785 
786 
removeTreeExpansionListener(const Reference<XTreeExpansionListener> & xListener)787 void SAL_CALL TreeControlPeer::removeTreeExpansionListener( const Reference< XTreeExpansionListener >& xListener )
788 {
789     maTreeExpansionListeners.removeInterface( xListener );
790 }
791 
792 
getNodeForLocation(sal_Int32 x,sal_Int32 y)793 Reference< XTreeNode > SAL_CALL TreeControlPeer::getNodeForLocation( sal_Int32 x, sal_Int32 y )
794 {
795     SolarMutexGuard aGuard;
796 
797     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
798 
799     Reference< XTreeNode > xNode;
800 
801     const Point aPos( x, y );
802     UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.GetEntry( aPos, true ) );
803     if( pEntry )
804         xNode = pEntry->mxNode;
805 
806     return xNode;
807 }
808 
809 
getClosestNodeForLocation(sal_Int32 x,sal_Int32 y)810 Reference< XTreeNode > SAL_CALL TreeControlPeer::getClosestNodeForLocation( sal_Int32 x, sal_Int32 y )
811 {
812     SolarMutexGuard aGuard;
813 
814     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
815 
816     Reference< XTreeNode > xNode;
817 
818     const Point aPos( x, y );
819     UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.GetEntry( aPos, true ) );
820     if( pEntry )
821         xNode = pEntry->mxNode;
822 
823     return xNode;
824 }
825 
826 
getNodeRect(const Reference<XTreeNode> & i_Node)827 awt::Rectangle SAL_CALL TreeControlPeer::getNodeRect( const Reference< XTreeNode >& i_Node )
828 {
829     SolarMutexGuard aGuard;
830 
831     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
832     UnoTreeListEntry* pEntry = getEntry( i_Node );
833 
834     ::tools::Rectangle aEntryRect( rTree.GetFocusRect( pEntry, rTree.GetEntryPosition( pEntry ).Y() ) );
835     return VCLUnoHelper::ConvertToAWTRect( aEntryRect );
836 }
837 
838 
isEditing()839 sal_Bool SAL_CALL TreeControlPeer::isEditing(  )
840 {
841     SolarMutexGuard aGuard;
842 
843     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
844     return rTree.IsEditingActive();
845 }
846 
847 
stopEditing()848 sal_Bool SAL_CALL TreeControlPeer::stopEditing()
849 {
850     SolarMutexGuard aGuard;
851 
852     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
853     if( rTree.IsEditingActive() )
854     {
855         rTree.EndEditing();
856         return true;
857     }
858     else
859     {
860         return false;
861     }
862 }
863 
864 
cancelEditing()865 void SAL_CALL TreeControlPeer::cancelEditing(  )
866 {
867     SolarMutexGuard aGuard;
868 
869     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
870     rTree.EndEditing();
871 }
872 
873 
startEditingAtNode(const Reference<XTreeNode> & xNode)874 void SAL_CALL TreeControlPeer::startEditingAtNode( const Reference< XTreeNode >& xNode )
875 {
876     SolarMutexGuard aGuard;
877 
878     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
879     UnoTreeListEntry* pEntry = getEntry( xNode );
880     rTree.EditEntry( pEntry );
881 }
882 
addTreeEditListener(const Reference<XTreeEditListener> & xListener)883 void SAL_CALL TreeControlPeer::addTreeEditListener( const Reference< XTreeEditListener >& xListener )
884 {
885     maTreeEditListeners.addInterface( xListener );
886 }
887 
removeTreeEditListener(const Reference<XTreeEditListener> & xListener)888 void SAL_CALL TreeControlPeer::removeTreeEditListener( const Reference< XTreeEditListener >& xListener )
889 {
890     maTreeEditListeners.removeInterface( xListener );
891 }
892 
onEditingEntry(UnoTreeListEntry const * pEntry)893 bool TreeControlPeer::onEditingEntry( UnoTreeListEntry const * pEntry )
894 {
895     if( mpTreeImpl && pEntry && pEntry->mxNode.is() && (maTreeEditListeners.getLength() > 0)  )
896     {
897         try
898         {
899             maTreeEditListeners.nodeEditing( pEntry->mxNode );
900         }
901         catch( VetoException& )
902         {
903             return false;
904         }
905         catch( Exception& )
906         {
907         }
908     }
909     return true;
910 }
911 
onEditedEntry(UnoTreeListEntry const * pEntry,const OUString & rNewText)912 bool TreeControlPeer::onEditedEntry( UnoTreeListEntry const * pEntry, const OUString& rNewText )
913 {
914     if( mpTreeImpl && pEntry && pEntry->mxNode.is() ) try
915     {
916         LockGuard aLockGuard( mnEditLock );
917         if( maTreeEditListeners.getLength() > 0 )
918         {
919             maTreeEditListeners.nodeEdited( pEntry->mxNode, rNewText );
920             return false;
921         }
922         else
923         {
924             Reference< XMutableTreeNode > xMutableNode( pEntry->mxNode, UNO_QUERY );
925             if( xMutableNode.is() )
926                 xMutableNode->setDisplayValue( Any( rNewText ) );
927             else
928                 return false;
929         }
930 
931     }
932     catch( Exception& )
933     {
934     }
935 
936     return true;
937 }
938 
939 
940 // css::awt::tree::TreeDataModelListener
941 
942 
treeNodesChanged(const css::awt::tree::TreeDataModelEvent & rEvent)943 void SAL_CALL TreeControlPeer::treeNodesChanged( const css::awt::tree::TreeDataModelEvent& rEvent )
944 {
945     SolarMutexGuard aGuard;
946 
947     if( mnEditLock != 0 )
948         return;
949 
950     updateTree( rEvent );
951 }
952 
treeNodesInserted(const css::awt::tree::TreeDataModelEvent & rEvent)953 void SAL_CALL TreeControlPeer::treeNodesInserted( const css::awt::tree::TreeDataModelEvent& rEvent )
954 {
955     SolarMutexGuard aGuard;
956 
957     if( mnEditLock != 0 )
958         return;
959 
960     updateTree( rEvent );
961 }
962 
treeNodesRemoved(const css::awt::tree::TreeDataModelEvent & rEvent)963 void SAL_CALL TreeControlPeer::treeNodesRemoved( const css::awt::tree::TreeDataModelEvent& rEvent )
964 {
965     SolarMutexGuard aGuard;
966 
967     if( mnEditLock != 0 )
968         return;
969 
970     updateTree( rEvent );
971 }
972 
treeStructureChanged(const css::awt::tree::TreeDataModelEvent & rEvent)973 void SAL_CALL TreeControlPeer::treeStructureChanged( const css::awt::tree::TreeDataModelEvent& rEvent )
974 {
975     SolarMutexGuard aGuard;
976 
977     if( mnEditLock != 0 )
978         return;
979 
980     updateTree( rEvent );
981 }
982 
updateTree(const css::awt::tree::TreeDataModelEvent & rEvent)983 void TreeControlPeer::updateTree( const css::awt::tree::TreeDataModelEvent& rEvent )
984 {
985     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
986 
987     Sequence< Reference< XTreeNode > > Nodes;
988     Reference< XTreeNode > xNode( rEvent.ParentNode );
989     if( !xNode.is() && Nodes.hasElements() )
990     {
991         xNode = Nodes[0];
992     }
993 
994     if( xNode.is() )
995         updateNode( rTree, xNode );
996 }
997 
updateNode(UnoTreeListBoxImpl const & rTree,const Reference<XTreeNode> & xNode)998 void TreeControlPeer::updateNode( UnoTreeListBoxImpl const & rTree, const Reference< XTreeNode >& xNode )
999 {
1000     if( !xNode.is() )
1001         return;
1002 
1003     UnoTreeListEntry* pNodeEntry = getEntry( xNode, false );
1004 
1005     if( !pNodeEntry )
1006     {
1007         Reference< XTreeNode > xParentNode( xNode->getParent() );
1008         UnoTreeListEntry* pParentEntry = nullptr;
1009         sal_uLong nChild = TREELIST_APPEND;
1010 
1011         if( xParentNode.is() )
1012         {
1013             pParentEntry = getEntry( xParentNode  );
1014             nChild = xParentNode->getIndex( xNode );
1015         }
1016 
1017         pNodeEntry = createEntry( xNode, pParentEntry, nChild );
1018     }
1019 
1020     updateChildNodes( rTree, xNode, pNodeEntry );
1021 }
1022 
updateChildNodes(UnoTreeListBoxImpl const & rTree,const Reference<XTreeNode> & xParentNode,UnoTreeListEntry * pParentEntry)1023 void TreeControlPeer::updateChildNodes( UnoTreeListBoxImpl const & rTree, const Reference< XTreeNode >& xParentNode, UnoTreeListEntry* pParentEntry )
1024 {
1025     if( !(xParentNode.is() && pParentEntry) )
1026         return;
1027 
1028     UnoTreeListEntry* pCurrentChild = dynamic_cast< UnoTreeListEntry* >( rTree.FirstChild( pParentEntry ) );
1029 
1030     const sal_Int32 nChildCount = xParentNode->getChildCount();
1031     for( sal_Int32 nChild = 0; nChild < nChildCount; nChild++ )
1032     {
1033         Reference< XTreeNode > xNode( xParentNode->getChildAt( nChild ) );
1034         if( !pCurrentChild || ( pCurrentChild->mxNode != xNode ) )
1035         {
1036             UnoTreeListEntry* pNodeEntry = getEntry( xNode, false );
1037             if( pNodeEntry == nullptr )
1038             {
1039                 // child node is not yet part of the tree, add it
1040                 pCurrentChild = createEntry( xNode, pParentEntry, nChild );
1041             }
1042             else if( pNodeEntry != pCurrentChild )
1043             {
1044                 // node is already part of the tree, but not on the correct position
1045                 rTree.GetModel()->Move( pNodeEntry, pParentEntry, nChild );
1046                 pCurrentChild = pNodeEntry;
1047                 updateEntry( pCurrentChild );
1048             }
1049         }
1050         else
1051         {
1052             // child node has entry and entry is equal to current entry,
1053             // so no structural changes happened
1054             updateEntry( pCurrentChild );
1055         }
1056 
1057         pCurrentChild = dynamic_cast< UnoTreeListEntry* >( pCurrentChild->NextSibling() );
1058     }
1059 
1060     // check if we have entries without nodes left, we need to remove them
1061     while( pCurrentChild )
1062     {
1063         UnoTreeListEntry* pNextChild = dynamic_cast< UnoTreeListEntry* >( pCurrentChild->NextSibling() );
1064         rTree.GetModel()->Remove( pCurrentChild );
1065         pCurrentChild = pNextChild;
1066     }
1067 }
1068 
getEntryString(const Any & rValue)1069 OUString TreeControlPeer::getEntryString( const Any& rValue )
1070 {
1071     OUString sValue;
1072     if( rValue.hasValue() )
1073     {
1074         switch( rValue.getValueTypeClass() )
1075         {
1076         case TypeClass_SHORT:
1077         case TypeClass_LONG:
1078             {
1079                 sal_Int32 nValue = 0;
1080                 if( rValue >>= nValue )
1081                     sValue = OUString::number( nValue );
1082                 break;
1083             }
1084         case TypeClass_BYTE:
1085         case TypeClass_UNSIGNED_SHORT:
1086         case TypeClass_UNSIGNED_LONG:
1087             {
1088                 sal_uInt32 nValue = 0;
1089                 if( rValue >>= nValue )
1090                     sValue = OUString::number( nValue );
1091                 break;
1092             }
1093         case TypeClass_HYPER:
1094             {
1095                 sal_Int64 nValue = 0;
1096                 if( rValue >>= nValue )
1097                     sValue = OUString::number( nValue );
1098                 break;
1099             }
1100         case TypeClass_UNSIGNED_HYPER:
1101             {
1102                 sal_uInt64 nValue = 0;
1103                 if( rValue >>= nValue )
1104                     sValue = OUString::number( nValue );
1105                 break;
1106             }
1107         case TypeClass_FLOAT:
1108         case TypeClass_DOUBLE:
1109             {
1110                 double fValue = 0.0;
1111                 if( rValue >>= fValue )
1112                     sValue = OUString::number( fValue );
1113                 break;
1114             }
1115         case TypeClass_STRING:
1116             rValue >>= sValue;
1117             break;
1118     /*
1119         case TypeClass_INTERFACE:
1120             // @todo
1121             break;
1122         case TypeClass_SEQUENCE:
1123             {
1124                 Sequence< Any > aValues;
1125                 if( aValue >>= aValues )
1126                 {
1127                     updateEntry( SvTreeListEntry& rEntry, aValues );
1128                     return;
1129                 }
1130             }
1131             break;
1132     */
1133         default:
1134             break;
1135         }
1136     }
1137     return sValue;
1138 }
1139 
1140 // XEventListener
disposing(const css::lang::EventObject &)1141 void SAL_CALL TreeControlPeer::disposing( const css::lang::EventObject& )
1142 {
1143     // model is disposed, so we clear our tree
1144     SolarMutexGuard aGuard;
1145     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
1146     rTree.Clear();
1147     mxDataModel.clear();
1148 }
1149 
onChangeDataModel(UnoTreeListBoxImpl & rTree,const Reference<XTreeDataModel> & xDataModel)1150 void TreeControlPeer::onChangeDataModel( UnoTreeListBoxImpl& rTree, const Reference< XTreeDataModel >& xDataModel )
1151 {
1152     if( xDataModel.is() && (mxDataModel == xDataModel) )
1153         return; // do nothing
1154 
1155     Reference< XTreeDataModelListener > xListener( this );
1156 
1157     if( mxDataModel.is() )
1158         mxDataModel->removeTreeDataModelListener( xListener );
1159 
1160     mxDataModel = xDataModel;
1161 
1162     fillTree( rTree, mxDataModel );
1163 
1164     if( mxDataModel.is() )
1165         mxDataModel->addTreeDataModelListener( xListener );
1166 }
1167 
1168 
1169 // css::awt::XLayoutConstrains
1170 
1171 
getMinimumSize()1172 css::awt::Size TreeControlPeer::getMinimumSize()
1173 {
1174     SolarMutexGuard aGuard;
1175 
1176     css::awt::Size aSz;
1177 /* todo
1178     MultiLineEdit* pEdit = (MultiLineEdit*) GetWindow();
1179     if ( pEdit )
1180         aSz = AWTSize(pEdit->CalcMinimumSize());
1181 */
1182     return aSz;
1183 }
1184 
getPreferredSize()1185 css::awt::Size TreeControlPeer::getPreferredSize()
1186 {
1187     return getMinimumSize();
1188 }
1189 
calcAdjustedSize(const css::awt::Size & rNewSize)1190 css::awt::Size TreeControlPeer::calcAdjustedSize( const css::awt::Size& rNewSize )
1191 {
1192     SolarMutexGuard aGuard;
1193 
1194     css::awt::Size aSz = rNewSize;
1195 /* todo
1196     MultiLineEdit* pEdit = (MultiLineEdit*) GetWindow();
1197     if ( pEdit )
1198         aSz = AWTSize(pEdit->CalcAdjustedSize( VCLSize(rNewSize )));
1199 */
1200     return aSz;
1201 }
1202 
1203 
1204 // css::awt::XVclWindowPeer
1205 
1206 
setProperty(const OUString & PropertyName,const Any & aValue)1207 void TreeControlPeer::setProperty( const OUString& PropertyName, const Any& aValue)
1208 {
1209     SolarMutexGuard aGuard;
1210 
1211     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
1212 
1213     switch( GetPropertyId( PropertyName ) )
1214     {
1215         case BASEPROPERTY_HIDEINACTIVESELECTION:
1216         {
1217             bool bEnabled = false;
1218             if ( aValue >>= bEnabled )
1219             {
1220                 WinBits nStyle = rTree.GetStyle();
1221                 if ( bEnabled )
1222                     nStyle |= WB_HIDESELECTION;
1223                 else
1224                     nStyle &= ~WB_HIDESELECTION;
1225                 rTree.SetStyle( nStyle );
1226             }
1227         }
1228         break;
1229 
1230         case BASEPROPERTY_TREE_SELECTIONTYPE:
1231         {
1232             SelectionType eSelectionType;
1233             if( aValue >>= eSelectionType )
1234             {
1235                 SelectionMode eSelMode;
1236                 switch( eSelectionType )
1237                 {
1238                 case SelectionType_SINGLE:  eSelMode = SelectionMode::Single; break;
1239                 case SelectionType_RANGE:   eSelMode = SelectionMode::Range; break;
1240                 case SelectionType_MULTI:   eSelMode = SelectionMode::Multiple; break;
1241     //          case SelectionType_NONE:
1242                 default:                    eSelMode = SelectionMode::NONE; break;
1243                 }
1244                 if( rTree.GetSelectionMode() != eSelMode )
1245                     rTree.SetSelectionMode( eSelMode );
1246             }
1247             break;
1248         }
1249 
1250         case BASEPROPERTY_TREE_DATAMODEL:
1251             onChangeDataModel( rTree, Reference< XTreeDataModel >( aValue, UNO_QUERY ) );
1252             break;
1253         case BASEPROPERTY_ROW_HEIGHT:
1254         {
1255             sal_Int32 nHeight = 0;
1256             if( aValue >>= nHeight )
1257                 rTree.SetEntryHeight( static_cast<short>(nHeight) );
1258             break;
1259         }
1260         case BASEPROPERTY_TREE_EDITABLE:
1261         {
1262             bool bEnabled = false;
1263             if( aValue >>= bEnabled )
1264                 rTree.EnableInplaceEditing( bEnabled );
1265             break;
1266         }
1267         case BASEPROPERTY_TREE_INVOKESSTOPNODEEDITING:
1268             break; // @todo
1269         case BASEPROPERTY_TREE_ROOTDISPLAYED:
1270         {
1271             bool bDisplayed = false;
1272             if( (aValue >>= bDisplayed) && ( bDisplayed != mbIsRootDisplayed) )
1273             {
1274                 onChangeRootDisplayed(bDisplayed);
1275             }
1276             break;
1277         }
1278         case BASEPROPERTY_TREE_SHOWSHANDLES:
1279         {
1280             bool bEnabled = false;
1281             if( aValue >>= bEnabled )
1282             {
1283                 WinBits nBits = rTree.GetStyle() & (~WB_HASLINES);
1284                 if( bEnabled )
1285                     nBits |= WB_HASLINES;
1286                 if( nBits != rTree.GetStyle() )
1287                     rTree.SetStyle( nBits );
1288             }
1289             break;
1290         }
1291         case BASEPROPERTY_TREE_SHOWSROOTHANDLES:
1292         {
1293             bool bEnabled = false;
1294             if( aValue >>= bEnabled )
1295             {
1296                 WinBits nBits = rTree.GetStyle() & (~WB_HASLINESATROOT);
1297                 if( bEnabled )
1298                     nBits |= WB_HASLINESATROOT;
1299                 if( nBits != rTree.GetStyle() )
1300                     rTree.SetStyle( nBits );
1301             }
1302             break;
1303         }
1304         default:
1305         VCLXWindow::setProperty( PropertyName, aValue );
1306         break;
1307     }
1308 }
1309 
getProperty(const OUString & PropertyName)1310 Any TreeControlPeer::getProperty( const OUString& PropertyName )
1311 {
1312     SolarMutexGuard aGuard;
1313 
1314     const sal_uInt16 nPropId = GetPropertyId( PropertyName );
1315     if( (nPropId >= BASEPROPERTY_TREE_START) && (nPropId <= BASEPROPERTY_TREE_END) )
1316     {
1317         UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
1318         switch(nPropId)
1319         {
1320         case BASEPROPERTY_TREE_SELECTIONTYPE:
1321         {
1322             SelectionType eSelectionType;
1323 
1324             SelectionMode eSelMode = rTree.GetSelectionMode();
1325             switch( eSelMode )
1326             {
1327             case SelectionMode::Single:  eSelectionType = SelectionType_SINGLE; break;
1328             case SelectionMode::Range:   eSelectionType = SelectionType_RANGE; break;
1329             case SelectionMode::Multiple:eSelectionType = SelectionType_MULTI; break;
1330 //          case SelectionMode::NONE:
1331             default:                eSelectionType = SelectionType_NONE; break;
1332             }
1333             return Any( eSelectionType );
1334         }
1335         case BASEPROPERTY_ROW_HEIGHT:
1336             return Any( static_cast<sal_Int32>(rTree.GetEntryHeight()) );
1337         case BASEPROPERTY_TREE_DATAMODEL:
1338             return Any( mxDataModel );
1339         case BASEPROPERTY_TREE_EDITABLE:
1340             return Any( rTree.IsInplaceEditingEnabled() );
1341         case BASEPROPERTY_TREE_INVOKESSTOPNODEEDITING:
1342             return Any( true ); // @todo
1343         case BASEPROPERTY_TREE_ROOTDISPLAYED:
1344             return Any( mbIsRootDisplayed );
1345         case BASEPROPERTY_TREE_SHOWSHANDLES:
1346             return Any( (rTree.GetStyle() & WB_HASLINES) != 0 );
1347         case BASEPROPERTY_TREE_SHOWSROOTHANDLES:
1348             return Any( (rTree.GetStyle() & WB_HASLINESATROOT) != 0 );
1349         }
1350     }
1351     return VCLXWindow::getProperty( PropertyName );
1352 }
1353 
onChangeRootDisplayed(bool bIsRootDisplayed)1354 void TreeControlPeer::onChangeRootDisplayed( bool bIsRootDisplayed )
1355 {
1356     if( mbIsRootDisplayed == bIsRootDisplayed )
1357         return;
1358 
1359     mbIsRootDisplayed = bIsRootDisplayed;
1360 
1361     UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
1362 
1363     if( rTree.GetEntryCount() == 0 )
1364         return;
1365 
1366     // todo
1367     fillTree( rTree, mxDataModel );
1368 }
1369 
loadImage(const OUString & rURL,Image & rImage)1370 bool TreeControlPeer::loadImage( const OUString& rURL, Image& rImage )
1371 {
1372     if( !mxGraphicProvider.is() )
1373     {
1374         mxGraphicProvider = graphic::GraphicProvider::create(
1375             comphelper::getProcessComponentContext());
1376     }
1377 
1378     try
1379     {
1380         css::beans::PropertyValues aProps( 1 );
1381         aProps[0].Name = "URL";
1382         aProps[0].Value <<= rURL;
1383 
1384         Reference< XGraphic > xGraphic( mxGraphicProvider->queryGraphic( aProps ) );
1385 
1386         Graphic aGraphic( xGraphic );
1387         rImage = Image(aGraphic.GetBitmapEx());
1388         return true;
1389     }
1390     catch( Exception& )
1391     {
1392     }
1393 
1394     return false;
1395 }
1396 
1397 
1398 // class UnoTreeListBoxImpl
1399 
1400 
UnoTreeListBoxImpl(TreeControlPeer * pPeer,vcl::Window * pParent,WinBits nWinStyle)1401 UnoTreeListBoxImpl::UnoTreeListBoxImpl( TreeControlPeer* pPeer, vcl::Window* pParent, WinBits nWinStyle )
1402 : SvTreeListBox( pParent, nWinStyle )
1403 , mxPeer( pPeer )
1404 {
1405     SetStyle( WB_BORDER | WB_HASLINES |WB_HASBUTTONS | WB_HASLINESATROOT | WB_HASBUTTONSATROOT | WB_HSCROLL );
1406     SetNodeDefaultImages();
1407     SetSelectHdl( LINK(this, UnoTreeListBoxImpl, OnSelectionChangeHdl) );
1408     SetDeselectHdl( LINK(this, UnoTreeListBoxImpl, OnSelectionChangeHdl) );
1409 
1410     SetExpandingHdl( LINK(this, UnoTreeListBoxImpl, OnExpandingHdl) );
1411     SetExpandedHdl( LINK(this, UnoTreeListBoxImpl, OnExpandedHdl) );
1412 
1413 }
1414 
1415 
~UnoTreeListBoxImpl()1416 UnoTreeListBoxImpl::~UnoTreeListBoxImpl()
1417 {
1418     disposeOnce();
1419 }
1420 
dispose()1421 void UnoTreeListBoxImpl::dispose()
1422 {
1423     if( mxPeer.is() )
1424         mxPeer->disposeControl();
1425     mxPeer.clear();
1426     SvTreeListBox::dispose();
1427 }
1428 
1429 
IMPL_LINK_NOARG(UnoTreeListBoxImpl,OnSelectionChangeHdl,SvTreeListBox *,void)1430 IMPL_LINK_NOARG(UnoTreeListBoxImpl, OnSelectionChangeHdl, SvTreeListBox*, void)
1431 {
1432     if( mxPeer.is() )
1433         mxPeer->onSelectionChanged();
1434 }
1435 
1436 
IMPL_LINK_NOARG(UnoTreeListBoxImpl,OnExpandingHdl,SvTreeListBox *,bool)1437 IMPL_LINK_NOARG(UnoTreeListBoxImpl, OnExpandingHdl, SvTreeListBox*, bool)
1438 {
1439     UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( GetHdlEntry() );
1440 
1441     if( pEntry && mxPeer.is() )
1442     {
1443         return mxPeer->onExpanding( pEntry->mxNode, !IsExpanded( pEntry ) );
1444     }
1445     return false;
1446 }
1447 
1448 
IMPL_LINK_NOARG(UnoTreeListBoxImpl,OnExpandedHdl,SvTreeListBox *,void)1449 IMPL_LINK_NOARG(UnoTreeListBoxImpl, OnExpandedHdl, SvTreeListBox*, void)
1450 {
1451     UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( GetHdlEntry() );
1452     if( pEntry && mxPeer.is() )
1453     {
1454         mxPeer->onExpanded( pEntry->mxNode, IsExpanded( pEntry ) );
1455     }
1456 }
1457 
1458 
insert(SvTreeListEntry * pEntry,SvTreeListEntry * pParent,sal_uLong nPos)1459 void UnoTreeListBoxImpl::insert( SvTreeListEntry* pEntry,SvTreeListEntry* pParent,sal_uLong nPos )
1460 {
1461     if( pParent )
1462         SvTreeListBox::Insert( pEntry, pParent, nPos );
1463     else
1464         SvTreeListBox::Insert( pEntry, nPos );
1465 }
1466 
1467 
RequestingChildren(SvTreeListEntry * pParent)1468 void UnoTreeListBoxImpl::RequestingChildren( SvTreeListEntry* pParent )
1469 {
1470     UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( pParent );
1471     if( pEntry && pEntry->mxNode.is() && mxPeer.is() )
1472         mxPeer->onRequestChildNodes( pEntry->mxNode );
1473 }
1474 
1475 
EditingEntry(SvTreeListEntry * pEntry,Selection &)1476 bool UnoTreeListBoxImpl::EditingEntry( SvTreeListEntry* pEntry, Selection& )
1477 {
1478     return mxPeer.is() && mxPeer->onEditingEntry( dynamic_cast< UnoTreeListEntry* >( pEntry ) );
1479 }
1480 
1481 
EditedEntry(SvTreeListEntry * pEntry,const OUString & rNewText)1482 bool UnoTreeListBoxImpl::EditedEntry( SvTreeListEntry* pEntry, const OUString& rNewText )
1483 {
1484     return mxPeer.is() && mxPeer->onEditedEntry( dynamic_cast< UnoTreeListEntry* >( pEntry ), rNewText );
1485 }
1486 
1487 
1488 // class UnoTreeListItem
1489 
1490 
UnoTreeListItem()1491 UnoTreeListItem::UnoTreeListItem()
1492 : SvLBoxString(OUString())
1493 {
1494 }
1495 
Paint(const Point & rPos,SvTreeListBox & rDev,vcl::RenderContext & rRenderContext,const SvViewDataEntry *,const SvTreeListEntry & rEntry)1496 void UnoTreeListItem::Paint(
1497     const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext, const SvViewDataEntry* /*pView*/, const SvTreeListEntry& rEntry)
1498 {
1499     Point aPos(rPos);
1500     Size aSize(GetWidth(&rDev, &rEntry), GetHeight(&rDev, &rEntry));
1501     if (!!maImage)
1502     {
1503         rRenderContext.DrawImage(aPos, maImage, rDev.IsEnabled() ? DrawImageFlags::NONE : DrawImageFlags::Disable);
1504         int nWidth = maImage.GetSizePixel().Width() + 6;
1505         aPos.AdjustX(nWidth );
1506         aSize.AdjustWidth( -nWidth );
1507     }
1508     rRenderContext.DrawText(tools::Rectangle(aPos,aSize),maText, rDev.IsEnabled() ? DrawTextFlags::NONE : DrawTextFlags::Disable);
1509 }
1510 
1511 
Clone(SvLBoxItem const * pSource) const1512 std::unique_ptr<SvLBoxItem> UnoTreeListItem::Clone(SvLBoxItem const * pSource) const
1513 {
1514     std::unique_ptr<UnoTreeListItem> pNew(new UnoTreeListItem);
1515     UnoTreeListItem const * pSourceItem = static_cast< UnoTreeListItem const * >( pSource );
1516     pNew->maText = pSourceItem->maText;
1517     pNew->maImage = pSourceItem->maImage;
1518     return std::unique_ptr<SvLBoxItem>(pNew.release());
1519 }
1520 
1521 
SetImage(const Image & rImage)1522 void UnoTreeListItem::SetImage( const Image& rImage )
1523 {
1524     maImage = rImage;
1525 }
1526 
1527 
SetGraphicURL(const OUString & rGraphicURL)1528 void UnoTreeListItem::SetGraphicURL( const OUString& rGraphicURL )
1529 {
1530     maGraphicURL = rGraphicURL;
1531 }
1532 
1533 
InitViewData(SvTreeListBox * pView,SvTreeListEntry * pEntry,SvViewDataItem * pViewData)1534 void UnoTreeListItem::InitViewData( SvTreeListBox* pView,SvTreeListEntry* pEntry, SvViewDataItem* pViewData)
1535 {
1536     if( !pViewData )
1537         pViewData = pView->GetViewDataItem( pEntry, this );
1538 
1539     Size aSize(maImage.GetSizePixel());
1540     pViewData->mnWidth = aSize.Width();
1541     pViewData->mnHeight = aSize.Height();
1542 
1543     const Size aTextSize(pView->GetTextWidth( maText ), pView->GetTextHeight());
1544     if( pViewData->mnWidth )
1545     {
1546         pViewData->mnWidth += (6 + aTextSize.Width());
1547         if( pViewData->mnHeight < aTextSize.Height() )
1548             pViewData->mnHeight = aTextSize.Height();
1549     }
1550     else
1551     {
1552         pViewData->mnWidth = aTextSize.Width();
1553         pViewData->mnHeight = aTextSize.Height();
1554     }
1555 }
1556 
1557 
UnoTreeListEntry(const Reference<XTreeNode> & xNode,TreeControlPeer * pPeer)1558 UnoTreeListEntry::UnoTreeListEntry( const Reference< XTreeNode >& xNode, TreeControlPeer* pPeer )
1559 : SvTreeListEntry()
1560 , mxNode( xNode )
1561 , mpPeer( pPeer )
1562 {
1563     if( mpPeer )
1564         mpPeer->addEntry( this );
1565 }
1566 
1567 
~UnoTreeListEntry()1568 UnoTreeListEntry::~UnoTreeListEntry()
1569 {
1570     if( mpPeer )
1571         mpPeer->removeEntry( this );
1572 }
1573 
1574 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1575