summaryrefslogtreecommitdiff
path: root/toolkit
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2020-02-16 16:00:45 +0000
committerCaolán McNamara <caolanm@redhat.com>2020-02-16 20:17:08 +0100
commit475d6c193f043d796825bdde3944f006491a1794 (patch)
tree496d1e7553e09fb260fa9d4f5ebbc3be65e5148f /toolkit
parent0078b90f64c412487ab0818aa9101ccc4b137e5a (diff)
move TreeControlPeer to toolkit
Change-Id: Id5298615f0f3dad6e61955e23367c0345b33f2b6 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88813 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'toolkit')
-rw-r--r--toolkit/Library_tk.mk1
-rw-r--r--toolkit/inc/controls/treecontrolpeer.hxx170
-rw-r--r--toolkit/source/awt/vclxtoolkit.cxx7
-rw-r--r--toolkit/source/controls/tree/treecontrolpeer.cxx1581
4 files changed, 1759 insertions, 0 deletions
diff --git a/toolkit/Library_tk.mk b/toolkit/Library_tk.mk
index 55639910d7fb..752a0cc15f7b 100644
--- a/toolkit/Library_tk.mk
+++ b/toolkit/Library_tk.mk
@@ -103,6 +103,7 @@ $(eval $(call gb_Library_add_exception_objects,tk,\
toolkit/source/controls/animatedimages \
toolkit/source/controls/spinningprogress \
toolkit/source/controls/tree/treecontrol \
+ toolkit/source/controls/tree/treecontrolpeer \
toolkit/source/controls/tree/treedatamodel \
toolkit/source/controls/unocontrol \
toolkit/source/controls/unocontrolbase \
diff --git a/toolkit/inc/controls/treecontrolpeer.hxx b/toolkit/inc/controls/treecontrolpeer.hxx
new file mode 100644
index 000000000000..fb547973283d
--- /dev/null
+++ b/toolkit/inc/controls/treecontrolpeer.hxx
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/awt/tree/XTreeControl.hpp>
+#include <com/sun/star/awt/tree/XTreeDataModel.hpp>
+#include <com/sun/star/graphic/XGraphicProvider.hpp>
+
+#include <toolkit/awt/vclxwindow.hxx>
+#include <toolkit/helper/listenermultiplexer.hxx>
+
+#include <vcl/image.hxx>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <map>
+
+namespace com { namespace sun { namespace star { namespace awt { namespace tree {
+
+class XTreeNode;
+
+}}}}}
+
+class UnoTreeListEntry;
+class TreeControlPeer;
+class UnoTreeListBoxImpl;
+
+class TreeControlPeer : public ::cppu::ImplInheritanceHelper< VCLXWindow, css::awt::tree::XTreeControl, css::awt::tree::XTreeDataModelListener >
+{
+ typedef std::map<css::uno::Reference<css::awt::tree::XTreeNode>, UnoTreeListEntry*> TreeNodeMap;
+
+ friend class UnoTreeListBoxImpl;
+ friend class UnoTreeListEntry;
+public:
+ TreeControlPeer();
+ virtual ~TreeControlPeer() override;
+
+ vcl::Window* createVclControl( vcl::Window* pParent, sal_Int64 nWinStyle );
+
+ // css::view::XSelectionSupplier
+ virtual sal_Bool SAL_CALL select( const css::uno::Any& xSelection ) override;
+ virtual css::uno::Any SAL_CALL getSelection( ) override;
+ virtual void SAL_CALL addSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override;
+ virtual void SAL_CALL removeSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override;
+
+ // css::view::XMultiSelectionSupplier
+ virtual sal_Bool SAL_CALL addSelection( const css::uno::Any& Selection ) override;
+ virtual void SAL_CALL removeSelection( const css::uno::Any& Selection ) override;
+ virtual void SAL_CALL clearSelection( ) override;
+ virtual ::sal_Int32 SAL_CALL getSelectionCount( ) override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createSelectionEnumeration( ) override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createReverseSelectionEnumeration( ) override;
+
+ // css::awt::XTreeControl
+ virtual OUString SAL_CALL getDefaultExpandedGraphicURL() override;
+ virtual void SAL_CALL setDefaultExpandedGraphicURL( const OUString& _defaultexpandedgraphicurl ) override;
+ virtual OUString SAL_CALL getDefaultCollapsedGraphicURL() override;
+ virtual void SAL_CALL setDefaultCollapsedGraphicURL( const OUString& _defaultcollapsedgraphicurl ) override;
+ virtual sal_Bool SAL_CALL isNodeExpanded( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override;
+ virtual sal_Bool SAL_CALL isNodeCollapsed( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override;
+ virtual void SAL_CALL makeNodeVisible( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override;
+ virtual sal_Bool SAL_CALL isNodeVisible( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override;
+ virtual void SAL_CALL expandNode( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override;
+ virtual void SAL_CALL collapseNode( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override;
+ virtual void SAL_CALL addTreeExpansionListener( const css::uno::Reference< css::awt::tree::XTreeExpansionListener >& Listener ) override;
+ virtual void SAL_CALL removeTreeExpansionListener( const css::uno::Reference< css::awt::tree::XTreeExpansionListener >& Listener ) override;
+ virtual css::uno::Reference< css::awt::tree::XTreeNode > SAL_CALL getNodeForLocation( ::sal_Int32 x, ::sal_Int32 y ) override;
+ virtual css::uno::Reference< css::awt::tree::XTreeNode > SAL_CALL getClosestNodeForLocation( ::sal_Int32 x, ::sal_Int32 y ) override;
+ virtual css::awt::Rectangle SAL_CALL getNodeRect( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override;
+ virtual sal_Bool SAL_CALL isEditing( ) override;
+ virtual sal_Bool SAL_CALL stopEditing( ) override;
+ virtual void SAL_CALL cancelEditing( ) override;
+ virtual void SAL_CALL startEditingAtNode( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override;
+ virtual void SAL_CALL addTreeEditListener( const css::uno::Reference< css::awt::tree::XTreeEditListener >& Listener ) override;
+ virtual void SAL_CALL removeTreeEditListener( const css::uno::Reference< css::awt::tree::XTreeEditListener >& Listener ) override;
+
+ // css::awt::tree::TreeDataModelListener
+ virtual void SAL_CALL treeNodesChanged( const css::awt::tree::TreeDataModelEvent& aEvent ) override;
+ virtual void SAL_CALL treeNodesInserted( const css::awt::tree::TreeDataModelEvent& aEvent ) override;
+ virtual void SAL_CALL treeNodesRemoved( const css::awt::tree::TreeDataModelEvent& aEvent ) override;
+ virtual void SAL_CALL treeStructureChanged( const css::awt::tree::TreeDataModelEvent& aEvent ) override;
+
+ // XEventListener
+ void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // css::awt::XLayoutConstrains
+ css::awt::Size SAL_CALL getMinimumSize() override;
+ css::awt::Size SAL_CALL getPreferredSize() override;
+ css::awt::Size SAL_CALL calcAdjustedSize( const css::awt::Size& aNewSize ) override;
+
+ // css::awt::XVclWindowPeer
+ void SAL_CALL setProperty( const OUString& PropertyName, const css::uno::Any& Value ) override;
+ css::uno::Any SAL_CALL getProperty( const OUString& PropertyName ) override;
+
+private:
+ /// @throws css::lang::IllegalArgumentException
+ UnoTreeListEntry* getEntry( const css::uno::Reference< css::awt::tree::XTreeNode >& xNode, bool bThrow = true );
+
+ void disposeControl();
+
+ bool onEditingEntry( UnoTreeListEntry const * pEntry );
+ bool onEditedEntry( UnoTreeListEntry const * pEntry, const OUString& rNewText );
+
+ void fillTree( UnoTreeListBoxImpl& rTree, const css::uno::Reference< css::awt::tree::XTreeDataModel >& xDataModel );
+ void addNode( UnoTreeListBoxImpl& rTree, const css::uno::Reference< css::awt::tree::XTreeNode >& xNode, UnoTreeListEntry* pParentEntry );
+
+ UnoTreeListEntry* createEntry( const css::uno::Reference< css::awt::tree::XTreeNode >& xNode, UnoTreeListEntry* pParent, sal_uLong nPos );
+ void updateEntry( UnoTreeListEntry* pEntry );
+
+ void updateTree( const css::awt::tree::TreeDataModelEvent& rEvent );
+ void updateNode( UnoTreeListBoxImpl const & rTree, const css::uno::Reference< css::awt::tree::XTreeNode >& xNode );
+ void updateChildNodes( UnoTreeListBoxImpl const & rTree, const css::uno::Reference< css::awt::tree::XTreeNode >& xParentNode, UnoTreeListEntry* pParentEntry );
+
+ static OUString getEntryString( const css::uno::Any& rValue );
+
+ /// @throws css::uno::RuntimeException
+ UnoTreeListBoxImpl& getTreeListBoxOrThrow() const;
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void ChangeNodesSelection( const css::uno::Any& rSelection, bool bSelect, bool bSetSelection );
+
+ void onChangeDataModel( UnoTreeListBoxImpl& rTree, const css::uno::Reference< css::awt::tree::XTreeDataModel >& xDataModel );
+
+ void onSelectionChanged();
+ void onRequestChildNodes( const css::uno::Reference< css::awt::tree::XTreeNode >& xNode );
+ bool onExpanding( const css::uno::Reference< css::awt::tree::XTreeNode >& xNode, bool bExpanding );
+ void onExpanded( const css::uno::Reference< css::awt::tree::XTreeNode >& xNode, bool bExpanding );
+
+ void onChangeRootDisplayed( bool bIsRootDisplayed );
+
+ void addEntry( UnoTreeListEntry* pEntry );
+ void removeEntry( UnoTreeListEntry const * pEntry );
+
+ bool loadImage( const OUString& rURL, Image& rImage );
+
+private:
+ css::uno::Reference< css::awt::tree::XTreeDataModel >mxDataModel;
+ TreeSelectionListenerMultiplexer maSelectionListeners;
+ TreeExpansionListenerMultiplexer maTreeExpansionListeners;
+ TreeEditListenerMultiplexer maTreeEditListeners;
+ bool mbIsRootDisplayed;
+ VclPtr<UnoTreeListBoxImpl> mpTreeImpl;
+ sal_Int32 mnEditLock;
+ OUString msDefaultCollapsedGraphicURL;
+ OUString msDefaultExpandedGraphicURL;
+ Image maDefaultExpandedImage;
+ Image maDefaultCollapsedImage;
+ std::unique_ptr<TreeNodeMap> mpTreeNodeMap;
+ css::uno::Reference< css::graphic::XGraphicProvider > mxGraphicProvider;
+};
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/toolkit/source/awt/vclxtoolkit.cxx b/toolkit/source/awt/vclxtoolkit.cxx
index cc3adf9c3cde..64b33e4de956 100644
--- a/toolkit/source/awt/vclxtoolkit.cxx
+++ b/toolkit/source/awt/vclxtoolkit.cxx
@@ -79,6 +79,7 @@
#include <toolkit/helper/convert.hxx>
#include <controls/filectrl.hxx>
+#include <controls/treecontrolpeer.hxx>
#include <vcl/button.hxx>
#include <vcl/combobox.hxx>
#include <vcl/ctrl.hxx>
@@ -1808,6 +1809,12 @@ vcl::Window* VCLXToolkit::ImplCreateWindow( VCLXWindow** ppNewComp,
pNewWindow = VclPtr<FileControl>::Create( pParent, nWinBits );
*ppNewComp = new VCLXFileControl;
}
+ else if (aServiceName == "tree")
+ {
+ TreeControlPeer* pPeer = new TreeControlPeer;
+ *ppNewComp = pPeer;
+ pNewWindow = pPeer->createVclControl( pParent, nWinBits );
+ }
break;
default:
OSL_ENSURE( false, "VCLXToolkit::ImplCreateWindow: unknown window type!" );
diff --git a/toolkit/source/controls/tree/treecontrolpeer.cxx b/toolkit/source/controls/tree/treecontrolpeer.cxx
new file mode 100644
index 000000000000..cefb7d4762ea
--- /dev/null
+++ b/toolkit/source/controls/tree/treecontrolpeer.cxx
@@ -0,0 +1,1581 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <memory>
+#include <com/sun/star/graphic/GraphicProvider.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/view/SelectionType.hpp>
+#include <com/sun/star/util/VetoException.hpp>
+#include <o3tl/any.hxx>
+#include <toolkit/helper/property.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+
+#include <com/sun/star/awt/tree/XMutableTreeNode.hpp>
+#include <controls/treecontrolpeer.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/treelistbox.hxx>
+#include <vcl/treelistentry.hxx>
+#include <vcl/viewdataentry.hxx>
+#include <vcl/svlbitm.hxx>
+
+#include <map>
+
+using namespace ::com::sun::star;
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::awt::tree;
+using namespace css::beans;
+using namespace css::view;
+using namespace css::container;
+using namespace css::util;
+using namespace css::graphic;
+
+namespace {
+
+struct LockGuard
+{
+public:
+ explicit LockGuard( sal_Int32& rLock )
+ : mrLock( rLock )
+ {
+ rLock++;
+ }
+
+ ~LockGuard()
+ {
+ mrLock--;
+ }
+
+ sal_Int32& mrLock;
+};
+
+
+class ImplContextGraphicItem : public SvLBoxContextBmp
+{
+public:
+ ImplContextGraphicItem( Image const & rI1, Image const & rI2, bool bExpanded)
+ : SvLBoxContextBmp(rI1, rI2, bExpanded) {}
+
+ OUString msExpandedGraphicURL;
+ OUString msCollapsedGraphicURL;
+};
+
+
+}
+
+class UnoTreeListBoxImpl : public SvTreeListBox
+{
+public:
+ UnoTreeListBoxImpl( TreeControlPeer* pPeer, vcl::Window* pParent, WinBits nWinStyle );
+ virtual ~UnoTreeListBoxImpl() override;
+ virtual void dispose() override;
+
+ void insert( SvTreeListEntry* pEntry, SvTreeListEntry* pParent, sal_uLong nPos );
+
+ virtual void RequestingChildren( SvTreeListEntry* pParent ) override;
+
+ virtual bool EditingEntry( SvTreeListEntry* pEntry, Selection& ) override;
+ virtual bool EditedEntry( SvTreeListEntry* pEntry, const OUString& rNewText ) override;
+
+ DECL_LINK(OnSelectionChangeHdl, SvTreeListBox*, void);
+ DECL_LINK(OnExpandingHdl, SvTreeListBox*, bool);
+ DECL_LINK(OnExpandedHdl, SvTreeListBox*, void);
+
+private:
+ rtl::Reference< TreeControlPeer > mxPeer;
+};
+
+
+namespace {
+
+class UnoTreeListItem : public SvLBoxString
+{
+public:
+ UnoTreeListItem();
+
+ void InitViewData( SvTreeListBox*,SvTreeListEntry*,SvViewDataItem * = nullptr ) override;
+ void SetImage( const Image& rImage );
+ const OUString& GetGraphicURL() const { return maGraphicURL;}
+ void SetGraphicURL( const OUString& rGraphicURL );
+ virtual void Paint(const Point& rPos, SvTreeListBox& rOutDev, vcl::RenderContext& rRenderContext,
+ const SvViewDataEntry* pView, const SvTreeListEntry& rEntry) override;
+ std::unique_ptr<SvLBoxItem> Clone( SvLBoxItem const * pSource ) const override;
+
+private:
+ OUString maGraphicURL;
+ Image maImage;
+};
+
+}
+
+class UnoTreeListEntry : public SvTreeListEntry
+{
+public:
+ UnoTreeListEntry( const Reference< XTreeNode >& xNode, TreeControlPeer* pPeer );
+ virtual ~UnoTreeListEntry() override;
+
+ Reference< XTreeNode > mxNode;
+ TreeControlPeer* mpPeer;
+};
+
+TreeControlPeer::TreeControlPeer()
+ : maSelectionListeners( *this )
+ , maTreeExpansionListeners( *this )
+ , maTreeEditListeners( *this )
+ , mbIsRootDisplayed(false)
+ , mpTreeImpl( nullptr )
+ , mnEditLock( 0 )
+{
+}
+
+
+TreeControlPeer::~TreeControlPeer()
+{
+ if( mpTreeImpl )
+ mpTreeImpl->Clear();
+}
+
+
+void TreeControlPeer::addEntry( UnoTreeListEntry* pEntry )
+{
+ if( pEntry && pEntry->mxNode.is() )
+ {
+ if( !mpTreeNodeMap )
+ {
+ mpTreeNodeMap.reset( new TreeNodeMap );
+ }
+
+ (*mpTreeNodeMap)[ pEntry->mxNode ] = pEntry;
+ }
+}
+
+
+void TreeControlPeer::removeEntry( UnoTreeListEntry const * pEntry )
+{
+ if( mpTreeNodeMap && pEntry && pEntry->mxNode.is() )
+ {
+ TreeNodeMap::iterator aIter( mpTreeNodeMap->find( pEntry->mxNode ) );
+ if( aIter != mpTreeNodeMap->end() )
+ {
+ mpTreeNodeMap->erase( aIter );
+ }
+ }
+}
+
+
+UnoTreeListEntry* TreeControlPeer::getEntry( const Reference< XTreeNode >& xNode, bool bThrow /* = true */ )
+{
+ if( mpTreeNodeMap )
+ {
+ TreeNodeMap::iterator aIter( mpTreeNodeMap->find( xNode ) );
+ if( aIter != mpTreeNodeMap->end() )
+ return (*aIter).second;
+ }
+
+ if( bThrow )
+ throw IllegalArgumentException();
+
+ return nullptr;
+}
+
+
+vcl::Window* TreeControlPeer::createVclControl( vcl::Window* pParent, sal_Int64 nWinStyle )
+{
+ mpTreeImpl = VclPtr<UnoTreeListBoxImpl>::Create( this, pParent, nWinStyle );
+ return mpTreeImpl;
+}
+
+
+/** called from the UnoTreeListBoxImpl when it gets deleted */
+void TreeControlPeer::disposeControl()
+{
+ mpTreeNodeMap.reset();
+ mpTreeImpl = nullptr;
+}
+
+
+UnoTreeListEntry* TreeControlPeer::createEntry( const Reference< XTreeNode >& xNode, UnoTreeListEntry* pParent, sal_uLong nPos /* = TREELIST_APPEND */ )
+{
+ UnoTreeListEntry* pEntry = nullptr;
+ if( mpTreeImpl )
+ {
+ Image aImage;
+ pEntry = new UnoTreeListEntry( xNode, this );
+ pEntry->AddItem(std::make_unique<ImplContextGraphicItem>(aImage, aImage, true));
+
+ std::unique_ptr<UnoTreeListItem> pUnoItem(new UnoTreeListItem);
+
+ if( !xNode->getNodeGraphicURL().isEmpty() )
+ {
+ pUnoItem->SetGraphicURL( xNode->getNodeGraphicURL() );
+ Image aNodeImage;
+ loadImage( xNode->getNodeGraphicURL(), aNodeImage );
+ pUnoItem->SetImage( aNodeImage );
+ mpTreeImpl->AdjustEntryHeight( aNodeImage );
+ }
+
+ pEntry->AddItem(std::move(pUnoItem));
+
+ mpTreeImpl->insert( pEntry, pParent, nPos );
+
+ if( !msDefaultExpandedGraphicURL.isEmpty() )
+ mpTreeImpl->SetExpandedEntryBmp( pEntry, maDefaultExpandedImage );
+
+ if( !msDefaultCollapsedGraphicURL.isEmpty() )
+ mpTreeImpl->SetCollapsedEntryBmp( pEntry, maDefaultCollapsedImage );
+
+ updateEntry( pEntry );
+ }
+ return pEntry;
+}
+
+
+void TreeControlPeer::updateEntry( UnoTreeListEntry* pEntry )
+{
+ bool bChanged = false;
+ if( !(pEntry && pEntry->mxNode.is() && mpTreeImpl) )
+ return;
+
+ const OUString aValue( getEntryString( pEntry->mxNode->getDisplayValue() ) );
+ UnoTreeListItem* pUnoItem = dynamic_cast< UnoTreeListItem* >( &pEntry->GetItem( 1 ) );
+ if( pUnoItem )
+ {
+ if( aValue != pUnoItem->GetText() )
+ {
+ pUnoItem->SetText( aValue );
+ bChanged = true;
+ }
+
+ if( pUnoItem->GetGraphicURL() != pEntry->mxNode->getNodeGraphicURL() )
+ {
+ Image aImage;
+ if( loadImage( pEntry->mxNode->getNodeGraphicURL(), aImage ) )
+ {
+ pUnoItem->SetGraphicURL( pEntry->mxNode->getNodeGraphicURL() );
+ pUnoItem->SetImage( aImage );
+ mpTreeImpl->AdjustEntryHeight( aImage );
+ bChanged = true;
+ }
+ }
+ }
+
+ if( bool(pEntry->mxNode->hasChildrenOnDemand()) != pEntry->HasChildrenOnDemand() )
+ {
+ pEntry->EnableChildrenOnDemand( pEntry->mxNode->hasChildrenOnDemand() );
+ bChanged = true;
+ }
+
+ ImplContextGraphicItem* pContextGraphicItem = dynamic_cast< ImplContextGraphicItem* >( &pEntry->GetItem( 0 ) );
+ if( pContextGraphicItem )
+ {
+ if( pContextGraphicItem->msExpandedGraphicURL != pEntry->mxNode->getExpandedGraphicURL() )
+ {
+ Image aImage;
+ if( loadImage( pEntry->mxNode->getExpandedGraphicURL(), aImage ) )
+ {
+ pContextGraphicItem->msExpandedGraphicURL = pEntry->mxNode->getExpandedGraphicURL();
+ mpTreeImpl->SetExpandedEntryBmp( pEntry, aImage );
+ bChanged = true;
+ }
+ }
+ if( pContextGraphicItem->msCollapsedGraphicURL != pEntry->mxNode->getCollapsedGraphicURL() )
+ {
+ Image aImage;
+ if( loadImage( pEntry->mxNode->getCollapsedGraphicURL(), aImage ) )
+ {
+ pContextGraphicItem->msCollapsedGraphicURL = pEntry->mxNode->getCollapsedGraphicURL();
+ mpTreeImpl->SetCollapsedEntryBmp( pEntry, aImage );
+ bChanged = true;
+ }
+ }
+ }
+
+ if( bChanged )
+ mpTreeImpl->GetModel()->InvalidateEntry( pEntry );
+}
+
+
+void TreeControlPeer::onSelectionChanged()
+{
+ Reference< XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) );
+ EventObject aEvent( xSource );
+ maSelectionListeners.selectionChanged( aEvent );
+}
+
+
+void TreeControlPeer::onRequestChildNodes( const Reference< XTreeNode >& xNode )
+{
+ try
+ {
+ Reference< XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) );
+ TreeExpansionEvent aEvent( xSource, xNode );
+ maTreeExpansionListeners.requestChildNodes( aEvent );
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+
+bool TreeControlPeer::onExpanding( const Reference< XTreeNode >& xNode, bool bExpanding )
+{
+ try
+ {
+ Reference< XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) );
+ TreeExpansionEvent aEvent( xSource, xNode );
+ if( bExpanding )
+ {
+ maTreeExpansionListeners.treeExpanding( aEvent );
+ }
+ else
+ {
+ maTreeExpansionListeners.treeCollapsing( aEvent );
+ }
+ }
+ catch( Exception& )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+void TreeControlPeer::onExpanded( const Reference< XTreeNode >& xNode, bool bExpanding )
+{
+ try
+ {
+ Reference< XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) );
+ TreeExpansionEvent aEvent( xSource, xNode );
+
+ if( bExpanding )
+ {
+ maTreeExpansionListeners.treeExpanded( aEvent );
+ }
+ else
+ {
+ maTreeExpansionListeners.treeCollapsed( aEvent );
+ }
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+
+void TreeControlPeer::fillTree( UnoTreeListBoxImpl& rTree, const Reference< XTreeDataModel >& xDataModel )
+{
+ rTree.Clear();
+
+ if( !xDataModel.is() )
+ return;
+
+ Reference< XTreeNode > xRootNode( xDataModel->getRoot() );
+ if( !xRootNode.is() )
+ return;
+
+ if( mbIsRootDisplayed )
+ {
+ addNode( rTree, xRootNode, nullptr );
+ }
+ else
+ {
+ const sal_Int32 nChildCount = xRootNode->getChildCount();
+ for( sal_Int32 nChild = 0; nChild < nChildCount; nChild++ )
+ addNode( rTree, xRootNode->getChildAt( nChild ), nullptr );
+ }
+}
+
+
+void TreeControlPeer::addNode( UnoTreeListBoxImpl& rTree, const Reference< XTreeNode >& xNode, UnoTreeListEntry* pParentEntry )
+{
+ if( xNode.is() )
+ {
+ UnoTreeListEntry* pEntry = createEntry( xNode, pParentEntry, TREELIST_APPEND );
+ const sal_Int32 nChildCount = xNode->getChildCount();
+ for( sal_Int32 nChild = 0; nChild < nChildCount; nChild++ )
+ addNode( rTree, xNode->getChildAt( nChild ), pEntry );
+ }
+}
+
+
+UnoTreeListBoxImpl& TreeControlPeer::getTreeListBoxOrThrow() const
+{
+ if( !mpTreeImpl )
+ throw DisposedException();
+ return *mpTreeImpl;
+}
+
+
+void TreeControlPeer::ChangeNodesSelection( const Any& rSelection, bool bSelect, bool bSetSelection )
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+
+ Reference< XTreeNode > xTempNode;
+
+ Sequence<Reference<XTreeNode>> pNodes;
+ sal_Int32 nCount = 0;
+
+ if( rSelection.hasValue() )
+ {
+ switch( rSelection.getValueTypeClass() )
+ {
+ case TypeClass_INTERFACE:
+ {
+ rSelection >>= xTempNode;
+ if( xTempNode.is() )
+ {
+ nCount = 1;
+ pNodes = {xTempNode};
+ }
+ break;
+ }
+ case TypeClass_SEQUENCE:
+ {
+ if( auto rSeq = o3tl::tryAccess<Sequence<Reference<XTreeNode>>>(
+ rSelection) )
+ {
+ nCount = rSeq->getLength();
+ pNodes = *rSeq;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if( nCount == 0 )
+ throw IllegalArgumentException();
+ }
+
+ if( bSetSelection )
+ rTree.SelectAll( false );
+
+ for( sal_Int32 i = 0; i != nCount; ++i )
+ {
+ UnoTreeListEntry* pEntry = getEntry( pNodes[i] );
+ rTree.Select( pEntry, bSelect );
+ }
+}
+
+
+// css::view::XSelectionSupplier
+
+
+sal_Bool SAL_CALL TreeControlPeer::select( const Any& rSelection )
+{
+ SolarMutexGuard aGuard;
+ ChangeNodesSelection( rSelection, true, true );
+ return true;
+}
+
+
+Any SAL_CALL TreeControlPeer::getSelection()
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+
+ Any aRet;
+
+ sal_uLong nSelectionCount = rTree.GetSelectionCount();
+ if( nSelectionCount == 1 )
+ {
+ UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.FirstSelected() );
+ if( pEntry && pEntry->mxNode.is() )
+ aRet <<= pEntry->mxNode;
+ }
+ else if( nSelectionCount > 1 )
+ {
+ Sequence< Reference< XTreeNode > > aSelection( nSelectionCount );
+ Reference< XTreeNode >* pNodes = aSelection.getArray();
+ UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.FirstSelected() );
+ while( pEntry && nSelectionCount )
+ {
+ *pNodes++ = pEntry->mxNode;
+ pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.NextSelected( pEntry ) );
+ --nSelectionCount;
+ }
+
+ OSL_ASSERT( (pEntry == nullptr) && (nSelectionCount == 0) );
+ aRet <<= aSelection;
+ }
+
+ return aRet;
+}
+
+
+void SAL_CALL TreeControlPeer::addSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener )
+{
+ maSelectionListeners.addInterface( xListener );
+}
+
+
+void SAL_CALL TreeControlPeer::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener )
+{
+ maSelectionListeners.addInterface( xListener );
+}
+
+
+// css::view::XMultiSelectionSupplier
+
+
+sal_Bool SAL_CALL TreeControlPeer::addSelection( const Any& rSelection )
+{
+ ChangeNodesSelection( rSelection, true, false );
+ return true;
+}
+
+
+void SAL_CALL TreeControlPeer::removeSelection( const Any& rSelection )
+{
+ ChangeNodesSelection( rSelection, false, false );
+}
+
+
+void SAL_CALL TreeControlPeer::clearSelection()
+{
+ SolarMutexGuard aGuard;
+ getTreeListBoxOrThrow().SelectAll( false );
+}
+
+
+sal_Int32 SAL_CALL TreeControlPeer::getSelectionCount()
+{
+ SolarMutexGuard aGuard;
+ return getTreeListBoxOrThrow().GetSelectionCount();
+}
+
+namespace {
+
+class TreeSelectionEnumeration : public ::cppu::WeakImplHelper< XEnumeration >
+{
+public:
+ explicit TreeSelectionEnumeration( std::list< Any >& rSelection );
+ virtual sal_Bool SAL_CALL hasMoreElements() override;
+ virtual Any SAL_CALL nextElement() override;
+
+ std::list< Any > maSelection;
+ std::list< Any >::iterator maIter;
+};
+
+}
+
+TreeSelectionEnumeration::TreeSelectionEnumeration( std::list< Any >& rSelection )
+{
+ maSelection.swap( rSelection );
+ maIter = maSelection.begin();
+}
+
+
+sal_Bool SAL_CALL TreeSelectionEnumeration::hasMoreElements()
+{
+ return maIter != maSelection.end();
+}
+
+
+Any SAL_CALL TreeSelectionEnumeration::nextElement()
+{
+ if( maIter == maSelection.end() )
+ throw NoSuchElementException();
+
+ return (*maIter++);
+}
+
+
+Reference< XEnumeration > SAL_CALL TreeControlPeer::createSelectionEnumeration()
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+
+ sal_uInt32 nSelectionCount = rTree.GetSelectionCount();
+ std::list< Any > aSelection( nSelectionCount );
+
+ UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.FirstSelected() );
+ while( pEntry && nSelectionCount )
+ {
+ aSelection.emplace_back( pEntry->mxNode );
+ pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.NextSelected( pEntry ) );
+ --nSelectionCount;
+ }
+
+ OSL_ASSERT( (pEntry == nullptr) && (nSelectionCount == 0) );
+
+ return Reference< XEnumeration >( new TreeSelectionEnumeration( aSelection ) );
+}
+
+
+Reference< XEnumeration > SAL_CALL TreeControlPeer::createReverseSelectionEnumeration()
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+
+ sal_uInt32 nSelectionCount = rTree.GetSelectionCount();
+ std::list< Any > aSelection;
+
+ UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.FirstSelected() );
+ while( pEntry && nSelectionCount )
+ {
+ aSelection.push_front( Any( pEntry->mxNode ) );
+ pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.NextSelected( pEntry ) );
+ --nSelectionCount;
+ }
+
+ OSL_ASSERT( (pEntry == nullptr) && (nSelectionCount == 0) );
+
+ return Reference< XEnumeration >( new TreeSelectionEnumeration( aSelection ) );
+}
+
+
+// css::awt::XTreeControl
+
+
+OUString SAL_CALL TreeControlPeer::getDefaultExpandedGraphicURL()
+{
+ SolarMutexGuard aGuard;
+ return msDefaultExpandedGraphicURL;
+}
+
+
+void SAL_CALL TreeControlPeer::setDefaultExpandedGraphicURL( const OUString& sDefaultExpandedGraphicURL )
+{
+ SolarMutexGuard aGuard;
+ if( msDefaultExpandedGraphicURL == sDefaultExpandedGraphicURL )
+ return;
+
+ if( !sDefaultExpandedGraphicURL.isEmpty() )
+ loadImage( sDefaultExpandedGraphicURL, maDefaultExpandedImage );
+ else
+ maDefaultExpandedImage = Image();
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+
+ SvTreeListEntry* pEntry = rTree.First();
+ while( pEntry )
+ {
+ ImplContextGraphicItem* pContextGraphicItem = dynamic_cast< ImplContextGraphicItem* >( &pEntry->GetItem( 0 ) );
+ if( pContextGraphicItem )
+ {
+ if( pContextGraphicItem->msExpandedGraphicURL.isEmpty() )
+ rTree.SetExpandedEntryBmp( pEntry, maDefaultExpandedImage );
+ }
+ pEntry = rTree.Next( pEntry );
+ }
+
+ msDefaultExpandedGraphicURL = sDefaultExpandedGraphicURL;
+}
+
+
+OUString SAL_CALL TreeControlPeer::getDefaultCollapsedGraphicURL()
+{
+ SolarMutexGuard aGuard;
+ return msDefaultCollapsedGraphicURL;
+}
+
+
+void SAL_CALL TreeControlPeer::setDefaultCollapsedGraphicURL( const OUString& sDefaultCollapsedGraphicURL )
+{
+ SolarMutexGuard aGuard;
+ if( msDefaultCollapsedGraphicURL == sDefaultCollapsedGraphicURL )
+ return;
+
+ if( !sDefaultCollapsedGraphicURL.isEmpty() )
+ loadImage( sDefaultCollapsedGraphicURL, maDefaultCollapsedImage );
+ else
+ maDefaultCollapsedImage = Image();
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+
+ SvTreeListEntry* pEntry = rTree.First();
+ while( pEntry )
+ {
+ ImplContextGraphicItem* pContextGraphicItem = dynamic_cast< ImplContextGraphicItem* >( &pEntry->GetItem( 0 ) );
+ if( pContextGraphicItem )
+ {
+ if( pContextGraphicItem->msCollapsedGraphicURL.isEmpty() )
+ rTree.SetCollapsedEntryBmp( pEntry, maDefaultCollapsedImage );
+ }
+ pEntry = rTree.Next( pEntry );
+ }
+
+ msDefaultCollapsedGraphicURL = sDefaultCollapsedGraphicURL;
+}
+
+
+sal_Bool SAL_CALL TreeControlPeer::isNodeExpanded( const Reference< XTreeNode >& xNode )
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+ UnoTreeListEntry* pEntry = getEntry( xNode );
+ return pEntry && rTree.IsExpanded( pEntry );
+}
+
+
+sal_Bool SAL_CALL TreeControlPeer::isNodeCollapsed( const Reference< XTreeNode >& xNode )
+{
+ SolarMutexGuard aGuard;
+ return !isNodeExpanded( xNode );
+}
+
+
+void SAL_CALL TreeControlPeer::makeNodeVisible( const Reference< XTreeNode >& xNode )
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+ UnoTreeListEntry* pEntry = getEntry( xNode );
+ if( pEntry )
+ rTree.MakeVisible( pEntry );
+}
+
+
+sal_Bool SAL_CALL TreeControlPeer::isNodeVisible( const Reference< XTreeNode >& xNode )
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+ UnoTreeListEntry* pEntry = getEntry( xNode );
+ return pEntry && rTree.IsEntryVisible( pEntry );
+}
+
+
+void SAL_CALL TreeControlPeer::expandNode( const Reference< XTreeNode >& xNode )
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+ UnoTreeListEntry* pEntry = getEntry( xNode );
+ if( pEntry )
+ rTree.Expand( pEntry );
+}
+
+
+void SAL_CALL TreeControlPeer::collapseNode( const Reference< XTreeNode >& xNode )
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+ UnoTreeListEntry* pEntry = getEntry( xNode );
+ if( pEntry )
+ rTree.Collapse( pEntry );
+}
+
+
+void SAL_CALL TreeControlPeer::addTreeExpansionListener( const Reference< XTreeExpansionListener >& xListener )
+{
+ maTreeExpansionListeners.addInterface( xListener );
+}
+
+
+void SAL_CALL TreeControlPeer::removeTreeExpansionListener( const Reference< XTreeExpansionListener >& xListener )
+{
+ maTreeExpansionListeners.removeInterface( xListener );
+}
+
+
+Reference< XTreeNode > SAL_CALL TreeControlPeer::getNodeForLocation( sal_Int32 x, sal_Int32 y )
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+
+ Reference< XTreeNode > xNode;
+
+ const Point aPos( x, y );
+ UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.GetEntry( aPos, true ) );
+ if( pEntry )
+ xNode = pEntry->mxNode;
+
+ return xNode;
+}
+
+
+Reference< XTreeNode > SAL_CALL TreeControlPeer::getClosestNodeForLocation( sal_Int32 x, sal_Int32 y )
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+
+ Reference< XTreeNode > xNode;
+
+ const Point aPos( x, y );
+ UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.GetEntry( aPos, true ) );
+ if( pEntry )
+ xNode = pEntry->mxNode;
+
+ return xNode;
+}
+
+
+awt::Rectangle SAL_CALL TreeControlPeer::getNodeRect( const Reference< XTreeNode >& i_Node )
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+ UnoTreeListEntry* pEntry = getEntry( i_Node );
+
+ ::tools::Rectangle aEntryRect( rTree.GetFocusRect( pEntry, rTree.GetEntryPosition( pEntry ).Y() ) );
+ return VCLUnoHelper::ConvertToAWTRect( aEntryRect );
+}
+
+
+sal_Bool SAL_CALL TreeControlPeer::isEditing( )
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+ return rTree.IsEditingActive();
+}
+
+
+sal_Bool SAL_CALL TreeControlPeer::stopEditing()
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+ if( rTree.IsEditingActive() )
+ {
+ rTree.EndEditing();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+void SAL_CALL TreeControlPeer::cancelEditing( )
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+ rTree.EndEditing();
+}
+
+
+void SAL_CALL TreeControlPeer::startEditingAtNode( const Reference< XTreeNode >& xNode )
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+ UnoTreeListEntry* pEntry = getEntry( xNode );
+ rTree.EditEntry( pEntry );
+}
+
+void SAL_CALL TreeControlPeer::addTreeEditListener( const Reference< XTreeEditListener >& xListener )
+{
+ maTreeEditListeners.addInterface( xListener );
+}
+
+void SAL_CALL TreeControlPeer::removeTreeEditListener( const Reference< XTreeEditListener >& xListener )
+{
+ maTreeEditListeners.removeInterface( xListener );
+}
+
+bool TreeControlPeer::onEditingEntry( UnoTreeListEntry const * pEntry )
+{
+ if( mpTreeImpl && pEntry && pEntry->mxNode.is() && (maTreeEditListeners.getLength() > 0) )
+ {
+ try
+ {
+ maTreeEditListeners.nodeEditing( pEntry->mxNode );
+ }
+ catch( VetoException& )
+ {
+ return false;
+ }
+ catch( Exception& )
+ {
+ }
+ }
+ return true;
+}
+
+bool TreeControlPeer::onEditedEntry( UnoTreeListEntry const * pEntry, const OUString& rNewText )
+{
+ if( mpTreeImpl && pEntry && pEntry->mxNode.is() ) try
+ {
+ LockGuard aLockGuard( mnEditLock );
+ if( maTreeEditListeners.getLength() > 0 )
+ {
+ maTreeEditListeners.nodeEdited( pEntry->mxNode, rNewText );
+ return false;
+ }
+ else
+ {
+ Reference< XMutableTreeNode > xMutableNode( pEntry->mxNode, UNO_QUERY );
+ if( xMutableNode.is() )
+ xMutableNode->setDisplayValue( Any( rNewText ) );
+ else
+ return false;
+ }
+
+ }
+ catch( Exception& )
+ {
+ }
+
+ return true;
+}
+
+
+// css::awt::tree::TreeDataModelListener
+
+
+void SAL_CALL TreeControlPeer::treeNodesChanged( const css::awt::tree::TreeDataModelEvent& rEvent )
+{
+ SolarMutexGuard aGuard;
+
+ if( mnEditLock != 0 )
+ return;
+
+ updateTree( rEvent );
+}
+
+void SAL_CALL TreeControlPeer::treeNodesInserted( const css::awt::tree::TreeDataModelEvent& rEvent )
+{
+ SolarMutexGuard aGuard;
+
+ if( mnEditLock != 0 )
+ return;
+
+ updateTree( rEvent );
+}
+
+void SAL_CALL TreeControlPeer::treeNodesRemoved( const css::awt::tree::TreeDataModelEvent& rEvent )
+{
+ SolarMutexGuard aGuard;
+
+ if( mnEditLock != 0 )
+ return;
+
+ updateTree( rEvent );
+}
+
+void SAL_CALL TreeControlPeer::treeStructureChanged( const css::awt::tree::TreeDataModelEvent& rEvent )
+{
+ SolarMutexGuard aGuard;
+
+ if( mnEditLock != 0 )
+ return;
+
+ updateTree( rEvent );
+}
+
+void TreeControlPeer::updateTree( const css::awt::tree::TreeDataModelEvent& rEvent )
+{
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+
+ Sequence< Reference< XTreeNode > > Nodes;
+ Reference< XTreeNode > xNode( rEvent.ParentNode );
+ if( !xNode.is() && Nodes.hasElements() )
+ {
+ xNode = Nodes[0];
+ }
+
+ if( xNode.is() )
+ updateNode( rTree, xNode );
+}
+
+void TreeControlPeer::updateNode( UnoTreeListBoxImpl const & rTree, const Reference< XTreeNode >& xNode )
+{
+ if( !xNode.is() )
+ return;
+
+ UnoTreeListEntry* pNodeEntry = getEntry( xNode, false );
+
+ if( !pNodeEntry )
+ {
+ Reference< XTreeNode > xParentNode( xNode->getParent() );
+ UnoTreeListEntry* pParentEntry = nullptr;
+ sal_uLong nChild = TREELIST_APPEND;
+
+ if( xParentNode.is() )
+ {
+ pParentEntry = getEntry( xParentNode );
+ nChild = xParentNode->getIndex( xNode );
+ }
+
+ pNodeEntry = createEntry( xNode, pParentEntry, nChild );
+ }
+
+ updateChildNodes( rTree, xNode, pNodeEntry );
+}
+
+void TreeControlPeer::updateChildNodes( UnoTreeListBoxImpl const & rTree, const Reference< XTreeNode >& xParentNode, UnoTreeListEntry* pParentEntry )
+{
+ if( !(xParentNode.is() && pParentEntry) )
+ return;
+
+ UnoTreeListEntry* pCurrentChild = dynamic_cast< UnoTreeListEntry* >( rTree.FirstChild( pParentEntry ) );
+
+ const sal_Int32 nChildCount = xParentNode->getChildCount();
+ for( sal_Int32 nChild = 0; nChild < nChildCount; nChild++ )
+ {
+ Reference< XTreeNode > xNode( xParentNode->getChildAt( nChild ) );
+ if( !pCurrentChild || ( pCurrentChild->mxNode != xNode ) )
+ {
+ UnoTreeListEntry* pNodeEntry = getEntry( xNode, false );
+ if( pNodeEntry == nullptr )
+ {
+ // child node is not yet part of the tree, add it
+ pCurrentChild = createEntry( xNode, pParentEntry, nChild );
+ }
+ else if( pNodeEntry != pCurrentChild )
+ {
+ // node is already part of the tree, but not on the correct position
+ rTree.GetModel()->Move( pNodeEntry, pParentEntry, nChild );
+ pCurrentChild = pNodeEntry;
+ updateEntry( pCurrentChild );
+ }
+ }
+ else
+ {
+ // child node has entry and entry is equal to current entry,
+ // so no structural changes happened
+ updateEntry( pCurrentChild );
+ }
+
+ pCurrentChild = dynamic_cast< UnoTreeListEntry* >( pCurrentChild->NextSibling() );
+ }
+
+ // check if we have entries without nodes left, we need to remove them
+ while( pCurrentChild )
+ {
+ UnoTreeListEntry* pNextChild = dynamic_cast< UnoTreeListEntry* >( pCurrentChild->NextSibling() );
+ rTree.GetModel()->Remove( pCurrentChild );
+ pCurrentChild = pNextChild;
+ }
+}
+
+OUString TreeControlPeer::getEntryString( const Any& rValue )
+{
+ OUString sValue;
+ if( rValue.hasValue() )
+ {
+ switch( rValue.getValueTypeClass() )
+ {
+ case TypeClass_SHORT:
+ case TypeClass_LONG:
+ {
+ sal_Int32 nValue = 0;
+ if( rValue >>= nValue )
+ sValue = OUString::number( nValue );
+ break;
+ }
+ case TypeClass_BYTE:
+ case TypeClass_UNSIGNED_SHORT:
+ case TypeClass_UNSIGNED_LONG:
+ {
+ sal_uInt32 nValue = 0;
+ if( rValue >>= nValue )
+ sValue = OUString::number( nValue );
+ break;
+ }
+ case TypeClass_HYPER:
+ {
+ sal_Int64 nValue = 0;
+ if( rValue >>= nValue )
+ sValue = OUString::number( nValue );
+ break;
+ }
+ case TypeClass_UNSIGNED_HYPER:
+ {
+ sal_uInt64 nValue = 0;
+ if( rValue >>= nValue )
+ sValue = OUString::number( nValue );
+ break;
+ }
+ case TypeClass_FLOAT:
+ case TypeClass_DOUBLE:
+ {
+ double fValue = 0.0;
+ if( rValue >>= fValue )
+ sValue = OUString::number( fValue );
+ break;
+ }
+ case TypeClass_STRING:
+ rValue >>= sValue;
+ break;
+ /*
+ case TypeClass_INTERFACE:
+ // @todo
+ break;
+ case TypeClass_SEQUENCE:
+ {
+ Sequence< Any > aValues;
+ if( aValue >>= aValues )
+ {
+ updateEntry( SvTreeListEntry& rEntry, aValues );
+ return;
+ }
+ }
+ break;
+ */
+ default:
+ break;
+ }
+ }
+ return sValue;
+}
+
+// XEventListener
+void SAL_CALL TreeControlPeer::disposing( const css::lang::EventObject& )
+{
+ // model is disposed, so we clear our tree
+ SolarMutexGuard aGuard;
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+ rTree.Clear();
+ mxDataModel.clear();
+}
+
+void TreeControlPeer::onChangeDataModel( UnoTreeListBoxImpl& rTree, const Reference< XTreeDataModel >& xDataModel )
+{
+ if( xDataModel.is() && (mxDataModel == xDataModel) )
+ return; // do nothing
+
+ Reference< XTreeDataModelListener > xListener( this );
+
+ if( mxDataModel.is() )
+ mxDataModel->removeTreeDataModelListener( xListener );
+
+ mxDataModel = xDataModel;
+
+ fillTree( rTree, mxDataModel );
+
+ if( mxDataModel.is() )
+ mxDataModel->addTreeDataModelListener( xListener );
+}
+
+
+// css::awt::XLayoutConstrains
+
+
+css::awt::Size TreeControlPeer::getMinimumSize()
+{
+ SolarMutexGuard aGuard;
+
+ css::awt::Size aSz;
+/* todo
+ MultiLineEdit* pEdit = (MultiLineEdit*) GetWindow();
+ if ( pEdit )
+ aSz = AWTSize(pEdit->CalcMinimumSize());
+*/
+ return aSz;
+}
+
+css::awt::Size TreeControlPeer::getPreferredSize()
+{
+ return getMinimumSize();
+}
+
+css::awt::Size TreeControlPeer::calcAdjustedSize( const css::awt::Size& rNewSize )
+{
+ SolarMutexGuard aGuard;
+
+ css::awt::Size aSz = rNewSize;
+/* todo
+ MultiLineEdit* pEdit = (MultiLineEdit*) GetWindow();
+ if ( pEdit )
+ aSz = AWTSize(pEdit->CalcAdjustedSize( VCLSize(rNewSize )));
+*/
+ return aSz;
+}
+
+
+// css::awt::XVclWindowPeer
+
+
+void TreeControlPeer::setProperty( const OUString& PropertyName, const Any& aValue)
+{
+ SolarMutexGuard aGuard;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+
+ switch( GetPropertyId( PropertyName ) )
+ {
+ case BASEPROPERTY_HIDEINACTIVESELECTION:
+ {
+ bool bEnabled = false;
+ if ( aValue >>= bEnabled )
+ {
+ WinBits nStyle = rTree.GetStyle();
+ if ( bEnabled )
+ nStyle |= WB_HIDESELECTION;
+ else
+ nStyle &= ~WB_HIDESELECTION;
+ rTree.SetStyle( nStyle );
+ }
+ }
+ break;
+
+ case BASEPROPERTY_TREE_SELECTIONTYPE:
+ {
+ SelectionType eSelectionType;
+ if( aValue >>= eSelectionType )
+ {
+ SelectionMode eSelMode;
+ switch( eSelectionType )
+ {
+ case SelectionType_SINGLE: eSelMode = SelectionMode::Single; break;
+ case SelectionType_RANGE: eSelMode = SelectionMode::Range; break;
+ case SelectionType_MULTI: eSelMode = SelectionMode::Multiple; break;
+ // case SelectionType_NONE:
+ default: eSelMode = SelectionMode::NONE; break;
+ }
+ if( rTree.GetSelectionMode() != eSelMode )
+ rTree.SetSelectionMode( eSelMode );
+ }
+ break;
+ }
+
+ case BASEPROPERTY_TREE_DATAMODEL:
+ onChangeDataModel( rTree, Reference< XTreeDataModel >( aValue, UNO_QUERY ) );
+ break;
+ case BASEPROPERTY_ROW_HEIGHT:
+ {
+ sal_Int32 nHeight = 0;
+ if( aValue >>= nHeight )
+ rTree.SetEntryHeight( static_cast<short>(nHeight) );
+ break;
+ }
+ case BASEPROPERTY_TREE_EDITABLE:
+ {
+ bool bEnabled = false;
+ if( aValue >>= bEnabled )
+ rTree.EnableInplaceEditing( bEnabled );
+ break;
+ }
+ case BASEPROPERTY_TREE_INVOKESSTOPNODEEDITING:
+ break; // @todo
+ case BASEPROPERTY_TREE_ROOTDISPLAYED:
+ {
+ bool bDisplayed = false;
+ if( (aValue >>= bDisplayed) && ( bDisplayed != mbIsRootDisplayed) )
+ {
+ onChangeRootDisplayed(bDisplayed);
+ }
+ break;
+ }
+ case BASEPROPERTY_TREE_SHOWSHANDLES:
+ {
+ bool bEnabled = false;
+ if( aValue >>= bEnabled )
+ {
+ WinBits nBits = rTree.GetStyle() & (~WB_HASLINES);
+ if( bEnabled )
+ nBits |= WB_HASLINES;
+ if( nBits != rTree.GetStyle() )
+ rTree.SetStyle( nBits );
+ }
+ break;
+ }
+ case BASEPROPERTY_TREE_SHOWSROOTHANDLES:
+ {
+ bool bEnabled = false;
+ if( aValue >>= bEnabled )
+ {
+ WinBits nBits = rTree.GetStyle() & (~WB_HASLINESATROOT);
+ if( bEnabled )
+ nBits |= WB_HASLINESATROOT;
+ if( nBits != rTree.GetStyle() )
+ rTree.SetStyle( nBits );
+ }
+ break;
+ }
+ default:
+ VCLXWindow::setProperty( PropertyName, aValue );
+ break;
+ }
+}
+
+Any TreeControlPeer::getProperty( const OUString& PropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ const sal_uInt16 nPropId = GetPropertyId( PropertyName );
+ if( (nPropId >= BASEPROPERTY_TREE_START) && (nPropId <= BASEPROPERTY_TREE_END) )
+ {
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+ switch(nPropId)
+ {
+ case BASEPROPERTY_TREE_SELECTIONTYPE:
+ {
+ SelectionType eSelectionType;
+
+ SelectionMode eSelMode = rTree.GetSelectionMode();
+ switch( eSelMode )
+ {
+ case SelectionMode::Single: eSelectionType = SelectionType_SINGLE; break;
+ case SelectionMode::Range: eSelectionType = SelectionType_RANGE; break;
+ case SelectionMode::Multiple:eSelectionType = SelectionType_MULTI; break;
+// case SelectionMode::NONE:
+ default: eSelectionType = SelectionType_NONE; break;
+ }
+ return Any( eSelectionType );
+ }
+ case BASEPROPERTY_ROW_HEIGHT:
+ return Any( static_cast<sal_Int32>(rTree.GetEntryHeight()) );
+ case BASEPROPERTY_TREE_DATAMODEL:
+ return Any( mxDataModel );
+ case BASEPROPERTY_TREE_EDITABLE:
+ return Any( rTree.IsInplaceEditingEnabled() );
+ case BASEPROPERTY_TREE_INVOKESSTOPNODEEDITING:
+ return Any( true ); // @todo
+ case BASEPROPERTY_TREE_ROOTDISPLAYED:
+ return Any( mbIsRootDisplayed );
+ case BASEPROPERTY_TREE_SHOWSHANDLES:
+ return Any( (rTree.GetStyle() & WB_HASLINES) != 0 );
+ case BASEPROPERTY_TREE_SHOWSROOTHANDLES:
+ return Any( (rTree.GetStyle() & WB_HASLINESATROOT) != 0 );
+ }
+ }
+ return VCLXWindow::getProperty( PropertyName );
+}
+
+void TreeControlPeer::onChangeRootDisplayed( bool bIsRootDisplayed )
+{
+ if( mbIsRootDisplayed == bIsRootDisplayed )
+ return;
+
+ mbIsRootDisplayed = bIsRootDisplayed;
+
+ UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
+
+ if( rTree.GetEntryCount() == 0 )
+ return;
+
+ // todo
+ fillTree( rTree, mxDataModel );
+}
+
+bool TreeControlPeer::loadImage( const OUString& rURL, Image& rImage )
+{
+ if( !mxGraphicProvider.is() )
+ {
+ mxGraphicProvider = graphic::GraphicProvider::create(
+ comphelper::getProcessComponentContext());
+ }
+
+ try
+ {
+ css::beans::PropertyValues aProps( 1 );
+ aProps[0].Name = "URL";
+ aProps[0].Value <<= rURL;
+
+ Reference< XGraphic > xGraphic( mxGraphicProvider->queryGraphic( aProps ) );
+
+ Graphic aGraphic( xGraphic );
+ rImage = Image(aGraphic.GetBitmapEx());
+ return true;
+ }
+ catch( Exception& )
+ {
+ }
+
+ return false;
+}
+
+
+
+
+UnoTreeListBoxImpl::UnoTreeListBoxImpl( TreeControlPeer* pPeer, vcl::Window* pParent, WinBits nWinStyle )
+: SvTreeListBox( pParent, nWinStyle )
+, mxPeer( pPeer )
+{
+ SetStyle( WB_BORDER | WB_HASLINES |WB_HASBUTTONS | WB_HASLINESATROOT | WB_HASBUTTONSATROOT | WB_HSCROLL );
+ SetNodeDefaultImages();
+ SetSelectHdl( LINK(this, UnoTreeListBoxImpl, OnSelectionChangeHdl) );
+ SetDeselectHdl( LINK(this, UnoTreeListBoxImpl, OnSelectionChangeHdl) );
+
+ SetExpandingHdl( LINK(this, UnoTreeListBoxImpl, OnExpandingHdl) );
+ SetExpandedHdl( LINK(this, UnoTreeListBoxImpl, OnExpandedHdl) );
+
+}
+
+
+UnoTreeListBoxImpl::~UnoTreeListBoxImpl()
+{
+ disposeOnce();
+}
+
+void UnoTreeListBoxImpl::dispose()
+{
+ if( mxPeer.is() )
+ mxPeer->disposeControl();
+ mxPeer.clear();
+ SvTreeListBox::dispose();
+}
+
+
+IMPL_LINK_NOARG(UnoTreeListBoxImpl, OnSelectionChangeHdl, SvTreeListBox*, void)
+{
+ if( mxPeer.is() )
+ mxPeer->onSelectionChanged();
+}
+
+
+IMPL_LINK_NOARG(UnoTreeListBoxImpl, OnExpandingHdl, SvTreeListBox*, bool)
+{
+ UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( GetHdlEntry() );
+
+ if( pEntry && mxPeer.is() )
+ {
+ return mxPeer->onExpanding( pEntry->mxNode, !IsExpanded( pEntry ) );
+ }
+ return false;
+}
+
+
+IMPL_LINK_NOARG(UnoTreeListBoxImpl, OnExpandedHdl, SvTreeListBox*, void)
+{
+ UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( GetHdlEntry() );
+ if( pEntry && mxPeer.is() )
+ {
+ mxPeer->onExpanded( pEntry->mxNode, IsExpanded( pEntry ) );
+ }
+}
+
+
+void UnoTreeListBoxImpl::insert( SvTreeListEntry* pEntry,SvTreeListEntry* pParent,sal_uLong nPos )
+{
+ if( pParent )
+ SvTreeListBox::Insert( pEntry, pParent, nPos );
+ else
+ SvTreeListBox::Insert( pEntry, nPos );
+}
+
+
+void UnoTreeListBoxImpl::RequestingChildren( SvTreeListEntry* pParent )
+{
+ UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( pParent );
+ if( pEntry && pEntry->mxNode.is() && mxPeer.is() )
+ mxPeer->onRequestChildNodes( pEntry->mxNode );
+}
+
+
+bool UnoTreeListBoxImpl::EditingEntry( SvTreeListEntry* pEntry, Selection& )
+{
+ return mxPeer.is() && mxPeer->onEditingEntry( dynamic_cast< UnoTreeListEntry* >( pEntry ) );
+}
+
+
+bool UnoTreeListBoxImpl::EditedEntry( SvTreeListEntry* pEntry, const OUString& rNewText )
+{
+ return mxPeer.is() && mxPeer->onEditedEntry( dynamic_cast< UnoTreeListEntry* >( pEntry ), rNewText );
+}
+
+
+
+
+UnoTreeListItem::UnoTreeListItem()
+: SvLBoxString(OUString())
+{
+}
+
+void UnoTreeListItem::Paint(
+ const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext, const SvViewDataEntry* /*pView*/, const SvTreeListEntry& rEntry)
+{
+ Point aPos(rPos);
+ Size aSize(GetWidth(&rDev, &rEntry), GetHeight(&rDev, &rEntry));
+ if (!!maImage)
+ {
+ rRenderContext.DrawImage(aPos, maImage, rDev.IsEnabled() ? DrawImageFlags::NONE : DrawImageFlags::Disable);
+ int nWidth = maImage.GetSizePixel().Width() + 6;
+ aPos.AdjustX(nWidth );
+ aSize.AdjustWidth( -nWidth );
+ }
+ rRenderContext.DrawText(tools::Rectangle(aPos,aSize),maText, rDev.IsEnabled() ? DrawTextFlags::NONE : DrawTextFlags::Disable);
+}
+
+
+std::unique_ptr<SvLBoxItem> UnoTreeListItem::Clone(SvLBoxItem const * pSource) const
+{
+ std::unique_ptr<UnoTreeListItem> pNew(new UnoTreeListItem);
+ UnoTreeListItem const * pSourceItem = static_cast< UnoTreeListItem const * >( pSource );
+ pNew->maText = pSourceItem->maText;
+ pNew->maImage = pSourceItem->maImage;
+ return std::unique_ptr<SvLBoxItem>(pNew.release());
+}
+
+
+void UnoTreeListItem::SetImage( const Image& rImage )
+{
+ maImage = rImage;
+}
+
+
+void UnoTreeListItem::SetGraphicURL( const OUString& rGraphicURL )
+{
+ maGraphicURL = rGraphicURL;
+}
+
+
+void UnoTreeListItem::InitViewData( SvTreeListBox* pView,SvTreeListEntry* pEntry, SvViewDataItem* pViewData)
+{
+ if( !pViewData )
+ pViewData = pView->GetViewDataItem( pEntry, this );
+
+ Size aSize(maImage.GetSizePixel());
+ pViewData->mnWidth = aSize.Width();
+ pViewData->mnHeight = aSize.Height();
+
+ const Size aTextSize(pView->GetTextWidth( maText ), pView->GetTextHeight());
+ if( pViewData->mnWidth )
+ {
+ pViewData->mnWidth += (6 + aTextSize.Width());
+ if( pViewData->mnHeight < aTextSize.Height() )
+ pViewData->mnHeight = aTextSize.Height();
+ }
+ else
+ {
+ pViewData->mnWidth = aTextSize.Width();
+ pViewData->mnHeight = aTextSize.Height();
+ }
+}
+
+
+UnoTreeListEntry::UnoTreeListEntry( const Reference< XTreeNode >& xNode, TreeControlPeer* pPeer )
+: SvTreeListEntry()
+, mxNode( xNode )
+, mpPeer( pPeer )
+{
+ if( mpPeer )
+ mpPeer->addEntry( this );
+}
+
+
+UnoTreeListEntry::~UnoTreeListEntry()
+{
+ if( mpPeer )
+ mpPeer->removeEntry( this );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */