📄 treeview.cpp
字号:
/*
JumpToIt - PC Magazine password utility
Copyright (c) 1999 Ziff-Davis Publishing Company. All rights reserved.
First published in PC Magazine, US Edition.
Written by Steven E. Sipe
This file implements the group tree class.
*/
#include "stdafx.h"
#include "jumptoit.h"
#include "mainfrm.h"
#include "Doc.h"
#include "listview.h"
#include "treeview.h"
#include "grpprdlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CJTITreeView
IMPLEMENT_DYNCREATE(CJTITreeView, CTreeView)
BEGIN_MESSAGE_MAP(CJTITreeView, CTreeView)
//{{AFX_MSG_MAP(CJTITreeView)
ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBeginDrag)
ON_WM_LBUTTONUP()
ON_WM_TIMER()
ON_WM_MOUSEMOVE()
ON_WM_KEYDOWN()
ON_COMMAND(ID_ADD_GROUP, OnAddItem)
ON_COMMAND(ID_DELETE_GROUP, OnDeleteItem)
ON_COMMAND(ID_GROUP_PROPERTIES, OnItemProperties)
ON_UPDATE_COMMAND_UI(ID_GROUP_PROPERTIES, OnUpdateItemProperties)
ON_UPDATE_COMMAND_UI(ID_DELETE_GROUP, OnUpdateDeleteItem)
ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditCut)
ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
ON_COMMAND(ID_PASTE_DEFAULT, OnPasteDefault)
ON_UPDATE_COMMAND_UI(ID_PASTE_DEFAULT, OnUpdatePasteDefault)
ON_COMMAND(ID_MOVE_DOWN, OnMoveDown)
ON_UPDATE_COMMAND_UI(ID_MOVE_DOWN, OnUpdateMoveDown)
ON_COMMAND(ID_MOVE_UP, OnMoveUp)
ON_UPDATE_COMMAND_UI(ID_MOVE_UP, OnUpdateMoveUp)
ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelChanged)
ON_NOTIFY_REFLECT(NM_RCLICK, OnRclick)
//}}AFX_MSG_MAP
ON_COMMAND(ID_TOOL_ADD, OnAddItem)
ON_COMMAND(ID_TOOL_DELETE, OnDeleteItem)
ON_COMMAND(ID_TOOL_PROPERTIES, OnItemProperties)
ON_UPDATE_COMMAND_UI(ID_TOOL_PROPERTIES, OnUpdateItemProperties)
ON_UPDATE_COMMAND_UI(ID_TOOL_DELETE, OnUpdateDeleteItem)
END_MESSAGE_MAP()
// Constructor
CJTITreeView::CJTITreeView()
{
CTreeCtrl& tree = GetTreeCtrl();
m_pTree = &tree;
m_bDragging = FALSE;
m_nLevel = 0;
m_pMap = NULL;
}
// Destructor
CJTITreeView::~CJTITreeView()
{
}
// Called when the tree is created
BOOL CJTITreeView::PreCreateWindow(CREATESTRUCT& cs)
{
return CTreeView::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CJTITreeView drawing
void CJTITreeView::OnDraw(CDC* pDC)
{
CJTIDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
}
// Called when the view is initialized
void CJTITreeView::OnInitialUpdate()
{
static BOOL bFirstTime = TRUE;
if(bFirstTime)
{
// Set the tree style to have links and expand/contract buttons
m_pTree->ModifyStyle(0,TVS_HASLINES|TVS_HASBUTTONS|TVS_SHOWSELALWAYS);
m_ImageList.Create(IDB_GROUPS,16,1,RGB(255,0,255));
// Setup the image list
m_pTree->SetImageList(&m_ImageList, TVSIL_NORMAL);
// Make sure the at least have the initial Groups item
if(m_pTree->GetRootItem() == NULL)
{
m_pTree->InsertItem("Groups",0,0);
GROUPS& arrGroups = GetDocument()->GetGroups();
CGroup group;
arrGroups.Add(group);
m_nGroupCount = 1;
}
bFirstTime = FALSE;
}
CTreeView::OnInitialUpdate();
}
/////////////////////////////////////////////////////////////////////////////
// CJTITreeView diagnostics
#ifdef _DEBUG
void CJTITreeView::AssertValid() const
{
CTreeView::AssertValid();
}
void CJTITreeView::Dump(CDumpContext& dc) const
{
CTreeView::Dump(dc);
}
CJTIDoc* CJTITreeView::GetDocument()
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CJTIDoc)));
return (CJTIDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CJTITreeView message handlers
// Called when the drag operation is beginning
void CJTITreeView::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW *pNMTreeView = (NM_TREEVIEW*)pNMHDR;
UINT nFlags;
m_htreeItemDrag = m_pTree->HitTest(pNMTreeView->ptDrag,&nFlags);
m_htreeItemDrop = NULL;
// Can't drag the root item
if(m_htreeItemDrag && (m_htreeItemDrag != m_pTree->GetRootItem()))
{
m_bDragging = TRUE;
// Create drag image and begin dragging
m_pImageList = m_pTree->CreateDragImage(m_htreeItemDrag);
m_pImageList->BeginDrag(0,CPoint(0,0));
// Setup the image list for dragging and grab control of the mouse
m_pImageList->DragEnter(GetDesktopWindow(),pNMTreeView->ptDrag);
SetCapture();
// Setup a scroll timer in case we need auto-scrolling
SetTimer(1,75,NULL);
// Save the location where the drag began
CRect rect;
GetClientRect(&rect);
ClientToScreen(&rect);
m_cyTop = rect.top;
m_cyBottom = rect.bottom;
}
*pResult = 0;
}
// Handles dropping of dragged tree items
void CJTITreeView::OnLButtonUp(UINT nFlags, CPoint point)
{
// Transfer data if the need be and release capture.
if(m_bDragging)
{
// End the drag operation for the image list
m_pImageList->DragLeave(this);
m_pImageList->EndDrag();
// Make sure we can drop this item in the specified location
if(m_htreeItemDrop && m_htreeItemDrag != m_htreeItemDrop &&
!IsChild(m_htreeItemDrop,m_htreeItemDrag))
{
// Move the item and all of its children, the delete the original item
MoveNode(m_htreeItemDrag,m_htreeItemDrop);
m_pTree->DeleteItem(m_htreeItemDrag);
GetDocument()->SetModifiedFlag(TRUE);
GetDocument()->SaveModified();
}
else ::MessageBeep(0);
// Let go of the mouse
ReleaseCapture();
// Kill the scroll timer
KillTimer(1);
// Reset the flags
m_bDragging = FALSE;
m_pTree->SelectDropTarget(NULL);
AfxGetMainWnd()->Invalidate();
}
CTreeView::OnLButtonUp(nFlags, point);
}
// Handles auto-scrolling during drag operation
void CJTITreeView::OnTimer(UINT nIDEvent)
{
if(nIDEvent == 1)
{
// Get the current message
const MSG* pMessage = GetCurrentMessage();
// Move the drag image
m_pImageList->DragMove(pMessage->pt);
// Should we scroll the tree
if(pMessage->pt.y < m_cyTop || pMessage->pt.y > m_cyBottom)
{
// Figure out how we should scroll the tree
int nScrollType = GetScrollType(pMessage->pt);
// Scroll the window
SendMessage(WM_VSCROLL,nScrollType);
// Select the drop target
m_pImageList->DragLeave(this);
HTREEITEM htreeItem = m_pTree->GetFirstVisibleItem();
// Determine the type of scrolling we're doing
switch(nScrollType)
{
case SB_LINEUP:
if(htreeItem != m_pTree->GetRootItem())
{
m_pTree->EnsureVisible(htreeItem);
m_htreeItemDrop = NULL;
}
break;
case SB_LINEDOWN:
int nCount = m_pTree->GetVisibleCount();
for(int i = 0; i < nCount; i++)
htreeItem = m_pTree->GetNextVisibleItem(htreeItem);
m_pTree->EnsureVisible(htreeItem);
m_htreeItemDrop = NULL;
break;
}
m_pImageList->DragEnter(this,pMessage->pt);
AfxGetMainWnd()->Invalidate();
}
}
CTreeView::OnTimer(nIDEvent);
}
// Handles moving the mouse during a drag operation
void CJTITreeView::OnMouseMove(UINT nFlags, CPoint point)
{
if(m_bDragging)
{
CPoint ptScreen(point);
ClientToScreen(&ptScreen);
CRect rc;
GetClientRect(&rc);
// Is the mouse inside the tree control?
if(rc.PtInRect(point))
{
UINT nFlags;
// Yes, select the drop target and display the drop cursor
::SetCursor(::LoadCursor(NULL,IDC_ARROW));
m_pImageList->DragMove(ptScreen);
m_pImageList->DragShowNolock(FALSE);
m_htreeItemDrop = m_pTree->HitTest(point,&nFlags);
m_pTree->SelectDropTarget(m_htreeItemDrop);
m_pImageList->DragShowNolock(TRUE);
}
else
{
m_htreeItemDrop = NULL;
// No...select the no-drop cursor
m_pTree->SelectDropTarget(NULL);
::SetCursor(::LoadCursor(NULL,IDC_NO));
}
}
CTreeView::OnMouseMove(nFlags, point);
}
// Determines if the specified item is a child of the specified parent item
BOOL CJTITreeView::IsChild(HTREEITEM htreeItemChild, HTREEITEM htreeItemParent)
{
do
{
if(htreeItemChild == htreeItemParent)
break;
}
while((htreeItemChild = m_pTree->GetParentItem(htreeItemChild)) != NULL);
return(htreeItemChild != NULL);
}
// Recursively moves an item along with all of its child items
HTREEITEM CJTITreeView::MoveNode(HTREEITEM htreeItem, HTREEITEM htreeItemParent,
HTREEITEM htreeItemSibling)
{
TV_INSERTSTRUCT tvInsert;
HTREEITEM htreeNewItem, htreeChild;
// Get information about the dragged item
tvInsert.item.hItem = htreeItem;
tvInsert.item.cchTextMax = sizeof(m_szBuffer);
tvInsert.item.pszText = m_szBuffer;
tvInsert.item.mask = TVIF_HANDLE|TVIF_SELECTEDIMAGE|TVIF_IMAGE|TVIF_TEXT|TVIF_CHILDREN|TVIF_PARAM;
m_pTree->GetItem(&tvInsert.item);
// Set the new parent and insert the item
tvInsert.hParent = htreeItemParent;
tvInsert.hInsertAfter = (htreeItemSibling?htreeItemSibling:TVI_FIRST);
tvInsert.item.mask = TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_TEXT|TVIF_PARAM;
htreeNewItem = m_pTree->InsertItem(&tvInsert);
// Recursively handle child items
while((htreeChild = m_pTree->GetChildItem(htreeItem)) != NULL)
{
// Move each item's children
MoveNode(htreeChild,htreeNewItem);
// Remove the original item
m_pTree->DeleteItem(htreeChild);
}
return(htreeNewItem);
}
// Determines whether scrolling up or down is required
int CJTITreeView::GetScrollType(CPoint pt)
{
int nRet;
if(pt.y > m_cyBottom)
nRet = SB_LINEDOWN;
else if(pt.y < m_cyTop)
nRet = SB_LINEUP;
return(nRet);
}
//// Storing and loading support
// Recursively saves the tree's items using the specified callback routine
BOOL CJTITreeView::RecurseItem(HTREEITEM hitem, BOOL (CJTITreeView::*lpfnCallback)(void))
{
HTREEITEM hFirstChild;
m_tvItem.hItem = hitem;
m_tvItem.cchTextMax = sizeof(m_szBuffer);
m_tvItem.pszText = m_szBuffer;
m_tvItem.mask = TVIF_TEXT|TVIF_IMAGE;
// Call the callback routine
if(m_pTree->GetItem(&m_tvItem))
{
if((this->*lpfnCallback)())
return(TRUE);
}
// Get the first child
hFirstChild = m_pTree->GetNextItem(hitem,TVGN_CHILD);
// Keep going until we have all of them
while(hFirstChild)
{
// Save the current indention level
m_nLevel++;
// Recusively save all of the child items
RecurseItem(hFirstChild,lpfnCallback);
hFirstChild = m_pTree->GetNextItem(hFirstChild,TVGN_NEXT);
}
// Finished with this node, so move back an indention level
m_nLevel--;
return TRUE;
}
// Writes the current item to an archive object (m_pArchive)
BOOL CJTITreeView::ArchiveItem()
{
CString strData;
BYTE byCount = strlen(m_tvItem.pszText);
BYTE byImage = m_tvItem.iImage;
int nType = 0;
// Write the item's data
m_pArchive->Write(&m_nLevel,sizeof(m_nLevel));
m_pArchive->Write(&byImage,sizeof(byImage));
m_pArchive->Write(&byCount,sizeof(byCount));
m_pArchive->Write(m_tvItem.pszText,byCount);
// Map the old group number to the new one. This assures that the
// group's items get associated with the "new" group number when the
// items are saved.
if(m_pMap)
{
int nGroup = m_tvItem.lParam;
m_pMap[m_nIndex] = nGroup;
}
m_nIndex++;
return(0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -