You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1229 lines
29 KiB
C++
1229 lines
29 KiB
C++
2 years ago
|
// XTPShellTreeView.cpp : implementation file
|
||
|
//
|
||
|
// This file is a part of the XTREME CONTROLS MFC class library.
|
||
|
// (c)1998-2012 Codejock Software, All Rights Reserved.
|
||
|
//
|
||
|
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
|
||
|
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
|
||
|
// CONSENT OF CODEJOCK SOFTWARE.
|
||
|
//
|
||
|
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
|
||
|
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
|
||
|
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
|
||
|
// SINGLE COMPUTER.
|
||
|
//
|
||
|
// CONTACT INFORMATION:
|
||
|
// support@codejock.com
|
||
|
// http://www.codejock.com
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "Common/XTPVC80Helpers.h" // Visual Studio 2005 helper functions
|
||
|
#include "Common/XTPResourceManager.h"
|
||
|
#include "Common/XTPSystemHelpers.h"
|
||
|
#include "Common/XTPWinThemeWrapper.h"
|
||
|
|
||
|
#include "XTPDropSource.h"
|
||
|
#include "../Tree/XTPTreeBase.h"
|
||
|
#include "XTPShellSettings.h"
|
||
|
#include "XTPShellPidl.h"
|
||
|
#include "XTPShellTreeBase.h"
|
||
|
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
#define new DEBUG_NEW
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CXTPShellTreeBase
|
||
|
|
||
|
CXTPShellTreeBase::CXTPShellTreeBase()
|
||
|
: m_bTunneling(false)
|
||
|
{
|
||
|
m_bContextMenu = TRUE;
|
||
|
m_pComboBox = NULL;
|
||
|
m_uFlags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS;
|
||
|
m_ulSFGAOFlags = SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_DISPLAYATTRMASK | SFGAO_REMOVABLE | SFGAO_COMPRESSED | SFGAO_ENCRYPTED;
|
||
|
|
||
|
if (m_shSettings.ShowAllFiles() && !m_shSettings.ShowSysFiles())
|
||
|
{
|
||
|
m_uFlags |= SHCONTF_INCLUDEHIDDEN;
|
||
|
}
|
||
|
|
||
|
m_nRootFolder = CSIDL_DESKTOP;
|
||
|
m_bShowFiles = FALSE;
|
||
|
m_bShowShellLinkIcons = FALSE;
|
||
|
|
||
|
m_bExplorerStyle = FALSE;
|
||
|
}
|
||
|
|
||
|
CXTPShellTreeBase::~CXTPShellTreeBase()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CXTPShellTreeBase message handlers
|
||
|
|
||
|
HTREEITEM CXTPShellTreeBase::InsertDesktopItem(int nFolder /*= CSIDL_DESKTOP*/)
|
||
|
{
|
||
|
HTREEITEM hItem = TVI_ROOT;
|
||
|
|
||
|
CShellMalloc lpMalloc;
|
||
|
|
||
|
if (!lpMalloc)
|
||
|
return NULL;
|
||
|
|
||
|
// Get ShellFolder Pidl
|
||
|
LPITEMIDLIST pidlDesktop = NULL;
|
||
|
if (FAILED(::SHGetSpecialFolderLocation(NULL, nFolder, &pidlDesktop)))
|
||
|
{
|
||
|
pidlDesktop = NULL;
|
||
|
}
|
||
|
|
||
|
// insert the desktop.
|
||
|
if (pidlDesktop)
|
||
|
{
|
||
|
SHFILEINFO fileInfo;
|
||
|
::ZeroMemory(&fileInfo, sizeof(fileInfo));
|
||
|
|
||
|
::SHGetFileInfo((LPCTSTR)pidlDesktop, NULL, &fileInfo, sizeof(fileInfo),
|
||
|
SHGFI_PIDL | SHGFI_ATTRIBUTES | SHGFI_DISPLAYNAME);
|
||
|
|
||
|
TV_ITEM tvi;
|
||
|
tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
|
||
|
|
||
|
// Allocate memory for ITEMDATA struct
|
||
|
XTP_TVITEMDATA* lptvid = new XTP_TVITEMDATA;
|
||
|
if (lptvid != NULL)
|
||
|
{
|
||
|
GetNormalAndSelectedIcons(pidlDesktop, &tvi);
|
||
|
|
||
|
// Now, make a copy of the ITEMIDLIST and store the parent folders SF.
|
||
|
lptvid->lpi = DuplicateItem(lpMalloc, pidlDesktop);
|
||
|
lptvid->lpsfParent = NULL;
|
||
|
lptvid->lpifq = ConcatPidls(lpMalloc, NULL, pidlDesktop);
|
||
|
|
||
|
TCHAR szBuff[MAX_PATH];
|
||
|
STRCPY_S(szBuff, MAX_PATH, fileInfo.szDisplayName);
|
||
|
|
||
|
tvi.lParam = (LPARAM)lptvid;
|
||
|
tvi.pszText = szBuff;
|
||
|
tvi.cchTextMax = MAX_PATH;
|
||
|
|
||
|
// Populate the TreeVeiw Insert Struct
|
||
|
// The item is the one filled above.
|
||
|
// Insert it after the last item inserted at this level.
|
||
|
// And indicate this is a root entry.
|
||
|
TV_INSERTSTRUCT tvins;
|
||
|
tvins.item = tvi;
|
||
|
tvins.hInsertAfter = hItem;
|
||
|
tvins.hParent = hItem;
|
||
|
|
||
|
// Add the item to the tree
|
||
|
hItem = m_pTreeCtrl->InsertItem(&tvins);
|
||
|
}
|
||
|
|
||
|
if (pidlDesktop)
|
||
|
{
|
||
|
lpMalloc.Free(pidlDesktop);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hItem;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CXTPShellTreeBase::PopulateTreeView()
|
||
|
{
|
||
|
// Get a pointer to the desktop folder.
|
||
|
CShellSpecialFolder lpsfFolder(m_nRootFolder);
|
||
|
if (!lpsfFolder)
|
||
|
return;
|
||
|
|
||
|
// turn off redraw and remove all tree items.
|
||
|
m_pTreeCtrl->SetRedraw(FALSE);
|
||
|
m_pTreeCtrl->DeleteAllItems();
|
||
|
|
||
|
HTREEITEM hItemDesktop = InsertDesktopItem(m_nRootFolder);
|
||
|
|
||
|
LPITEMIDLIST pidlRoot = NULL;
|
||
|
if (FAILED(::SHGetSpecialFolderLocation(NULL, m_nRootFolder, &pidlRoot)))
|
||
|
{
|
||
|
pidlRoot = NULL;
|
||
|
}
|
||
|
|
||
|
// Fill in the tree view from the root.
|
||
|
InitTreeViewItems(lpsfFolder, pidlRoot, hItemDesktop);
|
||
|
|
||
|
if (pidlRoot)
|
||
|
{
|
||
|
CShellMalloc malloc;
|
||
|
malloc.Free(pidlRoot);
|
||
|
}
|
||
|
|
||
|
// Sort the items in the tree view
|
||
|
SortChildren(hItemDesktop);
|
||
|
|
||
|
HTREEITEM hItemRoot = m_pTreeCtrl->GetRootItem();
|
||
|
m_pTreeCtrl->Expand(hItemRoot, TVE_EXPAND);
|
||
|
|
||
|
if (hItemDesktop != TVI_ROOT)
|
||
|
{
|
||
|
HTREEITEM hItemChild = m_pTreeCtrl->GetChildItem(hItemDesktop);
|
||
|
m_pTreeCtrl->Select(hItemChild, TVGN_CARET);
|
||
|
|
||
|
if ((::GetWindowLong(m_pTreeCtrl->m_hWnd, GWL_STYLE) & TVS_SINGLEEXPAND) == 0)
|
||
|
{
|
||
|
m_pTreeCtrl->Expand(hItemChild, TVE_EXPAND);
|
||
|
}
|
||
|
|
||
|
// get the item path.
|
||
|
CString strFolderPath;
|
||
|
GetFolderItemPath(hItemChild, strFolderPath);
|
||
|
|
||
|
// call virtual change notify method.
|
||
|
SelectionChanged(hItemChild, strFolderPath);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_pTreeCtrl->Select(hItemRoot, TVGN_CARET);
|
||
|
|
||
|
// get the item path.
|
||
|
CString strFolderPath;
|
||
|
GetFolderItemPath(hItemRoot, strFolderPath);
|
||
|
|
||
|
// call virtual change notify method.
|
||
|
SelectionChanged(hItemRoot, strFolderPath);
|
||
|
}
|
||
|
|
||
|
// turn on redraw and refresh tree.
|
||
|
m_pTreeCtrl->SetRedraw(TRUE);
|
||
|
m_pTreeCtrl->RedrawWindow();
|
||
|
m_pTreeCtrl->SetFocus();
|
||
|
}
|
||
|
|
||
|
void CXTPShellTreeBase::SetAttributes(HTREEITEM hItem, DWORD dwAttributes)
|
||
|
{
|
||
|
if (hItem != NULL)
|
||
|
{
|
||
|
// set the display attributes for the tree item.
|
||
|
if (dwAttributes != 0)
|
||
|
{
|
||
|
MapShellFlagsToItemAttributes(m_pTreeCtrl, hItem, dwAttributes);
|
||
|
|
||
|
// the item is compress or encrypted, show alt color.
|
||
|
if (m_shSettings.ShowCompColor())
|
||
|
{
|
||
|
if (dwAttributes & SFGAO_COMPRESSED)
|
||
|
SetItemColor(hItem, m_shSettings.m_crCompColor);
|
||
|
|
||
|
else if (dwAttributes & SFGAO_ENCRYPTED)
|
||
|
SetItemColor(hItem, m_shSettings.m_crEncrColor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL CXTPShellTreeBase::InitTreeViewItems(LPSHELLFOLDER lpsf, LPITEMIDLIST lpifq, HTREEITEM hParent)
|
||
|
{
|
||
|
CWaitCursor wait; // show wait cursor.
|
||
|
|
||
|
// Allocate a shell memory object.
|
||
|
CShellMalloc lpMalloc;
|
||
|
|
||
|
if (!lpMalloc)
|
||
|
return FALSE;
|
||
|
|
||
|
// Get the IEnumIDList object for the given folder.
|
||
|
LPENUMIDLIST lpe = NULL;
|
||
|
if (FAILED(lpsf->EnumObjects(::GetParent(m_pTreeCtrl->m_hWnd), m_uFlags, &lpe)))
|
||
|
return FALSE;
|
||
|
|
||
|
if (lpe == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
ULONG ulFetched = 0;
|
||
|
HTREEITEM hPrev = NULL;
|
||
|
LPITEMIDLIST lpi = NULL;
|
||
|
|
||
|
// Enumerate through the list of folder and non-folder objects.
|
||
|
while (lpe->Next(1, &lpi, &ulFetched) == S_OK)
|
||
|
{
|
||
|
// Create a fully qualified path to the current item
|
||
|
// the SH* shell api's take a fully qualified path pidl,
|
||
|
// (see GetIcon above where I call SHGetFileInfo) whereas the
|
||
|
// interface methods take a relative path pidl.
|
||
|
|
||
|
// Determine what type of object we have.
|
||
|
ULONG ulAttrs = GetAttributes(lpsf, lpi, m_ulSFGAOFlags);
|
||
|
|
||
|
// We need this next if statement so that we don't add things like
|
||
|
// the MSN to our tree. MSN is not a folder, but according to the
|
||
|
// shell it has subfolders.
|
||
|
if ((ulAttrs & SFGAO_FOLDER) || m_bShowFiles)
|
||
|
{
|
||
|
TV_ITEM tvi;
|
||
|
tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
|
||
|
|
||
|
if ((ulAttrs & SFGAO_HASSUBFOLDER) || (m_bShowFiles && (ulAttrs & SFGAO_FOLDER)))
|
||
|
{
|
||
|
//This item has sub-folders, so let's put the + in the TreeView.
|
||
|
//The first time the user clicks on the item, we'll populate the
|
||
|
//sub-folders.
|
||
|
tvi.cChildren = 1;
|
||
|
tvi.mask |= TVIF_CHILDREN;
|
||
|
}
|
||
|
|
||
|
// Allocate memory for ITEMDATA struct
|
||
|
CString szBuff;
|
||
|
XTP_TVITEMDATA* lptvid = new XTP_TVITEMDATA;
|
||
|
if (lptvid == NULL || GetName(lpsf, lpi, SHGDN_NORMAL, szBuff) == FALSE)
|
||
|
{
|
||
|
if (lptvid)
|
||
|
{
|
||
|
lpMalloc.Free(lptvid);
|
||
|
}
|
||
|
if (lpe)
|
||
|
{
|
||
|
lpe->Release();
|
||
|
}
|
||
|
if (lpi)
|
||
|
{
|
||
|
lpMalloc.Free(lpi);
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Now, make a copy of the ITEMIDLIST and store the parent folders SF.
|
||
|
lptvid->lpi = DuplicateItem(lpMalloc, lpi);
|
||
|
lptvid->lpsfParent = lpsf;
|
||
|
lptvid->lpifq = ConcatPidls(lpMalloc, lpifq, lpi);
|
||
|
lpsf->AddRef();
|
||
|
|
||
|
GetNormalAndSelectedIcons(lptvid->lpifq, &tvi);
|
||
|
|
||
|
tvi.lParam = (LPARAM)lptvid;
|
||
|
tvi.pszText = (LPTSTR)(LPCTSTR)szBuff;
|
||
|
tvi.cchTextMax = 0;
|
||
|
|
||
|
// Populate the TreeVeiw Insert Struct
|
||
|
// The item is the one filled above.
|
||
|
// Insert it after the last item inserted at this level.
|
||
|
// And indicate this is a root entry.
|
||
|
TV_INSERTSTRUCT tvins;
|
||
|
tvins.item = tvi;
|
||
|
tvins.hInsertAfter = hPrev;
|
||
|
tvins.hParent = hParent;
|
||
|
|
||
|
// Add the item to the tree
|
||
|
hPrev = m_pTreeCtrl->InsertItem(&tvins);
|
||
|
SetAttributes(hPrev, ulAttrs);
|
||
|
}
|
||
|
|
||
|
// Free the pidl that the shell gave us.
|
||
|
if (lpi)
|
||
|
{
|
||
|
lpMalloc.Free(lpi);
|
||
|
lpi = 0;
|
||
|
}
|
||
|
}
|
||
|
if (lpi)
|
||
|
{
|
||
|
lpMalloc.Free(lpi);
|
||
|
}
|
||
|
|
||
|
if (lpe)
|
||
|
{
|
||
|
lpe->Release();
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void CXTPShellTreeBase::GetNormalAndSelectedIcons(LPITEMIDLIST lpifq, LPTV_ITEM lptvitem)
|
||
|
{
|
||
|
// Note that we don't check the return value here because if GetIcon()
|
||
|
// fails, then we're in big trouble...
|
||
|
lptvitem->iImage = GetItemIcon(lpifq,
|
||
|
SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
|
||
|
|
||
|
lptvitem->iSelectedImage = GetItemIcon(lpifq,
|
||
|
SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON);
|
||
|
}
|
||
|
|
||
|
void CXTPShellTreeBase::OnFolderExpanding(NM_TREEVIEW* pNMTreeView)
|
||
|
{
|
||
|
if (!(pNMTreeView->itemNew.state & TVIS_EXPANDEDONCE))
|
||
|
{
|
||
|
// Long pointer to TreeView item data
|
||
|
XTP_TVITEMDATA* lptvid = (XTP_TVITEMDATA*)pNMTreeView->itemNew.lParam;
|
||
|
if (lptvid != NULL && lptvid->lpsfParent != NULL)
|
||
|
{
|
||
|
LPSHELLFOLDER lpsf = NULL;
|
||
|
if (SUCCEEDED(lptvid->lpsfParent->BindToObject(lptvid->lpi,
|
||
|
0, IID_IShellFolder, (LPVOID *)&lpsf)))
|
||
|
{
|
||
|
InitTreeViewItems(lpsf, lptvid->lpifq, pNMTreeView->itemNew.hItem);
|
||
|
}
|
||
|
|
||
|
SortChildren(pNMTreeView->itemNew.hItem);
|
||
|
|
||
|
m_pTreeCtrl->SetItemState(pNMTreeView->itemNew.hItem, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HTREEITEM CXTPShellTreeBase::GetContextMenu()
|
||
|
{
|
||
|
CPoint point;
|
||
|
::GetCursorPos(&point);
|
||
|
m_pTreeCtrl->ScreenToClient(&point);
|
||
|
|
||
|
TV_HITTESTINFO tvhti;
|
||
|
tvhti.pt = point;
|
||
|
m_pTreeCtrl->HitTest(&tvhti);
|
||
|
|
||
|
if (tvhti.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))
|
||
|
{
|
||
|
// Long pointer to TreeView item data
|
||
|
XTP_TVITEMDATA* lptvid = (XTP_TVITEMDATA*)m_pTreeCtrl->GetItemData(tvhti.hItem);
|
||
|
|
||
|
m_pTreeCtrl->ClientToScreen(&point);
|
||
|
|
||
|
if (lptvid->lpsfParent == NULL)
|
||
|
{
|
||
|
LPSHELLFOLDER lpShellFolder;
|
||
|
if (FAILED(::SHGetDesktopFolder(&lpShellFolder)))
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ShowContextMenu(m_pTreeCtrl->m_hWnd,
|
||
|
lpShellFolder, lptvid->lpi, &point);
|
||
|
|
||
|
if (lpShellFolder)
|
||
|
{
|
||
|
lpShellFolder->Release();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ShowContextMenu(m_pTreeCtrl->m_hWnd,
|
||
|
lptvid->lpsfParent, lptvid->lpi, &point);
|
||
|
}
|
||
|
|
||
|
return tvhti.hItem;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void CXTPShellTreeBase::SortChildren(HTREEITEM hParent)
|
||
|
{
|
||
|
TV_SORTCB tvscb;
|
||
|
tvscb.hParent = hParent;
|
||
|
tvscb.lParam = 1;
|
||
|
tvscb.lpfnCompare = TreeViewCompareProc;
|
||
|
m_pTreeCtrl->SortChildrenCB(&tvscb);
|
||
|
}
|
||
|
|
||
|
BOOL CXTPShellTreeBase::OnFolderSelected(NM_TREEVIEW* pNMTreeView, CString &strFolderPath)
|
||
|
{
|
||
|
// check tree item handle.
|
||
|
if (!pNMTreeView || !pNMTreeView->itemNew.hItem)
|
||
|
return FALSE;
|
||
|
|
||
|
// set a reference to the tree item struct.
|
||
|
TVITEM& tvi = pNMTreeView->itemNew;
|
||
|
|
||
|
// Long pointer to TreeView item data
|
||
|
XTP_TVITEMDATA* lptvid = (XTP_TVITEMDATA*)m_pTreeCtrl->GetItemData(tvi.hItem);
|
||
|
if (lptvid && lptvid->lpi && lptvid->lpsfParent)
|
||
|
{
|
||
|
LPSHELLFOLDER lpsf = NULL;
|
||
|
if (SUCCEEDED(lptvid->lpsfParent->BindToObject(lptvid->lpi,
|
||
|
0, IID_IShellFolder, (LPVOID*)&lpsf)))
|
||
|
{
|
||
|
if (m_pTreeCtrl->ItemHasChildren(tvi.hItem) && (tvi.state & TVIS_EXPANDEDONCE) == 0)
|
||
|
{
|
||
|
InitTreeViewItems(lpsf, lptvid->lpifq, tvi.hItem);
|
||
|
SortChildren(tvi.hItem);
|
||
|
m_pTreeCtrl->SetItemState(tvi.hItem, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE);
|
||
|
}
|
||
|
|
||
|
if (lpsf)
|
||
|
{
|
||
|
lpsf->Release();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return GetFolderItemPath(tvi.hItem, strFolderPath);
|
||
|
}
|
||
|
|
||
|
BOOL CXTPShellTreeBase::InitSystemImageLists()
|
||
|
{
|
||
|
HIMAGELIST himlSmall = GetSystemImageList(SHGFI_SMALLICON);
|
||
|
|
||
|
if (himlSmall)
|
||
|
{
|
||
|
TreeView_SetImageList(m_pTreeCtrl->GetSafeHwnd(), himlSmall, TVSIL_NORMAL);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL CXTPShellTreeBase::GetSelectedFolderPath(CString &strFolderPath)
|
||
|
{
|
||
|
HTREEITEM hItem = m_pTreeCtrl->GetSelectedItem();
|
||
|
return GetFolderItemPath(hItem, strFolderPath);
|
||
|
}
|
||
|
|
||
|
BOOL CXTPShellTreeBase::FindTreeItem(HTREEITEM hItem, XTP_LVITEMDATA* lplvid, BOOL bRecursively)
|
||
|
{
|
||
|
if (lplvid == NULL)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (!bRecursively)
|
||
|
{
|
||
|
hItem = m_pTreeCtrl->GetChildItem(hItem);
|
||
|
}
|
||
|
|
||
|
while (hItem)
|
||
|
{
|
||
|
// Long pointer to TreeView item data
|
||
|
XTP_TVITEMDATA* lptvid = (XTP_TVITEMDATA*)m_pTreeCtrl->GetItemData(hItem);
|
||
|
if (lptvid)
|
||
|
{
|
||
|
if (SCODE_CODE(GetScode(lplvid->lpsfParent->CompareIDs(
|
||
|
0, lplvid->lpi, lptvid->lpi))) == 0)
|
||
|
{
|
||
|
m_pTreeCtrl->EnsureVisible(hItem);
|
||
|
m_pTreeCtrl->SelectItem(hItem);
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (bRecursively)
|
||
|
{
|
||
|
HTREEITEM hNextItem = m_pTreeCtrl->GetChildItem(hItem);
|
||
|
if (hNextItem)
|
||
|
{
|
||
|
if (FindTreeItem(hNextItem, lplvid))
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hItem = m_pTreeCtrl->GetNextSiblingItem(hItem);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
void CXTPShellTreeBase::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)
|
||
|
{
|
||
|
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
|
||
|
OnFolderExpanding(pNMTreeView);
|
||
|
*pResult = 0;
|
||
|
}
|
||
|
|
||
|
void CXTPShellTreeBase::SelectionChanged(HTREEITEM hItem, CString strFolderPath)
|
||
|
{
|
||
|
if (hItem != NULL && !m_bTunneling)
|
||
|
{
|
||
|
if (!m_pComboBox || !::IsWindow(m_pComboBox->m_hWnd))
|
||
|
return;
|
||
|
|
||
|
// update combo box association.
|
||
|
if (m_pComboBox->IsKindOf(RUNTIME_CLASS(CComboBoxEx)))
|
||
|
{
|
||
|
CComboBoxEx* pComboBoxEx = DYNAMIC_DOWNCAST(CComboBoxEx, m_pComboBox);
|
||
|
ASSERT_VALID(pComboBoxEx);
|
||
|
|
||
|
int nFound = CB_ERR;
|
||
|
int nIndex;
|
||
|
for (nIndex = 0; nIndex < pComboBoxEx->GetCount(); ++nIndex)
|
||
|
{
|
||
|
CString strText;
|
||
|
pComboBoxEx->GetLBText(nIndex, strText);
|
||
|
|
||
|
if (strFolderPath.Compare(strText) == 0)
|
||
|
{
|
||
|
nFound = nIndex;
|
||
|
pComboBoxEx->SetCurSel(nIndex);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (nFound == CB_ERR)
|
||
|
{
|
||
|
HTREEITEM hti = m_pTreeCtrl->GetSelectedItem();
|
||
|
ASSERT(hti);
|
||
|
|
||
|
if (strFolderPath.IsEmpty())
|
||
|
{
|
||
|
strFolderPath = m_pTreeCtrl->GetItemText(hti);
|
||
|
}
|
||
|
|
||
|
int nImage, nSelectedImage;
|
||
|
m_pTreeCtrl->GetItemImage(hti, nImage, nSelectedImage);
|
||
|
|
||
|
COMBOBOXEXITEM cbItem = { 0 };
|
||
|
|
||
|
cbItem.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE | CBEIF_INDENT;
|
||
|
cbItem.iItem = 0;
|
||
|
cbItem.pszText = (LPTSTR)(LPCTSTR)strFolderPath;
|
||
|
cbItem.iImage = nImage;
|
||
|
cbItem.iSelectedImage = nImage;
|
||
|
cbItem.iIndent = 0;
|
||
|
|
||
|
pComboBoxEx->InsertItem(&cbItem);
|
||
|
pComboBoxEx->SetCurSel(0);
|
||
|
pComboBoxEx->SetItemDataPtr(0, hti);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else if (m_pComboBox->IsKindOf(RUNTIME_CLASS(CComboBox)))
|
||
|
{
|
||
|
CComboBox* pComboBox = DYNAMIC_DOWNCAST(CComboBox, m_pComboBox);
|
||
|
ASSERT_VALID(pComboBox);
|
||
|
|
||
|
int nFound = pComboBox->FindStringExact(-1, strFolderPath);
|
||
|
if (nFound == CB_ERR)
|
||
|
{
|
||
|
HTREEITEM hti = m_pTreeCtrl->GetSelectedItem();
|
||
|
ASSERT(hti);
|
||
|
|
||
|
pComboBox->InsertString(0, strFolderPath);
|
||
|
pComboBox->SetCurSel(0);
|
||
|
pComboBox->SetItemDataPtr(0, (HTREEITEM)hti);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pComboBox->SetCurSel(nFound);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CXTPShellTreeBase::OnDeleteTreeItem(NMHDR* pNMHDR, LRESULT* pResult)
|
||
|
{
|
||
|
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
|
||
|
|
||
|
XTP_TVITEMDATA* lptvid = (XTP_TVITEMDATA*)pNMTreeView->itemOld.lParam;
|
||
|
if (lptvid != NULL)
|
||
|
{
|
||
|
CShellMalloc lpMalloc;
|
||
|
|
||
|
if (lptvid->lpi)
|
||
|
{
|
||
|
lpMalloc.Free(lptvid->lpi);
|
||
|
lptvid->lpi = NULL;
|
||
|
}
|
||
|
if (lptvid->lpsfParent)
|
||
|
{
|
||
|
lptvid->lpsfParent->Release();
|
||
|
lptvid->lpsfParent = NULL;
|
||
|
}
|
||
|
if (lptvid->lpifq)
|
||
|
{
|
||
|
lpMalloc.Free(lptvid->lpifq);
|
||
|
lptvid->lpifq = NULL;
|
||
|
}
|
||
|
|
||
|
delete lptvid;
|
||
|
}
|
||
|
|
||
|
*pResult = 0;
|
||
|
}
|
||
|
|
||
|
void CXTPShellTreeBase::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
|
||
|
{
|
||
|
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
|
||
|
|
||
|
if (pNMTreeView)
|
||
|
{
|
||
|
// get a reference to the tree item struct.
|
||
|
TVITEM& tvi = pNMTreeView->itemNew;
|
||
|
|
||
|
// initialize the tree node.
|
||
|
CString strFolderPath;
|
||
|
if (!OnFolderSelected(pNMTreeView, strFolderPath))
|
||
|
{
|
||
|
// could not determine path from IDL, make sure
|
||
|
// path is empty.
|
||
|
strFolderPath.Empty();
|
||
|
}
|
||
|
|
||
|
// call virtual change notify method.
|
||
|
SelectionChanged(tvi.hItem, strFolderPath);
|
||
|
|
||
|
// mimic modern Windows Explorer behavior.
|
||
|
if (XTPSystemVersion()->IsWinXPOrGreater())
|
||
|
{
|
||
|
// expand selected item.
|
||
|
if (tvi.hItem && m_pTreeCtrl->ItemHasChildren(tvi.hItem))
|
||
|
{
|
||
|
m_pTreeCtrl->Expand(tvi.hItem, TVE_EXPAND);
|
||
|
}
|
||
|
|
||
|
// collapse siblings.
|
||
|
if (tvi.hItem != TVI_ROOT)
|
||
|
{
|
||
|
HTREEITEM hItem = m_pTreeCtrl->GetChildItem(
|
||
|
m_pTreeCtrl->GetParentItem(tvi.hItem));
|
||
|
|
||
|
while (hItem != NULL)
|
||
|
{
|
||
|
if (hItem != tvi.hItem)
|
||
|
{
|
||
|
m_pTreeCtrl->Expand(hItem, TVE_COLLAPSE);
|
||
|
}
|
||
|
|
||
|
hItem = m_pTreeCtrl->GetNextSiblingItem(hItem);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*pResult = 0;
|
||
|
}
|
||
|
|
||
|
void CXTPShellTreeBase::OnRclick(NMHDR* /*pNMHDR*/, LRESULT* pResult)
|
||
|
{
|
||
|
// Display the shell context menu.
|
||
|
if (m_bContextMenu == TRUE)
|
||
|
{
|
||
|
HTREEITEM hItem = GetContextMenu();
|
||
|
if (hItem != NULL)
|
||
|
{
|
||
|
// TODO: Additional error handling.
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*pResult = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL CXTPShellTreeBase::InitializeTree(DWORD dwStyle/*= TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT*/)
|
||
|
{
|
||
|
if (m_pTreeCtrl->GetImageList(TVSIL_NORMAL) == NULL)
|
||
|
{
|
||
|
// Initialize the system image list for the tree control.
|
||
|
VERIFY(InitSystemImageLists());
|
||
|
|
||
|
// Set the style for the tree control, remove styles that change depending on OS.
|
||
|
m_pTreeCtrl->ModifyStyle(TVS_HASLINES | TVS_LINESATROOT | TVS_TRACKSELECT, dwStyle);
|
||
|
|
||
|
// Make sure multi-select mode is disabled.
|
||
|
EnableMultiSelect(FALSE);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifndef TVM_SETEXTENDEDSTYLE
|
||
|
#define TVM_SETEXTENDEDSTYLE (TV_FIRST + 44)
|
||
|
#endif
|
||
|
|
||
|
#ifndef TVS_EX_DOUBLEBUFFER
|
||
|
#define TVS_EX_DOUBLEBUFFER 0x0004
|
||
|
#define TVS_EX_FADEINOUTEXPANDOS 0x0040
|
||
|
#endif
|
||
|
|
||
|
void CXTPShellTreeBase::SetExplorerStyle()
|
||
|
{
|
||
|
if (XTPSystemVersion()->IsWinVistaOrGreater())
|
||
|
{
|
||
|
m_bExplorerStyle = TRUE;
|
||
|
|
||
|
CXTPWinThemeWrapper().SetWindowTheme(m_pTreeCtrl->GetSafeHwnd(), L"EXPLORER", NULL);
|
||
|
m_pTreeCtrl->ModifyStyle(TVS_HASLINES, 0);
|
||
|
|
||
|
DWORD dwExStyle = TVS_EX_DOUBLEBUFFER | TVS_EX_FADEINOUTEXPANDOS;
|
||
|
|
||
|
::SendMessage(m_pTreeCtrl->m_hWnd, TVM_SETEXTENDEDSTYLE, (WPARAM)dwExStyle, (LPARAM)dwExStyle);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CXTPShellTreeBase::InitTreeNode(HTREEITEM hItem, XTP_TVITEMDATA* lptvid)
|
||
|
{
|
||
|
m_pTreeCtrl->SetRedraw(FALSE);
|
||
|
if (lptvid)
|
||
|
{
|
||
|
LPSHELLFOLDER lpsf = NULL;
|
||
|
if (SUCCEEDED(lptvid->lpsfParent->BindToObject(lptvid->lpi,
|
||
|
0, IID_IShellFolder, (LPVOID *)&lpsf)))
|
||
|
{
|
||
|
InitTreeViewItems(lpsf, lptvid->lpifq, hItem);
|
||
|
}
|
||
|
|
||
|
SortChildren(hItem);
|
||
|
}
|
||
|
|
||
|
m_pTreeCtrl->SetRedraw(TRUE);
|
||
|
}
|
||
|
|
||
|
HTREEITEM CXTPShellTreeBase::SearchTree(HTREEITEM hItem, LPCITEMIDLIST pABSPidl)
|
||
|
{
|
||
|
XTP_TVITEMDATA *pItem = NULL;
|
||
|
HTREEITEM hChildItem = m_pTreeCtrl->GetChildItem(hItem);
|
||
|
|
||
|
CShellSpecialFolder pShellFolder;
|
||
|
if (!pShellFolder)
|
||
|
return NULL;
|
||
|
|
||
|
while (hChildItem)
|
||
|
{
|
||
|
// Get the pidl that is stored in the tree node
|
||
|
pItem = (XTP_TVITEMDATA *)m_pTreeCtrl->GetItemData(hChildItem);
|
||
|
|
||
|
// See if it matches the one we're looking for
|
||
|
if (ComparePidls(pItem->lpifq, pABSPidl, pShellFolder))
|
||
|
{
|
||
|
m_pTreeCtrl->Select(hChildItem, TVGN_CARET);
|
||
|
|
||
|
// Ensure that we are expanded
|
||
|
UINT uState = m_pTreeCtrl->GetItemState(hChildItem, TVIS_EXPANDEDONCE);
|
||
|
if (!(uState & TVIS_EXPANDEDONCE))
|
||
|
{
|
||
|
InitTreeNode(hChildItem, (XTP_TVITEMDATA*)m_pTreeCtrl->GetItemData(hChildItem));
|
||
|
m_pTreeCtrl->SetItemState(hChildItem, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Didn't compare... try next one
|
||
|
hChildItem = m_pTreeCtrl->GetNextSiblingItem(hChildItem);
|
||
|
}
|
||
|
|
||
|
return hChildItem;
|
||
|
}
|
||
|
|
||
|
BOOL CXTPShellTreeBase::TunnelTree(CString strFindPath)
|
||
|
{
|
||
|
if (strFindPath.IsEmpty())
|
||
|
return false;
|
||
|
|
||
|
m_bTunneling = true;
|
||
|
|
||
|
BOOL bLock = m_pTreeCtrl->LockWindowUpdate();
|
||
|
BOOL bFound = false;
|
||
|
|
||
|
LPITEMIDLIST pidlPath;
|
||
|
|
||
|
// Attempt to get the folder's item list
|
||
|
pidlPath = IDLFromPath(strFindPath);
|
||
|
|
||
|
// If it is NULL then see if it is one of the special folders
|
||
|
if (pidlPath == NULL)
|
||
|
{
|
||
|
// These are the ones we care about.
|
||
|
const int nCSIDLMax = 0x001b;
|
||
|
for (int i = 0; i <= nCSIDLMax; i++)
|
||
|
{
|
||
|
LPITEMIDLIST pidlSpecialPath = NULL;
|
||
|
if (::SHGetSpecialFolderLocation(NULL, i, &pidlSpecialPath) != NOERROR)
|
||
|
continue;
|
||
|
|
||
|
SHFILEINFO fileInfo;
|
||
|
::ZeroMemory(&fileInfo, sizeof(fileInfo));
|
||
|
::SHGetFileInfo((LPCTSTR)pidlSpecialPath, NULL, &fileInfo, sizeof(fileInfo),
|
||
|
SHGFI_PIDL | SHGFI_DISPLAYNAME);
|
||
|
|
||
|
CString cs = fileInfo.szDisplayName;
|
||
|
if (cs.CompareNoCase(strFindPath) == 0)
|
||
|
{
|
||
|
// Found the pidl for the special folder
|
||
|
pidlPath = pidlSpecialPath;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pidlPath != NULL)
|
||
|
{
|
||
|
// Now work through the list and tree nodes until we compare
|
||
|
int nItems = GetPidlCount(pidlPath);
|
||
|
LPITEMIDLIST pPartPidl;
|
||
|
LPITEMIDLIST pABSPidl = NULL;
|
||
|
HTREEITEM hItem = m_pTreeCtrl->GetRootItem();
|
||
|
bFound = false;
|
||
|
|
||
|
// Loop through all the parts and see if we can find a match in the tree. It should
|
||
|
// be there unless something got added to the namespace after we built the tree last
|
||
|
// and we didn't catch it, but that's pretty unlikely.
|
||
|
for (int i = 0; i < nItems; i++)
|
||
|
{
|
||
|
pPartPidl = CopyPidlItem(pidlPath, i);
|
||
|
pABSPidl = ConcatPidls(pABSPidl, pPartPidl);
|
||
|
FreePidl(pPartPidl);
|
||
|
|
||
|
hItem = SearchTree(hItem, pABSPidl);
|
||
|
if (!hItem)
|
||
|
break; // Our partial path should still found
|
||
|
}
|
||
|
|
||
|
// If it was found the final path should compare to the full path entered
|
||
|
// and the hItem should be set to the place in the tree where the path ends
|
||
|
if (hItem && (nItems == 0 || ComparePidls(pidlPath, pABSPidl, NULL)))
|
||
|
{
|
||
|
m_pTreeCtrl->Select(hItem, TVGN_CARET);
|
||
|
// Ensure that we are expanded
|
||
|
UINT uState = m_pTreeCtrl->GetItemState(hItem, TVIS_EXPANDEDONCE);
|
||
|
if (!(uState & TVIS_EXPANDEDONCE))
|
||
|
{
|
||
|
InitTreeNode(hItem, (XTP_TVITEMDATA*)m_pTreeCtrl->GetItemData(hItem));
|
||
|
m_pTreeCtrl->SetItemState(hItem, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE);
|
||
|
}
|
||
|
bFound = true;
|
||
|
}
|
||
|
|
||
|
// Clean up
|
||
|
if (pidlPath)
|
||
|
FreePidl(pidlPath);
|
||
|
|
||
|
if (pABSPidl)
|
||
|
FreePidl(pABSPidl);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Must not be a special folder (stand alone) or a path that ParseDisplayName() doesn't recognize so look through tree
|
||
|
// directly to see if we can find it that way.
|
||
|
// Start at Desktop ...
|
||
|
HTREEITEM hItemRoot = m_pTreeCtrl->GetRootItem();
|
||
|
TCHAR* pszNext = NULL;
|
||
|
TCHAR szBuff[MAX_PATH];
|
||
|
|
||
|
STRCPY_S(szBuff, MAX_PATH, strFindPath);
|
||
|
|
||
|
TCHAR* lpszContext = 0;
|
||
|
pszNext = STRTOK_S(szBuff, _T("\\/"), &lpszContext);
|
||
|
|
||
|
bFound = false;
|
||
|
|
||
|
if (pszNext != NULL)
|
||
|
{
|
||
|
CString strItemText(m_pTreeCtrl->GetItemText(hItemRoot));
|
||
|
|
||
|
// Are we looking from desktop?
|
||
|
if (strItemText.CompareNoCase(pszNext) == 0)
|
||
|
pszNext = STRTOK_S(NULL, _T("\\/"), &lpszContext);
|
||
|
|
||
|
hItemRoot = m_pTreeCtrl->GetChildItem(hItemRoot);
|
||
|
|
||
|
// Ensure that we are expanded
|
||
|
UINT uState = m_pTreeCtrl->GetItemState(hItemRoot, TVIS_EXPANDEDONCE);
|
||
|
if (!(uState & TVIS_EXPANDEDONCE))
|
||
|
{
|
||
|
InitTreeNode(hItemRoot, (XTP_TVITEMDATA*)m_pTreeCtrl->GetItemData(hItemRoot));
|
||
|
m_pTreeCtrl->SetItemState(hItemRoot, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE);
|
||
|
}
|
||
|
|
||
|
while (pszNext && hItemRoot)
|
||
|
{
|
||
|
strItemText = m_pTreeCtrl->GetItemText(hItemRoot);
|
||
|
if (strItemText.CompareNoCase(pszNext) == 0)
|
||
|
{
|
||
|
// Found it
|
||
|
// We know this was successful - expand at this new root
|
||
|
m_pTreeCtrl->Select(hItemRoot, TVGN_CARET);
|
||
|
|
||
|
// Ensure that we are expanded
|
||
|
uState = m_pTreeCtrl->GetItemState(hItemRoot, TVIS_EXPANDEDONCE);
|
||
|
if (!(uState & TVIS_EXPANDEDONCE))
|
||
|
{
|
||
|
InitTreeNode(hItemRoot, (XTP_TVITEMDATA*)m_pTreeCtrl->GetItemData(hItemRoot));
|
||
|
m_pTreeCtrl->SetItemState(hItemRoot, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE);
|
||
|
}
|
||
|
pszNext = STRTOK_S(NULL, _T("\\/"), &lpszContext);
|
||
|
if (pszNext)
|
||
|
{
|
||
|
// Move down a level
|
||
|
hItemRoot = m_pTreeCtrl->GetChildItem(hItemRoot);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hItemRoot = m_pTreeCtrl->GetNextSiblingItem(hItemRoot);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (bLock)
|
||
|
{
|
||
|
m_pTreeCtrl->UnlockWindowUpdate();
|
||
|
}
|
||
|
|
||
|
m_bTunneling = false;
|
||
|
|
||
|
// make sure list gets updated.
|
||
|
SelectionChanged(m_pTreeCtrl->GetSelectedItem(), strFindPath);
|
||
|
return bFound;
|
||
|
}
|
||
|
|
||
|
BOOL CXTPShellTreeBase::GetFolderItemPath(HTREEITEM hItem, CString& strFolderPath)
|
||
|
{
|
||
|
if (hItem == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
XTP_TVITEMDATA* lptvid = (XTP_TVITEMDATA*)m_pTreeCtrl->GetItemData(hItem);
|
||
|
if (lptvid && lptvid->lpi)
|
||
|
{
|
||
|
if (lptvid->lpsfParent)
|
||
|
{
|
||
|
// Determine what type of object we have.
|
||
|
ULONG ulAttrs = SFGAO_FILESYSTEM;
|
||
|
lptvid->lpsfParent->GetAttributesOf(1, (const struct _ITEMIDLIST **)&lptvid->lpi, &ulAttrs);
|
||
|
|
||
|
// if the object is a file, folder or root set the path.
|
||
|
if (ulAttrs & SFGAO_FILESYSTEM)
|
||
|
{
|
||
|
TCHAR szFolderPath[_MAX_PATH];
|
||
|
if (::SHGetPathFromIDList(lptvid->lpifq, szFolderPath))
|
||
|
{
|
||
|
strFolderPath = szFolderPath;
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Determine what type of object we have.
|
||
|
SHFILEINFO sfi;
|
||
|
::ZeroMemory(&sfi, sizeof(SHFILEINFO));
|
||
|
|
||
|
::SHGetFileInfo((TCHAR*)lptvid->lpi, 0, &sfi,
|
||
|
sizeof(SHFILEINFO), SHGFI_PIDL | SHGFI_ATTRIBUTES);
|
||
|
|
||
|
// if the object is a file, folder or root set the path.
|
||
|
if (sfi.dwAttributes & SFGAO_FILESYSTEM)
|
||
|
{
|
||
|
TCHAR szFolderPath[_MAX_PATH];
|
||
|
if (::SHGetPathFromIDList(lptvid->lpi, szFolderPath))
|
||
|
{
|
||
|
strFolderPath = szFolderPath;
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
CString CXTPShellTreeBase::PathFindNextComponent(const CString& pszPath)
|
||
|
{
|
||
|
// Find the path delimiter
|
||
|
int nIndex = pszPath.Find(_T('\\'));
|
||
|
|
||
|
if (nIndex == -1)
|
||
|
return _T("");
|
||
|
|
||
|
return pszPath.Mid(nIndex + 1);
|
||
|
}
|
||
|
|
||
|
void CXTPShellTreeBase::PopulateTree(LPCTSTR lpszPath)
|
||
|
{
|
||
|
CString strFolder = lpszPath;
|
||
|
CString strNextFolder;
|
||
|
CString strPath;
|
||
|
|
||
|
CShellMalloc lpMalloc;
|
||
|
if (!lpMalloc)
|
||
|
return;
|
||
|
|
||
|
// Get a pointer to the desktop folder.
|
||
|
LPSHELLFOLDER lpSF = NULL;
|
||
|
if (FAILED(::SHGetDesktopFolder(&lpSF)))
|
||
|
return;
|
||
|
|
||
|
LPITEMIDLIST lpIDL = NULL;
|
||
|
|
||
|
// turn off redraw and remove all tree items.
|
||
|
m_pTreeCtrl->SetRedraw(FALSE);
|
||
|
m_pTreeCtrl->DeleteAllItems();
|
||
|
|
||
|
do
|
||
|
{
|
||
|
// Get the Next Component
|
||
|
strNextFolder = PathFindNextComponent(strFolder);
|
||
|
if (!strNextFolder.IsEmpty())
|
||
|
{
|
||
|
strPath = strFolder.Left(strFolder.GetLength() -
|
||
|
strNextFolder.GetLength());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
strPath = strFolder;
|
||
|
strNextFolder.Empty();
|
||
|
}
|
||
|
|
||
|
// Get ShellFolder Pidl
|
||
|
ULONG eaten;
|
||
|
if (FAILED(lpSF->ParseDisplayName(NULL, NULL, (LPOLESTR)XTP_CT2CW(strPath),
|
||
|
&eaten, &lpIDL, NULL)))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
LPSHELLFOLDER lpSF2 = NULL;
|
||
|
if (FAILED(lpSF->BindToObject(lpIDL, 0, IID_IShellFolder, (LPVOID*)&lpSF2)))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
lpMalloc.Free(lpIDL);
|
||
|
|
||
|
// Release the Parent Folder pointer.
|
||
|
lpSF->Release();
|
||
|
|
||
|
// Change Folder Info
|
||
|
lpSF = lpSF2;
|
||
|
strFolder = strNextFolder;
|
||
|
}
|
||
|
while (!strNextFolder.IsEmpty());
|
||
|
|
||
|
// get the base folders item ide list.
|
||
|
lpIDL = IDLFromPath(lpszPath);
|
||
|
|
||
|
SHFILEINFO fileInfo;
|
||
|
::ZeroMemory(&fileInfo, sizeof(fileInfo));
|
||
|
|
||
|
::SHGetFileInfo((LPCTSTR)lpIDL, NULL, &fileInfo, sizeof(fileInfo),
|
||
|
SHGFI_PIDL | SHGFI_ATTRIBUTES | SHGFI_DISPLAYNAME);
|
||
|
|
||
|
TV_ITEM tvi;
|
||
|
tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
|
||
|
|
||
|
// Allocate memory for ITEMDATA struct
|
||
|
XTP_TVITEMDATA* lptvid = new XTP_TVITEMDATA;
|
||
|
if (lptvid != NULL)
|
||
|
{
|
||
|
HTREEITEM hItem = TVI_ROOT;
|
||
|
|
||
|
// get the normal and selected icons for the path.
|
||
|
GetNormalAndSelectedIcons(lpIDL, &tvi);
|
||
|
|
||
|
// Now, make a copy of the ITEMIDLIST and store the parent folders SF.
|
||
|
lptvid->lpi = DuplicateItem(lpMalloc, lpIDL);
|
||
|
lptvid->lpsfParent = NULL;
|
||
|
lptvid->lpifq = ConcatPidls(lpMalloc, NULL, lpIDL);
|
||
|
|
||
|
TCHAR szBuff[MAX_PATH];
|
||
|
STRCPY_S(szBuff, MAX_PATH, fileInfo.szDisplayName);
|
||
|
|
||
|
tvi.lParam = (LPARAM)lptvid;
|
||
|
tvi.pszText = szBuff;
|
||
|
tvi.cchTextMax = MAX_PATH;
|
||
|
|
||
|
// Populate the TreeView Insert Struct
|
||
|
// The item is the one filled above.
|
||
|
// Insert it after the last item inserted at this level.
|
||
|
// And indicate this is a root entry.
|
||
|
TV_INSERTSTRUCT tvins;
|
||
|
tvins.item = tvi;
|
||
|
tvins.hInsertAfter = hItem;
|
||
|
tvins.hParent = hItem;
|
||
|
|
||
|
// Add the item to the tree
|
||
|
hItem = m_pTreeCtrl->InsertItem(&tvins);
|
||
|
|
||
|
// insert child items.
|
||
|
InitTreeViewItems(lpSF, lpIDL, hItem);
|
||
|
|
||
|
// Sort the items in the tree view
|
||
|
SortChildren(TVI_ROOT);
|
||
|
|
||
|
// expand parent.
|
||
|
m_pTreeCtrl->Expand(hItem, TVE_EXPAND);
|
||
|
}
|
||
|
|
||
|
// turn on redraw and refresh tree.
|
||
|
m_pTreeCtrl->SetRedraw(TRUE);
|
||
|
m_pTreeCtrl->RedrawWindow();
|
||
|
|
||
|
lpMalloc.Free(lpIDL);
|
||
|
|
||
|
if (lpSF)
|
||
|
{
|
||
|
lpSF->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CXTPShellTreeBase::AssociateCombo(CWnd* pWnd)
|
||
|
{
|
||
|
ASSERT_VALID(pWnd); // must be a valid window.
|
||
|
|
||
|
if (::IsWindow(pWnd->GetSafeHwnd()))
|
||
|
{
|
||
|
m_pComboBox = pWnd;
|
||
|
|
||
|
if (m_pComboBox->IsKindOf(RUNTIME_CLASS(CComboBoxEx)))
|
||
|
{
|
||
|
HIMAGELIST hImageList = GetSystemImageList(SHGFI_SMALLICON);
|
||
|
|
||
|
if (hImageList != NULL)
|
||
|
{
|
||
|
CComboBoxEx* pComboBoxEx = DYNAMIC_DOWNCAST(CComboBoxEx, m_pComboBox);
|
||
|
ASSERT_VALID(pComboBoxEx);
|
||
|
pComboBoxEx->SetImageList(CImageList::FromHandle(hImageList));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL CXTPShellTreeBase::OnEraseBkgnd(CDC* /*pDC*/)
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void CXTPShellTreeBase::OnPaint()
|
||
|
{
|
||
|
CPaintDC dc(m_pTreeCtrl);
|
||
|
DoPaint(dc, !m_bExplorerStyle);
|
||
|
}
|
||
|
|
||
|
void CXTPShellTreeBase::BeginDrag(NM_TREEVIEW* pNMTreeView)
|
||
|
{
|
||
|
// Long pointer to ListView item data
|
||
|
XTP_TVITEMDATA* lplvid = (XTP_TVITEMDATA*)m_pTreeCtrl->GetItemData(pNMTreeView->itemNew.hItem);
|
||
|
ASSERT(lplvid);
|
||
|
|
||
|
if (lplvid && lplvid->lpsfParent)
|
||
|
{
|
||
|
LPDATAOBJECT lpdo;
|
||
|
|
||
|
HRESULT hResult = lplvid->lpsfParent->GetUIObjectOf(AfxGetMainWnd()->m_hWnd, 1,
|
||
|
(const struct _ITEMIDLIST**)&lplvid->lpi, IID_IDataObject, 0, (LPVOID*)&lpdo);
|
||
|
|
||
|
if (SUCCEEDED(hResult))
|
||
|
{
|
||
|
LPDROPSOURCE lpds = new CXTPDropSource();
|
||
|
ASSERT(lpds != NULL);
|
||
|
|
||
|
DWORD dwEffect;
|
||
|
::DoDragDrop(lpdo, lpds,
|
||
|
DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK, &dwEffect);
|
||
|
|
||
|
lpdo->Release();
|
||
|
lpds->Release();
|
||
|
}
|
||
|
}
|
||
|
}
|