📄 explorertreeviewctrl.h
字号:
::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 + -