// 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;
}
}