TreeCtrlMultiColumn.cpp
上传用户:louyoung
上传日期:2007-01-02
资源大小:123k
文件大小:17k
源码类别:

ActiveX/DCOM/ATL

开发平台:

Visual C++

  1. /************************************
  2.   REVISION LOG ENTRY
  3.   Revision By: Mihai Filimon
  4.   Revised on 6/13/98 11:58:20 AM
  5.   Comments: TreeCtrlMultiColumn.cpp: implementation of the CTreeMultiColumnCtrl class.
  6.  ************************************/
  7. #include "stdafx.h"
  8. #include "TreeCtrlMultiColumn.h"
  9. #include "tfilltree.h"
  10. #define IDLIST 0x1111
  11. #define dxNode 20
  12. #define dxSquareNode 9
  13. #define rgbLine RGB(128,128,128)
  14. #define rgbExpand RGB(0,0,0)
  15. #define PS_DOT 2
  16. //////////////////////////////////////////////////////////////////////
  17. // Construction/Destruction
  18. //////////////////////////////////////////////////////////////////////
  19. BEGIN_MESSAGE_MAP(CTreeMultiColumnCtrl, CTsyslistviewex)
  20. //{{AFX_MSG_MAP(CTreeMultiColumnCtrl)
  21. ON_WM_LBUTTONDOWN()
  22. ON_WM_KEYDOWN()
  23. //}}AFX_MSG_MAP
  24. END_MESSAGE_MAP()
  25. _STTreeMCCloneMessage CTreeMultiColumnCtrl::m_mapCloneMessage;
  26. // Function name : CTreeMultiColumnCtrl::CTreeMultiColumnCtrl
  27. // Description     : Constructor
  28. // Return type : 
  29. CTreeMultiColumnCtrl::CTreeMultiColumnCtrl(int nHeightRel):CTsyslistviewex(nHeightRel)
  30. {
  31. m_bInsideCode = 0;
  32. m_nTreeColumn = 0;
  33. m_nLastItemFind = -1;
  34. m_nLastItemFound = -1;
  35. }
  36. // Function name : CTreeMultiColumnCtrl::~CTreeMultiColumnCtrl
  37. // Description     : virtual Destructor
  38. // Return type : 
  39. CTreeMultiColumnCtrl::~CTreeMultiColumnCtrl()
  40. {
  41. }
  42. // Function name : CTreeMultiColumnCtrl::SetRootColumn
  43. // Description     : Set the new tree column.
  44. // Return type : int 
  45. // Argument         : int nNewTreeColumn
  46. int CTreeMultiColumnCtrl::SetRootColumn(int nNewTreeColumn)
  47. {
  48. ASSERT (nNewTreeColumn < GetCountColumn());
  49. ASSERT (nNewTreeColumn >= 0);
  50. int nOldTreeColumn = m_nTreeColumn;
  51. m_nTreeColumn = nNewTreeColumn;
  52. Invalidate();
  53. return nOldTreeColumn;
  54. }
  55. // Function name : CTreeMultiColumnCtrl::GetRootColumn
  56. // Description     : Return the current tree column
  57. // Return type : int 
  58. int CTreeMultiColumnCtrl::GetRootColumn() const
  59. {
  60. return m_nTreeColumn;
  61. }
  62. // Function name : CTreeMultiColumnCtrl::DrawCell
  63. // Description     : Draw a cell of tree control
  64. // Return type : void 
  65. // Argument         : CDC* pDC
  66. // Argument         : CRect& drawRect
  67. // Argument         : DWORD format
  68. // Argument         : int nItem
  69. // Argument         : int nColumn
  70. void CTreeMultiColumnCtrl::DrawCell(CDC* pDC, CRect& drawRect, DWORD format, int nItem, int nColumn)
  71. {
  72. m_bInsideCode++;
  73. if (nColumn == m_nTreeColumn)
  74. {
  75. CRect clipRect(drawRect);
  76. clipRect.top -= 2;
  77. clipRect.bottom += 2;
  78. CRgn clipRgn; clipRgn.CreateRectRgnIndirect(clipRect);
  79. pDC->SelectClipRgn(&clipRgn);
  80. int i = GetItemData(nItem);
  81. CArray<int,int> arPathParents;
  82. int level = GetItemPath(i, arPathParents);
  83. int x = drawRect.left;
  84. int yTop = drawRect.top;
  85. int yBottom = drawRect.bottom;
  86. CPoint middle(dxNode / 2, drawRect.Height() / 2);
  87. int psStyle = PS_SOLID;
  88. CPen penGray( psStyle, 1, rgbLine);
  89. CPen penBlack(PS_SOLID, 1, rgbExpand);
  90. CPen* pOldPen = (CPen*)pDC->SelectObject(penGray);
  91. int j = 0;
  92. for (j = 0; j < level; j++, x += dxNode)
  93. if (!IsLastChildren(arPathParents[j]))
  94. {
  95. pDC->MoveTo(x + middle.x, yTop - 1);
  96. pDC->LineTo(x + middle.x, yBottom + 1);
  97. }
  98. int yM1 = (yBottom + yTop) / 2;
  99. int yM2 = yM1;
  100. int xM1 = x + middle.x;
  101. int xM2 = xM1;
  102. if (ItemHasChildren(i))
  103. {
  104. SIZE size = {dxSquareNode, dxSquareNode};
  105. POINT point = {xM1 -  size.cx / 2, yM1 - size.cy / 2};
  106. pDC->FrameRect(CRect(point,size), &CBrush(rgbLine));
  107. xM1 -= size.cx / 2;
  108. xM2 += size.cx / 2;
  109. pDC->SelectObject(penBlack);
  110. pDC->MoveTo(xM1 + 2, yM1);
  111. pDC->LineTo(xM2 - 1, yM1);
  112. yM1 -= size.cy / 2;
  113. yM2 += size.cy / 2;
  114. if (!ItemIsExpanded(i))
  115. {
  116. pDC->MoveTo(x + middle.x, yM1 + 2);
  117. pDC->LineTo(x + middle.x, yM2 - 1);
  118. }
  119. pDC->SelectObject(penGray);
  120. }
  121. if (i != 0)
  122. {
  123. pDC->MoveTo(x + middle.x, yTop - 1);
  124. pDC->LineTo(x + middle.x, yM1);
  125. }
  126. if (!IsLastChildren(i))
  127. {
  128. pDC->MoveTo(x + middle.x, yM2);
  129. pDC->LineTo(x + middle.x, yBottom + 1);
  130. }
  131. pDC->MoveTo(xM2, (yBottom + yTop) / 2);
  132. pDC->LineTo(x + dxNode, (yBottom + yTop) / 2);
  133. x += dxNode;
  134. drawRect.left = x + 2;
  135. pDC->SelectClipRgn(NULL);
  136. }
  137. CTsyslistviewex::DrawCell(pDC, drawRect, format, nItem, nColumn);
  138. m_bInsideCode--;
  139. }
  140. // Function name : CTreeMultiColumnCtrl::PreSubclassWindow
  141. // Description     : When control is subclassed, object try to construct a clone of this list object
  142. // Return type : void 
  143. void CTreeMultiColumnCtrl::PreSubclassWindow( )
  144. {
  145. CTsyslistviewex::PreSubclassWindow();
  146. ModifyStyle(LVS_SORTASCENDING,0);
  147. ModifyStyle(LVS_SORTDESCENDING,0);
  148. m_listItems.Create(WS_CHILD, CRect(0,0,0,0), this, IDLIST);
  149. }
  150. // Function name : CTreeMultiColumnCtrl::WindowProc
  151. // Description     : Treat messages separatly if variable m_bInsideCode is zero
  152. // Return type : LRESULT 
  153. // Argument         :  UINT message
  154. // Argument         : WPARAM wParam
  155. // Argument         : LPARAM lParam
  156. LRESULT CTreeMultiColumnCtrl::WindowProc( UINT message, WPARAM wParam, LPARAM lParam )
  157. {
  158. LRESULT result = NULL;
  159. if (m_bInsideCode == 0)
  160. if (m_mapCloneMessage.IsCloneMessage(message))
  161. {
  162. result = m_listItems.SendMessage(message, wParam, lParam);
  163. UpdateTree(message, wParam, lParam, result);
  164. return result;
  165. }
  166. if (m_bInsideCode == 0)
  167. if (m_mapCloneMessage.IsHeaderMessage(message))
  168. if (m_listItems.GetSafeHwnd())
  169. m_listItems.SendMessage(message, wParam, lParam);
  170. result = CTsyslistviewex::WindowProc(message, wParam, lParam );
  171. return result;
  172. }
  173. // Function name : CTreeMultiColumnCtrl::SetItemParent
  174. // Description     : Set the new parent of iItem to iItemParent
  175. // Return type : BOOL 
  176. // Argument         : int iItem
  177. // Argument         : int iItemParent
  178. BOOL CTreeMultiColumnCtrl::SetItemParent(int iItem, int iItemParent)
  179. {
  180. UpdateTree(LVM_SETPARENT, iItem, iItemParent, 0);
  181. return TRUE;
  182. }
  183. // Function name : CTreeMultiColumnCtrl::GetItemParent
  184. // Description     : Return -1 if iItem do not have parent
  185. // Return type : int 
  186. int CTreeMultiColumnCtrl::GetItemParent(int iItem)
  187. {
  188. int value = -1;
  189. if (m_mapParents.Lookup(iItem, value))
  190. return value;
  191. return -1;
  192. }
  193. // Function name : CTreeMultiColumnCtrl::ItemHasChildren
  194. // Description     : Return TRUE if item iItem has at least one children
  195. // Return type : BOOL 
  196. // Argument         : int iItem
  197. BOOL CTreeMultiColumnCtrl::ItemHasChildren(int iItem)
  198. {
  199. int key = -1;
  200. int value = -1;
  201. POSITION position = m_mapParents.GetStartPosition();
  202. while (position)
  203. {
  204. m_mapParents.GetNextAssoc(position, key, value);
  205. if (value == iItem)
  206. return TRUE;
  207. }
  208. return FALSE;
  209. }
  210. // Function name : CTreeMultiColumnCtrl::GetPath
  211. // Description     : Insert parents of iItem in arParents.
  212. // Return type : int 
  213. // Argument         : int iItem
  214. // Argument         : CArray<int,int>&
  215. // Argument         :  arParents
  216. int CTreeMultiColumnCtrl::GetItemPath(int iItem, CArray<int, int>& arParents)
  217. {
  218. arParents.RemoveAll();
  219. int i = iItem;
  220. while ((i = GetItemParent(i))>=0)
  221. arParents.InsertAt(0, i);
  222. return arParents.GetSize();
  223. }
  224. // Function name : CTreeMultiColumnCtrl::IsLastChildren
  225. // Description     : Check if iItem is last children
  226. // Return type : BOOL 
  227. // Argument         : int iItem
  228. BOOL CTreeMultiColumnCtrl::IsLastChildren(int iItem)
  229. {
  230. int iParent = GetItemParent(iItem);
  231. int cItem = m_listItems.GetItemCount();
  232. int i = iItem + 1;
  233. while (i < cItem)
  234. {
  235. if (GetItemParent(i) == iParent)
  236. return FALSE;
  237. i++;
  238. }
  239. return TRUE;
  240. }
  241. // Function name : CTreeMultiColumnCtrl::ItemIsExpanded
  242. // Description     : Return TRUE if Item is Expanded, FALSE if iItem is collapsed
  243. // Return type : BOOL 
  244. // Argument         : int iItem
  245. BOOL CTreeMultiColumnCtrl::ItemIsExpanded(int iItem)
  246. {
  247. BOOL value = FALSE;
  248. if (m_mapItemExpanded.Lookup(iItem, value))
  249. return value;
  250. return FALSE;
  251. }
  252. // Function name : CTreeMultiColumnCtrl::UpdateTree
  253. // Description     : Update the tree control function by message receive by object
  254. // Return type : void 
  255. // Argument         : UINT message
  256. // Argument         : WPARAM wParam
  257. // Argument         : LPARAM lParam
  258. // Argument         : LRESULT result
  259. void CTreeMultiColumnCtrl::UpdateTree(UINT message, WPARAM wParam, LPARAM lParam, LRESULT result)
  260. {
  261. m_bInsideCode++; // Do not process WindowProc...
  262. switch (message)
  263. {
  264. // Set new parent
  265. case LVM_DELETEALLITEMS:
  266. {
  267. m_listItems.DeleteAllItems();
  268. DeleteAllItems();
  269. m_mapItemExpanded.RemoveAll();
  270. m_mapParents.RemoveAll();
  271. break;
  272. }
  273. case LVM_SETPARENT:
  274. {
  275. int iItem = (int)wParam;
  276. int iItemParent = (int)lParam;
  277. int iItemOldParent = GetItemParent(iItem);
  278. LV_FINDINFO fInfo; fInfo.flags = LVFI_PARAM; fInfo.lParam = iItem;
  279. int i = FindItem(&fInfo);
  280. while ( (i < GetItemCount())  && ((int)GetItemParent(GetItemData(i)) == iItemOldParent) )
  281. {
  282. DeleteItem(i);
  283. if (iItemOldParent < 0)
  284. break;
  285. }
  286. m_mapItemExpanded.RemoveKey(iItem);
  287. if (ItemIsExpanded(iItemParent))
  288. {
  289. fInfo.flags = LVFI_PARAM;
  290. fInfo.lParam = iItemParent;
  291. i = FindItem(&fInfo);
  292. int newI = InsertItem(i < 0 ? GetItemCount() : i + 1, m_listItems.GetItemText(iItem,0));
  293. SetItemData(newI, iItem);
  294. for (int t = 1; t < GetCountColumn(); t++)
  295. SetItemText(newI, t, m_listItems.GetItemText(iItem,t));
  296. }
  297. m_mapParents[iItem] = iItemParent;
  298. if (CWnd* pParent = GetParent())
  299. pParent->SendMessage(LVM_SETPARENT, iItem, iItemParent);
  300. Invalidate();
  301. break;
  302. }
  303. // Insert item
  304. case LVM_INSERTITEMA:
  305. case LVM_INSERTITEMW:
  306. {
  307. int niItem = InsertItem(GetItemCount(),((const LV_ITEM FAR *)lParam)->pszText);
  308. SetItemData(niItem,result);
  309. break;
  310. }
  311. // Set the item text
  312. case LVM_SETITEMA:
  313. case LVM_SETITEMW:
  314. case LVM_SETITEMTEXTA:
  315. case LVM_SETITEMTEXTW:
  316. {
  317. const LV_ITEM FAR * pItem = (const LV_ITEM FAR *)lParam;
  318. LV_FINDINFO fInfo; fInfo.flags = LVFI_PARAM; fInfo.lParam = pItem->iItem;
  319. int sItem = FindItem(&fInfo);
  320. if (sItem >= 0)
  321. SetItemText(sItem, pItem->iSubItem, pItem->pszText);
  322. break;
  323. }
  324. }
  325. m_bInsideCode--;
  326. }
  327. // Function name : CTreeMultiColumnCtrl::ExpandItem
  328. // Description     : Expand nItem if this has childrens
  329. // Return type : void 
  330. // Argument         : int nItem
  331. void CTreeMultiColumnCtrl::ExpandItem(int nItem)
  332. {
  333. m_bInsideCode++;
  334. ASSERT (nItem >= 0);
  335. ASSERT (nItem < m_listItems.GetItemCount());
  336. if (ItemHasChildren(nItem))
  337. if (!ItemIsExpanded(nItem))
  338. {
  339. LV_FINDINFO fInfo; fInfo.flags = LVFI_PARAM; fInfo.lParam = nItem;
  340. int iEnd = FindItem(&fInfo);
  341. if (iEnd >= 0)
  342. {
  343. m_mapItemExpanded[nItem] = TRUE;
  344. int iStart = iEnd;
  345. int iChild = GetFirstItemChild(nItem);
  346. while (iChild >= 0)
  347. {
  348. int newI = InsertItem(++iEnd,m_listItems.GetItemText(iChild,0));
  349. for (int t = 1; t < GetCountColumn(); t++)
  350. SetItemText(newI, t, m_listItems.GetItemText(iChild,t));
  351. SetItemData(newI, iChild);
  352. iChild = GetNextItemChild();
  353. }
  354. RedrawItems(iStart,iStart);
  355. if (CWnd* pParent = GetParent())
  356. pParent->SendMessage(LVM_EXPAND, nItem, 0);
  357. }
  358. }
  359. m_bInsideCode--;
  360. }
  361. // Function name : CTreeMultiColumnCtrl::RecExpandItems
  362. // Description     : Expand all childs of nItem recursively
  363. // Return type : void 
  364. // Argument         : int nItem
  365. void CTreeMultiColumnCtrl::RecExpandItems(int nItem)
  366. {
  367. ExpandItem(nItem);
  368. int iChild = GetFirstItemChild(nItem);
  369. CArray<int,int> arChilds;
  370. while (iChild >= 0)
  371. {
  372. arChilds.Add(iChild);
  373. iChild = GetNextItemChild();
  374. };
  375. for (int k = 0; k < arChilds.GetSize(); k++)
  376. RecExpandItems(arChilds[k]);
  377. }
  378. // Function name : CTreeMultiColumnCtrl::CollapseItem
  379. // Description     : Close item nItem if that has childrens
  380. // Return type : void 
  381. // Argument         : int nItem
  382. void CTreeMultiColumnCtrl::CollapseItem(int nItem)
  383. {
  384. m_bInsideCode++;
  385. ASSERT (nItem >= 0);
  386. ASSERT (nItem < m_listItems.GetItemCount());
  387. if (ItemHasChildren(nItem))
  388. if (ItemIsExpanded(nItem))
  389. {
  390. m_mapItemExpanded.RemoveKey(nItem);
  391. LV_FINDINFO fInfo; fInfo.flags = LVFI_PARAM; fInfo.lParam = nItem;
  392. int iEnd = FindItem(&fInfo);
  393. if (iEnd >=0)
  394. {
  395. int iStart = iEnd;
  396. iEnd++;
  397. while (iEnd < GetItemCount())
  398. {
  399. CArray<int,int> arPathParents;
  400. int nTrueItem = GetItemData(iEnd);
  401. int level = GetItemPath(nTrueItem, arPathParents);
  402. if (level)
  403. {
  404. level--;
  405. while ((level>=0) && (arPathParents[level] != nItem)) level--;
  406. if ( level>=0 )
  407. {
  408. m_mapItemExpanded.RemoveKey(nTrueItem);
  409. DeleteItem(iEnd);
  410. }
  411. else
  412. break;
  413. }
  414. else break;
  415. }
  416. RedrawItems(iStart,iStart);
  417. if (CWnd* pParent = GetParent())
  418. pParent->SendMessage(LVM_COLLAPSE, nItem, 0);
  419. }
  420. }
  421. m_bInsideCode--;
  422. }
  423. // Function name : CTreeMultiColumnCtrl::GetFirstItemChild
  424. // Description     : Return the index of first item child of nItem
  425. // Return type : int 
  426. // Argument         : int nItem
  427. int CTreeMultiColumnCtrl::GetFirstItemChild(int nItem)
  428. {
  429. m_nLastItemFind = -1;
  430. m_nLastItemFound = nItem;
  431. return GetNextItemChild();
  432. }
  433. // Function name : CTreeMultiColumnCtrl::GetNextItemChild
  434. // Description     : Return the index of next item child of nItem
  435. // Return type : int 
  436. int CTreeMultiColumnCtrl::GetNextItemChild()
  437. {
  438. m_nLastItemFind++;
  439. while ((m_nLastItemFind < m_listItems.GetItemCount()) && (GetItemParent(m_nLastItemFind) != m_nLastItemFound))
  440. m_nLastItemFind++;
  441. if (m_nLastItemFind < m_listItems.GetItemCount())
  442. return m_nLastItemFind;
  443. return -1;
  444. }
  445. // Function name : CTreeMultiColumnCtrl::GetItemLevel
  446. // Description     : Return the level of item nItem
  447. // Return type : int 
  448. // Argument         : int nItem
  449. int CTreeMultiColumnCtrl::GetItemLevel(int nItem)
  450. {
  451. int i = nItem;
  452. int result = 0;
  453. while ((i = GetItemParent(i))>=0) result++;
  454. return result;
  455. }
  456. // Function name : CTreeMultiColumnCtrl::IsPtnInSquareRect
  457. // Description     : Return true if item from point has childrens, and point is in 
  458. // square node.
  459. // Return type : BOOL 
  460. // Argument         : CPoint point
  461. BOOL CTreeMultiColumnCtrl::IsPtnInSquareRect(CPoint point)
  462. {
  463. int subItem = -1;
  464. int nItem = HitTestEx(point, subItem);
  465. CRect rect;
  466. if (subItem == m_nTreeColumn)
  467. {
  468. int nTrueItem = GetItemData(nItem);
  469. if (ItemHasChildren(nTrueItem))
  470. if (GetSubItemRect(nItem, subItem, rect))
  471. {
  472. CRect rectSquare(CPoint(rect.left + GetItemLevel(nTrueItem) * dxNode + (dxNode - dxSquareNode) / 2, (rect.top + rect.bottom)/2 - dxSquareNode/2), CSize(dxSquareNode,dxSquareNode));
  473. return rectSquare.PtInRect(point + CPoint(-2,0));
  474. }
  475. }
  476. return FALSE;
  477. }
  478. // Function name : CTreeMultiColumnCtrl::OnLButtonDown
  479. // Description     : If user press the left button of mouse...
  480. // Return type : void 
  481. // Argument         : UINT nFlags
  482. // Argument         : CPoint point
  483. void CTreeMultiColumnCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
  484. {
  485. int subItem = -1;
  486. int nItem = HitTestEx(point, subItem);
  487. if ((nItem >= 0) && (IsPtnInSquareRect(point)))
  488. {
  489. int nTrueItem = GetItemData(nItem);
  490. if (ItemHasChildren(nTrueItem))
  491. if (!ItemIsExpanded(nTrueItem))
  492. ExpandItem(nTrueItem);
  493. else
  494. CollapseItem(nTrueItem);
  495. }
  496. CTsyslistviewex::OnLButtonDown(nFlags, point);
  497. }
  498. // Function name : CTreeMultiColumnCtrl::OnKeyDown
  499. // Description     : If user press the one of following keys...
  500. // Return type : void 
  501. // Argument         : UINT nChar
  502. // Argument         : UINT nRepCnt
  503. // Argument         : UINT nFlags
  504. void CTreeMultiColumnCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
  505. {
  506. m_bInsideCode++;
  507. int iSelected = -1;
  508. while ((iSelected = GetNextItem(iSelected, LVNI_SELECTED))>=0)
  509. {
  510. int nTrueItem = GetItemData(iSelected);
  511. switch (nChar)
  512. {
  513. case VK_ADD:
  514. case VK_RIGHT:
  515. {
  516. ExpandItem(nTrueItem);
  517. break;
  518. }
  519. case VK_SUBTRACT:
  520. case VK_LEFT:
  521. {
  522. CollapseItem(nTrueItem);
  523. break;
  524. }
  525. case VK_MULTIPLY:
  526. {
  527. RecExpandItems(nTrueItem);
  528. break;
  529. }
  530. }
  531. iSelected++;
  532. }
  533. m_bInsideCode--;
  534. if ((nChar != VK_RIGHT) && (nChar != VK_LEFT))
  535. CTsyslistviewex::OnKeyDown(nChar, nRepCnt, nFlags);
  536. }
  537. // Function name : CTreeMultiColumnCtrl::Fill
  538. // Description     : Fill the tree control with items from lpszItems. See tfilltree.h, tfilltree.cpp
  539. // Return type : void 
  540. // Argument         : LPCTSTR lpszItems
  541. void CTreeMultiColumnCtrl::Fill(LPCTSTR lpszItems)
  542. {
  543. STFillTreeMultiColumn s(this, lpszItems);
  544. s.Fill();
  545. }