ListCtrlEx.cpp
上传用户:zhouyunkk
上传日期:2022-07-16
资源大小:98k
文件大小:29k
源码类别:

ListView/ListBox

开发平台:

Visual C++

  1. // ListCtrlEx.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "ListCtrlEx.h"
  5. CListCtrlEx::EditorInfo::EditorInfo()
  6. :m_pfnInitEditor(NULL)
  7. ,m_pfnEndEditor(NULL)
  8. ,m_pWnd(NULL)
  9. ,m_bReadOnly(false)
  10. {
  11. }
  12. CListCtrlEx::EditorInfo::EditorInfo(PFNEDITORCALLBACK pfnInitEditor, PFNEDITORCALLBACK pfnEndEditor, CWnd *pWnd)
  13. :m_pfnInitEditor(pfnInitEditor)
  14. ,m_pfnEndEditor(pfnEndEditor)
  15. ,m_pWnd(pWnd)
  16. ,m_bReadOnly(false)
  17. {
  18. }
  19. CListCtrlEx::CellInfo::CellInfo(int nColumn)
  20. :m_clrBack(-1)
  21. ,m_clrText(-1)
  22. ,m_dwUserData(NULL)
  23. ,m_nColumn(nColumn)
  24. {
  25. }
  26. CListCtrlEx::CellInfo::CellInfo(int nColumn, COLORREF clrBack, COLORREF clrText, DWORD_PTR dwUserData)
  27. :m_clrBack(clrBack)
  28. ,m_clrText(clrText)
  29. ,m_dwUserData(dwUserData)
  30. ,m_nColumn(nColumn)
  31. {
  32. }
  33. CListCtrlEx::CellInfo::CellInfo(int nColumn, EditorInfo eiEditor, COLORREF clrBack, COLORREF clrText, DWORD_PTR dwUserData)
  34. :m_clrBack(clrBack)
  35. ,m_clrText(clrText)
  36. ,m_dwUserData(dwUserData)
  37. ,m_eiEditor(eiEditor)
  38. ,m_nColumn(nColumn)
  39. {
  40. }
  41. CListCtrlEx::CellInfo::CellInfo(int nColumn, EditorInfo eiEditor, DWORD_PTR dwUserData)
  42. :m_clrBack(-1)
  43. ,m_clrText(-1)
  44. ,m_dwUserData(dwUserData)
  45. ,m_eiEditor(eiEditor)
  46. ,m_nColumn(nColumn)
  47. {
  48. }
  49. CListCtrlEx::ColumnInfo::ColumnInfo(int nColumn)
  50. :m_eiEditor()
  51. ,m_clrBack(-1)
  52. ,m_clrText(-1)
  53. ,m_nColumn(nColumn)
  54. ,m_eSort(None)
  55. ,m_eCompare(NotSet)
  56. ,m_fnCompare(NULL)
  57. {
  58. }
  59. CListCtrlEx::ColumnInfo::ColumnInfo(int nColumn, PFNEDITORCALLBACK pfnInitEditor, PFNEDITORCALLBACK pfnEndEditor, CWnd *pWnd)
  60. :m_eiEditor(pfnInitEditor, pfnEndEditor, pWnd)
  61. ,m_nColumn(nColumn)
  62. ,m_clrBack(-1)
  63. ,m_clrText(-1)
  64. ,m_eSort(None)
  65. ,m_eCompare(NotSet)
  66. ,m_fnCompare(NULL)
  67. {
  68. }
  69. CListCtrlEx::ItemData::ItemData(DWORD_PTR dwUserData)
  70. :m_clrBack(0xFFFFFFFF)
  71. ,m_clrText(0xFFFFFFFF)
  72. ,m_dwUserData(dwUserData)
  73. {
  74. }
  75. CListCtrlEx::ItemData::ItemData(COLORREF clrBack, COLORREF clrText, DWORD_PTR dwUserData)
  76. :m_clrBack(clrBack)
  77. ,m_clrText(clrText)
  78. ,m_dwUserData(dwUserData)
  79. {
  80. }
  81. CListCtrlEx::ItemData::~ItemData()
  82. {
  83. while(m_aCellInfo.GetCount()>0)
  84. {
  85. CellInfo *pInfo = (CellInfo*)m_aCellInfo.GetAt(0);
  86. m_aCellInfo.RemoveAt(0);
  87. delete pInfo;
  88. }
  89. }
  90. // CListCtrlEx
  91. IMPLEMENT_DYNAMIC(CListCtrlEx, CListCtrl)
  92. CListCtrlEx::CListCtrlEx()
  93. :m_pEditor(NULL)
  94. ,m_nEditingRow(-1)
  95. ,m_nEditingColumn(-1)
  96. ,m_msgHook()
  97. ,m_nRow(-1)
  98. ,m_nColumn(-1)
  99. ,m_bHandleDelete(FALSE)
  100. ,m_nSortColumn(-1)
  101. ,m_fnCompare(NULL)
  102. ,m_hAccel(NULL)
  103. ,m_dwSortData(NULL)
  104. , m_bInvokeAddNew(FALSE)
  105. {
  106. #ifndef _WIN32_WCE
  107. EnableActiveAccessibility();
  108. #endif
  109. }
  110. #define ID_EDITOR_CTRL 5000
  111. CListCtrlEx::~CListCtrlEx()
  112. {
  113. DeleteAllItemsData();
  114. DeleteAllColumnInfo();
  115. }
  116. BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
  117. ON_NOTIFY_REFLECT_EX(NM_DBLCLK, &CListCtrlEx::OnNMDblclk)
  118. ON_NOTIFY_REFLECT_EX(NM_CUSTOMDRAW, &CListCtrlEx::OnNMCustomdraw)
  119. ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, &CListCtrlEx::OnHdnItemclick)
  120. END_MESSAGE_MAP()
  121. // CListCtrlEx message handlers
  122. // Retrieves the data (lParam) associated with a particular item.
  123. DWORD_PTR CListCtrlEx::GetItemData(int nItem) const
  124. {
  125. ItemData* pData = (ItemData*)GetItemDataInternal(nItem);
  126. if(!pData) return NULL;
  127. return pData->m_dwUserData;
  128. }
  129. // Retrieves the data (lParam) associated with a particular item.
  130. DWORD_PTR CListCtrlEx::GetItemDataInternal(int nItem) const
  131. {
  132. return CListCtrl::GetItemData(nItem);
  133. }
  134. int CListCtrlEx::InsertItem(int nItem, LPCTSTR lpszItem)
  135. {
  136. int ret = CListCtrl::InsertItem(nItem, lpszItem);
  137. SetItemData(ret, 0);
  138. return ret;
  139. }
  140. int CListCtrlEx::InsertItem(int nItem, LPCTSTR lpszItem, int nImage)
  141. {
  142. int ret = CListCtrl::InsertItem(nItem, lpszItem, nImage);
  143. SetItemData(ret, 0);
  144. return ret;
  145. }
  146. int CListCtrlEx::InsertItem(const LVITEM* pItem)
  147. {
  148. int ret = 0;
  149. LVITEM pI = *pItem;
  150. if(pItem && (pItem->mask & LVIF_PARAM))
  151. {
  152. pI.mask &= (~LVIF_PARAM);
  153. }
  154. ret = CListCtrl::InsertItem(&pI);
  155. SetItemData(ret, pItem->lParam);
  156. return ret;
  157. }
  158. // Sets the data (lParam) associated with a particular item.
  159. BOOL CListCtrlEx::SetItemData(int nItem, DWORD_PTR dwData)
  160. {
  161. ItemData* pData = (ItemData*)GetItemDataInternal(nItem);
  162. if(!pData)
  163. {
  164. pData = new ItemData(dwData);
  165. m_aItemData.Add(pData);
  166. }
  167. else
  168. pData->m_dwUserData = dwData;
  169. return CListCtrl::SetItemData(nItem, (DWORD_PTR)pData);
  170. }
  171. // Removes a single item from the control.
  172. BOOL CListCtrlEx::DeleteItem(int nItem)
  173. {
  174. DeleteItemData(nItem);
  175. return CListCtrl::DeleteItem(nItem);
  176. }
  177. // Removes all items from the control.
  178. BOOL CListCtrlEx::DeleteAllItems()
  179. {
  180. int nCount = this->GetItemCount();
  181. DeleteAllItemsData();
  182. return CListCtrl::DeleteAllItems();
  183. }
  184. BOOL CListCtrlEx::DeleteAllItemsData( )
  185. {
  186. while(m_aItemData.GetCount()>0)
  187. {
  188. ItemData* pData = (ItemData*)m_aItemData.GetAt(0);
  189. if(pData) delete pData;
  190. m_aItemData.RemoveAt(0);
  191. }
  192. return TRUE;
  193. }
  194. BOOL CListCtrlEx::DeleteItemData(int nItem)
  195. {
  196. if(nItem < 0 || nItem > GetItemCount()) return FALSE;
  197. ItemData* pData = (ItemData*)CListCtrl::GetItemData(nItem);
  198. INT_PTR nCount = m_aItemData.GetCount();
  199. for(INT_PTR i = 0; i < nCount && pData; i++)
  200. {
  201. if(m_aItemData.GetAt(i) == pData)
  202. {
  203. m_aItemData.RemoveAt(i);
  204. break;
  205. }
  206. }
  207. if(pData) delete pData;
  208. return TRUE;
  209. }
  210. BOOL CListCtrlEx::DeleteAllColumnInfo( )
  211. {
  212. while(m_aColumnInfo.GetCount()>0)
  213. {
  214. ColumnInfo* pData = (ColumnInfo*)m_aColumnInfo.GetAt(0);
  215. if(pData) delete pData;
  216. m_aColumnInfo.RemoveAt(0);
  217. }
  218. return TRUE;
  219. }
  220. BOOL CListCtrlEx::DeleteColumnInfo(int nColumn)
  221. {
  222. if(nColumn < 0 || nColumn > GetColumnCount()) return FALSE;
  223. ColumnInfo* pData = (ColumnInfo*)GetColumnInfo(nColumn);
  224. INT_PTR nCount = m_aColumnInfo.GetCount();
  225. for(INT_PTR i = 0; i < nCount && pData; i++)
  226. {
  227. if(m_aColumnInfo.GetAt(i) == pData)
  228. {
  229. m_aColumnInfo.RemoveAt(i);
  230. break;
  231. }
  232. }
  233. if(pData) delete pData;
  234. return TRUE;
  235. }
  236. void CListCtrlEx::SetColumnEditor(int nColumn, PFNEDITORCALLBACK pfnInitEditor, PFNEDITORCALLBACK pfnEndEditor, CWnd* pWnd)
  237. {
  238. ColumnInfo* pColInfo = GetColumnInfo(nColumn);
  239. if(!pColInfo)
  240. pColInfo = new ColumnInfo(nColumn);  
  241. m_aColumnInfo.Add(pColInfo);
  242. }
  243. pColInfo->m_eiEditor.m_pfnInitEditor = pfnInitEditor;
  244. pColInfo->m_eiEditor.m_pfnEndEditor = pfnEndEditor;
  245. pColInfo->m_eiEditor.m_pWnd = pWnd;
  246. }
  247. void CListCtrlEx::SetColumnEditor(int nColumn, CWnd* pWnd)
  248. {
  249. SetColumnEditor(nColumn, NULL, NULL, pWnd);
  250. }
  251. void CListCtrlEx::SetRowEditor(int nRow, CWnd* pWnd)
  252. {
  253. SetRowEditor(nRow, NULL, NULL, pWnd);
  254. }
  255. void CListCtrlEx::SetRowEditor(int nRow, PFNEDITORCALLBACK pfnInitEditor, PFNEDITORCALLBACK pfnEndEditor, CWnd* pWnd)
  256. {
  257. ItemData* pData = (ItemData*)GetItemDataInternal(nRow);
  258. if(!pData)
  259. SetItemData(nRow, 0);
  260. pData = (ItemData*)GetItemDataInternal(nRow);
  261. }
  262. pData->m_eiEditor.m_pfnInitEditor = pfnInitEditor;
  263. pData->m_eiEditor.m_pfnEndEditor = pfnEndEditor;
  264. pData->m_eiEditor.m_pWnd = pWnd;
  265. }
  266. CListCtrlEx::ColumnInfo* CListCtrlEx::GetColumnInfo(int nColumn)
  267. {
  268. INT_PTR nCount = m_aColumnInfo.GetCount();
  269. for(INT_PTR i = 0; i < nCount; i++)
  270. {
  271. ColumnInfo* pColInfo = (ColumnInfo*)m_aColumnInfo.GetAt(i);
  272. if(pColInfo->m_nColumn == nColumn) return pColInfo;
  273. }
  274. return NULL;
  275. }
  276. int CListCtrlEx::FindItem(LVFINDINFO* pFindInfo, int nStart ) const
  277. {
  278. if(pFindInfo->flags & LVIF_PARAM)
  279. {
  280. int nCount = GetItemCount();
  281. for(int i = nStart+1; i < nCount; i++)
  282. {
  283. if(pFindInfo->lParam == GetItemData(i)) return i;
  284. }
  285. return -1;
  286. }
  287. else
  288. {
  289. return CListCtrl::FindItem(pFindInfo, nStart);
  290. }
  291. }
  292. int CListCtrlEx::GetItemIndexFromData(DWORD_PTR dwData)
  293. {
  294. LVFINDINFO find;
  295. find.flags = LVFI_PARAM;
  296. find.lParam = dwData;
  297. return CListCtrl::FindItem(&find);
  298. }
  299. int CALLBACK CListCtrlEx::CompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  300. {
  301. CListCtrlEx *This = reinterpret_cast<CListCtrlEx*>(lParamSort);
  302. ColumnInfo *pColInfo;
  303. int nSort = 0;
  304. int nCompare = 0;
  305. if(!This) return 0;
  306. if(!(This->m_nSortColumn < 0 || This->m_nSortColumn >= This->GetColumnCount()) )
  307. {
  308. pColInfo = This->GetColumnInfo(This->m_nSortColumn);
  309. if(pColInfo && (pColInfo->m_eSort & SortBits)) 
  310. {
  311. nSort = pColInfo->m_eSort & Ascending ? 1: -1 ;
  312. if(!This->m_fnCompare && pColInfo->m_fnCompare) This->m_fnCompare = pColInfo->m_fnCompare;
  313. }
  314. }
  315. if(This->m_fnCompare && This->m_fnCompare != &CListCtrlEx::CompareProc) 
  316. {
  317. ItemData *pD1 = reinterpret_cast<ItemData*>(lParam1);
  318. ItemData *pD2 = reinterpret_cast<ItemData*>(lParam2);
  319. if(pD1) lParam1 = pD1->m_dwUserData;
  320. if(pD2) lParam2 = pD2->m_dwUserData;
  321. nCompare = This->m_fnCompare(lParam1, lParam2, This->m_dwSortData?This->m_dwSortData:This->m_nSortColumn);
  322. if(!This->m_dwSortData && nSort) 
  323. {
  324. return nCompare * nSort;
  325. }
  326. }
  327. if(!nSort) return 0;
  328. int nLeft = This->GetItemIndexFromData(lParam1); 
  329. int nRight = This->GetItemIndexFromData(lParam2);
  330. if(nLeft < 0) nLeft = lParam1;
  331. if(nRight < 0) nRight = lParam2;
  332. int nCount = This->GetItemCount();
  333. if(nLeft < 0 || nRight < 0 || nLeft >= nCount || nRight >= nCount) return 0;
  334. nCompare = Compare(nLeft, nRight, lParamSort);
  335. return (nCompare * nSort);
  336. }
  337. void CListCtrlEx::OnHdnItemclick(NMHDR *pNMHDR, LRESULT *pResult)
  338. {
  339. NM_LISTVIEW*  phdr = reinterpret_cast<NM_LISTVIEW*>(pNMHDR);
  340. SortOnColumn(phdr->iSubItem, TRUE);
  341. *pResult = 0;
  342. //return FALSE;
  343. }
  344. BOOL CListCtrlEx::SortItems(PFNLVCOMPARE pfnCompare, DWORD_PTR dwData)
  345. {
  346. int nCount = GetItemCount();
  347. DWORD_PTR dwEditingItemData = 0;
  348. if(m_nEditingRow >= 0 && m_nEditingRow < nCount)
  349.  dwEditingItemData = GetItemDataInternal(m_nEditingRow);
  350. CString dbg;
  351. dbg.Format("nBefore : %d", m_nEditingRow);
  352. OutputDebugString(dbg);
  353. m_fnCompare = pfnCompare;
  354. m_dwSortData = dwData;
  355. BOOL ret = CListCtrl::SortItems(CompareProc, (DWORD_PTR)this);
  356. m_fnCompare = NULL;
  357. m_dwSortData = NULL;
  358. if(dwEditingItemData) 
  359. m_nEditingRow = GetItemIndexFromData(dwEditingItemData);
  360. dbg.Format("nAfter : %d", m_nEditingRow);
  361. OutputDebugString(dbg);
  362. return ret;
  363. }
  364. BOOL CListCtrlEx::SortOnColumn(int nColumn, BOOL bChangeOrder)
  365. {
  366. ColumnInfo *pColInfo;
  367. if((pColInfo = GetColumnInfo(nColumn)) && (pColInfo->m_eSort & SortBits ))
  368. {
  369. if(pColInfo->m_eSort & Auto)
  370. {
  371. pColInfo->m_eSort =(Sort)((pColInfo->m_eSort & (Ascending | Descending)) ? pColInfo->m_eSort : pColInfo->m_eSort | Descending);
  372. if(bChangeOrder) pColInfo->m_eSort = (Sort)(pColInfo->m_eSort ^ (Ascending | Descending));
  373. }
  374. CHeaderCtrl *pHdr = this->GetHeaderCtrl();
  375. HDITEM hd;
  376. hd.mask = HDI_FORMAT;
  377. if(pHdr)
  378. {
  379. pHdr->GetItem(m_nSortColumn, &hd);
  380. hd.fmt = hd.fmt & ~(HDF_SORTDOWN|HDF_SORTUP);
  381. pHdr->SetItem(m_nSortColumn, &hd);
  382. }
  383. m_nSortColumn = nColumn;
  384. CListCtrl::SortItems(CompareProc, (DWORD_PTR)this);
  385. if(pHdr)
  386. {
  387. pHdr->GetItem(nColumn, &hd);
  388. hd.fmt = hd.fmt & ~(HDF_SORTDOWN|HDF_SORTUP);
  389. hd.fmt |= pColInfo->m_eSort & Ascending ? HDF_SORTUP : HDF_SORTDOWN;
  390. pHdr->SetItem(nColumn, &hd);
  391. }
  392. return TRUE;
  393. }
  394. return FALSE;
  395. }
  396. BOOL CListCtrlEx::OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult)
  397. {
  398. NM_LISTVIEW *pNMListView = (NM_LISTVIEW *)pNMHDR;
  399. if(!pNMListView) return FALSE;
  400. int nItem = pNMListView->iItem, nSubItem = pNMListView->iSubItem;
  401. *pResult = DisplayEditor(nItem, nSubItem);
  402. return *pResult;
  403. }
  404. BOOL CListCtrlEx::EnsureSubItemVisible(int nItem, int nSubItem, CRect *pRect)
  405. {
  406. BOOL ret = EnsureVisible(nItem, FALSE);
  407. CRect rect;
  408. GetSubItemRect(nItem, nSubItem, LVIR_LABEL, rect);
  409. CRect rtList;
  410. GetClientRect(&rtList);
  411. if(rect.right > rtList.Width()) Scroll(CSize( rect.Width() > rtList.Width()?rect.left : rect.right - rtList.Width(), 0));
  412. if(rect.left < 0) Scroll(CSize(rect.left));
  413. if(pRect)
  414. {
  415. GetSubItemRect(nItem, nSubItem, LVIR_LABEL, rect);
  416. rect.right = min(rect.right, rtList.Width()-4);
  417. *pRect = rect;
  418. }
  419. return ret;
  420. }
  421. BOOL CListCtrlEx::DisplayEditor(int nItem, int nSubItem)
  422. {
  423. int nCount = GetItemCount();
  424. DWORD_PTR dwEditingItemData = 0;
  425. if(nItem >= 0 && nItem < nCount)
  426.  dwEditingItemData = GetItemDataInternal(nItem);
  427. HideEditor();
  428. if(dwEditingItemData) 
  429. nItem = GetItemIndexFromData(dwEditingItemData);
  430. if(nItem < 0 || nItem > nCount || nSubItem < 0 || nSubItem > this->GetColumnCount() 
  431. || IsColumnReadOnly(nSubItem) || IsRowReadOnly(nItem) || IsCellReadOnly(nItem, nSubItem)) return FALSE;
  432. CRect rectSubItem;
  433. //GetSubItemRect(nItem, nSubItem, LVIR_LABEL, rectSubItem);
  434. EnsureSubItemVisible(nItem, nSubItem, &rectSubItem);
  435. CellInfo *pCellInfo = GetCellInfo(nItem, nSubItem);
  436. ColumnInfo *pColInfo = GetColumnInfo(nSubItem);
  437. ItemData *pRowInfo = (ItemData *)GetItemDataInternal(nItem);
  438. m_pEditor = &m_eiDefEditor;
  439. BOOL bReadOnly = FALSE;
  440. if(pColInfo && !(bReadOnly|= pColInfo->m_eiEditor.m_bReadOnly) && pColInfo->m_eiEditor.IsSet())
  441. {
  442. m_pEditor = &pColInfo->m_eiEditor;
  443. }
  444. if(pRowInfo && !(bReadOnly|= pRowInfo->m_eiEditor.m_bReadOnly) && pRowInfo->m_eiEditor.IsSet())
  445. {
  446. m_pEditor = &pRowInfo->m_eiEditor;
  447. }
  448. if(pCellInfo && !(bReadOnly|= pCellInfo->m_eiEditor.m_bReadOnly) && pCellInfo->m_eiEditor.IsSet())
  449. {
  450. m_pEditor = &pCellInfo->m_eiEditor;
  451. }
  452. if(bReadOnly || !m_pEditor || !m_pEditor->IsSet() || m_pEditor->m_bReadOnly){m_pEditor = NULL; return  FALSE;}
  453. m_nEditingRow = nItem;
  454. m_nEditingColumn = nSubItem;
  455. m_nRow = nItem;
  456. m_nColumn = nSubItem;
  457. CString text =  GetItemText(nItem, nSubItem);
  458. if(m_pEditor->m_pfnInitEditor) 
  459. m_pEditor->m_pfnInitEditor(&m_pEditor->m_pWnd, nItem, nSubItem, text, GetItemData(nItem), this, TRUE);
  460. if(!m_pEditor->m_pWnd) return  FALSE;
  461. SelectItem(-1, FALSE);
  462. if(!m_pEditor->m_pfnInitEditor) m_pEditor->m_pWnd->SetWindowText(text);
  463. m_pEditor->m_pWnd->SetParent(this);
  464. m_pEditor->m_pWnd->SetOwner(this);
  465. ASSERT(m_pEditor->m_pWnd->GetParent() == this);
  466. m_pEditor->m_pWnd->SetWindowPos(NULL, rectSubItem.left, rectSubItem.top, rectSubItem.Width(), rectSubItem.Height(), SWP_SHOWWINDOW);
  467. m_pEditor->m_pWnd->ShowWindow(SW_SHOW);
  468. m_pEditor->m_pWnd->SetFocus();
  469. m_msgHook.Attach(m_pEditor->m_pWnd->m_hWnd, this->m_hWnd);
  470. return TRUE;
  471. }
  472. CListCtrlEx::CellInfo* CListCtrlEx::GetCellInfo(int nItem, int nSubItem)
  473. {
  474. ItemData* pData = (ItemData*)GetItemDataInternal(nItem);
  475. if(pData == NULL) return NULL;
  476. INT_PTR nCount = pData->m_aCellInfo.GetCount();
  477. for(INT_PTR i = 0; i < nCount; i++)
  478. {
  479. CellInfo *pInfo = (CellInfo*)pData->m_aCellInfo.GetAt(i);
  480. if(pInfo && pInfo->m_nColumn == nSubItem) return pInfo;
  481. }
  482. return NULL;
  483. }
  484. void CListCtrlEx::HideEditor(BOOL bUpdate)
  485. {
  486. CSingleLock lock(&m_oLock, TRUE);
  487. if(lock.IsLocked() && m_msgHook.Detach())
  488. {
  489. if(m_pEditor && m_pEditor->m_pWnd)
  490. {
  491. m_pEditor->m_pWnd->ShowWindow(SW_HIDE);
  492. CString text;
  493. DWORD_PTR dwData = 0;
  494. if(GetItemCount() > m_nEditingRow)
  495. {
  496. text =  GetItemText(m_nEditingRow, m_nEditingColumn);
  497. dwData = GetItemData(m_nEditingRow);
  498. }
  499. else
  500. {
  501. bUpdate = FALSE;
  502. }
  503. if(m_pEditor->m_pfnEndEditor)
  504. {
  505. bUpdate = m_pEditor->m_pfnEndEditor(&m_pEditor->m_pWnd, m_nEditingRow, m_nEditingColumn, text, dwData, this, bUpdate);
  506. }
  507. else
  508. {
  509. m_pEditor->m_pWnd->GetWindowText(text);
  510. }
  511. if(bUpdate)
  512. {
  513. SetItemText(m_nEditingRow, m_nEditingColumn, text);
  514. }
  515. if(GetItemCount() > m_nEditingRow) Update(m_nEditingRow);
  516. if(bUpdate == -1) SortOnColumn(m_nEditingColumn);
  517. m_pEditor = NULL;
  518. }
  519. }
  520. lock.Unlock();
  521. }
  522. int CListCtrlEx::GetColumnCount(void)
  523. {
  524. CHeaderCtrl *pHdr = GetHeaderCtrl();
  525. if(pHdr) return pHdr->GetItemCount();
  526. int i = 0;
  527. LVCOLUMN col;
  528. col.mask = LVCF_WIDTH;
  529. while(GetColumn(i++, &col));
  530. return i;
  531. }
  532. BOOL CListCtrlEx::PreTranslateMessage(MSG* pMsg)
  533. {
  534. if((m_hAccel && GetParent() && GetFocus() == this && ::TranslateAccelerator(GetParent()->m_hWnd, m_hAccel, pMsg))) return TRUE;
  535. if(pMsg->message == WM_KEYDOWN )
  536. {
  537. if( pMsg->wParam == VK_TAB && (GetKeyState(VK_CONTROL)>>8 != -1))
  538. {
  539. int nCount = GetItemCount();
  540. int nColCount = GetColumnCount();
  541. if(m_pEditor && m_pEditor->m_pWnd && m_pEditor->m_pWnd->m_hWnd == pMsg->hwnd)
  542. {
  543. PostMessage(pMsg->message, pMsg->wParam, pMsg->lParam);
  544. return TRUE;
  545. }
  546. bool bShiftPressed = (GetKeyState(VK_SHIFT)>>8 == -1);
  547. if(!bShiftPressed && nCount == 0 && OnAddNew())
  548. {
  549. nCount = GetItemCount();
  550. m_nColumn = 0;
  551. }
  552. if(nCount > 0 && nColCount > 0)
  553. {
  554. BOOL bContinue;
  555. do
  556. {
  557. bContinue = FALSE;
  558. if(m_nRow < 0 || m_nColumn < 0)
  559. m_nRow = bShiftPressed ? nCount - 1: 0; 
  560. m_nColumn = bShiftPressed ? nColCount - 1: 0;
  561. }
  562. else if(m_nRow >= nCount || m_nColumn >= nColCount)
  563. {
  564. m_nRow = bShiftPressed ? nCount - 1: 0 ; 
  565. m_nColumn = bShiftPressed ? nColCount - 1: 0;
  566. }
  567. else
  568. {
  569. m_nColumn += (bShiftPressed ? -1 : 1);
  570. if(m_nColumn <0 || m_nColumn >= nColCount)
  571. {
  572. m_nRow += (bShiftPressed ? -1 : 1);
  573. m_nColumn = (bShiftPressed ? nColCount-1 : 0);
  574. }
  575. }
  576. if(m_bInvokeAddNew && ((m_nRow == nCount -1 && m_nColumn >= nColCount)||m_nRow >= nCount))
  577. {
  578. HideEditor();
  579. if(OnAddNew())
  580. {
  581. nCount = GetItemCount();
  582. m_nColumn = 0;
  583. }
  584. else return TRUE;
  585. }
  586. if(m_nRow >= 0 && m_nRow < nCount && m_nColumn >= 0 && m_nColumn < nColCount )
  587. {
  588. if(DisplayEditor(m_nRow, m_nColumn))
  589. return TRUE;
  590. bContinue = TRUE;
  591. }
  592. }while(bContinue);
  593. }
  594. }
  595. else if( pMsg->wParam == VK_DELETE  && m_bHandleDelete)
  596. {
  597. DeleteSelectedItems();
  598. return TRUE;
  599. }
  600. }
  601. return CListCtrl::PreTranslateMessage(pMsg);
  602. }
  603. BOOL CListCtrlEx::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
  604. {
  605. LPNMLVCUSTOMDRAW lplvcd = reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR);
  606. int iRow = lplvcd->nmcd.dwItemSpec;
  607. int iCol = lplvcd->iSubItem;
  608. *pResult = 0;
  609. switch(lplvcd->nmcd.dwDrawStage)
  610. {
  611. case CDDS_PREPAINT:
  612. *pResult = CDRF_NOTIFYSUBITEMDRAW;          // ask for subitem notifications.
  613. break;
  614. case CDDS_ITEMPREPAINT:
  615. *pResult = CDRF_NOTIFYSUBITEMDRAW;
  616. break;
  617. case CDDS_ITEMPREPAINT|CDDS_SUBITEM:
  618. {
  619. COLORREF clrBack = 0xFFFFFFFF;
  620. COLORREF clrText = 0xFFFFFFFF;
  621. *pResult = CDRF_DODEFAULT;
  622. CellInfo *pCell = GetCellInfo(iRow, iCol);
  623. if(pCell)
  624. {
  625. clrBack = pCell->m_clrBack;
  626. clrText = pCell->m_clrText;
  627. }
  628. if(clrBack == 0xFFFFFFFF && clrText == 0xFFFFFFFF)
  629. {
  630. ItemData* pData = (ItemData*)GetItemDataInternal(iRow);
  631. if(pData)
  632. {
  633. clrBack = pData->m_clrBack;
  634. clrText = pData->m_clrText;
  635. }
  636. }
  637. if(clrBack == 0xFFFFFFFF && clrText == 0xFFFFFFFF)
  638. {
  639. ColumnInfo *pInfo = GetColumnInfo(iCol);
  640. if(pInfo)
  641. {
  642. clrBack = pInfo->m_clrBack;
  643. clrText = pInfo->m_clrText;
  644. }
  645. }
  646. if(clrBack != 0xFFFFFFFF)
  647. {
  648. lplvcd->clrTextBk = clrBack;
  649. *pResult  = CDRF_NEWFONT;
  650. }
  651. else
  652. {
  653. if(clrBack != m_clrDefBack)
  654. {
  655. lplvcd->clrTextBk = m_clrDefBack;
  656. *pResult  = CDRF_NEWFONT;
  657. }
  658. }
  659. if(clrText != 0xFFFFFFFF)
  660. {
  661. lplvcd->clrText = clrText;
  662. *pResult  = CDRF_NEWFONT;
  663. }
  664. else
  665. {
  666. if(clrText != m_clrDefText)
  667. {
  668. lplvcd->clrText = m_clrDefText;
  669. *pResult  = CDRF_NEWFONT;
  670. }
  671. }
  672. }
  673. break;
  674. default:
  675. *pResult = CDRF_DODEFAULT;
  676. }
  677. if(*pResult == 0 || *pResult == CDRF_DODEFAULT)
  678. return FALSE;
  679. else
  680. return TRUE;
  681. }
  682. void CListCtrlEx::SetRowColors(int nItem, COLORREF clrBk, COLORREF clrText)
  683. {
  684. ItemData* pData = (ItemData*)GetItemDataInternal(nItem);
  685. if(!pData) SetItemData(nItem, 0);
  686. pData = (ItemData*)GetItemDataInternal(nItem);
  687. if(!pData) return;
  688. pData->m_clrText = clrText;
  689. pData->m_clrBack = clrBk;
  690. Update(nItem);
  691. }
  692. BOOL CListCtrlEx::AddItem(int ItemIndex, int SubItemIndex, LPCTSTR ItemText, int ImageIndex)
  693. {
  694. LV_ITEM lvItem;
  695. lvItem.mask = LVIF_TEXT;
  696. lvItem.iItem = ItemIndex;
  697. lvItem.iSubItem = SubItemIndex;
  698. lvItem.pszText = (LPTSTR) ItemText;
  699. if(ImageIndex != -1){
  700. lvItem.mask |= LVIF_IMAGE;
  701. lvItem.iImage |= LVIF_IMAGE;
  702. }
  703. if(SubItemIndex == 0)
  704. return InsertItem(&lvItem);
  705. return SetItem(&lvItem);
  706. }
  707. LRESULT CListCtrlEx::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
  708. {
  709. if(message == UM_HIDEEDITOR)
  710. {
  711. HideEditor((BOOL)wParam);
  712. }
  713. return CListCtrl::WindowProc(message, wParam, lParam);
  714. }
  715. void CListCtrlEx::SetColumnColors(int nColumn, COLORREF clrBack, COLORREF clrText)
  716. {
  717. if(nColumn < 0 || nColumn >= GetColumnCount()) return;
  718. ColumnInfo* pColInfo = GetColumnInfo(nColumn);
  719. if(!pColInfo)
  720. pColInfo = new ColumnInfo(nColumn);  
  721. m_aColumnInfo.Add(pColInfo);
  722. }
  723. pColInfo->m_clrBack = clrBack;
  724. pColInfo->m_clrText = clrText;
  725. }
  726. void CListCtrlEx::SetCellColors(int nRow, int nColumn, COLORREF clrBack, COLORREF clrText)
  727. {
  728. if(nRow < 0 || nRow >= GetItemCount() || nColumn < 0 || nColumn >= GetColumnCount()) return;
  729. CellInfo* pCellInfo = GetCellInfo(nRow, nColumn);
  730. if(!pCellInfo)
  731. SetCellData(nRow, nColumn, 0);
  732. }
  733. pCellInfo = GetCellInfo(nRow, nColumn);
  734. ASSERT(pCellInfo);
  735. pCellInfo->m_clrBack = clrBack;
  736. pCellInfo->m_clrText = clrText;
  737. }
  738. void CListCtrlEx::PreSubclassWindow()
  739. {
  740. m_clrDefBack = GetTextBkColor();
  741. m_clrDefText = GetTextColor();
  742. CListCtrl::PreSubclassWindow();
  743. SetExtendedStyle(LVS_EX_FULLROWSELECT);
  744. ModifyStyle(0, LVS_REPORT );
  745. }
  746. BOOL CListCtrlEx::SetCellData(int nItem, int nSubItem, DWORD_PTR dwData)
  747. {
  748. if(nItem < 0 || nItem >= GetItemCount() || nSubItem < 0 || nSubItem >= GetColumnCount()) return FALSE;
  749. CellInfo* pCellInfo = GetCellInfo(nItem, nSubItem);
  750. if(!pCellInfo)
  751. pCellInfo = new CellInfo(nSubItem);
  752. ItemData *pData = (ItemData*)GetItemDataInternal(nItem);
  753. if(!pData)
  754. {
  755. SetItemData(nItem, 0);
  756. pData = (ItemData*)GetItemDataInternal(nItem);
  757. }
  758. pData->m_aCellInfo.Add(pCellInfo);
  759. }
  760. pCellInfo->m_dwUserData = dwData;
  761. return TRUE;
  762. }
  763. DWORD_PTR CListCtrlEx::GetCellData(int nItem, int nSubItem)
  764. {
  765. CellInfo* pCellInfo = GetCellInfo(nItem, nSubItem);
  766. if(pCellInfo) return pCellInfo->m_dwUserData;
  767. else return 0;
  768. }
  769. void CListCtrlEx::SetCellEditor(int nRow, int nColumn, PFNEDITORCALLBACK pfnInitEditor, PFNEDITORCALLBACK pfnEndEditor, CWnd* pWnd)
  770. {
  771. if(nRow < 0 || nRow >= GetItemCount() || nColumn < 0 || nColumn >= GetColumnCount()) return;
  772. CellInfo* pCellInfo = GetCellInfo(nRow, nColumn);
  773. if(!pCellInfo)
  774. SetCellData(nRow, nColumn, 0);
  775. pCellInfo = (CellInfo*)GetCellInfo(nRow, nColumn);
  776. ASSERT(pCellInfo);
  777. }
  778. pCellInfo->m_eiEditor.m_pfnInitEditor = pfnInitEditor;
  779. pCellInfo->m_eiEditor.m_pfnEndEditor = pfnEndEditor;
  780. pCellInfo->m_eiEditor.m_pWnd = pWnd;
  781. }
  782. void CListCtrlEx::SetCellEditor(int nRow, int nColumn, CWnd* pWnd)
  783. {
  784. SetCellEditor(nRow, nColumn, NULL, NULL, pWnd);
  785. }
  786. void CListCtrlEx::SetDefaultEditor(PFNEDITORCALLBACK pfnInitEditor, PFNEDITORCALLBACK pfnEndEditor, CWnd* pWnd)
  787. {
  788. m_eiDefEditor.m_pfnInitEditor = pfnInitEditor;
  789. m_eiDefEditor.m_pfnEndEditor = pfnEndEditor;
  790. m_eiDefEditor.m_pWnd = pWnd;
  791. }
  792. void CListCtrlEx::SetDefaultEditor(CWnd* pWnd)
  793. {
  794. SetDefaultEditor(NULL, NULL, pWnd);
  795. }
  796. void CListCtrlEx::SetColumnReadOnly(int nColumn, bool bReadOnly)
  797. {
  798. if(nColumn < 0 || nColumn >= GetColumnCount()) return;
  799. ColumnInfo *pInfo = (ColumnInfo*)GetColumnInfo(nColumn);
  800. if(!pInfo) SetColumnEditor(nColumn, (CWnd*)NULL);
  801. pInfo = (ColumnInfo*)GetColumnInfo(nColumn);
  802. ASSERT(pInfo);
  803. pInfo->m_eiEditor.m_bReadOnly = bReadOnly;
  804. }
  805. void CListCtrlEx::SetColumnSorting(int nColumn, Sort eSort, Comparer eComparer)
  806. {
  807. if(nColumn < 0 || nColumn >= GetColumnCount() || !(eSort & SortBits)) return;
  808. ColumnInfo *pInfo = (ColumnInfo*)GetColumnInfo(nColumn);
  809. if(!pInfo) SetColumnEditor(nColumn, (CWnd*)NULL);
  810. pInfo = (ColumnInfo*)GetColumnInfo(nColumn);
  811. ASSERT(pInfo);
  812. pInfo->m_eSort = eSort;
  813. pInfo->m_eCompare = eComparer;
  814. pInfo->m_fnCompare = NULL;
  815. }
  816. void CListCtrlEx::SetColumnSorting(int nColumn, Sort eSort, PFNLVCOMPARE fnCallBack)
  817. {
  818. if(nColumn < 0 || nColumn >= GetColumnCount() || !(eSort & SortBits)) return;
  819. ColumnInfo *pInfo = (ColumnInfo*)GetColumnInfo(nColumn);
  820. if(!pInfo) SetColumnEditor(nColumn, (CWnd*)NULL);
  821. pInfo = (ColumnInfo*)GetColumnInfo(nColumn);
  822. ASSERT(pInfo);
  823. pInfo->m_eSort = eSort;
  824. pInfo->m_eCompare = NotSet;
  825. pInfo->m_fnCompare = fnCallBack;
  826. }
  827. void CListCtrlEx::SetCellReadOnly(int nRow, int nColumn, bool bReadOnly )
  828. {
  829. if(nRow < 0 || nRow >= GetItemCount() || nColumn < 0 || nColumn >= GetColumnCount()) return;
  830. CellInfo *pInfo = (CellInfo*)GetCellInfo(nRow, nColumn);
  831. if(!pInfo) SetCellEditor(nRow, nColumn, (CWnd*)NULL);
  832. pInfo = (CellInfo*)GetCellInfo(nRow, nColumn);
  833. ASSERT(pInfo);
  834. pInfo->m_eiEditor.m_bReadOnly = bReadOnly;
  835. }
  836. void CListCtrlEx::SetRowReadOnly(int nRow, bool bReadOnly)
  837. {
  838. if(nRow < 0 || nRow >= GetItemCount() ) return;
  839. ItemData *pInfo = (ItemData*)GetItemDataInternal(nRow);
  840. if(!pInfo) SetItemData(nRow, 0);
  841. pInfo = (ItemData*)GetItemDataInternal(nRow);
  842. ASSERT(pInfo);
  843. pInfo->m_eiEditor.m_bReadOnly = bReadOnly;
  844. }
  845. BOOL CListCtrlEx::IsColumnReadOnly(int nColumn)
  846. {
  847. if(nColumn < 0 || nColumn >= GetColumnCount()) return FALSE;
  848. ColumnInfo *pInfo = (ColumnInfo*)GetColumnInfo(nColumn);
  849. if( pInfo )
  850. {
  851.  return pInfo->m_eiEditor.m_bReadOnly;
  852. }
  853. return FALSE;
  854. }
  855. BOOL CListCtrlEx::IsRowReadOnly(int nRow)
  856. {
  857. if(nRow < 0 || nRow >= GetItemCount() ) return FALSE;
  858. ItemData *pInfo = (ItemData*)GetItemDataInternal(nRow);
  859. if( pInfo )
  860. {
  861.  return pInfo->m_eiEditor.m_bReadOnly;
  862. }
  863. return FALSE;
  864. }
  865. BOOL CListCtrlEx::IsCellReadOnly(int nRow, int nColumn)
  866. {
  867. if(nRow < 0 || nRow >= GetItemCount() || nColumn < 0 || nColumn >= GetColumnCount()) return FALSE;
  868. CellInfo *pInfo = (CellInfo*)GetCellInfo(nRow, nColumn);
  869. if( pInfo )
  870. {
  871.  return pInfo->m_eiEditor.m_bReadOnly;
  872. }
  873. else
  874. return (IsRowReadOnly(nRow) || IsColumnReadOnly(nColumn));
  875. }
  876. void CListCtrlEx::DeleteSelectedItems(void)
  877. {
  878. int nItem = -1;
  879. while((nItem = GetNextItem(-1, LVNI_SELECTED)) >= 0)
  880. {
  881. DeleteItem(nItem);
  882. }
  883. }
  884. void CListCtrlEx::HandleDeleteKey(BOOL bHandle)
  885. {
  886. m_bHandleDelete = bHandle;
  887. }
  888. void CListCtrlEx::SelectItem(int nItem, BOOL bSelect)
  889. {
  890. if(nItem < 0)
  891. {
  892. int nIndex = -1;
  893. while((nIndex = this->GetNextItem(nIndex, bSelect ? LVNI_ALL : LVNI_SELECTED)) >= 0)
  894. {
  895. this->SetItemState(nIndex, (bSelect ? LVIS_SELECTED: 0 ), LVIS_SELECTED);
  896. }
  897. }
  898. else
  899. {
  900. this->SetItemState(nItem, (bSelect ? LVIS_SELECTED: 0 ), LVIS_SELECTED);
  901. }
  902. }
  903. BOOL CListCtrlEx::DeleteAllColumns(void)
  904. {
  905. while(DeleteColumn(0));
  906. return (GetColumnCount() == 0);
  907. }
  908. BOOL CListCtrlEx::Reset(void)
  909. {
  910. return (DeleteAllItems() &&
  911. DeleteAllColumns());
  912. }
  913. int CListCtrlEx::Compare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  914. {
  915. CListCtrlEx *This = (CListCtrlEx *)lParamSort;
  916. if(!This || This->m_nSortColumn < 0 || This->m_nSortColumn >= This->GetColumnCount()) return 0;
  917. int nSubItem = This->m_nSortColumn;
  918. ColumnInfo *pInfo = This->GetColumnInfo(nSubItem);
  919. if(!pInfo) return 0;
  920. CString strLeft = This->GetItemText(lParam1, nSubItem);
  921. CString strRight = This->GetItemText(lParam2, nSubItem);
  922. switch(pInfo->m_eCompare)
  923. {
  924. case Int:
  925. return CompareInt(strLeft, strRight);
  926. case Double:
  927. return CompareDouble(strLeft, strRight);
  928. case StringNoCase:
  929. return CompareStringNoCase(strLeft, strRight);
  930. case StringNumber:
  931. return CompareNumberString(strLeft, strRight);
  932. case StringNumberNoCase:
  933. return CompareNumberStringNoCase(strLeft, strRight);
  934. case String:
  935. return CompareString(strLeft, strRight);
  936. case Date:
  937. return CompareDate(strLeft, strRight);
  938. case NotSet:
  939. return 0;
  940. default:
  941. return CompareString(strLeft, strRight);
  942. }
  943. return CompareString(strLeft, strRight);
  944. }
  945. int CListCtrlEx::CompareInt(LPCSTR pLeftText, LPCSTR pRightText)
  946. {
  947. return (int)(atol(pLeftText) - atol(pRightText));
  948. }
  949. int CListCtrlEx::CompareDouble(LPCSTR pLeftText, LPCSTR pRightText)
  950. {
  951. return (int)(atof(pLeftText) - atof(pRightText));
  952. }
  953. int CListCtrlEx::CompareString(LPCSTR pLeftText, LPCSTR pRightText)
  954. {
  955. return CString(pLeftText).Compare(pRightText);
  956. }
  957. int CListCtrlEx::CompareNumberString(LPCSTR pLeftText, LPCSTR pRightText)
  958. {
  959. LONGLONG l1 = atol(pLeftText);
  960. LONGLONG l2 = atol(pRightText);
  961. if(l1 && l2 && (l1 - l2))
  962. {
  963. CString str1, str2;
  964. str1.Format("%ld", l1);
  965. str2.Format("%ld", l2);
  966. CString left(pLeftText);
  967. CString right(pRightText);
  968. if(str1.GetLength() == left.GetLength() && str2.GetLength() == right.GetLength()) return (int) (l1 - l2);
  969. }
  970. return CString(pLeftText).Compare(pRightText);
  971. }
  972. int CListCtrlEx::CompareNumberStringNoCase(LPCSTR pLeftText, LPCSTR pRightText)
  973. {
  974. LONGLONG l1 = atol(pLeftText);
  975. LONGLONG l2 = atol(pRightText);
  976. if(l1 && l2 && (l1 - l2))
  977. {
  978. CString str1, str2;
  979. str1.Format("%ld", l1);
  980. str2.Format("%ld", l2);
  981. CString left(pLeftText);
  982. CString right(pRightText);
  983. if(str1.GetLength() == left.GetLength() && str2.GetLength() == right.GetLength()) return (int) (l1 - l2);
  984. }
  985. return CString(pLeftText).CompareNoCase(pRightText);
  986. }
  987. int CListCtrlEx::CompareStringNoCase(LPCSTR pLeftText, LPCSTR pRightText)
  988. {
  989. return CString(pLeftText).CompareNoCase(pRightText);
  990. }
  991. int CListCtrlEx::CompareDate(LPCSTR pLeftText, LPCSTR pRightText)
  992. {
  993. COleDateTime dL, dR;
  994. dL.ParseDateTime(pLeftText);
  995. dR.ParseDateTime(pRightText);
  996. return (dL == dR ? 0 :(dL < dR ? -1 : 1));
  997. }
  998. BOOL CListCtrlEx::PreCreateWindow(CREATESTRUCT& cs)
  999. {
  1000. cs.dwExStyle |= LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES;
  1001. return CListCtrl::PreCreateWindow(cs);
  1002. }