|
|
/////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1996-1997 Microsoft Corporation
//
// Module Name:
// TreeView.cpp
//
// Abstract:
// Implementation of the CClusterTreeView class.
//
// Author:
// David Potter (davidp) May 1, 1996
//
// Revision History:
//
// Notes:
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CluAdmin.h"
#include "ConstDef.h"
#include "ClusDoc.h"
#include "TreeView.h"
#include "ListView.h"
#include "SplitFrm.h"
#include "TreeItem.inl"
#include "TraceTag.h"
#include "ExcOper.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
/////////////////////////////////////////////////////////////////////////////
// Global Variables
/////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
CTraceTag g_tagTreeView(_T("UI"), _T("TREE VIEW"), 0); CTraceTag g_tagTreeDrag(_T("Drag&Drop"), _T("TREE VIEW DRAG"), 0); CTraceTag g_tagTreeDragMouse(_T("Drag&Drop"), _T("TREE VIEW DRAG MOUSE"), 0); CTraceTag g_tagTreeViewSelect(_T("UI"), _T("TREE VIEW SELECT"), 0); #endif
/////////////////////////////////////////////////////////////////////////////
// CClusterTreeView
/////////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CClusterTreeView, CTreeView)
/////////////////////////////////////////////////////////////////////////////
// Message Maps
BEGIN_MESSAGE_MAP(CClusterTreeView, CTreeView) //{{AFX_MSG_MAP(CClusterTreeView)
ON_WM_DESTROY() ON_COMMAND(ID_FILE_RENAME, OnCmdRename) ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelChanged) ON_NOTIFY_REFLECT(TVN_BEGINLABELEDIT, OnBeginLabelEdit) ON_NOTIFY_REFLECT(TVN_ENDLABELEDIT, OnEndLabelEdit) ON_NOTIFY_REFLECT(TVN_ITEMEXPANDED, OnItemExpanded) ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBeginDrag) ON_NOTIFY_REFLECT(TVN_BEGINRDRAG, OnBeginDrag) ON_NOTIFY_REFLECT(TVN_KEYDOWN, OnKeyDown) //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::CClusterTreeView
//
// Routine Description:
// Default constructor.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
CClusterTreeView::CClusterTreeView(void) { m_pframe = NULL;
// Initialize label editing.
m_ptiBeingEdited = NULL; m_bShiftPressed = FALSE; m_bControlPressed = FALSE; m_bAltPressed = FALSE;
// Initialize drag & drop.
m_htiDrag = NULL; m_ptiDrag = NULL; m_htiDrop = NULL;
} //*** CClusterTreeView::CClusterTreeView()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::~CClusterTreeView
//
// Routine Description:
// Destructor.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
CClusterTreeView::~CClusterTreeView(void) { } //*** CClusterTreeView::~CClusterTreeView()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::PreCreateWindow
//
// Routine Description:
// Called before the window has been created.
//
// Arguments:
// cs CREATESTRUCT
//
// Return Value:
// TRUE Successful.
// FALSE Failed.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterTreeView::PreCreateWindow(CREATESTRUCT & cs) { // TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CTreeView::PreCreateWindow(cs);
} //*** CClusterTreeView::PreCreateWindow()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::Create
//
// Routine Description:
// Create the window.
//
// Arguments:
// lpszClassName [IN] Name of the window class to create.
// lpszWindowName [IN] Name of the window (used as the caption).
// dwStyle [IN] Window styles.
// rect [IN] Size and position of the window
// pParentWnd [IN OUT] Parent window.
// nID [IN] ID of the window.
// pContext [IN OUT] Create context of the window.
//
// Return Value:
// 0 Successful.
// !0 Unsuccessful.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterTreeView::Create( LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT & rect, CWnd * pParentWnd, UINT nID, CCreateContext * pContext ) { dwStyle |= TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_EDITLABELS | TVS_SHOWSELALWAYS; return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
} //*** CClusterTreeView::Create()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::OnDraw
//
// Routine Description:
// Called to draw the view.
//
// Arguments:
// pDC [IN OUT] Device Context for the view.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::OnDraw(IN OUT CDC* pDC) { #if 0
CClusterDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
#endif
} //*** CClusterTreeView::OnDraw()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::OnInitialUpdate
//
// Routine Description:
// Do one-time initialization.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::OnInitialUpdate(void) { CClusterAdminApp * papp = GetClusterAdminApp(); CClusterDoc * pdocCluster = GetDocument(); CString strSelection;
CTreeView::OnInitialUpdate();
// Save the frame pointer.
// ASSERT(m_pframe == NULL);
m_pframe = (CSplitterFrame *) GetParentFrame(); ASSERT_VALID(m_pframe); ASSERT_KINDOF(CSplitterFrame, m_pframe);
// Tell the tree control about our images. We are using the
// same image list for both normal and state images.
GetTreeCtrl().SetImageList(papp->PilSmallImages(), TVSIL_NORMAL); // GetTreeCtrl().SetImageList(papp->PilSmallImages(), TVSIL_STATE);
// Read the last selection.
ReadPreviousSelection(strSelection);
// Recursively add items starting with the cluster.
BAddItems(pdocCluster->PtiCluster(), strSelection, TRUE /*bExpanded*/);
// Expand the Cluster item by default.
// pdocCluster->PtiCluster()->BExpand(this, TVE_EXPAND);
} //*** CClusterTreeView::OnInitialUpdate()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::BAddItems
//
// Routine Description:
// Add an item and then add all its children.
//
// Arguments:
// pti [IN OUT] Item to add to the tree.
// rstrSelection [IN] Previous selection.
// bExpanded [IN] TRUE = add expanded.
//
// Return Value:
// TRUE Parent needs to be expanded.
// FALSE Parent does not need to be expanded.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterTreeView::BAddItems( IN OUT CTreeItem * pti, IN const CString & rstrSelection, IN BOOL bExpanded // = FALSE
) { POSITION posChild; CTreeItem * ptiChild; BOOL bRetExpanded = FALSE;
ASSERT_VALID(pti);
// Insert this item into the tree.
pti->HtiInsertInTree(this); if (bExpanded || pti->BShouldBeExpanded(this)) bRetExpanded = TRUE;
// Add all the child items.
posChild = pti->LptiChildren().GetHeadPosition(); while (posChild != NULL) { ptiChild = pti->LptiChildren().GetNext(posChild); ASSERT_VALID(ptiChild); bExpanded = BAddItems(ptiChild, rstrSelection); if (bExpanded) bRetExpanded = TRUE; } // while: more child items
if (bRetExpanded) pti->BExpand(this, TVE_EXPAND);
if (rstrSelection == pti->StrProfileSection()) { pti->Select(this, TRUE /*bSelectInTrue*/); bRetExpanded = TRUE; } // if: this is the selected item
return bRetExpanded;
} //*** CClusterTreeView::BAddItems()
#ifdef NEVER
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::CleanupItems
//
// Routine Description:
// Cleanup an item and all its children.
//
// Arguments:
// ptiParent [IN OUT] Parent item to cleanup.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::CleanupItems(IN OUT CTreeItem * ptiParent) { POSITION posChild; CTreeItem * ptiChild;
// Cleanup all child items.
if (ptiParent != NULL) { posChild = ptiParent->LptiChildren().GetHeadPosition(); while (posChild != NULL) { ptiChild = ptiParent->LptiChildren().GetNext(posChild); ASSERT_VALID(ptiChild); CleanupItems(ptiChild); } // while: more items in the list
// Cleanup this item.
ptiParent->PreRemoveFromTree(this); } // if: parent was specified
} //*** CClusterTreeView::CleanupItems()
#endif
/////////////////////////////////////////////////////////////////////////////
// CClusterTreeView diagnostics
#ifdef _DEBUG
void CClusterTreeView::AssertValid(void) const { CTreeView::AssertValid();
} //*** CClusterTreeView::AssertValid()
void CClusterTreeView::Dump(CDumpContext & dc) const { CTreeView::Dump(dc);
} //*** CClusterTreeView::Dump()
CClusterDoc * CClusterTreeView::GetDocument(void) // non-debug version is inline
{ ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CClusterDoc))); return (CClusterDoc *) m_pDocument;
} //*** CClusterTreeView::GetDocument()
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::PtiSelected
//
// Routine Description:
// Get the tree item that is selected.
//
// Arguments:
// None.
//
// Return Value:
// ptiSelected The selected item or NULL if no item is selected.
//
//--
/////////////////////////////////////////////////////////////////////////////
CTreeItem * CClusterTreeView::PtiSelected(void) const { HTREEITEM htiSelected; CTreeItem * ptiSelected;
htiSelected = HtiSelected(); if (htiSelected != NULL) { ptiSelected = (CTreeItem *) GetTreeCtrl().GetItemData(htiSelected); ASSERT_VALID(ptiSelected); } // if: selected item found
else ptiSelected = NULL;
return ptiSelected;
} //*** CClusterTreeView::PtiSelected()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::SaveCurrentSelection
//
// Routine Description:
// Save the current selection.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::SaveCurrentSelection(void) { CTreeItem * ptiSelected = PtiSelected();
if (ptiSelected != NULL) { CString strSection; CString strValueName;
ASSERT_VALID(Pframe());
try { strSection.Format( REGPARAM_CONNECTIONS _T("\\%s"), GetDocument()->StrNode() );
Pframe()->ConstructProfileValueName(strValueName, REGPARAM_SELECTION);
AfxGetApp()->WriteProfileString( strSection, strValueName, ptiSelected->StrProfileSection() ); } // try
catch (CException * pe) { pe->Delete(); } // catch: CException
} // if: there is a current selection
} //*** CClusterTreeView::SaveCurrentSelection()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::ReadPreviousSelection
//
// Routine Description:
// Read the previous selection.
//
// Arguments:
// rstrSelection [OUT] Previous selection read from the user's profile.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::ReadPreviousSelection(OUT CString & rstrSelection) { CString strSection; CString strValueName;
ASSERT_VALID(Pframe());
try { // Get the selected item.
strSection.Format( REGPARAM_CONNECTIONS _T("\\%s"), GetDocument()->StrNode() );
Pframe()->ConstructProfileValueName(strValueName, REGPARAM_SELECTION);
rstrSelection = AfxGetApp()->GetProfileString( strSection, strValueName, _T("") ); } // try
catch (CException * pe) { pe->Delete(); } // catch: CException
} //*** CClusterTreeView::ReadPreviousSelection()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::OnSelChanged
//
// Routine Description:
// Handler method for the TVN_SELCHANGED message.
//
// Arguments:
// pNMHDR [IN OUT] WM_NOTIFY structure.
// pResult [OUT] LRESULT in which to return the result of this operation.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::OnSelChanged(NMHDR * pNMHDR, LRESULT * pResult) { NM_TREEVIEW * pNMTreeView = (NM_TREEVIEW *) pNMHDR; CTreeItem * ptiSelected;
if (!BDragging()) { Trace(g_tagTreeViewSelect, _T("OnSelChanged() - BEGIN"));
// Get the selected item.
ptiSelected = (CTreeItem *) pNMTreeView->itemNew.lParam; ASSERT_VALID(ptiSelected);
// Ask the list view to display the items for this tree item.
ASSERT_VALID(ptiSelected->Pci()); Trace(g_tagTreeViewSelect, _T("OnSelChanged() - '%s' selected"), ptiSelected->Pci()->StrName()); ptiSelected->Select(this, FALSE /*bSelectInTree*/);
// Tell the document of the new selection.
if (m_pDocument != NULL) // this happens on system shutdown
GetDocument()->OnSelChanged(ptiSelected->Pci());
*pResult = 0; Trace(g_tagTreeViewSelect, _T("OnSelChanged() - END")); } // if: not dragging
} //*** CClusterTreeView::OnSelChanged()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::OnCmdMsg
//
// Routine Description:
// Processes command messages. Attempts to pass them on to a selected
// item first.
//
// Arguments:
// nID [IN] Command ID.
// nCode [IN] Notification code.
// pExtra [IN OUT] Used according to the value of nCode.
// pHandlerInfo [OUT] ???
//
// Return Value:
// TRUE Message has been handled.
// FALSE Message has NOT been handled.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterTreeView::OnCmdMsg( UINT nID, int nCode, void * pExtra, AFX_CMDHANDLERINFO * pHandlerInfo ) { BOOL bHandled = FALSE;
// If there is a current item selected, give it a chance
// to handle the message.
if (HtiSelected() != NULL) bHandled = PtiSelected()->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
if (!bHandled) bHandled = CTreeView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
return bHandled;
} //*** CClusterTreeView::OnCmdMsg()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::PmenuPopup
//
// Routine Description:
// Returns a popup menu.
//
// Arguments:
// rpointScreen [IN OUT] Position of the cursor, in screen coordinates.
// rpci [OUT] Pointer in which to return associated cluster item.
//
// Return Value:
// pmenu A popup menu for the item.
//
//--
/////////////////////////////////////////////////////////////////////////////
CMenu * CClusterTreeView::PmenuPopup( IN OUT CPoint & rpointScreen, OUT CClusterItem *& rpci ) { CTreeItem * pti = NULL; CMenu * pmenu = NULL;
rpci = NULL;
// If there are no coordinates (-1,-1), display a menu for the selected item.
if ((rpointScreen.x == -1) && (rpointScreen.y == -1)) { CRect rect; CTreeItem * ptiSelected = PtiSelected();
if ((ptiSelected != NULL) && GetTreeCtrl().GetItemRect(HtiSelected(), &rect, FALSE)) { pti = ptiSelected; } // if: selected item and it is visible
else GetWindowRect(&rect); rpointScreen.x = (rect.right - rect.left) / 2; rpointScreen.y = (rect.bottom - rect.top) / 2; ClientToScreen(&rpointScreen); } // if: no coordinates
else { CPoint pointClient; HTREEITEM hti; UINT uiFlags;
// Get the coordinates of the point where the user clicked the right mouse
// button. We need in both screen and client coordinates.
pointClient = rpointScreen; ScreenToClient(&pointClient);
// Get the item under the cursor and get its popup menu.
hti = GetTreeCtrl().HitTest(pointClient, &uiFlags); if (hti != NULL) { // Get the tree item for the item under the cursor.
pti = (CTreeItem *) GetTreeCtrl().GetItemData(hti); ASSERT_VALID(pti);
// Select the item because that's the only way for it us process the menu.
pti->BSelectItem(this); } // if: on an item
} // else: coordinates specified
if (pti != NULL) { // Get a menu from the item.
pmenu = pti->PmenuPopup(); rpci = pti->Pci(); } // if: item found
return pmenu;
} //*** CClusterTreeView::PmenuPopup()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::OnActivateView
//
// Routine Description:
// Called when the view is activated.
//
// Arguments:
// bActivate [IN] Indicates whether the view being activated or deactivated.
// pActivateView [IN OUT] Points to the view object that is being activated.
// peactiveView [IN OUT] Points to the view object that is being deactivated.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::OnActivateView( BOOL bActivate, CView * pActivateView, CView * pDeactiveView ) { CTreeItem * ptiSelected = PtiSelected();
if (m_pDocument != NULL) // this happens on system shutdown
{ if (bActivate && (ptiSelected != NULL)) { ASSERT_VALID(ptiSelected->Pci()); Trace(g_tagTreeViewSelect, _T("OnActiveView: '%s' selected"), ptiSelected->Pci()->StrName());
// Tell the document of the new selection.
GetDocument()->OnSelChanged(ptiSelected->Pci()); } // if: we are being activated
} // if: document is available
CTreeView::OnActivateView(bActivate, pActivateView, pDeactiveView);
} //*** CClusterTreeView::OnActivateView()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::OnDestroy
//
// Routine Description:
// Handler method for the WM_DESTROY message.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::OnDestroy(void) { // Clean up the control.
if (m_pDocument != NULL) // this happens on system shutdown
{ // Save the currently selected item.
SaveCurrentSelection();
// Cleanup after ourselves.
// CleanupItems(GetDocument()->PtiCluster());
} // if: the document is still available
CTreeView::OnDestroy();
} //*** CClusterTreeView::OnDestroy()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::OnItemExpanded
//
// Routine Description:
// Handler method for the TVN_ITEMEXPANDED message.
//
// Arguments:
// pNMHDR Notification message structure.
// pResult Place in which to return the result.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::OnItemExpanded(NMHDR * pNMHDR, LRESULT * pResult) { NM_TREEVIEW * pNMTreeView = (NM_TREEVIEW *) pNMHDR;
if (pNMTreeView->itemNew.mask & TVIF_STATE) { BOOL bExpanded; CTreeItem * pti;
bExpanded = (pNMTreeView->itemNew.state & TVIS_EXPANDED) != 0; ASSERT(pNMTreeView->itemNew.mask & TVIF_PARAM); pti = (CTreeItem *) pNMTreeView->itemNew.lParam; ASSERT_VALID(pti); ASSERT_KINDOF(CTreeItem, pti); pti->SetExpandedState(this, bExpanded); } // if: expanded state changed.
*pResult = 0;
} //*** CClusterTreeView::OnItemExpanded()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::OnBeginLabelEdit
//
// Routine Description:
// Handler method for the TVN_BEGINLABELEDIT message.
//
// Arguments:
// pNMHDR Notification message structure.
// pResult Place in which to return the result.
// TRUE = don't edit, FALSE = edit.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::OnBeginLabelEdit(NMHDR * pNMHDR, LRESULT * pResult) { ASSERT(pNMHDR != NULL);
TV_DISPINFO * pTVDispInfo = (TV_DISPINFO *) pNMHDR; CTreeItem * pti = (CTreeItem *) pTVDispInfo->item.lParam;
ASSERT(m_ptiBeingEdited == NULL); ASSERT_VALID(pti); ASSERT_VALID(pti->Pci());
if (!BDragging() && pti->Pci()->BCanBeEdited()) { pti->Pci()->OnBeginLabelEdit(GetTreeCtrl().GetEditControl()); m_ptiBeingEdited = pti; *pResult = FALSE; } // if: not dragging and object can be edited
else *pResult = TRUE;
m_bShiftPressed = FALSE; m_bControlPressed = FALSE; m_bAltPressed = FALSE;
} //*** CClusterTreeView::OnBeginLabelEdit()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::OnEndLabelEdit
//
// Routine Description:
// Handler method for the TVN_ENDLABELEDIT message.
//
// Arguments:
// pNMHDR Notification message structure.
// pResult Place in which to return the result.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::OnEndLabelEdit(NMHDR * pNMHDR, LRESULT * pResult) { ASSERT(pNMHDR != NULL);
TV_DISPINFO * pTVDispInfo = (TV_DISPINFO *) pNMHDR; CTreeItem * pti = (CTreeItem *) pTVDispInfo->item.lParam;
ASSERT_VALID(pti); ASSERT(pti == m_ptiBeingEdited); ASSERT_VALID(pti->Pci());
// If the edit wasn't cancelled, rename it.
if (pTVDispInfo->item.mask & LVIF_TEXT) { ASSERT(pti->Pci()->BCanBeEdited()); ASSERT(pTVDispInfo->item.pszText != NULL);
Trace(g_tagTreeView, _T("Ending edit of item '%s' (Saving as '%s')"), pti->Pci()->StrName(), pTVDispInfo->item.pszText);
if ( pti->Pci()->BIsLabelEditValueValid( pTVDispInfo->item.pszText ) ) { try { pti->Pci()->Rename(pTVDispInfo->item.pszText); *pResult = TRUE; } // try
catch (CException * pe) { pe->ReportError(); pe->Delete(); *pResult = FALSE; } // catch: CException
} // if: name is valid
else { *pResult = FALSE; } } // if: the edit wasn't cancelled
else { Trace(g_tagTreeView, _T("Ending edit of item '%s' (Not Saving)"), pti->Pci()->StrName()); *pResult = TRUE; } // else: edit was cancelled
m_ptiBeingEdited = NULL; m_bShiftPressed = FALSE; m_bControlPressed = FALSE; m_bAltPressed = FALSE;
} //*** CClusterTreeView::OnEndLabelEdit()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::OnBeginDrag
//
// Routine Description:
// Handler method for the TVN_BEGINDRAG and TVN_BEGINRDRAG messages.
//
// Arguments:
// pNMHDR Notification message structure.
// pResult Place in which to return the result.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::OnBeginDrag(NMHDR * pNMHDR, LRESULT * pResult) { CTreeCtrl & rtc = GetTreeCtrl(); CPoint ptScreen; CPoint ptFrame; CPoint ptView; UINT nFlags; CClusterItem * pci = NULL; CImageList * pimagelist;
ASSERT_VALID(Pframe());
// Get the current cursor position for identifying the item being dragged.
GetCursorPos(&ptScreen); ptFrame = ptScreen; Pframe()->ScreenToClient(&ptFrame); ptView = ptScreen; rtc.ScreenToClient(&ptView);
// Get the item being dragged.
{ HTREEITEM hti; CTreeItem * pti;
hti = rtc.HitTest(ptView, &nFlags); if (hti == NULL) return;
pti = (CTreeItem *) rtc.GetItemData(hti); ASSERT_VALID(pti); ASSERT_KINDOF(CTreeItem, pti); ASSERT_VALID(pti->Pci());
// If the item can not be dragged, abort the operation.
if (!pti->Pci()->BCanBeDragged()) return;
// Save info for later.
m_htiDrag = hti; m_ptiDrag = pti; m_htiDrop = NULL; pci = pti->Pci(); } // Get the item being dragged
Trace(g_tagTreeDrag, _T("OnBeginDrag() - Dragging '%s' at (%d,%d)"), m_ptiDrag->StrName(), ptFrame.x, ptFrame.y);
// Create an image list for the image being dragged.
pimagelist = rtc.CreateDragImage(m_htiDrag);
// Let the frame window initialize the drag operation.
Pframe()->BeginDrag(pimagelist, pci, ptFrame, CPoint(0, -16));
*pResult = 0;
} //*** CClusterTreeView::OnBeginDrag(pNMHDR, pResult)
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::OnMouseMoveForDrag
//
// Routine Description:
// Handler method for the WM_MOUSEMOVE message during a drag operation.
// This function is only responsible for providing view-specific
// functionality, such as selecting the drop target if it is valid.
//
// Arguments:
// nFlags Indicates whether various virtual keys are down.
// point Specifies the x- and y-coordinate of the cursor in frame
// coordinates.
// pwndDrop Specifies the window under the cursor.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::OnMouseMoveForDrag( IN UINT nFlags, IN CPoint point, IN const CWnd * pwndDrop ) { ASSERT(BDragging()); ASSERT_VALID(Pframe());
// If we are dragging, select the drop target.
if (BDragging()) { HTREEITEM hti; UINT flags; CPoint ptView; CTreeCtrl & rtc = GetTreeCtrl();
// Convert the point to view coordinates.
ptView = point; Pframe()->ClientToScreen(&ptView); rtc.ScreenToClient(&ptView);
// If this window is the drop target, find the item under the cursor.
if (pwndDrop == &rtc) { // If we are over a tree item, highlight it.
hti = rtc.HitTest(ptView, &flags); if (hti != NULL) { CTreeItem * pti;
// Get the item to be highlight.
pti = (CTreeItem *) rtc.GetItemData(hti); ASSERT_VALID(pti); ASSERT_KINDOF(CTreeItem, pti); ASSERT_VALID(pti->Pci());
// If this is not a drop target, change the cursor.
if (pti->Pci()->BCanBeDropTarget(Pframe()->PciDrag())) Pframe()->ChangeDragCursor(IDC_ARROW); else Pframe()->ChangeDragCursor(IDC_NO); } // if: over a tree item
} // if: this window is the drop target
else hti = NULL;
// Unlock window updates.
VERIFY(Pimagelist()->DragShowNolock(FALSE /*bShow*/));
// Highlight the new drop target.
rtc.SelectDropTarget(hti); m_htiDrop = hti;
VERIFY(Pimagelist()->DragShowNolock(TRUE /*bShow*/)); } // if: tree item is being dragged
} //*** CClusterTreeView::OnMouseMoveForDrag()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::OnButtonUpForDrag
//
// Routine Description:
// Called to handle a button up event during drag and drop.
//
// Arguments:
// nFlags Indicates whether various virtual keys are down.
// point Specifies the x- and y-coordinate of the cursor.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::OnButtonUpForDrag(IN UINT nFlags, IN CPoint point) { ASSERT(BDragging()); ASSERT_VALID(Pframe()); ASSERT_VALID(Pframe()->PciDrag());
// If we are dragging, process the drop.
if (BDragging()) { HTREEITEM hti; UINT flags; CPoint ptView; CTreeCtrl & rtc = GetTreeCtrl();
Trace(g_tagTreeDrag, _T("OnButtonUpForDrag()"));
// Convert the point to view coordinates.
ptView = point; Pframe()->ClientToScreen(&ptView); rtc.ScreenToClient(&ptView);
// If we are over a tree item, drop the item being dragged.
hti = rtc.HitTest(ptView, &flags); if (hti != NULL) { CTreeItem * ptiDropTarget;
// Get the item to drop on.
ptiDropTarget = (CTreeItem *) rtc.GetItemData(hti); ASSERT_VALID(ptiDropTarget); ASSERT_KINDOF(CTreeItem, ptiDropTarget); ASSERT_VALID(ptiDropTarget->Pci());
if (ptiDropTarget->Pci() != Pframe()->PciDrag()) ptiDropTarget->Pci()->DropItem(Pframe()->PciDrag());
} // if: over a tree item
} // if: tree item is being dragged
} //*** CClusterTreeView::OnButtonUpForDrag()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::BeginDrag
//
// Routine Description:
// Called by the frame to begin a drag operation.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::BeginDrag(void) { Trace(g_tagTreeDrag, _T("BeginDrag()"));
} //*** CClusterTreeView::BeginDrag()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::EndDrag
//
// Routine Description:
// Called by the frame to end a drag operation.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::EndDrag(void) { // Cleanup.
GetTreeCtrl().SelectDropTarget(NULL); m_htiDrag = NULL; m_ptiDrag = NULL; m_htiDrop = NULL;
Trace(g_tagTreeDrag, _T("EndDrag()"));
} //*** CClusterTreeView::EndDrag()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::PreTranslateMessage
//
// Routine Description:
// Translate window messages before they are dispatched.
//
// Arguments:
// pMsg Points to a MSG structure that contains the message to process.
//
// Return Value:
// TRUE Message was handled.
// FALSE Message was not handled.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterTreeView::PreTranslateMessage(MSG * pMsg) { BOOL bForward = FALSE;
if (m_ptiBeingEdited != NULL) { CEdit * pedit = GetTreeCtrl().GetEditControl(); ASSERT(pedit != NULL);
if (pMsg->message == WM_KEYDOWN) { if (pMsg->wParam == VK_SHIFT) m_bShiftPressed = TRUE; else if (pMsg->wParam == VK_CONTROL) { ::CopyMemory(&m_msgControl, pMsg, sizeof(m_msgControl)); m_bControlPressed = TRUE; } // else if: control key pressed
else if ((pMsg->wParam == VK_RETURN) || (pMsg->wParam == VK_ESCAPE) || (pMsg->wParam == VK_INSERT) || (pMsg->wParam == VK_DELETE) || (pMsg->wParam == VK_F1) || (pMsg->wParam == VK_F5) || (pMsg->wParam == VK_F6) ) { Trace(g_tagTreeView, _T("PreTranslateMessage() - Forwarding WM_KEYDOWN - %d '%c', lparam = %08.8x"), pMsg->wParam, pMsg->wParam, pMsg->lParam); bForward = TRUE; if (m_bControlPressed) { if (pMsg->wParam == VK_RETURN) pedit->SendMessage(WM_KEYUP, m_msgControl.wParam, m_msgControl.lParam); } // if: control key pressed
} // else if: editing key pressed
else if ((pMsg->wParam == VK_TAB) || (m_bControlPressed && (_T('A') <= pMsg->wParam) && (pMsg->wParam <= _T('Y')) && (pMsg->wParam != _T('C')) && (pMsg->wParam != _T('H')) && (pMsg->wParam != _T('M')) && (pMsg->wParam != _T('V')) && (pMsg->wParam != _T('X')) ) ) { Trace(g_tagTreeView, _T("PreTranslateMessage() - Ignoring WM_KEYDOWN - %d '%c', lparam = %08.8x"), pMsg->wParam, pMsg->wParam, pMsg->lParam); MessageBeep(MB_ICONEXCLAMATION); return TRUE; } // else if: key pressed that should be ignored
#ifdef NEVER
else { Trace(g_tagTreeView, _T("PreTranslateMessage() - Not forwarding WM_KEYDOWN - %d '%c', lparam = %08.8x"), pMsg->wParam, pMsg->wParam, pMsg->lParam); } // else: not processing key
#endif
} // if: key pressed while editing label
else if (pMsg->message == WM_SYSKEYDOWN) { if (pMsg->wParam == VK_MENU) m_bAltPressed = TRUE; else if ((pMsg->wParam == VK_RETURN) ) { Trace(g_tagTreeView, _T("PreTranslateMessage() - Forwarding WM_SYSKEYDOWN - %d '%c', lparam = %08.8x"), pMsg->wParam, pMsg->wParam, pMsg->lParam); bForward = TRUE; } // else if: editing key pressed
#ifdef NEVER
else { Trace(g_tagTreeView, _T("PreTranslateMessage() - Not forwarding WM_SYSKEYDOWN - %d '%c', lparam = %08.8x"), pMsg->wParam, pMsg->wParam, pMsg->lParam); } // else: not processing key
#endif
} // else if: system key pressed while editing label
if (bForward) { pedit->SendMessage(pMsg->message, pMsg->wParam, pMsg->lParam); return TRUE; } // if: forwarding the message
else if (pMsg->message == WM_KEYUP) { if (pMsg->wParam == VK_SHIFT) m_bShiftPressed = FALSE; else if (pMsg->wParam == VK_CONTROL) m_bControlPressed = FALSE; } // else if: key up
else if (pMsg->message == WM_SYSKEYUP) { if (pMsg->wParam == VK_MENU) m_bAltPressed = FALSE; } // else if: system key up
} // if: editing a label
return CTreeView::PreTranslateMessage(pMsg);
} //*** CClusterTreeView::PreTranslateMessage()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::OnCmdRename
//
// Routine Description:
// Processes the ID_FILE_RENAME menu command.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::OnCmdRename(void) { CTreeItem * ptiSelected = PtiSelected();
// If an item has benn selected, begin label editing
if (ptiSelected != NULL) { ASSERT_VALID(ptiSelected); ptiSelected->EditLabel(this); } // if: an item has the focus
} //*** CClusterTreeView::OnCmdRename()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterTreeView::OnKeyDown
//
// Routine Description:
// Handler method for the TVN_KEYDOWN message.
//
// Arguments:
// pNMHDR Notification message structure.
// pResult Place in which to return the result.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterTreeView::OnKeyDown(NMHDR * pNMHDR, LRESULT * pResult) { TV_KEYDOWN * pTVKeyDown = (TV_KEYDOWN *) pNMHDR;
if (BDragging() && (pTVKeyDown->wVKey == VK_ESCAPE)) Pframe()->AbortDrag();
*pResult = 0;
} //*** CClusterTreeView::OnKeyDown()
|