/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svtools.hxx"

#define _SVTREEBX_CXX
#include <tools/debug.hxx>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/DisposedException.hpp>
#include <com/sun/star/view/SelectionType.hpp>
#include <toolkit/helper/property.hxx>
#include <toolkit/helper/vclunohelper.hxx>

#include <com/sun/star/awt/tree/XMutableTreeNode.hpp>
#include <treecontrolpeer.hxx>
#include <comphelper/processfactory.hxx>

#include <rtl/ref.hxx>
#include <vcl/graph.hxx>
#include <svtools/svtreebx.hxx>

#include <map>

using ::rtl::OUString;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::awt::tree;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::view;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::util;
using namespace ::com::sun::star::graphic;

#define O(x) OUString( RTL_CONSTASCII_USTRINGPARAM(x) )

struct LockGuard
{
public:
	LockGuard( sal_Int32& rLock )
	: mrLock( rLock )
	{
		rLock++;
	}

	~LockGuard()
	{
		mrLock--;
	}

	sal_Int32& mrLock;
};

// --------------------------------------------------------------------

class ImplGraphicItem : public SvLBoxBmp
{
public:
	ImplGraphicItem( SvLBoxEntry* pEntry, sal_uInt16 nFlags, Image& aImage ) : SvLBoxBmp( pEntry, nFlags, aImage ) {}

	OUString msGraphicURL;
};

// --------------------------------------------------------------------

class ImplContextGraphicItem : public SvLBoxContextBmp
{
public:
	ImplContextGraphicItem( SvLBoxEntry* pEntry,sal_uInt16 nFlags,Image& rI1,Image& rI2, sal_uInt16 nEntryFlagsBmp1)
		: SvLBoxContextBmp( pEntry, nFlags, rI1, rI2, nEntryFlagsBmp1 ) {}

	OUString msExpandedGraphicURL;
	OUString msCollapsedGraphicURL;
};

// --------------------------------------------------------------------

class UnoTreeListBoxImpl : public SvTreeListBox
{
public:
	UnoTreeListBoxImpl( TreeControlPeer* pPeer, Window* pParent, WinBits nWinStyle );
	~UnoTreeListBoxImpl();

	sal_uInt32 insert( SvLBoxEntry* pEntry,SvLBoxEntry* pParent,sal_uLong nPos=LIST_APPEND );

	virtual void	RequestingChilds( SvLBoxEntry* pParent );

	virtual sal_Bool	EditingEntry( SvLBoxEntry* pEntry, Selection& );
	virtual sal_Bool	EditedEntry( SvLBoxEntry* pEntry, const XubString& rNewText );

	DECL_LINK( OnSelectionChangeHdl, UnoTreeListBoxImpl* );
	DECL_LINK( OnExpandingHdl, UnoTreeListBoxImpl* );
	DECL_LINK( OnExpandedHdl, UnoTreeListBoxImpl* );

private:
	rtl::Reference< TreeControlPeer > mxPeer;
};

// --------------------------------------------------------------------

class SVT_DLLPUBLIC UnoTreeListItem : public SvLBoxItem
{
public:
					UnoTreeListItem( SvLBoxEntry* );
					UnoTreeListItem();
	virtual			~UnoTreeListItem();
	virtual sal_uInt16	IsA();
	void			InitViewData( SvLBox*,SvLBoxEntry*,SvViewDataItem* );
	OUString		GetText() const;
	void 			SetText( const OUString& rText );
	Image			GetImage() const;
	void			SetImage( const Image& rImage );
	OUString		GetGraphicURL() const;
	void			SetGraphicURL( const OUString& rGraphicURL );
	void			Paint( const Point&, SvLBox& rDev, sal_uInt16 nFlags,SvLBoxEntry* );
	SvLBoxItem* 	Create() const;
	void 			Clone( SvLBoxItem* pSource );

private:
	OUString		maText;
	OUString		maGraphicURL;
	Image			maImage;
};

// --------------------------------------------------------------------

class UnoTreeListEntry : public SvLBoxEntry
{
public:
	UnoTreeListEntry( const Reference< XTreeNode >& xNode, TreeControlPeer* pPeer );
	virtual ~UnoTreeListEntry();

	Reference< XTreeNode > mxNode;
	TreeControlPeer* mpPeer;
};

// --------------------------------------------------------------------

class TreeNodeMap : public std::map< Reference< XTreeNode >, UnoTreeListEntry* >
{
};

// --------------------------------------------------------------------

TreeControlPeer::TreeControlPeer()
: maSelectionListeners( *this )
, maTreeExpansionListeners( *this )
, maTreeEditListeners( *this )
, mpTreeImpl( 0 )
, mnEditLock( 0 )
, mpTreeNodeMap( 0 )
{
}

// --------------------------------------------------------------------

TreeControlPeer::~TreeControlPeer()
{
	if( mpTreeImpl )
		mpTreeImpl->Clear();
	delete mpTreeNodeMap;
}

// --------------------------------------------------------------------

void TreeControlPeer::addEntry( UnoTreeListEntry* pEntry )
{
	if( pEntry && pEntry->mxNode.is() )
	{
		if( !mpTreeNodeMap )
		{
			mpTreeNodeMap = new TreeNodeMap();
		}

		(*mpTreeNodeMap)[ pEntry->mxNode ] = pEntry;
	}
}

// --------------------------------------------------------------------

void TreeControlPeer::removeEntry( UnoTreeListEntry* 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 */ ) throw( IllegalArgumentException )
{
	if( mpTreeNodeMap )
	{
		TreeNodeMap::iterator aIter( mpTreeNodeMap->find( xNode ) );
		if( aIter != mpTreeNodeMap->end() )
			return (*aIter).second;
	}

	if( bThrow )
		throw IllegalArgumentException();

	return 0;
}

// --------------------------------------------------------------------

Window* TreeControlPeer::createVclControl( Window* pParent, sal_Int64 nWinStyle )
{
	mpTreeImpl = new UnoTreeListBoxImpl( this, pParent, nWinStyle );
	return mpTreeImpl;
}

// --------------------------------------------------------------------

/** called from the UnoTreeListBoxImpl when it gets deleted */
void TreeControlPeer::disposeControl()
{
	delete mpTreeNodeMap;
	mpTreeNodeMap = 0;
	mpTreeImpl = 0;
}

// --------------------------------------------------------------------

void TreeControlPeer::SetWindow( Window* pWindow )
{
	VCLXWindow::SetWindow( pWindow );
}

// --------------------------------------------------------------------

UnoTreeListEntry* TreeControlPeer::createEntry( const Reference< XTreeNode >& xNode, UnoTreeListEntry* pParent, sal_uLong nPos /* = LIST_APPEND */ )
{
	UnoTreeListEntry* pEntry = 0;
	if( mpTreeImpl )
	{
		Image aImage;
		pEntry = new UnoTreeListEntry( xNode, this );
		ImplContextGraphicItem* pContextBmp= new ImplContextGraphicItem( pEntry,0, aImage, aImage, SVLISTENTRYFLAG_EXPANDED );

		pEntry->AddItem( pContextBmp );

		UnoTreeListItem * pUnoItem = new UnoTreeListItem( pEntry );

		if( xNode->getNodeGraphicURL().getLength() )
		{
			pUnoItem->SetGraphicURL( xNode->getNodeGraphicURL() );
			Image aNodeImage;
			loadImage( xNode->getNodeGraphicURL(), aNodeImage );
			pUnoItem->SetImage( aNodeImage );
			mpTreeImpl->AdjustEntryHeight( aNodeImage );
		}

		pEntry->AddItem( pUnoItem );

		mpTreeImpl->insert( pEntry, pParent, nPos );

        if( msDefaultExpandedGraphicURL.getLength() )
			mpTreeImpl->SetExpandedEntryBmp( pEntry, maDefaultExpandedImage );

		if( msDefaultCollapsedGraphicURL.getLength() )
			mpTreeImpl->SetCollapsedEntryBmp( pEntry, maDefaultCollapsedImage );

		updateEntry( pEntry );
	}
	return pEntry;
}

// --------------------------------------------------------------------

bool TreeControlPeer::updateEntry( UnoTreeListEntry* pEntry )
{
	bool bChanged = false;
	if( pEntry && pEntry->mxNode.is() && mpTreeImpl )
	{
		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( (pEntry->mxNode->hasChildrenOnDemand() == sal_True) != (pEntry->HasChildsOnDemand() == sal_True) )
		{
			pEntry->EnableChildsOnDemand( pEntry->mxNode->hasChildrenOnDemand() ? sal_True : sal_False );
			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 );
	}

	return bChanged;
}

// --------------------------------------------------------------------

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() )
	{
		Reference< XTreeNode > xRootNode( xDataModel->getRoot() );
		if( xRootNode.is() )
		{
			if( mbIsRootDisplayed )
			{
				addNode( rTree, xRootNode, 0 );
			}
			else
			{
				const sal_Int32 nChildCount = xRootNode->getChildCount();
				for( sal_Int32 nChild = 0; nChild < nChildCount; nChild++ )
					addNode( rTree, xRootNode->getChildAt( nChild ), 0 );
			}
		}
	}
}

// --------------------------------------------------------------------

void TreeControlPeer::addNode( UnoTreeListBoxImpl& rTree, const Reference< XTreeNode >& xNode, UnoTreeListEntry* pParentEntry )
{
	if( xNode.is() )
	{
		UnoTreeListEntry* pEntry = createEntry( xNode, pParentEntry, LIST_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 throw (RuntimeException )
{
	if( !mpTreeImpl )
		throw DisposedException();
	return *mpTreeImpl;
}

// --------------------------------------------------------------------

void TreeControlPeer::ChangeNodesSelection( const Any& rSelection, bool bSelect, bool bSetSelection ) throw( RuntimeException, IllegalArgumentException )
{
	::vos::OGuard aGuard( GetMutex() );

	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();

	Reference< XTreeNode > xTempNode;
	Sequence< XTreeNode > aTempSeq;

	const Reference< XTreeNode > *pNodes = 0;
	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( rSelection.getValueType() == ::getCppuType( (const Sequence< Reference< XTreeNode > > *) 0 ) )
				{
					const Sequence< Reference< XTreeNode > >& rSeq( *(const Sequence< Reference< XTreeNode > > *)rSelection.getValue() );
					nCount = rSeq.getLength();
					if( nCount )
						pNodes = rSeq.getConstArray();
				}
				break;
			}
		default:
			break;
		}

		if( nCount == 0 )
			throw IllegalArgumentException();
	}

	if( bSetSelection )
		rTree.SelectAll( sal_False );

	if( pNodes && nCount )
	{
		while( nCount-- )
		{
			UnoTreeListEntry* pEntry = getEntry( *pNodes++ );
			rTree.Select( pEntry, bSelect ? sal_True : sal_False );
		}
	}
}

// -------------------------------------------------------------------
// ::com::sun::star::view::XSelectionSupplier
// -------------------------------------------------------------------

sal_Bool SAL_CALL TreeControlPeer::select( const Any& rSelection ) throw (IllegalArgumentException, RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );
	ChangeNodesSelection( rSelection, true, true );
	return sal_True;
}

// -------------------------------------------------------------------

Any SAL_CALL TreeControlPeer::getSelection() throw (RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	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 == 0) && (nSelectionCount == 0) );
		aRet <<= aSelection;
	}

	return aRet;
}

// -------------------------------------------------------------------

void SAL_CALL TreeControlPeer::addSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener ) throw (RuntimeException)
{
	maSelectionListeners.addInterface( xListener );
}

// -------------------------------------------------------------------

void SAL_CALL TreeControlPeer::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener ) throw (RuntimeException)
{
	maSelectionListeners.addInterface( xListener );
}

// -------------------------------------------------------------------
// ::com::sun::star::view::XMultiSelectionSupplier
// -------------------------------------------------------------------

sal_Bool SAL_CALL TreeControlPeer::addSelection( const Any& rSelection ) throw (IllegalArgumentException, RuntimeException)
{
	ChangeNodesSelection( rSelection, true, false );
	return sal_True;
}

// -------------------------------------------------------------------

void SAL_CALL TreeControlPeer::removeSelection( const Any& rSelection ) throw (IllegalArgumentException, RuntimeException)
{
	ChangeNodesSelection( rSelection, false, false );
}

// -------------------------------------------------------------------

void SAL_CALL TreeControlPeer::clearSelection() throw (RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );
	getTreeListBoxOrThrow().SelectAll( sal_False );
}

// -------------------------------------------------------------------

sal_Int32 SAL_CALL TreeControlPeer::getSelectionCount() throw (RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );
	return getTreeListBoxOrThrow().GetSelectionCount();
}

// -------------------------------------------------------------------

class TreeSelectionEnumeration : public ::cppu::WeakImplHelper1< XEnumeration >
{
public:
	TreeSelectionEnumeration( std::list< Any >& rSelection );
    virtual ::sal_Bool SAL_CALL hasMoreElements() throw (RuntimeException);
    virtual Any SAL_CALL nextElement() throw (NoSuchElementException, WrappedTargetException, RuntimeException);

	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() throw (RuntimeException)
{
	return maIter != maSelection.end();
}

// -------------------------------------------------------------------

Any SAL_CALL TreeSelectionEnumeration::nextElement() throw (NoSuchElementException, WrappedTargetException, RuntimeException)
{
	if( maIter == maSelection.end() )
		throw NoSuchElementException();

	return (*maIter++);
}

// -------------------------------------------------------------------

Reference< XEnumeration > SAL_CALL TreeControlPeer::createSelectionEnumeration() throw (RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
	
	sal_uInt32 nSelectionCount = rTree.GetSelectionCount();
	std::list< Any > aSelection( nSelectionCount );

	UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.FirstSelected() );
	while( pEntry && nSelectionCount )
	{
		aSelection.push_back( Any( pEntry->mxNode ) );
		pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.NextSelected( pEntry ) );
		--nSelectionCount;
	}

	OSL_ASSERT( (pEntry == 0) && (nSelectionCount == 0) );

	return Reference< XEnumeration >( new TreeSelectionEnumeration( aSelection ) );
}

// -------------------------------------------------------------------

Reference< XEnumeration > SAL_CALL TreeControlPeer::createReverseSelectionEnumeration() throw (RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	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 == 0) && (nSelectionCount == 0) );

	return Reference< XEnumeration >( new TreeSelectionEnumeration( aSelection ) );
}

// --------------------------------------------------------------------
// ::com::sun::star::awt::XTreeControl
// --------------------------------------------------------------------

OUString SAL_CALL TreeControlPeer::getDefaultExpandedGraphicURL() throw (::com::sun::star::uno::RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );
	return msDefaultExpandedGraphicURL;
}

// --------------------------------------------------------------------

void SAL_CALL TreeControlPeer::setDefaultExpandedGraphicURL( const ::rtl::OUString& sDefaultExpandedGraphicURL ) throw (::com::sun::star::uno::RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );
	if( msDefaultExpandedGraphicURL != sDefaultExpandedGraphicURL )
	{
		if( sDefaultExpandedGraphicURL.getLength() )
			loadImage( sDefaultExpandedGraphicURL, maDefaultExpandedImage );
		else
			maDefaultExpandedImage = Image();

		UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();

		SvLBoxEntry* pEntry = rTree.First();
		while( pEntry )
		{
			ImplContextGraphicItem* pContextGraphicItem = dynamic_cast< ImplContextGraphicItem* >( pEntry->GetItem( 0 ) );
			if( pContextGraphicItem )
			{
				if( pContextGraphicItem->msExpandedGraphicURL.getLength() == 0 )
					rTree.SetExpandedEntryBmp( pEntry, maDefaultExpandedImage );
			}
			pEntry = rTree.Next( pEntry );
		}

		msDefaultExpandedGraphicURL = sDefaultExpandedGraphicURL;
	}
}

// --------------------------------------------------------------------

OUString SAL_CALL TreeControlPeer::getDefaultCollapsedGraphicURL() throw (::com::sun::star::uno::RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );
	return msDefaultCollapsedGraphicURL;
}

// --------------------------------------------------------------------

void SAL_CALL TreeControlPeer::setDefaultCollapsedGraphicURL( const ::rtl::OUString& sDefaultCollapsedGraphicURL ) throw (::com::sun::star::uno::RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );
	if( msDefaultCollapsedGraphicURL != sDefaultCollapsedGraphicURL )
	{
		if( sDefaultCollapsedGraphicURL.getLength() )
			loadImage( sDefaultCollapsedGraphicURL, maDefaultCollapsedImage );
		else
			maDefaultCollapsedImage = Image();

		UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();

		SvLBoxEntry* pEntry = rTree.First();
		while( pEntry )
		{
			ImplContextGraphicItem* pContextGraphicItem = dynamic_cast< ImplContextGraphicItem* >( pEntry->GetItem( 0 ) );
			if( pContextGraphicItem )
			{
				if( pContextGraphicItem->msCollapsedGraphicURL.getLength() == 0 )
					rTree.SetCollapsedEntryBmp( pEntry, maDefaultCollapsedImage );
			}
			pEntry = rTree.Next( pEntry );
		}

		msDefaultCollapsedGraphicURL = sDefaultCollapsedGraphicURL;
	}
}

// --------------------------------------------------------------------

sal_Bool SAL_CALL TreeControlPeer::isNodeExpanded( const Reference< XTreeNode >& xNode ) throw (RuntimeException, IllegalArgumentException)
{
	::vos::OGuard aGuard( GetMutex() );

	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
	UnoTreeListEntry* pEntry = getEntry( xNode );
	return ( pEntry && rTree.IsExpanded( pEntry ) ) ? sal_True : sal_False;
}

// -------------------------------------------------------------------

sal_Bool SAL_CALL TreeControlPeer::isNodeCollapsed( const Reference< XTreeNode >& xNode ) throw (RuntimeException, IllegalArgumentException)
{
	::vos::OGuard aGuard( GetMutex() );
	return !isNodeExpanded( xNode );
}

// -------------------------------------------------------------------

void SAL_CALL TreeControlPeer::makeNodeVisible( const Reference< XTreeNode >& xNode ) throw (RuntimeException, ExpandVetoException, IllegalArgumentException)
{
	::vos::OGuard aGuard( GetMutex() );

	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
	UnoTreeListEntry* pEntry = getEntry( xNode );
	if( pEntry )
		rTree.MakeVisible( pEntry );
}

// -------------------------------------------------------------------

sal_Bool SAL_CALL TreeControlPeer::isNodeVisible( const Reference< XTreeNode >& xNode ) throw (RuntimeException, IllegalArgumentException)
{
	::vos::OGuard aGuard( GetMutex() );

	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
	UnoTreeListEntry* pEntry = getEntry( xNode );
	return ( pEntry && rTree.IsEntryVisible( pEntry ) ) ? sal_True : sal_False;
}

// -------------------------------------------------------------------

void SAL_CALL TreeControlPeer::expandNode( const Reference< XTreeNode >& xNode ) throw (RuntimeException, ExpandVetoException, IllegalArgumentException)
{
	::vos::OGuard aGuard( GetMutex() );

	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
	UnoTreeListEntry* pEntry = getEntry( xNode );
	if( pEntry )
		rTree.Expand( pEntry );
}

// -------------------------------------------------------------------

void SAL_CALL TreeControlPeer::collapseNode( const Reference< XTreeNode >& xNode ) throw (RuntimeException, ExpandVetoException, IllegalArgumentException)
{
	::vos::OGuard aGuard( GetMutex() );

	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
	UnoTreeListEntry* pEntry = getEntry( xNode );
	if( pEntry )
		rTree.Collapse( pEntry );
}

// -------------------------------------------------------------------

void SAL_CALL TreeControlPeer::addTreeExpansionListener( const Reference< XTreeExpansionListener >& xListener ) throw (RuntimeException)
{
	maTreeExpansionListeners.addInterface( xListener );
}

// -------------------------------------------------------------------

void SAL_CALL TreeControlPeer::removeTreeExpansionListener( const Reference< XTreeExpansionListener >& xListener ) throw (RuntimeException)
{
	maTreeExpansionListeners.removeInterface( xListener );
}

// -------------------------------------------------------------------

Reference< XTreeNode > SAL_CALL TreeControlPeer::getNodeForLocation( sal_Int32 x, sal_Int32 y ) throw (RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();

	Reference< XTreeNode > xNode;

	const Point aPos( x, y );
	UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.GetEntry( aPos, sal_True ) );
	if( pEntry )
		xNode = pEntry->mxNode;

	return xNode;
}

// -------------------------------------------------------------------

Reference< XTreeNode > SAL_CALL TreeControlPeer::getClosestNodeForLocation( sal_Int32 x, sal_Int32 y ) throw (RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();

	Reference< XTreeNode > xNode;

	const Point aPos( x, y );
	UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.GetEntry( aPos, sal_True ) );
	if( pEntry )
		xNode = pEntry->mxNode;

	return xNode;
}

// -------------------------------------------------------------------

awt::Rectangle SAL_CALL TreeControlPeer::getNodeRect( const Reference< XTreeNode >& i_Node ) throw (IllegalArgumentException, RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
	UnoTreeListEntry* pEntry = getEntry( i_Node, true );

    ::Rectangle aEntryRect( rTree.GetFocusRect( pEntry, rTree.GetEntryPosition( pEntry ).Y() ) );
    return VCLUnoHelper::ConvertToAWTRect( aEntryRect );
}

// -------------------------------------------------------------------

sal_Bool SAL_CALL TreeControlPeer::isEditing(  ) throw (RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
	return rTree.IsEditingActive() ? sal_True : sal_False;
}

// -------------------------------------------------------------------

sal_Bool SAL_CALL TreeControlPeer::stopEditing() throw (RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
	if( rTree.IsEditingActive() )
	{
		rTree.EndEditing(sal_False);
		return sal_True;
	}
	else
	{
		return sal_False;
	}
}

// -------------------------------------------------------------------

void SAL_CALL TreeControlPeer::cancelEditing(  ) throw (RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
	rTree.EndEditing(sal_False);
}

// -------------------------------------------------------------------

void SAL_CALL TreeControlPeer::startEditingAtNode( const Reference< XTreeNode >& xNode ) throw (IllegalArgumentException, RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
	UnoTreeListEntry* pEntry = getEntry( xNode );
	rTree.EditEntry( pEntry );
}

void SAL_CALL TreeControlPeer::addTreeEditListener( const Reference< XTreeEditListener >& xListener ) throw (RuntimeException)
{
	maTreeEditListeners.addInterface( xListener );
}

void SAL_CALL TreeControlPeer::removeTreeEditListener( const Reference< XTreeEditListener >& xListener ) throw (RuntimeException)
{
	maTreeEditListeners.removeInterface( xListener );
}

bool TreeControlPeer::onEditingEntry( UnoTreeListEntry* 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* pEntry, const XubString& rNewText )
{
	if( mpTreeImpl && pEntry && pEntry->mxNode.is() ) try
	{
		LockGuard aLockGuard( mnEditLock );
		const OUString aNewText( rNewText );
		if( maTreeEditListeners.getLength() > 0 )
		{
			maTreeEditListeners.nodeEdited( pEntry->mxNode, aNewText );
			return false;
		}
		else
		{
			Reference< XMutableTreeNode > xMutableNode( pEntry->mxNode, UNO_QUERY );
			if( xMutableNode.is() )
				xMutableNode->setDisplayValue( Any( aNewText ) );
			else
				return false;
		}

	}
	catch( Exception& )
	{
	}

	return true;
}

// --------------------------------------------------------------------
// ::com::sun::star::awt::tree::TreeDataModelListener
// --------------------------------------------------------------------

void SAL_CALL TreeControlPeer::treeNodesChanged( const ::com::sun::star::awt::tree::TreeDataModelEvent& rEvent ) throw (RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	if( mnEditLock != 0 )
		return;

	updateTree( rEvent, true );
}

void SAL_CALL TreeControlPeer::treeNodesInserted( const ::com::sun::star::awt::tree::TreeDataModelEvent& rEvent ) throw (RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	if( mnEditLock != 0 )
		return;

	updateTree( rEvent, true );
}

void SAL_CALL TreeControlPeer::treeNodesRemoved( const ::com::sun::star::awt::tree::TreeDataModelEvent& rEvent ) throw (RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	if( mnEditLock != 0 )
		return;

	updateTree( rEvent, true );
}

void SAL_CALL TreeControlPeer::treeStructureChanged( const ::com::sun::star::awt::tree::TreeDataModelEvent& rEvent ) throw (RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	if( mnEditLock != 0 )
		return;

	updateTree( rEvent, true );
}

void TreeControlPeer::updateTree( const ::com::sun::star::awt::tree::TreeDataModelEvent& rEvent, bool bRecursive )
{
	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();

	Sequence< Reference< XTreeNode > > Nodes;
	Reference< XTreeNode > xNode( rEvent.ParentNode );
	if( !xNode.is() && Nodes.getLength() )
	{
		xNode = Nodes[0];
	}

	if( xNode.is() )
		updateNode( rTree, xNode, bRecursive );
}

void TreeControlPeer::updateNode( UnoTreeListBoxImpl& rTree, const Reference< XTreeNode >& xNode, bool bRecursive )
{
	if( xNode.is() )
	{
		UnoTreeListEntry* pNodeEntry = getEntry( xNode, false );

		if( !pNodeEntry )
		{
			Reference< XTreeNode > xParentNode( xNode->getParent() );
			UnoTreeListEntry* pParentEntry = 0;
			sal_uLong nChild = LIST_APPEND;
			
			if( xParentNode.is() )
			{
				pParentEntry = getEntry( xParentNode  );
				nChild = xParentNode->getIndex( xNode );
			}

			pNodeEntry = createEntry( xNode, pParentEntry, nChild );
		}

		if( bRecursive )
			updateChildNodes( rTree, xNode, pNodeEntry );
	}
}

void TreeControlPeer::updateChildNodes( UnoTreeListBoxImpl& rTree, const Reference< XTreeNode >& xParentNode, UnoTreeListEntry* pParentEntry )
{
	if( xParentNode.is() && pParentEntry )
	{
		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 == 0 )
				{
					// 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* >( rTree.NextSibling( pCurrentChild ) );
		}

		// check if we have entries without nodes left, we need to remove them
		while( pCurrentChild )
		{
			UnoTreeListEntry* pNextChild = dynamic_cast< UnoTreeListEntry* >( rTree.NextSibling( pCurrentChild ) );
			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::valueOf( nValue );
				break;
			}
		case TypeClass_BYTE:
		case TypeClass_UNSIGNED_SHORT:
		case TypeClass_UNSIGNED_LONG:
			{
				sal_uInt32 nValue = 0;
				if( rValue >>= nValue )
					sValue = OUString::valueOf( (sal_Int64)nValue );
				break;
			}
		case TypeClass_HYPER:
			{
				sal_Int64 nValue = 0;
				if( rValue >>= nValue )
					sValue = OUString::valueOf( nValue );
				break;
			}
		case TypeClass_UNSIGNED_HYPER:
			{
				sal_uInt64 nValue = 0;
				if( rValue >>= nValue )
					sValue = OUString::valueOf( (sal_Int64)nValue );
				break;
			}
		case TypeClass_FLOAT:
		case TypeClass_DOUBLE:
			{
				double fValue = 0.0;
				if( rValue >>= fValue )
					sValue = OUString::valueOf( fValue );
				break;
			}
		case TypeClass_STRING:
			rValue >>= sValue;
			break;
	/*
		case TypeClass_INTERFACE:
			// @todo
			break;
		case TypeClass_SEQUENCE:
			{
				Sequence< Any > aValues;
				if( aValue >>= aValues )
				{
					updateEntry( SvLBoxEntry& rEntry, aValues );
					return;
				}
			}
			break;
	*/
		default:
			break;
		}
	}
	return sValue;
}

// XEventListener
void SAL_CALL TreeControlPeer::disposing( const ::com::sun::star::lang::EventObject& ) throw(::com::sun::star::uno::RuntimeException)
{
	// model is disposed, so we clear our tree
	::vos::OGuard aGuard( GetMutex() );
	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 );

	if( !xDataModel.is() )
	{
		static const OUString aSN( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.tree.DefaultTreeDataModel" ) );
		Reference< XMultiServiceFactory > xORB( ::comphelper::getProcessServiceFactory() );
		if( xORB.is() )
		{
			mxDataModel.query( xORB->createInstance( aSN ) );
		}
	}

	mxDataModel = xDataModel;

	fillTree( rTree, mxDataModel );

	if( mxDataModel.is() )
		mxDataModel->addTreeDataModelListener( xListener );
}

// --------------------------------------------------------------------
// ::com::sun::star::awt::XLayoutConstrains
// --------------------------------------------------------------------

::com::sun::star::awt::Size TreeControlPeer::getMinimumSize() throw(RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	::com::sun::star::awt::Size aSz;
/* todo
	MultiLineEdit* pEdit = (MultiLineEdit*) GetWindow();
	if ( pEdit )
		aSz = AWTSize(pEdit->CalcMinimumSize());
*/
	return aSz;
}

::com::sun::star::awt::Size TreeControlPeer::getPreferredSize() throw(RuntimeException)
{
	return getMinimumSize();
}

::com::sun::star::awt::Size TreeControlPeer::calcAdjustedSize( const ::com::sun::star::awt::Size& rNewSize ) throw(RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	::com::sun::star::awt::Size aSz = rNewSize;
/* todo
	MultiLineEdit* pEdit = (MultiLineEdit*) GetWindow();
	if ( pEdit )
		aSz = AWTSize(pEdit->CalcAdjustedSize( VCLSize(rNewSize )));
*/
	return aSz;
}

// --------------------------------------------------------------------
// ::com::sun::star::awt::XVclWindowPeer
// --------------------------------------------------------------------

void TreeControlPeer::setProperty( const ::rtl::OUString& PropertyName, const Any& aValue) throw(RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();

	switch( GetPropertyId( PropertyName ) )
	{
        case BASEPROPERTY_HIDEINACTIVESELECTION:
        {
            sal_Bool bEnabled = sal_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 = SINGLE_SELECTION; break;
				case SelectionType_RANGE:	eSelMode = RANGE_SELECTION; break;
				case SelectionType_MULTI:	eSelMode = MULTIPLE_SELECTION; break;
	//			case SelectionType_NONE:		
				default:					eSelMode = NO_SELECTION; 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( (short)nHeight );
			break;
		}
		case BASEPROPERTY_TREE_EDITABLE:
		{
			sal_Bool bEnabled = false;
			if( aValue >>= bEnabled )
				rTree.EnableInplaceEditing( bEnabled ? sal_True : sal_False );
			break;
		}
		case BASEPROPERTY_TREE_INVOKESSTOPNODEEDITING:
			break; // @todo
		case BASEPROPERTY_TREE_ROOTDISPLAYED:
        {
			sal_Bool bDisplayed = false;
			if( (aValue >>= bDisplayed) && ( bDisplayed != mbIsRootDisplayed) )
			{
				onChangeRootDisplayed(bDisplayed);
			}
			break;
        }
		case BASEPROPERTY_TREE_SHOWSHANDLES:
		{
			sal_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:
		{
			sal_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 ::rtl::OUString& PropertyName ) throw(RuntimeException)
{
	::vos::OGuard aGuard( GetMutex() );

	const sal_uInt16 nPropId = GetPropertyId( PropertyName );
	if( (nPropId >= BASEPROPERTY_TREE_START) && (nPropId <= BASEPROPERTY_TREE_END) )
	{
		UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();
		switch(nPropId)
		{
        case BASEPROPERTY_HIDEINACTIVESELECTION:
			return Any( ( rTree.GetStyle() & WB_HIDESELECTION ) != 0 ? sal_True : sal_False );

		case BASEPROPERTY_TREE_SELECTIONTYPE:
		{
			SelectionType eSelectionType;

			SelectionMode eSelMode = rTree.GetSelectionMode();
			switch( eSelMode )
			{
			case SINGLE_SELECTION:	eSelectionType = SelectionType_SINGLE; break;
			case RANGE_SELECTION:	eSelectionType = SelectionType_RANGE; break;
			case MULTIPLE_SELECTION:eSelectionType = SelectionType_MULTI; break;
//			case NO_SELECTION:		
			default:				eSelectionType = SelectionType_NONE; break;
			}
			return Any( eSelectionType );
		}
		case BASEPROPERTY_ROW_HEIGHT:
			return Any( (sal_Int32)rTree.GetEntryHeight() );
		case BASEPROPERTY_TREE_DATAMODEL:
			return Any( mxDataModel );
		case BASEPROPERTY_TREE_EDITABLE:
			return Any( rTree.IsInplaceEditingEnabled() ? sal_True : sal_False );
		case BASEPROPERTY_TREE_INVOKESSTOPNODEEDITING:
			return Any( sal_True ); // @todo
		case BASEPROPERTY_TREE_ROOTDISPLAYED:
			return Any( mbIsRootDisplayed );
		case BASEPROPERTY_TREE_SHOWSHANDLES:
			return Any( (rTree.GetStyle() & WB_HASLINES) != 0 ? sal_True : sal_False );
		case BASEPROPERTY_TREE_SHOWSROOTHANDLES:
			return Any( (rTree.GetStyle() & WB_HASLINESATROOT) != 0 ? sal_True : sal_False );
		}
	}
	return VCLXWindow::getProperty( PropertyName );
}

void TreeControlPeer::onChangeRootDisplayed( sal_Bool bIsRootDisplayed )
{
	if( mbIsRootDisplayed == bIsRootDisplayed )
		return;

	mbIsRootDisplayed = bIsRootDisplayed;

	UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow();

	if( rTree.GetEntryCount() == 0 )
		return;

	// todo
	fillTree( rTree, mxDataModel );
	if( mbIsRootDisplayed )
	{
	}
	else
	{
	}
}

bool TreeControlPeer::loadImage( const ::rtl::OUString& rURL, Image& rImage )
{
	if( !mxGraphicProvider.is() )
	{
		static const OUString aSN( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.graphic.GraphicProvider" ) );
		Reference< XMultiServiceFactory > xORB( ::comphelper::getProcessServiceFactory() );
		if( xORB.is() )
		{
			Reference< XInterface > x( xORB->createInstance( aSN ) );
			mxGraphicProvider.query( x );
			mxGraphicProvider = Reference< XGraphicProvider >( x, UNO_QUERY );
		}
	}

	if( mxGraphicProvider.is() ) try
	{
		::com::sun::star::beans::PropertyValues aProps( 1 );
		aProps[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) );
		aProps[0].Value <<= rURL;

		Reference< XGraphic > xGraphic( mxGraphicProvider->queryGraphic( aProps ) );

		Graphic aGraphic( xGraphic );
		rImage = aGraphic.GetBitmapEx();
		return true;
	}
	catch( Exception& )
	{
	}

	return false;
}

// ====================================================================
// class UnoTreeListBoxImpl
// ====================================================================

UnoTreeListBoxImpl::UnoTreeListBoxImpl( TreeControlPeer* pPeer, 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()
{
	if( mxPeer.is() )
		mxPeer->disposeControl();
}

// --------------------------------------------------------------------

IMPL_LINK( UnoTreeListBoxImpl, OnSelectionChangeHdl, UnoTreeListBoxImpl*, EMPTYARG )
{
	if( mxPeer.is() )
		mxPeer->onSelectionChanged();
	return 0;
}

// --------------------------------------------------------------------

IMPL_LINK(UnoTreeListBoxImpl, OnExpandingHdl, UnoTreeListBoxImpl*, EMPTYARG )
{
	UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( GetHdlEntry() );

	if( pEntry && mxPeer.is() )
	{
		return mxPeer->onExpanding( pEntry->mxNode, !IsExpanded( pEntry ) ) ? 1 : 0;
	}
	return 0;
}

// --------------------------------------------------------------------

IMPL_LINK(UnoTreeListBoxImpl, OnExpandedHdl, UnoTreeListBoxImpl*, EMPTYARG )
{
	UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( GetHdlEntry() );
	if( pEntry && mxPeer.is() )
	{
		mxPeer->onExpanded( pEntry->mxNode, IsExpanded( pEntry ) );
	}
	return 0;
}

// --------------------------------------------------------------------

sal_uInt32 UnoTreeListBoxImpl::insert( SvLBoxEntry* pEntry,SvLBoxEntry* pParent,sal_uLong nPos )
{
	if( pParent )
		return SvTreeListBox::Insert( pEntry, pParent, nPos );
	else
		return SvTreeListBox::Insert( pEntry, nPos );
}

// --------------------------------------------------------------------

void UnoTreeListBoxImpl::RequestingChilds( SvLBoxEntry* pParent )
{
	UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( pParent );
	if( pEntry && pEntry->mxNode.is() && mxPeer.is() )
		mxPeer->onRequestChildNodes( pEntry->mxNode );
}

// --------------------------------------------------------------------

sal_Bool UnoTreeListBoxImpl::EditingEntry( SvLBoxEntry* pEntry, Selection& )
{
	return mxPeer.is() ? mxPeer->onEditingEntry( dynamic_cast< UnoTreeListEntry* >( pEntry ) ) : false;
}

// --------------------------------------------------------------------

sal_Bool UnoTreeListBoxImpl::EditedEntry( SvLBoxEntry* pEntry, const XubString& rNewText )
{
	return mxPeer.is() ? mxPeer->onEditedEntry( dynamic_cast< UnoTreeListEntry* >( pEntry ), rNewText ) : false;
}

// ====================================================================
// class UnoTreeListItem
// ====================================================================

UnoTreeListItem::UnoTreeListItem( SvLBoxEntry* pEntry )
: SvLBoxItem( pEntry, 0 )
{
}

// --------------------------------------------------------------------

UnoTreeListItem::UnoTreeListItem()
: SvLBoxItem()
{
}

// --------------------------------------------------------------------

UnoTreeListItem::~UnoTreeListItem()
{
}

// --------------------------------------------------------------------

sal_uInt16 UnoTreeListItem::IsA()
{
	return 0;
}

// --------------------------------------------------------------------

void UnoTreeListItem::Paint( const Point& rPos, SvLBox& rDev, sal_uInt16 /* nFlags */, SvLBoxEntry* _pEntry)
{
	Point aPos( rPos );
	if( _pEntry )
	{
		Size aSize( GetSize(&rDev,_pEntry) );
		if( !!maImage )
		{
			rDev.DrawImage( aPos, maImage, rDev.IsEnabled() ? 0 : IMAGE_DRAW_DISABLE );
			int nWidth = maImage.GetSizePixel().Width() + 6;
			aPos.X() += nWidth;
			aSize.Width() -= nWidth;
		}
		rDev.DrawText( Rectangle(aPos,aSize),maText, rDev.IsEnabled() ? 0 : TEXT_DRAW_DISABLE );
	}
	else
	{
		if( !!maImage )
		{
			rDev.DrawImage( aPos, maImage, rDev.IsEnabled() ? 0 : IMAGE_DRAW_DISABLE);
			aPos.X() += maImage.GetSizePixel().Width() + 6;
		}
		rDev.DrawText( aPos, maText);
	}
}

// --------------------------------------------------------------------

SvLBoxItem* UnoTreeListItem::Create() const
{
	return new UnoTreeListItem;
}

// --------------------------------------------------------------------

void UnoTreeListItem::Clone( SvLBoxItem* pSource )
{
	UnoTreeListItem* pSourceItem = dynamic_cast< UnoTreeListItem* >( pSource );
	if( pSourceItem )
	{
		maText = pSourceItem->maText;
		maImage = pSourceItem->maImage;
	}
}

// --------------------------------------------------------------------

OUString UnoTreeListItem::GetText() const
{
	return maText;
}

// --------------------------------------------------------------------

void UnoTreeListItem::SetText( const OUString& rText )
{
	maText = rText;
}

// --------------------------------------------------------------------

void UnoTreeListItem::SetImage( const Image& rImage )
{
	maImage = rImage;
}

// --------------------------------------------------------------------

OUString UnoTreeListItem::GetGraphicURL() const
{
	return maGraphicURL;
}

// --------------------------------------------------------------------

void UnoTreeListItem::SetGraphicURL( const OUString& rGraphicURL )
{
	maGraphicURL = rGraphicURL;
}

// --------------------------------------------------------------------

void UnoTreeListItem::InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, SvViewDataItem* pViewData)
{
	if( !pViewData )
		pViewData = pView->GetViewDataItem( pEntry, this );

	pViewData->aSize = maImage.GetSizePixel();

	const Size aTextSize(pView->GetTextWidth( maText ), pView->GetTextHeight());
	if( pViewData->aSize.Width() )
	{
		pViewData->aSize.Width() += 6 + aTextSize.Width();
		if( pViewData->aSize.Height() < aTextSize.Height() )
			pViewData->aSize.Height() = aTextSize.Height();
	}
	else
	{
		pViewData->aSize = aTextSize;
	}
}

// --------------------------------------------------------------------

UnoTreeListEntry::UnoTreeListEntry( const Reference< XTreeNode >& xNode, TreeControlPeer* pPeer )
: SvLBoxEntry()
, mxNode( xNode )
, mpPeer( pPeer )
{
	if( mpPeer )
		mpPeer->addEntry( this );
}

// --------------------------------------------------------------------

UnoTreeListEntry::~UnoTreeListEntry()
{
	if( mpPeer )
		mpPeer->removeEntry( this );
}
