📄 explorertreeviewctrl.h
字号:
// shview_demoView.h : interface of the CShview_demoView class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_SHVIEW_DEMOVIEW_H__0DD77E8E_1C9C_11D5_8A9C_9D5C3CCEE371__INCLUDED_)
#define AFX_SHVIEW_DEMOVIEW_H__0DD77E8E_1C9C_11D5_8A9C_9D5C3CCEE371__INCLUDED_
#include "ItemIDList.h"
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// for debug
#ifdef _DEBUG
const bool _Mtl_ExplorerTreeView_traceOn = false;
#define etvTRACE if (_Mtl_ExplorerTreeView_traceOn) ATLTRACE
#else
#define etvTRACE
#endif
// Extended styles
#define ETV_EX_LOADREMOTEICON 0x00000001L
#define ETV_EX_SINGLEEXPAND 0x00000002L
#define ETV_EX_USER 0x00010000L
template <class T>
class CExplorerTreeViewCtrlImpl : public CWindowImpl<T, CTreeViewCtrl>
{
public:
DECLARE_WND_SUPERCLASS(NULL, CTreeViewCtrl::GetWndClassName())
// Data members
CComPtr<IShellFolder> m_spDesktopFolder;
bool m_bDestroying;
CItemIDList m_idlRootFolder;
CItemIDList m_idlHtm; // used to draw .url icon faster
CComPtr<IContextMenu2> m_spContextMenu2;
DWORD m_dwExplorerTreeViewExtendedStyle;
// Constants
enum { s_nIDExpand = 1, s_nIDCollapse = 2, s_nIDNewFolder = 3, s_nIDOpen = 4, s_nIDLast = 100 };
enum { s_kcxItemGap = 4 };
// Ctor/Detor
CExplorerTreeViewCtrlImpl() : m_bDestroying(false), m_dwExplorerTreeViewExtendedStyle(0)
{
m_idlHtm = MtlGetHtmlFileIDList();
}
~CExplorerTreeViewCtrlImpl()
{
MtlDeleteHtmlFileIDList();
}
BOOL PreTranslateMessage(MSG* pMsg)
{
pMsg;
return FALSE;
}
// Attributes
void ModifyExplorerTreeViewExtendedStyle(DWORD dwRemove, DWORD dwAdd)
{
m_dwExplorerTreeViewExtendedStyle = (m_dwExplorerTreeViewExtendedStyle & ~dwRemove) | dwAdd;
if (_check_flag(ETV_EX_SINGLEEXPAND, m_dwExplorerTreeViewExtendedStyle))
ModifyStyle(0, TVS_SINGLEEXPAND);
else
ModifyStyle(TVS_SINGLEEXPAND, 0);
}
void SetExplorerTreeViewExtendedStyle(DWORD dwStyle)
{
m_dwExplorerTreeViewExtendedStyle = dwStyle;
if (_check_flag(ETV_EX_SINGLEEXPAND, m_dwExplorerTreeViewExtendedStyle))
ModifyStyle(0, TVS_SINGLEEXPAND);
else
ModifyStyle(TVS_SINGLEEXPAND, 0);
}
DWORD GetExplorerTreeViewExtendedStyle() const
{
return m_dwExplorerTreeViewExtendedStyle;
}
// Overridables
CItemIDList OnInitRootFolder()
{
CItemIDList idl;
HRESULT hr = ::SHGetSpecialFolderLocation(m_hWnd, CSIDL_DRIVES, &idl);
return idl;
}
void OnGetAdditionalTreeItems(CSimpleArray<TV_INSERTSTRUCT>& items, LPCITEMIDLIST pidl)
{
}
void OnInitialUpdateTreeItems(CSimpleArray<TV_INSERTSTRUCT>& items, LPCITEMIDLIST pidl)
{
std::sort(_begin(items), _end(items), _DefaultTreeItemCompare());
}
void OnOpenTreeItem(HTREEITEM hItem, LPITEMIDLIST pidl)
{
MtlShellExecute(m_hWnd, pidl);
}
void OnTreeItemClicked(HTREEITEM hTreeItem, UINT uFlags)
{
CItemIDList idl = _GetItemIDList(hTreeItem);
if (!idl.IsNull())
MtlShellExecute(m_hWnd, idl);
}
void OnExplorerTreeViewInit()
{
}
void OnExplorerTreeViewTerm()
{
}
bool OnGetInfoToolTip(HTREEITEM hItem, CString& strTip, int cchTextMax)
{
return false;
}
UINT OnPrepareMenuForContext(HTREEITEM hTreeItem, CMenuHandle menu, int& nPos)
{
return CMF_EXPLORE | CMF_CANRENAME;
}
void OnPrepareMenuForPopup(HTREEITEM hTreeItem, CMenuHandle menu)
{
}
bool OnCmdContextMenu(HTREEITEM hTreeItem, int nID)
{
return false;
}
// Message map and handlers
BEGIN_MSG_MAP(CExplorerTreeViewCtrlImpl)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
HANDLE_MENU_MESSAGE_CONTEXTMENU(m_spContextMenu2)
MESSAGE_HANDLER(WM_RBUTTONDOWN, OnRButtonDown)
MESSAGE_HANDLER(WM_RBUTTONUP, OnRButtonUp)
MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
MSG_WM_MOUSEWHEEL(OnMouseWheel)
// MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClk)
REFLECTED_NOTIFY_CODE_HANDLER(TVN_GETDISPINFO, OnGetDispInfo)
REFLECTED_NOTIFY_CODE_HANDLER(TVN_ITEMEXPANDING, OnItemExpanding)
REFLECTED_NOTIFY_CODE_HANDLER(TVN_ITEMEXPANDED, OnItemExpanded)
REFLECTED_NOTIFY_CODE_HANDLER(TVN_ENDLABELEDIT, OnEndLabelEdit)
REFLECTED_NOTIFY_CODE_HANDLER(TVN_GETINFOTIP, OnGetInfoTip)
END_MSG_MAP()
LRESULT OnMouseWheel(UINT fwKeys, short zDelta, CPoint point)
{
// I've never touched a wheel mouse.
if (IsWindowVisible()) {
CRect rc;
GetWindowRect(&rc);
if (rc.PtInRect(point)) {
SetMsgHandled(FALSE); // pass to tree view control
return 1;
}
}
SetMsgHandled(TRUE);// eat it
return 1; // but not processed
}
LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
RECT rect;
GetClientRect(&rect);
::FillRect((HDC)wParam, &rect, (HBRUSH)LongToPtr(COLOR_WINDOW + 1));
return 1; // no background needed
}
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
etvTRACE(_T("OnCreate in\n"));
LRESULT lRet = DefWindowProc();
_SetSystemImageList();
HRESULT hr = ::SHGetDesktopFolder(&m_spDesktopFolder);
if (FAILED(hr))
return lRet;
T* pT = static_cast<T*>(this);
pT->OnExplorerTreeViewInit();// before _InitRootTree()!
_InitRootTree();
SetItemHeight(GetItemHeight() + s_kcxItemGap);
etvTRACE(_T("OnCreate out\n"));
return lRet;
}
LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
bHandled = FALSE;
m_bDestroying = true;
T* pT = static_cast<T*>(this);
pT->OnExplorerTreeViewTerm();
etvTRACE(_T("OnDestroy(%d)\n"), GetCount());
_CleanUpAll();
return 0;
}
LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
int nVirtKey = (int)wParam;
if (nVirtKey == VK_RETURN || nVirtKey == VK_SPACE) {
HTREEITEM hItem = GetSelectedItem();
if (hItem == NULL)
return 0;
if (_IsItemFolder(hItem)) {
bHandled = FALSE;
return 1;
}
T* pT = static_cast<T*>(this);
// pT->OnOpenTreeItem(hItem, _GetItemIDList(hItem));
pT->OnTreeItemClicked(hItem, 0);
}
else {
bHandled = FALSE;
return 1;
}
return 0;
}
LRESULT OnLButtonDblClk(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
HTREEITEM hItem = _HitTestForFullLow(pt);
if (hItem == NULL)
return 0;
MtlShellExecute(m_hWnd, _GetItemIDList(hItem));
// GetUrlFromHistory(hItem);
return 0;
}
HTREEITEM _HitTestForFullLow(CPoint pt)
{
UINT flag;
HTREEITEM hItem = HitTest(pt, &flag);
if (hItem == NULL || !_CheckTVHTFlag_For_FullLow(flag))
return NULL;
else
return hItem;
}
LRESULT OnRButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
HTREEITEM hItem = _HitTestForFullLow(pt);
if (hItem == NULL)
return 0;
EndEditLabelNow(TRUE);// cancel
HTREEITEM hItemSelected = GetSelectedItem();
bool bHilight = (hItem != hItemSelected);
if (bHilight) // hilight item
SetItem(hItem, TVIF_STATE, NULL, 0, 0, TVIS_SELECTED , TVIS_SELECTED, NULL);
// SelectItem(hItem);
HTREEITEM hItemExpanded = NULL;
_PopupContextMenu(hItem, pt, hItemExpanded);
// SelectItem(NULL);
if (hItemExpanded == NULL && bHilight) // reset hilight
SetItem(hItem, TVIF_STATE, NULL, 0, 0, 0, TVIS_SELECTED/*TVIS_SELECTED*/, NULL);
return 0;
}
LRESULT OnRButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
HTREEITEM hItem = _HitTestForFullLow(pt);
if (hItem == NULL)
return 0;
HTREEITEM hItemExpanded = NULL;
_PopupContextMenu(hItem, pt, hItemExpanded);
return 0;
}
LRESULT OnItemExpanding(int, LPNMHDR lpnmhdr, BOOL&)
{
if (m_bDestroying)
return 0;
LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lpnmhdr;
if (pnmtv->action == TVE_EXPAND) {
TVITEM& item = pnmtv->itemNew;
_CleanUpChildren(item.hItem);
_AddChildren(item.hItem);
}
// else if (pnmtv->action == TVE_COLLAPSE) {
// etvTRACE(_T("collapse\n"));
// TVITEM& item = pnmtv->itemNew;
// _CleanUpChildren(item.hItem);
// }
return 0;
}
LRESULT OnItemExpanded(int, LPNMHDR lpnmhdr, BOOL&)
{
if (m_bDestroying)
return 0;
LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lpnmhdr;
if (pnmtv->action == TVE_COLLAPSE) {
etvTRACE(_T("collapse\n"));
TVITEM& item = pnmtv->itemNew;
_CleanUpChildren(item.hItem);
}
return 0;
}
LRESULT OnEndLabelEdit(int, LPNMHDR lpnmhdr, BOOL&)
{
NMTVDISPINFO* pnmv = (NMTVDISPINFO*)lpnmhdr;
TVITEM& item = pnmv->item;
if (item.pszText != NULL) {
CItemIDList idl = _GetItemIDList(item.hItem); // full path of file
CItemIDList idlFolder = _GetItemIDList(GetParentItem(item.hItem)); // full path of folder
idl -= idlFolder; // get file name
if (idl.IsNull())
return 0;
CComPtr<IShellFolder> spFolder;
HRESULT hr = m_spDesktopFolder->BindToObject(idlFolder, NULL, IID_IShellFolder, (void**)&spFolder);
if (FAILED(hr))
return 0;
CItemIDList idlRet = MtlSetDisplayName(spFolder, idl, item.pszText, m_hWnd);
if (idlRet.IsNull()) {// failed
EditLabel(item.hItem);
}
else {
CItemIDList idlNew = idlFolder + idlRet;
TVITEM tvi;
tvi.mask = TVIF_HANDLE | TVIF_PARAM;
tvi.hItem = item.hItem;
GetItem(&tvi);
CItemIDList::FreeIDList((LPITEMIDLIST)tvi.lParam);
tvi.lParam = (LPARAM)idlNew.Detach();
tvi.mask |= TVIF_TEXT;
// SetItemText(item.hItem, item.pszText);
tvi.pszText = item.pszText;
SetItem(&tvi);
_RefreshChildren(item.hItem);
}
}
return 0;
}
LRESULT OnGetInfoTip(int, LPNMHDR lpnmhdr, BOOL&)
{
LPNMTVGETINFOTIP lpGetInfoTip = (LPNMTVGETINFOTIP)lpnmhdr;
CString strTip;
ATLASSERT(lpGetInfoTip->pszText != NULL);
T* pT = static_cast<T*>(this);
if (pT->OnGetInfoToolTip(lpGetInfoTip->hItem, strTip, lpGetInfoTip->cchTextMax))
::lstrcpyn(lpGetInfoTip->pszText, strTip, lpGetInfoTip->cchTextMax);
return 0;
}
LRESULT OnGetDispInfo(int, LPNMHDR lpnmhdr, BOOL&)
{
NMTVDISPINFO* pnmv = (NMTVDISPINFO*)lpnmhdr;
TVITEM& item = pnmv->item;
if (!(item.mask & (TVIF_SELECTEDIMAGE | TVIF_IMAGE)))
return 0;
CItemIDList idl = (LPCITEMIDLIST)item.lParam;
bool bExpanded = _IsItemExpanded(item.hItem);
bool bFolder = _IsItemFolder(item.hItem);
LPCITEMIDLIST pidl;
if (_check_flag(ETV_EX_LOADREMOTEICON, m_dwExplorerTreeViewExtendedStyle))
pidl = NULL;
else
pidl = m_idlHtm;
if (bFolder) { // if folder, never mind selected or not
if (bExpanded) {
item.iImage = MtlGetSelectedIconIndex(idl, bFolder, pidl);
item.iSelectedImage = item.iImage;
}
else {
item.iImage = MtlGetNormalIconIndex(idl, pidl);
item.iSelectedImage = item.iImage;
}
}
else {
// Note. item.mask is vague
if (item.mask & TVIF_SELECTEDIMAGE) {
item.iSelectedImage = MtlGetSelectedIconIndex(idl, bFolder, pidl);
}
if (item.mask & TVIF_IMAGE) {
item.iImage = MtlGetNormalIconIndex(idl, pidl);
}
_NoImageCallBack(item);
}
return 0;
}
void _SetSystemImageList()
{
ATLASSERT(::IsWindow(m_hWnd));
SHFILEINFO sfi;
HIMAGELIST hImgs = (HIMAGELIST)::SHGetFileInfo(_T("C:\\"), 0, &sfi, sizeof(sfi),
SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
ATLASSERT(hImgs != NULL);
SetImageList(hImgs, TVSIL_NORMAL);
}
void _InitRootTree()
{
m_bDestroying = true;
_CleanUpAll();
m_bDestroying = false;
T* pT = static_cast<T*>(this);
m_idlRootFolder = pT->OnInitRootFolder();
_AddChildrenAux(NULL);
}
void _AddChildren(HTREEITEM hItemParent)
{
_AddChildrenAux(hItemParent);
}
void _AddChildrenAux(HTREEITEM hItemParent)
{// hItemParent can be NULL
T* pT = static_cast<T*>(this);
LPITEMIDLIST pidlFolder = _GetItemIDList(hItemParent);
if (pidlFolder == NULL)
return;
// folders
CSimpleArray<TV_INSERTSTRUCT> items;
{// add additional items
pT->OnGetAdditionalTreeItems(items, pidlFolder);
int i;
for (i = 0; i < items.GetSize(); ++i)
InsertItem(&items[i]);
for (i = 0; i < items.GetSize(); ++i)
delete [] items[i].item.pszText;
items.RemoveAll();
}
// for each object
MtlForEachObject(pidlFolder, _Function_AddTreeItem(items, hItemParent, m_idlHtm));
pT->OnInitialUpdateTreeItems(items, pidlFolder);
int i;
for (i = 0; i < items.GetSize(); ++i)
InsertItem(&items[i]);
for (i = 0; i < items.GetSize(); ++i)
delete [] items[i].item.pszText;
}
struct _Function_AddTreeItem
{
CSimpleArray<TV_INSERTSTRUCT>& _arrTvis;
HTREEITEM _hItemParent;
LPCITEMIDLIST _pidlHtm;
_Function_AddTreeItem(CSimpleArray<TV_INSERTSTRUCT>& arrTvis, HTREEITEM hItemParent, LPITEMIDLIST pidlHtm)
: _arrTvis(arrTvis), _hItemParent(hItemParent), _pidlHtm(pidlHtm) { }
void operator()(IShellFolder* pFolder, const CItemIDList& idlFolder, const CItemIDList& idlFile, bool bFolder)
{
CString strText;
MtlGetDisplayName(pFolder, idlFile, strText);
LPTSTR lpszText = NULL;
ATLTRY(lpszText = new TCHAR[strText.GetLength() + 1]);
if (lpszText == NULL)
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -