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

ActiveX/DCOM/ATL

开发平台:

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::AttachIconCell
  628. // Description     : Attach icon to a cell.
  629. // Return type : BOOL 
  630. // Argument         : USHORT nIDRow
  631. // Argument         : USHORT nColumn
  632. // Argument         : HICON hIcon
  633. // Argument         : BOOL bBigIcon
  634. BOOL CTsyslistviewex::AttachIconCell(USHORT nIDRow, USHORT nColumn, HICON hIcon, BOOL bBigIcon)
  635. {
  636. CTCellIcon* pBitmap = NULL;
  637. if (pBitmap = new CTCellIcon(hIcon,bBigIcon))
  638. {
  639. if (CTColumnBitmap* pOldBitmap = GetBitmapCell(nIDRow,nColumn))
  640. delete pOldBitmap;
  641. m_bmpCells[ComposeKeyForCell(nIDRow, nColumn)] = (CTColumnBitmap*)pBitmap;
  642. return TRUE;
  643. }
  644. return FALSE;
  645. }
  646. // Function name : CTsyslistviewex::GetBitmapColumn
  647. // Description     : Return pointer to CTColumnBitmap object if nColumn is registered
  648. // as column of bitmaps.
  649. // Return type : CTColumnBitmap* 
  650. // Argument         : int nColumn
  651. CTColumnBitmap* CTsyslistviewex::GetBitmapColumn(int nColumn)
  652. {
  653. CTColumnBitmap* pOldBitmap = NULL;
  654. m_bmpColumns.Lookup(nColumn, pOldBitmap);
  655. return pOldBitmap;
  656. }
  657. // Function name : CTsyslistviewex::GetBitmapCell
  658. // Description     : Return pointer to CTColumnBitmap object if cell from (Item with nIDRow userdata,nColumn) is registered
  659. // as bitmap cell.
  660. // Return type : CTColumnBitmap* 
  661. // Argument         : DWORD nIDRow
  662. // Argument         : int nColumn
  663. CTColumnBitmap* CTsyslistviewex::GetBitmapCell(DWORD nIDRow, int nColumn)
  664. {
  665. CTColumnBitmap* pOldBitmap = GetBitmapColumn(nColumn);
  666. if (pOldBitmap == NULL)
  667. m_bmpCells.Lookup(ComposeKeyForCell((USHORT)nIDRow,(USHORT)nColumn), pOldBitmap);
  668. return pOldBitmap;
  669. }
  670. // Function name : CTsyslistviewex::SortAllItems
  671. // Description     : Call sort items specified by lpszColumnsSort. lpszColumnsSort can be: _T("0,2D,1A"),
  672. //   and this means that order of sort is column 0 ascending, the next, 2 descending
  673. //   This procedure take all column for order from lpszColumnsSort, and reset old
  674. //   columns sort.
  675. //   (!) Stop relay event in all recordsets in SortAllItems().
  676. // Return type : void 
  677. // Argument         : LPCTSTR lpszColumnsSort
  678. void CTsyslistviewex::SortAllItems(LPCTSTR lpszColumnsSort)
  679. {
  680. // Already call EnableSort...
  681. ASSERT ( m_bSorted );
  682. LPCTSTR lpszCurrentColumnsSort = lpszColumnsSort;
  683. CString sRegisterColumnsSort; sRegisterColumnsSort.Empty();
  684. if (GetRegisteredSort(sRegisterColumnsSort))
  685. lpszCurrentColumnsSort = (LPCTSTR)sRegisterColumnsSort;
  686. CString column; int i = 0;
  687. m_wndSortHeaderEx.ResetSortColumns();
  688. do 
  689. {
  690. AfxExtractSubString(column, lpszCurrentColumnsSort, i++, ',');
  691. if (!column.IsEmpty())
  692. {
  693. TCHAR cAsc = column[column.GetLength()-1];
  694. BOOL bAsc = true;
  695. if (!iswdigit(cAsc))
  696. {
  697. ASSERT (cAsc == 'A' || cAsc == 'D');
  698. if (cAsc == 'D')
  699. bAsc = !bAsc;
  700. column = column.Left(column.GetLength()-1);
  701. }
  702. int nColumn = atoi((LPCTSTR)column);
  703. m_wndSortHeaderEx.SetColumnOrder(nColumn, bAsc);
  704. }
  705. }
  706. while (!column.IsEmpty());
  707. SortAllItems();
  708. }
  709. // Function name : CTsyslistviewex::SortAllItems
  710. // Description     : sort all items according to header flags
  711. //   (!) Stop relay event in all recordsets.
  712. // Return type : void 
  713. void CTsyslistviewex::SortAllItems()
  714. {
  715. ASSERT ( m_bSorted );
  716. m_sortColumns.ResetOrderColumn();
  717. int column = 0;
  718. BOOL bAsc = true;
  719. for (int iPosition = 1; m_wndSortHeaderEx.GetPositionColumn(iPosition, bAsc, column); iPosition++ )
  720. m_sortColumns.AddOrderColumn(column,bAsc ? 1 : -1);
  721. if (m_sortColumns.GetCountOrderColumn())
  722. {
  723. AfxGetApp()->DoWaitCursor(1);
  724. m_sortColumns.Sort();
  725. AfxGetApp()->DoWaitCursor(-1);
  726. }
  727. SaveHeader();
  728. }
  729. // Function name : CTsyslistviewex::GetCountColumn
  730. // Description     : Return number of columns from control.
  731. // Return type : int ; columns count
  732. int CTsyslistviewex::GetCountColumn()
  733. {
  734. return ((CHeaderCtrl*)GetDlgItem(0))->GetItemCount();
  735. }
  736. // Function name : CTsyslistviewex::Progress
  737. // Description     : displays the progress bar
  738. // Return type : void 
  739. // Argument         : int nPercent ; 0 - progress bar set top middle, 100 progress bar is off
  740. void CTsyslistviewex::Progress(int nPercent)
  741. {
  742. if (!m_wndProgress.GetSafeHwnd())
  743. {
  744. const int dyProgress = 20;
  745. CRect rect; GetWindowRect(rect);
  746. ScreenToClient(rect);
  747. int dxProgress = rect.Width() * 3 / 4;
  748. rect.top += (rect.Height() - dyProgress) / 2;
  749. rect.bottom = rect.top + dyProgress ;
  750. rect.left += (rect.Width() - dxProgress) / 2;
  751. rect.right = rect.left + dxProgress;
  752. m_wndProgress.Create(WS_CHILD | WS_BORDER | WS_VISIBLE, rect, this, GetDlgCtrlID());
  753. }
  754. m_wndProgress.SetPos(nPercent);
  755. if (nPercent == 100)
  756. m_wndProgress.DestroyWindow();
  757. }
  758. // Function name : CTsyslistviewex::ResetBoldLines
  759. // Description     : reset all bold lines
  760. // Return type : void 
  761. void CTsyslistviewex::ResetBoldLines()
  762. {
  763. m_mapRowsBold.RemoveAll();
  764. }
  765. // Function name : CTsyslistviewex::SetBoldRow
  766. // Description     : If lParam == NULL then set bold for focused line.
  767. // Return type : void 
  768. // Argument         : LPARAM lParam
  769. // Argument         : BOOL bBold
  770. // Argument         : BOOL bInvalidate
  771. void CTsyslistviewex::SetBoldRow(LPARAM lParam, BOOL bBold, BOOL bInvalidate)
  772. {
  773. if (m_boldFont.GetSafeHandle())
  774. {
  775. if (!lParam)
  776. lParam = GetItemData(GetNextItem(-1, LVNI_FOCUSED));
  777. if (bBold)
  778. m_mapRowsBold[lParam] = 1;
  779. else
  780. m_mapRowsBold.RemoveKey(lParam);
  781. if (bInvalidate)
  782. Invalidate(false);
  783. }
  784. }
  785. // Function name : CTsyslistviewex::SetItalicRow
  786. // Description     : If lParam == NULL then set italic for focused line.
  787. // Return type : void 
  788. // Argument         : LPARAM lParam
  789. // Argument         : BOOL bItalic
  790. // Argument         : BOOL bInvalidate
  791. void CTsyslistviewex::SetItalicRow(LPARAM lParam, BOOL bItalic, BOOL bInvalidate)
  792. {
  793. if (m_italicFont.GetSafeHandle())
  794. {
  795. if (!lParam)
  796. lParam = GetItemData(GetNextItem(-1, LVNI_FOCUSED));
  797. if (bItalic)
  798. m_mapRowsItalic[lParam] = 1;
  799. else
  800. m_mapRowsItalic.RemoveKey(lParam);
  801. if (bInvalidate)
  802. Invalidate(false);
  803. }
  804. }
  805. // Function name : CTsyslistviewex::DeselectAll
  806. // Description     : Deselect all items from control
  807. // Return type : void 
  808. void CTsyslistviewex::DeselectAll()
  809. {
  810. int iCurrent = GetNextItem(-1, LVIS_SELECTED);
  811. while (iCurrent >= 0)
  812. {
  813. SetItemState(iCurrent, ~LVIS_SELECTED, LVIS_SELECTED);
  814. iCurrent = GetNextItem(iCurrent, LVIS_SELECTED);
  815. }
  816. }
  817. // Function name : CTsyslistviewex::SelectItem
  818. // Description     : Deselect all items, and select one item.
  819. // Return type : void 
  820. // Argument         : int i ; item index
  821. void CTsyslistviewex::SelectItem(int i)
  822. {
  823. DeselectAll();
  824. SetItemState(i, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
  825. EnsureVisible(i,false);
  826. }
  827. // Function name : CTsyslistviewex::GetHeaderSortString
  828. // Description     : Called in SaveAllItems(), returns header format string
  829. // Return type : CString ; sort header as string, for save it in the registry
  830. CString CTsyslistviewex::GetHeaderSortString()
  831. {
  832. CString result; result.Empty();
  833. if (m_bSorted)
  834. {
  835. int nPosition = 1;
  836. int nColumn = NULL;
  837. BOOL bAsc = true;
  838. while (m_wndSortHeaderEx.GetPositionColumn(nPosition++, bAsc, nColumn))
  839. {
  840. CString sColumn; sColumn.Format(_T("%i%s,"),nColumn, (bAsc ? _T("") : _T("D")));
  841. result += sColumn;
  842. }
  843. if (!result.IsEmpty())
  844. result = result.Left(result.GetLength() - 1);
  845. }
  846. return result;
  847. }
  848. // Function name : CTsyslistviewex::GetHeaderString
  849. // Description     : Return the header format string
  850. // Return type : CString ; header formated as: ColumnName1:FormatColumn1:WidthColumn1,...
  851. CString CTsyslistviewex::GetHeaderString()
  852. {
  853. CString result; result.Empty();
  854. LV_COLUMN column; 
  855.    TCHAR pszText[MAX_PATH];
  856.  column.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH;
  857.  column.pszText = pszText;
  858.  column.cchTextMax = MAX_PATH;
  859. for (int i = 0; GetColumn(i, &column); i++)
  860. {
  861. TCHAR f = TCHAR('L');
  862. switch (column.fmt & LVCFMT_JUSTIFYMASK)
  863. {
  864. case LVCFMT_RIGHT:
  865. f = TCHAR('R');
  866. break;
  867. case LVCFMT_CENTER:
  868. f = TCHAR('C');
  869. break;
  870. }
  871. CString w; w.Format(_T("%i"), column.cx);
  872. result = result + column.pszText + TCHAR(':') + w + TCHAR(':') + f + TCHAR(',');
  873. column.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH;
  874. }
  875. return result.Left(result.GetLength() - (result.IsEmpty() ? 0 : 1)); // last ,
  876. }
  877. // Function name : CTsyslistviewex::OnNotify
  878. // Description     : Called when item width changed. If necessarly the widths are saved in registry.
  879. // Return type : BOOL 
  880. // Argument         : WPARAM wParam
  881. // Argument         : LPARAM lParam
  882. // Argument         : LRESULT* pResult
  883. BOOL CTsyslistviewex::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) 
  884. {
  885. if ((int)wParam == 0)
  886. if (GetDlgItem(0)->IsWindowVisible())
  887. {
  888. switch (((HD_NOTIFY*)lParam)->hdr.code)
  889. {
  890. case HDN_ITEMCHANGEDA:
  891. case HDN_ITEMCHANGEDW:
  892. SaveHeader();
  893. break;
  894. }
  895. }
  896. return CListCtrl::OnNotify(wParam, lParam, pResult);
  897. }
  898. // Function name : CTsyslistviewex::NeedCX
  899. // Description     : Calc total width of listctrl
  900. // Return type : int ; listctrl width
  901. int CTsyslistviewex::NeedCX()
  902. {
  903. int result = 0;
  904. LV_COLUMN lvc; lvc.mask = LVCF_WIDTH;
  905. for (int i = 0; GetColumn(i, &lvc); i++)
  906. result += lvc.cx;
  907. return result;
  908. }
  909. // Function name : CTsyslistviewex::NeedCY
  910. // Description     : Calc partial visible height of listctrl
  911. // Return type : int ; visible height of listctrl
  912. int CTsyslistviewex::NeedCY()
  913. {
  914. CRect rect; GetClientRect(rect); int hRect = rect.Height();
  915. CRect rcItem;
  916. int result = 0;
  917. for (int i = GetTopIndex(); GetItemRect(i, rcItem,LVIR_LABEL) && result + rcItem.Height() < hRect; i++ )
  918. result += rcItem.Height();
  919. return result;
  920. }
  921. // Function name : CTsyslistviewex::OnChar
  922. // Description     : Treat specialy CTRL+S for sorting, if m_bSortWhenClickHeader is FALSE
  923. // Return type : void 
  924. // Argument         : UINT nChar
  925. // Argument         : UINT nRepCnt
  926. // Argument         : UINT nFlags
  927. void CTsyslistviewex::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
  928. {
  929. if (!m_bSortWhenClickHeader)
  930. if (GetKeyState(VK_CONTROL) < 0)
  931. if (nChar == scanCodeS)
  932. SortAllItems();
  933. CListCtrl::OnChar(nChar, nRepCnt, nFlags);
  934. }
  935. // Function name : CTsyslistviewex::GetCountRowsBold
  936. // Description     : Return count of bold rows
  937. // Return type : int 
  938. int CTsyslistviewex::GetCountRowsBold()
  939. {
  940. return m_mapRowsBold.GetCount();
  941. }
  942. // Function name : CTsyslistviewex::GetCountRowsItalic
  943. // Description     : Return count of italic rows
  944. // Return type : int 
  945. int CTsyslistviewex::GetCountRowsItalic()
  946. {
  947. return m_mapRowsItalic.GetCount();
  948. }
  949. // Function name : CTsyslistview32::SetHeader
  950. // Description     : 
  951. // Return type : BOOL 
  952. // Argument         : CListCtrl * pList
  953. // Argument         : CString newHeader
  954. BOOL CTsyslistviewex::SetHeader(CListCtrl * pList, CString newHeader)
  955. {
  956. CHeaderCtrl* pHeader = (CHeaderCtrl*)pList->GetDlgItem(0);
  957. if (pHeader)
  958. {
  959. while (pHeader->GetItemCount()) pHeader->DeleteItem(0);
  960. int i = 0; CString rString; rString.Empty();
  961. CMap<TCHAR,TCHAR,int,int> justifyMap;
  962. justifyMap['L'] = LVCFMT_LEFT;
  963. justifyMap['C'] = LVCFMT_CENTER;
  964. justifyMap['R'] = LVCFMT_RIGHT;
  965. do
  966. {
  967. AfxExtractSubString(rString, newHeader, i, ',');
  968. if (!rString.IsEmpty())
  969. {
  970. CString columnName;
  971. AfxExtractSubString(columnName, rString, 0, ':');
  972. CString columnWidth;
  973. AfxExtractSubString(columnWidth, rString, 1, ':');
  974. if (columnWidth.IsEmpty()) columnWidth = _T("128"); // default value
  975. CString columnJustify;
  976. AfxExtractSubString(columnJustify, rString, 2, ':');
  977. int justify = LVCFMT_LEFT;
  978. if (!columnJustify.IsEmpty())
  979. justifyMap.Lookup(columnJustify[0], justify);
  980. pList->InsertColumn(i,columnName, justify, _wtoi((const wchar_t*)columnWidth.GetBuffer(0)));
  981. i++;
  982. }
  983. } while (!rString.IsEmpty());
  984. }
  985. return (pHeader != NULL);
  986. }