///////////////////////////////////////////////////////////////////////////// // // 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()