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