summaryrefslogtreecommitdiffstats
path: root/toolkit/source/controls/tree
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/source/controls/tree')
-rw-r--r--toolkit/source/controls/tree/treecontrol.cxx514
-rw-r--r--toolkit/source/controls/tree/treecontrol.hxx65
-rw-r--r--toolkit/source/controls/tree/treecontrolpeer.cxx1579
-rw-r--r--toolkit/source/controls/tree/treedatamodel.cxx523
4 files changed, 2681 insertions, 0 deletions
diff --git a/toolkit/source/controls/tree/treecontrol.cxx b/toolkit/source/controls/tree/treecontrol.cxx
new file mode 100644
index 000000000..d4439a4ff
--- /dev/null
+++ b/toolkit/source/controls/tree/treecontrol.cxx
@@ -0,0 +1,514 @@
+/* -*- 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 "treecontrol.hxx"
+
+#include <com/sun/star/awt/tree/XTreeControl.hpp>
+#include <com/sun/star/awt/tree/XTreeDataModel.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/view/SelectionType.hpp>
+#include <toolkit/controls/unocontrolbase.hxx>
+#include <toolkit/helper/property.hxx>
+#include <osl/diagnose.h>
+#include <cppuhelper/implbase.hxx>
+
+#include <helper/unopropertyarrayhelper.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::awt::tree;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::view;
+
+namespace toolkit
+{
+
+
+UnoTreeModel::UnoTreeModel( const css::uno::Reference< css::uno::XComponentContext >& i_factory )
+ :UnoControlModel( i_factory )
+{
+ ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR );
+ ImplRegisterProperty( BASEPROPERTY_BORDER );
+ ImplRegisterProperty( BASEPROPERTY_BORDERCOLOR );
+ ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL );
+ ImplRegisterProperty( BASEPROPERTY_ENABLED );
+ ImplRegisterProperty( BASEPROPERTY_ENABLEVISIBLE );
+ ImplRegisterProperty( BASEPROPERTY_FILLCOLOR );
+ ImplRegisterProperty( BASEPROPERTY_HELPTEXT );
+ ImplRegisterProperty( BASEPROPERTY_HELPURL );
+ ImplRegisterProperty( BASEPROPERTY_PRINTABLE );
+ ImplRegisterProperty( BASEPROPERTY_TABSTOP );
+ ImplRegisterProperty( BASEPROPERTY_TREE_SELECTIONTYPE );
+ ImplRegisterProperty( BASEPROPERTY_TREE_EDITABLE );
+ ImplRegisterProperty( BASEPROPERTY_TREE_DATAMODEL );
+ ImplRegisterProperty( BASEPROPERTY_TREE_ROOTDISPLAYED );
+ ImplRegisterProperty( BASEPROPERTY_TREE_SHOWSHANDLES );
+ ImplRegisterProperty( BASEPROPERTY_TREE_SHOWSROOTHANDLES );
+ ImplRegisterProperty( BASEPROPERTY_ROW_HEIGHT );
+ ImplRegisterProperty( BASEPROPERTY_TREE_INVOKESSTOPNODEEDITING );
+ ImplRegisterProperty( BASEPROPERTY_HIDEINACTIVESELECTION );
+}
+
+rtl::Reference<UnoControlModel> UnoTreeModel::Clone() const
+{
+ return new UnoTreeModel( *this );
+}
+
+OUString UnoTreeModel::getServiceName()
+{
+ return "com.sun.star.awt.tree.TreeControlModel";
+}
+
+Any UnoTreeModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const
+{
+ switch( nPropId )
+ {
+ case BASEPROPERTY_TREE_SELECTIONTYPE:
+ return Any( SelectionType_NONE );
+ case BASEPROPERTY_ROW_HEIGHT:
+ return Any( sal_Int32( 0 ) );
+ case BASEPROPERTY_TREE_DATAMODEL:
+ return Any( Reference< XTreeDataModel >( nullptr ) );
+ case BASEPROPERTY_TREE_EDITABLE:
+ case BASEPROPERTY_TREE_INVOKESSTOPNODEEDITING:
+ return Any( false );
+ case BASEPROPERTY_TREE_ROOTDISPLAYED:
+ case BASEPROPERTY_TREE_SHOWSROOTHANDLES:
+ case BASEPROPERTY_TREE_SHOWSHANDLES:
+ return Any( true );
+ case BASEPROPERTY_DEFAULTCONTROL:
+ return uno::Any( OUString( "com.sun.star.awt.tree.TreeControl" ) );
+ default:
+ return UnoControlModel::ImplGetDefaultValue( nPropId );
+ }
+}
+
+::cppu::IPropertyArrayHelper& UnoTreeModel::getInfoHelper()
+{
+ static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() );
+ return aHelper;
+}
+
+// XMultiPropertySet
+Reference< XPropertySetInfo > UnoTreeModel::getPropertySetInfo( )
+{
+ static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+
+}
+
+namespace {
+
+typedef ::cppu::ImplInheritanceHelper< UnoControlBase, css::awt::tree::XTreeControl > UnoTreeControl_Base;
+class UnoTreeControl : public UnoTreeControl_Base
+{
+public:
+ UnoTreeControl();
+ OUString GetComponentServiceName() const override;
+
+ // css::lang::XComponent
+ void SAL_CALL dispose( ) override;
+
+ // css::awt::XControl
+ void SAL_CALL createPeer( const css::uno::Reference< css::awt::XToolkit >& Toolkit, const css::uno::Reference< css::awt::XWindowPeer >& Parent ) override;
+
+ // 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::lang::XServiceInfo
+ DECLIMPL_SERVICEINFO_DERIVED( UnoTreeControl, UnoControlBase, "com.sun.star.awt.tree.TreeControl" )
+
+ using UnoControl::getPeer;
+private:
+ TreeSelectionListenerMultiplexer maSelectionListeners;
+ TreeExpansionListenerMultiplexer maTreeExpansionListeners;
+ TreeEditListenerMultiplexer maTreeEditListeners;
+};
+
+UnoTreeControl::UnoTreeControl()
+: maSelectionListeners( *this )
+, maTreeExpansionListeners( *this )
+, maTreeEditListeners( *this )
+{
+}
+
+OUString UnoTreeControl::GetComponentServiceName() const
+{
+ return "Tree";
+}
+
+
+// css::view::XSelectionSupplier
+
+
+sal_Bool SAL_CALL UnoTreeControl::select( const Any& rSelection )
+{
+ return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->select( rSelection );
+}
+
+
+Any SAL_CALL UnoTreeControl::getSelection()
+{
+ return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->getSelection();
+}
+
+
+void SAL_CALL UnoTreeControl::addSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener )
+{
+ maSelectionListeners.addInterface( xListener );
+ if( getPeer().is() && (maSelectionListeners.getLength() == 1) )
+ {
+ // maSelectionListeners acts as a proxy,
+ // add it to the peer if this is the first listener added to that proxy
+ Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->addSelectionChangeListener(&maSelectionListeners);
+ }
+}
+
+
+void SAL_CALL UnoTreeControl::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener )
+{
+ if( getPeer().is() && (maSelectionListeners.getLength() == 1) )
+ {
+ // maSelectionListeners acts as a proxy,
+ // remove it from the peer if this is the last listener removed from that proxy
+ Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->removeSelectionChangeListener(&maSelectionListeners);
+ }
+ maSelectionListeners.removeInterface( xListener );
+}
+
+
+// css::view::XMultiSelectionSupplier
+
+
+sal_Bool SAL_CALL UnoTreeControl::addSelection( const Any& rSelection )
+{
+ return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->addSelection(rSelection);
+}
+
+
+void SAL_CALL UnoTreeControl::removeSelection( const Any& rSelection )
+{
+ Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->removeSelection(rSelection);
+}
+
+
+void SAL_CALL UnoTreeControl::clearSelection()
+{
+ Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->clearSelection();
+}
+
+
+sal_Int32 SAL_CALL UnoTreeControl::getSelectionCount()
+{
+ return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->getSelectionCount();
+}
+
+
+Reference< XEnumeration > SAL_CALL UnoTreeControl::createSelectionEnumeration()
+{
+ return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->createSelectionEnumeration();
+}
+
+
+Reference< XEnumeration > SAL_CALL UnoTreeControl::createReverseSelectionEnumeration()
+{
+ return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->createReverseSelectionEnumeration();
+}
+
+
+// XTreeControl
+
+
+OUString SAL_CALL UnoTreeControl::getDefaultExpandedGraphicURL()
+{
+ return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->getDefaultExpandedGraphicURL();
+}
+
+
+void SAL_CALL UnoTreeControl::setDefaultExpandedGraphicURL( const OUString& _defaultexpansiongraphicurl )
+{
+ Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->setDefaultExpandedGraphicURL(_defaultexpansiongraphicurl);
+}
+
+
+OUString SAL_CALL UnoTreeControl::getDefaultCollapsedGraphicURL()
+{
+ return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->getDefaultCollapsedGraphicURL();
+}
+
+
+void SAL_CALL UnoTreeControl::setDefaultCollapsedGraphicURL( const OUString& _defaultcollapsedgraphicurl )
+{
+ Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->setDefaultCollapsedGraphicURL(_defaultcollapsedgraphicurl);
+}
+
+
+sal_Bool SAL_CALL UnoTreeControl::isNodeExpanded( const Reference< XTreeNode >& xNode )
+{
+ return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->isNodeExpanded(xNode);
+}
+
+
+sal_Bool SAL_CALL UnoTreeControl::isNodeCollapsed( const Reference< XTreeNode >& xNode )
+{
+ return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->isNodeCollapsed(xNode);
+}
+
+
+void SAL_CALL UnoTreeControl::makeNodeVisible( const Reference< XTreeNode >& xNode )
+{
+ Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->makeNodeVisible(xNode);
+}
+
+
+sal_Bool SAL_CALL UnoTreeControl::isNodeVisible( const Reference< XTreeNode >& xNode )
+{
+ return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->isNodeVisible(xNode);
+}
+
+
+void SAL_CALL UnoTreeControl::expandNode( const Reference< XTreeNode >& xNode )
+{
+ Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->expandNode(xNode);
+}
+
+
+void SAL_CALL UnoTreeControl::collapseNode( const Reference< XTreeNode >& xNode )
+{
+ Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->collapseNode(xNode);
+}
+
+
+void SAL_CALL UnoTreeControl::addTreeExpansionListener( const Reference< XTreeExpansionListener >& xListener )
+{
+ maTreeExpansionListeners.addInterface( xListener );
+ if( getPeer().is() && (maTreeExpansionListeners.getLength() == 1) )
+ {
+ // maSelectionListeners acts as a proxy,
+ // add it to the peer if this is the first listener added to that proxy
+ Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->addTreeExpansionListener(&maTreeExpansionListeners);
+ }
+}
+
+
+void SAL_CALL UnoTreeControl::removeTreeExpansionListener( const Reference< XTreeExpansionListener >& xListener )
+{
+ if( getPeer().is() && (maTreeExpansionListeners.getLength() == 1) )
+ {
+ // maSelectionListeners acts as a proxy,
+ // remove it from the peer if this is the last listener removed from that proxy
+ Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->removeTreeExpansionListener(&maTreeExpansionListeners);
+ }
+ maTreeExpansionListeners.removeInterface( xListener );
+}
+
+
+Reference< XTreeNode > SAL_CALL UnoTreeControl::getNodeForLocation( sal_Int32 x, sal_Int32 y )
+{
+ return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->getNodeForLocation(x,y);
+}
+
+
+Reference< XTreeNode > SAL_CALL UnoTreeControl::getClosestNodeForLocation( sal_Int32 x, sal_Int32 y )
+{
+ return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->getClosestNodeForLocation(x,y);
+}
+
+
+awt::Rectangle SAL_CALL UnoTreeControl::getNodeRect( const Reference< XTreeNode >& Node )
+{
+ return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->getNodeRect( Node );
+}
+
+
+sal_Bool SAL_CALL UnoTreeControl::isEditing( )
+{
+ return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->isEditing();
+}
+
+
+sal_Bool SAL_CALL UnoTreeControl::stopEditing()
+{
+ return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->stopEditing();
+}
+
+
+void SAL_CALL UnoTreeControl::cancelEditing()
+{
+ Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->cancelEditing();
+}
+
+
+void SAL_CALL UnoTreeControl::startEditingAtNode( const Reference< XTreeNode >& xNode )
+{
+ Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->startEditingAtNode(xNode);
+}
+
+
+void SAL_CALL UnoTreeControl::addTreeEditListener( const Reference< XTreeEditListener >& xListener )
+{
+ maTreeEditListeners.addInterface( xListener );
+ if( getPeer().is() && (maTreeEditListeners.getLength() == 1) )
+ {
+ // maSelectionListeners acts as a proxy,
+ // add it to the peer if this is the first listener added to that proxy
+ Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->addTreeEditListener(&maTreeEditListeners);
+ }
+}
+
+
+void SAL_CALL UnoTreeControl::removeTreeEditListener( const Reference< XTreeEditListener >& xListener )
+{
+ if( getPeer().is() && (maTreeEditListeners.getLength() == 1) )
+ {
+ // maSelectionListeners acts as a proxy,
+ // remove it from the peer if this is the last listener removed from that proxy
+ Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->removeTreeEditListener(&maTreeEditListeners);
+ }
+ maTreeEditListeners.removeInterface( xListener );
+}
+
+
+// XComponent
+
+
+void SAL_CALL UnoTreeControl::dispose( )
+{
+ lang::EventObject aEvt;
+ aEvt.Source = static_cast< ::cppu::OWeakObject* >(this);
+ maSelectionListeners.disposeAndClear( aEvt );
+ maTreeExpansionListeners.disposeAndClear( aEvt );
+ UnoControl::dispose();
+}
+
+void UnoTreeControl::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer )
+{
+ UnoControlBase::createPeer( rxToolkit, rParentPeer );
+
+ Reference< XTreeControl > xTree( getPeer(), UNO_QUERY_THROW );
+ if( maSelectionListeners.getLength() )
+ xTree->addSelectionChangeListener( &maSelectionListeners );
+ if( maTreeExpansionListeners.getLength() )
+ xTree->addTreeExpansionListener( &maTreeExpansionListeners );
+}
+
+}
+
+void SAL_CALL TreeEditListenerMultiplexer::nodeEditing( const Reference< XTreeNode >& Node )
+{
+ ::comphelper::OInterfaceIteratorHelper3 aIt(*this);
+ while( aIt.hasMoreElements() )
+ {
+ Reference<XTreeEditListener> xListener(aIt.next());
+ try
+ {
+ xListener->nodeEditing( Node );
+ }
+ catch( const DisposedException& e )
+ {
+ OSL_ENSURE( e.Context.is(), "caught DisposedException with empty Context field" );
+ if ( e.Context == xListener || !e.Context.is() )
+ aIt.remove();
+ }
+ catch( const RuntimeException& )
+ {
+ DISPLAY_EXCEPTION( TreeEditListenerMultiplexer, nodeEditing )
+ }
+ }
+}
+
+void SAL_CALL TreeEditListenerMultiplexer::nodeEdited( const Reference< XTreeNode >& Node, const OUString& NewText )
+{
+ ::comphelper::OInterfaceIteratorHelper3 aIt(*this);
+ while( aIt.hasMoreElements() )
+ {
+ Reference<XTreeEditListener> xListener(aIt.next());
+ try
+ {
+ xListener->nodeEdited( Node, NewText );
+ }
+ catch( const DisposedException& e )
+ {
+ OSL_ENSURE( e.Context.is(), "caught DisposedException with empty Context field" );
+ if ( e.Context == xListener || !e.Context.is() )
+ aIt.remove();
+ }
+ catch( const RuntimeException& )
+ {
+ DISPLAY_EXCEPTION( TreeEditListenerMultiplexer, nodeEdited )
+ }
+ }
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+stardiv_Toolkit_TreeControlModel_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new toolkit::UnoTreeModel(context));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+stardiv_Toolkit_TreeControl_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new UnoTreeControl());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/toolkit/source/controls/tree/treecontrol.hxx b/toolkit/source/controls/tree/treecontrol.hxx
new file mode 100644
index 000000000..af4793fe9
--- /dev/null
+++ b/toolkit/source/controls/tree/treecontrol.hxx
@@ -0,0 +1,65 @@
+/* -*- 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 .
+ */
+
+#ifndef INCLUDED_TOOLKIT_SOURCE_CONTROLS_TREE_TREECONTROL_HXX
+#define INCLUDED_TOOLKIT_SOURCE_CONTROLS_TREE_TREECONTROL_HXX
+
+#include <toolkit/controls/unocontrolmodel.hxx>
+
+namespace toolkit
+{
+// = UnoTreeModel
+
+class UnoTreeModel : public UnoControlModel
+{
+protected:
+ css::uno::Any ImplGetDefaultValue(sal_uInt16 nPropId) const override;
+ ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+public:
+ explicit UnoTreeModel(const css::uno::Reference<css::uno::XComponentContext>& i_factory);
+
+ rtl::Reference<UnoControlModel> Clone() const override;
+
+ // css::beans::XMultiPropertySet
+ css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+
+ // css::io::XPersistObject
+ OUString SAL_CALL getServiceName() override;
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override
+ {
+ return "stardiv.Toolkit.TreeControlModel";
+ }
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
+ {
+ auto s(UnoControlModel::getSupportedServiceNames());
+ s.realloc(s.getLength() + 1);
+ s.getArray()[s.getLength() - 1] = "com.sun.star.awt.tree.TreeControlModel";
+ return s;
+ }
+};
+
+} // toolkit
+
+#endif // _ INCLUDED_TOOLKIT_SOURCE_CONTROLS_TREE_TREECONTROL_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/toolkit/source/controls/tree/treecontrolpeer.cxx b/toolkit/source/controls/tree/treecontrolpeer.cxx
new file mode 100644
index 000000000..fe273e0f6
--- /dev/null
+++ b/toolkit/source/controls/tree/treecontrolpeer.cxx
@@ -0,0 +1,1579 @@
+/* -*- 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 <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 <comphelper/propertyvalue.hxx>
+
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/toolkit/treelistbox.hxx>
+#include <vcl/toolkit/treelistentry.hxx>
+#include <vcl/toolkit/viewdataentry.hxx>
+#include <vcl/toolkit/svlbitm.hxx>
+
+#include <map>
+#include <memory>
+#include <list>
+
+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 ) 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{ comphelper::makePropertyValue("URL", 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 )
+{
+ 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 )
+: mxNode( xNode )
+, mpPeer( pPeer )
+{
+ if( mpPeer )
+ mpPeer->addEntry( this );
+}
+
+
+UnoTreeListEntry::~UnoTreeListEntry()
+{
+ if( mpPeer )
+ mpPeer->removeEntry( this );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/toolkit/source/controls/tree/treedatamodel.cxx b/toolkit/source/controls/tree/treedatamodel.cxx
new file mode 100644
index 000000000..df8056057
--- /dev/null
+++ b/toolkit/source/controls/tree/treedatamodel.cxx
@@ -0,0 +1,523 @@
+/* -*- 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 <com/sun/star/awt/tree/XMutableTreeDataModel.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/implbase2.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <o3tl/safeint.hxx>
+#include <rtl/ref.hxx>
+#include <toolkit/helper/mutexandbroadcasthelper.hxx>
+#include <mutex>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::awt::tree;
+using namespace ::com::sun::star::lang;
+
+namespace {
+
+ enum broadcast_type { nodes_changed, nodes_inserted, nodes_removed, structure_changed };
+
+class MutableTreeNode;
+class MutableTreeDataModel;
+
+typedef std::vector< rtl::Reference< MutableTreeNode > > TreeNodeVector;
+
+class MutableTreeDataModel : public ::cppu::WeakAggImplHelper2< XMutableTreeDataModel, XServiceInfo >,
+ public MutexAndBroadcastHelper
+{
+public:
+ MutableTreeDataModel();
+
+ void broadcast( broadcast_type eType, const Reference< XTreeNode >& xParentNode, const Reference< XTreeNode >& rNode );
+
+ // XMutableTreeDataModel
+ virtual css::uno::Reference< css::awt::tree::XMutableTreeNode > SAL_CALL createNode( const css::uno::Any& DisplayValue, sal_Bool ChildrenOnDemand ) override;
+ virtual void SAL_CALL setRoot( const css::uno::Reference< css::awt::tree::XMutableTreeNode >& RootNode ) override;
+
+ // XTreeDataModel
+ virtual css::uno::Reference< css::awt::tree::XTreeNode > SAL_CALL getRoot( ) override;
+ virtual void SAL_CALL addTreeDataModelListener( const css::uno::Reference< css::awt::tree::XTreeDataModelListener >& Listener ) override;
+ virtual void SAL_CALL removeTreeDataModelListener( const css::uno::Reference< css::awt::tree::XTreeDataModelListener >& Listener ) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) override;
+ virtual void SAL_CALL addEventListener( const Reference< XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const Reference< XEventListener >& aListener ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+private:
+ bool mbDisposed;
+ Reference< XTreeNode > mxRootNode;
+};
+
+class MutableTreeNode: public ::cppu::WeakAggImplHelper2< XMutableTreeNode, XServiceInfo >
+{
+ friend class MutableTreeDataModel;
+
+public:
+ MutableTreeNode( const rtl::Reference< MutableTreeDataModel >& xModel, const Any& rValue, bool bChildrenOnDemand );
+ virtual ~MutableTreeNode() override;
+
+ void setParent( MutableTreeNode* pParent );
+ void broadcast_changes();
+ void broadcast_changes(std::unique_lock<std::mutex> & rLock,
+ const Reference< XTreeNode >& xNode, bool bNew);
+
+ // XMutableTreeNode
+ virtual css::uno::Any SAL_CALL getDataValue() override;
+ virtual void SAL_CALL setDataValue( const css::uno::Any& _datavalue ) override;
+ virtual void SAL_CALL appendChild( const css::uno::Reference< css::awt::tree::XMutableTreeNode >& ChildNode ) override;
+ virtual void SAL_CALL insertChildByIndex( ::sal_Int32 Index, const css::uno::Reference< css::awt::tree::XMutableTreeNode >& ChildNode ) override;
+ virtual void SAL_CALL removeChildByIndex( ::sal_Int32 Index ) override;
+ virtual void SAL_CALL setHasChildrenOnDemand( sal_Bool ChildrenOnDemand ) override;
+ virtual void SAL_CALL setDisplayValue( const css::uno::Any& Value ) override;
+ virtual void SAL_CALL setNodeGraphicURL( const OUString& URL ) override;
+ virtual void SAL_CALL setExpandedGraphicURL( const OUString& URL ) override;
+ virtual void SAL_CALL setCollapsedGraphicURL( const OUString& URL ) override;
+
+ // XTreeNode
+ virtual css::uno::Reference< css::awt::tree::XTreeNode > SAL_CALL getChildAt( ::sal_Int32 Index ) override;
+ virtual ::sal_Int32 SAL_CALL getChildCount( ) override;
+ virtual css::uno::Reference< css::awt::tree::XTreeNode > SAL_CALL getParent( ) override;
+ virtual ::sal_Int32 SAL_CALL getIndex( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override;
+ virtual sal_Bool SAL_CALL hasChildrenOnDemand( ) override;
+ virtual css::uno::Any SAL_CALL getDisplayValue( ) override;
+ virtual OUString SAL_CALL getNodeGraphicURL( ) override;
+ virtual OUString SAL_CALL getExpandedGraphicURL( ) override;
+ virtual OUString SAL_CALL getCollapsedGraphicURL( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+private:
+ TreeNodeVector maChildren;
+ Any maDisplayValue;
+ Any maDataValue;
+ bool mbHasChildrenOnDemand;
+ std::mutex maMutex;
+ MutableTreeNode* mpParent;
+ rtl::Reference< MutableTreeDataModel > mxModel;
+ OUString maNodeGraphicURL;
+ OUString maExpandedGraphicURL;
+ OUString maCollapsedGraphicURL;
+ bool mbIsInserted;
+};
+
+MutableTreeDataModel::MutableTreeDataModel()
+: mbDisposed( false )
+{
+}
+
+void MutableTreeDataModel::broadcast( broadcast_type eType, const Reference< XTreeNode >& xParentNode, const Reference< XTreeNode >& rNode )
+{
+ ::cppu::OInterfaceContainerHelper* pIter = BrdcstHelper.getContainer( cppu::UnoType<XTreeDataModelListener>::get() );
+ if( !pIter )
+ return;
+
+ Reference< XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) );
+ const Sequence< Reference< XTreeNode > > aNodes { rNode };
+ TreeDataModelEvent aEvent( xSource, aNodes, xParentNode );
+
+ ::cppu::OInterfaceIteratorHelper aListIter(*pIter);
+ while(aListIter.hasMoreElements())
+ {
+ XTreeDataModelListener* pListener = static_cast<XTreeDataModelListener*>(aListIter.next());
+ switch( eType )
+ {
+ case nodes_changed: pListener->treeNodesChanged(aEvent); break;
+ case nodes_inserted: pListener->treeNodesInserted(aEvent); break;
+ case nodes_removed: pListener->treeNodesRemoved(aEvent); break;
+ case structure_changed: pListener->treeStructureChanged(aEvent); break;
+ }
+ }
+}
+
+Reference< XMutableTreeNode > SAL_CALL MutableTreeDataModel::createNode( const Any& aValue, sal_Bool bChildrenOnDemand )
+{
+ return new MutableTreeNode( this, aValue, bChildrenOnDemand );
+}
+
+void SAL_CALL MutableTreeDataModel::setRoot( const Reference< XMutableTreeNode >& xNode )
+{
+ if( !xNode.is() )
+ throw IllegalArgumentException();
+
+ ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
+ if( xNode == mxRootNode )
+ return;
+
+ if( mxRootNode.is() )
+ {
+ rtl::Reference< MutableTreeNode > xOldImpl( dynamic_cast< MutableTreeNode* >( mxRootNode.get() ) );
+ if( xOldImpl.is() )
+ xOldImpl->mbIsInserted = false;
+ }
+
+ rtl::Reference< MutableTreeNode > xImpl( dynamic_cast< MutableTreeNode* >( xNode.get() ) );
+ if( !xImpl.is() || xImpl->mbIsInserted )
+ throw IllegalArgumentException();
+
+ xImpl->mbIsInserted = true;
+ mxRootNode = xImpl;
+
+ Reference< XTreeNode > xParentNode;
+ broadcast( structure_changed, xParentNode, mxRootNode );
+}
+
+Reference< XTreeNode > SAL_CALL MutableTreeDataModel::getRoot( )
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
+ return mxRootNode;
+}
+
+void SAL_CALL MutableTreeDataModel::addTreeDataModelListener( const Reference< XTreeDataModelListener >& xListener )
+{
+ BrdcstHelper.addListener( cppu::UnoType<XTreeDataModelListener>::get(), xListener );
+}
+
+void SAL_CALL MutableTreeDataModel::removeTreeDataModelListener( const Reference< XTreeDataModelListener >& xListener )
+{
+ BrdcstHelper.removeListener( cppu::UnoType<XTreeDataModelListener>::get(), xListener );
+}
+
+void SAL_CALL MutableTreeDataModel::dispose()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
+
+ if( !mbDisposed )
+ {
+ mbDisposed = true;
+ css::lang::EventObject aEvent;
+ aEvent.Source.set( static_cast< ::cppu::OWeakObject* >( this ) );
+ BrdcstHelper.aLC.disposeAndClear( aEvent );
+ }
+}
+
+void SAL_CALL MutableTreeDataModel::addEventListener( const Reference< XEventListener >& xListener )
+{
+ BrdcstHelper.addListener( cppu::UnoType<XEventListener>::get(), xListener );
+}
+
+void SAL_CALL MutableTreeDataModel::removeEventListener( const Reference< XEventListener >& xListener )
+{
+ BrdcstHelper.removeListener( cppu::UnoType<XEventListener>::get(), xListener );
+}
+
+OUString SAL_CALL MutableTreeDataModel::getImplementationName( )
+{
+ return "toolkit.MutableTreeDataModel";
+}
+
+sal_Bool SAL_CALL MutableTreeDataModel::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > SAL_CALL MutableTreeDataModel::getSupportedServiceNames( )
+{
+ Sequence<OUString> aSeq { "com.sun.star.awt.tree.MutableTreeDataModel" };
+ return aSeq;
+}
+
+MutableTreeNode::MutableTreeNode( const rtl::Reference< MutableTreeDataModel >& xModel, const Any& rValue, bool bChildrenOnDemand )
+: maDisplayValue( rValue )
+, mbHasChildrenOnDemand( bChildrenOnDemand )
+, mpParent( nullptr )
+, mxModel( xModel )
+, mbIsInserted( false )
+{
+}
+
+MutableTreeNode::~MutableTreeNode()
+{
+ for( auto& rChild : maChildren )
+ rChild->setParent(nullptr);
+}
+
+void MutableTreeNode::setParent( MutableTreeNode* pParent )
+{
+ mpParent = pParent;
+}
+
+void MutableTreeNode::broadcast_changes()
+{
+ if( mxModel.is() )
+ {
+ mxModel->broadcast( nodes_changed, mpParent, this );
+ }
+}
+
+void MutableTreeNode::broadcast_changes(std::unique_lock<std::mutex> & rLock,
+ const Reference< XTreeNode >& xNode, bool const bNew)
+{
+ auto const xModel(mxModel);
+ rLock.unlock();
+ if (xModel.is())
+ {
+ xModel->broadcast(bNew ? nodes_inserted : nodes_removed, this, xNode);
+ }
+}
+
+Any SAL_CALL MutableTreeNode::getDataValue()
+{
+ std::scoped_lock aGuard( maMutex );
+ return maDataValue;
+}
+
+void SAL_CALL MutableTreeNode::setDataValue( const Any& _datavalue )
+{
+ std::scoped_lock aGuard( maMutex );
+ maDataValue = _datavalue;
+}
+
+void SAL_CALL MutableTreeNode::appendChild( const Reference< XMutableTreeNode >& xChildNode )
+{
+ std::unique_lock aGuard( maMutex );
+ rtl::Reference< MutableTreeNode > xImpl( dynamic_cast< MutableTreeNode* >( xChildNode.get() ) );
+
+ if( !xImpl.is() || xImpl->mbIsInserted || (this == xImpl.get()) )
+ throw IllegalArgumentException();
+
+ maChildren.push_back( xImpl );
+ xImpl->setParent(this);
+ xImpl->mbIsInserted = true;
+
+ broadcast_changes(aGuard, xChildNode, true);
+}
+
+void SAL_CALL MutableTreeNode::insertChildByIndex( sal_Int32 nChildIndex, const Reference< XMutableTreeNode >& xChildNode )
+{
+ std::unique_lock aGuard( maMutex );
+
+ if( (nChildIndex < 0) || (o3tl::make_unsigned(nChildIndex) > maChildren.size()) )
+ throw IndexOutOfBoundsException();
+
+ rtl::Reference< MutableTreeNode > xImpl( dynamic_cast< MutableTreeNode* >( xChildNode.get() ) );
+ if( !xImpl.is() || xImpl->mbIsInserted || (this == xImpl.get()) )
+ throw IllegalArgumentException();
+
+ xImpl->mbIsInserted = true;
+
+ TreeNodeVector::iterator aIter( maChildren.begin() );
+ std::advance(aIter, nChildIndex);
+
+ maChildren.insert( aIter, xImpl );
+ xImpl->setParent( this );
+
+ broadcast_changes(aGuard, xChildNode, true);
+}
+
+void SAL_CALL MutableTreeNode::removeChildByIndex( sal_Int32 nChildIndex )
+{
+ std::unique_lock aGuard( maMutex );
+
+ if( (nChildIndex < 0) || (o3tl::make_unsigned(nChildIndex) >= maChildren.size()) )
+ throw IndexOutOfBoundsException();
+
+ rtl::Reference< MutableTreeNode > xImpl;
+
+ TreeNodeVector::iterator aIter( maChildren.begin() );
+ std::advance(aIter, nChildIndex);
+
+ xImpl = *aIter;
+ maChildren.erase( aIter );
+
+ if( !xImpl.is() )
+ throw IndexOutOfBoundsException();
+
+ xImpl->setParent(nullptr);
+ xImpl->mbIsInserted = false;
+
+ broadcast_changes(aGuard, xImpl, false);
+}
+
+void SAL_CALL MutableTreeNode::setHasChildrenOnDemand( sal_Bool bChildrenOnDemand )
+{
+ bool bChanged;
+
+ {
+ std::scoped_lock aGuard( maMutex );
+ bChanged = mbHasChildrenOnDemand != bool(bChildrenOnDemand);
+ mbHasChildrenOnDemand = bChildrenOnDemand;
+ }
+
+ if( bChanged )
+ broadcast_changes();
+}
+
+void SAL_CALL MutableTreeNode::setDisplayValue( const Any& aValue )
+{
+ {
+ std::scoped_lock aGuard( maMutex );
+ maDisplayValue = aValue;
+ }
+
+ broadcast_changes();
+}
+
+void SAL_CALL MutableTreeNode::setNodeGraphicURL( const OUString& rURL )
+{
+ bool bChanged;
+
+ {
+ std::scoped_lock aGuard( maMutex );
+ bChanged = maNodeGraphicURL != rURL;
+ maNodeGraphicURL = rURL;
+ }
+
+ if( bChanged )
+ broadcast_changes();
+}
+
+void SAL_CALL MutableTreeNode::setExpandedGraphicURL( const OUString& rURL )
+{
+ bool bChanged;
+
+ {
+ std::scoped_lock aGuard( maMutex );
+ bChanged = maExpandedGraphicURL != rURL;
+ maExpandedGraphicURL = rURL;
+ }
+
+ if( bChanged )
+ broadcast_changes();
+}
+
+void SAL_CALL MutableTreeNode::setCollapsedGraphicURL( const OUString& rURL )
+{
+ bool bChanged;
+
+ {
+ std::scoped_lock aGuard( maMutex );
+ bChanged = maCollapsedGraphicURL != rURL;
+ maCollapsedGraphicURL = rURL;
+ }
+
+ if( bChanged )
+ broadcast_changes();
+}
+
+Reference< XTreeNode > SAL_CALL MutableTreeNode::getChildAt( sal_Int32 nChildIndex )
+{
+ std::scoped_lock aGuard( maMutex );
+
+ if( (nChildIndex < 0) || (o3tl::make_unsigned(nChildIndex) >= maChildren.size()) )
+ throw IndexOutOfBoundsException();
+ return maChildren[nChildIndex];
+}
+
+sal_Int32 SAL_CALL MutableTreeNode::getChildCount( )
+{
+ std::scoped_lock aGuard( maMutex );
+ return static_cast<sal_Int32>(maChildren.size());
+}
+
+Reference< XTreeNode > SAL_CALL MutableTreeNode::getParent( )
+{
+ std::scoped_lock aGuard( maMutex );
+ return mpParent;
+}
+
+sal_Int32 SAL_CALL MutableTreeNode::getIndex( const Reference< XTreeNode >& xNode )
+{
+ std::scoped_lock aGuard( maMutex );
+
+ rtl::Reference< MutableTreeNode > xImpl( dynamic_cast< MutableTreeNode* >( xNode.get() ) );
+ if( xImpl.is() )
+ {
+ sal_Int32 nChildCount = maChildren.size();
+ while( nChildCount-- )
+ {
+ if( maChildren[nChildCount] == xImpl )
+ return nChildCount;
+ }
+ }
+
+ return -1;
+}
+
+sal_Bool SAL_CALL MutableTreeNode::hasChildrenOnDemand( )
+{
+ std::scoped_lock aGuard( maMutex );
+ return mbHasChildrenOnDemand;
+}
+
+Any SAL_CALL MutableTreeNode::getDisplayValue( )
+{
+ std::scoped_lock aGuard( maMutex );
+ return maDisplayValue;
+}
+
+OUString SAL_CALL MutableTreeNode::getNodeGraphicURL( )
+{
+ std::scoped_lock aGuard( maMutex );
+ return maNodeGraphicURL;
+}
+
+OUString SAL_CALL MutableTreeNode::getExpandedGraphicURL( )
+{
+ std::scoped_lock aGuard( maMutex );
+ return maExpandedGraphicURL;
+}
+
+OUString SAL_CALL MutableTreeNode::getCollapsedGraphicURL( )
+{
+ std::scoped_lock aGuard( maMutex );
+ return maCollapsedGraphicURL;
+}
+
+OUString SAL_CALL MutableTreeNode::getImplementationName( )
+{
+ return "toolkit.MutableTreeNode";
+}
+
+sal_Bool SAL_CALL MutableTreeNode::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > SAL_CALL MutableTreeNode::getSupportedServiceNames( )
+{
+ Sequence<OUString> aSeq { "com.sun.star.awt.tree.MutableTreeNode" };
+ return aSeq;
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+stardiv_Toolkit_MutableTreeDataModel_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new MutableTreeDataModel());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */