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 "ViewResources.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 "ViewResources.h"
30 #include "Events.h"
31 #include <wx/arrimpl.cpp>
32 #include "res/usage.xpm"
33
34 WX_DEFINE_OBJARRAY(wxArrayColour);
35
IMPLEMENT_DYNAMIC_CLASS(CViewResources,CBOINCBaseView)36 IMPLEMENT_DYNAMIC_CLASS(CViewResources, CBOINCBaseView)
37
38 BEGIN_EVENT_TABLE (CViewResources, CBOINCBaseView)
39 END_EVENT_TABLE ()
40
41
42 CViewResources::CViewResources()
43 {}
44
CViewResources(wxNotebook * pNotebook)45 CViewResources::CViewResources(wxNotebook* pNotebook) :
46 CBOINCBaseView(pNotebook)
47 {
48 m_BOINCwasEmpty=false;
49
50 wxGridSizer* itemGridSizer = new wxGridSizer(2, 0, 3);
51 wxASSERT(itemGridSizer);
52
53 // create pie chart ctrl for total disk usage
54 m_pieCtrlTotal = new wxPieCtrl(this, ID_PIECTRL_RESOURCEUTILIZATIONVIEWTOTAL, wxDefaultPosition, wxDefaultSize);
55 wxASSERT(m_pieCtrlTotal);
56
57 // setup the legend
58 m_pieCtrlTotal->SetTransparent(true);
59 m_pieCtrlTotal->SetHorLegendBorder(10);
60 m_pieCtrlTotal->SetLabelFont(*wxSWISS_FONT);
61 m_pieCtrlTotal->SetLabelColour(wxColour(0,0,0));
62 m_pieCtrlTotal->SetLabel(_("Total disk usage"));
63
64 // initialize pie control
65 m_pieCtrlTotal->m_Series.Clear();
66 wxPiePart CtrlTotalPart;
67 CtrlTotalPart.SetLabel(wxEmptyString);
68 CtrlTotalPart.SetValue(1);
69 CtrlTotalPart.SetColour(wxColour(255,255,255));
70 m_pieCtrlTotal->m_Series.Add(CtrlTotalPart);
71 m_pieCtrlTotal->Refresh();
72
73
74 // create pie chart ctrl for BOINC disk usage
75 m_pieCtrlBOINC = new wxPieCtrl(this, ID_PIECTRL_RESOURCEUTILIZATIONVIEW, wxDefaultPosition, wxDefaultSize);
76 wxASSERT(m_pieCtrlBOINC);
77
78 //setup the legend
79 m_pieCtrlBOINC->SetTransparent(true);
80 m_pieCtrlBOINC->SetHorLegendBorder(10);
81 m_pieCtrlBOINC->SetLabelFont(*wxSWISS_FONT);
82 m_pieCtrlBOINC->SetLabelColour(wxColour(0,0,0));
83 m_pieCtrlBOINC->SetLabel(_("Disk usage by BOINC projects"));
84
85 // initialize pie control
86 m_pieCtrlBOINC->m_Series.Clear();
87 wxPiePart CtrlBOINCPart;
88 CtrlBOINCPart.SetLabel(wxEmptyString);
89 CtrlBOINCPart.SetValue(1);
90 CtrlBOINCPart.SetColour(wxColour(255,255,255));
91 m_pieCtrlBOINC->m_Series.Add(CtrlBOINCPart);
92 m_pieCtrlBOINC->Refresh();
93
94 //init the flexGrid
95 itemGridSizer->Add(m_pieCtrlTotal, 1, wxGROW|wxALL,1);
96 itemGridSizer->Add(m_pieCtrlBOINC, 1, wxGROW|wxALL,1);
97
98 SetSizer(itemGridSizer);
99
100 UpdateSelection();
101 }
102
103
~CViewResources()104 CViewResources::~CViewResources() {
105 EmptyTasks();
106 }
107
108
GetViewName()109 wxString& CViewResources::GetViewName() {
110 static wxString strViewName(wxT("Disk"));
111 return strViewName;
112 }
113
114
GetViewDisplayName()115 wxString& CViewResources::GetViewDisplayName() {
116 static wxString strViewName(_("Disk"));
117 return strViewName;
118 }
119
120
GetViewIcon()121 const char** CViewResources::GetViewIcon() {
122 return usage_xpm;
123 }
124
125
GetViewRefreshRate()126 int CViewResources::GetViewRefreshRate() {
127 return 10;
128 }
129
130
GetViewCurrentViewPage()131 int CViewResources::GetViewCurrentViewPage() {
132 return VW_DISK;
133 }
134
135
UpdateSelection()136 void CViewResources::UpdateSelection() {
137 CBOINCBaseView::PreUpdateSelection();
138 }
139
140
FormatProjectName(PROJECT * project,wxString & strBuffer) const141 wxInt32 CViewResources::FormatProjectName(PROJECT* project, wxString& strBuffer) const {
142 CMainDocument* doc = wxGetApp().GetDocument();
143 std::string project_name;
144
145 wxASSERT(doc);
146 wxASSERT(wxDynamicCast(doc, CMainDocument));
147
148 if (project) {
149 PROJECT* state_project = doc->state.lookup_project(project->master_url);
150 if (state_project) {
151 state_project->get_name(project_name);
152 strBuffer = HtmlEntityDecode(wxString(project_name.c_str(), wxConvUTF8));
153 }
154 }
155
156 return 0;
157 }
158
159
OnSaveState(wxConfigBase *)160 bool CViewResources::OnSaveState(wxConfigBase* /*pConfig*/) {
161 return true;
162 }
163
OnRestoreState(wxConfigBase *)164 bool CViewResources::OnRestoreState(wxConfigBase* /*pConfig*/) {
165 return true;
166 }
167
OnListRender(wxTimerEvent & WXUNUSED (event))168 void CViewResources::OnListRender( wxTimerEvent& WXUNUSED(event) ) {
169 CMainDocument* pDoc = wxGetApp().GetDocument();
170 wxString diskspace;
171 static double project_total=0.0;
172 unsigned int i;
173
174 wxASSERT(pDoc);
175 wxASSERT(wxDynamicCast(pDoc, CMainDocument));
176
177 //get data for BOINC projects disk usage
178 pDoc->CachedDiskUsageUpdate();
179 pDoc->CachedStateUpdate();
180 bool refreshBOINC = false;
181 if (pDoc->disk_usage.projects.size()>0) {
182 m_BOINCwasEmpty=false;
183 //check for changes worth a refresh
184 if (pDoc->disk_usage.projects.size() != m_pieCtrlBOINC->m_Series.size()) {
185 refreshBOINC = true;
186 } else {
187 for (i=0; i<pDoc->disk_usage.projects.size(); i++) {
188 wxString oldValue;
189 wxString newValue;
190 FormatDiskSpace(pDoc->DiskUsageProject(i)->disk_usage, newValue);
191 FormatDiskSpace(m_pieCtrlBOINC->m_Series.Item(i).GetValue(), oldValue);
192 if(newValue.Cmp(oldValue)!=0) {
193 refreshBOINC = true;
194 break;
195 }
196 }
197 }
198 // only refresh when worthy changes
199 if (refreshBOINC) {
200 m_pieCtrlBOINC->m_Series.Clear();
201 project_total = 0;
202 for (i=0; i<pDoc->disk_usage.projects.size(); i++) {
203 //update data for boinc projects pie chart
204 PROJECT* project = pDoc->DiskUsageProject(i);
205 wxString projectname;
206 FormatProjectName(project, projectname);
207 FormatDiskSpace(project->disk_usage, diskspace);
208 double usage = project->disk_usage;
209 project_total += usage;
210 wxPiePart part;
211 part.SetLabel(projectname + wxT(": ") + diskspace);
212 part.SetValue(usage);
213 wxColour color;
214 color_cycle(i, pDoc->disk_usage.projects.size(), color);
215 part.SetColour(color);
216 m_pieCtrlBOINC->m_Series.Add(part);
217 }
218 m_pieCtrlBOINC->Refresh();
219 }
220 } else {
221 if(!m_BOINCwasEmpty) {
222 //paint an empty black pie
223 m_pieCtrlBOINC->m_Series.Clear();
224 wxPiePart part;
225 part.SetLabel(_("no projects: 0 bytes used"));
226 part.SetValue(1);
227 part.SetColour(wxColour(0,0,0));
228 m_pieCtrlBOINC->m_Series.Add(part);
229 m_pieCtrlBOINC->Refresh();
230 m_BOINCwasEmpty=true;
231 refreshBOINC=true;
232 }
233 }
234
235 // pDoc->disk_usage.d_allowed = 0;
236 // data for pie chart 2 (total disk usage)
237 //
238 bool refreshTotal=false;
239 double free = pDoc->disk_usage.d_free;
240 double total = pDoc->disk_usage.d_total;
241 if (m_pieCtrlTotal->m_Series.size()>0) {
242 wxString oldFree;
243 wxString newFree;
244 FormatDiskSpace(free, newFree);
245 FormatDiskSpace(m_pieCtrlTotal->m_Series.Item(0).GetValue(), oldFree);
246 if(oldFree.Cmp(newFree)!=0) {
247 refreshTotal=true;
248 }
249 } else {
250 refreshTotal=true;
251 }
252 if (refreshBOINC || refreshTotal) {
253 m_pieCtrlTotal->m_Series.Clear();
254 wxPiePart part;
255
256 // used by BOINC
257 double boinc_total = project_total + pDoc->disk_usage.d_boinc;
258 FormatDiskSpace(boinc_total, diskspace);
259 part.SetLabel(_("used by BOINC: ") + diskspace);
260 part.SetValue(boinc_total);
261 part.SetColour(wxColour(0,0,0));
262 m_pieCtrlTotal->m_Series.Add(part);
263
264 if (pDoc->disk_usage.d_allowed > 0) {
265 double avail = pDoc->disk_usage.d_allowed - boinc_total;
266 if (avail > 0) {
267 if (avail > free) avail = free;
268 FormatDiskSpace(avail, diskspace);
269 part.SetLabel(_("free, available to BOINC: ") + diskspace);
270 part.SetValue(avail);
271 part.SetColour(wxColour(128, 128, 128));
272 m_pieCtrlTotal->m_Series.Add(part);
273 } else {
274 avail = 0;
275 }
276 double not_avail = free - avail;
277 if (not_avail > 0) {
278 FormatDiskSpace(not_avail, diskspace);
279 part.SetLabel(_("free, not available to BOINC: ") + diskspace);
280 part.SetValue(not_avail);
281 part.SetColour(wxColour(238,238,238));
282 m_pieCtrlTotal->m_Series.Add(part);
283 }
284 } else {
285 // if d_allowed is zero, we must be talking to a pre-6.3 client.
286 // Just show free space
287 //
288 FormatDiskSpace(free, diskspace);
289 part.SetLabel(_("free: ") + diskspace);
290 part.SetValue(free);
291 part.SetColour(wxColour(238,238,238));
292 m_pieCtrlTotal->m_Series.Add(part);
293 }
294
295 // used by others
296 double used_by_others = total-boinc_total-free;
297 FormatDiskSpace(used_by_others, diskspace);
298 part.SetLabel(_("used by other programs: ") + diskspace);
299 part.SetValue(used_by_others);
300 part.SetColour(wxColour(192,192,192));
301 m_pieCtrlTotal->m_Series.Add(part);
302 m_pieCtrlTotal->Refresh();
303 }
304 }
305
FormatDiskSpace(double bytes,wxString & strBuffer) const306 wxInt32 CViewResources::FormatDiskSpace(double bytes, wxString& strBuffer) const {
307 double xTera = 1099511627776.0;
308 double xGiga = 1073741824.0;
309 double xMega = 1048576.0;
310 double xKilo = 1024.0;
311
312 if (bytes >= xTera) {
313 strBuffer.Printf(wxT("%0.2f TB"), bytes/xTera);
314 } else if (bytes >= xGiga) {
315 strBuffer.Printf(wxT("%0.2f GB"), bytes/xGiga);
316 } else if (bytes >= xMega) {
317 strBuffer.Printf(wxT("%0.2f MB"), bytes/xMega);
318 } else {
319 strBuffer.Printf(wxT("%0.2f KB"), bytes/xKilo);
320 }
321
322 return 0;
323 }
324
325