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