Source code of Windows XP (NT5)
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.

302 lines
8.4 KiB

  1. /*****************************************************************************
  2. *
  3. * lvframe.cpp
  4. *
  5. * Frame window that hosts a listview.
  6. *
  7. *****************************************************************************/
  8. #include "sdview.h"
  9. /*****************************************************************************
  10. *
  11. * class LVFrame
  12. *
  13. *****************************************************************************/
  14. LRESULT
  15. LVFrame::HandleMessage(UINT uiMsg, WPARAM wParam, LPARAM lParam)
  16. {
  17. switch (uiMsg) {
  18. FW_MSG(WM_NOTIFY);
  19. FW_MSG(WM_COMMAND);
  20. FW_MSG(WM_CONTEXTMENU);
  21. }
  22. return super::HandleMessage(uiMsg, wParam, lParam);
  23. }
  24. LRESULT LVFrame::ON_WM_NOTIFY(UINT uiMsg, WPARAM wParam, LPARAM lParam)
  25. {
  26. NMHDR *pnm = RECAST(NMHDR *, lParam);
  27. if (pnm->idFrom == IDC_LIST) {
  28. switch (pnm->code) {
  29. case LVN_ITEMACTIVATE:
  30. {
  31. NMITEMACTIVATE *pia = CONTAINING_RECORD(pnm, NMITEMACTIVATE, hdr);
  32. return SendSelfMessage(LM_ITEMACTIVATE, pia->iItem, 0);
  33. }
  34. break;
  35. case LVN_GETINFOTIP:
  36. {
  37. NMLVGETINFOTIP *pgit = CONTAINING_RECORD(pnm, NMLVGETINFOTIP, hdr);
  38. LPTSTR pszBuf = pgit->pszText;
  39. SendSelfMessage(LM_GETINFOTIP, pgit->iItem, RECAST(LPARAM, pgit));
  40. LPTSTR pszInfoTip = pgit->pszText;
  41. pgit->pszText = pszBuf;
  42. _it.SetInfoTip(pgit, pszInfoTip);
  43. }
  44. return 0;
  45. case LVN_DELETEITEM:
  46. {
  47. NMLISTVIEW *plv = CONTAINING_RECORD(pnm, NMLISTVIEW, hdr);
  48. SendSelfMessage(LM_DELETEITEM, plv->iItem, plv->lParam);
  49. }
  50. return 0;
  51. default:;
  52. }
  53. }
  54. return super::HandleMessage(uiMsg, wParam, lParam);
  55. }
  56. LRESULT LVFrame::ON_WM_COMMAND(UINT uiMsg, WPARAM wParam, LPARAM lParam)
  57. {
  58. int iSel;
  59. switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  60. case IDM_COPY:
  61. iSel = GetCurSel();
  62. if (iSel >= 0) {
  63. SendSelfMessage(LM_COPYTOCLIPBOARD, iSel, iSel + 1);
  64. }
  65. return 0;
  66. case IDM_COPYALL:
  67. SendSelfMessage(LM_COPYTOCLIPBOARD, 0, ListView_GetItemCount(_hwndChild));
  68. return 0;
  69. }
  70. return super::HandleMessage(uiMsg, wParam, lParam);
  71. }
  72. LRESULT LVFrame::ON_WM_CONTEXTMENU(UINT uiMsg, WPARAM wParam, LPARAM lParam)
  73. {
  74. int iItem;
  75. HMENU hmenu;
  76. if ((DWORD)lParam == 0xFFFFFFFF) {
  77. iItem = ListView_GetCurSel(_hwndChild);
  78. if (iItem < 0) {
  79. goto fail;
  80. }
  81. RECT rc;
  82. if (!ListView_GetItemRect(_hwndChild, iItem, &rc, LVIR_LABEL)) {
  83. goto fail;
  84. }
  85. MapWindowRect(_hwndChild, HWND_DESKTOP, &rc);
  86. int cyHalf = (rc.bottom - rc.top)/2;
  87. lParam = MAKELPARAM(rc.left + cyHalf, rc.top + cyHalf);
  88. } else {
  89. LVHITTESTINFO hti;
  90. hti.pt.x = GET_X_LPARAM(lParam);
  91. hti.pt.y = GET_Y_LPARAM(lParam);
  92. ScreenToClient(_hwndChild, &hti.pt);
  93. iItem = ListView_HitTest(_hwndChild, &hti);
  94. if (iItem < 0) {
  95. goto fail;
  96. }
  97. ListView_SetCurSel(_hwndChild, iItem);
  98. }
  99. hmenu = RECAST(HMENU, SendSelfMessage(LM_GETCONTEXTMENU, iItem, 0));
  100. if (!hmenu) {
  101. goto fail;
  102. }
  103. TrackPopupMenuEx(hmenu,
  104. TPM_LEFTALIGN | TPM_TOPALIGN |
  105. TPM_RIGHTBUTTON | TPM_NONOTIFY,
  106. GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
  107. _hwnd, NULL);
  108. DestroyMenu(hmenu);
  109. return 0;
  110. fail:
  111. return super::HandleMessage(uiMsg, wParam, lParam);
  112. }
  113. BOOL LVFrame::CreateChild(DWORD dwStyle, DWORD dwExStyle)
  114. {
  115. _hwndChild = CreateWindowEx(WS_EX_CLIENTEDGE,
  116. WC_LISTVIEW, NULL,
  117. WS_CHILD | WS_VISIBLE |
  118. WS_BORDER | WS_TABSTOP |
  119. WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
  120. dwStyle,
  121. 0,0,0,0,
  122. _hwnd, RECAST(HMENU, IDC_LIST), g_hinst, 0);
  123. if (!_hwndChild) return FALSE;
  124. ListView_SetExtendedListViewStyleEx(_hwndChild, dwExStyle, dwExStyle);
  125. SetFocus(_hwndChild);
  126. _it.Attach(_hwndChild);
  127. return TRUE;
  128. }
  129. BOOL LVFrame::AddColumns(const LVFCOLUMN *pcol)
  130. {
  131. int cxChar = LOWORD(GetDialogBaseUnits());
  132. for (; pcol->cch; pcol++) {
  133. LVCOLUMN lvc;
  134. TCHAR szName[MAX_PATH];
  135. LoadString(g_hinst, pcol->ids, szName, ARRAYSIZE(szName));
  136. lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
  137. lvc.fmt = pcol->fmt;
  138. lvc.pszText = szName;
  139. lvc.cx = pcol->cch * cxChar;
  140. ListView_InsertColumn(_hwndChild, MAXLONG, &lvc);
  141. }
  142. return TRUE;
  143. }
  144. void *LVFrame::GetLVItem(int iItem)
  145. {
  146. LVITEM lvi;
  147. lvi.iItem = iItem;
  148. lvi.iSubItem = 0;
  149. lvi.mask = LVIF_PARAM;
  150. lvi.lParam = 0;
  151. ListView_GetItem(_hwndChild, &lvi);
  152. return RECAST(LPVOID, lvi.lParam);
  153. }
  154. /*****************************************************************************
  155. *
  156. * LVInfoTip
  157. *
  158. *****************************************************************************/
  159. void LVInfoTip::Attach(HWND hwnd)
  160. {
  161. if (SetProp(hwnd, GetSubclassProperty(), RECAST(HANDLE, this))) {
  162. _wndprocPrev = SubclassWindow(hwnd, SubclassWndProc);
  163. }
  164. // Those infotips can get really long, so set the autopop delay
  165. // to the maximum allowable value.
  166. HWND hwndTT = ListView_GetToolTips(hwnd);
  167. if (hwndTT) {
  168. SendMessage(hwndTT, TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT);
  169. }
  170. }
  171. void LVInfoTip::FreeLastTipAlt()
  172. {
  173. if (_pszLastTipAlt) {
  174. LPSSTR pszFree = _pszLastTipAlt;
  175. _pszLastTipAlt = NULL;
  176. delete [] pszFree;
  177. }
  178. }
  179. void LVInfoTip::SetInfoTip(NMLVGETINFOTIP *pgit, LPCTSTR pszTip)
  180. {
  181. _pszLastTip = NULL;
  182. FreeLastTipAlt();
  183. if (pgit->pszText != pszTip) {
  184. if (lstrlen(pszTip) >= pgit->cchTextMax) {
  185. _pszLastTip = pszTip;
  186. }
  187. lstrcpyn(pgit->pszText, pszTip, pgit->cchTextMax);
  188. }
  189. }
  190. //
  191. // Convert from TCHAR to SCHAR.
  192. //
  193. inline int T2S(LPCTSTR pszIn, int cchIn, LPSSTR pszOut, int cchOut)
  194. {
  195. #ifdef UNICODE
  196. return WideCharToMultiByte(CP_ACP, 0, pszIn, cchIn, pszOut, cchOut, NULL, NULL);
  197. #else
  198. return MultiByteToWideChar(CP_ACP, 0, pszIn, cchIn, pszOut, cchOut);
  199. #endif
  200. }
  201. //
  202. // Make _pszLastTipAlt match _pszLastTip, but of opposite character set.
  203. //
  204. BOOL LVInfoTip::ThunkLastTip()
  205. {
  206. ASSERT(_pszLastTip);
  207. FreeLastTipAlt();
  208. int cch = T2S(_pszLastTip, -1, NULL, 0);
  209. if (cch) {
  210. _pszLastTipAlt = new SCHAR[cch];
  211. if (_pszLastTipAlt &&
  212. T2S(_pszLastTip, -1, _pszLastTipAlt, cch)) {
  213. return TRUE;
  214. }
  215. }
  216. return FALSE;
  217. }
  218. LRESULT LVInfoTip::SubclassWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  219. {
  220. LVInfoTip *self = RECAST(LVInfoTip *, GetProp(hwnd, GetSubclassProperty()));
  221. if (self) {
  222. LRESULT lres;
  223. NMHDR *pnm;
  224. switch (uMsg) {
  225. case WM_NOTIFY:
  226. pnm = RECAST(NMHDR *, lParam);
  227. switch (pnm->code) {
  228. case TTN_GETDISPINFOA:
  229. case TTN_GETDISPINFOW:
  230. lres = CallWindowProc(self->_wndprocPrev, hwnd, uMsg, wParam, lParam);
  231. if (SendMessage(pnm->hwndFrom, TTM_GETMAXTIPWIDTH, 0, 0) >= 0) {
  232. // It's an infotip. Tweak it to suit our needs.
  233. NMTTDISPINFO *ptdi = CONTAINING_RECORD(pnm, NMTTDISPINFO, hdr);
  234. // Set the width to the maximum allowed without going single-line.
  235. SendMessage(pnm->hwndFrom, TTM_SETMAXTIPWIDTH, 0, MAXLONG);
  236. // If we overflowed the returned buffer, then listview used
  237. // only a partial infotip. So fill in the rest here.
  238. if (self->_pszLastTip) {
  239. if (pnm->code == TTN_GETDISPINFO) {
  240. ptdi->lpszText = CCAST(LPTSTR, self->_pszLastTip);
  241. } else {
  242. if (self->ThunkLastTip()) {
  243. ptdi->lpszText = RECAST(LPTSTR, self->_pszLastTipAlt);
  244. }
  245. }
  246. }
  247. } else {
  248. self->_pszLastTip = NULL;
  249. }
  250. return lres;
  251. }
  252. }
  253. return CallWindowProc(self->_wndprocPrev, hwnd, uMsg, wParam, lParam);
  254. } else {
  255. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  256. }
  257. }