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

TreeView控件

开发平台:

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::GetPath
  194. // Description     : Insert parents of iItem in arParents.
  195. // Return type : int 
  196. // Argument         : int iItem
  197. // Argument         : CArray<int,int>&
  198. // Argument         :  arParents
  199. int CTreeMultiColumnCtrl::GetItemPath(int iItem, CArray<int, int>& arParents)
  200. {
  201. arParents.RemoveAll();
  202. int i = iItem;
  203. while ((i = GetItemParent(i))>=0)
  204. arParents.InsertAt(0, i);
  205. return arParents.GetSize();
  206. }
  207. // Function name : CTreeMultiColumnCtrl::ItemIsExpanded
  208. // Description     : Return TRUE if Item is Expanded, FALSE if iItem is collapsed
  209. // Return type : BOOL 
  210. // Argument         : int iItem
  211. BOOL CTreeMultiColumnCtrl::ItemIsExpanded(int iItem)
  212. {
  213. BOOL value = FALSE;
  214. if (m_mapItemExpanded.Lookup(iItem, value))
  215. return value;
  216. return FALSE;
  217. }
  218. // Function name : CTreeMultiColumnCtrl::UpdateTree
  219. // Description     : Update the tree control function by message receive by object
  220. // Return type : void 
  221. // Argument         : UINT message
  222. // Argument         : WPARAM wParam
  223. // Argument         : LPARAM lParam
  224. // Argument         : LRESULT result
  225. void CTreeMultiColumnCtrl::UpdateTree(UINT message, WPARAM wParam, LPARAM lParam, LRESULT result)
  226. {
  227. m_bInsideCode++; // Do not process WindowProc...
  228. switch (message)
  229. {
  230. // Set new parent
  231. case LVM_DELETEALLITEMS:
  232. {
  233. m_listItems.DeleteAllItems();
  234. DeleteAllItems();
  235. m_mapItemExpanded.RemoveAll();
  236. m_mapParents.RemoveAll();
  237. break;
  238. }
  239. case LVM_SETPARENT:
  240. {
  241. int iItem = (int)wParam;
  242. int iItemParent = (int)lParam;
  243. int iItemOldParent = GetItemParent(iItem);
  244. LV_FINDINFO fInfo; fInfo.flags = LVFI_PARAM; fInfo.lParam = iItem;
  245. int i = FindItem(&fInfo);
  246. while ( (i < GetItemCount())  && ((int)GetItemParent(GetItemData(i)) == iItemOldParent) )
  247. {
  248. DeleteItem(i);
  249. if (iItemOldParent < 0)
  250. break;
  251. }
  252. m_mapItemExpanded.RemoveKey(iItem);
  253. if (ItemIsExpanded(iItemParent))
  254. {
  255. fInfo.flags = LVFI_PARAM;
  256. fInfo.lParam = iItemParent;
  257. i = FindItem(&fInfo);
  258. int newI = InsertItem(i < 0 ? GetItemCount() : i + 1, m_listItems.GetItemText(iItem,0));
  259. SetItemData(newI, iItem);
  260. for (int t = 1; t < GetCountColumn(); t++)
  261. SetItemText(newI, t, m_listItems.GetItemText(iItem,t));
  262. }
  263. m_mapParents[iItem] = iItemParent;
  264. if (CWnd* pParent = GetParent())
  265. pParent->SendMessage(LVM_SETPARENT, iItem, iItemParent);
  266. Invalidate();
  267. break;
  268. }
  269. // Insert item
  270. case LVM_INSERTITEMA:
  271. case LVM_INSERTITEMW:
  272. {
  273. int niItem = InsertItem(GetItemCount(),((const LV_ITEM FAR *)lParam)->pszText);
  274. SetItemData(niItem,result);
  275. break;
  276. }
  277. // Set the item text
  278. case LVM_SETITEMA:
  279. case LVM_SETITEMW:
  280. case LVM_SETITEMTEXTA:
  281. case LVM_SETITEMTEXTW:
  282. {
  283. const LV_ITEM FAR * pItem = (const LV_ITEM FAR *)lParam;
  284. LV_FINDINFO fInfo; fInfo.flags = LVFI_PARAM; fInfo.lParam = pItem->iItem;
  285. int sItem = FindItem(&fInfo);
  286. if (sItem >= 0)
  287. SetItemText(sItem, pItem->iSubItem, pItem->pszText);
  288. break;
  289. }
  290. }
  291. m_bInsideCode--;
  292. }
  293. // Function name : CTreeMultiColumnCtrl::ExpandItem
  294. // Description     : Expand nItem if this has childrens
  295. // Return type : void 
  296. // Argument         : int nItem
  297. void CTreeMultiColumnCtrl::ExpandItem(int nItem)
  298. {
  299. m_bInsideCode++;
  300. ASSERT (nItem >= 0);
  301. ASSERT (nItem < m_listItems.GetItemCount());
  302. if (ItemHasChildren(nItem))
  303. if (!ItemIsExpanded(nItem))
  304. {
  305. LV_FINDINFO fInfo; fInfo.flags = LVFI_PARAM; fInfo.lParam = nItem;
  306. int iEnd = FindItem(&fInfo);
  307. if (iEnd >= 0)
  308. {
  309. m_mapItemExpanded[nItem] = TRUE;
  310. int iStart = iEnd;
  311. int iChild = GetFirstItemChild(nItem);
  312. while (iChild >= 0)
  313. {
  314. int newI = InsertItem(++iEnd,m_listItems.GetItemText(iChild,0));
  315. for (int t = 1; t < GetCountColumn(); t++)
  316. SetItemText(newI, t, m_listItems.GetItemText(iChild,t));
  317. SetItemData(newI, iChild);
  318. iChild = GetNextItemChild();
  319. }
  320. RedrawItems(iStart,iStart);
  321. if (CWnd* pParent = GetParent())
  322. pParent->SendMessage(LVM_EXPAND, nItem, 0);
  323. }
  324. }
  325. m_bInsideCode--;
  326. }
  327. // Function name : CTreeMultiColumnCtrl::RecExpandItems
  328. // Description     : Expand all childs of nItem recursively
  329. // Return type : void 
  330. // Argument         : int nItem
  331. void CTreeMultiColumnCtrl::RecExpandItems(int nItem)
  332. {
  333. ExpandItem(nItem);
  334. int iChild = GetFirstItemChild(nItem);
  335. CArray<int,int> arChilds;
  336. while (iChild >= 0)
  337. {
  338. arChilds.Add(iChild);
  339. iChild = GetNextItemChild();
  340. };
  341. for (int k = 0; k < arChilds.GetSize(); k++)
  342. RecExpandItems(arChilds[k]);
  343. }
  344. // Function name : CTreeMultiColumnCtrl::CollapseItem
  345. // Description     : Close item nItem if that has childrens
  346. // Return type : void 
  347. // Argument         : int nItem
  348. void CTreeMultiColumnCtrl::CollapseItem(int nItem)
  349. {
  350. m_bInsideCode++;
  351. ASSERT (nItem >= 0);
  352. ASSERT (nItem < m_listItems.GetItemCount());
  353. if (ItemHasChildren(nItem))
  354. if (ItemIsExpanded(nItem))
  355. {
  356. m_mapItemExpanded.RemoveKey(nItem);
  357. LV_FINDINFO fInfo; fInfo.flags = LVFI_PARAM; fInfo.lParam = nItem;
  358. int iEnd = FindItem(&fInfo);
  359. if (iEnd >=0)
  360. {
  361. int iStart = iEnd;
  362. iEnd++;
  363. while (iEnd < GetItemCount())
  364. {
  365. CArray<int,int> arPathParents;
  366. int nTrueItem = GetItemData(iEnd);
  367. int level = GetItemPath(nTrueItem, arPathParents);
  368. if (level)
  369. {
  370. level--;
  371. while ((level>=0) && (arPathParents[level] != nItem)) level--;
  372. if ( level>=0 )
  373. {
  374. m_mapItemExpanded.RemoveKey(nTrueItem);
  375. DeleteItem(iEnd);
  376. }
  377. else
  378. break;
  379. }
  380. else break;
  381. }
  382. RedrawItems(iStart,iStart);
  383. if (CWnd* pParent = GetParent())
  384. pParent->SendMessage(LVM_COLLAPSE, nItem, 0);
  385. }
  386. }
  387. m_bInsideCode--;
  388. }
  389. // Function name : CTreeMultiColumnCtrl::GetItemLevel
  390. // Description     : Return the level of item nItem
  391. // Return type : int 
  392. // Argument         : int nItem
  393. int CTreeMultiColumnCtrl::GetItemLevel(int nItem)
  394. {
  395. int i = nItem;
  396. int result = 0;
  397. while ((i = GetItemParent(i))>=0) result++;
  398. return result;
  399. }
  400. // Function name : CTreeMultiColumnCtrl::IsPtnInSquareRect
  401. // Description     : Return true if item from point has childrens, and point is in 
  402. // square node.
  403. // Return type : BOOL 
  404. // Argument         : CPoint point
  405. BOOL CTreeMultiColumnCtrl::IsPtnInSquareRect(CPoint point)
  406. {
  407. int subItem = -1;
  408. int nItem = HitTestEx(point, subItem);
  409. CRect rect;
  410. if (subItem == m_nTreeColumn)
  411. {
  412. int nTrueItem = GetItemData(nItem);
  413. if (ItemHasChildren(nTrueItem))
  414. if (GetSubItemRect(nItem, subItem, rect))
  415. {
  416. CRect rectSquare(CPoint(rect.left + GetItemLevel(nTrueItem) * dxNode + (dxNode - dxSquareNode) / 2, (rect.top + rect.bottom)/2 - dxSquareNode/2), CSize(dxSquareNode,dxSquareNode));
  417. return rectSquare.PtInRect(point + CPoint(-2,0));
  418. }
  419. }
  420. return FALSE;
  421. }
  422. // Function name : CTreeMultiColumnCtrl::OnLButtonDown
  423. // Description     : If user press the left button of mouse...
  424. // Return type : void 
  425. // Argument         : UINT nFlags
  426. // Argument         : CPoint point
  427. void CTreeMultiColumnCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
  428. {
  429. int subItem = -1;
  430. int nItem = HitTestEx(point, subItem);
  431. if ((nItem >= 0) && (IsPtnInSquareRect(point)))
  432. {
  433. int nTrueItem = GetItemData(nItem);
  434. if (ItemHasChildren(nTrueItem))
  435. if (!ItemIsExpanded(nTrueItem))
  436. ExpandItem(nTrueItem);
  437. else
  438. CollapseItem(nTrueItem);
  439. }
  440. CTsyslistviewex::OnLButtonDown(nFlags, point);
  441. }
  442. // Function name : CTreeMultiColumnCtrl::OnKeyDown
  443. // Description     : If user press the one of following keys...
  444. // Return type : void 
  445. // Argument         : UINT nChar
  446. // Argument         : UINT nRepCnt
  447. // Argument         : UINT nFlags
  448. void CTreeMultiColumnCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
  449. {
  450. m_bInsideCode++;
  451. int iSelected = -1;
  452. while ((iSelected = GetNextItem(iSelected, LVNI_SELECTED))>=0)
  453. {
  454. int nTrueItem = GetItemData(iSelected);
  455. switch (nChar)
  456. {
  457. case VK_ADD:
  458. case VK_RIGHT:
  459. {
  460. ExpandItem(nTrueItem);
  461. break;
  462. }
  463. case VK_SUBTRACT:
  464. case VK_LEFT:
  465. {
  466. CollapseItem(nTrueItem);
  467. break;
  468. }
  469. case VK_MULTIPLY:
  470. {
  471. RecExpandItems(nTrueItem);
  472. break;
  473. }
  474. }
  475. iSelected++;
  476. }
  477. m_bInsideCode--;
  478. if ((nChar != VK_RIGHT) && (nChar != VK_LEFT))
  479. CTsyslistviewex::OnKeyDown(nChar, nRepCnt, nFlags);
  480. }
  481. // Function name : CTreeMultiColumnCtrl::Fill
  482. // Description     : Fill the tree control with items from lpszItems. See tfilltree.h, tfilltree.cpp
  483. // Return type : void 
  484. // Argument         : LPCTSTR lpszItems
  485. void CTreeMultiColumnCtrl::Fill(LPCTSTR lpszItems)
  486. {
  487. STFillTreeMultiColumn s(this, lpszItems);
  488. s.Fill();
  489. }
  490. // Function name : CTreeMultiColumnCtrl::Delete
  491. // Description     : 
  492. // Return type : BOOL 
  493. // Argument         : int nItem
  494. // Argument         : BOOL bRecurse
  495. BOOL CTreeMultiColumnCtrl::Delete(int nItem)
  496. {
  497. int nTrueItem = GetItemData(nItem);
  498. if (!ItemHasChildren(nTrueItem))
  499. {
  500. m_bInsideCode++;
  501. DeleteItem(nItem);
  502. m_mapItemDeleted[nTrueItem] = TRUE;
  503. int lItem = max(0, nItem - 1);
  504. RedrawItems(lItem, lItem);
  505. m_bInsideCode--;
  506. return TRUE;
  507. }
  508. return FALSE;
  509. }
  510. // Function name : CTreeMultiColumnCtrl::IsDeleted
  511. // Description     : 
  512. // Return type : BOOL 
  513. // Argument         : int nItem
  514. BOOL CTreeMultiColumnCtrl::IsDeleted(int nItem)
  515. {
  516. BOOL bValue = FALSE;
  517. m_mapItemDeleted.Lookup(nItem, bValue);
  518. return bValue;
  519. }
  520. // Function name : CTreeMultiColumnCtrl::ItemHasChildren
  521. // Description     : Return TRUE if item iItem has at least one children
  522. // Return type : BOOL 
  523. // Argument         : int iItem
  524. BOOL CTreeMultiColumnCtrl::ItemHasChildren(int iItem)
  525. {
  526. int key = -1;
  527. int value = -1;
  528. POSITION position = m_mapParents.GetStartPosition();
  529. while (position)
  530. {
  531. m_mapParents.GetNextAssoc(position, key, value);
  532. if (!IsDeleted(value))
  533. if (!IsDeleted(key))
  534. if (value == iItem)
  535. return TRUE;
  536. }
  537. return FALSE;
  538. }
  539. // Function name : CTreeMultiColumnCtrl::GetFirstItemChild
  540. // Description     : Return the index of first item child of nItem
  541. // Return type : int 
  542. // Argument         : int nItem
  543. int CTreeMultiColumnCtrl::GetFirstItemChild(int nItem)
  544. {
  545. m_nLastItemFind = -1;
  546. m_nLastItemFound = nItem;
  547. return GetNextItemChild();
  548. }
  549. // Function name : CTreeMultiColumnCtrl::GetNextItemChild
  550. // Description     : Return the index of next item child of nItem
  551. // Return type : int 
  552. int CTreeMultiColumnCtrl::GetNextItemChild()
  553. {
  554. m_nLastItemFind++;
  555. while (IsDeleted(m_nLastItemFind) || ((m_nLastItemFind < m_listItems.GetItemCount()) && (GetItemParent(m_nLastItemFind) != m_nLastItemFound)))
  556. m_nLastItemFind++;
  557. if (m_nLastItemFind < m_listItems.GetItemCount())
  558. return m_nLastItemFind;
  559. return -1;
  560. }
  561. // Function name : CTreeMultiColumnCtrl::IsLastChildren
  562. // Description     : Check if iItem is last children
  563. // Return type : BOOL 
  564. // Argument         : int iItem
  565. BOOL CTreeMultiColumnCtrl::IsLastChildren(int iItem)
  566. {
  567. int iParent = GetItemParent(iItem);
  568. int cItem = m_listItems.GetItemCount();
  569. int i = iItem + 1;
  570. while (i < cItem)
  571. {
  572. if (!IsDeleted(i))
  573. if (!IsDeleted(GetItemParent(i)))
  574. if (GetItemParent(i) == iParent)
  575. return FALSE;
  576. i++;
  577. }
  578. return TRUE;
  579. }
  580. //-------------------------------------------------------------------------------//