Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

462 lines
10 KiB

  1. //============================================================================
  2. // Copyright (C) Microsoft Corporation, 1996 - 1999
  3. //
  4. // File: lcx.cpp
  5. //
  6. // History:
  7. // 07/13/96 Abolade Gbadegesin Created, based on C code by Steve Cobb
  8. //
  9. // Implements an enhanced list-control.
  10. //============================================================================
  11. #include "stdafx.h"
  12. #include "resource.h"
  13. #include "util.h"
  14. #include "listctrl.h"
  15. #ifdef _DEBUG
  16. #define new DEBUG_NEW
  17. #undef THIS_FILE
  18. static char THIS_FILE[] = __FILE__;
  19. #endif
  20. IMPLEMENT_DYNAMIC(CListCtrlEx, CListCtrl)
  21. BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
  22. //{{AFX_MSG_MAP(CListCtrlEx)
  23. ON_WM_LBUTTONDOWN()
  24. ON_WM_CHAR()
  25. ON_WM_KEYDOWN()
  26. //}}AFX_MSG_MAP
  27. END_MESSAGE_MAP()
  28. //----------------------------------------------------------------------------
  29. // Function: CListCtrlEx::~CListCtrlEx
  30. //
  31. // Destructor. Deletes the image list, if any, and unloads row-information.
  32. //----------------------------------------------------------------------------
  33. CListCtrlEx::~CListCtrlEx(
  34. ) {
  35. delete m_pimlChecks;
  36. }
  37. //----------------------------------------------------------------------------
  38. // Function: CListCtrlEx::GetColumnCount
  39. //
  40. // Called to retrieve the number of columns in any list-control.
  41. //----------------------------------------------------------------------------
  42. INT
  43. CListCtrlEx::GetColumnCount(
  44. ) {
  45. return Header_GetItemCount(ListView_GetHeader(m_hWnd));
  46. }
  47. //----------------------------------------------------------------------------
  48. // Function: CListCtrlEx::SetColumnText
  49. //
  50. // Sets the text in the header of the column in position 'iCol'.
  51. //----------------------------------------------------------------------------
  52. BOOL
  53. CListCtrlEx::SetColumnText(
  54. INT iCol,
  55. LPCTSTR pszText,
  56. INT fmt
  57. ) {
  58. LV_COLUMN lvc;
  59. lvc.mask = LVCF_FMT | LVCF_TEXT;
  60. lvc.pszText = (LPTSTR)pszText;
  61. lvc.fmt = fmt;
  62. return SetColumn(iCol, &lvc);
  63. }
  64. //----------------------------------------------------------------------------
  65. // Function: CListCtrlEx::InstallChecks
  66. //
  67. // Installs check-box handling for the list-control.
  68. //----------------------------------------------------------------------------
  69. BOOL
  70. CListCtrlEx::InstallChecks(
  71. ) {
  72. HICON hIcon;
  73. //
  74. // Make sure the list-control is in report-mode
  75. //
  76. if (!(GetStyle() & LVS_REPORT)) { return FALSE; }
  77. //
  78. // Allocate a new image-list.
  79. //
  80. m_pimlChecks = new CImageList;
  81. if (!m_pimlChecks) { return FALSE; }
  82. do {
  83. //
  84. // Initialize the image-list
  85. //
  86. if (!m_pimlChecks->Create(
  87. ::GetSystemMetrics(SM_CXSMICON),
  88. ::GetSystemMetrics(SM_CYSMICON),
  89. ILC_MASK, 2, 2
  90. )) {
  91. break;
  92. }
  93. //
  94. // Add the icons for the checked and unchecked images
  95. //
  96. hIcon = ::LoadIcon(
  97. AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_COMMON_UNCHECK)
  98. );
  99. if (!hIcon) { break; }
  100. m_pimlChecks->Add(hIcon); ::DeleteObject(hIcon);
  101. hIcon = ::LoadIcon(
  102. AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_COMMON_CHECK)
  103. );
  104. if (!hIcon) { break; }
  105. m_pimlChecks->Add(hIcon); ::DeleteObject(hIcon);
  106. //
  107. // Replace the list-control's current image-list with the new one
  108. //
  109. m_pimlOldState = SetImageList(m_pimlChecks, LVSIL_STATE);
  110. return TRUE;
  111. } while(FALSE);
  112. //
  113. // If we arrive here, an error occurred, so clean up and fail
  114. //
  115. delete m_pimlChecks; m_pimlChecks = NULL;
  116. return FALSE;
  117. }
  118. //----------------------------------------------------------------------------
  119. // Function: CListCtrlEx::UninstallChecks
  120. //
  121. // Uninstalls checkbox-handling for the list-control.
  122. //----------------------------------------------------------------------------
  123. VOID
  124. CListCtrlEx::UninstallChecks(
  125. ) {
  126. if (!m_pimlChecks) { return; }
  127. if (m_pimlOldState) { SetImageList(m_pimlOldState, LVSIL_STATE); }
  128. delete m_pimlChecks; m_pimlChecks = NULL;
  129. }
  130. //----------------------------------------------------------------------------
  131. // Function: CListCtrlEx::GetCheck
  132. //
  133. // Returns TRUE if the specified item is checked, FALSE otherwise.
  134. //----------------------------------------------------------------------------
  135. BOOL
  136. CListCtrlEx::GetCheck(
  137. INT iItem
  138. ) {
  139. return !!(GetItemState(iItem, LVIS_STATEIMAGEMASK) &
  140. INDEXTOSTATEIMAGEMASK(LCXI_CHECKED));
  141. }
  142. //----------------------------------------------------------------------------
  143. // Function: CListCtrlEx::SetCheck
  144. //
  145. // If 'fCheck' is non-zero, checks 'iItem', otherwise clears 'iItem'.
  146. //----------------------------------------------------------------------------
  147. VOID
  148. CListCtrlEx::SetCheck(
  149. INT iItem,
  150. BOOL fCheck
  151. ) {
  152. SetItemState(
  153. iItem,
  154. INDEXTOSTATEIMAGEMASK(fCheck ? LCXI_CHECKED : LCXI_UNCHECKED),
  155. LVIS_STATEIMAGEMASK
  156. );
  157. if (GetParent()) {
  158. NMHDR nmh;
  159. nmh.code = LVXN_SETCHECK;
  160. nmh.hwndFrom = m_hWnd;
  161. ::SendMessage(
  162. GetParent()->m_hWnd, WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmh
  163. );
  164. }
  165. }
  166. //----------------------------------------------------------------------------
  167. // Function: CListCtrlEx::OnChar
  168. //
  169. // Handles the 'WM_CHAR' message for the list-control.
  170. // This allows users to change items' checked-states using the keyboard.
  171. //----------------------------------------------------------------------------
  172. VOID
  173. CListCtrlEx::OnChar(
  174. UINT nChar,
  175. UINT nRepCnt,
  176. UINT nFlags
  177. ) {
  178. BOOL fSet = FALSE;
  179. BOOL fClear = FALSE;
  180. BOOL fToggle = FALSE;
  181. INT iItem;
  182. //
  183. // Handle characters with special meaning for us
  184. //
  185. switch (nChar) {
  186. case TEXT(' '): { fToggle = TRUE; break; }
  187. case TEXT('+'):
  188. case TEXT('='): { fSet = TRUE; break; }
  189. case TEXT('-'): { fClear = TRUE; break; }
  190. }
  191. if (!fToggle && !fSet && !fClear) {
  192. CListCtrl::OnChar(nChar, nRepCnt, nFlags);
  193. }
  194. else {
  195. //
  196. // Change the state of all the selected items
  197. //
  198. for (iItem = GetNextItem(-1, LVNI_SELECTED);
  199. iItem != -1;
  200. iItem = GetNextItem(iItem, LVNI_SELECTED)) {
  201. if (fToggle) {
  202. SetCheck(iItem, !GetCheck(iItem));
  203. }
  204. else
  205. if (fSet) {
  206. if (!GetCheck(iItem)) { SetCheck(iItem, TRUE); }
  207. }
  208. else {
  209. if (GetCheck(iItem)) { SetCheck(iItem, FALSE); }
  210. }
  211. }
  212. }
  213. }
  214. //----------------------------------------------------------------------------
  215. // Function: CListCtrlEx::OnKeyDown
  216. //
  217. // Handles the 'WM_KEYDOWN' message for the list-control.
  218. // This allows users to change items' checked-states using the keyboard.
  219. //----------------------------------------------------------------------------
  220. VOID
  221. CListCtrlEx::OnKeyDown(
  222. UINT nChar,
  223. UINT nRepCnt,
  224. UINT nFlags
  225. ) {
  226. //
  227. // We want the left-arrow treated as an up-arrow
  228. // and the right-arrow treated as a down-arrow.
  229. //
  230. if (nChar == VK_LEFT) {
  231. CListCtrl::OnKeyDown(VK_UP, nRepCnt, nFlags); return;
  232. }
  233. else
  234. if (nChar == VK_RIGHT) {
  235. CListCtrl::OnKeyDown(VK_DOWN, nRepCnt, nFlags); return;
  236. }
  237. CListCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
  238. }
  239. //----------------------------------------------------------------------------
  240. // Function: CListCtrlEx::OnLButtonDown
  241. //
  242. // Handles the 'WM_LBUTTONDOWN' message, changing an item's checked state
  243. // when the user clicks the item's check-image.
  244. //----------------------------------------------------------------------------
  245. VOID
  246. CListCtrlEx::OnLButtonDown(
  247. UINT nFlags,
  248. CPoint pt
  249. ) {
  250. INT iItem;
  251. UINT uiFlags;
  252. //
  253. // If the left-mouse button is over the check-box icon,
  254. // we treat it as a toggle on the check-box.
  255. //
  256. uiFlags = 0;
  257. iItem = HitTest(pt, &uiFlags);
  258. if (iItem != -1 && (uiFlags & LVHT_ONITEMSTATEICON)) {
  259. SetCheck(iItem, !GetCheck(iItem));
  260. // Redraw this item
  261. RedrawItems(iItem, iItem);
  262. }
  263. CListCtrl::OnLButtonDown(nFlags, pt);
  264. }
  265. //----------------------------------------------------------------------------
  266. // Function: AdjustColumnWidth
  267. //
  268. // Called to adjust the width of column 'iCol' so that the string 'pszContent'
  269. // can be displayed in the column without truncation.
  270. //
  271. // If 'NULL' is specified for 'pszContent', the function adjusts the column
  272. // so that the first string in the column is displayed without truncation.
  273. //
  274. // Returns the new width of the column.
  275. //----------------------------------------------------------------------------
  276. INT
  277. AdjustColumnWidth(
  278. IN CListCtrl& listCtrl,
  279. IN INT iCol,
  280. IN LPCTSTR pszContent
  281. ) {
  282. INT iWidth, iOldWidth;
  283. //
  284. // Compute the minimum width the column needs to be
  285. //
  286. if (pszContent) {
  287. iWidth = listCtrl.GetStringWidth(pszContent);
  288. }
  289. else {
  290. iWidth = listCtrl.GetStringWidth(listCtrl.GetItemText(0, iCol));
  291. }
  292. //
  293. // Adjust 'iWidth' to leave some breathing space
  294. //
  295. iWidth += ::GetSystemMetrics(SM_CXSMICON) +
  296. ::GetSystemMetrics(SM_CXEDGE) * 2;
  297. //
  298. // If the column is narrower than 'iWidth', enlarge it.
  299. //
  300. iOldWidth = listCtrl.GetColumnWidth(iCol);
  301. if (iOldWidth < iWidth) {
  302. listCtrl.SetColumnWidth(iCol, iWidth);
  303. iOldWidth = iWidth;
  304. }
  305. return iOldWidth;
  306. }
  307. INT
  308. AdjustColumnWidth(
  309. IN CListCtrl& listCtrl,
  310. IN INT iCol,
  311. IN UINT idsContent
  312. ) {
  313. // Needed for Loadstring
  314. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  315. CString sCol;
  316. sCol.LoadString(idsContent);
  317. return AdjustColumnWidth(listCtrl, iCol, sCol);
  318. }