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

📄 explorertreeviewctrl.h

📁 一个使用wtl写的完整的多窗口浏览器
💻 H
📖 第 1 页 / 共 2 页
字号:

			::lstrcpy(lpszText, strText);	
			TV_INSERTSTRUCT tvis;
			tvis.hParent = _hItemParent;
			tvis.hInsertAfter = TVI_LAST;
			tvis.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
			tvis.item.pszText = lpszText;
			tvis.item.iImage = I_IMAGECALLBACK;//MtlGetNormalIconIndex(idlFull, _pidlHtm);
			tvis.item.iSelectedImage = I_IMAGECALLBACK;//MtlGetSelectedIconIndex(idlFull, false, _pidlHtm);

			if (bFolder) {// if folder, it can expand.
				tvis.item.mask |= TVIF_CHILDREN;
				tvis.item.cChildren = 1;
			}
			
			// set up full item id list!
			CItemIDList idlFull = idlFolder + idlFile;
			ATLASSERT(idlFull.m_pidl != NULL);

			// fill mask
			DWORD dwAttributes = SFGAO_LINK|SFGAO_SHARE|SFGAO_GHOSTED;
			HRESULT hr = pFolder->GetAttributesOf(1, (LPCITEMIDLIST*)&idlFile.m_pidl, &dwAttributes);
			if (SUCCEEDED(hr) && !MtlIsTooSlowIDList(idlFull))
				_TreeItemMask(tvis.item, dwAttributes);

			// set up!!
			tvis.item.lParam = (LPARAM)idlFull.m_pidl;			
		
			idlFull.Detach();// *********don't forget clean up the lParam!!!!!!!********
			_arrTvis.Add(tvis);
		}
	};

	void _CleanUpAll()
	{
		_CleanUpChildrenFromChild(GetRootItem());
//		_CleanUpIDListFromChild(GetRootItem());
//		DeleteAllItems();// makes strange expanding and crash it, sucks
		ATLASSERT(GetCount() == 0);
	}

	void RefreshRootTree()
	{
		_CLockRedrawTreeView lock(NULL, m_hWnd);
		_InitRootTree();
	}

//	void _CleanUpIDListFromChild(HTREEITEM hItemChild)
//	{
//		for (; hItemChild != NULL; hItemChild = GetNextItem(hItemChild, TVGN_NEXT)) {
//			_FreeIDListSafely(hItemChild);
//			_CleanUpIDList(hItemChild);
//		}
//	}

	void _CleanUpChildrenFromChild(HTREEITEM hItemChild)
	{
		etvTRACE(_T("_CleanUpChildren\n"));
		if (hItemChild == NULL)
			return;

		do {
			HTREEITEM hItemNextChild = GetNextItem(hItemChild, TVGN_NEXT);// cache

			// clean pidl
			_FreeIDListSafely(hItemChild);
			
			// clean children of this child
			_CleanUpChildren(hItemChild);

			DeleteItem(hItemChild);

			hItemChild = hItemNextChild;
		} while (hItemChild != NULL);
	}

/*	void _CleanUpIDList(HTREEITEM hItemParent)
	{
		HTREEITEM hItemChild = GetChildItem(hItemParent);
		if (hItemChild == NULL)
			return;

		do {
			HTREEITEM hItemNextChild = GetNextItem(hItemChild, TVGN_NEXT);// cache

			// clean pidl
			_FreeIDListSafely(hItemChild);
			
			// clean children of this child
			_CleanUpIDList(hItemChild);

			hItemChild = hItemNextChild;
		} while (hItemChild != NULL);
	}
*/
	void _RefreshChildren(HTREEITEM hItemParent)
	{
		m_bDestroying = true;

		_CLockRedrawTreeView lock(hItemParent, m_hWnd);

		if (hItemParent == NULL) {// root
			_InitRootTree();
		}
		else if (_IsItemExpanded(hItemParent)) {
			_CleanUpChildren(hItemParent);
			_AddChildren(hItemParent);
		}

		m_bDestroying = false;
	}

	void _CleanUpChildren(HTREEITEM hItemParent)
	{
		etvTRACE(_T("_CleanUpChildren\n"));
		HTREEITEM hItemChild = GetChildItem(hItemParent);
		if (hItemChild == NULL)
			return;

		do {
			HTREEITEM hItemNextChild = GetNextItem(hItemChild, TVGN_NEXT);// cache

			// clean pidl
			_FreeIDListSafely(hItemChild);
			
			// clean children of this child
			_CleanUpChildren(hItemChild);

			DeleteItem(hItemChild);

			hItemChild = hItemNextChild;
		} while (hItemChild != NULL);

		ATLASSERT(GetChildItem(hItemParent) == NULL);
	}

	static _TreeItemMask(TVITEM& item, ULONG dwAttributes)
	{
		if (dwAttributes & SFGAO_LINK){
			item.mask |= TVIF_STATE;
			item.stateMask = TVIS_OVERLAYMASK;
			item.state = INDEXTOOVERLAYMASK(2);
		}

		if (dwAttributes & SFGAO_SHARE){
			item.mask |= TVIF_STATE;
			item.stateMask = TVIS_OVERLAYMASK;
			item.state = INDEXTOOVERLAYMASK(1);
		}

		if (dwAttributes & SFGAO_GHOSTED){
			item.mask |= TVIF_STATE;
			item.stateMask |= TVIS_CUT;
			item.state |= TVIS_CUT;
		}
	}

	static bool _CheckTVHTFlag_For_FullLow(UINT flag)
	{
		return (flag & (TVHT_ONITEM | TVHT_ONITEMINDENT | TVHT_ONITEMRIGHT)) ? true : false;
	}

	bool _PopupContextMenu(HTREEITEM hTreeItem, CPoint pt, HTREEITEM& hItemExpanded)
	{
		CItemIDList idl = _GetItemIDList(hTreeItem);						// full path of file
		CItemIDList idlFolder = _GetItemIDList(GetParentItem(hTreeItem));	// full path of folder
		idl -= idlFolder;	// get file name

		if (idl.IsNull())
			return false;

		// get parent IShellFolder
		CComPtr<IShellFolder> spFolder;
		HRESULT hr = m_spDesktopFolder->BindToObject(idlFolder, NULL, IID_IShellFolder, (void**)&spFolder);
		if (FAILED(hr))
			return false;

		LPITEMIDLIST pidls[] = { idl.m_pidl };

		CComPtr<IContextMenu> spContextMenu;
		hr = spFolder->GetUIObjectOf(m_hWnd, 1, (const struct _ITEMIDLIST **)pidls, 
			IID_IContextMenu, 0, (void**)&spContextMenu);
		if (FAILED(hr))
			return false;

		m_spContextMenu2.Release();

		hr = spContextMenu->QueryInterface(IID_IContextMenu2, (void**)&m_spContextMenu2);
		if (FAILED(hr))
			return false;

		// setup menu
		CMenu menu; menu.CreatePopupMenu();
		int nPos = 0;

		T* pT = static_cast<T*>(this);
		UINT uFlags = pT->OnPrepareMenuForContext(hTreeItem, menu.m_hMenu, nPos);

		hr = m_spContextMenu2->QueryContextMenu(menu.m_hMenu, nPos, s_nIDLast, 0x7fff, uFlags);
		if (FAILED(hr))
			return false;
	
		int nRenameID = MtlGetCmdIDFromAccessKey(menu.m_hMenu, _T("&M"));
		int nDeleteID = MtlGetCmdIDFromAccessKey(menu.m_hMenu, _T("&D"));
		int nCreateShortCutID = MtlGetCmdIDFromAccessKey(menu.m_hMenu, _T("&S"));		

		pT->OnPrepareMenuForPopup(hTreeItem, menu.m_hMenu);

		ClientToScreen(&pt);

		UINT uMenuFlags = TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON;
		int idCmd = menu.TrackPopupMenu(uMenuFlags|TPM_RETURNCMD, pt.x, pt.y, m_hWnd, NULL);


		CMINVOKECOMMANDINFO cmi;
		cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
		cmi.fMask = 0;
		cmi.hwnd = m_hWnd;
		cmi.lpVerb = (LPCSTR)MAKEINTRESOURCE(idCmd - s_nIDLast);
		cmi.lpParameters = NULL;
		cmi.lpDirectory = NULL;
		cmi.nShow = SW_SHOWNORMAL;
		cmi.dwHotKey = 0;
		cmi.hIcon  = NULL;


		if (idCmd == 0) {
			return false;
		}
		else if (idCmd == nRenameID) {
			EditLabel(hTreeItem);
			return true;
		}
		else if (idCmd == nDeleteID) {
			_CLockRedrawTreeView lock(hTreeItem, m_hWnd);
			m_bDestroying = true;
			_CleanUpChildren(hTreeItem);
			DeleteItem(hTreeItem);
			m_bDestroying = false;
			// pass it
		}
		else if (idCmd == nCreateShortCutID) {
			hr = m_spContextMenu2->InvokeCommand(&cmi);
			_RefreshChildren(GetParentItem(hTreeItem));
			return true;
		}
		else if (idCmd == s_nIDExpand) {
			hItemExpanded = hTreeItem;
//			_CollapseChildrenForSingleExpand(GetParentItem(hTreeItem));
			Select(hTreeItem, TVGN_CARET);
			Expand(hTreeItem, TVE_EXPAND);// required. cuz if already selected, Select(hTreeItem, TVGN_CARET) does nothing.
			return true;
		}
		else if (idCmd == s_nIDCollapse) {
			Expand(hTreeItem, TVE_COLLAPSE);
			return true;
		}
		else if (idCmd == s_nIDOpen) {
			// overridable
			T* pT = static_cast<T*>(this);
			pT->OnOpenTreeItem(hTreeItem, _GetItemIDList(hTreeItem));
			return true;
		}
		else if (idCmd == s_nIDNewFolder) {
			_CreateNewFolder(GetParentItem(hTreeItem));
			return true;
		}
		else {
			if (pT->OnCmdContextMenu(hTreeItem, idCmd))
				return true;

//			CItemIDList idlFullPath = _GetItemIDList(hTreeItem);
//			cmi.lpParameters = T2A((LPTSTR)(LPCTSTR)idlFullPath.GetPath());
		}

		// Execute command now
		hr = m_spContextMenu2->InvokeCommand(&cmi);

		m_spContextMenu2.Release();

		if (FAILED(hr))
			return false;

		return true;
	}

	LPITEMIDLIST _GetItemIDList(HTREEITEM hTreeItem)
	{// hTreeItem can be NULL
		if (hTreeItem == NULL)
			return m_idlRootFolder;

		TVITEM tvi;
		tvi.mask = TVIF_HANDLE | TVIF_PARAM;
		tvi.hItem = hTreeItem;
		GetItem(&tvi);

		ATLASSERT(tvi.lParam != NULL);
		return (LPITEMIDLIST)tvi.lParam;
	}

	HTREEITEM _FindItemIDList(HTREEITEM hItemParent, LPCITEMIDLIST pidl)
	{
		HTREEITEM hItem;
		if (hItemParent == NULL)
			hItem = GetRootItem();
		else
			hItem = GetChildItem(hItemParent);

		for (; hItem != NULL; hItem = GetNextItem(hItem, TVGN_NEXT))
		{
			CItemIDList idl = _GetItemIDList(hItem);
			if (idl == pidl)
				return hItem;
		}

		return NULL;
	}

	bool _IsItemFolder(HTREEITEM hItem)
	{
		return ItemHasChildren(hItem) == TRUE;
	}

	bool _IsItemExpanded(HTREEITEM hItem)
	{
		if (hItem == NULL)
			return false;

		TVITEM tvi;
		tvi.mask = TVIF_HANDLE | TVIF_STATE;
		tvi.hItem = hItem;
		GetItem(&tvi);

		return (tvi.state & TVIS_EXPANDED) != 0;
	}

	bool _CreateNewFolder(HTREEITEM hItemParent)
	{// I've found CMDSTR_NEWFOLDER command, but I wanna handle a hTreeItem.
		bool bRet = false;
		CString str(_T("New Folder"));

		CString strPath = CItemIDList(_GetItemIDList(hItemParent)).GetPath();
		if (strPath.IsEmpty())
			return bRet;

		MtlMakeSureTrailingBackSlash(strPath);

		int i = 2;
		CString strTmp = str;
		for (;;) {
			if (!MtlIsDirectory(strPath + strTmp))
				break;

			strTmp = str + _T(" (");
			strTmp.Append(i++);
			strTmp += _T(')');
		}

		strPath = strPath + strTmp;

		SECURITY_ATTRIBUTES sa;
		sa.nLength = sizeof(SECURITY_ATTRIBUTES);
		sa.lpSecurityDescriptor = NULL;
		sa.bInheritHandle = FALSE;
		if (!::CreateDirectory(strPath, &sa))
			return bRet;

		// insert
		TV_INSERTSTRUCT tvis;
		tvis.hParent = hItemParent;
		tvis.hInsertAfter = TVI_LAST;
		tvis.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
		tvis.item.pszText = (LPTSTR)(LPCTSTR)strTmp;

		// set up full item id list!
		CItemIDList idlFull = strPath;
		if (idlFull.IsNull())
			return bRet;

		tvis.item.lParam = (LPARAM)idlFull.m_pidl;

		tvis.item.mask |= TVIF_CHILDREN;
		tvis.item.cChildren = 1;

		tvis.item.iImage = I_IMAGECALLBACK;
		tvis.item.iSelectedImage = I_IMAGECALLBACK;

		idlFull.Detach();// *********don't forget clean up the lParam!!!!!!!********
		EditLabel(InsertItem(&tvis));
		return true;
	}

	bool _InsertItem(HTREEITEM hItemParent, LPCITEMIDLIST pidl, const CString& strItem, bool bFolder)
	{
		TV_INSERTSTRUCT tvis;
		tvis.hParent = hItemParent;
		tvis.hInsertAfter = TVI_LAST;
		tvis.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
		tvis.item.pszText = (LPTSTR)(LPCTSTR)strItem;

		// set up full item id list!
		CItemIDList idlFull = strPath;
		if (idlFull.IsNull())
			return bRet;

		tvis.item.lParam = (LPARAM)pidl;

		if (bFolder) {
			tvis.item.mask |= TVIF_CHILDREN;
			tvis.item.cChildren = 1;
		}

		tvis.item.iImage = I_IMAGECALLBACK;
		tvis.item.iSelectedImage = I_IMAGECALLBACK;
	}

	struct _Function_CompareTreeItem
	{
		bool operator()(const TV_INSERTSTRUCT& tv1, const TV_INSERTSTRUCT& tv2)
		{
			return ::lstrcmp(tv1.item.pszText, tv2.item.pszText) < 0;
		}
	};

	struct _CLockRedrawTreeView
	{
		HTREEITEM _hItemParent;
		CTreeViewCtrl _tree;
		CRect _rcInvalid;
		HWND _hWndFocus;
		_CLockRedrawTreeView(HTREEITEM hItemParent, HWND hWnd)
			: _hItemParent(hItemParent), _tree(hWnd), _hWndFocus(NULL)
		{
			ATLASSERT(::IsWindow(hWnd));

			CRect rcItem; rcItem.SetRectEmpty();
			if (_hItemParent != NULL)
				_tree.GetItemRect(_hItemParent, &rcItem, FALSE);
			
			_tree.GetClientRect(&_rcInvalid);
			_rcInvalid = CRect(_rcInvalid.left, (rcItem.bottom == 0) ? _rcInvalid.top : rcItem.bottom,
				_rcInvalid.right, _rcInvalid.bottom);

			_tree.SetRedraw(FALSE);

			if (_hItemParent == NULL) {
				_hWndFocus = ::GetFocus();
				_tree.ShowWindow(SW_HIDE);
			}
		}

		~_CLockRedrawTreeView()
		{
			if (_hItemParent == NULL) {
				_tree.ShowWindow(SW_SHOWNORMAL);
				if (_tree.m_hWnd == _hWndFocus)
					_tree.SetFocus();
			}

			_tree.SetRedraw(TRUE);
			_tree.InvalidateRect(_rcInvalid);
		}
	};

	void _CollapseRootItem()
	{
		_CLockRedrawTreeView lock(NULL, m_hWnd);

		HTREEITEM hItem = GetRootItem();
		if (_IsItemExpanded(hItem))
			Expand(hItem, TVE_COLLAPSE);
	}

	void _FreeIDListSafely(HTREEITEM hItem)
	{
		TVITEM tvi;
		tvi.mask = TVIF_HANDLE | TVIF_PARAM;
		tvi.hItem = hItem;
		GetItem(&tvi);

		CItemIDList::FreeIDList((LPITEMIDLIST)tvi.lParam);
		tvi.lParam = NULL;
		SetItem(&tvi);
	}

	void _NoImageCallBack(TVITEM tvi)
	{
		ATLASSERT(tvi.hItem != NULL);

		tvi.mask |= TVIF_HANDLE;
		tvi.mask = tvi.mask & (TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE);// update only these

		if (tvi.mask == TVIF_HANDLE)// no need to do anything
			return;

		SetItem(&tvi);
	}

	struct _DefaultTreeItemCompare : public std::binary_function<const TV_INSERTSTRUCT&, const TV_INSERTSTRUCT&, bool>
	{
		_DefaultTreeItemCompare()
		{
		}

		bool operator()(const TV_INSERTSTRUCT& x, const TV_INSERTSTRUCT& y)
		{
			bool bDirA = (x.item.cChildren == 1);
			bool bDirB = (y.item.cChildren == 1);

			if (bDirA == bDirB)
				return ::lstrcmp(x.item.pszText, y.item.pszText) < 0;
			else {
				if (bDirA)
					return true;
				else
					return false;
			}
		}
	};
};

class CExplorerTreeViewCtrl : public CExplorerTreeViewCtrlImpl<CExplorerTreeViewCtrl>
{
public:
	DECLARE_WND_SUPERCLASS(_T("MTL_ExpTreeViewCtrl"), GetWndClassName())
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ 偼慜峴偺捈慜偵捛壛偺愰尵傪憓擖偟傑偡丅

#endif // !defined(AFX_SHVIEW_DEMOVIEW_H__0DD77E8E_1C9C_11D5_8A9C_9D5C3CCEE371__INCLUDED_)

⌨️ 快捷键说明

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