From 475d6c193f043d796825bdde3944f006491a1794 Mon Sep 17 00:00:00 2001 From: Caolán McNamara Date: Sun, 16 Feb 2020 16:00:45 +0000 Subject: move TreeControlPeer to toolkit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id5298615f0f3dad6e61955e23367c0345b33f2b6 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88813 Tested-by: Jenkins Reviewed-by: Caolán McNamara --- toolkit/Library_tk.mk | 1 + toolkit/inc/controls/treecontrolpeer.hxx | 170 +++ toolkit/source/awt/vclxtoolkit.cxx | 7 + toolkit/source/controls/tree/treecontrolpeer.cxx | 1581 ++++++++++++++++++++++ 4 files changed, 1759 insertions(+) create mode 100644 toolkit/inc/controls/treecontrolpeer.hxx create mode 100644 toolkit/source/controls/tree/treecontrolpeer.cxx (limited to 'toolkit') 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 +#include +#include + +#include +#include + +#include + +#include + +#include + +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, 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 mpTreeImpl; + sal_Int32 mnEditLock; + OUString msDefaultCollapsedGraphicURL; + OUString msDefaultExpandedGraphicURL; + Image maDefaultExpandedImage; + Image maDefaultCollapsedImage; + std::unique_ptr 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 #include +#include #include #include #include @@ -1808,6 +1809,12 @@ vcl::Window* VCLXToolkit::ImplCreateWindow( VCLXWindow** ppNewComp, pNewWindow = VclPtr::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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 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::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(aImage, aImage, true)); + + std::unique_ptr 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> 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>>( + 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(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(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 UnoTreeListItem::Clone(SvLBoxItem const * pSource) const +{ + std::unique_ptr pNew(new UnoTreeListItem); + UnoTreeListItem const * pSourceItem = static_cast< UnoTreeListItem const * >( pSource ); + pNew->maText = pSourceItem->maText; + pNew->maImage = pSourceItem->maImage; + return std::unique_ptr(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: */ -- cgit