Click here to Skip to main content
15,892,199 members
Articles / Desktop Programming / ATL

CM_ConfigBuilder 1.2g: Visual Studio 6/Visual Studio 2005/Visual Studio 2008 Code Generator for Application Settings Graphic Management

Rate me:
Please Sign up or sign in to vote.
4.94/5 (126 votes)
12 Feb 2008CPOL17 min read 697.6K   9.8K   262  
CM_ConfigBuilder generates and compiles the required files to manage your application's settings/preferences and to store/retrieve them in XML format.
// ProjectTreeView.cpp : implementation of the CProjectTreeView class
//

#include "stdafx.h"
#include "AsCfgBuilder.h"
#include "ProjectDoc.h"
#include "ProjectTreeView.h"
#include "XmlBaseElement.h"
#include "XmlClassInfo.h"
#include "MemDC.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


#define ICON_INDEX_CLASS	0
#define ICON_INDEX_MEMBER	1
#define ICON_INDEX_LINK		2
#define ICON_INDEX_LOCK		3

/////////////////////////////////////////////////////////////////////////////
// CProjectTreeView

IMPLEMENT_DYNCREATE(CProjectTreeView, CTreeView)

BEGIN_MESSAGE_MAP(CProjectTreeView, CTreeView)
	//{{AFX_MSG_MAP(CProjectTreeView)
	ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged)
	ON_NOTIFY_REFLECT(TVN_ENDLABELEDIT, OnEndLabelEdit)
	ON_COMMAND(ID_STRUCTURE_APPENDCLASSELEMENT, OnMnuAppendClassElement)
	ON_UPDATE_COMMAND_UI(ID_STRUCTURE_APPENDCLASSELEMENT, OnUpdateMnuAppendClassElement)
	ON_COMMAND(ID_STRUCTURE_APPENDMEMBERELEMENT, OnMnuAppendMemberElement)
	ON_UPDATE_COMMAND_UI(ID_STRUCTURE_APPENDMEMBERELEMENT, OnUpdateMnuAppendMemberElement)
	ON_COMMAND(ID_STRUCTURE_REMOVEELEMENT, OnMnuRemoveElement)
	ON_UPDATE_COMMAND_UI(ID_STRUCTURE_REMOVEELEMENT, OnUpdateMnuRemoveElement)
	ON_WM_RBUTTONDOWN()
	ON_WM_ERASEBKGND()
	ON_WM_SIZE()
	ON_WM_PAINT()
	ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBegindrag)
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONUP()
	ON_WM_TIMER()
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CTreeView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CTreeView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CTreeView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CProjectTreeView construction/destruction

CProjectTreeView::CProjectTreeView():
	displayItemId_(false),
	isDragging_(false),
	hDragItem_(NULL),
	dragImageList_(NULL),
	scrollMargin_(10),
	scrollInterval_(200),
	delayInterval_(500)

{

}

CProjectTreeView::~CProjectTreeView()
{
}

BOOL CProjectTreeView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CTreeView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CProjectTreeView drawing

void CProjectTreeView::OnDraw(CDC* pDC)
{
	CProjectDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	
}


/////////////////////////////////////////////////////////////////////////////
// CProjectTreeView printing

BOOL CProjectTreeView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CProjectTreeView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CProjectTreeView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

void CProjectTreeView::OnInitialUpdate()
{
	CTreeView::OnInitialUpdate();

	ModifyStyle(0, /*TVS_EDITLABELS | */TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS);

	if (!imageList_.GetSafeHandle()) {
		imageList_.Create(16, 16, ILC_COLOR32 | ILC_MASK, 4, 4);
		imageList_.Add(AfxGetApp()->LoadIcon(IDI_CLASS));
		imageList_.Add(AfxGetApp()->LoadIcon(IDI_CLASS_MEMBER));
		imageList_.Add(AfxGetApp()->LoadIcon(IDI_LINK));
		imageList_.Add(AfxGetApp()->LoadIcon(IDI_LOCK));

		GetTreeCtrl().SetImageList(&imageList_, TVSIL_NORMAL);

		BuildTree();
	}

}

/////////////////////////////////////////////////////////////////////////////
// CProjectTreeView diagnostics

#ifdef _DEBUG
void CProjectTreeView::AssertValid() const
{
	CTreeView::AssertValid();
}

void CProjectTreeView::Dump(CDumpContext& dc) const
{
	CTreeView::Dump(dc);
}

CProjectDoc* CProjectTreeView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CProjectDoc)));
	return (CProjectDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CProjectTreeView message handlers

void CProjectTreeView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
	HTREEITEM selItem;
	CXmlBaseElement* selElement;

	switch ((enUpdateViewReason)lHint) {
		case enUpdateViewReason_DocLoaded:
			BuildTree();
			break;

		case enUpdateViewReason_ItemNameChanged:
			selElement = GetSelectedItem();
			selItem = GetTreeCtrl().GetSelectedItem();
			if (selElement)
				GetTreeCtrl().SetItemText(selItem, FormatNodeLabel(selElement));
			break;

		case enUpdateViewReason_ItemChanged:
			UpdateAllStates();
	}
	
	
}

void CProjectTreeView::BuildTree()
{
	CProjectDoc* doc;

	doc = GetDocument();

	Clear();
	if (doc->GetDisplayRootNode()) {
		CreateNode(doc->GetProject()->GetRootElement());
	} else {
		ClassMemberMap* members;
		ClassMemberMap::iterator it;
		CXmlBaseElement* member;

		members = doc->GetProject()->GetRootElement()->GetMembers();

		for (it = members->begin(); it != members->end(); it++) {
			member = it->second;

			CreateNode(member);
		}
	}
}

void CProjectTreeView::Clear()
{
	GetTreeCtrl().DeleteAllItems();
	treeItems_.clear();
}

HTREEITEM CProjectTreeView::CreateNode(CXmlBaseElement* xmlElement, HTREEITEM parentNode) 
{
	HTREEITEM newTreeNode;
	int iconIndex;
	cmString nodeCaption;
	
	if (xmlElement->GetDataType() == enDataType_Class) {
		CXmlClassInfo* classInfo;

		classInfo = dynamic_cast<CXmlClassInfo*>(xmlElement);

		if (classInfo->GetLockedByInheritance())
			iconIndex = ICON_INDEX_LOCK;
		else if (classInfo->GetDefinitionInheritance())
			iconIndex = ICON_INDEX_LINK;
		else
			iconIndex = ICON_INDEX_CLASS;
	} else {
		iconIndex = ICON_INDEX_MEMBER;
	}
	
	nodeCaption = FormatNodeLabel(xmlElement);

	newTreeNode = GetTreeCtrl().InsertItem(nodeCaption, iconIndex, iconIndex, parentNode);
	//UpdateNodeState(newTreeNode);

	GetTreeCtrl().RedrawWindow();

	treeItems_[newTreeNode] = xmlElement->GetId();
	
	// create members nodes
	//
	if (xmlElement->GetDataType() == enDataType_Class) {
		ClassMemberMap* members;
		ClassMemberMap::iterator it;
		CXmlBaseElement* member;

		members = dynamic_cast<CXmlClassInfo*>(xmlElement)->GetMembers();

		for (it = members->begin(); it != members->end(); it++) {
			member = it->second;

			CreateNode(member, newTreeNode);
		}
		//GetTreeCtrl().Expand(newTreeNode, TVE_EXPAND);
	}

	return newTreeNode;
}

void CProjectTreeView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	
	TreeItemToIdMap::iterator it;
	
	it = treeItems_.find(GetTreeCtrl().GetSelectedItem());
	if (it != treeItems_.end()) {
		CProjectDoc* doc;

		doc = GetDocument();
		doc->SetSelectedItemId(it->second);	

		doc->UpdateAllViews(this, enUpdateViewReason_SelectionChanged);

		RedrawWindow();
	}
	

	
	*pResult = 0;
}

void CProjectTreeView::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) 
{
	TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
	
	if (pTVDispInfo->item.mask == TVIF_TEXT) {
		cmString id;
		CXmlBaseElement* selElement;
		HTREEITEM selItem;

		selItem = GetTreeCtrl().GetSelectedItem();
		id = treeItems_[selItem];
		GetDocument()->SetSelectedItemId(id);
		
		selElement = GetDocument()->GetElementById(id);
		
		selElement->SetName(pTVDispInfo->item.pszText);
		GetDocument()->UpdateAllViews(this, enUpdateViewReason_ItemNameChanged);
		
		GetTreeCtrl().SetItemText(selItem, pTVDispInfo->item.pszText);
	}

	*pResult = 0;
}

void CProjectTreeView::OnMnuAppendClassElement() 
{
	CXmlBaseElement* selElement;

	selElement = GetSelectedItem();
	if (selElement && (selElement->GetDataType() == enDataType_Class))
		AppendNode(enDataType_Class, selElement, GetTreeItemById(selElement->GetId()));
	else
		AppendNode(enDataType_Class, GetDocument()->GetProject()->GetRootElement(), GetTreeCtrl().GetRootItem());
}

void CProjectTreeView::OnUpdateMnuAppendClassElement(CCmdUI* pCmdUI) 
{
	CXmlBaseElement* selElement;

	selElement = GetSelectedItem();
	if (selElement)
		pCmdUI->Enable(selElement->GetDataType() == enDataType_Class);
	else
		pCmdUI->Enable(FALSE);
}

void CProjectTreeView::OnMnuAppendMemberElement() 
{
	CXmlBaseElement* selElement;

	selElement = GetSelectedItem();
	if (selElement && (selElement->GetDataType() == enDataType_Class))
		AppendNode(enDataType_String, selElement, GetTreeItemById(selElement->GetId()));
	else
		AppendNode(enDataType_String, GetDocument()->GetProject()->GetRootElement(), GetTreeCtrl().GetRootItem());
}

void CProjectTreeView::OnUpdateMnuAppendMemberElement(CCmdUI* pCmdUI) 
{
	CXmlBaseElement* selElement;

	selElement = GetSelectedItem();
	if (selElement)
		pCmdUI->Enable(selElement->GetDataType() == enDataType_Class);
	else
		pCmdUI->Enable(FALSE);
}

void CProjectTreeView::OnMnuRemoveElement() 
{
	HTREEITEM selNode;
	
	selNode = GetTreeCtrl().GetSelectedItem();
	
	if (selNode)
		RemoveItem(selNode);

	GetTreeCtrl().Select(GetTreeCtrl().GetParentItem(selNode), TVGN_CARET | TVGN_DROPHILITE);
}

void CProjectTreeView::OnUpdateMnuRemoveElement(CCmdUI* pCmdUI) 
{
	CXmlBaseElement* selElement;

	selElement = GetSelectedItem();
	if (selElement && selElement->GetId() != GetDocument()->GetProject()->GetRootElement()->GetId())
		pCmdUI->Enable(TRUE);
	else
		pCmdUI->Enable(FALSE);
}



void CProjectTreeView::OnRButtonDown(UINT nFlags, CPoint point) 
{
	
	CTreeView::OnRButtonDown(nFlags, point);
}

BOOL CProjectTreeView::PreTranslateMessage(MSG* pMsg) 
{
	if (pMsg->message == WM_RBUTTONDOWN) {
		CMenu* structMenu;
		UINT flags;
		HTREEITEM selItem;
		CPoint tmpPoint(pMsg->pt);
		CRect rc;

		// select item
		//
		ScreenToClient(&tmpPoint);
		selItem = GetTreeCtrl().HitTest(tmpPoint, &flags);
		GetTreeCtrl().Select(selItem, TVGN_CARET | TVGN_DROPHILITE);
		
		// get menu top-left point
		//
		if (GetTreeCtrl().GetItemRect( selItem, rc, TRUE)) {
			tmpPoint.x = rc.right;
			tmpPoint.y = rc.top;

			ClientToScreen(&tmpPoint);
		} else {
			tmpPoint = pMsg->pt;
		}
		
		// display menu
		//
		CWnd* mainWindow = AfxGetMainWnd();
		CMenu* topLevelMenu = mainWindow->GetMenu();

		structMenu = topLevelMenu->GetSubMenu(2);
		structMenu->TrackPopupMenu( TPM_LEFTALIGN | TPM_TOPALIGN, tmpPoint.x, tmpPoint.y, mainWindow);

		return TRUE;
	}
		
	return CTreeView::PreTranslateMessage(pMsg);
}

CXmlBaseElement* CProjectTreeView::GetSelectedItem()
{
	HTREEITEM selItem;
	cmString id;
	CXmlBaseElement* selElement;

	selItem = GetTreeCtrl().GetSelectedItem();
	if (selItem) {
		id = treeItems_[selItem];
		selElement = GetDocument()->GetElementById(id);
	} else {
		selElement = GetDocument()->GetProject()->GetRootElement();
	}

	return selElement;
}

CXmlBaseElement* CProjectTreeView::GetItem(HTREEITEM hItem)
{
	CXmlBaseElement* ret;
	cmString id;

	id = treeItems_[hItem];
	ret = GetDocument()->GetElementById(id);

	return ret;
}

void CProjectTreeView::AppendNode(enDataType dataType, CXmlBaseElement* parentXmlElement, HTREEITEM parentTreeItem)
{
	if (parentXmlElement == NULL)
		return;

	if (parentXmlElement->GetDataType() != enDataType_Class)
		return;

	CXmlClassInfo* classInfo;
	CXmlBaseElement* newElement;
	
	classInfo = dynamic_cast<CXmlClassInfo*>(parentXmlElement);
	
	newElement = classInfo->AddMember(dataType);

	CreateNode(newElement, parentTreeItem);
}

HTREEITEM CProjectTreeView::GetTreeItemById(const cmString& id)
{
	TreeItemToIdMap::iterator it;

	for (it = treeItems_.begin(); it != treeItems_.end(); it++) {
		if (it->second == id)
			return it->first;
	}

	return NULL;
}

void CProjectTreeView::UpdateAllStates()
{
	TreeItemToIdMap::iterator it;

	for (it = treeItems_.begin(); it != treeItems_.end(); it++)
		UpdateNode(it->first);
}

void CProjectTreeView::UpdateNode(HTREEITEM item)
{
	cmString id;
	CXmlClassInfo* classInfo;
	CXmlBaseElement* element;

	id = treeItems_[item];
	element = GetDocument()->GetElementById(id);
	classInfo = dynamic_cast<CXmlClassInfo*>(element);

	if (classInfo) {
		int iconIndex;
		
		if(classInfo->GetLockedByInheritance())
			iconIndex = ICON_INDEX_LOCK;
		else if (classInfo->GetDefinitionInheritance())
			iconIndex = ICON_INDEX_LINK;
		else
			iconIndex = ICON_INDEX_CLASS;
		
		

		GetTreeCtrl().SetItemImage(GetTreeItemById(classInfo->GetId()), iconIndex, iconIndex);
	}

	CString curItemText;
	cmString newItemText;

	curItemText = GetTreeCtrl().GetItemText(item);
	newItemText = FormatNodeLabel(element);
	if ((const TCHAR*)curItemText != newItemText)
		GetTreeCtrl().SetItemText(item, newItemText); 
}

cmString CProjectTreeView::FormatNodeLabel(CXmlBaseElement* element)
{
	cmString ret;

	if (element) {
		ret = element->GetName() + _T(" As ") + CXmlBaseElement::DataType2String(element->GetDataType());
		if (displayItemId_)
			ret += _T(" [") + element->GetId() + _T("]");
	}

	return ret;
}

void CProjectTreeView::DisplayItemId(bool display)
{
	displayItemId_ = display;

	UpdateAllLabels();
}
BOOL CProjectTreeView::OnEraseBkgnd(CDC* pDC) 
{
	return TRUE;
	
	return CTreeView::OnEraseBkgnd(pDC);
}

void CProjectTreeView::OnSize(UINT nType, int cx, int cy) 
{
	CTreeView::OnSize(nType, cx, cy);
	
	GetClientRect(clientRect_);
	
}

void CProjectTreeView::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	CMemDC memDC(&dc);//, &clientRect_);
	
	CWnd::DefWindowProc(WM_PAINT, (WPARAM)memDC.m_hDC, 0);
}

void CProjectTreeView::UpdateAllLabels()
{
	UpdateNodeLabel(GetTreeCtrl().GetRootItem());
}

void CProjectTreeView::UpdateNodeLabel(HTREEITEM node)
{
	CXmlBaseElement* element;
	TreeItemToIdMap::iterator it;

	it = treeItems_.find(node);
	assert(it != treeItems_.end());
	if (it == treeItems_.end())
		return;

	element = GetDocument()->GetElementById(it->second);
	
	GetTreeCtrl().SetItemText(node, FormatNodeLabel(element));

	// update labels on children
	//
	if (!GetTreeCtrl().ItemHasChildren(node))
		return;

	HTREEITEM child;

	child = GetTreeCtrl().GetChildItem(node);
	while(child) {
		UpdateNodeLabel(child);
	
		child = GetTreeCtrl().GetNextSiblingItem(child);
	}
}
void CProjectTreeView::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	
	//
	// Do nothing if the user is attempting to drag a top-level item.
	//
	HTREEITEM hItem = pNMTreeView->itemNew.hItem;
	if (GetTreeCtrl().GetParentItem (hItem) == NULL)
		return;

	//
	// Create a drag image. If the assertion fails, you probably forgot
	// to assign an image list to the control with SetImageList. Create-
	// DragImage will not work if the control hasn't been assigned an
	// image list!
	//
	dragImageList_ = GetTreeCtrl().CreateDragImage(hItem);
	ASSERT (dragImageList_ != NULL);

	if (dragImageList_ != NULL) { // Just to be sure
		//
		// Compute the coordinates of the "hot spot"--the location of the
		// cursor relative to the upper left corner of the item rectangle.
		//
		CRect rect;
		GetTreeCtrl().GetItemRect (hItem, rect, TRUE);
		CPoint point (pNMTreeView->ptDrag.x, pNMTreeView->ptDrag.y);
		CPoint hotSpot = point;
		hotSpot.x -= rect.left;
		hotSpot.y -= rect.top;

		//
		// Convert the client coordinates in "point" to coordinates relative
		// to the upper left corner of the control window.
		//
		CPoint client (0, 0);
		ClientToScreen (&client);
		GetWindowRect (rect);
		point.x += client.x - rect.left;
		point.y += client.y - rect.top;

		//
		// Capture the mouse and begin dragging.
		//
		SetCapture ();
		dragImageList_->BeginDrag (0, hotSpot);
		dragImageList_->DragEnter (this, point);
		hDragItem_ = hItem;
		isDragging_ = true;
	}

	*pResult = 0;
}

//DEL void CProjectTreeView::BeginDrag (NM_TREEVIEW *item)
//DEL {
//DEL 	CRect rc;
//DEL 	CPoint pt;
//DEL 
//DEL 	GetCursorPos(&pt);
//DEL 
//DEL 	isDragging_ = true;
//DEL 	hDragItem_ = item->itemNew.hItem;
//DEL 
//DEL 	TRACE(_T("BeginDrag\n"));
//DEL 
//DEL 	// create an image to use for dragging.
//DEL 	//
//DEL 	dragImageList_ = GetTreeCtrl().CreateDragImage(hDragItem_);
//DEL 	
//DEL 	// get the bounding rectangle of the item being dragged.
//DEL 	//
//DEL 	GetTreeCtrl().GetItemRect(hDragItem_, rc, TRUE);
//DEL 	
//DEL 	// start dragging the image.
//DEL 	//
//DEL 	dragImageList_->BeginDrag(0, CPoint(0, 0));
//DEL 	dragImageList_->DragEnter(this, pt);
//DEL 	
//DEL 	// capture the mouse.
//DEL 	//
//DEL 	GetTreeCtrl().SetCapture();
//DEL }

void CProjectTreeView::OnMouseMove(UINT nFlags, CPoint point) 
{
	//HTREEITEM hTarget;
	//UINT flags;

	if (isDragging_ && dragImageList_ != NULL) {
		//
		// Stop the scroll timer if it's running.
		//
		KillTimer (1);

		//
		// Erase the old drag image and draw a new one.
		//
		dragImageList_->DragMove (point);

		//
		// Highlight the drop target if the cursor is over an item.
		//
		HTREEITEM hItem = HighlightDropTarget (point);

		//
		// Modify the cursor to provide visual feedback to the user.
		// Note: It's important to do this AFTER the call to DragMove.
		//
		::SetCursor (hItem == NULL ?
			AfxGetApp ()->LoadStandardCursor (IDC_NO) :
			(HCURSOR) ::GetClassLong (m_hWnd, GCL_HCURSOR));

		//
		// Set a timer if the cursor is at the top or bottom of the window,
		// or if it's over a collapsed item.
		//
		CRect rect;
		GetClientRect (rect);
		int cy = rect.Height ();

		if ((point.y >= 0 && point.y <= scrollMargin_) ||
			(point.y >= cy - scrollMargin_ && point.y <= cy) ||
			(hItem != NULL && GetTreeCtrl().ItemHasChildren (hItem) &&
			!IsItemExpanded (hItem)))

			SetTimer (1, delayInterval_, NULL);
	}

	CTreeView::OnMouseMove(nFlags, point);
}

void CProjectTreeView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	
	if (isDragging_ && dragImageList_) {
		// Stop the scroll timer if it's running.
		//
		KillTimer (1);

		// Terminate the dragging operation and release the mouse.
		//
		dragImageList_->DragLeave (this);
		dragImageList_->EndDrag ();
		::ReleaseCapture ();
		isDragging_ = false;
		GetTreeCtrl().SelectDropTarget(NULL);

		// Delete the image list created by CreateDragImage.
		//
		delete dragImageList_;
		dragImageList_ = NULL;

		// Get the HTREEITEM of the drop target and exit now if it's NULL.
		//
		UINT nFlags;
		HTREEITEM hItem = GetTreeCtrl().HitTest (point, &nFlags);
		if (hItem == NULL)
			return;

		// Display an error message if the move is illegal.
		//
		if (hItem == hDragItem_) {
			MessageBox (_T ("An item can't be dropped onto itself"));
			return;
		}
		
		if (hItem == GetTreeCtrl().GetParentItem (hDragItem_)) {
			MessageBox (_T ("An item can't be dropped onto its parent"));
			return;
		}
		
		if (IsChildOf (hItem, hDragItem_)) {
			MessageBox (_T ("An item can't be dropped onto one of its children"));
			return;
		}

		CXmlBaseElement* dragSource;
		CXmlClassInfo* dragSourceParent;
		CXmlClassInfo* dropTarget;
		
		dragSource = GetItem(hDragItem_);
		dragSourceParent = dynamic_cast<CXmlClassInfo*>(GetItem(GetTreeCtrl().GetParentItem(hDragItem_)));
		dropTarget = dynamic_cast<CXmlClassInfo*>(GetItem(hItem));
		if (dropTarget == NULL) {
			MessageBox (_T ("A member element can be dropped only onto classes"));
			return;
		}
				
		// move the XmlBaseElement to the target
		//
		dragSourceParent->DetachMember(dragSource->GetId());
		dropTarget->AttachMember(dragSource);

		// delete drag source node
		//
		GetTreeCtrl().DeleteItem(hDragItem_);
		
		// create new subtree
		//
		HTREEITEM newItem;

		newItem = CreateNode(dragSource, hItem);
		GetTreeCtrl().SortChildren(hItem);
		GetTreeCtrl().SelectItem(newItem);
		if (IsItemExpanded(hItem))
			GetTreeCtrl().EnsureVisible(newItem);

		//
		// Move the dragged item and its subitems (if any) to the drop point.
		//
		/***
		
		
		newItem = MoveTree (hItem, hDragItem_);
		
		// update node2id
		//
		treeItems_.erase(hDragItem_);
		treeItems_[newItem] = dragSource->GetId();

		***/

		hDragItem_ = NULL;
	
	}

	CTreeView::OnLButtonUp(nFlags, point);
}

//DEL void CProjectTreeView::DropItem()
//DEL {
//DEL 	/***
//DEL 	HTREEITEM hParent, hTarget;
//DEL 	
//DEL 	TRACE(_T("DropItem\n"));
//DEL 
//DEL 	// get the handle to the drop target.
//DEL 	//
//DEL 	hTarget = GetTreeCtrl().GetDropHilightItem();
//DEL 
//DEL 	// get the parent of the drop target.
//DEL 	//
//DEL 	hParent = GetTreeCtrl().GetParentItem(hTarget);
//DEL 
//DEL 	// add the drag item under target
//DEL 	//
//DEL 	CXmlBaseElement* dragElement;
//DEL 	CXmlClassInfo* dragParent;
//DEL 	CXmlClassInfo* targetElement;
//DEL 	HTREEITEM hDragParent;
//DEL 	HTREEITEM hContainerNode = hTarget;
//DEL 
//DEL 	hDragParent = GetTreeCtrl().GetParentItem(hDragItem_);
//DEL 	dragElement = GetItem(hDragItem_);
//DEL 	dragParent = dynamic_cast<CXmlClassInfo*>(GetItem(hDragParent));
//DEL 	targetElement = dynamic_cast<CXmlClassInfo*>(GetItem(hTarget));
//DEL 	if (targetElement == NULL) { // if the user drops over a member element we take the parent class
//DEL 		targetElement = dynamic_cast<CXmlClassInfo*>(GetItem(hParent));
//DEL 		hContainerNode = hParent;
//DEL 	}
//DEL 
//DEL 	// TODO: manage failure when name is duplicated
//DEL 	//
//DEL 
//DEL 	if (targetElement->GetId() == dragParent->GetId())
//DEL 		return;
//DEL 
//DEL 	// add member
//DEL 	//
//DEL 	CXmlBaseElement* newElement;
//DEL 	HTREEITEM newItem;
//DEL 
//DEL 	newElement = targetElement->AddMember(*dragElement);
//DEL 	newItem = CreateNode(newElement, hContainerNode);
//DEL 	GetTreeCtrl().SortChildren(hContainerNode);
//DEL 	if (newElement->GetDataType() == enDataType_Class) 
//DEL 		GetTreeCtrl().SetItemImage(newItem, ICON_INDEX_CLASS, ICON_INDEX_CLASS);
//DEL 	else
//DEL 		GetTreeCtrl().SetItemImage(newItem, ICON_INDEX_MEMBER, ICON_INDEX_MEMBER);
//DEL 	
//DEL 	RemoveItem(hDragItem_);
//DEL 	hDragItem_ = NULL;
//DEL 
//DEL 	// select new node
//DEL 	//
//DEL 	GetTreeCtrl().SelectItem(newItem);
//DEL 
//DEL 	RedrawWindow();
//DEL 
//DEL   ***/
//DEL }

//DEL void CProjectTreeView::EndDrag()
//DEL {
//DEL 	TRACE(_T("EndDrag\n"));
//DEL 	// inform the image list that dragging has stopped.
//DEL 	//
//DEL 	dragImageList_->EndDrag();
//DEL 	delete dragImageList_;
//DEL 	dragImageList_ = NULL;
//DEL 
//DEL 	// release the mouse capture.
//DEL 	//
//DEL 	ReleaseCapture();
//DEL 
//DEL 	isDragging_ = false; 	
//DEL }

void CProjectTreeView::RemoveItem(HTREEITEM item)
{
	HTREEITEM parentNode;
	HTREEITEM selNode;
	CXmlBaseElement* selElement;
	CXmlClassInfo* parentClass;

	selElement = GetItem(item);
	if (selElement == NULL)
		return;

	selNode = GetTreeItemById(selElement->GetId());
	parentNode = GetTreeCtrl().GetParentItem(selNode);
	
	// remove item from internal map
	//
	treeItems_.erase(item);

	// delete item from treeCtrl
	//
	GetTreeCtrl().DeleteItem(selNode);
	
	parentClass = dynamic_cast<CXmlClassInfo*>(GetDocument()->GetElementById(treeItems_[parentNode]));
	parentClass->RemoveMemberById(selElement->GetId());
}

bool CProjectTreeView::IsChildOf(HTREEITEM hItem1, HTREEITEM hItem2)
{
	HTREEITEM hParent = hItem1;
	while ((hParent = GetTreeCtrl().GetParentItem (hParent)) != NULL) {
		if (hParent == hItem2)
			return true;
	}
	return false;
}

HTREEITEM CProjectTreeView::MoveTree(HTREEITEM hDest, HTREEITEM hSrc)
{
	HTREEITEM newItem;

	newItem = CopyTree (hDest, hSrc);
	GetTreeCtrl().DeleteItem(hSrc);

	return newItem;
}

HTREEITEM CProjectTreeView::CopyTree(HTREEITEM hDest, HTREEITEM hSrc)
{
	//
	// Get the attributes of item to be copied.
	//
	int nImage, nSelectedImage;
	GetTreeCtrl().GetItemImage (hSrc, nImage, nSelectedImage);
	CString string = GetTreeCtrl().GetItemText (hSrc);

	//
	// Create an exact copy of the item at the destination.
	//
	HTREEITEM hNewItem = GetTreeCtrl().InsertItem (string, nImage, nSelectedImage, hDest);

	//
	// If the item has subitems, copy them, too.
	//
	if (GetTreeCtrl().ItemHasChildren (hSrc))
		CopyChildren (hNewItem, hSrc);

	//
	// Select the newly added item.
	//
	GetTreeCtrl().SelectItem(hNewItem);

	return hNewItem;
}

void CProjectTreeView::CopyChildren(HTREEITEM hDest, HTREEITEM hSrc)
{
	//
	// Get the first subitem.
	//
	HTREEITEM hItem = GetTreeCtrl().GetChildItem (hSrc);
	ASSERT (hItem != NULL);

	//
	// Create a copy of it at the destination.
	//
	int nImage, nSelectedImage;
	GetTreeCtrl().GetItemImage (hItem, nImage, nSelectedImage);
	CString string = GetTreeCtrl().GetItemText (hItem);
	HTREEITEM hNewItem = GetTreeCtrl().InsertItem (string, nImage, nSelectedImage, hDest);

	//
	// If the subitem has subitems, copy them, too.
	//
	if (GetTreeCtrl().ItemHasChildren (hItem))
		CopyChildren (hNewItem, hItem);

	//
	// Do the same for other subitems of hSrc.
	//
	while ((hItem = GetTreeCtrl().GetNextSiblingItem (hItem)) != NULL) {
		GetTreeCtrl().GetItemImage (hItem, nImage, nSelectedImage);
		string = GetTreeCtrl().GetItemText (hItem);
		hNewItem = GetTreeCtrl().InsertItem (string, nImage, nSelectedImage, hDest);
		if (GetTreeCtrl().ItemHasChildren (hItem))
			CopyChildren (hNewItem, hItem);
	}
}

BOOL CProjectTreeView::IsItemExpanded(HTREEITEM hItem)
{
	return GetTreeCtrl().GetItemState (hItem, TVIS_EXPANDED) & TVIS_EXPANDED;
}

HTREEITEM CProjectTreeView::HighlightDropTarget(CPoint point)
{
	//
	// Find out which item (if any) the cursor is over.
	//
	UINT nFlags;
	HTREEITEM hItem = GetTreeCtrl().HitTest (point, &nFlags);

	//
	// Highlight the item, or unhighlight all items if the cursor isn't
	// over an item.
	//
	dragImageList_->DragShowNolock (FALSE);
	GetTreeCtrl().SelectDropTarget(hItem);
	dragImageList_->DragShowNolock (TRUE);

	//
	// Return the handle of the highlighted item.
	//
	return hItem;
}

void CProjectTreeView::OnTimer(UINT nIDEvent) 
{
	CTreeView::OnTimer(nIDEvent);

	//
	// Reset the timer.
	//
	SetTimer (1, scrollInterval_, NULL);

	//
	// Get the current cursor position and window height.
	//
	DWORD dwPos = ::GetMessagePos ();
	CPoint point (LOWORD (dwPos), HIWORD (dwPos));
	ScreenToClient (&point);

	CRect rect;
	GetClientRect (rect);
	int cy = rect.Height ();

	//
	// Scroll the window if the cursor is near the top or bottom.
	//
	if (point.y >= 0 && point.y <= scrollMargin_) {
		HTREEITEM hFirstVisible = GetTreeCtrl().GetFirstVisibleItem ();
		dragImageList_->DragShowNolock (FALSE);
		SendMessage (WM_VSCROLL, MAKEWPARAM (SB_LINEUP, 0), NULL);
		dragImageList_->DragShowNolock (TRUE);

		//
		// Kill the timer if the window did not scroll, or redraw the
		// drop target highlight if the window did scroll.
		//
		if (GetTreeCtrl().GetFirstVisibleItem () == hFirstVisible)
			KillTimer (1);
		else {
			HighlightDropTarget (point);
			return;
		}
	}
	else if (point.y >= cy - scrollMargin_ && point.y <= cy) {
		HTREEITEM hFirstVisible = GetTreeCtrl().GetFirstVisibleItem ();
		dragImageList_->DragShowNolock (FALSE);
		SendMessage(WM_VSCROLL, MAKEWPARAM (SB_LINEDOWN, 0), NULL);
		dragImageList_->DragShowNolock (TRUE);

		//
		// Kill the timer if the window did not scroll, or redraw the
		// drop target highlight if the window did scroll.
		//
		if (GetTreeCtrl().GetFirstVisibleItem () == hFirstVisible)
			KillTimer (1);
		else {
			HighlightDropTarget (point);
			return;
		}
	}

	//
	// If the cursor is hovering over a collapsed item, expand the tree.
	//
	UINT nFlags;
	HTREEITEM hItem = GetTreeCtrl().HitTest (point, &nFlags);

	if (hItem != NULL && GetTreeCtrl().ItemHasChildren (hItem) && !IsItemExpanded (hItem) && isDragging_) {
		dragImageList_->DragShowNolock (FALSE);
		GetTreeCtrl().Expand (hItem, TVE_EXPAND);
		dragImageList_->DragShowNolock (TRUE);
		KillTimer (1);
		return;
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Italy Italy
For all Stefano's latest code, binaries and tutorials visit www.codemachines.com

Comments and Discussions