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

📄 explorertreeviewctrl.h

📁 一个使用wtl写的完整的多窗口浏览器
💻 H
📖 第 1 页 / 共 2 页
字号:
// 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 + -