Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

380 lines
8.7 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 1999
  6. //
  7. // File: trobimpl.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // trobimpl.cpp : implementation file
  11. //
  12. #include "stdafx.h"
  13. #include "amc.h"
  14. #include "trobimpl.h"
  15. /////////////////////////////////////////////////////////////////////////////
  16. // CTreeObserverTreeImpl
  17. CTreeObserverTreeImpl::CTreeObserverTreeImpl() :
  18. m_pTreeSrc(NULL), m_dwStyle(0), m_tidRoot(NULL)
  19. {
  20. }
  21. CTreeObserverTreeImpl::~CTreeObserverTreeImpl()
  22. {
  23. }
  24. HRESULT CTreeObserverTreeImpl::SetStyle(DWORD dwStyle)
  25. {
  26. ASSERT((dwStyle & ~(TOBSRV_HIDEROOT | TOBSRV_FOLDERSONLY)) == 0);
  27. m_dwStyle = dwStyle;
  28. return S_OK;
  29. }
  30. HRESULT CTreeObserverTreeImpl::SetTreeSource(CTreeSource* pTreeSrc)
  31. {
  32. // Window may be gone before source is disconnected
  33. if (IsWindow(m_hWnd))
  34. DeleteAllItems();
  35. m_pTreeSrc = pTreeSrc;
  36. if (pTreeSrc == NULL)
  37. return S_OK;
  38. // Must have window before populating tree
  39. ASSERT(IsWindow(m_hWnd));
  40. // populate top level of tree
  41. TREEITEMID tidRoot = m_pTreeSrc->GetRootItem();
  42. if (tidRoot != NULL)
  43. {
  44. // Trigger handler as though item were just added
  45. ItemAdded(tidRoot);
  46. }
  47. return S_OK;
  48. }
  49. TREEITEMID CTreeObserverTreeImpl::GetSelection()
  50. {
  51. HTREEITEM hti = GetSelectedItem();
  52. if (hti)
  53. return static_cast<TREEITEMID>(GetItemData(hti));
  54. else
  55. return NULL;
  56. }
  57. void CTreeObserverTreeImpl::SetSelection(TREEITEMID tid)
  58. {
  59. ASSERT(m_pTreeSrc != NULL);
  60. HTREEITEM hti = FindHTI(tid, TRUE);
  61. ASSERT(hti != NULL);
  62. SelectItem(hti);
  63. EnsureVisible(hti);
  64. }
  65. void CTreeObserverTreeImpl::ExpandItem(TREEITEMID tid)
  66. {
  67. ASSERT(m_pTreeSrc != NULL);
  68. HTREEITEM hti = FindHTI(tid, TRUE);
  69. if (hti != NULL)
  70. Expand(hti, TVE_EXPAND);
  71. }
  72. BOOL CTreeObserverTreeImpl::IsItemExpanded(TREEITEMID tid)
  73. {
  74. ASSERT(m_pTreeSrc != NULL);
  75. HTREEITEM hti = FindHTI(tid, TRUE);
  76. return (IsItemExpanded(hti));
  77. }
  78. HTREEITEM CTreeObserverTreeImpl::FindChildHTI(HTREEITEM htiParent, TREEITEMID tid)
  79. {
  80. HTREEITEM htiTemp;
  81. if (htiParent == TVI_ROOT)
  82. htiTemp = GetRootItem();
  83. else
  84. htiTemp = GetChildItem(htiParent);
  85. while (htiTemp && GetItemData(htiTemp) != tid)
  86. {
  87. htiTemp = GetNextSiblingItem(htiTemp);
  88. }
  89. return htiTemp;
  90. }
  91. HTREEITEM CTreeObserverTreeImpl::FindHTI(TREEITEMID tid, BOOL bAutoExpand)
  92. {
  93. ASSERT(m_pTreeSrc != NULL);
  94. if (tid == NULL || (tid == m_tidRoot && RootHidden()))
  95. return TVI_ROOT;
  96. HTREEITEM htiParent = FindHTI(m_pTreeSrc->GetParentItem(tid), bAutoExpand);
  97. if (htiParent == NULL)
  98. return NULL;
  99. if (bAutoExpand && !WasItemExpanded(htiParent))
  100. Expand(htiParent, TVE_EXPAND);
  101. return FindChildHTI(htiParent, tid);
  102. }
  103. HTREEITEM CTreeObserverTreeImpl::AddOneItem(HTREEITEM htiParent, HTREEITEM htiAfter, TREEITEMID tid)
  104. {
  105. ASSERT(m_pTreeSrc != NULL);
  106. TVINSERTSTRUCT insert;
  107. insert.hParent = htiParent;
  108. insert.hInsertAfter = htiAfter;
  109. insert.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  110. insert.item.lParam = tid;
  111. insert.item.iImage = m_pTreeSrc->GetItemImage(tid);
  112. insert.item.iSelectedImage = insert.item.iImage;
  113. insert.item.cChildren = m_pTreeSrc->GetChildItem(tid) ? 1 : 0;
  114. TCHAR name[MAX_PATH];
  115. m_pTreeSrc->GetItemName(tid, name, MAX_PATH);
  116. insert.item.pszText = name;
  117. return InsertItem(&insert);
  118. }
  119. void CTreeObserverTreeImpl::AddChildren(HTREEITEM hti)
  120. {
  121. ASSERT(m_pTreeSrc != NULL);
  122. TREEITEMID tidChild;
  123. // if adding top level item
  124. if (hti == TVI_ROOT)
  125. {
  126. if (RootHidden())
  127. {
  128. // if root is hidden, add its children
  129. ASSERT(m_tidRoot != 0);
  130. tidChild = m_pTreeSrc->GetChildItem(m_tidRoot);
  131. }
  132. else
  133. {
  134. // else add root item itself
  135. tidChild = m_pTreeSrc->GetRootItem();
  136. }
  137. }
  138. else
  139. {
  140. // convert to TID, then get its child
  141. TREEITEMID tid = static_cast<TREEITEMID>(GetItemData(hti));
  142. ASSERT(tid != 0);
  143. tidChild = m_pTreeSrc->GetChildItem(tid);
  144. }
  145. while (tidChild)
  146. {
  147. // Add visible items
  148. if (!ShowFoldersOnly() || m_pTreeSrc->IsFolderItem(tidChild))
  149. AddOneItem(hti, TVI_LAST, tidChild);
  150. tidChild = m_pTreeSrc->GetNextSiblingItem(tidChild);
  151. }
  152. }
  153. void CTreeObserverTreeImpl::ItemAdded(TREEITEMID tid)
  154. {
  155. ASSERT(m_pTreeSrc != NULL);
  156. ASSERT(tid != 0);
  157. // if only folders visible, skip this item
  158. if (ShowFoldersOnly() && !m_pTreeSrc->IsFolderItem(tid))
  159. return;
  160. // Get parent tree item
  161. TREEITEMID tidParent = m_pTreeSrc->GetParentItem(tid);
  162. // if this is the tree root and the root is not displayed
  163. if (tidParent == NULL && RootHidden())
  164. {
  165. // Can only have one hidden root
  166. ASSERT(m_tidRoot == NULL);
  167. // Just save TID as the hidden root and return
  168. m_tidRoot = tid;
  169. // since root is hidden, add its children to the tree
  170. AddChildren(TVI_ROOT);
  171. return;
  172. }
  173. // Add new item to tree
  174. HTREEITEM htiParent = FindHTI(tidParent);
  175. // Parent exists and has been expanded
  176. if (WasItemExpanded(htiParent))
  177. {
  178. // Determine previous tree item
  179. // Because the source doesn't support GetPrevSibling
  180. // we have to get the next TID then use our own tree to
  181. // back up to the previous item
  182. //
  183. HTREEITEM htiPrev;
  184. TREEITEMID tidNext = m_pTreeSrc->GetNextSiblingItem(tid);
  185. if (tidNext)
  186. {
  187. HTREEITEM htiNext = FindChildHTI(htiParent, tidNext);
  188. ASSERT(htiNext);
  189. htiPrev = GetPrevSiblingItem(htiNext);
  190. if (htiPrev == NULL)
  191. htiPrev = TVI_FIRST;
  192. }
  193. else
  194. {
  195. htiPrev = TVI_LAST;
  196. }
  197. // Insert the new tree item
  198. AddOneItem(htiParent, htiPrev, tid);
  199. }
  200. else if (htiParent)
  201. {
  202. // Set child count so parent can expand
  203. TV_ITEM item;
  204. item.mask = TVIF_CHILDREN;
  205. item.hItem = htiParent;
  206. item.cChildren = 1;
  207. SetItem(&item);
  208. }
  209. }
  210. void CTreeObserverTreeImpl::ItemRemoved(TREEITEMID tidParent, TREEITEMID tid)
  211. {
  212. ASSERT(m_pTreeSrc != NULL);
  213. ASSERT(tid != 0);
  214. // if deleting hidden root, clear tree and return
  215. if (tid == m_tidRoot)
  216. {
  217. DeleteAllItems();
  218. m_tidRoot = NULL;
  219. return;
  220. }
  221. // Get parent tree item
  222. HTREEITEM htiParent = FindHTI(tidParent);
  223. if (WasItemExpanded(htiParent))
  224. {
  225. // Find removed item
  226. HTREEITEM hti = FindChildHTI(htiParent, tid);
  227. // Remove the item
  228. DeleteItem(hti);
  229. }
  230. }
  231. void CTreeObserverTreeImpl::ItemChanged(TREEITEMID tid, DWORD dwAttrib)
  232. {
  233. ASSERT(m_pTreeSrc != NULL);
  234. ASSERT(tid != 0);
  235. if (dwAttrib & TIA_NAME)
  236. {
  237. // Get changed tree item
  238. HTREEITEM hti = FindHTI(tid);
  239. // Force item update
  240. if (hti != 0)
  241. {
  242. TCHAR name[MAX_PATH];
  243. m_pTreeSrc->GetItemName(tid, name, MAX_PATH);
  244. TVITEM item;
  245. item.hItem = hti;
  246. item.mask = TVIF_TEXT;
  247. item.pszText = name;
  248. SetItem(&item);
  249. }
  250. }
  251. }
  252. void CTreeObserverTreeImpl::OnItemExpanding(NMHDR* pNMHDR, LRESULT* pResult)
  253. {
  254. NM_TREEVIEW* pNotify = (NM_TREEVIEW*)pNMHDR;
  255. ASSERT(pNotify != NULL);
  256. HTREEITEM hti = pNotify->itemNew.hItem;
  257. ASSERT(hti != NULL);
  258. // Enumerate the folders below this item
  259. if (pNotify->action == TVE_EXPAND)
  260. {
  261. // Only add children on first expansion
  262. if (!(pNotify->itemNew.state & TVIS_EXPANDEDONCE))
  263. AddChildren(hti);
  264. }
  265. // Flip state of icon open/closed
  266. ASSERT(m_pTreeSrc != NULL);
  267. TREEITEMID tid = pNotify->itemNew.lParam;
  268. ASSERT(m_pTreeSrc->IsFolderItem(tid));
  269. int iImage = (pNotify->action == TVE_EXPAND) ?
  270. m_pTreeSrc->GetItemOpenImage(tid) : m_pTreeSrc->GetItemImage(tid);
  271. TVITEM item;
  272. item.hItem = hti;
  273. item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  274. item.iImage = item.iSelectedImage = iImage;
  275. SetItem(&item);
  276. *pResult = 0;
  277. }
  278. void CTreeObserverTreeImpl::OnSingleExpand(NMHDR* pNMHDR, LRESULT* pResult)
  279. {
  280. *pResult = TVNRET_DEFAULT;
  281. }
  282. BEGIN_MESSAGE_MAP(CTreeObserverTreeImpl, CTreeCtrl)
  283. ON_NOTIFY_REFLECT(TVN_SINGLEEXPAND, OnSingleExpand)
  284. ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemExpanding)
  285. END_MESSAGE_MAP()
  286. /////////////////////////////////////////////////////////////////////////////
  287. // CFavoritesView message handlers