// MyTreeCtrl.cpp : implementation file
//
#include "stdafx.h"
#include "TreeEditor.h"
#include "TreeEditorDoc.h"
#include "TreeEditorView.h"
#include "MyTreeCtrl.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
extern CTreeEditorApp theApp;
/////////////////////////////////////////////////////////////////////////////
// CEditTreeCtrl
CEditTreeCtrl::CEditTreeCtrl()
{
int aid[] =
{
IDC_DROP_COPY_ROOT,
IDC_DROP_COPY_SON,
IDC_DROP_MOVE_ABOVE,
IDC_DROP_COPY_ABOVE,
IDC_DROP_MOVE_ROOT,
IDC_DROP_MOVE_SON,
IDC_NODROP,
}, k;
ASSERT(ARRAY_SIZE(aid) == CUR_COUNT);
m_pted = NULL;
m_uLimitText = 0;
m_bDragging = FALSE;
m_pimagelist = NULL;
m_bInsertionMode = false;
m_hCursor = NULL;
for (k = 0; k < CUR_COUNT; k++)
m_ahCursor[k] = theApp.LoadCursor(aid[k]);
}
BEGIN_MESSAGE_MAP(CEditTreeCtrl, CTreeCtrl)
//{{AFX_MSG_MAP(CEditTreeCtrl)
ON_COMMAND(ID_COLLAPSE_ALL_ENTIRE_TREE, OnCollapseAllEntireTree)
ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBegindrag)
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_DESTROY()
ON_WM_SETCURSOR()
ON_WM_TIMER()
ON_COMMAND(IDC_COUNT_ENTIRE_TREE, OnCountEntireTree)
ON_COMMAND(IDC_COUNT_SUBTREE, OnCountSubtree)
ON_NOTIFY_REFLECT(TVN_ITEMEXPANDED, OnItemexpanded)
ON_COMMAND(ID_CALCULATE_LEVEL, OnCalculateLevel)
ON_NOTIFY_REFLECT(TVN_BEGINLABELEDIT, OnBeginlabeledit)
ON_NOTIFY_REFLECT(TVN_ENDLABELEDIT, OnEndlabeledit)
ON_WM_CONTEXTMENU()
ON_NOTIFY_REFLECT(NM_RCLICK, OnRclick)
ON_COMMAND(ID_RENAME, OnRename)
ON_COMMAND(ID_ADD_CHILD, OnAddChild)
ON_COMMAND(ID_ADD_SIBLING, OnAddSibling)
ON_COMMAND(ID_DELETE_ITEM, OnDeleteItem)
ON_COMMAND(ID_DELETE_ALL_ITEMS, OnDeleteAllItems)
ON_COMMAND(IDC_EXPAND_ALL_TREE, OnExpandAllTree)
ON_COMMAND(ID_SORT_SUBTREE_ALPHABETIC, OnSortSubtreeAlphabetic)
ON_COMMAND(ID_SORT_SUBTREE_NUMERIC, OnSortSubtreeNumeric)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CEditTreeCtrl message handlers
/***********************************************************************************
* Keyboard Handling
***********************************************************************************/
BOOL CEditTreeCtrl::PreTranslateMessage(MSG* pMsg)
{
// When an item is being edited make sure the edit control
// receives certain important key strokes
if (GetEditControl())
{
if(pMsg->message == WM_KEYDOWN)
{
if (pMsg->wParam == VK_INSERT)
{
// If VK_INSERT was preessed in course of editing, we want to cause
// the program to add another sibling. Therefore, we simulate pressing of
// VK_RETURN.
m_bInsertionMode = true;
pMsg->wParam = VK_RETURN;
}
else
m_bInsertionMode = false;
}
::TranslateMessage(pMsg);
::DispatchMessage(pMsg);
return TRUE; // DO NOT process further
}
if (m_bDragging &&
(pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP))
{
if (pMsg->wParam == VK_ESCAPE)
{ // Cancel Drag Mode
m_bDragging = false;
ReleaseCapture();
SelectDropTarget(NULL);
m_hCursor = NULL;
}
POINT pt;
GetCursorPos(&pt);
// Cause MouseMove() (and as a result OnSetCursor()) to be called.
SetCursorPos(pt.x, pt.y);
return true;
}
if (pMsg->message == WM_KEYDOWN)
{
switch(pMsg->wParam)
{
case 'C':
if (GetKeyState(VK_CONTROL) & 0x80000000)
OnSaveSubtree();
break;
case 'A':
// Ctrl+A Paste m_ttTransfer above current item
if (GetKeyState(VK_CONTROL) & 0x80000000)
OnLoadAbove(GetSelectedItem());
break;
case 'V':
// Ctrl+V Paste m_ttTransfer as a son of current item
// Ctrl+Shift+V Paste m_ttTransfer as a new root
if (GetKeyState(VK_CONTROL) & 0x80000000)
{
if (GetKeyState(VK_SHIFT) & 0x80000000)
OnLoadSubtree(TVI_ROOT);
else
OnLoadSubtree(GetSelectedItem());
}
break;
case 'X':
if (GetKeyState(VK_CONTROL) & 0x80000000)
CutSubtree();
break;
case 'N':
// Ctrl+N Count Subtree
// Ctrl+Shift+N Count entire tree
if (GetKeyState(VK_CONTROL) & 0x80000000)
{
if (GetKeyState(VK_SHIFT) & 0x80000000)
OnCountEntireTree();
else
OnCountSubtree();
}
break;
case 'T':
// Ctrl+T Sort Subtree Alphabetic
// Ctrl+Shift+T Sort Subtree Numeric
if (GetKeyState(VK_CONTROL) & 0x80000000)
{
if (GetKeyState(VK_SHIFT) & 0x80000000)
OnSortSubtreeNumeric();
else
OnSortSubtreeAlphabetic();
}
break;
case 'L':
if (GetKeyState(VK_CONTROL) & 0x80000000)
OnCalculateLevel();
break;
case VK_SPACE:
case VK_RETURN:
OnAddSibling();
break;
case VK_INSERT:
if (GetKeyState(VK_CONTROL) & 0x80000000)
OnSaveEntireTree(FF_CLIPBOARD_TYPE, m_pted->m_tt);
else if (GetKeyState(VK_SHIFT) & 0x80000000)
OnLoadEntireTree(FF_CLIPBOARD_TYPE, m_pted->m_tt);
else
OnAddChild();
break;
case VK_F2:
OnRename();
break;
case VK_DELETE:
if (GetKeyState(VK_CONTROL) & 0x80000000)
OnDeleteAllItems();
else
OnDeleteItem();
break;
default:
// Default behaviour for other keys such as arrows
return CTreeCtrl::PreTranslateMessage(pMsg);
}
return TRUE; // DO NOT process further
}
return CTreeCtrl::PreTranslateMessage(pMsg);
}
/***********************************************************************************
* Context-Menu Handling
***********************************************************************************/
void CEditTreeCtrl::OnRclick(NMHDR* pNMHDR, LRESULT* pResult)
{
//Work out the position of where the context menu should be
CPoint p(GetCurrentMessage()->pt);
CPoint pt(p);
ScreenToClient(&pt);
Select(HitTest(pt), TVGN_CARET);
OnContextMenu(NULL, p);
*pResult = 0;
}
void CEditTreeCtrl::OnContextMenu(CWnd* pWnd, CPoint point)
{
CMenu menu;
VERIFY(menu.LoadMenu(IDR_POPUP_MENU));
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
}
/***********************************************************************************
* Functions to handle Drag and drop to Copy/Move/Paste items
***********************************************************************************/
void CEditTreeCtrl::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult)
{
CPoint ptAction;
NMTREEVIEW *pnmtv;
GetCursorPos(&ptAction);
ScreenToClient(&ptAction);
ASSERT(!m_bDragging);
m_bDragging = TRUE;
m_bTimerABOVE_Active = false;
m_bTimerBELOW_Active = false;
m_uOldFlags = 0;
// determine the item being dragged:
pnmtv = (NMTREEVIEW*)pNMHDR;
m_hitemDrag = pnmtv->itemNew.hItem;
m_hitemDrop = NULL;
SetCapture();
SelectDropCursor();
}
void CEditTreeCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
HTREEITEM hitem;
if (m_bDragging)
{
hitem = SelectDropCursor(&point);
if (hitem != NULL)
{
SelectDropTarget(hitem);
m_hitemDrop = hitem;
}
}
CTreeCtrl::OnMouseMove(nFlags, point);
}
void CEditTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
OnButtonUp();
CTreeCtrl::OnLButtonUp(nFlags, point);
}
void CEditTreeCtrl::OnButtonUp()
{
/************************************************************************************
Ensure m_ttTransfer is always allocated and deallocated correctly:
*************************************************************************************
1) This function allocates a CTreeType.
2) The CTreeType is used to save data from the TreeControl. This is done
in SaveTreeData()
3) At the end of the function, the CTreeType is deallocated.
************************************************************************************/
int iCount;
if (m_bDragging)
{
m_bDr