Team Fortress 2 Source Code as on 22/4/2020
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.

648 lines
17 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // JobWatchDlg.cpp : implementation file
  9. //
  10. #include "stdafx.h"
  11. #include "JobWatchDlg.h"
  12. #include "tier1/strtools.h"
  13. #include "consolewnd.h"
  14. #include "vmpi_browser_helpers.h"
  15. #ifdef _DEBUG
  16. #define new DEBUG_NEW
  17. #undef THIS_FILE
  18. static char THIS_FILE[] = __FILE__;
  19. #endif
  20. #define IMPLEMENT_SORT_NUMBER_FN( FnName, VarName ) \
  21. static int CALLBACK FnName( LPARAM iItem1, LPARAM iItem2, LPARAM lpParam ) \
  22. { \
  23. CWorkerInfo *pInfo1 = (CWorkerInfo*)iItem1; \
  24. CWorkerInfo *pInfo2 = (CWorkerInfo*)iItem2; \
  25. return pInfo1->VarName > pInfo2->VarName; \
  26. }
  27. static int CALLBACK SortByName( LPARAM iItem1, LPARAM iItem2, LPARAM lpParam )
  28. {
  29. CWorkerInfo *pInfo1 = (CWorkerInfo*)iItem1;
  30. CWorkerInfo *pInfo2 = (CWorkerInfo*)iItem2;
  31. return strcmp( pInfo1->m_ComputerName, pInfo2->m_ComputerName );
  32. }
  33. static int CALLBACK SortByCurrentStage( LPARAM iItem1, LPARAM iItem2, LPARAM lpParam )
  34. {
  35. CWorkerInfo *pInfo1 = (CWorkerInfo*)iItem1;
  36. CWorkerInfo *pInfo2 = (CWorkerInfo*)iItem2;
  37. return strcmp( pInfo1->m_CurrentStage, pInfo2->m_CurrentStage );
  38. }
  39. IMPLEMENT_SORT_NUMBER_FN( SortByConnected, m_bConnected )
  40. IMPLEMENT_SORT_NUMBER_FN( SortByWorkUnitsDone, m_nWorkUnitsDone );
  41. IMPLEMENT_SORT_NUMBER_FN( SortByRunningTime, m_RunningTimeMS );
  42. IMPLEMENT_SORT_NUMBER_FN( SortByThread0WU, m_ThreadWUs[0] );
  43. IMPLEMENT_SORT_NUMBER_FN( SortByThread1WU, m_ThreadWUs[1] );
  44. IMPLEMENT_SORT_NUMBER_FN( SortByThread2WU, m_ThreadWUs[2] );
  45. IMPLEMENT_SORT_NUMBER_FN( SortByThread3WU, m_ThreadWUs[3] );
  46. typedef int (CALLBACK *ServicesSortFn)( LPARAM iItem1, LPARAM iItem2, LPARAM lpParam );
  47. struct
  48. {
  49. char *pText;
  50. int width;
  51. ServicesSortFn sortFn;
  52. } g_ColumnInfos[] =
  53. {
  54. {"Computer Name", 150, SortByName},
  55. {"Connected", 70, SortByConnected},
  56. {"Work Units Done", 100, SortByWorkUnitsDone},
  57. {"Running Time", 80, SortByRunningTime},
  58. {"Current Stage", 180, SortByCurrentStage},
  59. {"Thread 0", 70, SortByThread0WU},
  60. {"Thread 1", 70, SortByThread1WU},
  61. {"Thread 2", 70, SortByThread2WU},
  62. {"Thread 3", 70, SortByThread3WU}
  63. };
  64. #define COLUMN_COMPUTER_NAME 0
  65. #define COLUMN_CONNECTED 1
  66. #define COLUMN_WORK_UNITS_DONE 2
  67. #define COLUMN_RUNNING_TIME 3
  68. #define COLUMN_CURRENT_STAGE 4
  69. #define COLUMN_THREAD0_WU 5
  70. #define COLUMN_THREAD1_WU 6
  71. #define COLUMN_THREAD2_WU 7
  72. #define COLUMN_THREAD3_WU 8
  73. int g_iSortColumn = 0;
  74. /////////////////////////////////////////////////////////////////////////////
  75. // CJobWatchDlg dialog
  76. CJobWatchDlg::CJobWatchDlg(CWnd* pParent /*=NULL*/)
  77. : CIdleDialog(CJobWatchDlg::IDD, pParent)
  78. {
  79. m_CurMessageIndex = 0;
  80. m_CurGraphTime = 0;
  81. m_pSQL = NULL;
  82. m_hMySQLDLL = NULL;
  83. m_CurWorkerTextToken = 0;
  84. m_LastQueryTime = 0;
  85. //{{AFX_DATA_INIT(CJobWatchDlg)
  86. // NOTE: the ClassWizard will add member initialization here
  87. //}}AFX_DATA_INIT
  88. }
  89. CJobWatchDlg::~CJobWatchDlg()
  90. {
  91. if ( m_pSQL )
  92. {
  93. m_pSQL->Release();
  94. }
  95. if ( m_hMySQLDLL )
  96. {
  97. Sys_UnloadModule( m_hMySQLDLL );
  98. }
  99. }
  100. void CJobWatchDlg::DoDataExchange(CDataExchange* pDX)
  101. {
  102. CDialog::DoDataExchange(pDX);
  103. //{{AFX_DATA_MAP(CJobWatchDlg)
  104. DDX_Control(pDX, IDC_WORKERS, m_Workers);
  105. DDX_Control(pDX, IDC_TEXTOUTPUT, m_TextOutput);
  106. //}}AFX_DATA_MAP
  107. }
  108. BEGIN_MESSAGE_MAP(CJobWatchDlg, CIdleDialog)
  109. //{{AFX_MSG_MAP(CJobWatchDlg)
  110. ON_LBN_SELCHANGE(IDC_WORKERS, OnSelChangeWorkers)
  111. ON_WM_SIZE()
  112. ON_NOTIFY(LVN_ODSTATECHANGED, IDC_WORKERS, OnOdstatechangedWorkers)
  113. ON_NOTIFY(LVN_ITEMCHANGED, IDC_WORKERS, OnItemchangedWorkers)
  114. //}}AFX_MSG_MAP
  115. END_MESSAGE_MAP()
  116. /////////////////////////////////////////////////////////////////////////////
  117. // CJobWatchDlg message handlers
  118. const char* FindArg( const char *pArgName, const char *pDefault="" )
  119. {
  120. for ( int i=1; i < __argc; i++ )
  121. {
  122. if ( Q_stricmp( pArgName, __argv[i] ) == 0 )
  123. {
  124. if ( (i+1) < __argc )
  125. return __argv[i+1];
  126. else
  127. return pDefault;
  128. }
  129. }
  130. return NULL;
  131. }
  132. bool ReadStringFromFile( FILE *fp, char *pStr, int strSize )
  133. {
  134. int i=0;
  135. for ( i; i < strSize-2; i++ )
  136. {
  137. if ( fread( &pStr[i], 1, 1, fp ) != 1 ||
  138. pStr[i] == '\n' )
  139. {
  140. break;
  141. }
  142. }
  143. pStr[i] = 0;
  144. return i != 0;
  145. }
  146. BOOL CJobWatchDlg::OnInitDialog()
  147. {
  148. CDialog::OnInitDialog();
  149. m_Workers.SetExtendedStyle( LVS_EX_FULLROWSELECT );
  150. // Setup the headers.
  151. for ( int i=0; i < ARRAYSIZE( g_ColumnInfos ); i++ )
  152. {
  153. m_Workers.InsertColumn( i, g_ColumnInfos[i].pText, LVCFMT_LEFT, g_ColumnInfos[i].width, i );
  154. }
  155. m_GraphControl.SubclassDlgItem( IDC_GRAPH_AREA, this );
  156. CString str;
  157. // Get all our startup info from the command line.
  158. const char *pJobID = FindArg( "-JobID", NULL );
  159. const char *pDBName = FindArg( "-dbname", NULL );
  160. const char *pHostName = FindArg( "-hostname", NULL );
  161. const char *pUserName = FindArg( "-username", NULL );
  162. if ( !pJobID )
  163. {
  164. str.Format( "Missing a command line parameter (-JobID or -dbname or -hostname or -username)" );
  165. MessageBox( str, "Error", MB_OK );
  166. EndDialog( 1 );
  167. return FALSE;
  168. }
  169. char hostName[512], dbName[512], userName[512];
  170. if ( !pDBName || !pHostName || !pUserName )
  171. {
  172. char errString[512];
  173. // If they don't specify the DB info, get it from where
  174. const char *pFilename = "dbinfo_job_search.txt";
  175. FILE *fp = fopen( pFilename, "rt" );
  176. if ( !fp )
  177. {
  178. Q_snprintf( errString, sizeof( errString ), "Can't open '%s' for database info.", pFilename );
  179. MessageBox( errString, "Error", MB_OK );
  180. EndDialog( 0 );
  181. return FALSE;
  182. }
  183. if ( !ReadStringFromFile( fp, hostName, sizeof( hostName ) ) ||
  184. !ReadStringFromFile( fp, dbName, sizeof( dbName ) ) ||
  185. !ReadStringFromFile( fp, userName, sizeof( userName ) )
  186. )
  187. {
  188. fclose( fp );
  189. Q_snprintf( errString, sizeof( errString ), "'%s' has invalid format.", pFilename );
  190. MessageBox( errString, "Error", MB_OK );
  191. EndDialog( 0 );
  192. return FALSE;
  193. }
  194. pDBName = dbName;
  195. pHostName = hostName;
  196. pUserName = userName;
  197. fclose( fp );
  198. }
  199. m_JobID = atoi( pJobID );
  200. // Get the mysql interface.
  201. IMySQL *pSQL;
  202. if ( !Sys_LoadInterface( "mysql_wrapper", MYSQL_WRAPPER_VERSION_NAME, &m_hMySQLDLL, (void**)&pSQL ) )
  203. return false;
  204. if ( !pSQL->InitMySQL( pDBName, pHostName, pUserName ) )
  205. {
  206. pSQL->Release();
  207. str.Format( "Can't init MYSQL db (db = '%s', host = '%s', user = '%s')", pDBName, pHostName, pUserName );
  208. MessageBox( str, "Error", MB_OK );
  209. EndDialog( 0 );
  210. return FALSE;
  211. }
  212. m_pSQL = CreateMySQLAsync( pSQL );
  213. if ( !m_pSQL )
  214. {
  215. pSQL->Release();
  216. str.Format( "Can't create IMySQLAsync" );
  217. MessageBox( str, "Error", MB_OK );
  218. EndDialog( 0 );
  219. return FALSE;
  220. }
  221. memset( m_bQueriesInProgress, 0, sizeof( m_bQueriesInProgress ) );
  222. // (Init the idle processor so we can update text and graphs).
  223. StartIdleProcessing( 100 );
  224. // Fill in the command line control.
  225. char cmdLine[2048];
  226. Q_snprintf( cmdLine, sizeof( cmdLine ), "vmpi_job_watch -JobID %s -hostname %s -dbname %s -username %s",
  227. pJobID, pHostName, pDBName, pUserName );
  228. SetDlgItemText( IDC_COMMAND_LINE, cmdLine );
  229. // Setup anchors.
  230. m_AnchorMgr.AddAnchor( this, GetDlgItem( IDC_WORKERS_PANEL ), ANCHOR_LEFT, ANCHOR_TOP, ANCHOR_WIDTH_PERCENT, ANCHOR_HEIGHT_PERCENT );
  231. m_AnchorMgr.AddAnchor( this, GetDlgItem( IDC_WORKERS ), ANCHOR_LEFT, ANCHOR_TOP, ANCHOR_WIDTH_PERCENT, ANCHOR_HEIGHT_PERCENT );
  232. m_AnchorMgr.AddAnchor( this, GetDlgItem( IDC_TEXT_OUTPUT_PANEL ), ANCHOR_LEFT, ANCHOR_HEIGHT_PERCENT, ANCHOR_WIDTH_PERCENT, ANCHOR_BOTTOM );
  233. m_AnchorMgr.AddAnchor( this, GetDlgItem( IDC_TEXTOUTPUT ), ANCHOR_LEFT, ANCHOR_HEIGHT_PERCENT, ANCHOR_WIDTH_PERCENT, ANCHOR_BOTTOM );
  234. m_AnchorMgr.AddAnchor( this, GetDlgItem( IDC_GRAPHS_PANEL ), ANCHOR_WIDTH_PERCENT, ANCHOR_TOP, ANCHOR_RIGHT, ANCHOR_HEIGHT_PERCENT );
  235. m_AnchorMgr.AddAnchor( this, &m_GraphControl, ANCHOR_WIDTH_PERCENT, ANCHOR_TOP, ANCHOR_RIGHT, ANCHOR_HEIGHT_PERCENT );
  236. return TRUE; // return TRUE unless you set the focus to a control
  237. // EXCEPTION: OCX Property Pages should return FALSE
  238. }
  239. CWorkerInfo* CJobWatchDlg::FindWorkerByID( unsigned long jobWorkerID )
  240. {
  241. int nIndex = -1;
  242. while ( ( nIndex = m_Workers.GetNextItem( nIndex, LVNI_ALL ) ) != -1 )
  243. {
  244. CWorkerInfo *pInfo = (CWorkerInfo*)m_Workers.GetItemData( nIndex );
  245. if ( pInfo->m_JobWorkerID == jobWorkerID )
  246. return pInfo;
  247. }
  248. return NULL;
  249. }
  250. CWorkerInfo* CJobWatchDlg::FindWorkerByMachineName( const char *pMachineName )
  251. {
  252. int nIndex = -1;
  253. while ( ( nIndex = m_Workers.GetNextItem( nIndex, LVNI_ALL ) ) != -1 )
  254. {
  255. CWorkerInfo *pInfo = (CWorkerInfo*)m_Workers.GetItemData( nIndex );
  256. if ( Q_stricmp( pInfo->m_ComputerName, pMachineName ) == 0 )
  257. return pInfo;
  258. }
  259. return NULL;
  260. }
  261. void CJobWatchDlg::SetWorkerListItemInt( int nIndex, int iColumn, int value )
  262. {
  263. char str[512];
  264. Q_snprintf( str, sizeof( str ), "%d", value );
  265. m_Workers.SetItemText( nIndex, iColumn, str );
  266. }
  267. void CJobWatchDlg::UpdateWorkersList()
  268. {
  269. int nIndex = -1;
  270. while ( ( nIndex = m_Workers.GetNextItem( nIndex, LVNI_ALL ) ) != -1 )
  271. {
  272. CWorkerInfo *pInfo = (CWorkerInfo*)m_Workers.GetItemData( nIndex );
  273. char *pConnectedStr = pInfo->m_bConnected ? "yes" : "no";
  274. m_Workers.SetItemText( nIndex, COLUMN_CONNECTED, pConnectedStr );
  275. SetWorkerListItemInt( nIndex, COLUMN_WORK_UNITS_DONE, pInfo->m_nWorkUnitsDone );
  276. char timeStr[1024];
  277. FormatTimeString( pInfo->m_RunningTimeMS / 1000, timeStr, sizeof( timeStr ) );
  278. m_Workers.SetItemText( nIndex, COLUMN_RUNNING_TIME, timeStr );
  279. // Current stage.
  280. SetWorkerListItemInt( nIndex, COLUMN_WORK_UNITS_DONE, pInfo->m_nWorkUnitsDone );
  281. m_Workers.SetItemText( nIndex, COLUMN_CURRENT_STAGE, pInfo->m_CurrentStage );
  282. SetWorkerListItemInt( nIndex, COLUMN_THREAD0_WU, pInfo->m_ThreadWUs[0] );
  283. SetWorkerListItemInt( nIndex, COLUMN_THREAD1_WU, pInfo->m_ThreadWUs[1] );
  284. SetWorkerListItemInt( nIndex, COLUMN_THREAD2_WU, pInfo->m_ThreadWUs[2] );
  285. SetWorkerListItemInt( nIndex, COLUMN_THREAD3_WU, pInfo->m_ThreadWUs[3] );
  286. }
  287. ResortItems();
  288. }
  289. bool CJobWatchDlg::GetCurJobWorkerID( unsigned long &id )
  290. {
  291. POSITION pos = m_Workers.GetFirstSelectedItemPosition();
  292. if ( !pos )
  293. return false;
  294. int index = m_Workers.GetNextSelectedItem( pos );
  295. CWorkerInfo *pInfo = (CWorkerInfo*)m_Workers.GetItemData( index );
  296. id = pInfo->m_JobWorkerID;
  297. return true;
  298. }
  299. void CJobWatchDlg::OnSelChangeWorkers()
  300. {
  301. // Clear the text output and invalidate any old queries for text.
  302. int nLen = m_TextOutput.SendMessage( EM_GETLIMITTEXT, 0, 0 );
  303. m_TextOutput.SendMessage( EM_SETSEL, 0, nLen );
  304. m_TextOutput.SendMessage( EM_REPLACESEL, FALSE, (LPARAM)"" );
  305. m_CurMessageIndex = 0;
  306. m_CurWorkerTextToken++;
  307. m_LastQueryTime = 0; // force a query.
  308. m_GraphControl.Clear();
  309. m_CurGraphTime = -1;
  310. }
  311. void CJobWatchDlg::ResortItems()
  312. {
  313. m_Workers.SortItems( g_ColumnInfos[g_iSortColumn].sortFn, (LPARAM)this );
  314. }
  315. void CJobWatchDlg::OnIdle()
  316. {
  317. // Issue any queries that we need to.
  318. DWORD curTime = GetTickCount();
  319. if ( curTime - m_LastQueryTime >= 1000 )
  320. {
  321. m_LastQueryTime = curTime;
  322. char query[2048];
  323. unsigned long jobWorkerID;
  324. bool bJobWorkerIDValid = GetCurJobWorkerID( jobWorkerID );
  325. if ( !m_bQueriesInProgress[QUERY_TEXT] && bJobWorkerIDValid )
  326. {
  327. Q_snprintf( query, sizeof( query ), "select * from text_messages where JobWorkerID=%lu and MessageIndex >= %lu", jobWorkerID, m_CurMessageIndex );
  328. m_pSQL->Execute( query, (void*)(QUERY_TEXT | (m_CurWorkerTextToken << 16)) );
  329. m_bQueriesInProgress[QUERY_TEXT] = true;
  330. }
  331. if ( !m_bQueriesInProgress[QUERY_GRAPH] && bJobWorkerIDValid )
  332. {
  333. Q_snprintf( query, sizeof( query ), "select * from graph_entry where JobWorkerID=%lu", jobWorkerID );
  334. m_pSQL->Execute( query, (void*)QUERY_GRAPH );
  335. m_bQueriesInProgress[QUERY_GRAPH] = true;
  336. }
  337. if ( !m_bQueriesInProgress[QUERY_WORKER_STATS] )
  338. {
  339. Q_snprintf( query, sizeof( query ), "select JobWorkerID, WorkerState, NumWorkUnits, "
  340. "RunningTimeMS, CurrentStage, Thread0WU, Thread1WU, Thread2WU, Thread3WU, IsMaster, MachineName "
  341. " from job_worker_start where JobID=%lu", m_JobID );
  342. m_pSQL->Execute( query, (void*)QUERY_WORKER_STATS );
  343. m_bQueriesInProgress[QUERY_WORKER_STATS] = true;
  344. }
  345. }
  346. // Pickup query results.
  347. CQueryResults results;
  348. while ( m_pSQL->GetNextResults( results ) && results.m_pResults )
  349. {
  350. int iQueryID = ((int)results.m_pUserData) & 0xFFFF;
  351. int iExtraData = ((int)results.m_pUserData) >> 16;
  352. if ( results.m_pResults )
  353. {
  354. if ( iQueryID == QUERY_TEXT )
  355. {
  356. if ( iExtraData == m_CurWorkerTextToken )
  357. {
  358. ProcessQueryResults_Text( results.m_pResults );
  359. }
  360. }
  361. else if ( iQueryID == QUERY_GRAPH )
  362. {
  363. ProcessQueryResults_Graph( results.m_pResults );
  364. }
  365. else if ( iQueryID == QUERY_WORKER_STATS )
  366. {
  367. ProcessQueryResults_WorkerStats( results.m_pResults );
  368. }
  369. results.m_pResults->Release();
  370. }
  371. m_bQueriesInProgress[iQueryID] = false;
  372. }
  373. }
  374. void CJobWatchDlg::ProcessQueryResults_WorkerStats( IMySQLRowSet *pSet )
  375. {
  376. bool bChange = false;
  377. while ( pSet->NextRow() )
  378. {
  379. int iColumn = 0;
  380. int workerID = pSet->GetColumnValue_Int( iColumn++ );
  381. int workerState = pSet->GetColumnValue_Int( iColumn++ );
  382. int nWorkUnits = pSet->GetColumnValue_Int( iColumn++ );
  383. unsigned long runningTimeMS = pSet->GetColumnValue_Int( iColumn++ );
  384. const char *pCurrentStage = pSet->GetColumnValue_String( iColumn++ );
  385. int iThread0WU = pSet->GetColumnValue_Int( iColumn++ );
  386. int iThread1WU = pSet->GetColumnValue_Int( iColumn++ );
  387. int iThread2WU = pSet->GetColumnValue_Int( iColumn++ );
  388. int iThread3WU = pSet->GetColumnValue_Int( iColumn++ );
  389. int bIsMaster = pSet->GetColumnValue_Int( iColumn++ );
  390. const char *pMachineName = pSet->GetColumnValue_String( iColumn );
  391. CWorkerInfo *pInfo = FindWorkerByID( workerID );
  392. if ( pInfo )
  393. {
  394. if ( workerState != pInfo->m_bConnected ||
  395. nWorkUnits != pInfo->m_nWorkUnitsDone ||
  396. runningTimeMS != pInfo->m_RunningTimeMS ||
  397. stricmp( pCurrentStage, pInfo->m_CurrentStage ) != 0 ||
  398. iThread0WU != pInfo->m_ThreadWUs[0] ||
  399. iThread1WU != pInfo->m_ThreadWUs[1] ||
  400. iThread2WU != pInfo->m_ThreadWUs[2] ||
  401. iThread3WU != pInfo->m_ThreadWUs[3]
  402. )
  403. {
  404. bChange = true;
  405. pInfo->m_bConnected = workerState;
  406. pInfo->m_nWorkUnitsDone = nWorkUnits;
  407. pInfo->m_RunningTimeMS = runningTimeMS;
  408. pInfo->m_CurrentStage = pCurrentStage;
  409. pInfo->m_ThreadWUs[0] = iThread0WU;
  410. pInfo->m_ThreadWUs[1] = iThread1WU;
  411. pInfo->m_ThreadWUs[2] = iThread2WU;
  412. pInfo->m_ThreadWUs[3] = iThread3WU;
  413. }
  414. }
  415. else
  416. {
  417. // Add a new entry.
  418. CWorkerInfo *pInfo = new CWorkerInfo;
  419. pInfo->m_ComputerName = pMachineName;
  420. pInfo->m_bConnected = false;
  421. pInfo->m_nWorkUnitsDone = 0;
  422. pInfo->m_RunningTimeMS = 0;
  423. pInfo->m_JobWorkerID = workerID;
  424. int index;
  425. if ( bIsMaster )
  426. {
  427. char tempStr[512];
  428. Q_snprintf( tempStr, sizeof( tempStr ), "%s [master]", (const char*)pInfo->m_ComputerName );
  429. index = m_Workers.InsertItem( COLUMN_COMPUTER_NAME, tempStr, NULL );
  430. }
  431. else
  432. {
  433. index = m_Workers.InsertItem( COLUMN_COMPUTER_NAME, pInfo->m_ComputerName, NULL );
  434. }
  435. m_Workers.SetItemData( index, (DWORD)pInfo );
  436. bChange = true;
  437. }
  438. }
  439. if ( bChange )
  440. {
  441. UpdateWorkersList();
  442. }
  443. }
  444. void CJobWatchDlg::ProcessQueryResults_Text( IMySQLRowSet *pSet )
  445. {
  446. CUtlVector<char> text;
  447. while ( pSet->NextRow() )
  448. {
  449. const char *pTextStr = pSet->GetColumnValue( "text" ).String();
  450. int len = strlen( pTextStr );
  451. text.AddMultipleToTail( len, pTextStr );
  452. m_CurMessageIndex = pSet->GetColumnValue( "MessageIndex" ).Int32() + 1;
  453. }
  454. text.AddToTail( 0 );
  455. FormatAndSendToEditControl( m_TextOutput.GetSafeHwnd(), text.Base() );
  456. }
  457. void CJobWatchDlg::ProcessQueryResults_Graph( IMySQLRowSet *pSet )
  458. {
  459. int iMSTime = pSet->GetColumnIndex( "MSSinceJobStart" );
  460. int iBytesSent = pSet->GetColumnIndex( "BytesSent" );
  461. int iBytesReceived = pSet->GetColumnIndex( "BytesReceived" );
  462. // See if there's anything new.
  463. CUtlVector<CGraphEntry> entries;
  464. int highest = m_CurGraphTime;
  465. while ( pSet->NextRow() )
  466. {
  467. CGraphEntry entry;
  468. entry.m_msTime = pSet->GetColumnValue( iMSTime ).Int32();
  469. entry.m_nBytesSent = pSet->GetColumnValue( iBytesSent ).Int32();
  470. entry.m_nBytesReceived = pSet->GetColumnValue( iBytesReceived ).Int32();
  471. entries.AddToTail( entry );
  472. highest = max( highest, entry.m_msTime );
  473. }
  474. if ( highest > m_CurGraphTime )
  475. {
  476. m_CurGraphTime = highest;
  477. m_GraphControl.Clear();
  478. m_GraphControl.Fill( entries );
  479. }
  480. }
  481. void CJobWatchDlg::OnSize(UINT nType, int cx, int cy)
  482. {
  483. CIdleDialog::OnSize(nType, cx, cy);
  484. m_AnchorMgr.UpdateAnchors( this );
  485. }
  486. BOOL CJobWatchDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
  487. {
  488. NMHDR *pHdr = (NMHDR*)lParam;
  489. if ( pHdr->idFrom == IDC_WORKERS )
  490. {
  491. if ( pHdr->code == LVN_COLUMNCLICK )
  492. {
  493. LPNMLISTVIEW pListView = (LPNMLISTVIEW)lParam;
  494. // Now sort by this column.
  495. g_iSortColumn = max( 0, min( pListView->iSubItem, (int)ARRAYSIZE( g_ColumnInfos ) - 1 ) );
  496. ResortItems();
  497. }
  498. }
  499. return CIdleDialog::OnNotify(wParam, lParam, pResult);
  500. }
  501. void CJobWatchDlg::OnOdstatechangedWorkers(NMHDR* pNMHDR, LRESULT* pResult)
  502. {
  503. NMLVODSTATECHANGE* pStateChanged = (NMLVODSTATECHANGE*)pNMHDR;
  504. if ( !( pStateChanged->uOldState & LVIS_SELECTED ) && ( pStateChanged->uNewState & LVIS_SELECTED ) )
  505. {
  506. OnSelChangeWorkers();
  507. }
  508. *pResult = 0;
  509. }
  510. void CJobWatchDlg::OnItemchangedWorkers(NMHDR* pNMHDR, LRESULT* pResult)
  511. {
  512. NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
  513. if ( !( pNMListView->uOldState & LVIS_SELECTED ) && ( pNMListView->uNewState & LVIS_SELECTED ) )
  514. {
  515. OnSelChangeWorkers();
  516. }
  517. *pResult = 0;
  518. }