1
1
// This file is part of BOINC.
2
2
// http://boinc.berkeley.edu
3
- // Copyright (C) 2020 University of California
3
+ // Copyright (C) 2022 University of California
4
4
//
5
5
// BOINC is free software; you can redistribute it and/or modify it
6
6
// under the terms of the GNU Lesser General Public License
52
52
#define COLUMN_REPORTDEADLINE 5
53
53
#define COLUMN_APPLICATION 6
54
54
#define COLUMN_NAME 7
55
+ #define COLUMN_ESTIMATEDCOMPLETION 8
56
+ #define COLUMN_DEADLINEDIFF 9
57
+
55
58
56
59
// DefaultShownColumns is an array containing the
57
60
// columnIDs of the columns to be shown by default,
58
61
// in ascending order. It may or may not include
59
62
// all columns.
63
+ // Columns ESTIMATEDCOMPLETION and DEADLINEDIFF are hidden by default.
64
+ // Not all users may want to see those columns.
60
65
//
61
- // For now, show all columns by default
62
66
static int DefaultShownColumns[] = { COLUMN_PROJECT, COLUMN_PROGRESS, COLUMN_STATUS,
63
67
COLUMN_CPUTIME, COLUMN_TOCOMPLETION,
64
68
COLUMN_REPORTDEADLINE, COLUMN_APPLICATION,
65
- COLUMN_NAME};
69
+ COLUMN_NAME };
66
70
67
71
// groups that contain buttons
68
72
#define GRP_TASKS 0
@@ -81,7 +85,9 @@ CWork::CWork() {
81
85
m_fCPUTime = -1.0 ;
82
86
m_fProgress = -1.0 ;
83
87
m_fTimeToCompletion = -1.0 ;
84
- m_tReportDeadline = (time_t )0 ;
88
+ m_fDeadlineDiff = -1.0 ;
89
+ m_tReportDeadline = (time_t )-1 ;
90
+ m_tEstimatedCompletion = (time_t )-1 ;
85
91
}
86
92
87
93
@@ -95,6 +101,8 @@ CWork::~CWork() {
95
101
m_strProgress.Clear ();
96
102
m_strTimeToCompletion.Clear ();
97
103
m_strReportDeadline.Clear ();
104
+ m_strEstimatedCompletion.Clear ();
105
+ m_strDeadlineDiff.Clear ();
98
106
}
99
107
100
108
@@ -181,6 +189,20 @@ static bool CompareViewWorkItems(int iRowIndex1, int iRowIndex2) {
181
189
case COLUMN_STATUS:
182
190
result = work1->m_strStatus .CmpNoCase (work2->m_strStatus );
183
191
break ;
192
+ case COLUMN_ESTIMATEDCOMPLETION:
193
+ if (work1->m_tEstimatedCompletion < work2->m_tEstimatedCompletion ) {
194
+ result = -1 ;
195
+ } else if (work1->m_tEstimatedCompletion > work2->m_tEstimatedCompletion ) {
196
+ result = 1 ;
197
+ }
198
+ break ;
199
+ case COLUMN_DEADLINEDIFF:
200
+ if (work1->m_fDeadlineDiff < work2->m_fDeadlineDiff ) {
201
+ result = -1 ;
202
+ } else if (work1->m_fDeadlineDiff > work2->m_fDeadlineDiff ) {
203
+ result = 1 ;
204
+ }
205
+ break ;
184
206
}
185
207
186
208
// Always return FALSE for equality (result == 0)
@@ -265,6 +287,8 @@ CViewWork::CViewWork(wxNotebook* pNotebook) :
265
287
m_aStdColNameOrder->Insert (_ (" Deadline" ), COLUMN_REPORTDEADLINE);
266
288
m_aStdColNameOrder->Insert (_ (" Application" ), COLUMN_APPLICATION);
267
289
m_aStdColNameOrder->Insert (_ (" Name" ), COLUMN_NAME);
290
+ m_aStdColNameOrder->Insert (_ (" Estimated Completion" ), COLUMN_ESTIMATEDCOMPLETION);
291
+ m_aStdColNameOrder->Insert (_ (" Completion Before Deadline" ), COLUMN_DEADLINEDIFF);
268
292
269
293
// m_iStdColWidthOrder is an array of the width for each column.
270
294
// Entries must be in order of ascending Column ID. We initialize
@@ -281,6 +305,8 @@ CViewWork::CViewWork(wxNotebook* pNotebook) :
281
305
m_iStdColWidthOrder.Insert (150 , COLUMN_REPORTDEADLINE);
282
306
m_iStdColWidthOrder.Insert (95 , COLUMN_APPLICATION);
283
307
m_iStdColWidthOrder.Insert (285 , COLUMN_NAME);
308
+ m_iStdColWidthOrder.Insert (150 , COLUMN_ESTIMATEDCOMPLETION);
309
+ m_iStdColWidthOrder.Insert (150 , COLUMN_DEADLINEDIFF);
284
310
285
311
wxASSERT (m_iStdColWidthOrder.size () == m_aStdColNameOrder->size ());
286
312
@@ -331,6 +357,14 @@ void CViewWork::AppendColumn(int columnID){
331
357
m_pListPane->AppendColumn ((*m_aStdColNameOrder)[COLUMN_NAME],
332
358
wxLIST_FORMAT_LEFT, m_iStdColWidthOrder[COLUMN_NAME]);
333
359
break ;
360
+ case COLUMN_ESTIMATEDCOMPLETION:
361
+ m_pListPane->AppendColumn ((*m_aStdColNameOrder)[COLUMN_ESTIMATEDCOMPLETION],
362
+ wxLIST_FORMAT_LEFT, m_iStdColWidthOrder[COLUMN_ESTIMATEDCOMPLETION]);
363
+ break ;
364
+ case COLUMN_DEADLINEDIFF:
365
+ m_pListPane->AppendColumn ((*m_aStdColNameOrder)[COLUMN_DEADLINEDIFF],
366
+ wxLIST_FORMAT_LEFT, m_iStdColWidthOrder[COLUMN_DEADLINEDIFF]);
367
+ break ;
334
368
}
335
369
}
336
370
@@ -752,9 +786,15 @@ wxString CViewWork::OnListGetItemText(long item, long column) const {
752
786
case COLUMN_STATUS:
753
787
strBuffer = work->m_strStatus ;
754
788
break ;
789
+ case COLUMN_ESTIMATEDCOMPLETION:
790
+ strBuffer = work->m_strEstimatedCompletion ;
791
+ break ;
792
+ case COLUMN_DEADLINEDIFF:
793
+ strBuffer = work->m_strDeadlineDiff ;
794
+ break ;
755
795
}
756
796
}
757
-
797
+
758
798
return strBuffer;
759
799
}
760
800
@@ -870,7 +910,7 @@ void CViewWork::UpdateSelection() {
870
910
// Step through all selected items
871
911
row = m_pListPane->GetNextItem (row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
872
912
if (row < 0 ) break ; // Should never happen
873
-
913
+
874
914
result = pDoc->result (m_iSortedIndexes[row]);
875
915
if (!result) continue ;
876
916
if (i == 0 ) {
@@ -919,7 +959,7 @@ void CViewWork::UpdateSelection() {
919
959
enableShowGraphics = false ;
920
960
}
921
961
}
922
-
962
+
923
963
// Disable Show VM console if the selected task hasn't registered a remote
924
964
// desktop connection
925
965
//
@@ -941,7 +981,7 @@ void CViewWork::UpdateSelection() {
941
981
enableShowGraphics = false ;
942
982
}
943
983
}
944
-
984
+
945
985
// Disable Abort button if any selected task already aborted
946
986
if (
947
987
result->active_task_state == PROCESS_ABORT_PENDING ||
@@ -959,7 +999,7 @@ void CViewWork::UpdateSelection() {
959
999
all_same_project = false ;
960
1000
}
961
1001
}
962
-
1002
+
963
1003
if (n == 1 ) {
964
1004
enableProperties = true ;
965
1005
}
@@ -1002,7 +1042,7 @@ void CViewWork::UpdateSelection() {
1002
1042
bool CViewWork::SynchronizeCacheItem (wxInt32 iRowIndex, wxInt32 iColumnIndex) {
1003
1043
wxString strDocumentText = wxEmptyString;
1004
1044
wxString strDocumentText2 = wxEmptyString;
1005
- double x = 0.0 ;
1045
+ double x = 0.0 ;
1006
1046
time_t tDocumentTime = (time_t )0 ;
1007
1047
CWork* work;
1008
1048
@@ -1011,9 +1051,9 @@ bool CViewWork::SynchronizeCacheItem(wxInt32 iRowIndex, wxInt32 iColumnIndex) {
1011
1051
if (GetWorkCacheAtIndex (work, m_iSortedIndexes[iRowIndex])) {
1012
1052
return false ;
1013
1053
}
1014
-
1054
+
1015
1055
if (iColumnIndex < 0 ) return false ;
1016
-
1056
+
1017
1057
switch (m_iColumnIndexToColumnID[iColumnIndex]) {
1018
1058
case COLUMN_PROJECT:
1019
1059
GetDocProjectName (m_iSortedIndexes[iRowIndex], strDocumentText);
@@ -1066,7 +1106,39 @@ bool CViewWork::SynchronizeCacheItem(wxInt32 iRowIndex, wxInt32 iColumnIndex) {
1066
1106
GetDocReportDeadline (m_iSortedIndexes[iRowIndex], tDocumentTime);
1067
1107
if (tDocumentTime != work->m_tReportDeadline ) {
1068
1108
work->m_tReportDeadline = tDocumentTime;
1069
- FormatReportDeadline (tDocumentTime, work->m_strReportDeadline );
1109
+ FormatDateTime (tDocumentTime, work->m_strReportDeadline );
1110
+ return true ;
1111
+ }
1112
+ break ;
1113
+ case COLUMN_ESTIMATEDCOMPLETION:
1114
+ GetDocEstCompletionDate (m_iSortedIndexes[iRowIndex], tDocumentTime);
1115
+ if (tDocumentTime != work->m_tEstimatedCompletion ) {
1116
+ work->m_tEstimatedCompletion = tDocumentTime;
1117
+ if (work->m_tEstimatedCompletion == 0 ) {
1118
+ work->m_strEstimatedCompletion = _ (" ---" );
1119
+ }
1120
+ else {
1121
+ FormatDateTime (tDocumentTime, work->m_strEstimatedCompletion );
1122
+ }
1123
+ return true ;
1124
+ }
1125
+ break ;
1126
+ case COLUMN_DEADLINEDIFF:
1127
+ GetDocEstDeadlineDiff (m_iSortedIndexes[iRowIndex], x);
1128
+ if (x != work->m_fDeadlineDiff ) {
1129
+ work->m_fDeadlineDiff = x;
1130
+ if (x < 0 ) {
1131
+ // A negative difference means the task will not meet the
1132
+ // deadline. Because FormatTime does not recognize negative
1133
+ // numbers, the adjustment will be made here.
1134
+ //
1135
+ x *= -1 ;
1136
+ work->m_strDeadlineDiff = _ (" -" );
1137
+ work->m_strDeadlineDiff += FormatTime (x);
1138
+ }
1139
+ else {
1140
+ work->m_strDeadlineDiff = FormatTime (x);
1141
+ }
1070
1142
return true ;
1071
1143
}
1072
1144
break ;
@@ -1185,6 +1257,7 @@ void CViewWork::GetDocCPUTime(wxInt32 item, double& fBuffer) const {
1185
1257
}
1186
1258
}
1187
1259
1260
+
1188
1261
void CViewWork::GetDocProgress (wxInt32 item, double & fBuffer ) const {
1189
1262
RESULT* result = wxGetApp ().GetDocument ()->result (item);
1190
1263
@@ -1219,37 +1292,65 @@ void CViewWork::GetDocTimeToCompletion(wxInt32 item, double& fBuffer) const {
1219
1292
}
1220
1293
}
1221
1294
1222
- void CViewWork::GetDocReportDeadline (wxInt32 item, time_t & time) const {
1295
+
1296
+ void CViewWork::GetDocReportDeadline (wxInt32 item, time_t & tBuffer) const {
1223
1297
RESULT* result = wxGetApp ().GetDocument ()->result (item);
1224
1298
1225
1299
if (result) {
1226
- time = (time_t )result->report_deadline ;
1300
+ tBuffer = (time_t )result->report_deadline ;
1227
1301
} else {
1228
- time = (time_t )0 ;
1302
+ tBuffer = (time_t )0 ;
1229
1303
}
1230
1304
}
1231
1305
1232
1306
1233
- wxInt32 CViewWork::FormatReportDeadline (time_t deadline, wxString& strBuffer) const {
1307
+ // Calculates the estimated date and time a task will be completed.
1308
+ // This is only calculated for active tasks. If a task is not active,
1309
+ // time pt will remain at zero. The intent is for the command calling this
1310
+ // function to use that value to display '---', not the epoch time.
1311
+ //
1312
+ void CViewWork::GetDocEstCompletionDate (wxInt32 item, time_t & tBuffer) const {
1313
+ RESULT* result = wxGetApp ().GetDocument ()->result (item);
1314
+ tBuffer = 0 ;
1315
+ if (result->active_task_state == 1 ) {
1316
+ time_t ttime = time (0 );
1317
+ tBuffer = ttime;
1318
+ tBuffer += (time_t )result->estimated_cpu_time_remaining ;
1319
+ }
1320
+ }
1321
+
1322
+
1323
+ void CViewWork::GetDocEstDeadlineDiff (wxInt32 item, double & fBuffer ) const {
1324
+ RESULT* result = wxGetApp ().GetDocument ()->result (item);
1325
+ fBuffer = 0 ;
1326
+ if (result->active_task_state == 1 ) {
1327
+ time_t tdeadline, testcompletion;
1328
+ GetDocEstCompletionDate (item, testcompletion);
1329
+ GetDocReportDeadline (item, tdeadline);
1330
+ fBuffer = (double )(tdeadline - testcompletion);
1331
+ }
1332
+
1333
+ }
1334
+
1335
+
1336
+ wxInt32 CViewWork::FormatDateTime (time_t datetime, wxString& strBuffer) const {
1234
1337
#ifdef __WXMAC__
1235
1338
// Work around a wxCocoa bug(?) in wxDateTime::Format()
1236
1339
char buf[80 ];
1237
- struct tm * timeinfo = localtime (&deadline );
1340
+ struct tm * timeinfo = localtime (&datetime );
1238
1341
strftime (buf, sizeof (buf), " %c" , timeinfo);
1239
1342
strBuffer = buf;
1240
1343
#else
1241
1344
wxDateTime dtTemp;
1242
1345
1243
- dtTemp.Set (deadline );
1346
+ dtTemp.Set (datetime );
1244
1347
strBuffer = dtTemp.Format ();
1245
1348
#endif
1246
1349
1247
1350
return 0 ;
1248
1351
}
1249
1352
1250
1353
1251
-
1252
-
1253
1354
wxInt32 CViewWork::FormatStatus (wxInt32 item, wxString& strBuffer) const {
1254
1355
CWork* work;
1255
1356
@@ -1319,7 +1420,7 @@ int CViewWork::GetWorkCacheAtIndex(CWork*& workPtr, int index) {
1319
1420
workPtr = NULL ;
1320
1421
return -1 ;
1321
1422
}
1322
-
1423
+
1323
1424
return 0 ;
1324
1425
}
1325
1426
0 commit comments