boinc/clientgui/ViewWorkGrid.cpp

1060 lines
34 KiB
C++

// Berkeley Open Infrastructure for Network Computing
// http://boinc.berkeley.edu
// Copyright (C) 2005 University of California
//
// This is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation;
// either version 2.1 of the License, or (at your option) any later version.
//
// This software is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Lesser General Public License for more details.
//
// To view the GNU Lesser General Public License visit
// http://www.gnu.org/copyleft/lesser.html
// or write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#if defined(__GNUG__) && !defined(__APPLE__)
#pragma implementation "ViewWorkGrid.h"
#endif
#include "stdwx.h"
#include "util.h"
#include "BOINCGUIApp.h"
#include "BOINCBaseFrame.h"
#include "MainDocument.h"
#include "AdvancedFrame.h"
#include "BOINCTaskCtrl.h"
#include "ViewWorkGrid.h"
#include "Events.h"
#include "error_numbers.h"
#include "res/result.xpm"
using std::string;
#define COLUMN_PROJECT 0
#define COLUMN_APPLICATION 1
#define COLUMN_NAME 2
#define COLUMN_CPUTIME 3
#define COLUMN_PROGRESS 4
#define COLUMN_TOCOMPLETION 5
#define COLUMN_REPORTDEADLINE 6
#define COLUMN_STATUS 7
#define COLUMN_HIDDEN_URL 8
#define COLUMN_RESULTS_INDEX 9
#define NUM_COLUMNS (COLUMN_RESULTS_INDEX+1)
// groups that contain buttons
#define GRP_TASKS 0
#define GRP_WEBSITES 1
// buttons in the "tasks" area
#define BTN_GRAPHICS 0
#define BTN_SUSPEND 1
#define BTN_ABORT 2
IMPLEMENT_DYNAMIC_CLASS(CViewWorkGrid, CBOINCBaseView)
BEGIN_EVENT_TABLE (CViewWorkGrid, CBOINCBaseView)
EVT_BUTTON(ID_TASK_WORK_SUSPEND, CViewWorkGrid::OnWorkSuspend)
EVT_BUTTON(ID_TASK_WORK_SHOWGRAPHICS, CViewWorkGrid::OnWorkShowGraphics)
EVT_BUTTON(ID_TASK_WORK_ABORT, CViewWorkGrid::OnWorkAbort)
EVT_CUSTOM_RANGE(wxEVT_COMMAND_BUTTON_CLICKED, ID_TASK_PROJECT_WEB_PROJDEF_MIN, ID_TASK_PROJECT_WEB_PROJDEF_MAX, CViewWorkGrid::OnProjectWebsiteClicked)
EVT_GRID_SELECT_CELL(CViewWorkGrid::OnGridSelectCell)
EVT_GRID_RANGE_SELECT(CViewWorkGrid::OnGridSelectRange)
#if PREVENT_MULTIPLE_TASK_SELECTIONS
EVT_GRID_CELL_LEFT_CLICK(CViewWorkGrid::OnCellLeftClick)
#endif
END_EVENT_TABLE ()
CViewWorkGrid::CViewWorkGrid()
{
}
CViewWorkGrid::CViewWorkGrid(wxNotebook* pNotebook) :
CBOINCBaseView(pNotebook)
{
//
// Setup View
//
wxFlexGridSizer* itemFlexGridSizer = new wxFlexGridSizer(2, 0, 0);
wxASSERT(itemFlexGridSizer);
itemFlexGridSizer->AddGrowableRow(0);
itemFlexGridSizer->AddGrowableCol(1);
m_pTaskPane = new CBOINCTaskCtrl(this, ID_TASK_WORKGRIDVIEW, DEFAULT_TASK_FLAGS);
wxASSERT(m_pTaskPane);
m_pGridPane = new CBOINCGridCtrl(this, ID_LIST_WORKGRIDVIEW);
wxASSERT(m_pGridPane);
itemFlexGridSizer->Add(m_pTaskPane, 1, wxGROW|wxALL, 1);
itemFlexGridSizer->Add(m_pGridPane, 1, wxGROW|wxALL, 1);
SetSizer(itemFlexGridSizer);
Layout();
// Setup TaskPane
CTaskItemGroup* pGroup = NULL;
CTaskItem* pItem = NULL;
pGroup = new CTaskItemGroup( _("Commands") );
m_TaskGroups.push_back( pGroup );
pItem = new CTaskItem(
_("Show graphics"),
_("Show application graphics in a window."),
ID_TASK_WORK_SHOWGRAPHICS
);
pGroup->m_Tasks.push_back( pItem );
pItem = new CTaskItem(
_("Suspend"),
_("Suspend work for this result."),
ID_TASK_WORK_SUSPEND
);
pGroup->m_Tasks.push_back( pItem );
pItem = new CTaskItem(
_("Abort"),
_("Abandon work on the result. "
"You will get no credit for it."),
ID_TASK_WORK_ABORT
);
pGroup->m_Tasks.push_back( pItem );
// Create Task Pane Items
m_pTaskPane->UpdateControls();
// Create Grid (one dummy row is needed)
m_pGridPane->Setup();
m_pGridPane->SetTable(new CBOINCGridTable(1,NUM_COLUMNS));
//don't use wxGrid->Create() here !!!!
m_pGridPane->SetSelectionMode(wxGrid::wxGridSelectRows);
// init grid columns
wxInt32 colSizes[] = {125,95,285,80,60,100,150,135,0,0};
wxString colTitles[] = {_("Project"),_("Application"),_("Name"),_("CPU time"),
_("Progress"),_("To completion"),_("Report deadline"),
_("Status"),wxEmptyString,wxEmptyString
};
for(int i=0; i< NUM_COLUMNS;i++){
m_pGridPane->SetColLabelValue(i,colTitles[i]);
m_pGridPane->SetColSize(i,colSizes[i]);
}
// set alignment for cpu time column to right
m_pGridPane->SetColAlignment(COLUMN_CPUTIME,wxALIGN_RIGHT,wxALIGN_CENTER);
// set alignment for completion column to right
m_pGridPane->SetColAlignment(COLUMN_TOCOMPLETION,wxALIGN_RIGHT,wxALIGN_CENTER);
//change the default cell renderer
m_pGridPane->SetDefaultRenderer(new CBOINCGridCellProgressRenderer(COLUMN_PROGRESS));
//set column sort types
m_pGridPane->SetColumnSortType(COLUMN_PROGRESS,CST_FLOAT);
m_pGridPane->SetColumnSortType(COLUMN_CPUTIME,CST_TIME);
m_pGridPane->SetColumnSortType(COLUMN_TOCOMPLETION,CST_TIME);
m_pGridPane->SetColumnSortType(COLUMN_REPORTDEADLINE,CST_DATETIME);
m_pGridPane->SetColumnSortType(COLUMN_RESULTS_INDEX,CST_LONG);
//set primary key column index
m_pGridPane->SetPrimaryKeyColumns(COLUMN_NAME,COLUMN_HIDDEN_URL);
// Hide the Index and URL columns
int min_width = m_pGridPane->GetColMinimalAcceptableWidth();
m_pGridPane->SetColMinimalAcceptableWidth(0);
m_pGridPane->SetColSize(COLUMN_HIDDEN_URL,0);
m_pGridPane->SetColSize(COLUMN_RESULTS_INDEX,0);
m_pGridPane->SetColMinimalAcceptableWidth(min_width);
UpdateSelection();
}
CViewWorkGrid::~CViewWorkGrid() {
EmptyTasks();
}
wxString& CViewWorkGrid::GetViewName() {
static wxString strViewName(_("TasksGrid"));
return strViewName;
}
wxString& CViewWorkGrid::GetViewDisplayName() {
static wxString strViewName(_("Tasks"));
return strViewName;
}
const char** CViewWorkGrid::GetViewIcon() {
return result_xpm;
}
void CViewWorkGrid::OnWorkSuspend( wxCommandEvent& WXUNUSED(event) ) {
wxLogTrace(wxT("Function Start/End"), wxT("CViewWorkGrid::OnWorkSuspend - Function Begin"));
CMainDocument* pDoc = wxGetApp().GetDocument();
CAdvancedFrame* pFrame = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
int i, n;
wxASSERT(pDoc);
wxASSERT(wxDynamicCast(pDoc, CMainDocument));
wxASSERT(pFrame);
wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
wxASSERT(m_pGridPane);
wxArrayInt arrSelRows = m_pGridPane->GetSelectedRows2();
n = (int)arrSelRows.GetCount();
for(i=0; i<n; i++) {
wxString resultName = m_pGridPane->GetCellValue(arrSelRows[i],COLUMN_NAME).Trim(false);
wxString projectURL = m_pGridPane->GetCellValue(arrSelRows[i],COLUMN_HIDDEN_URL).Trim(false);
RESULT* result = pDoc->result(resultName, projectURL);
if (result->suspended_via_gui) {
pFrame->UpdateStatusText(_("Resuming task..."));
pDoc->WorkResume(result->project_url, result->name);
} else {
pFrame->UpdateStatusText(_("Suspending task..."));
pDoc->WorkSuspend(result->project_url, result->name);
}
}
pFrame->UpdateStatusText(wxT(""));
UpdateSelection();
pFrame->FireRefreshView();
wxLogTrace(wxT("Function Start/End"), wxT("CViewWorkGrid::OnWorkSuspend - Function End"));
}
void CViewWorkGrid::OnWorkShowGraphics( wxCommandEvent& WXUNUSED(event) ) {
wxLogTrace(wxT("Function Start/End"), wxT("CViewWorkGrid::OnWorkShowGraphics - Function Begin"));
wxInt32 iAnswer = 0;
wxString strMachineName = wxEmptyString;
CMainDocument* pDoc = wxGetApp().GetDocument();
CAdvancedFrame* pFrame = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
int i, n;
wxASSERT(pDoc);
wxASSERT(wxDynamicCast(pDoc, CMainDocument));
wxASSERT(pFrame);
wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
wxASSERT(m_pGridPane);
pFrame->UpdateStatusText(_("Showing graphics for task..."));
// TODO: implement hide as well as show
#if (defined(_WIN32) || defined(__WXMAC__))
pDoc->GetConnectedComputerName(strMachineName);
if (!pDoc->IsComputerNameLocal(strMachineName)) {
iAnswer = ::wxMessageBox(
_("Are you sure you want to display graphics on a remote machine?"),
_("Show graphics"),
wxYES_NO | wxICON_QUESTION,
this
);
} else {
iAnswer = wxYES;
}
#else
iAnswer = wxYES;
#endif
if (wxYES == iAnswer) {
wxArrayInt arrSelRows = m_pGridPane->GetSelectedRows2();
n = (int)arrSelRows.GetCount();
for(i=0; i<n; i++) {
wxString resultName = m_pGridPane->GetCellValue(arrSelRows[i],COLUMN_NAME).Trim(false);
wxString projectURL = m_pGridPane->GetCellValue(arrSelRows[i],COLUMN_HIDDEN_URL).Trim(false);
RESULT* result = pDoc->result(resultName, projectURL);
pDoc->WorkShowGraphics(result);
}
}
pFrame->UpdateStatusText(wxT(""));
UpdateSelection();
pFrame->FireRefreshView();
wxLogTrace(wxT("Function Start/End"), wxT("CViewWorkGrid::OnWorkShowGraphics - Function End"));
}
void CViewWorkGrid::OnWorkAbort( wxCommandEvent& WXUNUSED(event) ) {
wxLogTrace(wxT("Function Start/End"), wxT("CViewWorkGrid::OnWorkAbort - Function Begin"));
wxInt32 iAnswer = 0;
//wxInt32 iResult = 0;
wxString strMessage = wxEmptyString;
wxString strName = wxEmptyString;
wxString strProgress = wxEmptyString;
wxString strStatus = wxEmptyString;
CMainDocument* pDoc = wxGetApp().GetDocument();
CAdvancedFrame* pFrame = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
int i, n;
wxASSERT(pDoc);
wxASSERT(pFrame);
wxASSERT(wxDynamicCast(pDoc, CMainDocument));
wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
wxASSERT(m_pTaskPane);
wxASSERT(m_pGridPane);
if (!pDoc->IsUserAuthorized())
return;
pFrame->UpdateStatusText(_("Aborting result..."));
wxArrayInt arrSelRows = m_pGridPane->GetSelectedRows2();
n = (int)arrSelRows.GetCount();
for(i=0; i<n; i++) {
strName = m_pGridPane->GetCellValue(arrSelRows[i],COLUMN_NAME).Trim(false);
strProgress = m_pGridPane->GetCellValue(arrSelRows[i],COLUMN_PROGRESS).Trim(false);
strStatus = m_pGridPane->GetCellValue(arrSelRows[i],COLUMN_STATUS).Trim(false);
//FormatName(iResult, strName);
//FormatProgress(iResult, strProgress);
//FormatStatus(iResult, strStatus);
strMessage.Printf(
_("Are you sure you want to abort this task '%s'?\n"
"(Progress: %s %%, Status: %s)"),
strName.c_str(),
strProgress.c_str(),
strStatus.c_str()
);
iAnswer = ::wxMessageBox(
strMessage,
_("Abort task"),
wxYES_NO | wxICON_QUESTION,
this
);
if (wxYES == iAnswer) {
wxString projectURL = m_pGridPane->GetCellValue(arrSelRows[i],COLUMN_HIDDEN_URL).Trim(false);
std::string resultNameStr = (const char*)strName.mb_str();
std::string projectURLStr = (const char*)projectURL.mb_str();
pDoc->WorkAbort(projectURLStr, resultNameStr);
}
}
pFrame->UpdateStatusText(wxT(""));
UpdateSelection();
pFrame->FireRefreshView();
wxLogTrace(wxT("Function Start/End"), wxT("CViewWorkGrid::OnWorkAbort - Function End"));
}
void CViewWorkGrid::OnProjectWebsiteClicked( wxEvent& event ) {
wxLogTrace(wxT("Function Start/End"), wxT("CViewWorkGrid::OnProjectWebsiteClicked - Function Begin"));
CAdvancedFrame* pFrame = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
wxASSERT(pFrame);
wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
wxASSERT(m_pTaskPane);
wxASSERT(m_pGridPane);
pFrame->UpdateStatusText(_("Launching browser..."));
int website_task_index = event.GetId() - ID_TASK_PROJECT_WEB_PROJDEF_MIN;
pFrame->ExecuteBrowserLink(
m_TaskGroups[1]->m_Tasks[website_task_index]->m_strWebSiteLink
);
pFrame->UpdateStatusText(wxT(""));
UpdateSelection();
pFrame->FireRefreshView();
wxLogTrace(wxT("Function Start/End"), wxT("CViewWorkGrid::OnProjectWebsiteClicked - Function End"));
}
#if PREVENT_MULTIPLE_TASK_SELECTIONS
void CViewWorkGrid::OnGridSelectRange( wxGridRangeSelectEvent& event ) {
// Disallow multiple selections
if (m_pGridPane->GetSelectedRows2().size() > 1) {
int theRow = event.GetBottomRow();
m_pGridPane->ClearSelection();
m_pGridPane->SelectRow(theRow);
}
CBOINCBaseView::OnGridSelectRange(event);
}
void CViewWorkGrid::OnCellLeftClick( wxGridEvent& event ) {
// Disallow multiple selections
int theRow = event.GetRow();
m_pGridPane->ClearSelection();
m_pGridPane->SelectRow(theRow);
}
#endif
void CViewWorkGrid::UpdateSelection() {
CTaskItemGroup* pGroup = NULL;
RESULT* result = NULL;
PROJECT* project = NULL;
CC_STATUS status;
CMainDocument* pDoc = wxGetApp().GetDocument();
int i, n;
bool wasSuspended=false, all_same_project=false;
string first_project_url;
wxASSERT(NULL != pDoc);
wxASSERT(wxDynamicCast(pDoc, CMainDocument));
wxASSERT(NULL != m_pTaskPane);
CBOINCBaseView::PreUpdateSelection();
pGroup = m_TaskGroups[0];
wxArrayInt arrSelRows = m_pGridPane->GetSelectedRows2();
n = (int)arrSelRows.GetCount();
if (n > 0) {
m_pTaskPane->EnableTaskGroupTasks(pGroup);
pDoc->GetCoreClientStatus(status);
if (status.task_suspend_reason & ~(SUSPEND_REASON_CPU_USAGE_LIMIT)) {
m_pTaskPane->DisableTask(pGroup->m_Tasks[BTN_GRAPHICS]);
}
} else {
m_pTaskPane->DisableTaskGroupTasks(pGroup);
}
for(i=0; i<n; i++) {
wxString resultName = m_pGridPane->GetCellValue(arrSelRows[i],COLUMN_NAME).Trim(false);
wxString projectURL = m_pGridPane->GetCellValue(arrSelRows[i],COLUMN_HIDDEN_URL).Trim(false);
result = pDoc->result(resultName, projectURL);
if (result) {
if (i == 0) {
wasSuspended = result->suspended_via_gui;
if (result->suspended_via_gui) {
m_pTaskPane->UpdateTask(
pGroup->m_Tasks[BTN_SUSPEND],
_("Resume"),
_("Resume work for this task.")
);
} else {
m_pTaskPane->UpdateTask(
pGroup->m_Tasks[BTN_SUSPEND],
_("Suspend"),
_("Suspend work for this task.")
);
}
} else {
if (wasSuspended != result->suspended_via_gui) {
// Disable Suspend / Resume button if the multiple selection
// has a mix of suspended and not suspended tasks
m_pTaskPane->DisableTask(pGroup->m_Tasks[BTN_SUSPEND]);
}
}
// Disable Show Graphics button if any selected task can't display graphics
if (((!result->supports_graphics) || pDoc->GetState()->executing_as_daemon)
&& result->graphics_exec_path.empty()
) {
m_pTaskPane->DisableTask(pGroup->m_Tasks[BTN_GRAPHICS]);
}
if (result->suspended_via_gui || result->project_suspended_via_gui) {
m_pTaskPane->DisableTask(pGroup->m_Tasks[BTN_GRAPHICS]);
}
// Disable Abort button if any selected task already aborted
if (
result->active_task_state == PROCESS_ABORT_PENDING ||
result->active_task_state == PROCESS_ABORTED ||
result->state == RESULT_ABORTED
) {
m_pTaskPane->DisableTask(pGroup->m_Tasks[BTN_ABORT]);
}
if (i == 0) {
first_project_url = result->project_url;
all_same_project = true;
} else {
if (first_project_url != result->project_url) {
all_same_project = false;
}
}
}
}
if (all_same_project) {
project = pDoc->state.lookup_project(result->project_url);
UpdateWebsiteSelection(GRP_WEBSITES, project);
if(m_TaskGroups.size()>1) {
m_pTaskPane->EnableTaskGroupTasks(m_TaskGroups[1]);
}
} else {
UpdateWebsiteSelection(GRP_WEBSITES, NULL);
if(m_TaskGroups.size()>1) {
m_pTaskPane->DisableTaskGroupTasks(m_TaskGroups[1]);
}
}
CBOINCBaseView::PostUpdateSelection();
}
void CViewWorkGrid::UpdateWebsiteSelection(long lControlGroup, PROJECT* project){
unsigned int i;
CTaskItemGroup* pGroup = NULL;
CTaskItem* pItem = NULL;
wxASSERT(m_pTaskPane);
wxASSERT(m_pGridPane);
// Update the websites list
//
if (m_bForceUpdateSelection) {
if (m_TaskGroups.size() > 1) {
// Delete task group, objects, and controls.
pGroup = m_TaskGroups[lControlGroup];
m_pTaskPane->DeleteTaskGroupAndTasks(pGroup);
for (i=0; i<pGroup->m_Tasks.size(); i++) {
delete pGroup->m_Tasks[i];
}
pGroup->m_Tasks.clear();
delete pGroup;
pGroup = NULL;
m_TaskGroups.erase( m_TaskGroups.begin() + 1 );
}
// If something is selected create the tasks and controls
if (m_pGridPane->GetFirstSelectedRow()>=0) {
if (project) {
// Create the web sites task group
pGroup = new CTaskItemGroup( _("Web sites") );
m_TaskGroups.push_back( pGroup );
// Default project url
pItem = new CTaskItem(
wxString(project->project_name.c_str(), wxConvUTF8),
wxT(""),
wxString(project->master_url.c_str(), wxConvUTF8),
ID_TASK_PROJECT_WEB_PROJDEF_MIN
);
pGroup->m_Tasks.push_back(pItem);
// Project defined urls
for (i=0;(i<project->gui_urls.size())&&(i<=ID_TASK_PROJECT_WEB_PROJDEF_MAX);i++) {
pItem = new CTaskItem(
wxGetTranslation(wxString(project->gui_urls[i].name.c_str(), wxConvUTF8)),
wxGetTranslation(wxString(project->gui_urls[i].description.c_str(), wxConvUTF8)),
wxString(project->gui_urls[i].url.c_str(), wxConvUTF8),
ID_TASK_PROJECT_WEB_PROJDEF_MIN + 1 + i
);
pGroup->m_Tasks.push_back(pItem);
}
}
}
m_bForceUpdateSelection = false;
}
}
wxInt32 CViewWorkGrid::FormatProjectName(wxInt32 item, wxString& strBuffer) const {
CMainDocument* doc = wxGetApp().GetDocument();
RESULT* result = wxGetApp().GetDocument()->result(item);
PROJECT* state_project = NULL;
std::string project_name;
wxASSERT(doc);
wxASSERT(wxDynamicCast(doc, CMainDocument));
if (result) {
state_project = doc->state.lookup_project(result->project_url);
if (state_project) {
state_project->get_name(project_name);
strBuffer = wxT(" ") + HtmlEntityDecode(wxString(project_name.c_str(), wxConvUTF8));
} else {
doc->ForceCacheUpdate();
}
}
return 0;
}
wxInt32 CViewWorkGrid::FormatApplicationName(wxInt32 item, wxString& strBuffer) const {
CMainDocument* pDoc = wxGetApp().GetDocument();
RESULT* result = wxGetApp().GetDocument()->result(item);
RESULT* state_result = NULL;
wxString strLocalBuffer;
wxASSERT(pDoc);
wxASSERT(wxDynamicCast(pDoc, CMainDocument));
if (result) {
state_result = pDoc->state.lookup_result(result->project_url, result->name);
if (!state_result) {
pDoc->ForceCacheUpdate();
state_result = pDoc->state.lookup_result(result->project_url, result->name);
}
wxASSERT(state_result);
wxString strLocale = wxString(setlocale(LC_NUMERIC, NULL), wxConvUTF8);
setlocale(LC_NUMERIC, "C");
if (state_result->wup->app->user_friendly_name.size()) {
strLocalBuffer = HtmlEntityDecode(wxString(state_result->app->user_friendly_name.c_str(), wxConvUTF8));
} else {
strLocalBuffer = HtmlEntityDecode(wxString(state_result->wup->avp->app_name.c_str(), wxConvUTF8));
}
char buf[256];
if (state_result->wup->avp->plan_class.size()) {
sprintf(buf, " (%s)", state_result->wup->avp->plan_class.c_str());
} else {
strcpy(buf, "");
}
strBuffer.Printf(
wxT(" %s %.2f%s"),
strLocalBuffer.c_str(),
state_result->wup->avp->version_num/100.0,
buf
);
setlocale(LC_NUMERIC, (const char*)strLocale.mb_str());
}
return 0;
}
wxInt32 CViewWorkGrid::FormatName(wxInt32 item, wxString& strBuffer) const {
RESULT* result = wxGetApp().GetDocument()->result(item);
wxASSERT(result);
if (result) {
strBuffer = _T(" ") + wxString(result->name.c_str(), wxConvUTF8);
}
return 0;
}
wxInt32 CViewWorkGrid::FormatCPUTime(wxInt32 item, wxString& strBuffer) const {
float fBuffer = 0;
wxInt32 iHour = 0;
wxInt32 iMin = 0;
wxInt32 iSec = 0;
wxTimeSpan ts;
RESULT* result = wxGetApp().GetDocument()->result(item);
if (result) {
if (result->active_task) {
fBuffer = result->current_cpu_time;
} else {
if(result->state < RESULT_COMPUTE_ERROR) {
fBuffer = 0;
} else {
fBuffer = result->final_cpu_time;
}
}
}
if (0 == fBuffer) {
strBuffer = wxT("---");
} else {
iHour = (wxInt32)(fBuffer / (60 * 60));
iMin = (wxInt32)(fBuffer / 60) % 60;
iSec = (wxInt32)(fBuffer) % 60;
ts = wxTimeSpan(iHour, iMin, iSec);
strBuffer = wxT(" ") + ts.Format();
}
return 0;
}
wxInt32 CViewWorkGrid::FormatProgress(wxInt32 item, wxString& strBuffer) const {
float fBuffer = 0;
RESULT* result = wxGetApp().GetDocument()->result(item);
if (result) {
if (result->active_task) {
fBuffer = floor(result->fraction_done * 100000)/1000;
} else {
if(result->state < RESULT_COMPUTE_ERROR) {
fBuffer = 0.0;
} else {
fBuffer = 100.0;
}
}
}
strBuffer.Printf(wxT("%.3f"), fBuffer);
return 0;
}
wxInt32 CViewWorkGrid::FormatTimeToCompletion(wxInt32 item, wxString& strBuffer) const {
float fBuffer = 0;
wxInt32 iHour = 0;
wxInt32 iMin = 0;
wxInt32 iSec = 0;
wxTimeSpan ts;
RESULT* result = wxGetApp().GetDocument()->result(item);
if (result) {
fBuffer = result->estimated_cpu_time_remaining;
}
if (0 >= fBuffer) {
strBuffer = wxT("---");
} else {
iHour = (wxInt32)(fBuffer / (60 * 60));
iMin = (wxInt32)(fBuffer / 60) % 60;
iSec = (wxInt32)(fBuffer) % 60;
ts = wxTimeSpan(iHour, iMin, iSec);
strBuffer = wxT(" ") + ts.Format();
}
return 0;
}
wxInt32 CViewWorkGrid::FormatReportDeadline(wxInt32 item, wxString& strBuffer) const {
wxDateTime dtTemp;
RESULT* result = wxGetApp().GetDocument()->result(item);
if (result) {
dtTemp.Set((time_t)result->report_deadline);
//don't trust default date string representation, this could prevent correct sorting
strBuffer = dtTemp.Format(wxT(" %x %X"));
}
return 0;
}
wxInt32 CViewWorkGrid::FormatStatus(wxInt32 item, wxString& strBuffer) const {
CMainDocument* doc = wxGetApp().GetDocument();
RESULT* result = wxGetApp().GetDocument()->result(item);
CC_STATUS status;
wxASSERT(doc);
wxASSERT(wxDynamicCast(doc, CMainDocument));
doc->GetCoreClientStatus(status);
if (!result) return 0;
int throttled = status.task_suspend_reason & SUSPEND_REASON_CPU_USAGE_LIMIT;
switch(result->state) {
case RESULT_NEW:
strBuffer = _("New");
break;
case RESULT_FILES_DOWNLOADING:
if (result->ready_to_report) {
strBuffer = _("Download failed");
} else {
strBuffer = _("Downloading");
}
break;
case RESULT_FILES_DOWNLOADED:
if (result->project_suspended_via_gui) {
strBuffer = _("Project suspended by user");
} else if (result->suspended_via_gui) {
strBuffer = _("Task suspended by user");
} else if (status.task_suspend_reason && !throttled) {
strBuffer = _("Suspended");
if (status.task_suspend_reason & SUSPEND_REASON_BATTERIES) {
strBuffer += _(" - on batteries");
}
if (status.task_suspend_reason & SUSPEND_REASON_USER_ACTIVE) {
strBuffer += _(" - user active");
}
if (status.task_suspend_reason & SUSPEND_REASON_USER_REQ) {
strBuffer += _(" - computation suspended");
}
if (status.task_suspend_reason & SUSPEND_REASON_TIME_OF_DAY) {
strBuffer += _(" - time of day");
}
if (status.task_suspend_reason & SUSPEND_REASON_BENCHMARKS) {
strBuffer += _(" - CPU benchmarks");
}
if (status.task_suspend_reason & SUSPEND_REASON_DISK_SIZE) {
strBuffer += _(" - need disk space");
}
} else if (result->active_task) {
if (result->too_large) {
strBuffer = _("Waiting for memory");
} else if (result->needs_shmem) {
strBuffer = _("Waiting for shared memory");
} else if (result->scheduler_state == CPU_SCHED_SCHEDULED) {
if (result->edf_scheduled) {
strBuffer = _("Running, high priority");
} else {
strBuffer = _("Running");
}
#if 0
// doesn't work - result pointer not there
if (result->project->non_cpu_intensive) {
strBuffer += _(" (non-CPU-intensive)");
}
#endif
} else if (result->scheduler_state == CPU_SCHED_PREEMPTED) {
strBuffer = _("Waiting to run");
} else if (result->scheduler_state == CPU_SCHED_UNINITIALIZED) {
strBuffer = _("Ready to start");
}
} else {
strBuffer = _("Ready to start");
}
break;
case RESULT_COMPUTE_ERROR:
strBuffer = _("Computation error");
break;
case RESULT_FILES_UPLOADING:
if (result->ready_to_report) {
strBuffer = _("Upload failed");
} else {
strBuffer = _("Uploading");
}
break;
case RESULT_ABORTED:
switch(result->exit_status) {
case ERR_ABORTED_VIA_GUI:
strBuffer = _("Aborted by user");
break;
case ERR_ABORTED_BY_PROJECT:
strBuffer = _("Aborted by project");
break;
default:
strBuffer = _("Aborted");
}
break;
default:
if (result->got_server_ack) {
strBuffer = _("Acknowledged");
} else if (result->ready_to_report) {
strBuffer = _("Ready to report");
} else {
strBuffer.Format(_("Error: invalid state '%d'"), result->state);
}
break;
}
strBuffer = wxT(" ") + strBuffer;
return 0;
}
wxInt32 CViewWorkGrid::FormatProjectURL(wxInt32 item, wxString& strBuffer) const {
RESULT* result = wxGetApp().GetDocument()->result(item);
wxASSERT(result);
if (result) {
strBuffer = wxString(result->project_url.c_str(), wxConvUTF8);
}
return 0;
}
bool CViewWorkGrid::OnSaveState(wxConfigBase* pConfig) {
bool bReturnValue = true;
wxASSERT(pConfig);
wxASSERT(m_pTaskPane);
wxASSERT(m_pGridPane);
if (!m_pTaskPane->OnSaveState(pConfig)) {
bReturnValue = false;
}
if (!m_pGridPane->OnSaveState(pConfig)) {
bReturnValue = false;
}
return bReturnValue;
}
bool CViewWorkGrid::OnRestoreState(wxConfigBase* pConfig) {
wxASSERT(pConfig);
wxASSERT(m_pTaskPane);
wxASSERT(m_pGridPane);
if (!m_pTaskPane->OnRestoreState(pConfig)) {
return false;
}
if (!m_pGridPane->OnRestoreState(pConfig)) {
return false;
}
return true;
}
wxInt32 CViewWorkGrid::GetDocCount() {
return wxGetApp().GetDocument()->GetWorkCount();
}
void CViewWorkGrid::OnListRender( wxTimerEvent& WXUNUSED(event) ) {
wxInt32 docCount = GetDocCount();
// We haven't connected up to the CC yet, there is nothing to display, make sure
// everything is deleted.
if ( docCount <= 0 ) {
if ( m_pGridPane->GetNumberRows() ) {
m_pGridPane->DeleteRows(0, m_pGridPane->GetNumberRows());
m_bForceUpdateSelection = true;
UpdateSelection();
UpdateWebsiteSelection(GRP_WEBSITES, NULL);
}
return;
}
// flag for row count changes
bool rowCountChanged=false;
// Right-size the grid so that the number of rows matches
// the document state.
if(docCount != m_pGridPane->GetNumberRows()) {
if (docCount > m_pGridPane->GetNumberRows()) {
m_pGridPane->AppendRows(docCount - m_pGridPane->GetNumberRows());
rowCountChanged=true;
} else {
m_pGridPane->DeleteRows(0, m_pGridPane->GetNumberRows() - docCount);
rowCountChanged=true;
m_bForceUpdateSelection = true;
}
wxASSERT(docCount == m_pGridPane->GetNumberRows());
}
//init array to detect cell value changes
wxArrayInt arrColumnDataChanged;
for(int i=0; i< NUM_COLUMNS;i++) {
arrColumnDataChanged.Add(0);
}
//update cell values
wxString strBuffer;
int iMax = m_pGridPane->GetNumberRows();
if (rowCountChanged) {
for(int iRow = 0; iRow < iMax; iRow++) {
m_pGridPane->SetCellValue(iRow, COLUMN_RESULTS_INDEX, strBuffer.Format(wxT("%d"), iRow));
}
}
for(int iRow = 0; iRow < iMax; iRow++) {
long results_index;
(m_pGridPane->GetCellValue(iRow, COLUMN_RESULTS_INDEX)).ToLong(&results_index);
FormatProjectName(results_index, strBuffer);
if (m_pGridPane->GetCellValue(iRow, COLUMN_PROJECT) != strBuffer) {
m_pGridPane->SetCellValue(iRow, COLUMN_PROJECT, strBuffer);
arrColumnDataChanged[COLUMN_PROJECT]=1;
}
FormatApplicationName(results_index, strBuffer);
if (m_pGridPane->GetCellValue(iRow, COLUMN_APPLICATION) != strBuffer) {
m_pGridPane->SetCellValue(iRow, COLUMN_APPLICATION, strBuffer);
arrColumnDataChanged[COLUMN_APPLICATION]=1;
}
FormatName(results_index, strBuffer);
if (m_pGridPane->GetCellValue(iRow, COLUMN_NAME) != strBuffer) {
m_pGridPane->SetCellValue(iRow, COLUMN_NAME, strBuffer);
arrColumnDataChanged[COLUMN_NAME]=1;
}
FormatCPUTime(results_index, strBuffer);
if (m_pGridPane->GetCellValue(iRow, COLUMN_CPUTIME) != strBuffer) {
m_pGridPane->SetCellValue(iRow, COLUMN_CPUTIME, strBuffer);
arrColumnDataChanged[COLUMN_CPUTIME]=1;
}
FormatProgress(results_index, strBuffer);
if (m_pGridPane->GetCellValue(iRow, COLUMN_PROGRESS) != strBuffer) {
m_pGridPane->SetCellValue(iRow, COLUMN_PROGRESS, strBuffer);
m_pGridPane->SetCellAlignment(iRow, COLUMN_PROGRESS, wxALIGN_CENTRE, wxALIGN_CENTRE);
arrColumnDataChanged[COLUMN_PROGRESS]=1;
}
FormatTimeToCompletion(results_index, strBuffer);
if (m_pGridPane->GetCellValue(iRow, COLUMN_TOCOMPLETION) != strBuffer) {
m_pGridPane->SetCellValue(iRow, COLUMN_TOCOMPLETION, strBuffer);
arrColumnDataChanged[COLUMN_TOCOMPLETION]=1;
}
FormatReportDeadline(results_index, strBuffer);
if (m_pGridPane->GetCellValue(iRow, COLUMN_REPORTDEADLINE) != strBuffer) {
m_pGridPane->SetCellValue(iRow, COLUMN_REPORTDEADLINE, strBuffer);
arrColumnDataChanged[COLUMN_REPORTDEADLINE]=1;
}
strBuffer = wxEmptyString;
FormatStatus(results_index, strBuffer);
if (m_pGridPane->GetCellValue(iRow, COLUMN_STATUS) != strBuffer) {
m_pGridPane->SetCellValue(iRow, COLUMN_STATUS, strBuffer);
arrColumnDataChanged[COLUMN_STATUS]=1;
}
FormatProjectURL(results_index, strBuffer);
if (m_pGridPane->GetCellValue(iRow, COLUMN_HIDDEN_URL) != strBuffer) {
m_pGridPane->SetCellValue(iRow, COLUMN_HIDDEN_URL, strBuffer);
arrColumnDataChanged[COLUMN_HIDDEN_URL]=1;
}
}
//sort only
//1. if row count changed
//2. if sorting column has cell value changes
//3. if sort is enforced by user through label click
if( rowCountChanged ||
(arrColumnDataChanged[m_pGridPane->sortColumn]==1) ||
m_pGridPane->sortNeededByLabelClick)
{
wxArrayString ordered_indexes;
m_bIgnoreUIEvents = true;
m_pGridPane->SaveSelection();
m_bIgnoreUIEvents = false;
for(int iRow = 0; iRow < iMax; iRow++) {
ordered_indexes.Add(m_pGridPane->GetCellValue(iRow, COLUMN_RESULTS_INDEX));
}
m_pGridPane->SortData();
for(int iRow = 0; iRow < iMax; iRow++) {
if (ordered_indexes[iRow] != m_pGridPane->GetCellValue(iRow, COLUMN_RESULTS_INDEX)) {
// Refresh entire grid if sort order has changed
m_bIgnoreUIEvents = true;
m_pGridPane->RestoreSelection();
m_bIgnoreUIEvents = false;
m_pGridPane->ForceRefresh();
break;
}
}
}
UpdateSelection();
}