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.

900 lines
25 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: statsdlg.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // StatsDlg.cpp : implementation file
  11. //
  12. #include "stdafx.h"
  13. #include "StatsDlg.h"
  14. #include "coldlg.h"
  15. #include "modeless.h" // ModelessThread
  16. #ifdef _DEBUG
  17. #define new DEBUG_NEW
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21. BEGIN_MESSAGE_MAP(CStatsListCtrl, CListCtrl)
  22. //{{AFX_MSG_MAP(CStatsListCtrl)
  23. ON_WM_KEYDOWN()
  24. //}}AFX_MSG_MAP
  25. END_MESSAGE_MAP()
  26. void CStatsListCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  27. {
  28. BOOL fControlDown;
  29. BOOL fShiftDown;
  30. fControlDown = (GetKeyState(VK_CONTROL) < 0);
  31. fShiftDown = (GetKeyState(VK_SHIFT) < 0);
  32. switch(nChar)
  33. {
  34. case 'c':
  35. case 'C':
  36. case VK_INSERT:
  37. if (fControlDown)
  38. CopyToClipboard();
  39. break;
  40. }
  41. }
  42. void CStatsListCtrl::CopyToClipboard()
  43. {
  44. CString strText, strLine, strData;
  45. int nCount = GetItemCount();
  46. int nColumns = 0;
  47. TCHAR szBuffer[256];
  48. LV_COLUMN ColumnInfo = {0};
  49. ColumnInfo.mask = LVCF_TEXT;
  50. ColumnInfo.pszText = szBuffer;
  51. ColumnInfo.cchTextMax = sizeof(szBuffer);
  52. // build up the column info
  53. while (GetColumn(nColumns, &ColumnInfo))
  54. {
  55. if (!strLine.IsEmpty())
  56. strLine += _T(",");
  57. strLine += ColumnInfo.pszText;
  58. nColumns++;
  59. }
  60. strLine += _T("\r\n");
  61. strData += strLine;
  62. strLine.Empty();
  63. // now get the other data
  64. for (int i = 0; i < nCount; i++)
  65. {
  66. for (int j = 0; j < nColumns; j++)
  67. {
  68. if (!strLine.IsEmpty())
  69. strLine += _T(",");
  70. strText = GetItemText(i, j);
  71. strLine += strText;
  72. }
  73. strLine += _T("\r\n");
  74. strData += strLine;
  75. strLine.Empty();
  76. }
  77. int nLength = strData.GetLength() + 1;
  78. nLength *= sizeof(TCHAR);
  79. HGLOBAL hMem = GlobalAlloc(GPTR, nLength);
  80. if (hMem)
  81. {
  82. memcpy (hMem, strData, nLength);
  83. if (!OpenClipboard())
  84. {
  85. GlobalFree(hMem);
  86. return;
  87. }
  88. EmptyClipboard();
  89. SetClipboardData(CF_UNICODETEXT, hMem);
  90. CloseClipboard();
  91. }
  92. }
  93. /*!--------------------------------------------------------------------------
  94. StatsDialog::StatsDialog
  95. -
  96. Author: KennT
  97. ---------------------------------------------------------------------------*/
  98. StatsDialog::StatsDialog(DWORD dwOptions) :
  99. m_dwOptions(dwOptions),
  100. m_ulId(0),
  101. m_pConfig(NULL),
  102. m_bAfterInitDialog(FALSE)
  103. {
  104. m_sizeMinimum.cx = m_sizeMinimum.cy = 0;
  105. m_hEventThreadKilled = ::CreateEvent(NULL, FALSE, FALSE, NULL);
  106. Assert(m_hEventThreadKilled);
  107. // Initialize the array of buttons
  108. ::ZeroMemory(m_rgBtn, sizeof(m_rgBtn));
  109. m_rgBtn[INDEX_CLOSE].m_ulId = IDCANCEL;
  110. m_rgBtn[INDEX_REFRESH].m_ulId = IDC_STATSDLG_BTN_REFRESH;
  111. m_rgBtn[INDEX_SELECT].m_ulId = IDC_STATSDLG_BTN_SELECT_COLUMNS;
  112. m_rgBtn[INDEX_CLEAR].m_ulId = IDC_STATSDLG_BTN_CLEAR;
  113. // Bug 134785 - create the ability to default to an ascending
  114. // rather than a descending sort.
  115. m_fSortDirection = !((dwOptions & STATSDLG_DEFAULTSORT_ASCENDING) != 0);
  116. m_fDefaultSortDirection = m_fSortDirection;
  117. // Multiply text header width with 2 for width of columns
  118. m_ColWidthMultiple = 2;
  119. m_ColWidthAdder = 0;
  120. }
  121. /*!--------------------------------------------------------------------------
  122. StatsDialog::~StatsDialog
  123. -
  124. Author: KennT
  125. ---------------------------------------------------------------------------*/
  126. StatsDialog::~StatsDialog()
  127. {
  128. if (m_hEventThreadKilled)
  129. ::CloseHandle(m_hEventThreadKilled);
  130. m_hEventThreadKilled = 0;
  131. }
  132. /*!--------------------------------------------------------------------------
  133. StatsDialog::DoDataExchange
  134. -
  135. Author: KennT
  136. ---------------------------------------------------------------------------*/
  137. void StatsDialog::DoDataExchange(CDataExchange* pDX)
  138. {
  139. CBaseDialog::DoDataExchange(pDX);
  140. //{{AFX_DATA_MAP(StatsDialog)
  141. // NOTE: the ClassWizard will add DDX and DDV calls here
  142. DDX_Control(pDX, IDC_STATSDLG_LIST, m_listCtrl);
  143. //}}AFX_DATA_MAP
  144. }
  145. BEGIN_MESSAGE_MAP(StatsDialog, CBaseDialog)
  146. //{{AFX_MSG_MAP(StatsDialog)
  147. ON_COMMAND(IDC_STATSDLG_BTN_REFRESH, OnRefresh)
  148. ON_COMMAND(IDC_STATSDLG_BTN_SELECT_COLUMNS, OnSelectColumns)
  149. ON_WM_MOVE()
  150. ON_WM_SIZE()
  151. ON_WM_GETMINMAXINFO()
  152. ON_WM_CONTEXTMENU()
  153. ON_NOTIFY(LVN_COLUMNCLICK, IDC_STATSDLG_LIST, OnNotifyListControlClick)
  154. //}}AFX_MSG_MAP
  155. END_MESSAGE_MAP()
  156. /////////////////////////////////////////////////////////////////////////////
  157. // StatsDialog message handlers
  158. /*!--------------------------------------------------------------------------
  159. StatsDialog::SetColumnInfo
  160. -
  161. Author: KennT
  162. ---------------------------------------------------------------------------*/
  163. HRESULT StatsDialog::SetColumnInfo(const ContainerColumnInfo *pColumnInfo, UINT cColumnInfo)
  164. {
  165. if (m_pConfig)
  166. {
  167. m_pConfig->InitViewInfo(m_ulId, TRUE, cColumnInfo, m_fDefaultSortDirection, pColumnInfo);
  168. }
  169. else
  170. {
  171. m_viewInfo.InitViewInfo(cColumnInfo, TRUE, m_fDefaultSortDirection, pColumnInfo);
  172. }
  173. return hrOK;
  174. }
  175. /*!--------------------------------------------------------------------------
  176. StatsDialog::MapColumnToSubitem
  177. -
  178. Author: KennT
  179. ---------------------------------------------------------------------------*/
  180. int StatsDialog::MapColumnToSubitem(UINT nColumnId)
  181. {
  182. if (m_pConfig)
  183. return m_pConfig->MapColumnToSubitem(m_ulId, nColumnId);
  184. else
  185. return m_viewInfo.MapColumnToSubitem(nColumnId);
  186. }
  187. /*!--------------------------------------------------------------------------
  188. StatsDialog::MapSubitemToColumn
  189. -
  190. Author: KennT
  191. ---------------------------------------------------------------------------*/
  192. int StatsDialog::MapSubitemToColumn(UINT nSubitemId)
  193. {
  194. if (m_pConfig)
  195. return m_pConfig->MapSubitemToColumn(m_ulId, nSubitemId);
  196. else
  197. return m_viewInfo.MapSubitemToColumn(nSubitemId);
  198. }
  199. /*!--------------------------------------------------------------------------
  200. StatsDialog::IsSubitemVisible
  201. -
  202. Author: KennT
  203. ---------------------------------------------------------------------------*/
  204. BOOL StatsDialog::IsSubitemVisible(UINT nSubitemId)
  205. {
  206. if (m_pConfig)
  207. return m_pConfig->IsSubitemVisible(m_ulId, nSubitemId);
  208. else
  209. return m_viewInfo.IsSubitemVisible(nSubitemId);
  210. }
  211. /*!--------------------------------------------------------------------------
  212. StatsDialog::RefreshData
  213. -
  214. Author: KennT
  215. ---------------------------------------------------------------------------*/
  216. HRESULT StatsDialog::RefreshData(BOOL fGrabNewData)
  217. {
  218. return hrOK;
  219. }
  220. /*!--------------------------------------------------------------------------
  221. StatsDialog::OnInitDialog
  222. -
  223. Author: KennT
  224. ---------------------------------------------------------------------------*/
  225. BOOL StatsDialog::OnInitDialog()
  226. {
  227. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  228. RECT rcWnd, rcBtn;
  229. CBaseDialog::OnInitDialog();
  230. m_bAfterInitDialog = TRUE;
  231. // If this is the first time, get the location of the buttons and
  232. // list control relative to the edge of the screen
  233. if (m_sizeMinimum.cx == 0)
  234. {
  235. ::GetWindowRect(GetSafeHwnd(), &rcWnd);
  236. // m_sizeMinimum.cx = rcWnd.right - rcWnd.left;
  237. // m_sizeMinimum.cy = rcWnd.bottom - rcWnd.top;
  238. m_sizeMinimum.cx = 100;
  239. m_sizeMinimum.cy = 100;
  240. ::GetClientRect(GetSafeHwnd(), &rcWnd);
  241. // what are the button locations?
  242. for (int i=0; i<INDEX_COUNT; i++)
  243. {
  244. ::GetWindowRect(GetDlgItem(m_rgBtn[i].m_ulId)->GetSafeHwnd(),
  245. &rcBtn);
  246. ScreenToClient(&rcBtn);
  247. m_rgBtn[i].m_rc.left = rcWnd.right - rcBtn.left;
  248. m_rgBtn[i].m_rc.right = rcWnd.right - rcBtn.right;
  249. m_rgBtn[i].m_rc.top = rcWnd.bottom - rcBtn.top;
  250. m_rgBtn[i].m_rc.bottom = rcWnd.bottom - rcBtn.bottom;
  251. }
  252. // what is the list control location?
  253. // The list control top, left is locked in position
  254. ::GetWindowRect(GetDlgItem(IDC_STATSDLG_LIST)->GetSafeHwnd(), &rcBtn);
  255. ScreenToClient(&rcBtn);
  256. m_rcList.left = rcBtn.left;
  257. m_rcList.top = rcBtn.top;
  258. // The bottom, right corner follows the expansion
  259. m_rcList.right = rcWnd.right - rcBtn.right;
  260. m_rcList.bottom = rcWnd.bottom - rcBtn.bottom;
  261. }
  262. // If we have a preferred position and size do that
  263. if (m_pConfig)
  264. {
  265. m_pConfig->GetStatsWindowRect(m_ulId, &m_rcPosition);
  266. m_fSortDirection = m_pConfig->GetSortDirection(m_ulId);
  267. }
  268. if (m_pConfig && (m_rcPosition.top != m_rcPosition.bottom))
  269. {
  270. MoveWindow(m_rcPosition.left, m_rcPosition.top,
  271. m_rcPosition.right - m_rcPosition.left,
  272. m_rcPosition.bottom - m_rcPosition.top);
  273. }
  274. if (m_dwOptions & STATSDLG_FULLWINDOW)
  275. {
  276. RECT rcClient;
  277. // Resize the list control if needed
  278. GetClientRect(&rcClient);
  279. OnSize(SIZE_MAXIMIZED, rcClient.right - rcClient.left,
  280. rcClient.bottom - rcClient.top);
  281. // Disable the buttons also
  282. for (int i=0; i<INDEX_COUNT; i++)
  283. {
  284. GetDlgItem(m_rgBtn[i].m_ulId)->ShowWindow(SW_HIDE);
  285. if (i != INDEX_CLOSE)
  286. GetDlgItem(m_rgBtn[i].m_ulId)->EnableWindow(FALSE);
  287. }
  288. }
  289. // If we do not have the select columns then we hide and disable
  290. // the select columns button.
  291. if ((m_dwOptions & STATSDLG_SELECT_COLUMNS) == 0)
  292. {
  293. GetDlgItem(m_rgBtn[INDEX_SELECT].m_ulId)->ShowWindow(SW_HIDE);
  294. GetDlgItem(m_rgBtn[INDEX_SELECT].m_ulId)->EnableWindow(FALSE);
  295. }
  296. // If we do not have the clear button then we hide and disable
  297. // the clear button.
  298. if ((m_dwOptions & STATSDLG_CLEAR) == 0)
  299. {
  300. GetDlgItem(m_rgBtn[INDEX_CLEAR].m_ulId)->ShowWindow(SW_HIDE);
  301. GetDlgItem(m_rgBtn[INDEX_CLEAR].m_ulId)->EnableWindow(FALSE);
  302. }
  303. ListView_SetExtendedListViewStyle(GetDlgItem(IDC_STATSDLG_LIST)->GetSafeHwnd(), LVS_EX_FULLROWSELECT);
  304. // Now initialize the headers
  305. LoadHeaders();
  306. RefreshData(TRUE);
  307. if (m_pConfig)
  308. {
  309. Sort( m_pConfig->GetSortColumn(m_ulId) );
  310. }
  311. if ((m_dwOptions & STATSDLG_FULLWINDOW) == 0)
  312. {
  313. GetDlgItem(IDCANCEL)->SetFocus();
  314. return FALSE;
  315. }
  316. return TRUE;
  317. }
  318. /*!--------------------------------------------------------------------------
  319. StatsDialog::OnOK
  320. -
  321. Author: KennT
  322. ---------------------------------------------------------------------------*/
  323. void StatsDialog::OnOK()
  324. {
  325. }
  326. /*!--------------------------------------------------------------------------
  327. StatsDialog::OnCancel
  328. -
  329. Author: KennT
  330. ---------------------------------------------------------------------------*/
  331. void StatsDialog::OnCancel()
  332. {
  333. DeleteAllItems();
  334. DestroyWindow();
  335. // Explicitly kill this thread.
  336. AfxPostQuitMessage(0);
  337. }
  338. /*!--------------------------------------------------------------------------
  339. StatsDialog::PostNcDestroy
  340. -
  341. Author: KennT
  342. ---------------------------------------------------------------------------*/
  343. void StatsDialog::PostNcDestroy()
  344. {
  345. // Make sure that this is NULL since this is how we detect that
  346. // the dialog is showing
  347. m_hWnd = NULL;
  348. m_bAfterInitDialog = FALSE;
  349. }
  350. /*!--------------------------------------------------------------------------
  351. StatsDialog::PreCreateWindow
  352. -
  353. Author: KennT
  354. ---------------------------------------------------------------------------*/
  355. BOOL StatsDialog::PreCreateWindow(CREATESTRUCT& cs)
  356. {
  357. // Have to refresh the event
  358. Verify( ResetEvent(m_hEventThreadKilled) );
  359. return CBaseDialog::PreCreateWindow(cs);
  360. }
  361. /*!--------------------------------------------------------------------------
  362. StatsDialog::OnRefresh
  363. -
  364. Author: KennT
  365. ---------------------------------------------------------------------------*/
  366. void StatsDialog::OnRefresh()
  367. {
  368. if ((m_dwOptions & STATSDLG_VERTICAL) == 0)
  369. {
  370. DeleteAllItems();
  371. }
  372. RefreshData(TRUE);
  373. }
  374. /*!--------------------------------------------------------------------------
  375. StatsDialog::OnSelectColumns
  376. -
  377. Author: KennT
  378. ---------------------------------------------------------------------------*/
  379. void StatsDialog::OnSelectColumns()
  380. {
  381. // We should bring up the columns dialog
  382. ColumnDlg columnDlg(NULL);
  383. ColumnData *pColumnData;
  384. ULONG cColumns;
  385. ULONG cVisible;
  386. int i;
  387. DWORD dwWidth;
  388. if (m_pConfig)
  389. {
  390. cColumns = m_pConfig->GetColumnCount(m_ulId);
  391. cVisible = m_pConfig->GetVisibleColumns(m_ulId);
  392. }
  393. else
  394. {
  395. cColumns = m_viewInfo.GetColumnCount();
  396. cVisible = m_viewInfo.GetVisibleColumns();
  397. }
  398. pColumnData = (ColumnData *) alloca(sizeof(ColumnData) * cColumns);
  399. if (m_pConfig)
  400. m_pConfig->GetColumnData(m_ulId, cColumns, pColumnData);
  401. else
  402. m_viewInfo.GetColumnData(cColumns, pColumnData);
  403. // Save the column width information
  404. if ((m_dwOptions & STATSDLG_VERTICAL) == 0)
  405. {
  406. for (i=0; i<(int) cVisible; i++)
  407. {
  408. dwWidth = m_listCtrl.GetColumnWidth(i);
  409. if (m_pConfig)
  410. pColumnData[m_pConfig->MapColumnToSubitem(m_ulId, i)].m_dwWidth = dwWidth;
  411. else
  412. pColumnData[m_viewInfo.MapColumnToSubitem(i)].m_dwWidth = dwWidth;
  413. }
  414. }
  415. columnDlg.Init(m_pConfig ?
  416. m_pConfig->GetColumnInfo(m_ulId) :
  417. m_viewInfo.GetColumnInfo(),
  418. cColumns,
  419. pColumnData
  420. );
  421. if (columnDlg.DoModal() == IDOK)
  422. {
  423. if (m_dwOptions & STATSDLG_VERTICAL)
  424. {
  425. //$ HACK HACK
  426. // To save the column info for vertical columns we will save the
  427. // width data in the first two "columns"
  428. pColumnData[0].m_dwWidth = m_listCtrl.GetColumnWidth(0);
  429. pColumnData[1].m_dwWidth = m_listCtrl.GetColumnWidth(1);
  430. }
  431. // Set the information back in
  432. if (m_pConfig)
  433. m_pConfig->SetColumnData(m_ulId, cColumns, pColumnData);
  434. else
  435. m_viewInfo.SetColumnData(cColumns, pColumnData);
  436. // Clear out the data
  437. DeleteAllItems();
  438. // Remove all of the columns
  439. if (m_dwOptions & STATSDLG_VERTICAL)
  440. {
  441. m_listCtrl.DeleteColumn(1);
  442. m_listCtrl.DeleteColumn(0);
  443. }
  444. else
  445. {
  446. for (i=(int) cVisible; --i >= 0; )
  447. m_listCtrl.DeleteColumn(i);
  448. }
  449. // Readd all of the columns
  450. LoadHeaders();
  451. // Do a refresh
  452. RefreshData(FALSE);
  453. }
  454. }
  455. void StatsDialog::OnMove(int x, int y)
  456. {
  457. if (!m_bAfterInitDialog)
  458. return;
  459. GetWindowRect(&m_rcPosition);
  460. if (m_pConfig)
  461. m_pConfig->SetStatsWindowRect(m_ulId, m_rcPosition);
  462. }
  463. /*!--------------------------------------------------------------------------
  464. StatsDialog::OnSize
  465. -
  466. Author: KennT
  467. ---------------------------------------------------------------------------*/
  468. void StatsDialog::OnSize(UINT nType, int cx, int cy)
  469. {
  470. RECT rcWnd;
  471. RECT rcBtn;
  472. RECT rcDlg;
  473. if (nType == SIZE_MINIMIZED)
  474. return;
  475. if (m_dwOptions & STATSDLG_FULLWINDOW)
  476. {
  477. // If we're full window, resize the list control to fill
  478. // the entire client area
  479. ::SetWindowPos(::GetDlgItem(GetSafeHwnd(), IDC_STATSDLG_LIST), NULL,
  480. 0, 0, cx, cy, SWP_NOZORDER);
  481. }
  482. else if (m_sizeMinimum.cx)
  483. {
  484. ::GetClientRect(GetSafeHwnd(), &rcDlg);
  485. // reposition the buttons
  486. // The widths are caluclated opposite of the normal order
  487. // since the positions are relative to the right and bottom.
  488. for (int i=0; i<INDEX_COUNT; i++)
  489. {
  490. ::SetWindowPos(::GetDlgItem(GetSafeHwnd(), m_rgBtn[i].m_ulId),
  491. NULL,
  492. rcDlg.right - m_rgBtn[i].m_rc.left,
  493. rcDlg.bottom - m_rgBtn[i].m_rc.top,
  494. m_rgBtn[i].m_rc.left - m_rgBtn[i].m_rc.right,
  495. m_rgBtn[i].m_rc.top - m_rgBtn[i].m_rc.bottom,
  496. SWP_NOZORDER);
  497. }
  498. // resize the list control
  499. ::SetWindowPos(::GetDlgItem(GetSafeHwnd(), IDC_STATSDLG_LIST),
  500. NULL,
  501. m_rcList.left,
  502. m_rcList.top,
  503. rcDlg.right - m_rcList.right - m_rcList.left,
  504. rcDlg.bottom - m_rcList.bottom - m_rcList.top,
  505. SWP_NOZORDER);
  506. }
  507. if (m_bAfterInitDialog)
  508. {
  509. GetWindowRect(&m_rcPosition);
  510. if (m_pConfig)
  511. m_pConfig->SetStatsWindowRect(m_ulId, m_rcPosition);
  512. }
  513. }
  514. /*!--------------------------------------------------------------------------
  515. StatsDialog::OnGetMinMaxInfo
  516. -
  517. Author: KennT
  518. ---------------------------------------------------------------------------*/
  519. void StatsDialog::OnGetMinMaxInfo(MINMAXINFO *pMinMax)
  520. {
  521. pMinMax->ptMinTrackSize.x = m_sizeMinimum.cx;
  522. pMinMax->ptMinTrackSize.y = m_sizeMinimum.cy;
  523. }
  524. /*!--------------------------------------------------------------------------
  525. StatsDialog::LoadHeaders
  526. -
  527. Author: KennT
  528. ---------------------------------------------------------------------------*/
  529. void StatsDialog::LoadHeaders()
  530. {
  531. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  532. ULONG cVis;
  533. ULONG i, iPos;
  534. ULONG ulId;
  535. CString st;
  536. DWORD dwWidth;
  537. ColumnData rgColumnData[2]; // used for vertical format
  538. // Load those headers that we have data for
  539. // Go through the column data finding the headers that we have
  540. if (m_pConfig)
  541. cVis = m_pConfig->GetVisibleColumns(m_ulId);
  542. else
  543. cVis = m_viewInfo.GetVisibleColumns();
  544. if (m_dwOptions & STATSDLG_VERTICAL)
  545. {
  546. if (m_pConfig)
  547. m_pConfig->GetColumnData(m_ulId, 2, rgColumnData);
  548. else
  549. m_viewInfo.GetColumnData(2, rgColumnData);
  550. // For the vertical format, the data is on a column
  551. // Thus we add two columns and fill in the data for the
  552. // first column
  553. st.LoadString(IDS_STATSDLG_DESCRIPTION);
  554. dwWidth = rgColumnData[0].m_dwWidth;
  555. if (dwWidth == AUTO_WIDTH)
  556. {
  557. dwWidth = m_ColWidthAdder + static_cast<DWORD>(m_ColWidthMultiple*m_listCtrl.GetStringWidth((LPCTSTR) st));
  558. }
  559. m_listCtrl.InsertColumn(0, st, rgColumnData[0].fmt, dwWidth, 0);
  560. st.LoadString(IDS_STATSDLG_DETAILS);
  561. dwWidth = rgColumnData[1].m_dwWidth;
  562. if (dwWidth == AUTO_WIDTH)
  563. {
  564. dwWidth = m_ColWidthAdder + static_cast<DWORD>(m_ColWidthMultiple*m_listCtrl.GetStringWidth((LPCTSTR) st));
  565. }
  566. m_listCtrl.InsertColumn(1, st, rgColumnData[1].fmt, dwWidth, 1);
  567. // Now go through and add the rows for each of our "columns"
  568. for (i=0; i<cVis; i++)
  569. {
  570. // Now get the info for iPos
  571. if (m_pConfig)
  572. ulId = m_pConfig->GetStringId(m_ulId, i);
  573. else
  574. ulId = m_viewInfo.GetStringId(i);
  575. st.LoadString(ulId);
  576. Assert(st.GetLength());
  577. m_listCtrl.InsertItem(i, _T(""));
  578. m_listCtrl.SetItemText(i, 0, (LPCTSTR) st);
  579. }
  580. }
  581. else
  582. {
  583. // For the normal horizontal format, the data is on a row
  584. // so we need to add the various columnar data
  585. for (i=0; i<cVis; i++)
  586. {
  587. int fmt = LVCFMT_LEFT;
  588. iPos = MapColumnToSubitem(i);
  589. // Now get the info for iPos
  590. if (m_pConfig)
  591. ulId = m_pConfig->GetStringId(m_ulId, i);
  592. else
  593. ulId = m_viewInfo.GetStringId(i);
  594. st.LoadString(ulId);
  595. Assert(st.GetLength());
  596. if (m_pConfig)
  597. {
  598. dwWidth = m_pConfig->GetColumnWidth(m_ulId, i);
  599. m_pConfig->GetColumnData(m_ulId, i, 1, rgColumnData);
  600. fmt = rgColumnData[0].fmt;
  601. }
  602. else
  603. {
  604. dwWidth = m_viewInfo.GetColumnWidth(i);
  605. m_viewInfo.GetColumnData(i, 1, rgColumnData);
  606. fmt = rgColumnData[0].fmt;
  607. }
  608. if (dwWidth == AUTO_WIDTH)
  609. {
  610. dwWidth = m_ColWidthAdder + static_cast<DWORD>(m_ColWidthMultiple*m_listCtrl.GetStringWidth((LPCTSTR) st));
  611. }
  612. m_listCtrl.InsertColumn(i, st, fmt, dwWidth, iPos);
  613. }
  614. }
  615. }
  616. HRESULT StatsDialog::AddToContextMenu(CMenu* pMenu)
  617. {
  618. return S_OK;
  619. }
  620. /*!--------------------------------------------------------------------------
  621. StatsDialog::OnContextMenu
  622. -
  623. Author: KennT
  624. ---------------------------------------------------------------------------*/
  625. void StatsDialog::OnContextMenu(CWnd *pWnd, CPoint pos)
  626. {
  627. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  628. CMenu menu;
  629. CString st;
  630. if ((m_dwOptions & STATSDLG_CONTEXTMENU) == 0)
  631. return;
  632. if (pWnd->GetDlgCtrlID() != IDC_STATSDLG_LIST)
  633. return;
  634. // Bring up a context menu if we need to
  635. menu.CreatePopupMenu();
  636. st.LoadString(IDS_STATSDLG_MENU_REFRESH);
  637. menu.AppendMenu(MF_STRING, IDC_STATSDLG_BTN_REFRESH, st);
  638. if (m_dwOptions & STATSDLG_SELECT_COLUMNS)
  639. {
  640. st.LoadString(IDS_STATSDLG_MENU_SELECT);
  641. menu.AppendMenu(MF_STRING, IDC_STATSDLG_BTN_SELECT_COLUMNS, st);
  642. }
  643. //virtual override to add additional context menus
  644. AddToContextMenu(&menu);
  645. menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
  646. pos.x,
  647. pos.y,
  648. this,
  649. NULL);
  650. }
  651. void StatsDialog::OnNotifyListControlClick(NMHDR *pNmHdr, LRESULT *pResult)
  652. {
  653. NM_LISTVIEW * pnmlv = reinterpret_cast<NM_LISTVIEW *>(pNmHdr);
  654. if (m_pConfig)
  655. m_pConfig->SetSortColumn(m_ulId, pnmlv->iSubItem);
  656. // Call through to the user to sort
  657. Sort(pnmlv->iSubItem);
  658. if (m_pConfig)
  659. m_pConfig->SetSortDirection(m_ulId, m_fSortDirection);
  660. }
  661. void StatsDialog::Sort(UINT nColumn)
  662. {
  663. // Default is to do nothing
  664. }
  665. void StatsDialog::PreDeleteAllItems()
  666. {
  667. }
  668. void StatsDialog::DeleteAllItems()
  669. {
  670. PreDeleteAllItems();
  671. m_listCtrl.DeleteAllItems();
  672. }
  673. void StatsDialog::PostRefresh()
  674. {
  675. if (GetSafeHwnd())
  676. PostMessage(WM_COMMAND, IDC_STATSDLG_BTN_REFRESH);
  677. }
  678. /*!--------------------------------------------------------------------------
  679. StatsDialog::SetColumnWidths
  680. Loops through all items and calculates the max width for columns
  681. in a listbox.
  682. Author: EricDav
  683. ---------------------------------------------------------------------------*/
  684. void StatsDialog::SetColumnWidths(UINT uNumColumns)
  685. {
  686. // Set the default column widths to the width of the widest column
  687. int * aColWidth = (int *) alloca(uNumColumns * sizeof(int));
  688. int nRow, nCol;
  689. CString strTemp;
  690. ZeroMemory(aColWidth, uNumColumns * sizeof(int));
  691. // for each item, loop through each column and calculate the max width
  692. for (nRow = 0; nRow < m_listCtrl.GetItemCount(); nRow++)
  693. {
  694. for (nCol = 0; nCol < (int) uNumColumns; nCol++)
  695. {
  696. strTemp = m_listCtrl.GetItemText(nRow, nCol);
  697. if (aColWidth[nCol] < m_listCtrl.GetStringWidth(strTemp))
  698. aColWidth[nCol] = m_listCtrl.GetStringWidth(strTemp);
  699. }
  700. }
  701. // now update the column widths based on what we calculated
  702. for (nCol = 0; nCol < (int) uNumColumns; nCol++)
  703. {
  704. // GetStringWidth doesn't seem to report the right thing,
  705. // so we have to add a fudge factor of 15.... oh well.
  706. m_listCtrl.SetColumnWidth(nCol, aColWidth[nCol] + 15);
  707. }
  708. }
  709. void StatsDialog::SetConfigInfo(ConfigStream *pConfig, ULONG ulId)
  710. {
  711. m_pConfig = pConfig;
  712. m_ulId = ulId;
  713. }
  714. void StatsDialog::SetPosition(RECT rc)
  715. {
  716. m_rcPosition = rc;
  717. }
  718. void StatsDialog::GetPosition(RECT *prc)
  719. {
  720. *prc = m_rcPosition;
  721. }
  722. void CreateNewStatisticsWindow(StatsDialog *pWndStats,
  723. HWND hWndParent,
  724. UINT nIDD)
  725. {
  726. ModelessThread * pMT;
  727. // If the dialog is still up, don't create a new one
  728. if (pWndStats->GetSafeHwnd())
  729. {
  730. ::SetActiveWindow(pWndStats->GetSafeHwnd());
  731. return;
  732. }
  733. pMT = new ModelessThread(hWndParent,
  734. nIDD,
  735. pWndStats->GetSignalEvent(),
  736. pWndStats);
  737. pMT->CreateThread();
  738. }
  739. void WaitForStatisticsWindow(StatsDialog *pWndStats)
  740. {
  741. if (pWndStats->GetSafeHwnd())
  742. {
  743. // Post a cancel to that window
  744. // Do an explicit post so that it executes on the other thread
  745. pWndStats->PostMessage(WM_COMMAND, IDCANCEL, 0);
  746. // Now we need to wait for the event to be signalled so that
  747. // its memory can be cleaned up
  748. WaitForSingleObject(pWndStats->GetSignalEvent(), INFINITE);
  749. }
  750. }