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.

2177 lines
61 KiB

  1. // TreeCtrl.cpp : implementation file
  2. //
  3. //+-------------------------------------------------------------------------
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1999
  7. //
  8. // File: amctreectrl.cpp
  9. //
  10. // Contents: AMC Tree control implementation
  11. //
  12. // History: 16-Jul-96 WayneSc Created
  13. //
  14. //
  15. //--------------------------------------------------------------------------
  16. #include "stdafx.h"
  17. #include "AMCDoc.h" // AMC Console Document
  18. #include "amcview.h"
  19. #include "childfrm.h"
  20. #include "macros.h"
  21. #include "AMCPriv.h"
  22. #include "AMC.h"
  23. #include "mainfrm.h"
  24. #include "TreeCtrl.h"
  25. #include "resource.h"
  26. #include "guidhelp.h" // LoadRootDisplayName
  27. #include "histlist.h"
  28. #include "websnk.h"
  29. #include "webctrl.h"
  30. #include "..\inc\mmcutil.h"
  31. #include "amcmsgid.h"
  32. #include "resultview.h"
  33. #include "eventlock.h"
  34. extern "C" UINT dbg_count;
  35. //############################################################################
  36. //############################################################################
  37. //
  38. // Traces
  39. //
  40. //############################################################################
  41. //############################################################################
  42. #ifdef DBG
  43. CTraceTag tagTree(TEXT("Tree View"), TEXT("Tree View"));
  44. #endif //DBG
  45. //############################################################################
  46. //############################################################################
  47. //
  48. // Implementation of class CTreeViewMap
  49. //
  50. //############################################################################
  51. //############################################################################
  52. /*+-------------------------------------------------------------------------*
  53. *
  54. * CTreeViewMap::ScOnItemAdded
  55. *
  56. * PURPOSE: Called when an item is added. Indexes the item.
  57. *
  58. * PARAMETERS:
  59. * TVINSERTSTRUCT * pTVInsertStruct :
  60. * HTREEITEM hti :
  61. * HMTNODE hMTNode :
  62. *
  63. * RETURNS:
  64. * SC
  65. *
  66. *+-------------------------------------------------------------------------*/
  67. SC
  68. CTreeViewMap::ScOnItemAdded (TVINSERTSTRUCT *pTVInsertStruct, HTREEITEM hti, HMTNODE hMTNode)
  69. {
  70. DECLARE_SC(sc, TEXT("CTreeViewMap::ScOnItemAdded"));
  71. // validate parameters
  72. sc = ScCheckPointers(pTVInsertStruct);
  73. if(sc)
  74. return sc;
  75. if(!hti || !hMTNode)
  76. return (sc = E_INVALIDARG);
  77. // create a new map info structure.
  78. TreeViewMapInfo *pMapInfo = new TreeViewMapInfo;
  79. if(!pMapInfo)
  80. return (sc = E_OUTOFMEMORY);
  81. // fill in the values
  82. pMapInfo->hNode = CAMCTreeView::NodeFromLParam (pTVInsertStruct->item.lParam);
  83. pMapInfo->hti = hti;
  84. pMapInfo->hMTNode = hMTNode;
  85. // set up the indexes
  86. ASSERT(m_hMTNodeMap.find(pMapInfo->hMTNode) == m_hMTNodeMap.end());
  87. ASSERT(m_hNodeMap.find(pMapInfo->hNode) == m_hNodeMap.end());
  88. m_hMTNodeMap [pMapInfo->hMTNode] = pMapInfo;
  89. m_hNodeMap [pMapInfo->hNode] = pMapInfo;
  90. return sc;
  91. }
  92. /*+-------------------------------------------------------------------------*
  93. *
  94. * CTreeViewMap::ScOnItemDeleted
  95. *
  96. * PURPOSE: Called when a tree item is deleted. Removes the item from the
  97. * indexes.
  98. *
  99. * PARAMETERS:
  100. * HNODE hNode :
  101. * HTREEITEM hti :
  102. *
  103. * RETURNS:
  104. * SC
  105. *
  106. *+-------------------------------------------------------------------------*/
  107. SC
  108. CTreeViewMap::ScOnItemDeleted (HNODE hNode, HTREEITEM hti)
  109. {
  110. DECLARE_SC(sc, TEXT("CTreeViewMap::ScOnItemDeleted"));
  111. // validate parameters
  112. sc = ScCheckPointers((LPVOID) hNode, (LPVOID) hti);
  113. if(sc)
  114. return sc;
  115. // remove the TreeViewMapInfo pointer from all the maps
  116. HNodeLookupMap::iterator iter = m_hNodeMap.find(hNode);
  117. if(iter == m_hNodeMap.end())
  118. return (sc = E_UNEXPECTED);
  119. TreeViewMapInfo *pMapInfo = iter->second; // find the map info structure.
  120. if(!pMapInfo)
  121. return (sc = E_UNEXPECTED);
  122. HMTNODE hMTNode = pMapInfo->hMTNode;
  123. #ifdef DBG
  124. // verify that the same structure is pointed to by the other maps.
  125. ASSERT(m_hMTNodeMap.find(hMTNode)->second == pMapInfo);
  126. #endif
  127. m_hMTNodeMap.erase(hMTNode);
  128. m_hNodeMap.erase(hNode);
  129. // finally delete the TreeViewMapInfo structure
  130. delete pMapInfo;
  131. return sc;
  132. }
  133. // Fast lookup methods
  134. /*+-------------------------------------------------------------------------*
  135. *
  136. * CTreeViewMap::ScGetHNodeFromHMTNode
  137. *
  138. * PURPOSE: Quickly (log n time) retrieves the HNODE for an HMTNODE.
  139. *
  140. * PARAMETERS:
  141. * HMTNODE hMTNode :
  142. * ou t :
  143. *
  144. * RETURNS:
  145. * SC
  146. *
  147. *+-------------------------------------------------------------------------*/
  148. SC
  149. CTreeViewMap::ScGetHNodeFromHMTNode (HMTNODE hMTNode, /*out*/ HNODE* phNode) // fast conversion from hNode to hMTNode.
  150. {
  151. DECLARE_SC(sc, TEXT("CTreeViewMap::ScGetHNode"));
  152. // validate parameters
  153. sc = ScCheckPointers((LPVOID) hMTNode, phNode);
  154. if(sc)
  155. return sc;
  156. // find the mapinfo structure.
  157. HMTNodeLookupMap::iterator iter = m_hMTNodeMap.find(hMTNode);
  158. if(iter == m_hMTNodeMap.end())
  159. return (sc = ScFromMMC(IDS_NODE_NOT_FOUND));
  160. TreeViewMapInfo *pMapInfo = iter->second; // find the map info structure.
  161. if(!pMapInfo)
  162. return (sc = E_UNEXPECTED);
  163. *phNode = pMapInfo->hNode;
  164. return sc;
  165. }
  166. /*+-------------------------------------------------------------------------*
  167. *
  168. * CTreeViewMap::ScGetHTreeItemFromHNode
  169. *
  170. * PURPOSE: Quickly (log n time) retrieves the HTREEITEM for an HNODE.
  171. *
  172. * PARAMETERS:
  173. * HNODE hNode :
  174. * ou t :
  175. *
  176. * RETURNS:
  177. * SC
  178. *
  179. *+-------------------------------------------------------------------------*/
  180. SC
  181. CTreeViewMap::ScGetHTreeItemFromHNode(HNODE hNode, /*out*/ HTREEITEM* phti) // fast conversion from HTREEITEM to HNODE
  182. {
  183. DECLARE_SC(sc, TEXT("CTreeViewMap::ScGetHTreeItem"));
  184. // validate parameters
  185. sc = ScCheckPointers((LPVOID) hNode, phti);
  186. if(sc)
  187. return sc;
  188. // find the mapinfo structure.
  189. HNodeLookupMap::iterator iter = m_hNodeMap.find(hNode);
  190. if(iter == m_hNodeMap.end())
  191. return (sc = E_UNEXPECTED);
  192. TreeViewMapInfo *pMapInfo = iter->second; // find the map info structure.
  193. if(!pMapInfo)
  194. return (sc = E_UNEXPECTED);
  195. *phti = pMapInfo->hti;
  196. return sc;
  197. }
  198. /*+-------------------------------------------------------------------------*
  199. *
  200. * CTreeViewMap::ScGetHTreeItemFromHMTNode
  201. *
  202. * PURPOSE: Quickly (log n time) retrieves the HTREEITEM for an HMTNODE.
  203. *
  204. * PARAMETERS:
  205. * HMTNODE hMTNode :
  206. * ou t :
  207. *
  208. * RETURNS:
  209. * SC
  210. *
  211. *+-------------------------------------------------------------------------*/
  212. SC
  213. CTreeViewMap::ScGetHTreeItemFromHMTNode(HMTNODE hMTNode, /*out*/ HTREEITEM* phti) // fast conversion from HMTNode to HTREEITEM.
  214. {
  215. DECLARE_SC(sc, TEXT("CTreeViewMap::ScGetHTreeItem"));
  216. // validate parameters
  217. //sc = ScCheckPointers(hMTNode, phti);
  218. if(sc)
  219. return sc;
  220. // find the mapinfo structure.
  221. HMTNodeLookupMap::iterator iter = m_hMTNodeMap.find(hMTNode);
  222. if(iter == m_hMTNodeMap.end())
  223. return (sc = E_UNEXPECTED);
  224. TreeViewMapInfo *pMapInfo = iter->second; // find the map info structure.
  225. if(!pMapInfo)
  226. return (sc = E_UNEXPECTED);
  227. *phti = pMapInfo->hti;
  228. return sc;
  229. }
  230. //############################################################################
  231. //############################################################################
  232. //
  233. // Implementation of class CAMCTreeView
  234. //
  235. //############################################################################
  236. //############################################################################
  237. /////////////////////////////////////////////////////////////////////////////
  238. // CAMCTreeView
  239. DEBUG_DECLARE_INSTANCE_COUNTER(CAMCTreeView);
  240. CAMCTreeView::CAMCTreeView()
  241. : m_FontLinker (this)
  242. {
  243. DEBUG_INCREMENT_INSTANCE_COUNTER(CAMCTreeView);
  244. m_fInCleanUp = FALSE;
  245. m_fInExpanding = FALSE;
  246. m_pAMCView = NULL;
  247. SetHasList(TRUE);
  248. SetTempSelectedItem (NULL);
  249. ASSERT (!IsTempSelectionActive());
  250. AddObserver(static_cast<CTreeViewObserver&>(m_treeMap)); // add an observer to this control.
  251. }
  252. CAMCTreeView::~CAMCTreeView()
  253. {
  254. DEBUG_DECREMENT_INSTANCE_COUNTER(CAMCTreeView);
  255. // Smart pointer are released during their destructor
  256. }
  257. IMPLEMENT_DYNCREATE(CAMCTreeView, CTreeView)
  258. BEGIN_MESSAGE_MAP(CAMCTreeView, CTreeView)
  259. //{{AFX_MSG_MAP(CAMCTreeView)
  260. ON_WM_CREATE()
  261. ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelChanged)
  262. ON_NOTIFY_REFLECT(TVN_SELCHANGING, OnSelChanging)
  263. ON_NOTIFY_REFLECT(TVN_GETDISPINFO, OnGetDispInfo)
  264. ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemExpanding)
  265. ON_NOTIFY_REFLECT(TVN_ITEMEXPANDED, OnItemExpanded)
  266. ON_WM_DESTROY()
  267. ON_WM_KEYDOWN()
  268. ON_WM_SYSKEYDOWN()
  269. ON_WM_SYSCHAR()
  270. ON_WM_MOUSEACTIVATE()
  271. ON_WM_SETFOCUS()
  272. ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBeginDrag)
  273. ON_NOTIFY_REFLECT(TVN_BEGINRDRAG, OnBeginRDrag)
  274. ON_WM_KILLFOCUS()
  275. //}}AFX_MSG_MAP
  276. ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
  277. END_MESSAGE_MAP()
  278. /*+-------------------------------------------------------------------------*
  279. * CAMCTreeView::ScSetTempSelection
  280. *
  281. * Applies temporary selection to the specified HTREEITEM.
  282. *--------------------------------------------------------------------------*/
  283. SC CAMCTreeView::ScSetTempSelection (HTREEITEM htiTempSelect)
  284. {
  285. AFX_MANAGE_STATE (AfxGetAppModuleState());
  286. DECLARE_SC (sc, _T("CAMCTreeView::ScSetTempSelection"));
  287. /*
  288. * Don't use ScSetTempSelection(NULL) to remove temporary selection;
  289. * use ScRemoveTempSelection instead.
  290. */
  291. ASSERT (htiTempSelect != NULL);
  292. if (htiTempSelect == NULL)
  293. return (sc = E_FAIL);
  294. /*
  295. * If this fails, you must first call ScRemoveTempSelection to remove
  296. * the temporary selection state (TVIS_SELECTED) from the current
  297. * temporary selection.
  298. */
  299. ASSERT (!IsTempSelectionActive());
  300. SetTempSelectedItem (htiTempSelect);
  301. ASSERT (GetTempSelectedItem() == htiTempSelect);
  302. HTREEITEM htiSelected = GetSelectedItem();
  303. if (htiSelected != htiTempSelect)
  304. {
  305. SetItemState (htiSelected, 0, TVIS_SELECTED);
  306. SetItemState (htiTempSelect, TVIS_SELECTED, TVIS_SELECTED);
  307. }
  308. ASSERT (IsTempSelectionActive());
  309. return (sc);
  310. }
  311. /*+-------------------------------------------------------------------------*
  312. * CAMCTreeView::ScRemoveTempSelection
  313. *
  314. * Removes the temporary selection from the current temporarily selected
  315. * item, if there is one, and restores it to the item that was selected
  316. * when the temp selection was applied.
  317. *--------------------------------------------------------------------------*/
  318. SC CAMCTreeView::ScRemoveTempSelection ()
  319. {
  320. AFX_MANAGE_STATE (AfxGetAppModuleState());
  321. DECLARE_SC (sc, _T("CAMCTreeView::ScRemoveTempSelection"));
  322. if (!IsTempSelectionActive())
  323. return (sc = S_FALSE);
  324. HTREEITEM htiTempSelect = GetTempSelectedItem();
  325. HTREEITEM htiSelected = GetSelectedItem();
  326. if (htiTempSelect != htiSelected)
  327. {
  328. SetItemState (htiTempSelect, 0, TVIS_SELECTED);
  329. SetItemState (htiSelected, TVIS_SELECTED, TVIS_SELECTED);
  330. }
  331. SetTempSelectedItem (NULL);
  332. ASSERT (!IsTempSelectionActive());
  333. return (sc);
  334. }
  335. /*+-------------------------------------------------------------------------*
  336. * CAMCTreeView::ScReselect
  337. *
  338. *
  339. *--------------------------------------------------------------------------*/
  340. SC CAMCTreeView::ScReselect ()
  341. {
  342. AFX_MANAGE_STATE (AfxGetAppModuleState());
  343. NM_TREEVIEW nmtv;
  344. nmtv.itemOld.hItem = nmtv.itemNew.hItem = GetSelectedItem();
  345. if (nmtv.itemOld.hItem)
  346. {
  347. nmtv.itemOld.lParam = nmtv.itemNew.lParam = GetItemData(nmtv.itemOld.hItem);
  348. LRESULT lUnused;
  349. OnSelChangingWorker (&nmtv, &lUnused);
  350. OnSelChangedWorker (&nmtv, &lUnused);
  351. }
  352. return (S_OK);
  353. }
  354. /////////////////////////////////////////////////////////////////////////////
  355. // CAMCTreeView message handlers
  356. BOOL CAMCTreeView::PreCreateWindow(CREATESTRUCT& cs)
  357. {
  358. cs.style |= TVS_EDITLABELS | TVS_HASBUTTONS | TVS_HASLINES | TVS_SHOWSELALWAYS;
  359. cs.dwExStyle |= WS_EX_CLIENTEDGE;
  360. // do not paint over the children
  361. cs.style |= WS_CLIPCHILDREN;
  362. return CTreeView::PreCreateWindow(cs);
  363. }
  364. INodeCallback* CAMCTreeView::GetNodeCallback()
  365. {
  366. return m_pAMCView->GetNodeCallback();
  367. }
  368. inline IScopeTreeIter* CAMCTreeView::GetScopeIterator()
  369. {
  370. return m_pAMCView->GetScopeIterator();
  371. }
  372. inline IScopeTree* CAMCTreeView::GetScopeTree()
  373. {
  374. return m_pAMCView->GetScopeTree();
  375. }
  376. void CAMCTreeView::OnGetDispInfo(NMHDR* pNMHDR, LRESULT* pResult)
  377. {
  378. HRESULT hr;
  379. TV_DISPINFO* ptvdi = (TV_DISPINFO*)pNMHDR;
  380. HNODE hNode = NodeFromLParam (ptvdi->item.lParam);
  381. ASSERT(m_pAMCView != NULL);
  382. INodeCallback* spCallback = GetNodeCallback();
  383. ASSERT(spCallback != NULL);
  384. if (hNode)
  385. {
  386. if (ptvdi->item.mask & TVIF_TEXT)
  387. {
  388. tstring strName;
  389. hr = spCallback->GetDisplayName(hNode, strName);
  390. if (hr != S_OK)
  391. {
  392. ptvdi->item.pszText[0] = _T('\0');
  393. ASSERT(FALSE);
  394. }
  395. else
  396. {
  397. // copy the text, but not too much
  398. ASSERT (!IsBadWritePtr (ptvdi->item.pszText, ptvdi->item.cchTextMax));
  399. _tcsncpy (ptvdi->item.pszText, strName.data(), ptvdi->item.cchTextMax);
  400. /*
  401. * _tcsncpy won't terminate the destination if the
  402. * source is bigger than the buffer; make sure the
  403. * string is NULL-terminated
  404. */
  405. ptvdi->item.pszText[ptvdi->item.cchTextMax-1] = _T('\0');
  406. /*
  407. * If this is the selected item and it's text has changed,
  408. * fire an event so observers can know.
  409. */
  410. if ((m_strSelectedItemText != strName.data()) &&
  411. (GetSelectedItem() == ptvdi->item.hItem))
  412. {
  413. m_strSelectedItemText = strName.data();
  414. SC sc = ScFireEvent (CTreeViewObserver::ScOnSelectedItemTextChanged,
  415. (LPCTSTR) m_strSelectedItemText);
  416. if (sc)
  417. sc.TraceAndClear();
  418. }
  419. }
  420. }
  421. int nImage, nSelectedImage;
  422. hr = spCallback->GetImages(hNode, &nImage, &nSelectedImage);
  423. #ifdef DBG
  424. if (hr != S_OK)
  425. {
  426. ASSERT(nImage == 0 && nSelectedImage == 0);
  427. }
  428. #endif
  429. if (ptvdi->item.mask & TVIF_IMAGE)
  430. ptvdi->item.iImage = nImage;
  431. if (ptvdi->item.mask & TVIF_SELECTEDIMAGE)
  432. ptvdi->item.iSelectedImage = nSelectedImage;
  433. // We will get this request once, the first time the scope item comes into view
  434. if (ptvdi->item.mask & TVIF_CHILDREN)
  435. {
  436. ptvdi->item.cChildren = (spCallback->IsExpandable(hNode) != S_FALSE);
  437. // set children to fixed value, to avoid any more callbacks
  438. SetCountOfChildren(ptvdi->item.hItem, ptvdi->item.cChildren);
  439. }
  440. }
  441. else
  442. {
  443. ASSERT(0 && "OnGetDispInfo(HNODE is NULL)");
  444. }
  445. *pResult = 0;
  446. }
  447. //
  448. // Description: This method will set the folders Button(+/-) on or
  449. // of depending on the value of bState
  450. //
  451. // Parameters:
  452. // hItem: the tree item affected
  453. // bState: TRUE = Enable for folder to show it has children
  454. // FALSE = Disable for folder to show it has NO children
  455. //
  456. void CAMCTreeView::SetButton(HTREEITEM hItem, BOOL bState)
  457. {
  458. ASSERT(hItem != NULL);
  459. TV_ITEM item;
  460. ZeroMemory(&item, sizeof(item));
  461. item.hItem = hItem;
  462. item.mask = TVIF_HANDLE | TVIF_CHILDREN;
  463. item.cChildren = bState;
  464. SetItem(&item);
  465. }
  466. //
  467. // Description: This method will populate hItem's(parent folder) children into
  468. // the tree control.
  469. //
  470. // Parameters:
  471. // hItem: the parent
  472. //
  473. BOOL CAMCTreeView::ExpandNode(HTREEITEM hItem)
  474. {
  475. TRACE_METHOD(CAMCTreeView, ExpandNode);
  476. // not frequently, but... snap-in will display the dialog, dismissing that will
  477. // activate the frame again. Tree item will be automatically selected if there
  478. // is none selected yet. Following will prevent the recursion.
  479. if (m_fInExpanding)
  480. return FALSE;
  481. HRESULT hr;
  482. // Get the HNODE from the tree node
  483. HNODE hNode = GetItemNode(hItem);
  484. ASSERT(hNode != NULL);
  485. ASSERT(m_pAMCView != NULL);
  486. HMTNODE hMTNode;
  487. INodeCallback* spCallback = GetNodeCallback();
  488. ASSERT(spCallback != NULL);
  489. hr = spCallback->GetMTNode(hNode, &hMTNode);
  490. ASSERT(hr == S_OK);
  491. if (hr == S_OK)
  492. {
  493. // The notify will return S_FALSE to indicate already expanded
  494. // or E_xxxx to indicate an error.
  495. hr = spCallback->Notify(hNode, NCLBK_EXPAND, FALSE, 0);
  496. if (hr == S_FALSE)
  497. {
  498. __try
  499. {
  500. m_fInExpanding = TRUE;
  501. hr = spCallback->Notify(hNode, NCLBK_EXPAND, TRUE, 0);
  502. }
  503. __finally
  504. {
  505. m_fInExpanding = FALSE;
  506. }
  507. if (SUCCEEDED(hr))
  508. {
  509. IScopeTreeIter* spIterator = m_pAMCView->GetScopeIterator();
  510. hr = spIterator->SetCurrent(hMTNode);
  511. HMTNODE hMTChildNode;
  512. // Get the child for the current iterator node and add
  513. // them to this tree
  514. if (spIterator->Child(&hMTChildNode) == S_OK)
  515. {
  516. IScopeTree* spScopeTree = m_pAMCView->GetScopeTree();
  517. HNODE hNewNode;
  518. unsigned int nFetched = 0;
  519. if (spIterator->SetCurrent(hMTChildNode) == S_OK)
  520. {
  521. HMTNODE hCurrentChildNode = hMTChildNode;
  522. do
  523. {
  524. // Get the children and convert them to HNODEs
  525. // and add them to the tree
  526. hr = spIterator->Next(1, &hCurrentChildNode,
  527. &nFetched);
  528. if (hr != S_OK || nFetched <= 0)
  529. break;
  530. // Insert node into the tree control
  531. spScopeTree->CreateNode(hCurrentChildNode,
  532. reinterpret_cast<LONG_PTR>(m_pAMCView->GetViewData()),
  533. FALSE, &hNewNode);
  534. #include "pushwarn.h"
  535. #pragma warning(disable: 4552) // "!=" operator has no effect
  536. VERIFY(InsertNode(hItem, hNewNode) != NULL);
  537. #include "popwarn.h"
  538. // give 'em a chance to do the "preload" thing, if applicable
  539. spCallback->PreLoad (hNewNode);
  540. } while (1);
  541. }
  542. }
  543. spCallback->Notify(hNode, NCLBK_EXPANDED, 0, 0);
  544. }
  545. }
  546. }
  547. return SUCCEEDED(hr);
  548. }
  549. HTREEITEM CAMCTreeView::InsertNode(HTREEITEM hParent, HNODE hNode,
  550. HTREEITEM hInsertAfter)
  551. {
  552. DECLARE_SC(sc, TEXT("CAMCTreeView::InsertNode"));
  553. ASSERT(hParent != NULL);
  554. ASSERT(hNode != NULL);
  555. HRESULT hr;
  556. TV_INSERTSTRUCT tvInsertStruct;
  557. TV_ITEM& item = tvInsertStruct.item;
  558. ZeroMemory(&tvInsertStruct, sizeof(tvInsertStruct));
  559. // Insert item at the end of the hItem chain
  560. tvInsertStruct.hParent = hParent;
  561. tvInsertStruct.hInsertAfter = hInsertAfter;
  562. item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN |
  563. TVIF_PARAM | TVIF_TEXT;
  564. item.pszText = LPSTR_TEXTCALLBACK;
  565. item.lParam = LParamFromNode (hNode);
  566. INodeCallback* spCallback = GetNodeCallback();
  567. ASSERT(spCallback != NULL);
  568. // Set callback mode for children, so we don't have to determine this
  569. // until the scope item becomes visible (it can be expensive).
  570. item.cChildren = I_CHILDRENCALLBACK;
  571. spCallback->GetImages(hNode, &item.iImage, &item.iSelectedImage);
  572. HTREEITEM hti = InsertItem(&tvInsertStruct);
  573. HMTNODE hMTNode = NULL;
  574. sc = spCallback->GetMTNode(hNode, &hMTNode);
  575. if(sc)
  576. sc.TraceAndClear();
  577. // send an event to all interested observers
  578. sc = ScFireEvent(CTreeViewObserver::ScOnItemAdded, &tvInsertStruct, hti, hMTNode);
  579. if(sc)
  580. sc.TraceAndClear();
  581. if (hParent != TVI_ROOT && hti != NULL)
  582. SetCountOfChildren(hParent, 1);
  583. return hti;
  584. }
  585. void CAMCTreeView::ResetNode(HTREEITEM hItem)
  586. {
  587. if (hItem == NULL)
  588. return;
  589. TV_ITEM item;
  590. ZeroMemory(&item, sizeof(item));
  591. item.hItem = hItem;
  592. item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE |
  593. TVIF_STATE | TVIF_TEXT | TVIF_CHILDREN;
  594. item.pszText = LPSTR_TEXTCALLBACK;
  595. item.iImage = I_IMAGECALLBACK;
  596. item.iSelectedImage = I_IMAGECALLBACK;
  597. item.cChildren = I_CHILDRENCALLBACK;
  598. item.lParam = GetItemData(hItem);
  599. SetItem(&item);
  600. }
  601. void CAMCTreeView::OnItemExpanding(NMHDR* pNMHDR, LRESULT* pResult)
  602. {
  603. TRACE_METHOD(CAMCTreeView, OnItemExpanding);
  604. HRESULT hr;
  605. NM_TREEVIEW* pNotify = (NM_TREEVIEW*)pNMHDR;
  606. ASSERT(pNotify != NULL);
  607. HTREEITEM &hItem = pNotify->itemNew.hItem;
  608. ASSERT(hItem != NULL);
  609. BOOL bExpand = FALSE;
  610. // Iteratate the folders below this item
  611. if (pNotify->action == TVE_EXPAND)
  612. {
  613. /*
  614. * Bug 333971: Node expansion might take awhile. Supply a wait cursor
  615. * for all of the UI-challenged snap-ins out there.
  616. */
  617. SetCursor (LoadCursor (NULL, IDC_WAIT));
  618. ExpandNode(hItem);
  619. bExpand = TRUE;
  620. /*
  621. * return the arrow
  622. */
  623. SetCursor (LoadCursor (NULL, IDC_ARROW));
  624. }
  625. INodeCallback* pCallback = GetNodeCallback();
  626. ASSERT(pCallback != NULL);
  627. HNODE hNode = GetItemNode (hItem);
  628. pCallback->Notify(hNode, NCLBK_SETEXPANDEDVISUALLY, bExpand, 0);
  629. // If item has no children remove the + sign
  630. if (GetChildItem(hItem) == NULL)
  631. SetButton(hItem, FALSE);
  632. *pResult = 0;
  633. }
  634. /*+-------------------------------------------------------------------------*
  635. * CAMCTreeView::OnItemExpanded
  636. *
  637. * TVN_ITEMEXPANDED handler for CAMCTreeView.
  638. *--------------------------------------------------------------------------*/
  639. void CAMCTreeView::OnItemExpanded(NMHDR* pNMHDR, LRESULT* pResult)
  640. {
  641. DECLARE_SC (sc, _T("CAMCTreeView::OnItemExpanded"));
  642. NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR;
  643. sc = ScCheckPointers (pnmtv);
  644. if (sc)
  645. return;
  646. /*
  647. * Bug 23153: when collapsing, totally collapse the tree beneath the
  648. * collapsing item. We do this in OnItemExpanded rather than
  649. * OnItemExpanding so we won't see the collapse happen.
  650. */
  651. if (pnmtv->action == TVE_COLLAPSE)
  652. {
  653. CWaitCursor wait;
  654. CollapseChildren (pnmtv->itemNew.hItem);
  655. }
  656. }
  657. /*+-------------------------------------------------------------------------*
  658. * CAMCTreeView::CollapseChildren
  659. *
  660. * Collapses each descendent node of htiParent.
  661. *--------------------------------------------------------------------------*/
  662. void CAMCTreeView::CollapseChildren (HTREEITEM htiParent)
  663. {
  664. HTREEITEM htiChild;
  665. for (htiChild = GetChildItem (htiParent);
  666. htiChild != NULL;
  667. htiChild = GetNextItem (htiChild, TVGN_NEXT))
  668. {
  669. Expand (htiChild, TVE_COLLAPSE);
  670. CollapseChildren (htiChild);
  671. }
  672. }
  673. void CAMCTreeView::OnDeSelectNode(HNODE hNode)
  674. {
  675. DECLARE_SC(sc, TEXT("CAMCTreeView::OnDeSelectNode"));
  676. {
  677. // tell all interested observers about the deselection.
  678. // NOTE: the order is important - legacy snapins believe they can access the
  679. // result pane at this point and have the items still there.
  680. // But this is intermediate state, so Com events are locked out until the
  681. // results are cleared.
  682. // see windows bug (ntbug09) bug# 198660. (10/11/00)
  683. LockComEventInterface(AppEvents);
  684. sc = ScFireEvent(CTreeViewObserver::ScOnItemDeselected, hNode);
  685. if(sc)
  686. return;
  687. // Ensure the result view is clean.
  688. if (HasList())
  689. {
  690. // First findout if the result view is properly
  691. // set in the nodemgr by asking IFramePrivate.
  692. IFramePrivatePtr spFrame = m_spResultData;
  693. if (NULL != spFrame)
  694. {
  695. BOOL bIsResultViewSet = FALSE;
  696. sc = spFrame->IsResultViewSet(&bIsResultViewSet);
  697. // The result view is set, clean it up.
  698. if (bIsResultViewSet)
  699. {
  700. m_spResultData->DeleteAllRsltItems();
  701. m_spResultData->ResetResultData();
  702. }
  703. }
  704. }
  705. }
  706. // don't have a valid result pane type anymore.
  707. SetHasList(false);
  708. }
  709. // Note that OnSelectNode will return S_FALSE if the snap-in changes
  710. // the selection during the process of selecting the requested node.
  711. // A caller that gets an S_FALSE should assume that a different node
  712. // is selected and continue accordingly.
  713. HRESULT CAMCTreeView::OnSelectNode(HTREEITEM hItem, HNODE hNode)
  714. {
  715. DECLARE_SC(sc, _T("CAMCTreeView::OnSelectNode"));
  716. if (!hItem)
  717. {
  718. TraceError(_T("Null hItem ptr\n"), sc);
  719. sc = S_FALSE;
  720. return sc.ToHr();
  721. }
  722. if (!hNode)
  723. {
  724. TraceError(_T("Null hNode ptr\n"), sc);
  725. sc = S_FALSE;
  726. return sc.ToHr();
  727. }
  728. // First ensure that the node has been enumerated by calling expand node.
  729. ExpandNode(hItem);
  730. // set up the AMCView correctly.
  731. BOOL bAddSubFolders = FALSE;
  732. sc = m_pAMCView->ScOnSelectNode(hNode, bAddSubFolders);
  733. if(sc)
  734. return sc.ToHr();
  735. SetHasList(m_pAMCView->HasList());
  736. // add subfolders if necessary.
  737. if(bAddSubFolders)
  738. {
  739. sc = AddSubFolders(hItem, m_spResultData);
  740. if (sc)
  741. return sc.ToHr();
  742. }
  743. if (HasList())
  744. m_spResultData->SetLoadMode(FALSE); // SetLoadMode(FALSE) was called by CAMCView::OnSelectNode.
  745. // Need to change so that both calls are from the same function.
  746. // get the node callback
  747. INodeCallback* spNodeCallBack = GetNodeCallback();
  748. sc = ScCheckPointers(spNodeCallBack, E_UNEXPECTED);
  749. if (sc)
  750. return sc.ToHr();
  751. // send preload notify to children
  752. HTREEITEM hti = GetChildItem (hItem);
  753. while (hti != NULL)
  754. {
  755. HNODE hNode = GetItemNode (hti);
  756. if (hNode != 0)
  757. spNodeCallBack->PreLoad (hNode);
  758. hti = GetNextItem(hti, TVGN_NEXT);
  759. }
  760. return S_OK;
  761. }
  762. /*+-------------------------------------------------------------------------*
  763. * CAMCTreeView::SetNavigatingWithKeyboard
  764. *
  765. *
  766. *--------------------------------------------------------------------------*/
  767. void CAMCTreeView::SetNavigatingWithKeyboard (bool fKeyboardNav)
  768. {
  769. /*
  770. * if the requested state doesn't match the current state,
  771. * change the current state to match the request
  772. */
  773. if (fKeyboardNav != IsNavigatingWithKeyboard())
  774. {
  775. m_spKbdNavDelay = std::auto_ptr<CKeyboardNavDelay>(
  776. (fKeyboardNav)
  777. ? new CKeyboardNavDelay (this)
  778. : NULL /*assigning NULL deletes*/);
  779. }
  780. }
  781. /*+-------------------------------------------------------------------------*
  782. * CAMCTreeView::OnSelChanging
  783. *
  784. * TVN_SELCHANGING handler for CAMCTreeView.
  785. *--------------------------------------------------------------------------*/
  786. void CAMCTreeView::OnSelChanging(NMHDR* pNMHDR, LRESULT* pResult)
  787. {
  788. *pResult = 0;
  789. if (!IsNavigatingWithKeyboard())
  790. OnSelChangingWorker ((NM_TREEVIEW*) pNMHDR, pResult);
  791. }
  792. /*+-------------------------------------------------------------------------*
  793. * CAMCTreeView::OnSelChanged
  794. *
  795. * TVN_SELCHANGED handler for CAMCTreeView.
  796. *--------------------------------------------------------------------------*/
  797. void CAMCTreeView::OnSelChanged(NMHDR* pNMHDR, LRESULT* pResult)
  798. {
  799. NM_TREEVIEW* pnmtv = (NM_TREEVIEW*) pNMHDR;
  800. *pResult = 0;
  801. if (IsNavigatingWithKeyboard())
  802. m_spKbdNavDelay->ScStopTimer();
  803. SetNavigatingWithKeyboard (pnmtv->action == TVC_BYKEYBOARD);
  804. bool fDelayedSelection = IsNavigatingWithKeyboard() &&
  805. !m_spKbdNavDelay->ScStartTimer(pnmtv).IsError();
  806. if (!fDelayedSelection)
  807. OnSelChangedWorker (pnmtv, pResult);
  808. }
  809. /*+-------------------------------------------------------------------------*
  810. * CAMCTreeView::CKeyboardNavDelay::CKeyboardNavDelay
  811. *
  812. *
  813. *--------------------------------------------------------------------------*/
  814. CAMCTreeView::CKeyboardNavDelay::CKeyboardNavDelay (CAMCTreeView* pTreeView) :
  815. m_pTreeView (pTreeView)
  816. {
  817. ZeroMemory (&m_nmtvSelChanged, sizeof (m_nmtvSelChanged));
  818. }
  819. /*+-------------------------------------------------------------------------*
  820. * CAMCTreeView::CKeyboardNavDelay::OnTimer
  821. *
  822. * Called when the keyboard navigation delay timer fires. When that happens,
  823. * we need to perform the selection
  824. *--------------------------------------------------------------------------*/
  825. void CAMCTreeView::CKeyboardNavDelay::OnTimer()
  826. {
  827. /*
  828. * we don't need any more ticks from this timer (ignoring errors)
  829. */
  830. ScStopTimer();
  831. Trace (tagKeyboardNavDelay, _T("Applying delayed scope selection change"));
  832. LRESULT lUnused = 0;
  833. m_pTreeView->OnSelChangedWorker (&m_nmtvSelChanged, &lUnused);
  834. m_pTreeView->SetNavigatingWithKeyboard (false);
  835. /*
  836. * HANDS OFF! CAMCTreeView::SetNavigatingWithKeyboard deleted this object!
  837. */
  838. }
  839. /*+-------------------------------------------------------------------------*
  840. * CAMCTreeView::CKeyboardNavDelay::ScStartTimer
  841. *
  842. *
  843. *--------------------------------------------------------------------------*/
  844. SC CAMCTreeView::CKeyboardNavDelay::ScStartTimer(NMTREEVIEW* pnmtv)
  845. {
  846. DECLARE_SC (sc, _T("CAMCTreeView:CKeyboardNavDelay::ScStartTimer"));
  847. /*
  848. * let the base class start the timer
  849. */
  850. sc = BaseClass::ScStartTimer();
  851. if (sc)
  852. return (sc);
  853. /*
  854. * copy the notification struct so we can send it when our timer ticks
  855. */
  856. m_nmtvSelChanged = *pnmtv;
  857. return (sc);
  858. }
  859. void CAMCTreeView::OnSelChangedWorker(NM_TREEVIEW* pnmtv, LRESULT* pResult)
  860. {
  861. TRACE_METHOD(CAMCTreeView, OnSelChangedWorker);
  862. if (m_fInCleanUp == TRUE)
  863. return;
  864. // See which pane has focus. Some snapins/ocx may steal the focus
  865. // so we restore the focus after selecting the node.
  866. ASSERT (m_pAMCView != NULL);
  867. const CConsoleView::ViewPane ePane = m_pAMCView->GetFocusedPane();
  868. //
  869. // Select the new node
  870. //
  871. // Disable drawing to avoid seeing intermediate tree states.
  872. UpdateWindow();
  873. HRESULT hr = OnSelectNode(pnmtv->itemNew.hItem, (HNODE)pnmtv->itemNew.lParam);
  874. if (hr == S_OK)
  875. {
  876. CStandardToolbar* pStdToolbar = m_pAMCView->GetStdToolbar();
  877. ASSERT(NULL != pStdToolbar);
  878. if (NULL != pStdToolbar)
  879. {
  880. pStdToolbar->ScEnableUpOneLevel(GetRootItem() != pnmtv->itemNew.hItem);
  881. pStdToolbar->ScEnableExportList(m_pAMCView->HasListOrListPad());
  882. }
  883. *pResult = 0;
  884. }
  885. else if (hr == S_FALSE)
  886. {
  887. // snap-in changed the selection on us, so don't continue with this node.
  888. return;
  889. }
  890. else
  891. {
  892. // something wrong with the node we are trying to select, reselect the old one
  893. // SelectItem(pnmtv->itemOld.hItem);
  894. MMCMessageBox(IDS_SNAPIN_FAILED_INIT);
  895. *pResult = hr;
  896. }
  897. /*
  898. * Even if the active view hasn't changed always restore the active view.
  899. * Reason being, for OCX's even though they have the focus, they require
  900. * MMC to inform that OCX being selected. (see bug: 180964)
  901. */
  902. switch (ePane)
  903. {
  904. case CConsoleView::ePane_ScopeTree:
  905. {
  906. // if another view was made active, switch it back.
  907. // View could still be active, but have focus stolen by
  908. // a snap-in or ocx, so ensure view has focus too.
  909. CFrameWnd* pFrame = GetParentFrame();
  910. if (pFrame->GetActiveView() != this)
  911. pFrame->SetActiveView(this);
  912. else if (::GetFocus() != m_hWnd)
  913. SetFocus();
  914. break;
  915. }
  916. case CConsoleView::ePane_Results:
  917. // If the result pane has the focus before and after
  918. // the node was selected, then the last event snapin
  919. // receives is scope selected which is incorrect.
  920. // So we first set scope pane as active view but do
  921. // not send notifications. Then we set result pane
  922. // as active view which sends scope de-select and
  923. // result pane select.
  924. // Set Scope pane as active view and we also want to
  925. // be notified about this active view so that our
  926. // view activation observers will know who is the
  927. // active view.
  928. GetParentFrame()->SetActiveView(this, true);
  929. // Now set result pane as active view and ask for notifications.
  930. m_pAMCView->ScDeferSettingFocusToResultPane();
  931. break;
  932. case CConsoleView::ePane_None:
  933. // no pane is active, do nothing
  934. break;
  935. default:
  936. m_pAMCView->ScSetFocusToPane (ePane);
  937. break;
  938. }
  939. /*
  940. * Bug 345402: Make sure the focus rect is on the list control (if it
  941. * actually has the focus) to wake up any accessibility tools that might
  942. * be watching for input and focus changes.
  943. */
  944. m_pAMCView->ScJiggleListViewFocus ();
  945. }
  946. void CAMCTreeView::OnSelChangingWorker (NM_TREEVIEW* pnmtv, LRESULT* pResult)
  947. {
  948. TRACE_METHOD(CAMCTreeView, OnSelChangingWorker);
  949. if (m_fInCleanUp == TRUE)
  950. return;
  951. //
  952. // De-select the current node
  953. //
  954. OnDeSelectNode ((HNODE)pnmtv->itemOld.lParam);
  955. *pResult = 0;
  956. }
  957. HRESULT CAMCTreeView::AddSubFolders(MTNODEID* pIDs, int length)
  958. {
  959. ASSERT(pIDs != NULL && length != 0);
  960. HRESULT hr = E_FAIL;
  961. // first make sure the specified node is expanded in the tree ctrl
  962. HTREEITEM hti = ExpandNode(pIDs, length, TRUE, false /*bExpandVisually*/);
  963. ASSERT(hti != NULL);
  964. // if successful, add the node's subfolders to the list view
  965. if (hti != NULL)
  966. {
  967. hr = AddSubFolders(hti, m_spResultData);
  968. ASSERT(SUCCEEDED(hr));
  969. }
  970. return hr;
  971. }
  972. HRESULT CAMCTreeView::AddSubFolders(HTREEITEM hti, LPRESULTDATA pResultData)
  973. {
  974. HRESULT hr;
  975. RESULTDATAITEM tRDI;
  976. ::ZeroMemory(&tRDI, sizeof(tRDI));
  977. tRDI.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
  978. tRDI.nCol = 0;
  979. tRDI.str = MMC_TEXTCALLBACK;
  980. tRDI.nImage = MMC_IMAGECALLBACK;
  981. tRDI.nIndex = -1;
  982. hti = GetChildItem(hti);
  983. ASSERT(m_pAMCView != NULL);
  984. INodeCallback* spCallback = GetNodeCallback();
  985. ASSERT(spCallback != NULL);
  986. while (hti != NULL)
  987. {
  988. HNODE hNode = GetItemNode (hti);
  989. if (hNode != 0)
  990. {
  991. tRDI.lParam = LParamFromNode (hNode);
  992. hr = pResultData->InsertItem(&tRDI);
  993. CHECK_HRESULT(hr);
  994. if (SUCCEEDED(hr))
  995. hr = spCallback->SetResultItem(hNode, tRDI.itemID);
  996. // add custom image if any
  997. spCallback->AddCustomFolderImage (hNode, m_spRsltImageList);
  998. }
  999. hti = GetNextItem(hti, TVGN_NEXT);
  1000. }
  1001. return S_OK;
  1002. }
  1003. int CAMCTreeView::OnCreate(LPCREATESTRUCT lpCreateStruct)
  1004. {
  1005. DECLARE_SC (sc, _T("CAMCTreeView::OnCreate"));
  1006. TRACE_METHOD(CAMCTreeView, OnCreate);
  1007. if (CTreeView::OnCreate(lpCreateStruct) == -1)
  1008. return -1;
  1009. m_pAMCView = ::GetAMCView (this);
  1010. ASSERT(m_pAMCView != NULL);
  1011. IScopeTree* spScopeTree = m_pAMCView->GetScopeTree();
  1012. ASSERT(spScopeTree != NULL);
  1013. HIMAGELIST hImageList;
  1014. spScopeTree->GetImageList(reinterpret_cast<PLONG_PTR>(&hImageList));
  1015. CBitmap bmp;
  1016. bmp.LoadBitmap(MAKEINTRESOURCE(IDB_AMC_NODES16));
  1017. int i = ImageList_AddMasked(hImageList, (HBITMAP) bmp.GetSafeHandle(), RGB(255,0,255));
  1018. ASSERT(i != -1 && "ImageList_Add failed.");
  1019. TreeView_SetImageList( *this, hImageList, TVSIL_NORMAL );
  1020. sc = ScRegisterAsDropTarget(m_hWnd);
  1021. if (sc)
  1022. return (-1);
  1023. sc = CreateNodeManager();
  1024. if (sc)
  1025. return (-1);
  1026. return 0;
  1027. }
  1028. BOOL CAMCTreeView::DestroyWindow()
  1029. {
  1030. TRACE_METHOD(CAMCTreeView, DestroyWindow);
  1031. CleanUp();
  1032. return CTreeView::DestroyWindow();
  1033. }
  1034. void
  1035. CAMCTreeView::DeleteNode(
  1036. HTREEITEM htiToDelete,
  1037. BOOL fDeleteThis)
  1038. {
  1039. // Ensure curr sel is not a child of the item to be deleted.
  1040. for (HTREEITEM hti = GetSelectedItem();
  1041. hti != NULL;
  1042. hti = GetParentItem(hti))
  1043. {
  1044. if (htiToDelete == hti)
  1045. {
  1046. if (fDeleteThis == TRUE)
  1047. {
  1048. hti = GetParentItem(hti);
  1049. if (hti)
  1050. SelectItem(hti);
  1051. }
  1052. break;
  1053. }
  1054. }
  1055. // There are two paths to this function. Path 1, the view is deleted and there is no
  1056. // longer a root node. Path 2. When a node is manually deleted, the selection is updated
  1057. // in CAMCView::OnUpdateSelectionForDelete, therefore, the above code traverses to the root node
  1058. ASSERT(hti == NULL || fDeleteThis == FALSE);
  1059. SDeleteNodeInfo dniLocal = {htiToDelete, hti, fDeleteThis};
  1060. _DeleteNode(dniLocal);
  1061. }
  1062. void CAMCTreeView::_DeleteNode(SDeleteNodeInfo& dni)
  1063. {
  1064. ASSERT(&dni != NULL);
  1065. ASSERT(dni.htiToDelete != NULL);
  1066. if (dni.htiToDelete == NULL)
  1067. return;
  1068. SDeleteNodeInfo dniLocal = {GetChildItem(dni.htiToDelete),
  1069. dni.htiSelected, TRUE};
  1070. // delete all the child nodes of the node being deleted
  1071. while (dniLocal.htiToDelete != NULL)
  1072. {
  1073. _DeleteNode(dniLocal);
  1074. dniLocal.htiToDelete = GetChildItem(dni.htiToDelete);
  1075. }
  1076. if (dni.fDeleteThis == TRUE)
  1077. {
  1078. // Reset the temp selection cache.
  1079. // This deals with items that are right click selected (temporary) on the context
  1080. // menu
  1081. if (IsTempSelectionActive() && (GetTempSelectedItem() == dni.htiToDelete))
  1082. {
  1083. SC sc = ScRemoveTempSelection ();
  1084. if (sc)
  1085. sc.TraceAndClear();
  1086. }
  1087. HNODE hNode = (HNODE)GetItemData(dni.htiToDelete);
  1088. HTREEITEM htiParentOfItemToDelete = GetParentItem(dni.htiToDelete);
  1089. // If the item is in list view remove it. We do not want to do this
  1090. // if it is virtual list or if selected item is "Console Root"
  1091. // in which case then parent is NULL.
  1092. if (HasList() && !m_pAMCView->IsVirtualList() &&
  1093. (NULL != htiParentOfItemToDelete) &&
  1094. (htiParentOfItemToDelete == dni.htiSelected) )
  1095. {
  1096. HRESULTITEM itemID;
  1097. HRESULT hr;
  1098. hr = m_spResultData->FindItemByLParam(LParamFromNode(hNode), &itemID);
  1099. if (SUCCEEDED(hr))
  1100. {
  1101. hr = m_spResultData->DeleteItem(itemID, 0);
  1102. ASSERT(SUCCEEDED(hr));
  1103. }
  1104. }
  1105. // tell the tree control to nuke it
  1106. DeleteItem(dni.htiToDelete);
  1107. // send an event to all interested observers
  1108. SC sc = ScFireEvent(CTreeViewObserver::ScOnItemDeleted, hNode, dni.htiToDelete);
  1109. if(sc)
  1110. sc.TraceAndClear();
  1111. // tell the master tree to nuke it.
  1112. m_pAMCView->GetScopeTree()->DestroyNode(hNode);
  1113. // maintain history
  1114. m_pAMCView->GetHistoryList()->DeleteEntry (hNode);
  1115. }
  1116. }
  1117. void CAMCTreeView::DeleteScopeTree()
  1118. {
  1119. DECLARE_SC(sc, _T("CAMCTreeView::DeleteScopeTree"));
  1120. m_fInCleanUp = TRUE;
  1121. // Release the ResultView from the IFrame in the primary snapin in
  1122. // the selected node.
  1123. // This is necessary to release the result view if the selected node
  1124. // is a snap-in node.
  1125. // Free all the nodes
  1126. HTREEITEM htiRoot = GetRootItem();
  1127. if (htiRoot != NULL)
  1128. DeleteNode(htiRoot, TRUE);
  1129. // First findout if the result view is properly
  1130. // set in the nodemgr by asking IFramePrivate.
  1131. IFramePrivatePtr spFrame = m_spResultData;
  1132. if (NULL != spFrame)
  1133. {
  1134. BOOL bIsResultViewSet = FALSE;
  1135. sc = spFrame->IsResultViewSet(&bIsResultViewSet);
  1136. // The result view is set, clean it up.
  1137. if (bIsResultViewSet)
  1138. sc = m_spResultData->DeleteAllRsltItems();
  1139. }
  1140. m_fInCleanUp = FALSE;
  1141. }
  1142. void CAMCTreeView::CleanUp()
  1143. {
  1144. TRACE_METHOD(CAMCTreeView, CleanUp);
  1145. m_fInCleanUp = TRUE;
  1146. m_spNodeManager = NULL;
  1147. m_spHeaderCtrl = NULL;
  1148. m_spResultData = NULL;
  1149. m_spRsltImageList = NULL;
  1150. m_spScopeData = NULL;
  1151. m_fInCleanUp = FALSE;
  1152. }
  1153. void CAMCTreeView::OnDestroy()
  1154. {
  1155. TRACE_METHOD(CAMCTreeView, OnDestroy);
  1156. //CleanUp();
  1157. CTreeView::OnDestroy();
  1158. CleanUp();
  1159. }
  1160. HRESULT CAMCTreeView::CreateNodeManager(void)
  1161. {
  1162. TRACE_METHOD(CAMCTreeView, CreateNodeManager);
  1163. if (m_spScopeData)
  1164. return S_OK;
  1165. #if _MSC_VER >= 1100
  1166. IFramePrivatePtr pIFrame(CLSID_NodeInit, NULL, MMC_CLSCTX_INPROC);
  1167. #else
  1168. IFramePrivatePtr pIFrame(CLSID_NodeInit, MMC_CLSCTX_INPROC);
  1169. #endif
  1170. ASSERT(pIFrame != NULL); if (pIFrame == NULL) return E_FAIL;
  1171. m_spScopeData = pIFrame;
  1172. m_spHeaderCtrl = pIFrame;
  1173. if (m_spHeaderCtrl)
  1174. pIFrame->SetHeader(m_spHeaderCtrl);
  1175. m_spResultData = pIFrame;
  1176. m_spRsltImageList = pIFrame;
  1177. m_spNodeManager = pIFrame;
  1178. pIFrame->SetComponentID(TVOWNED_MAGICWORD);
  1179. return S_OK;
  1180. }
  1181. HTREEITEM CAMCTreeView::GetClickedNode()
  1182. {
  1183. TV_HITTESTINFO tvhi;
  1184. tvhi.pt = (POINT)GetCaretPos();
  1185. tvhi.flags = TVHT_ONITEMLABEL;
  1186. tvhi.hItem = 0;
  1187. HTREEITEM htiClicked = HitTest(&tvhi);
  1188. return htiClicked;
  1189. }
  1190. void CAMCTreeView::GetCountOfChildren(HTREEITEM hItem, LONG* pcChildren)
  1191. {
  1192. TV_ITEM tvi;
  1193. tvi.hItem = hItem;
  1194. tvi.mask = TVIF_CHILDREN;
  1195. tvi.cChildren = 0;
  1196. GetItem(&tvi);
  1197. *pcChildren = tvi.cChildren;
  1198. }
  1199. void CAMCTreeView::SetCountOfChildren(HTREEITEM hItem, int cChildren)
  1200. {
  1201. TV_ITEM tvi;
  1202. tvi.hItem = hItem;
  1203. tvi.mask = TVIF_HANDLE | TVIF_CHILDREN;
  1204. tvi.cChildren = cChildren;
  1205. SetItem(&tvi);
  1206. }
  1207. HTREEITEM CAMCTreeView::FindNode(HTREEITEM hti, MTNODEID id)
  1208. {
  1209. INodeCallback* pCallback = GetNodeCallback();
  1210. static MTNODEID nID = -1;
  1211. static HRESULT hr = S_OK;
  1212. hr = pCallback->GetMTNodeID(GetItemNode(hti), &nID);
  1213. ASSERT(SUCCEEDED(hr));
  1214. if (FAILED(hr))
  1215. return NULL;
  1216. if (nID == id)
  1217. return hti;
  1218. HTREEITEM htiTemp = GetChildItem(hti);
  1219. if (htiTemp != NULL)
  1220. htiTemp = FindNode(htiTemp, id);
  1221. if (htiTemp == NULL)
  1222. {
  1223. htiTemp = GetNextSiblingItem(hti);
  1224. if (htiTemp != NULL)
  1225. htiTemp = FindNode(htiTemp, id);
  1226. }
  1227. return htiTemp;
  1228. }
  1229. HTREEITEM CAMCTreeView::FindSiblingItem(HTREEITEM hti, MTNODEID id)
  1230. {
  1231. INodeCallback* pCallback = GetNodeCallback();
  1232. if (!pCallback)
  1233. return NULL;
  1234. static MTNODEID nID = -1;
  1235. static HRESULT hr = S_OK;
  1236. while (hti != NULL)
  1237. {
  1238. hr = pCallback->GetMTNodeID(GetItemNode(hti), &nID);
  1239. if (FAILED(hr))
  1240. return NULL;
  1241. if (nID == id)
  1242. return hti;
  1243. hti = GetNextSiblingItem(hti);
  1244. }
  1245. return NULL;
  1246. }
  1247. //+-------------------------------------------------------------------
  1248. //
  1249. // Member: CAMCTreeView::SelectNode
  1250. //
  1251. // Synopsis: Given path to a node, select the node. If bSelectExactNode
  1252. // is false then walk the path as much as possible and select
  1253. // the last node in the best matched path. If bSelectExactNode
  1254. // is true then select the node if available else do nothing.
  1255. //
  1256. // Arguments: [pIDs] - [in] Array of node-id's (the path)
  1257. // [length] - [in] length of the above array
  1258. // [bSelectExactNode] - [in] select the exact node or not?
  1259. //
  1260. // Returns: SC, return ScFromMMC(IDS_NODE_NOT_FOUND) if select exact node is specified
  1261. // and it cannot be selected
  1262. //
  1263. //--------------------------------------------------------------------
  1264. SC CAMCTreeView::ScSelectNode(MTNODEID* pIDs, int length, bool bSelectExactNode /*= false*/)
  1265. {
  1266. DECLARE_SC(sc, TEXT("CAMCTreeView::ScSelectNode"));
  1267. sc = ScCheckPointers(pIDs);
  1268. if (sc)
  1269. return sc;
  1270. if (m_fInExpanding)
  1271. return (sc);
  1272. HTREEITEM hti = GetRootItem();
  1273. sc = ScCheckPointers( (void*)hti, E_UNEXPECTED);
  1274. if (sc)
  1275. return sc;
  1276. if (pIDs[0] != ROOTNODEID)
  1277. return (sc = E_INVALIDARG);
  1278. INodeCallback* pCallback = GetNodeCallback();
  1279. sc = ScCheckPointers(pCallback, E_UNEXPECTED);
  1280. if (sc)
  1281. return sc;
  1282. MTNODEID nID = 0;
  1283. sc = pCallback->GetMTNodeID(GetItemNode(hti), &nID);
  1284. if (sc)
  1285. return sc;
  1286. bool bExactNodeFound = false;
  1287. for (int i=0; i<length; ++i)
  1288. {
  1289. if (pIDs[i] == nID)
  1290. break;
  1291. }
  1292. for (++i; i < length; ++i)
  1293. {
  1294. if (GetChildItem(hti) == NULL)
  1295. Expand(hti, TVE_EXPAND);
  1296. hti = FindSiblingItem(GetChildItem(hti), pIDs[i]);
  1297. if (hti == NULL)
  1298. break;
  1299. }
  1300. if (length == i)
  1301. bExactNodeFound = true;
  1302. if (hti)
  1303. {
  1304. // If exact node is to be selected make sure we have walked through the entire path.
  1305. if ( (bSelectExactNode) && (! bExactNodeFound) )
  1306. return ScFromMMC(IDS_NODE_NOT_FOUND); // do not trace this error.
  1307. if (GetSelectedItem() == hti)
  1308. ScReselect();
  1309. else
  1310. SelectItem(hti);
  1311. }
  1312. return sc;
  1313. }
  1314. /*+-------------------------------------------------------------------------*
  1315. *
  1316. * CAMCTreeView::Expand
  1317. *
  1318. * PURPOSE: Expands a particular tree item. This is just a wrapper around the
  1319. * tree control's expand method, which allows items to be expanded
  1320. * without changing the visual appearance of the tree.
  1321. *
  1322. * PARAMETERS:
  1323. * HTREEITEM hItem :
  1324. * UINT nCode :
  1325. * bool bExpandVisually :
  1326. *
  1327. * RETURNS:
  1328. * BOOL
  1329. *
  1330. *+-------------------------------------------------------------------------*/
  1331. BOOL
  1332. CAMCTreeView::Expand(HTREEITEM hItem, UINT nCode, bool bExpandVisually)
  1333. {
  1334. if( (nCode==TVE_EXPAND) && (!bExpandVisually) )
  1335. {
  1336. bool bExpand = true;
  1337. // code repeated here from OnItemExpand - we just mimic the effect of TVN_ITEMEXPANDING.
  1338. ExpandNode(hItem);
  1339. INodeCallback* pCallback = GetNodeCallback();
  1340. ASSERT(pCallback != NULL);
  1341. HNODE hNode = GetItemNode(hItem);
  1342. pCallback->Notify(hNode, NCLBK_SETEXPANDEDVISUALLY, bExpand, 0);
  1343. // If item has no children remove the + sign
  1344. if (GetChildItem(hItem) == NULL)
  1345. SetButton(hItem, FALSE);
  1346. return true;
  1347. }
  1348. else
  1349. return Expand(hItem, nCode);
  1350. }
  1351. /*+-------------------------------------------------------------------------*
  1352. *
  1353. * CAMCTreeView::ExpandNode
  1354. *
  1355. * PURPOSE: Expands a particular node in the tree.
  1356. *
  1357. * PARAMETERS:
  1358. * MTNODEID* pIDs :
  1359. * int length :
  1360. * bool bExpand :
  1361. * bool bExpandVisually : valid only if bExpand is true. If bExpandVisually
  1362. * is true, the items appear in the tree. If false,
  1363. * the tree appears unchanged, although items have been
  1364. * added.
  1365. *
  1366. * RETURNS:
  1367. * HTREEITEM
  1368. *
  1369. *+-------------------------------------------------------------------------*/
  1370. HTREEITEM
  1371. CAMCTreeView::ExpandNode(MTNODEID* pIDs, int length, bool bExpand, bool bExpandVisually)
  1372. {
  1373. HTREEITEM hti = GetRootItem();
  1374. ASSERT(hti != NULL);
  1375. ASSERT(pIDs[0] == ROOTNODEID);
  1376. INodeCallback* pCallback = GetNodeCallback();
  1377. if (!pCallback)
  1378. return NULL;
  1379. MTNODEID nID = 0;
  1380. HRESULT hr = pCallback->GetMTNodeID(GetItemNode(hti), &nID);
  1381. if (FAILED(hr))
  1382. return NULL;
  1383. for (int i=0; i<length; ++i)
  1384. {
  1385. if (pIDs[i] == nID)
  1386. break;
  1387. }
  1388. for (++i; i < length; ++i)
  1389. {
  1390. if (GetChildItem(hti) == NULL)
  1391. Expand(hti, TVE_EXPAND, bExpandVisually);
  1392. hti = FindSiblingItem(GetChildItem(hti), pIDs[i]);
  1393. if (hti == NULL)
  1394. break;
  1395. }
  1396. if (hti)
  1397. Expand(hti, bExpand ? TVE_EXPAND : TVE_COLLAPSE, bExpandVisually);
  1398. return hti;
  1399. }
  1400. /*+-------------------------------------------------------------------------*
  1401. * CAMCTreeView::OnKeyDown
  1402. *
  1403. * WM_KEYDOWN handler for CAMCTreeView.
  1404. *--------------------------------------------------------------------------*/
  1405. void CAMCTreeView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  1406. {
  1407. switch (nChar)
  1408. {
  1409. case VK_DELETE:
  1410. if (m_pAMCView->IsVerbEnabled(MMC_VERB_DELETE))
  1411. {
  1412. HTREEITEM hti = GetSelectedItem();
  1413. if (hti != NULL)
  1414. {
  1415. HNODE hNodeSel = GetItemNode(hti);
  1416. ASSERT(hNodeSel != NULL);
  1417. INodeCallback* pNC = GetNodeCallback();
  1418. ASSERT(pNC != NULL);
  1419. pNC->Notify(hNodeSel, NCLBK_DELETE, TRUE, 0);
  1420. }
  1421. return;
  1422. }
  1423. break;
  1424. }
  1425. CTreeView::OnKeyDown(nChar, nRepCnt, nFlags);
  1426. }
  1427. #ifdef DBG
  1428. void CAMCTreeView::DbgDisplayNodeName(HNODE hNode)
  1429. {
  1430. ASSERT(hNode != NULL);
  1431. INodeCallback* spCallback = GetNodeCallback();
  1432. ASSERT(spCallback != NULL);
  1433. tstring strName;
  1434. HRESULT hr = spCallback->GetDisplayName(hNode, strName);
  1435. ::MMCMessageBox( strName.data() );
  1436. }
  1437. void CAMCTreeView::DbgDisplayNodeName(HTREEITEM hti)
  1438. {
  1439. DbgDisplayNodeName((HNODE)GetItemData(hti));
  1440. }
  1441. #endif
  1442. /*+-------------------------------------------------------------------------*
  1443. *
  1444. * CAMCTreeView::OnSysKeyDown and CAMCTreeView::OnSysChar
  1445. *
  1446. * PURPOSE: Handle the WM_SYSKEYDOWN and WM_SYSCHAR messages. Note:
  1447. * VK_RETURN causes a beep if handled in WM_SYSKEYDOWN. And VK_LEFT and
  1448. * VK_RIGHT don't cause a WM_SYSCHAR. Thats why we need to handle these
  1449. * differently.
  1450. *
  1451. * PARAMETERS:
  1452. * UINT nChar :
  1453. * UINT nRepCnt :
  1454. * UINT nFlags :
  1455. *
  1456. * RETURNS:
  1457. * void
  1458. *
  1459. *+-------------------------------------------------------------------------*/
  1460. void CAMCTreeView::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  1461. {
  1462. switch (nChar)
  1463. {
  1464. case VK_LEFT:
  1465. case VK_RIGHT:
  1466. {
  1467. CWnd* pwndParent = GetParent();
  1468. ASSERT(pwndParent != NULL);
  1469. if (pwndParent != NULL)
  1470. pwndParent->SendMessage (WM_SYSKEYDOWN, nChar,
  1471. MAKELPARAM (nRepCnt, nFlags));
  1472. return;
  1473. }
  1474. default:
  1475. break;
  1476. }
  1477. CTreeView::OnSysKeyDown(nChar, nRepCnt, nFlags);
  1478. }
  1479. void CAMCTreeView::OnSysChar(UINT nChar, UINT nRepCnt, UINT nFlags)
  1480. {
  1481. DECLARE_SC(sc, TEXT("CAMCTreeView::OnSysChar"));
  1482. switch (nChar)
  1483. {
  1484. case VK_RETURN:
  1485. {
  1486. INodeCallback* pCallback = GetNodeCallback();
  1487. CAMCView* pAMCView = GetAMCView();
  1488. sc = ScCheckPointers(pAMCView, pCallback, E_UNEXPECTED);
  1489. if (sc)
  1490. return;
  1491. if (! pAMCView->IsVerbEnabled(MMC_VERB_PROPERTIES))
  1492. return;
  1493. HTREEITEM hti = GetSelectedItem();
  1494. if (!hti)
  1495. break;
  1496. HNODE hNode = (HNODE)GetItemData(hti);
  1497. if (hNode != 0)
  1498. pCallback->Notify(hNode, NCLBK_PROPERTIES, TRUE, 0);
  1499. return;
  1500. }
  1501. default:
  1502. break;
  1503. }
  1504. CTreeView::OnSysChar(nChar, nRepCnt, nFlags);
  1505. }
  1506. BOOL CAMCTreeView::OnCmdMsg( UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo )
  1507. {
  1508. // Do normal command routing
  1509. if (CTreeView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  1510. return TRUE;
  1511. // if view didn't handle it, give parent view a chance
  1512. if (m_pAMCView != NULL)
  1513. return static_cast<CWnd*>(m_pAMCView)->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
  1514. else
  1515. return FALSE;
  1516. }
  1517. void CAMCTreeView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
  1518. {
  1519. switch (lHint)
  1520. {
  1521. case VIEW_UPDATE_DELETE_EMPTY_VIEW:
  1522. {
  1523. if (!m_pAMCView)
  1524. {
  1525. CWnd* pWnd = GetParent();
  1526. ASSERT(pWnd != NULL);
  1527. m_pAMCView = reinterpret_cast<CAMCView*>(pWnd);
  1528. }
  1529. ASSERT(m_pAMCView != NULL);
  1530. if (m_pAMCView)
  1531. m_pAMCView->OnDeleteEmptyView();
  1532. }
  1533. break;
  1534. default:
  1535. break;
  1536. }
  1537. }
  1538. int CAMCTreeView::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
  1539. {
  1540. /*------------------------------------------------------------------------*/
  1541. /* Short out the WM_MOUSEACTIVATE here to prevent default processing, */
  1542. /* which is to send the message on to succeeding parent windows until */
  1543. /* one answers the message. In our case, it goes all the way up to */
  1544. /* the main frame, which invariably decides to activate. This is a */
  1545. /* problem for two reasons: */
  1546. /* */
  1547. /* 1. On the way back down from the main frame, the message passes */
  1548. /* through CAMCView, which lets CView::OnMouseActivate do the */
  1549. /* work. CView::OnMouseActivate will set itself (CAMCView) as */
  1550. /* the active view, which in turn causes focus to be set to */
  1551. /* the view. CAMCView never wants the focus, since it is just */
  1552. /* a frame for the scope and result panes, so it will deflect */
  1553. /* the activation to the scope pane (CAMCTreeView) in */
  1554. /* CAMCView::OnSetFocus, which is where we want it to be. If */
  1555. /* we short out the processing here, we avoid excessive focus */
  1556. /* churn. It is essential that CAMCTreeView::OnSetFocus set */
  1557. /* itself as the active view to keep the bookkeeping straight. */
  1558. /* */
  1559. /* 2. If we don't short out here and avoid excessive focus churn, */
  1560. /* we have a problem with sometimes erroneously entering rename */
  1561. /* mode when the tree isn't active and the user clicks (once) on */
  1562. /* the selected item. An ordinary activation sequence goes like */
  1563. /* this: WM_MOUSEACTIVATE, WM_xBUTTONDOWN, WM_SETFOUS -- all to */
  1564. /* the tree view. The tree's button down processing doesn't enter */
  1565. /* the label edit (i.e. rename) sequence because it recognizes */
  1566. /* that it doesn't have the focus when the click happens. When */
  1567. /* the tree view is a CView, as in this case, CView::OnMouseActivate */
  1568. /* sets the focus to the tree view, causing the activation sequence */
  1569. /* to look like this: WM_MOUSEACTIVATE, WM_SETFOCUS, WM_xBUTTONDOWN. */
  1570. /* Now the tree's button down processing sees that the tree has */
  1571. /* the focus, so it enters label edit mode. BUG! Shorting out */
  1572. /* here (and relying on CAMCTreeView::OnSetFocus to properly activate */
  1573. /* the view) fixes all that. */
  1574. /*------------------------------------------------------------------------*/
  1575. return (MA_ACTIVATE);
  1576. }
  1577. /*+-------------------------------------------------------------------------*
  1578. * CAMCTreeView::OnSetFocus
  1579. *
  1580. * WM_SETFOCUS handler for CAMCTreeView.
  1581. *--------------------------------------------------------------------------*/
  1582. void CAMCTreeView::OnSetFocus(CWnd* pOldWnd)
  1583. {
  1584. Trace(tagTree, TEXT("OnSetFocus"));
  1585. /*
  1586. * if this view has the focus, it should be the active view
  1587. */
  1588. GetParentFrame()->SetActiveView (this);
  1589. CTreeView::OnSetFocus(pOldWnd);
  1590. }
  1591. /*+-------------------------------------------------------------------------*
  1592. * CAMCTreeView::OnKillFocus
  1593. *
  1594. * WM_KILLFOCUS handler for CAMCTreeView.
  1595. *--------------------------------------------------------------------------*/
  1596. void CAMCTreeView::OnKillFocus(CWnd* pNewWnd)
  1597. {
  1598. Trace(tagTree, TEXT("OnKillFocus"));
  1599. CTreeView::OnKillFocus(pNewWnd);
  1600. /*
  1601. * Bug 114948 (from the "Windows NT Bugs" database, aka "the overlapping
  1602. * rectangle problem"): The tree control has code to invalidate the
  1603. * selected item when focus is lost. If we have a temp selection, we've
  1604. * made a temporary item appear selected by fiddling with TVIS_SELECTED
  1605. * states (see ScSet/RemoveTempSelection). We need to do it that way
  1606. * instead of sending TVM_SELECTITEM so we don't get unwanted
  1607. * TVN_SELCHANGED notifications, but it has the side effect of fooling
  1608. * the tree control's WM_KILLFOCUS handler into invalidating the non-temp
  1609. * selected item instead of the item that is really showing selection, the
  1610. * temp item.
  1611. *
  1612. * This bug was originally fixed with a sledgehammer, specifically by
  1613. * forcing the entire main frame and all of its children to be totally
  1614. * redrawn after displaying any context menu. This caused bug 139541
  1615. * (in the "Windows Bugs" database).
  1616. *
  1617. * A much more surgical fix to 114948, which also avoids 139541, is to
  1618. * manually invalidate the temporarily selected item. It's important
  1619. * that we do this after calling the base class so it will be redrawn
  1620. * in the "we don't have the focus" color (usually gray), rather than
  1621. * the standard selection color.
  1622. */
  1623. if (IsTempSelectionActive())
  1624. {
  1625. CRect rectItem;
  1626. GetItemRect (GetTempSelectedItem(), rectItem, false);
  1627. RedrawWindow (rectItem);
  1628. }
  1629. }
  1630. void CAMCTreeView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
  1631. {
  1632. DECLARE_SC(sc, TEXT("CAMCTreeView::OnActivateView"));
  1633. #ifdef DBG
  1634. Trace(tagTree, _T("TreeView::OnActivateView (%s, pAct=0x%08x, pDeact=0x%08x))\n"),
  1635. (bActivate) ? _T("true") : _T("false"), pActivateView, pDeactiveView);
  1636. #endif
  1637. if ( (pActivateView != pDeactiveView) &&
  1638. (bActivate) )
  1639. {
  1640. sc = ScFireEvent(CTreeViewObserver::ScOnTreeViewActivated);
  1641. if (sc)
  1642. sc.TraceAndClear();
  1643. }
  1644. CTreeView::OnActivateView(bActivate, pActivateView, pDeactiveView);
  1645. }
  1646. /*+-------------------------------------------------------------------------*
  1647. * CAMCTreeView::OnCustomDraw
  1648. *
  1649. * NM_CUSTOMDRAW handler for CAMCTreeView.
  1650. *--------------------------------------------------------------------------*/
  1651. void CAMCTreeView::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
  1652. {
  1653. NMCUSTOMDRAW* pnmcd = reinterpret_cast<NMCUSTOMDRAW *>(pNMHDR);
  1654. ASSERT (CWnd::FromHandle (pnmcd->hdr.hwndFrom) == this);
  1655. *pResult = m_FontLinker.OnCustomDraw (pnmcd);
  1656. }
  1657. /*+-------------------------------------------------------------------------*
  1658. * CTreeFontLinker::GetItemText
  1659. *
  1660. *
  1661. *--------------------------------------------------------------------------*/
  1662. std::wstring CTreeFontLinker::GetItemText (NMCUSTOMDRAW* pnmcd) const
  1663. {
  1664. USES_CONVERSION;
  1665. HTREEITEM hItem = reinterpret_cast<HTREEITEM>(pnmcd->dwItemSpec);
  1666. CTreeCtrl& tc = m_pTreeView->GetTreeCtrl();
  1667. return (std::wstring (T2CW (tc.GetItemText (hItem))));
  1668. }
  1669. //+-------------------------------------------------------------------
  1670. //
  1671. // Member: CAMCTreeView::ScGetTreeItemIconInfo
  1672. //
  1673. // Synopsis: Get the given node's small icon.
  1674. //
  1675. // Arguments: [hNode] - for which info is needed.
  1676. // [phIcon] - [out], ptr to HICON.
  1677. //
  1678. // Note: Caller calls DestroyIcon on the HICON returned.
  1679. //
  1680. // Returns: SC
  1681. //
  1682. //--------------------------------------------------------------------
  1683. SC CAMCTreeView::ScGetTreeItemIconInfo(HNODE hNode, HICON *phIcon)
  1684. {
  1685. DECLARE_SC(sc, TEXT("CAMCTreeView::ScGetTreeItemIconInfo"));
  1686. sc = ScCheckPointers(hNode, phIcon);
  1687. if (sc)
  1688. return sc;
  1689. INodeCallback* spNodeCallBack = GetNodeCallback();
  1690. sc = ScCheckPointers(spNodeCallBack, m_pAMCView, E_UNEXPECTED);
  1691. if (sc)
  1692. return sc;
  1693. // Get the index.
  1694. int nImage = -1;
  1695. int nSelectedImage = -1;
  1696. sc = spNodeCallBack->GetImages(hNode, &nImage, &nSelectedImage);
  1697. if (sc)
  1698. return sc;
  1699. // Get the imagelist.
  1700. HIMAGELIST hImageList = NULL;
  1701. hImageList = TreeView_GetImageList(GetSafeHwnd(), TVSIL_NORMAL);
  1702. if (! hImageList)
  1703. return (sc = E_FAIL);
  1704. *phIcon = ImageList_GetIcon(hImageList, nImage, ILD_TRANSPARENT);
  1705. if (!*phIcon)
  1706. return (sc = E_FAIL);
  1707. return sc;
  1708. }
  1709. /*+-------------------------------------------------------------------------*
  1710. *
  1711. * CAMCTreeView::ScRenameScopeNode
  1712. *
  1713. * PURPOSE: put the specified scope node into rename mode.
  1714. *
  1715. * PARAMETERS:
  1716. * HMTNODE hMTNode :
  1717. *
  1718. * RETURNS:
  1719. * SC
  1720. *
  1721. *+-------------------------------------------------------------------------*/
  1722. SC
  1723. CAMCTreeView::ScRenameScopeNode(HMTNODE hMTNode)
  1724. {
  1725. DECLARE_SC(sc, TEXT("CAMCTreeView::ScRenameScopeNode"));
  1726. if(!IsWindowVisible())
  1727. return (sc = E_FAIL);
  1728. HTREEITEM hti = NULL;
  1729. sc = m_treeMap.ScGetHTreeItemFromHMTNode(hMTNode, &hti);
  1730. if(sc)
  1731. return sc;
  1732. // must have the focus to rename
  1733. if (::GetFocus() != m_hWnd)
  1734. SetFocus();
  1735. if(NULL==EditLabel(hti))
  1736. return (sc = E_FAIL); // if for any reason the operation failed, return an error
  1737. return sc;
  1738. }