1 // This file is part of BOINC.
2 // http://boinc.berkeley.edu
3 // Copyright (C) 2008 University of California
4 //
5 // BOINC is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License
7 // as published by the Free Software Foundation,
8 // either version 3 of the License, or (at your option) any later version.
9 //
10 // BOINC is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 // See the GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
17 
18 #if defined(__GNUG__) && !defined(__APPLE__)
19 #pragma implementation "ViewWork.h"
20 #endif
21 
22 #include "stdwx.h"
23 #include "BOINCGUIApp.h"
24 #include "BOINCBaseFrame.h"
25 #include "MainDocument.h"
26 #include "AdvancedFrame.h"
27 #include "BOINCTaskCtrl.h"
28 #include "BOINCListCtrl.h"
29 #include "ViewWork.h"
30 #include "Events.h"
31 #include "error_numbers.h"
32 #include "app_ipc.h"
33 #include "util.h"
34 #include "DlgItemProperties.h"
35 
36 #include "res/result.xpm"
37 
38 
39 // Column IDs must be equal to the column's default
40 // position (left to right, zero-based) when all
41 // columns are shown.  However, any column may be
42 // hidden, either by default or by the user.
43 // (On MS Windows only, the user can also rearrange
44 // the columns from the default order.)
45 //
46 // Column IDs
47 #define COLUMN_PROJECT              0
48 #define COLUMN_PROGRESS             1
49 #define COLUMN_STATUS               2
50 #define COLUMN_CPUTIME              3
51 #define COLUMN_TOCOMPLETION         4
52 #define COLUMN_REPORTDEADLINE       5
53 #define COLUMN_APPLICATION          6
54 #define COLUMN_NAME                 7
55 
56 // DefaultShownColumns is an array containing the
57 // columnIDs of the columns to be shown by default,
58 // in ascending order.  It may or may not include
59 // all columns.
60 //
61 // For now, show all columns by default
62 static int DefaultShownColumns[] = { COLUMN_PROJECT, COLUMN_PROGRESS, COLUMN_STATUS,
63                                 COLUMN_CPUTIME, COLUMN_TOCOMPLETION,
64                                 COLUMN_REPORTDEADLINE, COLUMN_APPLICATION,
65                                 COLUMN_NAME};
66 
67 // groups that contain buttons
68 #define GRP_TASKS    0
69 #define GRP_WEBSITES 1
70 
71 // buttons in the "tasks" area
72 #define BTN_ACTIVE_ONLY             0
73 #define BTN_GRAPHICS                1
74 #define BTN_VMCONSOLE               2
75 #define BTN_SUSPEND                 3
76 #define BTN_ABORT                   4
77 #define BTN_PROPERTIES              5
78 
79 
CWork()80 CWork::CWork() {
81     m_fCPUTime = -1.0;
82     m_fProgress = -1.0;
83     m_fTimeToCompletion = -1.0;
84     m_tReportDeadline = (time_t)0;
85 }
86 
87 
~CWork()88 CWork::~CWork() {
89     m_strProjectName.Clear();
90     m_strApplicationName.Clear();
91     m_strName.Clear();
92     m_strStatus.Clear();
93     m_strProjectURL.Clear();
94     m_strCPUTime.Clear();
95     m_strProgress.Clear();
96     m_strTimeToCompletion.Clear();
97     m_strReportDeadline.Clear();
98 }
99 
100 
101 IMPLEMENT_DYNAMIC_CLASS(CViewWork, CBOINCBaseView)
102 
103 BEGIN_EVENT_TABLE (CViewWork, CBOINCBaseView)
104     EVT_BUTTON(ID_TASK_WORK_SUSPEND, CViewWork::OnWorkSuspend)
105     EVT_BUTTON(ID_TASK_WORK_SHOWGRAPHICS, CViewWork::OnWorkShowGraphics)
106     EVT_BUTTON(ID_TASK_WORK_VMCONSOLE, CViewWork::OnWorkShowVMConsole)
107     EVT_BUTTON(ID_TASK_WORK_ABORT, CViewWork::OnWorkAbort)
108     EVT_BUTTON(ID_TASK_SHOW_PROPERTIES, CViewWork::OnShowItemProperties)
109     EVT_BUTTON(ID_TASK_ACTIVE_ONLY, CViewWork::OnActiveTasksOnly)
110     EVT_CUSTOM_RANGE(wxEVT_COMMAND_BUTTON_CLICKED, ID_TASK_PROJECT_WEB_PROJDEF_MIN, ID_TASK_PROJECT_WEB_PROJDEF_MAX, CViewWork::OnProjectWebsiteClicked)
111 // We currently handle EVT_LIST_CACHE_HINT on Windows or
112 // EVT_CHECK_SELECTION_CHANGED on Mac & Linux instead of EVT_LIST_ITEM_SELECTED
113 // or EVT_LIST_ITEM_DESELECTED.  See CBOINCBaseView::OnCacheHint() for info.
114 #if USE_LIST_CACHE_HINT
115     EVT_LIST_CACHE_HINT(ID_LIST_WORKVIEW, CViewWork::OnCacheHint)
116 #else
117 	EVT_CHECK_SELECTION_CHANGED(CViewWork::OnCheckSelectionChanged)
118 #endif
119     EVT_LIST_COL_CLICK(ID_LIST_WORKVIEW, CViewWork::OnColClick)
120     EVT_LIST_COL_END_DRAG(ID_LIST_WORKVIEW, CViewWork::OnColResize)
121 END_EVENT_TABLE ()
122 
123 
124 static CViewWork* myCViewWork;
125 
CompareViewWorkItems(int iRowIndex1,int iRowIndex2)126 static bool CompareViewWorkItems(int iRowIndex1, int iRowIndex2) {
127     CWork*          work1;
128     CWork*          work2;
129     int             result = false;
130 
131     try {
132         work1 = myCViewWork->m_WorkCache.at(iRowIndex1);
133     } catch ( std::out_of_range ) {
134         return 0;
135     }
136 
137     try {
138         work2 = myCViewWork->m_WorkCache.at(iRowIndex2);
139     } catch ( std::out_of_range ) {
140         return 0;
141     }
142 
143     switch (myCViewWork->m_iSortColumnID) {
144     case COLUMN_PROJECT:
145         result = work1->m_strProjectName.CmpNoCase(work2->m_strProjectName);
146         break;
147     case COLUMN_APPLICATION:
148         result = work1->m_strApplicationName.CmpNoCase(work2->m_strApplicationName);
149         break;
150     case COLUMN_NAME:
151         result = work1->m_strName.CmpNoCase(work2->m_strName);
152         break;
153     case COLUMN_CPUTIME:
154         if (work1->m_fCPUTime < work2->m_fCPUTime) {
155             result = -1;
156         } else if (work1->m_fCPUTime > work2->m_fCPUTime) {
157             result = 1;
158         }
159         break;
160     case COLUMN_PROGRESS:
161         if (work1->m_fProgress < work2->m_fProgress) {
162             result = -1;
163         } else if (work1->m_fProgress > work2->m_fProgress) {
164             result = 1;
165         }
166         break;
167     case COLUMN_TOCOMPLETION:
168         if (work1->m_fTimeToCompletion < work2->m_fTimeToCompletion) {
169             result = -1;
170         } else if (work1->m_fTimeToCompletion > work2->m_fTimeToCompletion) {
171             result = 1;
172         }
173         break;
174     case COLUMN_REPORTDEADLINE:
175         if (work1->m_tReportDeadline < work2->m_tReportDeadline) {
176             result = -1;
177         } else if (work1->m_tReportDeadline > work2->m_tReportDeadline) {
178             result = 1;
179         }
180         break;
181     case COLUMN_STATUS:
182         result = work1->m_strStatus.CmpNoCase(work2->m_strStatus);
183         break;
184     }
185 
186     // Always return FALSE for equality (result == 0)
187     return (myCViewWork->m_bReverseSort ? (result > 0) : (result < 0));
188 }
189 
190 
CViewWork()191 CViewWork::CViewWork()
192 {}
193 
194 
CViewWork(wxNotebook * pNotebook)195 CViewWork::CViewWork(wxNotebook* pNotebook) :
196     CBOINCBaseView(pNotebook, ID_TASK_WORKVIEW, DEFAULT_TASK_FLAGS, ID_LIST_WORKVIEW, DEFAULT_LIST_FLAGS)
197 {
198     CTaskItemGroup* pGroup = NULL;
199     CTaskItem*      pItem = NULL;
200 
201     wxASSERT(m_pTaskPane);
202     wxASSERT(m_pListPane);
203 
204     //
205     // Setup View
206     //
207     pGroup = new CTaskItemGroup( _("Commands") );
208     m_TaskGroups.push_back( pGroup );
209 
210     pItem = new CTaskItem(
211         _("Show active tasks"),
212         _("Show only active tasks."),
213         ID_TASK_ACTIVE_ONLY
214     );
215     pGroup->m_Tasks.push_back( pItem );
216 
217     pItem = new CTaskItem(
218         _("Show graphics"),
219         _("Show application graphics in a window."),
220         ID_TASK_WORK_SHOWGRAPHICS
221     );
222     pGroup->m_Tasks.push_back( pItem );
223 
224     pItem = new CTaskItem(
225         _("Show VM Console"),
226         _("Show VM Console in a window."),
227         ID_TASK_WORK_VMCONSOLE
228     );
229     pGroup->m_Tasks.push_back( pItem );
230 
231     pItem = new CTaskItem(
232         _("Suspend"),
233         _("Suspend work for this result."),
234         ID_TASK_WORK_SUSPEND
235     );
236     pGroup->m_Tasks.push_back( pItem );
237 
238     pItem = new CTaskItem(
239         _("Abort"),
240         _("Abandon work on the result. You will get no credit for it."),
241         ID_TASK_WORK_ABORT
242     );
243     pGroup->m_Tasks.push_back( pItem );
244 
245     pItem = new CTaskItem(
246         _("Properties"),
247         _("Show task details."),
248         ID_TASK_SHOW_PROPERTIES
249     );
250     pGroup->m_Tasks.push_back( pItem );
251 
252     // Create Task Pane Items
253     m_pTaskPane->UpdateControls();
254 
255     // m_aStdColNameOrder is an array of all column heading labels
256     // (localized) in order of ascending Column ID.
257     // Once initialized, it should not be modified.
258     //
259     m_aStdColNameOrder = new wxArrayString;
260     m_aStdColNameOrder->Insert(_("Project"), COLUMN_PROJECT);
261     m_aStdColNameOrder->Insert(_("Progress"), COLUMN_PROGRESS);
262     m_aStdColNameOrder->Insert(_("Status"), COLUMN_STATUS);
263     m_aStdColNameOrder->Insert(_("Elapsed"), COLUMN_CPUTIME);
264     m_aStdColNameOrder->Insert(_("Remaining (estimated)"), COLUMN_TOCOMPLETION);
265     m_aStdColNameOrder->Insert(_("Deadline"), COLUMN_REPORTDEADLINE);
266     m_aStdColNameOrder->Insert(_("Application"), COLUMN_APPLICATION);
267     m_aStdColNameOrder->Insert(_("Name"), COLUMN_NAME);
268 
269     // m_iStdColWidthOrder is an array of the width for each column.
270     // Entries must be in order of ascending Column ID.  We initalize
271     // it here to the default column widths.  It is updated by
272     // CBOINCListCtrl::OnRestoreState() and also when a user resizes
273     // a column by dragging the divider between two columns.
274     //
275     m_iStdColWidthOrder.Clear();
276     m_iStdColWidthOrder.Insert(125, COLUMN_PROJECT);
277     m_iStdColWidthOrder.Insert(60, COLUMN_PROGRESS);
278     m_iStdColWidthOrder.Insert(135, COLUMN_STATUS);
279     m_iStdColWidthOrder.Insert(80, COLUMN_CPUTIME);
280     m_iStdColWidthOrder.Insert(100, COLUMN_TOCOMPLETION);
281     m_iStdColWidthOrder.Insert(150, COLUMN_REPORTDEADLINE);
282     m_iStdColWidthOrder.Insert(95, COLUMN_APPLICATION);
283     m_iStdColWidthOrder.Insert(285, COLUMN_NAME);
284 
285     wxASSERT(m_iStdColWidthOrder.size() == m_aStdColNameOrder->size());
286 
287     m_iDefaultShownColumns = DefaultShownColumns;
288     m_iNumDefaultShownColumns = sizeof(DefaultShownColumns) / sizeof(int);
289     m_iProgressColumn = COLUMN_PROGRESS;
290 
291     // Needed by static sort routine;
292     myCViewWork = this;
293     m_funcSortCompare = CompareViewWorkItems;
294 
295     UpdateSelection();
296 }
297 
298 
299 // Create List Pane Items
AppendColumn(int columnID)300 void CViewWork::AppendColumn(int columnID){
301     switch(columnID) {
302         case COLUMN_PROJECT:
303             m_pListPane->AppendColumn((*m_aStdColNameOrder)[COLUMN_PROJECT],
304                 wxLIST_FORMAT_LEFT, m_iStdColWidthOrder[COLUMN_PROJECT]);
305             break;
306         case COLUMN_PROGRESS:
307             m_pListPane->AppendColumn((*m_aStdColNameOrder)[COLUMN_PROGRESS],
308                 wxLIST_FORMAT_RIGHT, m_iStdColWidthOrder[COLUMN_PROGRESS]);
309             break;
310         case COLUMN_STATUS:
311             m_pListPane->AppendColumn((*m_aStdColNameOrder)[COLUMN_STATUS],
312                 wxLIST_FORMAT_LEFT, m_iStdColWidthOrder[COLUMN_STATUS]);
313             break;
314         case COLUMN_CPUTIME:
315             m_pListPane->AppendColumn((*m_aStdColNameOrder)[COLUMN_CPUTIME],
316                 wxLIST_FORMAT_RIGHT, m_iStdColWidthOrder[COLUMN_CPUTIME]);
317             break;
318         case COLUMN_TOCOMPLETION:
319             m_pListPane->AppendColumn((*m_aStdColNameOrder)[COLUMN_TOCOMPLETION],
320                 wxLIST_FORMAT_RIGHT, m_iStdColWidthOrder[COLUMN_TOCOMPLETION]);
321             break;
322         case COLUMN_REPORTDEADLINE:
323             m_pListPane->AppendColumn((*m_aStdColNameOrder)[COLUMN_REPORTDEADLINE],
324                 wxLIST_FORMAT_RIGHT, m_iStdColWidthOrder[COLUMN_REPORTDEADLINE]);
325             break;
326         case COLUMN_APPLICATION:
327             m_pListPane->AppendColumn((*m_aStdColNameOrder)[COLUMN_APPLICATION],
328                 wxLIST_FORMAT_LEFT, m_iStdColWidthOrder[COLUMN_APPLICATION]);
329             break;
330         case COLUMN_NAME:
331             m_pListPane->AppendColumn((*m_aStdColNameOrder)[COLUMN_NAME],
332                 wxLIST_FORMAT_LEFT, m_iStdColWidthOrder[COLUMN_NAME]);
333             break;
334     }
335 }
336 
337 
~CViewWork()338 CViewWork::~CViewWork() {
339     EmptyCache();
340     EmptyTasks();
341 }
342 
343 
GetViewName()344 wxString& CViewWork::GetViewName() {
345     static wxString strViewName(wxT("Tasks"));
346     return strViewName;
347 }
348 
349 
GetViewDisplayName()350 wxString& CViewWork::GetViewDisplayName() {
351     static wxString strViewName(_("Tasks"));
352     return strViewName;
353 }
354 
355 
GetViewIcon()356 const char** CViewWork::GetViewIcon() {
357     return result_xpm;
358 }
359 
360 
GetViewCurrentViewPage()361 int CViewWork::GetViewCurrentViewPage() {
362     return VW_TASK;
363 }
364 
365 
GetKeyValue1(int iRowIndex)366 wxString CViewWork::GetKeyValue1(int iRowIndex) {
367     CWork*          work;
368 
369     if (GetWorkCacheAtIndex(work, m_iSortedIndexes[iRowIndex])) {
370         return wxEmptyString;
371     }
372 
373     if (m_iColumnIDToColumnIndex[COLUMN_NAME] < 0) {
374         // Column is hidden, so SynchronizeCacheItem() did not set its value
375         GetDocName(m_iSortedIndexes[iRowIndex], work->m_strName);
376     }
377 
378     return work->m_strName;
379 }
380 
381 
GetKeyValue2(int iRowIndex)382 wxString CViewWork::GetKeyValue2(int iRowIndex) {
383      CWork*          work;
384 
385     if (GetWorkCacheAtIndex(work, m_iSortedIndexes[iRowIndex])) {
386         return wxEmptyString;
387     }
388 
389     if (m_iColumnIDToColumnIndex[COLUMN_PROJECT] < 0) {
390         // Column is hidden, so SynchronizeCacheItem() did not set its value
391         GetDocProjectURL(m_iSortedIndexes[iRowIndex], work->m_strProjectURL);
392     }
393 
394     return work->m_strProjectURL;
395 }
396 
397 
FindRowIndexByKeyValues(wxString & key1,wxString & key2)398 int CViewWork::FindRowIndexByKeyValues(wxString& key1, wxString& key2) {
399     CWork* work;
400     unsigned int iRowIndex, n = GetCacheCount();
401     for(iRowIndex=0; iRowIndex < n; iRowIndex++) {
402         if (GetWorkCacheAtIndex(work, m_iSortedIndexes[iRowIndex])) {
403             continue;
404         }
405         if(! (work->m_strName).IsSameAs(key1)) continue;
406         if((work->m_strProjectURL).IsSameAs(key2)) return iRowIndex;
407     }
408     return -1;
409 }
410 
411 
OnActiveTasksOnly(wxCommandEvent & WXUNUSED (event))412 void CViewWork::OnActiveTasksOnly( wxCommandEvent& WXUNUSED(event) ) {
413     wxLogTrace(wxT("Function Start/End"), wxT("CViewWork::OnActiveTasksOnly - Function Begin"));
414 
415     CMainDocument* pDoc     = wxGetApp().GetDocument();
416     CAdvancedFrame* pFrame      = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
417 
418     wxASSERT(pDoc);
419     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
420     wxASSERT(pFrame);
421     wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
422 
423     pDoc->m_ActiveTasksOnly = !pDoc->m_ActiveTasksOnly;
424     UpdateSelection();
425     pFrame->FireRefreshView();
426 
427     wxLogTrace(wxT("Function Start/End"), wxT("CViewWork::OnActiveTasksOnly - Function End"));
428 }
429 
430 
OnWorkSuspend(wxCommandEvent & WXUNUSED (event))431 void CViewWork::OnWorkSuspend( wxCommandEvent& WXUNUSED(event) ) {
432     wxLogTrace(wxT("Function Start/End"), wxT("CViewWork::OnWorkSuspend - Function Begin"));
433 
434     CMainDocument* pDoc     = wxGetApp().GetDocument();
435     CAdvancedFrame* pFrame  = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
436     int row;
437 
438     wxASSERT(pDoc);
439     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
440     wxASSERT(pFrame);
441     wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
442     wxASSERT(m_pTaskPane);
443     wxASSERT(m_pListPane);
444 
445     row = -1;
446     while (1) {
447         // Step through all selected items
448         row = m_pListPane->GetNextItem(row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
449         if (row < 0) break;
450 
451         RESULT* result = pDoc->result(m_iSortedIndexes[row]);
452         if (result) {
453             if (result->suspended_via_gui) {
454                 pDoc->WorkResume(result->project_url, result->name);
455             } else {
456                 pDoc->WorkSuspend(result->project_url, result->name);
457             }
458         }
459     }
460 
461     UpdateSelection();
462     pFrame->FireRefreshView();
463 
464     wxLogTrace(wxT("Function Start/End"), wxT("CViewWork::OnWorkSuspend - Function End"));
465 }
466 
467 
OnWorkShowGraphics(wxCommandEvent & WXUNUSED (event))468 void CViewWork::OnWorkShowGraphics( wxCommandEvent& WXUNUSED(event) ) {
469     wxLogTrace(wxT("Function Start/End"), wxT("CViewWork::OnWorkShowGraphics - Function Begin"));
470 
471     CMainDocument* pDoc     = wxGetApp().GetDocument();
472     CAdvancedFrame* pFrame  = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
473     RESULT* result;
474     int row;
475 
476     wxASSERT(pDoc);
477     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
478     wxASSERT(pFrame);
479     wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
480     wxASSERT(m_pListPane);
481 
482     row = -1;
483     while (1) {
484         // Step through all selected items
485         row = m_pListPane->GetNextItem(row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
486         if (row < 0) break;
487 
488         result = pDoc->result(m_iSortedIndexes[row]);
489         if (result) {
490             pDoc->WorkShowGraphics(result);
491         }
492     }
493 
494     UpdateSelection();
495     pFrame->FireRefreshView();
496 
497     wxLogTrace(wxT("Function Start/End"), wxT("CViewWork::OnWorkShowGraphics - Function End"));
498 }
499 
500 
OnWorkShowVMConsole(wxCommandEvent & WXUNUSED (event))501 void CViewWork::OnWorkShowVMConsole( wxCommandEvent& WXUNUSED(event) ) {
502     wxLogTrace(wxT("Function Start/End"), wxT("CViewWork::OnWorkShowVMConsole - Function Begin"));
503 
504     CMainDocument* pDoc     = wxGetApp().GetDocument();
505     CAdvancedFrame* pFrame  = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
506     RESULT* result;
507     int row;
508 
509     wxASSERT(pDoc);
510     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
511     wxASSERT(pFrame);
512     wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
513     wxASSERT(m_pListPane);
514 
515     row = -1;
516     while (1) {
517         // Step through all selected items
518         row = m_pListPane->GetNextItem(row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
519         if (row < 0) break;
520 
521         result = pDoc->result(m_iSortedIndexes[row]);
522         if (result) {
523             pDoc->WorkShowVMConsole(result);
524         }
525     }
526 
527     UpdateSelection();
528     pFrame->FireRefreshView();
529 
530     wxLogTrace(wxT("Function Start/End"), wxT("CViewWork::OnWorkShowVMConsole - Function End"));
531 }
532 
533 
OnWorkAbort(wxCommandEvent & WXUNUSED (event))534 void CViewWork::OnWorkAbort( wxCommandEvent& WXUNUSED(event) ) {
535     wxLogTrace(wxT("Function Start/End"), wxT("CViewWork::OnWorkAbort - Function Begin"));
536 
537     wxInt32  iAnswer        = 0;
538     wxString strMessage     = wxEmptyString;
539     CMainDocument* pDoc     = wxGetApp().GetDocument();
540     CAdvancedFrame* pFrame  = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
541     CWork* work;
542     int row, n;
543 
544     wxASSERT(pDoc);
545     wxASSERT(pFrame);
546     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
547     wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
548     wxASSERT(m_pTaskPane);
549     wxASSERT(m_pListPane);
550 
551     if (!pDoc->IsUserAuthorized())
552         return;
553 
554     n = m_pListPane->GetSelectedItemCount();
555 
556     if (n == 1) {
557         row = -1;
558         row = m_pListPane->GetNextItem(row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
559         if (row < 0) return;
560         if (GetWorkCacheAtIndex(work, m_iSortedIndexes[row])) {
561             return;
562         }
563         strMessage.Printf(
564            _("Are you sure you want to abort this task '%s'?\n(Progress: %s, Status: %s)"),
565            (work->m_strName).c_str(),
566            (work->m_strProgress).c_str(),
567            (work->m_strStatus).c_str()
568         );
569     } else {
570         strMessage.Printf(_("Are you sure you want to abort these %d tasks?"), n);
571     }
572 
573     iAnswer = wxGetApp().SafeMessageBox(
574         strMessage,
575         _("Abort task"),
576         wxYES_NO | wxICON_QUESTION,
577         this
578     );
579 
580     if (wxYES != iAnswer) {
581         return;
582     }
583 
584     row = -1;
585     while (1) {
586         // Step through all selected items
587         row = m_pListPane->GetNextItem(row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
588         if (row < 0) break;
589 
590         RESULT* result = pDoc->result(m_iSortedIndexes[row]);
591         if (result) {
592             pDoc->WorkAbort(result->project_url, result->name);
593         }
594     }
595 
596     UpdateSelection();
597     pFrame->FireRefreshView();
598 
599     wxLogTrace(wxT("Function Start/End"), wxT("CViewWork::OnWorkAbort - Function End"));
600 }
601 
602 
OnShowItemProperties(wxCommandEvent & WXUNUSED (event))603 void CViewWork::OnShowItemProperties( wxCommandEvent& WXUNUSED(event) ) {
604     wxASSERT(m_pListPane);
605 
606     long item = m_pListPane->GetFirstSelected();
607     RESULT* result = wxGetApp().GetDocument()->result(m_iSortedIndexes[item]);
608 
609     if(!result) return;     // TODO: display some sort of error alert?
610     //displaying the infos on a dialog
611     CDlgItemProperties dlg(this);
612     dlg.renderInfos(result);
613     dlg.ShowModal();
614 }
615 
616 
OnSaveState(wxConfigBase * pConfig)617 bool CViewWork::OnSaveState(wxConfigBase* pConfig) {
618     bool bReturnValue = true;
619     CMainDocument* pDoc     = wxGetApp().GetDocument();
620 
621     wxASSERT(pDoc);
622     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
623     wxASSERT(pConfig);
624     wxASSERT(m_pTaskPane);
625     wxASSERT(m_pListPane);
626 
627     if (!m_pTaskPane->OnSaveState(pConfig)) {
628         bReturnValue = false;
629     }
630     if (!m_pListPane->OnSaveState(pConfig)) {
631         bReturnValue = false;
632     }
633 
634     wxString    strBaseConfigLocation = wxEmptyString;
635     strBaseConfigLocation = wxT("/Tasks");
636     pConfig->SetPath(strBaseConfigLocation);
637     pConfig->Write(wxT("ActiveTasksOnly"), (pDoc->m_ActiveTasksOnly ? 1 : 0));
638 
639     return bReturnValue;
640 }
641 
642 
OnRestoreState(wxConfigBase * pConfig)643 bool CViewWork::OnRestoreState(wxConfigBase* pConfig) {
644     CMainDocument* pDoc     = wxGetApp().GetDocument();
645 
646     wxASSERT(pDoc);
647     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
648     wxASSERT(pConfig);
649     wxASSERT(m_pTaskPane);
650     wxASSERT(m_pListPane);
651 
652     if (!m_pTaskPane->OnRestoreState(pConfig)) {
653         return false;
654     }
655     if (!m_pListPane->OnRestoreState(pConfig)) {
656         return false;
657     }
658 
659     int     iTempValue = 0;
660     wxString    strBaseConfigLocation = wxEmptyString;
661     strBaseConfigLocation = wxT("/Tasks");
662     pConfig->SetPath(strBaseConfigLocation);
663     pConfig->Read(wxT("ActiveTasksOnly"), &iTempValue, 0);
664     pDoc->m_ActiveTasksOnly = (iTempValue != 0);
665 
666     return true;
667 }
668 
669 
OnProjectWebsiteClicked(wxEvent & event)670 void CViewWork::OnProjectWebsiteClicked( wxEvent& event ) {
671     wxLogTrace(wxT("Function Start/End"), wxT("CViewWork::OnProjectWebsiteClicked - Function Begin"));
672 
673     CAdvancedFrame* pFrame      = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
674 
675     wxASSERT(pFrame);
676     wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
677     wxASSERT(m_pTaskPane);
678     wxASSERT(m_pListPane);
679 
680     int website_task_index = event.GetId() - ID_TASK_PROJECT_WEB_PROJDEF_MIN;
681     wxLaunchDefaultBrowser(
682         m_TaskGroups[1]->m_Tasks[website_task_index]->m_strWebSiteLink
683     );
684 
685     UpdateSelection();
686     pFrame->FireRefreshView();
687 
688     wxLogTrace(wxT("Function Start/End"), wxT("CViewWork::OnProjectWebsiteClicked - Function End"));
689 }
690 
691 
OnColResize(wxListEvent &)692 void CViewWork::OnColResize( wxListEvent& ) {
693     // Register the new column widths immediately
694     CAdvancedFrame* pFrame = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
695 
696     wxASSERT(pFrame);
697     wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
698     pFrame->SaveState();
699 }
700 
701 
GetDocCount()702 wxInt32 CViewWork::GetDocCount() {
703     return wxGetApp().GetDocument()->GetWorkCount();
704 }
705 
706 
OnListGetItemText(long item,long column) const707 wxString CViewWork::OnListGetItemText(long item, long column) const {
708     CWork*    work      = NULL;
709     wxString  strBuffer = wxEmptyString;
710 
711     m_pListPane->AddPendingProgressBar(item);
712 
713     try {
714         work = m_WorkCache.at(m_iSortedIndexes[item]);
715     } catch ( std::out_of_range ) {
716         work = NULL;
717     }
718 
719     if (work && (column >= 0)) {
720         switch(m_iColumnIndexToColumnID[column]) {
721             case COLUMN_PROJECT:
722                 strBuffer = work->m_strProjectName;
723                 break;
724             case COLUMN_APPLICATION:
725                 strBuffer = work->m_strApplicationName;
726                 break;
727             case COLUMN_NAME:
728                 strBuffer = work->m_strName;
729                 break;
730             case COLUMN_CPUTIME:
731                 strBuffer = work->m_strCPUTime;
732                 break;
733             case COLUMN_PROGRESS:
734                 // CBOINCListCtrl::DrawProgressBars() will draw this using
735                 // data provided by GetProgressText() and GetProgressValue(),
736                 // but we need it here for accessibility programs.
737                 strBuffer = work->m_strProgress;
738                 break;
739             case COLUMN_TOCOMPLETION:
740                 strBuffer = work->m_strTimeToCompletion;
741                 break;
742             case COLUMN_REPORTDEADLINE:
743                 strBuffer = work->m_strReportDeadline;
744                 break;
745             case COLUMN_STATUS:
746                 strBuffer = work->m_strStatus;
747                 break;
748         }
749     }
750 
751     return strBuffer;
752 }
753 
754 
AddCacheElement()755 wxInt32 CViewWork::AddCacheElement() {
756     CWork* pItem = new CWork();
757     wxASSERT(pItem);
758     if (pItem) {
759         m_WorkCache.push_back(pItem);
760         m_iSortedIndexes.Add((int)m_WorkCache.size()-1);
761         return 0;
762     }
763     return -1;
764 }
765 
766 
EmptyCache()767 wxInt32 CViewWork::EmptyCache() {
768     unsigned int i;
769     for (i=0; i<m_WorkCache.size(); i++) {
770         delete m_WorkCache[i];
771     }
772     m_WorkCache.clear();
773     m_iSortedIndexes.Clear();
774     return 0;
775 }
776 
777 
GetCacheCount()778 wxInt32 CViewWork::GetCacheCount() {
779     return (wxInt32)m_WorkCache.size();
780 }
781 
782 
RemoveCacheElement()783 wxInt32 CViewWork::RemoveCacheElement() {
784     unsigned int i;
785     delete m_WorkCache.back();
786     m_WorkCache.erase(m_WorkCache.end() - 1);
787     m_iSortedIndexes.Clear();
788     for (i=0; i<m_WorkCache.size(); i++) {
789         m_iSortedIndexes.Add(i);
790     }
791     return 0;
792 }
793 
794 
IsSelectionManagementNeeded()795 bool CViewWork::IsSelectionManagementNeeded() {
796     return true;
797 }
798 
799 
UpdateSelection()800 void CViewWork::UpdateSelection() {
801     int                 i, n, row;
802     CTaskItemGroup*     pGroup = NULL;
803     RESULT*             result = NULL;
804     PROJECT*            project = NULL;
805     CC_STATUS           status;
806     CMainDocument*      pDoc = wxGetApp().GetDocument();
807     std::string         first_project_url;
808     wxString            strMachineName;
809     bool                wasSuspended=false;
810     bool                all_same_project=false;
811     bool                enableShowGraphics = false;
812     bool                enableShowVMConsole = false;
813     bool                enableSuspendResume = false;
814     bool                enableAbort = false;
815     bool                enableProperties = false;
816 
817     wxASSERT(NULL != pDoc);
818     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
819     wxASSERT(NULL != m_pTaskPane);
820 
821     CBOINCBaseView::PreUpdateSelection();
822 
823     pGroup = m_TaskGroups[0];
824 
825     n = m_pListPane->GetSelectedItemCount();
826     if (n > 0) {
827         enableShowGraphics = true;
828         enableShowVMConsole = true;
829         enableSuspendResume = true;
830         enableAbort = true;
831 
832         pDoc->GetCoreClientStatus(status);
833         if (status.task_suspend_reason & ~(SUSPEND_REASON_CPU_THROTTLE)) {
834             enableShowGraphics = false;
835             enableShowVMConsole = false;
836         }
837 
838         pDoc->GetConnectedComputerName(strMachineName);
839         if (!pDoc->IsComputerNameLocal(strMachineName)) {
840             enableShowGraphics = false;
841             enableShowVMConsole = false;
842         }
843     }
844 
845     if (pDoc->m_ActiveTasksOnly) {
846         m_pTaskPane->UpdateTask(
847             pGroup->m_Tasks[BTN_ACTIVE_ONLY],
848             _("Show all tasks"),
849             _("Show all tasks.")
850         );
851     } else {
852         m_pTaskPane->UpdateTask(
853             pGroup->m_Tasks[BTN_ACTIVE_ONLY],
854             _("Show active tasks"),
855             _("Show only active tasks.")
856         );
857     }
858 
859     row = -1;
860     for (i=0; i<n; i++) {
861         // Step through all selected items
862         row = m_pListPane->GetNextItem(row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
863         if (row < 0) break;     // Should never happen
864 
865         result = pDoc->result(m_iSortedIndexes[row]);
866         if (!result) continue;
867         if (i == 0) {
868             wasSuspended = result->suspended_via_gui;
869             if (result->suspended_via_gui) {
870                 m_pTaskPane->UpdateTask(
871                     pGroup->m_Tasks[BTN_SUSPEND],
872                     _("Resume"),
873                     _("Resume work for this task.")
874                 );
875             } else {
876                 m_pTaskPane->UpdateTask(
877                     pGroup->m_Tasks[BTN_SUSPEND],
878                     _("Suspend"),
879                     _("Suspend work for this task.")
880                 );
881             }
882         } else {
883             if (wasSuspended != result->suspended_via_gui) {
884                 // Disable Suspend / Resume button if the multiple selection
885                 // has a mix of suspended and not suspended tasks
886                 enableSuspendResume = false;
887             }
888         }
889 
890         // Disable Show VM console if the selected task hasn't registered a remote
891         // desktop connection
892         //
893         if (!strlen(result->remote_desktop_addr)) {
894             enableShowVMConsole = false;
895         }
896 
897         // Disable Show Graphics button if the selected task can't display graphics
898         //
899         if (!strlen(result->web_graphics_url) && !strlen(result->graphics_exec_path)) {
900             enableShowGraphics = false;
901         }
902 
903         if (result->suspended_via_gui ||
904             result->project_suspended_via_gui ||
905             (result->scheduler_state != CPU_SCHED_SCHEDULED)
906         ) {
907             enableShowGraphics = false;
908         }
909 
910         // Disable Abort button if any selected task already aborted
911         if (
912             result->active_task_state == PROCESS_ABORT_PENDING ||
913             result->active_task_state == PROCESS_ABORTED ||
914             result->state == RESULT_ABORTED
915         ) {
916             enableAbort = false;
917         }
918 
919        if (i == 0) {
920             first_project_url = result->project_url;
921             all_same_project = true;
922         } else {
923             if (first_project_url != result->project_url) {
924                 all_same_project = false;
925             }
926         }
927 
928         if (n == 1) {
929             enableProperties = true;
930         }
931     }
932 
933     // To minimize flicker, set each button only once to the final desired state
934     pGroup->m_Tasks[BTN_GRAPHICS]->m_pButton->Enable(enableShowGraphics);
935     if (enableShowVMConsole) {
936         pGroup->m_Tasks[BTN_VMCONSOLE]->m_pButton->Enable();
937         if (pGroup->m_Tasks[BTN_VMCONSOLE]->m_pButton->Show()) {
938             m_pTaskPane->FitInside();
939         }
940     } else {
941         pGroup->m_Tasks[BTN_VMCONSOLE]->m_pButton->Disable();
942         if (pGroup->m_Tasks[BTN_VMCONSOLE]->m_pButton->Hide()) {
943             m_pTaskPane->FitInside();
944         };
945     }
946     pGroup->m_Tasks[BTN_SUSPEND]->m_pButton->Enable(enableSuspendResume);
947     pGroup->m_Tasks[BTN_ABORT]->m_pButton->Enable(enableAbort);
948     pGroup->m_Tasks[BTN_PROPERTIES]->m_pButton->Enable(enableProperties);
949 
950     if (all_same_project) {
951         project = pDoc->state.lookup_project(result->project_url);
952         UpdateWebsiteSelection(GRP_WEBSITES, project);
953         if(m_TaskGroups.size()>1) {
954             m_pTaskPane->EnableTaskGroupTasks(m_TaskGroups[1]);
955         }
956     } else {
957         UpdateWebsiteSelection(GRP_WEBSITES, NULL);
958         if(m_TaskGroups.size()>1) {
959             m_pTaskPane->DisableTaskGroupTasks(m_TaskGroups[1]);
960         }
961     }
962 
963     CBOINCBaseView::PostUpdateSelection();
964 }
965 
966 
SynchronizeCacheItem(wxInt32 iRowIndex,wxInt32 iColumnIndex)967 bool CViewWork::SynchronizeCacheItem(wxInt32 iRowIndex, wxInt32 iColumnIndex) {
968     wxString    strDocumentText  = wxEmptyString;
969     wxString    strDocumentText2 = wxEmptyString;
970     double       x = 0.0;
971     time_t      tDocumentTime = (time_t)0;
972     CWork*      work;
973 
974     strDocumentText.Empty();
975 
976      if (GetWorkCacheAtIndex(work, m_iSortedIndexes[iRowIndex])) {
977         return false;
978     }
979 
980     if (iColumnIndex < 0) return false;
981 
982     switch (m_iColumnIndexToColumnID[iColumnIndex]) {
983         case COLUMN_PROJECT:
984             GetDocProjectName(m_iSortedIndexes[iRowIndex], strDocumentText);
985             GetDocProjectURL(m_iSortedIndexes[iRowIndex], strDocumentText2);
986             if (!strDocumentText.IsSameAs(work->m_strProjectName) || !strDocumentText2.IsSameAs(work->m_strProjectURL)) {
987                 work->m_strProjectName = strDocumentText;
988                 work->m_strProjectURL = strDocumentText2;
989                 return true;
990             }
991             break;
992         case COLUMN_APPLICATION:
993             GetDocApplicationName(m_iSortedIndexes[iRowIndex], strDocumentText);
994             if (!strDocumentText.IsSameAs(work->m_strApplicationName)) {
995                 work->m_strApplicationName = strDocumentText;
996                 return true;
997             }
998             break;
999         case COLUMN_NAME:
1000             GetDocName(m_iSortedIndexes[iRowIndex], strDocumentText);
1001             if (!strDocumentText.IsSameAs(work->m_strName)) {
1002                 work->m_strName = strDocumentText;
1003                 return true;
1004             }
1005             break;
1006         case COLUMN_CPUTIME:
1007             GetDocCPUTime(m_iSortedIndexes[iRowIndex], x);
1008             if (x != work->m_fCPUTime) {
1009                 work->m_fCPUTime = x;
1010                 work->m_strCPUTime = FormatTime(x);
1011                 return true;
1012             }
1013             break;
1014         case COLUMN_PROGRESS:
1015             GetDocProgress(m_iSortedIndexes[iRowIndex], x);
1016             if (x != work->m_fProgress) {
1017                 work->m_fProgress = x;
1018                 FormatProgress(x, work->m_strProgress);
1019                 return true;
1020             }
1021             break;
1022         case COLUMN_TOCOMPLETION:
1023             GetDocTimeToCompletion(m_iSortedIndexes[iRowIndex], x);
1024             if (x != work->m_fTimeToCompletion) {
1025                 work->m_fTimeToCompletion = x;
1026                 work->m_strTimeToCompletion = FormatTime(x);
1027                 return true;
1028             }
1029             break;
1030         case COLUMN_REPORTDEADLINE:
1031             GetDocReportDeadline(m_iSortedIndexes[iRowIndex], tDocumentTime);
1032             if (tDocumentTime != work->m_tReportDeadline) {
1033                 work->m_tReportDeadline = tDocumentTime;
1034                 FormatReportDeadline(tDocumentTime, work->m_strReportDeadline);
1035                 return true;
1036             }
1037             break;
1038         case COLUMN_STATUS:
1039             int i = m_iSortedIndexes[iRowIndex];
1040             RESULT* result = wxGetApp().GetDocument()->result(i);
1041             strDocumentText = result_description(result);
1042             if (!strDocumentText.IsSameAs(work->m_strStatus)) {
1043                 work->m_strStatus = strDocumentText;
1044                 return true;
1045             }
1046             break;
1047     }
1048 
1049     return false;
1050 }
1051 
1052 
GetDocProjectName(wxInt32 item,wxString & strBuffer) const1053 void CViewWork::GetDocProjectName(wxInt32 item, wxString& strBuffer) const {
1054     CMainDocument* doc = wxGetApp().GetDocument();
1055     RESULT* result = wxGetApp().GetDocument()->result(item);
1056     PROJECT* state_project = NULL;
1057     std::string project_name;
1058 
1059     wxASSERT(doc);
1060     wxASSERT(wxDynamicCast(doc, CMainDocument));
1061 
1062     if (result) {
1063         // TODO: should we get the name directly with result->project->get_name(project_name) ?
1064         state_project = doc->state.lookup_project(result->project_url);
1065         if (state_project) {
1066             state_project->get_name(project_name);
1067             strBuffer = HtmlEntityDecode(wxString(project_name.c_str(), wxConvUTF8));
1068          } else {
1069             doc->ForceCacheUpdate();
1070         }
1071     }
1072 }
1073 
1074 
GetDocApplicationName(wxInt32 item,wxString & strBuffer) const1075 void CViewWork::GetDocApplicationName(wxInt32 item, wxString& strBuffer) const {
1076     CMainDocument* pDoc = wxGetApp().GetDocument();
1077     RESULT*        result = wxGetApp().GetDocument()->result(item);
1078     RESULT*        state_result = NULL;
1079     wxString       strAppBuffer = wxEmptyString;
1080     wxString       strClassBuffer = wxEmptyString;
1081 
1082     wxASSERT(pDoc);
1083     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
1084 
1085     if (result) {
1086         state_result = pDoc->state.lookup_result(result->project_url, result->name);
1087         if (!state_result) {
1088             pDoc->ForceCacheUpdate();
1089             state_result = pDoc->state.lookup_result(result->project_url, result->name);
1090         }
1091 
1092         if (!state_result) return;
1093         WORKUNIT* wup = state_result->wup;
1094         if (!wup) return;
1095         APP* app = wup->app;
1096         if (!app) return;
1097         APP_VERSION* avp = state_result->avp;
1098         if (!avp) return;
1099 
1100         if (strlen(app->user_friendly_name)) {
1101             strAppBuffer = HtmlEntityDecode(wxString(state_result->app->user_friendly_name, wxConvUTF8));
1102         } else {
1103             strAppBuffer = HtmlEntityDecode(wxString(state_result->avp->app_name, wxConvUTF8));
1104         }
1105 
1106         if (strlen(avp->plan_class)) {
1107             strClassBuffer.Printf(
1108                 wxT(" (%s)"),
1109                 wxString(avp->plan_class, wxConvUTF8).c_str()
1110             );
1111         }
1112 
1113         strBuffer.Printf(
1114             wxT(" %s%s %d.%02d %s"),
1115             state_result->project->anonymous_platform?_("Local: "):wxT(""),
1116             strAppBuffer.c_str(),
1117             state_result->avp->version_num / 100,
1118             state_result->avp->version_num % 100,
1119             strClassBuffer.c_str()
1120         );
1121     }
1122 }
1123 
1124 
GetDocName(wxInt32 item,wxString & strBuffer) const1125 void CViewWork::GetDocName(wxInt32 item, wxString& strBuffer) const {
1126     RESULT* result = wxGetApp().GetDocument()->result(item);
1127 
1128     if (result) {
1129         strBuffer = wxString(result->name, wxConvUTF8);
1130     }
1131 }
1132 
1133 
GetDocCPUTime(wxInt32 item,double & fBuffer) const1134 void CViewWork::GetDocCPUTime(wxInt32 item, double& fBuffer) const {
1135     RESULT*        result = wxGetApp().GetDocument()->result(item);
1136 
1137     fBuffer = 0;
1138     if (result) {
1139         if (result->active_task) {
1140             fBuffer = result->elapsed_time;
1141             if (!fBuffer) fBuffer = result->current_cpu_time;
1142         } else {
1143             if(result->state < RESULT_COMPUTE_ERROR) {
1144                 fBuffer = 0;
1145             } else {
1146                 fBuffer = result->final_elapsed_time;
1147                 if (!fBuffer) fBuffer = result->final_cpu_time;
1148             }
1149         }
1150     }
1151 }
1152 
GetDocProgress(wxInt32 item,double & fBuffer) const1153 void CViewWork::GetDocProgress(wxInt32 item, double& fBuffer) const {
1154     RESULT*        result = wxGetApp().GetDocument()->result(item);
1155 
1156     fBuffer = 0;
1157     if (result) {
1158         if (result->active_task) {
1159             fBuffer = floor(result->fraction_done * 100000)/1000;
1160         } else {
1161             if(result->state < RESULT_COMPUTE_ERROR) {
1162                 fBuffer = 0.0;
1163             } else {
1164                 fBuffer = 100.0;
1165             }
1166         }
1167     }
1168 }
1169 
1170 
FormatProgress(double fBuffer,wxString & strBuffer) const1171 wxInt32 CViewWork::FormatProgress(double fBuffer, wxString& strBuffer) const {
1172     strBuffer.Printf(wxT("%.3f%%"), fBuffer);
1173 
1174     return 0;
1175 }
1176 
1177 
GetDocTimeToCompletion(wxInt32 item,double & fBuffer) const1178 void CViewWork::GetDocTimeToCompletion(wxInt32 item, double& fBuffer) const {
1179     RESULT*        result = wxGetApp().GetDocument()->result(item);
1180 
1181     fBuffer = 0;
1182     if (result) {
1183         fBuffer = result->estimated_cpu_time_remaining;
1184     }
1185 }
1186 
GetDocReportDeadline(wxInt32 item,time_t & time) const1187 void CViewWork::GetDocReportDeadline(wxInt32 item, time_t& time) const {
1188     RESULT*        result = wxGetApp().GetDocument()->result(item);
1189 
1190     if (result) {
1191         time = (time_t)result->report_deadline;
1192     } else {
1193         time = (time_t)0;
1194     }
1195 }
1196 
1197 
FormatReportDeadline(time_t deadline,wxString & strBuffer) const1198 wxInt32 CViewWork::FormatReportDeadline(time_t deadline, wxString& strBuffer) const {
1199 #ifdef __WXMAC__
1200     // Work around a wxCocoa bug(?) in wxDateTime::Format()
1201     char buf[80];
1202     struct tm * timeinfo = localtime(&deadline);
1203     strftime(buf, sizeof(buf), "%c", timeinfo);
1204     strBuffer = buf;
1205 #else
1206     wxDateTime     dtTemp;
1207 
1208     dtTemp.Set(deadline);
1209     strBuffer = dtTemp.Format();
1210 #endif
1211 
1212     return 0;
1213 }
1214 
1215 
1216 
1217 
FormatStatus(wxInt32 item,wxString & strBuffer) const1218 wxInt32 CViewWork::FormatStatus(wxInt32 item, wxString& strBuffer) const {
1219     CWork*          work;
1220 
1221     try {
1222         work = m_WorkCache.at(m_iSortedIndexes[item]);
1223     } catch ( std::out_of_range ) {
1224         work = NULL;
1225     }
1226 
1227     if (work) {
1228         strBuffer = work->m_strStatus;
1229     } else {
1230         strBuffer = wxEmptyString;
1231     }
1232     return 0;
1233 }
1234 
1235 
GetDocProjectURL(wxInt32 item,wxString & strBuffer) const1236 void CViewWork::GetDocProjectURL(wxInt32 item, wxString& strBuffer) const {
1237     RESULT* result = wxGetApp().GetDocument()->result(item);
1238 
1239     if (result) {
1240         strBuffer = wxString(result->project_url, wxConvUTF8);
1241     }
1242 }
1243 
1244 
GetProgressValue(long item)1245 double CViewWork::GetProgressValue(long item) {
1246     double          fBuffer = 0;
1247     RESULT*        result = wxGetApp().GetDocument()->result(m_iSortedIndexes[item]);
1248 
1249     if (result) {
1250         if (result->active_task) {
1251             fBuffer = result->fraction_done;
1252         } else {
1253             if(result->state < RESULT_COMPUTE_ERROR) {
1254                 fBuffer = 0.0;
1255             } else {
1256                 fBuffer = 1.0;
1257             }
1258         }
1259     }
1260     if (fBuffer > 1) fBuffer = 1;
1261 
1262     return fBuffer;
1263 }
1264 
1265 
GetProgressText(long item)1266 wxString CViewWork::GetProgressText( long item) {
1267     CWork*    work      = NULL;
1268     wxString  strBuffer = wxEmptyString;
1269 
1270     if (GetWorkCacheAtIndex(work, m_iSortedIndexes[item])) {
1271         strBuffer = wxEmptyString;
1272     } else {
1273         strBuffer = work->m_strProgress;
1274     }
1275 
1276     return strBuffer;
1277 }
1278 
1279 
GetWorkCacheAtIndex(CWork * & workPtr,int index)1280 int CViewWork::GetWorkCacheAtIndex(CWork*& workPtr, int index) {
1281     try {
1282         workPtr = m_WorkCache.at(index);
1283     } catch ( std::out_of_range ) {
1284         workPtr = NULL;
1285         return -1;
1286     }
1287 
1288     return 0;
1289 }
1290 
1291