1 // This file is part of BOINC.
2 // http://boinc.berkeley.edu
3 // Copyright (C) 2014 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 "DlgHiddenColumns.cpp"
20 #endif
21 
22 #include "stdwx.h"
23 #include "util.h"
24 #include "DlgHiddenColumns.h"
25 #include "BOINCGUIApp.h"
26 #include "Events.h"
27 #include "error_numbers.h"
28 #include "gui_rpc_client.h"
29 #include "SkinManager.h"
30 #include "MainDocument.h"
31 #include "AdvancedFrame.h"
32 #include "BOINCBaseView.h"
33 #include "BOINCListCtrl.h"
34 
35 #define DLGDIAGNOSTICS_INITIAL_WIDTH ADJUSTFORXDPI(480)
36 #define DLGDIAGNOSTICS_INITIAL_HEIGHT ADJUSTFORYDPI(480)
37 #define DLGDIAGNOSTICS_MIN_WIDTH ADJUSTFORXDPI(400)
38 #define DLGDIAGNOSTICS_MIN_HEIGHT ADJUSTFORYDPI(400)
39 
IMPLEMENT_DYNAMIC_CLASS(CDlgHiddenColumns,wxDialog)40 IMPLEMENT_DYNAMIC_CLASS(CDlgHiddenColumns, wxDialog)
41 
42 BEGIN_EVENT_TABLE(CDlgHiddenColumns, wxDialog)
43     EVT_SIZE(CDlgHiddenColumns::OnSize)
44     EVT_BUTTON(wxID_OK,CDlgHiddenColumns::OnOK)
45     EVT_BUTTON(ID_DEFAULTSBTN,CDlgHiddenColumns::OnSetDefaults)
46     EVT_CHECKBOX(wxID_ANY, CDlgHiddenColumns::OnCheckboxClick )
47 
48 
49 END_EVENT_TABLE()
50 
51 /* Constructor */
52 CDlgHiddenColumns::CDlgHiddenColumns(wxWindow* parent) :
53     wxDialog( parent, ID_ANYDIALOG, wxEmptyString, wxDefaultPosition,
54                 wxSize( DLGDIAGNOSTICS_INITIAL_WIDTH,DLGDIAGNOSTICS_INITIAL_HEIGHT ),
55                 wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER
56             ) {
57 
58     CSkinAdvanced*     pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced();
59     wxASSERT(pSkinAdvanced);
60     wxASSERT(wxDynamicCast(pSkinAdvanced, CSkinAdvanced));
61 
62     wxString title;
63     title.Printf(
64         _("%s Column Selection"),
65         pSkinAdvanced->GetApplicationShortName().c_str()
66     );
67 
68     SetTitle(title);
69 
70     SetSizeHints(DLGDIAGNOSTICS_MIN_WIDTH, DLGDIAGNOSTICS_MIN_HEIGHT);
71     SetExtraStyle( GetExtraStyle() | wxWS_EX_VALIDATE_RECURSIVELY );
72 
73     wxBoxSizer* bSizer1 = new wxBoxSizer( wxVERTICAL );
74     m_headingSizer = new wxGridSizer( 1 );
75 
76     m_headingText.Printf(
77         _("Select which columns %s should show."),
78         pSkinAdvanced->GetApplicationShortName().c_str()
79     );
80 
81     m_heading = new wxStaticText(this, wxID_ANY, m_headingText);
82 
83     m_headingSizer->Add(m_heading, 1, wxLEFT | wxRIGHT, 25);
84 
85     bSizer1->AddSpacer(7);
86     bSizer1->Add( m_headingSizer, 0, wxEXPAND | wxALL, 5 );
87     bSizer1->AddSpacer(7);
88 
89     m_scrolledWindow = new wxScrolledWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHSCROLL|wxVSCROLL );
90     m_scrolledWindow->SetScrollRate( 5, 5 );
91 
92     m_scrolledSizer = new wxBoxSizer(wxVERTICAL);
93 
94     CreateCheckboxes();
95 
96     bSizer1->Add( m_scrolledWindow, 1, wxEXPAND | wxALL, 5 );
97 
98     wxBoxSizer* buttonSizer = new wxBoxSizer( wxHORIZONTAL );
99 
100     m_btnOK = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxDefaultSize, 0 );
101     m_btnOK->SetToolTip( _("Save all values and close the dialog") );
102     buttonSizer->Add( m_btnOK, 0, wxALL, 5 );
103 
104     wxButton* btnDefaults = new wxButton( this, ID_DEFAULTSBTN, _("Defaults"), wxDefaultPosition, wxDefaultSize, 0 );
105     btnDefaults->SetToolTip( _("Restore default settings") );
106     buttonSizer->Add( btnDefaults, 0, wxALL, 5 );
107 
108     wxButton* btnCancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0 );
109     btnCancel->SetToolTip( _("Close the dialog without saving") );
110     buttonSizer->Add( btnCancel, 0, wxALL, 5 );
111 
112     btnCancel->SetDefault();
113     bSizer1->Add( buttonSizer, 0, wxALIGN_RIGHT | wxALL, 15 );
114 
115     SetSizer( bSizer1 );
116 
117     RestoreState();
118     Layout();
119     Center( wxBOTH );
120 
121 #if defined(__WXMSW__) || defined(__WXGTK__)
122     SetDoubleBuffered(true);
123 #endif
124 }
125 
126 // destructor
~CDlgHiddenColumns()127 CDlgHiddenColumns::~CDlgHiddenColumns() {
128     unsigned int i, count;
129 
130     SaveState();
131 
132     count = m_checkbox_list.size();
133     for (i=0; i<count; ++i) {
134         std::vector <wxCheckBox*> *checkbox_list = m_checkbox_list[i];
135         checkbox_list->clear();
136         delete checkbox_list;
137     }
138     m_checkbox_list.clear();
139     m_pBOINCBaseView.clear();
140 }
141 
142 
CreateCheckboxes()143 void CDlgHiddenColumns::CreateCheckboxes() {
144     int i, stdCount, actualCount;
145     bool val;
146     CAdvancedFrame* pFrame = (CAdvancedFrame*)GetParent();
147     wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
148 
149     wxNotebook* pNotebook = pFrame->GetNotebook();
150     wxASSERT(pNotebook);
151 
152     actualCount = m_checkbox_list.size();
153     for (i=0; i<actualCount; ++i) {
154         std::vector <wxCheckBox*> *checkbox_list = m_checkbox_list[i];
155         checkbox_list->clear();
156         delete checkbox_list;
157     }
158     m_checkbox_list.clear();
159 
160     wxWindow*       pwndNotebookPage = NULL;
161     CBOINCBaseView* pView = NULL;
162     long            iIndex;
163     long            iPageCount;
164 
165     iPageCount = (long)pNotebook->GetPageCount();
166 
167     for (iIndex = 0; iIndex < iPageCount; iIndex++) {
168         pwndNotebookPage = pNotebook->GetPage(iIndex);
169         wxASSERT(wxDynamicCast(pwndNotebookPage, CBOINCBaseView));
170 
171         pView = wxDynamicCast(pwndNotebookPage, CBOINCBaseView);
172         wxASSERT(pView);
173 
174         CBOINCListCtrl* listPane = pView->GetListCtrl();
175         if (!listPane) continue;
176 
177         m_pBOINCBaseView.push_back(pView);
178 
179         std::vector <wxCheckBox*> *checkbox_list = new std::vector <wxCheckBox*>;
180 
181         wxStaticBox* tabStaticBox = new wxStaticBox(m_scrolledWindow, -1, pView->GetViewDisplayName());
182         wxStaticBoxSizer* tabStaticBoxSizer = new wxStaticBoxSizer( tabStaticBox, wxVERTICAL );
183         wxGridSizer* checkboxSizer = new wxGridSizer(2, wxSize(0,3));
184 
185         CBOINCListCtrl* listCtrl = pView->GetListCtrl();
186         wxInt32 iShownColumnCount = listCtrl->GetColumnCount();
187         wxArrayInt aOrder(iShownColumnCount);
188 
189 #ifdef wxHAS_LISTCTRL_COLUMN_ORDER
190         aOrder = listCtrl->GetColumnsOrder();
191 #else
192         for (i = 0; i < iShownColumnCount; ++i) {
193             aOrder[i] = i;
194         }
195 #endif
196 
197         stdCount = pView->m_aStdColNameOrder->GetCount();
198 
199 #ifdef wxHAS_LISTCTRL_COLUMN_ORDER
200         // Create checkboxes for shown columns in current column order
201         for (i=0; i<iShownColumnCount; ++i) {
202             wxString columnLabel = pView->m_aStdColNameOrder->Item(pView->m_iColumnIndexToColumnID[aOrder[i]]);
203             wxCheckBox* ckbox = new wxCheckBox(tabStaticBox, wxID_ANY, columnLabel);
204             checkboxSizer->Add(ckbox, 0, wxLEFT, 25);
205             val = false;
206             ckbox->SetValue(true);
207             checkbox_list->push_back(ckbox);
208         }
209 
210         // Create checkboxes for hidden columns
211         for (i=0; i<stdCount; ++i) {
212             bool found = false;
213             for (int j = 0; j < iShownColumnCount; ++j) {
214                 if (pView->m_iColumnIndexToColumnID[aOrder[j]] == i) {
215                     found = true;
216                     break;
217                 }
218             }
219             if (found) continue;
220 
221             wxString columnLabel = pView->m_aStdColNameOrder->Item(i);
222             wxCheckBox* ckbox = new wxCheckBox(tabStaticBox, wxID_ANY, columnLabel);
223             checkboxSizer->Add(ckbox, 0, wxLEFT, 25);
224             ckbox->SetValue(false);
225             checkbox_list->push_back(ckbox);
226         }
227 #else
228         for (i=0; i<stdCount; ++i) {
229             wxString columnLabel = pView->m_aStdColNameOrder->Item(i);
230             wxCheckBox* ckbox = new wxCheckBox(tabStaticBox, wxID_ANY, columnLabel);
231             checkboxSizer->Add(ckbox, 0, wxLEFT, 25);
232             val = false;
233             if (pView->m_iColumnIDToColumnIndex[i] >= 0) val = true;
234             ckbox->SetValue(val);
235             checkbox_list->push_back(ckbox);
236         }
237 #endif
238 
239         m_checkbox_list.push_back(checkbox_list);
240 
241         tabStaticBoxSizer->Add(checkboxSizer, 0, wxEXPAND, 1 );
242         m_scrolledSizer->Add(tabStaticBoxSizer, 0, wxEXPAND, 1 );
243     }
244     m_scrolledWindow->SetSizer( m_scrolledSizer );
245     m_scrolledWindow->Layout();
246     m_scrolledSizer->Fit( m_scrolledWindow );
247 }
248 
249 
250 /* saves dialog size and (on Mac) position */
SaveState()251 bool CDlgHiddenColumns::SaveState() {
252     wxConfigBase*   pConfig = wxConfigBase::Get(FALSE);
253 
254     wxASSERT(pConfig);
255     if (!pConfig) return false;
256 
257     pConfig->SetPath("/DlgHiddenColumns/");
258     pConfig->Write(wxT("Width"), GetSize().GetWidth());
259     pConfig->Write(wxT("Height"), GetSize().GetHeight());
260 
261     pConfig->Flush();
262 
263     return true;
264 }
265 
266 /* restores former dialog size and (on Mac) position */
RestoreState()267 bool CDlgHiddenColumns::RestoreState() {
268     wxConfigBase*   pConfig = wxConfigBase::Get(FALSE);
269     int                iWidth, iHeight;
270 
271     wxASSERT(pConfig);
272     if (!pConfig) return false;
273 
274     pConfig->SetPath("/DlgHiddenColumns/");
275 
276     pConfig->Read(wxT("Width"), &iWidth, DLGDIAGNOSTICS_INITIAL_WIDTH);
277     pConfig->Read(wxT("Height"), &iHeight, DLGDIAGNOSTICS_INITIAL_HEIGHT);
278 
279     // Guard against a rare situation where registry values are zero
280     if ((iWidth < 50) && (iWidth != wxDefaultCoord)) iWidth = DLGDIAGNOSTICS_INITIAL_WIDTH;
281     if ((iHeight < 50) && (iHeight != wxDefaultCoord)) iHeight = DLGDIAGNOSTICS_INITIAL_HEIGHT;
282 
283     // Set size to saved values or defaults if no saved values
284     SetSize(std::max(iWidth, DLGDIAGNOSTICS_MIN_WIDTH), std::max(iHeight, DLGDIAGNOSTICS_MIN_HEIGHT));
285 
286     return true;
287 }
288 
289 
OnSize(wxSizeEvent & event)290 void CDlgHiddenColumns::OnSize(wxSizeEvent& event) {
291     m_heading->SetLabel(m_headingText);
292     m_heading->Wrap(m_headingSizer->GetSize().GetWidth()-50);
293     m_headingSizer->Fit(m_heading);
294     Layout();
295     SaveState();
296     Refresh();
297 
298     event.Skip();
299 }
300 
301 
OnCheckboxClick(wxCommandEvent & event)302 void CDlgHiddenColumns::OnCheckboxClick(wxCommandEvent& event){
303     bool bAllOffInGroup, bEnableOK = true;
304 
305     size_t actualCount = m_checkbox_list.size();
306     for (size_t i=0; i<actualCount; ++i) {
307         std::vector <wxCheckBox*> *checkbox_list = m_checkbox_list[i];
308         bAllOffInGroup = true;
309         for (size_t j=0; j<checkbox_list->size(); ++j) {
310             wxCheckBox* ckbox = (*checkbox_list)[j];
311             if (ckbox->GetValue()) {
312                 bAllOffInGroup = false;
313                 break;
314             }
315         }
316         if (bAllOffInGroup) {
317             bEnableOK =  false;
318             break;
319         }
320     }
321     m_btnOK->Enable(bEnableOK);
322 
323     event.Skip();
324 }
325 
326 
OnOK(wxCommandEvent & event)327 void CDlgHiddenColumns::OnOK(wxCommandEvent& event) {
328     size_t actualCount = m_checkbox_list.size();
329     wxASSERT (m_pBOINCBaseView.size() == actualCount);
330 
331     for (size_t i=0; i<actualCount; ++i) {
332         CBOINCBaseView* pView = m_pBOINCBaseView[i];
333         std::vector <wxCheckBox*> *checkbox_list = m_checkbox_list[i];
334         wxArrayString orderArray;
335         for (size_t j=0; j<checkbox_list->size(); ++j) {
336             wxCheckBox* ckbox = (*checkbox_list)[j];
337             if (ckbox->GetValue()) {
338                 wxString name = ckbox->GetLabel();
339                 orderArray.Add(name);
340             }
341         }
342 
343         CBOINCListCtrl* listPane = pView->GetListCtrl();
344         listPane->SetListColumnOrder(orderArray);
345 
346         // Write the new column configuration to the registry
347         wxConfigBase* pConfig = wxConfigBase::Get(false);
348         pConfig->SetPath(wxT("/") + pView->GetViewName());
349         listPane->OnSaveState(pConfig);
350     }
351 
352     event.Skip();
353 }
354 
355 
OnSetDefaults(wxCommandEvent &)356 void CDlgHiddenColumns::OnSetDefaults(wxCommandEvent& ) {
357     wxMessageDialog* dlg = new wxMessageDialog(this, _("Are you sure you want to reset all list columns to the default configurations?"),
358                     _("Confirm defaults"), wxOK|wxCANCEL|wxCENTRE, wxDefaultPosition);
359 
360     if (dlg->ShowModal() != wxID_OK) return;
361 
362     int count = m_pBOINCBaseView.size();
363     for (int i=0; i<count; ++i) {
364         CBOINCBaseView* pView = m_pBOINCBaseView[i];
365         CBOINCListCtrl* listPane = pView->GetListCtrl();
366 
367         listPane->SetListColumnOrder(*(pView->m_aStdColNameOrder));
368         listPane->SetDefaultColumnDisplay();
369 
370         // Write the new column configuration to the registry
371         wxConfigBase* pConfig = wxConfigBase::Get(false);
372         pConfig->SetPath(wxT("/") + pView->GetViewName());
373         listPane->OnSaveState(pConfig);
374     }
375 
376     EndModal(0);
377 }
378