XTShellTreeBase.cpp
上传用户:szled88
上传日期:2015-04-09
资源大小:43957k
文件大小:29k
源码类别:

对话框与窗口

开发平台:

Visual C++

  1. // XTShellTreeView.cpp : implementation file
  2. //
  3. // This file is a part of the XTREME CONTROLS MFC class library.
  4. // (c)1998-2008 Codejock Software, All Rights Reserved.
  5. //
  6. // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
  7. // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
  8. // CONSENT OF CODEJOCK SOFTWARE.
  9. //
  10. // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
  11. // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
  12. // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
  13. // SINGLE COMPUTER.
  14. //
  15. // CONTACT INFORMATION:
  16. // support@codejock.com
  17. // http://www.codejock.com
  18. //
  19. /////////////////////////////////////////////////////////////////////////////
  20. #include "stdafx.h"
  21. #include "Common/XTPVC80Helpers.h"  // Visual Studio 2005 helper functions
  22. #include "Common/XTPResourceManager.h"
  23. #include "XTFunctions.h"
  24. #include "XTDropSource.h"
  25. #include "XTTreeBase.h"
  26. #include "XTShellSettings.h"
  27. #include "XTShellPidl.h"
  28. #include "XTShellTreeBase.h"
  29. #include "XTComboBoxEx.h"
  30. #ifdef _DEBUG
  31. #define new DEBUG_NEW
  32. #undef THIS_FILE
  33. static char THIS_FILE[] = __FILE__;
  34. #endif
  35. /////////////////////////////////////////////////////////////////////////////
  36. // CXTShellTreeBase
  37. CXTShellTreeBase::CXTShellTreeBase()
  38. : m_bTunneling(false)
  39. {
  40. m_bContextMenu = TRUE;
  41. m_pComboBox = NULL;
  42. m_uFlags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS;
  43. if (m_shSettings.ShowAllFiles() && !m_shSettings.ShowSysFiles())
  44. {
  45. m_uFlags |= SHCONTF_INCLUDEHIDDEN;
  46. }
  47. m_nRootFolder = CSIDL_DESKTOP;
  48. m_bShowFiles = FALSE;
  49. m_bShowShellLinkIcons = FALSE;
  50. }
  51. CXTShellTreeBase::~CXTShellTreeBase()
  52. {
  53. }
  54. /////////////////////////////////////////////////////////////////////////////
  55. // CXTShellTreeBase message handlers
  56. HTREEITEM CXTShellTreeBase::InsertDesktopItem(int nFolder /*= CSIDL_DESKTOP*/)
  57. {
  58. HTREEITEM hItem = TVI_ROOT;
  59. CShellMalloc lpMalloc;
  60. if (!lpMalloc)
  61. return NULL;
  62. // Get ShellFolder Pidl
  63. LPITEMIDLIST pidlDesktop = NULL;
  64. if (FAILED(::SHGetSpecialFolderLocation(NULL, nFolder, &pidlDesktop)))
  65. {
  66. pidlDesktop = NULL;
  67. }
  68. // insert the desktop.
  69. if (pidlDesktop)
  70. {
  71. SHFILEINFO fileInfo;
  72. ::ZeroMemory(&fileInfo, sizeof(fileInfo));
  73. ::SHGetFileInfo((LPCTSTR)pidlDesktop, NULL, &fileInfo, sizeof(fileInfo),
  74. SHGFI_PIDL | SHGFI_ATTRIBUTES | SHGFI_DISPLAYNAME);
  75. TV_ITEM  tvi;
  76. tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
  77. // Allocate memory for ITEMDATA struct
  78. XT_TVITEMDATA* lptvid = new XT_TVITEMDATA;
  79. if (lptvid != NULL)
  80. {
  81. GetNormalAndSelectedIcons(pidlDesktop, &tvi);
  82. // Now, make a copy of the ITEMIDLIST and store the parent folders SF.
  83. lptvid->lpi = DuplicateItem(lpMalloc, pidlDesktop);
  84. lptvid->lpsfParent = NULL;
  85. lptvid->lpifq = ConcatPidls(lpMalloc, NULL, pidlDesktop);
  86. TCHAR szBuff[MAX_PATH];
  87. STRCPY_S(szBuff, MAX_PATH, fileInfo.szDisplayName);
  88. tvi.lParam = (LPARAM)lptvid;
  89. tvi.pszText = szBuff;
  90. tvi.cchTextMax = MAX_PATH;
  91. // Populate the TreeVeiw Insert Struct
  92. // The item is the one filled above.
  93. // Insert it after the last item inserted at this level.
  94. // And indicate this is a root entry.
  95. TV_INSERTSTRUCT tvins;
  96. tvins.item = tvi;
  97. tvins.hInsertAfter = hItem;
  98. tvins.hParent = hItem;
  99. // Add the item to the tree
  100. hItem = m_pTreeCtrl->InsertItem(&tvins);
  101. }
  102. if (pidlDesktop)
  103. {
  104. lpMalloc.Free(pidlDesktop);
  105. }
  106. }
  107. return hItem;
  108. }
  109. void CXTShellTreeBase::PopulateTreeView()
  110. {
  111. // Get a pointer to the desktop folder.
  112. CShellSpecialFolder lpsfFolder(m_nRootFolder);
  113. if (!lpsfFolder)
  114. return;
  115. // turn off redraw and remove all tree items.
  116. m_pTreeCtrl->SetRedraw(FALSE);
  117. m_pTreeCtrl->DeleteAllItems();
  118. HTREEITEM hItemDesktop = InsertDesktopItem(m_nRootFolder);
  119. LPITEMIDLIST pidlRoot = NULL;
  120. if (FAILED(::SHGetSpecialFolderLocation(NULL, m_nRootFolder, &pidlRoot)))
  121. {
  122. pidlRoot = NULL;
  123. }
  124. // Fill in the tree view from the root.
  125. InitTreeViewItems(lpsfFolder, pidlRoot, hItemDesktop);
  126. if (pidlRoot)
  127. {
  128. CShellMalloc malloc;
  129. malloc.Free(pidlRoot);
  130. }
  131. // Sort the items in the tree view
  132. SortChildren(hItemDesktop);
  133. HTREEITEM hItemRoot = m_pTreeCtrl->GetRootItem();
  134. m_pTreeCtrl->Expand(hItemRoot, TVE_EXPAND);
  135. if (hItemDesktop != TVI_ROOT)
  136. {
  137. HTREEITEM hItemChild = m_pTreeCtrl->GetChildItem(hItemDesktop);
  138. m_pTreeCtrl->Select(hItemChild, TVGN_CARET);
  139. if ((::GetWindowLong(m_pTreeCtrl->m_hWnd, GWL_STYLE) & TVS_SINGLEEXPAND) == 0)
  140. {
  141. m_pTreeCtrl->Expand(hItemChild, TVE_EXPAND);
  142. }
  143. }
  144. else
  145. {
  146. m_pTreeCtrl->Select(hItemRoot, TVGN_CARET);
  147. }
  148. // turn on redraw and refresh tree.
  149. m_pTreeCtrl->SetRedraw(TRUE);
  150. m_pTreeCtrl->RedrawWindow();
  151. m_pTreeCtrl->SetFocus();
  152. }
  153. void CXTShellTreeBase::SetAttributes(HTREEITEM hItem, DWORD dwAttributes)
  154. {
  155. MapShellFlagsToItemAttributes(m_pTreeCtrl, hItem, dwAttributes);
  156. }
  157. BOOL CXTShellTreeBase::InitTreeViewItems(LPSHELLFOLDER lpsf, LPITEMIDLIST  lpifq, HTREEITEM     hParent)
  158. {
  159. CWaitCursor wait; // show wait cursor.
  160. // Allocate a shell memory object.
  161. CShellMalloc lpMalloc;
  162. if (!lpMalloc)
  163. return FALSE;
  164. // Get the IEnumIDList object for the given folder.
  165. LPENUMIDLIST lpe = NULL;
  166. if (FAILED(lpsf->EnumObjects(::GetParent(m_pTreeCtrl->m_hWnd), m_uFlags, &lpe)))
  167. return FALSE;
  168. ULONG        ulFetched = 0;
  169. HTREEITEM    hPrev = NULL;
  170. LPITEMIDLIST lpi = NULL;
  171. // Enumerate through the list of folder and non-folder objects.
  172. while (lpe->Next(1, &lpi, &ulFetched) == S_OK)
  173. {
  174. // Create a fully qualified path to the current item
  175. // the SH* shell api's take a fully qualified path pidl,
  176. // (see GetIcon above where I call SHGetFileInfo) whereas the
  177. // interface methods take a relative path pidl.
  178. ULONG ulAttrs = SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_DISPLAYATTRMASK | SFGAO_REMOVABLE;
  179. // Determine what type of object we have.
  180. lpsf->GetAttributesOf(1, (const struct _ITEMIDLIST **)&lpi, &ulAttrs);
  181. // We need this next if statement so that we don't add things like
  182. // the MSN to our tree.  MSN is not a folder, but according to the
  183. // shell it has subfolders.
  184. if ((ulAttrs & SFGAO_FOLDER) || m_bShowFiles)
  185. {
  186. TV_ITEM  tvi;
  187. tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
  188. if ((ulAttrs & SFGAO_HASSUBFOLDER) || (m_bShowFiles && (ulAttrs & SFGAO_FOLDER)))
  189. {
  190. //This item has sub-folders, so let's put the + in the TreeView.
  191. //The first time the user clicks on the item, we'll populate the
  192. //sub-folders.
  193. tvi.cChildren = 1;
  194. tvi.mask |= TVIF_CHILDREN;
  195. }
  196. // Allocate memory for ITEMDATA struct
  197. CString szBuff;
  198. XT_TVITEMDATA* lptvid = new XT_TVITEMDATA;
  199. if (lptvid == NULL || GetName(lpsf, lpi, SHGDN_NORMAL, szBuff) == FALSE)
  200. {
  201. if (lptvid)
  202. {
  203. lpMalloc.Free(lptvid);
  204. }
  205. if (lpe)
  206. {
  207. lpe->Release();
  208. }
  209. if (lpi)
  210. {
  211. lpMalloc.Free(lpi);
  212. }
  213. return FALSE;
  214. }
  215. // Now, make a copy of the ITEMIDLIST and store the parent folders SF.
  216. lptvid->lpi = DuplicateItem(lpMalloc, lpi);
  217. lptvid->lpsfParent = lpsf;
  218. lptvid->lpifq = ConcatPidls(lpMalloc, lpifq, lpi);
  219. lpsf->AddRef();
  220. GetNormalAndSelectedIcons(lptvid->lpifq, &tvi);
  221. tvi.lParam = (LPARAM)lptvid;
  222. tvi.pszText = (LPTSTR)(LPCTSTR)szBuff;
  223. tvi.cchTextMax = 0;
  224. // Populate the TreeVeiw Insert Struct
  225. // The item is the one filled above.
  226. // Insert it after the last item inserted at this level.
  227. // And indicate this is a root entry.
  228. TV_INSERTSTRUCT tvins;
  229. tvins.item = tvi;
  230. tvins.hInsertAfter = hPrev;
  231. tvins.hParent = hParent;
  232. // Add the item to the tree
  233. hPrev = m_pTreeCtrl->InsertItem(&tvins);
  234. SetAttributes(hPrev, ulAttrs);
  235. }
  236. // Free the pidl that the shell gave us.
  237. if (lpi)
  238. {
  239. lpMalloc.Free(lpi);
  240. lpi = 0;
  241. }
  242. }
  243. if (lpi)
  244. {
  245. lpMalloc.Free(lpi);
  246. }
  247. if (lpe)
  248. {
  249. lpe->Release();
  250. }
  251. return TRUE;
  252. }
  253. void CXTShellTreeBase::GetNormalAndSelectedIcons(LPITEMIDLIST lpifq, LPTV_ITEM lptvitem)
  254. {
  255. // Note that we don't check the return value here because if GetIcon()
  256. // fails, then we're in big trouble...
  257. lptvitem->iImage = GetItemIcon(lpifq,
  258. SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
  259. lptvitem->iSelectedImage = GetItemIcon(lpifq,
  260. SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON);
  261. }
  262. void CXTShellTreeBase::OnFolderExpanding(NM_TREEVIEW* pNMTreeView)
  263. {
  264. if (!(pNMTreeView->itemNew.state & TVIS_EXPANDEDONCE))
  265. {
  266. // Long pointer to TreeView item data
  267. XT_TVITEMDATA* lptvid = (XT_TVITEMDATA*)pNMTreeView->itemNew.lParam;
  268. if (lptvid != NULL && lptvid->lpsfParent != NULL)
  269. {
  270. LPSHELLFOLDER lpsf = NULL;
  271. if (SUCCEEDED(lptvid->lpsfParent->BindToObject(lptvid->lpi,
  272. 0, IID_IShellFolder, (LPVOID *)&lpsf)))
  273. {
  274. InitTreeViewItems(lpsf, lptvid->lpifq, pNMTreeView->itemNew.hItem);
  275. }
  276. SortChildren(pNMTreeView->itemNew.hItem);
  277. m_pTreeCtrl->SetItemState(pNMTreeView->itemNew.hItem, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE);
  278. }
  279. }
  280. }
  281. HTREEITEM CXTShellTreeBase::GetContextMenu()
  282. {
  283. CPoint point;
  284. ::GetCursorPos(&point);
  285. m_pTreeCtrl->ScreenToClient(&point);
  286. TV_HITTESTINFO tvhti;
  287. tvhti.pt = point;
  288. m_pTreeCtrl->HitTest(&tvhti);
  289. if (tvhti.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))
  290. {
  291. // Long pointer to TreeView item data
  292. XT_TVITEMDATA*  lptvid = (XT_TVITEMDATA*)m_pTreeCtrl->GetItemData(tvhti.hItem);
  293. m_pTreeCtrl->ClientToScreen(&point);
  294. if (lptvid->lpsfParent == NULL)
  295. {
  296. LPSHELLFOLDER lpShellFolder;
  297. if (FAILED(::SHGetDesktopFolder(&lpShellFolder)))
  298. {
  299. return NULL;
  300. }
  301. ShowContextMenu(m_pTreeCtrl->m_hWnd,
  302. lpShellFolder, lptvid->lpi, &point);
  303. if (lpShellFolder)
  304. {
  305. lpShellFolder->Release();
  306. }
  307. }
  308. else
  309. {
  310. ShowContextMenu(m_pTreeCtrl->m_hWnd,
  311. lptvid->lpsfParent, lptvid->lpi, &point);
  312. }
  313. return tvhti.hItem;
  314. }
  315. return NULL;
  316. }
  317. void CXTShellTreeBase::SortChildren(HTREEITEM hParent)
  318. {
  319. TV_SORTCB tvscb;
  320. tvscb.hParent = hParent;
  321. tvscb.lParam = 0;
  322. tvscb.lpfnCompare = TreeViewCompareProc;
  323. m_pTreeCtrl->SortChildrenCB(&tvscb);
  324. }
  325. BOOL CXTShellTreeBase::OnFolderSelected(NM_TREEVIEW* pNMTreeView, CString &strFolderPath)
  326. {
  327. BOOL bRet = FALSE;
  328. HTREEITEM hItem = pNMTreeView->itemNew.hItem;
  329. if (hItem == NULL)
  330. return FALSE;
  331. LPSHELLFOLDER lpsf = NULL;
  332. // Long pointer to TreeView item data
  333. XT_TVITEMDATA*  lptvid = (XT_TVITEMDATA*)m_pTreeCtrl->GetItemData(hItem);
  334. if (lptvid && lptvid->lpsfParent && lptvid->lpi)
  335. {
  336. if (SUCCEEDED(lptvid->lpsfParent->BindToObject(lptvid->lpi,
  337. 0, IID_IShellFolder, (LPVOID*)&lpsf)))
  338. {
  339. ULONG ulAttrs = SFGAO_FILESYSTEM;
  340. // Determine what type of object we have.
  341. lptvid->lpsfParent->GetAttributesOf(1, (const struct _ITEMIDLIST **)&lptvid->lpi, &ulAttrs);
  342. if (ulAttrs & (SFGAO_FILESYSTEM))
  343. {
  344. TCHAR szBuff[MAX_PATH];
  345. if (::SHGetPathFromIDList(lptvid->lpifq, szBuff))
  346. {
  347. strFolderPath = szBuff;
  348. bRet = TRUE;
  349. }
  350. }
  351. if (m_pTreeCtrl->ItemHasChildren(pNMTreeView->itemNew.hItem) && !(pNMTreeView->itemNew.state & TVIS_EXPANDEDONCE))
  352. {
  353. InitTreeViewItems(lpsf, lptvid->lpifq, pNMTreeView->itemNew.hItem);
  354. SortChildren(pNMTreeView->itemNew.hItem);
  355. m_pTreeCtrl->SetItemState(pNMTreeView->itemNew.hItem, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE);
  356. }
  357. if (lpsf)
  358. {
  359. lpsf->Release();
  360. }
  361. }
  362. }
  363. return bRet;
  364. }
  365. BOOL CXTShellTreeBase::InitSystemImageLists()
  366. {
  367. HIMAGELIST himlSmall = GetSystemImageList(SHGFI_SMALLICON);
  368. if (himlSmall)
  369. {
  370. TreeView_SetImageList(m_pTreeCtrl->GetSafeHwnd(), himlSmall, TVSIL_NORMAL);
  371. return TRUE;
  372. }
  373. return FALSE;
  374. }
  375. BOOL CXTShellTreeBase::GetSelectedFolderPath(CString &strFolderPath)
  376. {
  377. BOOL bRet = FALSE;
  378. HTREEITEM hItem = m_pTreeCtrl->GetSelectedItem();
  379. if (hItem != NULL)
  380. {
  381. // Long pointer to TreeView item data
  382. XT_TVITEMDATA*  lptvid = (XT_TVITEMDATA*)m_pTreeCtrl->GetItemData(hItem);
  383. if (lptvid && lptvid->lpsfParent && lptvid->lpi)
  384. {
  385. LPSHELLFOLDER lpsf = NULL;
  386. if (SUCCEEDED(lptvid->lpsfParent->BindToObject(lptvid->lpi,
  387. 0, IID_IShellFolder, (LPVOID *)&lpsf)))
  388. {
  389. ULONG ulAttrs = SFGAO_FILESYSTEM;
  390. // Determine what type of object we have.
  391. lptvid->lpsfParent->GetAttributesOf(1, (const struct _ITEMIDLIST **)&lptvid->lpi, &ulAttrs);
  392. if (ulAttrs & (SFGAO_FILESYSTEM))
  393. {
  394. TCHAR szBuff[MAX_PATH];
  395. if (::SHGetPathFromIDList(lptvid->lpifq, szBuff))
  396. {
  397. strFolderPath = szBuff;
  398. bRet = TRUE;
  399. }
  400. }
  401. if (lpsf)
  402. {
  403. lpsf->Release();
  404. }
  405. }
  406. }
  407. }
  408. return bRet;
  409. }
  410. BOOL CXTShellTreeBase::FindTreeItem(HTREEITEM hItem, XT_LVITEMDATA* lplvid, BOOL bRecursively)
  411. {
  412. if (lplvid == NULL)
  413. {
  414. return FALSE;
  415. }
  416. if (!bRecursively)
  417. {
  418. hItem = m_pTreeCtrl->GetChildItem(hItem);
  419. }
  420. while (hItem)
  421. {
  422. // Long pointer to TreeView item data
  423. XT_TVITEMDATA*  lptvid = (XT_TVITEMDATA*)m_pTreeCtrl->GetItemData(hItem);
  424. if (lptvid)
  425. {
  426. if (SCODE_CODE(GetScode(lplvid->lpsfParent->CompareIDs(
  427. 0, lplvid->lpi, lptvid->lpi))) == 0)
  428. {
  429. m_pTreeCtrl->EnsureVisible(hItem);
  430. m_pTreeCtrl->SelectItem(hItem);
  431. return TRUE;
  432. }
  433. }
  434. if (bRecursively)
  435. {
  436. HTREEITEM hNextItem = m_pTreeCtrl->GetChildItem(hItem);
  437. if (hNextItem)
  438. {
  439. if (FindTreeItem(hNextItem, lplvid))
  440. {
  441. return TRUE;
  442. }
  443. }
  444. }
  445. hItem = m_pTreeCtrl->GetNextSiblingItem(hItem);
  446. }
  447. return FALSE;
  448. }
  449. void CXTShellTreeBase::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)
  450. {
  451. NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
  452. OnFolderExpanding(pNMTreeView);
  453. *pResult = 0;
  454. }
  455. void CXTShellTreeBase::SelectionChanged(HTREEITEM hItem, CString strFolderPath)
  456. {
  457. if (hItem != NULL && !m_bTunneling)
  458. {
  459. if (!m_pComboBox || !::IsWindow(m_pComboBox->m_hWnd))
  460. return;
  461. // update combo box association.
  462. if (m_pComboBox->IsKindOf(RUNTIME_CLASS(CXTComboBoxEx)))
  463. {
  464. CXTComboBoxEx* pComboBoxEx = DYNAMIC_DOWNCAST(CXTComboBoxEx, m_pComboBox);
  465. ASSERT_VALID(pComboBoxEx);
  466. int nFound = CB_ERR;
  467. int nIndex;
  468. for (nIndex = 0; nIndex < pComboBoxEx->GetCount(); ++nIndex)
  469. {
  470. CString strText;
  471. pComboBoxEx->GetLBText(nIndex, strText);
  472. if (strFolderPath.Compare(strText) == 0)
  473. {
  474. nFound = nIndex;
  475. pComboBoxEx->SetCurSel(nIndex);
  476. break;
  477. }
  478. }
  479. if (nFound == CB_ERR)
  480. {
  481. HTREEITEM hti = m_pTreeCtrl->GetSelectedItem();
  482. ASSERT(hti);
  483. if (strFolderPath.IsEmpty())
  484. {
  485. strFolderPath = m_pTreeCtrl->GetItemText(hti);
  486. }
  487. int nImage, nSelectedImage;
  488. m_pTreeCtrl->GetItemImage(hti, nImage, nSelectedImage);
  489. pComboBoxEx->InsertItem(0, strFolderPath, 0, nImage, nImage);
  490. pComboBoxEx->SetCurSel(0);
  491. pComboBoxEx->SetItemDataPtr(0, hti);
  492. }
  493. }
  494. else if (m_pComboBox->IsKindOf(RUNTIME_CLASS(CComboBox)))
  495. {
  496. CComboBox* pComboBox = DYNAMIC_DOWNCAST(CComboBox, m_pComboBox);
  497. ASSERT_VALID(pComboBox);
  498. int nFound = pComboBox->FindStringExact(-1, strFolderPath);
  499. if (nFound == CB_ERR)
  500. {
  501. HTREEITEM hti = m_pTreeCtrl->GetSelectedItem();
  502. ASSERT(hti);
  503. pComboBox->InsertString(0, strFolderPath);
  504. pComboBox->SetCurSel(0);
  505. pComboBox->SetItemDataPtr(0, (HTREEITEM)hti);
  506. }
  507. else
  508. {
  509. pComboBox->SetCurSel(nFound);
  510. }
  511. }
  512. }
  513. }
  514. void CXTShellTreeBase::OnDeleteTreeItem(NMHDR* pNMHDR, LRESULT* pResult)
  515. {
  516. NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
  517. XT_TVITEMDATA* lptvid = (XT_TVITEMDATA*)pNMTreeView->itemOld.lParam;
  518. if (lptvid != NULL)
  519. {
  520. CShellMalloc lpMalloc;
  521. if (lptvid->lpi)
  522. {
  523. lpMalloc.Free(lptvid->lpi);
  524. lptvid->lpi = NULL;
  525. }
  526. if (lptvid->lpsfParent)
  527. {
  528. lptvid->lpsfParent->Release();
  529. lptvid->lpsfParent = NULL;
  530. }
  531. if (lptvid->lpifq)
  532. {
  533. lpMalloc.Free(lptvid->lpifq);
  534. lptvid->lpifq = NULL;
  535. }
  536. delete lptvid;
  537. }
  538. *pResult = 0;
  539. }
  540. void CXTShellTreeBase::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
  541. {
  542. NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
  543. CString strFolderPath;
  544. OnFolderSelected(pNMTreeView, strFolderPath);
  545. if (strFolderPath.IsEmpty())
  546. {
  547. strFolderPath = m_pTreeCtrl->GetItemText(pNMTreeView->itemNew.hItem);
  548. }
  549. // currently selected TreeItem
  550. SelectionChanged(m_pTreeCtrl->GetSelectedItem(), strFolderPath);
  551. *pResult = 0;
  552. }
  553. void CXTShellTreeBase::OnRclick(NMHDR* /*pNMHDR*/, LRESULT* pResult)
  554. {
  555. // Display the shell context menu.
  556. if (m_bContextMenu == TRUE)
  557. {
  558. HTREEITEM hItem = GetContextMenu();
  559. if (hItem != NULL)
  560. {
  561. // TODO: Additional error handling.
  562. }
  563. }
  564. *pResult = 0;
  565. }
  566. BOOL CXTShellTreeBase::InitializeTree(DWORD dwStyle/*= TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT*/)
  567. {
  568. if (m_pTreeCtrl->GetImageList(TVSIL_NORMAL) == NULL)
  569. {
  570. // Initialize the image list for the list view and populate it.
  571. VERIFY(InitSystemImageLists());
  572. // Set the style for the tree control.
  573. m_pTreeCtrl->ModifyStyle(0, dwStyle);
  574. // Make sure multi-select mode is disabled.
  575. EnableMultiSelect(FALSE);
  576. return TRUE;
  577. }
  578. return FALSE;
  579. }
  580. void CXTShellTreeBase::InitTreeNode(HTREEITEM hItem, XT_TVITEMDATA* lptvid)
  581. {
  582. m_pTreeCtrl->SetRedraw(FALSE);
  583. if (lptvid)
  584. {
  585. LPSHELLFOLDER lpsf = NULL;
  586. if (SUCCEEDED(lptvid->lpsfParent->BindToObject(lptvid->lpi,
  587. 0, IID_IShellFolder, (LPVOID *)&lpsf)))
  588. {
  589. InitTreeViewItems(lpsf, lptvid->lpifq, hItem);
  590. }
  591. SortChildren(hItem);
  592. }
  593. m_pTreeCtrl->SetRedraw(TRUE);
  594. }
  595. HTREEITEM CXTShellTreeBase::SearchTree(HTREEITEM hItem, LPCITEMIDLIST pABSPidl)
  596. {
  597. XT_TVITEMDATA *pItem = NULL;
  598. HTREEITEM hChildItem = m_pTreeCtrl->GetChildItem(hItem);
  599. CShellSpecialFolder pShellFolder;
  600. if (!pShellFolder)
  601. return NULL;
  602. while (hChildItem)
  603. {
  604. // Get the pidl that is stored in the tree node
  605. pItem = (XT_TVITEMDATA *)m_pTreeCtrl->GetItemData(hChildItem);
  606. // See if it matches the one we're looking for
  607. if (ComparePidls(pItem->lpifq, pABSPidl, pShellFolder))
  608. {
  609. m_pTreeCtrl->Select(hChildItem, TVGN_CARET);
  610. // Ensure that we are expanded
  611. UINT uState = m_pTreeCtrl->GetItemState(hChildItem, TVIS_EXPANDEDONCE);
  612. if (!(uState & TVIS_EXPANDEDONCE))
  613. {
  614. InitTreeNode(hChildItem, (XT_TVITEMDATA*)m_pTreeCtrl->GetItemData(hChildItem));
  615. m_pTreeCtrl->SetItemState(hChildItem, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE);
  616. }
  617. break;
  618. }
  619. // Didn't compare... try next one
  620. hChildItem = m_pTreeCtrl->GetNextSiblingItem(hChildItem);
  621. }
  622. return hChildItem;
  623. }
  624. BOOL CXTShellTreeBase::TunnelTree(CString strFindPath)
  625. {
  626. if (strFindPath.IsEmpty())
  627. return false;
  628. m_bTunneling = true;
  629. BOOL bLock = m_pTreeCtrl->LockWindowUpdate();
  630. BOOL bFound = false;
  631. LPITEMIDLIST pidlPath;
  632. // Attempt to get the folder's item list
  633. pidlPath = IDLFromPath(strFindPath);
  634. // If it is NULL then see if it is one of the special folders
  635. if (pidlPath == NULL)
  636. {
  637. // These are the ones we care about.
  638. const int nCSIDLMax = 0x001b;
  639. for (int i = 0; i <= nCSIDLMax; i++)
  640. {
  641. LPITEMIDLIST pidlSpecialPath = NULL;
  642. if (::SHGetSpecialFolderLocation(NULL, i, &pidlSpecialPath) != NOERROR)
  643. continue;
  644. SHFILEINFO fileInfo;
  645. ::ZeroMemory(&fileInfo, sizeof(fileInfo));
  646. ::SHGetFileInfo((LPCTSTR)pidlSpecialPath, NULL, &fileInfo, sizeof(fileInfo),
  647. SHGFI_PIDL | SHGFI_DISPLAYNAME);
  648. CString cs = fileInfo.szDisplayName;
  649. if (cs.CompareNoCase(strFindPath) == 0)
  650. {
  651. // Found the pidl for the special folder
  652. pidlPath = pidlSpecialPath;
  653. break;
  654. }
  655. }
  656. }
  657. if (pidlPath != NULL)
  658. {
  659. // Now work through the list and tree nodes until we compare
  660. int nItems = GetPidlCount(pidlPath);
  661. LPITEMIDLIST pPartPidl;
  662. LPITEMIDLIST pABSPidl = NULL;
  663. HTREEITEM hItem = m_pTreeCtrl->GetRootItem();
  664. bFound = false;
  665. // Loop through all the parts and see if we can find a match in the tree.  It should
  666. // be there unless something got added to the namespace after we built the tree last
  667. // and we didn't catch it, but that's pretty unlikely.
  668. for (int i = 0; i < nItems; i++)
  669. {
  670. pPartPidl = CopyPidlItem(pidlPath, i);
  671. pABSPidl = ConcatPidls(pABSPidl, pPartPidl);
  672. FreePidl(pPartPidl);
  673. hItem = SearchTree(hItem, pABSPidl);
  674. if (!hItem)
  675. break; // Our partial path should still found
  676. }
  677. // If it was found the final path should compare to the full path entered
  678. // and the hItem should be set to the place in the tree where the path ends
  679. if (hItem && (nItems == 0 || ComparePidls(pidlPath, pABSPidl, NULL)))
  680. {
  681. m_pTreeCtrl->Select(hItem, TVGN_CARET);
  682. // Ensure that we are expanded
  683. UINT uState = m_pTreeCtrl->GetItemState(hItem, TVIS_EXPANDEDONCE);
  684. if (!(uState & TVIS_EXPANDEDONCE))
  685. {
  686. InitTreeNode(hItem, (XT_TVITEMDATA*)m_pTreeCtrl->GetItemData(hItem));
  687. m_pTreeCtrl->SetItemState(hItem, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE);
  688. }
  689. bFound = true;
  690. }
  691. // Clean up
  692. if (pidlPath)
  693. FreePidl(pidlPath);
  694. if (pABSPidl)
  695. FreePidl(pABSPidl);
  696. }
  697. else
  698. {
  699. // Must not be a special folder (stand alone) or a path that ParseDisplayName() doesn't recognize so look through tree
  700. // directly to see if we can find it that way.
  701. // Start at Desktop ...
  702. HTREEITEM hItemRoot = m_pTreeCtrl->GetRootItem();
  703. TCHAR* pszNext = NULL;
  704. TCHAR szBuff[MAX_PATH];
  705. STRCPY_S(szBuff, MAX_PATH, strFindPath);
  706. TCHAR* lpszContext = 0;
  707. pszNext = STRTOK_S(szBuff, _T("\/"), &lpszContext);
  708. bFound = false;
  709. if (pszNext != NULL)
  710. {
  711. CString strItemText(m_pTreeCtrl->GetItemText(hItemRoot));
  712. // Are we looking from desktop?
  713. if (strItemText.CompareNoCase(pszNext) == 0)
  714. pszNext = STRTOK_S(NULL, _T("\/"), &lpszContext);
  715. hItemRoot = m_pTreeCtrl->GetChildItem(hItemRoot);
  716. // Ensure that we are expanded
  717. UINT uState = m_pTreeCtrl->GetItemState(hItemRoot, TVIS_EXPANDEDONCE);
  718. if (!(uState & TVIS_EXPANDEDONCE))
  719. {
  720. InitTreeNode(hItemRoot, (XT_TVITEMDATA*)m_pTreeCtrl->GetItemData(hItemRoot));
  721. m_pTreeCtrl->SetItemState(hItemRoot, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE);
  722. }
  723. while (pszNext && hItemRoot)
  724. {
  725. strItemText = m_pTreeCtrl->GetItemText(hItemRoot);
  726. if (strItemText.CompareNoCase(pszNext) == 0)
  727. {
  728. // Found it
  729. // We know this was successful - expand at this new root
  730. m_pTreeCtrl->Select(hItemRoot, TVGN_CARET);
  731. // Ensure that we are expanded
  732. uState = m_pTreeCtrl->GetItemState(hItemRoot, TVIS_EXPANDEDONCE);
  733. if (!(uState & TVIS_EXPANDEDONCE))
  734. {
  735. InitTreeNode(hItemRoot, (XT_TVITEMDATA*)m_pTreeCtrl->GetItemData(hItemRoot));
  736. m_pTreeCtrl->SetItemState(hItemRoot, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE);
  737. }
  738. pszNext = STRTOK_S(NULL, _T("\/"), &lpszContext);
  739. if (pszNext)
  740. {
  741. // Move down a level
  742. hItemRoot = m_pTreeCtrl->GetChildItem(hItemRoot);
  743. }
  744. }
  745. else
  746. {
  747. hItemRoot = m_pTreeCtrl->GetNextSiblingItem(hItemRoot);
  748. }
  749. }
  750. }
  751. }
  752. if (bLock)
  753. {
  754. m_pTreeCtrl->UnlockWindowUpdate();
  755. }
  756. m_bTunneling = false;
  757. // make sure list gets updated.
  758. SelectionChanged(m_pTreeCtrl->GetSelectedItem(), strFindPath);
  759. return bFound;
  760. }
  761. BOOL CXTShellTreeBase::GetFolderItemPath(HTREEITEM hItem, CString &strFolderPath)
  762. {
  763. BOOL bRet = FALSE;
  764. // Long pointer to TreeView item data
  765. XT_TVITEMDATA*  lptvid = (XT_TVITEMDATA*)m_pTreeCtrl->GetItemData(hItem);
  766. if (lptvid && lptvid->lpsfParent && lptvid->lpi)
  767. {
  768. LPSHELLFOLDER lpsf = NULL;
  769. if (SUCCEEDED(lptvid->lpsfParent->BindToObject(lptvid->lpi,
  770. 0, IID_IShellFolder, (LPVOID *)&lpsf)))
  771. {
  772. ULONG ulAttrs = SFGAO_FILESYSTEM;
  773. // Determine what type of object we have.
  774. lptvid->lpsfParent->GetAttributesOf(1,
  775. (const struct _ITEMIDLIST **)&lptvid->lpi, &ulAttrs);
  776. if (ulAttrs & (SFGAO_FILESYSTEM))
  777. {
  778. TCHAR szBuff[MAX_PATH];
  779. if (::SHGetPathFromIDList(lptvid->lpifq, szBuff))
  780. {
  781. strFolderPath = szBuff;
  782. bRet = TRUE;
  783. }
  784. }
  785. }
  786. if (lpsf)
  787. {
  788. lpsf->Release();
  789. }
  790. }
  791. return bRet;
  792. }
  793. //-----------------------------------------------------------------------------
  794. // FUNCTION: XTFuncPathFindNextComponent()
  795. //-----------------------------------------------------------------------------
  796. CString CXTShellTreeBase::PathFindNextComponent(const CString& pszPath)
  797. {
  798. // Find the path delimiter
  799. int nIndex = pszPath.Find(_T('\'));
  800. if (nIndex == -1)
  801. return _T("");
  802. return pszPath.Mid(nIndex + 1);
  803. }
  804. void CXTShellTreeBase::PopulateTree(LPCTSTR lpszPath)
  805. {
  806. CString strFolder = lpszPath;
  807. CString strNextFolder;
  808. CString strPath;
  809. CShellMalloc lpMalloc;
  810. if (!lpMalloc)
  811. return;
  812. // Get a pointer to the desktop folder.
  813. LPSHELLFOLDER lpSF = NULL;
  814. if (FAILED(::SHGetDesktopFolder(&lpSF)))
  815. return;
  816. LPITEMIDLIST lpIDL = NULL;
  817. // turn off redraw and remove all tree items.
  818. m_pTreeCtrl->SetRedraw(FALSE);
  819. m_pTreeCtrl->DeleteAllItems();
  820. do
  821. {
  822. // Get the Next Component
  823. strNextFolder = PathFindNextComponent(strFolder);
  824. if (!strNextFolder.IsEmpty())
  825. {
  826. strPath = strFolder.Left(strFolder.GetLength() -
  827. strNextFolder.GetLength());
  828. }
  829. else
  830. {
  831. strPath = strFolder;
  832. strNextFolder.Empty();
  833. }
  834. // Get ShellFolder Pidl
  835. ULONG eaten;
  836. if (FAILED(lpSF->ParseDisplayName(NULL, NULL, (LPOLESTR)XTP_CT2CW(strPath),
  837. &eaten, &lpIDL, NULL)))
  838. {
  839. break;
  840. }
  841. LPSHELLFOLDER lpSF2 = NULL;
  842. if (FAILED(lpSF->BindToObject(lpIDL, 0, IID_IShellFolder, (LPVOID*)&lpSF2)))
  843. {
  844. break;
  845. }
  846. lpMalloc.Free(lpIDL);
  847. // Release the Parent Folder pointer.
  848. lpSF->Release();
  849. // Change Folder Info
  850. lpSF = lpSF2;
  851. strFolder = strNextFolder;
  852. }
  853. while (!strNextFolder.IsEmpty());
  854. // get the base folders item ide list.
  855. lpIDL = IDLFromPath(lpszPath);
  856. SHFILEINFO fileInfo;
  857. ::ZeroMemory(&fileInfo, sizeof(fileInfo));
  858. ::SHGetFileInfo((LPCTSTR)lpIDL, NULL, &fileInfo, sizeof(fileInfo),
  859. SHGFI_PIDL | SHGFI_ATTRIBUTES | SHGFI_DISPLAYNAME);
  860. TV_ITEM  tvi;
  861. tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
  862. // Allocate memory for ITEMDATA struct
  863. XT_TVITEMDATA* lptvid = new XT_TVITEMDATA;
  864. if (lptvid != NULL)
  865. {
  866. HTREEITEM hItem = TVI_ROOT;
  867. // get the normal and selected icons for the path.
  868. GetNormalAndSelectedIcons(lpIDL, &tvi);
  869. // Now, make a copy of the ITEMIDLIST and store the parent folders SF.
  870. lptvid->lpi = DuplicateItem(lpMalloc, lpIDL);
  871. lptvid->lpsfParent = NULL;
  872. lptvid->lpifq = ConcatPidls(lpMalloc, NULL, lpIDL);
  873. TCHAR szBuff[MAX_PATH];
  874. STRCPY_S(szBuff, MAX_PATH, fileInfo.szDisplayName);
  875. tvi.lParam = (LPARAM)lptvid;
  876. tvi.pszText = szBuff;
  877. tvi.cchTextMax = MAX_PATH;
  878. // Populate the TreeView Insert Struct
  879. // The item is the one filled above.
  880. // Insert it after the last item inserted at this level.
  881. // And indicate this is a root entry.
  882. TV_INSERTSTRUCT tvins;
  883. tvins.item = tvi;
  884. tvins.hInsertAfter = hItem;
  885. tvins.hParent = hItem;
  886. // Add the item to the tree
  887. hItem = m_pTreeCtrl->InsertItem(&tvins);
  888. // insert child items.
  889. InitTreeViewItems(lpSF, lpIDL, hItem);
  890. // Sort the items in the tree view
  891. SortChildren(TVI_ROOT);
  892. // expand parent.
  893. m_pTreeCtrl->Expand(hItem, TVE_EXPAND);
  894. }
  895. // turn on redraw and refresh tree.
  896. m_pTreeCtrl->SetRedraw(TRUE);
  897. m_pTreeCtrl->RedrawWindow();
  898. lpMalloc.Free(lpIDL);
  899. if (lpSF)
  900. {
  901. lpSF->Release();
  902. }
  903. }
  904. void CXTShellTreeBase::AssociateCombo(CWnd* pWnd)
  905. {
  906. ASSERT_VALID(pWnd); // must be a valid window.
  907. if (::IsWindow(pWnd->GetSafeHwnd()))
  908. {
  909. m_pComboBox = pWnd;
  910. if (m_pComboBox->IsKindOf(RUNTIME_CLASS(CXTComboBoxEx)))
  911. {
  912. HIMAGELIST hImageList = GetSystemImageList(SHGFI_SMALLICON);
  913. if (hImageList != NULL)
  914. {
  915. CXTComboBoxEx* pComboBoxEx = DYNAMIC_DOWNCAST(CXTComboBoxEx, m_pComboBox);
  916. ASSERT_VALID(pComboBoxEx);
  917. pComboBoxEx->SetImageList(CImageList::FromHandle(hImageList));
  918. }
  919. }
  920. }
  921. }
  922. BOOL CXTShellTreeBase::OnEraseBkgnd(CDC* /*pDC*/)
  923. {
  924. return TRUE;
  925. }
  926. void CXTShellTreeBase::OnPaint()
  927. {
  928. CPaintDC dc(m_pTreeCtrl);
  929. DoPaint(dc, FALSE);
  930. }
  931. void CXTShellTreeBase::BeginDrag(NM_TREEVIEW* pNMTreeView)
  932. {
  933. // Long pointer to ListView item data
  934. XT_TVITEMDATA*  lplvid = (XT_TVITEMDATA*)m_pTreeCtrl->GetItemData(pNMTreeView->itemNew.hItem);
  935. ASSERT(lplvid);
  936. if (lplvid && lplvid->lpsfParent)
  937. {
  938. LPDATAOBJECT lpdo;
  939. HRESULT hResult = lplvid->lpsfParent->GetUIObjectOf(AfxGetMainWnd()->m_hWnd, 1,
  940. (const struct _ITEMIDLIST**)&lplvid->lpi, IID_IDataObject, 0, (LPVOID*)&lpdo);
  941. if (SUCCEEDED(hResult))
  942. {
  943. LPDROPSOURCE lpds = new CXTDropSource();
  944. ASSERT(lpds != NULL);
  945. DWORD dwEffect;
  946. ::DoDragDrop(lpdo, lpds,
  947. DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK, &dwEffect);
  948. lpdo->Release();
  949. lpds->Release();
  950. }
  951. }
  952. }