#include "stdafx.h"
#include "util.h"
#include "resource.h"

#include "TypeLibTreeView.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

#define MAX_NAMES   256

IMPLEMENT_DYNCREATE(CTypeLibTreeView, CView)

CTypeLibTreeView::CTypeLibTreeView( ITypeLib* pTLB )
{
	m_hTypeInfos = NULL ;
	m_ptlb = pTLB ;
}

CTypeLibTreeView::~CTypeLibTreeView()
{
	if (m_ptlb) {
		int i = m_ptlb->Release() ;
	}
}

BEGIN_MESSAGE_MAP(CTypeLibTreeView, CView)

	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_SIZE()

	ON_NOTIFY(TVN_SELCHANGED, ID_TREEVIEW, OnTreeSelchanged)
	ON_NOTIFY(TVN_ITEMEXPANDING, ID_TREEVIEW, OnTreeItemExpanding)
	ON_NOTIFY(TVN_ITEMEXPANDED, ID_TREEVIEW, OnTreeItemExpanded)
	ON_NOTIFY(NM_RETURN, ID_TREEVIEW, OnTreeItemReturn)
	ON_NOTIFY(TVN_DELETEITEM, ID_TREEVIEW, OnTreeDeleteItem)
END_MESSAGE_MAP()

#ifdef _DEBUG
void CTypeLibTreeView::AssertValid() const
{
	CView::AssertValid();
}

void CTypeLibTreeView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}
#endif 

int CTypeLibTreeView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;

	RECT rect ;
	rect.top = lpCreateStruct->y ;
	rect.left = lpCreateStruct->x ;
	rect.bottom = lpCreateStruct->cy ;
	rect.right = lpCreateStruct->cx ;

	if (!m_tree.Create( WS_CHILD | WS_VISIBLE |
								WS_BORDER |
								TVS_HASLINES |
								TVS_LINESATROOT |
								TVS_SHOWSELALWAYS |
								TVS_HASBUTTONS |
								TVS_DISABLEDRAGDROP,
								rect, this, ID_TREEVIEW ))
	{
		TRACE( _T("Tree control failed to create!") ) ;
		return -1 ;
	}

	m_images.Create( IDB_IMAGELIST, 16, 64, RGB(0,255,0) ) ;
	m_tree.SetImageList( &m_images, TVSIL_NORMAL ) ;

	return 0;
}

void CTypeLibTreeView::OnDestroy()
{
	CView::OnDestroy();
	m_tree.DeleteAllItems() ;
}

void CTypeLibTreeView::OnDraw(CDC* pDC)
{

}

void CTypeLibTreeView::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);
	m_tree.SetWindowPos( NULL, -1, -1, cx+2, cy+2, SWP_NOZORDER ) ;
}

void CTypeLibTreeView::OnInitialUpdate()
{
	TRACE(_T("OnInitialUpdate\n")) ;	
	ASSERT( m_ptlb );
	m_ptlb->AddRef() ;

	CView::OnInitialUpdate();
}

void CTypeLibTreeView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
	USES_CONVERSION;
	if (lHint != NULL )
		return ;

	TRACE(_T("OnUpdate\n")) ;
	m_tree.SetRedraw( FALSE ) ;
	BeginWaitCursor() ;

	m_tree.DeleteAllItems() ;
	m_hTypeInfos = NULL ;

	TV_INSERTSTRUCT tvis ;
	tvis.hParent = TVI_ROOT ;
	tvis.hInsertAfter = TVI_FIRST ;
	tvis.item.mask = TVIF_TEXT | TVIF_CHILDREN | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE ;
	tvis.item.iImage = CTreeItem::typeTypeLib ;
	tvis.item.iSelectedImage = tvis.item.iImage + 1 ;

	HRESULT hr = S_OK ;
	CString strError ;
	TRY
	{

		tvis.item.cChildren = m_ptlb->GetTypeInfoCount() ;

		BSTR    bstrName = NULL ;
		BSTR    bstrDoc = NULL ;
		BSTR    bstrHelp = NULL ;
		DWORD   dwHelpID ;
		hr = m_ptlb->GetDocumentation( MEMBERID_NIL, &bstrName, &bstrDoc, &dwHelpID, &bstrHelp ) ;
		if (FAILED(hr))
		{
			strError = _T("ITypeLib::GetDocumentation failed.") ;
			AfxThrowMemoryException() ;
		}

		CTreeItem* pItem = new CTreeItem(&m_tree) ;
		pItem->m_Type = CTreeItem::typeTypeLib ;
		pItem->SetTypeLib( m_ptlb ) ;
		m_ptlb->AddRef() ;
		tvis.item.lParam = (LPARAM)pItem ;

		LPCTSTR lpszName = OLE2CT(bstrName);
		if (::SysStringLen(bstrDoc) != 0)
		{
			LPCTSTR lpszDoc = OLE2CT(bstrDoc);
			CString str;
			str.Format( _T("%s (%s)"), lpszName, lpszDoc);
			tvis.item.pszText = str.GetBuffer(0);
			m_hTypeInfos = m_tree.InsertItem( &tvis ) ;
			str.ReleaseBuffer(-1) ;
		}
		else
		{
			tvis.item.pszText = (LPTSTR)lpszName;
			m_hTypeInfos = m_tree.InsertItem( &tvis ) ;
		}

		::SysFreeString( bstrName ) ;
		::SysFreeString( bstrDoc ) ;
		::SysFreeString( bstrHelp ) ;
	}
	CATCH(CException, pException)
	{
	}
	END_CATCH

	if (m_hTypeInfos)
	{
		m_tree.Expand( m_hTypeInfos, TVE_EXPAND ) ;

	}

	m_tree.SetRedraw( TRUE ) ;
	EndWaitCursor() ;
}

void CTypeLibTreeView::DeleteTreeItems( HTREEITEM htree )
{
	HTREEITEM       hItem, hItemNext ;
	ASSERT(htree) ;

	hItem = m_tree.GetChildItem( htree ) ;
	while( hItem )
	{
		hItemNext = m_tree.GetNextSiblingItem( hItem ) ;
		m_tree.DeleteItem( hItem ) ;
		hItem = hItemNext ;
	}
}

void CTypeLibTreeView::OnTreeSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
{
	NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR;
	*pResult = 0;

	CTreeItem*  pItem = (CTreeItem*)pnmtv->itemNew.lParam ;
	if (pItem == NULL)
		return ;
	ASSERT(pItem->IsKindOf(RUNTIME_CLASS(CTreeItem)));
}

void CTypeLibTreeView::OnTreeItemExpanding(NMHDR* pNMHDR, LRESULT* pResult)
{
	*pResult = 0 ;
	NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR;

	if ((pnmtv->action != TVE_EXPAND && pnmtv->itemNew.lParam) ||
		(pnmtv->itemNew.state & TVIS_EXPANDEDONCE))
		return ;

	CTreeItem*  pItem = (CTreeItem*)pnmtv->itemNew.lParam ;
	if (pItem == NULL)
		return ;
	ASSERT(pItem->IsKindOf(RUNTIME_CLASS(CTreeItem)));

	BeginWaitCursor() ;
	m_tree.SetRedraw( FALSE ) ;

	*pResult = !pItem->Expand(  pnmtv->itemNew.hItem ) ;

	if (*pResult == TRUE)
	{
		TV_ITEM item ;
		item.cChildren = 0 ;
		item.mask = TVIF_CHILDREN ;
		item.hItem = pnmtv->itemNew.hItem ;
		m_tree.SetItem( &item ) ;
	}

	m_tree.SetRedraw( TRUE ) ;
	EndWaitCursor() ;
}

void CTypeLibTreeView::OnTreeItemExpanded(NMHDR* pNMHDR, LRESULT* pResult)
{
	*pResult = (LRESULT)FALSE ;
}

void CTypeLibTreeView::OnTreeItemReturn(NMHDR* pNMHDR, LRESULT* pResult)
{
	*pResult = (LRESULT)TRUE ;
	HTREEITEM hTreeItemSel = m_tree.GetSelectedItem() ;

	if (hTreeItemSel)
		m_tree.Expand( hTreeItemSel, TVE_TOGGLE ) ;
}

inline void CTypeLibTreeView::OnTreeDeleteItem(NMHDR* pNMHDR, LRESULT* pResult)
{
	*pResult = (LRESULT)TRUE ;
	NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR;

	if (pnmtv->itemOld.lParam)
	{
		CTreeItem* pItem = (CTreeItem*)pnmtv->itemOld.lParam ;
		ASSERT(pItem->IsKindOf(RUNTIME_CLASS(CTreeItem)));
		delete pItem ;

	}

}
// tlbtree.cpp : implementation file
//

// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#include "stdafx.h"
#include "util.h"
#include "resource.h"
//#include "typelib.h"
#include "TypeLibTreeView.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

#define MAX_NAMES   256

/////////////////////////////////////////////////////////////////////////////
// CTypeLibTreeView
IMPLEMENT_DYNCREATE(CTypeLibTreeView, CView)

CTypeLibTreeView::CTypeLibTreeView( ITypeLib* pTLB )
{
	m_hTypeInfos = NULL ;
	m_ptlb = pTLB ;
}

CTypeLibTreeView::~CTypeLibTreeView()
{
	if (m_ptlb) {
		int i = m_ptlb->Release() ;
	}
}


BEGIN_MESSAGE_MAP(CTypeLibTreeView, CView)
	//{{AFX_MSG_MAP(CTypeLibTreeView)
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_SIZE()
	//}}AFX_MSG_MAP
	ON_NOTIFY(TVN_SELCHANGED, ID_TREEVIEW, OnTreeSelchanged)
	ON_NOTIFY(TVN_ITEMEXPANDING, ID_TREEVIEW, OnTreeItemExpanding)
	ON_NOTIFY(TVN_ITEMEXPANDED, ID_TREEVIEW, OnTreeItemExpanded)
	ON_NOTIFY(NM_RETURN, ID_TREEVIEW, OnTreeItemReturn)
	ON_NOTIFY(TVN_DELETEITEM, ID_TREEVIEW, OnTreeDeleteItem)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CTypeLibTreeView drawing


/////////////////////////////////////////////////////////////////////////////
// CTypeLibTreeView diagnostics

#ifdef _DEBUG
void CTypeLibTreeView::AssertValid() const
{
	CView::AssertValid();
}

void CTypeLibTreeView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CTypeLibTreeView message handlers

int CTypeLibTreeView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;

	RECT rect ;
	rect.top = lpCreateStruct->y ;
	rect.left = lpCreateStruct->x ;
	rect.bottom = lpCreateStruct->cy ;
	rect.right = lpCreateStruct->cx ;

	if (!m_tree.Create( WS_CHILD | WS_VISIBLE |
								WS_BORDER |
								TVS_HASLINES |
								TVS_LINESATROOT |
								TVS_SHOWSELALWAYS |
								TVS_HASBUTTONS |
								TVS_DISABLEDRAGDROP,
								rect, this, ID_TREEVIEW ))
	{
		TRACE( _T("Tree control failed to create!") ) ;
		return -1 ;
	}

	m_images.Create( IDB_IMAGELIST, 16, 64, RGB(0,255,0) ) ;
	m_tree.SetImageList( &m_images, TVSIL_NORMAL ) ;

	return 0;
}

void CTypeLibTreeView::OnDestroy()
{
	CView::OnDestroy();
	m_tree.DeleteAllItems() ;
}

void CTypeLibTreeView::OnDraw(CDC* pDC)
{
	// TODO: Add your specialized code here and/or call the base class

}

void CTypeLibTreeView::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);
	m_tree.SetWindowPos( NULL, -1, -1, cx+2, cy+2, SWP_NOZORDER ) ;
}

void CTypeLibTreeView::OnInitialUpdate()
{
	TRACE(_T("OnInitialUpdate\n")) ;	
	ASSERT( m_ptlb );
	m_ptlb->AddRef() ;

	CView::OnInitialUpdate();
}

void CTypeLibTreeView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
	USES_CONVERSION;
	if (lHint != NULL )
		return ;

	TRACE(_T("OnUpdate\n")) ;
	m_tree.SetRedraw( FALSE ) ;
	BeginWaitCursor() ;

	m_tree.DeleteAllItems() ;
	m_hTypeInfos = NULL ;

	TV_INSERTSTRUCT tvis ;
	tvis.hParent = TVI_ROOT ;
	tvis.hInsertAfter = TVI_FIRST ;
	tvis.item.mask = TVIF_TEXT | TVIF_CHILDREN | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE ;
	tvis.item.iImage = CTreeItem::typeTypeLib ;
	tvis.item.iSelectedImage = tvis.item.iImage + 1 ;

	HRESULT hr = S_OK ;
	CString strError ;
	TRY
	{
		
		tvis.item.cChildren = m_ptlb->GetTypeInfoCount() ;
		

		BSTR    bstrName = NULL ;
		BSTR    bstrDoc = NULL ;
		BSTR    bstrHelp = NULL ;
		DWORD   dwHelpID ;
		hr = m_ptlb->GetDocumentation( MEMBERID_NIL, &bstrName, &bstrDoc, &dwHelpID, &bstrHelp ) ;
		if (FAILED(hr))
		{
			strError = _T("ITypeLib::GetDocumentation failed.") ;
			AfxThrowMemoryException() ;
		}

		CTreeItem* pItem = new CTreeItem(&m_tree) ;
		pItem->m_Type = CTreeItem::typeTypeLib ;
		pItem->SetTypeLib( m_ptlb ) ;
		m_ptlb->AddRef() ;
		tvis.item.lParam = (LPARAM)pItem ;

		LPCTSTR lpszName = OLE2CT(bstrName);
		if (::SysStringLen(bstrDoc) != 0)
		{
			LPCTSTR lpszDoc = OLE2CT(bstrDoc);
			CString str;
			str.Format( _T("%s (%s)"), lpszName, lpszDoc);
			tvis.item.pszText = str.GetBuffer(0);
			m_hTypeInfos = m_tree.InsertItem( &tvis ) ;
			str.ReleaseBuffer(-1) ;
		}
		else
		{
			tvis.item.pszText = (LPTSTR)lpszName;
			m_hTypeInfos = m_tree.InsertItem( &tvis ) ;
		}

		::SysFreeString( bstrName ) ;
		::SysFreeString( bstrDoc ) ;
		::SysFreeString( bstrHelp ) ;
	}
	CATCH(CException, pException)
	{
	}
	END_CATCH

	if (m_hTypeInfos)
	{
		m_tree.Expand( m_hTypeInfos, TVE_EXPAND ) ;
		//m_tree.SelectItem( m_hTypeInfos ) ;
	}

	m_tree.SetRedraw( TRUE ) ;
	EndWaitCursor() ;
}

void CTypeLibTreeView::DeleteTreeItems( HTREEITEM htree )
{
	HTREEITEM       hItem, hItemNext ;
	ASSERT(htree) ;

	hItem = m_tree.GetChildItem( htree ) ;
	while( hItem )
	{
		hItemNext = m_tree.GetNextSiblingItem( hItem ) ;
		m_tree.DeleteItem( hItem ) ;
		hItem = hItemNext ;
	}
}

void CTypeLibTreeView::OnTreeSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
{
	NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR;
	*pResult = 0;

	CTreeItem*  pItem = (CTreeItem*)pnmtv->itemNew.lParam ;
	if (pItem == NULL)
		return ;
	ASSERT(pItem->IsKindOf(RUNTIME_CLASS(CTreeItem)));
}

void CTypeLibTreeView::OnTreeItemExpanding(NMHDR* pNMHDR, LRESULT* pResult)
{
	*pResult = 0 ;
	NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR;

	if ((pnmtv->action != TVE_EXPAND && pnmtv->itemNew.lParam) ||
		(pnmtv->itemNew.state & TVIS_EXPANDEDONCE))
		return ;

	CTreeItem*  pItem = (CTreeItem*)pnmtv->itemNew.lParam ;
	if (pItem == NULL)
		return ;
	ASSERT(pItem->IsKindOf(RUNTIME_CLASS(CTreeItem)));

	BeginWaitCursor() ;
	m_tree.SetRedraw( FALSE ) ;

	*pResult = !pItem->Expand(  pnmtv->itemNew.hItem ) ;

	// No children
	if (*pResult == TRUE)
	{
		TV_ITEM item ;
		item.cChildren = 0 ;
		item.mask = TVIF_CHILDREN ;
		item.hItem = pnmtv->itemNew.hItem ;
		m_tree.SetItem( &item ) ;
	}

	m_tree.SetRedraw( TRUE ) ;
	EndWaitCursor() ;
}


void CTypeLibTreeView::OnTreeItemExpanded(NMHDR* pNMHDR, LRESULT* pResult)
{
	*pResult = (LRESULT)FALSE ;
}

void CTypeLibTreeView::OnTreeItemReturn(NMHDR* pNMHDR, LRESULT* pResult)
{
	*pResult = (LRESULT)TRUE ;
	HTREEITEM hTreeItemSel = m_tree.GetSelectedItem() ;

	if (hTreeItemSel)
		m_tree.Expand( hTreeItemSel, TVE_TOGGLE ) ;
}

inline void CTypeLibTreeView::OnTreeDeleteItem(NMHDR* pNMHDR, LRESULT* pResult)
{
	*pResult = (LRESULT)TRUE ;
	NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR;

	if (pnmtv->itemOld.lParam)
	{
		CTreeItem* pItem = (CTreeItem*)pnmtv->itemOld.lParam ;
		ASSERT(pItem->IsKindOf(RUNTIME_CLASS(CTreeItem)));
		delete pItem ;
		//pnmtv->itemOld.lParam = NULL ;
	}

}
