IEFolderTreeCtrl.cpp
上传用户:yatsl7111
上传日期:2007-01-08
资源大小:1433k
文件大小:15k
源码类别:

图形图象

开发平台:

Visual C++

  1. //*******************************************************************************
  2. // COPYRIGHT NOTES
  3. // ---------------
  4. // You may use this source code, compile or redistribute it as part of your application 
  5. // for free. You cannot redistribute it as a part of a software development 
  6. // library without the agreement of the author. If the sources are 
  7. // distributed along with the application, you should leave the original 
  8. // copyright notes in the source code without any changes.
  9. // This code can be used WITHOUT ANY WARRANTIES at your own risk.
  10. // 
  11. // For the latest updates to this code, check this site:
  12. // http://www.masmex.com 
  13. // after Sept 2000
  14. // 
  15. // Copyright(C) 2000 Philip Oldaker <email: philip@masmex.com>
  16. //*******************************************************************************
  17. #include "stdafx.h"
  18. #include "IEFolderTreeCtrl.h"
  19. #include "UIMessages.h"
  20. #include <vector>
  21. #include <map>
  22. #ifdef _DEBUG
  23. #define new DEBUG_NEW
  24. #undef THIS_FILE
  25. static char THIS_FILE[] = __FILE__;
  26. #endif
  27. typedef map<CShellPidlCompare,HTREEITEM> mapPidlToHTREEITEM;
  28. typedef vector<LPITEMIDLIST> vecPidl;
  29. int CALLBACK CIEFolderTreeCtrl::CompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  30. {
  31. LPTVITEMDATA lptvid1 = (LPTVITEMDATA)((CUIListCtrlData*)lParam1)->GetExtData();
  32. LPTVITEMDATA lptvid2 = (LPTVITEMDATA)((CUIListCtrlData*)lParam2)->GetExtData();
  33. LPSHELLFOLDER psfParent = (LPSHELLFOLDER)lParamSort;
  34. HRESULT hr = psfParent->CompareIDs (0, lptvid1->lpi, lptvid2->lpi);
  35. if (FAILED (hr))
  36. return 0;
  37. return (short)hr;
  38. /////////////////////////////////////////////////////////////////////////////
  39. // CIEFolderTreeCtrl
  40. CIEFolderTreeCtrl::CIEFolderTreeCtrl()
  41. {
  42. SHGetMalloc(&m_pMalloc);
  43. m_hImageList = NULL;
  44. }
  45. CIEFolderTreeCtrl::~CIEFolderTreeCtrl()
  46. {
  47. // Free our memory allocator
  48. if (m_pMalloc)
  49. m_pMalloc->Release();
  50. }
  51. void CIEFolderTreeCtrl::Refresh()
  52. {
  53. HTREEITEM hItem = GetRootItem();
  54.     if (hItem == NULL)
  55.         return;
  56. CWaitCursor w;
  57. SetRedraw(FALSE);
  58.     RefreshNode(hItem);
  59. SetRedraw(TRUE);
  60. }
  61. void CIEFolderTreeCtrl::OnDeleteItemData(DWORD dwData)
  62. {
  63. LPTVITEMDATA pItemData=(LPTVITEMDATA)dwData;
  64. if (pItemData == NULL)
  65. return;
  66. if (pItemData->lpsfParent)
  67. pItemData->lpsfParent->Release();
  68. if (pItemData->lpi)
  69. m_pMalloc->Free(pItemData->lpi);  
  70. if (pItemData->lpifq)
  71. m_pMalloc->Free(pItemData->lpifq);  
  72. m_pMalloc->Free(pItemData);
  73. }
  74. BOOL CIEFolderTreeCtrl::LoadURL(HTREEITEM hItem)
  75. {
  76. if (GetRootItem() == hItem)
  77. return FALSE;
  78. if (ItemHasChildren(hItem))
  79. return FALSE;
  80. CString strText(GetItemText(hItem));
  81. AfxMessageBox(strText);
  82. return TRUE;
  83. }
  84. bool CIEFolderTreeCtrl::LoadItems(LPCTSTR pszPath,DWORD dwFolderType)
  85. {
  86. ASSERT(m_pMalloc);
  87. if (m_hImageList == NULL)
  88. Init();
  89. bool bRet = false;
  90. CWaitCursor w;
  91. DeleteAllItems();
  92. //DeleteItemData();
  93. LPITEMIDLIST pidl=NULL;
  94. LPSHELLFOLDER psfDesktop=NULL;
  95. LPSHELLFOLDER pSubFolder=NULL;
  96. HRESULT hr = SHGetDesktopFolder(&psfDesktop);
  97. if (dwFolderType)
  98. {
  99. hr = SHGetSpecialFolderLocation(NULL, dwFolderType, &pidl);
  100. #ifdef _DEBUG
  101. CString sPath;
  102. GetShellPidl().SHPidlToPathEx(pidl,sPath);
  103. TRACE1("Populating special folder %sn",sPath);
  104. #endif
  105. hr = psfDesktop->BindToObject(pidl, 0, IID_IShellFolder,(LPVOID*)&pSubFolder);
  106. }
  107. else
  108. {
  109. if (pszPath && *pszPath != '')
  110. {
  111. hr = m_ShellPidl.SHPathToPidlEx(pszPath,&pidl,psfDesktop);
  112. if (SUCCEEDED(hr))
  113. {
  114. hr = psfDesktop->BindToObject(pidl, 0, IID_IShellFolder,(LPVOID*)&pSubFolder);
  115. if (SUCCEEDED(hr))
  116. m_sRootPath = pszPath;
  117. }
  118. }
  119. else
  120. {
  121. hr = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
  122. }
  123. }
  124. LPCTSTR pszTitle=NULL;
  125. SHFILEINFO fileInfo;
  126. ZeroMemory(&fileInfo,sizeof(fileInfo));
  127. int nImage=0, nSelImage=0;
  128. if (pidl)
  129. {
  130. SHGetFileInfo((LPCTSTR)pidl, NULL, &fileInfo, sizeof(fileInfo), SHGFI_PIDL|SHGFI_ATTRIBUTES|SHGFI_DISPLAYNAME);
  131. pszTitle = fileInfo.szDisplayName;
  132. m_ShellPidl.GetNormalAndSelectedIcons(pidl, nImage, nSelImage);
  133. if (nImage < 0)
  134. nImage = 0;
  135. if (nSelImage < 0)
  136. nSelImage = 0;
  137. }
  138. if (SUCCEEDED(hr))
  139. {
  140. LPTVITEMDATA lptvid = (LPTVITEMDATA)m_pMalloc->Alloc(sizeof(TVITEMDATA));
  141. if (lptvid == NULL)
  142. return bRet;
  143. ZeroMemory(lptvid,sizeof(TVITEMDATA));
  144. // Now make a copy of the ITEMIDLIST.
  145. lptvid->lpi = m_ShellPidl.CopyLastItemID(pidl);
  146. lptvid->lpifq = m_ShellPidl.CopyItemIDList(pidl);
  147. lptvid->lpsfParent = NULL;
  148. if (lptvid->lpsfParent)
  149. lptvid->lpsfParent->AddRef();
  150. HTREEITEM hRootItem = AddAnItem((HTREEITEM)NULL,pszTitle,(LPARAM)lptvid,(HTREEITEM)TVI_ROOT,nImage,nSelImage);
  151. AddItems(hRootItem,pSubFolder ? pSubFolder : psfDesktop);
  152. Expand(hRootItem,TVE_EXPAND);
  153. PostMessage(WM_APP_POPULATE_TREE);
  154. bRet = true;
  155. }
  156. if (pidl)
  157. m_pMalloc->Free(pidl);
  158. if (pSubFolder)
  159. pSubFolder->Release();
  160. if (psfDesktop)
  161. psfDesktop->Release();
  162. return bRet;
  163. }
  164. bool CIEFolderTreeCtrl::AddItems(HTREEITEM hItem,IShellFolder* pFolder)
  165. {
  166. IEnumIDList* pItems = NULL;
  167. LPITEMIDLIST pidlNext = NULL;
  168. DWORD dwFlags = SHCONTF_FOLDERS;
  169. if (GetShellSettings().ShowAllObjects() && !GetShellSettings().ShowSysFiles())
  170. dwFlags |= SHCONTF_INCLUDEHIDDEN;
  171. // Enumerate all object in the given folder
  172. HRESULT hr = pFolder->EnumObjects(NULL, dwFlags, &pItems);
  173. if (hr != NOERROR)
  174. return false;
  175. while (NOERROR == hr)
  176. {
  177. hr = pItems->Next(1, &pidlNext, NULL);
  178. if (hr == S_FALSE || pidlNext == NULL)
  179. break;
  180. if (AddFolder(hItem,pidlNext,pFolder) == NULL)
  181. m_pMalloc->Free(pidlNext);
  182. pidlNext = NULL;
  183. }
  184. if (pidlNext)
  185. m_pMalloc->Free(pidlNext);
  186. if (pItems)
  187. pItems->Release();
  188. Sort(hItem,pFolder);
  189. return true;
  190. }
  191. void CIEFolderTreeCtrl::Sort(HTREEITEM hParent,LPSHELLFOLDER pFolder)
  192. {
  193. // Sort the the node based on pidls
  194. TVSORTCB cbSort;
  195. cbSort.hParent = hParent;
  196. cbSort.lpfnCompare = CompareProc;
  197. cbSort.lParam = (LPARAM)pFolder;
  198. SortChildrenCB(&cbSort);
  199. }
  200. HTREEITEM CIEFolderTreeCtrl::AddFolder(HTREEITEM hItem,LPCTSTR pszPath)
  201. {
  202. LPITEMIDLIST pidlfq=NULL;
  203. HRESULT hr = GetShellPidl().SHPathToPidlEx(pszPath,&pidlfq,NULL);
  204. if (FAILED(hr))
  205. return NULL;
  206. LPTVITEMDATA lptvid = (LPTVITEMDATA)GetItemData(hItem);
  207. ASSERT(lptvid);
  208. LPITEMIDLIST pidl = GetShellPidl().CopyLastItemID(pidlfq);
  209. HTREEITEM hFolderItem = AddFolder(hItem,pidl,lptvid->lpsfParent);
  210. if (pidlfq)
  211. m_pMalloc->Free(pidlfq);
  212. return hFolderItem;
  213. }
  214. HTREEITEM CIEFolderTreeCtrl::AddFolder(HTREEITEM hItem,LPITEMIDLIST pidl,LPSHELLFOLDER pFolder)
  215. {
  216. ASSERT(m_pMalloc);
  217. LPTSTR pszFilePath = NULL;
  218. STRRET StrRetFilePath;
  219. SHFILEINFO FileInfo;
  220. ZeroMemory(&FileInfo,sizeof(FileInfo));
  221. FileInfo.dwAttributes=SFGAO_HASSUBFOLDER | SFGAO_FOLDER;
  222. HRESULT hr = pFolder->GetAttributesOf(1,(LPCITEMIDLIST*)&pidl,&FileInfo.dwAttributes);
  223. if (FAILED(hr))
  224. return NULL;
  225. // Create a submenu if this item is a folder
  226. if (!(FileInfo.dwAttributes & (SFGAO_HASSUBFOLDER | SFGAO_FOLDER)))
  227. return NULL;
  228. pFolder->GetDisplayNameOf(pidl,SHGDN_INFOLDER,&StrRetFilePath);
  229. GetShellPidl().StrRetToStr(StrRetFilePath, &pszFilePath, pidl);
  230. if (pszFilePath)
  231. {
  232. lstrcpy(FileInfo.szDisplayName,pszFilePath);
  233. m_pMalloc->Free(pszFilePath);
  234. pszFilePath = NULL;
  235. }
  236. // allocate new itemdata
  237. LPTVITEMDATA lptvid = (LPTVITEMDATA)m_pMalloc->Alloc(sizeof(TVITEMDATA));
  238. if (lptvid == NULL)
  239. return NULL;
  240. ZeroMemory(lptvid,sizeof(TVITEMDATA));
  241. // get itemdata for current node
  242. LPTVITEMDATA lpptvid = (LPTVITEMDATA)GetItemData(hItem);
  243. ASSERT(lpptvid);
  244. // create new fully qualified pidl
  245. lptvid->lpifq = m_ShellPidl.ConcatPidl(lpptvid->lpifq,pidl);
  246. // save relative pidl (will be freed in the clean up)
  247. lptvid->lpi = pidl;
  248. int nImage=0;
  249. int nSelImage=0;
  250. // get icons for new fq pidl
  251. m_ShellPidl.GetNormalAndSelectedIcons(lptvid->lpifq, nImage, nSelImage);
  252. // save folder for later use(when node is expanded)
  253. lptvid->lpsfParent = pFolder; // pointer to parent folder
  254. // keep hold of it(will be released in clean up)
  255. lptvid->lpsfParent->AddRef();
  256. // add the node to the tree unsorted (will be sorted later)
  257. int nChildren = 0;
  258. if (FileInfo.dwAttributes & SFGAO_HASSUBFOLDER)
  259. {
  260. nChildren=1;
  261. }
  262. HTREEITEM hNewItem = AddAnItem(hItem,FileInfo.szDisplayName,(DWORD)lptvid,(HTREEITEM)TVI_FIRST,nImage,nSelImage,nChildren);
  263. // set overlay images
  264. if (hNewItem)
  265. {
  266. SetAttributes(hNewItem,pFolder,pidl);
  267. }
  268. return hNewItem;
  269. }
  270. void CIEFolderTreeCtrl::SetAttributes(HTREEITEM hItem,LPSHELLFOLDER pFolder,LPITEMIDLIST pidl)
  271. {
  272. DWORD dwAttributes = SFGAO_DISPLAYATTRMASK | SFGAO_REMOVABLE;
  273. HRESULT hr = pFolder->GetAttributesOf(1,(LPCITEMIDLIST*)&pidl,&dwAttributes);
  274. if (FAILED(hr))
  275. return;  
  276. if ((dwAttributes & SFGAO_COMPRESSED) && GetShellSettings().ShowCompColor())
  277. SetTextColor(hItem,RGB(0,0,255));
  278. else
  279. SetDefaultTextColor(hItem);
  280. if (dwAttributes & SFGAO_GHOSTED)
  281. SetItemState(hItem,TVIS_CUT,TVIS_CUT);
  282. else
  283. SetItemState(hItem,TVIS_CUT,0);
  284. if (dwAttributes & SFGAO_LINK)
  285. SetItemState(hItem,INDEXTOOVERLAYMASK(2),TVIS_OVERLAYMASK);
  286. else
  287. SetItemState(hItem,0,TVIS_OVERLAYMASK);
  288. if (dwAttributes & SFGAO_SHARE)
  289. SetItemState(hItem,INDEXTOOVERLAYMASK(1),TVIS_OVERLAYMASK);
  290. else
  291. SetItemState(hItem,0,TVIS_OVERLAYMASK);
  292. }
  293. BEGIN_MESSAGE_MAP(CIEFolderTreeCtrl, CUITreeCtrl)
  294. //{{AFX_MSG_MAP(CIEFolderTreeCtrl)
  295. ON_WM_CREATE()
  296. ON_WM_DESTROY()
  297. ON_MESSAGE(WM_SETTINGCHANGE,OnSettingChange)
  298. //}}AFX_MSG_MAP
  299. END_MESSAGE_MAP()
  300. /////////////////////////////////////////////////////////////////////////////
  301. // CIEFolderTreeCtrl message handlers
  302. int CIEFolderTreeCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  303. {
  304. if (CUITreeCtrl::OnCreate(lpCreateStruct) == -1)
  305. return -1;
  306. // TODO: Add your specialized creation code here
  307. return 0;
  308. }
  309. BOOL CIEFolderTreeCtrl::PreCreateWindow(CREATESTRUCT& cs) 
  310. {
  311. // TODO: Add your specialized code here and/or call the base class
  312. // No label editing for Explorer items
  313. cs.style |= (TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_SHOWSELALWAYS);
  314. return CTreeCtrl::PreCreateWindow(cs);
  315. }
  316. void CIEFolderTreeCtrl::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType) 
  317. {
  318. // TODO: Add your specialized code here and/or call the base class
  319. CUITreeCtrl::CalcWindowRect(lpClientRect, nAdjustType);
  320. }
  321. LPCITEMIDLIST CIEFolderTreeCtrl::GetPathPidl(HTREEITEM hItem)
  322. {
  323. if (hItem == NULL)
  324. return NULL;
  325. LPLVITEMDATA plvit = (LPLVITEMDATA)GetItemData(hItem);
  326. ASSERT(plvit);
  327. if (plvit == NULL)
  328. return NULL;
  329. return plvit->lpifq;
  330. }
  331. LPSHELLFOLDER CIEFolderTreeCtrl::GetItemFolder(HTREEITEM hItem)
  332. {
  333.     LPTVITEMDATA lpidCurr = (LPTVITEMDATA)GetItemData(hItem);
  334. ASSERT(lpidCurr);
  335. if (lpidCurr == NULL)
  336. return NULL;
  337. LPSHELLFOLDER psfCurr=NULL;
  338. if (lpidCurr->lpsfParent)
  339. lpidCurr->lpsfParent->BindToObject(lpidCurr->lpi,0,IID_IShellFolder,(LPVOID*)&psfCurr);
  340. if (psfCurr == NULL)
  341. {
  342. SHGetDesktopFolder(&psfCurr);
  343. }
  344. return psfCurr;
  345. }
  346. CString CIEFolderTreeCtrl::GetPathName(HTREEITEM hItem)
  347. {
  348. if (hItem == NULL)
  349. hItem = GetSelectedItem();
  350.     CString sPath;
  351. if (hItem == NULL)
  352. return sPath;
  353. LPTVITEMDATA lptvid = (LPTVITEMDATA)GetItemData(hItem);
  354. if (lptvid != NULL)
  355. {
  356. SHGetPathFromIDList(lptvid->lpifq,sPath.GetBuffer(MAX_PATH));
  357. sPath.ReleaseBuffer();
  358. }
  359. return sPath;
  360. }
  361. void CIEFolderTreeCtrl::SetButtonState(HTREEITEM hItem)
  362. {
  363. LPSHELLFOLDER psfCurr=GetItemFolder(hItem);
  364. if (psfCurr == NULL)
  365. return;
  366. IEnumIDList* pItems=NULL;
  367. HRESULT hr = psfCurr->EnumObjects(NULL, SHCONTF_FOLDERS, &pItems);
  368. int nChildren=0;
  369. if (SUCCEEDED(hr))
  370. {
  371. pItems->Release();
  372. nChildren=1;
  373. }
  374. if (nChildren == 1 && !ItemHasChildren(hItem))
  375. {
  376. TVITEM tv;
  377. tv.mask = TVIF_CHILDREN;
  378. ZeroMemory(&tv,sizeof(tv));
  379. SetItem(&tv);
  380. }
  381. psfCurr->Release();
  382. }
  383. void CIEFolderTreeCtrl::RefreshNode(HTREEITEM hItem)
  384. {
  385.     // If the item is not expanded, update its button state and return.
  386.     if (!(GetItemState(hItem, TVIS_EXPANDED) & TVIS_EXPANDED)) 
  387. {
  388.         SetButtonState(hItem);
  389.         return;
  390. }
  391. LPSHELLFOLDER psfCurr=GetItemFolder(hItem);
  392. if (psfCurr == NULL)
  393. return;
  394. mapPidlToHTREEITEM mPidlCurr;
  395. vecPidl vPidlNew;
  396. HTREEITEM hSelItem = GetSelectedItem();
  397.     HTREEITEM hChild = GetChildItem(hItem);
  398.     while (hChild != NULL)
  399. {
  400.         HTREEITEM hNextItem = GetNextSiblingItem(hChild);
  401.         LPTVITEMDATA lpid = (LPTVITEMDATA)GetItemData(hChild);
  402. mPidlCurr[CShellPidlCompare(psfCurr,lpid->lpi)] = hChild;
  403.         hChild = hNextItem;
  404.     }
  405. LPITEMIDLIST pidlNext=NULL;
  406. LPITEMIDLIST pidlCopy=NULL;
  407. IEnumIDList* pItems=NULL;
  408. DWORD dwFlags = SHCONTF_FOLDERS;
  409. if (GetShellSettings().ShowAllObjects() && !GetShellSettings().ShowSysFiles())
  410. dwFlags |= SHCONTF_INCLUDEHIDDEN;
  411. HRESULT hr = psfCurr->EnumObjects(NULL, dwFlags, &pItems);
  412. while (NOERROR == hr)
  413. {
  414. hr = pItems->Next(1, &pidlNext, NULL);
  415. if (hr == S_FALSE || pidlNext == NULL)// || pidlNext == pidlCopy)
  416. break;
  417. pidlCopy = pidlNext;
  418. mapPidlToHTREEITEM::iterator it = mPidlCurr.find(CShellPidlCompare(psfCurr,pidlNext));
  419. if (it != mPidlCurr.end())
  420. {
  421. mPidlCurr.erase(it);
  422. }
  423. else
  424. {
  425. SetAttributes((*it).second,psfCurr,pidlNext);
  426. vPidlNew.push_back(GetShellPidl().CopyItemIDList(pidlNext));
  427. }
  428. GetShellPidl().FreePidl(pidlNext);
  429. pidlNext=NULL;
  430. }
  431. if (pItems)
  432. pItems->Release();
  433. for(mapPidlToHTREEITEM::iterator it1=mPidlCurr.begin();it1 != mPidlCurr.end();it1++)
  434. {
  435. HTREEITEM hDelItem = (*it1).second;
  436. #ifdef _DEBUG
  437. CString sPath;
  438. GetShellPidl().SHPidlToPathEx((*it1).first.GetPidl(),sPath,psfCurr);
  439. TRACE1("Deleting item %s in tree refreshn",sPath);
  440. #endif
  441. DeleteItem(hDelItem);
  442. }
  443. HTREEITEM hSortItem=NULL;
  444. for(vecPidl::iterator it2=vPidlNew.begin();it2 != vPidlNew.end();it2++)
  445. {
  446. AddFolder(hItem,*it2,psfCurr);
  447. hSortItem = hItem;
  448. }
  449. if (hSortItem)
  450. Sort(hSortItem,psfCurr);
  451.     // Remove all items from the map
  452.     mPidlCurr.erase(mPidlCurr.begin(),mPidlCurr.end());
  453.     vPidlNew.erase(vPidlNew.begin(),vPidlNew.end());
  454. psfCurr->Release();
  455.     // Now repeat this procedure for hItem's children.
  456.     hChild = GetChildItem(hItem);
  457.     while (hChild != NULL) 
  458. {
  459.         RefreshNode(hChild); 
  460.         hChild = GetNextSiblingItem (hChild);
  461.     }
  462. }
  463. void CIEFolderTreeCtrl::Init()
  464. {
  465. CUITreeCtrl::Init();
  466. GetShellSettings().GetSettings();
  467. // TODO: Add your specialized code here and/or call the base class
  468.     // Get the handle to the system image list, for our icons
  469.     SHFILEINFO    sfi;
  470.     m_hImageList = (HIMAGELIST)SHGetFileInfo((LPCTSTR)_T("C:\"), 
  471.                                            0,
  472.                                            &sfi, 
  473.                                            sizeof(SHFILEINFO), 
  474.                                            SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
  475.     // Attach ImageList to TreeCtrl
  476.     if (m_hImageList)
  477.         ::SendMessage(m_hWnd, TVM_SETIMAGELIST, (WPARAM) TVSIL_NORMAL,(LPARAM)m_hImageList);
  478. }
  479. void CIEFolderTreeCtrl::OnDestroy()
  480. {
  481. SetImageList(NULL,TVSIL_NORMAL);
  482. CUITreeCtrl::OnDestroy();
  483. }
  484. LRESULT CIEFolderTreeCtrl::OnSettingChange(WPARAM wParam,LPARAM lParam)
  485. LPCTSTR lpszSection=(LPCTSTR)lParam;
  486. if (lpszSection == NULL)
  487. return 0L;
  488. if (lstrcmpi(lpszSection, _T("ShellState")) == 0) 
  489. {  
  490. GetShellSettings().GetSettings();
  491. Refresh();
  492.     }
  493. return 1L; 
  494. }