supergridctrl.cpp
上传用户:dengkfang
上传日期:2008-12-30
资源大小:5233k
文件大小:64k
源码类别:

CA认证

开发平台:

Visual C++

  1. // SuperGridCtrl.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "SuperGridCtrl.h"
  5. #ifdef _DEBUG
  6. #define new DEBUG_NEW
  7. #undef THIS_FILE
  8. static char THIS_FILE[] = __FILE__;
  9. #endif
  10. /*
  11.     SuperGrid, YALC (yet another listview control) 
  12. Written by me(Allan Nielsen), that is .. if the code works :)
  13. mailto:allan@object-oriented.com
  14. Copyright (c) 1999.
  15. If you find bugs, please notify me and I'll contact the author who wrote the darn thing :)
  16.     You may use it, abuse it, redistribute it, in any way you desire, but
  17. if you choose to use this control in any commercial or non commercial application then please 
  18. send me an email letting me know, makes me :) . 
  19. HISTORY 
  20. what's new since last update: 
  21. 4 dec. 1998.
  22. - MeasureItem now uses current font
  23. - Combobox support in CItemInfo
  24.   see the ShowList in MySuperGrid.h/cpp, PreTranslateMessage functions
  25.   and the file ComboInListView.cpp/h
  26.                 - function to indicate the precens of a combobox it draws a down arrow ..see DrawComboBox
  27.   the idea came from Robert Bouwens. :)
  28. - in file TestTreeDlg.cpp:  due to the MeasureItem message-reflection
  29.   the listctrl is now created in the CDialog::OnCreate function and later on resized
  30. - LVIS_DROPHILITED support when dragging items
  31. - Support for LVS_EX_CHECKBOXES   
  32. - Added some examples on how to print preview selected item(or at least to get some information from of the grid)
  33.   the sample is in the CTreeList.h/cpp which is derived from CSuperGridCtrl it shows you
  34.   how to initalize the grid, sort items, search for items and subitems, select and delete thems
  35. - added virtual GetIcon function to set your default icon handler for a listview index.
  36. - added virtual GetCellRGB() to set the color for current selected cell
  37. - renamed CTreeNode to CTreeItem, sorry ;-(
  38. - the nested class CTreeItem has been stripped down to nothing but simple (struct)data members
  39.   only servering as a linked list of lists now :-)
  40. - well.. moved all the importent stuff from CTreeItem to CSuperGridCtrl e.g
  41.   all operations on a CTreeItem now resides in the CSuperGridCtrl, much more OO-like ;-)
  42. - added Quicksort function
  43. - got rid of TheOpenCloseThing function.
  44. - added virtual function OnUpdateListViewItem..called when ever an Item is about to be updated
  45. - added virtual function OnControlLButtonDown...called when ever LButtondown in a cell
  46. - added virtual function CreateDragImageEx...
  47. 11 jan 1999:
  48. - added SetFocus in OnDblclk and in OnLButtonDown, big thank you to Dieter Gollwitzer 
  49. - fixed a minor hittest error in the HitTestOnSign(), again thanks to Dieter Gollwitzer 
  50. 16 jan 1999: 
  51. - added virtual OnItemExpanding(....
  52. - added virtual OnItemExpanded(...
  53. - added virtual OnCollapsing(....
  54. - added virtual OnItemCollapsed(...
  55. - added virtual OnDeleteItem(....
  56. - added virtual OnVKMultiply(...
  57. - added virtual OnVkSubTract(..
  58. - added virtual OnVKAdd(....
  59. - added SetChildrenFlag();
  60. 1 feb 1999:
  61. - CItemInfo now supports individual cell-color
  62. - fixed some bugs in regards to listdata associated with in each cell
  63. - added virtual BOOL OnVkReturn(........
  64. - added virtual BOOL OnItemLButtonDown(.....
  65. 4 mai 1999  - moved to Switzerland to work as a systemdeveloper for 2-3 years :).
  66. - new email :)
  67. - added new class for encapsulating drawing + - buttons.
  68.    22.june 1999 - Added GetCount()
  69. - removed support for VC++ 5.0.
  70. - added GetTreeItem(.....) 
  71. - GetSelectedItem(.....)
  72. - Howto disable Drag/drop in CTreeList
  73. - level 4 compiled
  74. - Clean up some redudant code crap
  75. 30.june 99  - fixed minor error in DrawItem, a drawing error occurred when 1.st column was hidden, 
  76.   it was previous fixed, but some how it was introduced again :).
  77. 9. juli 99  - CRAIG SCHMIDT "the beachboy":)
  78.   Craig did the implementation of the Multiple Root request
  79.   his email are "craig_a_schmidt@yahoo.com" if you have any Questions
  80.   in regards to multiple roots implementation, although I think I can help too :).
  81.   he added the following functions :
  82.   - CTreeItem*  InsertRootItem(.....
  83.   - void DeleteRootItem(....
  84.   - BOOL IsRoot(...
  85.   - CTreeItem* GetRootItem(..
  86.   - int GetRootIndex(..
  87.   - int GetRootCount(...
  88.   - and a member variable, CPtrList m_RootItems which of course are a collection of ..ta da RootItems a.k.a CTreeItem.
  89.   see the file CTreeList.cpp for usage of the InsertRootItem.
  90.     10.juli 99    added simple wrappers for the rootitems collection
  91.   - Added GetRootHeadPosition(...)
  92.   - Added GetRootTailPosition();
  93.   - Added CTreeItem* GetNextRoot(...
  94.   - Added CTreeItem* GetPrevRoot(...
  95. 12. juli 99  - fixed minor error in CreateDragImageEx, an error occurred when 1st column was hidden and a drag operation was initiated
  96. 13. juli 99  - Added void DeleteAll()...deletes all items in the grid, uhh
  97.  - Removed GetNextSiblingItem(...), GetPrevSiblingItem(...) due to support for multiple roots. 
  98.  - Added CTreeItem *GetNext(...) and CTreeItem* GetPrev(..) due to support for multiple roots.
  99. 14. juli 99  - Fixed a memory leak in CTreeList::HowToInsertItemsAfterTheGridHasBeenInitialized....
  100. WHAT'S UP :
  101. - Vacation
  102. - ATL VERSION COMMING UP.
  103. - Better documentation :)
  104. - Peace on earth.
  105. - service pack 4 for VC++ 6.0 :=|
  106. - Windows 3000 :)
  107. */
  108. /////////////////////////////////////////////////////////////////////////////
  109. // CSuperGridCtrl
  110. CSuperGridCtrl::CSuperGridCtrl()
  111. {
  112. m_cxImage = m_cyImage = 16;
  113. m_bIsDragging = m_CurSubItem = 0;
  114.     m_nDragTarget=m_nDragItem = -1;
  115. m_psTreeLine.CreatePen(PS_SOLID, 1, RGB(192,192,192));
  116. m_psRectangle.CreatePen(PS_SOLID, 1, RGB(198,198,198));
  117. m_psPlusMinus.CreatePen(PS_SOLID, 1, RGB(0,0,0));
  118. m_brushErase.CreateSolidBrush(RGB(255,255,255));
  119. m_himl = NULL;
  120. }
  121. CSuperGridCtrl::~CSuperGridCtrl()
  122. {
  123. m_psPlusMinus.DeleteObject();
  124. m_psRectangle.DeleteObject();
  125. m_psTreeLine.DeleteObject();
  126. m_brushErase.DeleteObject();
  127. while(m_RootItems.GetCount())
  128. {
  129. CTreeItem * root = (CTreeItem*)m_RootItems.RemoveHead();
  130. if(root!=NULL && GetData(root) != NULL)
  131. delete GetData(root);
  132. delete root;
  133. }
  134. m_RootItems.RemoveAll();
  135. }
  136. BEGIN_MESSAGE_MAP(CSuperGridCtrl, CListCtrl)
  137. //{{AFX_MSG_MAP(CSuperGridCtrl)
  138. // ON_NOTIFY_REFLECT(NM_DBLCLK, OnDblclk)
  139. // ON_NOTIFY_REFLECT(LVN_ENDLABELEDIT, OnEndlabeledit)
  140. ON_WM_CREATE()
  141. ON_WM_HSCROLL()
  142. ON_WM_LBUTTONDOWN()
  143. ON_WM_MOUSEMOVE()
  144. ON_WM_TIMER()
  145. ON_WM_VSCROLL()
  146. ON_WM_LBUTTONUP()
  147. // ON_NOTIFY_REFLECT(LVN_KEYDOWN, OnKeydown)
  148. // ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBegindrag)
  149. ON_WM_MEASUREITEM_REFLECT()
  150. ON_WM_DRAWITEM_REFLECT()
  151. ON_WM_SYSCOLORCHANGE()
  152. // ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
  153. //}}AFX_MSG_MAP
  154. END_MESSAGE_MAP()
  155. /////////////////////////////////////////////////////////////////////////////
  156. // CSuperGridCtrl message handlers
  157. BOOL CSuperGridCtrl::PreCreateWindow(CREATESTRUCT& cs) 
  158. {
  159. cs.style |= LVS_REPORT | LVS_SINGLESEL | LVS_SHAREIMAGELISTS | LVS_OWNERDRAWFIXED | LVS_SHOWSELALWAYS;
  160. // cs.dwExStyle |= LVS_EX_GRIDLINES;
  161. return CListCtrl::PreCreateWindow(cs);
  162. }
  163. int CSuperGridCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  164. {
  165. if (CListCtrl::OnCreate(lpCreateStruct) == -1)
  166. return -1;
  167. return 0;
  168. }
  169. #define OFFSET_FIRST 2 
  170. #define OFFSET_OTHER 6
  171. void CSuperGridCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
  172. {
  173. if (lpDrawItemStruct->CtlType != ODT_LISTVIEW)
  174.         return;
  175. if(lpDrawItemStruct->itemAction == ODA_DRAWENTIRE)
  176. {
  177. if(m_himl==NULL)
  178. {
  179. m_himl = (HIMAGELIST)::SendMessage(m_hWnd, LVM_GETIMAGELIST, (WPARAM)(int)(LVSIL_SMALL), 0L);
  180. if(m_himl==NULL)
  181. return;
  182. }
  183. LV_ITEM lvi;
  184. static _TCHAR szBuff[MAX_PATH];
  185. LPCTSTR pszText;
  186. int nItem = lpDrawItemStruct->itemID;
  187. CRect rcItem(lpDrawItemStruct->rcItem);
  188. lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT | LVIF_PARAM; 
  189. lvi.iItem = nItem;
  190. lvi.iSubItem =0;
  191. lvi.pszText = szBuff;
  192. lvi.cchTextMax = sizeof(szBuff);
  193. lvi.stateMask = 0xFFFF;
  194. GetItem(&lvi);
  195. CTreeItem *pSelItem = (CTreeItem*)lpDrawItemStruct->itemData;
  196. CRect rcLabel;
  197. GetItemRect(nItem, rcLabel, LVIR_LABEL);
  198. CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
  199. ASSERT(pDC);
  200. CRect rcClipBox;
  201. pDC->GetClipBox(rcClipBox);
  202. COLORREF crBackground, crText;
  203. if (lpDrawItemStruct->itemState & ODS_SELECTED)
  204. {
  205. // Set the text background and foreground colors
  206. crBackground = GetSysColor (COLOR_HIGHLIGHT);
  207. crText = GetSysColor (COLOR_HIGHLIGHTTEXT);
  208. }
  209. else
  210. {
  211. // Set the text background and foreground colors to the standard window
  212. // colors
  213. crBackground = GetSysColor (COLOR_WINDOW);
  214. crText = GetSysColor (COLOR_WINDOWTEXT);
  215. }
  216. //Get current Icon, you have overridden this I hope :-)
  217. /* int iImage = GetIcon(pSelItem);
  218. // iImage =  4;
  219. if(iImage!=-1)
  220. {
  221. if(lvi.iImage!=iImage)
  222. {
  223. LV_ITEM lvItem;
  224. lvItem.mask =  LVIF_IMAGE;
  225. lvItem.iImage = iImage;
  226. lvItem.iItem = nItem;
  227. lvItem.iSubItem = 0;
  228. SetItem(&lvItem);
  229. lvi.iImage = iImage; 
  230. }
  231. }*/
  232. CRect rc;
  233. GetItemRect(nItem, rc, LVIR_BOUNDS);
  234. CRect rcIcon;
  235. GetItemRect(nItem, rcIcon, LVIR_ICON);
  236. //Draw Current image
  237. int nOffset = (rcItem.Height() - m_cyImage)/2;
  238. int nY = rcItem.bottom - m_cyImage - nOffset;
  239. int nWidth = m_cxImage;//def icon size
  240. //do not draw icon out side 1.st column.
  241. int iTryIndent = GetIndent(pSelItem) * m_cxImage + m_cxImage;
  242. if(rc.left + iTryIndent  > GetColumnWidth(0)-2/*looks better -2*/)
  243. nWidth = (rc.left + iTryIndent) - GetColumnWidth(0);
  244. UINT uiFlags = ILD_TRANSPARENT;
  245. if( GetItemState(nItem, LVIF_STATE) & LVIS_DROPHILITED)//if dragging show a SelectDropTarget alike effect :)
  246. uiFlags |= ILD_BLEND50;
  247. if((nWidth=m_cxImage-nWidth) >-1)//calc width of icon
  248. {
  249. ImageList_DrawEx(m_himl, lvi.iImage, pDC->m_hDC,  
  250.  rc.left + (GetIndent(pSelItem) * m_cxImage), 
  251.  nY, 
  252.  nWidth,
  253.  m_cyImage,
  254.  CLR_DEFAULT, 
  255.  CLR_DEFAULT, 
  256.  uiFlags);
  257. DrawTreeItem(pDC, pSelItem, nItem, rc);
  258. }
  259. //Draw selection bar (erase old selection too)
  260. pDC->SetBkColor(crBackground);
  261. CRect rcClip = lpDrawItemStruct->rcItem;
  262. rcClip.left += GetIndent(pSelItem) * m_cxImage + m_cxImage + 2;
  263. if(rcClip.left > GetColumnWidth(0))
  264. rcClip.left = GetColumnWidth(0);
  265. //fill background color
  266. ExtTextOut(pDC->GetSafeHdc(), 0, 0, ETO_OPAQUE, rcClip, NULL, 0, NULL);
  267. //draw color in first col if any
  268. rcClip.right = rcLabel.right;
  269. CItemInfo *pItemInfo = GetData(pSelItem);
  270. COLORREF clf = pItemInfo->GetItemClr();
  271. if(clf!=-1)
  272. {
  273. CBrush br(clf);
  274. pDC->FillRect(rcClip, &br);
  275. }
  276. //draw selection rect in 1.st col if selected
  277. if ((lpDrawItemStruct->itemState & ODS_SELECTED) && (m_CurSubItem==0))
  278. {
  279. CBrush br(GetCellRGB());
  280. pDC->FillRect(rcClip,&br);
  281. pDC->DrawFocusRect(rcClip);
  282. }
  283. //if checkbox style
  284. UINT nStateImageMask = lvi.state & LVIS_STATEIMAGEMASK;
  285. if (nStateImageMask)
  286. {
  287. int nImage = (nStateImageMask>>12) - 1;
  288. CImageList *pImageList = GetImageList(LVSIL_STATE);
  289. if (pImageList)
  290. {
  291. int cxIcon,cyIcon=0;
  292. ImageList_GetIconSize(pImageList->m_hImageList, &cxIcon, &cyIcon);
  293. if(rc.left + (GetIndent(pSelItem) * m_cxImage) + m_cxImage + cxIcon < GetColumnWidth(0))
  294. pImageList->Draw(pDC, nImage,CPoint(rc.left + (GetIndent(pSelItem) * m_cxImage) + cxIcon, nY), ILD_TRANSPARENT);
  295. }
  296. }
  297. //draw 1. item
  298. GetItemRect(nItem, rcItem, LVIR_LABEL);
  299. pszText = MakeShortString(pDC, szBuff, rcItem.right - rcItem.left, 2*OFFSET_FIRST);
  300. rcLabel = rcItem;
  301. rcLabel.left+=OFFSET_FIRST;
  302. rcLabel.right-=OFFSET_FIRST;
  303. pDC->SetBkColor (crBackground);
  304. pDC->SetTextColor (crText);
  305. pDC->DrawText(pszText,-1, rcLabel,DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER | DT_EXTERNALLEADING);
  306. //draw subitems..
  307. LV_COLUMN lvc;
  308. lvc.mask = LVCF_FMT | LVCF_WIDTH;
  309. for(int nColumn=1; GetColumn(nColumn, &lvc); nColumn++)
  310. {
  311. rcItem.left=rcItem.right;
  312. rcItem.right+=lvc.cx;
  313. if (rcItem.left < rcClipBox.right && rcItem.right > rcClipBox.left && rcItem.right > rcItem.left)
  314. {
  315. //support for colors in each cell
  316. COLORREF clf = pItemInfo->GetBkColor(nColumn-1);
  317. if(clf!=-1)
  318. {
  319. CBrush br(clf);
  320. pDC->FillRect(rcItem, &br);
  321. }
  322. int nRetLen = GetItemText(nItem, nColumn, szBuff, sizeof(szBuff));
  323. if(nRetLen==0)
  324. pszText=NULL;
  325. else
  326. pszText=MakeShortString(pDC,szBuff,rcItem.right-rcItem.left,2*OFFSET_OTHER);
  327. UINT nJustify=DT_LEFT;
  328. if(pszText==szBuff)
  329. {
  330. switch(lvc.fmt & LVCFMT_JUSTIFYMASK)
  331. {
  332. case LVCFMT_RIGHT:
  333. nJustify=DT_RIGHT;
  334. break;
  335. case LVCFMT_CENTER:
  336. nJustify=DT_CENTER;
  337. break;
  338. default:
  339. break;
  340. }
  341. }
  342. rcLabel=rcItem;
  343. rcLabel.left+=OFFSET_OTHER;
  344. rcLabel.right-=OFFSET_OTHER;
  345. if (lpDrawItemStruct->itemState & ODS_SELECTED && !m_bIsDragging)
  346. DrawFocusCell(pDC, lpDrawItemStruct->itemID, nColumn);
  347. if(pszText!=NULL)
  348. pDC->DrawText(pszText,-1,rcLabel, nJustify | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER | DT_EXTERNALLEADING);
  349. }//if
  350. //draw down arrow if combobox regardless of rcClipBox rgn
  351. if (lpDrawItemStruct->itemState & ODS_SELECTED)
  352. DrawComboBox(pDC, pSelItem, nItem, nColumn);
  353. }//for
  354. }//ODA_DRAWENTIRE
  355. }
  356. void CSuperGridCtrl::DrawComboBox(CDC* pDC, CTreeItem *pSelItem, int nItem, int nColumn)
  357. {
  358. CItemInfo* pInfo = GetData(pSelItem);
  359. CItemInfo::CONTROLTYPE ctrlType;
  360. if(pInfo->GetControlType(nColumn-1, ctrlType))
  361. {
  362. if(ctrlType == pInfo->CONTROLTYPE::combobox) 
  363. {
  364. CRect rect;
  365. GetSubItemRect(nItem, nColumn, LVIR_BOUNDS, rect);
  366. rect.left=rect.right - GetSystemMetrics(SM_CYVSCROLL);
  367. pDC->DrawFrameControl(rect, DFC_SCROLL, DFCS_SCROLLDOWN);
  368. }
  369. }
  370. }
  371. //this piece of code is borrowed from the wndproc.c file in the odlistvw.exe example from MSDN and was converted to mfc-style
  372. void CSuperGridCtrl::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
  373. {
  374.     if (lpMeasureItemStruct->CtlType != ODT_LISTVIEW)
  375.         return;
  376. TEXTMETRIC tm;
  377. CClientDC dc(this);
  378. CFont* pFont = GetFont();
  379. CFont* pOldFont = dc.SelectObject(pFont);
  380. dc.GetTextMetrics(&tm);
  381. int nItemHeight = tm.tmHeight + tm.tmExternalLeading;
  382. lpMeasureItemStruct->itemHeight = nItemHeight + 4; //or should I go for max(nItemheight+4, m_cxImage+2);
  383. dc.SelectObject(pOldFont);
  384. }
  385. //the basic rutine making the ... thing snatched it from some tedious code example some where in MSDN call odlistvw.exe
  386. LPCTSTR CSuperGridCtrl::MakeShortString(CDC* pDC, LPCTSTR lpszLong, int nColumnLen, int nOffset)
  387. {
  388. static const _TCHAR szThreeDots[]=_T("...");
  389. int nStringLen=lstrlen(lpszLong);
  390. if(nStringLen==0 || pDC->GetTextExtent(lpszLong,nStringLen).cx + nOffset < nColumnLen)
  391. return(lpszLong);
  392. static _TCHAR szShort[MAX_PATH];
  393. lstrcpy(szShort,lpszLong);
  394. int nAddLen = pDC->GetTextExtent(szThreeDots,sizeof(szThreeDots)).cx;
  395. for(int i=nStringLen-1; i > 0; i--)
  396. {
  397. szShort[i]=0;
  398. if(pDC->GetTextExtent(szShort,i).cx + nOffset + nAddLen < nColumnLen)
  399. break;
  400. }
  401. lstrcat(szShort,szThreeDots);
  402. return(szShort);
  403. }
  404. /*void CSuperGridCtrl::OnKeydown(NMHDR* pNMHDR, LRESULT* pResult) 
  405. {
  406. LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR;
  407. switch(pLVKeyDow->wVKey)
  408. {
  409. case VK_SPACE: 
  410. {
  411. if(GetExtendedStyle() & LVS_EX_CHECKBOXES)
  412. {
  413. int nIndex = GetSelectedItem();
  414. if(nIndex !=-1)
  415. {
  416. CTreeItem* pItem = GetTreeItem(nIndex);
  417. if(pItem!=NULL)
  418. {
  419. CItemInfo *pInfo = GetData(pItem);
  420. pInfo->SetCheck(!pInfo->GetCheck());
  421. }
  422. }
  423. }
  424. }break;
  425. case VK_DELETE: 
  426. {
  427. int nItem = GetSelectedItem();
  428. if(nItem!=-1)
  429. {
  430. CTreeItem* pSelItem = GetTreeItem(nItem);
  431. if(pSelItem != NULL)
  432. {
  433. if(OnDeleteItem(pSelItem, nItem))
  434. DeleteItemEx(pSelItem, nItem);
  435. }
  436. }
  437. } break;
  438. case VK_MULTIPLY:
  439. {  
  440. int nIndex = GetSelectedItem();
  441. if(nIndex != -1)
  442. {
  443. CWaitCursor wait;
  444. SetRedraw(0);
  445. CTreeItem *pParent = GetTreeItem(nIndex);
  446. int nScroll=0;
  447. if(OnVKMultiply(pParent, nIndex))
  448. {
  449. ExpandAll(pParent, nScroll);
  450. }
  451. SetRedraw(1);
  452. RedrawItems(nIndex, nScroll);
  453. EnsureVisible(nScroll, TRUE);
  454.  }
  455.  }break;
  456. case VK_ADD:
  457. {
  458. int nIndex = GetSelectedItem();
  459. if(nIndex!=-1)
  460. {
  461. CWaitCursor wait;
  462. CTreeItem *pSelItem = GetTreeItem(nIndex);
  463. int nScrollIndex = 0;
  464. if(OnVKAdd(pSelItem, nIndex))
  465. {
  466.  nScrollIndex = Expand(pSelItem, nIndex);
  467. }
  468. CRect rc;
  469. GetItemRect(nIndex, rc, LVIR_BOUNDS);
  470. InvalidateRect(rc);
  471. UpdateWindow();
  472. EnsureVisible(nScrollIndex, 1);
  473. }
  474. }break;
  475. case VK_SUBTRACT:
  476. {
  477. int nIndex = GetSelectedItem();
  478. if(nIndex!=-1)
  479. {
  480. CWaitCursor wait;
  481. CTreeItem *pSelItem = GetTreeItem(nIndex);
  482. if(OnVkSubTract(pSelItem, nIndex))
  483. {
  484. Collapse(pSelItem);
  485. }
  486. CRect rc;
  487. GetItemRect(nIndex, rc, LVIR_BOUNDS);
  488. InvalidateRect(rc);
  489. UpdateWindow();
  490. }
  491. }break;
  492. default :break;
  493. }
  494. *pResult = 0;
  495. }*/
  496. BOOL CSuperGridCtrl::HitTestOnSign(CPoint point, LVHITTESTINFO& ht)
  497. {
  498. ht.pt = point;
  499. // Test which subitem was clicked.
  500. SubItemHitTest(&ht);
  501. if(ht.iItem!=-1)
  502. {
  503. //first hittest on checkbox
  504. BOOL bHit = FALSE;
  505. if(GetExtendedStyle() & LVS_EX_CHECKBOXES)
  506. {
  507. if (ht.flags == LVHT_ONITEM && (GetStyle() & LVS_OWNERDRAWFIXED))//isn't this allways ownerdrawfixed :-)
  508. {
  509. CRect rcIcon,rcLabel;
  510. GetItemRect(ht.iItem, rcIcon, LVIR_ICON);//has to be between these two ....right :)
  511. GetItemRect(ht.iItem, rcLabel, LVIR_LABEL);
  512. // check if hit was on a state icon 
  513. if (point.x > rcIcon.left && point.x < rcLabel.left)
  514. bHit = TRUE;
  515. }
  516. else if (ht.flags & LVHT_ONITEMSTATEICON)
  517. bHit = TRUE;
  518. }
  519. CTreeItem* pItem = GetTreeItem(ht.iItem);
  520. if(pItem!=NULL)
  521. {
  522. if(bHit)//if checkbox
  523. {
  524. //yes I know..have to maintain to sets of checkstates here...
  525. //one for listview statemask and one for CTreeItem..but its located here so no harm done
  526. SetCheck(ht.iItem,!GetCheck(ht.iItem));
  527. CItemInfo *pInfo = GetData(pItem);
  528. pInfo->SetCheck(!pInfo->GetCheck());
  529. }
  530. //if haschildren and clicked on + or - then expand/collapse
  531. if(ItemHasChildren(pItem))
  532. {
  533. //hittest on the plus/sign "button" 
  534. CRect rcBounds;
  535. GetItemRect(ht.iItem, rcBounds, LVIR_BOUNDS);
  536. CRectangle rect(this, NULL, GetIndent(pItem), rcBounds);
  537. BOOL bRedraw=0;//if OnItemExpanding or OnCollapsing returns false, dont redraw
  538. if(rect.HitTest(point))
  539. {
  540. SetRedraw(0);
  541. int nScrollIndex=0;
  542. if(IsCollapsed(pItem))
  543. {
  544. if(OnItemExpanding(pItem, ht.iItem))
  545. {
  546. nScrollIndex = Expand(pItem, ht.iItem);
  547. OnItemExpanded(pItem, ht.iItem);
  548. bRedraw=1;
  549. }
  550. }
  551. else {
  552.    if(OnCollapsing(pItem))
  553.    {
  554. Collapse(pItem);
  555. OnItemCollapsed(pItem);
  556. bRedraw=1;
  557.    }
  558. }
  559. SetRedraw(1);
  560. if(bRedraw)
  561. {
  562. CRect rc;
  563. GetItemRect(ht.iItem, rc, LVIR_BOUNDS);
  564. InvalidateRect(rc);
  565. UpdateWindow();
  566. EnsureVisible(nScrollIndex, 1);
  567. return 0;
  568. }
  569. }
  570. }//has kids
  571. }//pItem!=NULL
  572. }
  573. return 1;
  574. }
  575. /*void CSuperGridCtrl::OnDblclk(NMHDR* pNMHDR, LRESULT* pResult) 
  576. {
  577. if( GetFocus() != this) 
  578. SetFocus();
  579. NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
  580. LVHITTESTINFO ht;
  581. ht.pt = pNMListView->ptAction;
  582. SubItemHitTest(&ht);
  583. if(OnItemLButtonDown(ht))
  584. {
  585. BOOL bSelect=1;
  586. bSelect = HitTestOnSign(pNMListView->ptAction, ht);
  587. //normal selection
  588. if(bSelect && ht.iItem !=-1)
  589. {
  590. int nIndex = GetSelectedItem();
  591. if(nIndex!=-1)
  592. {
  593. CTreeItem *pSelItem = GetTreeItem(nIndex);
  594. if (pSelItem != NULL)
  595. {
  596. BOOL bRedraw=0;
  597. if(ItemHasChildren(pSelItem))
  598. {
  599. SetRedraw(0);
  600. int nScrollIndex=0;
  601. if(IsCollapsed(pSelItem))
  602. {
  603. if(OnItemExpanding(pSelItem, nIndex))
  604. {
  605. nScrollIndex = Expand(pSelItem, nIndex);
  606. OnItemExpanded(pSelItem, nIndex);
  607. bRedraw=1;
  608. }
  609. }
  610. else 
  611. {
  612.    if(OnCollapsing(pSelItem))
  613.    {
  614. Collapse(pSelItem);
  615. OnItemCollapsed(pSelItem);
  616. bRedraw=1;
  617.    }
  618. }
  619. SetRedraw(1);
  620. if(bRedraw)
  621. {
  622. CRect rc;
  623. GetItemRect(nIndex,rc,LVIR_BOUNDS);
  624. InvalidateRect(rc);
  625. UpdateWindow();
  626. EnsureVisible(nScrollIndex,1);
  627. }
  628. }//ItemHasChildren
  629. }//!=NULL
  630. }
  631. }
  632. }
  633. *pResult = 0;
  634. }*/
  635. /*void CSuperGridCtrl::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) 
  636. {
  637. NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
  638. if(pNMListView->iItem != -1)
  639. {
  640. m_nDragItem = pNMListView->iItem;
  641. CImageList* pDragImage=NULL;
  642. pDragImage = CreateDragImageEx(m_nDragItem);//override this if you want another dragimage or none at all.
  643. if(pDragImage)
  644. {
  645. pDragImage->BeginDrag(0, CPoint(0,0));
  646. pDragImage->DragEnter(this, pNMListView->ptAction);
  647. SetCapture();
  648. m_bIsDragging = TRUE;
  649. }
  650. delete pDragImage;
  651. }
  652. *pResult = 0;
  653. }*/
  654. //Create dragimage : Icon + the itemtext
  655. CImageList *CSuperGridCtrl::CreateDragImageEx(int nItem)
  656. {
  657.     CImageList *pList = new CImageList;          
  658. //get image index
  659. LV_ITEM lvItem;
  660. lvItem.mask =  LVIF_IMAGE;
  661. lvItem.iItem = nItem;
  662. lvItem.iSubItem = 0;
  663. GetItem(&lvItem);
  664. CRect rc;
  665. GetItemRect(nItem, &rc, LVIR_BOUNDS);         
  666. CString str;
  667. str = GetItemText(nItem, 0);
  668. CFont *pFont = GetFont();
  669. rc.OffsetRect(-rc.left, -rc.top);            
  670. rc.right = GetColumnWidth(0);                
  671. pList->Create(rc.Width(), rc.Height(),ILC_COLOR24| ILC_MASK , 1, 1);
  672. CDC *pDC = GetDC();                          
  673. if(pDC) 
  674. {
  675. CDC dc;       
  676. dc.CreateCompatibleDC(pDC);      
  677. CBitmap bmpMap;
  678. bmpMap.CreateCompatibleBitmap(pDC, rc.Width(), rc.Height());
  679. CBitmap *pOldBmp = dc.SelectObject(&bmpMap);
  680. CFont *pOldFont = dc.SelectObject(pFont);
  681. dc.FillSolidRect(rc, GetSysColor(COLOR_WINDOW));
  682. CImageList *pImgList = GetImageList(LVSIL_SMALL);
  683. if(pImgList)
  684. pImgList->Draw(&dc, lvItem.iImage, CPoint(0,0), ILD_TRANSPARENT);
  685. dc.TextOut(m_cxImage + 4, 0, str);
  686. dc.SelectObject(pOldFont);
  687. dc.SelectObject(pOldBmp);                 
  688. bmpMap.DeleteObject(); //hpxs 添加的销毁代码
  689. //causes an error if the 1st column is hidden so must check the imagelist
  690. if(pList->m_hImageList != NULL)
  691. pList->Add(&bmpMap, RGB(255,255,255));
  692. else
  693. delete pList;
  694. pList=NULL;
  695. }
  696. dc.DeleteDC(); //hpxs 添加的销毁DC代码
  697. ReleaseDC(pDC);   
  698. }   
  699. return pList;
  700. }
  701. /*void CSuperGridCtrl::OnMouseMove(UINT nFlags, CPoint point) 
  702. {
  703.     if(m_bIsDragging)
  704.     {
  705. KillTimer(1);
  706. if (CWnd::GetCapture() != this)
  707. m_bIsDragging=0;
  708. if(nFlags==MK_RBUTTON || nFlags==MK_MBUTTON)
  709. m_bIsDragging=0;
  710. if(GetKeyState(VK_ESCAPE) < 0)
  711. m_bIsDragging=0;
  712. if(!m_bIsDragging)//why not put this in a funtion :)
  713. {
  714. SetItemState (m_nDragTarget, 0, LVIS_DROPHILITED);
  715. CImageList::DragLeave(this);
  716. CImageList::EndDrag();
  717. ReleaseCapture();
  718. InvalidateRect(NULL);
  719. UpdateWindow();
  720. }
  721. else
  722. {
  723. CPoint ptList(point);
  724. MapWindowPoints(this, &ptList, 1);
  725. CImageList::DragMove(ptList);
  726. UINT uHitTest = LVHT_ONITEM;
  727. m_nDragTarget = HitTest(ptList, &uHitTest);
  728. // try turn off hilight for previous DROPHILITED state
  729. int nPrev = GetNextItem(-1,LVNI_DROPHILITED);
  730. if(nPrev != m_nDragTarget)//prevents flicker 
  731. SetItemState(nPrev, 0, LVIS_DROPHILITED);
  732. CRect rect;
  733. GetClientRect (rect);
  734. int cy = rect.Height();
  735. if(m_nDragTarget!=-1)
  736. {
  737. SetItemState(m_nDragTarget, LVIS_DROPHILITED, LVIS_DROPHILITED);
  738. CTreeItem* pTarget = GetTreeItem(m_nDragTarget);
  739. if ((point.y >= 0 && point.y <= m_cyImage) || (point.y >= cy - m_cyImage && point.y <= cy) || 
  740. ( pTarget!=NULL && ItemHasChildren(pTarget) && IsCollapsed(pTarget)))
  741. {
  742. SetTimer(1,300,NULL);
  743. }
  744. }
  745. }
  746.     }
  747. CListCtrl::OnMouseMove(nFlags, point);
  748. }*/
  749. /*void CSuperGridCtrl::OnTimer(UINT nIDEvent) 
  750. {
  751. CListCtrl::OnTimer(nIDEvent);
  752. if(nIDEvent==1)
  753. {
  754. if(CWnd::GetCapture()!=this)
  755. {
  756. SetItemState(m_nDragTarget, 0, LVIS_DROPHILITED);
  757. m_bIsDragging=0;
  758. CImageList::DragLeave(this);
  759. CImageList::EndDrag();
  760. ReleaseCapture();
  761. InvalidateRect(NULL);
  762. UpdateWindow();
  763. KillTimer(1);
  764. return;
  765. }
  766. SetTimer(1,300,NULL);//reset timer
  767. DWORD dwPos = ::GetMessagePos();
  768. CPoint ptList(LOWORD(dwPos),HIWORD(dwPos));
  769. ScreenToClient(&ptList);
  770. CRect rect;
  771. GetClientRect(rect);
  772. int cy = rect.Height();
  773. //
  774. // perform autoscroll if the cursor is near the top or bottom.
  775. //
  776. if (ptList.y >= 0 && ptList.y <= m_cyImage) 
  777. {
  778. int n = GetTopIndex(); 
  779. CImageList::DragShowNolock(0);
  780. SendMessage(WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), NULL);
  781. CImageList::DragShowNolock(1);
  782. if (GetTopIndex()== n)
  783. KillTimer (1);
  784. else {
  785. CImageList::DragShowNolock(0);
  786. CImageList::DragMove(ptList);
  787. CImageList::DragShowNolock(1);
  788. return;
  789. }
  790. }
  791. else if (ptList.y >= cy - m_cyImage && ptList.y <= cy) 
  792. {
  793. int n = GetTopIndex(); 
  794. CImageList::DragShowNolock(0);
  795. SendMessage(WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), NULL);
  796. CImageList::DragShowNolock(1);
  797. if (GetTopIndex()== n)
  798. KillTimer (1);
  799. else {
  800. CImageList::DragShowNolock(0);
  801. CImageList::DragMove(ptList);
  802. CImageList::DragShowNolock(1);
  803. return;
  804. }
  805. }
  806. //Hover test 
  807. CImageList::DragMove(ptList);
  808. UINT uHitTest = LVHT_ONITEM;
  809. m_nDragTarget = HitTest(ptList, &uHitTest);
  810. if(m_nDragTarget!=-1)
  811. {
  812. //if the target has children
  813. //expand them
  814. CTreeItem* pTarget=GetTreeItem(m_nDragTarget);
  815. if(pTarget != NULL && ItemHasChildren(pTarget) && IsCollapsed(pTarget) && (m_nDragItem!=-1))
  816. {
  817. CImageList::DragShowNolock(0);
  818. CTreeItem* pSource = GetTreeItem(m_nDragItem);
  819. SetRedraw(0);
  820. int nScrollIndex=0;
  821. if(ItemHasChildren(pTarget) && IsCollapsed(pTarget))
  822. {
  823. if(OnItemExpanding(pTarget, m_nDragTarget))
  824. {
  825. nScrollIndex = Expand(pTarget, m_nDragTarget);
  826. OnItemExpanded(pTarget, m_nDragTarget);
  827. }
  828. }
  829. m_nDragItem = NodeToIndex(pSource);
  830. SetRedraw(1);
  831. EnsureVisible(nScrollIndex, 1);
  832. InvalidateRect(NULL);
  833. UpdateWindow();
  834. CImageList::DragShowNolock(1);
  835. KillTimer(1);
  836. return;
  837. }
  838. }
  839. KillTimer(1);
  840. }
  841. }*/
  842. void CSuperGridCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
  843. {
  844. if(m_bIsDragging == TRUE)
  845.     {
  846. KillTimer(1);
  847.         CImageList::DragLeave(this);
  848.         CImageList::EndDrag();
  849.         ReleaseCapture();
  850.         m_bIsDragging = FALSE;
  851. SetItemState(m_nDragTarget, 0, LVIS_DROPHILITED);
  852.         if((m_nDragTarget != -1) && (m_nDragTarget != m_nDragItem) && (m_nDragItem!=-1))//no drop on me self
  853.         {
  854. CTreeItem* pSource = GetTreeItem(m_nDragItem);
  855. CTreeItem* pTarget = GetTreeItem(m_nDragTarget);
  856. if(IsRoot(pSource))
  857. return;
  858. CTreeItem* pParent = GetParentItem(pSource);
  859. if(pParent==pTarget) //can't drag child to parent
  860. return;
  861. if(!IsChildOf(pSource, pTarget))//can't drag parent to child
  862. {
  863. CWaitCursor wait;
  864. SetRedraw(0);
  865. if(DoDragDrop(pTarget, pSource))
  866. {
  867. UINT uflag = LVIS_SELECTED | LVIS_FOCUSED;
  868. SetItemState(m_nDragTarget, uflag, uflag);
  869. m_nDragItem=-1;
  870. //delete source
  871. int nIndex = NodeToIndex(pSource);
  872. DeleteItem(nIndex);
  873. HideChildren(pSource, TRUE, nIndex);
  874. Delete(pSource);
  875. InternaleUpdateTree();
  876. SetRedraw(1);
  877. InvalidateRect(NULL);
  878. UpdateWindow();
  879. }else
  880. SetRedraw(1);
  881. }
  882.     }
  883.     }
  884.     else
  885. CListCtrl::OnLButtonUp(nFlags, point);
  886. }
  887. //used with the drag/drop operation
  888. void CSuperGridCtrl::CopyChildren(CTreeItem* pDest, CTreeItem* pSrc)
  889. {
  890. if (ItemHasChildren(pSrc))
  891. {
  892. POSITION pos = pSrc->m_listChild.GetHeadPosition();
  893. while (pos != NULL)
  894. {
  895. CTreeItem* pItem = (CTreeItem *)pSrc->m_listChild.GetNext(pos);
  896. CItemInfo* lp = CopyData(GetData(pItem));
  897. CTreeItem* pNewItem = InsertItem(pDest, lp);
  898. CopyChildren(pNewItem, pItem);
  899. }
  900. }
  901. }
  902. //hmmm 
  903. BOOL CSuperGridCtrl::DoDragDrop(CTreeItem* pTarget, CTreeItem* pSource)
  904. {
  905. if(pTarget==NULL)
  906. return 0;
  907. BOOL bUpdate=FALSE;
  908. if(!IsCollapsed(pTarget))
  909. bUpdate=TRUE; //children are expanded, want to see update right away
  910. //make a copy of the source data
  911. CItemInfo* lp = CopyData(GetData(pSource));
  912. //create new node with the source data and make pTarget the parent
  913. CTreeItem* pNewParent = InsertItem(pTarget, lp, bUpdate);
  914. //if the source has children copy all source data and make the newly create item the parent
  915. if(ItemHasChildren(pSource))
  916. CopyChildren(pNewParent, pSource);
  917. return 1;
  918. }
  919. void CSuperGridCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
  920. {
  921. //its not meself
  922. if( GetFocus() != this) 
  923. SetFocus();
  924. CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
  925. }
  926. void CSuperGridCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
  927. {
  928. if( GetFocus() != this) 
  929. SetFocus();
  930. CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
  931. }
  932. BOOL CSuperGridCtrl::PreTranslateMessage(MSG* pMsg) 
  933. {
  934. if(pMsg->message == WM_KEYDOWN)
  935. {
  936. if(GetFocus()==this)
  937. {
  938. switch( pMsg->wParam )
  939. {
  940. case VK_LEFT:
  941. {
  942. // Decrement the order number.
  943. m_CurSubItem--;
  944. if(m_CurSubItem < 0) 
  945. m_CurSubItem = 0;
  946. else{
  947. CHeaderCtrl* pHeader = GetHeaderCtrl();
  948. // Make the column visible.
  949. // We have to take into account that the header may be reordered.
  950. MakeColumnVisible( Header_OrderToIndex( pHeader->m_hWnd, m_CurSubItem));
  951. // Invalidate the item.
  952. int iItem = GetSelectedItem();
  953. if( iItem != -1 )
  954. {
  955. CRect rcBounds;
  956. GetItemRect(iItem, rcBounds, LVIR_BOUNDS);
  957. InvalidateRect(&rcBounds);
  958. UpdateWindow();
  959. }
  960. }
  961. }
  962. return TRUE;
  963. case VK_RIGHT:
  964. {
  965. // Increment the order number.
  966. m_CurSubItem++;
  967. CHeaderCtrl* pHeader = GetHeaderCtrl();
  968. int nColumnCount = pHeader->GetItemCount();
  969. // Don't go beyond the last column.
  970. if( m_CurSubItem > nColumnCount -1 ) 
  971. m_CurSubItem = nColumnCount-1;
  972. else
  973. {
  974. MakeColumnVisible(Header_OrderToIndex( pHeader->m_hWnd, m_CurSubItem));
  975.  
  976. int iItem = GetSelectedItem();
  977. // Invalidate the item.
  978. if( iItem != -1 )
  979. {
  980. CRect rcBounds;
  981. GetItemRect(iItem, rcBounds, LVIR_BOUNDS);
  982. InvalidateRect(&rcBounds);
  983. UpdateWindow();
  984. }
  985. }
  986. }
  987. return TRUE;
  988. case VK_RETURN://edit itemdata
  989. {
  990. BOOL bResult = OnVkReturn();
  991. if(!bResult)
  992. {
  993. int iItem = GetSelectedItem();
  994. if( m_CurSubItem != -1 && iItem != -1)
  995. {
  996. CHeaderCtrl* pHeader = GetHeaderCtrl();
  997. int iSubItem = Header_OrderToIndex(pHeader->m_hWnd, m_CurSubItem);
  998. if(iSubItem==0)//that's just me saying all nodes in col 0 are edit-controls, you may modify this
  999. {
  1000. CRect rcItem;
  1001. GetItemRect(iItem, rcItem, LVIR_LABEL);
  1002. DWORD dwStyle = WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL|ES_LEFT;
  1003. // CEdit *pEdit = new CListEditCtrl(iItem, iSubItem, GetItemText(iItem, iSubItem));
  1004. // pEdit->Create(dwStyle, rcItem, this, 0x1233);
  1005. }
  1006. // else
  1007. // EditLabelEx(iItem, iSubItem);
  1008. return 1;
  1009. }
  1010. }
  1011. }
  1012. break;
  1013. default:
  1014. break;
  1015. }
  1016. }
  1017. }
  1018. return CListCtrl::PreTranslateMessage(pMsg);
  1019. }
  1020. #define IDC_EDITCTRL 0x1234
  1021. /*CEdit* CSuperGridCtrl::EditLabelEx(int nItem, int nCol)
  1022. {
  1023. CRect rect;
  1024. int offset = 0;
  1025. if(!EnsureVisible(nItem, TRUE)) 
  1026. return NULL;
  1027. GetSubItemRect(nItem, nCol, LVIR_BOUNDS, rect);
  1028. // Now scroll if we need to expose the column
  1029. CRect rcClient;
  1030. GetClientRect(rcClient);
  1031. if( offset + rect.left < 0 || offset + rect.left > rcClient.right )
  1032. {
  1033. CSize size(offset + rect.left,0);
  1034. Scroll(size);
  1035. rect.left -= size.cx;
  1036. }
  1037. rect.left += offset;
  1038. rect.right = rect.left + GetColumnWidth(nCol);
  1039. if(rect.right > rcClient.right) 
  1040.    rect.right = rcClient.right;
  1041. // Get Column alignment
  1042. LV_COLUMN lvcol;
  1043. lvcol.mask = LVCF_FMT;
  1044. GetColumn(nCol, &lvcol);
  1045. DWORD dwStyle;
  1046. if((lvcol.fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT)
  1047. dwStyle = ES_LEFT;
  1048. else if((lvcol.fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT)
  1049. dwStyle = ES_RIGHT;
  1050. else 
  1051. dwStyle = ES_CENTER;
  1052. dwStyle |=WS_BORDER|WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL;
  1053. CEdit *pEdit = new CListEditCtrl(nItem, nCol, GetItemText(nItem, nCol));
  1054. pEdit->Create(dwStyle, rect, this, IDC_EDITCTRL);
  1055. //pEdit->ModifyStyleEx(0,WS_EX_CLIENTEDGE); //funny thing happend here, uncomment this, 
  1056. //and then edit an item, 
  1057. //enter a long text so that the ES_AUTOHSCROLL comes to rescue
  1058. //yes that's look funny, ???.
  1059. return pEdit;
  1060. }*/
  1061.  /*void CSuperGridCtrl::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult) 
  1062. {
  1063. LV_DISPINFO *plvDispInfo = (LV_DISPINFO*)pNMHDR;
  1064. LV_ITEM *plvItem = &plvDispInfo->item;
  1065. if (plvItem->pszText != NULL)//valid text
  1066. {
  1067. if(plvItem->iItem != -1) //valid item
  1068. {
  1069. CTreeItem*pSelItem = GetTreeItem(plvItem->iItem);
  1070. if(pSelItem != NULL)
  1071. {
  1072. OnUpdateListViewItem(pSelItem, plvItem);
  1073. }
  1074. }
  1075. }
  1076. *pResult = 0;
  1077. }*/
  1078. int CSuperGridCtrl::GetNumCol()
  1079. {
  1080. CHeaderCtrl* pHeader = GetHeaderCtrl();
  1081. return pHeader ? pHeader->GetItemCount() : 0;
  1082. }
  1083. //Think Rex Myer is spooking here
  1084. void CSuperGridCtrl::MakeColumnVisible(int nCol)
  1085. {
  1086. if(nCol < 0)
  1087. return;
  1088. // Get the order array to total the column offset.
  1089. CHeaderCtrl* pHeader = GetHeaderCtrl();
  1090. int nColCount = pHeader->GetItemCount();
  1091. ASSERT( nCol < nColCount);
  1092. int *pOrderarray = new int[nColCount];
  1093. Header_GetOrderArray(pHeader->m_hWnd, nColCount, pOrderarray);
  1094. // Get the column offset
  1095. int offset = 0;
  1096. for(int i = 0; pOrderarray[i] != nCol; i++)
  1097. offset += GetColumnWidth(pOrderarray[i]);
  1098. int colwidth = GetColumnWidth(nCol);
  1099. delete[] pOrderarray;
  1100. CRect rect;
  1101. GetItemRect(0, &rect, LVIR_BOUNDS);
  1102. // Now scroll if we need to show the column
  1103. CRect rcClient;
  1104. GetClientRect(&rcClient);
  1105. if(offset + rect.left < 0 || offset + colwidth + rect.left > rcClient.right)
  1106. {
  1107. CSize size(offset + rect.left,0);
  1108. Scroll(size);
  1109. InvalidateRect(NULL);
  1110. UpdateWindow();
  1111. }
  1112. }
  1113. //Think Rex Myer is spooking here
  1114. int CSuperGridCtrl::IndexToOrder( int iIndex )
  1115. {
  1116. // This translates a column index value to a column order value.
  1117. CHeaderCtrl* pHeader = GetHeaderCtrl();
  1118. int nColCount = pHeader->GetItemCount();
  1119. int *pOrderarray = new int[nColCount];
  1120. Header_GetOrderArray(pHeader->m_hWnd, nColCount, pOrderarray);
  1121. for(int i=0; i<nColCount; i++)
  1122. {
  1123. if(pOrderarray[i] == iIndex )
  1124. {
  1125. delete[] pOrderarray;
  1126. return i;
  1127. }
  1128. }
  1129. delete[] pOrderarray;
  1130. return -1;
  1131. }
  1132. void CSuperGridCtrl::DrawFocusCell(CDC *pDC, int nItem, int iSubItem)
  1133. {
  1134. if(iSubItem==m_CurSubItem)
  1135. {
  1136. CRect rect;
  1137. GetSubItemRect(nItem, iSubItem, LVIR_BOUNDS, rect);
  1138. CBrush br(GetCellRGB());
  1139. if(iSubItem==0)
  1140. GetItemRect(iSubItem, rect, LVIR_LABEL);
  1141. pDC->FillRect(rect, &br);
  1142. pDC->DrawFocusRect(rect);
  1143. }
  1144. }
  1145. //insert item and return new parent pointer.
  1146. CSuperGridCtrl::CTreeItem* CSuperGridCtrl::InsertItem(CTreeItem *pParent, CItemInfo* lpInfo,
  1147.   BOOL bUpdate)
  1148. {
  1149. if(pParent==NULL)
  1150. return NULL;
  1151. CTreeItem *pItem = NULL;
  1152. pItem =  new CTreeItem();
  1153. if(lpInfo==NULL)
  1154. lpInfo = new CItemInfo;
  1155. UpdateData(pItem, lpInfo);
  1156. SetIndent(pItem, GetIndent(pParent)+1);
  1157. SetParentItem(pItem, pParent);
  1158. //add as the last child 
  1159. pParent->m_listChild.AddTail(pItem);
  1160. if(!bUpdate)
  1161.  Hide(pParent, TRUE);
  1162. else
  1163. {
  1164. //calc listview index for the new node
  1165. int nIndex = NodeToIndex(pItem);
  1166. CString str = GetData(pItem)->GetItemText();
  1167. LV_ITEM     lvItem;
  1168. lvItem.mask = LVIF_TEXT | LVIF_INDENT | LVIF_PARAM  | LVIF_IMAGE;
  1169. lvItem.pszText = str.GetBuffer(1); 
  1170. //insert item
  1171. lvItem.iItem = nIndex;
  1172. lvItem.iSubItem = 0;
  1173. lvItem.lParam = (LPARAM)pItem;
  1174. lvItem.iIndent = GetIndent(pItem);
  1175. lvItem.iImage = lpInfo->GetImage();
  1176. CListCtrl::InsertItem(&lvItem);
  1177. if(lpInfo->GetCheck())
  1178. SetCheck(nIndex);
  1179. //Get subitems
  1180. int nSize = GetData(pItem)->GetItemCount();
  1181. for(int i=0; i < nSize;i++)
  1182. {
  1183.    CString str = GetData(pItem)->GetSubItem(i);
  1184.    lvItem.mask = LVIF_TEXT;
  1185.    lvItem.iSubItem = i+1;
  1186.    lvItem.pszText = str.GetBuffer(1);
  1187.    SetItem(&lvItem);
  1188. }
  1189. InternaleUpdateTree();//better do this
  1190. }
  1191. return pItem;
  1192. }
  1193. void CSuperGridCtrl::InternaleUpdateTree()
  1194. {
  1195. int nItems = GetItemCount();
  1196. for(int nItem=0; nItem < nItems; nItem++)
  1197. {
  1198. CTreeItem* pItem = GetTreeItem(nItem);
  1199. SetCurIndex(pItem, nItem);
  1200. }
  1201. }
  1202. int CSuperGridCtrl::NodeToIndex(CTreeItem *pNode)
  1203. {
  1204. int nStartIndex=0;
  1205. POSITION pos = m_RootItems.GetHeadPosition();
  1206. while(pos!=NULL)
  1207. {
  1208. CTreeItem * root = (CTreeItem*)m_RootItems.GetNext(pos);
  1209. int ret = _NodeToIndex(root, pNode, nStartIndex);
  1210. if(ret != -1)
  1211. return ret;
  1212. }
  1213. return -1;
  1214. }
  1215. CSuperGridCtrl::CTreeItem* CSuperGridCtrl::GetRootItem(int nIndex)
  1216. {
  1217. POSITION pos = m_RootItems.FindIndex(nIndex);
  1218. if(pos==NULL)
  1219. return NULL;
  1220. return (CTreeItem*)m_RootItems.GetAt(pos);
  1221. }
  1222. int CSuperGridCtrl::GetRootIndex(CTreeItem * root)
  1223. {
  1224. int nIndex = 0;
  1225. POSITION pos = m_RootItems.GetHeadPosition();
  1226. while(pos != NULL)
  1227. {
  1228. CTreeItem * pItem = (CTreeItem*)m_RootItems.GetNext(pos);
  1229. if(pItem== root)
  1230. return nIndex;
  1231. nIndex++;
  1232. }
  1233. return -1;
  1234. }
  1235. BOOL CSuperGridCtrl::IsRoot(CTreeItem * lpItem)
  1236. {
  1237. return m_RootItems.Find(lpItem) != NULL;
  1238. }
  1239. void CSuperGridCtrl::DeleteRootItem(CTreeItem * root)
  1240. {
  1241. POSITION pos = m_RootItems.Find(root);
  1242. if(pos!=NULL)
  1243. {
  1244. CTreeItem* pRoot=(CTreeItem*)m_RootItems.GetAt(pos);
  1245. if(pRoot->m_lpNodeInfo!=NULL)
  1246. delete pRoot->m_lpNodeInfo;
  1247. delete pRoot;
  1248. m_RootItems.RemoveAt(pos);
  1249. }
  1250. }
  1251. CSuperGridCtrl::CTreeItem*  CSuperGridCtrl::InsertRootItem(CItemInfo * lpInfo)
  1252. {
  1253. if(lpInfo==NULL)
  1254. lpInfo = new CItemInfo;
  1255. CTreeItem* pRoot = NULL;
  1256. pRoot =  new CTreeItem();
  1257. CleanMe(pRoot);
  1258. UpdateData(pRoot, lpInfo);
  1259. SetIndent(pRoot, 1);
  1260. SetCurIndex(pRoot, GetItemCount());
  1261. SetParentItem(pRoot, NULL);
  1262. CItemInfo* lp = GetData(pRoot);
  1263. LV_ITEM lvItem;
  1264. lvItem.mask = LVIF_TEXT | LVIF_INDENT | LVIF_PARAM | LVIF_IMAGE;
  1265. CString strItem = lp->GetItemText();
  1266. lvItem.pszText = strItem.GetBuffer(1); 
  1267. lvItem.iItem = GetItemCount();
  1268. lvItem.lParam = (LPARAM)pRoot;
  1269. lvItem.iIndent = 1;
  1270. lvItem.iSubItem = 0;
  1271. lvItem.iImage = lpInfo->GetImage();
  1272. CListCtrl::InsertItem(&lvItem);
  1273. int nSize = lp->GetItemCount();
  1274. for(int i=0; i < nSize;i++)
  1275. {
  1276.    CString str = lp->GetSubItem(i);
  1277.    lvItem.mask = LVIF_TEXT;
  1278.    lvItem.iSubItem = i+1;
  1279.    lvItem.pszText = str.GetBuffer(1);
  1280.    SetItem(&lvItem);
  1281. }
  1282. m_RootItems.AddTail(pRoot);
  1283. return pRoot;
  1284. }
  1285. void CSuperGridCtrl::DrawTreeItem(CDC* pDC, CTreeItem* pSelItem, int nListItem, const CRect& rcBounds)
  1286. {
  1287. int nColWidth = GetColumnWidth(0);
  1288. int yDown = rcBounds.top;
  1289.     CPen* pPenTreeLine = pDC->SelectObject(&m_psTreeLine);
  1290. int iIndent = GetIndent(pSelItem);
  1291. int nHalfImage = (m_cxImage >> 1);
  1292. int nBottomDown = yDown + nHalfImage + ((rcBounds.Height() - m_cyImage) >> 1);
  1293. //
  1294. BOOL bChild = ItemHasChildren(pSelItem);
  1295. BOOL bCollapsed = IsCollapsed(pSelItem);
  1296. //draw outline
  1297. while(1)
  1298. {
  1299. CTreeItem* pParent = GetParentItem(pSelItem);
  1300. if(pParent==NULL)//no more parents, stop
  1301. break;
  1302. POSITION pos = pParent->m_listChild.GetTailPosition();
  1303. while(pos!=NULL)
  1304. {
  1305. CTreeItem *pLastChild = (CTreeItem*)pParent->m_listChild.GetPrev(pos);
  1306. int nIndex = GetCurIndex(pLastChild);
  1307. int nCurIndent = GetIndent(pLastChild);
  1308. if(nListItem > nIndex && iIndent > nCurIndent)//no need to go further in this loop
  1309. break;
  1310. //no drawing outside the 1st columns right
  1311. int xLine =  rcBounds.left + nCurIndent * m_cxImage - nHalfImage;
  1312. if(nIndex == nListItem && nCurIndent==iIndent)
  1313. {
  1314. //draw '-
  1315. int x;
  1316. pDC->MoveTo(xLine, yDown);
  1317. pDC->LineTo(xLine, nBottomDown);
  1318. // -
  1319. xLine + nHalfImage > nColWidth ? x = nColWidth: x = xLine + nHalfImage;
  1320. pDC->MoveTo(xLine, nBottomDown);
  1321. pDC->LineTo(x, nBottomDown);
  1322. break;
  1323. }
  1324. else
  1325. if(nIndex > nListItem && nCurIndent==iIndent)
  1326. {
  1327. //draw |-
  1328. int x;
  1329. xLine + nHalfImage > nColWidth ? x = nColWidth : x = xLine + nHalfImage;
  1330. pDC->MoveTo(xLine, nBottomDown);
  1331. pDC->LineTo(x, nBottomDown);
  1332. //-
  1333. pDC->MoveTo(xLine, yDown);
  1334. pDC->LineTo(xLine, rcBounds.bottom);
  1335. break;
  1336. }
  1337. else
  1338. if(nIndex > nListItem && nCurIndent < iIndent)
  1339. {
  1340. //draw |
  1341. pDC->MoveTo(xLine, yDown);
  1342. pDC->LineTo(xLine, rcBounds.bottom);
  1343. break;
  1344. }
  1345. }
  1346. pSelItem = pParent;//next
  1347. }
  1348. //draw plus/minus sign
  1349. if(bChild)
  1350. {
  1351. CRectangle rect(this, pDC, iIndent, rcBounds);
  1352. rect.DrawRectangle(this);
  1353. CPen* pPenPlusMinus = pDC->SelectObject(&m_psPlusMinus);
  1354. if(bCollapsed)
  1355. rect.DrawPlus();
  1356. else {
  1357. rect.DrawMinus();
  1358. //draw line up to parent folder
  1359. CPen* pLine = pDC->SelectObject(&m_psTreeLine);
  1360. int nOffset = (rcBounds.Height() - m_cyImage)/2;
  1361. pDC->MoveTo(rect.GetLeft()+ m_cxImage, rcBounds.top + m_cyImage+nOffset);
  1362. pDC->LineTo(rect.GetLeft() + m_cxImage, rcBounds.bottom);
  1363. pDC->SelectObject(pLine);
  1364. }
  1365. pDC->SelectObject(pPenPlusMinus);
  1366. }
  1367. pDC->SelectObject(pPenTreeLine);
  1368. }
  1369. //walk all over the place setting the hide/show flag of the nodes.
  1370. //it also deletes items from the listviewctrl.
  1371. void CSuperGridCtrl::HideChildren(CTreeItem *pItem, BOOL bHide,int nItem)
  1372. {
  1373. if(!IsCollapsed(pItem))
  1374. if(ItemHasChildren(pItem))
  1375. {
  1376. Hide(pItem, bHide);
  1377. POSITION pos = pItem->m_listChild.GetHeadPosition();
  1378. while (pos != NULL)
  1379. {
  1380. HideChildren((CTreeItem *)pItem->m_listChild.GetNext(pos),bHide,nItem+1);
  1381. DeleteItem(nItem);
  1382. }
  1383. }
  1384. }
  1385. void CSuperGridCtrl::Collapse(CTreeItem *pItem)
  1386. {
  1387. if(pItem != NULL && ItemHasChildren(pItem))
  1388. {
  1389. SetRedraw(0);
  1390. int nIndex = NodeToIndex(pItem);
  1391. HideChildren(pItem, TRUE, nIndex+1);
  1392. InternaleUpdateTree();
  1393. SetRedraw(1);
  1394. }
  1395. }
  1396. void CSuperGridCtrl::ExpandAll(CTreeItem *pItem, int& nScroll)
  1397. {
  1398. const int nChildren = pItem->m_listChild.GetCount();
  1399. if (nChildren > 0)
  1400. {
  1401. int nIndex = NodeToIndex(pItem);
  1402. nScroll = Expand(pItem, nIndex);
  1403. }
  1404. POSITION pos = pItem->m_listChild.GetHeadPosition();
  1405. while (pos)
  1406. {
  1407. CTreeItem *pChild = (CTreeItem*)pItem->m_listChild.GetNext(pos);
  1408. ExpandAll(pChild, nScroll);
  1409. }
  1410. }
  1411. int CSuperGridCtrl::Expand(CTreeItem* pSelItem, int nIndex)
  1412. {
  1413. if(ItemHasChildren(pSelItem) && IsCollapsed(pSelItem))
  1414. {
  1415. LV_ITEM lvItem;
  1416. lvItem.mask = LVIF_INDENT ;
  1417. lvItem.iItem = nIndex;
  1418. lvItem.iSubItem = 0;
  1419. lvItem.lParam=(LPARAM)pSelItem;
  1420. lvItem.iIndent = GetIndent(pSelItem);
  1421. // lvItem.iImage = pSelItem->m_lpNodeInfo->m_iImage;
  1422. SetItem(&lvItem);
  1423. Hide(pSelItem, FALSE);
  1424. //expand children
  1425. POSITION pos = pSelItem->m_listChild.GetHeadPosition();
  1426. while(pos != NULL)
  1427. {
  1428. CTreeItem* pNextNode = (CTreeItem*)pSelItem->m_listChild.GetNext(pos);
  1429. CString str = GetData(pNextNode)->GetItemText();
  1430. LV_ITEM lvItem;
  1431. lvItem.mask = LVIF_TEXT | LVIF_INDENT | LVIF_PARAM | LVIF_IMAGE;
  1432. lvItem.pszText =str.GetBuffer(1); 
  1433. lvItem.iItem = nIndex + 1;
  1434. lvItem.iSubItem = 0;
  1435. lvItem.lParam=(LPARAM)pNextNode;
  1436. lvItem.iIndent = GetIndent(pSelItem)+1;
  1437. lvItem.iImage = pNextNode->m_lpNodeInfo->GetImage();
  1438. CListCtrl::InsertItem(&lvItem);
  1439. if(GetData(pNextNode)->GetCheck())
  1440. SetCheck(nIndex + 1);
  1441. //get subitems
  1442. int nSize = GetData(pNextNode)->GetItemCount();
  1443. for(int i=0; i< nSize;i++)
  1444. {
  1445.    CString str=GetData(pNextNode)->GetSubItem(i);
  1446.    lvItem.mask = LVIF_TEXT;
  1447.    lvItem.iSubItem = i+1;
  1448.    lvItem.pszText=str.GetBuffer(1);
  1449.    SetItem(&lvItem);
  1450. }
  1451. nIndex++;
  1452. }
  1453. }
  1454. InternaleUpdateTree();
  1455. return nIndex;
  1456. }
  1457. int CSuperGridCtrl::SelectNode(CTreeItem *pLocateNode)
  1458. {
  1459. if(IsRoot(pLocateNode))
  1460. {
  1461. UINT uflag = LVIS_SELECTED | LVIS_FOCUSED;
  1462. SetItemState(0, uflag, uflag);
  1463. return 0;
  1464. }
  1465. int nSelectedItem=-1;
  1466. CTreeItem* pNode = pLocateNode;
  1467. CTreeItem* pTopLevelParent=NULL;
  1468. //Get top parent
  1469. while(1)
  1470. {
  1471. CTreeItem *pParent = GetParentItem(pLocateNode);
  1472. if(IsRoot(pParent))
  1473. break;
  1474. pLocateNode = pParent;
  1475. }
  1476. pTopLevelParent = pLocateNode;//on top of all
  1477. //Expand the folder
  1478. if(pTopLevelParent != NULL)
  1479. {
  1480. SetRedraw(0);
  1481. CWaitCursor wait;
  1482. CTreeItem *pRoot = GetParentItem(pTopLevelParent);
  1483. if(IsCollapsed(pRoot))
  1484. //old Expand(pRoot,0);
  1485. Expand(pRoot, NodeToIndex(pRoot)); // Yep! Now it's right!
  1486. ExpandUntil(pTopLevelParent, pNode);
  1487. UINT uflag = LVIS_SELECTED | LVIS_FOCUSED;
  1488. nSelectedItem = NodeToIndex(pNode);
  1489. SetItemState(nSelectedItem, uflag, uflag);
  1490. SetRedraw(1);
  1491. EnsureVisible(nSelectedItem, TRUE);
  1492. }
  1493. return nSelectedItem;
  1494. }
  1495. void CSuperGridCtrl::ExpandUntil(CTreeItem *pItem, CTreeItem* pStopAt)
  1496. {
  1497. const int nChildren = pItem->m_listChild.GetCount();
  1498. if (nChildren > 0)
  1499. {
  1500. POSITION pos = pItem->m_listChild.GetHeadPosition();
  1501. while (pos)
  1502. {
  1503. CTreeItem *pChild = (CTreeItem*)pItem->m_listChild.GetNext(pos);
  1504. if(pChild == pStopAt)
  1505. {
  1506. int nSize = GetIndent(pChild);
  1507. CTreeItem** ppParentArray = new CTreeItem*[nSize];
  1508. int i=0;
  1509. while(1)
  1510. {
  1511. CTreeItem *pParent = GetParentItem(pChild);
  1512. if(IsRoot(pParent))
  1513. break;
  1514. pChild = pParent;
  1515. ppParentArray[i] = pChild;
  1516. i++;
  1517. }
  1518. for(int x=i; x > 0; x--)
  1519. {
  1520. CTreeItem *pParent = ppParentArray[x-1];
  1521. Expand(pParent, NodeToIndex(pParent));
  1522. }
  1523. delete [] ppParentArray;
  1524. return;
  1525. }
  1526. }
  1527. }
  1528. POSITION pos = pItem->m_listChild.GetHeadPosition();
  1529. while (pos)
  1530. {
  1531. CTreeItem *pChild = (CTreeItem*)pItem->m_listChild.GetNext(pos);
  1532. ExpandUntil(pChild, pStopAt);
  1533. }
  1534. }
  1535. void CSuperGridCtrl::DeleteItemEx(CTreeItem *pSelItem, int nItem)
  1536. {
  1537. SetRedraw(0);
  1538. DeleteItem(nItem);//delete cur item in listview
  1539. //delete/hide all children in pSelItem
  1540. HideChildren(pSelItem, TRUE, nItem);
  1541. //delete all internal nodes
  1542. // If root, must delete from m_rootData
  1543. if(GetParentItem(pSelItem) == NULL )
  1544. {
  1545. DeleteRootItem(pSelItem);
  1546. }
  1547. else
  1548. Delete(pSelItem);
  1549. InternaleUpdateTree();
  1550. if(nItem-1<0)//no more items in list
  1551. {
  1552. SetRedraw(1); 
  1553. InvalidateRect(NULL);
  1554. UpdateWindow();
  1555. return;
  1556. }
  1557. UINT uflag = LVIS_SELECTED | LVIS_FOCUSED;
  1558. CRect rcTestIfItemIsValidToSelectOtherWiseSubtrackOneFromItem;//just to get the documention right :)
  1559. GetItemRect(nItem, rcTestIfItemIsValidToSelectOtherWiseSubtrackOneFromItem ,LVIR_LABEL) ? SetItemState(nItem, uflag, uflag) : SetItemState(nItem-1, uflag, uflag);
  1560. SetRedraw(1);
  1561. InvalidateRect(NULL);
  1562. UpdateWindow();
  1563. }
  1564. void CSuperGridCtrl::CleanMe(CTreeItem *pItem)
  1565. {
  1566. // delete child nodes
  1567. POSITION pos = pItem->m_listChild.GetHeadPosition();
  1568. while (pos != NULL)
  1569. {
  1570. CTreeItem* pItemData = (CTreeItem*)pItem->m_listChild.GetNext(pos);
  1571. if(pItemData!=NULL)
  1572. {
  1573. if(pItemData->m_lpNodeInfo!=NULL)
  1574. delete pItemData->m_lpNodeInfo;
  1575. pItemData->m_listChild.RemoveAll();
  1576. delete pItemData;
  1577. }
  1578. }
  1579. pItem->m_listChild.RemoveAll();
  1580. }
  1581. CSuperGridCtrl::CTreeItem* CSuperGridCtrl::GetNext(CTreeItem* pStartAt, CTreeItem* pNode, BOOL bInit, BOOL bDontIncludeHidden)
  1582. {
  1583. static BOOL bFound;
  1584. if (bInit)
  1585. bFound = FALSE;
  1586. if (pNode == pStartAt)
  1587. bFound = TRUE;
  1588. if(bDontIncludeHidden)
  1589. {
  1590. if (!IsCollapsed(pStartAt))
  1591. {
  1592. POSITION pos = pStartAt->m_listChild.GetHeadPosition();
  1593. while (pos != NULL)
  1594. {
  1595. CTreeItem* pChild = (CTreeItem*)pStartAt->m_listChild.GetNext(pos);
  1596. if (bFound)
  1597. return pChild;
  1598. pChild = GetNext(pChild, pNode, FALSE, TRUE);
  1599. if (pChild != NULL)
  1600. return pChild;
  1601. }
  1602. }
  1603. }
  1604. else {
  1605. POSITION pos = pStartAt->m_listChild.GetHeadPosition();
  1606. while (pos != NULL)
  1607. {
  1608. CTreeItem* pChild = (CTreeItem*)pStartAt->m_listChild.GetNext(pos);
  1609. if (bFound)
  1610. return pChild;
  1611. pChild = GetNext(pChild, pNode, FALSE,FALSE);
  1612. if (pChild != NULL)
  1613. return pChild;
  1614. }
  1615. }
  1616. // if reached top and last level return original
  1617. if (bInit)
  1618. return pNode;
  1619. else
  1620. return NULL;
  1621. }
  1622. CSuperGridCtrl::CTreeItem* CSuperGridCtrl::GetPrev(CTreeItem* pStartAt, CTreeItem* pNode, BOOL bInit, BOOL bDontIncludeHidden)
  1623. {
  1624. static CTreeItem* pPrev;
  1625. if (bInit)
  1626. pPrev = pStartAt;
  1627. if (pNode == pStartAt)
  1628. return pPrev;
  1629. pPrev = pStartAt;
  1630. if(bDontIncludeHidden)
  1631. {
  1632. if (!IsCollapsed(pStartAt))
  1633. {
  1634. POSITION pos = pStartAt->m_listChild.GetHeadPosition();
  1635. while (pos != NULL)
  1636. {
  1637. CTreeItem* pCur = (CTreeItem*)pStartAt->m_listChild.GetNext(pos);
  1638. CTreeItem* pChild = GetPrev(pCur,pNode, FALSE,TRUE);
  1639. if (pChild != NULL)
  1640. return pChild;
  1641. }
  1642. }
  1643. }
  1644. else {
  1645. POSITION pos = pStartAt->m_listChild.GetHeadPosition();
  1646. while (pos != NULL)
  1647. {
  1648. CTreeItem* pCur = (CTreeItem*)pStartAt->m_listChild.GetNext(pos);
  1649. CTreeItem* pChild = GetPrev(pCur,pNode, FALSE,FALSE);
  1650. if (pChild != NULL)
  1651. return pChild;
  1652. }
  1653. }
  1654. if (bInit)
  1655. return pPrev;
  1656. else
  1657. return NULL;
  1658. }
  1659. int CSuperGridCtrl::_NodeToIndex(CTreeItem *pStartpos, CTreeItem* pNode, int& nIndex, BOOL binit)
  1660. {
  1661. static BOOL bFound;
  1662. // Account for other root nodes
  1663. if(GetParentItem(pStartpos) == NULL && GetRootIndex(pStartpos) !=0)
  1664. nIndex++;
  1665. if(binit)
  1666. bFound=FALSE;
  1667. if(pStartpos==pNode)
  1668. bFound=TRUE;
  1669. if(!IsCollapsed(pStartpos))
  1670. {
  1671. POSITION pos = GetHeadPosition(pStartpos);
  1672. while (pos)
  1673. {
  1674. CTreeItem *pChild = GetNextChild(pStartpos, pos);
  1675. if(bFound)
  1676. return nIndex;
  1677. // Craig Schmidt: Cannot set nIndex as return value.  Worked find with single root but
  1678. //    the calling function get confused since the return value may indicate
  1679. //    that the next root needs to be searched.  Didn'd spend much time on
  1680. //    this so there is probably a better way of doing this.
  1681. // nIndex = _NodeToIndex(pChild, pNode, nIndex, binit);
  1682. _NodeToIndex(pChild, pNode, nIndex, binit);
  1683. nIndex++;
  1684. }
  1685. }
  1686. if(binit && bFound)
  1687. return nIndex;
  1688. else
  1689. return -1;
  1690. }
  1691. BOOL CSuperGridCtrl::Delete(CTreeItem* pNode, BOOL bClean)
  1692. {
  1693. POSITION pos = m_RootItems.GetHeadPosition();
  1694. while(pos!=NULL)
  1695. {
  1696. CTreeItem * pRoot = (CTreeItem*)m_RootItems.GetNext(pos);
  1697. if(_Delete(pRoot, pNode, bClean))
  1698. return TRUE;
  1699. }
  1700. return FALSE;
  1701. }
  1702. BOOL CSuperGridCtrl::_Delete(CTreeItem* pStartAt, CTreeItem* pNode, BOOL bClean)
  1703. {
  1704. POSITION pos = pStartAt->m_listChild.GetHeadPosition();
  1705. while (pos != NULL)
  1706. {
  1707. POSITION posPrev = pos;
  1708. CTreeItem *pChild = (CTreeItem*)pStartAt->m_listChild.GetNext(pos);
  1709. if (pChild == pNode)
  1710. {
  1711. pStartAt->m_listChild.RemoveAt(posPrev);
  1712. if(bClean)
  1713. {
  1714. if(GetData(pNode)!=NULL)
  1715. delete GetData(pNode);
  1716. delete pNode;
  1717. }
  1718. return TRUE;
  1719. }
  1720. if (_Delete(pChild, pNode) == TRUE)
  1721. return TRUE;
  1722. }
  1723. return FALSE;
  1724. }
  1725. BOOL CSuperGridCtrl::IsChildOf(const CTreeItem* pParent, const CTreeItem* pChild) const
  1726. {
  1727. if (pChild == pParent)
  1728. return TRUE;
  1729. POSITION pos = pParent->m_listChild.GetHeadPosition();
  1730. while (pos != NULL)
  1731. {
  1732. CTreeItem* pNode = (CTreeItem*)pParent->m_listChild.GetNext(pos);
  1733. if (IsChildOf(pNode, pChild))
  1734. return TRUE;
  1735. }
  1736. return FALSE;
  1737. }
  1738. void CSuperGridCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
  1739. {
  1740. if( GetFocus() != this) 
  1741. SetFocus();
  1742. LVHITTESTINFO ht;
  1743. ht.pt = point;
  1744. SubItemHitTest(&ht);
  1745. if(OnItemLButtonDown(ht))
  1746. {
  1747. BOOL bSelect=1;
  1748. bSelect = HitTestOnSign(point, ht);
  1749. if(bSelect && ht.iItem!=-1)
  1750. {
  1751. m_CurSubItem = IndexToOrder(ht.iSubItem);
  1752. CHeaderCtrl* pHeader = GetHeaderCtrl();
  1753. // Make the column fully visible.
  1754. MakeColumnVisible(Header_OrderToIndex(pHeader->m_hWnd, m_CurSubItem));
  1755. CListCtrl::OnLButtonDown(nFlags, point);
  1756. OnControlLButtonDown(nFlags, point, ht);
  1757. //update row anyway for selection bar
  1758. CRect rc;
  1759. GetItemRect(ht.iItem, rc, LVIR_BOUNDS);
  1760. InvalidateRect(rc);
  1761. UpdateWindow();
  1762. }
  1763. }
  1764. }
  1765. void CSuperGridCtrl::OnUpdateListViewItem(CTreeItem* lpItem, LV_ITEM *plvItem)
  1766. {
  1767. //default implementation you would go for this 9 out of 10 times
  1768. CItemInfo *lp = GetData(lpItem);
  1769. CString str = (CString)plvItem->pszText;
  1770. if(lp!=NULL)
  1771. {
  1772. if(plvItem->iSubItem==0)
  1773. lp->SetItemText(str);
  1774. else //subitem data 
  1775. lp->SetSubItemText(plvItem->iSubItem-1, str);
  1776.    UpdateData(lpItem, lp);
  1777. }
  1778. SetItemText(plvItem->iItem, plvItem->iSubItem, plvItem->pszText);
  1779. }
  1780. void CSuperGridCtrl::DeleteAll()
  1781. {
  1782. POSITION pos = m_RootItems.GetHeadPosition();
  1783. while(pos!=NULL)
  1784. {
  1785. CTreeItem * pRoot = (CTreeItem*)m_RootItems.GetNext(pos);
  1786. if(pRoot!=NULL)
  1787. DeleteItemEx(pRoot, 0);
  1788. }
  1789. }
  1790. POSITION CSuperGridCtrl::GetRootHeadPosition() const
  1791. {
  1792. return m_RootItems.GetHeadPosition();
  1793. }
  1794. POSITION CSuperGridCtrl::GetRootTailPosition() const
  1795. {
  1796. return m_RootItems.GetTailPosition();
  1797. }
  1798. CSuperGridCtrl::CTreeItem* CSuperGridCtrl::GetNextRoot(POSITION& pos) const
  1799. {
  1800. return (CTreeItem*)m_RootItems.GetNext(pos);
  1801. }
  1802. CSuperGridCtrl::CTreeItem* CSuperGridCtrl::GetPrevRoot(POSITION& pos) const
  1803. {
  1804. return (CTreeItem*)m_RootItems.GetNext(pos);
  1805. }
  1806. POSITION CSuperGridCtrl::GetHeadPosition(CTreeItem* pItem) const
  1807. {
  1808. return pItem->m_listChild.GetHeadPosition();
  1809. }
  1810. CSuperGridCtrl::CTreeItem* CSuperGridCtrl::GetNextChild(CTreeItem *pItem, POSITION& pos) const
  1811. {
  1812. return (CTreeItem*)pItem->m_listChild.GetNext(pos);
  1813. }
  1814. CSuperGridCtrl::CTreeItem* CSuperGridCtrl::GetPrevChild(CTreeItem *pItem, POSITION& pos) const
  1815. {
  1816. return (CTreeItem*)pItem->m_listChild.GetPrev(pos);
  1817. }
  1818. POSITION CSuperGridCtrl::GetTailPosition(CTreeItem *pItem) const
  1819. {
  1820. return pItem->m_listChild.GetTailPosition();
  1821. }
  1822. void CSuperGridCtrl::AddTail(CTreeItem *pParent, CTreeItem *pChild)
  1823. {
  1824. pParent->m_listChild.AddTail(pChild);
  1825. }
  1826. inline int StrComp(const CString* pElement1, const CString* pElement2)
  1827. {
  1828. return pElement1->Compare(*pElement2);
  1829. }
  1830. int CSuperGridCtrl::CompareChildren(const void* p1, const void* p2)
  1831. {
  1832. CTreeItem * pChild1 = *(CTreeItem**)p1;
  1833. CTreeItem * pChild2 = *((CTreeItem**)p2);
  1834. CItemInfo *pItem1=(*pChild1).m_lpNodeInfo;
  1835. CItemInfo *pItem2=(*pChild2).m_lpNodeInfo;
  1836. return StrComp(&(pItem1->GetItemText()), &(pItem2->GetItemText()));
  1837. }
  1838. void CSuperGridCtrl::Sort(CTreeItem* pParent, BOOL bSortChildren)
  1839. {
  1840. const int nChildren = NumChildren(pParent);
  1841. if (nChildren > 1)
  1842. {
  1843. CTreeItem** ppSortArray = new CTreeItem*[nChildren];
  1844. // Fill in array with pointers to our children.
  1845. POSITION pos = pParent->m_listChild.GetHeadPosition();
  1846. for (int i=0; pos; i++)
  1847. {
  1848. ASSERT(i < nChildren);
  1849. ppSortArray[i] = (CTreeItem*)pParent->m_listChild.GetAt(pos);
  1850. pParent->m_listChild.GetNext(pos);
  1851. }
  1852. qsort(ppSortArray, nChildren, sizeof(CTreeItem*), CompareChildren);
  1853. // reorg children with new sorted list
  1854. pos = pParent->m_listChild.GetHeadPosition();
  1855. for (i=0; pos; i++)
  1856. {
  1857. ASSERT(i < nChildren);
  1858. pParent->m_listChild.SetAt(pos, ppSortArray[i]);
  1859. pParent->m_listChild.GetNext(pos);
  1860. }
  1861. delete [] ppSortArray;
  1862. }
  1863. if(bSortChildren)
  1864. {
  1865. POSITION pos = pParent->m_listChild.GetHeadPosition();
  1866. while (pos)
  1867. {
  1868. CTreeItem *pChild = (CTreeItem*)pParent->m_listChild.GetNext(pos);
  1869. Sort(pChild, TRUE);
  1870. }
  1871. }
  1872. }
  1873. int CSuperGridCtrl::NumChildren(const CTreeItem *pItem) const
  1874. {
  1875. return pItem->m_listChild.GetCount();
  1876. }
  1877. BOOL CSuperGridCtrl::ItemHasChildren(const CTreeItem* pItem) const
  1878. BOOL bChildren = pItem->m_listChild.GetCount() != 0;
  1879. //see if we have a flag
  1880. int nFlag = pItem->m_bSetChildFlag;
  1881. if(nFlag!=-1)
  1882. return 1;
  1883. else
  1884. return bChildren;
  1885. }
  1886. void CSuperGridCtrl::SetChildrenFlag(CTreeItem *pItem, int nFlag) const
  1887. {
  1888. pItem->m_bSetChildFlag = nFlag;
  1889. }
  1890. BOOL CSuperGridCtrl::IsCollapsed(const CTreeItem* pItem) const
  1891. {
  1892. return pItem->m_bHideChildren;//e.g not visible
  1893. }
  1894. void CSuperGridCtrl::Hide(CTreeItem* pItem, BOOL bFlag)
  1895. {
  1896. pItem->m_bHideChildren=bFlag;
  1897. }
  1898. int CSuperGridCtrl::GetIndent(const CTreeItem* pItem) const
  1899. {
  1900. return pItem->m_nIndent;
  1901. }
  1902. void CSuperGridCtrl::SetIndent(CTreeItem *pItem, int iIndent)
  1903. {
  1904. pItem->m_nIndent = iIndent;
  1905. }
  1906. int CSuperGridCtrl::GetCurIndex(const CTreeItem *pItem) const
  1907. {
  1908. return pItem->m_nIndex;
  1909. }
  1910. void CSuperGridCtrl::SetCurIndex(CTreeItem* pItem, int nIndex) 
  1911. {
  1912. pItem->m_nIndex = nIndex;
  1913. }
  1914. void CSuperGridCtrl::SetParentItem(CTreeItem*pItem, CTreeItem* pParent)
  1915. {
  1916. pItem->m_pParent=pParent;
  1917. }
  1918. CSuperGridCtrl::CTreeItem* CSuperGridCtrl::GetParentItem(const CTreeItem* pItem) 
  1919. {
  1920. return pItem->m_pParent;
  1921. };
  1922. CItemInfo* CSuperGridCtrl::GetData(const CTreeItem* pItem) 
  1923. {
  1924. return pItem->m_lpNodeInfo;
  1925. }
  1926. void CSuperGridCtrl::UpdateData(CTreeItem* pItem, CItemInfo* lpInfo)
  1927. {
  1928. pItem->m_lpNodeInfo = lpInfo;
  1929. }
  1930. //overrides
  1931. CItemInfo* CSuperGridCtrl::CopyData(CItemInfo* lpSrc)
  1932. {
  1933. ASSERT(FALSE);//debug
  1934. return NULL;  //release
  1935. }
  1936. //default implementation for setting icons
  1937. int CSuperGridCtrl::GetIcon(const CTreeItem* pItem)
  1938. {
  1939. return 0;//just take the first item in CImageList ..what ever that is
  1940. }
  1941. void CSuperGridCtrl::OnControlLButtonDown(UINT nFlags, CPoint point, LVHITTESTINFO& ht)
  1942. {
  1943. if(ht.iSubItem==0)
  1944. {
  1945. CRect rcItem;
  1946. GetItemRect(ht.iItem, rcItem, LVIR_LABEL);
  1947. DWORD dwStyle = WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL|ES_LEFT;
  1948. // CEdit *pEdit = new CListEditCtrl(ht.iItem, ht.iSubItem, GetItemText(ht.iItem, ht.iSubItem));
  1949. // pEdit->Create(dwStyle, rcItem, this, 0x1233);
  1950. }
  1951. // else
  1952. // EditLabelEx(ht.iItem, ht.iSubItem);
  1953. }
  1954. COLORREF CSuperGridCtrl::GetCellRGB()
  1955. {
  1956. return RGB(192,0,0);
  1957. }
  1958. BOOL CSuperGridCtrl::OnVKMultiply(CTreeItem *pItem, int nIndex)
  1959. {
  1960. return 1;
  1961. }
  1962. BOOL CSuperGridCtrl::OnVkSubTract(CTreeItem *pItem, int nIndex)
  1963. {
  1964. return 1;
  1965. }
  1966. BOOL CSuperGridCtrl::OnVKAdd(CTreeItem *pItem, int nIndex)
  1967. {
  1968. return 1;
  1969. }
  1970. BOOL CSuperGridCtrl::OnDeleteItem(CTreeItem* pItem, int nIndex)
  1971. {
  1972. return 1;
  1973. }
  1974. BOOL CSuperGridCtrl::OnItemExpanding(CTreeItem *pItem, int iItem)
  1975. {
  1976. return 1;
  1977. }
  1978. BOOL CSuperGridCtrl::OnItemExpanded(CTreeItem* pItem, int iItem)
  1979. {
  1980. return 1;
  1981. }
  1982. BOOL CSuperGridCtrl::OnCollapsing(CTreeItem *pItem)
  1983. {
  1984. return 1;
  1985. }
  1986. BOOL CSuperGridCtrl::OnItemCollapsed(CTreeItem *pItem)
  1987. {
  1988. return 1;
  1989. }
  1990. BOOL CSuperGridCtrl::OnItemLButtonDown(LVHITTESTINFO& ht)
  1991. {
  1992. return 1;
  1993. }
  1994. BOOL CSuperGridCtrl::OnVkReturn(void)
  1995. {
  1996. return 0;
  1997. }
  1998. void CSuperGridCtrl::OnSysColorChange() 
  1999. {
  2000. CListCtrl::OnSysColorChange();
  2001. //nop nothing yet
  2002. }
  2003. UINT CSuperGridCtrl::_GetCount(CTreeItem* pItem, UINT& nCount)
  2004. {
  2005. POSITION pos = pItem->m_listChild.GetHeadPosition();
  2006. while (pos)
  2007. {
  2008. CTreeItem *pChild = (CTreeItem*)pItem->m_listChild.GetNext(pos);
  2009. nCount = _GetCount(pChild, nCount);
  2010. nCount++;
  2011. }
  2012. return nCount;
  2013. }
  2014. UINT CSuperGridCtrl::GetCount(void) 
  2015. {
  2016. UINT nCount=0;
  2017. POSITION pos = m_RootItems.GetHeadPosition();
  2018. while(pos!=NULL)
  2019. {
  2020. CTreeItem * pRoot = (CTreeItem*)m_RootItems.GetNext(pos);
  2021. UINT _nCount=0;
  2022. nCount += _GetCount(pRoot, _nCount) + 1;
  2023. }
  2024. return nCount;
  2025. }
  2026. CSuperGridCtrl::CTreeItem* CSuperGridCtrl::GetTreeItem(int nIndex /*nIndex must be valid of course*/ ) 
  2027. {
  2028. return reinterpret_cast<CTreeItem*>(GetItemData(nIndex));
  2029. }
  2030. int CSuperGridCtrl::GetSelectedItem(void) const
  2031. {
  2032. return GetNextItem(-1, LVNI_ALL | LVNI_SELECTED); 
  2033. }
  2034. //////////////////////////////////////////////////////////////////////////
  2035. //
  2036. // not much but ... 
  2037. //
  2038. //////////////////////////////////////////////////////////////////////////
  2039. CSuperGridCtrl::CTreeItem::~CTreeItem()
  2040. {
  2041. // delete child nodes
  2042. POSITION pos = m_listChild.GetHeadPosition();
  2043. while (pos != NULL)
  2044. {
  2045. CTreeItem* pItem = (CTreeItem*)m_listChild.GetNext(pos);
  2046. if(pItem!=NULL)
  2047. {
  2048. if(pItem->m_lpNodeInfo!=NULL)
  2049. delete pItem->m_lpNodeInfo;
  2050. delete pItem;
  2051. }
  2052. }
  2053. m_listChild.RemoveAll();
  2054. }
  2055. void CSuperGridCtrl::DrawProgressBar(CDC* pDC, int iItem, int iSubItem)
  2056. {
  2057. ASSERT(pDC);
  2058. CRect rect;
  2059. BOOL bRC = CListCtrl::GetSubItemRect(iItem, iSubItem, LVIR_LABEL, rect);
  2060. // GetProgressRect(id, rect, false);
  2061. //First, fill area outside progress bar with background color
  2062. {
  2063. CRect outrect;
  2064. GetSubItemRect(iItem, iSubItem, LVIR_BOUNDS, outrect);
  2065. // GetTextRect(id, outrect);
  2066. pDC->SaveDC();
  2067. pDC->ExcludeClipRect(&rect);
  2068. FillSolidRect(pDC, outrect, RGB(0,0,0));
  2069. pDC->RestoreDC(-1);
  2070. }
  2071. // if(id.m_edge != 0)
  2072. {
  2073. // draw border
  2074. pDC->DrawEdge(&rect, EDGE_SUNKEN, BF_RECT);
  2075. }
  2076. // GetProgressRect(id, rect, true);
  2077. // fill interior with background color
  2078. FillSolidRect(pDC, rect, RGB(128,0,0)); //id.m_progressBar.m_fillColor==DEFAULTCOLOR));
  2079. // if (id.m_value > 0)
  2080. {
  2081. // draw progress bar and text
  2082. // rect.right = rect.left + GetBarSize(id, rect);
  2083. COLORREF fill = ::GetSysColor(COLOR_GRAYTEXT);
  2084. FillSolidRect(pDC, rect, fill);
  2085. }
  2086. }
  2087. //Custom draw
  2088. /*void CSuperGridCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
  2089. {
  2090. NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );
  2091.   //  *pResult = 0; return;
  2092.     // If this is the beginning of the control's paint cycle, request
  2093.     // notifications for each item.
  2094.     if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )
  2095. {
  2096.         *pResult = CDRF_NOTIFYITEMDRAW;
  2097. }
  2098.     else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage )
  2099. {
  2100.         // This is the pre-paint stage for an item.  We need to make another
  2101.         // request to be notified during the post-paint stage.
  2102.         *pResult = CDRF_NOTIFYSUBITEMDRAW;;
  2103. }
  2104.     else if ( (CDDS_ITEMPREPAINT| CDDS_SUBITEM) == pLVCD->nmcd.dwDrawStage )
  2105. {
  2106. CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc);
  2107. DrawProgressBar(pDC, static_cast<int> (pLVCD->nmcd.dwItemSpec), pLVCD->iSubItem);
  2108. *pResult = CDRF_SKIPDEFAULT; // We've painted everything.
  2109. }
  2110. }*/
  2111. //////////////////////////////////////////////////////////////////////////
  2112. //
  2113. // Simple class CRectangle for the + - sign, 
  2114. //
  2115. //////////////////////////////////////////////////////////////////////////
  2116. CRectangle::CRectangle(CSuperGridCtrl* pCtrl, CDC* pDC, int iIndent, const CRect& rcBounds)
  2117. {
  2118. m_pDC=pDC;
  2119. int nHalfImage = (pCtrl->m_cxImage >> 1);
  2120. int nBottomDown = rcBounds.top + nHalfImage + ((rcBounds.Height() - pCtrl->m_cyImage) >> 1);
  2121. m_right_bottom.cx = (pCtrl->m_cxImage>>1)+2+1;
  2122. m_right_bottom.cy = (pCtrl->m_cyImage>>1)+2+1;
  2123. m_left = rcBounds.left  + iIndent * pCtrl->m_cxImage - nHalfImage;
  2124. m_top = nBottomDown - (m_right_bottom.cy >> 1);
  2125. m_left_top.x = m_left -  (m_right_bottom.cx >> 1);
  2126. m_left_top.y = m_top;
  2127. m_topdown = nBottomDown;
  2128. }
  2129. void CRectangle::DrawRectangle(CSuperGridCtrl* pCtrl)
  2130. {
  2131. //erase bkgrnd
  2132. CRect rc(m_left_top, m_right_bottom);
  2133. m_pDC->FillRect(rc, &pCtrl->m_brushErase);
  2134. //draw rectangle
  2135. CPen* pPenRectangle = m_pDC->SelectObject(&pCtrl->m_psRectangle);
  2136. m_pDC->Rectangle(rc);
  2137. m_pDC->SelectObject(pPenRectangle);
  2138. }
  2139. CRectangle::~CRectangle()
  2140. {
  2141. }
  2142. BOOL CRectangle::HitTest(CPoint pt)
  2143. {
  2144. CRect rc = GetHitTestRect();
  2145. return rc.PtInRect(pt);
  2146. }
  2147. void CRectangle::DrawPlus(void)
  2148. {
  2149. m_pDC->MoveTo(m_left, m_topdown-2);
  2150. m_pDC->LineTo(m_left, m_topdown+3);
  2151. m_pDC->MoveTo(m_left-2, m_topdown);
  2152. m_pDC->LineTo(m_left+3, m_topdown);
  2153. }
  2154. void CRectangle::DrawMinus(void)
  2155. {
  2156. m_pDC->MoveTo(m_left-2, m_topdown);
  2157. m_pDC->LineTo(m_left+3, m_topdown);
  2158. }