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

TreeView控件

开发平台:

Visual C++

  1. /************************************
  2.   REVISION LOG ENTRY
  3.   Revision By: Mihai Filimon
  4.   Revised on 5/22/98 9:23:23 AM
  5.   Comments: Tsyslistviewex.cpp : implementation file
  6.  ************************************/
  7. #include "stdafx.h"
  8. #include "Tsyslistviewex.h"
  9. #include "resource.h"
  10. #ifdef _DEBUG
  11. #define new DEBUG_NEW
  12. #undef THIS_FILE
  13. static char THIS_FILE[] = __FILE__;
  14. #endif
  15. #define scanCodeS 0x13
  16. /////////////////////////////////////////////////////////////////////////////
  17. // CTsyslistviewex
  18. TCHAR CTsyslistviewex::m_cImageTextSeparator = TCHAR(':');
  19. // Function name : CTsyslistviewex::CTsyslistviewex
  20. // Description     : constructor
  21. // In contructor u must set the height of item list. (MeasureItem is called before
  22. // PreSubclassWindow!). U can not modify item height at runtime, therefore.
  23. // Return type : void
  24. // Argument         : int nHeightRel ; set item height
  25. CTsyslistviewex::CTsyslistviewex(int nHeightRel)
  26. {
  27. m_fctDrawItem = CTsyslistviewex::DrawItemNoGrid;
  28. m_nHeightRel = nHeightRel;
  29. m_bSorted = false;
  30. m_bSortWhenClickHeader = TRUE;
  31. m_nSortItems = 0;
  32. m_nIProgress = 0;
  33. m_bSaveHeader = false;
  34. ResetBoldLines();
  35. }
  36. // Function name : CTsyslistviewex::~CTsyslistviewex
  37. // Description     : destructor
  38. // Return type : void
  39. CTsyslistviewex::~CTsyslistviewex()
  40. {
  41. // Remove the CTColumnBitmap from m_bmpColumns
  42. POSITION posBmp = m_bmpColumns.GetStartPosition( );
  43. while (posBmp)
  44. {
  45. CTColumnBitmap* pBitmap = NULL;
  46. int nColumn = 0;
  47. m_bmpColumns.GetNextAssoc( posBmp , nColumn,  pBitmap );
  48. if (pBitmap)
  49. delete pBitmap;
  50. }
  51. m_bmpColumns.RemoveAll();
  52. // Remove the CTColumnBitmap from m_bmpCells
  53. posBmp = m_bmpCells.GetStartPosition( );
  54. while (posBmp)
  55. {
  56. CTColumnBitmap* pBitmap = NULL;
  57. DWORD nKey = 0;
  58. m_bmpCells.GetNextAssoc( posBmp , nKey,  pBitmap );
  59. if (pBitmap)
  60. delete pBitmap;
  61. }
  62. m_bmpCells.RemoveAll();
  63. }
  64. // Function name : CTsyslistviewex::IsHeaderSaved
  65. // Description     : accessor: header saved
  66. // Return type : BOOL ;Return TRUE if EnableSaveHeader was called
  67. BOOL CTsyslistviewex::IsHeaderSaved()
  68. {
  69. return m_bSaveHeader;
  70. }
  71. // Function name : CTsyslistviewex::GetRegisteredSort
  72. // Description     : Read form registry in dest for Sort:ID. 
  73. // Return type : BOOL ; Return TRUE if key exist.
  74. // Argument         : CString & dest ; string to put value into
  75. BOOL CTsyslistviewex::GetRegisteredSort(CString & dest)
  76. {
  77. BOOL bResult = false;
  78. if (IsHeaderSaved())
  79. {
  80. CString secid; secid.Format(_T("Sort:%08X"), GetDlgCtrlID());
  81. CString result = AfxGetApp()->GetProfileString(LIST_SECTION, secid, _T("Default"));
  82. if (result != _T("Default"))
  83. {
  84. dest = result;
  85. bResult = true;
  86. }
  87. }
  88. return bResult;
  89. }
  90. // Function name : CTsyslistviewex::SaveHeader
  91. // Description     : Save widths and sort columns in registry in fromat:
  92. // Header:ID = Column1:C:126, ...
  93. // Sort:ID = 1D,2,3 ...
  94. // Return type : void 
  95. void CTsyslistviewex::SaveHeader()
  96. {
  97. if (IsHeaderSaved())
  98. {
  99. CString secid; secid.Format(_T("Header:%08X"), GetDlgCtrlID());
  100. AfxGetApp()->WriteProfileString(LIST_SECTION, secid, (LPCTSTR)GetHeaderString());
  101. secid.Format(_T("Sort:%08X"), GetDlgCtrlID());
  102. AfxGetApp()->WriteProfileString(LIST_SECTION, secid, (LPCTSTR)GetHeaderSortString());
  103. }
  104. }
  105. BEGIN_MESSAGE_MAP(CTsyslistviewex, CListCtrl)
  106. //{{AFX_MSG_MAP(CTsyslistviewex)
  107. ON_WM_LBUTTONDOWN()
  108. ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclick)
  109. ON_WM_CHAR()
  110. //}}AFX_MSG_MAP
  111. ON_WM_MEASUREITEM_REFLECT()
  112. END_MESSAGE_MAP()
  113. /////////////////////////////////////////////////////////////////////////////
  114. // CTsyslistviewex message handlers
  115. // Function name : CTsyslistviewex::PreSubclassWindow
  116. // Description     : Called when user subclass list control form resource
  117. // Return type : void 
  118. void CTsyslistviewex::PreSubclassWindow( )
  119. {
  120. // Must be owner draw and report mode....
  121. ModifyStyle(LVS_SMALLICON | LVS_LIST | LVS_ICON , LVS_OWNERDRAWFIXED | LVS_REPORT);
  122. m_pOldHeaderCtrl = GetDlgItem(0);
  123. // Create different fonts..
  124. if (CFont* pFont = GetFont())
  125. {
  126. LOGFONT lf;
  127. pFont->GetLogFont(&lf);
  128. lf.lfWeight = FW_BOLD;
  129. m_boldFont.CreateFontIndirect(&lf);
  130. lf.lfWeight = FW_NORMAL;
  131. lf.lfItalic = TRUE;
  132. m_italicFont.CreateFontIndirect(&lf);
  133. lf.lfWeight = FW_BOLD;
  134. lf.lfItalic = TRUE;
  135. m_italicBoldFont.CreateFontIndirect(&lf);
  136. }
  137. SetWindowLong(m_hWnd, GWL_USERDATA , LIST_SUBCLASSED);
  138. }
  139. // Function name : CTsyslistviewex::OnLButtonDown
  140. // Description     : If user click in list ctrl, test item, subItem
  141. // Return type : void 
  142. // Argument         : UINT nFlags
  143. // Argument         : CPoint point
  144. void CTsyslistviewex::OnLButtonDown(UINT nFlags, CPoint point)
  145. {
  146. SetFocus();
  147. int item = -1, subItem = -1 ;
  148. item = HitTestEx(point, subItem);
  149. CListCtrl::OnLButtonDown(nFlags, point);
  150. }
  151. // Function name : CTsyslistviewex::MakeShortString
  152. // Description     : Return shorted string lpszLong in device pDC
  153. // Return type : LPCTSTR 
  154. // Argument         : CDC* pDC
  155. // Argument         : LPCTSTR lpszLong
  156. // Argument         : int nColumnLen
  157. // Argument         : int nOffset
  158. LPCTSTR CTsyslistviewex::MakeShortString(CDC* pDC, LPCTSTR lpszLong, int nColumnLen, int nOffset)
  159. {
  160. static const TCHAR szThreeDots[] = _T("...");
  161. static TCHAR szShort[MAX_PATH];
  162. int nStringLen = strlen(lpszLong);
  163. if(nStringLen == 0 ||
  164. (pDC->GetTextExtent(lpszLong, nStringLen).cx + nOffset) <= nColumnLen)
  165. {
  166. return(lpszLong);
  167. }
  168. strcpy(szShort,lpszLong);
  169. int nAddLen = pDC->GetTextExtent(szThreeDots,strlen(szThreeDots)).cx;
  170. for(int i = nStringLen-1; i > 0; i--)
  171. {
  172. szShort[i] = '';
  173. if((pDC->GetTextExtent(szShort, i).cx + nOffset + nAddLen)
  174. <= nColumnLen)
  175. {
  176. break;
  177. }
  178. }
  179. strcat(szShort, szThreeDots);
  180. return(szShort);
  181. }
  182. // Function name : CTsyslistviewex::DrawCell
  183. // Description     : Draw at pDC in drawRect cell(nItem,nColumn) with format
  184. // Return type : void 
  185. // Argument         : CDC* pDC
  186. // Argument         : CRect& drawRect
  187. // Argument         : int nItem
  188. // Argument         : int nColumn
  189. void CTsyslistviewex::DrawCell(CDC* pDC, CRect& drawRect, DWORD format, int nItem, int nColumn)
  190. {
  191. static TCHAR szBuff[MAX_PATH];
  192. LPCTSTR pszText;
  193. GetItemText(nItem, nColumn, szBuff, sizeof(szBuff));
  194. {
  195. CTColumnBitmap* pBitmap = GetBitmapCell(GetItemData(nItem),nColumn);
  196. int dxBitmap = 0;
  197. CString sImageBitmap, sText(szBuff);
  198. if (pBitmap)
  199. {
  200. dxBitmap = min(pBitmap->GetWidth(),drawRect.Width());
  201. int p = sText.Find(m_cImageTextSeparator);
  202. sImageBitmap = sText.Left(max(0,p));
  203. sText = sText.Mid(p + 1);
  204. if (p < 0)
  205. {
  206. sImageBitmap = sText;
  207. sText.Empty();
  208. }
  209. }
  210. pszText = MakeShortString(pDC, (LPCTSTR)sText, (drawRect.right - (drawRect.left + dxBitmap + OFFSET)), OFFSET);
  211. if (*pszText != TCHAR(''))
  212. {
  213. UINT nJustify = DT_LEFT;    
  214. if(pszText == sText)
  215. {
  216. switch(format & LVCFMT_JUSTIFYMASK)
  217. {
  218. case LVCFMT_RIGHT:
  219. nJustify = DT_RIGHT;
  220. break;
  221. case LVCFMT_CENTER:
  222. nJustify = DT_CENTER;
  223. break;
  224. default:
  225. break;
  226. }
  227. }
  228. drawRect.left = drawRect.left + dxBitmap + OFFSET;
  229. pDC->DrawText(pszText, -1, drawRect, nJustify | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
  230. drawRect.left = drawRect.left -(dxBitmap + OFFSET);
  231. }
  232. if (dxBitmap)
  233. {
  234. int nImageColumn = atoi(sImageBitmap);
  235. int x = drawRect.left;
  236. CRect rectImage = pBitmap->GetRectImage(nImageColumn);
  237. pBitmap->Put(nImageColumn, pDC, x , drawRect.top + (drawRect.Height() - rectImage.Height())/2, dxBitmap);
  238. }
  239. }
  240. }
  241. // Function name : CTsyslistviewex::DrawItemGrid
  242. // Description     : Draw item with grid lines
  243. // Return type : void 
  244. // Argument         : LPDRAWITEMSTRUCT lpDrawItemStruct
  245. void CTsyslistviewex::DrawItemGrid(LPDRAWITEMSTRUCT lpDrawItemStruct)
  246. {
  247. // device contextul itemului
  248. CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
  249. // dreptunghiul corespunzator itemului
  250. CRect rcItem(lpDrawItemStruct->rcItem);
  251. // identificatorul itemului
  252. int nItem = lpDrawItemStruct->itemID;
  253. BYTE value = 0;
  254. CFont* pOldFont = NULL;
  255. if (m_mapRowsBold.Lookup(lpDrawItemStruct->itemData, value))
  256. pOldFont = (CFont*)pDC->SelectObject(&m_boldFont);
  257. if (m_mapRowsItalic.Lookup(lpDrawItemStruct->itemData, value))
  258. {
  259. CFont* pF = (CFont*)pDC->SelectObject(&m_italicFont);
  260. if (pOldFont)
  261. pF = (CFont*)pDC->SelectObject(&m_italicBoldFont);
  262. else
  263. pOldFont = pF;
  264. }
  265. // culori
  266. COLORREF clrTextSave, clrBkSave;
  267. // get item data
  268. LV_ITEM lvi;
  269. lvi.mask = LVIF_STATE;
  270. lvi.iItem = nItem;
  271. lvi.iSubItem = 0;
  272. lvi.stateMask = 0xFFFF; // get all state flags
  273. GetItem(&lvi);
  274. BOOL bFocus = ((lvi.state & LVIS_FOCUSED) == LVIS_FOCUSED);
  275. BOOL bSelected = (GetStyle() & LVS_SHOWSELALWAYS) && (lvi.state & LVIS_SELECTED);
  276. bSelected = bSelected || (lvi.state & LVIS_DROPHILITED);
  277. // set colors if item is selected
  278. CRect rcAllLabels;
  279. GetItemRect(nItem, rcAllLabels, LVIR_BOUNDS);
  280. if (bSelected)
  281. {
  282. clrTextSave = pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
  283. clrBkSave = pDC->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
  284. }
  285. pDC->FillRect(rcAllLabels, &CBrush(::GetSysColor(bSelected ? COLOR_HIGHLIGHT : COLOR_WINDOW)));
  286. // draw item
  287. CBrush brush(RGB(128,128,128));
  288. GetItemRect(nItem, rcItem, LVIR_LABEL);
  289. LV_COLUMN lvc;
  290.  lvc.mask = LVCF_FMT | LVCF_WIDTH;
  291. rcItem.OffsetRect(-OFFSET,0);
  292. for(int nColumn = 0; GetColumn(nColumn, &lvc); nColumn++)
  293. {
  294. rcItem.right = rcItem.left + lvc.cx;
  295. CRect drawRect(rcItem);
  296. drawRect.InflateRect(-1,-1);
  297. pDC->FrameRect(drawRect, &brush);
  298. drawRect.OffsetRect(1,0);
  299. drawRect.InflateRect(-2,0);
  300. DrawCell(pDC,drawRect,lvc.fmt, nItem,nColumn);
  301. rcItem.left = rcItem.right;
  302. }
  303. pDC->SelectObject(pOldFont);
  304. // draw focus rectangle if item has focus
  305. if (bFocus)
  306. pDC->DrawFocusRect(rcAllLabels);
  307. // set original colors if item was selected
  308. if (bSelected)
  309. {
  310. pDC->SetTextColor(clrTextSave);
  311. pDC->SetBkColor(clrBkSave);
  312. }
  313. }
  314. // Function name : CTsyslistviewex::DrawItemNoGrid
  315. // Description     : Draw item without grid lines.
  316. // Return type : void 
  317. // Argument         : LPDRAWITEMSTRUCT lpDrawItemStruct
  318. void CTsyslistviewex::DrawItemNoGrid(LPDRAWITEMSTRUCT lpDrawItemStruct)
  319. {
  320. // device contextul itemului
  321. CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
  322. // dreptunghiul corespunzator itemului
  323. CRect rcItem(lpDrawItemStruct->rcItem);
  324. // identificatorul itemului
  325. int nItem = lpDrawItemStruct->itemID;
  326. BYTE value = 0;
  327. CFont* pOldFont = NULL;
  328. if (m_mapRowsBold.Lookup(lpDrawItemStruct->itemData, value))
  329. pOldFont = (CFont*)pDC->SelectObject(&m_boldFont);
  330. if (m_mapRowsItalic.Lookup(lpDrawItemStruct->itemData, value))
  331. {
  332. CFont* pF = (CFont*)pDC->SelectObject(&m_italicFont);
  333. if (pOldFont)
  334. pF = (CFont*)pDC->SelectObject(&m_italicBoldFont);
  335. else
  336. pOldFont = pF;
  337. }
  338. // culori
  339. COLORREF clrTextSave, clrBkSave;
  340. // get item data
  341. LV_ITEM lvi;
  342. lvi.mask = LVIF_STATE;
  343. lvi.iItem = nItem;
  344. lvi.iSubItem = 0;
  345. lvi.stateMask = 0xFFFF; // get all state flags
  346. GetItem(&lvi);
  347. BOOL bFocus = ((lvi.state & LVIS_FOCUSED) == LVIS_FOCUSED);
  348. BOOL bSelected = (GetStyle() & LVS_SHOWSELALWAYS) && (lvi.state & LVIS_SELECTED);
  349. bSelected = bSelected || (lvi.state & LVIS_DROPHILITED);
  350. // set colors if item is selected
  351. CRect rcAllLabels;
  352. GetItemRect(nItem, rcAllLabels, LVIR_BOUNDS);
  353. if (bSelected)
  354. {
  355. clrTextSave = pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
  356. clrBkSave = pDC->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
  357. }
  358. pDC->FillRect(rcAllLabels, &CBrush(::GetSysColor(bSelected ? COLOR_HIGHLIGHT : COLOR_WINDOW)));
  359. // draw item
  360. CBrush brush(RGB(0,0,0));
  361. GetItemRect(nItem, rcItem, LVIR_LABEL);
  362. LV_COLUMN lvc;
  363.  lvc.mask = LVCF_FMT | LVCF_WIDTH;
  364. rcItem.OffsetRect(-OFFSET,0);
  365. for(int nColumn = 0; GetColumn(nColumn, &lvc); nColumn++)
  366. {
  367. rcItem.right = rcItem.left + lvc.cx;
  368. CRect drawRect(rcItem);
  369. drawRect.InflateRect(-1,-1);
  370. drawRect.OffsetRect(2,0);
  371. drawRect.InflateRect(-4,0);
  372. DrawCell(pDC,drawRect,lvc.fmt, nItem,nColumn);
  373. rcItem.left = rcItem.right;
  374. }
  375. pDC->SelectObject(pOldFont);
  376. // draw focus rectangle if item has focus
  377. if (bFocus)
  378. pDC->DrawFocusRect(rcAllLabels);
  379. // set original colors if item was selected
  380. if (bSelected)
  381. {
  382. pDC->SetTextColor(clrTextSave);
  383. pDC->SetBkColor(clrBkSave);
  384. }
  385. }
  386. // Function name : CTsyslistviewex::DrawItem
  387. // Description     : Draw one item. m_fctDrawItem is set in ViewGridLines(BOOL bEnable ).
  388. // Return type : void 
  389. // Argument         : LPDRAWITEMSTRUCT lpDrawItemStruct
  390. void CTsyslistviewex::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
  391. {
  392. (this->*m_fctDrawItem)(lpDrawItemStruct);
  393. }
  394. // Function name : CTsyslistviewex::HitTestEx
  395. // Description     : Check if point is in on of list's cell. Return row(return value) an column (subItem)
  396. // Return type : int 
  397. // Argument         : CPoint point
  398. // Argument         : int& subItem
  399. int CTsyslistviewex::HitTestEx(CPoint point, int& subItem)
  400. {
  401. CRect rect; int item = -1;
  402. subItem = -1;
  403. if (GetItemRect(0, rect, LVIR_LABEL))
  404. {
  405. CRect hRect = rect;
  406. hRect.OffsetRect((abs(hRect.left) - hRect.left)/2,0);
  407. item = HitTest(CPoint(int((hRect.left + hRect.right)/2), point.y));
  408. }
  409. if (item>=0)
  410. {
  411. int ccx = rect.left;
  412. LV_COLUMN lvc;lvc.mask = LVCF_WIDTH;
  413. for(int nColumn = 0; GetColumn(nColumn, &lvc); nColumn++, ccx += lvc.cx)
  414. if ((point.x >= ccx) && (point.x < ccx + lvc.cx))
  415. {
  416. subItem = nColumn;
  417. break;
  418. }
  419. }
  420. item = subItem >= 0 ? item : -1;
  421. return item;
  422. }
  423. // Function name : CTsyslistviewex::GetSubItemRect
  424. // Description     : Return the rect of subitem subItem
  425. // Return type : BOOL ; TRUE if succeeded
  426. // Argument         : int item ; item - row position
  427. // Argument         : int subItem ; subItem - column position 
  428. // Argument         : CRect & rect ; CRect to complete
  429. BOOL CTsyslistviewex::GetSubItemRect(int item, int subItem, CRect & rect)
  430. {
  431. if (subItem >= 0)
  432. if (GetItemRect(item, rect, LVIR_LABEL))
  433. {
  434. int ccx = rect.TopLeft().x;
  435. LV_COLUMN lvc;lvc.mask = LVCF_WIDTH;
  436. if (GetColumn(subItem, &lvc))
  437. {
  438. int dx = lvc.cx;
  439. for (int nColumn = 0; nColumn < subItem && GetColumn(nColumn, &lvc); nColumn++)
  440. ccx += lvc.cx;
  441. rect = CRect(CPoint(ccx,rect.TopLeft().y),CPoint(ccx + dx,rect.BottomRight().y));
  442. return TRUE;
  443. }
  444. }
  445. return FALSE;
  446. }
  447. // Function name : CTsyslistviewex::MeasureItem
  448. // Description     : see contructor CTsyslistviewex(int nHeightRel)
  449. // Return type : void 
  450. // Argument         : LPMEASUREITEMSTRUCT lpMeasureItem ; finds StructHeight of item needed to set m_nHeightRel
  451. void CTsyslistviewex::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
  452. {
  453. lpMeasureItemStruct->itemHeight += m_nHeightRel;
  454. }
  455. // Function name : CTsyslistviewex::ViewGridLines
  456. // Description     : Enable or disable draw grid lines.
  457. // Return type : void 
  458. // Argument         : BOOL bEnable ; TRUE to enable
  459. void CTsyslistviewex::ViewGridLines(BOOL bEnable )
  460. {
  461. m_fctDrawItem = bEnable ? CTsyslistviewex::DrawItemGrid : CTsyslistviewex::DrawItemNoGrid;
  462. Invalidate();
  463. }
  464. // Function name : CTsyslistviewex::ExpandHeader
  465. // Description     : Try to put all columns from list control in client rect.
  466. // Return type : void 
  467. void CTsyslistviewex::ExpandHeader()
  468. {
  469. const offsetMarginHeader = 8;
  470. CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
  471. CRect rect; GetClientRect(rect);
  472. int dxRect = rect.Width() - 2;
  473. int dxHeader = 0, i = 0; BOOL bColumn = true;
  474. int nLastColumn = pHeader->GetItemCount() - 1;
  475. if (nLastColumn >= 0)
  476. {
  477. HD_ITEM item; item.mask = HDI_WIDTH;
  478. for (i = 0; i < nLastColumn && (pHeader->GetItem(i, &item)); i++)
  479. dxHeader += item.cxy ;
  480. BOOL bStop = false;
  481. do
  482. {
  483. pHeader->GetItem(nLastColumn, &item);
  484. int icx = dxRect - dxHeader;
  485. bStop = icx >=0;
  486. if (!bStop)
  487. icx = offsetMarginHeader / 2;
  488. item.cxy = icx;
  489. pHeader->SetItem(nLastColumn, &item);
  490. if (bStop)
  491. return;
  492. ASSERT (icx >= 0);
  493. nLastColumn--;
  494. pHeader->GetItem(nLastColumn, &item);
  495. dxHeader = dxHeader - item.cxy + icx;
  496. }
  497. while (nLastColumn>=0);
  498. }
  499. }
  500. // Function name : CTsyslistviewex::AddSortCallBack
  501. // Description     : Attach to an column nColumn
  502. //   comparing function:
  503. // typedef int (*COLUMNCALLBACKCOMPARE) (const wchar_t *stringi, const wchar_t *stringj)
  504. //   return values:
  505. // -1 for stringi < stringj
  506. //  0 for stringi == stringj
  507. // +1 for stringi > stringj
  508. // Return type : void 
  509. // Argument         : int nColumn
  510. // Argument         : COLUMNCALLBACKCOMPARE pCallBack
  511. void CTsyslistviewex::AddSortCallBack(int nColumn, COLUMNCALLBACKCOMPARE pCallBack)
  512. {
  513. // Already u must call EnableSort...
  514. ASSERT (m_sortColumns.m_pListCtrl == this);
  515. // pCallBack must be nenul...
  516. ASSERT (pCallBack != NULL);
  517. m_sortColumns.Add(nColumn, pCallBack);
  518. }
  519. // Function name : CTsyslistviewex::EnableSaveHeader
  520. // Description     : Enable or disable save widths of listctrl
  521. //   Must call it before attach this list control attach to record set
  522. //   (!)In InitInstance, u must call: SetRegistryKey(AfxGetAppName());
  523. // Return type : void 
  524. // Argument         : BOOL bEnable ; TRUE to enable
  525. void CTsyslistviewex::EnableSaveHeader(BOOL bEnable)
  526. {
  527. // The control must already subclassed....
  528. ASSERT ((GetWindowLong(m_hWnd, GWL_USERDATA) & LIST_MASKCLASS) == LIST_SUBCLASSED);
  529. m_bSaveHeader = bEnable;
  530. }
  531. // Function name : CTsyslistviewex::EnableSort
  532. // Description     : Enable or disable sort procedure.
  533. // Return type : void 
  534. // Argument         : BOOL bEnable ; TRUE to enable
  535. void CTsyslistviewex::EnableSort(BOOL bEnable)
  536. {
  537. CWnd* pWnd = bEnable ? &m_wndSortHeaderEx : m_pOldHeaderCtrl;
  538. pWnd->SubclassDlgItem(0,this);
  539. m_bSorted = bEnable;
  540. m_sortColumns.AttachControl(bEnable ? this : NULL);
  541. }
  542. // Function name : CTsyslistviewex::OnColumnclick
  543. // Description     : SortClick handler (if m_bSortWhenClickHeader is set)
  544. // Return type : void 
  545. // Argument         : NMHDR* pNMHDR
  546. // Argument         : LRESULT* pResult
  547. void CTsyslistviewex::OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult) 
  548. {
  549. NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
  550. *pResult = 0;
  551. if (m_bSorted)
  552. {
  553. GetAsyncKeyState(VK_CONTROL);
  554. BOOL bControl = GetAsyncKeyState(VK_CONTROL);
  555. int iNewSortColumn = pNMListView->iSubItem;
  556. BOOL bAsc = true;
  557. int nPosition = 0;
  558. BOOL bSortedColumn = m_wndSortHeaderEx.GetColumnOrder(iNewSortColumn, bAsc, nPosition);
  559. if (!bControl && !bSortedColumn)
  560. m_wndSortHeaderEx.ResetSortColumns();
  561. if (bSortedColumn)
  562. if (!bAsc)
  563. {
  564. m_wndSortHeaderEx.DeleteColumnOrder(iNewSortColumn);
  565. iNewSortColumn = -1;
  566. }
  567. else
  568. bAsc = !bAsc;
  569. if (iNewSortColumn >= 0)
  570. m_wndSortHeaderEx.SetColumnOrder(iNewSortColumn, bAsc);
  571. if (m_bSortWhenClickHeader)
  572. SortAllItems();
  573. }
  574. }
  575. // Function name : CTsyslistviewex::AttachBitmap
  576. // Description     : Attach a bitmap image to a column
  577. // Return type : BOOL 
  578. // Argument         : int nColumn ; column to put immage into
  579. // Argument         : UINT nIDBitmap ; bitmap identifier
  580. // Argument         : int nImageWidth ; bitmap width
  581. // Argument         : int nImageHeight ; bitmap height
  582. // Argument         : int nRowImage ; sub-bitmap index (for multi-icon bitmaps)
  583. BOOL CTsyslistviewex::AttachBitmap(int nColumn, UINT nIDBitmap, int nImageWidth, int nImageHeight, int nRowImage)
  584. {
  585. CTColumnBitmap* pBitmap = NULL;
  586. if (pBitmap = new CTColumnBitmap(nIDBitmap, nImageWidth, nImageHeight, nRowImage))
  587. {
  588. ASSERT(pBitmap->IsLoad());
  589. if (CTColumnBitmap* pOldBitmap = GetBitmapColumn(nColumn))
  590. delete pOldBitmap;
  591. m_bmpColumns[nColumn] = pBitmap;
  592. return TRUE;
  593. }
  594. return FALSE;
  595. }
  596. // Function name : CTHxgrid::ComposeKeyForCell
  597. // Description     : Return a key identifier for search in maps.
  598. // Return type : DWORD 
  599. // Argument         : short nIDRow
  600. // Argument         : short nColumn
  601. DWORD CTsyslistviewex::ComposeKeyForCell(USHORT nIDRow, USHORT nColumn)
  602. {
  603. return MAKELONG(nColumn,nIDRow);
  604. }
  605. // Function name : CTsyslistviewex::AttachBitmapCell
  606. // Description     : Attach a bitmap to a cell.
  607. // Return type : BOOL 
  608. // Argument         : USHORT nIDRow - cell is on item witch contain in userdata nIDRow
  609. // Argument         : USHORT nColumn - cell is on column nColumn
  610. // Argument         : UINT nIDBitmap - Resource identifier of bitmap.
  611. // Argument         : int nImageWidth - Width of bitmap cell.
  612. // Argument         : int nImageHeight - Height of bitmap cell
  613. // Argument         : int nRowImage - sub-bitmap index (for multi-icon bitmaps)
  614. BOOL CTsyslistviewex::AttachBitmapCell(USHORT nIDRow, USHORT nColumn, UINT nIDBitmap, int nImageWidth, int nImageHeight, int nRowImage)
  615. {
  616. CTColumnBitmap* pBitmap = NULL;
  617. if (pBitmap = new CTColumnBitmap(nIDBitmap, nImageWidth, nImageHeight, nRowImage))
  618. {
  619. ASSERT(pBitmap->IsLoad());
  620. if (CTColumnBitmap* pOldBitmap = GetBitmapCell(nIDRow,nColumn))
  621. delete pOldBitmap;
  622. m_bmpCells[ComposeKeyForCell(nIDRow, nColumn)] = pBitmap;
  623. return TRUE;
  624. }
  625. return FALSE;
  626. }
  627. // Function name : CTsyslistviewex::GetBitmapColumn
  628. // Description     : Return pointer to CTColumnBitmap object if nColumn is registered
  629. // as column of bitmaps.
  630. // Return type : CTColumnBitmap* 
  631. // Argument         : int nColumn
  632. CTColumnBitmap* CTsyslistviewex::GetBitmapColumn(int nColumn)
  633. {
  634. CTColumnBitmap* pOldBitmap = NULL;
  635. m_bmpColumns.Lookup(nColumn, pOldBitmap);
  636. return pOldBitmap;
  637. }
  638. // Function name : CTsyslistviewex::GetBitmapCell
  639. // Description     : Return pointer to CTColumnBitmap object if cell from (Item with nIDRow userdata,nColumn) is registered
  640. // as bitmap cell.
  641. // Return type : CTColumnBitmap* 
  642. // Argument         : DWORD nIDRow
  643. // Argument         : int nColumn
  644. CTColumnBitmap* CTsyslistviewex::GetBitmapCell(DWORD nIDRow, int nColumn)
  645. {
  646. CTColumnBitmap* pOldBitmap = GetBitmapColumn(nColumn);
  647. if (pOldBitmap == NULL)
  648. m_bmpCells.Lookup(ComposeKeyForCell((USHORT)nIDRow,(USHORT)nColumn), pOldBitmap);
  649. return pOldBitmap;
  650. }
  651. // Function name : CTsyslistviewex::SortAllItems
  652. // Description     : Call sort items specified by lpszColumnsSort. lpszColumnsSort can be: _T("0,2D,1A"),
  653. //   and this means that order of sort is column 0 ascending, the next, 2 descending
  654. //   This procedure take all column for order from lpszColumnsSort, and reset old
  655. //   columns sort.
  656. //   (!) Stop relay event in all recordsets in SortAllItems().
  657. // Return type : void 
  658. // Argument         : LPCTSTR lpszColumnsSort
  659. void CTsyslistviewex::SortAllItems(LPCTSTR lpszColumnsSort)
  660. {
  661. // Already call EnableSort...
  662. ASSERT ( m_bSorted );
  663. LPCTSTR lpszCurrentColumnsSort = lpszColumnsSort;
  664. CString sRegisterColumnsSort; sRegisterColumnsSort.Empty();
  665. if (GetRegisteredSort(sRegisterColumnsSort))
  666. lpszCurrentColumnsSort = (LPCTSTR)sRegisterColumnsSort;
  667. CString column; int i = 0;
  668. m_wndSortHeaderEx.ResetSortColumns();
  669. do 
  670. {
  671. AfxExtractSubString(column, lpszCurrentColumnsSort, i++, ',');
  672. if (!column.IsEmpty())
  673. {
  674. TCHAR cAsc = column[column.GetLength()-1];
  675. BOOL bAsc = true;
  676. if (!iswdigit(cAsc))
  677. {
  678. ASSERT (cAsc == 'A' || cAsc == 'D');
  679. if (cAsc == 'D')
  680. bAsc = !bAsc;
  681. column = column.Left(column.GetLength()-1);
  682. }
  683. int nColumn = atoi((LPCTSTR)column);
  684. m_wndSortHeaderEx.SetColumnOrder(nColumn, bAsc);
  685. }
  686. }
  687. while (!column.IsEmpty());
  688. SortAllItems();
  689. }
  690. // Function name : CTsyslistviewex::SortAllItems
  691. // Description     : sort all items according to header flags
  692. //   (!) Stop relay event in all recordsets.
  693. // Return type : void 
  694. void CTsyslistviewex::SortAllItems()
  695. {
  696. ASSERT ( m_bSorted );
  697. m_sortColumns.ResetOrderColumn();
  698. int column = 0;
  699. BOOL bAsc = true;
  700. for (int iPosition = 1; m_wndSortHeaderEx.GetPositionColumn(iPosition, bAsc, column); iPosition++ )
  701. m_sortColumns.AddOrderColumn(column,bAsc ? 1 : -1);
  702. if (m_sortColumns.GetCountOrderColumn())
  703. {
  704. AfxGetApp()->DoWaitCursor(1);
  705. m_sortColumns.Sort();
  706. AfxGetApp()->DoWaitCursor(-1);
  707. }
  708. SaveHeader();
  709. }
  710. // Function name : CTsyslistviewex::GetCountColumn
  711. // Description     : Return number of columns from control.
  712. // Return type : int ; columns count
  713. int CTsyslistviewex::GetCountColumn()
  714. {
  715. return ((CHeaderCtrl*)GetDlgItem(0))->GetItemCount();
  716. }
  717. // Function name : CTsyslistviewex::Progress
  718. // Description     : displays the progress bar
  719. // Return type : void 
  720. // Argument         : int nPercent ; 0 - progress bar set top middle, 100 progress bar is off
  721. void CTsyslistviewex::Progress(int nPercent)
  722. {
  723. if (!m_wndProgress.GetSafeHwnd())
  724. {
  725. const int dyProgress = 20;
  726. CRect rect; GetWindowRect(rect);
  727. ScreenToClient(rect);
  728. int dxProgress = rect.Width() * 3 / 4;
  729. rect.top += (rect.Height() - dyProgress) / 2;
  730. rect.bottom = rect.top + dyProgress ;
  731. rect.left += (rect.Width() - dxProgress) / 2;
  732. rect.right = rect.left + dxProgress;
  733. m_wndProgress.Create(WS_CHILD | WS_BORDER | WS_VISIBLE, rect, this, GetDlgCtrlID());
  734. }
  735. m_wndProgress.SetPos(nPercent);
  736. if (nPercent == 100)
  737. m_wndProgress.DestroyWindow();
  738. }
  739. // Function name : CTsyslistviewex::ResetBoldLines
  740. // Description     : reset all bold lines
  741. // Return type : void 
  742. void CTsyslistviewex::ResetBoldLines()
  743. {
  744. m_mapRowsBold.RemoveAll();
  745. }
  746. // Function name : CTsyslistviewex::SetBoldRow
  747. // Description     : If lParam == NULL then set bold for focused line.
  748. // Return type : void 
  749. // Argument         : LPARAM lParam
  750. // Argument         : BOOL bBold
  751. // Argument         : BOOL bInvalidate
  752. void CTsyslistviewex::SetBoldRow(LPARAM lParam, BOOL bBold, BOOL bInvalidate)
  753. {
  754. if (m_boldFont.GetSafeHandle())
  755. {
  756. if (!lParam)
  757. lParam = GetItemData(GetNextItem(-1, LVNI_FOCUSED));
  758. if (bBold)
  759. m_mapRowsBold[lParam] = 1;
  760. else
  761. m_mapRowsBold.RemoveKey(lParam);
  762. if (bInvalidate)
  763. Invalidate(false);
  764. }
  765. }
  766. // Function name : CTsyslistviewex::SetItalicRow
  767. // Description     : If lParam == NULL then set italic for focused line.
  768. // Return type : void 
  769. // Argument         : LPARAM lParam
  770. // Argument         : BOOL bItalic
  771. // Argument         : BOOL bInvalidate
  772. void CTsyslistviewex::SetItalicRow(LPARAM lParam, BOOL bItalic, BOOL bInvalidate)
  773. {
  774. if (m_italicFont.GetSafeHandle())
  775. {
  776. if (!lParam)
  777. lParam = GetItemData(GetNextItem(-1, LVNI_FOCUSED));
  778. if (bItalic)
  779. m_mapRowsItalic[lParam] = 1;
  780. else
  781. m_mapRowsItalic.RemoveKey(lParam);
  782. if (bInvalidate)
  783. Invalidate(false);
  784. }
  785. }
  786. // Function name : CTsyslistviewex::DeselectAll
  787. // Description     : Deselect all items from control
  788. // Return type : void 
  789. void CTsyslistviewex::DeselectAll()
  790. {
  791. int iCurrent = GetNextItem(-1, LVIS_SELECTED);
  792. while (iCurrent >= 0)
  793. {
  794. SetItemState(iCurrent, ~LVIS_SELECTED, LVIS_SELECTED);
  795. iCurrent = GetNextItem(iCurrent, LVIS_SELECTED);
  796. }
  797. }
  798. // Function name : CTsyslistviewex::SelectItem
  799. // Description     : Deselect all items, and select one item.
  800. // Return type : void 
  801. // Argument         : int i ; item index
  802. void CTsyslistviewex::SelectItem(int i)
  803. {
  804. DeselectAll();
  805. SetItemState(i, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
  806. EnsureVisible(i,false);
  807. }
  808. // Function name : CTsyslistviewex::GetHeaderSortString
  809. // Description     : Called in SaveAllItems(), returns header format string
  810. // Return type : CString ; sort header as string, for save it in the registry
  811. CString CTsyslistviewex::GetHeaderSortString()
  812. {
  813. CString result; result.Empty();
  814. if (m_bSorted)
  815. {
  816. int nPosition = 1;
  817. int nColumn = NULL;
  818. BOOL bAsc = true;
  819. while (m_wndSortHeaderEx.GetPositionColumn(nPosition++, bAsc, nColumn))
  820. {
  821. CString sColumn; sColumn.Format(_T("%i%s,"),nColumn, (bAsc ? _T("") : _T("D")));
  822. result += sColumn;
  823. }
  824. if (!result.IsEmpty())
  825. result = result.Left(result.GetLength() - 1);
  826. }
  827. return result;
  828. }
  829. // Function name : CTsyslistviewex::GetHeaderString
  830. // Description     : Return the header format string
  831. // Return type : CString ; header formated as: ColumnName1:FormatColumn1:WidthColumn1,...
  832. CString CTsyslistviewex::GetHeaderString()
  833. {
  834. CString result; result.Empty();
  835. LV_COLUMN column; 
  836.    TCHAR pszText[MAX_PATH];
  837.  column.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH;
  838.  column.pszText = pszText;
  839.  column.cchTextMax = MAX_PATH;
  840. for (int i = 0; GetColumn(i, &column); i++)
  841. {
  842. TCHAR f = TCHAR('L');
  843. switch (column.fmt & LVCFMT_JUSTIFYMASK)
  844. {
  845. case LVCFMT_RIGHT:
  846. f = TCHAR('R');
  847. break;
  848. case LVCFMT_CENTER:
  849. f = TCHAR('C');
  850. break;
  851. }
  852. CString w; w.Format(_T("%i"), column.cx);
  853. result = result + column.pszText + TCHAR(':') + w + TCHAR(':') + f + TCHAR(',');
  854. column.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH;
  855. }
  856. return result.Left(result.GetLength() - (result.IsEmpty() ? 0 : 1)); // last ,
  857. }
  858. // Function name : CTsyslistviewex::OnNotify
  859. // Description     : Called when item width changed. If necessarly the widths are saved in registry.
  860. // Return type : BOOL 
  861. // Argument         : WPARAM wParam
  862. // Argument         : LPARAM lParam
  863. // Argument         : LRESULT* pResult
  864. BOOL CTsyslistviewex::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) 
  865. {
  866. if ((int)wParam == 0)
  867. if (GetDlgItem(0)->IsWindowVisible())
  868. {
  869. switch (((HD_NOTIFY*)lParam)->hdr.code)
  870. {
  871. case HDN_ITEMCHANGEDA:
  872. case HDN_ITEMCHANGEDW:
  873. SaveHeader();
  874. break;
  875. }
  876. }
  877. return CListCtrl::OnNotify(wParam, lParam, pResult);
  878. }
  879. // Function name : CTsyslistviewex::NeedCX
  880. // Description     : Calc total width of listctrl
  881. // Return type : int ; listctrl width
  882. int CTsyslistviewex::NeedCX()
  883. {
  884. int result = 0;
  885. LV_COLUMN lvc; lvc.mask = LVCF_WIDTH;
  886. for (int i = 0; GetColumn(i, &lvc); i++)
  887. result += lvc.cx;
  888. return result;
  889. }
  890. // Function name : CTsyslistviewex::NeedCY
  891. // Description     : Calc partial visible height of listctrl
  892. // Return type : int ; visible height of listctrl
  893. int CTsyslistviewex::NeedCY()
  894. {
  895. CRect rect; GetClientRect(rect); int hRect = rect.Height();
  896. CRect rcItem;
  897. int result = 0;
  898. for (int i = GetTopIndex(); GetItemRect(i, rcItem,LVIR_LABEL) && result + rcItem.Height() < hRect; i++ )
  899. result += rcItem.Height();
  900. return result;
  901. }
  902. // Function name : CTsyslistviewex::OnChar
  903. // Description     : Treat specialy CTRL+S for sorting, if m_bSortWhenClickHeader is FALSE
  904. // Return type : void 
  905. // Argument         : UINT nChar
  906. // Argument         : UINT nRepCnt
  907. // Argument         : UINT nFlags
  908. void CTsyslistviewex::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
  909. {
  910. if (!m_bSortWhenClickHeader)
  911. if (GetKeyState(VK_CONTROL) < 0)
  912. if (nChar == scanCodeS)
  913. SortAllItems();
  914. CListCtrl::OnChar(nChar, nRepCnt, nFlags);
  915. }
  916. // Function name : CTsyslistviewex::GetCountRowsBold
  917. // Description     : Return count of bold rows
  918. // Return type : int 
  919. int CTsyslistviewex::GetCountRowsBold()
  920. {
  921. return m_mapRowsBold.GetCount();
  922. }
  923. // Function name : CTsyslistviewex::GetCountRowsItalic
  924. // Description     : Return count of italic rows
  925. // Return type : int 
  926. int CTsyslistviewex::GetCountRowsItalic()
  927. {
  928. return m_mapRowsItalic.GetCount();
  929. }
  930. // Function name : CTsyslistview32::SetHeader
  931. // Description     : 
  932. // Return type : BOOL 
  933. // Argument         : CListCtrl * pList
  934. // Argument         : CString newHeader
  935. BOOL CTsyslistviewex::SetHeader(CListCtrl * pList, CString newHeader)
  936. {
  937. CHeaderCtrl* pHeader = (CHeaderCtrl*)pList->GetDlgItem(0);
  938. if (pHeader)
  939. {
  940. while (pHeader->GetItemCount()) pHeader->DeleteItem(0);
  941. int i = 0; CString rString; rString.Empty();
  942. CMap<TCHAR,TCHAR,int,int> justifyMap;
  943. justifyMap['L'] = LVCFMT_LEFT;
  944. justifyMap['C'] = LVCFMT_CENTER;
  945. justifyMap['R'] = LVCFMT_RIGHT;
  946. do
  947. {
  948. AfxExtractSubString(rString, newHeader, i, ',');
  949. if (!rString.IsEmpty())
  950. {
  951. CString columnName;
  952. AfxExtractSubString(columnName, rString, 0, ':');
  953. CString columnWidth;
  954. AfxExtractSubString(columnWidth, rString, 1, ':');
  955. if (columnWidth.IsEmpty()) columnWidth = _T("128"); // default value
  956. CString columnJustify;
  957. AfxExtractSubString(columnJustify, rString, 2, ':');
  958. int justify = LVCFMT_LEFT;
  959. if (!columnJustify.IsEmpty())
  960. justifyMap.Lookup(columnJustify[0], justify);
  961. pList->InsertColumn(i,columnName, justify, _wtoi((const wchar_t*)columnWidth.GetBuffer(0)));
  962. i++;
  963. }
  964. } while (!rString.IsEmpty());
  965. }
  966. return (pHeader != NULL);
  967. }