11// This file is part of BOINC.
22// http://boinc.berkeley.edu
3- // Copyright (C) 2020 University of California
3+ // Copyright (C) 2022 University of California
44//
55// BOINC is free software; you can redistribute it and/or modify it
66// under the terms of the GNU Lesser General Public License
5252#define COLUMN_REPORTDEADLINE 5
5353#define COLUMN_APPLICATION 6
5454#define COLUMN_NAME 7
55+ #define COLUMN_ESTIMATEDCOMPLETION 8
56+ #define COLUMN_DEADLINEDIFF 9
57+
5558
5659// DefaultShownColumns is an array containing the
5760// columnIDs of the columns to be shown by default,
5861// in ascending order. It may or may not include
5962// all columns.
63+ // Columns ESTIMATEDCOMPLETION and DEADLINEDIFF are hidden by default.
64+ // Not all users may want to see those columns.
6065//
61- // For now, show all columns by default
6266static int DefaultShownColumns[] = { COLUMN_PROJECT, COLUMN_PROGRESS, COLUMN_STATUS,
6367 COLUMN_CPUTIME, COLUMN_TOCOMPLETION,
6468 COLUMN_REPORTDEADLINE, COLUMN_APPLICATION,
65- COLUMN_NAME};
69+ COLUMN_NAME };
6670
6771// groups that contain buttons
6872#define GRP_TASKS 0
@@ -81,7 +85,9 @@ CWork::CWork() {
8185 m_fCPUTime = -1.0 ;
8286 m_fProgress = -1.0 ;
8387 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 ;
8591}
8692
8793
@@ -95,6 +101,8 @@ CWork::~CWork() {
95101 m_strProgress.Clear ();
96102 m_strTimeToCompletion.Clear ();
97103 m_strReportDeadline.Clear ();
104+ m_strEstimatedCompletion.Clear ();
105+ m_strDeadlineDiff.Clear ();
98106}
99107
100108
@@ -181,6 +189,20 @@ static bool CompareViewWorkItems(int iRowIndex1, int iRowIndex2) {
181189 case COLUMN_STATUS:
182190 result = work1->m_strStatus .CmpNoCase (work2->m_strStatus );
183191 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 ;
184206 }
185207
186208 // Always return FALSE for equality (result == 0)
@@ -265,6 +287,8 @@ CViewWork::CViewWork(wxNotebook* pNotebook) :
265287 m_aStdColNameOrder->Insert (_ (" Deadline" ), COLUMN_REPORTDEADLINE);
266288 m_aStdColNameOrder->Insert (_ (" Application" ), COLUMN_APPLICATION);
267289 m_aStdColNameOrder->Insert (_ (" Name" ), COLUMN_NAME);
290+ m_aStdColNameOrder->Insert (_ (" Estimated Completion" ), COLUMN_ESTIMATEDCOMPLETION);
291+ m_aStdColNameOrder->Insert (_ (" Completion Before Deadline" ), COLUMN_DEADLINEDIFF);
268292
269293 // m_iStdColWidthOrder is an array of the width for each column.
270294 // Entries must be in order of ascending Column ID. We initialize
@@ -281,6 +305,8 @@ CViewWork::CViewWork(wxNotebook* pNotebook) :
281305 m_iStdColWidthOrder.Insert (150 , COLUMN_REPORTDEADLINE);
282306 m_iStdColWidthOrder.Insert (95 , COLUMN_APPLICATION);
283307 m_iStdColWidthOrder.Insert (285 , COLUMN_NAME);
308+ m_iStdColWidthOrder.Insert (150 , COLUMN_ESTIMATEDCOMPLETION);
309+ m_iStdColWidthOrder.Insert (150 , COLUMN_DEADLINEDIFF);
284310
285311 wxASSERT (m_iStdColWidthOrder.size () == m_aStdColNameOrder->size ());
286312
@@ -331,6 +357,14 @@ void CViewWork::AppendColumn(int columnID){
331357 m_pListPane->AppendColumn ((*m_aStdColNameOrder)[COLUMN_NAME],
332358 wxLIST_FORMAT_LEFT, m_iStdColWidthOrder[COLUMN_NAME]);
333359 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 ;
334368 }
335369}
336370
@@ -752,9 +786,15 @@ wxString CViewWork::OnListGetItemText(long item, long column) const {
752786 case COLUMN_STATUS:
753787 strBuffer = work->m_strStatus ;
754788 break ;
789+ case COLUMN_ESTIMATEDCOMPLETION:
790+ strBuffer = work->m_strEstimatedCompletion ;
791+ break ;
792+ case COLUMN_DEADLINEDIFF:
793+ strBuffer = work->m_strDeadlineDiff ;
794+ break ;
755795 }
756796 }
757-
797+
758798 return strBuffer;
759799}
760800
@@ -870,7 +910,7 @@ void CViewWork::UpdateSelection() {
870910 // Step through all selected items
871911 row = m_pListPane->GetNextItem (row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
872912 if (row < 0 ) break ; // Should never happen
873-
913+
874914 result = pDoc->result (m_iSortedIndexes[row]);
875915 if (!result) continue ;
876916 if (i == 0 ) {
@@ -919,7 +959,7 @@ void CViewWork::UpdateSelection() {
919959 enableShowGraphics = false ;
920960 }
921961 }
922-
962+
923963 // Disable Show VM console if the selected task hasn't registered a remote
924964 // desktop connection
925965 //
@@ -941,7 +981,7 @@ void CViewWork::UpdateSelection() {
941981 enableShowGraphics = false ;
942982 }
943983 }
944-
984+
945985 // Disable Abort button if any selected task already aborted
946986 if (
947987 result->active_task_state == PROCESS_ABORT_PENDING ||
@@ -959,7 +999,7 @@ void CViewWork::UpdateSelection() {
959999 all_same_project = false ;
9601000 }
9611001 }
962-
1002+
9631003 if (n == 1 ) {
9641004 enableProperties = true ;
9651005 }
@@ -1002,7 +1042,7 @@ void CViewWork::UpdateSelection() {
10021042bool CViewWork::SynchronizeCacheItem (wxInt32 iRowIndex, wxInt32 iColumnIndex) {
10031043 wxString strDocumentText = wxEmptyString;
10041044 wxString strDocumentText2 = wxEmptyString;
1005- double x = 0.0 ;
1045+ double x = 0.0 ;
10061046 time_t tDocumentTime = (time_t )0 ;
10071047 CWork* work;
10081048
@@ -1011,9 +1051,9 @@ bool CViewWork::SynchronizeCacheItem(wxInt32 iRowIndex, wxInt32 iColumnIndex) {
10111051 if (GetWorkCacheAtIndex (work, m_iSortedIndexes[iRowIndex])) {
10121052 return false ;
10131053 }
1014-
1054+
10151055 if (iColumnIndex < 0 ) return false ;
1016-
1056+
10171057 switch (m_iColumnIndexToColumnID[iColumnIndex]) {
10181058 case COLUMN_PROJECT:
10191059 GetDocProjectName (m_iSortedIndexes[iRowIndex], strDocumentText);
@@ -1066,7 +1106,39 @@ bool CViewWork::SynchronizeCacheItem(wxInt32 iRowIndex, wxInt32 iColumnIndex) {
10661106 GetDocReportDeadline (m_iSortedIndexes[iRowIndex], tDocumentTime);
10671107 if (tDocumentTime != work->m_tReportDeadline ) {
10681108 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+ }
10701142 return true ;
10711143 }
10721144 break ;
@@ -1185,6 +1257,7 @@ void CViewWork::GetDocCPUTime(wxInt32 item, double& fBuffer) const {
11851257 }
11861258}
11871259
1260+
11881261void CViewWork::GetDocProgress (wxInt32 item, double & fBuffer ) const {
11891262 RESULT* result = wxGetApp ().GetDocument ()->result (item);
11901263
@@ -1219,37 +1292,65 @@ void CViewWork::GetDocTimeToCompletion(wxInt32 item, double& fBuffer) const {
12191292 }
12201293}
12211294
1222- void CViewWork::GetDocReportDeadline (wxInt32 item, time_t & time) const {
1295+
1296+ void CViewWork::GetDocReportDeadline (wxInt32 item, time_t & tBuffer) const {
12231297 RESULT* result = wxGetApp ().GetDocument ()->result (item);
12241298
12251299 if (result) {
1226- time = (time_t )result->report_deadline ;
1300+ tBuffer = (time_t )result->report_deadline ;
12271301 } else {
1228- time = (time_t )0 ;
1302+ tBuffer = (time_t )0 ;
12291303 }
12301304}
12311305
12321306
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 {
12341337#ifdef __WXMAC__
12351338 // Work around a wxCocoa bug(?) in wxDateTime::Format()
12361339 char buf[80 ];
1237- struct tm * timeinfo = localtime (&deadline );
1340+ struct tm * timeinfo = localtime (&datetime );
12381341 strftime (buf, sizeof (buf), " %c" , timeinfo);
12391342 strBuffer = buf;
12401343#else
12411344 wxDateTime dtTemp;
12421345
1243- dtTemp.Set (deadline );
1346+ dtTemp.Set (datetime );
12441347 strBuffer = dtTemp.Format ();
12451348#endif
12461349
12471350 return 0 ;
12481351}
12491352
12501353
1251-
1252-
12531354wxInt32 CViewWork::FormatStatus (wxInt32 item, wxString& strBuffer) const {
12541355 CWork* work;
12551356
@@ -1319,7 +1420,7 @@ int CViewWork::GetWorkCacheAtIndex(CWork*& workPtr, int index) {
13191420 workPtr = NULL ;
13201421 return -1 ;
13211422 }
1322-
1423+
13231424 return 0 ;
13241425}
13251426
0 commit comments