1 // This file is part of BOINC.
2 // http://boinc.berkeley.edu
3 // Copyright (C) 2015 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 "DlgAdvPreferences.h"
20 #endif
21 
22 #include "stdwx.h"
23 #include "BOINCGUIApp.h"
24 #include "MainDocument.h"
25 #include "BOINCBaseFrame.h"
26 #include "SkinManager.h"
27 #include "Events.h"
28 #include "error_numbers.h"
29 #include "version.h"
30 #include "DlgAdvPreferences.h"
31 
32 #include "res/usage.xpm"
33 #include "res/xfer.xpm"
34 #include "res/proj.xpm"
35 #include "res/clock.xpm"
36 #include "res/warning.xpm"
37 
38 
39 using std::string;
40 
IMPLEMENT_DYNAMIC_CLASS(CDlgAdvPreferences,wxDialog)41 IMPLEMENT_DYNAMIC_CLASS(CDlgAdvPreferences, wxDialog)
42 
43 BEGIN_EVENT_TABLE(CDlgAdvPreferences, wxDialog)
44     EVT_COMMAND_RANGE(ID_ADV_PREFS_START,ID_ADV_PREFS_LAST,wxEVT_COMMAND_CHECKBOX_CLICKED,CDlgAdvPreferences::OnHandleCommandEvent)
45     //buttons
46     EVT_BUTTON(wxID_OK,CDlgAdvPreferences::OnOK)
47     EVT_BUTTON(ID_HELPBOINC,CDlgAdvPreferences::OnHelp)
48     EVT_BUTTON(ID_BTN_CLEAR,CDlgAdvPreferences::OnClear)
49 END_EVENT_TABLE()
50 
51 /* Constructor */
52 CDlgAdvPreferences::CDlgAdvPreferences(wxWindow* parent) : CDlgAdvPreferencesBase(parent,ID_ANYDIALOG) {
53     m_arrTabPageIds.Add(ID_TABPAGE_PROC);
54     m_arrTabPageIds.Add(ID_TABPAGE_NET);
55     m_arrTabPageIds.Add(ID_TABPAGE_DISK);
56     m_arrTabPageIds.Add(ID_TABPAGE_SCHED);
57 
58     //setting tab page images (not handled by generated code)
59     int iImageIndex = 0;
60     wxImageList* pImageList = m_Notebook->GetImageList();
61     if (!pImageList) {
62         pImageList = new wxImageList(ADJUSTFORXDPI(16), ADJUSTFORYDPI(16), true, 0);
63         wxASSERT(pImageList != NULL);
64         m_Notebook->SetImageList(pImageList);
65     }
66     iImageIndex = pImageList->Add(GetScaledBitmapFromXPMData(proj_xpm));
67     m_Notebook->SetPageImage(0,iImageIndex);
68 
69     iImageIndex = pImageList->Add(GetScaledBitmapFromXPMData(xfer_xpm));
70     m_Notebook->SetPageImage(1,iImageIndex);
71 
72     iImageIndex = pImageList->Add(GetScaledBitmapFromXPMData(usage_xpm));
73     m_Notebook->SetPageImage(2,iImageIndex);
74 
75     iImageIndex = pImageList->Add(GetScaledBitmapFromXPMData(clock_xpm));
76     m_Notebook->SetPageImage(3,iImageIndex);
77 
78     //setting warning bitmap
79     if (m_bmpWarning) {
80         m_bmpWarning->SetBitmap(GetScaledBitmapFromXPMData(warning_xpm));
81     }
82 
83     wxCheckBox* proc_cb[] = {m_chkProcSunday,m_chkProcMonday,m_chkProcTuesday,m_chkProcWednesday,m_chkProcThursday,m_chkProcFriday,m_chkProcSaturday};
84     wxTextCtrl* proc_tstarts[] = {m_txtProcSundayStart,m_txtProcMondayStart,m_txtProcTuesdayStart,m_txtProcWednesdayStart,m_txtProcThursdayStart,m_txtProcFridayStart,m_txtProcSaturdayStart};
85     wxTextCtrl* proc_tstops[] = {m_txtProcSundayStop,m_txtProcMondayStop,m_txtProcTuesdayStop,m_txtProcWednesdayStop,m_txtProcThursdayStop,m_txtProcFridayStop,m_txtProcSaturdayStop};
86     wxCheckBox* net_cb[] = {m_chkNetSunday,m_chkNetMonday,m_chkNetTuesday,m_chkNetWednesday,m_chkNetThursday,m_chkNetFriday,m_chkNetSaturday};
87     wxTextCtrl* net_tstarts[] = {m_txtNetSundayStart,m_txtNetMondayStart,m_txtNetTuesdayStart,m_txtNetWednesdayStart,m_txtNetThursdayStart,m_txtNetFridayStart,m_txtNetSaturdayStart};
88     wxTextCtrl* net_tstops[] = {m_txtNetSundayStop,m_txtNetMondayStop,m_txtNetTuesdayStop,m_txtNetWednesdayStop,m_txtNetThursdayStop,m_txtNetFridayStop,m_txtNetSaturdayStop};
89     for (int i=0; i<7; ++i) {
90         procDayChks[i] = proc_cb[i];
91         procDayStartTxts[i] = proc_tstarts[i];
92         procDayStopTxts[i] = proc_tstops[i];
93         netDayChks[i] = net_cb[i];
94         netDayStartTxts[i] = net_tstarts[i];
95         netDayStopTxts[i] = net_tstops[i];
96     }
97 
98     // init special tooltips
99     SetSpecialTooltips();
100     //setting the validators for correct input handling
101     SetValidators();
102     //read in settings and initialize controls
103     ReadPreferenceSettings();
104 
105     lastErrorCtrl = NULL;
106     stdTextBkgdColor = *wxWHITE;
107 
108     if (! m_bOKToShow) return;
109 
110     // Get default preference values
111     defaultPrefs.enabled_defaults();
112     //
113     RestoreState();
114 
115 #ifdef __WXMSW__
116     int tabStart = 0, tabwidth = 0;
117     RECT r;
118     BOOL success = TabCtrl_GetItemRect(m_Notebook->GetHWND(), 0, &r);
119     if (success) {
120         tabStart = r.left;
121     }
122 
123     success = TabCtrl_GetItemRect(m_Notebook->GetHWND(), m_Notebook->GetPageCount()-1, &r);
124     if (success) {
125         tabwidth = r.right - tabStart + ADJUSTFORXDPI(4);
126     }
127     wxSize sz = m_Notebook->GetBestSize();
128     if (sz.x < tabwidth) {
129         sz.x = tabwidth;
130         m_Notebook->SetMinSize(sz);
131     }
132 #endif
133     Layout();
134     Fit();
135     Centre();
136 }
137 
138 /* destructor */
~CDlgAdvPreferences()139 CDlgAdvPreferences::~CDlgAdvPreferences() {
140     if (m_bOKToShow) {
141         SaveState();
142     }
143     delete m_vTimeValidator;
144 }
145 
146 /* set validators for input filtering purposes only */
SetValidators()147 void CDlgAdvPreferences::SetValidators() {
148     m_vTimeValidator = new wxTextValidator(wxFILTER_INCLUDE_CHAR_LIST);
149     m_vTimeValidator->SetCharIncludes(wxT("0123456789:"));
150 
151     // ######### proc usage page
152     m_txtProcUseProcessors->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
153     m_txtProcUseCPUTime->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
154 
155     m_txtProcIdleFor->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
156     m_txtMaxLoad->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
157 
158     m_txtNetConnectInterval->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
159     m_txtNetAdditionalDays->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
160     m_txtProcSwitchEvery->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
161     m_txtDiskWriteToDisk->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
162 
163     // ######### net usage page
164     m_txtNetDownloadRate->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
165     m_txt_daily_xfer_limit_mb->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
166     m_txt_daily_xfer_period_days->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
167     m_txtNetUploadRate->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
168 
169     // ######### disk and memory page
170     m_txtDiskMaxSpace->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
171     m_txtDiskLeastFree->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
172     m_txtDiskMaxOfTotal->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
173     m_txtMemoryMaxInUse->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
174     m_txtMemoryMaxOnIdle->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
175     m_txtDiskMaxSwap->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
176 
177     // ######### daily schedules page
178     m_txtProcEveryDayStart->SetValidator(*m_vTimeValidator);
179     m_txtProcEveryDayStop->SetValidator(*m_vTimeValidator);
180 
181     m_txtNetEveryDayStart->SetValidator(*m_vTimeValidator);
182     m_txtNetEveryDayStop->SetValidator(*m_vTimeValidator);
183 
184     for (int i=0; i<7; ++i) {
185         procDayStartTxts[i]->SetValidator(*m_vTimeValidator);
186         procDayStopTxts[i]->SetValidator(*m_vTimeValidator);
187         netDayStartTxts[i]->SetValidator(*m_vTimeValidator);
188         netDayStopTxts[i]->SetValidator(*m_vTimeValidator);
189     }
190 }
191 
192 /* some controls share the same tooltip, set them here */
SetSpecialTooltips()193 void CDlgAdvPreferences::SetSpecialTooltips() {
194     wxString procDaysTimeTT(PROC_DAY_OF_WEEK_TOOLTIP_TEXT);
195     wxString netDaysTimeTT(NET_DAY_OF_WEEK_TOOLTIP_TEXT);
196     for (int i=0; i<7; ++i) {
197         procDayChks[i]->SetToolTip(procDaysTimeTT);
198         procDayStartTxts[i]->SetToolTip(procDaysTimeTT);
199         procDayStopTxts[i]->SetToolTip(procDaysTimeTT);
200         netDayChks[i]->SetToolTip(netDaysTimeTT);
201         netDayStartTxts[i]->SetToolTip(netDaysTimeTT);
202         netDayStopTxts[i]->SetToolTip(netDaysTimeTT);
203     }
204 }
205 
206 /* saves selected tab page */
SaveState()207 bool CDlgAdvPreferences::SaveState() {
208     wxString        strBaseConfigLocation = wxString(wxT("/DlgAdvPreferences/"));
209     wxConfigBase*   pConfig = wxConfigBase::Get(FALSE);
210 
211     wxASSERT(pConfig);
212     if (!pConfig) return false;
213 
214     pConfig->SetPath(strBaseConfigLocation);
215     pConfig->Write(wxT("CurrentPage"),m_Notebook->GetSelection());
216 
217     pConfig->Flush();
218 
219     return true;
220 }
221 
222 /* restores former selected tab page */
RestoreState()223 bool CDlgAdvPreferences::RestoreState() {
224     wxString        strBaseConfigLocation = wxString(wxT("/DlgAdvPreferences/"));
225     wxConfigBase*   pConfig = wxConfigBase::Get(FALSE);
226     int                p;
227 
228     wxASSERT(pConfig);
229 
230     if (!pConfig) return false;
231 
232     pConfig->SetPath(strBaseConfigLocation);
233 
234     pConfig->Read(wxT("CurrentPage"), &p,0);
235     m_Notebook->SetSelection(p);
236 
237     return true;
238 }
239 
240 // convert a Timestring HH:MM into a double
TimeStringToDouble(wxString timeStr)241 double CDlgAdvPreferences::TimeStringToDouble(wxString timeStr) {
242     double hour;
243     double minutes;
244     timeStr.SubString(0,timeStr.First(':')).ToDouble(&hour);
245     timeStr.SubString(timeStr.First(':')+1,timeStr.Length()).ToDouble(&minutes);
246     minutes = minutes/60.0;
247     return hour + minutes;
248 }
249 
250 // convert a double into a timestring HH:MM
DoubleToTimeString(double dt)251 wxString CDlgAdvPreferences::DoubleToTimeString(double dt) {
252     int hour = (int)dt;
253     int minutes = (int)(60.0 * (dt - hour)+.5);
254     return wxString::Format(wxT("%02d:%02d"),hour,minutes);
255 }
256 
257 
258 // We only display 2 places past the decimal, so restrict the
259 // precision of saved values to .01.  This prevents unexpected
260 // behavior when, for example, a zero value means no restriction
261 // and the value is displayed as 0.00 but is actually 0.001.
RoundToHundredths(double td)262 double CDlgAdvPreferences::RoundToHundredths(double td) {
263     int i = (int)((td + .005) * 100.);
264     return ((double)(i) / 100.);
265 }
266 
DisplayValue(double value,wxTextCtrl * textCtrl,wxCheckBox * checkBox)267 void CDlgAdvPreferences::DisplayValue(double value, wxTextCtrl* textCtrl, wxCheckBox* checkBox) {
268     wxString buffer;
269 
270     wxASSERT(textCtrl);
271 
272     if (checkBox) {
273         if (! checkBox->IsChecked()) {
274             textCtrl->Clear();
275             textCtrl->Disable();
276             return;
277         }
278     }
279     buffer.Printf(wxT("%g"), value);
280     textCtrl->ChangeValue(buffer);
281     textCtrl->Enable();
282 }
283 
284 
285 /* read preferences from core client and initialize control values */
ReadPreferenceSettings()286 void CDlgAdvPreferences::ReadPreferenceSettings() {
287     CMainDocument* pDoc = wxGetApp().GetDocument();
288     int retval;
289 
290     wxASSERT(pDoc);
291     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
292 
293     // Get current working preferences (including any overrides) from client
294     retval = pDoc->rpc.get_global_prefs_working_struct(prefs, mask);
295     if (retval == ERR_NOT_FOUND) {
296         // Older clients don't support get_global_prefs_working_struct RPC
297         prefs = pDoc->state.global_prefs;
298         retval = pDoc->rpc.get_global_prefs_override_struct(prefs, mask);
299     }
300     if (retval) {
301         m_bOKToShow = false;
302         return;
303     }
304 
305     m_bOKToShow = true;
306 
307     // ######### proc usage page
308     // max cpus
309     // 0 means "no retriction" but we don't use a checkbox here
310     if (prefs.max_ncpus_pct == 0.0) prefs.max_ncpus_pct = 100.0;
311     DisplayValue(prefs.max_ncpus_pct, m_txtProcUseProcessors);
312 
313             //cpu limit
314     // 0 means "no retriction" but we don't use a checkbox here
315     if (prefs.cpu_usage_limit == 0.0) prefs.cpu_usage_limit = 100.0;
316     DisplayValue(prefs.cpu_usage_limit, m_txtProcUseCPUTime);
317 
318     // on batteries
319     m_chkProcOnBatteries->SetValue(! prefs.run_on_batteries);
320 
321     // in use
322     m_chkProcInUse->SetValue(! prefs.run_if_user_active);
323     m_chkGPUProcInUse->SetValue(! prefs.run_gpu_if_user_active);
324 
325     //"Suspend while computer in use" implies "Suspend GPU while computer in use" so set
326     // and disable "Suspend GPU ..." checkbox, overriding its saved value if necessary.
327     if (m_chkProcInUse->IsChecked()) {
328         m_chkGPUProcInUse->SetValue(true);
329         m_chkGPUProcInUse->Disable();
330     }
331 
332     // idle for X minutes
333     if (m_chkProcInUse->IsChecked() || m_chkGPUProcInUse->IsChecked()) {
334         m_txtProcIdleFor->Enable();
335         DisplayValue(prefs.idle_time_to_run, m_txtProcIdleFor);
336     } else {
337         m_txtProcIdleFor->Clear();
338         m_txtProcIdleFor->Disable();
339     }
340 
341     m_chkMaxLoad->SetValue(prefs.suspend_cpu_usage > 0.0);
342     DisplayValue(prefs.suspend_cpu_usage, m_txtMaxLoad, m_chkMaxLoad);
343 
344     // connection interval
345     DisplayValue(prefs.work_buf_min_days, m_txtNetConnectInterval);
346 
347     DisplayValue(prefs.work_buf_additional_days, m_txtNetAdditionalDays);
348 
349     // switch every X minutes
350     DisplayValue(prefs.cpu_scheduling_period_minutes, m_txtProcSwitchEvery);
351 
352     // write to disk every X seconds
353     DisplayValue(prefs.disk_interval, m_txtDiskWriteToDisk);
354 
355     // ######### net usage page
356 
357     //download rate
358     m_chkNetDownloadRate->SetValue(prefs.max_bytes_sec_down > 0.0);
359     DisplayValue((prefs.max_bytes_sec_down / 1024), m_txtNetDownloadRate, m_chkNetDownloadRate);
360 
361 
362     // upload rate
363     m_chkNetUploadRate->SetValue(prefs.max_bytes_sec_up > 0.0);
364     DisplayValue((prefs.max_bytes_sec_up / 1024), m_txtNetUploadRate, m_chkNetUploadRate);
365 
366     m_chk_daily_xfer_limit->SetValue((prefs.daily_xfer_limit_mb > 0.0) && (prefs.daily_xfer_period_days > 0.0));
367     DisplayValue(prefs.daily_xfer_limit_mb, m_txt_daily_xfer_limit_mb, m_chk_daily_xfer_limit);
368     DisplayValue(prefs.daily_xfer_period_days, m_txt_daily_xfer_period_days, m_chk_daily_xfer_limit);
369 
370     //
371     // skip image verification
372     m_chkNetSkipImageVerification->SetValue(prefs.dont_verify_images);
373     // confirm before connect
374     m_chkNetConfirmBeforeConnect->SetValue(prefs.confirm_before_connecting);
375     // disconnect when done
376     m_chkNetDisconnectWhenDone->SetValue(prefs.hangup_if_dialed);
377 
378     // ######### disk and memory usage page
379     //max space used
380     m_chkDiskMaxSpace->SetValue(prefs.disk_max_used_gb > 0.0);
381     DisplayValue(prefs.disk_max_used_gb, m_txtDiskMaxSpace, m_chkDiskMaxSpace);
382 
383     // min free
384     m_chkDiskLeastFree->SetValue(prefs.disk_min_free_gb > 0.0);
385     DisplayValue(prefs.disk_min_free_gb, m_txtDiskLeastFree, m_chkDiskLeastFree);
386 
387     // max used percentage
388     m_chkDiskMaxOfTotal->SetValue(prefs.disk_max_used_pct < 100.0);
389     DisplayValue(prefs.disk_max_used_pct, m_txtDiskMaxOfTotal, m_chkDiskMaxOfTotal);
390 
391     // max VM used
392     DisplayValue((prefs.ram_max_used_busy_frac*100.0), m_txtMemoryMaxInUse);
393 
394     // max VM idle
395     DisplayValue((prefs.ram_max_used_idle_frac*100.0), m_txtMemoryMaxOnIdle);
396 
397     // suspend to memory
398     m_chkMemoryWhileSuspended->SetValue(prefs.leave_apps_in_memory);
399 
400     // max swap space (virtual memory)
401     DisplayValue((prefs.vm_max_used_frac*100.0), m_txtDiskMaxSwap);
402 
403     // ######### daily schedules page
404     // do work between
405     m_chkProcEveryDay->SetValue(prefs.cpu_times.start_hour != prefs.cpu_times.end_hour);
406     if (m_chkProcEveryDay->IsChecked()) {
407         m_txtProcEveryDayStart->ChangeValue(DoubleToTimeString(prefs.cpu_times.start_hour));
408         m_txtProcEveryDayStop->ChangeValue(DoubleToTimeString(prefs.cpu_times.end_hour));
409     }
410 
411     //special day times
412     for(int i=0; i< 7;i++) {
413         TIME_SPAN& cpu = prefs.cpu_times.week.days[i];
414         if(cpu.present && (cpu.start_hour != cpu.end_hour)) {
415             procDayChks[i]->SetValue(true);
416             procDayStartTxts[i]->ChangeValue(DoubleToTimeString(cpu.start_hour));
417             procDayStopTxts[i]->ChangeValue(DoubleToTimeString(cpu.end_hour));
418         }
419     }
420 
421     // use network between
422     m_chkNetEveryDay->SetValue(prefs.net_times.start_hour != prefs.net_times.end_hour);
423     if (m_chkNetEveryDay->IsChecked()) {
424         m_txtNetEveryDayStart->ChangeValue(DoubleToTimeString(prefs.net_times.start_hour));
425         m_txtNetEveryDayStop->ChangeValue(DoubleToTimeString(prefs.net_times.end_hour));
426     }
427 
428     //special net times
429     for(int i=0; i< 7;i++) {
430         TIME_SPAN& net = prefs.net_times.week.days[i];
431         if(net.present && (net.start_hour != net.end_hour)) {
432             netDayChks[i]->SetValue(true);
433             netDayStartTxts[i]->ChangeValue(DoubleToTimeString(net.start_hour));
434             netDayStopTxts[i]->ChangeValue(DoubleToTimeString(net.end_hour));
435         }
436     }
437 
438     //update control states
439     this->UpdateControlStates();
440 }
441 
442 /* write overridden preferences to disk (global_prefs_override.xml) */
443 /* IMPORTANT: Any items added here must be checked in ValidateInput()! */
SavePreferencesSettings()444 bool CDlgAdvPreferences::SavePreferencesSettings() {
445     double td;
446 
447     mask.clear();
448 
449     // ######### proc usage page
450     m_txtProcUseProcessors->GetValue().ToDouble(&td);
451     prefs.max_ncpus_pct = RoundToHundredths(td);
452     mask.max_ncpus_pct=true;
453 
454     //
455     m_txtProcUseCPUTime->GetValue().ToDouble(&td);
456     prefs.cpu_usage_limit=RoundToHundredths(td);
457     mask.cpu_usage_limit=true;
458 
459     prefs.run_on_batteries = ! (m_chkProcOnBatteries->GetValue());
460     mask.run_on_batteries=true;
461     //
462     prefs.run_if_user_active = (! m_chkProcInUse->GetValue());
463     mask.run_if_user_active=true;
464 
465     prefs.run_gpu_if_user_active = (! m_chkGPUProcInUse->GetValue());
466     mask.run_gpu_if_user_active=true;
467     //
468     if(m_txtProcIdleFor->IsEnabled()) {
469         m_txtProcIdleFor->GetValue().ToDouble(&td);
470         prefs.idle_time_to_run=RoundToHundredths(td);
471         mask.idle_time_to_run=true;
472     }
473 
474     if (m_chkMaxLoad->IsChecked()) {
475         m_txtMaxLoad->GetValue().ToDouble(&td);
476         prefs.suspend_cpu_usage=RoundToHundredths(td);
477     } else {
478         prefs.suspend_cpu_usage = 0.0;
479     }
480     mask.suspend_cpu_usage=true;
481 
482     m_txtNetConnectInterval->GetValue().ToDouble(&td);
483     prefs.work_buf_min_days=RoundToHundredths(td);
484     mask.work_buf_min_days=true;
485 
486     //
487     m_txtNetAdditionalDays->GetValue().ToDouble(&td);
488     prefs.work_buf_additional_days = RoundToHundredths(td);
489     mask.work_buf_additional_days = true;
490 
491     //
492     m_txtProcSwitchEvery->GetValue().ToDouble(&td);
493     prefs.cpu_scheduling_period_minutes=RoundToHundredths(td);
494     mask.cpu_scheduling_period_minutes=true;
495 
496      //
497     m_txtDiskWriteToDisk->GetValue().ToDouble(&td);
498     prefs.disk_interval=RoundToHundredths(td);
499     mask.disk_interval=true;
500 
501    // ######### net usage page
502     //
503     if (m_chkNetDownloadRate->IsChecked()) {
504         m_txtNetDownloadRate->GetValue().ToDouble(&td);
505         td = RoundToHundredths(td);
506         td = td * 1024;
507         prefs.max_bytes_sec_down=td;
508     } else {
509         prefs.max_bytes_sec_down = 0.0;
510     }
511     mask.max_bytes_sec_down=true;
512     //
513     if (m_chkNetUploadRate->IsChecked()) {
514         m_txtNetUploadRate->GetValue().ToDouble(&td);
515         td = RoundToHundredths(td);
516         td = td * 1024;
517         prefs.max_bytes_sec_up=td;
518     } else {
519         prefs.max_bytes_sec_up = 0.0;
520     }
521     mask.max_bytes_sec_up=true;
522 
523     if (m_chk_daily_xfer_limit->IsChecked()) {
524         m_txt_daily_xfer_limit_mb->GetValue().ToDouble(&td);
525         prefs.daily_xfer_limit_mb=RoundToHundredths(td);
526         m_txt_daily_xfer_period_days->GetValue().ToDouble(&td);
527         prefs.daily_xfer_period_days=(int)td;
528     } else {
529         prefs.daily_xfer_limit_mb = 0.0;
530         prefs.daily_xfer_period_days = 0.0;
531     }
532     mask.daily_xfer_limit_mb=true;
533     mask.daily_xfer_period_days=true;
534     //
535     prefs.dont_verify_images=m_chkNetSkipImageVerification->GetValue();
536     mask.dont_verify_images=true;
537     //
538     prefs.confirm_before_connecting= m_chkNetConfirmBeforeConnect->GetValue();
539     mask.confirm_before_connecting=true;
540     //
541     prefs.hangup_if_dialed= m_chkNetDisconnectWhenDone->GetValue();
542     mask.hangup_if_dialed=true;
543 
544     // ######### disk and memory page
545 
546     if (m_chkDiskMaxSpace->IsChecked()) {
547         m_txtDiskMaxSpace->GetValue().ToDouble(&td);
548         prefs.disk_max_used_gb=RoundToHundredths(td);
549     } else {
550         prefs.disk_max_used_gb = 0.0;
551     }
552     mask.disk_max_used_gb=true;
553     //
554     if (m_chkDiskLeastFree->IsChecked()) {
555         m_txtDiskLeastFree->GetValue().ToDouble(&td);
556         prefs.disk_min_free_gb=RoundToHundredths(td);
557     } else {
558         prefs.disk_min_free_gb = 0.0;
559     }
560     mask.disk_min_free_gb=true;
561     //
562     if (m_chkDiskMaxOfTotal->IsChecked()) {
563         m_txtDiskMaxOfTotal->GetValue().ToDouble(&td);
564         prefs.disk_max_used_pct = RoundToHundredths(td);
565     } else {
566         prefs.disk_max_used_pct = 100.0;
567     }
568     mask.disk_max_used_pct=true;
569     //Memory
570     m_txtMemoryMaxInUse->GetValue().ToDouble(&td);
571     td = RoundToHundredths(td);
572     td = td / 100.0;
573     prefs.ram_max_used_busy_frac=td;
574     mask.ram_max_used_busy_frac=true;
575     //
576     m_txtMemoryMaxOnIdle->GetValue().ToDouble(&td);
577     td = RoundToHundredths(td);
578     td = td / 100.0;
579     prefs.ram_max_used_idle_frac=td;
580     mask.ram_max_used_idle_frac=true;
581     //
582     prefs.leave_apps_in_memory = m_chkMemoryWhileSuspended->GetValue();
583     mask.leave_apps_in_memory=true;
584     //
585     m_txtDiskMaxSwap->GetValue().ToDouble(&td);
586     td = RoundToHundredths(td);
587     td = td / 100.0 ;
588     prefs.vm_max_used_frac=td;
589     mask.vm_max_used_frac=true;
590 
591     // ######### daily schedules page
592 
593     if (m_chkProcEveryDay->IsChecked()) {
594         prefs.cpu_times.start_hour = TimeStringToDouble(m_txtProcEveryDayStart->GetValue());
595         prefs.cpu_times.end_hour = TimeStringToDouble(m_txtProcEveryDayStop->GetValue());
596     } else {
597         prefs.cpu_times.start_hour = prefs.cpu_times.end_hour = 0.0;
598     }
599     mask.start_hour = mask.end_hour = true;
600 
601     //clear special day times settings
602     prefs.cpu_times.week.clear();
603     for(int i=0; i< 7;i++) {
604         if(procDayChks[i]->GetValue()) {
605             wxString startStr = procDayStartTxts[i]->GetValue();
606             wxString endStr = procDayStopTxts[i]->GetValue();
607             prefs.cpu_times.week.set(i,
608                 TimeStringToDouble(startStr),
609                 TimeStringToDouble(endStr)
610                 );
611         }
612     }
613 
614     if (m_chkNetEveryDay->IsChecked()) {
615         prefs.net_times.start_hour = TimeStringToDouble(m_txtNetEveryDayStart->GetValue());
616         prefs.net_times.end_hour = TimeStringToDouble(m_txtNetEveryDayStop->GetValue());
617     } else {
618         prefs.net_times.start_hour = prefs.net_times.end_hour = 0.0;
619     }
620     mask.net_start_hour = mask.net_end_hour = true;
621 
622     //clear special net times settings
623     prefs.net_times.week.clear();
624     for(int i=0; i< 7;i++) {
625         if(netDayChks[i]->GetValue()) {
626             wxString startStr = netDayStartTxts[i]->GetValue();
627             wxString endStr = netDayStopTxts[i]->GetValue();
628             prefs.net_times.week.set(i,
629                 TimeStringToDouble(startStr),
630                 TimeStringToDouble(endStr)
631                 );
632         }
633     }
634 
635     return true;
636 }
637 
638 /* set state of control depending on other control's state */
UpdateControlStates()639 void CDlgAdvPreferences::UpdateControlStates() {
640     // ######### proc usage page
641     // Disable idle timeout edit text item if we allow both CPU and GPU when idle.
642     bool wasEnabled = m_txtProcIdleFor->IsEnabled();
643     bool shouldEnable = m_chkProcInUse->IsChecked() || m_chkGPUProcInUse->IsChecked();
644     m_txtProcIdleFor->Enable(shouldEnable);
645     if (wasEnabled && !shouldEnable) m_txtProcIdleFor->Clear();
646     if (shouldEnable && !wasEnabled) {
647         DisplayValue(defaultPrefs.idle_time_to_run, m_txtProcIdleFor);
648     }
649 
650     // If we suspend work when in use, disable and check "Use GPU when in use"
651     m_chkGPUProcInUse->Enable(! m_chkProcInUse->IsChecked());
652     if (m_chkProcInUse->IsChecked()) m_chkGPUProcInUse->SetValue(true);
653 
654     m_txtMaxLoad->Enable(m_chkMaxLoad->IsChecked());
655 
656     // ######### disk and memory usage page
657     m_txtDiskMaxSpace->Enable(m_chkDiskMaxSpace->IsChecked());
658     m_txtDiskLeastFree->Enable(m_chkDiskLeastFree->IsChecked());
659     m_txtDiskMaxOfTotal->Enable(m_chkDiskMaxOfTotal->IsChecked());
660 
661     // ######### net usage page
662     m_txtNetDownloadRate->Enable(m_chkNetDownloadRate->IsChecked());
663     m_txtNetUploadRate->Enable(m_chkNetUploadRate->IsChecked());
664     m_txt_daily_xfer_limit_mb->Enable(m_chk_daily_xfer_limit->IsChecked());
665     m_txt_daily_xfer_period_days->Enable(m_chk_daily_xfer_limit->IsChecked());
666 
667     // ######### daily schedules page
668     m_txtProcEveryDayStart->Enable(m_chkProcEveryDay->IsChecked());
669     m_txtProcEveryDayStop->Enable(m_chkProcEveryDay->IsChecked());
670 
671     m_txtNetEveryDayStart->Enable(m_chkNetEveryDay->IsChecked());
672     m_txtNetEveryDayStop->Enable(m_chkNetEveryDay->IsChecked());
673 
674     for (int i=0; i<7; ++i) {
675         procDayStartTxts[i]->Enable(procDayChks[i]->IsChecked());
676         procDayStopTxts[i]->Enable(procDayChks[i]->IsChecked());
677         netDayStartTxts[i]->Enable(netDayChks[i]->IsChecked());
678         netDayStopTxts[i]->Enable(netDayChks[i]->IsChecked());
679     }
680 }
681 
682 /* validates the entered informations */
ValidateInput()683 bool CDlgAdvPreferences::ValidateInput() {
684     wxString invMsgFloat = _("Invalid number");
685     wxString invMsgTime = _("Invalid time, value must be between 0:00 and 24:00, format is HH:MM");
686     wxString invMsgTimeSpan = _("Start time must be different from end time");
687     wxString invMsgLimit10 = _("Number must be between 0 and 10");
688     wxString invMsgLimit100 = _("Number must be between 0 and 100");
689     wxString invMsgLimit1_100 = _("Number must be between 1 and 100");
690     wxString buffer;
691     double startTime, endTime;
692 
693     // ######### proc usage page
694     buffer = m_txtProcUseProcessors->GetValue();
695     if(!IsValidFloatValueBetween(buffer, 0.0, 100.0)) {
696         ShowErrorMessage(invMsgLimit100, m_txtProcUseProcessors);
697         return false;
698     }
699 
700     buffer = m_txtProcUseCPUTime->GetValue();
701     if(!IsValidFloatValueBetween(buffer, 0.0, 100.0)) {
702         ShowErrorMessage(invMsgLimit100, m_txtProcUseCPUTime);
703         return false;
704     }
705 
706     if(m_txtProcIdleFor->IsEnabled()) {
707         buffer = m_txtProcIdleFor->GetValue();
708         if(!IsValidFloatValueBetween(buffer, 0, 10000)) {
709             ShowErrorMessage(invMsgFloat,m_txtProcIdleFor);
710             return false;
711         }
712     }
713 
714     if (m_chkMaxLoad->IsChecked()) {
715         buffer = m_txtMaxLoad->GetValue();
716         if(!IsValidFloatValueBetween(buffer, 1.0, 100.0)) {
717             ShowErrorMessage(invMsgLimit1_100, m_txtMaxLoad);
718             return false;
719         }
720     }
721 
722     //limit additional days from 0 to 10
723     buffer = m_txtNetConnectInterval->GetValue();
724     if(!IsValidFloatValueBetween(buffer, 0.0, 10.0)) {
725         ShowErrorMessage(invMsgLimit10,m_txtNetConnectInterval);
726         return false;
727     }
728 
729     buffer = m_txtNetAdditionalDays->GetValue();
730     if(!IsValidFloatValueBetween(buffer, 0.0, 10.0)) {
731         ShowErrorMessage(invMsgLimit10,m_txtNetAdditionalDays);
732         return false;
733     }
734 
735     buffer = m_txtProcSwitchEvery->GetValue();
736     if(!IsValidFloatValue(buffer)) {
737         ShowErrorMessage(invMsgFloat, m_txtProcSwitchEvery);
738         return false;
739     } else {
740         double td;
741         if((!buffer.ToDouble(&td)) || (td < 1.0)) {
742             ShowErrorMessage(invMsgFloat, m_txtProcSwitchEvery);
743             return false;
744         }
745     }
746 
747     buffer = m_txtDiskWriteToDisk->GetValue();
748     if(!IsValidFloatValue(buffer)) {
749         ShowErrorMessage(invMsgFloat, m_txtDiskWriteToDisk);
750         return false;
751     }
752 
753     // ######### net usage page
754 
755     if (m_chkNetDownloadRate->IsChecked()) {
756         buffer = m_txtNetDownloadRate->GetValue();
757         if(!IsValidFloatValue(buffer)) {
758             ShowErrorMessage(invMsgFloat, m_txtNetDownloadRate);
759             return false;
760         }
761     }
762 
763     if (m_chkNetUploadRate->IsChecked()) {
764         buffer = m_txtNetUploadRate->GetValue();
765         if(!IsValidFloatValue(buffer)) {
766             ShowErrorMessage(invMsgFloat, m_txtNetUploadRate);
767             return false;
768         }
769     }
770 
771     if (m_chk_daily_xfer_limit->IsChecked()) {
772         buffer = m_txt_daily_xfer_limit_mb->GetValue();
773         if(!IsValidFloatValue(buffer)) {
774             ShowErrorMessage(invMsgFloat, m_txt_daily_xfer_limit_mb);
775             return false;
776         }
777 
778         buffer = m_txt_daily_xfer_period_days->GetValue();
779         if(!IsValidFloatValue(buffer)) {
780             ShowErrorMessage(invMsgFloat, m_txt_daily_xfer_period_days);
781             return false;
782         }
783     }
784 
785     // ######### disk and memory page
786     if (m_chkDiskMaxSpace->IsChecked()) {
787         buffer = m_txtDiskMaxSpace->GetValue();
788         if(!IsValidFloatValue(buffer)) {
789             ShowErrorMessage(invMsgFloat, m_txtDiskMaxSpace);
790             return false;
791         }
792     }
793 
794     if (m_chkDiskLeastFree->IsChecked()) {
795         buffer = m_txtDiskLeastFree->GetValue();
796         if(!IsValidFloatValue(buffer)) {
797             ShowErrorMessage(invMsgFloat, m_txtDiskLeastFree);
798             return false;
799         }
800     }
801 
802     if (m_chkDiskMaxOfTotal->IsChecked()) {
803         buffer = m_txtDiskMaxOfTotal->GetValue();
804         if(!IsValidFloatValueBetween(buffer, 0.0, 100.0)) {
805             ShowErrorMessage(invMsgLimit100, m_txtDiskMaxOfTotal);
806             return false;
807         }
808     }
809 
810     buffer = m_txtMemoryMaxInUse->GetValue();
811     if(!IsValidFloatValueBetween(buffer, 1.0, 100.0)) {
812         ShowErrorMessage(invMsgLimit1_100, m_txtMemoryMaxInUse);
813         return false;
814     }
815 
816     buffer = m_txtMemoryMaxOnIdle->GetValue();
817     if(!IsValidFloatValueBetween(buffer, 1.0, 100.0)) {
818         ShowErrorMessage(invMsgLimit1_100, m_txtMemoryMaxOnIdle);
819         return false;
820     }
821 
822     buffer = m_txtDiskMaxSwap->GetValue();
823     if(!IsValidFloatValueBetween(buffer, 1.0, 100.0)) {
824         ShowErrorMessage(invMsgLimit1_100, m_txtDiskMaxSwap);
825         return false;
826     }
827 
828     // ######### daily schedules page
829     if (m_chkProcEveryDay->IsChecked()) {
830         buffer = m_txtProcEveryDayStart->GetValue();
831         if(!IsValidTimeValue(buffer)) {
832             ShowErrorMessage(invMsgTime,m_txtProcEveryDayStart);
833             return false;
834         }
835         buffer = m_txtProcEveryDayStop->GetValue();
836         if(!IsValidTimeValue(buffer)) {
837             ShowErrorMessage(invMsgTime,m_txtProcEveryDayStop);
838             return false;
839         }
840         startTime = TimeStringToDouble(m_txtProcEveryDayStart->GetValue());
841         endTime = TimeStringToDouble(m_txtProcEveryDayStop->GetValue());
842         if (startTime == endTime) {
843             ShowErrorMessage(invMsgTimeSpan,m_txtProcEveryDayStop);
844             return false;
845         }
846     }
847 
848     //all text ctrls in proc special time textBox
849     for(int i=0; i< 7;i++) {
850         if(procDayChks[i]->GetValue()) {
851            buffer = procDayStartTxts[i]->GetValue();
852             if(!IsValidTimeValue(buffer)) {
853                 ShowErrorMessage(invMsgTime,procDayStartTxts[i]);
854                 return false;
855             }
856            buffer = procDayStopTxts[i]->GetValue();
857             if(!IsValidTimeValue(buffer)) {
858                 ShowErrorMessage(invMsgTime,procDayStopTxts[i]);
859                 return false;
860             }
861             startTime = TimeStringToDouble(procDayStartTxts[i]->GetValue());
862             endTime = TimeStringToDouble(procDayStopTxts[i]->GetValue());
863             if (startTime == endTime) {
864                 ShowErrorMessage(invMsgTimeSpan,procDayStopTxts[i]);
865                 return false;
866             }
867         }
868     }
869 
870     if (m_chkNetEveryDay->IsChecked()) {
871         buffer = m_txtNetEveryDayStart->GetValue();
872         if(!IsValidTimeValue(buffer)) {
873             ShowErrorMessage(invMsgTime,m_txtNetEveryDayStart);
874             return false;
875         }
876         buffer = m_txtNetEveryDayStop->GetValue();
877         if(!IsValidTimeValue(buffer)) {
878             ShowErrorMessage(invMsgTime,m_txtNetEveryDayStop);
879             return false;
880         }
881         startTime = TimeStringToDouble(m_txtNetEveryDayStart->GetValue());
882         endTime = TimeStringToDouble(m_txtNetEveryDayStop->GetValue());
883         if (startTime == endTime) {
884             ShowErrorMessage(invMsgTimeSpan,m_txtNetEveryDayStop);
885             return false;
886         }
887     }
888 
889     //all text ctrls in net special time textBox
890     for(int i=0; i< 7;i++) {
891         if(netDayChks[i]->GetValue()) {
892            buffer = netDayStartTxts[i]->GetValue();
893             if(!IsValidTimeValue(buffer)) {
894                 ShowErrorMessage(invMsgTime,netDayStartTxts[i]);
895                 return false;
896             }
897             buffer = netDayStopTxts[i]->GetValue();
898             if(!IsValidTimeValue(buffer)) {
899                 ShowErrorMessage(invMsgTime,netDayStopTxts[i]);
900                 return false;
901             }
902             startTime = TimeStringToDouble(netDayStartTxts[i]->GetValue());
903             endTime = TimeStringToDouble(netDayStopTxts[i]->GetValue());
904             if (startTime == endTime) {
905                 ShowErrorMessage(invMsgTimeSpan,netDayStopTxts[i]);
906                 return false;
907             }
908         }
909     }
910     return true;
911 }
912 
913 /* ensures that the page which contains txtCtrl is selected */
EnsureTabPageVisible(wxTextCtrl * txtCtrl)914 bool CDlgAdvPreferences::EnsureTabPageVisible(wxTextCtrl* txtCtrl) {
915     wxWindow* parent = txtCtrl->GetParent();
916     wxASSERT(parent);
917     int parentid = parent->GetId();
918     int index = m_arrTabPageIds.Index(parentid);
919     if(index == wxNOT_FOUND) {
920         //some controls are contained in an additional panel,
921         //so look at its parent and grandparent
922         for (int i=0; i<2; ++i) {
923             parent = parent->GetParent();
924             wxASSERT(parent);
925             parentid = parent->GetId();
926             index = m_arrTabPageIds.Index(parentid);
927             if(index != wxNOT_FOUND) break;
928         }
929         if(index == wxNOT_FOUND) {
930             //this should never happen
931             return false;
932         }
933     }
934     m_Notebook->SetSelection(index);
935     return true;
936 }
937 
938 /* show an error message and set the focus to the control that caused the error */
ShowErrorMessage(wxString & message,wxTextCtrl * errorCtrl)939 void CDlgAdvPreferences::ShowErrorMessage(wxString& message,wxTextCtrl* errorCtrl) {
940 #if wxDEBUG_LEVEL   // Prevent compiler warning (unused variable)
941     bool visibleOK =
942 #endif
943     this->EnsureTabPageVisible(errorCtrl);
944     wxASSERT(visibleOK);
945     //
946     if(message.IsEmpty()){
947         message = _("invalid input value detected");
948     }
949     if (lastErrorCtrl) {
950         lastErrorCtrl->SetBackgroundColour(stdTextBkgdColor);
951         lastErrorCtrl->Refresh();
952     }
953     if (lastErrorCtrl != errorCtrl) {
954         stdTextBkgdColor = errorCtrl->GetBackgroundColour();
955     }
956     errorCtrl->SetBackgroundColour(wxColour(255, 192, 192));
957     errorCtrl->Refresh();
958     lastErrorCtrl = errorCtrl;
959     wxGetApp().SafeMessageBox(message,_("Validation Error"),wxOK | wxCENTRE | wxICON_ERROR,this);
960     errorCtrl->SetFocus();
961 }
962 
963 /* checks if ch is a valid character for float values */
IsValidFloatChar(const wxChar & ch)964 bool CDlgAdvPreferences::IsValidFloatChar(const wxChar& ch) {
965     //don't accept the e
966     return wxIsdigit(ch) || ch=='.' || ch==',' || ch=='+' || ch=='-';}
967 
968 /* checks if ch is a valid character for time values */
IsValidTimeChar(const wxChar & ch)969 bool CDlgAdvPreferences::IsValidTimeChar(const wxChar& ch) {
970     return wxIsdigit(ch) || ch==':';
971 }
972 
973 /* checks if the value contains a valid float */
IsValidFloatValue(const wxString & value,bool allowNegative)974 bool CDlgAdvPreferences::IsValidFloatValue(const wxString& value, bool allowNegative) {
975     for(unsigned int i=0; i < value.Length();i++) {
976         if(!IsValidFloatChar(value[i])) {
977             return false;
978         }
979     }
980     //all chars are valid, now what is with the value as a whole ?
981     double td;
982     if(!value.ToDouble(&td)) {
983         return false;
984     }
985     if (!allowNegative) {
986         if (td < 0.0) return false;
987     }
988     return true;
989 }
990 
IsValidFloatValueBetween(const wxString & value,double minVal,double maxVal)991 bool CDlgAdvPreferences::IsValidFloatValueBetween(const wxString& value, double minVal, double maxVal){
992     for(unsigned int i=0; i < value.Length();i++) {
993         if(!IsValidFloatChar(value[i])) {
994             return false;
995         }
996     }
997     //all chars are valid, now what is with the value as a whole ?
998     double td;
999     if(!value.ToDouble(&td)) {
1000         return false;
1001     }
1002     if ((td < minVal) || (td > maxVal)) return false;
1003     return true;
1004 }
1005 
1006 
1007 /* checks if the value is a valid time */
IsValidTimeValue(const wxString & value)1008 bool CDlgAdvPreferences::IsValidTimeValue(const wxString& value) {
1009     for(unsigned int i=0; i < value.Length();i++) {
1010         if(!IsValidTimeChar(value[i])) {
1011             return false;
1012         }
1013     }
1014     //all chars are valid, now what is with the value as a whole ?
1015     wxDateTime dt;
1016     const wxChar* stopChar = dt.ParseFormat(value,wxT("%H:%M"));
1017     if(stopChar==NULL && value != wxT("24:00")) {
1018         // conversion failed
1019         return false;
1020     }
1021     return true;
1022 }
1023 
1024 
1025 // ------------ Event handlers starts here
1026 // -------- generic command handler
1027 // handles all control command events
OnHandleCommandEvent(wxCommandEvent & ev)1028 void CDlgAdvPreferences::OnHandleCommandEvent(wxCommandEvent& ev) {
1029     ev.Skip();
1030     // If user has just set the checkbox, set textedit field to default value.
1031     // Note: use ChangeValue() here to avoid generating extra events.
1032     // m_txtProcIdleFor depends on 2 checkboxes, set it in UpdateControlStates().
1033     switch (ev.GetId()) {
1034     // processor usage page
1035     case ID_CHKMAXLOAD:
1036         DisplayValue(defaultPrefs.suspend_cpu_usage, m_txtMaxLoad, m_chkMaxLoad);
1037         break;
1038 
1039     // network usage page
1040     case ID_CHKNETDOWNLOADRATE:
1041         DisplayValue((defaultPrefs.max_bytes_sec_down / 1024), m_txtNetDownloadRate, m_chkNetDownloadRate);
1042         break;
1043     case ID_CHKNETUPLOADRATE:
1044         DisplayValue((defaultPrefs.max_bytes_sec_up / 1024), m_txtNetUploadRate, m_chkNetUploadRate);
1045         break;
1046     case ID_CHKDAILYXFERLIMIT:
1047         DisplayValue(defaultPrefs.daily_xfer_limit_mb, m_txt_daily_xfer_limit_mb, m_chk_daily_xfer_limit);
1048         DisplayValue(defaultPrefs.daily_xfer_period_days, m_txt_daily_xfer_period_days, m_chk_daily_xfer_limit);
1049         break;
1050 
1051     // disk usage page
1052     case ID_CHKDISKMAXSPACE:
1053         DisplayValue(defaultPrefs.disk_max_used_gb, m_txtDiskMaxSpace, m_chkDiskMaxSpace);
1054         break;
1055     case ID_CHKDISKLEASTFREE:
1056         DisplayValue(defaultPrefs.disk_min_free_gb, m_txtDiskLeastFree, m_chkDiskLeastFree);
1057         break;
1058     case ID_CHKDISKMAXOFTOTAL:
1059         DisplayValue(defaultPrefs.disk_max_used_pct, m_txtDiskMaxOfTotal, m_chkDiskMaxOfTotal);
1060         break;
1061     case ID_CHKPROCEVERYDAY:
1062         if (ev.IsChecked()) {
1063             m_txtProcEveryDayStart->ChangeValue(DoubleToTimeString(defaultPrefs.cpu_times.start_hour));
1064             m_txtProcEveryDayStop->ChangeValue(DoubleToTimeString(defaultPrefs.cpu_times.end_hour));
1065         } else {
1066             m_txtProcEveryDayStart->Clear();
1067             m_txtProcEveryDayStop->Clear();
1068         }
1069         break;
1070     case ID_CHKPROCSUNDAY:
1071     case ID_CHKPROCMONDAY:
1072     case ID_CHKPROCTUESDAY:
1073     case ID_CHKPROCWEDNESDAY:
1074     case ID_CHKPROCTHURSDAY:
1075     case ID_CHKPROCFRIDAY:
1076     case ID_CHKPROCSATURDAY:
1077         if (ev.IsChecked()) {
1078             (procDayStartTxts[ev.GetId() - ID_CHKPROCSUNDAY])->ChangeValue(DoubleToTimeString(defaultPrefs.cpu_times.start_hour));
1079             (procDayStopTxts[ev.GetId() - ID_CHKPROCSUNDAY])->ChangeValue(DoubleToTimeString(defaultPrefs.cpu_times.end_hour));
1080         } else {
1081             (procDayStartTxts[ev.GetId() - ID_CHKPROCSUNDAY])->Clear();
1082             (procDayStopTxts[ev.GetId() - ID_CHKPROCSUNDAY])->Clear();
1083         }
1084         break;
1085     case ID_CHKNETEVERYDAY:
1086        if (ev.IsChecked()) {
1087             m_txtNetEveryDayStart->ChangeValue(DoubleToTimeString(defaultPrefs.net_times.start_hour));
1088             m_txtNetEveryDayStop->ChangeValue(DoubleToTimeString(defaultPrefs.net_times.end_hour));
1089         } else {
1090             m_txtNetEveryDayStart->Clear();
1091             m_txtNetEveryDayStop->Clear();
1092         }
1093         break;
1094     case ID_CHKNETSUNDAY:
1095     case ID_CHKNETMONDAY:
1096     case ID_CHKNETTUESDAY:
1097     case ID_CHKNETWEDNESDAY:
1098     case ID_CHKNETTHURSDAY:
1099     case ID_CHKNETFRIDAY:
1100     case ID_CHKNETSATURDAY:
1101        if (ev.IsChecked()) {
1102             (netDayStartTxts[ev.GetId() - ID_CHKNETSUNDAY])->ChangeValue(DoubleToTimeString(defaultPrefs.net_times.start_hour));
1103             (netDayStopTxts[ev.GetId() - ID_CHKNETSUNDAY])->ChangeValue(DoubleToTimeString(defaultPrefs.net_times.end_hour));
1104         } else {
1105             (netDayStartTxts[ev.GetId() - ID_CHKNETSUNDAY])->Clear();
1106             (netDayStopTxts[ev.GetId() - ID_CHKNETSUNDAY])->Clear();
1107         }
1108         break;
1109 
1110     default:
1111         break;
1112     }
1113 //    }
1114     UpdateControlStates();
1115 }
1116 
1117 // ---- command buttons handlers
1118 // handles OK button clicked
OnOK(wxCommandEvent & ev)1119 void CDlgAdvPreferences::OnOK(wxCommandEvent& ev) {
1120     CMainDocument*    pDoc = wxGetApp().GetDocument();
1121 
1122     wxASSERT(pDoc);
1123     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
1124 
1125     if(!ValidateInput()) {
1126         return;
1127     }
1128     if(SavePreferencesSettings()) {
1129         pDoc->rpc.set_global_prefs_override_struct(prefs,mask);
1130         pDoc->rpc.read_global_prefs_override();
1131     }
1132 
1133     ev.Skip();
1134 }
1135 
1136 // handles Help button clicked
OnHelp(wxCommandEvent & ev)1137 void CDlgAdvPreferences::OnHelp(wxCommandEvent& ev) {
1138     if (IsShown()) {
1139 
1140         wxString strURL = wxGetApp().GetSkinManager()->GetAdvanced()->GetOrganizationHelpUrl();
1141 
1142         wxString wxurl;
1143         wxurl.Printf(
1144             wxT("%s?target=advanced_preferences&version=%s&controlid=%d"),
1145             strURL.c_str(),
1146             wxString(BOINC_VERSION_STRING, wxConvUTF8).c_str(),
1147             ev.GetId()
1148         );
1149         wxLaunchDefaultBrowser(wxurl);
1150     }
1151 }
1152 
1153 // handles Clear button clicked
OnClear(wxCommandEvent & ev)1154 void CDlgAdvPreferences::OnClear(wxCommandEvent& ev) {
1155     if(this->ConfirmClear()) {
1156         CMainDocument*    pDoc = wxGetApp().GetDocument();
1157 
1158         wxASSERT(pDoc);
1159         wxASSERT(wxDynamicCast(pDoc, CMainDocument));
1160 
1161         mask.clear();
1162         pDoc->rpc.set_global_prefs_override_struct(prefs,mask);
1163         pDoc->rpc.read_global_prefs_override();
1164         this->EndModal(wxID_CANCEL);
1165     }
1166     ev.Skip();
1167 }
1168 
ConfirmClear()1169 bool CDlgAdvPreferences::ConfirmClear() {
1170     int res = wxGetApp().SafeMessageBox(_(
1171         "Discard local preferences and use web-based preferences?"),
1172         _("Confirmation"),wxCENTER | wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT,this);
1173 
1174     return res==wxYES;
1175 }
1176 
1177 
1178 
1179