⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mytreectrl.cpp

📁 Password Safe Password Safe is a password database utility. Users can keep their passwords securely
💻 CPP
字号:
/* * Silly subclass of CTreeCtrl just to implement Drag&Drop. * * Based on MFC sample code from CMNCTRL1 */#include "stdafx.h"#include "MyTreeCtrl.h"#include "DboxMain.h"#include "corelib/ItemData.h"#include "corelib/MyString.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endifstatic const TCHAR GROUP_SEP = TCHAR('.');CMyTreeCtrl::CMyTreeCtrl() : m_bDragging(false), m_pimagelist(NULL){}CMyTreeCtrl::~CMyTreeCtrl(){  delete m_pimagelist;}BEGIN_MESSAGE_MAP(CMyTreeCtrl, CTreeCtrl)	//{{AFX_MSG_MAP(CMyTreeCtrl)	ON_NOTIFY_REFLECT(TVN_BEGINLABELEDIT, OnBeginLabelEdit)	ON_NOTIFY_REFLECT(TVN_ENDLABELEDIT, OnEndLabelEdit)	ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBeginDrag)	ON_WM_MOUSEMOVE()	ON_WM_DESTROY()	ON_WM_LBUTTONUP()	//}}AFX_MSG_MAPEND_MESSAGE_MAP()void CMyTreeCtrl::OnDestroy(){  CImageList  *pimagelist;  pimagelist = GetImageList(TVSIL_NORMAL);  if (pimagelist != NULL) {    pimagelist->DeleteImageList();    delete pimagelist;  }}BOOL CMyTreeCtrl::PreTranslateMessage(MSG* pMsg) {  // When an item is being edited make sure the edit control  // receives certain important key strokes  if (GetEditControl())  {    ::TranslateMessage(pMsg);    ::DispatchMessage(pMsg);    return TRUE; // DO NOT process further  }  //Hitting the Escape key, Cancelling drag & drop  if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE && m_bDragging)  {    EndDragging(TRUE);    return TRUE;  }  //hitting the F2 key, being in-place editing of an item  else if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_F2)  {    HTREEITEM hItem = GetSelectedItem();    if (hItem != NULL)       EditLabel(hItem);    return TRUE;  }  //Let the parent class do its thing  return CTreeCtrl::PreTranslateMessage(pMsg);}void CMyTreeCtrl::SetNewStyle(long lStyleMask, BOOL bSetBits){  long        lStyleOld;  lStyleOld = GetWindowLong(m_hWnd, GWL_STYLE);  lStyleOld &= ~lStyleMask;  if (bSetBits)    lStyleOld |= lStyleMask;  SetWindowLong(m_hWnd, GWL_STYLE, lStyleOld);  SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);}void CMyTreeCtrl::UpdateLeafsGroup(HTREEITEM hItem, CString prefix){  // Starting with hItem, update the Group field of all of hItem's  // children. Called after a label has been edited.  if (IsLeafNode(hItem)) {    DWORD itemData = GetItemData(hItem);    ASSERT(itemData != NULL);    CItemData *ci = (CItemData *)itemData;    ci->SetGroup(CMyString(prefix));  } else { // update prefix with current group name and recurse    if (!prefix.IsEmpty())      prefix += GROUP_SEP;    prefix += GetItemText(hItem);    HTREEITEM child;    for(child = GetChildItem(hItem); child != NULL; child = GetNextSiblingItem(child)) {      UpdateLeafsGroup(child, prefix);    }  }}void CMyTreeCtrl::OnBeginLabelEdit(LPNMHDR , LRESULT *pLResult){  //TV_DISPINFO *ptvinfo = (TV_DISPINFO *)pnmhdr;  *pLResult = FALSE; // TRUE cancels label editing}static void splitLeafText(const char *lt, CString &newTitle, CString &newUser){  CString leafText(lt);  int leftBraceIndex = leafText.Find('[');  if (leftBraceIndex == -1) {    newTitle = leafText;    newUser = _T("");  } else {    newTitle = leafText.Left(leftBraceIndex - 1);    int rightBraceIndex = leafText.Find(']');    if (rightBraceIndex == -1) {      newUser = leafText.Mid(leftBraceIndex + 1);    } else {      newUser = leafText.Mid(leftBraceIndex + 1, rightBraceIndex - leftBraceIndex - 1);    }  }}static void makeLeafText(CString &treeDispString, const CString &title, const CString &user){  treeDispString = title;  if (!user.IsEmpty()) {    treeDispString += _T(" [");    treeDispString += user;    treeDispString += _T("]");  }}void CMyTreeCtrl::OnEndLabelEdit(LPNMHDR pnmhdr, LRESULT *pLResult){  TV_DISPINFO *ptvinfo = (TV_DISPINFO *)pnmhdr;  HTREEITEM ti = ptvinfo->item.hItem;  DboxMain *parent = (DboxMain *)GetParent();  if (ptvinfo->item.pszText != NULL && // NULL if edit cancelled,      ptvinfo->item.pszText[0] != '\0') // empty if text deleted - not allowed  {    ptvinfo->item.mask = TVIF_TEXT;    SetItem(&ptvinfo->item);    if (IsLeafNode(ptvinfo->item.hItem)) {      /*       * Leaf text is of the form: title [user]       * If edited text contains '[', then the user is updated       * If not, then the user is retrieved and the leaf is updated       */      // Update leaf's title      DWORD itemData = GetItemData(ti);      ASSERT(itemData != NULL);      CItemData *ci = (CItemData *)itemData;      CString newTitle, newUser;      splitLeafText(ptvinfo->item.pszText, newTitle, newUser);      if (newUser.IsEmpty())	newUser = CString(ci->GetUser());      CString treeDispString;      makeLeafText(treeDispString, newTitle, newUser);      // Update corresponding Tree mode text with the new display text (ie: in case       // the username was removed and had to be normalized back in).  Note that      // we cannot do "SetItemText(ti, treeDispString)" here since Windows will      // automatically overwrite and update the item text with the contents from       // the "ptvinfo->item.pszText" buffer.      strncpy(ptvinfo->item.pszText, treeDispString, ptvinfo->item.cchTextMax);      ptvinfo->item.pszText[ptvinfo->item.cchTextMax - 1] = '\0';      // update the password database record.      ci->SetTitle(newTitle); ci->SetUser(newUser);      // update corresponding List mode text      DisplayInfo *di = (DisplayInfo *)ci->GetDisplayInfo();      ASSERT(di != NULL);      int lindex = di->list_index;      parent->UpdateListItemTitle(lindex, newTitle);      parent->UpdateListItemUser(lindex, newUser);    } else {      // Update all leaf children with new path element      // prefix is path up to and NOT including renamed node      CString prefix;      HTREEITEM parent, current = ti;      do {	parent = GetParentItem(current);	if (parent == NULL) {	  break;	}	current = parent;	if (!prefix.IsEmpty())	  prefix = GROUP_SEP + prefix;	prefix = GetItemText(current) + prefix;      } while (1);      UpdateLeafsGroup(ti, prefix);    }    // Mark database as modified    parent->SetChanged(true);    SortChildren(GetParentItem(ti));    *pLResult = TRUE;  } else {    // restore text    // (not that this is documented anywhere in MS's docs...)    *pLResult = FALSE;  }}void CMyTreeCtrl::OnMouseMove(UINT nFlags, CPoint point){  if (m_bDragging) {    UINT                flags;    ASSERT(m_pimagelist != NULL);    m_pimagelist->DragMove(point);    HTREEITEM hitem = HitTest(point, &flags);    if (hitem != NULL) {      m_pimagelist->DragLeave(this);      SelectDropTarget(hitem);      m_hitemDrop = hitem;      m_pimagelist->DragEnter(this, point);    }  }  CTreeCtrl::OnMouseMove(nFlags, point);}bool CMyTreeCtrl::IsChildNodeOf(HTREEITEM hitemChild, HTREEITEM hitemSuspectedParent){  do {    if (hitemChild == hitemSuspectedParent)      break;  } while ((hitemChild = GetParentItem(hitemChild)) != NULL);  return (hitemChild != NULL);}bool CMyTreeCtrl::IsLeafNode(HTREEITEM hItem){  // ItemHasChildren() won't work in the general case  BOOL status;  int i, dummy;  status = GetItemImage(hItem, i, dummy);  ASSERT(status);  return (i == LEAF);}void CMyTreeCtrl::DeleteWithParents(HTREEITEM hItem){  // We don't want nodes that have no children to remain  HTREEITEM p;  do {    p = GetParentItem(hItem);    DeleteItem(hItem);    if (ItemHasChildren(p))      break;    hItem = p;  } while (p != TVI_ROOT && p != NULL);}// Return the full path leading up to a given item, but// not including the name of the item itself.CString CMyTreeCtrl::GetGroup(HTREEITEM hItem){  CString retval;  CString nodeText;  while (hItem != NULL) {    nodeText = GetItemText(hItem);    if (!retval.IsEmpty())      nodeText += GROUP_SEP;    retval = nodeText + retval;    hItem = GetParentItem(hItem);  }  return retval;}static CMyString GetPathElem(CMyString &path){  // Get first path element and chop it off, i.e., if  // path = "a.b.c.d"  // will return "a" and path will be "b.c.d"  // (assuming GROUP_SEP is '.')  CMyString retval;  int N = path.Find(GROUP_SEP);  if (N == -1) {    retval = path;    path = _T("");  } else {    const int Len = path.GetLength();    retval = CMyString(path.Left(N));    path = CMyString(path.Right(Len - N - 1));  }  return retval;}static bool ExistsInTree(CTreeCtrl &Tree, HTREEITEM node,			 const CMyString &s, HTREEITEM &si){  // returns true iff s is a direct descendant of node  HTREEITEM ti = Tree.GetChildItem(node);    while (ti != NULL) {    const CMyString itemText = Tree.GetItemText(ti);    if (itemText == s) {      si = ti;      return true;    }    ti = Tree.GetNextItem(ti, TVGN_NEXT);  }  return false;}HTREEITEM CMyTreeCtrl::AddGroup(const CString &group){  // Add a group at the end of path  HTREEITEM ti = TVI_ROOT;  HTREEITEM si;  if (!group.IsEmpty()) {    CMyString path = group;    CMyString s;    do {      s = GetPathElem(path);      if (!ExistsInTree(*this, ti, s, si)) {	ti = InsertItem(s, ti, TVI_SORT);	SetItemImage(ti, CMyTreeCtrl::NODE, CMyTreeCtrl::NODE);      } else	ti = si;    } while (!path.IsEmpty());  }  return ti;}bool CMyTreeCtrl::TransferItem(HTREEITEM hitemDrag, HTREEITEM hitemDrop){  TV_INSERTSTRUCT     tvstruct;  TCHAR               sztBuffer[128];  HTREEITEM           hNewItem, hFirstChild;  DWORD itemData = GetItemData(hitemDrag);  // avoid an infinite recursion  tvstruct.item.hItem = hitemDrag;  tvstruct.item.cchTextMax = sizeof(sztBuffer)/sizeof(TCHAR) - 1;  tvstruct.item.pszText = sztBuffer;  tvstruct.item.mask = (TVIF_CHILDREN | TVIF_HANDLE | TVIF_IMAGE			| TVIF_SELECTEDIMAGE | TVIF_TEXT);  GetItem(&tvstruct.item);  // get information of the dragged element  tvstruct.hParent = hitemDrop;  tvstruct.hInsertAfter = TVI_SORT;  tvstruct.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;  hNewItem = InsertItem(&tvstruct);  if (itemData != 0) { // Non-NULL itemData implies Leaf    CItemData *ci = (CItemData *)itemData;    // Update Group    CMyString path, elem;    HTREEITEM p, q = hNewItem;    do {      p = GetParentItem(q);      if (p != NULL) {	elem = CMyString(GetItemText(p));	if (!path.IsEmpty())	  elem += GROUP_SEP;	path = elem + path;	q = p;      } else	break;    } while (1);    ci->SetGroup(path);    // Mark database as modified!    ((DboxMain *)GetParent())->SetChanged(true);    // Update DisplayInfo record associated with ItemData    DisplayInfo *di = (DisplayInfo *)ci->GetDisplayInfo();    ASSERT(di != NULL);    di->tree_item = hNewItem;  }  SetItemData(hNewItem, itemData);  while ((hFirstChild = GetChildItem(hitemDrag)) != NULL) {    TransferItem(hFirstChild, hNewItem);  // recursively transfer all the items    DeleteItem(hFirstChild);  }  return true;}void CMyTreeCtrl::EndDragging(BOOL bCancel){  if (m_bDragging) {    ASSERT(m_pimagelist != NULL);    m_pimagelist->DragLeave(this);    m_pimagelist->EndDrag();    delete m_pimagelist;    m_pimagelist = NULL;    HTREEITEM parent = GetParentItem(m_hitemDrag);    if (!bCancel &&        m_hitemDrag != m_hitemDrop &&	!IsLeafNode(m_hitemDrop) &&	!IsChildNodeOf(m_hitemDrop, m_hitemDrag) &&	parent != m_hitemDrop)    {      // drag operation completed successfully.      TransferItem(m_hitemDrag, m_hitemDrop);      DeleteItem(m_hitemDrag);      while (parent != NULL && !ItemHasChildren(parent)) {	HTREEITEM grandParent = GetParentItem(parent);	DeleteItem(parent);	parent = grandParent;      }      SelectItem(m_hitemDrop);    } else {      // drag failed or cancelled, revert to last selected      SelectItem(m_hitemDrag);    }    ReleaseCapture();    m_bDragging = FALSE;    SelectDropTarget(NULL);  }}void CMyTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point){  if (m_bDragging) {    // Dragging operation should be ended, but first check to see    // if the mouse is outside the window to decide if the     // drag operation should be aborted.    CRect clientRect;    GetClientRect(&clientRect);    if (clientRect.PtInRect(point))      EndDragging(FALSE);    else      EndDragging(TRUE);  }  CTreeCtrl::OnLButtonUp(nFlags, point);}void CMyTreeCtrl::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult) {  CPoint      ptAction;  NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;  *pResult = 0;  GetCursorPos(&ptAction);  ScreenToClient(&ptAction);  ASSERT(!m_bDragging);  m_bDragging = TRUE;  m_hitemDrag = pNMTreeView->itemNew.hItem;  m_hitemDrop = NULL;  SelectItem(m_hitemDrag);  ASSERT(m_pimagelist == NULL);  m_pimagelist = CreateDragImage(m_hitemDrag);  m_pimagelist->DragShowNolock(TRUE);  m_pimagelist->SetDragCursorImage(0, CPoint(0, 0));  m_pimagelist->BeginDrag(0, CPoint(0,0));  m_pimagelist->DragMove(ptAction);  m_pimagelist->DragEnter(this, ptAction);  SetCapture();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -